@prestyj/cli 5.30.3 → 5.32.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 (59) hide show
  1. package/dist/app-sidecar/goal-routes.d.ts +2 -22
  2. package/dist/app-sidecar/goal-routes.js +12 -93
  3. package/dist/app-sidecar/goal-routes.js.map +1 -1
  4. package/dist/app-sidecar/history-routes.js +1 -2
  5. package/dist/app-sidecar/history-routes.js.map +1 -1
  6. package/dist/app-sidecar/prompt-routes.js +1 -2
  7. package/dist/app-sidecar/prompt-routes.js.map +1 -1
  8. package/dist/app-sidecar/run-control-routes.d.ts +14 -0
  9. package/dist/app-sidecar/run-control-routes.js +61 -22
  10. package/dist/app-sidecar/run-control-routes.js.map +1 -1
  11. package/dist/app-sidecar/session-routes.js +5 -1
  12. package/dist/app-sidecar/session-routes.js.map +1 -1
  13. package/dist/app-sidecar/task-routes.js +22 -0
  14. package/dist/app-sidecar/task-routes.js.map +1 -1
  15. package/dist/app-sidecar.js +6 -7
  16. package/dist/app-sidecar.js.map +1 -1
  17. package/dist/core/agent-session.d.ts +17 -0
  18. package/dist/core/agent-session.js +48 -12
  19. package/dist/core/agent-session.js.map +1 -1
  20. package/dist/core/custom-commands.d.ts +6 -0
  21. package/dist/core/custom-commands.js +17 -0
  22. package/dist/core/custom-commands.js.map +1 -1
  23. package/dist/core/goal-run-marker.d.ts +32 -0
  24. package/dist/core/goal-run-marker.js +178 -0
  25. package/dist/core/goal-run-marker.js.map +1 -0
  26. package/dist/core/goal-summary.d.ts +32 -0
  27. package/dist/core/goal-summary.js +110 -0
  28. package/dist/core/goal-summary.js.map +1 -0
  29. package/dist/core/plan-handoff.d.ts +8 -0
  30. package/dist/core/plan-handoff.js +11 -0
  31. package/dist/core/plan-handoff.js.map +1 -1
  32. package/dist/core/resolve-start.d.ts +2 -0
  33. package/dist/core/resolve-start.js +34 -5
  34. package/dist/core/resolve-start.js.map +1 -1
  35. package/dist/core/subagent-policy.js +4 -1
  36. package/dist/core/subagent-policy.js.map +1 -1
  37. package/dist/goals-agent/goals-agent.js +43 -1
  38. package/dist/goals-agent/goals-agent.js.map +1 -1
  39. package/dist/modes/acp-autopilot.d.ts +27 -0
  40. package/dist/modes/acp-autopilot.js +54 -0
  41. package/dist/modes/acp-autopilot.js.map +1 -0
  42. package/dist/modes/acp-goals.d.ts +52 -0
  43. package/dist/modes/acp-goals.js +102 -0
  44. package/dist/modes/acp-goals.js.map +1 -0
  45. package/dist/modes/acp-mode.d.ts +128 -3
  46. package/dist/modes/acp-mode.js +1086 -52
  47. package/dist/modes/acp-mode.js.map +1 -1
  48. package/dist/tools/grep-scan.d.ts +96 -0
  49. package/dist/tools/grep-scan.js +283 -0
  50. package/dist/tools/grep-scan.js.map +1 -0
  51. package/dist/tools/grep.d.ts +10 -0
  52. package/dist/tools/grep.js +418 -10
  53. package/dist/tools/grep.js.map +1 -1
  54. package/dist/ui/components/Footer.js +4 -0
  55. package/dist/ui/components/Footer.js.map +1 -1
  56. package/dist/utils/git-overview.d.ts +41 -0
  57. package/dist/utils/git-overview.js +146 -0
  58. package/dist/utils/git-overview.js.map +1 -0
  59. package/package.json +4 -4
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Autopilot Nolan for `ezcoder acp`: the reviewer session the autopilot cycle
3
+ * prompts. Built like the desktop's `ensureNolanAutoSession` (app-sidecar.ts):
4
+ * Nolan's autopilot system prompt, Nolan's read-only tool set, a transient
5
+ * session, long cache retention, and the project's Nolan model pin when one is
6
+ * valid (otherwise Nolan follows EZ Coder's model, as on the desktop).
7
+ */
8
+ import type { Provider } from "@prestyj/ai";
9
+ /** The reviewer the ACP autopilot cycle talks to. A seam so tests can script Nolan. */
10
+ export interface AcpNolanReviewer {
11
+ /** Wipe review history (start of each cycle). */
12
+ reset(): Promise<void>;
13
+ /** Prompt Nolan 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 AcpNolanReviewerOptions {
20
+ cwd: string;
21
+ /** EZ Coder's current model; Nolan follows it unless the project pins his own. */
22
+ buildModel: () => {
23
+ provider: Provider;
24
+ model: string;
25
+ };
26
+ }
27
+ export declare function createAcpNolanReviewer(options: AcpNolanReviewerOptions): AcpNolanReviewer;
@@ -0,0 +1,54 @@
1
+ import { getModel } from "@prestyj/core";
2
+ import { AgentSession } from "../core/agent-session.js";
3
+ import { buildNolanAutopilotSystemPrompt } from "../core/nolan-prompt.js";
4
+ import { validateNolanModelPref } from "../core/nolan-model.js";
5
+ import { NOLAN_ALLOWED_TOOLS, lastAssistantText } from "../app-sidecar/nolan-context.js";
6
+ import { loadNolanModelPref } from "../app-sidecar/app-settings.js";
7
+ export function createAcpNolanReviewer(options) {
8
+ let abort = new AbortController();
9
+ let nolan = null;
10
+ async function ensure() {
11
+ if (nolan)
12
+ return nolan;
13
+ const pinned = validateNolanModelPref(await loadNolanModelPref(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 buildNolanAutopilotSystemPrompt(options.cwd),
23
+ allowedTools: NOLAN_ALLOWED_TOOLS,
24
+ transient: true,
25
+ signal: abort.signal,
26
+ forceLongCacheRetention: true,
27
+ });
28
+ await created.initialize();
29
+ nolan = created;
30
+ return created;
31
+ }
32
+ return {
33
+ async reset() {
34
+ await nolan?.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
+ nolan?.setSignal(abort.signal);
45
+ },
46
+ async dispose() {
47
+ abort.abort();
48
+ const current = nolan;
49
+ nolan = 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,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,+BAA+B,EAAE,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,iCAAiC,CAAC;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAmBpE,MAAM,UAAU,sBAAsB,CAAC,OAAgC;IACrE,IAAI,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IAClC,IAAI,KAAK,GAAwB,IAAI,CAAC;IAEtC,KAAK,UAAU,MAAM;QACnB,IAAI,KAAK;YAAE,OAAO,KAAK,CAAC;QACxB,MAAM,MAAM,GAAG,sBAAsB,CAAC,MAAM,kBAAkB,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;YAC3E,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,+BAA+B,CAAC,OAAO,CAAC,GAAG,CAAC;YAChE,YAAY,EAAE,mBAAmB;YACjC,SAAS,EAAE,IAAI;YACf,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,uBAAuB,EAAE,IAAI;SAC9B,CAAC,CAAC;QACH,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;QAC3B,KAAK,GAAG,OAAO,CAAC;QAChB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,KAAK,CAAC,KAAK;YACT,MAAM,KAAK,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QACnD,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,KAAK,EAAE,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;QACD,KAAK,CAAC,OAAO;YACX,KAAK,CAAC,KAAK,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,KAAK,CAAC;YACtB,KAAK,GAAG,IAAI,CAAC;YACb,MAAM,OAAO,EAAE,OAAO,EAAE,CAAC;QAC3B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,52 @@
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
+ /**
22
+ * `running` when some process holds the goal's run marker (this one, the
23
+ * desktop app, another `ezcoder acp`). A client that knows of a live run of
24
+ * its own may still overlay `running` on top.
25
+ */
26
+ status: "briefing" | "running" | "paused" | "interrupted" | "idle";
27
+ }
28
+ /** pew2 wire `GoalWorker`. */
29
+ export interface AcpGoalWorker {
30
+ id: string;
31
+ name: string;
32
+ agent?: string;
33
+ state: "starting" | "running" | "completed" | "failed" | "interrupted" | "closed";
34
+ activity?: string;
35
+ startedAt?: number;
36
+ elapsedMs?: number;
37
+ toolUses?: number;
38
+ model?: string;
39
+ error?: string;
40
+ }
41
+ /** Every goal, most recently active first. */
42
+ export declare function listAcpGoals(agentDir: string): Promise<AcpGoalSummary[]>;
43
+ /** Create a goal from `_gg/goals/create` params; the store's own error text on failure. */
44
+ export declare function createAcpGoal(agentDir: string, params: unknown): Promise<GoalResult<AcpGoalSummary>>;
45
+ /** The worker roster for `_gg/goal_state`. A reaped worker reads as closed. */
46
+ export declare function goalWorkers(snapshots: readonly SubAgentSnapshot[]): AcpGoalWorker[];
47
+ /**
48
+ * ACP `image` prompt blocks as the app's attachment shape, so they take the
49
+ * same `prepareAttachments` → `promptWithAttachments` path the desktop does.
50
+ * Blocks carrying only a `uri` (no inline data) are skipped.
51
+ */
52
+ export declare function acpImageAttachments(blocks: unknown): AppAttachment[];
@@ -0,0 +1,102 @@
1
+ /**
2
+ * EZ 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
+ status: summary.status,
23
+ };
24
+ }
25
+ function sessionsDir(agentDir) {
26
+ return path.join(agentDir, "sessions");
27
+ }
28
+ /** Every goal, most recently active first. */
29
+ export async function listAcpGoals(agentDir) {
30
+ const sessions = new SessionManager(sessionsDir(agentDir));
31
+ const goals = await listGoals(goalsRoot(agentDir));
32
+ const rows = await Promise.all(goals.map(async (g) => toAcpSummary(await summarizeGoal(sessions, g.dir, g.record), g.record.instructions)));
33
+ rows.sort((a, b) => b.lastActiveMs - a.lastActiveMs || a.id.localeCompare(b.id));
34
+ return rows;
35
+ }
36
+ /** Create a goal from `_gg/goals/create` params; the store's own error text on failure. */
37
+ export async function createAcpGoal(agentDir, params) {
38
+ const input = params && typeof params === "object"
39
+ ? params
40
+ : {};
41
+ const created = await createGoal(goalsRoot(agentDir), {
42
+ name: typeof input.name === "string" ? input.name : "",
43
+ goal: typeof input.goal === "string" ? input.goal : "",
44
+ context: Array.isArray(input.context)
45
+ ? input.context.filter((p) => typeof p === "string")
46
+ : [],
47
+ ...(typeof input.instructions === "string" ? { instructions: input.instructions } : {}),
48
+ }, new Date());
49
+ if (!created.ok)
50
+ return created;
51
+ const sessions = new SessionManager(sessionsDir(agentDir));
52
+ return {
53
+ ok: true,
54
+ value: toAcpSummary(await summarizeGoal(sessions, created.value.dir, created.value.record), created.value.record.instructions),
55
+ };
56
+ }
57
+ /** The worker roster for `_gg/goal_state`. A reaped worker reads as closed. */
58
+ export function goalWorkers(snapshots) {
59
+ return snapshots.map((s) => ({
60
+ id: s.agent_id,
61
+ name: s.task_name,
62
+ ...(s.agent_name ? { agent: s.agent_name } : {}),
63
+ state: s.state === "reaped" ? "closed" : s.state,
64
+ ...(s.current_activity ? { activity: s.current_activity } : {}),
65
+ startedAt: s.started_at,
66
+ elapsedMs: s.elapsed_ms,
67
+ toolUses: s.tool_use_count,
68
+ ...(s.model ? { model: s.model } : {}),
69
+ ...(s.error ? { error: s.error } : {}),
70
+ }));
71
+ }
72
+ const IMAGE_EXTENSIONS = {
73
+ "image/png": "png",
74
+ "image/jpeg": "jpg",
75
+ "image/gif": "gif",
76
+ "image/webp": "webp",
77
+ };
78
+ /**
79
+ * ACP `image` prompt blocks as the app's attachment shape, so they take the
80
+ * same `prepareAttachments` → `promptWithAttachments` path the desktop does.
81
+ * Blocks carrying only a `uri` (no inline data) are skipped.
82
+ */
83
+ export function acpImageAttachments(blocks) {
84
+ if (!Array.isArray(blocks))
85
+ return [];
86
+ const out = [];
87
+ for (const block of blocks) {
88
+ const entry = block;
89
+ if (entry?.type !== "image" || typeof entry.data !== "string" || !entry.data)
90
+ continue;
91
+ const mediaType = typeof entry.mimeType === "string" ? entry.mimeType : "image/png";
92
+ const ext = IMAGE_EXTENSIONS[mediaType] ?? "img";
93
+ out.push({
94
+ kind: "image",
95
+ name: `image-${out.length + 1}.${ext}`,
96
+ mediaType,
97
+ data: entry.data,
98
+ });
99
+ }
100
+ return out;
101
+ }
102
+ //# sourceMappingURL=acp-goals.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"acp-goals.js","sourceRoot":"","sources":["../../src/modes/acp-goals.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,UAAU,EACV,SAAS,EACT,SAAS,GAGV,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,aAAa,EAAiC,MAAM,yBAAyB,CAAC;AACvF,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AA2C5D,SAAS,YAAY,CACnB,OAAiC,EACjC,YAAgC;IAEhC,OAAO;QACL,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzC,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,SAAS,EAAE,OAAO,CAAC,SAAS;QAC5B,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;QAC5C,cAAc,EAAE,OAAO,CAAC,eAAe;QACvC,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,QAAgB;IACnC,OAAO,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AACzC,CAAC;AAED,8CAA8C;AAC9C,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3D,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,GAAG,CAC5B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CACpB,YAAY,CAAC,MAAM,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CACpF,CACF,CAAC;IACF,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC;AACd,CAAC;AAED,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAgB,EAChB,MAAe;IAEf,MAAM,KAAK,GACT,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ;QAClC,CAAC,CAAE,MAAwF;QAC3F,CAAC,CAAC,EAAE,CAAC;IACT,MAAM,OAAO,GAAG,MAAM,UAAU,CAC9B,SAAS,CAAC,QAAQ,CAAC,EACnB;QACE,IAAI,EAAE,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;QACtD,IAAI,EAAE,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;QACtD,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;YACnC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC;YACjE,CAAC,CAAC,EAAE;QACN,GAAG,CAAC,OAAO,KAAK,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxF,EACD,IAAI,IAAI,EAAE,CACX,CAAC;IACF,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,OAAO,OAAO,CAAC;IAChC,MAAM,QAAQ,GAAG,IAAI,cAAc,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC3D,OAAO;QACL,EAAE,EAAE,IAAI;QACR,KAAK,EAAE,YAAY,CACjB,MAAM,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,EACtE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,YAAY,CAClC;KACF,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,WAAW,CAAC,SAAsC;IAChE,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3B,EAAE,EAAE,CAAC,CAAC,QAAQ;QACd,IAAI,EAAE,CAAC,CAAC,SAAS;QACjB,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD,KAAK,EAAE,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK;QAChD,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,gBAAgB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/D,SAAS,EAAE,CAAC,CAAC,UAAU;QACvB,SAAS,EAAE,CAAC,CAAC,UAAU;QACvB,QAAQ,EAAE,CAAC,CAAC,cAAc;QAC1B,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACvC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,gBAAgB,GAA2B;IAC/C,WAAW,EAAE,KAAK;IAClB,YAAY,EAAE,KAAK;IACnB,WAAW,EAAE,KAAK;IAClB,YAAY,EAAE,MAAM;CACrB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAe;IACjD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,CAAC;IACtC,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,KAA+D,CAAC;QAC9E,IAAI,KAAK,EAAE,IAAI,KAAK,OAAO,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI;YAAE,SAAS;QACvF,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC;QACpF,MAAM,GAAG,GAAG,gBAAgB,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC;QACjD,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,SAAS,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,EAAE;YACtC,SAAS;YACT,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -1,6 +1,12 @@
1
- import type { Message, Provider, ThinkingLevel } from "@prestyj/ai";
1
+ import type { Message, MessageProvenance, Provider, ThinkingLevel } from "@prestyj/ai";
2
2
  import { type ToolExecuteResult } from "@prestyj/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 AcpNolanReviewer } 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
- prompt(content: string): Promise<void>;
22
+ /** `provenance` marks EZ 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
+ /** EZ 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
+ * Nolan's verdict markers (desktop `persistAutopilotMarker`). Optional so a
70
+ * test double need not persist; without them a reopened session has no
71
+ * Nolan 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 Nolan'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 EZ 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
+ /** `~/.ezcoder` 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 Nolan's reviewer for a session's project. Overridden by
192
+ * tests; production gets {@link createAcpNolanReviewer}.
193
+ */
194
+ createNolanReviewer?: (cwd: string, buildModel: () => {
195
+ provider: Provider;
196
+ model: string;
197
+ }) => AcpNolanReviewer;
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 Nolan 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 Nolan'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
  *