feinai 0.5.8 → 0.6.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feinai",
3
- "version": "0.5.8",
3
+ "version": "0.6.1",
4
4
  "description": "Task & spec manager for AI agents — parallel worktrees, live dashboard, SDD skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -10,6 +10,7 @@
10
10
  "scripts": {
11
11
  "dev": "bun src/cli.ts",
12
12
  "test": "bun test",
13
+ "postinstall": "bun src/postinstall.ts",
13
14
  "build": "bun build src/cli.ts --compile --outfile dist/feinai",
14
15
  "build:linux-x64": "bun build src/cli.ts --compile --target=bun-linux-x64 --outfile dist/feinai-linux-x64",
15
16
  "build:linux-arm64": "bun build src/cli.ts --compile --target=bun-linux-arm64 --outfile dist/feinai-linux-arm64",
@@ -41,6 +42,7 @@
41
42
  },
42
43
  "files": [
43
44
  "src/*.ts",
45
+ "src/*.sh",
44
46
  "src/*.html",
45
47
  "src/*.sh",
46
48
  "README.md",
@@ -1,12 +1,12 @@
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 `.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.
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, 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
- SDD workflows. When a project has `.tasca/tasca.db`, you should write to that
9
+ SDD workflows. When a project has `\.feinai/feinai.db`, you should write to that
10
10
  database instead of producing markdown files under `docs/superpowers/`.
11
11
 
12
12
  This skill extends superpowers — it does not replace it. You still follow the
@@ -19,7 +19,7 @@ just change *where the artifacts get stored*.
19
19
 
20
20
  Invoke when **all** of the following are true:
21
21
 
22
- 1. The project has a `.tasca/tasca.db` file (walk up the directory tree from
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
24
  Check with: `feinai status` (exit code 0 = tasca is set up).
25
25
  2. You are about to:
@@ -28,7 +28,7 @@ Invoke when **all** of the following are true:
28
28
  - Execute tasks via `subagent-driven-development` or `executing-plans`, OR
29
29
  - The user explicitly mentions creating/claiming/marking tasks or specs.
30
30
 
31
- If `.tasca/tasca.db` does not exist, skip this skill — let superpowers do its
31
+ If `\.feinai/feinai.db` does not exist, skip this skill — let superpowers do its
32
32
  normal markdown-based flow.
33
33
 
34
34
  ---
@@ -42,7 +42,7 @@ feinai status 2>/dev/null
42
42
  ```
43
43
 
44
44
  - Exit code 0: feinai is active in this project → use this skill.
45
- - Exit code 2: `No .tasca/tasca.db found` → fall back to vanilla superpowers
45
+ - Exit code 2: `No \.feinai/feinai.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:
48
48
 
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.8";
51
+ const VERSION = "0.6.1";
52
52
 
53
53
  interface ParsedArgs {
54
54
  positional: string[];
@@ -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 'feinai init' to create one.",
166
+ "Error: no .feinai/feinai.db found. Run 'feinai init' to create one.",
167
167
  );
168
168
  process.exit(2);
169
169
  }
@@ -188,8 +188,8 @@ USAGE:
188
188
  feinai <command> [options]
189
189
 
190
190
  DB MANAGEMENT:
191
- init [--force] Create .tasca/tasca.db in cwd
192
- destroy [--yes] Delete .tasca/ entirely (prompts unless --yes)
191
+ init [--force] Create .feinai/feinai.db in cwd
192
+ destroy [--yes] Delete .feinai/ entirely (prompts unless --yes)
193
193
  (--force allows nesting under an existing DB)
194
194
  status Summary of pending/in_progress/completed counts
195
195
 
@@ -365,7 +365,7 @@ function cmdGit(rest: string[]): void {
365
365
  async function cmdDestroy(args: ParsedArgs): Promise<void> {
366
366
  const dbPath = findDbPath();
367
367
  if (!dbPath) {
368
- console.error("Error: no .tasca/tasca.db found.");
368
+ console.error("Error: no .feinai/feinai.db found.");
369
369
  process.exit(2);
370
370
  }
371
371
 
@@ -795,7 +795,7 @@ async function cmdServer(args: ParsedArgs): Promise<void> {
795
795
 
796
796
  // Verify DB exists before starting server (fast fail)
797
797
  if (!findDbPath()) {
798
- console.error("Error: no .tasca/tasca.db found. Run 'feinai init' first.");
798
+ console.error("Error: no .feinai/feinai.db found. Run 'feinai init' first.");
799
799
  process.exit(2);
800
800
  }
801
801
 
package/src/db.ts CHANGED
@@ -1,9 +1,46 @@
1
- import { existsSync, mkdirSync } from "node:fs";
1
+ import { existsSync, mkdirSync, renameSync } from "node:fs";
2
2
  import { dirname, join, resolve } from "node:path";
3
3
  import { openSqlite, type DbAdapter } from "./sqlite-adapter";
4
4
 
5
- const DB_DIR = ".tasca";
6
- const DB_FILE = "tasca.db";
5
+ const DB_DIR = ".feinai";
6
+ const DB_FILE = "feinai.db";
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
+ }
7
44
 
8
45
  export type DbInstance = DbAdapter;
9
46
 
@@ -152,6 +189,8 @@ function applySchema(db: DbInstance): void {
152
189
  export function findDbPath(startDir: string = process.cwd()): string | null {
153
190
  let current = resolve(startDir);
154
191
  while (true) {
192
+ // migrate legacy .tasca/tasca.db → .feinai/feinai.db if found
193
+ migrateLegacyDir(current);
155
194
  const candidate = join(current, DB_DIR, DB_FILE);
156
195
  if (existsSync(candidate)) return candidate;
157
196
  const parent = dirname(current);
@@ -187,7 +226,7 @@ export function openDb(): DbInstance {
187
226
  const path = findDbPath();
188
227
  if (!path) {
189
228
  throw new Error(
190
- `No tasca DB found. Run 'tasca init' to create one in the current directory.`,
229
+ `No feinai DB found. Run 'feinai init' to create one in the current directory.`,
191
230
  );
192
231
  }
193
232
  const db = openSqlite(path);
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bun
2
+ // Runs after bun install -g feinai
3
+ // Copies feinai skills to opencode agents dir if opencode is configured
4
+
5
+ import { existsSync, mkdirSync, copyFileSync, readdirSync } from "node:fs";
6
+ import { join, dirname } from "node:path";
7
+ import { homedir } from "node:os";
8
+ import { fileURLToPath } from "node:url";
9
+
10
+ const home = homedir();
11
+ const openCodeAgentsDir = join(home, ".config", "opencode", "agents");
12
+ const skillsDir = join(dirname(fileURLToPath(import.meta.url)), "..", "skills");
13
+
14
+ // Only run if opencode is configured
15
+ if (!existsSync(join(home, ".config", "opencode"))) process.exit(0);
16
+
17
+ if (!existsSync(openCodeAgentsDir)) mkdirSync(openCodeAgentsDir, { recursive: true });
18
+
19
+ let copied = 0;
20
+ for (const skill of readdirSync(skillsDir)) {
21
+ if (!skill.startsWith("feinai-")) continue;
22
+ const src = join(skillsDir, skill, "SKILL.md");
23
+ const dst = join(openCodeAgentsDir, `${skill}.md`);
24
+ if (existsSync(src)) {
25
+ copyFileSync(src, dst);
26
+ copied++;
27
+ }
28
+ }
29
+
30
+ if (copied > 0 && process.stdout.isTTY) {
31
+ console.log(`feinai: ${copied} skills copied to opencode agents (${openCodeAgentsDir})`);
32
+ }