@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 CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.345.29] — 2026-10-06
6
+ - Route `hq core checkpoint` through an isolated fast entry and defer identity and ontology imports to the paths that use them.
7
+
8
+ - Add folder-based company registry resolution to the native resolve-company fast path.
9
+
10
+ ## [5.345.28] — 2026-10-06
11
+ - Limit `hq meetings live` to active, recent, and imminent notetakers by default, and avoid transcript requests for inactive meetings.
12
+
5
13
  ## [5.345.27] — 2026-10-06
6
14
 
7
15
  - Add `hq meetings live` to list, read, and follow provisional live meeting
package/README.md CHANGED
@@ -14,12 +14,15 @@ for install and link commands.
14
14
 
15
15
  ## Live meeting transcripts
16
16
 
17
- Use `hq meetings live --company <slug>` to list the live or recently ended
18
- meetings you can read. Give it a Recall bot id to print the current transcript,
19
- or add `--follow` to print new lines as they arrive.
17
+ Use `hq meetings live --company <slug>` to list active meetings, meetings that
18
+ ended in the last seven days, and notetakers scheduled in the next 15 minutes.
19
+ Use `--all` to include older and future notetakers. Give it a Recall bot id to
20
+ print the current transcript, or add `--follow` to print new lines as they
21
+ arrive.
20
22
 
21
23
  ```bash
22
24
  hq meetings live --company acme
25
+ hq meetings live --company acme --all
23
26
  hq meetings live --company acme <recallBotId> --follow
24
27
  ```
25
28
 
@@ -8,26 +8,36 @@
8
8
  #
9
9
  # Output: {"company":"<slug>","source":"prompt|session|device_default|none"}
10
10
  # Always exits 0 and never writes state.
11
+ #
12
+ # Folder mode (--path <dir>): ask the repo-to-company registry through
13
+ # `$HQ_CLI_BIN resolve-company --path <dir> --json` (HQ_CLI_BIN defaults to
14
+ # `hq`). Sources: registry (linked folder), registry_miss (not linked), or
15
+ # unavailable (CLI missing, failed, timed out, or returned bad output). A
16
+ # registry answer is accepted only when it names a real companies/<slug>
17
+ # directory. Folder mode never falls back to prompt, session, or device default.
11
18
 
12
19
  set -uo pipefail
13
20
 
14
21
  ROOT=""
15
22
  PROMPT=""
16
23
  HAVE_PROMPT=0
24
+ FOLDER=""
25
+ HAVE_FOLDER=0
17
26
 
18
27
  while [ $# -gt 0 ]; do
19
28
  case "$1" in
20
29
  --root) ROOT="${2:-}"; shift 2 || shift ;;
21
30
  --prompt) PROMPT="${2:-}"; HAVE_PROMPT=1; shift 2 || shift ;;
31
+ --path) FOLDER="${2:-}"; HAVE_FOLDER=1; shift 2 || shift ;;
22
32
  --help|-h)
23
- sed -n '2,14p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
33
+ sed -n '2,21p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
24
34
  exit 0
25
35
  ;;
26
36
  *) shift ;;
27
37
  esac
28
38
  done
29
39
 
30
- if [ "$HAVE_PROMPT" -eq 0 ] && [ ! -t 0 ]; then
40
+ if [ "$HAVE_PROMPT" -eq 0 ] && [ "$HAVE_FOLDER" -eq 0 ] && [ ! -t 0 ]; then
31
41
  PROMPT="$(cat 2>/dev/null || true)"
32
42
  fi
33
43
  : "${PROMPT:=}"
@@ -41,6 +51,150 @@ if [ -z "$ROOT" ]; then
41
51
  ROOT="${HQ_ROOT:-${CLAUDE_PROJECT_DIR:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && cd .. && pwd)}}"
42
52
  fi
43
53
 
54
+ # Runs a command with a hard deadline (HQ_RESOLVE_TIMEOUT_MS, default 2000).
55
+ run_with_timeout() {
56
+ command -v node >/dev/null 2>&1 || return 127
57
+ node -e '
58
+ const { spawn } = require("child_process");
59
+ const command = process.argv[1];
60
+ const args = process.argv.slice(2);
61
+ const timeoutMs = Number(process.env.HQ_RESOLVE_TIMEOUT_MS) || 2000;
62
+ if (!command) process.exitCode = 127;
63
+ else {
64
+ let child;
65
+ try {
66
+ child = spawn(command, args, { detached: true, stdio: ["ignore", "pipe", "ignore"] });
67
+ } catch {
68
+ process.exitCode = 127;
69
+ }
70
+ if (child) {
71
+ let exited = false;
72
+ let exitStatus = 1;
73
+ let timedOut = false;
74
+ let drainExpired = false;
75
+ let pendingWrites = 0;
76
+ let finished = false;
77
+ let drainTimer;
78
+ let timeoutKillTimer;
79
+ let timeoutFinalTimer;
80
+ let deadlineTimer;
81
+ const signalGroup = (signal) => {
82
+ if (!child.pid) return;
83
+ try {
84
+ if (process.platform === "win32") child.kill(signal);
85
+ else process.kill(-child.pid, signal);
86
+ } catch {}
87
+ };
88
+ const maybeFinish = () => {
89
+ if (finished || !exited || pendingWrites !== 0 || (!drainExpired && !child.stdout.readableEnded)) return;
90
+ finished = true;
91
+ clearTimeout(deadlineTimer);
92
+ clearTimeout(drainTimer);
93
+ clearTimeout(timeoutKillTimer);
94
+ clearTimeout(timeoutFinalTimer);
95
+ signalGroup("SIGTERM");
96
+ process.exitCode = timedOut ? 124 : exitStatus;
97
+ process.exit();
98
+ };
99
+ const writeChunk = (chunk) => {
100
+ pendingWrites += 1;
101
+ process.stdout.write(chunk, () => {
102
+ pendingWrites -= 1;
103
+ maybeFinish();
104
+ });
105
+ };
106
+ child.stdout.on("data", writeChunk);
107
+ child.stdout.once("end", () => {
108
+ drainExpired = true;
109
+ maybeFinish();
110
+ });
111
+ child.once("error", () => {
112
+ exited = true;
113
+ exitStatus = 127;
114
+ drainExpired = true;
115
+ maybeFinish();
116
+ });
117
+ child.once("exit", (code) => {
118
+ exited = true;
119
+ exitStatus = typeof code === "number" ? code : 1;
120
+ signalGroup("SIGTERM");
121
+ if (!child.stdout.readableEnded) {
122
+ drainTimer = setTimeout(() => {
123
+ child.stdout.pause();
124
+ let chunk;
125
+ while ((chunk = child.stdout.read()) !== null) writeChunk(chunk);
126
+ process.stdout.write("", () => {
127
+ drainExpired = true;
128
+ maybeFinish();
129
+ });
130
+ }, 100);
131
+ } else {
132
+ drainExpired = true;
133
+ }
134
+ maybeFinish();
135
+ });
136
+ deadlineTimer = setTimeout(() => {
137
+ timedOut = true;
138
+ signalGroup("SIGTERM");
139
+ timeoutKillTimer = setTimeout(() => signalGroup("SIGKILL"), 100);
140
+ timeoutFinalTimer = setTimeout(() => {
141
+ if (!exited) {
142
+ exited = true;
143
+ exitStatus = 124;
144
+ child.stdout.destroy();
145
+ drainExpired = true;
146
+ maybeFinish();
147
+ }
148
+ }, 1000);
149
+ }, timeoutMs);
150
+ }
151
+ }
152
+ ' "$@"
153
+ }
154
+
155
+ unavailable() {
156
+ printf 'resolve-company: WARNING company registry unavailable (%s); binding personal, not guessing a company\n' "$1" >&2
157
+ emit "" "unavailable"
158
+ }
159
+
160
+ if [ "$HAVE_FOLDER" -eq 1 ]; then
161
+ [ -n "$FOLDER" ] || unavailable "empty --path"
162
+ case "$FOLDER" in
163
+ /*|[A-Za-z]:/*|[A-Za-z]:\\*|\\\\*) ;;
164
+ *)
165
+ caller_cwd="${HQ_CALLER_CWD:-$PWD}"
166
+ caller_cwd="$(cd "$caller_cwd" 2>/dev/null && pwd -P)" || unavailable "caller working directory unavailable"
167
+ if [ "$FOLDER" = "." ]; then FOLDER="$caller_cwd"; else FOLDER="$caller_cwd/$FOLDER"; fi
168
+ ;;
169
+ esac
170
+ cli="${HQ_CLI_BIN:-hq}"
171
+ command -v "$cli" >/dev/null 2>&1 || unavailable "'$cli' not found"
172
+ command -v jq >/dev/null 2>&1 || unavailable "jq not found"
173
+ status=0
174
+ if command -v node >/dev/null 2>&1; then
175
+ out="$(HQ_NO_UPDATE_CHECK=1 HQ_RESOLVE_TIMEOUT_MS="${HQ_RESOLVE_TIMEOUT_MS:-5000}" run_with_timeout "$cli" resolve-company --path "$FOLDER" --json)" || status=$?
176
+ else
177
+ out="$("$cli" resolve-company --path "$FOLDER" --json 2>/dev/null)" || status=$?
178
+ fi
179
+ kind="$(printf '%s' "$out" | jq -r 'if type != "object" then "bad" elif .company == null then "miss" elif (.company | type) == "string" then "hit" else "bad" end' 2>/dev/null | sed 's/\r$//' || printf 'bad')"
180
+ if [ "$status" -ne 0 ] && ! { [ "$status" -eq 1 ] && [ "$kind" = "miss" ]; }; then
181
+ unavailable "'$cli resolve-company' exited $status"
182
+ fi
183
+ case "$kind" in
184
+ miss) emit "" "registry_miss" ;;
185
+ hit) ;;
186
+ *) unavailable "'$cli resolve-company' returned unreadable output" ;;
187
+ esac
188
+ slug="$(printf '%s' "$out" | jq -r '.company' | sed 's/\r$//')"
189
+ case "$slug" in
190
+ ''|personal|_*|*[!A-Za-z0-9_-]*) unavailable "registry returned invalid company '$slug'" ;;
191
+ esac
192
+ if [ ! -d "$ROOT/companies/$slug" ] || [ -L "$ROOT/companies/$slug" ]; then
193
+ unavailable "registry company '$slug' has no companies/$slug directory in $ROOT"
194
+ fi
195
+ emit "$slug" "registry"
196
+ fi
197
+
44
198
  MANIFEST="$ROOT/companies/manifest.yaml"
45
199
  [ -f "$MANIFEST" ] || emit "" "none"
46
200
 
@@ -65,7 +219,7 @@ SLUGS="$(
65
219
  [ -n "$SLUGS" ] || emit "" "none"
66
220
 
67
221
  is_known_slug() {
68
- printf '%s\n' "$SLUGS" | grep -Fx -- "$1" >/dev/null
222
+ printf '%s\n' "$SLUGS" | grep -Fx "$1" >/dev/null
69
223
  }
70
224
 
71
225
  prompt_slug() {
@@ -134,72 +288,6 @@ is_fleet_identity() {
134
288
  return 1
135
289
  }
136
290
 
137
- run_with_timeout() {
138
- command -v node >/dev/null 2>&1 || return 127
139
- node -e '
140
- const { spawn } = require("child_process");
141
- const command = process.argv[1];
142
- if (!command) process.exit(127);
143
- const child = spawn(command, process.argv.slice(2), { detached: true, stdio: ["ignore", "pipe", "ignore"] });
144
- let finished = false;
145
- let exited = false;
146
- let exitStatus = 1;
147
- let flushedAfterExit = false;
148
- let pendingWrites = 0;
149
- let stdoutEnded = false;
150
- let drainTimer;
151
- const finishWhenReady = () => {
152
- if (finished || !exited || pendingWrites !== 0) return;
153
- if (!stdoutEnded && !flushedAfterExit) return;
154
- finished = true;
155
- clearTimeout(timer);
156
- clearTimeout(drainTimer);
157
- try { process.kill(-child.pid, "SIGTERM"); } catch (_) {}
158
- process.exit(exitStatus);
159
- };
160
- const forward = (chunk) => {
161
- pendingWrites++;
162
- process.stdout.write(chunk, () => {
163
- pendingWrites--;
164
- finishWhenReady();
165
- });
166
- };
167
- const finish = (status) => {
168
- if (finished) return;
169
- finished = true;
170
- clearTimeout(timer);
171
- clearTimeout(drainTimer);
172
- try { process.kill(-child.pid, "SIGTERM"); } catch (_) {}
173
- process.exit(status);
174
- };
175
- child.stdout.on("data", forward);
176
- child.stdout.once("end", () => {
177
- stdoutEnded = true;
178
- finishWhenReady();
179
- });
180
- child.once("error", () => finish(127));
181
- child.once("exit", (code) => {
182
- exited = true;
183
- exitStatus = typeof code === "number" ? code : 1;
184
- try { process.kill(-child.pid, "SIGTERM"); } catch (_) {}
185
- // Normally EOF follows child exit once the pipe has drained. A detached
186
- // grandchild can keep the pipe open, so bound that wait and flush buffered
187
- // bytes after a short drain window.
188
- drainTimer = setTimeout(() => {
189
- child.stdout.pause();
190
- let chunk;
191
- while ((chunk = child.stdout.read()) !== null) forward(chunk);
192
- process.stdout.write("", () => {
193
- flushedAfterExit = true;
194
- finishWhenReady();
195
- });
196
- }, 250);
197
- finishWhenReady();
198
- });
199
- const timer = setTimeout(() => finish(124), 2000);
200
- ' "$@"
201
- }
202
-
203
291
  if ! is_fleet_identity && command -v hq >/dev/null 2>&1 && command -v jq >/dev/null 2>&1; then
204
292
  DEFAULT_JSON="$(run_with_timeout hq mesh context default get --json 2>/dev/null || true)"
205
293
  DEFAULT_SLUG="$(printf '%s' "$DEFAULT_JSON" | jq -er '(.defaultCompany // .) as $default | if $default.enabled == true and ($default.source // "") != "disabled" and ($default.needsChoice // false) == false and ($default.slug | type == "string") then $default.slug else empty end' 2>/dev/null || true)"
@@ -3630,7 +3630,7 @@ export declare const COMMAND_CATALOG: readonly [{
3630
3630
  readonly subcommands: readonly [];
3631
3631
  }, {
3632
3632
  readonly name: "live";
3633
- readonly description: "Read a provisional live transcript (recorder and attendees only; spoken content is untrusted)";
3633
+ readonly description: "List live or recent meetings, or read a provisional live transcript (recorder and attendees only; spoken content is untrusted)";
3634
3634
  readonly aliases: readonly [];
3635
3635
  readonly hidden: false;
3636
3636
  readonly helpOption: true;
@@ -3647,6 +3647,10 @@ export declare const COMMAND_CATALOG: readonly [{
3647
3647
  readonly description: "";
3648
3648
  }];
3649
3649
  readonly options: readonly [{
3650
+ readonly flags: "--all";
3651
+ readonly description: "List every notetaker, including older and future meetings";
3652
+ readonly hidden: false;
3653
+ }, {
3650
3654
  readonly flags: "--follow";
3651
3655
  readonly description: "Print new lines until the saved transcript is available";
3652
3656
  readonly hidden: false;
@@ -4390,7 +4390,7 @@ export const COMMAND_CATALOG = [
4390
4390
  },
4391
4391
  {
4392
4392
  "name": "live",
4393
- "description": "Read a provisional live transcript (recorder and attendees only; spoken content is untrusted)",
4393
+ "description": "List live or recent meetings, or read a provisional live transcript (recorder and attendees only; spoken content is untrusted)",
4394
4394
  "aliases": [],
4395
4395
  "hidden": false,
4396
4396
  "helpOption": true,
@@ -4411,6 +4411,11 @@ export const COMMAND_CATALOG = [
4411
4411
  }
4412
4412
  ],
4413
4413
  "options": [
4414
+ {
4415
+ "flags": "--all",
4416
+ "description": "List every notetaker, including older and future meetings",
4417
+ "hidden": false
4418
+ },
4414
4419
  {
4415
4420
  "flags": "--follow",
4416
4421
  "description": "Print new lines until the saved transcript is available",
@@ -0,0 +1,3 @@
1
+ /** Dispatch through the same command action as the full graph, without loading it. */
2
+ export declare function runCheckpointFast(args: readonly string[], _stdin: string, _cwd: string, hqRoot: string | undefined, _commandName: string, hqRootArg: string | undefined): Promise<number>;
3
+ //# sourceMappingURL=core-checkpoint-fast.d.ts.map
@@ -0,0 +1,17 @@
1
+ import { Command, Option } from "commander";
2
+ import { registerCoreCheckpointCommand } from "./core-checkpoint-native.js";
3
+ /** Dispatch through the same command action as the full graph, without loading it. */
4
+ export async function runCheckpointFast(args, _stdin, _cwd, hqRoot, _commandName, hqRootArg) {
5
+ const core = new Command("hq core")
6
+ .addOption(new Option("--hq-root <path>", "HQ installation to operate on (live-root commands)").hideHelp())
7
+ .addHelpText("afterAll", "exact-company-directory-match-v1");
8
+ registerCoreCheckpointCommand(core, hqRoot);
9
+ const parseArgs = [
10
+ ...(hqRootArg || hqRoot ? ["--hq-root", hqRootArg ?? hqRoot] : []),
11
+ "checkpoint",
12
+ ...args,
13
+ ];
14
+ await core.parseAsync(parseArgs, { from: "user" });
15
+ return typeof process.exitCode === "number" ? process.exitCode : 0;
16
+ }
17
+ //# sourceMappingURL=core-checkpoint-fast.js.map
@@ -0,0 +1,76 @@
1
+ /**
2
+ * `hq core checkpoint` — synchronous end-of-turn state capture plus an
3
+ * optional detached HQ-maintenance sibling.
4
+ *
5
+ * The foreground command intentionally performs only local filesystem and git
6
+ * reads/writes. It never waits for the sibling, and it never performs network
7
+ * I/O itself.
8
+ */
9
+ import * as fs from "node:fs";
10
+ import { Command } from "commander";
11
+ type Backend = "claude" | "codex" | "grok" | "none";
12
+ type SpawnableBackend = Exclude<Backend, "none">;
13
+ /**
14
+ * Printed after every non-dry-run checkpoint, real or --idle. Agents were
15
+ * treating the checkpoint call as the end of the turn, leaving their actual
16
+ * findings only in the checkpoint payload — which the user never sees. This
17
+ * line rides the command output (the one channel guaranteed to reach the
18
+ * calling agent) to force the user-facing reply. Deliberately conditional on
19
+ * whether the reply was already delivered this turn: an unconditional
20
+ * "restate in full" made agents repeat a reply the user had already seen
21
+ * (both the CLI and the desktop app render pre-tool-call text), while an
22
+ * unconditional "no commentary after" hid the reply from agents that had not
23
+ * yet written one. The Stop gate makes the same distinction from the
24
+ * transcript — and backstops this reminder mechanically: a satisfying
25
+ * checkpoint on a work turn whose genuine reply is still missing is blocked
26
+ * once with a dedicated reply demand. This line covers proactive checkpoints
27
+ * the gate never sees. Mirrors the hq-core policies
28
+ * `checkpoint-is-bookkeeping-not-user-communication` and
29
+ * `checkpoint-is-not-the-user-report`.
30
+ */
31
+ export declare const CHECKPOINT_REPLY_REMINDER: string;
32
+ /**
33
+ * The --idle variant: an idle-only turn (nothing ran, nothing to report) is
34
+ * exempt at the Stop gate, so this text must never order a reply into
35
+ * existence — but an --idle after read-only work is NOT exempt (the gate
36
+ * demands the findings), so the conditional half still points there.
37
+ */
38
+ export declare const CHECKPOINT_IDLE_REPLY_REMINDER: string;
39
+ export declare function renderSiblingPrompt(runDir: string, payloadPath: string, options?: {
40
+ company?: string | null;
41
+ hqRoot?: string;
42
+ }): string;
43
+ export type WriteStampsOptions = {
44
+ /**
45
+ * Filesystem seam (default the real `node:fs`); injected in tests to force a
46
+ * permission errno so the HqStateWriteError conversion can be proven without a
47
+ * real unwritable path.
48
+ */
49
+ fs?: Pick<typeof fs, "mkdirSync" | "writeFileSync" | "renameSync" | "unlinkSync">;
50
+ /** Runtime seam for proving the Windows-only atomic path without host assumptions. */
51
+ platform?: NodeJS.Platform;
52
+ /** Synchronous delay seam for the bounded Windows lock retry. */
53
+ waitForRetry?: (delayMs: number) => void;
54
+ };
55
+ export declare function writeStamps(liveRoot: string, sessionId: string | undefined, options?: WriteStampsOptions): string[];
56
+ /**
57
+ * Preference order for `--backend auto`: the caller's own backend first, so a
58
+ * claude session keeps using claude and a codex session keeps using codex
59
+ * (same-engine continuity), then the fallback priority claude -> codex -> grok
60
+ * for whatever the caller is not. Deterministic and env-only, so it is unit
61
+ * tested directly. `preferGrok` (the company's grok-backend flag) puts grok
62
+ * ahead of that order and leaves the rest as the fallback.
63
+ */
64
+ export declare function autoBackendPreference(preferGrok?: boolean): SpawnableBackend[];
65
+ /**
66
+ * Whether the payload company's last ontology plan recorded
67
+ * checkpoint.ontology.grok-backend as on. Reads only the local state file the
68
+ * detached sibling writes, so a foreground checkpoint never waits on the flag
69
+ * registry; a flag change takes effect from the checkpoint after the next plan.
70
+ */
71
+ export declare function companyPrefersGrok(liveRoot: string, companySlug: string | null | undefined): Promise<boolean>;
72
+ export declare function siblingArgs(backend: SpawnableBackend, prompt: string): string[];
73
+ /** Attach the native checkpoint command to the hidden `hq core` group. */
74
+ export declare function registerCoreCheckpointCommand(core: Command, preResolvedHqRoot?: string): void;
75
+ export {};
76
+ //# sourceMappingURL=core-checkpoint-native.d.ts.map