archctx 0.7.1 → 0.7.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "archcontext.practice-catalog-manifest/v1",
3
3
  "catalogVersion": "2026.06.0",
4
- "productVersion": "0.7.1",
4
+ "productVersion": "0.7.2",
5
5
  "generatedAt": "1970-01-01T00:00:00.000Z",
6
6
  "entries": [
7
7
  {
@@ -389,5 +389,5 @@
389
389
  "structurizr.dsl",
390
390
  "twelve-factor"
391
391
  ],
392
- "catalogDigest": "sha256:09f15d17439ef2ef12ec5eede5244505e7cdb124628657c7df640e8a049e7cb7"
392
+ "catalogDigest": "sha256:b5dd0791d81dae183a03d5ea53e18645d6d7eb8a89ea2540fabd3547a5454536"
393
393
  }
package/bin/archctx.mjs CHANGED
@@ -1869,7 +1869,7 @@ function productVersionManifest() {
1869
1869
  }
1870
1870
  };
1871
1871
  }
1872
- var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.7.1", ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.3", ARCHCONTEXT_NODE_RANGE = ">=22.22 <26", LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1", ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";
1872
+ var ARCHCONTEXT_PRODUCT_NAME = "archctx", ARCHCONTEXT_PRODUCT_VERSION = "0.7.2", ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.3", ARCHCONTEXT_NODE_RANGE = ">=22.22 <26", LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1", ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";
1873
1873
 
1874
1874
  // packages/contracts/src/refactor.ts
1875
1875
  function refactorProposalDigest(proposal) {
@@ -32792,6 +32792,17 @@ function acquireDaemonLock(lockPath, root) {
32792
32792
  throw new Error(`archctxd already running for ${root}; lock=${lockPath}`);
32793
32793
  }
32794
32794
  }
32795
+ function liveDaemonLockOwnerPid(root = process.cwd()) {
32796
+ try {
32797
+ const body = readPrivateControlFile(defaultDaemonLockPath(root));
32798
+ if (body === undefined)
32799
+ return;
32800
+ const pid = JSON.parse(body).pid;
32801
+ return typeof pid === "number" && pid > 0 && isProcessAlive(pid) ? pid : undefined;
32802
+ } catch {
32803
+ return;
32804
+ }
32805
+ }
32795
32806
  function isValidRuntimeRpcConnection(value) {
32796
32807
  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";
32797
32808
  }
@@ -42695,6 +42706,9 @@ function runNodeInvestigationTransport(input, options) {
42695
42706
  child.once("exit", (code) => {
42696
42707
  settleResolve(unwrapClaudeCodeEnvelope(code ?? 1, stdout, stderr));
42697
42708
  });
42709
+ child.stdin?.on("error", () => {
42710
+ return;
42711
+ });
42698
42712
  child.stdin?.end(input.stdin);
42699
42713
  });
42700
42714
  }
@@ -51830,7 +51844,6 @@ function completeTaskProjectionFreshness(root) {
51830
51844
  currentSourceTreeDigest: architectureDocumentationSourceTreeDigest(root, model, sourceFiles)
51831
51845
  });
51832
51846
  }
51833
-
51834
51847
  // packages/surfaces/adapter-likec4/src/index.ts
51835
51848
  init_src();
51836
51849
  function exportLikeC4Model(model) {
@@ -55202,14 +55215,14 @@ async function createOrStartRuntimeRpcClient(cwd) {
55202
55215
  throw new RuntimeVersionUnsupportedError(fileIssue);
55203
55216
  const client = createRuntimeRpcClientFromConnectionFile(cwd);
55204
55217
  if (client) {
55205
- const health = await client.health().catch(() => {
55206
- return;
55207
- });
55218
+ const { health, unresponsivePid } = await probeDaemonHealth(client);
55208
55219
  const healthIssue = runtimeRpcCompatibilityIssueFromHealth(cwd, client, health);
55209
55220
  if (healthIssue)
55210
55221
  throw new RuntimeVersionUnsupportedError(healthIssue);
55211
55222
  if (health?.ok === true)
55212
55223
  return client;
55224
+ if (unresponsivePid !== undefined)
55225
+ throw new Error(unresponsiveDaemonMessage(unresponsivePid));
55213
55226
  recoverStaleDaemonControlFiles(cwd, { removeUnhealthyConnection: true });
55214
55227
  } else {
55215
55228
  recoverStaleDaemonControlFiles(cwd);
@@ -55291,16 +55304,16 @@ async function runDaemonCommand(args, cwd) {
55291
55304
  return okEnvelope("daemon.status", incompatibleDaemonStatus(compatibilityIssue));
55292
55305
  }
55293
55306
  const recovery = recoverStaleDaemonControlFiles(cwd);
55307
+ const lockOwnerPid = liveDaemonLockOwnerPid(cwd);
55294
55308
  return okEnvelope("daemon.status", {
55295
55309
  running: false,
55296
55310
  protocol: "http-loopback",
55297
55311
  connectionPath: defaultDaemonConnectionPath(cwd),
55312
+ ...lockOwnerPid === undefined ? {} : { lockOwnerPid, action: orphanedDaemonMessage(lockOwnerPid) },
55298
55313
  ...recoveryData(recovery)
55299
55314
  });
55300
55315
  }
55301
- const health = await client.health().catch(() => {
55302
- return;
55303
- });
55316
+ const { health, unresponsivePid } = await probeDaemonHealth(client);
55304
55317
  const healthIssue = runtimeRpcCompatibilityIssueFromHealth(cwd, client, health);
55305
55318
  if (healthIssue) {
55306
55319
  return okEnvelope("daemon.status", incompatibleDaemonStatus(healthIssue));
@@ -55319,6 +55332,16 @@ async function runDaemonCommand(args, cwd) {
55319
55332
  token: "stored-in-connection-file"
55320
55333
  });
55321
55334
  }
55335
+ if (unresponsivePid !== undefined) {
55336
+ return okEnvelope("daemon.status", {
55337
+ running: true,
55338
+ responding: false,
55339
+ pid: unresponsivePid,
55340
+ protocol: "http-loopback",
55341
+ connectionPath: client.connectionInfo().connectionPath,
55342
+ action: unresponsiveDaemonMessage(unresponsivePid)
55343
+ });
55344
+ }
55322
55345
  const recovery = recoverStaleDaemonControlFiles(cwd, { removeUnhealthyConnection: true });
55323
55346
  return okEnvelope("daemon.status", {
55324
55347
  running: false,
@@ -55358,6 +55381,9 @@ async function startBackgroundDaemon(args, cwd) {
55358
55381
  if (discovered.compatibilityIssue?.pidAlive) {
55359
55382
  return errorEnvelope("daemon.start", "AC_RUNTIME_VERSION_UNSUPPORTED", runtimeVersionUnsupportedMessage(discovered.compatibilityIssue));
55360
55383
  }
55384
+ if (discovered.unresponsivePid !== undefined) {
55385
+ return errorEnvelope("daemon.start", "AC_RUNTIME_UNAVAILABLE", unresponsiveDaemonMessage(discovered.unresponsivePid));
55386
+ }
55361
55387
  if (discovered.info) {
55362
55388
  return okEnvelope("daemon.start", {
55363
55389
  running: true,
@@ -55399,7 +55425,7 @@ async function startBackgroundDaemon(args, cwd) {
55399
55425
  child.unref();
55400
55426
  const ready = await waitForDaemonReady(cwd, daemonStartTimeoutMs(args), () => childError !== undefined || childExit !== undefined && childExit.code !== DAEMON_OWNED_ELSEWHERE_EXIT_CODE);
55401
55427
  if (!ready) {
55402
- return errorEnvelope("daemon.start", "AC_RUNTIME_UNAVAILABLE", daemonStartFailureMessage(logPath, childExit, childError));
55428
+ return errorEnvelope("daemon.start", "AC_RUNTIME_UNAVAILABLE", daemonStartFailureMessage(cwd, logPath, child.pid, childExit, childError));
55403
55429
  }
55404
55430
  return okEnvelope("daemon.start", {
55405
55431
  running: true,
@@ -55469,9 +55495,7 @@ async function discoverRunningDaemonInfo(cwd, options = {}) {
55469
55495
  recovery: options.recoverStale ? recoverStaleDaemonControlFiles(cwd) : emptyRecovery(cwd)
55470
55496
  };
55471
55497
  }
55472
- const health = await client.health().catch(() => {
55473
- return;
55474
- });
55498
+ const { health, unresponsivePid } = await probeDaemonHealth(client);
55475
55499
  const compatibilityIssue = runtimeRpcCompatibilityIssueFromHealth(cwd, client, health) ?? cliEntryStalenessIssue(cwd);
55476
55500
  if (compatibilityIssue) {
55477
55501
  return {
@@ -55483,6 +55507,9 @@ async function discoverRunningDaemonInfo(cwd, options = {}) {
55483
55507
  if (health?.ok === true) {
55484
55508
  return { info: client.connectionInfo(), compatibilityIssue: undefined, recovery: emptyRecovery(cwd) };
55485
55509
  }
55510
+ if (unresponsivePid !== undefined) {
55511
+ return { info: undefined, compatibilityIssue: undefined, unresponsivePid, recovery: emptyRecovery(cwd) };
55512
+ }
55486
55513
  return {
55487
55514
  info: undefined,
55488
55515
  compatibilityIssue: undefined,
@@ -55548,6 +55575,24 @@ function runtimeVersionUnsupportedMessage(issue) {
55548
55575
  }
55549
55576
  return `archctxd RPC version ${issue.received} is incompatible with this CLI (${issue.expected}); run ${issue.upgradeCommand} to replace the local daemon.`;
55550
55577
  }
55578
+ async function probeDaemonHealth(client) {
55579
+ try {
55580
+ return { health: await client.health() };
55581
+ } catch (error) {
55582
+ const pid = client.connectionInfo().pid;
55583
+ const busy = error instanceof RuntimeRpcTransportError && error.code === "RPC_TIMEOUT" && typeof pid === "number" && isPidAlive(pid);
55584
+ return { health: undefined, ...busy ? { unresponsivePid: pid } : {} };
55585
+ }
55586
+ }
55587
+ function stopProcessCommand(pid) {
55588
+ return process.platform === "win32" ? `taskkill /PID ${pid}` : `kill -TERM ${pid}`;
55589
+ }
55590
+ function unresponsiveDaemonMessage(pid) {
55591
+ return `archctxd pid ${pid} is alive but did not answer its health check in time; it is likely busy, so its connection file was kept. Retry later, or stop it with \`${stopProcessCommand(pid)}\` and run the command again.`;
55592
+ }
55593
+ function orphanedDaemonMessage(pid) {
55594
+ return `the daemon lock names live pid ${pid}, but no connection file points to it; stop it with \`${stopProcessCommand(pid)}\`, then run the command again.`;
55595
+ }
55551
55596
  async function waitForPidExit(pid, timeoutMs) {
55552
55597
  const deadline = Date.now() + timeoutMs;
55553
55598
  while (Date.now() < deadline) {
@@ -55582,9 +55627,11 @@ function daemonStartTimeoutMs(args) {
55582
55627
  const parsed = Number(configured);
55583
55628
  return Number.isFinite(parsed) && parsed > 0 ? parsed : DAEMON_START_TIMEOUT_MS;
55584
55629
  }
55585
- function daemonStartFailureMessage(logPath, childExit, childError) {
55630
+ function daemonStartFailureMessage(cwd, logPath, childPid, childExit, childError) {
55586
55631
  const childState = childError ? `childError=${childError.message}` : childExit ? `childExit=${childExit.code ?? "null"}/${childExit.signal ?? "none"}` : "childState=still-running";
55587
- return `archctxd did not become ready; ${childState}; log=${logPath}; logTail=${readFileTail(logPath)}`;
55632
+ const lockOwnerPid = existsSync28(defaultDaemonConnectionPath(cwd)) ? undefined : liveDaemonLockOwnerPid(cwd);
55633
+ const owner = lockOwnerPid === undefined || lockOwnerPid === childPid ? "" : `; ${orphanedDaemonMessage(lockOwnerPid)}`;
55634
+ return `archctxd did not become ready; ${childState}${owner}; log=${logPath}; logTail=${readFileTail(logPath)}`;
55588
55635
  }
55589
55636
  async function waitForDaemonReady(cwd, timeoutMs, shouldStop) {
55590
55637
  const deadline = Date.now() + timeoutMs;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "archctx",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Local architecture context CLI for agentic coding workflows.",
5
5
  "private": false,
6
6
  "type": "module",