paqad-ai 1.76.1 → 1.76.2
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 +16 -0
- package/dist/cli/index.js +1 -1
- package/dist/index.js +3 -3
- package/package.json +1 -1
- package/runtime/AGENT-BOOTSTRAP.md +5 -2
- package/runtime/hooks/capability-gate.mjs +13 -5
- package/runtime/hooks/stage-marker-parse.mjs +7 -12
- package/runtime/scripts/verify-backstop.mjs +19 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# paqad-ai
|
|
2
2
|
|
|
3
|
+
## 1.76.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7ce4c34: fix: stop the `Stop says:` narration leak — silence Stop-hook `{systemMessage}` prose
|
|
8
|
+
|
|
9
|
+
Claude Code changed how it renders Stop-hook output: a Stop-hook `{systemMessage}` now renders on Desktop as literal `Stop says:` lines, inverting the premise the #368/#409 narration design was built on (that the channel was invisible, so the agent speaks the receipt and the hook echo is a silent backchannel). With the host inverted, paqad's three Stop-event emitters poured user-facing prose into that channel on every turn, across every onboarded repo and machine — duplicating the receipt the agent already speaks and leaking the model-only narration advisory into the developer's chat.
|
|
10
|
+
|
|
11
|
+
The Stop hooks no longer emit user-facing `{systemMessage}` prose:
|
|
12
|
+
|
|
13
|
+
- `runtime/scripts/verify-backstop.mjs` (`hook-completion`): writes nothing on a pass/inconclusive turn and only a model-only `{decision:'block'}` reason on a hard failure. Enforcement is unchanged — the block reason reaches the model (never rendered on either host) and the git/CI backstop still hard-fails with exit 2.
|
|
14
|
+
- `runtime/hooks/capability-gate.mjs` (`completion` seam): no longer echoes narration on the allow path; the `pre-mutation` (PreToolUse) seam is unchanged.
|
|
15
|
+
- `runtime/hooks/stage-marker-parse.mjs`: still records every parsed marker to the ledger; only the chat echo is removed.
|
|
16
|
+
|
|
17
|
+
The developer-facing channel is the agent's own final message (the #409 contract), which was always the intended primary channel. The narration contract docs and the verification module doc are corrected to state the new host behavior. Decision `D-01KZV9HFGDXZ03J0S6P9BTQ53Q` records the approach.
|
|
18
|
+
|
|
3
19
|
## 1.76.1
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/dist/cli/index.js
CHANGED
|
@@ -36251,7 +36251,7 @@ init_cancelled_error();
|
|
|
36251
36251
|
init_events();
|
|
36252
36252
|
|
|
36253
36253
|
// src/index.ts
|
|
36254
|
-
var VERSION = "1.76.
|
|
36254
|
+
var VERSION = "1.76.2";
|
|
36255
36255
|
|
|
36256
36256
|
// src/cli/commands/audit.ts
|
|
36257
36257
|
init_esm_shims();
|
package/dist/index.js
CHANGED
|
@@ -24632,7 +24632,7 @@ var memoizedReport;
|
|
|
24632
24632
|
function getEngineVersionReport() {
|
|
24633
24633
|
if (memoizedReport === void 0) {
|
|
24634
24634
|
memoizedReport = Object.freeze({
|
|
24635
|
-
engineVersion: normalizeEngineVersion("1.76.
|
|
24635
|
+
engineVersion: normalizeEngineVersion("1.76.2"),
|
|
24636
24636
|
minConsumerVersion: MIN_CONSUMER_VERSION,
|
|
24637
24637
|
deprecatedAsOf: DEPRECATED_AS_OF
|
|
24638
24638
|
});
|
|
@@ -46151,7 +46151,7 @@ function formatVerdictSummary(input2) {
|
|
|
46151
46151
|
|
|
46152
46152
|
// src/verification/repository/run-repository-verification.ts
|
|
46153
46153
|
function verifierVersion() {
|
|
46154
|
-
return true ? "1.76.
|
|
46154
|
+
return true ? "1.76.2" : "0.0.0-dev";
|
|
46155
46155
|
}
|
|
46156
46156
|
function backstopGates() {
|
|
46157
46157
|
return [
|
|
@@ -49085,7 +49085,7 @@ var WorkflowEngine = class {
|
|
|
49085
49085
|
};
|
|
49086
49086
|
|
|
49087
49087
|
// src/index.ts
|
|
49088
|
-
var VERSION = "1.76.
|
|
49088
|
+
var VERSION = "1.76.2";
|
|
49089
49089
|
function getFrameworkName() {
|
|
49090
49090
|
return "paqad-ai";
|
|
49091
49091
|
}
|
package/package.json
CHANGED
|
@@ -155,12 +155,15 @@ Emit the `start` marker as you begin the stage and the `end` marker as you finis
|
|
|
155
155
|
|
|
156
156
|
| Channel | Claude Code CLI | Claude Code Desktop |
|
|
157
157
|
| --- | --- | --- |
|
|
158
|
-
| Hook `{systemMessage}`
|
|
158
|
+
| Hook `{systemMessage}` — PreToolUse | rendered | **not rendered** — recorded as a hook attachment |
|
|
159
|
+
| Hook `{systemMessage}` — Stop | rendered | **rendered as literal `Stop says:` lines** |
|
|
159
160
|
| Hook `{decision:'block'}` `reason` | reaches the model only | reaches the model only |
|
|
160
161
|
| CLI verb stdout (`stage start`, `plan compile`) | inside the tool-result block | collapsed — invisible unless expanded |
|
|
161
162
|
| Your assistant text, final message of the turn | **rendered** | **rendered** |
|
|
162
163
|
|
|
163
|
-
|
|
164
|
+
A Stop-hook `{systemMessage}` used to be invisible on Desktop, so paqad kept a receipt echo there as belt-and-braces. Claude Code changed that: a Stop `{systemMessage}` now renders verbatim as `Stop says:` lines, which duplicated the receipt the agent already speaks and leaked model-only advisories into the chat. So paqad's Stop hooks no longer emit user-facing `{systemMessage}` prose at all — they write the ledger and, on a hard failure, ride the model-only `{decision:'block'}` `reason`. The developer-facing channel is your own final message, full stop.
|
|
165
|
+
|
|
166
|
+
**Per host — who speaks.** On **Claude Code** YOU speak. The stage hooks do fire on your edits and at turn end, and they do write the ledger — but they no longer narrate in chat: their `{systemMessage}` echo was removed once Claude Code began rendering a Stop `{systemMessage}` as `Stop says:` lines, because it duplicated the receipt you already speak and leaked model-only advisories to the developer. Before that it was the opposite failure — the echo was recorded and never shown on Desktop (issue #409: a full six-stage run emitted eleven stage lines and the developer saw none of them, while the evidence bundle was complete). Either way the lesson holds. Never treat a hook as having spoken for you. On **Codex** and **Gemini** the record hook is deliberately record-only — it writes the ledger at turn end but says nothing in chat — so there too YOU must narrate your own `▸ paqad` stage lines and speak the end-of-change verdict in prose. On **advisory hosts** (JetBrains "Claude Agent" / AI Assistant, Cursor, Windsurf, Copilot, Continue, Aider, Antigravity) **no native hook fires at all** — nothing blocks an edit, nothing writes the ledger for you, nothing speaks a verdict. Never rely on a hook-spoken line or a hook-written ledger row on an advisory host. Narrating alone is **not enough**: a narrated-but-unrecorded stage leaves the ledger empty, exactly the JetBrains Claude Agent gap (issue #389) — "framework followed" but "no evidence".
|
|
164
167
|
|
|
165
168
|
**Advisory-host stage protocol — run the CLI, do not just narrate.** On an advisory host, for any **feature-development** change you MUST populate the ledger yourself by running the host-independent CLI (plain `npx paqad-ai …` in the IDE's shell — no hook required), in this order, and narrate each `▸ paqad` stage line as you go:
|
|
166
169
|
|
|
@@ -130,12 +130,20 @@ export async function main(input, seam = SEAM) {
|
|
|
130
130
|
}
|
|
131
131
|
return 2;
|
|
132
132
|
}
|
|
133
|
-
// Allow path: surface narration + advisory
|
|
134
|
-
// user-message channel (`systemMessage`)
|
|
133
|
+
// Allow path: on the pre-mutation (PreToolUse) seam, surface narration + advisory
|
|
134
|
+
// findings through the host's user-message channel (`systemMessage`) — bare stdout is
|
|
135
135
|
// only visible in verbose mode, and narration is non-negotiable (issue #307).
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
136
|
+
//
|
|
137
|
+
// The completion (Stop) seam no longer emits here. Claude Code changed: a Stop-hook
|
|
138
|
+
// `{systemMessage}` now RENDERS on Desktop as literal "Stop says:" lines, and the agent
|
|
139
|
+
// already speaks its end-of-change narration in its final message (issue #409), so a
|
|
140
|
+
// Stop echo would duplicate that and leak into the developer's chat (the "Stop says:"
|
|
141
|
+
// narration leak). A PreToolUse `{systemMessage}` is still not rendered, so it stays.
|
|
142
|
+
if (seam !== 'completion') {
|
|
143
|
+
const visible = [result.narration, result.summary].filter(Boolean).join('\n');
|
|
144
|
+
if (visible) {
|
|
145
|
+
process.stdout.write(`${JSON.stringify({ systemMessage: visible })}\n`);
|
|
146
|
+
}
|
|
139
147
|
}
|
|
140
148
|
return 0;
|
|
141
149
|
} catch {
|
|
@@ -31,22 +31,17 @@ async function main(input) {
|
|
|
31
31
|
if (!transcriptText) return 0;
|
|
32
32
|
|
|
33
33
|
const distUrl = new URL('../../dist/stage-evidence/marker-parse.js', import.meta.url);
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
const { parseAndRecordMarkers } = await import(distUrl.href);
|
|
35
|
+
// Record every parsed marker to the ledger (issue #307 — the ledger write is
|
|
36
|
+
// non-negotiable). The chat echo that used to ride `{systemMessage}` is gone: this is a
|
|
37
|
+
// Stop hook, and Claude Code now RENDERS a Stop-hook `{systemMessage}` on Desktop as
|
|
38
|
+
// literal "Stop says:" lines, so echoing here duplicated the stage lines the agent
|
|
39
|
+
// already speaks itself (issue #409) and leaked into the developer's chat.
|
|
40
|
+
parseAndRecordMarkers({
|
|
40
41
|
projectRoot,
|
|
41
42
|
transcriptText,
|
|
42
43
|
sessionId: payload?.session_id ?? null,
|
|
43
44
|
});
|
|
44
|
-
// Narration and ledger are both non-negotiable (issue #307): every row this
|
|
45
|
-
// parse just minted is shown to the user via the host's user-message channel.
|
|
46
|
-
const narration = markerBatchNarration(recorded);
|
|
47
|
-
if (narration) {
|
|
48
|
-
process.stdout.write(`${JSON.stringify({ systemMessage: narration })}\n`);
|
|
49
|
-
}
|
|
50
45
|
return 0;
|
|
51
46
|
} catch {
|
|
52
47
|
/* v8 ignore next */
|
|
@@ -128,33 +128,34 @@ export async function runVerificationBackstop({
|
|
|
128
128
|
// hook (it is a PreToolUse mechanism), so the old `return 2` was both invisible AND
|
|
129
129
|
// a no-op. git/CI keep the exit-code-gated path below.
|
|
130
130
|
if (origin === 'hook-completion') {
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
//
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
? `${receipt}\n\n${verdict.narrationAdvisory}`
|
|
142
|
-
: receipt,
|
|
143
|
-
};
|
|
131
|
+
// The Stop hook no longer emits a `{systemMessage}`. Claude Code changed: a
|
|
132
|
+
// Stop-hook `{systemMessage}` now RENDERS on Desktop as literal "Stop says:" lines,
|
|
133
|
+
// inverting the #368/#409 premise that this channel was invisible. Routing the
|
|
134
|
+
// receipt through it duplicated the narration the agent already speaks (the #409
|
|
135
|
+
// contract) and leaked the model-only narration advisory into the developer's chat
|
|
136
|
+
// (the "Stop says:" narration leak). So the developer-facing channel is the agent's
|
|
137
|
+
// own final message; enforcement rides the `{decision:'block'}` reason below, which
|
|
138
|
+
// is NOT rendered on either host (it reaches the model only), plus the git/CI
|
|
139
|
+
// backstop.
|
|
140
|
+
const payload = {};
|
|
144
141
|
// Give the gate real teeth on a HARD failure (a gate reported `fail`, e.g. a
|
|
145
142
|
// mandatory stage missing or a red checks report): tell the model to keep working
|
|
146
143
|
// and resolve it before the turn ends. An Inconclusive verdict (no failing gate —
|
|
147
|
-
// only unproven signals)
|
|
148
|
-
//
|
|
149
|
-
//
|
|
150
|
-
//
|
|
144
|
+
// only unproven signals) never blocks: "do not over-trust", not "you must fix". The
|
|
145
|
+
// loop guard (`loopActive`, from Claude's `stop_hook_active`) means the gate already
|
|
146
|
+
// bit once this turn, so a second block would loop — step aside and let the session
|
|
147
|
+
// end (git/CI remains the hard gate). The narration advisory (issue #409) still rides
|
|
148
|
+
// the model-only reason when a block is already firing; on a clean turn there is no
|
|
149
|
+
// model-facing decision to convey, so the hook stays silent.
|
|
151
150
|
if (verdictHasHardFailure(verdict) && !loopActive) {
|
|
152
151
|
payload.decision = 'block';
|
|
153
152
|
payload.reason = verdict.narrationAdvisory
|
|
154
153
|
? `${blockReason(verdict)}\n\n${verdict.narrationAdvisory}`
|
|
155
154
|
: blockReason(verdict);
|
|
156
155
|
}
|
|
157
|
-
|
|
156
|
+
if (payload.decision) {
|
|
157
|
+
out.write(`${JSON.stringify(payload)}\n`);
|
|
158
|
+
}
|
|
158
159
|
return 0;
|
|
159
160
|
}
|
|
160
161
|
|