@archme/cli 0.11.1 → 0.11.3
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 +311 -75
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -13127,6 +13127,21 @@ Everything a reader sees in a sequence \u2014 arrow labels, Note text, and the c
|
|
|
13127
13127
|
}
|
|
13128
13128
|
});
|
|
13129
13129
|
|
|
13130
|
+
// ../shared/waypoints.ts
|
|
13131
|
+
var init_waypoints = __esm({
|
|
13132
|
+
"../shared/waypoints.ts"() {
|
|
13133
|
+
}
|
|
13134
|
+
});
|
|
13135
|
+
|
|
13136
|
+
// ../shared/leafEndpoints.ts
|
|
13137
|
+
var LEAF_ENDPOINT_GUIDANCE;
|
|
13138
|
+
var init_leafEndpoints = __esm({
|
|
13139
|
+
"../shared/leafEndpoints.ts"() {
|
|
13140
|
+
init_waypoints();
|
|
13141
|
+
LEAF_ENDPOINT_GUIDANCE = `- **Arrows connect leaves.** Name the component that does the work, never the parent it sits in. A component with children (other than its input/output interface ports) is a group: an arrow to it lands on the group's box and can't be followed inside, while an arrow to a leaf still draws on the parent's box whenever the parent is collapsed. If a parent's own code acts, model that code as one more child and name that child. An arrow between a component and one of its own children is always this mistake.`;
|
|
13142
|
+
}
|
|
13143
|
+
});
|
|
13144
|
+
|
|
13130
13145
|
// ../shared/componentOrganization.ts
|
|
13131
13146
|
var COMPONENT_ORGANIZATION_GUIDANCE;
|
|
13132
13147
|
var init_componentOrganization = __esm({
|
|
@@ -13181,9 +13196,10 @@ ${draftBlock}Sequence diagram format:
|
|
|
13181
13196
|
- Use "as" aliases for display names: participant root.api.gateway as API Gateway
|
|
13182
13197
|
- Supports combined fragments: alt/else, opt, par/and, loop, critical/option, break
|
|
13183
13198
|
- All participant references MUST be absolute paths prefixed with "root." (e.g., root.backend.api, never backend.api). Scope-relative paths are rejected on write \u2014 they break move_architecture's path-rewriter and the UML grouping logic.
|
|
13199
|
+
${LEAF_ENDPOINT_GUIDANCE}
|
|
13184
13200
|
- Example: "sequenceDiagram\\n root.mobile_user->>root.client: opens app\\n root.client->>root.api.post_users: POST /users\\n root.api.post_users->>root.db: Save new user\\n root.db-->>root.api.post_users: user record\\n root.api.post_users-->>root.client: Account created"
|
|
13185
|
-
- With branching: "sequenceDiagram\\n root.client->>root.api: POST /upload\\n alt File accepted\\n root.api-->>root.client: Upload saved\\n else Wrong type or too large\\n root.api-->>root.client: Upload rejected\\n end"
|
|
13186
|
-
- With parallelism: "sequenceDiagram\\n root.api->>root.db: Record the upload\\n par\\n root.api->>root.storage: Store the file\\n and\\n root.api->>root.search: Make it searchable\\n end"
|
|
13201
|
+
- With branching: "sequenceDiagram\\n root.client->>root.api.upload: POST /upload\\n alt File accepted\\n root.api.upload-->>root.client: Upload saved\\n else Wrong type or too large\\n root.api.upload-->>root.client: Upload rejected\\n end"
|
|
13202
|
+
- With parallelism: "sequenceDiagram\\n root.api.upload->>root.db: Record the upload\\n par\\n root.api.upload->>root.storage: Store the file\\n and\\n root.api.upload->>root.search: Make it searchable\\n end"
|
|
13187
13203
|
|
|
13188
13204
|
${SEQUENCE_WORDING_GUIDANCE}
|
|
13189
13205
|
|
|
@@ -13221,6 +13237,7 @@ var init_scanPrompts = __esm({
|
|
|
13221
13237
|
init_storyNaming();
|
|
13222
13238
|
init_storyChapterGuidance();
|
|
13223
13239
|
init_sequenceWording();
|
|
13240
|
+
init_leafEndpoints();
|
|
13224
13241
|
init_componentOrganization();
|
|
13225
13242
|
BUILD_METHODOLOGY = `You are a build sub-agent. You are part of a multi-agent system that builds a comprehensive visual architecture of a codebase \u2014 components, connections, and user stories that trace data flow end-to-end. Your role is to translate research findings into actual architecture: creating components backed by real code references, wiring connections between them, and building story sequence diagrams that trace how data flows through the system.
|
|
13226
13243
|
|
|
@@ -13229,7 +13246,7 @@ var init_scanPrompts = __esm({
|
|
|
13229
13246
|
- Only build what the research findings and code evidence support. Do not invent components, connections, or user stories that aren't backed by real code. If findings are insufficient, flag gaps rather than guessing.
|
|
13230
13247
|
- Every connection MUST have a non-empty method
|
|
13231
13248
|
- Keep component hierarchies nested (e.g., backend > api > routes)
|
|
13232
|
-
-
|
|
13249
|
+
- Name connectionUpdates endpoints with "root."-prefixed paths; each connection is stored where its endpoints meet
|
|
13233
13250
|
- External services must be created as components with \`role: "external"\` (and \`kind: "human"\` for human actors), then referenced by dot-path in sequences like any other component
|
|
13234
13251
|
- Small utility modules are implementation details \u2014 omit unless architecturally significant
|
|
13235
13252
|
- Components must exist before non-draft stories can reference them. Add components first, then wire stories.
|
|
@@ -13341,8 +13358,9 @@ Component annotations:
|
|
|
13341
13358
|
- Example: { id: "user-org", from: "user", to: "org", method: "belongs_to", reference: true }
|
|
13342
13359
|
|
|
13343
13360
|
Connection format:
|
|
13344
|
-
-
|
|
13345
|
-
-
|
|
13361
|
+
- Name both endpoints with "root."-prefixed dot-paths, as in sequences (or paths relative to the entry's "at"); interface children too: "root.api_server.post_users"
|
|
13362
|
+
- You don't choose the scope: each connection is stored where its endpoints' parents meet, and the result says where and under which id \u2014 use that "at" + id to remove it
|
|
13363
|
+
- id is optional: omitted, it is minted as "<from>-><to>"
|
|
13346
13364
|
- method describes how components communicate (e.g., REST, gRPC, GraphQL, WebSocket, Kafka, function, event)`;
|
|
13347
13365
|
FORMAT_REF_DRAFT_STORIES_BLOCK = `Draft stories:
|
|
13348
13366
|
- Set draft: true for stories where the architecture isn't built yet
|
|
@@ -13571,6 +13589,16 @@ var init_validationCodes = __esm({
|
|
|
13571
13589
|
// ──────────────────────────────────────────────────────────────────────────
|
|
13572
13590
|
/** componentUpdates[].remove references an id that doesn't exist at scope. */
|
|
13573
13591
|
COMPONENT_REMOVE_ID_NOT_FOUND: "component.remove.id-not-found",
|
|
13592
|
+
/**
|
|
13593
|
+
* WARNING (non-blocking): this write removed components, so the connections
|
|
13594
|
+
* naming them (or their descendants), in any scope, were removed with them.
|
|
13595
|
+
*/
|
|
13596
|
+
COMPONENT_REMOVE_CONNECTIONS_REMOVED: "component.remove.connections-removed",
|
|
13597
|
+
/**
|
|
13598
|
+
* WARNING (non-blocking): this write removed components that story sequences
|
|
13599
|
+
* still name. The sequences are left as they are for the agent to fix.
|
|
13600
|
+
*/
|
|
13601
|
+
COMPONENT_REMOVE_STORY_STILL_REFERENCES: "component.remove.story-still-references",
|
|
13574
13602
|
// ──────────────────────────────────────────────────────────────────────────
|
|
13575
13603
|
// connection.add
|
|
13576
13604
|
// ──────────────────────────────────────────────────────────────────────────
|
|
@@ -13584,9 +13612,16 @@ var init_validationCodes = __esm({
|
|
|
13584
13612
|
CONNECTION_ADD_MISSING_TO: "connection.add.missing-to",
|
|
13585
13613
|
/** Missing or empty `method`. */
|
|
13586
13614
|
CONNECTION_ADD_MISSING_METHOD: "connection.add.missing-method",
|
|
13587
|
-
/**
|
|
13615
|
+
/**
|
|
13616
|
+
* @deprecated No longer emitted: a connection add is stored where its
|
|
13617
|
+
* endpoints meet (`resolveConnectionUpdates`), whatever scope it names.
|
|
13618
|
+
* Connection emitted at a parent scope outside the current scope.
|
|
13619
|
+
*/
|
|
13588
13620
|
CONNECTION_AT_WRONG_SCOPE_OUTSIDE: "connection.add.wrong-scope-outside",
|
|
13589
|
-
/**
|
|
13621
|
+
/**
|
|
13622
|
+
* @deprecated No longer emitted, as above.
|
|
13623
|
+
* Connection internal to a child but added at the parent level.
|
|
13624
|
+
*/
|
|
13590
13625
|
CONNECTION_AT_WRONG_SCOPE_INTERNAL: "connection.add.wrong-scope-internal",
|
|
13591
13626
|
// ──────────────────────────────────────────────────────────────────────────
|
|
13592
13627
|
// connection.remove
|
|
@@ -13606,6 +13641,12 @@ var init_validationCodes = __esm({
|
|
|
13606
13641
|
* One code, both sites: to an agent it's the same rule.
|
|
13607
13642
|
*/
|
|
13608
13643
|
CONNECTION_PAIR_ALREADY_CONNECTED: "connection.add.pair-already-connected",
|
|
13644
|
+
/**
|
|
13645
|
+
* WARNING (non-blocking): an explicit `connectionUpdates.add` was NOT stored —
|
|
13646
|
+
* a finer edge on the same pair (one endpoint a child of this one's) already
|
|
13647
|
+
* says it, and the subsumption prune keeps only the finer edge.
|
|
13648
|
+
*/
|
|
13649
|
+
CONNECTION_ADD_SUBSUMED_BY_CHILD: "connection.add.subsumed-by-child",
|
|
13609
13650
|
// ──────────────────────────────────────────────────────────────────────────
|
|
13610
13651
|
// story.add — story-add fields
|
|
13611
13652
|
// ──────────────────────────────────────────────────────────────────────────
|
|
@@ -13696,6 +13737,14 @@ var init_validationCodes = __esm({
|
|
|
13696
13737
|
PARTICIPANT_NOT_ROOT_PREFIXED: "sequence.participant.not-root-prefixed",
|
|
13697
13738
|
/** Participant dot-path references a component that doesn't exist. */
|
|
13698
13739
|
PARTICIPANT_COMPONENT_NOT_FOUND: "sequence.participant.component-not-found",
|
|
13740
|
+
/**
|
|
13741
|
+
* WARNING (non-blocking): an arrow in a sequence the write authored, or a
|
|
13742
|
+
* `connectionUpdates` add, ends on a component with children
|
|
13743
|
+
* (`LEAF_ENDPOINT_GUIDANCE`). The connection lands on the group's box instead
|
|
13744
|
+
* of the part that does the work. One code for both sites, as with
|
|
13745
|
+
* CONNECTION_PAIR_ALREADY_CONNECTED. Silent on a byte-identical re-send.
|
|
13746
|
+
*/
|
|
13747
|
+
PARTICIPANT_HAS_CHILDREN: "sequence.participant.has-children",
|
|
13699
13748
|
// ──────────────────────────────────────────────────────────────────────────
|
|
13700
13749
|
// sequence.ref — validateSequenceRefs
|
|
13701
13750
|
// ──────────────────────────────────────────────────────────────────────────
|
|
@@ -16540,7 +16589,19 @@ function stripPromptEcho(haystack, prompt) {
|
|
|
16540
16589
|
function rateLimitDeferPlanForExit(channels, nowMs = Date.now(), defaultTimeZone = localTimeZone()) {
|
|
16541
16590
|
const haystack = stripPromptEcho(`${channels.message}
|
|
16542
16591
|
${channels.stderr}`, channels.prompt);
|
|
16543
|
-
|
|
16592
|
+
const plan = rateLimitDeferPlan(haystack, nowMs, defaultTimeZone);
|
|
16593
|
+
if (plan?.parsed) return plan;
|
|
16594
|
+
return claudeErrorDeferPlan(channels.claudeError, nowMs, defaultTimeZone) ?? plan;
|
|
16595
|
+
}
|
|
16596
|
+
function claudeErrorDeferPlan(error, nowMs, defaultTimeZone) {
|
|
16597
|
+
if (!error) return null;
|
|
16598
|
+
const text = error.text.trim();
|
|
16599
|
+
const parsed = rateLimitPauseUntil(text, nowMs, defaultTimeZone);
|
|
16600
|
+
const opensWithLimit = parsed != null && text.startsWith(parsed.info.matched);
|
|
16601
|
+
if (error.apiErrorStatus === 429 || error.apiErrorStatus == null && opensWithLimit) {
|
|
16602
|
+
return parsed ? { parsed: true, pauseUntil: parsed.pauseUntil, info: parsed.info } : { parsed: false, pauseUntil: new Date(nowMs + RATE_LIMIT_TENTATIVE_PAUSE_MS), info: null };
|
|
16603
|
+
}
|
|
16604
|
+
return null;
|
|
16544
16605
|
}
|
|
16545
16606
|
var RATE_LIMIT_RE, MONTHS, RATE_LIMIT_TENTATIVE_PAUSE_MS, DATED_RESET_ROLLOVER_GRACE_MS, RATE_LIMIT_PAUSE_PADDING_MS, RATE_LIMIT_SHAPED_RE;
|
|
16546
16607
|
var init_rateLimit = __esm({
|
|
@@ -17230,6 +17291,16 @@ var init_defaultBranch = __esm({
|
|
|
17230
17291
|
});
|
|
17231
17292
|
|
|
17232
17293
|
// ../shared/prRefs.ts
|
|
17294
|
+
function parsePrRefs(message) {
|
|
17295
|
+
if (!message) return [];
|
|
17296
|
+
const refs = [...message.matchAll(PR_REF)].map((m) => Number(m[1]));
|
|
17297
|
+
const bare = refs.length ? null : bareMergePrNumber(message);
|
|
17298
|
+
return bare === null ? refs : [bare];
|
|
17299
|
+
}
|
|
17300
|
+
function lastPrRef(message) {
|
|
17301
|
+
const refs = parsePrRefs(message);
|
|
17302
|
+
return refs[refs.length - 1] ?? null;
|
|
17303
|
+
}
|
|
17233
17304
|
function pushCommitSubject(message) {
|
|
17234
17305
|
if (message == null) return null;
|
|
17235
17306
|
const [subject = "", ...body] = message.split("\n");
|
|
@@ -17237,10 +17308,15 @@ function pushCommitSubject(message) {
|
|
|
17237
17308
|
const title = body.find((line) => line.trim())?.trim();
|
|
17238
17309
|
return pr && title && !TRAILER_LINE.test(title) ? `${title} (#${pr[1]})` : subject;
|
|
17239
17310
|
}
|
|
17240
|
-
|
|
17311
|
+
function bareMergePrNumber(subject) {
|
|
17312
|
+
const pr = subject ? MERGE_PR_SUBJECT.exec(subject.trim()) : null;
|
|
17313
|
+
return pr ? Number(pr[1]) : null;
|
|
17314
|
+
}
|
|
17315
|
+
var PR_REF, MERGE_PR_SUBJECT, TRAILER_LINE;
|
|
17241
17316
|
var init_prRefs = __esm({
|
|
17242
17317
|
"../shared/prRefs.ts"() {
|
|
17243
17318
|
init_repoContainer();
|
|
17319
|
+
PR_REF = /\(#(\d+)\)/g;
|
|
17244
17320
|
MERGE_PR_SUBJECT = /^Merge pull request #(\d+) from \S+$/;
|
|
17245
17321
|
TRAILER_LINE = /^[A-Za-z0-9]+(?:-[A-Za-z0-9]+)+:\s/;
|
|
17246
17322
|
}
|
|
@@ -17615,6 +17691,87 @@ var init_localPrAdapters = __esm({
|
|
|
17615
17691
|
}
|
|
17616
17692
|
});
|
|
17617
17693
|
|
|
17694
|
+
// ../shared/pushSubject.ts
|
|
17695
|
+
async function resolvePushSubject(message, push, lookup, timeoutMs = PUSH_SUBJECT_TIMEOUT_MS) {
|
|
17696
|
+
const subject = pushCommitSubject(message);
|
|
17697
|
+
if (!subject) return subject;
|
|
17698
|
+
const bare = bareMergePrNumber(subject);
|
|
17699
|
+
if (bare === null && lastPrRef(subject) !== null) return subject;
|
|
17700
|
+
try {
|
|
17701
|
+
const found = await withTimeout(findPr(subject, bare, push, lookup), timeoutMs);
|
|
17702
|
+
return found ? `${found.title} (#${found.number})` : subject;
|
|
17703
|
+
} catch {
|
|
17704
|
+
return subject;
|
|
17705
|
+
}
|
|
17706
|
+
}
|
|
17707
|
+
async function findPr(subject, bare, push, lookup) {
|
|
17708
|
+
if (bare !== null) {
|
|
17709
|
+
const title = (await lookup.pullTitle(bare))?.trim();
|
|
17710
|
+
return title ? { number: bare, title } : null;
|
|
17711
|
+
}
|
|
17712
|
+
const pr = mergedPrForCommit(await lookup.pullsForCommit(push.sha), push);
|
|
17713
|
+
return pr ? { number: pr.number, title: pr.title?.trim() || subject } : null;
|
|
17714
|
+
}
|
|
17715
|
+
function mergedPrForCommit(prs, push) {
|
|
17716
|
+
const merged = prs.filter((p) => p.mergedAt && (!p.baseRef || p.baseRef === push.branch));
|
|
17717
|
+
const exact = merged.filter((p) => p.mergeCommitSha === push.sha);
|
|
17718
|
+
if (exact.length === 1) return exact[0] ?? null;
|
|
17719
|
+
return merged.length === 1 ? merged[0] ?? null : null;
|
|
17720
|
+
}
|
|
17721
|
+
function withTimeout(work, ms) {
|
|
17722
|
+
let timer;
|
|
17723
|
+
const expired = new Promise((_, reject) => {
|
|
17724
|
+
timer = setTimeout(() => reject(new Error("timed out")), ms);
|
|
17725
|
+
});
|
|
17726
|
+
return Promise.race([work, expired]).finally(() => clearTimeout(timer));
|
|
17727
|
+
}
|
|
17728
|
+
function githubPrLookup(opts) {
|
|
17729
|
+
const doFetch = opts.fetch ?? fetch;
|
|
17730
|
+
let tokens = null;
|
|
17731
|
+
async function get(path7) {
|
|
17732
|
+
tokens ??= opts.tokens();
|
|
17733
|
+
for (const token of await tokens) {
|
|
17734
|
+
const res = await doFetch(`${GITHUB_API}/repos/${opts.repo}${path7}`, {
|
|
17735
|
+
headers: {
|
|
17736
|
+
Accept: "application/vnd.github+json",
|
|
17737
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
17738
|
+
"User-Agent": "archme",
|
|
17739
|
+
...token ? { Authorization: `Bearer ${token}` } : {}
|
|
17740
|
+
}
|
|
17741
|
+
});
|
|
17742
|
+
if (REFUSED.has(res.status)) continue;
|
|
17743
|
+
return res.ok ? await res.json() : null;
|
|
17744
|
+
}
|
|
17745
|
+
return null;
|
|
17746
|
+
}
|
|
17747
|
+
return {
|
|
17748
|
+
async pullTitle(prNumber) {
|
|
17749
|
+
const pr = await get(`/pulls/${prNumber}`);
|
|
17750
|
+
return typeof pr?.title === "string" ? pr.title : null;
|
|
17751
|
+
},
|
|
17752
|
+
async pullsForCommit(sha) {
|
|
17753
|
+
const prs = await get(`/commits/${sha}/pulls`);
|
|
17754
|
+
if (!Array.isArray(prs)) return [];
|
|
17755
|
+
return prs.map((p) => ({
|
|
17756
|
+
number: Number(p.number),
|
|
17757
|
+
title: typeof p.title === "string" ? p.title : null,
|
|
17758
|
+
mergedAt: p.merged_at ?? null,
|
|
17759
|
+
mergeCommitSha: p.merge_commit_sha ?? null,
|
|
17760
|
+
baseRef: p.base?.ref ?? null
|
|
17761
|
+
}));
|
|
17762
|
+
}
|
|
17763
|
+
};
|
|
17764
|
+
}
|
|
17765
|
+
var PUSH_SUBJECT_TIMEOUT_MS, GITHUB_API, REFUSED;
|
|
17766
|
+
var init_pushSubject = __esm({
|
|
17767
|
+
"../shared/pushSubject.ts"() {
|
|
17768
|
+
init_prRefs();
|
|
17769
|
+
PUSH_SUBJECT_TIMEOUT_MS = 3e3;
|
|
17770
|
+
GITHUB_API = "https://api.github.com";
|
|
17771
|
+
REFUSED = /* @__PURE__ */ new Set([401, 403, 404]);
|
|
17772
|
+
}
|
|
17773
|
+
});
|
|
17774
|
+
|
|
17618
17775
|
// src/daemon/localPoller.ts
|
|
17619
17776
|
async function pollRepoOnce(entry, deps) {
|
|
17620
17777
|
const repo = `${entry.repoOwner}/${entry.repoName}`;
|
|
@@ -17788,6 +17945,14 @@ function makePollerDeps(client, log, gateTimeoutMs) {
|
|
|
17788
17945
|
},
|
|
17789
17946
|
async enqueue(entry, row, beforeSha, afterSha) {
|
|
17790
17947
|
const meta = await readCommitMeta(entry.mirrorPath, afterSha);
|
|
17948
|
+
const subject = await resolvePushSubject(
|
|
17949
|
+
meta.message || null,
|
|
17950
|
+
{ sha: afterSha, branch: row.repoBranch },
|
|
17951
|
+
githubPrLookup({
|
|
17952
|
+
repo: `${entry.repoOwner}/${entry.repoName}`,
|
|
17953
|
+
tokens: async () => (await resolveGithubTokens()).map((t) => t.token)
|
|
17954
|
+
})
|
|
17955
|
+
);
|
|
17791
17956
|
const { data, error } = await client.rpc("enqueue_local_archme_job", {
|
|
17792
17957
|
p_watched_repo_id: entry.watchedRepoId,
|
|
17793
17958
|
// From the ROW, not the registry: these decide which lane the job lands
|
|
@@ -17796,7 +17961,7 @@ function makePollerDeps(client, log, gateTimeoutMs) {
|
|
|
17796
17961
|
p_archme_branch: row.archmeBranch,
|
|
17797
17962
|
p_before_sha: beforeSha,
|
|
17798
17963
|
p_after_sha: afterSha,
|
|
17799
|
-
p_commit_message:
|
|
17964
|
+
p_commit_message: subject,
|
|
17800
17965
|
p_head_commit_timestamp: meta.committedAt,
|
|
17801
17966
|
p_author_name: meta.authorName,
|
|
17802
17967
|
// `author_login` is a GitHub concept with no git equivalent. The webhook
|
|
@@ -17823,6 +17988,7 @@ var init_localPoller = __esm({
|
|
|
17823
17988
|
init_branchMarker();
|
|
17824
17989
|
init_localGit();
|
|
17825
17990
|
init_localPrAdapters();
|
|
17991
|
+
init_pushSubject();
|
|
17826
17992
|
DEFAULT_POLL_INTERVAL_MS = 6e4;
|
|
17827
17993
|
DEFAULT_GATE_TIMEOUT_MS = 4 * 60 * 60 * 1e3;
|
|
17828
17994
|
}
|
|
@@ -17840,16 +18006,20 @@ __export(run_exports, {
|
|
|
17840
18006
|
buildClaudeExitMessage: () => buildClaudeExitMessage,
|
|
17841
18007
|
buildDevices: () => buildDevices,
|
|
17842
18008
|
buildDiffPrompt: () => buildDiffPrompt,
|
|
18009
|
+
claudeErrorDetails: () => claudeErrorDetails,
|
|
18010
|
+
claudeErrorResult: () => claudeErrorResult,
|
|
17843
18011
|
claudeFailureDetail: () => claudeFailureDetail,
|
|
17844
18012
|
computeDiff: () => computeDiff,
|
|
17845
18013
|
forkRepoScope: () => forkRepoScope,
|
|
18014
|
+
isClaudeAuthFailure: () => isClaudeAuthFailure,
|
|
17846
18015
|
parseClaudeResult: () => parseClaudeResult,
|
|
17847
18016
|
parseJobTokenResponse: () => parseJobTokenResponse,
|
|
17848
18017
|
probeMcpAuth: () => probeMcpAuth,
|
|
17849
18018
|
readBranchMarker: () => readBranchMarker,
|
|
17850
18019
|
routeShutdownInterrupt: () => routeShutdownInterrupt,
|
|
17851
18020
|
runDaemon: () => runDaemon,
|
|
17852
|
-
teeStream: () => teeStream
|
|
18021
|
+
teeStream: () => teeStream,
|
|
18022
|
+
withFailureDetail: () => withFailureDetail
|
|
17853
18023
|
});
|
|
17854
18024
|
import { createClient } from "@supabase/supabase-js";
|
|
17855
18025
|
import { randomUUID } from "node:crypto";
|
|
@@ -17866,12 +18036,29 @@ function attributeKillCause(result, recorded) {
|
|
|
17866
18036
|
function buildClaudeExitMessage(exitCode, causeSuffix, stderr) {
|
|
17867
18037
|
return `claude exited ${exitCode}${causeSuffix}: ${stderr.slice(0, 4e3)}`;
|
|
17868
18038
|
}
|
|
18039
|
+
function claudeErrorResult(stdout) {
|
|
18040
|
+
return claudeErrorDetails(stdout)?.text || null;
|
|
18041
|
+
}
|
|
18042
|
+
function claudeErrorDetails(stdout) {
|
|
18043
|
+
const parsed = parseClaudeResult(stdout);
|
|
18044
|
+
return parsed.parsed && parsed.isError ? { text: parsed.summary.trim(), apiErrorStatus: parsed.apiErrorStatus } : null;
|
|
18045
|
+
}
|
|
17869
18046
|
function claudeFailureDetail(stderr, stdout) {
|
|
18047
|
+
const result = claudeErrorResult(stdout);
|
|
18048
|
+
if (result) return result.slice(-FAILURE_DETAIL_MAX);
|
|
17870
18049
|
if (stderr.trim() || !stdout.trim()) return null;
|
|
17871
18050
|
const parsed = parseClaudeResult(stdout);
|
|
17872
18051
|
const text = (parsed.parsed ? parsed.summary : stdout).trim();
|
|
17873
18052
|
return text ? text.slice(-FAILURE_DETAIL_MAX) : null;
|
|
17874
18053
|
}
|
|
18054
|
+
function isClaudeAuthFailure(errorResult, stderr) {
|
|
18055
|
+
return /failed to authenticate|oauth session expired|not logged in|please run \/login/i.test(`${errorResult ?? ""}
|
|
18056
|
+
${stderr}`);
|
|
18057
|
+
}
|
|
18058
|
+
function withFailureDetail(message, detail) {
|
|
18059
|
+
return detail ? `claude said: ${detail}
|
|
18060
|
+
${message}` : message;
|
|
18061
|
+
}
|
|
17875
18062
|
async function routeShutdownInterrupt(id, cancelled2, fail, exitCode) {
|
|
17876
18063
|
if (cancelled2.has(id)) return;
|
|
17877
18064
|
if (exitCode === 0) {
|
|
@@ -18625,10 +18812,11 @@ function parseClaudeResult(stdout) {
|
|
|
18625
18812
|
usage: modelUsage ? sumModelUsage(modelUsage) : null,
|
|
18626
18813
|
costUsd: typeof d.total_cost_usd === "number" ? d.total_cost_usd : null,
|
|
18627
18814
|
isError: d.is_error === true,
|
|
18815
|
+
apiErrorStatus: typeof d.api_error_status === "number" ? d.api_error_status : null,
|
|
18628
18816
|
parsed: true
|
|
18629
18817
|
};
|
|
18630
18818
|
} catch {
|
|
18631
|
-
return { summary: raw, modelServed: null, usage: null, costUsd: null, isError: false, parsed: false };
|
|
18819
|
+
return { summary: raw, modelServed: null, usage: null, costUsd: null, isError: false, apiErrorStatus: null, parsed: false };
|
|
18632
18820
|
}
|
|
18633
18821
|
}
|
|
18634
18822
|
async function setupDigestMcp(ctx, job, deviceId) {
|
|
@@ -18917,16 +19105,30 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
18917
19105
|
if (result.exitCode !== 0) {
|
|
18918
19106
|
const causeSuffix = cause ? ` (${result.signal ?? "exit"}, cause: ${cause})` : "";
|
|
18919
19107
|
const stderr = result.stderr ? String(result.stderr) : "";
|
|
18920
|
-
const
|
|
19108
|
+
const stdout = result.stdout ? String(result.stdout) : "";
|
|
19109
|
+
const detail = claudeFailureDetail(stderr, stdout);
|
|
18921
19110
|
if (detail) log(`claude output: ${detail.replace(/\n/g, " ")}`);
|
|
18922
|
-
throw new
|
|
19111
|
+
throw new ClaudeRunError(
|
|
19112
|
+
buildClaudeExitMessage(result.exitCode, causeSuffix, stderr),
|
|
19113
|
+
detail,
|
|
19114
|
+
isClaudeAuthFailure(claudeErrorResult(stdout), stderr),
|
|
19115
|
+
claudeErrorDetails(stdout)
|
|
19116
|
+
);
|
|
18923
19117
|
}
|
|
18924
19118
|
const runResult = parseClaudeResult(result.stdout ? String(result.stdout) : "");
|
|
18925
19119
|
if (!runResult.parsed) {
|
|
18926
19120
|
log(`warning: claude --output-format json stdout was not a JSON result object; using raw text as summary`);
|
|
18927
19121
|
}
|
|
18928
19122
|
if (runResult.isError) {
|
|
18929
|
-
throw new
|
|
19123
|
+
throw new ClaudeRunError(
|
|
19124
|
+
`claude reported is_error in its JSON result (no successful completion)`,
|
|
19125
|
+
runResult.summary.trim().slice(-FAILURE_DETAIL_MAX) || null,
|
|
19126
|
+
isClaudeAuthFailure(
|
|
19127
|
+
claudeErrorResult(result.stdout ? String(result.stdout) : ""),
|
|
19128
|
+
result.stderr ? String(result.stderr) : ""
|
|
19129
|
+
),
|
|
19130
|
+
claudeErrorDetails(result.stdout ? String(result.stdout) : "")
|
|
19131
|
+
);
|
|
18930
19132
|
}
|
|
18931
19133
|
const summary2 = runResult.summary.trim().slice(0, 4e3);
|
|
18932
19134
|
if (summary2) log(`claude> ${summary2.slice(0, 500).replace(/\n/g, " ")}`);
|
|
@@ -18983,20 +19185,22 @@ async function runJob(ctx, job, claimDeviceId) {
|
|
|
18983
19185
|
return;
|
|
18984
19186
|
}
|
|
18985
19187
|
const msg = err4 instanceof Error ? err4.message : String(err4);
|
|
19188
|
+
const runErr = err4 instanceof ClaudeRunError ? err4 : null;
|
|
18986
19189
|
const haystack = stripPromptEcho(`${msg}
|
|
18987
19190
|
${logs.stderr}`, sentPrompt);
|
|
18988
19191
|
const plan = rateLimitDeferPlanForExit({
|
|
18989
19192
|
message: msg,
|
|
18990
19193
|
stderr: logs.stderr,
|
|
18991
19194
|
stdout: logs.stdout,
|
|
18992
|
-
prompt: sentPrompt
|
|
19195
|
+
prompt: sentPrompt,
|
|
19196
|
+
claudeError: runErr?.claudeError
|
|
18993
19197
|
});
|
|
18994
19198
|
if (plan) {
|
|
18995
19199
|
const { parsed, pauseUntil, info } = plan;
|
|
18996
19200
|
if (!parsed) {
|
|
18997
19201
|
void rpcReportEvent(ctx, job.org_id, "rate_limit_unmatched_exit", {
|
|
18998
19202
|
job_id: job.id,
|
|
18999
|
-
excerpt: haystack.slice(0, 500)
|
|
19203
|
+
excerpt: [runErr?.claudeError?.text, haystack].filter(Boolean).join("\n").slice(0, 500)
|
|
19000
19204
|
});
|
|
19001
19205
|
}
|
|
19002
19206
|
console.log(
|
|
@@ -19016,8 +19220,21 @@ ${logs.stderr}`, sentPrompt);
|
|
|
19016
19220
|
if (deferred) return;
|
|
19017
19221
|
console.warn(`[${job.id}] defer no-op \u2014 falling through to fail`);
|
|
19018
19222
|
}
|
|
19019
|
-
|
|
19020
|
-
|
|
19223
|
+
if (!plan && runErr?.authFailure) {
|
|
19224
|
+
const pauseUntil = new Date(Date.now() + AUTH_PAUSE_MS);
|
|
19225
|
+
console.error(
|
|
19226
|
+
`[${job.id}] CLAUDE CODE IS NOT AUTHENTICATED on this host (${runErr.detail ?? "auth failure"}). Run \`claude /login\` from this machine's DESKTOP session, not over SSH: on macOS an SSH login writes ~/.claude/.credentials.json while this daemon reads the keychain. Deferring job + pausing daemon until ${pauseUntil.toISOString()}.`
|
|
19227
|
+
);
|
|
19228
|
+
const detail = { job_id: job.id, claude_said: runErr.detail };
|
|
19229
|
+
await rpcSetDaemonPause(ctx, pauseUntil, "claude_auth_expired", detail);
|
|
19230
|
+
setLocalPause(pauseUntil.getTime());
|
|
19231
|
+
const deferred = await rpcDefer(ctx, job.id, deviceId, "claude_auth_expired", detail);
|
|
19232
|
+
if (deferred) return;
|
|
19233
|
+
console.warn(`[${job.id}] defer no-op \u2014 falling through to fail`);
|
|
19234
|
+
}
|
|
19235
|
+
const failMessage = withFailureDetail(msg, runErr?.detail ?? null);
|
|
19236
|
+
console.log(`[${job.id}] failed: ${failMessage}`);
|
|
19237
|
+
await rpcFail(ctx, job.id, deviceId, failMessage, metrics, logs);
|
|
19021
19238
|
} finally {
|
|
19022
19239
|
clearInterval(heartbeat);
|
|
19023
19240
|
inFlight.delete(job.id);
|
|
@@ -19422,7 +19639,7 @@ ${signal} received, shutting down`);
|
|
|
19422
19639
|
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
19423
19640
|
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
19424
19641
|
}
|
|
19425
|
-
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, JOB_TOKEN_PREFIX, 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;
|
|
19642
|
+
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, AUTH_PAUSE_MS, ClaudeRunError, 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, JOB_TOKEN_PREFIX, 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;
|
|
19426
19643
|
var init_run = __esm({
|
|
19427
19644
|
"src/daemon/run.ts"() {
|
|
19428
19645
|
"use strict";
|
|
@@ -19472,6 +19689,15 @@ var init_run = __esm({
|
|
|
19472
19689
|
LOG_STDOUT_CAP_BYTES = 30 * 1024;
|
|
19473
19690
|
LOG_STDERR_CAP_BYTES = 30 * 1024;
|
|
19474
19691
|
FAILURE_DETAIL_MAX = 400;
|
|
19692
|
+
AUTH_PAUSE_MS = 15 * 60 * 1e3;
|
|
19693
|
+
ClaudeRunError = class extends Error {
|
|
19694
|
+
constructor(message, detail, authFailure, claudeError) {
|
|
19695
|
+
super(message);
|
|
19696
|
+
this.detail = detail;
|
|
19697
|
+
this.authFailure = authFailure;
|
|
19698
|
+
this.claudeError = claudeError;
|
|
19699
|
+
}
|
|
19700
|
+
};
|
|
19475
19701
|
PRE_SPAWN_TOKEN_MIN_LIFETIME_MS = CLAUDE_LARGE_DIFF_TIMEOUT_MS + 5 * 60 * 1e3;
|
|
19476
19702
|
inFlight = /* @__PURE__ */ new Map();
|
|
19477
19703
|
cancelled = /* @__PURE__ */ new Set();
|
|
@@ -22514,9 +22740,9 @@ var init_run_init = __esm({
|
|
|
22514
22740
|
}
|
|
22515
22741
|
});
|
|
22516
22742
|
|
|
22517
|
-
// ../shared/
|
|
22518
|
-
var
|
|
22519
|
-
"../shared/
|
|
22743
|
+
// ../shared/connectionPair.ts
|
|
22744
|
+
var init_connectionPair = __esm({
|
|
22745
|
+
"../shared/connectionPair.ts"() {
|
|
22520
22746
|
}
|
|
22521
22747
|
});
|
|
22522
22748
|
|
|
@@ -22645,80 +22871,87 @@ function toAbsolute(endpoint, scopePath) {
|
|
|
22645
22871
|
if (scopePath.length === 0) return "root." + endpoint;
|
|
22646
22872
|
return "root." + scopePath.join(".") + "." + endpoint;
|
|
22647
22873
|
}
|
|
22648
|
-
function
|
|
22649
|
-
const
|
|
22650
|
-
|
|
22651
|
-
return absolute;
|
|
22652
|
-
}
|
|
22653
|
-
function rewriteAllConnections(arch, rewriter) {
|
|
22654
|
-
const entries = [];
|
|
22655
|
-
function walkConns(connections, scopePath) {
|
|
22874
|
+
function listAllConnections(arch) {
|
|
22875
|
+
const out = [];
|
|
22876
|
+
const walkConns = (connections, scopePath) => {
|
|
22656
22877
|
for (const conn of connections) {
|
|
22657
|
-
|
|
22658
|
-
const absTo = toAbsolute(conn.to, scopePath);
|
|
22659
|
-
const newAbsFrom = rewriter(absFrom);
|
|
22660
|
-
const newAbsTo = rewriter(absTo);
|
|
22661
|
-
const changed = newAbsFrom !== absFrom || newAbsTo !== absTo;
|
|
22662
|
-
entries.push({
|
|
22878
|
+
out.push({
|
|
22663
22879
|
conn,
|
|
22664
22880
|
scopePath,
|
|
22665
|
-
|
|
22666
|
-
|
|
22667
|
-
changed
|
|
22881
|
+
absFrom: toAbsolute(conn.from, scopePath),
|
|
22882
|
+
absTo: toAbsolute(conn.to, scopePath)
|
|
22668
22883
|
});
|
|
22669
22884
|
}
|
|
22670
|
-
}
|
|
22671
|
-
|
|
22885
|
+
};
|
|
22886
|
+
const walkComponents = (components, basePath) => {
|
|
22672
22887
|
for (const comp of components) {
|
|
22673
22888
|
const compPath = [...basePath, comp.id];
|
|
22674
22889
|
if (comp.connections) walkConns(comp.connections, compPath);
|
|
22675
22890
|
if (comp.components) walkComponents(comp.components, compPath);
|
|
22676
22891
|
}
|
|
22677
|
-
}
|
|
22892
|
+
};
|
|
22678
22893
|
walkConns(arch.connections, []);
|
|
22679
22894
|
walkComponents(arch.components, []);
|
|
22680
|
-
|
|
22681
|
-
|
|
22895
|
+
return out;
|
|
22896
|
+
}
|
|
22897
|
+
function dropConnections(arch, doomed) {
|
|
22898
|
+
const byScope = /* @__PURE__ */ new Map();
|
|
22899
|
+
for (const { conn, scopePath } of doomed) {
|
|
22900
|
+
const key = scopePath.join(".");
|
|
22901
|
+
const ids = byScope.get(key) ?? /* @__PURE__ */ new Set();
|
|
22902
|
+
ids.add(conn.id);
|
|
22903
|
+
byScope.set(key, ids);
|
|
22904
|
+
}
|
|
22682
22905
|
let result = arch;
|
|
22683
|
-
const
|
|
22684
|
-
for (const entry of entries) {
|
|
22685
|
-
if (!entry.changed) continue;
|
|
22686
|
-
const key = entry.scopePath.join(".");
|
|
22687
|
-
if (!removeByScopeKey.has(key)) removeByScopeKey.set(key, /* @__PURE__ */ new Set());
|
|
22688
|
-
removeByScopeKey.get(key).add(entry.conn.id);
|
|
22689
|
-
}
|
|
22690
|
-
for (const [scopeKey, connIds] of removeByScopeKey) {
|
|
22906
|
+
for (const [scopeKey, ids] of byScope) {
|
|
22691
22907
|
const scopePath = scopeKey === "" ? [] : scopeKey.split(".");
|
|
22692
22908
|
const nav = navigateToScope(result, scopePath);
|
|
22693
22909
|
if (!nav) continue;
|
|
22694
22910
|
result = replaceScopeAtPath(result, scopePath, {
|
|
22695
22911
|
...nav.scope,
|
|
22696
|
-
connections: nav.scope.connections.filter((c3) => !
|
|
22912
|
+
connections: nav.scope.connections.filter((c3) => !ids.has(c3.id))
|
|
22697
22913
|
});
|
|
22698
22914
|
}
|
|
22699
|
-
|
|
22700
|
-
|
|
22701
|
-
|
|
22702
|
-
|
|
22703
|
-
|
|
22704
|
-
|
|
22705
|
-
|
|
22706
|
-
|
|
22915
|
+
return result;
|
|
22916
|
+
}
|
|
22917
|
+
function connectionHome(absFrom, absTo) {
|
|
22918
|
+
const a2 = absFrom.split(".").slice(1);
|
|
22919
|
+
const b = absTo.split(".").slice(1);
|
|
22920
|
+
const scopePath = findLCA(a2.slice(0, -1), b.slice(0, -1));
|
|
22921
|
+
return { scopePath, from: a2.slice(scopePath.length).join("."), to: b.slice(scopePath.length).join(".") };
|
|
22922
|
+
}
|
|
22923
|
+
function rewriteAllConnections(arch, rewriter) {
|
|
22924
|
+
const changed = listAllConnections(arch).map((e) => ({ ...e, newFrom: rewriter(e.absFrom), newTo: rewriter(e.absTo) })).filter((e) => e.newFrom !== e.absFrom || e.newTo !== e.absTo);
|
|
22925
|
+
if (changed.length === 0) return { arch, connectionsUpdated: 0, notCarried: [] };
|
|
22926
|
+
let result = dropConnections(arch, changed);
|
|
22927
|
+
const notCarried = [];
|
|
22928
|
+
for (const entry of changed) {
|
|
22929
|
+
const home2 = connectionHome(entry.newFrom, entry.newTo);
|
|
22930
|
+
const nav = navigateToScope(result, home2.scopePath);
|
|
22931
|
+
if (!nav) continue;
|
|
22707
22932
|
const newConn = {
|
|
22708
22933
|
...entry.conn,
|
|
22709
|
-
from:
|
|
22710
|
-
to:
|
|
22711
|
-
id: `${
|
|
22712
|
-
};
|
|
22713
|
-
const existingConns =
|
|
22714
|
-
|
|
22715
|
-
|
|
22716
|
-
|
|
22717
|
-
|
|
22718
|
-
|
|
22934
|
+
from: home2.from,
|
|
22935
|
+
to: home2.to,
|
|
22936
|
+
id: `${home2.from}-${home2.to}`
|
|
22937
|
+
};
|
|
22938
|
+
const existingConns = nav.scope.connections;
|
|
22939
|
+
const taken = existingConns.find((c3) => c3.id === newConn.id);
|
|
22940
|
+
if (taken) {
|
|
22941
|
+
notCarried.push(
|
|
22942
|
+
`connection \`${entry.conn.id}\` (${newConn.from} \u2192 ${newConn.to}) was not carried over: ${scopeLabel(home2.scopePath)} already has \`${taken.id}\` (${taken.from} \u2192 ${taken.to}).`
|
|
22943
|
+
);
|
|
22944
|
+
continue;
|
|
22719
22945
|
}
|
|
22946
|
+
result = replaceScopeAtPath(result, home2.scopePath, {
|
|
22947
|
+
...nav.scope,
|
|
22948
|
+
connections: [...existingConns, newConn]
|
|
22949
|
+
});
|
|
22720
22950
|
}
|
|
22721
|
-
return { arch: result, connectionsUpdated:
|
|
22951
|
+
return { arch: result, connectionsUpdated: changed.length, notCarried };
|
|
22952
|
+
}
|
|
22953
|
+
function scopeLabel(scopePath) {
|
|
22954
|
+
return scopePath.length === 0 ? "root" : `root.${scopePath.join(".")}`;
|
|
22722
22955
|
}
|
|
22723
22956
|
function applyComponentMove(arch, move) {
|
|
22724
22957
|
const fromPath = move.from === "root" || move.from === "" ? [] : move.from.replace(/^root\./, "").split(".");
|
|
@@ -22767,7 +23000,7 @@ function applyComponentMove(arch, move) {
|
|
|
22767
23000
|
});
|
|
22768
23001
|
const rewriter = buildPathRewriter(oldAbsolute, newAbsolute);
|
|
22769
23002
|
result = rewriteArchPaths(result, rewriter);
|
|
22770
|
-
const { arch: afterConns, connectionsUpdated } = rewriteAllConnections(
|
|
23003
|
+
const { arch: afterConns, connectionsUpdated, notCarried } = rewriteAllConnections(
|
|
22771
23004
|
result,
|
|
22772
23005
|
rewriter
|
|
22773
23006
|
);
|
|
@@ -22793,13 +23026,16 @@ function applyComponentMove(arch, move) {
|
|
|
22793
23026
|
walk(a2.components);
|
|
22794
23027
|
};
|
|
22795
23028
|
countAllHops(result);
|
|
22796
|
-
const
|
|
23029
|
+
const notCarriedNote = notCarried.length > 0 ? ` Warning: ${notCarried.join(" ")}` : "";
|
|
23030
|
+
const summary2 = `Moved component '${move.id}' from ${move.from} to ${move.to}. As part of this move, ${hopsRewritten} story hop(s) and ${connectionsUpdated} connection(s) were updated to reflect the new path.${notCarriedNote}`;
|
|
22797
23031
|
return { arch: result, summary: summary2 };
|
|
22798
23032
|
}
|
|
22799
23033
|
var init_archUpdate = __esm({
|
|
22800
23034
|
"../shared/archUpdate.ts"() {
|
|
22801
23035
|
init_waypoints();
|
|
22802
23036
|
init_validationCodes();
|
|
23037
|
+
init_connectionPair();
|
|
23038
|
+
init_leafEndpoints();
|
|
22803
23039
|
}
|
|
22804
23040
|
});
|
|
22805
23041
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@archme/cli",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.3",
|
|
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",
|