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.
- package/LICENSE +48 -0
- package/README.md +197 -2
- package/dist/bin/glimmervoid.js +259 -0
- package/dist/chunks/adapters-DIavI9-i.js +2 -0
- package/dist/chunks/adapters-Dlvu1FVB.js +566 -0
- package/dist/chunks/agent-api-cli-ClOzm28U.js +71 -0
- package/dist/chunks/agent-api-core-D6LHrpSL.js +103 -0
- package/dist/chunks/agent-setup-cli-C1CQ8Nkk.js +137 -0
- package/dist/chunks/ascii-figure-core-pDAwtlKO.js +45 -0
- package/dist/chunks/child-process-safe-Cz22RwlG.js +69 -0
- package/dist/chunks/config-path-core-DFt-TemS.js +38 -0
- package/dist/chunks/config-store-DtPUFVaO.js +1400 -0
- package/dist/chunks/config-store-DtUGwi4-.js +2 -0
- package/dist/chunks/contracts-JKChPhZ0.js +2998 -0
- package/dist/chunks/grok-COekzawt.js +407 -0
- package/dist/chunks/hook-relay-core-BHfYFnYV.js +88 -0
- package/dist/chunks/ingest-core-DWI1Mbu4.js +342 -0
- package/dist/chunks/ingest-editor-core-BuI1gMF_.js +445 -0
- package/dist/chunks/loopback-post-C7C22eYi.js +79 -0
- package/dist/chunks/main-BVDjy7vH.js +42740 -0
- package/dist/chunks/node-pty-preflight-CK1knGIR.js +162 -0
- package/dist/chunks/pair-cli-BQQnhkkc.js +110 -0
- package/dist/chunks/path-doctor-C23VAqeu.js +63 -0
- package/dist/chunks/refocus-core-BKQKllq7.js +38 -0
- package/dist/chunks/relay-stdin-CpHvLu6M.js +20 -0
- package/dist/chunks/remote-config-BHoDFCpo.js +521 -0
- package/dist/chunks/rtk-hook-core-DRYrKwYP.js +26 -0
- package/dist/chunks/rtk-resolver-DDVVNRBT.js +2 -0
- package/dist/chunks/rtk-resolver-oGmO-ew7.js +58 -0
- package/dist/chunks/runtime-paths-CVvq20A4.js +51 -0
- package/dist/chunks/sandbox-deps-BwvbDBDl.js +67 -0
- package/dist/chunks/session-CJtOveHl.js +162 -0
- package/dist/chunks/spawn-command-Cc40FiZI.js +134 -0
- package/dist/chunks/visions-cli-DUZnopGY.js +98 -0
- package/dist/chunks/visions-setup-C_kJobsy.js +1753 -0
- package/dist/client/assets/favicon-CKygeLwW.svg +7 -0
- package/dist/client/assets/index-BTwYgSAH.js +248 -0
- package/dist/client/assets/index-DgA708PE.css +1 -0
- package/dist/client/index.html +108 -0
- package/dist/package.json +3 -0
- package/dist/scripts/postinstall-path-check.js +36 -0
- package/dist/server/index.js +92 -0
- package/dist/session/command-hook-relay.js +16 -0
- package/dist/session/hook-relay.js +24 -0
- package/dist/session/rtk-relay.js +90 -0
- package/dist/session/statusline-relay.js +82 -0
- package/dist/session/visions-relay.js +627 -0
- package/dist/tools/vscode-visions/extension.js +289 -0
- package/dist/tools/vscode-visions/lsp-convert.js +80 -0
- package/dist/tools/vscode-visions/package.json +32 -0
- package/dist/tools/vscode-visions/visions-lsp-core.js +112 -0
- package/package.json +95 -4
- package/scripts/postinstall.mjs +4 -0
- package/scripts/prepare-build.js +38 -0
- 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 };
|