@indigoai-us/hq-cli 5.342.18 → 5.343.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/command-catalog.generated.d.ts +12 -4
  3. package/dist/command-catalog.generated.js +14 -4
  4. package/dist/commands/company.d.ts +12 -0
  5. package/dist/commands/company.js +103 -6
  6. package/dist/commands/daemon.js +2 -11
  7. package/dist/commands/dm.js +10 -1
  8. package/dist/commands/lanes-shared.d.ts +1 -0
  9. package/dist/commands/lanes.d.ts +1 -0
  10. package/dist/commands/lanes.js +11 -0
  11. package/dist/commands/mesh.js +6 -2
  12. package/dist/commands/pack-install.d.ts +2 -0
  13. package/dist/commands/pack-install.js +7 -0
  14. package/dist/commands/pkg-update.d.ts +2 -0
  15. package/dist/commands/pkg-update.js +5 -1
  16. package/dist/commands/secrets.js +2 -3
  17. package/dist/lib/agent-kit/mcp/tools.js +1 -1
  18. package/dist/lib/bot/api.d.ts +1 -0
  19. package/dist/lib/bot/api.js +2 -0
  20. package/dist/lib/bot/progress.d.ts +12 -14
  21. package/dist/lib/bot/progress.js +29 -40
  22. package/dist/lib/bot/run.js +24 -24
  23. package/dist/lib/core-utils/sentry-report.d.ts +1 -1
  24. package/dist/lib/core-utils/sentry-report.js +18 -1
  25. package/dist/lib/daemon/command-call.d.ts +9 -0
  26. package/dist/lib/daemon/command-call.js +18 -0
  27. package/dist/lib/doctor/checks/work-context.js +5 -0
  28. package/dist/lib/lanes/outpost-dispatch.d.ts +1 -0
  29. package/dist/lib/lanes/outpost-dispatch.js +1 -0
  30. package/dist/lib/mesh/client.js +11 -0
  31. package/dist/lib/mesh/denial-codes.d.ts +13 -2
  32. package/dist/lib/mesh/denial-codes.js +25 -1
  33. package/dist/lib/mesh/live/daemon/doctor.js +4 -0
  34. package/dist/lib/work-context/outbox.js +8 -2
  35. package/dist/utils/cli-telemetry.js +5 -1
  36. package/dist/utils/install-tree-torn.d.ts +16 -13
  37. package/dist/utils/install-tree-torn.js +58 -26
  38. package/dist/utils/resident-package-preload.d.ts +1 -1
  39. package/dist/utils/resident-package-preload.js +62 -0
  40. package/dist/utils/secrets-sandbox-resident.d.ts +5 -0
  41. package/dist/utils/secrets-sandbox-resident.js +8 -0
  42. package/package.json +1 -1
@@ -714,6 +714,28 @@ function updaterPidAlive(lockPath, fs, isPidAlive) {
714
714
  return "unknown";
715
715
  }
716
716
  }
717
+ /** Whether the lock names a live process other than this CLI invocation. */
718
+ function liveForeignUpdaterPid(lockPath, fs, isPidAlive) {
719
+ try {
720
+ const lock = JSON.parse(fs.readFileSync(lockPath, "utf-8"));
721
+ if (typeof lock.startedAt !== "string" ||
722
+ Number.isNaN(Date.parse(lock.startedAt)) ||
723
+ typeof lock.tool !== "string" ||
724
+ lock.tool.length === 0 ||
725
+ typeof lock.version !== "string" ||
726
+ lock.version.length === 0) {
727
+ return false;
728
+ }
729
+ return typeof lock.pid === "number" &&
730
+ Number.isSafeInteger(lock.pid) &&
731
+ lock.pid > 0 &&
732
+ lock.pid !== process.pid &&
733
+ isPidAlive(lock.pid);
734
+ }
735
+ catch {
736
+ return false;
737
+ }
738
+ }
717
739
  /** Snapshot retired sibling trees so changes below their root stay observable. */
718
740
  function retiredSiblingActivitySignature(packageRoot, fs) {
719
741
  const { leaf } = cliNameParts();
@@ -917,7 +939,8 @@ const DEFAULT_INSTALL_TREE_STALE_PROBE_MS = 1_500;
917
939
  /**
918
940
  * Poll until the install tree has been continuously READY for `quietMs`, or the
919
941
  * wait exhausts its bounds. READY means: (i) no FRESH update lock held by another
920
- * pid, (ii) the missing target is present, and — when `packageRoot` is known —
942
+ * pid and no live recorded updater while the tree is in flight, (ii) the missing
943
+ * target is present, and — when `packageRoot` is known —
921
944
  * (iii) `<packageRoot>/package.json` parses with `name === CLI_NAME` and (iv) no
922
945
  * `.<leaf>-<rand>` retired sibling remains beside it. Every filesystem error makes
923
946
  * its condition "not ready" rather than throwing.
@@ -934,20 +957,22 @@ const DEFAULT_INSTALL_TREE_STALE_PROBE_MS = 1_500;
934
957
  * any installer before attempting a repair. Any observed signature change
935
958
  * keeps the ordinary settle deadline in force. `deadlineMs === 0` evaluates
936
959
  * readiness once.
937
- * - LOCKED time — wall time observed under a fresh foreign lock held by a live
938
- * pid — is bounded SEPARATELY by `lockWaitMs` (default the lock contract's own
939
- * 10-minute staleness window) and does NOT consume the settle budget. When
940
- * that ceiling is reached with the lock still held, the result is unsettled
941
- * with `lockHeldAtEnd` true so the seam can report a distinct `lock-held`
942
- * outcome and remedy rather than telling the user to reinstall over a live
943
- * writer.
944
- * Each poll's REAL elapsed interval (now() deltas) is attributed to the locked or
945
- * unlocked bucket by whether a fresh foreign lock was held when the interval
946
- * began, so a starved event loop only makes the wait coarser, never unbounded. A
960
+ * - WRITER time — wall time observed under a fresh foreign lock, or while a
961
+ * recorded foreign updater pid is alive and the tree has an in-flight signal
962
+ * — is bounded SEPARATELY by `lockWaitMs` (default the lock contract's own
963
+ * 10-minute staleness window) and does NOT consume the settle budget. This
964
+ * also covers a still-running updater whose lock became stale by age. When
965
+ * that ceiling is reached, the result is unsettled; `lockHeldAtEnd` remains
966
+ * reserved for a fresh lock held at the end.
967
+ * Each poll's REAL elapsed interval (now() deltas) is attributed to the writer or
968
+ * unlocked bucket by whether a fresh lock or qualifying live updater was observed
969
+ * when the interval began, so a starved event loop only makes the wait coarser,
970
+ * never unbounded. A
947
971
  * stale lock (dead pid, older than the staleness window, unparseable) or our own
948
- * pid never extends anything. The whole wait is bounded (≤ `deadlineMs +
972
+ * pid never extends anything by itself. The whole wait is bounded (≤ `deadlineMs +
949
973
  * lockWaitMs`), and the unchanged-tree path normally returns after the much
950
- * shorter `staleProbeMs` observation window.
974
+ * shorter `staleProbeMs` observation window unless a live updater pid is still
975
+ * present with an in-flight tree signal.
951
976
  */
952
977
  export async function waitForInstallTreeSettled(args) {
953
978
  const now = args.now ?? Date.now;
@@ -967,17 +992,21 @@ export async function waitForInstallTreeSettled(args) {
967
992
  let sawLock = false;
968
993
  let sawRetired = false;
969
994
  let lockedMs = 0;
995
+ let writerMs = 0;
970
996
  let unlockedMs = 0;
971
997
  let lockTool = "";
972
998
  let prevT = start;
973
999
  let prevForeignLockHeld = false;
1000
+ let prevWriterHeld = false;
974
1001
  let lockExtendedFired = false;
975
1002
  for (;;) {
976
1003
  const t = now();
977
- // Attribute the interval that just elapsed [prevT, t) to the bucket for the
978
- // lock state that held when it BEGAN (real now() deltas, never nominal pollMs).
1004
+ // Attribute the interval that just elapsed [prevT, t) using the state that
1005
+ // held when it BEGAN (real now() deltas, never nominal pollMs).
979
1006
  if (prevForeignLockHeld)
980
1007
  lockedMs += t - prevT;
1008
+ if (prevWriterHeld)
1009
+ writerMs += t - prevT;
981
1010
  else
982
1011
  unlockedMs += t - prevT;
983
1012
  const lock = freshForeignLock(args.lockPath, t, isPidAlive, fs);
@@ -1015,7 +1044,10 @@ export async function waitForInstallTreeSettled(args) {
1015
1044
  retiredCheckFailed = true;
1016
1045
  }
1017
1046
  }
1018
- let ready = !foreignLockHeld && installTargetPresent(args.target, fs);
1047
+ const inFlightTree = sawLock || sawRetired || sawTreeChange;
1048
+ const updaterPidHeld = inFlightTree && liveForeignUpdaterPid(args.lockPath, fs, isPidAlive);
1049
+ const writerHeld = foreignLockHeld || updaterPidHeld;
1050
+ let ready = !writerHeld && installTargetPresent(args.target, fs);
1019
1051
  if (ready && args.packageRoot) {
1020
1052
  try {
1021
1053
  if (!packageRootHealthy(args.packageRoot, fs))
@@ -1055,6 +1087,7 @@ export async function waitForInstallTreeSettled(args) {
1055
1087
  }
1056
1088
  if (!ready &&
1057
1089
  !foreignLockHeld &&
1090
+ !updaterPidHeld &&
1058
1091
  !retiredCheckFailed &&
1059
1092
  !sawLock &&
1060
1093
  !sawTreeChange &&
@@ -1078,14 +1111,13 @@ export async function waitForInstallTreeSettled(args) {
1078
1111
  };
1079
1112
  }
1080
1113
  // Give up when the TREE has had a full unlocked budget with no writer visible,
1081
- // OR a writer is STILL holding the lock and has held it past its own staleness
1082
- // ceiling. The lock ceiling is gated on a lock being held RIGHT NOW so that a
1083
- // ceiling of 0 (HQ_INSTALL_SETTLE_LOCK_TIMEOUT_MS=0, "do not extend under a
1084
- // lock") disables only the extension and does not collapse the ordinary
1085
- // deadlineMs settle when no lock exists — `lockedMs` is 0 ≥ 0 on every poll.
1114
+ // OR a qualifying writer has exceeded the shared writer ceiling. The writer
1115
+ // ceiling only extends while a fresh lock or in-flight live PID is present, so
1116
+ // a ceiling of 0 disables only that extension and does not collapse the normal
1117
+ // deadlineMs settle when no writer exists.
1086
1118
  // `deadlineMs` 0 makes the unlocked test fire on the first poll (evaluate-once),
1087
1119
  // matching the pre-lock-aware contract; `lockHeldAtEnd` distinguishes the causes.
1088
- if (unlockedMs >= deadlineMs || (foreignLockHeld && lockedMs >= lockWaitMs)) {
1120
+ if (unlockedMs >= deadlineMs || (writerHeld && writerMs >= lockWaitMs)) {
1089
1121
  return {
1090
1122
  settled: false,
1091
1123
  waitedMs,
@@ -1102,15 +1134,15 @@ export async function waitForInstallTreeSettled(args) {
1102
1134
  updaterPidAlive: updaterPidAlive(args.lockPath, fs, isPidAlive),
1103
1135
  };
1104
1136
  }
1105
- // The first poll at which the wait has reached `deadlineMs` while a lock is
1106
- // still held is exactly where the pre-lock-aware wait gave up — announce the
1107
- // extension once, and only when we are genuinely going to keep waiting.
1108
- if (!lockExtendedFired && foreignLockHeld && waitedMs >= deadlineMs) {
1137
+ // Announce once when the deadline has passed and a qualifying writer is why
1138
+ // the bounded wait continues.
1139
+ if (!lockExtendedFired && writerHeld && waitedMs >= deadlineMs) {
1109
1140
  lockExtendedFired = true;
1110
1141
  args.onLockExtended?.();
1111
1142
  }
1112
1143
  prevT = t;
1113
1144
  prevForeignLockHeld = foreignLockHeld;
1145
+ prevWriterHeld = writerHeld;
1114
1146
  await sleep(pollMs);
1115
1147
  }
1116
1148
  }
@@ -1,4 +1,4 @@
1
- export type ResidentPackagePath = "agent-kit" | "agent-mcp" | "auth-login" | "agents-terminal" | "bot" | "bot-logs-follow" | "childWrapper" | "coreJobRun" | "login" | "mcp" | "daemon" | "daemon-logs-follow" | "mesh-daemon" | "lanes-watch" | "monitor-wait" | "monitor-run" | "agents-message-wait" | "integrations-oauth-wait";
1
+ export type ResidentPackagePath = "agent-kit" | "agent-mcp" | "auth-login" | "agents-terminal" | "bot" | "bot-logs-follow" | "childWrapper" | "coreJobRun" | "daemon-call" | "login" | "mcp" | "daemon" | "daemon-logs-follow" | "mesh-daemon" | "lanes-watch" | "monitor-wait" | "monitor-run" | "agents-message-wait" | "integrations-oauth-wait" | "outpost-wait" | "secrets-sandbox" | "pkg-update" | "pack-install";
2
2
  /** Runtime modules that resident commands may need after a wait starts. */
3
3
  export declare const RESIDENT_PACKAGE_MODULES: Record<ResidentPackagePath, readonly string[]>;
4
4
  export declare class ResidentPackagePreloadError extends Error {
@@ -43,6 +43,7 @@ export const RESIDENT_PACKAGE_MODULES = {
43
43
  mcp: ["../lib/mcp/tools.js", "../lib/mcp/prompts.js"],
44
44
  childWrapper: ["../main.js"],
45
45
  coreJobRun: ["../lib/flag-registry.js"],
46
+ "daemon-call": ["../lib/daemon/protocol.js"],
46
47
  daemon: [
47
48
  "../sentry.js",
48
49
  "../utils/cognito-session.js",
@@ -63,6 +64,24 @@ export const RESIDENT_PACKAGE_MODULES = {
63
64
  "monitor-run": ["../commands/lanes.js", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "../sentry.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
64
65
  "agents-message-wait": ["../sentry.js", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
65
66
  "integrations-oauth-wait": ["../sentry.js", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
67
+ "outpost-wait": ["../commands/lanes.js", "../lib/plan-limit-nag.js", "../utils/plan-gate-error.js", "../sentry.js", "open", "../utils/cognito-session.js", "../lib/first-sync-next-step.js", "@indigoai-us/hq-cloud"],
68
+ "secrets-sandbox": [],
69
+ "pkg-update": ["../sentry.js", "../utils/cognito-session.js", "@indigoai-us/hq-cloud"],
70
+ "pack-install": [
71
+ "../sentry.js",
72
+ "../lib/plan-limit-nag.js",
73
+ "../utils/plan-gate-error.js",
74
+ "open",
75
+ "../commands/mcp-serve.js",
76
+ "../lib/daemon/mcp-oauth.js",
77
+ "../lib/mcp/tools.js",
78
+ "../lib/mcp/prompts.js",
79
+ "../utils/sandbox-runner-client.js",
80
+ "../utils/cli-telemetry.js",
81
+ "../utils/cognito-session.js",
82
+ "../lib/first-sync-next-step.js",
83
+ "@indigoai-us/hq-cloud",
84
+ ],
66
85
  };
67
86
  const LOADERS = {
68
87
  "agent-kit": [
@@ -158,6 +177,9 @@ const LOADERS = {
158
177
  coreJobRun: [
159
178
  () => import("../lib/flag-registry.js"),
160
179
  ],
180
+ "daemon-call": [
181
+ () => import("../lib/daemon/protocol.js"),
182
+ ],
161
183
  daemon: [
162
184
  async () => {
163
185
  const { preloadSentrySdk } = await import("../sentry.js");
@@ -248,6 +270,46 @@ const LOADERS = {
248
270
  () => import("../lib/first-sync-next-step.js"),
249
271
  () => import("@indigoai-us/hq-cloud"),
250
272
  ],
273
+ "outpost-wait": [
274
+ () => import("../commands/lanes.js"),
275
+ () => import("../lib/plan-limit-nag.js"),
276
+ () => import("../utils/plan-gate-error.js"),
277
+ async () => {
278
+ const { preloadSentrySdk } = await import("../sentry.js");
279
+ preloadSentrySdk();
280
+ },
281
+ () => import("open"),
282
+ () => import("../utils/cognito-session.js"),
283
+ () => import("../lib/first-sync-next-step.js"),
284
+ () => import("@indigoai-us/hq-cloud"),
285
+ ],
286
+ "secrets-sandbox": [],
287
+ "pkg-update": [
288
+ async () => {
289
+ const { preloadSentrySdk } = await import("../sentry.js");
290
+ preloadSentrySdk();
291
+ },
292
+ () => import("../utils/cognito-session.js"),
293
+ () => import("@indigoai-us/hq-cloud"),
294
+ ],
295
+ "pack-install": [
296
+ async () => {
297
+ const { preloadSentrySdk } = await import("../sentry.js");
298
+ preloadSentrySdk();
299
+ },
300
+ () => import("../lib/plan-limit-nag.js"),
301
+ () => import("../utils/plan-gate-error.js"),
302
+ () => import("open"),
303
+ () => import("../commands/mcp-serve.js"),
304
+ () => import("../lib/daemon/mcp-oauth.js"),
305
+ () => import("../lib/mcp/tools.js"),
306
+ () => import("../lib/mcp/prompts.js"),
307
+ () => import("../utils/sandbox-runner-client.js"),
308
+ () => import("../utils/cli-telemetry.js"),
309
+ () => import("../utils/cognito-session.js"),
310
+ () => import("../lib/first-sync-next-step.js"),
311
+ () => import("@indigoai-us/hq-cloud"),
312
+ ],
251
313
  };
252
314
  export class ResidentPackagePreloadError extends Error {
253
315
  moduleSpecifier;
@@ -0,0 +1,5 @@
1
+ import type { SandboxRunnerClient, SandboxRunnerJob, SandboxRunnerStartResponse } from "./sandbox-runner-client.js";
2
+ import { type ResidentCommandLeaseOptions } from "./resident-package-preload.js";
3
+ /** Poll a submitted remote job after loading local result and error-path modules. */
4
+ export declare function runSandboxJobAfterSubmission(client: Pick<SandboxRunnerClient, "getJob" | "pollJob">, token: string, started: SandboxRunnerStartResponse, leaseOptions?: ResidentCommandLeaseOptions): Promise<SandboxRunnerJob>;
5
+ //# sourceMappingURL=secrets-sandbox-resident.d.ts.map
@@ -0,0 +1,8 @@
1
+ import { runResidentCommandWithPackageLease } from "./resident-package-preload.js";
2
+ /** Poll a submitted remote job after loading local result and error-path modules. */
3
+ export function runSandboxJobAfterSubmission(client, token, started, leaseOptions) {
4
+ return runResidentCommandWithPackageLease("secrets-sandbox", () => started.status === "succeeded" || started.status === "failed"
5
+ ? client.getJob(token, started.jobId)
6
+ : client.pollJob(token, started.jobId), leaseOptions);
7
+ }
8
+ //# sourceMappingURL=secrets-sandbox-resident.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.342.18",
3
+ "version": "5.343.1",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {