@trieungoctam/speckit 0.1.0 → 0.2.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 +11 -1
- package/dist/adapters/tool-checks.js +0 -1
- package/dist/cli.js +20 -2
- package/dist/commands/close.d.ts +6 -0
- package/dist/commands/close.js +34 -0
- package/dist/commands/context.d.ts +6 -0
- package/dist/commands/context.js +53 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +29 -1
- package/dist/commands/init.d.ts +1 -0
- package/dist/commands/init.js +5 -3
- package/dist/commands/run.js +4 -22
- package/dist/commands/start.d.ts +6 -0
- package/dist/commands/start.js +47 -0
- package/dist/commands/sync.js +1 -7
- package/dist/commands/triage.d.ts +6 -0
- package/dist/commands/triage.js +33 -0
- package/dist/core/scaffold.d.ts +1 -0
- package/dist/core/scaffold.js +46 -0
- package/dist/core/story.d.ts +8 -0
- package/dist/core/story.js +33 -0
- package/docs/development-roadmap.md +7 -6
- package/docs/product-contract.md +4 -4
- package/docs/project-changelog.md +31 -1
- package/docs/release-checklist.md +1 -1
- package/docs/spec-enterprise-harness-plan.md +68 -0
- package/docs/spec-quality-gates.md +70 -0
- package/docs/system-architecture.md +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Speckit is a local-first Agile + TDD workflow compiler for agentic IDEs. It turns rough intent into specs, stories, TDD evidence, and native IDE instruction packs.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Speckit owns the workflow contract and generates adapters for the tools you already use. The public product vocabulary is Speckit-only: Agile shaping, TDD execution, task graph triage, and IDE adapter compilation.
|
|
6
6
|
|
|
7
7
|
## Quickstart
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
10
|
npx @trieungoctam/speckit@latest init --ide all
|
|
11
|
+
npx @trieungoctam/speckit@latest init --enterprise --ide all
|
|
11
12
|
npx @trieungoctam/speckit@latest quick "Add checkout validation"
|
|
12
13
|
npx @trieungoctam/speckit@latest review
|
|
13
14
|
```
|
|
@@ -24,9 +25,12 @@ speckit doctor
|
|
|
24
25
|
|
|
25
26
|
```text
|
|
26
27
|
intent
|
|
28
|
+
-> start session
|
|
27
29
|
-> shape
|
|
28
30
|
-> plan
|
|
31
|
+
-> context
|
|
29
32
|
-> story with acceptance criteria
|
|
33
|
+
-> sync / triage
|
|
30
34
|
-> red test evidence
|
|
31
35
|
-> minimal implementation
|
|
32
36
|
-> green test evidence
|
|
@@ -41,15 +45,21 @@ For implementation stories, red-green-refactor evidence is mandatory. A story is
|
|
|
41
45
|
| Command | Purpose |
|
|
42
46
|
| --- | --- |
|
|
43
47
|
| `speckit init` | Create `.speckit/` core rules and all IDE adapters. |
|
|
48
|
+
| `speckit init --enterprise` | Add flow, tool policy, and prompt harness files. |
|
|
44
49
|
| `speckit init --ide <name>` | Generate one adapter: `claude-code`, `codex`, `antigravity`, `opencode`, or `cursor`. |
|
|
45
50
|
| `speckit doctor` | Report required tools, optional integrations, test commands, and adapter readiness. |
|
|
51
|
+
| `speckit doctor --deep` | Verify core enterprise harness files. |
|
|
52
|
+
| `speckit start "<idea>"` | Create a durable session handoff and current context. |
|
|
46
53
|
| `speckit shape "<intent>"` | Create a short spec contract. |
|
|
54
|
+
| `speckit context <story>` | Build the current implementation context from a story. |
|
|
47
55
|
| `speckit quick "<intent>"` | Create one story plus matching TDD evidence file. |
|
|
48
56
|
| `speckit plan "<intent>"` | Create PRD, architecture, story, and evidence skeletons. |
|
|
57
|
+
| `speckit triage` | Summarize synced story state without interactive graph commands. |
|
|
49
58
|
| `speckit next` | Safely wraps `bv --robot-next --format json`. |
|
|
50
59
|
| `speckit sync` | Export Speckit stories as beads-compatible JSONL metadata. |
|
|
51
60
|
| `speckit run <story>` | Print the TDD execution handoff for a story. |
|
|
52
61
|
| `speckit review` | Print the review checklist and current diff summary. |
|
|
62
|
+
| `speckit close <story>` | Create a closure checklist linked to the story and sync step. |
|
|
53
63
|
|
|
54
64
|
## Supported IDEs
|
|
55
65
|
|
|
@@ -2,7 +2,6 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
const tools = [
|
|
3
3
|
["git", true, "Install Git and run Speckit inside a repository."],
|
|
4
4
|
["node", true, "Install Node.js 20 or newer."],
|
|
5
|
-
["ck", false, "Recommended for ClaudeKit-style skills and workflows."],
|
|
6
5
|
["br", false, "Recommended beads CLI. Use bd only for older projects."],
|
|
7
6
|
["bd", false, "Legacy beads CLI fallback."],
|
|
8
7
|
["bv", false, "Recommended for Beads Viewer robot commands."],
|
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { initCommand } from "./commands/init.js";
|
|
2
2
|
import { doctorCommand } from "./commands/doctor.js";
|
|
3
|
+
import { startCommand } from "./commands/start.js";
|
|
3
4
|
import { shapeCommand } from "./commands/shape.js";
|
|
5
|
+
import { contextCommand } from "./commands/context.js";
|
|
4
6
|
import { quickCommand } from "./commands/quick.js";
|
|
5
7
|
import { planCommand } from "./commands/plan.js";
|
|
8
|
+
import { triageCommand } from "./commands/triage.js";
|
|
6
9
|
import { nextCommand } from "./commands/next.js";
|
|
7
10
|
import { syncCommand } from "./commands/sync.js";
|
|
8
11
|
import { runCommand } from "./commands/run.js";
|
|
9
12
|
import { reviewCommand } from "./commands/review.js";
|
|
13
|
+
import { closeCommand } from "./commands/close.js";
|
|
10
14
|
export async function main(argv = process.argv.slice(2), root = process.cwd()) {
|
|
11
15
|
const parsed = parseArgs(argv);
|
|
12
16
|
try {
|
|
@@ -16,15 +20,22 @@ export async function main(argv = process.argv.slice(2), root = process.cwd()) {
|
|
|
16
20
|
root,
|
|
17
21
|
ide: value(parsed, "ide"),
|
|
18
22
|
force: has(parsed, "force"),
|
|
23
|
+
enterprise: has(parsed, "enterprise"),
|
|
19
24
|
});
|
|
20
25
|
case "doctor":
|
|
21
|
-
return doctorCommand({ root, json: has(parsed, "json") });
|
|
26
|
+
return doctorCommand({ root, json: has(parsed, "json"), deep: has(parsed, "deep") });
|
|
27
|
+
case "start":
|
|
28
|
+
return startCommand({ root, intent: requiredIntent(parsed) });
|
|
22
29
|
case "shape":
|
|
23
30
|
return shapeCommand({ root, intent: requiredIntent(parsed) });
|
|
31
|
+
case "context":
|
|
32
|
+
return contextCommand({ root, target: requiredIntent(parsed) });
|
|
24
33
|
case "quick":
|
|
25
34
|
return quickCommand({ root, intent: requiredIntent(parsed) });
|
|
26
35
|
case "plan":
|
|
27
36
|
return planCommand({ root, intent: requiredIntent(parsed) });
|
|
37
|
+
case "triage":
|
|
38
|
+
return triageCommand({ root, json: has(parsed, "json") });
|
|
28
39
|
case "next":
|
|
29
40
|
return nextCommand();
|
|
30
41
|
case "sync":
|
|
@@ -33,6 +44,8 @@ export async function main(argv = process.argv.slice(2), root = process.cwd()) {
|
|
|
33
44
|
return runCommand({ root, target: requiredIntent(parsed) });
|
|
34
45
|
case "review":
|
|
35
46
|
return reviewCommand({ root });
|
|
47
|
+
case "close":
|
|
48
|
+
return closeCommand({ root, target: requiredIntent(parsed) });
|
|
36
49
|
case "help":
|
|
37
50
|
case "":
|
|
38
51
|
printHelp();
|
|
@@ -88,14 +101,19 @@ function printHelp() {
|
|
|
88
101
|
|
|
89
102
|
Usage:
|
|
90
103
|
speckit init [--ide all|claude-code|codex|antigravity|opencode|cursor] [--force]
|
|
91
|
-
speckit
|
|
104
|
+
speckit init --enterprise [--ide all] [--force]
|
|
105
|
+
speckit doctor [--json] [--deep]
|
|
106
|
+
speckit start "<idea>"
|
|
92
107
|
speckit shape "<intent>"
|
|
108
|
+
speckit context <story-path-or-id>
|
|
93
109
|
speckit quick "<intent>"
|
|
94
110
|
speckit plan "<intent>"
|
|
111
|
+
speckit triage [--json]
|
|
95
112
|
speckit next
|
|
96
113
|
speckit sync
|
|
97
114
|
speckit run <story-path-or-id>
|
|
98
115
|
speckit review
|
|
116
|
+
speckit close <story-path-or-id>
|
|
99
117
|
`);
|
|
100
118
|
}
|
|
101
119
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { markdown, writeManagedFiles } from "../core/managed-files.js";
|
|
2
|
+
import { slugify, timestamp } from "../core/slug.js";
|
|
3
|
+
import { resolveStory } from "../core/story.js";
|
|
4
|
+
export async function closeCommand(options) {
|
|
5
|
+
const stdout = options.stdout ?? console;
|
|
6
|
+
const story = await resolveStory(options.root, options.target);
|
|
7
|
+
if (!story) {
|
|
8
|
+
stdout.error(`Story not found: ${options.target}`);
|
|
9
|
+
return 1;
|
|
10
|
+
}
|
|
11
|
+
const closePath = `.speckit/closures/${timestamp()}-${slugify(story.id)}.md`;
|
|
12
|
+
await writeManagedFiles(options.root, [
|
|
13
|
+
{
|
|
14
|
+
path: closePath,
|
|
15
|
+
content: markdown(`# Spec Close: ${story.title}
|
|
16
|
+
|
|
17
|
+
## Story
|
|
18
|
+
\`${story.path}\`
|
|
19
|
+
|
|
20
|
+
## Required Verification
|
|
21
|
+
- [ ] Acceptance criteria reviewed
|
|
22
|
+
- [ ] TDD evidence reviewed
|
|
23
|
+
- [ ] Tests passed
|
|
24
|
+
- [ ] Docs impact recorded
|
|
25
|
+
- [ ] Graph sync completed with \`speckit sync\`
|
|
26
|
+
|
|
27
|
+
## Review Command
|
|
28
|
+
\`speckit review\`
|
|
29
|
+
`),
|
|
30
|
+
},
|
|
31
|
+
]);
|
|
32
|
+
stdout.log(closePath);
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { markdown, writeManagedFiles } from "../core/managed-files.js";
|
|
2
|
+
import { resolveStory } from "../core/story.js";
|
|
3
|
+
export async function contextCommand(options) {
|
|
4
|
+
const stdout = options.stdout ?? console;
|
|
5
|
+
const story = await resolveStory(options.root, options.target);
|
|
6
|
+
if (!story) {
|
|
7
|
+
stdout.error(`Story not found: ${options.target}`);
|
|
8
|
+
return 1;
|
|
9
|
+
}
|
|
10
|
+
const contextPath = ".speckit/context/current.md";
|
|
11
|
+
await writeManagedFiles(options.root, [
|
|
12
|
+
{
|
|
13
|
+
path: contextPath,
|
|
14
|
+
content: markdown(`# Current Spec Context
|
|
15
|
+
|
|
16
|
+
## Story
|
|
17
|
+
${story.title}
|
|
18
|
+
|
|
19
|
+
## Story Path
|
|
20
|
+
\`${story.path}\`
|
|
21
|
+
|
|
22
|
+
## Acceptance Criteria
|
|
23
|
+
${extractSection(story.content, "Acceptance Criteria") ?? "- Not defined"}
|
|
24
|
+
|
|
25
|
+
## TDD Evidence
|
|
26
|
+
${extractEvidenceReference(story.content) ?? "- Create or update matching `.speckit/evidence/*tdd-evidence.md`"}
|
|
27
|
+
|
|
28
|
+
## Next Command
|
|
29
|
+
\`speckit run ${story.id}\`
|
|
30
|
+
`),
|
|
31
|
+
},
|
|
32
|
+
], true);
|
|
33
|
+
stdout.log(contextPath);
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
function extractEvidenceReference(content) {
|
|
37
|
+
const match = content.match(/`([^`]*tdd-evidence\.md)`/i);
|
|
38
|
+
return match ? `\`${match[1]}\`` : undefined;
|
|
39
|
+
}
|
|
40
|
+
function extractSection(content, heading) {
|
|
41
|
+
const lines = content.split("\n");
|
|
42
|
+
const start = lines.findIndex((line) => line.trim().toLowerCase() === `## ${heading}`.toLowerCase());
|
|
43
|
+
if (start === -1)
|
|
44
|
+
return undefined;
|
|
45
|
+
const collected = [];
|
|
46
|
+
for (const line of lines.slice(start + 1)) {
|
|
47
|
+
if (line.startsWith("## "))
|
|
48
|
+
break;
|
|
49
|
+
if (line.trim())
|
|
50
|
+
collected.push(line);
|
|
51
|
+
}
|
|
52
|
+
return collected.length > 0 ? collected.join("\n") : undefined;
|
|
53
|
+
}
|
package/dist/commands/doctor.js
CHANGED
|
@@ -3,10 +3,12 @@ import { join } from "node:path";
|
|
|
3
3
|
import { getAdapters } from "../config/adapter-registry.js";
|
|
4
4
|
import { checkTools } from "../adapters/tool-checks.js";
|
|
5
5
|
import { detectTestCommands } from "../core/test-detection.js";
|
|
6
|
+
import { coreFiles, enterpriseFiles } from "../core/scaffold.js";
|
|
6
7
|
export async function doctorCommand(options) {
|
|
7
8
|
const stdout = options.stdout ?? console;
|
|
8
9
|
const tools = checkTools();
|
|
9
10
|
const tests = await detectTestCommands(options.root);
|
|
11
|
+
const deepChecks = options.deep ? await runDeepChecks(options.root) : [];
|
|
10
12
|
const adapters = await Promise.all(getAdapters("all").map(async (adapter) => ({
|
|
11
13
|
name: adapter.name,
|
|
12
14
|
...(await adapterStatus(options.root, adapter.outputPaths)),
|
|
@@ -15,8 +17,9 @@ export async function doctorCommand(options) {
|
|
|
15
17
|
node: process.versions.node,
|
|
16
18
|
tools,
|
|
17
19
|
tests,
|
|
20
|
+
deepChecks,
|
|
18
21
|
adapters,
|
|
19
|
-
status: tools
|
|
22
|
+
status: statusFor(tools, deepChecks),
|
|
20
23
|
};
|
|
21
24
|
if (options.json) {
|
|
22
25
|
stdout.log(JSON.stringify(report, null, 2));
|
|
@@ -26,12 +29,37 @@ export async function doctorCommand(options) {
|
|
|
26
29
|
stdout.log(`Node: ${report.node}`);
|
|
27
30
|
stdout.log(`Tools: ${tools.map((tool) => `${tool.name}=${tool.available ? "ok" : "missing"}`).join(", ")}`);
|
|
28
31
|
stdout.log(`Tests: ${tests[0]?.command ?? "not detected"}`);
|
|
32
|
+
for (const check of deepChecks) {
|
|
33
|
+
stdout.log(`Deep ${check.name}: ${check.ok ? "ok" : "missing"}`);
|
|
34
|
+
}
|
|
29
35
|
for (const adapter of adapters) {
|
|
30
36
|
stdout.log(`Adapter ${adapter.name}: ${adapter.present}/${adapter.total} files present`);
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
return report.status === "ok" ? 0 : 1;
|
|
34
40
|
}
|
|
41
|
+
async function runDeepChecks(root) {
|
|
42
|
+
const requiredFiles = [...coreFiles(), ...enterpriseFiles()];
|
|
43
|
+
return Promise.all(requiredFiles.map(async (file) => ({
|
|
44
|
+
name: file.path,
|
|
45
|
+
path: file.path,
|
|
46
|
+
ok: await fileExists(root, file.path),
|
|
47
|
+
})));
|
|
48
|
+
}
|
|
49
|
+
async function fileExists(root, path) {
|
|
50
|
+
try {
|
|
51
|
+
await access(join(root, path));
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function statusFor(tools, deepChecks) {
|
|
59
|
+
const requiredToolsMissing = tools.some((tool) => tool.required && !tool.available);
|
|
60
|
+
const deepChecksMissing = deepChecks.some((check) => !check.ok);
|
|
61
|
+
return requiredToolsMissing || deepChecksMissing ? "needs-attention" : "ok";
|
|
62
|
+
}
|
|
35
63
|
async function adapterStatus(root, paths) {
|
|
36
64
|
const missing = [];
|
|
37
65
|
for (const path of paths) {
|
package/dist/commands/init.d.ts
CHANGED
package/dist/commands/init.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { coreFiles } from "../core/scaffold.js";
|
|
1
|
+
import { coreFiles, enterpriseFiles } from "../core/scaffold.js";
|
|
2
2
|
import { writeManagedFiles } from "../core/managed-files.js";
|
|
3
3
|
import { getAdapters } from "../config/adapter-registry.js";
|
|
4
4
|
export async function initCommand(options) {
|
|
5
5
|
const stdout = options.stdout ?? console;
|
|
6
6
|
const selectedIde = options.ide ?? "all";
|
|
7
|
+
const baseFiles = options.enterprise ? [...coreFiles(), ...enterpriseFiles()] : coreFiles();
|
|
7
8
|
const adapterFiles = getAdapters(selectedIde).flatMap((adapter) => adapter.render());
|
|
8
|
-
const results = await writeManagedFiles(options.root, [...
|
|
9
|
+
const results = await writeManagedFiles(options.root, [...baseFiles, ...adapterFiles], options.force ?? false);
|
|
9
10
|
const created = results.filter((result) => result.status === "created").length;
|
|
10
11
|
const updated = results.filter((result) => result.status === "updated").length;
|
|
11
12
|
const skipped = results.filter((result) => result.status === "skipped");
|
|
12
|
-
|
|
13
|
+
const mode = options.enterprise ? "enterprise" : "standard";
|
|
14
|
+
stdout.log(`Speckit initialized (${mode}): ${created} created, ${updated} updated, ${skipped.length} skipped.`);
|
|
13
15
|
for (const result of skipped) {
|
|
14
16
|
stdout.log(`skipped ${result.path}: ${result.reason}`);
|
|
15
17
|
}
|
package/dist/commands/run.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { join } from "node:path";
|
|
1
|
+
import { resolveStory } from "../core/story.js";
|
|
3
2
|
export async function runCommand(options) {
|
|
4
3
|
const stdout = options.stdout ?? console;
|
|
5
|
-
const
|
|
6
|
-
if (!
|
|
4
|
+
const story = await resolveStory(options.root, options.target);
|
|
5
|
+
if (!story) {
|
|
7
6
|
stdout.error(`Story not found: ${options.target}`);
|
|
8
7
|
return 1;
|
|
9
8
|
}
|
|
10
9
|
stdout.log(`# Speckit TDD Run
|
|
11
10
|
|
|
12
|
-
Story: ${
|
|
11
|
+
Story: ${story.path}
|
|
13
12
|
|
|
14
13
|
1. Read the story and acceptance criteria.
|
|
15
14
|
2. Identify the smallest executable test that should fail.
|
|
@@ -23,20 +22,3 @@ Recommended handoff:
|
|
|
23
22
|
`);
|
|
24
23
|
return 0;
|
|
25
24
|
}
|
|
26
|
-
async function resolveStory(root, target) {
|
|
27
|
-
const candidates = [
|
|
28
|
-
target,
|
|
29
|
-
`.speckit/stories/${target}`,
|
|
30
|
-
`.speckit/stories/${target}.md`,
|
|
31
|
-
];
|
|
32
|
-
for (const candidate of candidates) {
|
|
33
|
-
try {
|
|
34
|
-
await access(join(root, candidate));
|
|
35
|
-
return candidate;
|
|
36
|
-
}
|
|
37
|
-
catch {
|
|
38
|
-
// Try the next candidate.
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return undefined;
|
|
42
|
-
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { markdown, writeManagedFiles } from "../core/managed-files.js";
|
|
2
|
+
import { slugify, timestamp } from "../core/slug.js";
|
|
3
|
+
export async function startCommand(options) {
|
|
4
|
+
const stdout = options.stdout ?? console;
|
|
5
|
+
const sessionId = `${timestamp()}-${slugify(options.intent)}`;
|
|
6
|
+
const handoffPath = `.speckit/sessions/${sessionId}/handoff.md`;
|
|
7
|
+
const contextPath = ".speckit/context/current.md";
|
|
8
|
+
await writeManagedFiles(options.root, [
|
|
9
|
+
{
|
|
10
|
+
path: handoffPath,
|
|
11
|
+
content: markdown(`# Spec Session: ${sessionId}
|
|
12
|
+
|
|
13
|
+
## Idea
|
|
14
|
+
${options.intent}
|
|
15
|
+
|
|
16
|
+
## Current Phase
|
|
17
|
+
shape
|
|
18
|
+
|
|
19
|
+
## Linked Artifacts
|
|
20
|
+
- Context: \`${contextPath}\`
|
|
21
|
+
|
|
22
|
+
## Next Command
|
|
23
|
+
\`speckit shape "${options.intent}"\`
|
|
24
|
+
`),
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
path: contextPath,
|
|
28
|
+
content: markdown(`# Current Spec Context
|
|
29
|
+
|
|
30
|
+
## Session
|
|
31
|
+
${sessionId}
|
|
32
|
+
|
|
33
|
+
## Idea
|
|
34
|
+
${options.intent}
|
|
35
|
+
|
|
36
|
+
## Active Artifact
|
|
37
|
+
\`${handoffPath}\`
|
|
38
|
+
|
|
39
|
+
## Next Command
|
|
40
|
+
\`speckit shape "${options.intent}"\`
|
|
41
|
+
`),
|
|
42
|
+
},
|
|
43
|
+
], true);
|
|
44
|
+
stdout.log(sessionId);
|
|
45
|
+
stdout.log(handoffPath);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
package/dist/commands/sync.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readdir, readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { markdown, writeManagedFiles } from "../core/managed-files.js";
|
|
4
|
+
import { firstHeading } from "../core/story.js";
|
|
4
5
|
export async function syncCommand(options) {
|
|
5
6
|
const stdout = options.stdout ?? console;
|
|
6
7
|
const storiesDir = join(options.root, ".speckit", "stories");
|
|
@@ -45,10 +46,3 @@ bv --robot-next --format json
|
|
|
45
46
|
stdout.log(`Synced ${stories.length} stories to .speckit/sync/beads-sync.jsonl`);
|
|
46
47
|
return 0;
|
|
47
48
|
}
|
|
48
|
-
function firstHeading(content) {
|
|
49
|
-
return content
|
|
50
|
-
.split("\n")
|
|
51
|
-
.find((line) => line.startsWith("# "))
|
|
52
|
-
?.replace(/^#\s+/, "")
|
|
53
|
-
.trim();
|
|
54
|
-
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
export async function triageCommand(options) {
|
|
4
|
+
const stdout = options.stdout ?? console;
|
|
5
|
+
const stories = await readSyncedStories(options.root);
|
|
6
|
+
const open = stories.filter((story) => story.status === "open");
|
|
7
|
+
const ready = stories.filter((story) => story.status !== "open");
|
|
8
|
+
const report = {
|
|
9
|
+
source: ".speckit/sync/beads-sync.jsonl",
|
|
10
|
+
open: open.length,
|
|
11
|
+
ready: ready.length,
|
|
12
|
+
next: open[0] ?? null,
|
|
13
|
+
};
|
|
14
|
+
if (options.json) {
|
|
15
|
+
stdout.log(JSON.stringify(report, null, 2));
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
stdout.log(`Spec triage: ${open.length} open, ${ready.length} ready`);
|
|
19
|
+
stdout.log(open[0] ? `Next: ${open[0].id} (${open[0].path})` : "Next: none");
|
|
20
|
+
return 0;
|
|
21
|
+
}
|
|
22
|
+
async function readSyncedStories(root) {
|
|
23
|
+
try {
|
|
24
|
+
const content = await readFile(join(root, ".speckit", "sync", "beads-sync.jsonl"), "utf8");
|
|
25
|
+
return content
|
|
26
|
+
.split("\n")
|
|
27
|
+
.filter(Boolean)
|
|
28
|
+
.map((line) => JSON.parse(line));
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
}
|
package/dist/core/scaffold.d.ts
CHANGED
package/dist/core/scaffold.js
CHANGED
|
@@ -69,3 +69,49 @@ adapters:
|
|
|
69
69
|
},
|
|
70
70
|
];
|
|
71
71
|
}
|
|
72
|
+
export function enterpriseFiles() {
|
|
73
|
+
return [
|
|
74
|
+
{
|
|
75
|
+
path: ".speckit/flows/spec-flow.md",
|
|
76
|
+
content: markdown(`# Spec Flow
|
|
77
|
+
|
|
78
|
+
## Order
|
|
79
|
+
start -> shape -> plan -> context -> sync -> triage -> run -> review -> close
|
|
80
|
+
|
|
81
|
+
## Traceability
|
|
82
|
+
- A session links the original idea to every downstream artifact.
|
|
83
|
+
- A story links acceptance criteria to TDD evidence.
|
|
84
|
+
- Sync links stories to graph-ready JSONL.
|
|
85
|
+
- Close links review output back to story and graph sync.
|
|
86
|
+
`),
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
path: ".speckit/tool-policy.yaml",
|
|
90
|
+
content: text(`version: 1
|
|
91
|
+
phases:
|
|
92
|
+
shape:
|
|
93
|
+
may_edit_code: false
|
|
94
|
+
plan:
|
|
95
|
+
may_edit_code: false
|
|
96
|
+
run:
|
|
97
|
+
may_edit_code: true
|
|
98
|
+
requires_tdd_evidence: true
|
|
99
|
+
review:
|
|
100
|
+
may_edit_code: false
|
|
101
|
+
graph:
|
|
102
|
+
robot_only: true`),
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
path: ".speckit/prompts/spec-run.md",
|
|
106
|
+
content: markdown(`# Spec Run Prompt
|
|
107
|
+
|
|
108
|
+
1. Read \`.speckit/context/current.md\`.
|
|
109
|
+
2. Confirm story acceptance criteria.
|
|
110
|
+
3. Write or run the failing test first.
|
|
111
|
+
4. Implement the smallest change.
|
|
112
|
+
5. Record red, green, and refactor evidence.
|
|
113
|
+
6. Run \`speckit review\` before handoff.
|
|
114
|
+
`),
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type StoryResolution = {
|
|
2
|
+
path: string;
|
|
3
|
+
content: string;
|
|
4
|
+
id: string;
|
|
5
|
+
title: string;
|
|
6
|
+
};
|
|
7
|
+
export declare function resolveStory(root: string, target: string): Promise<StoryResolution | undefined>;
|
|
8
|
+
export declare function firstHeading(content: string): string | undefined;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { access, readFile } from "node:fs/promises";
|
|
2
|
+
import { basename, join } from "node:path";
|
|
3
|
+
export async function resolveStory(root, target) {
|
|
4
|
+
const candidates = [
|
|
5
|
+
target,
|
|
6
|
+
`.speckit/stories/${target}`,
|
|
7
|
+
`.speckit/stories/${target}.md`,
|
|
8
|
+
];
|
|
9
|
+
for (const candidate of candidates) {
|
|
10
|
+
try {
|
|
11
|
+
const fullPath = join(root, candidate);
|
|
12
|
+
await access(fullPath);
|
|
13
|
+
const content = await readFile(fullPath, "utf8");
|
|
14
|
+
return {
|
|
15
|
+
path: candidate,
|
|
16
|
+
content,
|
|
17
|
+
id: basename(candidate).replace(/\.md$/, ""),
|
|
18
|
+
title: firstHeading(content) ?? basename(candidate).replace(/\.md$/, ""),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// Try the next candidate.
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
export function firstHeading(content) {
|
|
28
|
+
return content
|
|
29
|
+
.split("\n")
|
|
30
|
+
.find((line) => line.startsWith("# "))
|
|
31
|
+
?.replace(/^#\s+/, "")
|
|
32
|
+
.trim();
|
|
33
|
+
}
|
|
@@ -6,7 +6,7 @@ Speckit MVP is implemented and pushed to `git@github.com:trieungoctam/speckit.gi
|
|
|
6
6
|
|
|
7
7
|
Current package target: `@trieungoctam/speckit@0.1.0`.
|
|
8
8
|
|
|
9
|
-
The CLI is npx-ready, generates Agile + TDD rules, creates workflow artifacts, supports five IDE adapters, wraps Beads Viewer safely, and has automated tests plus CI.
|
|
9
|
+
The CLI is npx-ready, generates Agile + TDD rules, creates workflow artifacts, supports five IDE adapters, wraps Beads Viewer safely, includes an enterprise harness, and has automated tests plus CI.
|
|
10
10
|
|
|
11
11
|
## Milestones
|
|
12
12
|
|
|
@@ -14,17 +14,18 @@ The CLI is npx-ready, generates Agile + TDD rules, creates workflow artifacts, s
|
|
|
14
14
|
| --- | --- | --- |
|
|
15
15
|
| Product contract | Complete | Contract, workflow model, and command surface documented. |
|
|
16
16
|
| CLI scaffold | Complete | `bin/speckit`, TypeScript build, command router, managed file writer. |
|
|
17
|
-
| Workflow engine |
|
|
17
|
+
| Workflow engine | Complete | `start`, `shape`, `plan`, `context`, `quick`, `sync`, `triage`, `run`, `review`, and `close` generate linked artifacts. |
|
|
18
18
|
| IDE adapters | Complete | Claude Code, Codex, Antigravity, OpenCode, Cursor. |
|
|
19
19
|
| Beads integration | MVP Complete | `next` wraps BV robot mode; `sync` exports story metadata JSONL. |
|
|
20
|
-
|
|
|
20
|
+
| Enterprise harness | MVP Complete | `init --enterprise` creates flow, tool-policy, and prompt harness files; `doctor --deep` verifies them. |
|
|
21
|
+
| Validation | Complete | Build and `node:test` suite pass locally with flow contract gates. |
|
|
21
22
|
| GitHub publish | Complete | Initial code pushed to `trieungoctam/speckit` at commit `7e5c582`; status docs follow-up in progress. |
|
|
22
23
|
| npm package readiness | Ready | Package scoped as `@trieungoctam/speckit`; `npm pack --dry-run` passes. |
|
|
23
24
|
|
|
24
25
|
## Next Roadmap
|
|
25
26
|
|
|
26
|
-
-
|
|
27
|
+
- Release Speckit-only vocabulary cleanup as `0.1.1` or fold it into `0.2.0`.
|
|
28
|
+
- Expand Speckit Enterprise Harness with richer profile and context-pack layers.
|
|
29
|
+
- Add graph commands: `graph-plan`, `insights`, and `drift`.
|
|
27
30
|
- Add GitHub trusted publishing for npm releases.
|
|
28
|
-
- Add richer config loading from `.speckit/config.yaml`.
|
|
29
|
-
- Add optional direct `br`/`bd` import once command compatibility is pinned.
|
|
30
31
|
- Add snapshot tests for full adapter file contents.
|
package/docs/product-contract.md
CHANGED
|
@@ -5,7 +5,7 @@ Speckit owns the workflow contract for enterprise Agile + TDD development with a
|
|
|
5
5
|
## Speckit Owns
|
|
6
6
|
|
|
7
7
|
- The `.speckit/` source of truth: config, rules, workflows, templates, generated artifacts.
|
|
8
|
-
- The command surface: `init`, `doctor`, `shape`, `plan`, `
|
|
8
|
+
- The command surface: `init`, `doctor`, `start`, `shape`, `plan`, `context`, `quick`, `sync`, `triage`, `next`, `run`, `review`, `close`.
|
|
9
9
|
- The TDD gate: code stories require red, green, and refactor evidence.
|
|
10
10
|
- The adapter compiler for Claude Code, Codex, Antigravity, OpenCode, and Cursor.
|
|
11
11
|
- The safety policy for destructive commands, secrets, production access, and review readiness.
|
|
@@ -13,15 +13,15 @@ Speckit owns the workflow contract for enterprise Agile + TDD development with a
|
|
|
13
13
|
## Speckit Delegates
|
|
14
14
|
|
|
15
15
|
- Implementation to the selected IDE and agent runtime.
|
|
16
|
-
- Product lifecycle
|
|
17
|
-
- Execution orchestration
|
|
16
|
+
- Product lifecycle, story readiness, and quality gates to Speckit-native phases.
|
|
17
|
+
- Execution orchestration to Speckit-native plan/run/test/review flows.
|
|
18
18
|
- Task graph prioritization to beads and Beads Viewer robot commands.
|
|
19
19
|
- Git, tests, CI, and deployment to project-local tooling.
|
|
20
20
|
|
|
21
21
|
## State Model
|
|
22
22
|
|
|
23
23
|
```text
|
|
24
|
-
intake ->
|
|
24
|
+
intake -> session -> shaped -> planned -> context-ready -> synced -> triaged -> tests-red -> running -> tests-green -> refactor -> review-ready -> closed
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
Implementation starts only after a story is spec-ready. Review starts only after test evidence exists.
|
|
@@ -1,7 +1,36 @@
|
|
|
1
1
|
# Project Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.0 - 2026-05-10
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- Added enterprise harness generation with `speckit init --enterprise`.
|
|
8
|
+
- Added deep harness verification with `speckit doctor --deep`.
|
|
9
|
+
- Added linked flow commands: `start`, `context`, `triage`, and `close`.
|
|
10
|
+
- Added quality gates for Speckit-only vocabulary, flow linkage, adapter parity, and robot-safe graph commands.
|
|
11
|
+
|
|
12
|
+
### Validation
|
|
13
|
+
|
|
14
|
+
- `npm run lint` passes.
|
|
15
|
+
- `npm test` passes with 21 tests.
|
|
16
|
+
- `npm pack --dry-run` passes.
|
|
17
|
+
- Full enterprise temp flow passes: `init --enterprise -> start -> quick -> context -> sync -> triage -> close -> doctor --deep`.
|
|
18
|
+
|
|
3
19
|
## 2026-05-10
|
|
4
20
|
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Migrated product vocabulary to Speckit-only workflow language.
|
|
24
|
+
- Added Spec Enterprise Harness planning and quality gates.
|
|
25
|
+
- Removed legacy workflow runtime checks from `speckit doctor`.
|
|
26
|
+
- Added enterprise flow commands for session start, story context, graph triage, and closure.
|
|
27
|
+
|
|
28
|
+
### Quality
|
|
29
|
+
|
|
30
|
+
- Added forbidden vocabulary regression test.
|
|
31
|
+
- Added Spec flow contract tests for TDD linkage, adapter parity, and robot-safe graph commands.
|
|
32
|
+
- Added end-to-end command tests for `start`, `context`, `triage`, and `close`.
|
|
33
|
+
|
|
5
34
|
### Added
|
|
6
35
|
|
|
7
36
|
- Created Speckit TypeScript CLI package.
|
|
@@ -9,6 +38,7 @@
|
|
|
9
38
|
- Added GitHub repository metadata for `trieungoctam/speckit`.
|
|
10
39
|
- Added GitHub Actions CI for lint, test, and package dry-run checks.
|
|
11
40
|
- Added `init`, `doctor`, `shape`, `quick`, `plan`, `next`, `sync`, `run`, and `review` commands.
|
|
41
|
+
- Added `init --enterprise`, `doctor --deep`, `start`, `context`, `triage`, and `close` commands.
|
|
12
42
|
- Added managed-file generation with overwrite protection.
|
|
13
43
|
- Added native adapter generation for Claude Code, Codex, Antigravity, OpenCode, and Cursor.
|
|
14
44
|
- Added Beads Viewer-safe `next` command using robot mode only.
|
|
@@ -21,7 +51,7 @@
|
|
|
21
51
|
- `bin/speckit init --ide all` works in a temporary directory.
|
|
22
52
|
- `npm run build` passes.
|
|
23
53
|
- `npm run lint` passes.
|
|
24
|
-
- `npm test` passes with
|
|
54
|
+
- `npm test` passes with 21 tests.
|
|
25
55
|
- `npm pack --dry-run` passes.
|
|
26
56
|
|
|
27
57
|
### Published
|
|
@@ -12,7 +12,7 @@ Before publishing Speckit:
|
|
|
12
12
|
- [x] Adapter output paths match `docs/adapters.md`.
|
|
13
13
|
- [x] Cursor output uses `.cursor/rules/*.mdc`, not `.cursorrules`.
|
|
14
14
|
- [x] `speckit next` only invokes `bv --robot-*`.
|
|
15
|
-
- [ ] License and attribution review is complete for
|
|
15
|
+
- [ ] License and attribution review is complete for Speckit, Speckit Method, and Beads Viewer inspiration.
|
|
16
16
|
- [x] README quickstart is accurate.
|
|
17
17
|
- [x] No secrets, local credentials, or generated private data are included.
|
|
18
18
|
- [x] Initial code pushed to `git@github.com:trieungoctam/speckit.git`.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Spec Enterprise Harness Plan
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Speckit Enterprise must behave like one coherent Spec system, not a bundle of unrelated prompts.
|
|
6
|
+
|
|
7
|
+
The product vocabulary is Spec-only. External tools may exist underneath, but generated prompts, docs, commands, sessions, context packs, and adapter outputs must speak Speckit terms.
|
|
8
|
+
|
|
9
|
+
## Operating Model
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
idea
|
|
13
|
+
-> spec start
|
|
14
|
+
-> spec shape
|
|
15
|
+
-> spec plan
|
|
16
|
+
-> spec context
|
|
17
|
+
-> graph triage
|
|
18
|
+
-> spec run
|
|
19
|
+
-> spec review
|
|
20
|
+
-> spec close
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Harness Layers
|
|
24
|
+
|
|
25
|
+
| Layer | Responsibility | Required Output |
|
|
26
|
+
| --- | --- | --- |
|
|
27
|
+
| Spec Flow | Phase order and state transitions | `.speckit/flows/*.md` |
|
|
28
|
+
| Spec Prompt | Phase-specific instructions | `.speckit/prompts/**/*.md` |
|
|
29
|
+
| Spec Session | Durable continuity across agents | `.speckit/sessions/<id>/*` |
|
|
30
|
+
| Spec Context | Bounded task context | `.speckit/context/current.md` |
|
|
31
|
+
| Spec Tool | Phase-aware allowed/denied actions | `.speckit/tool-policy.yaml` |
|
|
32
|
+
| Spec Graph | Work queue and priority bridge | `.speckit/graph/*` |
|
|
33
|
+
| IDE Compiler | Native adapter generation | IDE-specific config files |
|
|
34
|
+
|
|
35
|
+
## Command Contract
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
speckit init --enterprise --ide all
|
|
39
|
+
speckit doctor --deep
|
|
40
|
+
speckit start "<idea>"
|
|
41
|
+
speckit shape "<idea>"
|
|
42
|
+
speckit plan "<feature>"
|
|
43
|
+
speckit context <story-or-bead>
|
|
44
|
+
speckit triage
|
|
45
|
+
speckit next
|
|
46
|
+
speckit run <story-or-bead>
|
|
47
|
+
speckit review
|
|
48
|
+
speckit close <story-or-bead>
|
|
49
|
+
speckit sync
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quality Gates
|
|
53
|
+
|
|
54
|
+
- Forbidden legacy vocabulary must not appear in publishable source, docs, tests, prompts, or generated adapter templates.
|
|
55
|
+
- Every implementation story must link to acceptance criteria and TDD evidence.
|
|
56
|
+
- Every run must have a session handoff.
|
|
57
|
+
- Every graph task must trace back to a story or spec artifact.
|
|
58
|
+
- Every review must check AC coverage, TDD evidence, tool policy, and docs impact.
|
|
59
|
+
- All robot task graph commands must use non-interactive flags.
|
|
60
|
+
|
|
61
|
+
## Definition Of Enterprise Ready
|
|
62
|
+
|
|
63
|
+
- `speckit init --enterprise --ide all` creates a complete harness in a temp repo.
|
|
64
|
+
- `speckit doctor --deep --json` returns stable machine-readable status.
|
|
65
|
+
- `speckit start -> context -> run -> review -> close` preserves a single session id.
|
|
66
|
+
- `speckit sync -> triage -> next` preserves story-to-graph traceability.
|
|
67
|
+
- All IDE adapters compile from the same Spec policies.
|
|
68
|
+
- Tests enforce vocabulary, flow links, adapter parity, and robot-safe graph commands.
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Spec Quality Gates
|
|
2
|
+
|
|
3
|
+
## Vocabulary Gate
|
|
4
|
+
|
|
5
|
+
Publishable files must not contain legacy workflow brand names or command prefixes.
|
|
6
|
+
|
|
7
|
+
Allowed:
|
|
8
|
+
|
|
9
|
+
- `Speckit`
|
|
10
|
+
- `Spec`
|
|
11
|
+
- IDE names such as `Claude Code`
|
|
12
|
+
- external graph tool names such as `Beads` and `Beads Viewer`
|
|
13
|
+
|
|
14
|
+
Forbidden in publishable files:
|
|
15
|
+
|
|
16
|
+
- old workflow brand names
|
|
17
|
+
- old slash command prefixes
|
|
18
|
+
- old implementation command names
|
|
19
|
+
|
|
20
|
+
## Flow Link Gate
|
|
21
|
+
|
|
22
|
+
Every phase must link to the next durable artifact.
|
|
23
|
+
|
|
24
|
+
| Phase | Input | Output | Required Link |
|
|
25
|
+
| --- | --- | --- | --- |
|
|
26
|
+
| start | idea | session | session id |
|
|
27
|
+
| shape | session | spec brief | session -> spec |
|
|
28
|
+
| plan | spec brief | PRD / architecture / story | spec -> plan |
|
|
29
|
+
| context | story | context pack | story -> context |
|
|
30
|
+
| sync | story | graph task | story -> task id |
|
|
31
|
+
| run | task/story | TDD evidence | task -> evidence |
|
|
32
|
+
| review | diff + evidence | review checklist | evidence -> review |
|
|
33
|
+
| close | review | changelog / graph close | review -> close |
|
|
34
|
+
|
|
35
|
+
## Tool Gate
|
|
36
|
+
|
|
37
|
+
Tool permissions are phase-specific.
|
|
38
|
+
|
|
39
|
+
- Shape and plan may inspect files but should not edit implementation code.
|
|
40
|
+
- Run may edit code but must record TDD evidence.
|
|
41
|
+
- Review should inspect and test; it should not implement.
|
|
42
|
+
- Graph commands must never launch an interactive TUI.
|
|
43
|
+
|
|
44
|
+
## Adapter Parity Gate
|
|
45
|
+
|
|
46
|
+
All supported IDEs must receive the same Speckit policy:
|
|
47
|
+
|
|
48
|
+
- Spec policy
|
|
49
|
+
- TDD policy
|
|
50
|
+
- Enterprise safety policy
|
|
51
|
+
- Session/context instructions
|
|
52
|
+
- Graph command safety
|
|
53
|
+
|
|
54
|
+
## Release Gate
|
|
55
|
+
|
|
56
|
+
Before release:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm run lint
|
|
60
|
+
npm test
|
|
61
|
+
npm pack --dry-run
|
|
62
|
+
speckit doctor --json
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
For enterprise releases:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
speckit init --enterprise --ide all
|
|
69
|
+
speckit doctor --deep --json
|
|
70
|
+
```
|
|
@@ -24,4 +24,4 @@ bin/speckit
|
|
|
24
24
|
user intent -> CLI command -> markdown/json artifact -> IDE adapter -> agent workflow
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
The CLI does not depend on
|
|
27
|
+
The CLI does not depend on external workflow runtimes. Beads and Beads Viewer are optional integrations discovered at runtime.
|