@archme/cli 0.8.0 → 0.8.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 +89 -5
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -10344,10 +10344,31 @@ var init_preflight = __esm({
|
|
|
10344
10344
|
});
|
|
10345
10345
|
|
|
10346
10346
|
// ../shared/daemonModel.ts
|
|
10347
|
-
|
|
10347
|
+
function parseClaudeCodeVersion(output) {
|
|
10348
|
+
return /(\d+)\.(\d+)\.(\d+)/.exec(output ?? "")?.[0] ?? null;
|
|
10349
|
+
}
|
|
10350
|
+
function versionBelow(version, minimum) {
|
|
10351
|
+
const a2 = version.split(".").map(Number);
|
|
10352
|
+
const b = minimum.split(".").map(Number);
|
|
10353
|
+
for (let i2 = 0; i2 < Math.max(a2.length, b.length); i2++) {
|
|
10354
|
+
const d = (a2[i2] ?? 0) - (b[i2] ?? 0);
|
|
10355
|
+
if (d !== 0) return d < 0;
|
|
10356
|
+
}
|
|
10357
|
+
return false;
|
|
10358
|
+
}
|
|
10359
|
+
function runnableModel(requested, installedVersion) {
|
|
10360
|
+
const needs = MIN_CLAUDE_CODE_VERSION[requested];
|
|
10361
|
+
if (!needs || !installedVersion || !versionBelow(installedVersion, needs)) return { model: requested };
|
|
10362
|
+
return { model: FALLBACK_CLAUDE_MODEL, fellBack: { from: requested, needs } };
|
|
10363
|
+
}
|
|
10364
|
+
var DEFAULT_CLAUDE_MODEL, FALLBACK_CLAUDE_MODEL, MIN_CLAUDE_CODE_VERSION;
|
|
10348
10365
|
var init_daemonModel = __esm({
|
|
10349
10366
|
"../shared/daemonModel.ts"() {
|
|
10350
10367
|
DEFAULT_CLAUDE_MODEL = "claude-opus-5-5";
|
|
10368
|
+
FALLBACK_CLAUDE_MODEL = "claude-opus-4-8";
|
|
10369
|
+
MIN_CLAUDE_CODE_VERSION = {
|
|
10370
|
+
"claude-opus-5-5": "2.1.280"
|
|
10371
|
+
};
|
|
10351
10372
|
}
|
|
10352
10373
|
});
|
|
10353
10374
|
|
|
@@ -10509,6 +10530,39 @@ var init_spawn_claude = __esm({
|
|
|
10509
10530
|
}
|
|
10510
10531
|
});
|
|
10511
10532
|
|
|
10533
|
+
// src/scan/claudeVersion.ts
|
|
10534
|
+
async function runClaudeVersion() {
|
|
10535
|
+
const r = await execa("claude", ["--version"], { reject: false, timeout: 15e3 });
|
|
10536
|
+
return r.exitCode === 0 ? String(r.stdout) : null;
|
|
10537
|
+
}
|
|
10538
|
+
function createClaudeVersionProbe(opts = {}) {
|
|
10539
|
+
const exec = opts.exec ?? runClaudeVersion;
|
|
10540
|
+
const now = opts.now ?? Date.now;
|
|
10541
|
+
const ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
|
|
10542
|
+
let cached;
|
|
10543
|
+
return async () => {
|
|
10544
|
+
if (cached && now() - cached.at < ttlMs) return cached.version;
|
|
10545
|
+
let version = null;
|
|
10546
|
+
try {
|
|
10547
|
+
version = parseClaudeCodeVersion(await exec());
|
|
10548
|
+
} catch {
|
|
10549
|
+
version = null;
|
|
10550
|
+
}
|
|
10551
|
+
cached = { version, at: now() };
|
|
10552
|
+
return version;
|
|
10553
|
+
};
|
|
10554
|
+
}
|
|
10555
|
+
var DEFAULT_TTL_MS, claudeCodeVersion;
|
|
10556
|
+
var init_claudeVersion = __esm({
|
|
10557
|
+
"src/scan/claudeVersion.ts"() {
|
|
10558
|
+
"use strict";
|
|
10559
|
+
init_execa();
|
|
10560
|
+
init_daemonModel();
|
|
10561
|
+
DEFAULT_TTL_MS = 10 * 6e4;
|
|
10562
|
+
claudeCodeVersion = createClaudeVersionProbe();
|
|
10563
|
+
}
|
|
10564
|
+
});
|
|
10565
|
+
|
|
10512
10566
|
// src/scan/model-pin.ts
|
|
10513
10567
|
async function resolveModelPin(supabase) {
|
|
10514
10568
|
try {
|
|
@@ -10522,10 +10576,30 @@ async function resolveModelPin(supabase) {
|
|
|
10522
10576
|
return DEFAULT_CLAUDE_MODEL;
|
|
10523
10577
|
}
|
|
10524
10578
|
}
|
|
10579
|
+
async function resolveRunnableModel(supabase, deps = {}) {
|
|
10580
|
+
const requested = await resolveModelPin(supabase);
|
|
10581
|
+
const installed = await (deps.version ?? claudeCodeVersion)();
|
|
10582
|
+
const { model, fellBack } = runnableModel(requested, installed);
|
|
10583
|
+
if (fellBack) {
|
|
10584
|
+
const warned = deps.warned ?? warnedFallbacks;
|
|
10585
|
+
const key = `${fellBack.from}@${installed}`;
|
|
10586
|
+
if (!warned.has(key)) {
|
|
10587
|
+
warned.add(key);
|
|
10588
|
+
(deps.warn ?? console.warn)(
|
|
10589
|
+
`Claude Code ${installed} can't run ${fellBack.from} (needs ${fellBack.needs}+); running ${model} instead. Run \`claude update\` to use ${fellBack.from}.`
|
|
10590
|
+
);
|
|
10591
|
+
}
|
|
10592
|
+
}
|
|
10593
|
+
return model;
|
|
10594
|
+
}
|
|
10595
|
+
var warnedFallbacks;
|
|
10525
10596
|
var init_model_pin = __esm({
|
|
10526
10597
|
"src/scan/model-pin.ts"() {
|
|
10527
10598
|
"use strict";
|
|
10528
10599
|
init_spawn_claude();
|
|
10600
|
+
init_daemonModel();
|
|
10601
|
+
init_claudeVersion();
|
|
10602
|
+
warnedFallbacks = /* @__PURE__ */ new Set();
|
|
10529
10603
|
}
|
|
10530
10604
|
});
|
|
10531
10605
|
|
|
@@ -10646,7 +10720,7 @@ async function runDigestJob(ctx, job, deviceId, inFlight2, mcp) {
|
|
|
10646
10720
|
mcpConfigPath = join8(dir, "mcp.json");
|
|
10647
10721
|
await writeFile5(mcpConfigPath, JSON.stringify({ mcpServers: {} }));
|
|
10648
10722
|
}
|
|
10649
|
-
const model = await
|
|
10723
|
+
const model = await resolveRunnableModel(ctx.supabase);
|
|
10650
10724
|
const proc = spawnClaude({
|
|
10651
10725
|
prompt: buildDigestPrompt(payload),
|
|
10652
10726
|
mcpConfigPath,
|
|
@@ -17051,6 +17125,7 @@ __export(run_exports, {
|
|
|
17051
17125
|
buildClaudeExitMessage: () => buildClaudeExitMessage,
|
|
17052
17126
|
buildDevices: () => buildDevices,
|
|
17053
17127
|
buildDiffPrompt: () => buildDiffPrompt,
|
|
17128
|
+
claudeFailureDetail: () => claudeFailureDetail,
|
|
17054
17129
|
computeDiff: () => computeDiff,
|
|
17055
17130
|
parseClaudeResult: () => parseClaudeResult,
|
|
17056
17131
|
probeMcpAuth: () => probeMcpAuth,
|
|
@@ -17074,6 +17149,12 @@ function attributeKillCause(result, recorded) {
|
|
|
17074
17149
|
function buildClaudeExitMessage(exitCode, causeSuffix, stderr) {
|
|
17075
17150
|
return `claude exited ${exitCode}${causeSuffix}: ${stderr.slice(0, 4e3)}`;
|
|
17076
17151
|
}
|
|
17152
|
+
function claudeFailureDetail(stderr, stdout) {
|
|
17153
|
+
if (stderr.trim() || !stdout.trim()) return null;
|
|
17154
|
+
const parsed = parseClaudeResult(stdout);
|
|
17155
|
+
const text = (parsed.parsed ? parsed.summary : stdout).trim();
|
|
17156
|
+
return text ? text.slice(-FAILURE_DETAIL_MAX) : null;
|
|
17157
|
+
}
|
|
17077
17158
|
async function routeShutdownInterrupt(id, cancelled2, fail, exitCode) {
|
|
17078
17159
|
if (cancelled2.has(id)) return;
|
|
17079
17160
|
if (exitCode === 0) {
|
|
@@ -18016,7 +18097,7 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
18016
18097
|
`MCP auth preflight failed after ${probe.attempts} attempt(s) (last status ${probe.lastStatus ?? "n/a"}): ${probe.detail}. Not spawning claude \u2014 the architecture would not be writable and the run would silently no-op. Failing the job so it retries with a freshly minted token.`
|
|
18017
18098
|
);
|
|
18018
18099
|
}
|
|
18019
|
-
const model = await
|
|
18100
|
+
const model = await resolveRunnableModel(ctx.supabase, { warn: log });
|
|
18020
18101
|
metrics.model = model;
|
|
18021
18102
|
log(`spawning claude (mcp config at ${configPath}, model ${model})`);
|
|
18022
18103
|
const proc = spawnClaude({
|
|
@@ -18054,6 +18135,8 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
18054
18135
|
if (result.exitCode !== 0) {
|
|
18055
18136
|
const causeSuffix = cause ? ` (${result.signal ?? "exit"}, cause: ${cause})` : "";
|
|
18056
18137
|
const stderr = result.stderr ? String(result.stderr) : "";
|
|
18138
|
+
const detail = claudeFailureDetail(stderr, result.stdout ? String(result.stdout) : "");
|
|
18139
|
+
if (detail) log(`claude output: ${detail.replace(/\n/g, " ")}`);
|
|
18057
18140
|
throw new Error(buildClaudeExitMessage(result.exitCode, causeSuffix, stderr));
|
|
18058
18141
|
}
|
|
18059
18142
|
const runResult = parseClaudeResult(result.stdout ? String(result.stdout) : "");
|
|
@@ -18557,7 +18640,7 @@ ${signal} received, shutting down`);
|
|
|
18557
18640
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
18558
18641
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
18559
18642
|
}
|
|
18560
|
-
var HEARTBEAT_INTERVAL_MS, CLAUDE_TIMEOUT_MS, CLAUDE_LARGE_DIFF_TIMEOUT_MS, SAFETY_SWEEP_MS, LOG_STDOUT_CAP_BYTES, LOG_STDERR_CAP_BYTES, PRE_SPAWN_TOKEN_MIN_LIFETIME_MS, SUPABASE_URL, SUPABASE_ANON_KEY, ARCHME_DAEMON_CLIENT_ID, ARCHME_MCP_BASE_URL, CLONE_BASE_DIR, DAEMON_ID, LEASE_SECONDS, inFlight, cancelled, killReasons, activeCleanups, cloneMutex, shuttingDown, daemonVersion, pauseUntilMs, resumeTimer, currentSched, MAX_CONCURRENT_JOBS, ctxByJob, deviceByJob, DEFAULT_CLONE_BASE_DIR, INLINE_PATCH_BYTE_CAP, GIT_SHA_RE, CURATOR_PREAMBLE, CORE_PRINCIPLES, STORY_COVERAGE_GATE, NEW_STORY_GUIDANCE, STORY_DESCRIPTION_EDIT_RULE, PHASE_GUIDANCE, BASE_RULES, DIFF_RULES, finite, channelSeq, MultipleAccountsError, __testDispatch;
|
|
18643
|
+
var HEARTBEAT_INTERVAL_MS, CLAUDE_TIMEOUT_MS, CLAUDE_LARGE_DIFF_TIMEOUT_MS, SAFETY_SWEEP_MS, LOG_STDOUT_CAP_BYTES, LOG_STDERR_CAP_BYTES, FAILURE_DETAIL_MAX, PRE_SPAWN_TOKEN_MIN_LIFETIME_MS, SUPABASE_URL, SUPABASE_ANON_KEY, ARCHME_DAEMON_CLIENT_ID, ARCHME_MCP_BASE_URL, CLONE_BASE_DIR, DAEMON_ID, LEASE_SECONDS, inFlight, cancelled, killReasons, activeCleanups, cloneMutex, shuttingDown, daemonVersion, pauseUntilMs, resumeTimer, currentSched, MAX_CONCURRENT_JOBS, ctxByJob, deviceByJob, DEFAULT_CLONE_BASE_DIR, INLINE_PATCH_BYTE_CAP, GIT_SHA_RE, CURATOR_PREAMBLE, CORE_PRINCIPLES, STORY_COVERAGE_GATE, NEW_STORY_GUIDANCE, STORY_DESCRIPTION_EDIT_RULE, PHASE_GUIDANCE, BASE_RULES, DIFF_RULES, finite, channelSeq, MultipleAccountsError, __testDispatch;
|
|
18561
18644
|
var init_run = __esm({
|
|
18562
18645
|
"src/daemon/run.ts"() {
|
|
18563
18646
|
"use strict";
|
|
@@ -18603,6 +18686,7 @@ var init_run = __esm({
|
|
|
18603
18686
|
SAFETY_SWEEP_MS = 3e4;
|
|
18604
18687
|
LOG_STDOUT_CAP_BYTES = 30 * 1024;
|
|
18605
18688
|
LOG_STDERR_CAP_BYTES = 30 * 1024;
|
|
18689
|
+
FAILURE_DETAIL_MAX = 400;
|
|
18606
18690
|
PRE_SPAWN_TOKEN_MIN_LIFETIME_MS = CLAUDE_LARGE_DIFF_TIMEOUT_MS + 5 * 60 * 1e3;
|
|
18607
18691
|
inFlight = /* @__PURE__ */ new Map();
|
|
18608
18692
|
cancelled = /* @__PURE__ */ new Set();
|
|
@@ -19983,7 +20067,7 @@ async function runScan(opts, deps = {}) {
|
|
|
19983
20067
|
...sourceRepo ? { source: await buildScanSource(opts.repoPath, sourceRepo, headSha) } : {}
|
|
19984
20068
|
});
|
|
19985
20069
|
try {
|
|
19986
|
-
const model = await
|
|
20070
|
+
const model = await resolveRunnableModel(supabase, { warn: log });
|
|
19987
20071
|
const interactive = opts.interactive !== false;
|
|
19988
20072
|
log(
|
|
19989
20073
|
interactive ? `starting claude (mcp config at ${configPath}, model ${model}) \u2014 this session is interactive; answer its questions as they come` : `spawning claude (mcp config at ${configPath}, model ${model}, timeout ${Math.round(SCAN_CLAUDE_TIMEOUT_MS / 6e4)} min)`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archme/cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.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",
|