@sleds/cli 0.1.45 → 0.1.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/sleds.mjs +506 -240
- package/package.json +2 -1
package/dist/sleds.mjs
CHANGED
|
@@ -295,7 +295,6 @@ var init_sledSort = __esm(() => {
|
|
|
295
295
|
function slugify(text, max = 63) {
|
|
296
296
|
return text.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, max);
|
|
297
297
|
}
|
|
298
|
-
|
|
299
298
|
// ../../packages/shared/src/seat/agents.ts
|
|
300
299
|
var init_agents = () => {};
|
|
301
300
|
// ../../packages/shared/src/seat/burn.ts
|
|
@@ -2086,7 +2085,7 @@ ${state}`)}, fillcolor="${fill}", color="${border}"${style}];`);
|
|
|
2086
2085
|
`)}
|
|
2087
2086
|
`;
|
|
2088
2087
|
}
|
|
2089
|
-
var ROUTE_APPROACH_MAX = 2000, PLAN_APPROACH_MAX = 1200, PLAN_LIST_MAX = 8, PLAN_LINE_MAX = 240, CONTROL, MAX_NODES = 24, DEPTH_WARN = 4, norm2 = (s) => s.trim().toUpperCase(), AREA_ROOTS, NOT_AREAS, sameRepo = (a, b) => a.length === 0 || b.length === 0 || a.some((r) => b.includes(r)), DOT_COLORS, ROUTE_DRAFT_RULE = "
|
|
2088
|
+
var ROUTE_APPROACH_MAX = 2000, PLAN_APPROACH_MAX = 1200, PLAN_LIST_MAX = 8, PLAN_LINE_MAX = 240, CONTROL, MAX_NODES = 24, DEPTH_WARN = 4, norm2 = (s) => s.trim().toUpperCase(), AREA_ROOTS, NOT_AREAS, sameRepo = (a, b) => a.length === 0 || b.length === 0 || a.some((r) => b.includes(r)), DOT_COLORS, ROUTE_DRAFT_RULE = "Plan the route: PR-sized nodes, file-disjoint where they run in parallel, each with a title, the files or areas it touches, the repo, and the nodes it waits on (by key: A, B, C…). Prefer wide waves over chains deeper than four. Make the tough calls once, so each node's session follows them: an `approach` paragraph for the whole route, and on each node a `plan` — its approach, what it `provides` that later nodes rely on (names, shapes, files), what it `expects` from the nodes it waits on, and the `doneChecks` that say it landed. Show the graph and the plans as text and ask for a yes; file nothing before it. An item with children takes no nodes: its children are the work, and their order lives in their blockedBy. Then `route {q, approach, nodes: [{key, title, touches, repos, blockedBy, plan: {approach, provides, expects, doneChecks}}], confirm: true}`.";
|
|
2090
2089
|
var init_route = __esm(() => {
|
|
2091
2090
|
CONTROL = /[\u0000-\u0008\u000b-\u001f\u007f-\u009f]/g;
|
|
2092
2091
|
AREA_ROOTS = new Set(["apps", "packages", "services", "libs", "crates", "modules"]);
|
|
@@ -2598,7 +2597,11 @@ function failureText(e, timeoutMs) {
|
|
|
2598
2597
|
function fetchClient(o) {
|
|
2599
2598
|
const fetchFn = o.fetchFn ?? fetch;
|
|
2600
2599
|
const base = o.proxyUrl.replace(/\/+$/, "");
|
|
2601
|
-
const headers = {
|
|
2600
|
+
const headers = {
|
|
2601
|
+
"content-type": "application/json",
|
|
2602
|
+
authorization: `Bearer ${o.token}`,
|
|
2603
|
+
...o.version ? { "x-sleds-version": o.version } : {}
|
|
2604
|
+
};
|
|
2602
2605
|
const timeout = () => AbortSignal.timeout(o.timeoutMs ?? MCP_TIMEOUT_MS);
|
|
2603
2606
|
return {
|
|
2604
2607
|
async post(path, body) {
|
|
@@ -3411,7 +3414,7 @@ An engine (or you) takes a ready node with \`sled {take: "${key}/<key>"}\`; Run
|
|
|
3411
3414
|
}
|
|
3412
3415
|
if (nodes.length > 0)
|
|
3413
3416
|
return {
|
|
3414
|
-
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
|
|
3417
|
+
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.",
|
|
3415
3418
|
isError: true
|
|
3416
3419
|
};
|
|
3417
3420
|
const r = await ctx.client.get(`/proxy/route?q=${encodeURIComponent(q)}`);
|
|
@@ -3425,7 +3428,7 @@ An engine (or you) takes a ready node with \`sled {take: "${key}/<key>"}\`; Run
|
|
|
3425
3428
|
const key = str5(r.key) ?? q;
|
|
3426
3429
|
const n = Array.isArray(proposed.nodes) ? proposed.nodes.length : 0;
|
|
3427
3430
|
return {
|
|
3428
|
-
text: `${proposalText(str5(r.text)) || `${key} · route
|
|
3431
|
+
text: `${proposalText(str5(r.text)) || `${key} · route planned, not filed — ${n} nodes`}
|
|
3429
3432
|
|
|
3430
3433
|
${PROPOSED_NEXT(key)}`,
|
|
3431
3434
|
structured: { key, nodes: 0, proposed: n }
|
|
@@ -4434,7 +4437,7 @@ async function handleLine(line, ctx) {
|
|
|
4434
4437
|
return isNotification ? null : errorResponse(id, -32601, `method not found: ${method}`);
|
|
4435
4438
|
}
|
|
4436
4439
|
}
|
|
4437
|
-
var PROTOCOL_VERSION = "2025-06-18", SERVER_INFO, SERVER_INSTRUCTIONS, MCP_TIMEOUT_MS = 5000, sourceSchema, specSchema, TOOLS, VIEW_TOOLS, NOT_SET_UP, UNREACHABLE, isObject4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num3 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, str5 = (v) => typeof v === "string" ? v : undefined, errorMessage = (j) => isObject4(j?.error) ? str5(j.error.message) : str5(j?.error), proposalText = (t) => (t ?? "").replace(/\n*Nothing runs until a person says yes:[^\n]*$/, ""), PROPOSED_NEXT = (key) => `Nothing runs until a person approves it: Approve in the SLEDS app or on the item page, or \`sleds route approve ${key}\`. If you are a
|
|
4440
|
+
var PROTOCOL_VERSION = "2025-06-18", SERVER_INFO, SERVER_INSTRUCTIONS, MCP_TIMEOUT_MS = 5000, sourceSchema, specSchema, TOOLS, VIEW_TOOLS, NOT_SET_UP, UNREACHABLE, isObject4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v), num3 = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined, str5 = (v) => typeof v === "string" ? v : undefined, errorMessage = (j) => isObject4(j?.error) ? str5(j.error.message) : str5(j?.error), proposalText = (t) => (t ?? "").replace(/\n*Nothing runs until a person says yes:[^\n]*$/, ""), PROPOSED_NEXT = (key) => `Nothing runs until a person approves it: Approve in the SLEDS app or on the item page, or \`sleds route approve ${key}\`. If you are a planning session, stop here.`, strList = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : undefined, RELATION_HOWS, UI_RESOURCES, response = (id, result) => JSON.stringify({ jsonrpc: "2.0", id, result }), errorResponse = (id, code, message) => JSON.stringify({ jsonrpc: "2.0", id, error: { code, message } });
|
|
4438
4441
|
var init_server = __esm(() => {
|
|
4439
4442
|
init_worth();
|
|
4440
4443
|
init_intake();
|
|
@@ -4722,7 +4725,7 @@ var init_server = __esm(() => {
|
|
|
4722
4725
|
},
|
|
4723
4726
|
{
|
|
4724
4727
|
name: "route",
|
|
4725
|
-
description: "The route — an item's internal order as PR-sized nodes with blockers (spec 26). With only `q`: the route as filed (each node's state, what it waits on, the ready set, where each run can be watched), or, when none is filed, the pack and the
|
|
4728
|
+
description: "The route — an item's internal order as PR-sized nodes with blockers (spec 26). With only `q`: the route as filed (each node's state, what it waits on, the ready set, where each run can be watched), or, when none is filed, the pack and the planning rule so you plan one (Plan route — the AI step; a person's hand editor on the item page is Edit route). Planning: PR-sized nodes, file-disjoint where they run in parallel, each with a title, the files or areas it touches, the repo, and the nodes it waits on by key (A, B, C…); prefer wide waves over chains deeper than four. Make the tough calls once: an `approach` for the route and a `plan` on each node (its approach, what it provides to later nodes, what it expects from the nodes it waits on, its done-checks), so each node's session follows them instead of re-planning. Show the graph and the plans as text and ask for a yes; file nothing before it. Then call again with `nodes` and `confirm: true`. An item with children is refused nodes — its children are the work: set their order with blockedBy on them. The item lands only when every child has landed. Planning it again shows what changed; a node with a run or a PR is never removed. Ready is computed from landed blockers, never set. With nobody to ask (a planning session an engine started, spec 26 §5.1): call with `nodes` and `propose: true` instead — the route is held on the item for a person's yes and nothing is filed; then stop. A read of an item with a proposal shows it as planned, not filed.",
|
|
4726
4729
|
inputSchema: {
|
|
4727
4730
|
type: "object",
|
|
4728
4731
|
properties: {
|
|
@@ -4733,7 +4736,7 @@ var init_server = __esm(() => {
|
|
|
4733
4736
|
},
|
|
4734
4737
|
nodes: {
|
|
4735
4738
|
type: "array",
|
|
4736
|
-
description: "The
|
|
4739
|
+
description: "The planned nodes, in route order. Keys are minted (A, B, C…) when absent.",
|
|
4737
4740
|
items: {
|
|
4738
4741
|
type: "object",
|
|
4739
4742
|
properties: {
|
|
@@ -4789,7 +4792,7 @@ var init_server = __esm(() => {
|
|
|
4789
4792
|
},
|
|
4790
4793
|
propose: {
|
|
4791
4794
|
type: "boolean",
|
|
4792
|
-
description: "true holds the nodes on the item as a
|
|
4795
|
+
description: "true holds the nodes on the item as a planned route, waiting for a person's yes; nothing is filed. For a planning session with nobody at the keyboard — with a person here, ask and confirm instead."
|
|
4793
4796
|
},
|
|
4794
4797
|
disjoint: {
|
|
4795
4798
|
type: "boolean",
|
|
@@ -6455,11 +6458,15 @@ var init_flags = () => {};
|
|
|
6455
6458
|
// ../../packages/shared/src/sentry/sentry.ts
|
|
6456
6459
|
var init_sentry = () => {};
|
|
6457
6460
|
|
|
6461
|
+
// ../../packages/shared/src/pack/outside.ts
|
|
6462
|
+
var init_outside = () => {};
|
|
6463
|
+
|
|
6458
6464
|
// ../../packages/shared/src/pack/pack.ts
|
|
6459
6465
|
var init_pack = __esm(() => {
|
|
6460
6466
|
init_flags();
|
|
6461
6467
|
init_profile();
|
|
6462
6468
|
init_sentry();
|
|
6469
|
+
init_outside();
|
|
6463
6470
|
init_setup();
|
|
6464
6471
|
});
|
|
6465
6472
|
// ../../packages/shared/src/pack/prHeader.ts
|
|
@@ -6471,6 +6478,7 @@ var init_pack2 = __esm(() => {
|
|
|
6471
6478
|
init_setup();
|
|
6472
6479
|
init_pack();
|
|
6473
6480
|
init_prHeader();
|
|
6481
|
+
init_outside();
|
|
6474
6482
|
});
|
|
6475
6483
|
|
|
6476
6484
|
// ../../packages/shared/src/deploys/deploys.ts
|
|
@@ -8588,8 +8596,8 @@ var init_seat = __esm(() => {
|
|
|
8588
8596
|
});
|
|
8589
8597
|
|
|
8590
8598
|
// src/index.ts
|
|
8591
|
-
import { realpathSync as realpathSync3 } from "fs";
|
|
8592
|
-
import { homedir, platform as platform3 } from "os";
|
|
8599
|
+
import { existsSync as existsSync31, realpathSync as realpathSync3 } from "fs";
|
|
8600
|
+
import { homedir as homedir3, platform as platform3 } from "os";
|
|
8593
8601
|
import { fileURLToPath } from "url";
|
|
8594
8602
|
|
|
8595
8603
|
// ../../packages/shared/src/index.ts
|
|
@@ -9930,7 +9938,7 @@ import {
|
|
|
9930
9938
|
writeFileSync as writeFileSync17
|
|
9931
9939
|
} from "node:fs";
|
|
9932
9940
|
import { tmpdir } from "node:os";
|
|
9933
|
-
import { join as
|
|
9941
|
+
import { join as join21, resolve as resolve9 } from "node:path";
|
|
9934
9942
|
|
|
9935
9943
|
// src/agentMcp.ts
|
|
9936
9944
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
@@ -10387,20 +10395,37 @@ import { basename as basename3, dirname as dirname10, join as join12 } from "nod
|
|
|
10387
10395
|
|
|
10388
10396
|
// src/runners/sandbox.ts
|
|
10389
10397
|
var absRule = (dir) => `/${dir.replace(/\/+$/, "")}/**`;
|
|
10398
|
+
var gitDenyWrite = (gitCommonDir) => {
|
|
10399
|
+
const g = gitCommonDir.replace(/\/+$/, "");
|
|
10400
|
+
return {
|
|
10401
|
+
files: [`${g}/config`, `${g}/config.worktree`, `${g}/worktrees/*/config.worktree`],
|
|
10402
|
+
dirs: [`${g}/hooks`]
|
|
10403
|
+
};
|
|
10404
|
+
};
|
|
10390
10405
|
var sandboxSettings = (o) => {
|
|
10391
10406
|
const domains = [...new Set(o.allow ?? [])];
|
|
10407
|
+
const git = gitDenyWrite(o.gitCommonDir);
|
|
10392
10408
|
return {
|
|
10393
10409
|
sandbox: {
|
|
10394
10410
|
enabled: true,
|
|
10395
10411
|
allowUnsandboxedCommands: false,
|
|
10396
10412
|
failIfUnavailable: true,
|
|
10397
|
-
filesystem: {
|
|
10413
|
+
filesystem: {
|
|
10414
|
+
denyRead: [...o.denyRead],
|
|
10415
|
+
allowWrite: [o.gitCommonDir],
|
|
10416
|
+
denyWrite: [...git.files, ...git.dirs]
|
|
10417
|
+
},
|
|
10398
10418
|
network: { allowedDomains: domains, strictAllowlist: true }
|
|
10399
10419
|
},
|
|
10400
10420
|
permissions: {
|
|
10401
|
-
deny:
|
|
10421
|
+
deny: [
|
|
10422
|
+
...o.denyRead.flatMap((d) => [`Read(${absRule(d)})`, `Edit(${absRule(d)})`]),
|
|
10423
|
+
...git.files.map((f) => `Edit(/${f})`),
|
|
10424
|
+
...git.dirs.map((d) => `Edit(${absRule(d)})`)
|
|
10425
|
+
],
|
|
10402
10426
|
allow: [`Edit(${absRule(o.gitCommonDir)})`, ...domains.map((d) => `WebFetch(domain:${d})`)]
|
|
10403
|
-
}
|
|
10427
|
+
},
|
|
10428
|
+
env: { CLAUDE_CODE_SUBPROCESS_ENV_SCRUB: "1" }
|
|
10404
10429
|
};
|
|
10405
10430
|
};
|
|
10406
10431
|
var sandboxAgentKind = (agent) => {
|
|
@@ -11131,7 +11156,7 @@ function beatBody(state, flags, host = {}, cap = {}) {
|
|
|
11131
11156
|
name: flags.name,
|
|
11132
11157
|
os: host.os ?? process.platform,
|
|
11133
11158
|
runner: flags.runner,
|
|
11134
|
-
version: host.version ?? "0.1.
|
|
11159
|
+
version: host.version ?? "0.1.47" ?? "dev",
|
|
11135
11160
|
running: live.length,
|
|
11136
11161
|
items: live.slice(0, BEAT_ITEMS).map((r) => `${r.item}/${r.node}`),
|
|
11137
11162
|
...cap.atOnce !== undefined ? { atOnce: cap.atOnce } : {},
|
|
@@ -11148,13 +11173,28 @@ function beatBody(state, flags, host = {}, cap = {}) {
|
|
|
11148
11173
|
} : {}
|
|
11149
11174
|
};
|
|
11150
11175
|
}
|
|
11176
|
+
var versionOrNull = (v) => v === null || typeof v === "string";
|
|
11177
|
+
function updateOf(v) {
|
|
11178
|
+
if (typeof v !== "object" || v === null)
|
|
11179
|
+
return;
|
|
11180
|
+
const { target, minimum, manifestUrl } = v;
|
|
11181
|
+
return versionOrNull(target) && versionOrNull(minimum) && versionOrNull(manifestUrl) ? { target, minimum, manifestUrl } : undefined;
|
|
11182
|
+
}
|
|
11151
11183
|
async function postBeat(client, body) {
|
|
11152
11184
|
try {
|
|
11153
11185
|
const r = await client.postFull("/proxy/engine/beat", { ...body });
|
|
11154
|
-
if (r?.status === 200 && r.json?.ok === true)
|
|
11155
|
-
|
|
11186
|
+
if (r?.status === 200 && r.json?.ok === true) {
|
|
11187
|
+
const update = updateOf(r.json.update);
|
|
11188
|
+
return update ? { ok: true, update } : { ok: true };
|
|
11189
|
+
}
|
|
11156
11190
|
const error = r?.json?.error;
|
|
11157
|
-
|
|
11191
|
+
if (typeof error !== "string")
|
|
11192
|
+
return { ok: false };
|
|
11193
|
+
if (r?.status === 409)
|
|
11194
|
+
return { ok: false, refused: error };
|
|
11195
|
+
if (r?.status === 426)
|
|
11196
|
+
return { ok: false, refused: error, below: true };
|
|
11197
|
+
return { ok: false };
|
|
11158
11198
|
} catch {
|
|
11159
11199
|
return { ok: false };
|
|
11160
11200
|
}
|
|
@@ -12207,6 +12247,18 @@ function groupOf(j, item) {
|
|
|
12207
12247
|
const title = str6(j.title);
|
|
12208
12248
|
return title ? { key, title } : null;
|
|
12209
12249
|
}
|
|
12250
|
+
function runOf(v) {
|
|
12251
|
+
if (!Array.isArray(v))
|
|
12252
|
+
return;
|
|
12253
|
+
return v.filter(isObject8).flatMap((x) => {
|
|
12254
|
+
const repo = str6(x.repo)?.trim();
|
|
12255
|
+
if (!repo)
|
|
12256
|
+
return [];
|
|
12257
|
+
const install = str6(x.install)?.trim();
|
|
12258
|
+
const gate = str6(x.gate)?.trim();
|
|
12259
|
+
return [{ repo, ...install ? { install } : {}, ...gate ? { gate } : {} }];
|
|
12260
|
+
});
|
|
12261
|
+
}
|
|
12210
12262
|
function sameEngine(a, b) {
|
|
12211
12263
|
const bare = (s) => s.trim().replace(/^engine:/, "").toLowerCase();
|
|
12212
12264
|
return bare(a) === bare(b);
|
|
@@ -12258,14 +12310,14 @@ var PROFILE_TEXT = [
|
|
|
12258
12310
|
"reposDir",
|
|
12259
12311
|
"engine"
|
|
12260
12312
|
];
|
|
12261
|
-
var SHELL_TEXT = ["agent", "launcher"];
|
|
12313
|
+
var SHELL_TEXT = ["agent", "launcher", "mode"];
|
|
12262
12314
|
function profileOf(r) {
|
|
12263
12315
|
if (!r || r.ok === false || !isObject8(r.profile))
|
|
12264
12316
|
return null;
|
|
12265
12317
|
const p = r.profile;
|
|
12266
12318
|
const member = isObject8(r.member) ? r.member : {};
|
|
12267
12319
|
const out = {
|
|
12268
|
-
pickup: p.pickup === "auto" ? "auto" : "approve",
|
|
12320
|
+
pickup: p.pickup === "auto" && member.pickup === "auto" ? "auto" : "approve",
|
|
12269
12321
|
...HOLD_DEFAULTS2,
|
|
12270
12322
|
holdOff: p.holdOff === true
|
|
12271
12323
|
};
|
|
@@ -12284,8 +12336,8 @@ function profileOf(r) {
|
|
|
12284
12336
|
else if (str6(p[k])?.trim())
|
|
12285
12337
|
notYours.push(k);
|
|
12286
12338
|
}
|
|
12287
|
-
if (
|
|
12288
|
-
|
|
12339
|
+
if (p.pickup === "auto" && out.pickup !== "auto")
|
|
12340
|
+
notYours.push("pickup");
|
|
12289
12341
|
const atOnce = num5(p.atOnce);
|
|
12290
12342
|
if (atOnce !== undefined && atOnce >= 1)
|
|
12291
12343
|
out.atOnce = Math.round(atOnce);
|
|
@@ -12304,13 +12356,17 @@ function profileOf(r) {
|
|
|
12304
12356
|
if (names.length)
|
|
12305
12357
|
out.mcpAllow = names;
|
|
12306
12358
|
}
|
|
12307
|
-
if (
|
|
12359
|
+
if (p.sandbox === true || p.sandbox === false && member.sandbox === false)
|
|
12308
12360
|
out.sandbox = p.sandbox;
|
|
12361
|
+
else if (p.sandbox === false)
|
|
12362
|
+
notYours.push("sandbox");
|
|
12309
12363
|
if (Array.isArray(p.sandboxAllow)) {
|
|
12310
12364
|
const hosts = p.sandboxAllow.filter((x) => typeof x === "string" && x.trim() !== "");
|
|
12311
12365
|
if (hosts.length)
|
|
12312
12366
|
out.sandboxAllow = hosts;
|
|
12313
12367
|
}
|
|
12368
|
+
if (notYours.length)
|
|
12369
|
+
out.notYours = notYours;
|
|
12314
12370
|
return out;
|
|
12315
12371
|
}
|
|
12316
12372
|
async function readProfile(client) {
|
|
@@ -12322,21 +12378,17 @@ async function readProfile(client) {
|
|
|
12322
12378
|
}
|
|
12323
12379
|
function nextPickup(r, o) {
|
|
12324
12380
|
const mine = Array.isArray(r.mine) ? r.mine.filter(isObject8) : [];
|
|
12325
|
-
let running = 0;
|
|
12326
12381
|
for (const row of mine) {
|
|
12327
12382
|
const route = row.route;
|
|
12328
|
-
if (isObject8(route)
|
|
12329
|
-
running++;
|
|
12330
|
-
if (!isObject8(route) || !isObject8(route.armed))
|
|
12383
|
+
if (!isObject8(route) || !armedFor(route.armed, o.engine))
|
|
12331
12384
|
continue;
|
|
12332
12385
|
const states = isObject8(route.states) ? route.states : {};
|
|
12333
|
-
|
|
12334
|
-
if (!armedFor(route.armed, o.engine) || statesLanded(states))
|
|
12386
|
+
if (statesLanded(states))
|
|
12335
12387
|
continue;
|
|
12336
12388
|
if (strings(route.ready).length > 0)
|
|
12337
12389
|
return null;
|
|
12338
12390
|
}
|
|
12339
|
-
if (
|
|
12391
|
+
if (sledRunning(mine) >= o.atOnce)
|
|
12340
12392
|
return null;
|
|
12341
12393
|
for (const row of mine) {
|
|
12342
12394
|
const route = row.route;
|
|
@@ -12352,6 +12404,33 @@ function nextPickup(r, o) {
|
|
|
12352
12404
|
}
|
|
12353
12405
|
return null;
|
|
12354
12406
|
}
|
|
12407
|
+
function sledRunning(r) {
|
|
12408
|
+
const mine = Array.isArray(r) ? r : Array.isArray(r.mine) ? r.mine.filter(isObject8) : [];
|
|
12409
|
+
let running = 0;
|
|
12410
|
+
for (const row of mine) {
|
|
12411
|
+
const route = row.route;
|
|
12412
|
+
if (isObject8(route) && route.drafting === true)
|
|
12413
|
+
running++;
|
|
12414
|
+
if (!isObject8(route) || !isObject8(route.armed))
|
|
12415
|
+
continue;
|
|
12416
|
+
running += keysIn(isObject8(route.states) ? route.states : {}, "running").length;
|
|
12417
|
+
}
|
|
12418
|
+
return running;
|
|
12419
|
+
}
|
|
12420
|
+
function armedDrafts(r, engine) {
|
|
12421
|
+
const mine = Array.isArray(r.mine) ? r.mine.filter(isObject8) : [];
|
|
12422
|
+
return mine.filter((row) => {
|
|
12423
|
+
const route = row.route;
|
|
12424
|
+
if (!isObject8(route) || !armedFor(route.armed, engine) || route.implicit !== true)
|
|
12425
|
+
return false;
|
|
12426
|
+
if (route.drafting === true || route.proposed === true || route.draftParked)
|
|
12427
|
+
return false;
|
|
12428
|
+
if (strings(route.needsRoute).length === 0 || isPrMirror(row.source))
|
|
12429
|
+
return false;
|
|
12430
|
+
const states = isObject8(route.states) ? route.states : {};
|
|
12431
|
+
return !statesLanded(states) && keysIn(states, "running").length === 0;
|
|
12432
|
+
});
|
|
12433
|
+
}
|
|
12355
12434
|
function redraftDue(route) {
|
|
12356
12435
|
return isObject8(route) && isObject8(route.redraft) && route.drafting !== true && route.proposed !== true;
|
|
12357
12436
|
}
|
|
@@ -12365,14 +12444,15 @@ function routeText(route, states) {
|
|
|
12365
12444
|
}
|
|
12366
12445
|
function sledsSource(client, o) {
|
|
12367
12446
|
const routeOf = (q) => client.get(`/proxy/route?q=${encodeURIComponent(q)}`);
|
|
12368
|
-
async function pickup(sled) {
|
|
12447
|
+
async function pickup(sled, drafted) {
|
|
12369
12448
|
const engine = o.engine;
|
|
12370
12449
|
const profile = await readProfile(client);
|
|
12371
12450
|
if (profile?.pickup !== "auto")
|
|
12372
12451
|
return null;
|
|
12373
12452
|
if (profile.engine && !sameEngine(profile.engine, engine))
|
|
12374
12453
|
return null;
|
|
12375
|
-
const
|
|
12454
|
+
const atOnce = (o.atOnce ?? profile.atOnce ?? 1) - drafted;
|
|
12455
|
+
const row = nextPickup(sled, { atOnce, engine });
|
|
12376
12456
|
if (!row)
|
|
12377
12457
|
return null;
|
|
12378
12458
|
const item = str6(row.key) ?? String(row.project);
|
|
@@ -12400,7 +12480,7 @@ function sledsSource(client, o) {
|
|
|
12400
12480
|
...armedTerms(armed)
|
|
12401
12481
|
};
|
|
12402
12482
|
}
|
|
12403
|
-
async function draft(row, item, why) {
|
|
12483
|
+
async function draft(row, item, why, started = false) {
|
|
12404
12484
|
const project = str6(row.project) ?? item;
|
|
12405
12485
|
const pending = isObject8(row.route) && isObject8(row.route.redraft) ? row.route.redraft : null;
|
|
12406
12486
|
const runner = typeof o.runner === "function" ? o.runner() : o.runner;
|
|
@@ -12412,7 +12492,7 @@ function sledsSource(client, o) {
|
|
|
12412
12492
|
...o.leaseMin !== undefined ? { leaseMin: o.leaseMin } : {}
|
|
12413
12493
|
});
|
|
12414
12494
|
if (!r || r.status >= 300 || !r.json || r.json.ok === false) {
|
|
12415
|
-
o.log?.(`${pending ? `${item}: could not claim
|
|
12495
|
+
o.log?.(`${pending ? `${item}: could not claim it to plan its route again` : started ? `${item}: Start could not claim it for planning` : `Pickup: Auto could not claim ${item} for planning`} — ${r ? serverMessage(r) : UNREACHABLE2}`);
|
|
12416
12496
|
return null;
|
|
12417
12497
|
}
|
|
12418
12498
|
const j = r.json;
|
|
@@ -12434,7 +12514,7 @@ function sledsSource(client, o) {
|
|
|
12434
12514
|
route: routeText(brief, isObject8(row.route) ? row.route.states : null)
|
|
12435
12515
|
};
|
|
12436
12516
|
}
|
|
12437
|
-
o.log?.(redraft ? `${item}:
|
|
12517
|
+
o.log?.(redraft ? `${item}: planning the route again from ${redraft.by}'s answer — it waits for a yes` : `${started ? `${item}: Start` : "Pickup: Auto"} is planning ${started ? "its" : `${item}'s`} route first (${why.join(", ")}) — it waits for a yes`);
|
|
12438
12518
|
const leaseUntil = num5(j.leaseUntil);
|
|
12439
12519
|
const claim = {
|
|
12440
12520
|
item,
|
|
@@ -12474,7 +12554,28 @@ function sledsSource(client, o) {
|
|
|
12474
12554
|
if (claimed?.draft && it)
|
|
12475
12555
|
it.draft = claimed.draft;
|
|
12476
12556
|
}
|
|
12477
|
-
const
|
|
12557
|
+
const waiting = armedDrafts(r, o.engine);
|
|
12558
|
+
let drafted = 0;
|
|
12559
|
+
if (waiting.length > 0) {
|
|
12560
|
+
const cap = o.atOnce ?? (await readProfile(client))?.atOnce ?? 1;
|
|
12561
|
+
let room = cap - sledRunning(r);
|
|
12562
|
+
for (const row of waiting) {
|
|
12563
|
+
const item = str6(row.key) ?? String(row.project);
|
|
12564
|
+
const it = items.find((x) => x.item === item);
|
|
12565
|
+
if (it)
|
|
12566
|
+
it.ready = [];
|
|
12567
|
+
if (room <= 0)
|
|
12568
|
+
continue;
|
|
12569
|
+
const route = isObject8(row.route) ? row.route : {};
|
|
12570
|
+
const claimed = await draft(row, item, strings(route.needsRoute), true);
|
|
12571
|
+
if (claimed?.draft && it) {
|
|
12572
|
+
it.draft = claimed.draft;
|
|
12573
|
+
drafted++;
|
|
12574
|
+
room--;
|
|
12575
|
+
}
|
|
12576
|
+
}
|
|
12577
|
+
}
|
|
12578
|
+
const picked = await pickup(r, drafted);
|
|
12478
12579
|
if (picked)
|
|
12479
12580
|
items.push(picked);
|
|
12480
12581
|
}
|
|
@@ -12515,6 +12616,7 @@ function sledsSource(client, o) {
|
|
|
12515
12616
|
}
|
|
12516
12617
|
const leaseUntil = num5(hit.leaseUntil);
|
|
12517
12618
|
const runToken = str6(hit.runToken) ?? (taken.length === 1 ? str6(r.json?.runToken) : undefined);
|
|
12619
|
+
const run = runOf(hit.run);
|
|
12518
12620
|
const claim = {
|
|
12519
12621
|
item,
|
|
12520
12622
|
node: str6(hit.node) ?? node,
|
|
@@ -12526,7 +12628,8 @@ function sledsSource(client, o) {
|
|
|
12526
12628
|
...t.seatId ? { seatId: t.seatId } : {},
|
|
12527
12629
|
...str6(hit.answer) ? { answer: str6(hit.answer) } : {},
|
|
12528
12630
|
...runToken ? { runToken } : {},
|
|
12529
|
-
...group ? { group } : {}
|
|
12631
|
+
...group ? { group } : {},
|
|
12632
|
+
...run ? { run } : {}
|
|
12530
12633
|
};
|
|
12531
12634
|
return { ok: true, claim };
|
|
12532
12635
|
},
|
|
@@ -13046,17 +13149,20 @@ var MANAGERS = new Set(["pnpm", "npm", "yarn", "bun"]);
|
|
|
13046
13149
|
var INSTALL_VERBS = new Set(["install", "i", "ci"]);
|
|
13047
13150
|
function installArgv(command) {
|
|
13048
13151
|
const line = command?.trim().replace(/^`|`$/g, "") ?? "";
|
|
13049
|
-
if (!line || /[;&|<>$`()]/.test(line))
|
|
13152
|
+
if (!line || /[;&|<>$`()\n]/.test(line))
|
|
13050
13153
|
return null;
|
|
13051
13154
|
const argv = shellWords(line);
|
|
13052
13155
|
const [tool, verb] = argv;
|
|
13053
13156
|
if (!tool || !MANAGERS.has(tool))
|
|
13054
13157
|
return null;
|
|
13055
|
-
|
|
13056
|
-
|
|
13057
|
-
|
|
13158
|
+
let rest;
|
|
13159
|
+
if (tool === "yarn")
|
|
13160
|
+
rest = argv.slice(verb === "install" ? 2 : 1);
|
|
13161
|
+
else if (verb && INSTALL_VERBS.has(verb))
|
|
13162
|
+
rest = argv.slice(2);
|
|
13163
|
+
else
|
|
13058
13164
|
return null;
|
|
13059
|
-
return argv;
|
|
13165
|
+
return rest.every((a) => a.startsWith("-")) ? argv : null;
|
|
13060
13166
|
}
|
|
13061
13167
|
function lockfileInstall(path, exists) {
|
|
13062
13168
|
if (exists(join15(path, "pnpm-lock.yaml")))
|
|
@@ -13069,57 +13175,59 @@ function lockfileInstall(path, exists) {
|
|
|
13069
13175
|
return ["npm", "ci"];
|
|
13070
13176
|
return null;
|
|
13071
13177
|
}
|
|
13072
|
-
|
|
13073
|
-
|
|
13074
|
-
|
|
13075
|
-
|
|
13076
|
-
|
|
13077
|
-
|
|
13078
|
-
|
|
13079
|
-
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
|
|
13083
|
-
|
|
13084
|
-
|
|
13085
|
-
|
|
13086
|
-
|
|
13087
|
-
|
|
13088
|
-
|
|
13089
|
-
|
|
13090
|
-
|
|
13091
|
-
|
|
13092
|
-
|
|
13093
|
-
|
|
13094
|
-
|
|
13095
|
-
const
|
|
13096
|
-
|
|
13097
|
-
|
|
13098
|
-
|
|
13099
|
-
|
|
13100
|
-
|
|
13101
|
-
|
|
13102
|
-
|
|
13103
|
-
continue;
|
|
13104
|
-
const m = line.match(/^\s*-\s*([^:`]+?):\s*`(.+)`\s*$/);
|
|
13105
|
-
if (!m?.[1] || !m[2])
|
|
13106
|
-
continue;
|
|
13107
|
-
const name = m[1].trim().toLowerCase();
|
|
13108
|
-
if (name === "done means" || name.startsWith("try it"))
|
|
13109
|
-
continue;
|
|
13110
|
-
if (want && name === want)
|
|
13111
|
-
return m[2];
|
|
13112
|
-
first ??= m[2];
|
|
13113
|
-
}
|
|
13114
|
-
return first;
|
|
13178
|
+
var INTERPRETERS = new Set([
|
|
13179
|
+
"node",
|
|
13180
|
+
"bun",
|
|
13181
|
+
"deno",
|
|
13182
|
+
"python",
|
|
13183
|
+
"python3",
|
|
13184
|
+
"sh",
|
|
13185
|
+
"bash",
|
|
13186
|
+
"zsh",
|
|
13187
|
+
"fish",
|
|
13188
|
+
"npx",
|
|
13189
|
+
"pnpx",
|
|
13190
|
+
"bunx",
|
|
13191
|
+
"dlx",
|
|
13192
|
+
"env",
|
|
13193
|
+
"eval",
|
|
13194
|
+
"exec",
|
|
13195
|
+
"ruby",
|
|
13196
|
+
"perl",
|
|
13197
|
+
"sudo"
|
|
13198
|
+
]);
|
|
13199
|
+
function runsInterpreter(part) {
|
|
13200
|
+
const [first = "", second, third] = part.split(/\s+/);
|
|
13201
|
+
const tool = first.split("/").pop() ?? first;
|
|
13202
|
+
if (tool.includes("=") || INTERPRETERS.has(tool))
|
|
13203
|
+
return true;
|
|
13204
|
+
if (!MANAGERS.has(tool))
|
|
13205
|
+
return false;
|
|
13206
|
+
if (second === "dlx" || second === "x")
|
|
13207
|
+
return true;
|
|
13208
|
+
return second === "exec" && third !== undefined && INTERPRETERS.has(third.split("/").pop() ?? "");
|
|
13115
13209
|
}
|
|
13116
13210
|
function gateAllowRules(gate) {
|
|
13117
13211
|
const whole = gate?.trim();
|
|
13118
13212
|
if (!whole)
|
|
13119
13213
|
return [];
|
|
13214
|
+
if (/[$`()<>|&\n]/.test(whole.replace(/&&|\|\|/g, " ")))
|
|
13215
|
+
return [];
|
|
13120
13216
|
const parts = whole.split(/&&|\|\||;/).map((p) => p.trim()).filter(Boolean);
|
|
13217
|
+
if (parts.some(runsInterpreter))
|
|
13218
|
+
return [];
|
|
13121
13219
|
return [...new Set([whole, ...parts])].map((c) => `Bash(${c})`);
|
|
13122
13220
|
}
|
|
13221
|
+
function claimRunOf(run, repo) {
|
|
13222
|
+
if (!run?.length)
|
|
13223
|
+
return {};
|
|
13224
|
+
const want = repo?.trim().toLowerCase();
|
|
13225
|
+
const hit = want && run.find((r) => r.repo.trim().toLowerCase() === want) || run[0];
|
|
13226
|
+
return {
|
|
13227
|
+
...hit?.install ? { install: hit.install } : {},
|
|
13228
|
+
...hit?.gate ? { gate: hit.gate } : {}
|
|
13229
|
+
};
|
|
13230
|
+
}
|
|
13123
13231
|
function ensureInstalled(exec, path, fs, o = {}) {
|
|
13124
13232
|
if (!fs.exists(join15(path, "package.json")) || fs.exists(join15(path, "node_modules")))
|
|
13125
13233
|
return null;
|
|
@@ -13677,10 +13785,10 @@ async function tickOnce(d) {
|
|
|
13677
13785
|
let mcpConfig;
|
|
13678
13786
|
try {
|
|
13679
13787
|
const base = d.defaultBranch(d.exec, repoPath);
|
|
13680
|
-
const
|
|
13788
|
+
const { install, gate } = claimRunOf(claim.run, claim.repos[0]);
|
|
13789
|
+
const worktree = d.runner.makesWorktree ? repoPath : d.ensureWorktree(d.exec, repoPath, branch, worktreePath(repoPath, name), base, install) ?? worktreePath(repoPath, name);
|
|
13681
13790
|
const prTitle = d.prTitleOf?.(claim);
|
|
13682
13791
|
mcpConfig = engineMcpConfigFor(d, name, claim.runToken, at, worktree);
|
|
13683
|
-
const gate = packGateOf(claim.pack, claim.repos[0]);
|
|
13684
13792
|
const allow = gateAllowRules(gate);
|
|
13685
13793
|
const prompt = nodePrompt({
|
|
13686
13794
|
claim,
|
|
@@ -14654,7 +14762,7 @@ async function startDraft(d, claim, why, state, started, finished) {
|
|
|
14654
14762
|
};
|
|
14655
14763
|
state.runs.push(run);
|
|
14656
14764
|
d.writeState(state);
|
|
14657
|
-
d.log(claim.redraft ? `${at}:
|
|
14765
|
+
d.log(claim.redraft ? `${at}: planning the route again from ${claim.redraft.by}'s answer — it waits for a yes` : `${at}: planning the route${why.length ? ` (${why.join(", ")})` : ""} — it waits for a yes, unless it is one node inside the brief's touches`);
|
|
14658
14766
|
try {
|
|
14659
14767
|
await d.source.heartbeat(claim, watch);
|
|
14660
14768
|
} catch (e) {
|
|
@@ -14671,7 +14779,7 @@ async function settleDraft(d, run, claim, runner, finished) {
|
|
|
14671
14779
|
return true;
|
|
14672
14780
|
}
|
|
14673
14781
|
if (beat === "done") {
|
|
14674
|
-
d.log(`${ref(run)}: route
|
|
14782
|
+
d.log(`${ref(run)}: route planned — it waits for a person's yes`);
|
|
14675
14783
|
endDraft(d, run, runner);
|
|
14676
14784
|
return false;
|
|
14677
14785
|
}
|
|
@@ -14685,7 +14793,7 @@ async function settleDraft(d, run, claim, runner, finished) {
|
|
|
14685
14793
|
return false;
|
|
14686
14794
|
}
|
|
14687
14795
|
if (beat === "lost") {
|
|
14688
|
-
d.log(`${ref(run)}: the
|
|
14796
|
+
d.log(`${ref(run)}: the planning claim was lost — stopping the session`);
|
|
14689
14797
|
endDraft(d, run, runner);
|
|
14690
14798
|
return false;
|
|
14691
14799
|
}
|
|
@@ -14701,7 +14809,7 @@ async function settleDraft(d, run, claim, runner, finished) {
|
|
|
14701
14809
|
let log = "";
|
|
14702
14810
|
if (status === "exited") {
|
|
14703
14811
|
try {
|
|
14704
|
-
log = runner.read(run.handle) || "The
|
|
14812
|
+
log = runner.read(run.handle) || "The planning session exited with no route proposed.";
|
|
14705
14813
|
} catch (e) {
|
|
14706
14814
|
log = `(the session's output could not be read: ${message(e)})`;
|
|
14707
14815
|
}
|
|
@@ -15644,6 +15752,18 @@ init_machine();
|
|
|
15644
15752
|
init_state();
|
|
15645
15753
|
init_meter();
|
|
15646
15754
|
|
|
15755
|
+
// src/runners/gitGuard.ts
|
|
15756
|
+
import { basename as basename4 } from "node:path";
|
|
15757
|
+
var GIT_GUARD_ENV = {
|
|
15758
|
+
GIT_CONFIG_COUNT: "2",
|
|
15759
|
+
GIT_CONFIG_KEY_0: "core.fsmonitor",
|
|
15760
|
+
GIT_CONFIG_VALUE_0: "false",
|
|
15761
|
+
GIT_CONFIG_KEY_1: "core.hooksPath",
|
|
15762
|
+
GIT_CONFIG_VALUE_1: "/dev/null"
|
|
15763
|
+
};
|
|
15764
|
+
var GUARDED = new Set(["git", "gh"]);
|
|
15765
|
+
var guardGit = (exec) => (cmd, args, o) => GUARDED.has(basename4(cmd)) ? exec(cmd, args, { ...o, env: { ...o?.env, ...GIT_GUARD_ENV } }) : exec(cmd, args, o);
|
|
15766
|
+
|
|
15647
15767
|
// src/runners/command.ts
|
|
15648
15768
|
var expandCommandTemplate = (template, o) => {
|
|
15649
15769
|
const values = {
|
|
@@ -16585,7 +16705,7 @@ function flagsFromProfile(flags, given, profile, home) {
|
|
|
16585
16705
|
const used = [];
|
|
16586
16706
|
const skipped = [];
|
|
16587
16707
|
for (const k of profile.notYours ?? [])
|
|
16588
|
-
skipped.push(`${k} (the workspace default — the engine
|
|
16708
|
+
skipped.push(`${k} (the workspace default — the engine takes it only from your own profile)`);
|
|
16589
16709
|
if (profile.atOnce !== undefined && !has("at-once")) {
|
|
16590
16710
|
out.atOnce = profile.atOnce;
|
|
16591
16711
|
used.push(`at-once ${profile.atOnce}`);
|
|
@@ -16749,7 +16869,11 @@ function engineClient(o, org) {
|
|
|
16749
16869
|
const env = o.env ?? process.env;
|
|
16750
16870
|
const src = meterSource(o.home, undefined, { ...org ? { flag: org } : {}, env });
|
|
16751
16871
|
if (src)
|
|
16752
|
-
return fetchClient({
|
|
16872
|
+
return fetchClient({
|
|
16873
|
+
...src,
|
|
16874
|
+
timeoutMs: ENGINE_TIMEOUT_MS,
|
|
16875
|
+
version: "0.1.47"
|
|
16876
|
+
});
|
|
16753
16877
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
16754
16878
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
16755
16879
|
return {
|
|
@@ -16813,7 +16937,7 @@ function engineToken(o, org) {
|
|
|
16813
16937
|
}
|
|
16814
16938
|
var withToken = (token, now) => token ? { token, tokenNow: now } : {};
|
|
16815
16939
|
function engineDeps(o, flags, source, runner, stateName) {
|
|
16816
|
-
const exec = o.exec ?? defaultExec;
|
|
16940
|
+
const exec = guardGit(o.exec ?? defaultExec);
|
|
16817
16941
|
const cwd = o.cwd ?? process.cwd();
|
|
16818
16942
|
const exists = o.exists ?? realExists;
|
|
16819
16943
|
const log = o.log ?? console.log;
|
|
@@ -16944,7 +17068,15 @@ function engineDeps(o, flags, source, runner, stateName) {
|
|
|
16944
17068
|
function sandboxDenyRead(home, env) {
|
|
16945
17069
|
return {
|
|
16946
17070
|
dirs: [...new Set([configDir(home, env), join16(home, ".config", "sleds")])],
|
|
16947
|
-
files: [
|
|
17071
|
+
files: [
|
|
17072
|
+
...new Set([
|
|
17073
|
+
tokenPath(home, env),
|
|
17074
|
+
join16(home, ".sleds-token"),
|
|
17075
|
+
settingsPath(home, env),
|
|
17076
|
+
backupPath(home, env),
|
|
17077
|
+
join16(claudeDir(home, env), "settings.local.json")
|
|
17078
|
+
])
|
|
17079
|
+
]
|
|
16948
17080
|
};
|
|
16949
17081
|
}
|
|
16950
17082
|
function engineSandboxSettings(home, env, gitCommonDir, allow) {
|
|
@@ -17001,7 +17133,7 @@ async function driveEngine(o, flags, deps, until = {}) {
|
|
|
17001
17133
|
runner: deps.runner.name,
|
|
17002
17134
|
atOnce: flags.atOnce,
|
|
17003
17135
|
interval: flags.interval,
|
|
17004
|
-
cliVersion: "0.1.
|
|
17136
|
+
cliVersion: "0.1.47"
|
|
17005
17137
|
};
|
|
17006
17138
|
const beat = (checkedAt) => {
|
|
17007
17139
|
const m = deps.machine;
|
|
@@ -17187,7 +17319,7 @@ async function drive(o, flags, deps, until, beat) {
|
|
|
17187
17319
|
var SEAT_CHANGED_EXIT = 3;
|
|
17188
17320
|
function engineRunner(o, flags) {
|
|
17189
17321
|
const runnerFor = o.runnerFor ?? runnerFor2;
|
|
17190
|
-
return runnerFor(flags.runner, o.exec ?? defaultExec, {
|
|
17322
|
+
return runnerFor(flags.runner, guardGit(o.exec ?? defaultExec), {
|
|
17191
17323
|
...flags.runnerCmd ? { command: flags.runnerCmd } : {}
|
|
17192
17324
|
});
|
|
17193
17325
|
}
|
|
@@ -17274,7 +17406,7 @@ async function enginePauseCmd(o) {
|
|
|
17274
17406
|
source = sledsSource(c, { engine, log });
|
|
17275
17407
|
}
|
|
17276
17408
|
const why = parsed.why ?? `paused on ${defaultEngineName(host)} (sleds engine pause)`;
|
|
17277
|
-
const exec = o.exec ?? defaultExec;
|
|
17409
|
+
const exec = guardGit(o.exec ?? defaultExec);
|
|
17278
17410
|
const gone = new Set;
|
|
17279
17411
|
for (const run of running) {
|
|
17280
17412
|
const at = `${run.item}/${run.node}`;
|
|
@@ -17323,13 +17455,18 @@ import {
|
|
|
17323
17455
|
writeFileSync as writeFileSync15
|
|
17324
17456
|
} from "node:fs";
|
|
17325
17457
|
import { hostname as hostname3 } from "node:os";
|
|
17326
|
-
import { basename as
|
|
17458
|
+
import { basename as basename5, dirname as dirname12, isAbsolute as isAbsolute2, join as join20 } from "node:path";
|
|
17327
17459
|
init_state();
|
|
17328
17460
|
|
|
17461
|
+
// src/runtime.ts
|
|
17462
|
+
import { homedir } from "node:os";
|
|
17463
|
+
import { join as join17, win32 } from "node:path";
|
|
17464
|
+
var sledsLink = (home = homedir(), platform = process.platform) => platform === "win32" ? win32.join(process.env.LOCALAPPDATA ?? win32.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") : join17(home, ".sleds", "bin", "sleds");
|
|
17465
|
+
|
|
17329
17466
|
// src/schedule.ts
|
|
17330
17467
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
17331
17468
|
import { existsSync as existsSync14, mkdirSync as mkdirSync13, rmSync as rmSync5, writeFileSync as writeFileSync14 } from "node:fs";
|
|
17332
|
-
import { join as
|
|
17469
|
+
import { join as join18 } from "node:path";
|
|
17333
17470
|
var REVERT_LABEL = "ai.sleds.revert";
|
|
17334
17471
|
var defaultExec2 = (cmd, args) => {
|
|
17335
17472
|
const r = spawnSync4(cmd, [...args], { stdio: ["ignore", "ignore", "pipe"], encoding: "utf8" });
|
|
@@ -17337,7 +17474,7 @@ var defaultExec2 = (cmd, args) => {
|
|
|
17337
17474
|
return { ok: false, stderr: r.error.message };
|
|
17338
17475
|
return { ok: r.status === 0, stderr: r.stderr ?? "" };
|
|
17339
17476
|
};
|
|
17340
|
-
var plistPath = (home) =>
|
|
17477
|
+
var plistPath = (home) => join18(home, "Library", "LaunchAgents", `${REVERT_LABEL}.plist`);
|
|
17341
17478
|
var xmlEscape2 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
17342
17479
|
var buildLaunchdPlist = (sledsArgv, deadline) => {
|
|
17343
17480
|
const args = [...sledsArgv, "off"].map((a) => ` <string>${xmlEscape2(a)}</string>`).join(`
|
|
@@ -17376,7 +17513,7 @@ var scheduleRevert = (d, deadlineMs) => {
|
|
|
17376
17513
|
if (d.platform === "darwin") {
|
|
17377
17514
|
const p = plistPath(d.home);
|
|
17378
17515
|
try {
|
|
17379
|
-
mkdirSync13(
|
|
17516
|
+
mkdirSync13(join18(d.home, "Library", "LaunchAgents"), { recursive: true });
|
|
17380
17517
|
d.exec("launchctl", ["unload", p]);
|
|
17381
17518
|
writeFileSync14(p, buildLaunchdPlist(d.sledsArgv, deadline));
|
|
17382
17519
|
const r = d.exec("launchctl", ["load", p]);
|
|
@@ -17416,16 +17553,16 @@ var cancelRevert = (d, kind) => {
|
|
|
17416
17553
|
};
|
|
17417
17554
|
|
|
17418
17555
|
// src/commands/engineSystemd.ts
|
|
17419
|
-
import { join as
|
|
17556
|
+
import { join as join19 } from "node:path";
|
|
17420
17557
|
var BOX_ENV_UNIT_PATH = "%h/.config/sleds/box.env";
|
|
17421
17558
|
function boxEnvPath(home) {
|
|
17422
|
-
return
|
|
17559
|
+
return join19(home, ".config", "sleds", "box.env");
|
|
17423
17560
|
}
|
|
17424
17561
|
function engineUnitDir(home) {
|
|
17425
|
-
return
|
|
17562
|
+
return join19(home, ".config", "systemd", "user");
|
|
17426
17563
|
}
|
|
17427
17564
|
function engineUnitPath(home, label) {
|
|
17428
|
-
return
|
|
17565
|
+
return join19(engineUnitDir(home), `${label}.service`);
|
|
17429
17566
|
}
|
|
17430
17567
|
function systemdQuote(s) {
|
|
17431
17568
|
const body = s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/%/g, "%%").replace(/\$/g, "$$$$");
|
|
@@ -17468,9 +17605,10 @@ function parseEngineUnit(text) {
|
|
|
17468
17605
|
var ENGINE_LABEL = "ai.sleds.engine";
|
|
17469
17606
|
var ENGINE_INSTALL_USAGE = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
|
|
17470
17607
|
${ENGINE_USAGE}`;
|
|
17471
|
-
function stableArgv(argv, realpath = realpathSync) {
|
|
17608
|
+
function stableArgv(argv, realpath = realpathSync, home) {
|
|
17609
|
+
const link = sledsLink(home);
|
|
17472
17610
|
return argv.map((a) => {
|
|
17473
|
-
if (!isAbsolute2(a))
|
|
17611
|
+
if (!isAbsolute2(a) || a === link)
|
|
17474
17612
|
return a;
|
|
17475
17613
|
try {
|
|
17476
17614
|
return realpath(a);
|
|
@@ -17483,13 +17621,13 @@ function engineLabel(name, org, seat) {
|
|
|
17483
17621
|
return [ENGINE_LABEL, org, seat?.trim(), name].filter((p) => Boolean(p)).map((p, i) => i === 0 ? p : engineSlug(p)).join(".");
|
|
17484
17622
|
}
|
|
17485
17623
|
function enginePlistPath(home, name, org, seat) {
|
|
17486
|
-
return
|
|
17624
|
+
return join20(home, "Library", "LaunchAgents", `${engineLabel(name, org, seat)}.plist`);
|
|
17487
17625
|
}
|
|
17488
17626
|
function engineLogPath(stateDir, name) {
|
|
17489
|
-
return
|
|
17627
|
+
return join20(stateDir, `${engineSlug(name)}.log`);
|
|
17490
17628
|
}
|
|
17491
17629
|
function engineEventsPath(stateDir, name) {
|
|
17492
|
-
return
|
|
17630
|
+
return join20(stateDir, `${engineSlug(name)}.events.jsonl`);
|
|
17493
17631
|
}
|
|
17494
17632
|
var xmlEscape3 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
17495
17633
|
function buildEnginePlist(o) {
|
|
@@ -17586,7 +17724,7 @@ function readEngines(dir, suffix, manager, parse) {
|
|
|
17586
17724
|
}
|
|
17587
17725
|
const out = [];
|
|
17588
17726
|
for (const name of names.filter((n) => n.startsWith(`${ENGINE_LABEL}.`) && n.endsWith(suffix))) {
|
|
17589
|
-
const path =
|
|
17727
|
+
const path = join20(dir, name);
|
|
17590
17728
|
let parsed;
|
|
17591
17729
|
try {
|
|
17592
17730
|
parsed = parse(readFileSync14(path, "utf8"), name);
|
|
@@ -17606,10 +17744,10 @@ function readEngines(dir, suffix, manager, parse) {
|
|
|
17606
17744
|
}
|
|
17607
17745
|
function installedEngines(home) {
|
|
17608
17746
|
return [
|
|
17609
|
-
...readEngines(
|
|
17747
|
+
...readEngines(join20(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist),
|
|
17610
17748
|
...readEngines(engineUnitDir(home), ".service", "systemd", (text, file) => {
|
|
17611
17749
|
const parsed = parseEngineUnit(text);
|
|
17612
|
-
return parsed && { label:
|
|
17750
|
+
return parsed && { label: basename5(file, ".service"), ...parsed };
|
|
17613
17751
|
})
|
|
17614
17752
|
];
|
|
17615
17753
|
}
|
|
@@ -17644,7 +17782,7 @@ function engineInstall(o) {
|
|
|
17644
17782
|
const label = engineLabel(parsed.name, parsed.org, seat);
|
|
17645
17783
|
const logPath = engineLogPath(stateDir, parsed.name);
|
|
17646
17784
|
mkdirSync14(stateDir, { recursive: true, mode: 448 });
|
|
17647
|
-
const sledsArgv = stableArgv(o.sledsArgv, o.realpath);
|
|
17785
|
+
const sledsArgv = stableArgv(o.sledsArgv, o.realpath, o.home);
|
|
17648
17786
|
const execPath = sledsArgv[0] ?? process.execPath;
|
|
17649
17787
|
const agentEnv = {
|
|
17650
17788
|
PATH: musherPath(o.home, execPath, env.PATH ?? ""),
|
|
@@ -17696,7 +17834,7 @@ function installUnit(a) {
|
|
|
17696
17834
|
const log = o.log ?? console.log;
|
|
17697
17835
|
const error = o.error ?? console.error;
|
|
17698
17836
|
const unit = engineUnitPath(o.home, label);
|
|
17699
|
-
const unitName =
|
|
17837
|
+
const unitName = basename5(unit);
|
|
17700
17838
|
const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
|
|
17701
17839
|
mkdirSync14(dirname12(unit), { recursive: true });
|
|
17702
17840
|
if (existsSync15(unit))
|
|
@@ -17706,7 +17844,7 @@ function installUnit(a) {
|
|
|
17706
17844
|
continue;
|
|
17707
17845
|
if (engineArg(other.programArgs, "name") !== parsed.name)
|
|
17708
17846
|
continue;
|
|
17709
|
-
systemctl("disable", "--now",
|
|
17847
|
+
systemctl("disable", "--now", basename5(other.plist));
|
|
17710
17848
|
rmSync6(other.plist, { force: true });
|
|
17711
17849
|
log(`replaced ${other.label}, this engine as installed before`);
|
|
17712
17850
|
}
|
|
@@ -17765,13 +17903,13 @@ function engineUninstall(o) {
|
|
|
17765
17903
|
const unit = file.endsWith(".service");
|
|
17766
17904
|
const exec = o.exec ?? defaultExec2;
|
|
17767
17905
|
if (unit)
|
|
17768
|
-
exec("systemctl", ["--user", "disable", "--now",
|
|
17906
|
+
exec("systemctl", ["--user", "disable", "--now", basename5(file)]);
|
|
17769
17907
|
else
|
|
17770
17908
|
exec("launchctl", ["unload", file]);
|
|
17771
17909
|
rmSync6(file, { force: true });
|
|
17772
17910
|
if (unit)
|
|
17773
17911
|
exec("systemctl", ["--user", "daemon-reload"]);
|
|
17774
|
-
log(`engine:${name} removed: ${
|
|
17912
|
+
log(`engine:${name} removed: ${basename5(file, unit ? ".service" : ".plist")} — its sessions keep running`);
|
|
17775
17913
|
return 0;
|
|
17776
17914
|
}
|
|
17777
17915
|
|
|
@@ -17888,7 +18026,7 @@ function nodeOk(version, min = NODE_MIN) {
|
|
|
17888
18026
|
}
|
|
17889
18027
|
var MARK = { ok: "ok ", warn: "warn", fail: "FAIL" };
|
|
17890
18028
|
function formatDoctor(checks) {
|
|
17891
|
-
const lines = checks.map((c) => `${MARK[c.level]} ${c.name.padEnd(
|
|
18029
|
+
const lines = checks.map((c) => `${MARK[c.level]} ${c.name.padEnd(15)} ${c.detail}`);
|
|
17892
18030
|
const fixes = checks.filter((c) => c.level !== "ok" && c.fix);
|
|
17893
18031
|
if (fixes.length > 0) {
|
|
17894
18032
|
lines.push("");
|
|
@@ -17928,7 +18066,7 @@ async function runDoctor(o) {
|
|
|
17928
18066
|
level: "fail",
|
|
17929
18067
|
name: "config",
|
|
17930
18068
|
detail: `${configPath(home)} does not exist${overrides.length ? ` (this shell has ${overrides.join(" ")})` : ""}`,
|
|
17931
|
-
fix: overrides.length ? "unset SLEDS_HOME CLAUDE_CONFIG_DIR — or run `sleds init` for this seat" : "sleds init
|
|
18069
|
+
fix: overrides.length ? "unset SLEDS_HOME CLAUDE_CONFIG_DIR — or run `sleds init` for this seat" : "sleds init"
|
|
17932
18070
|
});
|
|
17933
18071
|
} else {
|
|
17934
18072
|
checks.push({
|
|
@@ -17958,7 +18096,7 @@ async function runDoctor(o) {
|
|
|
17958
18096
|
level: "warn",
|
|
17959
18097
|
name: "claude",
|
|
17960
18098
|
detail: `${sPath} carries a different token (${maskToken(pointed.token)}) than ${configPath(home)} (${maskToken(cfg.token)})`,
|
|
17961
|
-
fix: "sleds init
|
|
18099
|
+
fix: "sleds init (or `sleds login` as the seat you mean)"
|
|
17962
18100
|
});
|
|
17963
18101
|
} else {
|
|
17964
18102
|
checks.push({ level: "ok", name: "claude", detail: `${sPath} → ${pointed.url}` });
|
|
@@ -18124,13 +18262,16 @@ async function runDoctor(o) {
|
|
|
18124
18262
|
}
|
|
18125
18263
|
var SANDBOX_PROBE = "sandbox-probe";
|
|
18126
18264
|
var PROBE_ENV = "SLEDS_DOCTOR_PROBE";
|
|
18265
|
+
var SETTINGS_ENV = "SLEDS_DOCTOR_SETTINGS";
|
|
18127
18266
|
var SANDBOX_PROBE_COMMAND = [
|
|
18128
18267
|
`cat "$${PROBE_ENV}"; echo "SLEDS_CAT_EXIT=$?"`,
|
|
18268
|
+
`[ -n "$ANTHROPIC_AUTH_TOKEN$ANTHROPIC_API_KEY" ]; echo "SLEDS_ENV_EMPTY=$?"`,
|
|
18269
|
+
`cat "$${SETTINGS_ENV}" >/dev/null; echo "SLEDS_SETTINGS_EXIT=$?"`,
|
|
18129
18270
|
`curl -sS -m 10 -o /dev/null -w "SLEDS_CURL_CODE=%{http_code}\\n" https://example.com; echo "SLEDS_CURL_EXIT=$?"`,
|
|
18130
18271
|
`gh api user -q .login; echo "SLEDS_GH_EXIT=$?"`
|
|
18131
18272
|
].join("; ");
|
|
18132
18273
|
var marker = (out, name) => new RegExp(`${name}=(\\d+)`).exec(out)?.[1] ?? null;
|
|
18133
|
-
function readSandboxProbe(run, nonce) {
|
|
18274
|
+
function readSandboxProbe(run, nonce, o = {}) {
|
|
18134
18275
|
const out = `${run.stdout}
|
|
18135
18276
|
${run.stderr}`;
|
|
18136
18277
|
const failed = run.status !== 0;
|
|
@@ -18152,6 +18293,34 @@ ${run.stderr}`;
|
|
|
18152
18293
|
detail: catExit === "0" ? "cat succeeded but printed no nonce — inconclusive" : `${why} — inconclusive`,
|
|
18153
18294
|
fix
|
|
18154
18295
|
};
|
|
18296
|
+
const leaked = Boolean(o.token) && out.includes(o.token);
|
|
18297
|
+
const envEmpty = marker(out, "SLEDS_ENV_EMPTY");
|
|
18298
|
+
const envRow = envEmpty === "0" ? {
|
|
18299
|
+
level: "fail",
|
|
18300
|
+
name: "sandbox env",
|
|
18301
|
+
detail: "a sandboxed session's shell has ANTHROPIC_AUTH_TOKEN or ANTHROPIC_API_KEY — the seat token is readable",
|
|
18302
|
+
fix: "update Claude Code: the sandbox settings' env sets CLAUDE_CODE_SUBPROCESS_ENV_SCRUB, which 2.1.310 honors"
|
|
18303
|
+
} : envEmpty !== null ? {
|
|
18304
|
+
level: "ok",
|
|
18305
|
+
name: "sandbox env",
|
|
18306
|
+
detail: "the session's shell has no Anthropic credential in its env"
|
|
18307
|
+
} : { level: "warn", name: "sandbox env", detail: `${why} — inconclusive`, fix };
|
|
18308
|
+
const settingsExit = marker(out, "SLEDS_SETTINGS_EXIT");
|
|
18309
|
+
const settingsRow = leaked || settingsExit === "0" && o.settingsExists !== false ? {
|
|
18310
|
+
level: "fail",
|
|
18311
|
+
name: "sandbox settings read",
|
|
18312
|
+
detail: leaked ? "the seat token appeared in a sandboxed session's output" : "a sandboxed session read Claude Code's settings.json — a proxied seat's token is readable",
|
|
18313
|
+
fix: "check that the sandbox settings deny the Claude settings files (sandbox.filesystem.denyRead)"
|
|
18314
|
+
} : o.settingsExists === false ? {
|
|
18315
|
+
level: "warn",
|
|
18316
|
+
name: "sandbox settings read",
|
|
18317
|
+
detail: "Claude Code has no settings.json for this seat — nothing to guard yet",
|
|
18318
|
+
fix: "sleds init"
|
|
18319
|
+
} : settingsExit !== null ? {
|
|
18320
|
+
level: "ok",
|
|
18321
|
+
name: "sandbox settings read",
|
|
18322
|
+
detail: "Claude Code's settings.json is unreadable from a sandboxed session"
|
|
18323
|
+
} : { level: "warn", name: "sandbox settings read", detail: `${why} — inconclusive`, fix };
|
|
18155
18324
|
const code = marker(out, "SLEDS_CURL_CODE");
|
|
18156
18325
|
const curlExit = marker(out, "SLEDS_CURL_EXIT");
|
|
18157
18326
|
const egress = code !== null && code !== "000" ? {
|
|
@@ -18176,8 +18345,15 @@ ${run.stderr}`;
|
|
|
18176
18345
|
detail: ghExit === null ? `${why} — inconclusive` : `gh fails inside the sandbox (exit ${ghExit}) — a sandboxed node cannot push or open its PR`,
|
|
18177
18346
|
fix: ghExit === null ? fix : "gh auth status; api.github.com on the allowlist; on macOS gh (Go) needs sandbox.enableWeakerNetworkIsolation for TLS"
|
|
18178
18347
|
};
|
|
18179
|
-
return [read, egress, github];
|
|
18348
|
+
return [read, envRow, settingsRow, egress, github];
|
|
18180
18349
|
}
|
|
18350
|
+
var proxyToken = (home, env) => {
|
|
18351
|
+
try {
|
|
18352
|
+
return readProxy(readSettings(home, env))?.token;
|
|
18353
|
+
} catch {
|
|
18354
|
+
return;
|
|
18355
|
+
}
|
|
18356
|
+
};
|
|
18181
18357
|
function sandboxChecks(o, env) {
|
|
18182
18358
|
const which = (c) => (o.which ?? defaultWhich2)(c)[0] ?? null;
|
|
18183
18359
|
const exec = o.exec ?? sessionExec;
|
|
@@ -18202,17 +18378,14 @@ function sandboxChecks(o, env) {
|
|
|
18202
18378
|
}
|
|
18203
18379
|
];
|
|
18204
18380
|
const nonce = o.nonce ?? `sleds-probe-${randomBytes(16).toString("hex")}`;
|
|
18205
|
-
const probe =
|
|
18206
|
-
const work = mkdtempSync(
|
|
18381
|
+
const probe = join21(dir, SANDBOX_PROBE);
|
|
18382
|
+
const work = mkdtempSync(join21(tmpdir(), "sleds-sandbox-"));
|
|
18207
18383
|
try {
|
|
18208
18384
|
writeFileSync17(probe, `${nonce}
|
|
18209
18385
|
`, { mode: 384 });
|
|
18210
|
-
const settingsFile =
|
|
18211
|
-
const settings =
|
|
18212
|
-
|
|
18213
|
-
gitCommonDir: work,
|
|
18214
|
-
allow: SANDBOX_DEFAULT_ALLOW
|
|
18215
|
-
});
|
|
18386
|
+
const settingsFile = join21(work, "settings.json");
|
|
18387
|
+
const settings = engineSandboxSettings(o.home, env, work, SANDBOX_DEFAULT_ALLOW);
|
|
18388
|
+
const claudeSettings = settingsPath(o.home, env);
|
|
18216
18389
|
writeFileSync17(settingsFile, JSON.stringify(settings, null, 2), { mode: 384 });
|
|
18217
18390
|
const prompt = `Run exactly this one Bash command, once, then reply with its complete output verbatim and nothing else:
|
|
18218
18391
|
|
|
@@ -18221,6 +18394,7 @@ ${SANDBOX_PROBE_COMMAND}`;
|
|
|
18221
18394
|
"-u",
|
|
18222
18395
|
"SLEDS_TOKEN",
|
|
18223
18396
|
`${PROBE_ENV}=${probe}`,
|
|
18397
|
+
`${SETTINGS_ENV}=${claudeSettings}`,
|
|
18224
18398
|
claude,
|
|
18225
18399
|
"-p",
|
|
18226
18400
|
"--model",
|
|
@@ -18233,7 +18407,9 @@ ${SANDBOX_PROBE_COMMAND}`;
|
|
|
18233
18407
|
"3",
|
|
18234
18408
|
prompt
|
|
18235
18409
|
], { cwd: work });
|
|
18236
|
-
|
|
18410
|
+
const settingsExists = existsSync17(claudeSettings);
|
|
18411
|
+
const token = settingsExists ? proxyToken(o.home, env) : undefined;
|
|
18412
|
+
return readSandboxProbe(run, nonce, { ...token ? { token } : {}, settingsExists });
|
|
18237
18413
|
} finally {
|
|
18238
18414
|
rmSync8(probe, { force: true });
|
|
18239
18415
|
rmSync8(work, { recursive: true, force: true });
|
|
@@ -18470,7 +18646,7 @@ import {
|
|
|
18470
18646
|
writeFileSync as writeFileSync18
|
|
18471
18647
|
} from "node:fs";
|
|
18472
18648
|
import { hostname as hostname4 } from "node:os";
|
|
18473
|
-
import { join as
|
|
18649
|
+
import { join as join22, resolve as resolve10 } from "node:path";
|
|
18474
18650
|
init_machine();
|
|
18475
18651
|
init_state();
|
|
18476
18652
|
init_meter();
|
|
@@ -18652,7 +18828,7 @@ function flagsFromProfile2(flags, given, profile, home) {
|
|
|
18652
18828
|
const used = [];
|
|
18653
18829
|
const skipped = [];
|
|
18654
18830
|
for (const k of profile.notYours ?? [])
|
|
18655
|
-
skipped.push(`${k} (the workspace default — the engine
|
|
18831
|
+
skipped.push(`${k} (the workspace default — the engine takes it only from your own profile)`);
|
|
18656
18832
|
if (profile.atOnce !== undefined && !has("at-once")) {
|
|
18657
18833
|
out.atOnce = profile.atOnce;
|
|
18658
18834
|
used.push(`at-once ${profile.atOnce}`);
|
|
@@ -18725,7 +18901,7 @@ function flagsFromProfile2(flags, given, profile, home) {
|
|
|
18725
18901
|
}
|
|
18726
18902
|
}
|
|
18727
18903
|
if (profile.reposDir && !has("repos-dir") && !has("repo")) {
|
|
18728
|
-
out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ?
|
|
18904
|
+
out.reposDir = splitReposDirs(profile.reposDir).map((d) => home && /^~(\/|$)/.test(d) ? join22(home, d.slice(1)) : d).join(":");
|
|
18729
18905
|
used.push(`repos ${profile.reposDir}`);
|
|
18730
18906
|
}
|
|
18731
18907
|
if (profile.mcpStrict !== undefined && !has("strict-mcp") && !has("no-strict-mcp")) {
|
|
@@ -18868,7 +19044,11 @@ function engineClient2(o, org) {
|
|
|
18868
19044
|
const env = o.env ?? process.env;
|
|
18869
19045
|
const src = meterSource(o.home, undefined, { ...org ? { flag: org } : {}, env });
|
|
18870
19046
|
if (src)
|
|
18871
|
-
return fetchClient({
|
|
19047
|
+
return fetchClient({
|
|
19048
|
+
...src,
|
|
19049
|
+
timeoutMs: ENGINE_TIMEOUT_MS2,
|
|
19050
|
+
version: "0.1.47"
|
|
19051
|
+
});
|
|
18872
19052
|
const asked = org?.trim() || env.SLEDS_ORG?.trim();
|
|
18873
19053
|
if (asked && !selectOrg(readConfig(o.home), org, env).seat)
|
|
18874
19054
|
return {
|
|
@@ -18916,12 +19096,12 @@ function memberMcpConfigs2(o, cwd) {
|
|
|
18916
19096
|
});
|
|
18917
19097
|
const claudeDir = (o.env ?? process.env).CLAUDE_CONFIG_DIR;
|
|
18918
19098
|
return [
|
|
18919
|
-
read(claudeDir ?
|
|
18920
|
-
...cwd ? [read(
|
|
19099
|
+
read(claudeDir ? join22(claudeDir, ".claude.json") : join22(o.home, ".claude.json")),
|
|
19100
|
+
...cwd ? [read(join22(cwd, ".mcp.json"))] : []
|
|
18921
19101
|
];
|
|
18922
19102
|
}
|
|
18923
19103
|
function engineStateDir2(o, org, seat) {
|
|
18924
|
-
return seatStateDir(orgStateDir(o.stateDir ??
|
|
19104
|
+
return seatStateDir(orgStateDir(o.stateDir ?? join22(configDir(o.home, o.env ?? process.env), "engine"), org), seat);
|
|
18925
19105
|
}
|
|
18926
19106
|
function engineSeat2(o, org) {
|
|
18927
19107
|
try {
|
|
@@ -18941,7 +19121,7 @@ function engineToken2(o, org) {
|
|
|
18941
19121
|
}
|
|
18942
19122
|
var withToken2 = (token, now) => token ? { token, tokenNow: now } : {};
|
|
18943
19123
|
function engineDeps2(o, flags, source, runner, stateName) {
|
|
18944
|
-
const exec = o.exec ?? defaultExec;
|
|
19124
|
+
const exec = guardGit(o.exec ?? defaultExec);
|
|
18945
19125
|
const cwd = o.cwd ?? process.cwd();
|
|
18946
19126
|
const exists = o.exists ?? realExists2;
|
|
18947
19127
|
const log = o.log ?? console.log;
|
|
@@ -18951,8 +19131,8 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
18951
19131
|
const repo = flags.repo ? resolve10(cwd, flags.repo) : undefined;
|
|
18952
19132
|
const reposDirs = splitReposDirs(flags.reposDir).map((d) => resolve10(cwd, d));
|
|
18953
19133
|
const { branch, prTitle } = flags;
|
|
18954
|
-
const hooksDir =
|
|
18955
|
-
const permissionMark = (name) =>
|
|
19134
|
+
const hooksDir = join22(stateDir, "hooks");
|
|
19135
|
+
const permissionMark = (name) => join22(hooksDir, `${name}.permission.json`);
|
|
18956
19136
|
const withHook = (name, settings) => applyPermissionHook(settings, [...o.sledsArgv ?? ["sleds"], "permission-event", "--mark", permissionMark(name)].map(shq2).join(" "));
|
|
18957
19137
|
return {
|
|
18958
19138
|
source,
|
|
@@ -18977,9 +19157,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
18977
19157
|
sandbox: true,
|
|
18978
19158
|
writeSandboxSettings: o.writeSandboxSettings ?? ((name, cwd, allow) => {
|
|
18979
19159
|
const gitCommonDir = gitCommonDirOf2(exec, cwd);
|
|
18980
|
-
const dir =
|
|
19160
|
+
const dir = join22(stateDir, "sandbox");
|
|
18981
19161
|
mkdirSync16(dir, { recursive: true, mode: 448 });
|
|
18982
|
-
const p =
|
|
19162
|
+
const p = join22(dir, `${name}.json`);
|
|
18983
19163
|
const walls = engineSandboxSettings2(o.home, o.env ?? process.env, gitCommonDir, [
|
|
18984
19164
|
...SANDBOX_DEFAULT_ALLOW,
|
|
18985
19165
|
...flags.sandboxAllow ?? []
|
|
@@ -18996,7 +19176,7 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
18996
19176
|
} : {},
|
|
18997
19177
|
writeHookSettings: (name, allow) => {
|
|
18998
19178
|
mkdirSync16(hooksDir, { recursive: true, mode: 448 });
|
|
18999
|
-
const p =
|
|
19179
|
+
const p = join22(hooksDir, `${name}.json`);
|
|
19000
19180
|
const base = allow?.length ? { permissions: { allow: [...allow] } } : {};
|
|
19001
19181
|
writeFileSync18(p, `${JSON.stringify(withHook(name, base), null, 2)}
|
|
19002
19182
|
`, { mode: 384 });
|
|
@@ -19024,9 +19204,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
19024
19204
|
exists
|
|
19025
19205
|
}),
|
|
19026
19206
|
writeMcpConfig: o.writeMcpConfig ?? ((name, runToken, worktree) => {
|
|
19027
|
-
const dir =
|
|
19207
|
+
const dir = join22(stateDir, "mcp");
|
|
19028
19208
|
mkdirSync16(dir, { recursive: true, mode: 448 });
|
|
19029
|
-
const p =
|
|
19209
|
+
const p = join22(dir, `${name}.json`);
|
|
19030
19210
|
let others = {};
|
|
19031
19211
|
if (flags.strictMcp && flags.mcpAllow?.length) {
|
|
19032
19212
|
const r = mcpPassThrough(flags.mcpAllow, memberMcpConfigs2(o, worktree));
|
|
@@ -19042,9 +19222,9 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
19042
19222
|
}),
|
|
19043
19223
|
removeMcpConfig: o.removeMcpConfig ?? ((p) => rmSync9(p, { force: true })),
|
|
19044
19224
|
writePrompt: o.writePrompt ?? ((name, text) => {
|
|
19045
|
-
const dir =
|
|
19225
|
+
const dir = join22(stateDir, "prompts");
|
|
19046
19226
|
mkdirSync16(dir, { recursive: true, mode: 448 });
|
|
19047
|
-
const p =
|
|
19227
|
+
const p = join22(dir, `${name}.md`);
|
|
19048
19228
|
writeFileSync18(p, text, { mode: 384 });
|
|
19049
19229
|
return p;
|
|
19050
19230
|
}),
|
|
@@ -19071,8 +19251,16 @@ function engineDeps2(o, flags, source, runner, stateName) {
|
|
|
19071
19251
|
}
|
|
19072
19252
|
function sandboxDenyRead2(home, env) {
|
|
19073
19253
|
return {
|
|
19074
|
-
dirs: [...new Set([configDir(home, env),
|
|
19075
|
-
files: [
|
|
19254
|
+
dirs: [...new Set([configDir(home, env), join22(home, ".config", "sleds")])],
|
|
19255
|
+
files: [
|
|
19256
|
+
...new Set([
|
|
19257
|
+
tokenPath(home, env),
|
|
19258
|
+
join22(home, ".sleds-token"),
|
|
19259
|
+
settingsPath(home, env),
|
|
19260
|
+
backupPath(home, env),
|
|
19261
|
+
join22(claudeDir(home, env), "settings.local.json")
|
|
19262
|
+
])
|
|
19263
|
+
]
|
|
19076
19264
|
};
|
|
19077
19265
|
}
|
|
19078
19266
|
function engineSandboxSettings2(home, env, gitCommonDir, allow) {
|
|
@@ -19096,6 +19284,8 @@ function sandboxRefusal(flags) {
|
|
|
19096
19284
|
return "sandboxed sessions: the conductor runner starts them in Conductor's cloud, where the engine cannot put the sandbox on — use another runner, or --no-sandbox";
|
|
19097
19285
|
if (flags.agent && sandboxAgentKind(flags.agent) === null)
|
|
19098
19286
|
return `sandboxed sessions: --agent '${flags.agent}' is neither Claude Code nor Codex, so the engine cannot sandbox it — use one of those, or --no-sandbox`;
|
|
19287
|
+
if (flags.agent && sandboxAgentKind(flags.agent) === "codex")
|
|
19288
|
+
return "sandboxed sessions: Codex's sandbox walls writes, not reads — the seat token stays readable; use Claude Code, or --no-sandbox";
|
|
19099
19289
|
return null;
|
|
19100
19290
|
}
|
|
19101
19291
|
function pinOrg3(configJson, org) {
|
|
@@ -19138,7 +19328,7 @@ async function driveEngine2(o, flags, deps, until = {}) {
|
|
|
19138
19328
|
runner: deps.runner.name,
|
|
19139
19329
|
atOnce: flags.atOnce,
|
|
19140
19330
|
interval: flags.interval,
|
|
19141
|
-
cliVersion: "0.1.
|
|
19331
|
+
cliVersion: "0.1.47"
|
|
19142
19332
|
};
|
|
19143
19333
|
const beat = (checkedAt) => {
|
|
19144
19334
|
const m = deps.machine;
|
|
@@ -19324,7 +19514,7 @@ async function drive2(o, flags, deps, until, beat) {
|
|
|
19324
19514
|
var SEAT_CHANGED_EXIT2 = 3;
|
|
19325
19515
|
function engineRunner2(o, flags) {
|
|
19326
19516
|
const runnerFor = o.runnerFor ?? runnerFor2;
|
|
19327
|
-
return runnerFor(flags.runner, o.exec ?? defaultExec, {
|
|
19517
|
+
return runnerFor(flags.runner, guardGit(o.exec ?? defaultExec), {
|
|
19328
19518
|
...flags.runnerCmd ? { command: flags.runnerCmd } : {}
|
|
19329
19519
|
});
|
|
19330
19520
|
}
|
|
@@ -19465,7 +19655,7 @@ var engineCmd = async (o) => {
|
|
|
19465
19655
|
if (!r || r.ok || !r.refused || r.refused === refused)
|
|
19466
19656
|
return;
|
|
19467
19657
|
refused = r.refused;
|
|
19468
|
-
error(`${r.refused}. This engine is not shown as up until it beats under a name of its own.`);
|
|
19658
|
+
error(r.below ? `${r.refused}. This engine is not shown as up until it beats on a version SLEDS serves.` : `${r.refused}. This engine is not shown as up until it beats under a name of its own.`);
|
|
19469
19659
|
};
|
|
19470
19660
|
afterTick = () => {
|
|
19471
19661
|
try {
|
|
@@ -19563,7 +19753,7 @@ async function enginePauseCmd2(o) {
|
|
|
19563
19753
|
source = sledsSource(c, { engine, log });
|
|
19564
19754
|
}
|
|
19565
19755
|
const why = parsed.why ?? `paused on ${defaultEngineName2(host)} (sleds engine pause)`;
|
|
19566
|
-
const exec = o.exec ?? defaultExec;
|
|
19756
|
+
const exec = guardGit(o.exec ?? defaultExec);
|
|
19567
19757
|
const gone = new Set;
|
|
19568
19758
|
for (const run of running) {
|
|
19569
19759
|
const at = `${run.item}/${run.node}`;
|
|
@@ -19612,14 +19802,15 @@ import {
|
|
|
19612
19802
|
writeFileSync as writeFileSync19
|
|
19613
19803
|
} from "node:fs";
|
|
19614
19804
|
import { hostname as hostname5 } from "node:os";
|
|
19615
|
-
import { basename as
|
|
19805
|
+
import { basename as basename6, dirname as dirname13, isAbsolute as isAbsolute3, join as join23 } from "node:path";
|
|
19616
19806
|
init_state();
|
|
19617
19807
|
var ENGINE_LABEL2 = "ai.sleds.engine";
|
|
19618
19808
|
var ENGINE_INSTALL_USAGE2 = `usage: sleds engine install [engine flags] | sleds engine uninstall [--name <n>] [--org <slug>]
|
|
19619
19809
|
${ENGINE_USAGE}`;
|
|
19620
|
-
function stableArgv2(argv, realpath = realpathSync2) {
|
|
19810
|
+
function stableArgv2(argv, realpath = realpathSync2, home) {
|
|
19811
|
+
const link = sledsLink(home);
|
|
19621
19812
|
return argv.map((a) => {
|
|
19622
|
-
if (!isAbsolute3(a))
|
|
19813
|
+
if (!isAbsolute3(a) || a === link)
|
|
19623
19814
|
return a;
|
|
19624
19815
|
try {
|
|
19625
19816
|
return realpath(a);
|
|
@@ -19632,13 +19823,13 @@ function engineLabel2(name, org, seat) {
|
|
|
19632
19823
|
return [ENGINE_LABEL2, org, seat?.trim(), name].filter((p) => Boolean(p)).map((p, i) => i === 0 ? p : engineSlug(p)).join(".");
|
|
19633
19824
|
}
|
|
19634
19825
|
function enginePlistPath2(home, name, org, seat) {
|
|
19635
|
-
return
|
|
19826
|
+
return join23(home, "Library", "LaunchAgents", `${engineLabel2(name, org, seat)}.plist`);
|
|
19636
19827
|
}
|
|
19637
19828
|
function engineLogPath2(stateDir, name) {
|
|
19638
|
-
return
|
|
19829
|
+
return join23(stateDir, `${engineSlug(name)}.log`);
|
|
19639
19830
|
}
|
|
19640
19831
|
function engineEventsPath2(stateDir, name) {
|
|
19641
|
-
return
|
|
19832
|
+
return join23(stateDir, `${engineSlug(name)}.events.jsonl`);
|
|
19642
19833
|
}
|
|
19643
19834
|
var xmlEscape4 = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
19644
19835
|
function buildEnginePlist2(o) {
|
|
@@ -19735,7 +19926,7 @@ function readEngines2(dir, suffix, manager, parse) {
|
|
|
19735
19926
|
}
|
|
19736
19927
|
const out = [];
|
|
19737
19928
|
for (const name of names.filter((n) => n.startsWith(`${ENGINE_LABEL2}.`) && n.endsWith(suffix))) {
|
|
19738
|
-
const path =
|
|
19929
|
+
const path = join23(dir, name);
|
|
19739
19930
|
let parsed;
|
|
19740
19931
|
try {
|
|
19741
19932
|
parsed = parse(readFileSync19(path, "utf8"), name);
|
|
@@ -19755,10 +19946,10 @@ function readEngines2(dir, suffix, manager, parse) {
|
|
|
19755
19946
|
}
|
|
19756
19947
|
function installedEngines2(home) {
|
|
19757
19948
|
return [
|
|
19758
|
-
...readEngines2(
|
|
19949
|
+
...readEngines2(join23(home, "Library", "LaunchAgents"), ".plist", "launchd", parseEnginePlist2),
|
|
19759
19950
|
...readEngines2(engineUnitDir(home), ".service", "systemd", (text, file) => {
|
|
19760
19951
|
const parsed = parseEngineUnit(text);
|
|
19761
|
-
return parsed && { label:
|
|
19952
|
+
return parsed && { label: basename6(file, ".service"), ...parsed };
|
|
19762
19953
|
})
|
|
19763
19954
|
];
|
|
19764
19955
|
}
|
|
@@ -19793,7 +19984,7 @@ async function ensureReposDir(o) {
|
|
|
19793
19984
|
return false;
|
|
19794
19985
|
}
|
|
19795
19986
|
const exists = o.exists ?? existsSync18;
|
|
19796
|
-
const missing = dirs.filter((d) => !exists(/^~(\/|$)/.test(d) ?
|
|
19987
|
+
const missing = dirs.filter((d) => !exists(/^~(\/|$)/.test(d) ? join23(o.home, d.slice(1)) : d));
|
|
19797
19988
|
if (missing.length) {
|
|
19798
19989
|
error(`Not a folder on this machine: ${missing.join(", ")}. ${REPOS_DIR_NEEDED}`);
|
|
19799
19990
|
return false;
|
|
@@ -19837,7 +20028,7 @@ function engineInstall2(o) {
|
|
|
19837
20028
|
const label = engineLabel2(parsed.name, parsed.org, seat);
|
|
19838
20029
|
const logPath = engineLogPath2(stateDir, parsed.name);
|
|
19839
20030
|
mkdirSync17(stateDir, { recursive: true, mode: 448 });
|
|
19840
|
-
const sledsArgv = stableArgv2(o.sledsArgv, o.realpath);
|
|
20031
|
+
const sledsArgv = stableArgv2(o.sledsArgv, o.realpath, o.home);
|
|
19841
20032
|
const execPath = sledsArgv[0] ?? process.execPath;
|
|
19842
20033
|
const agentEnv = {
|
|
19843
20034
|
PATH: musherPath(o.home, execPath, env.PATH ?? ""),
|
|
@@ -19889,7 +20080,7 @@ function installUnit2(a) {
|
|
|
19889
20080
|
const log = o.log ?? console.log;
|
|
19890
20081
|
const error = o.error ?? console.error;
|
|
19891
20082
|
const unit = engineUnitPath(o.home, label);
|
|
19892
|
-
const unitName =
|
|
20083
|
+
const unitName = basename6(unit);
|
|
19893
20084
|
const systemctl = (...args) => exec("systemctl", ["--user", ...args]);
|
|
19894
20085
|
mkdirSync17(dirname13(unit), { recursive: true });
|
|
19895
20086
|
if (existsSync18(unit))
|
|
@@ -19899,7 +20090,7 @@ function installUnit2(a) {
|
|
|
19899
20090
|
continue;
|
|
19900
20091
|
if (engineArg2(other.programArgs, "name") !== parsed.name)
|
|
19901
20092
|
continue;
|
|
19902
|
-
systemctl("disable", "--now",
|
|
20093
|
+
systemctl("disable", "--now", basename6(other.plist));
|
|
19903
20094
|
rmSync10(other.plist, { force: true });
|
|
19904
20095
|
log(`replaced ${other.label}, this engine as installed before`);
|
|
19905
20096
|
}
|
|
@@ -19958,13 +20149,13 @@ function engineUninstall2(o) {
|
|
|
19958
20149
|
const unit = file.endsWith(".service");
|
|
19959
20150
|
const exec = o.exec ?? defaultExec2;
|
|
19960
20151
|
if (unit)
|
|
19961
|
-
exec("systemctl", ["--user", "disable", "--now",
|
|
20152
|
+
exec("systemctl", ["--user", "disable", "--now", basename6(file)]);
|
|
19962
20153
|
else
|
|
19963
20154
|
exec("launchctl", ["unload", file]);
|
|
19964
20155
|
rmSync10(file, { force: true });
|
|
19965
20156
|
if (unit)
|
|
19966
20157
|
exec("systemctl", ["--user", "daemon-reload"]);
|
|
19967
|
-
log(`engine:${name} removed: ${
|
|
20158
|
+
log(`engine:${name} removed: ${basename6(file, unit ? ".service" : ".plist")} — its sessions keep running`);
|
|
19968
20159
|
return 0;
|
|
19969
20160
|
}
|
|
19970
20161
|
|
|
@@ -20910,9 +21101,9 @@ init_meter();
|
|
|
20910
21101
|
// src/owed.ts
|
|
20911
21102
|
init_config();
|
|
20912
21103
|
import { existsSync as existsSync22, mkdirSync as mkdirSync18, readFileSync as readFileSync23, renameSync as renameSync7, writeFileSync as writeFileSync20 } from "node:fs";
|
|
20913
|
-
import { dirname as dirname14, join as
|
|
20914
|
-
var owedPath = (home) =>
|
|
20915
|
-
var sessionPath = (home) =>
|
|
21104
|
+
import { dirname as dirname14, join as join24 } from "node:path";
|
|
21105
|
+
var owedPath = (home) => join24(configDir(home), "owed.json");
|
|
21106
|
+
var sessionPath = (home) => join24(configDir(home), "session.json");
|
|
20916
21107
|
var OWED_TTL_MS = 3 * 24 * 60 * 60000;
|
|
20917
21108
|
var str13 = (v) => typeof v === "string" ? v : undefined;
|
|
20918
21109
|
function sourceKey(s) {
|
|
@@ -21066,7 +21257,12 @@ function trackingClient(client, home, now) {
|
|
|
21066
21257
|
function contextFor(deps) {
|
|
21067
21258
|
const src = meterSource(deps.home, runTokenOf(deps.env));
|
|
21068
21259
|
const now = deps.now ?? Date.now;
|
|
21069
|
-
const client = src ? trackingClient(fetchClient({
|
|
21260
|
+
const client = src ? trackingClient(fetchClient({
|
|
21261
|
+
...src,
|
|
21262
|
+
fetchFn: deps.fetchFn,
|
|
21263
|
+
timeoutMs: deps.timeoutMs,
|
|
21264
|
+
version: "0.1.47"
|
|
21265
|
+
}), deps.home, now) : null;
|
|
21070
21266
|
return {
|
|
21071
21267
|
channel: "code",
|
|
21072
21268
|
client,
|
|
@@ -21335,7 +21531,7 @@ var DEVICE_REASONS = {
|
|
|
21335
21531
|
bad_answer: "the proxy gave an answer this CLI does not understand — update it: curl -fsSL sleds.ai/install | sh"
|
|
21336
21532
|
};
|
|
21337
21533
|
function deviceFailureText(reason) {
|
|
21338
|
-
return `Sign-in did not complete: ${DEVICE_REASONS[reason]} Or mint a seat on the dashboard (Settings › Your seat & tools) and run \`sleds init
|
|
21534
|
+
return `Sign-in did not complete: ${DEVICE_REASONS[reason]} Or mint a seat on the dashboard (Settings › Your seat & tools), set it as SLEDS_TOKEN and run \`sleds init\`.`;
|
|
21339
21535
|
}
|
|
21340
21536
|
function parseStart(body) {
|
|
21341
21537
|
if (typeof body !== "object" || body === null)
|
|
@@ -21597,7 +21793,7 @@ var SIGNUP_REASONS = {
|
|
|
21597
21793
|
not_configured: "the proxy is not set up for self-serve signup yet.",
|
|
21598
21794
|
team: "the team needs a name (2–80 characters).",
|
|
21599
21795
|
personal_email: "a team needs a work email — that domain is a personal mailbox. Sign up as an individual instead, or use your company address.",
|
|
21600
|
-
org_exists: "someone at your company already set up SLEDS. Ask them
|
|
21796
|
+
org_exists: "someone at your company already set up SLEDS. Ask them to invite you (Members → invite), then run `sleds init` and sign in through the browser.",
|
|
21601
21797
|
unavailable: "the proxy could not reach its control plane. Try again in a moment.",
|
|
21602
21798
|
unreachable: "could not reach the proxy.",
|
|
21603
21799
|
code: "that code is six digits.",
|
|
@@ -21724,7 +21920,7 @@ var resolveToken = async (o) => {
|
|
|
21724
21920
|
return null;
|
|
21725
21921
|
}
|
|
21726
21922
|
log(`Created ${team} with you as owner (${email}).${credential ? " Your platform key is stored encrypted as the org's upstream key." : " No platform key yet — add one on the dashboard (Admin → Keys) to unlock continue / overnight / switch at a wall."}`);
|
|
21727
|
-
log("Invite your team on the dashboard (Members → invite by email, Admin → Mint a seat); each person runs `sleds init
|
|
21923
|
+
log("Invite your team on the dashboard (Members → invite by email, Admin → Mint a seat); each person runs `sleds init` and signs in through the browser.");
|
|
21728
21924
|
return { token: r.token, source: "signup" };
|
|
21729
21925
|
}
|
|
21730
21926
|
const credential = (await o.prompt("Your Anthropic API key (sk-ant-…, stored encrypted, spends only your account): ")).trim();
|
|
@@ -21748,7 +21944,7 @@ var init = async (o) => {
|
|
|
21748
21944
|
}
|
|
21749
21945
|
const resolved = await resolveToken(o);
|
|
21750
21946
|
if (!resolved) {
|
|
21751
|
-
error(o.signup ? "Signup did not complete. Nothing was changed." : "No seat token. Run `sleds init` without --non-interactive to sign in through the browser, or
|
|
21947
|
+
error(o.signup ? "Signup did not complete. Nothing was changed." : "No seat token. Run `sleds init` without --non-interactive to sign in through the browser, or set SLEDS_TOKEN (never the token on the command line).");
|
|
21752
21948
|
return 2;
|
|
21753
21949
|
}
|
|
21754
21950
|
if (!isSeatToken(resolved.token)) {
|
|
@@ -22464,7 +22660,7 @@ var on = (o) => {
|
|
|
22464
22660
|
return 2;
|
|
22465
22661
|
}
|
|
22466
22662
|
if (!isSeatToken(token)) {
|
|
22467
|
-
error("Saved token is not a sled_ token. Run `sleds
|
|
22663
|
+
error("Saved token is not a sled_ token. Run `sleds login` to sign in again.");
|
|
22468
22664
|
return 2;
|
|
22469
22665
|
}
|
|
22470
22666
|
if (cfg.org && !cfg.org.capabilities.upstreamKey) {
|
|
@@ -22632,7 +22828,7 @@ var orgCmd = (o) => {
|
|
|
22632
22828
|
init_src();
|
|
22633
22829
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
22634
22830
|
import { writeFileSync as writeFileSync23 } from "node:fs";
|
|
22635
|
-
import { join as
|
|
22831
|
+
import { join as join25 } from "node:path";
|
|
22636
22832
|
function packFileName(key) {
|
|
22637
22833
|
return `pack-${slugify(key, 80) || "item"}.md`;
|
|
22638
22834
|
}
|
|
@@ -22660,7 +22856,7 @@ var packCmd = async (o) => {
|
|
|
22660
22856
|
log(r.text);
|
|
22661
22857
|
return 0;
|
|
22662
22858
|
}
|
|
22663
|
-
const path =
|
|
22859
|
+
const path = join25(o.cwd ?? process.cwd(), packFileName(key));
|
|
22664
22860
|
(o.write ?? ((p, t) => writeFileSync23(p, t.endsWith(`
|
|
22665
22861
|
`) ? t : `${t}
|
|
22666
22862
|
`)))(path, r.text);
|
|
@@ -22919,7 +23115,9 @@ function parseVerbArgs(argv, allowed) {
|
|
|
22919
23115
|
if (flag === "name")
|
|
22920
23116
|
out.name = value;
|
|
22921
23117
|
i++;
|
|
22922
|
-
} else if (
|
|
23118
|
+
} else if (a.startsWith("-"))
|
|
23119
|
+
return { error: `unknown flag ${a}` };
|
|
23120
|
+
else if (out.key === undefined)
|
|
22923
23121
|
out.key = a;
|
|
22924
23122
|
else
|
|
22925
23123
|
return { error: `one item at a time — "${a}" is extra` };
|
|
@@ -23101,7 +23299,7 @@ async function proposeCmd(o, argv) {
|
|
|
23101
23299
|
log(`- ${w}`);
|
|
23102
23300
|
const shown = typeof r.json?.key === "string" ? r.json.key : a.key;
|
|
23103
23301
|
const text = typeof r.json?.text === "string" ? r.json.text : "";
|
|
23104
|
-
log(text.replace(/\n*Nothing runs until a person says yes:[^\n]*$/, "") || `${shown} · route
|
|
23302
|
+
log(text.replace(/\n*Nothing runs until a person says yes:[^\n]*$/, "") || `${shown} · route planned, not filed`);
|
|
23105
23303
|
log("");
|
|
23106
23304
|
log(`Nothing runs until a person approves it: \`sleds route approve ${shown}\`, or Approve in the app.`);
|
|
23107
23305
|
});
|
|
@@ -23143,7 +23341,7 @@ async function approveCmd(o, argv) {
|
|
|
23143
23341
|
return said(o, a.key, a.json, r, () => log(approvedLine(a.key, r.json ?? {})));
|
|
23144
23342
|
}
|
|
23145
23343
|
async function redraftCmd(o, argv) {
|
|
23146
|
-
return oneVerb(o, argv, REDRAFT_USAGE, { draft: "retry" }, "nothing
|
|
23344
|
+
return oneVerb(o, argv, REDRAFT_USAGE, { draft: "retry" }, "nothing planned again", (key) => redraftLine(key));
|
|
23147
23345
|
}
|
|
23148
23346
|
async function singleCmd(o, argv) {
|
|
23149
23347
|
return oneVerb(o, argv, SINGLE_USAGE, { single: true }, "nothing changed", (key) => singleLine(key));
|
|
@@ -23171,17 +23369,17 @@ async function oneVerb(o, argv, usage, body, unreachable, line) {
|
|
|
23171
23369
|
return said(o, a.key, a.json, r, () => log(line(shown)));
|
|
23172
23370
|
}
|
|
23173
23371
|
function redraftLine(key) {
|
|
23174
|
-
return `${key}
|
|
23372
|
+
return `${key} plan again asked — the engine plans its route on its next check`;
|
|
23175
23373
|
}
|
|
23176
23374
|
function singleLine(key) {
|
|
23177
|
-
return `${key} runs as one node — it is not
|
|
23375
|
+
return `${key} runs as one node — it is not planned again`;
|
|
23178
23376
|
}
|
|
23179
23377
|
function answeredLine(key, route, held) {
|
|
23180
23378
|
const nodes = Array.isArray(held) && held.length ? ` (${held.join(", ")})` : "";
|
|
23181
23379
|
if (route === "accept")
|
|
23182
23380
|
return `${key}: change accepted — what it held${nodes} waits until the route is re-filed`;
|
|
23183
23381
|
if (route === "redraft")
|
|
23184
|
-
return `${key}:
|
|
23382
|
+
return `${key}: plan again asked — what it held${nodes} waits until the route is re-filed`;
|
|
23185
23383
|
if (route === "keep")
|
|
23186
23384
|
return `${key}: route kept as filed — what it held is released`;
|
|
23187
23385
|
return `${key}: answered — what it held is released`;
|
|
@@ -23258,12 +23456,24 @@ function lookToReady(route, id) {
|
|
|
23258
23456
|
return { error: `no decision ${id} on this item` };
|
|
23259
23457
|
if (d.kind !== "look")
|
|
23260
23458
|
return { error: `decision ${id} is not a look — --ready marks a look` };
|
|
23459
|
+
if (d.state === "superseded" || d.state === "answered")
|
|
23460
|
+
return { settled: `decision ${id} is ${d.state}` };
|
|
23261
23461
|
if (d.state !== "escalated")
|
|
23262
23462
|
return { error: `decision ${id} is ${String(d.state)} — not a look you owe` };
|
|
23263
23463
|
const about = d.about && typeof d.about === "object" ? d.about : {};
|
|
23264
23464
|
const pr = Array.isArray(about.prs) ? about.prs.find((p) => typeof p === "string" && p) : undefined;
|
|
23265
23465
|
return typeof pr === "string" ? { pr } : { error: `decision ${id} names no PR` };
|
|
23266
23466
|
}
|
|
23467
|
+
function prLookState(stdout) {
|
|
23468
|
+
try {
|
|
23469
|
+
const j = JSON.parse(stdout);
|
|
23470
|
+
if (!j || typeof j.isDraft !== "boolean" || typeof j.state !== "string")
|
|
23471
|
+
return null;
|
|
23472
|
+
return { isDraft: j.isDraft, state: j.state };
|
|
23473
|
+
} catch {
|
|
23474
|
+
return null;
|
|
23475
|
+
}
|
|
23476
|
+
}
|
|
23267
23477
|
async function readyCmd(o, argv) {
|
|
23268
23478
|
const log = o.log ?? console.log;
|
|
23269
23479
|
const error = o.error ?? console.error;
|
|
@@ -23284,6 +23494,13 @@ async function readyCmd(o, argv) {
|
|
|
23284
23494
|
error(reader.error);
|
|
23285
23495
|
return 1;
|
|
23286
23496
|
}
|
|
23497
|
+
const settled = (why) => {
|
|
23498
|
+
if (json)
|
|
23499
|
+
log(JSON.stringify({ ok: true, settled: why }));
|
|
23500
|
+
else
|
|
23501
|
+
log(`${key}: the look is already settled — nothing to do`);
|
|
23502
|
+
return 0;
|
|
23503
|
+
};
|
|
23287
23504
|
const route = await reader.read(key).catch((e) => {
|
|
23288
23505
|
error(e instanceof Error ? e.message : String(e));
|
|
23289
23506
|
return;
|
|
@@ -23295,12 +23512,25 @@ async function readyCmd(o, argv) {
|
|
|
23295
23512
|
error(`${key}: ${look.error}`);
|
|
23296
23513
|
return 1;
|
|
23297
23514
|
}
|
|
23298
|
-
|
|
23299
|
-
|
|
23300
|
-
|
|
23515
|
+
if ("settled" in look)
|
|
23516
|
+
return settled(look.settled);
|
|
23517
|
+
const exec = o.exec ?? defaultExec;
|
|
23518
|
+
const view = exec("gh", ["pr", "view", look.pr, "--json", "isDraft,state"]);
|
|
23519
|
+
const pr = view.status === 0 ? prLookState(view.stdout) : null;
|
|
23520
|
+
if (!pr) {
|
|
23521
|
+
error(view.stderr.trim() || (view.status === 0 ? `gh pr view ${look.pr} said nothing readable` : `gh pr view ${look.pr} exited ${view.status}`));
|
|
23301
23522
|
error(`${key}: the look is not answered`);
|
|
23302
23523
|
return 1;
|
|
23303
23524
|
}
|
|
23525
|
+
const draft = pr.state === "OPEN" && pr.isDraft;
|
|
23526
|
+
if (draft) {
|
|
23527
|
+
const gh = exec("gh", ["pr", "ready", look.pr]);
|
|
23528
|
+
if (gh.status !== 0) {
|
|
23529
|
+
error(gh.stderr.trim() || `gh pr ready ${look.pr} exited ${gh.status}`);
|
|
23530
|
+
error(`${key}: the look is not answered`);
|
|
23531
|
+
return 1;
|
|
23532
|
+
}
|
|
23533
|
+
}
|
|
23304
23534
|
const r = await client.postFull("/proxy/route/decision", {
|
|
23305
23535
|
project: key,
|
|
23306
23536
|
id,
|
|
@@ -23310,7 +23540,13 @@ async function readyCmd(o, argv) {
|
|
|
23310
23540
|
error(`${key}: ${look.pr} is ready for review, but SLEDS is unreachable — the look is not answered`);
|
|
23311
23541
|
return 1;
|
|
23312
23542
|
}
|
|
23313
|
-
|
|
23543
|
+
if (r.status >= 300 || r.json?.ok === false) {
|
|
23544
|
+
const again = await reader.read(key).catch(() => null);
|
|
23545
|
+
const now = lookToReady(again ?? null, id);
|
|
23546
|
+
if ("settled" in now)
|
|
23547
|
+
return settled(now.settled);
|
|
23548
|
+
}
|
|
23549
|
+
return said(o, key, json, r, () => log(draft ? `${key}: ${look.pr} marked ready for review — the look is answered` : `${key}: ${look.pr} is ${pr.state === "OPEN" ? "already ready for review" : pr.state.toLowerCase()} — the look is answered`));
|
|
23314
23550
|
}
|
|
23315
23551
|
var DECISIONS_USAGE = "usage: sleds route decisions [<key>] [--flagged] [--json]";
|
|
23316
23552
|
function decisionsLines(raw) {
|
|
@@ -23323,7 +23559,7 @@ function decisionsLines(raw) {
|
|
|
23323
23559
|
const first = q.replace(/\s+/g, " ").trim().slice(0, 100);
|
|
23324
23560
|
const where = [d.project && !j.project ? d.project : null, d.node].filter(Boolean).join("/");
|
|
23325
23561
|
const flag = d.flagged ? " · decided for you" : "";
|
|
23326
|
-
const pending = d.redraftPending ? " ·
|
|
23562
|
+
const pending = d.redraftPending ? " · plan again pending" : "";
|
|
23327
23563
|
return `${String(d.state)}${flag}${pending} ${where || "—"} ${first} [${String(d.id)}]`;
|
|
23328
23564
|
});
|
|
23329
23565
|
}
|
|
@@ -23539,12 +23775,14 @@ function routeReader(o, org) {
|
|
|
23539
23775
|
read: (k) => readOrSay(client, `/proxy/route?q=${encodeURIComponent(k)}`, k)
|
|
23540
23776
|
};
|
|
23541
23777
|
}
|
|
23542
|
-
var SLED_USAGE = "usage: sleds sled --json | sleds sled top <KEY>";
|
|
23778
|
+
var SLED_USAGE = "usage: sleds sled --json | sleds sled top <KEY> | sleds sled order <KEY>…";
|
|
23543
23779
|
async function sledCmd(o) {
|
|
23544
23780
|
const log = o.log ?? console.log;
|
|
23545
23781
|
const error = o.error ?? console.error;
|
|
23546
23782
|
const top = o.argv[0] === "top" && o.argv.length === 2 && !o.argv[1]?.startsWith("-");
|
|
23547
|
-
|
|
23783
|
+
const keys = o.argv.slice(1);
|
|
23784
|
+
const order = o.argv[0] === "order" && keys.length > 0 && keys.every((k) => k.trim() && !k.startsWith("-"));
|
|
23785
|
+
if (!top && !order && (o.argv.length !== 1 || o.argv[0] !== "--json")) {
|
|
23548
23786
|
error(SLED_USAGE);
|
|
23549
23787
|
return 2;
|
|
23550
23788
|
}
|
|
@@ -23555,6 +23793,8 @@ async function sledCmd(o) {
|
|
|
23555
23793
|
}
|
|
23556
23794
|
if (top)
|
|
23557
23795
|
return sledTop(client, o.argv[1], log, error);
|
|
23796
|
+
if (order)
|
|
23797
|
+
return sledOrder(client, keys, log, error);
|
|
23558
23798
|
try {
|
|
23559
23799
|
log(JSON.stringify(await readOrSay(client, "/proxy/sled", "the sled")));
|
|
23560
23800
|
return 0;
|
|
@@ -23576,6 +23816,19 @@ async function sledTop(client, key, log, error) {
|
|
|
23576
23816
|
log(`${typeof r.json?.key === "string" ? r.json.key : key} is first on your sled`);
|
|
23577
23817
|
return 0;
|
|
23578
23818
|
}
|
|
23819
|
+
async function sledOrder(client, keys, log, error) {
|
|
23820
|
+
const r = await client.postFull("/proxy/sled/order", { order: keys });
|
|
23821
|
+
if (!r) {
|
|
23822
|
+
error("SLEDS unreachable — the sled is unchanged");
|
|
23823
|
+
return 1;
|
|
23824
|
+
}
|
|
23825
|
+
if (r.status >= 300 || r.json?.ok === false) {
|
|
23826
|
+
error(typeof r.json?.error === "string" ? r.json.error : `sled order: HTTP ${r.status}`);
|
|
23827
|
+
return 1;
|
|
23828
|
+
}
|
|
23829
|
+
log(`${typeof r.json?.ordered === "number" ? r.json.ordered : keys.length} ordered on your sled`);
|
|
23830
|
+
return 0;
|
|
23831
|
+
}
|
|
23579
23832
|
|
|
23580
23833
|
// src/commands/run.ts
|
|
23581
23834
|
init_config();
|
|
@@ -23681,12 +23934,12 @@ var seatEvent = async (o) => {
|
|
|
23681
23934
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
23682
23935
|
import { existsSync as existsSync26, mkdirSync as mkdirSync22, readFileSync as readFileSync28, readdirSync as readdirSync5, rmSync as rmSync16, writeFileSync as writeFileSync25 } from "node:fs";
|
|
23683
23936
|
import { platform as platform2 } from "node:os";
|
|
23684
|
-
import { dirname as dirname17, join as
|
|
23937
|
+
import { dirname as dirname17, join as join27 } from "node:path";
|
|
23685
23938
|
|
|
23686
23939
|
// src/cookieDb.ts
|
|
23687
23940
|
import { copyFileSync, rmSync as rmSync15 } from "node:fs";
|
|
23688
23941
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
23689
|
-
import { join as
|
|
23942
|
+
import { join as join26 } from "node:path";
|
|
23690
23943
|
var QUERY = "SELECT name, hex(encrypted_value) AS ev FROM cookies WHERE host_key LIKE '%claude.ai%'";
|
|
23691
23944
|
var isBun = () => typeof globalThis.Bun !== "undefined";
|
|
23692
23945
|
async function queryRows(dbPath) {
|
|
@@ -23715,7 +23968,7 @@ function nodeSqlite() {
|
|
|
23715
23968
|
return mod;
|
|
23716
23969
|
}
|
|
23717
23970
|
async function readCookieRows(dbPath) {
|
|
23718
|
-
const copy =
|
|
23971
|
+
const copy = join26(tmpdir2(), `sleds-cookies-${process.pid}-${Date.now()}.sqlite`);
|
|
23719
23972
|
copyFileSync(dbPath, copy);
|
|
23720
23973
|
try {
|
|
23721
23974
|
const rows = await queryRows(copy);
|
|
@@ -24008,7 +24261,7 @@ function findFile(root, name) {
|
|
|
24008
24261
|
continue;
|
|
24009
24262
|
}
|
|
24010
24263
|
for (const e of entries) {
|
|
24011
|
-
const p =
|
|
24264
|
+
const p = join27(dir, e.name);
|
|
24012
24265
|
if (e.isDirectory())
|
|
24013
24266
|
stack.push(p);
|
|
24014
24267
|
else if (e.name === name)
|
|
@@ -24019,7 +24272,7 @@ function findFile(root, name) {
|
|
|
24019
24272
|
}
|
|
24020
24273
|
function findCookieDb(home, source) {
|
|
24021
24274
|
const b = BROWSERS[source.browser];
|
|
24022
|
-
const root =
|
|
24275
|
+
const root = join27(home, APP_SUPPORT, b.appDir);
|
|
24023
24276
|
if (!existsSync26(root))
|
|
24024
24277
|
throw new Error(`no ${source.browser} data at ${root} (is it installed?)`);
|
|
24025
24278
|
if (!b.profiled) {
|
|
@@ -24028,7 +24281,7 @@ function findCookieDb(home, source) {
|
|
|
24028
24281
|
throw new Error(`no cookie store under ${root}`);
|
|
24029
24282
|
return db;
|
|
24030
24283
|
}
|
|
24031
|
-
const localStatePath =
|
|
24284
|
+
const localStatePath = join27(root, "Local State");
|
|
24032
24285
|
const localState = existsSync26(localStatePath) ? readFileSync28(localStatePath, "utf8") : null;
|
|
24033
24286
|
const wanted = source.profile ?? "Default";
|
|
24034
24287
|
const { dir, ambiguous } = resolveProfileDir(localState, wanted);
|
|
@@ -24036,7 +24289,7 @@ function findCookieDb(home, source) {
|
|
|
24036
24289
|
throw new Error(`"${wanted}" names ${ambiguous.length} ${source.browser} profiles (${ambiguous.join(", ")}) — pass the directory or the account email instead`);
|
|
24037
24290
|
if (!dir)
|
|
24038
24291
|
throw new Error(`no ${source.browser} profile named "${wanted}" (check chrome://version)`);
|
|
24039
|
-
const db = cookieDbCandidates(
|
|
24292
|
+
const db = cookieDbCandidates(join27(root, dir)).find((p) => existsSync26(p));
|
|
24040
24293
|
if (!db)
|
|
24041
24294
|
throw new Error(`profile "${dir}" has no cookie store yet (open claude.ai in it once)`);
|
|
24042
24295
|
return db;
|
|
@@ -24078,11 +24331,11 @@ function fetchSeatUsage(jar, org, now, run) {
|
|
|
24078
24331
|
return { usage: null, status };
|
|
24079
24332
|
}
|
|
24080
24333
|
}
|
|
24081
|
-
function launchAgentPlist(
|
|
24334
|
+
function launchAgentPlist(argv, home, source) {
|
|
24082
24335
|
const label = launchLabel(source);
|
|
24083
|
-
const log =
|
|
24336
|
+
const log = join27(home, ".config", "sleds", `${label.slice("ai.sleds.".length)}.log`);
|
|
24084
24337
|
const esc = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
24085
|
-
const args = [
|
|
24338
|
+
const args = [...argv, "seat-sync", ...sourceArgs(source)].map((a) => ` <string>${esc(a)}</string>`).join(`
|
|
24086
24339
|
`);
|
|
24087
24340
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
24088
24341
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -24102,16 +24355,14 @@ ${args}
|
|
|
24102
24355
|
`;
|
|
24103
24356
|
}
|
|
24104
24357
|
function plistPath2(home, source) {
|
|
24105
|
-
return
|
|
24358
|
+
return join27(home, "Library", "LaunchAgents", `${launchLabel(source)}.plist`);
|
|
24106
24359
|
}
|
|
24107
|
-
function install(home, argv, source, log) {
|
|
24108
|
-
|
|
24109
|
-
|
|
24110
|
-
if (!script) {
|
|
24111
|
-
log("cannot resolve the sleds script path to install the timer");
|
|
24360
|
+
function install(home, argv, source, log, launchctl) {
|
|
24361
|
+
if (!argv[0]) {
|
|
24362
|
+
log("cannot resolve the sleds command to install the timer");
|
|
24112
24363
|
return 1;
|
|
24113
24364
|
}
|
|
24114
|
-
const dir =
|
|
24365
|
+
const dir = join27(home, "Library", "LaunchAgents");
|
|
24115
24366
|
mkdirSync22(dir, { recursive: true });
|
|
24116
24367
|
const path = plistPath2(home, source);
|
|
24117
24368
|
const tokenPath = seatTokenPath(home, source);
|
|
@@ -24121,11 +24372,11 @@ function install(home, argv, source, log) {
|
|
|
24121
24372
|
writeFileSync25(tokenPath, `${source.token}
|
|
24122
24373
|
`, { mode: 384 });
|
|
24123
24374
|
}
|
|
24124
|
-
writeFileSync25(path, launchAgentPlist(
|
|
24375
|
+
writeFileSync25(path, launchAgentPlist(argv, home, source), { mode: 384 });
|
|
24125
24376
|
try {
|
|
24126
|
-
|
|
24377
|
+
launchctl(["unload", path]);
|
|
24127
24378
|
} catch {}
|
|
24128
|
-
|
|
24379
|
+
launchctl(["load", "-w", path]);
|
|
24129
24380
|
log(`seat-sync timer installed (every ${SYNC_INTERVAL_S / 60} min) → ${path}`);
|
|
24130
24381
|
return 0;
|
|
24131
24382
|
}
|
|
@@ -24150,7 +24401,9 @@ var seatSync = async (o) => {
|
|
|
24150
24401
|
if (source.uninstall)
|
|
24151
24402
|
return uninstall(o.home, source, log);
|
|
24152
24403
|
if (source.install)
|
|
24153
|
-
return install(o.home, [process.execPath, process.argv[1] ?? ""], source, log)
|
|
24404
|
+
return install(o.home, o.sledsArgv ?? [process.execPath, process.argv[1] ?? ""], source, log, o.launchctl ?? ((args) => {
|
|
24405
|
+
execFileSync5("launchctl", args, args[0] === "unload" ? { stdio: "ignore" } : {});
|
|
24406
|
+
}));
|
|
24154
24407
|
if (platform2() !== "darwin" && !o.readCookieRows) {
|
|
24155
24408
|
log("seat-sync is macOS-only for now.");
|
|
24156
24409
|
return 2;
|
|
@@ -24293,7 +24546,7 @@ var sessionEvent = async (o) => {
|
|
|
24293
24546
|
// src/commands/specEvent.ts
|
|
24294
24547
|
init_meter();
|
|
24295
24548
|
import { readFileSync as readFileSync29, statSync as statSync2 } from "node:fs";
|
|
24296
|
-
import { basename as
|
|
24549
|
+
import { basename as basename7, isAbsolute as isAbsolute4, relative } from "node:path";
|
|
24297
24550
|
var HOOK_STDIN_TIMEOUT_MS3 = 1000;
|
|
24298
24551
|
var ESTIMATE_TIMEOUT_MS = 4000;
|
|
24299
24552
|
var MIN_SPEC_CHARS = 200;
|
|
@@ -24306,12 +24559,12 @@ function isSpecPath(path) {
|
|
|
24306
24559
|
return false;
|
|
24307
24560
|
if (NOT_SPEC.test(path))
|
|
24308
24561
|
return false;
|
|
24309
|
-
return SPEC_DIRS.test(path) || SPEC_NAMES.test(
|
|
24562
|
+
return SPEC_DIRS.test(path) || SPEC_NAMES.test(basename7(path));
|
|
24310
24563
|
}
|
|
24311
24564
|
function specTitle(body, path) {
|
|
24312
24565
|
const m = /^#\s+(.+?)\s*$/m.exec(body);
|
|
24313
24566
|
const t = m?.[1]?.trim();
|
|
24314
|
-
return (t && t.length > 0 ? t :
|
|
24567
|
+
return (t && t.length > 0 ? t : basename7(path).replace(/\.(md|mdx)$/i, "")).slice(0, 120);
|
|
24315
24568
|
}
|
|
24316
24569
|
function looksLikeSpec(body) {
|
|
24317
24570
|
if (body.trim().length < MIN_SPEC_CHARS)
|
|
@@ -24369,7 +24622,7 @@ var specEvent = async (o) => {
|
|
|
24369
24622
|
const spec = {
|
|
24370
24623
|
title: specTitle(body, input.filePath),
|
|
24371
24624
|
body: body.slice(0, MAX_SPEC_CHARS),
|
|
24372
|
-
repoHint: input.cwd ?
|
|
24625
|
+
repoHint: input.cwd ? basename7(input.cwd) : undefined
|
|
24373
24626
|
};
|
|
24374
24627
|
try {
|
|
24375
24628
|
const res = await (o.fetchFn ?? fetch)(`${src.proxyUrl}/proxy/estimate`, {
|
|
@@ -25089,12 +25342,12 @@ var webhooksCmd = async (o) => {
|
|
|
25089
25342
|
// src/config.ts
|
|
25090
25343
|
init_settings();
|
|
25091
25344
|
import { chmodSync as chmodSync7, existsSync as existsSync30, mkdirSync as mkdirSync23, readFileSync as readFileSync31, renameSync as renameSync9, writeFileSync as writeFileSync26 } from "node:fs";
|
|
25092
|
-
import { join as
|
|
25345
|
+
import { join as join28, resolve as resolve11 } from "node:path";
|
|
25093
25346
|
var configDir2 = (home, env = process.env) => {
|
|
25094
25347
|
const o = env.SLEDS_HOME?.trim();
|
|
25095
|
-
return o ? resolve11(home, o) :
|
|
25348
|
+
return o ? resolve11(home, o) : join28(home, ".config", "sleds");
|
|
25096
25349
|
};
|
|
25097
|
-
var configPath2 = (home) =>
|
|
25350
|
+
var configPath2 = (home) => join28(configDir2(home), "config.json");
|
|
25098
25351
|
var isObject17 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
25099
25352
|
var optString2 = (v) => typeof v === "string" ? v : undefined;
|
|
25100
25353
|
var parsePriorEnv2 = (v) => {
|
|
@@ -25270,6 +25523,12 @@ function runnerFor3(name, exec = defaultExec, o = {}) {
|
|
|
25270
25523
|
}
|
|
25271
25524
|
}
|
|
25272
25525
|
|
|
25526
|
+
// src/runtime.ts
|
|
25527
|
+
import { homedir as homedir2 } from "node:os";
|
|
25528
|
+
import { join as join29, win32 as win322 } from "node:path";
|
|
25529
|
+
var isCompiled = (argv1 = process.argv[1]) => Boolean(argv1 && (argv1.startsWith("/$bunfs/") || argv1.startsWith("B:\\~BUN\\")));
|
|
25530
|
+
var sledsLink2 = (home = homedir2(), platform = process.platform) => platform === "win32" ? win322.join(process.env.LOCALAPPDATA ?? win322.join(home, "AppData", "Local"), "sleds", "bin", "sleds.exe") : join29(home, ".sleds", "bin", "sleds");
|
|
25531
|
+
|
|
25273
25532
|
// src/schedule.ts
|
|
25274
25533
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
25275
25534
|
var defaultExec5 = (cmd, args) => {
|
|
@@ -25280,7 +25539,7 @@ var defaultExec5 = (cmd, args) => {
|
|
|
25280
25539
|
};
|
|
25281
25540
|
|
|
25282
25541
|
// src/settings.ts
|
|
25283
|
-
import { dirname as dirname18, join as
|
|
25542
|
+
import { dirname as dirname18, join as join30, resolve as resolve12 } from "node:path";
|
|
25284
25543
|
var withSeatEnv2 = (command, home, env = process.env, org) => {
|
|
25285
25544
|
const parts = [];
|
|
25286
25545
|
const sh = env.SLEDS_HOME?.trim();
|
|
@@ -25376,6 +25635,7 @@ commands:
|
|
|
25376
25635
|
Token from SLEDS_DEPLOY_TOKEN (Settings \u203A Deploys). SLEDS down never fails a release.
|
|
25377
25636
|
sled --json What is on your sled (mine with each route, proposed, sent), for a front end.
|
|
25378
25637
|
sleds sled top KEY put KEY first on your sled; the engine picks it next
|
|
25638
|
+
sleds sled order KEY\u2026 those items in this order, in the places they hold; the rest stay
|
|
25379
25639
|
route <key> Print an item's route: its nodes, what each waits on, what is ready, where each
|
|
25380
25640
|
run can be watched.
|
|
25381
25641
|
--dot Graphviz instead: \`sleds route QW-142 --dot | dot -Tpng -o route.png\`
|
|
@@ -25385,10 +25645,10 @@ commands:
|
|
|
25385
25645
|
disarms; --name <engine> sends it to that engine; --json)
|
|
25386
25646
|
answer <key>/<node> answer a parked node: the words after it, or --stdin; it
|
|
25387
25647
|
goes back to ready and the engine takes it (--json)
|
|
25388
|
-
propose <key> hold a
|
|
25389
|
-
nothing (a
|
|
25648
|
+
propose <key> hold a planned route on the item for a person's yes, filing
|
|
25649
|
+
nothing (a planning session with no connector): --file
|
|
25390
25650
|
<nodes.json> or --stdin, --name <engine> (--json)
|
|
25391
|
-
approve <key> a person's yes to a
|
|
25651
|
+
approve <key> a person's yes to a planned route: files it and, under
|
|
25392
25652
|
Pickup: Auto, arms it; --file <nodes.json> approves an
|
|
25393
25653
|
edited set instead (--json)
|
|
25394
25654
|
run <key> run the engine for this one item until its route lands
|
|
@@ -25424,8 +25684,8 @@ commands:
|
|
|
25424
25684
|
high, xhigh or max. With --agent, a claude command gets it;
|
|
25425
25685
|
another runs as given and the engine says so
|
|
25426
25686
|
--decider-effort <e> the effort every answerer launches with; default the node's
|
|
25427
|
-
--drafter-model <id> the model a
|
|
25428
|
-
--drafter-effort <e> the effort a
|
|
25687
|
+
--drafter-model <id> the model a planning session launches with; default the node's
|
|
25688
|
+
--drafter-effort <e> the effort a planning session launches with; default the node's
|
|
25429
25689
|
--pr-title '<template>' the PR title the session must use: {key} {ticket} {item}
|
|
25430
25690
|
{node} {title}, e.g. 'feat: [{key}] {title}'
|
|
25431
25691
|
Flags left out come from your engine profile in SLEDS (Settings); with Pickup:
|
|
@@ -25552,14 +25812,20 @@ var hookStdin = async () => {
|
|
|
25552
25812
|
const text = await readStdin2(300);
|
|
25553
25813
|
return text.trim() ? text : undefined;
|
|
25554
25814
|
};
|
|
25555
|
-
var sledsArgv = (execPath = process.execPath, script = process.argv[1], realpath
|
|
25815
|
+
var sledsArgv = (execPath = process.execPath, script = process.argv[1], realpath, o = {}) => {
|
|
25816
|
+
if (isCompiled(script)) {
|
|
25817
|
+
const link = sledsLink2(o.home);
|
|
25818
|
+
return stableArgv2([(o.exists ?? existsSync31)(link) ? link : execPath], realpath, o.home);
|
|
25819
|
+
}
|
|
25820
|
+
return stableArgv2(script ? [execPath, script] : [execPath], realpath, o.home);
|
|
25821
|
+
};
|
|
25556
25822
|
var shellQuote = (s) => /^[\w./-]+$/.test(s) ? s : `'${s.replace(/'/g, "'\\''")}'`;
|
|
25557
|
-
var statusLineCommand = (argv, home =
|
|
25558
|
-
var seatEventCommand = (argv, home =
|
|
25559
|
-
var promptEventCommand = (argv, home =
|
|
25560
|
-
var sessionEventCommand = (argv, home =
|
|
25561
|
-
var stopEventCommand = (argv, home =
|
|
25562
|
-
var specEventCommand = (argv, home =
|
|
25823
|
+
var statusLineCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "statusline"].map(shellQuote).join(" "), home);
|
|
25824
|
+
var seatEventCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "seat-event"].map(shellQuote).join(" "), home);
|
|
25825
|
+
var promptEventCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "prompt-event"].map(shellQuote).join(" "), home);
|
|
25826
|
+
var sessionEventCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "session-event"].map(shellQuote).join(" "), home);
|
|
25827
|
+
var stopEventCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "stop-event"].map(shellQuote).join(" "), home);
|
|
25828
|
+
var specEventCommand = (argv, home = homedir3()) => withSeatEnv2([...argv, "spec-event"].map(shellQuote).join(" "), home);
|
|
25563
25829
|
var mcpFlag = (flags) => flags["no-mcp"] === true ? false : flags.mcp === true ? true : undefined;
|
|
25564
25830
|
var main = async (argv) => {
|
|
25565
25831
|
const { cmd, flags } = parseArgs(argv);
|
|
@@ -25567,7 +25833,7 @@ var main = async (argv) => {
|
|
|
25567
25833
|
console.log(commandUsage(cmd));
|
|
25568
25834
|
return 0;
|
|
25569
25835
|
}
|
|
25570
|
-
const home =
|
|
25836
|
+
const home = homedir3();
|
|
25571
25837
|
const scheduler = {
|
|
25572
25838
|
platform: platform3(),
|
|
25573
25839
|
home,
|
|
@@ -25777,7 +26043,7 @@ var main = async (argv) => {
|
|
|
25777
26043
|
case "mcp":
|
|
25778
26044
|
return mcp({ home });
|
|
25779
26045
|
case "seat-sync":
|
|
25780
|
-
return seatSync({ home, argv: process.argv.slice(3) });
|
|
26046
|
+
return seatSync({ home, argv: process.argv.slice(3), sledsArgv: sledsArgv() });
|
|
25781
26047
|
case "statusline":
|
|
25782
26048
|
return statusline({ home });
|
|
25783
26049
|
case "help":
|
|
@@ -25790,7 +26056,7 @@ ${renderHelpText(argv[1])}`);
|
|
|
25790
26056
|
case "version":
|
|
25791
26057
|
case "--version":
|
|
25792
26058
|
case "-v":
|
|
25793
|
-
console.log("sleds 0.1.
|
|
26059
|
+
console.log("sleds 0.1.47");
|
|
25794
26060
|
return 0;
|
|
25795
26061
|
default:
|
|
25796
26062
|
console.error(`unknown command: ${cmd}
|