glimmervoid 0.0.0-stage → 0.29.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 (55) hide show
  1. package/LICENSE +48 -0
  2. package/README.md +197 -2
  3. package/dist/bin/glimmervoid.js +259 -0
  4. package/dist/chunks/adapters-DIavI9-i.js +2 -0
  5. package/dist/chunks/adapters-Dlvu1FVB.js +566 -0
  6. package/dist/chunks/agent-api-cli-ClOzm28U.js +71 -0
  7. package/dist/chunks/agent-api-core-D6LHrpSL.js +103 -0
  8. package/dist/chunks/agent-setup-cli-C1CQ8Nkk.js +137 -0
  9. package/dist/chunks/ascii-figure-core-pDAwtlKO.js +45 -0
  10. package/dist/chunks/child-process-safe-Cz22RwlG.js +69 -0
  11. package/dist/chunks/config-path-core-DFt-TemS.js +38 -0
  12. package/dist/chunks/config-store-DtPUFVaO.js +1400 -0
  13. package/dist/chunks/config-store-DtUGwi4-.js +2 -0
  14. package/dist/chunks/contracts-JKChPhZ0.js +2998 -0
  15. package/dist/chunks/grok-COekzawt.js +407 -0
  16. package/dist/chunks/hook-relay-core-BHfYFnYV.js +88 -0
  17. package/dist/chunks/ingest-core-DWI1Mbu4.js +342 -0
  18. package/dist/chunks/ingest-editor-core-BuI1gMF_.js +445 -0
  19. package/dist/chunks/loopback-post-C7C22eYi.js +79 -0
  20. package/dist/chunks/main-BVDjy7vH.js +42740 -0
  21. package/dist/chunks/node-pty-preflight-CK1knGIR.js +162 -0
  22. package/dist/chunks/pair-cli-BQQnhkkc.js +110 -0
  23. package/dist/chunks/path-doctor-C23VAqeu.js +63 -0
  24. package/dist/chunks/refocus-core-BKQKllq7.js +38 -0
  25. package/dist/chunks/relay-stdin-CpHvLu6M.js +20 -0
  26. package/dist/chunks/remote-config-BHoDFCpo.js +521 -0
  27. package/dist/chunks/rtk-hook-core-DRYrKwYP.js +26 -0
  28. package/dist/chunks/rtk-resolver-DDVVNRBT.js +2 -0
  29. package/dist/chunks/rtk-resolver-oGmO-ew7.js +58 -0
  30. package/dist/chunks/runtime-paths-CVvq20A4.js +51 -0
  31. package/dist/chunks/sandbox-deps-BwvbDBDl.js +67 -0
  32. package/dist/chunks/session-CJtOveHl.js +162 -0
  33. package/dist/chunks/spawn-command-Cc40FiZI.js +134 -0
  34. package/dist/chunks/visions-cli-DUZnopGY.js +98 -0
  35. package/dist/chunks/visions-setup-C_kJobsy.js +1753 -0
  36. package/dist/client/assets/favicon-CKygeLwW.svg +7 -0
  37. package/dist/client/assets/index-BTwYgSAH.js +248 -0
  38. package/dist/client/assets/index-DgA708PE.css +1 -0
  39. package/dist/client/index.html +108 -0
  40. package/dist/package.json +3 -0
  41. package/dist/scripts/postinstall-path-check.js +36 -0
  42. package/dist/server/index.js +92 -0
  43. package/dist/session/command-hook-relay.js +16 -0
  44. package/dist/session/hook-relay.js +24 -0
  45. package/dist/session/rtk-relay.js +90 -0
  46. package/dist/session/statusline-relay.js +82 -0
  47. package/dist/session/visions-relay.js +627 -0
  48. package/dist/tools/vscode-visions/extension.js +289 -0
  49. package/dist/tools/vscode-visions/lsp-convert.js +80 -0
  50. package/dist/tools/vscode-visions/package.json +32 -0
  51. package/dist/tools/vscode-visions/visions-lsp-core.js +112 -0
  52. package/package.json +95 -4
  53. package/scripts/postinstall.mjs +4 -0
  54. package/scripts/prepare-build.js +38 -0
  55. package/scripts/recover-handoff.mjs +82 -0
@@ -0,0 +1,67 @@
1
+ import { i as execSync } from "./child-process-safe-Cz22RwlG.js";
2
+ import { r as resolvePathCommandMatches } from "./spawn-command-Cc40FiZI.js";
3
+ //#region server/core/sandbox-deps-core.ts
4
+ var LINUX_SANDBOX_BINARIES = Object.freeze(["bwrap", "socat"]);
5
+ var NO_SANDBOX_BINARIES = Object.freeze([]);
6
+ var SANDBOX_INSTALL_HINT = "Install bubblewrap and socat, for example: sudo apt install bubblewrap socat";
7
+ var SANDBOXED_LANE_NAMES = Object.freeze([
8
+ "team review",
9
+ "Keep mergeable repairs",
10
+ "workflow sessions",
11
+ "benchmark runs"
12
+ ]);
13
+ function requiredSandboxBinaries(platform) {
14
+ return platform === "linux" ? LINUX_SANDBOX_BINARIES : NO_SANDBOX_BINARIES;
15
+ }
16
+ function sandboxDependencyReport({ platform, binariesOnPath }) {
17
+ const requiredBinaries = requiredSandboxBinaries(platform);
18
+ const missingBinaries = requiredBinaries.filter((binary) => !binariesOnPath.has(binary));
19
+ return {
20
+ platform,
21
+ requiredBinaries,
22
+ missingBinaries,
23
+ installHint: missingBinaries.length > 0 ? SANDBOX_INSTALL_HINT : null
24
+ };
25
+ }
26
+ function missingBinariesPhrase(report) {
27
+ return `${report.missingBinaries.join(" and ")} ${report.missingBinaries.length === 1 ? "is" : "are"} not on PATH`;
28
+ }
29
+ function sandboxSpawnRefusal(report) {
30
+ if (report.missingBinaries.length === 0) return null;
31
+ return `not started: the Claude Code sandbox needs ${report.requiredBinaries.join(" and ")}, and ${missingBinariesPhrase(report)}. ${report.installHint}`;
32
+ }
33
+ function sandboxBootWarning(report) {
34
+ if (report.missingBinaries.length === 0) return null;
35
+ return `[sandbox] ${missingBinariesPhrase(report)}, so ${SANDBOXED_LANE_NAMES.join(", ")} will refuse to start sandboxed sessions. ${report.installHint}`;
36
+ }
37
+ function sandboxDoctorRows(report) {
38
+ if (report.requiredBinaries.length === 0) return [["sandbox", `nothing to check on ${report.platform}`]];
39
+ const binaryRows = report.requiredBinaries.map((binary) => [binary, report.missingBinaries.includes(binary) ? "MISSING" : "found"]);
40
+ if (report.installHint === null) return binaryRows;
41
+ return [...binaryRows, ["hint", report.installHint]];
42
+ }
43
+ function sandboxInstallNotice(report) {
44
+ if (report.installHint === null) return null;
45
+ return `glimmervoid: ${missingBinariesPhrase(report)}; team review, Keep mergeable, workflow sessions and benchmark runs need ${report.requiredBinaries.join(" and ")}. ${report.installHint}`;
46
+ }
47
+ //#endregion
48
+ //#region server/sandbox-deps.ts
49
+ function probeSandboxDependencies({ platform = process.platform, exec = execSync } = {}) {
50
+ return sandboxDependencyReport({
51
+ platform,
52
+ binariesOnPath: new Set(requiredSandboxBinaries(platform).filter((binary) => resolvePathCommandMatches(binary, {
53
+ platform,
54
+ exec
55
+ }).length > 0))
56
+ });
57
+ }
58
+ function checkSandboxDependencies({ probe = probeSandboxDependencies, log = console } = {}) {
59
+ const report = probe();
60
+ const warning = sandboxBootWarning(report);
61
+ if (warning !== null) log.warn(warning);
62
+ const refusal = sandboxSpawnRefusal(report);
63
+ return () => refusal;
64
+ }
65
+ var allowSandboxedSpawn = () => null;
66
+ //#endregion
67
+ export { sandboxInstallNotice as a, sandboxDoctorRows as i, checkSandboxDependencies as n, probeSandboxDependencies as r, allowSandboxedSpawn as t };
@@ -0,0 +1,162 @@
1
+ import { z } from "zod";
2
+ //#region shared/states.ts
3
+ var STATES = Object.freeze({
4
+ DORMANT: "DORMANT",
5
+ INITIALIZING: "INITIALIZING",
6
+ STARTING: "STARTING",
7
+ RUNNING: "RUNNING",
8
+ WAITING: "WAITING",
9
+ IDLE: "IDLE",
10
+ COMPLETE: "COMPLETE",
11
+ DONE: "DONE",
12
+ FAILED: "FAILED"
13
+ });
14
+ Object.freeze({
15
+ [STATES.DORMANT]: "Dormant",
16
+ [STATES.INITIALIZING]: "Preparing",
17
+ [STATES.STARTING]: "Starting",
18
+ [STATES.RUNNING]: "Working",
19
+ [STATES.WAITING]: "Needs Input",
20
+ [STATES.IDLE]: "Idle",
21
+ [STATES.COMPLETE]: "Complete",
22
+ [STATES.DONE]: "Exited",
23
+ [STATES.FAILED]: "Failed"
24
+ });
25
+ Object.freeze({
26
+ [STATES.DORMANT]: "○",
27
+ [STATES.INITIALIZING]: "◌",
28
+ [STATES.STARTING]: "◐",
29
+ [STATES.RUNNING]: "●",
30
+ [STATES.WAITING]: "◆",
31
+ [STATES.IDLE]: "◍",
32
+ [STATES.FAILED]: "▲",
33
+ [STATES.DONE]: "■",
34
+ [STATES.COMPLETE]: "◇"
35
+ });
36
+ var KILLABLE_STATES = Object.freeze([
37
+ STATES.INITIALIZING,
38
+ STATES.STARTING,
39
+ STATES.RUNNING,
40
+ STATES.WAITING,
41
+ STATES.IDLE,
42
+ STATES.COMPLETE
43
+ ]);
44
+ var RESTARTABLE_STATES = Object.freeze([STATES.DONE, STATES.FAILED]);
45
+ var MERGEABLE_LIVE_STATES = Object.freeze([
46
+ STATES.WAITING,
47
+ STATES.IDLE,
48
+ STATES.COMPLETE
49
+ ]);
50
+ var DETAIL_FIELD_BY_TOOL = Object.freeze({
51
+ Bash: "command",
52
+ Read: "file_path",
53
+ Edit: "file_path",
54
+ MultiEdit: "file_path",
55
+ Write: "file_path",
56
+ NotebookEdit: "notebook_path",
57
+ Grep: "pattern",
58
+ Glob: "pattern",
59
+ WebFetch: "url",
60
+ WebSearch: "query",
61
+ Task: "description",
62
+ Agent: "description",
63
+ Skill: "skill"
64
+ });
65
+ function firstDetailLine(text) {
66
+ const line = text.split(/\r?\n/, 1)[0]?.trim() ?? "";
67
+ if (line.length <= 160) return line;
68
+ return `${line.slice(0, 157)}...`;
69
+ }
70
+ function toolDetailFieldValue(toolName, toolInput) {
71
+ const field = DETAIL_FIELD_BY_TOOL[toolName];
72
+ if (!field) return null;
73
+ if (!toolInput || typeof toolInput !== "object" || Array.isArray(toolInput)) return null;
74
+ const value = toolInput[field];
75
+ return typeof value === "string" ? value : null;
76
+ }
77
+ function toolDetailLine(toolName, toolInput) {
78
+ const fieldValue = toolDetailFieldValue(toolName, toolInput);
79
+ return fieldValue === null ? "" : firstDetailLine(fieldValue);
80
+ }
81
+ var TASK_TITLE_CONTROL_CHARACTERS = /[\x00-\x1f\x7f-\x9f]/;
82
+ var PROMPT_DETAIL_HIDDEN_CHARACTERS = new RegExp(`${TASK_TITLE_CONTROL_CHARACTERS.source}|[\\p{Cf}\\u2028\\u2029]`, "u");
83
+ var TaskTitle = z.string().refine((title) => !TASK_TITLE_CONTROL_CHARACTERS.test(title)).trim().max(120);
84
+ var SessionState = z.enum(STATES);
85
+ var PendingWakeup = z.object({
86
+ at: z.number().finite().nullable(),
87
+ kind: z.string(),
88
+ reason: z.string().nullable()
89
+ }).passthrough();
90
+ var ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
91
+ var hasNoHiddenCharacters = (text) => !PROMPT_DETAIL_HIDDEN_CHARACTERS.test(text);
92
+ var PendingPromptQuestion = z.object({
93
+ text: z.string().min(1).max(300).refine(hasNoHiddenCharacters),
94
+ options: z.array(z.string().min(1).max(80).refine(hasNoHiddenCharacters)).min(1).max(8),
95
+ multiSelect: z.boolean()
96
+ });
97
+ var PendingPromptDetail = z.object({
98
+ toolName: z.string().max(160),
99
+ summary: z.string().max(160),
100
+ isComplete: z.boolean(),
101
+ question: PendingPromptQuestion.nullable().optional()
102
+ });
103
+ var SessionSnapshot = z.object({
104
+ id: z.string(),
105
+ name: z.string(),
106
+ taskTitle: TaskTitle.nullable().default(null),
107
+ taskTitleIsCustom: z.boolean().default(false),
108
+ path: z.string(),
109
+ agent: z.string(),
110
+ state: SessionState,
111
+ stateSince: z.number(),
112
+ sleeping: z.boolean(),
113
+ dangerouslySkipPermissions: z.boolean(),
114
+ ephemeral: z.boolean(),
115
+ isWorktree: z.boolean(),
116
+ isWorkspace: z.boolean().default(false),
117
+ resumeSessionId: z.string().nullable(),
118
+ activeAgents: z.number().int().nonnegative(),
119
+ awaitingBackgroundTasks: z.boolean(),
120
+ hasEndedTurn: z.boolean().default(false),
121
+ pendingWakeup: PendingWakeup.nullable(),
122
+ pendingPromptKind: z.string().nullable(),
123
+ pendingPromptDetail: PendingPromptDetail.nullable().default(null),
124
+ hasPlan: z.boolean().default(false),
125
+ mergeStatus: z.string().nullable(),
126
+ mergeReason: z.string().nullable(),
127
+ worktreeNotice: z.string().nullable(),
128
+ effectiveBase: z.string().nullable(),
129
+ auditLog: z.array(z.unknown())
130
+ }).passthrough();
131
+ function isSamePromptQuestion(left, right) {
132
+ if (!left || !right) return !left && !right;
133
+ return left.text === right.text && left.multiSelect === right.multiSelect && left.options.length === right.options.length && left.options.every((option, index) => option === right.options[index]);
134
+ }
135
+ var AGENT_URL_ENV = "GLIMMERVOID_AGENT_URL";
136
+ var AGENT_API_VERBS = [
137
+ "spawn",
138
+ "attention",
139
+ "board"
140
+ ];
141
+ var AgentSpawnRequest = z.object({
142
+ prompt: z.string({ error: "prompt must be a string" }).min(1, { error: "prompt must not be empty" }).max(2e4, { error: "prompt must be at most 20000 characters" }).refine((prompt) => !prompt.trimStart().startsWith("-"), { message: "prompt must not start with a dash, which the agent CLI would read as an option" }),
143
+ name: z.string({ error: "name must be a string" }).min(1, { error: "name must not be empty" }).max(200, { error: "name must be at most 200 characters" }).optional(),
144
+ agent: z.string({ error: "agent must be a string" }).min(1, { error: "agent must not be empty" }).max(40, { error: "agent must be at most 40 characters" }).optional()
145
+ }).strict();
146
+ var AgentAttentionRequest = z.object({ note: z.string({ error: "note must be a string" }).min(1, { error: "note must not be empty" }).max(500, { error: "note must be at most 500 characters" }) }).strict();
147
+ z.union([z.object({
148
+ ok: z.literal(true),
149
+ pending: z.boolean()
150
+ }).strict(), z.object({
151
+ ok: z.literal(false),
152
+ error: z.string()
153
+ }).strict()]);
154
+ z.object({
155
+ id: SessionSnapshot.shape.id,
156
+ name: SessionSnapshot.shape.name,
157
+ agent: SessionSnapshot.shape.agent,
158
+ state: SessionSnapshot.shape.state,
159
+ ephemeral: SessionSnapshot.shape.ephemeral
160
+ }).strict();
161
+ //#endregion
162
+ export { toolDetailLine as _, AgentSpawnRequest as a, RESTARTABLE_STATES as b, PendingPromptQuestion as c, SessionState as d, TASK_TITLE_CONTROL_CHARACTERS as f, toolDetailFieldValue as g, firstDetailLine as h, AgentAttentionRequest as i, PendingWakeup as l, isSamePromptQuestion as m, AGENT_URL_ENV as n, PROMPT_DETAIL_HIDDEN_CHARACTERS as o, TaskTitle as p, ASK_USER_QUESTION_TOOL_NAME as r, PendingPromptDetail as s, AGENT_API_VERBS as t, SessionSnapshot as u, KILLABLE_STATES as v, STATES as x, MERGEABLE_LIVE_STATES as y };
@@ -0,0 +1,134 @@
1
+ import path from "node:path";
2
+ //#region session/core/spawn-command.ts
3
+ function classifyCommandKind(resolvedPath) {
4
+ if (!resolvedPath) return "unresolved";
5
+ const ext = (resolvedPath.match(/\.[^.\\/]+$/) || [""])[0].toLowerCase();
6
+ return ext === ".exe" || ext === ".com" ? "exe" : "shim";
7
+ }
8
+ function dedupePathMatches(matches, platform = process.platform) {
9
+ const pathApi = platform === "win32" ? path.win32 : path.posix;
10
+ const seen = /* @__PURE__ */ new Set();
11
+ const unique = [];
12
+ for (const candidate of matches) {
13
+ let normalized = pathApi.normalize(candidate.trim());
14
+ if (normalized.length > 1) normalized = normalized.replace(/[\\/]+$/, "");
15
+ const key = platform === "win32" ? normalized.toLowerCase() : normalized;
16
+ if (seen.has(key)) continue;
17
+ seen.add(key);
18
+ unique.push(normalized);
19
+ }
20
+ return unique;
21
+ }
22
+ var PATH_PROBE_OPTIONS = {
23
+ encoding: "utf8",
24
+ stdio: [
25
+ "ignore",
26
+ "pipe",
27
+ "ignore"
28
+ ],
29
+ timeout: 2e3
30
+ };
31
+ function pathProbesFor(name, platform) {
32
+ if (platform === "win32") return [{
33
+ shellCommand: `where ${name}`,
34
+ file: "where",
35
+ args: [name]
36
+ }];
37
+ return [{
38
+ shellCommand: `which -a ${name}`,
39
+ file: "which",
40
+ args: ["-a", name]
41
+ }, {
42
+ shellCommand: `sh -c "command -v ${name}"`,
43
+ file: "sh",
44
+ args: [
45
+ "-c",
46
+ "command -v \"$1\"",
47
+ "sh",
48
+ name
49
+ ]
50
+ }];
51
+ }
52
+ function resolveCommandMatches(name, { platform, runProbe }) {
53
+ for (const probe of pathProbesFor(name, platform)) {
54
+ let matches = [];
55
+ try {
56
+ matches = dedupePathMatches(runProbe(probe).split(/\r?\n/).filter((line) => line.trim()), platform);
57
+ } catch {
58
+ matches = [];
59
+ }
60
+ if (matches.length > 0) return matches;
61
+ }
62
+ return [];
63
+ }
64
+ function resolvePathCommandMatches(name, { platform, exec }) {
65
+ return resolveCommandMatches(name, {
66
+ platform,
67
+ runProbe: (probe) => exec(probe.shellCommand, PATH_PROBE_OPTIONS)
68
+ });
69
+ }
70
+ function resolveArgvCommandMatches(name, { platform, execFile }) {
71
+ return resolveCommandMatches(name, {
72
+ platform,
73
+ runProbe: (probe) => execFile(probe.file, probe.args, PATH_PROBE_OPTIONS)
74
+ });
75
+ }
76
+ function isAbsoluteCommandPath(name, platform) {
77
+ return (platform === "win32" ? path.win32 : path.posix).isAbsolute(name);
78
+ }
79
+ function resolveAgentCommand({ name, platform = process.platform, execFile, pathExists }) {
80
+ if (isAbsoluteCommandPath(name, platform)) {
81
+ if (typeof pathExists !== "function") throw new TypeError("resolveAgentCommand requires a pathExists probe for an absolute command");
82
+ if (pathExists(name)) return {
83
+ path: name,
84
+ kind: classifyCommandKind(name)
85
+ };
86
+ console.warn(`[glimmervoid] could not resolve '${name}'`);
87
+ return {
88
+ path: null,
89
+ kind: "unresolved"
90
+ };
91
+ }
92
+ if (typeof execFile !== "function") throw new TypeError("resolveAgentCommand requires an execFile function");
93
+ const matches = resolveArgvCommandMatches(name, {
94
+ platform,
95
+ execFile
96
+ });
97
+ if (matches.length === 0) {
98
+ console.warn(`[glimmervoid] could not resolve '${name}'`);
99
+ return {
100
+ path: null,
101
+ kind: "unresolved"
102
+ };
103
+ }
104
+ const resolvedPath = matches[0];
105
+ if (process.env.GLIMMERVOID_DEBUG_SPAWN) console.log(`[glimmervoid] resolved '${name}' (first match wins): ${resolvedPath}`);
106
+ if (matches.length > 1) console.warn(`[glimmervoid] multiple '${name}' on PATH (Bun shim risk):\n ${matches.join("\n ")}`);
107
+ const kind = classifyCommandKind(resolvedPath);
108
+ if (platform === "win32") console.log(`[glimmervoid] ${name} spawn strategy: ${kind === "exe" ? "direct exe" : "cmd.exe shim fallback"}`);
109
+ return {
110
+ path: resolvedPath,
111
+ kind
112
+ };
113
+ }
114
+ function buildAgentSpawnCommand({ name, platform, resolved, argGroups = [] }) {
115
+ const childArgs = argGroups.flatMap((group) => group || []);
116
+ if (platform !== "win32") return {
117
+ file: name,
118
+ args: childArgs
119
+ };
120
+ if (resolved && resolved.kind === "exe" && resolved.path) return {
121
+ file: resolved.path,
122
+ args: childArgs
123
+ };
124
+ return {
125
+ file: "cmd.exe",
126
+ args: [
127
+ "/c",
128
+ name,
129
+ ...childArgs
130
+ ]
131
+ };
132
+ }
133
+ //#endregion
134
+ export { resolveAgentCommand as n, resolvePathCommandMatches as r, buildAgentSpawnCommand as t };
@@ -0,0 +1,98 @@
1
+ import { t as renderTable } from "./ascii-figure-core-pDAwtlKO.js";
2
+ import { a as relayInvocationOptions, c as unwireEverything, d as extensionIdOf, f as buildSetupGuide, h as isExtensionInstalled, i as packVsix, l as wireEverything, m as recipeIds, o as resolveRelayInvocation, p as commandLine, r as editorExtensions, s as resolvedEditorPaths, t as RELAY_PATH, u as editorTargets } from "./visions-setup-C_kJobsy.js";
3
+ import fs from "node:fs";
4
+ //#region server/visions-cli.ts
5
+ function fileOutcomeRows(files) {
6
+ return files.map((file) => [file.label, `${file.action}: ${file.filePath}`]);
7
+ }
8
+ async function runInstall(args) {
9
+ const requestedIndex = args.indexOf("--editor");
10
+ const requested = requestedIndex >= 0 ? args[requestedIndex + 1] || null : null;
11
+ const report = await wireEverything({ requested });
12
+ if (!report.ok) {
13
+ console.error(`visions install: ${report.reason}`);
14
+ return 1;
15
+ }
16
+ const rows = [];
17
+ for (const result of report.extensions.results) rows.push([result.label, result.ok ? "extension installed" : `FAILED: ${result.detail}`]);
18
+ if (report.extensions.results.length === 0) rows.push(["VS Code family", report.extensions.reason]);
19
+ rows.push(...fileOutcomeRows(report.files));
20
+ console.log(renderTable({
21
+ title: "Visions install",
22
+ rows,
23
+ terminalColumns: process.stdout.columns
24
+ }));
25
+ console.log(`\nrelay ${report.invocation ? commandLine(report.invocation) : "(unresolved)"}`);
26
+ console.log("reload any open editor window, then open a markdown file inside a project the daemon knows.");
27
+ return report.extensions.results.some((result) => !result.ok) ? 1 : 0;
28
+ }
29
+ async function runUninstall() {
30
+ const report = await unwireEverything();
31
+ const rows = [];
32
+ for (const result of report.extensions.results) rows.push([result.label, result.ok ? `extension ${result.detail}` : `FAILED: ${result.detail}`]);
33
+ rows.push(...fileOutcomeRows(report.files));
34
+ console.log(renderTable({
35
+ title: "Visions uninstall",
36
+ rows,
37
+ terminalColumns: process.stdout.columns
38
+ }));
39
+ return 0;
40
+ }
41
+ async function runStatus() {
42
+ const { manifest } = packVsix();
43
+ const extensionId = extensionIdOf(manifest);
44
+ const editors = Object.entries(resolvedEditorPaths());
45
+ const rows = [["relay", fs.existsSync(RELAY_PATH) ? commandLine(resolveRelayInvocation()) : `MISSING: ${RELAY_PATH}`], ["extension", `${extensionId} ${manifest.version}`]];
46
+ if (editors.length === 0) rows.push(["VS Code family", "none found on PATH or on disk"]);
47
+ for (const [command, commandPath] of editors) {
48
+ const installed = isExtensionInstalled(await editorExtensions(commandPath), extensionId);
49
+ rows.push([command, installed ? "extension installed" : "not installed"]);
50
+ }
51
+ for (const target of editorTargets()) rows.push([target.label, `${fs.existsSync(target.filePath) ? "wired" : "not wired"}: ${target.filePath}`]);
52
+ console.log(renderTable({
53
+ title: "Visions status",
54
+ rows,
55
+ terminalColumns: process.stdout.columns
56
+ }));
57
+ return 0;
58
+ }
59
+ async function runRelay() {
60
+ const { createRelay } = await import("../session/visions-relay.js");
61
+ createRelay().start();
62
+ return new Promise(() => {});
63
+ }
64
+ function runSetup(args) {
65
+ const editorIndex = args.indexOf("--editor");
66
+ const editorId = editorIndex >= 0 ? args[editorIndex + 1] || null : null;
67
+ const { chosen: invocation, absolute, onPath } = relayInvocationOptions();
68
+ const guide = buildSetupGuide({
69
+ editorId,
70
+ invocation
71
+ });
72
+ if (!guide.ok) {
73
+ console.error(`visions setup: ${guide.reason} (known: ${recipeIds().join(", ")})`);
74
+ return 1;
75
+ }
76
+ console.log(`The Visions relay is one stdio LSP server: ${commandLine(invocation)}`);
77
+ if (onPath) console.log(`An editor launched from a desktop menu may not see your PATH; there, use: ${commandLine(absolute)}`);
78
+ console.log("Turning Visions on wires these for you; this is the manual form.\n");
79
+ for (const section of guide.sections) {
80
+ console.log(`${section.label} (${section.where})`);
81
+ console.log(`${section.snippet}\n`);
82
+ }
83
+ console.log("Findings reach the dashboard Visions tab whichever client mirrors the buffer.");
84
+ console.log("The relay tries port 5173 then 3000; GLIMMERVOID_PORT or --port names another one.");
85
+ return 0;
86
+ }
87
+ async function runVisionsCli(args = []) {
88
+ const command = args[0];
89
+ if (command === "relay") return runRelay();
90
+ if (command === "install") return runInstall(args.slice(1));
91
+ if (command === "uninstall") return runUninstall();
92
+ if (command === "setup") return runSetup(args.slice(1));
93
+ if (command === "status") return runStatus();
94
+ console.error("Usage: glimmervoid visions relay\n glimmervoid visions install [--editor <command>]\n glimmervoid visions uninstall\n glimmervoid visions setup [--editor <id>]\n glimmervoid visions status");
95
+ return 1;
96
+ }
97
+ //#endregion
98
+ export { runVisionsCli };