@gavin-hu/my-pi-agent 0.20.0 → 0.22.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 +46 -30
- package/README.zh-CN.md +40 -25
- package/assets/screens/board.png +0 -0
- package/assets/screens/chrome.png +0 -0
- package/assets/screens/file-browse.png +0 -0
- package/assets/screens/plan-review.png +0 -0
- package/assets/screens/plan.png +0 -0
- package/docs/extensions/README.md +22 -23
- package/docs/extensions/board.md +397 -168
- package/docs/extensions/bytefly.md +234 -197
- package/docs/extensions/check.md +15 -17
- package/docs/extensions/context.md +35 -15
- package/docs/extensions/file-browse.md +57 -63
- package/docs/extensions/file-open.md +9 -11
- package/docs/extensions/file-read.md +12 -14
- package/docs/extensions/goal.md +15 -17
- package/docs/extensions/job.md +54 -42
- package/docs/extensions/memory.md +17 -19
- package/docs/extensions/plan.md +197 -140
- package/docs/extensions/question.md +16 -18
- package/docs/extensions/rewind.md +17 -19
- package/docs/extensions/serve.md +145 -0
- package/docs/extensions/session-bus.md +38 -16
- package/docs/extensions/subagent.md +23 -25
- package/docs/extensions/team.md +83 -44
- package/docs/extensions/todo.md +18 -18
- package/docs/extensions/watch.md +31 -31
- package/docs/extensions/web-access.md +2 -4
- package/docs/extensions/wechat.md +34 -35
- package/docs/extensions/worktree.md +56 -50
- package/extensions/board/commands.ts +79 -25
- package/extensions/board/format.ts +43 -24
- package/extensions/board/index.ts +17 -4
- package/extensions/board/input.ts +4 -9
- package/extensions/board/join.ts +5 -20
- package/extensions/board/lazy-page.ts +40 -0
- package/extensions/board/page.ts +65 -93
- package/extensions/board/result.ts +30 -39
- package/extensions/board/rows.ts +62 -25
- package/extensions/board/schema.ts +49 -11
- package/extensions/board/snapshot.ts +8 -6
- package/extensions/board/tone.ts +22 -0
- package/extensions/board/tools.ts +154 -55
- package/extensions/board/transport/router.ts +3 -5
- package/extensions/board/transport/server.ts +59 -28
- package/extensions/board/types.ts +36 -42
- package/extensions/board/view/card.ts +229 -0
- package/extensions/board/view/client.ts +35 -16
- package/extensions/board/view/dialog.ts +169 -6
- package/extensions/board/view/empty.ts +47 -0
- package/extensions/board/view/keys.ts +13 -2
- package/extensions/board/view/live.ts +90 -28
- package/extensions/board/view/names.ts +13 -4
- package/extensions/board/view/page.ts +38 -13
- package/extensions/board/view/render.ts +219 -277
- package/extensions/board/view/styles.ts +130 -32
- package/extensions/board/view/team.ts +297 -76
- package/extensions/bytefly/block/fallback.ts +1 -1
- package/extensions/bytefly/doctor/runtime.ts +5 -2
- package/extensions/bytefly/footer/collect/label.ts +60 -0
- package/extensions/bytefly/footer/collect/snapshot.ts +8 -1
- package/extensions/bytefly/footer/config.ts +7 -8
- package/extensions/bytefly/footer/register.ts +33 -4
- package/extensions/bytefly/footer/render/footer.ts +18 -4
- package/extensions/bytefly/footer/render/key.ts +46 -0
- package/extensions/bytefly/footer/render/layout.ts +13 -3
- package/extensions/bytefly/footer/render/lines.ts +10 -7
- package/extensions/bytefly/footer/render/segments.ts +41 -38
- package/extensions/bytefly/footer/render/status.ts +0 -11
- package/extensions/bytefly/footer/types.ts +7 -0
- package/extensions/bytefly/header/component.ts +4 -20
- package/extensions/bytefly/header/config.ts +1 -1
- package/extensions/bytefly/index.ts +32 -6
- package/extensions/bytefly/mode/editor.ts +115 -0
- package/extensions/bytefly/panel/commands.ts +210 -120
- package/extensions/bytefly/panel/format.ts +4 -4
- package/extensions/bytefly/panel/settings.ts +73 -6
- package/extensions/bytefly/panel/tui/keys.ts +2 -6
- package/extensions/bytefly/update/cache.ts +1 -1
- package/extensions/bytefly/update/register.ts +4 -4
- package/extensions/bytefly/working/config.ts +5 -7
- package/extensions/bytefly/working/format.ts +10 -13
- package/extensions/bytefly/working/register.ts +22 -27
- package/extensions/check/commands.ts +3 -2
- package/extensions/check/render.ts +10 -1
- package/extensions/check/{tui.ts → view/check-screens.ts} +14 -19
- package/extensions/context/commands.ts +2 -2
- package/extensions/context/{tui.ts → view/context-report.ts} +51 -19
- package/extensions/file-browse/config/config.ts +4 -19
- package/extensions/file-browse/index.ts +89 -79
- package/extensions/file-browse/live/live.ts +1 -1
- package/extensions/file-browse/transport/router.ts +12 -4
- package/extensions/file-browse/transport/server.ts +61 -28
- package/extensions/file-browse/view/chrome.ts +4 -4
- package/extensions/file-browse/view/client.ts +3 -1
- package/extensions/file-browse/view/html.ts +73 -40
- package/extensions/file-browse/view/live-client.ts +2 -2
- package/extensions/file-browse/view/markdown.ts +13 -14
- package/extensions/file-browse/view/palette.ts +2 -2
- package/extensions/file-browse/view/raw-html.ts +9 -9
- package/extensions/file-browse/view/tree.ts +1 -1
- package/extensions/file-browse/view/urls.ts +20 -6
- package/extensions/file-read/render.ts +4 -4
- package/extensions/goal/plan-route.ts +2 -2
- package/extensions/goal/tui.ts +12 -2
- package/extensions/job/child.ts +527 -0
- package/extensions/job/clock.ts +142 -0
- package/extensions/job/commands.ts +4 -2
- package/extensions/job/config.ts +8 -1
- package/extensions/job/format.ts +22 -1
- package/extensions/job/log-writer.ts +13 -2
- package/extensions/job/registry.ts +63 -7
- package/extensions/job/render.ts +34 -0
- package/extensions/job/runtime.ts +296 -655
- package/extensions/job/session.ts +132 -19
- package/extensions/job/store.ts +7 -7
- package/extensions/job/tools.ts +21 -9
- package/extensions/job/types.ts +47 -0
- package/extensions/job/{tui.ts → view/jobs-screen.ts} +19 -99
- package/extensions/job/waiters.ts +44 -1
- package/extensions/memory/commands.ts +4 -2
- package/extensions/memory/{tui.ts → view/memory-picker.ts} +12 -12
- package/extensions/plan/commands.ts +12 -9
- package/extensions/plan/feedback.ts +62 -16
- package/extensions/plan/format.ts +8 -2
- package/extensions/plan/git-bash.ts +115 -16
- package/extensions/plan/index.ts +58 -51
- package/extensions/plan/plan-index.ts +4 -2
- package/extensions/plan/plan-text.ts +114 -0
- package/extensions/plan/plans.ts +5 -54
- package/extensions/plan/policy.ts +8 -10
- package/extensions/plan/review-lazy.ts +85 -0
- package/extensions/plan/review.ts +2 -2
- package/extensions/plan/runtime.ts +61 -41
- package/extensions/plan/sections.ts +1 -1
- package/extensions/plan/steps.ts +3 -3
- package/extensions/plan/todos.ts +1 -1
- package/extensions/plan/tools/cancel.ts +27 -62
- package/extensions/plan/tools/enter.ts +55 -81
- package/extensions/plan/tools/exit.ts +221 -238
- package/extensions/plan/tools/refusal.ts +18 -0
- package/extensions/plan/tools/steps.ts +75 -92
- package/extensions/plan/tools/write.ts +77 -120
- package/extensions/plan/tools.ts +188 -30
- package/extensions/plan/tui.ts +5 -5
- package/extensions/plan/types.ts +48 -5
- package/extensions/plan/web-blocks.ts +76 -5
- package/extensions/plan/web-chrome.ts +4 -0
- package/extensions/plan/web-client.ts +102 -2
- package/extensions/plan/web-collab.ts +4 -4
- package/extensions/plan/web-comments.ts +39 -8
- package/extensions/plan/web-composer.ts +14 -3
- package/extensions/plan/web-keys.ts +149 -25
- package/extensions/plan/web-lazy.ts +53 -0
- package/extensions/plan/web-markdown.ts +10 -68
- package/extensions/plan/web-outline.ts +22 -2
- package/extensions/plan/web-page.ts +56 -86
- package/extensions/plan/web-payload.ts +188 -0
- package/extensions/plan/web-plan.ts +23 -13
- package/extensions/plan/web-router.ts +18 -9
- package/extensions/plan/web-settle.ts +14 -7
- package/extensions/plan/web-share-session.ts +24 -55
- package/extensions/plan/web-share.ts +19 -37
- package/extensions/plan/web-write.ts +112 -0
- package/extensions/plan/web.ts +67 -131
- package/extensions/question/tools.ts +6 -2
- package/extensions/question/{tui.ts → view/question-screen.ts} +11 -11
- package/extensions/rewind/commands/commands.ts +6 -3
- package/extensions/rewind/state/runtime.ts +1 -1
- package/extensions/rewind/{view/status.ts → status.ts} +4 -4
- package/extensions/rewind/view/review-tui.ts +4 -4
- package/extensions/serve/config.ts +39 -0
- package/extensions/serve/index.ts +85 -0
- package/extensions/serve/registry.ts +260 -0
- package/extensions/session-bus/commands.ts +11 -6
- package/extensions/session-bus/join-request.ts +17 -9
- package/extensions/session-bus/mail-watch.ts +26 -17
- package/extensions/session-bus/protocol.ts +15 -3
- package/extensions/session-bus/resolve.ts +5 -7
- package/extensions/session-bus/result.ts +1 -27
- package/extensions/session-bus/runtime.ts +40 -12
- package/extensions/session-bus/store.ts +101 -19
- package/extensions/session-bus/tools.ts +5 -4
- package/extensions/session-bus/types.ts +19 -0
- package/extensions/session-bus/{tui.ts → view/session-list.ts} +16 -16
- package/extensions/subagent/agents.ts +1 -1
- package/extensions/subagent/commands.ts +4 -2
- package/extensions/subagent/format.ts +15 -15
- package/extensions/subagent/index.ts +1 -1
- package/extensions/subagent/render.ts +3 -3
- package/extensions/subagent/{background-tui.ts → view/agents-board.ts} +11 -11
- package/extensions/team/commands.ts +24 -5
- package/extensions/team/dispatch.ts +18 -4
- package/extensions/team/format.ts +17 -2
- package/extensions/team/index.ts +9 -8
- package/extensions/team/schema.ts +6 -5
- package/extensions/team/tools.ts +107 -45
- package/extensions/team/types.ts +3 -2
- package/extensions/todo/commands.ts +4 -2
- package/extensions/todo/format.ts +11 -0
- package/extensions/todo/render.ts +57 -0
- package/extensions/todo/runtime.ts +1 -1
- package/extensions/todo/tools.ts +1 -1
- package/extensions/todo/{tui.ts → view/todo-screen.ts} +18 -90
- package/extensions/todo/widget.ts +47 -0
- package/extensions/watch/commands.ts +4 -2
- package/extensions/watch/format.ts +36 -7
- package/extensions/watch/render.ts +57 -0
- package/extensions/watch/runtime.ts +27 -22
- package/extensions/watch/tools.ts +4 -4
- package/extensions/watch/{tui.ts → view/watch-screen.ts} +18 -80
- package/extensions/web-access/fetch/tool.ts +12 -4
- package/extensions/wechat/commands/commands.ts +18 -14
- package/extensions/wechat/index.ts +72 -37
- package/extensions/wechat/state/credentials.ts +1 -1
- package/extensions/wechat/state/state.ts +1 -1
- package/extensions/wechat/text/status.ts +112 -0
- package/extensions/wechat/types.ts +2 -2
- package/extensions/wechat/view/status-screen.ts +4 -103
- package/extensions/worktree/commands.ts +11 -9
- package/extensions/worktree/enter.ts +2 -2
- package/extensions/worktree/exit.ts +2 -2
- package/extensions/worktree/index.ts +5 -5
- package/extensions/worktree/screen.ts +3 -3
- package/extensions/worktree/status.ts +2 -2
- package/extensions/worktree/tools.ts +113 -116
- package/lib/README.md +28 -13
- package/lib/board/actions.ts +111 -0
- package/lib/board/artifact.ts +149 -0
- package/lib/board/card.ts +163 -52
- package/lib/board/config.ts +58 -0
- package/lib/board/contract.ts +113 -0
- package/lib/board/join.ts +38 -0
- package/lib/board/lanes.ts +182 -0
- package/lib/board/lead.ts +130 -0
- package/lib/board/limits.ts +78 -0
- package/lib/board/links.ts +31 -10
- package/lib/board/page-pointer.ts +30 -5
- package/lib/board/read.ts +83 -0
- package/lib/board/reason.ts +102 -0
- package/lib/board/round-text.ts +68 -6
- package/lib/board/round.ts +31 -15
- package/lib/board/rules.ts +151 -307
- package/lib/board/seat.ts +35 -0
- package/lib/board/session.ts +199 -51
- package/lib/board/skipped.ts +22 -0
- package/lib/board/steps.ts +487 -0
- package/lib/board/store.ts +119 -36
- package/lib/board/tone.ts +92 -0
- package/lib/board/view.ts +81 -63
- package/lib/bus-request.ts +83 -0
- package/{extensions/watch → lib}/child.ts +40 -21
- package/lib/env.ts +65 -7
- package/lib/format.ts +13 -0
- package/lib/http/index.ts +17 -11
- package/lib/http/mount.ts +142 -0
- package/lib/http/port.ts +30 -0
- package/lib/http/serve.ts +170 -46
- package/lib/http/server.ts +3 -3
- package/lib/lazy.ts +45 -0
- package/lib/plan-entry.ts +46 -21
- package/lib/plans/paths.ts +82 -0
- package/lib/policy.ts +9 -6
- package/lib/report.ts +3 -2
- package/lib/requirements.ts +10 -10
- package/lib/session-label.ts +129 -7
- package/lib/session-roster.ts +43 -1
- package/lib/session-tool.ts +39 -22
- package/lib/stray-fields.ts +7 -2
- package/lib/tool-names.ts +5 -10
- package/lib/tui/README.md +29 -11
- package/lib/tui/chrome.ts +16 -15
- package/lib/tui/cursor.ts +18 -3
- package/lib/tui/glyphs.ts +11 -11
- package/lib/tui/render-cache.ts +29 -0
- package/lib/tui/tokens.ts +33 -2
- package/lib/tui/tool.ts +33 -4
- package/lib/web/README.md +21 -0
- package/lib/web/client-runtime.ts +27 -1
- package/lib/web/components.ts +5 -1
- package/lib/web/index.ts +1 -0
- package/lib/web/markdown.ts +83 -0
- package/lib/web/markup.ts +20 -2
- package/lib/web/runtime.ts +9 -10
- package/package.json +8 -2
- package/skills/init/SKILL.md +5 -5
- package/skills/next/SKILL.md +3 -5
- package/extensions/board/config.ts +0 -36
- package/extensions/board/seat.ts +0 -28
- package/lib/tui/index.ts +0 -34
- package/skills/project-docs/SKILL.md +0 -133
- package/skills/project-docs/references/audit.md +0 -131
- package/skills/project-docs/references/changelog.md +0 -105
- package/skills/project-docs/references/discovery.md +0 -127
- package/skills/project-docs/references/readme.md +0 -80
- package/skills/project-docs/references/release.md +0 -84
- package/skills/project-docs/references/roadmap.md +0 -93
- package/skills/project-docs/scripts/state.ts +0 -316
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The `
|
|
2
|
+
* The `exit` action of the `plan` tool.
|
|
3
3
|
*
|
|
4
4
|
* It presents the saved plan for approval, then seeds the approved steps into
|
|
5
5
|
* the todo list and finalizes the session goal: a `planning` goal becomes the
|
|
@@ -9,36 +9,31 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { basename } from "node:path";
|
|
12
|
-
import type { ExtensionAPI, ExtensionToolContext } from "@earendil-works/pi-coding-agent";
|
|
13
|
-
import { Type, type Static } from "typebox";
|
|
12
|
+
import type { AgentToolResult, ExtensionAPI, ExtensionToolContext, Theme } from "@earendil-works/pi-coding-agent";
|
|
14
13
|
import { sanitizeLine } from "../../../lib/format.ts";
|
|
15
14
|
import { lastGoal } from "../../../lib/goal-state.ts";
|
|
16
15
|
import { GOAL_TOOL } from "../../../lib/tool-names.ts";
|
|
17
|
-
import {
|
|
16
|
+
import { failedResult } from "../../../lib/tool-result.ts";
|
|
18
17
|
import { GLYPHS } from "../../../lib/tui/glyphs.ts";
|
|
19
18
|
import { paint } from "../../../lib/tui/tokens.ts";
|
|
20
|
-
import { callLine,
|
|
21
|
-
import { failedResult } from "../../../lib/tool-result.ts";
|
|
19
|
+
import { callLine, moreHint, type ToolCallText } from "../../../lib/tui/tool.ts";
|
|
22
20
|
import { feedbackSummary } from "../feedback.ts";
|
|
23
|
-
import { mergeSummary, overCap, preview, verificationNote } from "../format.ts";
|
|
21
|
+
import { mergeSummary, overCap, preview, TICK_CALL, verificationNote } from "../format.ts";
|
|
24
22
|
import { sanitizePlanText } from "../plan-text.ts";
|
|
25
23
|
import { planTitle, type StoredPlan } from "../plans.ts";
|
|
26
|
-
import { reviewPlan } from "../review.ts";
|
|
27
|
-
import {
|
|
24
|
+
import { reviewPlan } from "../review-lazy.ts";
|
|
25
|
+
import { PLAN_TOOL, type PlanRuntime } from "../runtime.ts";
|
|
28
26
|
import { goalSection, MAX_STEPS, planStepSummary } from "../steps.ts";
|
|
29
|
-
import type { ExitPlanModeDetails } from "../types.ts";
|
|
27
|
+
import type { ExitPlanModeDetails, PlanDetails } from "../types.ts";
|
|
30
28
|
import type { PlanWebReview } from "../web.ts";
|
|
31
29
|
import { firstTextLine } from "./nested.ts";
|
|
30
|
+
import { planRefusal } from "./refusal.ts";
|
|
32
31
|
import { seedTodos } from "./todo-seed.ts";
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}),
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
type ExitPlanModeArgs = Static<typeof ExitPlanModeParams>;
|
|
33
|
+
/** The fields `action: "exit"` reads. */
|
|
34
|
+
export interface ExitPlanModeArgs {
|
|
35
|
+
plan_path?: string;
|
|
36
|
+
}
|
|
42
37
|
|
|
43
38
|
/** How the goal ended up: no action when it was already final. */
|
|
44
39
|
interface GoalOutcome {
|
|
@@ -77,233 +72,221 @@ function planObjective(plan: StoredPlan): string {
|
|
|
77
72
|
return title || planTitle(basename(plan.path));
|
|
78
73
|
}
|
|
79
74
|
|
|
80
|
-
export function
|
|
81
|
-
pi
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
parameters: ExitPlanModeParams,
|
|
90
|
-
defaultActive: false,
|
|
91
|
-
executionMode: "sequential",
|
|
92
|
-
// readOnlyHint stays true: it writes no files, and the review dialog inside
|
|
93
|
-
// execute is the human gate, so an outer prompt would only double-ask.
|
|
94
|
-
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
95
|
-
|
|
96
|
-
async execute(_toolCallId, params, signal, _onUpdate, ctx) {
|
|
97
|
-
const args = params as ExitPlanModeArgs;
|
|
98
|
-
const planPath = args.plan_path.trim();
|
|
75
|
+
export async function executeExit(
|
|
76
|
+
pi: ExtensionAPI,
|
|
77
|
+
runtime: PlanRuntime,
|
|
78
|
+
web: PlanWebReview,
|
|
79
|
+
args: ExitPlanModeArgs,
|
|
80
|
+
ctx: ExtensionToolContext,
|
|
81
|
+
signal: AbortSignal | undefined,
|
|
82
|
+
): Promise<AgentToolResult<PlanDetails>> {
|
|
83
|
+
const planPath = args.plan_path?.trim() ?? "";
|
|
99
84
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
85
|
+
if (!runtime.isEnabled()) {
|
|
86
|
+
return planRefusal("exit", "Not in plan mode; there is no plan to approve.");
|
|
87
|
+
}
|
|
88
|
+
if (planPath === "") {
|
|
89
|
+
return planRefusal("exit", "`exit` needs plan_path: the file `plan` action `write` returned.");
|
|
90
|
+
}
|
|
107
91
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
92
|
+
const file = await runtime.plans.read(ctx.cwd, planPath);
|
|
93
|
+
if (!file) {
|
|
94
|
+
return planRefusal(
|
|
95
|
+
"exit",
|
|
96
|
+
`No plan file at "${planPath}". Save the plan with \`plan\` action \`write\` first, then pass the returned path.`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
115
99
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
100
|
+
const total = planStepSummary(file.content).total;
|
|
101
|
+
if (total > MAX_STEPS) {
|
|
102
|
+
// A hand-edited or older plan file can still be over the cap; refuse it here
|
|
103
|
+
// too, so approval never seeds a list it cannot hold in full. The refusal
|
|
104
|
+
// carries the file it read, so the block still shows what was not presented.
|
|
105
|
+
return failedResult(
|
|
106
|
+
`Error: ${overCap(total)} It was not presented for approval; call \`plan\` action \`write\` with plan_path to group the steps, then \`exit\` again.`,
|
|
107
|
+
{
|
|
108
|
+
action: "exit",
|
|
109
|
+
approved: false,
|
|
110
|
+
plan: file.content,
|
|
111
|
+
planPath: file.path,
|
|
112
|
+
relativePath: file.relativePath,
|
|
113
|
+
} satisfies ExitPlanModeDetails,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
130
116
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
117
|
+
if (!ctx.hasUI) {
|
|
118
|
+
return failedResult(
|
|
119
|
+
`Error: No interactive UI is available to approve the plan. It is saved at ${file.relativePath}; present it and ask the user to approve it in their reply.`,
|
|
120
|
+
{
|
|
121
|
+
action: "exit",
|
|
122
|
+
approved: false,
|
|
123
|
+
plan: file.content,
|
|
124
|
+
planPath: file.path,
|
|
125
|
+
relativePath: file.relativePath,
|
|
126
|
+
unavailable: true,
|
|
127
|
+
} satisfies ExitPlanModeDetails,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
143
130
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
131
|
+
// One decision, however the session is attached; `review.ts` owns the loop,
|
|
132
|
+
// the baseline, and closing the browser review when the turn is aborted.
|
|
133
|
+
const decision = await reviewPlan({
|
|
134
|
+
ctx,
|
|
135
|
+
web,
|
|
136
|
+
plans: runtime.plans,
|
|
137
|
+
baselines: runtime,
|
|
138
|
+
plan: file,
|
|
139
|
+
signal,
|
|
140
|
+
});
|
|
154
141
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
142
|
+
if (decision.action === "refine") {
|
|
143
|
+
// A browser save already wrote its comments into the file; either way the
|
|
144
|
+
// model revises the same plan and presents it again.
|
|
145
|
+
const feedback = decision.fromBrowser
|
|
146
|
+
? `The user reviewed the plan in the browser and left feedback:\n${decision.refinement}`
|
|
147
|
+
: `The user asked to refine the plan: ${decision.refinement}`;
|
|
148
|
+
return {
|
|
149
|
+
content: [
|
|
150
|
+
{
|
|
151
|
+
type: "text",
|
|
152
|
+
text: `${feedback}\nStay in plan mode, revise the plan (\`plan\` action \`write\`, reusing plan_path), then call \`plan\` action \`exit\` again.`,
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
details: {
|
|
156
|
+
action: "exit",
|
|
157
|
+
approved: false,
|
|
158
|
+
plan: decision.plan.content,
|
|
159
|
+
planPath: decision.plan.path,
|
|
160
|
+
relativePath: decision.plan.relativePath,
|
|
161
|
+
refined: true,
|
|
162
|
+
refinement: decision.refinement,
|
|
163
|
+
annotations: decision.comments.length > 0 ? decision.comments : undefined,
|
|
164
|
+
} satisfies ExitPlanModeDetails,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
if (decision.action === "keep") {
|
|
168
|
+
return {
|
|
169
|
+
content: [
|
|
170
|
+
{ type: "text", text: "Plan not approved. Stay in plan mode, ask what to change, and revise the plan." },
|
|
171
|
+
],
|
|
172
|
+
details: {
|
|
173
|
+
action: "exit",
|
|
174
|
+
approved: false,
|
|
175
|
+
plan: decision.plan.content,
|
|
176
|
+
planPath: decision.plan.path,
|
|
177
|
+
relativePath: decision.plan.relativePath,
|
|
178
|
+
} satisfies ExitPlanModeDetails,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
if (decision.action === "cancel") {
|
|
182
|
+
runtime.disable(ctx);
|
|
183
|
+
const shown = decision.plan.relativePath;
|
|
184
|
+
ctx.ui.notify("Plan mode off — full access restored. The plan was not approved.", "info");
|
|
185
|
+
return {
|
|
186
|
+
content: [
|
|
187
|
+
{
|
|
188
|
+
type: "text",
|
|
189
|
+
text:
|
|
190
|
+
"Plan mode is off and write access is restored. The plan was not approved and no steps were recorded. " +
|
|
191
|
+
`The plan file ${shown} remains if the user wants to review it later.`,
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
details: {
|
|
195
|
+
action: "exit",
|
|
196
|
+
approved: false,
|
|
197
|
+
cancelled: true,
|
|
198
|
+
plan: decision.plan.content,
|
|
199
|
+
planPath: decision.plan.path,
|
|
200
|
+
relativePath: decision.plan.relativePath,
|
|
201
|
+
} satisfies ExitPlanModeDetails,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
214
204
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
},
|
|
205
|
+
runtime.disable(ctx);
|
|
206
|
+
// A plan refined and approved again seeds over the list its first approval made:
|
|
207
|
+
// the steps that approval appended are the ones this one may replace.
|
|
208
|
+
const previous = runtime.seeded(decision.plan.path);
|
|
209
|
+
const { steps, merged, error } = await seedTodos(pi, ctx, decision.plan.content, previous);
|
|
210
|
+
if (error === undefined && steps.length > 0) {
|
|
211
|
+
runtime.markSeeded(
|
|
212
|
+
decision.plan.path,
|
|
213
|
+
steps.map((step) => step.content),
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
const goal = await finalizeGoal(pi, ctx, decision.plan);
|
|
217
|
+
const listing =
|
|
218
|
+
steps.length > 0
|
|
219
|
+
? `\n\n${steps
|
|
220
|
+
.map((step, index) => `${index + 1}. [${step.status === "completed" ? "x" : " "}] ${step.content}`)
|
|
221
|
+
.join("\n")}`
|
|
222
|
+
: "";
|
|
223
|
+
const tick = TICK_CALL;
|
|
224
|
+
const tail =
|
|
225
|
+
steps.length === 0
|
|
226
|
+
? " The plan has no steps to record."
|
|
227
|
+
: error
|
|
228
|
+
? ` Could not record the steps in the todo list: ${error}. Keep these steps in mind and tick them off with ${tick} as you go.`
|
|
229
|
+
: merged
|
|
230
|
+
? mergeSummary(merged, steps)
|
|
231
|
+
: ` Could not read the todo list. Record these steps with the todo tool before you start, and tick them off with ${tick}.`;
|
|
232
|
+
const verification = verificationNote(merged);
|
|
233
|
+
const goalNote =
|
|
234
|
+
goal.action === undefined
|
|
235
|
+
? ""
|
|
236
|
+
: goal.error !== undefined
|
|
237
|
+
? ` Could not ${goal.action === "recorded" ? "record" : "update"} the session goal: ${goal.error}. Use the goal tool to set it.`
|
|
238
|
+
: goal.action === "recorded"
|
|
239
|
+
? ` Recorded the session goal: ${goal.objective}.`
|
|
240
|
+
: ` Set the session goal from the plan: ${goal.objective}.`;
|
|
241
|
+
const browserNote = decision.comments.length
|
|
242
|
+
? `\n\nThe user approved from the browser review with these comments:\n${feedbackSummary(decision.comments)}`
|
|
243
|
+
: "";
|
|
244
|
+
return {
|
|
245
|
+
content: [
|
|
246
|
+
{
|
|
247
|
+
type: "text",
|
|
248
|
+
text: `Plan approved. Plan mode is off and write access is restored. The plan file ${decision.plan.relativePath} is the source of truth; follow its steps.${browserNote}${tail}${verification}${goalNote}${listing}`,
|
|
249
|
+
},
|
|
250
|
+
],
|
|
251
|
+
details: {
|
|
252
|
+
action: "exit",
|
|
253
|
+
approved: true,
|
|
254
|
+
plan: decision.plan.content,
|
|
255
|
+
planPath: decision.plan.path,
|
|
256
|
+
relativePath: decision.plan.relativePath,
|
|
257
|
+
annotations: decision.comments.length > 0 ? decision.comments : undefined,
|
|
258
|
+
} satisfies ExitPlanModeDetails,
|
|
259
|
+
};
|
|
260
|
+
}
|
|
269
261
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
262
|
+
export function callExit(args: ExitPlanModeArgs, theme: Theme, last: unknown): ToolCallText {
|
|
263
|
+
const path = args.plan_path?.trim() ?? "";
|
|
264
|
+
return callLine(theme, last, PLAN_TOOL, path === "" ? "exit" : `exit ${basename(path)}`);
|
|
265
|
+
}
|
|
273
266
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (planText) {
|
|
300
|
-
const { body, more } = expanded ? { body: planText, more: 0 } : preview(planText);
|
|
301
|
-
// A blank line separates the header block from the plan body.
|
|
302
|
-
out += `\n\n${theme.fg("toolOutput", body)}`;
|
|
303
|
-
if (more > 0) out += `\n${moreHint(theme, more)}`;
|
|
304
|
-
}
|
|
305
|
-
text.setText(out);
|
|
306
|
-
return text;
|
|
307
|
-
},
|
|
308
|
-
});
|
|
267
|
+
export function textExit(details: ExitPlanModeDetails, expanded: boolean, theme: Theme): string {
|
|
268
|
+
const heading = details.unavailable
|
|
269
|
+
? paint(theme, "warn", "No UI to approve the plan")
|
|
270
|
+
: details.cancelled
|
|
271
|
+
? paint(theme, "warn", "Plan mode off — plan not approved")
|
|
272
|
+
: details.approved
|
|
273
|
+
? paint(theme, "ok", `${GLYPHS.check} Plan approved`)
|
|
274
|
+
: details.refined
|
|
275
|
+
? paint(theme, "accent", "Refining the plan")
|
|
276
|
+
: paint(theme, "warn", "Plan not approved");
|
|
277
|
+
const extra =
|
|
278
|
+
details.refined && details.refinement
|
|
279
|
+
? `\n${paint(theme, "meta", `↳ ${sanitizePlanText(details.refinement)}`)}`
|
|
280
|
+
: "";
|
|
281
|
+
const shown = details.relativePath ?? details.planPath;
|
|
282
|
+
const path = shown ? `\n${paint(theme, "meta", shown)}` : "";
|
|
283
|
+
const planText = sanitizePlanText(details.plan);
|
|
284
|
+
let out = `${heading}${extra}${path}`;
|
|
285
|
+
if (planText) {
|
|
286
|
+
const { body, more } = expanded ? { body: planText, more: 0 } : preview(planText);
|
|
287
|
+
// A blank line separates the header block from the plan body.
|
|
288
|
+
out += `\n\n${paint(theme, "toolOutput", body)}`;
|
|
289
|
+
if (more > 0) out += `\n${moreHint(theme, more)}`;
|
|
290
|
+
}
|
|
291
|
+
return out;
|
|
309
292
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One refusal for the folded `plan` tool.
|
|
3
|
+
*
|
|
4
|
+
* A rejected action says what it needed and carries the same words in `details`,
|
|
5
|
+
* so the transcript draws the reason rather than a bare rejected-call envelope.
|
|
6
|
+
* Every refusal happens before the first write, so a rejected call leaves the
|
|
7
|
+
* plan mode and the plan file exactly as they were.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { failedResult, type ToolFailure } from "../../../lib/tool-result.ts";
|
|
11
|
+
import type { PlanAction, RefusedPlanDetails } from "../types.ts";
|
|
12
|
+
|
|
13
|
+
export function planRefusal<Action extends PlanAction>(
|
|
14
|
+
action: Action,
|
|
15
|
+
message: string,
|
|
16
|
+
): ToolFailure<RefusedPlanDetails> {
|
|
17
|
+
return failedResult(`Error: ${message}`, { refused: action, error: message });
|
|
18
|
+
}
|