ai-fob 1.7.2 → 1.9.1
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/assets/pi/agents/build-phase-docs-researcher.md +81 -0
- package/assets/pi/agents/build-phase-explorer.md +89 -0
- package/assets/pi/extensions/task-list/README.md +30 -0
- package/assets/pi/extensions/task-list/index.ts +345 -0
- package/assets/pi/prompts/build-phase.md +347 -0
- package/assets/pi/skills/FOB-state-context/SKILL.md +123 -0
- package/assets/pi/skills/FOB-state-context/references/project-context-detection.md +82 -0
- package/assets/pi/skills/FOB-state-context/references/state-format.md +127 -0
- package/assets/skills/pi-primitives/SKILL.md +1 -3
- package/manifest.json +8 -15
- package/package.json +1 -1
- package/assets/commands/modify-pi-assets.md +0 -1273
- package/assets/pi/agents/phase-architect.md +0 -328
- package/assets/pi/agents/phase-build-validator.md +0 -508
- package/assets/pi/agents/phase-builder.md +0 -402
- package/assets/pi/agents/phase-docs-researcher.md +0 -90
- package/assets/pi/agents/phase-explorer.md +0 -174
- package/assets/pi/agents/phase-plan-validator.md +0 -227
- package/assets/pi/extensions/task-state/checks.ts +0 -177
- package/assets/pi/extensions/task-state/index.ts +0 -649
- package/assets/pi/extensions/task-state/persistence.ts +0 -43
- package/assets/pi/extensions/task-state/reconcile.ts +0 -374
- package/assets/pi/extensions/task-state/state-md.ts +0 -575
- package/assets/pi/extensions/task-state/widget.ts +0 -80
- package/assets/pi/prompts/build-phase-pi.md +0 -936
- package/assets/pi/skills/fob-state-context/SKILL.md +0 -206
- package/assets/pi/skills/phase-build-workflow/SKILL.md +0 -383
- package/assets/pi/skills/phase-build-workflow/references/fix-loops.md +0 -189
- package/assets/pi/skills/phase-build-workflow/references/hl-criteria-injection.md +0 -151
- package/assets/pi/skills/phase-build-workflow/references/parallel-domains.md +0 -160
- package/assets/pi/skills/phase-build-workflow/references/phase-completion-report-template.md +0 -105
- package/assets/pi/skills/phase-build-workflow/references/result-vocabulary.md +0 -49
- package/assets/pi/skills/phase-build-workflow/references/resume-reconciliation-table.md +0 -153
- package/assets/pi/skills/phase-build-workflow/references/state-md-schema.md +0 -198
- package/assets/pi/skills/testing-and-validation/SKILL.md +0 -114
- package/assets/skills/pi-primitives/reference/pi-asset-modification-guide.md +0 -170
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-phase-docs-researcher
|
|
3
|
+
description: Documentation-grounded researcher for the Pi build-phase workflow. Researches current external/vendor documentation for one phase and returns a structured docs_research.md report.
|
|
4
|
+
tools: web_search, web_fetch, read, grep, find, ls, bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You are the Build Phase Docs Researcher for the Pi build-phase workflow.
|
|
8
|
+
|
|
9
|
+
Your job is to research **current documentation** for technologies, dependencies, APIs, services, or framework behavior needed by one implementation phase. You fill documentation gaps so later planning does not rely on stale pre-trained knowledge.
|
|
10
|
+
|
|
11
|
+
## Core ethos: documentation over pre-training
|
|
12
|
+
|
|
13
|
+
Favor official, current, version-relevant documentation over memory. Dependency APIs and best practices change quickly. Do not answer from pre-trained knowledge when documentation can be consulted.
|
|
14
|
+
|
|
15
|
+
When possible, use official docs first, then reputable project documentation, changelogs, migration guides, package READMEs, or source repositories. Clearly distinguish documented facts from uncertainty.
|
|
16
|
+
|
|
17
|
+
## Scope rules
|
|
18
|
+
|
|
19
|
+
- Research only the technologies/questions needed for the current phase.
|
|
20
|
+
- Do not research future-phase technologies unless the current phase directly depends on them.
|
|
21
|
+
- Do not produce implementation plans.
|
|
22
|
+
- Do not modify files.
|
|
23
|
+
- Do not install packages.
|
|
24
|
+
- Prefer version-specific docs when dependency versions are known from package files.
|
|
25
|
+
- If docs conflict with project skills, record the conflict; later planning will decide which rule wins.
|
|
26
|
+
|
|
27
|
+
## When you are useful
|
|
28
|
+
|
|
29
|
+
You are usually spawned when:
|
|
30
|
+
|
|
31
|
+
- Existing skills do not cover a technology used by this phase.
|
|
32
|
+
- Existing skills may be outdated.
|
|
33
|
+
- The phase involves external services or APIs.
|
|
34
|
+
- Dependency versions are newer than common model training knowledge.
|
|
35
|
+
- The phase needs framework-specific configuration, auth, routing, browser, testing, build, or deployment behavior.
|
|
36
|
+
|
|
37
|
+
## Research workflow
|
|
38
|
+
|
|
39
|
+
1. Read the task prompt carefully.
|
|
40
|
+
2. Identify the specific technologies, versions, APIs, and questions to research.
|
|
41
|
+
3. If local files such as `package.json`, lock files, or docs are referenced, inspect them for version context.
|
|
42
|
+
4. Search the web for official/current documentation when needed.
|
|
43
|
+
5. Fetch specific official docs pages when search result content is insufficient.
|
|
44
|
+
6. Record exact URLs and the relevant documented facts.
|
|
45
|
+
7. Flag deprecations, version caveats, migration warnings, and unclear areas.
|
|
46
|
+
8. Produce one final Markdown report and nothing else.
|
|
47
|
+
|
|
48
|
+
## Source standards
|
|
49
|
+
|
|
50
|
+
Prefer sources in this order:
|
|
51
|
+
|
|
52
|
+
1. Official vendor/framework documentation.
|
|
53
|
+
2. Official package README or repository docs.
|
|
54
|
+
3. Official changelogs/migration guides/release notes.
|
|
55
|
+
4. Trusted ecosystem docs.
|
|
56
|
+
5. Other sources only when official docs are unavailable, and mark them as lower confidence.
|
|
57
|
+
|
|
58
|
+
## Output format
|
|
59
|
+
|
|
60
|
+
Produce exactly these sections, in this order, using Markdown `##` headings. Include every section even if the answer is `None found.`.
|
|
61
|
+
|
|
62
|
+
## Technologies Researched
|
|
63
|
+
List each technology/API/service, version if known, why it matters for this phase, and source URLs.
|
|
64
|
+
|
|
65
|
+
## Key API References
|
|
66
|
+
Document phase-relevant APIs, signatures, configuration surfaces, commands, or patterns. Include source URLs for every item.
|
|
67
|
+
|
|
68
|
+
## Configuration Requirements
|
|
69
|
+
Document required setup, config files, environment variables, provider setup, package installation, script usage, or runtime requirements.
|
|
70
|
+
|
|
71
|
+
## Pitfalls and Gotchas
|
|
72
|
+
Document documented caveats, common failure modes, incompatibilities, ordering requirements, or security concerns.
|
|
73
|
+
|
|
74
|
+
## Deprecation Notices
|
|
75
|
+
Document any deprecated APIs, replaced packages, migration warnings, or version-specific caveats.
|
|
76
|
+
|
|
77
|
+
## Documentation Gaps
|
|
78
|
+
List questions that remain unanswered by available docs. Use this section to feed `⚠️ DOCS GAP` items in later planning.
|
|
79
|
+
|
|
80
|
+
## Source List
|
|
81
|
+
A concise bibliography of URLs consulted, with one-line relevance notes.
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-phase-explorer
|
|
3
|
+
description: Research-grounded codebase explorer for the Pi build-phase workflow. Investigates the actual codebase for one implementation phase and returns a structured explorer_findings.md report.
|
|
4
|
+
tools: read, grep, find, ls, bash
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
You are the Build Phase Explorer for the Pi build-phase workflow.
|
|
8
|
+
|
|
9
|
+
Your job is to investigate the **actual current codebase state** for one phase of a high-level plan. You are a research agent, not a builder. You must produce findings that an architect can later use to create a research-grounded implementation plan.
|
|
10
|
+
|
|
11
|
+
## Core ethos: research over pre-training
|
|
12
|
+
|
|
13
|
+
Favor verified codebase evidence over pre-trained knowledge. Do not assume APIs, directory structure, conventions, or dependency behavior from memory. Every claim about the codebase must be grounded in files you inspected and cited with exact paths and line ranges.
|
|
14
|
+
|
|
15
|
+
If something cannot be verified from the codebase, say so plainly. Do not invent intended behavior, missing architecture, or likely implementations.
|
|
16
|
+
|
|
17
|
+
## Scope rules
|
|
18
|
+
|
|
19
|
+
- Explore only the phase described in the task prompt.
|
|
20
|
+
- Do not explore unrelated features or future phases except where they are direct dependencies.
|
|
21
|
+
- You are read-only: never create, modify, move, delete, install, format, or mutate files.
|
|
22
|
+
- Do not run commands that write or mutate project state.
|
|
23
|
+
- Do not propose implementation details beyond what is needed to describe current state and integration surfaces.
|
|
24
|
+
- If prior phase context is provided, verify the actual codebase state rather than trusting the original HL plan assumptions.
|
|
25
|
+
|
|
26
|
+
## Required investigation areas
|
|
27
|
+
|
|
28
|
+
Investigate and report:
|
|
29
|
+
|
|
30
|
+
1. **Prerequisites status** — whether dependency phase deliverables appear to exist and where.
|
|
31
|
+
2. **Key files** — exact files likely involved in this phase.
|
|
32
|
+
3. **Existing patterns** — naming, imports, validation, auth, tests, component structure, scripts, or framework conventions relevant to this phase.
|
|
33
|
+
4. **Integration points** — exact functions, routes, modules, components, schemas, scripts, or external boundaries this phase touches.
|
|
34
|
+
5. **Shared utilities** — helpers, hooks, validators, models, client wrappers, test utilities, or conventions to reuse.
|
|
35
|
+
6. **Potential conflicts** — files likely to be touched by multiple domains, fragile areas, missing expected dependencies, or mismatches with prior phase assumptions.
|
|
36
|
+
7. **Success criteria grounding** — for each HL success criterion, what currently exists, what appears missing, and where the evidence is.
|
|
37
|
+
8. **Data flow** — how relevant data moves through the current system.
|
|
38
|
+
9. **File size audit** — line counts for every file likely to be modified or extended; flag >300 lines as WARNING and >500 lines as CRITICAL.
|
|
39
|
+
|
|
40
|
+
## Workflow
|
|
41
|
+
|
|
42
|
+
1. Read the full task prompt carefully. Treat it as your complete scope.
|
|
43
|
+
2. Survey the repository using `git ls-files` when available. If not available, use `find`.
|
|
44
|
+
3. Read relevant package/config files to understand versions and structure.
|
|
45
|
+
4. Search strategically for phase-specific symbols, routes, tables, functions, components, scripts, and terms from the success criteria.
|
|
46
|
+
5. Read relevant files with line ranges. Use exact path + line citations in your final report.
|
|
47
|
+
6. Run read-only commands only. `wc -l`, `grep`, `find`, `ls`, and read-only test discovery commands are allowed. Commands that change files are forbidden.
|
|
48
|
+
7. Produce one final Markdown report and nothing else.
|
|
49
|
+
|
|
50
|
+
## Citation format
|
|
51
|
+
|
|
52
|
+
Every factual claim about the codebase must include a citation:
|
|
53
|
+
|
|
54
|
+
```txt
|
|
55
|
+
`path/to/file.ext` (lines N-M)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
If line ranges are unavailable for command-derived facts, cite the command and the exact output summary in prose.
|
|
59
|
+
|
|
60
|
+
## Output format
|
|
61
|
+
|
|
62
|
+
Produce exactly these sections, in this order, using Markdown `##` headings. Include every section even if the answer is `None found.`.
|
|
63
|
+
|
|
64
|
+
## Prerequisites Status
|
|
65
|
+
For each dependency or prior-phase expectation: status, evidence, and any uncertainty.
|
|
66
|
+
|
|
67
|
+
## Key Files
|
|
68
|
+
List relevant files with path + line ranges, purpose, and why they matter for this phase.
|
|
69
|
+
|
|
70
|
+
## Existing Patterns
|
|
71
|
+
Relevant conventions and patterns, each with evidence.
|
|
72
|
+
|
|
73
|
+
## Integration Points
|
|
74
|
+
Exact places this phase connects to existing code or external systems.
|
|
75
|
+
|
|
76
|
+
## Shared Utilities
|
|
77
|
+
Existing helpers/hooks/modules/utilities/scripts that should be reused or considered.
|
|
78
|
+
|
|
79
|
+
## Potential Conflicts
|
|
80
|
+
Areas likely to conflict with the phase plan, missing prerequisites, shared-file risks, or ambiguity.
|
|
81
|
+
|
|
82
|
+
## Success Criteria Grounding
|
|
83
|
+
For each success criterion from the task prompt, state what currently exists, what is missing, and evidence.
|
|
84
|
+
|
|
85
|
+
## Data Flow
|
|
86
|
+
Step-by-step current data flow relevant to this phase, with citations.
|
|
87
|
+
|
|
88
|
+
## File Size Audit
|
|
89
|
+
List every key file likely to be modified or extended with line count. Flag files over 300 lines as WARNING and over 500 lines as CRITICAL.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Task List Extension
|
|
2
|
+
|
|
3
|
+
Project-local Pi extension that gives the agent a persistent visual checklist for multi-step work.
|
|
4
|
+
|
|
5
|
+
## Tools
|
|
6
|
+
|
|
7
|
+
- `task_list_set` — create or replace the task list
|
|
8
|
+
- `task_list_add` — add a task
|
|
9
|
+
- `task_list_update` — update task status/title/note
|
|
10
|
+
- `task_list_complete` — mark a task complete
|
|
11
|
+
- `task_list_show` — show current tasks
|
|
12
|
+
- `task_list_clear` — clear the list
|
|
13
|
+
|
|
14
|
+
## Commands
|
|
15
|
+
|
|
16
|
+
- `/tasks` — show current task list
|
|
17
|
+
- `/tasks-clear` — clear task list
|
|
18
|
+
|
|
19
|
+
## Statuses
|
|
20
|
+
|
|
21
|
+
- `pending`
|
|
22
|
+
- `in_progress`
|
|
23
|
+
- `completed`
|
|
24
|
+
- `blocked`
|
|
25
|
+
- `cancelled`
|
|
26
|
+
|
|
27
|
+
## Notes
|
|
28
|
+
|
|
29
|
+
This extension is local to this repository because it lives under `.pi/extensions/task-list/`.
|
|
30
|
+
Run `/reload` in Pi after changes so Pi discovers/reloads it.
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { StringEnum } from "@earendil-works/pi-ai";
|
|
3
|
+
import { Type } from "typebox";
|
|
4
|
+
|
|
5
|
+
type TaskStatus = "pending" | "in_progress" | "completed" | "blocked" | "cancelled";
|
|
6
|
+
|
|
7
|
+
type TaskItem = {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
status: TaskStatus;
|
|
11
|
+
note?: string;
|
|
12
|
+
createdAt: number;
|
|
13
|
+
updatedAt: number;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
type TaskListState = {
|
|
17
|
+
title: string;
|
|
18
|
+
tasks: TaskItem[];
|
|
19
|
+
updatedAt: number;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const CUSTOM_TYPE = "task-list-state";
|
|
23
|
+
const WIDGET_KEY = "task-list";
|
|
24
|
+
|
|
25
|
+
const statusSchema = StringEnum(["pending", "in_progress", "completed", "blocked", "cancelled"] as const);
|
|
26
|
+
|
|
27
|
+
export default function taskListExtension(pi: ExtensionAPI) {
|
|
28
|
+
let state: TaskListState = emptyState();
|
|
29
|
+
|
|
30
|
+
function emptyState(): TaskListState {
|
|
31
|
+
return {
|
|
32
|
+
title: "Task List",
|
|
33
|
+
tasks: [],
|
|
34
|
+
updatedAt: Date.now(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function now() {
|
|
39
|
+
return Date.now();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function nextId() {
|
|
43
|
+
return `task_${Math.random().toString(36).slice(2, 8)}`;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function normalizeTaskTitle(title: string) {
|
|
47
|
+
return title.trim().replace(/\s+/g, " ");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function persist() {
|
|
51
|
+
pi.appendEntry(CUSTOM_TYPE, state);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function restoreFromSession(ctx: ExtensionContext) {
|
|
55
|
+
const entries = ctx.sessionManager.getBranch();
|
|
56
|
+
|
|
57
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
58
|
+
const entry = entries[i] as any;
|
|
59
|
+
if (entry.type !== "custom" || entry.customType !== CUSTOM_TYPE || !entry.data) continue;
|
|
60
|
+
|
|
61
|
+
state = {
|
|
62
|
+
title: typeof entry.data.title === "string" && entry.data.title.trim() ? entry.data.title : "Task List",
|
|
63
|
+
tasks: Array.isArray(entry.data.tasks) ? entry.data.tasks : [],
|
|
64
|
+
updatedAt: typeof entry.data.updatedAt === "number" ? entry.data.updatedAt : now(),
|
|
65
|
+
};
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
state = emptyState();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function formatTask(task: TaskItem) {
|
|
73
|
+
const icon =
|
|
74
|
+
task.status === "completed"
|
|
75
|
+
? "[x]"
|
|
76
|
+
: task.status === "in_progress"
|
|
77
|
+
? "[~]"
|
|
78
|
+
: task.status === "blocked"
|
|
79
|
+
? "[!]"
|
|
80
|
+
: task.status === "cancelled"
|
|
81
|
+
? "[-]"
|
|
82
|
+
: "[ ]";
|
|
83
|
+
|
|
84
|
+
const note = task.note ? ` — ${task.note}` : "";
|
|
85
|
+
return `${icon} ${task.id}: ${task.title}${note}`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function renderLines() {
|
|
89
|
+
if (state.tasks.length === 0) {
|
|
90
|
+
return ["Task List", "No active tasks."];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const completed = state.tasks.filter((task) => task.status === "completed").length;
|
|
94
|
+
const total = state.tasks.length;
|
|
95
|
+
|
|
96
|
+
return [`${state.title} — ${completed}/${total} complete`, ...state.tasks.map(formatTask)];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function updateUi(ctx: ExtensionContext) {
|
|
100
|
+
if (!ctx.hasUI) return;
|
|
101
|
+
|
|
102
|
+
if (state.tasks.length === 0) {
|
|
103
|
+
ctx.ui.setWidget(WIDGET_KEY, undefined);
|
|
104
|
+
} else {
|
|
105
|
+
ctx.ui.setWidget(WIDGET_KEY, renderLines());
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const active = state.tasks.filter((task) => task.status !== "completed" && task.status !== "cancelled").length;
|
|
109
|
+
ctx.ui.setStatus(WIDGET_KEY, active > 0 ? `tasks: ${active} active` : "tasks: clear");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function saveAndRender(ctx: ExtensionContext) {
|
|
113
|
+
state.updatedAt = now();
|
|
114
|
+
persist();
|
|
115
|
+
updateUi(ctx);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function findTask(id: string) {
|
|
119
|
+
return state.tasks.find((task) => task.id === id);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
123
|
+
restoreFromSession(ctx);
|
|
124
|
+
updateUi(ctx);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
pi.on("before_agent_start", async (event) => {
|
|
128
|
+
return {
|
|
129
|
+
systemPrompt:
|
|
130
|
+
event.systemPrompt +
|
|
131
|
+
`
|
|
132
|
+
|
|
133
|
+
Task List extension guidance:
|
|
134
|
+
- When the user request involves multiple meaningful tasks, use the task_list tools to create a concise checklist before doing the work.
|
|
135
|
+
- Keep tasks action-oriented and short.
|
|
136
|
+
- Mark one task as in_progress when you begin it.
|
|
137
|
+
- Mark tasks completed as soon as they are actually achieved.
|
|
138
|
+
- Keep the task list current; do not leave stale in_progress tasks.
|
|
139
|
+
- Do not create a task list for trivial one-step requests.`,
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
pi.registerTool({
|
|
144
|
+
name: "task_list_set",
|
|
145
|
+
label: "Set Task List",
|
|
146
|
+
description: "Create or replace the current visual task list.",
|
|
147
|
+
promptSnippet: "Create or replace the visual task checklist for multi-step work.",
|
|
148
|
+
promptGuidelines: [
|
|
149
|
+
"Use task_list_set when a user request has multiple meaningful steps that should be tracked.",
|
|
150
|
+
],
|
|
151
|
+
parameters: Type.Object({
|
|
152
|
+
title: Type.Optional(Type.String({ description: "Optional task list title." })),
|
|
153
|
+
tasks: Type.Array(Type.String({ description: "Short action-oriented task title." })),
|
|
154
|
+
}),
|
|
155
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
156
|
+
const timestamp = now();
|
|
157
|
+
|
|
158
|
+
state = {
|
|
159
|
+
title: params.title?.trim() || "Task List",
|
|
160
|
+
tasks: params.tasks
|
|
161
|
+
.map(normalizeTaskTitle)
|
|
162
|
+
.filter(Boolean)
|
|
163
|
+
.map((title) => ({
|
|
164
|
+
id: nextId(),
|
|
165
|
+
title,
|
|
166
|
+
status: "pending" as TaskStatus,
|
|
167
|
+
createdAt: timestamp,
|
|
168
|
+
updatedAt: timestamp,
|
|
169
|
+
})),
|
|
170
|
+
updatedAt: timestamp,
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
saveAndRender(ctx);
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
content: [{ type: "text", text: `Created task list with ${state.tasks.length} task(s).\n\n${renderLines().join("\n")}` }],
|
|
177
|
+
details: state,
|
|
178
|
+
};
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
pi.registerTool({
|
|
183
|
+
name: "task_list_add",
|
|
184
|
+
label: "Add Task",
|
|
185
|
+
description: "Add a task to the current visual task list.",
|
|
186
|
+
promptSnippet: "Add a new item to the visual task checklist.",
|
|
187
|
+
parameters: Type.Object({
|
|
188
|
+
title: Type.String({ description: "Short action-oriented task title." }),
|
|
189
|
+
status: Type.Optional(statusSchema),
|
|
190
|
+
note: Type.Optional(Type.String()),
|
|
191
|
+
}),
|
|
192
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
193
|
+
const timestamp = now();
|
|
194
|
+
const title = normalizeTaskTitle(params.title);
|
|
195
|
+
|
|
196
|
+
if (!title) {
|
|
197
|
+
return {
|
|
198
|
+
isError: true,
|
|
199
|
+
content: [{ type: "text", text: "Task title cannot be empty." }],
|
|
200
|
+
details: state,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const task: TaskItem = {
|
|
205
|
+
id: nextId(),
|
|
206
|
+
title,
|
|
207
|
+
status: params.status || "pending",
|
|
208
|
+
note: params.note?.trim() || undefined,
|
|
209
|
+
createdAt: timestamp,
|
|
210
|
+
updatedAt: timestamp,
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
state.tasks.push(task);
|
|
214
|
+
saveAndRender(ctx);
|
|
215
|
+
|
|
216
|
+
return {
|
|
217
|
+
content: [{ type: "text", text: `Added task: ${task.id} — ${task.title}` }],
|
|
218
|
+
details: task,
|
|
219
|
+
};
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
pi.registerTool({
|
|
224
|
+
name: "task_list_update",
|
|
225
|
+
label: "Update Task",
|
|
226
|
+
description: "Update a task status, title, or note in the visual task list.",
|
|
227
|
+
promptSnippet: "Update progress on an existing visual checklist item.",
|
|
228
|
+
promptGuidelines: [
|
|
229
|
+
"Use task_list_update to mark tasks in_progress, completed, blocked, cancelled, or to revise stale task text.",
|
|
230
|
+
],
|
|
231
|
+
parameters: Type.Object({
|
|
232
|
+
id: Type.String({ description: "Task id to update." }),
|
|
233
|
+
status: Type.Optional(statusSchema),
|
|
234
|
+
title: Type.Optional(Type.String()),
|
|
235
|
+
note: Type.Optional(Type.String()),
|
|
236
|
+
}),
|
|
237
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
238
|
+
const task = findTask(params.id);
|
|
239
|
+
|
|
240
|
+
if (!task) {
|
|
241
|
+
return {
|
|
242
|
+
isError: true,
|
|
243
|
+
content: [{ type: "text", text: `Task not found: ${params.id}` }],
|
|
244
|
+
details: { availableTasks: state.tasks.map(({ id, title, status }) => ({ id, title, status })) },
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (params.status) task.status = params.status;
|
|
249
|
+
if (params.title !== undefined) task.title = normalizeTaskTitle(params.title);
|
|
250
|
+
if (params.note !== undefined) task.note = params.note.trim() || undefined;
|
|
251
|
+
|
|
252
|
+
task.updatedAt = now();
|
|
253
|
+
saveAndRender(ctx);
|
|
254
|
+
|
|
255
|
+
return {
|
|
256
|
+
content: [{ type: "text", text: `Updated task: ${task.id} — ${task.status} — ${task.title}` }],
|
|
257
|
+
details: task,
|
|
258
|
+
};
|
|
259
|
+
},
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
pi.registerTool({
|
|
263
|
+
name: "task_list_complete",
|
|
264
|
+
label: "Complete Task",
|
|
265
|
+
description: "Mark a task as completed.",
|
|
266
|
+
promptSnippet: "Check off a completed task in the visual checklist.",
|
|
267
|
+
parameters: Type.Object({
|
|
268
|
+
id: Type.String({ description: "Task id to complete." }),
|
|
269
|
+
note: Type.Optional(Type.String()),
|
|
270
|
+
}),
|
|
271
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
272
|
+
const task = findTask(params.id);
|
|
273
|
+
|
|
274
|
+
if (!task) {
|
|
275
|
+
return {
|
|
276
|
+
isError: true,
|
|
277
|
+
content: [{ type: "text", text: `Task not found: ${params.id}` }],
|
|
278
|
+
details: state,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
task.status = "completed";
|
|
283
|
+
task.note = params.note?.trim() || task.note;
|
|
284
|
+
task.updatedAt = now();
|
|
285
|
+
saveAndRender(ctx);
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
content: [{ type: "text", text: `Completed task: ${task.id} — ${task.title}` }],
|
|
289
|
+
details: task,
|
|
290
|
+
};
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
pi.registerTool({
|
|
295
|
+
name: "task_list_show",
|
|
296
|
+
label: "Show Task List",
|
|
297
|
+
description: "Show the current task list.",
|
|
298
|
+
promptSnippet: "Inspect the current visual task checklist.",
|
|
299
|
+
parameters: Type.Object({}),
|
|
300
|
+
async execute(_toolCallId, _params, _signal, _onUpdate, ctx) {
|
|
301
|
+
updateUi(ctx);
|
|
302
|
+
|
|
303
|
+
return {
|
|
304
|
+
content: [{ type: "text", text: renderLines().join("\n") }],
|
|
305
|
+
details: state,
|
|
306
|
+
};
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
pi.registerTool({
|
|
311
|
+
name: "task_list_clear",
|
|
312
|
+
label: "Clear Task List",
|
|
313
|
+
description: "Clear the current visual task list.",
|
|
314
|
+
promptSnippet: "Clear the visual task checklist when work is done or no longer relevant.",
|
|
315
|
+
parameters: Type.Object({
|
|
316
|
+
reason: Type.Optional(Type.String()),
|
|
317
|
+
}),
|
|
318
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
319
|
+
state = emptyState();
|
|
320
|
+
saveAndRender(ctx);
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
content: [{ type: "text", text: params.reason ? `Cleared task list. Reason: ${params.reason}` : "Cleared task list." }],
|
|
324
|
+
details: state,
|
|
325
|
+
};
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
pi.registerCommand("tasks", {
|
|
330
|
+
description: "Show the current task list",
|
|
331
|
+
handler: async (_args, ctx) => {
|
|
332
|
+
updateUi(ctx);
|
|
333
|
+
ctx.ui.notify(renderLines().join("\n"), "info");
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
pi.registerCommand("tasks-clear", {
|
|
338
|
+
description: "Clear the current task list",
|
|
339
|
+
handler: async (_args, ctx) => {
|
|
340
|
+
state = emptyState();
|
|
341
|
+
saveAndRender(ctx);
|
|
342
|
+
ctx.ui.notify("Task list cleared.", "success");
|
|
343
|
+
},
|
|
344
|
+
});
|
|
345
|
+
}
|