@indigoai-us/hq-cli 5.342.17 → 5.342.18

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,10 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.342.18] — 2026-10-04
6
+ - Preserve confirmed remote lane-message responses for in-process monitor delivery.
7
+ - Use native TypeScript renderers for `hq core rebuild-index` commands.
8
+
5
9
  ## [5.342.17] — 2026-10-04
6
10
  - Show agent display names in the agents list and accept them when selecting an agent.
7
11
  - Resume due blocked keep-alive for story-less standing lead lanes, record no-open-story skips in lane history, and report the latest blocked skip in keep-alive audit.
@@ -44,7 +44,7 @@ describe_item() {
44
44
  n=$(find "$path" -mindepth 1 -maxdepth 1 ! -name '.*' 2>/dev/null | wc -l | tr -d ' ')
45
45
  local h=""
46
46
  if [[ -f "$path/README.md" ]]; then
47
- h=$(awk '/^# / { sub(/^# +/, ""); print; exit }' "$path/README.md" 2>/dev/null || true)
47
+ h=$(awk '/^# / { sub(/^# +/, ""); sub(/\r$/, ""); print; exit }' "$path/README.md" 2>/dev/null || true)
48
48
  fi
49
49
  if [[ -n "$h" ]]; then
50
50
  echo "${h} (${n} item(s))"
@@ -56,7 +56,7 @@ describe_item() {
56
56
  case "$name" in
57
57
  *.md)
58
58
  local h
59
- h=$(awk '/^# / { sub(/^# +/, ""); print; exit }' "$path" 2>/dev/null || true)
59
+ h=$(awk '/^# / { sub(/^# +/, ""); sub(/\r$/, ""); print; exit }' "$path" 2>/dev/null || true)
60
60
  [[ -z "$h" ]] && h="$name"
61
61
  echo "$h"
62
62
  ;;
@@ -25,7 +25,7 @@ trunc() {
25
25
  }
26
26
 
27
27
  heading_of() {
28
- awk '/^# / { sub(/^# +/, ""); print; exit }' "$1" 2>/dev/null || true
28
+ awk '/^# / { sub(/^# +/, ""); sub(/\r$/, ""); print; exit }' "$1" 2>/dev/null || true
29
29
  }
30
30
 
31
31
  describe_subdir() {
@@ -25,7 +25,7 @@ trunc() {
25
25
  }
26
26
 
27
27
  heading_md() {
28
- awk '/^# / { sub(/^# +/, ""); print; exit }' "$1" 2>/dev/null || true
28
+ awk '/^# / { sub(/^# +/, ""); sub(/\r$/, ""); print; exit }' "$1" 2>/dev/null || true
29
29
  }
30
30
  title_html() {
31
31
  awk 'BEGIN{IGNORECASE=1} /<title>/ { sub(/.*<title>/, ""); sub(/<\/title>.*/, ""); print; exit }' "$1" 2>/dev/null || true
@@ -27,7 +27,7 @@ trunc() {
27
27
  }
28
28
 
29
29
  heading_md() {
30
- awk '/^# / { sub(/^# +/, ""); print; exit }' "$1" 2>/dev/null || true
30
+ awk '/^# / { sub(/^# +/, ""); sub(/\r$/, ""); print; exit }' "$1" 2>/dev/null || true
31
31
  }
32
32
 
33
33
  describe_subdir() {
@@ -26,8 +26,12 @@ worker_desc() {
26
26
  if command -v yq >/dev/null 2>&1; then
27
27
  yq -r '.worker.description // .worker.bio.role // ""' "$yaml" 2>/dev/null || echo ""
28
28
  else
29
- # Fallback: first-line description grep
30
- awk -F: '/^[[:space:]]+description:/ { sub(/^[^:]+: */, ""); gsub(/^["\x27]|["\x27]$/, ""); print; exit }' "$yaml" 2>/dev/null || echo ""
29
+ # Fallback for machines without yq: prefer description, then bio.role.
30
+ awk -F: '
31
+ /^[[:space:]]+description:/ { sub(/^[^:]+:[[:space:]]*/, ""); gsub(/^["\x27]|["\x27]$/, ""); print; found=1; exit }
32
+ /^[[:space:]]+role:/ { role=$0; sub(/^[^:]+:[[:space:]]*/, "", role); gsub(/^["\x27]|["\x27]$/, "", role) }
33
+ END { if (!found && role != "") print role }
34
+ ' "$yaml" 2>/dev/null || echo ""
31
35
  fi
32
36
  }
33
37
 
@@ -309,8 +309,7 @@ export function createLaneMessageHandlers(deps) {
309
309
  throw err;
310
310
  }
311
311
  const text = readMessageText(requestedLaneId);
312
- await dispatchPrimaryLaneMessage(ctx, requestedLaneId, { ...opts, text });
313
- return;
312
+ return await dispatchPrimaryLaneMessage(ctx, requestedLaneId, { ...opts, text });
314
313
  }
315
314
  laneId = resolution.lane.lane_id;
316
315
  let text = readMessageText(laneId);
@@ -336,7 +335,7 @@ export function createLaneMessageHandlers(deps) {
336
335
  callerMatchesSessionSenior(ctx, sessionSeniorId)
337
336
  ? sessionSeniorId
338
337
  : undefined;
339
- await dispatchOutpostLaneCommand(ctx, lane, "message", {
338
+ return await dispatchOutpostLaneCommand(ctx, lane, "message", {
340
339
  ...opts,
341
340
  text,
342
341
  ...(supersededMessageCallerId === undefined ? {} : { supersededMessageCallerId }),
@@ -349,7 +348,6 @@ export function createLaneMessageHandlers(deps) {
349
348
  afterFallbackResume: () => deps.cancelFallbackQuestionsForLane(ctx, lane, "message", fallbackAt),
350
349
  }),
351
350
  });
352
- return;
353
351
  }
354
352
  assertLaneRunsHereForOperatorMutation(ctx, lane, "message");
355
353
  const projectId = opts.project?.trim() || lane.project_id;
@@ -179,8 +179,8 @@ export interface LaneMessageHandlerDeps {
179
179
  alreadyQueued?: boolean;
180
180
  }): Promise<AdmissionResult>;
181
181
  casUpdateLane(hqRoot: string, laneId: string, updater: (current: LaneRecord) => LaneRecord): LaneRecord;
182
- dispatchOutpostLaneCommand(ctx: Ctx, lane: LaneRecord, action: "message" | "resume", options: LaneMessageOptions | LaneResumeOptions, behavior?: OutpostLaneDispatchBehavior): Promise<void>;
183
- dispatchPrimaryLaneMessage(ctx: Ctx, laneId: string, options: LaneMessageOptions): Promise<void>;
182
+ dispatchOutpostLaneCommand(ctx: Ctx, lane: LaneRecord, action: "message" | "resume", options: LaneMessageOptions | LaneResumeOptions, behavior?: OutpostLaneDispatchBehavior): Promise<LaneMessageResponse | undefined>;
183
+ dispatchPrimaryLaneMessage(ctx: Ctx, laneId: string, options: LaneMessageOptions): Promise<LaneMessageResponse | undefined>;
184
184
  drainHookStatusFor(ctx: Ctx, lane: LaneRecord): {
185
185
  registered: boolean;
186
186
  kind: string;
@@ -4516,7 +4516,7 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options, behavior =
4516
4516
  const ownerCancellationFailures = Array.isArray(remote.question_cancellation_failures)
4517
4517
  ? remote.question_cancellation_failures
4518
4518
  : [];
4519
- printJson({
4519
+ const response = {
4520
4520
  ...remote,
4521
4521
  lane_id: ownerLane.lane_id,
4522
4522
  lane: ownerLane,
@@ -4534,8 +4534,10 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options, behavior =
4534
4534
  outpost_command_id: dispatched.commandId,
4535
4535
  outpost_transport: "outposts_exec",
4536
4536
  delivered_to: { host: outpostId, lane_id: ownerLane.lane_id, mechanism: "outposts_exec" },
4537
- });
4538
- return;
4537
+ };
4538
+ if (!("silent" in options) || !options.silent)
4539
+ printJson(response);
4540
+ return response;
4539
4541
  }
4540
4542
  if (action === "approve" || action === "reparent" || action === "resume") {
4541
4543
  const ownerLane = dispatchedOwnerLane(ctx, lane.lane_id, outpostId, remote.lane, behavior);
@@ -4578,7 +4580,7 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options, behavior =
4578
4580
  });
4579
4581
  return;
4580
4582
  }
4581
- printJson({
4583
+ const response = {
4582
4584
  ...remote,
4583
4585
  outpost_id: outpostId,
4584
4586
  outpost_command_id: dispatched.commandId,
@@ -4586,7 +4588,11 @@ async function dispatchOutpostLaneCommand(ctx, lane, action, options, behavior =
4586
4588
  ...(action === "message"
4587
4589
  ? { delivered_to: { host: outpostId, lane_id: lane.lane_id, mechanism: "outposts_exec" } }
4588
4590
  : {}),
4589
- });
4591
+ };
4592
+ const silentMessage = action === "message" && "silent" in options && options.silent === true;
4593
+ if (!silentMessage)
4594
+ printJson(response);
4595
+ return action === "message" ? response : undefined;
4590
4596
  }
4591
4597
  function dispatchedOwnerLane(ctx, laneId, outpostId, rawLane, behavior) {
4592
4598
  if (behavior.syncPrimary !== false) {
@@ -7426,15 +7432,16 @@ async function dispatchPrimaryLaneMessage(ctx, laneId, options) {
7426
7432
  remote.accepted !== true) {
7427
7433
  throw new LanesError("outpost_delivery_unconfirmed", `Primary completed exec without a confirmed message result for lane ${laneId}`, { lane_id: laneId, outpost_id: outpostId, command_id: confirmedCommandId });
7428
7434
  }
7429
- if (!options.silent) {
7430
- printJson({
7431
- ...remote,
7432
- outpost_id: outpostId,
7433
- outpost_command_id: confirmedCommandId,
7434
- outpost_transport: "outposts_exec",
7435
- delivered_to: { host: outpostId, lane_id: laneId, mechanism: "outposts_exec" },
7436
- });
7437
- }
7435
+ const response = {
7436
+ ...remote,
7437
+ outpost_id: outpostId,
7438
+ outpost_command_id: confirmedCommandId,
7439
+ outpost_transport: "outposts_exec",
7440
+ delivered_to: { host: outpostId, lane_id: laneId, mechanism: "outposts_exec" },
7441
+ };
7442
+ if (!options.silent)
7443
+ printJson(response);
7444
+ return response;
7438
7445
  }
7439
7446
  async function dispatchOutpostLaneStop(ctx, lane, reason, quiet = false) {
7440
7447
  if (lane.host.kind !== "outpost") {
@@ -8416,7 +8423,9 @@ export function registerLanesCommand(parent, deps = {}) {
8416
8423
  authorizeFailedResume,
8417
8424
  authorizeResumeProfileRepin,
8418
8425
  casUpdateLane,
8419
- dispatchOutpostLaneCommand,
8426
+ dispatchOutpostLaneCommand: async (commandCtx, lane, action, options, behavior) => {
8427
+ await dispatchOutpostLaneCommand(commandCtx, lane, action, options, behavior);
8428
+ },
8420
8429
  laneIsHostedHere,
8421
8430
  laneWithRecoveredProviderSession,
8422
8431
  mintMessageId,
@@ -33,7 +33,10 @@ export function renderIndexTarget(target, context, args = []) {
33
33
  }
34
34
  // The shell sorts and deduplicates the `wrote` paths before JSON output.
35
35
  const stdoutPaths = written.filter((file) => /^(workspace|companies|knowledge|workers|projects)/.test(file));
36
- (context.output ?? ((message) => process.stdout.write(message)))(`${JSON.stringify([...new Set(stdoutPaths)].sort(), null, 2)}\n`);
36
+ const json = JSON.stringify([...new Set(stdoutPaths)].sort(), null, 2);
37
+ // Windows jq emits CRLF when its JSON output is captured by the shell.
38
+ const lineEndings = process.platform === "win32" ? json.replace(/\n/g, "\r\n") : json;
39
+ (context.output ?? ((message) => process.stdout.write(message)))(`${lineEndings}\n`);
37
40
  context.log?.(errors ? `all-indexes: errors (${errors})` : "all-indexes: ok");
38
41
  return { written };
39
42
  }
@@ -1,5 +1,5 @@
1
1
  import * as fs from "fs";
2
- import { basename, countImmediate, date, exists, heading, immediateEntries, isHidden, log, mtime, sanitize, truncate, write } from "./shared.js";
2
+ import { basename, countImmediate, date, exists, heading, immediateEntries, isHidden, log, mtime, rel, sanitize, truncate, write } from "./shared.js";
3
3
  function directoryDescription(context, name) {
4
4
  const base = `workspace/social-drafts/${name}`;
5
5
  const files = countImmediate(context.root, base, (child, file) => !isHidden(child) && fs.statSync(file).isFile());
@@ -29,7 +29,7 @@ export function renderSocialDrafts(context) {
29
29
  const recent = ["x", "linkedin", "blog", "tiktok"].flatMap((channel) => immediateEntries(context.root, `${base}/${channel}`, "file").filter((file) => file.endsWith(".md"))).sort((a, b) => mtime(b) - mtime(a)).slice(0, 20);
30
30
  const lines = ["# Social Drafts", "", `> Auto-generated. Updated: ${date(context.now)}`, "", "## Recent Drafts", ""];
31
31
  for (const file of recent) {
32
- const relative = file.slice(`${context.root}/workspace/social-drafts/`.length);
32
+ const relative = rel(context.root, file).slice("workspace/social-drafts/".length);
33
33
  lines.push(`- \`${relative}\` - ${truncate(sanitize(heading(file) || basename(file).slice(0, -3)), 100)}`);
34
34
  }
35
35
  lines.push("", "## Directories", "", "| Name | Description |", "|------|-------------|");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.342.17",
3
+ "version": "5.342.18",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {