glimmervoid 0.38.2 → 0.39.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 (37) hide show
  1. package/dist/bin/glimmervoid.js +23 -29
  2. package/dist/chunks/{adapters-CAHxZYT3.js → adapters-B9tP9MXC.js} +26 -14
  3. package/dist/chunks/{adapters-DDjC7_vG.js → adapters-Buu6yI71.js} +1 -1
  4. package/dist/chunks/{agent-api-cli-B5Tm0wXO.js → agent-api-cli-2_RwTTTJ.js} +4 -66
  5. package/dist/chunks/{agent-api-cli-BDu1CxZf.js → agent-api-cli-PfCov-qb.js} +1 -1
  6. package/dist/chunks/agent-api-core-D2HLgBEe.js +180 -0
  7. package/dist/chunks/{agent-setup-cli-DmMfCw5O.js → agent-setup-cli-C1nFdgFg.js} +2 -2
  8. package/dist/chunks/config-store-8Z9vkWvf.js +1 -0
  9. package/dist/chunks/{config-store-BUNZs4j7.js → config-store-n23JDU4E.js} +63 -268
  10. package/dist/chunks/{contracts-HVCEJfxs.js → contracts-DYQW11de.js} +1018 -171
  11. package/dist/chunks/{git-version-rWZjF2Px.js → git-version-DXozXVnb.js} +2 -2
  12. package/dist/chunks/{grok-B6bsCgdd.js → grok-DeGAXgZF.js} +7 -8
  13. package/dist/chunks/{guardrails-deps-Cb-ki4EU.js → guardrails-deps-CLxK4J-g.js} +1 -1
  14. package/dist/chunks/{json-file-CIJf0Cel.js → json-file-DFCTvPjj.js} +3 -7
  15. package/dist/chunks/{main-BNSbP-Yk.js → main-D4uwk-_M.js} +16436 -21253
  16. package/dist/chunks/{pair-cli-DNp8i5L4.js → pair-cli-D9DZBqk0.js} +2 -2
  17. package/dist/chunks/{remote-config-C_s2pnLC.js → remote-config-DiLwnzBq.js} +2 -2
  18. package/dist/chunks/{session-BlT68ppa.js → session-D2EbiysG.js} +20 -32
  19. package/dist/chunks/{session-routes-CT1JrjoT.js → session-routes-BQAZzMKZ.js} +3 -8
  20. package/dist/chunks/{settings-cli-BbzxCyG5.js → settings-cli-DP4t-I9U.js} +3 -3
  21. package/dist/chunks/{ssh-sign-cli-C74BGTQS.js → ssh-sign-cli-D2RIs-iN.js} +2 -2
  22. package/dist/client/assets/index-C0YUJwjz.css +2 -0
  23. package/dist/client/assets/index-w8lG-tk2.js +148 -0
  24. package/dist/client/assets/xterm-kR64YvZ-.js +79 -0
  25. package/dist/client/assets/zod-BRLv4KqJ.js +55 -0
  26. package/dist/client/index.html +5 -2
  27. package/dist/scripts/postinstall-path-check.js +21 -3
  28. package/dist/server/index.js +1 -1
  29. package/package.json +2 -3
  30. package/dist/chunks/agent-api-core-B_mUSenR.js +0 -341
  31. package/dist/chunks/browser-config-BrBT8269.js +0 -762
  32. package/dist/chunks/config-CjawSOBk.js +0 -219
  33. package/dist/chunks/config-store-MAVQhGMh.js +0 -1
  34. package/dist/chunks/factory-D7ryES9n.js +0 -240
  35. package/dist/chunks/knowledge-graph-cli-ByUJoKw_.js +0 -1354
  36. package/dist/client/assets/index-B5uVtedd.css +0 -1
  37. package/dist/client/assets/index-b13-NGGS.js +0 -275
@@ -2,12 +2,12 @@
2
2
  import { o as nodePtyRebuildHint, r as firstLine, t as probeNodePty } from "../chunks/node-pty-preflight-C8QIlrtU.js";
3
3
  import { i as errorText } from "../chunks/text-DoirglWV.js";
4
4
  import { a as packageRoot } from "../chunks/runtime-paths-BkeftE60.js";
5
- import { t as AGENT_API_VERBS } from "../chunks/session-BlT68ppa.js";
5
+ import { t as AGENT_API_VERBS } from "../chunks/session-D2EbiysG.js";
6
6
  import { i as execSync } from "../chunks/child-process-safe-CbQnyh7D.js";
7
7
  import { t as renderTable } from "../chunks/ascii-figure-core-pDAwtlKO.js";
8
8
  import { n as glimmervoidHomeDir, t as decideConfigPath } from "../chunks/config-path-core-DFt-TemS.js";
9
- import { i as parseCommandLine, r as gitDoctorRows, t as probeGitVersion } from "../chunks/git-version-rWZjF2Px.js";
10
- import { i as guardrailsDoctorRows, r as probeGuardrailsDependencies } from "../chunks/guardrails-deps-Cb-ki4EU.js";
9
+ import { i as parseCommandLine, r as gitDoctorRows, t as probeGitVersion } from "../chunks/git-version-DXozXVnb.js";
10
+ import { i as guardrailsDoctorRows, r as probeGuardrailsDependencies } from "../chunks/guardrails-deps-CLxK4J-g.js";
11
11
  import { i as pnpmGlobalBinDir, n as npmGlobalBinDir, r as onPath, t as formatPathNotice } from "../chunks/path-doctor-C23VAqeu.js";
12
12
  import fs from "node:fs";
13
13
  import path from "node:path";
@@ -41,15 +41,8 @@ Inside a Glimmervoid session:
41
41
  push Land this session's commits on the integration branch and push it
42
42
  edit <path> Open a text file for the operator to edit in the dashboard
43
43
  limits List which of these commands answer here and what the guardrails block
44
- factory status Print each factory intent's tickets, state, last reason and next action
45
- factory retry <id> Reopen the parked tickets of a factory intent
46
- factory setup Prove and save the factory checks of this session's repository
47
- factory queue <file> Queue a factory intent (a spec cut.ts file or Factory tab request) on this session's repository
48
44
  ssh-sign Sign a commit with the operator's forwarded ssh agent (git runs this)
49
45
 
50
- Experimental:
51
- kg [command] Typed knowledge and task graph (Settings > Lanes > Knowledge graph)
52
-
53
46
  Options:
54
47
  --port <number> Server port (default: 3000)
55
48
  --config <path> Config file (default: ~/.glimmervoid/config.json)
@@ -76,19 +69,15 @@ var SUBCOMMAND_RUNNERS = new Map([
76
69
  return 0;
77
70
  }],
78
71
  ["pair", async (subcommandArgs) => {
79
- const { runPairCli } = await import("../chunks/pair-cli-DNp8i5L4.js");
72
+ const { runPairCli } = await import("../chunks/pair-cli-D9DZBqk0.js");
80
73
  return runPairCli(subcommandArgs);
81
74
  }],
82
75
  ["agent", async (subcommandArgs) => {
83
- const { runAgentSetupCli } = await import("../chunks/agent-setup-cli-DmMfCw5O.js");
76
+ const { runAgentSetupCli } = await import("../chunks/agent-setup-cli-C1nFdgFg.js");
84
77
  return runAgentSetupCli(subcommandArgs);
85
78
  }],
86
- ["kg", async (subcommandArgs) => {
87
- const { runKnowledgeGraphCommand } = await import("../chunks/knowledge-graph-cli-ByUJoKw_.js");
88
- return runKnowledgeGraphCommand(subcommandArgs);
89
- }],
90
79
  ["settings", async (subcommandArgs) => {
91
- const { runSettingsCommand } = await import("../chunks/settings-cli-BbzxCyG5.js");
80
+ const { runSettingsCommand } = await import("../chunks/settings-cli-DP4t-I9U.js");
92
81
  return runSettingsCommand(subcommandArgs);
93
82
  }],
94
83
  ["visions", async (subcommandArgs) => {
@@ -96,21 +85,26 @@ var SUBCOMMAND_RUNNERS = new Map([
96
85
  return runVisionsCli(subcommandArgs);
97
86
  }],
98
87
  ["ssh-sign", async (subcommandArgs) => {
99
- const { runSshSignCli } = await import("../chunks/ssh-sign-cli-C74BGTQS.js");
88
+ const { runSshSignCli } = await import("../chunks/ssh-sign-cli-D2RIs-iN.js");
100
89
  return runSshSignCli(subcommandArgs);
101
90
  }],
102
- ["factory", async (subcommandArgs) => {
103
- const { runAgentApiCli } = await import("../chunks/agent-api-cli-BDu1CxZf.js");
104
- return runAgentApiCli(["factory", ...subcommandArgs]);
105
- }],
106
91
  ...AGENT_API_VERBS.map((verb) => [verb, async (subcommandArgs, subcommandName) => {
107
- const { runAgentApiCli } = await import("../chunks/agent-api-cli-BDu1CxZf.js");
92
+ const { runAgentApiCli } = await import("../chunks/agent-api-cli-PfCov-qb.js");
108
93
  return runAgentApiCli([subcommandName, ...subcommandArgs]);
109
94
  }])
110
95
  ]);
96
+ var AGENT_INSTALL_COMMAND_BY_ID = {
97
+ "claude-code": "npm install -g @anthropic-ai/claude-code",
98
+ codex: "npm install -g @openai/codex"
99
+ };
100
+ function missingAgentText(agentId) {
101
+ const installCommand = AGENT_INSTALL_COMMAND_BY_ID[agentId];
102
+ if (!installCommand) return "not found on PATH";
103
+ return `not found on PATH; install with: ${installCommand}`;
104
+ }
111
105
  async function printSessionLimits() {
112
106
  if (!process.env["GLIMMERVOID_AGENT_URL"]) return;
113
- const { sessionLimitsHelpLines } = await import("../chunks/agent-api-cli-BDu1CxZf.js");
107
+ const { sessionLimitsHelpLines } = await import("../chunks/agent-api-cli-PfCov-qb.js");
114
108
  const limitsLines = await sessionLimitsHelpLines();
115
109
  console.log(`\n${limitsLines.join("\n")}`);
116
110
  }
@@ -167,7 +161,7 @@ async function readDeclaredCustomAgents() {
167
161
  declared: [],
168
162
  error: null
169
163
  };
170
- const { loadConfigFile } = await import("../chunks/config-store-MAVQhGMh.js");
164
+ const { loadConfigFile } = await import("../chunks/config-store-8Z9vkWvf.js");
171
165
  try {
172
166
  const loaded = loadConfigFile(decided.path, { exitOnError: false });
173
167
  if (!loaded.config) return {
@@ -243,15 +237,15 @@ async function runDoctor() {
243
237
  }
244
238
  switchSection("Agents");
245
239
  try {
246
- const { listAgentIds, describeAgentResolvability, setCustomAgents } = await import("../chunks/adapters-DDjC7_vG.js");
240
+ const { listAgentIds, describeAgentResolvability, setCustomAgents } = await import("../chunks/adapters-Buu6yI71.js");
247
241
  const declaredCustomAgents = await readDeclaredCustomAgents();
248
242
  if (declaredCustomAgents.error) line("config", declaredCustomAgents.error);
249
243
  setCustomAgents(declaredCustomAgents.declared);
250
244
  for (const id of listAgentIds()) {
251
245
  const { label, path: resolvedPath } = describeAgentResolvability(id);
252
- line(`${id} (${label})`, resolvedPath ?? "not found on PATH");
246
+ line(`${id} (${label})`, resolvedPath ?? missingAgentText(id));
253
247
  }
254
- const { inspectGrokAgentSetup } = await import("../chunks/agent-setup-cli-DmMfCw5O.js");
248
+ const { inspectGrokAgentSetup } = await import("../chunks/agent-setup-cli-C1nFdgFg.js");
255
249
  const grokSetup = inspectGrokAgentSetup();
256
250
  line("grok hook setup", `${grokSetup.classification}: ${grokSetup.filePath}`);
257
251
  } catch (err) {
@@ -268,7 +262,7 @@ async function runDoctor() {
268
262
  try {
269
263
  const { resolvePackageBin } = await import("../chunks/runtime-paths-DSmormp7.js");
270
264
  const { execFileSync } = await import("../chunks/child-process-safe-ChRmWAJP.js");
271
- const { inspectGrokAgentSetup } = await import("../chunks/agent-setup-cli-DmMfCw5O.js");
265
+ const { inspectGrokAgentSetup } = await import("../chunks/agent-setup-cli-C1nFdgFg.js");
272
266
  const binPath = resolvePackageBin("cc-safety-net", "cc-safety-net");
273
267
  line("Sane YOLO", binPath || "not installed");
274
268
  if (binPath) line("cc-safety-net version", execFileSync(process.execPath, [binPath, "--version"], {
@@ -3,10 +3,10 @@ import { r as execFileSync } from "./child-process-safe-CbQnyh7D.js";
3
3
  import { n as resolveAgentCommand, t as buildAgentSpawnCommand } from "./spawn-command-Cc40FiZI.js";
4
4
  import { s as rawTextOr } from "./coerce-NSst8oRP.js";
5
5
  import { r as nextBackoffMs } from "./backoff-DjVpfHk7.js";
6
- import { l as supervisionLine } from "./session-routes-CT1JrjoT.js";
7
- import { c as buildAgentEnv, i as isSpinnerChar, n as classifyAgentTitle, r as isBrailleChar, t as grok } from "./grok-B6bsCgdd.js";
6
+ import { l as supervisionLine } from "./session-routes-BQAZzMKZ.js";
7
+ import { i as isSpinnerChar, n as classifyAgentTitle, r as isBrailleChar, s as buildAgentEnv, t as grok } from "./grok-DeGAXgZF.js";
8
8
  import { t as buildHookCommand } from "./hook-command-core-qTNK-xMF.js";
9
- import "./contracts-HVCEJfxs.js";
9
+ import "./contracts-DYQW11de.js";
10
10
  import { n as mergeCodexPreToolUse, t as HOOK_TOOLS } from "./hook-tools-Dl7-r2Eb.js";
11
11
  import fs from "node:fs";
12
12
  import path from "node:path";
@@ -204,13 +204,6 @@ var claudeCode = {
204
204
  };
205
205
  //#endregion
206
206
  //#region server/usage/core/usage-scan-core.ts
207
- function laneSpendStatus({ isTrackingEnabled, scan }) {
208
- if (!isTrackingEnabled) return "tracking-off";
209
- if (scan === null) return "scanner-missing";
210
- if (scan.lastOutcome === "io-failed") return "read-failing";
211
- if (!scan.isHistoryCaughtUp || scan.lastOutcome === null) return "catching-up";
212
- return "known";
213
- }
214
207
  function scopedClaudeRoots(scopeDirs, claudeDirs) {
215
208
  if (!scopeDirs || scopeDirs.length === 0) return null;
216
209
  const isInside = (candidate, parent) => candidate.startsWith(`${parent}${path.sep}`);
@@ -473,9 +466,11 @@ function mayContributeHooks(configText) {
473
466
  function userConfigFolders(env) {
474
467
  return codexHomes(env, null);
475
468
  }
476
- function buildHookArgs({ relayPath = RELAY_PATH, events = HOOK_EVENTS, bypassHookTrust = false, hookTools = [], hookToolRelayPath = HOOK_TOOL_RELAY_PATH } = {}) {
469
+ var TOML_LITERAL_STRING_FORBIDDEN = /[\x00-\x08\x0a-\x1f\x27\x7f]/;
470
+ function buildHookArgs({ relayPath = RELAY_PATH, events = HOOK_EVENTS, bypassHookTrust = false, hookTools = [], hookToolRelayPath = HOOK_TOOL_RELAY_PATH, userHooks = [] } = {}) {
477
471
  const args = bypassHookTrust ? [TRUST_BYPASS_FLAG] : [];
478
472
  const preToolUseGroups = [];
473
+ const groupsByEvent = /* @__PURE__ */ new Map();
479
474
  for (const event of events) {
480
475
  const command = buildHookCommand(relayPath, event);
481
476
  if (!command) return null;
@@ -483,13 +478,30 @@ function buildHookArgs({ relayPath = RELAY_PATH, events = HOOK_EVENTS, bypassHoo
483
478
  preToolUseGroups.push(`{hooks=[{type='command',command='${command}'}]}`);
484
479
  continue;
485
480
  }
486
- args.push("-c", `hooks.${event}=[{hooks=[{type='command',command='${command}'}]}]`);
481
+ groupsByEvent.set(event, [`{hooks=[{type='command',command='${command}'}]}`]);
487
482
  }
488
483
  const groups = hookTools.flatMap((tool) => {
489
484
  const group = HOOK_TOOLS[tool.id].codexGroup(tool, hookToolRelayPath);
490
485
  return group ? [group] : [];
491
486
  });
492
- args.push(...mergeCodexPreToolUse([...preToolUseGroups, ...groups]));
487
+ preToolUseGroups.push(...groups);
488
+ for (const hook of userHooks) {
489
+ if (!hook.enabled || hook.type !== "command" || !hook.command) continue;
490
+ if (TOML_LITERAL_STRING_FORBIDDEN.test(hook.command) || hook.matcher !== void 0 && TOML_LITERAL_STRING_FORBIDDEN.test(hook.matcher)) {
491
+ console.warn(`[codex] hook ${hook.id} skipped: command or matcher cannot be expressed as a TOML literal string`);
492
+ continue;
493
+ }
494
+ const group = `{${hook.matcher === void 0 ? "" : `matcher='${hook.matcher}',`}hooks=[{type='command',command='${hook.command}'}]}`;
495
+ if (hook.event === "PreToolUse") {
496
+ preToolUseGroups.push(group);
497
+ continue;
498
+ }
499
+ const eventGroups = groupsByEvent.get(hook.event) ?? [];
500
+ eventGroups.push(group);
501
+ groupsByEvent.set(hook.event, eventGroups);
502
+ }
503
+ for (const [event, eventGroups] of groupsByEvent) args.push("-c", `hooks.${event}=[${eventGroups.join(",")}]`);
504
+ args.push(...mergeCodexPreToolUse(preToolUseGroups));
493
505
  return args;
494
506
  }
495
507
  var hooks = {
@@ -790,4 +802,4 @@ function resetCommandCache() {
790
802
  resolvedCommands.clear();
791
803
  }
792
804
  //#endregion
793
- export { shouldPersistWarehouse as A, isUsageFile as C, resolveProjectsDirs as D, projectDirCandidates as E, claudeCode as M, scopedClaudeRoots as O, grokRootCandidates as S, passOutcome as T, continuationDelayMs as _, describeAgentResolvability as a, expandTilde as b, isKnownAgentId as c, resolveAdapter as d, setCustomAgents as f, codexSessionIdFromPath as g, codexRootCandidates as h, customAgentFingerprint as i, splitLines as j, shouldEvaluateDespiteIoFailures as k, listAgentIds as l, codexHomes as m, cachedAgentResolvability as n, getAdapter as o, codexFallbackRoots as p, commandFor as r, hookProfileOf as s, DEFAULT_AGENT_ID as t, resetCommandCache as u, decideFileRead as v, laneSpendStatus as w, grokHomes as x, dedupeCodexFiles as y };
805
+ export { splitLines as A, isUsageFile as C, scopedClaudeRoots as D, resolveProjectsDirs as E, shouldEvaluateDespiteIoFailures as O, grokRootCandidates as S, projectDirCandidates as T, continuationDelayMs as _, describeAgentResolvability as a, expandTilde as b, isKnownAgentId as c, resolveAdapter as d, setCustomAgents as f, codexSessionIdFromPath as g, codexRootCandidates as h, customAgentFingerprint as i, claudeCode as j, shouldPersistWarehouse as k, listAgentIds as l, codexHomes as m, cachedAgentResolvability as n, getAdapter as o, codexFallbackRoots as p, commandFor as r, hookProfileOf as s, DEFAULT_AGENT_ID as t, resetCommandCache as u, decideFileRead as v, passOutcome as w, grokHomes as x, dedupeCodexFiles as y };
@@ -1 +1 @@
1
- export { a as describeAgentResolvability, l as listAgentIds, f as setCustomAgents } from "./adapters-CAHxZYT3.js";
1
+ export { a as describeAgentResolvability, l as listAgentIds, f as setCustomAgents } from "./adapters-B9tP9MXC.js";
@@ -1,22 +1,16 @@
1
1
  import { t as errorCode } from "./text-DoirglWV.js";
2
- import { a as AgentDispatchRequest, f as AgentTicketRequest, l as AgentFactoryStatusRequest, n as AGENT_URL_ENV, s as AgentFactoryRetryRequest, u as AgentLimitsReply } from "./session-BlT68ppa.js";
2
+ import { n as AGENT_URL_ENV, o as AgentLimitsReply } from "./session-D2EbiysG.js";
3
3
  import { i as resolveHookTarget } from "./hook-relay-core-DA_bz2KA.js";
4
4
  import { n as decideGuardrailsProxy } from "./guardrails-proxy-core-BI3rdY-m.js";
5
- import { n as isRecord } from "./coerce-NSst8oRP.js";
6
5
  import { t as parseJsonOrNull } from "./json-core-dfa_7Fak.js";
7
- import { a as formatSessionLimits } from "./session-routes-CT1JrjoT.js";
8
- import { g as isOrchestratorAgentVerb, h as isAgentApiVerb } from "./agent-api-core-B_mUSenR.js";
9
- import { readFileSync } from "node:fs";
6
+ import { a as formatSessionLimits } from "./session-routes-BQAZzMKZ.js";
7
+ import { l as isAgentApiVerb } from "./agent-api-core-D2HLgBEe.js";
10
8
  import path from "node:path";
11
9
  import http from "node:http";
12
10
  //#region server/agent-api-cli.ts
13
11
  var AGENT_PATH_PREFIX = "/agent/";
14
12
  var HELP_LIMITS_TIMEOUT_MS = 2e3;
15
13
  var HELP_LIMITS_UNKNOWN_LINE = "This session: Glimmervoid did not report its limits, so run glimmervoid limits to see why";
16
- function ticketBody(rest) {
17
- const parsed = AgentTicketRequest.safeParse({ workId: rest[0] });
18
- return parsed.success ? parsed.data : null;
19
- }
20
14
  var BODY_BUILDERS = {
21
15
  spawn: (rest) => {
22
16
  const prompt = rest.join(" ").trim();
@@ -32,42 +26,8 @@ var BODY_BUILDERS = {
32
26
  const docPath = rest.join(" ").trim();
33
27
  return docPath ? { path: path.resolve(docPath) } : null;
34
28
  },
35
- limits: () => ({}),
36
- dispatch: (rest) => {
37
- const parsed = AgentDispatchRequest.safeParse(rest[0] === "--ready" ? { readyIntent: rest[1] } : { workId: rest[0] });
38
- return parsed.success ? parsed.data : null;
39
- },
40
- reopen: (rest) => ticketBody(rest),
41
- cancel: (rest) => ticketBody(rest),
42
- "factory-status": (rest) => {
43
- if (rest.length === 0) return {};
44
- if (rest.length !== 2 || rest[0] !== "--project") return null;
45
- const parsed = AgentFactoryStatusRequest.safeParse({ projectId: rest[1] });
46
- return parsed.success ? parsed.data : null;
47
- },
48
- "factory-retry": (rest) => {
49
- if (rest.length !== 1) return null;
50
- const parsed = AgentFactoryRetryRequest.safeParse({ intentId: rest[0] });
51
- return parsed.success ? parsed.data : null;
52
- },
53
- "factory-setup": (rest) => rest.length === 0 ? {} : null,
54
- "factory-queue": (rest) => {
55
- if (rest.length !== 1) return null;
56
- const intent = parseJsonOrNull(readFileSync(rest[0], "utf8"));
57
- if (!isRecord(intent)) return null;
58
- const { name: _name, type: _type, requestId: _requestId, projectId: _projectId, ...request } = intent;
59
- return request;
60
- }
29
+ limits: () => ({})
61
30
  };
62
- var FACTORY_USAGE = Object.freeze({
63
- "factory-status": "status [--project <projectId>]",
64
- "factory-retry": "retry <intentId>",
65
- "factory-setup": "setup",
66
- "factory-queue": "queue <intent.json>"
67
- });
68
- function isFactoryVerb(verb) {
69
- return verb in FACTORY_USAGE;
70
- }
71
31
  function bodySaysOk(text) {
72
32
  try {
73
33
  const parsed = JSON.parse(text);
@@ -82,13 +42,6 @@ function limitsLines(replyText) {
82
42
  return formatSessionLimits(limits.data);
83
43
  }
84
44
  function printableReply(verb, replyText) {
85
- if (isFactoryVerb(verb)) {
86
- const reply = parseJsonOrNull(replyText);
87
- if (typeof reply !== "object" || reply === null) return replyText;
88
- if ("text" in reply && typeof reply.text === "string") return reply.text;
89
- if ("error" in reply && typeof reply.error === "string") return reply.error;
90
- return replyText;
91
- }
92
45
  if (verb !== "limits") return replyText;
93
46
  return limitsLines(replyText)?.join("\n") ?? replyText;
94
47
  }
@@ -188,13 +141,6 @@ async function sessionLimitsHelpLines({ timeoutMs = HELP_LIMITS_TIMEOUT_MS } = {
188
141
  }
189
142
  }
190
143
  async function runAgentApiCli(args) {
191
- if (args[0] === "factory") {
192
- if (!(`factory-${args[1]}` in FACTORY_USAGE)) {
193
- console.error(`glimmervoid factory: expected ${Object.values(FACTORY_USAGE).join(", or ")}`);
194
- return 1;
195
- }
196
- return runAgentApiCli([`factory-${args[1]}`, ...args.slice(2)]);
197
- }
198
144
  const verb = args[0];
199
145
  if (!verb || !isAgentApiVerb(verb)) {
200
146
  console.error(`glimmervoid: ${verb || "that"} is not an agent command`);
@@ -202,14 +148,6 @@ async function runAgentApiCli(args) {
202
148
  }
203
149
  const body = BODY_BUILDERS[verb](args.slice(1));
204
150
  if (!body) {
205
- if (isFactoryVerb(verb)) {
206
- console.error(`glimmervoid factory: expected ${FACTORY_USAGE[verb]}`);
207
- return 1;
208
- }
209
- if (isOrchestratorAgentVerb(verb)) {
210
- console.error(`glimmervoid ${verb}: expected a work id matching wrk-[0-9a-f]{16}`);
211
- return 1;
212
- }
213
151
  if (verb === "edit") {
214
152
  console.error("glimmervoid edit: this command needs a file path, for example \"glimmervoid edit drafts/post.md\"");
215
153
  return 1;
@@ -1 +1 @@
1
- export { n as runAgentApiCli, r as sessionLimitsHelpLines } from "./agent-api-cli-B5Tm0wXO.js";
1
+ export { n as runAgentApiCli, r as sessionLimitsHelpLines } from "./agent-api-cli-2_RwTTTJ.js";
@@ -0,0 +1,180 @@
1
+ import { a as AgentEditRequest, i as AgentAttentionRequest, s as AgentSpawnRequest, t as AGENT_API_VERBS } from "./session-D2EbiysG.js";
2
+ import { c as spawnRoute, i as editRoute, n as attentionRoute, s as pushRoute, t as NO_OWN_WORKTREE_REASON } from "./session-routes-BQAZzMKZ.js";
3
+ import crypto from "node:crypto";
4
+ var MAX_SPAWNS_IN_FLIGHT = 1;
5
+ var SPAWNABLE_DEPTH = 0;
6
+ var REFUSAL_REASON = "unknown session";
7
+ var INVALID_BODY_STATUS = 400;
8
+ var PUSH_REFUSED_STATUS = 409;
9
+ var PUSH_REFUSAL_COPY = Object.freeze({
10
+ "no-worktree": () => NO_OWN_WORKTREE_REASON,
11
+ "merge-in-progress": () => "a merge for this session is already running, so try again when it ends",
12
+ "not-continuable": () => "this session cannot be merged in its current state",
13
+ destroyed: () => "this session is ending",
14
+ "nothing-to-commit": () => "no commit on this branch is missing from the integration branch, so commit your work first",
15
+ "rebase-conflict": ({ base, conflicts = [] }) => `this branch conflicts with ${base} in ${conflicts.join(", ") || "one or more files"}, so rebase onto ${base}, resolve the conflicts, commit, then push again`,
16
+ "not-fast-forward": ({ base }) => `${base} could not be fast-forwarded to this branch, and a push is never forced`,
17
+ "base-diverged": ({ base }) => `the local ${base} and origin/${base} have diverged, which the operator has to reconcile`
18
+ });
19
+ function tokensMatch(presented, expected) {
20
+ if (presented.length !== expected.length) return false;
21
+ try {
22
+ return crypto.timingSafeEqual(Buffer.from(presented, "utf8"), Buffer.from(expected, "utf8"));
23
+ } catch {
24
+ return false;
25
+ }
26
+ }
27
+ function refused() {
28
+ return {
29
+ ok: false,
30
+ status: 404,
31
+ reason: REFUSAL_REASON
32
+ };
33
+ }
34
+ function decideAgentRequest({ sessionId, presentedToken, expectedToken, isLoopback }) {
35
+ if (!isLoopback) return refused();
36
+ if (!sessionId) return refused();
37
+ if (!expectedToken) return refused();
38
+ if (!presentedToken) return refused();
39
+ if (!tokensMatch(presentedToken, expectedToken)) return refused();
40
+ return { ok: true };
41
+ }
42
+ function refuseByRole(route) {
43
+ if (route.answers) return { ok: true };
44
+ return {
45
+ ok: false,
46
+ status: 403,
47
+ reason: route.reason
48
+ };
49
+ }
50
+ function decideSpawnAllowance({ liveChildren, lifetimeSpawns, inFlight, depth, isEphemeral }) {
51
+ const role = refuseByRole(spawnRoute({
52
+ isEphemeral,
53
+ isSpawnedChild: depth !== SPAWNABLE_DEPTH
54
+ }));
55
+ if (!role.ok) return role;
56
+ if (inFlight >= MAX_SPAWNS_IN_FLIGHT) return {
57
+ ok: false,
58
+ status: 429,
59
+ reason: "a spawn is already in flight"
60
+ };
61
+ if (liveChildren >= 3) return {
62
+ ok: false,
63
+ status: 429,
64
+ reason: `at most 3 spawned sessions may be live at once`
65
+ };
66
+ if (lifetimeSpawns >= 10) return {
67
+ ok: false,
68
+ status: 429,
69
+ reason: `this session has used its 10 spawns`
70
+ };
71
+ return { ok: true };
72
+ }
73
+ function decideAttentionAllowance(caller) {
74
+ return refuseByRole(attentionRoute(caller));
75
+ }
76
+ function decideEditAllowance(caller) {
77
+ return refuseByRole(editRoute(caller));
78
+ }
79
+ function describePushRouteRefusal(caller) {
80
+ const route = pushRoute(caller);
81
+ if (route.answers) return null;
82
+ return {
83
+ status: PUSH_REFUSED_STATUS,
84
+ body: {
85
+ ok: false,
86
+ reason: route.code,
87
+ error: route.reason
88
+ }
89
+ };
90
+ }
91
+ function isAgentApiVerb(verb) {
92
+ return AGENT_API_VERBS.includes(verb);
93
+ }
94
+ function refuseInvalidBody(issues) {
95
+ return {
96
+ ok: false,
97
+ status: INVALID_BODY_STATUS,
98
+ error: issues[0]?.message || "invalid request"
99
+ };
100
+ }
101
+ function parseAgentVerb(verb, payload) {
102
+ if (!isAgentApiVerb(verb)) return {
103
+ ok: false,
104
+ status: 404,
105
+ error: REFUSAL_REASON
106
+ };
107
+ if (verb === "board" || verb === "push" || verb === "limits") return {
108
+ ok: true,
109
+ verb
110
+ };
111
+ if (verb === "attention") {
112
+ const parsed = AgentAttentionRequest.safeParse(payload);
113
+ if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
114
+ return {
115
+ ok: true,
116
+ verb,
117
+ request: parsed.data
118
+ };
119
+ }
120
+ if (verb === "edit") {
121
+ const parsed = AgentEditRequest.safeParse(payload);
122
+ if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
123
+ return {
124
+ ok: true,
125
+ verb,
126
+ request: parsed.data
127
+ };
128
+ }
129
+ const parsed = AgentSpawnRequest.safeParse(payload);
130
+ if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
131
+ return {
132
+ ok: true,
133
+ verb,
134
+ request: parsed.data
135
+ };
136
+ }
137
+ function describePushLanding(landing) {
138
+ if (!landing.merged) {
139
+ const reason = landing.reason || "unknown";
140
+ const explain = PUSH_REFUSAL_COPY[reason];
141
+ return {
142
+ status: PUSH_REFUSED_STATUS,
143
+ body: {
144
+ ok: false,
145
+ reason,
146
+ error: explain ? explain(landing) : `the merge stopped: ${reason}`
147
+ }
148
+ };
149
+ }
150
+ if (landing.pushed) return {
151
+ status: 200,
152
+ body: {
153
+ ok: true,
154
+ landedOn: landing.base ?? null,
155
+ pushed: true
156
+ }
157
+ };
158
+ return {
159
+ status: 200,
160
+ body: {
161
+ ok: true,
162
+ landedOn: landing.base ?? null,
163
+ pushed: false,
164
+ note: "landed locally and nothing was pushed, because the repository has no origin remote or origin did not take a fast-forward"
165
+ }
166
+ };
167
+ }
168
+ function deriveChildSessionName(parentName, existingNames) {
169
+ const base = `${String(parentName || "").trim() || "session"} agent`;
170
+ const taken = new Set(existingNames);
171
+ let candidate = base;
172
+ let suffix = 1;
173
+ while (taken.has(candidate)) {
174
+ suffix += 1;
175
+ candidate = `${base} ${suffix}`;
176
+ }
177
+ return candidate;
178
+ }
179
+ //#endregion
180
+ export { decideSpawnAllowance as a, describePushRouteRefusal as c, decideEditAllowance as i, isAgentApiVerb as l, decideAgentRequest as n, deriveChildSessionName as o, decideAttentionAllowance as r, describePushLanding as s, REFUSAL_REASON as t, parseAgentVerb as u };
@@ -1,6 +1,6 @@
1
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-B6bsCgdd.js";
3
- import { p as writeTextAtomicSync } from "./json-file-CIJf0Cel.js";
2
+ import { a as classifyGrokHooksFile, o as renderGrokHooksFile, t as grok } from "./grok-DeGAXgZF.js";
3
+ import { p as writeTextAtomicSync } from "./json-file-DFCTvPjj.js";
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
6
  //#region server/agent-setup-cli.ts
@@ -0,0 +1 @@
1
+ export { s as loadConfigFile } from "./config-store-n23JDU4E.js";