@engineereddev/fractal-planner 0.1.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.
Files changed (46) hide show
  1. package/.claude-plugin/marketplace.json +22 -0
  2. package/.claude-plugin/plugin.json +19 -0
  3. package/LICENSE +21 -0
  4. package/README.md +257 -0
  5. package/agents/fp-analyst.md +96 -0
  6. package/agents/fp-context-builder.md +87 -0
  7. package/agents/fp-critic.md +140 -0
  8. package/agents/fp-decomposer.md +261 -0
  9. package/agents/fp-interviewer.md +263 -0
  10. package/agents/fp-linear-sync.md +128 -0
  11. package/agents/fp-researcher.md +82 -0
  12. package/agents/fp-task-tracker.md +134 -0
  13. package/dist/cli/classify-intent.js +118 -0
  14. package/dist/cli/compute-signals.js +495 -0
  15. package/dist/cli/generate-plan.js +14209 -0
  16. package/dist/cli/load-config.js +13661 -0
  17. package/dist/cli/validate-tasks.js +467 -0
  18. package/dist/index.js +24598 -0
  19. package/dist/src/cli/classify-intent.d.ts +3 -0
  20. package/dist/src/cli/compute-signals.d.ts +14 -0
  21. package/dist/src/cli/generate-plan.d.ts +3 -0
  22. package/dist/src/cli/load-config.d.ts +3 -0
  23. package/dist/src/cli/validate-tasks.d.ts +3 -0
  24. package/dist/src/config.d.ts +182 -0
  25. package/dist/src/index.d.ts +12 -0
  26. package/dist/src/phases/clearance.d.ts +12 -0
  27. package/dist/src/phases/decomposition.d.ts +41 -0
  28. package/dist/src/phases/interview.d.ts +17 -0
  29. package/dist/src/phases/planning.d.ts +21 -0
  30. package/dist/src/phases/research.d.ts +9 -0
  31. package/dist/src/types/index.d.ts +116 -0
  32. package/dist/src/utils/draft.d.ts +21 -0
  33. package/dist/src/utils/question-strategies.d.ts +24 -0
  34. package/dist/src/utils/task-parser.d.ts +3 -0
  35. package/hooks/hooks.json +27 -0
  36. package/hooks/nudge-teammate.sh +216 -0
  37. package/hooks/run-comment-checker.sh +91 -0
  38. package/package.json +65 -0
  39. package/skills/commit/SKILL.md +157 -0
  40. package/skills/fp/SKILL.md +857 -0
  41. package/skills/fp/scripts/resolve-env.sh +66 -0
  42. package/skills/handoff/SKILL.md +195 -0
  43. package/skills/implement/SKILL.md +783 -0
  44. package/skills/implement/reference.md +935 -0
  45. package/skills/retry/SKILL.md +333 -0
  46. package/skills/status/SKILL.md +182 -0
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ # Resolves plugin root, CLI runner, CLI directory, and full merged config.
5
+ # Called via !`command` in SKILL.md at skill load time.
6
+ #
7
+ # Output format (key: value, one per line):
8
+ # PLUGIN_ROOT: /path/to/fractal-planner
9
+ # CLI_RUNNER: bun
10
+ # CLI_DIR: /path/to/fractal-planner/src/cli
11
+ # CONFIG_JSON: {"maxComplexity":3,...}
12
+
13
+ # --- Resolve plugin root ---
14
+ # $CLAUDE_PLUGIN_ROOT points to the plugin root (where .claude-plugin/ lives).
15
+ # Fallback: script-relative path (scripts/ -> fp/ -> skills/ -> repo root).
16
+ PLUGIN_ROOT="${CLAUDE_PLUGIN_ROOT:-$(cd "$(dirname "$0")/../../.." && pwd)}"
17
+
18
+ # --- Read cliRunner from config ---
19
+ CONFIG_FILE="$PLUGIN_ROOT/.fractal-planner/config.json"
20
+ CLI_RUNNER_SETTING="auto"
21
+
22
+ if [[ -f "$CONFIG_FILE" ]]; then
23
+ CLI_RUNNER_SETTING=$(python3 -c "
24
+ import json,sys
25
+ try:
26
+ c=json.load(open('$CONFIG_FILE'))
27
+ print(c.get('cliRunner','auto'))
28
+ except: print('auto')
29
+ " 2>/dev/null || echo "auto")
30
+ fi
31
+
32
+ # --- Resolve CLI runner ---
33
+ case "$CLI_RUNNER_SETTING" in
34
+ bun) CLI_RUNNER="bun" ;;
35
+ node) CLI_RUNNER="node" ;;
36
+ *)
37
+ if command -v bun >/dev/null 2>&1; then
38
+ CLI_RUNNER="bun"
39
+ else
40
+ CLI_RUNNER="node"
41
+ fi
42
+ ;;
43
+ esac
44
+
45
+ # --- Resolve CLI directory ---
46
+ if [[ "$CLI_RUNNER" == "bun" ]] && [[ -f "$PLUGIN_ROOT/src/cli/classify-intent.ts" ]]; then
47
+ CLI_DIR="$PLUGIN_ROOT/src/cli"
48
+ else
49
+ CLI_DIR="$PLUGIN_ROOT/dist/cli"
50
+ fi
51
+
52
+ # --- Load full merged config via CLI helper ---
53
+ CONFIG_JSON=""
54
+ if [[ "$CLI_RUNNER" == "bun" ]] && [[ -f "$CLI_DIR/load-config.ts" ]]; then
55
+ CONFIG_JSON=$("$CLI_RUNNER" "$CLI_DIR/load-config.ts" 2>/dev/null || echo '{"_error":"config load failed"}')
56
+ elif [[ -f "$CLI_DIR/load-config.js" ]]; then
57
+ CONFIG_JSON=$("$CLI_RUNNER" "$CLI_DIR/load-config.js" 2>/dev/null || echo '{"_error":"config load failed"}')
58
+ else
59
+ CONFIG_JSON='{"_error":"load-config not found"}'
60
+ fi
61
+
62
+ # --- Output ---
63
+ echo "PLUGIN_ROOT: $PLUGIN_ROOT"
64
+ echo "CLI_RUNNER: $CLI_RUNNER"
65
+ echo "CLI_DIR: $CLI_DIR"
66
+ echo "CONFIG_JSON: $CONFIG_JSON"
@@ -0,0 +1,195 @@
1
+ ---
2
+ name: fp:handoff
3
+ description: Generate a session handoff summary for clean context continuation during large implementations
4
+ argument-hint: <plan-session-id>
5
+ allowed-tools: Read, Glob, Bash, Write
6
+ ---
7
+
8
+ # Fractal Planner: Session Handoff
9
+
10
+ You are generating a handoff summary for a fractal-planner implementation plan. This captures volatile state (discoveries, iteration counts, failure details) so the next `/fp:implement` session resumes with full context.
11
+
12
+ ## Step 1: Parse Arguments
13
+
14
+ Parse `$ARGUMENTS` to extract `planId` (the first positional argument).
15
+
16
+ If no `planId` is provided, report the error and stop:
17
+ > "Usage: `/fp:handoff <plan-session-id>`"
18
+
19
+ ## Step 2: Validate Prerequisites
20
+
21
+ Check `.fractal-planner/plans/{planId}/` has both:
22
+ 1. `plan.md`
23
+ 2. `execution-state.json`
24
+
25
+ If either is missing, report the error and stop:
26
+ > "Plan '{planId}' is missing required files. Both `plan.md` and `execution-state.json` must exist. Run `/fp:plan` and `/fp:implement` first."
27
+
28
+ ## Step 3: Load Execution State
29
+
30
+ Read `.fractal-planner/plans/{planId}/execution-state.json`. Extract:
31
+ - `taskMap` — object mapping plan task IDs to native task IDs
32
+ - `skippedTasks` — object mapping plan task IDs to skip reasons
33
+ - `failureReasons` — object mapping plan task IDs to failure reasons
34
+ - `iterationMap` — object mapping plan task IDs to iteration numbers (default `{}` if absent)
35
+ - `clarificationsUsed` — object mapping plan task IDs to booleans (default `{}` if absent)
36
+ - `maxIterations`
37
+
38
+ ## Step 4: Read Native Task Files
39
+
40
+ Use Glob to find task files:
41
+ ```
42
+ Glob("~/.claude/tasks/fp-impl-{planId}/*.json")
43
+ ```
44
+
45
+ For each file found, read and extract:
46
+ - `id` — native task ID
47
+ - `subject` — contains `[{planTaskId}] {description}` — extract planTaskId from the `[...]` prefix
48
+ - `status` — `pending`, `in_progress`, `completed`, or `deleted`
49
+ - `metadata` — object with `fpStatus`, `iterations`, `commit`, `summary`, `reason`, `owner` fields
50
+ - `blockedBy` — array of blocking native task IDs
51
+
52
+ Build `statusMap` keyed by planTaskId:
53
+ ```
54
+ statusMap[planTaskId] = {
55
+ nativeId, status, fpStatus, iterations, commit, summary, reason, owner, blockedBy
56
+ }
57
+ ```
58
+
59
+ **Fallback**: If the `~/.claude/tasks/fp-impl-{planId}/` directory does not exist or is empty:
60
+ - Classify all `taskMap` entries not in `skippedTasks`/`failureReasons` as PENDING
61
+ - Note "Native task files unavailable — using execution-state.json data only" in the output
62
+
63
+ ## Step 5: Active Session Detection
64
+
65
+ Check if `~/.claude/teams/fp-impl-{planId}/config.json` exists:
66
+ ```bash
67
+ ls ~/.claude/teams/fp-impl-{planId}/config.json 2>/dev/null
68
+ ```
69
+
70
+ If it exists AND any native task has `status: "in_progress"`, display warning:
71
+ > "An implementation session may still be active. Stop it before generating a handoff."
72
+
73
+ Proceed regardless (the warning is informational).
74
+
75
+ ## Step 6: Load Plan Descriptions
76
+
77
+ Read `.fractal-planner/plans/{planId}/plan.md`.
78
+
79
+ Build a `planTaskId -> description` map from the Execution Order section. Each entry in the execution order has the format:
80
+ ```
81
+ N. [Task {id}]: {description}
82
+ ```
83
+
84
+ Extract the full description for each task ID. If a task ID is not found in plan.md, fall back to the subject from the native task file.
85
+
86
+ ## Step 7: Read Artifacts
87
+
88
+ Read the following if they exist:
89
+ - `.fractal-planner/plans/{planId}/notepad.md` — for Key Discoveries (extract the `## Entries` section content)
90
+ - For FAILED tasks only: read `.fractal-planner/plans/{planId}/evidence/task-{planTaskId}-verification.md` to extract the failure reason from the `## Summary` section
91
+ - Note whether `.fractal-planner/plans/{planId}/context.md` exists (informational)
92
+
93
+ ## Step 8: Classify Tasks
94
+
95
+ For each plan task ID in `taskMap`, classify using the same table as `fp:status`:
96
+
97
+ | Condition | Classification |
98
+ |-----------|---------------|
99
+ | In `skippedTasks` AND (`status == "deleted"` OR native file absent) | **SKIPPED** |
100
+ | `status == "completed"` AND `fpStatus == "FAILED"` | **FAILED** |
101
+ | `status == "completed"` AND (`fpStatus == "COMPLETED"` OR fpStatus absent) | **COMPLETED** |
102
+ | `status == "in_progress"` | **IN_PROGRESS** |
103
+ | `status == "pending"` | **PENDING** |
104
+ | `status == "deleted"` AND `fpStatus == "SKIPPED"` | **SKIPPED** |
105
+ | Native file not found AND not in `skippedTasks` | **PENDING** |
106
+
107
+ Count each: `completed`, `failed`, `skipped`, `inProgress`, `pending`.
108
+ `total` = number of keys in `taskMap`.
109
+ `remaining` = `inProgress` + `pending`.
110
+
111
+ ## Step 9: Generate handoff.md
112
+
113
+ Write `.fractal-planner/plans/{planId}/handoff.md` with this structure:
114
+
115
+ ```markdown
116
+ # Handoff: {planId}
117
+ Generated: {ISO timestamp}
118
+
119
+ ## Progress
120
+ Completed: {completed}/{total} | Failed: {failed} | Skipped: {skipped} | Remaining: {remaining}
121
+
122
+ ## Completed Tasks
123
+ - {planTaskId}: {description} | Iterations: {n}/{maxIterations} | Commit: {hash}
124
+
125
+ ## Failed Tasks
126
+ - {planTaskId}: {description} | Iterations: {maxIterations}/{maxIterations} | Reason: {reason}
127
+
128
+ ## Skipped Tasks
129
+ - {planTaskId}: {description} | Reason: {skipReason}
130
+
131
+ ## In Progress (Interrupted)
132
+ - {planTaskId}: {description} | Iteration: {n}/{maxIterations} | Owner: {builder}
133
+
134
+ ## Pending Tasks
135
+ - {planTaskId}: {description} | Blocked by: {deps or "none (ready)"}
136
+
137
+ ## Key Discoveries
138
+ {verbatim entries from notepad.md ## Entries section, or "No discoveries recorded."}
139
+
140
+ ## Resume Notes
141
+ - Iteration counts and clarification state preserved in execution-state.json
142
+ {- task-specific warnings based on failure patterns, if any}
143
+ {- "All tasks complete. No resume needed." if completed == total}
144
+
145
+ ## Resume Command
146
+ /fp:implement {planId}
147
+ ```
148
+
149
+ **Rules:**
150
+ - Omit "Failed Tasks" section entirely when `failed == 0`
151
+ - Omit "Skipped Tasks" section entirely when `skipped == 0`
152
+ - Omit "In Progress (Interrupted)" section entirely when `inProgress == 0`
153
+ - Use description from `plan.md` lookup, not truncated subject from native task
154
+ - For COMPLETED: get iterations from `iterationMap[planTaskId]` (fall back to metadata.iterations), commit from metadata.commit
155
+ - For IN_PROGRESS: include owner from task metadata, iteration from `iterationMap[planTaskId]` (default 1)
156
+ - For FAILED: prefer evidence file reason (from Step 7), fall back to `failureReasons[planTaskId]` in execution-state.json
157
+ - For PENDING: list dependencies that are not yet completed. If all dependencies are completed (or task has none), show "none (ready)"
158
+
159
+ ## Step 10: Display Summary
160
+
161
+ Present a summary to the user:
162
+
163
+ ```
164
+ ## Handoff Generated: {planId}
165
+
166
+ **Progress**: [{████████░░░░░░░░░░░░}] {completed}/{total} tasks ({pct}%)
167
+
168
+ | Status | Count |
169
+ |--------------|-------|
170
+ | Completed | {N} |
171
+ | Failed | {N} |
172
+ | Skipped | {N} |
173
+ | In Progress | {N} |
174
+ | Pending | {N} |
175
+
176
+ Handoff written to: `.fractal-planner/plans/{planId}/handoff.md`
177
+
178
+ Resume with: `/fp:implement {planId}`
179
+ ```
180
+
181
+ Build the 20-character progress bar:
182
+ - Filled blocks (`█`): `floor(completed / total * 20)` chars
183
+ - Empty blocks (`░`): remainder
184
+
185
+ If all tasks are completed, replace the resume line with:
186
+ > "All tasks complete. No resume needed."
187
+
188
+ ## Important
189
+
190
+ - This skill is **read-only** except for writing `handoff.md` — it does not modify execution-state.json or native task files
191
+ - Primary source of truth: native task JSON files at `~/.claude/tasks/fp-impl-{planId}/`
192
+ - Secondary source of truth: `execution-state.json` (for `taskMap`, `skippedTasks`, `failureReasons`, `iterationMap`, `clarificationsUsed`)
193
+ - Mirrors `fp:status` patterns for task classification, fallback behavior, and progress display
194
+ - Multiple handoff runs overwrite `handoff.md` — the latest state is most accurate
195
+ - Pre-P7 execution-state.json files (without `iterationMap`/`clarificationsUsed`) are handled gracefully via `{}` defaults