glimmervoid 0.31.0 → 0.32.1

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 (39) hide show
  1. package/dist/bin/glimmervoid.js +19 -14
  2. package/dist/chunks/{adapters-gn7ulNO4.js → adapters-BS_7o8fj.js} +28 -23
  3. package/dist/chunks/{adapters-ClA_GbtA.js → adapters-Bn-dQ02i.js} +1 -1
  4. package/dist/chunks/{agent-api-cli-DAA7Jx8N.js → agent-api-cli-BR0GVDn6.js} +21 -5
  5. package/dist/chunks/agent-api-core-DUiWHSHg.js +201 -0
  6. package/dist/chunks/{agent-setup-cli-CiJSDWSo.js → agent-setup-cli-BqYcwfOs.js} +1 -1
  7. package/dist/chunks/child-process-safe-B3zcPdFM.js +2 -0
  8. package/dist/chunks/{child-process-safe-Ch-Zgxqs.js → child-process-safe-DDELk9XC.js} +2 -1
  9. package/dist/chunks/{config-W1Sv-iPK.js → config-B6BkTOcE.js} +20 -6
  10. package/dist/chunks/config-store-C8Ry8ZFD.js +2 -0
  11. package/dist/chunks/{config-store-BCy4FHNG.js → config-store-aZpWeX92.js} +14 -5
  12. package/dist/chunks/{contracts-3LkrilQX.js → contracts-DzDg-Z9I.js} +100 -7
  13. package/dist/chunks/git-version-CrLW4a6r.js +58 -0
  14. package/dist/chunks/{grok-CXKeSt2z.js → grok-7Z5KcgcY.js} +1 -2
  15. package/dist/chunks/{knowledge-graph-cli-D2tt5hPn.js → knowledge-graph-cli-D5Gf87Y7.js} +2 -2
  16. package/dist/chunks/{main-DyTCWIu2.js → main-BG6iHwoY.js} +3724 -1928
  17. package/dist/chunks/{pair-cli-BbCBfd6l.js → pair-cli-DQkrt_-s.js} +2 -2
  18. package/dist/chunks/{remote-config-DKIH_VxM.js → remote-config-Da4C7tMG.js} +2 -2
  19. package/dist/chunks/rtk-resolver-CIVLE_xk.js +2 -0
  20. package/dist/chunks/{rtk-resolver-BGDzw5XK.js → rtk-resolver-jJxy_Mrt.js} +1 -1
  21. package/dist/chunks/{sandbox-deps-BPKE-ylr.js → sandbox-deps-DuaNFq7n.js} +1 -1
  22. package/dist/chunks/{session-fc4pFbon.js → session-Dtkp9o3r.js} +28 -2
  23. package/dist/chunks/{visions-cli-CT5rjiwf.js → visions-cli-BhFdym5n.js} +1 -1
  24. package/dist/chunks/{visions-setup-BmOkI-QE.js → visions-setup-CfgNHiG3.js} +1 -1
  25. package/dist/client/assets/index-BxU3Ww0L.css +1 -0
  26. package/dist/client/assets/index-Co4S7tnh.js +254 -0
  27. package/dist/client/index.html +2 -2
  28. package/dist/scripts/postinstall-path-check.js +1 -1
  29. package/dist/server/index.js +1 -1
  30. package/dist/session/hook-tool-relay.js +1 -1
  31. package/dist/session/sandbox-open-launcher.js +42 -3
  32. package/dist/session/statusline-relay.js +1 -1
  33. package/package.json +1 -1
  34. package/dist/chunks/agent-api-core-hVcT26JW.js +0 -112
  35. package/dist/chunks/child-process-safe-BKPZ-5qQ.js +0 -2
  36. package/dist/chunks/config-store-DbBp7LJZ.js +0 -2
  37. package/dist/chunks/rtk-resolver-D4Nke1Fr.js +0 -2
  38. package/dist/client/assets/index-C6KD8lgZ.css +0 -1
  39. package/dist/client/assets/index-CThQEAEy.js +0 -249
@@ -7,8 +7,8 @@
7
7
  <link rel="icon" type="image/svg+xml" href="/assets/favicon-CKygeLwW.svg">
8
8
  <title>Glimmervoid</title>
9
9
  <style>html,body{background:var(--bg,#0a0810);height:100%;color:var(--text,#c8c0e0);font-family:var(--font-mono,"CommitMono", "Cascadia Code", "Fira Code", "Consolas", "Menlo", monospace);margin:0;padding:0}.app-shell{display:none}html:not([data-layout=phone]) .app-ready .app-shell{display:contents}.loading-screen{z-index:9999;background:#0a0810;flex-direction:column;justify-content:center;align-items:center;gap:20px;transition:opacity .3s;display:flex;position:fixed;inset:0}.loading-screen.fade-out{opacity:0;pointer-events:none}.loading-title{letter-spacing:.1em;color:#e8e0ff;text-transform:uppercase;font-family:CommitMono,Cascadia Code,Fira Code,Consolas,Menlo,monospace;font-size:20px;font-weight:700}.loading-title:before{content:"▸";color:#c084fc}.loading-status{color:#8276b0;letter-spacing:.04em;font-family:CommitMono,Cascadia Code,Fira Code,Consolas,Menlo,monospace;font-size:12px}.loading-spinner{border:2px solid #2a2440;border-top-color:#c084fc;border-radius:50%;width:28px;height:28px;animation:.8s linear infinite spin}@keyframes spin{to{transform:rotate(360deg)}}.shutdown-screen{z-index:9999;-webkit-backdrop-filter:blur();backdrop-filter:blur();pointer-events:none;opacity:0;background:#0a081000;flex-direction:column;justify-content:center;align-items:center;gap:20px;transition:background .4s,-webkit-backdrop-filter .4s,backdrop-filter .4s,opacity .3s;display:flex;position:fixed;inset:0}.shutdown-screen.active{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);pointer-events:auto;opacity:1;background:#0a0810eb}.shutdown-status{color:#8276b0;letter-spacing:.04em;font-family:CommitMono,Cascadia Code,Fira Code,Consolas,Menlo,monospace;font-size:12px;transition:color .3s}.shutdown-screen.done .loading-spinner{opacity:.3;border-color:#2a2440;animation:none}.shutdown-screen.done .shutdown-status{color:#4a4268}</style>
10
- <script type="module" crossorigin src="/assets/index-CThQEAEy.js"></script>
11
- <link rel="stylesheet" crossorigin href="/assets/index-C6KD8lgZ.css">
10
+ <script type="module" crossorigin src="/assets/index-Co4S7tnh.js"></script>
11
+ <link rel="stylesheet" crossorigin href="/assets/index-BxU3Ww0L.css">
12
12
  </head>
13
13
  <body>
14
14
  <div class="loading-screen" id="loading-screen">
@@ -1,4 +1,4 @@
1
- import { a as sandboxInstallNotice, r as probeSandboxDependencies } from "../chunks/sandbox-deps-BPKE-ylr.js";
1
+ import { a as sandboxInstallNotice, r as probeSandboxDependencies } from "../chunks/sandbox-deps-DuaNFq7n.js";
2
2
  import { n as npmGlobalBinDir, r as onPath, t as formatPathNotice } from "../chunks/path-doctor-C23VAqeu.js";
3
3
  import os from "node:os";
4
4
  //#region scripts/postinstall-path-check.ts
@@ -87,6 +87,6 @@ if (!nodePty.ok) {
87
87
  }));
88
88
  process.exit(1);
89
89
  }
90
- await import("../chunks/main-DyTCWIu2.js");
90
+ await import("../chunks/main-BG6iHwoY.js");
91
91
  //#endregion
92
92
  export {};
@@ -1,4 +1,4 @@
1
- import { o as spawn } from "../chunks/child-process-safe-Ch-Zgxqs.js";
1
+ import { o as spawn } from "../chunks/child-process-safe-DDELk9XC.js";
2
2
  import { t as readStdin } from "../chunks/relay-stdin-CpHvLu6M.js";
3
3
  import { a as SANE_YOLO_PATH_ENV, n as RTK_PATH_ENV, r as normalizeRtkHookResponse } from "../chunks/rtk-hook-core-BmEz2aq9.js";
4
4
  //#region session/hook-tool-relay.ts
@@ -1,7 +1,30 @@
1
1
  import { r as errorMessage } from "../chunks/text-DoirglWV.js";
2
- import { o as spawn } from "../chunks/child-process-safe-Ch-Zgxqs.js";
2
+ import { o as spawn } from "../chunks/child-process-safe-DDELk9XC.js";
3
3
  import fs from "node:fs";
4
+ import path from "node:path";
5
+ import tty from "node:tty";
4
6
  import { FilesystemConfigSchema, SandboxManager } from "@anthropic-ai/sandbox-runtime";
7
+ //#region session/core/sandbox-terminal-core.ts
8
+ var RUNTIME_TERMINAL_FILTER = "(regex #\"^/dev/ttys\")";
9
+ var RUNTIME_TERMINAL_FILTER_COUNT = 2;
10
+ var TERMINAL_PATH_SHAPE = /^\/dev\/ttys\d+$/;
11
+ function confineToOwnTerminal(argv, ownTerminalPath) {
12
+ if (!TERMINAL_PATH_SHAPE.test(ownTerminalPath)) return {
13
+ ok: false,
14
+ reason: `${ownTerminalPath} is not a pseudo-terminal the sandbox can be confined to`
15
+ };
16
+ const filterCount = argv.reduce((count, word) => count + word.split(RUNTIME_TERMINAL_FILTER).length - 1, 0);
17
+ if (filterCount !== RUNTIME_TERMINAL_FILTER_COUNT) return {
18
+ ok: false,
19
+ reason: `the sandbox runtime emitted ${filterCount} terminal rules instead of ${RUNTIME_TERMINAL_FILTER_COUNT}, so they cannot be confined to one terminal`
20
+ };
21
+ const ownTerminalFilter = `(literal "${ownTerminalPath}")`;
22
+ return {
23
+ ok: true,
24
+ argv: argv.map((word) => word.replaceAll(RUNTIME_TERMINAL_FILTER, ownTerminalFilter))
25
+ };
26
+ }
27
+ //#endregion
5
28
  //#region session/sandbox-open-launcher.ts
6
29
  var FORWARDED_SIGNALS = [
7
30
  "SIGINT",
@@ -9,6 +32,8 @@ var FORWARDED_SIGNALS = [
9
32
  "SIGHUP"
10
33
  ];
11
34
  var OPEN_NETWORK = { allowAllUnixSockets: false };
35
+ var DEVICE_FOLDER = "/dev";
36
+ var PSEUDO_TERMINAL_PREFIX = "ttys";
12
37
  function fieldOf(record, field) {
13
38
  if (typeof record !== "object" || record === null) return void 0;
14
39
  return Reflect.get(record, field);
@@ -21,9 +46,23 @@ function readOpenPolicy(policyPath) {
21
46
  if (fieldOf(fieldOf(policy, "network"), "allowedDomains") !== void 0) throw new Error("a policy with a domain list must run through the sandbox runtime CLI");
22
47
  return {
23
48
  network: OPEN_NETWORK,
24
- filesystem: FilesystemConfigSchema.parse(fieldOf(policy, "filesystem"))
49
+ filesystem: FilesystemConfigSchema.parse(fieldOf(policy, "filesystem")),
50
+ allowPty: fieldOf(policy, "allowPty") === true
25
51
  };
26
52
  }
53
+ function ownTerminalPath() {
54
+ if (!tty.isatty(0)) throw new Error("a policy with terminal access needs the launcher to run in a terminal");
55
+ const ownDevice = fs.fstatSync(0).rdev;
56
+ const ownName = fs.readdirSync(DEVICE_FOLDER).filter((name) => name.startsWith(PSEUDO_TERMINAL_PREFIX)).find((name) => fs.statSync(path.join(DEVICE_FOLDER, name)).rdev === ownDevice);
57
+ if (ownName === void 0) throw new Error("the launcher terminal is not a pseudo-terminal under /dev");
58
+ return path.join(DEVICE_FOLDER, ownName);
59
+ }
60
+ function sandboxArgv(argv, policy) {
61
+ if (policy.allowPty !== true || process.platform !== "darwin") return argv;
62
+ const confinement = confineToOwnTerminal(argv, ownTerminalPath());
63
+ if (!confinement.ok) throw new Error(confinement.reason);
64
+ return confinement.argv;
65
+ }
27
66
  function exitCodeFor(code, signal) {
28
67
  if (signal === null) return code ?? 0;
29
68
  return FORWARDED_SIGNALS.some((forwarded) => forwarded === signal) ? 0 : 1;
@@ -55,7 +94,7 @@ async function launchInOpenNetworkSandbox() {
55
94
  exitWhenInterrupted();
56
95
  throw wrapFailure;
57
96
  });
58
- const [shell, ...shellArgs] = wrapped.argv;
97
+ const [shell, ...shellArgs] = sandboxArgv(wrapped.argv, openPolicy);
59
98
  if (!shell || shellArgs.at(-1) === commandLine) throw new Error("the sandbox runtime returned the command unwrapped");
60
99
  exitWhenInterrupted();
61
100
  child = spawn(shell, shellArgs, {
@@ -1,4 +1,4 @@
1
- import { o as spawn } from "../chunks/child-process-safe-Ch-Zgxqs.js";
1
+ import { o as spawn } from "../chunks/child-process-safe-DDELk9XC.js";
2
2
  import { t as readStdin } from "../chunks/relay-stdin-CpHvLu6M.js";
3
3
  import { t as postPayload } from "../chunks/loopback-post-DepQfdcM.js";
4
4
  import { n as isRecord } from "../chunks/coerce-NSst8oRP.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glimmervoid",
3
- "version": "0.31.0",
3
+ "version": "0.32.1",
4
4
  "description": "Mission control for coding agents: run and supervise Claude Code, Codex and Grok sessions in parallel git worktrees from one local browser dashboard",
5
5
  "main": "dist/server/index.js",
6
6
  "type": "module",
@@ -1,112 +0,0 @@
1
- import { a as AgentDispatchRequest, i as AgentAttentionRequest, o as AgentSpawnRequest, t as AGENT_API_VERBS } from "./session-fc4pFbon.js";
2
- import crypto from "node:crypto";
3
- var MAX_SPAWNS_IN_FLIGHT = 1;
4
- var SPAWNABLE_DEPTH = 0;
5
- var REFUSAL_REASON = "unknown session";
6
- var INVALID_BODY_STATUS = 400;
7
- function tokensMatch(presented, expected) {
8
- if (presented.length !== expected.length) return false;
9
- try {
10
- return crypto.timingSafeEqual(Buffer.from(presented, "utf8"), Buffer.from(expected, "utf8"));
11
- } catch {
12
- return false;
13
- }
14
- }
15
- function refused() {
16
- return {
17
- ok: false,
18
- status: 404,
19
- reason: REFUSAL_REASON
20
- };
21
- }
22
- function decideAgentRequest({ sessionId, presentedToken, expectedToken, isLoopback, enabled }) {
23
- if (!enabled) return refused();
24
- if (!isLoopback) return refused();
25
- if (!sessionId) return refused();
26
- if (!expectedToken) return refused();
27
- if (!presentedToken) return refused();
28
- if (!tokensMatch(presentedToken, expectedToken)) return refused();
29
- return { ok: true };
30
- }
31
- function decideSpawnAllowance({ liveChildren, lifetimeSpawns, inFlight, depth }) {
32
- if (depth !== SPAWNABLE_DEPTH) return {
33
- ok: false,
34
- status: 403,
35
- reason: "a spawned session may not spawn another"
36
- };
37
- if (inFlight >= MAX_SPAWNS_IN_FLIGHT) return {
38
- ok: false,
39
- status: 429,
40
- reason: "a spawn is already in flight"
41
- };
42
- if (liveChildren >= 3) return {
43
- ok: false,
44
- status: 429,
45
- reason: `at most 3 spawned sessions may be live at once`
46
- };
47
- if (lifetimeSpawns >= 10) return {
48
- ok: false,
49
- status: 429,
50
- reason: `this session has used its 10 spawns`
51
- };
52
- return { ok: true };
53
- }
54
- function isAgentApiVerb(verb) {
55
- return AGENT_API_VERBS.includes(verb);
56
- }
57
- function refuseInvalidBody(issues) {
58
- return {
59
- ok: false,
60
- status: INVALID_BODY_STATUS,
61
- error: issues[0]?.message || "invalid request"
62
- };
63
- }
64
- function parseAgentVerb(verb, payload) {
65
- if (!isAgentApiVerb(verb)) return {
66
- ok: false,
67
- status: 404,
68
- error: REFUSAL_REASON
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
- }
79
- if (verb === "board") return {
80
- ok: true,
81
- verb
82
- };
83
- if (verb === "attention") {
84
- const parsed = AgentAttentionRequest.safeParse(payload);
85
- if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
86
- return {
87
- ok: true,
88
- verb,
89
- request: parsed.data
90
- };
91
- }
92
- const parsed = AgentSpawnRequest.safeParse(payload);
93
- if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
94
- return {
95
- ok: true,
96
- verb,
97
- request: parsed.data
98
- };
99
- }
100
- function deriveChildSessionName(parentName, existingNames) {
101
- const base = `${String(parentName || "").trim() || "session"} agent`;
102
- const taken = new Set(existingNames);
103
- let candidate = base;
104
- let suffix = 1;
105
- while (taken.has(candidate)) {
106
- suffix += 1;
107
- candidate = `${base} ${suffix}`;
108
- }
109
- return candidate;
110
- }
111
- //#endregion
112
- export { isAgentApiVerb as a, deriveChildSessionName as i, decideAgentRequest as n, parseAgentVerb as o, decideSpawnAllowance as r, REFUSAL_REASON as t };
@@ -1,2 +0,0 @@
1
- import { r as execFileSync } from "./child-process-safe-Ch-Zgxqs.js";
2
- export { execFileSync };
@@ -1,2 +0,0 @@
1
- import { c as loadConfigFile } from "./config-store-BCy4FHNG.js";
2
- export { loadConfigFile };
@@ -1,2 +0,0 @@
1
- import { t as getRtkPath } from "./rtk-resolver-BGDzw5XK.js";
2
- export { getRtkPath };