@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.
- package/CHANGELOG.md +111 -0
- package/dist/command-catalog.generated.d.ts +12 -0
- package/dist/command-catalog.generated.js +16 -0
- package/dist/commands/lanes.d.ts +13 -2
- package/dist/commands/lanes.js +394 -42
- package/dist/commands/mesh.js +20 -1
- package/dist/commands/update.js +1 -1
- package/dist/lib/bot/paths.d.ts +7 -5
- package/dist/lib/bot/paths.js +8 -1
- package/dist/lib/bot/prompt.d.ts +0 -2
- package/dist/lib/bot/prompt.js +5 -11
- package/dist/lib/bot/room-policy.d.ts +1 -24
- package/dist/lib/bot/room-policy.js +2 -35
- package/dist/lib/bot/run.d.ts +7 -8
- package/dist/lib/bot/run.js +21 -33
- package/dist/lib/bot/session.d.ts +1 -1
- package/dist/lib/bot/session.js +1 -1
- package/dist/lib/lanes/accounts.d.ts +6 -0
- package/dist/lib/lanes/accounts.js +2 -1
- package/dist/lib/lanes/config.d.ts +4 -0
- package/dist/lib/lanes/config.js +9 -0
- package/dist/lib/lanes/index.d.ts +10 -3
- package/dist/lib/lanes/index.js +5 -1
- package/dist/lib/lanes/mesh-events.js +4 -0
- package/dist/lib/lanes/models.d.ts +78 -0
- package/dist/lib/lanes/models.js +205 -0
- package/dist/lib/lanes/move-account.d.ts +56 -0
- package/dist/lib/lanes/move-account.js +193 -0
- package/dist/lib/lanes/provider-rejection.d.ts +86 -0
- package/dist/lib/lanes/provider-rejection.js +258 -0
- package/dist/lib/lanes/quota.d.ts +17 -0
- package/dist/lib/lanes/quota.js +24 -0
- package/dist/lib/lanes/reconcile-install.d.ts +24 -3
- package/dist/lib/lanes/reconcile-install.js +48 -12
- package/dist/lib/lanes/reconcile.js +41 -11
- package/dist/lib/lanes/spawn.js +26 -5
- package/dist/lib/lanes/store.js +10 -0
- package/dist/lib/lanes/types.d.ts +49 -2
- package/dist/lib/lanes/types.js +4 -3
- package/dist/lib/lanes/watcher.d.ts +27 -0
- package/dist/lib/lanes/watcher.js +68 -5
- package/dist/lib/mesh/live/backfill-held.d.ts +4 -3
- package/dist/lib/mesh/live/backfill-held.js +37 -14
- package/dist/lib/mesh/live/daemon/doctor.js +5 -2
- package/dist/lib/mesh/live/daemon/install.d.ts +5 -0
- package/dist/lib/mesh/live/daemon/install.js +84 -1
- package/dist/lib/mesh/live/daemon/run.d.ts +5 -0
- package/dist/lib/mesh/live/daemon/run.js +14 -4
- package/dist/lib/mesh/live/emit-evidence.d.ts +19 -0
- package/dist/lib/mesh/live/emit-evidence.js +20 -2
- package/dist/lib/work-context/company.d.ts +16 -0
- package/dist/lib/work-context/company.js +46 -14
- package/dist/utils/self-update.js +4 -1
- 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
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
277
|
-
if (
|
|
304
|
+
const identity = readAgentIdentityCompany(env);
|
|
305
|
+
if (identity?.uid || identity?.slug) {
|
|
278
306
|
return {
|
|
279
307
|
status: "resolved",
|
|
280
|
-
company: {
|
|
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
|
}
|