@trieungoctam/speckit 0.3.6 → 0.4.1

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 CHANGED
@@ -10,11 +10,18 @@ The curated skill set is intentionally small: `spec-shape`, `spec-research`, `sp
10
10
 
11
11
  ## Quickstart
12
12
 
13
+ Recommended enterprise setup:
14
+
13
15
  ```bash
14
16
  npx @trieungoctam/speckit@latest setup
15
- npx @trieungoctam/speckit@latest init --ide cursor
16
- npx @trieungoctam/speckit@latest init --ide all
17
- npx @trieungoctam/speckit@latest init --enterprise --ide all
17
+ npx @trieungoctam/speckit@latest doctor --deep
18
+ npx @trieungoctam/speckit@latest validate
19
+ npx @trieungoctam/speckit@latest score
20
+ ```
21
+
22
+ One story end-to-end:
23
+
24
+ ```bash
18
25
  npx @trieungoctam/speckit@latest memory refresh
19
26
  npx @trieungoctam/speckit@latest session start "Add checkout validation"
20
27
  npx @trieungoctam/speckit@latest quick "Add checkout validation"
@@ -23,6 +30,10 @@ npx @trieungoctam/speckit@latest sync
23
30
  npx @trieungoctam/speckit@latest graph setup
24
31
  npx @trieungoctam/speckit@latest sprint plan
25
32
  npx @trieungoctam/speckit@latest graph triage --json
33
+ npx @trieungoctam/speckit@latest team status .speckit/stories/<story>.md
34
+ npx @trieungoctam/speckit@latest team audit .speckit/stories/<story>.md --json
35
+ npx @trieungoctam/speckit@latest team handoff .speckit/stories/<story>.md --from dev --to qa
36
+ npx @trieungoctam/speckit@latest score .speckit/stories/<story>.md
26
37
  npx @trieungoctam/speckit@latest validate --json
27
38
  npx @trieungoctam/speckit@latest permissions audit --path .env --json
28
39
  npx @trieungoctam/speckit@latest ready .speckit/stories/<story>.md
@@ -30,6 +41,13 @@ npx @trieungoctam/speckit@latest session checkpoint --note "red complete"
30
41
  npx @trieungoctam/speckit@latest review
31
42
  ```
32
43
 
44
+ Reset repo-local adapters before reinstalling:
45
+
46
+ ```bash
47
+ rm -rf .claude CLAUDE.md .codex AGENTS.md .cursor .opencode opencode.json
48
+ npx @trieungoctam/speckit@latest setup
49
+ ```
50
+
33
51
  Interactive CLI output is colorized when the terminal supports ANSI colors. Use `NO_COLOR=1` to disable colors, or `SPECKIT_COLOR=1` to force colors for demos and snapshots.
34
52
 
35
53
  Or install globally:
@@ -85,6 +103,11 @@ For implementation stories, red-green-refactor evidence is mandatory. A story is
85
103
  | `speckit session compact` | Create an anchored summary for resume or handoff. |
86
104
  | `speckit session resume` | Mark a session as active and print its handoff path. |
87
105
  | `speckit session status` | Print active session state paths. |
106
+ | `speckit team status <story>` | Show role-by-role team artifact readiness for a story. |
107
+ | `speckit team audit <story>` | Run enterprise review-gate checks and return nonzero when blockers remain. |
108
+ | `speckit team handoff <story>` | Create a durable role-to-role handoff artifact. |
109
+ | `speckit score` | Score project workflow health across contract, team model, context/session, and graph sync. |
110
+ | `speckit score <story>` | Score story health across team readiness, developer trace, TDD evidence, and review gate. |
88
111
  | `speckit shape "<intent>"` | Create a short spec contract. |
89
112
  | `speckit context <story>` | Build the current implementation context from a story. |
90
113
  | `speckit quick "<intent>"` | Create one story plus matching TDD evidence file. |
@@ -117,7 +140,9 @@ See `docs/adapters.md` for exact output paths.
117
140
 
118
141
  ## Guides
119
142
 
143
+ - `docs/getting-started.md` covers setup, adapter reset, verification, story execution, team audit, and close.
120
144
  - `docs/use-cases.md` covers setup, migration, quick changes, full planning, long sessions, TDD, graph automation, review, CI, and troubleshooting.
145
+ - `docs/team-workflow.md` covers enterprise role ownership, status, audit, and handoff flow.
121
146
  - `docs/beads-viewer-setup.md` covers Beads Viewer installation, `bv` verification, and robot-safe graph usage.
122
147
  - `docs/workflow-model.md` describes the quick and full workflow lanes.
123
148
  - `docs/prompt-architecture.md` describes the prompt contract used by the super-agent, skills, workflows, run prompt, and IDE adapters.
package/dist/cli.js CHANGED
@@ -9,6 +9,8 @@ import { planCommand } from "./commands/plan.js";
9
9
  import { memoryCommand } from "./commands/memory.js";
10
10
  import { permissionsCommand } from "./commands/permissions.js";
11
11
  import { sessionCommand } from "./commands/session.js";
12
+ import { teamCommand } from "./commands/team.js";
13
+ import { scoreCommand } from "./commands/score.js";
12
14
  import { sprintCommand } from "./commands/sprint.js";
13
15
  import { graphCommand } from "./commands/graph.js";
14
16
  import { validateCommand } from "./commands/validate.js";
@@ -66,6 +68,21 @@ export async function main(argv = process.argv.slice(2), root = process.cwd()) {
66
68
  note: value(parsed, "note"),
67
69
  json: has(parsed, "json"),
68
70
  });
71
+ case "team":
72
+ return teamCommand({
73
+ root,
74
+ action: requiredAction(parsed),
75
+ target: parsed.args.slice(1).join(" ").trim() || undefined,
76
+ from: value(parsed, "from"),
77
+ to: value(parsed, "to"),
78
+ json: has(parsed, "json"),
79
+ });
80
+ case "score":
81
+ return scoreCommand({
82
+ root,
83
+ target: parsed.args.join(" ").trim() || undefined,
84
+ json: has(parsed, "json"),
85
+ });
69
86
  case "sprint":
70
87
  return sprintCommand({ root, action: requiredAction(parsed), json: has(parsed, "json") });
71
88
  case "graph":
@@ -162,6 +179,8 @@ Usage:
162
179
  speckit memory refresh
163
180
  speckit permissions audit [--path <path>] [--command <command>] [--json]
164
181
  speckit session start|checkpoint|compact|resume|status [target] [--note "..."] [--json]
182
+ speckit team status|audit|handoff <story-path-or-id> [--from <role>] [--to <role>] [--json]
183
+ speckit score [story-path-or-id] [--json]
165
184
  speckit sprint plan|next [--json]
166
185
  speckit graph setup|triage|plan|insights [--json]
167
186
  speckit validate [--json]
@@ -40,16 +40,49 @@ export async function planCommand(options) {
40
40
  evidence: ${dir}/tdd-evidence.md
41
41
  context: pending`, `# Story: ${options.intent}
42
42
 
43
+ ## Business Goal
44
+ - Goal: ${options.intent}
45
+ - Priority: medium
46
+ - Success signal:
47
+
43
48
  ## Acceptance Criteria
44
49
  - Given ...
45
50
  - When ...
46
51
  - Then ...
47
52
 
53
+ ## Edge Cases
54
+ - Boundary:
55
+ - Error path:
56
+ - State transition:
57
+
58
+ ## Implementation Scope
59
+ - In scope:
60
+ - Out of scope:
61
+ - Files likely to read:
62
+ - Files likely to modify:
63
+
64
+ ## Architecture Notes
65
+ - Constraints:
66
+ - Integration points:
67
+ - Risks:
68
+
48
69
  ## TDD Evidence File
49
70
  \`${dir}/tdd-evidence.md\`
50
71
 
51
72
  ## Implementation Notes
52
73
 
74
+ ## Dev Agent Record
75
+ ### Test Intent
76
+
77
+ ### Debug Log
78
+
79
+ ### Completion Notes
80
+
81
+ ### File List
82
+
83
+ ## Change Log
84
+ - ${new Date().toISOString().slice(0, 10)}: Story drafted.
85
+
53
86
  ## Spec Anti-Mistake Checklist
54
87
  - Reuse existing project patterns before adding new files.
55
88
  - Verify file locations before editing.
@@ -62,11 +95,15 @@ context: pending`, `# Story: ${options.intent}
62
95
  content: markdownWithFrontmatter(`status: missing
63
96
  story: ${dir}/story.md`, `# TDD Evidence: ${options.intent}
64
97
 
98
+ ## Test Intent
99
+
65
100
  ## Red
66
101
 
67
102
  ## Green
68
103
 
69
104
  ## Refactor
105
+
106
+ ## Review Evidence
70
107
  `),
71
108
  },
72
109
  ];
@@ -18,11 +18,32 @@ context: pending`, `# Story: ${options.intent}
18
18
  ## Intent
19
19
  ${options.intent}
20
20
 
21
+ ## Business Goal
22
+ - Goal: ${options.intent}
23
+ - Priority: medium
24
+ - Success signal: behavior is covered by executable tests and Speckit evidence
25
+
21
26
  ## Acceptance Criteria
22
27
  - Given the current product state
23
28
  - When this story is implemented
24
29
  - Then the behavior is covered by executable tests and Speckit evidence
25
30
 
31
+ ## Edge Cases
32
+ - Boundary: document the smallest input, state, or permission boundary this story touches.
33
+ - Error path: document how failures are surfaced or recovered.
34
+ - State transition: document before and after behavior.
35
+
36
+ ## Implementation Scope
37
+ - In scope: the smallest change needed to satisfy the acceptance criteria.
38
+ - Out of scope: unrelated refactors, new dependencies, or behavior not tied to acceptance criteria.
39
+ - Files likely to read:
40
+ - Files likely to modify:
41
+
42
+ ## Architecture Notes
43
+ - Constraints: reuse existing project patterns before adding new abstractions.
44
+ - Integration points:
45
+ - Risks:
46
+
26
47
  ## TDD Checklist
27
48
  - [ ] Test target identified
28
49
  - [ ] Red evidence recorded in ${evidencePath}
@@ -38,6 +59,18 @@ ${options.intent}
38
59
  - Do not introduce new libraries without explicit need.
39
60
  - Preserve existing behavior unless an acceptance criterion requires change.
40
61
  - Update docs only when behavior or workflow changes.
62
+
63
+ ## Dev Agent Record
64
+ ### Test Intent
65
+
66
+ ### Debug Log
67
+
68
+ ### Completion Notes
69
+
70
+ ### File List
71
+
72
+ ## Change Log
73
+ - ${new Date().toISOString().slice(0, 10)}: Story drafted.
41
74
  `),
42
75
  },
43
76
  {
@@ -58,6 +91,11 @@ story: ${storyPath}`, `# TDD Evidence: ${options.intent}
58
91
  ## Refactor
59
92
  - Command: \`${testCommand}\`
60
93
  - Result:
94
+
95
+ ## Review Evidence
96
+ - Reviewer:
97
+ - Outcome:
98
+ - Follow-ups:
61
99
  `),
62
100
  },
63
101
  ]);
@@ -0,0 +1,7 @@
1
+ export type ScoreOptions = {
2
+ root: string;
3
+ target?: string;
4
+ json?: boolean;
5
+ stdout?: Pick<typeof console, "log">;
6
+ };
7
+ export declare function scoreCommand(options: ScoreOptions): Promise<number>;
@@ -0,0 +1,29 @@
1
+ import { createColors } from "../core/colors.js";
2
+ import { calculateSpecScore } from "../core/spec-score.js";
3
+ export async function scoreCommand(options) {
4
+ const stdout = options.stdout ?? console;
5
+ const report = await calculateSpecScore(options.root, options.target);
6
+ stdout.log(options.json ? JSON.stringify(report, null, 2) : renderScore(report));
7
+ return report.status === "blocked" ? 1 : 0;
8
+ }
9
+ function renderScore(report) {
10
+ const colors = createColors();
11
+ const lines = [
12
+ `${colors.bold("Spec Runtime Score")}: ${colors.status(report.score >= 75, `${report.score}/100`, `${report.score}/100`)}`,
13
+ `Status: ${report.status}`,
14
+ ];
15
+ if (report.target)
16
+ lines.push(`Target: ${colors.cyan(report.target)}`);
17
+ lines.push("");
18
+ for (const category of report.categories) {
19
+ const ok = category.score >= 75;
20
+ lines.push(`${colors.status(ok, String(category.score), String(category.score)).padStart(colors.enabled ? 12 : 3)} ${category.name}: ${category.passed}/${category.total} - ${category.detail}`);
21
+ }
22
+ lines.push("", "Recommendations:");
23
+ lines.push(...report.recommendations.map((item) => `- ${item}`));
24
+ if (report.blockers.length) {
25
+ lines.push("", "Blockers:");
26
+ lines.push(...report.blockers.map((item) => `- ${item}`));
27
+ }
28
+ return lines.join("\n");
29
+ }
@@ -0,0 +1,10 @@
1
+ export type TeamOptions = {
2
+ root: string;
3
+ action: string;
4
+ target?: string;
5
+ from?: string;
6
+ to?: string;
7
+ json?: boolean;
8
+ stdout?: Pick<typeof console, "log" | "error">;
9
+ };
10
+ export declare function teamCommand(options: TeamOptions): Promise<number>;
@@ -0,0 +1,129 @@
1
+ import { buildTeamReport } from "../core/team-report.js";
2
+ import { createColors } from "../core/colors.js";
3
+ import { markdown, writeManagedFiles } from "../core/managed-files.js";
4
+ import { slugify, timestamp } from "../core/slug.js";
5
+ export async function teamCommand(options) {
6
+ const stdout = options.stdout ?? console;
7
+ switch (options.action) {
8
+ case "status":
9
+ return status(options);
10
+ case "audit":
11
+ return audit(options);
12
+ case "handoff":
13
+ return handoff(options);
14
+ default:
15
+ stdout.error("Usage: speckit team status|audit|handoff <story> [--from <role>] [--to <role>] [--json]");
16
+ return 1;
17
+ }
18
+ }
19
+ async function status(options) {
20
+ const stdout = options.stdout ?? console;
21
+ const target = requireTarget(options);
22
+ if (!target)
23
+ return 1;
24
+ const report = await buildTeamReport(options.root, target);
25
+ stdout.log(options.json ? JSON.stringify(report, null, 2) : renderReport(report, "Spec Team Status"));
26
+ return report.story ? 0 : 1;
27
+ }
28
+ async function audit(options) {
29
+ const stdout = options.stdout ?? console;
30
+ const target = requireTarget(options);
31
+ if (!target)
32
+ return 1;
33
+ const report = await buildTeamReport(options.root, target);
34
+ const auditReport = {
35
+ gate: "review",
36
+ status: report.status,
37
+ story: report.story,
38
+ blockers: report.blockers,
39
+ warnings: report.warnings,
40
+ roles: report.roles,
41
+ };
42
+ stdout.log(options.json ? JSON.stringify(auditReport, null, 2) : renderAudit(auditReport));
43
+ return report.status === "ok" ? 0 : 1;
44
+ }
45
+ async function handoff(options) {
46
+ const stdout = options.stdout ?? console;
47
+ const target = requireTarget(options);
48
+ if (!target)
49
+ return 1;
50
+ const report = await buildTeamReport(options.root, target);
51
+ if (!report.story) {
52
+ stdout.error(report.blockers[0] ?? `Story not found: ${target}`);
53
+ return 1;
54
+ }
55
+ const from = options.from ?? "current-role";
56
+ const to = options.to ?? "next-role";
57
+ const path = `.speckit/team/handoffs/${timestamp()}-${slugify(report.story.id)}-${slugify(from)}-to-${slugify(to)}.md`;
58
+ await writeManagedFiles(options.root, [
59
+ {
60
+ path,
61
+ content: markdown(`# Spec Team Handoff
62
+
63
+ ## Story
64
+ \`${report.story.path}\`
65
+
66
+ ## Route
67
+ - From: ${from}
68
+ - To: ${to}
69
+
70
+ ## Current Status
71
+ - Story status: ${report.story.status ?? "missing"}
72
+ - Team status: ${report.status}
73
+
74
+ ## Blockers
75
+ ${report.blockers.length ? report.blockers.map((item) => `- ${item}`).join("\n") : "- none"}
76
+
77
+ ## Warnings
78
+ ${report.warnings.length ? report.warnings.map((item) => `- ${item}`).join("\n") : "- none"}
79
+
80
+ ## Next Role Checklist
81
+ - [ ] Read the story and linked evidence file.
82
+ - [ ] Resolve blockers owned by the target role.
83
+ - [ ] Update durable artifacts before handing off again.
84
+ - [ ] Run \`speckit team audit ${report.story.path}\`.
85
+ `),
86
+ },
87
+ ]);
88
+ stdout.log(path);
89
+ return 0;
90
+ }
91
+ function renderReport(report, title) {
92
+ const colors = createColors();
93
+ if (!report.story)
94
+ return `${colors.bold(title)}: ${colors.red("blocked")}\n${report.blockers.join("\n")}`;
95
+ const lines = [
96
+ `${colors.bold(title)}: ${colors.status(report.status === "ok", "ok", "blocked")}`,
97
+ `Story: ${colors.cyan(report.story.path)}`,
98
+ `State: ${report.story.status ?? "missing"}`,
99
+ "",
100
+ ];
101
+ for (const role of report.roles) {
102
+ lines.push(`${colors.bold(role.role)}: ${colors.status(role.status === "ok", role.status, role.status)}`);
103
+ for (const check of role.checks) {
104
+ lines.push(` - ${colors.status(check.ok)} ${check.name}: ${check.detail}`);
105
+ }
106
+ lines.push("");
107
+ }
108
+ return lines.join("\n").trimEnd();
109
+ }
110
+ function renderAudit(report) {
111
+ const colors = createColors();
112
+ return [
113
+ `${colors.bold("Spec Team Audit")}: ${colors.status(report.status === "ok", "ok", "blocked")}`,
114
+ `Gate: ${report.gate}`,
115
+ report.story ? `Story: ${colors.cyan(report.story.path)}` : undefined,
116
+ "",
117
+ "Blocking:",
118
+ ...(report.blockers.length ? report.blockers.map((item) => `- ${item}`) : ["- none"]),
119
+ "",
120
+ "Warnings:",
121
+ ...(report.warnings.length ? report.warnings.map((item) => `- ${item}`) : ["- none"]),
122
+ ].filter((line) => line !== undefined).join("\n");
123
+ }
124
+ function requireTarget(options) {
125
+ if (options.target)
126
+ return options.target;
127
+ options.stdout?.error("Team command requires a story path or id.");
128
+ return undefined;
129
+ }
@@ -2,6 +2,7 @@ import { markdown, text } from "./managed-files.js";
2
2
  import { agilePolicy, enterpriseSafetyPolicy, tddPolicy, workflowReview, workflowShape, workflowTddRun, } from "./policy.js";
3
3
  import { permissionPolicyFile } from "./permission-policy.js";
4
4
  import { storyTemplate, tddEvidenceTemplate } from "./templates.js";
5
+ import { teamFiles } from "./team-scaffold.js";
5
6
  export function coreFiles() {
6
7
  return [
7
8
  {
@@ -48,6 +49,7 @@ adapters:
48
49
  }
49
50
  export function enterpriseFiles() {
50
51
  return [
52
+ ...teamFiles(),
51
53
  {
52
54
  path: ".speckit/flows/spec-flow.md",
53
55
  content: markdown(`# Spec Flow
@@ -0,0 +1,16 @@
1
+ export type ScoreCategory = {
2
+ name: string;
3
+ score: number;
4
+ passed: number;
5
+ total: number;
6
+ detail: string;
7
+ };
8
+ export type SpecScoreReport = {
9
+ score: number;
10
+ target?: string;
11
+ status: "excellent" | "healthy" | "needs-attention" | "blocked";
12
+ categories: ScoreCategory[];
13
+ blockers: string[];
14
+ recommendations: string[];
15
+ };
16
+ export declare function calculateSpecScore(root: string, target?: string): Promise<SpecScoreReport>;
@@ -0,0 +1,112 @@
1
+ import { access, readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { buildTeamReport } from "./team-report.js";
4
+ import { validateWorkflowContract } from "./workflow-validator.js";
5
+ export async function calculateSpecScore(root, target) {
6
+ const categories = target
7
+ ? await storyCategories(root, target)
8
+ : await projectCategories(root);
9
+ const score = Math.round(categories.reduce((sum, item) => sum + item.score, 0) / categories.length);
10
+ const blockers = categories
11
+ .filter((item) => item.score < 70)
12
+ .map((item) => `${item.name}: ${item.detail}`);
13
+ return {
14
+ score,
15
+ target,
16
+ status: statusFor(score, blockers.length),
17
+ categories,
18
+ blockers,
19
+ recommendations: recommendationsFor(categories, Boolean(target)),
20
+ };
21
+ }
22
+ async function projectCategories(root) {
23
+ const contract = await validateWorkflowContract(root);
24
+ return [
25
+ ratio("Workflow Contract", contract.filter((check) => check.ok).length, contract.length, "Core prompts, skills, adapters, and permissions"),
26
+ await fileScore(root, "Team Operating Model", [
27
+ ".speckit/team/roles.md",
28
+ ".speckit/team/artifact-ownership.md",
29
+ ".speckit/team/working-agreement.md",
30
+ ".speckit/team/review-gates.md",
31
+ ".speckit/team/handoff-protocol.md",
32
+ ]),
33
+ await fileScore(root, "Context And Session", [
34
+ ".speckit/memory/project-context.md",
35
+ ".speckit/sessions/active.md",
36
+ ".speckit/context/current.md",
37
+ ".speckit/context/subagent-handoff.md",
38
+ ]),
39
+ await fileScore(root, "Graph Sync", [
40
+ ".speckit/sync/beads-sync.jsonl",
41
+ ".beads/beads.jsonl",
42
+ ]),
43
+ ];
44
+ }
45
+ async function storyCategories(root, target) {
46
+ const team = await buildTeamReport(root, target);
47
+ if (!team.story) {
48
+ return [ratio("Story", 0, 1, team.blockers[0] ?? "Story not found")];
49
+ }
50
+ const allRoleChecks = team.roles.flatMap((role) => role.checks);
51
+ const qa = team.roles.find((role) => role.role === "QA/Test");
52
+ const developer = team.roles.find((role) => role.role === "Developer");
53
+ const reviewer = team.roles.find((role) => role.role === "Reviewer/Lead");
54
+ return [
55
+ ratio("Team Readiness", allRoleChecks.filter((check) => check.ok).length, allRoleChecks.length, "Role-owned story artifacts"),
56
+ ratio("Developer Trace", developer?.checks.filter((check) => check.ok).length ?? 0, developer?.checks.length ?? 1, "Dev Agent Record, File List, Change Log"),
57
+ ratio("TDD Evidence", qa?.checks.filter((check) => check.ok).length ?? 0, qa?.checks.length ?? 1, "Red, green, and refactor evidence"),
58
+ ratio("Review Gate", reviewer?.checks.filter((check) => check.ok).length ?? 0, reviewer?.checks.length ?? 1, "Review evidence and follow-ups"),
59
+ ];
60
+ }
61
+ async function fileScore(root, name, paths) {
62
+ const checks = await Promise.all(paths.map((path) => exists(root, path)));
63
+ const passed = checks.filter(Boolean).length;
64
+ return ratio(name, passed, paths.length, `${passed}/${paths.length} files present`);
65
+ }
66
+ function ratio(name, passed, total, detail) {
67
+ const denominator = Math.max(total, 1);
68
+ return {
69
+ name,
70
+ score: Math.round((passed / denominator) * 100),
71
+ passed,
72
+ total,
73
+ detail,
74
+ };
75
+ }
76
+ function statusFor(score, blockers) {
77
+ if (score >= 90 && blockers === 0)
78
+ return "excellent";
79
+ if (score >= 75)
80
+ return "healthy";
81
+ if (score >= 50)
82
+ return "needs-attention";
83
+ return "blocked";
84
+ }
85
+ function recommendationsFor(categories, storyMode) {
86
+ const weak = categories.filter((item) => item.score < 100);
87
+ if (weak.length === 0)
88
+ return ["Workflow is fully aligned."];
89
+ return weak.map((item) => {
90
+ if (storyMode && item.name === "TDD Evidence")
91
+ return "Complete red, green, and refactor evidence before review.";
92
+ if (storyMode && item.name === "Developer Trace")
93
+ return "Update Dev Agent Record, File List, and Change Log.";
94
+ if (storyMode && item.name === "Review Gate")
95
+ return "Record review outcome and follow-ups.";
96
+ if (item.name === "Context And Session")
97
+ return "Run memory refresh, session start, context, and compact before long work.";
98
+ if (item.name === "Graph Sync")
99
+ return "Run speckit sync and speckit graph setup.";
100
+ return `Fix ${item.name}.`;
101
+ });
102
+ }
103
+ async function exists(root, path) {
104
+ try {
105
+ await access(join(root, path));
106
+ const content = await readFile(join(root, path), "utf8");
107
+ return content.trim().length > 0;
108
+ }
109
+ catch {
110
+ return false;
111
+ }
112
+ }
@@ -0,0 +1,19 @@
1
+ import { StoryResolution } from "./story.js";
2
+ export type TeamCheck = {
3
+ name: string;
4
+ ok: boolean;
5
+ detail: string;
6
+ };
7
+ export type TeamRoleReport = {
8
+ role: string;
9
+ status: "ok" | "blocked" | "needs-attention" | "waiting";
10
+ checks: TeamCheck[];
11
+ };
12
+ export type TeamReport = {
13
+ status: "ok" | "blocked";
14
+ story?: Pick<StoryResolution, "id" | "path" | "title" | "status" | "evidencePath">;
15
+ roles: TeamRoleReport[];
16
+ blockers: string[];
17
+ warnings: string[];
18
+ };
19
+ export declare function buildTeamReport(root: string, target: string): Promise<TeamReport>;