@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.
- package/LICENSE +21 -0
- package/README.md +232 -0
- package/dist/skills/sf-bug/manifest.d.ts +2 -0
- package/dist/skills/sf-bug/manifest.js +6 -0
- package/dist/skills/sf-bug/manifest.js.map +1 -0
- package/dist/skills/sf-change/manifest.d.ts +2 -0
- package/dist/skills/sf-change/manifest.js +6 -0
- package/dist/skills/sf-change/manifest.js.map +1 -0
- package/dist/skills/sf-code-review/manifest.d.ts +2 -0
- package/dist/skills/sf-code-review/manifest.js +5 -0
- package/dist/skills/sf-code-review/manifest.js.map +1 -0
- package/dist/skills/sf-continue/manifest.d.ts +2 -0
- package/dist/skills/sf-continue/manifest.js +6 -0
- package/dist/skills/sf-continue/manifest.js.map +1 -0
- package/dist/skills/sf-feature/manifest.d.ts +2 -0
- package/dist/skills/sf-feature/manifest.js +6 -0
- package/dist/skills/sf-feature/manifest.js.map +1 -0
- package/dist/skills/sf-fix/manifest.d.ts +2 -0
- package/dist/skills/sf-fix/manifest.js +6 -0
- package/dist/skills/sf-fix/manifest.js.map +1 -0
- package/dist/skills/sf-handover/manifest.d.ts +2 -0
- package/dist/skills/sf-handover/manifest.js +5 -0
- package/dist/skills/sf-handover/manifest.js.map +1 -0
- package/dist/skills/sf-implement/manifest.d.ts +2 -0
- package/dist/skills/sf-implement/manifest.js +6 -0
- package/dist/skills/sf-implement/manifest.js.map +1 -0
- package/dist/skills/sf-plan/manifest.d.ts +2 -0
- package/dist/skills/sf-plan/manifest.js +6 -0
- package/dist/skills/sf-plan/manifest.js.map +1 -0
- package/dist/skills/sf-plan-review/manifest.d.ts +2 -0
- package/dist/skills/sf-plan-review/manifest.js +5 -0
- package/dist/skills/sf-plan-review/manifest.js.map +1 -0
- package/dist/skills/sf-receiving-review/manifest.d.ts +2 -0
- package/dist/skills/sf-receiving-review/manifest.js +5 -0
- package/dist/skills/sf-receiving-review/manifest.js.map +1 -0
- package/dist/skills/sf-spec-review/manifest.d.ts +2 -0
- package/dist/skills/sf-spec-review/manifest.js +5 -0
- package/dist/skills/sf-spec-review/manifest.js.map +1 -0
- package/dist/skills/sf-tdd/manifest.d.ts +2 -0
- package/dist/skills/sf-tdd/manifest.js +5 -0
- package/dist/skills/sf-tdd/manifest.js.map +1 -0
- package/dist/skills/sf-verification/manifest.d.ts +2 -0
- package/dist/skills/sf-verification/manifest.js +5 -0
- package/dist/skills/sf-verification/manifest.js.map +1 -0
- package/dist/src/cli/commands/bug.d.ts +2 -0
- package/dist/src/cli/commands/bug.js +58 -0
- package/dist/src/cli/commands/bug.js.map +1 -0
- package/dist/src/cli/commands/finish.d.ts +2 -0
- package/dist/src/cli/commands/finish.js +43 -0
- package/dist/src/cli/commands/finish.js.map +1 -0
- package/dist/src/cli/commands/fix.d.ts +2 -0
- package/dist/src/cli/commands/fix.js +60 -0
- package/dist/src/cli/commands/fix.js.map +1 -0
- package/dist/src/cli/commands/init.d.ts +2 -0
- package/dist/src/cli/commands/init.js +92 -0
- package/dist/src/cli/commands/init.js.map +1 -0
- package/dist/src/cli/commands/list.d.ts +2 -0
- package/dist/src/cli/commands/list.js +52 -0
- package/dist/src/cli/commands/list.js.map +1 -0
- package/dist/src/cli/commands/plan-ready.d.ts +2 -0
- package/dist/src/cli/commands/plan-ready.js +27 -0
- package/dist/src/cli/commands/plan-ready.js.map +1 -0
- package/dist/src/cli/commands/plan.d.ts +2 -0
- package/dist/src/cli/commands/plan.js +43 -0
- package/dist/src/cli/commands/plan.js.map +1 -0
- package/dist/src/cli/commands/spec-ready.d.ts +2 -0
- package/dist/src/cli/commands/spec-ready.js +27 -0
- package/dist/src/cli/commands/spec-ready.js.map +1 -0
- package/dist/src/cli/commands/spec.d.ts +2 -0
- package/dist/src/cli/commands/spec.js +46 -0
- package/dist/src/cli/commands/spec.js.map +1 -0
- package/dist/src/cli/commands/start.d.ts +2 -0
- package/dist/src/cli/commands/start.js +27 -0
- package/dist/src/cli/commands/start.js.map +1 -0
- package/dist/src/cli/commands/status.d.ts +2 -0
- package/dist/src/cli/commands/status.js +62 -0
- package/dist/src/cli/commands/status.js.map +1 -0
- package/dist/src/cli/commands/task.d.ts +2 -0
- package/dist/src/cli/commands/task.js +64 -0
- package/dist/src/cli/commands/task.js.map +1 -0
- package/dist/src/cli/commands/worktree.d.ts +2 -0
- package/dist/src/cli/commands/worktree.js +33 -0
- package/dist/src/cli/commands/worktree.js.map +1 -0
- package/dist/src/cli/index.d.ts +3 -0
- package/dist/src/cli/index.js +106 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/core/bugs/create.d.ts +13 -0
- package/dist/src/core/bugs/create.js +28 -0
- package/dist/src/core/bugs/create.js.map +1 -0
- package/dist/src/core/bugs/frontmatter.d.ts +7 -0
- package/dist/src/core/bugs/frontmatter.js +65 -0
- package/dist/src/core/bugs/frontmatter.js.map +1 -0
- package/dist/src/core/bugs/id.d.ts +1 -0
- package/dist/src/core/bugs/id.js +4 -0
- package/dist/src/core/bugs/id.js.map +1 -0
- package/dist/src/core/bugs/paths.d.ts +2 -0
- package/dist/src/core/bugs/paths.js +8 -0
- package/dist/src/core/bugs/paths.js.map +1 -0
- package/dist/src/core/bugs/types.d.ts +12 -0
- package/dist/src/core/bugs/types.js +3 -0
- package/dist/src/core/bugs/types.js.map +1 -0
- package/dist/src/core/fixes/create.d.ts +11 -0
- package/dist/src/core/fixes/create.js +43 -0
- package/dist/src/core/fixes/create.js.map +1 -0
- package/dist/src/core/fixes/frontmatter.d.ts +7 -0
- package/dist/src/core/fixes/frontmatter.js +50 -0
- package/dist/src/core/fixes/frontmatter.js.map +1 -0
- package/dist/src/core/fixes/id.d.ts +1 -0
- package/dist/src/core/fixes/id.js +4 -0
- package/dist/src/core/fixes/id.js.map +1 -0
- package/dist/src/core/fixes/list.d.ts +8 -0
- package/dist/src/core/fixes/list.js +43 -0
- package/dist/src/core/fixes/list.js.map +1 -0
- package/dist/src/core/fixes/paths.d.ts +2 -0
- package/dist/src/core/fixes/paths.js +9 -0
- package/dist/src/core/fixes/paths.js.map +1 -0
- package/dist/src/core/fixes/transition.d.ts +9 -0
- package/dist/src/core/fixes/transition.js +26 -0
- package/dist/src/core/fixes/transition.js.map +1 -0
- package/dist/src/core/fixes/types.d.ts +9 -0
- package/dist/src/core/fixes/types.js +2 -0
- package/dist/src/core/fixes/types.js.map +1 -0
- package/dist/src/core/init/config.d.ts +6 -0
- package/dist/src/core/init/config.js +18 -0
- package/dist/src/core/init/config.js.map +1 -0
- package/dist/src/core/init/install-skills.d.ts +8 -0
- package/dist/src/core/init/install-skills.js +14 -0
- package/dist/src/core/init/install-skills.js.map +1 -0
- package/dist/src/core/init/prompt-harness.d.ts +8 -0
- package/dist/src/core/init/prompt-harness.js +19 -0
- package/dist/src/core/init/prompt-harness.js.map +1 -0
- package/dist/src/core/init/scaffold.d.ts +5 -0
- package/dist/src/core/init/scaffold.js +91 -0
- package/dist/src/core/init/scaffold.js.map +1 -0
- package/dist/src/core/init/types.d.ts +5 -0
- package/dist/src/core/init/types.js +2 -0
- package/dist/src/core/init/types.js.map +1 -0
- package/dist/src/core/output/emit.d.ts +8 -0
- package/dist/src/core/output/emit.js +50 -0
- package/dist/src/core/output/emit.js.map +1 -0
- package/dist/src/core/output/errors.d.ts +14 -0
- package/dist/src/core/output/errors.js +36 -0
- package/dist/src/core/output/errors.js.map +1 -0
- package/dist/src/core/output/index.d.ts +4 -0
- package/dist/src/core/output/index.js +4 -0
- package/dist/src/core/output/index.js.map +1 -0
- package/dist/src/core/output/tty.d.ts +1 -0
- package/dist/src/core/output/tty.js +4 -0
- package/dist/src/core/output/tty.js.map +1 -0
- package/dist/src/core/package-root.d.ts +1 -0
- package/dist/src/core/package-root.js +18 -0
- package/dist/src/core/package-root.js.map +1 -0
- package/dist/src/core/skills/catalog.d.ts +6 -0
- package/dist/src/core/skills/catalog.js +69 -0
- package/dist/src/core/skills/catalog.js.map +1 -0
- package/dist/src/core/skills/harness/adapter.d.ts +15 -0
- package/dist/src/core/skills/harness/adapter.js +31 -0
- package/dist/src/core/skills/harness/adapter.js.map +1 -0
- package/dist/src/core/skills/harness/claude-code.d.ts +2 -0
- package/dist/src/core/skills/harness/claude-code.js +37 -0
- package/dist/src/core/skills/harness/claude-code.js.map +1 -0
- package/dist/src/core/skills/harness/register-defaults.d.ts +1 -0
- package/dist/src/core/skills/harness/register-defaults.js +4 -0
- package/dist/src/core/skills/harness/register-defaults.js.map +1 -0
- package/dist/src/core/skills/harness/registry.d.ts +3 -0
- package/dist/src/core/skills/harness/registry.js +22 -0
- package/dist/src/core/skills/harness/registry.js.map +1 -0
- package/dist/src/core/skills/types.d.ts +18 -0
- package/dist/src/core/skills/types.js +9 -0
- package/dist/src/core/skills/types.js.map +1 -0
- package/dist/src/core/slugify.d.ts +2 -0
- package/dist/src/core/slugify.js +13 -0
- package/dist/src/core/slugify.js.map +1 -0
- package/dist/src/core/specs/create.d.ts +11 -0
- package/dist/src/core/specs/create.js +35 -0
- package/dist/src/core/specs/create.js.map +1 -0
- package/dist/src/core/specs/id.d.ts +1 -0
- package/dist/src/core/specs/id.js +4 -0
- package/dist/src/core/specs/id.js.map +1 -0
- package/dist/src/core/specs/lifecycle.d.ts +17 -0
- package/dist/src/core/specs/lifecycle.js +97 -0
- package/dist/src/core/specs/lifecycle.js.map +1 -0
- package/dist/src/core/specs/list.d.ts +6 -0
- package/dist/src/core/specs/list.js +43 -0
- package/dist/src/core/specs/list.js.map +1 -0
- package/dist/src/core/specs/metadata.d.ts +3 -0
- package/dist/src/core/specs/metadata.js +13 -0
- package/dist/src/core/specs/metadata.js.map +1 -0
- package/dist/src/core/specs/paths.d.ts +3 -0
- package/dist/src/core/specs/paths.js +13 -0
- package/dist/src/core/specs/paths.js.map +1 -0
- package/dist/src/core/specs/plan-session.d.ts +18 -0
- package/dist/src/core/specs/plan-session.js +24 -0
- package/dist/src/core/specs/plan-session.js.map +1 -0
- package/dist/src/core/specs/transition.d.ts +8 -0
- package/dist/src/core/specs/transition.js +33 -0
- package/dist/src/core/specs/transition.js.map +1 -0
- package/dist/src/core/specs/types.d.ts +17 -0
- package/dist/src/core/specs/types.js +8 -0
- package/dist/src/core/specs/types.js.map +1 -0
- package/dist/src/core/specs/worktree.d.ts +10 -0
- package/dist/src/core/specs/worktree.js +32 -0
- package/dist/src/core/specs/worktree.js.map +1 -0
- package/dist/src/core/tasks/frontmatter.d.ts +7 -0
- package/dist/src/core/tasks/frontmatter.js +53 -0
- package/dist/src/core/tasks/frontmatter.js.map +1 -0
- package/dist/src/core/tasks/list.d.ts +2 -0
- package/dist/src/core/tasks/list.js +18 -0
- package/dist/src/core/tasks/list.js.map +1 -0
- package/dist/src/core/tasks/paths.d.ts +2 -0
- package/dist/src/core/tasks/paths.js +11 -0
- package/dist/src/core/tasks/paths.js.map +1 -0
- package/dist/src/core/tasks/transition.d.ts +8 -0
- package/dist/src/core/tasks/transition.js +30 -0
- package/dist/src/core/tasks/transition.js.map +1 -0
- package/dist/src/core/tasks/types.d.ts +8 -0
- package/dist/src/core/tasks/types.js +2 -0
- package/dist/src/core/tasks/types.js.map +1 -0
- package/package.json +67 -0
- package/skills/sf-bug/DISPATCH-CODE-REVIEW.md +22 -0
- package/skills/sf-bug/body.md +117 -0
- package/skills/sf-bug/manifest.ts +8 -0
- package/skills/sf-change/body.md +178 -0
- package/skills/sf-change/manifest.ts +8 -0
- package/skills/sf-code-review/body.md +155 -0
- package/skills/sf-code-review/manifest.ts +7 -0
- package/skills/sf-continue/body.md +90 -0
- package/skills/sf-continue/manifest.ts +8 -0
- package/skills/sf-feature/ADR-TEMPLATE.md +16 -0
- package/skills/sf-feature/DISPATCH-SPEC-REVIEW.md +16 -0
- package/skills/sf-feature/SPEC-TEMPLATE.md +37 -0
- package/skills/sf-feature/body.md +145 -0
- package/skills/sf-feature/manifest.ts +8 -0
- package/skills/sf-fix/DISPATCH-CODE-REVIEW.md +25 -0
- package/skills/sf-fix/body.md +174 -0
- package/skills/sf-fix/manifest.ts +8 -0
- package/skills/sf-handover/body.md +67 -0
- package/skills/sf-handover/manifest.ts +7 -0
- package/skills/sf-implement/DISPATCH-CODE-REVIEW.md +19 -0
- package/skills/sf-implement/DISPATCH-HANDOVER.md +19 -0
- package/skills/sf-implement/DISPATCH-IMPLEMENTER.md +36 -0
- package/skills/sf-implement/body.md +147 -0
- package/skills/sf-implement/manifest.ts +8 -0
- package/skills/sf-plan/ADR-TEMPLATE.md +16 -0
- package/skills/sf-plan/DESIGN-TEMPLATE.md +54 -0
- package/skills/sf-plan/DISPATCH-PLAN-REVIEW.md +17 -0
- package/skills/sf-plan/TASK-TEMPLATE.md +30 -0
- package/skills/sf-plan/body.md +162 -0
- package/skills/sf-plan/manifest.ts +8 -0
- package/skills/sf-plan-review/body.md +90 -0
- package/skills/sf-plan-review/manifest.ts +7 -0
- package/skills/sf-receiving-review/body.md +73 -0
- package/skills/sf-receiving-review/manifest.ts +7 -0
- package/skills/sf-spec-review/body.md +83 -0
- package/skills/sf-spec-review/manifest.ts +7 -0
- package/skills/sf-tdd/body.md +120 -0
- 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
|
+
[](https://github.com/KamilMarzynski/sci-fi/actions/workflows/ci.yml)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
[](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 @@
|
|
|
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,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,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,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,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,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,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,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,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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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,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,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"}
|