@trieungoctam/speckit 0.1.0 → 0.2.2

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.
Files changed (40) hide show
  1. package/README.md +16 -1
  2. package/dist/adapters/antigravity-adapter.js +5 -5
  3. package/dist/adapters/claude-code-adapter.js +8 -5
  4. package/dist/adapters/codex-adapter.js +5 -3
  5. package/dist/adapters/cursor-adapter.js +6 -3
  6. package/dist/adapters/opencode-adapter.js +1 -0
  7. package/dist/adapters/tool-checks.js +0 -1
  8. package/dist/cli.js +24 -2
  9. package/dist/commands/close.d.ts +6 -0
  10. package/dist/commands/close.js +34 -0
  11. package/dist/commands/context.d.ts +6 -0
  12. package/dist/commands/context.js +87 -0
  13. package/dist/commands/doctor.d.ts +1 -0
  14. package/dist/commands/doctor.js +29 -1
  15. package/dist/commands/init.d.ts +1 -0
  16. package/dist/commands/init.js +5 -3
  17. package/dist/commands/plan.js +19 -2
  18. package/dist/commands/quick.js +20 -2
  19. package/dist/commands/ready.d.ts +7 -0
  20. package/dist/commands/ready.js +20 -0
  21. package/dist/commands/run.js +19 -24
  22. package/dist/commands/start.d.ts +6 -0
  23. package/dist/commands/start.js +47 -0
  24. package/dist/commands/sync.js +2 -8
  25. package/dist/commands/triage.d.ts +6 -0
  26. package/dist/commands/triage.js +33 -0
  27. package/dist/core/readiness.d.ts +13 -0
  28. package/dist/core/readiness.js +120 -0
  29. package/dist/core/scaffold.d.ts +1 -0
  30. package/dist/core/scaffold.js +107 -2
  31. package/dist/core/story.d.ts +13 -0
  32. package/dist/core/story.js +67 -0
  33. package/docs/development-roadmap.md +8 -7
  34. package/docs/product-contract.md +5 -5
  35. package/docs/project-changelog.md +67 -1
  36. package/docs/release-checklist.md +2 -2
  37. package/docs/spec-enterprise-harness-plan.md +68 -0
  38. package/docs/spec-quality-gates.md +70 -0
  39. package/docs/system-architecture.md +1 -1
  40. package/package.json +1 -1
package/README.md CHANGED
@@ -2,13 +2,17 @@
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
- It is inspired by the operating patterns in ClaudeKit, BMad Method, and Beads Viewer, but it does not fork their runtime. Speckit owns the workflow contract and generates adapters for the tools you already use.
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"
13
+ npx @trieungoctam/speckit@latest context .speckit/stories/<story>.md
14
+ npx @trieungoctam/speckit@latest sync
15
+ npx @trieungoctam/speckit@latest ready .speckit/stories/<story>.md
12
16
  npx @trieungoctam/speckit@latest review
13
17
  ```
14
18
 
@@ -24,9 +28,13 @@ speckit doctor
24
28
 
25
29
  ```text
26
30
  intent
31
+ -> start session
27
32
  -> shape
28
33
  -> plan
34
+ -> context
29
35
  -> story with acceptance criteria
36
+ -> sync / triage
37
+ -> readiness gate
30
38
  -> red test evidence
31
39
  -> minimal implementation
32
40
  -> green test evidence
@@ -41,15 +49,22 @@ For implementation stories, red-green-refactor evidence is mandatory. A story is
41
49
  | Command | Purpose |
42
50
  | --- | --- |
43
51
  | `speckit init` | Create `.speckit/` core rules and all IDE adapters. |
52
+ | `speckit init --enterprise` | Add flow, tool policy, and prompt harness files. |
44
53
  | `speckit init --ide <name>` | Generate one adapter: `claude-code`, `codex`, `antigravity`, `opencode`, or `cursor`. |
45
54
  | `speckit doctor` | Report required tools, optional integrations, test commands, and adapter readiness. |
55
+ | `speckit doctor --deep` | Verify core enterprise harness files. |
56
+ | `speckit start "<idea>"` | Create a durable session handoff and current context. |
46
57
  | `speckit shape "<intent>"` | Create a short spec contract. |
58
+ | `speckit context <story>` | Build the current implementation context from a story. |
47
59
  | `speckit quick "<intent>"` | Create one story plus matching TDD evidence file. |
48
60
  | `speckit plan "<intent>"` | Create PRD, architecture, story, and evidence skeletons. |
61
+ | `speckit triage` | Summarize synced story state without interactive graph commands. |
49
62
  | `speckit next` | Safely wraps `bv --robot-next --format json`. |
50
63
  | `speckit sync` | Export Speckit stories as beads-compatible JSONL metadata. |
64
+ | `speckit ready <story>` | Validate story status, context, evidence, graph sync, and safety policy before implementation. |
51
65
  | `speckit run <story>` | Print the TDD execution handoff for a story. |
52
66
  | `speckit review` | Print the review checklist and current diff summary. |
67
+ | `speckit close <story>` | Create a closure checklist linked to the story and sync step. |
53
68
 
54
69
  ## Supported IDEs
55
70
 
@@ -12,12 +12,12 @@ export const antigravityAdapter = {
12
12
  ],
13
13
  render() {
14
14
  return [
15
- rule("agile", "Follow Speckit Agile: shape intent, create stories with ACs, preserve dependencies, and emit artifacts for review."),
16
- rule("tdd", "For code changes, use TDD: record red evidence, green evidence, and refactor validation."),
15
+ rule("agile", "Follow Speckit Agile: shape intent, read .speckit/context/current.md, create stories with ACs, preserve session handoff, and emit artifacts for review."),
16
+ rule("tdd", "For code changes, use TDD: confirm acceptance criteria, use red-green-refactor, 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, and dependencies."),
19
- workflow("tdd-run", "Run a story with TDD. Emit artifact sections: Test Intent, Red, Green, Refactor."),
20
- workflow("review", "Review the produced artifacts and code diff. Flag AC gaps, TDD gaps, security issues, and docs needs."),
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 .speckit/context/current.md and .speckit/context/subagent-handoff.md. 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, and session handoff gaps."),
21
21
  ];
22
22
  },
23
23
  };
@@ -1,5 +1,5 @@
1
1
  import { json, markdown } from "../core/managed-files.js";
2
- const skillIntro = `Follow Speckit: Agile story flow plus mandatory TDD evidence. Use project-local context first.`;
2
+ const skillIntro = `Follow Speckit: Agile story flow plus mandatory TDD evidence. Read .speckit/context/current.md first, preserve session handoff, 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",
@@ -21,7 +21,10 @@ Use Speckit for Agile + TDD work.
21
21
  - Start from \`.speckit/rules/agile-policy.md\`.
22
22
  - For implementation, follow \`.speckit/rules/tdd-policy.md\`.
23
23
  - For safety, follow \`.speckit/rules/enterprise-safety.md\`.
24
- - Prefer \`speckit quick\`, \`speckit plan\`, \`speckit run\`, and \`speckit review\` over ad hoc prompts.
24
+ - Prefer \`speckit start\`, \`speckit context\`, \`speckit sync\`, \`speckit triage\`, \`speckit run\`, and \`speckit review\` over ad hoc prompts.
25
+ - Run \`speckit ready <story>\` before implementation; story status must be \`ready-for-dev\` and context status must be \`fresh\`.
26
+ - For code stories, confirm acceptance criteria and record red-green-refactor evidence before handoff.
27
+ - Never run bare \`bv\`; use robot flags such as \`bv --robot-next --format json\`.
25
28
  `),
26
29
  },
27
30
  {
@@ -33,9 +36,9 @@ Use Speckit for Agile + TDD work.
33
36
  includeCoAuthoredBy: false,
34
37
  }),
35
38
  },
36
- skill("speckit-plan", "Create or update a Speckit Agile plan.", "Read `.speckit/workflows/shape.md`, then create PRD, architecture, and story artifacts with acceptance criteria."),
37
- skill("speckit-tdd", "Execute a Speckit story with TDD.", "Read `.speckit/workflows/tdd-run.md`. Do not implement before test intent and red evidence are recorded."),
38
- skill("speckit-review", "Review a Speckit change.", "Read `.speckit/workflows/review.md`. Prioritize bugs, TDD evidence gaps, security, and missing docs."),
39
+ skill("speckit-plan", "Create or update a Speckit Agile plan.", "Read `.speckit/workflows/shape.md`, preserve the session id, then create PRD, architecture, and story artifacts with acceptance criteria."),
40
+ skill("speckit-tdd", "Execute a Speckit story with TDD.", "Read `.speckit/context/current.md`, `.speckit/context/subagent-handoff.md`, and `.speckit/workflows/tdd-run.md`. Do not implement before `speckit ready <story>` passes, test intent is clear, and red evidence is recorded."),
41
+ skill("speckit-review", "Review a Speckit change.", "Read `.speckit/workflows/review.md`. Prioritize AC coverage, TDD evidence gaps, security, docs impact, and graph sync status."),
39
42
  ];
40
43
  },
41
44
  };
@@ -19,6 +19,8 @@ This repository uses Speckit: Agile + TDD for agentic development.
19
19
 
20
20
  Rules:
21
21
  - Shape intent before implementation.
22
+ - Read \`.speckit/context/current.md\` before running code changes.
23
+ - Run \`speckit ready <story>\` before implementation; story status must be \`ready-for-dev\` and context status must be \`fresh\`.
22
24
  - For code stories, write test intent and capture red/green/refactor evidence.
23
25
  - Never call bare \`bv\`; use \`bv --robot-*\`.
24
26
  - Do not weaken approval or sandbox settings.
@@ -37,9 +39,9 @@ web_search = true
37
39
  [features]
38
40
  child_agents_md = true`),
39
41
  },
40
- prompt("plan", "Create a Speckit plan from the user intent. Include PRD, architecture, stories, ACs, TDD checklist, and risks."),
41
- prompt("tdd-run", "Execute the selected Speckit story using red-green-refactor. Record command evidence before marking done."),
42
- prompt("review", "Review the current diff against Speckit ACs, TDD evidence, security, and docs impact."),
42
+ prompt("plan", "Create a Speckit plan from the user intent. Preserve session context, include PRD, architecture, stories, ACs, TDD checklist, risks, and graph sync notes."),
43
+ prompt("tdd-run", "Execute the selected Speckit story using .speckit/context/current.md, .speckit/context/subagent-handoff.md, and red-green-refactor. Require speckit ready <story>, confirm ACs, record command evidence, and use only robot-safe graph commands."),
44
+ prompt("review", "Review the current diff against Speckit ACs, TDD evidence, security, docs impact, session handoff, and graph sync status."),
43
45
  ];
44
46
  },
45
47
  };
@@ -12,9 +12,9 @@ export const cursorAdapter = {
12
12
  ],
13
13
  render() {
14
14
  return [
15
- rule("agile", "alwaysApply: true", "Use Speckit Agile flow. Shape intent, create stories with ACs, and keep work scoped."),
16
- rule("tdd", "description: Apply when implementing or modifying code", "Use red-green-refactor. Record TDD evidence before review-ready."),
17
- rule("review", "description: Apply when reviewing code or preparing a PR", "Review AC coverage, TDD evidence, security, and docs impact."),
15
+ rule("agile", "alwaysApply: true", "Use Speckit Agile flow. Read .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, 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, and graph sync status."),
18
18
  rule("enterprise-safety", "alwaysApply: true", "Do not expose secrets. Ask before destructive commands, deployment, or production changes."),
19
19
  {
20
20
  path: ".cursor/mcp.json",
@@ -30,6 +30,9 @@ Use Speckit for Agile + TDD work. Cursor-specific rules live in \`.cursor/rules/
30
30
 
31
31
  - Follow \`.speckit/rules/agile-policy.md\`.
32
32
  - Follow \`.speckit/rules/tdd-policy.md\` for code stories.
33
+ - Read \`.speckit/context/current.md\` before implementation work.
34
+ - Read \`.speckit/context/subagent-handoff.md\` before implementation work.
35
+ - Run \`speckit ready <story>\` before code changes.
33
36
  - Never run bare \`bv\`; use robot commands only.
34
37
  `),
35
38
  },
@@ -53,6 +53,7 @@ permission: ${JSON.stringify(permission)}
53
53
  # speckit-${name}
54
54
 
55
55
  Follow \`.speckit/rules/agile-policy.md\`, \`.speckit/rules/tdd-policy.md\`, and \`.speckit/rules/enterprise-safety.md\`.
56
+ Read \`.speckit/context/current.md\` and \`.speckit/context/subagent-handoff.md\` before implementation work, require \`speckit ready <story>\`, confirm acceptance criteria, preserve session handoff, record red-green-refactor evidence, and use only robot-safe graph commands.
56
57
  `),
57
58
  };
58
59
  }
@@ -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,17 @@
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";
12
+ import { readyCommand } from "./commands/ready.js";
9
13
  import { reviewCommand } from "./commands/review.js";
14
+ import { closeCommand } from "./commands/close.js";
10
15
  export async function main(argv = process.argv.slice(2), root = process.cwd()) {
11
16
  const parsed = parseArgs(argv);
12
17
  try {
@@ -16,23 +21,34 @@ export async function main(argv = process.argv.slice(2), root = process.cwd()) {
16
21
  root,
17
22
  ide: value(parsed, "ide"),
18
23
  force: has(parsed, "force"),
24
+ enterprise: has(parsed, "enterprise"),
19
25
  });
20
26
  case "doctor":
21
- return doctorCommand({ root, json: has(parsed, "json") });
27
+ return doctorCommand({ root, json: has(parsed, "json"), deep: has(parsed, "deep") });
28
+ case "start":
29
+ return startCommand({ root, intent: requiredIntent(parsed) });
22
30
  case "shape":
23
31
  return shapeCommand({ root, intent: requiredIntent(parsed) });
32
+ case "context":
33
+ return contextCommand({ root, target: requiredIntent(parsed) });
24
34
  case "quick":
25
35
  return quickCommand({ root, intent: requiredIntent(parsed) });
26
36
  case "plan":
27
37
  return planCommand({ root, intent: requiredIntent(parsed) });
38
+ case "triage":
39
+ return triageCommand({ root, json: has(parsed, "json") });
28
40
  case "next":
29
41
  return nextCommand();
30
42
  case "sync":
31
43
  return syncCommand({ root });
44
+ case "ready":
45
+ return readyCommand({ root, target: requiredIntent(parsed), json: has(parsed, "json") });
32
46
  case "run":
33
47
  return runCommand({ root, target: requiredIntent(parsed) });
34
48
  case "review":
35
49
  return reviewCommand({ root });
50
+ case "close":
51
+ return closeCommand({ root, target: requiredIntent(parsed) });
36
52
  case "help":
37
53
  case "":
38
54
  printHelp();
@@ -88,14 +104,20 @@ function printHelp() {
88
104
 
89
105
  Usage:
90
106
  speckit init [--ide all|claude-code|codex|antigravity|opencode|cursor] [--force]
91
- speckit doctor [--json]
107
+ speckit init --enterprise [--ide all] [--force]
108
+ speckit doctor [--json] [--deep]
109
+ speckit start "<idea>"
92
110
  speckit shape "<intent>"
111
+ speckit context <story-path-or-id>
93
112
  speckit quick "<intent>"
94
113
  speckit plan "<intent>"
114
+ speckit triage [--json]
95
115
  speckit next
96
116
  speckit sync
117
+ speckit ready <story-path-or-id> [--json]
97
118
  speckit run <story-path-or-id>
98
119
  speckit review
120
+ speckit close <story-path-or-id>
99
121
  `);
100
122
  }
101
123
  if (import.meta.url === `file://${process.argv[1]}`) {
@@ -0,0 +1,6 @@
1
+ export type CloseOptions = {
2
+ root: string;
3
+ target: string;
4
+ stdout?: Pick<typeof console, "log" | "error">;
5
+ };
6
+ export declare function closeCommand(options: CloseOptions): Promise<number>;
@@ -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,6 @@
1
+ export type ContextOptions = {
2
+ root: string;
3
+ target: string;
4
+ stdout?: Pick<typeof console, "log" | "error">;
5
+ };
6
+ export declare function contextCommand(options: ContextOptions): Promise<number>;
@@ -0,0 +1,87 @@
1
+ import { markdown, writeManagedFiles } from "../core/managed-files.js";
2
+ import { extractEvidenceReference, extractSection, 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
+ const handoffPath = ".speckit/context/subagent-handoff.md";
12
+ const acceptanceCriteria = extractSection(story.content, "Acceptance Criteria") ?? "- Not defined";
13
+ const evidenceReference = story.evidencePath ?? extractEvidenceReference(story.content);
14
+ await writeManagedFiles(options.root, [
15
+ {
16
+ path: contextPath,
17
+ content: markdown(`---
18
+ status: fresh
19
+ story: ${story.path}
20
+ evidence: ${evidenceReference ?? "missing"}
21
+ ---
22
+
23
+ # Current Spec Context
24
+
25
+ ## Story
26
+ ${story.title}
27
+
28
+ ## Story Path
29
+ \`${story.path}\`
30
+
31
+ ## Story Status
32
+ ${story.status ?? "missing"}
33
+
34
+ ## Acceptance Criteria
35
+ ${acceptanceCriteria}
36
+
37
+ ## TDD Evidence
38
+ ${evidenceReference ? `\`${evidenceReference}\`` : "- Create or update matching `.speckit/evidence/*tdd-evidence.md`"}
39
+
40
+ ## Spec Anti-Mistake Checklist
41
+ - Reuse existing project patterns before adding new files.
42
+ - Verify file locations before editing.
43
+ - Do not introduce new libraries without explicit need.
44
+ - Preserve existing behavior unless an acceptance criterion requires change.
45
+ - Check prior related stories or changelog before repeating work.
46
+
47
+ ## Next Command
48
+ \`speckit ready ${story.id}\`
49
+ \`speckit run ${story.id}\`
50
+ `),
51
+ },
52
+ {
53
+ path: handoffPath,
54
+ content: markdown(`# Spec Subagent Handoff
55
+
56
+ ## Task
57
+ Implement the story in \`${story.path}\`.
58
+
59
+ ## Files To Read
60
+ - \`.speckit/context/current.md\`
61
+ - \`${story.path}\`
62
+ ${evidenceReference ? `- \`${evidenceReference}\`` : "- Matching TDD evidence file"}
63
+ - \`.speckit/tool-policy.yaml\`
64
+
65
+ ## Acceptance Criteria
66
+ ${acceptanceCriteria}
67
+
68
+ ## Constraints
69
+ - Confirm story status is \`ready-for-dev\` before code changes.
70
+ - Record red-green-refactor evidence.
71
+ - Use only robot-safe graph commands.
72
+ - Stop before destructive commands, production changes, or secret access.
73
+
74
+ ## Completion Signal
75
+ - All acceptance criteria satisfied.
76
+ - TDD evidence updated.
77
+ - \`speckit review\` run before handoff.
78
+
79
+ ## Work Context
80
+ ${options.root}
81
+ `),
82
+ },
83
+ ], true);
84
+ stdout.log(contextPath);
85
+ stdout.log(handoffPath);
86
+ return 0;
87
+ }
@@ -1,6 +1,7 @@
1
1
  export type DoctorOptions = {
2
2
  root: string;
3
3
  json?: boolean;
4
+ deep?: boolean;
4
5
  stdout?: Pick<typeof console, "log">;
5
6
  };
6
7
  export declare function doctorCommand(options: DoctorOptions): Promise<number>;
@@ -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.filter((tool) => tool.required && !tool.available).length === 0 ? "ok" : "needs-attention",
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) {
@@ -2,6 +2,7 @@ export type InitOptions = {
2
2
  root: string;
3
3
  ide?: string;
4
4
  force?: boolean;
5
+ enterprise?: boolean;
5
6
  stdout?: Pick<typeof console, "log">;
6
7
  };
7
8
  export declare function initCommand(options: InitOptions): Promise<number>;
@@ -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, [...coreFiles(), ...adapterFiles], options.force ?? false);
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
- stdout.log(`Speckit initialized: ${created} created, ${updated} updated, ${skipped.length} skipped.`);
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
  }
@@ -36,7 +36,13 @@ export async function planCommand(options) {
36
36
  },
37
37
  {
38
38
  path: `${dir}/story.md`,
39
- content: markdown(`# Story: ${options.intent}
39
+ content: markdown(`---
40
+ status: draft
41
+ evidence: ${dir}/tdd-evidence.md
42
+ context: pending
43
+ ---
44
+
45
+ # Story: ${options.intent}
40
46
 
41
47
  ## Acceptance Criteria
42
48
  - Given ...
@@ -47,11 +53,22 @@ export async function planCommand(options) {
47
53
  \`${dir}/tdd-evidence.md\`
48
54
 
49
55
  ## Implementation Notes
56
+
57
+ ## Spec Anti-Mistake Checklist
58
+ - Reuse existing project patterns before adding new files.
59
+ - Verify file locations before editing.
60
+ - Do not introduce new libraries without explicit need.
61
+ - Preserve existing behavior unless an acceptance criterion requires change.
50
62
  `),
51
63
  },
52
64
  {
53
65
  path: `${dir}/tdd-evidence.md`,
54
- content: markdown(`# TDD Evidence: ${options.intent}
66
+ content: markdown(`---
67
+ status: missing
68
+ story: ${dir}/story.md
69
+ ---
70
+
71
+ # TDD Evidence: ${options.intent}
55
72
 
56
73
  ## Red
57
74
 
@@ -11,7 +11,13 @@ export async function quickCommand(options) {
11
11
  await writeManagedFiles(options.root, [
12
12
  {
13
13
  path: storyPath,
14
- content: markdown(`# Story: ${options.intent}
14
+ content: markdown(`---
15
+ status: ready-for-dev
16
+ evidence: ${evidencePath}
17
+ context: pending
18
+ ---
19
+
20
+ # Story: ${options.intent}
15
21
 
16
22
  ## Intent
17
23
  ${options.intent}
@@ -29,11 +35,23 @@ ${options.intent}
29
35
 
30
36
  ## Suggested Test Command
31
37
  \`${testCommand}\`
38
+
39
+ ## Spec Anti-Mistake Checklist
40
+ - Reuse existing project patterns before adding new files.
41
+ - Verify file locations before editing.
42
+ - Do not introduce new libraries without explicit need.
43
+ - Preserve existing behavior unless an acceptance criterion requires change.
44
+ - Update docs only when behavior or workflow changes.
32
45
  `),
33
46
  },
34
47
  {
35
48
  path: evidencePath,
36
- content: markdown(`# TDD Evidence: ${options.intent}
49
+ content: markdown(`---
50
+ status: missing
51
+ story: ${storyPath}
52
+ ---
53
+
54
+ # TDD Evidence: ${options.intent}
37
55
 
38
56
  ## Test Intent
39
57
 
@@ -0,0 +1,7 @@
1
+ export type ReadyOptions = {
2
+ root: string;
3
+ target: string;
4
+ json?: boolean;
5
+ stdout?: Pick<typeof console, "log" | "error">;
6
+ };
7
+ export declare function readyCommand(options: ReadyOptions): Promise<number>;
@@ -0,0 +1,20 @@
1
+ import { evaluateReadiness } from "../core/readiness.js";
2
+ export async function readyCommand(options) {
3
+ const stdout = options.stdout ?? console;
4
+ const report = await evaluateReadiness(options.root, options.target);
5
+ if (options.json) {
6
+ stdout.log(JSON.stringify(report, null, 2));
7
+ return report.status === "ready" ? 0 : 1;
8
+ }
9
+ stdout.log(`# Speckit Readiness: ${report.status}`);
10
+ if (report.story) {
11
+ stdout.log(`Story: ${report.story.path}`);
12
+ }
13
+ for (const check of report.checks) {
14
+ stdout.log(`- ${check.ok ? "ok" : "blocked"} ${check.name}: ${check.detail}`);
15
+ }
16
+ if (report.status !== "ready") {
17
+ stdout.error("Run the suggested setup commands before `speckit run`.");
18
+ }
19
+ return report.status === "ready" ? 0 : 1;
20
+ }