flowbook 0.1.6 → 0.2.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/README.md CHANGED
@@ -30,6 +30,7 @@ npm run build-flowbook
30
30
  flowbook init Set up Flowbook in your project
31
31
  flowbook dev [--port 6200] Start the dev server
32
32
  flowbook build [--out-dir d] Build a static site
33
+ flowbook skill <agent> [-g] Install AI agent skill & /flowbook command
33
34
  ```
34
35
 
35
36
  ### `flowbook init`
@@ -91,7 +92,7 @@ Ignores `node_modules/`, `.git/`, and `dist/`.
91
92
 
92
93
  ## AI Agent Skill
93
94
 
94
- `flowbook init` automatically installs AI agent skills to all supported coding agent directories.
95
+ Use `flowbook skill` to install AI agent skills and `/flowbook` slash commands for your coding agents.
95
96
  When a coding agent (Claude Code, OpenAI Codex, VS Code Copilot, Cursor, Gemini CLI, etc.) detects the keyword **"flowbook"** in your prompt, it will:
96
97
 
97
98
  1. Analyze your codebase for logical flows (API routes, auth, state management, business logic, etc.)
@@ -99,56 +100,77 @@ When a coding agent (Claude Code, OpenAI Codex, VS Code Copilot, Cursor, Gemini
99
100
  3. Generate `.flow.md` files with Mermaid diagrams for every significant flow
100
101
  4. Verify the build
101
102
 
102
- ### Install Skill via CLI
103
+ ### `flowbook skill`
103
104
 
104
- You can also install the skill standalone using [skills.sh](https://skills.sh):
105
+ Install skills and `/flowbook` slash commands for specific agents:
105
106
 
106
107
  ```bash
107
- npx skills add Epsilondelta-ai/flowbook
108
+ # Install for a specific agent (project-level)
109
+ flowbook skill opencode
110
+ flowbook skill claude
111
+ flowbook skill cursor
112
+
113
+ # Install for all agents
114
+ flowbook skill all
115
+
116
+ # Install globally (available across all projects)
117
+ flowbook skill opencode -g
118
+ flowbook skill all --global
108
119
  ```
109
120
 
110
- This auto-detects your installed coding agents and installs the skill to the correct directories.
121
+ **What gets installed:**
122
+
123
+ | Component | Description |
124
+ |-----------|-------------|
125
+ | **Skill** (`SKILL.md`) | Auto-triggers when you mention "flowbook" in prompts |
126
+ | **Slash command** (`/flowbook`) | Explicit trigger — type `/flowbook` to generate flowcharts |
111
127
 
112
- ### Global Installation
128
+ Slash commands are installed for agents that support them: **Claude Code**, **Cursor**, **Windsurf**, **OpenCode**.
113
129
 
114
- To install the skill globally (available across all projects):
130
+ ### Install via skills.sh
131
+
132
+ You can also install the skill standalone using [skills.sh](https://skills.sh):
115
133
 
116
134
  ```bash
135
+ # Project-level
136
+ npx skills add Epsilondelta-ai/flowbook
137
+
138
+ # Global
117
139
  npx skills add -g Epsilondelta-ai/flowbook
118
140
  ```
119
141
 
120
- This installs the skill to each agent's global directory (e.g., `~/.claude/skills/`, `~/.config/opencode/skills/`, etc.).
142
+ > **Note:** `npx skills add` installs skills only (SKILL.md). Use `flowbook skill` to also install `/flowbook` slash commands.
121
143
 
122
- ### Compatible Agents
144
+ ### Supported Agents
123
145
 
124
- | Agent | Skill Location |
125
- |-------|---------------|
126
- | Claude Code | `.claude/skills/flowbook/SKILL.md` |
127
- | OpenAI Codex | `.agents/skills/flowbook/SKILL.md` |
128
- | VS Code / GitHub Copilot | `.github/skills/flowbook/SKILL.md` |
129
- | Google Antigravity | `.agent/skills/flowbook/SKILL.md` |
130
- | Gemini CLI | `.gemini/skills/flowbook/SKILL.md` |
131
- | Cursor | `.cursor/skills/flowbook/SKILL.md` |
132
- | Windsurf (Codeium) | `.windsurf/skills/flowbook/SKILL.md` |
133
- | AmpCode | `.amp/skills/flowbook/SKILL.md` |
134
- | OpenCode / oh-my-opencode | `.opencode/skills/flowbook/SKILL.md` |
146
+ | Agent | Skill | Slash Command |
147
+ |-------|-------|---------------|
148
+ | Claude Code | `.claude/skills/flowbook/SKILL.md` | `.claude/commands/flowbook.md` |
149
+ | OpenAI Codex | `.agents/skills/flowbook/SKILL.md` | — |
150
+ | VS Code / GitHub Copilot | `.github/skills/flowbook/SKILL.md` | — |
151
+ | Google Antigravity | `.agent/skills/flowbook/SKILL.md` | — |
152
+ | Gemini CLI | `.gemini/skills/flowbook/SKILL.md` | — |
153
+ | Cursor | `.cursor/skills/flowbook/SKILL.md` | `.cursor/commands/flowbook.md` |
154
+ | Windsurf (Codeium) | `.windsurf/skills/flowbook/SKILL.md` | `.windsurf/workflows/flowbook.md` |
155
+ | AmpCode | `.amp/skills/flowbook/SKILL.md` | — |
156
+ | OpenCode / oh-my-opencode | `.opencode/skills/flowbook/SKILL.md` | `.opencode/command/flowbook.md` |
135
157
 
136
158
  <details>
137
- <summary>Manual Skill Installation</summary>
159
+ <summary>Manual Installation</summary>
138
160
 
139
- If you didn't use `flowbook init` or `npx skills add`, copy the skill manually:
161
+ If you didn't use `flowbook skill` or `npx skills add`, copy files manually:
140
162
 
141
163
  ```bash
142
- # Example: Claude Code
164
+ # Skill
143
165
  mkdir -p .claude/skills/flowbook
144
166
  cp node_modules/flowbook/src/skills/flowbook/SKILL.md .claude/skills/flowbook/
145
167
 
146
- # Example: Cursor
147
- mkdir -p .cursor/skills/flowbook
148
- cp node_modules/flowbook/src/skills/flowbook/SKILL.md .cursor/skills/flowbook/
168
+ # Slash command (Claude Code)
169
+ mkdir -p .claude/commands
170
+ cp node_modules/flowbook/src/commands/flowbook.md .claude/commands/
149
171
  ```
150
172
 
151
- Replace the directory with the appropriate path from the Compatible Agents table above.
173
+ Replace directories with the appropriate paths from the table above.
152
174
 
153
175
  </details>
154
176
  ## How It Works
@@ -175,12 +197,19 @@ Replace the directory with the appropriate path from the Compatible Agents table
175
197
  src/
176
198
  ├── types.ts # Shared types (FlowEntry, FlowbookData)
177
199
  ├── node/
178
- │ ├── cli.ts # CLI entry point (init, dev, build)
200
+ │ ├── cli.ts # CLI entry point (init, dev, build, skill)
179
201
  │ ├── server.ts # Programmatic Vite server & build
180
202
  │ ├── init.ts # Project initialization logic
203
+ │ ├── skill.ts # AI agent skill & command installer
181
204
  │ ├── discovery.ts # File scanner (fast-glob)
182
205
  │ ├── parser.ts # Frontmatter + mermaid extraction
183
206
  │ └── plugin.ts # Vite virtual module plugin
207
+ ├── skills/
208
+ │ └── flowbook/
209
+ │ └── SKILL.md # AI agent skill definition
210
+ ├── commands/
211
+ │ ├── flowbook.md # Slash command (frontmatter format)
212
+ │ └── flowbook.plain.md # Slash command (plain markdown format)
184
213
  └── client/
185
214
  ├── index.html # Entry HTML
186
215
  ├── main.tsx # React entry
@@ -193,7 +222,6 @@ src/
193
222
  ├── MermaidRenderer.tsx # Mermaid diagram rendering
194
223
  ├── FlowView.tsx # Single flow detail view
195
224
  └── EmptyState.tsx # Empty state with guide
196
- ```
197
225
 
198
226
  ## Development (Contributing)
199
227
 
package/dist/cli.js CHANGED
@@ -1,11 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/node/init.ts
4
- import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync } from "fs";
5
- import { resolve, dirname } from "path";
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
5
+ import { resolve } from "path";
6
6
  import { execSync } from "child_process";
7
- import { fileURLToPath } from "url";
8
- var __dirname = dirname(fileURLToPath(import.meta.url));
9
7
  var EXAMPLE_FLOW = `---
10
8
  title: Example Flow
11
9
  category: Getting Started
@@ -74,48 +72,12 @@ async function initFlowbook() {
74
72
  console.log(" \u2713 Added flowbook-static to .gitignore");
75
73
  }
76
74
  }
77
- const skillSrc = resolve(__dirname, "..", "src", "skills", "flowbook", "SKILL.md");
78
- const skillDirs = [
79
- resolve(cwd, ".claude", "skills", "flowbook"),
80
- // Claude Code
81
- resolve(cwd, ".agents", "skills", "flowbook"),
82
- // OpenAI Codex / cross-tool alias
83
- resolve(cwd, ".github", "skills", "flowbook"),
84
- // VS Code / GitHub Copilot
85
- resolve(cwd, ".agent", "skills", "flowbook"),
86
- // Google Antigravity
87
- resolve(cwd, ".gemini", "skills", "flowbook"),
88
- // Gemini CLI
89
- resolve(cwd, ".cursor", "skills", "flowbook"),
90
- // Cursor
91
- resolve(cwd, ".windsurf", "skills", "flowbook"),
92
- // Windsurf (Codeium)
93
- resolve(cwd, ".amp", "skills", "flowbook"),
94
- // AmpCode
95
- resolve(cwd, ".opencode", "skills", "flowbook")
96
- // OpenCode / oh-my-opencode
97
- ];
98
- if (existsSync(skillSrc)) {
99
- let installed = 0;
100
- for (const dir of skillDirs) {
101
- const dest = resolve(dir, "SKILL.md");
102
- if (!existsSync(dest)) {
103
- mkdirSync(dir, { recursive: true });
104
- copyFileSync(skillSrc, dest);
105
- installed++;
106
- }
107
- }
108
- if (installed > 0) {
109
- console.log(` \u2713 Installed AI agent skill to ${installed} agent directories`);
110
- } else {
111
- console.log(" \u2713 AI agent skills already installed");
112
- }
113
- }
114
75
  const run = pm === "yarn" ? "yarn" : `${pm} run`;
115
76
  console.log("");
116
77
  console.log(" Next steps:");
117
- console.log(` ${run} flowbook Start the dev server`);
118
- console.log(` ${run} build-flowbook Build static site`);
78
+ console.log(` ${run} flowbook Start the dev server`);
79
+ console.log(` ${run} build-flowbook Build static site`);
80
+ console.log(` flowbook skill <agent> [-g] Install AI skill & /flowbook command`);
119
81
  console.log("");
120
82
  }
121
83
  function detectPackageManager(cwd) {
@@ -228,11 +190,11 @@ function flowbookPlugin(options = {}) {
228
190
  }
229
191
 
230
192
  // src/node/server.ts
231
- import { resolve as resolve2, dirname as dirname2 } from "path";
232
- import { fileURLToPath as fileURLToPath2 } from "url";
233
- var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
193
+ import { resolve as resolve2, dirname } from "path";
194
+ import { fileURLToPath } from "url";
195
+ var __dirname = dirname(fileURLToPath(import.meta.url));
234
196
  function getClientDir() {
235
- return resolve2(__dirname2, "..", "src", "client");
197
+ return resolve2(__dirname, "..", "src", "client");
236
198
  }
237
199
  function createConfig(options) {
238
200
  const cwd = options.cwd ?? process.cwd();
@@ -272,6 +234,196 @@ async function buildStatic(options) {
272
234
  `);
273
235
  }
274
236
 
237
+ // src/node/skill.ts
238
+ import { existsSync as existsSync2, mkdirSync as mkdirSync2, copyFileSync } from "fs";
239
+ import { resolve as resolve3, dirname as dirname2 } from "path";
240
+ import { fileURLToPath as fileURLToPath2 } from "url";
241
+ import { homedir } from "os";
242
+ var __dirname2 = dirname2(fileURLToPath2(import.meta.url));
243
+ var AGENTS = [
244
+ {
245
+ name: "Claude Code",
246
+ aliases: ["claude"],
247
+ skill: {
248
+ project: ".claude/skills/flowbook",
249
+ global: ".claude/skills/flowbook"
250
+ },
251
+ command: {
252
+ project: ".claude/commands",
253
+ global: ".claude/commands",
254
+ format: "frontmatter"
255
+ }
256
+ },
257
+ {
258
+ name: "OpenAI Codex",
259
+ aliases: ["codex"],
260
+ skill: {
261
+ project: ".agents/skills/flowbook",
262
+ global: ".codex/skills/flowbook"
263
+ }
264
+ },
265
+ {
266
+ name: "VS Code / GitHub Copilot",
267
+ aliases: ["copilot", "vscode"],
268
+ skill: {
269
+ project: ".github/skills/flowbook",
270
+ global: ".copilot/skills/flowbook"
271
+ }
272
+ },
273
+ {
274
+ name: "Google Antigravity",
275
+ aliases: ["antigravity"],
276
+ skill: {
277
+ project: ".agent/skills/flowbook",
278
+ global: ".gemini/antigravity/skills/flowbook"
279
+ }
280
+ },
281
+ {
282
+ name: "Gemini CLI",
283
+ aliases: ["gemini"],
284
+ skill: {
285
+ project: ".gemini/skills/flowbook",
286
+ global: ".gemini/skills/flowbook"
287
+ }
288
+ },
289
+ {
290
+ name: "Cursor",
291
+ aliases: ["cursor"],
292
+ skill: {
293
+ project: ".cursor/skills/flowbook",
294
+ global: ".cursor/skills/flowbook"
295
+ },
296
+ command: {
297
+ project: ".cursor/commands",
298
+ global: ".cursor/commands",
299
+ format: "plain"
300
+ }
301
+ },
302
+ {
303
+ name: "Windsurf",
304
+ aliases: ["windsurf"],
305
+ skill: {
306
+ project: ".windsurf/skills/flowbook",
307
+ global: ".codeium/windsurf/skills/flowbook"
308
+ },
309
+ command: {
310
+ project: ".windsurf/workflows",
311
+ global: ".codeium/windsurf/workflows",
312
+ format: "plain"
313
+ }
314
+ },
315
+ {
316
+ name: "AmpCode",
317
+ aliases: ["amp"],
318
+ skill: {
319
+ project: ".amp/skills/flowbook",
320
+ global: ".config/agents/skills/flowbook"
321
+ }
322
+ },
323
+ {
324
+ name: "OpenCode",
325
+ aliases: ["opencode"],
326
+ skill: {
327
+ project: ".opencode/skills/flowbook",
328
+ global: ".config/opencode/skills/flowbook"
329
+ },
330
+ command: {
331
+ project: ".opencode/command",
332
+ global: ".config/opencode/command",
333
+ format: "frontmatter"
334
+ }
335
+ }
336
+ ];
337
+ function getSkillSrc() {
338
+ return resolve3(__dirname2, "..", "src", "skills", "flowbook", "SKILL.md");
339
+ }
340
+ function getCommandSrc(format) {
341
+ const file = format === "frontmatter" ? "flowbook.md" : "flowbook.plain.md";
342
+ return resolve3(__dirname2, "..", "src", "commands", file);
343
+ }
344
+ function resolveAgents(agentArg) {
345
+ if (agentArg === "all") return AGENTS;
346
+ const lower = agentArg.toLowerCase();
347
+ const found = AGENTS.filter(
348
+ (a) => a.aliases.includes(lower) || a.name.toLowerCase().includes(lower)
349
+ );
350
+ if (found.length === 0) {
351
+ console.error(` Unknown agent: "${agentArg}"`);
352
+ console.error(` Available: all, ${AGENTS.flatMap((a) => a.aliases).join(", ")}`);
353
+ process.exit(1);
354
+ }
355
+ return found;
356
+ }
357
+ function installFile(src, destDir, destFilename) {
358
+ const dest = resolve3(destDir, destFilename);
359
+ if (existsSync2(dest)) return false;
360
+ mkdirSync2(destDir, { recursive: true });
361
+ copyFileSync(src, dest);
362
+ return true;
363
+ }
364
+ function installSkills(agentArg, global) {
365
+ const agents = resolveAgents(agentArg);
366
+ const base = global ? homedir() : process.cwd();
367
+ const skillSrc = getSkillSrc();
368
+ if (!existsSync2(skillSrc)) {
369
+ console.error(" \u2717 Skill source file not found. Reinstall flowbook.");
370
+ process.exit(1);
371
+ }
372
+ let skillCount = 0;
373
+ let cmdCount = 0;
374
+ for (const agent of agents) {
375
+ const skillDir = resolve3(base, global ? agent.skill.global : agent.skill.project);
376
+ if (installFile(skillSrc, skillDir, "SKILL.md")) {
377
+ skillCount++;
378
+ }
379
+ if (agent.command) {
380
+ const cmdSrc = getCommandSrc(agent.command.format);
381
+ if (existsSync2(cmdSrc)) {
382
+ const cmdDir = resolve3(base, global ? agent.command.global : agent.command.project);
383
+ if (installFile(cmdSrc, cmdDir, "flowbook.md")) {
384
+ cmdCount++;
385
+ }
386
+ }
387
+ }
388
+ }
389
+ const scope = global ? "global" : "project";
390
+ const agentNames = agents.map((a) => a.name).join(", ");
391
+ if (skillCount > 0 || cmdCount > 0) {
392
+ if (skillCount > 0) console.log(` \u2713 Installed skill to ${skillCount} ${scope} director${skillCount > 1 ? "ies" : "y"}`);
393
+ if (cmdCount > 0) console.log(` \u2713 Installed /flowbook command to ${cmdCount} ${scope} director${cmdCount > 1 ? "ies" : "y"}`);
394
+ console.log(` Agents: ${agentNames}`);
395
+ } else {
396
+ console.log(` \u2713 Already installed for: ${agentNames}`);
397
+ }
398
+ }
399
+ function printSkillUsage() {
400
+ console.log(`
401
+ flowbook skill \u2014 Install AI agent skill & /flowbook command
402
+
403
+ Usage:
404
+ flowbook skill <agent> Install to project
405
+ flowbook skill <agent> --global Install globally
406
+ flowbook skill <agent> -g Install globally (short)
407
+
408
+ Agents:
409
+ all All supported agents
410
+ claude Claude Code
411
+ codex OpenAI Codex
412
+ copilot VS Code / GitHub Copilot
413
+ antigravity Google Antigravity
414
+ gemini Gemini CLI
415
+ cursor Cursor
416
+ windsurf Windsurf (Codeium)
417
+ amp AmpCode
418
+ opencode OpenCode / oh-my-opencode
419
+
420
+ Examples:
421
+ flowbook skill all Install to all agents (project)
422
+ flowbook skill opencode -g Install globally for OpenCode
423
+ flowbook skill claude --global Install globally for Claude Code
424
+ `);
425
+ }
426
+
275
427
  // src/node/cli.ts
276
428
  async function main() {
277
429
  const args = process.argv.slice(2);
@@ -290,6 +442,16 @@ async function main() {
290
442
  await buildStatic({ outDir });
291
443
  break;
292
444
  }
445
+ case "skill": {
446
+ const agent = args[1];
447
+ if (!agent) {
448
+ printSkillUsage();
449
+ break;
450
+ }
451
+ const isGlobal = args.includes("--global") || args.includes("-g");
452
+ installSkills(agent, isGlobal);
453
+ break;
454
+ }
293
455
  default:
294
456
  printUsage();
295
457
  break;
@@ -308,10 +470,13 @@ function printUsage() {
308
470
  flowbook init Set up Flowbook in your project
309
471
  flowbook dev [--port 6200] Start the dev server
310
472
  flowbook build [--out-dir d] Build a static site
473
+ flowbook skill <agent> [-g] Install AI agent skill & command
311
474
 
312
475
  Options:
313
476
  --port <number> Dev server port (default: 6200)
314
477
  --out-dir <path> Build output directory (default: flowbook-static)
478
+
479
+ Run 'flowbook skill' for agent-specific options.
315
480
  `);
316
481
  }
317
482
  main().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowbook",
3
- "version": "0.1.6",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "flowbook": "./dist/cli.js"
@@ -0,0 +1,13 @@
1
+ ---
2
+ description: Analyze codebase and generate Mermaid flowchart documentation using Flowbook
3
+ ---
4
+
5
+ Load the **flowbook** skill and execute the full flowchart generation workflow.
6
+
7
+ When prompted with `/flowbook`, you MUST:
8
+
9
+ 1. Load the `flowbook` skill (SKILL.md) for detailed instructions
10
+ 2. Analyze the codebase for logical flows (API routes, auth, state management, business logic)
11
+ 3. Set up Flowbook if not already initialized (`npx flowbook@latest init`)
12
+ 4. Generate `.flow.md` files with Mermaid diagrams for every significant flow
13
+ 5. Run `npm run flowbook` to verify the build
@@ -0,0 +1,13 @@
1
+ # /flowbook — Flowchart Documentation Generator
2
+
3
+ Analyze codebase and generate Mermaid flowchart documentation using Flowbook.
4
+
5
+ Load the **flowbook** skill and execute the full flowchart generation workflow.
6
+
7
+ When prompted with `/flowbook`, you MUST:
8
+
9
+ 1. Load the `flowbook` skill (SKILL.md) for detailed instructions
10
+ 2. Analyze the codebase for logical flows (API routes, auth, state management, business logic)
11
+ 3. Set up Flowbook if not already initialized (`npx flowbook@latest init`)
12
+ 4. Generate `.flow.md` files with Mermaid diagrams for every significant flow
13
+ 5. Run `npm run flowbook` to verify the build
package/src/node/cli.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { initFlowbook } from "./init";
2
2
  import { startDevServer, buildStatic } from "./server";
3
+ import { installSkills, printSkillUsage } from "./skill";
3
4
 
4
5
  async function main() {
5
6
  const args = process.argv.slice(2);
@@ -22,6 +23,17 @@ async function main() {
22
23
  break;
23
24
  }
24
25
 
26
+ case "skill": {
27
+ const agent = args[1];
28
+ if (!agent) {
29
+ printSkillUsage();
30
+ break;
31
+ }
32
+ const isGlobal = args.includes("--global") || args.includes("-g");
33
+ installSkills(agent, isGlobal);
34
+ break;
35
+ }
36
+
25
37
  default:
26
38
  printUsage();
27
39
  break;
@@ -46,10 +58,13 @@ function printUsage() {
46
58
  flowbook init Set up Flowbook in your project
47
59
  flowbook dev [--port 6200] Start the dev server
48
60
  flowbook build [--out-dir d] Build a static site
61
+ flowbook skill <agent> [-g] Install AI agent skill & command
49
62
 
50
63
  Options:
51
64
  --port <number> Dev server port (default: 6200)
52
65
  --out-dir <path> Build output directory (default: flowbook-static)
66
+
67
+ Run 'flowbook skill' for agent-specific options.
53
68
  `);
54
69
  }
55
70
 
package/src/node/init.ts CHANGED
@@ -1,9 +1,7 @@
1
- import { readFileSync, writeFileSync, existsSync, mkdirSync, copyFileSync } from "node:fs";
2
- import { resolve, dirname } from "node:path";
1
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
2
+ import { resolve } from "node:path";
3
3
  import { execSync } from "node:child_process";
4
- import { fileURLToPath } from "node:url";
5
4
 
6
- const __dirname = dirname(fileURLToPath(import.meta.url));
7
5
 
8
6
  const EXAMPLE_FLOW = `---
9
7
  title: Example Flow
@@ -88,42 +86,12 @@ export async function initFlowbook() {
88
86
  }
89
87
  }
90
88
 
91
- // 5. Install AI agent skill to all supported agent directories
92
- const skillSrc = resolve(__dirname, "..", "src", "skills", "flowbook", "SKILL.md");
93
- const skillDirs = [
94
- resolve(cwd, ".claude", "skills", "flowbook"), // Claude Code
95
- resolve(cwd, ".agents", "skills", "flowbook"), // OpenAI Codex / cross-tool alias
96
- resolve(cwd, ".github", "skills", "flowbook"), // VS Code / GitHub Copilot
97
- resolve(cwd, ".agent", "skills", "flowbook"), // Google Antigravity
98
- resolve(cwd, ".gemini", "skills", "flowbook"), // Gemini CLI
99
- resolve(cwd, ".cursor", "skills", "flowbook"), // Cursor
100
- resolve(cwd, ".windsurf", "skills", "flowbook"), // Windsurf (Codeium)
101
- resolve(cwd, ".amp", "skills", "flowbook"), // AmpCode
102
- resolve(cwd, ".opencode", "skills", "flowbook"), // OpenCode / oh-my-opencode
103
- ];
104
-
105
- if (existsSync(skillSrc)) {
106
- let installed = 0;
107
- for (const dir of skillDirs) {
108
- const dest = resolve(dir, "SKILL.md");
109
- if (!existsSync(dest)) {
110
- mkdirSync(dir, { recursive: true });
111
- copyFileSync(skillSrc, dest);
112
- installed++;
113
- }
114
- }
115
- if (installed > 0) {
116
- console.log(` \u2713 Installed AI agent skill to ${installed} agent directories`);
117
- } else {
118
- console.log(" \u2713 AI agent skills already installed");
119
- }
120
- }
121
-
122
89
  const run = pm === "yarn" ? "yarn" : `${pm} run`;
123
90
  console.log("");
124
91
  console.log(" Next steps:");
125
- console.log(` ${run} flowbook Start the dev server`);
126
- console.log(` ${run} build-flowbook Build static site`);
92
+ console.log(` ${run} flowbook Start the dev server`);
93
+ console.log(` ${run} build-flowbook Build static site`);
94
+ console.log(` flowbook skill <agent> [-g] Install AI skill & /flowbook command`);
127
95
  console.log("");
128
96
  }
129
97
 
@@ -0,0 +1,230 @@
1
+ import { existsSync, mkdirSync, copyFileSync } from "node:fs";
2
+ import { resolve, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { homedir } from "node:os";
5
+
6
+ const __dirname = dirname(fileURLToPath(import.meta.url));
7
+
8
+ interface AgentConfig {
9
+ name: string;
10
+ aliases: string[];
11
+ skill: { project: string; global: string };
12
+ command?: { project: string; global: string; format: "frontmatter" | "plain" };
13
+ }
14
+
15
+ const AGENTS: AgentConfig[] = [
16
+ {
17
+ name: "Claude Code",
18
+ aliases: ["claude"],
19
+ skill: {
20
+ project: ".claude/skills/flowbook",
21
+ global: ".claude/skills/flowbook",
22
+ },
23
+ command: {
24
+ project: ".claude/commands",
25
+ global: ".claude/commands",
26
+ format: "frontmatter",
27
+ },
28
+ },
29
+ {
30
+ name: "OpenAI Codex",
31
+ aliases: ["codex"],
32
+ skill: {
33
+ project: ".agents/skills/flowbook",
34
+ global: ".codex/skills/flowbook",
35
+ },
36
+ },
37
+ {
38
+ name: "VS Code / GitHub Copilot",
39
+ aliases: ["copilot", "vscode"],
40
+ skill: {
41
+ project: ".github/skills/flowbook",
42
+ global: ".copilot/skills/flowbook",
43
+ },
44
+ },
45
+ {
46
+ name: "Google Antigravity",
47
+ aliases: ["antigravity"],
48
+ skill: {
49
+ project: ".agent/skills/flowbook",
50
+ global: ".gemini/antigravity/skills/flowbook",
51
+ },
52
+ },
53
+ {
54
+ name: "Gemini CLI",
55
+ aliases: ["gemini"],
56
+ skill: {
57
+ project: ".gemini/skills/flowbook",
58
+ global: ".gemini/skills/flowbook",
59
+ },
60
+ },
61
+ {
62
+ name: "Cursor",
63
+ aliases: ["cursor"],
64
+ skill: {
65
+ project: ".cursor/skills/flowbook",
66
+ global: ".cursor/skills/flowbook",
67
+ },
68
+ command: {
69
+ project: ".cursor/commands",
70
+ global: ".cursor/commands",
71
+ format: "plain",
72
+ },
73
+ },
74
+ {
75
+ name: "Windsurf",
76
+ aliases: ["windsurf"],
77
+ skill: {
78
+ project: ".windsurf/skills/flowbook",
79
+ global: ".codeium/windsurf/skills/flowbook",
80
+ },
81
+ command: {
82
+ project: ".windsurf/workflows",
83
+ global: ".codeium/windsurf/workflows",
84
+ format: "plain",
85
+ },
86
+ },
87
+ {
88
+ name: "AmpCode",
89
+ aliases: ["amp"],
90
+ skill: {
91
+ project: ".amp/skills/flowbook",
92
+ global: ".config/agents/skills/flowbook",
93
+ },
94
+ },
95
+ {
96
+ name: "OpenCode",
97
+ aliases: ["opencode"],
98
+ skill: {
99
+ project: ".opencode/skills/flowbook",
100
+ global: ".config/opencode/skills/flowbook",
101
+ },
102
+ command: {
103
+ project: ".opencode/command",
104
+ global: ".config/opencode/command",
105
+ format: "frontmatter",
106
+ },
107
+ },
108
+ ];
109
+
110
+ function getSkillSrc(): string {
111
+ return resolve(__dirname, "..", "src", "skills", "flowbook", "SKILL.md");
112
+ }
113
+
114
+ function getCommandSrc(format: "frontmatter" | "plain"): string {
115
+ const file = format === "frontmatter" ? "flowbook.md" : "flowbook.plain.md";
116
+ return resolve(__dirname, "..", "src", "commands", file);
117
+ }
118
+
119
+ function resolveAgents(agentArg: string): AgentConfig[] {
120
+ if (agentArg === "all") return AGENTS;
121
+
122
+ const lower = agentArg.toLowerCase();
123
+ const found = AGENTS.filter(
124
+ (a) =>
125
+ a.aliases.includes(lower) ||
126
+ a.name.toLowerCase().includes(lower),
127
+ );
128
+
129
+ if (found.length === 0) {
130
+ console.error(` Unknown agent: "${agentArg}"`);
131
+ console.error(` Available: all, ${AGENTS.flatMap((a) => a.aliases).join(", ")}`);
132
+ process.exit(1);
133
+ }
134
+
135
+ return found;
136
+ }
137
+
138
+ function installFile(src: string, destDir: string, destFilename: string): boolean {
139
+ const dest = resolve(destDir, destFilename);
140
+ if (existsSync(dest)) return false;
141
+ mkdirSync(destDir, { recursive: true });
142
+ copyFileSync(src, dest);
143
+ return true;
144
+ }
145
+
146
+ export function installSkills(agentArg: string, global: boolean): void {
147
+ const agents = resolveAgents(agentArg);
148
+ const base = global ? homedir() : process.cwd();
149
+ const skillSrc = getSkillSrc();
150
+
151
+ if (!existsSync(skillSrc)) {
152
+ console.error(" ✗ Skill source file not found. Reinstall flowbook.");
153
+ process.exit(1);
154
+ }
155
+
156
+ let skillCount = 0;
157
+ let cmdCount = 0;
158
+
159
+ for (const agent of agents) {
160
+ const skillDir = resolve(base, global ? agent.skill.global : agent.skill.project);
161
+ if (installFile(skillSrc, skillDir, "SKILL.md")) {
162
+ skillCount++;
163
+ }
164
+
165
+ if (agent.command) {
166
+ const cmdSrc = getCommandSrc(agent.command.format);
167
+ if (existsSync(cmdSrc)) {
168
+ const cmdDir = resolve(base, global ? agent.command.global : agent.command.project);
169
+ if (installFile(cmdSrc, cmdDir, "flowbook.md")) {
170
+ cmdCount++;
171
+ }
172
+ }
173
+ }
174
+ }
175
+
176
+ const scope = global ? "global" : "project";
177
+ const agentNames = agents.map((a) => a.name).join(", ");
178
+
179
+ if (skillCount > 0 || cmdCount > 0) {
180
+ if (skillCount > 0) console.log(` ✓ Installed skill to ${skillCount} ${scope} director${skillCount > 1 ? "ies" : "y"}`);
181
+ if (cmdCount > 0) console.log(` ✓ Installed /flowbook command to ${cmdCount} ${scope} director${cmdCount > 1 ? "ies" : "y"}`);
182
+ console.log(` Agents: ${agentNames}`);
183
+ } else {
184
+ console.log(` ✓ Already installed for: ${agentNames}`);
185
+ }
186
+ }
187
+
188
+ /** Used by init.ts — installs skills only (no commands) to all agents at project level */
189
+ export function installAllProjectSkills(): number {
190
+ const cwd = process.cwd();
191
+ const skillSrc = getSkillSrc();
192
+ if (!existsSync(skillSrc)) return 0;
193
+
194
+ let installed = 0;
195
+ for (const agent of AGENTS) {
196
+ const dir = resolve(cwd, agent.skill.project);
197
+ if (installFile(skillSrc, dir, "SKILL.md")) {
198
+ installed++;
199
+ }
200
+ }
201
+ return installed;
202
+ }
203
+
204
+ export function printSkillUsage(): void {
205
+ console.log(`
206
+ flowbook skill — Install AI agent skill & /flowbook command
207
+
208
+ Usage:
209
+ flowbook skill <agent> Install to project
210
+ flowbook skill <agent> --global Install globally
211
+ flowbook skill <agent> -g Install globally (short)
212
+
213
+ Agents:
214
+ all All supported agents
215
+ claude Claude Code
216
+ codex OpenAI Codex
217
+ copilot VS Code / GitHub Copilot
218
+ antigravity Google Antigravity
219
+ gemini Gemini CLI
220
+ cursor Cursor
221
+ windsurf Windsurf (Codeium)
222
+ amp AmpCode
223
+ opencode OpenCode / oh-my-opencode
224
+
225
+ Examples:
226
+ flowbook skill all Install to all agents (project)
227
+ flowbook skill opencode -g Install globally for OpenCode
228
+ flowbook skill claude --global Install globally for Claude Code
229
+ `);
230
+ }