@the-librarian/cli 1.0.0-rc.21
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/LICENSE +201 -0
- package/README.md +94 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +15 -0
- package/dist/bin.js.map +1 -0
- package/dist/commands/install.d.ts +28 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +204 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/shared.d.ts +16 -0
- package/dist/commands/shared.d.ts.map +1 -0
- package/dist/commands/shared.js +30 -0
- package/dist/commands/shared.js.map +1 -0
- package/dist/commands/uninstall.d.ts +18 -0
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/commands/uninstall.js +67 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/update.d.ts +21 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +75 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/config.d.ts +40 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +65 -0
- package/dist/config.js.map +1 -0
- package/dist/doctor.d.ts +23 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +81 -0
- package/dist/doctor.js.map +1 -0
- package/dist/env.d.ts +39 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +208 -0
- package/dist/env.js.map +1 -0
- package/dist/exec.d.ts +37 -0
- package/dist/exec.d.ts.map +1 -0
- package/dist/exec.js +81 -0
- package/dist/exec.js.map +1 -0
- package/dist/harnesses/claude.d.ts +3 -0
- package/dist/harnesses/claude.d.ts.map +1 -0
- package/dist/harnesses/claude.js +88 -0
- package/dist/harnesses/claude.js.map +1 -0
- package/dist/harnesses/cli.d.ts +4 -0
- package/dist/harnesses/cli.d.ts.map +1 -0
- package/dist/harnesses/cli.js +16 -0
- package/dist/harnesses/cli.js.map +1 -0
- package/dist/harnesses/codex.d.ts +3 -0
- package/dist/harnesses/codex.d.ts.map +1 -0
- package/dist/harnesses/codex.js +183 -0
- package/dist/harnesses/codex.js.map +1 -0
- package/dist/harnesses/hermes.d.ts +16 -0
- package/dist/harnesses/hermes.d.ts.map +1 -0
- package/dist/harnesses/hermes.js +158 -0
- package/dist/harnesses/hermes.js.map +1 -0
- package/dist/harnesses/index.d.ts +12 -0
- package/dist/harnesses/index.d.ts.map +1 -0
- package/dist/harnesses/index.js +29 -0
- package/dist/harnesses/index.js.map +1 -0
- package/dist/harnesses/opencode.d.ts +3 -0
- package/dist/harnesses/opencode.d.ts.map +1 -0
- package/dist/harnesses/opencode.js +141 -0
- package/dist/harnesses/opencode.js.map +1 -0
- package/dist/harnesses/pi.d.ts +3 -0
- package/dist/harnesses/pi.d.ts.map +1 -0
- package/dist/harnesses/pi.js +72 -0
- package/dist/harnesses/pi.js.map +1 -0
- package/dist/harnesses/types.d.ts +48 -0
- package/dist/harnesses/types.d.ts.map +1 -0
- package/dist/harnesses/types.js +22 -0
- package/dist/harnesses/types.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/machine.d.ts +10 -0
- package/dist/machine.d.ts.map +1 -0
- package/dist/machine.js +39 -0
- package/dist/machine.js.map +1 -0
- package/dist/parse-args.d.ts +12 -0
- package/dist/parse-args.d.ts.map +1 -0
- package/dist/parse-args.js +54 -0
- package/dist/parse-args.js.map +1 -0
- package/dist/paths.d.ts +32 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +75 -0
- package/dist/paths.js.map +1 -0
- package/dist/prompt.d.ts +53 -0
- package/dist/prompt.d.ts.map +1 -0
- package/dist/prompt.js +165 -0
- package/dist/prompt.js.map +1 -0
- package/dist/runtime.d.ts +45 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +370 -0
- package/dist/runtime.js.map +1 -0
- package/dist/semver.d.ts +13 -0
- package/dist/semver.d.ts.map +1 -0
- package/dist/semver.js +98 -0
- package/dist/semver.js.map +1 -0
- package/dist/server/admin.d.ts +31 -0
- package/dist/server/admin.d.ts.map +1 -0
- package/dist/server/admin.js +110 -0
- package/dist/server/admin.js.map +1 -0
- package/dist/server/boot.d.ts +51 -0
- package/dist/server/boot.d.ts.map +1 -0
- package/dist/server/boot.js +233 -0
- package/dist/server/boot.js.map +1 -0
- package/dist/server/deploy-state.d.ts +33 -0
- package/dist/server/deploy-state.d.ts.map +1 -0
- package/dist/server/deploy-state.js +79 -0
- package/dist/server/deploy-state.js.map +1 -0
- package/dist/server/docker.d.ts +37 -0
- package/dist/server/docker.d.ts.map +1 -0
- package/dist/server/docker.js +138 -0
- package/dist/server/docker.js.map +1 -0
- package/dist/server/down.d.ts +19 -0
- package/dist/server/down.d.ts.map +1 -0
- package/dist/server/down.js +62 -0
- package/dist/server/down.js.map +1 -0
- package/dist/server/index.d.ts +8 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +48 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/logs.d.ts +50 -0
- package/dist/server/logs.d.ts.map +1 -0
- package/dist/server/logs.js +162 -0
- package/dist/server/logs.js.map +1 -0
- package/dist/server/preflight.d.ts +24 -0
- package/dist/server/preflight.d.ts.map +1 -0
- package/dist/server/preflight.js +58 -0
- package/dist/server/preflight.js.map +1 -0
- package/dist/server/redact.d.ts +2 -0
- package/dist/server/redact.d.ts.map +1 -0
- package/dist/server/redact.js +26 -0
- package/dist/server/redact.js.map +1 -0
- package/dist/server/status.d.ts +20 -0
- package/dist/server/status.d.ts.map +1 -0
- package/dist/server/status.js +103 -0
- package/dist/server/status.js.map +1 -0
- package/dist/server/up.d.ts +211 -0
- package/dist/server/up.d.ts.map +1 -0
- package/dist/server/up.js +625 -0
- package/dist/server/up.js.map +1 -0
- package/dist/server/update.d.ts +35 -0
- package/dist/server/update.d.ts.map +1 -0
- package/dist/server/update.js +308 -0
- package/dist/server/update.js.map +1 -0
- package/dist/status.d.ts +18 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +113 -0
- package/dist/status.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +20 -0
- package/dist/version.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,625 @@
|
|
|
1
|
+
// `librarian server up` — build + run the all-in-one container.
|
|
2
|
+
//
|
|
3
|
+
// This is the loop-closer: on a fresh Docker host it clones the monorepo at the
|
|
4
|
+
// resolved release tag, builds `the-librarian:<tag>`, mints the master key +
|
|
5
|
+
// agent token into a 0600 deploy env-file, runs the all-in-one container with
|
|
6
|
+
// `docker run --env-file` (ADR 0008 P4 — secrets off argv), waits for it to
|
|
7
|
+
// report healthy, surfaces the CLI-MINTED master key ONCE, and prints the MCP
|
|
8
|
+
// URL + dashboard URL + the agent token ready to paste into `librarian install`.
|
|
9
|
+
//
|
|
10
|
+
// ADR 0008 P3: there is no admin token. The admin tRPC API is served only on the
|
|
11
|
+
// trusted internal listener (off the network), so `server up` neither reads back
|
|
12
|
+
// nor surfaces an admin token, regardless of bind host.
|
|
13
|
+
//
|
|
14
|
+
// Bind host (spec §5.3 / §6): the default is `127.0.0.1` (host loopback only).
|
|
15
|
+
// `--host <addr>` sets it explicitly. Best-effort, an interactive run with no
|
|
16
|
+
// `--host` is OFFERED a detected Tailscale tailnet IP. Binding to `0.0.0.0`
|
|
17
|
+
// (all interfaces) is ask-first. We NEVER default to `0.0.0.0`, and a
|
|
18
|
+
// non-interactive/`--yes` run never silently exposes the server beyond
|
|
19
|
+
// localhost.
|
|
20
|
+
//
|
|
21
|
+
// The bind choice drives the localhost no-auth bypass via `LIBRARIAN_ALLOW_NO_AUTH`
|
|
22
|
+
// (the image always binds `0.0.0.0` internally, so the server can't see the host
|
|
23
|
+
// publish address — spec §6). Post ADR 0008 P4 it lives in the deploy env-file,
|
|
24
|
+
// not inline on argv:
|
|
25
|
+
// - `127.0.0.1` → env-file carries `LIBRARIAN_ALLOW_NO_AUTH=true`; /mcp
|
|
26
|
+
// grants the agent role without a token (loopback bypass).
|
|
27
|
+
// - tailnet / `0.0.0.0`→ OMIT it; /mcp requires the agent token. (The admin
|
|
28
|
+
// tRPC API is off the network entirely — ADR 0008.)
|
|
29
|
+
//
|
|
30
|
+
// EVERYTHING that touches the system is injected (`docker.ts` runner — which
|
|
31
|
+
// also routes the Tailscale probe, the latest-release fetcher, the prompter,
|
|
32
|
+
// `home`, the interactivity flag, and the health-poll sleep), so the whole flow
|
|
33
|
+
// is exercised in tests WITHOUT a real daemon, network, git, or tailscale.
|
|
34
|
+
//
|
|
35
|
+
// Security (AGENTS.md): the agent token + master key ride ONLY in the 0600
|
|
36
|
+
// deploy env-file fed to `docker run --env-file` (ADR 0008 P4) — never inline
|
|
37
|
+
// on argv. `--env-file` keeps them off the process argv (and out of any
|
|
38
|
+
// argv-echoing error); it does NOT hide them from `docker inspect .Config.Env`
|
|
39
|
+
// (docker expands the file client-side into the same env list) — that's an
|
|
40
|
+
// accepted trade-off (the wins are off-argv + off `/data`; truly hiding from
|
|
41
|
+
// `docker inspect` would need a mounted-file+entrypoint approach we deliberately
|
|
42
|
+
// did not build). The agent token may ALSO (if the user accepts) land in
|
|
43
|
+
// `~/.librarian/env` via env.ts. The master key is surfaced to stdout exactly
|
|
44
|
+
// once and is NEVER written to any host file other than the 0600 deploy env-file.
|
|
45
|
+
import { randomBytes } from "node:crypto";
|
|
46
|
+
import fs from "node:fs";
|
|
47
|
+
import { isIP } from "node:net";
|
|
48
|
+
import path from "node:path";
|
|
49
|
+
import { readEnvFile, writeEnvFile } from "../env.js";
|
|
50
|
+
import { librarianDir } from "../paths.js";
|
|
51
|
+
import { fetchLatestVersion } from "../status.js";
|
|
52
|
+
import { enableBoot } from "./boot.js";
|
|
53
|
+
import { writeDeployState } from "./deploy-state.js";
|
|
54
|
+
import { run, which } from "./docker.js";
|
|
55
|
+
import { preflight } from "./preflight.js";
|
|
56
|
+
import { redactSecrets } from "./redact.js";
|
|
57
|
+
// Re-exported from its shared home so existing importers (`update.ts`) keep
|
|
58
|
+
// working; new code should import from `./redact.js` directly.
|
|
59
|
+
export { redactSecrets } from "./redact.js";
|
|
60
|
+
/** The repository the deploy dir clones (same repo the latest-tag fetch targets). */
|
|
61
|
+
export const REPO_URL = "https://github.com/JimJafar/the-librarian";
|
|
62
|
+
/** The container name every `server` command operates on (single instance per host). */
|
|
63
|
+
export const CONTAINER_NAME = "the-librarian";
|
|
64
|
+
/** The named data volume default (`--data-volume` overrides). The volume is sacred. */
|
|
65
|
+
export const DEFAULT_DATA_VOLUME = "librarian_data";
|
|
66
|
+
/** Host loopback — the default, only-reachable-locally bind (spec §5/§6). */
|
|
67
|
+
export const LOCALHOST = "127.0.0.1";
|
|
68
|
+
/** Bind-all-interfaces — never the default; ask-first (spec §5.3, §11). */
|
|
69
|
+
export const ALL_INTERFACES = "0.0.0.0";
|
|
70
|
+
/** The warning printed beside the one-time master-key surfacing (spec §5.4). */
|
|
71
|
+
export const SAVE_KEY_WARNING = "SAVE THIS KEY — excluded from backups";
|
|
72
|
+
/**
|
|
73
|
+
* The 0600 deploy env-file fed to `docker run --env-file` (ADR 0008 P4). It
|
|
74
|
+
* lives in the deploy dir (alongside `deploy-state.json`) and carries the agent
|
|
75
|
+
* token + master key + (loopback) `LIBRARIAN_ALLOW_NO_AUTH`. It is DISTINCT from
|
|
76
|
+
* the client `~/.librarian/env` (env.ts). 0600, by construction.
|
|
77
|
+
*/
|
|
78
|
+
export const DEPLOY_ENV_FILE = "deploy.env";
|
|
79
|
+
/** `<deployDir>/deploy.env` — the 0600 deploy env-file path within a deploy dir. */
|
|
80
|
+
export function deployEnvFilePath(deployDir) {
|
|
81
|
+
return path.join(deployDir, DEPLOY_ENV_FILE);
|
|
82
|
+
}
|
|
83
|
+
const realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
84
|
+
let sleepImpl = realSleep;
|
|
85
|
+
/** Override the health-poll sleep (tests inject a no-op so polling is instant). */
|
|
86
|
+
export function setSleep(next) {
|
|
87
|
+
sleepImpl = next;
|
|
88
|
+
}
|
|
89
|
+
/** Restore the real sleep (tests). */
|
|
90
|
+
export function resetSleep() {
|
|
91
|
+
sleepImpl = realSleep;
|
|
92
|
+
}
|
|
93
|
+
const realMinter = () => randomBytes(32).toString("hex");
|
|
94
|
+
let minter = realMinter;
|
|
95
|
+
/** Override the agent-token minter (tests). */
|
|
96
|
+
export function setTokenMinter(next) {
|
|
97
|
+
minter = next;
|
|
98
|
+
}
|
|
99
|
+
/** Restore the real CSPRNG minter (tests). */
|
|
100
|
+
export function resetTokenMinter() {
|
|
101
|
+
minter = realMinter;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Mint one agent token through the CURRENT minter. Exported so `update` mints a
|
|
105
|
+
* fresh token (when the old container's token can't be read back) via the same
|
|
106
|
+
* injectable seam `up` uses — a single deterministic value in tests.
|
|
107
|
+
*/
|
|
108
|
+
export function mintAgentToken() {
|
|
109
|
+
return minter();
|
|
110
|
+
}
|
|
111
|
+
const realKeyMinter = () => randomBytes(32).toString("hex");
|
|
112
|
+
let keyMinter = realKeyMinter;
|
|
113
|
+
/** Override the master-key minter (tests). */
|
|
114
|
+
export function setSecretKeyMinter(next) {
|
|
115
|
+
keyMinter = next;
|
|
116
|
+
}
|
|
117
|
+
/** Restore the real CSPRNG master-key minter (tests). */
|
|
118
|
+
export function resetSecretKeyMinter() {
|
|
119
|
+
keyMinter = realKeyMinter;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Mint one master key through the CURRENT minter. Exported so `update` can mint a
|
|
123
|
+
* fresh key (only when the old container's key can't be read back) via the same
|
|
124
|
+
* injectable seam `up` uses — a single deterministic value in tests.
|
|
125
|
+
*/
|
|
126
|
+
export function mintSecretKey() {
|
|
127
|
+
return keyMinter();
|
|
128
|
+
}
|
|
129
|
+
/** A teaching error from `up`; the runtime renders `.message` as one stderr line. */
|
|
130
|
+
export class UpError extends Error {
|
|
131
|
+
constructor(message) {
|
|
132
|
+
super(message);
|
|
133
|
+
this.name = "UpError";
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Construct the `docker run` argv (everything after `docker`). The SINGLE place
|
|
138
|
+
* the run vector is assembled.
|
|
139
|
+
*
|
|
140
|
+
* Secrets are delivered via `--env-file <path>` — NOT inline `-e` — so the agent
|
|
141
|
+
* token, the master key, and (loopback only) `LIBRARIAN_ALLOW_NO_AUTH` never
|
|
142
|
+
* appear on argv (ADR 0008 P4). `--env-file` keeps them off argv (and out of any
|
|
143
|
+
* argv-echoing error); it does NOT hide them from `docker inspect .Config.Env`
|
|
144
|
+
* (docker expands the file client-side into the same env list) — an accepted
|
|
145
|
+
* trade-off (the wins are off-argv + the master key off `/data`).
|
|
146
|
+
*
|
|
147
|
+
* The image runs `tini` as PID 1, so `--init` is deliberately omitted. The
|
|
148
|
+
* publish address is derived from `host`; the loopback no-auth bypass
|
|
149
|
+
* (`LIBRARIAN_ALLOW_NO_AUTH`) lives INSIDE the env-file (loopback-only — see
|
|
150
|
+
* {@link writeDeployEnvFile}), not on this argv.
|
|
151
|
+
*/
|
|
152
|
+
export function buildRunArgs(input) {
|
|
153
|
+
const { host, dataVolume, tag, envFile } = input;
|
|
154
|
+
return [
|
|
155
|
+
"run",
|
|
156
|
+
"-d",
|
|
157
|
+
"--name",
|
|
158
|
+
CONTAINER_NAME,
|
|
159
|
+
"--restart",
|
|
160
|
+
"unless-stopped",
|
|
161
|
+
"-p",
|
|
162
|
+
`${host}:3000:3000`,
|
|
163
|
+
"-p",
|
|
164
|
+
`${host}:3838:3838`,
|
|
165
|
+
"-v",
|
|
166
|
+
`${dataVolume}:/data`,
|
|
167
|
+
"--env-file",
|
|
168
|
+
envFile,
|
|
169
|
+
`${CONTAINER_NAME}:${tag}`,
|
|
170
|
+
];
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Write the 0600 deploy env-file `docker run --env-file` reads, returning its
|
|
174
|
+
* path. It carries `LIBRARIAN_AGENT_TOKEN`, `LIBRARIAN_SECRET_KEY` (when
|
|
175
|
+
* supplied), and (loopback only) `LIBRARIAN_ALLOW_NO_AUTH=true`. Mode 0600 on
|
|
176
|
+
* create AND an unconditional `chmodSync(0o600)` so a pre-existing looser file is
|
|
177
|
+
* tightened (same discipline as env.ts `writeEnvFile`). The directory is created
|
|
178
|
+
* if missing.
|
|
179
|
+
*
|
|
180
|
+
* Format is `KEY=VALUE` lines (docker's `--env-file` syntax — NOT shell, so no
|
|
181
|
+
* quoting/`export`). The minted secrets are 64-hex with no special chars, so a
|
|
182
|
+
* raw value is safe; we reject a value with a newline (it would corrupt the file
|
|
183
|
+
* / smuggle a second var) rather than emit a malformed file.
|
|
184
|
+
*/
|
|
185
|
+
export function writeDeployEnvFile(deployDir, input) {
|
|
186
|
+
const secretKey = input.secretKey?.trim() ?? "";
|
|
187
|
+
for (const [name, value] of [
|
|
188
|
+
["LIBRARIAN_AGENT_TOKEN", input.agentToken],
|
|
189
|
+
["LIBRARIAN_SECRET_KEY", secretKey],
|
|
190
|
+
]) {
|
|
191
|
+
if (/[\r\n]/.test(value)) {
|
|
192
|
+
throw new UpError(`Refusing to write ${name} containing a newline to the deploy env-file.`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
fs.mkdirSync(deployDir, { recursive: true });
|
|
196
|
+
const lines = [`LIBRARIAN_AGENT_TOKEN=${input.agentToken}`];
|
|
197
|
+
// Omit the key line entirely when absent (update's read-back-failed path) — the
|
|
198
|
+
// server then resolves it from /data/secret.key, preserving encrypted secrets.
|
|
199
|
+
if (secretKey) {
|
|
200
|
+
lines.push(`LIBRARIAN_SECRET_KEY=${secretKey}`);
|
|
201
|
+
}
|
|
202
|
+
if (input.host === LOCALHOST) {
|
|
203
|
+
lines.push("LIBRARIAN_ALLOW_NO_AUTH=true");
|
|
204
|
+
}
|
|
205
|
+
const file = deployEnvFilePath(deployDir);
|
|
206
|
+
fs.writeFileSync(file, `${lines.join("\n")}\n`, { encoding: "utf8", mode: 0o600 });
|
|
207
|
+
// writeFileSync only applies `mode` on create; chmod unconditionally so a
|
|
208
|
+
// pre-existing looser file is tightened (env.ts discipline).
|
|
209
|
+
fs.chmodSync(file, 0o600);
|
|
210
|
+
return file;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Run `server up`. Throws `UpError` (teaching message) on any failure; on a
|
|
214
|
+
* failed health-wait it rolls the container back first so no half-up state is
|
|
215
|
+
* left behind. Works for any resolved bind host (loopback / tailnet / all
|
|
216
|
+
* interfaces); the bind choice drives the auth model (§6).
|
|
217
|
+
*/
|
|
218
|
+
export async function runUp(options, deps) {
|
|
219
|
+
// 1) Preflight: docker (daemon reachable) + git, or a teaching error.
|
|
220
|
+
await preflight(deps.platform ? { platform: deps.platform } : {});
|
|
221
|
+
// 2) Resolve the bind host (default loopback; Tailscale offer; `0.0.0.0`
|
|
222
|
+
// ask-first). May throw `UpError` if the user declines a `0.0.0.0` bind —
|
|
223
|
+
// BEFORE any clone/build/run, so a declined exposure leaves nothing behind.
|
|
224
|
+
const host = await resolveBindHost(options, deps);
|
|
225
|
+
const dataVolume = options.dataVolume ?? DEFAULT_DATA_VOLUME;
|
|
226
|
+
const deployDir = options.dir ?? path.join(librarianDir(deps.home), "server");
|
|
227
|
+
// 3) Resolve the ref (default = latest release tag), then the deploy dir.
|
|
228
|
+
const tag = await resolveRef(options.ref);
|
|
229
|
+
await prepareDeployDir(deployDir, tag);
|
|
230
|
+
// 4) Mint the secrets the CLI owns (the loop-closer). Both are CSPRNG and
|
|
231
|
+
// NEVER logged: the agent token, and — ADR 0008 P4 — the master key. The
|
|
232
|
+
// CLI minting the master key (env wins in core's `env → file → generate`)
|
|
233
|
+
// is what keeps it OFF `/data/secret.key`. They ride only in the 0600
|
|
234
|
+
// deploy env-file fed to `--env-file`, never inline on argv.
|
|
235
|
+
const agentToken = minter();
|
|
236
|
+
const masterKey = mintSecretKey();
|
|
237
|
+
const envFile = writeDeployEnvFile(deployDir, { agentToken, secretKey: masterKey, host });
|
|
238
|
+
// 5) Build the image, then run the container (secrets via `--env-file`).
|
|
239
|
+
await build(deployDir, tag);
|
|
240
|
+
await dockerRun(buildRunArgs({ host, dataVolume, tag, envFile }), deployDir);
|
|
241
|
+
// 6+7) Wait for health. ANY failure in this post-`docker run` phase — a
|
|
242
|
+
// timeout/unhealthy report or an exception from `docker inspect`/`sleep`
|
|
243
|
+
// — MUST force-remove the container so no half-up state is left behind
|
|
244
|
+
// (spec §11). `waitForHealthy` already rolls back on its own
|
|
245
|
+
// timeout/unhealthy path; this guard catches the throwing cases it
|
|
246
|
+
// can't (the second `rm -f` is best-effort + idempotent).
|
|
247
|
+
//
|
|
248
|
+
// ADR 0008 P4: the master key is no longer READ BACK from the container
|
|
249
|
+
// (`docker exec cat /data/secret.key`) — the CLI minted it and supplied
|
|
250
|
+
// it via env, so the server never writes that file. We surface the
|
|
251
|
+
// key we minted.
|
|
252
|
+
try {
|
|
253
|
+
await waitForHealthy(options);
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
await run("docker", ["rm", "-f", CONTAINER_NAME]).catch(() => undefined);
|
|
257
|
+
throw error;
|
|
258
|
+
}
|
|
259
|
+
// 7b) Persist the NON-SECRET deploy-state so `update` can recreate the
|
|
260
|
+
// container with the same config and `status` can report the deployed
|
|
261
|
+
// ref reliably. This carries the bind host / data volume / ref / image
|
|
262
|
+
// tag / container name — NEVER a token or key (deploy-state.ts whitelists
|
|
263
|
+
// the fields). Only after a confirmed-healthy run, so the recorded state
|
|
264
|
+
// reflects a container that actually came up.
|
|
265
|
+
writeDeployState(deployDir, {
|
|
266
|
+
containerName: CONTAINER_NAME,
|
|
267
|
+
host,
|
|
268
|
+
dataVolume,
|
|
269
|
+
ref: tag,
|
|
270
|
+
imageTag: `${CONTAINER_NAME}:${tag}`,
|
|
271
|
+
});
|
|
272
|
+
// 8) Boot persistence (opt-in, spec §5.8). With `--enable-boot`, install +
|
|
273
|
+
// enable the systemd unit AFTER a healthy up (so the named container the
|
|
274
|
+
// unit references actually exists). On macOS this prints the deferred
|
|
275
|
+
// notice and continues — the `up` still succeeds. The unit references the
|
|
276
|
+
// EXISTING container by name and carries NO secret (boot.ts).
|
|
277
|
+
const lines = [];
|
|
278
|
+
if (options.enableBoot) {
|
|
279
|
+
const bootResult = await enableBoot(deps.platform ? { platform: deps.platform } : {});
|
|
280
|
+
lines.push(bootResult.output, "");
|
|
281
|
+
}
|
|
282
|
+
// 9) Close the loop: surface secrets/URLs + offer the local env write.
|
|
283
|
+
await closeTheLoop(lines, { host, agentToken, masterKey, options, deps });
|
|
284
|
+
return { output: lines.join("\n") };
|
|
285
|
+
}
|
|
286
|
+
// --- bind-host resolution (spec §5.3, §6) -------------------------------
|
|
287
|
+
/**
|
|
288
|
+
* Resolve the host the container publishes on:
|
|
289
|
+
* - `--host <addr>` wins (explicit). `0.0.0.0` is still ask-first.
|
|
290
|
+
* - no `--host`, interactive, not `--yes`, and `tailscale ip -4` yields a
|
|
291
|
+
* tailnet IP → OFFER it (default: keep loopback).
|
|
292
|
+
* - otherwise → `127.0.0.1` (we never silently expose beyond localhost).
|
|
293
|
+
*
|
|
294
|
+
* Binding to `0.0.0.0` requires explicit confirmation (`--yes` auto-accepts);
|
|
295
|
+
* declining aborts with a teaching error BEFORE any clone/build/run.
|
|
296
|
+
*/
|
|
297
|
+
async function resolveBindHost(options, deps) {
|
|
298
|
+
// An empty/whitespace `--host` (e.g. `--host ""`) is treated as "not provided"
|
|
299
|
+
// rather than slipping through as `""` — which would publish `-p :3000:3000`
|
|
300
|
+
// (ALL interfaces) with no ask-first (I1). Fall through to the default path.
|
|
301
|
+
if (options.host !== undefined && options.host.trim().length > 0) {
|
|
302
|
+
const host = normalizeHost(options.host.trim());
|
|
303
|
+
if (host === ALL_INTERFACES) {
|
|
304
|
+
await confirmAllInterfaces(options, deps);
|
|
305
|
+
}
|
|
306
|
+
else if (isIpv6Literal(host)) {
|
|
307
|
+
// `::1` already normalized to loopback above; any OTHER IPv6 literal is
|
|
308
|
+
// beyond this slice's scope (the `-p` arg would need bracketing and the
|
|
309
|
+
// exposure path would need IPv6 reasoning). Teach rather than emit a
|
|
310
|
+
// malformed `-p ::ffff:…:3000:3000`.
|
|
311
|
+
throw new UpError(`IPv6 bind addresses other than loopback (::1) are not supported yet (got '${host}'). ` +
|
|
312
|
+
"Use an IPv4 address (e.g. a tailnet IP) or '0.0.0.0' to bind all interfaces.");
|
|
313
|
+
}
|
|
314
|
+
return host;
|
|
315
|
+
}
|
|
316
|
+
// No explicit host: best-effort offer the Tailscale IP (interactive only).
|
|
317
|
+
const interactive = deps.interactive ?? true;
|
|
318
|
+
if (interactive && options.yes !== true) {
|
|
319
|
+
const tailnetIp = await detectTailscaleIp();
|
|
320
|
+
if (tailnetIp) {
|
|
321
|
+
const answer = await deps.prompter.promptText(`Detected a Tailscale address (${tailnetIp}). Bind the server to it so your ` +
|
|
322
|
+
`tailnet can reach it (instead of localhost only)? [y/N]`, { default: "n" });
|
|
323
|
+
if (isYes(answer))
|
|
324
|
+
return tailnetIp;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return LOCALHOST;
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Normalize loopback spellings to the canonical `127.0.0.1` (I3). The server
|
|
331
|
+
* treats `localhost` / `::1` / `127.0.0.1` identically (loopback no-auth bypass),
|
|
332
|
+
* so the CLI must too — otherwise `--host localhost` would omit `ALLOW_NO_AUTH`
|
|
333
|
+
* and needlessly require an agent token for a loopback-only server. Any other
|
|
334
|
+
* value is returned unchanged (the caller decides whether it's allowed).
|
|
335
|
+
*/
|
|
336
|
+
function normalizeHost(host) {
|
|
337
|
+
const lower = host.toLowerCase();
|
|
338
|
+
if (lower === "localhost" || lower === "::1" || lower === LOCALHOST)
|
|
339
|
+
return LOCALHOST;
|
|
340
|
+
return host;
|
|
341
|
+
}
|
|
342
|
+
/** True for a genuine IPv6 literal (after loopback normalization). */
|
|
343
|
+
function isIpv6Literal(host) {
|
|
344
|
+
return isIP(host) === 6;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Confirm an all-interfaces (`0.0.0.0`) bind. `--yes` auto-accepts; otherwise
|
|
348
|
+
* prompt (default no). Declining throws `UpError` — exposing every interface is
|
|
349
|
+
* never something we do without an explicit yes.
|
|
350
|
+
*/
|
|
351
|
+
async function confirmAllInterfaces(options, deps) {
|
|
352
|
+
if (options.yes === true)
|
|
353
|
+
return;
|
|
354
|
+
const answer = await deps.prompter.promptText(`Binding to 0.0.0.0 exposes the server on ALL network interfaces — anyone who ` +
|
|
355
|
+
`can reach this machine can reach it. Continue? [y/N]`, { default: "n" });
|
|
356
|
+
if (!isYes(answer)) {
|
|
357
|
+
throw new UpError("Aborted: binding to 0.0.0.0 (all interfaces) was declined. " +
|
|
358
|
+
"Re-run without --host for a localhost-only server, or with --host <tailnet-ip> " +
|
|
359
|
+
"for a specific reachable address.");
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Best-effort probe for this machine's Tailscale IPv4 address, routed through
|
|
364
|
+
* the injectable `docker.ts` runner (so tests stub it; no real tailscale).
|
|
365
|
+
* Returns `null` when `tailscale` is absent or yields no usable IPv4 — the
|
|
366
|
+
* caller then stays on loopback. Never throws: a probe failure is silent.
|
|
367
|
+
*/
|
|
368
|
+
async function detectTailscaleIp() {
|
|
369
|
+
if ((await which("tailscale")) === null)
|
|
370
|
+
return null;
|
|
371
|
+
try {
|
|
372
|
+
const result = await run("tailscale", ["ip", "-4"]);
|
|
373
|
+
if (result.code !== 0)
|
|
374
|
+
return null;
|
|
375
|
+
// Use `node:net` `isIP` so invalid octets (e.g. `999.1.2.3`) are rejected —
|
|
376
|
+
// a loose `\d{1,3}` regex would accept them (S1).
|
|
377
|
+
const ip = result.stdout
|
|
378
|
+
.split("\n")
|
|
379
|
+
.map((l) => l.trim())
|
|
380
|
+
.find((l) => isIP(l) === 4);
|
|
381
|
+
return ip ?? null;
|
|
382
|
+
}
|
|
383
|
+
catch {
|
|
384
|
+
return null;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
// --- step helpers --------------------------------------------------------
|
|
388
|
+
/** Resolve the ref to deploy: an explicit `--ref` wins; else the latest tag. */
|
|
389
|
+
async function resolveRef(ref) {
|
|
390
|
+
if (ref && ref.trim().length > 0)
|
|
391
|
+
return ref.trim();
|
|
392
|
+
const latest = await fetchLatestVersion();
|
|
393
|
+
if (!latest) {
|
|
394
|
+
throw new UpError("Could not resolve the latest release tag from GitHub. " +
|
|
395
|
+
"Check your network, or pin a ref with `--ref <tag|main>`.");
|
|
396
|
+
}
|
|
397
|
+
// `fetchLatestVersion` strips the leading `v`; the tag we check out keeps it.
|
|
398
|
+
return `v${latest}`;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Ready the deploy dir at `tag`:
|
|
402
|
+
* - absent → `git clone <repo> <dir>` then checkout the ref;
|
|
403
|
+
* - already OUR managed clone → `git fetch` + checkout the ref;
|
|
404
|
+
* - exists but isn't our clone (different remote / dirty) → STOP and ask.
|
|
405
|
+
* Never clobbers a dir we didn't create.
|
|
406
|
+
*/
|
|
407
|
+
async function prepareDeployDir(dir, tag) {
|
|
408
|
+
const gitDir = path.join(dir, ".git");
|
|
409
|
+
if (!(await pathExists(gitDir))) {
|
|
410
|
+
if (await pathExists(dir)) {
|
|
411
|
+
// A non-empty dir that isn't a git repo → not ours; don't clobber.
|
|
412
|
+
if (!(await isEmptyDir(dir))) {
|
|
413
|
+
throw new UpError(`Deploy dir ${dir} exists but is not a Librarian clone (no .git). ` +
|
|
414
|
+
"Refusing to overwrite a directory I didn't create — " +
|
|
415
|
+
"remove it or choose another path with `--dir <path>`.");
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
await git(["clone", REPO_URL, dir]);
|
|
419
|
+
await checkoutRef(dir, tag);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
// It's a git repo — confirm it's OUR clone before touching it.
|
|
423
|
+
const originResult = await run("git", ["-C", dir, "remote", "get-url", "origin"]);
|
|
424
|
+
const origin = originResult.stdout.trim();
|
|
425
|
+
if (!sameRepo(origin, REPO_URL)) {
|
|
426
|
+
throw new UpError(`Deploy dir ${dir} is a git repo with a different remote (${origin || "none"}). ` +
|
|
427
|
+
"Refusing to touch a clone I didn't create — choose another path with `--dir <path>`.");
|
|
428
|
+
}
|
|
429
|
+
await git(["-C", dir, "fetch", "--tags", "origin"]);
|
|
430
|
+
await checkoutRef(dir, tag);
|
|
431
|
+
}
|
|
432
|
+
/** True iff `origin` points at the same repo as `REPO_URL` (scheme/.git tolerant). */
|
|
433
|
+
function sameRepo(origin, repo) {
|
|
434
|
+
const norm = (u) => u
|
|
435
|
+
.trim()
|
|
436
|
+
.replace(/\.git$/, "")
|
|
437
|
+
.replace(/\/$/, "")
|
|
438
|
+
.replace(/^git@github\.com:/, "https://github.com/")
|
|
439
|
+
.toLowerCase();
|
|
440
|
+
return norm(origin) === norm(repo);
|
|
441
|
+
}
|
|
442
|
+
/** Build the all-in-one image from the deploy dir (the VERIFIED build command). */
|
|
443
|
+
async function build(deployDir, tag) {
|
|
444
|
+
await dockerInDir(["build", "-f", "docker/all-in-one.Dockerfile", "-t", `${CONTAINER_NAME}:${tag}`, "."], deployDir);
|
|
445
|
+
}
|
|
446
|
+
/** Run the container (the assembled run argv) from the deploy dir. */
|
|
447
|
+
async function dockerRun(args, deployDir) {
|
|
448
|
+
await dockerInDir(args, deployDir);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Poll `docker inspect … Health.Status` until `healthy`, bounded. On timeout or
|
|
452
|
+
* an unhealthy report: surface `docker logs --tail` (REDACTED), roll the
|
|
453
|
+
* container back (`docker rm -f`), and throw — leaving NO half-up container.
|
|
454
|
+
*
|
|
455
|
+
* Exported so `update` recreates with the IDENTICAL health-wait + rollback
|
|
456
|
+
* pattern (a failed recreate force-removes the new container and never advances
|
|
457
|
+
* deploy-state). The thrown `UpError`'s message is already secret-redacted.
|
|
458
|
+
*/
|
|
459
|
+
export async function waitForHealthy(options) {
|
|
460
|
+
const attempts = options.healthAttempts ?? 60;
|
|
461
|
+
const intervalMs = options.healthIntervalMs ?? 2000;
|
|
462
|
+
const tail = options.logTailLines ?? 50;
|
|
463
|
+
for (let i = 0; i < attempts; i += 1) {
|
|
464
|
+
const result = await run("docker", [
|
|
465
|
+
"inspect",
|
|
466
|
+
"--format",
|
|
467
|
+
"{{.State.Health.Status}}",
|
|
468
|
+
CONTAINER_NAME,
|
|
469
|
+
]);
|
|
470
|
+
const state = result.stdout.trim();
|
|
471
|
+
if (state === "healthy")
|
|
472
|
+
return;
|
|
473
|
+
if (state === "unhealthy")
|
|
474
|
+
break; // no point waiting out the bound
|
|
475
|
+
if (i < attempts - 1)
|
|
476
|
+
await sleepImpl(intervalMs);
|
|
477
|
+
}
|
|
478
|
+
// Failed: surface the recent logs for triage, but REDACT first. Post-ADR-0008-P3
|
|
479
|
+
// the server no longer logs an admin token, but the redactor still scrubs the
|
|
480
|
+
// legacy generation line and any `libadmin_`/bearer token in the captured output
|
|
481
|
+
// (defense-in-depth, e.g. an older image) — none of that may reach an error
|
|
482
|
+
// message (spec §5.6 wants logs surfaced, just not secrets). Then roll back so
|
|
483
|
+
// no half-up container survives.
|
|
484
|
+
const logs = await run("docker", ["logs", "--tail", String(tail), CONTAINER_NAME]);
|
|
485
|
+
await run("docker", ["rm", "-f", CONTAINER_NAME]);
|
|
486
|
+
const detail = redactSecrets(logs.stdout.trim() || logs.stderr.trim());
|
|
487
|
+
throw new UpError(`The server did not become healthy in time and was rolled back ` +
|
|
488
|
+
`(container removed; the data volume is untouched). Recent logs:\n` +
|
|
489
|
+
(detail ? detail : "(no log output captured)") +
|
|
490
|
+
`\n\nFix the cause above, then re-run \`librarian server up\`.`);
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Close the loop: surface the master key ONCE (with the SAVE warning), print the
|
|
494
|
+
* MCP + dashboard URLs and the minted agent token, and OFFER to write this
|
|
495
|
+
* machine's `~/.librarian/env` when it's absent/incomplete (`--yes` auto-accepts).
|
|
496
|
+
*
|
|
497
|
+
* ADR 0008 P4: the master key surfaced here is the one the CLI MINTED (and
|
|
498
|
+
* delivered via the deploy env-file) — it is no longer read back from
|
|
499
|
+
* `/data/secret.key` (the server never writes that file when the key is env-
|
|
500
|
+
* supplied). It is never written to any host file (only the 0600 deploy env-file).
|
|
501
|
+
*
|
|
502
|
+
* ADR 0008 P3: no admin token is surfaced — the admin tRPC API is off the network
|
|
503
|
+
* (internal listener only), so there is no admin token to mint or paste anywhere.
|
|
504
|
+
*/
|
|
505
|
+
async function closeTheLoop(lines, ctx) {
|
|
506
|
+
const { host, agentToken, masterKey, options, deps } = ctx;
|
|
507
|
+
const mcpUrl = `http://${host}:3838/mcp`;
|
|
508
|
+
const dashboardUrl = `http://${host}:3000`;
|
|
509
|
+
lines.push("The Librarian server is up and healthy.", "", ` MCP URL: ${mcpUrl}`, ` Dashboard: ${dashboardUrl}`, ` Agent token: ${agentToken}`, "");
|
|
510
|
+
// `0.0.0.0` is a bind directive, not a connectable address — point clients at
|
|
511
|
+
// the machine's real reachable IP rather than over-engineering auto-detection.
|
|
512
|
+
if (host === ALL_INTERFACES) {
|
|
513
|
+
// S2: a `--yes` run auto-accepts the all-interfaces bind with no prompt, so
|
|
514
|
+
// print a one-line trace of that exposure — otherwise it's invisible in CI
|
|
515
|
+
// logs (the only record of "we bound every interface, unattended").
|
|
516
|
+
if (options.yes === true) {
|
|
517
|
+
lines.push("Note: binding 0.0.0.0 (all interfaces) — auto-accepted via --yes.", "");
|
|
518
|
+
}
|
|
519
|
+
lines.push("Note: 0.0.0.0 binds every interface but is NOT a connectable address — " +
|
|
520
|
+
"clients should use this machine's reachable LAN/tailnet IP in the URLs above.", "");
|
|
521
|
+
}
|
|
522
|
+
lines.push("Paste the MCP URL + agent token into `librarian install` on your clients.", "",
|
|
523
|
+
// The ONE-TIME master-key surfacing (the CLI-minted key — ADR 0008 P4).
|
|
524
|
+
// Never written to any host file other than the 0600 deploy env-file.
|
|
525
|
+
`Master key (${SAVE_KEY_WARNING}):`, ` ${masterKey}`, "");
|
|
526
|
+
await offerLocalEnv(lines, { mcpUrl, agentToken, options, deps });
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Offer to write this machine's own `~/.librarian/env` (so single-box dev gets
|
|
530
|
+
* server + client in one shot). OFFER, never force: prompt (default no), or
|
|
531
|
+
* auto-accept with `--yes`. Reuses env.ts so the token lands chmod-600 and is
|
|
532
|
+
* never logged. Only offers when the env is absent/incomplete.
|
|
533
|
+
*/
|
|
534
|
+
async function offerLocalEnv(lines, ctx) {
|
|
535
|
+
const { mcpUrl, agentToken, options, deps } = ctx;
|
|
536
|
+
const existing = readEnvFile(deps.home);
|
|
537
|
+
const complete = Boolean(existing?.mcpUrl && existing?.token);
|
|
538
|
+
if (complete) {
|
|
539
|
+
lines.push("This machine's `~/.librarian/env` is already configured — left as is.");
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
let accepted = options.yes === true;
|
|
543
|
+
if (!accepted) {
|
|
544
|
+
const answer = await deps.prompter.promptText("Write this machine's own ~/.librarian/env so local agents use this server? [y/N]", { default: "n" });
|
|
545
|
+
accepted = isYes(answer);
|
|
546
|
+
}
|
|
547
|
+
if (accepted) {
|
|
548
|
+
writeEnvFile({ mcpUrl, token: agentToken }, deps.home);
|
|
549
|
+
lines.push("Wrote ~/.librarian/env (chmod 600) — local agents now point at this server.");
|
|
550
|
+
}
|
|
551
|
+
else {
|
|
552
|
+
lines.push("Left ~/.librarian/env untouched. Configure a client later with:", ` librarian config --mcp-url ${mcpUrl} --token <the agent token above>`);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
function isYes(answer) {
|
|
556
|
+
const a = answer.trim().toLowerCase();
|
|
557
|
+
return a === "y" || a === "yes";
|
|
558
|
+
}
|
|
559
|
+
// --- thin runner wrappers (teaching errors on a non-zero exit) ----------
|
|
560
|
+
/** Run a `git …` command from anywhere; a non-zero exit is a teaching error. */
|
|
561
|
+
async function git(args) {
|
|
562
|
+
const result = await run("git", args);
|
|
563
|
+
failIfNonZero("git", args, result);
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Check out `ref` in `dir` without letting a `--…`-shaped ref inject a git
|
|
567
|
+
* option (S-1). `git checkout` does NOT honor `--end-of-options` — it reads the
|
|
568
|
+
* marker itself as a pathspec (`pathspec '--end-of-options' did not match`,
|
|
569
|
+
* verified on git 2.43), so guarding the ref on the checkout fails outright.
|
|
570
|
+
* `git rev-parse` DOES honor `--end-of-options`, so we resolve the ref to a
|
|
571
|
+
* commit SHA there (the injection guard that actually works), then check out
|
|
572
|
+
* that SHA — a hex object id can never be parsed as an option.
|
|
573
|
+
*/
|
|
574
|
+
export async function checkoutRef(dir, ref) {
|
|
575
|
+
const resolved = await run("git", [
|
|
576
|
+
"-C",
|
|
577
|
+
dir,
|
|
578
|
+
"rev-parse",
|
|
579
|
+
"--verify",
|
|
580
|
+
"--end-of-options",
|
|
581
|
+
`${ref}^{commit}`,
|
|
582
|
+
]);
|
|
583
|
+
failIfNonZero("git", ["-C", dir, "rev-parse", ref], resolved);
|
|
584
|
+
await git(["-C", dir, "checkout", resolved.stdout.trim()]);
|
|
585
|
+
}
|
|
586
|
+
/** Run a `docker …` command from the deploy dir; non-zero exit → teaching error. */
|
|
587
|
+
async function dockerInDir(args, cwd) {
|
|
588
|
+
const result = await run("docker", args, { cwd });
|
|
589
|
+
failIfNonZero("docker", args, result);
|
|
590
|
+
}
|
|
591
|
+
function failIfNonZero(cmd, args, result) {
|
|
592
|
+
if (result.code === 0)
|
|
593
|
+
return;
|
|
594
|
+
// Redact in case a failed docker/git step echoed a secret-shaped value. Post
|
|
595
|
+
// ADR 0008 P4 the secrets ride in the 0600 deploy env-file (via `--env-file`),
|
|
596
|
+
// NOT inline on argv — so an argv-echoing `build`/`run` failure no longer
|
|
597
|
+
// carries them. We still redact defensively (e.g. a daemon that prints the
|
|
598
|
+
// expanded env, or an older code path) so no 64-hex secret reaches the message.
|
|
599
|
+
const detail = redactSecrets(result.stderr.trim() || result.stdout.trim());
|
|
600
|
+
throw new UpError(`\`${cmd} ${args[0]}\` failed (exit ${result.code ?? "signal"})` +
|
|
601
|
+
(detail ? `:\n${detail}` : ".") +
|
|
602
|
+
"\n\nResolve the error above, then re-run `librarian server up`.");
|
|
603
|
+
}
|
|
604
|
+
// --- tiny fs probes (kept here so the flow stays self-contained) ---------
|
|
605
|
+
async function pathExists(p) {
|
|
606
|
+
const fs = await import("node:fs/promises");
|
|
607
|
+
try {
|
|
608
|
+
await fs.access(p);
|
|
609
|
+
return true;
|
|
610
|
+
}
|
|
611
|
+
catch {
|
|
612
|
+
return false;
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
async function isEmptyDir(p) {
|
|
616
|
+
const fs = await import("node:fs/promises");
|
|
617
|
+
try {
|
|
618
|
+
const entries = await fs.readdir(p);
|
|
619
|
+
return entries.length === 0;
|
|
620
|
+
}
|
|
621
|
+
catch {
|
|
622
|
+
return false;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
//# sourceMappingURL=up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"up.js","sourceRoot":"","sources":["../../src/server/up.ts"],"names":[],"mappings":"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"}
|