@sleds/cli 0.1.60 → 0.1.62
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/dist/sleds.mjs +1338 -458
- package/package.json +1 -1
package/dist/sleds.mjs
CHANGED
|
@@ -797,9 +797,9 @@ var init_verbs = __esm(() => {
|
|
|
797
797
|
id: "attach",
|
|
798
798
|
group: "meter",
|
|
799
799
|
want: "Put the spec, the prototype, a screenshot or a link on the item so the team can open it",
|
|
800
|
-
mcp: "attach {project, name, content, mime?, kind?} · attach {project, url, title?} — intake takes the same as `attachments` when filing",
|
|
800
|
+
mcp: "attach {project, name, content, mime?, kind?, mock?} · attach {project, url, title?} — intake takes the same as `attachments` when filing",
|
|
801
801
|
app: "Work › the item › Links",
|
|
802
|
-
how: "The file itself lives in SLEDS, not only in the chat that made it: a spec as markdown, a prototype as one HTML page (opens and renders in its own tab), a screenshot — or a link to a doc, a Figma, a Loom. Up to 4 MB; the same name again replaces. Anyone on the board opens it from the item; the person who added it, or an admin, can remove it."
|
|
802
|
+
how: "The file itself lives in SLEDS, not only in the chat that made it: a spec as markdown, a prototype as one HTML page (opens and renders in its own tab), a screenshot — or a link to a doc, a Figma, a Loom. Up to 4 MB; the same name again replaces. Mark the prototype or screenshot that shows the change with `mock: true` — the item's Overview shows it as the proposal. Anyone on the board opens it from the item; the person who added it, or an admin, can remove it."
|
|
803
803
|
},
|
|
804
804
|
{
|
|
805
805
|
id: "update",
|
|
@@ -1149,6 +1149,8 @@ function readForm(text) {
|
|
|
1149
1149
|
const val = (f) => plain(f.value.join(" "));
|
|
1150
1150
|
const one = (slot) => found.find((f) => f.slot === slot && val(f));
|
|
1151
1151
|
const ask = one("ask");
|
|
1152
|
+
const summary = one("summary");
|
|
1153
|
+
const expected = one("expected");
|
|
1152
1154
|
const users = one("users");
|
|
1153
1155
|
const sid = one("sid");
|
|
1154
1156
|
const loc = one("location");
|
|
@@ -1172,6 +1174,8 @@ function readForm(text) {
|
|
|
1172
1174
|
return {
|
|
1173
1175
|
form: def.name,
|
|
1174
1176
|
...ask ? { ask: val(ask) } : {},
|
|
1177
|
+
...summary ? { summary: val(summary) } : {},
|
|
1178
|
+
...expected ? { expected: val(expected) } : {},
|
|
1175
1179
|
...details ? { details } : {},
|
|
1176
1180
|
...touches ? { touches } : {},
|
|
1177
1181
|
...demand ? { demand } : {},
|
|
@@ -1196,6 +1200,8 @@ var init_forms = __esm(() => {
|
|
|
1196
1200
|
[/^sids?\b/, "sid"],
|
|
1197
1201
|
[/^location ids?\b/, "location"],
|
|
1198
1202
|
[/^issue description\b/, "ask"],
|
|
1203
|
+
[/^summary\b|^title\b/, "summary"],
|
|
1204
|
+
[/^expected (?:behaviou?r|result|outcome)\b/, "expected"],
|
|
1199
1205
|
[/^(?:number of )?clients? affected\b|^number of clients\b/, "clients"],
|
|
1200
1206
|
[/\bimpacting revenue\b|\brevenue impact\b/, "revenue"]
|
|
1201
1207
|
],
|
|
@@ -1281,8 +1287,12 @@ function draftBrief(input) {
|
|
|
1281
1287
|
const form = readForm(text);
|
|
1282
1288
|
const parsed = sections(text);
|
|
1283
1289
|
const preamble = parsed.preamble;
|
|
1284
|
-
const byKey = form ? {
|
|
1285
|
-
|
|
1290
|
+
const byKey = form ? {
|
|
1291
|
+
touches: form.touches,
|
|
1292
|
+
demand: form.demand,
|
|
1293
|
+
...form.expected ? { done: form.expected } : {}
|
|
1294
|
+
} : parsed.byKey;
|
|
1295
|
+
const fromText = form?.summary ? form.summary : form?.ask ? form.ask : askFrom(text, preamble);
|
|
1286
1296
|
const askText = a.ask?.trim() || (fromText ? titleOf(fromText) : undefined);
|
|
1287
1297
|
if (!askText)
|
|
1288
1298
|
return null;
|
|
@@ -3280,7 +3290,8 @@ function parseAttachments(raw) {
|
|
|
3280
3290
|
mime,
|
|
3281
3291
|
content,
|
|
3282
3292
|
...str5(a.kind) ? { kind: str5(a.kind) } : {},
|
|
3283
|
-
...a.encoding === "base64" ? { encoding: "base64" } : {}
|
|
3293
|
+
...a.encoding === "base64" ? { encoding: "base64" } : {},
|
|
3294
|
+
...typeof a.mock === "boolean" ? { mock: a.mock } : {}
|
|
3284
3295
|
});
|
|
3285
3296
|
}
|
|
3286
3297
|
return out.slice(0, 12);
|
|
@@ -3621,7 +3632,7 @@ An engine (or you) takes a ready node with \`sled {take: "${key}/<key>"}\`; Run
|
|
|
3621
3632
|
text: "Show the person the graph as text and ask for a yes; then call route again with the same nodes and confirm: true. With nobody to ask (a planning session), call again with propose: true instead.",
|
|
3622
3633
|
isError: true
|
|
3623
3634
|
};
|
|
3624
|
-
const r = await ctx.client.get(`/proxy/route?q=${encodeURIComponent(q)}`);
|
|
3635
|
+
const r = await ctx.client.get(`/proxy/route?q=${encodeURIComponent(q)}&draft=1`);
|
|
3625
3636
|
if (!r)
|
|
3626
3637
|
return UNREACHABLE;
|
|
3627
3638
|
if (r.ok === false)
|
|
@@ -4777,7 +4788,11 @@ var init_server = __esm(() => {
|
|
|
4777
4788
|
},
|
|
4778
4789
|
mime: { type: "string", description: "text/markdown, text/html, image/png…" },
|
|
4779
4790
|
content: { type: "string", description: "The file: text as is, or base64." },
|
|
4780
|
-
encoding: { type: "string", enum: ["text", "base64"] }
|
|
4791
|
+
encoding: { type: "string", enum: ["text", "base64"] },
|
|
4792
|
+
mock: {
|
|
4793
|
+
type: "boolean",
|
|
4794
|
+
description: "true on the prototype or screenshot that shows the change — the item's Overview shows it as the proposal."
|
|
4795
|
+
}
|
|
4781
4796
|
},
|
|
4782
4797
|
required: ["name", "content"]
|
|
4783
4798
|
}
|
|
@@ -5160,7 +5175,7 @@ var init_server = __esm(() => {
|
|
|
5160
5175
|
},
|
|
5161
5176
|
{
|
|
5162
5177
|
name: "attach",
|
|
5163
|
-
description: "Put a file or a link on an item so anyone on the board can open it — a spec or PRD as markdown, a prototype you made as one HTML page (it opens and renders in its own tab), a screenshot; or a URL (a doc, a Figma, a Loom) with `url` instead of a file. Pass the item's key (QW-142, from status, or what intake said). Files up to 4 MB; the same name again replaces the earlier one. `intake` takes the same files as `attachments` when filing.",
|
|
5178
|
+
description: "Put a file or a link on an item so anyone on the board can open it — a spec or PRD as markdown, a prototype you made as one HTML page (it opens and renders in its own tab), a screenshot; or a URL (a doc, a Figma, a Loom) with `url` instead of a file. Pass the item's key (QW-142, from status, or what intake said). Files up to 4 MB; the same name again replaces the earlier one. Mark the prototype or screenshot that shows the change with `mock: true` — the item's Overview shows it as the proposal. `intake` takes the same files as `attachments` when filing.",
|
|
5164
5179
|
inputSchema: {
|
|
5165
5180
|
type: "object",
|
|
5166
5181
|
properties: {
|
|
@@ -5184,7 +5199,11 @@ var init_server = __esm(() => {
|
|
|
5184
5199
|
type: "string",
|
|
5185
5200
|
description: "The file: text as is, or base64 with encoding base64."
|
|
5186
5201
|
},
|
|
5187
|
-
encoding: { type: "string", enum: ["text", "base64"] }
|
|
5202
|
+
encoding: { type: "string", enum: ["text", "base64"] },
|
|
5203
|
+
mock: {
|
|
5204
|
+
type: "boolean",
|
|
5205
|
+
description: "true on the prototype or screenshot that shows the change — the item's Overview shows it as the proposal. false clears the mark; omitted, a replaced file keeps its mark."
|
|
5206
|
+
}
|
|
5188
5207
|
},
|
|
5189
5208
|
required: ["project"]
|
|
5190
5209
|
}
|
|
@@ -5708,7 +5727,7 @@ var init_agent = __esm(() => {
|
|
|
5708
5727
|
REPLY_RULES = [
|
|
5709
5728
|
"How to answer this reply:",
|
|
5710
5729
|
'- If it answers nothing and changes nothing — thanks, "noted", "copy", "will do", or people talking to each other — set quiet to true and post nothing.',
|
|
5711
|
-
"- Never ask a question the thread already asked
|
|
5730
|
+
"- Never ask a question the thread already asked — by you or by anyone — and never ask one the thread has already answered, in anyone's reply. Read every reply in the thread as an answer first.",
|
|
5712
5731
|
"- If someone in the thread already gave the cause or a fix, do not ask the poster for details it makes moot. Say in one line what is left, or set quiet.",
|
|
5713
5732
|
"- Keep it to what changed and what is next. No recap of the ask."
|
|
5714
5733
|
].join(`
|
|
@@ -6731,12 +6750,14 @@ var init_sentry = () => {};
|
|
|
6731
6750
|
var init_outside = () => {};
|
|
6732
6751
|
|
|
6733
6752
|
// ../../packages/shared/src/pack/pack.ts
|
|
6753
|
+
var LANDING_GAP_MS;
|
|
6734
6754
|
var init_pack = __esm(() => {
|
|
6735
6755
|
init_flags();
|
|
6736
6756
|
init_profile();
|
|
6737
6757
|
init_sentry();
|
|
6738
6758
|
init_outside();
|
|
6739
6759
|
init_setup();
|
|
6760
|
+
LANDING_GAP_MS = 10 * 60000;
|
|
6740
6761
|
});
|
|
6741
6762
|
// ../../packages/shared/src/pack/prHeader.ts
|
|
6742
6763
|
var PR_HEADER_OPEN = "<!-- sleds:header -->", PR_HEADER_CLOSE = "<!-- /sleds:header -->";
|
|
@@ -6819,6 +6840,11 @@ var init_musher = __esm(() => {
|
|
|
6819
6840
|
init_plan4();
|
|
6820
6841
|
});
|
|
6821
6842
|
|
|
6843
|
+
// ../../packages/shared/src/route/handoff.ts
|
|
6844
|
+
var init_handoff = __esm(() => {
|
|
6845
|
+
init_route();
|
|
6846
|
+
});
|
|
6847
|
+
|
|
6822
6848
|
// ../../packages/shared/src/route/doneChecks.ts
|
|
6823
6849
|
function shellWords(s) {
|
|
6824
6850
|
const out = [];
|
|
@@ -7034,6 +7060,55 @@ var init_doneChecks = __esm(() => {
|
|
|
7034
7060
|
// ../../packages/shared/src/route/routeFix.ts
|
|
7035
7061
|
var init_routeFix = () => {};
|
|
7036
7062
|
|
|
7063
|
+
// ../../packages/shared/src/route/reshape.ts
|
|
7064
|
+
var init_reshape = __esm(() => {
|
|
7065
|
+
init_route();
|
|
7066
|
+
});
|
|
7067
|
+
|
|
7068
|
+
// ../../packages/shared/src/route/say.ts
|
|
7069
|
+
var VERB_MODAL, ORDER_VERB, each = (a, b, f) => a.flatMap((x) => b.map((y) => f(x, y))), FORMS2;
|
|
7070
|
+
var init_say = __esm(() => {
|
|
7071
|
+
init_reshape();
|
|
7072
|
+
init_route();
|
|
7073
|
+
VERB_MODAL = String.raw`(?:(?:should|must|can|has\s+to|have\s+to|needs?\s+to)\s+)?`;
|
|
7074
|
+
ORDER_VERB = String.raw`(?:${VERB_MODAL}(?:comes?|runs?|go|goes|starts?|be|is|are)\s+)?`;
|
|
7075
|
+
FORMS2 = [
|
|
7076
|
+
{
|
|
7077
|
+
kind: "pair",
|
|
7078
|
+
re: /^(?:merge|fold|combine)\s+(.+?)\s+into\s+(.+)$/i,
|
|
7079
|
+
ops: (a, b) => each(a, b, (absorb, into) => ({ op: "merge", absorb, into }))
|
|
7080
|
+
},
|
|
7081
|
+
{ kind: "split", re: /^split\s+(.+?)(?:\s*,?\s+(?:moving|move|taking|with|off)\s+(.+))?$/i },
|
|
7082
|
+
{ kind: "rename", re: /^(?:rename|retitle)\s+(.+?)\s+(?:to|as)\s+(.+)$/i },
|
|
7083
|
+
{ kind: "move", re: /^move\s+(.+?)\s+from\s+(.+?)\s+(?:to|into|onto)\s+(.+)$/i },
|
|
7084
|
+
{
|
|
7085
|
+
kind: "pair",
|
|
7086
|
+
re: /^unblock\s+(.+?)\s+from\s+(.+)$/i,
|
|
7087
|
+
ops: (a, b) => each(a, b, (node, on) => ({ op: "unwait", node, on }))
|
|
7088
|
+
},
|
|
7089
|
+
{
|
|
7090
|
+
kind: "pair",
|
|
7091
|
+
re: /^(.+?)\s+(?:no\s+longer|doesn't|does\s+not|don't|do\s+not|shouldn't|should\s+not|needn't|need\s+not|(?:should\s+|can\s+)?stops?)\s+(?:waits?|waiting|depends?|depending)\s+(?:on|for|upon)\s+(.+)$/i,
|
|
7092
|
+
ops: (a, b) => each(a, b, (node, on) => ({ op: "unwait", node, on }))
|
|
7093
|
+
},
|
|
7094
|
+
{
|
|
7095
|
+
kind: "pair",
|
|
7096
|
+
re: new RegExp(String.raw`^(?:make\s+)?(.+?)\s+${VERB_MODAL}(?:waits?|depends?)\s+(?:on|for|upon)\s+(.+)$`, "i"),
|
|
7097
|
+
ops: (a, b) => each(a, b, (node, on) => ({ op: "wait", node, on }))
|
|
7098
|
+
},
|
|
7099
|
+
{
|
|
7100
|
+
kind: "pair",
|
|
7101
|
+
re: new RegExp(String.raw`^(.+?)\s+${ORDER_VERB}after\s+(.+)$`, "i"),
|
|
7102
|
+
ops: (a, b) => each(a, b, (node, on) => ({ op: "wait", node, on }))
|
|
7103
|
+
},
|
|
7104
|
+
{
|
|
7105
|
+
kind: "pair",
|
|
7106
|
+
re: new RegExp(String.raw`^(.+?)\s+${ORDER_VERB}before\s+(.+)$`, "i"),
|
|
7107
|
+
ops: (a, b) => each(b, a, (node, on) => ({ op: "wait", node, on }))
|
|
7108
|
+
}
|
|
7109
|
+
];
|
|
7110
|
+
});
|
|
7111
|
+
|
|
7037
7112
|
// ../../packages/shared/src/route/engine.ts
|
|
7038
7113
|
function seatSlots(atOnce) {
|
|
7039
7114
|
if (typeof atOnce !== "number" || !Number.isFinite(atOnce))
|
|
@@ -7278,6 +7353,26 @@ function draftPrompt(o) {
|
|
|
7278
7353
|
${claim.pack.trim()}
|
|
7279
7354
|
`;
|
|
7280
7355
|
}
|
|
7356
|
+
function mockPrompt(o) {
|
|
7357
|
+
const base = o.base ?? "main";
|
|
7358
|
+
const lines = [
|
|
7359
|
+
`You are drawing a mock for ${o.item} — "${o.title}"${o.engine ? ` — started by ${o.engine}` : ""}. Nobody is at the keyboard: a person signs the mock before the build gets its nodes.`,
|
|
7360
|
+
"",
|
|
7361
|
+
"- Draw one self-contained HTML file: CSS and JS inline, no other files, nothing loaded from the network. Build it from the repo's real design tokens and components (read them in the code: colors, type, spacing, radii) and data shaped like the real thing.",
|
|
7362
|
+
"- Draw it on the screen the change lives on: find that page or component in this checkout and show it as it is today, with the change in place, so a person can compare it with the product. If the change has no screen of its own, draw the one a person sees it from.",
|
|
7363
|
+
`- Write the HTML only to \`${o.out}\` — that one file, outside this checkout. Write nothing anywhere else.`,
|
|
7364
|
+
`- Change no code: this checkout is \`origin/${base}\`, for reading. Do not edit, create or delete a file in it, and make no branch, commit, push or PR. The engine checks: a checkout left changed, or a commit, fails the run and nothing is attached.`,
|
|
7365
|
+
"- Ask nobody: a mock run cannot park. Where the brief leaves something open, draw the plainest reading and say it in a short note inside the HTML.",
|
|
7366
|
+
"- Once the file is written, stop. The engine reads it and attaches it to the item as its mock, marked as the next version."
|
|
7367
|
+
];
|
|
7368
|
+
return `${lines.join(`
|
|
7369
|
+
`)}
|
|
7370
|
+
|
|
7371
|
+
---
|
|
7372
|
+
|
|
7373
|
+
${o.pack.trim()}
|
|
7374
|
+
`;
|
|
7375
|
+
}
|
|
7281
7376
|
function quote(text) {
|
|
7282
7377
|
return text.trim().split(`
|
|
7283
7378
|
`).map((l) => l ? `> ${l}` : ">");
|
|
@@ -7542,7 +7637,7 @@ function eventPrompt(o) {
|
|
|
7542
7637
|
return reviewPrompt({ ...o, event });
|
|
7543
7638
|
return ciTwicePrompt({ ...o, event });
|
|
7544
7639
|
}
|
|
7545
|
-
var DEFAULT_SEAT = "\x00default", MAX_SEAT_AT_ONCE = 16, HOLD_DEFAULTS, DRAFT_NODE = "draft", BRANCH_FIELDS, PR_TITLE_FIELDS, ENGINE_MCP_SERVER = "sleds", RUN_TOKEN_ENV = "SLEDS_RUN_TOKEN", NO_RUN_TOKEN = "no run token from SLEDS: this session acts as the seat", SANDBOX_DOMAIN, SANDBOX_DEFAULT_ALLOW, toolName = (name, engineMcp) => engineMcp ? `mcp__${ENGINE_MCP_SERVER}__${name}` : name, ENGINE_MARK = "<!-- sleds:engine -->", VISUAL_PATH, APPROACH_SHAPE, AUTONOMY_SAYS, IRREVERSIBLE = "deleting or migrating data in place; deploying outside the playbook's window; anything that leaves the org (a message to a customer, a publish, a release, an email); spend past the band or the allowance; force-pushing or deleting a branch someone else holds; granting or removing access; changing the brief. When in doubt, it is irreversible.", oneLine = (s, max) => s.replace(/\s+/g, " ").trim().slice(0, max), VERDICT_SHAPE, DECIDER_RULES, codes = (xs) => xs.map((x) => `\`${x}\``).join(", "), RESOLVE_MAX_FILES = 8;
|
|
7640
|
+
var DEFAULT_SEAT = "\x00default", MAX_SEAT_AT_ONCE = 16, HOLD_DEFAULTS, DRAFT_NODE = "draft", MOCK_NODE = "mock", BRANCH_FIELDS, PR_TITLE_FIELDS, ENGINE_MCP_SERVER = "sleds", RUN_TOKEN_ENV = "SLEDS_RUN_TOKEN", NO_RUN_TOKEN = "no run token from SLEDS: this session acts as the seat", SANDBOX_DOMAIN, SANDBOX_DEFAULT_ALLOW, toolName = (name, engineMcp) => engineMcp ? `mcp__${ENGINE_MCP_SERVER}__${name}` : name, ENGINE_MARK = "<!-- sleds:engine -->", VISUAL_PATH, APPROACH_SHAPE, AUTONOMY_SAYS, IRREVERSIBLE = "deleting or migrating data in place; deploying outside the playbook's window; anything that leaves the org (a message to a customer, a publish, a release, an email); spend past the band or the allowance; force-pushing or deleting a branch someone else holds; granting or removing access; changing the brief. When in doubt, it is irreversible.", oneLine = (s, max) => s.replace(/\s+/g, " ").trim().slice(0, max), VERDICT_SHAPE, DECIDER_RULES, codes = (xs) => xs.map((x) => `\`${x}\``).join(", "), RESOLVE_MAX_FILES = 8;
|
|
7546
7641
|
var init_engine = __esm(() => {
|
|
7547
7642
|
init_prHeader();
|
|
7548
7643
|
init_route();
|
|
@@ -7727,6 +7822,18 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
|
|
|
7727
7822
|
return { ...settings };
|
|
7728
7823
|
const { [BASE_URL_KEY]: _url, [AUTH_TOKEN_KEY]: _token, ...rest } = settings.env;
|
|
7729
7824
|
return { ...settings, env: rest };
|
|
7825
|
+
}, bareUrl = (u) => u.trim().replace(/[./]+$/, "").toLowerCase(), isSledsProxyEnv = (settings, proxyUrls = []) => {
|
|
7826
|
+
const env = envOf(settings);
|
|
7827
|
+
const url = env[BASE_URL_KEY];
|
|
7828
|
+
const token = env[AUTH_TOKEN_KEY];
|
|
7829
|
+
if (typeof token === "string" && isSeatToken(token.trim()))
|
|
7830
|
+
return true;
|
|
7831
|
+
if (typeof url !== "string")
|
|
7832
|
+
return false;
|
|
7833
|
+
return proxyUrls.some((p) => p !== undefined && bareUrl(p) === bareUrl(url));
|
|
7834
|
+
}, hasGatewayEnv = (settings) => {
|
|
7835
|
+
const env = envOf(settings);
|
|
7836
|
+
return BASE_URL_KEY in env || AUTH_TOKEN_KEY in env;
|
|
7730
7837
|
}, readProxy = (settings) => {
|
|
7731
7838
|
const env = envOf(settings);
|
|
7732
7839
|
const url = env[BASE_URL_KEY];
|
|
@@ -7734,7 +7841,7 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
|
|
|
7734
7841
|
if (typeof url !== "string" || typeof token !== "string")
|
|
7735
7842
|
return null;
|
|
7736
7843
|
return { url, token };
|
|
7737
|
-
}, STATUS_LINE_KEY = "statusLine", statusLineEntry = (command) => ({ type: "command", command }), isSledsStatusLine = (value) => isObject5(value) && value.type === "command" && typeof value.command === "string" && /\bstatusline\b/.test(value.command), applyStatusLine = (settings, command) => {
|
|
7844
|
+
}, STATUS_LINE_KEY = "statusLine", statusLineEntry = (command) => ({ type: "command", command }), invokesSleds = (command) => /\bsleds\b/.test(command), isSledsStatusLine = (value) => isObject5(value) && value.type === "command" && typeof value.command === "string" && invokesSleds(value.command) && /\bstatusline\b/.test(value.command), applyStatusLine = (settings, command) => {
|
|
7738
7845
|
const current = settings[STATUS_LINE_KEY];
|
|
7739
7846
|
const prior = current === undefined || isSledsStatusLine(current) ? undefined : current;
|
|
7740
7847
|
return { settings: { ...settings, [STATUS_LINE_KEY]: statusLineEntry(command) }, prior };
|
|
@@ -7743,11 +7850,12 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
|
|
|
7743
7850
|
return { ...settings };
|
|
7744
7851
|
const { [STATUS_LINE_KEY]: _ours, ...rest } = settings;
|
|
7745
7852
|
return prior === undefined ? rest : { ...rest, [STATUS_LINE_KEY]: prior };
|
|
7746
|
-
}, HOOKS_KEY = "hooks", NOTIFICATION_EVENT = "Notification", SEAT_EVENT_MATCHER = "quota_auto_resume_fired|quota_auto_resume_stale|quota_auto_resume_disabled", SEAT_EVENT_TIMEOUT_S = 10,
|
|
7853
|
+
}, HOOKS_KEY = "hooks", NOTIFICATION_EVENT = "Notification", SEAT_EVENT_MATCHER = "quota_auto_resume_fired|quota_auto_resume_stale|quota_auto_resume_disabled", SEAT_EVENT_TIMEOUT_S = 10, isSledsHookFor = (sub) => (entry) => {
|
|
7747
7854
|
if (!isObject5(entry) || !Array.isArray(entry.hooks))
|
|
7748
7855
|
return false;
|
|
7749
|
-
|
|
7750
|
-
|
|
7856
|
+
const re = new RegExp(`\\b${sub}\\b`);
|
|
7857
|
+
return entry.hooks.some((h) => isObject5(h) && h.type === "command" && typeof h.command === "string" && invokesSleds(h.command) && re.test(h.command));
|
|
7858
|
+
}, isSledsSeatHook, seatHookEntry = (command) => ({
|
|
7751
7859
|
matcher: SEAT_EVENT_MATCHER,
|
|
7752
7860
|
hooks: [{ type: "command", command, timeout: SEAT_EVENT_TIMEOUT_S }]
|
|
7753
7861
|
}), notificationHooks = (settings) => {
|
|
@@ -7778,11 +7886,7 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
|
|
|
7778
7886
|
if (!list.some(isSledsSeatHook))
|
|
7779
7887
|
return { ...settings };
|
|
7780
7888
|
return withNotificationHooks(settings, list.filter((e) => !isSledsSeatHook(e)));
|
|
7781
|
-
}, hasSeatHook = (settings) => notificationHooks(settings).some(isSledsSeatHook), POST_TOOL_EVENT = "PostToolUse", SPEC_EVENT_MATCHER = "Write|Edit|MultiEdit", SPEC_EVENT_TIMEOUT_S = 5, isSledsSpecHook = (
|
|
7782
|
-
if (!isObject5(entry) || !Array.isArray(entry.hooks))
|
|
7783
|
-
return false;
|
|
7784
|
-
return entry.hooks.some((h) => isObject5(h) && h.type === "command" && typeof h.command === "string" && /\bspec-event\b/.test(h.command));
|
|
7785
|
-
}, specHookEntry = (command) => ({
|
|
7889
|
+
}, hasSeatHook = (settings) => notificationHooks(settings).some(isSledsSeatHook), POST_TOOL_EVENT = "PostToolUse", SPEC_EVENT_MATCHER = "Write|Edit|MultiEdit", SPEC_EVENT_TIMEOUT_S = 5, isSledsSpecHook, specHookEntry = (command) => ({
|
|
7786
7890
|
matcher: SPEC_EVENT_MATCHER,
|
|
7787
7891
|
hooks: [{ type: "command", command, timeout: SPEC_EVENT_TIMEOUT_S }]
|
|
7788
7892
|
}), eventHooks = (settings, event) => {
|
|
@@ -7813,11 +7917,7 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
|
|
|
7813
7917
|
if (!list.some(isSledsSpecHook))
|
|
7814
7918
|
return { ...settings };
|
|
7815
7919
|
return withEventHooks(settings, POST_TOOL_EVENT, list.filter((e) => !isSledsSpecHook(e)));
|
|
7816
|
-
}, hasSpecHook = (settings) => eventHooks(settings, POST_TOOL_EVENT).some(isSledsSpecHook), PROMPT_EVENT = "UserPromptSubmit", PROMPT_EVENT_TIMEOUT_S = 3, isSledsPromptHook = (
|
|
7817
|
-
if (!isObject5(entry) || !Array.isArray(entry.hooks))
|
|
7818
|
-
return false;
|
|
7819
|
-
return entry.hooks.some((h) => isObject5(h) && h.type === "command" && typeof h.command === "string" && /\bprompt-event\b/.test(h.command));
|
|
7820
|
-
}, promptHookEntry = (command) => ({
|
|
7920
|
+
}, hasSpecHook = (settings) => eventHooks(settings, POST_TOOL_EVENT).some(isSledsSpecHook), PROMPT_EVENT = "UserPromptSubmit", PROMPT_EVENT_TIMEOUT_S = 3, isSledsPromptHook, promptHookEntry = (command) => ({
|
|
7821
7921
|
hooks: [{ type: "command", command, timeout: PROMPT_EVENT_TIMEOUT_S }]
|
|
7822
7922
|
}), applyPromptHook = (settings, command) => {
|
|
7823
7923
|
const list = eventHooks(settings, PROMPT_EVENT);
|
|
@@ -7830,12 +7930,7 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
|
|
|
7830
7930
|
if (!list.some(isSledsPromptHook))
|
|
7831
7931
|
return { ...settings };
|
|
7832
7932
|
return withEventHooks(settings, PROMPT_EVENT, list.filter((e) => !isSledsPromptHook(e)));
|
|
7833
|
-
}, hasPromptHook = (settings) => eventHooks(settings, PROMPT_EVENT).some(isSledsPromptHook), SESSION_EVENT = "SessionStart", SESSION_EVENT_TIMEOUT_S = 3, STOP_EVENT = "Stop", STOP_EVENT_TIMEOUT_S = 3,
|
|
7834
|
-
if (!isObject5(entry) || !Array.isArray(entry.hooks))
|
|
7835
|
-
return false;
|
|
7836
|
-
const re = new RegExp(`\\b${sub}\\b`);
|
|
7837
|
-
return entry.hooks.some((h) => isObject5(h) && h.type === "command" && typeof h.command === "string" && re.test(h.command));
|
|
7838
|
-
}, isSledsSessionHook, isSledsStopHook, sessionHookEntry = (command) => ({
|
|
7933
|
+
}, hasPromptHook = (settings) => eventHooks(settings, PROMPT_EVENT).some(isSledsPromptHook), SESSION_EVENT = "SessionStart", SESSION_EVENT_TIMEOUT_S = 3, STOP_EVENT = "Stop", STOP_EVENT_TIMEOUT_S = 3, isSledsSessionHook, isSledsStopHook, sessionHookEntry = (command) => ({
|
|
7839
7934
|
hooks: [{ type: "command", command, timeout: SESSION_EVENT_TIMEOUT_S }]
|
|
7840
7935
|
}), stopHookEntry = (command) => ({
|
|
7841
7936
|
hooks: [{ type: "command", command, timeout: STOP_EVENT_TIMEOUT_S }]
|
|
@@ -7890,6 +7985,9 @@ var BASE_URL_KEY = "ANTHROPIC_BASE_URL", AUTH_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
|
|
|
7890
7985
|
var init_settings = __esm(() => {
|
|
7891
7986
|
LEADING_EXPORTS = /^(?:[A-Za-z_][A-Za-z0-9_]*=(?:'[^']*'|\S+)\s+)*/;
|
|
7892
7987
|
ORG_EXPORT = /(?:^|\s)SLEDS_ORG=(?:'[^']*'|\S+)(?=\s)/;
|
|
7988
|
+
isSledsSeatHook = isSledsHookFor("seat-event");
|
|
7989
|
+
isSledsSpecHook = isSledsHookFor("spec-event");
|
|
7990
|
+
isSledsPromptHook = isSledsHookFor("prompt-event");
|
|
7893
7991
|
isSledsSessionHook = isSledsHookFor("session-event");
|
|
7894
7992
|
isSledsStopHook = isSledsHookFor("stop-event");
|
|
7895
7993
|
isSledsPermissionHook = isSledsHookFor("permission-event");
|
|
@@ -7946,6 +8044,9 @@ var configDir = (home, env = process.env) => {
|
|
|
7946
8044
|
cfg.schedule = schedule;
|
|
7947
8045
|
if (raw.priorStatusLine !== undefined)
|
|
7948
8046
|
cfg.priorStatusLine = raw.priorStatusLine;
|
|
8047
|
+
const priorGatewayEnv = parsePriorEnv(raw.priorGatewayEnv);
|
|
8048
|
+
if (priorGatewayEnv !== undefined)
|
|
8049
|
+
cfg.priorGatewayEnv = priorGatewayEnv;
|
|
7949
8050
|
if (raw.wiring === "seat-first" || raw.wiring === "proxy-always")
|
|
7950
8051
|
cfg.wiring = raw.wiring;
|
|
7951
8052
|
if (raw.agentKind === "claude-code" || raw.agentKind === "codex")
|
|
@@ -8114,9 +8215,11 @@ var init_config = __esm(() => {
|
|
|
8114
8215
|
});
|
|
8115
8216
|
|
|
8116
8217
|
// src/meter.ts
|
|
8218
|
+
import { createHash } from "node:crypto";
|
|
8117
8219
|
import { existsSync as existsSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync6, renameSync as renameSync3, writeFileSync as writeFileSync6 } from "node:fs";
|
|
8118
8220
|
import { join as join6 } from "node:path";
|
|
8119
|
-
var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num4 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, meterCachePath = (home) => join6(configDir(home), "meter.json"),
|
|
8221
|
+
var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num4 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, meterCachePath = (home) => join6(configDir(home), "meter.json"), meterCacheKey = (src) => createHash("sha256").update(`${src.proxyUrl}
|
|
8222
|
+
${src.token}`).digest("hex").slice(0, 16), readMeterCache = (home, now, source) => {
|
|
8120
8223
|
const p = meterCachePath(home);
|
|
8121
8224
|
if (!existsSync6(p))
|
|
8122
8225
|
return null;
|
|
@@ -8124,6 +8227,8 @@ var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject7 = (v) => typeof
|
|
|
8124
8227
|
const raw = JSON.parse(readFileSync6(p, "utf8"));
|
|
8125
8228
|
if (!isObject7(raw))
|
|
8126
8229
|
return null;
|
|
8230
|
+
if (source !== undefined && raw.source !== source)
|
|
8231
|
+
return null;
|
|
8127
8232
|
const fetchedAt = num4(raw.fetchedAt);
|
|
8128
8233
|
if (fetchedAt === undefined || now - fetchedAt >= METER_CACHE_TTL_MS || fetchedAt > now)
|
|
8129
8234
|
return null;
|
|
@@ -8131,12 +8236,12 @@ var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject7 = (v) => typeof
|
|
|
8131
8236
|
} catch {
|
|
8132
8237
|
return null;
|
|
8133
8238
|
}
|
|
8134
|
-
}, writeMeterCache = (home, meter, now) => {
|
|
8239
|
+
}, writeMeterCache = (home, meter, now, source) => {
|
|
8135
8240
|
const dir = configDir(home);
|
|
8136
8241
|
mkdirSync6(dir, { recursive: true, mode: 448 });
|
|
8137
8242
|
const target = meterCachePath(home);
|
|
8138
8243
|
const tmp = `${target}.${process.pid}.tmp`;
|
|
8139
|
-
const file = { fetchedAt: now, meter };
|
|
8244
|
+
const file = { fetchedAt: now, meter, ...source ? { source } : {} };
|
|
8140
8245
|
writeFileSync6(tmp, `${JSON.stringify(file)}
|
|
8141
8246
|
`, { mode: 384 });
|
|
8142
8247
|
renameSync3(tmp, target);
|
|
@@ -8167,16 +8272,17 @@ var METER_CACHE_TTL_MS = 1e4, METER_TIMEOUT_MS = 1500, isObject7 = (v) => typeof
|
|
|
8167
8272
|
return proxyUrl && token ? { proxyUrl, token } : null;
|
|
8168
8273
|
}, loadMeter = async (o) => {
|
|
8169
8274
|
const now = o.now ?? Date.now();
|
|
8170
|
-
const
|
|
8171
|
-
if (cached)
|
|
8172
|
-
return cached;
|
|
8173
|
-
const src = meterSource(o.home);
|
|
8275
|
+
const src = meterSource(o.home, undefined, { env: o.env });
|
|
8174
8276
|
if (!src)
|
|
8175
8277
|
return null;
|
|
8278
|
+
const key = meterCacheKey(src);
|
|
8279
|
+
const cached = readMeterCache(o.home, now, key);
|
|
8280
|
+
if (cached)
|
|
8281
|
+
return cached;
|
|
8176
8282
|
const fresh = await fetchMeter({ ...src, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs });
|
|
8177
8283
|
if (fresh) {
|
|
8178
8284
|
try {
|
|
8179
|
-
writeMeterCache(o.home, fresh, now);
|
|
8285
|
+
writeMeterCache(o.home, fresh, now, key);
|
|
8180
8286
|
} catch {}
|
|
8181
8287
|
}
|
|
8182
8288
|
return fresh;
|
|
@@ -8241,8 +8347,11 @@ var init_src = __esm(() => {
|
|
|
8241
8347
|
init_newrelic();
|
|
8242
8348
|
init_musher();
|
|
8243
8349
|
init_route();
|
|
8350
|
+
init_handoff();
|
|
8244
8351
|
init_doneChecks();
|
|
8245
8352
|
init_routeFix();
|
|
8353
|
+
init_reshape();
|
|
8354
|
+
init_say();
|
|
8246
8355
|
init_engine();
|
|
8247
8356
|
init_sources();
|
|
8248
8357
|
init_otlp();
|
|
@@ -8640,7 +8749,15 @@ function parseRun(v) {
|
|
|
8640
8749
|
item,
|
|
8641
8750
|
node,
|
|
8642
8751
|
title: typeof title === "string" ? title : "",
|
|
8643
|
-
...v.kind === "draft" ? { kind:
|
|
8752
|
+
...v.kind === "draft" || v.kind === "mock" ? { kind: v.kind } : {},
|
|
8753
|
+
...isObject8(v.mock) && typeof v.mock.out === "string" && typeof v.mock.base === "string" ? {
|
|
8754
|
+
mock: {
|
|
8755
|
+
out: v.mock.out,
|
|
8756
|
+
base: v.mock.base,
|
|
8757
|
+
...typeof v.mock.model === "string" ? { model: v.mock.model } : {},
|
|
8758
|
+
...typeof v.mock.drawn === "string" ? { drawn: v.mock.drawn } : {}
|
|
8759
|
+
}
|
|
8760
|
+
} : {},
|
|
8644
8761
|
...typeof v.seatId === "string" ? { seatId: v.seatId } : {},
|
|
8645
8762
|
...typeof v.runId === "string" ? { runId: v.runId } : {},
|
|
8646
8763
|
...typeof v.leaseUntil === "number" ? { leaseUntil: v.leaseUntil } : {},
|
|
@@ -8688,6 +8805,7 @@ function parseRun(v) {
|
|
|
8688
8805
|
}
|
|
8689
8806
|
} : {},
|
|
8690
8807
|
...v.pr.clear === true ? { clear: true } : {},
|
|
8808
|
+
...v.pr.queued === true ? { queued: true } : {},
|
|
8691
8809
|
...typeof v.pr.ci === "string" ? { ci: v.pr.ci } : {},
|
|
8692
8810
|
...typeof v.pr.review === "string" ? { review: v.pr.review } : {},
|
|
8693
8811
|
...typeof v.pr.posted === "string" ? { posted: v.pr.posted } : {},
|
|
@@ -8698,13 +8816,15 @@ function parseRun(v) {
|
|
|
8698
8816
|
...conflicted ? { conflicted } : {},
|
|
8699
8817
|
...typeof v.pr.reviewed === "string" ? { reviewed: v.pr.reviewed } : {},
|
|
8700
8818
|
...typeof v.pr.look === "string" ? { look: v.pr.look } : {},
|
|
8819
|
+
...typeof v.pr.instructAt === "number" ? { instructAt: v.pr.instructAt } : {},
|
|
8701
8820
|
...isObject8(v.pr.instructed) && Array.isArray(v.pr.instructed.ids) && (v.pr.instructed.how === "told" || v.pr.instructed.how === "restarted") ? {
|
|
8702
8821
|
instructed: {
|
|
8703
8822
|
ids: v.pr.instructed.ids.filter((x) => typeof x === "string"),
|
|
8704
8823
|
how: v.pr.instructed.how
|
|
8705
8824
|
}
|
|
8706
8825
|
} : {},
|
|
8707
|
-
...typeof v.pr.findings === "string" ? { findings: v.pr.findings } : {}
|
|
8826
|
+
...typeof v.pr.findings === "string" ? { findings: v.pr.findings } : {},
|
|
8827
|
+
...v.pr.live === true ? { live: true } : {}
|
|
8708
8828
|
}
|
|
8709
8829
|
} : {}
|
|
8710
8830
|
};
|
|
@@ -8996,8 +9116,11 @@ init_sentry();
|
|
|
8996
9116
|
init_newrelic();
|
|
8997
9117
|
init_musher();
|
|
8998
9118
|
init_route();
|
|
9119
|
+
init_handoff();
|
|
8999
9120
|
init_doneChecks();
|
|
9000
9121
|
init_routeFix();
|
|
9122
|
+
init_reshape();
|
|
9123
|
+
init_say();
|
|
9001
9124
|
init_engine();
|
|
9002
9125
|
init_sources();
|
|
9003
9126
|
init_otlp();
|
|
@@ -9276,6 +9399,14 @@ import { basename, dirname as dirname5, join as join7 } from "node:path";
|
|
|
9276
9399
|
var MUSHER_LABEL = "ai.sleds.musher";
|
|
9277
9400
|
var MUSHER_INTERVAL_S = 300;
|
|
9278
9401
|
var DEFAULT_PERMISSION_MODE = "acceptEdits";
|
|
9402
|
+
var PERMISSION_MODES = [
|
|
9403
|
+
"acceptEdits",
|
|
9404
|
+
"auto",
|
|
9405
|
+
"bypassPermissions",
|
|
9406
|
+
"default",
|
|
9407
|
+
"dontAsk",
|
|
9408
|
+
"plan"
|
|
9409
|
+
];
|
|
9279
9410
|
var DEFAULT_TIMEOUT_MINUTES = 90;
|
|
9280
9411
|
var SUMMARY_MAX = 2000;
|
|
9281
9412
|
var musherLabel = (env = process.env) => {
|
|
@@ -9394,11 +9525,12 @@ var defaultExecCapture = (cmd, args, o) => {
|
|
|
9394
9525
|
stdio: ["ignore", "pipe", "pipe"],
|
|
9395
9526
|
env: { ...process.env, SLEDS_MUSHER: "1" }
|
|
9396
9527
|
});
|
|
9528
|
+
const timedOut = r.error?.code === "ETIMEDOUT";
|
|
9397
9529
|
return {
|
|
9398
9530
|
stdout: r.stdout ?? "",
|
|
9399
9531
|
stderr: r.stderr ?? "",
|
|
9400
9532
|
status: r.status,
|
|
9401
|
-
...r.error ? { error: r.error.message } : {}
|
|
9533
|
+
...timedOut ? { timedOut } : r.error ? { error: r.error.message } : {}
|
|
9402
9534
|
};
|
|
9403
9535
|
};
|
|
9404
9536
|
var musherClient = (o) => {
|
|
@@ -9474,8 +9606,10 @@ var runJob = async (o) => {
|
|
|
9474
9606
|
const r = exec(o.claudePath, args, { cwd, timeoutMs: o.timeoutMs });
|
|
9475
9607
|
const durationMs = Date.now() - t0;
|
|
9476
9608
|
const result = r.error ? { ok: false, summary: `could not run ${o.claudePath}: ${r.error}` } : parseClaudeOutput(r.stdout, r.status);
|
|
9477
|
-
if (!r.error && r.status === null)
|
|
9609
|
+
if (!r.error && (r.timedOut || r.status === null)) {
|
|
9610
|
+
result.ok = false;
|
|
9478
9611
|
result.summary = `timed out after ${Math.round(o.timeoutMs / 60000)} min. ${result.summary}`.trim();
|
|
9612
|
+
}
|
|
9479
9613
|
const outputs = collectOutputs(gitNewCommits(cwd, headBefore, gitHead(cwd, exec), exec), result.summary);
|
|
9480
9614
|
await o.client.finish({
|
|
9481
9615
|
jobId: o.job.jobId,
|
|
@@ -9910,8 +10044,32 @@ var markWarned = (state, events) => {
|
|
|
9910
10044
|
}
|
|
9911
10045
|
return { ...state, warned, ...lastWallResetsAt !== undefined ? { lastWallResetsAt } : {} };
|
|
9912
10046
|
};
|
|
9913
|
-
var
|
|
9914
|
-
var
|
|
10047
|
+
var CREDITS_LINE = /^\s*you(?:'|’)re out of usage credits\b/i;
|
|
10048
|
+
var entryText = (v) => {
|
|
10049
|
+
if (typeof v === "string")
|
|
10050
|
+
return v;
|
|
10051
|
+
if (!Array.isArray(v))
|
|
10052
|
+
return "";
|
|
10053
|
+
return v.map((b) => isObject9(b) && b.type === "text" && typeof b.text === "string" ? b.text : "").join(`
|
|
10054
|
+
`);
|
|
10055
|
+
};
|
|
10056
|
+
var isCreditsLine = (line) => {
|
|
10057
|
+
if (!line.includes("usage credits"))
|
|
10058
|
+
return false;
|
|
10059
|
+
let raw;
|
|
10060
|
+
try {
|
|
10061
|
+
raw = JSON.parse(line);
|
|
10062
|
+
} catch {
|
|
10063
|
+
return false;
|
|
10064
|
+
}
|
|
10065
|
+
if (!isObject9(raw))
|
|
10066
|
+
return false;
|
|
10067
|
+
const message = isObject9(raw.message) ? raw.message : undefined;
|
|
10068
|
+
const texts = raw.type === "system" ? [entryText(raw.content), entryText(raw.text)] : raw.type === "assistant" && raw.isApiErrorMessage === true ? [entryText(message?.content)] : [];
|
|
10069
|
+
return texts.some((t) => CREDITS_LINE.test(t));
|
|
10070
|
+
};
|
|
10071
|
+
var creditsHitIn = (text) => text.split(`
|
|
10072
|
+
`).some(isCreditsLine);
|
|
9915
10073
|
var transcriptPathFromStdin = (text) => {
|
|
9916
10074
|
try {
|
|
9917
10075
|
const raw = JSON.parse(text.trim());
|
|
@@ -9934,12 +10092,14 @@ var scanTranscriptForCredits = (path, prior) => {
|
|
|
9934
10092
|
try {
|
|
9935
10093
|
const buf = Buffer.alloc(size - start);
|
|
9936
10094
|
readSync(fd, buf, 0, buf.length, start);
|
|
9937
|
-
const
|
|
10095
|
+
const lastNewline = buf.lastIndexOf(10);
|
|
10096
|
+
const whole = lastNewline >= 0 ? buf.subarray(0, lastNewline + 1) : Buffer.alloc(0);
|
|
10097
|
+
const hit = creditsHitIn(whole.toString("utf8"));
|
|
9938
10098
|
return {
|
|
9939
10099
|
hit,
|
|
9940
10100
|
next: {
|
|
9941
10101
|
path,
|
|
9942
|
-
offset:
|
|
10102
|
+
offset: lastNewline >= 0 ? start + lastNewline + 1 : start,
|
|
9943
10103
|
...hit ? { hitAt: Date.now() } : prior?.hitAt ? { hitAt: prior.hitAt } : {}
|
|
9944
10104
|
}
|
|
9945
10105
|
};
|
|
@@ -10033,10 +10193,7 @@ var switchOff = (settings, prior) => {
|
|
|
10033
10193
|
}
|
|
10034
10194
|
return { ...stripped, env };
|
|
10035
10195
|
};
|
|
10036
|
-
var
|
|
10037
|
-
const env = envOf2(settings);
|
|
10038
|
-
return BASE_URL_KEY in env || AUTH_TOKEN_KEY in env;
|
|
10039
|
-
};
|
|
10196
|
+
var envToRestore = (priors, proxyUrls) => priors.find((p) => p !== undefined && !isSledsProxyEnv({ env: p }, proxyUrls)) ?? {};
|
|
10040
10197
|
var RELATIVE = /^\+(?:(\d+)h)?(?:(\d+)m)?$/;
|
|
10041
10198
|
var parseUntilReset = (input, nowMs) => {
|
|
10042
10199
|
const trimmed = input.trim();
|
|
@@ -10274,7 +10431,7 @@ var deployCmd = async (o) => {
|
|
|
10274
10431
|
return 0;
|
|
10275
10432
|
}
|
|
10276
10433
|
const why = typeof r.json?.error === "string" ? r.json.error : `HTTP ${r.status}`;
|
|
10277
|
-
if (r.status >= 400 && r.status < 500) {
|
|
10434
|
+
if (r.status >= 400 && r.status < 500 && r.status !== 429 && r.status !== 408) {
|
|
10278
10435
|
error(r.status === 401 ? `SLEDS refused the deploy token (${why})` : why);
|
|
10279
10436
|
return 1;
|
|
10280
10437
|
}
|
|
@@ -10290,13 +10447,13 @@ import {
|
|
|
10290
10447
|
existsSync as existsSync21,
|
|
10291
10448
|
lstatSync as lstatSync2,
|
|
10292
10449
|
mkdtempSync,
|
|
10293
|
-
readFileSync as
|
|
10450
|
+
readFileSync as readFileSync20,
|
|
10294
10451
|
readlinkSync as readlinkSync4,
|
|
10295
10452
|
rmSync as rmSync13,
|
|
10296
10453
|
writeFileSync as writeFileSync19
|
|
10297
10454
|
} from "node:fs";
|
|
10298
|
-
import { tmpdir, userInfo as userInfo2 } from "node:os";
|
|
10299
|
-
import { delimiter as delimiter3, dirname as
|
|
10455
|
+
import { tmpdir as tmpdir2, userInfo as userInfo2 } from "node:os";
|
|
10456
|
+
import { delimiter as delimiter3, dirname as dirname18, join as join27, resolve as resolve10 } from "node:path";
|
|
10300
10457
|
|
|
10301
10458
|
// src/agentMcp.ts
|
|
10302
10459
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
@@ -10402,6 +10559,7 @@ async function offerMcp2(o) {
|
|
|
10402
10559
|
}
|
|
10403
10560
|
|
|
10404
10561
|
// src/channels/cockpit.ts
|
|
10562
|
+
import { execFile } from "node:child_process";
|
|
10405
10563
|
var detectCockpit = (env) => {
|
|
10406
10564
|
if (env.CMUX_SOCKET_PATH || env.CMUX_WORKSPACE_ID || env.CMUX_SURFACE_ID) {
|
|
10407
10565
|
const c = { kind: "cmux" };
|
|
@@ -10650,23 +10808,19 @@ var fetchFeed = async (o, now) => {
|
|
|
10650
10808
|
return null;
|
|
10651
10809
|
}
|
|
10652
10810
|
};
|
|
10811
|
+
var execCockpit = (bin, args, timeoutMs) => new Promise((resolve) => {
|
|
10812
|
+
try {
|
|
10813
|
+
const child = execFile(bin, [...args], { timeout: timeoutMs }, () => resolve());
|
|
10814
|
+
child.stdin?.end();
|
|
10815
|
+
} catch {
|
|
10816
|
+
resolve();
|
|
10817
|
+
}
|
|
10818
|
+
});
|
|
10653
10819
|
var runCockpit = async (cockpit, argv, opts = {}) => {
|
|
10654
|
-
const
|
|
10820
|
+
const exec = opts.exec ?? execCockpit;
|
|
10655
10821
|
const timeoutMs = opts.timeoutMs ?? 300;
|
|
10656
10822
|
const bin = cockpit.kind === "cmux" ? "cmux" : cockpit.kind;
|
|
10657
|
-
await Promise.allSettled(argv.map(
|
|
10658
|
-
const proc = spawn([bin, ...a], { stdout: "ignore", stderr: "ignore", stdin: "ignore" });
|
|
10659
|
-
const timer = setTimeout(() => {
|
|
10660
|
-
try {
|
|
10661
|
-
proc.kill();
|
|
10662
|
-
} catch {}
|
|
10663
|
-
}, timeoutMs);
|
|
10664
|
-
try {
|
|
10665
|
-
await proc.exited;
|
|
10666
|
-
} finally {
|
|
10667
|
-
clearTimeout(timer);
|
|
10668
|
-
}
|
|
10669
|
-
}));
|
|
10823
|
+
await Promise.allSettled(argv.map((a) => exec(bin, a, timeoutMs)));
|
|
10670
10824
|
};
|
|
10671
10825
|
|
|
10672
10826
|
// src/commands/doctor.ts
|
|
@@ -10678,7 +10832,14 @@ import { join as join11 } from "node:path";
|
|
|
10678
10832
|
var API_KEY_VAR = "ANTHROPIC_API_KEY";
|
|
10679
10833
|
var SEAT_TOKEN_VAR = "CLAUDE_CODE_OAUTH_TOKEN";
|
|
10680
10834
|
function namesVar(text, name) {
|
|
10681
|
-
|
|
10835
|
+
const assign = new RegExp(`^[ \\t]*(?:export[ \\t]+)?${name}[ \\t]*=(.*)$`);
|
|
10836
|
+
return text.split(/\r?\n/).some((line) => {
|
|
10837
|
+
const value = assign.exec(line)?.[1]?.trim();
|
|
10838
|
+
if (!value)
|
|
10839
|
+
return false;
|
|
10840
|
+
const quoted = /^(["'])(.*)\1$/.exec(value);
|
|
10841
|
+
return (quoted ? (quoted[2] ?? "").trim() : value) !== "";
|
|
10842
|
+
});
|
|
10682
10843
|
}
|
|
10683
10844
|
function loginPath(env, home = homedir()) {
|
|
10684
10845
|
return join11(env.CLAUDE_CONFIG_DIR?.trim() || join11(home, ".claude"), ".credentials.json");
|
|
@@ -10758,12 +10919,18 @@ var readCmuxPassword = (exec) => {
|
|
|
10758
10919
|
return null;
|
|
10759
10920
|
return r.stdout.trim() || null;
|
|
10760
10921
|
};
|
|
10922
|
+
var securityQuote = (s) => `"${s.replace(/[\\"]/g, (c) => `\\${c}`)}"`;
|
|
10761
10923
|
var writeCmuxPassword = (exec, pw) => {
|
|
10762
|
-
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10924
|
+
if (/[\r\n\0]/.test(pw))
|
|
10925
|
+
throw new Error("could not store the cmux password in the Keychain: it has a line break");
|
|
10926
|
+
const command = ["add-generic-password", "-U", ...item, "-w"].join(" ");
|
|
10927
|
+
const r = exec("security", ["-i"], { input: `${command} ${securityQuote(pw)}
|
|
10928
|
+
` });
|
|
10929
|
+
const why = r.stderr.split(pw).join("…").trim();
|
|
10930
|
+
if (r.status !== 0)
|
|
10931
|
+
throw new Error(`could not store the cmux password in the Keychain: ${why || `exit ${r.status}`}`);
|
|
10932
|
+
if (readCmuxPassword(exec) !== pw.trim())
|
|
10933
|
+
throw new Error(`could not store the cmux password in the Keychain: ${why || "it did not read back"}`);
|
|
10767
10934
|
};
|
|
10768
10935
|
var clearCmuxPassword = (exec) => exec("security", ["delete-generic-password", ...item]).status === 0;
|
|
10769
10936
|
|
|
@@ -11595,14 +11762,14 @@ import {
|
|
|
11595
11762
|
appendFileSync as appendFileSync2,
|
|
11596
11763
|
chmodSync as chmodSync5,
|
|
11597
11764
|
mkdirSync as mkdirSync18,
|
|
11598
|
-
readFileSync as
|
|
11765
|
+
readFileSync as readFileSync16,
|
|
11599
11766
|
existsSync as realExists,
|
|
11600
11767
|
rmSync as rmSync10,
|
|
11601
|
-
statSync as
|
|
11768
|
+
statSync as statSync6,
|
|
11602
11769
|
writeFileSync as writeFileSync16
|
|
11603
11770
|
} from "node:fs";
|
|
11604
|
-
import { hostname as hostname2, userInfo } from "node:os";
|
|
11605
|
-
import { dirname as
|
|
11771
|
+
import { hostname as hostname2, tmpdir, userInfo } from "node:os";
|
|
11772
|
+
import { dirname as dirname16, isAbsolute as isAbsolute3, join as join25, resolve as resolve9 } from "node:path";
|
|
11606
11773
|
|
|
11607
11774
|
// src/engine/beat.ts
|
|
11608
11775
|
var BEAT_EVERY_MS = 60000;
|
|
@@ -11614,7 +11781,7 @@ function beatBody(state, flags, host = {}, cap = {}) {
|
|
|
11614
11781
|
name: flags.name,
|
|
11615
11782
|
os: host.os ?? process.platform,
|
|
11616
11783
|
runner: flags.runner,
|
|
11617
|
-
version: host.version ?? "0.1.
|
|
11784
|
+
version: host.version ?? "0.1.62" ?? "dev",
|
|
11618
11785
|
running: live.length,
|
|
11619
11786
|
items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
|
|
11620
11787
|
...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
|
|
@@ -12054,17 +12221,19 @@ function parsePrView(stdout) {
|
|
|
12054
12221
|
const name = String(r.name ?? r.context ?? "");
|
|
12055
12222
|
if (!name)
|
|
12056
12223
|
continue;
|
|
12057
|
-
latest.set(name
|
|
12224
|
+
latest.set(`${String(r.workflowName ?? "")}\x00${name}`, {
|
|
12225
|
+
name,
|
|
12058
12226
|
status: String(r.status ?? "COMPLETED"),
|
|
12059
12227
|
conclusion: String(r.conclusion ?? r.state ?? "")
|
|
12060
12228
|
});
|
|
12061
12229
|
}
|
|
12062
12230
|
const failing = [];
|
|
12063
12231
|
let pending = 0;
|
|
12064
|
-
for (const
|
|
12065
|
-
if (FAILED.has(c.conclusion))
|
|
12066
|
-
failing.
|
|
12067
|
-
|
|
12232
|
+
for (const c of latest.values()) {
|
|
12233
|
+
if (FAILED.has(c.conclusion)) {
|
|
12234
|
+
if (!failing.includes(c.name))
|
|
12235
|
+
failing.push(c.name);
|
|
12236
|
+
} else if (c.status !== "COMPLETED" && c.conclusion !== "SUCCESS")
|
|
12068
12237
|
pending++;
|
|
12069
12238
|
else if (c.conclusion === "PENDING" || c.conclusion === "EXPECTED")
|
|
12070
12239
|
pending++;
|
|
@@ -12283,6 +12452,7 @@ function prComment(exec, repoPath, url, body) {
|
|
|
12283
12452
|
|
|
12284
12453
|
// src/engine/jiraSource.ts
|
|
12285
12454
|
var JIRA_LOG_MAX = 1000;
|
|
12455
|
+
var JIRA_MAX_PAGES = 20;
|
|
12286
12456
|
function nodeKeyOf(summary) {
|
|
12287
12457
|
return /^\s*\[([A-Za-z]{1,3})\]/.exec(summary)?.[1]?.toUpperCase();
|
|
12288
12458
|
}
|
|
@@ -12428,10 +12598,20 @@ function jiraSource(o) {
|
|
|
12428
12598
|
};
|
|
12429
12599
|
const read = async () => {
|
|
12430
12600
|
const jql = encodeURIComponent(`parent = ${epic} ORDER BY key`);
|
|
12431
|
-
const
|
|
12432
|
-
|
|
12433
|
-
|
|
12434
|
-
|
|
12601
|
+
const issues = [];
|
|
12602
|
+
let token;
|
|
12603
|
+
for (let page = 0;; page++) {
|
|
12604
|
+
if (page >= JIRA_MAX_PAGES)
|
|
12605
|
+
throw new Error(`Jira: ${epic} has more than ${JIRA_MAX_PAGES} pages of children`);
|
|
12606
|
+
const r = await call(`/rest/api/3/search/jql?jql=${jql}&fields=summary,description,status,issuelinks&maxResults=100${token ? `&nextPageToken=${encodeURIComponent(token)}` : ""}`);
|
|
12607
|
+
if (!r.ok)
|
|
12608
|
+
throw new Error(`Jira: could not read ${epic}'s children — ${errorOf(r)}`);
|
|
12609
|
+
if (Array.isArray(r.json?.issues))
|
|
12610
|
+
issues.push(...r.json.issues.filter(isObject8));
|
|
12611
|
+
token = str6(r.json?.nextPageToken);
|
|
12612
|
+
if (!token || r.json?.isLast === true)
|
|
12613
|
+
break;
|
|
12614
|
+
}
|
|
12435
12615
|
const nodes = issues.map(jiraNode);
|
|
12436
12616
|
byNode.clear();
|
|
12437
12617
|
for (const n of nodes)
|
|
@@ -12763,6 +12943,26 @@ function instructionsOf(s) {
|
|
|
12763
12943
|
const i = s;
|
|
12764
12944
|
return i && typeof i.instructions === "function" ? s : null;
|
|
12765
12945
|
}
|
|
12946
|
+
function mocksOf(s) {
|
|
12947
|
+
const m = s;
|
|
12948
|
+
return m && typeof m.finishMock === "function" && typeof m.failMock === "function" ? s : null;
|
|
12949
|
+
}
|
|
12950
|
+
function mockRunOf(row) {
|
|
12951
|
+
const m = isObject8(row.mockRun) ? row.mockRun : {};
|
|
12952
|
+
return { asked: isObject8(m.asked), running: isObject8(m.running) };
|
|
12953
|
+
}
|
|
12954
|
+
function askedMocks(r) {
|
|
12955
|
+
const mine = Array.isArray(r.mine) ? r.mine.filter(isObject8) : [];
|
|
12956
|
+
return mine.filter((row) => {
|
|
12957
|
+
const m = mockRunOf(row);
|
|
12958
|
+
return m.asked && !m.running;
|
|
12959
|
+
});
|
|
12960
|
+
}
|
|
12961
|
+
function mockBandText(b) {
|
|
12962
|
+
const lo = num5(b.lowMin);
|
|
12963
|
+
const hi = num5(b.highMin);
|
|
12964
|
+
return lo !== undefined && hi !== undefined ? `${lo}–${hi} min` : undefined;
|
|
12965
|
+
}
|
|
12766
12966
|
function instructionsFrom(waiting) {
|
|
12767
12967
|
if (!Array.isArray(waiting))
|
|
12768
12968
|
return [];
|
|
@@ -13049,6 +13249,8 @@ function sledRunning(r) {
|
|
|
13049
13249
|
const route = row.route;
|
|
13050
13250
|
if (isObject8(route) && route.drafting === true)
|
|
13051
13251
|
running++;
|
|
13252
|
+
if (mockRunOf(row).running)
|
|
13253
|
+
running++;
|
|
13052
13254
|
if (!isObject8(route) || !isObject8(route.armed))
|
|
13053
13255
|
continue;
|
|
13054
13256
|
running += keysIn(isObject8(route.states) ? route.states : {}, "running").length;
|
|
@@ -13084,14 +13286,12 @@ function routeText(route, states) {
|
|
|
13084
13286
|
}
|
|
13085
13287
|
function sledsSource(client, o) {
|
|
13086
13288
|
const routeOf = (q) => client.get(`/proxy/route?q=${encodeURIComponent(q)}`);
|
|
13087
|
-
|
|
13289
|
+
const mockRefused = new Map;
|
|
13290
|
+
async function pickup(sled, drafted, profile) {
|
|
13088
13291
|
const engine = o.engine;
|
|
13089
|
-
|
|
13090
|
-
if (profile?.pickup !== "auto")
|
|
13091
|
-
return null;
|
|
13092
|
-
if (profile.engine && !sameEngine(profile.engine, engine))
|
|
13292
|
+
if (!autoHere(profile))
|
|
13093
13293
|
return null;
|
|
13094
|
-
const atOnce = (o.atOnce ?? profile
|
|
13294
|
+
const atOnce = (o.atOnce ?? profile?.atOnce ?? 1) - drafted;
|
|
13095
13295
|
const row = nextPickup(sled, { atOnce, engine });
|
|
13096
13296
|
if (!row)
|
|
13097
13297
|
return null;
|
|
@@ -13139,7 +13339,7 @@ function sledsSource(client, o) {
|
|
|
13139
13339
|
let pack = "";
|
|
13140
13340
|
let brief = null;
|
|
13141
13341
|
try {
|
|
13142
|
-
brief = await
|
|
13342
|
+
brief = await client.get(`/proxy/route?q=${encodeURIComponent(project)}&draft=1`);
|
|
13143
13343
|
pack = (isObject8(brief?.draft) ? str6(brief.draft.pack) : undefined) ?? "";
|
|
13144
13344
|
} catch {
|
|
13145
13345
|
pack = "";
|
|
@@ -13171,8 +13371,94 @@ function sledsSource(client, o) {
|
|
|
13171
13371
|
};
|
|
13172
13372
|
return { item, ready: [], running: [], landed: false, seatIds: [], draft: { claim, why } };
|
|
13173
13373
|
}
|
|
13374
|
+
function autoHere(profile) {
|
|
13375
|
+
if (profile?.pickup !== "auto")
|
|
13376
|
+
return false;
|
|
13377
|
+
return !profile.engine || sameEngine(profile.engine, o.engine);
|
|
13378
|
+
}
|
|
13379
|
+
async function mocks(sled, held, profile) {
|
|
13380
|
+
const waiting = askedMocks(sled);
|
|
13381
|
+
if (waiting.length === 0 || !autoHere(profile))
|
|
13382
|
+
return [];
|
|
13383
|
+
let room = (o.atOnce ?? profile?.atOnce ?? 1) - sledRunning(sled) - held;
|
|
13384
|
+
const out = [];
|
|
13385
|
+
for (const row of waiting) {
|
|
13386
|
+
if (room <= 0)
|
|
13387
|
+
break;
|
|
13388
|
+
const claim = await takeMock(row);
|
|
13389
|
+
if (!claim)
|
|
13390
|
+
continue;
|
|
13391
|
+
out.push(claim);
|
|
13392
|
+
room--;
|
|
13393
|
+
}
|
|
13394
|
+
return out;
|
|
13395
|
+
}
|
|
13396
|
+
async function takeMock(row) {
|
|
13397
|
+
const project = str6(row.project) ?? str6(row.key);
|
|
13398
|
+
if (!project)
|
|
13399
|
+
return null;
|
|
13400
|
+
const item = str6(row.key) ?? project;
|
|
13401
|
+
const runner = typeof o.runner === "function" ? o.runner() : o.runner;
|
|
13402
|
+
const r = await client.postFull("/proxy/mock", {
|
|
13403
|
+
project,
|
|
13404
|
+
take: true,
|
|
13405
|
+
engine: o.engine,
|
|
13406
|
+
...runner ? { runner } : {},
|
|
13407
|
+
...o.leaseMin !== undefined ? { leaseMin: o.leaseMin } : {}
|
|
13408
|
+
});
|
|
13409
|
+
if (!r || r.status >= 300 || !r.json || r.json.ok === false || !str6(r.json.runId)) {
|
|
13410
|
+
const why = r ? serverMessage(r) : UNREACHABLE3;
|
|
13411
|
+
if (mockRefused.get(item) !== why)
|
|
13412
|
+
o.log?.(`Pickup: Auto could not take ${item}'s mock — ${why}`);
|
|
13413
|
+
mockRefused.set(item, why);
|
|
13414
|
+
return null;
|
|
13415
|
+
}
|
|
13416
|
+
mockRefused.delete(item);
|
|
13417
|
+
const j = r.json;
|
|
13418
|
+
const key = str6(j.key) ?? item;
|
|
13419
|
+
const band = isObject8(j.band) ? mockBandText(j.band) : undefined;
|
|
13420
|
+
o.log?.(`Pickup: Auto is drawing ${key}'s mock — a no-code session${band ? `, sized ${band}` : ""}`);
|
|
13421
|
+
const leaseUntil = num5(j.leaseUntil);
|
|
13422
|
+
return {
|
|
13423
|
+
item: key,
|
|
13424
|
+
node: MOCK_NODE,
|
|
13425
|
+
title: str6(j.title) ?? key,
|
|
13426
|
+
pack: str6(j.pack) ?? "",
|
|
13427
|
+
repos: strings(j.repos),
|
|
13428
|
+
kind: "mock",
|
|
13429
|
+
runId: str6(j.runId),
|
|
13430
|
+
...leaseUntil !== undefined ? { leaseUntil } : {},
|
|
13431
|
+
...str6(j.seatId) ? { seatId: str6(j.seatId) } : {},
|
|
13432
|
+
...str6(j.runToken) ? { runToken: str6(j.runToken) } : {}
|
|
13433
|
+
};
|
|
13434
|
+
}
|
|
13435
|
+
async function postMock(body, what) {
|
|
13436
|
+
const r = await client.postFull("/proxy/mock", body);
|
|
13437
|
+
if (!r)
|
|
13438
|
+
throw new Error(`${UNREACHABLE3} — ${what} not recorded`);
|
|
13439
|
+
if (r.status < 300 && r.json?.ok !== false)
|
|
13440
|
+
return { ok: true };
|
|
13441
|
+
if (r.status === 401 || r.status === 403 || r.status === 404 && !r.json)
|
|
13442
|
+
throw new SeatTokenError(r.status);
|
|
13443
|
+
if (r.status === 409)
|
|
13444
|
+
return { gone: serverMessage(r) };
|
|
13445
|
+
if (r.status === 400 || r.status === 413)
|
|
13446
|
+
return { refused: serverMessage(r) };
|
|
13447
|
+
throw new Error(`${what}: ${serverMessage(r)}`);
|
|
13448
|
+
}
|
|
13449
|
+
async function failMock(claim, log, engine) {
|
|
13450
|
+
if (!claim.runId)
|
|
13451
|
+
return { gone: "no run" };
|
|
13452
|
+
return postMock({ runId: claim.runId, engine, fail: { log: log.slice(-FAIL_LOG_MAX) } }, `${claim.item}/${claim.node} fail`);
|
|
13453
|
+
}
|
|
13174
13454
|
return {
|
|
13175
13455
|
name: "sleds",
|
|
13456
|
+
async finishMock(claim, html, f) {
|
|
13457
|
+
if (!claim.runId)
|
|
13458
|
+
return { gone: "no run" };
|
|
13459
|
+
return postMock({ runId: claim.runId, engine: f.engine, html, ...f.model ? { model: f.model } : {} }, `${claim.item}/${claim.node} mock`);
|
|
13460
|
+
},
|
|
13461
|
+
failMock,
|
|
13176
13462
|
async read() {
|
|
13177
13463
|
if (o.only) {
|
|
13178
13464
|
const q = o.only;
|
|
@@ -13183,6 +13469,11 @@ function sledsSource(client, o) {
|
|
|
13183
13469
|
const r = await readOrSay(client, "/proxy/sled", "the sled");
|
|
13184
13470
|
const items = sledItems(r, o.armedOnly === true, o.engine);
|
|
13185
13471
|
if (o.armedOnly && o.engine) {
|
|
13472
|
+
let profileRead;
|
|
13473
|
+
const profileNow = () => {
|
|
13474
|
+
profileRead ??= readProfile(client);
|
|
13475
|
+
return profileRead;
|
|
13476
|
+
};
|
|
13186
13477
|
const mine = Array.isArray(r.mine) ? r.mine.filter(isObject8) : [];
|
|
13187
13478
|
for (const row of mine) {
|
|
13188
13479
|
const route = row.route;
|
|
@@ -13197,7 +13488,7 @@ function sledsSource(client, o) {
|
|
|
13197
13488
|
const waiting = armedDrafts(r, o.engine);
|
|
13198
13489
|
let drafted = 0;
|
|
13199
13490
|
if (waiting.length > 0) {
|
|
13200
|
-
const cap = o.atOnce ?? (await
|
|
13491
|
+
const cap = o.atOnce ?? (await profileNow())?.atOnce ?? 1;
|
|
13201
13492
|
let room = cap - sledRunning(r);
|
|
13202
13493
|
for (const row of waiting) {
|
|
13203
13494
|
const item = str6(row.key) ?? String(row.project);
|
|
@@ -13215,7 +13506,22 @@ function sledsSource(client, o) {
|
|
|
13215
13506
|
}
|
|
13216
13507
|
}
|
|
13217
13508
|
}
|
|
13218
|
-
const
|
|
13509
|
+
const asked = askedMocks(r).length > 0 ? await mocks(r, drafted, await profileNow()) : [];
|
|
13510
|
+
for (const claim of asked) {
|
|
13511
|
+
const it = items.find((x) => x.item === claim.item);
|
|
13512
|
+
if (it)
|
|
13513
|
+
it.mock = { claim };
|
|
13514
|
+
else
|
|
13515
|
+
items.push({
|
|
13516
|
+
item: claim.item,
|
|
13517
|
+
ready: [],
|
|
13518
|
+
running: [],
|
|
13519
|
+
landed: false,
|
|
13520
|
+
seatIds: [],
|
|
13521
|
+
mock: { claim }
|
|
13522
|
+
});
|
|
13523
|
+
}
|
|
13524
|
+
const picked = await pickup(r, drafted + asked.length, await profileNow());
|
|
13219
13525
|
if (picked)
|
|
13220
13526
|
items.push(picked);
|
|
13221
13527
|
}
|
|
@@ -13283,6 +13589,8 @@ function sledsSource(client, o) {
|
|
|
13283
13589
|
});
|
|
13284
13590
|
if (r?.status !== 409)
|
|
13285
13591
|
return "running";
|
|
13592
|
+
if (claim.kind === "mock")
|
|
13593
|
+
return "lost";
|
|
13286
13594
|
let route;
|
|
13287
13595
|
try {
|
|
13288
13596
|
route = await routeOf(claim.item);
|
|
@@ -13308,6 +13616,15 @@ function sledsSource(client, o) {
|
|
|
13308
13616
|
return "lost";
|
|
13309
13617
|
},
|
|
13310
13618
|
async report(claim, outcome, by) {
|
|
13619
|
+
if (claim.kind === "mock") {
|
|
13620
|
+
if (outcome.kind === "pr" || outcome.kind === "merged")
|
|
13621
|
+
return;
|
|
13622
|
+
const log = outcome.kind === "park" ? outcome.question : outcome.kind === "release" ? `released: ${outcome.why}` : outcome.log;
|
|
13623
|
+
const r = await failMock(claim, log, by);
|
|
13624
|
+
if ("refused" in r)
|
|
13625
|
+
throw new ReportRefusedError(400, `${claim.item}/${claim.node} fail: ${r.refused}`, true);
|
|
13626
|
+
return;
|
|
13627
|
+
}
|
|
13311
13628
|
let path;
|
|
13312
13629
|
let body;
|
|
13313
13630
|
if (outcome.kind === "pr" || outcome.kind === "merged") {
|
|
@@ -13823,6 +14140,24 @@ function fastForwardUntouched(exec, path, base, log) {
|
|
|
13823
14140
|
var INSTALL_TIMEOUT_MS = 15 * 60000;
|
|
13824
14141
|
var MANAGERS = new Set(["pnpm", "npm", "yarn", "bun"]);
|
|
13825
14142
|
var INSTALL_VERBS = new Set(["install", "i", "ci"]);
|
|
14143
|
+
var INSTALL_FLAGS = new Set([
|
|
14144
|
+
"--frozen-lockfile",
|
|
14145
|
+
"--immutable",
|
|
14146
|
+
"--prefer-offline",
|
|
14147
|
+
"--offline",
|
|
14148
|
+
"--ignore-scripts",
|
|
14149
|
+
"--prod",
|
|
14150
|
+
"--production",
|
|
14151
|
+
"--no-optional",
|
|
14152
|
+
"--no-audit",
|
|
14153
|
+
"--no-fund",
|
|
14154
|
+
"--non-interactive",
|
|
14155
|
+
"--silent",
|
|
14156
|
+
"--reporter=silent",
|
|
14157
|
+
"--reporter=append-only",
|
|
14158
|
+
"--loglevel=error",
|
|
14159
|
+
"--loglevel=warn"
|
|
14160
|
+
]);
|
|
13826
14161
|
function installArgv(command) {
|
|
13827
14162
|
const line = command?.trim().replace(/^`|`$/g, "") ?? "";
|
|
13828
14163
|
if (!line || /[;&|<>$`()\n]/.test(line))
|
|
@@ -13838,7 +14173,7 @@ function installArgv(command) {
|
|
|
13838
14173
|
rest = argv.slice(2);
|
|
13839
14174
|
else
|
|
13840
14175
|
return null;
|
|
13841
|
-
return rest.every((a) =>
|
|
14176
|
+
return rest.every((a) => INSTALL_FLAGS.has(a)) ? argv : null;
|
|
13842
14177
|
}
|
|
13843
14178
|
function lockfileInstall(path, exists) {
|
|
13844
14179
|
if (exists(join17(path, "pnpm-lock.yaml")))
|
|
@@ -14047,6 +14382,7 @@ function mcpConfigsOf(state) {
|
|
|
14047
14382
|
}
|
|
14048
14383
|
async function tick(deps) {
|
|
14049
14384
|
deps.setupNoted ??= new Set;
|
|
14385
|
+
deps.noClone ??= new Map;
|
|
14050
14386
|
const made = new Set(mcpConfigsOf(deps.readState()));
|
|
14051
14387
|
const write = deps.writeMcpConfig;
|
|
14052
14388
|
const d = write ? {
|
|
@@ -14136,6 +14472,11 @@ async function tickOnce(d) {
|
|
|
14136
14472
|
keep.push(run);
|
|
14137
14473
|
continue;
|
|
14138
14474
|
}
|
|
14475
|
+
if (run.kind === "mock") {
|
|
14476
|
+
if (await settleMock(d, run, claim, runner, finished))
|
|
14477
|
+
keep.push(run);
|
|
14478
|
+
continue;
|
|
14479
|
+
}
|
|
14139
14480
|
if (run.parked) {
|
|
14140
14481
|
if (liveAnswerer(run) && await settleAnswerer(d, run) === "released")
|
|
14141
14482
|
continue;
|
|
@@ -14208,6 +14549,7 @@ async function tickOnce(d) {
|
|
|
14208
14549
|
try {
|
|
14209
14550
|
await d.source.report(claim, outcome, d.engine);
|
|
14210
14551
|
finished.push({ item: run.item, node: run.node, outcome });
|
|
14552
|
+
endNodeSession(d, runner, run.handle, run.repoPath, ref(run));
|
|
14211
14553
|
} catch (e) {
|
|
14212
14554
|
d.log(`${ref(run)}: exited with no PR; the fail report failed, retrying next tick: ${message(e)}`);
|
|
14213
14555
|
keep.push(run);
|
|
@@ -14240,10 +14582,11 @@ async function tickOnce(d) {
|
|
|
14240
14582
|
run.seenTicks = (run.seenTicks ?? 0) + 1;
|
|
14241
14583
|
if (!ghDown) {
|
|
14242
14584
|
const quiet = now - (run.seenAt ?? run.startedAt);
|
|
14585
|
+
const provider = providerFailure(shown);
|
|
14243
14586
|
if (quiet >= PROVIDER_RETRY_MIN * 60000)
|
|
14244
|
-
failing =
|
|
14245
|
-
asked = !
|
|
14246
|
-
idle = !
|
|
14587
|
+
failing = provider;
|
|
14588
|
+
asked = !provider && run.seenTicks >= STILL_TICKS && askedAndStopped(shown);
|
|
14589
|
+
idle = !provider && (asked || quiet >= d.idleMin * 60000);
|
|
14247
14590
|
}
|
|
14248
14591
|
}
|
|
14249
14592
|
}
|
|
@@ -14263,6 +14606,11 @@ async function tickOnce(d) {
|
|
|
14263
14606
|
continue;
|
|
14264
14607
|
}
|
|
14265
14608
|
if (beat === "done") {
|
|
14609
|
+
if (ghDown) {
|
|
14610
|
+
d.log(`${ref(run)}: moved on, but its PR is not seen yet — kept until GitHub answers`);
|
|
14611
|
+
keep.push(run);
|
|
14612
|
+
continue;
|
|
14613
|
+
}
|
|
14266
14614
|
d.log(`${ref(run)}: moved on without the engine (PR or landed) — the session is left open (${runner.watchHint(run.handle)})`);
|
|
14267
14615
|
continue;
|
|
14268
14616
|
}
|
|
@@ -14374,6 +14722,9 @@ async function tickOnce(d) {
|
|
|
14374
14722
|
for (const it of items)
|
|
14375
14723
|
if (it.draft && !takeNone && !startsHeld(d))
|
|
14376
14724
|
await startDraft(d, it.draft.claim, it.draft.why, state, started, finished);
|
|
14725
|
+
for (const it of items)
|
|
14726
|
+
if (it.mock && !takeNone && !startsHeld(d))
|
|
14727
|
+
await startMock(d, it.mock.claim, state, started, finished);
|
|
14377
14728
|
const live = new Map(items.map((i) => [i.item, i]));
|
|
14378
14729
|
const unheld = state.runs.filter((r) => r.parked && (live.get(r.item)?.landed ?? true));
|
|
14379
14730
|
if (unheld.length) {
|
|
@@ -14400,8 +14751,14 @@ async function tickOnce(d) {
|
|
|
14400
14751
|
await rereadAtOnce(d);
|
|
14401
14752
|
const cap = await machineCap(d);
|
|
14402
14753
|
const atOnce = startsHeld(d) ? 0 : cap;
|
|
14754
|
+
for (const [k, c] of d.noClone ?? [])
|
|
14755
|
+
if (!alive(c) || typeof d.resolveRepo(c) === "string")
|
|
14756
|
+
d.noClone?.delete(k);
|
|
14403
14757
|
const takes = planTakes({
|
|
14404
|
-
items
|
|
14758
|
+
items: d.noClone?.size ? items.map((i) => ({
|
|
14759
|
+
...i,
|
|
14760
|
+
ready: i.ready.filter((n) => !d.noClone?.has(ref({ item: i.item, node: n })))
|
|
14761
|
+
})) : items,
|
|
14405
14762
|
tracked: [
|
|
14406
14763
|
...state.runs.filter((r) => !r.pr && (!r.parked || liveAnswerer(r))).map((r) => ({
|
|
14407
14764
|
item: r.item,
|
|
@@ -14474,6 +14831,7 @@ async function tickOnce(d) {
|
|
|
14474
14831
|
d.setupNoted?.add(repoPath.error);
|
|
14475
14832
|
d.log(`${at}: released, no try spent — ${repoPath.error}`);
|
|
14476
14833
|
}
|
|
14834
|
+
d.noClone?.set(at, claim);
|
|
14477
14835
|
await report({ kind: "release", why: repoPath.error });
|
|
14478
14836
|
continue;
|
|
14479
14837
|
}
|
|
@@ -14496,10 +14854,17 @@ async function tickOnce(d) {
|
|
|
14496
14854
|
}
|
|
14497
14855
|
let start;
|
|
14498
14856
|
let mcpConfig;
|
|
14857
|
+
let made;
|
|
14858
|
+
const dropMade = () => {
|
|
14859
|
+
if (made)
|
|
14860
|
+
removeEngineWorktree(d, repoPath, made, at);
|
|
14861
|
+
};
|
|
14499
14862
|
try {
|
|
14500
14863
|
const base = d.defaultBranch(d.exec, repoPath);
|
|
14501
14864
|
const { install, gate } = claimRunOf(claim.run, claim.repos[0]);
|
|
14502
14865
|
const worktree = d.runner.makesWorktree ? repoPath : d.ensureWorktree(d.exec, repoPath, branch, worktreePath(repoPath, name), base, install) ?? worktreePath(repoPath, name);
|
|
14866
|
+
if (!d.runner.makesWorktree)
|
|
14867
|
+
made = worktree;
|
|
14503
14868
|
const prTitle = d.prTitleOf?.(claim);
|
|
14504
14869
|
mcpConfig = engineMcpConfigFor(d, name, claim.runToken, at, worktree);
|
|
14505
14870
|
const allow = gateAllowRules(gate);
|
|
@@ -14535,6 +14900,7 @@ async function tickOnce(d) {
|
|
|
14535
14900
|
};
|
|
14536
14901
|
} catch (e) {
|
|
14537
14902
|
d.log(`${at}: could not start: ${message(e)}`);
|
|
14903
|
+
dropMade();
|
|
14538
14904
|
await report({ kind: "fail", log: `The engine could not start the session: ${message(e)}` });
|
|
14539
14905
|
continue;
|
|
14540
14906
|
}
|
|
@@ -14545,6 +14911,7 @@ async function tickOnce(d) {
|
|
|
14545
14911
|
const down = probeRunner(d);
|
|
14546
14912
|
if (down) {
|
|
14547
14913
|
d.log(`${at}: released — the runner could not start it: ${message(e)}`);
|
|
14914
|
+
dropMade();
|
|
14548
14915
|
await report({ kind: "release", why: `runner unavailable: ${down}` });
|
|
14549
14916
|
continue;
|
|
14550
14917
|
}
|
|
@@ -14563,6 +14930,8 @@ async function tickOnce(d) {
|
|
|
14563
14930
|
if (slow)
|
|
14564
14931
|
d.log(`${at}: ${slow} ${inRow} times in a row — failed, not released again`);
|
|
14565
14932
|
d.log(`${at}: could not start: ${message(e)}`);
|
|
14933
|
+
if (!slow)
|
|
14934
|
+
dropMade();
|
|
14566
14935
|
await report({ kind: "fail", log: `The engine could not start the session: ${message(e)}` });
|
|
14567
14936
|
continue;
|
|
14568
14937
|
}
|
|
@@ -14591,18 +14960,9 @@ async function tickOnce(d) {
|
|
|
14591
14960
|
setLane(d, d.runner, handle, "working");
|
|
14592
14961
|
try {
|
|
14593
14962
|
const beat = await d.source.heartbeat(claim, watch);
|
|
14594
|
-
if (beat === "parked" || beat === "done") {
|
|
14595
|
-
|
|
14596
|
-
|
|
14597
|
-
continue;
|
|
14598
|
-
}
|
|
14599
|
-
if (beat === "lost") {
|
|
14600
|
-
d.log(`${at}: the claim was lost as the session started — stopping it`);
|
|
14601
|
-
try {
|
|
14602
|
-
d.runner.stop(handle);
|
|
14603
|
-
} catch (e) {
|
|
14604
|
-
d.log(`${at}: could not stop the session: ${message(e)}`);
|
|
14605
|
-
}
|
|
14963
|
+
if (beat === "parked" || beat === "done" || beat === "lost") {
|
|
14964
|
+
d.log(beat === "lost" ? `${at}: the claim was lost as the session started — stopping it` : `${at}: the node moved on as the session started (${beat}) — stopping it`);
|
|
14965
|
+
endNodeSession(d, d.runner, handle, repoPath, at);
|
|
14606
14966
|
state.runs = state.runs.filter((r) => r !== run);
|
|
14607
14967
|
save();
|
|
14608
14968
|
continue;
|
|
@@ -15732,26 +16092,250 @@ ${shown}`;
|
|
|
15732
16092
|
endDraft(d, run, runner);
|
|
15733
16093
|
return false;
|
|
15734
16094
|
}
|
|
15735
|
-
function endDraft(d, run, runner) {
|
|
16095
|
+
function endDraft(d, run, runner, who = "drafter") {
|
|
15736
16096
|
try {
|
|
15737
16097
|
if (runner.status(run.handle) === "running")
|
|
15738
16098
|
runner.stop(run.handle);
|
|
15739
16099
|
} catch (e) {
|
|
15740
|
-
d.log(`${ref(run)}: could not close the session: ${message(e)}`);
|
|
16100
|
+
d.log(`${ref(run)}: could not close the session: ${message(e)}`);
|
|
16101
|
+
}
|
|
16102
|
+
const wt = run.handle.cwd;
|
|
16103
|
+
if (wt === run.repoPath)
|
|
16104
|
+
return;
|
|
16105
|
+
try {
|
|
16106
|
+
if (runner.makesWorktree) {
|
|
16107
|
+
const note = runner.removeWorktree?.(run.handle, run.repoPath);
|
|
16108
|
+
if (note)
|
|
16109
|
+
d.log(`${ref(run)}: ${note}`);
|
|
16110
|
+
} else if (wt.startsWith(`${run.repoPath}/.worktrees/`)) {
|
|
16111
|
+
d.removeWorktree(d.exec, run.repoPath, wt);
|
|
16112
|
+
}
|
|
16113
|
+
} catch (e) {
|
|
16114
|
+
d.log(`${ref(run)}: kept the ${who}'s checkout ${wt}: ${message(e)}`);
|
|
16115
|
+
}
|
|
16116
|
+
}
|
|
16117
|
+
async function startMock(d, claim, state, started, finished) {
|
|
16118
|
+
const at = ref(claim);
|
|
16119
|
+
const fail = async (log) => {
|
|
16120
|
+
d.log(`${at}: the mock was not drawn — ${log}`);
|
|
16121
|
+
try {
|
|
16122
|
+
await d.source.report(claim, { kind: "fail", log }, d.engine);
|
|
16123
|
+
} catch (e) {
|
|
16124
|
+
d.log(`${at}: fail report failed: ${message(e)}`);
|
|
16125
|
+
}
|
|
16126
|
+
finished.push({ item: claim.item, node: claim.node, outcome: { kind: "fail", log } });
|
|
16127
|
+
};
|
|
16128
|
+
if (!mocksOf(d.source) || !d.mockOut || !d.readMock) {
|
|
16129
|
+
await fail("this engine cannot draw mocks (its source or its files do not carry them)");
|
|
16130
|
+
return;
|
|
16131
|
+
}
|
|
16132
|
+
const repoPath = d.resolveRepo(claim);
|
|
16133
|
+
if (typeof repoPath !== "string") {
|
|
16134
|
+
await fail(repoPath.error);
|
|
16135
|
+
return;
|
|
16136
|
+
}
|
|
16137
|
+
const name = sessionName(claim.item, MOCK_NODE);
|
|
16138
|
+
const branch = nodeBranch(claim.item, MOCK_NODE);
|
|
16139
|
+
let handle;
|
|
16140
|
+
let out;
|
|
16141
|
+
let base;
|
|
16142
|
+
let launch;
|
|
16143
|
+
try {
|
|
16144
|
+
base = d.defaultBranch(d.exec, repoPath);
|
|
16145
|
+
const worktree = d.runner.makesWorktree ? repoPath : d.ensureDraftWorktree(d.exec, repoPath, worktreePath(repoPath, name), base) ?? worktreePath(repoPath, name);
|
|
16146
|
+
out = d.mockOut(name);
|
|
16147
|
+
const prompt = mockPrompt({
|
|
16148
|
+
item: claim.item,
|
|
16149
|
+
title: claim.title,
|
|
16150
|
+
pack: claim.pack,
|
|
16151
|
+
out,
|
|
16152
|
+
base,
|
|
16153
|
+
engine: d.engine
|
|
16154
|
+
});
|
|
16155
|
+
launch = nodeLaunchFor(d, at);
|
|
16156
|
+
const allow = [`Edit(/${out})`];
|
|
16157
|
+
handle = d.runner.start({
|
|
16158
|
+
name,
|
|
16159
|
+
repoPath,
|
|
16160
|
+
worktree,
|
|
16161
|
+
branch,
|
|
16162
|
+
base,
|
|
16163
|
+
promptFile: d.writePrompt(name, prompt),
|
|
16164
|
+
permissionMode: d.permissionMode,
|
|
16165
|
+
...launchOptions(launch),
|
|
16166
|
+
...sandboxFor(d, name, worktree, allow),
|
|
16167
|
+
...hooksFor(d, name, allow),
|
|
16168
|
+
...mainCheckoutFor(d, worktree)
|
|
16169
|
+
});
|
|
16170
|
+
} catch (e) {
|
|
16171
|
+
await fail(`the engine could not start the session: ${message(e)}`);
|
|
16172
|
+
return;
|
|
16173
|
+
}
|
|
16174
|
+
const watch = safeWatch(d.runner, handle);
|
|
16175
|
+
const run = {
|
|
16176
|
+
item: claim.item,
|
|
16177
|
+
node: MOCK_NODE,
|
|
16178
|
+
title: claim.title,
|
|
16179
|
+
kind: "mock",
|
|
16180
|
+
mock: { out, base, ...launch.model ? { model: launch.model } : {} },
|
|
16181
|
+
...claim.seatId ? { seatId: claim.seatId } : {},
|
|
16182
|
+
...claim.runId ? { runId: claim.runId } : {},
|
|
16183
|
+
...claim.leaseUntil !== undefined ? { leaseUntil: claim.leaseUntil } : {},
|
|
16184
|
+
branch,
|
|
16185
|
+
repoPath,
|
|
16186
|
+
handle,
|
|
16187
|
+
startedAt: d.now(),
|
|
16188
|
+
seenAt: d.now()
|
|
16189
|
+
};
|
|
16190
|
+
state.runs.push(run);
|
|
16191
|
+
d.writeState(state);
|
|
16192
|
+
d.log(`${at}: drawing a mock — no code; the HTML goes to ${out}`);
|
|
16193
|
+
try {
|
|
16194
|
+
await d.source.heartbeat(claim, watch);
|
|
16195
|
+
} catch (e) {
|
|
16196
|
+
d.log(`${at}: started, but the watch handle was not recorded: ${message(e)}`);
|
|
16197
|
+
}
|
|
16198
|
+
started.push({ item: claim.item, node: MOCK_NODE, watch, watchTarget: watchTarget(handle) });
|
|
16199
|
+
}
|
|
16200
|
+
function mockChangedCode(exec, cwd, base) {
|
|
16201
|
+
const status = exec("git", ["-C", cwd, "status", "--porcelain"]);
|
|
16202
|
+
if (status.status !== 0)
|
|
16203
|
+
return `git could not read the checkout: ${status.stderr.trim()}`;
|
|
16204
|
+
const changed = status.stdout.split(`
|
|
16205
|
+
`).filter((l) => l.trim());
|
|
16206
|
+
if (changed.length)
|
|
16207
|
+
return `${changed.length} file${changed.length === 1 ? "" : "s"} changed (${changed.slice(0, 5).map((l) => l.slice(3).trim()).join(", ")}${changed.length > 5 ? ", …" : ""})`;
|
|
16208
|
+
const ahead = exec("git", ["-C", cwd, "rev-list", "--count", `origin/${base}..HEAD`]);
|
|
16209
|
+
if (ahead.status !== 0)
|
|
16210
|
+
return `git could not count the commits: ${ahead.stderr.trim()}`;
|
|
16211
|
+
const n = Number.parseInt(ahead.stdout.trim(), 10);
|
|
16212
|
+
if (!Number.isFinite(n))
|
|
16213
|
+
return "git could not count the commits";
|
|
16214
|
+
return n > 0 ? `${n} commit${n === 1 ? "" : "s"} past origin/${base}` : null;
|
|
16215
|
+
}
|
|
16216
|
+
async function settleMock(d, run, claim, runner, finished) {
|
|
16217
|
+
let beat;
|
|
16218
|
+
try {
|
|
16219
|
+
beat = await d.source.heartbeat(claim, safeWatch(runner, run.handle));
|
|
16220
|
+
} catch (e) {
|
|
16221
|
+
d.log(`${ref(run)}: heartbeat failed, retrying next tick: ${message(e)}`);
|
|
16222
|
+
return true;
|
|
16223
|
+
}
|
|
16224
|
+
if (beat !== "running") {
|
|
16225
|
+
d.log(`${ref(run)}: the mock claim was lost — stopping the session`);
|
|
16226
|
+
endDraft(d, run, runner, "mock session");
|
|
16227
|
+
return false;
|
|
16228
|
+
}
|
|
16229
|
+
if (run.runId)
|
|
16230
|
+
run.leaseUntil = d.now() + d.leaseMin * 60000;
|
|
16231
|
+
let status;
|
|
16232
|
+
try {
|
|
16233
|
+
status = runner.status(run.handle);
|
|
16234
|
+
} catch (e) {
|
|
16235
|
+
d.log(`${ref(run)}: could not read the session's status: ${message(e)}`);
|
|
16236
|
+
return true;
|
|
16237
|
+
}
|
|
16238
|
+
const out = run.mock?.out;
|
|
16239
|
+
const read = out ? d.readMock?.(out) ?? null : null;
|
|
16240
|
+
const drawn = read?.trim() ? read : null;
|
|
16241
|
+
if (status === "running") {
|
|
16242
|
+
if (drawn) {
|
|
16243
|
+
const print = fingerprint(drawn);
|
|
16244
|
+
if (run.mock && run.mock.drawn !== print) {
|
|
16245
|
+
run.mock.drawn = print;
|
|
16246
|
+
return true;
|
|
16247
|
+
}
|
|
16248
|
+
} else {
|
|
16249
|
+
if (!runner.readsSession)
|
|
16250
|
+
return true;
|
|
16251
|
+
let shown = "";
|
|
16252
|
+
try {
|
|
16253
|
+
shown = runner.read(run.handle);
|
|
16254
|
+
} catch {
|
|
16255
|
+
shown = "";
|
|
16256
|
+
}
|
|
16257
|
+
const now = d.now();
|
|
16258
|
+
const print = fingerprint(shown);
|
|
16259
|
+
if (run.seen !== print) {
|
|
16260
|
+
run.seen = print;
|
|
16261
|
+
run.seenAt = now;
|
|
16262
|
+
return true;
|
|
16263
|
+
}
|
|
16264
|
+
if (now - (run.seenAt ?? run.startedAt) < d.idleMin * 60000)
|
|
16265
|
+
return true;
|
|
16266
|
+
}
|
|
16267
|
+
}
|
|
16268
|
+
const changed = mockChangedCode(d.exec, run.handle.cwd, run.mock?.base ?? "main");
|
|
16269
|
+
let log = "";
|
|
16270
|
+
if (changed)
|
|
16271
|
+
log = `the mock run changed code: ${changed}. Nothing was attached.`;
|
|
16272
|
+
else if (!drawn) {
|
|
16273
|
+
let tail = "";
|
|
16274
|
+
try {
|
|
16275
|
+
tail = runner.read(run.handle);
|
|
16276
|
+
} catch (e) {
|
|
16277
|
+
tail = `(the session's output could not be read: ${message(e)})`;
|
|
16278
|
+
}
|
|
16279
|
+
log = status === "exited" ? `The session exited with no HTML at ${out ?? "its file"}.${tail ? `
|
|
16280
|
+
${tail}` : ""}` : `Idle for ${d.idleMin} min with no HTML written.${tail ? ` Last output:
|
|
16281
|
+
${tail}` : ""}`;
|
|
16282
|
+
}
|
|
16283
|
+
const mocks = mocksOf(d.source);
|
|
16284
|
+
if (!log && mocks && drawn) {
|
|
16285
|
+
let posted;
|
|
16286
|
+
try {
|
|
16287
|
+
posted = await mocks.finishMock(claim, drawn, {
|
|
16288
|
+
engine: d.engine,
|
|
16289
|
+
...run.mock?.model ? { model: run.mock.model } : {}
|
|
16290
|
+
});
|
|
16291
|
+
} catch (e) {
|
|
16292
|
+
d.log(`${ref(run)}: the mock is drawn; posting it failed, retrying next tick: ${message(e)}`);
|
|
16293
|
+
return true;
|
|
16294
|
+
}
|
|
16295
|
+
if ("ok" in posted) {
|
|
16296
|
+
d.log(`${ref(run)}: mock drawn — attached to ${run.item} as its mock, for a person to sign`);
|
|
16297
|
+
endDraft(d, run, runner, "mock session");
|
|
16298
|
+
return false;
|
|
16299
|
+
}
|
|
16300
|
+
if ("gone" in posted) {
|
|
16301
|
+
d.log(`${ref(run)}: the mock is drawn, but SLEDS no longer runs it (${posted.gone}) — not attached`);
|
|
16302
|
+
endDraft(d, run, runner, "mock session");
|
|
16303
|
+
return false;
|
|
16304
|
+
}
|
|
16305
|
+
log = `SLEDS refused the HTML: ${posted.refused}`;
|
|
16306
|
+
}
|
|
16307
|
+
if (!log)
|
|
16308
|
+
log = "this engine cannot post mocks";
|
|
16309
|
+
const outcome = { kind: "fail", log };
|
|
16310
|
+
try {
|
|
16311
|
+
await d.source.report(claim, outcome, d.engine);
|
|
16312
|
+
} catch (e) {
|
|
16313
|
+
d.log(`${ref(run)}: the mock run failed; the fail report failed, retrying next tick: ${message(e)}`);
|
|
16314
|
+
return true;
|
|
16315
|
+
}
|
|
16316
|
+
d.log(`${ref(run)}: the mock was not drawn — ${log.split(`
|
|
16317
|
+
`)[0]}`);
|
|
16318
|
+
finished.push({ item: run.item, node: run.node, outcome });
|
|
16319
|
+
endDraft(d, run, runner, "mock session");
|
|
16320
|
+
return false;
|
|
16321
|
+
}
|
|
16322
|
+
function endNodeSession(d, runner, h, repoPath, at) {
|
|
16323
|
+
try {
|
|
16324
|
+
if (runner.status(h) === "running")
|
|
16325
|
+
runner.stop(h);
|
|
16326
|
+
} catch (e) {
|
|
16327
|
+
d.log(`${at}: could not close the session: ${message(e)}`);
|
|
15741
16328
|
}
|
|
15742
|
-
|
|
15743
|
-
|
|
16329
|
+
if (!runner.makesWorktree)
|
|
16330
|
+
removeEngineWorktree(d, repoPath, h.cwd, at);
|
|
16331
|
+
}
|
|
16332
|
+
function removeEngineWorktree(d, repoPath, wt, at) {
|
|
16333
|
+
if (wt === repoPath || !wt.startsWith(`${repoPath}/.worktrees/`))
|
|
15744
16334
|
return;
|
|
15745
16335
|
try {
|
|
15746
|
-
|
|
15747
|
-
const note = runner.removeWorktree?.(run.handle, run.repoPath);
|
|
15748
|
-
if (note)
|
|
15749
|
-
d.log(`${ref(run)}: ${note}`);
|
|
15750
|
-
} else if (wt.startsWith(`${run.repoPath}/.worktrees/`)) {
|
|
15751
|
-
d.removeWorktree(d.exec, run.repoPath, wt);
|
|
15752
|
-
}
|
|
16336
|
+
d.removeWorktree(d.exec, repoPath, wt);
|
|
15753
16337
|
} catch (e) {
|
|
15754
|
-
d.log(`${
|
|
16338
|
+
d.log(`${at}: kept the worktree ${wt}: ${message(e)}`);
|
|
15755
16339
|
}
|
|
15756
16340
|
}
|
|
15757
16341
|
function ciNudge(url, failing) {
|
|
@@ -15842,6 +16426,11 @@ async function follow(d, state, run, claim, runner, finished, attention, changes
|
|
|
15842
16426
|
stopOpen(d, run, runner);
|
|
15843
16427
|
return false;
|
|
15844
16428
|
}
|
|
16429
|
+
try {
|
|
16430
|
+
pr.live = runner.status(run.handle) === "running" || undefined;
|
|
16431
|
+
} catch {
|
|
16432
|
+
pr.live = undefined;
|
|
16433
|
+
}
|
|
15845
16434
|
const at = { item: run.item, node: run.node, url: pr.url };
|
|
15846
16435
|
const ci = ciLine(view);
|
|
15847
16436
|
if (ci !== pr.ci)
|
|
@@ -16791,16 +17380,60 @@ init_state();
|
|
|
16791
17380
|
init_meter();
|
|
16792
17381
|
|
|
16793
17382
|
// src/runners/gitGuard.ts
|
|
16794
|
-
import {
|
|
17383
|
+
import { statSync as statSync2 } from "node:fs";
|
|
17384
|
+
import { basename as basename4, dirname as dirname12, join as join18, resolve as resolve8 } from "node:path";
|
|
16795
17385
|
var GIT_GUARD_ENV = {
|
|
16796
|
-
GIT_CONFIG_COUNT: "
|
|
17386
|
+
GIT_CONFIG_COUNT: "4",
|
|
16797
17387
|
GIT_CONFIG_KEY_0: "core.fsmonitor",
|
|
16798
17388
|
GIT_CONFIG_VALUE_0: "false",
|
|
16799
17389
|
GIT_CONFIG_KEY_1: "core.hooksPath",
|
|
16800
|
-
GIT_CONFIG_VALUE_1: "/dev/null"
|
|
17390
|
+
GIT_CONFIG_VALUE_1: "/dev/null",
|
|
17391
|
+
GIT_CONFIG_KEY_2: "remote.origin.uploadpack",
|
|
17392
|
+
GIT_CONFIG_VALUE_2: "git-upload-pack",
|
|
17393
|
+
GIT_CONFIG_KEY_3: "remote.origin.receivepack",
|
|
17394
|
+
GIT_CONFIG_VALUE_3: "git-receive-pack",
|
|
17395
|
+
GIT_ALLOW_PROTOCOL: "file:http:https:ssh",
|
|
17396
|
+
GIT_TERMINAL_PROMPT: "0"
|
|
17397
|
+
};
|
|
17398
|
+
function trustedSshCommand(env = process.env, exec = defaultExec) {
|
|
17399
|
+
if (env.GIT_SSH_COMMAND?.trim())
|
|
17400
|
+
return env.GIT_SSH_COMMAND;
|
|
17401
|
+
const r = exec("git", ["config", "--get", "core.sshCommand"], {
|
|
17402
|
+
cwd: "/",
|
|
17403
|
+
env: { GIT_CEILING_DIRECTORIES: "/" },
|
|
17404
|
+
timeoutMs: 5000
|
|
17405
|
+
});
|
|
17406
|
+
return r.status === 0 && r.stdout.trim() || "ssh";
|
|
17407
|
+
}
|
|
17408
|
+
var ssh;
|
|
17409
|
+
function gitGuardEnv() {
|
|
17410
|
+
ssh ??= trustedSshCommand();
|
|
17411
|
+
return { ...GIT_GUARD_ENV, GIT_SSH_COMMAND: ssh };
|
|
17412
|
+
}
|
|
17413
|
+
var isFile = (p) => statSync2(p, { throwIfNoEntry: false })?.isFile() ?? false;
|
|
17414
|
+
var isDir = (p) => statSync2(p, { throwIfNoEntry: false })?.isDirectory() ?? false;
|
|
17415
|
+
function ownGitDirs(dir, stat = { isFile, isDir }) {
|
|
17416
|
+
const wt = resolve8(dir);
|
|
17417
|
+
if (basename4(dirname12(wt)) !== ".worktrees")
|
|
17418
|
+
return null;
|
|
17419
|
+
const common = join18(dirname12(dirname12(wt)), ".git");
|
|
17420
|
+
if (!stat.isFile(join18(wt, ".git")) || !stat.isDir(common))
|
|
17421
|
+
return null;
|
|
17422
|
+
return {
|
|
17423
|
+
GIT_DIR: join18(common, "worktrees", basename4(wt)),
|
|
17424
|
+
GIT_COMMON_DIR: common,
|
|
17425
|
+
GIT_WORK_TREE: wt
|
|
17426
|
+
};
|
|
17427
|
+
}
|
|
17428
|
+
var callDir = (args, cwd) => {
|
|
17429
|
+
const base = cwd ?? process.cwd();
|
|
17430
|
+
return args[0] === "-C" && args[1] ? resolve8(base, args[1]) : base;
|
|
16801
17431
|
};
|
|
16802
17432
|
var GUARDED = new Set(["git", "gh"]);
|
|
16803
|
-
var guardGit = (exec) => (cmd, args, o) => GUARDED.has(basename4(cmd)) ? exec(cmd, args, {
|
|
17433
|
+
var guardGit = (exec, guard = gitGuardEnv) => (cmd, args, o) => GUARDED.has(basename4(cmd)) ? exec(cmd, args, {
|
|
17434
|
+
...o,
|
|
17435
|
+
env: { ...o?.env, ...guard(), ...ownGitDirs(callDir(args, o?.cwd)) }
|
|
17436
|
+
}) : exec(cmd, args, o);
|
|
16804
17437
|
|
|
16805
17438
|
// src/runners/command.ts
|
|
16806
17439
|
var expandCommandTemplate = (template, o) => {
|
|
@@ -17500,7 +18133,7 @@ function tmuxRunner(exec) {
|
|
|
17500
18133
|
return r.status === 0 ? r.stdout : "";
|
|
17501
18134
|
},
|
|
17502
18135
|
send(h, text) {
|
|
17503
|
-
const typed = exec("tmux", ["send-keys", "-t", tmuxPane(h.id), "-l", text]);
|
|
18136
|
+
const typed = exec("tmux", ["send-keys", "-t", tmuxPane(h.id), "-l", "--", text]);
|
|
17504
18137
|
if (typed.status !== 0) {
|
|
17505
18138
|
throw new Error(`tmux send-keys ${h.id} failed: ${typed.stderr.trim() || `exit ${typed.status}`}`);
|
|
17506
18139
|
}
|
|
@@ -17568,9 +18201,20 @@ function restoreRunner(name, exec = defaultExec) {
|
|
|
17568
18201
|
init_settings();
|
|
17569
18202
|
|
|
17570
18203
|
// src/update/drain.ts
|
|
17571
|
-
import {
|
|
18204
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
18205
|
+
import {
|
|
18206
|
+
closeSync as closeSync4,
|
|
18207
|
+
existsSync as existsSync18,
|
|
18208
|
+
mkdirSync as mkdirSync17,
|
|
18209
|
+
openSync as openSync4,
|
|
18210
|
+
readFileSync as readFileSync15,
|
|
18211
|
+
rmSync as rmSync9,
|
|
18212
|
+
statSync as statSync5,
|
|
18213
|
+
utimesSync,
|
|
18214
|
+
writeSync as writeSync2
|
|
18215
|
+
} from "node:fs";
|
|
17572
18216
|
import { homedir as homedir7 } from "node:os";
|
|
17573
|
-
import { join as
|
|
18217
|
+
import { join as join24 } from "node:path";
|
|
17574
18218
|
|
|
17575
18219
|
// ../../packages/shared/src/updates/manifest.ts
|
|
17576
18220
|
var CLI_PLATFORMS = [
|
|
@@ -17665,7 +18309,7 @@ function belowMinimum(version, minimum) {
|
|
|
17665
18309
|
init_state();
|
|
17666
18310
|
|
|
17667
18311
|
// src/update/fetch.ts
|
|
17668
|
-
import { createHash } from "node:crypto";
|
|
18312
|
+
import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
|
|
17669
18313
|
import {
|
|
17670
18314
|
chmodSync as chmodSync4,
|
|
17671
18315
|
closeSync as closeSync3,
|
|
@@ -17709,16 +18353,16 @@ import {
|
|
|
17709
18353
|
readlinkSync as readlinkSync2,
|
|
17710
18354
|
renameSync as renameSync7,
|
|
17711
18355
|
rmSync as rmSync4,
|
|
17712
|
-
statSync as
|
|
18356
|
+
statSync as statSync3,
|
|
17713
18357
|
writeFileSync as writeFileSync13
|
|
17714
18358
|
} from "node:fs";
|
|
17715
18359
|
import { homedir as homedir3 } from "node:os";
|
|
17716
|
-
import { dirname as
|
|
18360
|
+
import { dirname as dirname13, join as join19, win32 as win322 } from "node:path";
|
|
17717
18361
|
var UPDATE_LOCK_STALE_MS = 10 * 60000;
|
|
17718
18362
|
function sledsRoot(home = homedir3(), platform = process.platform) {
|
|
17719
|
-
return platform === "win32" ? win322.join(process.env.LOCALAPPDATA ?? win322.join(home, "AppData", "Local"), "sleds") :
|
|
18363
|
+
return platform === "win32" ? win322.join(process.env.LOCALAPPDATA ?? win322.join(home, "AppData", "Local"), "sleds") : join19(home, ".sleds");
|
|
17720
18364
|
}
|
|
17721
|
-
var pathFor = (platform) => platform === "win32" ? win322 : { join:
|
|
18365
|
+
var pathFor = (platform) => platform === "win32" ? win322 : { join: join19 };
|
|
17722
18366
|
function versionDir(home, v, platform = process.platform) {
|
|
17723
18367
|
return pathFor(platform).join(sledsRoot(home, platform), "versions", v);
|
|
17724
18368
|
}
|
|
@@ -17791,36 +18435,87 @@ function readUpdateState(home) {
|
|
|
17791
18435
|
}
|
|
17792
18436
|
function writeUpdateState(home, s) {
|
|
17793
18437
|
const path = updateStatePath(home);
|
|
17794
|
-
mkdirSync12(
|
|
18438
|
+
mkdirSync12(dirname13(path), { recursive: true, mode: 448 });
|
|
17795
18439
|
const tmp = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
17796
18440
|
writeFileSync13(tmp, `${JSON.stringify(s, null, 2)}
|
|
17797
18441
|
`, { mode: 384 });
|
|
17798
18442
|
renameSync7(tmp, path);
|
|
17799
18443
|
}
|
|
17800
|
-
|
|
18444
|
+
var BREAK_STALE_MS = 30000;
|
|
18445
|
+
var readText = (path) => {
|
|
18446
|
+
try {
|
|
18447
|
+
return readFileSync13(path, "utf8");
|
|
18448
|
+
} catch {
|
|
18449
|
+
return null;
|
|
18450
|
+
}
|
|
18451
|
+
};
|
|
18452
|
+
function parseLockBody(text) {
|
|
18453
|
+
if (text === null)
|
|
18454
|
+
return null;
|
|
17801
18455
|
try {
|
|
17802
|
-
const v = JSON.parse(
|
|
18456
|
+
const v = JSON.parse(text);
|
|
17803
18457
|
if (isObj3(v) && num7(v.pid) && num7(v.at))
|
|
17804
18458
|
return { pid: v.pid, at: v.at, ...str11(v.token) ? { token: v.token } : {} };
|
|
17805
18459
|
} catch {}
|
|
17806
18460
|
return null;
|
|
17807
18461
|
}
|
|
17808
|
-
|
|
17809
|
-
|
|
18462
|
+
var readLockBody = (path) => parseLockBody(readText(path));
|
|
18463
|
+
function lockStale(path, text, now, maxMs) {
|
|
17810
18464
|
try {
|
|
17811
|
-
const at =
|
|
17812
|
-
return now - at >
|
|
18465
|
+
const at = parseLockBody(text)?.at ?? statSync3(path).mtimeMs;
|
|
18466
|
+
return now - at > maxMs;
|
|
17813
18467
|
} catch {
|
|
17814
18468
|
return false;
|
|
17815
18469
|
}
|
|
17816
18470
|
}
|
|
18471
|
+
function removeIfSame(path, text, aside) {
|
|
18472
|
+
try {
|
|
18473
|
+
renameSync7(path, aside);
|
|
18474
|
+
} catch {
|
|
18475
|
+
return;
|
|
18476
|
+
}
|
|
18477
|
+
if (readText(aside) !== text) {
|
|
18478
|
+
try {
|
|
18479
|
+
linkSync2(aside, path);
|
|
18480
|
+
} catch {}
|
|
18481
|
+
}
|
|
18482
|
+
rmSync4(aside, { force: true });
|
|
18483
|
+
}
|
|
18484
|
+
function breakStale(path, seen, token) {
|
|
18485
|
+
const brk = `${path}.break`;
|
|
18486
|
+
const tmp = `${brk}.${token}.tmp`;
|
|
18487
|
+
const aside = `${path}.${token}.stale`;
|
|
18488
|
+
const body = `${JSON.stringify({ pid: process.pid, at: Date.now(), token })}
|
|
18489
|
+
`;
|
|
18490
|
+
writeFileSync13(tmp, body, { mode: 384 });
|
|
18491
|
+
try {
|
|
18492
|
+
try {
|
|
18493
|
+
linkSync2(tmp, brk);
|
|
18494
|
+
} catch (e) {
|
|
18495
|
+
if (e.code !== "EEXIST")
|
|
18496
|
+
throw e;
|
|
18497
|
+
const held = readText(brk);
|
|
18498
|
+
if (held !== null && lockStale(brk, held, Date.now(), BREAK_STALE_MS))
|
|
18499
|
+
removeIfSame(brk, held, aside);
|
|
18500
|
+
return false;
|
|
18501
|
+
}
|
|
18502
|
+
try {
|
|
18503
|
+
if (readText(path) === seen && lockStale(path, seen, Date.now(), UPDATE_LOCK_STALE_MS))
|
|
18504
|
+
removeIfSame(path, seen, aside);
|
|
18505
|
+
return true;
|
|
18506
|
+
} finally {
|
|
18507
|
+
removeIfSame(brk, body, aside);
|
|
18508
|
+
}
|
|
18509
|
+
} finally {
|
|
18510
|
+
rmSync4(tmp, { force: true });
|
|
18511
|
+
}
|
|
18512
|
+
}
|
|
17817
18513
|
async function withUpdateLock(home, fn, o = {}) {
|
|
17818
18514
|
const waitMs = o.waitMs ?? 30000;
|
|
17819
18515
|
const path = updateLockPath(home);
|
|
17820
|
-
mkdirSync12(
|
|
18516
|
+
mkdirSync12(dirname13(path), { recursive: true, mode: 448 });
|
|
17821
18517
|
const token = randomUUID();
|
|
17822
18518
|
const tmp = `${path}.${token}.tmp`;
|
|
17823
|
-
const aside = `${path}.${token}.stale`;
|
|
17824
18519
|
writeFileSync13(tmp, `${JSON.stringify({ pid: process.pid, at: Date.now(), token })}
|
|
17825
18520
|
`, {
|
|
17826
18521
|
mode: 384
|
|
@@ -17835,22 +18530,9 @@ async function withUpdateLock(home, fn, o = {}) {
|
|
|
17835
18530
|
if (e.code !== "EEXIST")
|
|
17836
18531
|
throw e;
|
|
17837
18532
|
}
|
|
17838
|
-
|
|
17839
|
-
|
|
17840
|
-
renameSync7(path, aside);
|
|
17841
|
-
} catch (e) {
|
|
17842
|
-
if (e.code === "ENOENT")
|
|
17843
|
-
continue;
|
|
17844
|
-
throw e;
|
|
17845
|
-
}
|
|
17846
|
-
if (!lockStale(aside, Date.now())) {
|
|
17847
|
-
try {
|
|
17848
|
-
linkSync2(aside, path);
|
|
17849
|
-
} catch {}
|
|
17850
|
-
}
|
|
17851
|
-
rmSync4(aside, { force: true });
|
|
18533
|
+
const seen = readText(path);
|
|
18534
|
+
if (seen !== null && lockStale(path, seen, Date.now(), UPDATE_LOCK_STALE_MS) && breakStale(path, seen, token))
|
|
17852
18535
|
continue;
|
|
17853
|
-
}
|
|
17854
18536
|
if (Date.now() - start >= waitMs) {
|
|
17855
18537
|
const held = readLockBody(path);
|
|
17856
18538
|
throw new Error(`update.json is locked${held ? ` by pid ${held.pid}` : ""} (${path})`);
|
|
@@ -17897,7 +18579,7 @@ async function getText(fetchFn, url) {
|
|
|
17897
18579
|
return res.text();
|
|
17898
18580
|
}
|
|
17899
18581
|
async function sha256File(path) {
|
|
17900
|
-
const hash =
|
|
18582
|
+
const hash = createHash2("sha256");
|
|
17901
18583
|
let size = 0;
|
|
17902
18584
|
for await (const chunk of createReadStream(path)) {
|
|
17903
18585
|
hash.update(chunk);
|
|
@@ -17910,7 +18592,7 @@ async function fetchVersion(o) {
|
|
|
17910
18592
|
const platform = o.platform ?? process.platform;
|
|
17911
18593
|
const arch = o.arch ?? process.arch;
|
|
17912
18594
|
const publicKey = o.publicKey ?? RELEASE_PUBLIC_KEY;
|
|
17913
|
-
const running = o.running ?? "0.1.
|
|
18595
|
+
const running = o.running ?? "0.1.62";
|
|
17914
18596
|
if (!publicKey)
|
|
17915
18597
|
return { ok: false, why: "no release key yet" };
|
|
17916
18598
|
if (!VERSION_RE2.test(o.version))
|
|
@@ -17949,12 +18631,12 @@ async function fetchVersion(o) {
|
|
|
17949
18631
|
} catch {}
|
|
17950
18632
|
}
|
|
17951
18633
|
mkdirSync13(versionDir(o.home, o.version, platform), { recursive: true, mode: 493 });
|
|
17952
|
-
const part = `${bin}.part`;
|
|
18634
|
+
const part = `${bin}.${process.pid}.${randomUUID2()}.part`;
|
|
17953
18635
|
try {
|
|
17954
18636
|
const res = await fetchFn(asset.url);
|
|
17955
18637
|
if (!res.ok || !res.body)
|
|
17956
18638
|
return { ok: false, why: `${asset.url}: HTTP ${res.status}` };
|
|
17957
|
-
const hash =
|
|
18639
|
+
const hash = createHash2("sha256");
|
|
17958
18640
|
let size = 0;
|
|
17959
18641
|
const fd = openSync3(part, "w", 384);
|
|
17960
18642
|
try {
|
|
@@ -17964,6 +18646,7 @@ async function fetchVersion(o) {
|
|
|
17964
18646
|
break;
|
|
17965
18647
|
hash.update(chunk);
|
|
17966
18648
|
writeSync(fd, chunk);
|
|
18649
|
+
o.progress?.();
|
|
17967
18650
|
}
|
|
17968
18651
|
} finally {
|
|
17969
18652
|
closeSync3(fd);
|
|
@@ -17999,24 +18682,24 @@ import {
|
|
|
17999
18682
|
readlinkSync as readlinkSync3,
|
|
18000
18683
|
renameSync as renameSync9,
|
|
18001
18684
|
rmSync as rmSync7,
|
|
18002
|
-
statSync as
|
|
18685
|
+
statSync as statSync4,
|
|
18003
18686
|
symlinkSync,
|
|
18004
18687
|
writeFileSync as writeFileSync15
|
|
18005
18688
|
} from "node:fs";
|
|
18006
18689
|
import { homedir as homedir4 } from "node:os";
|
|
18007
|
-
import { basename as basename5, delimiter as delimiter2, dirname as
|
|
18690
|
+
import { basename as basename5, delimiter as delimiter2, dirname as dirname14, isAbsolute as isAbsolute2, join as join22, relative } from "node:path";
|
|
18008
18691
|
|
|
18009
18692
|
// src/commands/engineSystemd.ts
|
|
18010
|
-
import { join as
|
|
18693
|
+
import { join as join20 } from "node:path";
|
|
18011
18694
|
var BOX_ENV_UNIT_PATH = "%h/.config/sleds/box.env";
|
|
18012
18695
|
function boxEnvPath(home) {
|
|
18013
|
-
return
|
|
18696
|
+
return join20(home, ".config", "sleds", "box.env");
|
|
18014
18697
|
}
|
|
18015
18698
|
function engineUnitDir(home) {
|
|
18016
|
-
return
|
|
18699
|
+
return join20(home, ".config", "systemd", "user");
|
|
18017
18700
|
}
|
|
18018
18701
|
function engineUnitPath(home, label) {
|
|
18019
|
-
return
|
|
18702
|
+
return join20(engineUnitDir(home), `${label}.service`);
|
|
18020
18703
|
}
|
|
18021
18704
|
function systemdQuote(s) {
|
|
18022
18705
|
const body = s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/%/g, "%%").replace(/\$/g, "$$$$");
|
|
@@ -18058,7 +18741,7 @@ function parseEngineUnit(text) {
|
|
|
18058
18741
|
// src/schedule.ts
|
|
18059
18742
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
18060
18743
|
import { existsSync as existsSync15, mkdirSync as mkdirSync14, rmSync as rmSync6, writeFileSync as writeFileSync14 } from "node:fs";
|
|
18061
|
-
import { join as
|
|
18744
|
+
import { join as join21 } from "node:path";
|
|
18062
18745
|
var REVERT_LABEL = "ai.sleds.revert";
|
|
18063
18746
|
var defaultExec2 = (cmd, args) => {
|
|
18064
18747
|
const r = spawnSync4(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
|
|
@@ -18066,7 +18749,7 @@ var defaultExec2 = (cmd, args) => {
|
|
|
18066
18749
|
return { ok: false, stderr: r.error.message };
|
|
18067
18750
|
return { ok: r.status === 0, stderr: r.stderr ?? "" };
|
|
18068
18751
|
};
|
|
18069
|
-
var plistPath = (home) =>
|
|
18752
|
+
var plistPath = (home) => join21(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
|
|
18070
18753
|
var xmlEscape2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
18071
18754
|
var buildLaunchdPlist = (sledsArgv, deadline) => {
|
|
18072
18755
|
const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape2(a)}</string>`).join(`
|
|
@@ -18105,7 +18788,7 @@ var scheduleRevert = (d, deadlineMs) => {
|
|
|
18105
18788
|
if (d.platform === "darwin") {
|
|
18106
18789
|
const p = plistPath(d.home);
|
|
18107
18790
|
try {
|
|
18108
|
-
mkdirSync14(
|
|
18791
|
+
mkdirSync14(join21(d.home, "Library", "LaunchAgents"), { recursive: true });
|
|
18109
18792
|
d.exec("launchctl", ["unload", p]);
|
|
18110
18793
|
writeFileSync14(p, buildLaunchdPlist(d.sledsArgv, deadline));
|
|
18111
18794
|
const r = d.exec("launchctl", ["load", p]);
|
|
@@ -18157,8 +18840,8 @@ var HOOK_SUBS = [
|
|
|
18157
18840
|
"stop-event",
|
|
18158
18841
|
"permission-event"
|
|
18159
18842
|
];
|
|
18160
|
-
var migrateBakDir = (home) =>
|
|
18161
|
-
var manifestPath = (home) =>
|
|
18843
|
+
var migrateBakDir = (home) => join22(sledsRoot(home), "migrate.bak");
|
|
18844
|
+
var manifestPath = (home) => join22(migrateBakDir(home), "manifest.json");
|
|
18162
18845
|
var xmlEscape3 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
18163
18846
|
var xmlUnescape = (s) => s.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
18164
18847
|
var shQuote = (s) => /^[\w./~-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
|
|
@@ -18258,13 +18941,13 @@ function rewriteSettings(text, link) {
|
|
|
18258
18941
|
}
|
|
18259
18942
|
var listDir = (dir, keep) => {
|
|
18260
18943
|
try {
|
|
18261
|
-
return readdirSync2(dir).filter(keep).sort().map((n) =>
|
|
18944
|
+
return readdirSync2(dir).filter(keep).sort().map((n) => join22(dir, n));
|
|
18262
18945
|
} catch {
|
|
18263
18946
|
return [];
|
|
18264
18947
|
}
|
|
18265
18948
|
};
|
|
18266
18949
|
function unitFiles(home) {
|
|
18267
|
-
const agents = listDir(
|
|
18950
|
+
const agents = listDir(join22(home, "Library", "LaunchAgents"), (n) => n.startsWith("ai.sleds.") && n.endsWith(".plist")).map((path) => ({
|
|
18268
18951
|
path,
|
|
18269
18952
|
...basename5(path).startsWith("ai.sleds.revert") ? {} : { reload: "launchd" }
|
|
18270
18953
|
}));
|
|
@@ -18276,7 +18959,7 @@ function unitClaudeDir(text) {
|
|
|
18276
18959
|
return plist ? xmlUnescape(plist) : undefined;
|
|
18277
18960
|
}
|
|
18278
18961
|
function claudeDirs(home, env) {
|
|
18279
|
-
const dirs = [
|
|
18962
|
+
const dirs = [join22(home, ".claude"), claudeDir(home, env)];
|
|
18280
18963
|
for (const u of unitFiles(home)) {
|
|
18281
18964
|
try {
|
|
18282
18965
|
const d = unitClaudeDir(readFileSync14(u.path, "utf8"));
|
|
@@ -18300,7 +18983,7 @@ function migrationPlan(home, link, env = process.env) {
|
|
|
18300
18983
|
out.push({ ...u, text: next });
|
|
18301
18984
|
}
|
|
18302
18985
|
for (const dir of claudeDirs(home, env)) {
|
|
18303
|
-
const path =
|
|
18986
|
+
const path = join22(dir, "settings.json");
|
|
18304
18987
|
let text;
|
|
18305
18988
|
try {
|
|
18306
18989
|
text = readFileSync14(path, "utf8");
|
|
@@ -18315,12 +18998,12 @@ function migrationPlan(home, link, env = process.env) {
|
|
|
18315
18998
|
}
|
|
18316
18999
|
var backupFor = (home, path) => {
|
|
18317
19000
|
const rel = relative(home, path);
|
|
18318
|
-
return rel.startsWith("..") || isAbsolute2(rel) ?
|
|
19001
|
+
return rel.startsWith("..") || isAbsolute2(rel) ? join22(migrateBakDir(home), "abs", path) : join22(migrateBakDir(home), rel);
|
|
18319
19002
|
};
|
|
18320
19003
|
function writeKeepingMode(path, text) {
|
|
18321
19004
|
let mode = 420;
|
|
18322
19005
|
try {
|
|
18323
|
-
mode =
|
|
19006
|
+
mode = statSync4(path).mode & 511;
|
|
18324
19007
|
} catch {}
|
|
18325
19008
|
const tmp = `${path}.${process.pid}.migrate.tmp`;
|
|
18326
19009
|
writeFileSync15(tmp, text, { mode });
|
|
@@ -18332,7 +19015,7 @@ function copyInto(from, to) {
|
|
|
18332
19015
|
renameSync9(tmp, to);
|
|
18333
19016
|
}
|
|
18334
19017
|
function pointLink(link, bin) {
|
|
18335
|
-
mkdirSync15(
|
|
19018
|
+
mkdirSync15(dirname14(link), { recursive: true, mode: 448 });
|
|
18336
19019
|
const tmp = `${link}.tmp`;
|
|
18337
19020
|
rmSync7(tmp, { force: true });
|
|
18338
19021
|
symlinkSync(bin, tmp);
|
|
@@ -18357,9 +19040,7 @@ function reloadScript(lock, files) {
|
|
|
18357
19040
|
for (const a of agents)
|
|
18358
19041
|
lines.push(`launchctl unload ${shQuote(a.path)} 2>/dev/null; launchctl load ${shQuote(a.path)}`);
|
|
18359
19042
|
if (units.length)
|
|
18360
|
-
lines.push("systemctl --user daemon-reload");
|
|
18361
|
-
for (const u of units)
|
|
18362
|
-
lines.push(`systemctl --user restart ${shQuote(basename5(u.path))}`);
|
|
19043
|
+
lines.push("systemctl --user daemon-reload", `systemctl --user --no-block restart ${units.map((u) => shQuote(basename5(u.path))).join(" ")}`);
|
|
18363
19044
|
if (!lines.length)
|
|
18364
19045
|
return null;
|
|
18365
19046
|
return [
|
|
@@ -18453,7 +19134,7 @@ async function migrateToBinary(o) {
|
|
|
18453
19134
|
rmSync7(migrateBakDir(home), { recursive: true, force: true });
|
|
18454
19135
|
for (const p of plan) {
|
|
18455
19136
|
const backup = backupFor(home, p.path);
|
|
18456
|
-
mkdirSync15(
|
|
19137
|
+
mkdirSync15(dirname14(backup), { recursive: true, mode: 448 });
|
|
18457
19138
|
copyFileSync(p.path, backup);
|
|
18458
19139
|
manifest.files.push({ path: p.path, backup, ...p.reload ? { reload: p.reload } : {} });
|
|
18459
19140
|
}
|
|
@@ -18487,7 +19168,7 @@ async function migrateToBinary(o) {
|
|
|
18487
19168
|
log(`sleds stays on the npm install: ${result.why}`);
|
|
18488
19169
|
return { ok: false, why: result.why };
|
|
18489
19170
|
}
|
|
18490
|
-
const binDir =
|
|
19171
|
+
const binDir = dirname14(link);
|
|
18491
19172
|
if (!(env.PATH ?? "").split(delimiter2).includes(binDir))
|
|
18492
19173
|
log(`${binDir} is not on your PATH — add it in your shell profile to run this sleds from a terminal (sleds never edits it)`);
|
|
18493
19174
|
reload(home, result.files, detach);
|
|
@@ -18507,10 +19188,10 @@ import {
|
|
|
18507
19188
|
symlinkSync as symlinkSync2
|
|
18508
19189
|
} from "node:fs";
|
|
18509
19190
|
import { homedir as homedir5 } from "node:os";
|
|
18510
|
-
import { dirname as
|
|
19191
|
+
import { dirname as dirname15, join as join23 } from "node:path";
|
|
18511
19192
|
var NO_PREVIOUS = "no previous version on this machine";
|
|
18512
19193
|
function allStateFiles(home = homedir5(), env = process.env) {
|
|
18513
|
-
const roots = [...new Set([configDir(home, env),
|
|
19194
|
+
const roots = [...new Set([configDir(home, env), join23(home, ".config", "sleds")])];
|
|
18514
19195
|
const out = [];
|
|
18515
19196
|
const walk = (dir) => {
|
|
18516
19197
|
let names;
|
|
@@ -18521,20 +19202,20 @@ function allStateFiles(home = homedir5(), env = process.env) {
|
|
|
18521
19202
|
}
|
|
18522
19203
|
for (const n of names.sort())
|
|
18523
19204
|
if (n.endsWith(".json") && n !== "removed-engines.json")
|
|
18524
|
-
out.push(
|
|
19205
|
+
out.push(join23(dir, n));
|
|
18525
19206
|
for (const sub of ["orgs", "seats"]) {
|
|
18526
19207
|
let kids;
|
|
18527
19208
|
try {
|
|
18528
|
-
kids = readdirSync3(
|
|
19209
|
+
kids = readdirSync3(join23(dir, sub));
|
|
18529
19210
|
} catch {
|
|
18530
19211
|
continue;
|
|
18531
19212
|
}
|
|
18532
19213
|
for (const k of kids.sort())
|
|
18533
|
-
walk(
|
|
19214
|
+
walk(join23(dir, sub, k));
|
|
18534
19215
|
}
|
|
18535
19216
|
};
|
|
18536
19217
|
for (const r of roots)
|
|
18537
|
-
walk(
|
|
19218
|
+
walk(join23(r, "engine"));
|
|
18538
19219
|
return out;
|
|
18539
19220
|
}
|
|
18540
19221
|
var backupPath2 = (file, v) => `${file}.${v}.bak`;
|
|
@@ -18548,7 +19229,7 @@ function pointBinAt(home, v, platform) {
|
|
|
18548
19229
|
const target = versionBin(home, v, platform);
|
|
18549
19230
|
if (!existsSync16(target))
|
|
18550
19231
|
throw new Error(`${target} is missing — sleds ${v} is not downloaded`);
|
|
18551
|
-
mkdirSync16(
|
|
19232
|
+
mkdirSync16(dirname15(bin), { recursive: true, mode: 448 });
|
|
18552
19233
|
if (platform === "win32") {
|
|
18553
19234
|
replaceAside(bin, target);
|
|
18554
19235
|
return;
|
|
@@ -18620,7 +19301,7 @@ function applyConfirm(s, home, o = {}) {
|
|
|
18620
19301
|
if (!s.current)
|
|
18621
19302
|
return;
|
|
18622
19303
|
for (const f of o.stateFiles ?? allStateFiles(home)) {
|
|
18623
|
-
const dir =
|
|
19304
|
+
const dir = dirname15(f);
|
|
18624
19305
|
const prefix = `${f.slice(dir.length + 1)}.`;
|
|
18625
19306
|
let names;
|
|
18626
19307
|
try {
|
|
@@ -18630,10 +19311,10 @@ function applyConfirm(s, home, o = {}) {
|
|
|
18630
19311
|
}
|
|
18631
19312
|
for (const n of names)
|
|
18632
19313
|
if (n.startsWith(prefix) && n.endsWith(".bak"))
|
|
18633
|
-
rmSync8(
|
|
19314
|
+
rmSync8(join23(dir, n), { force: true });
|
|
18634
19315
|
}
|
|
18635
19316
|
const keep = new Set([s.current, s.previous, s.drain?.to].filter(Boolean));
|
|
18636
|
-
const versions =
|
|
19317
|
+
const versions = dirname15(versionDir(home, s.current, platform));
|
|
18637
19318
|
let names = [];
|
|
18638
19319
|
try {
|
|
18639
19320
|
names = readdirSync3(versions);
|
|
@@ -18684,6 +19365,7 @@ function reconcile(s, home, o) {
|
|
|
18684
19365
|
// src/update/guard.ts
|
|
18685
19366
|
var UPDATE_EXIT = 4;
|
|
18686
19367
|
var FIRST_BEAT_MS = 180000;
|
|
19368
|
+
var FIRE_RETRY_MS = 15000;
|
|
18687
19369
|
var STARTS_PER_ENGINE = 3;
|
|
18688
19370
|
function guarded(home, version, platform) {
|
|
18689
19371
|
return !!version && version !== "dev" && existsSync17(sledsRoot(home, platform));
|
|
@@ -18767,9 +19449,16 @@ function firstBeatWatchdog(o) {
|
|
|
18767
19449
|
const clearTimer = o.clearTimer ?? ((t) => clearTimeout(t));
|
|
18768
19450
|
let done = false;
|
|
18769
19451
|
let confirming = false;
|
|
19452
|
+
const setTimer = o.setTimer ?? ((fn, ms) => {
|
|
19453
|
+
const t = setTimeout(fn, ms);
|
|
19454
|
+
t.unref?.();
|
|
19455
|
+
return t;
|
|
19456
|
+
});
|
|
19457
|
+
let timer;
|
|
18770
19458
|
const fire = () => {
|
|
18771
19459
|
if (done)
|
|
18772
19460
|
return;
|
|
19461
|
+
const lock = o.lockWaitMs !== undefined ? { waitMs: o.lockWaitMs } : {};
|
|
18773
19462
|
withUpdateLock(home, (s) => {
|
|
18774
19463
|
if (s.pending?.to === version)
|
|
18775
19464
|
return rollBackHere(s, home, version, `sleds ${version} did not check in within 3 minutes`, now(), o);
|
|
@@ -18781,20 +19470,20 @@ function firstBeatWatchdog(o) {
|
|
|
18781
19470
|
why: `sleds ${version} was rolled back on this machine — restarting onto ${at}`
|
|
18782
19471
|
};
|
|
18783
19472
|
return null;
|
|
18784
|
-
}).then((g) => {
|
|
19473
|
+
}, lock).then((g) => {
|
|
18785
19474
|
done = true;
|
|
18786
19475
|
if (g && !g.go) {
|
|
18787
19476
|
say(g.why);
|
|
18788
19477
|
exit(g.exit);
|
|
18789
19478
|
}
|
|
18790
|
-
}, (e) =>
|
|
19479
|
+
}, (e) => {
|
|
19480
|
+
if (done)
|
|
19481
|
+
return;
|
|
19482
|
+
say(`the first-beat check could not run: ${e instanceof Error ? e.message : String(e)} — trying again in ${FIRE_RETRY_MS / 1000} s`);
|
|
19483
|
+
timer = setTimer(fire, FIRE_RETRY_MS);
|
|
19484
|
+
});
|
|
18791
19485
|
};
|
|
18792
|
-
|
|
18793
|
-
const t = setTimeout(fn, ms);
|
|
18794
|
-
t.unref?.();
|
|
18795
|
-
return t;
|
|
18796
|
-
});
|
|
18797
|
-
const timer = setTimer(fire, Math.max(0, pending.at + FIRST_BEAT_MS - now()));
|
|
19486
|
+
timer = setTimer(fire, Math.max(0, pending.at + FIRST_BEAT_MS - now()));
|
|
18798
19487
|
return {
|
|
18799
19488
|
beat: async () => {
|
|
18800
19489
|
if (done || confirming)
|
|
@@ -18891,9 +19580,10 @@ async function machineAnswer(client, tokens) {
|
|
|
18891
19580
|
return null;
|
|
18892
19581
|
}
|
|
18893
19582
|
}
|
|
19583
|
+
var FETCH_LOCK_TOUCH_MS = 30000;
|
|
18894
19584
|
async function fetchOnce(o) {
|
|
18895
19585
|
const dir = versionDir(o.home, o.version, o.platform);
|
|
18896
|
-
const lock =
|
|
19586
|
+
const lock = join24(dir, "fetch.lock");
|
|
18897
19587
|
mkdirSync17(dir, { recursive: true, mode: 493 });
|
|
18898
19588
|
let fd;
|
|
18899
19589
|
try {
|
|
@@ -18902,7 +19592,7 @@ async function fetchOnce(o) {
|
|
|
18902
19592
|
if (e.code !== "EEXIST")
|
|
18903
19593
|
throw e;
|
|
18904
19594
|
try {
|
|
18905
|
-
if ((o.now ?? Date.now()) -
|
|
19595
|
+
if ((o.now ?? Date.now()) - statSync5(lock).mtimeMs <= FETCH_LOCK_STALE_MS)
|
|
18906
19596
|
return null;
|
|
18907
19597
|
} catch {
|
|
18908
19598
|
return null;
|
|
@@ -18910,14 +19600,28 @@ async function fetchOnce(o) {
|
|
|
18910
19600
|
rmSync9(lock, { force: true });
|
|
18911
19601
|
return fetchOnce(o);
|
|
18912
19602
|
}
|
|
19603
|
+
const mine = `${process.pid} ${randomUUID3()}
|
|
19604
|
+
`;
|
|
18913
19605
|
try {
|
|
18914
|
-
writeSync2(fd,
|
|
18915
|
-
`);
|
|
19606
|
+
writeSync2(fd, mine);
|
|
18916
19607
|
closeSync4(fd);
|
|
18917
19608
|
const { fetch: f = fetchVersion, now: _n, ...rest } = o;
|
|
18918
|
-
|
|
19609
|
+
let touchedAt = 0;
|
|
19610
|
+
const progress = () => {
|
|
19611
|
+
const t = Date.now();
|
|
19612
|
+
if (t - touchedAt < FETCH_LOCK_TOUCH_MS)
|
|
19613
|
+
return;
|
|
19614
|
+
touchedAt = t;
|
|
19615
|
+
try {
|
|
19616
|
+
utimesSync(lock, t / 1000, t / 1000);
|
|
19617
|
+
} catch {}
|
|
19618
|
+
};
|
|
19619
|
+
return await f({ ...rest, progress });
|
|
18919
19620
|
} finally {
|
|
18920
|
-
|
|
19621
|
+
try {
|
|
19622
|
+
if (readFileSync15(lock, "utf8") === mine)
|
|
19623
|
+
rmSync9(lock, { force: true });
|
|
19624
|
+
} catch {}
|
|
18921
19625
|
}
|
|
18922
19626
|
}
|
|
18923
19627
|
function machineVersion(home, platform) {
|
|
@@ -19112,6 +19816,11 @@ function engineUpdater(o) {
|
|
|
19112
19816
|
};
|
|
19113
19817
|
}
|
|
19114
19818
|
|
|
19819
|
+
// src/version.ts
|
|
19820
|
+
function cliVersion(env) {
|
|
19821
|
+
return "0.1.62";
|
|
19822
|
+
}
|
|
19823
|
+
|
|
19115
19824
|
// src/commands/update.ts
|
|
19116
19825
|
init_server();
|
|
19117
19826
|
init_config();
|
|
@@ -19400,7 +20109,7 @@ function flagsFromProfile(flags, given, profile, home) {
|
|
|
19400
20109
|
}
|
|
19401
20110
|
}
|
|
19402
20111
|
if (profile.reposDir && !has("repos-dir") && !has("repo")) {
|
|
19403
|
-
out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ?
|
|
20112
|
+
out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join25(home, d.slice(1)) : d).join(":");
|
|
19404
20113
|
used.push(`repos ${profile.reposDir}`);
|
|
19405
20114
|
}
|
|
19406
20115
|
if (profile.mcpStrict !== undefined && !has("strict-mcp") && !has("no-strict-mcp")) {
|
|
@@ -19495,7 +20204,7 @@ function engineClient(o, org, breaker) {
|
|
|
19495
20204
|
...src,
|
|
19496
20205
|
...breaker ? { fetchFn: breaker.fetch } : {},
|
|
19497
20206
|
timeoutMs: ENGINE_TIMEOUT_MS,
|
|
19498
|
-
version: "0.1.
|
|
20207
|
+
version: "0.1.62"
|
|
19499
20208
|
});
|
|
19500
20209
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
19501
20210
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -19528,19 +20237,19 @@ function realPidAlive2(pid) {
|
|
|
19528
20237
|
function memberMcpConfigs(o, cwd) {
|
|
19529
20238
|
const read = o.readJson ?? ((p) => {
|
|
19530
20239
|
try {
|
|
19531
|
-
return JSON.parse(
|
|
20240
|
+
return JSON.parse(readFileSync16(p, "utf8"));
|
|
19532
20241
|
} catch {
|
|
19533
20242
|
return null;
|
|
19534
20243
|
}
|
|
19535
20244
|
});
|
|
19536
20245
|
const claudeDir = (o.env ?? process.env).CLAUDE_CONFIG_DIR;
|
|
19537
20246
|
return [
|
|
19538
|
-
read(claudeDir ?
|
|
19539
|
-
...cwd ? [read(
|
|
20247
|
+
read(claudeDir ? join25(claudeDir, ".claude.json") : join25(o.home, ".claude.json")),
|
|
20248
|
+
...cwd ? [read(join25(cwd, ".mcp.json"))] : []
|
|
19540
20249
|
];
|
|
19541
20250
|
}
|
|
19542
20251
|
function engineStateDir(o, org, seat) {
|
|
19543
|
-
return seatStateDir(orgStateDir(o.stateDir ??
|
|
20252
|
+
return seatStateDir(orgStateDir(o.stateDir ?? join25(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
|
|
19544
20253
|
}
|
|
19545
20254
|
function engineSeat(o, org) {
|
|
19546
20255
|
try {
|
|
@@ -19567,11 +20276,11 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
19567
20276
|
const stateDir = engineStateDir(o, flags.org, flags.seat);
|
|
19568
20277
|
const file = statePath(stateDir, stateName);
|
|
19569
20278
|
const mcpOrg = flags.org && engineOrg(o, flags.org).seated ? flags.org : undefined;
|
|
19570
|
-
const repo = flags.repo ?
|
|
19571
|
-
const reposDirs = splitReposDirs(flags.reposDir).map((d) =>
|
|
20279
|
+
const repo = flags.repo ? resolve9(cwd, flags.repo) : undefined;
|
|
20280
|
+
const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve9(cwd, d));
|
|
19572
20281
|
const { branch, prTitle } = flags;
|
|
19573
|
-
const hooksDir =
|
|
19574
|
-
const permissionMark = (name) =>
|
|
20282
|
+
const hooksDir = join25(stateDir, "hooks");
|
|
20283
|
+
const permissionMark = (name) => join25(hooksDir, `${name}.permission.json`);
|
|
19575
20284
|
const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
|
|
19576
20285
|
return {
|
|
19577
20286
|
source,
|
|
@@ -19596,9 +20305,9 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
19596
20305
|
sandbox: true,
|
|
19597
20306
|
writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow) => {
|
|
19598
20307
|
const gitCommonDir = gitCommonDirOf(exec, cwd);
|
|
19599
|
-
const dir =
|
|
20308
|
+
const dir = join25(stateDir, "sandbox");
|
|
19600
20309
|
mkdirSync18(dir, { recursive: true, mode: 448 });
|
|
19601
|
-
const p =
|
|
20310
|
+
const p = join25(dir, `${name}.json`);
|
|
19602
20311
|
const walls = engineSandboxSettings(o.home, o.env ?? process.env, gitCommonDir, [
|
|
19603
20312
|
...SANDBOX_DEFAULT_ALLOW,
|
|
19604
20313
|
...flags.sandboxAllow ?? []
|
|
@@ -19615,7 +20324,7 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
19615
20324
|
} : {},
|
|
19616
20325
|
writeHookSettings: (name, allow) => {
|
|
19617
20326
|
mkdirSync18(hooksDir, { recursive: true, mode: 448 });
|
|
19618
|
-
const p =
|
|
20327
|
+
const p = join25(hooksDir, `${name}.json`);
|
|
19619
20328
|
const base = allow?.length ? { permissions: { allow: [...allow] } } : {};
|
|
19620
20329
|
writeFileSync16(p, `${JSON.stringify(withHook(name, base), null, 2)}
|
|
19621
20330
|
`, { mode: 384 });
|
|
@@ -19643,9 +20352,9 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
19643
20352
|
exists
|
|
19644
20353
|
}),
|
|
19645
20354
|
writeMcpConfig: o.writeMcpConfig ?? ((name, runToken, worktree) => {
|
|
19646
|
-
const dir =
|
|
20355
|
+
const dir = join25(stateDir, "mcp");
|
|
19647
20356
|
mkdirSync18(dir, { recursive: true, mode: 448 });
|
|
19648
|
-
const p =
|
|
20357
|
+
const p = join25(dir, `${name}.json`);
|
|
19649
20358
|
let others = {};
|
|
19650
20359
|
if (flags.strictMcp && flags.mcpAllow?.length) {
|
|
19651
20360
|
const r = mcpPassThrough(flags.mcpAllow, memberMcpConfigs(o, worktree));
|
|
@@ -19661,12 +20370,26 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
19661
20370
|
}),
|
|
19662
20371
|
removeMcpConfig: o.removeMcpConfig ?? ((p) => rmSync10(p, { force: true })),
|
|
19663
20372
|
writePrompt: o.writePrompt ?? ((name, text) => {
|
|
19664
|
-
const dir =
|
|
20373
|
+
const dir = join25(stateDir, "prompts");
|
|
19665
20374
|
mkdirSync18(dir, { recursive: true, mode: 448 });
|
|
19666
|
-
const p =
|
|
20375
|
+
const p = join25(dir, `${name}.md`);
|
|
19667
20376
|
writeFileSync16(p, text, { mode: 384 });
|
|
19668
20377
|
return p;
|
|
19669
20378
|
}),
|
|
20379
|
+
mockOut: (name) => {
|
|
20380
|
+
const dir = join25(tmpdir(), "sleds-mocks");
|
|
20381
|
+
mkdirSync18(dir, { recursive: true, mode: 448 });
|
|
20382
|
+
const p = join25(dir, `${name}.html`);
|
|
20383
|
+
rmSync10(p, { force: true });
|
|
20384
|
+
return p;
|
|
20385
|
+
},
|
|
20386
|
+
readMock: (p) => {
|
|
20387
|
+
try {
|
|
20388
|
+
return readFileSync16(p, "utf8");
|
|
20389
|
+
} catch {
|
|
20390
|
+
return null;
|
|
20391
|
+
}
|
|
20392
|
+
},
|
|
19670
20393
|
ensureWorktree: (e, repoPath, branch, path, base, install) => ensureWorktree(e, repoPath, branch, path, base, o.worktreeFs ?? { ...realWorktreeFs, exists }, { ...install ? { command: install } : {}, log: o.log ?? console.log }),
|
|
19671
20394
|
ensureDraftWorktree: (e, repoPath, path, base) => ensureDetachedWorktree(e, repoPath, path, base, o.worktreeFs ?? { ...realWorktreeFs, exists }),
|
|
19672
20395
|
defaultBranch,
|
|
@@ -19691,14 +20414,14 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
19691
20414
|
}
|
|
19692
20415
|
function sandboxDenyRead(home, env) {
|
|
19693
20416
|
return {
|
|
19694
|
-
dirs: [...new Set([configDir(home, env),
|
|
20417
|
+
dirs: [...new Set([configDir(home, env), join25(home, ".config", "sleds")])],
|
|
19695
20418
|
files: [
|
|
19696
20419
|
...new Set([
|
|
19697
20420
|
tokenPath(home, env),
|
|
19698
|
-
|
|
20421
|
+
join25(home, ".sleds-token"),
|
|
19699
20422
|
settingsPath(home, env),
|
|
19700
20423
|
backupPath(home, env),
|
|
19701
|
-
|
|
20424
|
+
join25(claudeDir(home, env), "settings.local.json")
|
|
19702
20425
|
])
|
|
19703
20426
|
]
|
|
19704
20427
|
};
|
|
@@ -19715,21 +20438,21 @@ function gitCommonDirOf(exec, cwd) {
|
|
|
19715
20438
|
const dir = r.status === 0 ? r.stdout.trim() : "";
|
|
19716
20439
|
if (!dir)
|
|
19717
20440
|
throw new Error(`git has no common dir for ${cwd}, so the sandbox has nowhere to commit`);
|
|
19718
|
-
return
|
|
20441
|
+
return resolve9(cwd, dir);
|
|
19719
20442
|
}
|
|
19720
20443
|
var LENT_NEEDS_SANDBOX = "a lent engine runs every session sandboxed (spec 48 rule 10) — add --sandbox to --lent-by";
|
|
19721
20444
|
function lenderHome(accountHome, lentBy) {
|
|
19722
|
-
return isAbsolute3(lentBy) ?
|
|
20445
|
+
return isAbsolute3(lentBy) ? resolve9(lentBy) : join25(dirname16(accountHome), lentBy);
|
|
19723
20446
|
}
|
|
19724
20447
|
function lentHomeProblems(accountHome, lentBy, modeOf) {
|
|
19725
20448
|
const lender = lenderHome(accountHome, lentBy);
|
|
19726
|
-
if (lender ===
|
|
20449
|
+
if (lender === resolve9(accountHome))
|
|
19727
20450
|
return [
|
|
19728
20451
|
`--lent-by ${lentBy} is this account — a lent engine runs as the borrower's own OS user, not the lender's`
|
|
19729
20452
|
];
|
|
19730
20453
|
const problems = [];
|
|
19731
20454
|
for (const [who, home] of [
|
|
19732
|
-
["the borrower's",
|
|
20455
|
+
["the borrower's", resolve9(accountHome)],
|
|
19733
20456
|
["the lender's", lender]
|
|
19734
20457
|
]) {
|
|
19735
20458
|
const mode = modeOf(home);
|
|
@@ -19742,7 +20465,7 @@ function lentHomeProblems(accountHome, lentBy, modeOf) {
|
|
|
19742
20465
|
}
|
|
19743
20466
|
var homeMode = (path) => {
|
|
19744
20467
|
try {
|
|
19745
|
-
return
|
|
20468
|
+
return statSync6(path).mode & 4095;
|
|
19746
20469
|
} catch {
|
|
19747
20470
|
return null;
|
|
19748
20471
|
}
|
|
@@ -19787,7 +20510,7 @@ async function driveEngine(o, flags, deps, until = {}) {
|
|
|
19787
20510
|
runner: deps.runner.name,
|
|
19788
20511
|
atOnce: flags.atOnce,
|
|
19789
20512
|
interval: flags.interval,
|
|
19790
|
-
cliVersion: "0.1.
|
|
20513
|
+
cliVersion: "0.1.62"
|
|
19791
20514
|
};
|
|
19792
20515
|
const beat = (checkedAt) => {
|
|
19793
20516
|
const m = deps.machine;
|
|
@@ -20135,14 +20858,14 @@ init_config();
|
|
|
20135
20858
|
import {
|
|
20136
20859
|
existsSync as existsSync19,
|
|
20137
20860
|
mkdirSync as mkdirSync19,
|
|
20138
|
-
readFileSync as
|
|
20861
|
+
readFileSync as readFileSync17,
|
|
20139
20862
|
readdirSync as readdirSync4,
|
|
20140
20863
|
realpathSync,
|
|
20141
20864
|
rmSync as rmSync11,
|
|
20142
20865
|
writeFileSync as writeFileSync17
|
|
20143
20866
|
} from "node:fs";
|
|
20144
20867
|
import { hostname as hostname3 } from "node:os";
|
|
20145
|
-
import { basename as basename6, dirname as
|
|
20868
|
+
import { basename as basename6, dirname as dirname17, isAbsolute as isAbsolute4, join as join26 } from "node:path";
|
|
20146
20869
|
init_state();
|
|
20147
20870
|
var ENGINE_LABEL = "ai.sleds.engine";
|
|
20148
20871
|
var ENGINE_INSTALL_USAGE = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
|
|
@@ -20163,13 +20886,13 @@ function engineLabel(name, org, seat) {
|
|
|
20163
20886
|
return [ENGINE_LABEL, org, seat?.trim(), name].filter((p) => Boolean(p)).map((p, i) => i === 0 ? p : engineSlug(p)).join(".");
|
|
20164
20887
|
}
|
|
20165
20888
|
function enginePlistPath(home, name, org, seat) {
|
|
20166
|
-
return
|
|
20889
|
+
return join26(home, "Library", "LaunchAgents", `${engineLabel(name, org, seat)}.plist`);
|
|
20167
20890
|
}
|
|
20168
20891
|
function engineLogPath(stateDir, name) {
|
|
20169
|
-
return
|
|
20892
|
+
return join26(stateDir, `${engineSlug(name)}.log`);
|
|
20170
20893
|
}
|
|
20171
20894
|
function engineEventsPath(stateDir, name) {
|
|
20172
|
-
return
|
|
20895
|
+
return join26(stateDir, `${engineSlug(name)}.events.jsonl`);
|
|
20173
20896
|
}
|
|
20174
20897
|
var xmlEscape4 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
20175
20898
|
function buildEnginePlist(o) {
|
|
@@ -20266,10 +20989,10 @@ function readEngines(dir, suffix, manager, parse) {
|
|
|
20266
20989
|
}
|
|
20267
20990
|
const out = [];
|
|
20268
20991
|
for (const name of names.filter((n) => n.startsWith(`${ENGINE_LABEL}.`) && n.endsWith(suffix))) {
|
|
20269
|
-
const path =
|
|
20992
|
+
const path = join26(dir, name);
|
|
20270
20993
|
let parsed;
|
|
20271
20994
|
try {
|
|
20272
|
-
parsed = parse(
|
|
20995
|
+
parsed = parse(readFileSync17(path, "utf8"), name);
|
|
20273
20996
|
} catch {
|
|
20274
20997
|
parsed = null;
|
|
20275
20998
|
}
|
|
@@ -20286,7 +21009,7 @@ function readEngines(dir, suffix, manager, parse) {
|
|
|
20286
21009
|
}
|
|
20287
21010
|
function installedEngines(home) {
|
|
20288
21011
|
return [
|
|
20289
|
-
...readEngines(
|
|
21012
|
+
...readEngines(join26(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist),
|
|
20290
21013
|
...readEngines(engineUnitDir(home), ".service", "systemd", (text, file) => {
|
|
20291
21014
|
const parsed = parseEngineUnit(text);
|
|
20292
21015
|
return parsed && { label: basename6(file, ".service"), ...parsed };
|
|
@@ -20336,7 +21059,7 @@ function engineInstall(o) {
|
|
|
20336
21059
|
if (platform === "linux")
|
|
20337
21060
|
return installUnit({ o, parsed, label, sledsArgv, env: agentEnv, logPath, exec });
|
|
20338
21061
|
const plist = enginePlistPath(o.home, parsed.name, parsed.org, seat);
|
|
20339
|
-
mkdirSync19(
|
|
21062
|
+
mkdirSync19(dirname17(plist), { recursive: true });
|
|
20340
21063
|
if (existsSync19(plist))
|
|
20341
21064
|
exec("launchctl", ["unload", plist]);
|
|
20342
21065
|
for (const other of installedEngines(o.home)) {
|
|
@@ -20378,7 +21101,7 @@ function installUnit(a) {
|
|
|
20378
21101
|
const unit = engineUnitPath(o.home, label);
|
|
20379
21102
|
const unitName = basename6(unit);
|
|
20380
21103
|
const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
|
|
20381
|
-
mkdirSync19(
|
|
21104
|
+
mkdirSync19(dirname17(unit), { recursive: true });
|
|
20382
21105
|
if (existsSync19(unit))
|
|
20383
21106
|
systemctl("stop", unitName);
|
|
20384
21107
|
for (const other of installedEngines(o.home)) {
|
|
@@ -20456,7 +21179,7 @@ function engineUninstall(o) {
|
|
|
20456
21179
|
}
|
|
20457
21180
|
|
|
20458
21181
|
// src/commands/musher.ts
|
|
20459
|
-
import { existsSync as existsSync20, mkdirSync as mkdirSync20, readFileSync as
|
|
21182
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync20, readFileSync as readFileSync18, rmSync as rmSync12, writeFileSync as writeFileSync18 } from "node:fs";
|
|
20460
21183
|
init_config();
|
|
20461
21184
|
init_meter();
|
|
20462
21185
|
var defaultWhich = (cmd) => {
|
|
@@ -20484,12 +21207,14 @@ var findClaude = (home, configured, which) => {
|
|
|
20484
21207
|
return p;
|
|
20485
21208
|
return null;
|
|
20486
21209
|
};
|
|
21210
|
+
var MUSHER_SWITCHES = new Set(["install", "uninstall", "status"]);
|
|
21211
|
+
var MUSHER_SETTINGS = new Set(["claude", "mode", "timeout"]);
|
|
20487
21212
|
var musherAgentState = (home, env = process.env) => {
|
|
20488
21213
|
const plist = musherPlistPath(home, env);
|
|
20489
21214
|
if (!existsSync20(plist))
|
|
20490
21215
|
return { installed: false, thisSeat: false };
|
|
20491
21216
|
try {
|
|
20492
|
-
const text =
|
|
21217
|
+
const text = readFileSync18(plist, "utf8");
|
|
20493
21218
|
const want = env.SLEDS_HOME?.trim();
|
|
20494
21219
|
const has = /<key>SLEDS_HOME<\/key>\s*<string>([^<]*)<\/string>/.exec(text)?.[1];
|
|
20495
21220
|
return { installed: true, thisSeat: (want ?? undefined) === (has ?? undefined) };
|
|
@@ -20499,7 +21224,7 @@ var musherAgentState = (home, env = process.env) => {
|
|
|
20499
21224
|
};
|
|
20500
21225
|
|
|
20501
21226
|
// src/claudeAccount.ts
|
|
20502
|
-
import { readFileSync as
|
|
21227
|
+
import { readFileSync as readFileSync19 } from "node:fs";
|
|
20503
21228
|
var PLANS = {
|
|
20504
21229
|
claude_max: "Max",
|
|
20505
21230
|
claude_pro: "Pro",
|
|
@@ -20528,7 +21253,7 @@ var parseClaudeAccount = (raw) => {
|
|
|
20528
21253
|
};
|
|
20529
21254
|
var readClaudeAccount = (home, env = process.env) => {
|
|
20530
21255
|
try {
|
|
20531
|
-
return parseClaudeAccount(JSON.parse(
|
|
21256
|
+
return parseClaudeAccount(JSON.parse(readFileSync19(claudeUserConfigPath2(home, env), "utf8")));
|
|
20532
21257
|
} catch {
|
|
20533
21258
|
return null;
|
|
20534
21259
|
}
|
|
@@ -20665,7 +21390,7 @@ async function runDoctor(o) {
|
|
|
20665
21390
|
detail: `seat-event ${seat ? "on" : "missing"} · spec-event ${spec ? "on" : "missing"} · session-event ${session ? "on" : "missing"} · stop-event ${stop ? "on" : "missing"}`,
|
|
20666
21391
|
fix: all ? undefined : "sleds hooks"
|
|
20667
21392
|
});
|
|
20668
|
-
const want = env.SLEDS_HOME?.trim() ?
|
|
21393
|
+
const want = env.SLEDS_HOME?.trim() ? resolve10(home, env.SLEDS_HOME.trim()) : undefined;
|
|
20669
21394
|
const cmds = sledsCommandsIn(settings);
|
|
20670
21395
|
const wrong = cmds.filter((c) => {
|
|
20671
21396
|
const got = bakedHome(c);
|
|
@@ -20754,7 +21479,7 @@ async function runDoctor(o) {
|
|
|
20754
21479
|
checks.push({ level: "ok", name: "path", detail: which[0] ?? "" });
|
|
20755
21480
|
const link = sledsLink(home, o.platform);
|
|
20756
21481
|
if (existsSync21(link)) {
|
|
20757
|
-
const binDir =
|
|
21482
|
+
const binDir = dirname18(link);
|
|
20758
21483
|
const onPath = (env.PATH ?? "").split(delimiter3).includes(binDir);
|
|
20759
21484
|
const first = which[0];
|
|
20760
21485
|
const fix = `echo 'export PATH="${binDir}:$PATH"' >> ~/.zshrc`;
|
|
@@ -20943,12 +21668,12 @@ function sandboxChecks(o, env) {
|
|
|
20943
21668
|
}
|
|
20944
21669
|
];
|
|
20945
21670
|
const nonce = o.nonce ?? `sleds-probe-${randomBytes(16).toString("hex")}`;
|
|
20946
|
-
const probe =
|
|
20947
|
-
const work = mkdtempSync(
|
|
21671
|
+
const probe = join27(dir, SANDBOX_PROBE);
|
|
21672
|
+
const work = mkdtempSync(join27(tmpdir2(), "sleds-sandbox-"));
|
|
20948
21673
|
try {
|
|
20949
21674
|
writeFileSync19(probe, `${nonce}
|
|
20950
21675
|
`, { mode: 384 });
|
|
20951
|
-
const settingsFile =
|
|
21676
|
+
const settingsFile = join27(work, "settings.json");
|
|
20952
21677
|
const settings = engineSandboxSettings(o.home, env, work, SANDBOX_DEFAULT_ALLOW);
|
|
20953
21678
|
const claudeSettings = settingsPath(o.home, env);
|
|
20954
21679
|
writeFileSync19(settingsFile, JSON.stringify(settings, null, 2), { mode: 384 });
|
|
@@ -21122,7 +21847,7 @@ function boxChecks(o, env, which, need) {
|
|
|
21122
21847
|
const file = boxEnvPath(o.home);
|
|
21123
21848
|
let boxEnvText = null;
|
|
21124
21849
|
try {
|
|
21125
|
-
boxEnvText =
|
|
21850
|
+
boxEnvText = readFileSync20(file, "utf8");
|
|
21126
21851
|
} catch {
|
|
21127
21852
|
boxEnvText = null;
|
|
21128
21853
|
}
|
|
@@ -21240,14 +21965,14 @@ import {
|
|
|
21240
21965
|
appendFileSync as appendFileSync3,
|
|
21241
21966
|
chmodSync as chmodSync6,
|
|
21242
21967
|
mkdirSync as mkdirSync21,
|
|
21243
|
-
readFileSync as
|
|
21968
|
+
readFileSync as readFileSync21,
|
|
21244
21969
|
existsSync as realExists2,
|
|
21245
21970
|
rmSync as rmSync14,
|
|
21246
|
-
statSync as
|
|
21971
|
+
statSync as statSync7,
|
|
21247
21972
|
writeFileSync as writeFileSync20
|
|
21248
21973
|
} from "node:fs";
|
|
21249
|
-
import { hostname as hostname4, userInfo as userInfo3 } from "node:os";
|
|
21250
|
-
import { dirname as
|
|
21974
|
+
import { hostname as hostname4, tmpdir as tmpdir3, userInfo as userInfo3 } from "node:os";
|
|
21975
|
+
import { dirname as dirname19, isAbsolute as isAbsolute5, join as join28, resolve as resolve11 } from "node:path";
|
|
21251
21976
|
init_machine();
|
|
21252
21977
|
init_state();
|
|
21253
21978
|
init_meter();
|
|
@@ -21507,7 +22232,7 @@ function flagsFromProfile2(flags, given, profile, home) {
|
|
|
21507
22232
|
}
|
|
21508
22233
|
}
|
|
21509
22234
|
if (profile.reposDir && !has("repos-dir") && !has("repo")) {
|
|
21510
|
-
out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ?
|
|
22235
|
+
out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join28(home, d.slice(1)) : d).join(":");
|
|
21511
22236
|
used.push(`repos ${profile.reposDir}`);
|
|
21512
22237
|
}
|
|
21513
22238
|
if (profile.mcpStrict !== undefined && !has("strict-mcp") && !has("no-strict-mcp")) {
|
|
@@ -21654,7 +22379,7 @@ function engineClient2(o, org, breaker) {
|
|
|
21654
22379
|
...src,
|
|
21655
22380
|
...breaker ? { fetchFn: breaker.fetch } : {},
|
|
21656
22381
|
timeoutMs: ENGINE_TIMEOUT_MS2,
|
|
21657
|
-
version: "0.1.
|
|
22382
|
+
version: "0.1.62"
|
|
21658
22383
|
});
|
|
21659
22384
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
21660
22385
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
@@ -21696,19 +22421,19 @@ function realPidAlive3(pid) {
|
|
|
21696
22421
|
function memberMcpConfigs2(o, cwd) {
|
|
21697
22422
|
const read = o.readJson ?? ((p) => {
|
|
21698
22423
|
try {
|
|
21699
|
-
return JSON.parse(
|
|
22424
|
+
return JSON.parse(readFileSync21(p, "utf8"));
|
|
21700
22425
|
} catch {
|
|
21701
22426
|
return null;
|
|
21702
22427
|
}
|
|
21703
22428
|
});
|
|
21704
22429
|
const claudeDir = (o.env ?? process.env).CLAUDE_CONFIG_DIR;
|
|
21705
22430
|
return [
|
|
21706
|
-
read(claudeDir ?
|
|
21707
|
-
...cwd ? [read(
|
|
22431
|
+
read(claudeDir ? join28(claudeDir, ".claude.json") : join28(o.home, ".claude.json")),
|
|
22432
|
+
...cwd ? [read(join28(cwd, ".mcp.json"))] : []
|
|
21708
22433
|
];
|
|
21709
22434
|
}
|
|
21710
22435
|
function engineStateDir2(o, org, seat) {
|
|
21711
|
-
return seatStateDir(orgStateDir(o.stateDir ??
|
|
22436
|
+
return seatStateDir(orgStateDir(o.stateDir ?? join28(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
|
|
21712
22437
|
}
|
|
21713
22438
|
function engineSeat2(o, org) {
|
|
21714
22439
|
try {
|
|
@@ -21731,7 +22456,7 @@ function engineCredential(o) {
|
|
|
21731
22456
|
const file = boxEnvPath(o.home);
|
|
21732
22457
|
let boxEnvText = null;
|
|
21733
22458
|
try {
|
|
21734
|
-
boxEnvText =
|
|
22459
|
+
boxEnvText = readFileSync21(file, "utf8");
|
|
21735
22460
|
} catch {}
|
|
21736
22461
|
return detectCredential(o.env ?? process.env, {
|
|
21737
22462
|
home: o.home,
|
|
@@ -21748,11 +22473,11 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
21748
22473
|
const stateDir = engineStateDir2(o, flags.org, flags.seat);
|
|
21749
22474
|
const file = statePath(stateDir, stateName);
|
|
21750
22475
|
const mcpOrg = flags.org && engineOrg2(o, flags.org).seated ? flags.org : undefined;
|
|
21751
|
-
const repo = flags.repo ?
|
|
21752
|
-
const reposDirs = splitReposDirs(flags.reposDir).map((d) =>
|
|
22476
|
+
const repo = flags.repo ? resolve11(cwd, flags.repo) : undefined;
|
|
22477
|
+
const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve11(cwd, d));
|
|
21753
22478
|
const { branch, prTitle } = flags;
|
|
21754
|
-
const hooksDir =
|
|
21755
|
-
const permissionMark = (name) =>
|
|
22479
|
+
const hooksDir = join28(stateDir, "hooks");
|
|
22480
|
+
const permissionMark = (name) => join28(hooksDir, `${name}.permission.json`);
|
|
21756
22481
|
const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
|
|
21757
22482
|
return {
|
|
21758
22483
|
source,
|
|
@@ -21777,9 +22502,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
21777
22502
|
sandbox: true,
|
|
21778
22503
|
writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow) => {
|
|
21779
22504
|
const gitCommonDir = gitCommonDirOf2(exec, cwd);
|
|
21780
|
-
const dir =
|
|
22505
|
+
const dir = join28(stateDir, "sandbox");
|
|
21781
22506
|
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
21782
|
-
const p =
|
|
22507
|
+
const p = join28(dir, `${name}.json`);
|
|
21783
22508
|
const walls = engineSandboxSettings2(o.home, o.env ?? process.env, gitCommonDir, [
|
|
21784
22509
|
...SANDBOX_DEFAULT_ALLOW,
|
|
21785
22510
|
...flags.sandboxAllow ?? []
|
|
@@ -21796,7 +22521,7 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
21796
22521
|
} : {},
|
|
21797
22522
|
writeHookSettings: (name, allow) => {
|
|
21798
22523
|
mkdirSync21(hooksDir, { recursive: true, mode: 448 });
|
|
21799
|
-
const p =
|
|
22524
|
+
const p = join28(hooksDir, `${name}.json`);
|
|
21800
22525
|
const base = allow?.length ? { permissions: { allow: [...allow] } } : {};
|
|
21801
22526
|
writeFileSync20(p, `${JSON.stringify(withHook(name, base), null, 2)}
|
|
21802
22527
|
`, { mode: 384 });
|
|
@@ -21824,9 +22549,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
21824
22549
|
exists
|
|
21825
22550
|
}),
|
|
21826
22551
|
writeMcpConfig: o.writeMcpConfig ?? ((name, runToken, worktree) => {
|
|
21827
|
-
const dir =
|
|
22552
|
+
const dir = join28(stateDir, "mcp");
|
|
21828
22553
|
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
21829
|
-
const p =
|
|
22554
|
+
const p = join28(dir, `${name}.json`);
|
|
21830
22555
|
let others = {};
|
|
21831
22556
|
if (flags.strictMcp && flags.mcpAllow?.length) {
|
|
21832
22557
|
const r = mcpPassThrough(flags.mcpAllow, memberMcpConfigs2(o, worktree));
|
|
@@ -21842,12 +22567,26 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
21842
22567
|
}),
|
|
21843
22568
|
removeMcpConfig: o.removeMcpConfig ?? ((p) => rmSync14(p, { force: true })),
|
|
21844
22569
|
writePrompt: o.writePrompt ?? ((name, text) => {
|
|
21845
|
-
const dir =
|
|
22570
|
+
const dir = join28(stateDir, "prompts");
|
|
21846
22571
|
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
21847
|
-
const p =
|
|
22572
|
+
const p = join28(dir, `${name}.md`);
|
|
21848
22573
|
writeFileSync20(p, text, { mode: 384 });
|
|
21849
22574
|
return p;
|
|
21850
22575
|
}),
|
|
22576
|
+
mockOut: (name) => {
|
|
22577
|
+
const dir = join28(tmpdir3(), "sleds-mocks");
|
|
22578
|
+
mkdirSync21(dir, { recursive: true, mode: 448 });
|
|
22579
|
+
const p = join28(dir, `${name}.html`);
|
|
22580
|
+
rmSync14(p, { force: true });
|
|
22581
|
+
return p;
|
|
22582
|
+
},
|
|
22583
|
+
readMock: (p) => {
|
|
22584
|
+
try {
|
|
22585
|
+
return readFileSync21(p, "utf8");
|
|
22586
|
+
} catch {
|
|
22587
|
+
return null;
|
|
22588
|
+
}
|
|
22589
|
+
},
|
|
21851
22590
|
ensureWorktree: (e, repoPath, branch, path, base, install) => ensureWorktree(e, repoPath, branch, path, base, o.worktreeFs ?? { ...realWorktreeFs, exists }, { ...install ? { command: install } : {}, log: o.log ?? console.log }),
|
|
21852
22591
|
ensureDraftWorktree: (e, repoPath, path, base) => ensureDetachedWorktree(e, repoPath, path, base, o.worktreeFs ?? { ...realWorktreeFs, exists }),
|
|
21853
22592
|
defaultBranch,
|
|
@@ -21872,14 +22611,14 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
21872
22611
|
}
|
|
21873
22612
|
function sandboxDenyRead2(home, env) {
|
|
21874
22613
|
return {
|
|
21875
|
-
dirs: [...new Set([configDir(home, env),
|
|
22614
|
+
dirs: [...new Set([configDir(home, env), join28(home, ".config", "sleds")])],
|
|
21876
22615
|
files: [
|
|
21877
22616
|
...new Set([
|
|
21878
22617
|
tokenPath(home, env),
|
|
21879
|
-
|
|
22618
|
+
join28(home, ".sleds-token"),
|
|
21880
22619
|
settingsPath(home, env),
|
|
21881
22620
|
backupPath(home, env),
|
|
21882
|
-
|
|
22621
|
+
join28(claudeDir(home, env), "settings.local.json")
|
|
21883
22622
|
])
|
|
21884
22623
|
]
|
|
21885
22624
|
};
|
|
@@ -21896,7 +22635,7 @@ function gitCommonDirOf2(exec, cwd) {
|
|
|
21896
22635
|
const dir = r.status === 0 ? r.stdout.trim() : "";
|
|
21897
22636
|
if (!dir)
|
|
21898
22637
|
throw new Error(`git has no common dir for ${cwd}, so the sandbox has nowhere to commit`);
|
|
21899
|
-
return
|
|
22638
|
+
return resolve11(cwd, dir);
|
|
21900
22639
|
}
|
|
21901
22640
|
function sandboxRefusal(flags) {
|
|
21902
22641
|
if (flags.lentBy && !flags.sandbox)
|
|
@@ -21913,17 +22652,17 @@ function sandboxRefusal(flags) {
|
|
|
21913
22652
|
}
|
|
21914
22653
|
var LENT_NEEDS_SANDBOX2 = "a lent engine runs every session sandboxed (spec 48 rule 10) — add --sandbox to --lent-by";
|
|
21915
22654
|
function lenderHome2(accountHome, lentBy) {
|
|
21916
|
-
return isAbsolute5(lentBy) ?
|
|
22655
|
+
return isAbsolute5(lentBy) ? resolve11(lentBy) : join28(dirname19(accountHome), lentBy);
|
|
21917
22656
|
}
|
|
21918
22657
|
function lentHomeProblems2(accountHome, lentBy, modeOf) {
|
|
21919
22658
|
const lender = lenderHome2(accountHome, lentBy);
|
|
21920
|
-
if (lender ===
|
|
22659
|
+
if (lender === resolve11(accountHome))
|
|
21921
22660
|
return [
|
|
21922
22661
|
`--lent-by ${lentBy} is this account — a lent engine runs as the borrower's own OS user, not the lender's`
|
|
21923
22662
|
];
|
|
21924
22663
|
const problems = [];
|
|
21925
22664
|
for (const [who, home] of [
|
|
21926
|
-
["the borrower's",
|
|
22665
|
+
["the borrower's", resolve11(accountHome)],
|
|
21927
22666
|
["the lender's", lender]
|
|
21928
22667
|
]) {
|
|
21929
22668
|
const mode = modeOf(home);
|
|
@@ -21936,7 +22675,7 @@ function lentHomeProblems2(accountHome, lentBy, modeOf) {
|
|
|
21936
22675
|
}
|
|
21937
22676
|
var homeMode2 = (path) => {
|
|
21938
22677
|
try {
|
|
21939
|
-
return
|
|
22678
|
+
return statSync7(path).mode & 4095;
|
|
21940
22679
|
} catch {
|
|
21941
22680
|
return null;
|
|
21942
22681
|
}
|
|
@@ -21981,7 +22720,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
|
|
|
21981
22720
|
runner: deps.runner.name,
|
|
21982
22721
|
atOnce: flags.atOnce,
|
|
21983
22722
|
interval: flags.interval,
|
|
21984
|
-
cliVersion: "0.1.
|
|
22723
|
+
cliVersion: "0.1.62"
|
|
21985
22724
|
};
|
|
21986
22725
|
const beat = (checkedAt) => {
|
|
21987
22726
|
const m = deps.machine;
|
|
@@ -22187,7 +22926,7 @@ function engineRunner2(o, flags) {
|
|
|
22187
22926
|
});
|
|
22188
22927
|
}
|
|
22189
22928
|
function engineStartGuard(home, env, now) {
|
|
22190
|
-
return startGuard({ home, version: env
|
|
22929
|
+
return startGuard({ home, version: cliVersion(env), now });
|
|
22191
22930
|
}
|
|
22192
22931
|
var engineCmd = async (o) => {
|
|
22193
22932
|
const log = o.log ?? console.log;
|
|
@@ -22338,7 +23077,7 @@ var engineCmd = async (o) => {
|
|
|
22338
23077
|
log(terminalOf2(o).c.dim(n));
|
|
22339
23078
|
const watch = firstBeatWatchdog({
|
|
22340
23079
|
home: o.home,
|
|
22341
|
-
version: (o.env
|
|
23080
|
+
version: cliVersion(o.env),
|
|
22342
23081
|
say: error,
|
|
22343
23082
|
...o.updates?.stateFiles ? { stateFiles: o.updates.stateFiles() } : {},
|
|
22344
23083
|
...o.watchdog
|
|
@@ -22419,7 +23158,7 @@ function engineUpdaterFor(o, flags, deps, client) {
|
|
|
22419
23158
|
return engineUpdater({
|
|
22420
23159
|
home: o.home,
|
|
22421
23160
|
engine: statePath(engineStateDir2(o, flags.org, flags.seat), deps.engine),
|
|
22422
|
-
version: env
|
|
23161
|
+
version: cliVersion(env),
|
|
22423
23162
|
compiled: o.updates?.compiled ?? isCompiled(),
|
|
22424
23163
|
tokens: () => {
|
|
22425
23164
|
try {
|
|
@@ -22611,14 +23350,14 @@ init_config();
|
|
|
22611
23350
|
import {
|
|
22612
23351
|
existsSync as existsSync22,
|
|
22613
23352
|
mkdirSync as mkdirSync22,
|
|
22614
|
-
readFileSync as
|
|
23353
|
+
readFileSync as readFileSync22,
|
|
22615
23354
|
readdirSync as readdirSync6,
|
|
22616
23355
|
realpathSync as realpathSync2,
|
|
22617
23356
|
rmSync as rmSync15,
|
|
22618
23357
|
writeFileSync as writeFileSync21
|
|
22619
23358
|
} from "node:fs";
|
|
22620
23359
|
import { hostname as hostname5 } from "node:os";
|
|
22621
|
-
import { basename as basename7, dirname as
|
|
23360
|
+
import { basename as basename7, dirname as dirname20, isAbsolute as isAbsolute6, join as join29 } from "node:path";
|
|
22622
23361
|
init_state();
|
|
22623
23362
|
var ENGINE_LABEL2 = "ai.sleds.engine";
|
|
22624
23363
|
var ENGINE_INSTALL_USAGE2 = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
|
|
@@ -22639,13 +23378,13 @@ function engineLabel2(name, org, seat) {
|
|
|
22639
23378
|
return [ENGINE_LABEL2, org, seat?.trim(), name].filter((p) => Boolean(p)).map((p, i) => i === 0 ? p : engineSlug(p)).join(".");
|
|
22640
23379
|
}
|
|
22641
23380
|
function enginePlistPath2(home, name, org, seat) {
|
|
22642
|
-
return
|
|
23381
|
+
return join29(home, "Library", "LaunchAgents", `${engineLabel2(name, org, seat)}.plist`);
|
|
22643
23382
|
}
|
|
22644
23383
|
function engineLogPath2(stateDir, name) {
|
|
22645
|
-
return
|
|
23384
|
+
return join29(stateDir, `${engineSlug(name)}.log`);
|
|
22646
23385
|
}
|
|
22647
23386
|
function engineEventsPath2(stateDir, name) {
|
|
22648
|
-
return
|
|
23387
|
+
return join29(stateDir, `${engineSlug(name)}.events.jsonl`);
|
|
22649
23388
|
}
|
|
22650
23389
|
var xmlEscape5 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
22651
23390
|
function buildEnginePlist2(o) {
|
|
@@ -22742,10 +23481,10 @@ function readEngines2(dir, suffix, manager, parse) {
|
|
|
22742
23481
|
}
|
|
22743
23482
|
const out = [];
|
|
22744
23483
|
for (const name of names.filter((n) => n.startsWith(`${ENGINE_LABEL2}.`) && n.endsWith(suffix))) {
|
|
22745
|
-
const path =
|
|
23484
|
+
const path = join29(dir, name);
|
|
22746
23485
|
let parsed;
|
|
22747
23486
|
try {
|
|
22748
|
-
parsed = parse(
|
|
23487
|
+
parsed = parse(readFileSync22(path, "utf8"), name);
|
|
22749
23488
|
} catch {
|
|
22750
23489
|
parsed = null;
|
|
22751
23490
|
}
|
|
@@ -22762,7 +23501,7 @@ function readEngines2(dir, suffix, manager, parse) {
|
|
|
22762
23501
|
}
|
|
22763
23502
|
function installedEngines2(home) {
|
|
22764
23503
|
return [
|
|
22765
|
-
...readEngines2(
|
|
23504
|
+
...readEngines2(join29(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist2),
|
|
22766
23505
|
...readEngines2(engineUnitDir(home), ".service", "systemd", (text, file) => {
|
|
22767
23506
|
const parsed = parseEngineUnit(text);
|
|
22768
23507
|
return parsed && { label: basename7(file, ".service"), ...parsed };
|
|
@@ -22800,7 +23539,7 @@ async function ensureReposDir(o) {
|
|
|
22800
23539
|
return false;
|
|
22801
23540
|
}
|
|
22802
23541
|
const exists = o.exists ?? existsSync22;
|
|
22803
|
-
const missing = dirs.filter((d) => !exists(/^~(\/|$)/.test(d) ?
|
|
23542
|
+
const missing = dirs.filter((d) => !exists(/^~(\/|$)/.test(d) ? join29(o.home, d.slice(1)) : d));
|
|
22804
23543
|
if (missing.length) {
|
|
22805
23544
|
error(`Not a folder on this machine: ${missing.join(", ")}. ${REPOS_DIR_NEEDED}`);
|
|
22806
23545
|
return false;
|
|
@@ -22856,7 +23595,7 @@ function engineInstall2(o) {
|
|
|
22856
23595
|
if (platform === "linux")
|
|
22857
23596
|
return installUnit2({ o, parsed, label, sledsArgv, env: agentEnv, logPath, exec });
|
|
22858
23597
|
const plist = enginePlistPath2(o.home, parsed.name, parsed.org, seat);
|
|
22859
|
-
mkdirSync22(
|
|
23598
|
+
mkdirSync22(dirname20(plist), { recursive: true });
|
|
22860
23599
|
if (existsSync22(plist))
|
|
22861
23600
|
exec("launchctl", ["unload", plist]);
|
|
22862
23601
|
for (const other of installedEngines2(o.home)) {
|
|
@@ -22898,7 +23637,7 @@ function installUnit2(a) {
|
|
|
22898
23637
|
const unit = engineUnitPath(o.home, label);
|
|
22899
23638
|
const unitName = basename7(unit);
|
|
22900
23639
|
const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
|
|
22901
|
-
mkdirSync22(
|
|
23640
|
+
mkdirSync22(dirname20(unit), { recursive: true });
|
|
22902
23641
|
if (existsSync22(unit))
|
|
22903
23642
|
systemctl("stop", unitName);
|
|
22904
23643
|
for (const other of installedEngines2(o.home)) {
|
|
@@ -23099,7 +23838,7 @@ import { closeSync as closeSync5, fstatSync as fstatSync2, openSync as openSync5
|
|
|
23099
23838
|
import { hostname as hostname6 } from "node:os";
|
|
23100
23839
|
|
|
23101
23840
|
// src/commands/engineStatus.ts
|
|
23102
|
-
import { existsSync as existsSync23, readFileSync as
|
|
23841
|
+
import { existsSync as existsSync23, readFileSync as readFileSync23 } from "node:fs";
|
|
23103
23842
|
init_state();
|
|
23104
23843
|
|
|
23105
23844
|
// src/engine/status.ts
|
|
@@ -23181,7 +23920,10 @@ function engineStatus(i) {
|
|
|
23181
23920
|
...opt("review", r.pr.review || undefined),
|
|
23182
23921
|
mergeable: r.pr.clear === true,
|
|
23183
23922
|
queued: r.pr.queued === true,
|
|
23184
|
-
...opt("conflict", conflictOf(r, i.state.decisions, i.watchOf))
|
|
23923
|
+
...opt("conflict", conflictOf(r, i.state.decisions, i.watchOf)),
|
|
23924
|
+
runner: r.handle.runner,
|
|
23925
|
+
...r.pr.live ? { watch: i.watchOf(r), watchTarget: watchTarget(r.handle) } : {},
|
|
23926
|
+
...opt("worktree", r.handle.cwd !== r.repoPath ? r.handle.cwd : undefined)
|
|
23185
23927
|
});
|
|
23186
23928
|
continue;
|
|
23187
23929
|
}
|
|
@@ -23255,10 +23997,14 @@ function statusLines(s, now) {
|
|
|
23255
23997
|
}
|
|
23256
23998
|
lines.push(`running ${s.running.length}`);
|
|
23257
23999
|
for (const r of s.running)
|
|
23258
|
-
lines.push(` ${r.item}/${r.node} ${r.title} · ${r.answerer ? `parked, the decider answers${r.answerer.model ? ` on ${r.answerer.model}` : ""}${r.answerer.effort ? ` · ${r.answerer.effort}` : ""}` : r.parked ? "parked, waiting for your answer" : ago(r.startedAt)} · watch: ${r.watch}`);
|
|
24000
|
+
lines.push(` ${r.item}/${r.node} ${r.title} · ${r.answerer ? `parked, the decider answers${r.answerer.model ? ` on ${r.answerer.model}` : ""}${r.answerer.effort ? ` · ${r.answerer.effort}` : ""}` : r.parked ? "parked, waiting for your answer" : `${r.kind === "mock" ? "drawing a mock · " : ""}${ago(r.startedAt)}`} · watch: ${r.watch}`);
|
|
23259
24001
|
lines.push(`following ${s.following.length}`);
|
|
23260
24002
|
for (const f of s.following) {
|
|
23261
24003
|
lines.push(` ${f.item}/${f.node} ${f.pr}${f.checks ? ` checks ${f.checks}` : ""}${f.review ? ` · ${f.review}` : ""}${f.mergeable ? " · ready for your merge" : ""}${f.queued ? " · queued to merge" : ""}`);
|
|
24004
|
+
if (f.watch)
|
|
24005
|
+
lines.push(` watch: ${f.watch}`);
|
|
24006
|
+
else if (f.worktree)
|
|
24007
|
+
lines.push(` worktree: ${f.worktree}`);
|
|
23262
24008
|
const c = f.conflict;
|
|
23263
24009
|
if (c)
|
|
23264
24010
|
lines.push(` conflict on ${c.files.join(", ")}${c.cause ? ` · ${c.cause}` : ""} · ${CONFLICT_STAGE[c.stage]} · since ${ago(c.since)} ago${c.watch ? ` · watch: ${c.watch}` : ""}`);
|
|
@@ -23390,7 +24136,7 @@ var engineLogCmd = (o) => {
|
|
|
23390
24136
|
|
|
23391
24137
|
// src/commands/engineProfile.ts
|
|
23392
24138
|
init_src();
|
|
23393
|
-
import { existsSync as existsSync24, readFileSync as
|
|
24139
|
+
import { existsSync as existsSync24, readFileSync as readFileSync24 } from "node:fs";
|
|
23394
24140
|
import { hostname as hostname7 } from "node:os";
|
|
23395
24141
|
var PROFILE_USAGE = "usage: sleds engine profile [--json] | sleds engine profile set <field>=<value>… [--workspace] [--json] | sleds engine profile set --stdin [--workspace] [--json] | sleds engine profile --strict-mcp [--mcp-allow <a,b>] | --no-strict-mcp [--workspace] [--json] | sleds engine profile --sandbox [--sandbox-allow <a,b>] | --no-sandbox [--workspace] [--json] | sleds engine profile set --hold on|off [--workspace] [--json] | sleds engine profile set cmuxPassword=<pw> | --cmux-password <pw> [--json]";
|
|
23396
24142
|
var PROFILE_FIELDS = [
|
|
@@ -23661,7 +24407,7 @@ async function engineProfileCmd(o) {
|
|
|
23661
24407
|
const rest = words.slice(1);
|
|
23662
24408
|
let stdin = null;
|
|
23663
24409
|
if (fromStdin) {
|
|
23664
|
-
const taken = cmuxPasswordFromJson((o.stdin ?? (() =>
|
|
24410
|
+
const taken = cmuxPasswordFromJson((o.stdin ?? (() => readFileSync24(0, "utf8")))());
|
|
23665
24411
|
if ("error" in taken || taken.password !== undefined && password !== undefined) {
|
|
23666
24412
|
error("error" in taken ? taken.error : "the cmux password is given once");
|
|
23667
24413
|
error(PROFILE_USAGE);
|
|
@@ -23746,7 +24492,7 @@ var keychainLine = (k) => k === "set" ? "cmuxPassword: set (Keychain)" : k === "
|
|
|
23746
24492
|
|
|
23747
24493
|
// src/commands/engineStatus.ts
|
|
23748
24494
|
init_state();
|
|
23749
|
-
import { existsSync as existsSync25, readFileSync as
|
|
24495
|
+
import { existsSync as existsSync25, readFileSync as readFileSync25 } from "node:fs";
|
|
23750
24496
|
import { hostname as hostname8 } from "node:os";
|
|
23751
24497
|
var ENGINE_STATUS_USAGE = "usage: sleds engine status [--name <n>] [--org <slug>] [--json]";
|
|
23752
24498
|
function parseStatusArgs(argv, host) {
|
|
@@ -23802,7 +24548,7 @@ function readEngineStatus(stateDir, engine, host, pidAlive, seat) {
|
|
|
23802
24548
|
}
|
|
23803
24549
|
function safeRead(path) {
|
|
23804
24550
|
try {
|
|
23805
|
-
return
|
|
24551
|
+
return readFileSync25(path, "utf8");
|
|
23806
24552
|
} catch {
|
|
23807
24553
|
return "";
|
|
23808
24554
|
}
|
|
@@ -23923,10 +24669,10 @@ init_meter();
|
|
|
23923
24669
|
|
|
23924
24670
|
// src/owed.ts
|
|
23925
24671
|
init_config();
|
|
23926
|
-
import { existsSync as existsSync26, mkdirSync as mkdirSync23, readFileSync as
|
|
23927
|
-
import { dirname as
|
|
23928
|
-
var owedPath = (home) =>
|
|
23929
|
-
var sessionPath = (home) =>
|
|
24672
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync23, readFileSync as readFileSync26, renameSync as renameSync11, writeFileSync as writeFileSync22 } from "node:fs";
|
|
24673
|
+
import { dirname as dirname21, join as join30 } from "node:path";
|
|
24674
|
+
var owedPath = (home) => join30(configDir(home), "owed.json");
|
|
24675
|
+
var sessionPath = (home) => join30(configDir(home), "session.json");
|
|
23930
24676
|
var OWED_TTL_MS = 3 * 24 * 60 * 60000;
|
|
23931
24677
|
var str14 = (v) => typeof v === "string" ? v : undefined;
|
|
23932
24678
|
function sourceKey(s) {
|
|
@@ -23944,13 +24690,13 @@ var readJson = (p) => {
|
|
|
23944
24690
|
if (!existsSync26(p))
|
|
23945
24691
|
return null;
|
|
23946
24692
|
try {
|
|
23947
|
-
return JSON.parse(
|
|
24693
|
+
return JSON.parse(readFileSync26(p, "utf8"));
|
|
23948
24694
|
} catch {
|
|
23949
24695
|
return null;
|
|
23950
24696
|
}
|
|
23951
24697
|
};
|
|
23952
24698
|
var writeJson = (p, v) => {
|
|
23953
|
-
mkdirSync23(
|
|
24699
|
+
mkdirSync23(dirname21(p), { recursive: true, mode: 448 });
|
|
23954
24700
|
const tmp = `${p}.${process.pid}.tmp`;
|
|
23955
24701
|
writeFileSync22(tmp, `${JSON.stringify(v, null, 2)}
|
|
23956
24702
|
`, { mode: 384 });
|
|
@@ -24084,7 +24830,7 @@ function contextFor(deps) {
|
|
|
24084
24830
|
...src,
|
|
24085
24831
|
fetchFn: deps.fetchFn,
|
|
24086
24832
|
timeoutMs: deps.timeoutMs,
|
|
24087
|
-
version: "0.1.
|
|
24833
|
+
version: "0.1.62"
|
|
24088
24834
|
}), deps.home, now) : null;
|
|
24089
24835
|
return {
|
|
24090
24836
|
channel: "code",
|
|
@@ -24788,19 +25534,27 @@ var init = async (o) => {
|
|
|
24788
25534
|
const wrote = [];
|
|
24789
25535
|
const seatInfo = await fetchSeatInfo(url, resolved.token, o.fetchFn);
|
|
24790
25536
|
const org = seatInfo.org;
|
|
24791
|
-
const
|
|
25537
|
+
const current = readSettings(o.home, env);
|
|
25538
|
+
const prior = readConfig(o.home);
|
|
25539
|
+
const proxyUrls = [url, prior.proxyUrl, DEFAULT_PROXY_URL];
|
|
25540
|
+
const ours = isSledsProxyEnv(current, proxyUrls);
|
|
25541
|
+
const gateway = hasGatewayEnv(current) && !ours;
|
|
25542
|
+
const kept = ours ? "proxy-always" : "seat-first";
|
|
25543
|
+
if (!org && !o.proxyAlways && !o.seatFirst)
|
|
25544
|
+
error(`Could not read this seat's org from ${url}/proxy/meter; kept Claude Code's wiring as it was (${kept}). Re-run \`sleds init\` once the proxy answers.`);
|
|
25545
|
+
const wiring = o.proxyAlways ? "proxy-always" : o.seatFirst ? "seat-first" : org?.mode ?? kept;
|
|
24792
25546
|
if (wiring === "proxy-always" && org && !org.capabilities.upstreamKey) {
|
|
24793
25547
|
error(`${org.name} has no platform key for the proxy to forward with; --proxy-always would break every request. Using seat-first.`);
|
|
24794
25548
|
}
|
|
24795
25549
|
const finalWiring = wiring === "proxy-always" && org && !org.capabilities.upstreamKey ? "seat-first" : wiring;
|
|
24796
25550
|
if (backupSettings(o.home, env))
|
|
24797
25551
|
wrote.push(`backed up settings to ${backupPath(o.home, env)}`);
|
|
24798
|
-
const
|
|
24799
|
-
const
|
|
25552
|
+
const wired = finalWiring === "proxy-always" ? applyProxy(current, { url, token: resolved.token }) : ours ? switchOff(current, envToRestore([prior.priorEnv, prior.priorGatewayEnv], proxyUrls)) : current;
|
|
25553
|
+
const priorGatewayEnv = finalWiring !== "proxy-always" ? undefined : gateway ? capturePriorEnv(current) : prior.priorGatewayEnv;
|
|
24800
25554
|
const slug = org?.slug ?? resolved.approved?.org.slug;
|
|
24801
25555
|
const statusLine = applyStatusLine(wired, pinOrg(o.statusLineCommand ?? sledsCommand("statusline", o.home, o.env), slug));
|
|
24802
25556
|
writeSettings(o.home, statusLine.settings, env);
|
|
24803
|
-
wrote.push(finalWiring === "proxy-always" ? `set env.ANTHROPIC_BASE_URL and env.ANTHROPIC_AUTH_TOKEN in ${settingsPath(o.home, env)} (everything through the proxy)` : `left Claude Code on your seat (no ANTHROPIC_BASE_URL in ${settingsPath(o.home, env)}); \`sleds on\` switches to the proxy at a wall`);
|
|
25557
|
+
wrote.push(finalWiring === "proxy-always" ? `set env.ANTHROPIC_BASE_URL and env.ANTHROPIC_AUTH_TOKEN in ${settingsPath(o.home, env)} (everything through the proxy${gateway ? "; your own gateway is kept for `sleds off` and uninstall" : ""})` : gateway ? `left your own ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN in ${settingsPath(o.home, env)} as they were; \`sleds on\` switches to the proxy at a wall` : `left Claude Code on your seat (no ANTHROPIC_BASE_URL in ${settingsPath(o.home, env)}); \`sleds on\` switches to the proxy at a wall`);
|
|
24804
25558
|
wrote.push(statusLine.prior === undefined ? `set statusLine in ${settingsPath(o.home, env)}` : `set statusLine in ${settingsPath(o.home, env)} (previous one kept for uninstall)`);
|
|
24805
25559
|
hooks2({
|
|
24806
25560
|
home: o.home,
|
|
@@ -24819,12 +25573,12 @@ var init = async (o) => {
|
|
|
24819
25573
|
writeTokenFile(o.home, resolved.token);
|
|
24820
25574
|
wrote.push(`saved token to ${tokenPath(o.home)} (0600)`);
|
|
24821
25575
|
}
|
|
24822
|
-
const prior = readConfig(o.home);
|
|
24823
25576
|
const base = {
|
|
24824
25577
|
...prior,
|
|
24825
25578
|
proxyUrl: url,
|
|
24826
25579
|
agentKind: "claude-code",
|
|
24827
|
-
...statusLine.prior !== undefined ? { priorStatusLine: statusLine.prior } : {}
|
|
25580
|
+
...statusLine.prior !== undefined ? { priorStatusLine: statusLine.prior } : {},
|
|
25581
|
+
priorGatewayEnv
|
|
24828
25582
|
};
|
|
24829
25583
|
const email = seatInfo.email ?? resolved.approved?.email;
|
|
24830
25584
|
const asked = orgChoice(prior, o.org, env);
|
|
@@ -24978,8 +25732,9 @@ var login = async (o) => {
|
|
|
24978
25732
|
// src/commands/logout.ts
|
|
24979
25733
|
init_config();
|
|
24980
25734
|
init_state();
|
|
24981
|
-
import { existsSync as existsSync27, readFileSync as
|
|
25735
|
+
import { existsSync as existsSync27, readFileSync as readFileSync27, rmSync as rmSync16 } from "node:fs";
|
|
24982
25736
|
import { hostname as hostname10 } from "node:os";
|
|
25737
|
+
import { basename as basename8 } from "node:path";
|
|
24983
25738
|
init_settings();
|
|
24984
25739
|
var LOGOUT_USAGE = "usage: sleds logout [--org <slug>] [--json]";
|
|
24985
25740
|
function parseLogoutArgs(argv) {
|
|
@@ -25101,8 +25856,15 @@ async function logout(o) {
|
|
|
25101
25856
|
if (!name)
|
|
25102
25857
|
continue;
|
|
25103
25858
|
if (!e.org) {
|
|
25104
|
-
|
|
25105
|
-
|
|
25859
|
+
const exec = o.exec ?? defaultExec2;
|
|
25860
|
+
if (e.manager === "systemd") {
|
|
25861
|
+
exec("systemctl", ["--user", "disable", "--now", basename8(e.plist)]);
|
|
25862
|
+
rmSync16(e.plist, { force: true });
|
|
25863
|
+
exec("systemctl", ["--user", "daemon-reload"]);
|
|
25864
|
+
} else {
|
|
25865
|
+
exec("launchctl", ["unload", e.plist]);
|
|
25866
|
+
rmSync16(e.plist, { force: true });
|
|
25867
|
+
}
|
|
25106
25868
|
continue;
|
|
25107
25869
|
}
|
|
25108
25870
|
engineUninstall({
|
|
@@ -25135,7 +25897,7 @@ async function logout(o) {
|
|
|
25135
25897
|
};
|
|
25136
25898
|
writeConfig(o.home, next);
|
|
25137
25899
|
const tp = tokenPath(o.home, env);
|
|
25138
|
-
if (existsSync27(tp) &&
|
|
25900
|
+
if (existsSync27(tp) && readFileSync27(tp, "utf8").trim() === seat.token)
|
|
25139
25901
|
rmSync16(tp, { force: true });
|
|
25140
25902
|
const active = next.activeOrg ?? next.org?.slug ?? null;
|
|
25141
25903
|
const result = { ok: true, email, org: slug, paused, active };
|
|
@@ -25213,9 +25975,9 @@ var meter = async (o) => {
|
|
|
25213
25975
|
init_config();
|
|
25214
25976
|
init_meter();
|
|
25215
25977
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
25216
|
-
import { existsSync as existsSync28, mkdirSync as mkdirSync25, readFileSync as
|
|
25978
|
+
import { existsSync as existsSync28, mkdirSync as mkdirSync25, readFileSync as readFileSync28, rmSync as rmSync17, writeFileSync as writeFileSync24 } from "node:fs";
|
|
25217
25979
|
import { hostname as hostname11 } from "node:os";
|
|
25218
|
-
import { dirname as
|
|
25980
|
+
import { dirname as dirname22 } from "node:path";
|
|
25219
25981
|
var defaultWhich3 = (cmd) => {
|
|
25220
25982
|
const path = process.env.PATH ?? "";
|
|
25221
25983
|
for (const dir of path.split(":").filter(Boolean)) {
|
|
@@ -25253,7 +26015,7 @@ var musherInstall = (o) => {
|
|
|
25253
26015
|
const plist = musherPlistPath(o.home, env);
|
|
25254
26016
|
const label = musherLabel(env);
|
|
25255
26017
|
const dir = configDir(o.home, env);
|
|
25256
|
-
mkdirSync25(
|
|
26018
|
+
mkdirSync25(dirname22(plist), { recursive: true });
|
|
25257
26019
|
mkdirSync25(dir, { recursive: true, mode: 448 });
|
|
25258
26020
|
const execPath = o.sledsArgv[0] ?? process.execPath;
|
|
25259
26021
|
const agentEnv = {
|
|
@@ -25373,16 +26135,22 @@ var musherTick = async (o) => {
|
|
|
25373
26135
|
};
|
|
25374
26136
|
var musherConfigure = (o, flags) => {
|
|
25375
26137
|
const log = o.log ?? console.log;
|
|
26138
|
+
const error = o.error ?? console.error;
|
|
25376
26139
|
const cfg = readConfig(o.home);
|
|
25377
26140
|
const musher = { ...cfg.musher ?? {} };
|
|
25378
26141
|
if (flags.claude)
|
|
25379
26142
|
musher.claudePath = flags.claude;
|
|
25380
|
-
if (flags.mode)
|
|
26143
|
+
if (flags.mode) {
|
|
26144
|
+
if (!PERMISSION_MODES.includes(flags.mode)) {
|
|
26145
|
+
error(`--mode takes one of ${PERMISSION_MODES.join(", ")} (got ${flags.mode})`);
|
|
26146
|
+
return 1;
|
|
26147
|
+
}
|
|
25381
26148
|
musher.permissionMode = flags.mode;
|
|
26149
|
+
}
|
|
25382
26150
|
if (flags.timeout) {
|
|
25383
|
-
const n = Number
|
|
25384
|
-
if (!Number.
|
|
25385
|
-
|
|
26151
|
+
const n = /^\d+$/.test(flags.timeout) ? Number(flags.timeout) : Number.NaN;
|
|
26152
|
+
if (!Number.isSafeInteger(n) || n <= 0) {
|
|
26153
|
+
error("--timeout takes minutes, a positive whole number");
|
|
25386
26154
|
return 1;
|
|
25387
26155
|
}
|
|
25388
26156
|
musher.timeoutMinutes = n;
|
|
@@ -25397,22 +26165,38 @@ var defaultExecSync = (cmd, args) => {
|
|
|
25397
26165
|
return { ok: false, stderr: r.error.message };
|
|
25398
26166
|
return { ok: r.status === 0, stderr: r.stderr ?? "" };
|
|
25399
26167
|
};
|
|
25400
|
-
var
|
|
25401
|
-
|
|
26168
|
+
var MUSHER_SWITCHES2 = new Set(["install", "uninstall", "status"]);
|
|
26169
|
+
var MUSHER_SETTINGS2 = new Set(["claude", "mode", "timeout"]);
|
|
26170
|
+
var parseMusherArgs = (argv) => {
|
|
25402
26171
|
const flags = {};
|
|
25403
26172
|
const positional = [];
|
|
25404
|
-
for (let i = 0;i <
|
|
25405
|
-
const a =
|
|
25406
|
-
if (a.startsWith("--")) {
|
|
25407
|
-
const next = args[i + 1];
|
|
25408
|
-
if (next !== undefined && !next.startsWith("--")) {
|
|
25409
|
-
flags[a.slice(2)] = next;
|
|
25410
|
-
i++;
|
|
25411
|
-
} else
|
|
25412
|
-
flags[a.slice(2)] = "true";
|
|
25413
|
-
} else
|
|
26173
|
+
for (let i = 0;i < argv.length; i++) {
|
|
26174
|
+
const a = argv[i] ?? "";
|
|
26175
|
+
if (!a.startsWith("--")) {
|
|
25414
26176
|
positional.push(a);
|
|
26177
|
+
continue;
|
|
26178
|
+
}
|
|
26179
|
+
const eq = a.indexOf("=");
|
|
26180
|
+
const name = a.slice(2, eq < 0 ? undefined : eq);
|
|
26181
|
+
if (MUSHER_SWITCHES2.has(name) && eq < 0)
|
|
26182
|
+
flags[name] = "true";
|
|
26183
|
+
else if (MUSHER_SETTINGS2.has(name)) {
|
|
26184
|
+
const v = eq < 0 ? argv[++i] : a.slice(eq + 1);
|
|
26185
|
+
if (!v?.trim() || v.startsWith("--"))
|
|
26186
|
+
return { error: `--${name} needs a value` };
|
|
26187
|
+
flags[name] = v.trim();
|
|
26188
|
+
} else
|
|
26189
|
+
return { error: `unknown argument ${a}` };
|
|
26190
|
+
}
|
|
26191
|
+
return { flags, positional };
|
|
26192
|
+
};
|
|
26193
|
+
var musher3 = async (o) => {
|
|
26194
|
+
const parsed = parseMusherArgs(o.argv);
|
|
26195
|
+
if ("error" in parsed) {
|
|
26196
|
+
(o.error ?? console.error)(`sleds musher: ${parsed.error}`);
|
|
26197
|
+
return 1;
|
|
25415
26198
|
}
|
|
26199
|
+
const { flags, positional } = parsed;
|
|
25416
26200
|
if (flags.install)
|
|
25417
26201
|
return musherInstall(o);
|
|
25418
26202
|
if (flags.uninstall)
|
|
@@ -25430,13 +26214,24 @@ var musher3 = async (o) => {
|
|
|
25430
26214
|
// src/commands/off.ts
|
|
25431
26215
|
init_config();
|
|
25432
26216
|
init_settings();
|
|
26217
|
+
|
|
26218
|
+
// src/commands/init.ts
|
|
26219
|
+
init_config();
|
|
26220
|
+
init_state();
|
|
26221
|
+
init_settings();
|
|
26222
|
+
var DEFAULT_PROXY_URL2 = "https://proxy.sleds.ai";
|
|
26223
|
+
var lineReaders2 = new WeakMap;
|
|
26224
|
+
|
|
26225
|
+
// src/commands/off.ts
|
|
25433
26226
|
var off = (o) => {
|
|
25434
26227
|
const log = o.log ?? console.log;
|
|
25435
26228
|
const cfg = readConfig(o.home);
|
|
25436
26229
|
const settings = readSettings(o.home);
|
|
25437
|
-
const
|
|
25438
|
-
|
|
25439
|
-
|
|
26230
|
+
const proxyUrls = [cfg.proxyUrl, DEFAULT_PROXY_URL2];
|
|
26231
|
+
const pointed = isSledsProxyEnv(settings, proxyUrls);
|
|
26232
|
+
const wasOn = cfg.mode === "on" || pointed;
|
|
26233
|
+
if (pointed)
|
|
26234
|
+
writeSettings(o.home, switchOff(settings, cfg.priorEnv ?? cfg.priorGatewayEnv ?? {}));
|
|
25440
26235
|
if (o.scheduler)
|
|
25441
26236
|
cancelRevert(o.scheduler, cfg.schedule);
|
|
25442
26237
|
const next = {
|
|
@@ -25446,6 +26241,7 @@ var off = (o) => {
|
|
|
25446
26241
|
untilReset: undefined,
|
|
25447
26242
|
reason: undefined,
|
|
25448
26243
|
priorEnv: undefined,
|
|
26244
|
+
priorGatewayEnv: pointed && !cfg.priorEnv ? undefined : cfg.priorGatewayEnv,
|
|
25449
26245
|
schedule: undefined
|
|
25450
26246
|
};
|
|
25451
26247
|
writeConfig(o.home, next);
|
|
@@ -25460,15 +26256,6 @@ var off = (o) => {
|
|
|
25460
26256
|
// src/commands/on.ts
|
|
25461
26257
|
init_config();
|
|
25462
26258
|
init_settings();
|
|
25463
|
-
|
|
25464
|
-
// src/commands/init.ts
|
|
25465
|
-
init_config();
|
|
25466
|
-
init_state();
|
|
25467
|
-
init_settings();
|
|
25468
|
-
var DEFAULT_PROXY_URL2 = "https://proxy.sleds.ai";
|
|
25469
|
-
var lineReaders2 = new WeakMap;
|
|
25470
|
-
|
|
25471
|
-
// src/commands/on.ts
|
|
25472
26259
|
var on = (o) => {
|
|
25473
26260
|
const log = o.log ?? console.log;
|
|
25474
26261
|
const error = o.error ?? console.error;
|
|
@@ -25618,7 +26405,7 @@ var orgUse = (o) => {
|
|
|
25618
26405
|
writeTokenFile(o.home, seat.token);
|
|
25619
26406
|
if (existsSync29(settingsPath(o.home)) && cfg.mode !== "on") {
|
|
25620
26407
|
const settings = readSettings(o.home);
|
|
25621
|
-
const pointed = readProxy(settings);
|
|
26408
|
+
const pointed = isSledsProxyEnv(settings, [cfg.proxyUrl]) ? readProxy(settings) : null;
|
|
25622
26409
|
const url = pointed?.url ?? cfg.proxyUrl;
|
|
25623
26410
|
if (seat.wiring === "proxy-always" && url)
|
|
25624
26411
|
writeSettings(o.home, applyProxy(settings, { url, token: seat.token }));
|
|
@@ -25653,7 +26440,7 @@ var orgCmd = (o) => {
|
|
|
25653
26440
|
init_src();
|
|
25654
26441
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
25655
26442
|
import { writeFileSync as writeFileSync25 } from "node:fs";
|
|
25656
|
-
import { join as
|
|
26443
|
+
import { join as join31 } from "node:path";
|
|
25657
26444
|
function packFileName(key) {
|
|
25658
26445
|
return `pack-${slugify(key, 80) || "item"}.md`;
|
|
25659
26446
|
}
|
|
@@ -25681,7 +26468,7 @@ var packCmd = async (o) => {
|
|
|
25681
26468
|
log(r.text);
|
|
25682
26469
|
return 0;
|
|
25683
26470
|
}
|
|
25684
|
-
const path =
|
|
26471
|
+
const path = join31(o.cwd ?? process.cwd(), packFileName(key));
|
|
25685
26472
|
(o.write ?? ((p, t) => writeFileSync25(p, t.endsWith(`
|
|
25686
26473
|
`) ? t : `${t}
|
|
25687
26474
|
`)))(path, r.text);
|
|
@@ -25690,8 +26477,8 @@ var packCmd = async (o) => {
|
|
|
25690
26477
|
};
|
|
25691
26478
|
|
|
25692
26479
|
// src/commands/permissionEvent.ts
|
|
25693
|
-
import { chmodSync as chmodSync7, mkdirSync as mkdirSync26, readFileSync as
|
|
25694
|
-
import { dirname as
|
|
26480
|
+
import { chmodSync as chmodSync7, mkdirSync as mkdirSync26, readFileSync as readFileSync29, renameSync as renameSync12, rmSync as rmSync19, writeFileSync as writeFileSync26 } from "node:fs";
|
|
26481
|
+
import { dirname as dirname23 } from "node:path";
|
|
25695
26482
|
var isObject13 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
25696
26483
|
var messageOf = (text) => {
|
|
25697
26484
|
try {
|
|
@@ -25715,7 +26502,7 @@ var permissionEvent = async (o) => {
|
|
|
25715
26502
|
if (!isToolPermission2(message))
|
|
25716
26503
|
return 0;
|
|
25717
26504
|
const mark = { message, at: (o.now ?? Date.now)() };
|
|
25718
|
-
mkdirSync26(
|
|
26505
|
+
mkdirSync26(dirname23(o.mark), { recursive: true, mode: 448 });
|
|
25719
26506
|
const tmp = `${o.mark}.${process.pid}.tmp`;
|
|
25720
26507
|
writeFileSync26(tmp, `${JSON.stringify(mark)}
|
|
25721
26508
|
`, { mode: 384 });
|
|
@@ -25762,6 +26549,7 @@ var exitsLine = (hasUpstreamKey) => hasUpstreamKey ? "`/sled handoff <what you w
|
|
|
25762
26549
|
var approachingContext = (bar, usedPct, resetsAt, hasUpstreamKey, now) => `[SLEDS] This seat is at ${usedPct !== undefined ? `${Math.round(usedPct)}%` : "90%+"} of its ${LABEL[bar]} limit; it resets in ${fmtIn(resetsAt - now)}. Tell the user in one short line before you answer, and offer the exits: ${exitsLine(hasUpstreamKey)} Do not mention this again unless asked.`;
|
|
25763
26550
|
var hitContext = (bar, resetsAt, hasUpstreamKey, now) => `[SLEDS] This seat hit its ${LABEL[bar]} limit; it resets in ${fmtIn(resetsAt - now)}. If this reply fails or the user is stuck, the exits are: ${exitsLine(hasUpstreamKey)} Say so in one line.`;
|
|
25764
26551
|
var creditsBlockText = (hasUpstreamKey) => `SLEDS: this seat is out of usage credits — the next reply would fail, so this prompt was not sent. ${hasUpstreamKey ? "Exits: /sled handoff <task> (a buddy picks it up), sleds on (continue on the workspace's platform key), or /model to a cheaper model." : "Exits: /sled handoff <task> (a buddy picks it up), sleds defer (resume when credits are topped up), or /model to a cheaper model."} Re-send your prompt after choosing; SLEDS will not block again.`;
|
|
26552
|
+
var creditsContext = (hasUpstreamKey) => `[SLEDS] This seat is out of usage credits; this reply may fail. Tell the user in one short line, and offer the exits: ${exitsLine(hasUpstreamKey)}`;
|
|
25765
26553
|
var promptEvent = async (o) => {
|
|
25766
26554
|
const log = o.log ?? console.log;
|
|
25767
26555
|
const error = o.error ?? console.error;
|
|
@@ -25784,27 +26572,35 @@ var promptEvent = async (o) => {
|
|
|
25784
26572
|
const mark = (bar, stage, at) => {
|
|
25785
26573
|
told[bar] = { ...told[bar] ?? {}, [stage]: at };
|
|
25786
26574
|
};
|
|
25787
|
-
|
|
26575
|
+
for (const e of pending)
|
|
26576
|
+
mark(e.bar, e.stage, e.resetsAt);
|
|
26577
|
+
let saved = true;
|
|
26578
|
+
try {
|
|
26579
|
+
writeSeatState(o.home, { ...state, told }, key);
|
|
26580
|
+
} catch {
|
|
26581
|
+
saved = false;
|
|
26582
|
+
}
|
|
26583
|
+
let block = false;
|
|
25788
26584
|
const lines = [];
|
|
25789
26585
|
for (const e of pending) {
|
|
25790
|
-
mark(e.bar, e.stage, e.resetsAt);
|
|
25791
26586
|
if (e.bar === "credits") {
|
|
25792
|
-
if (
|
|
25793
|
-
|
|
25794
|
-
|
|
25795
|
-
|
|
26587
|
+
if (saved)
|
|
26588
|
+
block = true;
|
|
26589
|
+
else
|
|
26590
|
+
lines.push(creditsContext(hasKey));
|
|
25796
26591
|
continue;
|
|
25797
26592
|
}
|
|
25798
26593
|
const pct = state.window?.[e.bar]?.usedPct;
|
|
25799
26594
|
lines.push(e.stage === "approaching" ? approachingContext(e.bar, pct, e.resetsAt, hasKey, now) : hitContext(e.bar, e.resetsAt, hasKey, now));
|
|
25800
26595
|
}
|
|
25801
|
-
|
|
25802
|
-
|
|
25803
|
-
|
|
25804
|
-
|
|
26596
|
+
if (block) {
|
|
26597
|
+
error(creditsBlockText(hasKey));
|
|
26598
|
+
return 2;
|
|
26599
|
+
}
|
|
26600
|
+
if (lines.length > 0)
|
|
25805
26601
|
log(lines.join(`
|
|
25806
26602
|
`));
|
|
25807
|
-
return
|
|
26603
|
+
return 0;
|
|
25808
26604
|
};
|
|
25809
26605
|
|
|
25810
26606
|
// src/commands/reopen.ts
|
|
@@ -25878,13 +26674,14 @@ async function reopenCmd(o) {
|
|
|
25878
26674
|
|
|
25879
26675
|
// src/commands/route.ts
|
|
25880
26676
|
init_src();
|
|
25881
|
-
import { readFileSync as
|
|
26677
|
+
import { readFileSync as readFileSync30 } from "node:fs";
|
|
25882
26678
|
import { hostname as hostname12 } from "node:os";
|
|
25883
26679
|
var ARM_USAGE = "usage: sleds route arm <key> [--off] [--json] [--name <engine>] [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--mode <permission-mode>] [--model <id>] [--effort <e>] [--branch '<template>'] [--pr-title '<template>'] [--repos-dir <dir>]";
|
|
25884
|
-
var USAGE2 = "usage: sleds route <key> [--long | --dot | --json] | sleds route arm <key> [--off] [--json] | sleds route answer <key>/<node> --stdin | sleds route propose <key> --file <nodes.json> | sleds route approve <key> | sleds route redraft <key> | sleds route single <key> | sleds route elsewhere <key> [--note <text>] | sleds route decisions [<key>] [--flagged] | sleds route decision <key> <id> --seen | --answer --stdin [--route accept|keep|redraft] | --keep-route | --apply [--answer --stdin] | --overrule --stdin | --ready | sleds route run <key> [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--interval <s>] [--lease <min>] [--idle <min>] [--repo <path>] [--repos-dir <dir>] [--mode <permission-mode>] [--model <id>] [--branch '<template>'] [--pr-title '<template>'] [--once]";
|
|
26680
|
+
var USAGE2 = "usage: sleds route <key> [--long | --dot | --json] | sleds route arm <key> [--off] [--json] | sleds route answer <key>/<node> --stdin | sleds route instruct <key>/<node> --stdin [--voice] | sleds route propose <key> --file <nodes.json> | sleds route approve <key> [--voice --stdin] | sleds route redraft <key> | sleds route single <key> | sleds route elsewhere <key> [--note <text>] | sleds route decisions [<key>] [--flagged] | sleds route decision <key> <id> --seen | --answer --stdin [--route accept|keep|redraft] | --keep-route | --apply [--answer --stdin] | --overrule --stdin | --ready | sleds route run <key> [--at-once <n>] [--runner tmux|headless|command|orca|cmux] [--runner-cmd '<launcher>'] [--agent '<command>'] [--interval <s>] [--lease <min>] [--idle <min>] [--repo <path>] [--repos-dir <dir>] [--mode <permission-mode>] [--model <id>] [--branch '<template>'] [--pr-title '<template>'] [--once]";
|
|
25885
26681
|
var ANSWER_USAGE = "usage: sleds route answer <key>/<node> <answer…> | sleds route answer <key>/<node> --stdin [--json]";
|
|
26682
|
+
var INSTRUCT_USAGE = "usage: sleds route instruct <key>/<node> <instruction…> | sleds route instruct <key>/<node> --stdin [--voice] [--json]";
|
|
25886
26683
|
var PROPOSE_USAGE = "usage: sleds route propose <key> (--file <nodes.json> | --stdin) [--name <engine>] [--json]";
|
|
25887
|
-
var APPROVE_USAGE = "usage: sleds route approve <key> [--file <nodes.json>] [--json]";
|
|
26684
|
+
var APPROVE_USAGE = "usage: sleds route approve <key> [--file <nodes.json>] [--voice --stdin] [--json]";
|
|
25888
26685
|
var REDRAFT_USAGE = "usage: sleds route redraft <key> [--json]";
|
|
25889
26686
|
var SINGLE_USAGE = "usage: sleds route single <key> [--json]";
|
|
25890
26687
|
var ELSEWHERE_USAGE = "usage: sleds route elsewhere <key> [--note <text>] [--json]";
|
|
@@ -25933,6 +26730,10 @@ function parseVerbArgs(argv, allowed) {
|
|
|
25933
26730
|
out[flag] = true;
|
|
25934
26731
|
continue;
|
|
25935
26732
|
}
|
|
26733
|
+
if (flag === "voice") {
|
|
26734
|
+
out.voice = true;
|
|
26735
|
+
continue;
|
|
26736
|
+
}
|
|
25936
26737
|
const value = argv[i + 1];
|
|
25937
26738
|
if (value === undefined || value.startsWith("--"))
|
|
25938
26739
|
return { error: `${a} needs a value` };
|
|
@@ -26056,7 +26857,7 @@ async function answerCmd(o, argv) {
|
|
|
26056
26857
|
const words = argv.filter((a) => a !== "--json" && a !== "--stdin");
|
|
26057
26858
|
const ref = words[0] ?? "";
|
|
26058
26859
|
const slash = ref.lastIndexOf("/");
|
|
26059
|
-
const answer = (fromStdin ? (o.stdin ?? (() =>
|
|
26860
|
+
const answer = (fromStdin ? (o.stdin ?? (() => readFileSync30(0, "utf8")))() : words.slice(1).join(" ")).trim();
|
|
26060
26861
|
if (slash <= 0 || slash === ref.length - 1 || fromStdin && words.length > 1) {
|
|
26061
26862
|
error(ANSWER_USAGE);
|
|
26062
26863
|
return 2;
|
|
@@ -26088,6 +26889,59 @@ async function answerCmd(o, argv) {
|
|
|
26088
26889
|
log(r.json?.state === "answered" ? `${ref}: its landing is answered — the nodes it held are released` : `${ref} answered — back to ready; the engine takes it on its next check`);
|
|
26089
26890
|
return 0;
|
|
26090
26891
|
}
|
|
26892
|
+
async function instructCmd(o, argv) {
|
|
26893
|
+
const log = o.log ?? console.log;
|
|
26894
|
+
const error = o.error ?? console.error;
|
|
26895
|
+
const json = argv.includes("--json");
|
|
26896
|
+
const fromStdin = argv.includes("--stdin");
|
|
26897
|
+
const voice = argv.includes("--voice");
|
|
26898
|
+
const words = argv.filter((a) => a !== "--json" && a !== "--stdin" && a !== "--voice");
|
|
26899
|
+
const ref = words[0] ?? "";
|
|
26900
|
+
const slash = ref.lastIndexOf("/");
|
|
26901
|
+
if (slash <= 0 || slash === ref.length - 1 || fromStdin && words.length > 1 || voice && !fromStdin || words.some((w) => w.startsWith("--"))) {
|
|
26902
|
+
error(INSTRUCT_USAGE);
|
|
26903
|
+
return 2;
|
|
26904
|
+
}
|
|
26905
|
+
const text = fromStdin ? (o.stdin ?? (() => readFileSync30(0, "utf8")))() : words.slice(1).join(" ");
|
|
26906
|
+
const { md, heard } = voice ? splitVoiceStdin(text) : { md: text.trim(), heard: undefined };
|
|
26907
|
+
if (!md) {
|
|
26908
|
+
error("an instruction needs some text");
|
|
26909
|
+
return 2;
|
|
26910
|
+
}
|
|
26911
|
+
const client = engineClient(o);
|
|
26912
|
+
if ("error" in client) {
|
|
26913
|
+
error(client.error);
|
|
26914
|
+
return 1;
|
|
26915
|
+
}
|
|
26916
|
+
const r = await client.postFull("/proxy/route/instruct", {
|
|
26917
|
+
project: ref,
|
|
26918
|
+
md,
|
|
26919
|
+
...heard !== undefined ? { voice: { heard } } : {}
|
|
26920
|
+
});
|
|
26921
|
+
if (!r) {
|
|
26922
|
+
error(`${ref}: SLEDS unreachable — nothing sent`);
|
|
26923
|
+
return 1;
|
|
26924
|
+
}
|
|
26925
|
+
const ok = r.status < 300 && r.json?.ok !== false;
|
|
26926
|
+
if (json)
|
|
26927
|
+
log(JSON.stringify(r.json ?? { ok: false, error: `HTTP ${r.status}` }));
|
|
26928
|
+
if (!ok) {
|
|
26929
|
+
const why = typeof r.json?.error === "string" ? r.json.error : `HTTP ${r.status}`;
|
|
26930
|
+
if (!json)
|
|
26931
|
+
error(`${ref}: ${why}`);
|
|
26932
|
+
return 1;
|
|
26933
|
+
}
|
|
26934
|
+
if (!json)
|
|
26935
|
+
log(`${ref} instructed — the engine following its PR hands it to the session`);
|
|
26936
|
+
return 0;
|
|
26937
|
+
}
|
|
26938
|
+
function splitVoiceStdin(text) {
|
|
26939
|
+
const nl = text.indexOf(`
|
|
26940
|
+
`);
|
|
26941
|
+
const md = (nl < 0 ? text : text.slice(0, nl)).trim();
|
|
26942
|
+
const rest = nl < 0 ? "" : text.slice(nl + 1).trim();
|
|
26943
|
+
return { md, heard: rest || md };
|
|
26944
|
+
}
|
|
26091
26945
|
async function proposeCmd(o, argv) {
|
|
26092
26946
|
const log = o.log ?? console.log;
|
|
26093
26947
|
const error = o.error ?? console.error;
|
|
@@ -26135,12 +26989,13 @@ async function proposeCmd(o, argv) {
|
|
|
26135
26989
|
async function approveCmd(o, argv) {
|
|
26136
26990
|
const log = o.log ?? console.log;
|
|
26137
26991
|
const error = o.error ?? console.error;
|
|
26138
|
-
const a = parseVerbArgs(argv, ["file", "json"]);
|
|
26139
|
-
if ("error" in a) {
|
|
26140
|
-
error(a.error);
|
|
26992
|
+
const a = parseVerbArgs(argv, ["file", "json", "voice", "stdin"]);
|
|
26993
|
+
if ("error" in a || Boolean(a.voice) !== a.stdin) {
|
|
26994
|
+
error("error" in a ? a.error : "--voice and --stdin go together: stdin is what was heard");
|
|
26141
26995
|
error(APPROVE_USAGE);
|
|
26142
26996
|
return 2;
|
|
26143
26997
|
}
|
|
26998
|
+
const heard = a.voice ? (o.stdin ?? (() => readFileSync30(0, "utf8")))().trim() : undefined;
|
|
26144
26999
|
let nodes;
|
|
26145
27000
|
let approach;
|
|
26146
27001
|
if (a.file) {
|
|
@@ -26160,7 +27015,8 @@ async function approveCmd(o, argv) {
|
|
|
26160
27015
|
const r = await client.postFull("/proxy/route/approve", {
|
|
26161
27016
|
project: a.key,
|
|
26162
27017
|
...nodes ? { nodes } : {},
|
|
26163
|
-
...approach ? { approach } : {}
|
|
27018
|
+
...approach ? { approach } : {},
|
|
27019
|
+
...heard !== undefined ? { voice: { heard } } : {}
|
|
26164
27020
|
});
|
|
26165
27021
|
if (!r) {
|
|
26166
27022
|
error(`${a.key}: SLEDS unreachable — nothing approved`);
|
|
@@ -26262,7 +27118,7 @@ async function decisionCmd(o, argv) {
|
|
|
26262
27118
|
error(DECISION_USAGE);
|
|
26263
27119
|
return 2;
|
|
26264
27120
|
}
|
|
26265
|
-
const md = seen || routeAlone ? "" : (fromStdin ? (o.stdin ?? (() =>
|
|
27121
|
+
const md = seen || routeAlone ? "" : (fromStdin ? (o.stdin ?? (() => readFileSync30(0, "utf8")))() : rest.join(" ")).trim();
|
|
26266
27122
|
if (!seen && !routeAlone && (!md || fromStdin && rest.length > 0)) {
|
|
26267
27123
|
error(md ? DECISION_USAGE : `${answer ? "an answer" : "an overrule"} needs some text`);
|
|
26268
27124
|
return 2;
|
|
@@ -26441,7 +27297,7 @@ function approvedLine(key, j) {
|
|
|
26441
27297
|
function readNodes(o, a) {
|
|
26442
27298
|
let text;
|
|
26443
27299
|
try {
|
|
26444
|
-
text = a.file ? (o.readFile ?? ((p) =>
|
|
27300
|
+
text = a.file ? (o.readFile ?? ((p) => readFileSync30(p, "utf8")))(a.file) : (o.stdin ?? (() => readFileSync30(0, "utf8")))();
|
|
26445
27301
|
} catch (e) {
|
|
26446
27302
|
return { error: e instanceof Error ? e.message : String(e) };
|
|
26447
27303
|
}
|
|
@@ -26470,6 +27326,8 @@ var routeCmd = async (o) => {
|
|
|
26470
27326
|
return armCmd(o, o.argv.slice(1));
|
|
26471
27327
|
if (o.argv[0] === "answer")
|
|
26472
27328
|
return answerCmd(o, o.argv.slice(1));
|
|
27329
|
+
if (o.argv[0] === "instruct")
|
|
27330
|
+
return instructCmd(o, o.argv.slice(1));
|
|
26473
27331
|
if (o.argv[0] === "propose")
|
|
26474
27332
|
return proposeCmd(o, o.argv.slice(1));
|
|
26475
27333
|
if (o.argv[0] === "approve")
|
|
@@ -26796,8 +27654,11 @@ var seatEvent = async (o) => {
|
|
|
26796
27654
|
if (week && week.resetsAt > now)
|
|
26797
27655
|
writeSeatState(o.home, { ...state, lastWallResetsAt: week.resetsAt }, key);
|
|
26798
27656
|
} catch {}
|
|
26799
|
-
|
|
26800
|
-
|
|
27657
|
+
let hasKey = true;
|
|
27658
|
+
try {
|
|
27659
|
+
hasKey = readConfig(o.home).org?.capabilities.upstreamKey !== false;
|
|
27660
|
+
} catch {}
|
|
27661
|
+
log(seatWallLine(hasKey));
|
|
26801
27662
|
return 0;
|
|
26802
27663
|
};
|
|
26803
27664
|
|
|
@@ -26873,14 +27734,14 @@ async function seatRevokeCmd(o) {
|
|
|
26873
27734
|
|
|
26874
27735
|
// src/commands/seatSync.ts
|
|
26875
27736
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
26876
|
-
import { existsSync as existsSync30, mkdirSync as mkdirSync27, readFileSync as
|
|
27737
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync27, readFileSync as readFileSync31, readdirSync as readdirSync7, rmSync as rmSync21, writeFileSync as writeFileSync27 } from "node:fs";
|
|
26877
27738
|
import { platform as platform2 } from "node:os";
|
|
26878
|
-
import { dirname as
|
|
27739
|
+
import { dirname as dirname24, join as join33 } from "node:path";
|
|
26879
27740
|
|
|
26880
27741
|
// src/cookieDb.ts
|
|
26881
27742
|
import { copyFileSync as copyFileSync3, rmSync as rmSync20 } from "node:fs";
|
|
26882
|
-
import { tmpdir as
|
|
26883
|
-
import { join as
|
|
27743
|
+
import { tmpdir as tmpdir4 } from "node:os";
|
|
27744
|
+
import { join as join32 } from "node:path";
|
|
26884
27745
|
var QUERY = "SELECT name, hex(encrypted_value) AS ev FROM cookies WHERE host_key LIKE '%claude.ai%'";
|
|
26885
27746
|
var isBun = () => typeof globalThis.Bun !== "undefined";
|
|
26886
27747
|
async function queryRows(dbPath) {
|
|
@@ -26909,7 +27770,7 @@ function nodeSqlite() {
|
|
|
26909
27770
|
return mod;
|
|
26910
27771
|
}
|
|
26911
27772
|
async function readCookieRows(dbPath) {
|
|
26912
|
-
const copy =
|
|
27773
|
+
const copy = join32(tmpdir4(), `sleds-cookies-${process.pid}-${Date.now()}.sqlite`);
|
|
26913
27774
|
copyFileSync3(dbPath, copy);
|
|
26914
27775
|
try {
|
|
26915
27776
|
const rows = await queryRows(copy);
|
|
@@ -27202,7 +28063,7 @@ function findFile(root, name) {
|
|
|
27202
28063
|
continue;
|
|
27203
28064
|
}
|
|
27204
28065
|
for (const e of entries) {
|
|
27205
|
-
const p =
|
|
28066
|
+
const p = join33(dir, e.name);
|
|
27206
28067
|
if (e.isDirectory())
|
|
27207
28068
|
stack.push(p);
|
|
27208
28069
|
else if (e.name === name)
|
|
@@ -27213,7 +28074,7 @@ function findFile(root, name) {
|
|
|
27213
28074
|
}
|
|
27214
28075
|
function findCookieDb(home, source) {
|
|
27215
28076
|
const b = BROWSERS[source.browser];
|
|
27216
|
-
const root =
|
|
28077
|
+
const root = join33(home, APP_SUPPORT, b.appDir);
|
|
27217
28078
|
if (!existsSync30(root))
|
|
27218
28079
|
throw new Error(`no ${source.browser} data at ${root} (is it installed?)`);
|
|
27219
28080
|
if (!b.profiled) {
|
|
@@ -27222,15 +28083,15 @@ function findCookieDb(home, source) {
|
|
|
27222
28083
|
throw new Error(`no cookie store under ${root}`);
|
|
27223
28084
|
return db;
|
|
27224
28085
|
}
|
|
27225
|
-
const localStatePath =
|
|
27226
|
-
const localState = existsSync30(localStatePath) ?
|
|
28086
|
+
const localStatePath = join33(root, "Local State");
|
|
28087
|
+
const localState = existsSync30(localStatePath) ? readFileSync31(localStatePath, "utf8") : null;
|
|
27227
28088
|
const wanted = source.profile ?? "Default";
|
|
27228
28089
|
const { dir, ambiguous } = resolveProfileDir(localState, wanted);
|
|
27229
28090
|
if (ambiguous)
|
|
27230
28091
|
throw new Error(`"${wanted}" names ${ambiguous.length} ${source.browser} profiles (${ambiguous.join(", ")}) — pass the directory or the account email instead`);
|
|
27231
28092
|
if (!dir)
|
|
27232
28093
|
throw new Error(`no ${source.browser} profile named "${wanted}" (check chrome://version)`);
|
|
27233
|
-
const db = cookieDbCandidates(
|
|
28094
|
+
const db = cookieDbCandidates(join33(root, dir)).find((p) => existsSync30(p));
|
|
27234
28095
|
if (!db)
|
|
27235
28096
|
throw new Error(`profile "${dir}" has no cookie store yet (open claude.ai in it once)`);
|
|
27236
28097
|
return db;
|
|
@@ -27274,7 +28135,7 @@ function fetchSeatUsage(jar, org, now, run) {
|
|
|
27274
28135
|
}
|
|
27275
28136
|
function launchAgentPlist(argv, home, source) {
|
|
27276
28137
|
const label = launchLabel(source);
|
|
27277
|
-
const log =
|
|
28138
|
+
const log = join33(home, ".config", "sleds", `${label.slice("ai.sleds.".length)}.log`);
|
|
27278
28139
|
const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
27279
28140
|
const args = [...argv, "seat-sync", ...sourceArgs(source)].map((a) => ` <string>${esc(a)}</string>`).join(`
|
|
27280
28141
|
`);
|
|
@@ -27296,20 +28157,20 @@ ${args}
|
|
|
27296
28157
|
`;
|
|
27297
28158
|
}
|
|
27298
28159
|
function plistPath2(home, source) {
|
|
27299
|
-
return
|
|
28160
|
+
return join33(home, "Library", "LaunchAgents", `${launchLabel(source)}.plist`);
|
|
27300
28161
|
}
|
|
27301
28162
|
function install(home, argv, source, log, launchctl) {
|
|
27302
28163
|
if (!argv[0]) {
|
|
27303
28164
|
log("cannot resolve the sleds command to install the timer");
|
|
27304
28165
|
return 1;
|
|
27305
28166
|
}
|
|
27306
|
-
const dir =
|
|
28167
|
+
const dir = join33(home, "Library", "LaunchAgents");
|
|
27307
28168
|
mkdirSync27(dir, { recursive: true });
|
|
27308
28169
|
const path = plistPath2(home, source);
|
|
27309
28170
|
const tokenPath = seatTokenPath(home, source);
|
|
27310
28171
|
rmSync21(tokenPath, { force: true });
|
|
27311
28172
|
if (source.token) {
|
|
27312
|
-
mkdirSync27(
|
|
28173
|
+
mkdirSync27(dirname24(tokenPath), { recursive: true, mode: 448 });
|
|
27313
28174
|
writeFileSync27(tokenPath, `${source.token}
|
|
27314
28175
|
`, { mode: 384 });
|
|
27315
28176
|
}
|
|
@@ -27390,10 +28251,12 @@ var seatSync = async (o) => {
|
|
|
27390
28251
|
log(`seat-sync: usage read failed — ${why}`);
|
|
27391
28252
|
return 2;
|
|
27392
28253
|
}
|
|
27393
|
-
|
|
27394
|
-
|
|
27395
|
-
|
|
27396
|
-
|
|
28254
|
+
if (token === saved?.token) {
|
|
28255
|
+
try {
|
|
28256
|
+
const key = seatKeyFor(o.home, process.env);
|
|
28257
|
+
writeSeatState(o.home, { ...readSeatState(o.home, key), window: usageAsWindow(usage) }, key);
|
|
28258
|
+
} catch {}
|
|
28259
|
+
}
|
|
27397
28260
|
const posted = await postSeat(proxyUrl, token, seatSyncBody(usage), o.fetchFn ?? fetch);
|
|
27398
28261
|
const wk = usage.sevenDay ? `wk ${Math.round(usage.sevenDay.usedPct)}%` : "wk —";
|
|
27399
28262
|
const models = Object.keys(usage.models).length;
|
|
@@ -27403,7 +28266,7 @@ var seatSync = async (o) => {
|
|
|
27403
28266
|
};
|
|
27404
28267
|
function readSeatToken(home, source) {
|
|
27405
28268
|
try {
|
|
27406
|
-
return
|
|
28269
|
+
return readFileSync31(seatTokenPath(home, source), "utf8").trim() || undefined;
|
|
27407
28270
|
} catch {
|
|
27408
28271
|
return;
|
|
27409
28272
|
}
|
|
@@ -27486,8 +28349,8 @@ var sessionEvent = async (o) => {
|
|
|
27486
28349
|
|
|
27487
28350
|
// src/commands/specEvent.ts
|
|
27488
28351
|
init_meter();
|
|
27489
|
-
import { readFileSync as
|
|
27490
|
-
import { basename as
|
|
28352
|
+
import { readFileSync as readFileSync32, statSync as statSync8 } from "node:fs";
|
|
28353
|
+
import { basename as basename9, isAbsolute as isAbsolute7, relative as relative2 } from "node:path";
|
|
27491
28354
|
var HOOK_STDIN_TIMEOUT_MS3 = 1000;
|
|
27492
28355
|
var ESTIMATE_TIMEOUT_MS = 4000;
|
|
27493
28356
|
var MIN_SPEC_CHARS = 200;
|
|
@@ -27500,12 +28363,12 @@ function isSpecPath(path) {
|
|
|
27500
28363
|
return false;
|
|
27501
28364
|
if (NOT_SPEC.test(path))
|
|
27502
28365
|
return false;
|
|
27503
|
-
return SPEC_DIRS.test(path) || SPEC_NAMES.test(
|
|
28366
|
+
return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename9(path));
|
|
27504
28367
|
}
|
|
27505
28368
|
function specTitle(body, path) {
|
|
27506
28369
|
const m = /^#\s+(.+?)\s*$/m.exec(body);
|
|
27507
28370
|
const t = m?.[1]?.trim();
|
|
27508
|
-
return (t && t.length > 0 ? t :
|
|
28371
|
+
return (t && t.length > 0 ? t : basename9(path).replace(/\.(md|mdx)$/i, "")).slice(0, 120);
|
|
27509
28372
|
}
|
|
27510
28373
|
function looksLikeSpec(body) {
|
|
27511
28374
|
if (body.trim().length < MIN_SPEC_CHARS)
|
|
@@ -27540,9 +28403,9 @@ function projectKey(filePath, cwd) {
|
|
|
27540
28403
|
}
|
|
27541
28404
|
function readFileOrNull(path) {
|
|
27542
28405
|
try {
|
|
27543
|
-
if (
|
|
28406
|
+
if (statSync8(path).size > 2000000)
|
|
27544
28407
|
return null;
|
|
27545
|
-
return
|
|
28408
|
+
return readFileSync32(path, "utf8");
|
|
27546
28409
|
} catch {
|
|
27547
28410
|
return null;
|
|
27548
28411
|
}
|
|
@@ -27553,7 +28416,12 @@ var specEvent = async (o) => {
|
|
|
27553
28416
|
const input = raw ? parseHookInput(raw) : null;
|
|
27554
28417
|
if (!input || !isSpecPath(input.filePath))
|
|
27555
28418
|
return 0;
|
|
27556
|
-
|
|
28419
|
+
let src;
|
|
28420
|
+
try {
|
|
28421
|
+
src = meterSource(o.home);
|
|
28422
|
+
} catch {
|
|
28423
|
+
return 0;
|
|
28424
|
+
}
|
|
27557
28425
|
if (!src)
|
|
27558
28426
|
return 0;
|
|
27559
28427
|
const body = (o.readFile ?? readFileOrNull)(input.filePath);
|
|
@@ -27563,7 +28431,7 @@ var specEvent = async (o) => {
|
|
|
27563
28431
|
const spec = {
|
|
27564
28432
|
title: specTitle(body, input.filePath),
|
|
27565
28433
|
body: body.slice(0, MAX_SPEC_CHARS),
|
|
27566
|
-
repoHint: input.cwd ?
|
|
28434
|
+
repoHint: input.cwd ? basename9(input.cwd) : undefined
|
|
27567
28435
|
};
|
|
27568
28436
|
try {
|
|
27569
28437
|
const res = await (o.fetchFn ?? fetch)(`${src.proxyUrl}/proxy/estimate`, {
|
|
@@ -27759,7 +28627,6 @@ var status3 = async (o) => {
|
|
|
27759
28627
|
};
|
|
27760
28628
|
|
|
27761
28629
|
// src/commands/statusline.ts
|
|
27762
|
-
init_config();
|
|
27763
28630
|
init_meter();
|
|
27764
28631
|
var statusline = async (o) => {
|
|
27765
28632
|
const log = o.log ?? console.log;
|
|
@@ -27798,7 +28665,8 @@ var statusline = async (o) => {
|
|
|
27798
28665
|
home: o.home,
|
|
27799
28666
|
now,
|
|
27800
28667
|
fetchFn: o.fetchFn,
|
|
27801
|
-
timeoutMs: o.timeoutMs
|
|
28668
|
+
timeoutMs: o.timeoutMs,
|
|
28669
|
+
env: o.env
|
|
27802
28670
|
});
|
|
27803
28671
|
line = formatMeterLine(meter, now, seatFragment);
|
|
27804
28672
|
} catch {
|
|
@@ -27817,9 +28685,9 @@ var speakToCockpit = async (o, key, window, events, now) => {
|
|
|
27817
28685
|
try {
|
|
27818
28686
|
const st = readSeatState(o.home, key);
|
|
27819
28687
|
let feed;
|
|
27820
|
-
const src = meterSource(o.home);
|
|
28688
|
+
const src = meterSource(o.home, undefined, { env: o.env });
|
|
27821
28689
|
if (src && now - (st.cockpit?.feed?.at ?? 0) >= FEED_MIN_INTERVAL_MS) {
|
|
27822
|
-
const got = await fetchFeed({ ...src, email:
|
|
28690
|
+
const got = await fetchFeed({ ...src, email: key.email ?? undefined, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs }, now);
|
|
27823
28691
|
if (got)
|
|
27824
28692
|
feed = got;
|
|
27825
28693
|
}
|
|
@@ -27832,13 +28700,13 @@ var speakToCockpit = async (o, key, window, events, now) => {
|
|
|
27832
28700
|
return;
|
|
27833
28701
|
writeSeatState(o.home, { ...readSeatState(o.home, key), cockpit: r.state }, key);
|
|
27834
28702
|
if (r.argv.length)
|
|
27835
|
-
await runCockpit(cockpit, r.argv, {
|
|
28703
|
+
await runCockpit(cockpit, r.argv, { exec: o.exec });
|
|
27836
28704
|
} catch {}
|
|
27837
28705
|
};
|
|
27838
28706
|
var rememberSeat = (o, key, window, session, now, input) => {
|
|
27839
28707
|
const prior = readSeatState(o.home, key);
|
|
27840
28708
|
let state = { ...prior, window, ...session ? { session } : {} };
|
|
27841
|
-
const src = meterSource(o.home);
|
|
28709
|
+
const src = meterSource(o.home, undefined, { env: o.env });
|
|
27842
28710
|
const posts = [];
|
|
27843
28711
|
if (src && shouldPostSeat(prior, window, now)) {
|
|
27844
28712
|
state = markPosted(state, window, now);
|
|
@@ -27868,7 +28736,7 @@ var creditsEvent = (o, prior, input, now) => {
|
|
|
27868
28736
|
var announce = (o, events) => {
|
|
27869
28737
|
if (events.length === 0)
|
|
27870
28738
|
return [];
|
|
27871
|
-
const src = meterSource(o.home);
|
|
28739
|
+
const src = meterSource(o.home, undefined, { env: o.env });
|
|
27872
28740
|
if (!src)
|
|
27873
28741
|
return [];
|
|
27874
28742
|
return events.map((e) => postSeatWall({ ...src, fetchFn: o.fetchFn, timeoutMs: o.timeoutMs ?? SEAT_POST_TIMEOUT_MS }, {
|
|
@@ -27882,7 +28750,7 @@ var announce = (o, events) => {
|
|
|
27882
28750
|
|
|
27883
28751
|
// src/commands/stopEvent.ts
|
|
27884
28752
|
init_meter();
|
|
27885
|
-
import { existsSync as existsSync32, readFileSync as
|
|
28753
|
+
import { existsSync as existsSync32, readFileSync as readFileSync33 } from "node:fs";
|
|
27886
28754
|
|
|
27887
28755
|
// src/transcript.ts
|
|
27888
28756
|
var isObject16 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -27975,10 +28843,15 @@ async function postTranscript(o, payload, now) {
|
|
|
27975
28843
|
const path = payload.transcript_path?.trim();
|
|
27976
28844
|
if (!sessionId || !path)
|
|
27977
28845
|
return false;
|
|
27978
|
-
|
|
28846
|
+
let src;
|
|
28847
|
+
try {
|
|
28848
|
+
src = meterSource(o.home);
|
|
28849
|
+
} catch {
|
|
28850
|
+
return false;
|
|
28851
|
+
}
|
|
27979
28852
|
if (!src)
|
|
27980
28853
|
return false;
|
|
27981
|
-
const read = o.readFile ?? ((p) => existsSync32(p) ?
|
|
28854
|
+
const read = o.readFile ?? ((p) => existsSync32(p) ? readFileSync33(p, "utf8") : null);
|
|
27982
28855
|
let text;
|
|
27983
28856
|
try {
|
|
27984
28857
|
text = read(path);
|
|
@@ -28072,21 +28945,27 @@ var uninstall2 = (o) => {
|
|
|
28072
28945
|
if (existsSync33(settingsPath(o.home))) {
|
|
28073
28946
|
let settings = readSettings(o.home);
|
|
28074
28947
|
let changed = false;
|
|
28075
|
-
|
|
28076
|
-
|
|
28948
|
+
const cfg = readConfig(o.home);
|
|
28949
|
+
const proxyUrls = [cfg.proxyUrl, DEFAULT_PROXY_URL2];
|
|
28950
|
+
const restoredEnv = isSledsProxyEnv(settings, proxyUrls);
|
|
28951
|
+
if (restoredEnv) {
|
|
28952
|
+
const restore = envToRestore([cfg.priorEnv, cfg.priorGatewayEnv], proxyUrls);
|
|
28953
|
+
settings = switchOff(settings, restore);
|
|
28077
28954
|
changed = true;
|
|
28078
|
-
removed.push(`env.ANTHROPIC_BASE_URL and env.ANTHROPIC_AUTH_TOKEN from ${settingsPath(o.home)}`);
|
|
28955
|
+
removed.push(hasGatewayEnv(settings) ? `env.ANTHROPIC_BASE_URL and env.ANTHROPIC_AUTH_TOKEN from ${settingsPath(o.home)} (your own gateway restored)` : `env.ANTHROPIC_BASE_URL and env.ANTHROPIC_AUTH_TOKEN from ${settingsPath(o.home)}`);
|
|
28079
28956
|
}
|
|
28080
|
-
|
|
28081
|
-
|
|
28957
|
+
const restoredLine = isSledsStatusLine(settings[STATUS_LINE_KEY]);
|
|
28958
|
+
if (restoredLine) {
|
|
28082
28959
|
settings = removeStatusLine(settings, cfg.priorStatusLine);
|
|
28083
28960
|
changed = true;
|
|
28084
28961
|
removed.push(cfg.priorStatusLine === undefined ? `statusLine from ${settingsPath(o.home)}` : `statusLine from ${settingsPath(o.home)} (previous one restored)`);
|
|
28085
|
-
if (cfg.priorStatusLine !== undefined) {
|
|
28086
|
-
const { priorStatusLine: _restored, ...rest } = cfg;
|
|
28087
|
-
writeConfig(o.home, rest);
|
|
28088
|
-
}
|
|
28089
28962
|
}
|
|
28963
|
+
if (restoredLine && cfg.priorStatusLine !== undefined || restoredEnv && (cfg.priorEnv !== undefined || cfg.priorGatewayEnv !== undefined))
|
|
28964
|
+
writeConfig(o.home, {
|
|
28965
|
+
...cfg,
|
|
28966
|
+
...restoredLine ? { priorStatusLine: undefined } : {},
|
|
28967
|
+
...restoredEnv ? { priorEnv: undefined, priorGatewayEnv: undefined } : {}
|
|
28968
|
+
});
|
|
28090
28969
|
if (hasSeatHook(settings)) {
|
|
28091
28970
|
settings = removeSeatHook(settings);
|
|
28092
28971
|
changed = true;
|
|
@@ -28142,18 +29021,12 @@ var uninstall2 = (o) => {
|
|
|
28142
29021
|
log(`Kept ${tokenPath(o.home)} (delete it yourself if you want the token gone).`);
|
|
28143
29022
|
return 0;
|
|
28144
29023
|
};
|
|
28145
|
-
var hasEitherKey = (settings) => {
|
|
28146
|
-
const env = settings.env;
|
|
28147
|
-
if (typeof env !== "object" || env === null)
|
|
28148
|
-
return false;
|
|
28149
|
-
return BASE_URL_KEY in env || AUTH_TOKEN_KEY in env;
|
|
28150
|
-
};
|
|
28151
29024
|
|
|
28152
29025
|
// src/commands/update.ts
|
|
28153
29026
|
init_server();
|
|
28154
29027
|
import { existsSync as existsSync34 } from "node:fs";
|
|
28155
29028
|
import { homedir as homedir8, userInfo as userInfo4 } from "node:os";
|
|
28156
|
-
import { basename as
|
|
29029
|
+
import { basename as basename10 } from "node:path";
|
|
28157
29030
|
init_config();
|
|
28158
29031
|
init_state();
|
|
28159
29032
|
init_meter();
|
|
@@ -28218,7 +29091,7 @@ var realPidAlive4 = (pid) => {
|
|
|
28218
29091
|
};
|
|
28219
29092
|
function machineClient(home, env) {
|
|
28220
29093
|
const src = meterSource(home, undefined, { env });
|
|
28221
|
-
return src ? fetchClient({ ...src, version: "0.1.
|
|
29094
|
+
return src ? fetchClient({ ...src, version: "0.1.62" }) : null;
|
|
28222
29095
|
}
|
|
28223
29096
|
async function noteAnswer2(home, a, now) {
|
|
28224
29097
|
try {
|
|
@@ -28230,7 +29103,7 @@ async function noteAnswer2(home, a, now) {
|
|
|
28230
29103
|
}
|
|
28231
29104
|
function busyEngines(files) {
|
|
28232
29105
|
return files.map((f) => ({
|
|
28233
|
-
name:
|
|
29106
|
+
name: basename10(f, ".json"),
|
|
28234
29107
|
running: readState(f).runs.filter(isRunning).length
|
|
28235
29108
|
})).filter((e) => e.running > 0);
|
|
28236
29109
|
}
|
|
@@ -28252,7 +29125,7 @@ async function updateCmd(o) {
|
|
|
28252
29125
|
error(UPDATE_USAGE);
|
|
28253
29126
|
return 2;
|
|
28254
29127
|
}
|
|
28255
|
-
const version = o.version ?? env
|
|
29128
|
+
const version = o.version ?? cliVersion(env);
|
|
28256
29129
|
if (parsed.mode === "off" || parsed.mode === "on") {
|
|
28257
29130
|
const off = parsed.mode === "off";
|
|
28258
29131
|
await withUpdateLock(home, (s) => {
|
|
@@ -28543,13 +29416,13 @@ var webhooksCmd = async (o) => {
|
|
|
28543
29416
|
|
|
28544
29417
|
// src/config.ts
|
|
28545
29418
|
init_settings();
|
|
28546
|
-
import { chmodSync as chmodSync8, existsSync as existsSync35, mkdirSync as mkdirSync28, readFileSync as
|
|
28547
|
-
import { join as
|
|
29419
|
+
import { chmodSync as chmodSync8, existsSync as existsSync35, mkdirSync as mkdirSync28, readFileSync as readFileSync34, renameSync as renameSync13, writeFileSync as writeFileSync28 } from "node:fs";
|
|
29420
|
+
import { join as join34, resolve as resolve12 } from "node:path";
|
|
28548
29421
|
var configDir2 = (home, env = process.env) => {
|
|
28549
29422
|
const o = env.SLEDS_HOME?.trim();
|
|
28550
|
-
return o ?
|
|
29423
|
+
return o ? resolve12(home, o) : join34(home, ".config", "sleds");
|
|
28551
29424
|
};
|
|
28552
|
-
var configPath2 = (home) =>
|
|
29425
|
+
var configPath2 = (home) => join34(configDir2(home), "config.json");
|
|
28553
29426
|
var isObject17 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
28554
29427
|
var optString2 = (v) => typeof v === "string" ? v : undefined;
|
|
28555
29428
|
var parsePriorEnv2 = (v) => {
|
|
@@ -28599,6 +29472,9 @@ var parseConfig2 = (raw) => {
|
|
|
28599
29472
|
cfg.schedule = schedule;
|
|
28600
29473
|
if (raw.priorStatusLine !== undefined)
|
|
28601
29474
|
cfg.priorStatusLine = raw.priorStatusLine;
|
|
29475
|
+
const priorGatewayEnv = parsePriorEnv2(raw.priorGatewayEnv);
|
|
29476
|
+
if (priorGatewayEnv !== undefined)
|
|
29477
|
+
cfg.priorGatewayEnv = priorGatewayEnv;
|
|
28602
29478
|
if (raw.wiring === "seat-first" || raw.wiring === "proxy-always")
|
|
28603
29479
|
cfg.wiring = raw.wiring;
|
|
28604
29480
|
if (raw.agentKind === "claude-code" || raw.agentKind === "codex")
|
|
@@ -28683,7 +29559,7 @@ var readConfig2 = (home) => {
|
|
|
28683
29559
|
const p = configPath2(home);
|
|
28684
29560
|
if (!existsSync35(p))
|
|
28685
29561
|
return {};
|
|
28686
|
-
return parseConfig2(JSON.parse(
|
|
29562
|
+
return parseConfig2(JSON.parse(readFileSync34(p, "utf8")));
|
|
28687
29563
|
};
|
|
28688
29564
|
|
|
28689
29565
|
// src/runners/exec.ts
|
|
@@ -28741,9 +29617,9 @@ function runnerFor3(name, exec = defaultExec, o = {}) {
|
|
|
28741
29617
|
|
|
28742
29618
|
// src/runtime.ts
|
|
28743
29619
|
import { homedir as homedir9 } from "node:os";
|
|
28744
|
-
import { join as
|
|
29620
|
+
import { join as join35, win32 as win323 } from "node:path";
|
|
28745
29621
|
var isCompiled2 = (argv1 = process.argv[1]) => Boolean(argv1 && (argv1.startsWith("/$bunfs/") || argv1.startsWith("B:\\~BUN\\")));
|
|
28746
|
-
var sledsLink2 = (home = homedir9(), platform = process.platform) => platform === "win32" ? win323.join(process.env.LOCALAPPDATA ?? win323.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") :
|
|
29622
|
+
var sledsLink2 = (home = homedir9(), platform = process.platform) => platform === "win32" ? win323.join(process.env.LOCALAPPDATA ?? win323.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") : join35(home, ".sleds", "bin", "sleds");
|
|
28747
29623
|
|
|
28748
29624
|
// src/schedule.ts
|
|
28749
29625
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
@@ -28755,15 +29631,15 @@ var defaultExec5 = (cmd, args) => {
|
|
|
28755
29631
|
};
|
|
28756
29632
|
|
|
28757
29633
|
// src/settings.ts
|
|
28758
|
-
import { dirname as
|
|
29634
|
+
import { dirname as dirname25, join as join36, resolve as resolve13 } from "node:path";
|
|
28759
29635
|
var withSeatEnv2 = (command, home, env = process.env, org) => {
|
|
28760
29636
|
const parts = [];
|
|
28761
29637
|
const sh = env.SLEDS_HOME?.trim();
|
|
28762
29638
|
const cc = env.CLAUDE_CONFIG_DIR?.trim();
|
|
28763
29639
|
if (sh)
|
|
28764
|
-
parts.push(`SLEDS_HOME=${shellWord2(
|
|
29640
|
+
parts.push(`SLEDS_HOME=${shellWord2(resolve13(home, sh))}`);
|
|
28765
29641
|
if (cc)
|
|
28766
|
-
parts.push(`CLAUDE_CONFIG_DIR=${shellWord2(
|
|
29642
|
+
parts.push(`CLAUDE_CONFIG_DIR=${shellWord2(resolve13(home, cc))}`);
|
|
28767
29643
|
parts.push(command);
|
|
28768
29644
|
return pinOrg4(parts.join(" "), org);
|
|
28769
29645
|
};
|
|
@@ -28779,12 +29655,16 @@ var pinOrg4 = (command, org) => {
|
|
|
28779
29655
|
};
|
|
28780
29656
|
var shellWord2 = (v) => /^[\w./~-]+$/.test(v) ? v : `'${v.replace(/'/g, "'\\''")}'`;
|
|
28781
29657
|
var isObject18 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
29658
|
+
var invokesSleds2 = (command) => /\bsleds\b/.test(command);
|
|
28782
29659
|
var isSledsHookFor2 = (sub) => (entry) => {
|
|
28783
29660
|
if (!isObject18(entry) || !Array.isArray(entry.hooks))
|
|
28784
29661
|
return false;
|
|
28785
29662
|
const re = new RegExp(`\\b${sub}\\b`);
|
|
28786
|
-
return entry.hooks.some((h) => isObject18(h) && h.type === "command" && typeof h.command === "string" && re.test(h.command));
|
|
29663
|
+
return entry.hooks.some((h) => isObject18(h) && h.type === "command" && typeof h.command === "string" && invokesSleds2(h.command) && re.test(h.command));
|
|
28787
29664
|
};
|
|
29665
|
+
var isSledsSeatHook2 = isSledsHookFor2("seat-event");
|
|
29666
|
+
var isSledsSpecHook2 = isSledsHookFor2("spec-event");
|
|
29667
|
+
var isSledsPromptHook2 = isSledsHookFor2("prompt-event");
|
|
28788
29668
|
var isSledsSessionHook2 = isSledsHookFor2("session-event");
|
|
28789
29669
|
var isSledsStopHook2 = isSledsHookFor2("stop-event");
|
|
28790
29670
|
var isSledsPermissionHook2 = isSledsHookFor2("permission-event");
|
|
@@ -29081,7 +29961,7 @@ var main = async (argv) => {
|
|
|
29081
29961
|
now: Date.now(),
|
|
29082
29962
|
stderr: (line) => console.error(line),
|
|
29083
29963
|
isTTY: !!process.stderr.isTTY,
|
|
29084
|
-
version: "0.1.
|
|
29964
|
+
version: "0.1.62"
|
|
29085
29965
|
});
|
|
29086
29966
|
switch (cmd) {
|
|
29087
29967
|
case "update":
|
|
@@ -29314,7 +30194,7 @@ ${renderHelpText(argv[1])}`);
|
|
|
29314
30194
|
case "version":
|
|
29315
30195
|
case "--version":
|
|
29316
30196
|
case "-v":
|
|
29317
|
-
console.log("sleds 0.1.
|
|
30197
|
+
console.log("sleds 0.1.62");
|
|
29318
30198
|
return 0;
|
|
29319
30199
|
default:
|
|
29320
30200
|
console.error(`unknown command: ${cmd}
|