@longph2102/v-flow 1.5.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 (247) hide show
  1. package/AGENTS.md +265 -0
  2. package/CHANGELOG.md +318 -0
  3. package/LICENSE +21 -0
  4. package/README.md +326 -0
  5. package/agents/ba-agent.md +437 -0
  6. package/agents/ba-critic-agent.md +156 -0
  7. package/agents/ba-to-ptyc-agent.md +112 -0
  8. package/agents/bugfix-analyst-agent.md +221 -0
  9. package/agents/constitute-agent.md +155 -0
  10. package/agents/help-agent.md +168 -0
  11. package/agents/implement-agent.md +220 -0
  12. package/agents/import-ba-docs-agent.md +164 -0
  13. package/agents/master-check-agent.md +228 -0
  14. package/agents/metrics-agent.md +180 -0
  15. package/agents/operations-agent.md +123 -0
  16. package/agents/plan-agent.md +218 -0
  17. package/agents/prototype-agent.md +191 -0
  18. package/agents/retrospective-agent.md +196 -0
  19. package/agents/review-agent.md +210 -0
  20. package/agents/sprint-agent.md +191 -0
  21. package/agents/status-agent.md +186 -0
  22. package/agents/sync-agent.md +201 -0
  23. package/agents/test-agent.md +166 -0
  24. package/agents/understand-agent.md +339 -0
  25. package/cli/commands/check.js +96 -0
  26. package/cli/commands/dev-quiz.js +107 -0
  27. package/cli/commands/doctor.js +348 -0
  28. package/cli/commands/feature.js +259 -0
  29. package/cli/commands/hooks.js +163 -0
  30. package/cli/commands/init.js +189 -0
  31. package/cli/commands/log.js +199 -0
  32. package/cli/commands/plugin.js +230 -0
  33. package/cli/commands/score-card.js +203 -0
  34. package/cli/commands/status.js +269 -0
  35. package/cli/commands/sync.js +59 -0
  36. package/cli/commands/upgrade.js +150 -0
  37. package/cli/commands/validate.js +1259 -0
  38. package/cli/commands/watch.js +151 -0
  39. package/cli/index.js +46 -0
  40. package/cli/lib/ac-test-gate.js +89 -0
  41. package/cli/lib/activity-log.js +209 -0
  42. package/cli/lib/cli-error.js +183 -0
  43. package/cli/lib/constitution-lint.js +561 -0
  44. package/cli/lib/dev-quiz-grade.js +127 -0
  45. package/cli/lib/governance.js +78 -0
  46. package/cli/lib/hook-targets.js +167 -0
  47. package/cli/lib/i18n.js +375 -0
  48. package/cli/lib/knowledge-oracle.js +379 -0
  49. package/cli/lib/logger.js +203 -0
  50. package/cli/lib/module-card-lint.js +304 -0
  51. package/cli/lib/module-card-score.js +223 -0
  52. package/cli/lib/plugins.js +481 -0
  53. package/cli/lib/scanner.js +692 -0
  54. package/cli/lib/sync-core.js +232 -0
  55. package/cli/lib/sync-targets.js +84 -0
  56. package/cli/lib/templates.js +268 -0
  57. package/cli/lib/yaml-parser.js +203 -0
  58. package/commands/v.ba-critic.md +101 -0
  59. package/commands/v.ba-to-ptyc.md +71 -0
  60. package/commands/v.bugfix.md +86 -0
  61. package/commands/v.check.md +131 -0
  62. package/commands/v.constitute.md +87 -0
  63. package/commands/v.constitution.md +84 -0
  64. package/commands/v.fork.md +127 -0
  65. package/commands/v.help.md +73 -0
  66. package/commands/v.hotfix.md +200 -0
  67. package/commands/v.implement.md +92 -0
  68. package/commands/v.import-ba-docs.md +222 -0
  69. package/commands/v.metrics.md +74 -0
  70. package/commands/v.operations.md +70 -0
  71. package/commands/v.plan.md +78 -0
  72. package/commands/v.prototype.md +121 -0
  73. package/commands/v.quickfix.md +169 -0
  74. package/commands/v.retrospective.md +80 -0
  75. package/commands/v.review.md +78 -0
  76. package/commands/v.rewind.md +127 -0
  77. package/commands/v.specify.md +118 -0
  78. package/commands/v.sprint.md +75 -0
  79. package/commands/v.status.md +62 -0
  80. package/commands/v.sync.md +81 -0
  81. package/commands/v.test.md +67 -0
  82. package/commands/v.understand.md +112 -0
  83. package/package.json +65 -0
  84. package/skills/_shared/constitution-reader/SKILL.md +109 -0
  85. package/skills/_shared/constitution-reader/config.json +52 -0
  86. package/skills/_shared/constitution-reader/examples/good/b1-phase-output.md +48 -0
  87. package/skills/_shared/constitution-reader/gotchas.md +46 -0
  88. package/skills/_shared/context-reader/SKILL.md +111 -0
  89. package/skills/_shared/context-reader/config.json +54 -0
  90. package/skills/_shared/context-reader/examples/good/legacy-nodejs-output.md +35 -0
  91. package/skills/_shared/context-reader/gotchas.md +49 -0
  92. package/skills/_shared/ears-notation/SKILL.md +63 -0
  93. package/skills/_shared/ears-notation/config.json +55 -0
  94. package/skills/_shared/ears-notation/examples/good/plan-test-interpretation.md +29 -0
  95. package/skills/_shared/ears-notation/gotchas.md +43 -0
  96. package/skills/check/cross-validator/SKILL.md +206 -0
  97. package/skills/check/cross-validator/config.json +33 -0
  98. package/skills/check/cross-validator/examples/good/validation-report-pass-with-concerns.md +105 -0
  99. package/skills/check/cross-validator/gotchas.md +43 -0
  100. package/skills/implement/constitution-enforcer/SKILL.md +134 -0
  101. package/skills/implement/constitution-enforcer/config.json +16 -0
  102. package/skills/implement/constitution-enforcer/examples/bad/vague-report.md +42 -0
  103. package/skills/implement/constitution-enforcer/examples/good/compliance-report.md +57 -0
  104. package/skills/implement/constitution-enforcer/gotchas.md +26 -0
  105. package/skills/implement/constitution-enforcer/scripts/check-constitution.sh +88 -0
  106. package/skills/implement/no-go-zone-guard/SKILL.md +173 -0
  107. package/skills/implement/no-go-zone-guard/config.json +28 -0
  108. package/skills/implement/no-go-zone-guard/examples/good/adapter-workaround.md +46 -0
  109. package/skills/implement/no-go-zone-guard/gotchas.md +27 -0
  110. package/skills/implement/no-go-zone-guard/scripts/check-nogo-zones.sh +148 -0
  111. package/skills/implement/no-go-zone-guard/scripts/nogo-precommit.sh +96 -0
  112. package/skills/implement/tdd-driver/SKILL.md +159 -0
  113. package/skills/implement/tdd-driver/config.json +33 -0
  114. package/skills/implement/tdd-driver/examples/good/tdd-cycle-product-repo.md +81 -0
  115. package/skills/implement/tdd-driver/gotchas.md +34 -0
  116. package/skills/metrics/metrics-collector/SKILL.md +133 -0
  117. package/skills/metrics/metrics-collector/config.json +16 -0
  118. package/skills/metrics/metrics-collector/examples/bad/incomplete-report.md +48 -0
  119. package/skills/metrics/metrics-collector/examples/good/full-metrics-report.md +101 -0
  120. package/skills/metrics/metrics-collector/gotchas.md +26 -0
  121. package/skills/operations/incident-runbook/SKILL.md +167 -0
  122. package/skills/operations/incident-runbook/config.json +21 -0
  123. package/skills/operations/incident-runbook/examples/bad/vague-incident-report.md +48 -0
  124. package/skills/operations/incident-runbook/examples/good/p1-hotfix-response.md +119 -0
  125. package/skills/operations/incident-runbook/gotchas.md +26 -0
  126. package/skills/plan/architecture-designer/SKILL.md +228 -0
  127. package/skills/plan/architecture-designer/config.json +32 -0
  128. package/skills/plan/architecture-designer/examples/bad/vague-plan.md +62 -0
  129. package/skills/plan/architecture-designer/examples/good/expand-contract-migration.md +56 -0
  130. package/skills/plan/architecture-designer/examples/good/plan-structure.md +58 -0
  131. package/skills/plan/architecture-designer/gotchas.md +45 -0
  132. package/skills/plan/task-breakdown/SKILL.md +208 -0
  133. package/skills/plan/task-breakdown/config.json +26 -0
  134. package/skills/plan/task-breakdown/examples/bad/vague-tasks.md +77 -0
  135. package/skills/plan/task-breakdown/examples/good/spike-clarify-tasks.md +66 -0
  136. package/skills/plan/task-breakdown/examples/good/tasks-login-feature.md +111 -0
  137. package/skills/plan/task-breakdown/gotchas.md +39 -0
  138. package/skills/prototype/LOGIC.md +240 -0
  139. package/skills/prototype/SKILL.md +185 -0
  140. package/skills/prototype/UI.md +407 -0
  141. package/skills/prototype/config.json +104 -0
  142. package/skills/prototype/examples/bad/prototype-notes.md +68 -0
  143. package/skills/prototype/examples/good/prototype-notes-ui.md +109 -0
  144. package/skills/prototype/examples/good/prototype-notes.md +67 -0
  145. package/skills/prototype/gotchas.md +128 -0
  146. package/skills/prototype/scripts/check-flow-state.ps1 +112 -0
  147. package/skills/prototype/scripts/check-flow-state.sh +104 -0
  148. package/skills/prototype/scripts/check-prototype-cleanup.ps1 +124 -0
  149. package/skills/prototype/scripts/check-prototype-cleanup.sh +109 -0
  150. package/skills/prototype/scripts/check-prototype-notes.ps1 +107 -0
  151. package/skills/prototype/scripts/check-prototype-notes.sh +102 -0
  152. package/skills/review/adversarial-reviewer/SKILL.md +137 -0
  153. package/skills/review/adversarial-reviewer/config.json +32 -0
  154. package/skills/review/adversarial-reviewer/examples/good/review-report-template.md +56 -0
  155. package/skills/review/adversarial-reviewer/gotchas.md +46 -0
  156. package/skills/review/adversarial-reviewer/scripts/quick-security-scan.sh +52 -0
  157. package/skills/specify/ba-bpmn-doc-gen/SKILL.md +108 -0
  158. package/skills/specify/ba-bpmn-doc-gen/reference/reference-bpmn-generation.md +528 -0
  159. package/skills/specify/ba-bpmn-doc-gen/reference/reference-drawio-flowchart.md +466 -0
  160. package/skills/specify/ba-critic/SKILL.md +172 -0
  161. package/skills/specify/ba-critic/config.json +32 -0
  162. package/skills/specify/ba-critic/examples/good/critic-report-round1.md +51 -0
  163. package/skills/specify/ba-critic/gotchas.md +40 -0
  164. package/skills/specify/ba-critic/scripts/check-spec-quality.sh +72 -0
  165. package/skills/specify/ba-doc-generator/SKILL.md +102 -0
  166. package/skills/specify/ba-doc-generator/references/template-clevel.md +84 -0
  167. package/skills/specify/ba-doc-generator/references/template-compliance.md +83 -0
  168. package/skills/specify/ba-doc-generator/references/template-dev.md +138 -0
  169. package/skills/specify/ba-doc-generator/references/template-partner.md +167 -0
  170. package/skills/specify/ba-doc-generator/references/template-pm.md +92 -0
  171. package/skills/specify/ba-doc-generator/references/template-review.md +114 -0
  172. package/skills/specify/ba-doc-generator/references/template-tester.md +108 -0
  173. package/skills/specify/ba-doc-generator/references/template-user.md +98 -0
  174. package/skills/specify/bugfix-analyst/SKILL.md +296 -0
  175. package/skills/specify/bugfix-analyst/config.json +41 -0
  176. package/skills/specify/bugfix-analyst/examples/bad/common-mistakes.md +71 -0
  177. package/skills/specify/bugfix-analyst/examples/good/email-validation-bugfix.md +53 -0
  178. package/skills/specify/bugfix-analyst/gotchas.md +51 -0
  179. package/skills/specify/ears-writer/SKILL.md +129 -0
  180. package/skills/specify/ears-writer/config.json +20 -0
  181. package/skills/specify/ears-writer/examples/bad/common-mistakes.md +17 -0
  182. package/skills/specify/ears-writer/examples/good/login-requirements.md +41 -0
  183. package/skills/specify/ears-writer/gotchas.md +43 -0
  184. package/skills/specify/ears-writer/scripts/check-ears-compliance.sh +51 -0
  185. package/skills/test/test-case-generator/SKILL.md +161 -0
  186. package/skills/test/test-case-generator/config.json +33 -0
  187. package/skills/test/test-case-generator/examples/good/test-cases-login.md +104 -0
  188. package/skills/test/test-case-generator/gotchas.md +43 -0
  189. package/skills/understand/ba-docs-scanner/SKILL.md +239 -0
  190. package/skills/understand/ba-docs-scanner/config.json +47 -0
  191. package/skills/understand/ba-docs-scanner/examples/good/work-order-br-extract.md +28 -0
  192. package/skills/understand/ba-docs-scanner/gotchas.md +44 -0
  193. package/skills/understand/ba-docs-scanner/merge-rules.md +47 -0
  194. package/skills/understand/codebase-scanner/SKILL.md +260 -0
  195. package/skills/understand/codebase-scanner/config.json +56 -0
  196. package/skills/understand/codebase-scanner/examples/good/menu-module-output.md +44 -0
  197. package/skills/understand/codebase-scanner/gotchas.md +42 -0
  198. package/skills/understand/codebase-scanner/scripts/scan-project-structure.sh +64 -0
  199. package/templates/DESIGN.md +456 -0
  200. package/templates/agent-command-template.yaml +240 -0
  201. package/templates/agent-config-template.md +170 -0
  202. package/templates/agent-definition-template.md +145 -0
  203. package/templates/agent-metrics-template.md +150 -0
  204. package/templates/api-contract-template.md +72 -0
  205. package/templates/bugfix-report-template.md +195 -0
  206. package/templates/bugfix-spec-template.md +134 -0
  207. package/templates/code-review-report-template.md +119 -0
  208. package/templates/constitution-template.md +234 -0
  209. package/templates/context-template.md +94 -0
  210. package/templates/data-model-template.md +95 -0
  211. package/templates/decision-log-template.md +92 -0
  212. package/templates/flow-state-template.yaml +208 -0
  213. package/templates/github/workflows/v-flow-validate.yml +30 -0
  214. package/templates/knowledge/adr-template.md +70 -0
  215. package/templates/knowledge/api-contract-template.md +140 -0
  216. package/templates/knowledge/domain-glossary.md +29 -0
  217. package/templates/knowledge/golden-tests-readme.md +115 -0
  218. package/templates/knowledge/lessons-learned.md +41 -0
  219. package/templates/knowledge/patterns.md +103 -0
  220. package/templates/module-card/SKILL.md +85 -0
  221. package/templates/module-card/api-specs.md +96 -0
  222. package/templates/module-card/business-quiz.md +119 -0
  223. package/templates/module-card/cross-service.md +125 -0
  224. package/templates/module-card/db.md +85 -0
  225. package/templates/module-card/dev-quiz.md +62 -0
  226. package/templates/module-card/permissions.md +83 -0
  227. package/templates/module-card/state-diagram.md +64 -0
  228. package/templates/module-card/tech-context.md +90 -0
  229. package/templates/module-card/ui-flows.md +91 -0
  230. package/templates/module-card/use-cases.md +142 -0
  231. package/templates/module-template.yaml +161 -0
  232. package/templates/operations-report-template.md +108 -0
  233. package/templates/plan-template.md +308 -0
  234. package/templates/prototype-notes-template.md +116 -0
  235. package/templates/ptyc/PTYC.template.docx +0 -0
  236. package/templates/ptyc/ptyc.meta.example.yaml +44 -0
  237. package/templates/retrospective-report-template.md +136 -0
  238. package/templates/security-review-template.md +84 -0
  239. package/templates/session-template.md +167 -0
  240. package/templates/spec-review-log-template.md +75 -0
  241. package/templates/spec-template.md +229 -0
  242. package/templates/sprint-status-template.md +101 -0
  243. package/templates/tasks-template.md +275 -0
  244. package/templates/test-cases-template.md +124 -0
  245. package/templates/ux-checklist-template.md +79 -0
  246. package/templates/validation-report-template.md +125 -0
  247. package/templates/vflow-config-template.yaml +22 -0
@@ -0,0 +1,269 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+ const chalk = require('chalk');
4
+ const { isInitialized, getVFlowDir, listFeatures, checkFeatureArtifacts } = require('../lib/templates');
5
+ const { withErrorHandler, requireInit } = require('../lib/cli-error');
6
+ const { readFlowState } = require('../lib/yaml-parser');
7
+ const { createT } = require('../lib/i18n');
8
+
9
+ module.exports = function (program) {
10
+ program
11
+ .command('status')
12
+ .description('Show pipeline status for features')
13
+ .argument('[feature]', 'Feature name (optional, shows all if omitted)')
14
+ .option('--json', 'Output as JSON')
15
+ .action(withErrorHandler(async (featureName, options) => {
16
+ const t = createT();
17
+ const projectRoot = process.cwd();
18
+ requireInit(projectRoot, isInitialized);
19
+
20
+ const mfDir = getVFlowDir(projectRoot);
21
+ const features = await listFeatures(projectRoot);
22
+
23
+ if (features.length === 0) {
24
+ console.log(chalk.yellow(`\n${t('status.no_features')}`));
25
+ console.log(chalk.dim(`${t('status.no_features_hint')}\n`));
26
+ return;
27
+ }
28
+
29
+ // Filter to specific feature if provided
30
+ const targetFeatures = featureName
31
+ ? features.filter(f => f.includes(featureName))
32
+ : features;
33
+
34
+ if (targetFeatures.length === 0) {
35
+ console.log(chalk.red(t('status.feature_not_found', { name: featureName })));
36
+ console.log(chalk.dim(`${t('status.available_features', { features: features.join(', ') })}\n`));
37
+ return;
38
+ }
39
+
40
+ if (!options.json) {
41
+ console.log(chalk.cyan.bold(`\n${t('status.title')}\n`));
42
+ }
43
+
44
+ const allStatuses = [];
45
+
46
+ for (const feature of targetFeatures) {
47
+ const featureDir = path.join(mfDir, 'features', feature);
48
+ const artifacts = await checkFeatureArtifacts(projectRoot, feature);
49
+
50
+ // Use shared YAML parser
51
+ const state = await readFlowState(featureDir);
52
+ const hasFlowState = state !== null;
53
+
54
+ if (options.json) {
55
+ allStatuses.push({ feature, state, artifacts });
56
+ continue;
57
+ }
58
+
59
+ // ── Visual output ──
60
+ const completed = artifacts.filter(a => a.exists).length;
61
+ const total = artifacts.length;
62
+ const progress = Math.round((completed / total) * 100);
63
+
64
+ // Progress bar
65
+ const barLength = 25;
66
+ const filledLength = Math.round((completed / total) * barLength);
67
+ const bar = '█'.repeat(filledLength) + '░'.repeat(barLength - filledLength);
68
+ const barColor = progress === 100 ? chalk.green : progress > 50 ? chalk.yellow : chalk.red;
69
+
70
+ console.log(chalk.white.bold(`📂 ${feature}`));
71
+
72
+ // If we have flow state, show rich info
73
+ if (state) {
74
+ const phaseLabel = PHASE_LABELS[state.currentPhase] || state.currentPhase;
75
+ const statusIcon = STATUS_ICONS[state.phaseStatus] || '📂';
76
+
77
+ console.log(` ${barColor(bar)} ${progress}%`);
78
+ console.log('');
79
+ console.log(` ${chalk.cyan('Phase:')} ${statusIcon} ${chalk.bold(state.currentPhase)} — ${phaseLabel}`);
80
+ console.log(` ${chalk.cyan('Status:')} ${state.phaseStatus}`);
81
+ console.log(` ${chalk.cyan('Spec:')} ${state.specVersion || 'v1.0'} (${state.artifacts.spec?.status || 'draft'})`);
82
+ console.log(` ${chalk.cyan('Type:')} ${state.projectType || 'unknown'}`);
83
+
84
+ if (state.blocked) {
85
+ console.log(chalk.red(` 🚫 BLOCKED: ${state.blockedReason || 'reason unknown'}`));
86
+ }
87
+
88
+ if (state.awaitingCheckpoint && state.awaitingCheckpoint !== 'null') {
89
+ console.log(chalk.yellow(` 👤 Awaiting: ${state.awaitingCheckpoint.replace(/_/g, ' ')}`));
90
+ }
91
+
92
+ if (state.artifacts.tasks.total > 0) {
93
+ console.log(` ${chalk.cyan('Tasks:')} ${state.artifacts.tasks.completed}/${state.artifacts.tasks.total}`);
94
+ }
95
+
96
+ if (state.concernsCount > 0) {
97
+ console.log(chalk.yellow(` ⚡ Concerns: ${state.concernsCount} active`));
98
+ }
99
+
100
+ if (state.artifacts.validation_report?.verdict) {
101
+ const verdict = state.artifacts.validation_report.verdict;
102
+ const verdictColor = verdict === 'PASS' ? chalk.green
103
+ : verdict === 'PASS_WITH_CONCERNS' ? chalk.yellow
104
+ : chalk.red;
105
+ console.log(` ${chalk.cyan('Verdict:')} ${verdictColor(verdict)}`);
106
+ }
107
+ } else {
108
+ console.log(` ${barColor(bar)} ${progress}% (${completed}/${total})`);
109
+ }
110
+
111
+ console.log('');
112
+
113
+ // Artifact list
114
+ for (const artifact of artifacts) {
115
+ const icon = artifact.exists ? chalk.green('✅') : chalk.dim('⬜');
116
+ const name = artifact.exists ? chalk.white(artifact.name) : chalk.dim(artifact.name);
117
+ const phase = chalk.dim(` → ${artifact.phase}`);
118
+ console.log(` ${icon} ${name}${phase}`);
119
+ }
120
+
121
+ // Current phase / next step
122
+ const currentPhase = state
123
+ ? getNextStep(state)
124
+ : determineCurrentPhase(artifacts);
125
+
126
+ console.log(`\n ${chalk.cyan('▶ Next:')} ${currentPhase}\n`);
127
+
128
+ // Pipeline visualization
129
+ if (state) {
130
+ renderPipeline(state.currentPhase);
131
+ }
132
+
133
+ console.log(chalk.dim(` ${ '─'.repeat(50)}`));
134
+ console.log('');
135
+ }
136
+
137
+ if (options.json) {
138
+ console.log(JSON.stringify(buildStatusIndex(allStatuses), null, 2));
139
+ }
140
+ }));
141
+ };
142
+
143
+ /**
144
+ * Build a queryable cross-feature index from collected statuses (H5).
145
+ * Flattens the key fields + adds a summary so a dashboard / `jq` can answer
146
+ * "which High-risk features lack approval / are blocked / sit at phase X"
147
+ * without grepping markdown. No new dependency — plain JSON.
148
+ */
149
+ function buildStatusIndex(allStatuses) {
150
+ const features = allStatuses.map(({ feature, state, artifacts }) => ({
151
+ feature,
152
+ phase: state?.currentPhase || null,
153
+ status: state?.phaseStatus || null,
154
+ riskTier: state?.riskTier || null,
155
+ approvals: state?.approvals || [],
156
+ verdict: state?.artifacts?.validation_report?.verdict || null,
157
+ blocked: state?.blocked || false,
158
+ awaiting: state?.awaitingCheckpoint && state.awaitingCheckpoint !== 'null'
159
+ ? state.awaitingCheckpoint
160
+ : null,
161
+ concerns: state?.concernsCount || 0,
162
+ tasks: state
163
+ ? { completed: state.artifacts.tasks.completed, total: state.artifacts.tasks.total }
164
+ : null,
165
+ artifactsComplete: artifacts.filter(a => a.exists).length,
166
+ artifactsTotal: artifacts.length,
167
+ }));
168
+
169
+ const tally = (key, fallback) => features.reduce((acc, e) => {
170
+ const k = e[key] || fallback;
171
+ acc[k] = (acc[k] || 0) + 1;
172
+ return acc;
173
+ }, {});
174
+
175
+ return {
176
+ schema: 'v-flow-status-index/1',
177
+ total: features.length,
178
+ summary: {
179
+ byPhase: tally('phase', 'unknown'),
180
+ byRiskTier: tally('riskTier', 'undeclared'),
181
+ blocked: features.filter(e => e.blocked).length,
182
+ awaiting: features.filter(e => e.awaiting).length,
183
+ },
184
+ features,
185
+ };
186
+ }
187
+
188
+ // ═══════════════════════════════════════════════════════════════════════
189
+ // Constants & Helpers
190
+ // ═══════════════════════════════════════════════════════════════════════
191
+
192
+ const PHASE_LABELS = {
193
+ 'U.0': 'Understanding',
194
+ 'S.0a': 'Constitution',
195
+ 'S.0b': 'Agent Setup',
196
+ 'S.1': 'Specification',
197
+ 'B.0a': 'Planning',
198
+ 'B.0b': 'Test Cases',
199
+ 'R.0': 'Master Check',
200
+ 'B.1': 'Implementation',
201
+ 'R.1': 'Code Review',
202
+ 'M.0': 'Metrics',
203
+ 'O.0': 'Operations',
204
+ };
205
+
206
+ const STATUS_ICONS = {
207
+ 'pending': '⏳',
208
+ 'in_progress': '🔄',
209
+ 'awaiting_human': '👤',
210
+ 'done': '✅',
211
+ 'blocked': '🚫',
212
+ };
213
+
214
+ const PIPELINE_PHASES = ['S.1', 'B.0a', 'B.0b', 'R.0', 'B.1', 'R.1', 'M.0', 'O.0'];
215
+
216
+ function renderPipeline(currentPhase) {
217
+ const phases = PIPELINE_PHASES;
218
+ const currentIdx = phases.indexOf(currentPhase);
219
+
220
+ let pipeline = ' ';
221
+ for (let i = 0; i < phases.length; i++) {
222
+ const phase = phases[i];
223
+ if (i < currentIdx) {
224
+ pipeline += chalk.green(`✓ ${phase}`);
225
+ } else if (i === currentIdx) {
226
+ pipeline += chalk.cyan.bold(`▶ ${phase}`);
227
+ } else {
228
+ pipeline += chalk.dim(`○ ${phase}`);
229
+ }
230
+ if (i < phases.length - 1) {
231
+ pipeline += chalk.dim(' → ');
232
+ }
233
+ }
234
+ console.log(pipeline);
235
+ }
236
+
237
+ function getNextStep(state) {
238
+ if (state.blocked) return `🚫 Blocked: ${state.blockedReason || 'resolve blocker first'}`;
239
+
240
+ if (state.awaitingCheckpoint && state.awaitingCheckpoint !== 'null') {
241
+ return `👤 Awaiting human: ${state.awaitingCheckpoint.replace(/_/g, ' ')}`;
242
+ }
243
+
244
+ const phase = state.currentPhase;
245
+ const nextSteps = {
246
+ 'S.1': '/v.specify → write specification',
247
+ 'B.0a': '/v.plan → create technical plan',
248
+ 'B.0b': '/v.test → generate test cases',
249
+ 'R.0': '/v.check → Master Check validation',
250
+ 'B.1': '/v.implement → start implementation',
251
+ 'R.1': '/v.review → adversarial code review',
252
+ 'M.0': '/v.metrics → collect metrics',
253
+ 'O.0': 'Operations monitoring',
254
+ };
255
+
256
+ return nextSteps[phase] || `Phase ${phase}`;
257
+ }
258
+
259
+ function determineCurrentPhase(artifacts) {
260
+ const has = (name) => artifacts.find(a => a.name === name)?.exists;
261
+
262
+ if (!has('spec.md')) return '[S.1] Specification needed → run /v.specify';
263
+ if (!has('plan.md')) return '[B.0a] Planning needed → run /v.plan';
264
+ if (!has('test-cases.md')) return '[B.0b] Test cases needed → run /v.test';
265
+ if (!has('validation-report.md')) return '[R.0] Master Check needed → run /v.check';
266
+ if (!has('metrics-report.md')) return '[B.1→R.1] Implementation & Verification → run /v.implement';
267
+ if (!has('operations-report.md')) return '[M.0→O.0] Metrics collected, Operations monitoring';
268
+ return '🎉 All phases complete!';
269
+ }
@@ -0,0 +1,59 @@
1
+ const path = require('path');
2
+ const chalk = require('chalk');
3
+ const { runSync, selectTargets } = require('../lib/sync-core');
4
+ const { withErrorHandler } = require('../lib/cli-error');
5
+ const { createT } = require('../lib/i18n');
6
+
7
+ module.exports = function (program) {
8
+ program
9
+ .command('sync')
10
+ .description('Sync commands, agents, skills + runtime assets to AI folders & .v-flow/')
11
+ .option('--apply', 'Apply changes (default: dry-run)')
12
+ .option('--verbose', 'Show detailed file-level changes')
13
+ .option('--target <target>', 'Sync specific target only: antigravity, copilot, cursor, claude, all', 'all')
14
+ .action(withErrorHandler(async (options) => {
15
+ const t = createT();
16
+ const projectRoot = process.cwd();
17
+ const sourceRoot = path.resolve(__dirname, '../..');
18
+ const isDryRun = !options.apply;
19
+ const target = options.target.toLowerCase();
20
+
21
+ console.log(chalk.cyan.bold(`\n${t('sync.title')}${isDryRun ? ' (DRY RUN)' : ''}\n`));
22
+ if (isDryRun) {
23
+ console.log(chalk.yellow(' ℹ️ Dry-run mode: no files will be changed.'));
24
+ console.log(chalk.yellow(' Add --apply to execute changes.\n'));
25
+ }
26
+
27
+ // Single source of truth — the SAME engine `init` / `upgrade` use (no duplicate logic).
28
+ const stats = await runSync({
29
+ projectRoot,
30
+ sourceRoot,
31
+ dryRun: isDryRun,
32
+ verbose: options.verbose,
33
+ target,
34
+ silent: true,
35
+ });
36
+
37
+ const targetLabel = selectTargets(target).map(t => t.label).join(' + ') || target;
38
+ console.log(chalk.white(` 📂 ${targetLabel} (commands, agents, skills) + .v-flow/ (templates, skills)`));
39
+
40
+ // Summary — counts reflect tracked .md / global files (hash-compared).
41
+ // Skills/templates are bulk-copied (overwrite) so they don't show as numeric diffs.
42
+ console.log(chalk.cyan.bold(`\n── Summary${isDryRun ? ' (DRY RUN)' : ''} ──\n`));
43
+ console.log(` ✨ Added: ${chalk.green(stats.added)}`);
44
+ console.log(` 🔄 Updated: ${chalk.yellow(stats.synced)}`);
45
+ console.log(` ⏭️ Unchanged: ${chalk.dim(stats.skipped)}`);
46
+ if (stats.errors > 0) {
47
+ console.log(` ❌ Errors: ${chalk.red(stats.errors)}`);
48
+ }
49
+
50
+ if (isDryRun && (stats.added > 0 || stats.synced > 0)) {
51
+ console.log(chalk.yellow(`\n ℹ️ Run ${chalk.bold('v-flow sync --apply')} to execute these changes.`));
52
+ } else if (!isDryRun) {
53
+ console.log(chalk.green('\n ✅ All files synced successfully.'));
54
+ } else {
55
+ console.log(chalk.green('\n ✅ All files are up-to-date.'));
56
+ }
57
+ console.log('');
58
+ }));
59
+ };
@@ -0,0 +1,150 @@
1
+ const path = require('path');
2
+ const fs = require('fs-extra');
3
+ const chalk = require('chalk');
4
+ const { isInitialized, getVFlowDir } = require('../lib/templates');
5
+ const { runSync } = require('../lib/sync-core');
6
+ const { withErrorHandler, requireInit } = require('../lib/cli-error');
7
+ const { createT } = require('../lib/i18n');
8
+
9
+ module.exports = function (program) {
10
+ program
11
+ .command('upgrade')
12
+ .description('Upgrade templates, agents, and skills to the latest version')
13
+ .option('--dry-run', 'Preview changes without applying')
14
+ .option('--templates-only', 'Only upgrade templates')
15
+ .option('--agents-only', 'Only upgrade agent definitions')
16
+ .action(withErrorHandler(async (options) => {
17
+ const t = createT();
18
+ const projectRoot = process.cwd();
19
+ const sourceRoot = path.resolve(__dirname, '../..');
20
+ const isDryRun = options.dryRun;
21
+
22
+ console.log(chalk.cyan.bold(`\n${t('upgrade.title', { mode: isDryRun ? ' (DRY RUN)' : '' })}\n`));
23
+
24
+ requireInit(projectRoot, isInitialized);
25
+
26
+ const mfDir = getVFlowDir(projectRoot);
27
+ const stats = { updated: 0, added: 0, skipped: 0 };
28
+
29
+ // ── Read current version from installed package.json ──
30
+ const sourcePkg = await fs.readJson(path.join(sourceRoot, 'package.json'));
31
+ const sourceVersion = sourcePkg.version;
32
+ console.log(chalk.white(t('upgrade.source_version', { version: chalk.cyan.bold(sourceVersion) })));
33
+
34
+ // Check and display installed version
35
+ const versionFile = path.join(mfDir, '.v-flow-version');
36
+ let installedVersion = 'unknown';
37
+ if (fs.existsSync(versionFile)) {
38
+ installedVersion = (await fs.readFile(versionFile, 'utf8')).trim();
39
+ }
40
+ console.log(chalk.white(t('upgrade.installed_version', { version: chalk.dim(installedVersion) })));
41
+
42
+ if (installedVersion === sourceVersion && !isDryRun) {
43
+ console.log(chalk.green(`\n ${t('upgrade.up_to_date')}\n`));
44
+ return;
45
+ }
46
+
47
+ console.log('');
48
+
49
+ // ════════════════════════════════════════════════════════════════════
50
+ // 1. Upgrade Templates
51
+ // ════════════════════════════════════════════════════════════════════
52
+ if (!options.agentsOnly) {
53
+ console.log(chalk.white.bold(t('upgrade.templates')));
54
+
55
+ const templatesSrc = path.join(sourceRoot, 'templates');
56
+ const templatesDest = path.join(mfDir, 'templates');
57
+
58
+ if (fs.existsSync(templatesSrc)) {
59
+ // Walk source tree and compare with dest to count new vs updated
60
+ const walk = async (srcDir, destDir) => {
61
+ const entries = await fs.readdir(srcDir, { withFileTypes: true });
62
+ let added = 0, updated = 0;
63
+ for (const e of entries) {
64
+ const srcPath = path.join(srcDir, e.name);
65
+ const destPath = path.join(destDir, e.name);
66
+ if (e.isDirectory()) {
67
+ const sub = await walk(srcPath, destPath);
68
+ added += sub.added;
69
+ updated += sub.updated;
70
+ } else if (!fs.existsSync(destPath)) {
71
+ added++;
72
+ } else {
73
+ const srcContent = await fs.readFile(srcPath, 'utf8');
74
+ const destContent = await fs.readFile(destPath, 'utf8');
75
+ if (srcContent !== destContent) updated++;
76
+ }
77
+ }
78
+ return { added, updated };
79
+ };
80
+
81
+ const { added: newFiles, updated: changedFiles } = await walk(templatesSrc, templatesDest);
82
+ stats.added += newFiles;
83
+ stats.updated += changedFiles;
84
+
85
+ if (!isDryRun) {
86
+ await fs.ensureDir(templatesDest);
87
+ await fs.copy(templatesSrc, templatesDest, { overwrite: true });
88
+ }
89
+
90
+ console.log(chalk.green(` ✅ .v-flow/templates/ — synced`));
91
+ if (newFiles > 0) console.log(chalk.green(` ✨ ${newFiles} new file(s)`));
92
+ if (changedFiles > 0) console.log(chalk.yellow(` 🔄 ${changedFiles} updated file(s)`));
93
+ if (newFiles === 0 && changedFiles === 0) console.log(chalk.dim(` ⏭️ All templates up-to-date`));
94
+ }
95
+ }
96
+
97
+ // ════════════════════════════════════════════════════════════════════
98
+ // 2. Upgrade Agent Definitions & Commands
99
+ // ════════════════════════════════════════════════════════════════════
100
+ if (!options.templatesOnly) {
101
+ console.log(chalk.white.bold(`\n${t('upgrade.agents')}`));
102
+ console.log(chalk.dim(`${t('upgrade.agents_hint') }\n`));
103
+
104
+ const syncStats = await runSync({
105
+ projectRoot,
106
+ sourceRoot,
107
+ dryRun: isDryRun,
108
+ verbose: false,
109
+ target: 'all',
110
+ silent: true,
111
+ });
112
+
113
+ const syncTotal = syncStats.added + syncStats.synced + syncStats.skipped;
114
+ console.log(chalk.green(` ${t('upgrade.synced', { added: syncStats.added, synced: syncStats.synced, skipped: syncStats.skipped })}`));
115
+ if (syncStats.errors > 0) {
116
+ console.log(chalk.yellow(` ${t('upgrade.sync_errors', { count: syncStats.errors })}`));
117
+ }
118
+
119
+ stats.added += syncStats.added;
120
+ stats.updated += syncStats.synced;
121
+ stats.skipped += syncStats.skipped;
122
+ }
123
+
124
+ // ════════════════════════════════════════════════════════════════════
125
+ // 3. Update version marker
126
+ // ════════════════════════════════════════════════════════════════════
127
+ if (!isDryRun) {
128
+ await fs.writeFile(versionFile, sourceVersion, 'utf8');
129
+ }
130
+
131
+ // ════════════════════════════════════════════════════════════════════
132
+ // SUMMARY
133
+ // ════════════════════════════════════════════════════════════════════
134
+ console.log(chalk.cyan.bold(`\n${t('sync.summary', { mode: isDryRun ? ' (DRY RUN)' : '' })}\n`));
135
+ console.log(` ✨ ${t('common.added')}: ${chalk.green(stats.added)}`);
136
+ console.log(` 🔄 ${t('common.updated')}: ${chalk.yellow(stats.updated)}`);
137
+ console.log(` ⏭️ ${t('common.unchanged')}: ${chalk.dim(stats.skipped)}`);
138
+
139
+ if (!isDryRun) {
140
+ console.log(chalk.green(`\n ${t('upgrade.upgraded', { version: sourceVersion })}`));
141
+ console.log(chalk.dim(` ${t('upgrade.verify_hint')}`));
142
+ } else if (stats.added > 0 || stats.updated > 0) {
143
+ console.log(chalk.yellow(`\n ${t('upgrade.apply_hint')}`));
144
+ } else {
145
+ console.log(chalk.green(`\n ${t('upgrade.templates_uptodate')}`));
146
+ }
147
+
148
+ console.log('');
149
+ }));
150
+ };