archctx 0.4.0 → 0.4.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/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.1",
|
|
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:4d9f972043884502bdfc43a81b7f351df59a5f2af0231529fcdb49490bbf25d7"
|
|
393
393
|
}
|
package/bin/archctx.mjs
CHANGED
|
@@ -783,7 +783,11 @@ function archctxCapabilities(packageVersion) {
|
|
|
783
783
|
function projectionRequestInvariantIssues(input) {
|
|
784
784
|
const issues = [
|
|
785
785
|
...sortedUniqueIssues("targets", input.targets),
|
|
786
|
-
...sortedUniqueIssues("changedPaths", input.changedPaths)
|
|
786
|
+
...sortedUniqueIssues("changedPaths", input.changedPaths),
|
|
787
|
+
...input.acceptedChange ? [
|
|
788
|
+
...sortedUniqueIssues("acceptedChange.reasonCodes", input.acceptedChange.reasonCodes),
|
|
789
|
+
...sortedUniqueIssues("acceptedChange.affectedNodeIds", input.acceptedChange.affectedNodeIds)
|
|
790
|
+
] : []
|
|
787
791
|
];
|
|
788
792
|
if (input.targets.length === 0)
|
|
789
793
|
issues.push("targets must contain at least one projection target");
|
|
@@ -793,6 +797,25 @@ function projectionRequestInvariantIssues(input) {
|
|
|
793
797
|
issues.push("adoptionPlanId is required when mode=adopt");
|
|
794
798
|
if (input.mode !== "adopt" && input.adoptionPlanId !== undefined)
|
|
795
799
|
issues.push("adoptionPlanId is only allowed when mode=adopt");
|
|
800
|
+
if (input.acceptedChange) {
|
|
801
|
+
if (input.acceptedChange.changeSetId.trim() === "")
|
|
802
|
+
issues.push("acceptedChange.changeSetId must not be empty");
|
|
803
|
+
if (input.acceptedChange.eventId.trim() === "")
|
|
804
|
+
issues.push("acceptedChange.eventId must not be empty");
|
|
805
|
+
if (input.acceptedChange.reasonCodes.length === 0)
|
|
806
|
+
issues.push("acceptedChange.reasonCodes must contain at least one reason");
|
|
807
|
+
if (input.acceptedChange.affectedNodeIds.length === 0)
|
|
808
|
+
issues.push("acceptedChange.affectedNodeIds must contain at least one node");
|
|
809
|
+
const allowedReasons = new Set(ARCHITECTURE_MAJOR_CHANGE_REASON_CODES);
|
|
810
|
+
for (const reason of input.acceptedChange.reasonCodes) {
|
|
811
|
+
if (!allowedReasons.has(reason))
|
|
812
|
+
issues.push(`acceptedChange.reasonCodes contains unsupported reason: ${reason}`);
|
|
813
|
+
}
|
|
814
|
+
for (const nodeId of input.acceptedChange.affectedNodeIds) {
|
|
815
|
+
if (nodeId.trim() === "")
|
|
816
|
+
issues.push("acceptedChange.affectedNodeIds must not contain empty node ids");
|
|
817
|
+
}
|
|
818
|
+
}
|
|
796
819
|
return issues;
|
|
797
820
|
}
|
|
798
821
|
function projectionResultInvariantIssues(input) {
|
|
@@ -977,7 +1000,7 @@ function productVersionManifest() {
|
|
|
977
1000
|
}
|
|
978
1001
|
};
|
|
979
1002
|
}
|
|
980
|
-
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.4.
|
|
1003
|
+
var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.4.1", ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.3.10", ARCHCONTEXT_NODE_RANGE = ">=24 <26", LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1", ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";
|
|
981
1004
|
|
|
982
1005
|
// packages/contracts/src/validator.ts
|
|
983
1006
|
function validateJsonSchema(schema, value) {
|
|
@@ -40285,9 +40308,11 @@ async function runArchitectureDocsProjectionCommand(args2, cwd, daemon) {
|
|
|
40285
40308
|
const generatedAt = readFlag(args2, "--generated-at") ?? new Date(0).toISOString();
|
|
40286
40309
|
let profile;
|
|
40287
40310
|
let projection3;
|
|
40311
|
+
let acceptedChange;
|
|
40288
40312
|
try {
|
|
40289
40313
|
profile = architectureProjectionProfile(args2);
|
|
40290
|
-
|
|
40314
|
+
acceptedChange = acceptedArchitectureChange(args2);
|
|
40315
|
+
projection3 = buildArchitectureDocsProjection(root, generatedAt, profile, undefined, acceptedChange);
|
|
40291
40316
|
} catch (error) {
|
|
40292
40317
|
return errorEnvelope(`docs.${subcommand}`, "AC_PRECONDITION_FAILED", error instanceof Error ? error.message : String(error));
|
|
40293
40318
|
}
|
|
@@ -40320,7 +40345,7 @@ async function runArchitectureDocsProjectionCommand(args2, cwd, daemon) {
|
|
|
40320
40345
|
});
|
|
40321
40346
|
}
|
|
40322
40347
|
if (subcommand === "adopt") {
|
|
40323
|
-
return runArchitectureDocsAdoptionCommand(args2, root, daemon, projection3, profile, generatedAt);
|
|
40348
|
+
return runArchitectureDocsAdoptionCommand(args2, root, daemon, projection3, profile, generatedAt, acceptedChange);
|
|
40324
40349
|
}
|
|
40325
40350
|
if (projection3.plan.rejected.length > 0) {
|
|
40326
40351
|
return errorEnvelope("docs.plan", "AC_PRECONDITION_FAILED", `Architecture documentation projection requires explicit adoption or ownership repair: ${projection3.plan.rejected.map((diff) => `${diff.path} (${diff.reasonCode})`).join(", ")}`);
|
|
@@ -40415,7 +40440,7 @@ function buildArchitectureDocsProjection(root, generatedAt, profile = "default",
|
|
|
40415
40440
|
generatedAt,
|
|
40416
40441
|
refreshContext: {
|
|
40417
40442
|
repositoryId: repositoryFingerprint(root),
|
|
40418
|
-
workspaceId:
|
|
40443
|
+
workspaceId: projectionWorkspaceId(root),
|
|
40419
40444
|
headSha: provenance.baseHeadSha,
|
|
40420
40445
|
worktreeDigest: provenance.worktreeDigest,
|
|
40421
40446
|
...acceptedChange ? { acceptedChange } : {}
|
|
@@ -40456,7 +40481,7 @@ function architectureProjectionProfile(args2) {
|
|
|
40456
40481
|
}
|
|
40457
40482
|
return profile;
|
|
40458
40483
|
}
|
|
40459
|
-
async function runArchitectureDocsAdoptionCommand(args2, root, daemon, projection3, profile, generatedAt) {
|
|
40484
|
+
async function runArchitectureDocsAdoptionCommand(args2, root, daemon, projection3, profile, generatedAt, acceptedChange) {
|
|
40460
40485
|
if (profile !== REPO_HARNESS_PROJECTION_PROFILE) {
|
|
40461
40486
|
return errorEnvelope("docs.adopt", "AC_SCHEMA_INVALID", `docs adopt requires --profile ${REPO_HARNESS_PROJECTION_PROFILE}`);
|
|
40462
40487
|
}
|
|
@@ -40497,11 +40522,11 @@ async function runArchitectureDocsAdoptionCommand(args2, root, daemon, projectio
|
|
|
40497
40522
|
const simulatedByPath = new Map(projection3.loaded.existingFiles.map((file) => [file.path, file]));
|
|
40498
40523
|
for (const file of [...projection3.plan.files, ...adoption2.files])
|
|
40499
40524
|
simulatedByPath.set(file.path, file);
|
|
40500
|
-
const canonicalFirst = buildArchitectureDocsProjection(root, generatedAt, profile, [...simulatedByPath.values()]);
|
|
40525
|
+
const canonicalFirst = buildArchitectureDocsProjection(root, generatedAt, profile, [...simulatedByPath.values()], acceptedChange);
|
|
40501
40526
|
const canonicalExistingByPath = new Map(simulatedByPath);
|
|
40502
40527
|
for (const file of canonicalFirst.files)
|
|
40503
40528
|
canonicalExistingByPath.set(file.path, file);
|
|
40504
|
-
const canonical = buildArchitectureDocsProjection(root, generatedAt, profile, [...canonicalExistingByPath.values()]);
|
|
40529
|
+
const canonical = buildArchitectureDocsProjection(root, generatedAt, profile, [...canonicalExistingByPath.values()], acceptedChange);
|
|
40505
40530
|
if (!canonical.plan.drift.ok || canonical.plan.rejected.length > 0 || canonical.plan.projectionDigest !== canonicalFirst.plan.projectionDigest) {
|
|
40506
40531
|
return errorEnvelope("docs.adopt", "AC_PRECONDITION_FAILED", "projection-adoption-fixed-point-unproven");
|
|
40507
40532
|
}
|
|
@@ -40544,7 +40569,7 @@ async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
|
40544
40569
|
const generatedAt = new Date(0).toISOString();
|
|
40545
40570
|
let projection3;
|
|
40546
40571
|
try {
|
|
40547
|
-
projection3 = buildArchitectureDocsProjection(root, generatedAt, REPO_HARNESS_PROJECTION_PROFILE);
|
|
40572
|
+
projection3 = buildArchitectureDocsProjection(root, generatedAt, REPO_HARNESS_PROJECTION_PROFILE, undefined, request.acceptedChange);
|
|
40548
40573
|
assertProjectionExpectedSnapshot(request, root, projection3);
|
|
40549
40574
|
} catch (error) {
|
|
40550
40575
|
return errorEnvelope("projection.run", "AC_PRECONDITION_FAILED", error instanceof Error ? error.message : String(error));
|
|
@@ -40565,12 +40590,12 @@ async function runProjectionProtocolCommand(args2, cwd, daemon) {
|
|
|
40565
40590
|
expectedWorktreeDigest,
|
|
40566
40591
|
"--task-session-id",
|
|
40567
40592
|
request.requestId
|
|
40568
|
-
], root, daemon, projection3, REPO_HARNESS_PROJECTION_PROFILE, generatedAt);
|
|
40593
|
+
], root, daemon, projection3, REPO_HARNESS_PROJECTION_PROFILE, generatedAt, request.acceptedChange);
|
|
40569
40594
|
if (!adopted.ok)
|
|
40570
40595
|
return adopted;
|
|
40571
40596
|
let output;
|
|
40572
40597
|
try {
|
|
40573
|
-
output = buildArchitectureDocsProjection(root, generatedAt, REPO_HARNESS_PROJECTION_PROFILE);
|
|
40598
|
+
output = buildArchitectureDocsProjection(root, generatedAt, REPO_HARNESS_PROJECTION_PROFILE, undefined, request.acceptedChange);
|
|
40574
40599
|
if (!output.plan.drift.ok || output.plan.rejected.length > 0) {
|
|
40575
40600
|
return errorEnvelope("projection.run", "AC_PRECONDITION_FAILED", "projection adoption did not reach the architecture-docs fixed point");
|
|
40576
40601
|
}
|
|
@@ -40632,14 +40657,35 @@ function parseProjectionProtocolRequest(raw) {
|
|
|
40632
40657
|
throw new Error("projection request expected.headSha is invalid");
|
|
40633
40658
|
if (typeof snapshot.worktreeDigest !== "string" || !/^sha256:[a-f0-9]{64}$/.test(snapshot.worktreeDigest))
|
|
40634
40659
|
throw new Error("projection request expected.worktreeDigest is invalid");
|
|
40660
|
+
if (input.acceptedChange !== undefined)
|
|
40661
|
+
validateProjectionAcceptedChange(input.acceptedChange);
|
|
40635
40662
|
const request = input;
|
|
40636
40663
|
const issues = projectionRequestInvariantIssues(request);
|
|
40637
40664
|
if (issues.length > 0)
|
|
40638
40665
|
throw new Error(`projection request invariant failed: ${issues.join("; ")}`);
|
|
40639
40666
|
return request;
|
|
40640
40667
|
}
|
|
40668
|
+
function validateProjectionAcceptedChange(value) {
|
|
40669
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
40670
|
+
throw new Error("projection request acceptedChange must be an object");
|
|
40671
|
+
}
|
|
40672
|
+
const accepted = value;
|
|
40673
|
+
const supportedKeys = new Set(["changeSetId", "eventId", "reasonCodes", "affectedNodeIds"]);
|
|
40674
|
+
const unsupportedKey = Object.keys(accepted).find((key) => !supportedKeys.has(key));
|
|
40675
|
+
if (unsupportedKey)
|
|
40676
|
+
throw new Error(`projection request acceptedChange contains unsupported property: ${unsupportedKey}`);
|
|
40677
|
+
if (typeof accepted.changeSetId !== "string" || typeof accepted.eventId !== "string") {
|
|
40678
|
+
throw new Error("projection request acceptedChange changeSetId and eventId are required");
|
|
40679
|
+
}
|
|
40680
|
+
if (!Array.isArray(accepted.reasonCodes) || accepted.reasonCodes.some((reason) => typeof reason !== "string")) {
|
|
40681
|
+
throw new Error("projection request acceptedChange reasonCodes must be a string array");
|
|
40682
|
+
}
|
|
40683
|
+
if (!Array.isArray(accepted.affectedNodeIds) || accepted.affectedNodeIds.some((nodeId) => typeof nodeId !== "string")) {
|
|
40684
|
+
throw new Error("projection request acceptedChange affectedNodeIds must be a string array");
|
|
40685
|
+
}
|
|
40686
|
+
}
|
|
40641
40687
|
function assertProjectionExpectedSnapshot(request, root, projection3) {
|
|
40642
|
-
const workspaceId =
|
|
40688
|
+
const workspaceId = projectionWorkspaceId(root);
|
|
40643
40689
|
const actual = {
|
|
40644
40690
|
repositoryId: repositoryFingerprint(root),
|
|
40645
40691
|
workspaceId,
|
|
@@ -40651,6 +40697,10 @@ function assertProjectionExpectedSnapshot(request, root, projection3) {
|
|
|
40651
40697
|
throw new Error(`projection request expected snapshot mismatch: ${field}`);
|
|
40652
40698
|
}
|
|
40653
40699
|
}
|
|
40700
|
+
function projectionWorkspaceId(root) {
|
|
40701
|
+
const canonicalRoot = canonicalRepositoryRoot(root);
|
|
40702
|
+
return `workspace.${digestJson({ root: canonicalRoot }).replace(/^sha256:/, "").slice(0, 16)}`;
|
|
40703
|
+
}
|
|
40654
40704
|
function projectionProtocolHumanStatus(request, projection3) {
|
|
40655
40705
|
const humanSignal = projection3.plan.refreshSignals.some((signal) => signal.mode === "human-action-required");
|
|
40656
40706
|
const adoption2 = projection3.plan.rejected.some((diff) => diff.reasonCode === "projection-adoption-required");
|
package/package.json
CHANGED
|
@@ -24,7 +24,8 @@
|
|
|
24
24
|
"items": { "$ref": "#/$defs/repoPath" }
|
|
25
25
|
},
|
|
26
26
|
"expected": { "$ref": "#/$defs/expectedSnapshot" },
|
|
27
|
-
"adoptionPlanId": { "type": "string", "pattern": "^adoption_plan\\.[a-zA-Z0-9_.-]+$" }
|
|
27
|
+
"adoptionPlanId": { "type": "string", "pattern": "^adoption_plan\\.[a-zA-Z0-9_.-]+$" },
|
|
28
|
+
"acceptedChange": { "$ref": "#/$defs/acceptedChange" }
|
|
28
29
|
},
|
|
29
30
|
"allOf": [
|
|
30
31
|
{
|
|
@@ -46,6 +47,45 @@
|
|
|
46
47
|
]
|
|
47
48
|
}
|
|
48
49
|
},
|
|
50
|
+
"acceptedChange": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"additionalProperties": false,
|
|
53
|
+
"required": ["changeSetId", "eventId", "reasonCodes", "affectedNodeIds"],
|
|
54
|
+
"properties": {
|
|
55
|
+
"changeSetId": { "type": "string", "minLength": 1 },
|
|
56
|
+
"eventId": { "type": "string", "minLength": 1 },
|
|
57
|
+
"reasonCodes": {
|
|
58
|
+
"type": "array",
|
|
59
|
+
"minItems": 1,
|
|
60
|
+
"uniqueItems": true,
|
|
61
|
+
"description": "Canonical wire order is lexicographic and is enforced by projectionRequestInvariantIssues.",
|
|
62
|
+
"items": {
|
|
63
|
+
"enum": [
|
|
64
|
+
"constraint-changed",
|
|
65
|
+
"entrypoint-changed",
|
|
66
|
+
"interface-changed",
|
|
67
|
+
"lifecycle-changed",
|
|
68
|
+
"node-added",
|
|
69
|
+
"node-moved",
|
|
70
|
+
"node-removed",
|
|
71
|
+
"node-renamed",
|
|
72
|
+
"ownership-changed",
|
|
73
|
+
"relation-changed",
|
|
74
|
+
"responsibility-changed",
|
|
75
|
+
"risk-boundary-changed",
|
|
76
|
+
"verified-flow-proof-changed"
|
|
77
|
+
]
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"affectedNodeIds": {
|
|
81
|
+
"type": "array",
|
|
82
|
+
"minItems": 1,
|
|
83
|
+
"uniqueItems": true,
|
|
84
|
+
"description": "Canonical wire order is lexicographic and is enforced by projectionRequestInvariantIssues.",
|
|
85
|
+
"items": { "type": "string", "minLength": 1 }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
49
89
|
"expectedSnapshot": {
|
|
50
90
|
"type": "object",
|
|
51
91
|
"additionalProperties": false,
|