feinai 0.6.5 → 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 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
- - `tasca 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 `tasca` — `bun install -g tasca` now installs both
17
- - `tasca unblock <TASK-ID> --dep <TASK-ID>` — remove a specific dependency from a task
18
- - `tasca edit --clear-blocked-by` — clear all dependencies from a task
19
- - Live Agents Monitor: working directory, repo name, and `.tasca` path shown per agent card
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
- - `tasca init` now auto-adds `.tasca/` to `.gitignore` if in a git repo
23
- - Skills: `tasca-implement` — claim one pending task, implement in isolated worktree, run quality gates, push to main
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
- - `tasca-implement` SKILL.md updated to use `tasca git` instead of `opengit` directly
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
- `tasca-sdd` · `tasca-write-spec` · `tasca-write-tasks` · `tasca-dispatch` · `tasca-implement`
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
- - `tasca init / status / list / add / show / take / done / fail / block / release / reopen / edit`
41
- - `tasca spec` — spec lifecycle (add, start, done, archive, set-content, edit)
42
- - `tasca plan` — plan revisions per spec
43
- - `tasca server` — HTTP dashboard + REST API + SSE live updates
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: `tasca-sdd`, `tasca-write-spec`, `tasca-write-tasks`, `tasca-dispatch`
47
+ - Skills: `feinai-sdd`, `feinai-write-spec`, `feinai-write-tasks`, `feinai-dispatch`
package/README.md CHANGED
@@ -73,7 +73,7 @@ State lives in a local SQLite file. No cloud, no external service, no account.
73
73
  - Installs two binaries:
74
74
  - `feinai` – main CLI + embedded HTTP server and dashboard.
75
75
  - `opengit` – safe git wrapper for parallel worktrees.
76
- - Stores all state in a single SQLite file: `.tasca/tasca.db`, discovered by walking up from the current directory (like `.git`).
76
+ - Stores all state in a single SQLite file: `.feinai/feinai.db`, discovered by walking up from the current directory (like `.git`).
77
77
 
78
78
  No background services are required beyond the optional dashboard server.
79
79
 
@@ -83,7 +83,7 @@ No background services are required beyond the optional dashboard server.
83
83
 
84
84
  feinai is designed to be "boring" infrastructure:
85
85
 
86
- - **Local‑only state.** All coordination lives in `.tasca/tasca.db` in your repo. There is no remote backend.
86
+ - **Local‑only state.** All coordination lives in `.feinai/feinai.db` in your repo. There is no remote backend.
87
87
  - **Explicit operations.** Every change to specs, plans, tasks and worktrees goes through the CLI or HTTP API and is logged in `events`.
88
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
89
  - **Auditability.** Every task has a clear chain: spec → plan → task → worktree → events. Every agent identity can be traced (`$FEINAI_USER` override supported).
@@ -111,7 +111,7 @@ Agents don't parse `QUEUE.md`. They talk to a small local coordination service i
111
111
 
112
112
  ## Claude Code skills
113
113
 
114
- feinai ships five Claude Code skills covering the full development loop. They activate automatically when `.tasca/tasca.db` is present:
114
+ feinai ships five Claude Code skills covering the full development loop. They activate automatically when `.feinai/feinai.db` is present:
115
115
 
116
116
  | Skill | Purpose |
117
117
  |---------------------|--------------------------------------------------------|
@@ -169,7 +169,7 @@ sudo ln -sf ~/.bun/bin/bun /usr/local/bin/bun
169
169
  cd my-project
170
170
 
171
171
  # Initialize local state
172
- feinai init # creates .tasca/tasca.db, adds to .gitignore
172
+ feinai init # creates .feinai/feinai.db, adds to .gitignore
173
173
 
174
174
  # Add a spec and plan
175
175
  feinai spec add SPEC-001 "User authentication" --content "..."
@@ -197,7 +197,7 @@ feinai server # live dashboard at http://127.0.0.1:8272
197
197
  High‑level CLI:
198
198
 
199
199
  ```text
200
- feinai init Create .tasca/tasca.db
200
+ feinai init Create .feinai/feinai.db
201
201
  feinai status Show counts: pending / in_progress / completed
202
202
  feinai list [--pending] [--spec X] List tasks
203
203
  feinai add ID "subject" Create task
@@ -267,7 +267,7 @@ Use your normal git tooling inside each worktree; use `feinai git` when operatin
267
267
  ## Architecture
268
268
 
269
269
  ```text
270
- <project>/.tasca/tasca.db # local SQLite database (discovered like .git)
270
+ <project>/.feinai/feinai.db # local SQLite database (discovered like .git)
271
271
 
272
272
  specs — what to build
273
273
  plans — how to build it (versioned)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "feinai",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "Task & spec manager for AI agents — parallel worktrees, live dashboard, SDD skills",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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 .tasca/tasca.db found`)
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 tasca DB is the source of truth — re-query it:
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 tasca, 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.
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 tasca, implement it in an isolated worktree, run quality gates, push to main.
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 tasca — no separate setup needed)
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 tasca
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 tasca.
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 tasca directamente
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, 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.
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 = tasca is set up).
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 tasca set up here? | `feinai status` |
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 `.tasca/tasca.db`. Writes a complete spec + plan into tasca 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`.
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 tasca, not markdown files.
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 = tasca is active). If not active, stop and ask the
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 tasca yourself.
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 tasca, produce the executable task set.
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 tascaDir = dbPath.replace(/\/tasca\.db$/, "");
385
- rmSync(tascaDir, { recursive: true, force: true });
386
- console.log(`Destroyed ${tascaDir}`);
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 tasca port
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 tasca server (PID ${pid}).`);
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(`tasca dashboard → http://${host}:${port}`);
816
- console.log(`Stop with: tasca server --down`);
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(`tasca dashboard listening at ${server.url}`);
825
- console.log(`Stop with: tasca server --down`);
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", () => {
@@ -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>tasca dashboard</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
- tasca
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>tasca · streaming live · click any item for details &amp; actions · <span id="dash-version">v—</span></footer>
726
+ <footer>feinai · streaming live · click any item for details &amp; 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("tasca-skip-" + skipKey) === "1") { resolve(true); return; }
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("tasca-skip-" + skipKey, "1");
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-Tasca-Actor": "dashboard" } : { "X-Tasca-Actor": "dashboard" },
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 tascaLoc = appContext.tascaPath || "—";
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(tascaLoc)}</span></div>
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, renameSync } from "node:fs";
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 tascaDir = join(dir, DB_DIR);
208
- const dbPath = join(tascaDir, DB_FILE);
168
+ const feinaiDir = join(dir, DB_DIR);
169
+ const dbPath = join(feinaiDir, DB_FILE);
209
170
 
210
- if (!existsSync(tascaDir)) {
211
- mkdirSync(tascaDir, { recursive: true });
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; tasca spec content " + spec.id + " to export)")}`);
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; tasca plan show " + spec.id + " to export)")}`);
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 (tasca server -d to start)`);
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-Tasca-Actor header (explicit)
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-tasca-actor") {
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 -- tools/tasca/src/dashboard.html | wc -l`.cwd(root).text();
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 -- tools/tasca/src/dashboard.html`.cwd(root).text();
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-Tasca-Actor",
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 tasca DB context info for dashboard
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 tascaPath = dbPath?.startsWith(home)
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
- tascaPath,
455
+ feinaiPath,
456
456
  });
457
457
  }
458
458
 
@@ -114,7 +114,7 @@ export function getSqliteConstructor(): DbConstructor {
114
114
 
115
115
  if (!_constructor) {
116
116
  console.error(`
117
- Error: No SQLite backend found. tasca requires one of:
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)