@indigoai-us/hq-cli 5.103.5 → 5.103.7

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,17 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [5.103.7] — 2026-08-19
6
+
7
+ ### Fixed
8
+
9
+ - The checkpoint stop-gate and `hq core checkpoint` REMINDER now order the turn
10
+ checkpoint-first / user-reply-last. App-runtime Claude Code hosts collapse
11
+ assistant text that precedes a tool call, so the old "reply first, checkpoint
12
+ as final action" contract silently hid the substantive reply from the user.
13
+
14
+ ## [5.103.6] — 2026-08-19
15
+
5
16
  ## [5.103.5] — 2026-08-19
6
17
 
7
18
  ## [5.103.4] — 2026-08-19
@@ -120,7 +120,7 @@ set -uo pipefail
120
120
  *) [ -d "$gate_root/companies/$bound_co" ] && gate_bound=1 ;;
121
121
  esac
122
122
  if [ "$gate_bound" = 0 ]; then
123
- company_reason="$(printf 'This session has not declared its scope, and a scope is required before the turn can end. Decide where this work belongs, then bind the session as the FINAL action of the turn and end the turn immediately after:\n\n bash %s/core/scripts/hq-session.sh --session-id %s set company_slug <company-slug>\n\nUse a real tenant slug from companies/manifest.yaml — the company this session is actually working in, never an invented one. If this session does no company-scoped work, bind it to the reserved personal scope instead:\n\n bash %s/core/scripts/hq-session.sh --session-id %s set company_slug personal\n\nAn operator can also disable this requirement for the run by exporting HQ_CHECKPOINT_GATE=0.' "$gate_root" "$gate_session_id" "$gate_root" "$gate_session_id")"
123
+ company_reason="$(printf 'This session has not declared its scope, and a scope is required before the turn can end. Decide where this work belongs, then bind the session and finish the turn with your user-facing reply as the final text after the command output:\n\n bash %s/core/scripts/hq-session.sh --session-id %s set company_slug <company-slug>\n\nUse a real tenant slug from companies/manifest.yaml — the company this session is actually working in, never an invented one. If this session does no company-scoped work, bind it to the reserved personal scope instead:\n\n bash %s/core/scripts/hq-session.sh --session-id %s set company_slug personal\n\nAn operator can also disable this requirement for the run by exporting HQ_CHECKPOINT_GATE=0.' "$gate_root" "$gate_session_id" "$gate_root" "$gate_session_id")"
124
124
  printf '{"decision":"block","reason":%s}\n' "$(printf '%s' "$company_reason" | hq_json_encode)"
125
125
  exit 0
126
126
  fi
@@ -327,7 +327,7 @@ set -uo pipefail
327
327
 
328
328
  # Built with printf rather than concatenation so the session id can appear in
329
329
  # both commands without re-splitting the message into fragments.
330
- reason="$(printf 'This turn changed something, so it needs an end-of-turn checkpoint. Two different audiences are involved — do not conflate them:\n\n1. THE USER reads your normal chat reply. If you owe them anything — a result, a link, an answer, a status — say it in the reply as usual. The checkpoint is invisible to them and is NOT a message to them; running it does not count as having replied.\n2. THE SIBLING (a background maintenance agent) reads the checkpoint payload. It never sees your chat reply, so anything it needs must go into the flags.\n\nSo: finish whatever you owe the user in the reply first, then run the checkpoint as the FINAL action of the turn and end the turn immediately after it. The checkpoint output ends with a REMINDER restating this contract: if it catches you having skipped the user-facing reply, deliver that overdue reply nothing else and then end the turn; otherwise add no commentary after the command.\n\n hq core checkpoint --session-id %s --trigger stop-gate --summary "<what changed, in one line>" [--file <path>] [--decision "<choice and why>"] [--learning "<reusable rule>"] [--next "<outstanding step>"]\n\nOnly --summary is required, and the repeatable flags are what the sibling uses to enrich the record, distil policies and update the indexes — a bare summary gives it almost nothing to work with. Write them as machine record, not prose for the user, and pass each one that genuinely applies:\n --file every path you created or modified this turn\n --decision a choice you made that a reader would otherwise have to reverse-engineer\n --learning a rule that changes how someone acts next time, not a restatement of what just happened\n --next work that is genuinely still outstanding\nOmit a flag rather than padding it: an empty or invented learning is worse than none.\n\nIf this turn only read or inspected things and changed no state, the correct call instead is:\n\n hq core checkpoint --session-id %s --idle' "$session_id" "$session_id")"
330
+ reason="$(printf 'This turn changed something, so it needs an end-of-turn checkpoint. Two different audiences are involved — do not conflate them:\n\n1. THE USER reads your normal chat reply. If you owe them anything — a result, a link, an answer, a status — say it in the reply as usual. The checkpoint is invisible to them and is NOT a message to them; running it does not count as having replied.\n2. THE SIBLING (a background maintenance agent) reads the checkpoint payload. It never sees your chat reply, so anything it needs must go into the flags.\n\nORDER (this app folds any text that precedes a tool call into a collapsed sub-message only text AFTER the last tool call renders in full): run the checkpoint FIRST, then deliver your COMPLETE user-facing reply as the final text of the turn. Every link, URL, instruction, command, and decision the user needs MUST appear in that final post-checkpoint message, restated in full even if you already wrote it earlier in the turn earlier text is collapsed and the user will not see it.\n\n hq core checkpoint --session-id %s --trigger stop-gate --summary "<what changed, in one line>" [--file <path>] [--decision "<choice and why>"] [--learning "<reusable rule>"] [--next "<outstanding step>"]\n\nOnly --summary is required, and the repeatable flags are what the sibling uses to enrich the record, distil policies and update the indexes — a bare summary gives it almost nothing to work with. Write them as machine record, not prose for the user, and pass each one that genuinely applies:\n --file every path you created or modified this turn\n --decision a choice you made that a reader would otherwise have to reverse-engineer\n --learning a rule that changes how someone acts next time, not a restatement of what just happened\n --next work that is genuinely still outstanding\nOmit a flag rather than padding it: an empty or invented learning is worse than none.\n\nIf this turn only read or inspected things and changed no state, the correct call instead is:\n\n hq core checkpoint --session-id %s --idle' "$session_id" "$session_id")"
331
331
 
332
332
  # Codex surfaces a blocked Stop reason as a synthetic user prompt. Preserve
333
333
  # the actionable instruction out-of-band, then use the stable marker covered
@@ -190,7 +190,11 @@ export function registerApiKeysCommand(program) {
190
190
  const deployCapabilities = capabilities.filter((cap) => cap === "deploy:write" || cap === "deploy:read");
191
191
  const expiresAt = parseExpires(opts.expires);
192
192
  const token = await requireCognitoForApiKeys("api-keys create");
193
- const companyUid = await getCompanyUid(token, apiKeys.opts().company);
193
+ // The company selector the caller typed (a slug, e.g. `indigo`, unless
194
+ // they passed a raw uid). Kept so the metadata can lead with the slug
195
+ // instead of only the resolved uid.
196
+ const companyRef = apiKeys.opts().company;
197
+ const companyUid = await getCompanyUid(token, companyRef);
194
198
  const res = await vaultApiFetch({
195
199
  token,
196
200
  path: "/v1/api-keys",
@@ -224,7 +228,12 @@ export function registerApiKeysCommand(program) {
224
228
  console.log(chalk.bold("Metadata"));
225
229
  console.log(` Key ID: ${data.apiKey.keyId}`);
226
230
  console.log(` Name: ${data.apiKey.name}`);
227
- console.log(` Company: ${data.apiKey.companyUid}`);
231
+ // Lead with the slug the caller typed (uid in parens, since the key is
232
+ // uid-bound); fall back to the bare uid when they passed a uid or relied
233
+ // on a single active membership.
234
+ console.log(` Company: ${companyRef && companyRef !== data.apiKey.companyUid
235
+ ? `${companyRef} (${data.apiKey.companyUid})`
236
+ : data.apiKey.companyUid}`);
228
237
  console.log(` Permission: ${data.apiKey.scope.permission}`);
229
238
  console.log(` Capabilities: ${formatCapabilities(data.apiKey.scope.capabilities ?? capabilities)}`);
230
239
  console.log(` Prefixes: ${formatPrefixes(data.apiKey.scope.allowedPrefixes)}`);
@@ -15,9 +15,10 @@ type SpawnableBackend = Exclude<Backend, "none">;
15
15
  * findings only in the checkpoint payload — which the user never sees. This
16
16
  * line rides the command output (the one channel guaranteed to reach the
17
17
  * calling agent) to force the user-facing reply. Deliberately conditional so
18
- * it composes with the Stop-gate prompt's "reply first, checkpoint last, then
19
- * end the turn" ordering: an agent that already replied is told to end the
20
- * turn, not to add commentary. Mirrors the hq-core policies
18
+ * it composes with the Stop-gate prompt's "checkpoint first, reply last"
19
+ * ordering: some hosts (the desktop app runtime) do not reliably display
20
+ * assistant text that precedes a tool call, so the reply must come after
21
+ * the checkpoint output as the final text of the turn. Mirrors the hq-core policies
21
22
  * `checkpoint-is-bookkeeping-not-user-communication` and
22
23
  * `checkpoint-is-not-the-user-report`.
23
24
  */
@@ -46,17 +46,19 @@ class CheckpointUsageError extends Error {
46
46
  * findings only in the checkpoint payload — which the user never sees. This
47
47
  * line rides the command output (the one channel guaranteed to reach the
48
48
  * calling agent) to force the user-facing reply. Deliberately conditional so
49
- * it composes with the Stop-gate prompt's "reply first, checkpoint last, then
50
- * end the turn" ordering: an agent that already replied is told to end the
51
- * turn, not to add commentary. Mirrors the hq-core policies
49
+ * it composes with the Stop-gate prompt's "checkpoint first, reply last"
50
+ * ordering: some hosts (the desktop app runtime) do not reliably display
51
+ * assistant text that precedes a tool call, so the reply must come after
52
+ * the checkpoint output as the final text of the turn. Mirrors the hq-core policies
52
53
  * `checkpoint-is-bookkeeping-not-user-communication` and
53
54
  * `checkpoint-is-not-the-user-report`.
54
55
  */
55
56
  export const CHECKPOINT_REPLY_REMINDER = "checkpoint: REMINDER — this checkpoint is invisible bookkeeping; the user never sees it " +
56
- "and it does NOT count as your reply. If your reply to the user already contains " +
57
- "everything of substance from this turn, end the turn now. If anything — results, " +
58
- "findings, decisions, state changes, anything awaiting their input — exists only in this " +
59
- "checkpoint or your head, deliver it to the user in plain language before ending the turn.";
57
+ "and it does NOT count as your reply. Now write your user-facing reply as the FINAL text " +
58
+ "of the turn — everything of substance from this turn (results, findings, decisions, " +
59
+ "state changes, anything awaiting their input)even if you already wrote it earlier: " +
60
+ "assistant text that precedes a tool call is not reliably shown to the user on all " +
61
+ "hosts. Then end the turn.";
60
62
  function printResult(line) {
61
63
  process.stdout.write(`${line}\n`);
62
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@indigoai-us/hq-cli",
3
- "version": "5.103.5",
3
+ "version": "5.103.7",
4
4
  "description": "HQ by Indigo management CLI — modules and cloud sync",
5
5
  "main": "dist/index.js",
6
6
  "bin": {