@kamilmarzynski/scifi 0.1.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 (257) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +232 -0
  3. package/dist/skills/sf-bug/manifest.d.ts +2 -0
  4. package/dist/skills/sf-bug/manifest.js +6 -0
  5. package/dist/skills/sf-bug/manifest.js.map +1 -0
  6. package/dist/skills/sf-change/manifest.d.ts +2 -0
  7. package/dist/skills/sf-change/manifest.js +6 -0
  8. package/dist/skills/sf-change/manifest.js.map +1 -0
  9. package/dist/skills/sf-code-review/manifest.d.ts +2 -0
  10. package/dist/skills/sf-code-review/manifest.js +5 -0
  11. package/dist/skills/sf-code-review/manifest.js.map +1 -0
  12. package/dist/skills/sf-continue/manifest.d.ts +2 -0
  13. package/dist/skills/sf-continue/manifest.js +6 -0
  14. package/dist/skills/sf-continue/manifest.js.map +1 -0
  15. package/dist/skills/sf-feature/manifest.d.ts +2 -0
  16. package/dist/skills/sf-feature/manifest.js +6 -0
  17. package/dist/skills/sf-feature/manifest.js.map +1 -0
  18. package/dist/skills/sf-fix/manifest.d.ts +2 -0
  19. package/dist/skills/sf-fix/manifest.js +6 -0
  20. package/dist/skills/sf-fix/manifest.js.map +1 -0
  21. package/dist/skills/sf-handover/manifest.d.ts +2 -0
  22. package/dist/skills/sf-handover/manifest.js +5 -0
  23. package/dist/skills/sf-handover/manifest.js.map +1 -0
  24. package/dist/skills/sf-implement/manifest.d.ts +2 -0
  25. package/dist/skills/sf-implement/manifest.js +6 -0
  26. package/dist/skills/sf-implement/manifest.js.map +1 -0
  27. package/dist/skills/sf-plan/manifest.d.ts +2 -0
  28. package/dist/skills/sf-plan/manifest.js +6 -0
  29. package/dist/skills/sf-plan/manifest.js.map +1 -0
  30. package/dist/skills/sf-plan-review/manifest.d.ts +2 -0
  31. package/dist/skills/sf-plan-review/manifest.js +5 -0
  32. package/dist/skills/sf-plan-review/manifest.js.map +1 -0
  33. package/dist/skills/sf-receiving-review/manifest.d.ts +2 -0
  34. package/dist/skills/sf-receiving-review/manifest.js +5 -0
  35. package/dist/skills/sf-receiving-review/manifest.js.map +1 -0
  36. package/dist/skills/sf-spec-review/manifest.d.ts +2 -0
  37. package/dist/skills/sf-spec-review/manifest.js +5 -0
  38. package/dist/skills/sf-spec-review/manifest.js.map +1 -0
  39. package/dist/skills/sf-tdd/manifest.d.ts +2 -0
  40. package/dist/skills/sf-tdd/manifest.js +5 -0
  41. package/dist/skills/sf-tdd/manifest.js.map +1 -0
  42. package/dist/skills/sf-verification/manifest.d.ts +2 -0
  43. package/dist/skills/sf-verification/manifest.js +5 -0
  44. package/dist/skills/sf-verification/manifest.js.map +1 -0
  45. package/dist/src/cli/commands/bug.d.ts +2 -0
  46. package/dist/src/cli/commands/bug.js +58 -0
  47. package/dist/src/cli/commands/bug.js.map +1 -0
  48. package/dist/src/cli/commands/finish.d.ts +2 -0
  49. package/dist/src/cli/commands/finish.js +43 -0
  50. package/dist/src/cli/commands/finish.js.map +1 -0
  51. package/dist/src/cli/commands/fix.d.ts +2 -0
  52. package/dist/src/cli/commands/fix.js +60 -0
  53. package/dist/src/cli/commands/fix.js.map +1 -0
  54. package/dist/src/cli/commands/init.d.ts +2 -0
  55. package/dist/src/cli/commands/init.js +92 -0
  56. package/dist/src/cli/commands/init.js.map +1 -0
  57. package/dist/src/cli/commands/list.d.ts +2 -0
  58. package/dist/src/cli/commands/list.js +52 -0
  59. package/dist/src/cli/commands/list.js.map +1 -0
  60. package/dist/src/cli/commands/plan-ready.d.ts +2 -0
  61. package/dist/src/cli/commands/plan-ready.js +27 -0
  62. package/dist/src/cli/commands/plan-ready.js.map +1 -0
  63. package/dist/src/cli/commands/plan.d.ts +2 -0
  64. package/dist/src/cli/commands/plan.js +43 -0
  65. package/dist/src/cli/commands/plan.js.map +1 -0
  66. package/dist/src/cli/commands/spec-ready.d.ts +2 -0
  67. package/dist/src/cli/commands/spec-ready.js +27 -0
  68. package/dist/src/cli/commands/spec-ready.js.map +1 -0
  69. package/dist/src/cli/commands/spec.d.ts +2 -0
  70. package/dist/src/cli/commands/spec.js +46 -0
  71. package/dist/src/cli/commands/spec.js.map +1 -0
  72. package/dist/src/cli/commands/start.d.ts +2 -0
  73. package/dist/src/cli/commands/start.js +27 -0
  74. package/dist/src/cli/commands/start.js.map +1 -0
  75. package/dist/src/cli/commands/status.d.ts +2 -0
  76. package/dist/src/cli/commands/status.js +62 -0
  77. package/dist/src/cli/commands/status.js.map +1 -0
  78. package/dist/src/cli/commands/task.d.ts +2 -0
  79. package/dist/src/cli/commands/task.js +64 -0
  80. package/dist/src/cli/commands/task.js.map +1 -0
  81. package/dist/src/cli/commands/worktree.d.ts +2 -0
  82. package/dist/src/cli/commands/worktree.js +33 -0
  83. package/dist/src/cli/commands/worktree.js.map +1 -0
  84. package/dist/src/cli/index.d.ts +3 -0
  85. package/dist/src/cli/index.js +106 -0
  86. package/dist/src/cli/index.js.map +1 -0
  87. package/dist/src/core/bugs/create.d.ts +13 -0
  88. package/dist/src/core/bugs/create.js +28 -0
  89. package/dist/src/core/bugs/create.js.map +1 -0
  90. package/dist/src/core/bugs/frontmatter.d.ts +7 -0
  91. package/dist/src/core/bugs/frontmatter.js +65 -0
  92. package/dist/src/core/bugs/frontmatter.js.map +1 -0
  93. package/dist/src/core/bugs/id.d.ts +1 -0
  94. package/dist/src/core/bugs/id.js +4 -0
  95. package/dist/src/core/bugs/id.js.map +1 -0
  96. package/dist/src/core/bugs/paths.d.ts +2 -0
  97. package/dist/src/core/bugs/paths.js +8 -0
  98. package/dist/src/core/bugs/paths.js.map +1 -0
  99. package/dist/src/core/bugs/types.d.ts +12 -0
  100. package/dist/src/core/bugs/types.js +3 -0
  101. package/dist/src/core/bugs/types.js.map +1 -0
  102. package/dist/src/core/fixes/create.d.ts +11 -0
  103. package/dist/src/core/fixes/create.js +43 -0
  104. package/dist/src/core/fixes/create.js.map +1 -0
  105. package/dist/src/core/fixes/frontmatter.d.ts +7 -0
  106. package/dist/src/core/fixes/frontmatter.js +50 -0
  107. package/dist/src/core/fixes/frontmatter.js.map +1 -0
  108. package/dist/src/core/fixes/id.d.ts +1 -0
  109. package/dist/src/core/fixes/id.js +4 -0
  110. package/dist/src/core/fixes/id.js.map +1 -0
  111. package/dist/src/core/fixes/list.d.ts +8 -0
  112. package/dist/src/core/fixes/list.js +43 -0
  113. package/dist/src/core/fixes/list.js.map +1 -0
  114. package/dist/src/core/fixes/paths.d.ts +2 -0
  115. package/dist/src/core/fixes/paths.js +9 -0
  116. package/dist/src/core/fixes/paths.js.map +1 -0
  117. package/dist/src/core/fixes/transition.d.ts +9 -0
  118. package/dist/src/core/fixes/transition.js +26 -0
  119. package/dist/src/core/fixes/transition.js.map +1 -0
  120. package/dist/src/core/fixes/types.d.ts +9 -0
  121. package/dist/src/core/fixes/types.js +2 -0
  122. package/dist/src/core/fixes/types.js.map +1 -0
  123. package/dist/src/core/init/config.d.ts +6 -0
  124. package/dist/src/core/init/config.js +18 -0
  125. package/dist/src/core/init/config.js.map +1 -0
  126. package/dist/src/core/init/install-skills.d.ts +8 -0
  127. package/dist/src/core/init/install-skills.js +14 -0
  128. package/dist/src/core/init/install-skills.js.map +1 -0
  129. package/dist/src/core/init/prompt-harness.d.ts +8 -0
  130. package/dist/src/core/init/prompt-harness.js +19 -0
  131. package/dist/src/core/init/prompt-harness.js.map +1 -0
  132. package/dist/src/core/init/scaffold.d.ts +5 -0
  133. package/dist/src/core/init/scaffold.js +91 -0
  134. package/dist/src/core/init/scaffold.js.map +1 -0
  135. package/dist/src/core/init/types.d.ts +5 -0
  136. package/dist/src/core/init/types.js +2 -0
  137. package/dist/src/core/init/types.js.map +1 -0
  138. package/dist/src/core/output/emit.d.ts +8 -0
  139. package/dist/src/core/output/emit.js +50 -0
  140. package/dist/src/core/output/emit.js.map +1 -0
  141. package/dist/src/core/output/errors.d.ts +14 -0
  142. package/dist/src/core/output/errors.js +36 -0
  143. package/dist/src/core/output/errors.js.map +1 -0
  144. package/dist/src/core/output/index.d.ts +4 -0
  145. package/dist/src/core/output/index.js +4 -0
  146. package/dist/src/core/output/index.js.map +1 -0
  147. package/dist/src/core/output/tty.d.ts +1 -0
  148. package/dist/src/core/output/tty.js +4 -0
  149. package/dist/src/core/output/tty.js.map +1 -0
  150. package/dist/src/core/package-root.d.ts +1 -0
  151. package/dist/src/core/package-root.js +18 -0
  152. package/dist/src/core/package-root.js.map +1 -0
  153. package/dist/src/core/skills/catalog.d.ts +6 -0
  154. package/dist/src/core/skills/catalog.js +69 -0
  155. package/dist/src/core/skills/catalog.js.map +1 -0
  156. package/dist/src/core/skills/harness/adapter.d.ts +15 -0
  157. package/dist/src/core/skills/harness/adapter.js +31 -0
  158. package/dist/src/core/skills/harness/adapter.js.map +1 -0
  159. package/dist/src/core/skills/harness/claude-code.d.ts +2 -0
  160. package/dist/src/core/skills/harness/claude-code.js +37 -0
  161. package/dist/src/core/skills/harness/claude-code.js.map +1 -0
  162. package/dist/src/core/skills/harness/register-defaults.d.ts +1 -0
  163. package/dist/src/core/skills/harness/register-defaults.js +4 -0
  164. package/dist/src/core/skills/harness/register-defaults.js.map +1 -0
  165. package/dist/src/core/skills/harness/registry.d.ts +3 -0
  166. package/dist/src/core/skills/harness/registry.js +22 -0
  167. package/dist/src/core/skills/harness/registry.js.map +1 -0
  168. package/dist/src/core/skills/types.d.ts +18 -0
  169. package/dist/src/core/skills/types.js +9 -0
  170. package/dist/src/core/skills/types.js.map +1 -0
  171. package/dist/src/core/slugify.d.ts +2 -0
  172. package/dist/src/core/slugify.js +13 -0
  173. package/dist/src/core/slugify.js.map +1 -0
  174. package/dist/src/core/specs/create.d.ts +11 -0
  175. package/dist/src/core/specs/create.js +35 -0
  176. package/dist/src/core/specs/create.js.map +1 -0
  177. package/dist/src/core/specs/id.d.ts +1 -0
  178. package/dist/src/core/specs/id.js +4 -0
  179. package/dist/src/core/specs/id.js.map +1 -0
  180. package/dist/src/core/specs/lifecycle.d.ts +17 -0
  181. package/dist/src/core/specs/lifecycle.js +97 -0
  182. package/dist/src/core/specs/lifecycle.js.map +1 -0
  183. package/dist/src/core/specs/list.d.ts +6 -0
  184. package/dist/src/core/specs/list.js +43 -0
  185. package/dist/src/core/specs/list.js.map +1 -0
  186. package/dist/src/core/specs/metadata.d.ts +3 -0
  187. package/dist/src/core/specs/metadata.js +13 -0
  188. package/dist/src/core/specs/metadata.js.map +1 -0
  189. package/dist/src/core/specs/paths.d.ts +3 -0
  190. package/dist/src/core/specs/paths.js +13 -0
  191. package/dist/src/core/specs/paths.js.map +1 -0
  192. package/dist/src/core/specs/plan-session.d.ts +18 -0
  193. package/dist/src/core/specs/plan-session.js +24 -0
  194. package/dist/src/core/specs/plan-session.js.map +1 -0
  195. package/dist/src/core/specs/transition.d.ts +8 -0
  196. package/dist/src/core/specs/transition.js +33 -0
  197. package/dist/src/core/specs/transition.js.map +1 -0
  198. package/dist/src/core/specs/types.d.ts +17 -0
  199. package/dist/src/core/specs/types.js +8 -0
  200. package/dist/src/core/specs/types.js.map +1 -0
  201. package/dist/src/core/specs/worktree.d.ts +10 -0
  202. package/dist/src/core/specs/worktree.js +32 -0
  203. package/dist/src/core/specs/worktree.js.map +1 -0
  204. package/dist/src/core/tasks/frontmatter.d.ts +7 -0
  205. package/dist/src/core/tasks/frontmatter.js +53 -0
  206. package/dist/src/core/tasks/frontmatter.js.map +1 -0
  207. package/dist/src/core/tasks/list.d.ts +2 -0
  208. package/dist/src/core/tasks/list.js +18 -0
  209. package/dist/src/core/tasks/list.js.map +1 -0
  210. package/dist/src/core/tasks/paths.d.ts +2 -0
  211. package/dist/src/core/tasks/paths.js +11 -0
  212. package/dist/src/core/tasks/paths.js.map +1 -0
  213. package/dist/src/core/tasks/transition.d.ts +8 -0
  214. package/dist/src/core/tasks/transition.js +30 -0
  215. package/dist/src/core/tasks/transition.js.map +1 -0
  216. package/dist/src/core/tasks/types.d.ts +8 -0
  217. package/dist/src/core/tasks/types.js +2 -0
  218. package/dist/src/core/tasks/types.js.map +1 -0
  219. package/package.json +67 -0
  220. package/skills/sf-bug/DISPATCH-CODE-REVIEW.md +22 -0
  221. package/skills/sf-bug/body.md +117 -0
  222. package/skills/sf-bug/manifest.ts +8 -0
  223. package/skills/sf-change/body.md +178 -0
  224. package/skills/sf-change/manifest.ts +8 -0
  225. package/skills/sf-code-review/body.md +155 -0
  226. package/skills/sf-code-review/manifest.ts +7 -0
  227. package/skills/sf-continue/body.md +90 -0
  228. package/skills/sf-continue/manifest.ts +8 -0
  229. package/skills/sf-feature/ADR-TEMPLATE.md +16 -0
  230. package/skills/sf-feature/DISPATCH-SPEC-REVIEW.md +16 -0
  231. package/skills/sf-feature/SPEC-TEMPLATE.md +37 -0
  232. package/skills/sf-feature/body.md +145 -0
  233. package/skills/sf-feature/manifest.ts +8 -0
  234. package/skills/sf-fix/DISPATCH-CODE-REVIEW.md +25 -0
  235. package/skills/sf-fix/body.md +174 -0
  236. package/skills/sf-fix/manifest.ts +8 -0
  237. package/skills/sf-handover/body.md +67 -0
  238. package/skills/sf-handover/manifest.ts +7 -0
  239. package/skills/sf-implement/DISPATCH-CODE-REVIEW.md +19 -0
  240. package/skills/sf-implement/DISPATCH-HANDOVER.md +19 -0
  241. package/skills/sf-implement/DISPATCH-IMPLEMENTER.md +36 -0
  242. package/skills/sf-implement/body.md +147 -0
  243. package/skills/sf-implement/manifest.ts +8 -0
  244. package/skills/sf-plan/ADR-TEMPLATE.md +16 -0
  245. package/skills/sf-plan/DESIGN-TEMPLATE.md +54 -0
  246. package/skills/sf-plan/DISPATCH-PLAN-REVIEW.md +17 -0
  247. package/skills/sf-plan/TASK-TEMPLATE.md +30 -0
  248. package/skills/sf-plan/body.md +162 -0
  249. package/skills/sf-plan/manifest.ts +8 -0
  250. package/skills/sf-plan-review/body.md +90 -0
  251. package/skills/sf-plan-review/manifest.ts +7 -0
  252. package/skills/sf-receiving-review/body.md +73 -0
  253. package/skills/sf-receiving-review/manifest.ts +7 -0
  254. package/skills/sf-spec-review/body.md +83 -0
  255. package/skills/sf-spec-review/manifest.ts +7 -0
  256. package/skills/sf-tdd/body.md +120 -0
  257. package/skills/sf-tdd/manifest.ts +7 -0
@@ -0,0 +1,33 @@
1
+ import { cwd } from 'node:process';
2
+ import { emitError, emitSuccess, jsonMode } from '../../core/output/index.js';
3
+ import { setFeatureWorktree } from '../../core/specs/worktree.js';
4
+ export function registerWorktreeCommand(program) {
5
+ const worktree = program
6
+ .command('worktree')
7
+ .description('Manage the git branch + worktree pointer recorded on a feature');
8
+ worktree
9
+ .command('set')
10
+ .description('Record the git branch and worktree path backing a feature')
11
+ .argument('<slug>', 'feature folder slug')
12
+ .requiredOption('--branch <branch>', 'git branch backing the feature')
13
+ .requiredOption('--path <path>', 'worktree path backing the feature')
14
+ .option('--json', 'output as structured JSON')
15
+ .action(async (slug, options, command) => {
16
+ const json = jsonMode(command);
17
+ try {
18
+ const result = await setFeatureWorktree(cwd(), slug, {
19
+ branch: options.branch,
20
+ path: options.path,
21
+ });
22
+ emitSuccess({ action: 'worktree-set', ...result }, json, [
23
+ `feature ${result.slug}: worktree recorded`,
24
+ ` branch: ${result.branch}`,
25
+ ` worktree: ${result.worktreePath}`,
26
+ ]);
27
+ }
28
+ catch (error) {
29
+ emitError(error, json);
30
+ }
31
+ });
32
+ }
33
+ //# sourceMappingURL=worktree.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree.js","sourceRoot":"","sources":["../../../../src/cli/commands/worktree.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,UAAU,CAAC;SACnB,WAAW,CAAC,gEAAgE,CAAC,CAAC;IAEjF,QAAQ;SACL,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,2DAA2D,CAAC;SACxE,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;SACzC,cAAc,CAAC,mBAAmB,EAAE,gCAAgC,CAAC;SACrE,cAAc,CAAC,eAAe,EAAE,mCAAmC,CAAC;SACpE,MAAM,CAAC,QAAQ,EAAE,2BAA2B,CAAC;SAC7C,MAAM,CACL,KAAK,EACH,IAAY,EACZ,OAAyD,EACzD,OAAgB,EAChB,EAAE;QACF,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,EAAE,IAAI,EAAE;gBACnD,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,IAAI,EAAE,OAAO,CAAC,IAAI;aACnB,CAAC,CAAC;YACH,WAAW,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,EAAE,EAAE,IAAI,EAAE;gBACvD,WAAW,MAAM,CAAC,IAAI,qBAAqB;gBAC3C,eAAe,MAAM,CAAC,MAAM,EAAE;gBAC9B,eAAe,MAAM,CAAC,YAAY,EAAE;aACrC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,CACF,CAAC;AACN,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function buildProgram(): Command;
3
+ export declare function isDirectExecution(moduleUrl: string, argv: readonly string[]): boolean;
@@ -0,0 +1,106 @@
1
+ #!/usr/bin/env node
2
+ import { existsSync, realpathSync } from 'node:fs';
3
+ import { createRequire } from 'node:module';
4
+ import { join, resolve } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { Command, CommanderError } from 'commander';
7
+ import { ScifiError } from '../core/output/errors.js';
8
+ import { emitError } from '../core/output/index.js';
9
+ import { findPackageRoot } from '../core/package-root.js';
10
+ import { registerFinishCommand } from './commands/finish.js';
11
+ import { registerFixCommand } from './commands/fix.js';
12
+ import { registerInitCommand } from './commands/init.js';
13
+ import { registerListCommand } from './commands/list.js';
14
+ import { registerPlanCommand } from './commands/plan.js';
15
+ import { registerPlanReadyCommand } from './commands/plan-ready.js';
16
+ import { registerSpecCommand } from './commands/spec.js';
17
+ import { registerSpecReadyCommand } from './commands/spec-ready.js';
18
+ import { registerStartCommand } from './commands/start.js';
19
+ import { registerStatusCommand } from './commands/status.js';
20
+ import { registerTaskCommand } from './commands/task.js';
21
+ import { registerWorktreeCommand } from './commands/worktree.js';
22
+ const require = createRequire(import.meta.url);
23
+ const packageJson = require(join(findPackageRoot(import.meta.url), 'package.json'));
24
+ function readPackageVersion(value) {
25
+ if (typeof value === 'object' &&
26
+ value !== null &&
27
+ 'version' in value &&
28
+ typeof value.version === 'string') {
29
+ return value.version;
30
+ }
31
+ throw new Error('Unable to read version from package.json');
32
+ }
33
+ export function buildProgram() {
34
+ const program = new Command();
35
+ program
36
+ .name('scifi')
37
+ .description('Specification-driven CLI scaffolding for agentic workflows')
38
+ .version(readPackageVersion(packageJson))
39
+ .exitOverride();
40
+ registerInitCommand(program);
41
+ registerSpecCommand(program);
42
+ registerSpecReadyCommand(program);
43
+ registerPlanCommand(program);
44
+ registerPlanReadyCommand(program);
45
+ registerStartCommand(program);
46
+ registerFinishCommand(program);
47
+ registerListCommand(program);
48
+ registerStatusCommand(program);
49
+ registerTaskCommand(program);
50
+ registerFixCommand(program);
51
+ registerWorktreeCommand(program);
52
+ applyExitOverride(program);
53
+ return program;
54
+ }
55
+ function applyExitOverride(command) {
56
+ // Suppress Commander's own "error: ..." line so usage failures surface only
57
+ // through the structured emitError output (avoids double-printing).
58
+ command.configureOutput({ writeErr: () => { } });
59
+ for (const child of command.commands) {
60
+ child.exitOverride();
61
+ applyExitOverride(child);
62
+ }
63
+ }
64
+ export function isDirectExecution(moduleUrl, argv) {
65
+ const scriptPath = argv[1];
66
+ if (scriptPath === undefined) {
67
+ return false;
68
+ }
69
+ return normalizeExecutionPath(fileURLToPath(moduleUrl)) === normalizeExecutionPath(scriptPath);
70
+ }
71
+ function normalizeExecutionPath(path) {
72
+ const resolvedPath = resolve(path);
73
+ if (!existsSync(resolvedPath)) {
74
+ return resolvedPath;
75
+ }
76
+ return realpathSync(resolvedPath);
77
+ }
78
+ function handleCliError(error, argv) {
79
+ const json = argv.includes('--json');
80
+ if (error instanceof CommanderError) {
81
+ // Help/version requests exit cleanly; Commander already wrote output.
82
+ if (error.exitCode === 0) {
83
+ process.exitCode = 0;
84
+ return;
85
+ }
86
+ const message = error.message.replace(/^error:\s*/i, '');
87
+ emitError(new ScifiError('INVALID_ARGUMENT', message, {
88
+ hint: 'Run `scifi --help` (or `<command> --help`) for usage.',
89
+ cause: error,
90
+ }), json);
91
+ return;
92
+ }
93
+ emitError(error, json);
94
+ }
95
+ async function runCli(argv) {
96
+ try {
97
+ await buildProgram().parseAsync(argv);
98
+ }
99
+ catch (error) {
100
+ handleCliError(error, argv);
101
+ }
102
+ }
103
+ if (isDirectExecution(import.meta.url, process.argv)) {
104
+ await runCli(process.argv);
105
+ }
106
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { BugSeverity } from './types.js';
2
+ export interface CreateBugOptions {
3
+ projectRoot: string;
4
+ description: string;
5
+ relatedFeature?: string;
6
+ severity?: BugSeverity;
7
+ now: string;
8
+ }
9
+ export interface CreateBugResult {
10
+ id: string;
11
+ filePath: string;
12
+ }
13
+ export declare function createBug(options: CreateBugOptions): Promise<CreateBugResult>;
@@ -0,0 +1,28 @@
1
+ import { mkdir, readdir } from 'node:fs/promises';
2
+ import { slugify } from '../slugify.js';
3
+ import { writeBugFile } from './frontmatter.js';
4
+ import { formatBugId } from './id.js';
5
+ import { buildBugFilePath, buildBugsRootPath } from './paths.js';
6
+ export async function createBug(options) {
7
+ const { projectRoot, description, relatedFeature, severity, now } = options;
8
+ const bugsRoot = buildBugsRootPath(projectRoot);
9
+ await mkdir(bugsRoot, { recursive: true });
10
+ const existing = await readdir(bugsRoot, { withFileTypes: true });
11
+ const mdCount = existing.filter((e) => e.isFile() && e.name.endsWith('.md')).length;
12
+ const id = formatBugId(mdCount + 1);
13
+ const slug = slugify(description);
14
+ const filePath = buildBugFilePath(projectRoot, id, slug);
15
+ await writeBugFile(filePath, {
16
+ frontmatter: {
17
+ id,
18
+ slug,
19
+ status: 'open',
20
+ ...(severity !== undefined && { severity }),
21
+ ...(relatedFeature !== undefined && { 'related-feature': relatedFeature }),
22
+ created: now,
23
+ },
24
+ body: `# ${description}\n`,
25
+ });
26
+ return { id, filePath };
27
+ }
28
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../../src/core/bugs/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAgBjE,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAyB;IACvD,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAC5E,MAAM,QAAQ,GAAG,iBAAiB,CAAC,WAAW,CAAC,CAAC;IAEhD,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAEpF,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IAEzD,MAAM,YAAY,CAAC,QAAQ,EAAE;QAC3B,WAAW,EAAE;YACX,EAAE;YACF,IAAI;YACJ,MAAM,EAAE,MAAM;YACd,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,CAAC;YAC3C,GAAG,CAAC,cAAc,KAAK,SAAS,IAAI,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC;YAC1E,OAAO,EAAE,GAAG;SACb;QACD,IAAI,EAAE,KAAK,WAAW,IAAI;KAC3B,CAAC,CAAC;IAEH,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type BugFrontmatter } from './types.js';
2
+ export interface BugFile {
3
+ frontmatter: BugFrontmatter;
4
+ body: string;
5
+ }
6
+ export declare function readBugFile(filePath: string): Promise<BugFile>;
7
+ export declare function writeBugFile(filePath: string, file: BugFile): Promise<void>;
@@ -0,0 +1,65 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
+ import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
3
+ import { BUG_SEVERITY_VALUES, BUG_STATUS_VALUES, } from './types.js';
4
+ const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
5
+ function isValidBugStatus(value) {
6
+ return typeof value === 'string' && BUG_STATUS_VALUES.includes(value);
7
+ }
8
+ function isValidBugSeverity(value) {
9
+ return typeof value === 'string' && BUG_SEVERITY_VALUES.includes(value);
10
+ }
11
+ function isValidRawBugFrontmatter(raw) {
12
+ if (typeof raw !== 'object' || raw === null)
13
+ return false;
14
+ const obj = raw;
15
+ return (typeof obj.id === 'string' &&
16
+ typeof obj.slug === 'string' &&
17
+ isValidBugStatus(obj.status) &&
18
+ (obj.severity === undefined || isValidBugSeverity(obj.severity)) &&
19
+ (typeof obj['related-feature'] === 'string' || obj['related-feature'] === undefined) &&
20
+ typeof obj.created === 'string');
21
+ }
22
+ export async function readBugFile(filePath) {
23
+ const content = await readFile(filePath, 'utf8');
24
+ const match = FRONTMATTER_PATTERN.exec(content);
25
+ if (!match) {
26
+ throw new Error(`Bug file at ${filePath} is missing YAML frontmatter.`);
27
+ }
28
+ const raw = parseYaml(match[1] ?? '');
29
+ if (!isValidRawBugFrontmatter(raw)) {
30
+ throw new Error(`Bug file at ${filePath} has invalid frontmatter.`);
31
+ }
32
+ const frontmatter = {
33
+ id: raw.id,
34
+ slug: raw.slug,
35
+ status: raw.status,
36
+ created: raw.created,
37
+ };
38
+ if (raw.severity !== undefined) {
39
+ frontmatter.severity = raw.severity;
40
+ }
41
+ if (raw['related-feature'] !== undefined) {
42
+ frontmatter['related-feature'] = raw['related-feature'];
43
+ }
44
+ return {
45
+ frontmatter,
46
+ body: match[2] ?? '',
47
+ };
48
+ }
49
+ export async function writeBugFile(filePath, file) {
50
+ const rawFrontmatter = {
51
+ id: file.frontmatter.id,
52
+ slug: file.frontmatter.slug,
53
+ status: file.frontmatter.status,
54
+ ...(file.frontmatter.severity !== undefined && {
55
+ severity: file.frontmatter.severity,
56
+ }),
57
+ ...(file.frontmatter['related-feature'] !== undefined && {
58
+ 'related-feature': file.frontmatter['related-feature'],
59
+ }),
60
+ created: file.frontmatter.created,
61
+ };
62
+ const content = `---\n${stringifyYaml(rawFrontmatter)}---\n${file.body}`;
63
+ await writeFile(filePath, content, 'utf8');
64
+ }
65
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../../../src/core/bugs/frontmatter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function formatBugId(sequenceNumber: number): string;
@@ -0,0 +1,4 @@
1
+ export function formatBugId(sequenceNumber) {
2
+ return `BUG-${sequenceNumber.toString().padStart(4, '0')}`;
3
+ }
4
+ //# sourceMappingURL=id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.js","sourceRoot":"","sources":["../../../../src/core/bugs/id.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,cAAsB;IAChD,OAAO,OAAO,cAAc,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function buildBugsRootPath(projectRoot: string): string;
2
+ export declare function buildBugFilePath(projectRoot: string, id: string, slug: string): string;
@@ -0,0 +1,8 @@
1
+ import { join } from 'node:path';
2
+ export function buildBugsRootPath(projectRoot) {
3
+ return join(projectRoot, 'bugs');
4
+ }
5
+ export function buildBugFilePath(projectRoot, id, slug) {
6
+ return join(buildBugsRootPath(projectRoot), `${id}-${slug}.md`);
7
+ }
8
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../../src/core/bugs/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,UAAU,iBAAiB,CAAC,WAAmB;IACnD,OAAO,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAmB,EAAE,EAAU,EAAE,IAAY;IAC5E,OAAO,IAAI,CAAC,iBAAiB,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,KAAK,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,12 @@
1
+ export declare const BUG_STATUS_VALUES: readonly ["open", "in-progress", "resolved", "wont-fix"];
2
+ export type BugStatus = (typeof BUG_STATUS_VALUES)[number];
3
+ export declare const BUG_SEVERITY_VALUES: readonly ["low", "medium", "high", "critical"];
4
+ export type BugSeverity = (typeof BUG_SEVERITY_VALUES)[number];
5
+ export interface BugFrontmatter {
6
+ id: string;
7
+ slug: string;
8
+ status: BugStatus;
9
+ severity?: BugSeverity;
10
+ 'related-feature'?: string;
11
+ created: string;
12
+ }
@@ -0,0 +1,3 @@
1
+ export const BUG_STATUS_VALUES = ['open', 'in-progress', 'resolved', 'wont-fix'];
2
+ export const BUG_SEVERITY_VALUES = ['low', 'medium', 'high', 'critical'];
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/bugs/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,CAAU,CAAC;AAI1F,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAU,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface CreateFixOptions {
2
+ projectRoot: string;
3
+ description: string;
4
+ featureSlug: string;
5
+ now: string;
6
+ }
7
+ export interface CreateFixResult {
8
+ id: string;
9
+ filePath: string;
10
+ }
11
+ export declare function createFix(options: CreateFixOptions): Promise<CreateFixResult>;
@@ -0,0 +1,43 @@
1
+ import { mkdir, readdir, stat } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { ScifiError } from '../output/errors.js';
4
+ import { slugify } from '../slugify.js';
5
+ import { buildFeatureDirectoryPath } from '../specs/paths.js';
6
+ import { writeFixFile } from './frontmatter.js';
7
+ import { formatFixId } from './id.js';
8
+ import { buildFixesDirectoryPath, buildFixFilePath } from './paths.js';
9
+ function isMissingPathError(error) {
10
+ return error instanceof Error && 'code' in error && error.code === 'ENOENT';
11
+ }
12
+ export async function createFix(options) {
13
+ const { projectRoot, description, featureSlug, now } = options;
14
+ const featureDir = buildFeatureDirectoryPath(projectRoot, featureSlug);
15
+ const metadataPath = join(featureDir, '.scifi.json');
16
+ await stat(metadataPath).catch((error) => {
17
+ if (isMissingPathError(error)) {
18
+ throw new ScifiError('NOT_FOUND', `Feature "${featureSlug}" does not exist.`, {
19
+ hint: `Create it with \`scifi spec ${featureSlug}\`.`,
20
+ });
21
+ }
22
+ throw error;
23
+ });
24
+ const fixesDir = buildFixesDirectoryPath(projectRoot, featureSlug);
25
+ await mkdir(fixesDir, { recursive: true });
26
+ const existing = await readdir(fixesDir, { withFileTypes: true });
27
+ const mdCount = existing.filter((e) => e.isFile() && e.name.endsWith('.md')).length;
28
+ const id = formatFixId(mdCount + 1);
29
+ const slug = slugify(description);
30
+ const filePath = buildFixFilePath(projectRoot, featureSlug, id, slug);
31
+ await writeFixFile(filePath, {
32
+ frontmatter: {
33
+ id,
34
+ slug,
35
+ status: 'open',
36
+ feature: featureSlug,
37
+ created: now,
38
+ },
39
+ body: `# ${description}\n`,
40
+ });
41
+ return { id, filePath };
42
+ }
43
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../../src/core/fixes/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEvE,SAAS,kBAAkB,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC9E,CAAC;AAcD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAyB;IACvD,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC;IAE/D,MAAM,UAAU,GAAG,yBAAyB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACvE,MAAM,YAAY,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC;IACrD,MAAM,IAAI,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAChD,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,UAAU,CAAC,WAAW,EAAE,YAAY,WAAW,mBAAmB,EAAE;gBAC5E,IAAI,EAAE,+BAA+B,WAAW,KAAK;aACtD,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,uBAAuB,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IACnE,MAAM,KAAK,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE3C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC;IAEpF,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAClC,MAAM,QAAQ,GAAG,gBAAgB,CAAC,WAAW,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;IAEtE,MAAM,YAAY,CAAC,QAAQ,EAAE;QAC3B,WAAW,EAAE;YACX,EAAE;YACF,IAAI;YACJ,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,WAAW;YACpB,OAAO,EAAE,GAAG;SACb;QACD,IAAI,EAAE,KAAK,WAAW,IAAI;KAC3B,CAAC,CAAC;IAEH,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type FixFrontmatter } from './types.js';
2
+ export interface FixFile {
3
+ frontmatter: FixFrontmatter;
4
+ body: string;
5
+ }
6
+ export declare function readFixFile(filePath: string): Promise<FixFile>;
7
+ export declare function writeFixFile(filePath: string, file: FixFile): Promise<void>;
@@ -0,0 +1,50 @@
1
+ import { readFile, writeFile } from 'node:fs/promises';
2
+ import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
3
+ import { FIX_STATUS_VALUES } from './types.js';
4
+ const FRONTMATTER_PATTERN = /^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/;
5
+ function isValidFixStatus(value) {
6
+ return typeof value === 'string' && FIX_STATUS_VALUES.includes(value);
7
+ }
8
+ function isValidRawFixFrontmatter(raw) {
9
+ if (typeof raw !== 'object' || raw === null)
10
+ return false;
11
+ const obj = raw;
12
+ return (typeof obj.id === 'string' &&
13
+ typeof obj.slug === 'string' &&
14
+ isValidFixStatus(obj.status) &&
15
+ typeof obj.feature === 'string' &&
16
+ typeof obj.created === 'string');
17
+ }
18
+ export async function readFixFile(filePath) {
19
+ const content = await readFile(filePath, 'utf8');
20
+ const match = FRONTMATTER_PATTERN.exec(content);
21
+ if (!match) {
22
+ throw new Error(`Fix file at ${filePath} is missing YAML frontmatter.`);
23
+ }
24
+ const raw = parseYaml(match[1] ?? '');
25
+ if (!isValidRawFixFrontmatter(raw)) {
26
+ throw new Error(`Fix file at ${filePath} has invalid frontmatter.`);
27
+ }
28
+ return {
29
+ frontmatter: {
30
+ id: raw.id,
31
+ slug: raw.slug,
32
+ status: raw.status,
33
+ feature: raw.feature,
34
+ created: raw.created,
35
+ },
36
+ body: match[2] ?? '',
37
+ };
38
+ }
39
+ export async function writeFixFile(filePath, file) {
40
+ const rawFrontmatter = {
41
+ id: file.frontmatter.id,
42
+ slug: file.frontmatter.slug,
43
+ status: file.frontmatter.status,
44
+ feature: file.frontmatter.feature,
45
+ created: file.frontmatter.created,
46
+ };
47
+ const content = `---\n${stringifyYaml(rawFrontmatter)}---\n${file.body}`;
48
+ await writeFile(filePath, content, 'utf8');
49
+ }
50
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../../../src/core/fixes/frontmatter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,SAAS,IAAI,aAAa,EAAE,MAAM,MAAM,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAuB,MAAM,YAAY,CAAC;AAOpE,MAAM,mBAAmB,GAAG,4CAA4C,CAAC;AAEzE,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAK,iBAAuC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC/F,CAAC;AAED,SAAS,wBAAwB,CAAC,GAAY;IAC5C,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,MAAM,GAAG,GAAG,GAA8B,CAAC;IAC3C,OAAO,CACL,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ;QAC1B,OAAO,GAAG,CAAC,IAAI,KAAK,QAAQ;QAC5B,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC;QAC5B,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ;QAC/B,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAChC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB;IAChD,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEhD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,+BAA+B,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAY,CAAC;IAEjD,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,2BAA2B,CAAC,CAAC;IACtE,CAAC;IAED,OAAO;QACL,WAAW,EAAE;YACX,EAAE,EAAE,GAAG,CAAC,EAAY;YACpB,IAAI,EAAE,GAAG,CAAC,IAAc;YACxB,MAAM,EAAE,GAAG,CAAC,MAAkC;YAC9C,OAAO,EAAE,GAAG,CAAC,OAAiB;YAC9B,OAAO,EAAE,GAAG,CAAC,OAAiB;SAC/B;QACD,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;KACrB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAgB,EAAE,IAAa;IAChE,MAAM,cAAc,GAA4B;QAC9C,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE;QACvB,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;QAC3B,MAAM,EAAE,IAAI,CAAC,WAAW,CAAC,MAAM;QAC/B,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO;QACjC,OAAO,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO;KAClC,CAAC;IAEF,MAAM,OAAO,GAAG,QAAQ,aAAa,CAAC,cAAc,CAAC,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;IACzE,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function formatFixId(sequenceNumber: number): string;
@@ -0,0 +1,4 @@
1
+ export function formatFixId(sequenceNumber) {
2
+ return `FIX-${sequenceNumber.toString().padStart(4, '0')}`;
3
+ }
4
+ //# sourceMappingURL=id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.js","sourceRoot":"","sources":["../../../../src/core/fixes/id.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,WAAW,CAAC,cAAsB;IAChD,OAAO,OAAO,cAAc,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { FixFrontmatter } from './types.js';
2
+ export interface FixFileLocation {
3
+ filePath: string;
4
+ frontmatter: FixFrontmatter;
5
+ }
6
+ export declare function listFixes(projectRoot: string, featureSlug: string): Promise<FixFrontmatter[]>;
7
+ export declare function listOpenFixes(projectRoot: string, featureSlug: string): Promise<FixFrontmatter[]>;
8
+ export declare function findFixById(projectRoot: string, featureSlug: string, fixId: string): Promise<FixFileLocation | undefined>;
@@ -0,0 +1,43 @@
1
+ import { readdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { readFixFile } from './frontmatter.js';
4
+ import { buildFixesDirectoryPath } from './paths.js';
5
+ function isMissingPathError(error) {
6
+ return error instanceof Error && 'code' in error && error.code === 'ENOENT';
7
+ }
8
+ export async function listFixes(projectRoot, featureSlug) {
9
+ const fixesDir = buildFixesDirectoryPath(projectRoot, featureSlug);
10
+ const entries = await readdir(fixesDir, { withFileTypes: true }).catch((error) => {
11
+ if (isMissingPathError(error))
12
+ return [];
13
+ throw error;
14
+ });
15
+ const mdFiles = entries.filter((e) => e.isFile() && e.name.endsWith('.md'));
16
+ const results = await Promise.all(mdFiles.map(async (entry) => {
17
+ const file = await readFixFile(join(fixesDir, entry.name));
18
+ return file.frontmatter;
19
+ }));
20
+ return results;
21
+ }
22
+ export async function listOpenFixes(projectRoot, featureSlug) {
23
+ const fixes = await listFixes(projectRoot, featureSlug);
24
+ return fixes.filter((f) => f.status === 'open' || f.status === 'in-progress');
25
+ }
26
+ export async function findFixById(projectRoot, featureSlug, fixId) {
27
+ const fixesDir = buildFixesDirectoryPath(projectRoot, featureSlug);
28
+ const entries = await readdir(fixesDir, { withFileTypes: true }).catch((error) => {
29
+ if (isMissingPathError(error))
30
+ return [];
31
+ throw error;
32
+ });
33
+ const mdFiles = entries.filter((e) => e.isFile() && e.name.endsWith('.md'));
34
+ for (const entry of mdFiles) {
35
+ const filePath = join(fixesDir, entry.name);
36
+ const file = await readFixFile(filePath);
37
+ if (file.frontmatter.id === fixId) {
38
+ return { filePath, frontmatter: file.frontmatter };
39
+ }
40
+ }
41
+ return undefined;
42
+ }
43
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../../src/core/fixes/list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function buildFixesDirectoryPath(projectRoot: string, featureSlug: string): string;
2
+ export declare function buildFixFilePath(projectRoot: string, featureSlug: string, id: string, slug: string): string;
@@ -0,0 +1,9 @@
1
+ import { join } from 'node:path';
2
+ import { buildFeatureDirectoryPath } from '../specs/paths.js';
3
+ export function buildFixesDirectoryPath(projectRoot, featureSlug) {
4
+ return join(buildFeatureDirectoryPath(projectRoot, featureSlug), 'fixes');
5
+ }
6
+ export function buildFixFilePath(projectRoot, featureSlug, id, slug) {
7
+ return join(buildFixesDirectoryPath(projectRoot, featureSlug), `${id}-${slug}.md`);
8
+ }
9
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../../src/core/fixes/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAE9D,MAAM,UAAU,uBAAuB,CAAC,WAAmB,EAAE,WAAmB;IAC9E,OAAO,IAAI,CAAC,yBAAyB,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,CAAC;AAC5E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,WAAmB,EACnB,WAAmB,EACnB,EAAU,EACV,IAAY;IAEZ,OAAO,IAAI,CAAC,uBAAuB,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,GAAG,EAAE,IAAI,IAAI,KAAK,CAAC,CAAC;AACrF,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { FixStatus } from './types.js';
2
+ export interface UpdateFixStatusResult {
3
+ featureSlug: string;
4
+ id: string;
5
+ slug: string;
6
+ previousStatus: FixStatus;
7
+ newStatus: FixStatus;
8
+ }
9
+ export declare function updateFixStatus(projectRoot: string, featureSlug: string, fixId: string, targetStatus: FixStatus): Promise<UpdateFixStatusResult>;
@@ -0,0 +1,26 @@
1
+ import { ScifiError } from '../output/errors.js';
2
+ import { readFixFile, writeFixFile } from './frontmatter.js';
3
+ import { findFixById } from './list.js';
4
+ export async function updateFixStatus(projectRoot, featureSlug, fixId, targetStatus) {
5
+ const location = await findFixById(projectRoot, featureSlug, fixId);
6
+ if (location === undefined) {
7
+ throw new ScifiError('NOT_FOUND', `Fix "${fixId}" does not exist in feature "${featureSlug}".`, { hint: "Run `scifi status <slug>` to see this feature's fixes." });
8
+ }
9
+ const previousStatus = location.frontmatter.status;
10
+ if (previousStatus !== 'open' && previousStatus !== 'in-progress') {
11
+ throw new ScifiError('PRECONDITION_FAILED', `Cannot transition fix ${fixId}: it is already ${previousStatus}.`, { hint: 'Only open or in-progress fixes can be resolved or marked wont-fix.' });
12
+ }
13
+ const file = await readFixFile(location.filePath);
14
+ await writeFixFile(location.filePath, {
15
+ ...file,
16
+ frontmatter: { ...file.frontmatter, status: targetStatus },
17
+ });
18
+ return {
19
+ featureSlug,
20
+ id: file.frontmatter.id,
21
+ slug: file.frontmatter.slug,
22
+ previousStatus,
23
+ newStatus: targetStatus,
24
+ };
25
+ }
26
+ //# sourceMappingURL=transition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transition.js","sourceRoot":"","sources":["../../../../src/core/fixes/transition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAWxC,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,WAAmB,EACnB,WAAmB,EACnB,KAAa,EACb,YAAuB;IAEvB,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC;IAEpE,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,MAAM,IAAI,UAAU,CAClB,WAAW,EACX,QAAQ,KAAK,gCAAgC,WAAW,IAAI,EAC5D,EAAE,IAAI,EAAE,wDAAwD,EAAE,CACnE,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC;IAEnD,IAAI,cAAc,KAAK,MAAM,IAAI,cAAc,KAAK,aAAa,EAAE,CAAC;QAClE,MAAM,IAAI,UAAU,CAClB,qBAAqB,EACrB,yBAAyB,KAAK,mBAAmB,cAAc,GAAG,EAClE,EAAE,IAAI,EAAE,oEAAoE,EAAE,CAC/E,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAElD,MAAM,YAAY,CAAC,QAAQ,CAAC,QAAQ,EAAE;QACpC,GAAG,IAAI;QACP,WAAW,EAAE,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE;KAC3D,CAAC,CAAC;IAEH,OAAO;QACL,WAAW;QACX,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,EAAE;QACvB,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,IAAI;QAC3B,cAAc;QACd,SAAS,EAAE,YAAY;KACxB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare const FIX_STATUS_VALUES: readonly ["open", "in-progress", "resolved", "wont-fix"];
2
+ export type FixStatus = (typeof FIX_STATUS_VALUES)[number];
3
+ export interface FixFrontmatter {
4
+ id: string;
5
+ slug: string;
6
+ status: FixStatus;
7
+ feature: string;
8
+ created: string;
9
+ }
@@ -0,0 +1,2 @@
1
+ export const FIX_STATUS_VALUES = ['open', 'in-progress', 'resolved', 'wont-fix'];
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/core/fixes/types.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,UAAU,CAAU,CAAC"}