@indigoai-us/hq-cli 5.345.106 → 5.345.107

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 (53) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/assets/scaffold/core/scripts/hq-task.mjs +259 -0
  3. package/assets/scaffold/core/scripts/hq-task.sh +31 -0
  4. package/assets/scaffold/core/scripts/pipeline-worker-table.sh +285 -0
  5. package/dist/command-catalog.generated.d.ts +135 -5
  6. package/dist/command-catalog.generated.js +161 -5
  7. package/dist/commands/auth.js +42 -0
  8. package/dist/commands/core-hq-task-fast.d.ts +4 -0
  9. package/dist/commands/core-hq-task-fast.js +11 -0
  10. package/dist/commands/core-hq-task-native.d.ts +20 -0
  11. package/dist/commands/core-hq-task-native.js +275 -0
  12. package/dist/commands/core-native-bucket-c-flag.d.ts +3 -0
  13. package/dist/commands/core-native-bucket-c-flag.js +6 -0
  14. package/dist/commands/core-native-family-flag.d.ts +0 -2
  15. package/dist/commands/core-native-family-flag.js +0 -4
  16. package/dist/commands/core-native-pipeline-flag.d.ts +3 -0
  17. package/dist/commands/core-native-pipeline-flag.js +6 -0
  18. package/dist/commands/core-ontology-native.js +24 -30
  19. package/dist/commands/core-pipeline-workers-command.d.ts +3 -0
  20. package/dist/commands/core-pipeline-workers-command.js +37 -0
  21. package/dist/commands/core-pipeline-workers-native.d.ts +13 -0
  22. package/dist/commands/core-pipeline-workers-native.js +361 -0
  23. package/dist/commands/core.js +12 -10
  24. package/dist/commands/lanes.js +32 -7
  25. package/dist/commands/outposts.d.ts +5 -0
  26. package/dist/commands/outposts.js +5 -0
  27. package/dist/fast-scaffold.d.ts +1 -1
  28. package/dist/fast-scaffold.js +13 -5
  29. package/dist/hq-cloud-sync-runner/bin/sync-runner.js +56937 -64550
  30. package/dist/hq-cloud-sync-runner/package.json +1 -1
  31. package/dist/lib/daemon/remote-control-pools.d.ts +2 -2
  32. package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
  33. package/dist/lib/flag-registry-worker-source.generated.js +1 -1
  34. package/dist/lib/lanes/reconcile.js +4 -0
  35. package/dist/lib/lanes/remote-control-lane.d.ts +33 -0
  36. package/dist/lib/lanes/remote-control-lane.js +276 -0
  37. package/dist/lib/lanes/spawn.d.ts +5 -0
  38. package/dist/lib/lanes/spawn.js +65 -14
  39. package/dist/lib/lanes/store.js +7 -0
  40. package/dist/lib/lanes/types.d.ts +2 -0
  41. package/dist/lib/lanes/types.js +1 -1
  42. package/dist/lib/lanes/watcher.js +8 -1
  43. package/dist/utils/cognito-session.d.ts +12 -4
  44. package/dist/utils/cognito-session.js +42 -9
  45. package/dist/utils/token-keychain.d.ts +96 -0
  46. package/dist/utils/token-keychain.js +218 -0
  47. package/package.json +2 -2
  48. package/assets/scaffold/core/scripts/ontology-audience-grant.sh +0 -81
  49. package/assets/scaffold/core/scripts/ontology-brief.mjs +0 -93
  50. package/assets/scaffold/core/scripts/ontology-candidate.sh +0 -100
  51. package/assets/scaffold/core/scripts/ontology-garden.mjs +0 -327
  52. package/assets/scaffold/core/scripts/ontology-source-worklist.sh +0 -226
  53. package/assets/scaffold/core/scripts/source-yaml-validate.sh +0 -36
@@ -0,0 +1,361 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ export const PIPELINE_WORKER_TABLE_ASSET = "core/scripts/pipeline-worker-table.sh";
4
+ export const CORE_NATIVE_PIPELINE_FLAG = "core-native-pipeline";
5
+ const USAGE = "# pipeline-worker-table.sh — the per-worker engine/model table behind\n# /run-project --pipeline.\n#\n# Each worker lane runs on its own engine and model. This script proposes that\n# table from a prd.json and, once the owner has confirmed it, turns it into the\n# launcher exports each lane starts with. It never reads an engine or model\n# default from a settings file (orchestrator.yaml, settings.json, ...): the only\n# seed is each worker's own worker.yaml, and anything that cannot be read off\n# it is left empty and flagged for the owner to answer.\n#\n# Usage:\n# pipeline-worker-table.sh [--workers-root <dir>]... [--overlay <file>] <prd.json>\n# pipeline-worker-table.sh [--workers-root <dir>]... [--overlay <file>] --confirmed <table.tsv> <prd.json>\n#\n# PROPOSE MODE (no --confirmed) prints tab-separated lines:\n#\n# row <worker> <engine> <model> <effort> <status> <stories> <note>\n# hint <worker> <story> <model>\n# unclassified <story>\n#\n# status is `ok` or `needs-answer`. The lane set is the union of every\n# story's worker sequence: one `row` per distinct worker that appears in any\n# sequence (architect and qa-tester included), in first-seen order. A `hint`\n# line is a story's model_hint, shown for the owner; a confirmed table pin wins\n# over it (see CONFIRMED MODE).\n#\n# WORKER SEQUENCE (story -> workers, the full phase sequence in order), first\n# match wins; pipeline-conductor.sh classify reads the same three sources:\n# 1. --overlay <file> (the run's <state>/overlay.json, or the preflight plan):\n# {id: {\"worker_sequence\": [...]}}, {id: [...]}, or\n# {\"ordered_stories\": [{\"id\": .., \"worker_sequence\": [...]}]}.\n# 2. worker_preference — a string or an array of worker ids, used as given.\n# 3. Fallback, only when both are empty: the keyword table from\n# .claude/skills/execute-task/SKILL.md step 3, matched case-insensitively\n# against title + description + labels:\n# schema_change (database|migration|schema|prisma|sql) -> database-dev\n# ui_component (component|page|form|button|react|ui) -> frontend-dev\n# api_development (endpoint|api|rest|graphql|route|service) -> backend-dev\n# giving architect, the matched implementers (backend-dev also for a\n# schema change), then qa-tester.\n# A story matching none is printed as `unclassified`; no worker is guessed.\n#\n# UNKNOWN WORKERS: a worker with no worker.yaml under the worker roots gets an\n# empty, needs-answer row noted \"no worker.yaml\", and a line on stderr naming\n# the id, the roots searched and every known id. pipeline-conductor.sh classify\n# refuses such a worker before launch.\n#\n# ENGINE SEED (from worker.yaml `execution:`):\n# model only -> engine claude, model = execution.model\n# codex_model only -> engine codex, model = execution.codex_model,\n# effort = `--reasoning <x>` from execution.codex_flags\n# both set -> ambiguous: engine and model empty, needs-answer, the\n# candidates listed in the note column\n# neither / no file -> engine and model empty, needs-answer\n# worker.yaml has no grok field, so grok is never seeded; the owner chooses it\n# in the confirmed table.\n#\n# CONFIRMED MODE: --confirmed <file> holds one lane per line,\n# <worker> <engine> <model> <effort> (tabs or spaces; # comments allowed;\n# effort may be omitted). engine must be claude, codex, or grok and model must\n# be non-empty, or the script exits 2. Output per lane, using the pins in\n# core/scripts/workflow-runner.mjs, plus HQ_CONDUCT_ENGINE=<engine> for\n# every lane (a loop lane runs pipeline phase envelopes on that engine):\n# claude -> HQ_WORKFLOW_CLAUDE_PLAN_MODEL, HQ_WORKFLOW_CLAUDE_EXEC_MODEL,\n# HQ_WORKFLOW_CLAUDE_EFFORT\n# codex|grok -> HQ_WORKFLOW_MODEL, HQ_WORKFLOW_EFFORT\n# The effort export is omitted when effort is empty (runner default applies).\n# A story's model_hint never overrides the lane: the lane's table pin wins.\n# Each hinted story on a confirmed lane gets a `# lane <w> story <id>\n# (model_hint)` block whose exports are commented out and that says \"hint\n# ignored, table pins <model>\". A bare alias (opus, sonnet, haiku, fable) is\n# never printed as a model.\n#\n# Worker roots: --workers-root (repeatable) or PIPELINE_WORKERS_ROOTS\n# (colon-separated). Default: <hq>/core/workers, <hq>/companies/*/workers,\n# <hq>/personal/workers. A worker is the directory named <id> holding worker.yaml.\n#\n# POSIX sh (dash-clean); JSON work is done by jq.\n";
6
+ function isRecord(value) {
7
+ return value !== null && typeof value === "object" && !Array.isArray(value);
8
+ }
9
+ function stringValue(value) {
10
+ if (value === null || value === undefined)
11
+ return "null";
12
+ if (typeof value === "string")
13
+ return value;
14
+ return JSON.stringify(value);
15
+ }
16
+ function sequence(value) {
17
+ if (Array.isArray(value))
18
+ return value.filter((item) => typeof item === "string" && item.length > 0);
19
+ if (typeof value === "string")
20
+ return value.split(",").map((item) => item.trim()).filter(Boolean);
21
+ if (isRecord(value))
22
+ return sequence(value.worker_sequence ?? []);
23
+ return [];
24
+ }
25
+ function asciiLower(text) {
26
+ return text.replace(/[A-Z]/g, (letter) => letter.toLowerCase());
27
+ }
28
+ function storyText(story) {
29
+ const title = story.title ?? "";
30
+ const description = story.description ?? "";
31
+ const labels = Array.isArray(story.labels) ? story.labels.join(" ") : "";
32
+ return asciiLower([stringValue(title === "" ? "" : title), stringValue(description === "" ? "" : description), labels].join(" "));
33
+ }
34
+ const WORD = {
35
+ schema: /\b(database|migration|schema|prisma|sql)\b/,
36
+ ui: /\b(component|page|form|button|react|ui)\b/,
37
+ api: /\b(endpoint|api|rest|graphql|route|service)\b/,
38
+ };
39
+ function fallbackSequence(story) {
40
+ const text = storyText(story);
41
+ const schema = WORD.schema.test(text);
42
+ const ui = WORD.ui.test(text);
43
+ const api = WORD.api.test(text);
44
+ if (!schema && !ui && !api)
45
+ return [];
46
+ return [
47
+ "architect",
48
+ ...(schema ? ["database-dev"] : []),
49
+ ...(api || schema ? ["backend-dev"] : []),
50
+ ...(ui ? ["frontend-dev"] : []),
51
+ "qa-tester",
52
+ ];
53
+ }
54
+ function storyId(story) {
55
+ return story.id === null || story.id === undefined ? "" : stringValue(story.id);
56
+ }
57
+ function deriveSequences(stories, overlay) {
58
+ const overrides = {};
59
+ if (Array.isArray(overlay.ordered_stories)) {
60
+ for (const row of overlay.ordered_stories) {
61
+ if (isRecord(row) && typeof row.id === "string")
62
+ overrides[row.id] = sequence(row.worker_sequence ?? []);
63
+ }
64
+ }
65
+ else {
66
+ for (const [id, value] of Object.entries(overlay))
67
+ overrides[id] = sequence(value);
68
+ }
69
+ return stories.map((story) => {
70
+ const id = storyId(story);
71
+ const override = overrides[id] ?? [];
72
+ const preferred = sequence(story.worker_preference ?? []);
73
+ const workers = override.length > 0 ? override : preferred.length > 0 ? preferred : fallbackSequence(story);
74
+ return { id, workers, story };
75
+ });
76
+ }
77
+ function parseArgs(args) {
78
+ const roots = [];
79
+ let confirmed = "";
80
+ let overlay = "";
81
+ let prd = "";
82
+ for (let i = 0; i < args.length; i += 1) {
83
+ const arg = args[i];
84
+ if (arg === "--workers-root" || arg === "--confirmed" || arg === "--overlay") {
85
+ const value = args[i + 1];
86
+ if (value === undefined)
87
+ return `${arg} needs ${arg === "--workers-root" ? "a dir" : "a file"}`;
88
+ if (arg === "--workers-root")
89
+ roots.push(value);
90
+ if (arg === "--confirmed")
91
+ confirmed = value;
92
+ if (arg === "--overlay")
93
+ overlay = value;
94
+ i += 1;
95
+ }
96
+ else if (arg === "-h" || arg === "--help") {
97
+ return { roots, confirmed, overlay, prd, help: true };
98
+ }
99
+ else if (arg.startsWith("-")) {
100
+ return `unknown flag: ${arg}`;
101
+ }
102
+ else if (!prd) {
103
+ prd = arg;
104
+ }
105
+ else {
106
+ return "only one prd.json";
107
+ }
108
+ }
109
+ if (!prd)
110
+ return "usage: pipeline-worker-table.sh [--workers-root <dir>] [--overlay <file>] [--confirmed <table.tsv>] <prd.json>";
111
+ return { roots, confirmed, overlay, prd, help: false };
112
+ }
113
+ function readJson(file) {
114
+ return JSON.parse(fs.readFileSync(file, "utf8"));
115
+ }
116
+ export function pipelineWorkerRoots(argsRoots, root, env) {
117
+ if (argsRoots.length > 0)
118
+ return argsRoots;
119
+ if (env.PIPELINE_WORKERS_ROOTS !== undefined)
120
+ return env.PIPELINE_WORKERS_ROOTS.split(":");
121
+ const roots = [path.join(root, "core/workers")];
122
+ const companies = path.join(root, "companies");
123
+ try {
124
+ for (const name of fs.readdirSync(companies).sort()) {
125
+ const workers = path.join(companies, name, "workers");
126
+ try {
127
+ if (fs.statSync(workers).isDirectory())
128
+ roots.push(workers);
129
+ }
130
+ catch { /* shell skips missing company worker roots */ }
131
+ }
132
+ }
133
+ catch { /* shell glob has no matches when companies is absent */ }
134
+ roots.push(path.join(root, "personal/workers"));
135
+ return roots;
136
+ }
137
+ export function pipelineWorkerFallbackArgs(args, root, env) {
138
+ if (args.includes("--workers-root") || env.PIPELINE_WORKERS_ROOTS !== undefined)
139
+ return args;
140
+ const roots = pipelineWorkerRoots([], root, env);
141
+ return [...roots.flatMap((workerRoot) => ["--workers-root", workerRoot]), ...args];
142
+ }
143
+ function listWorkerYaml(root) {
144
+ const results = [];
145
+ const stack = [root];
146
+ while (stack.length > 0) {
147
+ const current = stack.pop();
148
+ let entries;
149
+ try {
150
+ entries = fs.readdirSync(current, { withFileTypes: true });
151
+ }
152
+ catch {
153
+ continue;
154
+ }
155
+ for (let i = entries.length - 1; i >= 0; i -= 1) {
156
+ const entry = entries[i];
157
+ const file = path.join(current, entry.name);
158
+ if (entry.isDirectory())
159
+ stack.push(file);
160
+ else if (entry.isFile() && entry.name === "worker.yaml")
161
+ results.push(file);
162
+ }
163
+ }
164
+ return results;
165
+ }
166
+ function findWorkerYaml(worker, roots) {
167
+ for (const root of roots) {
168
+ for (const file of listWorkerYaml(root)) {
169
+ if (path.basename(path.dirname(file)) === worker)
170
+ return file;
171
+ }
172
+ }
173
+ return undefined;
174
+ }
175
+ function knownWorkers(roots) {
176
+ return [...new Set(roots.flatMap((root) => listWorkerYaml(root).map((file) => path.basename(path.dirname(file)))))].sort();
177
+ }
178
+ function executionField(file, key) {
179
+ let text;
180
+ try {
181
+ text = fs.readFileSync(file, "utf8");
182
+ }
183
+ catch {
184
+ return "";
185
+ }
186
+ let inExecution = false;
187
+ for (const line of text.split(/\r?\n/)) {
188
+ if (/^[^\s#]/.test(line)) {
189
+ inExecution = /^execution:\s*$/.test(line);
190
+ continue;
191
+ }
192
+ if (!inExecution)
193
+ continue;
194
+ const match = new RegExp(`^[\\t ]+${key}:[\\t ]*(.*)$`).exec(line);
195
+ if (!match)
196
+ continue;
197
+ let value = match[1].replace(/[\t ]+#.*$/, "").replace(/[\t ]+$/, "");
198
+ if (value.startsWith("\"") || value.startsWith("'"))
199
+ value = value.slice(1);
200
+ if (value.endsWith("\"") || value.endsWith("'"))
201
+ value = value.slice(0, -1);
202
+ return value;
203
+ }
204
+ return "";
205
+ }
206
+ function quoteShell(value) {
207
+ return `'${value.replace(/'/g, "'\\''")}'`;
208
+ }
209
+ function emitExports(engine, model, effort, prefix = "") {
210
+ let output = `${prefix}export HQ_CONDUCT_ENGINE=${quoteShell(engine)}\n`;
211
+ if (engine === "claude") {
212
+ output += `${prefix}export HQ_WORKFLOW_CLAUDE_PLAN_MODEL=${quoteShell(model)}\n`;
213
+ output += `${prefix}export HQ_WORKFLOW_CLAUDE_EXEC_MODEL=${quoteShell(model)}\n`;
214
+ if (effort)
215
+ output += `${prefix}export HQ_WORKFLOW_CLAUDE_EFFORT=${quoteShell(effort)}\n`;
216
+ }
217
+ else if (engine === "codex" || engine === "grok") {
218
+ output += `${prefix}export HQ_WORKFLOW_MODEL=${quoteShell(model)}\n`;
219
+ if (effort)
220
+ output += `${prefix}export HQ_WORKFLOW_EFFORT=${quoteShell(effort)}\n`;
221
+ }
222
+ return output;
223
+ }
224
+ function bareAlias(hint) {
225
+ return ["opus", "sonnet", "haiku", "fable", "Opus", "Sonnet", "Haiku", "Fable"].includes(hint);
226
+ }
227
+ function confirmedOutput(file, stories, sequences) {
228
+ let text;
229
+ try {
230
+ text = fs.readFileSync(file, "utf8");
231
+ }
232
+ catch {
233
+ return { code: 1, stdout: "", stderr: `pipeline-worker-table: no such confirmed table: ${file}\n` };
234
+ }
235
+ let stdout = "";
236
+ for (const line of text.split(/\r?\n/)) {
237
+ const columns = line.trim().split(/\s+/);
238
+ if (!columns[0] || columns[0].startsWith("#") || columns[0] === "worker")
239
+ continue;
240
+ const [worker, engine, model, effort = ""] = columns;
241
+ if (!(engine === "claude" || engine === "codex" || engine === "grok")) {
242
+ return { code: 2, stdout: "", stderr: `pipeline-worker-table: lane ${worker}: engine must be claude, codex, or grok (got '${engine ?? ""}')\n` };
243
+ }
244
+ if (!model)
245
+ return { code: 2, stdout: "", stderr: `pipeline-worker-table: lane ${worker}: model is empty — answer it before launch\n` };
246
+ stdout += `# lane ${worker} (${engine})\n${emitExports(engine, model, effort)}`;
247
+ for (const story of stories) {
248
+ const id = storyId(story);
249
+ const hint = story.model_hint !== null && story.model_hint !== undefined && story.model_hint !== "" ? stringValue(story.model_hint) : "";
250
+ if (!hint || !sequences.some((row) => row.id === id && row.workers.includes(worker)))
251
+ continue;
252
+ if (bareAlias(hint))
253
+ stdout += `# lane ${worker} story ${id} (model_hint) bare alias ignored, table pins ${model}\n`;
254
+ else {
255
+ stdout += `# lane ${worker} story ${id} (model_hint) hint ignored, table pins ${model}\n`;
256
+ stdout += emitExports(engine, hint, effort, "# ");
257
+ }
258
+ }
259
+ }
260
+ return { code: 0, stdout, stderr: "" };
261
+ }
262
+ export function runPipelineWorkerTable(args, root, env = process.env) {
263
+ const parsed = parseArgs(args);
264
+ if (typeof parsed === "string")
265
+ return { code: parsed.startsWith("usage:") ? 1 : 1, stdout: "", stderr: `pipeline-worker-table: ${parsed}\n` };
266
+ if (parsed.help)
267
+ return { code: 0, stdout: USAGE, stderr: "" };
268
+ let prd;
269
+ try {
270
+ prd = readJson(parsed.prd);
271
+ }
272
+ catch {
273
+ return { code: 1, stdout: "", stderr: `pipeline-worker-table: not a prd (no userStories array): ${parsed.prd}\n` };
274
+ }
275
+ if (!isRecord(prd) || !Array.isArray(prd.userStories))
276
+ return { code: 1, stdout: "", stderr: `pipeline-worker-table: not a prd (no userStories array): ${parsed.prd}\n` };
277
+ let overlay = {};
278
+ if (parsed.overlay) {
279
+ try {
280
+ overlay = readJson(parsed.overlay);
281
+ }
282
+ catch {
283
+ return { code: 1, stdout: "", stderr: `pipeline-worker-table: overlay is not a JSON object: ${parsed.overlay}\n` };
284
+ }
285
+ if (!isRecord(overlay))
286
+ return { code: 1, stdout: "", stderr: `pipeline-worker-table: overlay is not a JSON object: ${parsed.overlay}\n` };
287
+ }
288
+ if (parsed.confirmed) {
289
+ if (!fs.existsSync(parsed.confirmed))
290
+ return { code: 1, stdout: "", stderr: `pipeline-worker-table: no such confirmed table: ${parsed.confirmed}\n` };
291
+ return confirmedOutput(parsed.confirmed, prd.userStories, deriveSequences(prd.userStories, overlay));
292
+ }
293
+ const roots = pipelineWorkerRoots(parsed.roots, root, env);
294
+ const sequences = deriveSequences(prd.userStories, overlay);
295
+ const workers = [];
296
+ const seen = new Set();
297
+ for (const row of sequences)
298
+ for (const worker of row.workers)
299
+ if (!seen.has(worker)) {
300
+ seen.add(worker);
301
+ workers.push(worker);
302
+ }
303
+ let stdout = "";
304
+ let stderr = "";
305
+ for (const row of sequences)
306
+ if (row.workers.length === 0)
307
+ stdout += `unclassified\t${row.id}\n`;
308
+ for (const worker of workers) {
309
+ const file = findWorkerYaml(worker, roots);
310
+ let engine = "";
311
+ let model = "";
312
+ let effort = "";
313
+ let status = "needs-answer";
314
+ let note = "";
315
+ if (!file) {
316
+ note = "no worker.yaml";
317
+ const rootText = roots.join(" ");
318
+ const known = knownWorkers(roots).join(" ") || "none";
319
+ stderr += `pipeline-worker-table: unknown worker ${worker}: no worker.yaml under ${rootText}; known: ${known}\n`;
320
+ }
321
+ else {
322
+ const claudeModel = executionField(file, "model");
323
+ const codexModel = executionField(file, "codex_model");
324
+ if (claudeModel && codexModel)
325
+ note = `ambiguous: claude:${claudeModel} codex:${codexModel}`;
326
+ else if (claudeModel) {
327
+ engine = "claude";
328
+ model = claudeModel;
329
+ status = "ok";
330
+ }
331
+ else if (codexModel) {
332
+ engine = "codex";
333
+ model = codexModel;
334
+ status = "ok";
335
+ const flags = executionField(file, "codex_flags");
336
+ effort = /.*--reasoning[= ]([A-Za-z]*).*/.exec(flags)?.[1] ?? "";
337
+ }
338
+ else
339
+ note = "no execution.model or execution.codex_model";
340
+ }
341
+ const storiesText = sequences.filter((row) => row.workers.includes(worker)).map((row) => row.id).join(" ");
342
+ stdout += `row\t${worker}\t${engine}\t${model}\t${effort}\t${status}\t${storiesText}\t${note}\n`;
343
+ }
344
+ for (const story of prd.userStories) {
345
+ const hint = story.model_hint !== null && story.model_hint !== undefined && story.model_hint !== "" ? stringValue(story.model_hint) : "";
346
+ if (!hint)
347
+ continue;
348
+ const id = storyId(story);
349
+ for (const worker of sequences.find((row) => row.id === id)?.workers ?? [])
350
+ stdout += `hint\t${worker}\t${id}\t${hint}\n`;
351
+ }
352
+ return { code: 0, stdout, stderr };
353
+ }
354
+ export function writePipelineWorkerTableResult(result) {
355
+ if (result.stdout)
356
+ process.stdout.write(result.stdout);
357
+ if (result.stderr)
358
+ process.stderr.write(result.stderr);
359
+ return result.code;
360
+ }
361
+ //# sourceMappingURL=core-pipeline-workers-native.js.map
@@ -50,6 +50,7 @@ import { registerCoreDeriveTriggerFactsCommand } from "./core-derive-trigger-fac
50
50
  import { DERIVE_TRIGGER_FACTS_ASSET } from "./core-derive-trigger-facts-native.js";
51
51
  import { registerCoreHookStateHelpers } from "./core-hook-state-helpers-native.js";
52
52
  import { registerCoreHookBatchCommand } from "./core-hook-batch-command.js";
53
+ import { registerCorePipelineWorkerTableCommand } from "./core-pipeline-workers-command.js";
53
54
  import { resolveLiveRoot } from "../utils/hq-roots.js";
54
55
  import { interpreterFor, runBundledScript } from "../utils/run-bundled-script.js";
55
56
  import { CompanyIndexUserError, renderIndexTarget } from "../lib/index-render/index.js";
@@ -218,6 +219,12 @@ export const REBUILD_INDEX_TARGETS = [
218
219
  * would make the forwarders harder to audit against this table.
219
220
  */
220
221
  export const SCAFFOLD_COMMANDS = [
222
+ {
223
+ name: "hq-task",
224
+ asset: "core/scripts/hq-task.sh",
225
+ root: "live",
226
+ summary: "List and update tasks on personal or company boards",
227
+ },
221
228
  // Session/harness plumbing relocated out of the HQ tree so a single published
222
229
  // CLI owns it. Both are `root: "live"`: they read and write the live HQ tree
223
230
  // (workspace/sessions, companies/, workspace/orchestrator/hook-state), so the
@@ -243,6 +250,7 @@ export const SCAFFOLD_COMMANDS = [
243
250
  * direct `hq core` command.
244
251
  */
245
252
  export const SCAFFOLD_ONLY_ASSETS = [
253
+ { asset: "core/scripts/hq-task.mjs", root: "live", summary: "Sibling implementation used by the hq-task shell rollback companion" },
246
254
  { asset: "core/scripts/session-journal.sh", root: "live", summary: "Rollback companion for native session journal" },
247
255
  { asset: "core/scripts/session-project.sh", root: "live", summary: "Rollback companion for native session project" },
248
256
  { asset: "core/scripts/session-title.sh", root: "live", summary: "Rollback companion for native session title" },
@@ -255,6 +263,7 @@ export const SCAFFOLD_ONLY_ASSETS = [
255
263
  { asset: "core/scripts/hq-job-run.sh", root: "live", summary: "Scheduled jobs runner used by generated systemd units" },
256
264
  { asset: "core/scripts/hq-job-notify.sh", root: "live", summary: "Scheduled jobs failure notification helper" },
257
265
  { asset: "core/scripts/hq-job-remediate.sh", root: "live", summary: "Scheduled jobs bounded remediation helper" },
266
+ { asset: "core/scripts/pipeline-worker-table.sh", root: "live", summary: "Rollback companion for native pipeline worker-table" },
258
267
  { asset: "core/scripts/hq-dm-bind.sh", root: "live", summary: "Rollback shell for native dm-bind" },
259
268
  { asset: "core/scripts/work-mesh-live-bind-trusted.sh", root: "live", summary: "Rollback shell for native work-mesh-bind-trusted" },
260
269
  { asset: "core/scripts/share-suggestion-state.sh", root: "live", summary: "Rollback shell for native share-suggestion-state" },
@@ -295,16 +304,8 @@ export const SCAFFOLD_ONLY_ASSETS = [
295
304
  { asset: "core/scripts/hq-delegate-send.sh", root: "live", summary: "Rollback shell for native delegate send" },
296
305
  { asset: "core/scripts/hq-delegate-verify.sh", root: "live", summary: "Rollback shell for native delegate verify" },
297
306
  { asset: "core/scripts/lib/secret-patterns.sh", root: "live", summary: "Secret-pattern library sourced by the delegate rollback shells" },
298
- // Retained rollback companions for the gated native ontology commands. These
299
- // are loose HQ-tree assets, but `hq core ontology` dispatches natively.
300
- { asset: "core/scripts/ontology-audience-grant.sh", root: "live", summary: "Rollback companion for native ontology audience grant" },
301
- { asset: "core/scripts/ontology-brief.mjs", root: "live", summary: "Rollback companion for native ontology brief" },
302
- { asset: "core/scripts/ontology-candidate.sh", root: "live", summary: "Rollback companion for native ontology candidate" },
303
- { asset: "core/scripts/ontology-garden.mjs", root: "live", summary: "Rollback companion for native ontology garden" },
304
- { asset: "core/scripts/ontology-source-worklist.sh", root: "live", summary: "Rollback companion for native ontology source worklist" },
305
- { asset: "core/scripts/source-yaml-validate.sh", root: "cwd", summary: "Rollback companion for native source YAML validation" },
306
- // Shared by native knowledge-prefs and the ontology candidate shell fallback.
307
- { asset: "core/scripts/knowledge-prefs.sh", root: "live", summary: "Sibling dependency for ontology candidate rollback companion" },
307
+ // Native knowledge-prefs retains its own shell companion until its family PR.
308
+ { asset: "core/scripts/knowledge-prefs.sh", root: "live", summary: "Rollback companion for native knowledge-prefs" },
308
309
  // Rollback companions for the default-off native knowledge and policy routes.
309
310
  // policy-retire also runs the scaffold validator in-process when native, but
310
311
  // its bundled shell fallback needs both helper assets at these exact paths.
@@ -412,6 +413,7 @@ export function registerCoreCommands(program) {
412
413
  registerCoreKnowledgePrefsCommand(core);
413
414
  registerCorePolicyCommand(core);
414
415
  registerCoreJobsNativeCommand(core);
416
+ registerCorePipelineWorkerTableCommand(core);
415
417
  registerCoreResolveCompanyNativeCommand(core);
416
418
  registerCoreAuditLogNative(core);
417
419
  registerCoreGitPackExtensionCheckNative(core);
@@ -73,6 +73,7 @@ import { createLaneMesh, emitLaneDecisionEvents, emitLaneTerminalStateEvent, lan
73
73
  import { sessionIdFromEnv } from "../lib/mesh/live/session-identity.js";
74
74
  import { listLaneReviews } from "../lib/lanes/reviews.js";
75
75
  import { effectiveAccountHome } from "../lib/lanes/account-home.js";
76
+ import { remoteControlSelectionConfig, remoteControlSessionHome } from "../lib/lanes/remote-control-lane.js";
76
77
  import { AccountResolutionError, compareLaneQueueOrder, LANE_PROVIDERS, LANE_STATES, QUESTION_STATUSES, SENIOR_KINDS, accountStatus, appendCappedHistory, canonicalizeHome, createLane, decideAdmission, defaultLivenessDeps, defaultSystemdUserDir, defaultThrottleDeps, installReconcileTimer, providerPathEnv, probeDrainHookRegistration, isLanesError, isLaneVersionConflict, isTerminalLaneState, isFinishedResumableHireChild, childrenHoldingHireGrantCarve, laneHoldsHireGrantCarve, assignedChildHireGrants, hireGrantCapacityError, planHireGrantBackfill, terminalChildResumeHireGrantError, withHireGrantAdmission, laneStoryLedgerEnabled, syncLaneToProjectStoryLedger, removeLaneFromProjectStoryLedger, validateProjectStories, buildLaneStatusSnapshot, formatLaneStatusHuman, listLaneIds, listQuestionIds, loadLanesConfig, laneRunsHere, MAX_LANE_DEPTH, MONITOR_ERROR_EXIT_CODE, readLiveMonitorEvidence, resolveMachineIdentity as lookupMachineIdentity, loadLivenessIndex, parseLaneProvider, parseLaneRecord, parseLaneState, parseQuestionRecord, parseSeniorKind, readAllLanes, readLane, sanitizeHostComponent, retryUpdateLane, syncLaneRecordFromOwner, readQuestion, resolveAccount, resolveLaneWorker, ignoredWorkerProfileFields, loadWorkerProfile, loadWorkerProfileWithRegistry, registryWorkerRecord, runReconcilePass, DEAD_HOST_MS, sessionLiveness, tryReadLane, uninstallReconcileTimer, updateLane, updateQuestion, dropboxDir, laneDeliveryMechanism, hasActiveAdmissionReservation, hasActivePendingResume, hasRecordedSessionId, hasEarlierEligibleQueuedLane, laneAdmissionCapReason, providerSupportsSessionResume, providerSessionPortable, isFailedQuotaKeepAliveLane, sessionNotPortableMessage, withLaneAdmissionLock, withAllLaneAdmissionLocks, readWorkerRunResult, resumeCommandRefusal, withLaneHireLocks, raiseLaneQuestion, sha256Text, } from "../lib/lanes/index.js";
77
78
  import { laneStories, storyWarning, } from "../lib/lanes/stories.js";
78
79
  import { resolveLaneKeepAlive } from "../lib/lanes/profile.js";
@@ -3350,6 +3351,9 @@ async function runCreate(ctx, opts) {
3350
3351
  if (opts.loop === true && (opts.outpost?.trim() || requestedPlacement?.kind === "outpost" || defaultPlacement?.kind === "outpost")) {
3351
3352
  throw new LanesError("loop_lane_outpost_unsupported", "Loop lanes currently require the local host", { outpost_id: opts.outpost?.trim() ?? (requestedPlacement?.kind === "outpost" ? requestedPlacement.id : defaultPlacement?.kind === "outpost" ? defaultPlacement.id : undefined) });
3352
3353
  }
3354
+ if (opts.remoteControl === true && (opts.outpost?.trim() || requestedPlacement?.kind === "outpost" || defaultPlacement?.kind === "outpost")) {
3355
+ throw new LanesError("remote_control_outpost_unsupported", "--remote-control requires the local daemon account pools", {});
3356
+ }
3353
3357
  let placementCompanyResolved = false;
3354
3358
  let placementCompany;
3355
3359
  let placementGate;
@@ -3391,8 +3395,11 @@ async function runCreate(ctx, opts) {
3391
3395
  const profile = resolvedWorker?.profile;
3392
3396
  const provider = explicitProvider ??
3393
3397
  profile?.meta.provider ??
3394
- parseLaneProvider("codex");
3395
- const continuityEnabled = opts.worker !== undefined && await readLanesRegistryFlagFailOpen(LANE_WORKER_CONTINUITY_FLAG, { company: company ?? meshCompany, env: ctx.env, defaultValue: true });
3398
+ parseLaneProvider(opts.remoteControl === true ? "claude" : "codex");
3399
+ if (opts.remoteControl === true && provider !== "claude") {
3400
+ throw new LanesError("remote_control_requires_claude", "--remote-control requires a Claude lane", { provider });
3401
+ }
3402
+ const continuityEnabled = opts.remoteControl !== true && opts.worker !== undefined && await readLanesRegistryFlagFailOpen(LANE_WORKER_CONTINUITY_FLAG, { company: company ?? meshCompany, env: ctx.env, defaultValue: true });
3396
3403
  let workerContinuity = continuityEnabled
3397
3404
  ? findWorkerContinuityLane(loadAllLanes(hqRoot), {
3398
3405
  senior,
@@ -3424,7 +3431,10 @@ async function runCreate(ctx, opts) {
3424
3431
  path: briefAbs,
3425
3432
  });
3426
3433
  }
3427
- const config = loadLanesConfig(hqRoot);
3434
+ const loadedConfig = loadLanesConfig(hqRoot);
3435
+ const config = opts.remoteControl === true
3436
+ ? remoteControlSelectionConfig(loadedConfig, ctx.env)
3437
+ : loadedConfig;
3428
3438
  let outpostId = opts.outpost?.trim() || undefined;
3429
3439
  let placementHostOverride;
3430
3440
  let placementBalanceHostOverride;
@@ -3458,7 +3468,9 @@ async function runCreate(ctx, opts) {
3458
3468
  inheritedPlacement = callerLane.placement_default;
3459
3469
  }
3460
3470
  }
3461
- const placementToApply = requestedPlacement ?? inheritedPlacement;
3471
+ const placementToApply = opts.remoteControl === true
3472
+ ? { kind: "local" }
3473
+ : requestedPlacement ?? inheritedPlacement;
3462
3474
  const outpostTargets = new Set();
3463
3475
  if (placementToApply?.kind === "outpost")
3464
3476
  outpostTargets.add(placementToApply.id);
@@ -3785,6 +3797,9 @@ async function runCreate(ctx, opts) {
3785
3797
  if (opts.loop === true && host.kind === "outpost") {
3786
3798
  throw new LanesError("loop_lane_outpost_unsupported", "Loop lanes currently require the local host", { outpost_id: host.id });
3787
3799
  }
3800
+ if (opts.remoteControl === true && host.kind === "outpost") {
3801
+ throw new LanesError("remote_control_outpost_unsupported", "--remote-control requires the local daemon account pools", { outpost_id: host.id });
3802
+ }
3788
3803
  // Repeat the busy check while holding provider admission serialization so
3789
3804
  // two concurrent creates cannot both claim one worker's provider thread.
3790
3805
  if (continuityEnabled) {
@@ -3947,6 +3962,7 @@ async function runCreate(ctx, opts) {
3947
3962
  ...(opts.loop === true ? { loop_mode: true } : {}),
3948
3963
  ...(keepAlive ? { keep_alive_opted_in_at: createdAt } : {}),
3949
3964
  provider,
3965
+ ...(opts.remoteControl === true ? { remote_control: true } : {}),
3950
3966
  ...(workerContinuity.resumable && workerContinuity.previous
3951
3967
  ? {
3952
3968
  provider_session_id: workerContinuity.previous.provider_session_id,
@@ -7208,13 +7224,18 @@ async function prepareAccountMove(ctx, lane, input) {
7208
7224
  throw new LanesError("no_provider_session", `Lane ${laneId} has no recorded provider session id, so there is no session to move`, { lane_id: laneId, provider: lane.provider });
7209
7225
  }
7210
7226
  const sessionId = lane.provider_session_id;
7211
- const config = loadLanesConfig(hqRoot);
7227
+ const loadedConfig = loadLanesConfig(hqRoot);
7228
+ const config = lane.remote_control === true
7229
+ ? remoteControlSelectionConfig(loadedConfig, ctx.env)
7230
+ : loadedConfig;
7212
7231
  const providerCfg = config.providers[lane.provider];
7213
7232
  const targetCfg = providerCfg.accounts[target];
7214
7233
  if (targetCfg === undefined) {
7215
7234
  throw new AccountResolutionError("unknown_account", `Unknown account ${JSON.stringify(target)} for ${lane.provider}. Configured: ${Object.keys(providerCfg.accounts).join(", ") || "(none)"}`, { provider: lane.provider, account: target, enabled: Object.keys(providerCfg.accounts).filter((id) => providerCfg.accounts[id]?.enabled) });
7216
7235
  }
7217
- const targetHome = effectiveAccountHome(targetCfg, ctx.hostname()).home;
7236
+ const targetHome = lane.remote_control === true
7237
+ ? remoteControlSessionHome(config, ctx.hostname())
7238
+ : effectiveAccountHome(targetCfg, ctx.hostname()).home;
7218
7239
  if (!targetCfg.enabled) {
7219
7240
  throw new AccountResolutionError("account_disabled", `Account ${JSON.stringify(target)} is disabled${targetCfg.disabled_reason ? `: ${targetCfg.disabled_reason}` : ""}`, { provider: lane.provider, account: target, reason: targetCfg.disabled_reason ?? "" });
7220
7241
  }
@@ -7375,7 +7396,10 @@ async function selectAutomaticClaudeResumeAccount(ctx, lane, workerProfile, opti
7375
7396
  if (lane.provider !== "claude")
7376
7397
  return undefined;
7377
7398
  const hqRoot = ctx.hqRoot();
7378
- const config = loadLanesConfig(hqRoot);
7399
+ const loadedConfig = loadLanesConfig(hqRoot);
7400
+ const config = lane.remote_control === true
7401
+ ? remoteControlSelectionConfig(loadedConfig, ctx.env)
7402
+ : loadedConfig;
7379
7403
  const currentConfig = lane.account === undefined
7380
7404
  ? undefined
7381
7405
  : config.providers.claude.accounts[lane.account];
@@ -9646,6 +9670,7 @@ export function registerLanesCommand(parent, deps = {}) {
9646
9670
  .option("--fresh-thread", "Skip worker continuity and start a cold provider session")
9647
9671
  .option("--loop", "Keep one worker lane registered to process queued phase envelopes")
9648
9672
  .option("--provider <name>", "claude | codex | grok")
9673
+ .option("--remote-control", "Open a Claude lane in Remote Control using account a for login and the selected account for inference")
9649
9674
  .option("--account <id>", "Provider account id")
9650
9675
  .option("--model <id>", "Model id for the provider CLI")
9651
9676
  .option("--effort <level>", "Effort level; claude: low|medium|high|xhigh|max, codex: minimal|low|medium|high|xhigh|max|ultra, grok: low|medium|high|xhigh")
@@ -12,6 +12,11 @@
12
12
  * `vaultApiFetch` satisfies hq-cloud's `OutpostTransport` structurally — the
13
13
  * option bags match field-for-field — so it is passed straight through with no
14
14
  * adapter shim.
15
+ *
16
+ * Company Outposts (`--company`, `jobs register`) are part of that same command
17
+ * tree. This adapter does not grow a second copy. The accepted revision, the
18
+ * catalog price, and the company payer are printed by hq-cloud. The /schedule
19
+ * skill text is a follow-up and is not changed here.
15
20
  */
16
21
  import type { Command } from "commander";
17
22
  import type { ReplicaSyncDependencies } from "@indigoai-us/hq-cloud/outposts/node";
@@ -12,6 +12,11 @@
12
12
  * `vaultApiFetch` satisfies hq-cloud's `OutpostTransport` structurally — the
13
13
  * option bags match field-for-field — so it is passed straight through with no
14
14
  * adapter shim.
15
+ *
16
+ * Company Outposts (`--company`, `jobs register`) are part of that same command
17
+ * tree. This adapter does not grow a second copy. The accepted revision, the
18
+ * catalog price, and the company payer are printed by hq-cloud. The /schedule
19
+ * skill text is a follow-up and is not changed here.
15
20
  */
16
21
  import { loadCachedTokens } from "@indigoai-us/hq-cloud";
17
22
  import { registerOutpostsCommand as registerOutpostsCommandFromCloud } from "@indigoai-us/hq-cloud/outposts/cli";
@@ -63,7 +63,7 @@ export declare function coreCommandHasPathOperands(argv: readonly string[]): boo
63
63
  /** Apply the manifest's operand rule to a copied process.argv vector. */
64
64
  export declare function normalizeCorePathOperands(argv: readonly string[], platform?: NodeJS.Platform, convertPath?: (value: string) => string): string[];
65
65
  /** Family kill switches whose owner-approved default is enabled. */
66
- export declare const CORE_NATIVE_DEFAULT_ON_FAMILY_FLAGS: readonly ["core-native-session", "core-native-hook-helpers", "core-native-policy", "core-native-utilities", "core-native-jobs", "core-native-ontology", "core-native-handoff", "core-native-delegate"];
66
+ export declare const CORE_NATIVE_DEFAULT_ON_FAMILY_FLAGS: readonly ["core-native-session", "core-native-hook-helpers", "core-native-policy", "core-native-utilities", "core-native-jobs", "core-native-handoff", "core-native-bucket-c", "core-native-delegate"];
67
67
  export declare function isDefaultOnFastFamily(flagKey: string): boolean;
68
68
  /** The relocated scripts that qualify for the entrypoint fast path. */
69
69
  export declare const FAST_SCAFFOLD_SCRIPTS: readonly FastScaffoldScript[];
@@ -152,8 +152,8 @@ export const CORE_NATIVE_DEFAULT_ON_FAMILY_FLAGS = [
152
152
  "core-native-policy",
153
153
  "core-native-utilities",
154
154
  "core-native-jobs",
155
- "core-native-ontology",
156
155
  "core-native-handoff",
156
+ "core-native-bucket-c",
157
157
  "core-native-delegate",
158
158
  ];
159
159
  const defaultOnFamilyFlags = new Set(CORE_NATIVE_DEFAULT_ON_FAMILY_FLAGS);
@@ -606,11 +606,7 @@ export const FAST_SCAFFOLD_SCRIPTS = [
606
606
  modulePath: "./commands/core-ontology-native.js",
607
607
  exportName: "runOntologyNativeFast",
608
608
  flagKey: "hq-core-native-fast-route",
609
- familyFlagKey: "core-native-ontology",
610
- asset: `core/scripts/${name === "audience-grant" ? "ontology-audience-grant" : name === "source-worklist" ? "ontology-source-worklist" : name === "source-yaml-validate" ? "source-yaml-validate" : `ontology-${name}`}.${name === "brief" || name === "garden" ? "mjs" : "sh"}`,
611
609
  root: name === "source-yaml-validate" ? "cwd" : "live",
612
- shellCwd: "caller",
613
- shellHqRoot: name === "source-yaml-validate" ? "none" : "live",
614
610
  })),
615
611
  {
616
612
  name: "audit-log",
@@ -713,6 +709,18 @@ export const FAST_SCAFFOLD_SCRIPTS = [
713
709
  shellHqRoot: "live",
714
710
  requiresNodeNetworkCompatibility: true,
715
711
  },
712
+ {
713
+ name: "hq-task",
714
+ kind: "native",
715
+ modulePath: "./commands/core-hq-task-fast.js",
716
+ exportName: "runHqTaskFast",
717
+ flagKey: "hq-core-native-fast-route",
718
+ familyFlagKey: "core-native-bucket-c",
719
+ asset: "core/scripts/hq-task.sh",
720
+ root: "live",
721
+ shellCwd: "live",
722
+ shellHqRoot: "live",
723
+ },
716
724
  ];
717
725
  /**
718
726
  * Parse the small, non-ambiguous `hq secrets env` surface for the gated entry