@indigoai-us/hq-cli 5.99.3 → 5.100.0
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,19 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [5.100.0] — 2026-08-13
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `hq core checkpoint` now ends every non-dry-run checkpoint — real writes and
|
|
10
|
+
`--idle` alike — with a REMINDER line telling the calling agent that the
|
|
11
|
+
checkpoint is invisible bookkeeping, not the user-facing reply, and that any
|
|
12
|
+
substance not yet reported to the user must be delivered before the turn ends
|
|
13
|
+
(#374). The reminder is emitted even when sibling startup fails, and the
|
|
14
|
+
bundled Stop-gate prompt was reworded to prescribe the same reply-first
|
|
15
|
+
ordering. Machine-parsed outputs (`--dry-run` JSON, `--gate-probe`) are
|
|
16
|
+
unchanged.
|
|
17
|
+
|
|
5
18
|
## [5.99.3] — 2026-08-13
|
|
6
19
|
|
|
7
20
|
### Fixed
|
|
@@ -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 — no
|
|
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")"
|
|
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
|
|
@@ -9,6 +9,19 @@
|
|
|
9
9
|
import { Command } from "commander";
|
|
10
10
|
type Backend = "claude" | "codex" | "grok" | "none";
|
|
11
11
|
type SpawnableBackend = Exclude<Backend, "none">;
|
|
12
|
+
/**
|
|
13
|
+
* Printed after every non-dry-run checkpoint, real or --idle. Agents were
|
|
14
|
+
* treating the checkpoint call as the end of the turn, leaving their actual
|
|
15
|
+
* findings only in the checkpoint payload — which the user never sees. This
|
|
16
|
+
* line rides the command output (the one channel guaranteed to reach the
|
|
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
|
|
21
|
+
* `checkpoint-is-bookkeeping-not-user-communication` and
|
|
22
|
+
* `checkpoint-is-not-the-user-report`.
|
|
23
|
+
*/
|
|
24
|
+
export declare const CHECKPOINT_REPLY_REMINDER: string;
|
|
12
25
|
/**
|
|
13
26
|
* Kept in TypeScript rather than in a bundled asset: it is an instruction to
|
|
14
27
|
* a locally-installed agent, not a scaffold script that should be packaged.
|
|
@@ -40,6 +40,23 @@ const SIBLING_LOCK_TTL_MS = 60 * 60 * 1000;
|
|
|
40
40
|
const MAX_PENDING_PAYLOADS = 50;
|
|
41
41
|
class CheckpointUsageError extends Error {
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Printed after every non-dry-run checkpoint, real or --idle. Agents were
|
|
45
|
+
* treating the checkpoint call as the end of the turn, leaving their actual
|
|
46
|
+
* findings only in the checkpoint payload — which the user never sees. This
|
|
47
|
+
* line rides the command output (the one channel guaranteed to reach the
|
|
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
|
|
52
|
+
* `checkpoint-is-bookkeeping-not-user-communication` and
|
|
53
|
+
* `checkpoint-is-not-the-user-report`.
|
|
54
|
+
*/
|
|
55
|
+
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.";
|
|
43
60
|
function printResult(line) {
|
|
44
61
|
process.stdout.write(`${line}\n`);
|
|
45
62
|
}
|
|
@@ -801,6 +818,9 @@ function runCheckpoint(options, command, group) {
|
|
|
801
818
|
}
|
|
802
819
|
writeStamps(liveRoot, resolveSessionId(options, command, readPayload(options.payload)));
|
|
803
820
|
printResult("checkpoint: idle (nothing to record)");
|
|
821
|
+
// An idle turn persisted nothing, but a read-only turn can still have
|
|
822
|
+
// produced substantive findings the user has not been told about.
|
|
823
|
+
printResult(CHECKPOINT_REPLY_REMINDER);
|
|
804
824
|
return;
|
|
805
825
|
}
|
|
806
826
|
const payload = readPayload(options.payload);
|
|
@@ -860,13 +880,22 @@ function runCheckpoint(options, command, group) {
|
|
|
860
880
|
fs.writeFileSync(threadPath, `${JSON.stringify(thread, null, 2)}\n`);
|
|
861
881
|
writeStamps(liveRoot, input.sessionId);
|
|
862
882
|
printResult(`checkpoint: ${relativeThreadPath}`);
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
883
|
+
// finally: the thread is already written at this point, so the agent must
|
|
884
|
+
// get the reminder even when sibling startup throws (e.g. an explicitly
|
|
885
|
+
// requested backend that is not installed).
|
|
886
|
+
try {
|
|
887
|
+
if (options.agent !== false) {
|
|
888
|
+
if (backend === "none") {
|
|
889
|
+
printResult("checkpoint: sibling disabled (backend none)");
|
|
890
|
+
}
|
|
891
|
+
else {
|
|
892
|
+
startSibling(liveRoot, input, threadPath, backend);
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
finally {
|
|
897
|
+
printResult(CHECKPOINT_REPLY_REMINDER);
|
|
868
898
|
}
|
|
869
|
-
startSibling(liveRoot, input, threadPath, backend);
|
|
870
899
|
}
|
|
871
900
|
function reportUsage(error) {
|
|
872
901
|
printError("Usage: hq core checkpoint --summary <text> [options]");
|