@trieungoctam/speckit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +71 -0
  2. package/bin/speckit +4 -0
  3. package/dist/adapters/antigravity-adapter.d.ts +2 -0
  4. package/dist/adapters/antigravity-adapter.js +41 -0
  5. package/dist/adapters/claude-code-adapter.d.ts +2 -0
  6. package/dist/adapters/claude-code-adapter.js +57 -0
  7. package/dist/adapters/codex-adapter.d.ts +2 -0
  8. package/dist/adapters/codex-adapter.js +54 -0
  9. package/dist/adapters/cursor-adapter.d.ts +2 -0
  10. package/dist/adapters/cursor-adapter.js +51 -0
  11. package/dist/adapters/ide-adapter.d.ts +7 -0
  12. package/dist/adapters/ide-adapter.js +1 -0
  13. package/dist/adapters/opencode-adapter.d.ts +2 -0
  14. package/dist/adapters/opencode-adapter.js +58 -0
  15. package/dist/adapters/tool-checks.d.ts +8 -0
  16. package/dist/adapters/tool-checks.js +28 -0
  17. package/dist/cli.d.ts +1 -0
  18. package/dist/cli.js +104 -0
  19. package/dist/commands/doctor.d.ts +6 -0
  20. package/dist/commands/doctor.js +50 -0
  21. package/dist/commands/init.d.ts +7 -0
  22. package/dist/commands/init.js +17 -0
  23. package/dist/commands/next.d.ts +4 -0
  24. package/dist/commands/next.js +17 -0
  25. package/dist/commands/plan.d.ts +6 -0
  26. package/dist/commands/plan.js +67 -0
  27. package/dist/commands/quick.d.ts +6 -0
  28. package/dist/commands/quick.js +57 -0
  29. package/dist/commands/review.d.ts +5 -0
  30. package/dist/commands/review.js +23 -0
  31. package/dist/commands/run.d.ts +6 -0
  32. package/dist/commands/run.js +42 -0
  33. package/dist/commands/shape.d.ts +6 -0
  34. package/dist/commands/shape.js +33 -0
  35. package/dist/commands/sync.d.ts +5 -0
  36. package/dist/commands/sync.js +54 -0
  37. package/dist/config/adapter-registry.d.ts +5 -0
  38. package/dist/config/adapter-registry.js +26 -0
  39. package/dist/core/managed-files.d.ts +14 -0
  40. package/dist/core/managed-files.js +46 -0
  41. package/dist/core/policy.d.ts +6 -0
  42. package/dist/core/policy.js +65 -0
  43. package/dist/core/scaffold.d.ts +2 -0
  44. package/dist/core/scaffold.js +71 -0
  45. package/dist/core/slug.d.ts +2 -0
  46. package/dist/core/slug.js +21 -0
  47. package/dist/core/test-detection.d.ts +7 -0
  48. package/dist/core/test-detection.js +27 -0
  49. package/docs/adapters.md +27 -0
  50. package/docs/code-standards.md +9 -0
  51. package/docs/development-roadmap.md +30 -0
  52. package/docs/enterprise-rollout.md +27 -0
  53. package/docs/product-contract.md +27 -0
  54. package/docs/project-changelog.md +33 -0
  55. package/docs/release-checklist.md +20 -0
  56. package/docs/system-architecture.md +27 -0
  57. package/docs/workflow-model.md +49 -0
  58. package/package.json +51 -0
package/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # Speckit
2
+
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
+
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.
6
+
7
+ ## Quickstart
8
+
9
+ ```bash
10
+ npx @trieungoctam/speckit@latest init --ide all
11
+ npx @trieungoctam/speckit@latest quick "Add checkout validation"
12
+ npx @trieungoctam/speckit@latest review
13
+ ```
14
+
15
+ Or install globally:
16
+
17
+ ```bash
18
+ npm i -g @trieungoctam/speckit
19
+ speckit init --ide cursor
20
+ speckit doctor
21
+ ```
22
+
23
+ ## Core Flow
24
+
25
+ ```text
26
+ intent
27
+ -> shape
28
+ -> plan
29
+ -> story with acceptance criteria
30
+ -> red test evidence
31
+ -> minimal implementation
32
+ -> green test evidence
33
+ -> refactor validation
34
+ -> review
35
+ ```
36
+
37
+ For implementation stories, red-green-refactor evidence is mandatory. A story is not review-ready until the evidence file records test intent, red result, green result, and refactor validation.
38
+
39
+ ## Commands
40
+
41
+ | Command | Purpose |
42
+ | --- | --- |
43
+ | `speckit init` | Create `.speckit/` core rules and all IDE adapters. |
44
+ | `speckit init --ide <name>` | Generate one adapter: `claude-code`, `codex`, `antigravity`, `opencode`, or `cursor`. |
45
+ | `speckit doctor` | Report required tools, optional integrations, test commands, and adapter readiness. |
46
+ | `speckit shape "<intent>"` | Create a short spec contract. |
47
+ | `speckit quick "<intent>"` | Create one story plus matching TDD evidence file. |
48
+ | `speckit plan "<intent>"` | Create PRD, architecture, story, and evidence skeletons. |
49
+ | `speckit next` | Safely wraps `bv --robot-next --format json`. |
50
+ | `speckit sync` | Export Speckit stories as beads-compatible JSONL metadata. |
51
+ | `speckit run <story>` | Print the TDD execution handoff for a story. |
52
+ | `speckit review` | Print the review checklist and current diff summary. |
53
+
54
+ ## Supported IDEs
55
+
56
+ Speckit generates native instruction/config files for:
57
+
58
+ - Claude Code
59
+ - Codex
60
+ - Antigravity
61
+ - OpenCode
62
+ - Cursor
63
+
64
+ See `docs/adapters.md` for exact output paths.
65
+
66
+ ## Validation
67
+
68
+ ```bash
69
+ npm run build
70
+ npm test
71
+ ```
package/bin/speckit ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { main } from "../dist/cli.js";
3
+
4
+ process.exitCode = await main();
@@ -0,0 +1,2 @@
1
+ import { IdeAdapter } from "./ide-adapter.js";
2
+ export declare const antigravityAdapter: IdeAdapter;
@@ -0,0 +1,41 @@
1
+ import { markdown } from "../core/managed-files.js";
2
+ export const antigravityAdapter = {
3
+ name: "antigravity",
4
+ displayName: "Antigravity",
5
+ outputPaths: [
6
+ ".agents/rules/speckit-agile.md",
7
+ ".agents/rules/speckit-tdd.md",
8
+ ".agents/rules/speckit-enterprise-safety.md",
9
+ ".agents/workflows/speckit-plan.md",
10
+ ".agents/workflows/speckit-tdd-run.md",
11
+ ".agents/workflows/speckit-review.md",
12
+ ],
13
+ render() {
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."),
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."),
21
+ ];
22
+ },
23
+ };
24
+ function rule(name, body) {
25
+ return {
26
+ path: `.agents/rules/speckit-${name}.md`,
27
+ content: markdown(`# Speckit ${name}
28
+
29
+ ${body}
30
+ `),
31
+ };
32
+ }
33
+ function workflow(name, body) {
34
+ return {
35
+ path: `.agents/workflows/speckit-${name}.md`,
36
+ content: markdown(`# /speckit-${name}
37
+
38
+ ${body}
39
+ `),
40
+ };
41
+ }
@@ -0,0 +1,2 @@
1
+ import { IdeAdapter } from "./ide-adapter.js";
2
+ export declare const claudeCodeAdapter: IdeAdapter;
@@ -0,0 +1,57 @@
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.`;
3
+ export const claudeCodeAdapter = {
4
+ name: "claude-code",
5
+ displayName: "Claude Code",
6
+ outputPaths: [
7
+ "CLAUDE.md",
8
+ ".claude/settings.json",
9
+ ".claude/skills/speckit-plan/SKILL.md",
10
+ ".claude/skills/speckit-tdd/SKILL.md",
11
+ ".claude/skills/speckit-review/SKILL.md",
12
+ ],
13
+ render() {
14
+ return [
15
+ {
16
+ path: "CLAUDE.md",
17
+ content: markdown(`# Speckit Project Instructions
18
+
19
+ Use Speckit for Agile + TDD work.
20
+
21
+ - Start from \`.speckit/rules/agile-policy.md\`.
22
+ - For implementation, follow \`.speckit/rules/tdd-policy.md\`.
23
+ - For safety, follow \`.speckit/rules/enterprise-safety.md\`.
24
+ - Prefer \`speckit quick\`, \`speckit plan\`, \`speckit run\`, and \`speckit review\` over ad hoc prompts.
25
+ `),
26
+ },
27
+ {
28
+ path: ".claude/settings.json",
29
+ content: json({
30
+ permissions: {
31
+ defaultMode: "ask",
32
+ },
33
+ includeCoAuthoredBy: false,
34
+ }),
35
+ },
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
+ ];
40
+ },
41
+ };
42
+ function skill(name, description, body) {
43
+ return {
44
+ path: `.claude/skills/${name}/SKILL.md`,
45
+ content: markdown(`---
46
+ name: ${name}
47
+ description: "${description}"
48
+ ---
49
+
50
+ # ${name}
51
+
52
+ ${skillIntro}
53
+
54
+ ${body}
55
+ `),
56
+ };
57
+ }
@@ -0,0 +1,2 @@
1
+ import { IdeAdapter } from "./ide-adapter.js";
2
+ export declare const codexAdapter: IdeAdapter;
@@ -0,0 +1,54 @@
1
+ import { markdown, text } from "../core/managed-files.js";
2
+ export const codexAdapter = {
3
+ name: "codex",
4
+ displayName: "Codex",
5
+ outputPaths: [
6
+ "AGENTS.md",
7
+ ".codex/config.toml",
8
+ ".speckit/codex-prompts/plan.md",
9
+ ".speckit/codex-prompts/tdd-run.md",
10
+ ".speckit/codex-prompts/review.md",
11
+ ],
12
+ render() {
13
+ return [
14
+ {
15
+ path: "AGENTS.md",
16
+ content: markdown(`# Speckit Agent Instructions
17
+
18
+ This repository uses Speckit: Agile + TDD for agentic development.
19
+
20
+ Rules:
21
+ - Shape intent before implementation.
22
+ - For code stories, write test intent and capture red/green/refactor evidence.
23
+ - Never call bare \`bv\`; use \`bv --robot-*\`.
24
+ - Do not weaken approval or sandbox settings.
25
+ - Keep changes scoped to the story and update docs when behavior changes.
26
+ `),
27
+ },
28
+ {
29
+ path: ".codex/config.toml",
30
+ content: text(`model = "gpt-5.4"
31
+ approval_policy = "on-request"
32
+ sandbox_mode = "workspace-write"
33
+
34
+ [tools]
35
+ web_search = true
36
+
37
+ [features]
38
+ child_agents_md = true`),
39
+ },
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."),
43
+ ];
44
+ },
45
+ };
46
+ function prompt(name, body) {
47
+ return {
48
+ path: `.speckit/codex-prompts/${name}.md`,
49
+ content: markdown(`# Codex Prompt: ${name}
50
+
51
+ ${body}
52
+ `),
53
+ };
54
+ }
@@ -0,0 +1,2 @@
1
+ import { IdeAdapter } from "./ide-adapter.js";
2
+ export declare const cursorAdapter: IdeAdapter;
@@ -0,0 +1,51 @@
1
+ import { json, markdown } from "../core/managed-files.js";
2
+ export const cursorAdapter = {
3
+ name: "cursor",
4
+ displayName: "Cursor",
5
+ outputPaths: [
6
+ ".cursor/rules/speckit-agile.mdc",
7
+ ".cursor/rules/speckit-tdd.mdc",
8
+ ".cursor/rules/speckit-review.mdc",
9
+ ".cursor/rules/speckit-enterprise-safety.mdc",
10
+ ".cursor/mcp.json",
11
+ "AGENTS.md",
12
+ ],
13
+ render() {
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."),
18
+ rule("enterprise-safety", "alwaysApply: true", "Do not expose secrets. Ask before destructive commands, deployment, or production changes."),
19
+ {
20
+ path: ".cursor/mcp.json",
21
+ content: json({
22
+ mcpServers: {},
23
+ }),
24
+ },
25
+ {
26
+ path: "AGENTS.md",
27
+ content: markdown(`# Speckit Agent Instructions
28
+
29
+ Use Speckit for Agile + TDD work. Cursor-specific rules live in \`.cursor/rules/*.mdc\`; this file is the cross-tool fallback.
30
+
31
+ - Follow \`.speckit/rules/agile-policy.md\`.
32
+ - Follow \`.speckit/rules/tdd-policy.md\` for code stories.
33
+ - Never run bare \`bv\`; use robot commands only.
34
+ `),
35
+ },
36
+ ];
37
+ },
38
+ };
39
+ function rule(name, frontmatter, body) {
40
+ return {
41
+ path: `.cursor/rules/speckit-${name}.mdc`,
42
+ content: markdown(`---
43
+ ${frontmatter}
44
+ ---
45
+
46
+ # Speckit ${name}
47
+
48
+ ${body}
49
+ `),
50
+ };
51
+ }
@@ -0,0 +1,7 @@
1
+ import { ManagedFile } from "../core/managed-files.js";
2
+ export type IdeAdapter = {
3
+ name: "claude-code" | "codex" | "antigravity" | "opencode" | "cursor";
4
+ displayName: string;
5
+ outputPaths: string[];
6
+ render(): ManagedFile[];
7
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,2 @@
1
+ import { IdeAdapter } from "./ide-adapter.js";
2
+ export declare const opencodeAdapter: IdeAdapter;
@@ -0,0 +1,58 @@
1
+ import { json, markdown } from "../core/managed-files.js";
2
+ export const opencodeAdapter = {
3
+ name: "opencode",
4
+ displayName: "OpenCode",
5
+ outputPaths: [
6
+ "opencode.json",
7
+ ".opencode/agent/speckit-planner.md",
8
+ ".opencode/agent/speckit-tdd-developer.md",
9
+ ".opencode/agent/speckit-reviewer.md",
10
+ ".opencode/agent/speckit-docs.md",
11
+ ],
12
+ render() {
13
+ return [
14
+ {
15
+ path: "opencode.json",
16
+ content: json({
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
+ },
25
+ agent("planner", "Plan Speckit Agile work without editing files.", "primary", {
26
+ edit: "deny",
27
+ bash: { "*": "ask", "git status*": "allow", "git diff*": "allow" },
28
+ }),
29
+ agent("tdd-developer", "Implement Speckit stories with TDD evidence.", "primary", {
30
+ edit: "ask",
31
+ bash: "ask",
32
+ }),
33
+ agent("reviewer", "Review changes without editing files.", "subagent", {
34
+ edit: "deny",
35
+ bash: { "*": "ask", "git diff*": "allow", "git log*": "allow", "npm test*": "allow" },
36
+ }),
37
+ agent("docs", "Update Speckit docs after approved changes.", "subagent", {
38
+ edit: "ask",
39
+ bash: "deny",
40
+ }),
41
+ ];
42
+ },
43
+ };
44
+ function agent(name, description, mode, permission) {
45
+ return {
46
+ path: `.opencode/agent/speckit-${name}.md`,
47
+ content: markdown(`---
48
+ description: "${description}"
49
+ mode: ${mode}
50
+ permission: ${JSON.stringify(permission)}
51
+ ---
52
+
53
+ # speckit-${name}
54
+
55
+ Follow \`.speckit/rules/agile-policy.md\`, \`.speckit/rules/tdd-policy.md\`, and \`.speckit/rules/enterprise-safety.md\`.
56
+ `),
57
+ };
58
+ }
@@ -0,0 +1,8 @@
1
+ export type ToolCheck = {
2
+ name: string;
3
+ required: boolean;
4
+ available: boolean;
5
+ hint: string;
6
+ };
7
+ export declare function checkTools(): ToolCheck[];
8
+ export declare function commandExists(command: string): boolean;
@@ -0,0 +1,28 @@
1
+ import { spawnSync } from "node:child_process";
2
+ const tools = [
3
+ ["git", true, "Install Git and run Speckit inside a repository."],
4
+ ["node", true, "Install Node.js 20 or newer."],
5
+ ["ck", false, "Recommended for ClaudeKit-style skills and workflows."],
6
+ ["br", false, "Recommended beads CLI. Use bd only for older projects."],
7
+ ["bd", false, "Legacy beads CLI fallback."],
8
+ ["bv", false, "Recommended for Beads Viewer robot commands."],
9
+ ["claude", false, "Claude Code adapter runtime."],
10
+ ["codex", false, "Codex adapter runtime."],
11
+ ["opencode", false, "OpenCode adapter runtime."],
12
+ ["cursor", false, "Cursor adapter runtime."],
13
+ ];
14
+ export function checkTools() {
15
+ return tools.map(([name, required, hint]) => ({
16
+ name,
17
+ required,
18
+ available: commandExists(name),
19
+ hint,
20
+ }));
21
+ }
22
+ export function commandExists(command) {
23
+ const result = spawnSync(command, ["--version"], {
24
+ encoding: "utf8",
25
+ stdio: "ignore",
26
+ });
27
+ return result.status === 0;
28
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1 @@
1
+ export declare function main(argv?: string[], root?: string): Promise<number>;
package/dist/cli.js ADDED
@@ -0,0 +1,104 @@
1
+ import { initCommand } from "./commands/init.js";
2
+ import { doctorCommand } from "./commands/doctor.js";
3
+ import { shapeCommand } from "./commands/shape.js";
4
+ import { quickCommand } from "./commands/quick.js";
5
+ import { planCommand } from "./commands/plan.js";
6
+ import { nextCommand } from "./commands/next.js";
7
+ import { syncCommand } from "./commands/sync.js";
8
+ import { runCommand } from "./commands/run.js";
9
+ import { reviewCommand } from "./commands/review.js";
10
+ export async function main(argv = process.argv.slice(2), root = process.cwd()) {
11
+ const parsed = parseArgs(argv);
12
+ try {
13
+ switch (parsed.command) {
14
+ case "init":
15
+ return initCommand({
16
+ root,
17
+ ide: value(parsed, "ide"),
18
+ force: has(parsed, "force"),
19
+ });
20
+ case "doctor":
21
+ return doctorCommand({ root, json: has(parsed, "json") });
22
+ case "shape":
23
+ return shapeCommand({ root, intent: requiredIntent(parsed) });
24
+ case "quick":
25
+ return quickCommand({ root, intent: requiredIntent(parsed) });
26
+ case "plan":
27
+ return planCommand({ root, intent: requiredIntent(parsed) });
28
+ case "next":
29
+ return nextCommand();
30
+ case "sync":
31
+ return syncCommand({ root });
32
+ case "run":
33
+ return runCommand({ root, target: requiredIntent(parsed) });
34
+ case "review":
35
+ return reviewCommand({ root });
36
+ case "help":
37
+ case "":
38
+ printHelp();
39
+ return 0;
40
+ default:
41
+ console.error(`Unknown command: ${parsed.command}`);
42
+ printHelp();
43
+ return 1;
44
+ }
45
+ }
46
+ catch (error) {
47
+ console.error(error instanceof Error ? error.message : String(error));
48
+ return 1;
49
+ }
50
+ }
51
+ function parseArgs(argv) {
52
+ const [command = "", ...rest] = argv;
53
+ const args = [];
54
+ const flags = new Map();
55
+ for (let index = 0; index < rest.length; index += 1) {
56
+ const token = rest[index];
57
+ if (!token.startsWith("--")) {
58
+ args.push(token);
59
+ continue;
60
+ }
61
+ const name = token.slice(2);
62
+ const next = rest[index + 1];
63
+ if (next && !next.startsWith("--")) {
64
+ flags.set(name, next);
65
+ index += 1;
66
+ }
67
+ else {
68
+ flags.set(name, true);
69
+ }
70
+ }
71
+ return { command, args, flags };
72
+ }
73
+ function requiredIntent(parsed) {
74
+ const intent = parsed.args.join(" ").trim();
75
+ if (!intent)
76
+ throw new Error(`Command "${parsed.command}" requires a target or intent.`);
77
+ return intent;
78
+ }
79
+ function value(parsed, name) {
80
+ const found = parsed.flags.get(name);
81
+ return typeof found === "string" ? found : undefined;
82
+ }
83
+ function has(parsed, name) {
84
+ return parsed.flags.has(name);
85
+ }
86
+ function printHelp() {
87
+ console.log(`Speckit - Agile + TDD workflow compiler for agentic IDEs
88
+
89
+ Usage:
90
+ speckit init [--ide all|claude-code|codex|antigravity|opencode|cursor] [--force]
91
+ speckit doctor [--json]
92
+ speckit shape "<intent>"
93
+ speckit quick "<intent>"
94
+ speckit plan "<intent>"
95
+ speckit next
96
+ speckit sync
97
+ speckit run <story-path-or-id>
98
+ speckit review
99
+ `);
100
+ }
101
+ if (import.meta.url === `file://${process.argv[1]}`) {
102
+ const exitCode = await main();
103
+ process.exitCode = exitCode;
104
+ }
@@ -0,0 +1,6 @@
1
+ export type DoctorOptions = {
2
+ root: string;
3
+ json?: boolean;
4
+ stdout?: Pick<typeof console, "log">;
5
+ };
6
+ export declare function doctorCommand(options: DoctorOptions): Promise<number>;
@@ -0,0 +1,50 @@
1
+ import { access } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { getAdapters } from "../config/adapter-registry.js";
4
+ import { checkTools } from "../adapters/tool-checks.js";
5
+ import { detectTestCommands } from "../core/test-detection.js";
6
+ export async function doctorCommand(options) {
7
+ const stdout = options.stdout ?? console;
8
+ const tools = checkTools();
9
+ const tests = await detectTestCommands(options.root);
10
+ const adapters = await Promise.all(getAdapters("all").map(async (adapter) => ({
11
+ name: adapter.name,
12
+ ...(await adapterStatus(options.root, adapter.outputPaths)),
13
+ })));
14
+ const report = {
15
+ node: process.versions.node,
16
+ tools,
17
+ tests,
18
+ adapters,
19
+ status: tools.filter((tool) => tool.required && !tool.available).length === 0 ? "ok" : "needs-attention",
20
+ };
21
+ if (options.json) {
22
+ stdout.log(JSON.stringify(report, null, 2));
23
+ }
24
+ else {
25
+ stdout.log(`Speckit doctor: ${report.status}`);
26
+ stdout.log(`Node: ${report.node}`);
27
+ stdout.log(`Tools: ${tools.map((tool) => `${tool.name}=${tool.available ? "ok" : "missing"}`).join(", ")}`);
28
+ stdout.log(`Tests: ${tests[0]?.command ?? "not detected"}`);
29
+ for (const adapter of adapters) {
30
+ stdout.log(`Adapter ${adapter.name}: ${adapter.present}/${adapter.total} files present`);
31
+ }
32
+ }
33
+ return report.status === "ok" ? 0 : 1;
34
+ }
35
+ async function adapterStatus(root, paths) {
36
+ const missing = [];
37
+ for (const path of paths) {
38
+ try {
39
+ await access(join(root, path));
40
+ }
41
+ catch {
42
+ missing.push(path);
43
+ }
44
+ }
45
+ return {
46
+ present: paths.length - missing.length,
47
+ total: paths.length,
48
+ missing,
49
+ };
50
+ }
@@ -0,0 +1,7 @@
1
+ export type InitOptions = {
2
+ root: string;
3
+ ide?: string;
4
+ force?: boolean;
5
+ stdout?: Pick<typeof console, "log">;
6
+ };
7
+ export declare function initCommand(options: InitOptions): Promise<number>;
@@ -0,0 +1,17 @@
1
+ import { coreFiles } from "../core/scaffold.js";
2
+ import { writeManagedFiles } from "../core/managed-files.js";
3
+ import { getAdapters } from "../config/adapter-registry.js";
4
+ export async function initCommand(options) {
5
+ const stdout = options.stdout ?? console;
6
+ const selectedIde = options.ide ?? "all";
7
+ const adapterFiles = getAdapters(selectedIde).flatMap((adapter) => adapter.render());
8
+ const results = await writeManagedFiles(options.root, [...coreFiles(), ...adapterFiles], options.force ?? false);
9
+ const created = results.filter((result) => result.status === "created").length;
10
+ const updated = results.filter((result) => result.status === "updated").length;
11
+ const skipped = results.filter((result) => result.status === "skipped");
12
+ stdout.log(`Speckit initialized: ${created} created, ${updated} updated, ${skipped.length} skipped.`);
13
+ for (const result of skipped) {
14
+ stdout.log(`skipped ${result.path}: ${result.reason}`);
15
+ }
16
+ return skipped.length > 0 ? 2 : 0;
17
+ }
@@ -0,0 +1,4 @@
1
+ export type NextOptions = {
2
+ stdout?: Pick<typeof console, "log" | "error">;
3
+ };
4
+ export declare function nextCommand(options?: NextOptions): Promise<number>;
@@ -0,0 +1,17 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { commandExists } from "../adapters/tool-checks.js";
3
+ export async function nextCommand(options = {}) {
4
+ const stdout = options.stdout ?? console;
5
+ if (!commandExists("bv")) {
6
+ stdout.error("bv is not installed. Install Beads Viewer, then run: bv --robot-next --format json");
7
+ return 1;
8
+ }
9
+ const result = spawnSync("bv", ["--robot-next", "--format", "json"], {
10
+ encoding: "utf8",
11
+ });
12
+ if (result.stdout)
13
+ stdout.log(result.stdout.trim());
14
+ if (result.stderr)
15
+ stdout.error(result.stderr.trim());
16
+ return result.status ?? 1;
17
+ }
@@ -0,0 +1,6 @@
1
+ export type PlanOptions = {
2
+ root: string;
3
+ intent: string;
4
+ stdout?: Pick<typeof console, "log">;
5
+ };
6
+ export declare function planCommand(options: PlanOptions): Promise<number>;