@kenkaiiii/ggcoder 5.70.0 → 5.72.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 (187) 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 +70 -0
  55. package/assets/motion/skills/before-after/SKILL.md +57 -0
  56. package/assets/motion/skills/brand-kit/SKILL.md +3 -3
  57. package/assets/motion/skills/dev-tool-video/SKILL.md +61 -0
  58. package/assets/motion/skills/launch-video/SKILL.md +66 -0
  59. package/assets/motion/skills/match-reference/SKILL.md +62 -0
  60. package/assets/motion/skills/motion/SKILL.md +148 -98
  61. package/assets/motion/skills/source-ingest/SKILL.md +17 -6
  62. package/assets/motion/skills/website-video/SKILL.md +76 -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 +48 -33
  104. package/dist/app-sidecar.js.map +1 -1
  105. package/dist/cli/thinking-arg.d.ts +6 -0
  106. package/dist/cli/thinking-arg.js +13 -0
  107. package/dist/cli/thinking-arg.js.map +1 -0
  108. package/dist/cli.d.ts +1 -2
  109. package/dist/cli.js +1 -14
  110. package/dist/cli.js.map +1 -1
  111. package/dist/core/agent-session.d.ts +25 -71
  112. package/dist/core/agent-session.js +79 -427
  113. package/dist/core/agent-session.js.map +1 -1
  114. package/dist/core/codex-request-shape.d.ts +12 -0
  115. package/dist/core/codex-request-shape.js +31 -0
  116. package/dist/core/codex-request-shape.js.map +1 -0
  117. package/dist/core/mcp/content.js +6 -2
  118. package/dist/core/mcp/content.js.map +1 -1
  119. package/dist/core/session-history.d.ts +12 -0
  120. package/dist/core/session-history.js +27 -0
  121. package/dist/core/session-history.js.map +1 -1
  122. package/dist/core/settings-manager.d.ts +10 -1
  123. package/dist/core/settings-manager.js +12 -5
  124. package/dist/core/settings-manager.js.map +1 -1
  125. package/dist/core/skills.js +3 -1
  126. package/dist/core/skills.js.map +1 -1
  127. package/dist/core/verification-gate.d.ts +8 -100
  128. package/dist/core/verification-gate.js +26 -260
  129. package/dist/core/verification-gate.js.map +1 -1
  130. package/dist/motion-agent/motion-agent.d.ts +6 -2
  131. package/dist/motion-agent/motion-agent.js +5 -7
  132. package/dist/motion-agent/motion-agent.js.map +1 -1
  133. package/dist/motion-agent/motion-prompt.d.ts +1 -1
  134. package/dist/motion-agent/motion-prompt.js +16 -20
  135. package/dist/motion-agent/motion-prompt.js.map +1 -1
  136. package/dist/motion-agent/motion-review.d.ts +5 -1
  137. package/dist/motion-agent/motion-review.js +8 -3
  138. package/dist/motion-agent/motion-review.js.map +1 -1
  139. package/dist/motion-agent/motion-studio-context.js +1 -1
  140. package/dist/motion-agent/motion-studio-context.js.map +1 -1
  141. package/dist/system-prompt.js +4 -1
  142. package/dist/system-prompt.js.map +1 -1
  143. package/dist/tools/bash-read-evidence.d.ts +10 -0
  144. package/dist/tools/bash-read-evidence.js +133 -0
  145. package/dist/tools/bash-read-evidence.js.map +1 -0
  146. package/dist/tools/edit.js +12 -4
  147. package/dist/tools/edit.js.map +1 -1
  148. package/dist/tools/index.d.ts +7 -1
  149. package/dist/tools/index.js +5 -0
  150. package/dist/tools/index.js.map +1 -1
  151. package/dist/tools/prompt-hints.js +4 -1
  152. package/dist/tools/prompt-hints.js.map +1 -1
  153. package/dist/tools/read-tracker.d.ts +5 -0
  154. package/dist/tools/read-tracker.js +19 -9
  155. package/dist/tools/read-tracker.js.map +1 -1
  156. package/dist/tools/skill.js +5 -0
  157. package/dist/tools/skill.js.map +1 -1
  158. package/dist/tools/subagent.d.ts +6 -0
  159. package/dist/tools/subagent.js +13 -2
  160. package/dist/tools/subagent.js.map +1 -1
  161. package/dist/tools/tool-tiers.d.ts +6 -0
  162. package/dist/tools/tool-tiers.js +7 -1
  163. package/dist/tools/tool-tiers.js.map +1 -1
  164. package/dist/ui/App.d.ts +0 -7
  165. package/dist/ui/App.js +6 -79
  166. package/dist/ui/App.js.map +1 -1
  167. package/dist/ui/hooks/useAgentLoop.d.ts +0 -7
  168. package/dist/ui/hooks/useAgentLoop.js +1 -119
  169. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  170. package/dist/ui/render.d.ts +0 -4
  171. package/dist/ui/render.js +0 -2
  172. package/dist/ui/render.js.map +1 -1
  173. package/dist/utils/image.d.ts +14 -0
  174. package/dist/utils/image.js +16 -0
  175. package/dist/utils/image.js.map +1 -1
  176. package/package.json +4 -4
  177. package/assets/motion/references/motion-language.md +0 -128
  178. package/assets/motion/skills/video-qa/SKILL.md +0 -89
  179. package/dist/core/ideal-review-subagent.d.ts +0 -56
  180. package/dist/core/ideal-review-subagent.js +0 -112
  181. package/dist/core/ideal-review-subagent.js.map +0 -1
  182. package/dist/core/ideal-review.d.ts +0 -82
  183. package/dist/core/ideal-review.js +0 -242
  184. package/dist/core/ideal-review.js.map +0 -1
  185. package/dist/motion-agent/motion-check-tool.d.ts +0 -42
  186. package/dist/motion-agent/motion-check-tool.js +0 -564
  187. package/dist/motion-agent/motion-check-tool.js.map +0 -1
@@ -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";
@@ -62,6 +62,7 @@ import { getGitHubOpenCounts, getGitHubRepoSlug } from "./utils/github.js";
62
62
  import { startGitHubCIPoll } from "./utils/github-ci.js";
63
63
  import { extractPlanSteps } from "./utils/plan-steps.js";
64
64
  import { getNextThinkingLevel, getSupportedThinkingLevels, isThinkingLevelSupported, } from "./core/thinking-level.js";
65
+ import { parseThinkingLevel } from "./cli/thinking-arg.js";
65
66
  import { PROMPT_COMMANDS } from "./core/prompt-commands.js";
66
67
  import { loadCustomCommands } from "./core/custom-commands.js";
67
68
  import { discoverProjects } from "./core/project-discovery.js";
@@ -72,7 +73,8 @@ import { installTerminationHandlers } from "./core/shutdown.js";
72
73
  import { KeepAwake } from "./core/keep-awake.js";
73
74
  import { RADIO_STATIONS, getCurrentStation, getRadioVolume, playRadio, setRadioVolume, stopRadio, } from "./core/radio.js";
74
75
  import { enrichProcessPath } from "./core/shell-path.js";
75
- import { downscaleForPreview, shrinkToFit, validateVisionImage } from "./utils/image.js";
76
+ import { downscaleForPreview, IMAGE_MEDIA_TYPES, shrinkToFit, validateVisionImage, } from "./utils/image.js";
77
+ import { readFileBounded } from "./tools/operations.js";
76
78
  import { startServeMode } from "./modes/serve-mode.js";
77
79
  import { installSteroids, probeSteroids } from "./core/steroids.js";
78
80
  import { loadTelegramConfig, saveTelegramConfig, verifyBotToken } from "./core/telegram-config.js";
@@ -491,6 +493,7 @@ async function runJsonModeIfRequested() {
491
493
  tools: { type: "string" },
492
494
  "mcp-servers": { type: "string" },
493
495
  "prompt-cache-key": { type: "string" },
496
+ thinking: { type: "string" },
494
497
  },
495
498
  allowPositionals: true,
496
499
  strict: true,
@@ -527,6 +530,7 @@ async function runJsonModeIfRequested() {
527
530
  allowedTools,
528
531
  allowedMcpServers,
529
532
  promptCacheKey: values["prompt-cache-key"],
533
+ thinkingLevel: parseThinkingLevel(values.thinking),
530
534
  }).catch(async (err) => {
531
535
  process.stderr.write((err instanceof Error ? err.message : String(err)) + "\n");
532
536
  process.exit(1);
@@ -1993,7 +1997,7 @@ async function createSession(deps, opts) {
1993
1997
  session.eventBus.on("hook", (d) => broadcast("hook", d));
1994
1998
  session.eventBus.on("diagnostics", (d) => broadcast("diagnostics", d));
1995
1999
  // 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
2000
+ // text back while armed, so an injected follow-up supersedes a draft that was never
1997
2001
  // painted instead of deleting one the user already started reading.
1998
2002
  session.eventBus.on("hook_armed", (d) => broadcast("hook_armed", d));
1999
2003
  session.eventBus.on("subagent_state", (d) => broadcast("subagent_state", d));
@@ -2065,10 +2069,8 @@ async function createSession(deps, opts) {
2065
2069
  // Autopilot (auto-review) toggle for THIS window's project. Loaded from
2066
2070
  // gg-app.json on boot; flipped via POST /autopilot. When on, POST /prompt runs
2067
2071
  // 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.
2072
+ // and drives the review→prompt→review loop.
2070
2073
  let autopilot = mode === "code" && (await loadAutopilot(cwd));
2071
- session.setIdealReviewSuppressed(autopilot);
2072
2074
  // True while an autopilot review is in flight (used to defer kenAuto model
2073
2075
  // switches, like kenRunning does for chat Ken, and to drive the spinner).
2074
2076
  let autopilotReviewing = false;
@@ -2274,9 +2276,6 @@ async function createSession(deps, opts) {
2274
2276
  // (often >5 min) regardless of the user's global speedProfile pick.
2275
2277
  forceLongCacheRetention: true,
2276
2278
  });
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
2279
  await ken.initialize();
2281
2280
  // Keep review text/tools silent; report usage only for whole-task accounting.
2282
2281
  ken.eventBus.on("turn_end", (d) => {
@@ -2541,7 +2540,6 @@ async function createSession(deps, opts) {
2541
2540
  const generation = runLifecycle.begin(abortOwnedWork).generation;
2542
2541
  pendingCancelDrain = null;
2543
2542
  autopilotActive = true;
2544
- session.setIdealReviewSuppressed(true);
2545
2543
  // Generation captured by the last plan review; acceptPlan re-checks it so
2546
2544
  // a user Accept/Reject landing mid-review always wins.
2547
2545
  let planGenAtReview = -1;
@@ -2659,7 +2657,6 @@ async function createSession(deps, opts) {
2659
2657
  }
2660
2658
  finally {
2661
2659
  autopilotActive = false;
2662
- session.setIdealReviewSuppressed(autopilot);
2663
2660
  finishOwnedGeneration(generation, true, session.getVerificationProblem() ? "unverified" : "completed");
2664
2661
  queueMicrotask(() => void runStrandedQueue());
2665
2662
  }
@@ -3294,7 +3291,16 @@ async function createSession(deps, opts) {
3294
3291
  // Pre-index tool results by toolCallId so we can pair tool calls with
3295
3292
  // their results (for sub-agent status + image extraction).
3296
3293
  const toolResultMap = new Map();
3294
+ // Tool name per call, so restore only trusts generate_image's own text
3295
+ // when it reads extra images from disk (an MCP server could fake it).
3296
+ const toolNameById = new Map();
3297
3297
  for (const msg of messages) {
3298
+ if (msg.role === "assistant" && typeof msg.content !== "string") {
3299
+ for (const c of msg.content) {
3300
+ if (c.type === "tool_call")
3301
+ toolNameById.set(c.id, c.name);
3302
+ }
3303
+ }
3298
3304
  if (msg.role !== "tool")
3299
3305
  continue;
3300
3306
  for (const tr of msg.content) {
@@ -3454,31 +3460,43 @@ async function createSession(deps, opts) {
3454
3460
  const imageBlocks = tr.content.filter((c) => c.type === "image");
3455
3461
  if (imageBlocks.length === 0)
3456
3462
  continue;
3457
- // Extract the path from the text block (e.g. "Generated image → /path").
3463
+ // Extract the path from the text block so the restored image
3464
+ // stays clickable (read / screenshot / generate_image formats).
3458
3465
  const textBlock = tr.content.find((c) => c.type === "text" && "text" in c && typeof c.text === "string");
3459
3466
  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.
3467
+ const imgPaths = extractToolImagePaths(textContent);
3468
+ // Downscale each image for the webview preview. Paths pair with
3469
+ // image blocks in order (a tool saves one file per image).
3463
3470
  const toolImages = [];
3471
+ let blockIndex = 0;
3464
3472
  for (const block of imageBlocks) {
3465
3473
  if (block.type !== "image")
3466
3474
  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
- }
3475
+ const imgPath = imgPaths[blockIndex++];
3476
+ const previewBuf = await downscaleForPreview(Buffer.from(block.data, "base64"));
3477
+ toolImages.push({
3478
+ src: `data:${block.mediaType};base64,${previewBuf.toString("base64")}`,
3479
+ path: imgPath,
3480
+ });
3481
+ }
3482
+ // generate_image persists only its first image's pixels; the
3483
+ // rest exist only on disk, so preview them from their files.
3484
+ // Skip silently if a file was moved or deleted since.
3485
+ const extraPaths = toolNameById.get(tr.toolCallId) === "generate_image"
3486
+ ? imgPaths.slice(blockIndex)
3487
+ : [];
3488
+ for (const extraPath of extraPaths) {
3489
+ const mediaType = IMAGE_MEDIA_TYPES[path.extname(extraPath).toLowerCase()];
3490
+ if (!mediaType)
3491
+ continue;
3492
+ const raw = await readFileBounded(extraPath).catch(() => null);
3493
+ if (!raw)
3494
+ continue;
3495
+ const previewBuf = await downscaleForPreview(raw);
3496
+ toolImages.push({
3497
+ src: `data:${mediaType};base64,${previewBuf.toString("base64")}`,
3498
+ path: extraPath,
3499
+ });
3482
3500
  }
3483
3501
  if (toolImages.length > 0) {
3484
3502
  history.push({
@@ -3909,9 +3927,6 @@ async function createSession(deps, opts) {
3909
3927
  return;
3910
3928
  }
3911
3929
  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
3930
  await saveAutopilot(cwd, enabled);
3916
3931
  log("INFO", "app-sidecar", "autopilot toggled", { enabled: String(enabled) });
3917
3932
  broadcast("autopilot", { autopilot: enabled });