@trieungoctam/speckit 0.3.0 → 0.3.3
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 +12 -1
- package/dist/adapters/antigravity-adapter.js +5 -5
- package/dist/adapters/claude-code-adapter.js +30 -17
- package/dist/adapters/codex-adapter.js +5 -3
- package/dist/adapters/cursor-adapter.js +33 -12
- package/dist/adapters/opencode-adapter.js +13 -16
- package/dist/cli.js +13 -0
- package/dist/commands/context.js +3 -7
- package/dist/commands/doctor.js +10 -3
- package/dist/commands/permissions.d.ts +8 -0
- package/dist/commands/permissions.js +18 -0
- package/dist/commands/plan.js +5 -13
- package/dist/commands/quick.js +5 -13
- package/dist/commands/validate.d.ts +6 -0
- package/dist/commands/validate.js +17 -0
- package/dist/core/agent-scaffold.js +22 -1
- package/dist/core/managed-files.d.ts +5 -0
- package/dist/core/managed-files.js +33 -1
- package/dist/core/permission-auditor.d.ts +10 -0
- package/dist/core/permission-auditor.js +65 -0
- package/dist/core/permission-policy.d.ts +6 -0
- package/dist/core/permission-policy.js +93 -0
- package/dist/core/policy.d.ts +5 -5
- package/dist/core/policy.js +53 -1
- package/dist/core/scaffold.js +67 -1
- package/dist/core/skill-catalog.d.ts +1 -0
- package/dist/core/skill-catalog.js +76 -3
- package/dist/core/templates.d.ts +2 -2
- package/dist/core/templates.js +49 -3
- package/dist/core/workflow-contract.d.ts +7 -0
- package/dist/core/workflow-contract.js +43 -0
- package/dist/core/workflow-validator.d.ts +6 -0
- package/dist/core/workflow-validator.js +133 -0
- package/docs/development-roadmap.md +5 -2
- package/docs/permission-rules-research.md +265 -0
- package/docs/product-contract.md +3 -1
- package/docs/project-changelog.md +45 -0
- package/docs/prompt-architecture.md +88 -0
- package/docs/use-cases.md +206 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -21,6 +21,8 @@ npx @trieungoctam/speckit@latest context .speckit/stories/<story>.md
|
|
|
21
21
|
npx @trieungoctam/speckit@latest sync
|
|
22
22
|
npx @trieungoctam/speckit@latest sprint plan
|
|
23
23
|
npx @trieungoctam/speckit@latest graph triage --json
|
|
24
|
+
npx @trieungoctam/speckit@latest validate --json
|
|
25
|
+
npx @trieungoctam/speckit@latest permissions audit --path .env --json
|
|
24
26
|
npx @trieungoctam/speckit@latest ready .speckit/stories/<story>.md
|
|
25
27
|
npx @trieungoctam/speckit@latest session checkpoint --note "red complete"
|
|
26
28
|
npx @trieungoctam/speckit@latest review
|
|
@@ -68,9 +70,11 @@ For implementation stories, red-green-refactor evidence is mandatory. A story is
|
|
|
68
70
|
| `speckit init --enterprise` | Add flow, tool policy, and prompt harness files on top of the shared runtime. |
|
|
69
71
|
| `speckit init --ide <name>` | Generate shared Speckit runtime plus one adapter: `claude-code`, `codex`, `antigravity`, `opencode`, or `cursor`. |
|
|
70
72
|
| `speckit doctor` | Report required tools, optional integrations, test commands, and adapter readiness. |
|
|
71
|
-
| `speckit doctor --deep` | Verify core enterprise harness files. |
|
|
73
|
+
| `speckit doctor --deep` | Verify core enterprise harness files and workflow contract checks. |
|
|
74
|
+
| `speckit validate` | Validate flow order, core skills, super-agent routing, prompts, and installed adapter contracts. |
|
|
72
75
|
| `speckit start "<idea>"` | Create a durable session handoff and current context. |
|
|
73
76
|
| `speckit memory refresh` | Create durable project memory files for long-running agent work. |
|
|
77
|
+
| `speckit permissions audit` | Check a path or command against the Speckit permission policy. |
|
|
74
78
|
| `speckit session start` | Create or resume the active session state. |
|
|
75
79
|
| `speckit session checkpoint` | Append a long-session checkpoint and artifact log entry. |
|
|
76
80
|
| `speckit session compact` | Create an anchored summary for resume or handoff. |
|
|
@@ -105,6 +109,13 @@ Speckit generates native instruction/config files for:
|
|
|
105
109
|
|
|
106
110
|
See `docs/adapters.md` for exact output paths.
|
|
107
111
|
|
|
112
|
+
## Guides
|
|
113
|
+
|
|
114
|
+
- `docs/use-cases.md` covers setup, migration, quick changes, full planning, long sessions, TDD, graph automation, review, CI, and troubleshooting.
|
|
115
|
+
- `docs/workflow-model.md` describes the quick and full workflow lanes.
|
|
116
|
+
- `docs/prompt-architecture.md` describes the prompt contract used by the super-agent, skills, workflows, run prompt, and IDE adapters.
|
|
117
|
+
- `docs/spec-quality-gates.md` describes validation gates for release readiness.
|
|
118
|
+
|
|
108
119
|
## Validation
|
|
109
120
|
|
|
110
121
|
```bash
|
|
@@ -12,12 +12,12 @@ export const antigravityAdapter = {
|
|
|
12
12
|
],
|
|
13
13
|
render() {
|
|
14
14
|
return [
|
|
15
|
-
rule("agile", "Follow Speckit Agile: shape intent, read .speckit/agents/super-agent.md, .speckit/skills/catalog.md, .speckit/memory/project-context.md, .speckit/sessions/active.md, and .speckit/context/
|
|
16
|
-
rule("tdd", "For code changes, use TDD: confirm acceptance criteria, use red-green-refactor, checkpoint each boundary, compact before handoff, and record evidence for each step."),
|
|
15
|
+
rule("agile", "Follow Speckit Agile: shape intent, read .speckit/agents/super-agent.md, .speckit/skills/catalog.md, .speckit/memory/project-context.md, .speckit/sessions/active.md, .speckit/context/current.md, and .speckit/context/subagent-handoff.md, create stories with ACs, preserve session handoff, and emit artifacts for review."),
|
|
16
|
+
rule("tdd", "For code changes, use TDD: require speckit ready <story>, confirm acceptance criteria, use red-green-refactor, checkpoint each boundary, compact before handoff, and record evidence for each step."),
|
|
17
17
|
rule("enterprise-safety", "Require human approval for destructive commands, production changes, secrets access, and deployment."),
|
|
18
|
-
workflow("plan", "Create a Speckit plan artifact with PRD, architecture, stories, risks, dependencies, and graph sync notes."),
|
|
19
|
-
workflow("tdd-run", "Run a story with TDD from the Speckit super agent router, skill catalog, .speckit/memory/project-context.md, .speckit/context/current.md, .speckit/context/subagent-handoff.md, and active session summary. Require speckit ready <story> first. Emit artifact sections: Test Intent, Red, Green, Refactor. Use only robot-safe graph commands."),
|
|
20
|
-
workflow("review", "Review the produced artifacts and code diff. Flag AC gaps, TDD gaps, security issues, docs needs, session checkpoint freshness, and session handoff gaps."),
|
|
18
|
+
workflow("plan", "Create a Speckit plan artifact with PRD, architecture, stories, risks, rollback, test strategy, dependencies, and graph sync notes."),
|
|
19
|
+
workflow("tdd-run", "Run a story with TDD from the Speckit super agent router, skill catalog, .speckit/prompts/spec-run.md, .speckit/memory/project-context.md, .speckit/context/current.md, .speckit/context/subagent-handoff.md, and active session summary. Require speckit ready <story> first. Emit artifact sections: Test Intent, Red, Green, Refactor, Review Evidence. Update Dev Agent Record, File List, and Change Log. Use only robot-safe graph commands."),
|
|
20
|
+
workflow("review", "Review the produced artifacts and code diff. Run spec compliance, edge-case pathing, and production readiness. Flag AC gaps, TDD gaps, security issues, docs needs, session checkpoint freshness, and session handoff gaps."),
|
|
21
21
|
];
|
|
22
22
|
},
|
|
23
23
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
const skillIntro = `Follow Speckit: Agile story flow plus mandatory TDD evidence. Read .speckit/memory/project-context.md, .speckit/context/current.md, and
|
|
1
|
+
import { markdown, markdownWithFrontmatter, strictJsonManaged, } from "../core/managed-files.js";
|
|
2
|
+
const skillIntro = `Follow Speckit: Agile story flow plus mandatory TDD evidence. Read .speckit/agents/super-agent.md, .speckit/skills/catalog.md, .speckit/memory/project-context.md, .speckit/sessions/active.md, .speckit/context/current.md, and .speckit/context/subagent-handoff.md before story work. Preserve session handoff, checkpoint long work, use red-green-refactor, and use robot-safe graph commands only.`;
|
|
3
3
|
export const claudeCodeAdapter = {
|
|
4
4
|
name: "claude-code",
|
|
5
5
|
displayName: "Claude Code",
|
|
@@ -11,6 +11,28 @@ export const claudeCodeAdapter = {
|
|
|
11
11
|
".claude/skills/speckit-review/SKILL.md",
|
|
12
12
|
],
|
|
13
13
|
render() {
|
|
14
|
+
const settings = {
|
|
15
|
+
permissions: {
|
|
16
|
+
defaultMode: "ask",
|
|
17
|
+
deny: [
|
|
18
|
+
"Read(.env*)",
|
|
19
|
+
"Read(**/*.pem)",
|
|
20
|
+
"Read(**/*.key)",
|
|
21
|
+
"Read(**/id_rsa)",
|
|
22
|
+
"Read(**/id_ed25519)",
|
|
23
|
+
"Write(.env*)",
|
|
24
|
+
"Write(**/*.pem)",
|
|
25
|
+
"Write(**/*.key)",
|
|
26
|
+
"Bash(rm -rf*)",
|
|
27
|
+
"Bash(git reset --hard*)",
|
|
28
|
+
"Bash(git clean -fd*)",
|
|
29
|
+
"Bash(git push --force*)",
|
|
30
|
+
"Bash(sudo *)",
|
|
31
|
+
],
|
|
32
|
+
ask: ["Bash(git push*)", "Bash(npm publish*)", "Bash(* deploy*)"],
|
|
33
|
+
},
|
|
34
|
+
includeCoAuthoredBy: false,
|
|
35
|
+
};
|
|
14
36
|
return [
|
|
15
37
|
{
|
|
16
38
|
path: "CLAUDE.md",
|
|
@@ -31,28 +53,19 @@ Use Speckit for Agile + TDD work.
|
|
|
31
53
|
},
|
|
32
54
|
{
|
|
33
55
|
path: ".claude/settings.json",
|
|
34
|
-
|
|
35
|
-
permissions: {
|
|
36
|
-
defaultMode: "ask",
|
|
37
|
-
},
|
|
38
|
-
includeCoAuthoredBy: false,
|
|
39
|
-
}),
|
|
56
|
+
...strictJsonManaged(settings),
|
|
40
57
|
},
|
|
41
|
-
skill("speckit-plan", "Create or update a Speckit Agile plan.", "Read `.speckit/
|
|
42
|
-
skill("speckit-tdd", "Execute a Speckit story with TDD.", "Read `.speckit/
|
|
43
|
-
skill("speckit-review", "Review a Speckit change.", "Read `.speckit/workflows/review.md` and the active session artifact log.
|
|
58
|
+
skill("speckit-plan", "Create or update a Speckit Agile plan.", "Read `.speckit/workflows/shape.md`, preserve the session id, then create PRD, architecture, story, risk, rollback, and test strategy artifacts with acceptance criteria. Do not cross into implementation."),
|
|
59
|
+
skill("speckit-tdd", "Execute a Speckit story with TDD.", "Read `.speckit/workflows/tdd-run.md` and `.speckit/prompts/spec-run.md`. Do not implement before `speckit ready <story>` passes, test intent is clear, and red evidence is recorded. Checkpoint after red, green, and refactor. Update story Dev Agent Record, File List, Change Log, and evidence."),
|
|
60
|
+
skill("speckit-review", "Review a Speckit change.", "Read `.speckit/workflows/review.md` and the active session artifact log. Review spec compliance, edge-case paths, production readiness, AC coverage, TDD evidence gaps, security, docs impact, session checkpoint freshness, and graph sync status."),
|
|
44
61
|
];
|
|
45
62
|
},
|
|
46
63
|
};
|
|
47
64
|
function skill(name, description, body) {
|
|
48
65
|
return {
|
|
49
66
|
path: `.claude/skills/${name}/SKILL.md`,
|
|
50
|
-
content:
|
|
51
|
-
|
|
52
|
-
description: "${description}"
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
# ${name}
|
|
67
|
+
content: markdownWithFrontmatter(`name: ${name}
|
|
68
|
+
description: "${description}"`, `# ${name}
|
|
56
69
|
|
|
57
70
|
${skillIntro}
|
|
58
71
|
|
|
@@ -34,6 +34,8 @@ Rules:
|
|
|
34
34
|
content: text(`model = "gpt-5.4"
|
|
35
35
|
approval_policy = "on-request"
|
|
36
36
|
sandbox_mode = "workspace-write"
|
|
37
|
+
allowed_approval_policies = ["untrusted", "on-request"]
|
|
38
|
+
allowed_sandbox_modes = ["read-only", "workspace-write"]
|
|
37
39
|
|
|
38
40
|
[tools]
|
|
39
41
|
web_search = true
|
|
@@ -41,9 +43,9 @@ web_search = true
|
|
|
41
43
|
[features]
|
|
42
44
|
child_agents_md = true`),
|
|
43
45
|
},
|
|
44
|
-
prompt("plan", "Create a Speckit plan from the user intent. Use the Speckit super agent router and skill catalog. Preserve session context, project memory, PRD, architecture, stories, ACs, TDD checklist, risks, and graph sync notes."),
|
|
45
|
-
prompt("tdd-run", "Execute the selected Speckit story using .speckit/memory/project-context.md, .speckit/context/current.md, .speckit/context/subagent-handoff.md, active session summary, and red-green-refactor. Require speckit ready <story>, confirm ACs, checkpoint each boundary, record command evidence, and use only robot-safe graph commands."),
|
|
46
|
-
prompt("review", "Review the current diff against Speckit ACs, TDD evidence, security, docs impact, session handoff, session checkpoint freshness, and graph sync status."),
|
|
46
|
+
prompt("plan", "Create a Speckit plan from the user intent. Use the Speckit super agent router and skill catalog. Preserve active session context, project memory, PRD, architecture, stories, ACs, TDD checklist, risks, rollback, test strategy, and graph sync notes. Stop before implementation."),
|
|
47
|
+
prompt("tdd-run", "Execute the selected Speckit story using .speckit/prompts/spec-run.md, .speckit/memory/project-context.md, .speckit/sessions/active.md, .speckit/context/current.md, .speckit/context/subagent-handoff.md, active session summary, and red-green-refactor. Require speckit ready <story>, confirm ACs, checkpoint each boundary, update story Dev Agent Record/File List/Change Log, record command evidence, and use only robot-safe graph commands."),
|
|
48
|
+
prompt("review", "Review the current diff against Speckit ACs, TDD evidence, security, docs impact, session handoff, session checkpoint freshness, and graph sync status. Run spec compliance first, edge-case pathing second, and production readiness third."),
|
|
47
49
|
];
|
|
48
50
|
},
|
|
49
51
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { markdown, markdownWithFrontmatter, strictJsonManaged, } from "../core/managed-files.js";
|
|
2
2
|
export const cursorAdapter = {
|
|
3
3
|
name: "cursor",
|
|
4
4
|
displayName: "Cursor",
|
|
@@ -8,19 +8,44 @@ export const cursorAdapter = {
|
|
|
8
8
|
".cursor/rules/speckit-review.mdc",
|
|
9
9
|
".cursor/rules/speckit-enterprise-safety.mdc",
|
|
10
10
|
".cursor/mcp.json",
|
|
11
|
+
".cursor/cli.json",
|
|
11
12
|
"AGENTS.md",
|
|
12
13
|
],
|
|
13
14
|
render() {
|
|
15
|
+
const mcpConfig = {
|
|
16
|
+
mcpServers: {},
|
|
17
|
+
};
|
|
18
|
+
const cliConfig = {
|
|
19
|
+
permissions: {
|
|
20
|
+
allow: ["Shell(git)", "Shell(npm)", "Shell(node)", "Read(.speckit/**)", "Read(src/**)", "Read(tests/**)"],
|
|
21
|
+
deny: [
|
|
22
|
+
"Read(.env*)",
|
|
23
|
+
"Read(**/*.pem)",
|
|
24
|
+
"Read(**/*.key)",
|
|
25
|
+
"Read(**/id_rsa)",
|
|
26
|
+
"Read(**/id_ed25519)",
|
|
27
|
+
"Write(.env*)",
|
|
28
|
+
"Write(**/*.pem)",
|
|
29
|
+
"Write(**/*.key)",
|
|
30
|
+
"Shell(rm)",
|
|
31
|
+
"Shell(sudo)",
|
|
32
|
+
"Shell(chmod)",
|
|
33
|
+
"Shell(chown)",
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
};
|
|
14
37
|
return [
|
|
15
|
-
rule("agile", "alwaysApply: true", "Use Speckit Agile flow. Read .speckit/agents/super-agent.md, .speckit/skills/catalog.md, .speckit/memory/project-context.md, .speckit/sessions/active.md, .speckit/context/current.md, and .speckit/context/subagent-handoff.md. Preserve session handoff, create stories with ACs, and keep work scoped."),
|
|
16
|
-
rule("tdd", "description: Apply when implementing or modifying code", "Use red-green-refactor. Run speckit ready <story>, confirm acceptance criteria, checkpoint each TDD boundary, and record TDD evidence before review-ready."),
|
|
17
|
-
rule("review", "description: Apply when reviewing code or preparing a PR", "Review AC coverage, TDD evidence, security, docs impact, session checkpoint freshness, and graph sync status."),
|
|
38
|
+
rule("agile", "alwaysApply: true", "Use Speckit Agile flow. Read .speckit/agents/super-agent.md, .speckit/skills/catalog.md, .speckit/memory/project-context.md, .speckit/sessions/active.md, .speckit/context/current.md, and .speckit/context/subagent-handoff.md. Preserve session handoff, create stories with ACs, and keep work scoped to the current artifact phase."),
|
|
39
|
+
rule("tdd", "description: Apply when implementing or modifying code", "Use red-green-refactor. Run speckit ready <story>, confirm acceptance criteria, checkpoint each TDD boundary, update story Dev Agent Record/File List/Change Log, and record TDD evidence before review-ready."),
|
|
40
|
+
rule("review", "description: Apply when reviewing code or preparing a PR", "Review spec compliance first, edge-case pathing second, and production readiness third. Check AC coverage, TDD evidence, security, docs impact, session checkpoint freshness, and graph sync status."),
|
|
18
41
|
rule("enterprise-safety", "alwaysApply: true", "Do not expose secrets. Ask before destructive commands, deployment, or production changes."),
|
|
19
42
|
{
|
|
20
43
|
path: ".cursor/mcp.json",
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
44
|
+
...strictJsonManaged(mcpConfig),
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
path: ".cursor/cli.json",
|
|
48
|
+
...strictJsonManaged(cliConfig),
|
|
24
49
|
},
|
|
25
50
|
{
|
|
26
51
|
path: "AGENTS.md",
|
|
@@ -46,11 +71,7 @@ Use Speckit for Agile + TDD work. Cursor-specific rules live in \`.cursor/rules/
|
|
|
46
71
|
function rule(name, frontmatter, body) {
|
|
47
72
|
return {
|
|
48
73
|
path: `.cursor/rules/speckit-${name}.mdc`,
|
|
49
|
-
content:
|
|
50
|
-
${frontmatter}
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
# Speckit ${name}
|
|
74
|
+
content: markdownWithFrontmatter(frontmatter, `# Speckit ${name}
|
|
54
75
|
|
|
55
76
|
${body}
|
|
56
77
|
`),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { markdownWithFrontmatter, strictJsonManaged } from "../core/managed-files.js";
|
|
2
2
|
export const opencodeAdapter = {
|
|
3
3
|
name: "opencode",
|
|
4
4
|
displayName: "OpenCode",
|
|
@@ -10,17 +10,18 @@ export const opencodeAdapter = {
|
|
|
10
10
|
".opencode/agent/speckit-docs.md",
|
|
11
11
|
],
|
|
12
12
|
render() {
|
|
13
|
+
const config = {
|
|
14
|
+
$schema: "https://opencode.ai/config.json",
|
|
15
|
+
instructions: ["AGENTS.md", ".speckit/rules/*.md"],
|
|
16
|
+
permission: {
|
|
17
|
+
edit: "ask",
|
|
18
|
+
bash: "ask",
|
|
19
|
+
},
|
|
20
|
+
};
|
|
13
21
|
return [
|
|
14
22
|
{
|
|
15
23
|
path: "opencode.json",
|
|
16
|
-
|
|
17
|
-
$schema: "https://opencode.ai/config.json",
|
|
18
|
-
instructions: ["AGENTS.md", ".speckit/rules/*.md"],
|
|
19
|
-
permission: {
|
|
20
|
-
edit: "ask",
|
|
21
|
-
bash: "ask",
|
|
22
|
-
},
|
|
23
|
-
}),
|
|
24
|
+
...strictJsonManaged(config),
|
|
24
25
|
},
|
|
25
26
|
agent("planner", "Plan Speckit Agile work without editing files.", "primary", {
|
|
26
27
|
edit: "deny",
|
|
@@ -44,16 +45,12 @@ export const opencodeAdapter = {
|
|
|
44
45
|
function agent(name, description, mode, permission) {
|
|
45
46
|
return {
|
|
46
47
|
path: `.opencode/agent/speckit-${name}.md`,
|
|
47
|
-
content:
|
|
48
|
-
description: "${description}"
|
|
48
|
+
content: markdownWithFrontmatter(`description: "${description}"
|
|
49
49
|
mode: ${mode}
|
|
50
|
-
permission: ${JSON.stringify(permission)}
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
# speckit-${name}
|
|
50
|
+
permission: ${JSON.stringify(permission)}`, `# speckit-${name}
|
|
54
51
|
|
|
55
52
|
Follow \`.speckit/rules/agile-policy.md\`, \`.speckit/rules/tdd-policy.md\`, and \`.speckit/rules/enterprise-safety.md\`.
|
|
56
|
-
Read \`.speckit/agents/super-agent.md\`, \`.speckit/skills/catalog.md\`, \`.speckit/memory/project-context.md\`, \`.speckit/sessions/active.md\`, \`.speckit/context/current.md\`, and \`.speckit/context/subagent-handoff.md\` before implementation work. Select the smallest matching Speckit skill. Require \`speckit ready <story>\`, confirm acceptance criteria, preserve session handoff, checkpoint red-green-refactor boundaries, compact before handoff, and use only robot-safe graph commands.
|
|
53
|
+
Read \`.speckit/agents/super-agent.md\`, \`.speckit/skills/catalog.md\`, \`.speckit/prompts/spec-run.md\`, \`.speckit/memory/project-context.md\`, \`.speckit/sessions/active.md\`, \`.speckit/context/current.md\`, and \`.speckit/context/subagent-handoff.md\` before implementation work. Select the smallest matching Speckit skill. Require \`speckit ready <story>\`, confirm acceptance criteria, preserve session handoff, checkpoint red-green-refactor boundaries, update story Dev Agent Record/File List/Change Log, compact before handoff, and use only robot-safe graph commands. Reviews run spec compliance, edge-case pathing, and production readiness before approval.
|
|
57
54
|
`),
|
|
58
55
|
};
|
|
59
56
|
}
|
package/dist/cli.js
CHANGED
|
@@ -6,9 +6,11 @@ import { contextCommand } from "./commands/context.js";
|
|
|
6
6
|
import { quickCommand } from "./commands/quick.js";
|
|
7
7
|
import { planCommand } from "./commands/plan.js";
|
|
8
8
|
import { memoryCommand } from "./commands/memory.js";
|
|
9
|
+
import { permissionsCommand } from "./commands/permissions.js";
|
|
9
10
|
import { sessionCommand } from "./commands/session.js";
|
|
10
11
|
import { sprintCommand } from "./commands/sprint.js";
|
|
11
12
|
import { graphCommand } from "./commands/graph.js";
|
|
13
|
+
import { validateCommand } from "./commands/validate.js";
|
|
12
14
|
import { triageCommand } from "./commands/triage.js";
|
|
13
15
|
import { nextCommand } from "./commands/next.js";
|
|
14
16
|
import { syncCommand } from "./commands/sync.js";
|
|
@@ -41,6 +43,13 @@ export async function main(argv = process.argv.slice(2), root = process.cwd()) {
|
|
|
41
43
|
return planCommand({ root, intent: requiredIntent(parsed) });
|
|
42
44
|
case "memory":
|
|
43
45
|
return memoryCommand({ root, action: requiredAction(parsed) });
|
|
46
|
+
case "permissions":
|
|
47
|
+
return permissionsCommand({
|
|
48
|
+
action: requiredAction(parsed),
|
|
49
|
+
path: value(parsed, "path"),
|
|
50
|
+
command: value(parsed, "command"),
|
|
51
|
+
json: has(parsed, "json"),
|
|
52
|
+
});
|
|
44
53
|
case "session":
|
|
45
54
|
return sessionCommand({
|
|
46
55
|
root,
|
|
@@ -53,6 +62,8 @@ export async function main(argv = process.argv.slice(2), root = process.cwd()) {
|
|
|
53
62
|
return sprintCommand({ root, action: requiredAction(parsed), json: has(parsed, "json") });
|
|
54
63
|
case "graph":
|
|
55
64
|
return graphCommand({ root, action: requiredAction(parsed), json: has(parsed, "json") });
|
|
65
|
+
case "validate":
|
|
66
|
+
return validateCommand({ root, json: has(parsed, "json") });
|
|
56
67
|
case "triage":
|
|
57
68
|
return triageCommand({ root, json: has(parsed, "json") });
|
|
58
69
|
case "next":
|
|
@@ -136,9 +147,11 @@ Usage:
|
|
|
136
147
|
speckit quick "<intent>"
|
|
137
148
|
speckit plan "<intent>"
|
|
138
149
|
speckit memory refresh
|
|
150
|
+
speckit permissions audit [--path <path>] [--command <command>] [--json]
|
|
139
151
|
speckit session start|checkpoint|compact|resume|status [target] [--note "..."] [--json]
|
|
140
152
|
speckit sprint plan|next [--json]
|
|
141
153
|
speckit graph triage|plan|insights [--json]
|
|
154
|
+
speckit validate [--json]
|
|
142
155
|
speckit triage [--json]
|
|
143
156
|
speckit next
|
|
144
157
|
speckit sync
|
package/dist/commands/context.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { markdown, writeManagedFiles } from "../core/managed-files.js";
|
|
1
|
+
import { markdown, markdownWithFrontmatter, writeManagedFiles } from "../core/managed-files.js";
|
|
2
2
|
import { extractEvidenceReference, extractSection, resolveStory } from "../core/story.js";
|
|
3
3
|
export async function contextCommand(options) {
|
|
4
4
|
const stdout = options.stdout ?? console;
|
|
@@ -14,13 +14,9 @@ export async function contextCommand(options) {
|
|
|
14
14
|
await writeManagedFiles(options.root, [
|
|
15
15
|
{
|
|
16
16
|
path: contextPath,
|
|
17
|
-
content:
|
|
18
|
-
status: fresh
|
|
17
|
+
content: markdownWithFrontmatter(`status: fresh
|
|
19
18
|
story: ${story.path}
|
|
20
|
-
evidence: ${evidenceReference ?? "missing"}
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
# Current Spec Context
|
|
19
|
+
evidence: ${evidenceReference ?? "missing"}`, `# Current Spec Context
|
|
24
20
|
|
|
25
21
|
## Story
|
|
26
22
|
${story.title}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -5,11 +5,13 @@ import { checkTools } from "../adapters/tool-checks.js";
|
|
|
5
5
|
import { detectTestCommands } from "../core/test-detection.js";
|
|
6
6
|
import { coreFiles, enterpriseFiles } from "../core/scaffold.js";
|
|
7
7
|
import { agentFiles } from "../core/agent-scaffold.js";
|
|
8
|
+
import { validateWorkflowContract } from "../core/workflow-validator.js";
|
|
8
9
|
export async function doctorCommand(options) {
|
|
9
10
|
const stdout = options.stdout ?? console;
|
|
10
11
|
const tools = checkTools();
|
|
11
12
|
const tests = await detectTestCommands(options.root);
|
|
12
13
|
const deepChecks = options.deep ? await runDeepChecks(options.root) : [];
|
|
14
|
+
const contractChecks = options.deep ? await validateWorkflowContract(options.root) : [];
|
|
13
15
|
const adapters = await Promise.all(getAdapters("all").map(async (adapter) => ({
|
|
14
16
|
name: adapter.name,
|
|
15
17
|
...(await adapterStatus(options.root, adapter.outputPaths)),
|
|
@@ -19,8 +21,9 @@ export async function doctorCommand(options) {
|
|
|
19
21
|
tools,
|
|
20
22
|
tests,
|
|
21
23
|
deepChecks,
|
|
24
|
+
contractChecks,
|
|
22
25
|
adapters,
|
|
23
|
-
status: statusFor(tools, deepChecks),
|
|
26
|
+
status: statusFor(tools, deepChecks, contractChecks),
|
|
24
27
|
};
|
|
25
28
|
if (options.json) {
|
|
26
29
|
stdout.log(JSON.stringify(report, null, 2));
|
|
@@ -33,6 +36,9 @@ export async function doctorCommand(options) {
|
|
|
33
36
|
for (const check of deepChecks) {
|
|
34
37
|
stdout.log(`Deep ${check.name}: ${check.ok ? "ok" : "missing"}`);
|
|
35
38
|
}
|
|
39
|
+
for (const check of contractChecks) {
|
|
40
|
+
stdout.log(`Contract ${check.name}: ${check.ok ? "ok" : check.detail}`);
|
|
41
|
+
}
|
|
36
42
|
for (const adapter of adapters) {
|
|
37
43
|
stdout.log(`Adapter ${adapter.name}: ${adapter.present}/${adapter.total} files present`);
|
|
38
44
|
}
|
|
@@ -56,10 +62,11 @@ async function fileExists(root, path) {
|
|
|
56
62
|
return false;
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
|
-
function statusFor(tools, deepChecks) {
|
|
65
|
+
function statusFor(tools, deepChecks, contractChecks) {
|
|
60
66
|
const requiredToolsMissing = tools.some((tool) => tool.required && !tool.available);
|
|
61
67
|
const deepChecksMissing = deepChecks.some((check) => !check.ok);
|
|
62
|
-
|
|
68
|
+
const contractChecksFailed = contractChecks.some((check) => !check.ok);
|
|
69
|
+
return requiredToolsMissing || deepChecksMissing || contractChecksFailed ? "needs-attention" : "ok";
|
|
63
70
|
}
|
|
64
71
|
async function adapterStatus(root, paths) {
|
|
65
72
|
const missing = [];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { auditPermission } from "../core/permission-auditor.js";
|
|
2
|
+
export async function permissionsCommand(options) {
|
|
3
|
+
const stdout = options.stdout ?? console;
|
|
4
|
+
if (options.action !== "audit") {
|
|
5
|
+
stdout.error?.(`Unknown permissions action: ${options.action}`);
|
|
6
|
+
return 1;
|
|
7
|
+
}
|
|
8
|
+
const result = auditPermission({ path: options.path, command: options.command });
|
|
9
|
+
if (options.json) {
|
|
10
|
+
stdout.log(JSON.stringify(result, null, 2));
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
stdout.log(`Speckit permission audit: ${result.status}`);
|
|
14
|
+
for (const reason of result.reasons)
|
|
15
|
+
stdout.log(`- ${reason}`);
|
|
16
|
+
}
|
|
17
|
+
return result.status === "deny" ? 1 : 0;
|
|
18
|
+
}
|
package/dist/commands/plan.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { markdown, writeManagedFiles } from "../core/managed-files.js";
|
|
1
|
+
import { markdown, markdownWithFrontmatter, writeManagedFiles } from "../core/managed-files.js";
|
|
2
2
|
import { slugify, timestamp } from "../core/slug.js";
|
|
3
3
|
export async function planCommand(options) {
|
|
4
4
|
const stdout = options.stdout ?? console;
|
|
@@ -36,13 +36,9 @@ export async function planCommand(options) {
|
|
|
36
36
|
},
|
|
37
37
|
{
|
|
38
38
|
path: `${dir}/story.md`,
|
|
39
|
-
content:
|
|
40
|
-
status: draft
|
|
39
|
+
content: markdownWithFrontmatter(`status: draft
|
|
41
40
|
evidence: ${dir}/tdd-evidence.md
|
|
42
|
-
context: pending
|
|
43
|
-
---
|
|
44
|
-
|
|
45
|
-
# Story: ${options.intent}
|
|
41
|
+
context: pending`, `# Story: ${options.intent}
|
|
46
42
|
|
|
47
43
|
## Acceptance Criteria
|
|
48
44
|
- Given ...
|
|
@@ -63,12 +59,8 @@ context: pending
|
|
|
63
59
|
},
|
|
64
60
|
{
|
|
65
61
|
path: `${dir}/tdd-evidence.md`,
|
|
66
|
-
content:
|
|
67
|
-
|
|
68
|
-
story: ${dir}/story.md
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
# TDD Evidence: ${options.intent}
|
|
62
|
+
content: markdownWithFrontmatter(`status: missing
|
|
63
|
+
story: ${dir}/story.md`, `# TDD Evidence: ${options.intent}
|
|
72
64
|
|
|
73
65
|
## Red
|
|
74
66
|
|
package/dist/commands/quick.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { markdownWithFrontmatter, writeManagedFiles } from "../core/managed-files.js";
|
|
2
2
|
import { slugify, timestamp } from "../core/slug.js";
|
|
3
3
|
import { detectPreferredTestCommand } from "../core/test-detection.js";
|
|
4
4
|
export async function quickCommand(options) {
|
|
@@ -11,13 +11,9 @@ export async function quickCommand(options) {
|
|
|
11
11
|
await writeManagedFiles(options.root, [
|
|
12
12
|
{
|
|
13
13
|
path: storyPath,
|
|
14
|
-
content:
|
|
15
|
-
status: ready-for-dev
|
|
14
|
+
content: markdownWithFrontmatter(`status: ready-for-dev
|
|
16
15
|
evidence: ${evidencePath}
|
|
17
|
-
context: pending
|
|
18
|
-
---
|
|
19
|
-
|
|
20
|
-
# Story: ${options.intent}
|
|
16
|
+
context: pending`, `# Story: ${options.intent}
|
|
21
17
|
|
|
22
18
|
## Intent
|
|
23
19
|
${options.intent}
|
|
@@ -46,12 +42,8 @@ ${options.intent}
|
|
|
46
42
|
},
|
|
47
43
|
{
|
|
48
44
|
path: evidencePath,
|
|
49
|
-
content:
|
|
50
|
-
|
|
51
|
-
story: ${storyPath}
|
|
52
|
-
---
|
|
53
|
-
|
|
54
|
-
# TDD Evidence: ${options.intent}
|
|
45
|
+
content: markdownWithFrontmatter(`status: missing
|
|
46
|
+
story: ${storyPath}`, `# TDD Evidence: ${options.intent}
|
|
55
47
|
|
|
56
48
|
## Test Intent
|
|
57
49
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { validateWorkflowContract } from "../core/workflow-validator.js";
|
|
2
|
+
export async function validateCommand(options) {
|
|
3
|
+
const stdout = options.stdout ?? console;
|
|
4
|
+
const checks = await validateWorkflowContract(options.root);
|
|
5
|
+
const status = checks.every((check) => check.ok) ? "ok" : "needs-attention";
|
|
6
|
+
const report = { status, checks };
|
|
7
|
+
if (options.json) {
|
|
8
|
+
stdout.log(JSON.stringify(report, null, 2));
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
stdout.log(`Speckit workflow contract: ${status}`);
|
|
12
|
+
for (const check of checks) {
|
|
13
|
+
stdout.log(`${check.ok ? "ok" : "fail"} ${check.name}: ${check.detail}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return status === "ok" ? 0 : 1;
|
|
17
|
+
}
|
|
@@ -8,7 +8,7 @@ export function agentFiles() {
|
|
|
8
8
|
|
|
9
9
|
## Mission
|
|
10
10
|
|
|
11
|
-
Act as the controller for Speckit enterprise work.
|
|
11
|
+
Act as the controller for Speckit enterprise work. Route intent into the smallest useful skill, preserve artifact continuity, and keep implementation bound to Agile + TDD evidence.
|
|
12
12
|
|
|
13
13
|
## Load Order
|
|
14
14
|
|
|
@@ -27,6 +27,19 @@ Act as the controller for Speckit enterprise work. Do not be the only worker whe
|
|
|
27
27
|
- Use graph skills before choosing or reordering work.
|
|
28
28
|
- Use session skills at every task boundary.
|
|
29
29
|
- Use review skills before closure.
|
|
30
|
+
- Load only the current workflow step and directly referenced artifacts.
|
|
31
|
+
- Prefer artifact evidence over conversational memory.
|
|
32
|
+
- Halt when the next action would cross from plan to code without a ready story.
|
|
33
|
+
|
|
34
|
+
## Workflow State Machine
|
|
35
|
+
|
|
36
|
+
1. Shape rough intent into bounded value and non-goals.
|
|
37
|
+
2. Plan PRD, architecture, epics, stories, risks, and rollback.
|
|
38
|
+
3. Prepare sprint status and graph sync.
|
|
39
|
+
4. Build current context and subagent handoff.
|
|
40
|
+
5. Run ready story through red-green-refactor.
|
|
41
|
+
6. Review spec compliance, edge cases, and production readiness.
|
|
42
|
+
7. Close by syncing story, session, docs, and graph artifacts.
|
|
30
43
|
|
|
31
44
|
## Delegation Contract
|
|
32
45
|
|
|
@@ -50,6 +63,14 @@ Subagents must finish with one status: \`DONE\`, \`DONE_WITH_CONCERNS\`, \`BLOCK
|
|
|
50
63
|
- Prefer focused subagent handoffs over passing full conversation history.
|
|
51
64
|
- Hydrate runtime tasks from unchecked plan/story checkboxes at session start.
|
|
52
65
|
- Sync completed runtime tasks back to durable plan/story files before close.
|
|
66
|
+
|
|
67
|
+
## Output Contract
|
|
68
|
+
|
|
69
|
+
- State selected skill and why.
|
|
70
|
+
- State artifacts read and artifacts updated.
|
|
71
|
+
- State current story status and evidence status for code work.
|
|
72
|
+
- State next command or halt reason.
|
|
73
|
+
- Never claim completion without verification evidence.
|
|
53
74
|
`),
|
|
54
75
|
},
|
|
55
76
|
...specSkillFiles(),
|
|
@@ -2,6 +2,7 @@ export declare const MANAGED_MARKER = "speckit:managed";
|
|
|
2
2
|
export type ManagedFile = {
|
|
3
3
|
path: string;
|
|
4
4
|
content: string;
|
|
5
|
+
isManaged?: (content: string) => boolean;
|
|
5
6
|
};
|
|
6
7
|
export type WriteResult = {
|
|
7
8
|
path: string;
|
|
@@ -10,5 +11,9 @@ export type WriteResult = {
|
|
|
10
11
|
};
|
|
11
12
|
export declare function writeManagedFiles(root: string, files: ManagedFile[], force?: boolean): Promise<WriteResult[]>;
|
|
12
13
|
export declare function markdown(content: string): string;
|
|
14
|
+
export declare function markdownWithFrontmatter(frontmatter: string, content: string): string;
|
|
13
15
|
export declare function json(content: unknown): string;
|
|
16
|
+
export declare function strictJson(content: unknown): string;
|
|
17
|
+
export declare function strictJsonManaged(content: unknown): Pick<ManagedFile, "content" | "isManaged">;
|
|
18
|
+
export declare function legacyJsonManaged(content: string): boolean;
|
|
14
19
|
export declare function text(content: string, comment?: string): string;
|
|
@@ -13,7 +13,10 @@ export async function writeManagedFiles(root, files, force = false) {
|
|
|
13
13
|
catch {
|
|
14
14
|
existing = undefined;
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
const isManaged = existing
|
|
17
|
+
? existing.includes(MANAGED_MARKER) || file.isManaged?.(existing) === true
|
|
18
|
+
: false;
|
|
19
|
+
if (existing && !isManaged && !force) {
|
|
17
20
|
results.push({
|
|
18
21
|
path: file.path,
|
|
19
22
|
status: "skipped",
|
|
@@ -32,9 +35,38 @@ export async function writeManagedFiles(root, files, force = false) {
|
|
|
32
35
|
export function markdown(content) {
|
|
33
36
|
return `<!-- ${MANAGED_MARKER} -->\n${content.trim()}\n`;
|
|
34
37
|
}
|
|
38
|
+
export function markdownWithFrontmatter(frontmatter, content) {
|
|
39
|
+
return `---\n${frontmatter.trim()}\n---\n<!-- ${MANAGED_MARKER} -->\n${content.trim()}\n`;
|
|
40
|
+
}
|
|
35
41
|
export function json(content) {
|
|
36
42
|
return `${JSON.stringify({ "x-speckit-managed": MANAGED_MARKER, ...asObject(content) }, null, 2)}\n`;
|
|
37
43
|
}
|
|
44
|
+
export function strictJson(content) {
|
|
45
|
+
return `${JSON.stringify(content, null, 2)}\n`;
|
|
46
|
+
}
|
|
47
|
+
export function strictJsonManaged(content) {
|
|
48
|
+
return {
|
|
49
|
+
content: strictJson(content),
|
|
50
|
+
isManaged: (existing) => legacyJsonManaged(existing) || jsonMatches(existing, content),
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function legacyJsonManaged(content) {
|
|
54
|
+
try {
|
|
55
|
+
const parsed = JSON.parse(content);
|
|
56
|
+
return parsed["x-speckit-managed"] === MANAGED_MARKER;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function jsonMatches(content, expected) {
|
|
63
|
+
try {
|
|
64
|
+
return JSON.stringify(JSON.parse(content)) === JSON.stringify(expected);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
38
70
|
export function text(content, comment = "#") {
|
|
39
71
|
return `${comment} ${MANAGED_MARKER}\n${content.trim()}\n`;
|
|
40
72
|
}
|