glimmervoid 0.0.0-stage → 0.30.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 (59) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +195 -2
  3. package/dist/bin/glimmervoid.js +275 -0
  4. package/dist/chunks/adapters-Dho1VSY5.js +2 -0
  5. package/dist/chunks/adapters-zPDx1Xox.js +575 -0
  6. package/dist/chunks/agent-api-cli-D0MmtEdz.js +71 -0
  7. package/dist/chunks/agent-api-core-Dz0r21y9.js +103 -0
  8. package/dist/chunks/agent-setup-cli-B5Atxr3F.js +139 -0
  9. package/dist/chunks/ascii-figure-core-pDAwtlKO.js +45 -0
  10. package/dist/chunks/child-process-safe-DRGsp0TE.js +69 -0
  11. package/dist/chunks/child-process-safe-DvQjXsgz.js +2 -0
  12. package/dist/chunks/config-path-core-DFt-TemS.js +38 -0
  13. package/dist/chunks/config-store-CC8T3okC.js +2 -0
  14. package/dist/chunks/config-store-mm7MgzoL.js +1412 -0
  15. package/dist/chunks/contracts-DGkKNh9W.js +3020 -0
  16. package/dist/chunks/grok-DuU8xVLZ.js +436 -0
  17. package/dist/chunks/hook-command-core-DclEoE9e.js +14 -0
  18. package/dist/chunks/hook-relay-core-BHfYFnYV.js +88 -0
  19. package/dist/chunks/hook-tools-pSJia7ks.js +74 -0
  20. package/dist/chunks/ingest-core-DWI1Mbu4.js +342 -0
  21. package/dist/chunks/ingest-editor-core-BuI1gMF_.js +445 -0
  22. package/dist/chunks/loopback-post-C7C22eYi.js +79 -0
  23. package/dist/chunks/main-CuIZQPhZ.js +43559 -0
  24. package/dist/chunks/node-pty-preflight-CK1knGIR.js +162 -0
  25. package/dist/chunks/pair-cli-w-gCAF-1.js +110 -0
  26. package/dist/chunks/path-doctor-C23VAqeu.js +63 -0
  27. package/dist/chunks/refocus-core-BKQKllq7.js +38 -0
  28. package/dist/chunks/relay-stdin-CpHvLu6M.js +20 -0
  29. package/dist/chunks/remote-config-C2ytQwrs.js +525 -0
  30. package/dist/chunks/rtk-hook-core-Bl6gYHPN.js +133 -0
  31. package/dist/chunks/rtk-resolver-CLo-gZzw.js +21 -0
  32. package/dist/chunks/rtk-resolver-CMQAidlI.js +2 -0
  33. package/dist/chunks/runtime-paths-Ci_ksSkj.js +75 -0
  34. package/dist/chunks/runtime-paths-JLrZ3wyi.js +2 -0
  35. package/dist/chunks/sandbox-deps-Dd5-kZnf.js +67 -0
  36. package/dist/chunks/session-Cez8aIWg.js +164 -0
  37. package/dist/chunks/spawn-command-Cc40FiZI.js +134 -0
  38. package/dist/chunks/visions-cli-BXQFIBCX.js +98 -0
  39. package/dist/chunks/visions-setup-CvVnOe1r.js +1753 -0
  40. package/dist/client/assets/favicon-CKygeLwW.svg +7 -0
  41. package/dist/client/assets/index-B1MFijjb.css +1 -0
  42. package/dist/client/assets/index-CU1iPPdn.js +249 -0
  43. package/dist/client/index.html +108 -0
  44. package/dist/package.json +3 -0
  45. package/dist/scripts/postinstall-path-check.js +36 -0
  46. package/dist/server/index.js +92 -0
  47. package/dist/session/command-hook-relay.js +16 -0
  48. package/dist/session/hook-relay.js +24 -0
  49. package/dist/session/hook-tool-relay.js +107 -0
  50. package/dist/session/statusline-relay.js +82 -0
  51. package/dist/session/visions-relay.js +627 -0
  52. package/dist/tools/vscode-visions/extension.js +289 -0
  53. package/dist/tools/vscode-visions/lsp-convert.js +80 -0
  54. package/dist/tools/vscode-visions/package.json +32 -0
  55. package/dist/tools/vscode-visions/visions-lsp-core.js +112 -0
  56. package/package.json +96 -4
  57. package/scripts/postinstall.mjs +4 -0
  58. package/scripts/prepare-build.js +38 -0
  59. package/scripts/recover-handoff.mjs +82 -0
@@ -0,0 +1,108 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <meta name="color-scheme" content="dark light">
7
+ <link rel="icon" type="image/svg+xml" href="/assets/favicon-CKygeLwW.svg">
8
+ <title>Glimmervoid</title>
9
+ <style>html,body{background:var(--bg,#0a0810);height:100%;color:var(--text,#c8c0e0);margin:0;padding:0;font-family:Segoe UI,system-ui,sans-serif}.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: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: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: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-CU1iPPdn.js"></script>
11
+ <link rel="stylesheet" crossorigin href="/assets/index-B1MFijjb.css">
12
+ </head>
13
+ <body>
14
+ <div class="loading-screen" id="loading-screen">
15
+ <div class="loading-title">Glimmervoid</div>
16
+ <div class="loading-spinner"></div>
17
+ <div class="loading-status" id="loading-status">Connecting to server...</div>
18
+ </div>
19
+
20
+ <div class="shutdown-screen" id="shutdown-screen">
21
+ <div class="loading-title">Glimmervoid</div>
22
+ <div class="loading-spinner"></div>
23
+ <div class="shutdown-status" id="shutdown-status">Shutting down sessions...</div>
24
+ </div>
25
+
26
+ <div class="app-shell">
27
+ <header class="header">
28
+ <div class="header-inner">
29
+ <div class="header-left">
30
+ <div class="header-brand">
31
+ <h1 class="header-title">Glimmervoid</h1>
32
+ <div class="status-indicator" id="status-indicator">
33
+ <span class="header-connection" id="connection-status" role="status" aria-label="Server connection">
34
+ <span class="connection-dot"></span>
35
+ <span class="connection-label">Connecting</span>
36
+ </span>
37
+ </div>
38
+ </div>
39
+ <div class="header-tabs" id="header-tabs" role="tablist" aria-label="Primary views">
40
+ <button class="header-tab" id="tab-focus" type="button" role="tab" aria-selected="true" aria-controls="view-focus" tabindex="0">Focus</button>
41
+ <button class="header-tab" id="tab-calm" type="button" role="tab" aria-selected="false" aria-controls="view-calm" tabindex="-1" hidden>Calm</button>
42
+ <button class="header-tab" id="tab-prs" type="button" role="tab" aria-selected="false" aria-controls="view-prs" tabindex="-1">Reviews<span class="tab-activity" id="tab-prs-activity" aria-hidden="true"></span></button>
43
+ <button class="header-tab" id="tab-issues" type="button" role="tab" aria-selected="false" aria-controls="view-issues" tabindex="-1">Issues</button>
44
+ <button class="header-tab" id="tab-usage" type="button" role="tab" aria-selected="false" aria-controls="view-usage" tabindex="-1">Usage<span class="tab-activity" id="tab-usage-activity" aria-hidden="true"></span></button>
45
+ <button class="header-tab" id="tab-radar" type="button" role="tab" aria-selected="false" aria-controls="view-radar" tabindex="-1">Radar<span class="tab-activity" id="tab-radar-activity" aria-hidden="true"></span></button>
46
+ <button class="header-tab" id="tab-visions" type="button" role="tab" aria-selected="false" aria-controls="view-visions" tabindex="-1">Visions<span class="tab-activity" id="tab-visions-activity" aria-hidden="true"></span></button>
47
+ <button class="header-tab" id="tab-hooks" type="button" role="tab" aria-selected="false" aria-controls="view-hooks" tabindex="-1">Hooks</button>
48
+ <button class="header-tab" id="tab-trace" type="button" role="tab" aria-selected="false" aria-controls="view-trace" tabindex="-1">Trace</button>
49
+ <button class="header-tab" id="tab-benchmarks" type="button" role="tab" aria-selected="false" aria-controls="view-benchmarks" tabindex="-1" hidden>Bench</button>
50
+ <button class="header-tab" id="tab-settings" type="button" role="tab" aria-selected="false" aria-controls="view-settings" tabindex="-1">Settings</button>
51
+ </div>
52
+ </div>
53
+ <div class="header-right">
54
+ <span class="header-aggregate" id="aggregate-status" role="status" aria-live="polite"></span>
55
+ <button class="btn-add-header" id="btn-add-session-header" type="button" title="Add a new session">+ Session</button>
56
+ <button class="btn-help" id="btn-help" type="button" title="Keyboard shortcuts" aria-label="Keyboard shortcuts and version">?</button>
57
+ <button class="btn-mute" id="btn-mute" type="button" title="Mute alerts" aria-label="Mute alerts" aria-pressed="false">&#9834;</button>
58
+ <div class="header-menu" id="power-menu">
59
+ <button class="btn-menu btn-power" id="btn-power" type="button" title="Server power" aria-label="Server power" aria-haspopup="menu" aria-expanded="false" aria-controls="power-menu-dropdown"><svg class="btn-power-icon" viewBox="0 0 16 16" width="15" height="15" aria-hidden="true" focusable="false"><path d="M8 1.5v6" /><path d="M4.4 3.6a5.5 5.5 0 1 0 7.2 0" /></svg></button>
60
+ <div class="header-menu-dropdown" id="power-menu-dropdown" role="menu">
61
+ <button class="menu-item menu-item-warning" id="btn-restart" type="button" role="menuitem"><span class="menu-item-glyph">&#8634;</span>Restart Server</button>
62
+ <div class="menu-divider" id="menu-divider-shutdown"></div>
63
+ <button class="menu-item menu-item-danger" id="btn-shutdown" type="button" role="menuitem"><span class="menu-item-glyph">&#9632;</span>Shut Down</button>
64
+ </div>
65
+ </div>
66
+ </div>
67
+ </div>
68
+ </header>
69
+ <div class="update-banner" id="update-banner" role="status" hidden>
70
+ <span class="update-banner-text" id="update-banner-text"></span>
71
+ <a class="update-banner-link" id="update-banner-link" href="https://github.com/johncwaters/glimmervoid/releases" target="_blank" rel="noopener noreferrer" hidden>View changes</a>
72
+ <a class="update-banner-link" id="update-banner-update" href="#settings/machine-updates/update-actions" hidden>Update</a>
73
+ <code class="update-banner-cmd" id="update-banner-cmd"></code>
74
+ <button class="update-banner-copy" id="update-banner-copy" type="button">Copy</button>
75
+ <span class="update-banner-copy-status" id="update-banner-copy-status" role="status"></span>
76
+ <button class="update-banner-dismiss" id="update-banner-dismiss" type="button" aria-label="Dismiss update notice">&times;</button>
77
+ </div>
78
+ <div class="update-banner" id="telemetry-banner" role="status" hidden>
79
+ <span class="update-banner-text">Glimmervoid sends anonymous usage and error data to help improve it. No paths, prompts or terminal output.</span>
80
+ <a class="update-banner-link" id="telemetry-banner-settings" href="#settings/privacy/telemetry-enabled">Open settings</a>
81
+ <button class="update-banner-copy telemetry-banner-dismiss" id="telemetry-banner-dismiss" type="button">Dismiss</button>
82
+ </div>
83
+ <div class="app-body" id="app-body">
84
+ <main class="app-main" id="app-main">
85
+ <section class="sessions" id="sessions-container">
86
+ </section>
87
+ <section class="calm-view" id="view-calm" role="tabpanel" aria-labelledby="tab-calm" hidden></section>
88
+ <section class="radar-view" id="view-radar" role="tabpanel" aria-labelledby="tab-radar" hidden></section>
89
+ <section class="pr-view" id="view-prs" role="tabpanel" aria-labelledby="tab-prs" hidden></section>
90
+ <section class="issues-view" id="view-issues" role="tabpanel" aria-labelledby="tab-issues" hidden></section>
91
+ <section class="usage-view" id="view-usage" role="tabpanel" aria-labelledby="tab-usage" hidden></section>
92
+ <section class="visions-view" id="view-visions" role="tabpanel" aria-labelledby="tab-visions" hidden></section>
93
+ <section class="hooks-view" id="view-hooks" role="tabpanel" aria-labelledby="tab-hooks" hidden></section>
94
+ <section class="trace-view" id="view-trace" role="tabpanel" aria-labelledby="tab-trace" hidden></section>
95
+ <section class="bench-view" id="view-benchmarks" role="tabpanel" aria-labelledby="tab-benchmarks" hidden></section>
96
+ <section class="settings-view" id="view-settings" role="tabpanel" aria-labelledby="tab-settings" hidden></section>
97
+ <section class="focus-view" id="view-focus" role="tabpanel" aria-labelledby="tab-focus" hidden>
98
+ <div class="focus-rail" id="focus-rail" role="listbox" aria-label="Session roster" aria-keyshortcuts="ArrowUp ArrowDown Alt+ArrowUp Alt+ArrowDown"></div>
99
+ <hr class="focus-rail-resizer" id="focus-rail-resizer" aria-orientation="vertical" aria-label="Resize session rail" aria-valuenow="240" tabindex="0">
100
+ <div class="focus-center" id="focus-center"></div>
101
+ </section>
102
+ </main>
103
+ <aside class="app-sidebar" id="review-sidebar" aria-label="Session review"></aside>
104
+ </div>
105
+ <div id="health-footer-mount"></div>
106
+ </div>
107
+ </body>
108
+ </html>
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,36 @@
1
+ import { a as sandboxInstallNotice, r as probeSandboxDependencies } from "../chunks/sandbox-deps-Dd5-kZnf.js";
2
+ import { n as npmGlobalBinDir, r as onPath, t as formatPathNotice } from "../chunks/path-doctor-C23VAqeu.js";
3
+ import os from "node:os";
4
+ //#region scripts/postinstall-path-check.ts
5
+ function printPathNotice() {
6
+ if (process.env.npm_config_global !== "true") return;
7
+ const platform = process.platform;
8
+ const binDir = npmGlobalBinDir({
9
+ env: process.env,
10
+ platform,
11
+ homedir: os.homedir()
12
+ });
13
+ if (!binDir) return;
14
+ const pathEnv = process.env.PATH || process.env.Path || "";
15
+ const onPathFlag = onPath(binDir, {
16
+ pathEnv,
17
+ platform
18
+ });
19
+ process.stdout.write(`\n${formatPathNotice({
20
+ installedBinDir: binDir,
21
+ onPathFlag,
22
+ platform
23
+ })}\n\n`);
24
+ }
25
+ function printSandboxNotice() {
26
+ const notice = sandboxInstallNotice(probeSandboxDependencies());
27
+ if (notice !== null) process.stdout.write(`${notice}\n`);
28
+ }
29
+ try {
30
+ printPathNotice();
31
+ } catch {}
32
+ try {
33
+ printSandboxNotice();
34
+ } catch {}
35
+ //#endregion
36
+ export {};
@@ -0,0 +1,92 @@
1
+ import { a as formatNodePtyBootRefusal, t as probeNodePty } from "../chunks/node-pty-preflight-CK1knGIR.js";
2
+ import { a as packageRoot } from "../chunks/runtime-paths-Ci_ksSkj.js";
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+ //#region scripts/recover-handoff.mjs
7
+ var PREVIOUS_DIST_BACKUP_NAME = "prev-dist";
8
+ var PREVIOUS_DEPENDENCIES_BACKUP_NAME = "prev-node_modules";
9
+ var QUARANTINE_NAME_PREFIX = "broken-";
10
+ function isRestoreEntry(entry) {
11
+ if (!entry || typeof entry !== "object") return false;
12
+ if (typeof entry.from !== "string") return false;
13
+ if (entry.to !== "dist" && entry.to !== "node_modules") return false;
14
+ if (!entry.from || path.dirname(entry.from) !== ".") return false;
15
+ return entry.from !== "." && entry.from !== "..";
16
+ }
17
+ function restore(updatePath, root, fromName, toName) {
18
+ const sourcePath = path.join(updatePath, fromName);
19
+ const targetPath = path.join(root, toName);
20
+ if (fs.existsSync(targetPath) || !fs.existsSync(sourcePath)) return;
21
+ fs.renameSync(sourcePath, targetPath);
22
+ console.log(`restored ${fromName} to ${toName}`);
23
+ }
24
+ function restoreOverBrokenTarget(updatePath, root, fromName, toName) {
25
+ const sourcePath = path.join(updatePath, fromName);
26
+ const targetPath = path.join(root, toName);
27
+ if (!fs.existsSync(sourcePath)) return fs.existsSync(targetPath);
28
+ if (fs.existsSync(targetPath)) {
29
+ const quarantinePath = path.join(updatePath, `${QUARANTINE_NAME_PREFIX}${toName}`);
30
+ fs.rmSync(quarantinePath, {
31
+ recursive: true,
32
+ force: true
33
+ });
34
+ fs.renameSync(targetPath, quarantinePath);
35
+ console.log(`quarantined ${toName} as ${QUARANTINE_NAME_PREFIX}${toName}`);
36
+ }
37
+ fs.renameSync(sourcePath, targetPath);
38
+ console.log(`restored ${fromName} to ${toName}`);
39
+ return true;
40
+ }
41
+ function restoreEverythingHandedOff(root) {
42
+ const updatePath = path.join(root, ".glimmervoid", "update");
43
+ restore(updatePath, root, PREVIOUS_DEPENDENCIES_BACKUP_NAME, "node_modules");
44
+ restore(updatePath, root, PREVIOUS_DIST_BACKUP_NAME, "dist");
45
+ const markerPath = path.join(updatePath, "restore.json");
46
+ if (!fs.existsSync(markerPath)) return;
47
+ const marker = JSON.parse(fs.readFileSync(markerPath, "utf8"));
48
+ const entries = Array.isArray(marker?.restore) ? marker.restore : [];
49
+ let everyEntryApplied = true;
50
+ for (const entry of entries) {
51
+ if (!isRestoreEntry(entry)) continue;
52
+ if (restoreOverBrokenTarget(updatePath, root, entry.from, entry.to)) continue;
53
+ everyEntryApplied = false;
54
+ console.log(`could not restore ${entry.from} to ${entry.to}`);
55
+ }
56
+ if (!everyEntryApplied) return;
57
+ fs.rmSync(markerPath, { force: true });
58
+ console.log("removed restore marker");
59
+ }
60
+ function recoverHandoff(root) {
61
+ try {
62
+ restoreEverythingHandedOff(root);
63
+ } catch (error) {
64
+ const message = error instanceof Error ? error.message : String(error);
65
+ console.log(`handoff recovery could not finish: ${message}`);
66
+ }
67
+ }
68
+ function wasRunAsTheRecoveryScript() {
69
+ const entryPath = process.argv[1];
70
+ if (!entryPath) return false;
71
+ if (path.basename(entryPath) !== "recover-handoff.mjs") return false;
72
+ return pathToFileURL(entryPath).href === import.meta.url;
73
+ }
74
+ if (wasRunAsTheRecoveryScript()) {
75
+ recoverHandoff(path.resolve(process.argv[2] || path.join(import.meta.dirname, "..")));
76
+ process.exitCode = 0;
77
+ }
78
+ //#endregion
79
+ //#region server/index.ts
80
+ recoverHandoff(packageRoot);
81
+ var nodePty = await probeNodePty();
82
+ if (!nodePty.ok) {
83
+ console.error(formatNodePtyBootRefusal({
84
+ platform: process.platform,
85
+ packageDir: nodePty.packageDir,
86
+ reason: nodePty.reason
87
+ }));
88
+ process.exit(1);
89
+ }
90
+ await import("../chunks/main-CuIZQPhZ.js");
91
+ //#endregion
92
+ export {};
@@ -0,0 +1,16 @@
1
+ import { t as readStdin } from "../chunks/relay-stdin-CpHvLu6M.js";
2
+ import { t as postPayload } from "../chunks/loopback-post-C7C22eYi.js";
3
+ import { n as sessionStartContextOutput } from "../chunks/refocus-core-BKQKllq7.js";
4
+ //#region session/command-hook-relay.ts
5
+ async function main(argv = process.argv.slice(2), stdin = process.stdin, stdout = process.stdout) {
6
+ const [postUrl] = argv;
7
+ const body = await readStdin(stdin);
8
+ if (!postUrl) return 0;
9
+ const responseBody = await postPayload(postUrl, body);
10
+ const contextOutput = sessionStartContextOutput(responseBody);
11
+ if (contextOutput !== null) stdout.write(contextOutput);
12
+ return 0;
13
+ }
14
+ if (process.argv[1] === import.meta.filename) main().then((code) => process.exit(code)).catch(() => process.exit(0));
15
+ //#endregion
16
+ export { main };
@@ -0,0 +1,24 @@
1
+ import { t as readStdin } from "../chunks/relay-stdin-CpHvLu6M.js";
2
+ import { r as decideRelayPost } from "../chunks/hook-relay-core-BHfYFnYV.js";
3
+ import { n as postToLoopback } from "../chunks/loopback-post-C7C22eYi.js";
4
+ //#region session/hook-relay.ts
5
+ async function main(argv = process.argv.slice(2), stdin = process.stdin, env = process.env) {
6
+ const [event] = argv;
7
+ const body = await readStdin(stdin);
8
+ const verdict = decideRelayPost({
9
+ env,
10
+ event,
11
+ payloadBytes: body.length
12
+ });
13
+ if (!verdict.post || !verdict.url) return {
14
+ code: 0,
15
+ reason: verdict.reason
16
+ };
17
+ return {
18
+ code: 0,
19
+ reason: (await postToLoopback(verdict.url, body)).reason
20
+ };
21
+ }
22
+ if (process.argv[1] === import.meta.filename) main().then((result) => process.exit(result.code)).catch(() => process.exit(0));
23
+ //#endregion
24
+ export { main };
@@ -0,0 +1,107 @@
1
+ import { o as spawn } from "../chunks/child-process-safe-DRGsp0TE.js";
2
+ import { t as readStdin } from "../chunks/relay-stdin-CpHvLu6M.js";
3
+ import { a as SANE_YOLO_PATH_ENV, n as RTK_PATH_ENV, r as normalizeRtkHookResponse } from "../chunks/rtk-hook-core-Bl6gYHPN.js";
4
+ //#region session/hook-tool-relay.ts
5
+ var RTK_TIMEOUT_MS = 3e3;
6
+ function runHookTool(toolId, binPath, body) {
7
+ return new Promise((resolve) => {
8
+ let settled = false;
9
+ let timer = null;
10
+ const done = (text) => {
11
+ if (settled) return;
12
+ settled = true;
13
+ if (timer) clearTimeout(timer);
14
+ resolve(text);
15
+ };
16
+ let child;
17
+ try {
18
+ const command = toolId === "rtk" ? binPath : process.execPath;
19
+ child = spawn(command, toolId === "rtk" ? ["hook", "claude"] : [
20
+ binPath,
21
+ "hook",
22
+ "--grok-build"
23
+ ], { stdio: [
24
+ "pipe",
25
+ "pipe",
26
+ "ignore"
27
+ ] });
28
+ } catch {
29
+ done("");
30
+ return;
31
+ }
32
+ const childStdout = child.stdout;
33
+ const childStdin = child.stdin;
34
+ if (!childStdout || !childStdin) {
35
+ try {
36
+ child.kill();
37
+ } catch {}
38
+ done("");
39
+ return;
40
+ }
41
+ timer = setTimeout(() => {
42
+ try {
43
+ child.kill();
44
+ } catch {}
45
+ done("");
46
+ }, RTK_TIMEOUT_MS);
47
+ const chunks = [];
48
+ let stdoutBytes = 0;
49
+ childStdout.on("data", (chunk) => {
50
+ const bytes = Buffer.from(chunk);
51
+ stdoutBytes += bytes.length;
52
+ if (stdoutBytes > 65536) {
53
+ try {
54
+ child.kill();
55
+ } catch {}
56
+ done("");
57
+ return;
58
+ }
59
+ chunks.push(bytes);
60
+ });
61
+ childStdout.on("error", () => done(""));
62
+ child.on("error", () => done(""));
63
+ child.on("close", (code) => done(code === 0 ? Buffer.concat(chunks).toString("utf8") : ""));
64
+ childStdin.on("error", () => {});
65
+ try {
66
+ childStdin.end(body);
67
+ } catch {
68
+ done("");
69
+ }
70
+ });
71
+ }
72
+ async function main(toolId = process.argv[2] ?? "", env = process.env, stdin = process.stdin, stdout = process.stdout, runner = (binPath, body) => runHookTool(toolId === "rtk" ? "rtk" : "saneYolo", binPath, body)) {
73
+ if (toolId !== "rtk" && toolId !== "saneYolo") return {
74
+ code: 0,
75
+ reason: "unknown-tool"
76
+ };
77
+ const configuredPath = env[toolId === "rtk" ? RTK_PATH_ENV : SANE_YOLO_PATH_ENV];
78
+ const binPath = typeof configuredPath === "string" ? configuredPath.trim() : "";
79
+ if (!binPath) return {
80
+ code: 0,
81
+ reason: "no-tool-path"
82
+ };
83
+ const body = await readStdin(stdin);
84
+ if (body.length === 0) return {
85
+ code: 0,
86
+ reason: "empty-payload"
87
+ };
88
+ const toolOutput = await runner(binPath, body);
89
+ const response = toolId === "rtk" ? normalizeRtkHookResponse(toolOutput) : toolOutput;
90
+ if (!response) return {
91
+ code: 0,
92
+ reason: "no-response"
93
+ };
94
+ try {
95
+ stdout.write(toolId === "rtk" ? `${response}\n` : response);
96
+ } catch {}
97
+ return {
98
+ code: 0,
99
+ reason: "forwarded"
100
+ };
101
+ }
102
+ if (process.argv[1] === import.meta.filename) main().then((result) => process.exit(result.code)).catch(() => process.exit(0));
103
+ function runRtk(binPath, body) {
104
+ return runHookTool("rtk", binPath, body);
105
+ }
106
+ //#endregion
107
+ export { RTK_TIMEOUT_MS, main, runHookTool, runRtk };
@@ -0,0 +1,82 @@
1
+ import { o as spawn } from "../chunks/child-process-safe-DRGsp0TE.js";
2
+ import { t as readStdin } from "../chunks/relay-stdin-CpHvLu6M.js";
3
+ import { t as postPayload } from "../chunks/loopback-post-C7C22eYi.js";
4
+ //#region session/statusline-relay.ts
5
+ var NO_CHAIN = "-";
6
+ function isPlainObject(value) {
7
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
8
+ }
9
+ function decodeChainCommand(encoded) {
10
+ if (!encoded || encoded === "-") return null;
11
+ try {
12
+ return Buffer.from(encoded, "base64").toString("utf8").trim() || null;
13
+ } catch {
14
+ return null;
15
+ }
16
+ }
17
+ function fallbackLine(payload) {
18
+ const parts = [];
19
+ const modelField = payload?.model;
20
+ const model = isPlainObject(modelField) ? modelField.display_name : void 0;
21
+ if (typeof model === "string" && model.trim()) parts.push(model.trim());
22
+ const costField = payload?.cost;
23
+ const cost = isPlainObject(costField) ? costField.total_cost_usd : void 0;
24
+ if (typeof cost === "number" && Number.isFinite(cost) && cost > 0) parts.push(`$${cost.toFixed(2)}`);
25
+ return parts.join(" ");
26
+ }
27
+ function parsePayload(raw) {
28
+ try {
29
+ const parsed = JSON.parse(String(raw));
30
+ if (isPlainObject(parsed)) return parsed;
31
+ return null;
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
36
+ function runChain(command, stdinBody) {
37
+ return new Promise((resolve) => {
38
+ let child;
39
+ try {
40
+ child = spawn(command, {
41
+ shell: true,
42
+ stdio: [
43
+ "pipe",
44
+ "inherit",
45
+ "inherit"
46
+ ]
47
+ });
48
+ } catch {
49
+ resolve(0);
50
+ return;
51
+ }
52
+ let settled = false;
53
+ const finish = (code) => {
54
+ if (settled) return;
55
+ settled = true;
56
+ resolve(typeof code === "number" ? code : 0);
57
+ };
58
+ child.on("error", () => finish(0));
59
+ child.on("close", (code) => finish(code));
60
+ child.stdin?.on("error", () => {});
61
+ try {
62
+ child.stdin?.end(stdinBody);
63
+ } catch {}
64
+ });
65
+ }
66
+ async function main(argv = process.argv.slice(2), stdin = process.stdin, stdout = process.stdout) {
67
+ const [postUrl, chainEncoded] = argv;
68
+ const raw = await readStdin(stdin);
69
+ const chainCommand = decodeChainCommand(chainEncoded);
70
+ const post = postUrl ? postPayload(postUrl, raw) : Promise.resolve();
71
+ if (!chainCommand) {
72
+ const line = fallbackLine(parsePayload(raw));
73
+ if (line) stdout.write(`${line}\n`);
74
+ await post;
75
+ return 0;
76
+ }
77
+ const [code] = await Promise.all([runChain(chainCommand, raw), post]);
78
+ return code;
79
+ }
80
+ if (process.argv[1] === import.meta.filename) main().then((code) => process.exit(code)).catch(() => process.exit(0));
81
+ //#endregion
82
+ export { NO_CHAIN, decodeChainCommand, fallbackLine, main, parsePayload };