@massa-ai/cursor-plugin 1.21.0 → 1.22.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/.cursor-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/skills/massa-ai/references/evidence-gate.md +1 -1
- package/skills/massa-ai/references/hook-enforcement.md +2 -2
- package/skills/massa-ai/references/implementation-delivery.md +3 -3
- package/skills/massa-ai/references/lessons.md +9 -10
- package/skills/massa-ai/references/mcp-tools.md +1 -1
- package/skills/massa-ai/references/project-context.md +1 -1
- package/skills/massa-ai/references/spec-driven/artifact-store.md +7 -8
- package/skills/massa-ai/references/spec-driven/design.md +1 -1
- package/skills/massa-ai/references/spec-driven/execute.md +5 -5
- package/skills/massa-ai/references/spec-driven/specify.md +6 -6
- package/skills/massa-ai/references/spec-driven/sub-agents.md +1 -1
- package/skills/massa-ai/references/spec-driven/tasks.md +2 -2
- package/skills/massa-ai/references/spec-driven/validate.md +3 -3
- package/skills/massa-ai/scripts/check_commit.ts +231 -0
- package/skills/massa-ai/scripts/check_specs_delivered.ts +209 -0
- package/skills/massa-ai/scripts/lessons.ts +907 -0
- package/skills/massa-ai/scripts/validate_spec.ts +413 -0
- package/skills/massa-ai/scripts/validate_state.ts +276 -0
- package/skills/massa-ai/scripts/validate_tasks.ts +498 -0
- package/skills/massa-ai/workflows/architecture/architecture-fix.md +1 -1
- package/skills/massa-ai/workflows/bugs/bugs-fix.md +1 -1
- package/skills/massa-ai/workflows/code-quality/code-quality-fix.md +1 -1
- package/skills/massa-ai/workflows/debug.md +1 -1
- package/skills/massa-ai/workflows/feature.md +1 -1
- package/skills/massa-ai/workflows/general.md +2 -2
- package/skills/massa-ai/workflows/implementation/implementation-fix.md +1 -1
- package/skills/massa-ai/workflows/maestro/maestro-fix.md +1 -1
- package/skills/massa-ai/workflows/mobile-figma/mobile-figma-fix.md +1 -1
- package/skills/massa-ai/workflows/refactor.md +1 -1
- package/skills/massa-ai/workflows/requirements/requirements-fix.md +1 -1
- package/skills/massa-ai/workflows/security/security-fix.md +1 -1
- package/skills/massa-ai/workflows/spec-driven.md +3 -3
- package/skills/massa-ai/workflows/tests/tests-fix.md +1 -1
- package/skills/massa-ai/scripts/check_commit.py +0 -128
- package/skills/massa-ai/scripts/check_specs_delivered.py +0 -137
- package/skills/massa-ai/scripts/lessons.py +0 -630
- package/skills/massa-ai/scripts/validate_spec.py +0 -272
- package/skills/massa-ai/scripts/validate_state.py +0 -183
- package/skills/massa-ai/scripts/validate_tasks.py +0 -302
package/package.json
CHANGED
|
@@ -38,7 +38,7 @@ Use this compact shape when closing docs or skill work:
|
|
|
38
38
|
✅ [Verified] Skill validation and stale-reference scans passed.
|
|
39
39
|
🏁 [Finished] Updated massa-ai references. Memory outcome: durable decision stored. Remaining risk: none found.
|
|
40
40
|
|
|
41
|
-
Evidence: `
|
|
41
|
+
Evidence: `bun run scripts/generate-skill-artifacts.ts --check` passed; stale-reference and local-link scans passed.
|
|
42
42
|
Changed artifacts: `skills/massa-ai/SKILL.md`, `workflows/spec-driven.md`, `references/spec-driven/`, and `references/memory-policy.md`.
|
|
43
43
|
Memory outcome: wrote decision memory `dec_...`; no failed memory writes.
|
|
44
44
|
Residual risk: none found.
|
|
@@ -44,7 +44,7 @@ Every hook exits 0 on bad stdin or non-critical error. Blocking hooks are
|
|
|
44
44
|
| Hook | Event | Enforces |
|
|
45
45
|
|---|---|---|
|
|
46
46
|
| `stop_evidence_gate.py` | Stop | `references/evidence-gate.md` |
|
|
47
|
-
| `continuous_learning_evaluate.py` | Stop | `references/lessons.md`, `scripts/lessons.
|
|
47
|
+
| `continuous_learning_evaluate.py` | Stop | `references/lessons.md`, `scripts/lessons.ts` |
|
|
48
48
|
| `precompact_save_state.py` | PreCompact | `workflows/long-session.md`, `references/context-firewall.md` |
|
|
49
49
|
| `suggest_compact.py` | PreToolUse(Edit\|Write) | `references/context-firewall.md` (compaction boundary) |
|
|
50
50
|
| `gateguard_fact_force.py` | PreToolUse(Edit) | `references/context-firewall.md` (investigate-before-edit) |
|
|
@@ -100,7 +100,7 @@ absent, it falls back to the flat evidence matrix (graceful degradation).
|
|
|
100
100
|
|
|
101
101
|
The continuous-learning loop writes two stores, not one:
|
|
102
102
|
|
|
103
|
-
- `lessons.
|
|
103
|
+
- `lessons.ts add` / `import` — deterministic grounded file store
|
|
104
104
|
(`.specs/lessons.json`); refuses ungrounded lessons; promotion/quarantine.
|
|
105
105
|
- `remember` — durable memory, best-effort via REST (`MASSA_AI_API_URL`),
|
|
106
106
|
file-only fallback when REST is unavailable.
|
|
@@ -22,8 +22,8 @@ human chose to merge it".
|
|
|
22
22
|
| 1 | Isolate | `git fetch origin <base> && git worktree add -b <type>/<slug> <path> origin/<base>` | Branch name taken → suffix `-2`. Worktree path taken → reuse it only if its branch matches |
|
|
23
23
|
| 2 | Implement | one task → gate → `git commit` | Gate red → fix before committing. Never commit through a failing gate |
|
|
24
24
|
| 3 | Push | `git push -u origin <type>/<slug>` | Rejected non-fast-forward → `git fetch` + rebase, never force-push a shared branch |
|
|
25
|
-
| 3.5 | Deliver specs | `
|
|
26
|
-
| 4 | Propose — precondition: Stage 3.5 (`check_specs_delivered.
|
|
25
|
+
| 3.5 | Deliver specs | `bun skills/massa-ai/scripts/check_specs_delivered.ts <feature> [--root .]` | Non-zero → commit the missing `.specs/` updates (a `docs(specs):`-type commit is normal), push, re-run. Defensive fallback — should not fire when the close-out task already committed `.specs/` before the first push |
|
|
26
|
+
| 4 | Propose — precondition: Stage 3.5 (`check_specs_delivered.ts`) green | `gh pr create --base <base> --title <t> --body <b>` | `gh` absent/unauthenticated → degraded path |
|
|
27
27
|
| 5 | Watch | `gh pr checks --watch` | No checks configured → say so; do not claim CI passed |
|
|
28
28
|
| 6 | Repair | fix on the branch, commit, return to stage 5 | Capped at 3 iterations, then stop as `Blocked` |
|
|
29
29
|
| 7 | **Ask** | report the PR URL and the green check list, then **stop** | — |
|
|
@@ -76,7 +76,7 @@ One explicit delivery authorization per feature, obtained before implementation
|
|
|
76
76
|
|
|
77
77
|
### Stage 3.5 — deliver specs before PR (defensive fallback)
|
|
78
78
|
|
|
79
|
-
Between Push and Propose, all feature `.specs/` artifacts (`spec/context/design/tasks/validation` as applicable), `.specs/project/STATE.md`, `.specs/HANDOFF.md`, and `.specs/project/FEATURES.json` must be updated and committed on the branch. **Deterministic backing (run it, do not eyeball it):** `
|
|
79
|
+
Between Push and Propose, all feature `.specs/` artifacts (`spec/context/design/tasks/validation` as applicable), `.specs/project/STATE.md`, `.specs/HANDOFF.md`, and `.specs/project/FEATURES.json` must be updated and committed on the branch. **Deterministic backing (run it, do not eyeball it):** `bun skills/massa-ai/scripts/check_specs_delivered.ts <feature> [--root .]` — a non-zero exit blocks Propose. If no code-execution tool is available, run the same checks by reading the artifact (graceful degradation preserved).
|
|
80
80
|
|
|
81
81
|
**Nominal path: this stage should never fire.** The feature's own close-out task (the last task before delivery — see `workflows/spec-driven.md` step 7) commits `.specs/` updates **before** the first push, so stage 3.5's remediation is a defensive fallback for the rare case something slipped through, not the normal place `.specs/` gets committed. On failure: commit the missing `.specs/` updates (a `docs(specs):`-type commit is normal), push, re-run this stage. No commits may land between the close-out commit and PR creation.
|
|
82
82
|
|
|
@@ -4,9 +4,8 @@ Use this reference when loading confirmed project lessons during startup, or rec
|
|
|
4
4
|
|
|
5
5
|
## Artifacts
|
|
6
6
|
|
|
7
|
-
- `.specs/lessons.json` — canonical machine-owned lesson state. Read it; do not hand-edit.
|
|
8
|
-
-
|
|
9
|
-
- `skills/massa-ai/scripts/lessons.py` — deterministic bookkeeping script.
|
|
7
|
+
- `.specs/lessons.json` — canonical machine-owned lesson state, the single lessons store. Read it; do not hand-edit.
|
|
8
|
+
- `skills/massa-ai/scripts/lessons.ts` — deterministic bookkeeping script; `lessons list` is the on-demand view.
|
|
10
9
|
|
|
11
10
|
## Lesson Signal Table
|
|
12
11
|
|
|
@@ -23,7 +22,7 @@ Use this reference when loading confirmed project lessons during startup, or rec
|
|
|
23
22
|
After a workflow's verification step finds a concrete reusable signal, record it:
|
|
24
23
|
|
|
25
24
|
```bash
|
|
26
|
-
|
|
25
|
+
bun skills/massa-ai/scripts/lessons.ts --root . add \
|
|
27
26
|
--feature "<feature-slug>" \
|
|
28
27
|
--signal "<ac_gap|surviving_mutant|spec_precision_gap|spec_deviation|gate_fail>" \
|
|
29
28
|
--source "<validation.md source, AC id, file:line, mutant id, or SPEC_DEVIATION ref>" \
|
|
@@ -51,7 +50,7 @@ Run this self-check after verification: if a failed acceptance criterion, surviv
|
|
|
51
50
|
During startup of any applicable workflow, load confirmed lessons when `.specs/lessons.json` exists:
|
|
52
51
|
|
|
53
52
|
```bash
|
|
54
|
-
|
|
53
|
+
bun skills/massa-ai/scripts/lessons.ts --root . list --status confirmed [--scope <relevant>]
|
|
55
54
|
```
|
|
56
55
|
|
|
57
56
|
- Use `--scope` or `--query` to keep the loaded set small.
|
|
@@ -69,7 +68,7 @@ python3 skills/massa-ai/scripts/lessons.py --root . list --status confirmed [--s
|
|
|
69
68
|
|
|
70
69
|
## No-Script Fallback
|
|
71
70
|
|
|
72
|
-
If `lessons.
|
|
71
|
+
If `lessons.ts` is unavailable or cannot run, record `Lessons: skipped - script unavailable` in the validation report or evidence gate, keep the raw signal in the report, and do not hand-edit `lessons.json`. A future run with the script can import the validated signal.
|
|
73
72
|
|
|
74
73
|
## Continuous-Learning Loop (hook-fed)
|
|
75
74
|
|
|
@@ -82,13 +81,13 @@ The lessons layer is a closed loop, not manual-only. Two runtime hooks
|
|
|
82
81
|
2. **evaluate** — `continuous_learning_evaluate.py` (Stop) reads the active
|
|
83
82
|
massa-ai context from `.specs/project/STATE.md` and the observations
|
|
84
83
|
buffer. For each observation that already carries grounded fields
|
|
85
|
-
(`signal`, `text`, `source`, `feature`), it calls `lessons.
|
|
84
|
+
(`signal`, `text`, `source`, `feature`), it calls `lessons.ts add` with the
|
|
86
85
|
`--project`/`--session`/`--workflow`/`--entity` context. Ungrounded
|
|
87
86
|
observations are left in the buffer for agent input and logged as skipped.
|
|
88
87
|
|
|
89
88
|
### massa-ai Dual-Write
|
|
90
89
|
|
|
91
|
-
`lessons.
|
|
90
|
+
`lessons.ts add` and `import` best-effort write massa-ai memory so the file store
|
|
92
91
|
and durable memory stay consistent:
|
|
93
92
|
|
|
94
93
|
- **type** is always `pattern` (lessons are procedural knowledge). `procedural`
|
|
@@ -105,8 +104,8 @@ and durable memory stay consistent:
|
|
|
105
104
|
### Round-Trip
|
|
106
105
|
|
|
107
106
|
```bash
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
bun skills/massa-ai/scripts/lessons.ts --root . export --out lessons.export.json
|
|
108
|
+
bun skills/massa-ai/scripts/lessons.ts --root . import --in lessons.export.json
|
|
110
109
|
```
|
|
111
110
|
|
|
112
111
|
`export`/`import` round-trip the file store; `import` re-emits massa-ai memory
|
|
@@ -285,7 +285,7 @@ delay. Preferred shell pattern:
|
|
|
285
285
|
MASSA_AI_API_URL="${MASSA_AI_API_URL:-http://localhost:3333}"
|
|
286
286
|
for i in $(seq 1 40); do
|
|
287
287
|
result=$(rtk curl -s "$MASSA_AI_API_URL/api/v1/project/index/status/JOB_ID")
|
|
288
|
-
status=$(printf '%s' "$result" |
|
|
288
|
+
status=$(printf '%s' "$result" | bun -e "console.log(JSON.parse(await Bun.stdin.text()).data.status)")
|
|
289
289
|
printf '[%s] status=%s\n' "$i" "$status"
|
|
290
290
|
[ "$status" = "completed" ] || [ "$status" = "failed" ] && break
|
|
291
291
|
sleep 15
|
|
@@ -23,7 +23,7 @@ continue only when the next decision still needs more.
|
|
|
23
23
|
| 2 — Host config | `.claude/` (`settings.json`, `settings.local.json`, `commands/`, `agents/`, `skills/`, `hooks/`), `.cursor/` (`rules/`, `mcp.json`), `.github/copilot-instructions.md`, `.opencode/`, `.codex/` | Permissions, hooks, host-specific tooling, MCP registrations |
|
|
24
24
|
| 3 — Product docs | `README.md`, `CONTRIBUTING.md`, `docs/`, `ARCHITECTURE.md` | Install/run/build surface, contribution protocol, architecture |
|
|
25
25
|
| 4 — Delivery config | `.github/workflows/`, `CHANGELOG.md`, `package.json` / `Cargo.toml` / `build.gradle*` / `pyproject.toml`, `.tool-versions`, `mise.toml`, `Makefile` | CI gates, release rules, runtime and toolchain pins, task commands |
|
|
26
|
-
| 5 — Live state | `.specs/project/STATE.md`, `.specs/project/FEATURES.json`, `.specs/HANDOFF.md`, `.specs/
|
|
26
|
+
| 5 — Live state | `.specs/project/STATE.md`, `.specs/project/FEATURES.json`, `.specs/HANDOFF.md`, `.specs/lessons.json` (single store; `lessons list` is the on-demand view) | In-flight work, decisions already made, confirmed lessons |
|
|
27
27
|
|
|
28
28
|
Tier 1 and Tier 3 (`README.md`) are mandatory in every workflow. Tiers 2, 4, and
|
|
29
29
|
5 are read when the task touches host tooling, a gate/release surface, or
|
|
@@ -27,8 +27,7 @@ Use these logical paths:
|
|
|
27
27
|
- `.specs/features/<slug>/validation.md` — feature validation report
|
|
28
28
|
- `.specs/quick/NNN-slug/TASK.md` — quick-mode task (one-line intent + acceptance)
|
|
29
29
|
- `.specs/quick/NNN-slug/SUMMARY.md` — quick-mode result (files changed + gate evidence)
|
|
30
|
-
- `.specs/lessons.json` — machine-owned
|
|
31
|
-
- `.specs/LESSONS.md` — rendered lesson playbook (read-only, generated by `lessons.py`)
|
|
30
|
+
- `.specs/lessons.json` — the single lessons store, machine-owned (managed by `lessons.ts`); `lessons list` is the on-demand view
|
|
32
31
|
|
|
33
32
|
## Quick Artifacts
|
|
34
33
|
|
|
@@ -61,21 +60,21 @@ Quick tasks are also listed in the STATE.md Quick Tasks table (see `references/s
|
|
|
61
60
|
|
|
62
61
|
Load only what you need. Prefer metadata-only inspection before loading full content.
|
|
63
62
|
|
|
64
|
-
- **Feature registry status:** `
|
|
63
|
+
- **Feature registry status:** `bun -e "const d=await Bun.file('.specs/project/FEATURES.json').json(); console.log('active:', d.active_feature); for (const f of d.features??[]) console.log(f.id, f.status);"`
|
|
65
64
|
- **Full feature registry:** `cat .specs/project/FEATURES.json`
|
|
66
65
|
- **Project state:** `cat .specs/project/STATE.md`
|
|
67
66
|
- **Handoff:** `cat .specs/HANDOFF.md`
|
|
68
67
|
- **Feature spec:** `cat .specs/features/<slug>/spec.md`
|
|
69
|
-
- **Confirmed lessons:** `
|
|
68
|
+
- **Confirmed lessons:** `bun skills/massa-ai/scripts/lessons.ts --root . list --status confirmed [--scope <relevant>]`
|
|
70
69
|
|
|
71
70
|
## Writing Artifacts
|
|
72
71
|
|
|
73
|
-
Write artifacts directly to `.specs/` files. Use a here-doc or `printf` for Markdown, or `
|
|
72
|
+
Write artifacts directly to `.specs/` files. Use a here-doc or `printf` for Markdown, or `bun -e` for JSON mutations.
|
|
74
73
|
|
|
75
74
|
- **Update state:** `printf '...' > .specs/project/STATE.md`
|
|
76
75
|
- **Update handoff:** `printf '...' > .specs/HANDOFF.md`
|
|
77
76
|
- **Write feature artifact:** `printf '...' > .specs/features/<slug>/design.md`
|
|
78
|
-
- **Update feature registry:** use `
|
|
77
|
+
- **Update feature registry:** use `bun -e` to read-modify-write `FEATURES.json`
|
|
79
78
|
|
|
80
79
|
Feature activate/complete flows update `.specs/project/FEATURES.json`, `.specs/project/STATE.md`, and `.specs/HANDOFF.md` through file writes.
|
|
81
80
|
|
|
@@ -83,7 +82,7 @@ Feature activate/complete flows update `.specs/project/FEATURES.json`, `.specs/p
|
|
|
83
82
|
|
|
84
83
|
- Feature artifacts under `.specs/features/<slug>/` are versioned by design (one file per slug).
|
|
85
84
|
- `.specs/project/FEATURES.json` and `.specs/project/STATE.md` are append-only versioned by their git history.
|
|
86
|
-
- `lessons.json` versioning is managed automatically by `lessons.
|
|
85
|
+
- `lessons.json` versioning is managed automatically by `lessons.ts`.
|
|
87
86
|
- When content must be superseded (e.g., a decision), update the existing file and rely on git history for the prior version.
|
|
88
87
|
|
|
89
88
|
## Debug Exports
|
|
@@ -94,5 +93,5 @@ Exports under `.specs-exports/` are optional, untracked review aids. Use `cp -r
|
|
|
94
93
|
|
|
95
94
|
- `.specs/` directory missing or not writable: block spec-driven state mutation; do not fall back to memory or chat.
|
|
96
95
|
- Required artifact missing: create it on first write or block unless it is an approved initial creation.
|
|
97
|
-
- `lessons.
|
|
96
|
+
- `lessons.ts` unavailable: skip lessons loading/recording, record skipped reason in validation report.
|
|
98
97
|
.specs/ files
|
|
@@ -35,7 +35,7 @@ Read `.specs/features/<slug>/spec.md` before designing. If `.specs/features/<slu
|
|
|
35
35
|
|
|
36
36
|
Silently ignoring an active decision is not an option — it creates invisible inconsistency across features.
|
|
37
37
|
|
|
38
|
-
**Also load confirmed lessons** relevant to this feature: `
|
|
38
|
+
**Also load confirmed lessons** relevant to this feature: `bun skills/massa-ai/scripts/lessons.ts list --status confirmed` (filter with `--scope`/`--query`). These are past verification failures distilled into guidance — apply them while designing. Load only `confirmed`. Skip silently if no store or no code tool. See [lessons.md](lessons.md).
|
|
39
39
|
|
|
40
40
|
### 1.5. Research (Optional but Recommended)
|
|
41
41
|
|
|
@@ -302,13 +302,13 @@ for reuse across multiple endpoints.
|
|
|
302
302
|
- Never sneak in "while I'm here" changes.
|
|
303
303
|
- If tests are part of the task, include them in the same commit.
|
|
304
304
|
|
|
305
|
-
**Deterministic backing (run it, do not eyeball it):** `
|
|
305
|
+
**Deterministic backing (run it, do not eyeball it):** `bun skills/massa-ai/scripts/check_commit.ts --message "<your message>"` before committing. A non-zero exit means fix the format first — this makes the format rule enforceable instead of memory-dependent. If no code-execution tool is available, run the same checks by reading the artifact (graceful degradation preserved).
|
|
306
306
|
|
|
307
307
|
**Optional git-level guard (git only, no agent dependency).** In a git repo the same check can run on every commit by wiring it as a `commit-msg` hook, so a malformed message is rejected regardless of who or what drives the commit:
|
|
308
308
|
|
|
309
309
|
```bash
|
|
310
310
|
# from the repo root, one time:
|
|
311
|
-
ln -sf skills/massa-ai/scripts/check_commit.
|
|
311
|
+
ln -sf skills/massa-ai/scripts/check_commit.ts .git/hooks/commit-msg && chmod +x .git/hooks/commit-msg
|
|
312
312
|
```
|
|
313
313
|
|
|
314
314
|
This is a plain git hook, not tied to any editor or assistant. Skip it if the project manages hooks its own way (for example a pre-commit framework); the manual check above still applies.
|
|
@@ -316,14 +316,14 @@ This is a plain git hook, not tied to any editor or assistant. Skip it if the pr
|
|
|
316
316
|
**Distill a confirmed lesson** when a task produced a reusable signal (an unexpected failure mode, a confirmed pattern, a corrected assumption):
|
|
317
317
|
|
|
318
318
|
```
|
|
319
|
-
|
|
319
|
+
bun skills/massa-ai/scripts/lessons.ts --root . add \
|
|
320
320
|
--feature <slug> --signal <S> --source <src> --text "<T>" --scope <O>
|
|
321
321
|
```
|
|
322
322
|
|
|
323
323
|
`--source` is mandatory (grounding gate). Load applicable confirmed lessons before starting a task:
|
|
324
324
|
|
|
325
325
|
```
|
|
326
|
-
|
|
326
|
+
bun skills/massa-ai/scripts/lessons.ts --root . list --status confirmed [--scope <relevant>]
|
|
327
327
|
```
|
|
328
328
|
|
|
329
329
|
### 8. Scope Guardrail / Scope Control
|
|
@@ -452,7 +452,7 @@ Then run `references/spec-driven/validate.md` as the final Execute gate. The ver
|
|
|
452
452
|
**Status**: ✅ Complete | ❌ Blocked | ⚠️ Partial
|
|
453
453
|
```
|
|
454
454
|
|
|
455
|
-
**After the LAST task:** dispatch the Verifier sub-agent (see step 9 and [sub-agents.md](sub-agents.md)) for independent feature-level validation, including the spec-anchored check and discrimination sensor. Validation always runs automatically — never prompted. Execute is not done until the Verifier reports PASS and the validation report is written, confirmed deterministically by `
|
|
455
|
+
**After the LAST task:** dispatch the Verifier sub-agent (see step 9 and [sub-agents.md](sub-agents.md)) for independent feature-level validation, including the spec-anchored check and discrimination sensor. Validation always runs automatically — never prompted. Execute is not done until the Verifier reports PASS and the validation report is written, confirmed deterministically by `bun skills/massa-ai/scripts/validate_state.ts <feature> [--root .]` (exit non-zero = not done); see [validate.md](validate.md). If no code-execution tool is available, run the same checks by reading the artifact (graceful degradation preserved).
|
|
456
456
|
|
|
457
457
|
---
|
|
458
458
|
|
|
@@ -9,7 +9,7 @@ If the feature has ambiguous gray areas (multiple valid approaches for user-faci
|
|
|
9
9
|
- First user request and any supplied requirement source.
|
|
10
10
|
- Current repository source and docs needed to understand scope.
|
|
11
11
|
- Existing `.specs/features/<slug>/` artifacts when resuming.
|
|
12
|
-
- `.specs/
|
|
12
|
+
- `.specs/lessons.json` (via `lessons list`) only when lessons are enabled by existing lesson artifacts.
|
|
13
13
|
|
|
14
14
|
## Required Sections
|
|
15
15
|
|
|
@@ -65,7 +65,7 @@ The table is canonical; the prose is the applied sweep. **Large/Complex** work m
|
|
|
65
65
|
|
|
66
66
|
### 1. Clarify Requirements
|
|
67
67
|
|
|
68
|
-
**Load confirmed lessons first:** Before clarifying, load the project's confirmed lessons so past verification failures shape this spec instead of repeating. Run `
|
|
68
|
+
**Load confirmed lessons first:** Before clarifying, load the project's confirmed lessons so past verification failures shape this spec instead of repeating. Run `bun skills/massa-ai/scripts/lessons.ts --root . list --status confirmed` (optionally `--scope [area]` or `--query [term]` for the area this feature touches) and apply what comes back as guidance. Load only `confirmed` — never `candidate` or `quarantined`. If no store exists yet or no code tool is available, skip silently. See [lessons.md](../lessons.md).
|
|
69
69
|
|
|
70
70
|
**Lightweight context scan first (Knowledge Verification Chain Step 1):** Before asking questions, briefly scan existing code, patterns, and neighboring features relevant to this feature. Prefer massa-ai tooling first (`list_projects`, `search`, `project_map`, `optimized_context`) before `ast-grep`/`rg`/`grep`, honoring freshness and source-precedence (current source overrides stale index/memory). Use what you find to ground your clarifying questions in reality — not to constrain the spec to current implementation. Keep it lightweight (stay within the <40k token budget; reuse the chain, no new machinery). The spec captures WHAT is needed, not only what exists.
|
|
71
71
|
|
|
@@ -115,7 +115,7 @@ Write every acceptance criterion in **EARS** (Easy Approach to Requirements Synt
|
|
|
115
115
|
|
|
116
116
|
**Why patterns beat one shape:** failure states, state transitions, and optional behavior become first-class criteria instead of footnotes squeezed into WHEN/THEN. The patterns map onto the implicit-requirement dimensions above: state-transition integrity to State-driven; failure and external-dependency failure to Unwanted-behavior; feature flags to Optional-feature.
|
|
117
117
|
|
|
118
|
-
**Rules:** one requirement per criterion (never bundle two behaviors); use concrete values (a specific status code, a specific message, a bound) rather than "quickly" or "gracefully"; every criterion contains a SHALL and is measurable. `
|
|
118
|
+
**Rules:** one requirement per criterion (never bundle two behaviors); use concrete values (a specific status code, a specific message, a bound) rather than "quickly" or "gracefully"; every criterion contains a SHALL and is measurable. `bun skills/massa-ai/scripts/validate_spec.ts` flags any criterion without a SHALL and any that matches no recognized pattern.
|
|
119
119
|
|
|
120
120
|
### 4. Requirement Closure Gate (before confirm)
|
|
121
121
|
|
|
@@ -135,7 +135,7 @@ Before Design, Tasks, or Execute — and before presenting the spec for confirma
|
|
|
135
135
|
|
|
136
136
|
6. **Continue only when** the Open Questions table is empty or every row has an accepted assumption.
|
|
137
137
|
|
|
138
|
-
7. **Deterministic backing (run it, do not eyeball it):** `
|
|
138
|
+
7. **Deterministic backing (run it, do not eyeball it):** `bun skills/massa-ai/scripts/validate_spec.ts <feature> [--root .]` checks that required sections exist, every AC is EARS-shaped (has a SHALL), no Assumptions row has an empty default or rationale, and requirement IDs are well-formed. A non-zero exit means fix before confirming — the script checks structure; the judgment calls (is the interpretation right, is the outcome precise) stay yours. If no code-execution tool is available, run the same checks by reading the artifact (graceful degradation preserved).
|
|
139
139
|
|
|
140
140
|
Fix inline. This gate is bounded to THIS feature's stated dimensions and actual behavior — never to "anything imaginable." The Out of Scope table and anti-scope-creep rules remain the counterweights: the gate clarifies existing requirements, it never invents new ones.
|
|
141
141
|
|
|
@@ -286,13 +286,13 @@ How we know the feature is successful:
|
|
|
286
286
|
- **Edge cases matter** — What breaks? What's empty? What's huge?
|
|
287
287
|
- **Out of Scope prevents creep** — If it's not here, it doesn't get built
|
|
288
288
|
- **Closure gate before confirm** — Three checks: unambiguity + precision, open-questions/assumptions closure, declined gray areas logged; scope-tiered; bounded to stated dimensions; never invents requirements
|
|
289
|
-
- **Confirm after the gate passes** — Present the spec for user confirmation only after the closure gate passes (no unresolved-and-unmarked items remain) and `validate_spec.
|
|
289
|
+
- **Confirm after the gate passes** — Present the spec for user confirmation only after the closure gate passes (no unresolved-and-unmarked items remain) and `validate_spec.ts` exits clean; user approves spec before moving to the discuss phase
|
|
290
290
|
|
|
291
291
|
---
|
|
292
292
|
|
|
293
293
|
## Done
|
|
294
294
|
|
|
295
|
-
Specify is done when every requirement has an ID, acceptance criteria are testable EARS statements, edge cases are named, out-of-scope boundaries are explicit, implicit-requirement dimensions are resolved or marked `N/A because <reason>`, the Requirement Closure Gate is satisfied, and `validate_spec.
|
|
295
|
+
Specify is done when every requirement has an ID, acceptance criteria are testable EARS statements, edge cases are named, out-of-scope boundaries are explicit, implicit-requirement dimensions are resolved or marked `N/A because <reason>`, the Requirement Closure Gate is satisfied, and `validate_spec.ts` exits clean (or the no-code-execution-tool fallback was applied).
|
|
296
296
|
|
|
297
297
|
## Massa-ai Integration
|
|
298
298
|
|
|
@@ -148,7 +148,7 @@ Delegated work returns through the compact summary contract above. Planning, tas
|
|
|
148
148
|
|
|
149
149
|
## Standalone Fallback
|
|
150
150
|
|
|
151
|
-
When sub-agents are unavailable (a single agent executing the full feature), use the standalone fresh-eyes fallback: run `references/spec-driven/validate.md` as a standalone pass — clear implementation assumptions, re-read `spec.md` and the diff from scratch, apply evidence-or-zero, run the spec-anchored coverage check and discrimination sensor, and write `.specs/features/<slug>/validation.md`. **Deterministic backing (run it, do not eyeball it):** `
|
|
151
|
+
When sub-agents are unavailable (a single agent executing the full feature), use the standalone fresh-eyes fallback: run `references/spec-driven/validate.md` as a standalone pass — clear implementation assumptions, re-read `spec.md` and the diff from scratch, apply evidence-or-zero, run the spec-anchored coverage check and discrimination sensor, and write `.specs/features/<slug>/validation.md`. **Deterministic backing (run it, do not eyeball it):** `bun skills/massa-ai/scripts/validate_state.ts <feature> [--root .]` confirms the report is a real PASS before the feature is marked done. If no code-execution tool is available, run the same checks by reading the artifact (graceful degradation preserved).
|
|
152
152
|
|
|
153
153
|
---
|
|
154
154
|
|
|
@@ -157,7 +157,7 @@ This keeps phase boundaries meaningful while letting the packing hit its target
|
|
|
157
157
|
|
|
158
158
|
Before showing tasks to the user, run ALL three pre-approval checks. These are NOT optional — they are gates. If any check fails, restructure the tasks and re-run until all pass.
|
|
159
159
|
|
|
160
|
-
**Deterministic backing (run it, do not eyeball it):** `
|
|
160
|
+
**Deterministic backing (run it, do not eyeball it):** `bun skills/massa-ai/scripts/validate_tasks.ts <feature> [--root .]` enforces the structural half of these checks so they cannot drift: it flags a `Where` that names multiple files (granularity smell, Check 1), a diagram edge with no matching `Depends on` within a phase and vice-versa (Check 2), a task missing its `Tests` or `Gate` field, a `Tests: none` to confirm against the matrix (Check 3), and any dependency pointing to a later phase. A non-zero exit means restructure before presenting. The script checks structure; the two tables below (the layer-to-test co-location judgment) are still yours. If no code-execution tool is available, run the same checks by reading the artifact (graceful degradation preserved).
|
|
161
161
|
|
|
162
162
|
**Check 1: Task Granularity** — verify each task is atomic (see Granularity Check section).
|
|
163
163
|
|
|
@@ -516,4 +516,4 @@ Before sampling tests manually, prefer massa-ai tooling to read the codebase:
|
|
|
516
516
|
|
|
517
517
|
## Done
|
|
518
518
|
|
|
519
|
-
Tasks is done when every in-scope requirement maps to one or more executable tasks, dependencies are explicit, the Test Coverage Matrix and Gate Check Commands are present, project testing guideline scan and pre-approval checks are recorded, the three mandatory pre-approval tables (Granularity, Diagram-Definition Cross-Check, Test Co-location Validation) pass, `validate_tasks.
|
|
519
|
+
Tasks is done when every in-scope requirement maps to one or more executable tasks, dependencies are explicit, the Test Coverage Matrix and Gate Check Commands are present, project testing guideline scan and pre-approval checks are recorded, the three mandatory pre-approval tables (Granularity, Diagram-Definition Cross-Check, Test Co-location Validation) pass, `validate_tasks.ts` exits clean (or the no-code-execution-tool fallback was applied), and each task has deterministic validation with artifact-store evidence recorded.
|
|
@@ -204,14 +204,14 @@ After all checks complete, the Verifier MUST:
|
|
|
204
204
|
1. **Write the persisted report** to `.specs/features/<slug>/validation.md` (see template below). This file is the evidence artifact — it survives the session and can be referenced by CI, reviewers, or future agents. Record in `.specs/project/STATE.md` (Decisions) that validation evidence is available at that path.
|
|
205
205
|
2. **Return a compact summary in chat** to the orchestrator (see Compact Chat Summary section below). The orchestrator surfaces it to the user and routes any ranked gaps to fix tasks.
|
|
206
206
|
|
|
207
|
-
**Deterministic backing (run it, do not eyeball it):** after writing the report, run `
|
|
207
|
+
**Deterministic backing (run it, do not eyeball it):** after writing the report, run `bun skills/massa-ai/scripts/validate_state.ts <feature> [--root .]`. It confirms the report is real — present, verdict filled to PASS, and backed by at least one `file:line` evidence citation — so a missing, hollow, placeholder, or FAIL report cannot slip through as done. A non-zero exit means the feature is NOT done: repair the report or route the FAIL gaps to fix tasks, then re-run. This is the closing gate of Execute and runs automatically, the same way the lessons layer runs at distillation — never a manual step. If no code-execution tool is available, run the same checks by reading the artifact (graceful degradation preserved).
|
|
208
208
|
|
|
209
209
|
### 10. Distill Lessons (MANDATORY when validation.md has signal)
|
|
210
210
|
|
|
211
211
|
This is the closing action of validation — not a separate phase. Immediately after the report is written, turn its grounded failures into reusable, project-local guidance by following [references/lessons.md](../lessons.md) and the stub at [references/spec-driven/lessons.md](lessons.md). In short: for each surviving mutant, spec-precision gap, failed/uncovered AC, or `// SPEC_DEVIATION`, record one terse general lesson via:
|
|
212
212
|
|
|
213
213
|
```bash
|
|
214
|
-
|
|
214
|
+
bun skills/massa-ai/scripts/lessons.ts --root . add --feature <slug> --signal "<signal>" --source "<source>" --text "<lesson>" --scope "<scope>"
|
|
215
215
|
```
|
|
216
216
|
|
|
217
217
|
The script enforces grounding (mandatory `--source`) and owns all bookkeeping. A clean PASS with no signal → record nothing. Run the self-check: if there was signal but no lesson was recorded, say so in chat. See [references/lessons.md](../lessons.md) for the exact commands, phrasing rules, scope discipline, and the no-script fallback.
|
|
@@ -398,5 +398,5 @@ Update `.specs/features/<slug>/spec.md` requirement statuses and reflect verifie
|
|
|
398
398
|
- **Max 3 diagnostic iterations** — Prevents infinite investigation loops
|
|
399
399
|
- **Update traceability** — Every verified requirement updates spec.md status and the FEATURES.json registry
|
|
400
400
|
- **Always write the report file** — `.specs/features/<slug>/validation.md` is the persisted evidence artifact
|
|
401
|
-
- **Distill after writing** — turn grounded failures into lessons via `
|
|
401
|
+
- **Distill after writing** — turn grounded failures into lessons via `bun skills/massa-ai/scripts/lessons.ts` ([references/lessons.md](../lessons.md)); clean PASS → no lesson
|
|
402
402
|
- **Independence first** — prefer a fresh read-only verifier; the author never verifies their own work when tooling allows
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* check_commit.ts - deterministic Conventional Commits validation.
|
|
4
|
+
*
|
|
5
|
+
* The per-task atomic-commit rule mandates Conventional Commits 1.0.0. This makes
|
|
6
|
+
* that rule checkable instead of trusting the model to remember the format. Bun
|
|
7
|
+
* builtins only, zero dependencies, agent-agnostic.
|
|
8
|
+
*
|
|
9
|
+
* It reads the message from (in priority order): a positional file path, --message,
|
|
10
|
+
* or stdin. The file-path form matches how git passes the message file to a
|
|
11
|
+
* `commit-msg` hook, so this doubles as an optional git-level guard WITHOUT
|
|
12
|
+
* coupling the skill to any AI agent:
|
|
13
|
+
*
|
|
14
|
+
* ln -s skills/massa-ai/scripts/check_commit.ts .git/hooks/commit-msg && chmod +x .git/hooks/commit-msg
|
|
15
|
+
*
|
|
16
|
+
* What it checks:
|
|
17
|
+
* ERROR - header does not match type(scope)!: description
|
|
18
|
+
* (an optional leading `[KEY] ` Jira-style prefix is stripped first -
|
|
19
|
+
* see massa-ai's `workflows/commit.md` §8, e.g. `[SA-142] feat(x): y`)
|
|
20
|
+
* ERROR - type is not one of the allowed Conventional Commits types
|
|
21
|
+
* ERROR - description is empty, starts uppercase, or ends with a period
|
|
22
|
+
* ERROR - `!` breaking marker present but no `BREAKING CHANGE:` footer
|
|
23
|
+
* WARN - header longer than 72 characters
|
|
24
|
+
*
|
|
25
|
+
* Usage:
|
|
26
|
+
* bun skills/massa-ai/scripts/check_commit.ts [msgfile]
|
|
27
|
+
* bun skills/massa-ai/scripts/check_commit.ts --message "feat(auth): add email validation"
|
|
28
|
+
* bun skills/massa-ai/scripts/check_commit.ts --message "[SA-142] feat(auth): reject expired tokens"
|
|
29
|
+
* echo "fix(cart): prevent negative quantity" | bun skills/massa-ai/scripts/check_commit.ts
|
|
30
|
+
*
|
|
31
|
+
* Exit codes: 0 pass, 1 violation, 2 usage error.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import { readFileSync } from "node:fs";
|
|
35
|
+
|
|
36
|
+
const TYPES = ["feat", "fix", "refactor", "docs", "test", "style", "perf", "build", "ci", "chore"];
|
|
37
|
+
|
|
38
|
+
// massa-ai patch (D1c): an optional leading Jira-style key prefix, e.g.
|
|
39
|
+
// "[SA-142] feat(auth): reject expired tokens" (workflows/commit.md §8). The
|
|
40
|
+
// key shape mirrors the branch-key regex there: [A-Z][A-Z0-9]{1,9}-\d+.
|
|
41
|
+
const PREFIX_RE = /^\[(?<key>[A-Z][A-Z0-9]{1,9}-\d+)\]\s+(?<rest>.+)$/;
|
|
42
|
+
const HEADER_RE = /^(?<type>\w+)(?:\((?<scope>[^)]+)\))?(?<bang>!)?: (?<desc>.+)$/;
|
|
43
|
+
|
|
44
|
+
const USAGE = "usage: check_commit.ts [-h] [--message MESSAGE] [msgfile]";
|
|
45
|
+
const HELP = `${USAGE}
|
|
46
|
+
|
|
47
|
+
Validate a Conventional Commits message.
|
|
48
|
+
|
|
49
|
+
positional arguments:
|
|
50
|
+
msgfile path to a commit message file (as git passes to commit-msg)
|
|
51
|
+
|
|
52
|
+
options:
|
|
53
|
+
-h, --help show this help message and exit
|
|
54
|
+
--message MESSAGE the commit message as a string`;
|
|
55
|
+
|
|
56
|
+
interface Args {
|
|
57
|
+
msgfile: string | null;
|
|
58
|
+
message: string | null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Mirrors Python's str.splitlines(): universal newline split, no trailing empty element. */
|
|
62
|
+
function splitLines(text: string): string[] {
|
|
63
|
+
if (text === "") return [];
|
|
64
|
+
const result: string[] = [];
|
|
65
|
+
const lineBreakRe = /\r\n|\r|\n/g;
|
|
66
|
+
let start = 0;
|
|
67
|
+
let match: RegExpExecArray | null;
|
|
68
|
+
while ((match = lineBreakRe.exec(text)) !== null) {
|
|
69
|
+
result.push(text.slice(start, match.index));
|
|
70
|
+
start = match.index + match[0].length;
|
|
71
|
+
}
|
|
72
|
+
if (start < text.length) {
|
|
73
|
+
result.push(text.slice(start));
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Mirrors Python's repr() for plain-text strings (single-quoted, backslash/quote/control escapes). */
|
|
79
|
+
function pyRepr(s: string): string {
|
|
80
|
+
const hasSingle = s.includes("'");
|
|
81
|
+
const hasDouble = s.includes('"');
|
|
82
|
+
const quote = hasSingle && !hasDouble ? '"' : "'";
|
|
83
|
+
let out = quote;
|
|
84
|
+
for (const ch of s) {
|
|
85
|
+
if (ch === "\\") out += "\\\\";
|
|
86
|
+
else if (ch === quote) out += "\\" + quote;
|
|
87
|
+
else if (ch === "\n") out += "\\n";
|
|
88
|
+
else if (ch === "\r") out += "\\r";
|
|
89
|
+
else if (ch === "\t") out += "\\t";
|
|
90
|
+
else {
|
|
91
|
+
const code = ch.codePointAt(0)!;
|
|
92
|
+
if (code < 0x20 || code === 0x7f) {
|
|
93
|
+
out += "\\x" + code.toString(16).padStart(2, "0");
|
|
94
|
+
} else {
|
|
95
|
+
out += ch;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
out += quote;
|
|
100
|
+
return out;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function printUsageError(msg: string): void {
|
|
104
|
+
process.stderr.write(`${USAGE}\ncheck_commit.ts: error: ${msg}\n`);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function parseArgs(argv: string[]): Args | null {
|
|
108
|
+
let message: string | null = null;
|
|
109
|
+
const positionals: string[] = [];
|
|
110
|
+
for (let i = 0; i < argv.length; i++) {
|
|
111
|
+
const a = argv[i];
|
|
112
|
+
if (a === "--message") {
|
|
113
|
+
if (i + 1 >= argv.length) {
|
|
114
|
+
printUsageError("argument --message: expected one argument");
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
message = argv[++i];
|
|
118
|
+
} else if (a.startsWith("--message=")) {
|
|
119
|
+
message = a.slice("--message=".length);
|
|
120
|
+
} else if (a === "-h" || a === "--help") {
|
|
121
|
+
console.log(HELP);
|
|
122
|
+
process.exit(0);
|
|
123
|
+
} else if (a.startsWith("-") && a !== "-") {
|
|
124
|
+
printUsageError(`unrecognized arguments: ${a}`);
|
|
125
|
+
return null;
|
|
126
|
+
} else {
|
|
127
|
+
positionals.push(a);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (positionals.length > 1) {
|
|
131
|
+
printUsageError(`unrecognized arguments: ${positionals.slice(1).join(" ")}`);
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
return { msgfile: positionals[0] ?? null, message };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function readMessage(args: Args): string {
|
|
138
|
+
if (args.message !== null) return args.message;
|
|
139
|
+
if (args.msgfile) {
|
|
140
|
+
return readFileSync(args.msgfile, "utf-8");
|
|
141
|
+
}
|
|
142
|
+
if (!process.stdin.isTTY) {
|
|
143
|
+
try {
|
|
144
|
+
return readFileSync(0, "utf-8");
|
|
145
|
+
} catch {
|
|
146
|
+
return "";
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return "";
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function check(message: string): { errors: string[]; warnings: string[] } {
|
|
153
|
+
const errors: string[] = [];
|
|
154
|
+
const warnings: string[] = [];
|
|
155
|
+
// Ignore comment lines (git puts '#' comments in the message file).
|
|
156
|
+
let lines = splitLines(message).filter((ln) => !ln.trimStart().startsWith("#"));
|
|
157
|
+
// Trim leading blank lines.
|
|
158
|
+
while (lines.length && !lines[0]!.trim()) {
|
|
159
|
+
lines.shift();
|
|
160
|
+
}
|
|
161
|
+
if (!lines.length) {
|
|
162
|
+
return { errors: ["empty commit message"], warnings };
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const header = lines[0]!.replace(/\s+$/, "");
|
|
166
|
+
if (header.length > 72) {
|
|
167
|
+
warnings.push(`header is ${header.length} chars (>72): ${header.slice(0, 60)}...`);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Strip an optional massa-ai Jira-style `[KEY] ` prefix before matching the
|
|
171
|
+
// Conventional Commits header shape.
|
|
172
|
+
const prefixed = PREFIX_RE.exec(header);
|
|
173
|
+
const headerBody = prefixed?.groups?.rest ?? header;
|
|
174
|
+
|
|
175
|
+
const m = HEADER_RE.exec(headerBody);
|
|
176
|
+
if (!m || !m.groups) {
|
|
177
|
+
errors.push(`header does not match 'type(scope): description': ${pyRepr(header)}`);
|
|
178
|
+
return { errors, warnings };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const ctype = m.groups.type!;
|
|
182
|
+
const desc = m.groups.desc!;
|
|
183
|
+
const bang = m.groups.bang;
|
|
184
|
+
|
|
185
|
+
if (!TYPES.includes(ctype)) {
|
|
186
|
+
errors.push(`type '${ctype}' is not one of: ${TYPES.join(", ")}`);
|
|
187
|
+
}
|
|
188
|
+
if (!desc.trim()) {
|
|
189
|
+
errors.push("description is empty");
|
|
190
|
+
} else {
|
|
191
|
+
if (/\p{Lu}/u.test(desc[0]!)) {
|
|
192
|
+
errors.push(`description should start lowercase: '${desc.slice(0, 30)}'`);
|
|
193
|
+
}
|
|
194
|
+
if (desc.replace(/\s+$/, "").endsWith(".")) {
|
|
195
|
+
errors.push("description should not end with a period");
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const body = lines.slice(1).join("\n");
|
|
200
|
+
const breakingFooter = /^BREAKING CHANGE:/m.test(body);
|
|
201
|
+
if (bang && !breakingFooter) {
|
|
202
|
+
errors.push("'!' breaking marker present but no 'BREAKING CHANGE:' footer");
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return { errors, warnings };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function main(argv: string[]): number {
|
|
209
|
+
const args = parseArgs(argv);
|
|
210
|
+
if (args === null) return 2;
|
|
211
|
+
|
|
212
|
+
const message = readMessage(args);
|
|
213
|
+
if (!message.trim()) {
|
|
214
|
+
console.error("check_commit: no message provided (pass a file, --message, or pipe via stdin).");
|
|
215
|
+
return 2;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const { errors, warnings } = check(message);
|
|
219
|
+
for (const w of warnings) console.log(` WARN ${w}`);
|
|
220
|
+
for (const e of errors) console.log(` ERROR ${e}`);
|
|
221
|
+
if (errors.length) {
|
|
222
|
+
console.log("\ncheck_commit: FAIL - see https://www.conventionalcommits.org/en/v1.0.0/");
|
|
223
|
+
return 1;
|
|
224
|
+
}
|
|
225
|
+
console.log("check_commit: OK");
|
|
226
|
+
return 0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (import.meta.main) {
|
|
230
|
+
process.exit(main(process.argv.slice(2)));
|
|
231
|
+
}
|