ultimate-pi 0.10.0 → 0.11.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/.agents/skills/harness-decisions/SKILL.md +3 -3
- package/.agents/skills/harness-orchestration/SKILL.md +19 -11
- package/.agents/skills/harness-plan/SKILL.md +15 -9
- package/.pi/agents/harness/planner.md +6 -47
- package/.pi/agents/harness/planning/decompose.md +84 -0
- package/.pi/agents/harness/planning/hypothesis-eval.md +59 -0
- package/.pi/agents/harness/planning/hypothesis.md +90 -0
- package/.pi/agents/harness/planning/plan-adversary.md +50 -0
- package/.pi/agents/harness/planning/planner.md +20 -0
- package/.pi/agents/harness/planning/scout-graphify.md +48 -0
- package/.pi/agents/harness/planning/scout-semantic.md +42 -0
- package/.pi/agents/harness/planning/scout-structure.md +44 -0
- package/.pi/extensions/harness-ask-user.ts +5 -0
- package/.pi/extensions/harness-live-widget.ts +48 -28
- package/.pi/extensions/harness-plan-approval.ts +192 -24
- package/.pi/extensions/harness-run-context.ts +24 -15
- package/.pi/extensions/harness-subagents.ts +8 -3
- package/.pi/extensions/harness-web-tools.ts +2 -0
- package/.pi/extensions/lib/extension-load-guard.ts +39 -0
- package/.pi/extensions/lib/harness-subagents/harness-subagent-policy.ts +33 -5
- package/.pi/extensions/lib/harness-subagents/parent-harness-ui-bridge.ts +2 -171
- package/.pi/extensions/lib/harness-subagents/parent-harness-ui-hooks.ts +18 -0
- package/.pi/extensions/lib/harness-subagents/spawn-policy.ts +1 -5
- package/.pi/extensions/lib/harness-subagents/vendored/agent-runner.ts +0 -18
- package/.pi/extensions/lib/harness-subagents/vendored/index.ts +4 -36
- package/.pi/extensions/lib/harness-subagents/vendored/ui/agent-widget.ts +2 -0
- package/.pi/extensions/lib/plan-approval/create-plan.ts +5 -0
- package/.pi/extensions/lib/plan-approval/dialog.ts +231 -147
- package/.pi/extensions/lib/plan-approval/plan-review.ts +393 -0
- package/.pi/extensions/lib/plan-approval/schema.ts +16 -1
- package/.pi/extensions/lib/plan-approval/types.ts +10 -0
- package/.pi/extensions/lib/plan-approval/validate.ts +2 -0
- package/.pi/extensions/policy-gate.ts +1 -1
- package/.pi/extensions/ultimate-pi-vcc.ts +5 -0
- package/.pi/harness/agents.manifest.json +114 -82
- package/.pi/harness/docs/adrs/0032-harness-command-orchestration.md +3 -3
- package/.pi/harness/docs/adrs/0033-parent-orchestrated-planning.md +34 -0
- package/.pi/harness/docs/adrs/0034-darwin-plan-research-pipeline.md +41 -0
- package/.pi/harness/docs/adrs/README.md +2 -0
- package/.pi/harness/specs/README.md +1 -1
- package/.pi/harness/specs/harness-spawn-context.schema.json +2 -1
- package/.pi/harness/specs/plan-adversary-brief.schema.json +45 -0
- package/.pi/harness/specs/plan-decomposition-brief.schema.json +108 -0
- package/.pi/harness/specs/plan-hypothesis-brief.schema.json +96 -0
- package/.pi/harness/specs/plan-hypothesis-eval.schema.json +61 -0
- package/.pi/lib/harness-run-context.ts +12 -0
- package/.pi/prompts/harness-auto.md +1 -1
- package/.pi/prompts/harness-plan.md +116 -20
- package/.pi/prompts/harness-setup.md +1 -1
- package/.pi/scripts/harness-resolve-up-pkg.mjs +13 -0
- package/CHANGELOG.md +18 -0
- package/biome.json +4 -1
- package/package.json +2 -2
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Registers ask_user
|
|
2
|
+
* Registers ask_user in subagent sessions, delegating UI to the parent harness session.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type {
|
|
6
6
|
ExtensionAPI,
|
|
7
7
|
ExtensionContext,
|
|
8
8
|
} from "@earendil-works/pi-coding-agent";
|
|
9
|
-
import { Text } from "@earendil-works/pi-tui";
|
|
10
|
-
import { Type } from "@sinclair/typebox";
|
|
11
9
|
import type {
|
|
12
10
|
PlanPacketLike,
|
|
13
11
|
PlanUserApproval,
|
|
@@ -27,32 +25,8 @@ import {
|
|
|
27
25
|
toToolDetails,
|
|
28
26
|
validateAskParams,
|
|
29
27
|
} from "../ask-user/validate.js";
|
|
30
|
-
import {
|
|
31
|
-
CREATE_PLAN_GUIDELINES,
|
|
32
|
-
CREATE_PLAN_SNIPPET,
|
|
33
|
-
executeCreatePlan,
|
|
34
|
-
formatCreatePlanResultText,
|
|
35
|
-
} from "../plan-approval/create-plan.js";
|
|
36
|
-
import { runPlanApprovalDialog } from "../plan-approval/dialog.js";
|
|
37
|
-
import { runPlanApprovalFallback } from "../plan-approval/fallback.js";
|
|
38
|
-
import {
|
|
39
|
-
renderApprovePlanCall,
|
|
40
|
-
renderApprovePlanResult,
|
|
41
|
-
} from "../plan-approval/render.js";
|
|
42
|
-
import {
|
|
43
|
-
ApprovePlanParamsSchema,
|
|
44
|
-
PROMPT_GUIDELINES as PLAN_PROMPT_GUIDELINES,
|
|
45
|
-
PROMPT_SNIPPET as PLAN_PROMPT_SNIPPET,
|
|
46
|
-
} from "../plan-approval/schema.js";
|
|
47
|
-
import type { ApprovePlanParams } from "../plan-approval/types.js";
|
|
48
|
-
import {
|
|
49
|
-
formatApprovePlanResultText,
|
|
50
|
-
toApprovePlanToolDetails,
|
|
51
|
-
validateApprovePlanParams,
|
|
52
|
-
} from "../plan-approval/validate.js";
|
|
53
28
|
|
|
54
29
|
const HARNESS_UI_AGENT_TYPES = new Set([
|
|
55
|
-
"harness/planner",
|
|
56
30
|
"harness/evaluator",
|
|
57
31
|
"harness/adversary",
|
|
58
32
|
"harness/tie-breaker",
|
|
@@ -76,18 +50,6 @@ export interface ParentHarnessUiHooks {
|
|
|
76
50
|
) => void;
|
|
77
51
|
}
|
|
78
52
|
|
|
79
|
-
const CreatePlanParamsSchema = Type.Object({
|
|
80
|
-
plan_packet: Type.Object(
|
|
81
|
-
{},
|
|
82
|
-
{
|
|
83
|
-
description:
|
|
84
|
-
"Approved PlanPacket to persist (same object as approve_plan).",
|
|
85
|
-
},
|
|
86
|
-
),
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const PLANNER_ONLY_AGENT = "harness/planner";
|
|
90
|
-
|
|
91
53
|
export function agentTypeAllowsParentHarnessUi(agentType: string): boolean {
|
|
92
54
|
return HARNESS_UI_AGENT_TYPES.has(agentType);
|
|
93
55
|
}
|
|
@@ -120,7 +82,7 @@ export function createParentHarnessUiBridgeFactory(
|
|
|
120
82
|
name: "ask_user",
|
|
121
83
|
label: "Ask User",
|
|
122
84
|
description:
|
|
123
|
-
"Ask the user a structured question (parent session UI).
|
|
85
|
+
"Ask the user a structured question (parent session UI). Plan approval uses approve_plan on the parent orchestrator only.",
|
|
124
86
|
promptSnippet: ASK_PROMPT_SNIPPET,
|
|
125
87
|
promptGuidelines: ASK_PROMPT_GUIDELINES,
|
|
126
88
|
parameters: AskUserParamsSchema,
|
|
@@ -162,137 +124,6 @@ export function createParentHarnessUiBridgeFactory(
|
|
|
162
124
|
return renderAskResult(result, options, theme);
|
|
163
125
|
},
|
|
164
126
|
});
|
|
165
|
-
|
|
166
|
-
if (agentType !== PLANNER_ONLY_AGENT) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
pi.registerTool({
|
|
171
|
-
name: "approve_plan",
|
|
172
|
-
label: "Approve Plan",
|
|
173
|
-
description:
|
|
174
|
-
"Present the full PlanPacket for user approval in the parent TUI (scrollable overlay).",
|
|
175
|
-
promptSnippet: PLAN_PROMPT_SNIPPET,
|
|
176
|
-
promptGuidelines: PLAN_PROMPT_GUIDELINES,
|
|
177
|
-
parameters: ApprovePlanParamsSchema,
|
|
178
|
-
async execute(_toolCallId, params, _signal, _onUpdate) {
|
|
179
|
-
const validated = validateApprovePlanParams(
|
|
180
|
-
params as ApprovePlanParams,
|
|
181
|
-
);
|
|
182
|
-
if (typeof validated === "string") {
|
|
183
|
-
return {
|
|
184
|
-
content: [{ type: "text", text: validated }],
|
|
185
|
-
details: {
|
|
186
|
-
plan_packet: (params as ApprovePlanParams).plan_packet ?? {},
|
|
187
|
-
options: [],
|
|
188
|
-
response: null,
|
|
189
|
-
cancelled: true,
|
|
190
|
-
},
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
hooks?.appendPlanDraft?.({
|
|
195
|
-
plan_packet: validated.plan_packet,
|
|
196
|
-
human_summary: validated.human_summary,
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
let outcome: DialogResult;
|
|
200
|
-
if (parentCtx.hasUI) {
|
|
201
|
-
outcome = await runPlanApprovalDialog(parentCtx.ui, validated);
|
|
202
|
-
} else {
|
|
203
|
-
outcome = await runPlanApprovalFallback(parentCtx.ui, validated);
|
|
204
|
-
}
|
|
205
|
-
const details = toApprovePlanToolDetails(
|
|
206
|
-
validated,
|
|
207
|
-
outcome.response,
|
|
208
|
-
outcome.cancelled,
|
|
209
|
-
);
|
|
210
|
-
notifyPlanApproval(hooks, details, "approve_plan");
|
|
211
|
-
const text = formatApprovePlanResultText(
|
|
212
|
-
outcome.response,
|
|
213
|
-
outcome.cancelled,
|
|
214
|
-
);
|
|
215
|
-
return {
|
|
216
|
-
content: [{ type: "text", text }],
|
|
217
|
-
details,
|
|
218
|
-
};
|
|
219
|
-
},
|
|
220
|
-
renderCall(args, theme) {
|
|
221
|
-
return renderApprovePlanCall(args, theme);
|
|
222
|
-
},
|
|
223
|
-
renderResult(result, options, theme) {
|
|
224
|
-
return renderApprovePlanResult(result, options, theme);
|
|
225
|
-
},
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
pi.registerTool({
|
|
229
|
-
name: "create_plan",
|
|
230
|
-
label: "Create Plan",
|
|
231
|
-
description:
|
|
232
|
-
"Write the approved PlanPacket to the canonical plan-packet.json for this harness run. Requires approve_plan Approve first. Do not use write/edit.",
|
|
233
|
-
promptSnippet: CREATE_PLAN_SNIPPET,
|
|
234
|
-
promptGuidelines: CREATE_PLAN_GUIDELINES,
|
|
235
|
-
parameters: CreatePlanParamsSchema,
|
|
236
|
-
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
237
|
-
const validated = validateApprovePlanParams(
|
|
238
|
-
params as ApprovePlanParams,
|
|
239
|
-
);
|
|
240
|
-
if (typeof validated === "string") {
|
|
241
|
-
return {
|
|
242
|
-
content: [{ type: "text", text: validated }],
|
|
243
|
-
details: { error: validated },
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
const projectRoot = hooks?.projectRoot ?? parentCtx.cwd;
|
|
247
|
-
const parentEntries = hooks?.getParentEntries?.() ?? [];
|
|
248
|
-
const subEntries = ctx.sessionManager.getEntries();
|
|
249
|
-
const result = await executeCreatePlan(validated.plan_packet, {
|
|
250
|
-
projectRoot,
|
|
251
|
-
getParentEntries: () => parentEntries,
|
|
252
|
-
getSubagentEntries: () => subEntries,
|
|
253
|
-
getParentRunContext: () => hooks?.getParentRunContext?.() ?? null,
|
|
254
|
-
onCommitted: (runCtx, packet, planPath) => {
|
|
255
|
-
hooks?.onPlanCommitted?.(runCtx, packet, planPath);
|
|
256
|
-
},
|
|
257
|
-
});
|
|
258
|
-
const text = formatCreatePlanResultText(result);
|
|
259
|
-
return {
|
|
260
|
-
content: [{ type: "text", text }],
|
|
261
|
-
details: result.ok
|
|
262
|
-
? {
|
|
263
|
-
plan_path: result.planPath,
|
|
264
|
-
plan_id: result.planId,
|
|
265
|
-
}
|
|
266
|
-
: { error: result.error },
|
|
267
|
-
isError: !result.ok,
|
|
268
|
-
};
|
|
269
|
-
},
|
|
270
|
-
renderCall(args, theme) {
|
|
271
|
-
const packet = (args as { plan_packet?: PlanPacketLike }).plan_packet;
|
|
272
|
-
const id = packet?.plan_id ?? "?";
|
|
273
|
-
return new Text(theme.fg("accent", `create_plan: ${id}`), 0, 0);
|
|
274
|
-
},
|
|
275
|
-
renderResult(result, _options, theme) {
|
|
276
|
-
const details = result.details as
|
|
277
|
-
| { plan_path?: string; error?: string }
|
|
278
|
-
| undefined;
|
|
279
|
-
if (details?.error) {
|
|
280
|
-
return new Text(
|
|
281
|
-
theme.fg("error", details.error ?? "create_plan failed"),
|
|
282
|
-
0,
|
|
283
|
-
0,
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
return new Text(
|
|
287
|
-
theme.fg(
|
|
288
|
-
"success",
|
|
289
|
-
`Wrote ${details?.plan_path ?? "plan-packet.json"}`,
|
|
290
|
-
),
|
|
291
|
-
0,
|
|
292
|
-
0,
|
|
293
|
-
);
|
|
294
|
-
},
|
|
295
|
-
});
|
|
296
127
|
};
|
|
297
128
|
}
|
|
298
129
|
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
type PlanUserApproval,
|
|
8
8
|
planPacketSummary,
|
|
9
9
|
} from "../../../lib/harness-run-context.js";
|
|
10
|
+
import { writePlanReviewMarkdown } from "../plan-approval/plan-review.js";
|
|
10
11
|
import type { ParentHarnessUiHooks } from "./parent-harness-ui-bridge.js";
|
|
11
12
|
|
|
12
13
|
function persistRunContext(pi: ExtensionAPI, runCtx: HarnessRunContext): void {
|
|
@@ -26,6 +27,23 @@ export function createParentHarnessUiHooks(
|
|
|
26
27
|
const planId = String(draft.plan_packet.plan_id ?? "plan");
|
|
27
28
|
const summary =
|
|
28
29
|
draft.human_summary?.trim() || `Plan ${planId} — pending your approval`;
|
|
30
|
+
const runCtx = getLatestRunContext(getParentEntries());
|
|
31
|
+
void writePlanReviewMarkdown(projectRoot, runCtx, draft.plan_packet, {
|
|
32
|
+
human_summary: draft.human_summary,
|
|
33
|
+
status: "draft",
|
|
34
|
+
}).then((reviewPath) => {
|
|
35
|
+
if (!reviewPath) return;
|
|
36
|
+
pi.sendMessage({
|
|
37
|
+
customType: "harness-plan-review-path",
|
|
38
|
+
content: `Editor review: ${reviewPath}`,
|
|
39
|
+
display: true,
|
|
40
|
+
details: {
|
|
41
|
+
schema_version: "1.0.0",
|
|
42
|
+
plan_review_path: reviewPath,
|
|
43
|
+
plan_id: planId,
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
});
|
|
29
47
|
pi.sendMessage({
|
|
30
48
|
customType: "harness-plan-draft",
|
|
31
49
|
content: summary,
|
|
@@ -10,7 +10,6 @@ export const SUBAGENT_BLOCKED_TOOLS = new Set([
|
|
|
10
10
|
]);
|
|
11
11
|
|
|
12
12
|
const ASK_USER_ALLOWED_AGENT_TYPES = new Set([
|
|
13
|
-
"harness/planner",
|
|
14
13
|
"harness/evaluator",
|
|
15
14
|
"harness/adversary",
|
|
16
15
|
"harness/tie-breaker",
|
|
@@ -42,12 +41,9 @@ export function evaluateSubagentToolCall(
|
|
|
42
41
|
};
|
|
43
42
|
}
|
|
44
43
|
if (toolName === "approve_plan" || toolName === "create_plan") {
|
|
45
|
-
if (agentType === "harness/planner") {
|
|
46
|
-
return { action: "allow" };
|
|
47
|
-
}
|
|
48
44
|
return {
|
|
49
45
|
action: "block",
|
|
50
|
-
reason: `Tool "${toolName}" is only available
|
|
46
|
+
reason: `Tool "${toolName}" is only available in the parent harness orchestrator session.`,
|
|
51
47
|
};
|
|
52
48
|
}
|
|
53
49
|
return { action: "allow" };
|
|
@@ -420,13 +420,6 @@ export async function runAgent(
|
|
|
420
420
|
names.filter((t) => {
|
|
421
421
|
if (EXCLUDED_TOOL_NAMES.includes(t)) return false;
|
|
422
422
|
if (t === "ask_user" && harnessUiBridge) return true;
|
|
423
|
-
if (
|
|
424
|
-
(t === "approve_plan" || t === "create_plan") &&
|
|
425
|
-
harnessUiBridge &&
|
|
426
|
-
type === "harness/planner"
|
|
427
|
-
) {
|
|
428
|
-
return true;
|
|
429
|
-
}
|
|
430
423
|
if (disallowedSet?.has(t)) return false;
|
|
431
424
|
if (builtinToolNameSet.has(t)) return true;
|
|
432
425
|
if (extensions === false) return false;
|
|
@@ -442,13 +435,6 @@ export async function runAgent(
|
|
|
442
435
|
} else {
|
|
443
436
|
const fallback = toolNames.filter((t) => {
|
|
444
437
|
if (t === "ask_user" && harnessUiBridge) return true;
|
|
445
|
-
if (
|
|
446
|
-
(t === "approve_plan" || t === "create_plan") &&
|
|
447
|
-
harnessUiBridge &&
|
|
448
|
-
type === "harness/planner"
|
|
449
|
-
) {
|
|
450
|
-
return true;
|
|
451
|
-
}
|
|
452
438
|
return !disallowedSet?.has(t);
|
|
453
439
|
});
|
|
454
440
|
session.setActiveToolsByName(fallback);
|
|
@@ -470,10 +456,6 @@ export async function runAgent(
|
|
|
470
456
|
if (harnessUiBridge) {
|
|
471
457
|
const withHarnessUi = new Set(session.getActiveToolNames());
|
|
472
458
|
withHarnessUi.add("ask_user");
|
|
473
|
-
if (type === "harness/planner") {
|
|
474
|
-
withHarnessUi.add("approve_plan");
|
|
475
|
-
withHarnessUi.add("create_plan");
|
|
476
|
-
}
|
|
477
459
|
session.setActiveToolsByName([...withHarnessUi]);
|
|
478
460
|
}
|
|
479
461
|
|
|
@@ -17,10 +17,7 @@ import {
|
|
|
17
17
|
} from "@earendil-works/pi-coding-agent";
|
|
18
18
|
import { Text } from "@earendil-works/pi-tui";
|
|
19
19
|
import { Type } from "@sinclair/typebox";
|
|
20
|
-
import {
|
|
21
|
-
getLatestRunContext,
|
|
22
|
-
syncPlannerApprovalsToParent,
|
|
23
|
-
} from "../../../../lib/harness-run-context.js";
|
|
20
|
+
import { getLatestRunContext } from "../../../../lib/harness-run-context.js";
|
|
24
21
|
import { getDriftReport } from "../agent-manifest.js";
|
|
25
22
|
import { Blackboard } from "../blackboard.js";
|
|
26
23
|
import {
|
|
@@ -759,7 +756,9 @@ export function createHarnessSubagentsExtension(packageRoot: string) {
|
|
|
759
756
|
});
|
|
760
757
|
|
|
761
758
|
// Live widget: show running agents above editor
|
|
762
|
-
const widget = new AgentWidget(manager, agentActivity)
|
|
759
|
+
const widget = new AgentWidget(manager, agentActivity, () => {
|
|
760
|
+
pi.events.emit("subagents:agents-widget-mounted", {});
|
|
761
|
+
});
|
|
763
762
|
|
|
764
763
|
// ---- Join mode configuration ----
|
|
765
764
|
let defaultJoinMode: JoinMode = "smart";
|
|
@@ -1501,24 +1500,6 @@ Guidelines:
|
|
|
1501
1500
|
|
|
1502
1501
|
clearInterval(spinnerInterval);
|
|
1503
1502
|
|
|
1504
|
-
if (
|
|
1505
|
-
subagentType === "harness/planner" &&
|
|
1506
|
-
record.session &&
|
|
1507
|
-
record.status !== "running" &&
|
|
1508
|
-
record.status !== "queued"
|
|
1509
|
-
) {
|
|
1510
|
-
const parentEntries = ctx.sessionManager.getEntries();
|
|
1511
|
-
const runCtx = getLatestRunContext(parentEntries);
|
|
1512
|
-
if (runCtx) {
|
|
1513
|
-
syncPlannerApprovalsToParent(
|
|
1514
|
-
(type, data) => pi.appendEntry(type, data),
|
|
1515
|
-
parentEntries,
|
|
1516
|
-
record.session.sessionManager.getEntries(),
|
|
1517
|
-
runCtx,
|
|
1518
|
-
);
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
|
|
1522
1503
|
// Clean up foreground agent from widget
|
|
1523
1504
|
if (fgId) {
|
|
1524
1505
|
agentActivity.delete(fgId);
|
|
@@ -1631,19 +1612,6 @@ Guidelines:
|
|
|
1631
1612
|
cancelNudge(params.agent_id);
|
|
1632
1613
|
}
|
|
1633
1614
|
|
|
1634
|
-
if (record.session && record.status !== "running") {
|
|
1635
|
-
const parentEntries = _ctx.sessionManager.getEntries();
|
|
1636
|
-
const runCtx = getLatestRunContext(parentEntries);
|
|
1637
|
-
if (runCtx) {
|
|
1638
|
-
syncPlannerApprovalsToParent(
|
|
1639
|
-
(type, data) => pi.appendEntry(type, data),
|
|
1640
|
-
parentEntries,
|
|
1641
|
-
record.session.sessionManager.getEntries(),
|
|
1642
|
-
runCtx,
|
|
1643
|
-
);
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
|
|
1647
1615
|
// Verbose: include full conversation
|
|
1648
1616
|
if (params.verbose && record.session) {
|
|
1649
1617
|
const conversation = getAgentConversation(record.session);
|
|
@@ -264,6 +264,7 @@ export class AgentWidget {
|
|
|
264
264
|
constructor(
|
|
265
265
|
private manager: AgentManager,
|
|
266
266
|
private agentActivity: Map<string, AgentActivity>,
|
|
267
|
+
private onWidgetRegistered?: () => void,
|
|
267
268
|
) {}
|
|
268
269
|
|
|
269
270
|
/** Set the UI context (grabbed from first tool execution). */
|
|
@@ -615,6 +616,7 @@ export class AgentWidget {
|
|
|
615
616
|
{ placement: "aboveEditor" },
|
|
616
617
|
);
|
|
617
618
|
this.widgetRegistered = true;
|
|
619
|
+
this.onWidgetRegistered?.();
|
|
618
620
|
} else {
|
|
619
621
|
// Widget already registered — just request a re-render of existing components.
|
|
620
622
|
this.tui?.requestRender();
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
saveRunContextToDisk,
|
|
10
10
|
validatePlanPacket,
|
|
11
11
|
} from "../../../lib/harness-run-context.js";
|
|
12
|
+
import { writePlanReviewMarkdown } from "./plan-review.js";
|
|
12
13
|
|
|
13
14
|
export const CREATE_PLAN_SNIPPET =
|
|
14
15
|
"create_plan({ plan_packet: { ...approved PlanPacket } })";
|
|
@@ -116,6 +117,10 @@ export async function executeCreatePlan(
|
|
|
116
117
|
/* disk mirror best-effort */
|
|
117
118
|
}
|
|
118
119
|
|
|
120
|
+
await writePlanReviewMarkdown(deps.projectRoot, updated, planPacket, {
|
|
121
|
+
status: "committed",
|
|
122
|
+
});
|
|
123
|
+
|
|
119
124
|
deps.onCommitted(updated, planPacket, planPath);
|
|
120
125
|
|
|
121
126
|
return {
|