archctx 0.4.5 → 0.4.7
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/assets/catalog.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "archcontext.practice-catalog-manifest/v1",
|
|
3
3
|
"catalogVersion": "2026.06.0",
|
|
4
|
-
"productVersion": "0.4.
|
|
4
|
+
"productVersion": "0.4.7",
|
|
5
5
|
"generatedAt": "1970-01-01T00:00:00.000Z",
|
|
6
6
|
"entries": [
|
|
7
7
|
{
|
|
@@ -389,5 +389,5 @@
|
|
|
389
389
|
"structurizr.dsl",
|
|
390
390
|
"twelve-factor"
|
|
391
391
|
],
|
|
392
|
-
"catalogDigest": "sha256:
|
|
392
|
+
"catalogDigest": "sha256:557e42cbb594f7f2244b78847ab8d442f02977d5a08742a5c9576c051b1405b4"
|
|
393
393
|
}
|
package/bin/archctx.mjs
CHANGED
|
@@ -1088,7 +1088,7 @@ function productVersionManifest() {
|
|
|
1088
1088
|
}
|
|
1089
1089
|
};
|
|
1090
1090
|
}
|
|
1091
|
-
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.4.
|
|
1091
|
+
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.4.7", ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.3.10", ARCHCONTEXT_NODE_RANGE = ">=22.22 <26", LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1", ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";
|
|
1092
1092
|
|
|
1093
1093
|
// packages/contracts/src/validator.ts
|
|
1094
1094
|
function validateJsonSchema(schema, value) {
|
|
@@ -10397,13 +10397,21 @@ function diagnostics() {
|
|
|
10397
10397
|
const egress = localEgressStatus();
|
|
10398
10398
|
return {
|
|
10399
10399
|
node: process.version,
|
|
10400
|
-
supportedNode:
|
|
10400
|
+
supportedNode: isSupportedNodeVersion(process.version),
|
|
10401
10401
|
codeGraphVersion: REQUIRED_CODEGRAPH_VERSION,
|
|
10402
10402
|
privacyRouteDigest: controlPlaneRouteDigest(),
|
|
10403
10403
|
secureDefaults: secureDefaults(),
|
|
10404
10404
|
egress
|
|
10405
10405
|
};
|
|
10406
10406
|
}
|
|
10407
|
+
function isSupportedNodeVersion(version) {
|
|
10408
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)$/.exec(version);
|
|
10409
|
+
if (!match)
|
|
10410
|
+
return false;
|
|
10411
|
+
const major = Number(match[1]);
|
|
10412
|
+
const minor = Number(match[2]);
|
|
10413
|
+
return major < 26 && (major > 22 || major === 22 && minor >= 22);
|
|
10414
|
+
}
|
|
10407
10415
|
function secureDefaults() {
|
|
10408
10416
|
return {
|
|
10409
10417
|
tunnelEnabledByDefault: false,
|
|
@@ -10449,8 +10457,9 @@ function uninstallMarker(content, host) {
|
|
|
10449
10457
|
function dependencyAudit(root) {
|
|
10450
10458
|
const packageJson = JSON.parse(readFileSync6(resolve6(root, "package.json"), "utf8"));
|
|
10451
10459
|
const issues = [];
|
|
10452
|
-
if (
|
|
10453
|
-
issues.push(
|
|
10460
|
+
if (packageJson.engines?.node !== ARCHCONTEXT_NODE_RANGE) {
|
|
10461
|
+
issues.push(`node engine must equal ${ARCHCONTEXT_NODE_RANGE}`);
|
|
10462
|
+
}
|
|
10454
10463
|
return { ok: issues.length === 0, issues };
|
|
10455
10464
|
}
|
|
10456
10465
|
function secretScan(root) {
|
|
@@ -28492,6 +28501,71 @@ function auditGithubIssuesEnabledInManifestText(manifestText) {
|
|
|
28492
28501
|
}
|
|
28493
28502
|
var RUNTIME_RPC_VERSION = LOCAL_RUNTIME_RPC_SCHEMA_VERSION;
|
|
28494
28503
|
|
|
28504
|
+
class RuntimeUpdateInputError extends Error {
|
|
28505
|
+
}
|
|
28506
|
+
function decodeRuntimeWorktreeDigestProfile(value, field) {
|
|
28507
|
+
switch (value) {
|
|
28508
|
+
case "repository":
|
|
28509
|
+
case "architecture-documentation-projection":
|
|
28510
|
+
return value;
|
|
28511
|
+
default:
|
|
28512
|
+
throw new RuntimeUpdateInputError(`${field} must be repository or architecture-documentation-projection`);
|
|
28513
|
+
}
|
|
28514
|
+
}
|
|
28515
|
+
function decodeRuntimePlanUpdateInput(value) {
|
|
28516
|
+
const input = runtimeUpdateInputRecord(value, "plan_update input");
|
|
28517
|
+
if (typeof input.id !== "string" || input.id.length === 0) {
|
|
28518
|
+
throw new RuntimeUpdateInputError("plan_update id must be a non-empty string");
|
|
28519
|
+
}
|
|
28520
|
+
if (!Array.isArray(input.operations)) {
|
|
28521
|
+
throw new RuntimeUpdateInputError("plan_update operations must be an array");
|
|
28522
|
+
}
|
|
28523
|
+
let worktreeDigestPrecondition;
|
|
28524
|
+
if (input.worktreeDigestPrecondition !== undefined) {
|
|
28525
|
+
const precondition = runtimeUpdateInputRecord(input.worktreeDigestPrecondition, "plan_update worktreeDigestPrecondition");
|
|
28526
|
+
const profile = decodeRuntimeWorktreeDigestProfile(precondition.profile, "plan_update worktreeDigestPrecondition.profile");
|
|
28527
|
+
if (profile !== "architecture-documentation-projection") {
|
|
28528
|
+
throw new RuntimeUpdateInputError("plan_update worktreeDigestPrecondition.profile must be architecture-documentation-projection");
|
|
28529
|
+
}
|
|
28530
|
+
if (typeof precondition.expectedDigest !== "string" || precondition.expectedDigest.length === 0) {
|
|
28531
|
+
throw new RuntimeUpdateInputError("plan_update worktreeDigestPrecondition.expectedDigest must be a non-empty string");
|
|
28532
|
+
}
|
|
28533
|
+
worktreeDigestPrecondition = { profile, expectedDigest: precondition.expectedDigest };
|
|
28534
|
+
}
|
|
28535
|
+
return {
|
|
28536
|
+
id: input.id,
|
|
28537
|
+
operations: input.operations,
|
|
28538
|
+
...input.reason === undefined ? {} : { reason: input.reason },
|
|
28539
|
+
...worktreeDigestPrecondition === undefined ? {} : { worktreeDigestPrecondition }
|
|
28540
|
+
};
|
|
28541
|
+
}
|
|
28542
|
+
function decodeRuntimeApplyUpdateInput(value) {
|
|
28543
|
+
const input = runtimeUpdateInputRecord(value, "apply_update input");
|
|
28544
|
+
if (typeof input.id !== "string" || input.id.length === 0) {
|
|
28545
|
+
throw new RuntimeUpdateInputError("apply_update id must be a non-empty string");
|
|
28546
|
+
}
|
|
28547
|
+
if (typeof input.approved !== "boolean") {
|
|
28548
|
+
throw new RuntimeUpdateInputError("apply_update approved must be a boolean");
|
|
28549
|
+
}
|
|
28550
|
+
if (typeof input.expectedWorktreeDigest !== "string" || input.expectedWorktreeDigest.length === 0) {
|
|
28551
|
+
throw new RuntimeUpdateInputError("apply_update expectedWorktreeDigest must be a non-empty string");
|
|
28552
|
+
}
|
|
28553
|
+
const worktreeDigestProfile = input.worktreeDigestProfile === undefined ? undefined : decodeRuntimeWorktreeDigestProfile(input.worktreeDigestProfile, "apply_update worktreeDigestProfile");
|
|
28554
|
+
return {
|
|
28555
|
+
id: input.id,
|
|
28556
|
+
approved: input.approved,
|
|
28557
|
+
expectedWorktreeDigest: input.expectedWorktreeDigest,
|
|
28558
|
+
...worktreeDigestProfile === undefined ? {} : { worktreeDigestProfile },
|
|
28559
|
+
...input.projectionApplyReceipt === undefined ? {} : { projectionApplyReceipt: input.projectionApplyReceipt }
|
|
28560
|
+
};
|
|
28561
|
+
}
|
|
28562
|
+
function runtimeUpdateInputRecord(value, field) {
|
|
28563
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
28564
|
+
throw new RuntimeUpdateInputError(`${field} must be an object`);
|
|
28565
|
+
}
|
|
28566
|
+
return value;
|
|
28567
|
+
}
|
|
28568
|
+
|
|
28495
28569
|
class ArchitectureLedgerReadModelStore {
|
|
28496
28570
|
fallback;
|
|
28497
28571
|
localStore;
|
|
@@ -28602,6 +28676,7 @@ class ArchctxDaemon {
|
|
|
28602
28676
|
checkpointBaselines = new Map;
|
|
28603
28677
|
checkpointCoalesced = new Map;
|
|
28604
28678
|
changesets = new Map;
|
|
28679
|
+
changeSetWorktreeDigestProfiles = new Map;
|
|
28605
28680
|
deferredArchitectureChangeFeedFailures = new Map;
|
|
28606
28681
|
auditRunAbortControllers = new Map;
|
|
28607
28682
|
landscape;
|
|
@@ -29591,6 +29666,7 @@ class ArchctxDaemon {
|
|
|
29591
29666
|
operations: [{ op: "write_waiver", path, expectedHash, body }]
|
|
29592
29667
|
});
|
|
29593
29668
|
this.changesets.set(draft.id, draft);
|
|
29669
|
+
this.changeSetWorktreeDigestProfiles.set(draft.id, "repository");
|
|
29594
29670
|
return okEnvelope("practices.waive", {
|
|
29595
29671
|
schemaVersion: "archcontext.practice-waiver-plan/v1",
|
|
29596
29672
|
waiver,
|
|
@@ -29762,21 +29838,36 @@ class ArchctxDaemon {
|
|
|
29762
29838
|
};
|
|
29763
29839
|
return okEnvelope("resource.read", result);
|
|
29764
29840
|
}
|
|
29765
|
-
async planUpdate(root,
|
|
29841
|
+
async planUpdate(root, rawInput) {
|
|
29766
29842
|
this.assertRunning();
|
|
29843
|
+
let input;
|
|
29844
|
+
try {
|
|
29845
|
+
input = decodeRuntimePlanUpdateInput(rawInput);
|
|
29846
|
+
} catch (error) {
|
|
29847
|
+
if (error instanceof RuntimeUpdateInputError) {
|
|
29848
|
+
return errorEnvelope("plan_update", "AC_SCHEMA_INVALID", error.message);
|
|
29849
|
+
}
|
|
29850
|
+
throw error;
|
|
29851
|
+
}
|
|
29767
29852
|
const session = await this.openSession(root);
|
|
29768
29853
|
const model = await this.readModelStore.validateModel(session.workspace);
|
|
29854
|
+
const worktreeDigestProfile = input.worktreeDigestPrecondition?.profile ?? "repository";
|
|
29855
|
+
const worktreeDigest = runtimeWorktreeDigest(root, worktreeDigestProfile);
|
|
29856
|
+
if (input.worktreeDigestPrecondition && input.worktreeDigestPrecondition.expectedDigest !== worktreeDigest) {
|
|
29857
|
+
throw new Error("Worktree digest changed before plan");
|
|
29858
|
+
}
|
|
29769
29859
|
const draft = this.changeSetEngine.plan({
|
|
29770
29860
|
id: input.id,
|
|
29771
29861
|
base: {
|
|
29772
29862
|
headSha: session.workspace.headSha,
|
|
29773
|
-
worktreeDigest
|
|
29863
|
+
worktreeDigest,
|
|
29774
29864
|
modelDigest: model.modelDigest
|
|
29775
29865
|
},
|
|
29776
29866
|
reason: input.reason ?? { taskSessionId: "task_runtime" },
|
|
29777
29867
|
operations: input.operations
|
|
29778
29868
|
});
|
|
29779
29869
|
this.changesets.set(draft.id, draft);
|
|
29870
|
+
this.changeSetWorktreeDigestProfiles.set(draft.id, worktreeDigestProfile);
|
|
29780
29871
|
return okEnvelope("plan_update", {
|
|
29781
29872
|
draft,
|
|
29782
29873
|
preview: this.changeSetEngine.preview(root, draft)
|
|
@@ -29905,18 +29996,31 @@ class ArchctxDaemon {
|
|
|
29905
29996
|
return cached ? { ...cached.resource, queryDigest, cacheStatus: "stale" } : undefined;
|
|
29906
29997
|
}
|
|
29907
29998
|
}
|
|
29908
|
-
async applyUpdate(root,
|
|
29999
|
+
async applyUpdate(root, rawInput) {
|
|
29909
30000
|
this.assertRunning();
|
|
30001
|
+
let input;
|
|
30002
|
+
try {
|
|
30003
|
+
input = decodeRuntimeApplyUpdateInput(rawInput);
|
|
30004
|
+
} catch (error) {
|
|
30005
|
+
if (error instanceof RuntimeUpdateInputError) {
|
|
30006
|
+
return errorEnvelope("apply_update", "AC_SCHEMA_INVALID", error.message);
|
|
30007
|
+
}
|
|
30008
|
+
throw error;
|
|
30009
|
+
}
|
|
29910
30010
|
return this.withWriter(async () => {
|
|
29911
|
-
if (!input.expectedWorktreeDigest)
|
|
29912
|
-
throw new Error("apply_update requires expectedWorktreeDigest");
|
|
29913
|
-
const current = computeWorktreeDigest2(root);
|
|
29914
|
-
if (current !== input.expectedWorktreeDigest)
|
|
29915
|
-
throw new Error("Worktree digest changed before apply");
|
|
29916
|
-
const session = await this.openSession(root);
|
|
29917
30011
|
const draft = this.changesets.get(input.id);
|
|
29918
30012
|
if (!draft)
|
|
29919
30013
|
throw new Error(`Unknown ChangeSet: ${input.id}`);
|
|
30014
|
+
const plannedProfile = this.changeSetWorktreeDigestProfiles.get(input.id);
|
|
30015
|
+
if (!plannedProfile)
|
|
30016
|
+
throw new Error("ChangeSet worktree digest profile missing before apply");
|
|
30017
|
+
const requestedProfile = input.worktreeDigestProfile ?? "repository";
|
|
30018
|
+
if (requestedProfile !== plannedProfile)
|
|
30019
|
+
throw new Error("ChangeSet worktree digest profile changed before apply");
|
|
30020
|
+
const current = runtimeWorktreeDigest(root, plannedProfile);
|
|
30021
|
+
if (current !== input.expectedWorktreeDigest)
|
|
30022
|
+
throw new Error("Worktree digest changed before apply");
|
|
30023
|
+
const session = await this.openSession(root);
|
|
29920
30024
|
if (draft.base.headSha !== session.workspace.headSha)
|
|
29921
30025
|
throw new Error("ChangeSet HEAD changed before apply");
|
|
29922
30026
|
if (draft.base.worktreeDigest !== current)
|
|
@@ -32404,7 +32508,7 @@ class ArchctxRuntimeRpcServer {
|
|
|
32404
32508
|
pid: process.pid,
|
|
32405
32509
|
protocol: "http-loopback",
|
|
32406
32510
|
version: 1,
|
|
32407
|
-
product: productVersionManifest(),
|
|
32511
|
+
product: this.options.productManifest?.() ?? productVersionManifest(),
|
|
32408
32512
|
composition: this.daemon.compositionReport()
|
|
32409
32513
|
});
|
|
32410
32514
|
return;
|
|
@@ -32719,6 +32823,16 @@ function shouldSkipGeneratedProjectionJob(metadata, input) {
|
|
|
32719
32823
|
function isRuntimeAgentJobCursorStale(job, scope) {
|
|
32720
32824
|
return job.worktree.headSha !== scope.worktree.headSha || job.worktree.worktreeDigest !== scope.worktree.worktreeDigest;
|
|
32721
32825
|
}
|
|
32826
|
+
function runtimeWorktreeDigest(root, profile) {
|
|
32827
|
+
switch (profile) {
|
|
32828
|
+
case "repository":
|
|
32829
|
+
return computeWorktreeDigest2(root);
|
|
32830
|
+
case "architecture-documentation-projection":
|
|
32831
|
+
return architectureDocumentationProjectionWorktreeDigest(root, loadNativeModelFromArchContext(root));
|
|
32832
|
+
default:
|
|
32833
|
+
throw new RuntimeUpdateInputError(`unsupported worktree digest profile: ${String(profile)}`);
|
|
32834
|
+
}
|
|
32835
|
+
}
|
|
32722
32836
|
function isArchContextGeneratedProjectionPath(path) {
|
|
32723
32837
|
return path.replace(/\\/g, "/").startsWith(".archcontext/generated/");
|
|
32724
32838
|
}
|
|
@@ -35773,14 +35887,19 @@ async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
|
35773
35887
|
const planned = await daemon.planUpdate(root, {
|
|
35774
35888
|
id: changeSetId,
|
|
35775
35889
|
reason: { taskSessionId: request.requestId },
|
|
35776
|
-
operations: [architectureDocsRenderProjectionOperation(root, projection3.files)]
|
|
35890
|
+
operations: [architectureDocsRenderProjectionOperation(root, projection3.files)],
|
|
35891
|
+
worktreeDigestPrecondition: {
|
|
35892
|
+
profile: "architecture-documentation-projection",
|
|
35893
|
+
expectedDigest: request.expected.worktreeDigest
|
|
35894
|
+
}
|
|
35777
35895
|
});
|
|
35778
35896
|
if (!planned.ok)
|
|
35779
35897
|
return planned;
|
|
35780
35898
|
const applied = await daemon.applyUpdate(root, {
|
|
35781
35899
|
id: changeSetId,
|
|
35782
35900
|
approved: true,
|
|
35783
|
-
expectedWorktreeDigest:
|
|
35901
|
+
expectedWorktreeDigest: request.expected.worktreeDigest,
|
|
35902
|
+
worktreeDigestProfile: "architecture-documentation-projection",
|
|
35784
35903
|
...applyReceipt ? { projectionApplyReceipt: applyReceipt } : {}
|
|
35785
35904
|
});
|
|
35786
35905
|
if (!applied.ok)
|
|
@@ -37571,6 +37690,9 @@ async function doctorDaemon(cwd) {
|
|
|
37571
37690
|
const health = await client.health().catch(() => {
|
|
37572
37691
|
return;
|
|
37573
37692
|
});
|
|
37693
|
+
const healthIssue = runtimeRpcCompatibilityIssueFromHealth(cwd, client, health);
|
|
37694
|
+
if (healthIssue)
|
|
37695
|
+
return incompatibleDaemonStatus(healthIssue);
|
|
37574
37696
|
if (health?.ok === true) {
|
|
37575
37697
|
const stalenessIssue = cliEntryStalenessIssue(cwd);
|
|
37576
37698
|
if (stalenessIssue?.pidAlive)
|
|
@@ -37580,6 +37702,7 @@ async function doctorDaemon(cwd) {
|
|
|
37580
37702
|
running: health?.ok === true,
|
|
37581
37703
|
staleConnection: health?.ok !== true,
|
|
37582
37704
|
rpcVersionCompatible: health?.schemaVersion === productVersionManifest().runtime.localRpc.schemaVersion,
|
|
37705
|
+
productVersionCompatible: health?.product?.product?.version === productVersionManifest().product.version,
|
|
37583
37706
|
connection: client.connectionInfo(),
|
|
37584
37707
|
health: health?.ok === true ? {
|
|
37585
37708
|
composition: health.composition,
|
|
@@ -37723,6 +37846,9 @@ async function createOrStartRuntimeRpcClient(cwd) {
|
|
|
37723
37846
|
const health = await startedClient.health().catch(() => {
|
|
37724
37847
|
return;
|
|
37725
37848
|
});
|
|
37849
|
+
const healthIssue = runtimeRpcCompatibilityIssueFromHealth(cwd, startedClient, health);
|
|
37850
|
+
if (healthIssue)
|
|
37851
|
+
throw new RuntimeVersionUnsupportedError(healthIssue);
|
|
37726
37852
|
if (health?.ok === true)
|
|
37727
37853
|
return startedClient;
|
|
37728
37854
|
}
|
|
@@ -37812,6 +37938,7 @@ async function runDaemonCommand(args2, cwd) {
|
|
|
37812
37938
|
running: true,
|
|
37813
37939
|
product: health.product,
|
|
37814
37940
|
rpcVersionCompatible: health.schemaVersion === RUNTIME_RPC_VERSION,
|
|
37941
|
+
productVersionCompatible: true,
|
|
37815
37942
|
...client.connectionInfo(),
|
|
37816
37943
|
token: "stored-in-connection-file"
|
|
37817
37944
|
});
|
|
@@ -37852,6 +37979,9 @@ async function startBackgroundDaemon(args2, cwd) {
|
|
|
37852
37979
|
return errorEnvelope("daemon.start", "AC_RUNTIME_VERSION_UNSUPPORTED", runtimeVersionUnsupportedMessage(compatibilityIssue));
|
|
37853
37980
|
}
|
|
37854
37981
|
const discovered = await discoverRunningDaemonInfo(cwd, { recoverStale: true });
|
|
37982
|
+
if (discovered.compatibilityIssue?.pidAlive) {
|
|
37983
|
+
return errorEnvelope("daemon.start", "AC_RUNTIME_VERSION_UNSUPPORTED", runtimeVersionUnsupportedMessage(discovered.compatibilityIssue));
|
|
37984
|
+
}
|
|
37855
37985
|
if (discovered.info) {
|
|
37856
37986
|
return okEnvelope("daemon.start", {
|
|
37857
37987
|
running: true,
|
|
@@ -37909,7 +38039,8 @@ async function startBackgroundDaemon(args2, cwd) {
|
|
|
37909
38039
|
}
|
|
37910
38040
|
}
|
|
37911
38041
|
async function upgradeDaemon(args2, cwd) {
|
|
37912
|
-
const
|
|
38042
|
+
const persistedIssue = runtimeRpcCompatibilityIssue(cwd) ?? cliEntryStalenessIssue(cwd);
|
|
38043
|
+
const issue = persistedIssue ?? (await discoverRunningDaemonInfo(cwd)).compatibilityIssue;
|
|
37913
38044
|
if (!issue) {
|
|
37914
38045
|
const started2 = await startBackgroundDaemon(args2, cwd);
|
|
37915
38046
|
return started2.ok ? { ...started2, requestId: "daemon.upgrade", data: { ...started2.data, upgraded: false, reason: "runtime-compatible" } } : started2;
|
|
@@ -37930,6 +38061,10 @@ async function upgradeDaemon(args2, cwd) {
|
|
|
37930
38061
|
previousStartedAt: issue.received,
|
|
37931
38062
|
entrypointMtime: issue.expected,
|
|
37932
38063
|
previousPid: issue.pid
|
|
38064
|
+
} : issue.reason === "product-version-mismatch" ? {
|
|
38065
|
+
previousProductVersion: issue.received,
|
|
38066
|
+
expectedProductVersion: issue.expected,
|
|
38067
|
+
previousPid: issue.pid
|
|
37933
38068
|
} : {
|
|
37934
38069
|
previousRpcSchemaVersion: issue.received,
|
|
37935
38070
|
expectedRpcSchemaVersion: issue.expected,
|
|
@@ -37954,17 +38089,27 @@ async function discoverRunningDaemonInfo(cwd, options = {}) {
|
|
|
37954
38089
|
if (!client) {
|
|
37955
38090
|
return {
|
|
37956
38091
|
info: undefined,
|
|
38092
|
+
compatibilityIssue: undefined,
|
|
37957
38093
|
recovery: options.recoverStale ? recoverStaleDaemonControlFiles(cwd) : emptyRecovery(cwd)
|
|
37958
38094
|
};
|
|
37959
38095
|
}
|
|
37960
38096
|
const health = await client.health().catch(() => {
|
|
37961
38097
|
return;
|
|
37962
38098
|
});
|
|
38099
|
+
const compatibilityIssue = runtimeRpcCompatibilityIssueFromHealth(cwd, client, health) ?? cliEntryStalenessIssue(cwd);
|
|
38100
|
+
if (compatibilityIssue) {
|
|
38101
|
+
return {
|
|
38102
|
+
info: undefined,
|
|
38103
|
+
compatibilityIssue,
|
|
38104
|
+
recovery: emptyRecovery(cwd)
|
|
38105
|
+
};
|
|
38106
|
+
}
|
|
37963
38107
|
if (health?.ok === true) {
|
|
37964
|
-
return { info: client.connectionInfo(), recovery: emptyRecovery(cwd) };
|
|
38108
|
+
return { info: client.connectionInfo(), compatibilityIssue: undefined, recovery: emptyRecovery(cwd) };
|
|
37965
38109
|
}
|
|
37966
38110
|
return {
|
|
37967
38111
|
info: undefined,
|
|
38112
|
+
compatibilityIssue: undefined,
|
|
37968
38113
|
recovery: options.recoverStale ? recoverStaleDaemonControlFiles(cwd, { removeUnhealthyConnection: true }) : emptyRecovery(cwd)
|
|
37969
38114
|
};
|
|
37970
38115
|
}
|
|
@@ -37972,26 +38117,40 @@ function runtimeRpcCompatibilityIssueFromHealth(cwd, client, health) {
|
|
|
37972
38117
|
if (!(health && typeof health === "object"))
|
|
37973
38118
|
return;
|
|
37974
38119
|
const body = health;
|
|
37975
|
-
if (body.ok !== false || body.error !== "runtime RPC version mismatch")
|
|
37976
|
-
return;
|
|
37977
38120
|
const connection = client.connectionInfo();
|
|
37978
38121
|
const pid = typeof connection.pid === "number" ? connection.pid : undefined;
|
|
37979
|
-
|
|
37980
|
-
reason: "rpc-version-mismatch",
|
|
37981
|
-
expected: RUNTIME_RPC_VERSION,
|
|
37982
|
-
received: typeof body.expected === "string" ? body.expected : "unknown",
|
|
38122
|
+
const location = {
|
|
37983
38123
|
connectionPath: connection.connectionPath ?? defaultDaemonConnectionPath(cwd),
|
|
37984
38124
|
lockPath: connection.lockPath ?? defaultDaemonLockPath(cwd),
|
|
37985
38125
|
pid,
|
|
37986
38126
|
pidAlive: pid !== undefined ? isPidAlive(pid) : false,
|
|
37987
38127
|
upgradeCommand: "archctx daemon upgrade"
|
|
37988
38128
|
};
|
|
38129
|
+
if (body.ok === true) {
|
|
38130
|
+
const expected = productVersionManifest().product.version;
|
|
38131
|
+
const received = typeof body.product?.product?.version === "string" ? body.product.product.version : "unknown";
|
|
38132
|
+
return received === expected ? undefined : {
|
|
38133
|
+
reason: "product-version-mismatch",
|
|
38134
|
+
expected,
|
|
38135
|
+
received,
|
|
38136
|
+
...location
|
|
38137
|
+
};
|
|
38138
|
+
}
|
|
38139
|
+
if (body.ok !== false || body.error !== "runtime RPC version mismatch")
|
|
38140
|
+
return;
|
|
38141
|
+
return {
|
|
38142
|
+
reason: "rpc-version-mismatch",
|
|
38143
|
+
expected: RUNTIME_RPC_VERSION,
|
|
38144
|
+
received: typeof body.expected === "string" ? body.expected : "unknown",
|
|
38145
|
+
...location
|
|
38146
|
+
};
|
|
37989
38147
|
}
|
|
37990
38148
|
function incompatibleDaemonStatus(issue) {
|
|
37991
38149
|
return {
|
|
37992
38150
|
running: issue.pidAlive,
|
|
37993
38151
|
protocol: "http-loopback",
|
|
37994
|
-
rpcVersionCompatible:
|
|
38152
|
+
rpcVersionCompatible: issue.reason === "product-version-mismatch",
|
|
38153
|
+
productVersionCompatible: issue.reason !== "product-version-mismatch",
|
|
37995
38154
|
connectionPath: issue.connectionPath,
|
|
37996
38155
|
lockPath: issue.lockPath,
|
|
37997
38156
|
pid: issue.pid,
|
|
@@ -38008,6 +38167,9 @@ function runtimeVersionUnsupportedMessage(issue) {
|
|
|
38008
38167
|
if (issue.reason === "stale-daemon-entry") {
|
|
38009
38168
|
return `archctxd (pid ${issue.pid ?? "unknown"}, started ${issue.received}) was spawned from an older copy of the archctx entrypoint than the one running this command (modified ${issue.expected}); run ${issue.upgradeCommand} to replace the local daemon.`;
|
|
38010
38169
|
}
|
|
38170
|
+
if (issue.reason === "product-version-mismatch") {
|
|
38171
|
+
return `archctxd product version ${issue.received} does not exactly match this CLI (${issue.expected}); run ${issue.upgradeCommand} to replace the local daemon.`;
|
|
38172
|
+
}
|
|
38011
38173
|
return `archctxd RPC version ${issue.received} is incompatible with this CLI (${issue.expected}); run ${issue.upgradeCommand} to replace the local daemon.`;
|
|
38012
38174
|
}
|
|
38013
38175
|
async function waitForPidExit(pid, timeoutMs) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "archctx",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"description": "Local architecture context CLI for agentic coding workflows.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"registry": "https://registry.npmjs.org/"
|
|
21
21
|
},
|
|
22
22
|
"engines": {
|
|
23
|
-
"node": ">=
|
|
23
|
+
"node": ">=22.22 <26"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@colbymchenry/codegraph": "1.5.0",
|