@kenkaiiii/ggcoder 5.79.3 → 5.80.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/dist/app-sidecar/goal-routes.d.ts +2 -22
- package/dist/app-sidecar/goal-routes.js +6 -91
- package/dist/app-sidecar/goal-routes.js.map +1 -1
- package/dist/app-sidecar.js +3 -3
- package/dist/app-sidecar.js.map +1 -1
- package/dist/core/goal-summary.d.ts +32 -0
- package/dist/core/goal-summary.js +104 -0
- package/dist/core/goal-summary.js.map +1 -0
- package/dist/core/plan-handoff.d.ts +8 -0
- package/dist/core/plan-handoff.js +11 -0
- package/dist/core/plan-handoff.js.map +1 -1
- package/dist/modes/acp-autopilot.d.ts +27 -0
- package/dist/modes/acp-autopilot.js +54 -0
- package/dist/modes/acp-autopilot.js.map +1 -0
- package/dist/modes/acp-goals.d.ts +48 -0
- package/dist/modes/acp-goals.js +103 -0
- package/dist/modes/acp-goals.js.map +1 -0
- package/dist/modes/acp-mode.d.ts +128 -3
- package/dist/modes/acp-mode.js +1082 -52
- package/dist/modes/acp-mode.js.map +1 -1
- package/dist/tools/grep-scan.d.ts +96 -0
- package/dist/tools/grep-scan.js +283 -0
- package/dist/tools/grep-scan.js.map +1 -0
- package/dist/tools/grep.d.ts +10 -0
- package/dist/tools/grep.js +418 -10
- package/dist/tools/grep.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Goal list rows, shared by the desktop sidecar (`app-sidecar/goal-routes.ts`)
|
|
3
|
+
* and ACP mode (`modes/acp-goals.ts`), so both surfaces describe a goal the
|
|
4
|
+
* same way.
|
|
5
|
+
*/
|
|
6
|
+
import { promises as fs } from "node:fs";
|
|
7
|
+
import { goalWasInterrupted } from "./goals-store.js";
|
|
8
|
+
import { formatRelativeTime } from "./project-discovery.js";
|
|
9
|
+
/** The kickoff/resume instruction is runtime-authored and never shown as a user bubble. */
|
|
10
|
+
export const GOAL_RUNTIME_PROVENANCE = {
|
|
11
|
+
source: "runtime",
|
|
12
|
+
kind: "automation",
|
|
13
|
+
visibility: "hidden",
|
|
14
|
+
};
|
|
15
|
+
/** How much of a session file's end is read to find its last message. */
|
|
16
|
+
const TAIL_BYTES = 64 * 1024;
|
|
17
|
+
/**
|
|
18
|
+
* The last few messages of a session file (role and content), read from its
|
|
19
|
+
* end only, never thawing or rewriting it. Empty when it can't be read
|
|
20
|
+
* (archived, gone): the goal then just isn't marked interrupted.
|
|
21
|
+
*/
|
|
22
|
+
async function lastMessages(file) {
|
|
23
|
+
let text;
|
|
24
|
+
try {
|
|
25
|
+
const handle = await fs.open(file, "r");
|
|
26
|
+
try {
|
|
27
|
+
const { size } = await handle.stat();
|
|
28
|
+
const start = Math.max(0, size - TAIL_BYTES);
|
|
29
|
+
const buf = Buffer.alloc(size - start);
|
|
30
|
+
await handle.read(buf, 0, buf.length, start);
|
|
31
|
+
text = buf.toString("utf-8");
|
|
32
|
+
}
|
|
33
|
+
finally {
|
|
34
|
+
await handle.close();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const out = [];
|
|
41
|
+
for (const line of text.split("\n")) {
|
|
42
|
+
if (!line.startsWith("{"))
|
|
43
|
+
continue;
|
|
44
|
+
try {
|
|
45
|
+
const entry = JSON.parse(line);
|
|
46
|
+
if (entry.type === "message" && entry.message?.role) {
|
|
47
|
+
out.push({ role: entry.message.role, content: entry.message.content });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// A line cut at the start of the read window.
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
/** A goal's status for the list (see GoalSummary.status). */
|
|
57
|
+
export function goalListStatus(record, busy, cutOff = false) {
|
|
58
|
+
if (record.pausedAt)
|
|
59
|
+
return "paused";
|
|
60
|
+
if (busy)
|
|
61
|
+
return "running";
|
|
62
|
+
if (cutOff)
|
|
63
|
+
return "interrupted";
|
|
64
|
+
return record.startedAt ? "idle" : "briefing";
|
|
65
|
+
}
|
|
66
|
+
/** Summarize one goal for a list, from its record and its coordinator sessions. */
|
|
67
|
+
export async function summarizeGoal(sessions, dir, record, busy = false) {
|
|
68
|
+
const list = await sessions.list(dir).catch(() => []);
|
|
69
|
+
const withMessages = list.filter((s) => s.messageCount > 0);
|
|
70
|
+
let lastActiveMs = Date.parse(record.createdAt) || 0;
|
|
71
|
+
let latestSessionPath = null;
|
|
72
|
+
let latestSessionId = null;
|
|
73
|
+
let latestMs = -1;
|
|
74
|
+
for (const s of withMessages) {
|
|
75
|
+
const ms = Date.parse(s.lastActivity) || 0;
|
|
76
|
+
if (ms > latestMs) {
|
|
77
|
+
latestMs = ms;
|
|
78
|
+
latestSessionPath = s.path;
|
|
79
|
+
latestSessionId = s.id;
|
|
80
|
+
}
|
|
81
|
+
if (ms > lastActiveMs)
|
|
82
|
+
lastActiveMs = ms;
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
id: record.id,
|
|
86
|
+
name: record.name,
|
|
87
|
+
goal: record.goal,
|
|
88
|
+
context: record.context,
|
|
89
|
+
path: dir,
|
|
90
|
+
createdAt: record.createdAt,
|
|
91
|
+
lastActiveMs,
|
|
92
|
+
lastActiveDisplay: formatRelativeTime(lastActiveMs),
|
|
93
|
+
latestSessionPath,
|
|
94
|
+
latestSessionId,
|
|
95
|
+
status: goalListStatus(record, busy,
|
|
96
|
+
// Not working, but its last turn never finished: the app closed, or it
|
|
97
|
+
// was stopped, mid-work. Workers aren't known here, only the session.
|
|
98
|
+
!busy &&
|
|
99
|
+
Boolean(record.startedAt) &&
|
|
100
|
+
latestSessionPath !== null &&
|
|
101
|
+
goalWasInterrupted(record, await lastMessages(latestSessionPath), [])),
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=goal-summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-summary.js","sourceRoot":"","sources":["../../src/core/goal-summary.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,3 +28,11 @@ export interface PendingPlanOfferInput {
|
|
|
28
28
|
queued: number;
|
|
29
29
|
}
|
|
30
30
|
export declare function shouldOfferPendingPlan(input: Readonly<PendingPlanOfferInput>): boolean;
|
|
31
|
+
/** The tool result exit_plan returns while a submitted plan awaits review. */
|
|
32
|
+
export declare const PLAN_SUBMITTED_FOR_REVIEW = "Plan submitted for user review. Wait for the user to approve, reject, or dismiss it before implementing.";
|
|
33
|
+
/** The prompt run in the fresh session after a plan is accepted — the SAME
|
|
34
|
+
* string gg-app's PlanReviewModal sends on a manual Accept (App.tsx). */
|
|
35
|
+
export declare const IMPLEMENT_PLAN_PROMPT = "The plan has been approved. Implement it now, following each step in order.";
|
|
36
|
+
/** The revision prompt for the user's plan feedback (gg-app App.tsx
|
|
37
|
+
* sendPlanFeedback wording). */
|
|
38
|
+
export declare function buildUserPlanFeedbackPrompt(feedback: string): string;
|
|
@@ -7,4 +7,15 @@ export function shouldOfferPendingPlan(input) {
|
|
|
7
7
|
return false;
|
|
8
8
|
return input.queued === 0;
|
|
9
9
|
}
|
|
10
|
+
/** The tool result exit_plan returns while a submitted plan awaits review. */
|
|
11
|
+
export const PLAN_SUBMITTED_FOR_REVIEW = "Plan submitted for user review. Wait for the user to approve, reject, or dismiss it before implementing.";
|
|
12
|
+
/** The prompt run in the fresh session after a plan is accepted — the SAME
|
|
13
|
+
* string gg-app's PlanReviewModal sends on a manual Accept (App.tsx). */
|
|
14
|
+
export const IMPLEMENT_PLAN_PROMPT = "The plan has been approved. Implement it now, following each step in order.";
|
|
15
|
+
/** The revision prompt for the user's plan feedback (gg-app App.tsx
|
|
16
|
+
* sendPlanFeedback wording). */
|
|
17
|
+
export function buildUserPlanFeedbackPrompt(feedback) {
|
|
18
|
+
return (`The plan was not approved. Feedback from the user:\n\n${feedback}\n\n` +
|
|
19
|
+
"Revise the plan based on this feedback, then call exit_plan again for review.");
|
|
20
|
+
}
|
|
10
21
|
//# sourceMappingURL=plan-handoff.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plan-handoff.js","sourceRoot":"","sources":["../../src/core/plan-handoff.ts"],"names":[],"mappings":"AA8BA,MAAM,UAAU,sBAAsB,CAAC,KAAsC;IAC3E,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,KAAK,CAAC,UAAU,KAAK,KAAK,CAAC,iBAAiB;QAAE,OAAO,KAAK,CAAC;IAC/D,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,eAAe;QAAE,OAAO,KAAK,CAAC;IAC3E,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;AAC5B,CAAC"}
|
|
1
|
+
{"version":3,"file":"plan-handoff.js","sourceRoot":"","sources":["../../src/core/plan-handoff.ts"],"names":[],"mappings":"AA8BA,MAAM,UAAU,sBAAsB,CAAC,KAAsC;IAC3E,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1C,IAAI,KAAK,CAAC,UAAU,KAAK,KAAK,CAAC,iBAAiB;QAAE,OAAO,KAAK,CAAC;IAC/D,IAAI,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,eAAe;QAAE,OAAO,KAAK,CAAC;IAC3E,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,MAAM,yBAAyB,GACpC,0GAA0G,CAAC;AAE7G;0EAC0E;AAC1E,MAAM,CAAC,MAAM,qBAAqB,GAChC,6EAA6E,CAAC;AAEhF;iCACiC;AACjC,MAAM,UAAU,2BAA2B,CAAC,QAAgB;IAC1D,OAAO,CACL,yDAAyD,QAAQ,MAAM;QACvE,+EAA+E,CAChF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Autopilot Ken for `ggcoder acp`: the reviewer session the autopilot cycle
|
|
3
|
+
* prompts. Built like the desktop's `ensureKenAutoSession` (app-sidecar.ts):
|
|
4
|
+
* Ken's autopilot system prompt, Ken's read-only tool set, a transient
|
|
5
|
+
* session, long cache retention, and the project's Ken model pin when one is
|
|
6
|
+
* valid (otherwise Ken follows GG Coder's model, as on the desktop).
|
|
7
|
+
*/
|
|
8
|
+
import type { Provider } from "@kenkaiiii/gg-ai";
|
|
9
|
+
/** The reviewer the ACP autopilot cycle talks to. A seam so tests can script Ken. */
|
|
10
|
+
export interface AcpKenReviewer {
|
|
11
|
+
/** Wipe review history (start of each cycle). */
|
|
12
|
+
reset(): Promise<void>;
|
|
13
|
+
/** Prompt Ken with a digest; resolves to his final reply text. */
|
|
14
|
+
review(digest: string): Promise<string>;
|
|
15
|
+
/** Stop an in-flight review (session/cancel, queued message). */
|
|
16
|
+
abort(): void;
|
|
17
|
+
dispose(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export interface AcpKenReviewerOptions {
|
|
20
|
+
cwd: string;
|
|
21
|
+
/** GG Coder's current model; Ken follows it unless the project pins his own. */
|
|
22
|
+
buildModel: () => {
|
|
23
|
+
provider: Provider;
|
|
24
|
+
model: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export declare function createAcpKenReviewer(options: AcpKenReviewerOptions): AcpKenReviewer;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getModel } from "@kenkaiiii/gg-core";
|
|
2
|
+
import { AgentSession } from "../core/agent-session.js";
|
|
3
|
+
import { buildKenAutopilotSystemPrompt } from "../core/ken-prompt.js";
|
|
4
|
+
import { validateKenModelPref } from "../core/ken-model.js";
|
|
5
|
+
import { KEN_ALLOWED_TOOLS, lastAssistantText } from "../app-sidecar/ken-context.js";
|
|
6
|
+
import { loadKenModelPref } from "../app-sidecar/app-settings.js";
|
|
7
|
+
export function createAcpKenReviewer(options) {
|
|
8
|
+
let abort = new AbortController();
|
|
9
|
+
let ken = null;
|
|
10
|
+
async function ensure() {
|
|
11
|
+
if (ken)
|
|
12
|
+
return ken;
|
|
13
|
+
const pinned = validateKenModelPref(await loadKenModelPref(options.cwd), {
|
|
14
|
+
modelExists: (id) => getModel(id) !== undefined,
|
|
15
|
+
providerConnected: () => true,
|
|
16
|
+
});
|
|
17
|
+
const target = pinned ?? options.buildModel();
|
|
18
|
+
const created = new AgentSession({
|
|
19
|
+
provider: target.provider,
|
|
20
|
+
model: target.model,
|
|
21
|
+
cwd: options.cwd,
|
|
22
|
+
systemPrompt: await buildKenAutopilotSystemPrompt(options.cwd),
|
|
23
|
+
allowedTools: KEN_ALLOWED_TOOLS,
|
|
24
|
+
transient: true,
|
|
25
|
+
signal: abort.signal,
|
|
26
|
+
forceLongCacheRetention: true,
|
|
27
|
+
});
|
|
28
|
+
await created.initialize();
|
|
29
|
+
ken = created;
|
|
30
|
+
return created;
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
async reset() {
|
|
34
|
+
await ken?.newSession().catch(() => undefined);
|
|
35
|
+
},
|
|
36
|
+
async review(digest) {
|
|
37
|
+
const session = await ensure();
|
|
38
|
+
await session.prompt(digest);
|
|
39
|
+
return lastAssistantText(session.getMessages());
|
|
40
|
+
},
|
|
41
|
+
abort() {
|
|
42
|
+
abort.abort();
|
|
43
|
+
abort = new AbortController();
|
|
44
|
+
ken?.setSignal(abort.signal);
|
|
45
|
+
},
|
|
46
|
+
async dispose() {
|
|
47
|
+
abort.abort();
|
|
48
|
+
const current = ken;
|
|
49
|
+
ken = null;
|
|
50
|
+
await current?.dispose();
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=acp-autopilot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acp-autopilot.js","sourceRoot":"","sources":["../../src/modes/acp-autopilot.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,6BAA6B,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AACrF,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAmBlE,MAAM,UAAU,oBAAoB,CAAC,OAA8B;IACjE,IAAI,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IAClC,IAAI,GAAG,GAAwB,IAAI,CAAC;IAEpC,KAAK,UAAU,MAAM;QACnB,IAAI,GAAG;YAAE,OAAO,GAAG,CAAC;QACpB,MAAM,MAAM,GAAG,oBAAoB,CAAC,MAAM,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YACvE,WAAW,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,SAAS;YAC/C,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI;SAC9B,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QAC9C,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC;YAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,YAAY,EAAE,MAAM,6BAA6B,CAAC,OAAO,CAAC,GAAG,CAAC;YAC9D,YAAY,EAAE,iBAAiB;YAC/B,SAAS,EAAE,IAAI;YACf,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,uBAAuB,EAAE,IAAI;SAC9B,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;QAC3B,GAAG,GAAG,OAAO,CAAC;QACd,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,KAAK,CAAC,KAAK;YACT,MAAM,GAAG,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACjD,CAAC;QACD,KAAK,CAAC,MAAM,CAAC,MAAM;YACjB,MAAM,OAAO,GAAG,MAAM,MAAM,EAAE,CAAC;YAC/B,MAAM,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7B,OAAO,iBAAiB,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;QAClD,CAAC;QACD,KAAK;YACH,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;YAC9B,GAAG,EAAE,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAC/B,CAAC;QACD,KAAK,CAAC,OAAO;YACX,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,GAAG,CAAC;YACpB,GAAG,GAAG,IAAI,CAAC;YACX,MAAM,OAAO,EAAE,OAAO,EAAE,CAAC;QAC3B,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type GoalRecord, type GoalResult } from "../core/goals-store.js";
|
|
2
|
+
import type { SubAgentSnapshot } from "../core/subagent-manager.js";
|
|
3
|
+
import type { AppAttachment } from "../app-sidecar/attachments.js";
|
|
4
|
+
/** `_gg/goals/list` row: the sidecar's GoalSummary, addressed by session id. */
|
|
5
|
+
export interface AcpGoalSummary {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
goal: string;
|
|
9
|
+
context: GoalRecord["context"];
|
|
10
|
+
path: string;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
lastActiveMs: number;
|
|
13
|
+
lastActiveDisplay: string;
|
|
14
|
+
/** The id `session/load` / `session/resume` take; null starts a fresh coordinator. */
|
|
15
|
+
agentSessionId: string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Standing instructions, so a client's goal settings can show what is set
|
|
18
|
+
* (absent = none). The desktop app reads them from the record the same way.
|
|
19
|
+
*/
|
|
20
|
+
instructions?: string;
|
|
21
|
+
/** Never `running`: ggcoder computes it without a live run (the client overlays that). */
|
|
22
|
+
status: "briefing" | "paused" | "interrupted" | "idle";
|
|
23
|
+
}
|
|
24
|
+
/** pew2 wire `GoalWorker`. */
|
|
25
|
+
export interface AcpGoalWorker {
|
|
26
|
+
id: string;
|
|
27
|
+
name: string;
|
|
28
|
+
agent?: string;
|
|
29
|
+
state: "starting" | "running" | "completed" | "failed" | "interrupted" | "closed";
|
|
30
|
+
activity?: string;
|
|
31
|
+
startedAt?: number;
|
|
32
|
+
elapsedMs?: number;
|
|
33
|
+
toolUses?: number;
|
|
34
|
+
model?: string;
|
|
35
|
+
error?: string;
|
|
36
|
+
}
|
|
37
|
+
/** Every goal, most recently active first. */
|
|
38
|
+
export declare function listAcpGoals(agentDir: string): Promise<AcpGoalSummary[]>;
|
|
39
|
+
/** Create a goal from `_gg/goals/create` params; the store's own error text on failure. */
|
|
40
|
+
export declare function createAcpGoal(agentDir: string, params: unknown): Promise<GoalResult<AcpGoalSummary>>;
|
|
41
|
+
/** The worker roster for `_gg/goal_state`. A reaped worker reads as closed. */
|
|
42
|
+
export declare function goalWorkers(snapshots: readonly SubAgentSnapshot[]): AcpGoalWorker[];
|
|
43
|
+
/**
|
|
44
|
+
* ACP `image` prompt blocks as the app's attachment shape, so they take the
|
|
45
|
+
* same `prepareAttachments` → `promptWithAttachments` path the desktop does.
|
|
46
|
+
* Blocks carrying only a `uri` (no inline data) are skipped.
|
|
47
|
+
*/
|
|
48
|
+
export declare function acpImageAttachments(blocks: unknown): AppAttachment[];
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GG Goals over ACP (`_gg/goals/*`, `_gg/goal/*`, `_gg/goal_state`): the pure
|
|
3
|
+
* pieces, kept out of `acp-mode.ts` so the transport stays readable. The goal
|
|
4
|
+
* list rows come from the same `summarizeGoal` the desktop sidecar uses.
|
|
5
|
+
*/
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { createGoal, goalsRoot, listGoals, } from "../core/goals-store.js";
|
|
8
|
+
import { summarizeGoal } from "../core/goal-summary.js";
|
|
9
|
+
import { SessionManager } from "../core/session-manager.js";
|
|
10
|
+
function toAcpSummary(summary, instructions) {
|
|
11
|
+
return {
|
|
12
|
+
...(instructions ? { instructions } : {}),
|
|
13
|
+
id: summary.id,
|
|
14
|
+
name: summary.name,
|
|
15
|
+
goal: summary.goal,
|
|
16
|
+
context: summary.context,
|
|
17
|
+
path: summary.path,
|
|
18
|
+
createdAt: summary.createdAt,
|
|
19
|
+
lastActiveMs: summary.lastActiveMs,
|
|
20
|
+
lastActiveDisplay: summary.lastActiveDisplay,
|
|
21
|
+
agentSessionId: summary.latestSessionId,
|
|
22
|
+
// summarizeGoal is never told the goal is busy, so `running` cannot occur.
|
|
23
|
+
status: summary.status === "running" ? "idle" : summary.status,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function sessionsDir(agentDir) {
|
|
27
|
+
return path.join(agentDir, "sessions");
|
|
28
|
+
}
|
|
29
|
+
/** Every goal, most recently active first. */
|
|
30
|
+
export async function listAcpGoals(agentDir) {
|
|
31
|
+
const sessions = new SessionManager(sessionsDir(agentDir));
|
|
32
|
+
const goals = await listGoals(goalsRoot(agentDir));
|
|
33
|
+
const rows = await Promise.all(goals.map(async (g) => toAcpSummary(await summarizeGoal(sessions, g.dir, g.record), g.record.instructions)));
|
|
34
|
+
rows.sort((a, b) => b.lastActiveMs - a.lastActiveMs || a.id.localeCompare(b.id));
|
|
35
|
+
return rows;
|
|
36
|
+
}
|
|
37
|
+
/** Create a goal from `_gg/goals/create` params; the store's own error text on failure. */
|
|
38
|
+
export async function createAcpGoal(agentDir, params) {
|
|
39
|
+
const input = params && typeof params === "object"
|
|
40
|
+
? params
|
|
41
|
+
: {};
|
|
42
|
+
const created = await createGoal(goalsRoot(agentDir), {
|
|
43
|
+
name: typeof input.name === "string" ? input.name : "",
|
|
44
|
+
goal: typeof input.goal === "string" ? input.goal : "",
|
|
45
|
+
context: Array.isArray(input.context)
|
|
46
|
+
? input.context.filter((p) => typeof p === "string")
|
|
47
|
+
: [],
|
|
48
|
+
...(typeof input.instructions === "string" ? { instructions: input.instructions } : {}),
|
|
49
|
+
}, new Date());
|
|
50
|
+
if (!created.ok)
|
|
51
|
+
return created;
|
|
52
|
+
const sessions = new SessionManager(sessionsDir(agentDir));
|
|
53
|
+
return {
|
|
54
|
+
ok: true,
|
|
55
|
+
value: toAcpSummary(await summarizeGoal(sessions, created.value.dir, created.value.record), created.value.record.instructions),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** The worker roster for `_gg/goal_state`. A reaped worker reads as closed. */
|
|
59
|
+
export function goalWorkers(snapshots) {
|
|
60
|
+
return snapshots.map((s) => ({
|
|
61
|
+
id: s.agent_id,
|
|
62
|
+
name: s.task_name,
|
|
63
|
+
...(s.agent_name ? { agent: s.agent_name } : {}),
|
|
64
|
+
state: s.state === "reaped" ? "closed" : s.state,
|
|
65
|
+
...(s.current_activity ? { activity: s.current_activity } : {}),
|
|
66
|
+
startedAt: s.started_at,
|
|
67
|
+
elapsedMs: s.elapsed_ms,
|
|
68
|
+
toolUses: s.tool_use_count,
|
|
69
|
+
...(s.model ? { model: s.model } : {}),
|
|
70
|
+
...(s.error ? { error: s.error } : {}),
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
const IMAGE_EXTENSIONS = {
|
|
74
|
+
"image/png": "png",
|
|
75
|
+
"image/jpeg": "jpg",
|
|
76
|
+
"image/gif": "gif",
|
|
77
|
+
"image/webp": "webp",
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* ACP `image` prompt blocks as the app's attachment shape, so they take the
|
|
81
|
+
* same `prepareAttachments` → `promptWithAttachments` path the desktop does.
|
|
82
|
+
* Blocks carrying only a `uri` (no inline data) are skipped.
|
|
83
|
+
*/
|
|
84
|
+
export function acpImageAttachments(blocks) {
|
|
85
|
+
if (!Array.isArray(blocks))
|
|
86
|
+
return [];
|
|
87
|
+
const out = [];
|
|
88
|
+
for (const block of blocks) {
|
|
89
|
+
const entry = block;
|
|
90
|
+
if (entry?.type !== "image" || typeof entry.data !== "string" || !entry.data)
|
|
91
|
+
continue;
|
|
92
|
+
const mediaType = typeof entry.mimeType === "string" ? entry.mimeType : "image/png";
|
|
93
|
+
const ext = IMAGE_EXTENSIONS[mediaType] ?? "img";
|
|
94
|
+
out.push({
|
|
95
|
+
kind: "image",
|
|
96
|
+
name: `image-${out.length + 1}.${ext}`,
|
|
97
|
+
mediaType,
|
|
98
|
+
data: entry.data,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=acp-goals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acp-goals.js","sourceRoot":"","sources":["../../src/modes/acp-goals.ts"],"names":[],"mappings":"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"}
|
package/dist/modes/acp-mode.d.ts
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
import type { Message, Provider, ThinkingLevel } from "@kenkaiiii/gg-ai";
|
|
1
|
+
import type { Message, MessageProvenance, Provider, ThinkingLevel } from "@kenkaiiii/gg-ai";
|
|
2
2
|
import { type ToolExecuteResult } from "@kenkaiiii/gg-agent";
|
|
3
|
+
import { AgentSession, type SessionAttachment } from "../core/agent-session.js";
|
|
4
|
+
import type { ChildModelPick, SubAgentSnapshot } from "../core/subagent-manager.js";
|
|
5
|
+
import { createAskUserTool } from "../tools/ask-user.js";
|
|
6
|
+
import { type GoalBriefExtras, type GoalRecord } from "../core/goals-store.js";
|
|
3
7
|
import type { EventBus } from "../core/event-bus.js";
|
|
8
|
+
import type { AutopilotMarkerPayload } from "../core/session-manager.js";
|
|
9
|
+
import { type AcpKenReviewer } from "./acp-autopilot.js";
|
|
4
10
|
/** The ACP major version this mode implements. Bumped only for breaking changes. */
|
|
5
11
|
export declare const ACP_PROTOCOL_VERSION = 1;
|
|
6
12
|
/**
|
|
@@ -13,7 +19,32 @@ export declare const ACP_PROTOCOL_VERSION = 1;
|
|
|
13
19
|
export interface AcpAgentSession {
|
|
14
20
|
readonly eventBus: Pick<EventBus, "on">;
|
|
15
21
|
initialize(): Promise<void>;
|
|
16
|
-
|
|
22
|
+
/** `provenance` marks GG Goals' hidden kickoff/resume instructions. */
|
|
23
|
+
prompt(content: string, provenance?: MessageProvenance): Promise<void>;
|
|
24
|
+
/** Image prompts (`promptCapabilities.image`); without it images are ignored. */
|
|
25
|
+
promptWithAttachments?(text: string, attachments: SessionAttachment[]): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Mid-run steering (`_gg/queue`). Optional so a test double or alternative
|
|
28
|
+
* session need not support it; `_gg/queue` then answers -32602.
|
|
29
|
+
*/
|
|
30
|
+
queueMessage?(text: string): number;
|
|
31
|
+
listQueuedMessages?(): Array<{
|
|
32
|
+
id: string;
|
|
33
|
+
text: string;
|
|
34
|
+
}>;
|
|
35
|
+
cancelQueuedMessage?(id: string): boolean;
|
|
36
|
+
drainQueue?(): string;
|
|
37
|
+
/** GG Goals' workers, for `_gg/goal_state`. */
|
|
38
|
+
listSubAgents?(): SubAgentSnapshot[];
|
|
39
|
+
/** Adds a goal's attached folder to the workspace. */
|
|
40
|
+
addDirectory?(dir: string): Promise<{
|
|
41
|
+
ok: true;
|
|
42
|
+
} | {
|
|
43
|
+
ok: false;
|
|
44
|
+
error: string;
|
|
45
|
+
}>;
|
|
46
|
+
/** Tell the agent a fact at its next turn (goal settings changed). */
|
|
47
|
+
notify?(id: string, text: string): void;
|
|
17
48
|
getState(): {
|
|
18
49
|
sessionId: string;
|
|
19
50
|
provider: Provider;
|
|
@@ -34,6 +65,16 @@ export interface AcpAgentSession {
|
|
|
34
65
|
setSignal(signal: AbortSignal): void;
|
|
35
66
|
/** Replay a session file from disk into this session. */
|
|
36
67
|
loadSession(sessionPath: string): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Ken's verdict markers (desktop `persistAutopilotMarker`). Optional so a
|
|
70
|
+
* test double need not persist; without them a reopened session has no
|
|
71
|
+
* Ken bubbles.
|
|
72
|
+
*/
|
|
73
|
+
persistAutopilotMarker?(phase: AutopilotMarkerPayload["phase"], extra?: {
|
|
74
|
+
reason?: string;
|
|
75
|
+
body?: string;
|
|
76
|
+
}): Promise<void>;
|
|
77
|
+
getAutopilotMarkers?(): AutopilotMarkerPayload[];
|
|
37
78
|
/** The conversation as restored, used to replay history to the client. */
|
|
38
79
|
getMessages(): Message[];
|
|
39
80
|
switchModel(provider: string, model: string): Promise<void>;
|
|
@@ -44,6 +85,12 @@ export interface AcpAgentSession {
|
|
|
44
85
|
setPlanMode(active: boolean): Promise<void>;
|
|
45
86
|
/** Bake an approved plan into the prompt so [DONE:n] progress markers work. */
|
|
46
87
|
setApprovedPlan(planPath: string | undefined): Promise<void>;
|
|
88
|
+
/** Host verification evidence for Ken's digest; optional for test doubles. */
|
|
89
|
+
getVerificationEvidence?(): AgentSession["getVerificationEvidence"] extends () => infer R ? R : never;
|
|
90
|
+
getVerificationProblem?(): string | null;
|
|
91
|
+
/** Fresh context for an accepted plan (desktop /plan/accept). Optional:
|
|
92
|
+
* without it an accept keeps the current context and sends no reset. */
|
|
93
|
+
newSession?(preserveConversation?: boolean): Promise<void>;
|
|
47
94
|
/**
|
|
48
95
|
* Registry commands (/model, /compact, …), including any an extension
|
|
49
96
|
* registered during `initialize`. Optional so a test double need not carry a
|
|
@@ -71,6 +118,52 @@ export interface AcpPlanHooks {
|
|
|
71
118
|
/** Returns the instruction handed back to the model after approval. */
|
|
72
119
|
onExitPlan: (planPath: string) => Promise<ToolExecuteResult>;
|
|
73
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* What a session is being built for, beyond the plan hooks.
|
|
123
|
+
*
|
|
124
|
+
* A third argument rather than a change to the first two so existing session
|
|
125
|
+
* factories (tests) keep working unchanged.
|
|
126
|
+
*/
|
|
127
|
+
export interface AcpSessionContext {
|
|
128
|
+
/** The session's working directory: the goal folder for a goal session. */
|
|
129
|
+
cwd: string;
|
|
130
|
+
/** Set when the cwd is a goal folder: build a GG Goals coordinator. */
|
|
131
|
+
goal: {
|
|
132
|
+
dir: string;
|
|
133
|
+
record: GoalRecord;
|
|
134
|
+
} | null;
|
|
135
|
+
/** The goal's brief extras (memory, attached projects' rules), read once. */
|
|
136
|
+
goalExtras?: GoalBriefExtras;
|
|
137
|
+
/** Read live: true once the user has started the goal. */
|
|
138
|
+
isGoalActive: () => boolean;
|
|
139
|
+
/** Read live at each worker spawn. */
|
|
140
|
+
getChildModel: () => ChildModelPick | undefined;
|
|
141
|
+
/**
|
|
142
|
+
* The `ask_user` tool, present only when the client opted in with
|
|
143
|
+
* `clientCapabilities._meta.gg.askUser`. Goes in `additionalTools` at
|
|
144
|
+
* construction (the tool array is append-only for the prompt cache).
|
|
145
|
+
*/
|
|
146
|
+
askUserTool?: ReturnType<typeof createAskUserTool>;
|
|
147
|
+
/**
|
|
148
|
+
* The client reviews plans itself (`clientCapabilities._meta.gg.planReview`):
|
|
149
|
+
* exit_plan parks the plan for a human decision instead of auto-approving,
|
|
150
|
+
* and the session gets the desktop's `planSubmissionGate`.
|
|
151
|
+
*/
|
|
152
|
+
planReview?: boolean;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* A plan submitted via exit_plan that awaits a decision (desktop parity:
|
|
156
|
+
* app-sidecar.ts pendingPlanPath/planGeneration/offeredPlanGeneration). One
|
|
157
|
+
* object so the autopilot cycle can read and settle it.
|
|
158
|
+
*/
|
|
159
|
+
export interface AcpPendingPlanState {
|
|
160
|
+
planPath: string | null;
|
|
161
|
+
content: string;
|
|
162
|
+
/** Bumped on every set/clear; a stale decision is refused. */
|
|
163
|
+
generation: number;
|
|
164
|
+
/** Generation last offered to the client; -1 when none. */
|
|
165
|
+
offeredGeneration: number;
|
|
166
|
+
}
|
|
74
167
|
export interface AcpModeOptions {
|
|
75
168
|
provider: Provider;
|
|
76
169
|
model: string;
|
|
@@ -86,7 +179,22 @@ export interface AcpModeOptions {
|
|
|
86
179
|
* Builds the session for `session/new`. Overridden by tests; production
|
|
87
180
|
* always gets a real {@link AgentSession}.
|
|
88
181
|
*/
|
|
89
|
-
createSession?: (signal: AbortSignal, hooks: AcpPlanHooks) => AcpAgentSession;
|
|
182
|
+
createSession?: (signal: AbortSignal, hooks: AcpPlanHooks, context: AcpSessionContext) => AcpAgentSession;
|
|
183
|
+
/** `~/.gg` by default; where goals (`goals/`) and sessions live. */
|
|
184
|
+
agentDir?: string;
|
|
185
|
+
/**
|
|
186
|
+
* `ask_user` soft deadline (default: the desktop's interactive 10 min). Past
|
|
187
|
+
* it the model hears "no answer yet" and the client's question stays open.
|
|
188
|
+
*/
|
|
189
|
+
askUserDeadlineMs?: number;
|
|
190
|
+
/**
|
|
191
|
+
* Builds Autopilot Ken's reviewer for a session's project. Overridden by
|
|
192
|
+
* tests; production gets {@link createAcpKenReviewer}.
|
|
193
|
+
*/
|
|
194
|
+
createKenReviewer?: (cwd: string, buildModel: () => {
|
|
195
|
+
provider: Provider;
|
|
196
|
+
model: string;
|
|
197
|
+
}) => AcpKenReviewer;
|
|
90
198
|
}
|
|
91
199
|
/** The selectors this agent exposes. Ids are part of the wire contract. */
|
|
92
200
|
export declare const MODEL_CONFIG_ID = "model";
|
|
@@ -107,6 +215,23 @@ export declare const MODE_CONFIG_ID = "mode";
|
|
|
107
215
|
* the protocol needs of them.
|
|
108
216
|
*/
|
|
109
217
|
export declare function historyUpdates(messages: readonly Message[]): Record<string, unknown>[];
|
|
218
|
+
/** A replayed Ken marker, as `_gg/autopilot_event` params (sans sessionId). */
|
|
219
|
+
export interface HistoryAutopilotEvent {
|
|
220
|
+
phase: string;
|
|
221
|
+
reason?: string;
|
|
222
|
+
body?: string;
|
|
223
|
+
history: true;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* {@link historyUpdates} with Ken's verdict markers interleaved at their
|
|
227
|
+
* `afterMessageCount` (non-system messages, as the desktop history route
|
|
228
|
+
* counts them). Marker phase `plan_approved` replays as ACP `plan_accepted`.
|
|
229
|
+
*/
|
|
230
|
+
export declare function historyFrames(messages: readonly Message[], markers: readonly AutopilotMarkerPayload[]): Array<{
|
|
231
|
+
update: Record<string, unknown>;
|
|
232
|
+
} | {
|
|
233
|
+
autopilot: HistoryAutopilotEvent;
|
|
234
|
+
}>;
|
|
110
235
|
/**
|
|
111
236
|
* Serve ACP on stdio until the input stream ends.
|
|
112
237
|
*
|