@archme/cli 0.16.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +357 -186
- package/package.json +1 -1
- package/sandbox-image.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8649,11 +8649,11 @@ async function findKey(supabaseUrl, userId) {
|
|
|
8649
8649
|
return (await listKeys(supabaseUrl)).find((k) => k.user_id === userId) ?? null;
|
|
8650
8650
|
}
|
|
8651
8651
|
async function saveKey(supabaseUrl, toSave) {
|
|
8652
|
-
const
|
|
8652
|
+
const saved2 = { ...toSave, saved_at: (/* @__PURE__ */ new Date()).toISOString() };
|
|
8653
8653
|
return withRingLock(async () => {
|
|
8654
|
-
const others = (await readEntries()).filter((k) => !isFor(k, supabaseUrl,
|
|
8655
|
-
await writeEntries([...others, { ...
|
|
8656
|
-
return
|
|
8654
|
+
const others = (await readEntries()).filter((k) => !isFor(k, supabaseUrl, saved2.user_id));
|
|
8655
|
+
await writeEntries([...others, { ...saved2, supabase_url: supabaseUrl }]);
|
|
8656
|
+
return saved2;
|
|
8657
8657
|
});
|
|
8658
8658
|
}
|
|
8659
8659
|
async function forgetKey(supabaseUrl, userId) {
|
|
@@ -9316,10 +9316,10 @@ async function mintKeyedAccount(deps) {
|
|
|
9316
9316
|
if (res.status !== 200 || !parsed || !data.user_id) {
|
|
9317
9317
|
throw new LoginError(`Could not create an account (${res.status}): ${redactKey(res.data)}`);
|
|
9318
9318
|
}
|
|
9319
|
-
let
|
|
9319
|
+
let saved2 = false;
|
|
9320
9320
|
try {
|
|
9321
9321
|
await deps.saveKey(deps.supabaseUrl, { user_id: data.user_id, key: data.key, handle: parsed.handle });
|
|
9322
|
-
|
|
9322
|
+
saved2 = true;
|
|
9323
9323
|
} catch (err4) {
|
|
9324
9324
|
deps.log(`! Created ${parsed.handle}, but its key could not be written to ${deps.keyRingPath}: ${err4 instanceof Error ? err4.message : String(err4)}`);
|
|
9325
9325
|
deps.log(" It is the only way back into this account. Save this now (a password manager is a good place):");
|
|
@@ -9331,7 +9331,7 @@ async function mintKeyedAccount(deps) {
|
|
|
9331
9331
|
const grant = await deps.passwordGrant(parsed.email, parsed.secret);
|
|
9332
9332
|
if (!grant.ok) {
|
|
9333
9333
|
throw new LoginError(
|
|
9334
|
-
`Created ${parsed.handle}${
|
|
9334
|
+
`Created ${parsed.handle}${saved2 ? " and saved its key" : ""}, but signing in failed: ${grant.error}. ` + (saved2 ? "Run `archme login --key` to try again." : `Try again with the key printed above: ${KEY_VIA_ENV}.`)
|
|
9335
9335
|
);
|
|
9336
9336
|
}
|
|
9337
9337
|
try {
|
|
@@ -9339,11 +9339,11 @@ async function mintKeyedAccount(deps) {
|
|
|
9339
9339
|
} catch (err4) {
|
|
9340
9340
|
if (!(err4 instanceof CredentialStoreError)) throw err4;
|
|
9341
9341
|
throw new LoginError(
|
|
9342
|
-
`${err4.message} Your account ${parsed.handle} was created${
|
|
9342
|
+
`${err4.message} Your account ${parsed.handle} was created${saved2 ? " and its key saved" : ""}; once that's fixed, sign in with it: ${saved2 ? "`archme login --key`" : KEY_VIA_ENV}.`
|
|
9343
9343
|
);
|
|
9344
9344
|
}
|
|
9345
9345
|
deps.log(`\u2713 Created your ArchMe account ${parsed.handle} \u2014 no email or password, just a key.`);
|
|
9346
|
-
if (
|
|
9346
|
+
if (saved2) {
|
|
9347
9347
|
deps.log(` The key is saved in ${deps.keyRingPath}. Save it in your password manager too: it is the`);
|
|
9348
9348
|
deps.log(" only way back in, including from another computer. `archme key show` prints it.");
|
|
9349
9349
|
}
|
|
@@ -10692,7 +10692,7 @@ __export(install_exports, {
|
|
|
10692
10692
|
import { isatty } from "node:tty";
|
|
10693
10693
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
10694
10694
|
import { dirname as dirname6, join as join5 } from "node:path";
|
|
10695
|
-
import { mkdir as mkdir5 } from "node:fs/promises";
|
|
10695
|
+
import { chmod as chmod3, mkdir as mkdir5 } from "node:fs/promises";
|
|
10696
10696
|
import { existsSync as existsSync2 } from "node:fs";
|
|
10697
10697
|
function bakedSystemdEnv(unit) {
|
|
10698
10698
|
const out = {};
|
|
@@ -10771,12 +10771,16 @@ Starting the installed service anyway; it reads its own sign-in when it boots.`)
|
|
|
10771
10771
|
}
|
|
10772
10772
|
}
|
|
10773
10773
|
}
|
|
10774
|
+
async function ensurePrivateDir(dir) {
|
|
10775
|
+
await mkdir5(dir, { recursive: true, mode: 448 });
|
|
10776
|
+
await chmod3(dir, 448);
|
|
10777
|
+
}
|
|
10774
10778
|
async function runStartFlow(opts = {}) {
|
|
10775
10779
|
const platform3 = opts.platform ?? process.platform;
|
|
10776
10780
|
const env = opts.env ?? process.env;
|
|
10777
10781
|
await ensureStartPrerequisites(opts);
|
|
10778
10782
|
const logPaths = resolveLogPath(platform3, env);
|
|
10779
|
-
await
|
|
10783
|
+
await ensurePrivateDir(resolveLogDir(platform3, env));
|
|
10780
10784
|
const controller = opts.controller ?? pickController(platform3, env);
|
|
10781
10785
|
const installed = await controller.readUnitContent();
|
|
10782
10786
|
const unitEnv2 = installed === null ? {} : platform3 === "darwin" ? bakedUnitEnv(installed) : bakedSystemdEnv(installed);
|
|
@@ -13691,6 +13695,89 @@ var init_repoContainer = __esm({
|
|
|
13691
13695
|
}
|
|
13692
13696
|
});
|
|
13693
13697
|
|
|
13698
|
+
// ../shared/seedArchitecture.ts
|
|
13699
|
+
function seedArchitectureFromRows(rows) {
|
|
13700
|
+
const components = [];
|
|
13701
|
+
const stories = [];
|
|
13702
|
+
for (const row of rows) {
|
|
13703
|
+
const compPath = componentPathFromFilePath(row.path);
|
|
13704
|
+
if (compPath !== null) {
|
|
13705
|
+
const parsed = tryParse(row.content);
|
|
13706
|
+
components.push({
|
|
13707
|
+
path: compPath,
|
|
13708
|
+
anchors: parsed?.anchors ?? [],
|
|
13709
|
+
unanchored: parsed?.unanchored === true ? true : void 0
|
|
13710
|
+
});
|
|
13711
|
+
continue;
|
|
13712
|
+
}
|
|
13713
|
+
const scope = storyScopeFromFilePath(row.path);
|
|
13714
|
+
if (scope !== null) {
|
|
13715
|
+
const parsed = tryParse(row.content);
|
|
13716
|
+
if (!parsed) continue;
|
|
13717
|
+
collectSeedStories(parsed, scope, row.path, stories);
|
|
13718
|
+
}
|
|
13719
|
+
}
|
|
13720
|
+
return { components, stories };
|
|
13721
|
+
}
|
|
13722
|
+
function tryParse(s) {
|
|
13723
|
+
try {
|
|
13724
|
+
return JSON.parse(s);
|
|
13725
|
+
} catch {
|
|
13726
|
+
return null;
|
|
13727
|
+
}
|
|
13728
|
+
}
|
|
13729
|
+
function componentPathFromFilePath(p) {
|
|
13730
|
+
if (!p.endsWith("/component.json")) return null;
|
|
13731
|
+
const inner = p.slice(0, -"/component.json".length);
|
|
13732
|
+
if (inner.length === 0) return null;
|
|
13733
|
+
const segments = inner.split("/");
|
|
13734
|
+
if (segments.length % 2 !== 0) return null;
|
|
13735
|
+
const ids = [];
|
|
13736
|
+
for (let i2 = 0; i2 < segments.length; i2 += 2) {
|
|
13737
|
+
if (segments[i2] !== "components") return null;
|
|
13738
|
+
const id = segments[i2 + 1];
|
|
13739
|
+
if (!id) return null;
|
|
13740
|
+
ids.push(id);
|
|
13741
|
+
}
|
|
13742
|
+
return `root.${ids.join(".")}`;
|
|
13743
|
+
}
|
|
13744
|
+
function storyScopeFromFilePath(p) {
|
|
13745
|
+
if (!STORY_PATH_RE.test(p)) return null;
|
|
13746
|
+
const prefix = p.slice(0, p.lastIndexOf("stories/"));
|
|
13747
|
+
if (prefix.length === 0) return [];
|
|
13748
|
+
const segments = prefix.split("/").filter(Boolean);
|
|
13749
|
+
const ids = [];
|
|
13750
|
+
for (let i2 = 0; i2 < segments.length; i2 += 2) {
|
|
13751
|
+
if (segments[i2] !== "components") return null;
|
|
13752
|
+
const id = segments[i2 + 1];
|
|
13753
|
+
if (!id) return null;
|
|
13754
|
+
ids.push(id);
|
|
13755
|
+
}
|
|
13756
|
+
return ids;
|
|
13757
|
+
}
|
|
13758
|
+
function collectSeedStories(raw, scope, fileFallbackId, out, parentId) {
|
|
13759
|
+
const id = raw.id ?? fileFallbackId;
|
|
13760
|
+
out.push({
|
|
13761
|
+
id,
|
|
13762
|
+
title: raw.title ?? id,
|
|
13763
|
+
sequence: raw.sequence ?? "",
|
|
13764
|
+
draft: raw.draft === true ? true : void 0,
|
|
13765
|
+
scope,
|
|
13766
|
+
parentId
|
|
13767
|
+
});
|
|
13768
|
+
if (Array.isArray(raw.userStories)) {
|
|
13769
|
+
for (const child of raw.userStories) {
|
|
13770
|
+
collectSeedStories(child, scope, fileFallbackId, out, id);
|
|
13771
|
+
}
|
|
13772
|
+
}
|
|
13773
|
+
}
|
|
13774
|
+
var STORY_PATH_RE;
|
|
13775
|
+
var init_seedArchitecture = __esm({
|
|
13776
|
+
"../shared/seedArchitecture.ts"() {
|
|
13777
|
+
STORY_PATH_RE = /^(?:components\/[^/]+\/)*stories\/[^/]+\.json$/;
|
|
13778
|
+
}
|
|
13779
|
+
});
|
|
13780
|
+
|
|
13694
13781
|
// src/scan/affected.ts
|
|
13695
13782
|
function normalizePath(p) {
|
|
13696
13783
|
return p.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/+/g, "/").replace(/\/$/, "");
|
|
@@ -13904,42 +13991,6 @@ function formatAffectedSeed(result, removedSymbols = [], allStories) {
|
|
|
13904
13991
|
}
|
|
13905
13992
|
return lines.join("\n");
|
|
13906
13993
|
}
|
|
13907
|
-
function tryParse(s) {
|
|
13908
|
-
try {
|
|
13909
|
-
return JSON.parse(s);
|
|
13910
|
-
} catch {
|
|
13911
|
-
return null;
|
|
13912
|
-
}
|
|
13913
|
-
}
|
|
13914
|
-
function componentPathFromFilePath(p) {
|
|
13915
|
-
if (!p.endsWith("/component.json")) return null;
|
|
13916
|
-
const inner = p.slice(0, -"/component.json".length);
|
|
13917
|
-
if (inner.length === 0) return null;
|
|
13918
|
-
const segments = inner.split("/");
|
|
13919
|
-
if (segments.length % 2 !== 0) return null;
|
|
13920
|
-
const ids = [];
|
|
13921
|
-
for (let i2 = 0; i2 < segments.length; i2 += 2) {
|
|
13922
|
-
if (segments[i2] !== "components") return null;
|
|
13923
|
-
const id = segments[i2 + 1];
|
|
13924
|
-
if (!id) return null;
|
|
13925
|
-
ids.push(id);
|
|
13926
|
-
}
|
|
13927
|
-
return `root.${ids.join(".")}`;
|
|
13928
|
-
}
|
|
13929
|
-
function storyScopeFromFilePath(p) {
|
|
13930
|
-
if (!STORY_PATH_RE.test(p)) return null;
|
|
13931
|
-
const prefix = p.slice(0, p.lastIndexOf("stories/"));
|
|
13932
|
-
if (prefix.length === 0) return [];
|
|
13933
|
-
const segments = prefix.split("/").filter(Boolean);
|
|
13934
|
-
const ids = [];
|
|
13935
|
-
for (let i2 = 0; i2 < segments.length; i2 += 2) {
|
|
13936
|
-
if (segments[i2] !== "components") return null;
|
|
13937
|
-
const id = segments[i2 + 1];
|
|
13938
|
-
if (!id) return null;
|
|
13939
|
-
ids.push(id);
|
|
13940
|
-
}
|
|
13941
|
-
return ids;
|
|
13942
|
-
}
|
|
13943
13994
|
async function loadArchitectureForSeeding(supabase, projectId, branch) {
|
|
13944
13995
|
const PAGE_SIZE2 = 1e3;
|
|
13945
13996
|
const rows = [];
|
|
@@ -13950,54 +14001,18 @@ async function loadArchitectureForSeeding(supabase, projectId, branch) {
|
|
|
13950
14001
|
rows.push(...data);
|
|
13951
14002
|
if (data.length < PAGE_SIZE2) break;
|
|
13952
14003
|
}
|
|
13953
|
-
|
|
13954
|
-
const stories = [];
|
|
13955
|
-
for (const row of rows) {
|
|
13956
|
-
const compPath = componentPathFromFilePath(row.path);
|
|
13957
|
-
if (compPath !== null) {
|
|
13958
|
-
const parsed = tryParse(row.content);
|
|
13959
|
-
components.push({
|
|
13960
|
-
path: compPath,
|
|
13961
|
-
anchors: parsed?.anchors ?? [],
|
|
13962
|
-
unanchored: parsed?.unanchored === true ? true : void 0
|
|
13963
|
-
});
|
|
13964
|
-
continue;
|
|
13965
|
-
}
|
|
13966
|
-
const scope = storyScopeFromFilePath(row.path);
|
|
13967
|
-
if (scope !== null) {
|
|
13968
|
-
const parsed = tryParse(row.content);
|
|
13969
|
-
if (!parsed) continue;
|
|
13970
|
-
collectSeedStories(parsed, scope, row.path, stories);
|
|
13971
|
-
}
|
|
13972
|
-
}
|
|
13973
|
-
return { components, stories };
|
|
14004
|
+
return seedArchitectureFromRows(rows);
|
|
13974
14005
|
}
|
|
13975
|
-
|
|
13976
|
-
const id = raw.id ?? fileFallbackId;
|
|
13977
|
-
out.push({
|
|
13978
|
-
id,
|
|
13979
|
-
title: raw.title ?? id,
|
|
13980
|
-
sequence: raw.sequence ?? "",
|
|
13981
|
-
draft: raw.draft === true ? true : void 0,
|
|
13982
|
-
scope,
|
|
13983
|
-
parentId
|
|
13984
|
-
});
|
|
13985
|
-
if (Array.isArray(raw.userStories)) {
|
|
13986
|
-
for (const child of raw.userStories) {
|
|
13987
|
-
collectSeedStories(child, scope, fileFallbackId, out, id);
|
|
13988
|
-
}
|
|
13989
|
-
}
|
|
13990
|
-
}
|
|
13991
|
-
var MESSAGE_RE, PARTICIPANT_RE, DISPLAY_FILE_CAP, STORY_PATH_RE;
|
|
14006
|
+
var MESSAGE_RE, PARTICIPANT_RE, DISPLAY_FILE_CAP;
|
|
13992
14007
|
var init_affected = __esm({
|
|
13993
14008
|
"src/scan/affected.ts"() {
|
|
13994
14009
|
"use strict";
|
|
13995
14010
|
init_esm3();
|
|
13996
14011
|
init_repoContainer();
|
|
14012
|
+
init_seedArchitecture();
|
|
13997
14013
|
MESSAGE_RE = /^\s*(\{[^}]+\}|\S+?)\s*(--?>>|--?>|->|-->|-x|-\))\s*(\{[^}]+\}|\S+?)\s*:\s*(.*)$/;
|
|
13998
14014
|
PARTICIPANT_RE = /^\s*participant\s+(\S+?)(?:\s+as\s+.+)?$/;
|
|
13999
14015
|
DISPLAY_FILE_CAP = 200;
|
|
14000
|
-
STORY_PATH_RE = /^(?:components\/[^/]+\/)*stories\/[^/]+\.json$/;
|
|
14001
14016
|
}
|
|
14002
14017
|
});
|
|
14003
14018
|
|
|
@@ -16251,10 +16266,11 @@ function buildBugReportGuidance(bugsFolderId) {
|
|
|
16251
16266
|
|
|
16252
16267
|
${folderMechanic}`;
|
|
16253
16268
|
}
|
|
16254
|
-
var BUGS_FOLDER_TITLE, BUG_REPORT_CORE;
|
|
16269
|
+
var BUGS_FOLDER_TITLE, BUGS_FOLDER_DESCRIPTION, BUG_REPORT_CORE;
|
|
16255
16270
|
var init_bugReport = __esm({
|
|
16256
16271
|
"../shared/bugReport.ts"() {
|
|
16257
16272
|
BUGS_FOLDER_TITLE = "Bugs found by ArchMe";
|
|
16273
|
+
BUGS_FOLDER_DESCRIPTION = "Bugs noticed by scan/diff agents in the code while updating the architecture. Prose-only proposals; humans triage.";
|
|
16258
16274
|
BUG_REPORT_CORE = "**Bugs you happen to notice.** Don't hunt for bugs \u2014 stay on the architecture task \u2014 but don't ignore an obvious, real one that surfaces while you read the code (a null-deref, a missing `await`, an unhandled error path, a broken invariant). Have any sub-agents you dispatch report a suspect back to you (a one-line `possible bug: <what> at <file:line>`) rather than filing it themselves. When suspects come back, dispatch ONE bug-validation sub-agent \u2014 it reads code and calls `create_proposal`, exactly like the build sub-agent, and never modifies the user's code \u2014 and have it: verify each suspect against the code, and for every one it confirms as a real defect, FILE it itself as a prose-only proposal (`create_proposal` with `kind: 'proposal'`, `stage: 'backlog'`, an empty graph delta, and a one-paragraph `body`: what is wrong, where by file:line or symbol, and why), `about` the component it lives in (`{ component: '<root.\u2026 path>' }` \u2014 find_components_for_paths maps the file to it), else the user story whose flow it breaks (`{ story: '<id>' }`). It skips anything it can't confirm, and searches the folder by title first to skip anything already logged. Keep the bar high \u2014 obvious, confirmed defects only, a few per run at most, never speculation, style, or a design opinion; record, never fix. Logging a bug is orthogonal to your architecture task and does NOT replace your completion signal \u2014 still call `update_architecture` or `report_no_change` exactly as you otherwise would.";
|
|
16259
16275
|
}
|
|
16260
16276
|
});
|
|
@@ -16685,7 +16701,11 @@ var init_validationCodes = __esm({
|
|
|
16685
16701
|
WALKTHROUGH_COVERAGE_CHAPTER_NOT_COVERED: "walkthrough.coverage.chapter-not-covered",
|
|
16686
16702
|
/** The delta added, removed or modified a component no step names. */
|
|
16687
16703
|
WALKTHROUGH_COVERAGE_COMPONENT_NOT_COVERED: "walkthrough.coverage.component-not-covered",
|
|
16688
|
-
/**
|
|
16704
|
+
/**
|
|
16705
|
+
* The delta changed a connection no step names, joins, or draws.
|
|
16706
|
+
* @deprecated Retired: connections show up through the stories that draw
|
|
16707
|
+
* them, so coverage no longer requires them.
|
|
16708
|
+
*/
|
|
16689
16709
|
WALKTHROUGH_COVERAGE_CONNECTION_NOT_COVERED: "walkthrough.coverage.connection-not-covered",
|
|
16690
16710
|
// ──────────────────────────────────────────────────────────────────────────
|
|
16691
16711
|
// mcp — request-level rules applied before any tool handler runs
|
|
@@ -16742,7 +16762,7 @@ var init_walkthroughGuidance = __esm({
|
|
|
16742
16762
|
init_walkthrough();
|
|
16743
16763
|
WALKTHROUGH_GUIDANCE = `A walkthrough breaks a change into bite-sized chunks a reviewer can step through. Each step names the elements it is about; the review surface filters the sequence diagram and the component graph down to just those, so the reader sees one chunk at a time instead of a forty-element diff at once.
|
|
16744
16764
|
|
|
16745
|
-
- **Every step must name what it is about** \u2014 the stories, chapters, components and/or connections it covers. A step with only prose is rejected: there is nothing to filter the diagrams by, and an explanation a reader cannot check against the change is exactly what this view exists to avoid.
|
|
16765
|
+
- **Every step must name what it is about** \u2014 the stories, chapters, components and/or connections it covers. A step with only prose is rejected: there is nothing to filter the diagrams by, and an explanation a reader cannot check against the change is exactly what this view exists to avoid. Name a connection inside a component as \`<component path>::<id>\` (\`daemon::session_auth->key_account\`); a root connection by its plain id.
|
|
16746
16766
|
- **Steps are in reading order, not build order.** This is not an implementation plan and not a restatement of your sequencing section \u2014 start where a reviewer should start, and put each step where it makes the next one make sense.
|
|
16747
16767
|
- **Group by idea.** One step is one coherent change, usually 3\u20138 elements. A one-element step is fine and often valuable: an independent fix that would otherwise be lost among the rest. Aim for a handful of steps; the cap is ${MAX_WALKTHROUGH_STEPS}.
|
|
16748
16768
|
- **Titles are terse** \u2014 a handle, not a summary. Under ${MAX_STEP_TITLE_CHARS} characters. \`Markers move per-repo\`, not \`This step explains how the source marker moves onto a per-repo table\`.
|
|
@@ -16754,7 +16774,7 @@ var init_walkthroughGuidance = __esm({
|
|
|
16754
16774
|
- Don't use the change's OWN new vocabulary undefined. If the step introduces a term, say what it means in the same breath or use plain words.
|
|
16755
16775
|
- Bad: \`A correctness item, not a phase-3 nicety: anchors are repo-relative paths, so two repos with the same conventional layout collide silently and seed stories from the wrong one.\`
|
|
16756
16776
|
- Good: \`With two repos in one project a path like src/index.ts exists in both, so looking up which component owns a changed file can return the wrong repo's. Each repo now records the container its code lives under, and lookups search only that subtree.\`
|
|
16757
|
-
- **Cover every change** \u2014 every story
|
|
16777
|
+
- **Cover every change** \u2014 every story and component the change touches \u2014 or \`set_walkthrough\` rejects the walkthrough and lists what is missing. Guided mode walks the steps and nothing after them, so anything no step reaches is a change the reviewer never sees. Connections need no step of their own: they show up through the stories that draw them.
|
|
16758
16778
|
- **Skip it for a small change.** A handful of elements needs no walkthrough; omit it rather than writing a step per element.
|
|
16759
16779
|
- **Prefer CHAPTERS to narrow a diagram.** If a story's sequence carries \`%% chapter: <id> | <Label>\` markers, name the ones your step covers as \`chapters: [{ story, chapter }]\`, using the **id**, never the label \u2014 ids are stable across a rename, labels are not. A chapter is a page break the story's author already wrote, so it is sharper than naming components, where one hub the step mentions decides the whole view.`;
|
|
16760
16780
|
}
|
|
@@ -16865,12 +16885,11 @@ async function ensureBugsFolder(client, projectId) {
|
|
|
16865
16885
|
return null;
|
|
16866
16886
|
}
|
|
16867
16887
|
}
|
|
16868
|
-
var
|
|
16888
|
+
var cache;
|
|
16869
16889
|
var init_bugsFolder = __esm({
|
|
16870
16890
|
"src/daemon/bugsFolder.ts"() {
|
|
16871
16891
|
"use strict";
|
|
16872
16892
|
init_bugReport();
|
|
16873
|
-
BUGS_FOLDER_DESCRIPTION = "Bugs noticed by scan/diff agents in the code while updating the architecture. Prose-only proposals; humans triage.";
|
|
16874
16893
|
cache = /* @__PURE__ */ new Map();
|
|
16875
16894
|
}
|
|
16876
16895
|
});
|
|
@@ -17406,9 +17425,9 @@ var init_sessionAuth = __esm({
|
|
|
17406
17425
|
this.userId = resolveUserId(userInfo2, ctx.fallbackUserId);
|
|
17407
17426
|
this.lastUserInfo = userInfo2;
|
|
17408
17427
|
}
|
|
17409
|
-
let
|
|
17428
|
+
let saved2 = null;
|
|
17410
17429
|
try {
|
|
17411
|
-
|
|
17430
|
+
saved2 = await saveCredentials({
|
|
17412
17431
|
kind: this.kind,
|
|
17413
17432
|
refresh_token: nextRefreshToken,
|
|
17414
17433
|
access_token: this.accessToken,
|
|
@@ -17423,7 +17442,7 @@ var init_sessionAuth = __esm({
|
|
|
17423
17442
|
`auth: ${err4.message} The refreshed sign-in was NOT saved: this process keeps working, but the saved one is now out of date. If this process ends before a later refresh saves it, sign in again then. ${this.reloginHint()}`
|
|
17424
17443
|
);
|
|
17425
17444
|
}
|
|
17426
|
-
return { userInfo: userInfo2, saved, nextRefreshToken };
|
|
17445
|
+
return { userInfo: userInfo2, saved: saved2, nextRefreshToken };
|
|
17427
17446
|
}
|
|
17428
17447
|
// The timer closure reads the LIVE this.refreshToken/deviceId/orgId at fire
|
|
17429
17448
|
// time (via runScheduledRefresh), never a captured value, so an out-of-band
|
|
@@ -17524,13 +17543,13 @@ var init_sessionAuth = __esm({
|
|
|
17524
17543
|
}
|
|
17525
17544
|
throw new LoadStoredAndRefreshError("transient", `${errorPrefix} failed: ${refreshed.error}`);
|
|
17526
17545
|
}
|
|
17527
|
-
const { saved } = await this.applyRefreshedTokens(refreshed, {
|
|
17546
|
+
const { saved: saved2 } = await this.applyRefreshedTokens(refreshed, {
|
|
17528
17547
|
prevRefreshToken: refreshToken,
|
|
17529
17548
|
deviceId,
|
|
17530
17549
|
orgId,
|
|
17531
17550
|
fallbackUserId: this.userId ?? void 0
|
|
17532
17551
|
});
|
|
17533
|
-
if (
|
|
17552
|
+
if (saved2) console.log(`auth: persisted refreshed token to ${describeCredentialSource(saved2)}`);
|
|
17534
17553
|
})();
|
|
17535
17554
|
this.refreshInFlight = p;
|
|
17536
17555
|
return p.finally(() => {
|
|
@@ -17563,13 +17582,13 @@ var init_sessionAuth = __esm({
|
|
|
17563
17582
|
// clearing. Permanent only when there is no saved key or the key is refused;
|
|
17564
17583
|
// the key ring itself is never modified here.
|
|
17565
17584
|
async signInWithSavedKey(userId, refreshError) {
|
|
17566
|
-
let
|
|
17585
|
+
let saved2;
|
|
17567
17586
|
try {
|
|
17568
|
-
|
|
17587
|
+
saved2 = userId ? await findKey(this.cfg.supabaseUrl, userId) : null;
|
|
17569
17588
|
} catch (err4) {
|
|
17570
17589
|
return { ok: false, permanent: false, error: `${refreshError}; ${err4 instanceof Error ? err4.message : String(err4)}` };
|
|
17571
17590
|
}
|
|
17572
|
-
const parsed = parseAccountKey(
|
|
17591
|
+
const parsed = parseAccountKey(saved2?.key);
|
|
17573
17592
|
if (!parsed) return { ok: false, permanent: true, error: `${refreshError}; no saved key for this account` };
|
|
17574
17593
|
console.error(`auth: refresh token rejected (${refreshError}); signing in again with the saved key for ${parsed.handle}`);
|
|
17575
17594
|
const granted = await passwordGrant(parsed.email, parsed.secret, this.cfg);
|
|
@@ -17902,7 +17921,10 @@ function rateLimitPauseUntil(text, nowMs = Date.now(), defaultTimeZone = localTi
|
|
|
17902
17921
|
if (!info) return null;
|
|
17903
17922
|
return {
|
|
17904
17923
|
info,
|
|
17905
|
-
|
|
17924
|
+
// The reset is text the run reported (a box can forge it, and a dated one a
|
|
17925
|
+
// week past rolls a year forward), and the pause stalls the whole account:
|
|
17926
|
+
// never longer than a day. A job still limited then just defers again.
|
|
17927
|
+
pauseUntil: new Date(Math.min(info.resetAt.getTime() + RATE_LIMIT_PAUSE_PADDING_MS, nowMs + RATE_LIMIT_MAX_PAUSE_MS))
|
|
17906
17928
|
};
|
|
17907
17929
|
}
|
|
17908
17930
|
function looksLikeRateLimit(text) {
|
|
@@ -17943,7 +17965,7 @@ function claudeErrorDeferPlan(error, nowMs, defaultTimeZone) {
|
|
|
17943
17965
|
}
|
|
17944
17966
|
return null;
|
|
17945
17967
|
}
|
|
17946
|
-
var RATE_LIMIT_RE, MONTHS, RATE_LIMIT_TENTATIVE_PAUSE_MS, DATED_RESET_ROLLOVER_GRACE_MS, RATE_LIMIT_PAUSE_PADDING_MS, RATE_LIMIT_SHAPED_RE;
|
|
17968
|
+
var RATE_LIMIT_RE, MONTHS, RATE_LIMIT_TENTATIVE_PAUSE_MS, DATED_RESET_ROLLOVER_GRACE_MS, RATE_LIMIT_PAUSE_PADDING_MS, RATE_LIMIT_MAX_PAUSE_MS, RATE_LIMIT_SHAPED_RE;
|
|
17947
17969
|
var init_rateLimit = __esm({
|
|
17948
17970
|
"src/daemon/rateLimit.ts"() {
|
|
17949
17971
|
"use strict";
|
|
@@ -17965,6 +17987,7 @@ var init_rateLimit = __esm({
|
|
|
17965
17987
|
RATE_LIMIT_TENTATIVE_PAUSE_MS = 60 * 60 * 1e3;
|
|
17966
17988
|
DATED_RESET_ROLLOVER_GRACE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
17967
17989
|
RATE_LIMIT_PAUSE_PADDING_MS = 9e4;
|
|
17990
|
+
RATE_LIMIT_MAX_PAUSE_MS = 24 * 60 * 60 * 1e3;
|
|
17968
17991
|
RATE_LIMIT_SHAPED_RE = /(\brate[ -]?limit\b|\blimit\b.{0,40}\bresets?\b|\bresets?\b.{0,40}\blimit\b|\b429\b|\bquota\b|\busage[ -]?limit\b)/i;
|
|
17969
17992
|
}
|
|
17970
17993
|
});
|
|
@@ -18298,7 +18321,7 @@ var init_localPrPoll = __esm({
|
|
|
18298
18321
|
});
|
|
18299
18322
|
|
|
18300
18323
|
// src/daemon/localRepos.ts
|
|
18301
|
-
import { chmod as
|
|
18324
|
+
import { chmod as chmod4, mkdir as mkdir9, readFile as readFile12, writeFile as writeFile9 } from "node:fs/promises";
|
|
18302
18325
|
import { homedir as homedir6 } from "node:os";
|
|
18303
18326
|
import { dirname as dirname12, join as join19 } from "node:path";
|
|
18304
18327
|
function localReposPath(env = process.env) {
|
|
@@ -18401,7 +18424,7 @@ async function saveLocalRepos(repos, env = process.env) {
|
|
|
18401
18424
|
const path7 = localReposPath(env);
|
|
18402
18425
|
await mkdir9(dirname12(path7), { recursive: true, mode: 448 });
|
|
18403
18426
|
await writeFile9(path7, serializeLocalRepos(repos), { mode: 384 });
|
|
18404
|
-
await
|
|
18427
|
+
await chmod4(path7, 384).catch(() => {
|
|
18405
18428
|
});
|
|
18406
18429
|
}
|
|
18407
18430
|
async function registerLocalRepo(entry, env = process.env) {
|
|
@@ -18634,6 +18657,21 @@ var init_defaultBranch = __esm({
|
|
|
18634
18657
|
}
|
|
18635
18658
|
});
|
|
18636
18659
|
|
|
18660
|
+
// src/daemon/sshAgent.ts
|
|
18661
|
+
function detachSshAgent(env = process.env) {
|
|
18662
|
+
if (env.SSH_AUTH_SOCK !== void 0) saved = env.SSH_AUTH_SOCK;
|
|
18663
|
+
delete env.SSH_AUTH_SOCK;
|
|
18664
|
+
}
|
|
18665
|
+
function localGitEnv() {
|
|
18666
|
+
return saved === void 0 ? process.env : { ...process.env, SSH_AUTH_SOCK: saved };
|
|
18667
|
+
}
|
|
18668
|
+
var saved;
|
|
18669
|
+
var init_sshAgent = __esm({
|
|
18670
|
+
"src/daemon/sshAgent.ts"() {
|
|
18671
|
+
"use strict";
|
|
18672
|
+
}
|
|
18673
|
+
});
|
|
18674
|
+
|
|
18637
18675
|
// ../shared/prRefs.ts
|
|
18638
18676
|
function parsePrRefs(message2) {
|
|
18639
18677
|
if (!message2) return [];
|
|
@@ -18686,7 +18724,8 @@ async function git(dir, args, opts = {}) {
|
|
|
18686
18724
|
requireBinary("git");
|
|
18687
18725
|
const res = await execa("git", args, {
|
|
18688
18726
|
cwd: dir ?? void 0,
|
|
18689
|
-
|
|
18727
|
+
// The SSH agent the daemon detached at boot (sshAgent.ts): origin may be ssh.
|
|
18728
|
+
env: { ...localGitEnv(), ...opts.env },
|
|
18690
18729
|
reject: false,
|
|
18691
18730
|
timeout: GIT_TIMEOUT_MS,
|
|
18692
18731
|
// Kill the whole process group: a hung `git fetch` has spawned helper
|
|
@@ -18792,6 +18831,7 @@ var init_localGit = __esm({
|
|
|
18792
18831
|
init_execa();
|
|
18793
18832
|
init_preflight();
|
|
18794
18833
|
init_defaultBranch();
|
|
18834
|
+
init_sshAgent();
|
|
18795
18835
|
init_prRefs();
|
|
18796
18836
|
GIT_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
18797
18837
|
}
|
|
@@ -19496,7 +19536,7 @@ var init_setting = __esm({
|
|
|
19496
19536
|
}
|
|
19497
19537
|
});
|
|
19498
19538
|
|
|
19499
|
-
//
|
|
19539
|
+
// ../shared/architectureCounts.ts
|
|
19500
19540
|
function countFromPaths(paths) {
|
|
19501
19541
|
let components = 0;
|
|
19502
19542
|
let stories = 0;
|
|
@@ -19510,6 +19550,12 @@ function countFromPaths(paths) {
|
|
|
19510
19550
|
}
|
|
19511
19551
|
return { components, stories, rootStories };
|
|
19512
19552
|
}
|
|
19553
|
+
var init_architectureCounts = __esm({
|
|
19554
|
+
"../shared/architectureCounts.ts"() {
|
|
19555
|
+
}
|
|
19556
|
+
});
|
|
19557
|
+
|
|
19558
|
+
// src/scan/architectureCounts.ts
|
|
19513
19559
|
async function countArchitecture(supabase, projectId, branch) {
|
|
19514
19560
|
const PAGE_SIZE2 = 1e3;
|
|
19515
19561
|
const paths = [];
|
|
@@ -19529,9 +19575,10 @@ function firstScanGate(counts) {
|
|
|
19529
19575
|
reason: `first scan incomplete: the branch holds ${counts.components} component(s) and ${counts.rootStories} root story(ies); needs at least one of each`
|
|
19530
19576
|
};
|
|
19531
19577
|
}
|
|
19532
|
-
var
|
|
19578
|
+
var init_architectureCounts2 = __esm({
|
|
19533
19579
|
"src/scan/architectureCounts.ts"() {
|
|
19534
19580
|
"use strict";
|
|
19581
|
+
init_architectureCounts();
|
|
19535
19582
|
}
|
|
19536
19583
|
});
|
|
19537
19584
|
|
|
@@ -19646,6 +19693,103 @@ var init_platformDevices = __esm({
|
|
|
19646
19693
|
}
|
|
19647
19694
|
});
|
|
19648
19695
|
|
|
19696
|
+
// src/daemon/jobReads.ts
|
|
19697
|
+
async function lookupProjectSlug(client, projectId) {
|
|
19698
|
+
const { data, error } = await client.from("projects").select("slug, organizations(slug)").eq("id", projectId).single();
|
|
19699
|
+
if (error || !data) throw new Error(`Project ${projectId} not found: ${error?.message}`);
|
|
19700
|
+
const orgSlug = data.organizations?.slug;
|
|
19701
|
+
if (!orgSlug) throw new Error(`Project ${projectId} has no org slug`);
|
|
19702
|
+
return `${orgSlug}/${data.slug}`;
|
|
19703
|
+
}
|
|
19704
|
+
async function detectWritesByPhase(client, projectId, archmeBranch, jobId) {
|
|
19705
|
+
const { data, error } = await client.from("commits").select("structural_changeset").eq("project_id", projectId).eq("branch", archmeBranch).eq("metadata->source->>job_id", jobId);
|
|
19706
|
+
if (error) {
|
|
19707
|
+
console.error("commits lookup error:", error.message);
|
|
19708
|
+
return { total: 0, diffWrites: 0, structuralWrites: 0 };
|
|
19709
|
+
}
|
|
19710
|
+
let diffWrites = 0;
|
|
19711
|
+
let structuralWrites = 0;
|
|
19712
|
+
for (const row of data ?? []) {
|
|
19713
|
+
if (row.structural_changeset == null) diffWrites++;
|
|
19714
|
+
else structuralWrites++;
|
|
19715
|
+
}
|
|
19716
|
+
return { total: diffWrites + structuralWrites, diffWrites, structuralWrites };
|
|
19717
|
+
}
|
|
19718
|
+
async function detectMcpActivity(client, jobId) {
|
|
19719
|
+
const { data, error } = await client.from("archme_jobs").select("meaningful_tool_calls, no_change_reason").eq("id", jobId).maybeSingle();
|
|
19720
|
+
if (error) {
|
|
19721
|
+
console.error("mcp_activity lookup error:", error.message);
|
|
19722
|
+
return { reads: void 0, noChange: false };
|
|
19723
|
+
}
|
|
19724
|
+
if (!data) return { reads: void 0, noChange: false };
|
|
19725
|
+
const row = data;
|
|
19726
|
+
return { reads: row.meaningful_tool_calls, noChange: row.no_change_reason != null };
|
|
19727
|
+
}
|
|
19728
|
+
function sessionJobReads(client, job) {
|
|
19729
|
+
return {
|
|
19730
|
+
projectSlug: () => lookupProjectSlug(client, job.project_id),
|
|
19731
|
+
marker: (repo) => readBranchMarker(client, job.project_id, job.archme_branch, repo),
|
|
19732
|
+
repoMappings: (log) => loadRepoMappings(client, job.project_id, log),
|
|
19733
|
+
seedArchitecture: () => loadArchitectureForSeeding(client, job.project_id, job.archme_branch),
|
|
19734
|
+
bugsFolderId: () => ensureBugsFolder(client, job.project_id),
|
|
19735
|
+
writesByPhase: () => detectWritesByPhase(client, job.project_id, job.archme_branch, job.id),
|
|
19736
|
+
mcpActivity: () => detectMcpActivity(client, job.id),
|
|
19737
|
+
architectureCounts: () => countArchitecture(client, job.project_id, job.archme_branch)
|
|
19738
|
+
};
|
|
19739
|
+
}
|
|
19740
|
+
function hostedJobReads(post) {
|
|
19741
|
+
let prefetch = null;
|
|
19742
|
+
let outcome = null;
|
|
19743
|
+
const pre = () => prefetch ??= post("prefetch");
|
|
19744
|
+
const out = () => outcome ??= post("outcome");
|
|
19745
|
+
return {
|
|
19746
|
+
projectSlug: async () => {
|
|
19747
|
+
const slug = (await pre()).project_slug;
|
|
19748
|
+
if (typeof slug !== "string") throw new Error("job-context returned no project slug");
|
|
19749
|
+
return slug;
|
|
19750
|
+
},
|
|
19751
|
+
marker: async () => (await pre()).marker,
|
|
19752
|
+
repoMappings: async (log) => {
|
|
19753
|
+
const mappings = (await pre()).repo_mappings;
|
|
19754
|
+
if (mappings === null) log("repo mappings unreadable (proceeding without repo scoping)");
|
|
19755
|
+
return mappings;
|
|
19756
|
+
},
|
|
19757
|
+
seedArchitecture: async () => {
|
|
19758
|
+
const p = await pre();
|
|
19759
|
+
if (!p.seed_architecture) throw new Error(p.seed_error ?? "seed architecture unavailable");
|
|
19760
|
+
return p.seed_architecture;
|
|
19761
|
+
},
|
|
19762
|
+
bugsFolderId: async () => (await pre()).bugs_folder_id,
|
|
19763
|
+
// Fails closed, unlike the session readers: a platform job has no session read to fall back on.
|
|
19764
|
+
writesByPhase: async () => {
|
|
19765
|
+
const { total, diff, structural } = (await out()).writes;
|
|
19766
|
+
return { total, diffWrites: diff, structuralWrites: structural };
|
|
19767
|
+
},
|
|
19768
|
+
mcpActivity: async () => {
|
|
19769
|
+
const { reads, no_change } = (await out()).mcp;
|
|
19770
|
+
return { reads: reads ?? void 0, noChange: no_change };
|
|
19771
|
+
},
|
|
19772
|
+
architectureCounts: async () => {
|
|
19773
|
+
const counts = (await out()).architecture_counts;
|
|
19774
|
+
if (!counts) throw new Error("job-context returned no architecture counts");
|
|
19775
|
+
return counts;
|
|
19776
|
+
}
|
|
19777
|
+
};
|
|
19778
|
+
}
|
|
19779
|
+
function jobReadsFor(deps, job) {
|
|
19780
|
+
return deps.isPlatformDevice ? hostedJobReads(deps.post) : sessionJobReads(deps.client, job);
|
|
19781
|
+
}
|
|
19782
|
+
var init_jobReads = __esm({
|
|
19783
|
+
"src/daemon/jobReads.ts"() {
|
|
19784
|
+
"use strict";
|
|
19785
|
+
init_architectureCounts2();
|
|
19786
|
+
init_affected();
|
|
19787
|
+
init_bugsFolder();
|
|
19788
|
+
init_branchMarker();
|
|
19789
|
+
init_repoMappings();
|
|
19790
|
+
}
|
|
19791
|
+
});
|
|
19792
|
+
|
|
19649
19793
|
// src/daemon/sandboxJob/result.ts
|
|
19650
19794
|
import { readFile as readFile13 } from "node:fs/promises";
|
|
19651
19795
|
function isValidNonce(nonce) {
|
|
@@ -19773,7 +19917,7 @@ var init_result2 = __esm({
|
|
|
19773
19917
|
});
|
|
19774
19918
|
|
|
19775
19919
|
// src/daemon/sandbox/inputDir.ts
|
|
19776
|
-
import { mkdtemp as mkdtemp3, readdir as readdir2, rm as rm7, writeFile as writeFile10, chmod as
|
|
19920
|
+
import { mkdtemp as mkdtemp3, readdir as readdir2, rm as rm7, writeFile as writeFile10, chmod as chmod5 } from "node:fs/promises";
|
|
19777
19921
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
19778
19922
|
import { join as join22 } from "node:path";
|
|
19779
19923
|
async function writeInputDir(step, input, base = tmpdir3()) {
|
|
@@ -19781,7 +19925,7 @@ async function writeInputDir(step, input, base = tmpdir3()) {
|
|
|
19781
19925
|
const cleanup = () => rm7(dir, { recursive: true, force: true }).catch(() => {
|
|
19782
19926
|
});
|
|
19783
19927
|
try {
|
|
19784
|
-
await
|
|
19928
|
+
await chmod5(dir, 448);
|
|
19785
19929
|
await writeFile10(join22(dir, "input.json"), JSON.stringify(input), { mode: 384, flag: "wx" });
|
|
19786
19930
|
} catch (e) {
|
|
19787
19931
|
await cleanup();
|
|
@@ -19993,7 +20137,7 @@ var init_confinement = __esm({
|
|
|
19993
20137
|
|
|
19994
20138
|
// src/daemon/sandbox/claudeToken.ts
|
|
19995
20139
|
import { constants as fsConstants } from "node:fs";
|
|
19996
|
-
import { chmod as
|
|
20140
|
+
import { chmod as chmod6, mkdir as mkdir11, open as open3 } from "node:fs/promises";
|
|
19997
20141
|
import { dirname as dirname15 } from "node:path";
|
|
19998
20142
|
function assertTokenShape(raw, where) {
|
|
19999
20143
|
const token = raw.trim();
|
|
@@ -20066,7 +20210,7 @@ async function storeSandboxClaudeToken(raw, opts) {
|
|
|
20066
20210
|
} finally {
|
|
20067
20211
|
await fh.close();
|
|
20068
20212
|
}
|
|
20069
|
-
await
|
|
20213
|
+
await chmod6(opts.path, 384);
|
|
20070
20214
|
return { source: "file", note };
|
|
20071
20215
|
}
|
|
20072
20216
|
async function checkClaudeToken(token, fetchFn = fetch) {
|
|
@@ -20492,24 +20636,28 @@ var init_runSandboxedJob = __esm({
|
|
|
20492
20636
|
|
|
20493
20637
|
// src/daemon/sandbox/classifySandboxExit.ts
|
|
20494
20638
|
function classifySandboxExit(input) {
|
|
20495
|
-
const { counters, exitCode,
|
|
20496
|
-
if ((counters?.cap_hits ?? 0) > 0
|
|
20639
|
+
const { counters, exitCode, stepFailure, claudeIsError } = input;
|
|
20640
|
+
if ((counters?.cap_hits ?? 0) > 0) {
|
|
20497
20641
|
return {
|
|
20498
20642
|
kind: "terminal",
|
|
20499
20643
|
reason: SANDBOX_REQUEST_CAP_REASON,
|
|
20500
20644
|
message: `${SANDBOX_REQUEST_CAP_REASON}: the job exceeded the sandbox model-request cap` + (counters ? ` (${counters.model_requests} requests, ${counters.cap_hits} refused)` : "")
|
|
20501
20645
|
};
|
|
20502
20646
|
}
|
|
20503
|
-
if (stepFailure == null && exitCode !== null && exitCode !== 0
|
|
20504
|
-
|
|
20647
|
+
if (stepFailure == null && exitCode !== null && (exitCode !== 0 || claudeIsError === true)) {
|
|
20648
|
+
const status = counters?.last_upstream_status;
|
|
20649
|
+
if (status === 429) return { kind: "upstream_rate_limit" };
|
|
20650
|
+
if (status === 401 || status === 403) return { kind: "upstream_auth_failure" };
|
|
20505
20651
|
}
|
|
20506
20652
|
return { kind: "normal" };
|
|
20507
20653
|
}
|
|
20508
20654
|
function routeSandboxFailure(verdict, planFor, nowMs = Date.now()) {
|
|
20509
|
-
if (verdict
|
|
20510
|
-
|
|
20511
|
-
|
|
20512
|
-
|
|
20655
|
+
if (verdict === null) {
|
|
20656
|
+
const plan = planFor();
|
|
20657
|
+
return plan ? { kind: "defer", plan } : { kind: "fail" };
|
|
20658
|
+
}
|
|
20659
|
+
if (verdict.kind === "terminal") return { kind: "terminal", message: verdict.message };
|
|
20660
|
+
if (verdict.kind === "upstream_rate_limit") {
|
|
20513
20661
|
return {
|
|
20514
20662
|
kind: "defer",
|
|
20515
20663
|
plan: { parsed: false, pauseUntil: new Date(nowMs + RATE_LIMIT_TENTATIVE_PAUSE_MS), info: null }
|
|
@@ -20522,7 +20670,6 @@ var init_classifySandboxExit = __esm({
|
|
|
20522
20670
|
"src/daemon/sandbox/classifySandboxExit.ts"() {
|
|
20523
20671
|
"use strict";
|
|
20524
20672
|
init_rateLimit();
|
|
20525
|
-
init_types();
|
|
20526
20673
|
SANDBOX_REQUEST_CAP_REASON = "sandbox_request_cap";
|
|
20527
20674
|
SandboxExitError = class extends Error {
|
|
20528
20675
|
constructor(message2, verdict) {
|
|
@@ -22248,9 +22395,9 @@ var init_run_scan = __esm({
|
|
|
22248
22395
|
init_transcript_signals();
|
|
22249
22396
|
init_report();
|
|
22250
22397
|
init_github_remote();
|
|
22251
|
-
|
|
22398
|
+
init_architectureCounts2();
|
|
22252
22399
|
init_claimDefaultProject();
|
|
22253
|
-
|
|
22400
|
+
init_architectureCounts2();
|
|
22254
22401
|
BOOTSTRAP_HEADLESS = `Run the \`scan\` MCP prompt now and follow it to completion. This is a non-interactive automated run \u2014 skip any steps that pause for user confirmation (e.g. "does this hierarchy look right?"). Proceed with your best-judgement decisions rather than waiting for human input.`;
|
|
22255
22402
|
BOOTSTRAP_INTERACTIVE = `Run the \`scan\` MCP prompt now and follow it to completion. The user is at an interactive terminal \u2014 ask them when the prompt says to, and wait for their answer.
|
|
22256
22403
|
|
|
@@ -22376,15 +22523,15 @@ async function runCloneStep(input, deps = {}) {
|
|
|
22376
22523
|
}
|
|
22377
22524
|
}
|
|
22378
22525
|
function applyEnv(env) {
|
|
22379
|
-
const
|
|
22526
|
+
const saved2 = /* @__PURE__ */ new Map();
|
|
22380
22527
|
for (const [k, v] of Object.entries(env)) {
|
|
22381
22528
|
if (process.env[k] === v) continue;
|
|
22382
|
-
|
|
22529
|
+
saved2.set(k, process.env[k]);
|
|
22383
22530
|
if (v === void 0) delete process.env[k];
|
|
22384
22531
|
else process.env[k] = v;
|
|
22385
22532
|
}
|
|
22386
22533
|
return () => {
|
|
22387
|
-
for (const [k, v] of
|
|
22534
|
+
for (const [k, v] of saved2) {
|
|
22388
22535
|
if (v === void 0) delete process.env[k];
|
|
22389
22536
|
else process.env[k] = v;
|
|
22390
22537
|
}
|
|
@@ -22528,7 +22675,9 @@ async function runAgentStep(input, deps = {}) {
|
|
|
22528
22675
|
cwd: repoDir,
|
|
22529
22676
|
timeoutMs: input.timeoutMs,
|
|
22530
22677
|
model: input.model,
|
|
22531
|
-
|
|
22678
|
+
// Diff/PR: no Bash. `-p` mode does not bind built-ins to --allowedTools,
|
|
22679
|
+
// and a build step run through Bash can forge claude's stderr (BUG-143).
|
|
22680
|
+
...firstScan ? { allowedTools: FIRST_SCAN_ALLOWED_TOOLS } : { builtinTools: ["Read", "Glob", "Grep", "Agent"] },
|
|
22532
22681
|
jsonOutput: true,
|
|
22533
22682
|
settingSources: "user",
|
|
22534
22683
|
// A box is Linux: a prompt over 128 KiB cannot be one argv string.
|
|
@@ -22678,7 +22827,7 @@ __export(run_exports, {
|
|
|
22678
22827
|
});
|
|
22679
22828
|
import { createClient as createClient2 } from "@supabase/supabase-js";
|
|
22680
22829
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
22681
|
-
import { mkdtemp as mkdtemp4, mkdir as mkdir16, writeFile as writeFile15, rm as rm8, stat as stat8, chmod as
|
|
22830
|
+
import { mkdtemp as mkdtemp4, mkdir as mkdir16, writeFile as writeFile15, rm as rm8, stat as stat8, chmod as chmod7 } from "node:fs/promises";
|
|
22682
22831
|
import { tmpdir as tmpdir4 } from "node:os";
|
|
22683
22832
|
import { join as join25 } from "node:path";
|
|
22684
22833
|
import { homedir as homedir8, networkInterfaces as networkInterfaces2 } from "node:os";
|
|
@@ -22739,13 +22888,6 @@ async function routeShutdownInterrupt(id, cancelled2, fail2, exitCode) {
|
|
|
22739
22888
|
console.error(` shutdown retry-route failed for ${id}: ${e instanceof Error ? e.message : e}`);
|
|
22740
22889
|
}
|
|
22741
22890
|
}
|
|
22742
|
-
async function lookupProjectSlug(client, projectId) {
|
|
22743
|
-
const { data, error } = await client.from("projects").select("slug, organizations(slug)").eq("id", projectId).single();
|
|
22744
|
-
if (error || !data) throw new Error(`Project ${projectId} not found: ${error?.message}`);
|
|
22745
|
-
const orgSlug = data.organizations?.slug;
|
|
22746
|
-
if (!orgSlug) throw new Error(`Project ${projectId} has no org slug`);
|
|
22747
|
-
return `${orgSlug}/${data.slug}`;
|
|
22748
|
-
}
|
|
22749
22891
|
function cloneDirFor(baseDir, owner, name) {
|
|
22750
22892
|
return join25(baseDir, owner, name);
|
|
22751
22893
|
}
|
|
@@ -22857,7 +22999,7 @@ async function buildGitEnv(credentials) {
|
|
|
22857
22999
|
].join("\n"),
|
|
22858
23000
|
{ mode: 448 }
|
|
22859
23001
|
);
|
|
22860
|
-
await
|
|
23002
|
+
await chmod7(askpassPath, 448).catch(() => {
|
|
22861
23003
|
});
|
|
22862
23004
|
const gitConfigEntries = [
|
|
22863
23005
|
["credential.helper", ""],
|
|
@@ -22891,24 +23033,24 @@ async function ensureLocalCloneAndFetch(job, entry) {
|
|
|
22891
23033
|
`local mirror ${dir} is missing or not a git repo \u2014 re-run \`archme init ${entry.sourcePath}\``
|
|
22892
23034
|
);
|
|
22893
23035
|
}
|
|
22894
|
-
await execa("git", ["fetch", "--no-tags", "origin", job.repo_branch], { cwd: dir, reject: false });
|
|
23036
|
+
await execa("git", ["fetch", "--no-tags", "origin", job.repo_branch], { cwd: dir, env: localGitEnv(), reject: false });
|
|
22895
23037
|
if (job.source_mode === "pr_update") {
|
|
22896
23038
|
await verifyLocalPrJob(job, async (args) => {
|
|
22897
|
-
const r = await execa("git", args, { cwd: dir, reject: false });
|
|
23039
|
+
const r = await execa("git", args, { cwd: dir, env: localGitEnv(), reject: false });
|
|
22898
23040
|
return { exitCode: r.exitCode ?? 1, stdout: String(r.stdout ?? ""), stderr: String(r.stderr ?? "") };
|
|
22899
23041
|
});
|
|
22900
23042
|
return;
|
|
22901
23043
|
}
|
|
22902
|
-
const afterCheck = await execa("git", ["cat-file", "-e", job.after_sha], { cwd: dir, reject: false });
|
|
23044
|
+
const afterCheck = await execa("git", ["cat-file", "-e", job.after_sha], { cwd: dir, env: localGitEnv(), reject: false });
|
|
22903
23045
|
if (afterCheck.exitCode !== 0) {
|
|
22904
|
-
await execa("git", ["fetch", "origin"], { cwd: dir, reject: false });
|
|
23046
|
+
await execa("git", ["fetch", "origin"], { cwd: dir, env: localGitEnv(), reject: false });
|
|
22905
23047
|
}
|
|
22906
23048
|
}).catch((err4) => {
|
|
22907
23049
|
if (err4 instanceof LocalPrJobRejectedError) throw err4;
|
|
22908
23050
|
const msg = err4 instanceof Error ? err4.message : String(err4);
|
|
22909
23051
|
throw new Error(`local repo ${job.repo_owner}/${job.repo_name} is not usable: ${msg}`);
|
|
22910
23052
|
});
|
|
22911
|
-
return { dir, gitEnv:
|
|
23053
|
+
return { dir, gitEnv: localGitEnv(), cleanupGitEnv: async () => {
|
|
22912
23054
|
} };
|
|
22913
23055
|
}
|
|
22914
23056
|
async function ensureCloneAndFetch(ctx, job, claimDeviceId) {
|
|
@@ -23221,30 +23363,6 @@ async function rpcComplete(ctx, jobId, deviceId, summary2, kind, changed, metric
|
|
|
23221
23363
|
function affectedFieldForComplete(sourceMode, affected) {
|
|
23222
23364
|
return sourceMode === "pr_update" && affected ? affected : void 0;
|
|
23223
23365
|
}
|
|
23224
|
-
async function detectWritesByPhase(client, projectId, archmeBranch, jobId) {
|
|
23225
|
-
const { data, error } = await client.from("commits").select("structural_changeset").eq("project_id", projectId).eq("branch", archmeBranch).eq("metadata->source->>job_id", jobId);
|
|
23226
|
-
if (error) {
|
|
23227
|
-
console.error("commits lookup error:", error.message);
|
|
23228
|
-
return { total: 0, diffWrites: 0, structuralWrites: 0 };
|
|
23229
|
-
}
|
|
23230
|
-
let diffWrites = 0;
|
|
23231
|
-
let structuralWrites = 0;
|
|
23232
|
-
for (const row of data ?? []) {
|
|
23233
|
-
if (row.structural_changeset == null) diffWrites++;
|
|
23234
|
-
else structuralWrites++;
|
|
23235
|
-
}
|
|
23236
|
-
return { total: diffWrites + structuralWrites, diffWrites, structuralWrites };
|
|
23237
|
-
}
|
|
23238
|
-
async function detectMcpActivity(client, jobId) {
|
|
23239
|
-
const { data, error } = await client.from("archme_jobs").select("meaningful_tool_calls, no_change_reason").eq("id", jobId).maybeSingle();
|
|
23240
|
-
if (error) {
|
|
23241
|
-
console.error("mcp_activity lookup error:", error.message);
|
|
23242
|
-
return { reads: void 0, noChange: false };
|
|
23243
|
-
}
|
|
23244
|
-
if (!data) return { reads: void 0, noChange: false };
|
|
23245
|
-
const row = data;
|
|
23246
|
-
return { reads: row.meaningful_tool_calls, noChange: row.no_change_reason != null };
|
|
23247
|
-
}
|
|
23248
23366
|
function setLocalPause(untilMs) {
|
|
23249
23367
|
if (!Number.isFinite(untilMs) || untilMs <= Date.now()) return;
|
|
23250
23368
|
if (pauseUntilMs != null && pauseUntilMs >= untilMs) return;
|
|
@@ -23518,11 +23636,36 @@ async function setupDigestMcp(ctx, job, deviceId) {
|
|
|
23518
23636
|
return {};
|
|
23519
23637
|
}
|
|
23520
23638
|
}
|
|
23639
|
+
function readsFor(ctx, job, deviceId) {
|
|
23640
|
+
return jobReadsFor(
|
|
23641
|
+
{ client: ctx.supabase, post: (part) => postJobContext(ctx, job.id, deviceId, part), isPlatformDevice: platformDevices.has(deviceId) },
|
|
23642
|
+
job
|
|
23643
|
+
);
|
|
23644
|
+
}
|
|
23645
|
+
async function postJobContext(ctx, jobId, deviceId, part) {
|
|
23646
|
+
const response = await fetchWithAuthRetry(
|
|
23647
|
+
"job-context",
|
|
23648
|
+
() => {
|
|
23649
|
+
const accessToken = ctx.auth.getAccessToken();
|
|
23650
|
+
if (!accessToken) throw new Error("daemon is not signed in with a registered device");
|
|
23651
|
+
return fetch(`${ctx.supabaseUrl.replace(/\/$/, "")}/functions/v1/agents-device/job-context`, {
|
|
23652
|
+
method: "POST",
|
|
23653
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${accessToken}` },
|
|
23654
|
+
body: JSON.stringify({ device_id: deviceId, job_id: jobId, part })
|
|
23655
|
+
});
|
|
23656
|
+
},
|
|
23657
|
+
ctx.reLogin
|
|
23658
|
+
);
|
|
23659
|
+
const body = await parseJsonResponse(response);
|
|
23660
|
+
if (!response.ok) throw new Error(`job-context ${part} failed: ${responseError(body, `status ${response.status}`)}`);
|
|
23661
|
+
return body;
|
|
23662
|
+
}
|
|
23521
23663
|
async function prefetchJobContext(ctx, job, deviceId, repoCredentials = getRepoCredentials) {
|
|
23522
23664
|
const log = (msg) => console.log(`[${job.id}] ${msg}`);
|
|
23523
23665
|
const firstScan = job.job_kind === "first_scan";
|
|
23524
23666
|
assertLocalJobShape(firstScan ? { ...job, after_sha: job.scan_ref ?? "" } : job);
|
|
23525
|
-
const
|
|
23667
|
+
const reads = readsFor(ctx, job, deviceId);
|
|
23668
|
+
const projectSlug = await reads.projectSlug();
|
|
23526
23669
|
const jobToken = await mintJobToken(ctx, job.id, deviceId);
|
|
23527
23670
|
const probe = await probeMcpAuth(
|
|
23528
23671
|
`${ctx.mcpBaseUrl}?project=${encodeURIComponent(projectSlug)}&branch=${encodeURIComponent(job.archme_branch)}`,
|
|
@@ -23533,15 +23676,15 @@ async function prefetchJobContext(ctx, job, deviceId, repoCredentials = getRepoC
|
|
|
23533
23676
|
`MCP auth preflight failed after ${probe.attempts} attempt(s) (last status ${probe.lastStatus ?? "n/a"}): ${probe.detail}. Not starting the sandbox \u2014 failing the job so it retries with a freshly minted token.`
|
|
23534
23677
|
);
|
|
23535
23678
|
}
|
|
23536
|
-
const marker = job.source_mode === "pr_update" || firstScan ? { sha: null, repo: null } : await
|
|
23679
|
+
const marker = job.source_mode === "pr_update" || firstScan ? { sha: null, repo: null } : await reads.marker(`${job.repo_owner}/${job.repo_name}`);
|
|
23537
23680
|
const jobRepo = `${job.repo_owner}/${job.repo_name}`;
|
|
23538
|
-
const mappings = await
|
|
23681
|
+
const mappings = await reads.repoMappings(log);
|
|
23539
23682
|
let jobScope = jobRepoScope(mappings, jobRepo);
|
|
23540
23683
|
if (!jobScope) log("repo mappings unreadable: proceeding unseeded");
|
|
23541
23684
|
let seedArch = null;
|
|
23542
23685
|
if (mappings && jobScope && !firstScan) {
|
|
23543
23686
|
try {
|
|
23544
|
-
seedArch = await
|
|
23687
|
+
seedArch = await reads.seedArchitecture();
|
|
23545
23688
|
if (job.source_mode === "pr_update") {
|
|
23546
23689
|
jobScope = forkRepoScope(mappings, jobRepo, new Set(seedArch.components.map((c3) => c3.path)));
|
|
23547
23690
|
}
|
|
@@ -23549,7 +23692,7 @@ async function prefetchJobContext(ctx, job, deviceId, repoCredentials = getRepoC
|
|
|
23549
23692
|
log(`seed architecture unavailable (the agent runs unseeded): ${e.message}`);
|
|
23550
23693
|
}
|
|
23551
23694
|
}
|
|
23552
|
-
const bugsFolderId = await
|
|
23695
|
+
const bugsFolderId = await reads.bugsFolderId();
|
|
23553
23696
|
const model = await resolveRunnableModel(ctx.supabase, { warn: log });
|
|
23554
23697
|
const credentials = await repoCredentials(ctx, job.id, deviceId);
|
|
23555
23698
|
return {
|
|
@@ -23594,8 +23737,9 @@ async function completeClaudeRun(ctx, job, deviceId, run) {
|
|
|
23594
23737
|
throw new ClaudeRunError(
|
|
23595
23738
|
`claude reported is_error in its JSON result (no successful completion)`,
|
|
23596
23739
|
runResult.summary.trim().slice(-FAILURE_DETAIL_MAX) || null,
|
|
23597
|
-
isClaudeAuthFailure(claudeErrorResult(run.stdout), run.stderr),
|
|
23598
|
-
claudeErrorDetails(run.stdout)
|
|
23740
|
+
run.sandboxVerdict ? run.sandboxVerdict.kind === "upstream_auth_failure" : isClaudeAuthFailure(claudeErrorResult(run.stdout), run.stderr),
|
|
23741
|
+
claudeErrorDetails(run.stdout),
|
|
23742
|
+
run.sandboxVerdict ?? null
|
|
23599
23743
|
);
|
|
23600
23744
|
}
|
|
23601
23745
|
const summary2 = runResult.summary.trim().slice(0, 4e3);
|
|
@@ -23603,8 +23747,9 @@ async function completeClaudeRun(ctx, job, deviceId, run) {
|
|
|
23603
23747
|
metrics.model_served = runResult.modelServed;
|
|
23604
23748
|
metrics.usage = runResult.usage;
|
|
23605
23749
|
metrics.cost_usd = runResult.costUsd;
|
|
23606
|
-
const
|
|
23607
|
-
const {
|
|
23750
|
+
const jobReads = run.reads ?? readsFor(ctx, job, deviceId);
|
|
23751
|
+
const { total: writes, diffWrites, structuralWrites } = await jobReads.writesByPhase();
|
|
23752
|
+
const { reads, noChange } = await jobReads.mcpActivity();
|
|
23608
23753
|
markPhase("write_detect", {
|
|
23609
23754
|
commits: writes,
|
|
23610
23755
|
diff_writes: diffWrites,
|
|
@@ -23860,7 +24005,12 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
23860
24005
|
await rpcRollback(ctx, job.id, deviceId);
|
|
23861
24006
|
return;
|
|
23862
24007
|
}
|
|
23863
|
-
const verdict = classifySandboxExit({
|
|
24008
|
+
const verdict = classifySandboxExit({
|
|
24009
|
+
counters: sandboxMetrics,
|
|
24010
|
+
exitCode: outcome.exitCode,
|
|
24011
|
+
stderr: outcome.stderr,
|
|
24012
|
+
claudeIsError: parseClaudeResult(outcome.claudeStdout).isError
|
|
24013
|
+
});
|
|
23864
24014
|
if (verdict.kind === "terminal") throw new SandboxExitError(verdict.message, verdict);
|
|
23865
24015
|
if (outcome.exitCode !== 0) {
|
|
23866
24016
|
const detail = claudeFailureDetail(outcome.stderr, outcome.claudeStdout);
|
|
@@ -23868,13 +24018,24 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
23868
24018
|
throw new ClaudeRunError(
|
|
23869
24019
|
buildClaudeExitMessage(outcome.exitCode, outcome.signal ? ` (${outcome.signal})` : "", outcome.stderr),
|
|
23870
24020
|
detail,
|
|
23871
|
-
|
|
24021
|
+
// The gate's own 401/403, never the box's text (BUG-143).
|
|
24022
|
+
verdict.kind === "upstream_auth_failure",
|
|
23872
24023
|
claudeErrorDetails(outcome.claudeStdout),
|
|
23873
24024
|
verdict
|
|
23874
24025
|
);
|
|
23875
24026
|
}
|
|
24027
|
+
const jobReads = readsFor(ctx, job, deviceId);
|
|
23876
24028
|
if (firstScan) {
|
|
23877
|
-
|
|
24029
|
+
if (verdict.kind === "upstream_rate_limit" || verdict.kind === "upstream_auth_failure") {
|
|
24030
|
+
throw new ClaudeRunError(
|
|
24031
|
+
`claude reported is_error in its JSON result (no successful completion)`,
|
|
24032
|
+
null,
|
|
24033
|
+
verdict.kind === "upstream_auth_failure",
|
|
24034
|
+
claudeErrorDetails(outcome.claudeStdout),
|
|
24035
|
+
verdict
|
|
24036
|
+
);
|
|
24037
|
+
}
|
|
24038
|
+
const gate = firstScanGate(await jobReads.architectureCounts());
|
|
23878
24039
|
if (!gate.ok) throw new Error(gate.reason);
|
|
23879
24040
|
}
|
|
23880
24041
|
await completeClaudeRun(ctx, job, deviceId, {
|
|
@@ -23885,7 +24046,9 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
23885
24046
|
affected: outcome.affected,
|
|
23886
24047
|
startedAt,
|
|
23887
24048
|
markPhase,
|
|
23888
|
-
log
|
|
24049
|
+
log,
|
|
24050
|
+
reads: jobReads,
|
|
24051
|
+
sandboxVerdict: verdict
|
|
23889
24052
|
});
|
|
23890
24053
|
return;
|
|
23891
24054
|
}
|
|
@@ -24155,8 +24318,9 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
24155
24318
|
const runErr = err4 instanceof ClaudeRunError ? err4 : null;
|
|
24156
24319
|
const haystack = stripPromptEcho(`${msg}
|
|
24157
24320
|
${logs.stderr}`, sentPrompt);
|
|
24321
|
+
const boxed = boxedJobs.has(job.id);
|
|
24158
24322
|
const route2 = routeSandboxFailure(
|
|
24159
|
-
err4 instanceof SandboxExitError ? err4.verdict : runErr?.sandboxVerdict ?? null,
|
|
24323
|
+
err4 instanceof SandboxExitError ? err4.verdict : runErr?.sandboxVerdict ?? (boxed ? { kind: "normal" } : null),
|
|
24160
24324
|
() => rateLimitDeferPlanForExit({
|
|
24161
24325
|
message: msg,
|
|
24162
24326
|
stderr: logs.stderr,
|
|
@@ -24173,7 +24337,7 @@ ${logs.stderr}`, sentPrompt);
|
|
|
24173
24337
|
const plan = route2.kind === "defer" ? route2.plan : null;
|
|
24174
24338
|
if (plan) {
|
|
24175
24339
|
const { parsed, pauseUntil, info } = plan;
|
|
24176
|
-
if (!parsed) {
|
|
24340
|
+
if (!parsed && !boxed) {
|
|
24177
24341
|
await rpcReportEvent(ctx, job, deviceId, "rate_limit_unmatched_exit", {
|
|
24178
24342
|
job_id: job.id,
|
|
24179
24343
|
excerpt: [runErr?.claudeError?.text, haystack].filter(Boolean).join("\n").slice(0, 500)
|
|
@@ -24205,8 +24369,12 @@ ${logs.stderr}`, sentPrompt);
|
|
|
24205
24369
|
const notice = authFailureNotice(boxedJobs.has(job.id), runErr.detail);
|
|
24206
24370
|
console.error(`[${job.id}] ${notice.message} Deferring job + pausing daemon until ${pauseUntil.toISOString()}.`);
|
|
24207
24371
|
const detail = { job_id: job.id, claude_said: runErr.detail };
|
|
24208
|
-
|
|
24209
|
-
|
|
24372
|
+
if (job.job_kind !== "first_scan") {
|
|
24373
|
+
await rpcSetDaemonPause(ctx, pauseUntil, notice.reason, detail);
|
|
24374
|
+
setLocalPause(pauseUntil.getTime());
|
|
24375
|
+
} else {
|
|
24376
|
+
firstScanPauseUntilMs = Math.max(firstScanPauseUntilMs, pauseUntil.getTime());
|
|
24377
|
+
}
|
|
24210
24378
|
const deferred = await rpcDefer(ctx, job.id, deviceId, notice.reason, detail);
|
|
24211
24379
|
if (deferred) return;
|
|
24212
24380
|
console.warn(`[${job.id}] defer no-op \u2014 falling through to fail`);
|
|
@@ -24401,6 +24569,7 @@ function exitDaemon(code) {
|
|
|
24401
24569
|
process.exit(resolveExitCode(code, process.env));
|
|
24402
24570
|
}
|
|
24403
24571
|
async function runDaemon() {
|
|
24572
|
+
detachSshAgent();
|
|
24404
24573
|
let lockHandle = null;
|
|
24405
24574
|
try {
|
|
24406
24575
|
lockHandle = await acquireSingleInstanceLock(resolvePidfilePath(process.env));
|
|
@@ -24766,14 +24935,16 @@ var init_run = __esm({
|
|
|
24766
24935
|
init_localPrJob();
|
|
24767
24936
|
init_localPoller();
|
|
24768
24937
|
init_setting();
|
|
24769
|
-
|
|
24938
|
+
init_architectureCounts2();
|
|
24770
24939
|
init_imageManifest();
|
|
24771
24940
|
init_claimStance();
|
|
24772
24941
|
init_platformDevices();
|
|
24942
|
+
init_jobReads();
|
|
24773
24943
|
init_claudeVersion();
|
|
24774
24944
|
init_host();
|
|
24775
24945
|
init_runSandboxedJob();
|
|
24776
24946
|
init_inputDir();
|
|
24947
|
+
init_sshAgent();
|
|
24777
24948
|
init_classifySandboxExit();
|
|
24778
24949
|
HEARTBEAT_INTERVAL_MS = 6e4;
|
|
24779
24950
|
CLAUDE_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
@@ -30597,7 +30768,7 @@ async function runConciergeToken(opts, deps) {
|
|
|
30597
30768
|
async function reserveStdout(fn) {
|
|
30598
30769
|
const stdout = process.stdout;
|
|
30599
30770
|
const realWrite = stdout.write;
|
|
30600
|
-
const
|
|
30771
|
+
const saved2 = { log: console.log, info: console.info, debug: console.debug };
|
|
30601
30772
|
const toStderr = (...args) => console.error(...args);
|
|
30602
30773
|
console.log = toStderr;
|
|
30603
30774
|
console.info = toStderr;
|
|
@@ -30609,9 +30780,9 @@ async function reserveStdout(fn) {
|
|
|
30609
30780
|
});
|
|
30610
30781
|
} finally {
|
|
30611
30782
|
stdout.write = realWrite;
|
|
30612
|
-
console.log =
|
|
30613
|
-
console.info =
|
|
30614
|
-
console.debug =
|
|
30783
|
+
console.log = saved2.log;
|
|
30784
|
+
console.info = saved2.info;
|
|
30785
|
+
console.debug = saved2.debug;
|
|
30615
30786
|
}
|
|
30616
30787
|
}
|
|
30617
30788
|
async function postConciergeTokenWith(supabaseUrl, accessToken, body) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archme/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.1",
|
|
4
4
|
"description": "Map your codebase into a living architecture diagram: run `archme init` in a repo to scan it, `archme daemon start` to keep it current on every commit.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
package/sandbox-image.json
CHANGED