@lumenflow/cli 3.1.3 → 3.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.
Files changed (267) hide show
  1. package/dist/agent-issues-query.js.map +1 -0
  2. package/dist/agent-log-issue.js.map +1 -0
  3. package/dist/agent-session-end.js.map +1 -0
  4. package/dist/agent-session.js.map +1 -0
  5. package/dist/backlog-prune.js.map +1 -0
  6. package/dist/cli-entry-point.js +139 -0
  7. package/dist/cli-entry-point.js.map +1 -0
  8. package/dist/commands/integrate.js.map +1 -0
  9. package/dist/commands.js.map +1 -0
  10. package/dist/config-get.js.map +1 -0
  11. package/dist/config-set.js.map +1 -0
  12. package/dist/constants.js +98 -0
  13. package/dist/constants.js.map +1 -0
  14. package/dist/delegation-list.js.map +1 -0
  15. package/dist/deps-add.js +259 -0
  16. package/dist/deps-add.js.map +1 -0
  17. package/dist/deps-remove.js +105 -0
  18. package/dist/deps-remove.js.map +1 -0
  19. package/dist/docs-sync.js.map +1 -0
  20. package/dist/doctor.js.map +1 -0
  21. package/dist/file-delete.js.map +1 -0
  22. package/dist/file-edit.js.map +1 -0
  23. package/dist/file-read.js.map +1 -0
  24. package/dist/file-write.js.map +1 -0
  25. package/dist/flow-bottlenecks.js.map +1 -0
  26. package/dist/flow-report.js.map +1 -0
  27. package/dist/formatters.js +151 -0
  28. package/dist/formatters.js.map +1 -0
  29. package/dist/gate-defaults.js +137 -0
  30. package/dist/gate-defaults.js.map +1 -0
  31. package/dist/gate-registry.js +73 -0
  32. package/dist/gate-registry.js.map +1 -0
  33. package/dist/gates-graceful-degradation.js +153 -0
  34. package/dist/gates-graceful-degradation.js.map +1 -0
  35. package/dist/gates-plan-resolvers.js +190 -0
  36. package/dist/gates-plan-resolvers.js.map +1 -0
  37. package/dist/gates-runners.js +545 -0
  38. package/dist/gates-runners.js.map +1 -0
  39. package/dist/gates-types.js +4 -0
  40. package/dist/gates-types.js.map +1 -0
  41. package/dist/gates-utils.js +333 -0
  42. package/dist/gates-utils.js.map +1 -0
  43. package/dist/gates.js.map +1 -0
  44. package/dist/git-branch.js.map +1 -0
  45. package/dist/git-diff.js.map +1 -0
  46. package/dist/git-log.js.map +1 -0
  47. package/dist/git-status.js.map +1 -0
  48. package/dist/guard-locked.js +172 -0
  49. package/dist/guard-locked.js.map +1 -0
  50. package/dist/guard-main-branch.js +217 -0
  51. package/dist/guard-main-branch.js.map +1 -0
  52. package/dist/guard-worktree-commit.js +163 -0
  53. package/dist/guard-worktree-commit.js.map +1 -0
  54. package/dist/hooks/auto-checkpoint-utils.js +54 -0
  55. package/dist/hooks/auto-checkpoint-utils.js.map +1 -0
  56. package/dist/hooks/enforcement-checks.js +399 -0
  57. package/dist/hooks/enforcement-checks.js.map +1 -0
  58. package/dist/hooks/enforcement-generator.js +139 -0
  59. package/dist/hooks/enforcement-generator.js.map +1 -0
  60. package/dist/hooks/enforcement-sync.js +380 -0
  61. package/dist/hooks/enforcement-sync.js.map +1 -0
  62. package/dist/hooks/generators/auto-checkpoint.js +125 -0
  63. package/dist/hooks/generators/auto-checkpoint.js.map +1 -0
  64. package/dist/hooks/generators/enforce-worktree.js +190 -0
  65. package/dist/hooks/generators/enforce-worktree.js.map +1 -0
  66. package/dist/hooks/generators/index.js +18 -0
  67. package/dist/hooks/generators/index.js.map +1 -0
  68. package/dist/hooks/generators/pre-compact-checkpoint.js +136 -0
  69. package/dist/hooks/generators/pre-compact-checkpoint.js.map +1 -0
  70. package/dist/hooks/generators/require-wu.js +117 -0
  71. package/dist/hooks/generators/require-wu.js.map +1 -0
  72. package/dist/hooks/generators/session-start-recovery.js +103 -0
  73. package/dist/hooks/generators/session-start-recovery.js.map +1 -0
  74. package/dist/hooks/generators/signal-utils.js +54 -0
  75. package/dist/hooks/generators/signal-utils.js.map +1 -0
  76. package/dist/hooks/generators/warn-incomplete.js +67 -0
  77. package/dist/hooks/generators/warn-incomplete.js.map +1 -0
  78. package/dist/hooks/index.js +10 -0
  79. package/dist/hooks/index.js.map +1 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/init-detection.js +232 -0
  82. package/dist/init-detection.js.map +1 -0
  83. package/dist/init-lane-validation.js +147 -0
  84. package/dist/init-lane-validation.js.map +1 -0
  85. package/dist/init-scaffolding.js +158 -0
  86. package/dist/init-scaffolding.js.map +1 -0
  87. package/dist/init-templates.js +1983 -0
  88. package/dist/init-templates.js.map +1 -0
  89. package/dist/init.js.map +1 -0
  90. package/dist/initiative-add-wu.js.map +1 -0
  91. package/dist/initiative-bulk-assign-wus.js.map +1 -0
  92. package/dist/initiative-create.js.map +1 -0
  93. package/dist/initiative-edit.js.map +1 -0
  94. package/dist/initiative-list.js.map +1 -0
  95. package/dist/initiative-plan.js.map +1 -0
  96. package/dist/initiative-remove-wu.js.map +1 -0
  97. package/dist/initiative-status.js.map +1 -0
  98. package/dist/lane-edit.js.map +1 -0
  99. package/dist/lane-health.js.map +1 -0
  100. package/dist/lane-lifecycle-process.js +381 -0
  101. package/dist/lane-lifecycle-process.js.map +1 -0
  102. package/dist/lane-lock.js.map +1 -0
  103. package/dist/lane-setup.js.map +1 -0
  104. package/dist/lane-status.js.map +1 -0
  105. package/dist/lane-suggest.js.map +1 -0
  106. package/dist/lane-validate.js.map +1 -0
  107. package/dist/lifecycle-regression-harness.js +181 -0
  108. package/dist/lifecycle-regression-harness.js.map +1 -0
  109. package/dist/lumenflow-upgrade.js +18 -10
  110. package/dist/lumenflow-upgrade.js.map +1 -0
  111. package/dist/mem-checkpoint.js.map +1 -0
  112. package/dist/mem-cleanup.js.map +1 -0
  113. package/dist/mem-context.js.map +1 -0
  114. package/dist/mem-create.js.map +1 -0
  115. package/dist/mem-delete.js.map +1 -0
  116. package/dist/mem-export.js.map +1 -0
  117. package/dist/mem-inbox.js.map +1 -0
  118. package/dist/mem-index.js +214 -0
  119. package/dist/mem-index.js.map +1 -0
  120. package/dist/mem-init.js.map +1 -0
  121. package/dist/mem-profile.js +210 -0
  122. package/dist/mem-profile.js.map +1 -0
  123. package/dist/mem-promote.js +257 -0
  124. package/dist/mem-promote.js.map +1 -0
  125. package/dist/mem-ready.js.map +1 -0
  126. package/dist/mem-recover.js.map +1 -0
  127. package/dist/mem-signal.js.map +1 -0
  128. package/dist/mem-start.js.map +1 -0
  129. package/dist/mem-summarize.js.map +1 -0
  130. package/dist/mem-triage.js.map +1 -0
  131. package/dist/merge-block.js +225 -0
  132. package/dist/merge-block.js.map +1 -0
  133. package/dist/metrics-cli.js.map +1 -0
  134. package/dist/metrics-snapshot.js.map +1 -0
  135. package/dist/object-guards.js +9 -0
  136. package/dist/object-guards.js.map +1 -0
  137. package/dist/onboard.js.map +1 -0
  138. package/dist/onboarding-smoke-test.js +432 -0
  139. package/dist/onboarding-smoke-test.js.map +1 -0
  140. package/dist/orchestrate-init-status.js.map +1 -0
  141. package/dist/orchestrate-initiative.js.map +1 -0
  142. package/dist/orchestrate-monitor.js.map +1 -0
  143. package/dist/pack-author.js.map +1 -0
  144. package/dist/pack-hash.js.map +1 -0
  145. package/dist/pack-install.js.map +1 -0
  146. package/dist/pack-publish.js.map +1 -0
  147. package/dist/pack-scaffold.js.map +1 -0
  148. package/dist/pack-search.js.map +1 -0
  149. package/dist/pack-validate.js.map +1 -0
  150. package/dist/plan-create.js.map +1 -0
  151. package/dist/plan-edit.js.map +1 -0
  152. package/dist/plan-link.js.map +1 -0
  153. package/dist/plan-promote.js.map +1 -0
  154. package/dist/public-manifest.js +931 -0
  155. package/dist/public-manifest.js.map +1 -0
  156. package/dist/release.js +664 -116
  157. package/dist/release.js.map +1 -0
  158. package/dist/rotate-progress.js +253 -0
  159. package/dist/rotate-progress.js.map +1 -0
  160. package/dist/session-coordinator.js +303 -0
  161. package/dist/session-coordinator.js.map +1 -0
  162. package/dist/shared-validators.js +81 -0
  163. package/dist/shared-validators.js.map +1 -0
  164. package/dist/signal-cleanup.js.map +1 -0
  165. package/dist/state-bootstrap.js.map +1 -0
  166. package/dist/state-cleanup.js.map +1 -0
  167. package/dist/state-doctor-fix.js +226 -0
  168. package/dist/state-doctor-fix.js.map +1 -0
  169. package/dist/state-doctor-stamps.js +23 -0
  170. package/dist/state-doctor-stamps.js.map +1 -0
  171. package/dist/state-doctor.js.map +1 -0
  172. package/dist/strict-progress.js +255 -0
  173. package/dist/strict-progress.js.map +1 -0
  174. package/dist/sync-templates.js.map +1 -0
  175. package/dist/task-claim.js.map +1 -0
  176. package/dist/trace-gen.js +401 -0
  177. package/dist/trace-gen.js.map +1 -0
  178. package/dist/validate-agent-skills.js +224 -0
  179. package/dist/validate-agent-skills.js.map +1 -0
  180. package/dist/validate-agent-sync.js +152 -0
  181. package/dist/validate-agent-sync.js.map +1 -0
  182. package/dist/validate-backlog-sync.js +77 -0
  183. package/dist/validate-backlog-sync.js.map +1 -0
  184. package/dist/validate-skills-spec.js +211 -0
  185. package/dist/validate-skills-spec.js.map +1 -0
  186. package/dist/validate.js.map +1 -0
  187. package/dist/validator-defaults.js +107 -0
  188. package/dist/validator-defaults.js.map +1 -0
  189. package/dist/validator-registry.js +71 -0
  190. package/dist/validator-registry.js.map +1 -0
  191. package/dist/workspace-init.js.map +1 -0
  192. package/dist/wu-block.js.map +1 -0
  193. package/dist/wu-brief.js.map +1 -0
  194. package/dist/wu-claim-branch.js +123 -0
  195. package/dist/wu-claim-branch.js.map +1 -0
  196. package/dist/wu-claim-cloud.js +79 -0
  197. package/dist/wu-claim-cloud.js.map +1 -0
  198. package/dist/wu-claim-mode.js +82 -0
  199. package/dist/wu-claim-mode.js.map +1 -0
  200. package/dist/wu-claim-output.js +85 -0
  201. package/dist/wu-claim-output.js.map +1 -0
  202. package/dist/wu-claim-repair-guidance.js +12 -0
  203. package/dist/wu-claim-repair-guidance.js.map +1 -0
  204. package/dist/wu-claim-resume-handler.js +87 -0
  205. package/dist/wu-claim-resume-handler.js.map +1 -0
  206. package/dist/wu-claim-state.js +581 -0
  207. package/dist/wu-claim-state.js.map +1 -0
  208. package/dist/wu-claim-validation.js +458 -0
  209. package/dist/wu-claim-validation.js.map +1 -0
  210. package/dist/wu-claim-worktree.js +238 -0
  211. package/dist/wu-claim-worktree.js.map +1 -0
  212. package/dist/wu-claim.js.map +1 -0
  213. package/dist/wu-cleanup-cloud.js +78 -0
  214. package/dist/wu-cleanup-cloud.js.map +1 -0
  215. package/dist/wu-cleanup.js.map +1 -0
  216. package/dist/wu-code-path-coverage.js +83 -0
  217. package/dist/wu-code-path-coverage.js.map +1 -0
  218. package/dist/wu-create-cloud.js +30 -0
  219. package/dist/wu-create-cloud.js.map +1 -0
  220. package/dist/wu-create-content.js +264 -0
  221. package/dist/wu-create-content.js.map +1 -0
  222. package/dist/wu-create-readiness.js +59 -0
  223. package/dist/wu-create-readiness.js.map +1 -0
  224. package/dist/wu-create-validation.js +128 -0
  225. package/dist/wu-create-validation.js.map +1 -0
  226. package/dist/wu-create.js.map +1 -0
  227. package/dist/wu-delegate.js.map +1 -0
  228. package/dist/wu-delete.js.map +1 -0
  229. package/dist/wu-deps.js.map +1 -0
  230. package/dist/wu-done-auto-cleanup.js +194 -0
  231. package/dist/wu-done-auto-cleanup.js.map +1 -0
  232. package/dist/wu-done-check.js +38 -0
  233. package/dist/wu-done-check.js.map +1 -0
  234. package/dist/wu-done-cloud.js +48 -0
  235. package/dist/wu-done-cloud.js.map +1 -0
  236. package/dist/wu-done-decay.js +83 -0
  237. package/dist/wu-done-decay.js.map +1 -0
  238. package/dist/wu-done.js.map +1 -0
  239. package/dist/wu-edit-operations.js +399 -0
  240. package/dist/wu-edit-operations.js.map +1 -0
  241. package/dist/wu-edit-validators.js +282 -0
  242. package/dist/wu-edit-validators.js.map +1 -0
  243. package/dist/wu-edit.js.map +1 -0
  244. package/dist/wu-infer-lane.js.map +1 -0
  245. package/dist/wu-preflight.js.map +1 -0
  246. package/dist/wu-prep.js.map +1 -0
  247. package/dist/wu-proto.js.map +1 -0
  248. package/dist/wu-prune.js.map +1 -0
  249. package/dist/wu-recover.js.map +1 -0
  250. package/dist/wu-release.js.map +1 -0
  251. package/dist/wu-repair.js.map +1 -0
  252. package/dist/wu-sandbox.js.map +1 -0
  253. package/dist/wu-spawn-completion.js +58 -0
  254. package/dist/wu-spawn-completion.js.map +1 -0
  255. package/dist/wu-spawn-prompt-builders.js +1190 -0
  256. package/dist/wu-spawn-prompt-builders.js.map +1 -0
  257. package/dist/wu-spawn-strategy-resolver.js +322 -0
  258. package/dist/wu-spawn-strategy-resolver.js.map +1 -0
  259. package/dist/wu-spawn.js +59 -0
  260. package/dist/wu-spawn.js.map +1 -0
  261. package/dist/wu-state-cloud.js +41 -0
  262. package/dist/wu-state-cloud.js.map +1 -0
  263. package/dist/wu-status.js.map +1 -0
  264. package/dist/wu-unblock.js.map +1 -0
  265. package/dist/wu-unlock-lane.js.map +1 -0
  266. package/dist/wu-validate.js.map +1 -0
  267. package/package.json +8 -10
@@ -0,0 +1,401 @@
1
+ #!/usr/bin/env node
2
+ // Copyright (c) 2026 Hellmai Ltd
3
+ // SPDX-License-Identifier: AGPL-3.0-only
4
+ /**
5
+ * Trace Generator CLI Command
6
+ *
7
+ * Creates traceability reports linking WUs to code changes.
8
+ * Useful for audit trails, compliance documentation, and understanding
9
+ * what code was changed as part of each WU.
10
+ *
11
+ * WU-1112: INIT-003 Phase 6 - Migrate remaining Tier 1 tools
12
+ * WU-1534: Harden CLI command execution surfaces - argv-based git invocations
13
+ *
14
+ * Usage:
15
+ * pnpm trace:gen --wu WU-1112
16
+ * pnpm trace:gen --since 2024-01-01 --format json
17
+ * pnpm trace:gen --format markdown --output trace.md
18
+ */
19
+ import { readFileSync, writeFileSync, existsSync, readdirSync } from 'node:fs';
20
+ import { join } from 'node:path';
21
+ import { execFileSync } from 'node:child_process';
22
+ import { parse as parseYaml } from 'yaml';
23
+ import { EXIT_CODES, FILE_SYSTEM } from '@lumenflow/core/wu-constants';
24
+ import { WU_PATHS } from '@lumenflow/core/wu-paths';
25
+ import { runCLI } from './cli-entry-point.js';
26
+ import { MAX_WU_ID_LENGTH, COMMIT_SHA_DISPLAY_LENGTH, MARKDOWN_TABLE_TITLE_LENGTH, TRACE_FILES_DISPLAY_LIMIT, JSON_INDENT, } from './constants.js';
27
+ /** Log prefix for console output */
28
+ const LOG_PREFIX = '[trace:gen]';
29
+ /**
30
+ * Regex for validating WU IDs.
31
+ * Valid format: WU-<digits> (e.g., WU-1112, WU-1, WU-99999)
32
+ */
33
+ const WU_ID_PATTERN = /^WU-\d+$/;
34
+ /**
35
+ * Output formats for trace report
36
+ */
37
+ export var TraceFormat;
38
+ (function (TraceFormat) {
39
+ TraceFormat["JSON"] = "json";
40
+ TraceFormat["MARKDOWN"] = "markdown";
41
+ TraceFormat["CSV"] = "csv";
42
+ })(TraceFormat || (TraceFormat = {}));
43
+ /**
44
+ * Validate a WU ID to ensure it matches the expected format.
45
+ *
46
+ * WU-1534: Input validation layer (defense-in-depth alongside argv-based execution).
47
+ *
48
+ * @param wuId - WU ID to validate
49
+ * @returns true if the WU ID matches the WU-<digits> pattern
50
+ */
51
+ export function validateWuId(wuId) {
52
+ if (!wuId || wuId.length > MAX_WU_ID_LENGTH) {
53
+ return false;
54
+ }
55
+ return WU_ID_PATTERN.test(wuId);
56
+ }
57
+ /**
58
+ * Build argv array for git log commit lookup.
59
+ *
60
+ * WU-1534: Returns an argv array for use with execFileSync (no shell).
61
+ * The WU ID is passed as a literal --grep= value, not interpolated into a shell string.
62
+ *
63
+ * @param wuId - WU ID to search for in commit messages
64
+ * @returns Argv array for execFileSync('git', args)
65
+ */
66
+ export function buildGitLogArgs(wuId) {
67
+ return ['log', '--all', '--oneline', '--date=iso-strict', '--format=%H|%ad|%s', `--grep=${wuId}`];
68
+ }
69
+ /**
70
+ * Build argv array for git log file listing.
71
+ *
72
+ * WU-1534: Returns an argv array for use with execFileSync (no shell).
73
+ * Replaces the previous shell pipe `| sort -u` with in-process dedup.
74
+ *
75
+ * @param wuId - WU ID to search for in commit messages
76
+ * @returns Argv array for execFileSync('git', args)
77
+ */
78
+ export function buildGitFilesArgs(wuId) {
79
+ return ['log', '--all', '--name-only', '--format=', `--grep=${wuId}`];
80
+ }
81
+ /**
82
+ * Parse command line arguments for trace-gen
83
+ *
84
+ * @param argv - Process argv array
85
+ * @returns Parsed arguments
86
+ */
87
+ export function parseTraceArgs(argv) {
88
+ const args = {};
89
+ // Skip node and script name
90
+ const cliArgs = argv.slice(2);
91
+ for (let i = 0; i < cliArgs.length; i++) {
92
+ const arg = cliArgs[i];
93
+ if (arg === '--help' || arg === '-h') {
94
+ args.help = true;
95
+ }
96
+ else if (arg === '--wu' || arg === '-w') {
97
+ args.wuId = cliArgs[++i];
98
+ }
99
+ else if (arg === '--format' || arg === '-f') {
100
+ args.format = cliArgs[++i];
101
+ }
102
+ else if (arg === '--output' || arg === '-o') {
103
+ args.output = cliArgs[++i];
104
+ }
105
+ else if (arg === '--since' || arg === '-s') {
106
+ args.since = cliArgs[++i];
107
+ }
108
+ }
109
+ return args;
110
+ }
111
+ /**
112
+ * Build a trace entry from WU and commit data
113
+ *
114
+ * @param input - Input data containing WU info, commits, and files
115
+ * @returns Trace entry with summary statistics
116
+ */
117
+ export function buildTraceEntry(input) {
118
+ const { wuId, title, status, commits, files } = input;
119
+ const entry = {
120
+ wuId,
121
+ title,
122
+ status,
123
+ commitCount: commits.length,
124
+ fileCount: files.length,
125
+ };
126
+ if (commits.length > 0) {
127
+ // Sort commits by date
128
+ const sorted = [...commits].sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime());
129
+ entry.firstCommit = sorted[0].date;
130
+ entry.lastCommit = sorted[sorted.length - 1].date;
131
+ entry.commits = sorted;
132
+ }
133
+ if (files.length > 0) {
134
+ entry.files = files;
135
+ }
136
+ return entry;
137
+ }
138
+ /**
139
+ * Get commits for a WU by searching git log.
140
+ *
141
+ * WU-1534: Uses execFileSync with argv array (no shell interpolation).
142
+ */
143
+ function getWuCommits(wuId) {
144
+ try {
145
+ const gitArgs = buildGitLogArgs(wuId);
146
+ // eslint-disable-next-line sonarjs/no-os-command-from-path -- git resolved from PATH; CLI tool requires git
147
+ const output = execFileSync('git', gitArgs, {
148
+ encoding: FILE_SYSTEM.ENCODING,
149
+ });
150
+ const commits = [];
151
+ for (const line of output.trim().split('\n')) {
152
+ if (!line)
153
+ continue;
154
+ const [sha, date, ...messageParts] = line.split('|');
155
+ commits.push({
156
+ sha: sha.slice(0, COMMIT_SHA_DISPLAY_LENGTH),
157
+ date,
158
+ message: messageParts.join('|'),
159
+ });
160
+ }
161
+ return commits;
162
+ }
163
+ catch {
164
+ return [];
165
+ }
166
+ }
167
+ /**
168
+ * Get files changed by a WU.
169
+ *
170
+ * WU-1534: Uses execFileSync with argv array (no shell interpolation).
171
+ * Dedup/sort done in-process instead of shell pipe `| sort -u`.
172
+ */
173
+ function getWuFiles(wuId) {
174
+ try {
175
+ const gitArgs = buildGitFilesArgs(wuId);
176
+ // eslint-disable-next-line sonarjs/no-os-command-from-path -- git resolved from PATH; CLI tool requires git
177
+ const output = execFileSync('git', gitArgs, {
178
+ encoding: FILE_SYSTEM.ENCODING,
179
+ });
180
+ // In-process dedup and sort (replaces shell `| sort -u`)
181
+ const files = output
182
+ .trim()
183
+ .split('\n')
184
+ .filter((f) => f.length > 0);
185
+ return [...new Set(files)].sort();
186
+ }
187
+ catch {
188
+ return [];
189
+ }
190
+ }
191
+ /**
192
+ * Get WU info from YAML file
193
+ */
194
+ function getWuInfo(wuId) {
195
+ // WU-1301: Use config-based paths
196
+ const yamlPath = join(process.cwd(), WU_PATHS.WU(wuId));
197
+ if (!existsSync(yamlPath)) {
198
+ return null;
199
+ }
200
+ try {
201
+ const content = readFileSync(yamlPath, { encoding: FILE_SYSTEM.ENCODING });
202
+ const yaml = parseYaml(content);
203
+ return {
204
+ title: yaml?.title || wuId,
205
+ status: yaml?.status || 'unknown',
206
+ };
207
+ }
208
+ catch {
209
+ return null;
210
+ }
211
+ }
212
+ /**
213
+ * Format trace report as JSON
214
+ */
215
+ function formatJson(entries) {
216
+ return JSON.stringify(entries, null, JSON_INDENT);
217
+ }
218
+ /**
219
+ * Format trace report as Markdown
220
+ */
221
+ function formatMarkdown(entries) {
222
+ const lines = [
223
+ '# Traceability Report',
224
+ '',
225
+ `Generated: ${new Date().toISOString()}`,
226
+ '',
227
+ '## WU Summary',
228
+ '',
229
+ '| WU ID | Title | Status | Commits | Files |',
230
+ '|-------|-------|--------|---------|-------|',
231
+ ];
232
+ for (const entry of entries) {
233
+ lines.push(`| ${entry.wuId} | ${entry.title.slice(0, MARKDOWN_TABLE_TITLE_LENGTH)} | ${entry.status} | ${entry.commitCount} | ${entry.fileCount} |`);
234
+ }
235
+ lines.push('', '## Details', '');
236
+ for (const entry of entries) {
237
+ lines.push(`### ${entry.wuId}: ${entry.title}`, '');
238
+ lines.push(`- **Status:** ${entry.status}`);
239
+ lines.push(`- **Commits:** ${entry.commitCount}`);
240
+ lines.push(`- **Files:** ${entry.fileCount}`);
241
+ if (entry.firstCommit) {
242
+ lines.push(`- **First commit:** ${entry.firstCommit}`);
243
+ lines.push(`- **Last commit:** ${entry.lastCommit}`);
244
+ }
245
+ if (entry.files && entry.files.length > 0) {
246
+ lines.push('', '**Files changed:**');
247
+ for (const file of entry.files.slice(0, TRACE_FILES_DISPLAY_LIMIT)) {
248
+ lines.push(`- ${file}`);
249
+ }
250
+ if (entry.files.length > TRACE_FILES_DISPLAY_LIMIT) {
251
+ lines.push(`- ... and ${entry.files.length - TRACE_FILES_DISPLAY_LIMIT} more`);
252
+ }
253
+ }
254
+ lines.push('');
255
+ }
256
+ return lines.join('\n');
257
+ }
258
+ /**
259
+ * Format trace report as CSV
260
+ */
261
+ function formatCsv(entries) {
262
+ const lines = ['WU ID,Title,Status,Commits,Files,First Commit,Last Commit'];
263
+ for (const entry of entries) {
264
+ const title = entry.title.replace(/,/g, ';');
265
+ lines.push(`${entry.wuId},"${title}",${entry.status},${entry.commitCount},${entry.fileCount},${entry.firstCommit || ''},${entry.lastCommit || ''}`);
266
+ }
267
+ return lines.join('\n');
268
+ }
269
+ /**
270
+ * Print help message for trace-gen
271
+ */
272
+ /* istanbul ignore next -- CLI entry point */
273
+ function printHelp() {
274
+ console.log(`
275
+ Usage: trace-gen [options]
276
+
277
+ Generate traceability reports linking WUs to code changes.
278
+
279
+ Options:
280
+ -w, --wu <id> Trace specific WU (otherwise traces all)
281
+ -f, --format <fmt> Output format: json, markdown, csv (default: json)
282
+ -o, --output <file> Write output to file (default: stdout)
283
+ -s, --since <date> Only trace WUs modified since date (ISO format)
284
+ -h, --help Show this help message
285
+
286
+ Examples:
287
+ trace:gen --wu WU-1112 # Trace single WU
288
+ trace:gen --format markdown --output report.md # Markdown report
289
+ trace:gen --since 2024-01-01 --format csv # CSV report since date
290
+
291
+ Output includes:
292
+ - WU ID and title
293
+ - Status
294
+ - Number of commits
295
+ - Number of files changed
296
+ - First and last commit dates
297
+ - List of changed files
298
+ `);
299
+ }
300
+ /**
301
+ * Main entry point for trace-gen command
302
+ */
303
+ /* istanbul ignore next -- CLI entry point */
304
+ async function main() {
305
+ const args = parseTraceArgs(process.argv);
306
+ if (args.help) {
307
+ printHelp();
308
+ process.exit(EXIT_CODES.SUCCESS);
309
+ }
310
+ // WU-1534: Validate WU ID if provided
311
+ if (args.wuId && !validateWuId(args.wuId)) {
312
+ console.error(`${LOG_PREFIX} Error: Invalid WU ID format: ${args.wuId}`);
313
+ console.error(`${LOG_PREFIX} Expected format: WU-<number> (e.g., WU-1112)`);
314
+ process.exit(EXIT_CODES.ERROR);
315
+ }
316
+ const format = args.format || TraceFormat.JSON;
317
+ const entries = [];
318
+ if (args.wuId) {
319
+ // Trace single WU
320
+ console.error(`${LOG_PREFIX} Tracing ${args.wuId}...`);
321
+ const info = getWuInfo(args.wuId);
322
+ if (!info) {
323
+ console.error(`${LOG_PREFIX} Error: WU ${args.wuId} not found`);
324
+ process.exit(EXIT_CODES.ERROR);
325
+ }
326
+ const commits = getWuCommits(args.wuId);
327
+ const files = getWuFiles(args.wuId);
328
+ entries.push(buildTraceEntry({
329
+ wuId: args.wuId,
330
+ title: info.title,
331
+ status: info.status,
332
+ commits,
333
+ files,
334
+ }));
335
+ }
336
+ else {
337
+ // Trace all WUs
338
+ console.error(`${LOG_PREFIX} Scanning all WUs...`);
339
+ // WU-1301: Use config-based paths
340
+ const wuDir = join(process.cwd(), WU_PATHS.WU_DIR());
341
+ if (!existsSync(wuDir)) {
342
+ console.error(`${LOG_PREFIX} Error: WU directory not found`);
343
+ process.exit(EXIT_CODES.ERROR);
344
+ }
345
+ const files = readdirSync(wuDir);
346
+ for (const file of files) {
347
+ if (!file.endsWith('.yaml') && !file.endsWith('.yml'))
348
+ continue;
349
+ const wuId = file.replace(/\.ya?ml$/, '');
350
+ const info = getWuInfo(wuId);
351
+ if (!info)
352
+ continue;
353
+ // Filter by since date if specified
354
+ if (args.since) {
355
+ const commits = getWuCommits(wuId);
356
+ if (commits.length === 0)
357
+ continue;
358
+ const lastCommitDate = new Date(commits[commits.length - 1]?.date || 0);
359
+ if (lastCommitDate < new Date(args.since))
360
+ continue;
361
+ }
362
+ const commits = getWuCommits(wuId);
363
+ const wuFiles = getWuFiles(wuId);
364
+ entries.push(buildTraceEntry({
365
+ wuId,
366
+ title: info.title,
367
+ status: info.status,
368
+ commits,
369
+ files: wuFiles,
370
+ }));
371
+ }
372
+ console.error(`${LOG_PREFIX} Found ${entries.length} WU(s)`);
373
+ }
374
+ // Format output
375
+ let output;
376
+ switch (format) {
377
+ case TraceFormat.MARKDOWN:
378
+ output = formatMarkdown(entries);
379
+ break;
380
+ case TraceFormat.CSV:
381
+ output = formatCsv(entries);
382
+ break;
383
+ case TraceFormat.JSON:
384
+ default:
385
+ output = formatJson(entries);
386
+ break;
387
+ }
388
+ // Write output
389
+ if (args.output) {
390
+ writeFileSync(args.output, output, { encoding: FILE_SYSTEM.ENCODING });
391
+ console.error(`${LOG_PREFIX} Report written to ${args.output}`);
392
+ }
393
+ else {
394
+ console.log(output);
395
+ }
396
+ }
397
+ // Run main if executed directly
398
+ if (import.meta.main) {
399
+ void runCLI(main);
400
+ }
401
+ //# sourceMappingURL=trace-gen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-gen.js","sourceRoot":"","sources":["../src/trace-gen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env node
2
+ // Copyright (c) 2026 Hellmai Ltd
3
+ // SPDX-License-Identifier: AGPL-3.0-only
4
+ /**
5
+ * @file validate-agent-skills.ts
6
+ * @description Validates agent skill definitions (WU-1111)
7
+ *
8
+ * Validates that skill files in .claude/skills/ follow the expected format
9
+ * and contain required sections.
10
+ *
11
+ * Usage:
12
+ * validate-agent-skills # Validate all skills
13
+ * validate-agent-skills --skill wu-lifecycle # Validate specific skill
14
+ *
15
+ * Exit codes:
16
+ * 0 - All skills valid
17
+ * 1 - Validation errors found
18
+ *
19
+ * @see {@link .claude/skills/} - Skill definitions
20
+ */
21
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
22
+ import path from 'node:path';
23
+ import { FILE_SYSTEM, EMOJI } from '@lumenflow/core/wu-constants';
24
+ import { runCLI } from './cli-entry-point.js';
25
+ import { MIN_SKILL_CONTENT_LENGTH } from './constants.js';
26
+ const LOG_PREFIX = '[validate-agent-skills]';
27
+ /**
28
+ * Required sections in a skill file
29
+ */
30
+ const REQUIRED_SECTIONS = ['When to Use'];
31
+ /**
32
+ * Recommended sections (produce warnings if missing)
33
+ */
34
+ const RECOMMENDED_SECTIONS = ['Examples', 'Key Concepts', 'Core Concepts'];
35
+ /**
36
+ * Validate a single skill file
37
+ *
38
+ * @param skillPath - Path to SKILL.md file
39
+ * @returns Validation result
40
+ */
41
+ export function validateSkillFile(skillPath) {
42
+ const errors = [];
43
+ const warnings = [];
44
+ if (!existsSync(skillPath)) {
45
+ errors.push(`Skill file not found: ${skillPath}`);
46
+ return { valid: false, errors, warnings };
47
+ }
48
+ const content = readFileSync(skillPath, { encoding: FILE_SYSTEM.UTF8 });
49
+ const lines = content.split('\n');
50
+ // Check for title heading
51
+ const hasTitle = lines.some((line) => line.startsWith('# '));
52
+ if (!hasTitle) {
53
+ errors.push('Missing title heading (# Skill Name)');
54
+ }
55
+ // Check for required sections
56
+ for (const section of REQUIRED_SECTIONS) {
57
+ // eslint-disable-next-line security/detect-non-literal-regexp -- section name from internal constant array, not user input
58
+ const sectionPattern = new RegExp(`^##\\s+${section}`, 'im');
59
+ if (!sectionPattern.test(content)) {
60
+ errors.push(`Missing required section: "## ${section}"`);
61
+ }
62
+ }
63
+ // Check for recommended sections
64
+ for (const section of RECOMMENDED_SECTIONS) {
65
+ // eslint-disable-next-line security/detect-non-literal-regexp -- section name from internal constant array, not user input
66
+ const sectionPattern = new RegExp(`^##\\s+${section}`, 'im');
67
+ if (!sectionPattern.test(content)) {
68
+ warnings.push(`Missing recommended section: "## ${section}"`);
69
+ }
70
+ }
71
+ // Check for minimum content
72
+ if (content.length < MIN_SKILL_CONTENT_LENGTH) {
73
+ warnings.push(`Skill content is very short (< ${MIN_SKILL_CONTENT_LENGTH} characters)`);
74
+ }
75
+ return {
76
+ valid: errors.length === 0,
77
+ errors,
78
+ warnings,
79
+ };
80
+ }
81
+ /**
82
+ * Validate all skills in a directory
83
+ *
84
+ * @param skillsDir - Path to skills directory
85
+ * @returns Validation summary
86
+ */
87
+ export function validateAllSkills(skillsDir) {
88
+ const results = [];
89
+ let totalValid = 0;
90
+ let totalInvalid = 0;
91
+ if (!existsSync(skillsDir)) {
92
+ return {
93
+ totalValid: 0,
94
+ totalInvalid: 1,
95
+ results: [
96
+ {
97
+ skillName: 'DIRECTORY',
98
+ valid: false,
99
+ errors: [`Skills directory not found: ${skillsDir}`],
100
+ warnings: [],
101
+ },
102
+ ],
103
+ };
104
+ }
105
+ const entries = readdirSync(skillsDir);
106
+ for (const entry of entries) {
107
+ const entryPath = path.join(skillsDir, entry);
108
+ const stat = statSync(entryPath);
109
+ if (!stat.isDirectory()) {
110
+ continue;
111
+ }
112
+ // Check for SKILL.md in the skill directory
113
+ const skillFile = path.join(entryPath, 'SKILL.md');
114
+ if (!existsSync(skillFile)) {
115
+ results.push({
116
+ skillName: entry,
117
+ valid: false,
118
+ errors: [`Missing SKILL.md in ${entry}/`],
119
+ warnings: [],
120
+ });
121
+ totalInvalid++;
122
+ continue;
123
+ }
124
+ const result = validateSkillFile(skillFile);
125
+ results.push({ skillName: entry, ...result });
126
+ if (result.valid) {
127
+ totalValid++;
128
+ }
129
+ else {
130
+ totalInvalid++;
131
+ }
132
+ }
133
+ return { totalValid, totalInvalid, results };
134
+ }
135
+ /**
136
+ * Get default skills directory based on cwd
137
+ */
138
+ function getDefaultSkillsDir() {
139
+ return path.join(process.cwd(), '.claude', 'skills');
140
+ }
141
+ /**
142
+ * Main CLI entry point
143
+ */
144
+ export async function main() {
145
+ const args = process.argv.slice(2);
146
+ // Parse arguments
147
+ let skillName;
148
+ let skillsDir = getDefaultSkillsDir();
149
+ for (let i = 0; i < args.length; i++) {
150
+ const arg = args[i];
151
+ if (arg === '--skill' || arg === '-s') {
152
+ skillName = args[++i];
153
+ }
154
+ else if (arg === '--dir' || arg === '-d') {
155
+ skillsDir = args[++i];
156
+ }
157
+ else if (arg === '--help' || arg === '-h') {
158
+ console.log(`Usage: validate-agent-skills [options]
159
+
160
+ Validate agent skill definitions.
161
+
162
+ Options:
163
+ --skill, -s NAME Validate specific skill
164
+ --dir, -d DIR Skills directory (default: .claude/skills)
165
+ -h, --help Show this help message
166
+
167
+ Examples:
168
+ validate-agent-skills # Validate all skills
169
+ validate-agent-skills --skill wu-lifecycle # Validate specific skill
170
+ `);
171
+ process.exit(0);
172
+ }
173
+ }
174
+ if (skillName) {
175
+ // Validate specific skill
176
+ const skillPath = path.join(skillsDir, skillName, 'SKILL.md');
177
+ console.log(`${LOG_PREFIX} Validating skill: ${skillName}...`);
178
+ const result = validateSkillFile(skillPath);
179
+ if (result.errors.length > 0) {
180
+ console.log(`${EMOJI.FAILURE} Validation failed:`);
181
+ result.errors.forEach((e) => console.log(` ${e}`));
182
+ }
183
+ if (result.warnings.length > 0) {
184
+ console.log(`${EMOJI.WARNING} Warnings:`);
185
+ result.warnings.forEach((w) => console.log(` ${w}`));
186
+ }
187
+ if (result.valid) {
188
+ console.log(`${EMOJI.SUCCESS} ${skillName} is valid`);
189
+ }
190
+ else {
191
+ process.exit(1);
192
+ }
193
+ }
194
+ else {
195
+ // Validate all skills
196
+ console.log(`${LOG_PREFIX} Validating all skills in ${skillsDir}...`);
197
+ const { totalValid, totalInvalid, results } = validateAllSkills(skillsDir);
198
+ // Print results
199
+ for (const result of results) {
200
+ if (result.errors.length > 0) {
201
+ console.log(`${EMOJI.FAILURE} ${result.skillName}:`);
202
+ result.errors.forEach((e) => console.log(` ${e}`));
203
+ }
204
+ if (result.warnings.length > 0) {
205
+ console.log(`${EMOJI.WARNING} ${result.skillName}: ${result.warnings.length} warning(s)`);
206
+ }
207
+ }
208
+ console.log('');
209
+ console.log(`${LOG_PREFIX} Summary:`);
210
+ console.log(` ${EMOJI.SUCCESS} Valid: ${totalValid}`);
211
+ console.log(` ${EMOJI.FAILURE} Invalid: ${totalInvalid}`);
212
+ if (totalInvalid > 0) {
213
+ process.exit(1);
214
+ }
215
+ }
216
+ }
217
+ // WU-1181: Use import.meta.main instead of process.argv[1] comparison
218
+ // The old pattern fails with pnpm symlinks because process.argv[1] is the symlink
219
+ // path but import.meta.url resolves to the real path - they never match
220
+ // WU-1537: Use import.meta.main + runCLI for consistent EPIPE and error handling
221
+ if (import.meta.main) {
222
+ void runCLI(main);
223
+ }
224
+ //# sourceMappingURL=validate-agent-skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-agent-skills.js","sourceRoot":"","sources":["../src/validate-agent-skills.ts"],"names":[],"mappings":"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"}