30 Commits

Author SHA1 Message Date
Peter Schilling 12860b253c ci: pin deno to 2.7.9 in the release and publish pipelines
027f25e pinned deno to 2.7.9 in mise.toml and ci.yaml, but the two workflows
that actually build and ship artifacts were left on 'v2.x': release.yml runs
'deno compile' for every target triple, and publish.yaml runs codegen before
'jsr publish'. So the binaries users install were produced by whatever v2.x
resolved to at build time, not the toolchain the project pins and tests on.

build-setup.yml is the dist 'github-build-setup' hook that generates the deno
step in release.yml, so it and the generated line are updated together to keep
'dist generate' a no-op.

setup-deno@v2 already runs an exact 2.7.9 in both ci.yaml jobs, so this is the
version resolution those jobs have been proving all along.
2026-07-14 22:10:47 -07:00
Peter Schilling d1beb924e4 fix(test): skip keyring integration test when the macOS keychain is locked
isKeyringAvailable() only probed on Linux and returned true unconditionally
everywhere else, so on macOS the keyring round-trip always attempted a real
write. Under ssh or an agent shell the login keychain has no UI session to
unlock it, so 'security add-generic-password' fails with exit 36
(errSecInteractionNotAllowed) and 'deno task test' fails locally even though
nothing is wrong with the code.

Probe with 'security show-keychain-info', which is read-only and returns 36 in
exactly that state. A read-only probe is not enough on its own: reads still
succeed while locked (find-generic-password returns 44), so only a
write-capable check detects it. The guard keys on 36 specifically rather than
any nonzero exit, so a genuine keyring bug still fails the test loudly.

CI is unaffected: its macOS keychain is unlocked, and the keyring job now sets
LINEAR_KEYRING_INTEGRATION=1 to force the test to run, so a probe that ever
wrongly reports 'unavailable' cannot quietly turn that job into a no-op.
2026-07-14 22:10:09 -07:00
schpetbot f7922d4121 ci: drop skill docs staleness check, keep generation smoke test (#218)
The skill docs check was failing because `Deno.consoleSize()` returns
different values depending on the runner's pseudo-terminal dimensions
(CI is wide, local terminals vary). Since the docs are for LLM
consumption and not correctness, dropping the `git diff` check and just
verifying generation doesn't crash.

Co-authored-by: Alex Broekhof <alex@quilt.com>
Co-authored-by: Peter Schilling <code@schpet.com>
2026-05-15 03:54:40 +00:00
Peter Schilling 027f25e30c chore: pin deno to 2.7.9 via mise.toml and ci workflow 2026-05-13 20:51:13 -07:00
Ben Drucker b8a7e54854 feat: store API keys in the system keyring (#136)
Move API key storage from plaintext TOML to OS-native keyrings (macOS
Keychain, Linux `libsecret`, Windows Credential Manager). The
credentials file retains only workspace metadata. Keys are loaded into
an in-memory cache at startup so all downstream reads remain synchronous
— no changes needed to any command files.

## Changes

### Keyring (`src/keyring/`)

- Platform-detecting wrapper with `getPassword`, `setPassword`,
`deletePassword` exports
- macOS: `/usr/bin/security` (exit 44 = not found)
- Linux: `secret-tool` via stdin for writes (exit 1 = not found)
- Windows: `Deno.dlopen("advapi32.dll")` FFI calling
`CredReadW`/`CredWriteW`/`CredDeleteW` directly
- `_setBackend()` test seam for injecting an in-memory `Map` backend

### Windows Credential Manager via FFI

The Windows backend calls `advapi32.dll` directly via Deno's FFI
(`Deno.dlopen`) rather than shelling out to PowerShell. This matches the
standard approach taken by every comparable credential tool:

-
[`danieljoos/wincred`](https://github.com/danieljoos/wincred/blob/623325312d3224d48d131159187b93e906216563/sys.go)
— Go library calling `advapi32.dll` via `windows.NewLazySystemDLL`, used
by:
-
[`docker-credential-helpers`](https://github.com/docker/docker-credential-helpers/blob/2b4e08bca3dbdb8e6c6e28790042742d0c0fc48f/wincred/wincred.go)
- [`gh`
CLI](https://github.com/cli/cli/blob/2c54a0d36a2f3c9c1f1b869a64120837c3a1e6f5/internal/keyring/keyring.go)
(via
[`zalando/go-keyring`](https://github.com/zalando/go-keyring/blob/5c6f7e0ba54d20daa8ea4e03f7ce0a27c075bfb6/keyring_windows.go))
-
[`aws-vault`](https://github.com/99designs/aws-vault/blob/70522e8f0b8f9c5b4e2e4e1e1e1cc4e3e5c3f04c/go.mod)
(via `99designs/keyring`)
-
[`node-keytar`](https://github.com/atom/node-keytar/blob/deae59a488789f2cd4a8dba6c7e58665795804fe/src/keytar_win.cc)
— C++ N-API addon, `#include <wincred.h>`
-
[`jaraco/keyring`](https://github.com/jaraco/keyring/blob/38c040133559682902f25fe96496756ee6849820/keyring/backends/Windows.py)
— Python, `win32cred` (pywin32-ctypes wrapping advapi32 via ctypes)

The implementation packs the 80-byte `CREDENTIALW` struct manually via
`DataView`, encodes strings as UTF-16LE for the `W`-suffix APIs, and
uses `GetLastError` from `kernel32.dll` to distinguish "not found"
(`ERROR_NOT_FOUND` = 1168) from real failures. DLLs are lazy-loaded so
the module import doesn't fail on macOS/Linux.

### Credentials (`src/credentials.ts`)

- `Credentials` interface changed from index signature to `{ default?:
string; workspaces: string[] }`
- `apiKeyCache` `Map` populated at startup, keeping
`getCredentialApiKey()` sync
- `addCredential`/`removeCredential` write to keyring first, only mutate
local state on success
- `parseInlineCredentials` / `parseKeyringCredentials` /
`populateKeyringCache` extracted from `loadCredentials`
- Parallel keyring lookups via `Promise.all`
- Malformed TOML parse errors caught with recovery guidance
- Warnings for: missing keyring entries, dangling default workspace,
inline format detected

### Backward Compatibility

- Inline-format TOML files (keys stored as `workspace = "lin_api_..."`)
are detected by `hasInlineKeys` and served from the file directly
- `addCredential` on an inline-format installation rewrites the file to
keyring format

### Auth List (`src/commands/auth/auth-list.ts`)

- Replaces removed `getAllCredentials()` with `getApiKeyForWorkspace()`
- Distinguishes auth errors (401/403) from network/other failures
instead of labeling everything "invalid credentials"

### CI

- Added `keyring-integration` job on `macos-latest` and `windows-latest`
for real credential round-trip testing

## Testing

- Subprocess isolation via `deno eval` for credential tests (required by
top-level `await loadCredentials()`)
- Mock keyring backend injected via `_setBackend` — covers happy paths,
error propagation, and cache consistency
- Integration test (`test/keyring.integration.test.ts`) exercises the
real macOS Keychain and Windows Credential Manager lifecycle
- Edge cases covered: keyring write/delete failures leave state
unchanged, null keyring returns warn but don't crash, dangling default
dropped on load, inline→keyring format transition on `addCredential`

## References

Closes #130

---------

Co-authored-by: Peter Schilling <code@schpet.com>
2026-03-10 22:03:52 -07:00
Peter Schilling dbebd16319 feat: add npm installer and publish job for @schpet/linear-cli 2026-03-06 21:39:27 +00:00
Peter Schilling f319866efa chore: bump cargo-dist to 0.31.0 and regenerate CI 2026-03-04 20:34:14 -08:00
Dan Wager 1f6b6ac2e3 fix: move build-setup.yml out of workflows dir 2026-03-04 20:25:14 -08:00
Peter Schilling 1a6dcb0fb4 Add CI check for skill docs and update documentation
- Add CI workflow step to verify generated skill docs are up-to-date
- Add development section to README with instructions for:
  - Updating skill documentation with deno task generate-skill-docs
  - Running code formatting with deno fmt
- Update generate-docs.ts to automatically format generated files
- Regenerate skill docs to ensure they match current CLI version

Fixes #135
2026-02-12 08:03:29 -08:00
Peter Schilling 1e4c6e354d chore: fix formatting in publish.yaml 2026-01-29 05:53:25 +00:00
Peter Schilling 39b6405c37 fix: trigger JSR publish on version tags instead of every push 2026-01-29 05:53:03 +00:00
Peter Schilling c752abaf24 chore: remove duplicate ci.yml (ci.yaml already exists) 2026-01-29 05:51:19 +00:00
Peter Schilling 992f05afe1 fix: add type annotations and CI workflow for type checking
- Add explicit type annotations to team-list.ts and project-list.ts to fix implicit any errors
- Add CI workflow (.github/workflows/ci.yml) that runs type check, format, lint, and tests on PRs
- Update justfile to use 'deno check src/main.ts' instead of '--all' to avoid npm dependency type errors
2026-01-29 05:48:54 +00:00
peter schilling 51ff1b2db6 Add 'issue commits' command (jj-vcs only) (#79)
use case: 

- you are addressing feedback on an issue ABC-123
- run `linear issue start 123` to re-start that issue
- fire up claude code
- run `! linear issue view` to drop the issue, and comments into context
- run `! linear issue commits` to dump the diff of previous work into
context
- ask claude to address the feedback (it will have a much better shot of
knowing what you are talking about)
2025-12-14 08:33:34 -08:00
Peter Schilling fe469cc6d5 upgrade cargo dist to latest 2025-12-02 22:38:06 -08:00
Peter Schilling 85591f8c2c Cache Rust build in release workflow to speed builds and reuse artifacts
Claude-session-id: b7feff7e-b2b9-4051-bbcc-98b5323cc412
2025-12-02 22:38:06 -08:00
Peter Schilling 24cfbc1ca9 run ci on PRs 2025-11-23 22:20:22 -08:00
Peter Schilling 93251900ec Organize code (#46) 2025-08-14 06:38:40 -07:00
Peter Schilling 2ea8138cf4 feat: Use graphql codegen to ensure linear api data has types (#34)
CLI-5
2025-08-11 22:48:29 -07:00
Peter Schilling b8828da219 Handle long team ids, Improve error output (#29)
- improves error output to be pretty json
- handles longer team ids
- adds a script to update linear's graphql schema
- adds tests
2025-06-17 22:02:01 -07:00
Peter Schilling 7459003755 chore: Release linear-cli version 0.5.7 2025-05-22 07:40:39 -07:00
Peter Schilling e2b4ff5ca4 chore: Release linear-cli version 0.5.6 2025-05-22 07:27:26 -07:00
Peter Schilling 9137cf3cdf Switch dist to fork: astral-sh/cargo-dist (#28) 2025-05-21 21:39:07 -07:00
Peter Schilling 5928955e72 use ubuntu latest instead of deprecated 20.04 2025-05-20 11:32:52 -07:00
Peter Schilling f65d4efc9e chore: Update release.yml 2025-01-31 14:42:19 -08:00
Peter Schilling ec3f6c9ba4 chore: Setup cargo dist (#6) 2025-01-31 14:38:49 -08:00
Peter Schilling df1eb18246 Build for x86 mac, and windows 2024-11-28 07:37:49 -08:00
Peter Schilling ef263755ef Add checkout step to release workflow to fix git repository access 2024-11-28 07:33:01 -08:00
Peter Schilling bf3e434206 Compile binaries (#4) 2024-11-28 07:30:10 -08:00
Peter Schilling 03ba7c9ed7 Basic features 2024-11-23 07:08:53 -08:00