@relipa/ai-flow-kit 0.0.6-beta.0 → 0.0.7-beta.0

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.
Files changed (40) hide show
  1. package/README.md +33 -13
  2. package/bin/aiflow.js +58 -2
  3. package/custom/mcp-presets/gitnexus.json +8 -0
  4. package/custom/rules/java/spring-boot-examples.md +329 -329
  5. package/custom/skills/generate-spec/SKILL.md +7 -0
  6. package/custom/skills/impact-analysis/SKILL.md +10 -0
  7. package/custom/skills/read-study-requirement/SKILL.md +11 -0
  8. package/custom/skills/review-plan/SKILL.md +15 -0
  9. package/custom/templates/spring-boot.md +224 -224
  10. package/docs/common/AIFLOW.md +12 -6
  11. package/docs/common/CHANGELOG.md +49 -5
  12. package/docs/common/QUICK_START.md +13 -11
  13. package/docs/common/cli-reference.md +23 -0
  14. package/package.json +2 -7
  15. package/scripts/checkpoint.js +46 -0
  16. package/scripts/doctor.js +192 -89
  17. package/scripts/gitnexus-worker.js +94 -0
  18. package/scripts/guide.js +42 -51
  19. package/scripts/hooks/session-start.js +274 -244
  20. package/scripts/hooks/session-stop.js +55 -0
  21. package/scripts/init.js +293 -18
  22. package/scripts/prompt.js +2 -2
  23. package/scripts/remove.js +54 -0
  24. package/scripts/task.js +446 -384
  25. package/scripts/update.js +14 -4
  26. package/scripts/use.js +41 -0
  27. package/upstream/.claude-plugin/marketplace.json +4 -4
  28. package/upstream/.claude-plugin/plugin.json +2 -4
  29. package/upstream/.cursor-plugin/plugin.json +2 -4
  30. package/upstream/docs/plans/2025-11-22-opencode-support-design.md +1 -1
  31. package/upstream/docs/plans/2025-11-28-skills-improvements-from-user-feedback.md +2 -2
  32. package/upstream/docs/testing.md +2 -2
  33. package/upstream/skills/subagent-driven-development/SKILL.md +5 -6
  34. package/upstream/skills/subagent-driven-development/implementer-prompt.md +2 -3
  35. package/upstream/skills/systematic-debugging/CREATION-LOG.md +1 -1
  36. package/upstream/skills/systematic-debugging/root-cause-tracing.md +1 -1
  37. package/upstream/skills/tdd-lean/SKILL.md +127 -0
  38. package/upstream/skills/using-git-worktrees/SKILL.md +4 -5
  39. package/upstream/skills/writing-plans/SKILL.md +3 -9
  40. package/upstream/tests/brainstorm-server/package-lock.json +36 -0
@@ -1,15 +1,42 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to **@relipa/ai-flow-kit** will be documented in this file.
3
+ All notable changes to **ai-flow-kit** will be documented in this file.
4
4
 
5
5
  Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
6
  Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ---
9
9
 
10
+ ## [0.0.7] - 2026-05-07
11
+
12
+ ### Added
13
+
14
+ - **Intelligent AI Instruction Synchronization** — Marker-based (`<!-- aiflow-kit-start -->`) block updates for `CLAUDE.md`, `GEMINI.md`, and `.cursorrules`.
15
+ - **Interactive Instruction Safety** — Granular confirmation prompts for all instruction file modifications (update block, overwrite, or create new).
16
+ - **Automated Repository Hygiene** — Generated files and folders (`.aiflow/`, `plan/`, `.claude/`, `.rules/`, `.mcp.json`, and instruction files) are now automatically managed in `.gitignore`.
17
+ - **`aiflow sync-skills` command** — Lightweight command to synchronize Skill Registry and Instruction files without a full version upgrade.
18
+ - **Enhanced `aiflow guide --flow`** — Now dynamically displays the `## Workflow Overview` section directly from `AIFLOW.md` for up-to-date documentation.
19
+ - **Token savings dashboard in `aiflow doctor`** — new "Token savings" section shows RTK status and estimated 60–90% reduction on bash outputs.
20
+
21
+ ### Changed
22
+
23
+ - **`aiflow update` efficiency** — Now automatically performs skill and instruction synchronization even if the version is unchanged (removes the need for `--force`).
24
+ - **Safety First Development** — Removed all automatic `git commit` instructions from AI skills (`subagent-driven-development`, `using-git-worktrees`, `writing-plans`) to ensure developer-led commit management.
25
+ - **Localized CLI** — All interactive prompts and confirmation messages translated to English for consistency.
26
+ - **`aiflow init` RTK entry** — flag description updated to clarify RTK saves bash output tokens (60–90%).
27
+ - **`aiflow doctor`** — RTK section merged into new "Token savings" section.
28
+ - **README.md / QUICK_START.md** — Updated to reflect `sync-skills` and improved update flow.
29
+
30
+ ### Fixed
31
+
32
+ - Fixed `.github/copilot-instructions.md` not being included in automated `.gitignore` rules.
33
+
34
+ ---
35
+
10
36
  ## [0.0.6] - 2026-04-29
11
37
 
12
38
  ### Added
39
+
13
40
  - **Global Fast Mode (Default)** — Optimize AI efficiency by prioritizing speed and minimizing token usage.
14
41
  - Gate 1: Fast track scan with max 1 clarifying question.
15
42
  - Gate 3: Disable subagents by default; implement all tasks in a single session.
@@ -25,6 +52,7 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
25
52
  - **Spring Boot code examples extracted** — Java code examples moved to separate files to reduce `CLAUDE.md` size.
26
53
 
27
54
  ### Changed
55
+
28
56
  - **Default mode** for all new tasks is now `fast` instead of `auto`.
29
57
  - **`aiflow init` improvements** — Supports multi-select framework and protects existing instruction files from being overwritten.
30
58
  - **CLAUDE.md Optimization** — Reduced Spring Boot template size by ~70%, saving ~3-5k tokens per session.
@@ -32,18 +60,20 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
32
60
  - **Automatic Task Pausing** — When loading a new ticket, the current task is automatically paused and its state is saved.
33
61
 
34
62
  ### Fixed
35
- - Broken 404 documentation links on the npmjs.com page.
36
63
 
64
+ - Broken 404 documentation links on the npmjs.com page.
37
65
 
38
66
  ---
39
67
 
40
68
  ## [0.0.4-beta.5] - 2026-04-21
41
69
 
42
70
  ### Added
71
+
43
72
  - Created a dedicated `docs/` folder to house all developer-facing documentation.
44
73
  - Integrated AI Skill Registry into all tool templates (Claude, Cursor, Gemini, Copilot) for better skill discovery.
45
74
 
46
75
  ### Changed
76
+
47
77
  - Moved `README.md`, `QUICK_START.md`, `AIFLOW.md`, `CHANGELOG.md`, and `IMPLEMENTATION_SUMMARY.md` into the `docs/` directory.
48
78
  - Updated `package.json` to exclude internal-only files (`CONTRIBUTING.md`, `plan.md`) from the NPM package distribution.
49
79
  - Updated `scripts/init.js` to source documentation from the new `docs/` location.
@@ -54,11 +84,13 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
54
84
  ## [0.0.5-beta.0] - 2026-04-23
55
85
 
56
86
  ### Added
87
+
57
88
  - **`aiflow gate <n> <action>` command** — Called automatically by AI during gate transitions. Supports `start` and `approved` actions for gates 1-5. Options: `--ticket <id>`, `--ai-tool <tool>`.
58
89
  - **Telemetry gate logging** — Gate workflow templates now emit `aiflow gate N start/approved --ticket [id]` telemetry calls at each gate transition for usage metrics.
59
90
  - **`aiflow telemetry flush` command** — Force-sends buffered telemetry events immediately.
60
91
 
61
92
  ### Changed
93
+
62
94
  - **`aiflow init` safe overwrite flow** — When a project already has `CLAUDE.md`, `GEMINI.md`, `.cursorrules`, etc., `aiflow init` now prompts before overwriting:
63
95
  - **No (default):** keeps existing file untouched; saves the aiflow template to `.aiflow/reference/<file>` for manual comparison/merge.
64
96
  - **Yes:** backs up the existing file to `.aiflow/backup/<file>` before overwriting — nothing is permanently lost.
@@ -73,7 +105,8 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
73
105
  ## [0.0.5] - 2026-04-23
74
106
 
75
107
  ### Added
76
- - **Telemetry System (MVP)**: Added anonymous usage tracking to measure command metrics and user adoption.
108
+
109
+ - **Telemetry System (MVP)**: Added anonymous usage tracking to measure command metrics and user adoption.
77
110
  - `aiflow telemetry enable/disable/status` commands to easily opt-in or opt-out.
78
111
  - Automatically captures environment metadata and Git email via `git config --global user.email`.
79
112
  - Secure payload signing natively using Node `crypto` HMAC-SHA256 to ensure data authenticity.
@@ -81,6 +114,7 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
81
114
  - Support tracking for multiple AI platforms including Cursor and Gemini via Command Execution events and the new Telemetry SDK.
82
115
 
83
116
  ### Security
117
+
84
118
  - **Strict Privacy**: Explicitly removed all prompt content and chat history tracking to ensure 100% confidentiality of company code and PII.
85
119
 
86
120
  ---
@@ -88,14 +122,18 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
88
122
  ## [Unreleased]
89
123
 
90
124
  ## [0.0.3-beta.0] - 2026-04-13
125
+
91
126
  ### Security
127
+
92
128
  - Removed internal GitLab repository links and tracking information.
93
129
  - Cleaned `.npmrc` configuration.
94
130
  - Added helper scripts for beta and stable releases.
95
131
 
96
132
  ## [0.0.2] - 2026-04-13
133
+
97
134
  ### Changed
98
- - Updated package to scoped name `@relipa/ai-flow-kit` in documentation and configuration.
135
+
136
+ - Updated package name in documentation and configuration.
99
137
  - Fixed installation guides in README and QUICK_START.
100
138
 
101
139
  ## [0.0.1] - 2026-04-13 — Initial Release
@@ -103,6 +141,7 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
103
141
  ### Added
104
142
 
105
143
  #### CLI (`aiflow`)
144
+
106
145
  - `aiflow init` — scaffold AI workflow config into any project
107
146
  (supports `--framework` spring-boot/reactjs, `--adapter` jira/backlog)
108
147
  - `aiflow use <skill>` — activate a custom skill in the current project
@@ -113,6 +152,7 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
113
152
  - `aiflow --version` — print installed version
114
153
 
115
154
  #### 5-Gate AI Workflow
155
+
116
156
  - **Gate 1 — AI Analyze Requirement**: Auto-starts when a ticket context exists
117
157
  in `.aiflow/context/current.json`; outputs `plan/[ticket-id]/requirement.md`
118
158
  - **Gate 2 — Implementation Plan**: TDD plan generation, gated by `APPROVED`
@@ -121,6 +161,7 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
121
161
  - **Gate 5 — Peer Review & PR**: Guided PR creation via `requesting-code-review` skill
122
162
 
123
163
  #### Custom Skills (7 skills)
164
+
124
165
  - `read-study-requirement` — Gate 1 requirement analysis with clarifying Q&A loop
125
166
  - `generate-spec` — Gate 2 TDD implementation spec generator
126
167
  - `impact-analysis` — breaking-change and dependency impact assessment
@@ -130,17 +171,20 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
130
171
  - `figma-to-component` — Figma design → UI component code generator
131
172
 
132
173
  #### Multi-AI Support
174
+
133
175
  - **Claude Code** integration via `CLAUDE.md` + `.claude/` directory structure
134
176
  - **Gemini CLI** integration via `GEMINI.md`
135
177
  - **GitHub Copilot** integration via agents config
136
178
  - Superpowers skill library bundled as `upstream/` (pinned to v5.0.5)
137
179
 
138
180
  #### Project Templates
181
+
139
182
  - `AIFLOW.md` — team workflow reference document
140
183
  - `QUICK_START.md` — 5-minute setup guide
141
184
  - `.aiflowrc.json.example` — configuration file reference
142
185
 
143
186
  ### Architecture Notes
187
+
144
188
  - Stateless per-ticket design — no persistent memory across sessions (planned: v0.1.x)
145
189
  - Manual skill sync model via `aiflow use` (managed `aiflow skill` CLI planned: v0.1.x)
146
190
  - Spring Boot (Java 17+) used as the reference framework in `CLAUDE.md` coding rules
@@ -150,7 +194,7 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
150
194
  ## How to upgrade
151
195
 
152
196
  ```bash
153
- npm install -g @relipa/ai-flow-kit@latest
197
+ npm install -g ai-flow-kit@latest
154
198
  aiflow --version
155
199
  ```
156
200
 
@@ -7,17 +7,16 @@
7
7
  ## Installation
8
8
 
9
9
  ```bash
10
- # Stable version
11
- npm install -g @relipa/ai-flow-kit
10
+ npm install -g ai-flow-kit
12
11
 
13
12
  # Beta version (recommend for newest features)
14
- npm install -g @relipa/ai-flow-kit@beta
13
+ npm install -g ai-flow-kit@beta
15
14
 
16
15
  # Verification
17
16
  aiflow --version
18
17
 
19
18
  # Uninstall
20
- npm uninstall -g @relipa/ai-flow-kit
19
+ npm uninstall -g ai-flow-kit
21
20
  ```
22
21
 
23
22
  ---
@@ -146,7 +145,7 @@ APPROVED
146
145
 
147
146
  AI outputs:
148
147
  - TDD task breakdown (test first → implement → verify)
149
- - Commit strategy (small, focused commits)
148
+ - Verification strategy (evidence before claims)
150
149
  - Test commands
151
150
 
152
151
  **Your action:**
@@ -166,7 +165,7 @@ APPROVED
166
165
 
167
166
  - Writes tests FIRST → runs → confirms FAIL
168
167
  - Implements code → tests PASS
169
- - Commits each small step
168
+ - Verifies implementation works
170
169
 
171
170
  **Your action:** Monitor. No action needed unless AI asks a question.
172
171
 
@@ -256,7 +255,7 @@ Developer AI Peer
256
255
  │ "APPROVED" ──────────────────►│ │
257
256
  │ │ │
258
257
  │ GATE 3 │ Write tests → implement │
259
- │ (monitor) │ Commit each step
258
+ │ (monitor) │ Verify implementation works
260
259
  │ │ │
261
260
  │ ─── GATE 4 ──────────────────►│ │
262
261
  │ │ Self-review + summary │
@@ -317,10 +316,13 @@ claude # AI auto-starts: map dependencies → ass
317
316
  ```bash
318
317
  # Setup
319
318
  aiflow init --framework nestjs --adapter backlog
320
- aiflow init --framework spring-boot --with-rtk # force enable RTK compression
321
- aiflow init --no-rtk # skip RTK setup
319
+ aiflow init --framework spring-boot --with-rtk # RTK: bash output compression (60–90%)
320
+ # aiflow init --framework spring-boot --with-gitnexus # GitNexus: waits for index to complete
321
+ # aiflow init --framework spring-boot --with-gitnexus --no-wait # GitNexus: index in background
322
+ aiflow init --no-rtk # skip RTK setup
322
323
  aiflow doctor # health check
323
324
  aiflow guide # multi-tool guide
325
+ aiflow sync-skills # manually sync AI instruction files
324
326
 
325
327
  # Per task
326
328
  aiflow use PROJ-33 # load context (Fast Mode, default)
@@ -366,7 +368,7 @@ aiflow guide --commands # command reference
366
368
  aiflow remove # remove from project
367
369
  aiflow remove --global # uninstall globally (npm uninstall -g)
368
370
  aiflow remove --version 1.0.0 # remove cached version from .aiflow/
369
- npm uninstall -g @relipa/ai-flow-kit # standard npm uninstall
371
+ npm uninstall -g ai-flow-kit # standard npm uninstall
370
372
  ```
371
373
 
372
374
  ---
@@ -405,7 +407,7 @@ aiflow guide
405
407
 
406
408
  **`aiflow` not found:**
407
409
  ```bash
408
- npm install -g @relipa/ai-flow-kit
410
+ npm install -g ai-flow-kit
409
411
  ```
410
412
 
411
413
  **Incorrect credentials:**
@@ -399,6 +399,29 @@ You can switch back with: aiflow use 1.0.0
399
399
  ✨ Update completed!
400
400
  ```
401
401
 
402
+ ## sync-skills
403
+
404
+ Manually synchronize AI Instruction files with local custom skills.
405
+
406
+ ```bash
407
+ # Sync AI Instruction files
408
+ aiflow sync-skills
409
+ ```
410
+
411
+ **What it does:**
412
+ 1. Reads all active local skills and upstream skills
413
+ 2. Generates the updated AI Skill Registry table
414
+ 3. Safely updates the AI Instruction blocks (`<!-- aiflow-kit-start -->`) in your project's `CLAUDE.md`, `GEMINI.md`, or `.cursorrules` without wiping your custom rules
415
+ 4. If no marker blocks are found, it asks for confirmation to overwrite with the correct structure
416
+
417
+ **Example:**
418
+ ```bash
419
+ $ aiflow sync-skills
420
+ ⟳ Syncing AI Instruction files...
421
+ ✓ Updated AI Flow block in CLAUDE.md
422
+ ✨ Sync completed!
423
+ ```
424
+
402
425
  ## doctor
403
426
 
404
427
  Health check for your setup.
package/package.json CHANGED
@@ -1,13 +1,8 @@
1
1
  {
2
2
  "name": "@relipa/ai-flow-kit",
3
- "version": "0.0.6-beta.0",
3
+ "version": "0.0.7-beta.0",
4
4
  "description": "All-in-one AI Flow Kit for team development with Claude AI - skills, templates, and MCP adapters",
5
- "author": "Relipa AI Team",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://gitlab.relipa.vn/ai/ai-flow-kit.git"
9
- },
10
- "homepage": "https://gitlab.relipa.vn/ai/ai-flow-kit#readme",
5
+ "author": "Example Team",
11
6
  "publishConfig": {
12
7
  "access": "public",
13
8
  "registry": "https://registry.npmjs.com/"
@@ -0,0 +1,46 @@
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+
5
+ const PROJECT_DIR = process.cwd();
6
+ const AIFLOW_DIR = path.join(PROJECT_DIR, '.aiflow');
7
+ const CONTEXT_FILE = path.join(AIFLOW_DIR, 'context', 'current.json');
8
+
9
+ const GATE_LABELS = { 1: 'Analyze', 2: 'Plan', 3: 'Code', 4: 'Review', 5: 'PR' };
10
+
11
+ module.exports = async function checkpoint(options = {}) {
12
+ const { gate, step, tokens, ticket: ticketOpt } = options;
13
+
14
+ if (!gate || !step || tokens === undefined) {
15
+ console.log(chalk.yellow('Usage: aiflow checkpoint --gate <N> --step <name> --tokens <N>'));
16
+ console.log(chalk.gray(' Example: aiflow checkpoint --gate 3 --step "tests-written" --tokens 3200'));
17
+ return;
18
+ }
19
+
20
+ // Resolve ticket ID
21
+ let ticketId = ticketOpt;
22
+ if (!ticketId) {
23
+ const ctx = await fs.readJson(CONTEXT_FILE).catch(() => null);
24
+ ticketId = ctx && ctx.taskId ? ctx.taskId : 'unknown';
25
+ }
26
+
27
+ const taskDir = path.join(AIFLOW_DIR, 'tasks', ticketId);
28
+ await fs.ensureDir(taskDir);
29
+
30
+ const checkpointPath = path.join(taskDir, 'checkpoints.json');
31
+ const existing = (await fs.pathExists(checkpointPath))
32
+ ? await fs.readJson(checkpointPath).catch(() => ({ checkpoints: [] }))
33
+ : { checkpoints: [] };
34
+
35
+ const entry = {
36
+ gate: parseInt(gate),
37
+ step,
38
+ tokens: parseInt(tokens),
39
+ timestamp: new Date().toISOString(),
40
+ };
41
+ existing.checkpoints.push(entry);
42
+ await fs.writeJson(checkpointPath, existing, { spaces: 2 });
43
+
44
+ const label = GATE_LABELS[parseInt(gate)] || `Gate ${gate}`;
45
+ console.log(chalk.green(`✓ Checkpoint: Gate ${gate} (${label}) — ${step} — ~${parseInt(tokens).toLocaleString()} tokens`));
46
+ };
package/scripts/doctor.js CHANGED
@@ -1,89 +1,192 @@
1
- const fs = require('fs-extra');
2
- const path = require('path');
3
- const chalk = require('chalk');
4
- const { detectRtk, isRtkHookConfigured } = require('./init');
5
-
6
- module.exports = async function doctor() {
7
- const projectDir = process.cwd();
8
- const errors = [];
9
- const warnings = [];
10
-
11
- console.log(chalk.blue('Running health check for AI Flow Kit...\n'));
12
-
13
- // ── Core setup ─────────────────────────────────────────────
14
- if (!(await fs.pathExists(path.join(projectDir, '.claude', 'skills')))) {
15
- errors.push('Missing `.claude/skills` directory. Did you run `aiflow init`?');
16
- } else {
17
- console.log(chalk.green('.claude/skills exists'));
18
- }
19
-
20
- if (!(await fs.pathExists(path.join(projectDir, '.rules')))) {
21
- errors.push('Missing `.rules` directory.');
22
- } else {
23
- console.log(chalk.green('✓ .rules exists'));
24
- }
25
-
26
- if (!(await fs.pathExists(path.join(projectDir, 'CLAUDE.md')))) {
27
- errors.push('Missing CLAUDE.md. AI context prompt is not set up.');
28
- } else {
29
- console.log(chalk.green('✓ CLAUDE.md exists'));
30
- }
31
-
32
- // ── Version tracking ───────────────────────────────────────
33
- const stateFile = path.join(projectDir, '.aiflow', 'state.json');
34
- if (!(await fs.pathExists(stateFile))) {
35
- errors.push('Missing `.aiflow/state.json`. Version tracking is broken.');
36
- } else {
37
- const state = await fs.readJson(stateFile);
38
- console.log(chalk.green(`✓ Version tracking active (v${state.current_version})`));
39
- }
40
-
41
- // ── SessionStart hook ──────────────────────────────────────
42
- const settingsPath = path.join(projectDir, '.claude', 'settings.json');
43
- if (await fs.pathExists(settingsPath)) {
44
- const settings = await fs.readJson(settingsPath).catch(() => ({}));
45
- const hookList = settings?.hooks?.SessionStart || [];
46
- const hasSessionHook = hookList.some(h =>
47
- (h.hooks || []).some(e => typeof e.command === 'string' && e.command.includes('session-start'))
48
- );
49
- if (hasSessionHook) {
50
- console.log(chalk.green('✓ SessionStart hook configured'));
51
- } else {
52
- warnings.push('SessionStart hook not found in .claude/settings.json — run `aiflow init` to set it up.');
53
- }
54
- } else {
55
- warnings.push('Missing .claude/settings.json run `aiflow init`.');
56
- }
57
-
58
- // ── RTK token compression ──────────────────────────────────
59
- console.log('');
60
- const rtk = await detectRtk();
61
- if (rtk.installed) {
62
- const hookOk = await isRtkHookConfigured(projectDir);
63
- if (hookOk) {
64
- console.log(chalk.green(`✓ RTK installed (${rtk.version}) — token compression active`));
65
- } else {
66
- console.log(chalk.green(`✓ RTK installed (${rtk.version})`));
67
- warnings.push('RTK is installed but hook not configured. Run `aiflow init` to enable token compression.');
68
- }
69
- } else {
70
- console.log(chalk.gray(' RTK not installed (optional) — token compression inactive'));
71
- console.log(chalk.gray(' Install: cargo install rtk | More: https://github.com/rtk-ai/rtk'));
72
- }
73
-
74
- // ── Summary ────────────────────────────────────────────────
75
- console.log('');
76
- if (warnings.length > 0) {
77
- console.log(chalk.yellow('Warnings:'));
78
- warnings.forEach(w => console.log(chalk.yellow(` ⚠ ${w}`)));
79
- console.log('');
80
- }
81
-
82
- if (errors.length > 0) {
83
- console.log(chalk.red('Issues found:'));
84
- errors.forEach(e => console.log(chalk.red(` ✗ ${e}`)));
85
- console.log(chalk.yellow('\nTry running `aiflow init` or `aiflow update` to fix these files.'));
86
- } else {
87
- console.log(chalk.green('✨ Everything looks healthy! You are ready to fly.'));
88
- }
89
- };
1
+ const fs = require('fs-extra');
2
+ const path = require('path');
3
+ const chalk = require('chalk');
4
+ const { detectRtk, isRtkHookConfigured, isGitNexusConfigured } = require('./init');
5
+
6
+ function formatAgo(isoString) {
7
+ const ms = Date.now() - new Date(isoString).getTime();
8
+ const mins = Math.floor(ms / 60000);
9
+ if (mins < 1) return 'just now';
10
+ if (mins < 60) return `${mins}m ago`;
11
+ const hrs = Math.floor(mins / 60);
12
+ if (hrs < 24) return `${hrs}h ago`;
13
+ return `${Math.floor(hrs / 24)}d ago`;
14
+ }
15
+
16
+ async function showTokenBreakdown(ticketId) {
17
+ const tasksDir = path.join(process.cwd(), '.aiflow', 'tasks');
18
+ const checkpointsFile = path.join(tasksDir, ticketId, 'checkpoints.json');
19
+ if (!(await fs.pathExists(checkpointsFile))) return;
20
+
21
+ const data = await fs.readJson(checkpointsFile).catch(() => ({ checkpoints: [] }));
22
+ if (!data.checkpoints || data.checkpoints.length === 0) return;
23
+
24
+ // Aggregate tokens per gate (taking the max/latest)
25
+ const gateTokens = {};
26
+ for (const cp of data.checkpoints) {
27
+ if (!gateTokens[cp.gate] || cp.tokens > gateTokens[cp.gate]) {
28
+ gateTokens[cp.gate] = cp.tokens;
29
+ }
30
+ }
31
+
32
+ const GATE_LABELS = { 1: 'Analyze', 2: 'Plan', 3: 'Code', 4: 'Review', 5: 'PR' };
33
+ const gates = Object.keys(gateTokens).sort();
34
+ const total = gates.reduce((sum, g) => sum + gateTokens[g], 0);
35
+
36
+ console.log('');
37
+ console.log(chalk.bold(`Token usage for task ${ticketId}:`));
38
+ for (const g of gates) {
39
+ const label = GATE_LABELS[parseInt(g)] || `Gate ${g}`;
40
+ const t = gateTokens[g];
41
+ const bar = '█'.repeat(Math.round((t / total) * 20)).padEnd(20, '░');
42
+ const pct = Math.round((t / total) * 100);
43
+ console.log(` Gate ${g} ${label.padEnd(8)} ~${t.toLocaleString().padStart(6)} ${chalk.gray(bar)} ${pct}%`);
44
+ }
45
+ console.log(` Total estimated: ~${total.toLocaleString()} tokens`);
46
+ }
47
+
48
+ module.exports = async function doctor(options = {}) {
49
+ const projectDir = process.cwd();
50
+ const errors = [];
51
+ const warnings = [];
52
+
53
+ console.log(chalk.blue('Running health check for AI Flow Kit...\n'));
54
+
55
+ // ── Token breakdown ────────────────────────────────────────
56
+ let ticketId = options.ticket;
57
+ if (!ticketId) {
58
+ const contextFile = path.join(projectDir, '.aiflow', 'context', 'current.json');
59
+ if (await fs.pathExists(contextFile)) {
60
+ const ctx = await fs.readJson(contextFile).catch(() => ({}));
61
+ ticketId = ctx.taskId;
62
+ }
63
+ }
64
+
65
+ if (ticketId) {
66
+ await showTokenBreakdown(ticketId);
67
+ }
68
+
69
+ // ── Core setup ─────────────────────────────────────────────
70
+ if (!(await fs.pathExists(path.join(projectDir, '.claude', 'skills')))) {
71
+ errors.push('Missing `.claude/skills` directory. Did you run `aiflow init`?');
72
+ } else {
73
+ console.log(chalk.green('✓ .claude/skills exists'));
74
+ }
75
+
76
+ if (!(await fs.pathExists(path.join(projectDir, '.rules')))) {
77
+ errors.push('Missing `.rules` directory.');
78
+ } else {
79
+ console.log(chalk.green('✓ .rules exists'));
80
+ }
81
+
82
+ if (!(await fs.pathExists(path.join(projectDir, 'CLAUDE.md')))) {
83
+ errors.push('Missing CLAUDE.md. AI context prompt is not set up.');
84
+ } else {
85
+ console.log(chalk.green(' CLAUDE.md exists'));
86
+ }
87
+
88
+ // ── Version tracking ───────────────────────────────────────
89
+ const stateFile = path.join(projectDir, '.aiflow', 'state.json');
90
+ if (!(await fs.pathExists(stateFile))) {
91
+ errors.push('Missing `.aiflow/state.json`. Version tracking is broken.');
92
+ } else {
93
+ const state = await fs.readJson(stateFile);
94
+ console.log(chalk.green(`✓ Version tracking active (v${state.current_version})`));
95
+ }
96
+
97
+ // ── SessionStart hook ──────────────────────────────────────
98
+ const settingsPath = path.join(projectDir, '.claude', 'settings.json');
99
+ if (await fs.pathExists(settingsPath)) {
100
+ const settings = await fs.readJson(settingsPath).catch(() => ({}));
101
+ const hookList = settings?.hooks?.SessionStart || [];
102
+ const hasSessionHook = hookList.some(h =>
103
+ (h.hooks || []).some(e => typeof e.command === 'string' && e.command.includes('session-start'))
104
+ );
105
+ if (hasSessionHook) {
106
+ console.log(chalk.green('✓ SessionStart hook configured'));
107
+ } else {
108
+ warnings.push('SessionStart hook not found in .claude/settings.json — run `aiflow init` to set it up.');
109
+ }
110
+ } else {
111
+ warnings.push('Missing .claude/settings.json — run `aiflow init`.');
112
+ }
113
+
114
+ // ── Token savings tools ────────────────────────────────────
115
+ console.log('');
116
+ console.log(chalk.bold('Token savings:'));
117
+
118
+ // RTK
119
+ const rtk = await detectRtk();
120
+ if (rtk.installed) {
121
+ const hookOk = await isRtkHookConfigured(projectDir);
122
+ if (hookOk) {
123
+ console.log(chalk.green(` ✓ RTK (${rtk.version}) — bash output compression active`));
124
+ console.log(chalk.gray(' Estimated: 60–90% reduction on bash command outputs (test runs, git, npm...)'));
125
+ } else {
126
+ console.log(chalk.yellow(` ⚠ RTK installed (${rtk.version}) but hook not configured`));
127
+ warnings.push('RTK hook not configured. Run `aiflow init` to enable token compression.');
128
+ }
129
+ } else {
130
+ console.log(chalk.gray(' ○ RTK not installed — bash output compression inactive'));
131
+ console.log(chalk.gray(' Install: cargo install rtk | Enable: aiflow init --with-rtk'));
132
+ }
133
+
134
+ // GitNexus
135
+ const gnConfigured = await isGitNexusConfigured(projectDir);
136
+ const gnStatusPath = path.join(projectDir, '.aiflow', 'gitnexus-status.json');
137
+ if (gnConfigured) {
138
+ let statusLine = chalk.green(' ✓ GitNexus MCP configured');
139
+ try {
140
+ if (await fs.pathExists(gnStatusPath)) {
141
+ const gn = await fs.readJson(gnStatusPath);
142
+ const GITNEXUS_STALE_MS = 3 * 60 * 60 * 1000; // 3 hours
143
+ if (gn.status === 'done') {
144
+ const ago = gn.completedAt
145
+ ? chalk.gray(` — indexed ${formatAgo(gn.completedAt)}`)
146
+ : '';
147
+ statusLine = chalk.green(` ✓ GitNexus MCP configured — index ready${ago}`);
148
+ console.log(statusLine);
149
+ console.log(chalk.gray(' Estimated: ~50% fewer tokens at Gate 1 (context queries vs file reads)'));
150
+ console.log(chalk.gray(' Estimated: ~70% fewer tokens at Gate 4 (impact() vs grep codebase)'));
151
+ } else if (gn.status === 'running') {
152
+ const age = Date.now() - new Date(gn.startedAt).getTime();
153
+ if (age > GITNEXUS_STALE_MS) {
154
+ console.log(chalk.red(' ✗ GitNexus MCP configured — indexing timed out (stale)'));
155
+ console.log(chalk.gray(` Started ${formatAgo(gn.startedAt)} but never finished. Process may have crashed.`));
156
+ // console.log(chalk.gray(' Retry: aiflow init --with-gitnexus --wait | Log: .aiflow/gitnexus-analyze.log'));
157
+ } else {
158
+ console.log(chalk.yellow(' ⟳ GitNexus MCP configured — indexing in progress...'));
159
+ console.log(chalk.gray(' Log: .aiflow/gitnexus-analyze.log'));
160
+ }
161
+ } else if (gn.status === 'error') {
162
+ console.log(chalk.red(' ✗ GitNexus MCP configured — last index failed'));
163
+ console.log(chalk.gray(' Retry: npx gitnexus analyze | Log: .aiflow/gitnexus-analyze.log'));
164
+ }
165
+ } else {
166
+ console.log(chalk.yellow(' ⚠ GitNexus MCP configured but not yet indexed'));
167
+ console.log(chalk.gray(' Run: npx gitnexus analyze'));
168
+ }
169
+ } catch (_) {
170
+ console.log(statusLine);
171
+ }
172
+ } else {
173
+ console.log(chalk.gray(' ○ GitNexus not configured — code intelligence inactive'));
174
+ // console.log(chalk.gray(' Enable: aiflow init --with-gitnexus'));
175
+ }
176
+
177
+ // ── Summary ────────────────────────────────────────────────
178
+ console.log('');
179
+ if (warnings.length > 0) {
180
+ console.log(chalk.yellow('Warnings:'));
181
+ warnings.forEach(w => console.log(chalk.yellow(` ⚠ ${w}`)));
182
+ console.log('');
183
+ }
184
+
185
+ if (errors.length > 0) {
186
+ console.log(chalk.red('Issues found:'));
187
+ errors.forEach(e => console.log(chalk.red(` ✗ ${e}`)));
188
+ console.log(chalk.yellow('\nTry running `aiflow init` or `aiflow update` to fix these files.'));
189
+ } else {
190
+ console.log(chalk.green('✨ Everything looks healthy! You are ready to fly.'));
191
+ }
192
+ };