@luizsantiago/spec-guardrails 3.9.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +107 -86
- package/index.js +109 -0
- package/lib/classify-change.js +18 -0
- package/lib/constants.js +3 -0
- package/lib/gates.js +2 -0
- package/lib/req-analysis.js +274 -0
- package/package.json +2 -2
- package/scripts/memory_index.py +64 -0
- package/scripts/req_context.py +145 -0
- package/scripts/validate_req_analysis.py +191 -0
- package/skills/agent-architecture.md +9 -2
- package/skills/references/elicitation.md +209 -0
- package/skills/references/explore.md +1 -0
- package/skills/references/specify.md +1 -0
- package/templates/config.yaml.example +9 -0
package/README.md
CHANGED
|
@@ -3,156 +3,177 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/@luizsantiago/spec-guardrails)
|
|
4
4
|
[](LICENSE)
|
|
5
5
|
|
|
6
|
-
**
|
|
6
|
+
**Governed spec-driven development for AI coding agents.**
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Spec Guardrails is a process kit that installs phase guides, persistent project memory, and optional structural checks into your repository. Teams keep ownership of requirements and approval gates; agents follow a repeatable path from written intent to verified delivery.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
npm: [`@luizsantiago/spec-guardrails`](https://www.npmjs.com/package/@luizsantiago/spec-guardrails) **4.1.x**
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
---
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
## What it is
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
2. **Break work into small jobs** (`tasks.md`)
|
|
18
|
-
3. **Implement in waves** with real checks
|
|
19
|
-
4. **Verify with fresh eyes** — proof, not “trust me”
|
|
16
|
+
Spec Guardrails is **not** an application framework, a vector database, or a replacement for your stack. It is an **operating model** for AI-assisted engineering:
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
| Layer | Role |
|
|
19
|
+
| --- | --- |
|
|
20
|
+
| **Phase guides** | Instructions the agent loads one step at a time |
|
|
21
|
+
| **Project memory** | `.specs/` — specs, tasks, validation, and state that survive chat sessions |
|
|
22
|
+
| **Structural checks** | Optional Python gates that enforce document shape and evidence hooks |
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
The default loop is **Specify → Tasks → Execute → Verify → Archive**. You approve specs and task plans; the agent implements in waves and produces proof before work is considered done.
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
Full narrative: [Overview](docs/guide/Overview.md) · [How it works](docs/guide/How-it-works.md)
|
|
26
27
|
|
|
27
28
|
---
|
|
28
29
|
|
|
29
|
-
##
|
|
30
|
+
## Why teams use it
|
|
31
|
+
|
|
32
|
+
| Benefit | Outcome |
|
|
33
|
+
| --- | --- |
|
|
34
|
+
| **Traceability** | Requirements, jobs, and verification live in version-controlled artifacts |
|
|
35
|
+
| **Controlled autonomy** | Agents propose and execute; humans approve scope, design forks, and git tiers |
|
|
36
|
+
| **Progressive depth** | Quick fixes skip ceremony; complex work gets discuss, design, and task graphs |
|
|
37
|
+
| **Platform-agnostic** | Cursor, Claude Code, GitHub Copilot, Codex, and other agents via root `AGENTS.md` |
|
|
38
|
+
| **Token efficiency** | One phase guide per turn instead of dumping the entire playbook |
|
|
39
|
+
| **Optional enforcement** | Process mode (Node only) or Brakes mode (Node + Python gates) |
|
|
30
40
|
|
|
31
|
-
|
|
32
|
-
- Not a vector database or “AI memory” that reads your whole codebase
|
|
33
|
-
- Not automatic push/merge/deploy — you stay in control of git tiers
|
|
34
|
-
- Not a replacement for code review or product judgment
|
|
41
|
+
Process vs Brakes: [FAQ](docs/guide/FAQ.md#process-vs-brakes) · Guarantees: [Guarantees matrix](docs/guide/Guarantees-matrix.md)
|
|
35
42
|
|
|
36
43
|
---
|
|
37
44
|
|
|
38
|
-
## Install
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
In your project root:
|
|
39
48
|
|
|
40
49
|
```bash
|
|
41
50
|
npx @luizsantiago/spec-guardrails install
|
|
42
51
|
```
|
|
43
52
|
|
|
44
|
-
|
|
53
|
+
Re-run after upgrading the package; existing `.specs/` notes are preserved. Check readiness with `doctor`.
|
|
54
|
+
|
|
55
|
+
| Requirement | Role |
|
|
45
56
|
| --- | --- |
|
|
46
57
|
| **Node.js 18+** | Required — CLI and install |
|
|
47
|
-
| **Python 3.10+** | Optional — enables
|
|
48
|
-
|
|
49
|
-
Re-run `install` after upgrading the package. Your `.specs/` notes and `STATE.md` are kept.
|
|
58
|
+
| **Python 3.10+** | Optional — enables Brakes mode (automatic gates) |
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
Works with **Cursor, Claude Code, GitHub Copilot, OpenAI Codex**, and other agents via root `AGENTS.md`. See [Platform parity](docs/guide/Platform-parity.md).
|
|
60
|
+
Platform setup: [Platform parity](docs/guide/Platform-parity.md) · Release notes: [CHANGELOG](docs/CHANGELOG.md)
|
|
54
61
|
|
|
55
62
|
---
|
|
56
63
|
|
|
57
|
-
## How you
|
|
64
|
+
## How you work day to day
|
|
65
|
+
|
|
66
|
+
Interaction happens in **agent chat**, not the terminal. The agent runs CLI helpers and gates when needed.
|
|
58
67
|
|
|
59
|
-
|
|
68
|
+
### Core commands
|
|
60
69
|
|
|
61
|
-
| Command |
|
|
70
|
+
| Command | Use when |
|
|
62
71
|
| --- | --- |
|
|
63
|
-
| `/specify` |
|
|
64
|
-
| `/
|
|
65
|
-
| `/
|
|
66
|
-
| `/
|
|
67
|
-
| `/
|
|
72
|
+
| `/specify` | Starting any non-trivial feature — requirements in writing first |
|
|
73
|
+
| `/elicit` | Kickoff or request is vague — structured Q&A before Specify *(optional)* |
|
|
74
|
+
| `/tasks` | Spec approved — break work into a job list |
|
|
75
|
+
| `/loop` | Implementation — one wave at a time |
|
|
76
|
+
| `/verify` | All jobs done — independent proof *(prefer a fresh chat)* |
|
|
77
|
+
| `/archive` | Feature validated — fold into project memory |
|
|
78
|
+
| `/quick` | Tiny fix only (≤3 files, no design fork) |
|
|
68
79
|
|
|
69
80
|
**Typical path:** `/specify` → approve → `/tasks` → approve → `/loop` → `/verify` → `/archive`
|
|
70
81
|
|
|
71
|
-
|
|
82
|
+
When input is still exploratory, `/explore` or `/elicit` may come first. The agent suggests depth; it does not block Specify without approval.
|
|
72
83
|
|
|
73
|
-
|
|
84
|
+
Command reference: [Agent commands](docs/guide/agent-commands.md) · Entry paths: [Overview → Three ways to start](docs/guide/Overview.md#three-ways-to-start-pick-one)
|
|
74
85
|
|
|
75
|
-
|
|
86
|
+
### Optional capabilities
|
|
76
87
|
|
|
77
|
-
|
|
88
|
+
Enable when the work warrants them — most teams start with the core loop only.
|
|
78
89
|
|
|
79
|
-
|
|
|
80
|
-
| --- | --- |
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
| Capability | Purpose |
|
|
91
|
+
| --- | --- |
|
|
92
|
+
| Memory search | Retrieve past specs, validations, and kickoff briefs |
|
|
93
|
+
| Context guards | Scope check before edit or “done” (Cursor: hooks) |
|
|
94
|
+
| Episodic memory | Session notes → lessons for future runs |
|
|
95
|
+
| Code index | Lightweight brownfield file and symbol map |
|
|
96
|
+
| Solution exploration | Compare implementation options before committing |
|
|
97
|
+
| Sandbox policy | Warn or block destructive shell commands (Cursor hook) |
|
|
98
|
+
| Execution policy | Path allowlists, budgets, read/write/delete effects |
|
|
99
|
+
| Semantic retrieval | Search by meaning — off by default |
|
|
85
100
|
|
|
86
|
-
|
|
101
|
+
Guides: [Memory](docs/guide/Memory.md) · [Cursor hooks and sandbox](docs/guide/Cursor-hooks-and-sandbox.md) · [Brownfield context](docs/guide/brownfield-context.md)
|
|
87
102
|
|
|
88
103
|
---
|
|
89
104
|
|
|
90
|
-
## What lands in your
|
|
105
|
+
## What lands in your repository
|
|
91
106
|
|
|
92
107
|
| Path | Role |
|
|
93
108
|
| --- | --- |
|
|
94
|
-
| `.cursor/skills/` (
|
|
95
|
-
| `.specs/STATE.md` |
|
|
96
|
-
| `.specs/features/NNN-slug/` | Spec, tasks, validation
|
|
109
|
+
| `.cursor/skills/` (+ Claude, Copilot, Codex trees) | Phase instructions for the agent |
|
|
110
|
+
| `.specs/STATE.md` | Active feature and next step |
|
|
111
|
+
| `.specs/features/NNN-slug/` | Spec, tasks, and validation per feature |
|
|
97
112
|
| `.specs/guardrails/scripts/` | Python gates (Brakes mode) |
|
|
98
|
-
| `.specs/config.yaml` | Optional project rules and policy |
|
|
113
|
+
| `.specs/config.yaml` | Optional project rules and execution policy |
|
|
114
|
+
|
|
115
|
+
Architecture: [Skills and hub](docs/guide/skills-and-hub.md) · [Architecture](docs/guide/Architecture.md)
|
|
99
116
|
|
|
100
117
|
---
|
|
101
118
|
|
|
102
|
-
##
|
|
119
|
+
## Documentation
|
|
103
120
|
|
|
104
|
-
|
|
121
|
+
Start with the guide that matches your question; each page links deeper where needed.
|
|
105
122
|
|
|
106
|
-
|
|
|
123
|
+
| Topic | Start here | Go deeper |
|
|
107
124
|
| --- | --- | --- |
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
| **Semantic retrieval** | Search by meaning (needs OpenAI or Ollama) | [Memory → Semantic](docs/guide/Memory.md#semantic-search-optional) |
|
|
125
|
+
| Orientation | [Overview](docs/guide/Overview.md) | [Concepts](docs/guide/concepts.md) |
|
|
126
|
+
| First session | [Quick start](docs/guide/Quick-start.md) | [Agent commands](docs/guide/agent-commands.md) |
|
|
127
|
+
| Cursor IDE protection | [Cursor hooks and sandbox](docs/guide/Cursor-hooks-and-sandbox.md) | [Guarantees matrix](docs/guide/Guarantees-matrix.md) |
|
|
128
|
+
| Process model | [How it works](docs/guide/How-it-works.md) | [Loop patterns](docs/guide/loop-patterns.md) |
|
|
129
|
+
| Enforcement | [Gates](docs/guide/gates.md) | [Gates and guarantees](docs/guide/Gates-and-guarantees.md) |
|
|
130
|
+
| Long-running projects | [Memory](docs/guide/Memory.md) | [Brownfield context](docs/guide/brownfield-context.md) |
|
|
131
|
+
| Questions | [FAQ](docs/guide/FAQ.md) | [Stability policy](docs/guide/Stability-policy.md) |
|
|
116
132
|
|
|
117
|
-
|
|
133
|
+
Full index: [docs/guide/README.md](docs/guide/README.md)
|
|
118
134
|
|
|
119
135
|
---
|
|
120
136
|
|
|
121
|
-
##
|
|
137
|
+
## Contributing
|
|
122
138
|
|
|
123
|
-
|
|
124
|
-
| --- | --- |
|
|
125
|
-
| **[Overview](docs/guide/Overview.md)** | Complete simple picture — workflow, layers, team use |
|
|
126
|
-
| [Quick start](docs/guide/Quick-start.md) | First ten minutes |
|
|
127
|
-
| [How it works](docs/guide/How-it-works.md) | Story from idea to archive |
|
|
128
|
-
| [Memory](docs/guide/Memory.md) | `.specs/` memory and search — when and how much |
|
|
129
|
-
| [FAQ](docs/guide/FAQ.md) | Common questions |
|
|
139
|
+
We welcome focused improvements — skills, gates, CLI, docs, and tests. See [CONTRIBUTING.md](CONTRIBUTING.md) for layout, gate stability rules, and local checks.
|
|
130
140
|
|
|
131
|
-
|
|
132
|
-
| --- | --- |
|
|
133
|
-
| [Agent commands](docs/guide/agent-commands.md) | Every `/specify`, `/loop`, CLI helper |
|
|
134
|
-
| [Guarantees matrix](docs/guide/Guarantees-matrix.md) | Product promises → mechanisms |
|
|
135
|
-
| [Gates](docs/guide/gates.md) | What each gate checks |
|
|
136
|
-
| [Architecture](docs/guide/Architecture.md) | Core vs platform adapters |
|
|
137
|
-
| [Concepts](docs/guide/concepts.md) | Spec-driven, loop, graph, tiers |
|
|
138
|
-
| [Changelog](docs/CHANGELOG.md) | Version history |
|
|
141
|
+
### Use Spec Guardrails to build your contribution
|
|
139
142
|
|
|
140
|
-
|
|
143
|
+
The recommended workflow is to **dogfood the product**: install Spec Guardrails, describe your change through the agent phases, implement against approved artifacts, and verify before opening a PR.
|
|
141
144
|
|
|
142
|
-
|
|
145
|
+
**In your own project or fork** — use the latest stable release from npm:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
npx @luizsantiago/spec-guardrails@latest install
|
|
149
|
+
npx @luizsantiago/spec-guardrails doctor
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Then in chat: `/specify` (or `/elicit` if scope is unclear) → `/tasks` → `/loop` → `/verify`. Your `.specs/` folder holds the spec and proof that guided the change.
|
|
143
153
|
|
|
144
|
-
|
|
154
|
+
**In this source repository** — work against the branch you are developing, not the published tarball:
|
|
145
155
|
|
|
146
156
|
```bash
|
|
147
|
-
|
|
157
|
+
git clone https://github.com/luizssantiago92/spec-guardrails.git
|
|
158
|
+
cd spec-guardrails
|
|
159
|
+
npm install
|
|
160
|
+
npm run guardrails -- install
|
|
161
|
+
npm run guardrails -- doctor
|
|
148
162
|
```
|
|
149
163
|
|
|
150
|
-
|
|
164
|
+
Edit source under `skills/`, `lib/`, `scripts/`, and `rules/`; re-run `npm run guardrails -- install` after skill or gate changes. Run `npm test` before every PR.
|
|
165
|
+
|
|
166
|
+
| Path | Role |
|
|
167
|
+
| --- | --- |
|
|
168
|
+
| `skills/` | Hub and sister skills shipped to consumers |
|
|
169
|
+
| `skills/references/` | Phase procedures (`specify.md`, `elicit.md`, …) |
|
|
170
|
+
| `scripts/` | Deterministic Python gates |
|
|
171
|
+
| `test/` | Node install tests and Python gate suites |
|
|
172
|
+
|
|
173
|
+
Gate changes follow the adversarial test policy in [CONTRIBUTING.md](CONTRIBUTING.md). Credits: [docs/guide/credits.md](docs/guide/credits.md)
|
|
151
174
|
|
|
152
175
|
---
|
|
153
176
|
|
|
154
|
-
##
|
|
177
|
+
## License
|
|
155
178
|
|
|
156
|
-
|
|
157
|
-
- [Credits](docs/guide/credits.md)
|
|
158
|
-
- MIT — see [LICENSE](LICENSE)
|
|
179
|
+
MIT — see [LICENSE](LICENSE).
|
package/index.js
CHANGED
|
@@ -35,6 +35,11 @@ import {
|
|
|
35
35
|
listWorkspaces,
|
|
36
36
|
prepareWorkspaces,
|
|
37
37
|
} from "./lib/workspace-isolation.js";
|
|
38
|
+
import {
|
|
39
|
+
formatDiscoverReport,
|
|
40
|
+
formatPromoteMessage,
|
|
41
|
+
reqAnalysisInit,
|
|
42
|
+
} from "./lib/req-analysis.js";
|
|
38
43
|
import {
|
|
39
44
|
formatExplorationInit,
|
|
40
45
|
formatExplorationStatus,
|
|
@@ -76,6 +81,17 @@ Commands:
|
|
|
76
81
|
feature-init "<description>" Allocate NNN-slug feature, STATE, local branch (Tier 0)
|
|
77
82
|
[--no-branch] Skip git checkout -b
|
|
78
83
|
[--no-spec] Skip spec.md stub
|
|
84
|
+
req-analysis init "<description>" Scaffold requirements brief (/elicit phase)
|
|
85
|
+
[--scope project|feature] project = macro brief; feature = one delivery (default: feature)
|
|
86
|
+
[--force] Replace existing brief scaffold
|
|
87
|
+
req-analysis discover List local kickoff sources (prd.md, kickoff.md, …)
|
|
88
|
+
req-analysis promote Print next steps after brief approval
|
|
89
|
+
[--scope project|feature] Match the brief scope
|
|
90
|
+
req-analysis validate [brief.md] Gate: approved requirements brief before /specify
|
|
91
|
+
req-analysis context Assemble kickoff + brief context for Specify
|
|
92
|
+
[--scope project|feature] Scope (default: project)
|
|
93
|
+
[--slug <feature-slug>] Feature slug when scope=feature
|
|
94
|
+
[--json] Machine-readable output
|
|
79
95
|
archive-feature [feature] Fold verified feature into ROADMAP + domain spec; reset STATE
|
|
80
96
|
[--domain <slug>] Domain folder under .specs/domains/ (default: feature slug)
|
|
81
97
|
[--skip-verify] Skip validate-state (tests / recovery only)
|
|
@@ -157,6 +173,7 @@ Commands:
|
|
|
157
173
|
[--json] Machine-readable plan for agents
|
|
158
174
|
validate-traceability [feature] REQ → tasks → validation coverage chain
|
|
159
175
|
validate-quick [quick-folder] Quick-mode TASK.md / SUMMARY.md structural gate
|
|
176
|
+
validate-req-analysis [brief.md] Requirements brief gate before /specify (/elicit)
|
|
160
177
|
validate-state [feature] Completion gate before declaring a feature done
|
|
161
178
|
check-commit --message "<msg>" Conventional Commits gate
|
|
162
179
|
lessons <add|list|penalize|prune|promote|graduate|status> Lessons engine
|
|
@@ -890,6 +907,98 @@ if (command === "--version" || command === "-v" || command === "version") {
|
|
|
890
907
|
console.error(`❌ ${err.message}`);
|
|
891
908
|
process.exit(1);
|
|
892
909
|
}
|
|
910
|
+
} else if (command === "req-analysis") {
|
|
911
|
+
try {
|
|
912
|
+
const sub = args[0];
|
|
913
|
+
const rest = args.slice(1);
|
|
914
|
+
|
|
915
|
+
if (sub === "init") {
|
|
916
|
+
let scope = "feature";
|
|
917
|
+
let force = false;
|
|
918
|
+
const positional = [];
|
|
919
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
920
|
+
const arg = rest[i];
|
|
921
|
+
if (arg === "--force") {
|
|
922
|
+
force = true;
|
|
923
|
+
} else if (arg === "--scope" && rest[i + 1]) {
|
|
924
|
+
scope = rest[i + 1];
|
|
925
|
+
i += 1;
|
|
926
|
+
} else if (arg.startsWith("--scope=")) {
|
|
927
|
+
scope = arg.slice("--scope=".length);
|
|
928
|
+
} else if (!arg.startsWith("--")) {
|
|
929
|
+
positional.push(arg);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
const description = positional.join(" ").trim();
|
|
933
|
+
if (scope === "feature" && !description) {
|
|
934
|
+
throw new Error(
|
|
935
|
+
'Usage: req-analysis init "<description>" [--scope project|feature] [--force]',
|
|
936
|
+
);
|
|
937
|
+
}
|
|
938
|
+
const result = await reqAnalysisInit(description, { scope, force });
|
|
939
|
+
console.log(`✅ Elicitation scaffold (${result.scope})`);
|
|
940
|
+
for (const briefPath of result.paths) {
|
|
941
|
+
console.log(` ${briefPath}`);
|
|
942
|
+
}
|
|
943
|
+
console.log("");
|
|
944
|
+
console.log(await formatDiscoverReport(process.cwd()));
|
|
945
|
+
} else if (sub === "discover") {
|
|
946
|
+
console.log(await formatDiscoverReport(process.cwd()));
|
|
947
|
+
} else if (sub === "promote") {
|
|
948
|
+
let scope = "feature";
|
|
949
|
+
let description = "";
|
|
950
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
951
|
+
const arg = rest[i];
|
|
952
|
+
if (arg.startsWith("--scope=")) {
|
|
953
|
+
scope = arg.slice("--scope=".length);
|
|
954
|
+
} else if (arg === "--scope" && rest[i + 1]) {
|
|
955
|
+
scope = rest[i + 1];
|
|
956
|
+
i += 1;
|
|
957
|
+
} else if (!arg.startsWith("--")) {
|
|
958
|
+
description = `${description} ${arg}`.trim();
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
console.log(formatPromoteMessage({ scope, description }));
|
|
962
|
+
} else if (sub === "validate") {
|
|
963
|
+
const briefPath = rest.find((arg) => !arg.startsWith("--"));
|
|
964
|
+
const code = await runGate("validate-req-analysis", briefPath ? [briefPath] : []);
|
|
965
|
+
process.exit(code);
|
|
966
|
+
} else if (sub === "context") {
|
|
967
|
+
let scope = "project";
|
|
968
|
+
let slug = "";
|
|
969
|
+
let json = false;
|
|
970
|
+
for (let i = 0; i < rest.length; i += 1) {
|
|
971
|
+
const arg = rest[i];
|
|
972
|
+
if (arg === "--json") {
|
|
973
|
+
json = true;
|
|
974
|
+
} else if (arg === "--scope" && rest[i + 1]) {
|
|
975
|
+
scope = rest[i + 1];
|
|
976
|
+
i += 1;
|
|
977
|
+
} else if (arg.startsWith("--scope=")) {
|
|
978
|
+
scope = arg.slice("--scope=".length);
|
|
979
|
+
} else if (arg === "--slug" && rest[i + 1]) {
|
|
980
|
+
slug = rest[i + 1];
|
|
981
|
+
i += 1;
|
|
982
|
+
} else if (arg.startsWith("--slug=")) {
|
|
983
|
+
slug = arg.slice("--slug=".length);
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
const scriptArgs = ["--scope", scope];
|
|
987
|
+
if (slug) {
|
|
988
|
+
scriptArgs.push("--slug", slug);
|
|
989
|
+
}
|
|
990
|
+
if (json) {
|
|
991
|
+
scriptArgs.push("--json");
|
|
992
|
+
}
|
|
993
|
+
const code = await runGuardrailsScript("req-context", scriptArgs);
|
|
994
|
+
process.exit(code);
|
|
995
|
+
} else {
|
|
996
|
+
throw new Error("Usage: req-analysis init | discover | promote | validate | context");
|
|
997
|
+
}
|
|
998
|
+
} catch (err) {
|
|
999
|
+
console.error(`❌ ${err.message}`);
|
|
1000
|
+
process.exit(1);
|
|
1001
|
+
}
|
|
893
1002
|
} else if (command === "classify-change") {
|
|
894
1003
|
try {
|
|
895
1004
|
let json = false;
|
package/lib/classify-change.js
CHANGED
|
@@ -26,12 +26,21 @@ const DEPENDENCY_SIGNALS = [
|
|
|
26
26
|
/\badd\s+package\b/i,
|
|
27
27
|
];
|
|
28
28
|
|
|
29
|
+
const VAGUE_SIGNALS = [
|
|
30
|
+
/\bimprove\b/i,
|
|
31
|
+
/\bmake\s+(?:it|this|things?)\s+better\b/i,
|
|
32
|
+
/\badd\s+(?:a\s+)?(?:interface|page|screen|ui|dashboard)\b/i,
|
|
33
|
+
/\b(?:somehow|something|stuff)\b/i,
|
|
34
|
+
/\bwithout\s+(?:criteria|details|spec)\b/i,
|
|
35
|
+
];
|
|
36
|
+
|
|
29
37
|
/**
|
|
30
38
|
* @param {{ description?: string, files?: string[] }} input
|
|
31
39
|
* @returns {{
|
|
32
40
|
* tier: "quick" | "simple" | "medium" | "complex",
|
|
33
41
|
* reasons: string[],
|
|
34
42
|
* next: string,
|
|
43
|
+
* suggestElicit: boolean,
|
|
35
44
|
* fileCount: number,
|
|
36
45
|
* }}
|
|
37
46
|
*/
|
|
@@ -45,6 +54,7 @@ export function classifyChange(input = {}) {
|
|
|
45
54
|
const hasComplex = COMPLEX_SIGNALS.some((re) => re.test(haystack));
|
|
46
55
|
const hasMedium = MEDIUM_SIGNALS.some((re) => re.test(haystack));
|
|
47
56
|
const hasNewDep = DEPENDENCY_SIGNALS.some((re) => re.test(haystack));
|
|
57
|
+
const hasVague = VAGUE_SIGNALS.some((re) => re.test(haystack));
|
|
48
58
|
|
|
49
59
|
if (hasComplex) {
|
|
50
60
|
reasons.push("sensitive surface or architecture signal in description/paths");
|
|
@@ -103,10 +113,15 @@ export function classifyChange(input = {}) {
|
|
|
103
113
|
'feature-init → full pipeline (+ /discuss, /plan; optional AppSec/QA on verify)',
|
|
104
114
|
};
|
|
105
115
|
|
|
116
|
+
if (hasVague) {
|
|
117
|
+
reasons.push("vague delivery language — consider /elicit before /specify");
|
|
118
|
+
}
|
|
119
|
+
|
|
106
120
|
return {
|
|
107
121
|
tier,
|
|
108
122
|
reasons,
|
|
109
123
|
next: nextByTier[tier],
|
|
124
|
+
suggestElicit: hasVague && !hasComplex,
|
|
110
125
|
fileCount,
|
|
111
126
|
};
|
|
112
127
|
}
|
|
@@ -123,5 +138,8 @@ export function formatClassifyChange(result) {
|
|
|
123
138
|
...result.reasons.map((r) => ` - ${r}`),
|
|
124
139
|
`Next: ${result.next}`,
|
|
125
140
|
];
|
|
141
|
+
if (result.suggestElicit) {
|
|
142
|
+
lines.push("Suggest: /elicit (structured Q&A) or /specify if scope is already clear");
|
|
143
|
+
}
|
|
126
144
|
return `${lines.join("\n")}\n`;
|
|
127
145
|
}
|
package/lib/constants.js
CHANGED
|
@@ -77,6 +77,7 @@ export const SKILL_ASSETS = [
|
|
|
77
77
|
/** @type {{ file: string, remotePath: string }[]} */
|
|
78
78
|
export const REFERENCE_ASSETS = [
|
|
79
79
|
{ file: "explore.md", remotePath: "skills/references/explore.md" },
|
|
80
|
+
{ file: "elicitation.md", remotePath: "skills/references/elicitation.md" },
|
|
80
81
|
{ file: "solution-exploration.md", remotePath: "skills/references/solution-exploration.md" },
|
|
81
82
|
{ file: "project-init.md", remotePath: "skills/references/project-init.md" },
|
|
82
83
|
{ file: "constitution.md", remotePath: "skills/references/constitution.md" },
|
|
@@ -117,6 +118,8 @@ export const SCRIPT_ASSETS = [
|
|
|
117
118
|
{ file: "_memory_embed.py", remotePath: "scripts/_memory_embed.py" },
|
|
118
119
|
{ file: "episodes.py", remotePath: "scripts/episodes.py" },
|
|
119
120
|
{ file: "code_index.py", remotePath: "scripts/code_index.py" },
|
|
121
|
+
{ file: "validate_req_analysis.py", remotePath: "scripts/validate_req_analysis.py" },
|
|
122
|
+
{ file: "req_context.py", remotePath: "scripts/req_context.py" },
|
|
120
123
|
];
|
|
121
124
|
|
|
122
125
|
/** @type {{ file: string, remotePath: string }[]} */
|
package/lib/gates.js
CHANGED
|
@@ -34,6 +34,7 @@ const GATE_SCRIPTS = {
|
|
|
34
34
|
"validate-state": "validate_state.py",
|
|
35
35
|
"validate-traceability": "validate_traceability.py",
|
|
36
36
|
"validate-quick": "validate_quick.py",
|
|
37
|
+
"validate-req-analysis": "validate_req_analysis.py",
|
|
37
38
|
"analyze-artifacts": "analyze_artifacts.py",
|
|
38
39
|
"check-commit": "check_commit.py",
|
|
39
40
|
lessons: "lessons.py",
|
|
@@ -47,6 +48,7 @@ const AUX_SCRIPTS = {
|
|
|
47
48
|
"memory-retrieve": "memory_retrieve.py",
|
|
48
49
|
episodes: "episodes.py",
|
|
49
50
|
"code-index": "code_index.py",
|
|
51
|
+
"req-context": "req_context.py",
|
|
50
52
|
};
|
|
51
53
|
|
|
52
54
|
const GUARDRAILS_SCRIPTS = { ...GATE_SCRIPTS, ...AUX_SCRIPTS };
|