@dreki-gg/pi-plan-mode 0.6.0 → 0.6.2
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/CHANGELOG.md +16 -0
- package/extensions/plan-mode/index.ts +12 -19
- package/extensions/plan-mode/plans-json.ts +5 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @dreki-gg/pi-plan-mode
|
|
2
2
|
|
|
3
|
+
## 0.6.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`376864c`](https://github.com/dreki-gg/pi-extensions/commit/376864c37cefa47530363b47055311269c1724a8) Thanks [@jalbarrang](https://github.com/jalbarrang)! - fix(plan-mode): queue messages with deliverAs to prevent "agent already processing" errors
|
|
8
|
+
|
|
9
|
+
All `sendMessage` and `sendUserMessage` calls inside the `agent_end` handler now use `deliverAs: 'followUp'` so they are queued until the agent fully settles. Previously, "Follow up", "Refine Plan", and "Execute Plan" would fire while the agent was still in a processing state, causing silent failures or the error: "Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message."
|
|
10
|
+
|
|
11
|
+
## 0.6.1
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [`d95dad2`](https://github.com/dreki-gg/pi-extensions/commit/d95dad2ac85c4e5428252ee691152a0db83a0ced) Thanks [@jalbarrang](https://github.com/jalbarrang)! - fix(plan-mode): replace Bun-specific APIs with Node.js `fs/promises`
|
|
16
|
+
|
|
17
|
+
`pi` runs under Node.js (`#!/usr/bin/env node`), so `Bun.file()` and `Bun.write()` are unavailable at runtime. Replaced all usages with `readFile` and `writeFile` from `node:fs/promises`, which work in both runtimes.
|
|
18
|
+
|
|
3
19
|
## 0.6.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
|
@@ -22,13 +22,8 @@ import type { AgentMessage } from '@earendil-works/pi-agent-core';
|
|
|
22
22
|
import type { AssistantMessage, TextContent } from '@earendil-works/pi-ai';
|
|
23
23
|
import type { ExtensionAPI, ExtensionContext } from '@earendil-works/pi-coding-agent';
|
|
24
24
|
import { Key } from '@earendil-works/pi-tui';
|
|
25
|
-
import { mkdir } from 'node:fs/promises';
|
|
26
|
-
import {
|
|
27
|
-
extractTodoItems,
|
|
28
|
-
isSafeCommand,
|
|
29
|
-
markCompletedSteps,
|
|
30
|
-
type TodoItem,
|
|
31
|
-
} from './utils.js';
|
|
25
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
26
|
+
import { extractTodoItems, isSafeCommand, markCompletedSteps, type TodoItem } from './utils.js';
|
|
32
27
|
import {
|
|
33
28
|
extractPlanTitle,
|
|
34
29
|
readPlansJson,
|
|
@@ -125,7 +120,7 @@ export default function planMode(pi: ExtensionAPI): void {
|
|
|
125
120
|
|
|
126
121
|
await mkdir('.plans', { recursive: true });
|
|
127
122
|
const content = serializePlansJson(manifest);
|
|
128
|
-
await
|
|
123
|
+
await writeFile('.plans/plans.json', content, 'utf-8');
|
|
129
124
|
}
|
|
130
125
|
|
|
131
126
|
// ── UI updates ────────────────────────────────────────────────────────────
|
|
@@ -253,9 +248,7 @@ export default function planMode(pi: ExtensionAPI): void {
|
|
|
253
248
|
ctx.ui.notify('No plan yet. Use /plan to start planning.', 'info');
|
|
254
249
|
return;
|
|
255
250
|
}
|
|
256
|
-
const list = todos
|
|
257
|
-
.map((t, i) => `${i + 1}. ${t.completed ? '✓' : '○'} ${t.text}`)
|
|
258
|
-
.join('\n');
|
|
251
|
+
const list = todos.map((t, i) => `${i + 1}. ${t.completed ? '✓' : '○'} ${t.text}`).join('\n');
|
|
259
252
|
ctx.ui.notify(`Plan Progress:\n${list}`, 'info');
|
|
260
253
|
},
|
|
261
254
|
});
|
|
@@ -419,7 +412,7 @@ Execute each step in order. You MUST include [DONE:n] in your response after com
|
|
|
419
412
|
let title = 'Untitled plan';
|
|
420
413
|
if (path.endsWith('PLAN.md')) {
|
|
421
414
|
try {
|
|
422
|
-
const content = await
|
|
415
|
+
const content = await readFile(path, 'utf-8');
|
|
423
416
|
title = extractPlanTitle(content);
|
|
424
417
|
} catch {
|
|
425
418
|
// Fall through
|
|
@@ -430,7 +423,7 @@ Execute each step in order. You MUST include [DONE:n] in your response after com
|
|
|
430
423
|
} else if (match && planDir && path.endsWith('PLAN.md')) {
|
|
431
424
|
// planDir already set but PLAN.md just written — update title
|
|
432
425
|
try {
|
|
433
|
-
const content = await
|
|
426
|
+
const content = await readFile(path, 'utf-8');
|
|
434
427
|
const title = extractPlanTitle(content);
|
|
435
428
|
await updatePlansManifest(match[1], 'in-progress', title);
|
|
436
429
|
} catch {
|
|
@@ -496,7 +489,7 @@ Execute each step in order. You MUST include [DONE:n] in your response after com
|
|
|
496
489
|
// Read the plan to extract todos
|
|
497
490
|
let planContent = '';
|
|
498
491
|
try {
|
|
499
|
-
planContent = await
|
|
492
|
+
planContent = await readFile(planMdPath, 'utf-8');
|
|
500
493
|
} catch {
|
|
501
494
|
// Fall through — will use empty plan content
|
|
502
495
|
}
|
|
@@ -509,7 +502,7 @@ Execute each step in order. You MUST include [DONE:n] in your response after com
|
|
|
509
502
|
// Read the start prompt for clean handoff
|
|
510
503
|
let startPrompt = '';
|
|
511
504
|
try {
|
|
512
|
-
startPrompt = (await
|
|
505
|
+
startPrompt = (await readFile(startPromptPath, 'utf-8')).trim();
|
|
513
506
|
} catch {
|
|
514
507
|
// Fall through
|
|
515
508
|
}
|
|
@@ -524,7 +517,7 @@ Execute each step in order. You MUST include [DONE:n] in your response after com
|
|
|
524
517
|
content: startPrompt,
|
|
525
518
|
display: true,
|
|
526
519
|
},
|
|
527
|
-
{ triggerTurn: true },
|
|
520
|
+
{ triggerTurn: true, deliverAs: 'followUp' },
|
|
528
521
|
);
|
|
529
522
|
} else {
|
|
530
523
|
// Fallback: ask executor to read the plan
|
|
@@ -534,7 +527,7 @@ Execute each step in order. You MUST include [DONE:n] in your response after com
|
|
|
534
527
|
content: `Execute the plan in ${planMdPath}. Read it first, then execute step by step. Mark each step with [DONE:n] before moving to the next.`,
|
|
535
528
|
display: true,
|
|
536
529
|
},
|
|
537
|
-
{ triggerTurn: true },
|
|
530
|
+
{ triggerTurn: true, deliverAs: 'followUp' },
|
|
538
531
|
);
|
|
539
532
|
}
|
|
540
533
|
} else if (choice === 'Refine Plan') {
|
|
@@ -553,12 +546,12 @@ Execute each step in order. You MUST include [DONE:n] in your response after com
|
|
|
553
546
|
After your review, update PLAN.md and START-PROMPT.md with any improvements.`,
|
|
554
547
|
display: true,
|
|
555
548
|
},
|
|
556
|
-
{ triggerTurn: true },
|
|
549
|
+
{ triggerTurn: true, deliverAs: 'followUp' },
|
|
557
550
|
);
|
|
558
551
|
} else if (choice === 'Follow up') {
|
|
559
552
|
const followUp = await ctx.ui.editor('Follow-up instructions for the planner:', '');
|
|
560
553
|
if (followUp?.trim()) {
|
|
561
|
-
pi.sendUserMessage(followUp.trim());
|
|
554
|
+
pi.sendUserMessage(followUp.trim(), { deliverAs: 'followUp' });
|
|
562
555
|
}
|
|
563
556
|
} else if (choice === 'Exit plan mode') {
|
|
564
557
|
await exitPlanMode(ctx);
|
|
@@ -23,17 +23,16 @@ export interface PlanEntry {
|
|
|
23
23
|
|
|
24
24
|
export type PlansManifest = Record<string, PlanEntry>;
|
|
25
25
|
|
|
26
|
+
import { readFile } from 'node:fs/promises';
|
|
27
|
+
|
|
26
28
|
const PLANS_JSON = '.plans/plans.json';
|
|
27
29
|
|
|
28
30
|
/** Read plans.json, returning current manifest (empty object if missing). */
|
|
29
31
|
export async function readPlansJson(): Promise<PlansManifest> {
|
|
30
32
|
try {
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
if (text.trim()) {
|
|
35
|
-
return JSON.parse(text) as PlansManifest;
|
|
36
|
-
}
|
|
33
|
+
const text = await readFile(PLANS_JSON, 'utf-8');
|
|
34
|
+
if (text.trim()) {
|
|
35
|
+
return JSON.parse(text) as PlansManifest;
|
|
37
36
|
}
|
|
38
37
|
} catch {
|
|
39
38
|
// File doesn't exist or isn't valid JSON
|
package/package.json
CHANGED