@aexol/spectral 0.9.231 → 0.9.240

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 (157) hide show
  1. package/README.md +47 -0
  2. package/dist/agent/index.d.ts +32 -5
  3. package/dist/agent/index.d.ts.map +1 -1
  4. package/dist/agent/index.js +209 -36
  5. package/dist/backend/generated-images.d.ts +1 -1
  6. package/dist/backend/generated-images.d.ts.map +1 -1
  7. package/dist/cli.d.ts +2 -0
  8. package/dist/cli.d.ts.map +1 -1
  9. package/dist/cli.js +18 -4
  10. package/dist/commands/desktop.d.ts +167 -0
  11. package/dist/commands/desktop.d.ts.map +1 -0
  12. package/dist/commands/desktop.js +540 -0
  13. package/dist/commands/serve.d.ts +9 -1
  14. package/dist/commands/serve.d.ts.map +1 -1
  15. package/dist/commands/serve.js +90 -2
  16. package/dist/commands/update.d.ts +85 -5
  17. package/dist/commands/update.d.ts.map +1 -1
  18. package/dist/commands/update.js +288 -58
  19. package/dist/extensions/desktop-control/macos.d.ts.map +1 -1
  20. package/dist/extensions/desktop-control/macos.js +2 -2
  21. package/dist/extensions/logic-trace.d.ts +1 -1
  22. package/dist/extensions/logic-trace.d.ts.map +1 -1
  23. package/dist/extensions/logic-trace.js +199 -70
  24. package/dist/extensions/video-generation/index.d.ts +3 -0
  25. package/dist/extensions/video-generation/index.d.ts.map +1 -0
  26. package/dist/extensions/video-generation/index.js +299 -0
  27. package/dist/generated/zeus/const.d.ts.map +1 -1
  28. package/dist/generated/zeus/const.js +30 -0
  29. package/dist/generated/zeus/index.d.ts +140 -0
  30. package/dist/generated/zeus/index.d.ts.map +1 -1
  31. package/dist/generated/zeus/index.js +5 -0
  32. package/dist/mcp/server-manager.d.ts.map +1 -1
  33. package/dist/mcp/server-manager.js +6 -0
  34. package/dist/memory/tools/receive-agent-observations.d.ts.map +1 -1
  35. package/dist/memory/tools/receive-agent-observations.js +12 -2
  36. package/dist/relay/dispatcher.d.ts +13 -1
  37. package/dist/relay/dispatcher.d.ts.map +1 -1
  38. package/dist/relay/dispatcher.js +41 -2
  39. package/dist/sdk/agent-core/agent-loop.js +13 -3
  40. package/dist/sdk/agent-core/agent.d.ts +11 -4
  41. package/dist/sdk/agent-core/agent.d.ts.map +1 -1
  42. package/dist/sdk/agent-core/agent.js +16 -4
  43. package/dist/sdk/agent-core/tool-call-registry.d.ts +75 -0
  44. package/dist/sdk/agent-core/tool-call-registry.d.ts.map +1 -0
  45. package/dist/sdk/agent-core/tool-call-registry.js +131 -0
  46. package/dist/sdk/agent-core/tool-execution.d.ts.map +1 -1
  47. package/dist/sdk/agent-core/tool-execution.js +103 -4
  48. package/dist/sdk/agent-core/types.d.ts +15 -4
  49. package/dist/sdk/agent-core/types.d.ts.map +1 -1
  50. package/dist/sdk/ai/index.d.ts +3 -0
  51. package/dist/sdk/ai/index.d.ts.map +1 -1
  52. package/dist/sdk/ai/index.js +3 -0
  53. package/dist/sdk/ai/providers/faux.d.ts.map +1 -1
  54. package/dist/sdk/ai/providers/faux.js +3 -0
  55. package/dist/sdk/ai/providers/leaked-tool-call-parser.d.ts +39 -6
  56. package/dist/sdk/ai/providers/leaked-tool-call-parser.d.ts.map +1 -1
  57. package/dist/sdk/ai/providers/leaked-tool-call-parser.js +159 -18
  58. package/dist/sdk/ai/providers/openai-completions.d.ts.map +1 -1
  59. package/dist/sdk/ai/providers/openai-completions.js +22 -8
  60. package/dist/sdk/ai/providers/openrouter-videos.d.ts +3 -0
  61. package/dist/sdk/ai/providers/openrouter-videos.d.ts.map +1 -0
  62. package/dist/sdk/ai/providers/openrouter-videos.js +412 -0
  63. package/dist/sdk/ai/providers/register-builtins.d.ts.map +1 -1
  64. package/dist/sdk/ai/providers/register-builtins.js +6 -0
  65. package/dist/sdk/ai/providers/simple-options.d.ts +1 -6
  66. package/dist/sdk/ai/providers/simple-options.d.ts.map +1 -1
  67. package/dist/sdk/ai/providers/simple-options.js +0 -22
  68. package/dist/sdk/ai/providers/transform-messages.d.ts.map +1 -1
  69. package/dist/sdk/ai/providers/transform-messages.js +52 -1
  70. package/dist/sdk/ai/types.d.ts +91 -10
  71. package/dist/sdk/ai/types.d.ts.map +1 -1
  72. package/dist/sdk/ai/video-models.d.ts +10 -0
  73. package/dist/sdk/ai/video-models.d.ts.map +1 -0
  74. package/dist/sdk/ai/video-models.generated.d.ts +440 -0
  75. package/dist/sdk/ai/video-models.generated.d.ts.map +1 -0
  76. package/dist/sdk/ai/video-models.generated.js +441 -0
  77. package/dist/sdk/ai/video-models.js +22 -0
  78. package/dist/sdk/ai/videos-api-registry.d.ts +14 -0
  79. package/dist/sdk/ai/videos-api-registry.d.ts.map +1 -0
  80. package/dist/sdk/ai/videos-api-registry.js +21 -0
  81. package/dist/sdk/ai/videos.d.ts +4 -0
  82. package/dist/sdk/ai/videos.d.ts.map +1 -0
  83. package/dist/sdk/ai/videos.js +13 -0
  84. package/dist/sdk/coding-agent/core/agent-session.d.ts +8 -0
  85. package/dist/sdk/coding-agent/core/agent-session.d.ts.map +1 -1
  86. package/dist/sdk/coding-agent/core/agent-session.js +11 -0
  87. package/dist/sdk/coding-agent/core/extensions/loader.d.ts.map +1 -1
  88. package/dist/sdk/coding-agent/core/extensions/loader.js +14 -0
  89. package/dist/sdk/coding-agent/core/extensions/native-extensions.d.ts +26 -0
  90. package/dist/sdk/coding-agent/core/extensions/native-extensions.d.ts.map +1 -1
  91. package/dist/sdk/coding-agent/core/extensions/native-extensions.js +23 -0
  92. package/dist/sdk/coding-agent/core/extensions/session-events.d.ts +2 -2
  93. package/dist/sdk/coding-agent/core/extensions/session-events.d.ts.map +1 -1
  94. package/dist/sdk/coding-agent/core/extensions/types.d.ts +12 -2
  95. package/dist/sdk/coding-agent/core/extensions/types.d.ts.map +1 -1
  96. package/dist/sdk/coding-agent/core/messages.d.ts.map +1 -1
  97. package/dist/sdk/coding-agent/core/messages.js +42 -2
  98. package/dist/sdk/coding-agent/core/resource-loader.d.ts +11 -0
  99. package/dist/sdk/coding-agent/core/resource-loader.d.ts.map +1 -1
  100. package/dist/sdk/coding-agent/core/resource-loader.js +23 -6
  101. package/dist/sdk/coding-agent/core/sdk.d.ts +24 -2
  102. package/dist/sdk/coding-agent/core/sdk.d.ts.map +1 -1
  103. package/dist/sdk/coding-agent/core/sdk.js +15 -3
  104. package/dist/sdk/coding-agent/core/settings-manager.d.ts +0 -8
  105. package/dist/sdk/coding-agent/core/settings-manager.d.ts.map +1 -1
  106. package/dist/sdk/coding-agent/core/settings-manager.js +3 -3
  107. package/dist/sdk/coding-agent/core/system-prompt.d.ts.map +1 -1
  108. package/dist/sdk/coding-agent/core/system-prompt.js +5 -0
  109. package/dist/sdk/coding-agent/index.d.ts +2 -2
  110. package/dist/sdk/coding-agent/index.d.ts.map +1 -1
  111. package/dist/sdk/coding-agent/index.js +1 -1
  112. package/dist/sdk-public.d.ts +96 -0
  113. package/dist/sdk-public.d.ts.map +1 -0
  114. package/dist/sdk-public.js +109 -0
  115. package/dist/server/agent-bridge/rehydrate.d.ts +2 -2
  116. package/dist/server/agent-bridge/rehydrate.d.ts.map +1 -1
  117. package/dist/server/agent-bridge/rehydrate.js +14 -0
  118. package/dist/server/agent-bridge/tps-metrics.d.ts +34 -0
  119. package/dist/server/agent-bridge/tps-metrics.d.ts.map +1 -1
  120. package/dist/server/agent-bridge/tps-metrics.js +22 -0
  121. package/dist/server/agent-bridge.d.ts +17 -2
  122. package/dist/server/agent-bridge.d.ts.map +1 -1
  123. package/dist/server/agent-bridge.js +108 -5
  124. package/dist/server/handlers/paths-list.d.ts +1 -1
  125. package/dist/server/handlers/paths-list.js +1 -1
  126. package/dist/server/inter-agent-broker.d.ts +12 -0
  127. package/dist/server/inter-agent-broker.d.ts.map +1 -1
  128. package/dist/server/inter-agent-broker.js +1 -0
  129. package/dist/server/preset-chain.d.ts +151 -0
  130. package/dist/server/preset-chain.d.ts.map +1 -0
  131. package/dist/server/preset-chain.js +250 -0
  132. package/dist/server/session-stream.d.ts +74 -1
  133. package/dist/server/session-stream.d.ts.map +1 -1
  134. package/dist/server/session-stream.js +238 -24
  135. package/dist/server/storage/rows.d.ts +2 -0
  136. package/dist/server/storage/rows.d.ts.map +1 -1
  137. package/dist/server/storage/schema.d.ts +2 -2
  138. package/dist/server/storage/schema.d.ts.map +1 -1
  139. package/dist/server/storage/schema.js +2 -1
  140. package/dist/server/storage.d.ts +7 -0
  141. package/dist/server/storage.d.ts.map +1 -1
  142. package/dist/server/storage.js +142 -9
  143. package/dist/server/wire.d.ts +84 -0
  144. package/dist/server/wire.d.ts.map +1 -1
  145. package/dist/utils/augment-path.d.ts +51 -0
  146. package/dist/utils/augment-path.d.ts.map +1 -0
  147. package/dist/utils/augment-path.js +234 -0
  148. package/dist/utils/open-browser.d.ts +55 -0
  149. package/dist/utils/open-browser.d.ts.map +1 -0
  150. package/dist/utils/open-browser.js +163 -0
  151. package/dist/utils/serve-state.d.ts +264 -0
  152. package/dist/utils/serve-state.d.ts.map +1 -0
  153. package/dist/utils/serve-state.js +563 -0
  154. package/dist/utils/standalone.d.ts +14 -0
  155. package/dist/utils/standalone.d.ts.map +1 -0
  156. package/dist/utils/standalone.js +23 -0
  157. package/package.json +7 -3
@@ -40,7 +40,7 @@ import { refreshCloudAgents as refreshCloudAgentsImpl } from "../agent/agents.js
40
40
  import { requireLogin } from "../preflight.js";
41
41
  import { RelayClient } from "../relay/client.js";
42
42
  import { getFanoutManager } from "../server/fanout/fanout-manager.js";
43
- import { detachAllSubscribers, handleAutoOptimizeFrame, handleAutoResearchFrame, handleCancelTurn, handleClientMessage, handleRestRequest, handleSubscribe, } from "../relay/dispatcher.js";
43
+ import { detachAllSubscribers, handleAutoOptimizeFrame, handleAutoResearchFrame, handleCancelTurn, handleClientMessage, handleRestRequest, handleStopToolCall, handleSubscribe, } from "../relay/dispatcher.js";
44
44
  import { ensureMachineRegistered } from "../relay/registration.js";
45
45
  import { saveMachine } from "../relay/machine-store.js";
46
46
  import { SessionStreamManager } from "../server/session-stream.js";
@@ -49,6 +49,8 @@ import { getLiveMcpState } from "../mcp/state-getter.js";
49
49
  import { preflightSqlite, SessionStore } from "../server/storage.js";
50
50
  import { DevProcessRegistry } from "../server/dev-process-registry.js";
51
51
  import { sweepOffloads } from "../server/offload-gc.js";
52
+ import { SERVE_READY_MARKER, clearServeState, getLiveServePid, ownsServeState, writeServePid, writeServeReady, } from "../utils/serve-state.js";
53
+ import { applyAugmentedPath } from "../utils/augment-path.js";
52
54
  /** Default backend base URL when neither env nor override is set. */
53
55
  const DEFAULT_BACKEND_URL = "https://api.aexol.ai";
54
56
  import { getVersion } from "../version.js";
@@ -127,6 +129,7 @@ export async function runServe(opts = {}) {
127
129
  const installSignalHandlers = opts.installSignalHandlers ?? true;
128
130
  const silent = opts.silent ?? false;
129
131
  const dbPath = opts.dbPath ?? join(getConfigDir(), "sessions.db");
132
+ const serveState = opts.serveState ?? true;
130
133
  // Pre-flight: native sqlite. Fail fast with a friendly hint BEFORE we
131
134
  // start opening sockets — keeps the error close to the cause.
132
135
  const preflight = preflightSqlite(dbPath);
@@ -134,6 +137,29 @@ export async function runServe(opts = {}) {
134
137
  process.stderr.write(`✗ ${preflight.error}\n`);
135
138
  process.exit(1);
136
139
  }
140
+ // Single-instance bookkeeping. Claim the pid file before any long-running
141
+ // work so `spectral desktop status|stop` and a second `spectral desktop`
142
+ // can find this daemon. Readers prune a stale file with a liveness check,
143
+ // so a SIGKILLed run never wedges the next start.
144
+ if (serveState) {
145
+ // Warn (never refuse) when another live daemon already holds the pid file.
146
+ // Two relays from one machine are legal — the second simply takes over
147
+ // ownership, which would otherwise silently make `desktop stop` target the
148
+ // wrong process.
149
+ //
150
+ // `spectral desktop` claims the pid file with its OWN pid before spawning
151
+ // us (that is what makes the single-instance check atomic), and passes that
152
+ // pid in `SPECTRAL_SERVE_PID_CLAIM`. Seeing it is the expected hand-off,
153
+ // not a competing daemon — ditto our direct parent.
154
+ const previous = getLiveServePid();
155
+ const launchClaim = Number.parseInt(process.env.SPECTRAL_SERVE_PID_CLAIM ?? "", 10);
156
+ const expectedHolder = previous === process.ppid || (Number.isInteger(launchClaim) && previous === launchClaim);
157
+ if (previous !== null && previous !== process.pid && !expectedHolder && !silent) {
158
+ process.stderr.write(`warning: another spectral serve appears to be running (pid ${previous}); ` +
159
+ `this process will take over ~/.spectral/serve.pid\n`);
160
+ }
161
+ writeServePid();
162
+ }
137
163
  // Pre-flight: sweep stale large-result offload files (fire-and-forget).
138
164
  const store = new SessionStore(dbPath);
139
165
  const devProcessRegistry = new DevProcessRegistry(getAgentDir());
@@ -278,6 +304,30 @@ export async function runServe(opts = {}) {
278
304
  // resume mid-turn.
279
305
  const subscribers = new Map();
280
306
  let relay;
307
+ /**
308
+ * Announce readiness to whoever launched us. The Electron app used to guess
309
+ * ("is the child still alive after 3 s?"), which raced the relay handshake:
310
+ * the web app loaded, subscribed to the relay before it existed, and showed
311
+ * `machine_disconnected` on every start. Instead, the FIRST time the socket
312
+ * is genuinely open we (a) drop `serve-ready.json` {pid, ts, version} and
313
+ * (b) print `SPECTRAL_SERVE_READY` on stdout. A launcher that redirected our
314
+ * stdio to a log file still has the file; a launcher watching stdout doesn't
315
+ * need the file. Later reconnects refresh the ready file's timestamp but do
316
+ * not re-print the marker — it is a startup signal, not a liveness ping.
317
+ */
318
+ let readyAnnounced = false;
319
+ const announceServeReady = () => {
320
+ // Only the pid-file holder may publish readiness. A second daemon that took
321
+ // over, or one that lost the file to a restart, must not overwrite the
322
+ // ready signal of the process that owns it — `desktop`/`status` read that
323
+ // file as the answer to "is MY agent up".
324
+ if (ownsServeState())
325
+ writeServeReady(version);
326
+ if (readyAnnounced)
327
+ return;
328
+ readyAnnounced = true;
329
+ process.stdout.write(`${SERVE_READY_MARKER}\n`);
330
+ };
281
331
  /** Wire event handlers on a (possibly new) RelayClient instance. */
282
332
  function wireRelay(r) {
283
333
  // Wire the meta publisher now that we have both the relay socket and
@@ -350,6 +400,17 @@ export async function runServe(opts = {}) {
350
400
  handleCancelTurn(frame, { manager });
351
401
  return;
352
402
  }
403
+ if (frame.kind === "stop_tool_call") {
404
+ // Per-tool-call stop: abort ONE hung tool call, keep the turn alive.
405
+ // Fire-and-forget with an internal catch — an unresolved settle must
406
+ // never hang the relay loop (the manager isolates per-call failures).
407
+ void handleStopToolCall(frame, {
408
+ manager,
409
+ }).catch((err) => {
410
+ process.stderr.write(`[serve] stop_tool_call failed: ${err instanceof Error ? err.message : String(err)}\n`);
411
+ });
412
+ return;
413
+ }
353
414
  if (frame.kind === "auto_research") {
354
415
  handleAutoResearchFrame(frame, {
355
416
  store,
@@ -453,6 +514,12 @@ export async function runServe(opts = {}) {
453
514
  process.stdout.write(`Reconnect attempt ${attempt} in ${delayMs}ms\n`);
454
515
  });
455
516
  }
517
+ // Readiness: fires on every successful socket open, including after the
518
+ // auth-failed re-registration below swaps in a fresh RelayClient.
519
+ r.on("open", () => {
520
+ if (serveState)
521
+ announceServeReady();
522
+ });
456
523
  // The `error` listener must be registered regardless of `silent`:
457
524
  // without it, a transport hiccup in silent mode would surface as an
458
525
  // unhandled 'error' event and kill the whole serve process. (RelayClient
@@ -586,10 +653,23 @@ export async function runServe(opts = {}) {
586
653
  catch {
587
654
  // browser extension may not be loaded or already closed
588
655
  }
656
+ // Only clear what we still own: a daemon that lost (or never took) the pid
657
+ // file must not delete the state of the daemon that holds it.
658
+ if (serveState && ownsServeState())
659
+ clearServeState();
589
660
  if (!silent)
590
661
  process.stdout.write("Spectral relay stopped\n");
591
662
  };
592
663
  if (installSignalHandlers) {
664
+ // Bookkeeping cleanup on EVERY exit route. The graceful-shutdown path calls
665
+ // `process.exit()` itself, so `close()` never runs on SIGTERM/SIGINT — and
666
+ // `spectral desktop stop` must not find a stale pid file after a clean
667
+ // shutdown. SIGKILL / crashes still leave a file behind, which readers prune
668
+ // via the liveness check in `getLiveServePid()`.
669
+ process.on("exit", () => {
670
+ if (serveState && ownsServeState())
671
+ clearServeState();
672
+ });
593
673
  // Top-level error nets. A daemon must NOT die from a transient
594
674
  // unhandled rejection (e.g. a fetch promise that lost its `.catch`
595
675
  // when the relay flapped) or a stray throw from a third-party
@@ -716,11 +796,19 @@ async function handleConfigPatch(frame, deps) {
716
796
  }
717
797
  /**
718
798
  * CLI entry point used by `cli.ts`. Surfaces the deprecation warning for
719
- * `--port`/`SPECTRAL_PORT` once, then defers to `runServe`.
799
+ * `--port`/`SPECTRAL_PORT` once, augments PATH for child processes, then defers
800
+ * to `runServe`.
720
801
  */
721
802
  export async function runServeCli(rawArgs) {
722
803
  const parsed = parseServeArgs(rawArgs);
723
804
  const machineName = parsed.machineName ?? process.env.SPECTRAL_MACHINE_NAME;
805
+ // A GUI-launched daemon (LaunchAgent, `.app` helper, `desktop` wrapper)
806
+ // inherits a minimal PATH, which breaks every `npx`-based MCP server and any
807
+ // shell tool that expects node/git. Augment the daemon's own PATH once here so
808
+ // all descendants — in-process AgentBridge shells, dev-process registry, MCP
809
+ // stdio transports — inherit a usable one. Deliberately in the CLI driver and
810
+ // not `runServe()`, so in-process tests never mutate the runner's env.
811
+ applyAugmentedPath();
724
812
  if (parsed.deprecatedPort || process.env.SPECTRAL_PORT) {
725
813
  process.stderr.write(`warning: --port / SPECTRAL_PORT are no longer used. ` +
726
814
  `spectral serve now connects outbound to the Aexol relay; there is no local port to bind.\n`);
@@ -2,16 +2,96 @@
2
2
  * `spectral update` — standalone binary self-update.
3
3
  *
4
4
  * Fetches the latest release manifest from api.aexol.ai, compares versions,
5
- * downloads the new binary, verifies its SHA256 checksum, and atomically
6
- * replaces the running binary on disk.
5
+ * downloads the new artifacts, verifies their SHA256 digests, and installs them
6
+ * over the current installation.
7
7
  *
8
- * Non-standalone install modes (Electron desktop app, npm global) are detected
9
- * and the user is pointed at the correct update path instead.
8
+ * Two manifest shapes are supported:
9
+ *
10
+ * - binary only (every manifest ever published): `url` + `sha256` pin the
11
+ * single-file binary. Only the binary is replaced — the companion assets an
12
+ * `install.sh` user has next to it (`data/systems/`, `mcp/`,
13
+ * `app-bridge.bundle.js`) keep the previous version, which is called out
14
+ * with a warning telling the user to re-run `curl | sh`.
15
+ * - release zip (ADDITIVE `zipUrl` + `zipSha256`, emitted by
16
+ * cli-node/scripts/generate-cli-manifest.sh once scripts/package-standalone.sh
17
+ * produced the archive): the zip carries the binary *and* the
18
+ * `<platform>-data/` companion directory. Both are installed with the same
19
+ * replace-don't-merge semantics as scripts/install.sh, so files deleted
20
+ * between releases do not linger.
21
+ *
22
+ * Nothing is installed unverified: the zip digest is checked before unpacking,
23
+ * the inner binary digest before swapping, and any mismatch aborts without
24
+ * touching the current installation.
25
+ *
26
+ * Non-standalone install modes (npm global install) are detected and the user
27
+ * is pointed at the correct update path instead.
28
+ */
29
+ /** Shape of the per-platform latest release manifest. */
30
+ export interface ReleaseManifest {
31
+ version: string;
32
+ platform: string;
33
+ url: string;
34
+ sha256: string;
35
+ /**
36
+ * Additive fields: manifests published before the release-zip scheme do not
37
+ * have them, so every reader must treat them as optional. When both are
38
+ * present, the release zip (binary + `<platform>-data/` companion assets) can
39
+ * be verified and installed instead of the raw binary alone.
40
+ */
41
+ zipUrl?: string;
42
+ zipSha256?: string;
43
+ }
44
+ /**
45
+ * Spawn a helper process (`unzip`, `tar`) and resolve with its exit code.
46
+ * Rejects when the executable cannot be started at all (ENOENT), which is how
47
+ * callers tell "tool missing" apart from "tool failed".
48
+ */
49
+ export type RunCommand = (cmd: string, args: string[]) => Promise<number>;
50
+ /**
51
+ * Everything I/O-shaped in the update flow, injectable for tests: the flow
52
+ * (verify → unpack → swap → stamp) is then covered without network access, real
53
+ * archives, or a real standalone binary.
54
+ */
55
+ export interface UpdateDeps {
56
+ out?: (t: string) => void;
57
+ err?: (t: string) => void;
58
+ fetchManifest?: (platform: string) => Promise<ReleaseManifest>;
59
+ download?: (url: string, destPath: string) => Promise<void>;
60
+ run?: RunCommand;
61
+ /** Executable to update (defaults to `process.execPath`). */
62
+ execPath?: string;
63
+ /** Current version (defaults to `getVersion()`). */
64
+ version?: string;
65
+ /** Standalone detection (defaults to `isStandaloneBinary()`). */
66
+ standalone?: boolean;
67
+ /** Release platform slug (defaults to `detectPlatform()`). */
68
+ platform?: string | null;
69
+ }
70
+ /**
71
+ * Replace the companion assets next to the binary with the ones from the zip.
72
+ *
73
+ * Semantics are those of scripts/install.sh: the `<platform>-data/` directory is
74
+ * placed next to the binary and *then* its contents are copied alongside it,
75
+ * with the previous `data/`, `mcp/` and `app-bridge.bundle.js` removed first —
76
+ * replace, not merge, so files deleted between releases do not linger.
77
+ *
78
+ * SAFETY: `installDir` is `dirname(process.execPath)` — the directory that
79
+ * *holds* the running binary. Only the explicitly named companion paths inside
80
+ * it are ever removed, and only for a real absolute path, so a bad `execPath`
81
+ * can never wipe a directory that contains the binary.
10
82
  */
83
+ export declare function swapCompanionAssets(params: {
84
+ stageDir: string;
85
+ installDir: string;
86
+ }): Promise<{
87
+ dataDirName: string | null;
88
+ replaced: string[];
89
+ }>;
11
90
  /**
12
91
  * Run the `spectral update` subcommand.
13
92
  *
14
93
  * @param args remaining CLI args after the `update` subcommand
94
+ * @param deps injectable I/O for tests (network, spawns, exec path, version)
15
95
  */
16
- export declare function runUpdate(args: string[]): Promise<void>;
96
+ export declare function runUpdate(args: string[], deps?: UpdateDeps): Promise<void>;
17
97
  //# sourceMappingURL=update.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA2NH;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA8H7D"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AA2BH,yDAAyD;AACzD,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAE1E;;;;GAIG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1B,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,eAAe,CAAC,CAAC;IAC/D,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAwMD;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAwC9D;AA2FD;;;;;GAKG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA4OpF"}