spets 0.1.10 → 0.1.12
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/dist/{chunk-NOS3N4GT.js → chunk-L3K6T5GO.js} +1 -17
- package/dist/index.js +191 -64
- package/dist/{state-54IS3PZH.js → state-3SI6H5IW.js} +1 -3
- package/package.json +3 -2
- package/templates/steps/01-plan/instruction.md +327 -0
- package/templates/steps/01-plan/template.md +460 -0
- package/templates/steps/02-implement/instruction.md +423 -0
- package/templates/steps/02-implement/template.md +435 -0
|
@@ -302,21 +302,6 @@ function loadTaskMetadata(taskId, cwd = process.cwd()) {
|
|
|
302
302
|
}
|
|
303
303
|
return JSON.parse(readFileSync2(metaPath, "utf-8"));
|
|
304
304
|
}
|
|
305
|
-
function extractPlanSummary(taskId, cwd = process.cwd()) {
|
|
306
|
-
const doc = loadDocument(taskId, "01-plan", cwd);
|
|
307
|
-
if (!doc) {
|
|
308
|
-
return null;
|
|
309
|
-
}
|
|
310
|
-
const summaryMatch = doc.content.match(/## Summary\n\n(.+?)(?=\n\n##|\n\n$|$)/s);
|
|
311
|
-
if (summaryMatch) {
|
|
312
|
-
return summaryMatch[1].trim();
|
|
313
|
-
}
|
|
314
|
-
const goalMatch = doc.content.match(/## Goal\n\n(.+?)(?=\n\n##|\n\n$|$)/s);
|
|
315
|
-
if (goalMatch) {
|
|
316
|
-
return goalMatch[1].trim();
|
|
317
|
-
}
|
|
318
|
-
return null;
|
|
319
|
-
}
|
|
320
305
|
|
|
321
306
|
export {
|
|
322
307
|
getSpetsDir,
|
|
@@ -338,6 +323,5 @@ export {
|
|
|
338
323
|
listTasks,
|
|
339
324
|
getWorkflowState,
|
|
340
325
|
saveTaskMetadata,
|
|
341
|
-
loadTaskMetadata
|
|
342
|
-
extractPlanSummary
|
|
326
|
+
loadTaskMetadata
|
|
343
327
|
};
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
saveTaskMetadata,
|
|
17
17
|
spetsExists,
|
|
18
18
|
updateDocumentStatus
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-L3K6T5GO.js";
|
|
20
20
|
|
|
21
21
|
// src/index.ts
|
|
22
22
|
import { Command } from "commander";
|
|
@@ -121,19 +121,19 @@ function createDefaultSteps(spetsDir) {
|
|
|
121
121
|
writeFileSync(join(implementDir, "template.md"), getImplementTemplate());
|
|
122
122
|
}
|
|
123
123
|
function getPlanInstruction() {
|
|
124
|
-
const fullTemplate = readFileSync(join(__dirname, "..", "
|
|
124
|
+
const fullTemplate = readFileSync(join(__dirname, "..", "templates", "steps", "01-plan", "instruction.md"), "utf-8");
|
|
125
125
|
return fullTemplate;
|
|
126
126
|
}
|
|
127
127
|
function getPlanTemplate() {
|
|
128
|
-
const fullTemplate = readFileSync(join(__dirname, "..", "
|
|
128
|
+
const fullTemplate = readFileSync(join(__dirname, "..", "templates", "steps", "01-plan", "template.md"), "utf-8");
|
|
129
129
|
return fullTemplate;
|
|
130
130
|
}
|
|
131
131
|
function getImplementInstruction() {
|
|
132
|
-
const fullTemplate = readFileSync(join(__dirname, "..", "
|
|
132
|
+
const fullTemplate = readFileSync(join(__dirname, "..", "templates", "steps", "02-implement", "instruction.md"), "utf-8");
|
|
133
133
|
return fullTemplate;
|
|
134
134
|
}
|
|
135
135
|
function getImplementTemplate() {
|
|
136
|
-
const fullTemplate = readFileSync(join(__dirname, "..", "
|
|
136
|
+
const fullTemplate = readFileSync(join(__dirname, "..", "templates", "steps", "02-implement", "template.md"), "utf-8");
|
|
137
137
|
return fullTemplate;
|
|
138
138
|
}
|
|
139
139
|
function createClaudeCommand(cwd) {
|
|
@@ -503,17 +503,12 @@ jobs:
|
|
|
503
503
|
run: npm ci
|
|
504
504
|
|
|
505
505
|
- name: Run Spets command
|
|
506
|
-
id: spets
|
|
507
506
|
run: |
|
|
508
507
|
npx spets github --issue ${gh("github.event.issue.number")} --comment "$COMMENT"
|
|
509
|
-
# Check if PR should be created
|
|
510
|
-
if [[ "$COMMENT" == "/approve --pr"* ]]; then
|
|
511
|
-
echo "create_pr=true" >> $GITHUB_OUTPUT
|
|
512
|
-
fi
|
|
513
508
|
env:
|
|
514
509
|
COMMENT: ${gh("github.event.comment.body")}
|
|
515
510
|
CLAUDE_CODE_OAUTH_TOKEN: ${gh("secrets.CLAUDE_CODE_OAUTH_TOKEN")}
|
|
516
|
-
GH_TOKEN: ${gh("secrets.
|
|
511
|
+
GH_TOKEN: ${gh("secrets.PAT_TOKEN")}
|
|
517
512
|
|
|
518
513
|
- name: Push changes
|
|
519
514
|
run: |
|
|
@@ -521,29 +516,6 @@ jobs:
|
|
|
521
516
|
git add -A
|
|
522
517
|
git diff --staged --quiet || git commit -m "Spets: Update from #${gh("github.event.issue.number")}"
|
|
523
518
|
git push
|
|
524
|
-
|
|
525
|
-
- name: Create PR
|
|
526
|
-
if: steps.spets.outputs.create_pr == 'true'
|
|
527
|
-
run: |
|
|
528
|
-
PR_BODY="Closes #${gh("github.event.issue.number")}
|
|
529
|
-
|
|
530
|
-
---
|
|
531
|
-
|
|
532
|
-
## Spets Commands
|
|
533
|
-
|
|
534
|
-
| Command | Description |
|
|
535
|
-
|---------|-------------|
|
|
536
|
-
| \\\`/approve\\\` | Approve current step and continue |
|
|
537
|
-
| \\\`/approve --pr\\\` | Approve and create PR |
|
|
538
|
-
| \\\`/revise <feedback>\\\` | Request changes with feedback |
|
|
539
|
-
| \\\`/reject\\\` | Reject and stop workflow |"
|
|
540
|
-
|
|
541
|
-
gh pr create \\
|
|
542
|
-
--title "Spets: Issue #${gh("github.event.issue.number")}" \\
|
|
543
|
-
--body "$PR_BODY" \\
|
|
544
|
-
--repo ${gh("github.repository")}
|
|
545
|
-
env:
|
|
546
|
-
GH_TOKEN: ${gh("secrets.PAT_TOKEN")}
|
|
547
519
|
`;
|
|
548
520
|
}
|
|
549
521
|
|
|
@@ -1834,7 +1806,9 @@ request: The user's task description for the workflow
|
|
|
1834
1806
|
}
|
|
1835
1807
|
|
|
1836
1808
|
// src/commands/github.ts
|
|
1837
|
-
import { execSync as execSync4 } from "child_process";
|
|
1809
|
+
import { execSync as execSync4, spawn as spawn4 } from "child_process";
|
|
1810
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync2, existsSync as existsSync4 } from "fs";
|
|
1811
|
+
import { join as join4 } from "path";
|
|
1838
1812
|
function getGitHubInfo2(cwd) {
|
|
1839
1813
|
const config = getGitHubConfig(cwd);
|
|
1840
1814
|
if (config?.owner && config?.repo) {
|
|
@@ -1904,7 +1878,7 @@ async function githubCommand(options) {
|
|
|
1904
1878
|
}
|
|
1905
1879
|
if (!taskId) {
|
|
1906
1880
|
const config2 = loadConfig(cwd);
|
|
1907
|
-
const { listTasks: listTasks2 } = await import("./state-
|
|
1881
|
+
const { listTasks: listTasks2 } = await import("./state-3SI6H5IW.js");
|
|
1908
1882
|
const tasks = listTasks2(cwd);
|
|
1909
1883
|
for (const tid of tasks) {
|
|
1910
1884
|
const state2 = getWorkflowState(tid, config2, cwd);
|
|
@@ -1939,7 +1913,8 @@ async function githubCommand(options) {
|
|
|
1939
1913
|
console.log(`Approving step: ${state.currentStepName}`);
|
|
1940
1914
|
updateDocumentStatus(outputPath, "approved");
|
|
1941
1915
|
if (parsed.createPR) {
|
|
1942
|
-
console.log("PR
|
|
1916
|
+
console.log("Creating PR with AI-generated content...");
|
|
1917
|
+
await createPullRequestWithAI(githubConfig, taskId, userQuery, cwd);
|
|
1943
1918
|
}
|
|
1944
1919
|
if (parsed.createIssue) {
|
|
1945
1920
|
console.log("Creating/Updating Issue...");
|
|
@@ -2024,11 +1999,11 @@ async function postRejectionComment(config, taskId, stepName) {
|
|
|
2024
1999
|
await postComment(config, comment);
|
|
2025
2000
|
}
|
|
2026
2001
|
async function postComment(config, body) {
|
|
2027
|
-
const { spawn:
|
|
2002
|
+
const { spawn: spawn5 } = await import("child_process");
|
|
2028
2003
|
const { owner, repo, prNumber, issueNumber } = config;
|
|
2029
2004
|
const args = prNumber ? ["pr", "comment", String(prNumber), "--body", body, "-R", `${owner}/${repo}`] : ["issue", "comment", String(issueNumber), "--body", body, "-R", `${owner}/${repo}`];
|
|
2030
2005
|
return new Promise((resolve, reject) => {
|
|
2031
|
-
const proc =
|
|
2006
|
+
const proc = spawn5("gh", args, { stdio: "inherit" });
|
|
2032
2007
|
proc.on("close", (code) => {
|
|
2033
2008
|
if (code !== 0) reject(new Error(`gh failed with code ${code}`));
|
|
2034
2009
|
else resolve();
|
|
@@ -2036,6 +2011,158 @@ async function postComment(config, body) {
|
|
|
2036
2011
|
proc.on("error", reject);
|
|
2037
2012
|
});
|
|
2038
2013
|
}
|
|
2014
|
+
async function createPullRequestWithAI(config, taskId, userQuery, cwd) {
|
|
2015
|
+
const { spawnSync } = await import("child_process");
|
|
2016
|
+
const { owner, repo, issueNumber } = config;
|
|
2017
|
+
console.log(`Creating PR with taskId: ${taskId}`);
|
|
2018
|
+
const outputsDir = join4(cwd, ".spets", "outputs", taskId);
|
|
2019
|
+
const outputs = [];
|
|
2020
|
+
if (existsSync4(outputsDir)) {
|
|
2021
|
+
const files = readdirSync2(outputsDir).filter((f) => f.endsWith(".md"));
|
|
2022
|
+
for (const file of files) {
|
|
2023
|
+
const content = readFileSync2(join4(outputsDir, file), "utf-8");
|
|
2024
|
+
outputs.push({ step: file.replace(".md", ""), content });
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
const prContent = await generatePRContent(userQuery, outputs, issueNumber);
|
|
2028
|
+
const result = spawnSync("gh", [
|
|
2029
|
+
"pr",
|
|
2030
|
+
"create",
|
|
2031
|
+
"--repo",
|
|
2032
|
+
`${owner}/${repo}`,
|
|
2033
|
+
"--title",
|
|
2034
|
+
prContent.title,
|
|
2035
|
+
"--body",
|
|
2036
|
+
prContent.body,
|
|
2037
|
+
"--head",
|
|
2038
|
+
config.branch || "HEAD"
|
|
2039
|
+
], { encoding: "utf-8" });
|
|
2040
|
+
if (result.status !== 0) {
|
|
2041
|
+
throw new Error(`Failed to create PR: ${result.stderr}`);
|
|
2042
|
+
}
|
|
2043
|
+
console.log(`PR created: ${result.stdout.trim()}`);
|
|
2044
|
+
const match = result.stdout.match(/\/pull\/(\d+)/);
|
|
2045
|
+
if (!match) {
|
|
2046
|
+
throw new Error("Failed to parse PR number from gh output");
|
|
2047
|
+
}
|
|
2048
|
+
return parseInt(match[1], 10);
|
|
2049
|
+
}
|
|
2050
|
+
async function generatePRContent(userQuery, outputs, issueNumber) {
|
|
2051
|
+
const outputsSummary = outputs.map((o) => `### ${o.step}
|
|
2052
|
+
${o.content}`).join("\n\n---\n\n");
|
|
2053
|
+
const prompt = `You are generating a Pull Request title and body based on the following workflow outputs.
|
|
2054
|
+
|
|
2055
|
+
## Original Request
|
|
2056
|
+
${userQuery}
|
|
2057
|
+
|
|
2058
|
+
## Workflow Outputs
|
|
2059
|
+
${outputsSummary}
|
|
2060
|
+
|
|
2061
|
+
---
|
|
2062
|
+
|
|
2063
|
+
Generate a PR title and body. Requirements:
|
|
2064
|
+
1. Title: Concise (max 72 chars), describes what was done (e.g., "feat: add user authentication", "fix: resolve login timeout issue")
|
|
2065
|
+
2. Body:
|
|
2066
|
+
- Start with "## Summary" section (2-3 sentences max)
|
|
2067
|
+
- Include "## Changes" section with bullet points of key changes
|
|
2068
|
+
${issueNumber ? `- End with "Closes #${issueNumber}"` : ""}
|
|
2069
|
+
|
|
2070
|
+
Output format (use exactly this format):
|
|
2071
|
+
\`\`\`pr
|
|
2072
|
+
TITLE: <your title here>
|
|
2073
|
+
BODY:
|
|
2074
|
+
<your body here>
|
|
2075
|
+
\`\`\`
|
|
2076
|
+
|
|
2077
|
+
Generate the PR content now:`;
|
|
2078
|
+
try {
|
|
2079
|
+
const response = await callClaude(prompt);
|
|
2080
|
+
return parsePRResponse(response, userQuery, issueNumber);
|
|
2081
|
+
} catch (error) {
|
|
2082
|
+
console.warn("Failed to generate PR content with AI, using fallback:", error);
|
|
2083
|
+
return getFallbackPRContent(userQuery, issueNumber);
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
function parsePRResponse(response, userQuery, issueNumber) {
|
|
2087
|
+
const prMatch = response.match(/```pr\n([\s\S]*?)```/);
|
|
2088
|
+
if (!prMatch) {
|
|
2089
|
+
return getFallbackPRContent(userQuery, issueNumber);
|
|
2090
|
+
}
|
|
2091
|
+
const content = prMatch[1];
|
|
2092
|
+
const titleMatch = content.match(/TITLE:\s*(.+)/);
|
|
2093
|
+
const bodyMatch = content.match(/BODY:\n([\s\S]*)/);
|
|
2094
|
+
if (!titleMatch || !bodyMatch) {
|
|
2095
|
+
return getFallbackPRContent(userQuery, issueNumber);
|
|
2096
|
+
}
|
|
2097
|
+
let body = bodyMatch[1].trim();
|
|
2098
|
+
body += `
|
|
2099
|
+
|
|
2100
|
+
---
|
|
2101
|
+
|
|
2102
|
+
## Spets Commands
|
|
2103
|
+
|
|
2104
|
+
| Command | Description |
|
|
2105
|
+
|---------|-------------|
|
|
2106
|
+
| \`/approve\` | Approve current step and continue |
|
|
2107
|
+
| \`/approve --pr\` | Approve and create PR |
|
|
2108
|
+
| \`/revise <feedback>\` | Request changes with feedback |
|
|
2109
|
+
| \`/reject\` | Reject and stop workflow |`;
|
|
2110
|
+
return {
|
|
2111
|
+
title: titleMatch[1].trim(),
|
|
2112
|
+
body
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2115
|
+
function getFallbackPRContent(userQuery, issueNumber) {
|
|
2116
|
+
const title = userQuery.slice(0, 72) + (userQuery.length > 72 ? "..." : "");
|
|
2117
|
+
let body = `## Summary
|
|
2118
|
+
|
|
2119
|
+
${userQuery}
|
|
2120
|
+
|
|
2121
|
+
---
|
|
2122
|
+
|
|
2123
|
+
## Spets Commands
|
|
2124
|
+
|
|
2125
|
+
| Command | Description |
|
|
2126
|
+
|---------|-------------|
|
|
2127
|
+
| \`/approve\` | Approve current step and continue |
|
|
2128
|
+
| \`/approve --pr\` | Approve and create PR |
|
|
2129
|
+
| \`/revise <feedback>\` | Request changes with feedback |
|
|
2130
|
+
| \`/reject\` | Reject and stop workflow |`;
|
|
2131
|
+
if (issueNumber) {
|
|
2132
|
+
body += `
|
|
2133
|
+
|
|
2134
|
+
Closes #${issueNumber}`;
|
|
2135
|
+
}
|
|
2136
|
+
return { title, body };
|
|
2137
|
+
}
|
|
2138
|
+
async function callClaude(prompt) {
|
|
2139
|
+
return new Promise((resolve, reject) => {
|
|
2140
|
+
const proc = spawn4("claude", [
|
|
2141
|
+
"--permission-mode",
|
|
2142
|
+
"bypassPermissions"
|
|
2143
|
+
], { stdio: ["pipe", "pipe", "pipe"] });
|
|
2144
|
+
let stdout = "";
|
|
2145
|
+
let stderr = "";
|
|
2146
|
+
proc.stdout.on("data", (data) => {
|
|
2147
|
+
stdout += data.toString();
|
|
2148
|
+
});
|
|
2149
|
+
proc.stderr.on("data", (data) => {
|
|
2150
|
+
stderr += data.toString();
|
|
2151
|
+
});
|
|
2152
|
+
proc.stdin.write(prompt);
|
|
2153
|
+
proc.stdin.end();
|
|
2154
|
+
proc.on("close", (code) => {
|
|
2155
|
+
if (code !== 0) {
|
|
2156
|
+
reject(new Error(`Claude CLI failed (code ${code}): ${stderr}`));
|
|
2157
|
+
} else {
|
|
2158
|
+
resolve(stdout);
|
|
2159
|
+
}
|
|
2160
|
+
});
|
|
2161
|
+
proc.on("error", (err) => {
|
|
2162
|
+
reject(new Error(`Failed to run Claude: ${err.message}`));
|
|
2163
|
+
});
|
|
2164
|
+
});
|
|
2165
|
+
}
|
|
2039
2166
|
async function createOrUpdateIssue(config, taskId, userQuery, stepName) {
|
|
2040
2167
|
const { spawnSync } = await import("child_process");
|
|
2041
2168
|
const { owner, repo, issueNumber } = config;
|
|
@@ -2083,8 +2210,8 @@ _Updated by [Spets](https://github.com/eatnug/spets)_`;
|
|
|
2083
2210
|
}
|
|
2084
2211
|
|
|
2085
2212
|
// src/orchestrator/index.ts
|
|
2086
|
-
import { readFileSync as
|
|
2087
|
-
import { join as
|
|
2213
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
2214
|
+
import { join as join5, dirname as dirname2 } from "path";
|
|
2088
2215
|
import matter from "gray-matter";
|
|
2089
2216
|
var Orchestrator = class {
|
|
2090
2217
|
cwd;
|
|
@@ -2102,33 +2229,33 @@ var Orchestrator = class {
|
|
|
2102
2229
|
return getOutputsDir(this.cwd);
|
|
2103
2230
|
}
|
|
2104
2231
|
getStatePath(taskId) {
|
|
2105
|
-
return
|
|
2232
|
+
return join5(this.getOutputPath(), taskId, ".state.json");
|
|
2106
2233
|
}
|
|
2107
2234
|
getSpecPath(taskId, step) {
|
|
2108
|
-
return
|
|
2235
|
+
return join5(this.getOutputPath(), taskId, `${step}.md`);
|
|
2109
2236
|
}
|
|
2110
2237
|
getStepInstructionPath(step) {
|
|
2111
|
-
return
|
|
2238
|
+
return join5(getStepsDir(this.cwd), step, "instruction.md");
|
|
2112
2239
|
}
|
|
2113
2240
|
getStepTemplatePath(step) {
|
|
2114
|
-
return
|
|
2241
|
+
return join5(getStepsDir(this.cwd), step, "template.md");
|
|
2115
2242
|
}
|
|
2116
2243
|
// ===========================================================================
|
|
2117
2244
|
// State Management
|
|
2118
2245
|
// ===========================================================================
|
|
2119
2246
|
loadState(taskId) {
|
|
2120
2247
|
const statePath = this.getStatePath(taskId);
|
|
2121
|
-
if (!
|
|
2248
|
+
if (!existsSync5(statePath)) {
|
|
2122
2249
|
return null;
|
|
2123
2250
|
}
|
|
2124
|
-
const data = JSON.parse(
|
|
2251
|
+
const data = JSON.parse(readFileSync3(statePath, "utf-8"));
|
|
2125
2252
|
return data;
|
|
2126
2253
|
}
|
|
2127
2254
|
saveState(state) {
|
|
2128
2255
|
state.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2129
2256
|
const statePath = this.getStatePath(state.taskId);
|
|
2130
2257
|
const dir = dirname2(statePath);
|
|
2131
|
-
if (!
|
|
2258
|
+
if (!existsSync5(dir)) {
|
|
2132
2259
|
mkdirSync3(dir, { recursive: true });
|
|
2133
2260
|
}
|
|
2134
2261
|
writeFileSync3(statePath, JSON.stringify(state, null, 2));
|
|
@@ -2137,10 +2264,10 @@ var Orchestrator = class {
|
|
|
2137
2264
|
// Spec Helpers
|
|
2138
2265
|
// ===========================================================================
|
|
2139
2266
|
checkUnresolvedQuestions(specPath) {
|
|
2140
|
-
if (!
|
|
2267
|
+
if (!existsSync5(specPath)) {
|
|
2141
2268
|
return [];
|
|
2142
2269
|
}
|
|
2143
|
-
const content =
|
|
2270
|
+
const content = readFileSync3(specPath, "utf-8");
|
|
2144
2271
|
const { data } = matter(content);
|
|
2145
2272
|
const questions = [];
|
|
2146
2273
|
if (data.open_questions && Array.isArray(data.open_questions)) {
|
|
@@ -2168,13 +2295,13 @@ var Orchestrator = class {
|
|
|
2168
2295
|
let previousOutput;
|
|
2169
2296
|
if (state.stepIndex > 1) {
|
|
2170
2297
|
const prevStep = steps[state.stepIndex - 2];
|
|
2171
|
-
const prevPath =
|
|
2172
|
-
if (
|
|
2298
|
+
const prevPath = join5(outputPath, state.taskId, `${prevStep}.md`);
|
|
2299
|
+
if (existsSync5(prevPath)) {
|
|
2173
2300
|
previousOutput = prevPath;
|
|
2174
2301
|
}
|
|
2175
2302
|
}
|
|
2176
2303
|
const templatePath = this.getStepTemplatePath(state.currentStep);
|
|
2177
|
-
const hasTemplate =
|
|
2304
|
+
const hasTemplate = existsSync5(templatePath);
|
|
2178
2305
|
return {
|
|
2179
2306
|
type: "step",
|
|
2180
2307
|
step: state.currentStep,
|
|
@@ -2186,7 +2313,7 @@ var Orchestrator = class {
|
|
|
2186
2313
|
instruction: this.getStepInstructionPath(state.currentStep),
|
|
2187
2314
|
template: hasTemplate ? templatePath : void 0,
|
|
2188
2315
|
previousOutput,
|
|
2189
|
-
output:
|
|
2316
|
+
output: join5(outputPath, state.taskId, `${state.currentStep}.md`),
|
|
2190
2317
|
revisionFeedback: state.revisionFeedback
|
|
2191
2318
|
},
|
|
2192
2319
|
onComplete: `done ${state.taskId}`
|
|
@@ -2216,7 +2343,7 @@ var Orchestrator = class {
|
|
|
2216
2343
|
step: state.currentStep,
|
|
2217
2344
|
stepIndex: state.stepIndex,
|
|
2218
2345
|
totalSteps: state.totalSteps,
|
|
2219
|
-
specPath:
|
|
2346
|
+
specPath: join5(outputPath, state.taskId, `${state.currentStep}.md`),
|
|
2220
2347
|
options: ["approve", "revise", "reject", "stop"],
|
|
2221
2348
|
onComplete: {
|
|
2222
2349
|
approve: `approve ${state.taskId}`,
|
|
@@ -2231,8 +2358,8 @@ var Orchestrator = class {
|
|
|
2231
2358
|
const outputPath = this.getOutputPath();
|
|
2232
2359
|
const outputs = [];
|
|
2233
2360
|
for (let i = 0; i < state.stepIndex; i++) {
|
|
2234
|
-
const specPath =
|
|
2235
|
-
if (
|
|
2361
|
+
const specPath = join5(outputPath, state.taskId, `${steps[i]}.md`);
|
|
2362
|
+
if (existsSync5(specPath)) {
|
|
2236
2363
|
outputs.push(specPath);
|
|
2237
2364
|
}
|
|
2238
2365
|
}
|
|
@@ -2289,7 +2416,7 @@ var Orchestrator = class {
|
|
|
2289
2416
|
return this.responseError(`No workflow found: ${taskId}`, taskId);
|
|
2290
2417
|
}
|
|
2291
2418
|
const specPath = this.getSpecPath(taskId, state.currentStep);
|
|
2292
|
-
if (!
|
|
2419
|
+
if (!existsSync5(specPath)) {
|
|
2293
2420
|
return this.responseError(`Spec not found: ${specPath}`, taskId, state.currentStep);
|
|
2294
2421
|
}
|
|
2295
2422
|
const questions = this.checkUnresolvedQuestions(specPath);
|
|
@@ -2311,8 +2438,8 @@ var Orchestrator = class {
|
|
|
2311
2438
|
return this.responseError(`No workflow found: ${taskId}`, taskId);
|
|
2312
2439
|
}
|
|
2313
2440
|
const specPath = this.getSpecPath(taskId, state.currentStep);
|
|
2314
|
-
if (
|
|
2315
|
-
const content =
|
|
2441
|
+
if (existsSync5(specPath)) {
|
|
2442
|
+
const content = readFileSync3(specPath, "utf-8");
|
|
2316
2443
|
const { content: body, data } = matter(content);
|
|
2317
2444
|
if (data.open_questions && Array.isArray(data.open_questions)) {
|
|
2318
2445
|
data.open_questions = data.open_questions.map((q, i) => ({
|
|
@@ -2338,8 +2465,8 @@ var Orchestrator = class {
|
|
|
2338
2465
|
}
|
|
2339
2466
|
const steps = this.getSteps();
|
|
2340
2467
|
const specPath = this.getSpecPath(taskId, state.currentStep);
|
|
2341
|
-
if (
|
|
2342
|
-
const content =
|
|
2468
|
+
if (existsSync5(specPath)) {
|
|
2469
|
+
const content = readFileSync3(specPath, "utf-8");
|
|
2343
2470
|
const { content: body, data } = matter(content);
|
|
2344
2471
|
data.status = "approved";
|
|
2345
2472
|
data.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -2380,8 +2507,8 @@ var Orchestrator = class {
|
|
|
2380
2507
|
return this.responseError(`No workflow found: ${taskId}`, taskId);
|
|
2381
2508
|
}
|
|
2382
2509
|
const specPath = this.getSpecPath(taskId, state.currentStep);
|
|
2383
|
-
if (
|
|
2384
|
-
const content =
|
|
2510
|
+
if (existsSync5(specPath)) {
|
|
2511
|
+
const content = readFileSync3(specPath, "utf-8");
|
|
2385
2512
|
const { content: body, data } = matter(content);
|
|
2386
2513
|
data.status = "rejected";
|
|
2387
2514
|
data.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createDocument,
|
|
3
3
|
ensureTaskDir,
|
|
4
|
-
extractPlanSummary,
|
|
5
4
|
generateTaskId,
|
|
6
5
|
getOutputPath,
|
|
7
6
|
getTaskDir,
|
|
@@ -13,11 +12,10 @@ import {
|
|
|
13
12
|
saveDocument,
|
|
14
13
|
saveTaskMetadata,
|
|
15
14
|
updateDocumentStatus
|
|
16
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-L3K6T5GO.js";
|
|
17
16
|
export {
|
|
18
17
|
createDocument,
|
|
19
18
|
ensureTaskDir,
|
|
20
|
-
extractPlanSummary,
|
|
21
19
|
generateTaskId,
|
|
22
20
|
getOutputPath,
|
|
23
21
|
getTaskDir,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spets",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Spec Driven Development Execution Framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
"spets": "./dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
|
-
"dist"
|
|
11
|
+
"dist",
|
|
12
|
+
"templates"
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
14
15
|
"dev": "tsx src/index.ts",
|