@trieungoctam/speckit 0.3.5 → 0.4.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 +12 -0
- package/dist/cli.js +22 -1
- package/dist/commands/doctor.js +12 -9
- package/dist/commands/graph.js +4 -2
- package/dist/commands/init.js +4 -2
- package/dist/commands/plan.js +37 -0
- package/dist/commands/quick.js +38 -0
- package/dist/commands/ready.js +6 -4
- package/dist/commands/score.d.ts +7 -0
- package/dist/commands/score.js +29 -0
- package/dist/commands/setup.js +24 -21
- package/dist/commands/sync.js +4 -2
- package/dist/commands/team.d.ts +10 -0
- package/dist/commands/team.js +129 -0
- package/dist/commands/validate.js +4 -2
- package/dist/core/colors.d.ts +11 -0
- package/dist/core/colors.js +40 -0
- package/dist/core/scaffold.js +2 -0
- package/dist/core/spec-score.d.ts +16 -0
- package/dist/core/spec-score.js +112 -0
- package/dist/core/team-report.d.ts +19 -0
- package/dist/core/team-report.js +149 -0
- package/dist/core/team-scaffold.d.ts +2 -0
- package/dist/core/team-scaffold.js +92 -0
- package/dist/core/templates.d.ts +1 -1
- package/dist/core/templates.js +15 -0
- package/docs/adapters.md +12 -0
- package/docs/code-standards.md +2 -0
- package/docs/development-roadmap.md +7 -3
- package/docs/enterprise-rollout.md +8 -3
- package/docs/product-contract.md +21 -2
- package/docs/project-changelog.md +31 -0
- package/docs/release-checklist.md +4 -0
- package/docs/spec-quality-gates.md +27 -0
- package/docs/system-architecture.md +19 -1
- package/docs/team-workflow.md +40 -0
- package/docs/use-cases.md +11 -0
- package/docs/workflow-model.md +31 -0
- package/package.json +1 -1
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { validateWorkflowContract } from "../core/workflow-validator.js";
|
|
2
|
+
import { createColors } from "../core/colors.js";
|
|
2
3
|
export async function validateCommand(options) {
|
|
3
4
|
const stdout = options.stdout ?? console;
|
|
5
|
+
const colors = createColors();
|
|
4
6
|
const checks = await validateWorkflowContract(options.root);
|
|
5
7
|
const status = checks.every((check) => check.ok) ? "ok" : "needs-attention";
|
|
6
8
|
const report = { status, checks };
|
|
@@ -8,9 +10,9 @@ export async function validateCommand(options) {
|
|
|
8
10
|
stdout.log(JSON.stringify(report, null, 2));
|
|
9
11
|
}
|
|
10
12
|
else {
|
|
11
|
-
stdout.log(
|
|
13
|
+
stdout.log(`${colors.bold("Speckit workflow contract")}: ${colors.status(status === "ok", "ok", status)}`);
|
|
12
14
|
for (const check of checks) {
|
|
13
|
-
stdout.log(`${check.ok
|
|
15
|
+
stdout.log(`${colors.status(check.ok, "ok", "fail")} ${check.name}: ${check.detail}`);
|
|
14
16
|
}
|
|
15
17
|
}
|
|
16
18
|
return status === "ok" ? 0 : 1;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type ColorOutput = {
|
|
2
|
+
isTTY?: boolean;
|
|
3
|
+
};
|
|
4
|
+
type ColorName = "blue" | "cyan" | "dim" | "green" | "red" | "yellow" | "bold";
|
|
5
|
+
export type Colors = Record<ColorName, (text: string) => string> & {
|
|
6
|
+
enabled: boolean;
|
|
7
|
+
status(ok: boolean, okText?: string, failText?: string): string;
|
|
8
|
+
};
|
|
9
|
+
export declare function createColors(output?: ColorOutput): Colors;
|
|
10
|
+
export declare function colorsEnabled(output?: ColorOutput): boolean;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const ansi = {
|
|
2
|
+
blue: [34, 39],
|
|
3
|
+
cyan: [36, 39],
|
|
4
|
+
dim: [2, 22],
|
|
5
|
+
green: [32, 39],
|
|
6
|
+
red: [31, 39],
|
|
7
|
+
yellow: [33, 39],
|
|
8
|
+
bold: [1, 22],
|
|
9
|
+
};
|
|
10
|
+
export function createColors(output) {
|
|
11
|
+
const enabled = colorsEnabled(output);
|
|
12
|
+
const style = (name) => (text) => {
|
|
13
|
+
if (!enabled)
|
|
14
|
+
return text;
|
|
15
|
+
const [open, close] = ansi[name];
|
|
16
|
+
return `\u001B[${open}m${text}\u001B[${close}m`;
|
|
17
|
+
};
|
|
18
|
+
return {
|
|
19
|
+
enabled,
|
|
20
|
+
blue: style("blue"),
|
|
21
|
+
cyan: style("cyan"),
|
|
22
|
+
dim: style("dim"),
|
|
23
|
+
green: style("green"),
|
|
24
|
+
red: style("red"),
|
|
25
|
+
yellow: style("yellow"),
|
|
26
|
+
bold: style("bold"),
|
|
27
|
+
status(ok, okText = "ok", failText = "missing") {
|
|
28
|
+
return ok ? this.green(okText) : this.red(failText);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function colorsEnabled(output) {
|
|
33
|
+
if (process.env.NO_COLOR || process.env.SPECKIT_COLOR === "0")
|
|
34
|
+
return false;
|
|
35
|
+
if (process.env.FORCE_COLOR === "0")
|
|
36
|
+
return false;
|
|
37
|
+
if (process.env.FORCE_COLOR || process.env.SPECKIT_COLOR === "1")
|
|
38
|
+
return true;
|
|
39
|
+
return output?.isTTY ?? process.stdout.isTTY ?? false;
|
|
40
|
+
}
|
package/dist/core/scaffold.js
CHANGED
|
@@ -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>;
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { access, readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { extractSection, resolveStory } from "./story.js";
|
|
4
|
+
export async function buildTeamReport(root, target) {
|
|
5
|
+
const story = await resolveStory(root, target);
|
|
6
|
+
if (!story) {
|
|
7
|
+
return {
|
|
8
|
+
status: "blocked",
|
|
9
|
+
roles: [],
|
|
10
|
+
blockers: [`Story not found: ${target}`],
|
|
11
|
+
warnings: [],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const evidence = await readEvidence(root, story.evidencePath);
|
|
15
|
+
const roles = [
|
|
16
|
+
productOwner(story.content),
|
|
17
|
+
analyst(story.content),
|
|
18
|
+
architect(story.content),
|
|
19
|
+
developer(story.content),
|
|
20
|
+
await qa(story.evidencePath, evidence),
|
|
21
|
+
reviewer(evidence),
|
|
22
|
+
];
|
|
23
|
+
const blockers = roles.flatMap((role) => role.checks.filter((check) => !check.ok).map((check) => `${role.role}: ${check.name} - ${check.detail}`));
|
|
24
|
+
return {
|
|
25
|
+
status: blockers.length ? "blocked" : "ok",
|
|
26
|
+
story: {
|
|
27
|
+
id: story.id,
|
|
28
|
+
path: story.path,
|
|
29
|
+
title: story.title,
|
|
30
|
+
status: story.status,
|
|
31
|
+
evidencePath: story.evidencePath,
|
|
32
|
+
},
|
|
33
|
+
roles,
|
|
34
|
+
blockers,
|
|
35
|
+
warnings: story.status === "ready-for-dev" ? [] : [`Story status is ${story.status ?? "missing"}`],
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function productOwner(content) {
|
|
39
|
+
return role("Product Owner", [
|
|
40
|
+
check("business-goal", sectionHasDetail(content, "Business Goal") || sectionHasDetail(content, "Intent"), "Business goal or intent is filled"),
|
|
41
|
+
check("priority", sectionHasValue(content, "Business Goal", "Priority"), "Priority is recorded"),
|
|
42
|
+
]);
|
|
43
|
+
}
|
|
44
|
+
function analyst(content) {
|
|
45
|
+
return role("Analyst", [
|
|
46
|
+
check("acceptance-criteria", hasActionableAcceptanceCriteria(content), "Acceptance criteria are testable"),
|
|
47
|
+
check("edge-cases", sectionHasDetail(content, "Edge Cases") || sectionHasValue(content, "Dev Notes", "Edge cases"), "Edge cases are recorded"),
|
|
48
|
+
]);
|
|
49
|
+
}
|
|
50
|
+
function architect(content) {
|
|
51
|
+
return role("Architect", [
|
|
52
|
+
check("implementation-scope", sectionHasDetail(content, "Implementation Scope"), "Implementation scope is recorded"),
|
|
53
|
+
check("risk-notes", sectionHasDetail(content, "Architecture Notes") || sectionHasValue(content, "Notes", "Risks"), "Constraints or risks are recorded"),
|
|
54
|
+
]);
|
|
55
|
+
}
|
|
56
|
+
function developer(content) {
|
|
57
|
+
return role("Developer", [
|
|
58
|
+
check("dev-agent-record", sectionHasDetail(content, "Dev Agent Record"), "Dev Agent Record exists"),
|
|
59
|
+
check("file-list", subsectionHasDetail(content, "File List"), "File List has at least one entry"),
|
|
60
|
+
check("change-log", sectionHasDetail(content, "Change Log"), "Change Log is updated"),
|
|
61
|
+
]);
|
|
62
|
+
}
|
|
63
|
+
async function qa(evidencePath, evidence) {
|
|
64
|
+
return role("QA/Test", [
|
|
65
|
+
check("evidence-link", Boolean(evidencePath), evidencePath ?? "Missing linked evidence file"),
|
|
66
|
+
check("evidence-file", Boolean(evidence), evidencePath ?? "Missing linked evidence file"),
|
|
67
|
+
check("red-evidence", evidence ? sectionHasDetail(evidence, "Red") : false, "Red evidence is recorded"),
|
|
68
|
+
check("green-evidence", evidence ? sectionHasDetail(evidence, "Green") : false, "Green evidence is recorded"),
|
|
69
|
+
check("refactor-evidence", evidence ? sectionHasDetail(evidence, "Refactor") : false, "Refactor validation is recorded"),
|
|
70
|
+
]);
|
|
71
|
+
}
|
|
72
|
+
function reviewer(evidence) {
|
|
73
|
+
const checks = [
|
|
74
|
+
check("review-evidence", evidence ? sectionHasDetail(evidence, "Review Evidence") : false, "Review outcome is recorded"),
|
|
75
|
+
];
|
|
76
|
+
const report = role("Reviewer/Lead", checks);
|
|
77
|
+
return report.status === "blocked" ? { ...report, status: "waiting" } : report;
|
|
78
|
+
}
|
|
79
|
+
function role(roleName, checks) {
|
|
80
|
+
return {
|
|
81
|
+
role: roleName,
|
|
82
|
+
status: checks.every((item) => item.ok) ? "ok" : "blocked",
|
|
83
|
+
checks,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function check(name, ok, detail) {
|
|
87
|
+
return { name, ok, detail };
|
|
88
|
+
}
|
|
89
|
+
function hasActionableAcceptanceCriteria(content) {
|
|
90
|
+
const criteria = extractSection(content, "Acceptance Criteria");
|
|
91
|
+
if (!criteria)
|
|
92
|
+
return false;
|
|
93
|
+
return /Given .+|When .+|Then .+|AC\d+:/i.test(criteria) && !criteria.includes("...");
|
|
94
|
+
}
|
|
95
|
+
function sectionHasValue(content, heading, label) {
|
|
96
|
+
const section = extractSection(content, heading);
|
|
97
|
+
if (!section)
|
|
98
|
+
return false;
|
|
99
|
+
const pattern = new RegExp(`${escapeRegExp(label)}:\\s*\\S+`, "i");
|
|
100
|
+
return pattern.test(section);
|
|
101
|
+
}
|
|
102
|
+
function sectionHasDetail(content, heading) {
|
|
103
|
+
const section = extractSection(content, heading);
|
|
104
|
+
if (!section)
|
|
105
|
+
return false;
|
|
106
|
+
return hasDetail(section);
|
|
107
|
+
}
|
|
108
|
+
function subsectionHasDetail(content, heading) {
|
|
109
|
+
const lines = content.split("\n");
|
|
110
|
+
const start = lines.findIndex((line) => /^#{2,3}\s+/.test(line) && line.replace(/^#{2,3}\s+/, "").trim().toLowerCase() === heading.toLowerCase());
|
|
111
|
+
if (start === -1)
|
|
112
|
+
return false;
|
|
113
|
+
const collected = [];
|
|
114
|
+
for (const line of lines.slice(start + 1)) {
|
|
115
|
+
if (/^#{2,3}\s+/.test(line))
|
|
116
|
+
break;
|
|
117
|
+
collected.push(line);
|
|
118
|
+
}
|
|
119
|
+
return hasDetail(collected.join("\n"));
|
|
120
|
+
}
|
|
121
|
+
function hasDetail(section) {
|
|
122
|
+
return section
|
|
123
|
+
.split("\n")
|
|
124
|
+
.map((line) => line.replace(/^[-*\s]+/, "").trim())
|
|
125
|
+
.filter((line) => line && !line.startsWith("###"))
|
|
126
|
+
.some((line) => {
|
|
127
|
+
if (line.includes("..."))
|
|
128
|
+
return false;
|
|
129
|
+
if (/^[A-Za-z -]+:\s*$/.test(line))
|
|
130
|
+
return false;
|
|
131
|
+
if (/^(Command|Result|Reviewer|Outcome|Follow-ups):\s*$/i.test(line))
|
|
132
|
+
return false;
|
|
133
|
+
return true;
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async function readEvidence(root, evidencePath) {
|
|
137
|
+
if (!evidencePath)
|
|
138
|
+
return undefined;
|
|
139
|
+
try {
|
|
140
|
+
await access(join(root, evidencePath));
|
|
141
|
+
return await readFile(join(root, evidencePath), "utf8");
|
|
142
|
+
}
|
|
143
|
+
catch {
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function escapeRegExp(value) {
|
|
148
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
149
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { markdown } from "./managed-files.js";
|
|
2
|
+
export function teamFiles() {
|
|
3
|
+
return [
|
|
4
|
+
{
|
|
5
|
+
path: ".speckit/team/roles.md",
|
|
6
|
+
content: markdown(`# Spec Team Roles
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
Speckit maps team collaboration to owned artifacts. Roles do not imply separate people; one person can hold multiple roles, but every story must show which artifact is ready and which role is blocked.
|
|
11
|
+
|
|
12
|
+
## Roles
|
|
13
|
+
|
|
14
|
+
| Role | Owns | Exit Signal |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| Product Owner | business goal, priority, scope intent | story has clear business value |
|
|
17
|
+
| Analyst | acceptance criteria, edge cases, assumptions | story is testable |
|
|
18
|
+
| Architect | implementation scope, constraints, risks | dev can start without guessing |
|
|
19
|
+
| Developer | Dev Agent Record, File List, Change Log | implementation evidence is traceable |
|
|
20
|
+
| QA/Test | red, green, refactor evidence | behavior is validated |
|
|
21
|
+
| Reviewer/Lead | review evidence, approval, follow-ups | story can close |
|
|
22
|
+
`),
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
path: ".speckit/team/artifact-ownership.md",
|
|
26
|
+
content: markdown(`# Spec Artifact Ownership
|
|
27
|
+
|
|
28
|
+
## Story Artifacts
|
|
29
|
+
|
|
30
|
+
- Product Owner owns \`Business Goal\`, \`Priority\`, and high-level intent.
|
|
31
|
+
- Analyst owns \`Acceptance Criteria\`, \`Edge Cases\`, and assumptions.
|
|
32
|
+
- Architect owns \`Implementation Scope\`, \`Architecture Notes\`, and risks.
|
|
33
|
+
- Developer owns \`Dev Agent Record\`, \`File List\`, and \`Change Log\`.
|
|
34
|
+
- QA/Test owns the linked TDD evidence file.
|
|
35
|
+
- Reviewer/Lead owns review outcome and closure readiness.
|
|
36
|
+
|
|
37
|
+
## Rule
|
|
38
|
+
|
|
39
|
+
Do not move a story to the next gate by chat memory alone. Update the durable artifact first, then run \`speckit team status <story>\` or \`speckit team audit <story>\`.
|
|
40
|
+
`),
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
path: ".speckit/team/working-agreement.md",
|
|
44
|
+
content: markdown(`# Spec Working Agreement
|
|
45
|
+
|
|
46
|
+
## Agreements
|
|
47
|
+
|
|
48
|
+
- One story is the unit of planning, implementation, review, and closure.
|
|
49
|
+
- Every implementation story must have a linked TDD evidence file.
|
|
50
|
+
- Agents and humans hand off through files, not conversation history.
|
|
51
|
+
- Graph commands stay robot-safe through Speckit wrappers.
|
|
52
|
+
- Review blocks closure when acceptance criteria, evidence, or file traceability are missing.
|
|
53
|
+
`),
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
path: ".speckit/team/review-gates.md",
|
|
57
|
+
content: markdown(`# Spec Review Gates
|
|
58
|
+
|
|
59
|
+
## Gates
|
|
60
|
+
|
|
61
|
+
| Gate | Required Checks |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| shape | business goal, priority |
|
|
64
|
+
| ready | acceptance criteria, scope, context, graph sync |
|
|
65
|
+
| dev | Dev Agent Record, File List, Change Log |
|
|
66
|
+
| qa | red, green, refactor evidence |
|
|
67
|
+
| review | review outcome, follow-ups, unresolved risk |
|
|
68
|
+
| close | sync, compact summary, docs impact |
|
|
69
|
+
|
|
70
|
+
Run \`speckit team audit <story>\` before review and close.
|
|
71
|
+
`),
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
path: ".speckit/team/handoff-protocol.md",
|
|
75
|
+
content: markdown(`# Spec Handoff Protocol
|
|
76
|
+
|
|
77
|
+
## Handoff Contract
|
|
78
|
+
|
|
79
|
+
Each handoff must include:
|
|
80
|
+
|
|
81
|
+
- Story path and current status.
|
|
82
|
+
- From role and to role.
|
|
83
|
+
- Current blockers and warnings.
|
|
84
|
+
- Files changed or expected files to inspect.
|
|
85
|
+
- Test evidence state.
|
|
86
|
+
- Next role checklist.
|
|
87
|
+
|
|
88
|
+
Use \`speckit team handoff <story> --from <role> --to <role>\` to generate a durable handoff.
|
|
89
|
+
`),
|
|
90
|
+
},
|
|
91
|
+
];
|
|
92
|
+
}
|
package/dist/core/templates.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const storyTemplate = "---\nstatus: draft\nevidence: .speckit/evidence/{{slug}}-tdd-evidence.md\ncontext: pending\nstory_key: {{slug}}\nac_count: 0\n---\n\n# Story: {{title}}\n\n## Intent\n{{intent}}\n\n## Acceptance Criteria\n- AC1: Given ...\n When ...\n Then ...\n\n## Implementation Scope\n- In scope:\n- Out of scope:\n- Files likely to read:\n- Files likely to modify:\n\n## Dev Notes\n- Existing patterns to reuse:\n- Architecture constraints:\n- Edge cases:\n- Previous-story learnings:\n\n## Tasks / Subtasks\n- [ ] Map acceptance criteria to tests.\n- [ ] RED: create or identify failing test.\n- [ ] GREEN: implement minimum passing change.\n- [ ] REFACTOR: improve design while tests stay green.\n- [ ] Update evidence, file list, and change log.\n\n## TDD Checklist\n- [ ] Test targets identified\n- [ ] Red evidence recorded\n- [ ] Green evidence recorded\n- [ ] Refactor validation recorded\n\n## Notes\n- Risks:\n- Dependencies:\n\n## Dev Agent Record\n### Test Intent\n\n### Debug Log\n\n### Completion Notes\n\n### File List\n\n## Change Log\n- {{date}}: Story drafted.\n\n## Spec Anti-Mistake Checklist\n- Reuse existing project patterns before adding new files.\n- Verify file locations before editing.\n- Do not introduce new libraries without explicit need.\n- Preserve existing behavior unless an acceptance criterion requires change.\n- Capture previous-story learnings if this continues prior work.\n- Do not mark any task complete without test or validation evidence.\n";
|
|
1
|
+
export declare const storyTemplate = "---\nstatus: draft\nevidence: .speckit/evidence/{{slug}}-tdd-evidence.md\ncontext: pending\nstory_key: {{slug}}\nac_count: 0\n---\n\n# Story: {{title}}\n\n## Intent\n{{intent}}\n\n## Business Goal\n- Goal:\n- Priority: medium\n- Success signal:\n\n## Acceptance Criteria\n- AC1: Given ...\n When ...\n Then ...\n\n## Edge Cases\n- Boundary:\n- Error path:\n- State transition:\n\n## Implementation Scope\n- In scope:\n- Out of scope:\n- Files likely to read:\n- Files likely to modify:\n\n## Architecture Notes\n- Constraints:\n- Integration points:\n- Risks:\n\n## Dev Notes\n- Existing patterns to reuse:\n- Architecture constraints:\n- Edge cases:\n- Previous-story learnings:\n\n## Tasks / Subtasks\n- [ ] Map acceptance criteria to tests.\n- [ ] RED: create or identify failing test.\n- [ ] GREEN: implement minimum passing change.\n- [ ] REFACTOR: improve design while tests stay green.\n- [ ] Update evidence, file list, and change log.\n\n## TDD Checklist\n- [ ] Test targets identified\n- [ ] Red evidence recorded\n- [ ] Green evidence recorded\n- [ ] Refactor validation recorded\n\n## Notes\n- Risks:\n- Dependencies:\n\n## Dev Agent Record\n### Test Intent\n\n### Debug Log\n\n### Completion Notes\n\n### File List\n\n## Change Log\n- {{date}}: Story drafted.\n\n## Spec Anti-Mistake Checklist\n- Reuse existing project patterns before adding new files.\n- Verify file locations before editing.\n- Do not introduce new libraries without explicit need.\n- Preserve existing behavior unless an acceptance criterion requires change.\n- Capture previous-story learnings if this continues prior work.\n- Do not mark any task complete without test or validation evidence.\n";
|
|
2
2
|
export declare const tddEvidenceTemplate = "---\nstatus: missing\nstory: {{story}}\nphase: not-started\n---\n\n# TDD Evidence: {{story}}\n\n## Test Intent\n- Acceptance criteria covered:\n- Test files:\n- Command:\n\n## Red\n- Command:\n- Result:\n- Failing reason:\n\n## Green\n- Command:\n- Result:\n- Passing evidence:\n\n## Refactor\n- Command:\n- Result:\n- Regression evidence:\n\n## Review Evidence\n- Reviewer:\n- Outcome:\n- Follow-ups:\n";
|
package/dist/core/templates.js
CHANGED
|
@@ -11,17 +11,32 @@ ac_count: 0
|
|
|
11
11
|
## Intent
|
|
12
12
|
{{intent}}
|
|
13
13
|
|
|
14
|
+
## Business Goal
|
|
15
|
+
- Goal:
|
|
16
|
+
- Priority: medium
|
|
17
|
+
- Success signal:
|
|
18
|
+
|
|
14
19
|
## Acceptance Criteria
|
|
15
20
|
- AC1: Given ...
|
|
16
21
|
When ...
|
|
17
22
|
Then ...
|
|
18
23
|
|
|
24
|
+
## Edge Cases
|
|
25
|
+
- Boundary:
|
|
26
|
+
- Error path:
|
|
27
|
+
- State transition:
|
|
28
|
+
|
|
19
29
|
## Implementation Scope
|
|
20
30
|
- In scope:
|
|
21
31
|
- Out of scope:
|
|
22
32
|
- Files likely to read:
|
|
23
33
|
- Files likely to modify:
|
|
24
34
|
|
|
35
|
+
## Architecture Notes
|
|
36
|
+
- Constraints:
|
|
37
|
+
- Integration points:
|
|
38
|
+
- Risks:
|
|
39
|
+
|
|
25
40
|
## Dev Notes
|
|
26
41
|
- Existing patterns to reuse:
|
|
27
42
|
- Architecture constraints:
|
package/docs/adapters.md
CHANGED
|
@@ -14,6 +14,18 @@ Speckit compiles one workflow into native files for five IDEs.
|
|
|
14
14
|
|
|
15
15
|
Generated files include the `speckit:managed` marker. Speckit updates managed files idempotently and skips unmanaged files unless `--force` is provided.
|
|
16
16
|
|
|
17
|
+
## Shared Enterprise Contract
|
|
18
|
+
|
|
19
|
+
All adapters point agents back to the shared Speckit runtime:
|
|
20
|
+
|
|
21
|
+
- `.speckit/agents/super-agent.md`
|
|
22
|
+
- `.speckit/skills/catalog.md`
|
|
23
|
+
- `.speckit/team/*.md`
|
|
24
|
+
- `.speckit/context/current.md`
|
|
25
|
+
- `.speckit/context/subagent-handoff.md`
|
|
26
|
+
|
|
27
|
+
Adapters should not redefine team workflow rules independently. Update the shared generator and re-run `speckit init --enterprise --ide <name>` when the contract changes.
|
|
28
|
+
|
|
17
29
|
## Cursor Policy
|
|
18
30
|
|
|
19
31
|
Cursor uses `.cursor/rules/*.mdc`. Speckit does not generate the legacy `.cursorrules` file.
|
package/docs/code-standards.md
CHANGED
|
@@ -5,5 +5,7 @@
|
|
|
5
5
|
- Prefer deterministic file generation over runtime prompts.
|
|
6
6
|
- Use `writeManagedFiles` for generated files so unmanaged user files are protected.
|
|
7
7
|
- Keep adapter logic declarative: `name`, `displayName`, `outputPaths`, `render`.
|
|
8
|
+
- Keep enterprise evaluators artifact-based. Team status, audit, and score should inspect durable files instead of chat history.
|
|
9
|
+
- Keep public docs aligned with CLI help whenever a command is added.
|
|
8
10
|
- Add tests for command behavior and adapter contracts before expanding implementation scope.
|
|
9
11
|
- Do not invoke interactive external tools from automation paths.
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
Speckit MVP is implemented and pushed to `git@github.com:trieungoctam/speckit.git` on `main`.
|
|
6
6
|
|
|
7
|
-
Current package target: `@trieungoctam/speckit@0.
|
|
7
|
+
Current package target: `@trieungoctam/speckit@0.4.0`.
|
|
8
8
|
|
|
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
|
|
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 now exposes team-role workflow status, review-gate audit, handoff files, and runtime scoring.
|
|
10
10
|
|
|
11
11
|
## Milestones
|
|
12
12
|
|
|
@@ -20,17 +20,21 @@ The CLI is npx-ready, generates Agile + TDD rules, creates workflow artifacts, s
|
|
|
20
20
|
| Beads integration | MVP Complete | `graph setup` prints install commands and prepares `.beads/beads.jsonl`; `next` and `graph triage/plan/insights` wrap BV robot mode; `sync` exports story metadata JSONL. |
|
|
21
21
|
| Sprint automation | MVP Complete | `sprint plan` and `sprint next` select work from synced stories. |
|
|
22
22
|
| Enterprise harness | MVP Complete | `init --enterprise` creates flow, tool-policy, and prompt harness files; `doctor --deep` verifies them. |
|
|
23
|
+
| Enterprise team workflow | Complete | `init --enterprise` creates `.speckit/team/*`; `team status`, `team audit`, and `team handoff` expose role-owned artifacts and review blockers. |
|
|
24
|
+
| Runtime scoring | Complete | `score` reports project or story workflow health across contract, team, session/context, graph, TDD, and review categories. |
|
|
23
25
|
| Curated skill catalog | Complete | Speckit now generates focused phase skills, a schema, delegation statuses, and task hydration/sync-back guidance. |
|
|
24
26
|
| Workflow contract validator | Complete | `speckit validate` and `doctor --deep` check phase order, core skills, router terms, run prompt terms, and adapter parity. |
|
|
25
27
|
| Prompt architecture | Complete | Generated prompts now enforce artifact contracts, hard gates, common mistake prevention, TDD evidence, and review layers across adapters. |
|
|
26
28
|
| Permission policy | MVP Complete | `.speckit/permissions.yaml` and `permissions audit` cover privacy files, heavy paths, destructive commands, and release commands. |
|
|
27
29
|
| Validation | Complete | Build and `node:test` suite pass locally with flow contract gates. |
|
|
28
30
|
| GitHub publish | Complete | Initial code pushed to `trieungoctam/speckit` at commit `7e5c582`; status docs follow-up in progress. |
|
|
29
|
-
| npm package readiness | Ready | Package scoped as `@trieungoctam/speckit`; `npm pack --dry-run` passes. |
|
|
31
|
+
| npm package readiness | Ready | Package scoped as `@trieungoctam/speckit`; `npm pack --dry-run` passes for `0.4.0`. |
|
|
30
32
|
|
|
31
33
|
## Next Roadmap
|
|
32
34
|
|
|
35
|
+
- Add `score --threshold <n>` for CI gating after teams agree on rollout policy.
|
|
33
36
|
- Add `review --deep` with multi-layer acceptance, edge-case, and production-readiness prompts.
|
|
34
37
|
- Add graph drift and history correlation commands.
|
|
38
|
+
- Add lockfile and drift detection for generated Speckit contracts.
|
|
35
39
|
- Add GitHub trusted publishing for npm releases.
|
|
36
40
|
- Add snapshot tests for full adapter file contents.
|
|
@@ -6,9 +6,10 @@ Speckit works best as a repo-local standard, then as an organization template.
|
|
|
6
6
|
|
|
7
7
|
1. Pilot in one service repository with `speckit init --ide all`.
|
|
8
8
|
2. Require stories to include acceptance criteria and TDD evidence.
|
|
9
|
-
3.
|
|
10
|
-
4.
|
|
11
|
-
5.
|
|
9
|
+
3. Require `speckit team status <story>` before implementation handoff.
|
|
10
|
+
4. Add `speckit doctor`, `speckit validate`, `speckit score --json`, and project tests to CI.
|
|
11
|
+
5. Export stories with `speckit sync` for task graph visibility.
|
|
12
|
+
6. Roll the generated adapter pack into team templates.
|
|
12
13
|
|
|
13
14
|
## Governance Layers
|
|
14
15
|
|
|
@@ -16,12 +17,16 @@ Speckit works best as a repo-local standard, then as an organization template.
|
|
|
16
17
|
| --- | --- | --- |
|
|
17
18
|
| Company policy | Engineering leadership | `.speckit/rules/enterprise-safety.md` |
|
|
18
19
|
| Team workflow | Tech lead | `.speckit/workflows/*.md` |
|
|
20
|
+
| Team roles | Product / engineering lead | `.speckit/team/*.md` |
|
|
19
21
|
| Repo standard | Maintainers | `AGENTS.md`, `CLAUDE.md`, IDE config |
|
|
20
22
|
| Story evidence | Implementer | `.speckit/evidence/*.md` |
|
|
23
|
+
| Review readiness | Reviewer / lead | `speckit team audit <story>` |
|
|
21
24
|
|
|
22
25
|
## Recommended Controls
|
|
23
26
|
|
|
24
27
|
- Do not allow code stories to merge without red-green-refactor evidence.
|
|
25
28
|
- Keep adapter output generated from Speckit instead of hand-maintaining per-IDE rules.
|
|
26
29
|
- Treat `speckit doctor` warnings as rollout debt.
|
|
30
|
+
- Treat `speckit score` as the adoption health metric. Start non-blocking, then define a threshold after the pilot.
|
|
31
|
+
- Use `speckit team handoff` whenever work moves from development to QA or review.
|
|
27
32
|
- Use Beads Viewer only through robot commands for non-interactive automation.
|