glimmervoid 0.38.2 → 0.40.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.
- package/README.md +1 -1
- package/dist/bin/glimmervoid.js +33 -42
- package/dist/chunks/{adapters-CAHxZYT3.js → adapters-B6tbX3Aj.js} +27 -14
- package/dist/chunks/{adapters-DDjC7_vG.js → adapters-CXQfLoyj.js} +1 -1
- package/dist/chunks/agent-api-cli-BBech5lF.js +1 -0
- package/dist/chunks/{agent-api-cli-B5Tm0wXO.js → agent-api-cli-BNHJTmNW.js} +44 -77
- package/dist/chunks/agent-api-core-DDrJQEdE.js +304 -0
- package/dist/chunks/{agent-setup-cli-DmMfCw5O.js → agent-setup-cli-CeBBwKuL.js} +2 -2
- package/dist/chunks/config-store-BZpN2djp.js +1 -0
- package/dist/chunks/{config-store-BUNZs4j7.js → config-store-DqMScSdg.js} +82 -268
- package/dist/chunks/contracts-CloExMlS.js +680 -0
- package/dist/chunks/{contracts-HVCEJfxs.js → control-messages-DpBaniJi.js} +1275 -1021
- package/dist/chunks/{git-version-rWZjF2Px.js → git-version-CJQMfxtZ.js} +2 -2
- package/dist/chunks/{grok-B6bsCgdd.js → grok-BLzhApwT.js} +7 -8
- package/dist/chunks/{guardrails-deps-Cb-ki4EU.js → guardrails-deps-CLxK4J-g.js} +1 -1
- package/dist/chunks/{json-file-CIJf0Cel.js → json-file-DFCTvPjj.js} +3 -7
- package/dist/chunks/{main-BNSbP-Yk.js → main-DDU8IvFD.js} +28791 -31978
- package/dist/chunks/{pair-cli-DNp8i5L4.js → pair-cli-CsOVTQGJ.js} +2 -2
- package/dist/chunks/{remote-config-C_s2pnLC.js → remote-config-HlABuLTp.js} +2 -2
- package/dist/chunks/{session-BlT68ppa.js → session-BwB43SCa.js} +119 -71
- package/dist/chunks/{session-routes-CT1JrjoT.js → session-routes-DNJzsckH.js} +25 -10
- package/dist/chunks/{settings-cli-BbzxCyG5.js → settings-cli-DkkbK-dj.js} +30 -156
- package/dist/chunks/settings-readout-core-DrXT4aWm.js +201 -0
- package/dist/chunks/{ssh-sign-cli-C74BGTQS.js → ssh-sign-cli-CYeKRevK.js} +2 -2
- package/dist/client/assets/index-BK9jLR47.js +148 -0
- package/dist/client/assets/index-CU_uqJmi.css +2 -0
- package/dist/client/assets/xterm-kR64YvZ-.js +79 -0
- package/dist/client/assets/zod-BRLv4KqJ.js +55 -0
- package/dist/client/index.html +7 -3
- package/dist/scripts/postinstall-path-check.js +21 -3
- package/dist/server/index.js +1 -1
- package/package.json +3 -4
- package/dist/chunks/agent-api-cli-BDu1CxZf.js +0 -1
- package/dist/chunks/agent-api-core-B_mUSenR.js +0 -341
- package/dist/chunks/browser-config-BrBT8269.js +0 -762
- package/dist/chunks/config-CjawSOBk.js +0 -219
- package/dist/chunks/config-store-MAVQhGMh.js +0 -1
- package/dist/chunks/factory-D7ryES9n.js +0 -240
- package/dist/chunks/knowledge-graph-cli-ByUJoKw_.js +0 -1354
- package/dist/client/assets/index-B5uVtedd.css +0 -1
- package/dist/client/assets/index-b13-NGGS.js +0 -275
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { a as AgentEditRequest, i as AgentAttentionRequest, l as AgentSettingsRequest, s as AgentPullRequestRequest, t as AGENT_API_VERBS, u as AgentSpawnRequest } from "./session-BwB43SCa.js";
|
|
2
|
+
import { a as pullRequestKeyFromReference } from "./control-messages-DpBaniJi.js";
|
|
3
|
+
import { n as NO_OWN_WORKTREE_REASON, t as COMMAND_ROUTES } from "./session-routes-DNJzsckH.js";
|
|
4
|
+
import crypto from "node:crypto";
|
|
5
|
+
var MAX_SPAWNS_IN_FLIGHT = 1;
|
|
6
|
+
var REFUSAL_REASON = "unknown session";
|
|
7
|
+
var INVALID_BODY_STATUS = 400;
|
|
8
|
+
var ROLE_REFUSED_STATUS = 403;
|
|
9
|
+
var PUSH_REFUSED_STATUS = 409;
|
|
10
|
+
var PUSH_REFUSAL_COPY = Object.freeze({
|
|
11
|
+
"no-worktree": () => NO_OWN_WORKTREE_REASON,
|
|
12
|
+
"merge-in-progress": () => "a merge for this session is already running, so try again when it ends",
|
|
13
|
+
"not-continuable": () => "this session cannot be merged in its current state",
|
|
14
|
+
destroyed: () => "this session is ending",
|
|
15
|
+
"nothing-to-commit": () => "no commit on this branch is missing from the integration branch, so commit your work first",
|
|
16
|
+
"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`,
|
|
17
|
+
"not-fast-forward": ({ base }) => `${base} could not be fast-forwarded to this branch, and a push is never forced`,
|
|
18
|
+
"base-diverged": ({ base }) => `the local ${base} and origin/${base} have diverged, which the operator has to reconcile`
|
|
19
|
+
});
|
|
20
|
+
function tokensMatch(presented, expected) {
|
|
21
|
+
if (presented.length !== expected.length) return false;
|
|
22
|
+
try {
|
|
23
|
+
return crypto.timingSafeEqual(Buffer.from(presented, "utf8"), Buffer.from(expected, "utf8"));
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function refused() {
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
status: 404,
|
|
32
|
+
reason: REFUSAL_REASON
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function decideAgentRequest({ sessionId, presentedToken, expectedToken, isLoopback }) {
|
|
36
|
+
if (!isLoopback) return refused();
|
|
37
|
+
if (!sessionId) return refused();
|
|
38
|
+
if (!expectedToken) return refused();
|
|
39
|
+
if (!presentedToken) return refused();
|
|
40
|
+
if (!tokensMatch(presentedToken, expectedToken)) return refused();
|
|
41
|
+
return { ok: true };
|
|
42
|
+
}
|
|
43
|
+
function decideSpawnAllowance({ liveChildren, lifetimeSpawns, inFlight }) {
|
|
44
|
+
if (inFlight >= MAX_SPAWNS_IN_FLIGHT) return {
|
|
45
|
+
ok: false,
|
|
46
|
+
status: 429,
|
|
47
|
+
reason: "a spawn is already in flight"
|
|
48
|
+
};
|
|
49
|
+
if (liveChildren >= 3) return {
|
|
50
|
+
ok: false,
|
|
51
|
+
status: 429,
|
|
52
|
+
reason: `at most 3 spawned sessions may be live at once`
|
|
53
|
+
};
|
|
54
|
+
if (lifetimeSpawns >= 10) return {
|
|
55
|
+
ok: false,
|
|
56
|
+
status: 429,
|
|
57
|
+
reason: `this session has used its 10 spawns`
|
|
58
|
+
};
|
|
59
|
+
return { ok: true };
|
|
60
|
+
}
|
|
61
|
+
function describeRoleRefusal(verb, caller) {
|
|
62
|
+
const route = COMMAND_ROUTES[verb](caller);
|
|
63
|
+
if (route.answers) return null;
|
|
64
|
+
if (route.code) return {
|
|
65
|
+
status: PUSH_REFUSED_STATUS,
|
|
66
|
+
body: {
|
|
67
|
+
ok: false,
|
|
68
|
+
reason: route.code,
|
|
69
|
+
error: route.reason
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
return {
|
|
73
|
+
status: ROLE_REFUSED_STATUS,
|
|
74
|
+
body: {
|
|
75
|
+
ok: false,
|
|
76
|
+
error: route.reason
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function isAgentApiVerb(verb) {
|
|
81
|
+
return AGENT_API_VERBS.includes(verb);
|
|
82
|
+
}
|
|
83
|
+
function refuseInvalidBody(issues) {
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
status: INVALID_BODY_STATUS,
|
|
87
|
+
error: issues[0]?.message || "invalid request"
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function bodyParser(schema) {
|
|
91
|
+
return (payload) => {
|
|
92
|
+
const parsed = schema.safeParse(payload);
|
|
93
|
+
if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
|
|
94
|
+
return {
|
|
95
|
+
ok: true,
|
|
96
|
+
request: parsed.data
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
var parseEmptyBody = () => ({
|
|
101
|
+
ok: true,
|
|
102
|
+
request: {}
|
|
103
|
+
});
|
|
104
|
+
var parsePullRequestBody = (payload) => {
|
|
105
|
+
const parsed = AgentPullRequestRequest.safeParse(payload);
|
|
106
|
+
if (!parsed.success) return refuseInvalidBody(parsed.error.issues);
|
|
107
|
+
const pullRequestKey = pullRequestKeyFromReference(parsed.data.pr);
|
|
108
|
+
if (!pullRequestKey) return {
|
|
109
|
+
ok: false,
|
|
110
|
+
status: INVALID_BODY_STATUS,
|
|
111
|
+
error: "pr must be a GitHub pull request url or owner/repo#number"
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
ok: true,
|
|
115
|
+
request: { pullRequestKey }
|
|
116
|
+
};
|
|
117
|
+
};
|
|
118
|
+
var REQUEST_PARSERS = Object.freeze({
|
|
119
|
+
spawn: bodyParser(AgentSpawnRequest),
|
|
120
|
+
attention: bodyParser(AgentAttentionRequest),
|
|
121
|
+
board: parseEmptyBody,
|
|
122
|
+
push: parseEmptyBody,
|
|
123
|
+
edit: bodyParser(AgentEditRequest),
|
|
124
|
+
limits: parseEmptyBody,
|
|
125
|
+
review: parsePullRequestBody,
|
|
126
|
+
reviews: parseEmptyBody,
|
|
127
|
+
prs: parseEmptyBody,
|
|
128
|
+
"link-pr": parsePullRequestBody,
|
|
129
|
+
settings: bodyParser(AgentSettingsRequest)
|
|
130
|
+
});
|
|
131
|
+
function parseAgentVerb(verb, payload) {
|
|
132
|
+
if (!isAgentApiVerb(verb)) return {
|
|
133
|
+
ok: false,
|
|
134
|
+
status: 404,
|
|
135
|
+
error: REFUSAL_REASON
|
|
136
|
+
};
|
|
137
|
+
const parsed = REQUEST_PARSERS[verb](payload);
|
|
138
|
+
if (!parsed.ok) return parsed;
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
verb,
|
|
142
|
+
request: parsed.request
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
function describePushLanding(landing) {
|
|
146
|
+
if (!landing.merged) {
|
|
147
|
+
const reason = landing.reason || "unknown";
|
|
148
|
+
const explain = PUSH_REFUSAL_COPY[reason];
|
|
149
|
+
return {
|
|
150
|
+
status: PUSH_REFUSED_STATUS,
|
|
151
|
+
body: {
|
|
152
|
+
ok: false,
|
|
153
|
+
reason,
|
|
154
|
+
error: explain ? explain(landing) : `the merge stopped: ${reason}`
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
if (landing.pushed) return {
|
|
159
|
+
status: 200,
|
|
160
|
+
body: {
|
|
161
|
+
ok: true,
|
|
162
|
+
landedOn: landing.base ?? null,
|
|
163
|
+
pushed: true
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
return {
|
|
167
|
+
status: 200,
|
|
168
|
+
body: {
|
|
169
|
+
ok: true,
|
|
170
|
+
landedOn: landing.base ?? null,
|
|
171
|
+
pushed: false,
|
|
172
|
+
note: "landed locally and nothing was pushed, because the repository has no origin remote or origin did not take a fast-forward"
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function projectReviews({ configured, reason, inFlight, queued, drafts }) {
|
|
177
|
+
const identity = ({ key, title, url, author }) => ({
|
|
178
|
+
key,
|
|
179
|
+
title,
|
|
180
|
+
url,
|
|
181
|
+
author
|
|
182
|
+
});
|
|
183
|
+
return {
|
|
184
|
+
ok: true,
|
|
185
|
+
configured,
|
|
186
|
+
reason: reason ?? null,
|
|
187
|
+
reviewing: inFlight.map((review) => ({
|
|
188
|
+
...identity(review),
|
|
189
|
+
phase: review.phase
|
|
190
|
+
})),
|
|
191
|
+
queued: queued.map(identity),
|
|
192
|
+
drafts: drafts.map((draft) => ({
|
|
193
|
+
...identity(draft),
|
|
194
|
+
status: draft.status,
|
|
195
|
+
verdict: draft.verdict,
|
|
196
|
+
summary: draft.summary,
|
|
197
|
+
comments: draft.comments.length,
|
|
198
|
+
isOutOfDate: draft.liveHead !== void 0 && draft.liveHead !== draft.reviewedHead
|
|
199
|
+
}))
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function projectMyPrs(snapshot) {
|
|
203
|
+
if (!snapshot) return {
|
|
204
|
+
ok: true,
|
|
205
|
+
configured: false,
|
|
206
|
+
prs: []
|
|
207
|
+
};
|
|
208
|
+
return {
|
|
209
|
+
ok: true,
|
|
210
|
+
configured: snapshot.configured,
|
|
211
|
+
prs: snapshot.prs.map((pr) => ({
|
|
212
|
+
key: pr.key,
|
|
213
|
+
title: pr.title,
|
|
214
|
+
url: pr.url,
|
|
215
|
+
state: pr.state,
|
|
216
|
+
isDraft: pr.isDraft,
|
|
217
|
+
stage: pr.stage,
|
|
218
|
+
reviewDecision: pr.reviewDecision,
|
|
219
|
+
approvals: pr.approvals,
|
|
220
|
+
unresolvedThreads: pr.unresolvedThreads,
|
|
221
|
+
behindBy: pr.behindBy,
|
|
222
|
+
mergeable: pr.mergeable,
|
|
223
|
+
isInMergeQueue: pr.isInMergeQueue,
|
|
224
|
+
checks: {
|
|
225
|
+
state: pr.checks.state,
|
|
226
|
+
failing: pr.checks.failing
|
|
227
|
+
}
|
|
228
|
+
}))
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
function deriveChildSessionName(parentName, existingNames) {
|
|
232
|
+
const base = `${String(parentName || "").trim() || "session"} agent`;
|
|
233
|
+
const taken = new Set(existingNames);
|
|
234
|
+
let candidate = base;
|
|
235
|
+
let suffix = 1;
|
|
236
|
+
while (taken.has(candidate)) {
|
|
237
|
+
suffix += 1;
|
|
238
|
+
candidate = `${base} ${suffix}`;
|
|
239
|
+
}
|
|
240
|
+
return candidate;
|
|
241
|
+
}
|
|
242
|
+
var USAGE_COLUMN_WIDTH = 20;
|
|
243
|
+
var AGENT_COMMAND_HELP = Object.freeze({
|
|
244
|
+
spawn: {
|
|
245
|
+
usage: "spawn <prompt>",
|
|
246
|
+
summary: "Start a sibling session on that prompt",
|
|
247
|
+
missingArgumentHint: "glimmervoid spawn: this command needs text, for example \"glimmervoid spawn check the failing test\""
|
|
248
|
+
},
|
|
249
|
+
attention: {
|
|
250
|
+
usage: "attention <note>",
|
|
251
|
+
summary: "Flag this session as needing the operator",
|
|
252
|
+
missingArgumentHint: "glimmervoid attention: this command needs text, for example \"glimmervoid attention check the failing test\""
|
|
253
|
+
},
|
|
254
|
+
board: {
|
|
255
|
+
usage: "board",
|
|
256
|
+
summary: "List the live sessions",
|
|
257
|
+
missingArgumentHint: null
|
|
258
|
+
},
|
|
259
|
+
push: {
|
|
260
|
+
usage: "push",
|
|
261
|
+
summary: "Land this session's commits on the integration branch and push it",
|
|
262
|
+
missingArgumentHint: null
|
|
263
|
+
},
|
|
264
|
+
edit: {
|
|
265
|
+
usage: "edit <path>",
|
|
266
|
+
summary: "Open a text file for the operator to edit in the dashboard",
|
|
267
|
+
missingArgumentHint: "glimmervoid edit: this command needs a file path, for example \"glimmervoid edit drafts/post.md\""
|
|
268
|
+
},
|
|
269
|
+
review: {
|
|
270
|
+
usage: "review <pr>",
|
|
271
|
+
summary: "Queue a team review of a pull request; the draft waits in the Reviews tab for the operator to post",
|
|
272
|
+
missingArgumentHint: "glimmervoid review: this command needs a pull request, for example \"glimmervoid review https://github.com/acme/app/pull/12\" or \"glimmervoid review acme/app#12\""
|
|
273
|
+
},
|
|
274
|
+
reviews: {
|
|
275
|
+
usage: "reviews",
|
|
276
|
+
summary: "List the Reviews tab: reviews running, queued and drafted",
|
|
277
|
+
missingArgumentHint: null
|
|
278
|
+
},
|
|
279
|
+
prs: {
|
|
280
|
+
usage: "prs",
|
|
281
|
+
summary: "List the operator's open pull requests with their checks, reviews and merge state",
|
|
282
|
+
missingArgumentHint: null
|
|
283
|
+
},
|
|
284
|
+
"link-pr": {
|
|
285
|
+
usage: "link-pr <pr>",
|
|
286
|
+
summary: "Link a pull request to this session's card",
|
|
287
|
+
missingArgumentHint: "glimmervoid link-pr: this command needs a pull request, for example \"glimmervoid link-pr acme/app#12\""
|
|
288
|
+
},
|
|
289
|
+
settings: {
|
|
290
|
+
usage: "settings list|get",
|
|
291
|
+
summary: "Read Glimmervoid's settings; a secret shows only as configured or not",
|
|
292
|
+
missingArgumentHint: null
|
|
293
|
+
},
|
|
294
|
+
limits: {
|
|
295
|
+
usage: "limits",
|
|
296
|
+
summary: "List which of these commands answer here and what the guardrails block",
|
|
297
|
+
missingArgumentHint: null
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
function agentCommandHelpLines() {
|
|
301
|
+
return Object.values(AGENT_COMMAND_HELP).map(({ usage, summary }) => ` ${usage.padEnd(USAGE_COLUMN_WIDTH)}${summary}`);
|
|
302
|
+
}
|
|
303
|
+
//#endregion
|
|
304
|
+
export { decideSpawnAllowance as a, describeRoleRefusal as c, projectMyPrs as d, projectReviews as f, decideAgentRequest as i, isAgentApiVerb as l, REFUSAL_REASON as n, deriveChildSessionName as o, agentCommandHelpLines as r, describePushLanding as s, AGENT_COMMAND_HELP 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-
|
|
3
|
-
import { p as writeTextAtomicSync } from "./json-file-
|
|
2
|
+
import { a as classifyGrokHooksFile, o as renderGrokHooksFile, t as grok } from "./grok-BLzhApwT.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-DqMScSdg.js";
|