feinai 0.5.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/CHANGELOG.md +41 -0
- package/README.md +230 -0
- package/package.json +60 -0
- package/skills/feinai-dispatch/SKILL.md +233 -0
- package/skills/feinai-implement/SKILL.md +133 -0
- package/skills/feinai-sdd/SKILL.md +291 -0
- package/skills/feinai-write-spec/SKILL.md +178 -0
- package/skills/feinai-write-tasks/SKILL.md +183 -0
- package/src/agents-status.ts +26 -0
- package/src/cli.ts +885 -0
- package/src/dashboard.html +1701 -0
- package/src/dashboard.ts +3 -0
- package/src/db.ts +221 -0
- package/src/format.ts +166 -0
- package/src/opengit.sh +117 -0
- package/src/server.ts +749 -0
- package/src/specs.ts +289 -0
- package/src/sqlite-adapter.ts +130 -0
- package/src/tasks.ts +415 -0
- package/src/worktree-status.ts +97 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: feinai-write-tasks
|
|
3
|
+
description: Use when a spec + plan already exist in feinai (written by `feinai-write-spec` or manually) and need to be broken down into executable tasks. Decomposes the plan into atomic `feinai add` calls, analyzes file-level parallelism, and embeds TDD instructions. Output: a set of tasks with `blocked_by` dependencies ready for `feinai-dispatch` to execute.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# feinai-write-tasks
|
|
7
|
+
|
|
8
|
+
Read an existing spec + plan from tasca, produce the executable task set.
|
|
9
|
+
|
|
10
|
+
## Preconditions
|
|
11
|
+
|
|
12
|
+
1. `feinai status` must succeed
|
|
13
|
+
2. The spec must exist: `feinai spec show SPEC-NNN` returns content
|
|
14
|
+
3. A plan must exist: `feinai plan show SPEC-NNN` returns content
|
|
15
|
+
|
|
16
|
+
If any fails: stop. Tell the user to run `feinai-write-spec` first.
|
|
17
|
+
|
|
18
|
+
## Input
|
|
19
|
+
|
|
20
|
+
User invokes you with a SPEC-ID. If they don't, ask: *"Which SPEC-ID? (e.g. SPEC-121-B)"*.
|
|
21
|
+
|
|
22
|
+
## The flow
|
|
23
|
+
|
|
24
|
+
### Step 1 — Load spec + plan
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
feinai spec show SPEC-NNN --full
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
That single command returns spec + latest plan. Read both. Internalize:
|
|
31
|
+
- What the spec says (the WHAT)
|
|
32
|
+
- What the plan says (the HOW)
|
|
33
|
+
- The "Files to touch" list in the plan
|
|
34
|
+
- The "Task breakdown preview" in the plan — your starting point, not a contract
|
|
35
|
+
|
|
36
|
+
### Step 2 — Build the task graph
|
|
37
|
+
|
|
38
|
+
For each unit of work in the plan, decide:
|
|
39
|
+
|
|
40
|
+
**A. Granularity** — One task per logical change. Rule of thumb: a task is the unit of work a single subagent can complete in one session. Split if too big, merge if too small.
|
|
41
|
+
|
|
42
|
+
**B. Parallelism** — Apply this rule, no exceptions:
|
|
43
|
+
|
|
44
|
+
> **Tasks that touch the same file cannot run in parallel.**
|
|
45
|
+
> Tasks in disjoint files can.
|
|
46
|
+
|
|
47
|
+
When the plan requires changes to a **shared file** (e.g. `router.ts`, `index.ts`, a schema file), split it:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
TASK-NNN-0: edit shared file once (e.g. add all new routes to router.ts)
|
|
51
|
+
↓ blocks
|
|
52
|
+
TASK-NNN-1: implement feature A (controller, service) ┐
|
|
53
|
+
TASK-NNN-2: implement feature B (controller, service) ├ parallel
|
|
54
|
+
TASK-NNN-3: implement feature C (controller, service) ┘
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The shared-file task goes first, sequentially. The rest parallelize.
|
|
58
|
+
|
|
59
|
+
**C. Dependencies** — Use `--blocked-by` to encode:
|
|
60
|
+
- File-level conflicts (above)
|
|
61
|
+
- Logical dependencies (B uses a type defined in A)
|
|
62
|
+
- Test tasks that need implementation tasks first (only if separated — see TDD below)
|
|
63
|
+
|
|
64
|
+
### Step 3 — Embed TDD instructions
|
|
65
|
+
|
|
66
|
+
Each implementation task description starts with this fixed paragraph:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
## TDD baseline
|
|
70
|
+
Write the tests first based on the "Tests required" section of SPEC-NNN.
|
|
71
|
+
Run them — they must fail (the implementation doesn't exist yet).
|
|
72
|
+
Implement until all tests pass. Then run the quality gates.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
No separate "write tests" tasks. Test + implementation live together. The
|
|
76
|
+
agent writes tests first because the description tells it to, and the quality
|
|
77
|
+
gates verify the tests pass.
|
|
78
|
+
|
|
79
|
+
**Exception:** if tests for one task need fixtures shared with other tasks,
|
|
80
|
+
extract the fixtures into a tiny TASK-NNN-0 that other tasks block on.
|
|
81
|
+
|
|
82
|
+
### Step 4 — Write the tasks
|
|
83
|
+
|
|
84
|
+
For each task:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
feinai add TASK-NNN-X "subject" \
|
|
88
|
+
--spec SPEC-NNN \
|
|
89
|
+
--desc "$(cat <<'EOF'
|
|
90
|
+
## TDD baseline
|
|
91
|
+
Write the tests first based on the "Tests required" section of SPEC-NNN.
|
|
92
|
+
Run them — they must fail. Implement until they pass.
|
|
93
|
+
|
|
94
|
+
## Files to touch
|
|
95
|
+
- packages/X/...
|
|
96
|
+
- packages/Y/...
|
|
97
|
+
|
|
98
|
+
## Implementation notes
|
|
99
|
+
<concrete, copy-pasteable details. Cite line numbers if useful.>
|
|
100
|
+
|
|
101
|
+
## Do not touch
|
|
102
|
+
- <files explicitly out of scope>
|
|
103
|
+
EOF
|
|
104
|
+
)" \
|
|
105
|
+
--package "@scope/pkg" \
|
|
106
|
+
--gate "pnpm --filter @scope/pkg typecheck" \
|
|
107
|
+
--gate "pnpm --filter @scope/pkg test -- --run" \
|
|
108
|
+
--blocked-by TASK-NNN-Y # if applicable, repeatable
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Task description = self-contained.** The subagent reads only the task (via
|
|
112
|
+
`feinai take`) and gets spec+plan as `spec_context` automatically. It does NOT
|
|
113
|
+
need to read external files for context.
|
|
114
|
+
|
|
115
|
+
### Step 5 — Annotate parallelism for dispatch
|
|
116
|
+
|
|
117
|
+
After writing all tasks, output a summary table to the user:
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
TASK-NNN-0: shared file edit (sequential)
|
|
121
|
+
TASK-NNN-1: feature A (parallel with 2, 3) blocked-by 0
|
|
122
|
+
TASK-NNN-2: feature B (parallel with 1, 3) blocked-by 0
|
|
123
|
+
TASK-NNN-3: feature C (parallel with 1, 2) blocked-by 0
|
|
124
|
+
TASK-NNN-4: integration tests (sequential) blocked-by 1, 2, 3
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
This summary tells the user (and `feinai-dispatch`) which tasks parallelize.
|
|
128
|
+
|
|
129
|
+
### Step 6 — Hand off
|
|
130
|
+
|
|
131
|
+
Tell the user:
|
|
132
|
+
> Tasks written for SPEC-NNN. View with `feinai list --spec SPEC-NNN`.
|
|
133
|
+
> Next step: run `/feinai-dispatch SPEC-NNN` to execute.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## Important rules
|
|
138
|
+
|
|
139
|
+
### Same-file rule (the only parallelism check that matters)
|
|
140
|
+
|
|
141
|
+
If two pending tasks would write to the same path, they must have a `blocked_by`
|
|
142
|
+
relationship — direct or via a common dependency. This is the only rule the
|
|
143
|
+
subagents need to trust about safety.
|
|
144
|
+
|
|
145
|
+
If a task touches MANY files (e.g. a refactor across the codebase), it does NOT
|
|
146
|
+
parallelize with anything in those files. Mark it sequential by giving it no
|
|
147
|
+
parallel siblings.
|
|
148
|
+
|
|
149
|
+
### Granularity guardrails
|
|
150
|
+
|
|
151
|
+
- Too big: "implement the entire auth system" — split by route
|
|
152
|
+
- Too small: "add a single import" — merge into the larger task
|
|
153
|
+
- Sweet spot: ~50–300 lines of changes, 1–3 files (or a single file for shared)
|
|
154
|
+
|
|
155
|
+
### What goes in description vs gates
|
|
156
|
+
|
|
157
|
+
- **description** — what to do, what to read, what to write, TDD baseline, exclusion list
|
|
158
|
+
- **quality_gates** — the verification commands. Subagent runs them; if they pass, calls `feinai done`.
|
|
159
|
+
|
|
160
|
+
If a gate is project-wide (e.g. `pnpm -r typecheck`), keep it. If it's local
|
|
161
|
+
to the task's package, scope it (`pnpm --filter @x typecheck`) so failures
|
|
162
|
+
don't cascade across unrelated work.
|
|
163
|
+
|
|
164
|
+
---
|
|
165
|
+
|
|
166
|
+
## What NOT to do
|
|
167
|
+
|
|
168
|
+
- ❌ Re-think architecture — it's in the plan, follow it
|
|
169
|
+
- ❌ Write tasks without a SPEC-ID — every task must have `--spec SPEC-NNN`
|
|
170
|
+
- ❌ Skip the same-file analysis — it's the single biggest cause of merge conflicts
|
|
171
|
+
- ❌ Put "and also fix X" in a task — one task, one change
|
|
172
|
+
- ❌ Hardcode worktree paths — `feinai-dispatch` assigns those at execution time
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## Quick reference
|
|
177
|
+
|
|
178
|
+
| Need | Command |
|
|
179
|
+
|---|---|
|
|
180
|
+
| Load spec + plan in one call | `feinai spec show SPEC-N --full` |
|
|
181
|
+
| List existing tasks for spec | `feinai list --spec SPEC-N` |
|
|
182
|
+
| Add task | `feinai add TASK-X "subject" --spec SPEC-N --desc "..." --gate "..." [--blocked-by TASK-Y]` |
|
|
183
|
+
| Edit task after writing | `feinai task edit TASK-X --desc "..." --gate "..."` |
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface AgentProcess {
|
|
2
|
+
pid: number;
|
|
3
|
+
cpu: number;
|
|
4
|
+
mem: number;
|
|
5
|
+
command: string;
|
|
6
|
+
taskId: string | null;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function listAgentProcesses(): Promise<AgentProcess[]> {
|
|
10
|
+
try {
|
|
11
|
+
const result = await Bun.$`ps -eo pid,pcpu,pmem,command | grep -E 'TASK-[A-Z0-9-]+' | grep -v grep`.text();
|
|
12
|
+
const lines = result.trim().split("\n").filter(Boolean);
|
|
13
|
+
return lines.map((line) => {
|
|
14
|
+
const parts = line.trim().split(/\s+/);
|
|
15
|
+
const pid = parseInt(parts[0]!, 10);
|
|
16
|
+
const cpu = parseFloat(parts[1]!);
|
|
17
|
+
const mem = parseFloat(parts[2]!);
|
|
18
|
+
const command = parts.slice(3).join(" ");
|
|
19
|
+
const taskMatch = command.match(/TASK-[A-Z0-9-]+/);
|
|
20
|
+
const taskId = taskMatch ? taskMatch[0] : null;
|
|
21
|
+
return { pid, cpu, mem, command, taskId };
|
|
22
|
+
}).filter((p) => Number.isFinite(p.pid));
|
|
23
|
+
} catch {
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|