archctx 0.1.0 → 0.1.2

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.
Files changed (2) hide show
  1. package/bin/archctx.mjs +1245 -187
  2. package/package.json +2 -4
package/bin/archctx.mjs CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env bun
1
+ #!/usr/bin/env node
2
2
  // @bun
3
3
  import { createRequire } from "node:module";
4
4
  var __defProp = Object.defineProperty;
@@ -667,7 +667,7 @@ function productVersionManifest() {
667
667
  }
668
668
  };
669
669
  }
670
- var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.1.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-20.fg1";
670
+ var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.1.2", 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-20.fg1";
671
671
  // packages/contracts/src/index.ts
672
672
  var init_src = __esm(() => {
673
673
  init_control_plane_routes();
@@ -1288,7 +1288,7 @@ __export(exports_src, {
1288
1288
  DevicePrivateKeyStore: () => DevicePrivateKeyStore
1289
1289
  });
1290
1290
  import {
1291
- createHash as createHash5,
1291
+ createHash as createHash7,
1292
1292
  createPrivateKey,
1293
1293
  generateKeyPairSync,
1294
1294
  randomBytes as randomBytes3,
@@ -1296,7 +1296,7 @@ import {
1296
1296
  } from "node:crypto";
1297
1297
  function createPkceAuthorizationRequest(input) {
1298
1298
  const codeVerifier = input.verifier ?? randomBytes3(32).toString("base64url");
1299
- const codeChallenge = createHash5("sha256").update(codeVerifier).digest("base64url");
1299
+ const codeChallenge = createHash7("sha256").update(codeVerifier).digest("base64url");
1300
1300
  const url = new URL("/oauth/authorize", input.issuer);
1301
1301
  url.searchParams.set("response_type", "code");
1302
1302
  url.searchParams.set("client_id", input.clientId);
@@ -4262,12 +4262,12 @@ __export(exports_src3, {
4262
4262
  assertLocalAttestationV1: () => assertLocalAttestationV1,
4263
4263
  assertAttestationV2: () => assertAttestationV22
4264
4264
  });
4265
- import { createHash as createHash6, sign as sign3, verify as verify2 } from "node:crypto";
4265
+ import { createHash as createHash8, sign as sign3, verify as verify2 } from "node:crypto";
4266
4266
  function publicKeyFingerprint2(publicKey) {
4267
4267
  if (publicKey.type !== "public")
4268
4268
  throw new Error("public-key-required");
4269
4269
  const der = publicKey.export({ format: "der", type: "spki" });
4270
- return `sha256:${createHash6("sha256").update(der).digest("hex")}`;
4270
+ return `sha256:${createHash8("sha256").update(der).digest("hex")}`;
4271
4271
  }
4272
4272
  function createReviewChallenge(input) {
4273
4273
  const nonce = digestJson({ repo: input.repository, headSha: input.headSha, expiresAt: input.expiresAt });
@@ -4708,7 +4708,7 @@ function deviceIntegritySignals2(input) {
4708
4708
  function signAttestation(input) {
4709
4709
  const unsigned = unsignedPayload2({
4710
4710
  schemaVersion: "archcontext.attestation/v1",
4711
- attestationId: `att_${createHash6("sha256").update(input.challenge.challengeId + input.reviewDigest + input.trustLevel).digest("hex").slice(0, 16)}`,
4711
+ attestationId: `att_${createHash8("sha256").update(input.challenge.challengeId + input.reviewDigest + input.trustLevel).digest("hex").slice(0, 16)}`,
4712
4712
  challengeId: input.challenge.challengeId,
4713
4713
  repository: input.challenge.repository,
4714
4714
  headSha: input.challenge.headSha,
@@ -5109,7 +5109,7 @@ var init_src7 = __esm(() => {
5109
5109
 
5110
5110
  // packages/surfaces/cli/src/main.ts
5111
5111
  import { spawn } from "child_process";
5112
- import { accessSync, chmodSync as chmodSync3, closeSync as closeSync6, constants, existsSync as existsSync10, mkdirSync as mkdirSync8, openSync as openSync6, readFileSync as readFileSync9, rmSync as rmSync8, statSync as statSync6, writeFileSync as writeFileSync5 } from "fs";
5112
+ import { accessSync, chmodSync as chmodSync5, closeSync as closeSync7, constants, existsSync as existsSync11, mkdirSync as mkdirSync9, openSync as openSync7, readFileSync as readFileSync11, rmSync as rmSync9, statSync as statSync6, writeFileSync as writeFileSync7 } from "fs";
5113
5113
  import { dirname as dirname9, join as join8, resolve as resolve14 } from "path";
5114
5114
  import { fileURLToPath } from "url";
5115
5115
 
@@ -5134,6 +5134,18 @@ var DEFAULT_IGNORES = new Set([
5134
5134
  ".archcontext/.local",
5135
5135
  ".DS_Store"
5136
5136
  ]);
5137
+ function repositoryFingerprint(root) {
5138
+ const normalized = canonicalRepositoryRoot(root);
5139
+ return `repo.${createHash2("sha256").update(normalized).digest("hex").slice(0, 16)}`;
5140
+ }
5141
+ function canonicalRepositoryRoot(root) {
5142
+ const resolved = resolve(root);
5143
+ try {
5144
+ return realpathSync.native(resolved);
5145
+ } catch {
5146
+ return resolved;
5147
+ }
5148
+ }
5137
5149
  function computeWorktreeDigest(root, options = {}) {
5138
5150
  const ignore = new Set([...DEFAULT_IGNORES, ...options.ignore ?? []]);
5139
5151
  const files = listRepoFiles(root, ignore);
@@ -5198,11 +5210,11 @@ var DEFAULT_IGNORES2 = new Set([
5198
5210
  ".archcontext/.local",
5199
5211
  ".DS_Store"
5200
5212
  ]);
5201
- function repositoryFingerprint(root) {
5202
- const normalized = canonicalRepositoryRoot(root);
5213
+ function repositoryFingerprint2(root) {
5214
+ const normalized = canonicalRepositoryRoot2(root);
5203
5215
  return `repo.${createHash3("sha256").update(normalized).digest("hex").slice(0, 16)}`;
5204
5216
  }
5205
- function canonicalRepositoryRoot(root) {
5217
+ function canonicalRepositoryRoot2(root) {
5206
5218
  const resolved = resolve2(root);
5207
5219
  try {
5208
5220
  return realpathSync2.native(resolved);
@@ -5341,9 +5353,9 @@ function computeReviewWorktreeDigest(input) {
5341
5353
  });
5342
5354
  }
5343
5355
  function bindRepository(root, headSha) {
5344
- const canonicalRoot = canonicalRepositoryRoot(root);
5356
+ const canonicalRoot = canonicalRepositoryRoot2(root);
5345
5357
  return {
5346
- repositoryId: repositoryFingerprint(canonicalRoot),
5358
+ repositoryId: repositoryFingerprint2(canonicalRoot),
5347
5359
  root: canonicalRoot,
5348
5360
  headSha,
5349
5361
  worktreeDigest: computeWorktreeDigest2(canonicalRoot)
@@ -6524,18 +6536,621 @@ function listFiles(root) {
6524
6536
  }
6525
6537
 
6526
6538
  // packages/local-runtime/local-store-sqlite/src/index.ts
6527
- import { dirname as dirname2, join as join2, resolve as resolve6 } from "node:path";
6539
+ import { execFileSync as execFileSync2 } from "node:child_process";
6540
+ import { createHash as createHash5, randomUUID } from "node:crypto";
6541
+ import { chmodSync, closeSync as closeSync3, existsSync as existsSync3, fsyncSync as fsyncSync2, lstatSync as lstatSync2, mkdirSync as mkdirSync2, openSync as openSync3, readFileSync as readFileSync5, realpathSync as realpathSync4, renameSync as renameSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "node:fs";
6542
+ import { createRequire as createRequire2 } from "node:module";
6543
+ import { homedir } from "node:os";
6544
+ import { dirname as dirname2, isAbsolute as isAbsolute3, join as join2, relative as relative4, resolve as resolve6 } from "node:path";
6545
+ var runtimeRequire = createRequire2(import.meta.url);
6546
+ var SQLITE_SIDECAR_SUFFIXES = ["", "-wal", "-shm"];
6547
+ var LEGACY_MIGRATION_MARKER_FILE = "runtime.sqlite.migration.json";
6548
+ var LEGACY_MIGRATION_LOCK_FILE = "runtime.sqlite.migration.lock";
6549
+ var REQUIRED_LOCAL_STORE_TABLES = [
6550
+ "schema_migrations",
6551
+ "repository_sessions",
6552
+ "snapshots",
6553
+ "task_states",
6554
+ "observed_evidence",
6555
+ "review_results",
6556
+ "landscapes",
6557
+ "cross_repo_edges",
6558
+ "changeset_journal"
6559
+ ];
6560
+ var SQLITE_PRAGMAS = [
6561
+ "PRAGMA journal_mode = WAL",
6562
+ "PRAGMA foreign_keys = ON",
6563
+ "PRAGMA busy_timeout = 5000"
6564
+ ];
6565
+ var LOCAL_SQLITE_MIGRATIONS = [
6566
+ {
6567
+ id: "0001_runtime_state",
6568
+ statements: [
6569
+ `CREATE TABLE IF NOT EXISTS schema_migrations (
6570
+ id TEXT PRIMARY KEY,
6571
+ applied_at TEXT NOT NULL
6572
+ )`,
6573
+ `CREATE TABLE IF NOT EXISTS repository_sessions (
6574
+ repository_id TEXT PRIMARY KEY,
6575
+ root TEXT NOT NULL,
6576
+ head_sha TEXT NOT NULL,
6577
+ worktree_digest TEXT NOT NULL,
6578
+ updated_at TEXT NOT NULL
6579
+ )`,
6580
+ `CREATE TABLE IF NOT EXISTS snapshots (
6581
+ id TEXT PRIMARY KEY,
6582
+ repository_id TEXT NOT NULL,
6583
+ head_sha TEXT NOT NULL,
6584
+ worktree_digest TEXT NOT NULL,
6585
+ state TEXT NOT NULL,
6586
+ created_at TEXT NOT NULL,
6587
+ committed_at TEXT
6588
+ )`,
6589
+ `CREATE TABLE IF NOT EXISTS task_states (
6590
+ task_session_id TEXT PRIMARY KEY,
6591
+ payload_json TEXT NOT NULL,
6592
+ updated_at TEXT NOT NULL
6593
+ )`,
6594
+ `CREATE TABLE IF NOT EXISTS observed_evidence (
6595
+ id TEXT PRIMARY KEY,
6596
+ repository_id TEXT NOT NULL,
6597
+ head_sha TEXT NOT NULL,
6598
+ selector_json TEXT NOT NULL,
6599
+ summary TEXT NOT NULL,
6600
+ confidence TEXT NOT NULL,
6601
+ created_at TEXT NOT NULL
6602
+ )`,
6603
+ `CREATE TABLE IF NOT EXISTS review_results (
6604
+ review_id TEXT PRIMARY KEY,
6605
+ task_session_id TEXT NOT NULL,
6606
+ payload_json TEXT NOT NULL,
6607
+ created_at TEXT NOT NULL
6608
+ )`
6609
+ ]
6610
+ },
6611
+ {
6612
+ id: "0002_indexes",
6613
+ statements: [
6614
+ "CREATE INDEX IF NOT EXISTS idx_snapshots_repository ON snapshots(repository_id, head_sha)",
6615
+ "CREATE INDEX IF NOT EXISTS idx_evidence_repository ON observed_evidence(repository_id, head_sha)",
6616
+ "CREATE INDEX IF NOT EXISTS idx_reviews_task ON review_results(task_session_id)"
6617
+ ]
6618
+ },
6619
+ {
6620
+ id: "0003_landscape_state",
6621
+ statements: [
6622
+ `CREATE TABLE IF NOT EXISTS landscapes (
6623
+ id TEXT PRIMARY KEY,
6624
+ digest TEXT NOT NULL,
6625
+ metadata_json TEXT NOT NULL,
6626
+ updated_at TEXT NOT NULL
6627
+ )`,
6628
+ `CREATE TABLE IF NOT EXISTS cross_repo_edges (
6629
+ id TEXT PRIMARY KEY,
6630
+ landscape_id TEXT NOT NULL,
6631
+ from_repository_id TEXT NOT NULL,
6632
+ from_node_id TEXT NOT NULL,
6633
+ to_repository_id TEXT NOT NULL,
6634
+ to_node_id TEXT NOT NULL,
6635
+ via_kind TEXT NOT NULL,
6636
+ via_id TEXT NOT NULL,
6637
+ metadata_json TEXT NOT NULL,
6638
+ updated_at TEXT NOT NULL
6639
+ )`,
6640
+ "CREATE INDEX IF NOT EXISTS idx_cross_repo_edges_from ON cross_repo_edges(from_repository_id, from_node_id)",
6641
+ "CREATE INDEX IF NOT EXISTS idx_cross_repo_edges_to ON cross_repo_edges(to_repository_id, to_node_id)"
6642
+ ]
6643
+ },
6644
+ {
6645
+ id: "0004_changeset_journal",
6646
+ statements: [
6647
+ `CREATE TABLE IF NOT EXISTS changeset_journal (
6648
+ journal_id TEXT PRIMARY KEY,
6649
+ changeset_id TEXT NOT NULL,
6650
+ root TEXT NOT NULL,
6651
+ status TEXT NOT NULL,
6652
+ metadata_json TEXT NOT NULL,
6653
+ files_json TEXT NOT NULL,
6654
+ created_at TEXT NOT NULL,
6655
+ updated_at TEXT NOT NULL,
6656
+ completed_at TEXT
6657
+ )`,
6658
+ "CREATE INDEX IF NOT EXISTS idx_changeset_journal_status ON changeset_journal(status)"
6659
+ ]
6660
+ }
6661
+ ];
6662
+ var ARCHCONTEXT_STATE_DIR_ENV = "ARCHCONTEXT_STATE_DIR";
6663
+ var ARCHCONTEXT_LOCAL_STORE_PATH_ENV = "ARCHCONTEXT_LOCAL_STORE_PATH";
6664
+ function defaultArchContextStateRoot(env = process.env, platform = process.platform, home = homedir()) {
6665
+ const override = env[ARCHCONTEXT_STATE_DIR_ENV];
6666
+ if (override)
6667
+ return { path: resolve6(override), source: "environment" };
6668
+ if (platform === "darwin")
6669
+ return { path: join2(home, "Library", "Application Support", "ArchContext"), source: "os-user-data" };
6670
+ if (platform === "win32")
6671
+ return { path: join2(env.LOCALAPPDATA ?? join2(home, "AppData", "Local"), "ArchContext"), source: "os-user-data" };
6672
+ return { path: join2(env.XDG_DATA_HOME ?? join2(home, ".local", "share"), "archcontext"), source: "os-user-data" };
6673
+ }
6674
+ function runtimeStatePaths(root = process.cwd(), env = process.env) {
6675
+ const repositoryRoot = readGitPath(root, ["rev-parse", "--show-toplevel"]) ?? root;
6676
+ const canonicalRepositoryRoot3 = canonicalPath(repositoryRoot);
6677
+ const gitCommonDir = readGitPath(canonicalRepositoryRoot3, ["rev-parse", "--git-common-dir"]);
6678
+ const repositoryAnchor = canonicalPath(gitCommonDir ? resolveMaybeRelative(canonicalRepositoryRoot3, gitCommonDir) : canonicalRepositoryRoot3);
6679
+ const workspaceAnchor = canonicalRepositoryRoot3;
6680
+ const storageRepositoryId = stableStorageId("repo", repositoryAnchor);
6681
+ const storageWorkspaceId = stableStorageId("ws", workspaceAnchor);
6682
+ const stateRoot = defaultArchContextStateRoot(env);
6683
+ const repositoryStateDir = join2(stateRoot.path, "repositories", storageRepositoryId);
6684
+ const workspaceStateDir = join2(repositoryStateDir, "worktrees", storageWorkspaceId);
6685
+ const legacyControlDir = resolve6(canonicalRepositoryRoot3, ".archcontext", ".local");
6686
+ return {
6687
+ schemaVersion: "archcontext.runtime-state-paths/v1",
6688
+ stateRoot: stateRoot.path,
6689
+ source: stateRoot.source,
6690
+ repositoryRoot: canonicalRepositoryRoot3,
6691
+ repositoryAnchor,
6692
+ workspaceAnchor,
6693
+ storageRepositoryId,
6694
+ storageWorkspaceId,
6695
+ repositoryId: storageRepositoryId,
6696
+ workspaceId: storageWorkspaceId,
6697
+ repositoryStateDir,
6698
+ workspaceStateDir,
6699
+ sharedCacheDir: join2(repositoryStateDir, "shared", "cache"),
6700
+ localStorePath: env[ARCHCONTEXT_LOCAL_STORE_PATH_ENV] ?? join2(workspaceStateDir, "runtime.sqlite"),
6701
+ daemonConnectionPath: join2(workspaceStateDir, "archctxd.json"),
6702
+ daemonLockPath: join2(workspaceStateDir, "archctxd.lock"),
6703
+ daemonLogPath: join2(workspaceStateDir, "archctxd.log"),
6704
+ developerReviewRunStateDir: join2(workspaceStateDir, "developer-review-runs"),
6705
+ legacyControlDir,
6706
+ legacyLocalStorePath: join2(legacyControlDir, "runtime.sqlite")
6707
+ };
6708
+ }
6528
6709
  function defaultLocalStorePath(root = process.cwd()) {
6529
- return process.env.ARCHCONTEXT_LOCAL_STORE_PATH ?? resolve6(root, ".archcontext/.local/runtime.sqlite");
6710
+ return runtimeStatePaths(root).localStorePath;
6711
+ }
6712
+ function inspectLegacyLocalStoreMigration(root = process.cwd(), env = process.env) {
6713
+ const paths = runtimeStatePaths(root, env);
6714
+ if (env[ARCHCONTEXT_LOCAL_STORE_PATH_ENV]) {
6715
+ return legacyMigrationResult(false, "explicit-local-store-override", paths, [], {
6716
+ status: "explicit-local-store-override"
6717
+ });
6718
+ }
6719
+ const legacyExists = existsSync3(paths.legacyLocalStorePath);
6720
+ const targetExists = existsSync3(paths.localStorePath);
6721
+ if (targetExists) {
6722
+ const target = safeCurrentLocalStoreCheck(paths.localStorePath);
6723
+ return legacyMigrationResult(false, "target-exists", paths, [], {
6724
+ status: target.ok ? "target-current" : "target-incomplete",
6725
+ integrityCheck: target.ok ? { target: target.result } : { target: "failed", error: target.error }
6726
+ });
6727
+ }
6728
+ if (!legacyExists) {
6729
+ return legacyMigrationResult(false, "legacy-missing", paths, [], {
6730
+ status: "legacy-missing"
6731
+ });
6732
+ }
6733
+ const source = safeTrustedLegacyLocalStoreSourceCheck(paths);
6734
+ if (!source.ok) {
6735
+ return legacyMigrationResult(false, undefined, paths, [], {
6736
+ status: "legacy-invalid",
6737
+ integrityCheck: { legacy: "failed", error: source.error }
6738
+ });
6739
+ }
6740
+ const legacy = safeSqliteIntegrityCheck(paths.legacyLocalStorePath);
6741
+ return legacyMigrationResult(false, undefined, paths, [], {
6742
+ status: legacy.ok ? "pending" : "legacy-invalid",
6743
+ integrityCheck: legacy.ok ? { legacy: legacy.result } : { legacy: "failed", error: legacy.error }
6744
+ });
6745
+ }
6746
+ function migrateLegacyLocalStoreIfNeeded(root = process.cwd(), env = process.env) {
6747
+ const paths = runtimeStatePaths(root, env);
6748
+ if (env[ARCHCONTEXT_LOCAL_STORE_PATH_ENV]) {
6749
+ return legacyMigrationResult(false, "explicit-local-store-override", paths, [], {
6750
+ status: "explicit-local-store-override"
6751
+ });
6752
+ }
6753
+ ensurePrivateDir(dirname2(paths.localStorePath));
6754
+ const legacyExists = existsSync3(paths.legacyLocalStorePath);
6755
+ const integrityCheck = {};
6756
+ const quarantinedFiles = [];
6757
+ const targetExists = existsSync3(paths.localStorePath);
6758
+ if (targetExists) {
6759
+ try {
6760
+ integrityCheck.target = assertCurrentLocalStore(paths.localStorePath);
6761
+ return legacyMigrationResult(false, "target-exists", paths, [], {
6762
+ status: "target-current",
6763
+ integrityCheck
6764
+ });
6765
+ } catch (error) {
6766
+ integrityCheck.target = "failed";
6767
+ integrityCheck.error = error instanceof Error ? error.message : String(error);
6768
+ if (!legacyExists) {
6769
+ throw new Error(`ArchContext runtime state target is not a valid SQLite database and no legacy store is available: ${paths.localStorePath}`);
6770
+ }
6771
+ }
6772
+ }
6773
+ if (!legacyExists) {
6774
+ return legacyMigrationResult(false, "legacy-missing", paths, [], {
6775
+ status: "legacy-missing",
6776
+ integrityCheck
6777
+ });
6778
+ }
6779
+ assertTrustedLegacyLocalStoreSource(paths);
6780
+ const lock = acquireLegacyMigrationLock(paths);
6781
+ const stagingDir = join2(paths.workspaceStateDir, `.runtime.sqlite.migration-${process.pid}-${randomUUID()}`);
6782
+ const stagingPath = join2(stagingDir, "runtime.sqlite");
6783
+ try {
6784
+ if (targetExists)
6785
+ quarantinedFiles.push(...quarantineExistingLocalStore(paths));
6786
+ ensurePrivateDir(stagingDir);
6787
+ integrityCheck.legacy = vacuumLegacySqliteInto(paths.legacyLocalStorePath, stagingPath);
6788
+ makePrivateFile(stagingPath);
6789
+ migrateSqliteDatabaseSync(stagingPath);
6790
+ compactSqliteDatabase(stagingPath);
6791
+ integrityCheck.staging = assertCurrentLocalStore(stagingPath);
6792
+ publishStagedLocalStore(stagingPath, paths.localStorePath);
6793
+ integrityCheck.target = assertCurrentLocalStore(paths.localStorePath);
6794
+ const markerPath = writeLegacyMigrationMarker(paths, integrityCheck, quarantinedFiles);
6795
+ return legacyMigrationResult(true, undefined, paths, [paths.localStorePath], {
6796
+ status: quarantinedFiles.length > 0 ? "target-quarantined-and-migrated" : "migrated",
6797
+ integrityCheck,
6798
+ markerPath,
6799
+ quarantinedFiles
6800
+ });
6801
+ } catch (error) {
6802
+ throw new Error(`ArchContext legacy SQLite migration failed: ${error instanceof Error ? error.message : String(error)}`);
6803
+ } finally {
6804
+ rmSync2(stagingDir, { recursive: true, force: true });
6805
+ releaseLegacyMigrationLock(lock);
6806
+ }
6807
+ }
6808
+ function openSqliteDatabaseSync(databasePath) {
6809
+ if (databasePath !== ":memory:")
6810
+ ensurePrivateDir(dirname2(databasePath));
6811
+ try {
6812
+ const nodeSqlite = runtimeRequire("node:sqlite");
6813
+ const db2 = new nodeSqlite.DatabaseSync(databasePath);
6814
+ return {
6815
+ exec: (sql) => db2.exec(sql),
6816
+ prepare: (sql) => db2.prepare(sql),
6817
+ close: () => db2.close()
6818
+ };
6819
+ } catch (error) {
6820
+ if (error.code !== "ERR_UNKNOWN_BUILTIN_MODULE" && error.code !== "MODULE_NOT_FOUND") {
6821
+ throw error;
6822
+ }
6823
+ }
6824
+ const bunSqlite = runtimeRequire("bun:sqlite");
6825
+ const db = new bunSqlite.Database(databasePath);
6826
+ return {
6827
+ exec: (sql) => db.exec(sql),
6828
+ prepare: (sql) => db.query(sql),
6829
+ close: () => db.close()
6830
+ };
6831
+ }
6832
+ function legacyMigrationResult(migrated, skippedReason, paths, copiedFiles, details) {
6833
+ return {
6834
+ schemaVersion: "archcontext.legacy-local-store-migration/v1",
6835
+ status: details.status,
6836
+ migrated,
6837
+ skippedReason,
6838
+ legacyLocalStorePath: paths.legacyLocalStorePath,
6839
+ targetLocalStorePath: paths.localStorePath,
6840
+ markerPath: details.markerPath ?? legacyMigrationMarkerPath(paths),
6841
+ lockPath: legacyMigrationLockPath(paths),
6842
+ integrityCheck: details.integrityCheck ?? {},
6843
+ copiedFiles,
6844
+ quarantinedFiles: details.quarantinedFiles ?? []
6845
+ };
6846
+ }
6847
+ function safeSqliteIntegrityCheck(path) {
6848
+ try {
6849
+ return { ok: true, result: assertSqliteIntegrity(path) };
6850
+ } catch (error) {
6851
+ return { ok: false, error: error instanceof Error ? error.message : String(error) };
6852
+ }
6853
+ }
6854
+ function safeCurrentLocalStoreCheck(path) {
6855
+ try {
6856
+ return { ok: true, result: assertCurrentLocalStore(path) };
6857
+ } catch (error) {
6858
+ return { ok: false, error: error instanceof Error ? error.message : String(error) };
6859
+ }
6860
+ }
6861
+ function safeTrustedLegacyLocalStoreSourceCheck(paths) {
6862
+ try {
6863
+ assertTrustedLegacyLocalStoreSource(paths);
6864
+ return { ok: true };
6865
+ } catch (error) {
6866
+ return { ok: false, error: error instanceof Error ? error.message : String(error) };
6867
+ }
6868
+ }
6869
+ function assertSqliteIntegrity(path) {
6870
+ const db = openSqliteDatabaseSync(path);
6871
+ try {
6872
+ db.exec("PRAGMA busy_timeout = 5000");
6873
+ const row = db.prepare("PRAGMA integrity_check").get();
6874
+ const result = firstSqliteColumn(row);
6875
+ if (result !== "ok")
6876
+ throw new Error(`SQLite integrity_check failed for ${path}: ${result}`);
6877
+ return result;
6878
+ } finally {
6879
+ db.close();
6880
+ }
6881
+ }
6882
+ function assertCurrentLocalStore(path) {
6883
+ const db = openSqliteDatabaseSync(path);
6884
+ try {
6885
+ db.exec("PRAGMA busy_timeout = 5000");
6886
+ const integrity = sqliteIntegrityCheckOpenDatabase(db, path);
6887
+ assertCurrentLocalStoreSchema(db, path);
6888
+ return integrity;
6889
+ } finally {
6890
+ db.close();
6891
+ }
6892
+ }
6893
+ function assertCurrentLocalStoreSchema(db, path) {
6894
+ const tables = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => String(row.name)));
6895
+ const missingTables = REQUIRED_LOCAL_STORE_TABLES.filter((table) => !tables.has(table));
6896
+ if (missingTables.length > 0) {
6897
+ throw new Error(`SQLite local store schema incomplete for ${path}: missing tables ${missingTables.join(", ")}`);
6898
+ }
6899
+ const migrations = new Set(db.prepare("SELECT id FROM schema_migrations").all().map((row) => String(row.id)));
6900
+ const missingMigrations = LOCAL_SQLITE_MIGRATIONS.map((migration) => migration.id).filter((id) => !migrations.has(id));
6901
+ if (missingMigrations.length > 0) {
6902
+ throw new Error(`SQLite local store schema incomplete for ${path}: missing migrations ${missingMigrations.join(", ")}`);
6903
+ }
6904
+ }
6905
+ function assertTrustedLegacyLocalStoreSource(paths) {
6906
+ const stat = lstatSync2(paths.legacyLocalStorePath);
6907
+ if (stat.isSymbolicLink()) {
6908
+ throw new Error(`Legacy SQLite source must not be a symbolic link: ${paths.legacyLocalStorePath}`);
6909
+ }
6910
+ if (!stat.isFile()) {
6911
+ throw new Error(`Legacy SQLite source must be a regular file: ${paths.legacyLocalStorePath}`);
6912
+ }
6913
+ const sourceRealPath = realpathSync4.native(paths.legacyLocalStorePath);
6914
+ if (!isPathInsideOrSame(sourceRealPath, paths.repositoryRoot)) {
6915
+ throw new Error(`Legacy SQLite source must stay inside the repository root: ${paths.legacyLocalStorePath}`);
6916
+ }
6917
+ }
6918
+ function vacuumLegacySqliteInto(sourcePath, targetPath) {
6919
+ const db = openSqliteDatabaseSync(sourcePath);
6920
+ try {
6921
+ db.exec("PRAGMA busy_timeout = 5000");
6922
+ db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
6923
+ const integrity = sqliteIntegrityCheckOpenDatabase(db, sourcePath);
6924
+ db.exec(`VACUUM INTO ${sqliteStringLiteral(targetPath)}`);
6925
+ return integrity;
6926
+ } finally {
6927
+ db.close();
6928
+ }
6929
+ }
6930
+ function migrateSqliteDatabaseSync(databasePath) {
6931
+ const db = openSqliteDatabaseSync(databasePath);
6932
+ try {
6933
+ for (const pragma of SQLITE_PRAGMAS)
6934
+ db.exec(pragma);
6935
+ for (const migration of LOCAL_SQLITE_MIGRATIONS) {
6936
+ for (const statement of migration.statements)
6937
+ db.exec(statement);
6938
+ db.prepare("INSERT OR IGNORE INTO schema_migrations (id, applied_at) VALUES (?, ?)").run(migration.id, nowIso());
6939
+ }
6940
+ } finally {
6941
+ db.close();
6942
+ }
6943
+ }
6944
+ function compactSqliteDatabase(databasePath) {
6945
+ const db = openSqliteDatabaseSync(databasePath);
6946
+ try {
6947
+ db.exec("PRAGMA busy_timeout = 5000");
6948
+ db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
6949
+ db.exec("PRAGMA journal_mode = DELETE");
6950
+ } finally {
6951
+ db.close();
6952
+ }
6953
+ for (const suffix of ["-wal", "-shm"])
6954
+ rmSync2(`${databasePath}${suffix}`, { force: true });
6955
+ }
6956
+ function sqliteIntegrityCheckOpenDatabase(db, path) {
6957
+ const row = db.prepare("PRAGMA integrity_check").get();
6958
+ const result = firstSqliteColumn(row);
6959
+ if (result !== "ok")
6960
+ throw new Error(`SQLite integrity_check failed for ${path}: ${result}`);
6961
+ return result;
6962
+ }
6963
+ function firstSqliteColumn(row) {
6964
+ const value = row ? Object.values(row)[0] : undefined;
6965
+ return typeof value === "string" ? value : String(value ?? "");
6966
+ }
6967
+ function sqliteStringLiteral(value) {
6968
+ return `'${value.replace(/'/g, "''")}'`;
6969
+ }
6970
+ function publishStagedLocalStore(stagingPath, targetPath) {
6971
+ for (const suffix of SQLITE_SIDECAR_SUFFIXES) {
6972
+ const path = `${targetPath}${suffix}`;
6973
+ if (existsSync3(path))
6974
+ throw new Error(`Cannot publish migrated SQLite over existing target file: ${path}`);
6975
+ }
6976
+ renameSync2(stagingPath, targetPath);
6977
+ makePrivateFile(targetPath);
6978
+ fsyncDirectory2(dirname2(targetPath));
6979
+ }
6980
+ function writeLegacyMigrationMarker(paths, integrityCheck, quarantinedFiles) {
6981
+ const markerPath = legacyMigrationMarkerPath(paths);
6982
+ writePrivateJson(markerPath, {
6983
+ schemaVersion: "archcontext.legacy-local-store-migration-marker/v1",
6984
+ migratedAt: nowIso(),
6985
+ legacyLocalStorePath: paths.legacyLocalStorePath,
6986
+ targetLocalStorePath: paths.localStorePath,
6987
+ integrityCheck,
6988
+ quarantinedFiles
6989
+ });
6990
+ return markerPath;
6991
+ }
6992
+ function acquireLegacyMigrationLock(paths) {
6993
+ const lockPath = legacyMigrationLockPath(paths);
6994
+ ensurePrivateDir(dirname2(lockPath));
6995
+ try {
6996
+ const fd = openSync3(lockPath, "wx", 384);
6997
+ writeFileSync2(fd, JSON.stringify({
6998
+ schemaVersion: "archcontext.legacy-local-store-migration-lock/v1",
6999
+ pid: process.pid,
7000
+ root: paths.repositoryRoot,
7001
+ targetLocalStorePath: paths.localStorePath,
7002
+ startedAt: nowIso()
7003
+ }, null, 2), "utf8");
7004
+ fsyncSync2(fd);
7005
+ return { fd, path: lockPath };
7006
+ } catch (error) {
7007
+ const code = error.code;
7008
+ if (code === "EEXIST" && isStaleMigrationLock(lockPath)) {
7009
+ rmSync2(lockPath, { force: true });
7010
+ return acquireLegacyMigrationLock(paths);
7011
+ }
7012
+ if (code === "EEXIST")
7013
+ throw new Error(`Legacy SQLite migration already in progress; lock=${lockPath}`);
7014
+ throw error;
7015
+ }
7016
+ }
7017
+ function releaseLegacyMigrationLock(lock) {
7018
+ closeSync3(lock.fd);
7019
+ rmSync2(lock.path, { force: true });
7020
+ }
7021
+ function isStaleMigrationLock(lockPath) {
7022
+ try {
7023
+ const parsed = JSON.parse(readFileSync5(lockPath, "utf8"));
7024
+ if (typeof parsed.pid !== "number" || parsed.pid <= 0)
7025
+ return true;
7026
+ return !isProcessAlive(parsed.pid);
7027
+ } catch {
7028
+ return true;
7029
+ }
7030
+ }
7031
+ function isProcessAlive(pid) {
7032
+ try {
7033
+ process.kill(pid, 0);
7034
+ return true;
7035
+ } catch (error) {
7036
+ return error.code !== "ESRCH";
7037
+ }
7038
+ }
7039
+ function quarantineExistingLocalStore(paths) {
7040
+ const quarantineDir = join2(paths.workspaceStateDir, "quarantine", `runtime.sqlite-${Date.now()}-${randomUUID()}`);
7041
+ ensurePrivateDir(quarantineDir);
7042
+ const quarantinedFiles = [];
7043
+ for (const suffix of SQLITE_SIDECAR_SUFFIXES) {
7044
+ const source = `${paths.localStorePath}${suffix}`;
7045
+ if (!existsSync3(source))
7046
+ continue;
7047
+ const target = join2(quarantineDir, `runtime.sqlite${suffix}`);
7048
+ renameSync2(source, target);
7049
+ quarantinedFiles.push(target);
7050
+ }
7051
+ const markerPath = legacyMigrationMarkerPath(paths);
7052
+ if (existsSync3(markerPath)) {
7053
+ const target = join2(quarantineDir, LEGACY_MIGRATION_MARKER_FILE);
7054
+ renameSync2(markerPath, target);
7055
+ quarantinedFiles.push(target);
7056
+ }
7057
+ fsyncDirectory2(quarantineDir);
7058
+ fsyncDirectory2(dirname2(paths.localStorePath));
7059
+ return quarantinedFiles;
7060
+ }
7061
+ function legacyMigrationMarkerPath(paths) {
7062
+ return join2(paths.workspaceStateDir, LEGACY_MIGRATION_MARKER_FILE);
7063
+ }
7064
+ function legacyMigrationLockPath(paths) {
7065
+ return join2(paths.workspaceStateDir, LEGACY_MIGRATION_LOCK_FILE);
7066
+ }
7067
+ function writePrivateJson(path, value) {
7068
+ ensurePrivateDir(dirname2(path));
7069
+ const fd = openSync3(path, "w", 384);
7070
+ try {
7071
+ writeFileSync2(fd, JSON.stringify(value, null, 2), "utf8");
7072
+ fsyncSync2(fd);
7073
+ } finally {
7074
+ closeSync3(fd);
7075
+ }
7076
+ makePrivateFile(path);
7077
+ fsyncDirectory2(dirname2(path));
7078
+ }
7079
+ function ensurePrivateDir(path) {
7080
+ mkdirSync2(path, { recursive: true, mode: 448 });
7081
+ if (process.platform !== "win32") {
7082
+ try {
7083
+ chmodSync(path, 448);
7084
+ } catch {}
7085
+ }
7086
+ }
7087
+ function makePrivateFile(path) {
7088
+ if (process.platform !== "win32") {
7089
+ try {
7090
+ chmodSync(path, 384);
7091
+ } catch {}
7092
+ }
7093
+ }
7094
+ function readGitPath(root, args) {
7095
+ try {
7096
+ const value = execFileSync2("git", args, {
7097
+ cwd: root,
7098
+ encoding: "utf8",
7099
+ stdio: ["ignore", "pipe", "ignore"]
7100
+ }).trim();
7101
+ return value.length > 0 ? value : undefined;
7102
+ } catch {
7103
+ return;
7104
+ }
7105
+ }
7106
+ function resolveMaybeRelative(base, path) {
7107
+ return isAbsolute3(path) ? resolve6(path) : resolve6(base, path);
7108
+ }
7109
+ function canonicalPath(path) {
7110
+ const resolved = resolve6(path);
7111
+ try {
7112
+ return realpathSync4.native(resolved);
7113
+ } catch {
7114
+ return resolved;
7115
+ }
7116
+ }
7117
+ function isPathInsideOrSame(path, parent) {
7118
+ const child = resolve6(path);
7119
+ const base = resolve6(parent);
7120
+ const fromBase = relative4(base, child);
7121
+ return fromBase === "" || !!fromBase && !fromBase.startsWith("..") && !isAbsolute3(fromBase);
7122
+ }
7123
+ function stableStorageId(prefix, value) {
7124
+ return `${prefix}.${createHash5("sha256").update(value).digest("hex").slice(0, 16)}`;
7125
+ }
7126
+ function nowIso() {
7127
+ return new Date().toISOString();
7128
+ }
7129
+ function fsyncDirectory2(path) {
7130
+ try {
7131
+ const fd = openSync3(path, "r");
7132
+ try {
7133
+ fsyncSync2(fd);
7134
+ } finally {
7135
+ closeSync3(fd);
7136
+ }
7137
+ } catch (error) {
7138
+ if (!isIgnorableDirectoryFsyncError2(error))
7139
+ throw error;
7140
+ }
7141
+ }
7142
+ function isIgnorableDirectoryFsyncError2(error) {
7143
+ const code = error.code;
7144
+ return code === "EINVAL" || code === "EISDIR" || process.platform === "win32" && code === "EPERM";
6530
7145
  }
6531
7146
 
6532
7147
  // packages/local-runtime/git-adapter/src/index.ts
6533
- import { execFileSync as execFileSync2, spawnSync } from "node:child_process";
6534
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, mkdtempSync, rmSync as rmSync2 } from "node:fs";
7148
+ import { execFileSync as execFileSync3, spawnSync } from "node:child_process";
7149
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, mkdtempSync, rmSync as rmSync3 } from "node:fs";
6535
7150
  import { dirname as dirname3, join as join3, resolve as resolve7 } from "node:path";
6536
7151
  function findRepositoryRoot(start) {
6537
7152
  try {
6538
- return resolve7(execFileSync2("git", ["rev-parse", "--show-toplevel"], {
7153
+ return resolve7(execFileSync3("git", ["rev-parse", "--show-toplevel"], {
6539
7154
  cwd: start,
6540
7155
  encoding: "utf8",
6541
7156
  stdio: ["ignore", "pipe", "ignore"]
@@ -6543,7 +7158,7 @@ function findRepositoryRoot(start) {
6543
7158
  } catch {
6544
7159
  let cursor = resolve7(start);
6545
7160
  while (cursor !== "/") {
6546
- if (existsSync3(resolve7(cursor, ".git")))
7161
+ if (existsSync4(resolve7(cursor, ".git")))
6547
7162
  return cursor;
6548
7163
  cursor = resolve7(cursor, "..");
6549
7164
  }
@@ -6552,7 +7167,7 @@ function findRepositoryRoot(start) {
6552
7167
  }
6553
7168
  function readHeadSha(root) {
6554
7169
  try {
6555
- return execFileSync2("git", ["rev-parse", "HEAD"], {
7170
+ return execFileSync3("git", ["rev-parse", "HEAD"], {
6556
7171
  cwd: root,
6557
7172
  encoding: "utf8",
6558
7173
  stdio: ["ignore", "pipe", "ignore"]
@@ -6564,7 +7179,7 @@ function readHeadSha(root) {
6564
7179
 
6565
7180
  // packages/local-runtime/runtime-daemon/src/index.ts
6566
7181
  import { randomBytes } from "node:crypto";
6567
- import { chmodSync, closeSync as closeSync4, existsSync as existsSync7, mkdirSync as mkdirSync6, mkdtempSync as mkdtempSync3, openSync as openSync4, readdirSync as readdirSync5, readFileSync as readFileSync6, rmSync as rmSync6, statSync as statSync4, writeFileSync as writeFileSync3 } from "node:fs";
7182
+ import { chmodSync as chmodSync3, closeSync as closeSync5, existsSync as existsSync8, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync3, openSync as openSync5, readdirSync as readdirSync5, readFileSync as readFileSync8, rmSync as rmSync7, statSync as statSync4, writeFileSync as writeFileSync5 } from "node:fs";
6568
7183
  import { createServer } from "node:http";
6569
7184
  import { tmpdir as tmpdir2 } from "node:os";
6570
7185
  import { dirname as dirname7, join as join6, resolve as resolve11 } from "node:path";
@@ -6599,13 +7214,13 @@ async function prepareTask(input) {
6599
7214
  init_src();
6600
7215
 
6601
7216
  // packages/local-runtime/git-adapter/src/index.ts
6602
- import { execFileSync as execFileSync3, spawnSync as spawnSync2 } from "node:child_process";
6603
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, mkdtempSync as mkdtempSync2, rmSync as rmSync3 } from "node:fs";
7217
+ import { execFileSync as execFileSync4, spawnSync as spawnSync2 } from "node:child_process";
7218
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, mkdtempSync as mkdtempSync2, rmSync as rmSync4 } from "node:fs";
6604
7219
  import { dirname as dirname4, join as join4, resolve as resolve8 } from "node:path";
6605
7220
  import { tmpdir } from "node:os";
6606
7221
  function findRepositoryRoot2(start) {
6607
7222
  try {
6608
- return resolve8(execFileSync3("git", ["rev-parse", "--show-toplevel"], {
7223
+ return resolve8(execFileSync4("git", ["rev-parse", "--show-toplevel"], {
6609
7224
  cwd: start,
6610
7225
  encoding: "utf8",
6611
7226
  stdio: ["ignore", "pipe", "ignore"]
@@ -6613,7 +7228,7 @@ function findRepositoryRoot2(start) {
6613
7228
  } catch {
6614
7229
  let cursor = resolve8(start);
6615
7230
  while (cursor !== "/") {
6616
- if (existsSync4(resolve8(cursor, ".git")))
7231
+ if (existsSync5(resolve8(cursor, ".git")))
6617
7232
  return cursor;
6618
7233
  cursor = resolve8(cursor, "..");
6619
7234
  }
@@ -6622,7 +7237,7 @@ function findRepositoryRoot2(start) {
6622
7237
  }
6623
7238
  function readHeadSha2(root) {
6624
7239
  try {
6625
- return execFileSync3("git", ["rev-parse", "HEAD"], {
7240
+ return execFileSync4("git", ["rev-parse", "HEAD"], {
6626
7241
  cwd: root,
6627
7242
  encoding: "utf8",
6628
7243
  stdio: ["ignore", "pipe", "ignore"]
@@ -6682,7 +7297,7 @@ function prepareDetachedReviewWorktree(input) {
6682
7297
  };
6683
7298
  }
6684
7299
  const parent = input.tempRoot ? resolve8(input.tempRoot) : tmpdir();
6685
- mkdirSync3(parent, { recursive: true });
7300
+ mkdirSync4(parent, { recursive: true });
6686
7301
  const temporaryRoot = mkdtempSync2(join4(parent, "archctx-review-worktree-"));
6687
7302
  const worktreeRoot = join4(temporaryRoot, "worktree");
6688
7303
  try {
@@ -6714,7 +7329,7 @@ function prepareDetachedReviewWorktree(input) {
6714
7329
  }
6715
7330
  };
6716
7331
  } catch (error) {
6717
- rmSync3(temporaryRoot, { recursive: true, force: true });
7332
+ rmSync4(temporaryRoot, { recursive: true, force: true });
6718
7333
  if (isGitWorktreeError(error)) {
6719
7334
  return {
6720
7335
  schemaVersion: "archcontext.detached-review-worktree-verification/v1",
@@ -6731,9 +7346,9 @@ function removeDetachedReviewWorktree(worktree) {
6731
7346
  try {
6732
7347
  runGit(worktree.sourceRoot, ["worktree", "remove", "--force", worktree.worktreeRoot]);
6733
7348
  } catch {
6734
- rmSync3(worktree.worktreeRoot, { recursive: true, force: true });
7349
+ rmSync4(worktree.worktreeRoot, { recursive: true, force: true });
6735
7350
  } finally {
6736
- rmSync3(worktree.temporaryRoot || dirname4(worktree.worktreeRoot), { recursive: true, force: true });
7351
+ rmSync4(worktree.temporaryRoot || dirname4(worktree.worktreeRoot), { recursive: true, force: true });
6737
7352
  }
6738
7353
  }
6739
7354
  function readCommitTreeOid(root, headSha) {
@@ -6769,7 +7384,7 @@ function readDetachedWorktreeObserved(worktreeRoot) {
6769
7384
  }
6770
7385
  }
6771
7386
  function runGit(root, args) {
6772
- return execFileSync3("git", args, {
7387
+ return execFileSync4("git", args, {
6773
7388
  cwd: root,
6774
7389
  encoding: "utf8",
6775
7390
  stdio: ["ignore", "pipe", "pipe"]
@@ -6787,16 +7402,34 @@ function isGitWorktreeError(error) {
6787
7402
  }
6788
7403
 
6789
7404
  // packages/local-runtime/local-store-sqlite/src/index.ts
6790
- import { randomUUID } from "node:crypto";
6791
- import { closeSync as closeSync3, existsSync as existsSync5, fsyncSync as fsyncSync2, mkdirSync as mkdirSync4, openSync as openSync3, renameSync as renameSync2, rmSync as rmSync4 } from "node:fs";
7405
+ import { execFileSync as execFileSync5 } from "node:child_process";
7406
+ import { createHash as createHash6, randomUUID as randomUUID2 } from "node:crypto";
7407
+ import { chmodSync as chmodSync2, closeSync as closeSync4, existsSync as existsSync6, fsyncSync as fsyncSync3, lstatSync as lstatSync3, mkdirSync as mkdirSync5, openSync as openSync4, readFileSync as readFileSync6, realpathSync as realpathSync5, renameSync as renameSync3, rmSync as rmSync5, writeFileSync as writeFileSync3 } from "node:fs";
6792
7408
  import { readdir, readFile } from "node:fs/promises";
6793
- import { dirname as dirname5, join as join5, resolve as resolve9 } from "node:path";
6794
- var SQLITE_PRAGMAS = [
7409
+ import { createRequire as createRequire3 } from "node:module";
7410
+ import { homedir as homedir2 } from "node:os";
7411
+ import { dirname as dirname5, isAbsolute as isAbsolute4, join as join5, relative as relative5, resolve as resolve9 } from "node:path";
7412
+ var runtimeRequire2 = createRequire3(import.meta.url);
7413
+ var SQLITE_SIDECAR_SUFFIXES2 = ["", "-wal", "-shm"];
7414
+ var LEGACY_MIGRATION_MARKER_FILE2 = "runtime.sqlite.migration.json";
7415
+ var LEGACY_MIGRATION_LOCK_FILE2 = "runtime.sqlite.migration.lock";
7416
+ var REQUIRED_LOCAL_STORE_TABLES2 = [
7417
+ "schema_migrations",
7418
+ "repository_sessions",
7419
+ "snapshots",
7420
+ "task_states",
7421
+ "observed_evidence",
7422
+ "review_results",
7423
+ "landscapes",
7424
+ "cross_repo_edges",
7425
+ "changeset_journal"
7426
+ ];
7427
+ var SQLITE_PRAGMAS2 = [
6795
7428
  "PRAGMA journal_mode = WAL",
6796
7429
  "PRAGMA foreign_keys = ON",
6797
7430
  "PRAGMA busy_timeout = 5000"
6798
7431
  ];
6799
- var LOCAL_SQLITE_MIGRATIONS = [
7432
+ var LOCAL_SQLITE_MIGRATIONS2 = [
6800
7433
  {
6801
7434
  id: "0001_runtime_state",
6802
7435
  statements: [
@@ -6893,8 +7526,117 @@ var LOCAL_SQLITE_MIGRATIONS = [
6893
7526
  ]
6894
7527
  }
6895
7528
  ];
7529
+ var ARCHCONTEXT_STATE_DIR_ENV2 = "ARCHCONTEXT_STATE_DIR";
7530
+ var ARCHCONTEXT_LOCAL_STORE_PATH_ENV2 = "ARCHCONTEXT_LOCAL_STORE_PATH";
7531
+ function defaultArchContextStateRoot2(env = process.env, platform = process.platform, home = homedir2()) {
7532
+ const override = env[ARCHCONTEXT_STATE_DIR_ENV2];
7533
+ if (override)
7534
+ return { path: resolve9(override), source: "environment" };
7535
+ if (platform === "darwin")
7536
+ return { path: join5(home, "Library", "Application Support", "ArchContext"), source: "os-user-data" };
7537
+ if (platform === "win32")
7538
+ return { path: join5(env.LOCALAPPDATA ?? join5(home, "AppData", "Local"), "ArchContext"), source: "os-user-data" };
7539
+ return { path: join5(env.XDG_DATA_HOME ?? join5(home, ".local", "share"), "archcontext"), source: "os-user-data" };
7540
+ }
7541
+ function runtimeStatePaths2(root = process.cwd(), env = process.env) {
7542
+ const repositoryRoot = readGitPath2(root, ["rev-parse", "--show-toplevel"]) ?? root;
7543
+ const canonicalRepositoryRoot3 = canonicalPath2(repositoryRoot);
7544
+ const gitCommonDir = readGitPath2(canonicalRepositoryRoot3, ["rev-parse", "--git-common-dir"]);
7545
+ const repositoryAnchor = canonicalPath2(gitCommonDir ? resolveMaybeRelative2(canonicalRepositoryRoot3, gitCommonDir) : canonicalRepositoryRoot3);
7546
+ const workspaceAnchor = canonicalRepositoryRoot3;
7547
+ const storageRepositoryId = stableStorageId2("repo", repositoryAnchor);
7548
+ const storageWorkspaceId = stableStorageId2("ws", workspaceAnchor);
7549
+ const stateRoot = defaultArchContextStateRoot2(env);
7550
+ const repositoryStateDir = join5(stateRoot.path, "repositories", storageRepositoryId);
7551
+ const workspaceStateDir = join5(repositoryStateDir, "worktrees", storageWorkspaceId);
7552
+ const legacyControlDir = resolve9(canonicalRepositoryRoot3, ".archcontext", ".local");
7553
+ return {
7554
+ schemaVersion: "archcontext.runtime-state-paths/v1",
7555
+ stateRoot: stateRoot.path,
7556
+ source: stateRoot.source,
7557
+ repositoryRoot: canonicalRepositoryRoot3,
7558
+ repositoryAnchor,
7559
+ workspaceAnchor,
7560
+ storageRepositoryId,
7561
+ storageWorkspaceId,
7562
+ repositoryId: storageRepositoryId,
7563
+ workspaceId: storageWorkspaceId,
7564
+ repositoryStateDir,
7565
+ workspaceStateDir,
7566
+ sharedCacheDir: join5(repositoryStateDir, "shared", "cache"),
7567
+ localStorePath: env[ARCHCONTEXT_LOCAL_STORE_PATH_ENV2] ?? join5(workspaceStateDir, "runtime.sqlite"),
7568
+ daemonConnectionPath: join5(workspaceStateDir, "archctxd.json"),
7569
+ daemonLockPath: join5(workspaceStateDir, "archctxd.lock"),
7570
+ daemonLogPath: join5(workspaceStateDir, "archctxd.log"),
7571
+ developerReviewRunStateDir: join5(workspaceStateDir, "developer-review-runs"),
7572
+ legacyControlDir,
7573
+ legacyLocalStorePath: join5(legacyControlDir, "runtime.sqlite")
7574
+ };
7575
+ }
6896
7576
  function defaultLocalStorePath2(root = process.cwd()) {
6897
- return process.env.ARCHCONTEXT_LOCAL_STORE_PATH ?? resolve9(root, ".archcontext/.local/runtime.sqlite");
7577
+ return runtimeStatePaths2(root).localStorePath;
7578
+ }
7579
+ function migrateLegacyLocalStoreIfNeeded2(root = process.cwd(), env = process.env) {
7580
+ const paths = runtimeStatePaths2(root, env);
7581
+ if (env[ARCHCONTEXT_LOCAL_STORE_PATH_ENV2]) {
7582
+ return legacyMigrationResult2(false, "explicit-local-store-override", paths, [], {
7583
+ status: "explicit-local-store-override"
7584
+ });
7585
+ }
7586
+ ensurePrivateDir2(dirname5(paths.localStorePath));
7587
+ const legacyExists = existsSync6(paths.legacyLocalStorePath);
7588
+ const integrityCheck = {};
7589
+ const quarantinedFiles = [];
7590
+ const targetExists = existsSync6(paths.localStorePath);
7591
+ if (targetExists) {
7592
+ try {
7593
+ integrityCheck.target = assertCurrentLocalStore2(paths.localStorePath);
7594
+ return legacyMigrationResult2(false, "target-exists", paths, [], {
7595
+ status: "target-current",
7596
+ integrityCheck
7597
+ });
7598
+ } catch (error) {
7599
+ integrityCheck.target = "failed";
7600
+ integrityCheck.error = error instanceof Error ? error.message : String(error);
7601
+ if (!legacyExists) {
7602
+ throw new Error(`ArchContext runtime state target is not a valid SQLite database and no legacy store is available: ${paths.localStorePath}`);
7603
+ }
7604
+ }
7605
+ }
7606
+ if (!legacyExists) {
7607
+ return legacyMigrationResult2(false, "legacy-missing", paths, [], {
7608
+ status: "legacy-missing",
7609
+ integrityCheck
7610
+ });
7611
+ }
7612
+ assertTrustedLegacyLocalStoreSource2(paths);
7613
+ const lock = acquireLegacyMigrationLock2(paths);
7614
+ const stagingDir = join5(paths.workspaceStateDir, `.runtime.sqlite.migration-${process.pid}-${randomUUID2()}`);
7615
+ const stagingPath = join5(stagingDir, "runtime.sqlite");
7616
+ try {
7617
+ if (targetExists)
7618
+ quarantinedFiles.push(...quarantineExistingLocalStore2(paths));
7619
+ ensurePrivateDir2(stagingDir);
7620
+ integrityCheck.legacy = vacuumLegacySqliteInto2(paths.legacyLocalStorePath, stagingPath);
7621
+ makePrivateFile2(stagingPath);
7622
+ migrateSqliteDatabaseSync2(stagingPath);
7623
+ compactSqliteDatabase2(stagingPath);
7624
+ integrityCheck.staging = assertCurrentLocalStore2(stagingPath);
7625
+ publishStagedLocalStore2(stagingPath, paths.localStorePath);
7626
+ integrityCheck.target = assertCurrentLocalStore2(paths.localStorePath);
7627
+ const markerPath = writeLegacyMigrationMarker2(paths, integrityCheck, quarantinedFiles);
7628
+ return legacyMigrationResult2(true, undefined, paths, [paths.localStorePath], {
7629
+ status: quarantinedFiles.length > 0 ? "target-quarantined-and-migrated" : "migrated",
7630
+ integrityCheck,
7631
+ markerPath,
7632
+ quarantinedFiles
7633
+ });
7634
+ } catch (error) {
7635
+ throw new Error(`ArchContext legacy SQLite migration failed: ${error instanceof Error ? error.message : String(error)}`);
7636
+ } finally {
7637
+ rmSync5(stagingDir, { recursive: true, force: true });
7638
+ releaseLegacyMigrationLock2(lock);
7639
+ }
6898
7640
  }
6899
7641
 
6900
7642
  class SqliteLocalStore {
@@ -6905,20 +7647,20 @@ class SqliteLocalStore {
6905
7647
  }
6906
7648
  async migrate() {
6907
7649
  const db = await this.database();
6908
- for (const pragma of SQLITE_PRAGMAS)
7650
+ for (const pragma of SQLITE_PRAGMAS2)
6909
7651
  db.exec(pragma);
6910
- for (const migration of LOCAL_SQLITE_MIGRATIONS) {
7652
+ for (const migration of LOCAL_SQLITE_MIGRATIONS2) {
6911
7653
  for (const statement of migration.statements)
6912
7654
  db.exec(statement);
6913
- db.prepare("INSERT OR IGNORE INTO schema_migrations (id, applied_at) VALUES (?, ?)").run(migration.id, nowIso());
7655
+ db.prepare("INSERT OR IGNORE INTO schema_migrations (id, applied_at) VALUES (?, ?)").run(migration.id, nowIso2());
6914
7656
  }
6915
7657
  }
6916
7658
  async beginSnapshot(snapshot) {
6917
7659
  const db = await this.database();
6918
- const snapshotId = `snapshot_${randomUUID()}`;
7660
+ const snapshotId = `snapshot_${randomUUID2()}`;
6919
7661
  db.prepare(`INSERT INTO snapshots
6920
7662
  (id, repository_id, head_sha, worktree_digest, state, created_at)
6921
- VALUES (?, ?, ?, ?, ?, ?)`).run(snapshotId, snapshot.repositoryId, snapshot.headSha, snapshot.worktreeDigest, "pending", nowIso());
7663
+ VALUES (?, ?, ?, ?, ?, ?)`).run(snapshotId, snapshot.repositoryId, snapshot.headSha, snapshot.worktreeDigest, "pending", nowIso2());
6922
7664
  return snapshotId;
6923
7665
  }
6924
7666
  async commitSnapshot(snapshotId) {
@@ -6926,7 +7668,7 @@ class SqliteLocalStore {
6926
7668
  const existing = db.prepare("SELECT id FROM snapshots WHERE id = ?").get(snapshotId);
6927
7669
  if (!existing)
6928
7670
  throw new Error(`Snapshot not found: ${snapshotId}`);
6929
- db.prepare("UPDATE snapshots SET state = ?, committed_at = ? WHERE id = ?").run("committed", nowIso(), snapshotId);
7671
+ db.prepare("UPDATE snapshots SET state = ?, committed_at = ? WHERE id = ?").run("committed", nowIso2(), snapshotId);
6930
7672
  }
6931
7673
  recoverPendingSnapshots() {
6932
7674
  const db = this.requireOpenDatabase();
@@ -6954,10 +7696,10 @@ class SqliteLocalStore {
6954
7696
  }
6955
7697
  async beginChangeSet(root, draft) {
6956
7698
  const db = await this.database();
6957
- const journalId = `changeset_${randomUUID()}`;
7699
+ const journalId = `changeset_${randomUUID2()}`;
6958
7700
  db.prepare(`INSERT INTO changeset_journal
6959
7701
  (journal_id, changeset_id, root, status, metadata_json, files_json, created_at, updated_at)
6960
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(journalId, draft.id, root, "pending", stableJson(changeSetMetadata(draft)), "[]", nowIso(), nowIso());
7702
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`).run(journalId, draft.id, root, "pending", stableJson(changeSetMetadata(draft)), "[]", nowIso2(), nowIso2());
6961
7703
  return journalId;
6962
7704
  }
6963
7705
  async recordChangeSetFile(journalId, file) {
@@ -6967,14 +7709,14 @@ class SqliteLocalStore {
6967
7709
  throw new Error(`ChangeSet journal not found: ${journalId}`);
6968
7710
  const files = JSON.parse(String(row.files_json));
6969
7711
  files.push(file);
6970
- db.prepare("UPDATE changeset_journal SET files_json = ?, updated_at = ? WHERE journal_id = ?").run(stableJson(files), nowIso(), journalId);
7712
+ db.prepare("UPDATE changeset_journal SET files_json = ?, updated_at = ? WHERE journal_id = ?").run(stableJson(files), nowIso2(), journalId);
6971
7713
  }
6972
7714
  async commitChangeSet(journalId) {
6973
7715
  const db = await this.database();
6974
7716
  const existing = db.prepare("SELECT journal_id FROM changeset_journal WHERE journal_id = ?").get(journalId);
6975
7717
  if (!existing)
6976
7718
  throw new Error(`ChangeSet journal not found: ${journalId}`);
6977
- db.prepare("UPDATE changeset_journal SET status = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("committed", nowIso(), nowIso(), journalId);
7719
+ db.prepare("UPDATE changeset_journal SET status = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("committed", nowIso2(), nowIso2(), journalId);
6978
7720
  }
6979
7721
  async abortChangeSet(journalId, reason) {
6980
7722
  const db = await this.database();
@@ -6982,7 +7724,7 @@ class SqliteLocalStore {
6982
7724
  if (!row)
6983
7725
  throw new Error(`ChangeSet journal not found: ${journalId}`);
6984
7726
  const metadata = JSON.parse(String(row.metadata_json));
6985
- db.prepare("UPDATE changeset_journal SET status = ?, metadata_json = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("aborted", stableJson({ ...metadata, abortReason: reason }), nowIso(), nowIso(), journalId);
7727
+ db.prepare("UPDATE changeset_journal SET status = ?, metadata_json = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("aborted", stableJson({ ...metadata, abortReason: reason }), nowIso2(), nowIso2(), journalId);
6986
7728
  }
6987
7729
  recoverPendingChangeSets() {
6988
7730
  const db = this.requireOpenDatabase();
@@ -6994,7 +7736,7 @@ class SqliteLocalStore {
6994
7736
  for (const row of rows) {
6995
7737
  const files = JSON.parse(String(row.files_json));
6996
7738
  recoverJournalFiles(String(row.root), files);
6997
- db.prepare("UPDATE changeset_journal SET status = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("recovered", nowIso(), nowIso(), String(row.journal_id));
7739
+ db.prepare("UPDATE changeset_journal SET status = ?, updated_at = ?, completed_at = ? WHERE journal_id = ?").run("recovered", nowIso2(), nowIso2(), String(row.journal_id));
6998
7740
  }
6999
7741
  return rows.length;
7000
7742
  }
@@ -7002,7 +7744,7 @@ class SqliteLocalStore {
7002
7744
  const db = await this.database();
7003
7745
  db.prepare(`INSERT OR REPLACE INTO task_states
7004
7746
  (task_session_id, payload_json, updated_at)
7005
- VALUES (?, ?, ?)`).run(taskSessionId, stableJson(state), nowIso());
7747
+ VALUES (?, ?, ?)`).run(taskSessionId, stableJson(state), nowIso2());
7006
7748
  }
7007
7749
  async readTaskState(taskSessionId) {
7008
7750
  const db = await this.database();
@@ -7013,13 +7755,13 @@ class SqliteLocalStore {
7013
7755
  const db = await this.database();
7014
7756
  db.prepare(`INSERT OR REPLACE INTO review_results
7015
7757
  (review_id, task_session_id, payload_json, created_at)
7016
- VALUES (?, ?, ?, ?)`).run(reviewId, reviewTaskSessionId(result) ?? reviewId, stableJson(result), nowIso());
7758
+ VALUES (?, ?, ?, ?)`).run(reviewId, reviewTaskSessionId(result) ?? reviewId, stableJson(result), nowIso2());
7017
7759
  }
7018
7760
  async saveLandscape(landscape) {
7019
7761
  const db = await this.database();
7020
7762
  db.prepare(`INSERT OR REPLACE INTO landscapes
7021
7763
  (id, digest, metadata_json, updated_at)
7022
- VALUES (?, ?, ?, ?)`).run(landscape.id, landscapeDigest(landscape), stableJson(landscape), nowIso());
7764
+ VALUES (?, ?, ?, ?)`).run(landscape.id, landscapeDigest(landscape), stableJson(landscape), nowIso2());
7023
7765
  }
7024
7766
  async readLandscape(landscapeId) {
7025
7767
  const db = await this.database();
@@ -7030,7 +7772,7 @@ class SqliteLocalStore {
7030
7772
  const db = await this.database();
7031
7773
  db.prepare(`INSERT OR REPLACE INTO cross_repo_edges
7032
7774
  (id, landscape_id, from_repository_id, from_node_id, to_repository_id, to_node_id, via_kind, via_id, metadata_json, updated_at)
7033
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(relation.id, "unscoped", relation.source.repositoryId, relation.source.nodeId, relation.target.repositoryId, relation.target.nodeId, relation.via.kind, relation.via.id, stableJson(relation), nowIso());
7775
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(relation.id, "unscoped", relation.source.repositoryId, relation.source.nodeId, relation.target.repositoryId, relation.target.nodeId, relation.via.kind, relation.via.id, stableJson(relation), nowIso2());
7034
7776
  }
7035
7777
  async listCrossRepoRelations(landscape) {
7036
7778
  const db = await this.database();
@@ -7090,7 +7832,7 @@ async function rebuildDerivedLandscapeState(store, input) {
7090
7832
  }
7091
7833
  async function openSqliteDatabase(databasePath) {
7092
7834
  if (databasePath !== ":memory:")
7093
- mkdirSync4(dirname5(databasePath), { recursive: true });
7835
+ ensurePrivateDir2(dirname5(databasePath));
7094
7836
  try {
7095
7837
  const nodeSqlite = await import("node:sqlite");
7096
7838
  const db = new nodeSqlite.DatabaseSync(databasePath);
@@ -7109,10 +7851,293 @@ async function openSqliteDatabase(databasePath) {
7109
7851
  };
7110
7852
  }
7111
7853
  }
7854
+ function openSqliteDatabaseSync2(databasePath) {
7855
+ if (databasePath !== ":memory:")
7856
+ ensurePrivateDir2(dirname5(databasePath));
7857
+ try {
7858
+ const nodeSqlite = runtimeRequire2("node:sqlite");
7859
+ const db2 = new nodeSqlite.DatabaseSync(databasePath);
7860
+ return {
7861
+ exec: (sql) => db2.exec(sql),
7862
+ prepare: (sql) => db2.prepare(sql),
7863
+ close: () => db2.close()
7864
+ };
7865
+ } catch (error) {
7866
+ if (error.code !== "ERR_UNKNOWN_BUILTIN_MODULE" && error.code !== "MODULE_NOT_FOUND") {
7867
+ throw error;
7868
+ }
7869
+ }
7870
+ const bunSqlite = runtimeRequire2("bun:sqlite");
7871
+ const db = new bunSqlite.Database(databasePath);
7872
+ return {
7873
+ exec: (sql) => db.exec(sql),
7874
+ prepare: (sql) => db.query(sql),
7875
+ close: () => db.close()
7876
+ };
7877
+ }
7878
+ function legacyMigrationResult2(migrated, skippedReason, paths, copiedFiles, details) {
7879
+ return {
7880
+ schemaVersion: "archcontext.legacy-local-store-migration/v1",
7881
+ status: details.status,
7882
+ migrated,
7883
+ skippedReason,
7884
+ legacyLocalStorePath: paths.legacyLocalStorePath,
7885
+ targetLocalStorePath: paths.localStorePath,
7886
+ markerPath: details.markerPath ?? legacyMigrationMarkerPath2(paths),
7887
+ lockPath: legacyMigrationLockPath2(paths),
7888
+ integrityCheck: details.integrityCheck ?? {},
7889
+ copiedFiles,
7890
+ quarantinedFiles: details.quarantinedFiles ?? []
7891
+ };
7892
+ }
7893
+ function assertCurrentLocalStore2(path) {
7894
+ const db = openSqliteDatabaseSync2(path);
7895
+ try {
7896
+ db.exec("PRAGMA busy_timeout = 5000");
7897
+ const integrity = sqliteIntegrityCheckOpenDatabase2(db, path);
7898
+ assertCurrentLocalStoreSchema2(db, path);
7899
+ return integrity;
7900
+ } finally {
7901
+ db.close();
7902
+ }
7903
+ }
7904
+ function assertCurrentLocalStoreSchema2(db, path) {
7905
+ const tables = new Set(db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all().map((row) => String(row.name)));
7906
+ const missingTables = REQUIRED_LOCAL_STORE_TABLES2.filter((table) => !tables.has(table));
7907
+ if (missingTables.length > 0) {
7908
+ throw new Error(`SQLite local store schema incomplete for ${path}: missing tables ${missingTables.join(", ")}`);
7909
+ }
7910
+ const migrations = new Set(db.prepare("SELECT id FROM schema_migrations").all().map((row) => String(row.id)));
7911
+ const missingMigrations = LOCAL_SQLITE_MIGRATIONS2.map((migration) => migration.id).filter((id) => !migrations.has(id));
7912
+ if (missingMigrations.length > 0) {
7913
+ throw new Error(`SQLite local store schema incomplete for ${path}: missing migrations ${missingMigrations.join(", ")}`);
7914
+ }
7915
+ }
7916
+ function assertTrustedLegacyLocalStoreSource2(paths) {
7917
+ const stat = lstatSync3(paths.legacyLocalStorePath);
7918
+ if (stat.isSymbolicLink()) {
7919
+ throw new Error(`Legacy SQLite source must not be a symbolic link: ${paths.legacyLocalStorePath}`);
7920
+ }
7921
+ if (!stat.isFile()) {
7922
+ throw new Error(`Legacy SQLite source must be a regular file: ${paths.legacyLocalStorePath}`);
7923
+ }
7924
+ const sourceRealPath = realpathSync5.native(paths.legacyLocalStorePath);
7925
+ if (!isPathInsideOrSame2(sourceRealPath, paths.repositoryRoot)) {
7926
+ throw new Error(`Legacy SQLite source must stay inside the repository root: ${paths.legacyLocalStorePath}`);
7927
+ }
7928
+ }
7929
+ function vacuumLegacySqliteInto2(sourcePath, targetPath) {
7930
+ const db = openSqliteDatabaseSync2(sourcePath);
7931
+ try {
7932
+ db.exec("PRAGMA busy_timeout = 5000");
7933
+ db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
7934
+ const integrity = sqliteIntegrityCheckOpenDatabase2(db, sourcePath);
7935
+ db.exec(`VACUUM INTO ${sqliteStringLiteral2(targetPath)}`);
7936
+ return integrity;
7937
+ } finally {
7938
+ db.close();
7939
+ }
7940
+ }
7941
+ function migrateSqliteDatabaseSync2(databasePath) {
7942
+ const db = openSqliteDatabaseSync2(databasePath);
7943
+ try {
7944
+ for (const pragma of SQLITE_PRAGMAS2)
7945
+ db.exec(pragma);
7946
+ for (const migration of LOCAL_SQLITE_MIGRATIONS2) {
7947
+ for (const statement of migration.statements)
7948
+ db.exec(statement);
7949
+ db.prepare("INSERT OR IGNORE INTO schema_migrations (id, applied_at) VALUES (?, ?)").run(migration.id, nowIso2());
7950
+ }
7951
+ } finally {
7952
+ db.close();
7953
+ }
7954
+ }
7955
+ function compactSqliteDatabase2(databasePath) {
7956
+ const db = openSqliteDatabaseSync2(databasePath);
7957
+ try {
7958
+ db.exec("PRAGMA busy_timeout = 5000");
7959
+ db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
7960
+ db.exec("PRAGMA journal_mode = DELETE");
7961
+ } finally {
7962
+ db.close();
7963
+ }
7964
+ for (const suffix of ["-wal", "-shm"])
7965
+ rmSync5(`${databasePath}${suffix}`, { force: true });
7966
+ }
7967
+ function sqliteIntegrityCheckOpenDatabase2(db, path) {
7968
+ const row = db.prepare("PRAGMA integrity_check").get();
7969
+ const result = firstSqliteColumn2(row);
7970
+ if (result !== "ok")
7971
+ throw new Error(`SQLite integrity_check failed for ${path}: ${result}`);
7972
+ return result;
7973
+ }
7974
+ function firstSqliteColumn2(row) {
7975
+ const value = row ? Object.values(row)[0] : undefined;
7976
+ return typeof value === "string" ? value : String(value ?? "");
7977
+ }
7978
+ function sqliteStringLiteral2(value) {
7979
+ return `'${value.replace(/'/g, "''")}'`;
7980
+ }
7981
+ function publishStagedLocalStore2(stagingPath, targetPath) {
7982
+ for (const suffix of SQLITE_SIDECAR_SUFFIXES2) {
7983
+ const path = `${targetPath}${suffix}`;
7984
+ if (existsSync6(path))
7985
+ throw new Error(`Cannot publish migrated SQLite over existing target file: ${path}`);
7986
+ }
7987
+ renameSync3(stagingPath, targetPath);
7988
+ makePrivateFile2(targetPath);
7989
+ fsyncDirectory3(dirname5(targetPath));
7990
+ }
7991
+ function writeLegacyMigrationMarker2(paths, integrityCheck, quarantinedFiles) {
7992
+ const markerPath = legacyMigrationMarkerPath2(paths);
7993
+ writePrivateJson2(markerPath, {
7994
+ schemaVersion: "archcontext.legacy-local-store-migration-marker/v1",
7995
+ migratedAt: nowIso2(),
7996
+ legacyLocalStorePath: paths.legacyLocalStorePath,
7997
+ targetLocalStorePath: paths.localStorePath,
7998
+ integrityCheck,
7999
+ quarantinedFiles
8000
+ });
8001
+ return markerPath;
8002
+ }
8003
+ function acquireLegacyMigrationLock2(paths) {
8004
+ const lockPath = legacyMigrationLockPath2(paths);
8005
+ ensurePrivateDir2(dirname5(lockPath));
8006
+ try {
8007
+ const fd = openSync4(lockPath, "wx", 384);
8008
+ writeFileSync3(fd, JSON.stringify({
8009
+ schemaVersion: "archcontext.legacy-local-store-migration-lock/v1",
8010
+ pid: process.pid,
8011
+ root: paths.repositoryRoot,
8012
+ targetLocalStorePath: paths.localStorePath,
8013
+ startedAt: nowIso2()
8014
+ }, null, 2), "utf8");
8015
+ fsyncSync3(fd);
8016
+ return { fd, path: lockPath };
8017
+ } catch (error) {
8018
+ const code = error.code;
8019
+ if (code === "EEXIST" && isStaleMigrationLock2(lockPath)) {
8020
+ rmSync5(lockPath, { force: true });
8021
+ return acquireLegacyMigrationLock2(paths);
8022
+ }
8023
+ if (code === "EEXIST")
8024
+ throw new Error(`Legacy SQLite migration already in progress; lock=${lockPath}`);
8025
+ throw error;
8026
+ }
8027
+ }
8028
+ function releaseLegacyMigrationLock2(lock) {
8029
+ closeSync4(lock.fd);
8030
+ rmSync5(lock.path, { force: true });
8031
+ }
8032
+ function isStaleMigrationLock2(lockPath) {
8033
+ try {
8034
+ const parsed = JSON.parse(readFileSync6(lockPath, "utf8"));
8035
+ if (typeof parsed.pid !== "number" || parsed.pid <= 0)
8036
+ return true;
8037
+ return !isProcessAlive2(parsed.pid);
8038
+ } catch {
8039
+ return true;
8040
+ }
8041
+ }
8042
+ function isProcessAlive2(pid) {
8043
+ try {
8044
+ process.kill(pid, 0);
8045
+ return true;
8046
+ } catch (error) {
8047
+ return error.code !== "ESRCH";
8048
+ }
8049
+ }
8050
+ function quarantineExistingLocalStore2(paths) {
8051
+ const quarantineDir = join5(paths.workspaceStateDir, "quarantine", `runtime.sqlite-${Date.now()}-${randomUUID2()}`);
8052
+ ensurePrivateDir2(quarantineDir);
8053
+ const quarantinedFiles = [];
8054
+ for (const suffix of SQLITE_SIDECAR_SUFFIXES2) {
8055
+ const source = `${paths.localStorePath}${suffix}`;
8056
+ if (!existsSync6(source))
8057
+ continue;
8058
+ const target = join5(quarantineDir, `runtime.sqlite${suffix}`);
8059
+ renameSync3(source, target);
8060
+ quarantinedFiles.push(target);
8061
+ }
8062
+ const markerPath = legacyMigrationMarkerPath2(paths);
8063
+ if (existsSync6(markerPath)) {
8064
+ const target = join5(quarantineDir, LEGACY_MIGRATION_MARKER_FILE2);
8065
+ renameSync3(markerPath, target);
8066
+ quarantinedFiles.push(target);
8067
+ }
8068
+ fsyncDirectory3(quarantineDir);
8069
+ fsyncDirectory3(dirname5(paths.localStorePath));
8070
+ return quarantinedFiles;
8071
+ }
8072
+ function legacyMigrationMarkerPath2(paths) {
8073
+ return join5(paths.workspaceStateDir, LEGACY_MIGRATION_MARKER_FILE2);
8074
+ }
8075
+ function legacyMigrationLockPath2(paths) {
8076
+ return join5(paths.workspaceStateDir, LEGACY_MIGRATION_LOCK_FILE2);
8077
+ }
8078
+ function writePrivateJson2(path, value) {
8079
+ ensurePrivateDir2(dirname5(path));
8080
+ const fd = openSync4(path, "w", 384);
8081
+ try {
8082
+ writeFileSync3(fd, JSON.stringify(value, null, 2), "utf8");
8083
+ fsyncSync3(fd);
8084
+ } finally {
8085
+ closeSync4(fd);
8086
+ }
8087
+ makePrivateFile2(path);
8088
+ fsyncDirectory3(dirname5(path));
8089
+ }
8090
+ function ensurePrivateDir2(path) {
8091
+ mkdirSync5(path, { recursive: true, mode: 448 });
8092
+ if (process.platform !== "win32") {
8093
+ try {
8094
+ chmodSync2(path, 448);
8095
+ } catch {}
8096
+ }
8097
+ }
8098
+ function makePrivateFile2(path) {
8099
+ if (process.platform !== "win32") {
8100
+ try {
8101
+ chmodSync2(path, 384);
8102
+ } catch {}
8103
+ }
8104
+ }
8105
+ function readGitPath2(root, args) {
8106
+ try {
8107
+ const value = execFileSync5("git", args, {
8108
+ cwd: root,
8109
+ encoding: "utf8",
8110
+ stdio: ["ignore", "pipe", "ignore"]
8111
+ }).trim();
8112
+ return value.length > 0 ? value : undefined;
8113
+ } catch {
8114
+ return;
8115
+ }
8116
+ }
8117
+ function resolveMaybeRelative2(base, path) {
8118
+ return isAbsolute4(path) ? resolve9(path) : resolve9(base, path);
8119
+ }
8120
+ function canonicalPath2(path) {
8121
+ const resolved = resolve9(path);
8122
+ try {
8123
+ return realpathSync5.native(resolved);
8124
+ } catch {
8125
+ return resolved;
8126
+ }
8127
+ }
8128
+ function isPathInsideOrSame2(path, parent) {
8129
+ const child = resolve9(path);
8130
+ const base = resolve9(parent);
8131
+ const fromBase = relative5(base, child);
8132
+ return fromBase === "" || !!fromBase && !fromBase.startsWith("..") && !isAbsolute4(fromBase);
8133
+ }
8134
+ function stableStorageId2(prefix, value) {
8135
+ return `${prefix}.${createHash6("sha256").update(value).digest("hex").slice(0, 16)}`;
8136
+ }
7112
8137
  function stableJson(value) {
7113
8138
  return JSON.stringify(value);
7114
8139
  }
7115
- function nowIso() {
8140
+ function nowIso2() {
7116
8141
  return new Date().toISOString();
7117
8142
  }
7118
8143
  function changeSetMetadata(draft) {
@@ -7137,36 +8162,36 @@ function recoverJournalFiles(root, files) {
7137
8162
  for (const file of [...files].reverse()) {
7138
8163
  const absolute = resolve9(root, file.path);
7139
8164
  if (file.tempPath)
7140
- rmSync4(file.tempPath, { recursive: true, force: true });
7141
- rmSync4(absolute, { recursive: true, force: true });
7142
- if (file.existed && file.backupPath && existsSync5(file.backupPath)) {
7143
- renameSync2(file.backupPath, absolute);
8165
+ rmSync5(file.tempPath, { recursive: true, force: true });
8166
+ rmSync5(absolute, { recursive: true, force: true });
8167
+ if (file.existed && file.backupPath && existsSync6(file.backupPath)) {
8168
+ renameSync3(file.backupPath, absolute);
7144
8169
  }
7145
- fsyncDirectory2(dirname5(absolute));
8170
+ fsyncDirectory3(dirname5(absolute));
7146
8171
  }
7147
8172
  }
7148
8173
  function cleanupCommittedJournalFiles(files) {
7149
8174
  for (const file of files) {
7150
8175
  if (file.tempPath)
7151
- rmSync4(file.tempPath, { recursive: true, force: true });
8176
+ rmSync5(file.tempPath, { recursive: true, force: true });
7152
8177
  if (file.backupPath)
7153
- rmSync4(file.backupPath, { recursive: true, force: true });
8178
+ rmSync5(file.backupPath, { recursive: true, force: true });
7154
8179
  }
7155
8180
  }
7156
- function fsyncDirectory2(path) {
8181
+ function fsyncDirectory3(path) {
7157
8182
  try {
7158
- const fd = openSync3(path, "r");
8183
+ const fd = openSync4(path, "r");
7159
8184
  try {
7160
- fsyncSync2(fd);
8185
+ fsyncSync3(fd);
7161
8186
  } finally {
7162
- closeSync3(fd);
8187
+ closeSync4(fd);
7163
8188
  }
7164
8189
  } catch (error) {
7165
- if (!isIgnorableDirectoryFsyncError2(error))
8190
+ if (!isIgnorableDirectoryFsyncError3(error))
7166
8191
  throw error;
7167
8192
  }
7168
8193
  }
7169
- function isIgnorableDirectoryFsyncError2(error) {
8194
+ function isIgnorableDirectoryFsyncError3(error) {
7170
8195
  const code = error.code;
7171
8196
  return code === "EINVAL" || code === "EISDIR" || process.platform === "win32" && code === "EPERM";
7172
8197
  }
@@ -7197,7 +8222,7 @@ async function readRelationFiles(root, relationsDir) {
7197
8222
 
7198
8223
  // packages/local-runtime/model-store-yaml/src/index.ts
7199
8224
  init_src();
7200
- import { existsSync as existsSync6, mkdirSync as mkdirSync5, readdirSync as readdirSync4, readFileSync as readFileSync5, rmSync as rmSync5, writeFileSync as writeFileSync2 } from "node:fs";
8225
+ import { existsSync as existsSync7, mkdirSync as mkdirSync6, readdirSync as readdirSync4, readFileSync as readFileSync7, rmSync as rmSync6, writeFileSync as writeFileSync4 } from "node:fs";
7201
8226
  import { dirname as dirname6, resolve as resolve10 } from "node:path";
7202
8227
  function createDefaultManifest(productId, productName) {
7203
8228
  return {
@@ -7251,7 +8276,7 @@ function initializeArchContextModel(root, productName = "ArchContext Project") {
7251
8276
  rebuildGeneratedProjection(root);
7252
8277
  }
7253
8278
  function rebuildGeneratedProjection(root) {
7254
- rmSync5(resolve10(root, ".archcontext/generated"), { recursive: true, force: true });
8279
+ rmSync6(resolve10(root, ".archcontext/generated"), { recursive: true, force: true });
7255
8280
  writeFile(root, ".archcontext/generated/ARCHITECTURE.md", [
7256
8281
  "<!-- Generated by ArchContext. Do not edit by hand. -->",
7257
8282
  "",
@@ -7265,7 +8290,7 @@ function rebuildGeneratedProjection(root) {
7265
8290
 
7266
8291
  class YamlModelStore {
7267
8292
  async loadManifest(workspace) {
7268
- return readFileSync5(resolve10(workspace.root, ".archcontext/manifest.yaml"), "utf8");
8293
+ return readFileSync7(resolve10(workspace.root, ".archcontext/manifest.yaml"), "utf8");
7269
8294
  }
7270
8295
  async loadModel(workspace) {
7271
8296
  return listModelFiles(workspace.root);
@@ -7274,7 +8299,7 @@ class YamlModelStore {
7274
8299
  const errors = [];
7275
8300
  for (const required of [".archcontext/manifest.yaml", ".archcontext/product.yaml"]) {
7276
8301
  try {
7277
- readFileSync5(resolve10(workspace.root, required), "utf8");
8302
+ readFileSync7(resolve10(workspace.root, required), "utf8");
7278
8303
  } catch {
7279
8304
  errors.push(`missing ${required}`);
7280
8305
  }
@@ -7301,7 +8326,7 @@ function listModelFiles(root) {
7301
8326
  ".archcontext/generated"
7302
8327
  ]);
7303
8328
  return paths.map((path) => {
7304
- const body = readFileSync5(resolve10(root, path), "utf8");
8329
+ const body = readFileSync7(resolve10(root, path), "utf8");
7305
8330
  return {
7306
8331
  path,
7307
8332
  body,
@@ -7314,7 +8339,7 @@ function collectArchContextFiles(root, entries) {
7314
8339
  const files = [];
7315
8340
  for (const entry of entries) {
7316
8341
  const absolute = resolve10(root, entry);
7317
- if (!existsSync6(absolute))
8342
+ if (!existsSync7(absolute))
7318
8343
  continue;
7319
8344
  const stat = readdirOrFile(absolute);
7320
8345
  if (stat === "file") {
@@ -7359,8 +8384,8 @@ function writeYaml(root, path, value) {
7359
8384
  }
7360
8385
  function writeFile(root, path, body) {
7361
8386
  const absolute = resolve10(root, path);
7362
- mkdirSync5(dirname6(absolute), { recursive: true });
7363
- writeFileSync2(absolute, body.endsWith(`
8387
+ mkdirSync6(dirname6(absolute), { recursive: true });
8388
+ writeFileSync4(absolute, body.endsWith(`
7364
8389
  `) ? body : `${body}
7365
8390
  `, "utf8");
7366
8391
  }
@@ -7568,9 +8593,9 @@ class ArchctxDaemon {
7568
8593
  tempRoot: input.tempRoot,
7569
8594
  stateDir: input.stateDir
7570
8595
  });
7571
- mkdirSync6(paths.stateDir, { recursive: true });
7572
- mkdirSync6(paths.runRoot, { recursive: true });
7573
- mkdirSync6(paths.worktreeTempRoot, { recursive: true });
8596
+ mkdirSync7(paths.stateDir, { recursive: true });
8597
+ mkdirSync7(paths.runRoot, { recursive: true });
8598
+ mkdirSync7(paths.worktreeTempRoot, { recursive: true });
7574
8599
  const preparing = {
7575
8600
  schemaVersion: "archcontext.developer-review-run/v1",
7576
8601
  runId: paths.runId,
@@ -7589,13 +8614,13 @@ class ArchctxDaemon {
7589
8614
  cleanup: "remove-run-root"
7590
8615
  }
7591
8616
  };
7592
- if (existsSync7(paths.lockPath) || existsSync7(paths.manifestPath)) {
7593
- rmSync6(paths.runRoot, { recursive: true, force: true });
8617
+ if (existsSync8(paths.lockPath) || existsSync8(paths.manifestPath)) {
8618
+ rmSync7(paths.runRoot, { recursive: true, force: true });
7594
8619
  throw new Error(`developer-review-run-already-active: ${input.challenge.challengeId}`);
7595
8620
  }
7596
8621
  let lockAcquired = false;
7597
8622
  try {
7598
- writePrivateJson(paths.lockPath, {
8623
+ writePrivateJson3(paths.lockPath, {
7599
8624
  schemaVersion: "archcontext.developer-review-run-lock/v1",
7600
8625
  runId: paths.runId,
7601
8626
  challengeId: input.challenge.challengeId,
@@ -7625,7 +8650,7 @@ class ArchctxDaemon {
7625
8650
  if (lockAcquired) {
7626
8651
  this.cleanupDeveloperReviewRun(preparing);
7627
8652
  } else {
7628
- rmSync6(paths.runRoot, { recursive: true, force: true });
8653
+ rmSync7(paths.runRoot, { recursive: true, force: true });
7629
8654
  }
7630
8655
  throw error;
7631
8656
  }
@@ -7646,7 +8671,7 @@ class ArchctxDaemon {
7646
8671
  const errors = [];
7647
8672
  if (run.worktree) {
7648
8673
  try {
7649
- const hadWorktree = existsSync7(run.worktree.worktreeRoot);
8674
+ const hadWorktree = existsSync8(run.worktree.worktreeRoot);
7650
8675
  removeDetachedReviewWorktree(run.worktree);
7651
8676
  if (hadWorktree)
7652
8677
  removed.push("worktree");
@@ -7660,8 +8685,8 @@ class ArchctxDaemon {
7660
8685
  ["lock", run.lockPath]
7661
8686
  ]) {
7662
8687
  try {
7663
- const existed = existsSync7(path);
7664
- rmSync6(path, { recursive: true, force: true });
8688
+ const existed = existsSync8(path);
8689
+ rmSync7(path, { recursive: true, force: true });
7665
8690
  if (existed)
7666
8691
  removed.push(kind);
7667
8692
  } catch (error) {
@@ -7689,7 +8714,7 @@ class ArchctxDaemon {
7689
8714
  removedLocks: [],
7690
8715
  skippedActive: []
7691
8716
  };
7692
- if (!existsSync7(stateDir))
8717
+ if (!existsSync8(stateDir))
7693
8718
  return recovery;
7694
8719
  for (const entry of readdirSync5(stateDir).sort()) {
7695
8720
  if (!entry.endsWith(".json"))
@@ -7697,7 +8722,7 @@ class ArchctxDaemon {
7697
8722
  const manifestPath = join6(stateDir, entry);
7698
8723
  const manifest = readDeveloperReviewRunManifest(manifestPath);
7699
8724
  if (!manifest) {
7700
- rmSync6(manifestPath, { force: true });
8725
+ rmSync7(manifestPath, { force: true });
7701
8726
  continue;
7702
8727
  }
7703
8728
  if (!input.force && isDeveloperReviewPidAlive(manifest.pid)) {
@@ -7717,7 +8742,7 @@ class ArchctxDaemon {
7717
8742
  recovery.skippedActive.push(runId);
7718
8743
  continue;
7719
8744
  }
7720
- rmSync6(lockPath, { force: true });
8745
+ rmSync7(lockPath, { force: true });
7721
8746
  recovery.removedLocks.push(lockPath);
7722
8747
  }
7723
8748
  return recovery;
@@ -8010,7 +9035,7 @@ class ArchctxDaemon {
8010
9035
  const status = this.status();
8011
9036
  if (!root)
8012
9037
  return okEnvelope("status", status);
8013
- const repositoryId = repositoryFingerprint(root);
9038
+ const repositoryId = repositoryFingerprint2(root);
8014
9039
  const session = this.sessions.get(repositoryId);
8015
9040
  return okEnvelope("status", {
8016
9041
  ...status,
@@ -8057,9 +9082,9 @@ class ArchctxDaemon {
8057
9082
  }
8058
9083
  async restoreRepositorySessions() {
8059
9084
  for (const record of await this.localStore.listRepositorySessions()) {
8060
- if (!record.root || !existsSync7(record.root))
9085
+ if (!record.root || !existsSync8(record.root))
8061
9086
  continue;
8062
- if (repositoryFingerprint(record.root) !== record.repositoryId)
9087
+ if (repositoryFingerprint2(record.root) !== record.repositoryId)
8063
9088
  continue;
8064
9089
  this.sessions.set(record.repositoryId, {
8065
9090
  workspace: {
@@ -8345,8 +9370,8 @@ class ArchctxRuntimeRpcServer {
8345
9370
  const root = this.options.root ?? process.cwd();
8346
9371
  const connectionPath = this.options.connectionPath ?? defaultDaemonConnectionPath(root);
8347
9372
  const lockPath = this.options.lockPath ?? defaultDaemonLockPath(root);
8348
- mkdirSync6(dirname7(connectionPath), { recursive: true });
8349
- mkdirSync6(dirname7(lockPath), { recursive: true });
9373
+ mkdirSync7(dirname7(connectionPath), { recursive: true });
9374
+ mkdirSync7(dirname7(lockPath), { recursive: true });
8350
9375
  this.lockFd = acquireDaemonLock(lockPath, root);
8351
9376
  const token = this.options.token ?? randomBytes(18).toString("base64url");
8352
9377
  const server = createServer((request, response) => {
@@ -8369,8 +9394,8 @@ class ArchctxRuntimeRpcServer {
8369
9394
  connectionPath,
8370
9395
  startedAt: (this.options.clock ?? (() => new Date().toISOString()))()
8371
9396
  };
8372
- writeFileSync3(connectionPath, JSON.stringify(this.connection, null, 2), { mode: 384 });
8373
- chmodSync(connectionPath, 384);
9397
+ writeFileSync5(connectionPath, JSON.stringify(this.connection, null, 2), { mode: 384 });
9398
+ chmodSync3(connectionPath, 384);
8374
9399
  return this.connection;
8375
9400
  }
8376
9401
  async stop() {
@@ -8385,12 +9410,12 @@ class ArchctxRuntimeRpcServer {
8385
9410
  }
8386
9411
  await this.daemon.stop();
8387
9412
  if (connection)
8388
- rmSync6(connection.connectionPath, { force: true });
9413
+ rmSync7(connection.connectionPath, { force: true });
8389
9414
  if (this.lockFd !== undefined)
8390
- closeSync4(this.lockFd);
9415
+ closeSync5(this.lockFd);
8391
9416
  this.lockFd = undefined;
8392
9417
  if (connection)
8393
- rmSync6(connection.lockPath, { force: true });
9418
+ rmSync7(connection.lockPath, { force: true });
8394
9419
  this.options.onStop?.();
8395
9420
  }
8396
9421
  async handleRequest(request, response) {
@@ -8513,24 +9538,21 @@ class ArchctxRuntimeRpcServer {
8513
9538
  }
8514
9539
  }
8515
9540
  }
8516
- function defaultDaemonControlDir(root = process.cwd()) {
8517
- return join6(root, ".archcontext", ".local");
8518
- }
8519
9541
  function defaultDeveloperReviewRunStateDir(root = process.cwd()) {
8520
- return join6(defaultDaemonControlDir(root), "developer-review-runs");
9542
+ return runtimeStatePaths2(root).developerReviewRunStateDir;
8521
9543
  }
8522
9544
  function defaultDaemonConnectionPath(root = process.cwd()) {
8523
- return join6(defaultDaemonControlDir(root), "archctxd.json");
9545
+ return runtimeStatePaths2(root).daemonConnectionPath;
8524
9546
  }
8525
9547
  function defaultDaemonLockPath(root = process.cwd()) {
8526
- return join6(defaultDaemonControlDir(root), "archctxd.lock");
9548
+ return runtimeStatePaths2(root).daemonLockPath;
8527
9549
  }
8528
9550
  function readRuntimeRpcConnectionFile(root = process.cwd()) {
8529
9551
  const path = defaultDaemonConnectionPath(root);
8530
9552
  try {
8531
9553
  if (!isPrivateControlFile(path))
8532
9554
  return;
8533
- const parsed = JSON.parse(readFileSync6(path, "utf8"));
9555
+ const parsed = JSON.parse(readFileSync8(path, "utf8"));
8534
9556
  if (!parsed || typeof parsed !== "object")
8535
9557
  return;
8536
9558
  return {
@@ -8562,7 +9584,7 @@ function runtimeRpcCompatibilityIssue(root = process.cwd()) {
8562
9584
  connectionPath: connection.connectionPath ?? defaultDaemonConnectionPath(root),
8563
9585
  lockPath: connection.lockPath ?? defaultDaemonLockPath(root),
8564
9586
  pid,
8565
- pidAlive: pid !== undefined ? isProcessAlive(pid) : false,
9587
+ pidAlive: pid !== undefined ? isProcessAlive3(pid) : false,
8566
9588
  upgradeCommand: "archctx daemon upgrade"
8567
9589
  };
8568
9590
  }
@@ -8571,7 +9593,7 @@ function readRuntimeRpcConnection(root = process.cwd()) {
8571
9593
  try {
8572
9594
  if (!isPrivateControlFile(path))
8573
9595
  return;
8574
- const parsed = JSON.parse(readFileSync6(path, "utf8"));
9596
+ const parsed = JSON.parse(readFileSync8(path, "utf8"));
8575
9597
  return isValidRuntimeRpcConnection(parsed) ? parsed : undefined;
8576
9598
  } catch {
8577
9599
  return;
@@ -8587,11 +9609,11 @@ function recoverStaleDaemonControlFiles(root = process.cwd(), options = {}) {
8587
9609
  const removed = [];
8588
9610
  const connectionReason = staleConnectionFileReason(connectionPath, options.removeUnhealthyConnection ?? false);
8589
9611
  if (connectionReason) {
8590
- rmSync6(connectionPath, { force: true });
9612
+ rmSync7(connectionPath, { force: true });
8591
9613
  removed.push(connectionReason);
8592
9614
  }
8593
- if (existsSync7(lockPath) && isStaleLock(lockPath)) {
8594
- rmSync6(lockPath, { force: true });
9615
+ if (existsSync8(lockPath) && isStaleLock(lockPath)) {
9616
+ rmSync7(lockPath, { force: true });
8595
9617
  removed.push("stale-lock-file");
8596
9618
  }
8597
9619
  return { connectionPath, lockPath, removed };
@@ -8687,7 +9709,7 @@ function createDeveloperReviewRunPaths(input) {
8687
9709
  const runId = `${safeChallengeId}-${randomBytes(6).toString("hex")}`;
8688
9710
  const stateDir = input.stateDir ? resolve11(input.stateDir) : defaultDeveloperReviewRunStateDir(input.sourceRoot);
8689
9711
  const tempParent = input.tempRoot ? resolve11(input.tempRoot) : tmpdir2();
8690
- mkdirSync6(tempParent, { recursive: true });
9712
+ mkdirSync7(tempParent, { recursive: true });
8691
9713
  const runRoot = mkdtempSync3(join6(tempParent, `archctx-developer-review-${safeChallengeId.slice(0, 32)}-`));
8692
9714
  return {
8693
9715
  runId,
@@ -8703,12 +9725,12 @@ function safeControlFileSegment(value) {
8703
9725
  return sanitized.length > 0 ? sanitized : "developer-review";
8704
9726
  }
8705
9727
  function writeDeveloperReviewRunManifest(manifest) {
8706
- writePrivateJson(manifest.manifestPath, manifest);
9728
+ writePrivateJson3(manifest.manifestPath, manifest);
8707
9729
  }
8708
- function writePrivateJson(path, value, flag = "w") {
8709
- mkdirSync6(dirname7(path), { recursive: true });
8710
- writeFileSync3(path, JSON.stringify(value, null, 2), { mode: 384, flag });
8711
- chmodSync(path, 384);
9730
+ function writePrivateJson3(path, value, flag = "w") {
9731
+ mkdirSync7(dirname7(path), { recursive: true });
9732
+ writeFileSync5(path, JSON.stringify(value, null, 2), { mode: 384, flag });
9733
+ chmodSync3(path, 384);
8712
9734
  }
8713
9735
  function readDeveloperReviewRunManifest(path) {
8714
9736
  const parsed = readJsonObject(path);
@@ -8730,7 +9752,7 @@ function readDeveloperReviewRunManifest(path) {
8730
9752
  }
8731
9753
  function readJsonObject(path) {
8732
9754
  try {
8733
- const parsed = JSON.parse(readFileSync6(path, "utf8"));
9755
+ const parsed = JSON.parse(readFileSync8(path, "utf8"));
8734
9756
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined;
8735
9757
  } catch {
8736
9758
  return;
@@ -8739,7 +9761,7 @@ function readJsonObject(path) {
8739
9761
  function isDeveloperReviewPidAlive(pid) {
8740
9762
  if (!pid || pid <= 0)
8741
9763
  return false;
8742
- return isProcessAlive(pid);
9764
+ return isProcessAlive3(pid);
8743
9765
  }
8744
9766
  function cleanupErrorMessage(kind, error) {
8745
9767
  return `${kind}: ${error instanceof Error ? error.message : String(error)}`;
@@ -8750,6 +9772,8 @@ async function createStartedDaemon(deps = {}) {
8750
9772
  return daemon;
8751
9773
  }
8752
9774
  function createProductionDaemon(options = {}) {
9775
+ if (!options.localStorePath)
9776
+ migrateLegacyLocalStoreIfNeeded2(options.root);
8753
9777
  const deps = {
8754
9778
  localStorePath: options.localStorePath ?? defaultLocalStorePath2(options.root),
8755
9779
  maxRepoSessions: options.maxRepoSessions
@@ -8796,15 +9820,15 @@ function blockedProductionInjections(deps) {
8796
9820
  }
8797
9821
  function acquireDaemonLock(lockPath, root) {
8798
9822
  try {
8799
- const fd = openSync4(lockPath, "wx", 384);
8800
- writeFileSync3(fd, JSON.stringify({ pid: process.pid, root, startedAt: new Date().toISOString() }, null, 2), "utf8");
9823
+ const fd = openSync5(lockPath, "wx", 384);
9824
+ writeFileSync5(fd, JSON.stringify({ pid: process.pid, root, startedAt: new Date().toISOString() }, null, 2), "utf8");
8801
9825
  return fd;
8802
9826
  } catch (error) {
8803
9827
  const code = error.code;
8804
9828
  if (code !== "EEXIST")
8805
9829
  throw error;
8806
9830
  if (isStaleLock(lockPath)) {
8807
- rmSync6(lockPath, { force: true });
9831
+ rmSync7(lockPath, { force: true });
8808
9832
  return acquireDaemonLock(lockPath, root);
8809
9833
  }
8810
9834
  throw new Error(`archctxd already running for ${root}; lock=${lockPath}`);
@@ -8814,15 +9838,15 @@ function isValidRuntimeRpcConnection(value) {
8814
9838
  return value.schemaVersion === RUNTIME_RPC_VERSION && value.protocol === "http-loopback" && value.version === 1 && typeof value.url === "string" && value.url.startsWith("http://127.0.0.1:") && typeof value.token === "string" && value.token.length > 0 && typeof value.pid === "number" && typeof value.connectionPath === "string" && typeof value.lockPath === "string";
8815
9839
  }
8816
9840
  function staleConnectionFileReason(path, removeUnhealthyConnection) {
8817
- if (!existsSync7(path))
9841
+ if (!existsSync8(path))
8818
9842
  return;
8819
9843
  try {
8820
9844
  if (!isPrivateControlFile(path))
8821
9845
  return "insecure-connection-file";
8822
- const parsed = JSON.parse(readFileSync6(path, "utf8"));
9846
+ const parsed = JSON.parse(readFileSync8(path, "utf8"));
8823
9847
  if (!isValidRuntimeRpcConnection(parsed))
8824
9848
  return "invalid-connection-file";
8825
- if (!isProcessAlive(parsed.pid))
9849
+ if (!isProcessAlive3(parsed.pid))
8826
9850
  return "dead-connection-pid";
8827
9851
  return removeUnhealthyConnection ? "unhealthy-connection-file" : undefined;
8828
9852
  } catch {
@@ -8837,15 +9861,15 @@ function isPrivateControlFile(path) {
8837
9861
  }
8838
9862
  function isStaleLock(lockPath) {
8839
9863
  try {
8840
- const lock = JSON.parse(readFileSync6(lockPath, "utf8"));
9864
+ const lock = JSON.parse(readFileSync8(lockPath, "utf8"));
8841
9865
  if (typeof lock.pid !== "number" || lock.pid <= 0)
8842
9866
  return true;
8843
- return !isProcessAlive(lock.pid);
9867
+ return !isProcessAlive3(lock.pid);
8844
9868
  } catch {
8845
9869
  return true;
8846
9870
  }
8847
9871
  }
8848
- function isProcessAlive(pid) {
9872
+ function isProcessAlive3(pid) {
8849
9873
  try {
8850
9874
  process.kill(pid, 0);
8851
9875
  return true;
@@ -9031,7 +10055,7 @@ init_src();
9031
10055
 
9032
10056
  // packages/local-runtime/runtime-daemon/src/index.ts
9033
10057
  import { randomBytes as randomBytes2 } from "node:crypto";
9034
- import { chmodSync as chmodSync2, closeSync as closeSync5, existsSync as existsSync8, mkdirSync as mkdirSync7, mkdtempSync as mkdtempSync4, openSync as openSync5, readdirSync as readdirSync6, readFileSync as readFileSync7, rmSync as rmSync7, statSync as statSync5, writeFileSync as writeFileSync4 } from "node:fs";
10058
+ import { chmodSync as chmodSync4, closeSync as closeSync6, existsSync as existsSync9, mkdirSync as mkdirSync8, mkdtempSync as mkdtempSync4, openSync as openSync6, readdirSync as readdirSync6, readFileSync as readFileSync9, rmSync as rmSync8, statSync as statSync5, writeFileSync as writeFileSync6 } from "node:fs";
9035
10059
  import { createServer as createServer2 } from "node:http";
9036
10060
  import { tmpdir as tmpdir3 } from "node:os";
9037
10061
  import { dirname as dirname8, join as join7, resolve as resolve12 } from "node:path";
@@ -9238,9 +10262,9 @@ class ArchctxDaemon2 {
9238
10262
  tempRoot: input.tempRoot,
9239
10263
  stateDir: input.stateDir
9240
10264
  });
9241
- mkdirSync7(paths.stateDir, { recursive: true });
9242
- mkdirSync7(paths.runRoot, { recursive: true });
9243
- mkdirSync7(paths.worktreeTempRoot, { recursive: true });
10265
+ mkdirSync8(paths.stateDir, { recursive: true });
10266
+ mkdirSync8(paths.runRoot, { recursive: true });
10267
+ mkdirSync8(paths.worktreeTempRoot, { recursive: true });
9244
10268
  const preparing = {
9245
10269
  schemaVersion: "archcontext.developer-review-run/v1",
9246
10270
  runId: paths.runId,
@@ -9259,13 +10283,13 @@ class ArchctxDaemon2 {
9259
10283
  cleanup: "remove-run-root"
9260
10284
  }
9261
10285
  };
9262
- if (existsSync8(paths.lockPath) || existsSync8(paths.manifestPath)) {
9263
- rmSync7(paths.runRoot, { recursive: true, force: true });
10286
+ if (existsSync9(paths.lockPath) || existsSync9(paths.manifestPath)) {
10287
+ rmSync8(paths.runRoot, { recursive: true, force: true });
9264
10288
  throw new Error(`developer-review-run-already-active: ${input.challenge.challengeId}`);
9265
10289
  }
9266
10290
  let lockAcquired = false;
9267
10291
  try {
9268
- writePrivateJson2(paths.lockPath, {
10292
+ writePrivateJson4(paths.lockPath, {
9269
10293
  schemaVersion: "archcontext.developer-review-run-lock/v1",
9270
10294
  runId: paths.runId,
9271
10295
  challengeId: input.challenge.challengeId,
@@ -9295,7 +10319,7 @@ class ArchctxDaemon2 {
9295
10319
  if (lockAcquired) {
9296
10320
  this.cleanupDeveloperReviewRun(preparing);
9297
10321
  } else {
9298
- rmSync7(paths.runRoot, { recursive: true, force: true });
10322
+ rmSync8(paths.runRoot, { recursive: true, force: true });
9299
10323
  }
9300
10324
  throw error;
9301
10325
  }
@@ -9316,7 +10340,7 @@ class ArchctxDaemon2 {
9316
10340
  const errors = [];
9317
10341
  if (run.worktree) {
9318
10342
  try {
9319
- const hadWorktree = existsSync8(run.worktree.worktreeRoot);
10343
+ const hadWorktree = existsSync9(run.worktree.worktreeRoot);
9320
10344
  removeDetachedReviewWorktree(run.worktree);
9321
10345
  if (hadWorktree)
9322
10346
  removed.push("worktree");
@@ -9330,8 +10354,8 @@ class ArchctxDaemon2 {
9330
10354
  ["lock", run.lockPath]
9331
10355
  ]) {
9332
10356
  try {
9333
- const existed = existsSync8(path);
9334
- rmSync7(path, { recursive: true, force: true });
10357
+ const existed = existsSync9(path);
10358
+ rmSync8(path, { recursive: true, force: true });
9335
10359
  if (existed)
9336
10360
  removed.push(kind);
9337
10361
  } catch (error) {
@@ -9359,7 +10383,7 @@ class ArchctxDaemon2 {
9359
10383
  removedLocks: [],
9360
10384
  skippedActive: []
9361
10385
  };
9362
- if (!existsSync8(stateDir))
10386
+ if (!existsSync9(stateDir))
9363
10387
  return recovery;
9364
10388
  for (const entry of readdirSync6(stateDir).sort()) {
9365
10389
  if (!entry.endsWith(".json"))
@@ -9367,7 +10391,7 @@ class ArchctxDaemon2 {
9367
10391
  const manifestPath = join7(stateDir, entry);
9368
10392
  const manifest = readDeveloperReviewRunManifest2(manifestPath);
9369
10393
  if (!manifest) {
9370
- rmSync7(manifestPath, { force: true });
10394
+ rmSync8(manifestPath, { force: true });
9371
10395
  continue;
9372
10396
  }
9373
10397
  if (!input.force && isDeveloperReviewPidAlive2(manifest.pid)) {
@@ -9387,7 +10411,7 @@ class ArchctxDaemon2 {
9387
10411
  recovery.skippedActive.push(runId);
9388
10412
  continue;
9389
10413
  }
9390
- rmSync7(lockPath, { force: true });
10414
+ rmSync8(lockPath, { force: true });
9391
10415
  recovery.removedLocks.push(lockPath);
9392
10416
  }
9393
10417
  return recovery;
@@ -9680,7 +10704,7 @@ class ArchctxDaemon2 {
9680
10704
  const status = this.status();
9681
10705
  if (!root)
9682
10706
  return okEnvelope("status", status);
9683
- const repositoryId = repositoryFingerprint(root);
10707
+ const repositoryId = repositoryFingerprint2(root);
9684
10708
  const session = this.sessions.get(repositoryId);
9685
10709
  return okEnvelope("status", {
9686
10710
  ...status,
@@ -9727,9 +10751,9 @@ class ArchctxDaemon2 {
9727
10751
  }
9728
10752
  async restoreRepositorySessions() {
9729
10753
  for (const record of await this.localStore.listRepositorySessions()) {
9730
- if (!record.root || !existsSync8(record.root))
10754
+ if (!record.root || !existsSync9(record.root))
9731
10755
  continue;
9732
- if (repositoryFingerprint(record.root) !== record.repositoryId)
10756
+ if (repositoryFingerprint2(record.root) !== record.repositoryId)
9733
10757
  continue;
9734
10758
  this.sessions.set(record.repositoryId, {
9735
10759
  workspace: {
@@ -9996,14 +11020,11 @@ class RuntimeRpcClient2 {
9996
11020
  return await response.json();
9997
11021
  }
9998
11022
  }
9999
- function defaultDaemonControlDir2(root = process.cwd()) {
10000
- return join7(root, ".archcontext", ".local");
10001
- }
10002
11023
  function defaultDeveloperReviewRunStateDir2(root = process.cwd()) {
10003
- return join7(defaultDaemonControlDir2(root), "developer-review-runs");
11024
+ return runtimeStatePaths2(root).developerReviewRunStateDir;
10004
11025
  }
10005
11026
  function defaultDaemonConnectionPath2(root = process.cwd()) {
10006
- return join7(defaultDaemonControlDir2(root), "archctxd.json");
11027
+ return runtimeStatePaths2(root).daemonConnectionPath;
10007
11028
  }
10008
11029
  function unwrapRpcData2(result) {
10009
11030
  if (!result.ok)
@@ -10015,7 +11036,7 @@ function readRuntimeRpcConnection2(root = process.cwd()) {
10015
11036
  try {
10016
11037
  if (!isPrivateControlFile2(path))
10017
11038
  return;
10018
- const parsed = JSON.parse(readFileSync7(path, "utf8"));
11039
+ const parsed = JSON.parse(readFileSync9(path, "utf8"));
10019
11040
  return isValidRuntimeRpcConnection2(parsed) ? parsed : undefined;
10020
11041
  } catch {
10021
11042
  return;
@@ -10116,7 +11137,7 @@ function createDeveloperReviewRunPaths2(input) {
10116
11137
  const runId = `${safeChallengeId}-${randomBytes2(6).toString("hex")}`;
10117
11138
  const stateDir = input.stateDir ? resolve12(input.stateDir) : defaultDeveloperReviewRunStateDir2(input.sourceRoot);
10118
11139
  const tempParent = input.tempRoot ? resolve12(input.tempRoot) : tmpdir3();
10119
- mkdirSync7(tempParent, { recursive: true });
11140
+ mkdirSync8(tempParent, { recursive: true });
10120
11141
  const runRoot = mkdtempSync4(join7(tempParent, `archctx-developer-review-${safeChallengeId.slice(0, 32)}-`));
10121
11142
  return {
10122
11143
  runId,
@@ -10132,12 +11153,12 @@ function safeControlFileSegment2(value) {
10132
11153
  return sanitized.length > 0 ? sanitized : "developer-review";
10133
11154
  }
10134
11155
  function writeDeveloperReviewRunManifest2(manifest) {
10135
- writePrivateJson2(manifest.manifestPath, manifest);
11156
+ writePrivateJson4(manifest.manifestPath, manifest);
10136
11157
  }
10137
- function writePrivateJson2(path, value, flag = "w") {
10138
- mkdirSync7(dirname8(path), { recursive: true });
10139
- writeFileSync4(path, JSON.stringify(value, null, 2), { mode: 384, flag });
10140
- chmodSync2(path, 384);
11158
+ function writePrivateJson4(path, value, flag = "w") {
11159
+ mkdirSync8(dirname8(path), { recursive: true });
11160
+ writeFileSync6(path, JSON.stringify(value, null, 2), { mode: 384, flag });
11161
+ chmodSync4(path, 384);
10141
11162
  }
10142
11163
  function readDeveloperReviewRunManifest2(path) {
10143
11164
  const parsed = readJsonObject2(path);
@@ -10159,7 +11180,7 @@ function readDeveloperReviewRunManifest2(path) {
10159
11180
  }
10160
11181
  function readJsonObject2(path) {
10161
11182
  try {
10162
- const parsed = JSON.parse(readFileSync7(path, "utf8"));
11183
+ const parsed = JSON.parse(readFileSync9(path, "utf8"));
10163
11184
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : undefined;
10164
11185
  } catch {
10165
11186
  return;
@@ -10168,7 +11189,7 @@ function readJsonObject2(path) {
10168
11189
  function isDeveloperReviewPidAlive2(pid) {
10169
11190
  if (!pid || pid <= 0)
10170
11191
  return false;
10171
- return isProcessAlive2(pid);
11192
+ return isProcessAlive4(pid);
10172
11193
  }
10173
11194
  function cleanupErrorMessage2(kind, error) {
10174
11195
  return `${kind}: ${error instanceof Error ? error.message : String(error)}`;
@@ -10214,7 +11235,7 @@ function isPrivateControlFile2(path) {
10214
11235
  const mode = statSync5(path).mode & 511;
10215
11236
  return (mode & 63) === 0;
10216
11237
  }
10217
- function isProcessAlive2(pid) {
11238
+ function isProcessAlive4(pid) {
10218
11239
  try {
10219
11240
  process.kill(pid, 0);
10220
11241
  return true;
@@ -10401,7 +11422,7 @@ async function runStdioMcpLoop(input, output, log = (line) => process.stderr.wri
10401
11422
 
10402
11423
  // packages/surfaces/renderer/src/index.ts
10403
11424
  init_src();
10404
- import { existsSync as existsSync9, readdirSync as readdirSync7, readFileSync as readFileSync8 } from "node:fs";
11425
+ import { existsSync as existsSync10, readdirSync as readdirSync7, readFileSync as readFileSync10 } from "node:fs";
10405
11426
  import { resolve as resolve13 } from "node:path";
10406
11427
  function normalizeNativeModel2(model) {
10407
11428
  return {
@@ -10437,9 +11458,9 @@ function mermaidId(id) {
10437
11458
  return stableId(id).replace(/-/g, "_").replace(/\./g, "_");
10438
11459
  }
10439
11460
  function readYamlObjects(dir) {
10440
- if (!existsSync9(dir))
11461
+ if (!existsSync10(dir))
10441
11462
  return [];
10442
- return readdirSync7(dir).filter((file) => /\.ya?ml$/.test(file)).sort().map((file) => parseFlatYaml(readFileSync8(resolve13(dir, file), "utf8")));
11463
+ return readdirSync7(dir).filter((file) => /\.ya?ml$/.test(file)).sort().map((file) => parseFlatYaml(readFileSync10(resolve13(dir, file), "utf8")));
10443
11464
  }
10444
11465
  function parseFlatYaml(body) {
10445
11466
  const out = {};
@@ -10464,7 +11485,7 @@ function escapeMermaid(value) {
10464
11485
  // packages/surfaces/cli/src/main.ts
10465
11486
  var [, , command, ...args] = process.argv;
10466
11487
  var CLI_ENTRY = fileURLToPath(import.meta.url);
10467
- var DAEMON_START_TIMEOUT_MS = 5000;
11488
+ var DAEMON_START_TIMEOUT_MS = 15000;
10468
11489
 
10469
11490
  class RuntimeVersionUnsupportedError extends Error {
10470
11491
  issue;
@@ -10679,6 +11700,8 @@ async function runCliUnchecked(command2 = "help", args2 = [], cwd, deps = {}) {
10679
11700
  };
10680
11701
  case "doctor":
10681
11702
  return { schemaVersion: "archcontext.envelope/v1", ok: true, requestId: "doctor", data: await doctorReport(cwd) };
11703
+ case "paths":
11704
+ return { schemaVersion: "archcontext.envelope/v1", ok: true, requestId: "paths", data: runtimePathsReport(cwd) };
10682
11705
  case "privacy-audit":
10683
11706
  return {
10684
11707
  schemaVersion: "archcontext.envelope/v1",
@@ -10724,8 +11747,8 @@ async function runCliUnchecked(command2 = "help", args2 = [], cwd, deps = {}) {
10724
11747
  ok: true,
10725
11748
  requestId: "help",
10726
11749
  data: {
10727
- commands: ["init", "sync", "validate", "context", "status", "daemon", "repo", "landscape", "explore", "prepare", "checkpoint", "plan", "apply", "review", "complete", "github", "config", "mcp", "install", "uninstall", "doctor", "privacy-audit", "export", "import", "tunnel"],
10728
- examples: ["archctx init --name MyApp", "archctx github connect", "archctx github status", "archctx daemon start", "archctx explore start --foreground", "archctx export likec4", "archctx import structurizr --content '<json>'", "archctx tunnel"]
11750
+ commands: ["init", "sync", "validate", "context", "status", "daemon", "repo", "landscape", "explore", "prepare", "checkpoint", "plan", "apply", "review", "complete", "github", "config", "mcp", "install", "uninstall", "doctor", "paths", "privacy-audit", "export", "import", "tunnel"],
11751
+ examples: ["archctx init --name MyApp", "archctx paths", "archctx github connect", "archctx github status", "archctx daemon start", "archctx explore start --foreground", "archctx export likec4", "archctx import structurizr --content '<json>'", "archctx tunnel"]
10729
11752
  }
10730
11753
  };
10731
11754
  }
@@ -10811,7 +11834,7 @@ async function runGithubCommand(args2, cwd, deps) {
10811
11834
  tokenStore.clear(record.codeVerifierRef);
10812
11835
  tokenStore.clear(record.refreshTokenRef);
10813
11836
  keyStore.removeDevicePrivateKey(record.deviceKey.keyRef);
10814
- rmSync8(connectionPath, { force: true });
11837
+ rmSync9(connectionPath, { force: true });
10815
11838
  return okEnvelope("github.disconnect", {
10816
11839
  disconnected: true,
10817
11840
  connected: false,
@@ -11094,20 +12117,20 @@ function defaultGithubDeveloperReviewStatePath(cwd, pullRequestNumber) {
11094
12117
  }
11095
12118
  async function writeGithubDeveloperReviewState(cwd, state) {
11096
12119
  const path = defaultGithubDeveloperReviewStatePath(cwd, state.challenge.pullRequestNumber);
11097
- mkdirSync8(dirname9(path), { recursive: true });
12120
+ mkdirSync9(dirname9(path), { recursive: true });
11098
12121
  const serialized = `${JSON.stringify(state, null, 2)}
11099
12122
  `;
11100
12123
  assertNoCliSecretMaterial(serialized);
11101
- writeFileSync5(path, serialized, { mode: 384 });
12124
+ writeFileSync7(path, serialized, { mode: 384 });
11102
12125
  if (process.platform !== "win32")
11103
- chmodSync3(path, 384);
12126
+ chmodSync5(path, 384);
11104
12127
  return { state, path };
11105
12128
  }
11106
12129
  function readGithubDeveloperReviewState(path) {
11107
- if (!existsSync10(path))
12130
+ if (!existsSync11(path))
11108
12131
  return;
11109
12132
  try {
11110
- const parsed = JSON.parse(readFileSync9(path, "utf8"));
12133
+ const parsed = JSON.parse(readFileSync11(path, "utf8"));
11111
12134
  if (parsed.schemaVersion !== "archcontext.github-developer-review-state/v1")
11112
12135
  return;
11113
12136
  if (!parsed.challenge || typeof parsed.challenge.pullRequestNumber !== "number")
@@ -11156,10 +12179,10 @@ function defaultGithubConnectionPath(cwd) {
11156
12179
  return join8(dirname9(defaultDaemonConnectionPath(cwd)), "github-connection.json");
11157
12180
  }
11158
12181
  function readGithubConnection(path) {
11159
- if (!existsSync10(path))
12182
+ if (!existsSync11(path))
11160
12183
  return;
11161
12184
  try {
11162
- const parsed = JSON.parse(readFileSync9(path, "utf8"));
12185
+ const parsed = JSON.parse(readFileSync11(path, "utf8"));
11163
12186
  if (parsed.schemaVersion !== "archcontext.github-connection/v1" || parsed.status !== "connected")
11164
12187
  return;
11165
12188
  return parsed;
@@ -11168,13 +12191,13 @@ function readGithubConnection(path) {
11168
12191
  }
11169
12192
  }
11170
12193
  function writeGithubConnection(path, record) {
11171
- mkdirSync8(dirname9(path), { recursive: true });
12194
+ mkdirSync9(dirname9(path), { recursive: true });
11172
12195
  const serialized = `${JSON.stringify(record, null, 2)}
11173
12196
  `;
11174
12197
  assertNoCliSecretMaterial(serialized);
11175
- writeFileSync5(path, serialized, { mode: 384 });
12198
+ writeFileSync7(path, serialized, { mode: 384 });
11176
12199
  if (process.platform !== "win32")
11177
- chmodSync3(path, 384);
12200
+ chmodSync5(path, 384);
11178
12201
  }
11179
12202
  function sanitizeGithubConnection(record, connectionPath) {
11180
12203
  return {
@@ -11203,7 +12226,7 @@ async function readReviewChallengeV2Arg(args2, cwd, commandName = "github verify
11203
12226
  if (!inline && !challengePath)
11204
12227
  return { ok: false, message: `${commandName} requires --challenge-json or --challenge-path` };
11205
12228
  try {
11206
- const raw = inline ?? readFileSync9(resolve14(cwd, challengePath), "utf8");
12229
+ const raw = inline ?? readFileSync11(resolve14(cwd, challengePath), "utf8");
11207
12230
  const parsed = JSON.parse(raw);
11208
12231
  const attestation = await Promise.resolve().then(() => (init_src7(), exports_src3));
11209
12232
  const assertReviewChallengeV23 = attestation.assertReviewChallengeV2;
@@ -11286,6 +12309,7 @@ function agentHostRemoveConfig(host) {
11286
12309
  }
11287
12310
  async function doctorReport(cwd) {
11288
12311
  const product = productVersionManifest();
12312
+ const paths = runtimePathsReport(cwd);
11289
12313
  const daemon = await doctorDaemon(cwd);
11290
12314
  const git = doctorGit(cwd);
11291
12315
  const sqlite = doctorSqlite(cwd);
@@ -11303,6 +12327,7 @@ async function doctorReport(cwd) {
11303
12327
  },
11304
12328
  daemon,
11305
12329
  sqlite,
12330
+ paths,
11306
12331
  codeGraph: product.runtime.codeGraph,
11307
12332
  git,
11308
12333
  permissions,
@@ -11350,23 +12375,46 @@ function doctorGit(cwd) {
11350
12375
  }
11351
12376
  }
11352
12377
  function doctorSqlite(cwd) {
11353
- const path = defaultLocalStorePath(cwd);
12378
+ const paths = runtimeStatePaths(cwd);
12379
+ const path = paths.localStorePath;
12380
+ const legacyLocalStore = inspectLegacyLocalStoreMigration(cwd);
11354
12381
  return {
11355
12382
  path,
11356
- exists: existsSync10(path),
11357
- migrations: productVersionManifest().runtime.sqliteMigrations
12383
+ exists: existsSync11(path),
12384
+ migrations: productVersionManifest().runtime.sqliteMigrations,
12385
+ legacyPath: paths.legacyLocalStorePath,
12386
+ legacyExists: existsSync11(paths.legacyLocalStorePath),
12387
+ legacyLocalStore
11358
12388
  };
11359
12389
  }
11360
12390
  function doctorPermissions(cwd) {
12391
+ const paths = runtimeStatePaths(cwd);
11361
12392
  const controlDir = dirname9(defaultDaemonConnectionPath(cwd));
11362
12393
  return {
11363
12394
  workspace: pathAccess(cwd),
12395
+ stateRoot: pathAccess(paths.stateRoot),
12396
+ runtimeStateDir: pathAccess(paths.workspaceStateDir),
11364
12397
  controlDir: pathAccess(controlDir),
11365
12398
  sqlite: pathAccess(defaultLocalStorePath(cwd))
11366
12399
  };
11367
12400
  }
12401
+ function runtimePathsReport(cwd) {
12402
+ const paths = runtimeStatePaths(cwd);
12403
+ return {
12404
+ ...paths,
12405
+ legacyLocalStore: inspectLegacyLocalStoreMigration(cwd),
12406
+ runtimeRepositoryId: repositoryFingerprint(paths.repositoryRoot),
12407
+ repositoryTruthDir: join8(paths.repositoryRoot, ".archcontext"),
12408
+ codeGraphIndexDir: join8(paths.repositoryRoot, ".codegraph"),
12409
+ npmGlobalInstallState: "forbidden",
12410
+ overrides: {
12411
+ stateRootEnv: "ARCHCONTEXT_STATE_DIR",
12412
+ localStorePathEnv: "ARCHCONTEXT_LOCAL_STORE_PATH"
12413
+ }
12414
+ };
12415
+ }
11368
12416
  function pathAccess(path) {
11369
- const exists = existsSync10(path);
12417
+ const exists = existsSync11(path);
11370
12418
  return {
11371
12419
  path,
11372
12420
  exists,
@@ -11442,6 +12490,8 @@ async function createCliRuntime(cwd, deps) {
11442
12490
  githubReviewSubmissionPort: _githubReviewSubmissionPort,
11443
12491
  ...runtimeDeps
11444
12492
  } = deps;
12493
+ if (!runtimeDeps.localStorePath)
12494
+ migrateLegacyLocalStoreIfNeeded(cwd);
11445
12495
  const daemon = await createStartedDaemon({
11446
12496
  localStorePath: defaultLocalStorePath(cwd),
11447
12497
  ...runtimeDeps,
@@ -11544,8 +12594,8 @@ async function startBackgroundDaemon(args2, cwd) {
11544
12594
  const connectionPath = defaultDaemonConnectionPath(cwd);
11545
12595
  const controlDir = dirname9(connectionPath);
11546
12596
  const logPath = join8(controlDir, "archctxd.log");
11547
- mkdirSync8(controlDir, { recursive: true });
11548
- const logFd = openSync6(logPath, "a", 384);
12597
+ mkdirSync9(controlDir, { recursive: true });
12598
+ const logFd = openSync7(logPath, "a", 384);
11549
12599
  try {
11550
12600
  const child = spawn(process.execPath, [
11551
12601
  CLI_ENTRY,
@@ -11563,7 +12613,7 @@ async function startBackgroundDaemon(args2, cwd) {
11563
12613
  child.unref();
11564
12614
  const ready = await waitForDaemonReady(cwd, Number(readFlag(args2, "--timeout-ms") ?? DAEMON_START_TIMEOUT_MS));
11565
12615
  if (!ready) {
11566
- return errorEnvelope("daemon.start", "AC_RUNTIME_UNAVAILABLE", `archctxd did not become ready; log=${logPath}`);
12616
+ return errorEnvelope("daemon.start", "AC_RUNTIME_UNAVAILABLE", `archctxd did not become ready; log=${logPath}; logTail=${readFileTail(logPath)}`);
11567
12617
  }
11568
12618
  return okEnvelope("daemon.start", {
11569
12619
  running: true,
@@ -11575,7 +12625,7 @@ async function startBackgroundDaemon(args2, cwd) {
11575
12625
  ...recoveryData(recovery)
11576
12626
  });
11577
12627
  } finally {
11578
- closeSync6(logFd);
12628
+ closeSync7(logFd);
11579
12629
  }
11580
12630
  }
11581
12631
  async function upgradeDaemon(args2, cwd) {
@@ -11712,8 +12762,16 @@ async function waitForDaemonReady(cwd, timeoutMs) {
11712
12762
  function sleep(ms) {
11713
12763
  return new Promise((resolve15) => setTimeout(resolve15, ms));
11714
12764
  }
12765
+ function readFileTail(path, maxBytes = 4096) {
12766
+ try {
12767
+ const content = readFileSync11(path, "utf8");
12768
+ return content.slice(Math.max(0, content.length - maxBytes)).replace(/\s+/g, " ").trim();
12769
+ } catch {
12770
+ return "<unavailable>";
12771
+ }
12772
+ }
11715
12773
  async function runForegroundDaemon(cwd, args2) {
11716
- const daemon = await createStartedProductionDaemon({ root: cwd, localStorePath: defaultLocalStorePath(cwd) });
12774
+ const daemon = await createStartedProductionDaemon({ root: cwd });
11717
12775
  let resolveStopped;
11718
12776
  const stopped = new Promise((resolve15) => {
11719
12777
  resolveStopped = resolve15;