@kenkaiiii/ggcoder 5.70.0 → 5.71.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.
Files changed (172) hide show
  1. package/assets/motion/bin/contact-sheet.mjs +9 -3
  2. package/assets/motion/bin/cues.mjs +337 -0
  3. package/assets/motion/bin/library.mjs +53 -10
  4. package/assets/motion/bin/motion-blur.mjs +943 -0
  5. package/assets/motion/bin/motion-check.mjs +354 -3
  6. package/assets/motion/bin/music-fit.mjs +436 -0
  7. package/assets/motion/bin/pdf-extract.mjs +22 -10
  8. package/assets/motion/bin/reference-study.mjs +346 -0
  9. package/assets/motion/bin/score-synth.mjs +1052 -93
  10. package/assets/motion/library/README.md +50 -14
  11. package/assets/motion/library/kit/moves.js +1981 -0
  12. package/assets/motion/library/library.json +232 -0
  13. package/assets/motion/library/pieces/camera-rig/meta.json +13 -0
  14. package/assets/motion/library/pieces/camera-rig/piece.html +153 -0
  15. package/assets/motion/library/pieces/camera-rig/preview.jpg +0 -0
  16. package/assets/motion/library/pieces/chain-knock/meta.json +13 -0
  17. package/assets/motion/library/pieces/chain-knock/piece.html +195 -0
  18. package/assets/motion/library/pieces/chain-knock/preview.jpg +0 -0
  19. package/assets/motion/library/pieces/gather-to-logo/meta.json +13 -0
  20. package/assets/motion/library/pieces/gather-to-logo/piece.html +159 -0
  21. package/assets/motion/library/pieces/gather-to-logo/preview.jpg +0 -0
  22. package/assets/motion/library/pieces/morph-carry/meta.json +13 -0
  23. package/assets/motion/library/pieces/morph-carry/piece.html +173 -0
  24. package/assets/motion/library/pieces/morph-carry/preview.jpg +0 -0
  25. package/assets/motion/library/pieces/one-shape-journey/meta.json +13 -0
  26. package/assets/motion/library/pieces/one-shape-journey/piece.html +195 -0
  27. package/assets/motion/library/pieces/one-shape-journey/preview.jpg +0 -0
  28. package/assets/motion/library/pieces/open-from-subject/meta.json +13 -0
  29. package/assets/motion/library/pieces/open-from-subject/piece.html +168 -0
  30. package/assets/motion/library/pieces/open-from-subject/preview.jpg +0 -0
  31. package/assets/motion/library/pieces/request-to-result/meta.json +13 -0
  32. package/assets/motion/library/pieces/request-to-result/piece.html +212 -0
  33. package/assets/motion/library/pieces/request-to-result/preview.jpg +0 -0
  34. package/assets/motion/library/pieces/scale-dive/meta.json +13 -0
  35. package/assets/motion/library/pieces/scale-dive/piece.html +321 -0
  36. package/assets/motion/library/pieces/scale-dive/preview.jpg +0 -0
  37. package/assets/motion/library/pieces/screen-replica-steps/meta.json +13 -0
  38. package/assets/motion/library/pieces/screen-replica-steps/piece.html +366 -0
  39. package/assets/motion/library/pieces/screen-replica-steps/preview.jpg +0 -0
  40. package/assets/motion/library/pieces/zoom-into-card/meta.json +13 -0
  41. package/assets/motion/library/pieces/zoom-into-card/piece.html +179 -0
  42. package/assets/motion/library/pieces/zoom-into-card/preview.jpg +0 -0
  43. package/assets/motion/library/sheets/diagram.jpg +0 -0
  44. package/assets/motion/library/sheets/frame.jpg +0 -0
  45. package/assets/motion/library/sheets/transition.jpg +0 -0
  46. package/assets/motion/library/sheets/ui.jpg +0 -0
  47. package/assets/motion/references/build-sheet.md +206 -0
  48. package/assets/motion/references/runtime/determinism-rules.md +1 -1
  49. package/assets/motion/references/runtime/gsap-easing-and-stagger.md +29 -29
  50. package/assets/motion/references/runtime/inputs-and-assets.md +7 -12
  51. package/assets/motion/references/runtime/lint-validate-inspect.md +3 -3
  52. package/assets/motion/references/runtime/minimal-composition.md +1 -1
  53. package/assets/motion/references/runtime/preview-render.md +3 -3
  54. package/assets/motion/skills/app-walkthrough/SKILL.md +66 -0
  55. package/assets/motion/skills/before-after/SKILL.md +53 -0
  56. package/assets/motion/skills/brand-kit/SKILL.md +3 -3
  57. package/assets/motion/skills/dev-tool-video/SKILL.md +57 -0
  58. package/assets/motion/skills/launch-video/SKILL.md +62 -0
  59. package/assets/motion/skills/match-reference/SKILL.md +58 -0
  60. package/assets/motion/skills/motion/SKILL.md +78 -85
  61. package/assets/motion/skills/source-ingest/SKILL.md +17 -6
  62. package/assets/motion/skills/website-video/SKILL.md +59 -0
  63. package/assets/skills/bulletproof/SKILL.md +36 -11
  64. package/assets/skills/bulletproof/references/agent-surface.md +19 -9
  65. package/assets/skills/bulletproof/references/audit-protocol.md +20 -5
  66. package/assets/skills/bulletproof/references/platform-playbooks.md +5 -4
  67. package/assets/skills/bulletproof/references/provenance.md +26 -1
  68. package/assets/skills/bulletproof/references/secure-defaults.md +6 -5
  69. package/assets/skills/bulletproof/references/supply-chain.md +21 -17
  70. package/assets/skills/bulletproof/references/threat-landscape.md +28 -26
  71. package/assets/skills/bulletproof/references/verification.md +2 -0
  72. package/assets/skills/clarify/SKILL.md +25 -16
  73. package/assets/skills/code-review/SKILL.md +71 -13
  74. package/assets/skills/code-review/references/agent-diffs.md +27 -0
  75. package/assets/skills/code-review/references/tests.md +19 -0
  76. package/assets/skills/compliance-guard/SKILL.md +20 -5
  77. package/assets/skills/compliance-guard/references/artifacts.md +1 -1
  78. package/assets/skills/compliance-guard/references/eu-uk.md +16 -16
  79. package/assets/skills/compliance-guard/references/lawsuit-vectors.md +5 -5
  80. package/assets/skills/compliance-guard/references/provenance.md +41 -2
  81. package/assets/skills/compliance-guard/references/sector-gates.md +3 -3
  82. package/assets/skills/compliance-guard/references/security-baseline.md +2 -2
  83. package/assets/skills/compliance-guard/references/trigger-map.md +5 -5
  84. package/assets/skills/compliance-guard/references/us.md +27 -21
  85. package/assets/skills/durable/SKILL.md +87 -79
  86. package/assets/skills/durable/references/agent-db-safety.md +69 -0
  87. package/assets/skills/durable/references/backups-and-runtime.md +19 -12
  88. package/assets/skills/durable/references/migrations-and-schema.md +13 -6
  89. package/assets/skills/evidence-led-ui/SKILL.md +69 -127
  90. package/assets/skills/evidence-led-ui/references/anti-defaults.md +107 -208
  91. package/assets/skills/evidence-led-ui/references/direction.md +124 -0
  92. package/assets/skills/evidence-led-ui/references/production-contract.md +8 -0
  93. package/assets/skills/evidence-led-ui/references/provenance.md +24 -1
  94. package/assets/skills/lean/SKILL.md +90 -71
  95. package/assets/skills/lean/references/memory-and-processes.md +3 -2
  96. package/assets/skills/lean/references/playbooks.md +37 -12
  97. package/assets/skills/refactoring/SKILL.md +24 -3
  98. package/assets/skills/refactoring/references/agent-pitfalls.md +4 -1
  99. package/assets/skills/refactoring/references/legacy.md +21 -0
  100. package/assets/skills/root-cause/SKILL.md +20 -10
  101. package/assets/skills/shared-language/SKILL.md +16 -14
  102. package/assets/skills/tdd/SKILL.md +27 -15
  103. package/dist/app-sidecar.js +45 -33
  104. package/dist/app-sidecar.js.map +1 -1
  105. package/dist/cli.js +0 -6
  106. package/dist/cli.js.map +1 -1
  107. package/dist/core/agent-session.d.ts +24 -71
  108. package/dist/core/agent-session.js +67 -427
  109. package/dist/core/agent-session.js.map +1 -1
  110. package/dist/core/mcp/content.js +6 -2
  111. package/dist/core/mcp/content.js.map +1 -1
  112. package/dist/core/session-history.d.ts +12 -0
  113. package/dist/core/session-history.js +27 -0
  114. package/dist/core/session-history.js.map +1 -1
  115. package/dist/core/settings-manager.d.ts +0 -1
  116. package/dist/core/settings-manager.js +2 -5
  117. package/dist/core/settings-manager.js.map +1 -1
  118. package/dist/core/skills.js +3 -1
  119. package/dist/core/skills.js.map +1 -1
  120. package/dist/core/verification-gate.d.ts +8 -100
  121. package/dist/core/verification-gate.js +26 -260
  122. package/dist/core/verification-gate.js.map +1 -1
  123. package/dist/motion-agent/motion-agent.d.ts +6 -2
  124. package/dist/motion-agent/motion-agent.js +5 -7
  125. package/dist/motion-agent/motion-agent.js.map +1 -1
  126. package/dist/motion-agent/motion-prompt.d.ts +1 -1
  127. package/dist/motion-agent/motion-prompt.js +14 -19
  128. package/dist/motion-agent/motion-prompt.js.map +1 -1
  129. package/dist/motion-agent/motion-review.d.ts +5 -1
  130. package/dist/motion-agent/motion-review.js +8 -3
  131. package/dist/motion-agent/motion-review.js.map +1 -1
  132. package/dist/motion-agent/motion-studio-context.js +1 -1
  133. package/dist/motion-agent/motion-studio-context.js.map +1 -1
  134. package/dist/system-prompt.js +3 -1
  135. package/dist/system-prompt.js.map +1 -1
  136. package/dist/tools/bash-read-evidence.d.ts +10 -0
  137. package/dist/tools/bash-read-evidence.js +133 -0
  138. package/dist/tools/bash-read-evidence.js.map +1 -0
  139. package/dist/tools/edit.js +12 -4
  140. package/dist/tools/edit.js.map +1 -1
  141. package/dist/tools/index.d.ts +7 -1
  142. package/dist/tools/index.js +5 -0
  143. package/dist/tools/index.js.map +1 -1
  144. package/dist/tools/read-tracker.d.ts +5 -0
  145. package/dist/tools/read-tracker.js +19 -9
  146. package/dist/tools/read-tracker.js.map +1 -1
  147. package/dist/tools/skill.js +5 -0
  148. package/dist/tools/skill.js.map +1 -1
  149. package/dist/ui/App.d.ts +0 -7
  150. package/dist/ui/App.js +6 -79
  151. package/dist/ui/App.js.map +1 -1
  152. package/dist/ui/hooks/useAgentLoop.d.ts +0 -7
  153. package/dist/ui/hooks/useAgentLoop.js +1 -119
  154. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  155. package/dist/ui/render.d.ts +0 -4
  156. package/dist/ui/render.js +0 -2
  157. package/dist/ui/render.js.map +1 -1
  158. package/dist/utils/image.d.ts +14 -0
  159. package/dist/utils/image.js +16 -0
  160. package/dist/utils/image.js.map +1 -1
  161. package/package.json +4 -4
  162. package/assets/motion/references/motion-language.md +0 -128
  163. package/assets/motion/skills/video-qa/SKILL.md +0 -89
  164. package/dist/core/ideal-review-subagent.d.ts +0 -56
  165. package/dist/core/ideal-review-subagent.js +0 -112
  166. package/dist/core/ideal-review-subagent.js.map +0 -1
  167. package/dist/core/ideal-review.d.ts +0 -82
  168. package/dist/core/ideal-review.js +0 -242
  169. package/dist/core/ideal-review.js.map +0 -1
  170. package/dist/motion-agent/motion-check-tool.d.ts +0 -42
  171. package/dist/motion-agent/motion-check-tool.js +0 -564
  172. package/dist/motion-agent/motion-check-tool.js.map +0 -1
@@ -1,30 +1,32 @@
1
1
  ---
2
2
  name: shared-language
3
- description: Use when a project's domain vocabulary is fuzzy or drifting, naming decisions keep recurring, or a hard-to-reverse architectural decision needs recording so it is not re-litigated or re-suggested later. Do NOT use for throwaway scripts or projects too small to have recurring vocabulary.
3
+ description: Use when a project's domain vocabulary is fuzzy or drifting (two names for one thing, one name for two), naming decisions keep recurring, or a hard-to-reverse architectural decision needs recording so it is not re-litigated or re-suggested — including mid-build when a term settles or a change contradicts an ADR. Do NOT use for throwaway scripts, projects too small to have recurring vocabulary, interviewing for requirements (clarify), or renames with no vocabulary decision (refactoring).
4
4
  ---
5
5
 
6
6
  # Shared Language
7
7
 
8
- A repo's terms are its compression. When you and the user mean the same thing by "reservation", every prompt, name, and doc gets shorter and sharper — and the agent stops spending thinking tokens re-deriving what a single word encodes. This skill builds and maintains that vocabulary.
8
+ Two artifacts: the glossary (`CONTEXT.md`) and decision records (`docs/adr/`). On entry, read both if they exist, then act on the trigger: term settled → glossary; hard call made → offer ADR; change contradicts an ADR → surface it.
9
9
 
10
10
  ## The glossary — CONTEXT.md
11
11
 
12
- At the repo root. **A glossary and nothing else**: term — a one-to-three-line definition, no implementation details, no history. If a definition names a file path, it has become documentation; move that out.
12
+ At the repo root. **A glossary and nothing else**: `term — 1–3 line definition`, plus `Avoid: <synonyms>` where drift exists. No file paths, implementation, or history.
13
13
 
14
- - Challenge fuzzy terms against it: "the glossary defines *cancellation* as pre-charge; this change reads as post-charge — which is meant?"
15
- - Stress-test a new term with an invented edge case before recording it ("is a no-show a cancellation?").
16
- - Update **inline, the moment a term settles** — never batch glossary edits for "later"; later never comes.
17
- - Name files, functions, variables, and tests with glossary terms verbatim. When code and glossary disagree, one of them is wrong — find out which.
18
- - Create the file lazily on the first settled term, never as an empty template.
19
- - On first creation, add one line to the repo's instruction file (AGENTS.md, or CLAUDE.md if that is what the repo uses): `Read CONTEXT.md before naming anything.` CONTEXT.md is not auto-loaded — the pointer is what makes the glossary ambient in every session.
14
+ - Challenge fuzzy usage against it: "glossary says *cancellation* is pre-charge; this reads post-charge — which?"
15
+ - Test a candidate term with an invented edge case before recording it ("is a no-show a cancellation?").
16
+ - Update the moment a term settles; create the file lazily on the first settled term, never as an empty template.
17
+ - Code, tests, and UI use glossary terms verbatim. Code and glossary disagree → one is wrong; ask which.
18
+ - On creation, add to the repo's instruction file (AGENTS.md, or CLAUDE.md if that is what it uses): `Read CONTEXT.md before naming anything.` CONTEXT.md is not auto-loaded — that pointer is what makes it count in later sessions.
20
19
 
21
20
  ## Decision records — docs/adr/
22
21
 
23
- An ADR earns its file only when a decision is **hard to reverse**, **surprising without context**, and **a real tradeoff** — all three. One file per decision: title, 1–3 sentences of context, the decision, the main rejected alternative and why. Numbered; immutable once accepted — supersede, never edit.
22
+ Only when a decision is **hard to reverse**, **surprising without context**, and **a real tradeoff** — all three. Offer it; don't write unasked.
24
23
 
25
- Read the ADRs before proposing a change that contradicts one: honor it, or surface the conflict to the user. Never silently relitigate a recorded decision, and never re-suggest a rejected alternative without new facts.
24
+ - Follow the repo's existing ADR format. None? Use the MADR 4 minimal shape: `NNNN-title-with-dashes.md` with Context and Problem Statement, Considered Options, Decision Outcome (chosen option + why), Consequences; `status: accepted` in front matter.
25
+ - Immutable once accepted — supersede, never edit: new ADR notes `Supersedes NNNN`; the old one's status becomes `superseded by NNNN` (the only allowed change).
26
+ - Before proposing a change that contradicts an ADR: honour it or raise the conflict. Never re-suggest a rejected option without new facts.
26
27
 
27
- ## Integration
28
+ ## Scaling: one agent or several
28
29
 
29
- - During a clarify session: settled terms go to the glossary; qualifying hard calls get an ADR offer.
30
- - Before naming anything: read the glossary if it exists.
30
+ Main thread only. On a large repo, one `owl` may inventory competing terms across packages (occurrences with file:line); the main thread decides and edits.
31
+
32
+ Sources (accessed 3 October 2026): MADR 4.0.0, latest release (2024-09-17) — https://adr.github.io/madr/; ubiquitous language — https://martinfowler.com/bliki/UbiquitousLanguage.html
@@ -1,30 +1,42 @@
1
1
  ---
2
2
  name: tdd
3
- description: Use when the user asks for test-driven development, red-green-refactor, or "write the test first", or wants a feature built test-first. Do NOT use when tests are a verification step after the build, the project has no suite and the user has not asked for one, or the change is throwaway probe code.
3
+ description: Use when the user asks for test-driven development, red-green-refactor, "write the test first", or wants a feature or bug fix built test-first — including mid-build when they ask to switch to test-first. Do NOT use when tests are a verification step after the build, the project has no suite and the user has not asked for one, the change is throwaway probe code, or the goal is restructuring without behaviour change (refactoring) or finding an unknown cause (root-cause).
4
4
  ---
5
5
 
6
6
  # TDD
7
7
 
8
- Red → green, one slice at a time. This skill is the reference that makes the loop produce tests worth keeping — most of it applies on every cycle, so consult it before and during the loop, not after.
8
+ Red → green, one vertical slice at a time. Before the first test: agree seams (below). Then loop.
9
9
 
10
10
  ## Seams — agree before writing
11
11
 
12
- A **seam** is the public boundary where behavior is observable: an exported function, an HTTP route, a CLI invocation. Tests live at seams; they never reach into internals.
13
-
14
- Before the first test, write down the seams under test and confirm them with the user — which boundaries get tests and which stay untested is a decision, and settling it up front is what keeps effort on critical paths instead of every edge case. No test at an unagreed seam.
12
+ A **seam** is a public boundary where behaviour is observable: exported function, HTTP route, CLI invocation. Tests live at seams, never in internals. List the seams under test and confirm them with the user (one `ask_user` call, recommended set marked). No test at an unagreed seam.
15
13
 
16
14
  ## The loop
17
15
 
18
- 1. **Red.** One failing test at an agreed seam, for the next smallest real behavior. Run it; watch it fail for the right reason.
19
- 2. **Green.** The least code that passes — nothing speculative. Run it.
20
- 3. **Repeat.** The next test responds to what the last cycle taught. Work in vertical slices, never layers: writing all tests then all implementation verifies *imagined* behavior and locks in structure before understanding.
21
- 4. **Refactor outside the loop.** Cleanup happens at a checkpoint after a green cycle or in a review pass — not interleaved guesswork inside red-green.
16
+ 1. **Red.** One failing test at an agreed seam for the next smallest real behaviour. Run it; confirm it fails for the right reason (assertion, not import/syntax error).
17
+ 2. **Green.** Least code that passes. Run the test and the touched suite.
18
+ 3. **Repeat.** The next test follows from what the last cycle taught. Never write all tests first, then all code.
19
+ 4. **Refactor** only on green, as a separate step; rerun tests after.
20
+
21
+ ## Test integrity (agent guard)
22
+
23
+ - **Tests are frozen during green.** Never edit, delete, skip, loosen, or `.only` a test to make it pass. If a test is wrong, stop, say why, and get agreement before changing it.
24
+ - Never special-case test inputs in production code (hard-coded returns for the test's literal).
25
+ - Before claiming done, `git diff` the test files; explain any change made during a green step.
26
+
27
+ ## Test quality
28
+
29
+ - **Expected values from an outside source of truth** — a known literal, worked example, or the spec. Never recompute the expected value the way the code does.
30
+ - **Behaviour, not structure.** A test that breaks under a behaviour-preserving refactor is coupled to internals; rewrite it at the seam.
31
+ - **Mock only external boundaries** (network, clock, filesystem), and only when slow or stateful.
32
+ - **Name like a spec**: "user can check out with an empty cart".
33
+ - **Property tests for rules over many inputs** (parsers, round-trips, invariants) when the project already has a property library (fast-check, Hypothesis, proptest); otherwise a table of examples.
34
+ - **Optional strength check:** if a mutation tool is already installed (Stryker, mutmut, cargo-mutants), run it on the changed module; surviving mutants point to missing assertions. Do not install one unasked. Manual alternative: break one line of the new code, confirm a test goes red, revert.
35
+
36
+ Never claim a cycle green that you did not run.
22
37
 
23
- ## Test quality rules
38
+ ## Scaling: one agent or several
24
39
 
25
- - **Expected values from an outside source of truth** — a known literal, a worked example, the spec. Never recompute the expected value the same way the code does; that test can only agree with itself and can never catch the bug.
26
- - **Behavior, not structure.** Assert on what the interface does. A test that breaks under a refactor with unchanged behavior is coupled to implementation — rewrite it at the seam, never patch it with mocks of internals.
27
- - **Real paths over mocks.** Exercise real code; mock only external boundaries (network, clock, filesystem) and only when they are slow or stateful.
28
- - **Named like a spec.** "user can check out with an empty cart" — the name alone states the capability.
40
+ Main thread only — the loop is sequential by design. Never parallelise red/green steps or let a child edit tests.
29
41
 
30
- The loop inherits the verification gate: never claim a cycle green that you did not run.
42
+ Sources (accessed 3 October 2026): https://code.claude.com/docs/en/best-practices (failing test before the fix); https://stryker-mutator.io/docs/ (killed vs surviving mutants); https://hypothesis.readthedocs.io/
@@ -37,7 +37,7 @@ import { isWorkflowCommandText, countAssistantMessages, shouldStartAutopilotCycl
37
37
  import { driveAutopilotCycle, frameAutopilotInjection } from "./core/autopilot-cycle.js";
38
38
  import { describeRunVerification, describeTurnVerification } from "./core/run-status.js";
39
39
  import { validateKenModelPref, effectiveKenModel } from "./core/ken-model.js";
40
- import { normalizeAutopilotMarkersForHistory, normalizeAppMarkersForHistory, normalizeKenTurnsForHistory, getHistoryMessageVisibility, replayMessagesInOrder, restoreUserRow, restoreAssistantTexts, resolveRestoredCommand, autopilotMarkerCopySeed, } from "./core/session-history.js";
40
+ import { normalizeAutopilotMarkersForHistory, normalizeAppMarkersForHistory, normalizeKenTurnsForHistory, getHistoryMessageVisibility, replayMessagesInOrder, restoreUserRow, restoreAssistantTexts, resolveRestoredCommand, autopilotMarkerCopySeed, extractToolImagePaths, } from "./core/session-history.js";
41
41
  import { sessionToMarkdown, defaultExportFilename, } from "./core/session-export.js";
42
42
  import { AuthStorage } from "./core/auth-storage.js";
43
43
  import { advancesPhase, explainPullFailure, isGgufShard, isValidHfRepoId, parseOllamaPullLine, pickGgufQuant, SHARDED_MESSAGE, toHfSearchRow, } from "./hf-pull.js";
@@ -72,7 +72,8 @@ import { installTerminationHandlers } from "./core/shutdown.js";
72
72
  import { KeepAwake } from "./core/keep-awake.js";
73
73
  import { RADIO_STATIONS, getCurrentStation, getRadioVolume, playRadio, setRadioVolume, stopRadio, } from "./core/radio.js";
74
74
  import { enrichProcessPath } from "./core/shell-path.js";
75
- import { downscaleForPreview, shrinkToFit, validateVisionImage } from "./utils/image.js";
75
+ import { downscaleForPreview, IMAGE_MEDIA_TYPES, shrinkToFit, validateVisionImage, } from "./utils/image.js";
76
+ import { readFileBounded } from "./tools/operations.js";
76
77
  import { startServeMode } from "./modes/serve-mode.js";
77
78
  import { installSteroids, probeSteroids } from "./core/steroids.js";
78
79
  import { loadTelegramConfig, saveTelegramConfig, verifyBotToken } from "./core/telegram-config.js";
@@ -1993,7 +1994,7 @@ async function createSession(deps, opts) {
1993
1994
  session.eventBus.on("hook", (d) => broadcast("hook", d));
1994
1995
  session.eventBus.on("diagnostics", (d) => broadcast("diagnostics", d));
1995
1996
  // Fires BEFORE the candidate final answer streams. The webview holds assistant
1996
- // text back while armed, so an Ideal review supersedes a draft that was never
1997
+ // text back while armed, so an injected follow-up supersedes a draft that was never
1997
1998
  // painted instead of deleting one the user already started reading.
1998
1999
  session.eventBus.on("hook_armed", (d) => broadcast("hook_armed", d));
1999
2000
  session.eventBus.on("subagent_state", (d) => broadcast("subagent_state", d));
@@ -2065,10 +2066,8 @@ async function createSession(deps, opts) {
2065
2066
  // Autopilot (auto-review) toggle for THIS window's project. Loaded from
2066
2067
  // gg-app.json on boot; flipped via POST /autopilot. When on, POST /prompt runs
2067
2068
  // runAutopilotCycle after the user's turn settles — Ken auto-reviews the work
2068
- // and drives the review→prompt→review loop. Ken is the sole verification
2069
- // owner in this mode, so suppress the build session's redundant Ideal hook.
2069
+ // and drives the review→prompt→review loop.
2070
2070
  let autopilot = mode === "code" && (await loadAutopilot(cwd));
2071
- session.setIdealReviewSuppressed(autopilot);
2072
2071
  // True while an autopilot review is in flight (used to defer kenAuto model
2073
2072
  // switches, like kenRunning does for chat Ken, and to drive the spinner).
2074
2073
  let autopilotReviewing = false;
@@ -2274,9 +2273,6 @@ async function createSession(deps, opts) {
2274
2273
  // (often >5 min) regardless of the user's global speedProfile pick.
2275
2274
  forceLongCacheRetention: true,
2276
2275
  });
2277
- // Ken is already the independent autopilot reviewer; recursively running
2278
- // his own Ideal self-review adds latency and can corrupt the verdict shape.
2279
- ken.setIdealReviewSuppressed(true);
2280
2276
  await ken.initialize();
2281
2277
  // Keep review text/tools silent; report usage only for whole-task accounting.
2282
2278
  ken.eventBus.on("turn_end", (d) => {
@@ -2541,7 +2537,6 @@ async function createSession(deps, opts) {
2541
2537
  const generation = runLifecycle.begin(abortOwnedWork).generation;
2542
2538
  pendingCancelDrain = null;
2543
2539
  autopilotActive = true;
2544
- session.setIdealReviewSuppressed(true);
2545
2540
  // Generation captured by the last plan review; acceptPlan re-checks it so
2546
2541
  // a user Accept/Reject landing mid-review always wins.
2547
2542
  let planGenAtReview = -1;
@@ -2659,7 +2654,6 @@ async function createSession(deps, opts) {
2659
2654
  }
2660
2655
  finally {
2661
2656
  autopilotActive = false;
2662
- session.setIdealReviewSuppressed(autopilot);
2663
2657
  finishOwnedGeneration(generation, true, session.getVerificationProblem() ? "unverified" : "completed");
2664
2658
  queueMicrotask(() => void runStrandedQueue());
2665
2659
  }
@@ -3294,7 +3288,16 @@ async function createSession(deps, opts) {
3294
3288
  // Pre-index tool results by toolCallId so we can pair tool calls with
3295
3289
  // their results (for sub-agent status + image extraction).
3296
3290
  const toolResultMap = new Map();
3291
+ // Tool name per call, so restore only trusts generate_image's own text
3292
+ // when it reads extra images from disk (an MCP server could fake it).
3293
+ const toolNameById = new Map();
3297
3294
  for (const msg of messages) {
3295
+ if (msg.role === "assistant" && typeof msg.content !== "string") {
3296
+ for (const c of msg.content) {
3297
+ if (c.type === "tool_call")
3298
+ toolNameById.set(c.id, c.name);
3299
+ }
3300
+ }
3298
3301
  if (msg.role !== "tool")
3299
3302
  continue;
3300
3303
  for (const tr of msg.content) {
@@ -3454,31 +3457,43 @@ async function createSession(deps, opts) {
3454
3457
  const imageBlocks = tr.content.filter((c) => c.type === "image");
3455
3458
  if (imageBlocks.length === 0)
3456
3459
  continue;
3457
- // Extract the path from the text block (e.g. "Generated image → /path").
3460
+ // Extract the path from the text block so the restored image
3461
+ // stays clickable (read / screenshot / generate_image formats).
3458
3462
  const textBlock = tr.content.find((c) => c.type === "text" && "text" in c && typeof c.text === "string");
3459
3463
  const textContent = textBlock && textBlock.type === "text" ? textBlock.text : "";
3460
- const pathMatch = textContent.match(/→\s*(\S+)/);
3461
- const imgPath = pathMatch?.[1];
3462
- // Downscale each image for the webview preview.
3464
+ const imgPaths = extractToolImagePaths(textContent);
3465
+ // Downscale each image for the webview preview. Paths pair with
3466
+ // image blocks in order (a tool saves one file per image).
3463
3467
  const toolImages = [];
3468
+ let blockIndex = 0;
3464
3469
  for (const block of imageBlocks) {
3465
3470
  if (block.type !== "image")
3466
3471
  continue;
3467
- try {
3468
- const rawBuf = Buffer.from(block.data, "base64");
3469
- const previewBuf = await downscaleForPreview(rawBuf);
3470
- toolImages.push({
3471
- src: `data:${block.mediaType};base64,${previewBuf.toString("base64")}`,
3472
- path: imgPath,
3473
- });
3474
- }
3475
- catch {
3476
- // Downscale failed — use the raw data.
3477
- toolImages.push({
3478
- src: `data:${block.mediaType};base64,${block.data}`,
3479
- path: imgPath,
3480
- });
3481
- }
3472
+ const imgPath = imgPaths[blockIndex++];
3473
+ const previewBuf = await downscaleForPreview(Buffer.from(block.data, "base64"));
3474
+ toolImages.push({
3475
+ src: `data:${block.mediaType};base64,${previewBuf.toString("base64")}`,
3476
+ path: imgPath,
3477
+ });
3478
+ }
3479
+ // generate_image persists only its first image's pixels; the
3480
+ // rest exist only on disk, so preview them from their files.
3481
+ // Skip silently if a file was moved or deleted since.
3482
+ const extraPaths = toolNameById.get(tr.toolCallId) === "generate_image"
3483
+ ? imgPaths.slice(blockIndex)
3484
+ : [];
3485
+ for (const extraPath of extraPaths) {
3486
+ const mediaType = IMAGE_MEDIA_TYPES[path.extname(extraPath).toLowerCase()];
3487
+ if (!mediaType)
3488
+ continue;
3489
+ const raw = await readFileBounded(extraPath).catch(() => null);
3490
+ if (!raw)
3491
+ continue;
3492
+ const previewBuf = await downscaleForPreview(raw);
3493
+ toolImages.push({
3494
+ src: `data:${mediaType};base64,${previewBuf.toString("base64")}`,
3495
+ path: extraPath,
3496
+ });
3482
3497
  }
3483
3498
  if (toolImages.length > 0) {
3484
3499
  history.push({
@@ -3909,9 +3924,6 @@ async function createSession(deps, opts) {
3909
3924
  return;
3910
3925
  }
3911
3926
  autopilot = enabled;
3912
- // A toggle-off during an active cycle takes effect after Ken finishes;
3913
- // until then, injected build runs must not re-enable Ideal self-review.
3914
- session.setIdealReviewSuppressed(enabled || autopilotActive);
3915
3927
  await saveAutopilot(cwd, enabled);
3916
3928
  log("INFO", "app-sidecar", "autopilot toggled", { enabled: String(enabled) });
3917
3929
  broadcast("autopilot", { autopilot: enabled });