spets 0.1.7 → 0.1.9

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.
@@ -10,6 +10,9 @@ import { parse as parseYaml } from "yaml";
10
10
  var SPETS_DIR = ".spets";
11
11
  var CONFIG_FILE = "config.yml";
12
12
  var STEPS_DIR = "steps";
13
+ var configCache = null;
14
+ var configCachePath = null;
15
+ var stepDefinitionCache = /* @__PURE__ */ new Map();
13
16
  function getSpetsDir(cwd = process.cwd()) {
14
17
  return join(cwd, SPETS_DIR);
15
18
  }
@@ -27,6 +30,9 @@ function spetsExists(cwd = process.cwd()) {
27
30
  }
28
31
  function loadConfig(cwd = process.cwd()) {
29
32
  const configPath = getConfigPath(cwd);
33
+ if (configCache && configCachePath === configPath) {
34
+ return configCache;
35
+ }
30
36
  if (!existsSync(configPath)) {
31
37
  throw new Error(`Spets config not found. Run 'spets init' first.`);
32
38
  }
@@ -35,9 +41,15 @@ function loadConfig(cwd = process.cwd()) {
35
41
  if (!config.steps || config.steps.length === 0) {
36
42
  throw new Error("Config must define at least one step");
37
43
  }
44
+ configCache = config;
45
+ configCachePath = configPath;
38
46
  return config;
39
47
  }
40
48
  function loadStepDefinition(stepName, cwd = process.cwd()) {
49
+ const cacheKey = `${cwd}:${stepName}`;
50
+ if (stepDefinitionCache.has(cacheKey)) {
51
+ return stepDefinitionCache.get(cacheKey);
52
+ }
41
53
  const stepDir = join(getStepsDir(cwd), stepName);
42
54
  const instructionPath = join(stepDir, "instruction.md");
43
55
  const templatePath = join(stepDir, "template.md");
@@ -46,19 +58,58 @@ function loadStepDefinition(stepName, cwd = process.cwd()) {
46
58
  }
47
59
  const instruction = readFileSync(instructionPath, "utf-8");
48
60
  const template = existsSync(templatePath) ? readFileSync(templatePath, "utf-8") : void 0;
49
- return {
61
+ const stepDef = {
50
62
  name: stepName,
51
63
  instruction,
52
64
  template
53
65
  };
66
+ stepDefinitionCache.set(cacheKey, stepDef);
67
+ return stepDef;
54
68
  }
55
69
  function getGitHubConfig(cwd = process.cwd()) {
56
70
  const config = loadConfig(cwd);
57
71
  return config.github;
58
72
  }
59
73
 
74
+ // src/core/slug.ts
75
+ function generateRandomSuffix() {
76
+ return Math.random().toString(36).substring(2, 6);
77
+ }
78
+ function generateDatePrefix() {
79
+ const now = /* @__PURE__ */ new Date();
80
+ const year = now.getFullYear();
81
+ const month = String(now.getMonth() + 1).padStart(2, "0");
82
+ const day = String(now.getDate()).padStart(2, "0");
83
+ return `${year}-${month}-${day}`;
84
+ }
85
+ function sanitizeDescription(description) {
86
+ let sanitized = description.toLowerCase();
87
+ sanitized = sanitized.replace(/[^\x00-\x7F]/g, "");
88
+ sanitized = sanitized.replace(/[^a-z0-9\s]/g, "");
89
+ sanitized = sanitized.trim();
90
+ sanitized = sanitized.replace(/\s+/g, " ");
91
+ sanitized = sanitized.replace(/\s+/g, "-");
92
+ if (sanitized.length > 10) {
93
+ sanitized = sanitized.substring(0, 10);
94
+ }
95
+ sanitized = sanitized.replace(/-+$/, "");
96
+ if (sanitized === "") {
97
+ sanitized = "task";
98
+ }
99
+ return sanitized;
100
+ }
101
+ function generateSlug(description) {
102
+ const datePrefix = generateDatePrefix();
103
+ const meaningfulName = sanitizeDescription(description);
104
+ const randomSuffix = generateRandomSuffix();
105
+ return `${datePrefix}-${meaningfulName}-${randomSuffix}`;
106
+ }
107
+
60
108
  // src/core/state.ts
61
- function generateTaskId() {
109
+ function generateTaskId(description) {
110
+ if (description) {
111
+ return generateSlug(description);
112
+ }
62
113
  const timestamp = Date.now().toString(36);
63
114
  const random = Math.random().toString(36).substring(2, 6);
64
115
  return `${timestamp}-${random}`;
@@ -132,11 +183,68 @@ function listTasks(cwd = process.cwd()) {
132
183
  }
133
184
  return readdirSync(outputsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name).sort().reverse();
134
185
  }
186
+ function getStateCachePath(taskId, cwd = process.cwd()) {
187
+ return join2(getTaskDir(taskId, cwd), ".state-cache.json");
188
+ }
189
+ function loadStateCache(taskId, cwd = process.cwd()) {
190
+ const cachePath = getStateCachePath(taskId, cwd);
191
+ if (!existsSync2(cachePath)) {
192
+ return null;
193
+ }
194
+ try {
195
+ const cached = JSON.parse(readFileSync2(cachePath, "utf-8"));
196
+ return cached;
197
+ } catch {
198
+ return null;
199
+ }
200
+ }
201
+ function saveStateCache(taskId, state, cwd = process.cwd()) {
202
+ const cachePath = getStateCachePath(taskId, cwd);
203
+ const stepStatuses = {};
204
+ for (const [stepName, output] of state.outputs.entries()) {
205
+ stepStatuses[stepName] = output.status;
206
+ }
207
+ const cached = {
208
+ lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
209
+ taskId: state.taskId,
210
+ userQuery: state.userQuery,
211
+ currentStepIndex: state.currentStepIndex,
212
+ currentStepName: state.currentStepName,
213
+ status: state.status,
214
+ stepStatuses
215
+ };
216
+ try {
217
+ writeFileSync(cachePath, JSON.stringify(cached, null, 2));
218
+ } catch {
219
+ }
220
+ }
221
+ function isStateCacheValid(cached, maxAgeMs = 5e3) {
222
+ const age = Date.now() - new Date(cached.lastUpdated).getTime();
223
+ return age < maxAgeMs;
224
+ }
135
225
  function getWorkflowState(taskId, config, cwd = process.cwd()) {
136
226
  const taskDir = getTaskDir(taskId, cwd);
137
227
  if (!existsSync2(taskDir)) {
138
228
  return null;
139
229
  }
230
+ const cached = loadStateCache(taskId, cwd);
231
+ if (cached && isStateCacheValid(cached)) {
232
+ const outputs2 = /* @__PURE__ */ new Map();
233
+ for (const [stepName, status] of Object.entries(cached.stepStatuses)) {
234
+ outputs2.set(stepName, {
235
+ path: getOutputPath(taskId, stepName, cwd),
236
+ status
237
+ });
238
+ }
239
+ return {
240
+ taskId: cached.taskId,
241
+ userQuery: cached.userQuery,
242
+ currentStepIndex: cached.currentStepIndex,
243
+ currentStepName: cached.currentStepName,
244
+ status: cached.status,
245
+ outputs: outputs2
246
+ };
247
+ }
140
248
  const outputs = /* @__PURE__ */ new Map();
141
249
  let lastApprovedIndex = -1;
142
250
  let currentStatus = "in_progress";
@@ -171,7 +279,7 @@ function getWorkflowState(taskId, config, cwd = process.cwd()) {
171
279
  if (currentDoc?.frontmatter.status === "draft" && currentDoc.frontmatter.open_questions?.length) {
172
280
  currentStatus = "paused";
173
281
  }
174
- return {
282
+ const state = {
175
283
  taskId,
176
284
  userQuery,
177
285
  currentStepIndex,
@@ -179,6 +287,8 @@ function getWorkflowState(taskId, config, cwd = process.cwd()) {
179
287
  status: currentStatus,
180
288
  outputs
181
289
  };
290
+ saveStateCache(taskId, state, cwd);
291
+ return state;
182
292
  }
183
293
  function saveTaskMetadata(taskId, userQuery, cwd = process.cwd()) {
184
294
  const taskDir = ensureTaskDir(taskId, cwd);
@@ -192,6 +302,21 @@ function loadTaskMetadata(taskId, cwd = process.cwd()) {
192
302
  }
193
303
  return JSON.parse(readFileSync2(metaPath, "utf-8"));
194
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
+ }
195
320
 
196
321
  export {
197
322
  getSpetsDir,
@@ -213,5 +338,6 @@ export {
213
338
  listTasks,
214
339
  getWorkflowState,
215
340
  saveTaskMetadata,
216
- loadTaskMetadata
341
+ loadTaskMetadata,
342
+ extractPlanSummary
217
343
  };
package/dist/index.js CHANGED
@@ -16,13 +16,13 @@ import {
16
16
  saveTaskMetadata,
17
17
  spetsExists,
18
18
  updateDocumentStatus
19
- } from "./chunk-YK5ZZE4P.js";
19
+ } from "./chunk-NOS3N4GT.js";
20
20
 
21
21
  // src/index.ts
22
22
  import { Command } from "commander";
23
23
 
24
24
  // src/commands/init.ts
25
- import { mkdirSync, writeFileSync } from "fs";
25
+ import { mkdirSync, writeFileSync, readFileSync } from "fs";
26
26
  import { join, dirname } from "path";
27
27
  import { fileURLToPath } from "url";
28
28
  import { execSync } from "child_process";
@@ -121,155 +121,20 @@ function createDefaultSteps(spetsDir) {
121
121
  writeFileSync(join(implementDir, "template.md"), getImplementTemplate());
122
122
  }
123
123
  function getPlanInstruction() {
124
- return `# Plan Step
125
-
126
- You are creating a technical plan for the given task.
127
-
128
- ## Your Goal
129
-
130
- Analyze the user's request and create a detailed implementation plan.
131
-
132
- ## Process
133
-
134
- 1. **Understand the Request**
135
- - Parse the user's query to identify the core requirements
136
- - Identify any ambiguities or missing information
137
-
138
- 2. **Ask Clarifying Questions** (if needed)
139
- - If requirements are unclear, list questions in the \`open_questions\` section
140
- - Questions should be specific and actionable
141
-
142
- 3. **Create the Plan**
143
- - Break down the task into concrete steps
144
- - Identify files to create/modify
145
- - Consider edge cases and potential issues
146
-
147
- ## Output Format
148
-
149
- Follow the template provided. Include:
150
- - Summary of what will be built
151
- - Step-by-step implementation plan
152
- - Files to be created/modified
153
- - Any open questions (if requirements are unclear)
154
- `;
124
+ const fullTemplate = readFileSync(join(__dirname, "..", ".spets", "steps", "01-plan", "instruction.md"), "utf-8");
125
+ return fullTemplate;
155
126
  }
156
127
  function getPlanTemplate() {
157
- return `# Plan: {{title}}
158
-
159
- ## Summary
160
-
161
- Brief description of what will be implemented.
162
-
163
- ## Requirements
164
-
165
- - Requirement 1
166
- - Requirement 2
167
-
168
- ## Implementation Steps
169
-
170
- ### Step 1: [Description]
171
-
172
- Details...
173
-
174
- ### Step 2: [Description]
175
-
176
- Details...
177
-
178
- ## Files to Modify
179
-
180
- | File | Action | Description |
181
- |------|--------|-------------|
182
- | path/to/file | Create/Modify | What changes |
183
-
184
- ## Open Questions
185
-
186
- <!-- Remove this section if no questions -->
187
-
188
- - Question 1?
189
- - Question 2?
190
-
191
- ## Risks & Considerations
192
-
193
- - Risk 1
194
- - Risk 2
195
- `;
128
+ const fullTemplate = readFileSync(join(__dirname, "..", ".spets", "steps", "01-plan", "template.md"), "utf-8");
129
+ return fullTemplate;
196
130
  }
197
131
  function getImplementInstruction() {
198
- return `# Implement Step
199
-
200
- You are implementing the plan from the previous step.
201
-
202
- ## Your Goal
203
-
204
- Write the actual code based on the approved plan.
205
-
206
- ## Process
207
-
208
- 1. **Review the Plan**
209
- - Read the approved plan document carefully
210
- - Understand all requirements and steps
211
-
212
- 2. **Implement**
213
- - Follow the plan step by step
214
- - Write clean, well-documented code
215
- - Handle edge cases identified in the plan
216
-
217
- 3. **Document Changes**
218
- - List all files created/modified
219
- - Explain key decisions made during implementation
220
-
221
- ## Output Format
222
-
223
- Follow the template provided. Include:
224
- - Summary of implementation
225
- - List of all changes made
226
- - Any deviations from the plan (with justification)
227
- - Testing notes
228
- `;
132
+ const fullTemplate = readFileSync(join(__dirname, "..", ".spets", "steps", "02-implement", "instruction.md"), "utf-8");
133
+ return fullTemplate;
229
134
  }
230
135
  function getImplementTemplate() {
231
- return `# Implementation: {{title}}
232
-
233
- ## Summary
234
-
235
- Brief description of what was implemented.
236
-
237
- ## Changes Made
238
-
239
- ### New Files
240
-
241
- | File | Description |
242
- |------|-------------|
243
- | path/to/file | What it does |
244
-
245
- ### Modified Files
246
-
247
- | File | Changes |
248
- |------|---------|
249
- | path/to/file | What changed |
250
-
251
- ## Key Decisions
252
-
253
- - Decision 1: Explanation
254
- - Decision 2: Explanation
255
-
256
- ## Deviations from Plan
257
-
258
- <!-- Remove if no deviations -->
259
-
260
- None / List any deviations with justification.
261
-
262
- ## Testing
263
-
264
- - [ ] Manual testing completed
265
- - [ ] Unit tests added
266
- - [ ] Integration tests pass
267
-
268
- ## Next Steps
269
-
270
- - Follow-up task 1
271
- - Follow-up task 2
272
- `;
136
+ const fullTemplate = readFileSync(join(__dirname, "..", ".spets", "steps", "02-implement", "template.md"), "utf-8");
137
+ return fullTemplate;
273
138
  }
274
139
  function createClaudeCommand(cwd) {
275
140
  const commandDir = join(cwd, ".claude", "commands");
@@ -702,6 +567,16 @@ var Executor = class {
702
567
  this.config = options.config;
703
568
  this.cwd = options.cwd || process.cwd();
704
569
  }
570
+ /**
571
+ * Preload all step definitions into cache for better performance
572
+ */
573
+ async preloadSteps() {
574
+ await Promise.all(
575
+ this.config.steps.map(
576
+ (stepName) => Promise.resolve(loadStepDefinition(stepName, this.cwd))
577
+ )
578
+ );
579
+ }
705
580
  async executeWorkflow(taskId, userQuery, startIndex = 0, feedback) {
706
581
  let previousOutput;
707
582
  if (startIndex > 0) {
@@ -954,7 +829,6 @@ var CliPlatform = class extends BasePlatform {
954
829
  async callClaude(prompt) {
955
830
  return new Promise((resolve, reject) => {
956
831
  const proc = spawn2(this.claudeCommand, [
957
- "--print",
958
832
  "--permission-mode",
959
833
  "bypassPermissions"
960
834
  ], {
@@ -1024,6 +898,21 @@ var CliPlatform = class extends BasePlatform {
1024
898
 
1025
899
  // src/platform/github.ts
1026
900
  import { spawn as spawn3 } from "child_process";
901
+ async function retryWithBackoff(fn, maxRetries = 3, initialDelayMs = 1e3) {
902
+ let lastError = null;
903
+ for (let i = 0; i < maxRetries; i++) {
904
+ try {
905
+ return await fn();
906
+ } catch (error) {
907
+ lastError = error;
908
+ if (i === maxRetries - 1) break;
909
+ const delay = initialDelayMs * Math.pow(2, i);
910
+ console.log(`Retry ${i + 1}/${maxRetries} after ${delay}ms...`);
911
+ await new Promise((resolve) => setTimeout(resolve, delay));
912
+ }
913
+ }
914
+ throw lastError || new Error("Retry failed");
915
+ }
1027
916
  var PauseForInputError = class extends Error {
1028
917
  constructor(inputType, data) {
1029
918
  super(`Paused waiting for ${inputType}`);
@@ -1211,26 +1100,39 @@ var GitHubPlatform = class extends BasePlatform {
1211
1100
  const { owner, repo, issueNumber } = this.config;
1212
1101
  await this.runGh(["issue", "comment", String(issueNumber), "--body", body, "-R", `${owner}/${repo}`]);
1213
1102
  }
1214
- async runGh(args) {
1215
- return new Promise((resolve, reject) => {
1216
- const proc = spawn3("gh", args, { stdio: ["pipe", "pipe", "pipe"] });
1217
- let stdout = "";
1218
- let stderr = "";
1219
- proc.stdout.on("data", (data) => {
1220
- stdout += data.toString();
1221
- });
1222
- proc.stderr.on("data", (data) => {
1223
- stderr += data.toString();
1224
- });
1225
- proc.on("close", (code) => {
1226
- if (code !== 0) {
1227
- reject(new Error(`gh command failed: ${stderr}`));
1228
- } else {
1229
- resolve(stdout);
1230
- }
1231
- });
1232
- proc.on("error", (err) => {
1233
- reject(new Error(`Failed to run gh: ${err.message}`));
1103
+ async runGh(args, timeoutMs = 3e4) {
1104
+ return retryWithBackoff(async () => {
1105
+ return new Promise((resolve, reject) => {
1106
+ const proc = spawn3("gh", args, { stdio: ["pipe", "pipe", "pipe"] });
1107
+ let stdout = "";
1108
+ let stderr = "";
1109
+ let isTimedOut = false;
1110
+ const timeoutId = setTimeout(() => {
1111
+ isTimedOut = true;
1112
+ proc.kill();
1113
+ reject(new Error(`gh command timed out after ${timeoutMs}ms`));
1114
+ }, timeoutMs);
1115
+ proc.stdout.on("data", (data) => {
1116
+ stdout += data.toString();
1117
+ });
1118
+ proc.stderr.on("data", (data) => {
1119
+ stderr += data.toString();
1120
+ });
1121
+ proc.on("close", (code) => {
1122
+ clearTimeout(timeoutId);
1123
+ if (isTimedOut) return;
1124
+ if (code !== 0) {
1125
+ reject(new Error(`gh command failed: ${stderr}`));
1126
+ } else {
1127
+ resolve(stdout);
1128
+ }
1129
+ });
1130
+ proc.on("error", (err) => {
1131
+ clearTimeout(timeoutId);
1132
+ if (!isTimedOut) {
1133
+ reject(new Error(`Failed to run gh: ${err.message}`));
1134
+ }
1135
+ });
1234
1136
  });
1235
1137
  });
1236
1138
  }
@@ -1264,11 +1166,9 @@ var GitHubPlatform = class extends BasePlatform {
1264
1166
  async callClaude(prompt) {
1265
1167
  return new Promise((resolve, reject) => {
1266
1168
  const proc = spawn3("claude", [
1267
- "-p",
1268
- prompt,
1269
1169
  "--permission-mode",
1270
1170
  "bypassPermissions"
1271
- ], { stdio: ["ignore", "pipe", "pipe"] });
1171
+ ], { stdio: ["pipe", "pipe", "pipe"] });
1272
1172
  let stdout = "";
1273
1173
  let stderr = "";
1274
1174
  proc.stdout.on("data", (data) => {
@@ -1277,6 +1177,8 @@ var GitHubPlatform = class extends BasePlatform {
1277
1177
  proc.stderr.on("data", (data) => {
1278
1178
  stderr += data.toString();
1279
1179
  });
1180
+ proc.stdin.write(prompt);
1181
+ proc.stdin.end();
1280
1182
  proc.on("close", (code) => {
1281
1183
  if (code !== 0) {
1282
1184
  reject(new Error(`Claude CLI failed (code ${code}): stderr=${stderr}, stdout=${stdout}`));
@@ -1402,7 +1304,7 @@ async function startCommand(query, options) {
1402
1304
  process.exit(1);
1403
1305
  }
1404
1306
  const config = loadConfig(cwd);
1405
- const taskId = generateTaskId();
1307
+ const taskId = generateTaskId(query);
1406
1308
  saveTaskMetadata(taskId, query, cwd);
1407
1309
  let platform;
1408
1310
  if (options.github || options.issue !== void 0 || options.pr !== void 0) {
@@ -1893,7 +1795,7 @@ async function githubCommand(options) {
1893
1795
  }
1894
1796
  if (!taskId) {
1895
1797
  const config2 = loadConfig(cwd);
1896
- const { listTasks: listTasks2 } = await import("./state-JLYPJWUT.js");
1798
+ const { listTasks: listTasks2 } = await import("./state-54IS3PZH.js");
1897
1799
  const tasks = listTasks2(cwd);
1898
1800
  for (const tid of tasks) {
1899
1801
  const state2 = getWorkflowState(tid, config2, cwd);
@@ -2072,7 +1974,7 @@ _Updated by [Spets](https://github.com/eatnug/spets)_`;
2072
1974
  }
2073
1975
 
2074
1976
  // src/orchestrator/index.ts
2075
- import { readFileSync, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
1977
+ import { readFileSync as readFileSync2, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
2076
1978
  import { join as join4, dirname as dirname2 } from "path";
2077
1979
  import matter from "gray-matter";
2078
1980
  var Orchestrator = class {
@@ -2110,7 +2012,7 @@ var Orchestrator = class {
2110
2012
  if (!existsSync4(statePath)) {
2111
2013
  return null;
2112
2014
  }
2113
- const data = JSON.parse(readFileSync(statePath, "utf-8"));
2015
+ const data = JSON.parse(readFileSync2(statePath, "utf-8"));
2114
2016
  return data;
2115
2017
  }
2116
2018
  saveState(state) {
@@ -2129,7 +2031,7 @@ var Orchestrator = class {
2129
2031
  if (!existsSync4(specPath)) {
2130
2032
  return [];
2131
2033
  }
2132
- const content = readFileSync(specPath, "utf-8");
2034
+ const content = readFileSync2(specPath, "utf-8");
2133
2035
  const { data } = matter(content);
2134
2036
  const questions = [];
2135
2037
  if (data.open_questions && Array.isArray(data.open_questions)) {
@@ -2148,11 +2050,6 @@ var Orchestrator = class {
2148
2050
  }
2149
2051
  return questions;
2150
2052
  }
2151
- generateTaskId(description) {
2152
- const timestamp = Date.now().toString(36);
2153
- const random = Math.random().toString(36).substring(2, 6);
2154
- return `${timestamp}-${random}`;
2155
- }
2156
2053
  // ===========================================================================
2157
2054
  // Protocol Response Builders
2158
2055
  // ===========================================================================
@@ -2258,7 +2155,7 @@ var Orchestrator = class {
2258
2155
  cmdInit(description) {
2259
2156
  try {
2260
2157
  const steps = this.getSteps();
2261
- const taskId = this.generateTaskId(description);
2158
+ const taskId = generateTaskId(description);
2262
2159
  const state = {
2263
2160
  taskId,
2264
2161
  description,
@@ -2306,7 +2203,7 @@ var Orchestrator = class {
2306
2203
  }
2307
2204
  const specPath = this.getSpecPath(taskId, state.currentStep);
2308
2205
  if (existsSync4(specPath)) {
2309
- const content = readFileSync(specPath, "utf-8");
2206
+ const content = readFileSync2(specPath, "utf-8");
2310
2207
  const { content: body, data } = matter(content);
2311
2208
  if (data.open_questions && Array.isArray(data.open_questions)) {
2312
2209
  data.open_questions = data.open_questions.map((q, i) => ({
@@ -2333,7 +2230,7 @@ var Orchestrator = class {
2333
2230
  const steps = this.getSteps();
2334
2231
  const specPath = this.getSpecPath(taskId, state.currentStep);
2335
2232
  if (existsSync4(specPath)) {
2336
- const content = readFileSync(specPath, "utf-8");
2233
+ const content = readFileSync2(specPath, "utf-8");
2337
2234
  const { content: body, data } = matter(content);
2338
2235
  data.status = "approved";
2339
2236
  data.updated_at = (/* @__PURE__ */ new Date()).toISOString();
@@ -2375,7 +2272,7 @@ var Orchestrator = class {
2375
2272
  }
2376
2273
  const specPath = this.getSpecPath(taskId, state.currentStep);
2377
2274
  if (existsSync4(specPath)) {
2378
- const content = readFileSync(specPath, "utf-8");
2275
+ const content = readFileSync2(specPath, "utf-8");
2379
2276
  const { content: body, data } = matter(content);
2380
2277
  data.status = "rejected";
2381
2278
  data.updated_at = (/* @__PURE__ */ new Date()).toISOString();
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  createDocument,
3
3
  ensureTaskDir,
4
+ extractPlanSummary,
4
5
  generateTaskId,
5
6
  getOutputPath,
6
7
  getTaskDir,
@@ -12,10 +13,11 @@ import {
12
13
  saveDocument,
13
14
  saveTaskMetadata,
14
15
  updateDocumentStatus
15
- } from "./chunk-YK5ZZE4P.js";
16
+ } from "./chunk-NOS3N4GT.js";
16
17
  export {
17
18
  createDocument,
18
19
  ensureTaskDir,
20
+ extractPlanSummary,
19
21
  generateTaskId,
20
22
  getOutputPath,
21
23
  getTaskDir,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spets",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Spec Driven Development Execution Framework",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",