archctx 0.2.0 → 0.2.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.2.0",
4
+ "productVersion": "0.2.1",
5
5
  "generatedAt": "1970-01-01T00:00:00.000Z",
6
6
  "entries": [
7
7
  {
package/bin/archctx.mjs CHANGED
@@ -702,7 +702,7 @@ function productVersionManifest() {
702
702
  }
703
703
  };
704
704
  }
705
- var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.2.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-06-25.al0-ledger";
705
+ var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.2.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-06-25.al0-ledger";
706
706
  // packages/contracts/src/index.ts
707
707
  var init_src = __esm(() => {
708
708
  init_control_plane_routes();
@@ -14850,6 +14850,12 @@ function uniqueSorted4(values) {
14850
14850
  init_src();
14851
14851
  import { existsSync as existsSync8, readdirSync as readdirSync6, readFileSync as readFileSync8 } from "node:fs";
14852
14852
  import { basename as basename4, resolve as resolve11 } from "node:path";
14853
+ function nativeNodeSource(node) {
14854
+ const value = node.source;
14855
+ if (!value || typeof value !== "object" || Array.isArray(value))
14856
+ return;
14857
+ return value;
14858
+ }
14853
14859
  var ARCHITECTURE_DOCS_RENDERER_VERSION = "archcontext.docs-renderer/v1";
14854
14860
  var ARCHITECTURE_DOCS_GENERATED_BEGIN_PREFIX = "<!-- BEGIN ARCHCONTEXT:generated";
14855
14861
  var ARCHITECTURE_DOCS_GENERATED_END_PREFIX = "<!-- END ARCHCONTEXT:generated";
@@ -15078,23 +15084,10 @@ function mermaidId(id) {
15078
15084
  function readYamlObjects(dir) {
15079
15085
  if (!existsSync8(dir))
15080
15086
  return [];
15081
- return readdirSync6(dir).filter((file) => /\.ya?ml$/.test(file)).sort().map((file) => parseFlatYaml(readFileSync8(resolve11(dir, file), "utf8")));
15082
- }
15083
- function parseFlatYaml(body) {
15084
- const out = {};
15085
- for (const line of body.split(/\r?\n/)) {
15086
- const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
15087
- if (!match)
15088
- continue;
15089
- const [, key, raw] = match;
15090
- if (raw.startsWith('"') && raw.endsWith('"'))
15091
- out[key] = JSON.parse(raw);
15092
- else if (raw === "true" || raw === "false")
15093
- out[key] = raw === "true";
15094
- else
15095
- out[key] = raw;
15096
- }
15097
- return out;
15087
+ return readdirSync6(dir).filter((file) => /\.ya?ml$/.test(file)).sort().map((file) => {
15088
+ const path = resolve11(dir, file);
15089
+ return parseJsonOrStableYaml(readFileSync8(path, "utf8"), path);
15090
+ });
15098
15091
  }
15099
15092
  function escapeMermaid(value) {
15100
15093
  return value.replace(/"/g, "'");
@@ -15441,6 +15434,61 @@ function escapeDsl(value) {
15441
15434
  function escapeRegExp(value) {
15442
15435
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15443
15436
  }
15437
+ function resolveArchitectureOwnerForPath(nodes, path) {
15438
+ const candidates = [];
15439
+ for (const node of nodes) {
15440
+ const source = nativeNodeSource(node);
15441
+ const include = source?.include ?? [];
15442
+ if (include.length === 0)
15443
+ continue;
15444
+ const excluded = (source?.exclude ?? []).some((pattern) => matchesGlob(path, pattern));
15445
+ if (excluded)
15446
+ continue;
15447
+ const specificity = include.filter((pattern) => matchesGlob(path, pattern)).reduce((max, pattern) => Math.max(max, globLiteralPrefixLength(pattern)), -1);
15448
+ if (specificity >= 0)
15449
+ candidates.push({ node, specificity });
15450
+ }
15451
+ if (candidates.length === 0)
15452
+ return { status: "no-match" };
15453
+ const maxSpecificity = candidates.reduce((max, candidate) => Math.max(max, candidate.specificity), -1);
15454
+ const winners = candidates.filter((candidate) => candidate.specificity === maxSpecificity).map((candidate) => candidate.node);
15455
+ if (winners.length > 1)
15456
+ return { status: "ambiguous", candidates: winners };
15457
+ return { status: "matched", node: winners[0] };
15458
+ }
15459
+ function matchesGlob(path, pattern) {
15460
+ return globToRegExp(pattern).test(path);
15461
+ }
15462
+ function globLiteralPrefixLength(pattern) {
15463
+ const index = pattern.search(/[*?]/);
15464
+ return index === -1 ? pattern.length : index;
15465
+ }
15466
+ function globToRegExp(pattern) {
15467
+ let out = "";
15468
+ let index = 0;
15469
+ while (index < pattern.length) {
15470
+ if (pattern.startsWith("**/", index)) {
15471
+ out += "(?:.*/)?";
15472
+ index += 3;
15473
+ continue;
15474
+ }
15475
+ if (pattern.startsWith("**", index)) {
15476
+ out += ".*";
15477
+ index += 2;
15478
+ continue;
15479
+ }
15480
+ const char = pattern[index];
15481
+ if (char === "*") {
15482
+ out += "[^/]*";
15483
+ } else if (char === "?") {
15484
+ out += "[^/]";
15485
+ } else {
15486
+ out += escapeRegExp(char);
15487
+ }
15488
+ index += 1;
15489
+ }
15490
+ return new RegExp(`^${out}$`);
15491
+ }
15444
15492
 
15445
15493
  // packages/local-runtime/explorer-html/src/index.ts
15446
15494
  var STATUS_STYLE = {
@@ -19494,6 +19542,22 @@ function createDefaultProjectionTargetManifest() {
19494
19542
  pathTemplate: "docs/architecture/diagrams/architecture.likec4",
19495
19543
  ownership: "generated",
19496
19544
  format: "likec4"
19545
+ },
19546
+ {
19547
+ id: "projection_rule.agent-context.claude",
19548
+ targetType: "agent-context",
19549
+ scope: { kind: "entity", entityKind: "capability" },
19550
+ pathTemplate: "{primarySourceDir}/CLAUDE.md",
19551
+ ownership: "mixed",
19552
+ format: "markdown"
19553
+ },
19554
+ {
19555
+ id: "projection_rule.agent-context.agents",
19556
+ targetType: "agent-context",
19557
+ scope: { kind: "entity", entityKind: "capability" },
19558
+ pathTemplate: "{primarySourceDir}/AGENTS.md",
19559
+ ownership: "mixed",
19560
+ format: "markdown"
19497
19561
  }
19498
19562
  ]
19499
19563
  };
@@ -28991,6 +29055,7 @@ function writeHtml2(response, statusCode, body) {
28991
29055
  }
28992
29056
 
28993
29057
  // packages/surfaces/mcp-local/src/index.ts
29058
+ var MCP_PROTOCOL_VERSION = "2025-03-26";
28994
29059
  var LOCAL_MCP_TOOLS = [
28995
29060
  {
28996
29061
  name: "archcontext_prepare_task",
@@ -29302,9 +29367,17 @@ async function runStdioMcpLoop(input, output, log = (line) => process.stderr.wri
29302
29367
  log("[archctx-mcp] started");
29303
29368
  for await (const line of input) {
29304
29369
  const message = JSON.parse(line);
29370
+ if (message.id === undefined)
29371
+ continue;
29305
29372
  let result;
29306
- if (message.method === "tools/list") {
29373
+ if (message.method === "initialize") {
29374
+ result = mcpInitializeResult(message.params?.protocolVersion);
29375
+ } else if (message.method === "ping") {
29376
+ result = {};
29377
+ } else if (message.method === "tools/list") {
29307
29378
  result = { tools: server.listTools() };
29379
+ } else if (message.method === "tools/call") {
29380
+ result = await server.callTool(message.params?.name, message.params?.arguments ?? {});
29308
29381
  } else if (message.method === "resources/list") {
29309
29382
  result = { resources: await server.listResources(message.params?.root) };
29310
29383
  } else if (message.method === "resources/read") {
@@ -29314,11 +29387,28 @@ async function runStdioMcpLoop(input, output, log = (line) => process.stderr.wri
29314
29387
  contents: content === undefined ? [] : [{ uri, mimeType: "application/json", text: JSON.stringify(content) }]
29315
29388
  };
29316
29389
  } else {
29317
- result = await server.callTool(message.params?.name, message.params?.arguments ?? {});
29390
+ result = {
29391
+ content: errorEnvelope("mcp", "AC_SCHEMA_INVALID", `Unknown MCP method: ${message.method}`),
29392
+ dataClassification: "local-metadata"
29393
+ };
29318
29394
  }
29319
29395
  output(JSON.stringify({ jsonrpc: "2.0", id: message.id, result }));
29320
29396
  }
29321
29397
  }
29398
+ function mcpInitializeResult(clientProtocolVersion) {
29399
+ const product = productVersionManifest().product;
29400
+ return {
29401
+ protocolVersion: typeof clientProtocolVersion === "string" ? clientProtocolVersion : MCP_PROTOCOL_VERSION,
29402
+ capabilities: {
29403
+ tools: { listChanged: false },
29404
+ resources: { subscribe: false, listChanged: false }
29405
+ },
29406
+ serverInfo: {
29407
+ name: product.name,
29408
+ version: product.version
29409
+ }
29410
+ };
29411
+ }
29322
29412
  function isExternalDocumentationResourceUri(uri) {
29323
29413
  return /^archcontext:\/\/external-docs\/context7\/sha256:[0-9a-f]{64}$/.test(uri);
29324
29414
  }
@@ -29365,6 +29455,8 @@ if (__require.main == __require.module) {
29365
29455
  `);
29366
29456
  if (result.ok === false)
29367
29457
  process.exitCode = 1;
29458
+ if (command === "resolve")
29459
+ process.exitCode = resolveCommandExitCode(result);
29368
29460
  }
29369
29461
  }
29370
29462
  async function* stdinLines() {
@@ -29621,6 +29713,37 @@ async function runCliUnchecked(command2 = "help", args2 = [], cwd, deps = {}) {
29621
29713
  revocation: "archctx tunnel --revoke"
29622
29714
  }
29623
29715
  };
29716
+ case "resolve": {
29717
+ const path = readFlag(args2, "--path");
29718
+ if (!path)
29719
+ return errorEnvelope("resolve", "AC_SCHEMA_INVALID", "resolve requires --path");
29720
+ if (!isRepoRelativePosixPath(path)) {
29721
+ return errorEnvelope("resolve", "AC_SCHEMA_INVALID", "resolve --path must be a repository-relative POSIX path");
29722
+ }
29723
+ const model = loadNativeModelFromArchContext(cwd);
29724
+ const outcome = resolveArchitectureOwnerForPath(model.nodes, path);
29725
+ if (outcome.status === "matched") {
29726
+ const node = outcome.node;
29727
+ return okEnvelope("resolve", {
29728
+ matched: true,
29729
+ ambiguous: false,
29730
+ stableId: node.id,
29731
+ kind: node.kind,
29732
+ name: node.name,
29733
+ ...node.source ? { source: node.source } : {},
29734
+ ...node.extensions ? { extensions: node.extensions } : {}
29735
+ });
29736
+ }
29737
+ if (outcome.status === "ambiguous") {
29738
+ return okEnvelope("resolve", {
29739
+ matched: false,
29740
+ ambiguous: true,
29741
+ path,
29742
+ candidates: outcome.candidates.map((node) => node.id)
29743
+ });
29744
+ }
29745
+ return okEnvelope("resolve", { matched: false, ambiguous: false, path });
29746
+ }
29624
29747
  case "help":
29625
29748
  default:
29626
29749
  return {
@@ -29628,8 +29751,8 @@ async function runCliUnchecked(command2 = "help", args2 = [], cwd, deps = {}) {
29628
29751
  ok: true,
29629
29752
  requestId: "help",
29630
29753
  data: {
29631
- commands: ["init", "sync", "validate", "context", "status", "daemon", "repo", "landscape", "ledger", "book", "recommendations", "explore", "prepare", "practices", "checkpoint", "hook", "hooks", "investigate", "agents", "jobs", "audit", "plan", "apply", "review", "complete", "github", "config", "mcp", "install", "uninstall", "doctor", "update", "paths", "privacy-audit", "export", "import", "tunnel"],
29632
- examples: ["archctx init --name MyApp", "archctx ledger migrate --from-yaml --dry-run", "archctx ledger promote --mode authoritative --preflight --rollback-plan", "archctx book recommendations --open --explain", "archctx recommendations accept --id recommendation.<id> --reason 'Accepted after local readback.'", "archctx recommendations metrics", "archctx practices validate --strict", "archctx practices list --json", "archctx practices waivers", "archctx practices waive --practice-id modularity.no-new-cycle --owner team-architecture --reason 'External migration window requires this edge until cutover.' --review-at 2026-07-10T00:00:00.000Z --expires-at 2026-07-24T00:00:00.000Z --evidence-digest sha256:<64-hex> --subject module.a->module.b", "archctx checkpoint --task-session-id task_cli", "archctx investigate --runner-port codex", "archctx agents status --status queued,running", "archctx agents budget", "archctx hook enqueue --event post-edit --path src/app.ts", "archctx jobs list --status queued", "archctx audit run --reason 'quarterly architecture audit'", "archctx audit run --no-wait", "archctx audit list --status pending", "archctx audit show audit_run.<id>", "archctx audit approve audit_run.<id>", "archctx audit approve audit_run.<id> --confirm-public-repo public:<owner/repo>:<baseSha>:<runId>", "archctx audit approve audit_run.<id> --resume", "archctx hooks install --host codex", "archctx paths", "archctx update --check", "archctx doctor --check-updates", "archctx github connect", "archctx github status", "archctx daemon start", "archctx explore start --foreground", "archctx export likec4", "archctx import structurizr --content '<json>'", "archctx tunnel"]
29754
+ commands: ["init", "sync", "validate", "context", "status", "daemon", "repo", "landscape", "ledger", "book", "recommendations", "explore", "prepare", "practices", "checkpoint", "hook", "hooks", "investigate", "agents", "jobs", "audit", "plan", "apply", "review", "complete", "github", "config", "mcp", "install", "uninstall", "doctor", "update", "paths", "privacy-audit", "export", "import", "resolve", "tunnel"],
29755
+ examples: ["archctx init --name MyApp", "archctx ledger migrate --from-yaml --dry-run", "archctx ledger promote --mode authoritative --preflight --rollback-plan", "archctx book recommendations --open --explain", "archctx recommendations accept --id recommendation.<id> --reason 'Accepted after local readback.'", "archctx recommendations metrics", "archctx practices validate --strict", "archctx practices list --json", "archctx practices waivers", "archctx practices waive --practice-id modularity.no-new-cycle --owner team-architecture --reason 'External migration window requires this edge until cutover.' --review-at 2026-07-10T00:00:00.000Z --expires-at 2026-07-24T00:00:00.000Z --evidence-digest sha256:<64-hex> --subject module.a->module.b", "archctx checkpoint --task-session-id task_cli", "archctx investigate --runner-port codex", "archctx agents status --status queued,running", "archctx agents budget", "archctx hook enqueue --event post-edit --path src/app.ts", "archctx jobs list --status queued", "archctx audit run --reason 'quarterly architecture audit'", "archctx audit run --no-wait", "archctx audit list --status pending", "archctx audit show audit_run.<id>", "archctx audit approve audit_run.<id>", "archctx audit approve audit_run.<id> --confirm-public-repo public:<owner/repo>:<baseSha>:<runId>", "archctx audit approve audit_run.<id> --resume", "archctx hooks install --host codex", "archctx paths", "archctx update --check", "archctx doctor --check-updates", "archctx github connect", "archctx github status", "archctx daemon start", "archctx explore start --foreground", "archctx export likec4", "archctx import structurizr --content '<json>'", "archctx resolve --path packages/core/projection-engine/src/index.ts", "archctx tunnel"]
29633
29756
  }
29634
29757
  };
29635
29758
  }
@@ -32164,6 +32287,16 @@ function renderResult(result, format) {
32164
32287
  return `OK ${result.requestId}
32165
32288
  ${JSON.stringify(result.data, null, 2)}`;
32166
32289
  }
32290
+ function resolveCommandExitCode(result) {
32291
+ if (!result || result.ok !== true)
32292
+ return 1;
32293
+ const data = result.data;
32294
+ if (data?.matched === true)
32295
+ return 0;
32296
+ if (data?.ambiguous === true)
32297
+ return 2;
32298
+ return 1;
32299
+ }
32167
32300
  function readFlag(args2, flag) {
32168
32301
  const index = args2.indexOf(flag);
32169
32302
  if (index === -1)
@@ -32193,5 +32326,6 @@ function readRepeatedFlag(args2, flag) {
32193
32326
  }
32194
32327
  export {
32195
32328
  runForegroundDaemon,
32196
- runCli
32329
+ runCli,
32330
+ resolveCommandExitCode
32197
32331
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archctx",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Local architecture context CLI for agentic coding workflows.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -10,7 +10,7 @@
10
10
  "targetId": { "type": "string", "pattern": "^projection_target\\.[a-zA-Z0-9_.-]+$" },
11
11
  "type": {
12
12
  "type": "string",
13
- "enum": ["architecture-index", "entity-summary", "relation-summary", "decision-index", "architecture-changelog", "diagram-mermaid", "diagram-structurizr", "diagram-likec4"]
13
+ "enum": ["architecture-index", "entity-summary", "relation-summary", "decision-index", "architecture-changelog", "diagram-mermaid", "diagram-structurizr", "diagram-likec4", "agent-context"]
14
14
  },
15
15
  "scope": {
16
16
  "type": "object",