@securecoms/agent-bridge 0.30.1 → 0.30.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -33,6 +33,7 @@ var init_resolve_node = __esm({
33
33
  // src/preflight-upgrade.cts
34
34
  var preflight_upgrade_exports = {};
35
35
  __export(preflight_upgrade_exports, {
36
+ DIST_BASE: () => DIST_BASE,
36
37
  guidedUpgrade: () => guidedUpgrade,
37
38
  parseShasums: () => parseShasums,
38
39
  promptYesNo: () => promptYesNo,
@@ -41,11 +42,10 @@ __export(preflight_upgrade_exports, {
41
42
  sha256Hex: () => sha256Hex
42
43
  });
43
44
  function parseShasums(text, arch) {
44
- const want = "-darwin-" + arch + ".pkg";
45
45
  const lines = String(text).split("\n");
46
46
  for (let i = 0; i < lines.length; i++) {
47
47
  const m = lines[i].trim().match(/^([0-9a-f]{6,64})\s+(\S+)$/);
48
- if (m && m[2].indexOf(want) !== -1 && m[2].indexOf("node-v24.") === 0) {
48
+ if (m && PKG_NAME.test(m[2])) {
49
49
  return { filename: m[2], sha256: m[1] };
50
50
  }
51
51
  }
@@ -62,48 +62,47 @@ async function promptYesNo(question, deps) {
62
62
  }
63
63
  async function guidedUpgrade(deps) {
64
64
  if (deps.platform !== "darwin") return false;
65
+ let consented = false;
66
+ const failed = () => {
67
+ if (consented) deps.stderr("[bridge] Couldn't install Node 24 from nodejs.org.\n");
68
+ return false;
69
+ };
65
70
  try {
66
71
  const existing = deps.existingCompatibleNode();
67
72
  if (existing) {
68
73
  deps.stderr(
69
- "[bridge] Node " + deps.activeVersion + " is running, but a compatible Node (>= " + REQUIRED_NODE_MAJOR + ") is already installed at " + existing + " \u2014 it is shadowed earlier on your PATH. Continuing under it (no install needed).\n"
74
+ "[bridge] Using Node " + REQUIRED_NODE_MAJOR + " or newer found at " + existing + ". (The node command on this computer is an older version.)\n"
70
75
  );
71
76
  return deps.reexec(existing);
72
77
  }
73
- const viaBrew = deps.hasBrew();
74
- const source = viaBrew ? "Homebrew (brew install node \u2014 user-space, no sudo)" : "the official installer from " + DIST_BASE + " (needs your admin password)";
75
78
  const ok = await promptYesNo(
76
- "[bridge] Node 24 LTS is required. Install it now via " + source + "? [y/N] ",
79
+ "[bridge] SecureComs needs Node 24. Install it now from nodejs.org? This needs your computer's administrator password. [y/N] ",
77
80
  deps
78
81
  );
79
82
  if (!ok) return false;
80
- if (viaBrew) {
81
- deps.stderr("[bridge] running: brew install node\n");
82
- if (deps.runBrew() !== 0) return false;
83
- } else {
84
- const shasums = await deps.fetchText(DIST_BASE + "/SHASUMS256.txt");
85
- const entry = parseShasums(shasums, deps.arch);
86
- if (!entry) return false;
87
- const dest = deps.tmpdir() + "/" + entry.filename;
88
- deps.stderr("[bridge] downloading " + DIST_BASE + "/" + entry.filename + "\n");
89
- try {
90
- await deps.fetchBinary(DIST_BASE + "/" + entry.filename, dest);
91
- if (deps.fileSha256(dest) !== entry.sha256) {
92
- deps.stderr("[bridge] checksum mismatch \u2014 aborting install (file discarded)\n");
93
- return false;
94
- }
95
- deps.stderr("[bridge] running: sudo installer -pkg " + entry.filename + " -target /\n");
96
- if (deps.runSudoInstaller(dest) !== 0) return false;
97
- } finally {
98
- deps.cleanup(dest);
83
+ consented = true;
84
+ const shasums = await deps.fetchText(DIST_BASE + "/SHASUMS256.txt");
85
+ const entry = parseShasums(shasums, deps.arch);
86
+ if (!entry) return failed();
87
+ const dest = deps.tmpdir() + "/" + entry.filename;
88
+ deps.stderr("[bridge] downloading " + DIST_BASE + "/" + entry.filename + "\n");
89
+ try {
90
+ await deps.fetchBinary(DIST_BASE + "/" + entry.filename, dest);
91
+ if (deps.fileSha256(dest) !== entry.sha256) {
92
+ deps.stderr("[bridge] checksum mismatch \u2014 aborting install (file discarded)\n");
93
+ return failed();
99
94
  }
95
+ deps.stderr("[bridge] running: sudo installer -pkg " + entry.filename + " -target /\n");
96
+ if (deps.runSudoInstaller(dest) !== 0) return failed();
97
+ } finally {
98
+ deps.cleanup(dest);
100
99
  }
101
100
  const fresh = deps.resolveNewNode();
102
- if (!fresh) return false;
101
+ if (!fresh) return failed();
103
102
  deps.stderr("[bridge] Node 24 installed \u2014 continuing under " + fresh + "\n");
104
103
  return deps.reexec(fresh);
105
104
  } catch {
106
- return false;
105
+ return failed();
107
106
  }
108
107
  }
109
108
  function resolveNewNodeFrom(probe, candidates) {
@@ -152,11 +151,6 @@ function realUpgradeDeps(originalArgv) {
152
151
  resolve(a);
153
152
  });
154
153
  }),
155
- hasBrew: () => spawnSync("brew", ["--version"], { stdio: "ignore" }).status === 0,
156
- runBrew: () => {
157
- var _a;
158
- return (_a = spawnSync("brew", ["install", "node"], { stdio: "inherit" }).status) != null ? _a : 1;
159
- },
160
154
  fetchText: async (url) => {
161
155
  const res = await fetch(url, 3);
162
156
  let out = "";
@@ -197,12 +191,13 @@ function realUpgradeDeps(originalArgv) {
197
191
  }
198
192
  };
199
193
  }
200
- var DIST_BASE, NODE_CANDIDATES;
194
+ var DIST_BASE, PKG_NAME, NODE_CANDIDATES;
201
195
  var init_preflight_upgrade = __esm({
202
196
  "src/preflight-upgrade.cts"() {
203
197
  "use strict";
204
198
  init_resolve_node();
205
199
  DIST_BASE = "https://nodejs.org/dist/latest-v24.x";
200
+ PKG_NAME = /^node-v24\.\d+\.\d+\.pkg$/;
206
201
  NODE_CANDIDATES = [
207
202
  "/usr/local/bin/node",
208
203
  // nodejs.org pkg (stable across upgrades)
@@ -216,6 +211,7 @@ var init_preflight_upgrade = __esm({
216
211
  // src/preflight.cts
217
212
  var preflight_exports = {};
218
213
  __export(preflight_exports, {
214
+ NODE_FLOOR: () => NODE_FLOOR,
219
215
  effectiveVersion: () => effectiveVersion,
220
216
  instructionsBlock: () => instructionsBlock,
221
217
  meetsFloor: () => meetsFloor,
@@ -224,7 +220,6 @@ __export(preflight_exports, {
224
220
  });
225
221
  module.exports = __toCommonJS(preflight_exports);
226
222
  var NODE_FLOOR = 24;
227
- var FLOOR_REASON = "requires >= 24 (node:sqlite stable API)";
228
223
  function parseNodeMajor(version) {
229
224
  const n = Number(String(version).split(".")[0]);
230
225
  return Number.isFinite(n) && n > 0 ? n : 0;
@@ -239,23 +234,30 @@ function effectiveVersion(real, faked) {
239
234
  return real;
240
235
  }
241
236
  function instructionsBlock(platform, current) {
242
- const lines = [
243
- "[bridge] Node " + current + " is too old \u2014 SecureComs " + FLOOR_REASON + ".",
244
- "",
245
- "How to get Node 24 LTS:",
246
- " 1. Official installer (recommended): https://nodejs.org \u2014 download the",
247
- " Node 24 LTS installer for your platform and run it."
248
- ];
237
+ const n = String(NODE_FLOOR);
238
+ const head = "[bridge] This computer has Node " + current + ". SecureComs needs Node " + n + " or newer.";
239
+ let lines;
249
240
  if (platform === "darwin") {
250
- lines.push(" 2. Homebrew: brew install node");
241
+ lines = [
242
+ head,
243
+ "",
244
+ "To get Node " + n + ":",
245
+ " 1. Download the Node " + n + " LTS installer for macOS from https://nodejs.org and run it.",
246
+ " 2. Run the SecureComs install command again."
247
+ ];
248
+ } else if (platform === "win32") {
249
+ lines = [
250
+ head,
251
+ "",
252
+ "Install Node " + n + " from https://nodejs.org, then run the SecureComs install command again."
253
+ ];
254
+ } else {
255
+ lines = [
256
+ head,
257
+ "",
258
+ "Install Node " + n + " so that it is at /usr/local/bin/node or /usr/bin/node, then run the SecureComs install command again. See https://nodejs.org for options."
259
+ ];
251
260
  }
252
- lines.push(" " + (platform === "darwin" ? "3" : "2") + ". nvm: nvm install 24 && nvm use 24");
253
- lines.push(
254
- "",
255
- "Then re-run the install command. (Always re-run the install command after",
256
- "upgrading Node \u2014 the background service pins the Node path it was",
257
- "installed with.)"
258
- );
259
261
  return lines.join("\n") + "\n";
260
262
  }
261
263
  async function runPreflight(deps) {
@@ -292,6 +294,7 @@ if (require.main === module) {
292
294
  }
293
295
  // Annotate the CommonJS export names for ESM import in node:
294
296
  0 && (module.exports = {
297
+ NODE_FLOOR,
295
298
  effectiveVersion,
296
299
  instructionsBlock,
297
300
  meetsFloor,
@@ -1,4 +1,18 @@
1
1
  #!/usr/bin/env node
2
+ /**
3
+ * CommonJS preflight shim — the package's bin entry. CJS on purpose: any
4
+ * Node back to v10 can parse it, so a machine with stale Node always gets
5
+ * the friendly diagnosis instead of an ESM/builtin crash (static imports in
6
+ * the ESM bundle hoist — node:sqlite would detonate before any guard ran).
7
+ * Built with esbuild format=cjs target=node10 to dist/preflight.cjs.
8
+ *
9
+ * AUDIT C1: this file must contain ZERO dynamic `import()` — esbuild's
10
+ * node10 downlevel would turn it into require() (cannot load ESM), and
11
+ * keeping the syntax breaks node10 parse. The real import lives in
12
+ * preflight-modern.cts, which is only require()d AFTER the gate passes.
13
+ * An artifact test greps the emitted file to pin this.
14
+ */
15
+ export declare const NODE_FLOOR = 24;
2
16
  export declare function parseNodeMajor(version: string): number;
3
17
  export declare function meetsFloor(version: string): boolean;
4
18
  export declare function effectiveVersion(real: string, faked: string | undefined): string;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * How `--credential` is read for `install` and run mode (spec 2026-10-15
3
+ * §5.3, OQ-18 (b)). A flag that is present with an empty value means "no key
4
+ * file": it never falls back to SECURECOMS_CREDENTIAL, so a copied command
5
+ * whose Downloads lookup found nothing cannot silently pick up a different
6
+ * agent's key file from the environment. The variable is used only when the
7
+ * flag is absent. Every other flag keeps argOrEnv's behaviour.
8
+ */
9
+ export type CredentialArg = {
10
+ kind: "path";
11
+ path: string;
12
+ } | {
13
+ kind: "empty_flag";
14
+ } | {
15
+ kind: "absent";
16
+ };
17
+ export declare function readCredentialArg(argv: string[], env: NodeJS.ProcessEnv): CredentialArg;
18
+ /**
19
+ * The one line printed when no key file was given: E8 for run mode
20
+ * (approved), E9 for install (DRAFT: the approved E9 names the agent, which
21
+ * the bridge cannot know when no key file was found).
22
+ */
23
+ export declare function noCredentialLine(verb: "run" | "install"): string;
@@ -13,7 +13,14 @@ export interface ServiceDeps {
13
13
  mkdirp: (path: string) => void;
14
14
  fileExists: (path: string) => boolean;
15
15
  user: string;
16
+ /** kill(pid, 0): true while the process runs (EPERM counts as running). */
17
+ pidAlive: (pid: number) => boolean;
18
+ /** Blocking sleep: installService is synchronous end to end. */
19
+ sleepMs: (ms: number) => void;
20
+ now: () => number;
16
21
  }
22
+ /** How long install waits for the previous bridge to exit after bootout. */
23
+ export declare const PREVIOUS_EXIT_WAIT_MS = 10000;
17
24
  export interface InstallResult {
18
25
  label: string;
19
26
  filePath: string;
@@ -7,6 +7,7 @@ export interface ResolveNodeDeps {
7
7
  arch: () => string;
8
8
  archOf: (p: string) => string | null;
9
9
  }
10
+ export declare const STABLE_LOCATIONS: readonly string[];
10
11
  export declare function resolveStableNodePath(runningExecPath: string, deps: ResolveNodeDeps): {
11
12
  path: string;
12
13
  stable: boolean;
@@ -49,6 +49,10 @@ export interface LocalReport {
49
49
  persona: Record<string, string>;
50
50
  has_search_key: boolean;
51
51
  has_llm_key: boolean;
52
+ /** L-2 (spec §7.9): a readable key for an extract-capable provider. Only a real true counts; absent is false. */
53
+ has_extract_provider: boolean;
54
+ /** D39: the owner-DM daily search cap the runtime enforces; an integer in [0, 2000], otherwise undefined. */
55
+ owner_dm_search_cap_effective?: number;
52
56
  legacy_memory: LegacyMemoryReport[];
53
57
  /** §B.4 counts; undefined when the runtime reported none or the block was malformed. */
54
58
  secret_paths?: SecretPathsReport;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const BRIDGE_VERSION = "0.30.1";
1
+ export declare const BRIDGE_VERSION = "0.30.3";
@@ -51,7 +51,7 @@ export declare const MEMORY_UNIFIED_FEATURE = "memory_unified";
51
51
  * fake against this list at run time (7b gate fix: a member added here without
52
52
  * a fake made three tests throw "is not a function").
53
53
  */
54
- export declare const WS_AGENT_MEMBERS: readonly ["ackRuntimeMessages", "action", "admitRuntimeDelivery", "applyMemoryNote", "clearHarnessReport", "clearManifestConsumer", "clearPerToolConsumer", "harnessGrantsWithheld", "isRuntimeMessageRetired", "noteConsumerCapability", "noteManifestConsumer", "noteRoomCapReached", "noteNotesConsumer", "notePerToolConsumer", "noteRecallConsumer", "noteUnifiedConsumer", "noteSessionClose", "noteSessionEvicted", "noteSessionOpen", "notesAppliedGeneration", "notesForDelivery", "recallForDelivery", "unifiedFeatureOn", "unifiedForDelivery", "recordHarnessReport", "recordRuntimeReply", "reportStatusGated", "requeueFailedRuntimeDeliveries", "requeueFront", "runtimeReplyReceipt", "send", "sendA2A", "subscribe", "takeDeliverable", "wakeListeners"];
54
+ export declare const WS_AGENT_MEMBERS: readonly ["ackRuntimeMessages", "action", "admitRuntimeDelivery", "applyMemoryNote", "clearHarnessReport", "clearManifestConsumer", "clearPerToolConsumer", "clearSearchProvidersSocket", "harnessGrantsWithheld", "signedSearchProvider", "isRuntimeMessageRetired", "noteConsumerCapability", "noteManifestConsumer", "noteRoomCapReached", "noteSearchProvidersSocket", "noteNotesConsumer", "notePerToolConsumer", "noteRecallConsumer", "noteUnifiedConsumer", "noteSessionClose", "noteSessionEvicted", "noteSessionOpen", "notesAppliedGeneration", "notesForDelivery", "recallForDelivery", "unifiedFeatureOn", "unifiedForDelivery", "recordHarnessReport", "recordRuntimeReply", "reportStatusGated", "requeueFailedRuntimeDeliveries", "requeueFront", "runtimeReplyReceipt", "send", "sendA2A", "subscribe", "takeDeliverable", "wakeListeners"];
55
55
  export type WsAgent = Pick<BridgeAgent, (typeof WS_AGENT_MEMBERS)[number]>;
56
56
  export declare function attachAgentWebSocket(server: HttpServer, agent: WsAgent, opts: AgentWebSocketOptions): {
57
57
  close(): void;
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@securecoms/agent-bridge",
3
- "version": "0.30.1",
3
+ "version": "0.30.3",
4
4
  "type": "module",
5
5
  "engines": {
6
- "node": ">=22.5.0"
6
+ "node": ">=24"
7
7
  },
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",