docs(KB-222): rebrand kb to Fusion across documentation and CLI

- Rebrand root README from kb to Fusion with updated descriptions
- Update CLI package README with Fusion branding
- Rebrand STANDALONE.md documentation to Fusion
- Update CLI help text to use 'fn' command reference
- Update pi extension descriptions and tool names for Fusion
- Add changeset for rebranding documentation
- Update dashboard ListView component and styles
- Remove obsolete store tests and ListView tests
This commit is contained in:
gsxdsm
2026-03-30 18:22:42 -07:00
parent 8017769bfb
commit 61417504a4
6 changed files with 176 additions and 167 deletions

View File

@@ -1,8 +1,8 @@
# @dustinbyrne/kb
An automated Kanban board for [pi](https://github.com/badlogic/pi-mono). You (or an agent) add high level ideas to your task list, and a team of agents execute them using worktrees.
An automated Kanban board for [pi](https://github.com/badlogic/pi-mono). Fusion is an AI-orchestrated task board where you (or an agent) add high level ideas to your task list, and a team of agents execute them using worktrees.
![kb dashboard](https://raw.githubusercontent.com/dustinbyrne/kb/main/demo/screenshot.png)
![Fusion dashboard](https://raw.githubusercontent.com/dustinbyrne/kb/main/demo/screenshot.png)
## Installation
@@ -10,16 +10,16 @@ An automated Kanban board for [pi](https://github.com/badlogic/pi-mono). You (or
pi install npm:@dustinbyrne/kb
```
This gives pi the ability to manage and create tasks in your kanban dashboard.
This gives pi the ability to manage and create tasks in your Fusion dashboard.
## The dashboard
Run `/kb` in pi to launch the dashboard and AI engine.
Run `/fn` in pi to launch the dashboard and AI engine.
```
/kb # start on default port 4040
/kb stop # stop it
/kb 8080 # run on a custom port
/fn # start on default port 4040
/fn stop # stop it
/fn 8080 # run on a custom port
```
The dashboard gives you:
@@ -49,14 +49,14 @@ An executor agent works through the spec step by step in the worktree. At each s
### Merge
When execution finishes and the reviewer signs off, the task moves to "in review." kb supports two completion modes:
When execution finishes and the reviewer signs off, the task moves to "in review." Fusion supports two completion modes:
- **Direct merge** *(default)* — automatically squash-merges the completed task branch into your current branch with a clean commit.
- **Pull request** — automatically creates or links a GitHub PR for the task branch, waits for GitHub reviews/checks, then merges the PR once policy conditions are satisfied.
`autoMerge` still controls whether kb performs completion automatically at all. If `autoMerge` is disabled, tasks stay in **In Review** until you finish the merge yourself.
`autoMerge` still controls whether Fusion performs completion automatically at all. If `autoMerge` is disabled, tasks stay in **In Review** until you finish the merge yourself.
For PR-first mode, authenticate GitHub with `gh auth login` or `GITHUB_TOKEN`, and make sure the task branch already exists on GitHub as `kb/<task-id-lower>`. kb does **not** push branches for you before PR creation.
For PR-first mode, authenticate GitHub with `gh auth login` or `GITHUB_TOKEN`, and make sure the task branch already exists on GitHub as `kb/<task-id-lower>`. Fusion does **not** push branches for you before PR creation.
Worktrees can be cleaned up after merge or reused by the next task to keep build caches warm.
@@ -68,7 +68,7 @@ You can manage tasks without leaving the conversation:
> "Every ten minutes, analyze the server code for logic the client hasn't implemented yet and create tasks. Tasks may spawn additional tasks, so just add enough to keep the board saturated."
> "Create a kb task to fix the login redirect bug"
> "Create a Fusion task to fix the login redirect bug"
> "Add a task for dark mode support, it depends on KB-003"
@@ -82,7 +82,7 @@ The extension gives pi tools to create tasks, check progress, attach files, and
## Standalone CLI
kb also works as a standalone CLI outside of pi. See [STANDALONE.md](./STANDALONE.md) for installation and usage without the pi extension.
Fusion also works as a standalone CLI outside of pi. See [STANDALONE.md](./STANDALONE.md) for installation and usage without the pi extension.
## Full documentation

View File

@@ -1,6 +1,6 @@
# Standalone CLI
kb works as a standalone CLI without pi. This is useful for CI environments, scripting, or if you prefer working from the terminal.
Fusion works as a standalone CLI without pi. This is useful for CI environments, scripting, or if you prefer working from the terminal.
## Installation
@@ -10,7 +10,7 @@ npm install -g @dustinbyrne/kb
## Authentication
kb uses [pi](https://github.com/badlogic/pi-mono) for AI agent sessions and reuses your existing pi authentication. You can also authenticate directly through the dashboard UI.
Fusion uses [pi](https://github.com/badlogic/pi-mono) for AI agent sessions and reuses your existing pi authentication. You can also authenticate directly through the dashboard UI.
If you don't have pi set up yet: `npm i -g @mariozechner/pi-coding-agent && pi` then `/login`.
@@ -21,11 +21,11 @@ If you don't have pi set up yet: `npm i -g @mariozechner/pi-coding-agent && pi`
Launch the web UI and AI engine:
```bash
kb dashboard
kb dashboard --port 8080
kb dashboard --interactive # Interactive port selection (prompts for port)
kb dashboard --paused # Start with automation paused (review before work begins)
kb dashboard --dev # Start web UI only (no AI engine)
fn dashboard
fn dashboard --port 8080
fn dashboard --interactive # Interactive port selection (prompts for port)
fn dashboard --paused # Start with automation paused (review before work begins)
fn dashboard --dev # Start web UI only (no AI engine)
```
### Multi-Instance Deployments
@@ -39,7 +39,7 @@ export KB_BADGE_PUBSUB_REDIS_URL="redis://redis.example.com:6379"
# Optional: customize the pub/sub channel (default: kb:badge-updates)
export KB_BADGE_PUBSUB_CHANNEL="my-app-badge-updates"
kb dashboard
fn dashboard
```
With this configuration, PR/issue badge updates received via webhook on one instance are delivered to subscribed WebSocket clients on all instances.
@@ -82,40 +82,40 @@ When webhooks are not configured or delivery fails, the dashboard falls back to
### Create a task
```bash
kb task create "Fix the login redirect bug"
kb task create "Update hero section" --attach screenshot.png --attach design.pdf
fn task create "Fix the login redirect bug"
fn task create "Update hero section" --attach screenshot.png --attach design.pdf
```
### Manage tasks
```bash
kb task list # List all tasks
kb task show KB-001 # Show task details, steps, and log
kb task move KB-001 todo # Move a task to a column
kb task merge KB-001 # Merge an in-review task and close it
kb task log KB-001 "Added context" # Add a log entry
kb task pause KB-001 # Pause a task (stops automation)
kb task unpause KB-001 # Resume a paused task
kb task attach KB-001 ./error.log # Attach a file to a task
kb task import owner/repo # Import GitHub issues as tasks
kb task import owner/repo --limit 10 --labels "bug,enhancement"
fn task list # List all tasks
fn task show KB-001 # Show task details, steps, and log
fn task move KB-001 todo # Move a task to a column
fn task merge KB-001 # Merge an in-review task and close it
fn task log KB-001 "Added context" # Add a log entry
fn task pause KB-001 # Pause a task (stops automation)
fn task unpause KB-001 # Resume a paused task
fn task attach KB-001 ./error.log # Attach a file to a task
fn task import owner/repo # Import GitHub issues as tasks
fn task import owner/repo --limit 10 --labels "bug,enhancement"
```
### Typical workflow
```bash
# 1. Create a task — it lands in triage
kb task create "Add dark mode support"
fn task create "Add dark mode support"
# 2. Start the dashboard — AI specs the task and begins working
kb dashboard
fn dashboard
# 3. Check progress
kb task list
kb task show KB-042
fn task list
fn task show KB-042
# 4. When it reaches "in-review", review the changes and merge
kb task merge KB-042
fn task merge KB-042
```
## Standalone binary

View File

@@ -44,41 +44,41 @@ const { runSettingsShow, runSettingsSet } = await import("./commands/settings.js
const { runGitStatus, runGitFetch, runGitPull, runGitPush } = await import("./commands/git.js");
const HELP = `
kb — AI-orchestrated task board
fn — AI-orchestrated task board
Usage:
kb dashboard Start the board web UI
kb dashboard --paused Start with automation paused
kb dashboard --dev Start web UI only (no AI engine)
kb dashboard --interactive Start with interactive port selection
kb task create [desc] [opts] Create a new task (goes to triage)
kb task plan [description] [opts] Create task via AI-guided planning
kb task list List all tasks
kb task show <id> Show task details, steps, log
kb task logs <id> [--follow] [--limit <n>] [--type <type>]
fn dashboard Start the board web UI
fn dashboard --paused Start with automation paused
fn dashboard --dev Start web UI only (no AI engine)
fn dashboard --interactive Start with interactive port selection
fn task create [desc] [opts] Create a new task (goes to triage)
fn task plan [description] [opts] Create task via AI-guided planning
fn task list List all tasks
fn task show <id> Show task details, steps, log
fn task logs <id> [--follow] [--limit <n>] [--type <type>]
Show task agent execution logs
kb task move <id> <col> Move a task to a column
kb task update <id> <step> <status> Update step status (pending|in-progress|done|skipped)
kb task log <id> <message> Add a log entry
kb task merge <id> Merge an in-review task and close it
kb task duplicate <id> Duplicate a task (creates copy in triage)
kb task refine <id> [opts] Create a refinement task from done/in-review
kb task archive <id> Archive a done task
kb task unarchive <id> Unarchive an archived task
kb task delete <id> [--force] Delete a task (use --force to skip confirmation)
kb task attach <id> <file> Attach a file to a task
kb task pause <id> Pause a task (stops all automation)
kb task unpause <id> Unpause a task (resumes automation)
kb task steer <id> [message] Add steering comment (prompts if message omitted)
kb task retry <id> Retry a failed task (clears error, moves to todo)
kb task import <owner/repo> [opts] Import GitHub issues as tasks
kb settings Show current kb configuration
kb settings set <key> <value> Update a configuration setting
fn task move <id> <col> Move a task to a column
fn task update <id> <step> <status> Update step status (pending|in-progress|done|skipped)
fn task log <id> <message> Add a log entry
fn task merge <id> Merge an in-review task and close it
fn task duplicate <id> Duplicate a task (creates copy in triage)
fn task refine <id> [opts] Create a refinement task from done/in-review
fn task archive <id> Archive a done task
fn task unarchive <id> Unarchive an archived task
fn task delete <id> [--force] Delete a task (use --force to skip confirmation)
fn task attach <id> <file> Attach a file to a task
fn task pause <id> Pause a task (stops all automation)
fn task unpause <id> Unpause a task (resumes automation)
fn task steer <id> [message] Add steering comment (prompts if message omitted)
fn task retry <id> Retry a failed task (clears error, moves to todo)
fn task import <owner/repo> [opts] Import GitHub issues as tasks
fn settings Show current Fusion configuration
fn settings set <key> <value> Update a configuration setting
kb git status Show current branch, commit, dirty state, ahead/behind
kb git push Push current branch
kb git pull Pull current branch
kb git fetch [remote] Fetch from remote (default: origin)
fn git status Show current branch, commit, dirty state, ahead/behind
fn git push Push current branch
fn git pull Pull current branch
fn git fetch [remote] Fetch from remote (default: origin)
Options:
--port, -p <port> Dashboard port (default: 4040)
@@ -171,7 +171,7 @@ async function main() {
const id = args[2];
const column = args[3];
if (!id || !column) {
console.error("Usage: kb task move <id> <column>");
console.error("Usage: fn task move <id> <column>");
process.exit(1);
}
await runTaskMove(id, column);
@@ -179,14 +179,14 @@ async function main() {
}
case "show": {
const id = args[2];
if (!id) { console.error("Usage: kb task show <id>"); process.exit(1); }
if (!id) { console.error("Usage: fn task show <id>"); process.exit(1); }
await runTaskShow(id);
break;
}
case "update": {
const id = args[2], step = args[3], status = args[4];
if (!id || !step || !status) {
console.error("Usage: kb task update <id> <step> <status>");
console.error("Usage: fn task update <id> <step> <status>");
console.error("Status: pending | in-progress | done | skipped");
process.exit(1);
}
@@ -195,13 +195,13 @@ async function main() {
}
case "log": {
const id = args[2], message = args.slice(3).join(" ");
if (!id || !message) { console.error("Usage: kb task log <id> <message>"); process.exit(1); }
if (!id || !message) { console.error("Usage: fn task log <id> <message>"); process.exit(1); }
await runTaskLog(id, message);
break;
}
case "logs": {
const id = args[2];
if (!id) { console.error("Usage: kb task logs <id> [--follow] [--limit <n>] [--type <type>]"); process.exit(1); }
if (!id) { console.error("Usage: fn task logs <id> [--follow] [--limit <n>] [--type <type>]"); process.exit(1); }
// Parse flags
const follow = args.includes("--follow");
@@ -226,19 +226,19 @@ async function main() {
}
case "merge": {
const id = args[2];
if (!id) { console.error("Usage: kb task merge <id>"); process.exit(1); }
if (!id) { console.error("Usage: fn task merge <id>"); process.exit(1); }
await runTaskMerge(id);
break;
}
case "duplicate": {
const id = args[2];
if (!id) { console.error("Usage: kb task duplicate <id>"); process.exit(1); }
if (!id) { console.error("Usage: fn task duplicate <id>"); process.exit(1); }
await runTaskDuplicate(id);
break;
}
case "refine": {
const id = args[2];
if (!id) { console.error("Usage: kb task refine <id> [--feedback <text>]"); process.exit(1); }
if (!id) { console.error("Usage: fn task refine <id> [--feedback <text>]"); process.exit(1); }
// Parse optional --feedback flag
const feedbackIdx = args.indexOf("--feedback");
const feedback = feedbackIdx !== -1 && feedbackIdx + 1 < args.length
@@ -249,19 +249,19 @@ async function main() {
}
case "archive": {
const id = args[2];
if (!id) { console.error("Usage: kb task archive <id>"); process.exit(1); }
if (!id) { console.error("Usage: fn task archive <id>"); process.exit(1); }
await runTaskArchive(id);
break;
}
case "unarchive": {
const id = args[2];
if (!id) { console.error("Usage: kb task unarchive <id>"); process.exit(1); }
if (!id) { console.error("Usage: fn task unarchive <id>"); process.exit(1); }
await runTaskUnarchive(id);
break;
}
case "delete": {
const id = args[2];
if (!id) { console.error("Usage: kb task delete <id> [--force]"); process.exit(1); }
if (!id) { console.error("Usage: fn task delete <id> [--force]"); process.exit(1); }
const force = args.includes("--force");
await runTaskDelete(id, force);
break;
@@ -269,7 +269,7 @@ async function main() {
case "attach": {
const id = args[2], file = args[3];
if (!id || !file) {
console.error("Usage: kb task attach <id> <file>");
console.error("Usage: fn task attach <id> <file>");
process.exit(1);
}
await runTaskAttach(id, file);
@@ -277,27 +277,27 @@ async function main() {
}
case "pause": {
const id = args[2];
if (!id) { console.error("Usage: kb task pause <id>"); process.exit(1); }
if (!id) { console.error("Usage: fn task pause <id>"); process.exit(1); }
await runTaskPause(id);
break;
}
case "unpause": {
const id = args[2];
if (!id) { console.error("Usage: kb task unpause <id>"); process.exit(1); }
if (!id) { console.error("Usage: fn task unpause <id>"); process.exit(1); }
await runTaskUnpause(id);
break;
}
case "steer": {
const id = args[2];
const message = args.slice(3).join(" ");
if (!id) { console.error("Usage: kb task steer <id> [message]"); process.exit(1); }
if (!id) { console.error("Usage: fn task steer <id> [message]"); process.exit(1); }
await runTaskSteer(id, message || undefined);
break;
}
case "retry": {
const id = args[2];
if (!id) {
console.error("Usage: kb task retry <id>");
console.error("Usage: fn task retry <id>");
process.exit(1);
}
await runTaskRetry(id);
@@ -306,7 +306,7 @@ async function main() {
case "import": {
const ownerRepo = args[2];
if (!ownerRepo) {
console.error("Usage: kb task import <owner/repo> [options]");
console.error("Usage: fn task import <owner/repo> [options]");
console.error("Options: --limit <n>, -l <n> (default: 30, max: 100)");
console.error(" --labels <labels>, -L <labels> (comma-separated)");
console.error(" --interactive, -i (interactive mode)");
@@ -346,7 +346,7 @@ async function main() {
}
default:
console.error(`Unknown subcommand: task ${subcommand || ""}`);
console.log("Try: kb task create | list | move");
console.log("Try: fn task create | list | move");
process.exit(1);
}
break;
@@ -362,15 +362,15 @@ async function main() {
const key = args[2];
const value = args.slice(3).join(" ");
if (!key || value === undefined) {
console.error("Usage: kb settings set <key> <value>");
console.error("Example: kb settings set maxConcurrent 4");
console.error("Usage: fn settings set <key> <value>");
console.error("Example: fn settings set maxConcurrent 4");
process.exit(1);
}
await runSettingsSet(key, value);
break;
}
console.error(`Unknown settings subcommand: ${subcommand}`);
console.error("Try: kb settings | kb settings set <key> <value>");
console.error("Try: fn settings | fn settings set <key> <value>");
process.exit(1);
}
@@ -397,7 +397,7 @@ async function main() {
}
default:
console.error(`Unknown subcommand: git ${subcommand || ""}`);
console.log("Try: kb git status | fetch | pull | push");
console.log("Try: fn git status | fetch | pull | push");
process.exit(1);
}
break;

View File

@@ -60,10 +60,10 @@ export default function kbExtension(pi: ExtensionAPI) {
name: "kb_task_create",
label: "KB: Create Task",
description:
"Create a new task on the kb task board. The task enters the triage column " +
"Create a new task on the Fusion task board. The task enters the triage column " +
"where the AI triage agent will specify it into a full prompt with steps, " +
"file scope, and acceptance criteria.",
promptSnippet: "Create a task on the kb AI-orchestrated task board",
promptSnippet: "Create a task on the Fusion AI-orchestrated task board",
promptGuidelines: [
"Use kb_task_create for task tracking — be descriptive so the triage agent can write a good spec.",
"Include the problem AND desired outcome. For bugs, describe current vs expected behavior.",
@@ -112,8 +112,8 @@ export default function kbExtension(pi: ExtensionAPI) {
pi.registerTool({
name: "kb_task_list",
label: "KB: List Tasks",
description: "List all tasks on the kb board, grouped by column.",
promptSnippet: "List all tasks on the kb board grouped by column",
description: "List all tasks on the Fusion board, grouped by column.",
promptSnippet: "List all tasks on the Fusion board grouped by column",
parameters: Type.Object({
column: Type.Optional(
StringEnum([...COLUMNS] as unknown as string[], {
@@ -171,7 +171,7 @@ export default function kbExtension(pi: ExtensionAPI) {
name: "kb_task_show",
label: "KB: Show Task",
description: "Show full details for a task including steps, progress, and log entries.",
promptSnippet: "Show full details for a kb task",
promptSnippet: "Show full details for a Fusion task",
parameters: Type.Object({
id: Type.String({ description: "Task ID (e.g. KB-001)" }),
}),
@@ -252,7 +252,7 @@ export default function kbExtension(pi: ExtensionAPI) {
description:
"Attach a file to a task. Supports images (png, jpg, gif, webp) and " +
"text files (txt, log, json, yaml, yml, toml, csv, xml).",
promptSnippet: "Attach a file to a kb task",
promptSnippet: "Attach a file to a Fusion task",
parameters: Type.Object({
id: Type.String({ description: "Task ID (e.g. KB-001)" }),
path: Type.String({ description: "Path to the file to attach" }),
@@ -302,7 +302,7 @@ export default function kbExtension(pi: ExtensionAPI) {
label: "KB: Pause Task",
description:
"Pause a task — stops all automated agent and scheduler interaction for this task.",
promptSnippet: "Pause a kb task (stops automation)",
promptSnippet: "Pause a Fusion task (stops automation)",
parameters: Type.Object({
id: Type.String({ description: "Task ID (e.g. KB-001)" }),
}),
@@ -325,7 +325,7 @@ export default function kbExtension(pi: ExtensionAPI) {
label: "KB: Unpause Task",
description:
"Unpause a task — resumes automated agent and scheduler interaction.",
promptSnippet: "Unpause a kb task (resumes automation)",
promptSnippet: "Unpause a Fusion task (resumes automation)",
parameters: Type.Object({
id: Type.String({ description: "Task ID (e.g. KB-001)" }),
}),
@@ -348,7 +348,7 @@ export default function kbExtension(pi: ExtensionAPI) {
label: "KB: Retry Task",
description:
"Retry a failed task — clears the error state and moves it back to the todo column for re-execution.",
promptSnippet: "Retry a failed kb task (clears error, moves to todo)",
promptSnippet: "Retry a failed Fusion task (clears error, moves to todo)",
promptGuidelines: [
"Use when a task has failed and needs to be retried from the beginning",
"Only tasks in 'failed' state can be retried",
@@ -407,7 +407,7 @@ export default function kbExtension(pi: ExtensionAPI) {
"Duplicate an existing task, creating a fresh copy in triage. " +
"Copies the title and description but resets all execution state. " +
"The AI triage agent will re-specify the new task.",
promptSnippet: "Duplicate a kb task (creates copy in triage)",
promptSnippet: "Duplicate a Fusion task (creates copy in triage)",
promptGuidelines: [
"Use when a task needs to be re-done, split, or used as a template",
"The duplicated task will be placed in triage for re-specification",
@@ -474,7 +474,7 @@ export default function kbExtension(pi: ExtensionAPI) {
description:
"Archive a done task (move from done → archived). " +
"Archived tasks are preserved for historical reference but moved out of the main board view.",
promptSnippet: "Archive a done kb task (moves to archived column)",
promptSnippet: "Archive a done Fusion task (moves to archived column)",
promptGuidelines: [
"Use to clean up old completed tasks from the done column",
"Only tasks in the 'done' column can be archived",
@@ -503,7 +503,7 @@ export default function kbExtension(pi: ExtensionAPI) {
description:
"Unarchive an archived task (move from archived → done). " +
"Restores the task to the done column.",
promptSnippet: "Unarchive a kb task (restores to done column)",
promptSnippet: "Unarchive a Fusion task (restores to done column)",
promptGuidelines: [
"Use to restore an archived task back to the done column",
"Only tasks in the 'archived' column can be unarchived",
@@ -529,9 +529,9 @@ export default function kbExtension(pi: ExtensionAPI) {
name: "kb_task_delete",
label: "KB: Delete Task",
description:
"Permanently delete a task from the kb board. " +
"Permanently delete a task from the Fusion board. " +
"Tasks are deleted immediately and cannot be recovered.",
promptSnippet: "Delete a kb task",
promptSnippet: "Delete a Fusion task",
promptGuidelines: [
"Use for cleaning up test tasks or tasks created in error",
"Tasks are permanently deleted and cannot be recovered",
@@ -558,12 +558,12 @@ export default function kbExtension(pi: ExtensionAPI) {
name: "kb_task_import_github",
label: "KB: Import GitHub Issues",
description:
"Import GitHub issues as kb tasks. Fetches open issues from a repository " +
"Import GitHub issues as Fusion tasks. Fetches open issues from a repository " +
"and creates tasks in the triage column. Each task includes the issue title " +
"and body with a link to the source issue.",
promptSnippet: "Import GitHub issues as kb tasks",
promptSnippet: "Import GitHub issues as Fusion tasks",
promptGuidelines: [
"Use for syncing GitHub issue backlog to kb board",
"Use for syncing GitHub issue backlog to Fusion board",
"Uses gh CLI authentication when available (run 'gh auth login')",
"Falls back to GITHUB_TOKEN env var for private repositories without gh CLI",
"Use --limit to control how many issues to import (default: 30)",
@@ -648,9 +648,9 @@ export default function kbExtension(pi: ExtensionAPI) {
name: "kb_task_import_github_issue",
label: "KB: Import GitHub Issue",
description:
"Import a specific GitHub issue as a kb task. Fetches the issue by number " +
"Import a specific GitHub issue as a Fusion task. Fetches the issue by number " +
"and creates a single task in the triage column with the issue title and body.",
promptSnippet: "Import a specific GitHub issue as a kb task",
promptSnippet: "Import a specific GitHub issue as a Fusion task",
promptGuidelines: [
"Use for importing a single known issue by its number",
"Uses gh CLI authentication when available (run 'gh auth login')",
@@ -680,7 +680,7 @@ export default function kbExtension(pi: ExtensionAPI) {
const headers: Record<string, string> = {
Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
"User-Agent": "kb-cli/1.0",
"User-Agent": "fusion-cli/1.0",
};
if (token) {
@@ -819,7 +819,7 @@ export default function kbExtension(pi: ExtensionAPI) {
const headers: Record<string, string> = {
Accept: "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
"User-Agent": "kb-cli/1.0",
"User-Agent": "fusion-cli/1.0",
};
if (token) {
@@ -975,46 +975,46 @@ export default function kbExtension(pi: ExtensionAPI) {
},
});
// ── /kb command — start the dashboard + engine ───────────────────
// ── /fn command — start the dashboard + engine ───────────────────
let dashboardProcess: ChildProcess | null = null;
let dashboardPort: number | null = null;
pi.registerCommand("kb", {
description: "Start (or stop) the kb dashboard and AI engine",
pi.registerCommand("fn", {
description: "Start (or stop) the Fusion dashboard and AI engine",
handler: async (args, ctx) => {
const trimmed = (args ?? "").trim();
// /kb stop — kill the dashboard
// /fn stop — kill the dashboard
if (trimmed === "stop") {
if (dashboardProcess) {
dashboardProcess.kill("SIGINT");
dashboardProcess = null;
dashboardPort = null;
ctx.ui.setStatus("kb", "");
ctx.ui.notify("kb dashboard stopped", "info");
ctx.ui.setStatus("fn", "");
ctx.ui.notify("Fusion dashboard stopped", "info");
} else {
ctx.ui.notify("kb dashboard is not running", "warning");
ctx.ui.notify("Fusion dashboard is not running", "warning");
}
return;
}
// /kb status
// /fn status
if (trimmed === "status") {
if (dashboardProcess && !dashboardProcess.killed) {
ctx.ui.notify(`kb dashboard running on http://localhost:${dashboardPort}`, "info");
ctx.ui.notify(`Fusion dashboard running on http://localhost:${dashboardPort}`, "info");
} else {
dashboardProcess = null;
dashboardPort = null;
ctx.ui.notify("kb dashboard is not running", "info");
ctx.ui.notify("Fusion dashboard is not running", "info");
}
return;
}
// /kb [port] — start the dashboard
// /fn [port] — start the dashboard
if (dashboardProcess && !dashboardProcess.killed) {
ctx.ui.notify(
`kb dashboard already running on http://localhost:${dashboardPort}. Use /kb stop first.`,
`Fusion dashboard already running on http://localhost:${dashboardPort}. Use /fn stop first.`,
"warning",
);
return;
@@ -1022,8 +1022,8 @@ export default function kbExtension(pi: ExtensionAPI) {
const port = trimmed ? parseInt(trimmed, 10) || 4040 : 4040;
// Find the kb binary: prefer local node_modules, then global
const child = spawn("kb", ["dashboard", "--port", String(port)], {
// Find the fn binary: prefer local node_modules, then global
const child = spawn("fn", ["dashboard", "--port", String(port)], {
cwd: ctx.cwd,
stdio: ["ignore", "pipe", "pipe"],
detached: false,
@@ -1033,21 +1033,21 @@ export default function kbExtension(pi: ExtensionAPI) {
dashboardProcess = child;
dashboardPort = port;
// Watch for early exit (e.g. kb not found)
// Watch for early exit (e.g. fn not found)
child.on("error", (err) => {
dashboardProcess = null;
dashboardPort = null;
ctx.ui.setStatus("kb", "");
ctx.ui.notify(`Failed to start kb dashboard: ${err.message}`, "error");
ctx.ui.setStatus("fn", "");
ctx.ui.notify(`Failed to start Fusion dashboard: ${err.message}`, "error");
});
child.on("exit", (code) => {
if (dashboardProcess === child) {
dashboardProcess = null;
dashboardPort = null;
ctx.ui.setStatus("kb", "");
ctx.ui.setStatus("fn", "");
if (code !== 0 && code !== null) {
ctx.ui.notify(`kb dashboard exited with code ${code}`, "warning");
ctx.ui.notify(`Fusion dashboard exited with code ${code}`, "warning");
}
}
});
@@ -1057,9 +1057,9 @@ export default function kbExtension(pi: ExtensionAPI) {
if (dashboardProcess && !dashboardProcess.killed) {
const url = `http://localhost:${port}`;
ctx.ui.notify(`kb dashboard started on ${url} (AI engine active)`, "info");
ctx.ui.notify(`Fusion dashboard started on ${url} (AI engine active)`, "info");
const link = `\x1b]8;;${url}\x1b\\${url}\x1b]8;;\x1b\\`;
ctx.ui.setStatus("kb", `kb${link}`);
ctx.ui.setStatus("fn", `Fusion${link}`);
}
},
});