@indigoai-us/hq-cli 5.125.0 → 5.126.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 (57) hide show
  1. package/CHANGELOG.md +118 -0
  2. package/assets/bot-workers/setup/skills/joining-a-team.md +125 -0
  3. package/assets/bot-workers/setup/skills/your-business.md +270 -0
  4. package/assets/bot-workers/setup/worker.yaml +189 -58
  5. package/dist/command-catalog.generated.d.ts +407 -4
  6. package/dist/command-catalog.generated.js +522 -4
  7. package/dist/command-registration-plan.d.ts +6 -0
  8. package/dist/command-registration-plan.js +1 -0
  9. package/dist/commands/bot.d.ts +10 -0
  10. package/dist/commands/bot.js +6 -0
  11. package/dist/commands/lanes.d.ts +75 -0
  12. package/dist/commands/lanes.js +2032 -0
  13. package/dist/commands/mesh.js +37 -9
  14. package/dist/commands/onboard-create-identity.d.ts +26 -0
  15. package/dist/commands/onboard-create-identity.js +23 -0
  16. package/dist/commands/onboard.js +13 -4
  17. package/dist/lib/bot/progress.d.ts +6 -0
  18. package/dist/lib/bot/progress.js +16 -0
  19. package/dist/lib/bot/runtime/grok.d.ts +30 -7
  20. package/dist/lib/bot/runtime/grok.js +86 -8
  21. package/dist/lib/bot/runtime/index.js +15 -8
  22. package/dist/lib/bot/runtime/messages-stream.d.ts +12 -3
  23. package/dist/lib/bot/runtime/messages-stream.js +49 -3
  24. package/dist/lib/lanes/accounts.d.ts +43 -0
  25. package/dist/lib/lanes/accounts.js +128 -0
  26. package/dist/lib/lanes/config.d.ts +56 -0
  27. package/dist/lib/lanes/config.js +351 -0
  28. package/dist/lib/lanes/errors.d.ts +39 -0
  29. package/dist/lib/lanes/errors.js +72 -0
  30. package/dist/lib/lanes/index.d.ts +19 -0
  31. package/dist/lib/lanes/index.js +12 -0
  32. package/dist/lib/lanes/liveness.d.ts +89 -0
  33. package/dist/lib/lanes/liveness.js +273 -0
  34. package/dist/lib/lanes/registry.d.ts +103 -0
  35. package/dist/lib/lanes/registry.js +247 -0
  36. package/dist/lib/lanes/store.d.ts +64 -0
  37. package/dist/lib/lanes/store.js +627 -0
  38. package/dist/lib/lanes/throttle.d.ts +89 -0
  39. package/dist/lib/lanes/throttle.js +297 -0
  40. package/dist/lib/lanes/types.d.ts +193 -0
  41. package/dist/lib/lanes/types.js +217 -0
  42. package/dist/lib/mesh/live/daemon/config.d.ts +27 -0
  43. package/dist/lib/mesh/live/daemon/config.js +75 -0
  44. package/dist/lib/mesh/live/daemon/index.d.ts +4 -3
  45. package/dist/lib/mesh/live/daemon/index.js +3 -3
  46. package/dist/lib/mesh/live/daemon/install.d.ts +143 -1
  47. package/dist/lib/mesh/live/daemon/install.js +444 -2
  48. package/dist/lib/mesh/live/daemon/paths.d.ts +2 -0
  49. package/dist/lib/mesh/live/daemon/paths.js +2 -0
  50. package/dist/lib/scan-packages/index.js +17 -12
  51. package/dist/lib/work-context/config.d.ts +20 -0
  52. package/dist/lib/work-context/config.js +26 -5
  53. package/dist/lib/work-context/reconcile.js +28 -7
  54. package/dist/lib/work-context/windows-acl.d.ts +123 -0
  55. package/dist/lib/work-context/windows-acl.js +425 -0
  56. package/dist/utils/pack-contributions.js +5 -4
  57. package/package.json +1 -1
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Library layer for `hq lanes`. The command module should import from here.
3
+ */
4
+ export { AccountResolutionError, LaneNotFoundError, LaneSchemaError, LaneVersionConflict, LanesConfigError, LanesError, WorkerResolutionError, isLaneVersionConflict, isLanesError, } from "./errors.js";
5
+ export { CONFIG_SCHEMA_VERSION, ENVELOPE_DECISIONS, ENVELOPE_SCHEMA_VERSION, HISTORY_CAP, HOST_KINDS, LANE_PROVIDERS, LANE_SCHEMA_VERSION, LANE_STATES, LIVENESS_STATES, QUESTION_BODY_STORES, QUESTION_SCHEMA_VERSION, QUESTION_STATUSES, QUEUED_REASONS, RAISED_VIA, ROUTING_REASONS, SENIOR_KINDS, STORY_STATUSES, TERMINAL_LANE_STATES, isEnvelopeDecision, isHostKind, isLaneProvider, isLaneState, isLivenessState, isQuestionStatus, isSeniorKind, isTerminalLaneState, parseLaneEnvelope, parseLaneProvider, parseLaneState, parseLivenessState, parseMajorSchema, parseQuestionStatus, parseSeniorKind, } from "./types.js";
6
+ export { DEFAULT_ACCOUNT_HOMES, DEFAULT_CPU_BUSY_PAUSE, DEFAULT_CPU_BUSY_RESUME, DEFAULT_LIVE_WITHIN_MS, DEFAULT_LIVENESS_WINDOWS, DEFAULT_MAX_QUEUED, DEFAULT_MIN_AVAILABLE_MEM_MB, DEFAULT_PROVIDER_MAX_RUNNING, DEFAULT_SILENT_LOST_MS, DEFAULT_TURN_START_LOST_MS, LANES_CONFIG_REL, accountMaxRunning, canonicalizeHome, documentedDefaultConfig, expandHome, lanesConfigPath, loadLanesConfig, parseLanesConfig, writeLanesConfig, } from "./config.js";
7
+ export { LANES_STORE_REL, LANE_RECORDS_DIR, PENDING_INDEX_DIR, QUESTION_RECORDS_DIR, appendCappedHistory, appendLaneAttribution, appendLaneSeniorHistory, appendQuestionRouting, createLane, createQuestion, isConflictSidecarName, laneRecordPath, lanesStoreRoot, listLaneIds, listQuestionIds, mergeLaneRecords, mergeQuestionRecords, mintLaneId, mintQuestionId, parseLaneRecord, parseQuestionRecord, pendingMarkerPath, questionRecordPath, readLane, readQuestion, resolveStoreHqRoot, sanitizeHostComponent, tryReadLane, tryReadQuestion, updateLane, updateQuestion, } from "./store.js";
8
+ export { CPU_SAMPLE_MS, LANES_CPU_BUSY_OVERRIDE, LANES_CPU_CHECK, PROC_MEMINFO, STARVATION_MAX_DEFERRALS, STARVATION_MAX_MS, applyThrottleDecision, busyFractionFromDeltas, cpuTimesSnapshot, decideAdmission, defaultThrottleDeps, emptyThrottleState, evaluateThrottle, isCpuCheckEnabled, parseMemAvailableKb, readAvailableMemMb, readThrottleState, resolveCpuBusyFraction, sampleCpuBusyFraction, starvationBoundReached, throttleStatePath, writeThrottleState, } from "./throttle.js";
9
+ export { AUTH_JSON_NAME, PROVIDER_HOME_ENV, accountEnv, accountStatus, authJsonPath, listAccountStatuses, resolveAccount, } from "./accounts.js";
10
+ export { LIVE_WITHIN_MS, LIVENESS_EVENT_KINDS, SILENT_LOST_MS, TURN_START_LOST_MS, buildLivenessIndexFromSpool, classifySessionLiveness, defaultLivenessDeps, defaultSpoolPath, ingestSpoolLine, listSessionLiveness, livenessIndexPath, loadLivenessIndex, readLivenessIndex, rebuildLivenessIndex, sessionLiveness, } from "./liveness.js";
11
+ export { WORKER_REGISTRY_REL, personalWorkerDir, personalWorkerExists, readWorkerRegistryFile, registryPath, resolveContextBasePaths, resolveLaneWorker, resolveSkillFiles, tenancyFromRegistryPath, } from "./registry.js";
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Session liveness from the work-mesh spool (spec §9).
3
+ *
4
+ * Source: ~/.hq/work-mesh/spool.jsonl, events session_start / turn_start /
5
+ * turn_end / session_end keyed by session id. Nothing latches, including
6
+ * `ended` — a later event for a reused id supersedes session_end.
7
+ *
8
+ * An index is a single compact file (workspace/lanes/sessions/index.json).
9
+ * This module never stats workspace/sessions/.
10
+ */
11
+ import * as fs from "node:fs";
12
+ import type { LivenessState, LivenessWindows } from "./types.js";
13
+ export declare const LIVE_WITHIN_MS: number;
14
+ export declare const TURN_START_LOST_MS: number;
15
+ export declare const SILENT_LOST_MS: number;
16
+ export declare const LIVENESS_EVENT_KINDS: readonly ["session_start", "turn_start", "turn_end", "session_end"];
17
+ export type LivenessEventKind = (typeof LIVENESS_EVENT_KINDS)[number];
18
+ export interface SessionIndexEntry {
19
+ sessionId: string;
20
+ lastKind: string;
21
+ lastAt: string;
22
+ lastSeq?: number;
23
+ }
24
+ export interface LivenessIndex {
25
+ schema_version: "hq-lane-liveness-index.v1";
26
+ built_at: string;
27
+ spool_path: string;
28
+ spool_bytes: number;
29
+ spool_mtime_ms: number;
30
+ sessions: Record<string, SessionIndexEntry>;
31
+ }
32
+ export interface LivenessDeps {
33
+ now: () => number;
34
+ homedir: () => string;
35
+ env: NodeJS.ProcessEnv;
36
+ readFileSync: (file: string, encoding: "utf8") => string;
37
+ writeFileSync: typeof fs.writeFileSync;
38
+ renameSync: typeof fs.renameSync;
39
+ unlinkSync: typeof fs.unlinkSync;
40
+ existsSync: (file: string) => boolean;
41
+ mkdirSync: typeof fs.mkdirSync;
42
+ statSync: (file: string) => fs.Stats;
43
+ }
44
+ export declare function defaultLivenessDeps(): LivenessDeps;
45
+ export declare function defaultSpoolPath(deps?: LivenessDeps): string;
46
+ export declare function livenessIndexPath(hqRoot: string): string;
47
+ /**
48
+ * Classify one session from its last spool event. `ended` is not latched:
49
+ * a later event for the same id is classified from that later event.
50
+ *
51
+ * Mid-turn (`turn_start` younger than 2h) stays `live` even after the 10
52
+ * minute recency window — spec §9's prose treats that as working, not idle.
53
+ * `session_end` as the last event is `ended` even when recent (fast path).
54
+ */
55
+ export declare function classifySessionLiveness(entry: SessionIndexEntry, nowMs: number, presenceConnected?: boolean, windows?: LivenessWindows): LivenessState;
56
+ export declare function ingestSpoolLine(line: string, sessions: Record<string, SessionIndexEntry>, lineNo: number): void;
57
+ export declare function buildLivenessIndexFromSpool(spoolContents: string, meta: {
58
+ spool_path: string;
59
+ spool_bytes: number;
60
+ spool_mtime_ms: number;
61
+ built_at: string;
62
+ }): LivenessIndex;
63
+ export declare function rebuildLivenessIndex(hqRoot: string, spoolPath: string, deps?: LivenessDeps): LivenessIndex;
64
+ export declare function readLivenessIndex(hqRoot: string, deps?: LivenessDeps): LivenessIndex | null;
65
+ /**
66
+ * Return the compact index, rebuilding from the spool when missing or stale.
67
+ * Never walks workspace/sessions/.
68
+ */
69
+ export declare function loadLivenessIndex(hqRoot: string, spoolPath?: string, deps?: LivenessDeps): LivenessIndex;
70
+ export declare function sessionLiveness(hqRoot: string, sessionId: string, opts?: {
71
+ spoolPath?: string;
72
+ nowMs?: number;
73
+ presenceConnected?: boolean;
74
+ deps?: LivenessDeps;
75
+ windows?: LivenessWindows;
76
+ }): LivenessState | null;
77
+ export declare function listSessionLiveness(hqRoot: string, opts?: {
78
+ spoolPath?: string;
79
+ nowMs?: number;
80
+ presenceConnected?: boolean;
81
+ deps?: LivenessDeps;
82
+ windows?: LivenessWindows;
83
+ }): Array<{
84
+ sessionId: string;
85
+ state: LivenessState;
86
+ lastKind: string;
87
+ lastAt: string;
88
+ }>;
89
+ //# sourceMappingURL=liveness.d.ts.map
@@ -0,0 +1,273 @@
1
+ /**
2
+ * Session liveness from the work-mesh spool (spec §9).
3
+ *
4
+ * Source: ~/.hq/work-mesh/spool.jsonl, events session_start / turn_start /
5
+ * turn_end / session_end keyed by session id. Nothing latches, including
6
+ * `ended` — a later event for a reused id supersedes session_end.
7
+ *
8
+ * An index is a single compact file (workspace/lanes/sessions/index.json).
9
+ * This module never stats workspace/sessions/.
10
+ */
11
+ import * as fs from "node:fs";
12
+ import * as os from "node:os";
13
+ import * as path from "node:path";
14
+ import { workMeshSpoolPath, workMeshRoot } from "../mesh/live/paths.js";
15
+ import { DEFAULT_LIVE_WITHIN_MS, DEFAULT_SILENT_LOST_MS, DEFAULT_TURN_START_LOST_MS, loadLanesConfig, } from "./config.js";
16
+ import { lanesStoreRoot } from "./store.js";
17
+ export const LIVE_WITHIN_MS = DEFAULT_LIVE_WITHIN_MS;
18
+ export const TURN_START_LOST_MS = DEFAULT_TURN_START_LOST_MS;
19
+ export const SILENT_LOST_MS = DEFAULT_SILENT_LOST_MS;
20
+ export const LIVENESS_EVENT_KINDS = [
21
+ "session_start",
22
+ "turn_start",
23
+ "turn_end",
24
+ "session_end",
25
+ ];
26
+ export function defaultLivenessDeps() {
27
+ return {
28
+ now: () => Date.now(),
29
+ homedir: () => os.homedir(),
30
+ env: process.env,
31
+ readFileSync: (file, encoding) => fs.readFileSync(file, encoding),
32
+ writeFileSync: fs.writeFileSync.bind(fs),
33
+ renameSync: fs.renameSync.bind(fs),
34
+ unlinkSync: fs.unlinkSync.bind(fs),
35
+ existsSync: (file) => fs.existsSync(file),
36
+ mkdirSync: fs.mkdirSync.bind(fs),
37
+ statSync: (file) => fs.statSync(file),
38
+ };
39
+ }
40
+ export function defaultSpoolPath(deps = defaultLivenessDeps()) {
41
+ return workMeshSpoolPath(workMeshRoot(deps.homedir(), deps.env));
42
+ }
43
+ export function livenessIndexPath(hqRoot) {
44
+ return path.join(lanesStoreRoot(hqRoot), "sessions", "index.json");
45
+ }
46
+ function isPlainObject(value) {
47
+ return value !== null && typeof value === "object" && !Array.isArray(value);
48
+ }
49
+ /**
50
+ * Classify one session from its last spool event. `ended` is not latched:
51
+ * a later event for the same id is classified from that later event.
52
+ *
53
+ * Mid-turn (`turn_start` younger than 2h) stays `live` even after the 10
54
+ * minute recency window — spec §9's prose treats that as working, not idle.
55
+ * `session_end` as the last event is `ended` even when recent (fast path).
56
+ */
57
+ export function classifySessionLiveness(entry, nowMs, presenceConnected = false, windows = {
58
+ live_within_ms: LIVE_WITHIN_MS,
59
+ turn_start_lost_ms: TURN_START_LOST_MS,
60
+ silent_lost_ms: SILENT_LOST_MS,
61
+ }) {
62
+ const at = Date.parse(entry.lastAt);
63
+ const age = Number.isFinite(at) ? nowMs - at : Number.POSITIVE_INFINITY;
64
+ const kind = entry.lastKind;
65
+ if (kind === "session_end")
66
+ return "ended";
67
+ if (presenceConnected)
68
+ return "live";
69
+ if (kind === "turn_start" && age < windows.turn_start_lost_ms)
70
+ return "live";
71
+ if (age <= windows.live_within_ms)
72
+ return "live";
73
+ if (kind === "turn_start" && age >= windows.turn_start_lost_ms)
74
+ return "lost";
75
+ if (age >= windows.silent_lost_ms)
76
+ return "lost";
77
+ if (kind === "turn_end")
78
+ return "idle";
79
+ return "idle";
80
+ }
81
+ export function ingestSpoolLine(line, sessions, lineNo) {
82
+ const trimmed = line.trim();
83
+ if (!trimmed)
84
+ return;
85
+ let parsed;
86
+ try {
87
+ parsed = JSON.parse(trimmed);
88
+ }
89
+ catch (err) {
90
+ process.stderr.write(`lanes liveness: skipping malformed spool line ${lineNo}: ${err instanceof Error ? err.message : String(err)}\n`);
91
+ return;
92
+ }
93
+ if (!isPlainObject(parsed))
94
+ return;
95
+ const sessionId = typeof parsed.sessionId === "string" ? parsed.sessionId : "";
96
+ const kind = typeof parsed.kind === "string" ? parsed.kind : "";
97
+ const at = typeof parsed.at === "string" ? parsed.at : "";
98
+ if (!sessionId || !kind || !at)
99
+ return;
100
+ if (!Number.isFinite(Date.parse(at))) {
101
+ process.stderr.write(`lanes liveness: skipping spool line ${lineNo} with unparseable at\n`);
102
+ return;
103
+ }
104
+ const existing = sessions[sessionId];
105
+ const seq = typeof parsed.seq === "number" ? parsed.seq : undefined;
106
+ if (existing) {
107
+ const existingAt = Date.parse(existing.lastAt);
108
+ const nextAt = Date.parse(at);
109
+ if (nextAt < existingAt)
110
+ return;
111
+ if (nextAt === existingAt &&
112
+ seq !== undefined &&
113
+ existing.lastSeq !== undefined &&
114
+ seq < existing.lastSeq) {
115
+ return;
116
+ }
117
+ }
118
+ const entry = { sessionId, lastKind: kind, lastAt: at };
119
+ if (seq !== undefined)
120
+ entry.lastSeq = seq;
121
+ sessions[sessionId] = entry;
122
+ }
123
+ export function buildLivenessIndexFromSpool(spoolContents, meta) {
124
+ const sessions = {};
125
+ const lines = spoolContents.split("\n");
126
+ for (let i = 0; i < lines.length; i += 1) {
127
+ ingestSpoolLine(lines[i] ?? "", sessions, i + 1);
128
+ }
129
+ return {
130
+ schema_version: "hq-lane-liveness-index.v1",
131
+ built_at: meta.built_at,
132
+ spool_path: meta.spool_path,
133
+ spool_bytes: meta.spool_bytes,
134
+ spool_mtime_ms: meta.spool_mtime_ms,
135
+ sessions,
136
+ };
137
+ }
138
+ function atomicWriteJson(target, value, deps) {
139
+ const dir = path.dirname(target);
140
+ deps.mkdirSync(dir, { recursive: true });
141
+ const tmp = `${target}.${process.pid}.${Date.now()}.tmp`;
142
+ try {
143
+ deps.writeFileSync(tmp, `${JSON.stringify(value)}\n`, { encoding: "utf8" });
144
+ deps.renameSync(tmp, target);
145
+ }
146
+ catch (err) {
147
+ try {
148
+ deps.unlinkSync(tmp);
149
+ }
150
+ catch (unlinkErr) {
151
+ const code = unlinkErr.code;
152
+ if (code !== "ENOENT") {
153
+ process.stderr.write(`lanes liveness: unlink tmp failed for ${tmp}: ${unlinkErr instanceof Error ? unlinkErr.message : String(unlinkErr)}\n`);
154
+ }
155
+ }
156
+ throw err;
157
+ }
158
+ }
159
+ export function rebuildLivenessIndex(hqRoot, spoolPath, deps = defaultLivenessDeps()) {
160
+ let contents;
161
+ let st;
162
+ try {
163
+ st = deps.statSync(spoolPath);
164
+ contents = deps.readFileSync(spoolPath, "utf8");
165
+ }
166
+ catch (err) {
167
+ const code = err.code;
168
+ if (code === "ENOENT") {
169
+ const empty = {
170
+ schema_version: "hq-lane-liveness-index.v1",
171
+ built_at: new Date(deps.now()).toISOString(),
172
+ spool_path: spoolPath,
173
+ spool_bytes: 0,
174
+ spool_mtime_ms: 0,
175
+ sessions: {},
176
+ };
177
+ atomicWriteJson(livenessIndexPath(hqRoot), empty, deps);
178
+ return empty;
179
+ }
180
+ throw err;
181
+ }
182
+ const index = buildLivenessIndexFromSpool(contents, {
183
+ spool_path: spoolPath,
184
+ spool_bytes: st.size,
185
+ spool_mtime_ms: Math.floor(st.mtimeMs),
186
+ built_at: new Date(deps.now()).toISOString(),
187
+ });
188
+ atomicWriteJson(livenessIndexPath(hqRoot), index, deps);
189
+ return index;
190
+ }
191
+ export function readLivenessIndex(hqRoot, deps = defaultLivenessDeps()) {
192
+ const filePath = livenessIndexPath(hqRoot);
193
+ if (!deps.existsSync(filePath))
194
+ return null;
195
+ let raw;
196
+ try {
197
+ raw = deps.readFileSync(filePath, "utf8");
198
+ }
199
+ catch (err) {
200
+ process.stderr.write(`lanes liveness: failed to read index ${filePath}: ${err instanceof Error ? err.message : String(err)}\n`);
201
+ throw err;
202
+ }
203
+ try {
204
+ const parsed = JSON.parse(raw);
205
+ if (!isPlainObject(parsed) || parsed.schema_version !== "hq-lane-liveness-index.v1") {
206
+ throw new Error(`unexpected liveness index schema in ${filePath}`);
207
+ }
208
+ if (!isPlainObject(parsed.sessions)) {
209
+ throw new Error(`liveness index sessions map missing in ${filePath}`);
210
+ }
211
+ return parsed;
212
+ }
213
+ catch (err) {
214
+ process.stderr.write(`lanes liveness: invalid index ${filePath}: ${err instanceof Error ? err.message : String(err)}\n`);
215
+ throw err;
216
+ }
217
+ }
218
+ /**
219
+ * Return the compact index, rebuilding from the spool when missing or stale.
220
+ * Never walks workspace/sessions/.
221
+ */
222
+ export function loadLivenessIndex(hqRoot, spoolPath, deps = defaultLivenessDeps()) {
223
+ const spool = spoolPath ?? defaultSpoolPath(deps);
224
+ const existing = (() => {
225
+ try {
226
+ return readLivenessIndex(hqRoot, deps);
227
+ }
228
+ catch (err) {
229
+ process.stderr.write(`lanes liveness: rebuilding after invalid index: ${err instanceof Error ? err.message : String(err)}\n`);
230
+ return null;
231
+ }
232
+ })();
233
+ if (existing) {
234
+ try {
235
+ const st = deps.statSync(spool);
236
+ if (existing.spool_path === spool &&
237
+ existing.spool_bytes === st.size &&
238
+ existing.spool_mtime_ms === Math.floor(st.mtimeMs)) {
239
+ return existing;
240
+ }
241
+ }
242
+ catch (err) {
243
+ const code = err.code;
244
+ if (code !== "ENOENT")
245
+ throw err;
246
+ if (existing.spool_bytes === 0)
247
+ return existing;
248
+ }
249
+ }
250
+ return rebuildLivenessIndex(hqRoot, spool, deps);
251
+ }
252
+ export function sessionLiveness(hqRoot, sessionId, opts = {}) {
253
+ const deps = opts.deps ?? defaultLivenessDeps();
254
+ const index = loadLivenessIndex(hqRoot, opts.spoolPath, deps);
255
+ const entry = index.sessions[sessionId];
256
+ if (!entry)
257
+ return null;
258
+ const windows = opts.windows ?? loadLanesConfig(hqRoot).liveness;
259
+ return classifySessionLiveness(entry, opts.nowMs ?? deps.now(), opts.presenceConnected ?? false, windows);
260
+ }
261
+ export function listSessionLiveness(hqRoot, opts = {}) {
262
+ const deps = opts.deps ?? defaultLivenessDeps();
263
+ const index = loadLivenessIndex(hqRoot, opts.spoolPath, deps);
264
+ const nowMs = opts.nowMs ?? deps.now();
265
+ const windows = opts.windows ?? loadLanesConfig(hqRoot).liveness;
266
+ return Object.values(index.sessions).map((entry) => ({
267
+ sessionId: entry.sessionId,
268
+ state: classifySessionLiveness(entry, nowMs, opts.presenceConnected ?? false, windows),
269
+ lastKind: entry.lastKind,
270
+ lastAt: entry.lastAt,
271
+ }));
272
+ }
273
+ //# sourceMappingURL=liveness.js.map
@@ -0,0 +1,103 @@
1
+ /**
2
+ * HQ worker resolution for lanes (spec §5.3).
3
+ *
4
+ * Tenancy derives from the registry entry's `path:` prefix, never from the
5
+ * optional `company:` field. A company path with a missing or contradictory
6
+ * `company:` is `worker_tenancy_unresolved`, never a global worker.
7
+ *
8
+ * The registry does not index personal/workers/ for this command. Naming a
9
+ * personal worker fails with a clear error and does not fall through to a
10
+ * same-named entry in another tree.
11
+ */
12
+ import * as fs from "node:fs";
13
+ export declare const WORKER_REGISTRY_REL: string;
14
+ export interface RegistryWorkerEntry {
15
+ id: string;
16
+ path: string;
17
+ type: string;
18
+ visibility?: string;
19
+ company?: string;
20
+ team?: string;
21
+ status?: string;
22
+ description?: string;
23
+ }
24
+ export type WorkerTenancy = {
25
+ kind: "global";
26
+ } | {
27
+ kind: "company";
28
+ slug: string;
29
+ };
30
+ export interface WorkerYamlSkill {
31
+ id?: string;
32
+ file: string;
33
+ }
34
+ export interface WorkerYaml {
35
+ worker?: {
36
+ id?: string;
37
+ name?: string;
38
+ description?: string;
39
+ type?: string;
40
+ company?: string;
41
+ status?: string;
42
+ };
43
+ instructions?: unknown;
44
+ skills?: WorkerYamlSkill[];
45
+ context?: {
46
+ base?: string[];
47
+ };
48
+ knowledge?: unknown;
49
+ verification?: {
50
+ approval_required?: boolean;
51
+ human_checkpoints?: unknown;
52
+ };
53
+ execution?: {
54
+ max_runtime?: unknown;
55
+ model?: unknown;
56
+ codex_model?: unknown;
57
+ codex_flags?: unknown;
58
+ };
59
+ }
60
+ export interface ResolvedLaneWorker {
61
+ id: string;
62
+ path: string;
63
+ type: string;
64
+ status: string;
65
+ visibility?: string;
66
+ description?: string;
67
+ tenancy: WorkerTenancy;
68
+ workerYaml: WorkerYaml;
69
+ workerDir: string;
70
+ resolvedContextBase: string[];
71
+ skillFiles: string[];
72
+ defaultTimeout: unknown;
73
+ approvalRequired: boolean;
74
+ humanCheckpoints: string[];
75
+ }
76
+ export interface RegistryDeps {
77
+ existsSync: (p: string) => boolean;
78
+ readFileSync: (p: string, encoding: "utf8") => string;
79
+ statSync: (p: string) => fs.Stats;
80
+ }
81
+ export declare function registryPath(hqRoot: string): string;
82
+ export declare function personalWorkerDir(hqRoot: string, workerId: string): string;
83
+ export declare function personalWorkerExists(hqRoot: string, workerId: string, deps?: RegistryDeps): boolean;
84
+ export declare function readWorkerRegistryFile(hqRoot: string, deps?: RegistryDeps): RegistryWorkerEntry[];
85
+ /**
86
+ * Tenancy from path, not from `company:`. A company path whose field is
87
+ * missing or disagrees is unresolved — never global.
88
+ */
89
+ export declare function tenancyFromRegistryPath(entry: RegistryWorkerEntry): WorkerTenancy | {
90
+ kind: "unresolved";
91
+ pathSlug: string;
92
+ field?: string;
93
+ } | {
94
+ kind: "personal";
95
+ };
96
+ /**
97
+ * Resolve context.base against HQ root, then core/, then the worker directory.
98
+ * Entries that resolve nowhere are dropped, not passed on.
99
+ */
100
+ export declare function resolveContextBasePaths(hqRoot: string, workerDir: string, bases: string[] | undefined, deps?: RegistryDeps): string[];
101
+ export declare function resolveSkillFiles(workerDir: string, skills: WorkerYamlSkill[] | undefined, deps?: RegistryDeps): string[];
102
+ export declare function resolveLaneWorker(hqRoot: string, workerId: string, laneCompany: string | undefined, deps?: RegistryDeps): ResolvedLaneWorker;
103
+ //# sourceMappingURL=registry.d.ts.map