@archme/cli 0.4.3 → 0.4.5
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 +78 -31
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -8666,12 +8666,6 @@ var init_enroll = __esm({
|
|
|
8666
8666
|
init_execa();
|
|
8667
8667
|
init_credentials();
|
|
8668
8668
|
init_defaults();
|
|
8669
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
8670
|
-
runLogin().catch((err2) => {
|
|
8671
|
-
console.error(err2 instanceof Error ? err2.message : err2);
|
|
8672
|
-
process.exit(1);
|
|
8673
|
-
});
|
|
8674
|
-
}
|
|
8675
8669
|
}
|
|
8676
8670
|
});
|
|
8677
8671
|
|
|
@@ -8726,13 +8720,43 @@ var init_paths = __esm({
|
|
|
8726
8720
|
}
|
|
8727
8721
|
});
|
|
8728
8722
|
|
|
8723
|
+
// src/daemon/supervision.ts
|
|
8724
|
+
function isSupervised(env) {
|
|
8725
|
+
return env[SUPERVISED_ENV_VAR] === "1";
|
|
8726
|
+
}
|
|
8727
|
+
function resolveExitCode(code, env) {
|
|
8728
|
+
return isSupervised(env) && PERMANENT_EXIT_CODES.has(code) ? 0 : code;
|
|
8729
|
+
}
|
|
8730
|
+
function supervisedStopNotice(code, env) {
|
|
8731
|
+
if (!isSupervised(env) || !PERMANENT_EXIT_CODES.has(code)) return null;
|
|
8732
|
+
return "this cannot be fixed by restarting, so the service is stopping rather than retrying; re-run `archme daemon start` once resolved";
|
|
8733
|
+
}
|
|
8734
|
+
var PERMANENT_EXIT_CODES, SUPERVISED_ENV_VAR;
|
|
8735
|
+
var init_supervision = __esm({
|
|
8736
|
+
"src/daemon/supervision.ts"() {
|
|
8737
|
+
"use strict";
|
|
8738
|
+
PERMANENT_EXIT_CODES = /* @__PURE__ */ new Set([
|
|
8739
|
+
1,
|
|
8740
|
+
// missing/unreadable config
|
|
8741
|
+
2,
|
|
8742
|
+
// no stored credentials — needs `archme login`
|
|
8743
|
+
78
|
|
8744
|
+
// several accounts on one machine — needs a human to choose
|
|
8745
|
+
]);
|
|
8746
|
+
SUPERVISED_ENV_VAR = "ARCHME_SUPERVISED";
|
|
8747
|
+
}
|
|
8748
|
+
});
|
|
8749
|
+
|
|
8729
8750
|
// src/daemon/service/unitFiles.ts
|
|
8751
|
+
function unitEnv(env) {
|
|
8752
|
+
return { ...env, [SUPERVISED_ENV_VAR]: "1" };
|
|
8753
|
+
}
|
|
8730
8754
|
function xmlEscape(s) {
|
|
8731
8755
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
8732
8756
|
}
|
|
8733
8757
|
function renderLaunchdPlist(opts) {
|
|
8734
8758
|
const argLines = [opts.nodeBin, opts.cliEntry, "daemon", "run"].map((a2) => ` <string>${xmlEscape(a2)}</string>`).join("\n");
|
|
8735
|
-
const envLines = Object.entries(opts.env).map(
|
|
8759
|
+
const envLines = Object.entries(unitEnv(opts.env)).map(
|
|
8736
8760
|
([k, v]) => ` <key>${xmlEscape(k)}</key>
|
|
8737
8761
|
<string>${xmlEscape(v)}</string>`
|
|
8738
8762
|
).join("\n");
|
|
@@ -8750,8 +8774,8 @@ ${argLines}
|
|
|
8750
8774
|
<true/>
|
|
8751
8775
|
<key>KeepAlive</key>
|
|
8752
8776
|
<dict>
|
|
8753
|
-
<key>
|
|
8754
|
-
<
|
|
8777
|
+
<key>SuccessfulExit</key>
|
|
8778
|
+
<false/>
|
|
8755
8779
|
</dict>
|
|
8756
8780
|
<key>ThrottleInterval</key>
|
|
8757
8781
|
<integer>10</integer>
|
|
@@ -8774,7 +8798,7 @@ function systemdArgQuote(s) {
|
|
|
8774
8798
|
return `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
8775
8799
|
}
|
|
8776
8800
|
function renderSystemdUnit(opts) {
|
|
8777
|
-
const envLines = Object.entries(opts.env).map(([k, v]) => `Environment="${k}=${systemdEnvEscape(v)}"`).join("\n");
|
|
8801
|
+
const envLines = Object.entries(unitEnv(opts.env)).map(([k, v]) => `Environment="${k}=${systemdEnvEscape(v)}"`).join("\n");
|
|
8778
8802
|
const execStart = [
|
|
8779
8803
|
systemdArgQuote(opts.nodeBin),
|
|
8780
8804
|
systemdArgQuote(opts.cliEntry),
|
|
@@ -8801,6 +8825,7 @@ var init_unitFiles = __esm({
|
|
|
8801
8825
|
"src/daemon/service/unitFiles.ts"() {
|
|
8802
8826
|
"use strict";
|
|
8803
8827
|
init_paths();
|
|
8828
|
+
init_supervision();
|
|
8804
8829
|
}
|
|
8805
8830
|
});
|
|
8806
8831
|
|
|
@@ -9581,6 +9606,9 @@ var init_daemonModel = __esm({
|
|
|
9581
9606
|
});
|
|
9582
9607
|
|
|
9583
9608
|
// src/scan/spawn-claude.ts
|
|
9609
|
+
function stripNulBytes(arg) {
|
|
9610
|
+
return arg.includes("\0") ? arg.replaceAll("\0", "\uFFFD") : arg;
|
|
9611
|
+
}
|
|
9584
9612
|
function buildClaudeArgs(opts) {
|
|
9585
9613
|
const tools = (opts.allowedTools ?? DEFAULT_ALLOWED_TOOLS).join(",");
|
|
9586
9614
|
const args = [
|
|
@@ -9607,7 +9635,7 @@ function buildClaudeArgs(opts) {
|
|
|
9607
9635
|
if (opts.model) {
|
|
9608
9636
|
args.push("--model", opts.model);
|
|
9609
9637
|
}
|
|
9610
|
-
return args;
|
|
9638
|
+
return args.map(stripNulBytes);
|
|
9611
9639
|
}
|
|
9612
9640
|
function spawnClaude(opts) {
|
|
9613
9641
|
requireBinary("claude");
|
|
@@ -14189,15 +14217,17 @@ async function acquireSingleInstanceLock(pidfile) {
|
|
|
14189
14217
|
}
|
|
14190
14218
|
};
|
|
14191
14219
|
}
|
|
14192
|
-
var SingleInstanceLockedError;
|
|
14220
|
+
var SINGLE_INSTANCE_EXIT_CODE, LOCK_HELD_MESSAGE, SingleInstanceLockedError;
|
|
14193
14221
|
var init_singleInstanceLock = __esm({
|
|
14194
14222
|
"src/daemon/service/singleInstanceLock.ts"() {
|
|
14195
14223
|
"use strict";
|
|
14224
|
+
SINGLE_INSTANCE_EXIT_CODE = 64;
|
|
14225
|
+
LOCK_HELD_MESSAGE = "already holds";
|
|
14196
14226
|
SingleInstanceLockedError = class extends Error {
|
|
14197
14227
|
heldByPid;
|
|
14198
14228
|
constructor(pidfile, heldByPid) {
|
|
14199
14229
|
super(
|
|
14200
|
-
heldByPid != null ? `another archme daemon
|
|
14230
|
+
heldByPid != null ? `another archme daemon ${LOCK_HELD_MESSAGE} ${pidfile} (pid ${heldByPid})` : `another archme daemon ${LOCK_HELD_MESSAGE} ${pidfile}`
|
|
14201
14231
|
);
|
|
14202
14232
|
this.heldByPid = heldByPid;
|
|
14203
14233
|
this.name = "SingleInstanceLockedError";
|
|
@@ -14881,9 +14911,13 @@ function rateLimitDeferPlan(text, nowMs = Date.now(), defaultTimeZone = localTim
|
|
|
14881
14911
|
}
|
|
14882
14912
|
return null;
|
|
14883
14913
|
}
|
|
14914
|
+
function stripPromptEcho(haystack, prompt) {
|
|
14915
|
+
if (!prompt || prompt.length < 40) return haystack;
|
|
14916
|
+
return haystack.split(prompt).join(" ");
|
|
14917
|
+
}
|
|
14884
14918
|
function rateLimitDeferPlanForExit(channels, nowMs = Date.now(), defaultTimeZone = localTimeZone()) {
|
|
14885
|
-
const haystack = `${channels.message}
|
|
14886
|
-
${channels.stderr}
|
|
14919
|
+
const haystack = stripPromptEcho(`${channels.message}
|
|
14920
|
+
${channels.stderr}`, channels.prompt);
|
|
14887
14921
|
return rateLimitDeferPlan(haystack, nowMs, defaultTimeZone);
|
|
14888
14922
|
}
|
|
14889
14923
|
var RATE_LIMIT_RE, MONTHS, RATE_LIMIT_TENTATIVE_PAUSE_MS, DATED_RESET_ROLLOVER_GRACE_MS, RATE_LIMIT_PAUSE_PADDING_MS, RATE_LIMIT_SHAPED_RE;
|
|
@@ -15680,7 +15714,6 @@ import { randomUUID } from "node:crypto";
|
|
|
15680
15714
|
import { mkdtemp as mkdtemp3, mkdir as mkdir10, writeFile as writeFile10, rm as rm6, stat as stat8, chmod as chmod3 } from "node:fs/promises";
|
|
15681
15715
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
15682
15716
|
import { join as join18 } from "node:path";
|
|
15683
|
-
import { pathToFileURL } from "node:url";
|
|
15684
15717
|
import { homedir as homedir5 } from "node:os";
|
|
15685
15718
|
function attributeKillCause(result, recorded) {
|
|
15686
15719
|
if (recorded) return recorded;
|
|
@@ -16428,6 +16461,7 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
16428
16461
|
};
|
|
16429
16462
|
let metrics = { durations_ms: timings };
|
|
16430
16463
|
let logs = { stdout: "", stderr: "" };
|
|
16464
|
+
let sentPrompt;
|
|
16431
16465
|
const cleanupFns = [];
|
|
16432
16466
|
const heartbeat = setInterval(() => {
|
|
16433
16467
|
rpcHeartbeat(ctx, job.id, deviceId);
|
|
@@ -16561,6 +16595,7 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
16561
16595
|
}
|
|
16562
16596
|
const bugsFolderId = await ensureBugsFolder(ctx.supabase, job.project_id);
|
|
16563
16597
|
const prompt = buildDiffPrompt(job, projectSlug, diff, worktreeDir, affectedSeed, bugsFolderId);
|
|
16598
|
+
sentPrompt = prompt;
|
|
16564
16599
|
if (cancelled.has(job.id)) {
|
|
16565
16600
|
log(`cancelled before claude spawn, aborting`);
|
|
16566
16601
|
return;
|
|
@@ -16677,9 +16712,14 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
16677
16712
|
return;
|
|
16678
16713
|
}
|
|
16679
16714
|
const msg = err2 instanceof Error ? err2.message : String(err2);
|
|
16680
|
-
const haystack = `${msg}
|
|
16681
|
-
${logs.stderr}
|
|
16682
|
-
const plan = rateLimitDeferPlanForExit({
|
|
16715
|
+
const haystack = stripPromptEcho(`${msg}
|
|
16716
|
+
${logs.stderr}`, sentPrompt);
|
|
16717
|
+
const plan = rateLimitDeferPlanForExit({
|
|
16718
|
+
message: msg,
|
|
16719
|
+
stderr: logs.stderr,
|
|
16720
|
+
stdout: logs.stdout,
|
|
16721
|
+
prompt: sentPrompt
|
|
16722
|
+
});
|
|
16683
16723
|
if (plan) {
|
|
16684
16724
|
const { parsed, pauseUntil, info } = plan;
|
|
16685
16725
|
if (!parsed) {
|
|
@@ -16862,6 +16902,11 @@ async function signInAccount(creds, makeAuth) {
|
|
|
16862
16902
|
}
|
|
16863
16903
|
return { active, lastErr, usedFallback };
|
|
16864
16904
|
}
|
|
16905
|
+
function exitDaemon(code) {
|
|
16906
|
+
const notice = supervisedStopNotice(code, process.env);
|
|
16907
|
+
if (notice) console.error(notice);
|
|
16908
|
+
process.exit(resolveExitCode(code, process.env));
|
|
16909
|
+
}
|
|
16865
16910
|
async function runDaemon() {
|
|
16866
16911
|
let lockHandle = null;
|
|
16867
16912
|
try {
|
|
@@ -16869,7 +16914,7 @@ async function runDaemon() {
|
|
|
16869
16914
|
} catch (err2) {
|
|
16870
16915
|
if (err2 instanceof SingleInstanceLockedError) {
|
|
16871
16916
|
console.error(String(err2.message));
|
|
16872
|
-
process.exit(
|
|
16917
|
+
process.exit(SINGLE_INSTANCE_EXIT_CODE);
|
|
16873
16918
|
}
|
|
16874
16919
|
throw err2;
|
|
16875
16920
|
}
|
|
@@ -16885,7 +16930,7 @@ async function runDaemon() {
|
|
|
16885
16930
|
} catch {
|
|
16886
16931
|
}
|
|
16887
16932
|
}
|
|
16888
|
-
|
|
16933
|
+
exitDaemon(1);
|
|
16889
16934
|
}
|
|
16890
16935
|
throw err2;
|
|
16891
16936
|
}
|
|
@@ -16916,7 +16961,7 @@ async function runDaemon() {
|
|
|
16916
16961
|
} catch {
|
|
16917
16962
|
}
|
|
16918
16963
|
}
|
|
16919
|
-
|
|
16964
|
+
exitDaemon(2);
|
|
16920
16965
|
}
|
|
16921
16966
|
let credentials;
|
|
16922
16967
|
try {
|
|
@@ -16930,7 +16975,7 @@ async function runDaemon() {
|
|
|
16930
16975
|
} catch {
|
|
16931
16976
|
}
|
|
16932
16977
|
}
|
|
16933
|
-
|
|
16978
|
+
exitDaemon(78);
|
|
16934
16979
|
}
|
|
16935
16980
|
throw err2;
|
|
16936
16981
|
}
|
|
@@ -16945,7 +16990,7 @@ async function runDaemon() {
|
|
|
16945
16990
|
} catch {
|
|
16946
16991
|
}
|
|
16947
16992
|
}
|
|
16948
|
-
|
|
16993
|
+
exitDaemon(75);
|
|
16949
16994
|
}
|
|
16950
16995
|
const auth = active.auth;
|
|
16951
16996
|
const client = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
|
@@ -17127,6 +17172,7 @@ var init_run = __esm({
|
|
|
17127
17172
|
init_dispatch();
|
|
17128
17173
|
init_defaults();
|
|
17129
17174
|
init_singleInstanceLock();
|
|
17175
|
+
init_supervision();
|
|
17130
17176
|
init_paths();
|
|
17131
17177
|
init_semaphore();
|
|
17132
17178
|
init_bearer();
|
|
@@ -17327,12 +17373,6 @@ ${ANCHOR_VERIFICATION}`;
|
|
|
17327
17373
|
return daemonVersion;
|
|
17328
17374
|
}
|
|
17329
17375
|
};
|
|
17330
|
-
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
17331
|
-
runDaemon().catch((err2) => {
|
|
17332
|
-
console.error("fatal:", err2);
|
|
17333
|
-
process.exit(1);
|
|
17334
|
-
});
|
|
17335
|
-
}
|
|
17336
17376
|
}
|
|
17337
17377
|
});
|
|
17338
17378
|
|
|
@@ -19267,7 +19307,14 @@ async function registerLocalWatch(args) {
|
|
|
19267
19307
|
p_project_id: projectId,
|
|
19268
19308
|
p_repo_owner: target.repoOwner,
|
|
19269
19309
|
p_repo_name: target.repoName,
|
|
19270
|
-
p_branch: target.repoBranch
|
|
19310
|
+
p_branch: target.repoBranch,
|
|
19311
|
+
// The ArchMe branch has to be RECORDED, not re-derived by each reader.
|
|
19312
|
+
// The poller resolves it from the row (`commit_update_archme_branch ??
|
|
19313
|
+
// branch`, mirroring the webhook); with the column unset it fell back to
|
|
19314
|
+
// the git branch, so registration checked `main-scan` while polling read
|
|
19315
|
+
// `main`, found no marker, and idled forever with everything looking
|
|
19316
|
+
// healthy. Migration 111.
|
|
19317
|
+
p_archme_branch: target.archmeBranch
|
|
19271
19318
|
});
|
|
19272
19319
|
if (watchErr || typeof watchedRepoId !== "string") {
|
|
19273
19320
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archme/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
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",
|