feinai 0.5.6 → 0.5.8
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/README.md +1 -1
- package/package.json +1 -1
- package/skills/feinai-sdd/SKILL.md +10 -10
- package/src/cli.ts +48 -42
package/README.md
CHANGED
|
@@ -165,7 +165,7 @@ tasks — atomic work units with blocked_by, quality_gates, worktree
|
|
|
165
165
|
events — append-only audit log: {parent_process}:{pid}:{user}
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
Every mutation is logged. Every agent is identified. Override identity with `$
|
|
168
|
+
Every mutation is logged. Every agent is identified. Override identity with `$FEINAI_USER`.
|
|
169
169
|
|
|
170
170
|
---
|
|
171
171
|
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ name: feinai-sdd
|
|
|
3
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 `.tasca/tasca.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, in a project that uses tasca.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
#
|
|
6
|
+
# feinai SDD integration
|
|
7
7
|
|
|
8
8
|
`feinai` is a CLI + local SQLite database for managing specs, plans, and tasks in
|
|
9
9
|
SDD workflows. When a project has `.tasca/tasca.db`, you should write to that
|
|
@@ -20,7 +20,7 @@ just change *where the artifacts get stored*.
|
|
|
20
20
|
Invoke when **all** of the following are true:
|
|
21
21
|
|
|
22
22
|
1. The project has a `.tasca/tasca.db` file (walk up the directory tree from
|
|
23
|
-
the current working directory;
|
|
23
|
+
the current working directory; feinai uses the same discovery pattern as git).
|
|
24
24
|
Check with: `feinai status` (exit code 0 = tasca is set up).
|
|
25
25
|
2. You are about to:
|
|
26
26
|
- Write a spec via the `brainstorming` skill, OR
|
|
@@ -41,7 +41,7 @@ Before any spec / plan / task write, run:
|
|
|
41
41
|
feinai status 2>/dev/null
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
- Exit code 0:
|
|
44
|
+
- Exit code 0: feinai is active in this project → use this skill.
|
|
45
45
|
- Exit code 2: `No .tasca/tasca.db found` → fall back to vanilla superpowers
|
|
46
46
|
(or ask the user `feinai init` if it seems intended).
|
|
47
47
|
- Command not found: feinai is not installed or not on PATH. Tell the user:
|
|
@@ -96,7 +96,7 @@ FEINAI_EOF
|
|
|
96
96
|
|
|
97
97
|
### What replaces what
|
|
98
98
|
|
|
99
|
-
| Superpowers step |
|
|
99
|
+
| Superpowers step | feinai equivalent |
|
|
100
100
|
|---|---|
|
|
101
101
|
| `Write(docs/superpowers/specs/YYYY-MM-DD-X-design.md, ...)` | `feinai spec add SPEC-NNN "title" --stdin <<<` content |
|
|
102
102
|
| Spec self-review (re-read the markdown) | `feinai spec content SPEC-NNN` (returns the markdown) |
|
|
@@ -169,7 +169,7 @@ single response, the full payload: `description` (workplan), `quality_gates`,
|
|
|
169
169
|
`packages`, `blocked_by`. **The subagent never has to read the plan markdown.**
|
|
170
170
|
|
|
171
171
|
This is the single biggest token saving and the strongest correctness
|
|
172
|
-
guarantee from using
|
|
172
|
+
guarantee from using feinai: each subagent's context contains exactly the task
|
|
173
173
|
it's executing, nothing else.
|
|
174
174
|
|
|
175
175
|
---
|
|
@@ -248,7 +248,7 @@ human-readable rationale; the tasks are the executable state.
|
|
|
248
248
|
|
|
249
249
|
### ❌ Don't create `docs/superpowers/specs/*.md` files
|
|
250
250
|
|
|
251
|
-
If
|
|
251
|
+
If feinai is active, those files become a source of drift. The spec lives in
|
|
252
252
|
the database. If you need to publish the spec elsewhere (PR description, wiki,
|
|
253
253
|
etc.), export it on demand: `feinai spec content SPEC-X > /tmp/spec.md`.
|
|
254
254
|
|
|
@@ -262,9 +262,9 @@ subagents that both `show` then act will collide. Always `feinai take`.
|
|
|
262
262
|
The CLI handles concurrency, audit logging, and validation. Direct SQL
|
|
263
263
|
mutations bypass the events table and leave the audit log incomplete.
|
|
264
264
|
|
|
265
|
-
### ✅ Do set `
|
|
265
|
+
### ✅ Do set `FEINAI_USER` for explicit subagent identity
|
|
266
266
|
|
|
267
|
-
When dispatching a subagent, pass `
|
|
267
|
+
When dispatching a subagent, pass `FEINAI_USER=subagent-N` in its environment
|
|
268
268
|
so the audit log distinguishes which subagent did what. Otherwise the actor
|
|
269
269
|
field will read `bun:<pid>:<user>` for everyone.
|
|
270
270
|
|
|
@@ -294,8 +294,8 @@ field will read `bun:<pid>:<user>` for everyone.
|
|
|
294
294
|
|
|
295
295
|
This skill is **additive**. The superpowers skills (`brainstorming`,
|
|
296
296
|
`writing-plans`, `subagent-driven-development`, etc.) still run; they still
|
|
297
|
-
own the process.
|
|
297
|
+
own the process. feinai only changes the storage of the artifacts they produce.
|
|
298
298
|
|
|
299
|
-
If you start brainstorming and discover the project has no
|
|
299
|
+
If you start brainstorming and discover the project has no feinai DB, fall back
|
|
300
300
|
to the normal superpowers behavior (markdown files). Do not silently switch
|
|
301
301
|
storage strategy mid-project.
|
package/src/cli.ts
CHANGED
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
type OutputFormat,
|
|
49
49
|
} from "./format";
|
|
50
50
|
|
|
51
|
-
const VERSION = "0.5.
|
|
51
|
+
const VERSION = "0.5.8";
|
|
52
52
|
|
|
53
53
|
interface ParsedArgs {
|
|
54
54
|
positional: string[];
|
|
@@ -123,10 +123,10 @@ function detectFormat(args: ParsedArgs): OutputFormat {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
/**
|
|
126
|
-
* Build a stable identifier for whoever is invoking
|
|
126
|
+
* Build a stable identifier for whoever is invoking feinai.
|
|
127
127
|
*
|
|
128
128
|
* Priority:
|
|
129
|
-
* 1. $
|
|
129
|
+
* 1. $FEINAI_USER env var (explicit override — used by agents to identify themselves)
|
|
130
130
|
* 2. parent process name (on Linux via /proc/$PPID/comm) → "{parent_name}:{ppid}:{user}"
|
|
131
131
|
* 3. fallback: "{user}@{hostname}"
|
|
132
132
|
*
|
|
@@ -134,7 +134,7 @@ function detectFormat(args: ParsedArgs): OutputFormat {
|
|
|
134
134
|
* from "bash:9999:m" in the events audit log without manual configuration.
|
|
135
135
|
*/
|
|
136
136
|
function getCurrentUser(): string {
|
|
137
|
-
const override = process.env.
|
|
137
|
+
const override = process.env.FEINAI_USER;
|
|
138
138
|
if (override) return override;
|
|
139
139
|
|
|
140
140
|
const username = process.env.USER ?? userInfo().username ?? "unknown";
|
|
@@ -163,7 +163,7 @@ function getCurrentUser(): string {
|
|
|
163
163
|
function ensureDb(): ReturnType<typeof openDb> {
|
|
164
164
|
if (!findDbPath()) {
|
|
165
165
|
console.error(
|
|
166
|
-
"Error: no .tasca/tasca.db found. Run '
|
|
166
|
+
"Error: no .tasca/tasca.db found. Run 'feinai init' to create one.",
|
|
167
167
|
);
|
|
168
168
|
process.exit(2);
|
|
169
169
|
}
|
|
@@ -182,10 +182,10 @@ function readContentFromArgs(args: ParsedArgs): string | undefined {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
function showHelp(): void {
|
|
185
|
-
console.log(`
|
|
185
|
+
console.log(`feinai v\${VERSION} — task & spec manager for AI agents and humans
|
|
186
186
|
|
|
187
187
|
USAGE:
|
|
188
|
-
|
|
188
|
+
feinai <command> [options]
|
|
189
189
|
|
|
190
190
|
DB MANAGEMENT:
|
|
191
191
|
init [--force] Create .tasca/tasca.db in cwd
|
|
@@ -250,7 +250,7 @@ SERVER:
|
|
|
250
250
|
--port <N> Port (default: 8272 — TASC on phone keypad)
|
|
251
251
|
--host <addr> Bind host (default: 127.0.0.1)
|
|
252
252
|
server --daemon / -d Start detached (no job control noise)
|
|
253
|
-
server --down Stop the running
|
|
253
|
+
server --down Stop the running feinai server (by port)
|
|
254
254
|
|
|
255
255
|
GLOBAL FLAGS:
|
|
256
256
|
--json Output as JSON
|
|
@@ -259,13 +259,19 @@ GLOBAL FLAGS:
|
|
|
259
259
|
--version Show version
|
|
260
260
|
|
|
261
261
|
ENV:
|
|
262
|
-
|
|
262
|
+
FEINAI_USER Override owner/actor identity used in audit log
|
|
263
263
|
|
|
264
|
-
\x1b[34m\x1b[1m──
|
|
265
|
-
\x1b[
|
|
266
|
-
|
|
267
|
-
\x1b[
|
|
268
|
-
|
|
264
|
+
\x1b[34m\x1b[1m── Claude Code Skills ─────────────────────────────────────────────\x1b[0m
|
|
265
|
+
\x1b[36mActivate feinai skills for Claude Code (run once after install):\x1b[0m
|
|
266
|
+
|
|
267
|
+
\x1b[33mmkdir -p ~/.claude/skills\x1b[0m
|
|
268
|
+
\x1b[33mSKILLS=~/.bun/install/global/node_modules/feinai/skills\x1b[0m
|
|
269
|
+
\x1b[33mfor skill in feinai-sdd feinai-write-spec feinai-write-tasks feinai-dispatch feinai-implement; do\x1b[0m
|
|
270
|
+
\x1b[33m ln -sf "$SKILLS/$skill" ~/.claude/skills/$skill\x1b[0m
|
|
271
|
+
\x1b[33mdone\x1b[0m
|
|
272
|
+
|
|
273
|
+
\x1b[36mSkills included:\x1b[0m
|
|
274
|
+
\x1b[34m \x1b[1;94mfeinai-sdd\x1b[0m \x1b[1;94mfeinai-write-spec\x1b[0m \x1b[1;94mfeinai-write-tasks\x1b[0m \x1b[1;94mfeinai-dispatch\x1b[0m \x1b[1;94mfeinai-implement\x1b[0m
|
|
269
275
|
\x1b[34m\x1b[1m────────────────────────────────────────────────────────────────────\x1b[0m
|
|
270
276
|
`);
|
|
271
277
|
}
|
|
@@ -328,7 +334,7 @@ async function main(): Promise<void> {
|
|
|
328
334
|
return;
|
|
329
335
|
default:
|
|
330
336
|
console.error(`Unknown command: ${command}`);
|
|
331
|
-
console.error("Run '
|
|
337
|
+
console.error("Run 'feinai --help' for usage.");
|
|
332
338
|
process.exit(1);
|
|
333
339
|
}
|
|
334
340
|
} catch (err) {
|
|
@@ -347,7 +353,7 @@ function cmdGit(rest: string[]): void {
|
|
|
347
353
|
const opengitPath = resolve(__dirname, "opengit.sh");
|
|
348
354
|
|
|
349
355
|
if (rest.length === 0) {
|
|
350
|
-
console.error("Usage:
|
|
356
|
+
console.error("Usage: feinai git <subcommand> [args...]");
|
|
351
357
|
console.error("Runs opengit — safe git wrapper for parallel worktree workflows.");
|
|
352
358
|
process.exit(1);
|
|
353
359
|
}
|
|
@@ -383,12 +389,12 @@ async function cmdDestroy(args: ParsedArgs): Promise<void> {
|
|
|
383
389
|
function cmdInit(args: ParsedArgs): void {
|
|
384
390
|
const existing = findDbPath();
|
|
385
391
|
if (existing && !args.flags.force) {
|
|
386
|
-
console.error(`
|
|
392
|
+
console.error(`feinai DB already exists at ${existing}`);
|
|
387
393
|
console.error(`Use --force to create a nested DB anyway.`);
|
|
388
394
|
process.exit(1);
|
|
389
395
|
}
|
|
390
396
|
const path = initDb();
|
|
391
|
-
console.log(`Initialized
|
|
397
|
+
console.log(`Initialized feinai DB at ${path}`);
|
|
392
398
|
|
|
393
399
|
// Auto-add .tasca/ to .gitignore if inside a git repo
|
|
394
400
|
if (existsSync(".git")) {
|
|
@@ -459,7 +465,7 @@ function cmdAdd(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
459
465
|
const [id, ...subjectParts] = rest;
|
|
460
466
|
if (!id || subjectParts.length === 0) {
|
|
461
467
|
console.error(
|
|
462
|
-
"Usage:
|
|
468
|
+
"Usage: feinai add <TASK-ID> <subject> [--spec ID] [--desc text] [--package X] [--gate X]",
|
|
463
469
|
);
|
|
464
470
|
process.exit(1);
|
|
465
471
|
}
|
|
@@ -479,7 +485,7 @@ function cmdAdd(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
479
485
|
function cmdShow(rest: string[], format: OutputFormat): void {
|
|
480
486
|
const [id] = rest;
|
|
481
487
|
if (!id) {
|
|
482
|
-
console.error("Usage:
|
|
488
|
+
console.error("Usage: feinai show <TASK-ID>");
|
|
483
489
|
process.exit(1);
|
|
484
490
|
}
|
|
485
491
|
const db = ensureDb();
|
|
@@ -510,7 +516,7 @@ function cmdShow(rest: string[], format: OutputFormat): void {
|
|
|
510
516
|
function cmdTake(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
511
517
|
const [id] = rest;
|
|
512
518
|
if (!id) {
|
|
513
|
-
console.error("Usage:
|
|
519
|
+
console.error("Usage: feinai take <TASK-ID> [--owner name]");
|
|
514
520
|
process.exit(1);
|
|
515
521
|
}
|
|
516
522
|
const db = ensureDb();
|
|
@@ -539,7 +545,7 @@ function cmdDone(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
539
545
|
const [id] = rest;
|
|
540
546
|
const result = args.options.result;
|
|
541
547
|
if (!id || !result) {
|
|
542
|
-
console.error("Usage:
|
|
548
|
+
console.error("Usage: feinai done <TASK-ID> --result <text>");
|
|
543
549
|
process.exit(1);
|
|
544
550
|
}
|
|
545
551
|
const db = ensureDb();
|
|
@@ -551,7 +557,7 @@ function cmdFail(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
551
557
|
const [id] = rest;
|
|
552
558
|
const error = args.options.error;
|
|
553
559
|
if (!id || !error) {
|
|
554
|
-
console.error("Usage:
|
|
560
|
+
console.error("Usage: feinai fail <TASK-ID> --error <text>");
|
|
555
561
|
process.exit(1);
|
|
556
562
|
}
|
|
557
563
|
const db = ensureDb();
|
|
@@ -561,7 +567,7 @@ function cmdFail(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
561
567
|
|
|
562
568
|
function cmdRelease(rest: string[], format: OutputFormat): void {
|
|
563
569
|
const [id] = rest;
|
|
564
|
-
if (!id) { console.error("Usage:
|
|
570
|
+
if (!id) { console.error("Usage: feinai release <TASK-ID>"); process.exit(1); }
|
|
565
571
|
const db = ensureDb();
|
|
566
572
|
const task = releaseTask(db, id, getCurrentUser());
|
|
567
573
|
console.log(formatTask(task, format));
|
|
@@ -569,7 +575,7 @@ function cmdRelease(rest: string[], format: OutputFormat): void {
|
|
|
569
575
|
|
|
570
576
|
function cmdReopen(rest: string[], format: OutputFormat): void {
|
|
571
577
|
const [id] = rest;
|
|
572
|
-
if (!id) { console.error("Usage:
|
|
578
|
+
if (!id) { console.error("Usage: feinai reopen <TASK-ID>"); process.exit(1); }
|
|
573
579
|
const db = ensureDb();
|
|
574
580
|
const task = reopenTask(db, id, getCurrentUser());
|
|
575
581
|
console.log(formatTask(task, format));
|
|
@@ -579,7 +585,7 @@ function cmdBlock(rest: string[], args: ParsedArgs, format: OutputFormat): void
|
|
|
579
585
|
const [id] = rest;
|
|
580
586
|
const by = args.options.by;
|
|
581
587
|
if (!id || !by) {
|
|
582
|
-
console.error("Usage:
|
|
588
|
+
console.error("Usage: feinai block <TASK-ID> --by <BLOCKER-ID>");
|
|
583
589
|
process.exit(1);
|
|
584
590
|
}
|
|
585
591
|
const db = ensureDb();
|
|
@@ -591,7 +597,7 @@ function cmdUnblock(rest: string[], args: ParsedArgs, format: OutputFormat): voi
|
|
|
591
597
|
const [id] = rest;
|
|
592
598
|
const dep = args.options.dep;
|
|
593
599
|
if (!id || !dep) {
|
|
594
|
-
console.error("Usage:
|
|
600
|
+
console.error("Usage: feinai unblock <TASK-ID> --dep <BLOCKER-ID>");
|
|
595
601
|
process.exit(1);
|
|
596
602
|
}
|
|
597
603
|
const db = ensureDb();
|
|
@@ -602,7 +608,7 @@ function cmdUnblock(rest: string[], args: ParsedArgs, format: OutputFormat): voi
|
|
|
602
608
|
function cmdTaskEdit(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
603
609
|
const [id] = rest;
|
|
604
610
|
if (!id) {
|
|
605
|
-
console.error('Usage:
|
|
611
|
+
console.error('Usage: feinai task edit <TASK-ID> [--subject text] [--desc text] [--package name] [--gate cmd]');
|
|
606
612
|
console.error(' Supports --stdin and --file for --desc');
|
|
607
613
|
process.exit(1);
|
|
608
614
|
}
|
|
@@ -639,7 +645,7 @@ function cmdSpec(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
639
645
|
case "show": {
|
|
640
646
|
const [id] = subRest;
|
|
641
647
|
if (!id) {
|
|
642
|
-
console.error("Usage:
|
|
648
|
+
console.error("Usage: feinai spec show <SPEC-ID> [--full]");
|
|
643
649
|
process.exit(1);
|
|
644
650
|
}
|
|
645
651
|
const spec = getSpec(db, id);
|
|
@@ -654,7 +660,7 @@ function cmdSpec(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
654
660
|
case "content": {
|
|
655
661
|
const [id] = subRest;
|
|
656
662
|
if (!id) {
|
|
657
|
-
console.error("Usage:
|
|
663
|
+
console.error("Usage: feinai spec content <SPEC-ID>");
|
|
658
664
|
process.exit(1);
|
|
659
665
|
}
|
|
660
666
|
const spec = getSpec(db, id);
|
|
@@ -673,7 +679,7 @@ function cmdSpec(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
673
679
|
const [id, ...titleParts] = subRest;
|
|
674
680
|
if (!id || titleParts.length === 0) {
|
|
675
681
|
console.error(
|
|
676
|
-
"Usage:
|
|
682
|
+
"Usage: feinai spec add <SPEC-ID> <title> [--content text | --file path | --stdin]",
|
|
677
683
|
);
|
|
678
684
|
process.exit(1);
|
|
679
685
|
}
|
|
@@ -689,7 +695,7 @@ function cmdSpec(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
689
695
|
const [id] = subRest;
|
|
690
696
|
if (!id) {
|
|
691
697
|
console.error(
|
|
692
|
-
"Usage:
|
|
698
|
+
"Usage: feinai spec set-content <SPEC-ID> --content text | --file path | --stdin",
|
|
693
699
|
);
|
|
694
700
|
process.exit(1);
|
|
695
701
|
}
|
|
@@ -705,7 +711,7 @@ function cmdSpec(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
705
711
|
case "start": {
|
|
706
712
|
const [id] = subRest;
|
|
707
713
|
if (!id) {
|
|
708
|
-
console.error("Usage:
|
|
714
|
+
console.error("Usage: feinai spec start <SPEC-ID>");
|
|
709
715
|
process.exit(1);
|
|
710
716
|
}
|
|
711
717
|
console.log(formatSpec(startSpec(db, id, actor), format));
|
|
@@ -714,7 +720,7 @@ function cmdSpec(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
714
720
|
case "done": {
|
|
715
721
|
const [id] = subRest;
|
|
716
722
|
if (!id) {
|
|
717
|
-
console.error("Usage:
|
|
723
|
+
console.error("Usage: feinai spec done <SPEC-ID> [--pr N] [--merged YYYY-MM-DD]");
|
|
718
724
|
process.exit(1);
|
|
719
725
|
}
|
|
720
726
|
const spec = doneSpec(
|
|
@@ -729,7 +735,7 @@ function cmdSpec(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
729
735
|
case "edit": {
|
|
730
736
|
const [id] = subRest;
|
|
731
737
|
if (!id) {
|
|
732
|
-
console.error("Usage:
|
|
738
|
+
console.error("Usage: feinai spec edit <SPEC-ID> [--title text]");
|
|
733
739
|
process.exit(1);
|
|
734
740
|
}
|
|
735
741
|
const spec = editSpec(db, id, { title: args.options.title }, actor);
|
|
@@ -738,19 +744,19 @@ function cmdSpec(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
738
744
|
}
|
|
739
745
|
case "archive": {
|
|
740
746
|
const [id] = subRest;
|
|
741
|
-
if (!id) { console.error("Usage:
|
|
747
|
+
if (!id) { console.error("Usage: feinai spec archive <SPEC-ID>"); process.exit(1); }
|
|
742
748
|
console.log(formatSpec(archiveSpec(db, id, actor), format));
|
|
743
749
|
return;
|
|
744
750
|
}
|
|
745
751
|
case "unarchive": {
|
|
746
752
|
const [id] = subRest;
|
|
747
|
-
if (!id) { console.error("Usage:
|
|
753
|
+
if (!id) { console.error("Usage: feinai spec unarchive <SPEC-ID>"); process.exit(1); }
|
|
748
754
|
console.log(formatSpec(unarchiveSpec(db, id, actor), format));
|
|
749
755
|
return;
|
|
750
756
|
}
|
|
751
757
|
case "delete": {
|
|
752
758
|
const [id] = subRest;
|
|
753
|
-
if (!id) { console.error("Usage:
|
|
759
|
+
if (!id) { console.error("Usage: feinai spec delete <SPEC-ID>"); process.exit(1); }
|
|
754
760
|
console.log(JSON.stringify(deleteSpec(db, id, actor)));
|
|
755
761
|
return;
|
|
756
762
|
}
|
|
@@ -789,7 +795,7 @@ async function cmdServer(args: ParsedArgs): Promise<void> {
|
|
|
789
795
|
|
|
790
796
|
// Verify DB exists before starting server (fast fail)
|
|
791
797
|
if (!findDbPath()) {
|
|
792
|
-
console.error("Error: no .tasca/tasca.db found. Run '
|
|
798
|
+
console.error("Error: no .tasca/tasca.db found. Run 'feinai init' first.");
|
|
793
799
|
process.exit(2);
|
|
794
800
|
}
|
|
795
801
|
|
|
@@ -836,7 +842,7 @@ function cmdPlan(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
836
842
|
const [specId] = subRest;
|
|
837
843
|
if (!specId) {
|
|
838
844
|
console.error(
|
|
839
|
-
"Usage:
|
|
845
|
+
"Usage: feinai plan add <SPEC-ID> --content text | --file path | --stdin",
|
|
840
846
|
);
|
|
841
847
|
process.exit(1);
|
|
842
848
|
}
|
|
@@ -852,7 +858,7 @@ function cmdPlan(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
852
858
|
case "show": {
|
|
853
859
|
const [specId] = subRest;
|
|
854
860
|
if (!specId) {
|
|
855
|
-
console.error("Usage:
|
|
861
|
+
console.error("Usage: feinai plan show <SPEC-ID>");
|
|
856
862
|
process.exit(1);
|
|
857
863
|
}
|
|
858
864
|
const plan = getLatestPlan(db, specId);
|
|
@@ -866,7 +872,7 @@ function cmdPlan(rest: string[], args: ParsedArgs, format: OutputFormat): void {
|
|
|
866
872
|
case "list": {
|
|
867
873
|
const [specId] = subRest;
|
|
868
874
|
if (!specId) {
|
|
869
|
-
console.error("Usage:
|
|
875
|
+
console.error("Usage: feinai plan list <SPEC-ID>");
|
|
870
876
|
process.exit(1);
|
|
871
877
|
}
|
|
872
878
|
console.log(formatPlanList(listPlans(db, specId), format));
|