@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.
- package/README.md +1 -1
- package/assets/skills/bulletproof/SKILL.md +1 -1
- package/assets/skills/clarify/SKILL.md +1 -1
- package/assets/skills/code-review/SKILL.md +1 -1
- package/assets/skills/compliance-guard/SKILL.md +1 -1
- package/assets/skills/durable/SKILL.md +1 -1
- package/assets/skills/evidence-led-ui/SKILL.md +1 -1
- package/assets/skills/lean/SKILL.md +1 -1
- package/assets/skills/refactoring/SKILL.md +1 -1
- package/assets/skills/root-cause/SKILL.md +1 -1
- package/assets/skills/shared-language/SKILL.md +1 -1
- package/assets/skills/tdd/SKILL.md +1 -1
- package/dist/app-sidecar/app-settings.d.ts +65 -0
- package/dist/app-sidecar/app-settings.js +147 -0
- package/dist/app-sidecar/app-settings.js.map +1 -0
- package/dist/app-sidecar/attachments.d.ts +11 -0
- package/dist/app-sidecar/attachments.js +47 -0
- package/dist/app-sidecar/attachments.js.map +1 -0
- package/dist/app-sidecar/auth-routes.d.ts +3 -0
- package/dist/app-sidecar/auth-routes.js +290 -0
- package/dist/app-sidecar/auth-routes.js.map +1 -0
- package/dist/app-sidecar/autopilot-runner.d.ts +61 -0
- package/dist/app-sidecar/autopilot-runner.js +367 -0
- package/dist/app-sidecar/autopilot-runner.js.map +1 -0
- package/dist/app-sidecar/file-search.d.ts +15 -0
- package/dist/app-sidecar/file-search.js +103 -0
- package/dist/app-sidecar/file-search.js.map +1 -0
- package/dist/app-sidecar/hf-pull-manager.d.ts +20 -0
- package/dist/app-sidecar/hf-pull-manager.js +224 -0
- package/dist/app-sidecar/hf-pull-manager.js.map +1 -0
- package/dist/app-sidecar/history-routes.d.ts +3 -0
- package/dist/app-sidecar/history-routes.js +375 -0
- package/dist/app-sidecar/history-routes.js.map +1 -0
- package/dist/app-sidecar/history.d.ts +67 -0
- package/dist/app-sidecar/history.js +23 -0
- package/dist/app-sidecar/history.js.map +1 -0
- package/dist/app-sidecar/http.d.ts +5 -0
- package/dist/app-sidecar/http.js +27 -0
- package/dist/app-sidecar/http.js.map +1 -0
- package/dist/app-sidecar/integration-routes.d.ts +3 -0
- package/dist/app-sidecar/integration-routes.js +286 -0
- package/dist/app-sidecar/integration-routes.js.map +1 -0
- package/dist/app-sidecar/json-mode.d.ts +10 -0
- package/dist/app-sidecar/json-mode.js +73 -0
- package/dist/app-sidecar/json-mode.js.map +1 -0
- package/dist/app-sidecar/keep-awake.d.ts +4 -0
- package/dist/app-sidecar/keep-awake.js +5 -0
- package/dist/app-sidecar/keep-awake.js.map +1 -0
- package/dist/app-sidecar/ken-context.d.ts +20 -0
- package/dist/app-sidecar/ken-context.js +55 -0
- package/dist/app-sidecar/ken-context.js.map +1 -0
- package/dist/app-sidecar/mcp-routes.d.ts +3 -0
- package/dist/app-sidecar/mcp-routes.js +185 -0
- package/dist/app-sidecar/mcp-routes.js.map +1 -0
- package/dist/app-sidecar/mcp-rows.d.ts +31 -0
- package/dist/app-sidecar/mcp-rows.js +77 -0
- package/dist/app-sidecar/mcp-rows.js.map +1 -0
- package/dist/app-sidecar/progress-manager.d.ts +10 -0
- package/dist/app-sidecar/progress-manager.js +116 -0
- package/dist/app-sidecar/progress-manager.js.map +1 -0
- package/dist/app-sidecar/prompt-routes.d.ts +3 -0
- package/dist/app-sidecar/prompt-routes.js +354 -0
- package/dist/app-sidecar/prompt-routes.js.map +1 -0
- package/dist/app-sidecar/route-context.d.ts +145 -0
- package/dist/app-sidecar/route-context.js +2 -0
- package/dist/app-sidecar/route-context.js.map +1 -0
- package/dist/app-sidecar/run-control-routes.d.ts +3 -0
- package/dist/app-sidecar/run-control-routes.js +430 -0
- package/dist/app-sidecar/run-control-routes.js.map +1 -0
- package/dist/app-sidecar/session-routes.d.ts +3 -0
- package/dist/app-sidecar/session-routes.js +115 -0
- package/dist/app-sidecar/session-routes.js.map +1 -0
- package/dist/app-sidecar/session-types.d.ts +39 -0
- package/dist/app-sidecar/session-types.js +5 -0
- package/dist/app-sidecar/session-types.js.map +1 -0
- package/dist/app-sidecar/task-routes.d.ts +3 -0
- package/dist/app-sidecar/task-routes.js +149 -0
- package/dist/app-sidecar/task-routes.js.map +1 -0
- package/dist/app-sidecar/usage.d.ts +19 -0
- package/dist/app-sidecar/usage.js +153 -0
- package/dist/app-sidecar/usage.js.map +1 -0
- package/dist/app-sidecar/workspace-routes.d.ts +3 -0
- package/dist/app-sidecar/workspace-routes.js +244 -0
- package/dist/app-sidecar/workspace-routes.js.map +1 -0
- package/dist/app-sidecar.js +482 -3695
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/core/acceptance-checks.js +3 -9
- package/dist/core/acceptance-checks.js.map +1 -1
- package/dist/core/agent-session/helpers.d.ts +26 -0
- package/dist/core/agent-session/helpers.js +47 -0
- package/dist/core/agent-session/helpers.js.map +1 -0
- package/dist/core/agent-session/mcp-tools.d.ts +68 -0
- package/dist/core/agent-session/mcp-tools.js +195 -0
- package/dist/core/agent-session/mcp-tools.js.map +1 -0
- package/dist/core/agent-session/run-loop-monitor.d.ts +63 -0
- package/dist/core/agent-session/run-loop-monitor.js +164 -0
- package/dist/core/agent-session/run-loop-monitor.js.map +1 -0
- package/dist/core/agent-session/transcript-markers.d.ts +57 -0
- package/dist/core/agent-session/transcript-markers.js +166 -0
- package/dist/core/agent-session/transcript-markers.js.map +1 -0
- package/dist/core/agent-session/verification-tracker.d.ts +46 -0
- package/dist/core/agent-session/verification-tracker.js +246 -0
- package/dist/core/agent-session/verification-tracker.js.map +1 -0
- package/dist/core/agent-session.d.ts +27 -87
- package/dist/core/agent-session.js +166 -709
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-providers.js +3 -3
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/autopilot-cycle.d.ts +6 -2
- package/dist/core/autopilot-cycle.js +1 -1
- package/dist/core/autopilot-cycle.js.map +1 -1
- package/dist/core/bundled-agents.js +6 -6
- package/dist/core/bundled-agents.js.map +1 -1
- package/dist/core/checklist-git.d.ts +19 -0
- package/dist/core/checklist-git.js +54 -0
- package/dist/core/checklist-git.js.map +1 -0
- package/dist/core/checklist-items.d.ts +10 -1
- package/dist/core/checklist-items.js +22 -0
- package/dist/core/checklist-items.js.map +1 -1
- package/dist/core/checklist-prompt.d.ts +5 -1
- package/dist/core/checklist-prompt.js +16 -5
- package/dist/core/checklist-prompt.js.map +1 -1
- package/dist/core/checklist-snapshot.d.ts +5 -1
- package/dist/core/checklist-snapshot.js +19 -2
- package/dist/core/checklist-snapshot.js.map +1 -1
- package/dist/core/context-limits.js +1 -1
- package/dist/core/context-limits.js.map +1 -1
- package/dist/core/plan-handoff.d.ts +30 -0
- package/dist/core/plan-handoff.js +10 -0
- package/dist/core/plan-handoff.js.map +1 -0
- package/dist/core/plan-submission-gate.d.ts +28 -0
- package/dist/core/plan-submission-gate.js +27 -0
- package/dist/core/plan-submission-gate.js.map +1 -0
- package/dist/core/skills.js +6 -9
- package/dist/core/skills.js.map +1 -1
- package/dist/core/style-packs/index.js +2 -11
- package/dist/core/style-packs/index.js.map +1 -1
- package/dist/core/style-packs/packs.d.ts +3 -12
- package/dist/core/style-packs/packs.js +132 -173
- package/dist/core/style-packs/packs.js.map +1 -1
- package/dist/system-prompt.js +55 -78
- package/dist/system-prompt.js.map +1 -1
- package/dist/tools/ask-user.js +13 -74
- package/dist/tools/ask-user.js.map +1 -1
- package/dist/tools/bash.js +13 -78
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/checklist.d.ts +2 -10
- package/dist/tools/checklist.js +7 -39
- package/dist/tools/checklist.js.map +1 -1
- package/dist/tools/code-nav.js +7 -29
- package/dist/tools/code-nav.js.map +1 -1
- package/dist/tools/edit.d.ts +3 -9
- package/dist/tools/edit.js +66 -65
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/enter-plan.js +2 -7
- package/dist/tools/enter-plan.js.map +1 -1
- package/dist/tools/exit-plan.js +2 -3
- package/dist/tools/exit-plan.js.map +1 -1
- package/dist/tools/find.js +3 -4
- package/dist/tools/find.js.map +1 -1
- package/dist/tools/grep.js +6 -18
- package/dist/tools/grep.js.map +1 -1
- package/dist/tools/ls.js +3 -3
- package/dist/tools/ls.js.map +1 -1
- package/dist/tools/prompt-hints.js +34 -47
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/read.js +8 -20
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/search-code.js +4 -12
- package/dist/tools/search-code.js.map +1 -1
- package/dist/tools/skill.js +13 -7
- package/dist/tools/skill.js.map +1 -1
- package/dist/tools/subagent-control.js +7 -22
- package/dist/tools/subagent-control.js.map +1 -1
- package/dist/tools/subagent.js +4 -7
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/task-output.js +4 -15
- package/dist/tools/task-output.js.map +1 -1
- package/dist/tools/task-send.js +5 -17
- package/dist/tools/task-send.js.map +1 -1
- package/dist/tools/task-stop.js +2 -2
- package/dist/tools/task-stop.js.map +1 -1
- package/dist/tools/tool-search.js +2 -7
- package/dist/tools/tool-search.js.map +1 -1
- package/dist/tools/tool-tiers.d.ts +17 -4
- package/dist/tools/tool-tiers.js +38 -15
- package/dist/tools/tool-tiers.js.map +1 -1
- package/dist/tools/web-fetch.js +7 -33
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tools/write.js +3 -4
- package/dist/tools/write.js.map +1 -1
- package/dist/ui/components/Footer.js +1 -2
- package/dist/ui/components/Footer.js.map +1 -1
- package/package.json +7 -4
- package/dist/core/api-benchmark.d.ts +0 -63
- package/dist/core/api-benchmark.js +0 -381
- package/dist/core/api-benchmark.js.map +0 -1
- package/dist/core/bash-spawn-benchmark.d.ts +0 -1
- package/dist/core/bash-spawn-benchmark.js +0 -139
- package/dist/core/bash-spawn-benchmark.js.map +0 -1
- package/dist/core/cache-warm-benchmark.d.ts +0 -21
- package/dist/core/cache-warm-benchmark.js +0 -170
- package/dist/core/cache-warm-benchmark.js.map +0 -1
- package/dist/core/fast-apply-benchmark.d.ts +0 -25
- package/dist/core/fast-apply-benchmark.js +0 -284
- package/dist/core/fast-apply-benchmark.js.map +0 -1
- package/dist/core/hashline-edit-benchmark.d.ts +0 -88
- package/dist/core/hashline-edit-benchmark.js +0 -518
- package/dist/core/hashline-edit-benchmark.js.map +0 -1
- package/dist/core/semantic-search-benchmark.d.ts +0 -36
- package/dist/core/semantic-search-benchmark.js +0 -211
- package/dist/core/semantic-search-benchmark.js.map +0 -1
- package/dist/core/speed-benchmark.d.ts +0 -132
- package/dist/core/speed-benchmark.js +0 -410
- 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;
|