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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "archcontext.practice-catalog-manifest/v1",
3
3
  "catalogVersion": "2026.06.0",
4
- "productVersion": "0.4.0",
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:61835a0efb9c5a19cb4fd16482026918785d01b94b6e60f2c2a06b64a4c713be"
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.0", 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";
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
- projection3 = buildArchitectureDocsProjection(root, generatedAt, profile, undefined, acceptedArchitectureChange(args2));
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: `workspace.${digestJson({ root }).replace(/^sha256:/, "").slice(0, 16)}`,
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 = `workspace.${digestJson({ root }).replace(/^sha256:/, "").slice(0, 16)}`;
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archctx",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Local architecture context CLI for agentic coding workflows.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -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,