@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kamil Marzynski
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,232 @@
1
+ # scifi
2
+
3
+ [![CI](https://github.com/KamilMarzynski/sci-fi/actions/workflows/ci.yml/badge.svg)](https://github.com/KamilMarzynski/sci-fi/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE)
5
+ [![Node.js](https://img.shields.io/badge/node-%3E%3D22-brightgreen.svg)](https://nodejs.org)
6
+
7
+ `scifi` is a specification-driven workflow for building software with a coding
8
+ agent. It gives a feature a lifecycle — *spec → plan → implement → done* — and
9
+ holds every stage to a written artifact and a review gate before it can advance.
10
+
11
+ It is two cooperating layers:
12
+
13
+ - A small **CLI** (`scifi`) that tracks each feature's lifecycle on disk and
14
+ refuses to skip a gate.
15
+ - A set of bundled **skills** (`sf-*`) that your agent runs to do the actual
16
+ work — interrogating the idea, writing the spec, planning the design,
17
+ implementing it test-first, and reviewing each step.
18
+
19
+ The CLI is the bookkeeping; the skills are the method. The CLI never refuses to
20
+ let the agent advance unless an artifact is genuinely missing, and the skills
21
+ never advance the lifecycle until a review has passed.
22
+
23
+ > **On the name:** originally `spec-flow` (`sf` for short), now `scifi` — same
24
+ > `sf`, spelled the fun way. The bundled skills keep their `sf-` prefix.
25
+
26
+ ## Requirements
27
+
28
+ - Node.js `>=22`
29
+ - A coding agent that supports skills (currently **Claude Code**)
30
+
31
+ ## Install
32
+
33
+ ```bash
34
+ npm install -g @kamilmarzynski/scifi
35
+ ```
36
+
37
+ Then, inside the repository you want to manage:
38
+
39
+ ```bash
40
+ scifi init
41
+ ```
42
+
43
+ `init` scaffolds the workspace under `docs/scifi/` and installs the skill
44
+ catalog into your agent. For Claude Code that means `.claude/skills/sf-*/SKILL.md`
45
+ for all 13 skills. It creates:
46
+
47
+ ```text
48
+ docs/scifi/
49
+ ├── .scifi/config.json # which harness you chose
50
+ ├── specs/ # one folder per feature
51
+ └── CONTEXT.md # project glossary (ubiquitous language)
52
+ ```
53
+
54
+ Skill files are owned by `scifi` — rerunning `init` overwrites them in place. To
55
+ customize one, copy it under a different id (e.g. `my-code-review`) and edit that;
56
+ your copy is never touched.
57
+
58
+ ## The lifecycle
59
+
60
+ Every feature climbs the same one-way ladder. Each step is gated: the CLI checks
61
+ that the backing artifact exists before it lets the status advance.
62
+
63
+ ```text
64
+ created ──spec.md──► spec-ready ──design.md+tasks──► plan-ready ──► in-progress ──► done
65
+ ```
66
+
67
+ | Status | Means | Gate to reach it |
68
+ | ------------- | ------------------------------ | ------------------------------------ |
69
+ | `created` | container exists, no spec yet | `scifi spec <slug>` |
70
+ | `spec-ready` | spec written and reviewed | `spec.md` exists |
71
+ | `plan-ready` | design + tasks written | `design.md` and ≥1 task file exist |
72
+ | `in-progress` | implementation started | reachable only from `plan-ready` |
73
+ | `done` | built, verified, closed out | all tasks done **and** no open fixes |
74
+
75
+ You never jump the ladder. A scope change that invalidates the spec rolls the
76
+ feature back to `spec-ready` and it climbs again through every gate.
77
+
78
+ ## How to use it (the everyday flow)
79
+
80
+ Work is driven by invoking skills in your agent. The CLI calls happen *inside*
81
+ the skills — you rarely type `scifi` commands by hand except to inspect state.
82
+
83
+ **1. Start a feature.** Run the `sf-feature` skill. It creates the container,
84
+ then grills you about the idea one question at a time — the real problem, what is
85
+ out of scope, testable acceptance criteria, the edge cases — until the spec has
86
+ no gaps. It writes `spec.md`, runs a spec review, and marks the feature
87
+ `spec-ready`.
88
+
89
+ **2. Plan it.** Run `sf-plan`. It grills the *how* against your codebase, pushing
90
+ for deep modules (lots of behavior behind a narrow interface). It writes
91
+ `design.md`, decomposes the work into test-first task files ordered by a
92
+ `depends-on` graph, runs a plan review, and marks the feature `plan-ready`.
93
+
94
+ **3. Implement it.** Run `sf-implement`. This stage is autonomous. It dispatches a
95
+ fresh subagent per task — each builds its slice test-first (`sf-tdd`) and is
96
+ gated by an independent code review before the task is marked done. When all
97
+ tasks pass, a handover subagent verifies the whole feature against the spec and
98
+ design, runs your checks, and the feature is finished.
99
+
100
+ That is the spine. The other skills handle the situations that come up around it:
101
+
102
+ | When… | Run… |
103
+ | -------------------------------------- | -------------- |
104
+ | You picked up work and forgot where it was | `sf-continue` — reads the status and routes you to the right next step |
105
+ | The feature's scope changed | `sf-change` — rolls the feature back exactly as far as the change cuts, then re-enters |
106
+ | You hit a defect with no owning feature | `sf-bug` — investigate-then-fix, no tracked artifact |
107
+ | You hit a defect in a real feature | `sf-fix` — same, but records a tracked fix that blocks `finish` until resolved |
108
+
109
+ **Inspect state any time** with the CLI directly:
110
+
111
+ ```bash
112
+ scifi list # all features, status, open-fix counts
113
+ scifi status <slug> # full inventory: artifacts, tasks, fixes
114
+ scifi task list <slug> # the task graph and each task's status
115
+ ```
116
+
117
+ ## What makes it work
118
+
119
+ A few ideas recur through every stage and are worth understanding:
120
+
121
+ - **Grill before write.** Spec and plan sessions are interactive interrogations,
122
+ not form-filling. The artifact is written only once every question is answered
123
+ — no `TBD`, no `TODO`.
124
+ - **Review gates, not trust.** Every artifact (spec, plan, each task) is reviewed
125
+ by a separate subagent with clean context before the lifecycle advances. The
126
+ reviewer judges; the author acts on the findings under `sf-receiving-review`
127
+ (verify, push back when wrong, no performative agreement). The loop repeats
128
+ until the verdict is **Pass**.
129
+ - **Test-first implementation.** No production code without a failing test first
130
+ (`sf-tdd`). The test proves the behavior exists; the regression test proves a
131
+ fixed bug stays fixed.
132
+ - **Clean subagent context.** The orchestrator never lets a subagent read its
133
+ session history. Each subagent's context is built from the artifacts alone, so
134
+ reviews stay unbiased and the coordinator stays focused.
135
+ - **Deep modules.** Planning and review both push for narrow interfaces over deep
136
+ implementations, and apply the *deletion test*: would removing a unit
137
+ concentrate complexity (keep it) or just scatter it (inline it)?
138
+ - **Isolated per feature.** Starting a feature with `sf-feature` creates its own
139
+ git branch (`feat/<slug>`) and worktree (`.worktrees/feat-<slug>`) up front, so
140
+ several features can be built in parallel without colliding, and nothing lands
141
+ on the default branch until the feature's PR merges. `scifi status` reports the
142
+ branch and worktree; the maintainer removes the worktree after the PR merges.
143
+
144
+ ## Project conventions
145
+
146
+ These live under `docs/scifi/` and the skills read and maintain them:
147
+
148
+ - **`CONTEXT.md`** — the project glossary (ubiquitous language). Every domain
149
+ term used in a spec is defined here; the skills add terms as they appear, so
150
+ naming stays consistent across features.
151
+ - **`adr/NNNN-slug.md`** — Architecture Decision Records. The directory is lazy
152
+ (created on the first record). A decision is recorded only when it is
153
+ hard to reverse, non-obvious, and a real trade-off was made. Skills grep these
154
+ before contradicting a past decision.
155
+ - **`HANDOVER.md`** *(optional)* — finishing actions the implement stage runs
156
+ after handover verification passes and before the feature is finished: smoke
157
+ tests, opening a pull request, invoking your release skill. Create it yourself
158
+ when you want it; absent, the feature finishes with no extra actions.
159
+ - **`specs/<slug>/`** — one feature: `spec.md`, `design.md`, `tasks/*.md`,
160
+ `fixes/*.md`, and the CLI-managed `.scifi.json` metadata.
161
+
162
+ ## The skills
163
+
164
+ `init` installs all 13. The first seven are the ones you invoke directly; the
165
+ rest are dispatched by other skills as subagents.
166
+
167
+ | Skill | Role |
168
+ | -------------------- | -------------------------------------------------------------- |
169
+ | `sf-feature` | Grill a new idea and write the spec |
170
+ | `sf-plan` | Grill the design and decompose into tasks |
171
+ | `sf-implement` | Orchestrate test-first implementation, task by task |
172
+ | `sf-continue` | Route a picked-up feature to its next step |
173
+ | `sf-change` | Absorb a scope change; roll the lifecycle back as far as needed |
174
+ | `sf-bug` | Investigate and fix a defect (untracked) |
175
+ | `sf-fix` | Investigate and fix a defect anchored to a feature (tracked) |
176
+ | `sf-tdd` | Test-first discipline held by implementer subagents |
177
+ | `sf-spec-review` | Critique a spec before `spec-ready` |
178
+ | `sf-plan-review` | Critique a plan before `plan-ready` |
179
+ | `sf-code-review` | Critique one task's code before it is marked done |
180
+ | `sf-receiving-review`| How an author acts on a review |
181
+ | `sf-handover` | Verify a completed feature against its spec and design |
182
+
183
+ ## CLI reference
184
+
185
+ | Command | Effect |
186
+ | ------------------------------------------ | --------------------------------------------------- |
187
+ | `scifi init` | Scaffold the workspace and install skills |
188
+ | `scifi spec <slug> [--title "..."]` | Create a feature container (status `created`) |
189
+ | `scifi spec-ready <slug>` | `created → spec-ready` (needs `spec.md`) |
190
+ | `scifi plan <slug>` | Report planning progress (read-only) |
191
+ | `scifi plan-ready <slug>` | `spec-ready → plan-ready` (needs design + tasks) |
192
+ | `scifi start <slug>` | `plan-ready → in-progress` |
193
+ | `scifi task list\|start\|done <slug> ...` | Manage task status within a feature |
194
+ | `scifi fix create\|resolve\|wont-fix ...` | Manage tracked fixes (open fixes block `finish`) |
195
+ | `scifi finish <slug>` | `in-progress → done` (all tasks done, no open fixes)|
196
+ | `scifi list [--status <s>]` | List features |
197
+ | `scifi status <slug>` | Show a feature's full state |
198
+ | `scifi worktree set <slug> --branch <b> --path <p>` | Record the branch + worktree backing a feature |
199
+
200
+ Every command accepts `--json` for structured output, and reports failures with
201
+ a stable error code (`NOT_FOUND`, `PRECONDITION_FAILED`, `CONFLICT`,
202
+ `INVALID_ARGUMENT`).
203
+
204
+ ## Development
205
+
206
+ ```bash
207
+ npm install
208
+ npm run typecheck
209
+ npm run build
210
+ npm test
211
+ npm run coverage
212
+ npm run check # Biome lint + format
213
+ ```
214
+
215
+ User-facing CLI changes are verified against an installed build, not only
216
+ source-level tests. That workflow lives under `.testing/` and is covered by
217
+ `tests/e2e/`; see `TESTING.md` for the mandatory process.
218
+
219
+ ## Contributing
220
+
221
+ Contributions are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for the dev
222
+ setup, branch/commit conventions, and verification steps. By participating you
223
+ agree to the [Code of Conduct](./CODE_OF_CONDUCT.md). To report a security issue,
224
+ follow [SECURITY.md](./SECURITY.md) — do not open a public issue.
225
+
226
+ Releases are automated with [release-please](https://github.com/googleapis/release-please):
227
+ merged [Conventional Commits](https://www.conventionalcommits.org/) drive the
228
+ version bump and changelog, and merging the Release PR publishes to npm.
229
+
230
+ ## License
231
+
232
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,6 @@
1
+ export const manifest = {
2
+ id: "sf-bug",
3
+ description: "Investigate one bug with the user, agree on a solution, then fix it test-first under review. No spec or tracked artifact.",
4
+ argumentHint: "[description]",
5
+ };
6
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-bug/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,QAAQ;IACZ,WAAW,EACT,2HAA2H;IAC7H,YAAY,EAAE,eAAe;CAC9B,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,6 @@
1
+ export const manifest = {
2
+ id: "sf-change",
3
+ description: "Absorb a scope change to an existing feature: scope it against spec/design, reset lifecycle status to the deepest artifact it invalidates, and re-enter the pipeline so the right review gate runs again.",
4
+ argumentHint: "[feature-slug | description]",
5
+ };
6
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-change/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,WAAW;IACf,WAAW,EACT,2MAA2M;IAC7M,YAAY,EAAE,8BAA8B;CAC7C,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,5 @@
1
+ export const manifest = {
2
+ id: "sf-code-review",
3
+ description: "Read-only critic pass on one change: a feature task against design.md + the task's acceptance, or a bug/fix against the agreed solution. Returns a verdict that gates acceptance.",
4
+ };
5
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-code-review/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,gBAAgB;IACpB,WAAW,EACT,mLAAmL;CACtL,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,6 @@
1
+ export const manifest = {
2
+ id: "sf-continue",
3
+ description: "Resume an interrupted feature. Reads `scifi status <slug> --json`, determines the next workflow step from lifecycle status, and runs the matching skill, pausing where human handoff is required.",
4
+ argumentHint: "[feature-slug | description]",
5
+ };
6
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-continue/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,aAAa;IACjB,WAAW,EACT,mMAAmM;IACrM,YAAY,EAAE,8BAA8B;CAC7C,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,6 @@
1
+ export const manifest = {
2
+ id: "sf-feature",
3
+ description: "Start grilling session for new feature. Greps docs/scifi/adr/ for relevant decisions; records an ADR only for hard, non-obvious choices. Writes spec.md.",
4
+ argumentHint: "[title]",
5
+ };
6
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-feature/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,YAAY;IAChB,WAAW,EACT,0JAA0J;IAC5J,YAAY,EAAE,SAAS;CACxB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,6 @@
1
+ export const manifest = {
2
+ id: "sf-fix",
3
+ description: "Fix a defect in an existing feature: diagnose against its spec/design with the user, agree on a solution, then fix it test-first under review and record a tracked fix.",
4
+ argumentHint: "[feature-slug | description]",
5
+ };
6
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-fix/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,QAAQ;IACZ,WAAW,EACT,yKAAyK;IAC3K,YAAY,EAAE,8BAA8B;CAC7C,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,5 @@
1
+ export const manifest = {
2
+ id: "sf-handover",
3
+ description: "Final implementation subagent. Verifies the completed feature against spec + design and runs a quality check before handover. Aware of the optional HANDOVER.md finishing actions the orchestrator runs.",
4
+ };
5
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-handover/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,aAAa;IACjB,WAAW,EACT,0MAA0M;CAC7M,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,6 @@
1
+ export const manifest = {
2
+ id: "sf-implement",
3
+ description: "Orchestrate implementation of a plan-ready feature. Dispatches one TDD subagent per task in dependency order, gates each on code review, then runs handover (sf-handover verification + optional HANDOVER.md actions) before finish.",
4
+ argumentHint: "[feature-slug]",
5
+ };
6
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-implement/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,cAAc;IAClB,WAAW,EACT,sOAAsO;IACxO,YAAY,EAAE,gBAAgB;CAC/B,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,6 @@
1
+ export const manifest = {
2
+ id: "sf-plan",
3
+ description: "Deep technical planning from approved spec.md. Writes design.md + tasks/. Greps docs/scifi/adr/ for context; records an ADR for hard, non-obvious decisions.",
4
+ argumentHint: "[feature-slug]",
5
+ };
6
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-plan/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,SAAS;IACb,WAAW,EACT,8JAA8J;IAChK,YAAY,EAAE,gBAAgB;CAC/B,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,5 @@
1
+ export const manifest = {
2
+ id: "sf-plan-review",
3
+ description: "Critic pass on design.md + tasks/. Checks spec coverage and declared seams.",
4
+ };
5
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-plan-review/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,gBAAgB;IACpB,WAAW,EACT,6EAA6E;CAChF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,5 @@
1
+ export const manifest = {
2
+ id: "sf-receiving-review",
3
+ description: "How to act on a review (spec, plan, or code). Verify before implementing, fix by severity, push back with technical reasoning when the reviewer is wrong.",
4
+ };
5
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-receiving-review/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,qBAAqB;IACzB,WAAW,EACT,2JAA2J;CAC9J,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,5 @@
1
+ export const manifest = {
2
+ id: "sf-spec-review",
3
+ description: "Critic pass on a spec.md. Surfaces ambiguity, missing AC, CONTEXT.md gaps.",
4
+ };
5
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-spec-review/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,gBAAgB;IACpB,WAAW,EACT,4EAA4E;CAC/E,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,5 @@
1
+ export const manifest = {
2
+ id: "sf-tdd",
3
+ description: "Tests-first implementation discipline for a single task. Red-green-refactor in vertical slices; no production code without a failing test first.",
4
+ };
5
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-tdd/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,QAAQ;IACZ,WAAW,EACT,kJAAkJ;CACrJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { SkillManifest } from "scifi/skill-types";
2
+ export declare const manifest: SkillManifest;
@@ -0,0 +1,5 @@
1
+ export const manifest = {
2
+ id: "sf-verification",
3
+ description: "Verify implementation matches spec + plan. Runs user validations from EVALUATION.md.",
4
+ };
5
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../skills/sf-verification/manifest.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,EAAE,EAAE,iBAAiB;IACrB,WAAW,EACT,sFAAsF;CACzF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerBugCommand(program: Command): void;
@@ -0,0 +1,58 @@
1
+ import { relative } from 'node:path';
2
+ import { cwd } from 'node:process';
3
+ import { createBug } from '../../core/bugs/create.js';
4
+ import { BUG_SEVERITY_VALUES } from '../../core/bugs/types.js';
5
+ import { emitError, emitSuccess, jsonMode, ScifiError } from '../../core/output/index.js';
6
+ function createTimestamp() {
7
+ return new Date().toISOString();
8
+ }
9
+ export function registerBugCommand(program) {
10
+ program
11
+ .command('bug')
12
+ .description('Create a standalone bug report in the root bugs/ directory')
13
+ .argument('<description>', 'short description of the bug')
14
+ .option('--related-feature <slug>', 'feature slug for context')
15
+ .option('--severity <level>', 'severity level: low, medium, high, or critical')
16
+ .option('--json', 'output as structured JSON')
17
+ .action(async (description, options, command) => {
18
+ const json = jsonMode(command);
19
+ try {
20
+ if (options.severity !== undefined &&
21
+ !BUG_SEVERITY_VALUES.includes(options.severity)) {
22
+ throw new ScifiError('INVALID_ARGUMENT', `Invalid severity "${options.severity}".`, {
23
+ hint: `Must be one of: ${BUG_SEVERITY_VALUES.join(', ')}.`,
24
+ });
25
+ }
26
+ const severity = options.severity;
27
+ const projectRoot = cwd();
28
+ const result = await createBug({
29
+ projectRoot,
30
+ description,
31
+ ...(options.relatedFeature !== undefined && {
32
+ relatedFeature: options.relatedFeature,
33
+ }),
34
+ ...(severity !== undefined && { severity }),
35
+ now: createTimestamp(),
36
+ });
37
+ const path = relative(projectRoot, result.filePath);
38
+ emitSuccess({
39
+ action: 'bug',
40
+ id: result.id,
41
+ description,
42
+ severity: severity ?? null,
43
+ path,
44
+ relatedFeature: options.relatedFeature ?? null,
45
+ }, json, [
46
+ `Bug created: ${result.id}`,
47
+ ` Description: ${description}`,
48
+ ` Severity: ${severity ?? 'unspecified'}`,
49
+ ` Path: ${path}`,
50
+ ` Related feature: ${options.relatedFeature ?? 'none'}`,
51
+ ]);
52
+ }
53
+ catch (error) {
54
+ emitError(error, json);
55
+ }
56
+ });
57
+ }
58
+ //# sourceMappingURL=bug.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bug.js","sourceRoot":"","sources":["../../../../src/cli/commands/bug.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,mBAAmB,EAAoB,MAAM,0BAA0B,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAE1F,SAAS,eAAe;IACtB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAgB;IACjD,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,4DAA4D,CAAC;SACzE,QAAQ,CAAC,eAAe,EAAE,8BAA8B,CAAC;SACzD,MAAM,CAAC,0BAA0B,EAAE,0BAA0B,CAAC;SAC9D,MAAM,CAAC,oBAAoB,EAAE,gDAAgD,CAAC;SAC9E,MAAM,CAAC,QAAQ,EAAE,2BAA2B,CAAC;SAC7C,MAAM,CACL,KAAK,EACH,WAAmB,EACnB,OAIC,EACD,OAAgB,EAChB,EAAE;QACF,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC;YACH,IACE,OAAO,CAAC,QAAQ,KAAK,SAAS;gBAC9B,CAAE,mBAAyC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,EACtE,CAAC;gBACD,MAAM,IAAI,UAAU,CAAC,kBAAkB,EAAE,qBAAqB,OAAO,CAAC,QAAQ,IAAI,EAAE;oBAClF,IAAI,EAAE,mBAAmB,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;iBAC3D,CAAC,CAAC;YACL,CAAC;YACD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAmC,CAAC;YAE7D,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC;YAC1B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC;gBAC7B,WAAW;gBACX,WAAW;gBACX,GAAG,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS,IAAI;oBAC1C,cAAc,EAAE,OAAO,CAAC,cAAc;iBACvC,CAAC;gBACF,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,CAAC;gBAC3C,GAAG,EAAE,eAAe,EAAE;aACvB,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YACpD,WAAW,CACT;gBACE,MAAM,EAAE,KAAK;gBACb,EAAE,EAAE,MAAM,CAAC,EAAE;gBACb,WAAW;gBACX,QAAQ,EAAE,QAAQ,IAAI,IAAI;gBAC1B,IAAI;gBACJ,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,IAAI;aAC/C,EACD,IAAI,EACJ;gBACE,gBAAgB,MAAM,CAAC,EAAE,EAAE;gBAC3B,kBAAkB,WAAW,EAAE;gBAC/B,eAAe,QAAQ,IAAI,aAAa,EAAE;gBAC1C,WAAW,IAAI,EAAE;gBACjB,sBAAsB,OAAO,CAAC,cAAc,IAAI,MAAM,EAAE;aACzD,CACF,CAAC;QACJ,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,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerFinishCommand(program: Command): void;
@@ -0,0 +1,43 @@
1
+ import { cwd } from 'node:process';
2
+ import { listOpenFixes } from '../../core/fixes/list.js';
3
+ import { emitError, emitSuccess, jsonMode, ScifiError } from '../../core/output/index.js';
4
+ import { updateFeatureStatus } from '../../core/specs/transition.js';
5
+ function createTimestamp() {
6
+ return new Date().toISOString();
7
+ }
8
+ export function registerFinishCommand(program) {
9
+ program
10
+ .command('finish')
11
+ .description('Mark a feature as done (requires all tasks done and no open fixes)')
12
+ .argument('<slug>', 'feature folder slug')
13
+ .option('--json', 'output as structured JSON')
14
+ .action(async (slug, _options, command) => {
15
+ const json = jsonMode(command);
16
+ try {
17
+ const projectRoot = cwd();
18
+ const openFixes = await listOpenFixes(projectRoot, slug);
19
+ if (openFixes.length > 0) {
20
+ const ids = openFixes.map((f) => f.id).join(', ');
21
+ throw new ScifiError('PRECONDITION_FAILED', `Cannot finish ${slug}: ${openFixes.length} open fix${openFixes.length === 1 ? '' : 'es'} block completion`, {
22
+ hint: `Resolve or mark wont-fix the following fixes: ${ids}`,
23
+ details: {
24
+ openFixes: openFixes.map((f) => ({
25
+ id: f.id,
26
+ status: f.status,
27
+ slug: f.slug,
28
+ })),
29
+ },
30
+ });
31
+ }
32
+ const result = await updateFeatureStatus(projectRoot, slug, 'done', createTimestamp());
33
+ emitSuccess({ action: 'finish', ...result }, json, [
34
+ `feature ${result.slug}: ${result.previousStatus} → ${result.newStatus}`,
35
+ ` Timestamp: ${result.timestamp}`,
36
+ ]);
37
+ }
38
+ catch (error) {
39
+ emitError(error, json);
40
+ }
41
+ });
42
+ }
43
+ //# sourceMappingURL=finish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finish.js","sourceRoot":"","sources":["../../../../src/cli/commands/finish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAC1F,OAAO,EAAE,mBAAmB,EAAE,MAAM,gCAAgC,CAAC;AAErE,SAAS,eAAe;IACtB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,oEAAoE,CAAC;SACjF,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;SACzC,MAAM,CAAC,QAAQ,EAAE,2BAA2B,CAAC;SAC7C,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,QAAiB,EAAE,OAAgB,EAAE,EAAE;QAClE,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC/B,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC;YAC1B,MAAM,SAAS,GAAG,MAAM,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;YAEzD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAClD,MAAM,IAAI,UAAU,CAClB,qBAAqB,EACrB,iBAAiB,IAAI,KAAK,SAAS,CAAC,MAAM,YAAY,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,mBAAmB,EAC3G;oBACE,IAAI,EAAE,iDAAiD,GAAG,EAAE;oBAC5D,OAAO,EAAE;wBACP,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BAC/B,EAAE,EAAE,CAAC,CAAC,EAAE;4BACR,MAAM,EAAE,CAAC,CAAC,MAAM;4BAChB,IAAI,EAAE,CAAC,CAAC,IAAI;yBACb,CAAC,CAAC;qBACJ;iBACF,CACF,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC,CAAC;YACvF,WAAW,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,EAAE,EAAE,IAAI,EAAE;gBACjD,WAAW,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,cAAc,MAAM,MAAM,CAAC,SAAS,EAAE;gBACxE,gBAAgB,MAAM,CAAC,SAAS,EAAE;aACnC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACzB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function registerFixCommand(program: Command): void;