@cotal-ai/cli 0.2.0 → 0.3.0

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 (93) hide show
  1. package/dist/commands/channels.d.ts.map +1 -1
  2. package/dist/commands/channels.js +4 -2
  3. package/dist/commands/channels.js.map +1 -1
  4. package/dist/commands/console.d.ts.map +1 -1
  5. package/dist/commands/console.js +11 -8
  6. package/dist/commands/console.js.map +1 -1
  7. package/dist/commands/demo.js +3 -2
  8. package/dist/commands/demo.js.map +1 -1
  9. package/dist/commands/down.d.ts +4 -0
  10. package/dist/commands/down.d.ts.map +1 -0
  11. package/dist/commands/down.js +36 -0
  12. package/dist/commands/down.js.map +1 -0
  13. package/dist/commands/history.d.ts.map +1 -1
  14. package/dist/commands/history.js +5 -3
  15. package/dist/commands/history.js.map +1 -1
  16. package/dist/commands/join.js +3 -2
  17. package/dist/commands/join.js.map +1 -1
  18. package/dist/commands/mint.d.ts.map +1 -1
  19. package/dist/commands/mint.js +3 -2
  20. package/dist/commands/mint.js.map +1 -1
  21. package/dist/commands/setup.d.ts +13 -6
  22. package/dist/commands/setup.d.ts.map +1 -1
  23. package/dist/commands/setup.js +542 -61
  24. package/dist/commands/setup.js.map +1 -1
  25. package/dist/commands/signer.d.ts +6 -0
  26. package/dist/commands/signer.d.ts.map +1 -0
  27. package/dist/commands/signer.js +30 -0
  28. package/dist/commands/signer.js.map +1 -0
  29. package/dist/commands/spawn.d.ts.map +1 -1
  30. package/dist/commands/spawn.js +9 -5
  31. package/dist/commands/spawn.js.map +1 -1
  32. package/dist/commands/up.d.ts +21 -0
  33. package/dist/commands/up.d.ts.map +1 -1
  34. package/dist/commands/up.js +108 -38
  35. package/dist/commands/up.js.map +1 -1
  36. package/dist/commands/web.d.ts +27 -0
  37. package/dist/commands/web.d.ts.map +1 -1
  38. package/dist/commands/web.js +101 -14
  39. package/dist/commands/web.js.map +1 -1
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +31 -8
  42. package/dist/index.js.map +1 -1
  43. package/dist/lib/assist.d.ts +16 -0
  44. package/dist/lib/assist.d.ts.map +1 -0
  45. package/dist/lib/assist.js +52 -0
  46. package/dist/lib/assist.js.map +1 -0
  47. package/dist/lib/cancel.d.ts +5 -0
  48. package/dist/lib/cancel.d.ts.map +1 -0
  49. package/dist/lib/cancel.js +12 -0
  50. package/dist/lib/cancel.js.map +1 -0
  51. package/dist/lib/live-window.d.ts +22 -0
  52. package/dist/lib/live-window.d.ts.map +1 -0
  53. package/dist/lib/live-window.js +71 -0
  54. package/dist/lib/live-window.js.map +1 -0
  55. package/dist/lib/manager-proc.d.ts +32 -0
  56. package/dist/lib/manager-proc.d.ts.map +1 -0
  57. package/dist/lib/manager-proc.js +84 -0
  58. package/dist/lib/manager-proc.js.map +1 -0
  59. package/dist/lib/nats-bin.d.ts +7 -0
  60. package/dist/lib/nats-bin.d.ts.map +1 -0
  61. package/dist/lib/nats-bin.js +21 -0
  62. package/dist/lib/nats-bin.js.map +1 -0
  63. package/dist/lib/onboard.d.ts +3 -0
  64. package/dist/lib/onboard.d.ts.map +1 -0
  65. package/dist/lib/onboard.js +15 -0
  66. package/dist/lib/onboard.js.map +1 -0
  67. package/dist/lib/paths.d.ts +7 -0
  68. package/dist/lib/paths.d.ts.map +1 -0
  69. package/dist/lib/paths.js +13 -0
  70. package/dist/lib/paths.js.map +1 -0
  71. package/dist/lib/self-exec.d.ts +18 -0
  72. package/dist/lib/self-exec.d.ts.map +1 -0
  73. package/dist/lib/self-exec.js +50 -0
  74. package/dist/lib/self-exec.js.map +1 -0
  75. package/dist/lib/setup-log.d.ts +8 -0
  76. package/dist/lib/setup-log.d.ts.map +1 -0
  77. package/dist/lib/setup-log.js +17 -0
  78. package/dist/lib/setup-log.js.map +1 -0
  79. package/dist/lib/status.d.ts +27 -0
  80. package/dist/lib/status.d.ts.map +1 -0
  81. package/dist/lib/status.js +57 -0
  82. package/dist/lib/status.js.map +1 -0
  83. package/dist/lib/steps.d.ts +31 -0
  84. package/dist/lib/steps.d.ts.map +1 -0
  85. package/dist/lib/steps.js +91 -0
  86. package/dist/lib/steps.js.map +1 -0
  87. package/dist/lib/theme.d.ts +18 -0
  88. package/dist/lib/theme.d.ts.map +1 -0
  89. package/dist/lib/theme.js +61 -0
  90. package/dist/lib/theme.js.map +1 -0
  91. package/dist/web/app.js +28 -0
  92. package/dist/web/index.html +2 -0
  93. package/package.json +11 -2
@@ -0,0 +1,84 @@
1
+ import { spawn, spawnSync } from "node:child_process";
2
+ import { existsSync, openSync, closeSync, writeFileSync, readFileSync, rmSync } from "node:fs";
3
+ import { DEFAULT_SERVER } from "@cotal-ai/core";
4
+ import { selfArgv } from "./self-exec.js";
5
+ import { resolveSpace } from "./status.js";
6
+ import { cotalPath } from "./paths.js";
7
+ const PID_PATH = () => cotalPath("manager.pid");
8
+ function alive(pid) {
9
+ try {
10
+ process.kill(pid, 0); // signal 0: liveness probe, doesn't actually signal
11
+ return true;
12
+ }
13
+ catch {
14
+ return false;
15
+ }
16
+ }
17
+ /** True if the manager we started for this folder is still running (pid file + liveness). */
18
+ export function managerUp() {
19
+ const p = PID_PATH();
20
+ if (!existsSync(p))
21
+ return false;
22
+ const pid = Number(readFileSync(p, "utf8").trim());
23
+ return Number.isFinite(pid) && alive(pid);
24
+ }
25
+ /** True if any process's full command line matches `pattern` (`pgrep -f`). Detects processes that
26
+ * have no pid file — the cmux-tab manager and the driving session — which live in cmux tabs. */
27
+ export function pgrepMatches(pattern) {
28
+ return spawnSync("pgrep", ["-f", pattern], { stdio: "ignore" }).status === 0;
29
+ }
30
+ /** True if a cmux-runtime manager is live for this space. Its cmux tab persists after the process
31
+ * exits, so a workspace listing isn't proof — the process is. Matches prod `cotal.js` and dev
32
+ * `cotal.ts` (both carry `cmux --space <space>`). */
33
+ export function cmuxManagerRunning(space) {
34
+ return pgrepMatches(`cmux --space ${space}`);
35
+ }
36
+ /** Start the control-plane manager detached (pid in `.cotal/manager.pid`, output to
37
+ * `.cotal/manager.log`), stopped by `cotal down`. Re-execs this same CLI's `supervise` — the
38
+ * composed `cotal` binary registers it; `process.execArgv` carries the tsx loader in dev and is
39
+ * empty in prod. `supervise`'s auto runtime resolves to pty when detached, which answers the
40
+ * control plane (`cotal_spawn`/`despawn`/`purge`/`persona`) with no tmux/cmux needed. */
41
+ export function startManagerDetached(o = {}) {
42
+ const fd = openSync(cotalPath("manager.log"), "a");
43
+ const [node, ...self] = selfArgv();
44
+ const args = [
45
+ ...self,
46
+ "supervise",
47
+ "--space",
48
+ o.space ?? resolveSpace(process.cwd()),
49
+ "--server",
50
+ o.server ?? DEFAULT_SERVER,
51
+ ...(o.spawn?.length ? ["--spawn", o.spawn.join(",")] : []),
52
+ ];
53
+ const child = spawn(node, args, { detached: true, stdio: ["ignore", fd, fd] });
54
+ closeSync(fd);
55
+ child.unref();
56
+ writeFileSync(PID_PATH(), String(child.pid));
57
+ return child.pid ?? 0;
58
+ }
59
+ /** Make the control plane available: reuse a manager already running for this folder, else start
60
+ * one detached. Best-effort — callers treat it as non-fatal. */
61
+ export function ensureManager(o = {}) {
62
+ if (managerUp())
63
+ return { running: true };
64
+ startManagerDetached(o);
65
+ return { running: true };
66
+ }
67
+ /** Stop the detached (pty) manager if we started one. Used when switching to the cmux-tab manager
68
+ * so the two don't both answer the control plane (queue-grouped requests would split between them). */
69
+ export function stopManager() {
70
+ const p = PID_PATH();
71
+ if (!existsSync(p))
72
+ return;
73
+ const pid = Number(readFileSync(p, "utf8").trim());
74
+ if (Number.isFinite(pid)) {
75
+ try {
76
+ process.kill(pid, "SIGTERM");
77
+ }
78
+ catch {
79
+ /* already gone */
80
+ }
81
+ }
82
+ rmSync(p);
83
+ }
84
+ //# sourceMappingURL=manager-proc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager-proc.js","sourceRoot":"","sources":["../../src/lib/manager-proc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /** Resolve the nats-server binary: PATH first (an operator-installed server always
2
+ * wins), then the bundled platform package. Throws when neither is available. */
3
+ export declare function resolveNatsServer(): Promise<{
4
+ bin: string;
5
+ source: "path" | "bundled";
6
+ }>;
7
+ //# sourceMappingURL=nats-bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nats-bin.d.ts","sourceRoot":"","sources":["../../src/lib/nats-bin.ts"],"names":[],"mappings":"AAMA;kFACkF;AAClF,wBAAsB,iBAAiB,IAAI,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC,CAc9F"}
@@ -0,0 +1,21 @@
1
+ import { spawnSync } from "node:child_process";
2
+ /** Platform-package prefix the bundled binary ships under. Swapping providers
3
+ * (e.g. to our own @cotal-ai/nats-server-*) is a one-line change here. */
4
+ const BUNDLED_PKG_PREFIX = "@eplightning/nats-server";
5
+ /** Resolve the nats-server binary: PATH first (an operator-installed server always
6
+ * wins), then the bundled platform package. Throws when neither is available. */
7
+ export async function resolveNatsServer() {
8
+ const onPath = spawnSync("nats-server", ["--version"], { stdio: "ignore" });
9
+ if (!onPath.error && onPath.status === 0)
10
+ return { bin: "nats-server", source: "path" };
11
+ const pkg = `${BUNDLED_PKG_PREFIX}-${process.platform}-${process.arch}`;
12
+ try {
13
+ const mod = (await import(pkg));
14
+ return { bin: mod.getBinaryPath(), source: "bundled" };
15
+ }
16
+ catch {
17
+ throw new Error(`nats-server not found on PATH and no bundled binary for ${process.platform}/${process.arch} (${pkg}). ` +
18
+ "Install nats-server (https://github.com/nats-io/nats-server/releases) and put it on PATH.");
19
+ }
20
+ }
21
+ //# sourceMappingURL=nats-bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nats-bin.js","sourceRoot":"","sources":["../../src/lib/nats-bin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C;2EAC2E;AAC3E,MAAM,kBAAkB,GAAG,0BAA0B,CAAC;AAEtD;kFACkF;AAClF,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,MAAM,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5E,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAExF,MAAM,GAAG,GAAG,GAAG,kBAAkB,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;IACxE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,CAAgC,CAAC;QAC/D,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACzD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,2DAA2D,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,KAAK,GAAG,KAAK;YACtG,2FAA2F,CAC9F,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function isOnboarded(): boolean;
2
+ export declare function markOnboarded(version: string): void;
3
+ //# sourceMappingURL=onboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboard.d.ts","sourceRoot":"","sources":["../../src/lib/onboard.ts"],"names":[],"mappings":"AASA,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAGnD"}
@@ -0,0 +1,15 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ /** Machine-level "I've onboarded before" marker. Its presence flips `cotal` from the
5
+ * full first-run flow to the compact ensure+status run. Lives next to the materialized
6
+ * plugin marketplace under ~/.cotal. */
7
+ const MARKER = join(homedir(), ".cotal", "onboarded.json");
8
+ export function isOnboarded() {
9
+ return existsSync(MARKER);
10
+ }
11
+ export function markOnboarded(version) {
12
+ mkdirSync(join(homedir(), ".cotal"), { recursive: true });
13
+ writeFileSync(MARKER, JSON.stringify({ version, ts: new Date().toISOString() }, null, 2));
14
+ }
15
+ //# sourceMappingURL=onboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"onboard.js","sourceRoot":"","sources":["../../src/lib/onboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;yCAEyC;AACzC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AAE3D,MAAM,UAAU,WAAW;IACzB,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,SAAS,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,aAAa,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC5F,CAAC"}
@@ -0,0 +1,7 @@
1
+ /** The project's `.cotal/` root, found by walking up from cwd (like git finds `.git`), so every
2
+ * command resolves the same `.cotal/` whether you're at the project root or a subdirectory. */
3
+ export declare function cotalRoot(): string;
4
+ /** A path inside the project's `.cotal/` directory. Use instead of `resolve(".cotal/…")` so paths
5
+ * don't break when `cotal` runs from a subdirectory. */
6
+ export declare function cotalPath(...segments: string[]): string;
7
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/lib/paths.ts"],"names":[],"mappings":"AAGA;gGACgG;AAChG,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED;yDACyD;AACzD,wBAAgB,SAAS,CAAC,GAAG,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAEvD"}
@@ -0,0 +1,13 @@
1
+ import { join } from "node:path";
2
+ import { findCotalRoot } from "@cotal-ai/core";
3
+ /** The project's `.cotal/` root, found by walking up from cwd (like git finds `.git`), so every
4
+ * command resolves the same `.cotal/` whether you're at the project root or a subdirectory. */
5
+ export function cotalRoot() {
6
+ return findCotalRoot();
7
+ }
8
+ /** A path inside the project's `.cotal/` directory. Use instead of `resolve(".cotal/…")` so paths
9
+ * don't break when `cotal` runs from a subdirectory. */
10
+ export function cotalPath(...segments) {
11
+ return join(cotalRoot(), ".cotal", ...segments);
12
+ }
13
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/lib/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C;gGACgG;AAChG,MAAM,UAAU,SAAS;IACvB,OAAO,aAAa,EAAE,CAAC;AACzB,CAAC;AAED;yDACyD;AACzD,MAAM,UAAU,SAAS,CAAC,GAAG,QAAkB;IAC7C,OAAO,IAAI,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,18 @@
1
+ /** This CLI's own invocation as argv: `[node, ...loaderFlags, entryScript]`. The loader flags carry
2
+ * tsx in dev (so a re-exec can run the `.ts` entry) and are empty in prod (entry = compiled JS).
3
+ * Re-execed children (web, manager) and cmux pane commands use this so they never depend on
4
+ * `cotal` being on PATH — works the same via `npx`, `npm i -g`, and a dev clone. */
5
+ export declare function selfArgv(): string[];
6
+ /** True when launched via `npx` — the package is unpacked under `~/.npm/_npx/<hash>/…`. */
7
+ export declare function isNpx(): boolean;
8
+ /** Is a `cotal` executable resolvable on PATH? A pure PATH scan (no exec): `cotal --version`
9
+ * isn't a real command, so probing it via `onPath` would always report cotal as missing. */
10
+ export declare function cotalOnPath(): boolean;
11
+ /** The copy-paste command prefix for user-facing hints: `cotal` when it's on PATH, `npx cotal-ai`
12
+ * for an npx run, `pnpm cotal` in a dev clone. (Display only — re-execs use {@link selfArgv}.) */
13
+ export declare function displayCmd(): string;
14
+ /** The self-invocation as a shell-ready, double-quoted command prefix (for cmux pane commands).
15
+ * Tokens are absolute paths with no single quotes, so the surrounding `bash -lc '…'` single-quote
16
+ * wrapping stays intact through a login shell (e.g. nushell) before bash. */
17
+ export declare function selfCotal(): string;
18
+ //# sourceMappingURL=self-exec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-exec.d.ts","sourceRoot":"","sources":["../../src/lib/self-exec.ts"],"names":[],"mappings":"AAGA;;;qFAGqF;AACrF,wBAAgB,QAAQ,IAAI,MAAM,EAAE,CAEnC;AAED,2FAA2F;AAC3F,wBAAgB,KAAK,IAAI,OAAO,CAE/B;AAED;6FAC6F;AAC7F,wBAAgB,WAAW,IAAI,OAAO,CAcrC;AAED;mGACmG;AACnG,wBAAgB,UAAU,IAAI,MAAM,CAInC;AAED;;8EAE8E;AAC9E,wBAAgB,SAAS,IAAI,MAAM,CAIlC"}
@@ -0,0 +1,50 @@
1
+ import { accessSync, constants } from "node:fs";
2
+ import { delimiter, join } from "node:path";
3
+ /** This CLI's own invocation as argv: `[node, ...loaderFlags, entryScript]`. The loader flags carry
4
+ * tsx in dev (so a re-exec can run the `.ts` entry) and are empty in prod (entry = compiled JS).
5
+ * Re-execed children (web, manager) and cmux pane commands use this so they never depend on
6
+ * `cotal` being on PATH — works the same via `npx`, `npm i -g`, and a dev clone. */
7
+ export function selfArgv() {
8
+ return [process.execPath, ...process.execArgv, process.argv[1]];
9
+ }
10
+ /** True when launched via `npx` — the package is unpacked under `~/.npm/_npx/<hash>/…`. */
11
+ export function isNpx() {
12
+ return /[/\\]_npx[/\\]/.test(process.argv[1] ?? "");
13
+ }
14
+ /** Is a `cotal` executable resolvable on PATH? A pure PATH scan (no exec): `cotal --version`
15
+ * isn't a real command, so probing it via `onPath` would always report cotal as missing. */
16
+ export function cotalOnPath() {
17
+ const exts = process.platform === "win32" ? ["", ".cmd", ".exe", ".bat"] : [""];
18
+ for (const dir of (process.env.PATH ?? "").split(delimiter)) {
19
+ if (!dir)
20
+ continue;
21
+ for (const ext of exts) {
22
+ try {
23
+ accessSync(join(dir, `cotal${ext}`), constants.X_OK);
24
+ return true;
25
+ }
26
+ catch {
27
+ /* not here */
28
+ }
29
+ }
30
+ }
31
+ return false;
32
+ }
33
+ /** The copy-paste command prefix for user-facing hints: `cotal` when it's on PATH, `npx cotal-ai`
34
+ * for an npx run, `pnpm cotal` in a dev clone. (Display only — re-execs use {@link selfArgv}.) */
35
+ export function displayCmd() {
36
+ if (cotalOnPath())
37
+ return "cotal";
38
+ if (isNpx())
39
+ return "npx cotal-ai";
40
+ return "pnpm cotal";
41
+ }
42
+ /** The self-invocation as a shell-ready, double-quoted command prefix (for cmux pane commands).
43
+ * Tokens are absolute paths with no single quotes, so the surrounding `bash -lc '…'` single-quote
44
+ * wrapping stays intact through a login shell (e.g. nushell) before bash. */
45
+ export function selfCotal() {
46
+ return selfArgv()
47
+ .map((a) => `"${a}"`)
48
+ .join(" ");
49
+ }
50
+ //# sourceMappingURL=self-exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"self-exec.js","sourceRoot":"","sources":["../../src/lib/self-exec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE5C;;;qFAGqF;AACrF,MAAM,UAAU,QAAQ;IACtB,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,KAAK;IACnB,OAAO,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;6FAC6F;AAC7F,MAAM,UAAU,WAAW;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAChF,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5D,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,GAAG,EAAE,CAAC,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;gBACrD,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,cAAc;YAChB,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;mGACmG;AACnG,MAAM,UAAU,UAAU;IACxB,IAAI,WAAW,EAAE;QAAE,OAAO,OAAO,CAAC;IAClC,IAAI,KAAK,EAAE;QAAE,OAAO,cAAc,CAAC;IACnC,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;8EAE8E;AAC9E,MAAM,UAAU,SAAS;IACvB,OAAO,QAAQ,EAAE;SACd,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC;SACpB,IAAI,CAAC,GAAG,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface SetupLog {
2
+ path: string;
3
+ line(s: string): void;
4
+ }
5
+ /** Timestamped append log for `cotal setup` — one file, also the first thing a
6
+ * Claude handoff is pointed at. Resolves the project's `.cotal/` (walks up from cwd). */
7
+ export declare function openSetupLog(_cwd: string): SetupLog;
8
+ //# sourceMappingURL=setup-log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-log.d.ts","sourceRoot":"","sources":["../../src/lib/setup-log.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;0FAC0F;AAC1F,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAUnD"}
@@ -0,0 +1,17 @@
1
+ import { appendFileSync, mkdirSync } from "node:fs";
2
+ import { dirname } from "node:path";
3
+ import { cotalPath } from "./paths.js";
4
+ /** Timestamped append log for `cotal setup` — one file, also the first thing a
5
+ * Claude handoff is pointed at. Resolves the project's `.cotal/` (walks up from cwd). */
6
+ export function openSetupLog(_cwd) {
7
+ const path = cotalPath("setup.log");
8
+ mkdirSync(dirname(path), { recursive: true });
9
+ appendFileSync(path, `\n=== cotal setup — ${new Date().toISOString()} ===\n`);
10
+ return {
11
+ path,
12
+ line(s) {
13
+ appendFileSync(path, `${new Date().toISOString()} ${s}\n`);
14
+ },
15
+ };
16
+ }
17
+ //# sourceMappingURL=setup-log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup-log.js","sourceRoot":"","sources":["../../src/lib/setup-log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAOvC;0FAC0F;AAC1F,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,IAAI,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;IACpC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,cAAc,CAAC,IAAI,EAAE,uBAAuB,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAC9E,OAAO;QACL,IAAI;QACJ,IAAI,CAAC,CAAS;YACZ,cAAc,CAAC,IAAI,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ export interface MeshStatus {
2
+ reachable: boolean;
3
+ server: string;
4
+ space: string;
5
+ auth: boolean;
6
+ }
7
+ /** The space this folder operates on: its `.cotal/auth` space if set up, else the default.
8
+ * A folder has exactly one space (its auth) — commands resolve it through here so they always
9
+ * match the folder's mesh instead of assuming the global default. */
10
+ export declare function resolveSpace(cwd: string): string;
11
+ /** Cheap, connectionless-ish snapshot of the mesh for this folder: is a server up,
12
+ * and what space/auth does the local `.cotal/` describe (found by walking up from `cwd`). */
13
+ export declare function meshStatus(cwd: string): Promise<MeshStatus>;
14
+ export interface MachineStatus {
15
+ nats: "path" | "bundled" | "missing";
16
+ claudePlugin: boolean;
17
+ agents: {
18
+ claude: boolean;
19
+ opencode: boolean;
20
+ };
21
+ }
22
+ /** Machine-level readiness: the once-per-machine setup pieces. */
23
+ export declare function machineStatus(): Promise<MachineStatus>;
24
+ export declare function onPath(bin: string): boolean;
25
+ /** True once the machine-level setup has completed at least once. */
26
+ export declare function hasLocalMesh(cwd: string): boolean;
27
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/lib/status.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,OAAO,CAAC;CACf;AAED;;sEAEsE;AACtE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;8FAC8F;AAC9F,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CASjE;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;IACrC,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;CAChD;AAED,kEAAkE;AAClE,wBAAsB,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC,CAe5D;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAG3C;AAQD,qEAAqE;AACrE,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGjD"}
@@ -0,0 +1,57 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { DEFAULT_SERVER, DEFAULT_SPACE, authDir, findCotalRoot, isReachable, loadSpaceAuth } from "@cotal-ai/core";
5
+ import { resolveNatsServer } from "./nats-bin.js";
6
+ /** The space this folder operates on: its `.cotal/auth` space if set up, else the default.
7
+ * A folder has exactly one space (its auth) — commands resolve it through here so they always
8
+ * match the folder's mesh instead of assuming the global default. */
9
+ export function resolveSpace(cwd) {
10
+ return loadSpaceAuth(authDir(findCotalRoot(cwd)))?.space ?? DEFAULT_SPACE;
11
+ }
12
+ /** Cheap, connectionless-ish snapshot of the mesh for this folder: is a server up,
13
+ * and what space/auth does the local `.cotal/` describe (found by walking up from `cwd`). */
14
+ export async function meshStatus(cwd) {
15
+ const server = DEFAULT_SERVER;
16
+ const auth = loadSpaceAuth(authDir(findCotalRoot(cwd)));
17
+ return {
18
+ reachable: await isReachable(server),
19
+ server,
20
+ space: auth?.space ?? DEFAULT_SPACE,
21
+ auth: Boolean(auth),
22
+ };
23
+ }
24
+ /** Machine-level readiness: the once-per-machine setup pieces. */
25
+ export async function machineStatus() {
26
+ let nats = "missing";
27
+ try {
28
+ nats = (await resolveNatsServer()).source;
29
+ }
30
+ catch {
31
+ nats = "missing";
32
+ }
33
+ return {
34
+ nats,
35
+ claudePlugin: claudePluginInstalled(),
36
+ agents: {
37
+ claude: onPath("claude"),
38
+ opencode: onPath("opencode"),
39
+ },
40
+ };
41
+ }
42
+ export function onPath(bin) {
43
+ const r = spawnSync(bin, ["--version"], { stdio: "ignore" });
44
+ return !r.error && r.status === 0;
45
+ }
46
+ function claudePluginInstalled() {
47
+ if (!onPath("claude"))
48
+ return false;
49
+ const r = spawnSync("claude", ["plugin", "list"], { encoding: "utf8" });
50
+ return r.status === 0 && /cotal@cotal-mesh/.test(`${r.stdout ?? ""}${r.stderr ?? ""}`);
51
+ }
52
+ /** True once the machine-level setup has completed at least once. */
53
+ export function hasLocalMesh(cwd) {
54
+ const root = findCotalRoot(cwd);
55
+ return existsSync(join(root, ".cotal", "auth", "auth.json")) || existsSync(join(root, ".cotal", "nats"));
56
+ }
57
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/lib/status.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACnH,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AASlD;;sEAEsE;AACtE,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,aAAa,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,aAAa,CAAC;AAC5E,CAAC;AAED;8FAC8F;AAC9F,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,MAAM,MAAM,GAAG,cAAc,CAAC;IAC9B,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACxD,OAAO;QACL,SAAS,EAAE,MAAM,WAAW,CAAC,MAAM,CAAC;QACpC,MAAM;QACN,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,aAAa;QACnC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC;KACpB,CAAC;AACJ,CAAC;AAQD,kEAAkE;AAClE,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,IAAI,GAA0B,SAAS,CAAC;IAC5C,IAAI,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,iBAAiB,EAAE,CAAC,CAAC,MAAM,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,SAAS,CAAC;IACnB,CAAC;IACD,OAAO;QACL,IAAI;QACJ,YAAY,EAAE,qBAAqB,EAAE;QACrC,MAAM,EAAE;YACN,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC;YACxB,QAAQ,EAAE,MAAM,CAAC,UAAU,CAAC;SAC7B;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,MAAM,CAAC,GAAG,SAAS,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7D,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,qBAAqB;IAC5B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,MAAM,CAAC,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACxE,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,IAAI,EAAE,GAAG,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAChC,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;AAC3G,CAAC"}
@@ -0,0 +1,31 @@
1
+ import type { SetupLog } from "./setup-log.js";
2
+ export interface Step {
3
+ /** Slug used in the log and the Claude handoff prompt. */
4
+ name: string;
5
+ /** Human line shown while the step runs. */
6
+ title: string;
7
+ /** One-line plain-language narration shown before the step runs. */
8
+ explain?: string;
9
+ /** Ask before running (Y/n); a declined optional step is simply skipped. */
10
+ optional?: boolean;
11
+ /** Consent prompt shown (Y/n, default yes) before the step runs on a TTY; a "no"
12
+ * skips the step. Non-TTY runs without asking. For steps that change the user's
13
+ * system (e.g. installing the Claude Code plugin). */
14
+ confirm?: string;
15
+ /** The step draws its own live pane; the runner shows no spinner, just the result line. */
16
+ live?: boolean;
17
+ /** Paths/URLs Claude should read when this step fails. */
18
+ context?: string[];
19
+ /** Throw to fail; a returned string becomes the detail on the result line. */
20
+ run(): Promise<string | void>;
21
+ }
22
+ /** Run steps in order with a failure loop per step: offer a Claude handoff, then
23
+ * retry / skip / quit. Returns false on abort.
24
+ *
25
+ * `yes` is non-interactive accept-all (agents/CI): optional and `confirm` steps run
26
+ * without prompting (so e.g. demo agents are written), and a failure aborts with the
27
+ * log path instead of opening the recovery menu/handoff, even on a TTY. */
28
+ export declare function runSteps(steps: Step[], log: SetupLog, opts?: {
29
+ yes?: boolean;
30
+ }): Promise<boolean>;
31
+ //# sourceMappingURL=steps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../../src/lib/steps.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,MAAM,WAAW,IAAI;IACnB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;2DAEuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,2FAA2F;IAC3F,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,0DAA0D;IAC1D,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,8EAA8E;IAC9E,GAAG,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/B;AAED;;;;;4EAK4E;AAC5E,wBAAsB,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAiB3G"}
@@ -0,0 +1,91 @@
1
+ import * as p from "@clack/prompts";
2
+ import { dim } from "./theme.js";
3
+ import { abortIfCancel } from "./cancel.js";
4
+ import { assistAvailable, runHandoff } from "./assist.js";
5
+ /** Run steps in order with a failure loop per step: offer a Claude handoff, then
6
+ * retry / skip / quit. Returns false on abort.
7
+ *
8
+ * `yes` is non-interactive accept-all (agents/CI): optional and `confirm` steps run
9
+ * without prompting (so e.g. demo agents are written), and a failure aborts with the
10
+ * log path instead of opening the recovery menu/handoff, even on a TTY. */
11
+ export async function runSteps(steps, log, opts = {}) {
12
+ const interactive = process.stdin.isTTY && !opts.yes;
13
+ for (const step of steps) {
14
+ if (step.optional && !opts.yes && (!interactive || !(await ask(`${step.title}?`)))) {
15
+ p.log.info(dim(`skipped: ${step.title}`));
16
+ log.line(`${step.name}: skipped (declined)`);
17
+ continue;
18
+ }
19
+ // Consent before a system-changing step (interactive only); a "no" skips it.
20
+ if (step.confirm && interactive && !(await ask(step.confirm))) {
21
+ p.log.info(dim(`skipped: ${step.title}`));
22
+ log.line(`${step.name}: skipped (declined consent)`);
23
+ continue;
24
+ }
25
+ if (!(await runOne(step, log, interactive)))
26
+ return false;
27
+ }
28
+ return true;
29
+ }
30
+ async function runOne(step, log, interactive) {
31
+ for (;;) {
32
+ if (step.explain)
33
+ p.log.step(step.explain);
34
+ const spin = step.live ? undefined : p.spinner();
35
+ spin?.start(step.title);
36
+ try {
37
+ const detail = await step.run();
38
+ const line = `${step.title}${detail ? dim(` · ${detail}`) : ""}`;
39
+ if (spin)
40
+ spin.stop(line);
41
+ else
42
+ p.log.success(line);
43
+ log.line(`${step.name}: ok${detail ? ` · ${detail}` : ""}`);
44
+ return true;
45
+ }
46
+ catch (e) {
47
+ const err = e;
48
+ if (spin)
49
+ spin.stop(`${step.title}: failed`);
50
+ p.log.error(err.message);
51
+ log.line(`${step.name}: FAILED · ${err.message}`);
52
+ // Non-interactive (CI, piped, or --yes): no recovery loop; abort with the log path.
53
+ if (!interactive) {
54
+ p.log.message(dim(`See ${log.path}`));
55
+ return false;
56
+ }
57
+ const choice = await failureMenu(step);
58
+ if (choice === "debug") {
59
+ await runHandoff({ step: step.name, error: err, context: step.context ?? [], logPath: log.path });
60
+ continue;
61
+ }
62
+ if (choice === "retry")
63
+ continue;
64
+ if (choice === "skip") {
65
+ if (!step.optional) {
66
+ p.log.warn(`Setup can't continue without "${step.title}". Fix it and re-run: cotal setup`);
67
+ return false;
68
+ }
69
+ log.line(`${step.name}: skipped (after failure)`);
70
+ return true;
71
+ }
72
+ return false; // quit
73
+ }
74
+ }
75
+ }
76
+ async function failureMenu(step) {
77
+ const options = [{ value: "retry", label: "Retry this step" }];
78
+ if (assistAvailable())
79
+ options.push({ value: "debug", label: "Debug it with Claude" });
80
+ options.push({ value: "skip", label: step.optional ? "Skip it" : "Skip (may abort)" });
81
+ options.push({ value: "quit", label: "Quit setup" });
82
+ const choice = await p.select({ message: "What now?", options });
83
+ if (p.isCancel(choice))
84
+ return "quit";
85
+ return choice;
86
+ }
87
+ async function ask(message) {
88
+ // A real "No" returns false (skip the step); Ctrl-C aborts setup.
89
+ return abortIfCancel(await p.confirm({ message, initialValue: true }));
90
+ }
91
+ //# sourceMappingURL=steps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steps.js","sourceRoot":"","sources":["../../src/lib/steps.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export declare const brand: (s: string) => string;
2
+ export declare const brandBold: (s: string) => string;
3
+ export declare const ok: (s: string) => string;
4
+ export declare const dim: (s: string) => string;
5
+ export declare const bold: (s: string) => string;
6
+ /** Multi-line strings get colored line-by-line so the SGR reset doesn't bleed across
7
+ * clack's `│` gutter prefix. Used as the `format` callback for `note()` bodies. */
8
+ export declare const brandBody: (s: string) => string;
9
+ /** Elapsed-time suffix for spinners: `47s` under a minute, `2m 34s` above. */
10
+ export declare function fmtDuration(ms: number): string;
11
+ /** Truncate to the terminal width (minus a gutter) so live-pane lines never wrap. */
12
+ export declare function fit(s: string, gutter?: number): string;
13
+ /** A branded `p.note` (body in brand color). */
14
+ export declare function note(message: string, title?: string): void;
15
+ /** First-run splash: brand wordmark + tagline + rule. No-op detail when ANSI is off
16
+ * still prints the plain wordmark so piped logs stay legible. */
17
+ export declare function splash(): void;
18
+ //# sourceMappingURL=theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/lib/theme.ts"],"names":[],"mappings":"AAwBA,eAAO,MAAM,KAAK,GAAI,GAAG,MAAM,WAAkB,CAAC;AAClD,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,WAAwB,CAAC;AAC5D,eAAO,MAAM,EAAE,GAAI,GAAG,MAAM,WAAyE,CAAC;AACtG,eAAO,MAAM,GAAG,GAAI,GAAG,MAAM,WAA0C,CAAC;AACxE,eAAO,MAAM,IAAI,GAAI,GAAG,MAAM,WAA0C,CAAC;AAEzE;oFACoF;AACpF,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,KAAG,MAIvB,CAAC;AAEhB,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAI9C;AAED,qFAAqF;AACrF,wBAAgB,GAAG,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,SAAI,GAAG,MAAM,CAGjD;AAED,gDAAgD;AAChD,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAE1D;AASD;kEACkE;AAClE,wBAAgB,MAAM,IAAI,IAAI,CAG7B"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Cotal brand palette for the terminal setup flow. Colors match the web dashboard
3
+ * (implementations/cli/src/web/index.html): brand blue #58a6ff, success green #3fb950.
4
+ *
5
+ * Rendering gates (same as the rest of the CLI's color story):
6
+ * - No TTY (piped/redirected) or NO_COLOR → plain text, no ANSI
7
+ * - COLORTERM truecolor/24bit → 24-bit ANSI (exact brand color)
8
+ * - otherwise → 16-color fallback
9
+ */
10
+ import * as p from "@clack/prompts";
11
+ const USE_ANSI = Boolean(process.stdout.isTTY) && !process.env.NO_COLOR;
12
+ const TRUECOLOR = USE_ANSI && (process.env.COLORTERM === "truecolor" || process.env.COLORTERM === "24bit");
13
+ const BRAND = [88, 166, 255]; // #58a6ff
14
+ const GREEN = [63, 185, 80]; // #3fb950
15
+ function rgb([r, g, b], s, bold = false) {
16
+ if (!USE_ANSI)
17
+ return s;
18
+ if (TRUECOLOR)
19
+ return `\x1b[${bold ? "1;" : ""}38;2;${r};${g};${b}m${s}\x1b[0m`;
20
+ return `\x1b[${bold ? "1;" : ""}34m${s}\x1b[0m`; // 16-color blue/green fallback
21
+ }
22
+ export const brand = (s) => rgb(BRAND, s);
23
+ export const brandBold = (s) => rgb(BRAND, s, true);
24
+ export const ok = (s) => (USE_ANSI ? (TRUECOLOR ? rgb(GREEN, s) : `\x1b[32m${s}\x1b[0m`) : s);
25
+ export const dim = (s) => (USE_ANSI ? `\x1b[2m${s}\x1b[0m` : s);
26
+ export const bold = (s) => (USE_ANSI ? `\x1b[1m${s}\x1b[0m` : s);
27
+ /** Multi-line strings get colored line-by-line so the SGR reset doesn't bleed across
28
+ * clack's `│` gutter prefix. Used as the `format` callback for `note()` bodies. */
29
+ export const brandBody = (s) => s
30
+ .split("\n")
31
+ .map((line) => (line.length ? brand(line) : line))
32
+ .join("\n");
33
+ /** Elapsed-time suffix for spinners: `47s` under a minute, `2m 34s` above. */
34
+ export function fmtDuration(ms) {
35
+ const total = Math.round(ms / 1000);
36
+ if (total < 60)
37
+ return `${total}s`;
38
+ return `${Math.floor(total / 60)}m ${total % 60}s`;
39
+ }
40
+ /** Truncate to the terminal width (minus a gutter) so live-pane lines never wrap. */
41
+ export function fit(s, gutter = 4) {
42
+ const width = Math.max(20, (process.stdout.columns ?? 80) - gutter);
43
+ return s.length > width ? `${s.slice(0, width - 1)}…` : s;
44
+ }
45
+ /** A branded `p.note` (body in brand color). */
46
+ export function note(message, title) {
47
+ p.note(message, title, { format: brandBody });
48
+ }
49
+ const WORDMARK = String.raw `
50
+ _ _
51
+ ___ ___ | |_ __ _| |
52
+ / __/ _ \| __/ _` + "`" + String.raw `| |
53
+ | (_| (_) | || (_| | |
54
+ \___\___/ \__\__,_|_|`;
55
+ /** First-run splash: brand wordmark + tagline + rule. No-op detail when ANSI is off
56
+ * still prints the plain wordmark so piped logs stay legible. */
57
+ export function splash() {
58
+ const rule = "─".repeat(Math.min(44, (process.stdout.columns ?? 80) - 2));
59
+ process.stdout.write(`${brand(WORDMARK)}\n\n ${dim("the web for agents")}\n ${brand(rule)}\n\n`);
60
+ }
61
+ //# sourceMappingURL=theme.js.map