feinai 0.5.7 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/cli.ts +45 -39
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feinai",
3
- "version": "0.5.7",
3
+ "version": "0.5.8",
4
4
  "description": "Task & spec manager for AI agents — parallel worktrees, live dashboard, SDD skills",
5
5
  "type": "module",
6
6
  "bin": {
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.7";
51
+ const VERSION = "0.5.8";
52
52
 
53
53
  interface ParsedArgs {
54
54
  positional: string[];
@@ -123,7 +123,7 @@ function detectFormat(args: ParsedArgs): OutputFormat {
123
123
  }
124
124
 
125
125
  /**
126
- * Build a stable identifier for whoever is invoking feina.
126
+ * Build a stable identifier for whoever is invoking feinai.
127
127
  *
128
128
  * Priority:
129
129
  * 1. $FEINAI_USER env var (explicit override — used by agents to identify themselves)
@@ -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 'feina init' to create one.",
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(`feina v\${VERSION} — task & spec manager for AI agents and humans
185
+ console.log(`feinai v\${VERSION} — task & spec manager for AI agents and humans
186
186
 
187
187
  USAGE:
188
- feina <command> [options]
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 feina server (by port)
253
+ server --down Stop the running feinai server (by port)
254
254
 
255
255
  GLOBAL FLAGS:
256
256
  --json Output as JSON
@@ -261,11 +261,17 @@ GLOBAL FLAGS:
261
261
  ENV:
262
262
  FEINAI_USER Override owner/actor identity used in audit log
263
263
 
264
- \x1b[34m\x1b[1m── Agent Integration ──────────────────────────────────────────────\x1b[0m
265
- \x1b[36mTeach your AI agents to use \x1b[1mfeina\x1b[0m\x1b[36m as their single source of truth for\x1b[0m
266
- \x1b[36mspecs, tasks, and plans.\x1b[0m
267
- \x1b[36mOr load \x1b[1mfeina skills\x1b[0m\x1b[36m from the Claude Code skills marketplace:\x1b[0m
268
- \x1b[34m \x1b[1;94mtasca-sdd\x1b[0m \x1b[1;94mtasca-write-spec\x1b[0m \x1b[1;94mtasca-write-tasks\x1b[0m \x1b[1;94mtasca-dispatch\x1b[0m
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 'feina --help' for usage.");
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: feina git <subcommand> [args...]");
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(`feina DB already exists at ${existing}`);
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 feina DB at ${path}`);
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: feina add <TASK-ID> <subject> [--spec ID] [--desc text] [--package X] [--gate X]",
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: feina show <TASK-ID>");
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: feina take <TASK-ID> [--owner name]");
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: feina done <TASK-ID> --result <text>");
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: feina fail <TASK-ID> --error <text>");
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: feina release <TASK-ID>"); process.exit(1); }
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: feina reopen <TASK-ID>"); process.exit(1); }
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: feina block <TASK-ID> --by <BLOCKER-ID>");
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: feina unblock <TASK-ID> --dep <BLOCKER-ID>");
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: feina task edit <TASK-ID> [--subject text] [--desc text] [--package name] [--gate cmd]');
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: feina spec show <SPEC-ID> [--full]");
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: feina spec content <SPEC-ID>");
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: feina spec add <SPEC-ID> <title> [--content text | --file path | --stdin]",
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: feina spec set-content <SPEC-ID> --content text | --file path | --stdin",
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: feina spec start <SPEC-ID>");
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: feina spec done <SPEC-ID> [--pr N] [--merged YYYY-MM-DD]");
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: feina spec edit <SPEC-ID> [--title text]");
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: feina spec archive <SPEC-ID>"); process.exit(1); }
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: feina spec unarchive <SPEC-ID>"); process.exit(1); }
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: feina spec delete <SPEC-ID>"); process.exit(1); }
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 'feina init' first.");
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: feina plan add <SPEC-ID> --content text | --file path | --stdin",
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: feina plan show <SPEC-ID>");
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: feina plan list <SPEC-ID>");
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));