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.
@@ -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
+ }