@indigoai-us/hq-cli 5.131.0 → 5.132.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +111 -0
  2. package/dist/command-catalog.generated.d.ts +12 -0
  3. package/dist/command-catalog.generated.js +16 -0
  4. package/dist/commands/lanes.d.ts +13 -2
  5. package/dist/commands/lanes.js +394 -42
  6. package/dist/commands/mesh.js +20 -1
  7. package/dist/commands/update.js +1 -1
  8. package/dist/lib/bot/paths.d.ts +7 -5
  9. package/dist/lib/bot/paths.js +8 -1
  10. package/dist/lib/bot/prompt.d.ts +0 -2
  11. package/dist/lib/bot/prompt.js +5 -11
  12. package/dist/lib/bot/room-policy.d.ts +1 -24
  13. package/dist/lib/bot/room-policy.js +2 -35
  14. package/dist/lib/bot/run.d.ts +7 -8
  15. package/dist/lib/bot/run.js +21 -33
  16. package/dist/lib/bot/session.d.ts +1 -1
  17. package/dist/lib/bot/session.js +1 -1
  18. package/dist/lib/lanes/accounts.d.ts +6 -0
  19. package/dist/lib/lanes/accounts.js +2 -1
  20. package/dist/lib/lanes/config.d.ts +4 -0
  21. package/dist/lib/lanes/config.js +9 -0
  22. package/dist/lib/lanes/index.d.ts +10 -3
  23. package/dist/lib/lanes/index.js +5 -1
  24. package/dist/lib/lanes/mesh-events.js +4 -0
  25. package/dist/lib/lanes/models.d.ts +78 -0
  26. package/dist/lib/lanes/models.js +205 -0
  27. package/dist/lib/lanes/move-account.d.ts +56 -0
  28. package/dist/lib/lanes/move-account.js +193 -0
  29. package/dist/lib/lanes/provider-rejection.d.ts +86 -0
  30. package/dist/lib/lanes/provider-rejection.js +258 -0
  31. package/dist/lib/lanes/quota.d.ts +17 -0
  32. package/dist/lib/lanes/quota.js +24 -0
  33. package/dist/lib/lanes/reconcile-install.d.ts +24 -3
  34. package/dist/lib/lanes/reconcile-install.js +48 -12
  35. package/dist/lib/lanes/reconcile.js +41 -11
  36. package/dist/lib/lanes/spawn.js +26 -5
  37. package/dist/lib/lanes/store.js +10 -0
  38. package/dist/lib/lanes/types.d.ts +49 -2
  39. package/dist/lib/lanes/types.js +4 -3
  40. package/dist/lib/lanes/watcher.d.ts +27 -0
  41. package/dist/lib/lanes/watcher.js +68 -5
  42. package/dist/lib/mesh/live/backfill-held.d.ts +4 -3
  43. package/dist/lib/mesh/live/backfill-held.js +37 -14
  44. package/dist/lib/mesh/live/daemon/doctor.js +5 -2
  45. package/dist/lib/mesh/live/daemon/install.d.ts +5 -0
  46. package/dist/lib/mesh/live/daemon/install.js +84 -1
  47. package/dist/lib/mesh/live/daemon/run.d.ts +5 -0
  48. package/dist/lib/mesh/live/daemon/run.js +14 -4
  49. package/dist/lib/mesh/live/emit-evidence.d.ts +19 -0
  50. package/dist/lib/mesh/live/emit-evidence.js +20 -2
  51. package/dist/lib/work-context/company.d.ts +16 -0
  52. package/dist/lib/work-context/company.js +46 -14
  53. package/dist/utils/self-update.js +4 -1
  54. package/package.json +1 -1
@@ -37,6 +37,17 @@ export interface BuildEmitEvidenceInput {
37
37
  readMeta?: (sessionId: string, hqRoot: string | undefined) => string | undefined;
38
38
  /** Injectable work-tree finder (tests). */
39
39
  findRepo?: (startDir: string) => string | null;
40
+ /**
41
+ * Env for HQ_SPAWN_COMPANY and the identity file. Defaults to empty so a
42
+ * unit test does not inherit the developer shell. Callers that emit pass
43
+ * `process.env`.
44
+ */
45
+ env?: NodeJS.ProcessEnv;
46
+ /** Injectable machine-company reader (tests). */
47
+ readMachineCompany?: (env: NodeJS.ProcessEnv) => {
48
+ slug?: string;
49
+ uid?: string;
50
+ } | undefined;
40
51
  }
41
52
  /** Dedupe absolute-ish paths, preserving first-seen order. */
42
53
  export declare function normalizeTouchedPaths(paths: Array<string | undefined | null>): string[];
@@ -46,4 +57,12 @@ export declare function normalizeTouchedPaths(paths: Array<string | undefined |
46
57
  * first touched file). All fields are omitted when empty.
47
58
  */
48
59
  export declare function buildEmitEvidence(input: BuildEmitEvidenceInput): EmitEvidence;
60
+ /**
61
+ * A machine credential with no company must not be posted. The server would
62
+ * file it as company NONE. Hold it instead.
63
+ */
64
+ export declare function machineEmitDisposition(input: {
65
+ machine: boolean;
66
+ companySlug?: string;
67
+ }): "post" | "hold";
49
68
  //# sourceMappingURL=emit-evidence.d.ts.map
@@ -9,7 +9,7 @@
9
9
  * work-tree off disk. Never reads prompts/tokens; never hits the network.
10
10
  */
11
11
  import * as path from "node:path";
12
- import { readMetaCompanySlug } from "../../work-context/company.js";
12
+ import { readMachineCompanyBinding, readMetaCompanySlug } from "../../work-context/company.js";
13
13
  import { findWorkTreeRoot } from "../../work-context/repo-remote.js";
14
14
  function clean(v) {
15
15
  return typeof v === "string" && v.trim() ? v.trim() : undefined;
@@ -41,7 +41,16 @@ export function buildEmitEvidence(input) {
41
41
  const cwd = clean(input.cwd);
42
42
  const hqRoot = clean(input.hqRoot);
43
43
  const touchedPaths = normalizeTouchedPaths(input.touchedPaths ?? []);
44
- const companySlug = clean(input.companySlug) ?? clean(readMeta(input.sessionId, hqRoot));
44
+ const env = input.env ?? {};
45
+ const machine = (input.readMachineCompany ?? readMachineCompanyBinding)(env);
46
+ const spawned = clean(env.HQ_SPAWN_COMPANY);
47
+ // Explicit, spawn, session meta, then the box binding (slug, else uid).
48
+ // A uid with no slug still rides companySlug so the event is not company NONE.
49
+ const companySlug = clean(input.companySlug) ??
50
+ spawned ??
51
+ clean(readMeta(input.sessionId, hqRoot)) ??
52
+ (machine && machine.slug !== spawned ? clean(machine.slug) : undefined) ??
53
+ clean(machine?.uid);
45
54
  let repoPath = clean(input.repoPath);
46
55
  if (!repoPath) {
47
56
  // Search from the cwd (a directory) or the directory of the first touched
@@ -69,6 +78,15 @@ export function buildEmitEvidence(input) {
69
78
  evidence.task = task;
70
79
  return evidence;
71
80
  }
81
+ /**
82
+ * A machine credential with no company must not be posted. The server would
83
+ * file it as company NONE. Hold it instead.
84
+ */
85
+ export function machineEmitDisposition(input) {
86
+ if (input.machine && !clean(input.companySlug))
87
+ return "hold";
88
+ return "post";
89
+ }
72
90
  /** Directory of the first absolute touched file, for work-tree discovery. */
73
91
  function firstFileDir(touchedPaths) {
74
92
  const abs = touchedPaths.find((p) => path.isAbsolute(p));
@@ -77,7 +77,23 @@ export declare const DEFAULT_AGENT_IDENTITY_FILE = "/var/lib/hq-agent/identity.j
77
77
  * Missing/unreadable/malformed → undefined
78
78
  * (never throws; never logs file contents).
79
79
  */
80
+ export interface AgentIdentityCompany {
81
+ uid?: string;
82
+ slug?: string;
83
+ }
84
+ /** Company uid and slug from the fleet identity file. Missing file → undefined. */
85
+ export declare function readAgentIdentityCompany(env?: NodeJS.ProcessEnv): AgentIdentityCompany | undefined;
80
86
  export declare function readAgentIdentityCompanyUid(env?: NodeJS.ProcessEnv): string | undefined;
87
+ /**
88
+ * Company named for a machine session.
89
+ * Order: HQ_SPAWN_COMPANY, identity-file slug, identity-file uid.
90
+ * Session meta is not included; callers place it between spawn and the file.
91
+ * No company → undefined. Never invents NONE.
92
+ */
93
+ export declare function readMachineCompanyBinding(env?: NodeJS.ProcessEnv): {
94
+ slug?: string;
95
+ uid?: string;
96
+ } | undefined;
81
97
  /**
82
98
  * Agent boxes must never infer a human device default. The file itself is the
83
99
  * machine marker; legacy identity files do not necessarily contain a company
@@ -38,13 +38,7 @@ function normalizeSlug(value) {
38
38
  return undefined;
39
39
  return s;
40
40
  }
41
- /**
42
- * Read `companyUid` from the agent identity file when
43
- * `HQ_AGENT_IDENTITY_FILE` is set, or the conventional fleet path otherwise.
44
- * Missing/unreadable/malformed → undefined
45
- * (never throws; never logs file contents).
46
- */
47
- export function readAgentIdentityCompanyUid(env = process.env) {
41
+ function readAgentIdentityRecord(env) {
48
42
  // An explicit override (including empty/missing paths) never falls back to
49
43
  // another identity. This prevents accidental attribution to a different box.
50
44
  const file = (env[HQ_AGENT_IDENTITY_FILE_ENV] ?? DEFAULT_AGENT_IDENTITY_FILE).trim();
@@ -54,15 +48,49 @@ export function readAgentIdentityCompanyUid(env = process.env) {
54
48
  if (!fs.existsSync(file))
55
49
  return undefined;
56
50
  const raw = JSON.parse(fs.readFileSync(file, "utf8"));
57
- const uid = raw.companyUid;
58
- return typeof uid === "string" && uid.trim().length > 0
59
- ? uid.trim()
60
- : undefined;
51
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
52
+ return undefined;
53
+ return raw;
61
54
  }
62
55
  catch {
63
56
  return undefined;
64
57
  }
65
58
  }
59
+ /** Company uid and slug from the fleet identity file. Missing file → undefined. */
60
+ export function readAgentIdentityCompany(env = process.env) {
61
+ const raw = readAgentIdentityRecord(env);
62
+ if (!raw)
63
+ return undefined;
64
+ const uid = typeof raw.companyUid === "string" ? raw.companyUid.trim() : "";
65
+ const slug = normalizeSlug(typeof raw.companySlug === "string" ? raw.companySlug : undefined);
66
+ if (!uid && !slug)
67
+ return undefined;
68
+ return {
69
+ ...(uid ? { uid } : {}),
70
+ ...(slug ? { slug } : {}),
71
+ };
72
+ }
73
+ export function readAgentIdentityCompanyUid(env = process.env) {
74
+ return readAgentIdentityCompany(env)?.uid;
75
+ }
76
+ /**
77
+ * Company named for a machine session.
78
+ * Order: HQ_SPAWN_COMPANY, identity-file slug, identity-file uid.
79
+ * Session meta is not included; callers place it between spawn and the file.
80
+ * No company → undefined. Never invents NONE.
81
+ */
82
+ export function readMachineCompanyBinding(env = process.env) {
83
+ const spawn = normalizeSlug(env.HQ_SPAWN_COMPANY);
84
+ const identity = readAgentIdentityCompany(env);
85
+ if (spawn)
86
+ return { slug: spawn, ...(identity?.uid ? { uid: identity.uid } : {}) };
87
+ if (!identity?.slug && !identity?.uid)
88
+ return undefined;
89
+ return {
90
+ ...(identity?.slug ? { slug: identity.slug } : {}),
91
+ ...(identity?.uid ? { uid: identity.uid } : {}),
92
+ };
93
+ }
66
94
  /**
67
95
  * Agent boxes must never infer a human device default. The file itself is the
68
96
  * machine marker; legacy identity files do not necessarily contain a company
@@ -273,11 +301,15 @@ export function resolveCompany(input) {
273
301
  // 4. Agent-box identity file (HQ_AGENT_IDENTITY_FILE). Prefer as the
274
302
  // device-default role with source trusted_explicit — never device_default /
275
303
  // "default company mode". Below HQ_SPAWN_COMPANY; above device default.
276
- const identityUid = readAgentIdentityCompanyUid(env);
277
- if (identityUid) {
304
+ const identity = readAgentIdentityCompany(env);
305
+ if (identity?.uid || identity?.slug) {
278
306
  return {
279
307
  status: "resolved",
280
- company: { uid: identityUid, source: "trusted_explicit" },
308
+ company: {
309
+ ...(identity.slug ? { slug: identity.slug } : {}),
310
+ ...(identity.uid ? { uid: identity.uid } : {}),
311
+ source: "trusted_explicit",
312
+ },
281
313
  };
282
314
  }
283
315
  // 4b. Persisted per-repo company map (gap 4). A person answered once for this
@@ -282,7 +282,10 @@ async function updateAndReexec(argv, flavor, known, deps) {
282
282
  // A resident mesh daemon keeps the old JS loaded after a global install.
283
283
  // Service restart is best-effort and cannot turn a successful update red.
284
284
  try {
285
- const restart = (deps.restartDaemon ?? restartDaemonServiceIfInstalled)();
285
+ const restart = (deps.restartDaemon ?? (() => restartDaemonServiceIfInstalled({
286
+ env,
287
+ hqRoot: env.HQ_ROOT,
288
+ })))();
286
289
  if (restart?.message)
287
290
  console.error(chalk.yellow(` ${restart.message}`));
288
291
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.131.0",
3
+ "version": "5.132.0",
4
4
  "description": "HQ by Indigo management CLI \u2014 modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {