@the-librarian/cli 1.0.0-rc.3

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.
Files changed (106) hide show
  1. package/README.md +94 -0
  2. package/dist/bin.d.ts +3 -0
  3. package/dist/bin.d.ts.map +1 -0
  4. package/dist/bin.js +15 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/commands/install.d.ts +22 -0
  7. package/dist/commands/install.d.ts.map +1 -0
  8. package/dist/commands/install.js +152 -0
  9. package/dist/commands/install.js.map +1 -0
  10. package/dist/commands/shared.d.ts +16 -0
  11. package/dist/commands/shared.d.ts.map +1 -0
  12. package/dist/commands/shared.js +30 -0
  13. package/dist/commands/shared.js.map +1 -0
  14. package/dist/commands/uninstall.d.ts +18 -0
  15. package/dist/commands/uninstall.d.ts.map +1 -0
  16. package/dist/commands/uninstall.js +67 -0
  17. package/dist/commands/uninstall.js.map +1 -0
  18. package/dist/commands/update.d.ts +21 -0
  19. package/dist/commands/update.d.ts.map +1 -0
  20. package/dist/commands/update.js +75 -0
  21. package/dist/commands/update.js.map +1 -0
  22. package/dist/config.d.ts +40 -0
  23. package/dist/config.d.ts.map +1 -0
  24. package/dist/config.js +65 -0
  25. package/dist/config.js.map +1 -0
  26. package/dist/doctor.d.ts +23 -0
  27. package/dist/doctor.d.ts.map +1 -0
  28. package/dist/doctor.js +81 -0
  29. package/dist/doctor.js.map +1 -0
  30. package/dist/env.d.ts +39 -0
  31. package/dist/env.d.ts.map +1 -0
  32. package/dist/env.js +208 -0
  33. package/dist/env.js.map +1 -0
  34. package/dist/exec.d.ts +37 -0
  35. package/dist/exec.d.ts.map +1 -0
  36. package/dist/exec.js +81 -0
  37. package/dist/exec.js.map +1 -0
  38. package/dist/harnesses/claude.d.ts +3 -0
  39. package/dist/harnesses/claude.d.ts.map +1 -0
  40. package/dist/harnesses/claude.js +88 -0
  41. package/dist/harnesses/claude.js.map +1 -0
  42. package/dist/harnesses/cli.d.ts +4 -0
  43. package/dist/harnesses/cli.d.ts.map +1 -0
  44. package/dist/harnesses/cli.js +16 -0
  45. package/dist/harnesses/cli.js.map +1 -0
  46. package/dist/harnesses/codex.d.ts +3 -0
  47. package/dist/harnesses/codex.d.ts.map +1 -0
  48. package/dist/harnesses/codex.js +183 -0
  49. package/dist/harnesses/codex.js.map +1 -0
  50. package/dist/harnesses/hermes.d.ts +16 -0
  51. package/dist/harnesses/hermes.d.ts.map +1 -0
  52. package/dist/harnesses/hermes.js +154 -0
  53. package/dist/harnesses/hermes.js.map +1 -0
  54. package/dist/harnesses/index.d.ts +12 -0
  55. package/dist/harnesses/index.d.ts.map +1 -0
  56. package/dist/harnesses/index.js +29 -0
  57. package/dist/harnesses/index.js.map +1 -0
  58. package/dist/harnesses/opencode.d.ts +3 -0
  59. package/dist/harnesses/opencode.d.ts.map +1 -0
  60. package/dist/harnesses/opencode.js +141 -0
  61. package/dist/harnesses/opencode.js.map +1 -0
  62. package/dist/harnesses/pi.d.ts +3 -0
  63. package/dist/harnesses/pi.d.ts.map +1 -0
  64. package/dist/harnesses/pi.js +72 -0
  65. package/dist/harnesses/pi.js.map +1 -0
  66. package/dist/harnesses/types.d.ts +48 -0
  67. package/dist/harnesses/types.d.ts.map +1 -0
  68. package/dist/harnesses/types.js +22 -0
  69. package/dist/harnesses/types.js.map +1 -0
  70. package/dist/index.d.ts +11 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +15 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/machine.d.ts +10 -0
  75. package/dist/machine.d.ts.map +1 -0
  76. package/dist/machine.js +39 -0
  77. package/dist/machine.js.map +1 -0
  78. package/dist/parse-args.d.ts +12 -0
  79. package/dist/parse-args.d.ts.map +1 -0
  80. package/dist/parse-args.js +54 -0
  81. package/dist/parse-args.js.map +1 -0
  82. package/dist/paths.d.ts +32 -0
  83. package/dist/paths.d.ts.map +1 -0
  84. package/dist/paths.js +75 -0
  85. package/dist/paths.js.map +1 -0
  86. package/dist/prompt.d.ts +46 -0
  87. package/dist/prompt.d.ts.map +1 -0
  88. package/dist/prompt.js +115 -0
  89. package/dist/prompt.js.map +1 -0
  90. package/dist/runtime.d.ts +25 -0
  91. package/dist/runtime.d.ts.map +1 -0
  92. package/dist/runtime.js +169 -0
  93. package/dist/runtime.js.map +1 -0
  94. package/dist/semver.d.ts +13 -0
  95. package/dist/semver.d.ts.map +1 -0
  96. package/dist/semver.js +98 -0
  97. package/dist/semver.js.map +1 -0
  98. package/dist/status.d.ts +18 -0
  99. package/dist/status.d.ts.map +1 -0
  100. package/dist/status.js +113 -0
  101. package/dist/status.js.map +1 -0
  102. package/dist/version.d.ts +2 -0
  103. package/dist/version.d.ts.map +1 -0
  104. package/dist/version.js +20 -0
  105. package/dist/version.js.map +1 -0
  106. package/package.json +37 -0
package/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # `@the-librarian/cli` — the `librarian` installer
2
+
3
+ A small cross-harness CLI that installs, updates, and tracks
4
+ [The Librarian](https://github.com/JimJafar/the-librarian)'s integrations across
5
+ all your harnesses and machines. Think of it as the package manager for your
6
+ Librarian setup: one tool you keep, driving each harness's **native** install
7
+ path rather than hand-editing five config formats.
8
+
9
+ Harnesses it manages: **Claude Code, Codex, OpenCode, Hermes, Pi.**
10
+
11
+ ## Install
12
+
13
+ Install the CLI globally, then run the interactive setup:
14
+
15
+ ```sh
16
+ npm i -g @the-librarian/cli
17
+ librarian install
18
+ ```
19
+
20
+ That's it — any harness you'd install into already has Node, so there's no
21
+ bootstrap script. `librarian install` with no args opens the interactive
22
+ multi-select and prompts once for your MCP URL + token; pass harness ids to
23
+ target specific ones. Re-run it any time to add a harness.
24
+
25
+ ## Commands
26
+
27
+ ```
28
+ librarian install [harness…] Install into one or more harnesses
29
+ (no args → interactive multi-select; prompts
30
+ for MCP URL + token once)
31
+ librarian uninstall [harness…] Remove The Librarian from each harness
32
+ librarian update [harness…] Update the integration to the current version
33
+ librarian status Live table: harness · installed · version
34
+ librarian doctor Token set? server reachable? which harness CLIs?
35
+ librarian config Show or set MCP URL, token, server URL
36
+ librarian self-update Update the CLI itself (coming in a later release)
37
+ librarian report Push this machine's state to the server
38
+ (coming in a later release)
39
+ ```
40
+
41
+ Useful flags: `--mcp-url <url>`, `--token <token>` (never printed),
42
+ `--shell <bash|zsh|fish>` to override shell detection, `-h/--help`,
43
+ `-v/--version`. Harness ids: `claude`, `codex`, `opencode`, `hermes`, `pi`. A
44
+ harness whose CLI isn't installed is reported `not-detected` and skipped — not
45
+ an error.
46
+
47
+ ## What it writes to your environment
48
+
49
+ The CLI keeps everything under `~/.librarian/`:
50
+
51
+ - **`~/.librarian/env`** — a POSIX env file (`chmod 600`, owner-only) holding
52
+ your two secrets:
53
+
54
+ ```sh
55
+ export LIBRARIAN_MCP_URL="…"
56
+ export LIBRARIAN_AGENT_TOKEN="…"
57
+ ```
58
+
59
+ - **`~/.librarian/machine-id`** — a UUID generated on first run, so the same
60
+ setup on different machines stays distinct in the dashboard.
61
+
62
+ It adds **one** idempotent managed block to your shell rc (`~/.bashrc` /
63
+ `~/.zshrc`) that sources the env file:
64
+
65
+ ```sh
66
+ # >>> librarian >>>
67
+ [ -f "$HOME/.librarian/env" ] && . "$HOME/.librarian/env"
68
+ # <<< librarian <<<
69
+ ```
70
+
71
+ Fish can't source a POSIX file, so it instead gets a native
72
+ `~/.config/fish/conf.d/librarian.fish` with `set -gx`. Re-running any command
73
+ replaces the block — it never duplicates. `librarian config` rewrites
74
+ `~/.librarian/env`.
75
+
76
+ ## Security
77
+
78
+ Your agent token is a credential. The CLI treats it like one:
79
+
80
+ - It's written **only** to `~/.librarian/env`, which is `chmod 600`
81
+ (owner read/write only) — never to a committed or world-readable file.
82
+ - It is **never printed** (not in `status`, `doctor`, `config`, or logs) and
83
+ never put in a URL — bearer tokens travel in headers, to the configured
84
+ server, over the configured URL, and nowhere else.
85
+
86
+ If you ever need to rotate it, re-run `librarian config --token <new>` (or edit
87
+ `~/.librarian/env` directly).
88
+
89
+ > **Avoid `--token <value>` on a shared or audited machine.** A value passed on
90
+ > the command line is visible to anyone who can run `ps` while the command runs,
91
+ > and it lands in your shell history. Prefer entering the token at the
92
+ > interactive prompt — `librarian install` reads it with the echo **muted**, so
93
+ > it never appears on screen, in `ps`, or in history — or edit the `chmod 600`
94
+ > `~/.librarian/env` file directly.
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ // `librarian` CLI bin entrypoint.
3
+ //
4
+ // Runs the typed runtime over the caller's argv, prints the captured
5
+ // stdout/stderr, and translates the structured result into a process exit
6
+ // code. The runtime is pure over `{ home }`, so tests drive it directly
7
+ // without spawning this process.
8
+ import { runCli } from "./runtime.js";
9
+ const result = await runCli(process.argv.slice(2));
10
+ if (result.stdout)
11
+ console.log(result.stdout);
12
+ if (result.stderr)
13
+ console.error(result.stderr);
14
+ process.exitCode = result.exitCode || 0;
15
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,kCAAkC;AAClC,EAAE;AACF,qEAAqE;AACrE,0EAA0E;AAC1E,wEAAwE;AACxE,iCAAiC;AAEjC,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACnD,IAAI,MAAM,CAAC,MAAM;IAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC9C,IAAI,MAAM,CAAC,MAAM;IAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAChD,OAAO,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC"}
@@ -0,0 +1,22 @@
1
+ import type { Shell } from "../env.js";
2
+ import type { Prompter } from "../prompt.js";
3
+ export interface InstallDeps {
4
+ home?: string | undefined;
5
+ shell?: Shell | undefined;
6
+ prompter: Prompter;
7
+ }
8
+ export interface InstallOutcome {
9
+ installed: string[];
10
+ skipped: {
11
+ id: string;
12
+ reason: string;
13
+ }[];
14
+ failed: {
15
+ id: string;
16
+ reason: string;
17
+ }[];
18
+ output: string;
19
+ }
20
+ /** Run the install orchestration over the (possibly empty) named harnesses. */
21
+ export declare function runInstall(named: string[], deps: InstallDeps): Promise<InstallOutcome>;
22
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAIvC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,+EAA+E;AAC/E,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CA2D5F"}
@@ -0,0 +1,152 @@
1
+ // `librarian install [harness…]` orchestration.
2
+ //
3
+ // Flow:
4
+ // 1. Resolve config. If the MCP URL or token is unset, prompt for them
5
+ // (token is a SECRET prompt — never echoed) and persist via `setConfig`,
6
+ // which also (re)applies the managed shell block for the user's shell.
7
+ // 2. Choose harnesses: explicit args win; otherwise an interactive
8
+ // multi-select over the harnesses whose native CLI is on PATH (file-based
9
+ // harnesses always offered). Non-interactive falls back to all available.
10
+ // 3. For each chosen harness, run its native `install(cfg)`:
11
+ // - a "CLI not found" error → SKIP with a note (not a failure);
12
+ // - any OTHER error → attempt `uninstall()` to avoid a half-applied
13
+ // state (spec §9), record it failed, and continue.
14
+ // 4. Print a summary (installed / skipped / failed) + a restart hint.
15
+ import { deriveServerUrl, readConfig, setConfig } from "../config.js";
16
+ import { which } from "../exec.js";
17
+ import { HARNESS_CLI } from "../harnesses/cli.js";
18
+ import { allHarnesses, isHarnessId } from "../harnesses/index.js";
19
+ import { messageOf, toHarnessConfig } from "./shared.js";
20
+ /** Run the install orchestration over the (possibly empty) named harnesses. */
21
+ export async function runInstall(named, deps) {
22
+ const lines = [];
23
+ // 1) Resolve config in-memory, prompting for any missing secret/URL. We do
24
+ // NOT persist `~/.librarian/env` or rewrite the shell rc block yet — that
25
+ // is deferred until at least one harness install succeeds (S1), so a total
26
+ // failure leaves no global side effect. The harness installs consume the
27
+ // in-memory cfg, never the env file, so deferring is safe.
28
+ const { cfg, changed } = await resolveConfig(deps);
29
+ // 2) Choose harnesses.
30
+ const chosen = await chooseHarnesses(named, deps, lines);
31
+ if (chosen.length === 0) {
32
+ lines.push("No harnesses selected — nothing to do.");
33
+ return { installed: [], skipped: [], failed: [], output: lines.join("\n") };
34
+ }
35
+ // 3) Install each, with per-harness skip / rollback.
36
+ const harnessCfg = toHarnessConfig(cfg);
37
+ const installed = [];
38
+ const skipped = [];
39
+ const failed = [];
40
+ for (const harness of chosen) {
41
+ try {
42
+ await harness.install(harnessCfg);
43
+ installed.push(harness.id);
44
+ }
45
+ catch (error) {
46
+ const reason = messageOf(error);
47
+ if (isCliNotFound(reason)) {
48
+ skipped.push({ id: harness.id, reason });
49
+ continue;
50
+ }
51
+ // Mid-install failure → roll back so we don't leave a half-applied
52
+ // state (spec §9). Best-effort: a failed rollback is noted, not fatal.
53
+ let rollbackNote = "";
54
+ try {
55
+ await harness.uninstall();
56
+ rollbackNote = " (rolled back)";
57
+ }
58
+ catch (rollbackError) {
59
+ rollbackNote = ` (rollback also failed: ${messageOf(rollbackError)})`;
60
+ }
61
+ failed.push({ id: harness.id, reason: `${reason}${rollbackNote}` });
62
+ }
63
+ }
64
+ // 4) Now that at least one harness may have succeeded, persist the config
65
+ // (writes `~/.librarian/env` + the managed shell block). Deferred from
66
+ // step 1 so a run where EVERY harness failed leaves no global side effect
67
+ // (S1). Only persist when the values actually changed — keeps re-runs
68
+ // idempotent and quiet.
69
+ if (installed.length > 0 && changed) {
70
+ setConfig({ mcpUrl: cfg.mcpUrl, token: cfg.token }, { home: deps.home, shell: deps.shell });
71
+ lines.unshift("Saved config to ~/.librarian/env and updated the shell block.", "");
72
+ }
73
+ // 5) Summary + restart hint.
74
+ renderSummary(lines, { installed, skipped, failed });
75
+ return { installed, skipped, failed, output: lines.join("\n") };
76
+ }
77
+ /**
78
+ * Resolve the config to install with, prompting for whatever is missing.
79
+ * Returns the in-memory config and whether it differs from what's persisted
80
+ * (so the caller can defer the actual `setConfig` write until a harness
81
+ * install has succeeded — S1). Does NOT touch the filesystem.
82
+ */
83
+ async function resolveConfig(deps) {
84
+ const existing = readConfig(deps.home);
85
+ let mcpUrl = existing?.mcpUrl ?? "";
86
+ let token = existing?.token ?? "";
87
+ if (!mcpUrl) {
88
+ mcpUrl = await deps.prompter.promptText("MCP URL");
89
+ }
90
+ if (!token) {
91
+ token = await deps.prompter.promptText("Agent token", { secret: true });
92
+ }
93
+ const changed = mcpUrl !== existing?.mcpUrl || token !== existing?.token;
94
+ const cfg = { mcpUrl, token, serverUrl: deriveServerUrl(mcpUrl) };
95
+ return { cfg, changed };
96
+ }
97
+ /**
98
+ * Resolve the harness set to install into:
99
+ * - explicit args (validated) win;
100
+ * - otherwise interactive multi-select over harnesses whose CLI is present
101
+ * (file-based harnesses always offered).
102
+ */
103
+ async function chooseHarnesses(named, deps, lines) {
104
+ if (named.length > 0) {
105
+ const valid = [];
106
+ for (const id of named) {
107
+ if (isHarnessId(id)) {
108
+ valid.push(allHarnesses.find((h) => h.id === id));
109
+ }
110
+ else {
111
+ lines.push(`Skipping unknown harness: ${id}`);
112
+ }
113
+ }
114
+ return valid;
115
+ }
116
+ // Default set: harnesses whose CLI is on PATH, plus file-based ones.
117
+ const available = [];
118
+ for (const harness of allHarnesses) {
119
+ const cli = HARNESS_CLI[harness.id];
120
+ if (cli === null || (await which(cli)))
121
+ available.push(harness);
122
+ }
123
+ if (available.length === 0) {
124
+ lines.push("No harness CLIs detected on PATH.");
125
+ return [];
126
+ }
127
+ const selectedIds = await deps.prompter.selectHarnesses(available.map((h) => ({ id: h.id, label: h.displayName })));
128
+ return available.filter((h) => selectedIds.includes(h.id));
129
+ }
130
+ function renderSummary(lines, outcome) {
131
+ lines.push("", "Install summary:");
132
+ if (outcome.installed.length > 0) {
133
+ lines.push(` Installed: ${outcome.installed.join(", ")}`);
134
+ }
135
+ for (const s of outcome.skipped) {
136
+ lines.push(` Skipped ${s.id}: ${s.reason}`);
137
+ }
138
+ for (const f of outcome.failed) {
139
+ lines.push(` Failed ${f.id}: ${f.reason}`);
140
+ }
141
+ if (outcome.installed.length === 0 &&
142
+ outcome.failed.length === 0 &&
143
+ outcome.skipped.length === 0) {
144
+ lines.push(" (nothing installed)");
145
+ }
146
+ lines.push("", "Restart your shell or run `source ~/.librarian/env` to load the new environment.");
147
+ }
148
+ /** True iff the error message is a harness "CLI not found on PATH" signal. */
149
+ function isCliNotFound(message) {
150
+ return /not found on path/i.test(message) || /cli not found/i.test(message);
151
+ }
152
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA,gDAAgD;AAChD,EAAE;AACF,QAAQ;AACR,yEAAyE;AACzE,8EAA8E;AAC9E,4EAA4E;AAC5E,qEAAqE;AACrE,+EAA+E;AAC/E,+EAA+E;AAC/E,+DAA+D;AAC/D,uEAAuE;AACvE,2EAA2E;AAC3E,4DAA4D;AAC5D,wEAAwE;AAExE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAwB,MAAM,cAAc,CAAC;AAE5F,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAsB,MAAM,uBAAuB,CAAC;AAEtF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAezD,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAe,EAAE,IAAiB;IACjE,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,2EAA2E;IAC3E,6EAA6E;IAC7E,8EAA8E;IAC9E,4EAA4E;IAC5E,8DAA8D;IAC9D,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;IAEnD,uBAAuB;IACvB,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IACzD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QACrD,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC9E,CAAC;IAED,qDAAqD;IACrD,MAAM,UAAU,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACxC,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAqC,EAAE,CAAC;IACrD,MAAM,MAAM,GAAqC,EAAE,CAAC;IAEpD,KAAK,MAAM,OAAO,IAAI,MAAM,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAClC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;YAChC,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1B,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;gBACzC,SAAS;YACX,CAAC;YACD,mEAAmE;YACnE,uEAAuE;YACvE,IAAI,YAAY,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC1B,YAAY,GAAG,gBAAgB,CAAC;YAClC,CAAC;YAAC,OAAO,aAAa,EAAE,CAAC;gBACvB,YAAY,GAAG,2BAA2B,SAAS,CAAC,aAAa,CAAC,GAAG,CAAC;YACxE,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,MAAM,GAAG,YAAY,EAAE,EAAE,CAAC,CAAC;QACtE,CAAC;IACH,CAAC;IAED,0EAA0E;IAC1E,0EAA0E;IAC1E,6EAA6E;IAC7E,yEAAyE;IACzE,2BAA2B;IAC3B,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,EAAE,CAAC;QACpC,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5F,KAAK,CAAC,OAAO,CAAC,+DAA+D,EAAE,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,6BAA6B;IAC7B,aAAa,CAAC,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IACrD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAClE,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,aAAa,CAC1B,IAAiB;IAEjB,MAAM,QAAQ,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,MAAM,GAAG,QAAQ,EAAE,MAAM,IAAI,EAAE,CAAC;IACpC,IAAI,KAAK,GAAG,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,KAAK,QAAQ,EAAE,MAAM,IAAI,KAAK,KAAK,QAAQ,EAAE,KAAK,CAAC;IACzE,MAAM,GAAG,GAAoB,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;IACnF,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,eAAe,CAC5B,KAAe,EACf,IAAiB,EACjB,KAAe;IAEf,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,KAAK,GAAoB,EAAE,CAAC;QAClC,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;YACvB,IAAI,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC;gBACpB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAkB,CAAC,CAAC;YACrE,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,CAAC,CAAC;YAChD,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,qEAAqE;IACrE,MAAM,SAAS,GAAoB,EAAE,CAAC;IACtC,KAAK,MAAM,OAAO,IAAI,YAAY,EAAE,CAAC;QACnC,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACpC,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;QAChD,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,eAAe,CACrD,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAC3D,CAAC;IACF,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,aAAa,CACpB,KAAe,EACf,OAIC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC;IACnC,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,gBAAgB,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7D,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,IACE,OAAO,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;QAC9B,OAAO,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;QAC3B,OAAO,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAC5B,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACtC,CAAC;IACD,KAAK,CAAC,IAAI,CACR,EAAE,EACF,kFAAkF,CACnF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,SAAS,aAAa,CAAC,OAAe;IACpC,OAAO,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAC9E,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { LibrarianConfig } from "../config.js";
2
+ import { type HarnessModule } from "../harnesses/index.js";
3
+ import type { HarnessConfig } from "../harnesses/types.js";
4
+ /** Adapt the persisted config into the shape harness modules consume. */
5
+ export declare function toHarnessConfig(cfg: LibrarianConfig): HarnessConfig;
6
+ /**
7
+ * Resolve named harness ids to modules, collecting any unknown ids. An empty
8
+ * `named` list returns every harness (the "all" default for uninstall/update).
9
+ */
10
+ export declare function resolveNamed(named: string[]): {
11
+ harnesses: HarnessModule[];
12
+ unknown: string[];
13
+ };
14
+ /** Pull a clean message string off an unknown thrown value. */
15
+ export declare function messageOf(error: unknown): string;
16
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/commands/shared.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAA6B,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,yEAAyE;AACzE,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,aAAa,CAEnE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG;IAC7C,SAAS,EAAE,aAAa,EAAE,CAAC;IAC3B,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAYA;AAED,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEhD"}
@@ -0,0 +1,30 @@
1
+ // Shared helpers for the harness-touching commands.
2
+ import { allHarnesses, isHarnessId } from "../harnesses/index.js";
3
+ /** Adapt the persisted config into the shape harness modules consume. */
4
+ export function toHarnessConfig(cfg) {
5
+ return { mcpUrl: cfg.mcpUrl, token: cfg.token, serverUrl: cfg.serverUrl };
6
+ }
7
+ /**
8
+ * Resolve named harness ids to modules, collecting any unknown ids. An empty
9
+ * `named` list returns every harness (the "all" default for uninstall/update).
10
+ */
11
+ export function resolveNamed(named) {
12
+ if (named.length === 0)
13
+ return { harnesses: [...allHarnesses], unknown: [] };
14
+ const harnesses = [];
15
+ const unknown = [];
16
+ for (const id of named) {
17
+ if (isHarnessId(id)) {
18
+ harnesses.push(allHarnesses.find((h) => h.id === id));
19
+ }
20
+ else {
21
+ unknown.push(id);
22
+ }
23
+ }
24
+ return { harnesses, unknown };
25
+ }
26
+ /** Pull a clean message string off an unknown thrown value. */
27
+ export function messageOf(error) {
28
+ return error instanceof Error ? error.message : String(error);
29
+ }
30
+ //# sourceMappingURL=shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/commands/shared.ts"],"names":[],"mappings":"AAAA,oDAAoD;AAGpD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAsB,MAAM,uBAAuB,CAAC;AAGtF,yEAAyE;AACzE,MAAM,UAAU,eAAe,CAAC,GAAoB;IAClD,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;AAC5E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAe;IAI1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC7E,MAAM,SAAS,GAAoB,EAAE,CAAC;IACtC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC;YACpB,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAkB,CAAC,CAAC;QACzE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AAChC,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,SAAS,CAAC,KAAc;IACtC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type Shell } from "../env.js";
2
+ import type { Prompter } from "../prompt.js";
3
+ export interface UninstallDeps {
4
+ home?: string | undefined;
5
+ shell?: Shell | undefined;
6
+ prompter: Prompter;
7
+ }
8
+ export interface UninstallOutcome {
9
+ removed: string[];
10
+ failed: {
11
+ id: string;
12
+ reason: string;
13
+ }[];
14
+ envRemoved: boolean;
15
+ output: string;
16
+ }
17
+ export declare function runUninstall(named: string[], deps: UninstallDeps): Promise<UninstallOutcome>;
18
+ //# sourceMappingURL=uninstall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.d.ts","sourceRoot":"","sources":["../../src/commands/uninstall.ts"],"names":[],"mappings":"AASA,OAAO,EAAiC,KAAK,KAAK,EAAE,MAAM,WAAW,CAAC;AAGtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAG7C,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC;IAC1B,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzC,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,YAAY,CAChC,KAAK,EAAE,MAAM,EAAE,EACf,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,gBAAgB,CAAC,CA6C3B"}
@@ -0,0 +1,67 @@
1
+ // `librarian uninstall [harness…]` orchestration.
2
+ //
3
+ // Each harness's `uninstall()` is no-op safe, so we just call them. After
4
+ // removing the named (or all) harnesses, if NO harness remains installed we
5
+ // OFFER to remove the managed shell block + `~/.librarian/env` — prompting,
6
+ // defaulting to NO (we never tear down the user's env without consent).
7
+ import fs from "node:fs";
8
+ import { readConfig } from "../config.js";
9
+ import { detectShell, removeShellBlock } from "../env.js";
10
+ import { allHarnesses } from "../harnesses/index.js";
11
+ import { envFilePath } from "../paths.js";
12
+ import { messageOf, resolveNamed } from "./shared.js";
13
+ export async function runUninstall(named, deps) {
14
+ const lines = [];
15
+ const { harnesses, unknown } = resolveNamed(named);
16
+ for (const id of unknown)
17
+ lines.push(`Skipping unknown harness: ${id}`);
18
+ const removed = [];
19
+ const failed = [];
20
+ for (const harness of harnesses) {
21
+ try {
22
+ await harness.uninstall();
23
+ removed.push(harness.id);
24
+ }
25
+ catch (error) {
26
+ failed.push({ id: harness.id, reason: messageOf(error) });
27
+ }
28
+ }
29
+ lines.push("Uninstall summary:");
30
+ if (removed.length > 0)
31
+ lines.push(` Removed: ${removed.join(", ")}`);
32
+ for (const f of failed)
33
+ lines.push(` Failed ${f.id}: ${f.reason}`);
34
+ if (removed.length === 0 && failed.length === 0)
35
+ lines.push(" (nothing to remove)");
36
+ // If nothing remains installed across ALL harnesses, offer to tear down env.
37
+ let envRemoved = false;
38
+ const stillInstalled = await anyInstalled();
39
+ if (!stillInstalled && readConfig(deps.home)) {
40
+ const answer = await deps.prompter.promptText("No harnesses remain installed. Remove the shell block + ~/.librarian/env?", { default: "no" });
41
+ if (isYes(answer)) {
42
+ const shell = deps.shell ?? detectShell();
43
+ removeShellBlock(shell, deps.home);
44
+ try {
45
+ fs.rmSync(envFilePath(deps.home));
46
+ }
47
+ catch {
48
+ // already gone
49
+ }
50
+ envRemoved = true;
51
+ lines.push("", "Removed the managed shell block and ~/.librarian/env.");
52
+ }
53
+ else {
54
+ lines.push("", "Left the shell block and ~/.librarian/env in place.");
55
+ }
56
+ }
57
+ return { removed, failed, envRemoved, output: lines.join("\n") };
58
+ }
59
+ /** True iff any harness still reports itself installed. */
60
+ async function anyInstalled() {
61
+ const detections = await Promise.all(allHarnesses.map((h) => h.detect()));
62
+ return detections.some((d) => d.installed);
63
+ }
64
+ function isYes(answer) {
65
+ return /^y(es)?$/i.test(answer.trim());
66
+ }
67
+ //# sourceMappingURL=uninstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uninstall.js","sourceRoot":"","sources":["../../src/commands/uninstall.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ export interface UpdateDeps {
2
+ home?: string | undefined;
3
+ }
4
+ export interface UpdateOutcome {
5
+ updated: {
6
+ id: string;
7
+ from?: string | undefined;
8
+ to?: string | undefined;
9
+ }[];
10
+ skipped: {
11
+ id: string;
12
+ reason: string;
13
+ }[];
14
+ failed: {
15
+ id: string;
16
+ reason: string;
17
+ }[];
18
+ output: string;
19
+ }
20
+ export declare function runUpdate(named: string[], deps: UpdateDeps): Promise<UpdateOutcome>;
21
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAYA,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,EAAE,CAAC;IAC9E,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,MAAM,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CAiEzF"}
@@ -0,0 +1,75 @@
1
+ // `librarian update [harness…]` orchestration.
2
+ //
3
+ // For each target harness — the named ones, or every CURRENTLY-INSTALLED
4
+ // harness when none are named — run its native `update(cfg)` and report the
5
+ // version transition (old → new) where both are detectable. Update needs
6
+ // config (it re-applies the integration), so it errors clearly if config is
7
+ // unset. A "CLI not found" error is a SKIP, not a failure, mirroring install.
8
+ import { readConfig } from "../config.js";
9
+ import { allHarnesses } from "../harnesses/index.js";
10
+ import { messageOf, resolveNamed, toHarnessConfig } from "./shared.js";
11
+ export async function runUpdate(named, deps) {
12
+ const lines = [];
13
+ const cfg = readConfig(deps.home);
14
+ if (!cfg || !cfg.mcpUrl || !cfg.token) {
15
+ lines.push("No config set. Run `librarian config --mcp-url <url> --token <token>` first.");
16
+ return { updated: [], skipped: [], failed: [], output: lines.join("\n") };
17
+ }
18
+ const harnessCfg = toHarnessConfig(cfg);
19
+ // Targets: named (validated), else every currently-installed harness.
20
+ const { harnesses: namedHarnesses, unknown } = resolveNamed(named);
21
+ for (const id of unknown)
22
+ lines.push(`Skipping unknown harness: ${id}`);
23
+ let targets;
24
+ if (named.length > 0) {
25
+ targets = namedHarnesses;
26
+ }
27
+ else {
28
+ const detections = await Promise.all(allHarnesses.map((h) => h.detect()));
29
+ targets = allHarnesses.filter((_, i) => detections[i]?.installed);
30
+ if (targets.length === 0) {
31
+ lines.push("No harnesses are currently installed — nothing to update.");
32
+ return { updated: [], skipped: [], failed: [], output: lines.join("\n") };
33
+ }
34
+ }
35
+ const updated = [];
36
+ const skipped = [];
37
+ const failed = [];
38
+ for (const harness of targets) {
39
+ const before = (await harness.detect()).version;
40
+ try {
41
+ await harness.update(harnessCfg);
42
+ }
43
+ catch (error) {
44
+ const reason = messageOf(error);
45
+ if (/not found on path/i.test(reason) || /cli not found/i.test(reason)) {
46
+ skipped.push({ id: harness.id, reason });
47
+ continue;
48
+ }
49
+ failed.push({ id: harness.id, reason });
50
+ continue;
51
+ }
52
+ const after = (await harness.detect()).version;
53
+ updated.push({ id: harness.id, from: before, to: after });
54
+ }
55
+ lines.push("Update summary:");
56
+ for (const u of updated) {
57
+ const transition = u.from && u.to
58
+ ? u.from === u.to
59
+ ? `already at ${u.to}`
60
+ : `${u.from} → ${u.to}`
61
+ : u.to
62
+ ? `now ${u.to}`
63
+ : "updated";
64
+ lines.push(` ${u.id}: ${transition}`);
65
+ }
66
+ for (const s of skipped)
67
+ lines.push(` Skipped ${s.id}: ${s.reason}`);
68
+ for (const f of failed)
69
+ lines.push(` Failed ${f.id}: ${f.reason}`);
70
+ if (updated.length === 0 && skipped.length === 0 && failed.length === 0) {
71
+ lines.push(" (nothing updated)");
72
+ }
73
+ return { updated, skipped, failed, output: lines.join("\n") };
74
+ }
75
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ import { type Shell } from "./env.js";
2
+ export interface LibrarianConfig {
3
+ /** The MCP endpoint URL the harnesses talk to. */
4
+ mcpUrl: string;
5
+ /** The bearer token. NEVER printed; redacted on display. */
6
+ token: string;
7
+ /** The server base URL; defaults to the MCP URL's origin. */
8
+ serverUrl: string;
9
+ }
10
+ /** A display-safe view of the config — token is redacted to a boolean. */
11
+ export interface RedactedConfig {
12
+ mcpUrl: string;
13
+ /** True iff a non-empty token is set. The value itself is never exposed. */
14
+ tokenSet: boolean;
15
+ serverUrl: string;
16
+ }
17
+ /** Derive the server base URL (origin) from the MCP URL; "" if unparseable. */
18
+ export declare function deriveServerUrl(mcpUrl: string): string;
19
+ /** Load the current config from `~/.librarian/env`, or null if unset. */
20
+ export declare function readConfig(home?: string): LibrarianConfig | null;
21
+ /** A display-safe view: the token is reduced to a boolean, never printed. */
22
+ export declare function redact(config: LibrarianConfig): RedactedConfig;
23
+ /** Render the redacted config as human-readable lines (no token value). */
24
+ export declare function formatConfig(config: RedactedConfig): string;
25
+ export interface SetConfigInput {
26
+ mcpUrl?: string | undefined;
27
+ token?: string | undefined;
28
+ }
29
+ /**
30
+ * Update config values and persist them to `~/.librarian/env`.
31
+ *
32
+ * Merges over whatever is already stored (so setting just the token
33
+ * keeps the URL). Re-applies the managed shell block so a fresh `config`
34
+ * on a new shell still wires up sourcing. Returns the new config.
35
+ */
36
+ export declare function setConfig(input: SetConfigInput, options?: {
37
+ home?: string | undefined;
38
+ shell?: Shell | undefined;
39
+ }): LibrarianConfig;
40
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AASA,OAAO,EAA0C,KAAK,KAAK,EAAE,MAAM,UAAU,CAAC;AAG9E,MAAM,WAAW,eAAe;IAC9B,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOtD;AAED,yEAAyE;AACzE,wBAAgB,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAQhE;AAED,6EAA6E;AAC7E,wBAAgB,MAAM,CAAC,MAAM,EAAE,eAAe,GAAG,cAAc,CAM9D;AAED,2EAA2E;AAC3E,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAM3D;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,cAAc,EACrB,OAAO,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,GAAG,SAAS,CAAA;CAAO,GACrE,eAAe,CAQjB"}