archctx 0.1.4 → 0.1.5

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.1.4",
4
+ "productVersion": "0.1.5",
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:89829151a844ca84c522924c43d7b174ff613b0b50dbbb2c7174a20d9ac3ab47"
392
+ "catalogDigest": "sha256:6da748c8c6230d18597951e5ff2de7d483e90caed61435cbd80418a5339c0299"
393
393
  }
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.1.4", 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.1.5", 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();
@@ -9485,7 +9485,7 @@ function migrateLegacyLocalStoreIfNeeded(root = process.cwd(), env = process.env
9485
9485
  integrityCheck.target = "failed";
9486
9486
  integrityCheck.error = error instanceof Error ? error.message : String(error);
9487
9487
  if (!legacyExists) {
9488
- throw new Error(`ArchContext runtime state target is not a valid SQLite database and no legacy store is available: ${paths.localStorePath}`);
9488
+ return upgradeExistingLocalStoreTarget(paths, integrityCheck);
9489
9489
  }
9490
9490
  }
9491
9491
  }
@@ -9524,6 +9524,28 @@ function migrateLegacyLocalStoreIfNeeded(root = process.cwd(), env = process.env
9524
9524
  releaseLegacyMigrationLock(lock);
9525
9525
  }
9526
9526
  }
9527
+ function upgradeExistingLocalStoreTarget(paths, integrityCheck) {
9528
+ const lock = acquireLegacyMigrationLock(paths);
9529
+ try {
9530
+ assertUpgradeableLocalStoreTarget(paths.localStorePath);
9531
+ integrityCheck.target = assertSqliteIntegrity(paths.localStorePath);
9532
+ migrateSqliteDatabaseSync(paths.localStorePath);
9533
+ compactSqliteDatabase(paths.localStorePath);
9534
+ integrityCheck.target = assertCurrentLocalStore(paths.localStorePath);
9535
+ delete integrityCheck.error;
9536
+ const markerPath = writeLegacyMigrationMarker(paths, integrityCheck, []);
9537
+ return legacyMigrationResult(true, undefined, paths, [paths.localStorePath], {
9538
+ status: "target-upgraded",
9539
+ integrityCheck,
9540
+ markerPath,
9541
+ quarantinedFiles: []
9542
+ });
9543
+ } catch (error) {
9544
+ throw new Error(`ArchContext runtime state target is not a valid SQLite database and no legacy store is available: ${paths.localStorePath}; target upgrade failed: ${error instanceof Error ? error.message : String(error)}`);
9545
+ } finally {
9546
+ releaseLegacyMigrationLock(lock);
9547
+ }
9548
+ }
9527
9549
  function applyLocalSqliteMigrations(db) {
9528
9550
  for (const pragma of SQLITE_PRAGMAS)
9529
9551
  db.exec(pragma);
@@ -9640,6 +9662,21 @@ function assertCurrentLocalStoreSchema(db, path) {
9640
9662
  throw new Error(`SQLite local store schema incomplete for ${path}: missing migrations ${missingMigrations.join(", ")}`);
9641
9663
  }
9642
9664
  }
9665
+ function assertUpgradeableLocalStoreTarget(path) {
9666
+ const db = openSqliteDatabaseSync(path);
9667
+ try {
9668
+ const integrity = sqliteIntegrityCheckOpenDatabase(db, path);
9669
+ const tables = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => String(row.name)));
9670
+ const hasArchContextMarker = ["schema_migrations", "task_states", "repository_sessions", "snapshots"].some((table) => tables.has(table));
9671
+ if (!hasArchContextMarker) {
9672
+ throw new Error(`SQLite target is not an ArchContext local store candidate: ${path}`);
9673
+ }
9674
+ if (integrity !== "ok")
9675
+ throw new Error(`SQLite integrity_check failed for ${path}: ${integrity}`);
9676
+ } finally {
9677
+ db.close();
9678
+ }
9679
+ }
9643
9680
  function assertTrustedLegacyLocalStoreSource(paths) {
9644
9681
  const stat = lstatSync(paths.legacyLocalStorePath);
9645
9682
  if (stat.isSymbolicLink()) {
@@ -15961,7 +15998,7 @@ function migrateLegacyLocalStoreIfNeeded2(root = process.cwd(), env = process.en
15961
15998
  integrityCheck.target = "failed";
15962
15999
  integrityCheck.error = error instanceof Error ? error.message : String(error);
15963
16000
  if (!legacyExists) {
15964
- throw new Error(`ArchContext runtime state target is not a valid SQLite database and no legacy store is available: ${paths.localStorePath}`);
16001
+ return upgradeExistingLocalStoreTarget2(paths, integrityCheck);
15965
16002
  }
15966
16003
  }
15967
16004
  }
@@ -16000,6 +16037,28 @@ function migrateLegacyLocalStoreIfNeeded2(root = process.cwd(), env = process.en
16000
16037
  releaseLegacyMigrationLock2(lock);
16001
16038
  }
16002
16039
  }
16040
+ function upgradeExistingLocalStoreTarget2(paths, integrityCheck) {
16041
+ const lock = acquireLegacyMigrationLock2(paths);
16042
+ try {
16043
+ assertUpgradeableLocalStoreTarget2(paths.localStorePath);
16044
+ integrityCheck.target = assertSqliteIntegrity2(paths.localStorePath);
16045
+ migrateSqliteDatabaseSync2(paths.localStorePath);
16046
+ compactSqliteDatabase2(paths.localStorePath);
16047
+ integrityCheck.target = assertCurrentLocalStore2(paths.localStorePath);
16048
+ delete integrityCheck.error;
16049
+ const markerPath = writeLegacyMigrationMarker2(paths, integrityCheck, []);
16050
+ return legacyMigrationResult2(true, undefined, paths, [paths.localStorePath], {
16051
+ status: "target-upgraded",
16052
+ integrityCheck,
16053
+ markerPath,
16054
+ quarantinedFiles: []
16055
+ });
16056
+ } catch (error) {
16057
+ throw new Error(`ArchContext runtime state target is not a valid SQLite database and no legacy store is available: ${paths.localStorePath}; target upgrade failed: ${error instanceof Error ? error.message : String(error)}`);
16058
+ } finally {
16059
+ releaseLegacyMigrationLock2(lock);
16060
+ }
16061
+ }
16003
16062
  var RUNTIME_AGENT_JOB_STATUSES = ["queued", "running", "succeeded", "failed", "cancelled", "superseded", "expired"];
16004
16063
 
16005
16064
  class SqliteLocalStore {
@@ -17334,6 +17393,21 @@ function assertCurrentLocalStoreSchema2(db, path) {
17334
17393
  throw new Error(`SQLite local store schema incomplete for ${path}: missing migrations ${missingMigrations.join(", ")}`);
17335
17394
  }
17336
17395
  }
17396
+ function assertUpgradeableLocalStoreTarget2(path) {
17397
+ const db = openSqliteDatabaseSync2(path);
17398
+ try {
17399
+ const integrity = sqliteIntegrityCheckOpenDatabase2(db, path);
17400
+ const tables = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => String(row.name)));
17401
+ const hasArchContextMarker = ["schema_migrations", "task_states", "repository_sessions", "snapshots"].some((table) => tables.has(table));
17402
+ if (!hasArchContextMarker) {
17403
+ throw new Error(`SQLite target is not an ArchContext local store candidate: ${path}`);
17404
+ }
17405
+ if (integrity !== "ok")
17406
+ throw new Error(`SQLite integrity_check failed for ${path}: ${integrity}`);
17407
+ } finally {
17408
+ db.close();
17409
+ }
17410
+ }
17337
17411
  function assertTrustedLegacyLocalStoreSource2(paths) {
17338
17412
  const stat = lstatSync5(paths.legacyLocalStorePath);
17339
17413
  if (stat.isSymbolicLink()) {
@@ -26460,7 +26534,7 @@ async function runCliUnchecked(command2 = "help", args2 = [], cwd, deps = {}) {
26460
26534
  requestId: "help",
26461
26535
  data: {
26462
26536
  commands: ["init", "sync", "validate", "context", "status", "daemon", "repo", "landscape", "ledger", "book", "recommendations", "explore", "prepare", "practices", "checkpoint", "hook", "hooks", "investigate", "agents", "jobs", "plan", "apply", "review", "complete", "github", "config", "mcp", "install", "uninstall", "doctor", "update", "paths", "privacy-audit", "export", "import", "tunnel"],
26463
- examples: ["archctx init --name MyApp", "archctx ledger migrate --from-yaml --dry-run", "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 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"]
26537
+ 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 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"]
26464
26538
  }
26465
26539
  };
26466
26540
  }
@@ -26479,6 +26553,24 @@ async function runLedgerCommand(args2, cwd, runtime) {
26479
26553
  const daemon = await requiredLedgerRuntime(runtime);
26480
26554
  return daemon.ledgerDrift(cwd);
26481
26555
  }
26556
+ if (subcommand === "promote") {
26557
+ if (args2.includes("--write") || args2.includes("--enable") || args2.includes("--apply")) {
26558
+ return errorEnvelope("ledger.promote", "AC_SCHEMA_INVALID", "ledger promote is preflight-only; it does not write runtime config or enable authority");
26559
+ }
26560
+ const mode = readFlag(args2, "--mode") ?? args2[1];
26561
+ const targetMode = normalizeLedgerPromotionTargetMode(mode);
26562
+ if (!targetMode) {
26563
+ return errorEnvelope("ledger.promote", "AC_SCHEMA_INVALID", "ledger promote requires --mode authoritative");
26564
+ }
26565
+ if (!args2.includes("--preflight")) {
26566
+ return errorEnvelope("ledger.promote", "AC_SCHEMA_INVALID", "ledger promote requires --preflight");
26567
+ }
26568
+ if (!args2.includes("--rollback-plan")) {
26569
+ return errorEnvelope("ledger.promote", "AC_SCHEMA_INVALID", "ledger promote requires --rollback-plan");
26570
+ }
26571
+ const daemon = await requiredLedgerRuntime(runtime);
26572
+ return runLedgerPromotionPreflight(cwd, daemon, targetMode);
26573
+ }
26482
26574
  if (subcommand === "project") {
26483
26575
  if (!args2.includes("--to-git")) {
26484
26576
  return errorEnvelope("ledger.project", "AC_SCHEMA_INVALID", "ledger project currently requires --to-git");
@@ -26547,13 +26639,124 @@ async function runLedgerCommand(args2, cwd, runtime) {
26547
26639
  expectedWorktreeDigest
26548
26640
  });
26549
26641
  }
26550
- return errorEnvelope("ledger", "AC_SCHEMA_INVALID", "ledger requires status, state, drift --json, migrate --from-yaml, rebuild --from-git, rollback --to-yaml, or project --to-git");
26642
+ return errorEnvelope("ledger", "AC_SCHEMA_INVALID", "ledger requires status, state, drift --json, promote --mode authoritative --preflight --rollback-plan, migrate --from-yaml, rebuild --from-git, rollback --to-yaml, or project --to-git");
26551
26643
  }
26552
26644
  async function requiredLedgerRuntime(runtime) {
26553
26645
  if (!runtime)
26554
26646
  throw new Error("ledger command requires runtime daemon");
26555
26647
  return runtime();
26556
26648
  }
26649
+ function normalizeLedgerPromotionTargetMode(value) {
26650
+ if (value === "authoritative" || value === "ledger-authoritative" || value === "ledger")
26651
+ return "ledger-authoritative";
26652
+ return;
26653
+ }
26654
+ async function runLedgerPromotionPreflight(cwd, daemon, targetMode) {
26655
+ const stateEnvelope = await daemon.ledgerState(cwd);
26656
+ if (!stateEnvelope.ok)
26657
+ return stateEnvelope;
26658
+ const driftEnvelope = await daemon.ledgerDrift(cwd);
26659
+ if (!driftEnvelope.ok)
26660
+ return driftEnvelope;
26661
+ const state = readObject(stateEnvelope.data);
26662
+ const driftData = readObject(driftEnvelope.data);
26663
+ const architectureLedger = readObject(state.architectureLedger);
26664
+ const phaseFlags = readObject(architectureLedger.phaseFlags);
26665
+ const currentPhase = String(phaseFlags.activePhase ?? architectureLedger.rolloutMode ?? "unknown");
26666
+ const worktree = readObject(state.worktree);
26667
+ const ledger3 = readObject(state.ledger);
26668
+ const yaml = readObject(state.yaml);
26669
+ const drift = readObject(driftData.drift ?? state.drift);
26670
+ const reconcile = readObject(driftData.reconcile ?? state.reconcile);
26671
+ const worktreeDigest = typeof worktree.worktreeDigest === "string" ? worktree.worktreeDigest : "<current>";
26672
+ const nextRequiredPhase = nextLedgerPromotionPhase(currentPhase);
26673
+ const preconditions = {
26674
+ currentPhase,
26675
+ targetMode,
26676
+ noModeSkip: currentPhase === "ledger-shadow" || currentPhase === targetMode,
26677
+ driftClean: drift.ok === true,
26678
+ reconcileClean: reconcile.ok === true,
26679
+ unsupportedYamlFilesAbsent: Number(yaml.unsupportedFileCount ?? 0) === 0,
26680
+ ledgerStatePresent: Number(ledger3.entityCount ?? 0) + Number(ledger3.relationCount ?? 0) + Number(ledger3.constraintCount ?? 0) > 0,
26681
+ rollbackPlanPresent: true,
26682
+ hardEnforcementUnchanged: true
26683
+ };
26684
+ const alreadyActive = currentPhase === targetMode;
26685
+ const ready = !alreadyActive && Object.values(preconditions).every((value) => value === true || typeof value === "string");
26686
+ const reasonCodes = [
26687
+ ...alreadyActive ? ["already-ledger-authoritative"] : [],
26688
+ ...preconditions.noModeSkip ? [] : [`mode-sequence-not-ready:${currentPhase}->${nextRequiredPhase ?? "ledger-shadow"}`],
26689
+ ...preconditions.driftClean ? [] : ["ledger-yaml-drift-not-clean"],
26690
+ ...preconditions.reconcileClean ? [] : ["ledger-reconcile-not-clean"],
26691
+ ...preconditions.unsupportedYamlFilesAbsent ? [] : ["unsupported-yaml-files-present"],
26692
+ ...preconditions.ledgerStatePresent ? [] : ["ledger-state-empty"]
26693
+ ];
26694
+ return okEnvelope("ledger.promote", {
26695
+ schemaVersion: "archcontext.runtime-architecture-ledger-promotion-preflight/v1",
26696
+ targetMode,
26697
+ status: alreadyActive ? "already-active" : ready ? "ready" : "blocked",
26698
+ ready,
26699
+ writes: "none",
26700
+ sideEffects: {
26701
+ ledgerModeChanged: false,
26702
+ hardEnforcementChanged: false,
26703
+ sqliteMutated: false,
26704
+ yamlMutated: false
26705
+ },
26706
+ repository: state.repository,
26707
+ worktree: state.worktree,
26708
+ current: {
26709
+ phase: currentPhase,
26710
+ readMode: architectureLedger.readMode,
26711
+ writeMode: architectureLedger.writeMode,
26712
+ readAuthority: architectureLedger.readAuthority,
26713
+ writeAuthority: architectureLedger.writeAuthority,
26714
+ graphDigest: state.graphDigest,
26715
+ ledgerGraphDigest: ledger3.graphDigest,
26716
+ yamlGraphDigest: yaml.graphDigest
26717
+ },
26718
+ preconditions,
26719
+ reasonCodes,
26720
+ nextRequiredPhase,
26721
+ recommendedEnvironment: {
26722
+ ARCHCONTEXT_LEDGER_MODE: targetMode,
26723
+ ARCHCONTEXT_LEDGER_READ_MODE: "ledger",
26724
+ ARCHCONTEXT_LEDGER_WRITE_MODE: "ledger-with-projection"
26725
+ },
26726
+ rollbackPlan: {
26727
+ required: true,
26728
+ targetAuthority: "yaml",
26729
+ dryRunCommand: "archctx ledger rollback --to-yaml --dry-run",
26730
+ command: `archctx ledger rollback --to-yaml --write --expected-worktree-digest ${worktreeDigest}`,
26731
+ commandTemplate: "archctx ledger rollback --to-yaml --write --expected-worktree-digest <current>",
26732
+ environment: {
26733
+ ARCHCONTEXT_LEDGER_MODE: "yaml",
26734
+ ARCHCONTEXT_LEDGER_READ_MODE: "yaml",
26735
+ ARCHCONTEXT_LEDGER_WRITE_MODE: "yaml"
26736
+ }
26737
+ },
26738
+ boundary: {
26739
+ advisoryDefaultPreserved: true,
26740
+ productionGaClaimed: false,
26741
+ hardEnforcementEnabled: false,
26742
+ operatorActionRequired: true
26743
+ }
26744
+ });
26745
+ }
26746
+ function nextLedgerPromotionPhase(currentPhase) {
26747
+ if (currentPhase === "yaml")
26748
+ return "dual";
26749
+ if (currentPhase === "dual")
26750
+ return "ledger-shadow";
26751
+ if (currentPhase === "ledger-shadow")
26752
+ return "ledger-authoritative";
26753
+ if (currentPhase === "ledger-authoritative")
26754
+ return null;
26755
+ return "yaml";
26756
+ }
26757
+ function readObject(value) {
26758
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
26759
+ }
26557
26760
  async function runBookCommand(args2, cwd, daemon) {
26558
26761
  const subcommand = args2[0] ?? "status";
26559
26762
  const maxItems = readOptionalNonNegativeIntegerFlag(args2, "--max-items", "book");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archctx",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Local architecture context CLI for agentic coding workflows.",
5
5
  "private": false,
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  "README.md"
17
17
  ],
18
18
  "homepage": "https://archcontext.repoharness.com",
19
- "license": "UNLICENSED",
19
+ "license": "Apache-2.0",
20
20
  "publishConfig": {
21
21
  "registry": "https://registry.npmjs.org/"
22
22
  },