@ifi/pi-spec 0.2.14

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.
@@ -0,0 +1,124 @@
1
+ import type { WorkflowPromptContext } from "./types.js";
2
+
3
+ function formatChecklistBlock(checklists: WorkflowPromptContext["checklists"]): string[] {
4
+ if (!checklists || checklists.length === 0) {
5
+ return ["- No checklist files found."];
6
+ }
7
+ return checklists.map((checklist) => {
8
+ const status = checklist.incomplete === 0 ? "PASS" : "FAIL";
9
+ return `- ${checklist.name}: ${status} (${checklist.completed}/${checklist.total} complete, ${checklist.incomplete} incomplete) — ${checklist.path}`;
10
+ });
11
+ }
12
+
13
+ export function buildWorkflowPrompt(context: WorkflowPromptContext): string {
14
+ const lines = [
15
+ `You are executing the native /spec ${context.step} workflow inside pi.`,
16
+ "",
17
+ "## Native runtime notes",
18
+ "- Do NOT run any shell or PowerShell scripts referenced by the workflow template.",
19
+ "- Do NOT rely on the external spec-kit CLI. This pi extension has already prepared the local workspace and resolved the relevant paths.",
20
+ "- Treat any `/speckit.<name>` references in the workflow template as the equivalent `/spec <name>` step.",
21
+ "- Use pi's built-in tools directly to read, edit, write, grep, find, and run validation commands.",
22
+ "- Use `.specify/memory/pi-agent.md` as the native pi replacement for agent-specific context files or update-agent-context scripts.",
23
+ "",
24
+ "## Prepared workspace",
25
+ `- Repository root: ${context.paths.repoRoot}`,
26
+ `- Current branch: ${context.currentBranch}`,
27
+ `- Workflow template to follow: ${context.workflowTemplatePath}`,
28
+ `- Workflow README: ${context.paths.workflowReadmeFile}`,
29
+ `- Template directory: ${context.paths.templatesDir}`,
30
+ `- Constitution file: ${context.paths.constitutionFile}`,
31
+ `- Pi agent context file: ${context.paths.agentContextFile}`,
32
+ `- Extensions config: ${context.paths.extensionsConfigFile}`,
33
+ ];
34
+
35
+ if (context.paths.featureBranch) {
36
+ lines.push(`- Active feature branch/name: ${context.paths.featureBranch}`);
37
+ }
38
+ if (context.paths.featureDir) {
39
+ lines.push(`- Feature directory: ${context.paths.featureDir}`);
40
+ }
41
+ if (context.paths.featureSpec) {
42
+ lines.push(`- Feature spec: ${context.paths.featureSpec}`);
43
+ }
44
+ if (context.paths.planFile) {
45
+ lines.push(`- Implementation plan: ${context.paths.planFile}`);
46
+ }
47
+ if (context.paths.tasksFile) {
48
+ lines.push(`- Task list: ${context.paths.tasksFile}`);
49
+ }
50
+ if (context.paths.researchFile) {
51
+ lines.push(`- Research file: ${context.paths.researchFile}`);
52
+ }
53
+ if (context.paths.dataModelFile) {
54
+ lines.push(`- Data model: ${context.paths.dataModelFile}`);
55
+ }
56
+ if (context.paths.quickstartFile) {
57
+ lines.push(`- Quickstart: ${context.paths.quickstartFile}`);
58
+ }
59
+ if (context.paths.contractsDir) {
60
+ lines.push(`- Contracts directory: ${context.paths.contractsDir}`);
61
+ }
62
+ if (context.paths.checklistsDir) {
63
+ lines.push(`- Checklists directory: ${context.paths.checklistsDir}`);
64
+ }
65
+
66
+ if (context.stepNotes.length > 0) {
67
+ lines.push("", "## Step-specific notes", ...context.stepNotes.map((note) => `- ${note}`));
68
+ }
69
+
70
+ if (context.step === "implement") {
71
+ lines.push("", "## Checklist status", ...formatChecklistBlock(context.checklists));
72
+ }
73
+
74
+ lines.push(
75
+ "",
76
+ "## User input from the slash command",
77
+ context.input.trim() || "(none)",
78
+ "",
79
+ "## Execution instructions",
80
+ "1. Read the workflow template path listed above before making changes.",
81
+ "2. Substitute the prepared paths above anywhere the original template expects script output variables.",
82
+ "3. If the template references optional hooks in `.specify/extensions.yml`, inspect that file manually instead of expecting automatic shell execution.",
83
+ "4. Perform the work directly in this repository using pi tools and then summarize what changed, what remains, and the next recommended `/spec` command.",
84
+ );
85
+
86
+ return lines.join("\n");
87
+ }
88
+
89
+ export function getStepNotes(step: WorkflowPromptContext["step"]): string[] {
90
+ switch (step) {
91
+ case "constitution":
92
+ return [
93
+ "Keep the constitution in `.specify/memory/constitution.md` as the canonical governance file.",
94
+ "When propagating changes, prefer updating `.specify/templates/*` and `.specify/memory/pi-agent.md` over agent-specific script outputs.",
95
+ ];
96
+ case "specify":
97
+ return [
98
+ "The native /spec runtime has already generated the feature number, branch name, feature directory, and spec scaffold.",
99
+ "Do not create a second feature branch or rerun any feature-creation shell scripts.",
100
+ ];
101
+ case "clarify":
102
+ return [
103
+ "Ask at most five high-impact clarification questions and update the spec incrementally after each accepted answer.",
104
+ ];
105
+ case "checklist":
106
+ return ["Generate checklist items that test requirement quality, not implementation behavior."];
107
+ case "plan":
108
+ return [
109
+ "The native /spec runtime has already scaffolded `plan.md` if it was missing.",
110
+ "Use `.specify/memory/pi-agent.md` as the pi-native output in place of agent-specific update scripts.",
111
+ ];
112
+ case "tasks":
113
+ return [
114
+ "Organize tasks by independently testable user stories and preserve the strict checkbox format from the template.",
115
+ ];
116
+ case "analyze":
117
+ return ["Keep the analysis strictly read-only; do not edit files during this step."];
118
+ case "implement":
119
+ return [
120
+ "Mark completed tasks as `[x]` in tasks.md as you implement them.",
121
+ "If checklists are incomplete, respect the user's decision about whether to proceed.",
122
+ ];
123
+ }
124
+ }
@@ -0,0 +1,151 @@
1
+ import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import type { WorkflowPaths } from "./types.js";
5
+
6
+ const WORKFLOW_README = `# Native /spec Workflow
7
+
8
+ This project uses the native pi spec workflow inspired by GitHub spec-kit.
9
+
10
+ ## Core commands
11
+
12
+ - /spec init
13
+ - /spec constitution <principles>
14
+ - /spec specify <feature description>
15
+ - /spec clarify [focus]
16
+ - /spec checklist [domain]
17
+ - /spec plan <technical context>
18
+ - /spec tasks [context]
19
+ - /spec analyze [focus]
20
+ - /spec implement [focus]
21
+ - /spec status
22
+ - /spec next
23
+
24
+ ## Runtime notes
25
+
26
+ - The pi extension handles feature numbering, branch naming, path resolution, and file scaffolding in TypeScript.
27
+ - Workflow templates live in .specify/templates/commands/ and can be customized per project.
28
+ - File templates live in .specify/templates/.
29
+ - The native replacement for agent-specific context files is .specify/memory/pi-agent.md.
30
+ - Feature artifacts live in specs/###-feature-name/.
31
+ `;
32
+
33
+ const DEFAULT_EXTENSIONS_YML = `settings:
34
+ auto_execute_hooks: true
35
+ hooks: {}
36
+ `;
37
+
38
+ function getExtensionRoot(): string {
39
+ return path.dirname(fileURLToPath(import.meta.url));
40
+ }
41
+
42
+ function getBundledTemplatesRoot(): string {
43
+ return path.join(getExtensionRoot(), "assets", "templates");
44
+ }
45
+
46
+ function ensureDir(dir: string): void {
47
+ mkdirSync(dir, { recursive: true });
48
+ }
49
+
50
+ function copyDirIfMissing(sourceDir: string, targetDir: string): void {
51
+ ensureDir(targetDir);
52
+ for (const entry of readdirSync(sourceDir)) {
53
+ const sourcePath = path.join(sourceDir, entry);
54
+ const targetPath = path.join(targetDir, entry);
55
+ const sourceStat = statSync(sourcePath);
56
+ if (sourceStat.isDirectory()) {
57
+ copyDirIfMissing(sourcePath, targetPath);
58
+ continue;
59
+ }
60
+ if (!existsSync(targetPath)) {
61
+ copyFileSync(sourcePath, targetPath);
62
+ }
63
+ }
64
+ }
65
+
66
+ export function ensureWorkflowScaffold(paths: WorkflowPaths): string[] {
67
+ const created: string[] = [];
68
+ ensureDir(paths.specifyDir);
69
+ ensureDir(paths.specsDir);
70
+ ensureDir(paths.templatesDir);
71
+ ensureDir(paths.memoryDir);
72
+
73
+ const beforeTemplates = new Set<string>();
74
+ if (existsSync(paths.templatesDir)) {
75
+ for (const entry of readdirSync(paths.templatesDir)) {
76
+ beforeTemplates.add(entry);
77
+ }
78
+ }
79
+
80
+ copyDirIfMissing(getBundledTemplatesRoot(), paths.templatesDir);
81
+
82
+ for (const entry of readdirSync(paths.templatesDir)) {
83
+ if (!beforeTemplates.has(entry)) {
84
+ created.push(path.join(paths.templatesDir, entry));
85
+ }
86
+ }
87
+
88
+ if (!existsSync(paths.workflowReadmeFile)) {
89
+ writeFileSync(paths.workflowReadmeFile, WORKFLOW_README, "utf8");
90
+ created.push(paths.workflowReadmeFile);
91
+ }
92
+ if (!existsSync(paths.extensionsConfigFile)) {
93
+ writeFileSync(paths.extensionsConfigFile, DEFAULT_EXTENSIONS_YML, "utf8");
94
+ created.push(paths.extensionsConfigFile);
95
+ }
96
+ if (!existsSync(paths.constitutionFile)) {
97
+ const template = readFileSync(path.join(paths.templatesDir, "constitution-template.md"), "utf8");
98
+ writeFileSync(paths.constitutionFile, template, "utf8");
99
+ created.push(paths.constitutionFile);
100
+ }
101
+ if (!existsSync(paths.agentContextFile)) {
102
+ const template = readFileSync(path.join(paths.templatesDir, "agent-file-template.md"), "utf8");
103
+ writeFileSync(paths.agentContextFile, template, "utf8");
104
+ created.push(paths.agentContextFile);
105
+ }
106
+
107
+ return created;
108
+ }
109
+
110
+ export function ensureFeatureArtifacts(paths: WorkflowPaths): string[] {
111
+ if (!(paths.featureDir && paths.featureSpec && paths.checklistsDir)) {
112
+ return [];
113
+ }
114
+
115
+ const created: string[] = [];
116
+ ensureDir(paths.featureDir);
117
+ ensureDir(paths.checklistsDir);
118
+ if (!existsSync(paths.featureSpec)) {
119
+ const template = readFileSync(path.join(paths.templatesDir, "spec-template.md"), "utf8");
120
+ writeFileSync(paths.featureSpec, template, "utf8");
121
+ created.push(paths.featureSpec);
122
+ }
123
+ return created;
124
+ }
125
+
126
+ export function ensurePlanArtifact(paths: WorkflowPaths): string[] {
127
+ if (!(paths.featureDir && paths.planFile && paths.contractsDir)) {
128
+ return [];
129
+ }
130
+
131
+ const created: string[] = [];
132
+ ensureDir(paths.featureDir);
133
+ ensureDir(paths.contractsDir);
134
+ if (!existsSync(paths.planFile)) {
135
+ const template = readFileSync(path.join(paths.templatesDir, "plan-template.md"), "utf8");
136
+ writeFileSync(paths.planFile, template, "utf8");
137
+ created.push(paths.planFile);
138
+ }
139
+ return created;
140
+ }
141
+
142
+ export function getWorkflowTemplatePath(paths: WorkflowPaths, name: string): string {
143
+ return path.join(paths.templatesDir, "commands", `${name}.md`);
144
+ }
145
+
146
+ export function formatCreatedFiles(created: string[]): string {
147
+ if (created.length === 0) {
148
+ return "No new scaffold files were needed.";
149
+ }
150
+ return `Created ${created.length} scaffold file(s):\n${created.map((file) => `- ${file}`).join("\n")}`;
151
+ }
@@ -0,0 +1,231 @@
1
+ import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
+ import path from "node:path";
3
+ import type { ChecklistSummary, WorkflowPaths, WorkflowStatus } from "./types.js";
4
+ import { getLatestFeatureDir, listFeatureDirs } from "./workspace.js";
5
+
6
+ function countChecklistItems(content: string): { total: number; completed: number; incomplete: number } {
7
+ const lines = content.split(/\r?\n/);
8
+ let total = 0;
9
+ let completed = 0;
10
+ let incomplete = 0;
11
+ for (const line of lines) {
12
+ if (/^- \[(?: |x|X)\]/.test(line)) {
13
+ total++;
14
+ if (/^- \[(?:x|X)\]/.test(line)) {
15
+ completed++;
16
+ } else {
17
+ incomplete++;
18
+ }
19
+ }
20
+ }
21
+ return { total, completed, incomplete };
22
+ }
23
+
24
+ export function summarizeChecklists(checklistsDir?: string): ChecklistSummary[] {
25
+ if (!(checklistsDir && existsSync(checklistsDir))) {
26
+ return [];
27
+ }
28
+
29
+ return readdirSync(checklistsDir)
30
+ .filter((entry) => entry.endsWith(".md"))
31
+ .map((entry) => {
32
+ const fullPath = path.join(checklistsDir, entry);
33
+ const content = readFileSync(fullPath, "utf8");
34
+ const counts = countChecklistItems(content);
35
+ return {
36
+ name: entry,
37
+ path: fullPath,
38
+ ...counts,
39
+ status: counts.incomplete === 0 ? "pass" : "fail",
40
+ } satisfies ChecklistSummary;
41
+ })
42
+ .sort((a, b) => a.name.localeCompare(b.name));
43
+ }
44
+
45
+ function nextStepsFor(paths: WorkflowPaths, initialized: boolean): string[] {
46
+ if (!initialized) {
47
+ return ["/spec init", "/spec constitution <principles>", "/spec specify <feature description>"];
48
+ }
49
+
50
+ if (!(paths.featureDir && paths.featureSpec)) {
51
+ return ["/spec specify <feature description>", "/spec list"];
52
+ }
53
+
54
+ const steps: string[] = [];
55
+ const specExists = existsSync(paths.featureSpec);
56
+ const planExists = !!paths.planFile && existsSync(paths.planFile);
57
+ const tasksExist = !!paths.tasksFile && existsSync(paths.tasksFile);
58
+ const checklists = summarizeChecklists(paths.checklistsDir);
59
+ const hasIncompleteChecklist = checklists.some((checklist) => checklist.incomplete > 0);
60
+
61
+ if (!specExists) {
62
+ steps.push("/spec specify <feature description>");
63
+ return steps;
64
+ }
65
+
66
+ steps.push("/spec clarify");
67
+ steps.push("/spec checklist quality");
68
+
69
+ if (!planExists) {
70
+ steps.push("/spec plan <technical context>");
71
+ return steps;
72
+ }
73
+
74
+ if (!tasksExist) {
75
+ steps.push("/spec tasks");
76
+ return steps;
77
+ }
78
+
79
+ steps.push("/spec analyze");
80
+ steps.push(hasIncompleteChecklist ? "/spec implement (after checklist review)" : "/spec implement");
81
+ return steps;
82
+ }
83
+
84
+ export function buildWorkflowStatus(options: {
85
+ repoRoot: string;
86
+ currentBranch: string;
87
+ paths: WorkflowPaths;
88
+ activeFeature?: string;
89
+ }): WorkflowStatus {
90
+ const featureDirs = listFeatureDirs(options.repoRoot);
91
+ const activeFeature = options.activeFeature ?? getLatestFeatureDir(options.repoRoot);
92
+ const initialized = existsSync(options.paths.specifyDir);
93
+ const artifacts = [
94
+ {
95
+ label: ".specify/README.md",
96
+ path: options.paths.workflowReadmeFile,
97
+ exists: existsSync(options.paths.workflowReadmeFile),
98
+ },
99
+ {
100
+ label: "constitution.md",
101
+ path: options.paths.constitutionFile,
102
+ exists: existsSync(options.paths.constitutionFile),
103
+ },
104
+ { label: "pi-agent.md", path: options.paths.agentContextFile, exists: existsSync(options.paths.agentContextFile) },
105
+ {
106
+ label: "extensions.yml",
107
+ path: options.paths.extensionsConfigFile,
108
+ exists: existsSync(options.paths.extensionsConfigFile),
109
+ },
110
+ ];
111
+
112
+ if (options.paths.featureSpec) {
113
+ artifacts.push({
114
+ label: "spec.md",
115
+ path: options.paths.featureSpec,
116
+ exists: existsSync(options.paths.featureSpec),
117
+ });
118
+ }
119
+ if (options.paths.planFile) {
120
+ artifacts.push({ label: "plan.md", path: options.paths.planFile, exists: existsSync(options.paths.planFile) });
121
+ }
122
+ if (options.paths.tasksFile) {
123
+ artifacts.push({ label: "tasks.md", path: options.paths.tasksFile, exists: existsSync(options.paths.tasksFile) });
124
+ }
125
+ if (options.paths.researchFile) {
126
+ artifacts.push({
127
+ label: "research.md",
128
+ path: options.paths.researchFile,
129
+ exists: existsSync(options.paths.researchFile),
130
+ });
131
+ }
132
+ if (options.paths.dataModelFile) {
133
+ artifacts.push({
134
+ label: "data-model.md",
135
+ path: options.paths.dataModelFile,
136
+ exists: existsSync(options.paths.dataModelFile),
137
+ });
138
+ }
139
+ if (options.paths.quickstartFile) {
140
+ artifacts.push({
141
+ label: "quickstart.md",
142
+ path: options.paths.quickstartFile,
143
+ exists: existsSync(options.paths.quickstartFile),
144
+ });
145
+ }
146
+ if (options.paths.contractsDir) {
147
+ artifacts.push({
148
+ label: "contracts/",
149
+ path: options.paths.contractsDir,
150
+ exists: existsSync(options.paths.contractsDir) && statSync(options.paths.contractsDir).isDirectory(),
151
+ });
152
+ }
153
+
154
+ return {
155
+ initialized,
156
+ repoRoot: options.repoRoot,
157
+ currentBranch: options.currentBranch,
158
+ featureDirs,
159
+ activeFeature,
160
+ paths: options.paths,
161
+ artifacts,
162
+ checklists: summarizeChecklists(options.paths.checklistsDir),
163
+ nextSteps: nextStepsFor(options.paths, initialized),
164
+ };
165
+ }
166
+
167
+ export function formatWorkflowStatus(status: WorkflowStatus): string {
168
+ const lines = [
169
+ "# /spec workflow status",
170
+ "",
171
+ `- Repository root: ${status.repoRoot}`,
172
+ `- Initialized: ${status.initialized ? "yes" : "no"}`,
173
+ `- Current branch: ${status.currentBranch}`,
174
+ `- Active feature: ${status.activeFeature ?? "(none)"}`,
175
+ `- Known features: ${status.featureDirs.length > 0 ? status.featureDirs.join(", ") : "(none)"}`,
176
+ "",
177
+ "## Artifacts",
178
+ ];
179
+
180
+ for (const artifact of status.artifacts) {
181
+ lines.push(`- ${artifact.exists ? "✅" : "⬜"} ${artifact.label} — ${artifact.path}`);
182
+ }
183
+
184
+ lines.push("", "## Checklist status");
185
+ if (status.checklists.length === 0) {
186
+ lines.push("- No checklist files found.");
187
+ } else {
188
+ for (const checklist of status.checklists) {
189
+ lines.push(
190
+ `- ${checklist.status === "pass" ? "✅" : "⚠️"} ${checklist.name}: ${checklist.completed}/${checklist.total} complete (${checklist.incomplete} incomplete)`,
191
+ );
192
+ }
193
+ }
194
+
195
+ lines.push("", "## Next steps");
196
+ for (const step of status.nextSteps) {
197
+ lines.push(`- ${step}`);
198
+ }
199
+ return lines.join("\n");
200
+ }
201
+
202
+ export function formatHelpReport(): string {
203
+ return [
204
+ "# Native /spec workflow",
205
+ "",
206
+ "Use `/spec` with one of these subcommands:",
207
+ "",
208
+ "- `/spec init` — scaffold `.specify/`, templates, and memory files",
209
+ "- `/spec constitution <principles>` — create or amend the project constitution",
210
+ "- `/spec specify <feature description>` — create a numbered feature branch and spec scaffold",
211
+ "- `/spec clarify [focus]` — resolve critical ambiguities in the active spec",
212
+ "- `/spec checklist [domain]` — generate a requirements-quality checklist",
213
+ "- `/spec plan <technical context>` — build the implementation plan and design artifacts",
214
+ "- `/spec tasks [context]` — derive an executable tasks.md ordered by user story",
215
+ "- `/spec analyze [focus]` — run a read-only cross-artifact consistency review",
216
+ "- `/spec implement [focus]` — execute the plan from tasks.md and mark completed tasks",
217
+ "- `/spec status` — show current workflow state",
218
+ "- `/spec next` — show the next recommended command",
219
+ "- `/spec list` — list all known feature directories",
220
+ "",
221
+ "Tip: `/spec` with no arguments shows the current workflow status.",
222
+ ].join("\n");
223
+ }
224
+
225
+ export function formatFeatureList(repoRoot: string): string {
226
+ const features = listFeatureDirs(repoRoot);
227
+ if (features.length === 0) {
228
+ return "# Known features\n\n- No feature directories found yet.";
229
+ }
230
+ return `# Known features\n\n${features.map((feature) => `- ${feature}`).join("\n")}`;
231
+ }
@@ -0,0 +1,93 @@
1
+ export const SPEC_SUBCOMMANDS = [
2
+ "status",
3
+ "help",
4
+ "init",
5
+ "constitution",
6
+ "specify",
7
+ "clarify",
8
+ "checklist",
9
+ "plan",
10
+ "tasks",
11
+ "analyze",
12
+ "implement",
13
+ "list",
14
+ "next",
15
+ ] as const;
16
+
17
+ export type SpecSubcommand = (typeof SPEC_SUBCOMMANDS)[number];
18
+
19
+ export const WORKFLOW_STEPS = [
20
+ "constitution",
21
+ "specify",
22
+ "clarify",
23
+ "checklist",
24
+ "plan",
25
+ "tasks",
26
+ "analyze",
27
+ "implement",
28
+ ] as const;
29
+
30
+ export type WorkflowStep = (typeof WORKFLOW_STEPS)[number];
31
+
32
+ export interface WorkflowPaths {
33
+ repoRoot: string;
34
+ specsDir: string;
35
+ specifyDir: string;
36
+ templatesDir: string;
37
+ memoryDir: string;
38
+ constitutionFile: string;
39
+ agentContextFile: string;
40
+ extensionsConfigFile: string;
41
+ workflowReadmeFile: string;
42
+ featureDir?: string;
43
+ featureBranch?: string;
44
+ featureNumber?: string;
45
+ featureSpec?: string;
46
+ planFile?: string;
47
+ tasksFile?: string;
48
+ researchFile?: string;
49
+ dataModelFile?: string;
50
+ quickstartFile?: string;
51
+ contractsDir?: string;
52
+ checklistsDir?: string;
53
+ }
54
+
55
+ export interface WorkflowStatus {
56
+ initialized: boolean;
57
+ repoRoot: string;
58
+ currentBranch: string;
59
+ featureDirs: string[];
60
+ activeFeature?: string;
61
+ paths: WorkflowPaths;
62
+ artifacts: Array<{ label: string; path: string; exists: boolean }>;
63
+ checklists: ChecklistSummary[];
64
+ nextSteps: string[];
65
+ }
66
+
67
+ export interface ChecklistSummary {
68
+ name: string;
69
+ path: string;
70
+ total: number;
71
+ completed: number;
72
+ incomplete: number;
73
+ status: "pass" | "fail";
74
+ }
75
+
76
+ export interface PreparedFeature {
77
+ branchName: string;
78
+ featureNumber: string;
79
+ featureDir: string;
80
+ specFile: string;
81
+ checklistsDir: string;
82
+ createdBranch: boolean;
83
+ }
84
+
85
+ export interface WorkflowPromptContext {
86
+ step: WorkflowStep;
87
+ input: string;
88
+ paths: WorkflowPaths;
89
+ currentBranch: string;
90
+ workflowTemplatePath: string;
91
+ stepNotes: string[];
92
+ checklists?: ChecklistSummary[];
93
+ }