pi-plan-task 1.0.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 +100 -0
- package/extensions/ask-question.test.ts +91 -0
- package/extensions/ask-question.ts +145 -0
- package/extensions/bash-guard.test.ts +17 -0
- package/extensions/bash-guard.ts +94 -0
- package/extensions/config.ts +49 -0
- package/extensions/files.test.ts +59 -0
- package/extensions/files.ts +50 -0
- package/extensions/framing.test.ts +85 -0
- package/extensions/framing.ts +79 -0
- package/extensions/index.ts +549 -0
- package/extensions/parse.ts +88 -0
- package/extensions/paths.ts +39 -0
- package/extensions/plan-input.test.ts +142 -0
- package/extensions/plan-input.ts +162 -0
- package/extensions/planning-and-task-breakdown.md +287 -0
- package/extensions/planning-method.test.ts +20 -0
- package/extensions/planning-method.ts +38 -0
- package/extensions/prompts.test.ts +70 -0
- package/extensions/prompts.ts +87 -0
- package/extensions/types.ts +26 -0
- package/package.json +18 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
# Planning and Task Breakdown
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Decompose work into small, verifiable tasks with explicit acceptance criteria. Good task breakdown is the difference between an agent that completes work reliably and one that produces a tangled mess. Every task should be small enough to implement, test, and verify in a single focused session.
|
|
6
|
+
|
|
7
|
+
## When to Use
|
|
8
|
+
|
|
9
|
+
- You have a spec and need to break it into implementable units
|
|
10
|
+
- A task feels too large or vague to start
|
|
11
|
+
- Work needs to be parallelized across multiple agents or sessions
|
|
12
|
+
- You need to communicate scope to a human
|
|
13
|
+
- The implementation order isn't obvious
|
|
14
|
+
|
|
15
|
+
**When NOT to use:** Single-file changes with obvious scope, or when the spec already contains well-defined tasks.
|
|
16
|
+
|
|
17
|
+
## The Planning Process
|
|
18
|
+
|
|
19
|
+
### Step 1: Enter Plan Mode
|
|
20
|
+
|
|
21
|
+
Before writing any code, operate in read-only mode:
|
|
22
|
+
|
|
23
|
+
- Read the spec and relevant codebase sections
|
|
24
|
+
- Identify existing patterns and conventions
|
|
25
|
+
- Map dependencies between components
|
|
26
|
+
- Note risks and unknowns
|
|
27
|
+
|
|
28
|
+
**Do NOT write code during planning.** The output is a plan document saved to `.plan_task/plan.md` and a task list saved to `.plan_task/task.md`, not implementation.
|
|
29
|
+
|
|
30
|
+
### Step 2: Identify the Dependency Graph
|
|
31
|
+
|
|
32
|
+
Map what depends on what:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
Database schema
|
|
36
|
+
│
|
|
37
|
+
├── API models/types
|
|
38
|
+
│ │
|
|
39
|
+
│ ├── API endpoints
|
|
40
|
+
│ │ │
|
|
41
|
+
│ │ └── Frontend API client
|
|
42
|
+
│ │ │
|
|
43
|
+
│ │ └── UI components
|
|
44
|
+
│ │
|
|
45
|
+
│ └── Validation logic
|
|
46
|
+
│
|
|
47
|
+
└── Seed data / migrations
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Implementation order follows the dependency graph bottom-up: build foundations first.
|
|
51
|
+
|
|
52
|
+
### Step 3: Slice Vertically
|
|
53
|
+
|
|
54
|
+
Instead of building all the database, then all the API, then all the UI — build one complete feature path at a time:
|
|
55
|
+
|
|
56
|
+
**Bad (horizontal slicing):**
|
|
57
|
+
```
|
|
58
|
+
Task 1: Build entire database schema
|
|
59
|
+
Task 2: Build all API endpoints
|
|
60
|
+
Task 3: Build all UI components
|
|
61
|
+
Task 4: Connect everything
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Good (vertical slicing):**
|
|
65
|
+
```
|
|
66
|
+
Task 1: User can create an account (schema + API + UI for registration)
|
|
67
|
+
Task 2: User can log in (auth schema + API + UI for login)
|
|
68
|
+
Task 3: User can create a task (task schema + API + UI for creation)
|
|
69
|
+
Task 4: User can view task list (query + API + UI for list view)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Each vertical slice delivers working, testable functionality.
|
|
73
|
+
|
|
74
|
+
### Step 4: Write Tasks
|
|
75
|
+
|
|
76
|
+
Each task follows this structure:
|
|
77
|
+
|
|
78
|
+
```markdown
|
|
79
|
+
## Task [N]: [Short descriptive title]
|
|
80
|
+
|
|
81
|
+
**Description:** One paragraph explaining what this task accomplishes.
|
|
82
|
+
|
|
83
|
+
**Acceptance criteria:**
|
|
84
|
+
- [ ] [Specific, testable condition]
|
|
85
|
+
- [ ] [Specific, testable condition]
|
|
86
|
+
|
|
87
|
+
**Verification:**
|
|
88
|
+
- [ ] Tests pass: [the repository's focused-test command]
|
|
89
|
+
- [ ] Build succeeds: [the repository's build command]
|
|
90
|
+
- [ ] Manual check: [description of what to verify]
|
|
91
|
+
|
|
92
|
+
**Dependencies:** [Task numbers this depends on, or "None"]
|
|
93
|
+
|
|
94
|
+
**Files likely touched:**
|
|
95
|
+
- `src/path/to/file.ts`
|
|
96
|
+
- `tests/path/to/test.ts`
|
|
97
|
+
|
|
98
|
+
**Estimated scope:** [Small: 1-2 files | Medium: 3-5 files | Large: 5+ files]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Step 5: Order and Checkpoint
|
|
102
|
+
|
|
103
|
+
Arrange tasks so that:
|
|
104
|
+
|
|
105
|
+
1. Dependencies are satisfied (build foundation first)
|
|
106
|
+
2. Each task leaves the system in a working state
|
|
107
|
+
3. Verification checkpoints occur after every 2-3 tasks
|
|
108
|
+
4. High-risk tasks are early (fail fast)
|
|
109
|
+
|
|
110
|
+
Add explicit checkpoints to the task list:
|
|
111
|
+
|
|
112
|
+
```markdown
|
|
113
|
+
## Checkpoint: After Tasks 1-3
|
|
114
|
+
- [ ] All tests pass
|
|
115
|
+
- [ ] Application builds without errors
|
|
116
|
+
- [ ] Core user flow works end-to-end
|
|
117
|
+
- [ ] Review with human before proceeding
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Task Sizing Guidelines
|
|
121
|
+
|
|
122
|
+
| Size | Files | Scope | Example |
|
|
123
|
+
|------|-------|-------|---------|
|
|
124
|
+
| **XS** | 1 | Single function or config change | Add a validation rule |
|
|
125
|
+
| **S** | 1-2 | One component or endpoint | Add a new API endpoint |
|
|
126
|
+
| **M** | 3-5 | One feature slice | User registration flow |
|
|
127
|
+
| **L** | 5-8 | Multi-component feature | Search with filtering and pagination |
|
|
128
|
+
| **XL** | 8+ | **Too large — break it down further** | — |
|
|
129
|
+
|
|
130
|
+
If a task is L or larger, it should be broken into smaller tasks. An agent performs best on S and M tasks.
|
|
131
|
+
|
|
132
|
+
**When to break a task down further:**
|
|
133
|
+
- It would take more than one focused session (roughly 2+ hours of agent work)
|
|
134
|
+
- You cannot describe the acceptance criteria in 3 or fewer bullet points
|
|
135
|
+
- It touches two or more independent subsystems (e.g., auth and billing)
|
|
136
|
+
- You find yourself writing "and" in the task title (a sign it is two tasks)
|
|
137
|
+
|
|
138
|
+
## Output Files
|
|
139
|
+
|
|
140
|
+
- **Plan document:** Save the implementation plan to `.plan_task/plan.md`. This is always a markdown file — design decisions, risks, and open questions don't map cleanly onto individual tracker issues.
|
|
141
|
+
- **Task list:** Record each task in `.plan_task/task.md`.
|
|
142
|
+
|
|
143
|
+
Create the `.plan_task/` directory if it does not exist.
|
|
144
|
+
|
|
145
|
+
The checklist at the top of `.plan_task/task.md` is the source of truth for `/build`. Keep items in the form `- [ ] N. Title` so later sessions can resume.
|
|
146
|
+
|
|
147
|
+
After the checklist, write one `## Task [N]:` section per item using the Step 4 structure. Put `## Checkpoint:` sections after the tasks they cover, not in the top checklist.
|
|
148
|
+
|
|
149
|
+
Example `.plan_task/task.md`:
|
|
150
|
+
|
|
151
|
+
```markdown
|
|
152
|
+
- [ ] 1. User can create an account
|
|
153
|
+
- [ ] 2. User can log in
|
|
154
|
+
|
|
155
|
+
## Task 1: User can create an account
|
|
156
|
+
|
|
157
|
+
**Description:** Registration schema, API, and UI as one vertical slice.
|
|
158
|
+
|
|
159
|
+
**Acceptance criteria:**
|
|
160
|
+
- [ ] A new user can register with email and password
|
|
161
|
+
- [ ] Duplicate emails are rejected
|
|
162
|
+
|
|
163
|
+
**Verification:**
|
|
164
|
+
- [ ] Tests pass: [the repository's focused-test command]
|
|
165
|
+
- [ ] Build succeeds: [the repository's build command]
|
|
166
|
+
- [ ] Manual check: submit the registration form
|
|
167
|
+
|
|
168
|
+
**Dependencies:** None
|
|
169
|
+
|
|
170
|
+
**Files likely touched:**
|
|
171
|
+
- `src/auth/register.ts`
|
|
172
|
+
- `tests/auth/register.test.ts`
|
|
173
|
+
|
|
174
|
+
**Estimated scope:** Medium: 3-5 files
|
|
175
|
+
|
|
176
|
+
## Task 2: User can log in
|
|
177
|
+
|
|
178
|
+
**Description:** Auth session API and login UI.
|
|
179
|
+
|
|
180
|
+
**Acceptance criteria:**
|
|
181
|
+
- [ ] Valid credentials create a session
|
|
182
|
+
- [ ] Invalid credentials are rejected
|
|
183
|
+
|
|
184
|
+
**Verification:**
|
|
185
|
+
- [ ] Tests pass: [the repository's focused-test command]
|
|
186
|
+
- [ ] Manual check: log in with the account from Task 1
|
|
187
|
+
|
|
188
|
+
**Dependencies:** 1
|
|
189
|
+
|
|
190
|
+
**Files likely touched:**
|
|
191
|
+
- `src/auth/login.ts`
|
|
192
|
+
- `tests/auth/login.test.ts`
|
|
193
|
+
|
|
194
|
+
**Estimated scope:** Small: 1-2 files
|
|
195
|
+
|
|
196
|
+
## Checkpoint: After Tasks 1-2
|
|
197
|
+
- [ ] Registration and login work end-to-end
|
|
198
|
+
- [ ] Review with human before proceeding
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Plan Document Template
|
|
202
|
+
|
|
203
|
+
```markdown
|
|
204
|
+
# Implementation Plan: [Feature/Project Name]
|
|
205
|
+
|
|
206
|
+
## Overview
|
|
207
|
+
[One paragraph summary of what we're building]
|
|
208
|
+
|
|
209
|
+
## Architecture Decisions
|
|
210
|
+
- [Key decision 1 and rationale]
|
|
211
|
+
- [Key decision 2 and rationale]
|
|
212
|
+
|
|
213
|
+
## Task List
|
|
214
|
+
|
|
215
|
+
### Phase 1: Foundation
|
|
216
|
+
- [ ] 1. ...
|
|
217
|
+
- [ ] 2. ...
|
|
218
|
+
|
|
219
|
+
### Checkpoint: Foundation
|
|
220
|
+
- [ ] Tests pass, builds clean
|
|
221
|
+
|
|
222
|
+
### Phase 2: Core Features
|
|
223
|
+
- [ ] 3. ...
|
|
224
|
+
- [ ] 4. ...
|
|
225
|
+
|
|
226
|
+
### Checkpoint: Core Features
|
|
227
|
+
- [ ] End-to-end flow works
|
|
228
|
+
|
|
229
|
+
### Phase 3: Polish
|
|
230
|
+
- [ ] 5. ...
|
|
231
|
+
- [ ] 6. ...
|
|
232
|
+
|
|
233
|
+
### Checkpoint: Complete
|
|
234
|
+
- [ ] All acceptance criteria met
|
|
235
|
+
- [ ] Ready for review
|
|
236
|
+
|
|
237
|
+
## Risks and Mitigations
|
|
238
|
+
| Risk | Impact | Mitigation |
|
|
239
|
+
|------|--------|------------|
|
|
240
|
+
| [Risk] | [High/Med/Low] | [Strategy] |
|
|
241
|
+
|
|
242
|
+
## Open Questions
|
|
243
|
+
- [Question needing human input]
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Parallelization Opportunities
|
|
247
|
+
|
|
248
|
+
When multiple agents or sessions are available:
|
|
249
|
+
|
|
250
|
+
- **Safe to parallelize:** Independent feature slices, tests for already-implemented features, documentation
|
|
251
|
+
- **Must be sequential:** Database migrations, shared state changes, dependency chains
|
|
252
|
+
- **Needs coordination:** Features that share an API contract (define the contract first, then parallelize)
|
|
253
|
+
|
|
254
|
+
## Common Rationalizations
|
|
255
|
+
|
|
256
|
+
| Rationalization | Reality |
|
|
257
|
+
|---|---|
|
|
258
|
+
| "I'll figure it out as I go" | That's how you end up with a tangled mess and rework. 10 minutes of planning saves hours. |
|
|
259
|
+
| "The tasks are obvious" | Write them down anyway. Explicit tasks surface hidden dependencies and forgotten edge cases. |
|
|
260
|
+
| "Planning is overhead" | Planning is the task. Implementation without a plan is just typing. |
|
|
261
|
+
| "I can hold it all in my head" | Context windows are finite. Written plans survive session boundaries and compaction. |
|
|
262
|
+
|
|
263
|
+
## Red Flags
|
|
264
|
+
|
|
265
|
+
- Starting implementation without a written task list
|
|
266
|
+
- Writing tasks somewhere other than `.plan_task/task.md`
|
|
267
|
+
- Tasks that say "implement the feature" without acceptance criteria
|
|
268
|
+
- No verification steps in the plan
|
|
269
|
+
- All tasks are XL-sized
|
|
270
|
+
- No checkpoints between tasks
|
|
271
|
+
- Dependency order isn't considered
|
|
272
|
+
|
|
273
|
+
## Verification
|
|
274
|
+
|
|
275
|
+
Before starting implementation, confirm:
|
|
276
|
+
|
|
277
|
+
- [ ] Every task has acceptance criteria
|
|
278
|
+
- [ ] Every task has a verification step
|
|
279
|
+
- [ ] Task dependencies are identified and ordered correctly
|
|
280
|
+
- [ ] Tasks are recorded in `.plan_task/task.md`
|
|
281
|
+
- [ ] No task touches more than ~5 files
|
|
282
|
+
- [ ] Checkpoints exist between major phases
|
|
283
|
+
- [ ] The human has reviewed and approved the plan
|
|
284
|
+
|
|
285
|
+
## See Also
|
|
286
|
+
|
|
287
|
+
Acceptance criteria are per-task and answer "did we build the right thing?". They sit on top of any project-wide Definition of Done, the standing bar every task clears before it counts as done.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { loadPlanningMethod, PLANNING_METHOD_HEADINGS } from "./planning-method.ts";
|
|
4
|
+
|
|
5
|
+
describe("loadPlanningMethod", () => {
|
|
6
|
+
it("keeps the same section headings as planning-and-task-breakdown.md", () => {
|
|
7
|
+
const method = loadPlanningMethod();
|
|
8
|
+
let cursor = 0;
|
|
9
|
+
for (const heading of PLANNING_METHOD_HEADINGS) {
|
|
10
|
+
const index = method.indexOf(heading, cursor);
|
|
11
|
+
assert.notEqual(index, -1, `missing heading: ${heading}`);
|
|
12
|
+
cursor = index + heading.length;
|
|
13
|
+
}
|
|
14
|
+
assert.doesNotMatch(method, /^---/);
|
|
15
|
+
assert.doesNotMatch(method, /This skill/);
|
|
16
|
+
assert.doesNotMatch(method, /tasks\/todo\.md/);
|
|
17
|
+
assert.match(method, /\.plan_task\/plan\.md/);
|
|
18
|
+
assert.match(method, /\.plan_task\/task\.md/);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* /plan methodology file.
|
|
7
|
+
*
|
|
8
|
+
* Section headings match `planning-and-task-breakdown.md` at the workspace
|
|
9
|
+
* root so later updates can be copied section-by-section from that file.
|
|
10
|
+
*
|
|
11
|
+
* Plan-task-only adaptations (do not copy these from the source blindly):
|
|
12
|
+
* - Output paths are `.plan_task/plan.md` and `.plan_task/task.md`
|
|
13
|
+
* - Checklist items must be `- [ ] N. Title`
|
|
14
|
+
* - No external tracker, no skill frontmatter, no definition-of-done.md link
|
|
15
|
+
*/
|
|
16
|
+
export const PLANNING_METHOD_FILE = resolve(
|
|
17
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
18
|
+
"planning-and-task-breakdown.md",
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
export const PLANNING_METHOD_HEADINGS = [
|
|
22
|
+
"# Planning and Task Breakdown",
|
|
23
|
+
"## Overview",
|
|
24
|
+
"## When to Use",
|
|
25
|
+
"## The Planning Process",
|
|
26
|
+
"## Task Sizing Guidelines",
|
|
27
|
+
"## Output Files",
|
|
28
|
+
"## Plan Document Template",
|
|
29
|
+
"## Parallelization Opportunities",
|
|
30
|
+
"## Common Rationalizations",
|
|
31
|
+
"## Red Flags",
|
|
32
|
+
"## Verification",
|
|
33
|
+
"## See Also",
|
|
34
|
+
] as const;
|
|
35
|
+
|
|
36
|
+
export function loadPlanningMethod(): string {
|
|
37
|
+
return readFileSync(PLANNING_METHOD_FILE, "utf8").trim();
|
|
38
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { PLANNING_METHOD_HEADINGS } from "./planning-method.ts";
|
|
4
|
+
import { buildPrompt, buildRequest, buildStatus, buildStatusKey, planPrompt, planRequest } from "./prompts.ts";
|
|
5
|
+
|
|
6
|
+
describe("planPrompt", () => {
|
|
7
|
+
it("injects the request, runtime rules, and planning method headings", () => {
|
|
8
|
+
const source = { kind: "prompt" as const, prompt: "Add login" };
|
|
9
|
+
const prompt = planPrompt(source);
|
|
10
|
+
assert.equal(planRequest(source), "Add login");
|
|
11
|
+
assert.match(prompt, /Request:\nAdd login/);
|
|
12
|
+
assert.match(prompt, /Runtime rules:/);
|
|
13
|
+
assert.match(prompt, /\.plan_task\/plan\.md/);
|
|
14
|
+
assert.match(prompt, /\.plan_task\/task\.md/);
|
|
15
|
+
assert.match(prompt, /- \[ \] N\. Title/);
|
|
16
|
+
for (const heading of PLANNING_METHOD_HEADINGS) {
|
|
17
|
+
assert.match(prompt, new RegExp(heading.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")));
|
|
18
|
+
}
|
|
19
|
+
assert.doesNotMatch(prompt, /Planning skill/);
|
|
20
|
+
assert.doesNotMatch(prompt, /tasks\/todo\.md/);
|
|
21
|
+
assert.match(prompt, /ask_user_question/);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("inlines a spec file and extra notes", () => {
|
|
25
|
+
const prompt = planPrompt({
|
|
26
|
+
kind: "file",
|
|
27
|
+
displayPath: "docs/spec.md",
|
|
28
|
+
resolvedPath: "/tmp/docs/spec.md",
|
|
29
|
+
notes: "focus on OAuth",
|
|
30
|
+
content: "# Auth\nAdd login.",
|
|
31
|
+
});
|
|
32
|
+
assert.match(prompt, /Request:\nWrite a plan from docs\/spec\.md\.\n\nfocus on OAuth/);
|
|
33
|
+
assert.match(prompt, /Spec file \(docs\/spec\.md\):/);
|
|
34
|
+
assert.match(prompt, /# Auth\nAdd login\./);
|
|
35
|
+
assert.match(prompt, /treat it as the primary requirements/);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe("buildPrompt", () => {
|
|
40
|
+
it("scopes work to one task and requires acceptance criteria", () => {
|
|
41
|
+
const task = {
|
|
42
|
+
id: 2,
|
|
43
|
+
title: "Add login UI",
|
|
44
|
+
done: false,
|
|
45
|
+
body: "## Task 2: Add login UI\n\n**Acceptance criteria:**\n- [ ] Form submits",
|
|
46
|
+
};
|
|
47
|
+
const prompt = buildPrompt(task, 3, false);
|
|
48
|
+
assert.equal(buildRequest(task), "Execute planned task 2. Add login UI");
|
|
49
|
+
assert.match(prompt, /Current task: 2\. Add login UI/);
|
|
50
|
+
assert.match(prompt, /Remaining tasks after this one: 2/);
|
|
51
|
+
assert.match(prompt, /Form submits/);
|
|
52
|
+
assert.match(prompt, /acceptance criteria/);
|
|
53
|
+
assert.match(prompt, /ask_user_question/);
|
|
54
|
+
assert.match(prompt, /Do not start the next task/);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("buildStatus", () => {
|
|
59
|
+
it("summarizes checklist progress for later turns", () => {
|
|
60
|
+
const tasks = [
|
|
61
|
+
{ id: 1, title: "API", done: true, body: "" },
|
|
62
|
+
{ id: 2, title: "UI", done: false, body: "" },
|
|
63
|
+
];
|
|
64
|
+
const status = buildStatus(tasks, 2);
|
|
65
|
+
assert.match(status, /Progress 1\/2/);
|
|
66
|
+
assert.match(status, /\[x\] 1\. API/);
|
|
67
|
+
assert.match(status, /\[ \] 2\. UI {2}<- current/);
|
|
68
|
+
assert.equal(buildStatusKey(tasks, 2), "2:1:1,2:0");
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { loadPlanningMethod } from "./planning-method.ts";
|
|
2
|
+
import type { PlanSource } from "./plan-input.ts";
|
|
3
|
+
import type { TaskItem } from "./types.ts";
|
|
4
|
+
|
|
5
|
+
export const DEFAULT_PLAN_REQUEST = "Write a plan from the current conversation and repository.";
|
|
6
|
+
|
|
7
|
+
export function planRequest(source: PlanSource): string {
|
|
8
|
+
if (source.kind === "empty") return DEFAULT_PLAN_REQUEST;
|
|
9
|
+
if (source.kind === "prompt") return source.prompt.trim() || DEFAULT_PLAN_REQUEST;
|
|
10
|
+
const notes = source.notes.trim();
|
|
11
|
+
const head = `Write a plan from ${source.displayPath}.`;
|
|
12
|
+
return notes ? `${head}\n\n${notes}` : head;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function specSection(source: PlanSource): string {
|
|
16
|
+
if (source.kind !== "file") return "";
|
|
17
|
+
if (source.content !== undefined) {
|
|
18
|
+
return `\nSpec file (${source.displayPath}):\n\`\`\`\n${source.content}\n\`\`\`\n`;
|
|
19
|
+
}
|
|
20
|
+
return `\nSpec file: ${source.displayPath}\nThe file is too large to inline. Read \`${source.resolvedPath}\` with the read tool before writing the plan.\n`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Delivered once when plan mode starts. Not a system-prompt patch. */
|
|
24
|
+
export function planPrompt(source: PlanSource): string {
|
|
25
|
+
const request = planRequest(source);
|
|
26
|
+
return `You are in plan mode. Explore the repository and write a plan. Do not implement product code.
|
|
27
|
+
|
|
28
|
+
Request:
|
|
29
|
+
${request}
|
|
30
|
+
${specSection(source)}
|
|
31
|
+
Runtime rules:
|
|
32
|
+
- Do not modify project files.
|
|
33
|
+
- The only files you may create or edit are \`.plan_task/plan.md\` and \`.plan_task/task.md\`.
|
|
34
|
+
- Use write/edit for those two files. Do not implement the work itself.
|
|
35
|
+
- Follow the planning method below for process, task sizing, templates, and verification.
|
|
36
|
+
- The checklist lines in \`.plan_task/task.md\` must stay in the exact form \`- [ ] N. Title\` so later sessions can resume.
|
|
37
|
+
- If a spec file is provided, treat it as the primary requirements.
|
|
38
|
+
- If a consequential, user-answerable decision remains, call \`ask_user_question\` with 2-4 options, a recommended default, and an Other path. Do not leave blocking decisions as open questions in the plan.
|
|
39
|
+
- When both files are written, stop and wait for /build.
|
|
40
|
+
|
|
41
|
+
${loadPlanningMethod()}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function buildRequest(task: TaskItem): string {
|
|
45
|
+
return `Execute planned task ${task.id}. ${task.title}`;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Delivered once when a build task starts. Not a system-prompt patch. */
|
|
49
|
+
export function buildPrompt(task: TaskItem, remaining: number, continueAll: boolean): string {
|
|
50
|
+
const stopRule = continueAll
|
|
51
|
+
? "After this task is complete, mark it done. Remaining tasks will be assigned automatically. Do not stop to ask about sessions."
|
|
52
|
+
: "After this task is complete, mark it done and stop. Do not start the next task.";
|
|
53
|
+
const body = task.body.trim() || `## Task ${task.id}: ${task.title}`;
|
|
54
|
+
return `Execute exactly one planned task. Do not start any other task.
|
|
55
|
+
|
|
56
|
+
Current task: ${task.id}. ${task.title}
|
|
57
|
+
Remaining tasks after this one: ${Math.max(0, remaining - 1)}
|
|
58
|
+
|
|
59
|
+
${body}
|
|
60
|
+
|
|
61
|
+
Rules:
|
|
62
|
+
- Implement only this task.
|
|
63
|
+
- Follow existing project conventions.
|
|
64
|
+
- Leave the system in a working state when the task ends.
|
|
65
|
+
- Verify against this task's acceptance criteria and verification steps before marking it done.
|
|
66
|
+
- Do not mark the task complete if acceptance criteria are unmet or verification failed.
|
|
67
|
+
- If a consequential decision is still ambiguous, call \`ask_user_question\` instead of guessing.
|
|
68
|
+
- When the task is done, call the plan_task tool with action "complete" and this task id, and keep the matching checklist box checked in \`.plan_task/task.md\`.
|
|
69
|
+
- ${stopRule}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function buildStatus(tasks: TaskItem[], currentId: number): string {
|
|
73
|
+
const done = tasks.filter((task) => task.done).length;
|
|
74
|
+
const lines = tasks.map((task) => {
|
|
75
|
+
const mark = task.done ? "[x]" : "[ ]";
|
|
76
|
+
const current = task.id === currentId ? " <- current" : "";
|
|
77
|
+
return `- ${mark} ${task.id}. ${task.title}${current}`;
|
|
78
|
+
});
|
|
79
|
+
return `[BUILD STATUS]
|
|
80
|
+
Progress ${done}/${tasks.length}
|
|
81
|
+
|
|
82
|
+
${lines.join("\n")}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function buildStatusKey(tasks: TaskItem[], currentId: number): string {
|
|
86
|
+
return `${currentId}:${tasks.map((task) => `${task.id}:${task.done ? "1" : "0"}`).join(",")}`;
|
|
87
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface PlanTaskConfig {
|
|
2
|
+
planTools: string[];
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export interface TaskItem {
|
|
6
|
+
id: number;
|
|
7
|
+
title: string;
|
|
8
|
+
done: boolean;
|
|
9
|
+
body: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface TaskFile {
|
|
13
|
+
raw: string;
|
|
14
|
+
tasks: TaskItem[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const DEFAULT_PLAN_TOOLS = ["read", "bash", "grep", "find", "ls", "pwsh", "rg"] as const;
|
|
18
|
+
|
|
19
|
+
export const DEFAULT_CONFIG: PlanTaskConfig = {
|
|
20
|
+
planTools: [...DEFAULT_PLAN_TOOLS],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const PLAN_DIR_NAME = ".plan_task";
|
|
24
|
+
export const PLAN_FILE_NAME = "plan.md";
|
|
25
|
+
export const TASK_FILE_NAME = "task.md";
|
|
26
|
+
export const CONFIG_FILE_NAME = "plan_task.json";
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-plan-task",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Pi package: /plan, /build, /goal, /tasks.",
|
|
6
|
+
"keywords": ["pi-package"],
|
|
7
|
+
"files": ["extensions", "README.md"],
|
|
8
|
+
"type": "module",
|
|
9
|
+
"pi": {
|
|
10
|
+
"extensions": ["./extensions/index.ts"]
|
|
11
|
+
},
|
|
12
|
+
"peerDependencies": {
|
|
13
|
+
"@earendil-works/pi-ai": "*",
|
|
14
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
15
|
+
"@earendil-works/pi-tui": "*",
|
|
16
|
+
"typebox": "*"
|
|
17
|
+
}
|
|
18
|
+
}
|