feinai 0.6.4 → 0.6.6
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 +14 -14
- package/README.md +184 -68
- package/package.json +1 -1
- package/skills/feinai-dispatch/SKILL.md +2 -2
- package/skills/feinai-implement/SKILL.md +6 -6
- package/skills/feinai-sdd/SKILL.md +3 -3
- package/skills/feinai-write-spec/SKILL.md +4 -4
- package/skills/feinai-write-tasks/SKILL.md +1 -1
- package/src/cli.ts +9 -9
- package/src/dashboard.html +8 -8
- package/src/db.ts +5 -44
- package/src/format.ts +3 -3
- package/src/server.ts +8 -8
- package/src/sqlite-adapter.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -12,23 +12,23 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
12
12
|
## [0.5.0] - 2026-06-10
|
|
13
13
|
|
|
14
14
|
### Added
|
|
15
|
-
- `
|
|
16
|
-
- `opengit` shipped as a binary alongside `
|
|
17
|
-
- `
|
|
18
|
-
- `
|
|
19
|
-
- Live Agents Monitor: working directory, repo name, and `.
|
|
15
|
+
- `feinai git <cmd>` — safe git wrapper subcommand. Passes through to `opengit`, enforcing a worktree-only whitelist (blocks branch, merge, rebase, checkout, etc.)
|
|
16
|
+
- `opengit` shipped as a binary alongside `feinai` — `bun install -g feinai` now installs both
|
|
17
|
+
- `feinai unblock <TASK-ID> --dep <TASK-ID>` — remove a specific dependency from a task
|
|
18
|
+
- `feinai edit --clear-blocked-by` — clear all dependencies from a task
|
|
19
|
+
- Live Agents Monitor: working directory, repo name, and `.feinai` path shown per agent card
|
|
20
20
|
- Live Agents Monitor: presence indicator — gray dot when idle, green dot with ripple animation when agents are active
|
|
21
21
|
- Live Agents Monitor: elapsed time and spec ID per card
|
|
22
|
-
- `
|
|
23
|
-
- Skills: `
|
|
22
|
+
- `feinai init` now auto-adds `.feinai/` to `.gitignore` if in a git repo
|
|
23
|
+
- Skills: `feinai-implement` — claim one pending task, implement in isolated worktree, run quality gates, push to main
|
|
24
24
|
|
|
25
25
|
### Changed
|
|
26
26
|
- Dashboard is now English-only — removed i18n/language selector
|
|
27
|
-
- `
|
|
27
|
+
- `feinai-implement` SKILL.md updated to use `feinai git` instead of `opengit` directly
|
|
28
28
|
- `package.json`: added `repository`, `homepage`, `bugs` fields
|
|
29
29
|
|
|
30
30
|
### Skills included
|
|
31
|
-
`
|
|
31
|
+
`feinai-sdd` · `feinai-write-spec` · `feinai-write-tasks` · `feinai-dispatch` · `feinai-implement`
|
|
32
32
|
|
|
33
33
|
---
|
|
34
34
|
|
|
@@ -37,11 +37,11 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
|
37
37
|
Initial public release. Core CLI with specs, plans, tasks, HTTP dashboard, and SDD skills.
|
|
38
38
|
|
|
39
39
|
### Features
|
|
40
|
-
- `
|
|
41
|
-
- `
|
|
42
|
-
- `
|
|
43
|
-
- `
|
|
40
|
+
- `feinai init / status / list / add / show / take / done / fail / block / release / reopen / edit`
|
|
41
|
+
- `feinai spec` — spec lifecycle (add, start, done, archive, set-content, edit)
|
|
42
|
+
- `feinai plan` — plan revisions per spec
|
|
43
|
+
- `feinai server` — HTTP dashboard + REST API + SSE live updates
|
|
44
44
|
- Live Agents Monitor — real-time view of in-progress tasks with worktree state
|
|
45
45
|
- Atomic `take` — SQL-level concurrency safety for parallel agents
|
|
46
46
|
- Append-only events audit log
|
|
47
|
-
- Skills: `
|
|
47
|
+
- Skills: `feinai-sdd`, `feinai-write-spec`, `feinai-write-tasks`, `feinai-dispatch`
|
package/README.md
CHANGED
|
@@ -1,73 +1,134 @@
|
|
|
1
1
|
# feinai
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Local coordination layer for multi‑agent coding workflows.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
When multiple coding agents work on the same repo, things break long before the model runs out of IQ: duplicated work, inconsistent task state, agents trampling each other's branches, and no clear visibility into what is happening where.
|
|
6
6
|
|
|
7
|
-
feinai
|
|
7
|
+
**feinai** focuses on one thing: make that coordination deterministic, auditable, and safe for your git repo – locally, without a cloud service.
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Why feinai
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Multi‑agent development breaks down without coordination infrastructure. Skills and prompts get agents started, but they do not solve the ugly parts of running several agents in parallel:
|
|
14
14
|
|
|
15
|
-
**
|
|
16
|
-
|
|
17
|
-
**No isolation.** Agents sharing a branch corrupt each other's work mid
|
|
18
|
-
|
|
19
|
-
**
|
|
20
|
-
|
|
21
|
-
**Skill-based approaches hit a ceiling.** Skills and prompt instructions are probabilistic — the model can ignore them, misinterpret them, or hallucinate state. Deterministic coordination requires a tool, not a suggestion. feinai makes the workflow atomic, auditable, and race-free at the infrastructure level.
|
|
15
|
+
- **Token waste on shared Markdown.** Agents reading `QUEUE.md` or `BACKLOG.md` to find their next task burn context on irrelevant state. A 200‑line plan file costs tokens every time – most of it noise for any given agent. feinai gives each agent exactly what it needs in a single call.
|
|
16
|
+
- **Inconsistent task state.** Two agents claim the same task. One overwrites the other's work. You find out when the merge fails. `feinai take` is an atomic SQL operation – if two agents race, one wins and one gets rejected. No duplicates, no silent overwrites.
|
|
17
|
+
- **No isolation in git.** Agents sharing a branch corrupt each other's work mid‑task. `feinai-dispatch` puts every agent in its own git worktree, linked to a specific task, visible in the dashboard. Work is isolated until it's ready to merge.
|
|
18
|
+
- **Zero visibility.** You don't know which agent is doing what, which files it touched, how long it has been running, or whether it's stuck. The feinai dashboard shows all of this live.
|
|
19
|
+
- **Skills hit a ceiling.** Skills and prompt instructions are probabilistic – the model can ignore them, misinterpret them, or hallucinate state. Deterministic coordination requires a tool, not a suggestion. feinai makes the workflow atomic, auditable, and race‑free at the infrastructure level.
|
|
22
20
|
|
|
23
21
|
---
|
|
24
22
|
|
|
25
23
|
## What feinai is
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
feinai is a **CLI + HTTP API + dashboard** that acts as the single source of truth for multi‑agent development workflows on a git repo.
|
|
26
|
+
|
|
27
|
+
It manages four core primitives:
|
|
28
|
+
|
|
29
|
+
- **Specs** – what to build and why.
|
|
30
|
+
- **Plans** – how to build it.
|
|
31
|
+
- **Tasks** – atomic units of work, with dependencies, quality gates, and worktree links.
|
|
32
|
+
- **Events** – append‑only audit log of every state change.
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
- **Plans** — how to build it
|
|
31
|
-
- **Tasks** — atomic units of work, with dependencies, quality gates, and worktree links
|
|
32
|
-
- **Dashboard** — live view of every agent, every worktree, every file being touched
|
|
34
|
+
Agents never read raw Markdown queues. They ask feinai for work:
|
|
33
35
|
|
|
34
|
-
```
|
|
36
|
+
```sh
|
|
35
37
|
feinai take TASK-121-A
|
|
36
38
|
# → {id, subject, description, workplan, packages, quality_gates, worktree, ...}
|
|
37
39
|
# One call. Everything the agent needs. Nothing it doesn't.
|
|
38
40
|
```
|
|
39
41
|
|
|
40
|
-
State lives in a local SQLite file. No cloud, no
|
|
42
|
+
State lives in a local SQLite file. No cloud, no external service, no account.
|
|
41
43
|
|
|
42
44
|
---
|
|
43
45
|
|
|
44
|
-
##
|
|
46
|
+
## Core concepts
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
- **Specs**
|
|
49
|
+
High‑level product requirements: why a feature exists and what "done" means. Specs link to plans and tasks.
|
|
47
50
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
+
- **Plans**
|
|
52
|
+
Versioned implementation plans for a spec. A plan explains how to build it – steps, trade‑offs, constraints.
|
|
51
53
|
|
|
52
|
-
|
|
54
|
+
- **Tasks**
|
|
55
|
+
Atomic units of work with:
|
|
56
|
+
- An ID (`TASK-001-A`)
|
|
57
|
+
- Subject and description
|
|
58
|
+
- Optional `blocked_by` dependencies
|
|
59
|
+
- `quality_gates` (commands/tests that must pass)
|
|
60
|
+
- A dedicated git worktree path
|
|
53
61
|
|
|
54
|
-
|
|
62
|
+
- **Events**
|
|
63
|
+
Append‑only log of everything that happens: `{parent_process}:{pid}:{user}`, timestamps, transitions. Every mutation to specs, plans, tasks or worktrees is recorded.
|
|
55
64
|
|
|
56
|
-
|
|
65
|
+
- **Worktrees**
|
|
66
|
+
Each task gets its own git worktree. Agents commit and push from there. The main branch stays clean until the work is ready to integrate.
|
|
57
67
|
|
|
58
|
-
|
|
68
|
+
---
|
|
59
69
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
70
|
+
## Runtime & footprint
|
|
71
|
+
|
|
72
|
+
- Implemented on top of **Bun 1.3+**.
|
|
73
|
+
- Installs two binaries:
|
|
74
|
+
- `feinai` – main CLI + embedded HTTP server and dashboard.
|
|
75
|
+
- `opengit` – safe git wrapper for parallel worktrees.
|
|
76
|
+
- Stores all state in a single SQLite file: `.feinai/feinai.db`, discovered by walking up from the current directory (like `.git`).
|
|
65
77
|
|
|
66
|
-
|
|
78
|
+
No background services are required beyond the optional dashboard server.
|
|
79
|
+
|
|
80
|
+
---
|
|
67
81
|
|
|
68
|
-
|
|
82
|
+
## Supply chain & safety
|
|
83
|
+
|
|
84
|
+
feinai is designed to be "boring" infrastructure:
|
|
85
|
+
|
|
86
|
+
- **Local‑only state.** All coordination lives in `.feinai/feinai.db` in your repo. There is no remote backend.
|
|
87
|
+
- **Explicit operations.** Every change to specs, plans, tasks and worktrees goes through the CLI or HTTP API and is logged in `events`.
|
|
88
|
+
- **Safe git workflow.** `feinai git` wraps git and blocks operations that can corrupt parallel worktrees (branch, checkout, merge, rebase, reset, fetch, pull, clone).
|
|
89
|
+
- **Auditability.** Every task has a clear chain: spec → plan → task → worktree → events. Every agent identity can be traced (`$FEINAI_USER` override supported).
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Using feinai with coding agents
|
|
94
|
+
|
|
95
|
+
feinai is built to sit **under** coding agents (Claude Code, pi‑style harnesses, etc.) as a coordination layer.
|
|
96
|
+
|
|
97
|
+
A typical pattern:
|
|
98
|
+
|
|
99
|
+
1. Human or design agent writes a spec and plan.
|
|
100
|
+
2. feinai decomposes the plan into tasks with dependencies and quality gates.
|
|
101
|
+
3. Worker agents:
|
|
102
|
+
- Call `feinai take` to claim a task atomically.
|
|
103
|
+
- Work in the dedicated worktree for that task.
|
|
104
|
+
- Run quality gates (tests, linters, typechecks).
|
|
105
|
+
- Mark the task as `done` or `fail` with a structured result.
|
|
106
|
+
4. A human (or integration agent) reviews and merges.
|
|
107
|
+
|
|
108
|
+
Agents don't parse `QUEUE.md`. They talk to a small local coordination service instead.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Claude Code skills
|
|
113
|
+
|
|
114
|
+
feinai ships five Claude Code skills covering the full development loop. They activate automatically when `.feinai/feinai.db` is present:
|
|
115
|
+
|
|
116
|
+
| Skill | Purpose |
|
|
117
|
+
|---------------------|--------------------------------------------------------|
|
|
118
|
+
| `feinai-sdd` | Teaches Claude the feinai workflow and concepts |
|
|
119
|
+
| `feinai-write-spec` | Writes spec + plan into feinai from a design thread |
|
|
120
|
+
| `feinai-write-tasks`| Decomposes a plan into atomic tasks with parallelism |
|
|
121
|
+
| `feinai-dispatch` | Orchestrates subagents in isolated git worktrees |
|
|
122
|
+
| `feinai-implement` | Claims and executes one task end‑to‑end |
|
|
123
|
+
|
|
124
|
+
Together they cover: design → spec → plan → tasks → parallel execution → merge.
|
|
125
|
+
|
|
126
|
+
### Activating skills in Claude Code
|
|
127
|
+
|
|
128
|
+
```sh
|
|
69
129
|
mkdir -p ~/.claude/skills
|
|
70
130
|
SKILLS=~/.bun/install/global/node_modules/feinai/skills
|
|
131
|
+
|
|
71
132
|
for skill in feinai-sdd feinai-write-spec feinai-write-tasks feinai-dispatch feinai-implement; do
|
|
72
133
|
ln -sf "$SKILLS/$skill" ~/.claude/skills/$skill
|
|
73
134
|
done
|
|
@@ -75,53 +136,79 @@ done
|
|
|
75
136
|
|
|
76
137
|
---
|
|
77
138
|
|
|
78
|
-
##
|
|
139
|
+
## Installation
|
|
79
140
|
|
|
80
|
-
|
|
81
|
-
cd my-project
|
|
82
|
-
feinai init # creates .tasca/tasca.db, adds to .gitignore
|
|
141
|
+
Requires [Bun](https://bun.sh/) 1.3+.
|
|
83
142
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
143
|
+
```sh
|
|
144
|
+
bun install -g feinai
|
|
145
|
+
```
|
|
87
146
|
|
|
88
|
-
|
|
89
|
-
feinai done TASK-001-A --result "typecheck ✓"
|
|
147
|
+
This installs:
|
|
90
148
|
|
|
91
|
-
feinai
|
|
149
|
+
- `feinai`
|
|
150
|
+
- `opengit` (safe git wrapper for parallel worktrees)
|
|
151
|
+
|
|
152
|
+
### PATH setup (non‑interactive SSH)
|
|
153
|
+
|
|
154
|
+
In interactive shells and for local agents (Claude Code, opencode) it should work out of the box.
|
|
155
|
+
|
|
156
|
+
For non‑interactive SSH sessions (e.g. `ssh host 'feinai status'`), you may need a one‑time setup:
|
|
157
|
+
|
|
158
|
+
```sh
|
|
159
|
+
sudo ln -sf ~/.bun/bin/feinai /usr/local/bin/feinai
|
|
160
|
+
sudo ln -sf ~/.bun/bin/opengit /usr/local/bin/opengit
|
|
161
|
+
sudo ln -sf ~/.bun/bin/bun /usr/local/bin/bun
|
|
92
162
|
```
|
|
93
163
|
|
|
94
164
|
---
|
|
95
165
|
|
|
96
|
-
##
|
|
166
|
+
## Quick start
|
|
167
|
+
|
|
168
|
+
```sh
|
|
169
|
+
cd my-project
|
|
170
|
+
|
|
171
|
+
# Initialize local state
|
|
172
|
+
feinai init # creates .feinai/feinai.db, adds to .gitignore
|
|
173
|
+
|
|
174
|
+
# Add a spec and plan
|
|
175
|
+
feinai spec add SPEC-001 "User authentication" --content "..."
|
|
176
|
+
feinai plan add SPEC-001 --content "..."
|
|
177
|
+
|
|
178
|
+
# Create a task with a quality gate
|
|
179
|
+
feinai add TASK-001-A "Create auth schema" \
|
|
180
|
+
--spec SPEC-001 \
|
|
181
|
+
--gate "pnpm typecheck"
|
|
97
182
|
|
|
98
|
-
|
|
183
|
+
# Agent claims a task (atomic)
|
|
184
|
+
feinai take TASK-001-A # returns full task payload as JSON
|
|
99
185
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
| `feinai-sdd` | Activates when `.tasca/tasca.db` exists — teaches Claude the workflow |
|
|
103
|
-
| `feinai-write-spec` | Writes spec + plan into feinai from a design conversation |
|
|
104
|
-
| `feinai-write-tasks` | Decomposes plan into atomic tasks with parallelism analysis |
|
|
105
|
-
| `feinai-dispatch` | Orchestrates subagents in isolated git worktrees |
|
|
106
|
-
| `feinai-implement` | Claims and executes one task end-to-end |
|
|
186
|
+
# Agent completes work
|
|
187
|
+
feinai done TASK-001-A --result "typecheck ✓"
|
|
107
188
|
|
|
108
|
-
|
|
189
|
+
# Start dashboard server
|
|
190
|
+
feinai server # live dashboard at http://127.0.0.1:8272
|
|
191
|
+
```
|
|
109
192
|
|
|
110
193
|
---
|
|
111
194
|
|
|
112
195
|
## Commands
|
|
113
196
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
197
|
+
High‑level CLI:
|
|
198
|
+
|
|
199
|
+
```text
|
|
200
|
+
feinai init Create .feinai/feinai.db
|
|
201
|
+
feinai status Show counts: pending / in_progress / completed
|
|
117
202
|
feinai list [--pending] [--spec X] List tasks
|
|
118
203
|
feinai add ID "subject" Create task
|
|
119
204
|
feinai take ID Atomic claim — returns full task JSON
|
|
120
205
|
feinai done ID --result "..." Mark completed
|
|
121
206
|
feinai fail ID --error "..." Mark failed
|
|
122
207
|
feinai release ID Release back to pending
|
|
208
|
+
|
|
123
209
|
feinai spec add/list/show/done Spec lifecycle
|
|
124
210
|
feinai plan add/show Plan versions
|
|
211
|
+
|
|
125
212
|
feinai git <cmd> Safe git wrapper (blocks merge/rebase/checkout)
|
|
126
213
|
feinai server [--port N] [-d] Dashboard + REST API
|
|
127
214
|
```
|
|
@@ -130,34 +217,57 @@ feinai server [--port N] [-d] Dashboard + REST API
|
|
|
130
217
|
|
|
131
218
|
## Dashboard
|
|
132
219
|
|
|
133
|
-
|
|
220
|
+
Run:
|
|
221
|
+
|
|
222
|
+
```sh
|
|
134
223
|
feinai server -d # background, port 8272
|
|
135
224
|
feinai server --port 9000 # custom port
|
|
136
225
|
```
|
|
137
226
|
|
|
138
|
-
|
|
227
|
+
The dashboard shows per agent:
|
|
228
|
+
|
|
229
|
+
- Current task ID
|
|
230
|
+
- Worktree path and repo
|
|
231
|
+
- Files being modified
|
|
232
|
+
- Elapsed time
|
|
233
|
+
|
|
234
|
+
Active agents ripple in green, idle ones in gray. Updates stream in real time via SSE.
|
|
139
235
|
|
|
140
236
|
---
|
|
141
237
|
|
|
142
238
|
## `feinai git`
|
|
143
239
|
|
|
144
|
-
|
|
240
|
+
`feinai git` is a safety wrapper around git for parallel worktrees.
|
|
241
|
+
|
|
242
|
+
Allowed operations include:
|
|
145
243
|
|
|
146
|
-
```
|
|
244
|
+
```sh
|
|
147
245
|
feinai git worktree add .worktrees/TASK-001 origin/main
|
|
148
|
-
feinai git add .
|
|
246
|
+
feinai git add .
|
|
247
|
+
feinai git commit -m "feat: ..."
|
|
149
248
|
feinai git push origin HEAD:main
|
|
150
249
|
feinai git complete # sync main after push
|
|
151
250
|
```
|
|
152
251
|
|
|
153
|
-
|
|
252
|
+
The following are blocked when they would break the parallel workflow:
|
|
253
|
+
|
|
254
|
+
- `branch`
|
|
255
|
+
- `checkout`
|
|
256
|
+
- `merge`
|
|
257
|
+
- `rebase`
|
|
258
|
+
- `reset`
|
|
259
|
+
- `fetch`
|
|
260
|
+
- `pull`
|
|
261
|
+
- `clone`
|
|
262
|
+
|
|
263
|
+
Use your normal git tooling inside each worktree; use `feinai git` when operating on shared branches.
|
|
154
264
|
|
|
155
265
|
---
|
|
156
266
|
|
|
157
267
|
## Architecture
|
|
158
268
|
|
|
159
|
-
```
|
|
160
|
-
<project>/.
|
|
269
|
+
```text
|
|
270
|
+
<project>/.feinai/feinai.db # local SQLite database (discovered like .git)
|
|
161
271
|
|
|
162
272
|
specs — what to build
|
|
163
273
|
plans — how to build it (versioned)
|
|
@@ -165,10 +275,16 @@ tasks — atomic work units with blocked_by, quality_gates, worktree
|
|
|
165
275
|
events — append-only audit log: {parent_process}:{pid}:{user}
|
|
166
276
|
```
|
|
167
277
|
|
|
168
|
-
Every mutation is logged. Every agent is identified.
|
|
278
|
+
Every mutation is logged. Every agent is identified. You can override identity using:
|
|
279
|
+
|
|
280
|
+
```sh
|
|
281
|
+
export FEINAI_USER="ci-bot-01"
|
|
282
|
+
```
|
|
169
283
|
|
|
170
284
|
---
|
|
171
285
|
|
|
172
286
|
## License
|
|
173
287
|
|
|
174
|
-
MIT — built with ❤️ in Barcelona.
|
|
288
|
+
MIT — built with ❤️ in Barcelona.
|
|
289
|
+
|
|
290
|
+
"Feina" means "work" in Catalan. feinai is a tiny piece of infrastructure to keep that work coordinated.
|
package/package.json
CHANGED
|
@@ -66,7 +66,7 @@ PATH issue in non-interactive SSH session. `~/.bun/bin` is not loaded. Tell the
|
|
|
66
66
|
|
|
67
67
|
---
|
|
68
68
|
|
|
69
|
-
### Failure: `feinai status` exits with code 2 (`no .
|
|
69
|
+
### Failure: `feinai status` exits with code 2 (`no .feinai/feinai.db found`)
|
|
70
70
|
|
|
71
71
|
feinai is installed but no DB in this project. Ask the user:
|
|
72
72
|
|
|
@@ -206,7 +206,7 @@ Spawn a subagent with this prompt template:
|
|
|
206
206
|
|
|
207
207
|
### Step E — Wait for results
|
|
208
208
|
|
|
209
|
-
Each subagent returns `done` or `fail`. The
|
|
209
|
+
Each subagent returns `done` or `fail`. The feinai DB is the source of truth — re-query it:
|
|
210
210
|
|
|
211
211
|
```bash
|
|
212
212
|
feinai show TASK-X --json
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: feinai-implement
|
|
3
|
-
description: Use when a feinai task needs to be executed. Claims one pending task from
|
|
3
|
+
description: Use when a feinai task needs to be executed. Claims one pending task from feinai, implements it in an isolated worktree, runs quality gates, and pushes to main. Designed to be dispatched by feinai-dispatch or run standalone for a single task.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# feinai-implement
|
|
7
7
|
|
|
8
|
-
Claim one pending task from
|
|
8
|
+
Claim one pending task from feinai, implement it in an isolated worktree, run quality gates, push to main.
|
|
9
9
|
|
|
10
10
|
## Preconditions
|
|
11
11
|
|
|
12
12
|
1. `feinai status` succeeds and there is at least one pending task
|
|
13
13
|
2. Current working directory is a clean git repo
|
|
14
|
-
3. `feinai git status` works (feinai git is bundled with
|
|
14
|
+
3. `feinai git status` works (feinai git is bundled with feinai — no separate setup needed)
|
|
15
15
|
|
|
16
16
|
If any fails: stop and report. Do not improvise.
|
|
17
17
|
|
|
@@ -79,7 +79,7 @@ Gates fallan → seguí "Si algo falla".
|
|
|
79
79
|
**Done = 3 hechos observables:**
|
|
80
80
|
1. Quality gates pasan sin errores
|
|
81
81
|
2. Los archivos de la tarea existen con contenido correcto
|
|
82
|
-
3. Commit limpio en `main` y tarea en estado `completed` en
|
|
82
|
+
3. Commit limpio en `main` y tarea en estado `completed` en feinai
|
|
83
83
|
|
|
84
84
|
---
|
|
85
85
|
|
|
@@ -102,7 +102,7 @@ Gates fallan, push falla, o error en cualquier paso:
|
|
|
102
102
|
|
|
103
103
|
## Git — `feinai git` exclusivamente
|
|
104
104
|
|
|
105
|
-
`git` y `gh` están bloqueados. Usá `feinai git` para todo — es opengit bundleado con
|
|
105
|
+
`git` y `gh` están bloqueados. Usá `feinai git` para todo — es opengit bundleado con feinai.
|
|
106
106
|
|
|
107
107
|
**Permitido:**
|
|
108
108
|
- `feinai git worktree add/list/lock/unlock`
|
|
@@ -125,7 +125,7 @@ Si `feinai git` falla → **STOP**. No reintentes, no uses `git`. Reportá al us
|
|
|
125
125
|
**No modifiques:**
|
|
126
126
|
- `AGENTS.md`, `CLAUDE.md`
|
|
127
127
|
- Archivos de configuración de CI/CD, infra, o secretos (`.env`, `.env.*`)
|
|
128
|
-
- La DB de
|
|
128
|
+
- La DB de feinai directamente
|
|
129
129
|
|
|
130
130
|
**Código:**
|
|
131
131
|
- Sin `any` sin comentario justificado en la misma línea
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: feinai-sdd
|
|
3
|
-
description: Use when working in spec-driven development (SDD) workflows that involve brainstorming, writing-plans, or subagent-driven-development AND the project has a `\.feinai/feinai.db` file. Replaces creating markdown files in `docs/superpowers/specs/` and `docs/superpowers/plans/` with atomic `feinai` CLI calls, keeping state queryable, race-free, and audit-logged. Also use when the user asks to create a spec, add a task, claim work, or mark progress
|
|
3
|
+
description: Use when working in spec-driven development (SDD) workflows that involve brainstorming, writing-plans, or subagent-driven-development AND the project has a `\.feinai/feinai.db` file. Replaces creating markdown files in `docs/superpowers/specs/` and `docs/superpowers/plans/` with atomic `feinai` CLI calls, keeping state queryable, race-free, and audit-logged. Also use when the user asks to create a spec, add a task, claim work, or mark progress.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# feinai SDD integration
|
|
@@ -21,7 +21,7 @@ Invoke when **all** of the following are true:
|
|
|
21
21
|
|
|
22
22
|
1. The project has a `\.feinai/feinai.db` file (walk up the directory tree from
|
|
23
23
|
the current working directory; feinai uses the same discovery pattern as git).
|
|
24
|
-
Check with: `feinai status` (exit code 0 =
|
|
24
|
+
Check with: `feinai status` (exit code 0 = feinai is set up).
|
|
25
25
|
2. You are about to:
|
|
26
26
|
- Write a spec via the `brainstorming` skill, OR
|
|
27
27
|
- Write a plan via the `writing-plans` skill, OR
|
|
@@ -274,7 +274,7 @@ field will read `bun:<pid>:<user>` for everyone.
|
|
|
274
274
|
|
|
275
275
|
| Need | Command |
|
|
276
276
|
|---|---|
|
|
277
|
-
| Is
|
|
277
|
+
| Is feinai set up here? | `feinai status` |
|
|
278
278
|
| Next pending task | `feinai list --pending --json` |
|
|
279
279
|
| Claim a task atomically | `feinai take TASK-X` |
|
|
280
280
|
| Read a spec | `feinai spec content SPEC-X` |
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: feinai-write-spec
|
|
3
|
-
description: Use when the user wants to design a new feature, refactor, or change in a project that has `.
|
|
3
|
+
description: Use when the user wants to design a new feature, refactor, or change in a project that has `.feinai/feinai.db`. Writes a complete spec + plan into feinai in a single session. Replaces `brainstorming` + `writing-plans` from superpowers when feinai is active. Reads project context (CLAUDE.md, ARCHITECTURE.md, README.md), asks clarifying questions only when context has gaps, and produces spec+plan atomically with one `feinai spec add` + one `feinai plan add`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# feinai-write-spec
|
|
7
7
|
|
|
8
|
-
Write a spec + plan for a feature in one session. Output goes to
|
|
8
|
+
Write a spec + plan for a feature in one session. Output goes to feinai, not markdown files.
|
|
9
9
|
|
|
10
10
|
## Preconditions
|
|
11
11
|
|
|
12
|
-
Run `feinai status` (exit 0 =
|
|
12
|
+
Run `feinai status` (exit 0 = feinai is active). If not active, stop and ask the
|
|
13
13
|
user if they want `feinai init` or to fall back to vanilla superpowers.
|
|
14
14
|
|
|
15
15
|
## The flow — three entry modes
|
|
@@ -163,7 +163,7 @@ These come up mid-session. Ask them inline, one at a time, brief:
|
|
|
163
163
|
|
|
164
164
|
If you delegate the spec drafting to a subagent (e.g. for parallel research),
|
|
165
165
|
the subagent must NOT use this skill — it has no context. Hand it concrete
|
|
166
|
-
findings and let it return text; you write to
|
|
166
|
+
findings and let it return text; you write to feinai yourself.
|
|
167
167
|
|
|
168
168
|
---
|
|
169
169
|
|
|
@@ -5,7 +5,7 @@ description: Use when a spec + plan already exist in feinai (written by `feinai-
|
|
|
5
5
|
|
|
6
6
|
# feinai-write-tasks
|
|
7
7
|
|
|
8
|
-
Read an existing spec + plan from
|
|
8
|
+
Read an existing spec + plan from feinai, produce the executable task set.
|
|
9
9
|
|
|
10
10
|
## Preconditions
|
|
11
11
|
|
package/src/cli.ts
CHANGED
|
@@ -381,9 +381,9 @@ async function cmdDestroy(args: ParsedArgs): Promise<void> {
|
|
|
381
381
|
}
|
|
382
382
|
}
|
|
383
383
|
|
|
384
|
-
const
|
|
385
|
-
rmSync(
|
|
386
|
-
console.log(`Destroyed ${
|
|
384
|
+
const feinaiDir = dbPath.replace(/\/feinai\.db$/, "");
|
|
385
|
+
rmSync(feinaiDir, { recursive: true, force: true });
|
|
386
|
+
console.log(`Destroyed ${feinaiDir}`);
|
|
387
387
|
}
|
|
388
388
|
|
|
389
389
|
function cmdInit(args: ParsedArgs): void {
|
|
@@ -770,7 +770,7 @@ function cmdSpec(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
770
770
|
async function cmdServer(args: ParsedArgs): Promise<void> {
|
|
771
771
|
const port = Number(args.options.port ?? "8272");
|
|
772
772
|
|
|
773
|
-
// --down: kill whatever is listening on the
|
|
773
|
+
// --down: kill whatever is listening on the feinai port
|
|
774
774
|
if (args.flags["down"]) {
|
|
775
775
|
if (Number.isNaN(port) || port < 1 || port > 65535) {
|
|
776
776
|
console.error("Error: --port must be a valid port number");
|
|
@@ -785,7 +785,7 @@ async function cmdServer(args: ParsedArgs): Promise<void> {
|
|
|
785
785
|
for (const pid of pids) {
|
|
786
786
|
try {
|
|
787
787
|
process.kill(Number(pid), "SIGTERM");
|
|
788
|
-
console.log(`Stopped
|
|
788
|
+
console.log(`Stopped feinai server (PID ${pid}).`);
|
|
789
789
|
} catch {
|
|
790
790
|
console.error(`Failed to kill PID ${pid}.`);
|
|
791
791
|
}
|
|
@@ -812,8 +812,8 @@ async function cmdServer(args: ParsedArgs): Promise<void> {
|
|
|
812
812
|
: [process.execPath, ...process.argv.slice(1).filter(noDaemon)];
|
|
813
813
|
const child = Bun.spawn(childArgs, { detached: true, stdio: ["ignore", "ignore", "ignore"] });
|
|
814
814
|
child.unref();
|
|
815
|
-
console.log(`
|
|
816
|
-
console.log(`Stop with:
|
|
815
|
+
console.log(`feinai dashboard → http://${host}:${port}`);
|
|
816
|
+
console.log(`Stop with: feinai server --down`);
|
|
817
817
|
return;
|
|
818
818
|
}
|
|
819
819
|
|
|
@@ -821,8 +821,8 @@ async function cmdServer(args: ParsedArgs): Promise<void> {
|
|
|
821
821
|
const { startServer } = await import("./server");
|
|
822
822
|
const server = startServer({ port, host });
|
|
823
823
|
|
|
824
|
-
console.log(`
|
|
825
|
-
console.log(`Stop with:
|
|
824
|
+
console.log(`feinai dashboard listening at ${server.url}`);
|
|
825
|
+
console.log(`Stop with: feinai server --down`);
|
|
826
826
|
|
|
827
827
|
// Keep process alive until SIGINT
|
|
828
828
|
process.on("SIGINT", () => {
|
package/src/dashboard.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
-
<title>
|
|
6
|
+
<title>feinai dashboard</title>
|
|
7
7
|
<style>
|
|
8
8
|
:root {
|
|
9
9
|
--bg: #0f1117;
|
|
@@ -672,7 +672,7 @@
|
|
|
672
672
|
<header>
|
|
673
673
|
<h1>
|
|
674
674
|
<span class="live-indicator" id="live"></span>
|
|
675
|
-
|
|
675
|
+
feinai
|
|
676
676
|
</h1>
|
|
677
677
|
<div class="stats" id="stats"></div>
|
|
678
678
|
<div class="header-actions">
|
|
@@ -723,7 +723,7 @@
|
|
|
723
723
|
</section>
|
|
724
724
|
</main>
|
|
725
725
|
|
|
726
|
-
<footer>
|
|
726
|
+
<footer>feinai · streaming live · click any item for details & actions · <span id="dash-version">v—</span></footer>
|
|
727
727
|
|
|
728
728
|
<div class="modal-bg" id="modal-bg">
|
|
729
729
|
<div class="modal" id="modal">
|
|
@@ -784,7 +784,7 @@
|
|
|
784
784
|
// -------- Confirm modal --------
|
|
785
785
|
function confirm(message, skipKey) {
|
|
786
786
|
return new Promise((resolve) => {
|
|
787
|
-
if (localStorage.getItem("
|
|
787
|
+
if (localStorage.getItem("feinai-skip-" + skipKey) === "1") { resolve(true); return; }
|
|
788
788
|
const overlay = document.createElement("div");
|
|
789
789
|
overlay.style.cssText = "position:fixed;inset:0;background:rgba(0,0,0,.6);z-index:9999;display:flex;align-items:center;justify-content:center;";
|
|
790
790
|
overlay.innerHTML = `
|
|
@@ -800,7 +800,7 @@
|
|
|
800
800
|
</div>`;
|
|
801
801
|
document.body.appendChild(overlay);
|
|
802
802
|
overlay.querySelector("#confirm-ok").onclick = () => {
|
|
803
|
-
if (overlay.querySelector("#skip-cb").checked) localStorage.setItem("
|
|
803
|
+
if (overlay.querySelector("#skip-cb").checked) localStorage.setItem("feinai-skip-" + skipKey, "1");
|
|
804
804
|
document.body.removeChild(overlay); resolve(true);
|
|
805
805
|
};
|
|
806
806
|
overlay.querySelector("#confirm-cancel").onclick = () => { document.body.removeChild(overlay); resolve(false); };
|
|
@@ -827,7 +827,7 @@
|
|
|
827
827
|
async function api(method, path, body) {
|
|
828
828
|
const res = await fetch(path, {
|
|
829
829
|
method,
|
|
830
|
-
headers: body ? { "Content-Type": "application/json", "X-
|
|
830
|
+
headers: body ? { "Content-Type": "application/json", "X-Feinai-Actor": "dashboard" } : { "X-Feinai-Actor": "dashboard" },
|
|
831
831
|
body: body ? JSON.stringify(body) : undefined,
|
|
832
832
|
});
|
|
833
833
|
if (!res.ok) {
|
|
@@ -1456,7 +1456,7 @@
|
|
|
1456
1456
|
: '';
|
|
1457
1457
|
const workingDir = task.worktree || appContext.repoRoot || "—";
|
|
1458
1458
|
const repoName = appContext.repoName || "—";
|
|
1459
|
-
const
|
|
1459
|
+
const feinaiLoc = appContext.feinaiPath || "—";
|
|
1460
1460
|
const card = document.createElement('div');
|
|
1461
1461
|
card.className = 'worktree-card';
|
|
1462
1462
|
card.setAttribute('data-worktree-task', task.id);
|
|
@@ -1469,7 +1469,7 @@
|
|
|
1469
1469
|
<div class="worktree-context">
|
|
1470
1470
|
<div class="context-row"><span class="context-label">Working directory</span><span class="context-value">${escapeHtml(workingDir)}</span></div>
|
|
1471
1471
|
<div class="context-row"><span class="context-label">Repo</span><span class="context-value">${escapeHtml(repoName)}</span></div>
|
|
1472
|
-
<div class="context-row"><span class="context-label">.feinai</span><span class="context-value">${escapeHtml(
|
|
1472
|
+
<div class="context-row"><span class="context-label">.feinai</span><span class="context-value">${escapeHtml(feinaiLoc)}</span></div>
|
|
1473
1473
|
</div>
|
|
1474
1474
|
<span class="elapsed-time" data-elapsed="${escapeHtml(task.taken_at ?? '')}"></span>
|
|
1475
1475
|
</div>
|
package/src/db.ts
CHANGED
|
@@ -1,47 +1,10 @@
|
|
|
1
|
-
import { existsSync, mkdirSync
|
|
1
|
+
import { existsSync, mkdirSync } from "node:fs";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { openSqlite, type DbAdapter } from "./sqlite-adapter";
|
|
4
4
|
|
|
5
5
|
const DB_DIR = ".feinai";
|
|
6
6
|
const DB_FILE = "feinai.db";
|
|
7
7
|
|
|
8
|
-
// v0.5.x migration: rename .tasca/tasca.db → .feinai/feinai.db
|
|
9
|
-
// TODO: remove in v0.7
|
|
10
|
-
function migrateLegacyDir(dir: string): void {
|
|
11
|
-
const legacyDir = join(dir, ".tasca");
|
|
12
|
-
const legacyDb = join(legacyDir, "tasca.db");
|
|
13
|
-
const newDir = join(dir, ".feinai");
|
|
14
|
-
const newDb = join(newDir, "feinai.db");
|
|
15
|
-
if (!existsSync(legacyDb) || existsSync(newDb)) return;
|
|
16
|
-
|
|
17
|
-
// Prompt user — only works in TTY contexts
|
|
18
|
-
if (process.stdout.isTTY) {
|
|
19
|
-
process.stdout.write(
|
|
20
|
-
`\n⚠ Found legacy .tasca/tasca.db at ${legacyDir}\n` +
|
|
21
|
-
` Rename to .feinai/feinai.db? [Y/n] `
|
|
22
|
-
);
|
|
23
|
-
const buf = Buffer.alloc(4);
|
|
24
|
-
let answer = "y";
|
|
25
|
-
try {
|
|
26
|
-
const n = require("node:fs").readSync(0, buf, 0, 4, null);
|
|
27
|
-
answer = buf.slice(0, n).toString().trim().toLowerCase() || "y";
|
|
28
|
-
} catch {}
|
|
29
|
-
if (answer !== "y" && answer !== "") {
|
|
30
|
-
process.stdout.write("Skipped. Run 'feinai init' to create a new DB.\n\n");
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
} else {
|
|
34
|
-
// Non-interactive (agent/CI): migrate silently
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (!existsSync(newDir)) mkdirSync(newDir, { recursive: true });
|
|
38
|
-
renameSync(legacyDb, newDb);
|
|
39
|
-
try { require("node:fs").rmdirSync(legacyDir); } catch {}
|
|
40
|
-
if (process.stdout.isTTY) {
|
|
41
|
-
process.stdout.write(`✓ Migrated to .feinai/feinai.db\n\n`);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
8
|
export type DbInstance = DbAdapter;
|
|
46
9
|
|
|
47
10
|
/**
|
|
@@ -189,8 +152,6 @@ function applySchema(db: DbInstance): void {
|
|
|
189
152
|
export function findDbPath(startDir: string = process.cwd()): string | null {
|
|
190
153
|
let current = resolve(startDir);
|
|
191
154
|
while (true) {
|
|
192
|
-
// migrate legacy .tasca/tasca.db → .feinai/feinai.db if found
|
|
193
|
-
migrateLegacyDir(current);
|
|
194
155
|
const candidate = join(current, DB_DIR, DB_FILE);
|
|
195
156
|
if (existsSync(candidate)) return candidate;
|
|
196
157
|
const parent = dirname(current);
|
|
@@ -204,11 +165,11 @@ export function findDbPath(startDir: string = process.cwd()): string | null {
|
|
|
204
165
|
* Returns the absolute path of the created DB file.
|
|
205
166
|
*/
|
|
206
167
|
export function initDb(dir: string = process.cwd()): string {
|
|
207
|
-
const
|
|
208
|
-
const dbPath = join(
|
|
168
|
+
const feinaiDir = join(dir, DB_DIR);
|
|
169
|
+
const dbPath = join(feinaiDir, DB_FILE);
|
|
209
170
|
|
|
210
|
-
if (!existsSync(
|
|
211
|
-
mkdirSync(
|
|
171
|
+
if (!existsSync(feinaiDir)) {
|
|
172
|
+
mkdirSync(feinaiDir, { recursive: true });
|
|
212
173
|
}
|
|
213
174
|
|
|
214
175
|
const db = openSqlite(dbPath, { create: true });
|
package/src/format.ts
CHANGED
|
@@ -96,7 +96,7 @@ export function formatSpec(
|
|
|
96
96
|
if (opts.includeContent) {
|
|
97
97
|
for (const line of spec.content.split("\n")) lines.push(` ${line}`);
|
|
98
98
|
} else {
|
|
99
|
-
lines.push(` ${c(format, "dim", "(use --full to view;
|
|
99
|
+
lines.push(` ${c(format, "dim", "(use --full to view; feinai spec content " + spec.id + " to export)")}`);
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
if (opts.plan) {
|
|
@@ -104,7 +104,7 @@ export function formatSpec(
|
|
|
104
104
|
if (opts.includeContent) {
|
|
105
105
|
for (const line of opts.plan.content.split("\n")) lines.push(` ${line}`);
|
|
106
106
|
} else {
|
|
107
|
-
lines.push(` ${c(format, "dim", "(use --full to view;
|
|
107
|
+
lines.push(` ${c(format, "dim", "(use --full to view; feinai plan show " + spec.id + " to export)")}`);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
return lines.join("\n");
|
|
@@ -154,7 +154,7 @@ export function formatStatus(
|
|
|
154
154
|
if (format === "json") return JSON.stringify(stats, null, 2);
|
|
155
155
|
const serverLine = stats.serverRunning
|
|
156
156
|
? c(format, "green", `server: running → http://127.0.0.1:${stats.serverPort}`)
|
|
157
|
-
: c(format, "dim", `server: stopped (
|
|
157
|
+
: c(format, "dim", `server: stopped (feinai server -d to start)`);
|
|
158
158
|
return [
|
|
159
159
|
`${c(format, "yellow", `pending: ${stats.pending}`)}`,
|
|
160
160
|
`${c(format, "blue", `in_progress: ${stats.in_progress}`)}`,
|
package/src/server.ts
CHANGED
|
@@ -250,7 +250,7 @@ function serverError(err: unknown): Response {
|
|
|
250
250
|
|
|
251
251
|
/**
|
|
252
252
|
* Determine actor for an inbound HTTP mutation. Priority:
|
|
253
|
-
* 1. X-
|
|
253
|
+
* 1. X-Feinai-Actor header (explicit)
|
|
254
254
|
* 2. derived from request: "dashboard:<host>" or "api:<user-agent>"
|
|
255
255
|
*/
|
|
256
256
|
function actorFromRequest(req: Request): string {
|
|
@@ -258,7 +258,7 @@ function actorFromRequest(req: Request): string {
|
|
|
258
258
|
// iterate manually to be safe.
|
|
259
259
|
let explicit: string | undefined;
|
|
260
260
|
for (const [k, v] of req.headers.entries()) {
|
|
261
|
-
if (k.toLowerCase() === "x-
|
|
261
|
+
if (k.toLowerCase() === "x-feinai-actor") {
|
|
262
262
|
explicit = v;
|
|
263
263
|
break;
|
|
264
264
|
}
|
|
@@ -294,9 +294,9 @@ async function resolveDashboardVersion(): Promise<string> {
|
|
|
294
294
|
const root = findRepoRoot();
|
|
295
295
|
if (!root) return "";
|
|
296
296
|
try {
|
|
297
|
-
const countResult = await Bun.$`git log --oneline --
|
|
297
|
+
const countResult = await Bun.$`git log --oneline -- src/dashboard.html | wc -l`.cwd(root).text();
|
|
298
298
|
const count = parseInt(countResult.trim(), 10);
|
|
299
|
-
const hashResult = await Bun.$`git log -1 --format=%h --
|
|
299
|
+
const hashResult = await Bun.$`git log -1 --format=%h -- src/dashboard.html`.cwd(root).text();
|
|
300
300
|
const hash = hashResult.trim();
|
|
301
301
|
cachedDashboardVersion = `dashboard-v${count} (${hash})`;
|
|
302
302
|
} catch {
|
|
@@ -325,7 +325,7 @@ export function startServer(opts: ServerOptions): { url: string; stop: () => voi
|
|
|
325
325
|
headers: {
|
|
326
326
|
"Access-Control-Allow-Origin": "*",
|
|
327
327
|
"Access-Control-Allow-Methods": "GET, POST, DELETE, PATCH, OPTIONS",
|
|
328
|
-
"Access-Control-Allow-Headers": "Content-Type, X-
|
|
328
|
+
"Access-Control-Allow-Headers": "Content-Type, X-Feinai-Actor",
|
|
329
329
|
},
|
|
330
330
|
});
|
|
331
331
|
}
|
|
@@ -441,18 +441,18 @@ export function startServer(opts: ServerOptions): { url: string; stop: () => voi
|
|
|
441
441
|
return json(agents);
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
-
// GET /api/context — repo and
|
|
444
|
+
// GET /api/context — repo and feinai DB context info for dashboard
|
|
445
445
|
if (path === "/api/context" && method === "GET") {
|
|
446
446
|
const repoRoot = findRepoRoot();
|
|
447
447
|
const dbPath = findDbPath();
|
|
448
448
|
const home = homedir();
|
|
449
|
-
const
|
|
449
|
+
const feinaiPath = dbPath?.startsWith(home)
|
|
450
450
|
? `~${dbPath.slice(home.length)}`
|
|
451
451
|
: (dbPath ?? null);
|
|
452
452
|
return json({
|
|
453
453
|
repoRoot: repoRoot ?? null,
|
|
454
454
|
repoName: repoRoot ? basename(repoRoot) : null,
|
|
455
|
-
|
|
455
|
+
feinaiPath,
|
|
456
456
|
});
|
|
457
457
|
}
|
|
458
458
|
|
package/src/sqlite-adapter.ts
CHANGED
|
@@ -114,7 +114,7 @@ export function getSqliteConstructor(): DbConstructor {
|
|
|
114
114
|
|
|
115
115
|
if (!_constructor) {
|
|
116
116
|
console.error(`
|
|
117
|
-
Error: No SQLite backend found.
|
|
117
|
+
Error: No SQLite backend found. feinai requires one of:
|
|
118
118
|
• Bun 1.0+ (current runtime)
|
|
119
119
|
• Node.js 22.5+ (built-in node:sqlite)
|
|
120
120
|
• better-sqlite3 (npm install -g better-sqlite3)
|