glimmervoid 0.30.0 → 0.31.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 (66) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/glimmervoid.js +140 -57
  3. package/dist/chunks/{adapters-Dho1VSY5.js → adapters-ClA_GbtA.js} +1 -1
  4. package/dist/chunks/{adapters-zPDx1Xox.js → adapters-gn7ulNO4.js} +32 -12
  5. package/dist/chunks/agent-api-cli-DAA7Jx8N.js +135 -0
  6. package/dist/chunks/{agent-api-core-Dz0r21y9.js → agent-api-core-hVcT26JW.js} +10 -1
  7. package/dist/chunks/{agent-setup-cli-B5Atxr3F.js → agent-setup-cli-CiJSDWSo.js} +11 -28
  8. package/dist/chunks/backoff-DjVpfHk7.js +14 -0
  9. package/dist/chunks/child-process-safe-BKPZ-5qQ.js +2 -0
  10. package/dist/chunks/coerce-NSst8oRP.js +32 -0
  11. package/dist/chunks/{contracts-DGkKNh9W.js → config-W1Sv-iPK.js} +358 -1682
  12. package/dist/chunks/{config-store-mm7MgzoL.js → config-store-BCy4FHNG.js} +583 -327
  13. package/dist/chunks/config-store-DbBp7LJZ.js +2 -0
  14. package/dist/chunks/contracts-3LkrilQX.js +2078 -0
  15. package/dist/chunks/{grok-DuU8xVLZ.js → grok-CXKeSt2z.js} +24 -20
  16. package/dist/chunks/{hook-relay-core-BHfYFnYV.js → hook-relay-core-DA_bz2KA.js} +10 -5
  17. package/dist/chunks/{hook-tools-pSJia7ks.js → hook-tools-UX2fmt81.js} +3 -5
  18. package/dist/chunks/{ingest-editor-core-BuI1gMF_.js → ingest-editor-core-vR6Wv6bP.js} +24 -13
  19. package/dist/chunks/json-core-dfa_7Fak.js +23 -0
  20. package/dist/chunks/json-file-oEH9vt-0.js +352 -0
  21. package/dist/chunks/knowledge-graph-cli-D2tt5hPn.js +1354 -0
  22. package/dist/chunks/{loopback-post-C7C22eYi.js → loopback-post-DepQfdcM.js} +40 -26
  23. package/dist/chunks/{main-CuIZQPhZ.js → main-DyTCWIu2.js} +28498 -21129
  24. package/dist/chunks/{node-pty-preflight-CK1knGIR.js → node-pty-preflight-C8QIlrtU.js} +4 -6
  25. package/dist/chunks/{pair-cli-w-gCAF-1.js → pair-cli-BbCBfd6l.js} +4 -3
  26. package/dist/chunks/paths-CeJl2Vcg.js +55 -0
  27. package/dist/chunks/{remote-config-C2ytQwrs.js → remote-config-DKIH_VxM.js} +36 -40
  28. package/dist/chunks/{rtk-hook-core-Bl6gYHPN.js → rtk-hook-core-BmEz2aq9.js} +3 -5
  29. package/dist/chunks/{rtk-resolver-CLo-gZzw.js → rtk-resolver-BGDzw5XK.js} +2 -2
  30. package/dist/chunks/rtk-resolver-D4Nke1Fr.js +2 -0
  31. package/dist/chunks/{runtime-paths-Ci_ksSkj.js → runtime-paths-BPoxENmK.js} +2 -6
  32. package/dist/chunks/runtime-paths-DU5jBEEO.js +2 -0
  33. package/dist/chunks/{sandbox-deps-Dd5-kZnf.js → sandbox-deps-BPKE-ylr.js} +16 -13
  34. package/dist/chunks/sandbox-proxy-core-hnQgKR0T.js +27 -0
  35. package/dist/chunks/{session-Cez8aIWg.js → session-fc4pFbon.js} +8 -2
  36. package/dist/chunks/text-DoirglWV.js +21 -0
  37. package/dist/chunks/timer-deps-u2DAQLok.js +15 -0
  38. package/dist/chunks/{visions-cli-BXQFIBCX.js → visions-cli-CT5rjiwf.js} +1 -1
  39. package/dist/chunks/{visions-setup-CvVnOe1r.js → visions-setup-BmOkI-QE.js} +20 -357
  40. package/dist/client/assets/index-C6KD8lgZ.css +1 -0
  41. package/dist/client/assets/index-CThQEAEy.js +249 -0
  42. package/dist/client/fonts/CommitMono-OFL.txt +92 -0
  43. package/dist/client/fonts/commit-mono-400-italic.woff2 +0 -0
  44. package/dist/client/fonts/commit-mono-400-regular.woff2 +0 -0
  45. package/dist/client/fonts/commit-mono-700-italic.woff2 +0 -0
  46. package/dist/client/fonts/commit-mono-700-regular.woff2 +0 -0
  47. package/dist/client/index.html +7 -24
  48. package/dist/client/octicons-LICENSE.txt +21 -0
  49. package/dist/scripts/postinstall-path-check.js +1 -1
  50. package/dist/server/index.js +3 -3
  51. package/dist/session/command-hook-relay.js +1 -1
  52. package/dist/session/hook-relay.js +3 -3
  53. package/dist/session/hook-tool-relay.js +2 -2
  54. package/dist/session/sandbox-open-launcher.js +79 -0
  55. package/dist/session/statusline-relay.js +8 -18
  56. package/dist/session/visions-relay.js +20 -11
  57. package/package.json +4 -1
  58. package/dist/chunks/agent-api-cli-D0MmtEdz.js +0 -71
  59. package/dist/chunks/child-process-safe-DvQjXsgz.js +0 -2
  60. package/dist/chunks/config-store-CC8T3okC.js +0 -2
  61. package/dist/chunks/ingest-core-DWI1Mbu4.js +0 -342
  62. package/dist/chunks/rtk-resolver-CMQAidlI.js +0 -2
  63. package/dist/chunks/runtime-paths-JLrZ3wyi.js +0 -2
  64. package/dist/client/assets/index-B1MFijjb.css +0 -1
  65. package/dist/client/assets/index-CU1iPPdn.js +0 -249
  66. package/dist/chunks/{child-process-safe-DRGsp0TE.js → child-process-safe-Ch-Zgxqs.js} +1 -1
package/README.md CHANGED
@@ -57,7 +57,7 @@ Update a clone with `git pull --ff-only && npm ci && npm run build`, then restar
57
57
  - **Claude Code CLI** on PATH, or another supported agent below.
58
58
  - **git** on PATH, for per-session worktrees.
59
59
  - **Linux only:** `build-essential` and `python3` for node-pty.
60
- - **Linux only:** `bubblewrap` (`bwrap`) and `socat` for Claude Code's sandbox, which team review, Keep mergeable, workflow sessions and benchmark runs use (`sudo apt install bubblewrap socat`). `glimmervoid doctor` reports both.
60
+ - **Linux only:** `bubblewrap` (`bwrap`), `socat` and `ripgrep` (`rg`) for the sandbox that sandboxed sessions and factory checks run in (`sudo apt install bubblewrap socat ripgrep`). `glimmervoid doctor` reports all three.
61
61
 
62
62
  ## Supported agents
63
63
 
@@ -1,15 +1,93 @@
1
1
  #!/usr/bin/env node
2
- import { o as nodePtyRebuildHint, t as probeNodePty } from "../chunks/node-pty-preflight-CK1knGIR.js";
3
- import { a as packageRoot } from "../chunks/runtime-paths-Ci_ksSkj.js";
4
- import { t as AGENT_API_VERBS } from "../chunks/session-Cez8aIWg.js";
5
- import { i as execSync } from "../chunks/child-process-safe-DRGsp0TE.js";
2
+ import { o as nodePtyRebuildHint, r as firstLine, t as probeNodePty } from "../chunks/node-pty-preflight-C8QIlrtU.js";
3
+ import { i as errorText } from "../chunks/text-DoirglWV.js";
4
+ import { a as packageRoot } from "../chunks/runtime-paths-BPoxENmK.js";
5
+ import { t as AGENT_API_VERBS } from "../chunks/session-fc4pFbon.js";
6
+ import { i as execSync } from "../chunks/child-process-safe-Ch-Zgxqs.js";
6
7
  import { t as renderTable } from "../chunks/ascii-figure-core-pDAwtlKO.js";
7
8
  import { n as glimmervoidHomeDir, t as decideConfigPath } from "../chunks/config-path-core-DFt-TemS.js";
8
- import { i as sandboxDoctorRows, r as probeSandboxDependencies } from "../chunks/sandbox-deps-Dd5-kZnf.js";
9
+ import { i as sandboxDoctorRows, r as probeSandboxDependencies } from "../chunks/sandbox-deps-BPKE-ylr.js";
9
10
  import { i as pnpmGlobalBinDir, n as npmGlobalBinDir, r as onPath, t as formatPathNotice } from "../chunks/path-doctor-C23VAqeu.js";
10
11
  import fs from "node:fs";
11
12
  import path from "node:path";
12
13
  import os from "node:os";
14
+ //#region server/core/command-line-core.ts
15
+ var SUBCOMMANDS_HONORING_TRAILING_GLOBAL_OPTIONS = /* @__PURE__ */ new Set([
16
+ "doctor",
17
+ "pair",
18
+ "visions"
19
+ ]);
20
+ var SUBCOMMANDS_HONORING_A_LEADING_HELP_OR_VERSION = new Set(AGENT_API_VERBS);
21
+ var OPTIONS_TAKING_A_VALUE = {
22
+ "--config": "configPath",
23
+ "--port": "port"
24
+ };
25
+ function scanGlobalOption(argv, index, state) {
26
+ const token = argv[index];
27
+ const valueKey = OPTIONS_TAKING_A_VALUE[token];
28
+ if (valueKey) {
29
+ const value = argv[index + 1];
30
+ if (value !== void 0) state[valueKey] = value;
31
+ return index + 2;
32
+ }
33
+ if (token === "--help" || token === "-h") state.wantsHelp = true;
34
+ if (token === "--version") state.wantsVersion = true;
35
+ if (token === "--doctor") state.wantsDoctor = true;
36
+ return index + 1;
37
+ }
38
+ function scanTrailingGlobalOptions(subcommandArgs, state) {
39
+ let index = 0;
40
+ while (index < subcommandArgs.length) {
41
+ if (!subcommandArgs[index].startsWith("-")) {
42
+ index += 1;
43
+ continue;
44
+ }
45
+ index = scanGlobalOption(subcommandArgs, index, state);
46
+ }
47
+ }
48
+ function scanLeadingHelpOrVersion(subcommandArgs, state) {
49
+ const firstArgument = subcommandArgs[0];
50
+ if (firstArgument === "--help" || firstArgument === "-h") state.wantsHelp = true;
51
+ if (firstArgument === "--version") state.wantsVersion = true;
52
+ }
53
+ function parseCommandLine(argv) {
54
+ const state = {
55
+ configPath: null,
56
+ port: null,
57
+ wantsHelp: false,
58
+ wantsVersion: false,
59
+ wantsDoctor: false
60
+ };
61
+ let index = 0;
62
+ while (index < argv.length && argv[index].startsWith("-")) index = scanGlobalOption(argv, index, state);
63
+ const name = argv[index];
64
+ const subcommandArgs = argv.slice(index + 1);
65
+ if (name !== void 0 && SUBCOMMANDS_HONORING_TRAILING_GLOBAL_OPTIONS.has(name)) scanTrailingGlobalOptions(subcommandArgs, state);
66
+ if (name !== void 0 && SUBCOMMANDS_HONORING_A_LEADING_HELP_OR_VERSION.has(name)) scanLeadingHelpOrVersion(subcommandArgs, state);
67
+ if (state.wantsHelp) return { kind: "help" };
68
+ if (state.wantsVersion) return { kind: "version" };
69
+ const globalOptions = {
70
+ configPath: state.configPath,
71
+ port: state.port
72
+ };
73
+ if (state.wantsDoctor) return {
74
+ kind: "subcommand",
75
+ name: "doctor",
76
+ subcommandArgs: [],
77
+ globalOptions
78
+ };
79
+ if (name === void 0) return {
80
+ kind: "server",
81
+ globalOptions
82
+ };
83
+ return {
84
+ kind: "subcommand",
85
+ name,
86
+ subcommandArgs,
87
+ globalOptions
88
+ };
89
+ }
90
+ //#endregion
13
91
  //#region bin/glimmervoid.ts
14
92
  var args = process.argv.slice(2);
15
93
  var pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, "package.json"), "utf8"));
@@ -28,6 +106,7 @@ Commands:
28
106
  spawn <prompt> From inside a Glimmervoid session, start a sibling session on that prompt
29
107
  attention <note> From inside a Glimmervoid session, flag it as needing the operator
30
108
  board From inside a Glimmervoid session, list the live sessions
109
+ kg [command] Experimental typed knowledge and task graph (Settings > Lanes > Knowledge graph)
31
110
 
32
111
  Options:
33
112
  --name <label> Label for the device being paired (with: pair)
@@ -35,71 +114,75 @@ Options:
35
114
  --config <path> Path to config file (default: ~/.glimmervoid/config.json)
36
115
  --version Show version number
37
116
  --help, -h Show this help message`;
38
- if (args.includes("--help") || args.includes("-h")) {
117
+ var commandLine = parseCommandLine(args);
118
+ if (commandLine.kind === "help") {
39
119
  console.log(USAGE);
40
120
  process.exit(0);
41
121
  }
42
- if (args.includes("--version")) {
122
+ if (commandLine.kind === "version") {
43
123
  console.log(pkg.version);
44
124
  process.exit(0);
45
125
  }
46
- function getArgValue(flag) {
47
- const idx = args.indexOf(flag);
48
- if (idx !== -1 && idx + 1 < args.length) return args[idx + 1];
49
- return null;
50
- }
51
- var configArg = getArgValue("--config");
52
- if (configArg) process.env.GLIMMERVOID_CONFIG = configArg;
53
- var portArg = getArgValue("--port");
54
- if (portArg) process.env.GLIMMERVOID_PORT = portArg;
126
+ if (commandLine.globalOptions.configPath) process.env.GLIMMERVOID_CONFIG = commandLine.globalOptions.configPath;
127
+ if (commandLine.globalOptions.port) process.env.GLIMMERVOID_PORT = commandLine.globalOptions.port;
55
128
  var SUBCOMMAND_RUNNERS = new Map([
56
129
  ["doctor", async () => {
57
130
  await runDoctor();
58
131
  return 0;
59
132
  }],
60
- ["pair", async (commandArgs) => {
61
- const { runPairCli } = await import("../chunks/pair-cli-w-gCAF-1.js");
62
- return runPairCli(commandArgs.slice(1));
133
+ ["pair", async (subcommandArgs) => {
134
+ const { runPairCli } = await import("../chunks/pair-cli-BbCBfd6l.js");
135
+ return runPairCli(subcommandArgs);
136
+ }],
137
+ ["agent", async (subcommandArgs) => {
138
+ const { runAgentSetupCli } = await import("../chunks/agent-setup-cli-CiJSDWSo.js");
139
+ return runAgentSetupCli(subcommandArgs);
63
140
  }],
64
- ["agent", async (commandArgs) => {
65
- const { runAgentSetupCli } = await import("../chunks/agent-setup-cli-B5Atxr3F.js");
66
- return runAgentSetupCli(commandArgs.slice(1));
141
+ ["kg", async (subcommandArgs) => {
142
+ const { runKnowledgeGraphCommand } = await import("../chunks/knowledge-graph-cli-D2tt5hPn.js");
143
+ return runKnowledgeGraphCommand(subcommandArgs);
67
144
  }],
68
- ["visions", async (commandArgs) => {
69
- const { runVisionsCli } = await import("../chunks/visions-cli-BXQFIBCX.js");
70
- return runVisionsCli(commandArgs.slice(1));
145
+ ["visions", async (subcommandArgs) => {
146
+ const { runVisionsCli } = await import("../chunks/visions-cli-CT5rjiwf.js");
147
+ return runVisionsCli(subcommandArgs);
71
148
  }],
72
- ...AGENT_API_VERBS.map((verb) => [verb, async (commandArgs) => {
73
- const { runAgentApiCli } = await import("../chunks/agent-api-cli-D0MmtEdz.js");
74
- return runAgentApiCli(commandArgs);
149
+ ...AGENT_API_VERBS.map((verb) => [verb, async (subcommandArgs, subcommandName) => {
150
+ const { runAgentApiCli } = await import("../chunks/agent-api-cli-DAA7Jx8N.js");
151
+ return runAgentApiCli([subcommandName, ...subcommandArgs]);
75
152
  }])
76
153
  ]);
154
+ function flushStream(stream) {
155
+ return new Promise((resolve) => {
156
+ stream.once("error", () => resolve());
157
+ stream.write("", () => resolve());
158
+ });
159
+ }
160
+ async function exitAfterOutputDrains(exitCode) {
161
+ await Promise.all([flushStream(process.stdout), flushStream(process.stderr)]);
162
+ process.exit(exitCode);
163
+ }
164
+ async function runSubcommandToExitCode(runSubcommand, subcommandArgs, subcommandName) {
165
+ try {
166
+ return await runSubcommand(subcommandArgs, subcommandName);
167
+ } catch (err) {
168
+ console.error(errorText(err));
169
+ return 1;
170
+ }
171
+ }
77
172
  async function dispatchCommandLine() {
78
- const requestedSubcommand = args.includes("--doctor") ? "doctor" : args[0];
79
- if (!requestedSubcommand || requestedSubcommand.startsWith("-")) {
173
+ if (commandLine.kind !== "subcommand") {
80
174
  await import("../server/index.js");
81
175
  return;
82
176
  }
83
- const runSubcommand = SUBCOMMAND_RUNNERS.get(requestedSubcommand);
177
+ const runSubcommand = SUBCOMMAND_RUNNERS.get(commandLine.name);
84
178
  if (!runSubcommand) {
85
- console.error(`Unknown command: ${requestedSubcommand}\n${USAGE}`);
86
- process.exit(1);
87
- }
88
- try {
89
- process.exit(await runSubcommand(args));
90
- } catch (err) {
91
- console.error(messageOf(err));
92
- process.exit(1);
179
+ console.error(`Unknown command: ${commandLine.name}\n${USAGE}`);
180
+ await exitAfterOutputDrains(1);
181
+ return;
93
182
  }
183
+ await exitAfterOutputDrains(await runSubcommandToExitCode(runSubcommand, commandLine.subcommandArgs, commandLine.name));
94
184
  }
95
185
  await dispatchCommandLine();
96
- function messageOf(error) {
97
- if (error instanceof Error && error.message) return error.message;
98
- return String(error);
99
- }
100
- function firstLineOf(error) {
101
- return messageOf(error).split("\n")[0];
102
- }
103
186
  function decideReadOnlyConfigPath() {
104
187
  return decideConfigPath({
105
188
  env: process.env,
@@ -118,7 +201,7 @@ async function readDeclaredCustomAgents() {
118
201
  declared: [],
119
202
  error: null
120
203
  };
121
- const { loadConfigFile } = await import("../chunks/config-store-CC8T3okC.js");
204
+ const { loadConfigFile } = await import("../chunks/config-store-DbBp7LJZ.js");
122
205
  try {
123
206
  const loaded = loadConfigFile(decided.path, { exitOnError: false });
124
207
  if (!loaded.config) return {
@@ -132,7 +215,7 @@ async function readDeclaredCustomAgents() {
132
215
  } catch (err) {
133
216
  return {
134
217
  declared: [],
135
- error: `could not read ${decided.path}: ${firstLineOf(err)}`
218
+ error: `could not read ${decided.path}: ${firstLine(errorText(err))}`
136
219
  };
137
220
  }
138
221
  }
@@ -194,7 +277,7 @@ async function runDoctor() {
194
277
  }
195
278
  switchSection("Agents");
196
279
  try {
197
- const { listAgentIds, describeAgentResolvability, setCustomAgents } = await import("../chunks/adapters-Dho1VSY5.js");
280
+ const { listAgentIds, describeAgentResolvability, setCustomAgents } = await import("../chunks/adapters-ClA_GbtA.js");
198
281
  const declaredCustomAgents = await readDeclaredCustomAgents();
199
282
  if (declaredCustomAgents.error) line("config", declaredCustomAgents.error);
200
283
  setCustomAgents(declaredCustomAgents.declared);
@@ -202,24 +285,24 @@ async function runDoctor() {
202
285
  const { label, path: resolvedPath } = describeAgentResolvability(id);
203
286
  line(`${id} (${label})`, resolvedPath ?? "not found on PATH");
204
287
  }
205
- const { inspectGrokAgentSetup } = await import("../chunks/agent-setup-cli-B5Atxr3F.js");
288
+ const { inspectGrokAgentSetup } = await import("../chunks/agent-setup-cli-CiJSDWSo.js");
206
289
  const grokSetup = inspectGrokAgentSetup();
207
290
  line("grok hook setup", `${grokSetup.classification}: ${grokSetup.filePath}`);
208
291
  } catch (err) {
209
- line("agents", `probe failed: ${firstLineOf(err)}`);
292
+ line("agents", `probe failed: ${firstLine(errorText(err))}`);
210
293
  }
211
294
  switchSection("rtk");
212
295
  try {
213
- const { getRtkPath } = await import("../chunks/rtk-resolver-CMQAidlI.js");
296
+ const { getRtkPath } = await import("../chunks/rtk-resolver-D4Nke1Fr.js");
214
297
  line("rtk", getRtkPath() || "not installed (Glimmervoid installs it when the rtk setting is on)");
215
298
  } catch (err) {
216
- line("rtk", `probe failed: ${firstLineOf(err)}`);
299
+ line("rtk", `probe failed: ${firstLine(errorText(err))}`);
217
300
  }
218
301
  switchSection("Sane YOLO");
219
302
  try {
220
- const { resolvePackageBin } = await import("../chunks/runtime-paths-JLrZ3wyi.js");
221
- const { execFileSync } = await import("../chunks/child-process-safe-DvQjXsgz.js");
222
- const { inspectGrokAgentSetup } = await import("../chunks/agent-setup-cli-B5Atxr3F.js");
303
+ const { resolvePackageBin } = await import("../chunks/runtime-paths-DU5jBEEO.js");
304
+ const { execFileSync } = await import("../chunks/child-process-safe-BKPZ-5qQ.js");
305
+ const { inspectGrokAgentSetup } = await import("../chunks/agent-setup-cli-CiJSDWSo.js");
223
306
  const binPath = resolvePackageBin("cc-safety-net", "cc-safety-net");
224
307
  line("Sane YOLO", binPath || "not installed");
225
308
  if (binPath) line("cc-safety-net version", execFileSync(process.execPath, [binPath, "--version"], {
@@ -229,7 +312,7 @@ async function runDoctor() {
229
312
  line("Codex hook trust", "Sane YOLO is inactive unless Codex trusts the injected hooks.");
230
313
  line("Grok Sane YOLO", inspectGrokAgentSetup().saneYoloReady ? "installed" : "inactive; run glimmervoid agent setup grok");
231
314
  } catch (err) {
232
- line("Sane YOLO", `probe failed: ${firstLineOf(err)}`);
315
+ line("Sane YOLO", `probe failed: ${firstLine(errorText(err))}`);
233
316
  }
234
317
  switchSection("Native module");
235
318
  const nodePty = await probeNodePty();
@@ -1,2 +1,2 @@
1
- import { a as describeAgentResolvability, d as setCustomAgents, l as listAgentIds } from "./adapters-zPDx1Xox.js";
1
+ import { a as describeAgentResolvability, d as setCustomAgents, l as listAgentIds } from "./adapters-gn7ulNO4.js";
2
2
  export { describeAgentResolvability, listAgentIds, setCustomAgents };
@@ -1,11 +1,12 @@
1
- import { o as relayPath } from "./runtime-paths-Ci_ksSkj.js";
2
- import { _ as toolDetailFieldValue, c as PendingPromptQuestion, g as firstDetailLine, o as PROMPT_DETAIL_HIDDEN_CHARACTERS } from "./session-Cez8aIWg.js";
3
- import { r as execFileSync } from "./child-process-safe-DRGsp0TE.js";
1
+ import { o as relayPath } from "./runtime-paths-BPoxENmK.js";
2
+ import { _ as firstDetailLine, l as PendingPromptQuestion, s as PROMPT_DETAIL_HIDDEN_CHARACTERS, v as toolDetailFieldValue } from "./session-fc4pFbon.js";
3
+ import { r as execFileSync } from "./child-process-safe-Ch-Zgxqs.js";
4
4
  import { n as resolveAgentCommand, t as buildAgentSpawnCommand } from "./spawn-command-Cc40FiZI.js";
5
- import { i as isSpinnerChar, n as classifyAgentTitle, r as isBrailleChar, s as buildAgentEnv, t as grok } from "./grok-DuU8xVLZ.js";
5
+ import { n as isRecord } from "./coerce-NSst8oRP.js";
6
+ import { c as buildAgentEnv, i as isSpinnerChar, n as classifyAgentTitle, r as isBrailleChar, t as grok } from "./grok-CXKeSt2z.js";
6
7
  import { t as buildHookCommand } from "./hook-command-core-DclEoE9e.js";
7
- import "./contracts-DGkKNh9W.js";
8
- import { n as mergeCodexPreToolUse, t as HOOK_TOOLS } from "./hook-tools-pSJia7ks.js";
8
+ import "./contracts-3LkrilQX.js";
9
+ import { n as mergeCodexPreToolUse, t as HOOK_TOOLS } from "./hook-tools-UX2fmt81.js";
9
10
  import fs from "node:fs";
10
11
  //#region session/core/anti-slop-prompt.ts
11
12
  var ANTI_SLOP_NOTE = [
@@ -87,9 +88,6 @@ function mapHookPromptDetail(event, payload) {
87
88
  question: answerableQuestionOf(toolName, payload?.tool_input)
88
89
  };
89
90
  }
90
- function isRecord(value) {
91
- return typeof value === "object" && value !== null && !Array.isArray(value);
92
- }
93
91
  function answerableQuestionOf(toolName, toolInput) {
94
92
  if (toolName !== "AskUserQuestion" || !isRecord(toolInput)) return null;
95
93
  const questions = toolInput.questions;
@@ -123,6 +121,8 @@ function isWholeBashCommandShown(toolName, toolInput, fieldValue, summary) {
123
121
  function mapHookToSignal$1(event, payload) {
124
122
  switch (String(event || "").toLowerCase()) {
125
123
  case "sessionstart": return "session-start";
124
+ case "precompact": return "compaction-start";
125
+ case "postcompact": return "compaction-end";
126
126
  case "sessionend": return "session-end";
127
127
  case "userpromptsubmit": return "resume";
128
128
  case "stop": return "ready";
@@ -178,7 +178,15 @@ var settingsArgs = (settingsPath) => ["--settings", settingsPath];
178
178
  function buildArgs$1({ dangerouslySkipPermissions = false, resumeSessionId = null, extraArgs = [], antiSlopPrompt = false, initialPrompt = null } = {}) {
179
179
  const args = dangerouslySkipPermissions ? ["--dangerously-skip-permissions"] : [];
180
180
  if (resumeSessionId) args.push("--resume", resumeSessionId);
181
- if (extraArgs.length > 0) args.push(...extraArgs);
181
+ for (let index = 0; index < extraArgs.length; index += 1) {
182
+ const argument = extraArgs[index];
183
+ if (resumeSessionId && argument === "--session-id") {
184
+ index += 1;
185
+ continue;
186
+ }
187
+ if (resumeSessionId && argument.startsWith("--session-id=")) continue;
188
+ args.push(argument);
189
+ }
182
190
  args.push(...buildAntiSlopArgs(antiSlopPrompt));
183
191
  if (initialPrompt != null) args.push(initialPrompt);
184
192
  return args;
@@ -344,10 +352,22 @@ var SKIP_PERMISSIONS_ARGS = [
344
352
  "-s",
345
353
  "workspace-write"
346
354
  ];
347
- function buildArgs({ dangerouslySkipPermissions = false, resumeSessionId = null, extraArgs = [], initialPrompt = null } = {}) {
355
+ var OUTER_SANDBOX_ARGS = ["-s", "danger-full-access"];
356
+ var OUTER_SANDBOX_SKIP_PERMISSIONS_ARGS = [
357
+ "-a",
358
+ "never",
359
+ ...OUTER_SANDBOX_ARGS
360
+ ];
361
+ function permissionArgs(dangerouslySkipPermissions, hasOuterSandbox) {
362
+ if (hasOuterSandbox && dangerouslySkipPermissions) return OUTER_SANDBOX_SKIP_PERMISSIONS_ARGS;
363
+ if (hasOuterSandbox) return OUTER_SANDBOX_ARGS;
364
+ if (dangerouslySkipPermissions) return SKIP_PERMISSIONS_ARGS;
365
+ return [];
366
+ }
367
+ function buildArgs({ dangerouslySkipPermissions = false, resumeSessionId = null, extraArgs = [], initialPrompt = null, hasOuterSandbox = false } = {}) {
348
368
  const args = [...UPDATE_CHECK_ARGS];
349
369
  if (resumeSessionId) args.push("resume", resumeSessionId);
350
- if (dangerouslySkipPermissions) args.push(...SKIP_PERMISSIONS_ARGS);
370
+ args.push(...permissionArgs(dangerouslySkipPermissions, hasOuterSandbox));
351
371
  if (extraArgs.length > 0) args.push(...extraArgs);
352
372
  if (initialPrompt != null) args.push(initialPrompt);
353
373
  return args;
@@ -0,0 +1,135 @@
1
+ import { t as errorCode } from "./text-DoirglWV.js";
2
+ import { a as AgentDispatchRequest, n as AGENT_URL_ENV } from "./session-fc4pFbon.js";
3
+ import { i as resolveHookTarget } from "./hook-relay-core-DA_bz2KA.js";
4
+ import { n as decideSandboxProxy } from "./sandbox-proxy-core-hnQgKR0T.js";
5
+ import { a as isAgentApiVerb } from "./agent-api-core-hVcT26JW.js";
6
+ import http from "node:http";
7
+ //#region server/agent-api-cli.ts
8
+ var AGENT_PATH_PREFIX = "/agent/";
9
+ var BODY_BUILDERS = {
10
+ spawn: (rest) => {
11
+ const prompt = rest.join(" ").trim();
12
+ return prompt ? { prompt } : null;
13
+ },
14
+ attention: (rest) => {
15
+ const note = rest.join(" ").trim();
16
+ return note ? { note } : null;
17
+ },
18
+ board: () => ({}),
19
+ dispatch: (rest) => {
20
+ const parsed = AgentDispatchRequest.safeParse(rest[0] === "--ready" ? { readyIntent: rest[1] } : { workId: rest[0] });
21
+ return parsed.success ? parsed.data : null;
22
+ }
23
+ };
24
+ function bodySaysOk(text) {
25
+ try {
26
+ const parsed = JSON.parse(text);
27
+ return typeof parsed === "object" && parsed !== null && parsed.ok === true;
28
+ } catch {
29
+ return false;
30
+ }
31
+ }
32
+ function verbEndpoint(rawUrl, verb) {
33
+ const target = resolveHookTarget(rawUrl, verb, AGENT_PATH_PREFIX);
34
+ if (!target.url) return { ok: false };
35
+ const endpoint = new URL(target.url);
36
+ const token = endpoint.searchParams.get("t") || "";
37
+ endpoint.search = "";
38
+ return {
39
+ ok: true,
40
+ endpoint,
41
+ token
42
+ };
43
+ }
44
+ async function postDirectly(endpoint, headers, bodyText) {
45
+ const response = await fetch(endpoint, {
46
+ method: "POST",
47
+ headers,
48
+ body: bodyText
49
+ });
50
+ return {
51
+ hasSuccessStatus: response.ok,
52
+ text: await response.text()
53
+ };
54
+ }
55
+ function postThroughSandboxProxy(sandboxProxy, endpoint, headers, bodyText) {
56
+ const proxyHeaders = sandboxProxy.authorization ? { "proxy-authorization": sandboxProxy.authorization } : {};
57
+ return new Promise((resolve, reject) => {
58
+ const request = http.request({
59
+ host: sandboxProxy.hostname,
60
+ port: sandboxProxy.port,
61
+ method: "POST",
62
+ path: endpoint.href,
63
+ headers: {
64
+ ...headers,
65
+ ...proxyHeaders,
66
+ host: endpoint.host,
67
+ "content-length": String(Buffer.byteLength(bodyText))
68
+ }
69
+ }, (response) => {
70
+ const chunks = [];
71
+ response.on("data", (chunk) => {
72
+ chunks.push(chunk);
73
+ });
74
+ response.on("error", reject);
75
+ response.on("end", () => {
76
+ const statusCode = response.statusCode ?? 0;
77
+ resolve({
78
+ hasSuccessStatus: statusCode >= 200 && statusCode < 300,
79
+ text: Buffer.concat(chunks).toString("utf8")
80
+ });
81
+ });
82
+ });
83
+ request.on("error", reject);
84
+ request.end(bodyText);
85
+ });
86
+ }
87
+ function wasConnectionRefused(error) {
88
+ return errorCode(error?.cause) === "ECONNREFUSED";
89
+ }
90
+ async function postToAgentIngress(endpoint, token, body) {
91
+ const headers = {
92
+ "content-type": "application/json",
93
+ authorization: `Bearer ${token}`
94
+ };
95
+ const bodyText = JSON.stringify(body);
96
+ try {
97
+ return await postDirectly(endpoint, headers, bodyText);
98
+ } catch (error) {
99
+ if (!wasConnectionRefused(error)) throw error;
100
+ const sandboxProxy = decideSandboxProxy(process.env);
101
+ if (!sandboxProxy) throw error;
102
+ return postThroughSandboxProxy(sandboxProxy, endpoint, headers, bodyText);
103
+ }
104
+ }
105
+ async function runAgentApiCli(args) {
106
+ const verb = args[0];
107
+ if (!verb || !isAgentApiVerb(verb)) {
108
+ console.error(`glimmervoid: ${verb || "that"} is not an agent command`);
109
+ return 1;
110
+ }
111
+ const body = BODY_BUILDERS[verb](args.slice(1));
112
+ if (!body) {
113
+ if (verb === "dispatch") {
114
+ console.error("glimmervoid dispatch: expected a work id matching wrk-[0-9a-f]{16}");
115
+ return 1;
116
+ }
117
+ console.error(`glimmervoid ${verb}: this command needs text, for example "glimmervoid ${verb} check the failing test"`);
118
+ return 1;
119
+ }
120
+ const rawUrl = process.env[AGENT_URL_ENV];
121
+ if (!rawUrl) {
122
+ console.error(`glimmervoid: ${AGENT_URL_ENV} is not set, so this is not a Glimmervoid session with the agent API turned on`);
123
+ return 1;
124
+ }
125
+ const target = verbEndpoint(rawUrl, verb);
126
+ if (!target.ok) {
127
+ console.error(`glimmervoid: ${AGENT_URL_ENV} must be a loopback http url under ${AGENT_PATH_PREFIX}, so nothing was sent`);
128
+ return 1;
129
+ }
130
+ const reply = await postToAgentIngress(target.endpoint, target.token, body);
131
+ console.log(reply.text);
132
+ return reply.hasSuccessStatus && bodySaysOk(reply.text) ? 0 : 1;
133
+ }
134
+ //#endregion
135
+ export { runAgentApiCli };
@@ -1,4 +1,4 @@
1
- import { a as AgentSpawnRequest, i as AgentAttentionRequest, t as AGENT_API_VERBS } from "./session-Cez8aIWg.js";
1
+ import { a as AgentDispatchRequest, i as AgentAttentionRequest, o as AgentSpawnRequest, t as AGENT_API_VERBS } from "./session-fc4pFbon.js";
2
2
  import crypto from "node:crypto";
3
3
  var MAX_SPAWNS_IN_FLIGHT = 1;
4
4
  var SPAWNABLE_DEPTH = 0;
@@ -67,6 +67,15 @@ function parseAgentVerb(verb, payload) {
67
67
  status: 404,
68
68
  error: REFUSAL_REASON
69
69
  };
70
+ if (verb === "dispatch") {
71
+ const parsed = AgentDispatchRequest.safeParse(payload);
72
+ if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
73
+ return {
74
+ ok: true,
75
+ verb,
76
+ request: parsed.data
77
+ };
78
+ }
70
79
  if (verb === "board") return {
71
80
  ok: true,
72
81
  verb
@@ -1,16 +1,10 @@
1
- import { a as classifyGrokHooksFile, o as renderGrokHooksFile, t as grok } from "./grok-DuU8xVLZ.js";
1
+ import { a as isMissingFileError, r as errorMessage } from "./text-DoirglWV.js";
2
+ import { a as classifyGrokHooksFile, o as renderGrokHooksFile, t as grok } from "./grok-CXKeSt2z.js";
3
+ import { p as writeTextAtomicSync } from "./json-file-oEH9vt-0.js";
2
4
  import fs from "node:fs";
3
5
  import path from "node:path";
4
- import crypto from "node:crypto";
5
6
  //#region server/agent-setup-cli.ts
6
7
  var USAGE = "Usage: glimmervoid agent setup grok";
7
- function errorCode(error) {
8
- const code = error?.code;
9
- return typeof code === "string" ? code : void 0;
10
- }
11
- function errorMessage(error) {
12
- return error instanceof Error ? error.message : String(error);
13
- }
14
8
  function setupInputs(env = process.env) {
15
9
  return {
16
10
  filePath: grok.hooksFilePath(env),
@@ -26,7 +20,7 @@ function inspectGrokAgentSetup({ env = process.env, readFileSync = fs.readFileSy
26
20
  try {
27
21
  contents = readFileSync(inputs.filePath, "utf8");
28
22
  } catch (error) {
29
- if (errorCode(error) === "ENOENT") return {
23
+ if (isMissingFileError(error, { includeNotDir: false })) return {
30
24
  filePath: inputs.filePath,
31
25
  classification: "absent"
32
26
  };
@@ -59,7 +53,7 @@ function ensureWritableHooksDirectory(directory, fileSystem) {
59
53
  assertRealDirectory(currentDirectory, fileSystem);
60
54
  continue;
61
55
  } catch (directoryError) {
62
- if (errorCode(directoryError) !== "ENOENT") throw directoryError;
56
+ if (!isMissingFileError(directoryError, { includeNotDir: false })) throw directoryError;
63
57
  }
64
58
  fileSystem.mkdirSync(currentDirectory, { mode: 448 });
65
59
  assertRealDirectory(currentDirectory, fileSystem);
@@ -69,23 +63,12 @@ function ensureWritableHooksDirectory(directory, fileSystem) {
69
63
  } catch {}
70
64
  }
71
65
  function replaceFileAtomically(filePath, contents, fileSystem) {
72
- const temporaryPath = `${filePath}.${process.pid}.${crypto.randomBytes(8).toString("hex")}.tmp`;
73
- try {
74
- fileSystem.writeFileSync(temporaryPath, contents, {
75
- encoding: "utf8",
76
- mode: 384,
77
- flag: "wx"
78
- });
79
- fileSystem.renameSync(temporaryPath, filePath);
80
- } catch (writeError) {
81
- try {
82
- fileSystem.rmSync(temporaryPath, { force: true });
83
- } catch {}
84
- throw writeError;
85
- }
86
- try {
87
- fileSystem.chmodSync(filePath, 384);
88
- } catch {}
66
+ writeTextAtomicSync(filePath, contents, {
67
+ mode: 384,
68
+ exclusive: true,
69
+ enforceMode: true,
70
+ fsSync: fileSystem
71
+ });
89
72
  }
90
73
  function runGrokSetup({ env, fileSystem, log, error }) {
91
74
  const inputs = setupInputs(env);
@@ -0,0 +1,14 @@
1
+ //#region shared/backoff.ts
2
+ var DEFAULT_BASE_MS = 6e4;
3
+ var DEFAULT_MAX_MS = 18e5;
4
+ var MAX_DOUBLING_ATTEMPT = 20;
5
+ function nextBackoffMs({ attempt = 1, baseMs = DEFAULT_BASE_MS, maxMs = DEFAULT_MAX_MS, retryAfterMs = null, random = Math.random, jitter = "full" } = {}) {
6
+ if (typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs > 0) return Math.min(retryAfterMs, maxMs);
7
+ const exponent = Math.max(0, Math.min(attempt, MAX_DOUBLING_ATTEMPT) - 1);
8
+ const ceiling = Math.min(maxMs, baseMs * 2 ** exponent);
9
+ if (jitter === "none") return ceiling;
10
+ if (jitter === "half") return Math.round(ceiling * (.5 + .5 * random()));
11
+ return Math.round(random() * ceiling);
12
+ }
13
+ //#endregion
14
+ export { DEFAULT_MAX_MS as n, nextBackoffMs as r, DEFAULT_BASE_MS as t };
@@ -0,0 +1,2 @@
1
+ import { r as execFileSync } from "./child-process-safe-Ch-Zgxqs.js";
2
+ export { execFileSync };
@@ -0,0 +1,32 @@
1
+ //#region shared/coerce.ts
2
+ function isRecord(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ function textOr(value, fallback) {
6
+ return typeof value === "string" && value.trim() ? value.trim() : fallback;
7
+ }
8
+ function rawTextOr(value, fallback) {
9
+ return typeof value === "string" && value.length > 0 ? value : fallback;
10
+ }
11
+ function numberOr(value, fallback) {
12
+ return typeof value === "number" && Number.isFinite(value) ? value : fallback;
13
+ }
14
+ function positiveNumberOr(value, fallback) {
15
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : fallback;
16
+ }
17
+ function nonNegativeIntOr(value, fallback) {
18
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0) return fallback;
19
+ return Math.floor(value);
20
+ }
21
+ function coercedNumberOr(value, fallback) {
22
+ const number = Number(value);
23
+ if (!Number.isFinite(number)) return fallback;
24
+ return number;
25
+ }
26
+ function positiveIntOr(value, fallback) {
27
+ const number = Number(value);
28
+ if (!Number.isFinite(number) || number <= 0) return fallback;
29
+ return Math.floor(number);
30
+ }
31
+ //#endregion
32
+ export { positiveIntOr as a, textOr as c, numberOr as i, isRecord as n, positiveNumberOr as o, nonNegativeIntOr as r, rawTextOr as s, coercedNumberOr as t };