codealmanac 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -6
- package/dist/agents-4Y7X24WW.js +25 -0
- package/dist/chunk-BF2J4XTC.js +766 -0
- package/dist/chunk-BF2J4XTC.js.map +1 -0
- package/dist/{chunk-B2AGSRXL.js → chunk-CW4HRLMS.js} +88 -7
- package/dist/chunk-CW4HRLMS.js.map +1 -0
- package/dist/{chunk-P3LDTCLB.js → chunk-H37GKBWI.js} +13 -1
- package/dist/chunk-H37GKBWI.js.map +1 -0
- package/dist/{chunk-MX2EW5MR.js → chunk-H6QKCB7M.js} +2 -2
- package/dist/{chunk-QQHIVTXT.js → chunk-MRRX4UQB.js} +4 -4
- package/dist/{chunk-QQHIVTXT.js.map → chunk-MRRX4UQB.js.map} +1 -1
- package/dist/chunk-P5WGG4FJ.js +359 -0
- package/dist/chunk-P5WGG4FJ.js.map +1 -0
- package/dist/{chunk-ZDJSJIB6.js → chunk-QRK3JLFX.js} +131 -15
- package/dist/chunk-QRK3JLFX.js.map +1 -0
- package/dist/{chunk-V3QOQSXI.js → chunk-TILAKDN6.js} +14 -8
- package/dist/chunk-TILAKDN6.js.map +1 -0
- package/dist/chunk-TT6ZP4GS.js +282 -0
- package/dist/chunk-TT6ZP4GS.js.map +1 -0
- package/dist/chunk-UU6FBRQO.js +187 -0
- package/dist/chunk-UU6FBRQO.js.map +1 -0
- package/dist/{cli-3XAVBTYG.js → cli-MYMZ66EN.js} +123 -32
- package/dist/cli-MYMZ66EN.js.map +1 -0
- package/dist/codealmanac.js +1 -1
- package/dist/config-ML2RCR7J.js +16 -0
- package/dist/{doctor-3BYSF3JD.js → doctor-W5KQQLAX.js} +6 -6
- package/dist/{register-commands-7QCIENRZ.js → register-commands-XTK2G2FB.js} +293 -393
- package/dist/register-commands-XTK2G2FB.js.map +1 -0
- package/dist/{uninstall-FDIOBAAR.js → uninstall-N7JY7ZV2.js} +5 -5
- package/dist/{update-RAF7QRYF.js → update-P2IPG7RO.js} +3 -3
- package/guides/mini.md +1 -1
- package/guides/reference.md +68 -9
- package/package.json +1 -1
- package/dist/agents-A4II4YJC.js +0 -15
- package/dist/auth-S5DVUIUJ.js +0 -18
- package/dist/chunk-B2AGSRXL.js.map +0 -1
- package/dist/chunk-P3LDTCLB.js.map +0 -1
- package/dist/chunk-R3URPHGH.js +0 -194
- package/dist/chunk-R3URPHGH.js.map +0 -1
- package/dist/chunk-SSYMRT4I.js +0 -126
- package/dist/chunk-SSYMRT4I.js.map +0 -1
- package/dist/chunk-V3QOQSXI.js.map +0 -1
- package/dist/chunk-WRUSDYYE.js +0 -97
- package/dist/chunk-WRUSDYYE.js.map +0 -1
- package/dist/chunk-ZDJSJIB6.js.map +0 -1
- package/dist/cli-3XAVBTYG.js.map +0 -1
- package/dist/register-commands-7QCIENRZ.js.map +0 -1
- /package/dist/{agents-A4II4YJC.js.map → agents-4Y7X24WW.js.map} +0 -0
- /package/dist/{chunk-MX2EW5MR.js.map → chunk-H6QKCB7M.js.map} +0 -0
- /package/dist/{auth-S5DVUIUJ.js.map → config-ML2RCR7J.js.map} +0 -0
- /package/dist/{doctor-3BYSF3JD.js.map → doctor-W5KQQLAX.js.map} +0 -0
- /package/dist/{uninstall-FDIOBAAR.js.map → uninstall-N7JY7ZV2.js.map} +0 -0
- /package/dist/{update-RAF7QRYF.js.map → update-P2IPG7RO.js.map} +0 -0
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
removeImportLine,
|
|
4
4
|
runUninstall
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-H6QKCB7M.js";
|
|
6
|
+
import "./chunk-QRK3JLFX.js";
|
|
7
7
|
import "./chunk-447U3GQJ.js";
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
import "./chunk-BF2J4XTC.js";
|
|
9
|
+
import "./chunk-P5WGG4FJ.js";
|
|
10
10
|
import "./chunk-7JUX4ADQ.js";
|
|
11
11
|
export {
|
|
12
12
|
removeImportLine,
|
|
13
13
|
runUninstall
|
|
14
14
|
};
|
|
15
|
-
//# sourceMappingURL=uninstall-
|
|
15
|
+
//# sourceMappingURL=uninstall-N7JY7ZV2.js.map
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runUpdate
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MRRX4UQB.js";
|
|
5
5
|
import "./chunk-F53U6JQG.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-P5WGG4FJ.js";
|
|
7
7
|
import "./chunk-7JUX4ADQ.js";
|
|
8
8
|
export {
|
|
9
9
|
runUpdate
|
|
10
10
|
};
|
|
11
|
-
//# sourceMappingURL=update-
|
|
11
|
+
//# sourceMappingURL=update-P2IPG7RO.js.map
|
package/guides/mini.md
CHANGED
|
@@ -69,7 +69,7 @@ Returns slugs, one per line. Pipe-friendly. Filters AND-intersect.
|
|
|
69
69
|
|
|
70
70
|
```bash
|
|
71
71
|
almanac show checkout-flow # metadata header + body (default)
|
|
72
|
-
almanac show checkout-flow --
|
|
72
|
+
almanac show checkout-flow --body # body only
|
|
73
73
|
almanac show checkout-flow --meta # metadata only
|
|
74
74
|
almanac show checkout-flow --lead # first paragraph (cheap preview)
|
|
75
75
|
almanac show checkout-flow --backlinks # pages linking TO this one
|
package/guides/reference.md
CHANGED
|
@@ -49,7 +49,8 @@ Unified reader. Absorbs the old `info` and `path` commands — pick fields with
|
|
|
49
49
|
| `--stdin` | false | Read slugs from stdin, one per line. JSON Lines output for `--json` mode. |
|
|
50
50
|
| `--wiki <name>` | current repo | Target a specific registered wiki. |
|
|
51
51
|
| `--json` | false | Structured JSON. Overrides every view/field flag. |
|
|
52
|
-
| `--
|
|
52
|
+
| `--body` | false | Body only. Guarantees exactly one trailing newline — shell redirect produces a well-formed file. |
|
|
53
|
+
| `--raw` | false | Deprecated alias for `--body`; still accepted for compatibility. |
|
|
53
54
|
| `--meta` | false | Metadata header only, no body. |
|
|
54
55
|
| `--lead` | false | First paragraph of the body only (cheap preview). |
|
|
55
56
|
| `--title` | false | Print title. |
|
|
@@ -117,7 +118,7 @@ All topic subcommands accept `--wiki <name>`. `list` / `show` accept `--json`.
|
|
|
117
118
|
|
|
118
119
|
#### `almanac bootstrap`
|
|
119
120
|
|
|
120
|
-
Spawns an agent to create initial wiki stubs. Requires
|
|
121
|
+
Spawns an agent to create initial wiki stubs. Requires the selected provider to be installed and logged in. `--quiet` suppresses per-tool streaming. `--agent <provider>` overrides the provider for this run. `--model <model>` overrides the provider-local model. `--json` emits a structured `CommandOutcome` and suppresses streaming. `--force` overwrites an existing populated wiki. Writes `.almanac/logs/.bootstrap-<timestamp>.log`.
|
|
121
122
|
|
|
122
123
|
Bootstrap is the scaffolding path — it creates `.almanac/pages/`, `.almanac/topics.yaml`, `.almanac/README.md`, and stub entity pages based on what the agent reads in the repo.
|
|
123
124
|
|
|
@@ -130,7 +131,9 @@ Run the writer/reviewer pipeline on a Claude Code session transcript. Usually au
|
|
|
130
131
|
| `[transcript]` | Explicit path. Falls back to `--session` match or most-recent-by-cwd. |
|
|
131
132
|
| `--session <id>` | Target a specific session by ID. Matches filename under `~/.claude/projects/`. |
|
|
132
133
|
| `--quiet` | Suppress per-tool streaming; print only the final summary. |
|
|
134
|
+
| `--agent <provider>` | Override the configured provider for this run. |
|
|
133
135
|
| `--model <model>` | Override the agent model. |
|
|
136
|
+
| `--json` | Emit a structured `CommandOutcome`; suppresses streaming so stdout is parseable. |
|
|
134
137
|
|
|
135
138
|
Writes SDK transcript to `.almanac/logs/.capture-<session-id>.jsonl` (one JSON message per line). When invoked manually without `--session`, falls back to `.capture-<timestamp>.jsonl` so repeated runs don't clobber each other. A writer subagent drafts pages; a reviewer subagent enforces notability + writing conventions (§9) before drafts land.
|
|
136
139
|
|
|
@@ -153,10 +156,12 @@ Install the SessionEnd hook + the two CLAUDE.md guides (`codealmanac.md`, `codea
|
|
|
153
156
|
| Flag | Semantics |
|
|
154
157
|
|---|---|
|
|
155
158
|
| `-y, --yes` | Skip prompts; install everything. |
|
|
159
|
+
| `--agent <agent>` | Set the default provider. Accepts `claude`, `codex`, `cursor`, or optional shorthand like `claude/opus`. |
|
|
160
|
+
| `--model <model>` | Set the provider-local model during setup. Non-interactive equivalent of the model picker. |
|
|
156
161
|
| `--skip-hook` | Opt out of the SessionEnd hook. |
|
|
157
162
|
| `--skip-guides` | Opt out of the CLAUDE.md guides. |
|
|
158
163
|
|
|
159
|
-
Both `almanac setup` and bare `codealmanac` route here. `codealmanac --yes`, `codealmanac --skip-hook`, and `codealmanac --skip-guides` are the typical first-run invocations. Passing `--skip-hook --skip-guides` together short-circuits with a terse line — nothing was installed, no banner drawn.
|
|
164
|
+
Both `almanac setup` and bare `codealmanac` route here. Interactive setup chooses provider first, then provider-local model. `codealmanac --yes`, `codealmanac --agent codex --model gpt-5.3-codex`, `codealmanac --skip-hook`, and `codealmanac --skip-guides` are the typical first-run invocations. Passing `--skip-hook --skip-guides` together short-circuits with a terse line — nothing was installed, no banner drawn.
|
|
160
165
|
|
|
161
166
|
#### `almanac uninstall`
|
|
162
167
|
|
|
@@ -190,6 +195,23 @@ Read-only install + current-wiki health report. Every check reports a state; non
|
|
|
190
195
|
{ "key": "install.guides", "status": "ok", "message": "..." },
|
|
191
196
|
{ "key": "install.import", "status": "ok", "message": "..." }
|
|
192
197
|
],
|
|
198
|
+
"agents": [
|
|
199
|
+
{
|
|
200
|
+
"id": "claude",
|
|
201
|
+
"label": "Claude",
|
|
202
|
+
"status": "ok",
|
|
203
|
+
"readiness": "ready",
|
|
204
|
+
"selected": true,
|
|
205
|
+
"recommended": true,
|
|
206
|
+
"installed": true,
|
|
207
|
+
"authenticated": true,
|
|
208
|
+
"model": "claude-sonnet-4-6",
|
|
209
|
+
"providerDefaultModel": "claude-sonnet-4-6",
|
|
210
|
+
"configuredModel": null,
|
|
211
|
+
"account": "rohan@example.com",
|
|
212
|
+
"detail": "rohan@example.com"
|
|
213
|
+
}
|
|
214
|
+
],
|
|
193
215
|
"wiki": [
|
|
194
216
|
{ "key": "wiki.repo", "status": "info", "message": "repo: /abs/path" },
|
|
195
217
|
{ "key": "wiki.registered", "status": "ok", "message": "registered as '...'" },
|
|
@@ -206,6 +228,43 @@ Each check has a stable `key` safe for scripting. ✗ entries include a `fix` fi
|
|
|
206
228
|
|
|
207
229
|
The report also includes an `## Updates` section (`updates: Check[]` in `--json`) with keys `update.status`, `update.last_check`, `update.notifier`, and `update.dismissed`. `update.status === "problem"` when a new version is available — mirrors the pre-command banner.
|
|
208
230
|
|
|
231
|
+
#### `almanac agents`
|
|
232
|
+
|
|
233
|
+
Provider-focused settings and readiness.
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
almanac agents list
|
|
237
|
+
almanac agents doctor
|
|
238
|
+
almanac agents use claude
|
|
239
|
+
almanac agents model claude claude-opus-4-6
|
|
240
|
+
almanac agents model claude --default
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
`agents use` writes the default provider. `agents model` writes the provider-local model override; `--default`, `default`, or `null` resets the provider to its own default. The older `almanac set default-agent ...` and `almanac set model ...` commands remain compatibility aliases and print deprecation warnings.
|
|
244
|
+
|
|
245
|
+
`bootstrap` and `capture` resolve provider settings in this order:
|
|
246
|
+
|
|
247
|
+
```text
|
|
248
|
+
--agent flag > ALMANAC_AGENT env > config.agent.default > built-in default
|
|
249
|
+
--model flag > ALMANAC_MODEL env > config.agent.models[provider] > provider default
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
#### `almanac config`
|
|
253
|
+
|
|
254
|
+
Low-level scriptable settings surface.
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
almanac config list
|
|
258
|
+
almanac config list --show-origin
|
|
259
|
+
almanac config get agent.default
|
|
260
|
+
almanac config set agent.models.claude claude-opus-4-6
|
|
261
|
+
almanac config set --project agent.default codex
|
|
262
|
+
almanac config unset agent.models.claude
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Supported keys: `update_notifier`, `agent.default`, `agent.models.claude`, `agent.models.codex`, and `agent.models.cursor`.
|
|
266
|
+
User config is stored at `~/.almanac/config.toml`. Project config lives at `.almanac/config.toml` and can override agent provider/model settings for a repo; `update_notifier` remains user-level only because it controls a global pre-command banner. Effective precedence is flag, environment, project config, user config, provider default.
|
|
267
|
+
|
|
209
268
|
#### `almanac update`
|
|
210
269
|
|
|
211
270
|
Upgrade command + the controls for the nag banner. See §11 for the full update-notifier architecture.
|
|
@@ -215,8 +274,8 @@ Upgrade command + the controls for the nag banner. See §11 for the full update-
|
|
|
215
274
|
| (none) | Run `npm i -g codealmanac@latest` synchronously in the foreground. Inherits stdio so you see npm's progress bar, permission prompts, and peer-dep warnings verbatim. |
|
|
216
275
|
| `--dismiss` | Mark the current `latest_version` as "don't nag". No install. Banner is suppressed until a newer version ships. |
|
|
217
276
|
| `--check` | Force a registry query now, bypassing the 24h cache. Prints the result. No install. |
|
|
218
|
-
| `--enable-notifier` |
|
|
219
|
-
| `--disable-notifier` |
|
|
277
|
+
| `--enable-notifier` | Deprecated alias for `almanac config set update_notifier true`. |
|
|
278
|
+
| `--disable-notifier` | Deprecated alias for `almanac config set update_notifier false`. |
|
|
220
279
|
|
|
221
280
|
**Exit codes:** `0` on successful install / check / dismiss / toggle. Install propagates npm's exit code on failure. `--check` exits `1` when the registry is unreachable.
|
|
222
281
|
|
|
@@ -297,7 +356,7 @@ inventory lock row to Supabase, returns the PI client secret. See
|
|
|
297
356
|
[[inventory-lock-gotcha]] for the deadlock we hit in March.
|
|
298
357
|
```
|
|
299
358
|
|
|
300
|
-
CRLF-terminated files are handled transparently — `show --
|
|
359
|
+
CRLF-terminated files are handled transparently — `show --body` strips frontmatter without leaving a stray `\r` at the body head.
|
|
301
360
|
|
|
302
361
|
---
|
|
303
362
|
|
|
@@ -432,7 +491,7 @@ almanac search --orphan | almanac show --stdin --path | xargs -n 1 "$EDITOR"
|
|
|
432
491
|
|
|
433
492
|
**Export a page's body to a standalone markdown file:**
|
|
434
493
|
```bash
|
|
435
|
-
almanac show checkout-flow --
|
|
494
|
+
almanac show checkout-flow --body > checkout-flow.md # exactly one trailing \n
|
|
436
495
|
```
|
|
437
496
|
|
|
438
497
|
**Doctor a flaky install in CI:**
|
|
@@ -722,7 +781,7 @@ command runs
|
|
|
722
781
|
### State files
|
|
723
782
|
|
|
724
783
|
- **`~/.almanac/update-state.json`** — written by the background worker + `almanac update`. Shape: `{last_check_at, installed_version, latest_version, dismissed_versions[], last_fetch_failed_at?}`. `last_check_at` is epoch seconds; `dismissed_versions` is a list of version strings the user muted via `--dismiss`. Missing / malformed → all read paths return defaults. Never break the CLI.
|
|
725
|
-
- **`~/.almanac/config.
|
|
784
|
+
- **`~/.almanac/config.toml`** — contains `update_notifier` plus user-level agent defaults. Toggles whether the banner ever prints. Default `true`. Flip via `almanac config set update_notifier true` / `false`. Legacy `~/.almanac/config.json` is migrated on normal config reads.
|
|
726
785
|
|
|
727
786
|
### Cache behavior
|
|
728
787
|
|
|
@@ -733,7 +792,7 @@ command runs
|
|
|
733
792
|
|
|
734
793
|
### Dismissal semantics
|
|
735
794
|
|
|
736
|
-
`almanac update --dismiss` appends the current `latest_version` to `dismissed_versions[]`. The banner suppresses **only that specific version** — when a newer one ships, `latest_version` moves on and the banner reappears. Multiple consecutive dismissals accumulate; `dismissed_versions` is never trimmed automatically. If you find yourself dismissing every release, `almanac
|
|
795
|
+
`almanac update --dismiss` appends the current `latest_version` to `dismissed_versions[]`. The banner suppresses **only that specific version** — when a newer one ships, `latest_version` moves on and the banner reappears. Multiple consecutive dismissals accumulate; `dismissed_versions` is never trimmed automatically. If you find yourself dismissing every release, `almanac config set update_notifier false` is the right tool instead.
|
|
737
796
|
|
|
738
797
|
Dismissal does NOT prevent `almanac update` from installing. It only silences the banner.
|
|
739
798
|
|
package/package.json
CHANGED
package/dist/agents-A4II4YJC.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
runAgentsList,
|
|
4
|
-
runSetAgentModel,
|
|
5
|
-
runSetDefaultAgent
|
|
6
|
-
} from "./chunk-R3URPHGH.js";
|
|
7
|
-
import "./chunk-SSYMRT4I.js";
|
|
8
|
-
import "./chunk-WRUSDYYE.js";
|
|
9
|
-
import "./chunk-7JUX4ADQ.js";
|
|
10
|
-
export {
|
|
11
|
-
runAgentsList,
|
|
12
|
-
runSetAgentModel,
|
|
13
|
-
runSetDefaultAgent
|
|
14
|
-
};
|
|
15
|
-
//# sourceMappingURL=agents-A4II4YJC.js.map
|
package/dist/auth-S5DVUIUJ.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
UNAUTHENTICATED_MESSAGE,
|
|
4
|
-
assertClaudeAuth,
|
|
5
|
-
checkClaudeAuth,
|
|
6
|
-
defaultSpawnCli,
|
|
7
|
-
legacySdkSpawnCli,
|
|
8
|
-
resolveClaudeExecutable
|
|
9
|
-
} from "./chunk-SSYMRT4I.js";
|
|
10
|
-
export {
|
|
11
|
-
UNAUTHENTICATED_MESSAGE,
|
|
12
|
-
assertClaudeAuth,
|
|
13
|
-
checkClaudeAuth,
|
|
14
|
-
defaultSpawnCli,
|
|
15
|
-
legacySdkSpawnCli,
|
|
16
|
-
resolveClaudeExecutable
|
|
17
|
-
};
|
|
18
|
-
//# sourceMappingURL=auth-S5DVUIUJ.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/doctor-checks/format.ts","../src/commands/doctor-checks/install.ts","../src/commands/doctor-checks/probes.ts","../src/commands/doctor-checks/updates.ts","../src/commands/doctor.ts"],"sourcesContent":["import { BLUE, BOLD, DIM, GREEN, RED, RST } from \"../../ansi.js\";\nimport type { Check, CheckStatus, DoctorOptions, DoctorReport } from \"./types.js\";\n\nexport function formatReport(\n report: DoctorReport,\n options: DoctorOptions,\n): string {\n const color = options.stdout === undefined && process.stdout.isTTY === true;\n const lines: string[] = [];\n lines.push(`codealmanac v${report.version}`);\n lines.push(\"\");\n if (report.install.length > 0) {\n lines.push(color ? `${BOLD}## Install${RST}` : \"## Install\");\n for (const c of report.install) {\n lines.push(formatCheck(c, color));\n }\n lines.push(\"\");\n }\n if (report.updates.length > 0) {\n lines.push(color ? `${BOLD}## Updates${RST}` : \"## Updates\");\n for (const c of report.updates) {\n lines.push(formatCheck(c, color));\n }\n lines.push(\"\");\n }\n if (report.wiki.length > 0) {\n lines.push(color ? `${BOLD}## Current wiki${RST}` : \"## Current wiki\");\n for (const c of report.wiki) {\n lines.push(formatCheck(c, color));\n }\n lines.push(\"\");\n }\n return `${lines.join(\"\\n\")}\\n`;\n}\n\nfunction formatCheck(c: Check, color: boolean): string {\n const { icon, tint } = iconFor(c.status, color);\n const head = ` ${tint}${icon}${color ? RST : \"\"} ${c.message}`;\n if (c.fix === undefined) return head;\n const fixLine = color\n ? ` ${DIM}${c.fix}${RST}`\n : ` ${c.fix}`;\n return `${head}\\n${fixLine}`;\n}\n\nfunction iconFor(\n status: CheckStatus,\n color: boolean,\n): { icon: string; tint: string } {\n switch (status) {\n case \"ok\":\n return { icon: \"\\u2713\", tint: color ? GREEN : \"\" };\n case \"problem\":\n return { icon: \"\\u2717\", tint: color ? RED : \"\" };\n case \"info\":\n return { icon: \"\\u25c7\", tint: color ? BLUE : \"\" };\n }\n}\n","import { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\n\nimport type { ClaudeAuthStatus } from \"../../agent/auth.js\";\nimport { IMPORT_LINE } from \"../setup.js\";\nimport {\n classifyInstallPath,\n detectInstallPath,\n probeBetterSqlite3,\n safeCheckAuth,\n} from \"./probes.js\";\nimport type { Check, DoctorOptions } from \"./types.js\";\n\nexport async function gatherInstallChecks(\n options: DoctorOptions,\n): Promise<Check[]> {\n const checks: Check[] = [];\n\n const rawPath = options.installPath ?? detectInstallPath();\n const { installPath, isEphemeral } = classifyInstallPath(rawPath);\n checks.push(describeInstallPath(installPath, isEphemeral));\n\n const nodeVersion = options.nodeVersion ?? process.version;\n const sqlite = options.sqliteProbe ?? probeBetterSqlite3();\n checks.push({\n status: sqlite.ok ? \"ok\" : \"problem\",\n key: \"install.sqlite\",\n message: sqlite.ok\n ? `better-sqlite3 native binding OK (Node ${nodeVersion})`\n : `better-sqlite3 native binding failed: ${sqlite.summary}`,\n fix: sqlite.ok\n ? undefined\n : \"run: npm rebuild better-sqlite3 (in the install directory)\",\n });\n\n const auth = await safeCheckAuth(options.spawnCli);\n checks.push(describeAuth(auth));\n\n const settingsPath =\n options.settingsPath ?? path.join(homedir(), \".claude\", \"settings.json\");\n checks.push(await describeHook(settingsPath));\n\n const claudeDir = options.claudeDir ?? path.join(homedir(), \".claude\");\n checks.push(describeGuides(claudeDir));\n checks.push(await describeImportLine(claudeDir));\n\n return checks;\n}\n\nfunction describeInstallPath(\n installPath: string | null,\n isEphemeral: boolean,\n): Check {\n if (installPath === null) {\n return {\n status: \"problem\",\n key: \"install.path\",\n message: \"could not detect codealmanac install path\",\n fix: \"reinstall with: npm install -g codealmanac\",\n };\n }\n return {\n status: isEphemeral ? \"info\" : \"ok\",\n key: \"install.path\",\n message: isEphemeral\n ? `codealmanac running from ephemeral npx location: ${installPath}`\n : `codealmanac installed at ${installPath}`,\n fix: isEphemeral\n ? \"run: npm install -g codealmanac (to make the install permanent)\"\n : undefined,\n };\n}\n\nfunction describeAuth(auth: ClaudeAuthStatus): Check {\n if (auth.loggedIn) {\n if (auth.authMethod === \"apiKey\") {\n return {\n status: \"ok\",\n key: \"install.auth\",\n message: \"claude auth: ANTHROPIC_API_KEY set\",\n };\n }\n const who = auth.email ?? \"Claude account\";\n const plan =\n auth.subscriptionType !== undefined\n ? ` (${auth.subscriptionType} subscription)`\n : \"\";\n return {\n status: \"ok\",\n key: \"install.auth\",\n message: `claude auth: ${who}${plan}`,\n };\n }\n if (\n process.env.ANTHROPIC_API_KEY !== undefined &&\n process.env.ANTHROPIC_API_KEY.length > 0\n ) {\n return {\n status: \"ok\",\n key: \"install.auth\",\n message: \"claude auth: ANTHROPIC_API_KEY set\",\n };\n }\n return {\n status: \"problem\",\n key: \"install.auth\",\n message: \"claude auth: not signed in\",\n fix: \"run: claude auth login --claudeai (or export ANTHROPIC_API_KEY)\",\n };\n}\n\nasync function describeHook(settingsPath: string): Promise<Check> {\n if (!existsSync(settingsPath)) {\n return {\n status: \"problem\",\n key: \"install.hook\",\n message: \"SessionEnd hook not installed\",\n fix: \"run: almanac setup --yes\",\n };\n }\n try {\n const raw = await readFile(settingsPath, \"utf8\");\n const parsed = JSON.parse(raw) as {\n hooks?: {\n SessionEnd?: {\n command?: string;\n hooks?: { command?: string }[];\n }[];\n };\n };\n const entries = parsed.hooks?.SessionEnd ?? [];\n const found = entries.some((e) => {\n if (\n typeof e?.command === \"string\" &&\n e.command.endsWith(\"almanac-capture.sh\")\n ) {\n return true;\n }\n if (Array.isArray(e?.hooks)) {\n return e.hooks.some(\n (h) =>\n typeof h?.command === \"string\" &&\n h.command.endsWith(\"almanac-capture.sh\"),\n );\n }\n return false;\n });\n if (!found) {\n return {\n status: \"problem\",\n key: \"install.hook\",\n message: \"SessionEnd hook not installed\",\n fix: \"run: almanac setup --yes\",\n };\n }\n return {\n status: \"ok\",\n key: \"install.hook\",\n message: `SessionEnd hook installed at ${settingsPath}`,\n };\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n status: \"problem\",\n key: \"install.hook\",\n message: `could not read ${settingsPath}: ${msg}`,\n fix: \"check the file for malformed JSON\",\n };\n }\n}\n\nfunction describeGuides(claudeDir: string): Check {\n const mini = path.join(claudeDir, \"codealmanac.md\");\n const ref = path.join(claudeDir, \"codealmanac-reference.md\");\n const haveMini = existsSync(mini);\n const haveRef = existsSync(ref);\n if (haveMini && haveRef) {\n return {\n status: \"ok\",\n key: \"install.guides\",\n message: `Agent guides installed (${path.basename(mini)}, ${path.basename(ref)})`,\n };\n }\n const missing = [\n haveMini ? null : \"codealmanac.md\",\n haveRef ? null : \"codealmanac-reference.md\",\n ].filter((s): s is string => s !== null);\n return {\n status: \"problem\",\n key: \"install.guides\",\n message: `Agent guides missing (${missing.join(\", \")})`,\n fix: \"run: almanac setup --yes\",\n };\n}\n\nasync function describeImportLine(claudeDir: string): Promise<Check> {\n const claudeMd = path.join(claudeDir, \"CLAUDE.md\");\n if (!existsSync(claudeMd)) {\n return {\n status: \"problem\",\n key: \"install.import\",\n message: \"CLAUDE.md import not present (no ~/.claude/CLAUDE.md)\",\n fix: \"run: almanac setup --yes\",\n };\n }\n try {\n const contents = await readFile(claudeMd, \"utf8\");\n const lines = contents.split(/\\r?\\n/).map((l) => l.trim());\n const present = lines.some((line) => {\n if (line === IMPORT_LINE) return true;\n if (!line.startsWith(IMPORT_LINE)) return false;\n const next = line[IMPORT_LINE.length];\n return next === \" \" || next === \"\\t\";\n });\n if (present) {\n return {\n status: \"ok\",\n key: \"install.import\",\n message: \"CLAUDE.md import present\",\n };\n }\n return {\n status: \"problem\",\n key: \"install.import\",\n message: \"CLAUDE.md import line missing\",\n fix: \"run: almanac setup --yes\",\n };\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n return {\n status: \"problem\",\n key: \"install.import\",\n message: `could not read ${claudeMd}: ${msg}`,\n };\n }\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { homedir } from \"node:os\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport { checkClaudeAuth, type ClaudeAuthStatus, type SpawnCliFn } from \"../../agent/auth.js\";\nimport type { SqliteProbeResult } from \"./types.js\";\n\n// Single `createRequire` instance — used by package/binding probes.\nconst req = createRequire(import.meta.url);\n\n/**\n * Detect where codealmanac is installed by walking up from the running\n * module until we find a `package.json` whose `name` is `codealmanac`.\n */\nexport function detectInstallPath(): string | null {\n try {\n const here = fileURLToPath(import.meta.url);\n let dir = path.dirname(here);\n for (let i = 0; i < 6; i++) {\n const pkgPath = path.join(dir, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const raw = readFileSync(pkgPath, \"utf-8\");\n const pkg = JSON.parse(raw) as { name?: unknown };\n if (pkg.name === \"codealmanac\") return dir;\n } catch {\n // ignore — keep walking\n }\n }\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * Classify the detected install path as permanent or ephemeral.\n * Ephemeral locations (npm npx cache, pnpm dlx cache, /tmp/) are valid\n * installs but will disappear when the cache is evicted or the machine\n * reboots. Doctor reports them as `info` rather than `ok`.\n */\nexport function classifyInstallPath(\n raw: string | null,\n): { installPath: string | null; isEphemeral: boolean } {\n if (raw === null) return { installPath: null, isEphemeral: false };\n const home = homedir();\n const ephemeralPrefixes = [\n path.join(home, \".npm\", \"_npx\"),\n path.join(home, \".local\", \"share\", \"pnpm\", \"dlx\"),\n \"/tmp/\",\n \"/var/folders/\",\n ];\n const isEphemeral = ephemeralPrefixes.some((p) => raw.startsWith(p));\n return { installPath: raw, isEphemeral };\n}\n\n/**\n * Probe the better-sqlite3 native binding by opening an in-memory DB.\n */\nexport function probeBetterSqlite3(): SqliteProbeResult {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const Database = req(\"better-sqlite3\") as typeof import(\"better-sqlite3\");\n const db = new Database(\":memory:\");\n db.close();\n return { ok: true, summary: \"native binding loads cleanly\" };\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n const firstLine = msg.split(\"\\n\")[0] ?? msg;\n return { ok: false, summary: firstLine };\n }\n}\n\nexport async function safeCheckAuth(\n spawnCli?: SpawnCliFn,\n): Promise<ClaudeAuthStatus> {\n try {\n return await checkClaudeAuth(spawnCli);\n } catch {\n return { loggedIn: false };\n }\n}\n\nexport function readPackageVersion(): string | null {\n const candidates = [\n \"../../../package.json\",\n \"../../package.json\",\n \"../package.json\",\n ];\n for (const candidate of candidates) {\n try {\n const pkg = req(candidate) as { version?: unknown };\n if (typeof pkg.version === \"string\" && pkg.version.length > 0) {\n return pkg.version;\n }\n } catch {\n // Fall through to the next runtime layout candidate.\n }\n }\n return null;\n}\n","import { readConfig } from \"../../update/config.js\";\nimport { readStateForDoctor } from \"../../update/schedule.js\";\nimport { isNewer } from \"../../update/semver.js\";\nimport { formatDuration } from \"./duration.js\";\nimport type { Check, DoctorOptions } from \"./types.js\";\n\nexport async function gatherUpdateChecks(\n options: DoctorOptions,\n installedVersion: string,\n): Promise<Check[]> {\n const checks: Check[] = [];\n const state = readStateForDoctor(options.updateStatePath);\n const config = await readConfig(options.updateConfigPath);\n\n if (state === null || state.latest_version.length === 0) {\n checks.push({\n status: \"info\",\n key: \"update.status\",\n message: `on ${installedVersion}; no update check has run yet`,\n fix: \"run: almanac update --check\",\n });\n } else if (isNewer(state.latest_version, installedVersion)) {\n const dismissed = state.dismissed_versions.includes(state.latest_version)\n ? \" (dismissed — run `almanac update` to install anyway)\"\n : \"\";\n checks.push({\n status: \"problem\",\n key: \"update.status\",\n message:\n `${state.latest_version} available (you're on ${installedVersion})${dismissed}`,\n fix: \"run: almanac update\",\n });\n } else {\n checks.push({\n status: \"ok\",\n key: \"update.status\",\n message: `on latest (${installedVersion})`,\n });\n }\n\n if (state !== null && state.last_check_at > 0) {\n const now = (options.now?.() ?? new Date()).getTime();\n const ageMs = now - state.last_check_at * 1000;\n const failedSuffix =\n state.last_fetch_failed_at !== undefined &&\n state.last_fetch_failed_at === state.last_check_at\n ? \" (last attempt failed — will retry next invocation)\"\n : \"\";\n checks.push({\n status: \"info\",\n key: \"update.last_check\",\n message: `last checked: ${formatDuration(ageMs)} ago${failedSuffix}`,\n });\n } else {\n checks.push({\n status: \"info\",\n key: \"update.last_check\",\n message: \"last checked: never\",\n });\n }\n\n checks.push({\n status: \"info\",\n key: \"update.notifier\",\n message: `update notifier: ${config.update_notifier ? \"enabled\" : \"disabled\"}`,\n fix: config.update_notifier\n ? undefined\n : \"run: almanac update --enable-notifier\",\n });\n\n if (state !== null && state.dismissed_versions.length > 0) {\n checks.push({\n status: \"info\",\n key: \"update.dismissed\",\n message: `dismissed versions: ${state.dismissed_versions.join(\", \")}`,\n });\n }\n\n return checks;\n}\n","import { formatReport } from \"./doctor-checks/format.js\";\nimport { gatherInstallChecks } from \"./doctor-checks/install.js\";\nimport { readPackageVersion } from \"./doctor-checks/probes.js\";\nimport type {\n Check,\n CheckStatus,\n DoctorOptions,\n DoctorReport,\n DoctorResult,\n SqliteProbeResult,\n} from \"./doctor-checks/types.js\";\nimport { gatherUpdateChecks } from \"./doctor-checks/updates.js\";\n\nexport type {\n Check,\n CheckStatus,\n DoctorOptions,\n DoctorReport,\n DoctorResult,\n SqliteProbeResult,\n};\n\n/**\n * `almanac doctor` — install + wiki health report.\n *\n * Separate from `almanac health` (which checks graph integrity of a\n * specific wiki). `doctor` answers the \"is this install even set up\n * correctly?\" question that users hit when first trying the tool or when\n * sessions silently stop getting captured.\n *\n * This file is the command composition root. The section-specific probes\n * and formatting live in `doctor-checks/` so each durable fact has one\n * obvious owner.\n */\nexport async function runDoctor(\n options: DoctorOptions,\n): Promise<DoctorResult> {\n const version =\n options.versionOverride ?? readPackageVersion() ?? \"unknown\";\n\n const install: Check[] = options.wikiOnly === true\n ? []\n : await gatherInstallChecks(options);\n\n const updates: Check[] = options.wikiOnly === true\n ? []\n : await gatherUpdateChecks(options, version);\n\n const wiki: Check[] = options.installOnly === true\n ? []\n : await safeGatherWikiChecks(options);\n\n const report: DoctorReport = { version, install, updates, wiki };\n\n if (options.json === true) {\n return {\n stdout: `${JSON.stringify(report, null, 2)}\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n }\n\n return {\n stdout: formatReport(report, options),\n stderr: \"\",\n exitCode: 0,\n };\n}\n\nasync function safeGatherWikiChecks(\n options: DoctorOptions,\n): Promise<Check[]> {\n try {\n const { gatherWikiChecks } = await import(\"./doctor-checks/wiki.js\");\n return await gatherWikiChecks(options);\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n return [\n {\n status: \"problem\",\n key: \"wiki.checks\",\n message: `could not run wiki checks: ${msg.split(\"\\n\")[0] ?? msg}`,\n fix: \"run: npm rebuild better-sqlite3 (in the install directory)\",\n },\n ];\n }\n}\n"],"mappings":"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","names":["existsSync","homedir","path","path","homedir","existsSync"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/helpers.ts"],"sourcesContent":["export interface CommandResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\nexport function emit(result: CommandResult): void {\n if (result.stderr.length > 0) process.stderr.write(result.stderr);\n if (result.stdout.length > 0) process.stdout.write(result.stdout);\n if (result.exitCode !== 0) process.exitCode = result.exitCode;\n}\n\nexport function collectOption(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\nexport function parsePositiveInt(value: string): number {\n const n = Number.parseInt(value, 10);\n if (!Number.isFinite(n) || n < 0) {\n throw new Error(`invalid --limit \"${value}\" (expected a non-negative integer)`);\n }\n return n;\n}\n\nexport async function readStdin(): Promise<string> {\n if (process.stdin.isTTY === true) return \"\";\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString(\"utf8\");\n}\n"],"mappings":";;;AAMO,SAAS,KAAK,QAA6B;AAChD,MAAI,OAAO,OAAO,SAAS,EAAG,SAAQ,OAAO,MAAM,OAAO,MAAM;AAChE,MAAI,OAAO,OAAO,SAAS,EAAG,SAAQ,OAAO,MAAM,OAAO,MAAM;AAChE,MAAI,OAAO,aAAa,EAAG,SAAQ,WAAW,OAAO;AACvD;AAEO,SAAS,cAAc,OAAe,UAA8B;AACzE,SAAO,CAAC,GAAG,UAAU,KAAK;AAC5B;AAEO,SAAS,iBAAiB,OAAuB;AACtD,QAAM,IAAI,OAAO,SAAS,OAAO,EAAE;AACnC,MAAI,CAAC,OAAO,SAAS,CAAC,KAAK,IAAI,GAAG;AAChC,UAAM,IAAI,MAAM,oBAAoB,KAAK,qCAAqC;AAAA,EAChF;AACA,SAAO;AACT;AAEA,eAAsB,YAA6B;AACjD,MAAI,QAAQ,MAAM,UAAU,KAAM,QAAO;AACzC,QAAM,SAAmB,CAAC;AAC1B,mBAAiB,SAAS,QAAQ,OAAO;AACvC,WAAO,KAAK,OAAO,SAAS,KAAK,IAAI,QAAQ,OAAO,KAAK,KAAK,CAAC;AAAA,EACjE;AACA,SAAO,OAAO,OAAO,MAAM,EAAE,SAAS,MAAM;AAC9C;","names":[]}
|
package/dist/chunk-R3URPHGH.js
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
assertClaudeAuth
|
|
4
|
-
} from "./chunk-SSYMRT4I.js";
|
|
5
|
-
import {
|
|
6
|
-
AGENT_PROVIDER_IDS,
|
|
7
|
-
isAgentProviderId,
|
|
8
|
-
readConfig,
|
|
9
|
-
writeConfig
|
|
10
|
-
} from "./chunk-WRUSDYYE.js";
|
|
11
|
-
|
|
12
|
-
// src/agent/providers.ts
|
|
13
|
-
import { spawn, spawnSync } from "child_process";
|
|
14
|
-
async function assertAgentAuth(args) {
|
|
15
|
-
if (args.provider === "claude") {
|
|
16
|
-
await assertClaudeAuth(args.spawnCli);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
const status = await checkProviderStatus(args.provider);
|
|
20
|
-
if (!status.installed || !status.authenticated) {
|
|
21
|
-
const err = new Error(`${status.id} not ready: ${status.detail}`);
|
|
22
|
-
err.code = "AGENT_AUTH_MISSING";
|
|
23
|
-
throw err;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
async function listProviderStatuses(spawnCli) {
|
|
27
|
-
const out = [];
|
|
28
|
-
for (const id of AGENT_PROVIDER_IDS) {
|
|
29
|
-
if (id === "claude") {
|
|
30
|
-
out.push(await checkClaudeProvider(spawnCli));
|
|
31
|
-
} else {
|
|
32
|
-
out.push(await checkProviderStatus(id));
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return out;
|
|
36
|
-
}
|
|
37
|
-
async function checkClaudeProvider(spawnCli) {
|
|
38
|
-
let auth = { loggedIn: false };
|
|
39
|
-
try {
|
|
40
|
-
auth = await import("./auth-S5DVUIUJ.js").then((m) => m.checkClaudeAuth(spawnCli));
|
|
41
|
-
} catch {
|
|
42
|
-
auth = { loggedIn: false };
|
|
43
|
-
}
|
|
44
|
-
const hasApiKey = process.env.ANTHROPIC_API_KEY !== void 0 && process.env.ANTHROPIC_API_KEY.length > 0;
|
|
45
|
-
const installed = commandExists("claude");
|
|
46
|
-
const authenticated = auth.loggedIn || hasApiKey;
|
|
47
|
-
const detail = authenticated ? auth.email ?? (hasApiKey ? "ANTHROPIC_API_KEY set" : "logged in") : installed ? "not logged in" : "claude not found on PATH";
|
|
48
|
-
return { id: "claude", installed, authenticated, detail };
|
|
49
|
-
}
|
|
50
|
-
async function checkProviderStatus(provider) {
|
|
51
|
-
const command = provider === "codex" ? "codex" : "cursor-agent";
|
|
52
|
-
if (!commandExists(command)) {
|
|
53
|
-
return {
|
|
54
|
-
id: provider,
|
|
55
|
-
installed: false,
|
|
56
|
-
authenticated: false,
|
|
57
|
-
detail: `${command} not found on PATH`
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
const auth = provider === "codex" ? await runStatusCommand(command, ["login", "status"]) : await runStatusCommand(command, ["status"]);
|
|
61
|
-
return {
|
|
62
|
-
id: provider,
|
|
63
|
-
installed: true,
|
|
64
|
-
authenticated: auth.ok,
|
|
65
|
-
detail: auth.detail
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function commandExists(command) {
|
|
69
|
-
const result = spawnSync("sh", ["-lc", `command -v ${command}`], {
|
|
70
|
-
encoding: "utf8"
|
|
71
|
-
});
|
|
72
|
-
return result.status === 0 && result.stdout.trim().length > 0;
|
|
73
|
-
}
|
|
74
|
-
function runStatusCommand(command, args) {
|
|
75
|
-
return new Promise((resolve) => {
|
|
76
|
-
let stdout = "";
|
|
77
|
-
let stderr = "";
|
|
78
|
-
let child;
|
|
79
|
-
try {
|
|
80
|
-
child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
81
|
-
} catch (err) {
|
|
82
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
83
|
-
resolve({ ok: false, detail: msg });
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const timer = setTimeout(() => {
|
|
87
|
-
try {
|
|
88
|
-
child.kill("SIGTERM");
|
|
89
|
-
} catch {
|
|
90
|
-
}
|
|
91
|
-
resolve({ ok: false, detail: `${command} status timed out` });
|
|
92
|
-
}, 1e4);
|
|
93
|
-
child.stdout?.on("data", (chunk) => {
|
|
94
|
-
stdout += chunk.toString("utf8");
|
|
95
|
-
});
|
|
96
|
-
child.stderr?.on("data", (chunk) => {
|
|
97
|
-
stderr += chunk.toString("utf8");
|
|
98
|
-
});
|
|
99
|
-
child.on("error", (err) => {
|
|
100
|
-
clearTimeout(timer);
|
|
101
|
-
resolve({ ok: false, detail: err.message });
|
|
102
|
-
});
|
|
103
|
-
child.on("close", (code) => {
|
|
104
|
-
clearTimeout(timer);
|
|
105
|
-
const text = `${stdout}
|
|
106
|
-
${stderr}`.trim();
|
|
107
|
-
resolve({
|
|
108
|
-
ok: code === 0,
|
|
109
|
-
detail: text.split("\n").find((line) => line.trim().length > 0)?.trim() ?? (code === 0 ? "ready" : `${command} exited ${code ?? 1}`)
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// src/commands/agents.ts
|
|
116
|
-
async function runAgentsList() {
|
|
117
|
-
const config = await readConfig();
|
|
118
|
-
const statuses = await listProviderStatuses();
|
|
119
|
-
const lines = ["codealmanac agents\n"];
|
|
120
|
-
for (const status of statuses) {
|
|
121
|
-
const selected = status.id === config.agent.default ? "*" : " ";
|
|
122
|
-
const auth = status.authenticated ? "ready" : "not ready";
|
|
123
|
-
const installed = status.installed ? "installed" : "missing";
|
|
124
|
-
lines.push(
|
|
125
|
-
`${selected} ${status.id.padEnd(6)} ${installed.padEnd(9)} ${auth.padEnd(9)} ${status.detail}`
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
lines.push("\nChange default with: almanac set default-agent <claude|codex|cursor>");
|
|
129
|
-
return { stdout: `${lines.join("\n")}
|
|
130
|
-
`, stderr: "", exitCode: 0 };
|
|
131
|
-
}
|
|
132
|
-
async function runSetDefaultAgent(opts) {
|
|
133
|
-
if (!isAgentProviderId(opts.provider)) {
|
|
134
|
-
return {
|
|
135
|
-
stdout: "",
|
|
136
|
-
stderr: `almanac: unknown agent '${opts.provider}'. Expected one of: claude, codex, cursor.
|
|
137
|
-
`,
|
|
138
|
-
exitCode: 1
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
const config = await readConfig();
|
|
142
|
-
const next = {
|
|
143
|
-
...config,
|
|
144
|
-
agent: {
|
|
145
|
-
...config.agent,
|
|
146
|
-
default: opts.provider
|
|
147
|
-
}
|
|
148
|
-
};
|
|
149
|
-
await writeConfig(next);
|
|
150
|
-
return {
|
|
151
|
-
stdout: `codealmanac: default agent set to ${opts.provider}.
|
|
152
|
-
`,
|
|
153
|
-
stderr: "",
|
|
154
|
-
exitCode: 0
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
async function runSetAgentModel(opts) {
|
|
158
|
-
if (!isAgentProviderId(opts.provider)) {
|
|
159
|
-
return {
|
|
160
|
-
stdout: "",
|
|
161
|
-
stderr: `almanac: unknown agent '${opts.provider}'. Expected one of: claude, codex, cursor.
|
|
162
|
-
`,
|
|
163
|
-
exitCode: 1
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
const provider = opts.provider;
|
|
167
|
-
const config = await readConfig();
|
|
168
|
-
const model = opts.model !== void 0 && opts.model.length > 0 ? opts.model : null;
|
|
169
|
-
await writeConfig({
|
|
170
|
-
...config,
|
|
171
|
-
agent: {
|
|
172
|
-
...config.agent,
|
|
173
|
-
models: {
|
|
174
|
-
...config.agent.models,
|
|
175
|
-
[provider]: model
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
return {
|
|
180
|
-
stdout: model === null ? `codealmanac: ${provider} model reset to provider default.
|
|
181
|
-
` : `codealmanac: ${provider} model set to ${model}.
|
|
182
|
-
`,
|
|
183
|
-
stderr: "",
|
|
184
|
-
exitCode: 0
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export {
|
|
189
|
-
assertAgentAuth,
|
|
190
|
-
runAgentsList,
|
|
191
|
-
runSetDefaultAgent,
|
|
192
|
-
runSetAgentModel
|
|
193
|
-
};
|
|
194
|
-
//# sourceMappingURL=chunk-R3URPHGH.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/agent/providers.ts","../src/commands/agents.ts"],"sourcesContent":["import { spawn, spawnSync, type ChildProcess } from \"node:child_process\";\n\nimport {\n assertClaudeAuth,\n type ClaudeAuthStatus,\n type SpawnCliFn,\n} from \"./auth.js\";\nimport {\n AGENT_PROVIDER_IDS,\n type AgentProviderId,\n} from \"../update/config.js\";\n\nexport interface ProviderStatus {\n id: AgentProviderId;\n installed: boolean;\n authenticated: boolean;\n detail: string;\n}\n\nexport async function assertAgentAuth(args: {\n provider: AgentProviderId;\n spawnCli?: SpawnCliFn;\n}): Promise<void> {\n if (args.provider === \"claude\") {\n await assertClaudeAuth(args.spawnCli);\n return;\n }\n const status = await checkProviderStatus(args.provider);\n if (!status.installed || !status.authenticated) {\n const err = new Error(`${status.id} not ready: ${status.detail}`);\n (err as { code?: string }).code = \"AGENT_AUTH_MISSING\";\n throw err;\n }\n}\n\nexport async function listProviderStatuses(\n spawnCli?: SpawnCliFn,\n): Promise<ProviderStatus[]> {\n const out: ProviderStatus[] = [];\n for (const id of AGENT_PROVIDER_IDS) {\n if (id === \"claude\") {\n out.push(await checkClaudeProvider(spawnCli));\n } else {\n out.push(await checkProviderStatus(id));\n }\n }\n return out;\n}\n\nasync function checkClaudeProvider(\n spawnCli?: SpawnCliFn,\n): Promise<ProviderStatus> {\n let auth: ClaudeAuthStatus = { loggedIn: false };\n try {\n auth = await import(\"./auth.js\").then((m) => m.checkClaudeAuth(spawnCli));\n } catch {\n auth = { loggedIn: false };\n }\n const hasApiKey =\n process.env.ANTHROPIC_API_KEY !== undefined &&\n process.env.ANTHROPIC_API_KEY.length > 0;\n const installed = commandExists(\"claude\");\n const authenticated = auth.loggedIn || hasApiKey;\n const detail = authenticated\n ? auth.email ?? (hasApiKey ? \"ANTHROPIC_API_KEY set\" : \"logged in\")\n : installed\n ? \"not logged in\"\n : \"claude not found on PATH\";\n return { id: \"claude\", installed, authenticated, detail };\n}\n\nasync function checkProviderStatus(\n provider: Exclude<AgentProviderId, \"claude\">,\n): Promise<ProviderStatus> {\n const command = provider === \"codex\" ? \"codex\" : \"cursor-agent\";\n if (!commandExists(command)) {\n return {\n id: provider,\n installed: false,\n authenticated: false,\n detail: `${command} not found on PATH`,\n };\n }\n\n const auth =\n provider === \"codex\"\n ? await runStatusCommand(command, [\"login\", \"status\"])\n : await runStatusCommand(command, [\"status\"]);\n\n return {\n id: provider,\n installed: true,\n authenticated: auth.ok,\n detail: auth.detail,\n };\n}\n\nfunction commandExists(command: string): boolean {\n const result = spawnSync(\"sh\", [\"-lc\", `command -v ${command}`], {\n encoding: \"utf8\",\n });\n return result.status === 0 && result.stdout.trim().length > 0;\n}\n\nfunction runStatusCommand(\n command: string,\n args: string[],\n): Promise<{ ok: boolean; detail: string }> {\n return new Promise((resolve) => {\n let stdout = \"\";\n let stderr = \"\";\n let child: ChildProcess;\n try {\n child = spawn(command, args, { stdio: [\"ignore\", \"pipe\", \"pipe\"] });\n } catch (err: unknown) {\n const msg = err instanceof Error ? err.message : String(err);\n resolve({ ok: false, detail: msg });\n return;\n }\n const timer = setTimeout(() => {\n try {\n child.kill(\"SIGTERM\");\n } catch {\n // already exited\n }\n resolve({ ok: false, detail: `${command} status timed out` });\n }, 10_000);\n child.stdout?.on(\"data\", (chunk) => {\n stdout += chunk.toString(\"utf8\");\n });\n child.stderr?.on(\"data\", (chunk) => {\n stderr += chunk.toString(\"utf8\");\n });\n child.on(\"error\", (err) => {\n clearTimeout(timer);\n resolve({ ok: false, detail: err.message });\n });\n child.on(\"close\", (code) => {\n clearTimeout(timer);\n const text = `${stdout}\\n${stderr}`.trim();\n resolve({\n ok: code === 0,\n detail: text.split(\"\\n\").find((line) => line.trim().length > 0)?.trim() ??\n (code === 0 ? \"ready\" : `${command} exited ${code ?? 1}`),\n });\n });\n });\n}\n","import { listProviderStatuses } from \"../agent/providers.js\";\nimport {\n isAgentProviderId,\n readConfig,\n writeConfig,\n type AgentProviderId,\n} from \"../update/config.js\";\n\nexport interface AgentsResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\nexport async function runAgentsList(): Promise<AgentsResult> {\n const config = await readConfig();\n const statuses = await listProviderStatuses();\n const lines = [\"codealmanac agents\\n\"];\n for (const status of statuses) {\n const selected = status.id === config.agent.default ? \"*\" : \" \";\n const auth = status.authenticated ? \"ready\" : \"not ready\";\n const installed = status.installed ? \"installed\" : \"missing\";\n lines.push(\n `${selected} ${status.id.padEnd(6)} ${installed.padEnd(9)} ${auth.padEnd(9)} ${status.detail}`,\n );\n }\n lines.push(\"\\nChange default with: almanac set default-agent <claude|codex|cursor>\");\n return { stdout: `${lines.join(\"\\n\")}\\n`, stderr: \"\", exitCode: 0 };\n}\n\nexport interface SetDefaultAgentOptions {\n provider: string;\n}\n\nexport async function runSetDefaultAgent(\n opts: SetDefaultAgentOptions,\n): Promise<AgentsResult> {\n if (!isAgentProviderId(opts.provider)) {\n return {\n stdout: \"\",\n stderr:\n `almanac: unknown agent '${opts.provider}'. ` +\n \"Expected one of: claude, codex, cursor.\\n\",\n exitCode: 1,\n };\n }\n const config = await readConfig();\n const next = {\n ...config,\n agent: {\n ...config.agent,\n default: opts.provider,\n },\n };\n await writeConfig(next);\n return {\n stdout: `codealmanac: default agent set to ${opts.provider}.\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n}\n\nexport async function runSetAgentModel(opts: {\n provider: string;\n model?: string;\n}): Promise<AgentsResult> {\n if (!isAgentProviderId(opts.provider)) {\n return {\n stdout: \"\",\n stderr:\n `almanac: unknown agent '${opts.provider}'. ` +\n \"Expected one of: claude, codex, cursor.\\n\",\n exitCode: 1,\n };\n }\n const provider = opts.provider as AgentProviderId;\n const config = await readConfig();\n const model =\n opts.model !== undefined && opts.model.length > 0 ? opts.model : null;\n await writeConfig({\n ...config,\n agent: {\n ...config.agent,\n models: {\n ...config.agent.models,\n [provider]: model,\n },\n },\n });\n return {\n stdout:\n model === null\n ? `codealmanac: ${provider} model reset to provider default.\\n`\n : `codealmanac: ${provider} model set to ${model}.\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n}\n"],"mappings":";;;;;;;;;;;;AAAA,SAAS,OAAO,iBAAoC;AAmBpD,eAAsB,gBAAgB,MAGpB;AAChB,MAAI,KAAK,aAAa,UAAU;AAC9B,UAAM,iBAAiB,KAAK,QAAQ;AACpC;AAAA,EACF;AACA,QAAM,SAAS,MAAM,oBAAoB,KAAK,QAAQ;AACtD,MAAI,CAAC,OAAO,aAAa,CAAC,OAAO,eAAe;AAC9C,UAAM,MAAM,IAAI,MAAM,GAAG,OAAO,EAAE,eAAe,OAAO,MAAM,EAAE;AAChE,IAAC,IAA0B,OAAO;AAClC,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,qBACpB,UAC2B;AAC3B,QAAM,MAAwB,CAAC;AAC/B,aAAW,MAAM,oBAAoB;AACnC,QAAI,OAAO,UAAU;AACnB,UAAI,KAAK,MAAM,oBAAoB,QAAQ,CAAC;AAAA,IAC9C,OAAO;AACL,UAAI,KAAK,MAAM,oBAAoB,EAAE,CAAC;AAAA,IACxC;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,oBACb,UACyB;AACzB,MAAI,OAAyB,EAAE,UAAU,MAAM;AAC/C,MAAI;AACF,WAAO,MAAM,OAAO,oBAAW,EAAE,KAAK,CAAC,MAAM,EAAE,gBAAgB,QAAQ,CAAC;AAAA,EAC1E,QAAQ;AACN,WAAO,EAAE,UAAU,MAAM;AAAA,EAC3B;AACA,QAAM,YACJ,QAAQ,IAAI,sBAAsB,UAClC,QAAQ,IAAI,kBAAkB,SAAS;AACzC,QAAM,YAAY,cAAc,QAAQ;AACxC,QAAM,gBAAgB,KAAK,YAAY;AACvC,QAAM,SAAS,gBACX,KAAK,UAAU,YAAY,0BAA0B,eACrD,YACE,kBACA;AACN,SAAO,EAAE,IAAI,UAAU,WAAW,eAAe,OAAO;AAC1D;AAEA,eAAe,oBACb,UACyB;AACzB,QAAM,UAAU,aAAa,UAAU,UAAU;AACjD,MAAI,CAAC,cAAc,OAAO,GAAG;AAC3B,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,WAAW;AAAA,MACX,eAAe;AAAA,MACf,QAAQ,GAAG,OAAO;AAAA,IACpB;AAAA,EACF;AAEA,QAAM,OACJ,aAAa,UACT,MAAM,iBAAiB,SAAS,CAAC,SAAS,QAAQ,CAAC,IACnD,MAAM,iBAAiB,SAAS,CAAC,QAAQ,CAAC;AAEhD,SAAO;AAAA,IACL,IAAI;AAAA,IACJ,WAAW;AAAA,IACX,eAAe,KAAK;AAAA,IACpB,QAAQ,KAAK;AAAA,EACf;AACF;AAEA,SAAS,cAAc,SAA0B;AAC/C,QAAM,SAAS,UAAU,MAAM,CAAC,OAAO,cAAc,OAAO,EAAE,GAAG;AAAA,IAC/D,UAAU;AAAA,EACZ,CAAC;AACD,SAAO,OAAO,WAAW,KAAK,OAAO,OAAO,KAAK,EAAE,SAAS;AAC9D;AAEA,SAAS,iBACP,SACA,MAC0C;AAC1C,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,SAAS;AACb,QAAI,SAAS;AACb,QAAI;AACJ,QAAI;AACF,cAAQ,MAAM,SAAS,MAAM,EAAE,OAAO,CAAC,UAAU,QAAQ,MAAM,EAAE,CAAC;AAAA,IACpE,SAAS,KAAc;AACrB,YAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,cAAQ,EAAE,IAAI,OAAO,QAAQ,IAAI,CAAC;AAClC;AAAA,IACF;AACA,UAAM,QAAQ,WAAW,MAAM;AAC7B,UAAI;AACF,cAAM,KAAK,SAAS;AAAA,MACtB,QAAQ;AAAA,MAER;AACA,cAAQ,EAAE,IAAI,OAAO,QAAQ,GAAG,OAAO,oBAAoB,CAAC;AAAA,IAC9D,GAAG,GAAM;AACT,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAClC,gBAAU,MAAM,SAAS,MAAM;AAAA,IACjC,CAAC;AACD,UAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU;AAClC,gBAAU,MAAM,SAAS,MAAM;AAAA,IACjC,CAAC;AACD,UAAM,GAAG,SAAS,CAAC,QAAQ;AACzB,mBAAa,KAAK;AAClB,cAAQ,EAAE,IAAI,OAAO,QAAQ,IAAI,QAAQ,CAAC;AAAA,IAC5C,CAAC;AACD,UAAM,GAAG,SAAS,CAAC,SAAS;AAC1B,mBAAa,KAAK;AAClB,YAAM,OAAO,GAAG,MAAM;AAAA,EAAK,MAAM,GAAG,KAAK;AACzC,cAAQ;AAAA,QACN,IAAI,SAAS;AAAA,QACb,QAAQ,KAAK,MAAM,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,KAAK,EAAE,SAAS,CAAC,GAAG,KAAK,MACnE,SAAS,IAAI,UAAU,GAAG,OAAO,WAAW,QAAQ,CAAC;AAAA,MAC1D,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;;;ACrIA,eAAsB,gBAAuC;AAC3D,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,WAAW,MAAM,qBAAqB;AAC5C,QAAM,QAAQ,CAAC,sBAAsB;AACrC,aAAW,UAAU,UAAU;AAC7B,UAAM,WAAW,OAAO,OAAO,OAAO,MAAM,UAAU,MAAM;AAC5D,UAAM,OAAO,OAAO,gBAAgB,UAAU;AAC9C,UAAM,YAAY,OAAO,YAAY,cAAc;AACnD,UAAM;AAAA,MACJ,GAAG,QAAQ,IAAI,OAAO,GAAG,OAAO,CAAC,CAAC,IAAI,UAAU,OAAO,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,IAAI,OAAO,MAAM;AAAA,IAC9F;AAAA,EACF;AACA,QAAM,KAAK,wEAAwE;AACnF,SAAO,EAAE,QAAQ,GAAG,MAAM,KAAK,IAAI,CAAC;AAAA,GAAM,QAAQ,IAAI,UAAU,EAAE;AACpE;AAMA,eAAsB,mBACpB,MACuB;AACvB,MAAI,CAAC,kBAAkB,KAAK,QAAQ,GAAG;AACrC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QACE,2BAA2B,KAAK,QAAQ;AAAA;AAAA,MAE1C,UAAU;AAAA,IACZ;AAAA,EACF;AACA,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,OAAO;AAAA,IACX,GAAG;AAAA,IACH,OAAO;AAAA,MACL,GAAG,OAAO;AAAA,MACV,SAAS,KAAK;AAAA,IAChB;AAAA,EACF;AACA,QAAM,YAAY,IAAI;AACtB,SAAO;AAAA,IACL,QAAQ,qCAAqC,KAAK,QAAQ;AAAA;AAAA,IAC1D,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AACF;AAEA,eAAsB,iBAAiB,MAGb;AACxB,MAAI,CAAC,kBAAkB,KAAK,QAAQ,GAAG;AACrC,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,QACE,2BAA2B,KAAK,QAAQ;AAAA;AAAA,MAE1C,UAAU;AAAA,IACZ;AAAA,EACF;AACA,QAAM,WAAW,KAAK;AACtB,QAAM,SAAS,MAAM,WAAW;AAChC,QAAM,QACJ,KAAK,UAAU,UAAa,KAAK,MAAM,SAAS,IAAI,KAAK,QAAQ;AACnE,QAAM,YAAY;AAAA,IAChB,GAAG;AAAA,IACH,OAAO;AAAA,MACL,GAAG,OAAO;AAAA,MACV,QAAQ;AAAA,QACN,GAAG,OAAO,MAAM;AAAA,QAChB,CAAC,QAAQ,GAAG;AAAA,MACd;AAAA,IACF;AAAA,EACF,CAAC;AACD,SAAO;AAAA,IACL,QACE,UAAU,OACN,gBAAgB,QAAQ;AAAA,IACxB,gBAAgB,QAAQ,iBAAiB,KAAK;AAAA;AAAA,IACpD,QAAQ;AAAA,IACR,UAAU;AAAA,EACZ;AACF;","names":[]}
|