@indigoai-us/hq-cli 5.345.106 → 5.345.108

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 (60) hide show
  1. package/CHANGELOG.md +25 -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 +175 -6
  6. package/dist/command-catalog.generated.js +209 -6
  7. package/dist/commands/auth.js +42 -0
  8. package/dist/commands/capacity.d.ts +1 -1
  9. package/dist/commands/capacity.js +74 -11
  10. package/dist/commands/core-checkpoint-stop-gate-native.js +17 -5
  11. package/dist/commands/core-hq-task-fast.d.ts +4 -0
  12. package/dist/commands/core-hq-task-fast.js +11 -0
  13. package/dist/commands/core-hq-task-native.d.ts +20 -0
  14. package/dist/commands/core-hq-task-native.js +275 -0
  15. package/dist/commands/core-native-bucket-c-flag.d.ts +3 -0
  16. package/dist/commands/core-native-bucket-c-flag.js +6 -0
  17. package/dist/commands/core-native-family-flag.d.ts +0 -2
  18. package/dist/commands/core-native-family-flag.js +0 -4
  19. package/dist/commands/core-native-pipeline-flag.d.ts +3 -0
  20. package/dist/commands/core-native-pipeline-flag.js +6 -0
  21. package/dist/commands/core-ontology-native.js +24 -30
  22. package/dist/commands/core-pipeline-workers-command.d.ts +3 -0
  23. package/dist/commands/core-pipeline-workers-command.js +37 -0
  24. package/dist/commands/core-pipeline-workers-native.d.ts +13 -0
  25. package/dist/commands/core-pipeline-workers-native.js +361 -0
  26. package/dist/commands/core.js +12 -10
  27. package/dist/commands/lanes.js +104 -19
  28. package/dist/commands/outposts.d.ts +5 -0
  29. package/dist/commands/outposts.js +5 -0
  30. package/dist/fast-scaffold.d.ts +1 -1
  31. package/dist/fast-scaffold.js +13 -5
  32. package/dist/hq-cloud-sync-runner/bin/sync-runner.js +56015 -63476
  33. package/dist/hq-cloud-sync-runner/package.json +1 -1
  34. package/dist/lib/capacity/ledger.d.ts +1 -0
  35. package/dist/lib/capacity/ledger.js +10 -0
  36. package/dist/lib/capacity/route.d.ts +146 -0
  37. package/dist/lib/capacity/route.js +452 -0
  38. package/dist/lib/daemon/remote-control-pools.d.ts +2 -2
  39. package/dist/lib/flag-registry-worker-source.generated.d.ts +1 -1
  40. package/dist/lib/flag-registry-worker-source.generated.js +1 -1
  41. package/dist/lib/lanes/reconcile.js +4 -0
  42. package/dist/lib/lanes/remote-control-lane.d.ts +33 -0
  43. package/dist/lib/lanes/remote-control-lane.js +276 -0
  44. package/dist/lib/lanes/spawn.d.ts +5 -0
  45. package/dist/lib/lanes/spawn.js +65 -14
  46. package/dist/lib/lanes/store.js +11 -4
  47. package/dist/lib/lanes/types.d.ts +22 -4
  48. package/dist/lib/lanes/types.js +1 -1
  49. package/dist/lib/lanes/watcher.js +8 -1
  50. package/dist/utils/cognito-session.d.ts +12 -4
  51. package/dist/utils/cognito-session.js +42 -9
  52. package/dist/utils/token-keychain.d.ts +96 -0
  53. package/dist/utils/token-keychain.js +218 -0
  54. package/package.json +2 -2
  55. package/assets/scaffold/core/scripts/ontology-audience-grant.sh +0 -81
  56. package/assets/scaffold/core/scripts/ontology-brief.mjs +0 -93
  57. package/assets/scaffold/core/scripts/ontology-candidate.sh +0 -100
  58. package/assets/scaffold/core/scripts/ontology-garden.mjs +0 -327
  59. package/assets/scaffold/core/scripts/ontology-source-worklist.sh +0 -226
  60. package/assets/scaffold/core/scripts/source-yaml-validate.sh +0 -36
@@ -3,12 +3,15 @@ import * as fs from "node:fs";
3
3
  import * as os from "node:os";
4
4
  import * as path from "node:path";
5
5
  import * as readline from "node:readline";
6
- import { LedgerCorrupt, LedgerMissing, READING_SOURCES, capacityRoot, nowViewJsonSchema, readCollectorMark, readLedgerEvents, readNow, rebuildNow, setCollectorEnabled, } from "../lib/capacity/ledger.js";
6
+ import { LedgerCorrupt, LedgerMissing, READING_SOURCES, capacityOptionsFromEnv, capacityRoot, nowViewJsonSchema, readCollectorMark, readLedgerEvents, readNow, rebuildNow, setCollectorEnabled, } from "../lib/capacity/ledger.js";
7
7
  import { listCapacityAccounts, registryAccountIds } from "../lib/capacity/accounts.js";
8
8
  import { claudeIdentityKeys } from "../lib/capacity/collectors/claude-oauth.js";
9
9
  import { projectCapacityView } from "../lib/capacity/project.js";
10
10
  import { capacityWidgetTimeZone, renderCapacityWidget } from "../lib/capacity/widget.js";
11
11
  import { resolveLanesHqRoot } from "../lib/lanes/hq-root.js";
12
+ import { loadLanesConfig } from "../lib/lanes/config.js";
13
+ import { readAllLanes } from "../lib/lanes/store.js";
14
+ import { RouteUsageError, formatRouteText, pickAccount, resolveFloor, } from "../lib/capacity/route.js";
12
15
  import { SignInUsageError, executeCapacityLogin, formatCredits, formatLoginText, formatRefreshLine, formatRoster, generateAccountId, loginJson, presentAccount, promptsAllowed, removeCapacityAccount, renameCapacityAccount, rosterFrom, } from "../lib/capacity/sign-in.js";
13
16
  import { ingestClaudeStatuslinePayload, installStatuslineSpoolScript } from "../lib/capacity/collectors/claude-statusline.js";
14
17
  import { CapacityUsageError, REFUSAL_HELP, ingestRefusal, } from "../lib/capacity/refusal.js";
@@ -45,16 +48,7 @@ const HISTORY_HEADERS = [
45
48
  "SOURCE",
46
49
  "CLI VERSION",
47
50
  ];
48
- export function capacityOptionsFromEnv(env = process.env) {
49
- const raw = env.HQ_CAPACITY_NOW?.trim();
50
- if (!raw)
51
- return { env };
52
- const parsed = Date.parse(raw);
53
- if (Number.isNaN(parsed)) {
54
- throw new Error(`HQ_CAPACITY_NOW must be a UTC timestamp, got '${raw}'`);
55
- }
56
- return { env, now: () => new Date(raw) };
57
- }
51
+ export { capacityOptionsFromEnv } from "../lib/capacity/ledger.js";
58
52
  export function withSchemaVersion(view) {
59
53
  return { ...view, schemaVersion: CAPACITY_SCHEMA_VERSION };
60
54
  }
@@ -297,6 +291,69 @@ export function registerCapacityCommand(program) {
297
291
  process.exitCode = 1;
298
292
  });
299
293
  });
294
+ capacity
295
+ .command("route")
296
+ .description("Pick the account with the most capacity for a new lane (read-only; port of boss-route)")
297
+ .option("--provider <list>", "Comma-separated list: any, claude, codex, grok", "any")
298
+ .option("--model <id>", "Model id. Narrows --provider any to the mapped provider")
299
+ .option("--prefer <list>", "Comma-separated preferred provider order", "claude,codex,grok")
300
+ .option("--floor <percent>", "Minimum headroom percent the pick must clear (0-100)", "15")
301
+ .option("--json", "Print the route result as JSON (default)")
302
+ .option("--text", "Print a single-line text summary instead of JSON")
303
+ .action((_opts, command) => {
304
+ runCli(() => {
305
+ const opts = command.optsWithGlobals();
306
+ if (opts.json && opts.text) {
307
+ throw new RouteUsageError("--text cannot be combined with --json");
308
+ }
309
+ const clock = capacityClock();
310
+ const view = loadNow(clock.options);
311
+ const freshness = capacityFreshness(view.generatedAt, clock.nowMs);
312
+ const mark = readCollectorMark(clock.options);
313
+ const hqRoot = resolveLanesHqRoot({ env: process.env });
314
+ const lanesConfig = loadLanesConfig(hqRoot);
315
+ let lanes = [];
316
+ let lanesError = null;
317
+ try {
318
+ lanes = readAllLanes(hqRoot);
319
+ }
320
+ catch (err) {
321
+ lanesError = err instanceof Error ? err.message : String(err);
322
+ }
323
+ let result;
324
+ try {
325
+ result = pickAccount({
326
+ view,
327
+ lanes,
328
+ lanesConfig,
329
+ providers: splitList(opts.provider),
330
+ model: opts.model ?? null,
331
+ prefer: splitList(opts.prefer),
332
+ floor: resolveFloor(opts.floor),
333
+ now: new Date(clock.nowMs),
334
+ collectorEnabled: mark ? mark.enabled : null,
335
+ capacityStale: freshness.stale,
336
+ lanesError,
337
+ });
338
+ }
339
+ catch (err) {
340
+ if (err instanceof RouteUsageError) {
341
+ console.error(err.message);
342
+ process.exitCode = 1;
343
+ return;
344
+ }
345
+ throw err;
346
+ }
347
+ if (opts.text) {
348
+ console.log(formatRouteText(result));
349
+ }
350
+ else {
351
+ console.log(JSON.stringify(result, null, 2));
352
+ }
353
+ if (!result.ok)
354
+ process.exitCode = 2;
355
+ });
356
+ });
300
357
  capacity
301
358
  .command("enable")
302
359
  .description("Create the ledger directory and mark the collector on")
@@ -594,6 +651,12 @@ function wantsJson(opts, command) {
594
651
  }
595
652
  return false;
596
653
  }
654
+ function splitList(raw) {
655
+ if (raw === undefined)
656
+ return undefined;
657
+ const parts = raw.split(",").map((v) => v.trim()).filter(Boolean);
658
+ return parts.length === 0 ? undefined : parts;
659
+ }
597
660
  function runCli(action) {
598
661
  try {
599
662
  process.exitCode = 0;
@@ -73,15 +73,27 @@ const defaults = () => ({
73
73
  },
74
74
  makeTempPath: () => path.join(os.tmpdir(), `tmp.${process.pid}.${Date.now()}.${Math.random().toString(16).slice(2)}`),
75
75
  commandExists: (name, env) => {
76
+ const windowsExtensions = process.platform === "win32"
77
+ ? (env?.PATHEXT ?? process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean)
78
+ : [];
76
79
  for (const entry of (env?.PATH ?? process.env.PATH ?? "").split(path.delimiter)) {
77
80
  if (!entry)
78
81
  continue;
79
- const candidate = path.join(entry, name);
80
- try {
81
- fs.accessSync(candidate, fs.constants.X_OK);
82
- return true;
82
+ const candidates = [name, ...windowsExtensions.map((extension) => `${name}${extension}`)];
83
+ for (const command of candidates) {
84
+ const candidate = path.join(entry, command);
85
+ try {
86
+ if (process.platform === "win32") {
87
+ if (fs.statSync(candidate).isFile())
88
+ return true;
89
+ }
90
+ else {
91
+ fs.accessSync(candidate, fs.constants.X_OK);
92
+ return true;
93
+ }
94
+ }
95
+ catch { /* try the next candidate in PATH */ }
83
96
  }
84
- catch { /* try the next PATH entry */ }
85
97
  }
86
98
  return false;
87
99
  },
@@ -0,0 +1,4 @@
1
+ import { HQ_TASK_ASSET, runHqTask } from "./core-hq-task-native.js";
2
+ export { HQ_TASK_ASSET, runHqTask };
3
+ export declare function runHqTaskFast(args: string[], _stdin: string, _cwd: string, root: string): number;
4
+ //# sourceMappingURL=core-hq-task-fast.d.ts.map
@@ -0,0 +1,11 @@
1
+ import { HQ_TASK_ASSET, runHqTask } from "./core-hq-task-native.js";
2
+ export { HQ_TASK_ASSET, runHqTask };
3
+ export function runHqTaskFast(args, _stdin, _cwd, root) {
4
+ const result = runHqTask(args, root);
5
+ if (result.stdout)
6
+ process.stdout.write(result.stdout);
7
+ if (result.stderr)
8
+ process.stderr.write(result.stderr);
9
+ return result.code;
10
+ }
11
+ //# sourceMappingURL=core-hq-task-fast.js.map
@@ -0,0 +1,20 @@
1
+ import * as fs from "node:fs";
2
+ export declare const HQ_TASK_ASSET = "core/scripts/hq-task.sh";
3
+ type Board = {
4
+ tasks: Array<Record<string, any>>;
5
+ objectives?: Array<Record<string, any>>;
6
+ [key: string]: any;
7
+ };
8
+ export type HqTaskResult = {
9
+ code: number;
10
+ stdout: string;
11
+ stderr: string;
12
+ };
13
+ type AtomicFileIO = Pick<typeof fs, "writeFileSync" | "renameSync" | "chmodSync" | "statSync" | "existsSync" | "unlinkSync">;
14
+ declare function save(file: string, board: Board, io?: AtomicFileIO): HqTaskResult | undefined;
15
+ export declare const __hqTaskTest: {
16
+ save: typeof save;
17
+ };
18
+ export declare function runHqTask(args: readonly string[], root: string, env?: NodeJS.ProcessEnv): HqTaskResult;
19
+ export {};
20
+ //# sourceMappingURL=core-hq-task-native.d.ts.map
@@ -0,0 +1,275 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ export const HQ_TASK_ASSET = "core/scripts/hq-task.sh";
5
+ const USAGE = `hq-task — the global task list on an HQ board
6
+
7
+ Usage:
8
+ hq-task.sh list [--company <slug>] [--all] [--goal <objective-id>]
9
+ hq-task.sh add [--company <slug>] --title "<short title>"
10
+ [--description "<context>"]
11
+ [--criteria "<one done-criterion>"]...
12
+ [--contact "Name <email>|role"]...
13
+ [--goal <objective-id>] [--priority <1-3>]
14
+ hq-task.sh done [--company <slug>] --id T-002
15
+ hq-task.sh block [--company <slug>] --id T-002 --reason "<what is in the way>"
16
+ hq-task.sh reopen [--company <slug>] --id T-002
17
+ hq-task.sh goals [--company <slug>]
18
+
19
+ Default board: personal/board.json. With --company: companies/<slug>/board.json.`;
20
+ function isUnsafeCompanySlug(root, company) {
21
+ if (company.length === 0 || path.isAbsolute(company) || path.win32.isAbsolute(company) ||
22
+ company.includes("..") || /[\\/]/.test(company))
23
+ return true;
24
+ const companiesRoot = path.resolve(root, "companies");
25
+ const target = path.resolve(companiesRoot, company, "board.json");
26
+ const relative = path.relative(companiesRoot, target);
27
+ return relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative);
28
+ }
29
+ function nodeOnPath(env, platform = process.platform) {
30
+ const searchPath = env.PATH || "";
31
+ const names = platform === "win32" ? ["node.exe", "node.cmd", "node.bat"] : ["node"];
32
+ for (const directory of searchPath.split(path.delimiter)) {
33
+ if (!directory)
34
+ continue;
35
+ for (const name of names) {
36
+ try {
37
+ const candidate = path.join(directory, name);
38
+ fs.accessSync(candidate, platform === "win32" ? fs.constants.F_OK : fs.constants.X_OK);
39
+ if (fs.statSync(candidate).isFile())
40
+ return true;
41
+ }
42
+ catch {
43
+ // command -v ignores PATH entries that do not contain an executable.
44
+ }
45
+ }
46
+ }
47
+ return false;
48
+ }
49
+ function fail(message, code = 1) {
50
+ return { code, stdout: "", stderr: `${message}\n` };
51
+ }
52
+ function parseArgs(argv) {
53
+ const repeatable = new Set(["criteria", "contact"]);
54
+ const bare = new Set(["all"]);
55
+ const flags = {};
56
+ for (let i = 0; i < argv.length; i += 1) {
57
+ const token = argv[i];
58
+ if (!token.startsWith("--"))
59
+ return { error: fail(`Unexpected argument: ${token}\n\n${USAGE}`) };
60
+ const key = token.slice(2);
61
+ if (bare.has(key)) {
62
+ flags[key] = true;
63
+ continue;
64
+ }
65
+ const value = argv[i + 1];
66
+ if (value === undefined || value.startsWith("--"))
67
+ return { error: fail(`Flag --${key} needs a value.\n\n${USAGE}`) };
68
+ i += 1;
69
+ if (repeatable.has(key)) {
70
+ const previous = flags[key];
71
+ flags[key] = [...(Array.isArray(previous) ? previous : []), value];
72
+ }
73
+ else
74
+ flags[key] = value;
75
+ }
76
+ return { flags };
77
+ }
78
+ function text(flags, key) {
79
+ const value = flags[key];
80
+ return typeof value === "string" ? value : undefined;
81
+ }
82
+ function boardPath(root, flags) {
83
+ const company = text(flags, "company");
84
+ return company ? path.join(root, "companies", company, "board.json") : path.join(root, "personal", "board.json");
85
+ }
86
+ function load(root, flags) {
87
+ const file = boardPath(root, flags);
88
+ if (!fs.existsSync(file))
89
+ return { error: fail(`No board at ${file}`) };
90
+ try {
91
+ const board = JSON.parse(fs.readFileSync(file, "utf8"));
92
+ board.tasks ||= [];
93
+ return { file, board };
94
+ }
95
+ catch (error) {
96
+ return { error: fail(error.message) };
97
+ }
98
+ }
99
+ function save(file, board, io = fs) {
100
+ board.updated_at = new Date().toISOString().replace(/\.\d+Z$/, "Z");
101
+ const temporary = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.${randomUUID()}.tmp`);
102
+ try {
103
+ const mode = io.statSync(file).mode & 0o7777;
104
+ io.writeFileSync(temporary, `${JSON.stringify(board, null, 2)}\n`, { flag: "wx", mode });
105
+ io.chmodSync(temporary, mode);
106
+ io.renameSync(temporary, file);
107
+ }
108
+ catch (error) {
109
+ try {
110
+ if (io.existsSync(temporary))
111
+ io.unlinkSync(temporary);
112
+ }
113
+ catch { /* preserve the write or rename error */ }
114
+ return fail(error.message);
115
+ }
116
+ return undefined;
117
+ }
118
+ export const __hqTaskTest = { save };
119
+ function parseContact(raw) {
120
+ let rest = raw;
121
+ let role;
122
+ const bar = rest.indexOf("|");
123
+ if (bar !== -1) {
124
+ role = rest.slice(bar + 1).trim();
125
+ rest = rest.slice(0, bar).trim();
126
+ }
127
+ let email;
128
+ const angle = /<([^>]+)>/.exec(rest);
129
+ if (angle) {
130
+ email = angle[1].trim();
131
+ rest = rest.slice(0, angle.index).trim();
132
+ }
133
+ const contact = { name: rest };
134
+ if (email)
135
+ contact.email = email;
136
+ if (role)
137
+ contact.role = role;
138
+ return contact;
139
+ }
140
+ function goalTitle(board, id) {
141
+ const objective = (board.objectives || []).find((row) => row.id === id);
142
+ return objective ? String(objective.title) : null;
143
+ }
144
+ function runList(root, flags) {
145
+ const loaded = load(root, flags);
146
+ if (loaded.error)
147
+ return loaded.error;
148
+ const board = loaded.board;
149
+ let tasks = board.tasks.filter((task) => flags.all === true || task.status !== "done");
150
+ const goal = text(flags, "goal");
151
+ if (goal)
152
+ tasks = tasks.filter((task) => task.objective_id === goal);
153
+ if (tasks.length === 0)
154
+ return { code: 0, stdout: "No open tasks.\n", stderr: "" };
155
+ const output = [`${text(flags, "company") || "personal"} — ${flags.all ? "all tasks" : "open tasks"} (${tasks.length})\n\n`];
156
+ tasks.sort((a, b) => (a.priority ?? 99) - (b.priority ?? 99) || String(a.id).localeCompare(String(b.id)));
157
+ for (const task of tasks) {
158
+ const mark = task.status === "blocked" ? "!" : task.status === "done" ? "x" : " ";
159
+ output.push(` [${mark}] ${task.id} ${task.title || ""}\n`);
160
+ const goalName = task.objective_id && goalTitle(board, task.objective_id);
161
+ if (goalName)
162
+ output.push(` goal: ${goalName}\n`);
163
+ if (task.status === "blocked" && task.blockedReason)
164
+ output.push(` blocked: ${task.blockedReason}\n`);
165
+ for (const contact of task.contacts || []) {
166
+ const trail = [contact.email, contact.phone].filter(Boolean).join(" · ");
167
+ output.push(` ${contact.name}${trail ? ` — ${trail}` : ""}\n`);
168
+ }
169
+ }
170
+ return { code: 0, stdout: output.join(""), stderr: "" };
171
+ }
172
+ function runGoals(root, flags) {
173
+ const loaded = load(root, flags);
174
+ if (loaded.error)
175
+ return loaded.error;
176
+ const board = loaded.board;
177
+ const objectives = board.objectives || [];
178
+ if (objectives.length === 0)
179
+ return { code: 0, stdout: "No goals on that board.\n", stderr: "" };
180
+ const output = [];
181
+ for (const objective of objectives) {
182
+ const count = board.tasks.filter((task) => task.objective_id === objective.id && task.status !== "done").length;
183
+ output.push(`${objective.id} ${objective.title} (${count} open task${count === 1 ? "" : "s"})\n`);
184
+ for (const kr of objective.key_results || [])
185
+ output.push(` ${kr.title} — ${kr.current ?? 0}/${kr.target} ${kr.unit || ""}\n`);
186
+ }
187
+ return { code: 0, stdout: output.join(""), stderr: "" };
188
+ }
189
+ export function runHqTask(args, root, env = process.env) {
190
+ if (!nodeOnPath(env))
191
+ return fail("hq-task: node is required but was not found on PATH.");
192
+ const [command, ...rest] = args;
193
+ if (!command || command === "--help" || command === "-h") {
194
+ return { code: command ? 0 : 1, stdout: `${USAGE}\n`, stderr: "" };
195
+ }
196
+ if (!(command in { list: 1, goals: 1, add: 1, done: 1, reopen: 1, block: 1 }))
197
+ return fail(`Unknown command: ${command}\n\n${USAGE}`);
198
+ const parsed = parseArgs(rest);
199
+ if (parsed.error)
200
+ return parsed.error;
201
+ const flags = parsed.flags;
202
+ const company = text(flags, "company");
203
+ if (company !== undefined && isUnsafeCompanySlug(root, company))
204
+ return fail(`Invalid company slug: ${company}`);
205
+ if (command === "list")
206
+ return runList(root, flags);
207
+ if (command === "goals")
208
+ return runGoals(root, flags);
209
+ if (command === "add") {
210
+ const title = text(flags, "title");
211
+ if (!title)
212
+ return fail(`add needs --title.\n\n${USAGE}`);
213
+ const priority = text(flags, "priority");
214
+ if (flags.priority !== undefined && !/^[1-3]$/.test(priority ?? "")) {
215
+ return fail("--priority must be an integer from 1 to 3");
216
+ }
217
+ const loaded = load(root, flags);
218
+ if (loaded.error)
219
+ return loaded.error;
220
+ const board = loaded.board, file = loaded.file;
221
+ const goal = text(flags, "goal");
222
+ if (goal && !goalTitle(board, goal))
223
+ return fail(`No goal ${goal} on that board. Run 'hq-task.sh goals' to list them.`);
224
+ let highest = 0;
225
+ for (const task of board.tasks) {
226
+ const match = /^T-(\d+)$/.exec(task.id || "");
227
+ if (match)
228
+ highest = Math.max(highest, Number(match[1]));
229
+ }
230
+ const criteria = flags.criteria;
231
+ const contacts = flags.contact;
232
+ const task = {
233
+ id: `T-${String(highest + 1).padStart(3, "0")}`,
234
+ title,
235
+ description: text(flags, "description") || title,
236
+ status: "open",
237
+ priority: priority ? Number(priority) : 2,
238
+ objective_id: goal || null,
239
+ criteria: criteria || [`${title} — completed.`],
240
+ contacts: (contacts || []).map(parseContact),
241
+ createdAt: new Date().toISOString().slice(0, 10),
242
+ };
243
+ board.tasks.push(task);
244
+ const error = save(file, board);
245
+ if (error)
246
+ return error;
247
+ return { code: 0, stdout: `Added ${task.id}: ${task.title}\n`, stderr: "" };
248
+ }
249
+ if (command === "block" && !text(flags, "reason"))
250
+ return fail(`block needs --reason.\n\n${USAGE}`);
251
+ const loaded = load(root, flags);
252
+ if (loaded.error)
253
+ return loaded.error;
254
+ const id = text(flags, "id");
255
+ const nextStatus = command === "done" ? "done" : command === "block" ? "blocked" : "open";
256
+ if (!id)
257
+ return fail(`${command} needs --id.\n\n${USAGE}`);
258
+ const task = loaded.board.tasks.find((row) => row.id === id);
259
+ if (!task)
260
+ return fail(`No task ${id} on that board.`);
261
+ task.status = nextStatus;
262
+ if (nextStatus === "done")
263
+ task.closedAt = new Date().toISOString().slice(0, 10);
264
+ else
265
+ delete task.closedAt;
266
+ if (nextStatus === "blocked")
267
+ task.blockedReason = text(flags, "reason") || "";
268
+ else
269
+ delete task.blockedReason;
270
+ const error = save(loaded.file, loaded.board);
271
+ if (error)
272
+ return error;
273
+ return { code: 0, stdout: `${task.id} → ${nextStatus}: ${task.title}\n`, stderr: "" };
274
+ }
275
+ //# sourceMappingURL=core-hq-task-native.js.map
@@ -0,0 +1,3 @@
1
+ export declare const CORE_NATIVE_BUCKET_C_FLAG = "core-native-bucket-c";
2
+ export declare function coreNativeBucketCEnabled(): Promise<boolean>;
3
+ //# sourceMappingURL=core-native-bucket-c-flag.d.ts.map
@@ -0,0 +1,6 @@
1
+ import { coreNativeFamilyEnabled } from "./core-native-family-flag.js";
2
+ export const CORE_NATIVE_BUCKET_C_FLAG = "core-native-bucket-c";
3
+ export function coreNativeBucketCEnabled() {
4
+ return coreNativeFamilyEnabled(CORE_NATIVE_BUCKET_C_FLAG);
5
+ }
6
+ //# sourceMappingURL=core-native-bucket-c-flag.js.map
@@ -1,7 +1,5 @@
1
1
  /** Shared fail-safe readers for shipped native core families. */
2
2
  export declare function coreNativeFamilyEnabled(flagKey: string): Promise<boolean>;
3
3
  export declare const CORE_NATIVE_DELEGATE_FLAG = "core-native-delegate";
4
- export declare const CORE_NATIVE_ONTOLOGY_FLAG = "core-native-ontology";
5
4
  export declare function coreNativeDelegateEnabled(): Promise<boolean>;
6
- export declare function coreNativeOntologyEnabled(): Promise<boolean>;
7
5
  //# sourceMappingURL=core-native-family-flag.d.ts.map
@@ -11,11 +11,7 @@ export async function coreNativeFamilyEnabled(flagKey) {
11
11
  });
12
12
  }
13
13
  export const CORE_NATIVE_DELEGATE_FLAG = "core-native-delegate";
14
- export const CORE_NATIVE_ONTOLOGY_FLAG = "core-native-ontology";
15
14
  export function coreNativeDelegateEnabled() {
16
15
  return coreNativeFamilyEnabled(CORE_NATIVE_DELEGATE_FLAG);
17
16
  }
18
- export function coreNativeOntologyEnabled() {
19
- return coreNativeFamilyEnabled(CORE_NATIVE_ONTOLOGY_FLAG);
20
- }
21
17
  //# sourceMappingURL=core-native-family-flag.js.map
@@ -0,0 +1,3 @@
1
+ export declare const CORE_NATIVE_PIPELINE_FLAG = "core-native-pipeline";
2
+ export declare function coreNativePipelineEnabled(): Promise<boolean>;
3
+ //# sourceMappingURL=core-native-pipeline-flag.d.ts.map
@@ -0,0 +1,6 @@
1
+ import { coreNativeFamilyEnabled } from "./core-native-family-flag.js";
2
+ export const CORE_NATIVE_PIPELINE_FLAG = "core-native-pipeline";
3
+ export function coreNativePipelineEnabled() {
4
+ return coreNativeFamilyEnabled(CORE_NATIVE_PIPELINE_FLAG);
5
+ }
6
+ //# sourceMappingURL=core-native-pipeline-flag.js.map
@@ -4,15 +4,16 @@ import { spawnSync } from "node:child_process";
4
4
  import * as fs from "node:fs";
5
5
  import * as path from "node:path";
6
6
  import { resolveWindowsExecutable } from "../lib/bot/runtime/windows.js";
7
- import { runBundledScript } from "../utils/run-bundled-script.js";
8
- import { resolveBundledAsset } from "../utils/hq-roots.js";
7
+ import { BUNDLED_ASSET_DIR, packageRoot } from "../utils/hq-roots.js";
9
8
  import { planResolvedCommandSpawn } from "../utils/windows-spawn.js";
10
9
  import { describeCoreCommand } from "./core-command-catalog.js";
11
10
  import { runKnowledgePrefs } from "./core-knowledge-prefs.js";
12
- const FLAG = "core-native-ontology";
13
11
  const ASSET = "core/scripts/";
14
12
  const SIGNAL_TYPES = ["decision", "commitment", "risk", "question", "action_item", "key_point", "participant_contribution", "summary"];
15
13
  const CANDIDATE_SIGNAL_TYPES = ["action_item", "commitment", "decision", "risk", "question", "key_point", "participant_contribution", "summary"];
14
+ function legacyAssetPath(name) {
15
+ return path.join(packageRoot(), BUNDLED_ASSET_DIR, ASSET, name);
16
+ }
16
17
  const ENTITY_TYPES = ["person", "project", "company", "concept"];
17
18
  const ok = (stdout = "") => ({ code: 0, stdout, stderr: "" });
18
19
  const err = (code, stderr, stdout = "") => ({ code, stdout, stderr });
@@ -179,7 +180,7 @@ export function candidateCommand(args, root) {
179
180
  "--company": 50, "--kind": 51, "--type": 52, "--audience": 53,
180
181
  "--source-ref": 54, "--body": 55, "--body-file": 56, "--created-by": 57,
181
182
  };
182
- return err(1, `${resolveBundledAsset(`${ASSET}ontology-candidate.sh`)}: line ${lines[name]}: $2: unbound variable\n`);
183
+ return err(1, `${legacyAssetPath("ontology-candidate.sh")}: line ${lines[name]}: $2: unbound variable\n`);
183
184
  }
184
185
  values[aliases[name]] = args[++index];
185
186
  }
@@ -677,7 +678,7 @@ export function audienceGrant(args, root) {
677
678
  const key = args[index];
678
679
  if (key === "--company") {
679
680
  if (index + 1 >= args.length)
680
- return err(1, `${resolveBundledAsset(`${ASSET}ontology-audience-grant.sh`)}: line 26: $2: unbound variable\n`);
681
+ return err(1, `${legacyAssetPath("ontology-audience-grant.sh")}: line 26: $2: unbound variable\n`);
681
682
  company = args[++index];
682
683
  }
683
684
  else if (key === "--dry-run")
@@ -707,9 +708,14 @@ export function audienceGrant(args, root) {
707
708
  if (!cloud)
708
709
  return ok("local-only, no grants\n");
709
710
  const membersRun = runHq(["members", "--company", company, "list"]);
710
- const memberLines = membersRun.stdout.split("\n").slice(1).map((line) => line.trim().split(/[\t ]+/)[0]?.toLowerCase() ?? "");
711
- const members = shellSubstitution(memberLines.join("\n"));
712
- if (!members)
711
+ const memberLines = membersRun.stdout.split("\n");
712
+ const members = new Set();
713
+ for (let index = 1; index < memberLines.length; index += 1) {
714
+ const member = memberLines[index].trim().split(/[\t ]+/)[0]?.toLowerCase() ?? "";
715
+ if (member)
716
+ members.add(member);
717
+ }
718
+ if (members.size === 0)
713
719
  return err(3, `could not list members of ${company}\n`);
714
720
  let granted = 0;
715
721
  let skipped = 0;
@@ -774,7 +780,7 @@ export function audienceGrant(args, root) {
774
780
  }
775
781
  }
776
782
  for (const who of principals) {
777
- if (!/^prs_|^agt_/.test(who) && !members.split("\n").includes(who)) {
783
+ if (!/^prs_|^agt_/.test(who) && !members.has(who)) {
778
784
  stderr += `skip ${who} (not a member of ${company})\n`;
779
785
  skipped += 1;
780
786
  continue;
@@ -913,7 +919,7 @@ export function worklistCommand(args, root) {
913
919
  if (key === "--company" || key === "--channel" || key === "--limit" || key === "--mark-done") {
914
920
  if (index + 1 >= args.length) {
915
921
  const line = key === "--mark-done" ? 30 : 29;
916
- return err(1, `${resolveBundledAsset(`${ASSET}ontology-source-worklist.sh`)}: line ${line}: $2: unbound variable\n`);
922
+ return err(1, `${legacyAssetPath("ontology-source-worklist.sh")}: line ${line}: $2: unbound variable\n`);
917
923
  }
918
924
  const value = args[++index];
919
925
  if (key === "--company")
@@ -1069,7 +1075,7 @@ export function worklistCommand(args, root) {
1069
1075
  if (/^[+-]?\d+$/.test(limit) && count >= Number(limit))
1070
1076
  break;
1071
1077
  if (!/^[+-]?\d+$/.test(limit)) {
1072
- process.stderr.write(`${resolveBundledAsset(`${ASSET}ontology-source-worklist.sh`)}: line 186: [: ${limit}: integer expression expected\n`);
1078
+ process.stderr.write(`${legacyAssetPath("ontology-source-worklist.sh")}: line 186: [: ${limit}: integer expression expected\n`);
1073
1079
  }
1074
1080
  count += 1;
1075
1081
  const file = path.join(directory, name);
@@ -1128,12 +1134,12 @@ export function worklistCommand(args, root) {
1128
1134
  }
1129
1135
  export function registerCoreOntologyNativeCommands(ontology, rootFor) {
1130
1136
  const entries = [
1131
- { name: "audience-grant", summary: "Grant scoped ontology audiences and verify each grant", asset: "ontology-audience-grant.sh", root: "live", run: audienceGrant },
1132
- { name: "brief", summary: "Render the local ontology company brief", asset: "ontology-brief.mjs", root: "live", run: (args, root) => briefCommand(args, root) },
1133
- { name: "candidate", summary: "Write a deterministic ontology candidate", asset: "ontology-candidate.sh", root: "live", run: candidateCommand },
1134
- { name: "garden", summary: "Promote local ontology candidates", asset: "ontology-garden.mjs", root: "live", run: (args, root) => gardenCommand(args, root) },
1135
- { name: "source-worklist", summary: "List unprocessed source items and their audience", asset: "ontology-source-worklist.sh", root: "live", run: worklistCommand },
1136
- { name: "source-yaml-validate", summary: "Validate a source.yaml file", asset: "source-yaml-validate.sh", root: "cwd", run: (args) => sourceYamlValidate(args[0]) },
1137
+ { name: "audience-grant", summary: "Grant scoped ontology audiences and verify each grant", root: "live", run: audienceGrant },
1138
+ { name: "brief", summary: "Render the local ontology company brief", root: "live", run: (args, root) => briefCommand(args, root) },
1139
+ { name: "candidate", summary: "Write a deterministic ontology candidate", root: "live", run: candidateCommand },
1140
+ { name: "garden", summary: "Promote local ontology candidates", root: "live", run: (args, root) => gardenCommand(args, root) },
1141
+ { name: "source-worklist", summary: "List unprocessed source items and their audience", root: "live", run: worklistCommand },
1142
+ { name: "source-yaml-validate", summary: "Validate a source.yaml file", root: "cwd", run: (args) => sourceYamlValidate(args[0]) },
1137
1143
  ];
1138
1144
  const rawArgv = process.argv.slice(2);
1139
1145
  const coreIndex = rawArgv.indexOf("core");
@@ -1170,21 +1176,9 @@ export function registerCoreOntologyNativeCommands(ontology, rootFor) {
1170
1176
  const forwarded = commandIndex >= 0 ? argv.slice(commandIndex + 1)
1171
1177
  : commandContext.args.length > 0 ? commandContext.args : args;
1172
1178
  const liveRoot = entry.root === "live" ? rootFor() : process.cwd();
1173
- const { coreNativeOntologyEnabled } = await import("./core-native-family-flag.js");
1174
- if (!await coreNativeOntologyEnabled()) {
1175
- const result = runBundledScript({
1176
- asset: `${ASSET}${entry.asset}`,
1177
- args: forwarded,
1178
- cwd: process.cwd(),
1179
- ...(entry.root === "live" ? { hqRoot: liveRoot } : {}),
1180
- });
1181
- if (result.code !== 0)
1182
- process.exitCode = result.code;
1183
- return;
1184
- }
1185
1179
  writeResult(entry.run(forwarded, entry.root === "live" ? liveRoot : process.cwd()));
1186
1180
  });
1187
- describeCoreCommand(command, { execution: "native", asset: `${ASSET}${entry.asset}`, root: entry.root });
1181
+ describeCoreCommand(command, { execution: "native", root: entry.root });
1188
1182
  }
1189
1183
  }
1190
1184
  //# sourceMappingURL=core-ontology-native.js.map
@@ -0,0 +1,3 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerCorePipelineWorkerTableCommand(core: Command): void;
3
+ //# sourceMappingURL=core-pipeline-workers-command.d.ts.map