@indigoai-us/hq-cli 5.345.27 → 5.345.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +6 -3
- package/assets/scaffold/core/scripts/resolve-company.sh +157 -69
- package/dist/command-catalog.generated.d.ts +5 -1
- package/dist/command-catalog.generated.js +6 -1
- package/dist/commands/core-checkpoint-fast.d.ts +3 -0
- package/dist/commands/core-checkpoint-fast.js +17 -0
- package/dist/commands/core-checkpoint-native.d.ts +76 -0
- package/dist/commands/core-checkpoint-native.js +1252 -0
- package/dist/commands/core-checkpoint.d.ts +2 -75
- package/dist/commands/core-checkpoint.js +2 -1248
- package/dist/commands/core-resolve-company-command.js +1 -0
- package/dist/commands/core-resolve-company-native.d.ts +2 -2
- package/dist/commands/core-resolve-company-native.js +149 -12
- package/dist/commands/meetings.js +58 -18
- package/dist/fast-scaffold.js +10 -0
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ type HqResult = {
|
|
|
10
10
|
code: number;
|
|
11
11
|
stdout: string;
|
|
12
12
|
};
|
|
13
|
-
type ResolveCompanyFs = Pick<typeof fs, "readFileSync" | "statSync" | "accessSync">;
|
|
13
|
+
type ResolveCompanyFs = Pick<typeof fs, "readFileSync" | "statSync" | "lstatSync" | "accessSync">;
|
|
14
14
|
export type ResolveCompanyDependencies = {
|
|
15
15
|
cwd: string;
|
|
16
16
|
hqRoot?: string;
|
|
@@ -18,7 +18,7 @@ export type ResolveCompanyDependencies = {
|
|
|
18
18
|
fs?: ResolveCompanyFs;
|
|
19
19
|
stdin?: string;
|
|
20
20
|
stdinIsTty?: boolean;
|
|
21
|
-
spawnHq?: (args: string[], env: NodeJS.ProcessEnv, timeoutMs: number, cwd?: string) => Promise<HqResult>;
|
|
21
|
+
spawnHq?: (args: string[], env: NodeJS.ProcessEnv, timeoutMs: number, cwd?: string, command?: string) => Promise<HqResult>;
|
|
22
22
|
pid?: number;
|
|
23
23
|
random?: () => number;
|
|
24
24
|
};
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/** Native port of resolve-company.sh. This module stays on the fast import path. */
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
2
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { awkCannotOpenFileDiagnostic } from "../lib/core-utils/awk-diagnostics.js";
|
|
6
|
+
import { buildCmdExeSpawnPlan, isWindowsBatchFile } from "../utils/windows-spawn.js";
|
|
6
7
|
export const RESOLVE_COMPANY_ASSET = "core/scripts/resolve-company.sh";
|
|
7
8
|
export const RESOLVE_COMPANY_HELP = [
|
|
8
9
|
"hq-core: public",
|
|
@@ -15,6 +16,13 @@ export const RESOLVE_COMPANY_HELP = [
|
|
|
15
16
|
"Output: {\"company\":\"<slug>\",\"source\":\"prompt|session|device_default|none\"}",
|
|
16
17
|
"Always exits 0 and never writes state.",
|
|
17
18
|
"",
|
|
19
|
+
"Folder mode (--path <dir>): ask the repo-to-company registry through",
|
|
20
|
+
"`$HQ_CLI_BIN resolve-company --path <dir> --json` (HQ_CLI_BIN defaults to",
|
|
21
|
+
"`hq`). Sources: registry (linked folder), registry_miss (not linked), or",
|
|
22
|
+
"unavailable (CLI missing, failed, timed out, or returned bad output). A",
|
|
23
|
+
"registry answer is accepted only when it names a real companies/<slug>",
|
|
24
|
+
"directory. Folder mode never falls back to prompt, session, or device default.",
|
|
25
|
+
"",
|
|
18
26
|
"set -uo pipefail",
|
|
19
27
|
"",
|
|
20
28
|
"ROOT=\"\"",
|
|
@@ -222,21 +230,49 @@ function validPreflight(text, slug, session, operation) {
|
|
|
222
230
|
value.companySlug === slug &&
|
|
223
231
|
typeof value.companyUid === "string" && value.companyUid.length > 0);
|
|
224
232
|
}
|
|
225
|
-
function
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
233
|
+
function commandPath(name, env) {
|
|
234
|
+
const hasPathSeparator = name.includes("/") || name.includes("\\");
|
|
235
|
+
const pathKey = Object.keys(env).find((key) => key.toUpperCase() === "PATH");
|
|
236
|
+
const candidates = hasPathSeparator
|
|
237
|
+
? [name]
|
|
238
|
+
: (pathKey ? env[pathKey] ?? "" : "").split(path.delimiter).flatMap((directory) => {
|
|
239
|
+
const base = path.join(directory || ".", name);
|
|
240
|
+
return process.platform === "win32" && !path.extname(name)
|
|
241
|
+
? [`${base}.com`, `${base}.exe`, `${base}.bat`, `${base}.cmd`]
|
|
242
|
+
: [base];
|
|
243
|
+
});
|
|
244
|
+
for (const candidate of candidates) {
|
|
229
245
|
try {
|
|
230
246
|
fs.accessSync(candidate, fs.constants.X_OK);
|
|
231
|
-
return
|
|
247
|
+
return candidate;
|
|
232
248
|
}
|
|
233
249
|
catch {
|
|
234
250
|
// `command -v` simply advances to the next PATH entry.
|
|
235
251
|
}
|
|
236
252
|
}
|
|
253
|
+
return undefined;
|
|
254
|
+
}
|
|
255
|
+
function commandOnPath(name, env) {
|
|
256
|
+
if (commandPath(name, env))
|
|
257
|
+
return true;
|
|
258
|
+
if (process.platform !== "win32" || name.includes("/") || name.includes("\\") || path.extname(name))
|
|
259
|
+
return false;
|
|
260
|
+
const pathKey = Object.keys(env).find((key) => key.toUpperCase() === "PATH");
|
|
261
|
+
for (const directory of (pathKey ? env[pathKey] ?? "" : "").split(path.delimiter)) {
|
|
262
|
+
try {
|
|
263
|
+
// Git Bash considers an executable extensionless script a command. Keep
|
|
264
|
+
// the presence check faithful to that shell contract; actual Windows
|
|
265
|
+
// process launch still selects a PATHEXT executable or batch shim.
|
|
266
|
+
fs.accessSync(path.join(directory || ".", name), fs.constants.X_OK);
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
// `command -v` advances through each PATH entry.
|
|
271
|
+
}
|
|
272
|
+
}
|
|
237
273
|
return false;
|
|
238
274
|
}
|
|
239
|
-
function runHq(args, env, timeoutMs, cwd) {
|
|
275
|
+
function runHq(args, env, timeoutMs, cwd, command = "hq") {
|
|
240
276
|
return new Promise((resolve) => {
|
|
241
277
|
let settled = false;
|
|
242
278
|
let stdout = "";
|
|
@@ -247,7 +283,15 @@ function runHq(args, env, timeoutMs, cwd) {
|
|
|
247
283
|
if (!child?.pid)
|
|
248
284
|
return;
|
|
249
285
|
try {
|
|
250
|
-
process.
|
|
286
|
+
if (process.platform === "win32") {
|
|
287
|
+
const taskkill = path.join(env.SystemRoot ?? env.WINDIR ?? "C:\\Windows", "System32", "taskkill.exe");
|
|
288
|
+
const result = spawnSync(taskkill, ["/PID", String(child.pid), "/T", "/F"], { windowsHide: true });
|
|
289
|
+
if (result.error || result.status !== 0)
|
|
290
|
+
child.kill(signal);
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
process.kill(-child.pid, signal);
|
|
294
|
+
}
|
|
251
295
|
}
|
|
252
296
|
catch (error) {
|
|
253
297
|
if (errorCode(error) !== "ESRCH")
|
|
@@ -279,7 +323,24 @@ function runHq(args, env, timeoutMs, cwd) {
|
|
|
279
323
|
}
|
|
280
324
|
}, timeoutMs);
|
|
281
325
|
try {
|
|
282
|
-
|
|
326
|
+
const resolved = commandPath(command, env);
|
|
327
|
+
if (!resolved) {
|
|
328
|
+
finish({ code: 127, stdout });
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
let executable = resolved;
|
|
332
|
+
let executableArgs = args;
|
|
333
|
+
let windowsVerbatimArguments;
|
|
334
|
+
if (process.platform === "win32" && isWindowsBatchFile(resolved)) {
|
|
335
|
+
const plan = buildCmdExeSpawnPlan(resolved, args, env);
|
|
336
|
+
executable = plan.cmd;
|
|
337
|
+
executableArgs = plan.args;
|
|
338
|
+
windowsVerbatimArguments = plan.windowsVerbatimArguments;
|
|
339
|
+
}
|
|
340
|
+
child = spawn(executable, executableArgs, {
|
|
341
|
+
cwd, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "ignore"], env,
|
|
342
|
+
windowsVerbatimArguments,
|
|
343
|
+
});
|
|
283
344
|
}
|
|
284
345
|
catch {
|
|
285
346
|
finish({ code: 127, stdout });
|
|
@@ -301,6 +362,8 @@ function parseArgs(args) {
|
|
|
301
362
|
let root = "";
|
|
302
363
|
let prompt = "";
|
|
303
364
|
let havePrompt = false;
|
|
365
|
+
let folder = "";
|
|
366
|
+
let haveFolder = false;
|
|
304
367
|
for (let index = 0; index < args.length;) {
|
|
305
368
|
const arg = args[index];
|
|
306
369
|
if (arg === "--root") {
|
|
@@ -312,14 +375,84 @@ function parseArgs(args) {
|
|
|
312
375
|
havePrompt = true;
|
|
313
376
|
index += Math.min(2, args.length - index);
|
|
314
377
|
}
|
|
378
|
+
else if (arg === "--path") {
|
|
379
|
+
folder = args[index + 1] ?? "";
|
|
380
|
+
haveFolder = true;
|
|
381
|
+
index += Math.min(2, args.length - index);
|
|
382
|
+
}
|
|
315
383
|
else if (arg === "--help" || arg === "-h") {
|
|
316
|
-
return { root, prompt, havePrompt, help: true };
|
|
384
|
+
return { root, prompt, havePrompt, folder, haveFolder, help: true };
|
|
317
385
|
}
|
|
318
386
|
else {
|
|
319
387
|
index += 1;
|
|
320
388
|
}
|
|
321
389
|
}
|
|
322
|
-
return { root, prompt, havePrompt, help: false };
|
|
390
|
+
return { root, prompt, havePrompt, folder, haveFolder, help: false };
|
|
391
|
+
}
|
|
392
|
+
function unavailable(reason) {
|
|
393
|
+
return {
|
|
394
|
+
...output("", "unavailable"),
|
|
395
|
+
stderr: Buffer.from(`resolve-company: WARNING company registry unavailable (${reason}); binding personal, not guessing a company\n`),
|
|
396
|
+
};
|
|
397
|
+
}
|
|
398
|
+
async function resolveFolder(folder, root, cwd, env, fileSystem, invoke) {
|
|
399
|
+
if (!folder)
|
|
400
|
+
return unavailable("empty --path");
|
|
401
|
+
const cli = env.HQ_CLI_BIN || "hq";
|
|
402
|
+
if (!commandPath(cli, env))
|
|
403
|
+
return unavailable(`'${cli}' not found`);
|
|
404
|
+
if (!commandPath("jq", env))
|
|
405
|
+
return unavailable("jq not found");
|
|
406
|
+
// The registry command is the contract boundary. Calling it preserves its
|
|
407
|
+
// own hq-anywhere gate and avoids importing the full command graph here.
|
|
408
|
+
const hqEnv = {
|
|
409
|
+
...EMPTY_ENV,
|
|
410
|
+
...env,
|
|
411
|
+
HQ_NO_UPDATE_CHECK: "1",
|
|
412
|
+
HQ_RESOLVE_TIMEOUT_MS: env.HQ_RESOLVE_TIMEOUT_MS || "5000",
|
|
413
|
+
};
|
|
414
|
+
const parsedTimeout = Number(hqEnv.HQ_RESOLVE_TIMEOUT_MS);
|
|
415
|
+
const timeoutMs = parsedTimeout || 2_000;
|
|
416
|
+
const response = await invoke(["resolve-company", "--path", folder, "--json"], hqEnv, timeoutMs, cwd, cli);
|
|
417
|
+
const value = record(parseJson(response.stdout));
|
|
418
|
+
if (response.code !== 0 && !(response.code === 1 && value?.company === null)) {
|
|
419
|
+
return unavailable(`'${cli} resolve-company' exited ${response.code}`);
|
|
420
|
+
}
|
|
421
|
+
if (!value)
|
|
422
|
+
return unavailable(`'${cli} resolve-company' returned unreadable output`);
|
|
423
|
+
if (value.company === null || value.company === undefined)
|
|
424
|
+
return output("", "registry_miss");
|
|
425
|
+
if (typeof value.company !== "string")
|
|
426
|
+
return unavailable(`'${cli} resolve-company' returned unreadable output`);
|
|
427
|
+
// jq -r plus command substitution removes trailing newlines before the
|
|
428
|
+
// shell validates the returned slug.
|
|
429
|
+
const slug = value.company.replace(/\n+$/, "");
|
|
430
|
+
if (!slug || slug === "personal" || slug.startsWith("_") || !/^[A-Za-z0-9_-]+$/.test(slug)) {
|
|
431
|
+
return unavailable(`registry returned invalid company '${slug}'`);
|
|
432
|
+
}
|
|
433
|
+
const companyPath = path.join(root, "companies", slug);
|
|
434
|
+
let isDirectory = false;
|
|
435
|
+
let isSymlink = false;
|
|
436
|
+
try {
|
|
437
|
+
isDirectory = fileSystem.statSync(companyPath).isDirectory();
|
|
438
|
+
}
|
|
439
|
+
catch (error) {
|
|
440
|
+
const code = errorCode(error);
|
|
441
|
+
if (code !== "ENOENT" && code !== "ENOTDIR" && code !== "EACCES" && code !== "ELOOP")
|
|
442
|
+
throw error;
|
|
443
|
+
}
|
|
444
|
+
try {
|
|
445
|
+
isSymlink = fileSystem.lstatSync(companyPath).isSymbolicLink();
|
|
446
|
+
}
|
|
447
|
+
catch (error) {
|
|
448
|
+
const code = errorCode(error);
|
|
449
|
+
if (code !== "ENOENT" && code !== "ENOTDIR" && code !== "EACCES" && code !== "ELOOP")
|
|
450
|
+
throw error;
|
|
451
|
+
}
|
|
452
|
+
if (!isDirectory || isSymlink) {
|
|
453
|
+
return unavailable(`registry company '${slug}' has no companies/${slug} directory in ${root}`);
|
|
454
|
+
}
|
|
455
|
+
return output(slug, "registry");
|
|
323
456
|
}
|
|
324
457
|
async function readStdin() {
|
|
325
458
|
const chunks = [];
|
|
@@ -333,11 +466,14 @@ export async function resolveCompany(args, dependencies) {
|
|
|
333
466
|
const parsed = parseArgs(args);
|
|
334
467
|
if (parsed.help)
|
|
335
468
|
return { code: 0, stdout: Buffer.from(RESOLVE_COMPANY_HELP), stderr: Buffer.alloc(0) };
|
|
469
|
+
const root = parsed.root || dependencies.hqRoot || env.HQ_ROOT || env.CLAUDE_PROJECT_DIR || dependencies.cwd;
|
|
470
|
+
if (parsed.haveFolder) {
|
|
471
|
+
return await resolveFolder(parsed.folder, root, dependencies.cwd, env, fileSystem, dependencies.spawnHq ?? runHq);
|
|
472
|
+
}
|
|
336
473
|
let prompt = parsed.prompt;
|
|
337
474
|
if (!parsed.havePrompt && dependencies.stdinIsTty !== true) {
|
|
338
475
|
prompt = dependencies.stdin ?? await readStdin();
|
|
339
476
|
}
|
|
340
|
-
const root = parsed.root || dependencies.hqRoot || env.HQ_ROOT || env.CLAUDE_PROJECT_DIR || dependencies.cwd;
|
|
341
477
|
const manifest = path.join(root, "companies/manifest.yaml");
|
|
342
478
|
if (!isFile(manifest, fileSystem))
|
|
343
479
|
return output("", "none");
|
|
@@ -393,6 +529,7 @@ export async function resolveCompany(args, dependencies) {
|
|
|
393
529
|
export async function runResolveCompanyFast(args, stdin, cwd, hqRoot, _commandName, _hqRootArg, stdinReader = readStdin) {
|
|
394
530
|
const parsed = parseArgs(args);
|
|
395
531
|
const actualStdin = parsed.havePrompt || process.stdin.isTTY === true
|
|
532
|
+
|| parsed.haveFolder
|
|
396
533
|
? stdin
|
|
397
534
|
: stdin || await stdinReader();
|
|
398
535
|
const result = await resolveCompany(args, {
|
|
@@ -3,15 +3,16 @@ import { readFile } from "node:fs/promises";
|
|
|
3
3
|
import { ensureCognitoToken } from "../utils/cognito-session.js";
|
|
4
4
|
import { vaultApiFetch, getCompanyUid, resolveCallerPersonUid, } from "../utils/vault-api.js";
|
|
5
5
|
import { isPlanGateError, planGateErrorFromPayload, } from "../utils/plan-gate-error.js";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { mapWithConcurrency } from "./sync-manifest.js";
|
|
7
|
+
const LIVE_SNAPSHOT_STATUSES = new Set([
|
|
8
8
|
"joining",
|
|
9
9
|
"recording",
|
|
10
10
|
"in_call",
|
|
11
|
-
"in-call",
|
|
12
|
-
"processing",
|
|
13
|
-
"completed",
|
|
14
11
|
]);
|
|
12
|
+
const RECENT_LIVE_BOT_STATUSES = new Set(["processing", "completed", "no_transcript"]);
|
|
13
|
+
const LIVE_LIST_SNAPSHOT_CONCURRENCY = 10;
|
|
14
|
+
const LIVE_LIST_RECENT_WINDOW_MS = 7 * 24 * 60 * 60 * 1000;
|
|
15
|
+
const LIVE_LIST_UPCOMING_WINDOW_MS = 15 * 60 * 1000;
|
|
15
16
|
const TERMINAL_LIVE_BOT_STATUSES = new Set(["completed", "failed", "done", "ended"]);
|
|
16
17
|
// Two minutes gives a large transcript time to arrive over a slow connection,
|
|
17
18
|
// while keeping the interactive command from waiting indefinitely.
|
|
@@ -91,15 +92,54 @@ function liveBotId(bot) {
|
|
|
91
92
|
return typeof bot.recallBotId === "string" ? bot.recallBotId : bot.botId;
|
|
92
93
|
}
|
|
93
94
|
function liveBotLineCount(bot) {
|
|
95
|
+
if (!LIVE_SNAPSHOT_STATUSES.has(normalizedLiveBotStatus(bot)))
|
|
96
|
+
return "-";
|
|
94
97
|
const value = bot.linesSoFar ?? bot.transcriptLineCount;
|
|
95
98
|
return typeof value === "number" ? String(value) : "-";
|
|
96
99
|
}
|
|
100
|
+
function normalizedLiveBotStatus(bot) {
|
|
101
|
+
return String(bot.status ?? "").toLowerCase().replaceAll("-", "_");
|
|
102
|
+
}
|
|
103
|
+
function liveBotTime(bot) {
|
|
104
|
+
const times = [bot.scheduledStartTime, bot.createdAt]
|
|
105
|
+
.filter((value) => typeof value === "string")
|
|
106
|
+
.map((value) => Date.parse(value))
|
|
107
|
+
.filter(Number.isFinite);
|
|
108
|
+
return times.length > 0 ? Math.max(...times) : Number.NEGATIVE_INFINITY;
|
|
109
|
+
}
|
|
110
|
+
/** Select bots intended for the default `meetings live` listing. */
|
|
111
|
+
function selectLiveMeetingBots(bots, companyId, includeAll, now = new Date()) {
|
|
112
|
+
const companyBots = bots.filter((bot) => bot.companyId === companyId);
|
|
113
|
+
const newestFirst = (a, b) => liveBotTime(b) - liveBotTime(a);
|
|
114
|
+
if (includeAll)
|
|
115
|
+
return companyBots.sort(newestFirst);
|
|
116
|
+
const nowMs = now.getTime();
|
|
117
|
+
const recentSince = nowMs - LIVE_LIST_RECENT_WINDOW_MS;
|
|
118
|
+
const upcomingUntil = nowMs + LIVE_LIST_UPCOMING_WINDOW_MS;
|
|
119
|
+
const active = [];
|
|
120
|
+
const recent = [];
|
|
121
|
+
const imminent = [];
|
|
122
|
+
for (const bot of companyBots) {
|
|
123
|
+
const status = normalizedLiveBotStatus(bot);
|
|
124
|
+
const time = liveBotTime(bot);
|
|
125
|
+
if (LIVE_SNAPSHOT_STATUSES.has(status)) {
|
|
126
|
+
active.push(bot);
|
|
127
|
+
}
|
|
128
|
+
else if (RECENT_LIVE_BOT_STATUSES.has(status) && time >= recentSince && time <= nowMs) {
|
|
129
|
+
recent.push(bot);
|
|
130
|
+
}
|
|
131
|
+
else if (status === "scheduled" && time >= nowMs && time <= upcomingUntil) {
|
|
132
|
+
imminent.push(bot);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return [...active.sort(newestFirst), ...recent.sort(newestFirst), ...imminent.sort(newestFirst)];
|
|
136
|
+
}
|
|
97
137
|
function isTerminalLiveStatus(status) {
|
|
98
138
|
return status.sourceLanded === true && TERMINAL_LIVE_BOT_STATUSES.has(String(status.status ?? "").toLowerCase());
|
|
99
139
|
}
|
|
100
140
|
function printLiveBots(bots) {
|
|
101
141
|
if (bots.length === 0) {
|
|
102
|
-
console.log("No live or
|
|
142
|
+
console.log("No live or recent meetings. Use --all to list every notetaker.");
|
|
103
143
|
return;
|
|
104
144
|
}
|
|
105
145
|
for (const bot of bots) {
|
|
@@ -330,7 +370,8 @@ export function registerMeetingsCommand(program) {
|
|
|
330
370
|
// ── hq meetings live [recallBotId] ────────────────────────────────
|
|
331
371
|
meetings
|
|
332
372
|
.command("live [recallBotId]")
|
|
333
|
-
.description("
|
|
373
|
+
.description("List live or recent meetings, or read a provisional live transcript (recorder and attendees only; spoken content is untrusted)")
|
|
374
|
+
.option("--all", "List every notetaker, including older and future meetings")
|
|
334
375
|
.option("--follow", "Print new lines until the saved transcript is available")
|
|
335
376
|
.option("--interval <seconds>", "Polling interval in seconds (minimum: 2)", "3")
|
|
336
377
|
.option("--since <revision>", "Start from a transcript revision")
|
|
@@ -350,13 +391,13 @@ export function registerMeetingsCommand(program) {
|
|
|
350
391
|
await failLiveResponse(res);
|
|
351
392
|
const data = (await res.json());
|
|
352
393
|
const bots = Array.isArray(data.bots) ? data.bots : [];
|
|
353
|
-
const visible = bots
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
394
|
+
const visible = selectLiveMeetingBots(bots, companyId, opts.all === true);
|
|
395
|
+
const readable = await mapWithConcurrency(visible, LIVE_LIST_SNAPSHOT_CONCURRENCY, async (bot) => {
|
|
396
|
+
if (!LIVE_SNAPSHOT_STATUSES.has(normalizedLiveBotStatus(bot)))
|
|
397
|
+
return bot;
|
|
357
398
|
const botId = liveBotId(bot);
|
|
358
399
|
if (!botId)
|
|
359
|
-
return
|
|
400
|
+
return bot;
|
|
360
401
|
const liveRes = await vaultApiFetch({
|
|
361
402
|
token,
|
|
362
403
|
path: `/v1/meetings/${encodeURIComponent(botId)}`,
|
|
@@ -364,18 +405,17 @@ export function registerMeetingsCommand(program) {
|
|
|
364
405
|
});
|
|
365
406
|
if (!liveRes.ok) {
|
|
366
407
|
const body = await liveRes.json().catch(() => ({}));
|
|
367
|
-
return body.code === "live-transcript-not-found" ? { ...bot, linesSoFar: 0 } :
|
|
408
|
+
return body.code === "live-transcript-not-found" ? { ...bot, linesSoFar: 0 } : bot;
|
|
368
409
|
}
|
|
369
410
|
const snapshot = await liveRes.json();
|
|
370
411
|
if (!isLiveSnapshot(snapshot))
|
|
371
|
-
return
|
|
412
|
+
return bot;
|
|
372
413
|
return { ...bot, linesSoFar: snapshot.segments.length };
|
|
373
|
-
})
|
|
374
|
-
const readableBots = readable.filter((bot) => bot !== null);
|
|
414
|
+
});
|
|
375
415
|
if (meetings.opts().json)
|
|
376
|
-
console.log(JSON.stringify(
|
|
416
|
+
console.log(JSON.stringify(readable, null, 2));
|
|
377
417
|
else
|
|
378
|
-
printLiveBots(
|
|
418
|
+
printLiveBots(readable);
|
|
379
419
|
return;
|
|
380
420
|
}
|
|
381
421
|
const intervalSeconds = Number(opts.interval ?? "3");
|
package/dist/fast-scaffold.js
CHANGED
|
@@ -184,6 +184,16 @@ export const FAST_SCAFFOLD_SCRIPTS = [
|
|
|
184
184
|
shellHqRoot: "live",
|
|
185
185
|
readsStdin: true,
|
|
186
186
|
},
|
|
187
|
+
{
|
|
188
|
+
name: "checkpoint",
|
|
189
|
+
kind: "native",
|
|
190
|
+
modulePath: "./commands/core-checkpoint-fast.js",
|
|
191
|
+
exportName: "runCheckpointFast",
|
|
192
|
+
flagKey: "hq-core-native-fast-route",
|
|
193
|
+
familyFlagKey: "core-native-session",
|
|
194
|
+
fallbackToCommandGraph: true,
|
|
195
|
+
root: "live",
|
|
196
|
+
},
|
|
187
197
|
{
|
|
188
198
|
name: "hq-session",
|
|
189
199
|
kind: "native",
|