mirror of
https://github.com/jbranchaud/til
synced 2026-10-31 00:13:27 +00:00
Compare commits
10
Commits
7ac2855666
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bff11a2fee | ||
|
|
891e3453d1 | ||
|
|
2b29a572bb | ||
|
|
91a69640d8 | ||
|
|
0f143e71ed | ||
|
|
ae83a39fa8 | ||
|
|
c301401663 | ||
|
|
8129ad0eaa | ||
|
|
29676e0d5a | ||
|
|
dded5f6135 |
@@ -10,7 +10,7 @@ working across different projects via [VisualMode](https://www.visualmode.dev/).
|
||||
|
||||
For a steady stream of TILs, [sign up for my newsletter](https://visualmode.kit.com/newsletter).
|
||||
|
||||
_1886 TILs and counting..._
|
||||
_1894 TILs and counting..._
|
||||
|
||||
See some of the other learning resources I work on:
|
||||
|
||||
@@ -173,6 +173,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Distinguish Sessions With Different Colors](claude-code/distinguish-sessions-with-different-colors.md)
|
||||
- [Monitor Usage Limits From CLI](claude-code/monitor-usage-limits-from-cli.md)
|
||||
- [Open Current Prompt In Default Editor](claude-code/open-current-prompt-in-default-editor.md)
|
||||
- [Pick Up Session Locally That Started In Cloud](claude-code/pick-up-session-locally-that-started-in-cloud.md)
|
||||
- [Resume Specific Session](claude-code/resume-specific-session.md)
|
||||
- [Set Permission Mode When Starting Session](claude-code/set-permission-mode-when-starting-session.md)
|
||||
- [Stash The Current Prompt To Send Another First](claude-code/stash-the-current-prompt-to-send-another-first.md)
|
||||
@@ -228,6 +229,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Parameterized SCSS Mixins](css/parameterized-scss-mixins.md)
|
||||
- [Prevent Invisible Elements From Being Clicked](css/prevent-invisible-elements-from-being-clicked.md)
|
||||
- [:root Has Higher Specificity Than html](css/root-has-higher-specificity-than-html.md)
|
||||
- [Show Full URLs With Print Styles](css/show-full-urls-with-print-styles.md)
|
||||
- [Style A Background With A Linear Gradient](css/style-a-background-with-a-linear-gradient.md)
|
||||
- [Using Maps In SCSS](css/using-maps-in-scss.md)
|
||||
|
||||
@@ -480,11 +482,13 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
### GitHub
|
||||
|
||||
- [Access Your GitHub Profile Photo](github/access-your-github-profile-photo.md)
|
||||
- [Create A Private Repo From The CLI](github/create-a-private-repo-from-the-cli.md)
|
||||
- [Create And Push To New Repo From CLI](github/create-and-push-to-new-repo-from-cli.md)
|
||||
- [List PRs Awaiting Your Review](github/list-prs-awaiting-your-review.md)
|
||||
- [Open A PR To An Unforked Repo](github/open-a-pr-to-an-unforked-repo.md)
|
||||
- [Open File To Specific Line In Browser](github/open-file-to-specific-line-in-browser.md)
|
||||
- [Process JSON Output From gh With jq](github/process-json-output-from-gh-with-jq.md)
|
||||
- [Rerun Failed Jobs For Current Branch](github/rerun-failed-jobs-for-current-branch.md)
|
||||
- [Target Another Repo When Creating A PR](github/target-another-repo-when-creating-a-pr.md)
|
||||
- [Tell gh What The Default Repo Is](github/tell-gh-what-the-default-repo-is.md)
|
||||
|
||||
@@ -495,6 +499,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Disable A Workflow With The gh CLI](github-actions/disable-a-workflow-with-the-gh-cli.md)
|
||||
- [Reference An Encrypted Secret In An Action](github-actions/reference-an-encrypted-secret-in-an-action.md)
|
||||
- [Run Schedule Action To Commit Regular Updates](github-actions/run-scheduled-action-to-commit-regular-updates.md)
|
||||
- [Set Repository Secret From CLI](github-actions/set-repository-secret-from-cli.md)
|
||||
- [Trigger A Workflow Via An API Call](github-actions/trigger-a-workflow-via-an-api-call.md)
|
||||
- [Use Labels To Block PR Merge](github-actions/use-labels-to-block-pr-merge.md)
|
||||
|
||||
@@ -1873,6 +1878,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Make Neovim The Default Way To View Man Pages](unix/make-neovim-the-default-way-to-view-man-pages.md)
|
||||
- [Manually Pass Two Git Files To Delta](unix/manually-pass-two-git-files-to-delta.md)
|
||||
- [Map A Domain To localhost](unix/map-a-domain-to-localhost.md)
|
||||
- [Merge A Sequence Of Lines Of Output](unix/merge-a-sequence-of-lines-of-output.md)
|
||||
- [Move A List Of Files To Another Directory](unix/move-a-list-of-files-to-another-directory.md)
|
||||
- [Negative Look-Ahead Search With ripgrep](unix/negative-look-ahead-search-with-ripgrep.md)
|
||||
- [Occupy A Local Port With Netcat](unix/occupy-a-local-port-with-netcat.md)
|
||||
@@ -1893,6 +1899,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Rename A Bunch Of Files By Constructing mv Commands](unix/rename-a-bunch-of-files-by-constructing-mv-commands.md)
|
||||
- [Repeat Yourself](unix/repeat-yourself.md)
|
||||
- [Replace Pattern Across Many Files In A Project](unix/replace-pattern-across-many-files-in-a-project.md)
|
||||
- [Restart Process Managed By `process-compose`](unix/restart-process-managed-by-process-compose.md)
|
||||
- [Restart Specific Overmind Process](unix/restart-specific-overmind-process.md)
|
||||
- [Reverse Each Line Of A File](unix/reverse-each-line-of-a-file.md)
|
||||
- [Run A Command Repeatedly Several Times](unix/run-a-command-repeatedly-several-times.md)
|
||||
@@ -2144,6 +2151,7 @@ If you've learned something here, support my efforts writing daily TILs by
|
||||
- [Change Window Name In iTerm](workflow/change-window-name-in-iterm.md)
|
||||
- [Configure Email Redirect With Cloudflare](workflow/configure-email-redirect-with-cloudflare.md)
|
||||
- [Control Media With Drop Keyboard](workflow/control-media-with-drop-keyboard.md)
|
||||
- [Create 1Password Login Item From The CLI](workflow/create-1password-login-item-from-the-cli.md)
|
||||
- [Convert An ePub Document To PDF On Mac](workflow/convert-an-epub-document-to-pdf-on-mac.md)
|
||||
- [Create A Local Sanity Dataset Backup](workflow/create-a-local-sanity-dataset-backup.md)
|
||||
- [Create A Public URL For A Local Server](workflow/create-a-public-url-for-a-local-server.md)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# Pick Up Session Locally That Started In Cloud
|
||||
|
||||
I've been enjoying using _Claude Code_ from the iOS and MacOS apps for various
|
||||
side tasks recently. For smaller things I can usually get most of the way there
|
||||
from the app. And eventually I pull down the branch or have Claude create a PR
|
||||
that I can review.
|
||||
|
||||
Sometimes I want to transfer the session onto my computer to pick up where it
|
||||
left off for various reasons (e.g. I want the session to have access to some
|
||||
local data or specific dependencies).
|
||||
|
||||
The `claude` CLI has a flag for that — `--teleport`.
|
||||
|
||||
> Resume a teleport session, optionally specify session ID
|
||||
|
||||
```
|
||||
❯ claude --teleport
|
||||
|
||||
Select a session to resume (jbranchaud/still):
|
||||
|
||||
Updated Session Title
|
||||
❯ 1. 21m ago Blogmark link search modal
|
||||
2. 11h ago Mobile feed reader margins
|
||||
3. 11h ago Feed pagination with Pagy
|
||||
4. 1d ago RSS feed highlights and annotations
|
||||
5. 1d ago RSS feed categories
|
||||
6. 3d ago Blogmarks image drag-and-drop upload
|
||||
|
||||
↑/↓ to select · Enter to confirm · Esc to cancel
|
||||
```
|
||||
|
||||
This is similar to how `--resume` works, but it is for a session that was
|
||||
previously running in the cloud.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Show Full URLs With Print Styles
|
||||
|
||||
Web pages are best experienced in a browser where you can fully interact with
|
||||
them. Links, for instance, can be hovered, inspected, and clicked on to navigate
|
||||
to the target location -- that's a core part of the web browser experience and
|
||||
what makes the internet.
|
||||
|
||||
Some people have printers though and they want to be able to print off web
|
||||
pages. Any web page can be printed off as is, but if your site or app is
|
||||
anticipating certain pages being printed, then you may add some
|
||||
`@print`-specific CSS styling to improve how it looks in print format.
|
||||
|
||||
Links are a prime example of lost interactivity. When printed, links render as
|
||||
blue underlined text with no way to know what they are linking to. One trick
|
||||
that I recently picked up from [this lobste.rs thread](https://lobste.rs/s/olnqh2/websites_should_be_printable#c_wigxfy) is to
|
||||
add _after content_ that renders the actual, full URL next to the link.
|
||||
|
||||
```css
|
||||
@media print
|
||||
{
|
||||
a[href]::after
|
||||
{
|
||||
content: " [" attr(href) "]";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This means that when a page has `<a href="https://still.visualmode.dev">still</a>`, the printed version will not
|
||||
just render the word "still", but will be styled to render `still [https://still.visualmode.dev]`.
|
||||
|
||||
This will add content after links for both absolute URLs and relative paths (and
|
||||
anchor tags). If I wanted to limit the after content to only show absolute URLs,
|
||||
I could add a bit more specificity to the matching tag.
|
||||
|
||||
```css
|
||||
@media print
|
||||
{
|
||||
a[href^="http"]::after
|
||||
{
|
||||
content: " [" attr(href) "]";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `^=` matches the pattern of `http` on the start of the `href` string which
|
||||
means it will only display absolute URLs.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Set Repository Secret From CLI
|
||||
|
||||
I set up a GitHub Action that will run daily and potentially push data up to a
|
||||
3rd-party API. To be able to post to that API, the action must include a secret
|
||||
as the bearer token in the requests. I need to securely include that secret in
|
||||
the GitHub Actions environment for this repo.
|
||||
|
||||
I can do that from the CLI with `gh` like so:
|
||||
|
||||
```bash
|
||||
❯ gh secret set TIL_SYNC_TOKEN
|
||||
? Paste your secret: ****************************************************************
|
||||
```
|
||||
|
||||
Notice that it prompts me for the secret and stars out what I paste in. That way
|
||||
the secret doesn't end up in my bash history and isn't visible on my screen.
|
||||
|
||||
After I've run this, I can see that the secret is set by opening up the repo in
|
||||
the GitHub web UI, clicking on _Settings_ > _Secrets and Variables_ > _Actions_.
|
||||
I should see `TIL_SYNC_TOKEN` listed under the _Repository Secrets_ section.
|
||||
|
||||
Here is an excerpt from my workflow action sync script where that secret is
|
||||
referenced -- notice the `${{ secrets.TIL_SYNC_TOKEN }}`.
|
||||
|
||||
```yaml
|
||||
- name: Sync posts
|
||||
env:
|
||||
TIL_SYNC_URL: ${{ vars.TIL_SYNC_URL }}
|
||||
TIL_SYNC_TOKEN: ${{ secrets.TIL_SYNC_TOKEN }}
|
||||
run: ruby script/til_sync/til_sync.rb --repo til ${{ inputs.all && '--all' || '--days 3' }}
|
||||
```
|
||||
@@ -0,0 +1,34 @@
|
||||
# Create A Private Repo From The CLI
|
||||
|
||||
The vast majority of the GitHub repos that I've created over my career have been
|
||||
done from the web UI. It was only recently that I found out that [I can create a
|
||||
new repo from the CLI with `gh`](create-and-push-to-new-repo-from-cli.md).
|
||||
|
||||
A repo can be created for the current directory (where a local git repo already
|
||||
exists) using the `gh repo create` command. I'm wanting this to be a private
|
||||
repo so I can include the `--private` flag instead of the `--public` flag.
|
||||
|
||||
```bash
|
||||
❯ gh repo create marathon-training --private --source=. --remote=origin --push
|
||||
✓ Created repository jbranchaud/marathon-training on github.com
|
||||
https://github.com/jbranchaud/marathon-training
|
||||
✓ Added remote https://github.com/jbranchaud/marathon-training.git
|
||||
Enumerating objects: 125, done.
|
||||
Counting objects: 100% (125/125), done.
|
||||
Delta compression using up to 16 threads
|
||||
Compressing objects: 100% (114/114), done.
|
||||
Writing objects: 100% (125/125), 56.69 KiB | 14.17 MiB/s, done.
|
||||
Total 125 (delta 52), reused 0 (delta 0), pack-reused 0 (from 0)
|
||||
remote: Resolving deltas: 100% (52/52), done.
|
||||
To https://github.com/jbranchaud/marathon-training.git
|
||||
* [new branch] HEAD -> main
|
||||
branch 'main' set up to track 'origin/main' by rebasing.
|
||||
✓ Pushed commits to https://github.com/jbranchaud/marathon-training.git
|
||||
```
|
||||
|
||||
Since I am running this command from the root directory of the git-backed
|
||||
project, I specify the `--source` as `.` (mean _here_, the current directory).
|
||||
The remaining flags tell it what the remote should be set up as and that I want
|
||||
to push this local repo up to the GitHub remote once it is created.
|
||||
|
||||
See `gh repo create --help` for more details.
|
||||
@@ -0,0 +1,30 @@
|
||||
# Rerun Failed Jobs For Current Branch
|
||||
|
||||
I have a branch that I've already opened a PR for. I've made more changes, run
|
||||
the tests, and pushed up the latest to the remote. I know the tests should have
|
||||
been green, but I'm seeing a flickering test fail in CI. I want to retrigger the
|
||||
relevant failed jobs to see if I can get the flickers to pass.
|
||||
|
||||
First, I need to figure out the workflow ID with any failed jobs.
|
||||
|
||||
```bash
|
||||
❯ gh run list --branch "$(git branch --show-current)" --status failure
|
||||
STATUS TITLE WORKFLOW BRANCH EVENT ID ELAPSED AGE
|
||||
X Better comp... Ruby on R... jbranchau... pull_request 38778306948 10m54s about 25 ...
|
||||
```
|
||||
|
||||
This one-liner does that by referencing the current branch (via `git`) and then
|
||||
asking `gh` to list failed workflows associated with that branch.
|
||||
|
||||
Grabbing the `ID` value, I can then ask `gh` to rerun failed jobs for that
|
||||
workflow.
|
||||
|
||||
```bash
|
||||
❯ gh run rerun 38778306948 --failed
|
||||
✓ Requested rerun (failed jobs) of run 38778306948
|
||||
```
|
||||
|
||||
Opening that PR up in the browser, I can see that the specific workflow has been
|
||||
rerun and is currently _in progress_.
|
||||
|
||||
See `gh run list --help` and `gh run rerun --help` for more details.
|
||||
@@ -0,0 +1,42 @@
|
||||
# Merge A Sequence Of Lines Of Output
|
||||
|
||||
More often than not when I'm chaining a sequence of Unix commands together, I'm
|
||||
eventually trying to fan them out or execute each argument separately. I
|
||||
recently had the need for a bunch of separate lines of output to be fanned back
|
||||
in to a single line.
|
||||
|
||||
The tool I found for this job is `paste` (not the most intuitive name).
|
||||
|
||||
> merge corresponding or subsequent lines of files
|
||||
|
||||
I was listing out all the categories that my active [TIL posts](https://github.com/jbranchaud/til) full under. I used the following
|
||||
command to do that.
|
||||
|
||||
```bash
|
||||
❯ git ls-files '*/*.md' | cut -d/ -f1 | sort -u
|
||||
ack
|
||||
ansible
|
||||
astro
|
||||
aws
|
||||
bash
|
||||
brew
|
||||
chrome
|
||||
...
|
||||
```
|
||||
|
||||
Those are all my categories, but then the format I really wanted was for them to
|
||||
be all on the same line with a clear delimiter so that I could paste them for
|
||||
[use in another script](/llm/translate-to-canonical-tags-with-small-model.md).
|
||||
|
||||
The trick is to tack on one more pipe to `paste`. The `-s` tells `paste` to join
|
||||
every line from a given input file (e.g. stdin) onto a single line. The `-d`
|
||||
allows for overriding the default delimiter (tab) with something like a `,`.
|
||||
Lastly, the trailing `-` tells `paste` to read from stdin rather than some other
|
||||
named file(s).
|
||||
|
||||
```bash
|
||||
❯ git ls-files '*/*.md' | cut -d/ -f1 | sort -u | paste -sd, -
|
||||
ack,ansible,astro,aws,bash,brew,chrome,claude-code,clojure,css,cursor,deno,devops,docker,drizzle,elixir,gatsby,git,github,github-actions,go,groq,heroku,html,http,inngest,internet,java,javascript,jj,jq,kitty,linux,llm,mac,math,mise,mongodb,mysql,neovim,netlify,next-auth,nextjs,phoenix,planetscale,pnpm,postgres,prisma,python,rails,react,react_native,react-testing-library,reason,remix,rspec,ruby,sed,shell,sqlite,streaming,tailwind,taskfile,tmux,typescript,unix,vercel,vim,vscode,webpack,workflow,xstate,yaml,zed,zod,zsh
|
||||
```
|
||||
|
||||
See `man paste` for more details.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Restart Process Managed By `process-compose`
|
||||
|
||||
I'm working on a project where we are experimenting with
|
||||
[`process-compose`](https://github.com/F1bonacc1/process-compose) as a better
|
||||
way orchestrate a set of processes that all need to be running for a web
|
||||
development server (Rails) to work. This includes the Rails server itself, a
|
||||
JavaScript build process, PostgreSQL, a background worker process, etc.
|
||||
|
||||
In the past [I've used `overmind` with
|
||||
Procfiles](/rails/run-dev-processes-with-overmind-instead-of-foreman.md) to do a
|
||||
similar sort of thing. No matter what tooling is in play, from time to time, I
|
||||
will eventually need to restart one of the processes that has become stale.
|
||||
|
||||
The `vite` (JavaScript build) process is a good example of this. Configuration
|
||||
changes, new `npm` dependencies, and tailwind classes on new files can all lead
|
||||
to the build being stale.
|
||||
|
||||
From the `process-compose` TUI, I can navigate the cursor over the `vite`
|
||||
process and hit `Ctrl-r` to restart the process.
|
||||
|
||||
I can also issue a restart via the CLI like so:
|
||||
|
||||
```
|
||||
❯ mise exec -- process-compose process restart vite
|
||||
Process vite restarted
|
||||
```
|
||||
|
||||
[source](https://f1bonacc1.github.io/process-compose/cli/process-compose_process_restart/)
|
||||
@@ -0,0 +1,38 @@
|
||||
# Create 1Password Login Item From The CLI
|
||||
|
||||
The default shape of a login item in 1Password is _Username_ and _Password_.
|
||||
Whenever I'm trying to save something in 1Password, like an AWS Access Key for
|
||||
example, I find myself manually adjusting the fields to get it into the right
|
||||
shape for that item.
|
||||
|
||||
What I realized would be nicer is using [`op` (the 1Password
|
||||
CLI)](https://www.1password.dev/cli) to create a login item with the shape I
|
||||
want (which I can later reference in my shell history). Then I can pop open the
|
||||
desktop app and update the latest entry with the actually secret values that I
|
||||
copy from, in this case, the AWS Console.
|
||||
|
||||
```bash
|
||||
❯ op item create --vault "Personal" --category login --title "AWS - jbranchaud-lastword-cli" \
|
||||
'Access Key ID[text]=TODO' \
|
||||
'Secret Access Key[concealed]=TODO' \
|
||||
'Default region[text]=us-east-1'
|
||||
ID: abc123
|
||||
Title: AWS - jbranchaud-lastword-cli
|
||||
Vault: Personal (efg456)
|
||||
Created: now
|
||||
Updated: now
|
||||
Favorite: false
|
||||
Version: 1
|
||||
Category: LOGIN
|
||||
Fields:
|
||||
Access Key ID: TODO
|
||||
Secret Access Key: [use 'op item get abc123 --reveal' to reveal]
|
||||
Default region: us-east-1
|
||||
```
|
||||
|
||||
In this command I point to my `Personal` vault, I update the title of the login
|
||||
item inline, and then I have some custom fields on the item that match the shape
|
||||
of this scenario.
|
||||
|
||||
When I hit enter, a listing of fields is output. I can then hop over to the
|
||||
desktop app to set the actually ID and secret for the access key.
|
||||
Reference in New Issue
Block a user