@kenkaiiii/ggcoder 5.74.2 → 5.75.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 (218) hide show
  1. package/README.md +1 -1
  2. package/assets/skills/bulletproof/SKILL.md +1 -1
  3. package/assets/skills/clarify/SKILL.md +1 -1
  4. package/assets/skills/code-review/SKILL.md +1 -1
  5. package/assets/skills/compliance-guard/SKILL.md +1 -1
  6. package/assets/skills/durable/SKILL.md +1 -1
  7. package/assets/skills/evidence-led-ui/SKILL.md +1 -1
  8. package/assets/skills/lean/SKILL.md +1 -1
  9. package/assets/skills/refactoring/SKILL.md +1 -1
  10. package/assets/skills/root-cause/SKILL.md +1 -1
  11. package/assets/skills/shared-language/SKILL.md +1 -1
  12. package/assets/skills/tdd/SKILL.md +1 -1
  13. package/dist/app-sidecar/app-settings.d.ts +65 -0
  14. package/dist/app-sidecar/app-settings.js +147 -0
  15. package/dist/app-sidecar/app-settings.js.map +1 -0
  16. package/dist/app-sidecar/attachments.d.ts +11 -0
  17. package/dist/app-sidecar/attachments.js +47 -0
  18. package/dist/app-sidecar/attachments.js.map +1 -0
  19. package/dist/app-sidecar/auth-routes.d.ts +3 -0
  20. package/dist/app-sidecar/auth-routes.js +290 -0
  21. package/dist/app-sidecar/auth-routes.js.map +1 -0
  22. package/dist/app-sidecar/autopilot-runner.d.ts +61 -0
  23. package/dist/app-sidecar/autopilot-runner.js +367 -0
  24. package/dist/app-sidecar/autopilot-runner.js.map +1 -0
  25. package/dist/app-sidecar/file-search.d.ts +15 -0
  26. package/dist/app-sidecar/file-search.js +103 -0
  27. package/dist/app-sidecar/file-search.js.map +1 -0
  28. package/dist/app-sidecar/hf-pull-manager.d.ts +20 -0
  29. package/dist/app-sidecar/hf-pull-manager.js +224 -0
  30. package/dist/app-sidecar/hf-pull-manager.js.map +1 -0
  31. package/dist/app-sidecar/history-routes.d.ts +3 -0
  32. package/dist/app-sidecar/history-routes.js +375 -0
  33. package/dist/app-sidecar/history-routes.js.map +1 -0
  34. package/dist/app-sidecar/history.d.ts +67 -0
  35. package/dist/app-sidecar/history.js +23 -0
  36. package/dist/app-sidecar/history.js.map +1 -0
  37. package/dist/app-sidecar/http.d.ts +5 -0
  38. package/dist/app-sidecar/http.js +27 -0
  39. package/dist/app-sidecar/http.js.map +1 -0
  40. package/dist/app-sidecar/integration-routes.d.ts +3 -0
  41. package/dist/app-sidecar/integration-routes.js +286 -0
  42. package/dist/app-sidecar/integration-routes.js.map +1 -0
  43. package/dist/app-sidecar/json-mode.d.ts +10 -0
  44. package/dist/app-sidecar/json-mode.js +73 -0
  45. package/dist/app-sidecar/json-mode.js.map +1 -0
  46. package/dist/app-sidecar/keep-awake.d.ts +4 -0
  47. package/dist/app-sidecar/keep-awake.js +5 -0
  48. package/dist/app-sidecar/keep-awake.js.map +1 -0
  49. package/dist/app-sidecar/ken-context.d.ts +20 -0
  50. package/dist/app-sidecar/ken-context.js +55 -0
  51. package/dist/app-sidecar/ken-context.js.map +1 -0
  52. package/dist/app-sidecar/mcp-routes.d.ts +3 -0
  53. package/dist/app-sidecar/mcp-routes.js +185 -0
  54. package/dist/app-sidecar/mcp-routes.js.map +1 -0
  55. package/dist/app-sidecar/mcp-rows.d.ts +31 -0
  56. package/dist/app-sidecar/mcp-rows.js +77 -0
  57. package/dist/app-sidecar/mcp-rows.js.map +1 -0
  58. package/dist/app-sidecar/progress-manager.d.ts +10 -0
  59. package/dist/app-sidecar/progress-manager.js +116 -0
  60. package/dist/app-sidecar/progress-manager.js.map +1 -0
  61. package/dist/app-sidecar/prompt-routes.d.ts +3 -0
  62. package/dist/app-sidecar/prompt-routes.js +354 -0
  63. package/dist/app-sidecar/prompt-routes.js.map +1 -0
  64. package/dist/app-sidecar/route-context.d.ts +145 -0
  65. package/dist/app-sidecar/route-context.js +2 -0
  66. package/dist/app-sidecar/route-context.js.map +1 -0
  67. package/dist/app-sidecar/run-control-routes.d.ts +3 -0
  68. package/dist/app-sidecar/run-control-routes.js +430 -0
  69. package/dist/app-sidecar/run-control-routes.js.map +1 -0
  70. package/dist/app-sidecar/session-routes.d.ts +3 -0
  71. package/dist/app-sidecar/session-routes.js +115 -0
  72. package/dist/app-sidecar/session-routes.js.map +1 -0
  73. package/dist/app-sidecar/session-types.d.ts +39 -0
  74. package/dist/app-sidecar/session-types.js +5 -0
  75. package/dist/app-sidecar/session-types.js.map +1 -0
  76. package/dist/app-sidecar/task-routes.d.ts +3 -0
  77. package/dist/app-sidecar/task-routes.js +149 -0
  78. package/dist/app-sidecar/task-routes.js.map +1 -0
  79. package/dist/app-sidecar/usage.d.ts +19 -0
  80. package/dist/app-sidecar/usage.js +153 -0
  81. package/dist/app-sidecar/usage.js.map +1 -0
  82. package/dist/app-sidecar/workspace-routes.d.ts +3 -0
  83. package/dist/app-sidecar/workspace-routes.js +244 -0
  84. package/dist/app-sidecar/workspace-routes.js.map +1 -0
  85. package/dist/app-sidecar.js +482 -3695
  86. package/dist/app-sidecar.js.map +1 -1
  87. package/dist/cli.js +2 -2
  88. package/dist/cli.js.map +1 -1
  89. package/dist/config.js +1 -1
  90. package/dist/core/acceptance-checks.js +3 -9
  91. package/dist/core/acceptance-checks.js.map +1 -1
  92. package/dist/core/agent-session/helpers.d.ts +26 -0
  93. package/dist/core/agent-session/helpers.js +47 -0
  94. package/dist/core/agent-session/helpers.js.map +1 -0
  95. package/dist/core/agent-session/mcp-tools.d.ts +68 -0
  96. package/dist/core/agent-session/mcp-tools.js +195 -0
  97. package/dist/core/agent-session/mcp-tools.js.map +1 -0
  98. package/dist/core/agent-session/run-loop-monitor.d.ts +63 -0
  99. package/dist/core/agent-session/run-loop-monitor.js +164 -0
  100. package/dist/core/agent-session/run-loop-monitor.js.map +1 -0
  101. package/dist/core/agent-session/transcript-markers.d.ts +57 -0
  102. package/dist/core/agent-session/transcript-markers.js +166 -0
  103. package/dist/core/agent-session/transcript-markers.js.map +1 -0
  104. package/dist/core/agent-session/verification-tracker.d.ts +46 -0
  105. package/dist/core/agent-session/verification-tracker.js +246 -0
  106. package/dist/core/agent-session/verification-tracker.js.map +1 -0
  107. package/dist/core/agent-session.d.ts +27 -87
  108. package/dist/core/agent-session.js +166 -709
  109. package/dist/core/agent-session.js.map +1 -1
  110. package/dist/core/auth-providers.js +3 -3
  111. package/dist/core/auth-providers.js.map +1 -1
  112. package/dist/core/autopilot-cycle.d.ts +6 -2
  113. package/dist/core/autopilot-cycle.js +1 -1
  114. package/dist/core/autopilot-cycle.js.map +1 -1
  115. package/dist/core/bundled-agents.js +6 -6
  116. package/dist/core/bundled-agents.js.map +1 -1
  117. package/dist/core/checklist-git.d.ts +19 -0
  118. package/dist/core/checklist-git.js +54 -0
  119. package/dist/core/checklist-git.js.map +1 -0
  120. package/dist/core/checklist-items.d.ts +10 -1
  121. package/dist/core/checklist-items.js +22 -0
  122. package/dist/core/checklist-items.js.map +1 -1
  123. package/dist/core/checklist-prompt.d.ts +5 -1
  124. package/dist/core/checklist-prompt.js +16 -5
  125. package/dist/core/checklist-prompt.js.map +1 -1
  126. package/dist/core/checklist-snapshot.d.ts +5 -1
  127. package/dist/core/checklist-snapshot.js +19 -2
  128. package/dist/core/checklist-snapshot.js.map +1 -1
  129. package/dist/core/context-limits.js +1 -1
  130. package/dist/core/context-limits.js.map +1 -1
  131. package/dist/core/plan-handoff.d.ts +30 -0
  132. package/dist/core/plan-handoff.js +10 -0
  133. package/dist/core/plan-handoff.js.map +1 -0
  134. package/dist/core/plan-submission-gate.d.ts +28 -0
  135. package/dist/core/plan-submission-gate.js +27 -0
  136. package/dist/core/plan-submission-gate.js.map +1 -0
  137. package/dist/core/skills.js +6 -9
  138. package/dist/core/skills.js.map +1 -1
  139. package/dist/core/style-packs/index.js +2 -11
  140. package/dist/core/style-packs/index.js.map +1 -1
  141. package/dist/core/style-packs/packs.d.ts +3 -12
  142. package/dist/core/style-packs/packs.js +132 -173
  143. package/dist/core/style-packs/packs.js.map +1 -1
  144. package/dist/system-prompt.js +55 -78
  145. package/dist/system-prompt.js.map +1 -1
  146. package/dist/tools/ask-user.js +13 -74
  147. package/dist/tools/ask-user.js.map +1 -1
  148. package/dist/tools/bash.js +13 -78
  149. package/dist/tools/bash.js.map +1 -1
  150. package/dist/tools/checklist.d.ts +2 -10
  151. package/dist/tools/checklist.js +7 -39
  152. package/dist/tools/checklist.js.map +1 -1
  153. package/dist/tools/code-nav.js +7 -29
  154. package/dist/tools/code-nav.js.map +1 -1
  155. package/dist/tools/edit.d.ts +3 -9
  156. package/dist/tools/edit.js +66 -65
  157. package/dist/tools/edit.js.map +1 -1
  158. package/dist/tools/enter-plan.js +2 -7
  159. package/dist/tools/enter-plan.js.map +1 -1
  160. package/dist/tools/exit-plan.js +2 -3
  161. package/dist/tools/exit-plan.js.map +1 -1
  162. package/dist/tools/find.js +3 -4
  163. package/dist/tools/find.js.map +1 -1
  164. package/dist/tools/grep.js +6 -18
  165. package/dist/tools/grep.js.map +1 -1
  166. package/dist/tools/ls.js +3 -3
  167. package/dist/tools/ls.js.map +1 -1
  168. package/dist/tools/prompt-hints.js +34 -47
  169. package/dist/tools/prompt-hints.js.map +1 -1
  170. package/dist/tools/read.js +8 -20
  171. package/dist/tools/read.js.map +1 -1
  172. package/dist/tools/search-code.js +4 -12
  173. package/dist/tools/search-code.js.map +1 -1
  174. package/dist/tools/skill.js +13 -7
  175. package/dist/tools/skill.js.map +1 -1
  176. package/dist/tools/subagent-control.js +7 -22
  177. package/dist/tools/subagent-control.js.map +1 -1
  178. package/dist/tools/subagent.js +4 -7
  179. package/dist/tools/subagent.js.map +1 -1
  180. package/dist/tools/task-output.js +4 -15
  181. package/dist/tools/task-output.js.map +1 -1
  182. package/dist/tools/task-send.js +5 -17
  183. package/dist/tools/task-send.js.map +1 -1
  184. package/dist/tools/task-stop.js +2 -2
  185. package/dist/tools/task-stop.js.map +1 -1
  186. package/dist/tools/tool-search.js +2 -7
  187. package/dist/tools/tool-search.js.map +1 -1
  188. package/dist/tools/tool-tiers.d.ts +17 -4
  189. package/dist/tools/tool-tiers.js +38 -15
  190. package/dist/tools/tool-tiers.js.map +1 -1
  191. package/dist/tools/web-fetch.js +7 -33
  192. package/dist/tools/web-fetch.js.map +1 -1
  193. package/dist/tools/write.js +3 -4
  194. package/dist/tools/write.js.map +1 -1
  195. package/dist/ui/components/Footer.js +1 -2
  196. package/dist/ui/components/Footer.js.map +1 -1
  197. package/package.json +7 -4
  198. package/dist/core/api-benchmark.d.ts +0 -63
  199. package/dist/core/api-benchmark.js +0 -381
  200. package/dist/core/api-benchmark.js.map +0 -1
  201. package/dist/core/bash-spawn-benchmark.d.ts +0 -1
  202. package/dist/core/bash-spawn-benchmark.js +0 -139
  203. package/dist/core/bash-spawn-benchmark.js.map +0 -1
  204. package/dist/core/cache-warm-benchmark.d.ts +0 -21
  205. package/dist/core/cache-warm-benchmark.js +0 -170
  206. package/dist/core/cache-warm-benchmark.js.map +0 -1
  207. package/dist/core/fast-apply-benchmark.d.ts +0 -25
  208. package/dist/core/fast-apply-benchmark.js +0 -284
  209. package/dist/core/fast-apply-benchmark.js.map +0 -1
  210. package/dist/core/hashline-edit-benchmark.d.ts +0 -88
  211. package/dist/core/hashline-edit-benchmark.js +0 -518
  212. package/dist/core/hashline-edit-benchmark.js.map +0 -1
  213. package/dist/core/semantic-search-benchmark.d.ts +0 -36
  214. package/dist/core/semantic-search-benchmark.js +0 -211
  215. package/dist/core/semantic-search-benchmark.js.map +0 -1
  216. package/dist/core/speed-benchmark.d.ts +0 -132
  217. package/dist/core/speed-benchmark.js +0 -410
  218. package/dist/core/speed-benchmark.js.map +0 -1
@@ -0,0 +1,367 @@
1
+ import fs from "node:fs/promises";
2
+ import { buildKenAutopilotContext, buildKenAutopilotPlanContext } from "../core/ken-context.js";
3
+ import { parseAutopilotVerdict } from "../core/autopilot-verdict.js";
4
+ import { isWorkflowCommandText, countAssistantMessages, shouldStartAutopilotCycle, extractTurnToolCalls, isMechanicalOnlyTurn, } from "../core/autopilot-gate.js";
5
+ import { driveAutopilotCycle, frameAutopilotInjection } from "../core/autopilot-cycle.js";
6
+ import { autopilotMarkerCopySeed } from "../core/session-history.js";
7
+ import { loadTasksSync, pruneDoneTasksSync, getNextPendingTask, markTaskInProgress, } from "../core/tasks-store.js";
8
+ import { log } from "../core/logger.js";
9
+ import { lastAssistantText } from "./ken-context.js";
10
+ const AUTOMATION_PROVENANCE = {
11
+ source: "runtime",
12
+ kind: "automation",
13
+ visibility: "hidden",
14
+ };
15
+ export function createAutopilotRunner(ctx) {
16
+ // ── Autopilot orchestration ─────────────────────────────────
17
+ // One review = prompt the kenAuto session with the review digest, read its
18
+ // final assistant text, parse a verdict. Returns null on failure (surfaced as
19
+ // an autopilot_error frame) so the cycle stops rather than looping blind.
20
+ // `originalRequest` is the user prompt that started the turn under review —
21
+ // pinned in the digest so it can't scroll out during multi-round cycles.
22
+ async function runAutopilotReview(originalRequest) {
23
+ ctx.autopilotReviewing = true;
24
+ ctx.broadcast("autopilot_review_start", {});
25
+ try {
26
+ const ken = await ctx.ensureKenAutoSession();
27
+ const digest = buildKenAutopilotContext({
28
+ cwd: ctx.cwd,
29
+ gitBranch: ctx.gitBranch,
30
+ messages: ctx.session.getMessages(),
31
+ verificationEvidence: ctx.session.getVerificationEvidence(),
32
+ verificationProblem: ctx.session.getVerificationProblem(),
33
+ originalRequest,
34
+ injectedPrompts: [...ctx.injectedAutopilotPrompts],
35
+ workflowCommands: await ctx.loadWorkflowCommandSpecs(),
36
+ });
37
+ await ken.prompt(digest);
38
+ return parseAutopilotVerdict(lastAssistantText(ken.getMessages()));
39
+ }
40
+ catch (err) {
41
+ if (!ctx.autopilotCancelled)
42
+ ctx.broadcastError("autopilot_error", "autopilot review failed", err);
43
+ return null;
44
+ }
45
+ finally {
46
+ ctx.autopilotReviewing = false;
47
+ // Apply any model switch that landed mid-review.
48
+ const pending = ctx.pendingKenAutoModel;
49
+ ctx.pendingKenAutoModel = null;
50
+ if (pending)
51
+ await ctx.syncKenAutoModel(pending.provider, pending.model);
52
+ }
53
+ }
54
+ // One PLAN review: like runAutopilotReview but the digest carries the
55
+ // submitted plan's markdown (`## Plan under review`) and the plan-review
56
+ // instruction — Ken judges the plan itself, not finished work. Returns null
57
+ // on failure; a failure caused by the user's own action racing the review
58
+ // (cancel or a manual Accept/Reject that bumped planGeneration) stays
59
+ // SILENT — no autopilot_error — because the user's decision already won.
60
+ async function runAutopilotPlanReview(originalRequest) {
61
+ const planPath = ctx.pendingPlanPath;
62
+ if (planPath === null)
63
+ return null;
64
+ const genAtStart = ctx.planGeneration;
65
+ ctx.autopilotReviewing = true;
66
+ ctx.broadcast("autopilot_review_start", {});
67
+ try {
68
+ const ken = await ctx.ensureKenAutoSession();
69
+ // Re-read the plan file (the run may have revised it in place); fall
70
+ // back to the content captured at exit_plan time.
71
+ const planContent = await fs.readFile(planPath, "utf-8").catch(() => ctx.pendingPlanContent);
72
+ const digest = buildKenAutopilotPlanContext({
73
+ cwd: ctx.cwd,
74
+ gitBranch: ctx.gitBranch,
75
+ messages: ctx.session.getMessages(),
76
+ verificationEvidence: ctx.session.getVerificationEvidence(),
77
+ verificationProblem: ctx.session.getVerificationProblem(),
78
+ originalRequest,
79
+ injectedPrompts: [...ctx.injectedAutopilotPrompts],
80
+ workflowCommands: await ctx.loadWorkflowCommandSpecs(),
81
+ planContent,
82
+ });
83
+ await ken.prompt(digest);
84
+ if (ctx.autopilotCancelled || ctx.planGeneration !== genAtStart)
85
+ return null;
86
+ return parseAutopilotVerdict(lastAssistantText(ken.getMessages()));
87
+ }
88
+ catch (err) {
89
+ // User action mid-review (manual Accept aborts the kenAuto run): drop
90
+ // the review silently — the user's decision supersedes Ken's.
91
+ if (ctx.autopilotCancelled || ctx.planGeneration !== genAtStart)
92
+ return null;
93
+ ctx.broadcastError("autopilot_error", "autopilot plan review failed", err);
94
+ return null;
95
+ }
96
+ finally {
97
+ ctx.autopilotReviewing = false;
98
+ // Apply any model switch that landed mid-review.
99
+ const pending = ctx.pendingKenAutoModel;
100
+ ctx.pendingKenAutoModel = null;
101
+ if (pending)
102
+ await ctx.syncKenAutoModel(pending.provider, pending.model);
103
+ }
104
+ }
105
+ // Drive the review→prompt→review loop for one finished user turn. Only ever
106
+ // called after shouldStartAutopilotCycle approves the turn (POST /prompt or
107
+ // the stranded-queue drain) — never from the task runner, resume, /ken, or
108
+ // error paths, so there's no recursion and no guard tangle. The loop's
109
+ // control flow lives in driveAutopilotCycle (core/autopilot-cycle.ts) so
110
+ // every exit path is unit-tested; this only wires the real dependencies.
111
+ async function runAutopilotCycle(originalRequest) {
112
+ if (!ctx.autopilot || ctx.autopilotCancelled)
113
+ return;
114
+ // Unverified work skips a work review silently. A pending plan still enters
115
+ // the cycle so driveAutopilotCycle says WHY Ken stepped aside
116
+ // (autopilot_human) before the plan is handed to the user.
117
+ if (ctx.pendingPlanPath === null && ctx.session.getVerificationProblem())
118
+ return;
119
+ const generation = ctx.runLifecycle.begin(ctx.abortOwnedWork).generation;
120
+ ctx.pendingCancelDrain = null;
121
+ ctx.autopilotActive = true;
122
+ // Generation captured by the last plan review; acceptPlan re-checks it so
123
+ // a user Accept/Reject landing mid-review always wins.
124
+ let planGenAtReview = -1;
125
+ try {
126
+ await driveAutopilotCycle({
127
+ // A plan-pending cycle needs extra rounds: approve+implement and the
128
+ // post-implement work review each consume one, so +2 keeps a real fix
129
+ // round available.
130
+ maxRounds: ctx.pendingPlanPath !== null ? ctx.MAX_AUTOPILOT_ROUNDS + 2 : ctx.MAX_AUTOPILOT_ROUNDS,
131
+ isCancelled: () => ctx.autopilotCancelled,
132
+ verificationProblem: () => ctx.session.getVerificationProblem(),
133
+ // An injected run entering plan mode WITHOUT submitting (enter_plan,
134
+ // no exit_plan) halts the cycle — Ken never prompts into a read-only
135
+ // plan-mode session. A submitted plan takes the planPending branch.
136
+ isPlanMode: () => ctx.session.getPlanMode(),
137
+ planPending: () => ctx.pendingPlanPath !== null,
138
+ reviewPlan: async () => {
139
+ planGenAtReview = ctx.planGeneration;
140
+ return runAutopilotPlanReview(originalRequest);
141
+ },
142
+ // Auto-accept: the inlined POST /plan/accept body. Returns false when
143
+ // the plan generation moved since the review (user acted) — the cycle
144
+ // exits silently and the user's action stands.
145
+ acceptPlan: async (reason) => {
146
+ if (ctx.pendingPlanPath === null || ctx.planGeneration !== planGenAtReview)
147
+ return false;
148
+ const planPath = ctx.pendingPlanPath;
149
+ let planTotal;
150
+ try {
151
+ await ctx.session.newSession(true);
152
+ ctx.injectedAutopilotPrompts = [];
153
+ planTotal = await ctx.activateApprovedPlan(planPath);
154
+ }
155
+ catch (err) {
156
+ ctx.broadcastError("autopilot_error", "autopilot plan accept failed", err);
157
+ return false;
158
+ }
159
+ ctx.clearPendingPlan();
160
+ // Keep the approval marker ahead of the reset, then seed the reset
161
+ // with the sidecar's canonical count from the actual plan file.
162
+ ctx.broadcast("autopilot_plan_accepted", reason ? { reason } : {});
163
+ ctx.broadcast("session_reset", { planTotal });
164
+ ctx.broadcast("plan_progress", ctx.planProgressPayload());
165
+ // Persisted into the NEW session so a resume shows the marker.
166
+ void ctx.session.persistAutopilotMarker("plan_approved", { reason });
167
+ return true;
168
+ },
169
+ runImplement: () => {
170
+ // Autopilot-injected run: frame it so GG Coder knows no human is
171
+ // watching the implementation. Record the framed string so Ken's
172
+ // digest labels it as injected, not as the user's ask. The run_start
173
+ // label stays the clean prompt.
174
+ const framed = frameAutopilotInjection(ctx.IMPLEMENT_PLAN_PROMPT);
175
+ ctx.injectedAutopilotPrompts.push(framed);
176
+ return ctx.runAgent(ctx.IMPLEMENT_PLAN_PROMPT, () => ctx.session.prompt(framed, AUTOMATION_PROVENANCE));
177
+ },
178
+ // Lean context per user turn: wipe prior review history so each new
179
+ // turn starts cheap, while within this cycle the few review messages
180
+ // persist so Ken remembers what he already asked GG Coder to fix.
181
+ resetReviewer: async () => {
182
+ await ctx.kenAutoSession?.newSession().catch(() => { });
183
+ },
184
+ review: () => runAutopilotReview(originalRequest),
185
+ // prompt → record the injected body (so later digests label it as
186
+ // Ken's, not the user's), show a compact Ken-tinted marker (not the
187
+ // prompt body), then feed GG Coder bracketed by runAgent so the run
188
+ // streams normally; the shared finally never re-triggers autopilot,
189
+ // so this can't recurse.
190
+ onInjected: (body, round) => {
191
+ // A revision injection supersedes the pending plan — if the run
192
+ // resubmits via exit_plan, onExitPlan re-sets it (no-op for work-
193
+ // branch injections, where nothing is pending).
194
+ ctx.clearPendingPlan();
195
+ // Record the FRAMED string (what actually lands in the build session,
196
+ // see runPrompt) so Ken's digest matches and labels it as injected.
197
+ // The webview marker + persisted body stay the CLEAN prompt so the UI
198
+ // shows Ken's actual instruction, not the autopilot preamble.
199
+ ctx.injectedAutopilotPrompts.push(frameAutopilotInjection(body));
200
+ ctx.broadcast("autopilot_prompted", { round, body });
201
+ void ctx.session.persistAutopilotMarker("prompted", { body });
202
+ },
203
+ // Autopilot-injected run: GG Coder receives the framed prompt (no human
204
+ // is watching this turn) while run_start keeps the clean label.
205
+ runPrompt: (body, opts) => ctx.runAgent(body, async () => {
206
+ if (opts?.planRevision)
207
+ await ctx.reenterPlanModeForRevision();
208
+ await ctx.session.prompt(frameAutopilotInjection(body), AUTOMATION_PROVENANCE);
209
+ }),
210
+ emit: (event) => {
211
+ // Persist the terminal verdict marker so a resumed session renders the
212
+ // same Ken bubble the live run showed instead of dropping it or
213
+ // falling back to the raw verdict text (e.g. ALL_CLEAR).
214
+ if (event.type === "autopilot_done") {
215
+ // Broadcast the SAME copySeed the persisted marker will produce on
216
+ // resume, so the live all-clear wording matches the resumed one.
217
+ // Must use the PERSISTED count — that's what persistAutopilotMarker
218
+ // anchors against, and it trails the in-memory list after a run
219
+ // whose messages never made it to disk.
220
+ const seed = autopilotMarkerCopySeed({
221
+ version: 1,
222
+ phase: "done",
223
+ afterMessageCount: ctx.session.getPersistedTranscriptCount(),
224
+ ...event.data,
225
+ });
226
+ ctx.broadcast(event.type, { ...event.data, copySeed: seed });
227
+ void ctx.session.persistAutopilotMarker("done", event.data);
228
+ return;
229
+ }
230
+ ctx.broadcast(event.type, event.data);
231
+ if (event.type === "autopilot_human") {
232
+ void ctx.session.persistAutopilotMarker("human", { reason: event.data.reason });
233
+ }
234
+ else if (event.type === "autopilot_capped") {
235
+ void ctx.session.persistAutopilotMarker("capped");
236
+ }
237
+ // autopilot_ignored renders nothing live, so nothing is persisted either.
238
+ },
239
+ });
240
+ }
241
+ finally {
242
+ ctx.autopilotActive = false;
243
+ ctx.finishOwnedGeneration(generation, true, ctx.session.getVerificationProblem() ? "unverified" : "completed");
244
+ queueMicrotask(() => void runStrandedQueue());
245
+ }
246
+ }
247
+ async function runStrandedQueue() {
248
+ if (ctx.drainingStrandedQueue)
249
+ return;
250
+ ctx.drainingStrandedQueue = true;
251
+ try {
252
+ for (;;) {
253
+ if (ctx.running || ctx.autopilotActive)
254
+ return;
255
+ const next = ctx.session.takeNextQueuedMessage();
256
+ if (!next)
257
+ return;
258
+ ctx.broadcast("queued", {
259
+ count: ctx.session.getQueuedCount(),
260
+ messages: ctx.session.listQueuedMessages(),
261
+ });
262
+ if (!next.text.trim() && next.attachments.length === 0)
263
+ continue;
264
+ // A queued message draining as a fresh turn supersedes any pending
265
+ // plan and clears a stale Stop, exactly like a direct POST /prompt
266
+ // turn — otherwise an earlier Stop silently disables Ken for this turn.
267
+ ctx.clearPendingPlan();
268
+ ctx.autopilotCancelled = false;
269
+ const workflowCommand = next.attachments.length === 0 &&
270
+ isWorkflowCommandText(next.text, await ctx.loadWorkflowCommandSpecs());
271
+ const assistantsBefore = countAssistantMessages(ctx.session.getMessages());
272
+ const messagesBefore = ctx.session.getMessages().length;
273
+ await ctx.runAgent(next.text, async () => {
274
+ if (next.attachments.length > 0) {
275
+ await ctx.session.promptWithAttachments(next.text, next.attachments);
276
+ }
277
+ else {
278
+ await ctx.session.prompt(next.text);
279
+ }
280
+ }, () => ctx.autopilot);
281
+ const decision = shouldStartAutopilotCycle({
282
+ enabled: ctx.autopilot,
283
+ cancelled: ctx.autopilotCancelled,
284
+ planMode: ctx.session.getPlanMode(),
285
+ // A submitted plan (exit_plan fired) routes into the PLAN review
286
+ // branch — the cycle reviews the plan itself instead of skipping.
287
+ planPending: ctx.pendingPlanPath !== null,
288
+ workflowCommand,
289
+ assistantMessagesAdded: countAssistantMessages(ctx.session.getMessages()) - assistantsBefore,
290
+ // Skip the review API call outright for turns that only started a
291
+ // background process (dev server/watcher), ran a read-only lookup, or
292
+ // committed/pushed — Ken's autopilot contract already IGNOREs these,
293
+ // so there's no reason to pay for that verdict.
294
+ mechanicalOnly: isMechanicalOnlyTurn(extractTurnToolCalls(ctx.session.getMessages(), messagesBefore)),
295
+ });
296
+ if (decision.start) {
297
+ log("INFO", "app-sidecar", "autopilot cycle starting (queued turn)", {
298
+ kind: decision.kind,
299
+ });
300
+ await runAutopilotCycle(next.text);
301
+ }
302
+ else {
303
+ ctx.broadcast("autopilot_ignored", { reason: decision.reason });
304
+ log("INFO", "app-sidecar", "autopilot skipped (queued turn)", {
305
+ reason: decision.reason,
306
+ });
307
+ }
308
+ }
309
+ }
310
+ finally {
311
+ ctx.drainingStrandedQueue = false;
312
+ ctx.offerPendingPlan();
313
+ }
314
+ }
315
+ async function runTaskById(taskId) {
316
+ const task = loadTasksSync(ctx.cwd).find((t) => t.id === taskId || t.id.startsWith(taskId));
317
+ if (!task)
318
+ return false;
319
+ // Fresh session per task so one task's context never bleeds into the next.
320
+ await ctx.session.newSession();
321
+ ctx.deactivateApprovedPlan();
322
+ ctx.injectedAutopilotPrompts = [];
323
+ ctx.clearPendingPlan();
324
+ ctx.broadcast("session_reset", {});
325
+ markTaskInProgress(ctx.cwd, task.id);
326
+ ctx.broadcast("tasks_list", { tasks: loadTasksSync(ctx.cwd) });
327
+ ctx.broadcast("task_start", { id: task.id, title: task.title });
328
+ // Persist the task header so a resumed task session shows what ran.
329
+ void ctx.session.persistAppMarker("task", { title: task.title }).catch(() => { });
330
+ const shortId = task.id.slice(0, 8);
331
+ const completionHint = `\n\n---\nWhen you have fully completed this task, call the tasks tool to mark it done:\n` +
332
+ `tasks({ action: "done", id: "${shortId}" })`;
333
+ await ctx.runAgent(task.title, () => ctx.session.prompt(task.prompt + completionHint, AUTOMATION_PROVENANCE));
334
+ // The agent typically marks the task done via the tasks tool during the run;
335
+ // prune completed tasks and push the refreshed list so the modal drops them.
336
+ ctx.broadcast("tasks_list", { tasks: pruneDoneTasksSync(ctx.cwd) });
337
+ return true;
338
+ }
339
+ async function runTasks(startId, all) {
340
+ ctx.taskRunAll = all;
341
+ let currentId = startId ?? getNextPendingTask(ctx.cwd)?.id ?? null;
342
+ while (currentId) {
343
+ const ran = await runTaskById(currentId);
344
+ if (!ran || !ctx.taskRunAll)
345
+ break;
346
+ const next = getNextPendingTask(ctx.cwd);
347
+ currentId = next ? next.id : null;
348
+ // Brief pause between tasks (mirrors the CLI cadence).
349
+ if (currentId)
350
+ await new Promise((resolve) => setTimeout(resolve, 500));
351
+ }
352
+ ctx.taskRunAll = false;
353
+ ctx.broadcast("tasks_run_done", {});
354
+ // Task runs never start an autopilot cycle; a plan a task submitted goes
355
+ // straight to the user.
356
+ ctx.offerPendingPlan();
357
+ }
358
+ return {
359
+ runAutopilotReview,
360
+ runAutopilotPlanReview,
361
+ runAutopilotCycle,
362
+ runStrandedQueue,
363
+ runTaskById,
364
+ runTasks,
365
+ };
366
+ }
367
+ //# sourceMappingURL=autopilot-runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autopilot-runner.js","sourceRoot":"","sources":["../../src/app-sidecar/autopilot-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export interface FileHit {
2
+ /** Project-relative POSIX path, e.g. "src/App.tsx". */
3
+ path: string;
4
+ /** File name only, e.g. "App.tsx". */
5
+ name: string;
6
+ }
7
+ export declare const FILE_SEARCH_LIMIT = 20;
8
+ export declare const FILE_SEARCH_SCAN_CAP = 50000;
9
+ /** Score a candidate path against a lowercased query. Higher is better; a
10
+ * negative score means "no match". Basename hits beat path hits; prefix beats
11
+ * substring; shorter paths break ties. */
12
+ export declare function scoreFile(relPath: string, name: string, query: string): number;
13
+ /** True when every char of `needle` appears in `haystack` in order (fuzzy). */
14
+ export declare function subsequenceMatch(haystack: string, needle: string): boolean;
15
+ export declare function searchProjectFiles(cwd: string, rawQuery: string): Promise<FileHit[]>;
@@ -0,0 +1,103 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { log } from "../core/logger.js";
4
+ export const FILE_SEARCH_LIMIT = 20;
5
+ // Upper bound on files walked per search (baseline #8 memory cap). Far above the
6
+ // 20-result output limit, so relevance/recency ranking is unaffected in practice.
7
+ export const FILE_SEARCH_SCAN_CAP = 50_000;
8
+ /** Score a candidate path against a lowercased query. Higher is better; a
9
+ * negative score means "no match". Basename hits beat path hits; prefix beats
10
+ * substring; shorter paths break ties. */
11
+ export function scoreFile(relPath, name, query) {
12
+ const lcPath = relPath.toLowerCase();
13
+ const lcName = name.toLowerCase();
14
+ let score = -1;
15
+ if (lcName === query)
16
+ score = 1000;
17
+ else if (lcName.startsWith(query))
18
+ score = 800;
19
+ else if (lcName.includes(query))
20
+ score = 600;
21
+ else if (lcPath.startsWith(query))
22
+ score = 400;
23
+ else if (lcPath.includes(query))
24
+ score = 200;
25
+ else if (subsequenceMatch(lcPath, query))
26
+ score = 100;
27
+ if (score < 0)
28
+ return -1;
29
+ // Prefer shorter paths (closer to root, less nesting) on equal match class.
30
+ return score - relPath.length * 0.1;
31
+ }
32
+ /** True when every char of `needle` appears in `haystack` in order (fuzzy). */
33
+ export function subsequenceMatch(haystack, needle) {
34
+ let i = 0;
35
+ for (const ch of haystack) {
36
+ if (ch === needle[i])
37
+ i++;
38
+ if (i === needle.length)
39
+ return true;
40
+ }
41
+ return needle.length === 0;
42
+ }
43
+ export async function searchProjectFiles(cwd, rawQuery) {
44
+ const fg = await import("fast-glob");
45
+ const ignore = await import("ignore");
46
+ const query = rawQuery.trim().toLowerCase();
47
+ let gitignore = [];
48
+ try {
49
+ const content = await fs.readFile(path.join(cwd, ".gitignore"), "utf-8");
50
+ gitignore = content
51
+ .split("\n")
52
+ .map((l) => l.trim())
53
+ .filter((l) => l && !l.startsWith("#"));
54
+ }
55
+ catch {
56
+ // No .gitignore — nothing extra to ignore.
57
+ }
58
+ const ig = ignore.default().add(gitignore);
59
+ // `stats: true` gives mtime without a second stat pass, so the empty-query
60
+ // "recent files" path is a single walk. Stream + hard scan cap (baseline #8):
61
+ // collecting the full result array retained ~0.9 MB per 1k files (18.5 MB at
62
+ // 20k), unbounded. Bail after FILE_SEARCH_SCAN_CAP entries so a giant repo
63
+ // can't balloon RSS; the newest/most-relevant matches still surface because
64
+ // the cap is far above the 20-result output limit.
65
+ const entries = [];
66
+ const scanStream = fg.default.stream("**/*", {
67
+ cwd,
68
+ dot: false,
69
+ onlyFiles: true,
70
+ ignore: ["**/node_modules/**", "**/.git/**", "**/.gg/**"],
71
+ suppressErrors: true,
72
+ followSymbolicLinks: false,
73
+ stats: true,
74
+ });
75
+ for await (const entry of scanStream) {
76
+ entries.push(entry);
77
+ if (entries.length >= FILE_SEARCH_SCAN_CAP) {
78
+ scanStream.destroy();
79
+ log("DEBUG", "app-sidecar", "file search scan cap hit", {
80
+ cap: String(FILE_SEARCH_SCAN_CAP),
81
+ cwd,
82
+ });
83
+ break;
84
+ }
85
+ }
86
+ const files = entries.filter((e) => !ig.ignores(e.path));
87
+ if (!query) {
88
+ return files
89
+ .sort((a, b) => (b.stats?.mtimeMs ?? 0) - (a.stats?.mtimeMs ?? 0))
90
+ .slice(0, FILE_SEARCH_LIMIT)
91
+ .map((e) => ({ path: e.path, name: path.posix.basename(e.path) }));
92
+ }
93
+ const scored = [];
94
+ for (const e of files) {
95
+ const name = path.posix.basename(e.path);
96
+ const score = scoreFile(e.path, name, query);
97
+ if (score >= 0)
98
+ scored.push({ hit: { path: e.path, name }, score });
99
+ }
100
+ scored.sort((a, b) => b.score - a.score);
101
+ return scored.slice(0, FILE_SEARCH_LIMIT).map((s) => s.hit);
102
+ }
103
+ //# sourceMappingURL=file-search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-search.js","sourceRoot":"","sources":["../../src/app-sidecar/file-search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { AppPaths, LocalEndpointProbe } from "@kenkaiiii/gg-core";
2
+ import { type HfSearchRow } from "../hf-pull.js";
3
+ import type { HfPullState } from "./session-types.js";
4
+ export interface HfPullManager {
5
+ /** Current/last pull (terminal state kept until the next pull). */
6
+ hfPull: HfPullState | null;
7
+ hfPullPayload: (s: HfPullState) => Record<string, unknown>;
8
+ hfSearch: (query: string) => Promise<HfSearchRow[]>;
9
+ startHfPull: (repo: string) => Promise<Record<string, unknown>>;
10
+ cancelHfPull: () => boolean;
11
+ }
12
+ /** Per-session Hugging Face → Ollama pull state + Hub search (moved verbatim
13
+ * out of `createSession`). */
14
+ export declare function createHfPullManager(deps: {
15
+ paths: AppPaths;
16
+ broadcast: (type: string, data: unknown) => void;
17
+ broadcastAll: (type: string, data: unknown) => void;
18
+ scanLocalModels: (force: boolean) => Promise<LocalEndpointProbe[]>;
19
+ localStatePayload: () => unknown;
20
+ }): HfPullManager;