@indigoai-us/hq-cli 5.342.18 → 5.343.0

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.343.0] — 2026-10-04
6
+ - `hq company --company <slug> settings set --work-registry-enabled <true|false>` and `--work-mesh-live-enabled <true|false>` let a company owner turn work tracking on or off. Work tracking needs both switches; after either is set the command says whether work tracking is on and prints the exact command for the switch that is still off. `hq company --company <slug> settings get` now also shows both switches for an owner or admin.
7
+ - `hq mesh context requeue` now also re-sends, by default, sessions that were refused while work tracking was off. `hq doctor` and `hq mesh daemon doctor` explain those refusals in plain words.
8
+ - Release the hq-cli package-use lease before the secrets sandbox poll and bounded package downloads after preloading their lazy runtime imports.
9
+
5
10
  ## [5.342.18] — 2026-10-04
6
11
  - Preserve confirmed remote lane-message responses for in-process monitor delivery.
7
12
  - Use native TypeScript renderers for `hq core rebuild-index` commands.
@@ -5334,7 +5334,7 @@ export declare const COMMAND_CATALOG: readonly [{
5334
5334
  readonly options: readonly [];
5335
5335
  readonly subcommands: readonly [{
5336
5336
  readonly name: "set";
5337
- readonly description: "Set per-company settings (PUT /company-settings). Require at least one of --crm-enabled / --ontology-enabled / --accounting-enabled / --checkpoint-gate-enabled.";
5337
+ readonly description: "Set per-company settings (PUT /company-settings). Require at least one of --crm-enabled / --ontology-enabled / --accounting-enabled / --checkpoint-gate-enabled / --work-registry-enabled / --work-mesh-live-enabled.";
5338
5338
  readonly aliases: readonly [];
5339
5339
  readonly hidden: false;
5340
5340
  readonly helpOption: true;
@@ -5358,11 +5358,19 @@ export declare const COMMAND_CATALOG: readonly [{
5358
5358
  readonly flags: "--checkpoint-gate-enabled <true|false>";
5359
5359
  readonly description: "Require (true) or stop requiring (false) a checkpoint before HQ sessions in this company end a turn";
5360
5360
  readonly hidden: false;
5361
+ }, {
5362
+ readonly flags: "--work-registry-enabled <true|false>";
5363
+ readonly description: "Turn work-session registration on or off for this company (default off). Work tracking needs this and --work-mesh-live-enabled";
5364
+ readonly hidden: false;
5365
+ }, {
5366
+ readonly flags: "--work-mesh-live-enabled <true|false>";
5367
+ readonly description: "Turn live work tracking on or off for this company (default off). Work tracking needs this and --work-registry-enabled";
5368
+ readonly hidden: false;
5361
5369
  }];
5362
5370
  readonly subcommands: readonly [];
5363
5371
  }, {
5364
5372
  readonly name: "get";
5365
- readonly description: "Show whether the checkpoint Stop gate is on for this company (GET /company-settings/checkpoint-gate; any member may read it).";
5373
+ readonly description: "Show whether the checkpoint Stop gate is on for this company (GET /company-settings/checkpoint-gate; any member may read it) and, for an owner or admin, the two work tracking switches (GET /company-settings).";
5366
5374
  readonly aliases: readonly [];
5367
5375
  readonly hidden: false;
5368
5376
  readonly helpOption: true;
@@ -9635,7 +9643,7 @@ export declare const COMMAND_CATALOG: readonly [{
9635
9643
  readonly subcommands: readonly [];
9636
9644
  }, {
9637
9645
  readonly name: "requeue";
9638
- readonly description: "Requeue quarantined outbox operations (default: only AUTH_DENIED — work-mesh-live gap 10 recovery)";
9646
+ readonly description: "Requeue quarantined outbox operations (default: AUTH_DENIED - work-mesh-live gap 10 recovery - plus sessions refused while work tracking was off). Run once after the company owner turns work tracking on";
9639
9647
  readonly aliases: readonly [];
9640
9648
  readonly hidden: false;
9641
9649
  readonly helpOption: true;
@@ -6478,7 +6478,7 @@ export const COMMAND_CATALOG = [
6478
6478
  "subcommands": [
6479
6479
  {
6480
6480
  "name": "set",
6481
- "description": "Set per-company settings (PUT /company-settings). Require at least one of --crm-enabled / --ontology-enabled / --accounting-enabled / --checkpoint-gate-enabled.",
6481
+ "description": "Set per-company settings (PUT /company-settings). Require at least one of --crm-enabled / --ontology-enabled / --accounting-enabled / --checkpoint-gate-enabled / --work-registry-enabled / --work-mesh-live-enabled.",
6482
6482
  "aliases": [],
6483
6483
  "hidden": false,
6484
6484
  "helpOption": true,
@@ -6506,13 +6506,23 @@ export const COMMAND_CATALOG = [
6506
6506
  "flags": "--checkpoint-gate-enabled <true|false>",
6507
6507
  "description": "Require (true) or stop requiring (false) a checkpoint before HQ sessions in this company end a turn",
6508
6508
  "hidden": false
6509
+ },
6510
+ {
6511
+ "flags": "--work-registry-enabled <true|false>",
6512
+ "description": "Turn work-session registration on or off for this company (default off). Work tracking needs this and --work-mesh-live-enabled",
6513
+ "hidden": false
6514
+ },
6515
+ {
6516
+ "flags": "--work-mesh-live-enabled <true|false>",
6517
+ "description": "Turn live work tracking on or off for this company (default off). Work tracking needs this and --work-registry-enabled",
6518
+ "hidden": false
6509
6519
  }
6510
6520
  ],
6511
6521
  "subcommands": []
6512
6522
  },
6513
6523
  {
6514
6524
  "name": "get",
6515
- "description": "Show whether the checkpoint Stop gate is on for this company (GET /company-settings/checkpoint-gate; any member may read it).",
6525
+ "description": "Show whether the checkpoint Stop gate is on for this company (GET /company-settings/checkpoint-gate; any member may read it) and, for an owner or admin, the two work tracking switches (GET /company-settings).",
6516
6526
  "aliases": [],
6517
6527
  "hidden": false,
6518
6528
  "helpOption": true,
@@ -11686,7 +11696,7 @@ export const COMMAND_CATALOG = [
11686
11696
  },
11687
11697
  {
11688
11698
  "name": "requeue",
11689
- "description": "Requeue quarantined outbox operations (default: only AUTH_DENIED — work-mesh-live gap 10 recovery)",
11699
+ "description": "Requeue quarantined outbox operations (default: AUTH_DENIED - work-mesh-live gap 10 recovery - plus sessions refused while work tracking was off). Run once after the company owner turns work tracking on",
11690
11700
  "aliases": [],
11691
11701
  "hidden": false,
11692
11702
  "helpOption": true,
@@ -1,3 +1,15 @@
1
1
  import { Command } from "commander";
2
+ /**
3
+ * The two per-company switches that together turn work tracking on. The server
4
+ * refuses work-session registration unless both are true. `null` means the
5
+ * values could not be read.
6
+ */
7
+ interface WorkTrackingSettings {
8
+ workRegistryEnabled: boolean;
9
+ workMeshLiveEnabled: boolean;
10
+ }
11
+ /** Plain next steps after a work tracking switch was set, from the effective settings. */
12
+ export declare function workTrackingNextSteps(companySlug: string, settings: WorkTrackingSettings | null): string[];
2
13
  export declare function registerCompanyCommand(program: Command): void;
14
+ export {};
3
15
  //# sourceMappingURL=company.d.ts.map
@@ -4,6 +4,64 @@ import { vaultApiFetch, getEntityUid } from "../utils/vault-api.js";
4
4
  import { registerCompanyTransferCommand } from "./company-transfer.js";
5
5
  import { registerCompanyRenameCommand } from "./company-rename.js";
6
6
  import { describeRefreshOutcome, refreshCheckpointGateSetting, } from "./core-checkpoint-gate-setting.js";
7
+ /** Both switches from a settings response body, or null unless both are booleans. */
8
+ function workTrackingFromBody(body) {
9
+ const { workRegistryEnabled, workMeshLiveEnabled } = body;
10
+ return typeof workRegistryEnabled === "boolean" && typeof workMeshLiveEnabled === "boolean"
11
+ ? { workRegistryEnabled, workMeshLiveEnabled }
12
+ : null;
13
+ }
14
+ /**
15
+ * Read both switches from GET /company-settings (owner or admin only). The
16
+ * server returns effective values, so an absent field means the default (off).
17
+ * A refused or failed read returns null rather than a guess.
18
+ */
19
+ async function readWorkTrackingSettings(token, companyUid) {
20
+ try {
21
+ const res = await vaultApiFetch({
22
+ token,
23
+ path: "/company-settings",
24
+ query: { companyUid },
25
+ });
26
+ if (!res.ok)
27
+ return null;
28
+ const body = (await res.json().catch(() => ({})));
29
+ return {
30
+ workRegistryEnabled: body.workRegistryEnabled === true,
31
+ workMeshLiveEnabled: body.workMeshLiveEnabled === true,
32
+ };
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ /** Plain next steps after a work tracking switch was set, from the effective settings. */
39
+ export function workTrackingNextSteps(companySlug, settings) {
40
+ const command = `hq company --company ${companySlug} settings`;
41
+ if (!settings) {
42
+ return [`Could not read the settings back. Check both switches with: ${command} get`];
43
+ }
44
+ if (settings.workRegistryEnabled && settings.workMeshLiveEnabled) {
45
+ return [
46
+ "Work tracking is on.",
47
+ "Sessions refused while it was off are held on each machine. " +
48
+ "Each person should run once: hq mesh context requeue",
49
+ ];
50
+ }
51
+ if (settings.workRegistryEnabled) {
52
+ return [
53
+ "Work tracking is not on yet. Sessions will still be refused until live tracking is also on. " +
54
+ `Run: ${command} set --work-mesh-live-enabled true`,
55
+ ];
56
+ }
57
+ if (settings.workMeshLiveEnabled) {
58
+ return [
59
+ "Work tracking is not on yet. Sessions will still be refused until the work registry is also on. " +
60
+ `Run: ${command} set --work-registry-enabled true`,
61
+ ];
62
+ }
63
+ return [`Work tracking is off for ${companySlug}.`];
64
+ }
7
65
  /**
8
66
  * Parse a `--flag <true|false>` string into a boolean, or throw. Commander
9
67
  * passes the raw string; we validate strictly so a typo never silently writes
@@ -32,11 +90,14 @@ export function registerCompanyCommand(program) {
32
90
  .command("set")
33
91
  .description("Set per-company settings (PUT /company-settings). Require at least one " +
34
92
  "of --crm-enabled / --ontology-enabled / --accounting-enabled / " +
35
- "--checkpoint-gate-enabled.")
93
+ "--checkpoint-gate-enabled / --work-registry-enabled / " +
94
+ "--work-mesh-live-enabled.")
36
95
  .option("--crm-enabled <true|false>", "Enable/disable the native CRM for this company")
37
96
  .option("--ontology-enabled <true|false>", "Enable/disable the ontology gardener for this company")
38
97
  .option("--accounting-enabled <true|false>", "Enable/disable the accounting pack for this company")
39
98
  .option("--checkpoint-gate-enabled <true|false>", "Require (true) or stop requiring (false) a checkpoint before HQ sessions in this company end a turn")
99
+ .option("--work-registry-enabled <true|false>", "Turn work-session registration on or off for this company (default off). Work tracking needs this and --work-mesh-live-enabled")
100
+ .option("--work-mesh-live-enabled <true|false>", "Turn live work tracking on or off for this company (default off). Work tracking needs this and --work-registry-enabled")
40
101
  .action(async (opts) => {
41
102
  try {
42
103
  const companySlug = company.opts().company;
@@ -47,8 +108,10 @@ export function registerCompanyCommand(program) {
47
108
  if (opts.crmEnabled === undefined &&
48
109
  opts.ontologyEnabled === undefined &&
49
110
  opts.accountingEnabled === undefined &&
50
- opts.checkpointGateEnabled === undefined) {
51
- console.error(chalk.red("Error: provide at least one of --crm-enabled / --ontology-enabled / --accounting-enabled / --checkpoint-gate-enabled."));
111
+ opts.checkpointGateEnabled === undefined &&
112
+ opts.workRegistryEnabled === undefined &&
113
+ opts.workMeshLiveEnabled === undefined) {
114
+ console.error(chalk.red("Error: provide at least one of --crm-enabled / --ontology-enabled / --accounting-enabled / --checkpoint-gate-enabled / --work-registry-enabled / --work-mesh-live-enabled."));
52
115
  process.exit(1);
53
116
  }
54
117
  const body = {};
@@ -64,6 +127,14 @@ export function registerCompanyCommand(program) {
64
127
  if (opts.checkpointGateEnabled !== undefined) {
65
128
  body.checkpointGateEnabled = parseBoolFlag(opts.checkpointGateEnabled, "--checkpoint-gate-enabled");
66
129
  }
130
+ if (opts.workRegistryEnabled !== undefined) {
131
+ body.workRegistryEnabled = parseBoolFlag(opts.workRegistryEnabled, "--work-registry-enabled");
132
+ }
133
+ if (opts.workMeshLiveEnabled !== undefined) {
134
+ body.workMeshLiveEnabled = parseBoolFlag(opts.workMeshLiveEnabled, "--work-mesh-live-enabled");
135
+ }
136
+ const setsWorkTracking = body.workRegistryEnabled !== undefined ||
137
+ body.workMeshLiveEnabled !== undefined;
67
138
  const token = await ensureCognitoToken();
68
139
  const companyUid = await getEntityUid(token, { companySlug });
69
140
  body.companyUid = companyUid;
@@ -76,7 +147,9 @@ export function registerCompanyCommand(program) {
76
147
  if (!res.ok) {
77
148
  const errBody = (await res.json().catch(() => ({})));
78
149
  if (res.status === 403) {
79
- console.error(chalk.red("Requires owner role on this company to change its settings."));
150
+ console.error(chalk.red(setsWorkTracking
151
+ ? "Only the company owner can change this setting."
152
+ : "Requires owner role on this company to change its settings."));
80
153
  process.exit(1);
81
154
  }
82
155
  console.error(chalk.red(`Failed to update company settings: ${errBody.error ?? res.statusText}`));
@@ -98,6 +171,16 @@ export function registerCompanyCommand(program) {
98
171
  // The setting is saved; the cache refreshes on the next Stop.
99
172
  }
100
173
  }
174
+ if (setsWorkTracking) {
175
+ // Registration needs both switches, so report the effective pair:
176
+ // from the PUT response when it echoes both, otherwise from a GET.
177
+ const resBody = (await res.json().catch(() => ({})));
178
+ const effective = workTrackingFromBody(resBody) ??
179
+ (await readWorkTrackingSettings(token, companyUid));
180
+ for (const line of workTrackingNextSteps(companySlug, effective)) {
181
+ console.log(line);
182
+ }
183
+ }
101
184
  }
102
185
  catch (err) {
103
186
  console.error(chalk.red("Error:"), err instanceof Error ? err.message : String(err));
@@ -107,7 +190,8 @@ export function registerCompanyCommand(program) {
107
190
  settings
108
191
  .command("get")
109
192
  .description("Show whether the checkpoint Stop gate is on for this company " +
110
- "(GET /company-settings/checkpoint-gate; any member may read it).")
193
+ "(GET /company-settings/checkpoint-gate; any member may read it) and, " +
194
+ "for an owner or admin, the two work tracking switches (GET /company-settings).")
111
195
  .option("--json", "Print the result as JSON")
112
196
  .action(async (opts) => {
113
197
  try {
@@ -137,11 +221,24 @@ export function registerCompanyCommand(program) {
137
221
  console.error(chalk.red("Failed to read company settings: no checkpointGateEnabled in the response."));
138
222
  process.exit(1);
139
223
  }
224
+ // The work tracking switches are only on the owner/admin settings
225
+ // route. A refused or failed read is reported as unknown, not guessed.
226
+ const workTracking = await readWorkTrackingSettings(token, companyUid);
140
227
  if (opts.json) {
141
- console.log(JSON.stringify({ company: companySlug, checkpointGateEnabled: enabled }));
228
+ console.log(JSON.stringify({
229
+ company: companySlug,
230
+ checkpointGateEnabled: enabled,
231
+ workRegistryEnabled: workTracking?.workRegistryEnabled ?? null,
232
+ workMeshLiveEnabled: workTracking?.workMeshLiveEnabled ?? null,
233
+ }));
142
234
  }
143
235
  else {
144
236
  console.log(`checkpointGateEnabled=${enabled}`);
237
+ for (const key of ["workRegistryEnabled", "workMeshLiveEnabled"]) {
238
+ console.log(workTracking
239
+ ? `${key}=${workTracking[key]}`
240
+ : `${key}=unknown (only the company owner or an admin can read this setting)`);
241
+ }
145
242
  }
146
243
  }
147
244
  catch (err) {
@@ -1424,7 +1424,9 @@ async function runContextRequeue(opts) {
1424
1424
  }
1425
1425
  const scope = errorCode === null
1426
1426
  ? "all quarantine reasons"
1427
- : `lastErrorCode=${errorCode === undefined ? "AUTH_DENIED" : errorCode}`;
1427
+ : errorCode === undefined
1428
+ ? "lastErrorCode=AUTH_DENIED or refused while work tracking was off"
1429
+ : `lastErrorCode=${errorCode}`;
1428
1430
  console.log(`Requeued ${requeued.length} quarantined outbox operation${requeued.length === 1 ? "" : "s"} (${scope}). The mesh daemon will retry them on its next replay.`);
1429
1431
  }
1430
1432
  async function runContextUntracked(sessionId, opts) {
@@ -2016,7 +2018,9 @@ export function registerMeshCommand(program) {
2016
2018
  .action((opts) => wrap(() => runContextCorrect(opts))());
2017
2019
  context
2018
2020
  .command("requeue")
2019
- .description("Requeue quarantined outbox operations (default: only AUTH_DENIED — work-mesh-live gap 10 recovery)")
2021
+ .description("Requeue quarantined outbox operations (default: AUTH_DENIED - work-mesh-live gap 10 recovery - " +
2022
+ "plus sessions refused while work tracking was off). " +
2023
+ "Run once after the company owner turns work tracking on")
2020
2024
  .option("--all", "Requeue every quarantined op regardless of lastErrorCode")
2021
2025
  .option("--error-code <code>", "Requeue quarantined ops with this lastErrorCode")
2022
2026
  .option("--json", "Print machine-readable JSON")
@@ -34,6 +34,7 @@
34
34
  * from each pack's package.yaml; rationale lives in the layout-fix PR.)
35
35
  */
36
36
  import { type KeyObject } from 'node:crypto';
37
+ import { type ResidentCommandLeaseOptions } from '../utils/resident-package-preload.js';
37
38
  import { type SecretResolver } from './mcp-registration.js';
38
39
  import type { PackManifest } from '../types.js';
39
40
  export interface ResolveLatestOptions {
@@ -447,6 +448,7 @@ export interface InstallPackOptions {
447
448
  */
448
449
  requireSignature?: boolean;
449
450
  }
451
+ export declare function runPackInstallWithLease<T>(run: () => Promise<T>, leaseOptions?: ResidentCommandLeaseOptions): Promise<T>;
450
452
  export declare function installPack(source: string, opts?: InstallPackOptions): Promise<void>;
451
453
  export {};
452
454
  //# sourceMappingURL=pack-install.d.ts.map
@@ -50,6 +50,7 @@ import { codexTargets } from '../lib/install/codex-targets.js';
50
50
  import { readHqVersion, routeContribution, listInstalledPacks, mcpServerNameForContribution } from '../utils/pack-contributions.js';
51
51
  import { CONTRIBUTION_TABLE, payloadFor } from '../utils/contribution-table.js';
52
52
  import { safeExtractTarball } from './safe-extract.js';
53
+ import { runResidentCommandWithPackageLease } from '../utils/resident-package-preload.js';
53
54
  import { getCompanyUid, vaultApiFetch, vaultApiFetchPublic, } from '../utils/vault-api.js';
54
55
  import { ensureCognitoToken } from '../utils/cognito-session.js';
55
56
  import { formatApiKeyCapabilityDenial, peekHqApiKey, } from '../utils/resolve-vault-credential.js';
@@ -1677,7 +1678,13 @@ export function runScanPackages(hqRoot, opts = {}) {
1677
1678
  console.log(chalk.yellow(' scan-packages.sh exited non-zero; see output above.'));
1678
1679
  }
1679
1680
  }
1681
+ export function runPackInstallWithLease(run, leaseOptions) {
1682
+ return runResidentCommandWithPackageLease("pack-install", run, leaseOptions);
1683
+ }
1680
1684
  export async function installPack(source, opts = {}) {
1685
+ return runPackInstallWithLease(() => installPackWithoutLease(source, opts));
1686
+ }
1687
+ async function installPackWithoutLease(source, opts) {
1681
1688
  // NOTE: the HQ_API_KEY fail-closed gate is NOT enforced here. `installPack`
1682
1689
  // is a shared primitive called both by the top-level `hq install` CLI route
1683
1690
  // (where Cognito-only is the right gate — checked there instead) AND by
@@ -5,5 +5,7 @@
5
5
  * If slug given: update only that package.
6
6
  */
7
7
  import { Command } from 'commander';
8
+ import { type ResidentCommandLeaseOptions } from '../utils/resident-package-preload.js';
8
9
  export declare function registerPackageUpdateCommand(parent: Command): void;
10
+ export declare function runPackageUpdateWithLease<T>(run: () => Promise<T>, leaseOptions?: ResidentCommandLeaseOptions): Promise<T>;
9
11
  //# sourceMappingURL=pkg-update.d.ts.map
@@ -9,6 +9,7 @@ import * as os from 'os';
9
9
  import * as path from 'path';
10
10
  import { parseUserYaml } from '../utils/user-yaml-error.js';
11
11
  import { execSync } from 'child_process';
12
+ import { runResidentCommandWithPackageLease } from '../utils/resident-package-preload.js';
12
13
  import chalk from 'chalk';
13
14
  import { ensureCognitoToken } from '../utils/cognito-session.js';
14
15
  import { resolveDefaultHqRoot } from '../utils/cognito-session.js';
@@ -21,7 +22,7 @@ export function registerPackageUpdateCommand(parent) {
21
22
  .description('Check for and apply package updates')
22
23
  .action(async (slug) => {
23
24
  try {
24
- await updatePackages(slug);
25
+ await runPackageUpdateWithLease(() => updatePackages(slug));
25
26
  }
26
27
  catch (error) {
27
28
  console.error(chalk.red('Update failed:'), error instanceof Error ? error.message : 'Unknown error');
@@ -29,6 +30,9 @@ export function registerPackageUpdateCommand(parent) {
29
30
  }
30
31
  });
31
32
  }
33
+ export function runPackageUpdateWithLease(run, leaseOptions) {
34
+ return runResidentCommandWithPackageLease("pkg-update", run, leaseOptions);
35
+ }
32
36
  async function updatePackages(slug) {
33
37
  const hqRoot = resolveDefaultHqRoot({ onMissing: 'throw' });
34
38
  const entries = readRegistry(hqRoot);
@@ -10,6 +10,7 @@ import { SECRET_NAME_PATTERN, GROUP_ID_PATTERN, EMAIL_PATTERN } from "./_pattern
10
10
  import { describeSecretsScope, formatSecretSaved, formatSecretsListEmpty, formatSecretsListHeader, } from "./secrets-scope.js";
11
11
  import { vaultApiFetch, getCompanyUid, getEntityUid, looksLikeCompanyUid, } from "../utils/vault-api.js";
12
12
  import { formatApiKeyCapabilityDenial, requireApiKeyCapability, resolveVaultCredentialForCapability, } from "../utils/resolve-vault-credential.js";
13
+ import { runSandboxJobAfterSubmission } from "../utils/secrets-sandbox-resident.js";
13
14
  export { vaultApiFetch, getCompanyUid, getEntityUid };
14
15
  /**
15
16
  * Mirrors `RESOURCE_SURFACES` in hq-pro
@@ -1061,9 +1062,7 @@ export function registerSecretsCommand(program) {
1061
1062
  secretNames: keys,
1062
1063
  command,
1063
1064
  });
1064
- const job = started.status === "succeeded" || started.status === "failed"
1065
- ? await client.getJob(token, started.jobId)
1066
- : await client.pollJob(token, started.jobId);
1065
+ const job = await runSandboxJobAfterSubmission(client, token, started);
1067
1066
  renderSandboxJobResult(job, keys);
1068
1067
  const exitCode = typeof job.exitCode === "number" ? job.exitCode : undefined;
1069
1068
  if (job.success === false || (exitCode !== undefined && exitCode !== 0) || job.status === "failed") {
@@ -13,6 +13,7 @@ import { workContextRoot, workContextSessionsDir } from "../../work-context/path
13
13
  import { countDistinctHeldEvents, countJsonlLines, deadLetterNonEmpty, } from "../../mesh/live/spool.js";
14
14
  import { workMeshDeadLetterPath, workMeshHeldPath, workMeshRoot, workMeshSpoolPath, } from "../../mesh/live/paths.js";
15
15
  import { collectDaemonDoctor, formatDaemonDoctor, } from "../../mesh/live/daemon/doctor.js";
16
+ import { workSessionDenialReason } from "../../mesh/denial-codes.js";
16
17
  export const WORK_CONTEXT_FAMILY_ID = "work-context";
17
18
  export const WORK_CONTEXT_FAMILY_TITLE = "Work context";
18
19
  const DEFAULT_DEPS = {
@@ -97,6 +98,9 @@ function runChecks(deps) {
97
98
  ]
98
99
  .filter(Boolean)
99
100
  .join(" ");
101
+ const quarantineDenialReason = showQuarantineReason
102
+ ? workSessionDenialReason(stats.lastQuarantineServerCode)
103
+ : undefined;
100
104
  results.push({
101
105
  status: stats.quarantined > 0 ? "WARN" : "PASS",
102
106
  checkId: "work-context.outbox-quarantined",
@@ -104,6 +108,7 @@ function runChecks(deps) {
104
108
  message: `Outbox quarantined count=${stats.quarantined}${showQuarantineReason
105
109
  ? ` (last reason=${stats.lastQuarantineReason ?? "unknown"}${quarantineDetails ? `; ${quarantineDetails}` : ""})`
106
110
  : ""}.`,
111
+ ...(quarantineDenialReason ? { remediation: quarantineDenialReason } : {}),
107
112
  });
108
113
  // Default-company mode + migration capability (US-017B)
109
114
  try {
@@ -79,6 +79,17 @@ export function createWorkSessionDeliverer(opts) {
79
79
  if (status === 429 || (status >= 500 && status <= 599)) {
80
80
  return { ok: false, retryable: true, code: `HTTP_${status}` };
81
81
  }
82
+ if (status === 404 && isWorkSessionDenialCode(errorFields.code)) {
83
+ // Keep the allowlisted code (FEATURE_DISABLED) so the refusal can be
84
+ // explained and picked up by the default requeue filter.
85
+ return {
86
+ ok: false,
87
+ retryable: false,
88
+ code: "HTTP_404",
89
+ httpStatus: 404,
90
+ serverCode: errorFields.code,
91
+ };
92
+ }
82
93
  if (status === 404 ||
83
94
  status === 409 ||
84
95
  status === 410 ||
@@ -1,5 +1,16 @@
1
- /** Explicit 401/403 codes returned by hq-pro's work-session registration path. */
2
- export declare const WORK_SESSION_DENIAL_CODES: readonly ["AUTH_REQUIRED", "AGENT_IDENTITY_UNVERIFIED", "IMPERSONATION_FORBIDDEN", "NO_PERSON_ENTITY", "INVALID_COMPANY", "WORK_REGISTRY_DISABLED"];
1
+ /**
2
+ * Explicit refusal codes returned by hq-pro's work-session registration path:
3
+ * the 401/403 denials, plus the 404 FEATURE_DISABLED answer given while the
4
+ * company's Work Mesh Live setting is off.
5
+ */
6
+ export declare const WORK_SESSION_DENIAL_CODES: readonly ["AUTH_REQUIRED", "AGENT_IDENTITY_UNVERIFIED", "IMPERSONATION_FORBIDDEN", "NO_PERSON_ENTITY", "INVALID_COMPANY", "WORK_REGISTRY_DISABLED", "FEATURE_DISABLED"];
7
+ /**
8
+ * Refusals that end once the company owner turns a setting on. The default
9
+ * `hq mesh context requeue` filter re-sends operations stored with these.
10
+ */
11
+ export declare const WORK_TRACKING_OFF_DENIAL_CODES: readonly WorkSessionDenialCode[];
3
12
  export type WorkSessionDenialCode = (typeof WORK_SESSION_DENIAL_CODES)[number];
4
13
  export declare function isWorkSessionDenialCode(value: unknown): value is WorkSessionDenialCode;
14
+ /** Plain reason for a server denial code, or undefined when there is none. */
15
+ export declare function workSessionDenialReason(value: unknown): string | undefined;
5
16
  //# sourceMappingURL=denial-codes.d.ts.map
@@ -1,4 +1,8 @@
1
- /** Explicit 401/403 codes returned by hq-pro's work-session registration path. */
1
+ /**
2
+ * Explicit refusal codes returned by hq-pro's work-session registration path:
3
+ * the 401/403 denials, plus the 404 FEATURE_DISABLED answer given while the
4
+ * company's Work Mesh Live setting is off.
5
+ */
2
6
  export const WORK_SESSION_DENIAL_CODES = [
3
7
  "AUTH_REQUIRED",
4
8
  "AGENT_IDENTITY_UNVERIFIED",
@@ -6,9 +10,29 @@ export const WORK_SESSION_DENIAL_CODES = [
6
10
  "NO_PERSON_ENTITY",
7
11
  "INVALID_COMPANY",
8
12
  "WORK_REGISTRY_DISABLED",
13
+ "FEATURE_DISABLED",
14
+ ];
15
+ /**
16
+ * Refusals that end once the company owner turns a setting on. The default
17
+ * `hq mesh context requeue` filter re-sends operations stored with these.
18
+ */
19
+ export const WORK_TRACKING_OFF_DENIAL_CODES = [
20
+ "WORK_REGISTRY_DISABLED",
21
+ "FEATURE_DISABLED",
9
22
  ];
10
23
  export function isWorkSessionDenialCode(value) {
11
24
  return typeof value === "string" &&
12
25
  WORK_SESSION_DENIAL_CODES.includes(value);
13
26
  }
27
+ /** Plain-language reasons for denial codes the user can act on. */
28
+ const WORK_SESSION_DENIAL_REASONS = {
29
+ WORK_REGISTRY_DISABLED: "Work tracking is turned off for this company. The company owner can turn it on with: hq company --company <slug> settings set --work-registry-enabled true",
30
+ FEATURE_DISABLED: "Live work tracking is turned off for this company. The company owner can turn it on with: hq company --company <slug> settings set --work-mesh-live-enabled true",
31
+ };
32
+ /** Plain reason for a server denial code, or undefined when there is none. */
33
+ export function workSessionDenialReason(value) {
34
+ return isWorkSessionDenialCode(value)
35
+ ? WORK_SESSION_DENIAL_REASONS[value]
36
+ : undefined;
37
+ }
14
38
  //# sourceMappingURL=denial-codes.js.map
@@ -23,6 +23,7 @@ import { readDaemonState } from "./state.js";
23
23
  import { CLI_VERSION } from "../../../../cli-version.js";
24
24
  import { resolveRunningCliEntry } from "./install.js";
25
25
  import { readInstalledCliVersion } from "./version-drift.js";
26
+ import { workSessionDenialReason } from "../../denial-codes.js";
26
27
  import { LEGACY_LISTENER_DOCTOR_LINE, legacyListenInstalled, } from "./legacy-listen.js";
27
28
  export const UNHEALTHY_SPOOL_AGE_MS = 60_000;
28
29
  function oldestJsonlAgeMs(filePath, nowMs) {
@@ -321,6 +322,9 @@ export function formatDaemonDoctor(report) {
321
322
  .filter(Boolean)
322
323
  .join(" ");
323
324
  lines.push(`outbox quarantined: ${report.outboxQuarantined} (last reason=${report.outboxLastQuarantineReason ?? "unknown"}${quarantineDetails ? `; ${quarantineDetails}` : ""})`);
325
+ const denialReason = workSessionDenialReason(report.outboxLastQuarantineServerCode);
326
+ if (denialReason)
327
+ lines.push(denialReason);
324
328
  }
325
329
  if (report.emitMode !== "legacy" && report.heldCount > 0) {
326
330
  lines.push(`held: ${report.heldCount} (needs_company; not sent as NONE)`);
@@ -8,7 +8,7 @@ import * as path from "node:path";
8
8
  import { WORK_CONTEXT_CONTRACT_VERSION } from "./contract.js";
9
9
  import { atomicWriteJson, ensureOwnerDir } from "./atomic.js";
10
10
  import { NotTrackingError } from "./errors.js";
11
- import { isWorkSessionDenialCode } from "../mesh/denial-codes.js";
11
+ import { isWorkSessionDenialCode, WORK_TRACKING_OFF_DENIAL_CODES, } from "../mesh/denial-codes.js";
12
12
  import { readSessionState, stripRegisterReceiptEpisodes, updateSessionState, writeAcknowledgedRegisterBinding, } from "./state.js";
13
13
  import { isSafeWorkContextSegment, workContextOutboxDir, workContextOutboxPath, } from "./paths.js";
14
14
  /** Base delay for outbox retry backoff (attempt 1 → 30s). */
@@ -390,8 +390,14 @@ export function requeueQuarantinedOutbox(root, opts = {}) {
390
390
  for (const op of listOutboxOperations(root)) {
391
391
  if (op.delivery !== "quarantined")
392
392
  continue;
393
- if (errorCode !== null && op.lastErrorCode !== errorCode)
393
+ // Default filter: AUTH_DENIED, plus refusals stored with a server code
394
+ // that means work tracking was off for the company (a 404 FEATURE_DISABLED
395
+ // is stored as HTTP_404). An explicit errorCode matches lastErrorCode only.
396
+ const workTrackingWasOff = opts.errorCode === undefined &&
397
+ WORK_TRACKING_OFF_DENIAL_CODES.includes(op.lastServerErrorCode ?? "");
398
+ if (errorCode !== null && op.lastErrorCode !== errorCode && !workTrackingWasOff) {
394
399
  continue;
400
+ }
395
401
  op.delivery = "queued";
396
402
  op.attemptCount = 0;
397
403
  op.lastErrorCode = undefined;
@@ -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" | "login" | "mcp" | "daemon" | "daemon-logs-follow" | "mesh-daemon" | "lanes-watch" | "monitor-wait" | "monitor-run" | "agents-message-wait" | "integrations-oauth-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 {
@@ -63,6 +63,23 @@ export const RESIDENT_PACKAGE_MODULES = {
63
63
  "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
64
  "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
65
  "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"],
66
+ "secrets-sandbox": [],
67
+ "pkg-update": ["../sentry.js", "../utils/cognito-session.js", "@indigoai-us/hq-cloud"],
68
+ "pack-install": [
69
+ "../sentry.js",
70
+ "../lib/plan-limit-nag.js",
71
+ "../utils/plan-gate-error.js",
72
+ "open",
73
+ "../commands/mcp-serve.js",
74
+ "../lib/daemon/mcp-oauth.js",
75
+ "../lib/mcp/tools.js",
76
+ "../lib/mcp/prompts.js",
77
+ "../utils/sandbox-runner-client.js",
78
+ "../utils/cli-telemetry.js",
79
+ "../utils/cognito-session.js",
80
+ "../lib/first-sync-next-step.js",
81
+ "@indigoai-us/hq-cloud",
82
+ ],
66
83
  };
67
84
  const LOADERS = {
68
85
  "agent-kit": [
@@ -248,6 +265,33 @@ const LOADERS = {
248
265
  () => import("../lib/first-sync-next-step.js"),
249
266
  () => import("@indigoai-us/hq-cloud"),
250
267
  ],
268
+ "secrets-sandbox": [],
269
+ "pkg-update": [
270
+ async () => {
271
+ const { preloadSentrySdk } = await import("../sentry.js");
272
+ preloadSentrySdk();
273
+ },
274
+ () => import("../utils/cognito-session.js"),
275
+ () => import("@indigoai-us/hq-cloud"),
276
+ ],
277
+ "pack-install": [
278
+ async () => {
279
+ const { preloadSentrySdk } = await import("../sentry.js");
280
+ preloadSentrySdk();
281
+ },
282
+ () => import("../lib/plan-limit-nag.js"),
283
+ () => import("../utils/plan-gate-error.js"),
284
+ () => import("open"),
285
+ () => import("../commands/mcp-serve.js"),
286
+ () => import("../lib/daemon/mcp-oauth.js"),
287
+ () => import("../lib/mcp/tools.js"),
288
+ () => import("../lib/mcp/prompts.js"),
289
+ () => import("../utils/sandbox-runner-client.js"),
290
+ () => import("../utils/cli-telemetry.js"),
291
+ () => import("../utils/cognito-session.js"),
292
+ () => import("../lib/first-sync-next-step.js"),
293
+ () => import("@indigoai-us/hq-cloud"),
294
+ ],
251
295
  };
252
296
  export class ResidentPackagePreloadError extends Error {
253
297
  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.0",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {