mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
fc655beb0e
* feat: extract checklist utilities to shared package Move ChecklistItem, parseChecklist, extractDoneSteps, and markCompletedSteps from Pi extension to @plannotator/shared for reuse by the OpenCode plugin. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: Pi-style iterative planning for OpenCode plugin Rewrite the OpenCode plugin to match Pi's planning methodology: - Inject rich iterative planning prompt when agent is "plan" (explore → update plan → ask user loop, structured plan format) - File-based submit_plan: reads plan from disk instead of requiring it as a string arg. Resolves path from OpenCode's system prompt, falls back to PLAN.md - Suppress plan_exit via tool.definition hook (directs to submit_plan) - Add PLANNOTATOR_ALLOW_SUBAGENTS env var for #289 - Pass planFilePath to denial feedback template - Keep existing subagent/build/title guards intact Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address review findings in OpenCode plugin - Cache agents list (static per session, was fetched every LLM call) - Remove TOCTOU: drop redundant file.exists() before file.text() - Eliminate duplicate system.join() by reusing joined string - Resolve getSharingEnabled() once in submit_plan instead of twice - Use path.join() instead of string concatenation for file paths Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: session-scoped plan files and tool-neutral prompt Replace plugin-global resolvedPlanFilePath and prompt-path parsing with per-session plan files at ~/.plannotator/session-plans/opencode/{id}/plan.md. Remove resolvePlanFilePath() regex (fixes spaces-in-path and cross-session race). Make planning prompt tool-neutral (no write/edit references) so it works with apply_patch models. Strip OpenCode's native read-only and experimental-mode prompt lines before injecting Plannotator's planning prompt. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: directory-based plan storage with path validation Replace session-scoped plan files with a shared plan directory at ~/.plannotator/session-plans/opencode/. Agent picks the filename, submit_plan takes a path arg and validates it (absolute, inside plan dir, exists, readable, non-empty) with canonical path checks to defeat traversal and symlink escapes. Remove summary and plan string args. Planning prompt is now tool-neutral and directs the agent to reuse the same file on feedback, not create new ones. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use OpenCode's native plans directory for permission compatibility OpenCode's plan mode permission ruleset only allows edits to .opencode/plans/*.md and $XDG_DATA_HOME/opencode/plans/*.md. Our custom ~/.plannotator/session-plans/opencode/ path was blocked by PermissionDeniedError at the tool level regardless of prompt stripping. Switch to the XDG path that OpenCode already allows. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: exploration-first planning prompt Restructure the planning prompt as a phased workflow: Explore → Ask → Write → Submit. The agent now explores the codebase before creating a plan file or asking questions, producing better-researched plans for existing codebases. Greenfield tasks can skip straight to questions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: fix stale path in JSDoc header comment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
53 lines
1.4 KiB
TypeScript
53 lines
1.4 KiB
TypeScript
/**
|
|
* Checklist parsing and progress tracking utilities.
|
|
*
|
|
* Shared between Pi extension and OpenCode plugin for plan execution tracking.
|
|
*/
|
|
|
|
export interface ChecklistItem {
|
|
/** 1-based step number, compatible with markCompletedSteps/extractDoneSteps. */
|
|
step: number;
|
|
text: string;
|
|
completed: boolean;
|
|
}
|
|
|
|
/**
|
|
* Parse standard markdown checkboxes from file content.
|
|
*
|
|
* Matches lines like:
|
|
* - [ ] Step description
|
|
* - [x] Completed step
|
|
* * [ ] Alternative bullet
|
|
*/
|
|
export function parseChecklist(content: string): ChecklistItem[] {
|
|
const items: ChecklistItem[] = [];
|
|
const pattern = /^[-*]\s*\[([ xX])\]\s+(.+)$/gm;
|
|
|
|
for (const match of content.matchAll(pattern)) {
|
|
const completed = match[1] !== " ";
|
|
const text = match[2].trim();
|
|
if (text.length > 0) {
|
|
items.push({ step: items.length + 1, text, completed });
|
|
}
|
|
}
|
|
return items;
|
|
}
|
|
|
|
export function extractDoneSteps(message: string): number[] {
|
|
const steps: number[] = [];
|
|
for (const match of message.matchAll(/\[DONE:(\d+)\]/gi)) {
|
|
const step = Number(match[1]);
|
|
if (Number.isFinite(step)) steps.push(step);
|
|
}
|
|
return steps;
|
|
}
|
|
|
|
export function markCompletedSteps(text: string, items: ChecklistItem[]): number {
|
|
const doneSteps = extractDoneSteps(text);
|
|
for (const step of doneSteps) {
|
|
const item = items.find((t) => t.step === step);
|
|
if (item) item.completed = true;
|
|
}
|
|
return doneSteps.length;
|
|
}
|