@kenkaiiii/ggcoder 5.15.1 → 5.17.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 (232) hide show
  1. package/assets/end-notification.mp3 +0 -0
  2. package/assets/skills/evidence-led-ui/LICENSES.md +68 -0
  3. package/assets/skills/evidence-led-ui/SKILL.md +139 -0
  4. package/{LICENSE → assets/skills/evidence-led-ui/corpus/awesome-design-md/LICENSE} +1 -1
  5. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/airbnb/DESIGN.md +545 -0
  6. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/airtable/DESIGN.md +554 -0
  7. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/apple/DESIGN.md +562 -0
  8. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/binance/DESIGN.md +634 -0
  9. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/bmw/DESIGN.md +544 -0
  10. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/bmw-m/DESIGN.md +503 -0
  11. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/bugatti/DESIGN.md +454 -0
  12. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/cal/DESIGN.md +542 -0
  13. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/claude/DESIGN.md +589 -0
  14. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/clay/DESIGN.md +541 -0
  15. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/clickhouse/DESIGN.md +544 -0
  16. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/cohere/DESIGN.md +451 -0
  17. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/coinbase/DESIGN.md +570 -0
  18. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/composio/DESIGN.md +506 -0
  19. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/cursor/DESIGN.md +537 -0
  20. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/dell-1996/DESIGN.md +632 -0
  21. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/elevenlabs/DESIGN.md +504 -0
  22. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/expo/DESIGN.md +526 -0
  23. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/ferrari/DESIGN.md +531 -0
  24. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/figma/DESIGN.md +578 -0
  25. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/framer/DESIGN.md +544 -0
  26. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/hashicorp/DESIGN.md +575 -0
  27. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/hp/DESIGN.md +670 -0
  28. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/ibm/DESIGN.md +550 -0
  29. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/intercom/DESIGN.md +546 -0
  30. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/kraken/DESIGN.md +125 -0
  31. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/lamborghini/DESIGN.md +288 -0
  32. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/linear.app/DESIGN.md +548 -0
  33. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/lovable/DESIGN.md +298 -0
  34. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mastercard/DESIGN.md +365 -0
  35. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/meta/DESIGN.md +683 -0
  36. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/minimax/DESIGN.md +746 -0
  37. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mintlify/DESIGN.md +852 -0
  38. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/miro/DESIGN.md +825 -0
  39. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mistral.ai/DESIGN.md +773 -0
  40. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mongodb/DESIGN.md +767 -0
  41. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/nike/DESIGN.md +575 -0
  42. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/nintendo-2001/DESIGN.md +649 -0
  43. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/notion/DESIGN.md +821 -0
  44. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/nvidia/DESIGN.md +640 -0
  45. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/ollama/DESIGN.md +539 -0
  46. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/opencode.ai/DESIGN.md +521 -0
  47. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/pinterest/DESIGN.md +597 -0
  48. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/playstation/DESIGN.md +661 -0
  49. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/posthog/DESIGN.md +690 -0
  50. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/raycast/DESIGN.md +669 -0
  51. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/renault/DESIGN.md +589 -0
  52. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/replicate/DESIGN.md +616 -0
  53. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/resend/DESIGN.md +585 -0
  54. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/revolut/DESIGN.md +636 -0
  55. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/runwayml/DESIGN.md +244 -0
  56. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/sanity/DESIGN.md +357 -0
  57. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/sentry/DESIGN.md +551 -0
  58. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/shopify/DESIGN.md +516 -0
  59. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/slack/DESIGN.md +482 -0
  60. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/spacex/DESIGN.md +363 -0
  61. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/spotify/DESIGN.md +246 -0
  62. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/starbucks/DESIGN.md +580 -0
  63. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/stripe/DESIGN.md +487 -0
  64. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/supabase/DESIGN.md +462 -0
  65. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/superhuman/DESIGN.md +448 -0
  66. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/tesla/DESIGN.md +286 -0
  67. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/theverge/DESIGN.md +339 -0
  68. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/together.ai/DESIGN.md +633 -0
  69. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/uber/DESIGN.md +636 -0
  70. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/vercel/DESIGN.md +736 -0
  71. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/vodafone/DESIGN.md +538 -0
  72. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/voltagent/DESIGN.md +521 -0
  73. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/warp/DESIGN.md +526 -0
  74. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/webflow/DESIGN.md +588 -0
  75. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/wired/DESIGN.md +497 -0
  76. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/wise/DESIGN.md +544 -0
  77. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/x.ai/DESIGN.md +465 -0
  78. package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/zapier/DESIGN.md +537 -0
  79. package/assets/skills/evidence-led-ui/data/corpus-manifest.json +768 -0
  80. package/assets/skills/evidence-led-ui/data/observations.json +47053 -0
  81. package/assets/skills/evidence-led-ui/references/anti-defaults.md +203 -0
  82. package/assets/skills/evidence-led-ui/references/archetypes.md +97 -0
  83. package/assets/skills/evidence-led-ui/references/craft-rulings.md +167 -0
  84. package/assets/skills/evidence-led-ui/references/methodology.md +72 -0
  85. package/assets/skills/evidence-led-ui/references/observed-patterns.md +68 -0
  86. package/assets/skills/evidence-led-ui/references/production-contract.md +120 -0
  87. package/assets/skills/evidence-led-ui/references/provenance.md +117 -0
  88. package/assets/skills/evidence-led-ui/references/quality-rubric.md +126 -0
  89. package/dist/app-sidecar.js +161 -48
  90. package/dist/app-sidecar.js.map +1 -1
  91. package/dist/chat-agents/general.test.js +3 -0
  92. package/dist/chat-agents/general.test.js.map +1 -1
  93. package/dist/chat-agents/jiwa.d.ts +53 -0
  94. package/dist/chat-agents/jiwa.d.ts.map +1 -0
  95. package/dist/chat-agents/jiwa.js +352 -0
  96. package/dist/chat-agents/jiwa.js.map +1 -0
  97. package/dist/chat-agents/jiwa.test.d.ts +2 -0
  98. package/dist/chat-agents/jiwa.test.d.ts.map +1 -0
  99. package/dist/chat-agents/jiwa.test.js +66 -0
  100. package/dist/chat-agents/jiwa.test.js.map +1 -0
  101. package/dist/chat-agents/shared.d.ts.map +1 -1
  102. package/dist/chat-agents/shared.js +5 -1
  103. package/dist/chat-agents/shared.js.map +1 -1
  104. package/dist/cli.d.ts.map +1 -1
  105. package/dist/cli.js +15 -0
  106. package/dist/cli.js.map +1 -1
  107. package/dist/core/agent-session-review-coverage.test.d.ts +2 -0
  108. package/dist/core/agent-session-review-coverage.test.d.ts.map +1 -0
  109. package/dist/core/agent-session-review-coverage.test.js +57 -0
  110. package/dist/core/agent-session-review-coverage.test.js.map +1 -0
  111. package/dist/core/agent-session.d.ts +13 -7
  112. package/dist/core/agent-session.d.ts.map +1 -1
  113. package/dist/core/agent-session.js +143 -38
  114. package/dist/core/agent-session.js.map +1 -1
  115. package/dist/core/compaction/compactor.test.js +1 -1
  116. package/dist/core/compaction/compactor.test.js.map +1 -1
  117. package/dist/core/event-bus.d.ts +2 -0
  118. package/dist/core/event-bus.d.ts.map +1 -1
  119. package/dist/core/event-bus.js.map +1 -1
  120. package/dist/core/ideal-review.d.ts +27 -0
  121. package/dist/core/ideal-review.d.ts.map +1 -1
  122. package/dist/core/ideal-review.js +64 -0
  123. package/dist/core/ideal-review.js.map +1 -1
  124. package/dist/core/ideal-review.test.js +34 -1
  125. package/dist/core/ideal-review.test.js.map +1 -1
  126. package/dist/core/ken-prompt.d.ts +3 -3
  127. package/dist/core/ken-prompt.d.ts.map +1 -1
  128. package/dist/core/ken-prompt.js +10 -10
  129. package/dist/core/ken-prompt.js.map +1 -1
  130. package/dist/core/ken-prompt.test.js +17 -0
  131. package/dist/core/ken-prompt.test.js.map +1 -1
  132. package/dist/core/loop-breaker.d.ts +23 -16
  133. package/dist/core/loop-breaker.d.ts.map +1 -1
  134. package/dist/core/loop-breaker.js +52 -11
  135. package/dist/core/loop-breaker.js.map +1 -1
  136. package/dist/core/loop-breaker.test.js +37 -16
  137. package/dist/core/loop-breaker.test.js.map +1 -1
  138. package/dist/core/lsp/client.d.ts +3 -0
  139. package/dist/core/lsp/client.d.ts.map +1 -1
  140. package/dist/core/lsp/client.js +20 -0
  141. package/dist/core/lsp/client.js.map +1 -1
  142. package/dist/core/lsp/manager.d.ts +32 -9
  143. package/dist/core/lsp/manager.d.ts.map +1 -1
  144. package/dist/core/lsp/manager.js +89 -37
  145. package/dist/core/lsp/manager.js.map +1 -1
  146. package/dist/core/lsp/manager.test.js +56 -4
  147. package/dist/core/lsp/manager.test.js.map +1 -1
  148. package/dist/core/run-lifecycle.d.ts +40 -0
  149. package/dist/core/run-lifecycle.d.ts.map +1 -0
  150. package/dist/core/run-lifecycle.js +95 -0
  151. package/dist/core/run-lifecycle.js.map +1 -0
  152. package/dist/core/run-lifecycle.test.d.ts +2 -0
  153. package/dist/core/run-lifecycle.test.d.ts.map +1 -0
  154. package/dist/core/run-lifecycle.test.js +64 -0
  155. package/dist/core/run-lifecycle.test.js.map +1 -0
  156. package/dist/core/session-manager.d.ts +25 -1
  157. package/dist/core/session-manager.d.ts.map +1 -1
  158. package/dist/core/session-manager.js +66 -1
  159. package/dist/core/session-manager.js.map +1 -1
  160. package/dist/core/session-manager.test.js +80 -2
  161. package/dist/core/session-manager.test.js.map +1 -1
  162. package/dist/core/skills-routing.test.d.ts +2 -0
  163. package/dist/core/skills-routing.test.d.ts.map +1 -0
  164. package/dist/core/skills-routing.test.js +70 -0
  165. package/dist/core/skills-routing.test.js.map +1 -0
  166. package/dist/core/skills.d.ts +2 -0
  167. package/dist/core/skills.d.ts.map +1 -1
  168. package/dist/core/skills.js +32 -9
  169. package/dist/core/skills.js.map +1 -1
  170. package/dist/core/subagent-manager.d.ts +40 -3
  171. package/dist/core/subagent-manager.d.ts.map +1 -1
  172. package/dist/core/subagent-manager.js +342 -30
  173. package/dist/core/subagent-manager.js.map +1 -1
  174. package/dist/core/subagent-manager.test.js +189 -3
  175. package/dist/core/subagent-manager.test.js.map +1 -1
  176. package/dist/core/subagent-store.d.ts +20 -0
  177. package/dist/core/subagent-store.d.ts.map +1 -0
  178. package/dist/core/subagent-store.js +177 -0
  179. package/dist/core/subagent-store.js.map +1 -0
  180. package/dist/core/subagent-store.test.d.ts +2 -0
  181. package/dist/core/subagent-store.test.d.ts.map +1 -0
  182. package/dist/core/subagent-store.test.js +94 -0
  183. package/dist/core/subagent-store.test.js.map +1 -0
  184. package/dist/modes/agent-home-mode.d.ts.map +1 -1
  185. package/dist/modes/agent-home-mode.js +10 -3
  186. package/dist/modes/agent-home-mode.js.map +1 -1
  187. package/dist/modes/serve-mode.d.ts.map +1 -1
  188. package/dist/modes/serve-mode.js +10 -3
  189. package/dist/modes/serve-mode.js.map +1 -1
  190. package/dist/modes/subagent-worker-mode.d.ts +2 -0
  191. package/dist/modes/subagent-worker-mode.d.ts.map +1 -1
  192. package/dist/modes/subagent-worker-mode.js +13 -3
  193. package/dist/modes/subagent-worker-mode.js.map +1 -1
  194. package/dist/system-prompt.js +2 -2
  195. package/dist/system-prompt.js.map +1 -1
  196. package/dist/system-prompt.test.js +3 -0
  197. package/dist/system-prompt.test.js.map +1 -1
  198. package/dist/tools/skill.d.ts.map +1 -1
  199. package/dist/tools/skill.js +8 -3
  200. package/dist/tools/skill.js.map +1 -1
  201. package/dist/tools/tasks.d.ts +1 -1
  202. package/dist/tools/web-fetch.d.ts +1 -1
  203. package/dist/ui/App.d.ts +7 -1
  204. package/dist/ui/App.d.ts.map +1 -1
  205. package/dist/ui/App.js +63 -17
  206. package/dist/ui/App.js.map +1 -1
  207. package/dist/ui/components/Footer.d.ts +1 -0
  208. package/dist/ui/components/Footer.d.ts.map +1 -1
  209. package/dist/ui/components/Footer.js +3 -3
  210. package/dist/ui/components/Footer.js.map +1 -1
  211. package/dist/ui/components/Footer.test.d.ts +2 -0
  212. package/dist/ui/components/Footer.test.d.ts.map +1 -0
  213. package/dist/ui/components/Footer.test.js +16 -0
  214. package/dist/ui/components/Footer.test.js.map +1 -0
  215. package/dist/ui/components/SkillsOverlay.d.ts.map +1 -1
  216. package/dist/ui/components/SkillsOverlay.js +8 -3
  217. package/dist/ui/components/SkillsOverlay.js.map +1 -1
  218. package/dist/ui/hooks/useAgentLoop.d.ts +8 -3
  219. package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
  220. package/dist/ui/hooks/useAgentLoop.js +71 -26
  221. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  222. package/dist/ui/hooks/useAgentLoop.test.js +27 -0
  223. package/dist/ui/hooks/useAgentLoop.test.js.map +1 -1
  224. package/dist/ui/hooks/useSessionPersistence.d.ts +4 -2
  225. package/dist/ui/hooks/useSessionPersistence.d.ts.map +1 -1
  226. package/dist/ui/hooks/useSessionPersistence.js +7 -1
  227. package/dist/ui/hooks/useSessionPersistence.js.map +1 -1
  228. package/dist/ui/render.d.ts +7 -0
  229. package/dist/ui/render.d.ts.map +1 -1
  230. package/dist/ui/render.js +4 -0
  231. package/dist/ui/render.js.map +1 -1
  232. package/package.json +6 -5
@@ -18,11 +18,13 @@ import os from "node:os";
18
18
  import path from "node:path";
19
19
  import { randomUUID } from "node:crypto";
20
20
  import { parseArgs } from "node:util";
21
- import { formatError } from "@kenkaiiii/gg-ai";
21
+ import { environmentSecrets, formatError, redactValue, } from "@kenkaiiii/gg-ai";
22
22
  import { runJsonMode } from "./modes/json-mode.js";
23
23
  import { runSubagentWorkerMode } from "./modes/subagent-worker-mode.js";
24
24
  import { AgentSession } from "./core/agent-session.js";
25
+ import { RunLifecycle } from "./core/run-lifecycle.js";
25
26
  import { CHAT_AGENT_IDS, chatAgentSessionsDir, createChatAgent, parseChatAgentId, sessionsDirForChatAgent, switchChatAgent, } from "./chat-agents/index.js";
27
+ import { buildJiwaTools, JiwaStore } from "./chat-agents/jiwa.js";
26
28
  import { buildMemoryTools, MemoryStore } from "./chat-agents/memory.js";
27
29
  import { buildKenSystemPrompt, buildKenAutopilotSystemPrompt } from "./core/ken-prompt.js";
28
30
  import { buildKenDigest, buildKenAutopilotContext, buildKenAutopilotPlanContext, } from "./core/ken-context.js";
@@ -517,6 +519,13 @@ async function main() {
517
519
  }
518
520
  },
519
521
  });
522
+ const jiwaStore = new JiwaStore({
523
+ onChange: ({ jiwa }) => {
524
+ for (const ctx of sessions.values()) {
525
+ ctx.broadcast("jiwa_change", { count: jiwa.length });
526
+ }
527
+ },
528
+ });
520
529
  // XP/rank progress — loaded once per daemon; awards fan out to every window.
521
530
  // Each frame is tagged `origin: true` only for the session that earned the
522
531
  // XP, so that window alone plays sounds/chips while the rest just re-render.
@@ -633,7 +642,7 @@ async function main() {
633
642
  const sessionPath = typeof body.sessionPath === "string" && body.sessionPath ? body.sessionPath : undefined;
634
643
  const id = randomUUID();
635
644
  try {
636
- const ctx = await createSession({ auth, paths, progress, memoryStore }, { id, mode, chatAgent, cwd: sessionCwd, sessionPath });
645
+ const ctx = await createSession({ auth, paths, progress, memoryStore, jiwaStore }, { id, mode, chatAgent, cwd: sessionCwd, sessionPath });
637
646
  sessions.set(id, ctx);
638
647
  log("INFO", "app-sidecar", "session created", {
639
648
  id,
@@ -886,7 +895,7 @@ async function createProgressManager(agentDir, broadcastAll) {
886
895
  * logger, PATH, shared auth file, and radio live at the daemon level.
887
896
  */
888
897
  async function createSession(deps, opts) {
889
- const { auth, progress, memoryStore } = deps;
898
+ const { auth, progress, memoryStore, jiwaStore } = deps;
890
899
  const paths = deps.paths;
891
900
  const mode = opts.mode;
892
901
  let chatAgent = opts.chatAgent;
@@ -921,7 +930,8 @@ async function createSession(deps, opts) {
921
930
  const clients = new Set();
922
931
  let clientSeq = 0;
923
932
  function broadcast(type, data) {
924
- const frame = `data: ${JSON.stringify({ type, data })}\n\n`;
933
+ const safePayload = redactValue({ type, data }, { secrets: environmentSecrets(process.env) });
934
+ const frame = `data: ${JSON.stringify(safePayload)}\n\n`;
925
935
  for (const c of clients)
926
936
  c.res.write(frame);
927
937
  }
@@ -1007,8 +1017,8 @@ async function createSession(deps, opts) {
1007
1017
  session = createChatAgent(chatAgent, {
1008
1018
  ...baseSessionOptions,
1009
1019
  sessionsDir: paths.sessionsDir,
1010
- additionalTools: buildMemoryTools(memoryStore),
1011
- getSystemPromptTail: () => memoryStore.renderForPrompt(),
1020
+ additionalTools: [...buildMemoryTools(memoryStore), ...buildJiwaTools(jiwaStore)],
1021
+ getSystemPromptTail: () => `${memoryStore.renderForPrompt()}\n\n${jiwaStore.renderForPrompt()}`,
1012
1022
  onAgentChange: async (nextAgent) => {
1013
1023
  chatAgent = nextAgent;
1014
1024
  broadcast("chat_agent_change", { chatAgent: nextAgent });
@@ -1115,6 +1125,13 @@ async function createSession(deps, opts) {
1115
1125
  session.eventBus.on("compaction_start", (d) => broadcast("compaction_start", d));
1116
1126
  session.eventBus.on("compaction_end", (d) => broadcast("compaction_end", d));
1117
1127
  let running = false;
1128
+ const runLifecycle = new RunLifecycle((runState) => {
1129
+ running = runState !== "idle";
1130
+ if (runState === "cancelling")
1131
+ broadcast("run_cancelling", { runState });
1132
+ });
1133
+ const cancelledRunEndGenerations = new Set();
1134
+ let pendingCancelDrain = null;
1118
1135
  let titleGenerated = false;
1119
1136
  // Bumped by /cancel — a run whose cancel generation changed mid-flight was
1120
1137
  // canceled and earns no XP.
@@ -1137,6 +1154,7 @@ async function createSession(deps, opts) {
1137
1154
  let autopilotCancelled = false;
1138
1155
  // Hard cap on review→prompt→review rounds per user turn (loop safety).
1139
1156
  const MAX_AUTOPILOT_ROUNDS = 3;
1157
+ const CANCEL_TIMEOUT_MS = 5_000;
1140
1158
  // Prompt bodies Autopilot Ken injected into the BUILD session this
1141
1159
  // conversation. Passed into every Ken digest so injected prompts render as
1142
1160
  // "Ken autopilot (injected)" instead of `**User:**` — otherwise multi-round
@@ -1343,29 +1361,63 @@ async function createSession(deps, opts) {
1343
1361
  });
1344
1362
  }
1345
1363
  }
1346
- // Core run lifecycle shared by /prompt and the task runner: flips `running`,
1347
- // brackets the run with run_start/run_end, refreshes the footer extras, and
1348
- // generates the session title once. `label` is the text shown live with the
1349
- // run_start frame.
1364
+ function abortOwnedWork() {
1365
+ cancelGeneration++;
1366
+ abort.abort();
1367
+ // Stop a run-all sweep and every async child through AgentSession's signal.
1368
+ taskRunAll = false;
1369
+ autopilotCancelled = true;
1370
+ kenAutoAbort.abort();
1371
+ }
1372
+ function installFreshRunControllers() {
1373
+ abort = new AbortController();
1374
+ session.setSignal(abort.signal);
1375
+ kenAutoAbort = new AbortController();
1376
+ kenAutoSession?.setSignal(kenAutoAbort.signal);
1377
+ }
1378
+ function finishOwnedGeneration(generation, emitCancelledFallback) {
1379
+ const cancelled = runLifecycle.isCancellationRequested(generation);
1380
+ const settlement = runLifecycle.settle(generation);
1381
+ if (!settlement.settled)
1382
+ return cancelled;
1383
+ // A replacement signal is safe only after the provider-backed owner settled.
1384
+ installFreshRunControllers();
1385
+ if (cancelled && emitCancelledFallback && !cancelledRunEndGenerations.has(generation)) {
1386
+ cancelledRunEndGenerations.add(generation);
1387
+ broadcast("run_end", { cancelled: true, runState: runLifecycle.state });
1388
+ }
1389
+ return cancelled;
1390
+ }
1391
+ // Core provider-run bracket. Standalone runs own a lifecycle generation;
1392
+ // injected autopilot runs share the cycle's outer generation.
1350
1393
  async function runAgent(label, run) {
1351
- running = true;
1394
+ const ownsGeneration = !runLifecycle.running;
1395
+ const generation = ownsGeneration
1396
+ ? runLifecycle.begin(abortOwnedWork).generation
1397
+ : runLifecycle.generation;
1398
+ if (ownsGeneration)
1399
+ pendingCancelDrain = null;
1352
1400
  // Progress (Ranks): completed, non-canceled runs with ≥1 assistant turn earn
1353
1401
  // XP — prompt + any commits authored during the run window.
1354
1402
  const runStartedAt = Date.now();
1355
1403
  const cancelGenAtStart = cancelGeneration;
1356
1404
  const assistantsBeforeRun = countAssistantMessages(session.getMessages());
1357
1405
  let runSucceeded = false;
1358
- broadcast("run_start", { text: label });
1406
+ broadcast("run_start", { text: label, runState: runLifecycle.state });
1359
1407
  try {
1360
- await run();
1408
+ if (!runLifecycle.isCancellationRequested(generation))
1409
+ await run();
1361
1410
  runSucceeded = true;
1362
1411
  }
1363
1412
  catch (err) {
1364
- broadcastError("error", "run failed", err);
1413
+ if (!runLifecycle.isCancellationRequested(generation)) {
1414
+ broadcastError("error", "run failed", err);
1415
+ }
1365
1416
  }
1366
1417
  finally {
1367
- running = false;
1418
+ const cancelled = runLifecycle.isCancellationRequested(generation);
1368
1419
  if (runSucceeded &&
1420
+ !cancelled &&
1369
1421
  cancelGeneration === cancelGenAtStart &&
1370
1422
  countAssistantMessages(session.getMessages()) > assistantsBeforeRun) {
1371
1423
  // Fire-and-forget — XP must never delay or break run teardown.
@@ -1375,21 +1427,24 @@ async function createSession(deps, opts) {
1375
1427
  // background tasks — refresh the footer extras once it settles.
1376
1428
  gitBranch = await getGitBranch(cwd).catch(() => gitBranch);
1377
1429
  gitIsRepo = await isGitRepo(cwd).catch(() => gitIsRepo);
1378
- broadcast("run_end", {});
1430
+ if (ownsGeneration)
1431
+ finishOwnedGeneration(generation, false);
1432
+ // A cancelled injected run is still owned by the surrounding autopilot
1433
+ // cycle; its outer finalizer emits the one terminal cancelled run_end.
1434
+ if (!(cancelled && !ownsGeneration)) {
1435
+ if (cancelled)
1436
+ cancelledRunEndGenerations.add(generation);
1437
+ broadcast("run_end", {
1438
+ ...(cancelled ? { cancelled: true } : {}),
1439
+ runState: runLifecycle.state,
1440
+ });
1441
+ }
1379
1442
  // Autopilot's review loop is driven explicitly from POST /prompt (see
1380
- // runAutopilotCycle), NOT from this shared finally — that keeps the
1381
- // injected GG Coder runs this cycle triggers from recursively re-entering
1382
- // the loop through the same bracket.
1383
- // The agent may have marked project tasks done during the run — prune the
1384
- // completed ones so they drop out of the Tasks modal automatically (users
1385
- // never have to delete finished tasks by hand).
1443
+ // runAutopilotCycle), NOT from this shared finally — that keeps injected
1444
+ // runs from recursively entering the same review loop.
1386
1445
  broadcast("tasks_list", { tasks: pruneDoneTasksSync(cwd) });
1387
- // Queue drains into the run as steering, so it's empty by run_end —
1388
- // sync the webview indicator.
1389
1446
  broadcast("queued", { count: session.getQueuedCount() });
1390
1447
  broadcast("extras", footerExtras());
1391
- // Generate a session title once, after the first run, for the title bar
1392
- // (best-effort, async — don't block the response).
1393
1448
  if (!titleGenerated) {
1394
1449
  titleGenerated = true;
1395
1450
  void session.generateTitle().then((title) => {
@@ -1422,7 +1477,8 @@ async function createSession(deps, opts) {
1422
1477
  return parseAutopilotVerdict(lastAssistantText(ken.getMessages()));
1423
1478
  }
1424
1479
  catch (err) {
1425
- broadcastError("autopilot_error", "autopilot review failed", err);
1480
+ if (!autopilotCancelled)
1481
+ broadcastError("autopilot_error", "autopilot review failed", err);
1426
1482
  return null;
1427
1483
  }
1428
1484
  finally {
@@ -1497,6 +1553,8 @@ async function createSession(deps, opts) {
1497
1553
  async function runAutopilotCycle(originalRequest) {
1498
1554
  if (!autopilot || autopilotCancelled)
1499
1555
  return;
1556
+ const generation = runLifecycle.begin(abortOwnedWork).generation;
1557
+ pendingCancelDrain = null;
1500
1558
  autopilotActive = true;
1501
1559
  // Generation captured by the last plan review; acceptPlan re-checks it so
1502
1560
  // a user Accept/Reject landing mid-review always wins.
@@ -1611,6 +1669,8 @@ async function createSession(deps, opts) {
1611
1669
  }
1612
1670
  finally {
1613
1671
  autopilotActive = false;
1672
+ finishOwnedGeneration(generation, true);
1673
+ queueMicrotask(() => void runStrandedQueue());
1614
1674
  }
1615
1675
  }
1616
1676
  // ── Stranded-queue drain ───────────────────────────────
@@ -1787,7 +1847,7 @@ async function createSession(deps, opts) {
1787
1847
  });
1788
1848
  }
1789
1849
  function json(res, status, body) {
1790
- const payload = JSON.stringify(body);
1850
+ const payload = JSON.stringify(redactValue(body, { secrets: environmentSecrets(process.env) }));
1791
1851
  res.writeHead(status, {
1792
1852
  "content-type": "application/json",
1793
1853
  "access-control-allow-origin": "*",
@@ -1803,6 +1863,7 @@ async function createSession(deps, opts) {
1803
1863
  mode,
1804
1864
  chatAgent,
1805
1865
  running,
1866
+ runState: runLifecycle.state,
1806
1867
  ready: true,
1807
1868
  thinkingLevel: session.getThinkingLevel() ?? null,
1808
1869
  supportedThinkingLevels: getSupportedThinkingLevels(st.provider, st.model),
@@ -1837,6 +1898,26 @@ async function createSession(deps, opts) {
1837
1898
  .catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
1838
1899
  return;
1839
1900
  }
1901
+ if (method === "GET" && url === "/jiwa") {
1902
+ void jiwaStore
1903
+ .snapshot()
1904
+ .then((snapshot) => json(res, 200, snapshot))
1905
+ .catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
1906
+ return;
1907
+ }
1908
+ if (method === "DELETE" && url.startsWith("/jiwa/")) {
1909
+ const id = decodeURIComponent(url.slice("/jiwa/".length));
1910
+ if (!id) {
1911
+ json(res, 400, { error: "Jiwa entry id is required" });
1912
+ return;
1913
+ }
1914
+ void jiwaStore
1915
+ .forget(id)
1916
+ .then(() => jiwaStore.snapshot())
1917
+ .then((snapshot) => json(res, 200, snapshot))
1918
+ .catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
1919
+ return;
1920
+ }
1840
1921
  if (method === "GET" && (url === "/events" || url.startsWith("/events?"))) {
1841
1922
  res.writeHead(200, {
1842
1923
  "content-type": "text/event-stream",
@@ -1855,6 +1936,7 @@ async function createSession(deps, opts) {
1855
1936
  mode,
1856
1937
  chatAgent,
1857
1938
  running,
1939
+ runState: runLifecycle.state,
1858
1940
  thinkingLevel: session.getThinkingLevel() ?? null,
1859
1941
  supportedThinkingLevels: getSupportedThinkingLevels(st.provider, st.model),
1860
1942
  supportsVideo: getModel(st.model)?.supportsVideo ?? false,
@@ -2350,6 +2432,13 @@ async function createSession(deps, opts) {
2350
2432
  json(res, 400, { error: "empty prompt" });
2351
2433
  return;
2352
2434
  }
2435
+ if (runLifecycle.running && runLifecycle.isCancellationRequested(runLifecycle.generation)) {
2436
+ json(res, 409, {
2437
+ error: runLifecycle.state === "cancelling" ? "run_cancelling" : "cancel_failed",
2438
+ runState: runLifecycle.state,
2439
+ });
2440
+ return;
2441
+ }
2353
2442
  if (running || autopilotActive) {
2354
2443
  // Queue prompts as mid-run steering (mirrors the CLI). Also queue while
2355
2444
  // an autopilot cycle is active but between injected runs (build idle,
@@ -2838,26 +2927,50 @@ async function createSession(deps, opts) {
2838
2927
  return;
2839
2928
  }
2840
2929
  if (method === "POST" && url === "/cancel") {
2841
- cancelGeneration++;
2842
- abort.abort();
2843
- abort = new AbortController();
2844
- session.setSignal(abort.signal);
2845
- running = false;
2846
- // Stop a run-all sweep so the next pending task isn't auto-started.
2847
- taskRunAll = false;
2848
- // Stop any in-flight autopilot cycle: flag it so the loop bails between
2849
- // steps, and abort a review that's mid-prompt on the kenAuto session.
2850
- autopilotCancelled = true;
2851
- kenAutoAbort.abort();
2852
- kenAutoAbort = new AbortController();
2853
- kenAutoSession?.setSignal(kenAutoAbort.signal);
2854
- autopilotReviewing = false;
2855
- // Drop any queued steering and return it so the webview can restore it to
2856
- // the composer.
2857
- const drained = session.drainQueue();
2858
- broadcast("run_end", { cancelled: true });
2859
- broadcast("queued", { count: 0 });
2860
- json(res, 200, { cancelled: true, drained });
2930
+ void (async () => {
2931
+ // Even between task runs, cancellation stops the sweep. Active provider
2932
+ // ownership invokes the full abort hook exactly once through lifecycle.
2933
+ taskRunAll = false;
2934
+ autopilotCancelled = true;
2935
+ if (!runLifecycle.running) {
2936
+ kenAutoAbort.abort();
2937
+ kenAutoAbort = new AbortController();
2938
+ kenAutoSession?.setSignal(kenAutoAbort.signal);
2939
+ }
2940
+ const generation = runLifecycle.generation;
2941
+ if (!pendingCancelDrain || pendingCancelDrain.generation !== generation) {
2942
+ pendingCancelDrain = { generation, text: session.drainQueue() };
2943
+ broadcast("queued", { count: 0 });
2944
+ }
2945
+ const result = await runLifecycle.cancel(CANCEL_TIMEOUT_MS);
2946
+ const drained = pendingCancelDrain.text;
2947
+ if (result.status === "failed") {
2948
+ broadcast("cancel_failed", {
2949
+ error: "cancel_failed",
2950
+ reason: result.reason,
2951
+ runState: runLifecycle.state,
2952
+ });
2953
+ json(res, 504, {
2954
+ error: "cancel_failed",
2955
+ reason: result.reason,
2956
+ runState: runLifecycle.state,
2957
+ drained,
2958
+ });
2959
+ return;
2960
+ }
2961
+ json(res, 200, {
2962
+ cancelled: result.status === "cancelled",
2963
+ runState: runLifecycle.state,
2964
+ drained,
2965
+ });
2966
+ })().catch((error) => {
2967
+ broadcast("cancel_failed", { error: "cancel_failed", runState: runLifecycle.state });
2968
+ json(res, 500, {
2969
+ error: "cancel_failed",
2970
+ message: error instanceof Error ? error.message : String(error),
2971
+ runState: runLifecycle.state,
2972
+ });
2973
+ });
2861
2974
  return;
2862
2975
  }
2863
2976
  if (method === "POST" && url === "/new-session") {