flowbook 0.2.0 → 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
@@ -37,7 +37,6 @@ flowbook skill <agent> [-g] Install AI agent skill & /flowbook command
37
37
 
38
38
  - Adds `"flowbook"` and `"build-flowbook"` scripts to your `package.json`
39
39
  - Creates `flows/example.flow.md` as a starter template
40
- - Installs AI agent skills to all supported agent directories
41
40
 
42
41
  ### `flowbook dev`
43
42
 
@@ -93,7 +92,7 @@ Ignores `node_modules/`, `.git/`, and `dist/`.
93
92
 
94
93
  ## AI Agent Skill
95
94
 
96
- `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.
97
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:
98
97
 
99
98
  1. Analyze your codebase for logical flows (API routes, auth, state management, business logic, etc.)
package/dist/cli.js CHANGED
@@ -1,214 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/node/init.ts
4
- import { readFileSync, writeFileSync, existsSync as existsSync2, mkdirSync as mkdirSync2 } from "fs";
5
- import { resolve as resolve2 } from "path";
4
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
5
+ import { resolve } from "path";
6
6
  import { execSync } from "child_process";
7
-
8
- // src/node/skill.ts
9
- import { existsSync, mkdirSync, copyFileSync } from "fs";
10
- import { resolve, dirname } from "path";
11
- import { fileURLToPath } from "url";
12
- import { homedir } from "os";
13
- var __dirname = dirname(fileURLToPath(import.meta.url));
14
- var AGENTS = [
15
- {
16
- name: "Claude Code",
17
- aliases: ["claude"],
18
- skill: {
19
- project: ".claude/skills/flowbook",
20
- global: ".claude/skills/flowbook"
21
- },
22
- command: {
23
- project: ".claude/commands",
24
- global: ".claude/commands",
25
- format: "frontmatter"
26
- }
27
- },
28
- {
29
- name: "OpenAI Codex",
30
- aliases: ["codex"],
31
- skill: {
32
- project: ".agents/skills/flowbook",
33
- global: ".codex/skills/flowbook"
34
- }
35
- },
36
- {
37
- name: "VS Code / GitHub Copilot",
38
- aliases: ["copilot", "vscode"],
39
- skill: {
40
- project: ".github/skills/flowbook",
41
- global: ".copilot/skills/flowbook"
42
- }
43
- },
44
- {
45
- name: "Google Antigravity",
46
- aliases: ["antigravity"],
47
- skill: {
48
- project: ".agent/skills/flowbook",
49
- global: ".gemini/antigravity/skills/flowbook"
50
- }
51
- },
52
- {
53
- name: "Gemini CLI",
54
- aliases: ["gemini"],
55
- skill: {
56
- project: ".gemini/skills/flowbook",
57
- global: ".gemini/skills/flowbook"
58
- }
59
- },
60
- {
61
- name: "Cursor",
62
- aliases: ["cursor"],
63
- skill: {
64
- project: ".cursor/skills/flowbook",
65
- global: ".cursor/skills/flowbook"
66
- },
67
- command: {
68
- project: ".cursor/commands",
69
- global: ".cursor/commands",
70
- format: "plain"
71
- }
72
- },
73
- {
74
- name: "Windsurf",
75
- aliases: ["windsurf"],
76
- skill: {
77
- project: ".windsurf/skills/flowbook",
78
- global: ".codeium/windsurf/skills/flowbook"
79
- },
80
- command: {
81
- project: ".windsurf/workflows",
82
- global: ".codeium/windsurf/workflows",
83
- format: "plain"
84
- }
85
- },
86
- {
87
- name: "AmpCode",
88
- aliases: ["amp"],
89
- skill: {
90
- project: ".amp/skills/flowbook",
91
- global: ".config/agents/skills/flowbook"
92
- }
93
- },
94
- {
95
- name: "OpenCode",
96
- aliases: ["opencode"],
97
- skill: {
98
- project: ".opencode/skills/flowbook",
99
- global: ".config/opencode/skills/flowbook"
100
- },
101
- command: {
102
- project: ".opencode/command",
103
- global: ".config/opencode/command",
104
- format: "frontmatter"
105
- }
106
- }
107
- ];
108
- function getSkillSrc() {
109
- return resolve(__dirname, "..", "src", "skills", "flowbook", "SKILL.md");
110
- }
111
- function getCommandSrc(format) {
112
- const file = format === "frontmatter" ? "flowbook.md" : "flowbook.plain.md";
113
- return resolve(__dirname, "..", "src", "commands", file);
114
- }
115
- function resolveAgents(agentArg) {
116
- if (agentArg === "all") return AGENTS;
117
- const lower = agentArg.toLowerCase();
118
- const found = AGENTS.filter(
119
- (a) => a.aliases.includes(lower) || a.name.toLowerCase().includes(lower)
120
- );
121
- if (found.length === 0) {
122
- console.error(` Unknown agent: "${agentArg}"`);
123
- console.error(` Available: all, ${AGENTS.flatMap((a) => a.aliases).join(", ")}`);
124
- process.exit(1);
125
- }
126
- return found;
127
- }
128
- function installFile(src, destDir, destFilename) {
129
- const dest = resolve(destDir, destFilename);
130
- if (existsSync(dest)) return false;
131
- mkdirSync(destDir, { recursive: true });
132
- copyFileSync(src, dest);
133
- return true;
134
- }
135
- function installSkills(agentArg, global) {
136
- const agents = resolveAgents(agentArg);
137
- const base = global ? homedir() : process.cwd();
138
- const skillSrc = getSkillSrc();
139
- if (!existsSync(skillSrc)) {
140
- console.error(" \u2717 Skill source file not found. Reinstall flowbook.");
141
- process.exit(1);
142
- }
143
- let skillCount = 0;
144
- let cmdCount = 0;
145
- for (const agent of agents) {
146
- const skillDir = resolve(base, global ? agent.skill.global : agent.skill.project);
147
- if (installFile(skillSrc, skillDir, "SKILL.md")) {
148
- skillCount++;
149
- }
150
- if (agent.command) {
151
- const cmdSrc = getCommandSrc(agent.command.format);
152
- if (existsSync(cmdSrc)) {
153
- const cmdDir = resolve(base, global ? agent.command.global : agent.command.project);
154
- if (installFile(cmdSrc, cmdDir, "flowbook.md")) {
155
- cmdCount++;
156
- }
157
- }
158
- }
159
- }
160
- const scope = global ? "global" : "project";
161
- const agentNames = agents.map((a) => a.name).join(", ");
162
- if (skillCount > 0 || cmdCount > 0) {
163
- if (skillCount > 0) console.log(` \u2713 Installed skill to ${skillCount} ${scope} director${skillCount > 1 ? "ies" : "y"}`);
164
- if (cmdCount > 0) console.log(` \u2713 Installed /flowbook command to ${cmdCount} ${scope} director${cmdCount > 1 ? "ies" : "y"}`);
165
- console.log(` Agents: ${agentNames}`);
166
- } else {
167
- console.log(` \u2713 Already installed for: ${agentNames}`);
168
- }
169
- }
170
- function installAllProjectSkills() {
171
- const cwd = process.cwd();
172
- const skillSrc = getSkillSrc();
173
- if (!existsSync(skillSrc)) return 0;
174
- let installed = 0;
175
- for (const agent of AGENTS) {
176
- const dir = resolve(cwd, agent.skill.project);
177
- if (installFile(skillSrc, dir, "SKILL.md")) {
178
- installed++;
179
- }
180
- }
181
- return installed;
182
- }
183
- function printSkillUsage() {
184
- console.log(`
185
- flowbook skill \u2014 Install AI agent skill & /flowbook command
186
-
187
- Usage:
188
- flowbook skill <agent> Install to project
189
- flowbook skill <agent> --global Install globally
190
- flowbook skill <agent> -g Install globally (short)
191
-
192
- Agents:
193
- all All supported agents
194
- claude Claude Code
195
- codex OpenAI Codex
196
- copilot VS Code / GitHub Copilot
197
- antigravity Google Antigravity
198
- gemini Gemini CLI
199
- cursor Cursor
200
- windsurf Windsurf (Codeium)
201
- amp AmpCode
202
- opencode OpenCode / oh-my-opencode
203
-
204
- Examples:
205
- flowbook skill all Install to all agents (project)
206
- flowbook skill opencode -g Install globally for OpenCode
207
- flowbook skill claude --global Install globally for Claude Code
208
- `);
209
- }
210
-
211
- // src/node/init.ts
212
7
  var EXAMPLE_FLOW = `---
213
8
  title: Example Flow
214
9
  category: Getting Started
@@ -228,8 +23,8 @@ flowchart TD
228
23
  `;
229
24
  async function initFlowbook() {
230
25
  const cwd = process.cwd();
231
- const pkgPath = resolve2(cwd, "package.json");
232
- if (!existsSync2(pkgPath)) {
26
+ const pkgPath = resolve(cwd, "package.json");
27
+ if (!existsSync(pkgPath)) {
233
28
  console.error(" No package.json found. Run 'npm init' first.");
234
29
  process.exit(1);
235
30
  }
@@ -260,40 +55,35 @@ async function initFlowbook() {
260
55
  } else {
261
56
  console.log(" \u2713 Scripts already exist in package.json");
262
57
  }
263
- const flowsDir = resolve2(cwd, "flows");
264
- const examplePath = resolve2(flowsDir, "example.flow.md");
265
- if (!existsSync2(examplePath)) {
266
- mkdirSync2(flowsDir, { recursive: true });
58
+ const flowsDir = resolve(cwd, "flows");
59
+ const examplePath = resolve(flowsDir, "example.flow.md");
60
+ if (!existsSync(examplePath)) {
61
+ mkdirSync(flowsDir, { recursive: true });
267
62
  writeFileSync(examplePath, EXAMPLE_FLOW);
268
63
  console.log(" \u2713 Created flows/example.flow.md");
269
64
  } else {
270
65
  console.log(" \u2713 Example flow already exists");
271
66
  }
272
- const gitignorePath = resolve2(cwd, ".gitignore");
273
- if (existsSync2(gitignorePath)) {
67
+ const gitignorePath = resolve(cwd, ".gitignore");
68
+ if (existsSync(gitignorePath)) {
274
69
  const gitignore = readFileSync(gitignorePath, "utf-8");
275
70
  if (!gitignore.includes("flowbook-static")) {
276
71
  writeFileSync(gitignorePath, gitignore.trimEnd() + "\nflowbook-static\n");
277
72
  console.log(" \u2713 Added flowbook-static to .gitignore");
278
73
  }
279
74
  }
280
- const installed = installAllProjectSkills();
281
- if (installed > 0) {
282
- console.log(` \u2713 Installed AI agent skill to ${installed} agent directories`);
283
- } else {
284
- console.log(" \u2713 AI agent skills already installed");
285
- }
286
75
  const run = pm === "yarn" ? "yarn" : `${pm} run`;
287
76
  console.log("");
288
77
  console.log(" Next steps:");
289
- console.log(` ${run} flowbook Start the dev server`);
290
- 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`);
291
81
  console.log("");
292
82
  }
293
83
  function detectPackageManager(cwd) {
294
- if (existsSync2(resolve2(cwd, "bun.lockb")) || existsSync2(resolve2(cwd, "bun.lock"))) return "bun";
295
- if (existsSync2(resolve2(cwd, "pnpm-lock.yaml"))) return "pnpm";
296
- if (existsSync2(resolve2(cwd, "yarn.lock"))) return "yarn";
84
+ if (existsSync(resolve(cwd, "bun.lockb")) || existsSync(resolve(cwd, "bun.lock"))) return "bun";
85
+ if (existsSync(resolve(cwd, "pnpm-lock.yaml"))) return "pnpm";
86
+ if (existsSync(resolve(cwd, "yarn.lock"))) return "yarn";
297
87
  return "npm";
298
88
  }
299
89
  function getInstallCommand(pm) {
@@ -400,11 +190,11 @@ function flowbookPlugin(options = {}) {
400
190
  }
401
191
 
402
192
  // src/node/server.ts
403
- import { resolve as resolve3, dirname as dirname2 } from "path";
404
- import { fileURLToPath as fileURLToPath2 } from "url";
405
- 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));
406
196
  function getClientDir() {
407
- return resolve3(__dirname2, "..", "src", "client");
197
+ return resolve2(__dirname, "..", "src", "client");
408
198
  }
409
199
  function createConfig(options) {
410
200
  const cwd = options.cwd ?? process.cwd();
@@ -425,7 +215,7 @@ function createConfig(options) {
425
215
  port: options.port ?? 6200
426
216
  },
427
217
  build: {
428
- outDir: resolve3(cwd, options.outDir ?? "flowbook-static"),
218
+ outDir: resolve2(cwd, options.outDir ?? "flowbook-static"),
429
219
  emptyOutDir: true
430
220
  }
431
221
  };
@@ -444,6 +234,196 @@ async function buildStatic(options) {
444
234
  `);
445
235
  }
446
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
+
447
427
  // src/node/cli.ts
448
428
  async function main() {
449
429
  const args = process.argv.slice(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flowbook",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "flowbook": "./dist/cli.js"
package/src/node/init.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
3
  import { execSync } from "node:child_process";
4
- import { installAllProjectSkills } from "./skill";
5
4
 
6
5
 
7
6
  const EXAMPLE_FLOW = `---
@@ -87,19 +86,12 @@ export async function initFlowbook() {
87
86
  }
88
87
  }
89
88
 
90
- // 5. Install AI agent skill to all supported agent directories
91
- const installed = installAllProjectSkills();
92
- if (installed > 0) {
93
- console.log(` ✓ Installed AI agent skill to ${installed} agent directories`);
94
- } else {
95
- console.log(" ✓ AI agent skills already installed");
96
- }
97
-
98
89
  const run = pm === "yarn" ? "yarn" : `${pm} run`;
99
90
  console.log("");
100
91
  console.log(" Next steps:");
101
- console.log(` ${run} flowbook Start the dev server`);
102
- 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`);
103
95
  console.log("");
104
96
  }
105
97