@launch11/srgical 0.0.4 → 0.0.6

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,270 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeAutoRun = executeAutoRun;
4
+ exports.requestAutoRunStop = requestAutoRunStop;
5
+ const execution_state_1 = require("./execution-state");
6
+ const execution_controls_1 = require("./execution-controls");
7
+ const planning_pack_state_1 = require("./planning-pack-state");
8
+ const auto_run_state_1 = require("./auto-run-state");
9
+ const workspace_1 = require("./workspace");
10
+ const agent_1 = require("./agent");
11
+ const DEFAULT_AUTO_MAX_STEPS = 10;
12
+ async function executeAutoRun(workspaceRoot, options) {
13
+ const planOptions = { planId: options.planId };
14
+ const initialState = await (0, planning_pack_state_1.readPlanningPackState)(workspaceRoot, planOptions);
15
+ assertAutoRunnable(initialState);
16
+ const maxSteps = sanitizeMaxSteps(options.maxSteps);
17
+ let autoRunState = await (0, auto_run_state_1.updateAutoRunState)(workspaceRoot, {
18
+ status: "running",
19
+ startedAt: new Date().toISOString(),
20
+ endedAt: null,
21
+ source: options.source,
22
+ maxSteps,
23
+ stepsAttempted: 0,
24
+ lastStartedStepId: initialState.currentPosition.nextRecommended,
25
+ lastObservedNextStepId: initialState.currentPosition.nextRecommended,
26
+ stopReason: null
27
+ }, planOptions);
28
+ await emit(options, `Auto mode started for plan \`${initialState.planId}\` with max ${maxSteps} step${maxSteps === 1 ? "" : "s"}.`);
29
+ for (let iteration = 0; iteration < maxSteps; iteration += 1) {
30
+ const requestedStopState = await (0, auto_run_state_1.loadAutoRunState)(workspaceRoot, planOptions);
31
+ if (requestedStopState?.status === "stop_requested") {
32
+ autoRunState = await finalizeAutoRun(workspaceRoot, "stopped", "Stop requested by user.", options, {
33
+ stepsAttempted: iteration
34
+ });
35
+ return {
36
+ finalState: autoRunState,
37
+ summary: autoRunState.stopReason ?? "Auto run stopped."
38
+ };
39
+ }
40
+ const beforeState = await (0, planning_pack_state_1.readPlanningPackState)(workspaceRoot, planOptions);
41
+ const naturalStop = describeNaturalStop(beforeState, iteration, maxSteps);
42
+ if (naturalStop) {
43
+ autoRunState = await finalizeAutoRun(workspaceRoot, naturalStop.status, naturalStop.reason, options, {
44
+ stepsAttempted: iteration,
45
+ lastObservedNextStepId: beforeState.currentPosition.nextRecommended
46
+ });
47
+ return {
48
+ finalState: autoRunState,
49
+ summary: naturalStop.reason
50
+ };
51
+ }
52
+ const stepLabel = (0, execution_controls_1.formatStepLabel)(beforeState.nextStepSummary, beforeState.currentPosition.nextRecommended) ?? "unknown step";
53
+ await emit(options, `Auto iteration ${iteration + 1}/${maxSteps}: ${stepLabel}`);
54
+ autoRunState = await (0, auto_run_state_1.updateAutoRunState)(workspaceRoot, {
55
+ status: "running",
56
+ source: options.source,
57
+ maxSteps,
58
+ stepsAttempted: iteration + 1,
59
+ lastStartedStepId: beforeState.currentPosition.nextRecommended,
60
+ lastObservedNextStepId: beforeState.currentPosition.nextRecommended,
61
+ stopReason: null
62
+ }, planOptions);
63
+ const iterationResult = await executeIteration(workspaceRoot, beforeState, options);
64
+ if (!iterationResult.success) {
65
+ autoRunState = await finalizeAutoRun(workspaceRoot, "failed", iterationResult.summary, options, {
66
+ stepsAttempted: iteration + 1,
67
+ lastStartedStepId: beforeState.currentPosition.nextRecommended,
68
+ lastObservedNextStepId: iterationResult.afterState.currentPosition.nextRecommended
69
+ });
70
+ return {
71
+ finalState: autoRunState,
72
+ summary: iterationResult.summary
73
+ };
74
+ }
75
+ await emit(options, iterationResult.summary);
76
+ }
77
+ autoRunState = await finalizeAutoRun(workspaceRoot, "stopped", `Reached the auto-run step cap (${maxSteps}).`, options, { stepsAttempted: maxSteps });
78
+ return {
79
+ finalState: autoRunState,
80
+ summary: autoRunState.stopReason ?? `Reached the auto-run step cap (${maxSteps}).`
81
+ };
82
+ }
83
+ async function requestAutoRunStop(workspaceRoot, options = {}) {
84
+ const current = await (0, auto_run_state_1.loadAutoRunState)(workspaceRoot, options);
85
+ const status = current?.status === "running" ? "stop_requested" : "stopped";
86
+ return (0, auto_run_state_1.updateAutoRunState)(workspaceRoot, {
87
+ status,
88
+ stopReason: status === "stop_requested" ? "Stop requested by user." : "No active auto run was in progress."
89
+ }, options);
90
+ }
91
+ function sanitizeMaxSteps(value) {
92
+ if (!value || !Number.isFinite(value) || value < 1) {
93
+ return DEFAULT_AUTO_MAX_STEPS;
94
+ }
95
+ return Math.floor(value);
96
+ }
97
+ function assertAutoRunnable(state) {
98
+ if (!state.packPresent) {
99
+ throw new Error("Auto mode requires an existing planning pack.");
100
+ }
101
+ if (state.packMode !== "authored") {
102
+ throw new Error("Auto mode only runs authored plans. Finish planning and `/write` the pack first.");
103
+ }
104
+ if (!(0, planning_pack_state_1.isExecutionReadyState)(state)) {
105
+ throw new Error("Auto mode requires a queued execution step in the selected plan.");
106
+ }
107
+ }
108
+ function describeNaturalStop(state, iteration, maxSteps) {
109
+ if (!state.currentPosition.nextRecommended) {
110
+ return {
111
+ status: "completed",
112
+ reason: "Auto mode completed because no next recommended step remains."
113
+ };
114
+ }
115
+ if (!state.nextStepSummary) {
116
+ return {
117
+ status: "failed",
118
+ reason: `Auto mode stopped because the tracker could not summarize \`${state.currentPosition.nextRecommended}\`.`
119
+ };
120
+ }
121
+ if (state.nextStepSummary.status.toLowerCase() === "blocked") {
122
+ return {
123
+ status: "failed",
124
+ reason: `Auto mode stopped because ${state.nextStepSummary.id} is blocked.`
125
+ };
126
+ }
127
+ if (!(0, planning_pack_state_1.isExecutionReadyState)(state)) {
128
+ return {
129
+ status: "stopped",
130
+ reason: `Auto mode stopped because ${state.nextStepSummary.id} is outside execution scope.`
131
+ };
132
+ }
133
+ if (iteration >= maxSteps) {
134
+ return {
135
+ status: "stopped",
136
+ reason: `Reached the auto-run step cap (${maxSteps}).`
137
+ };
138
+ }
139
+ return null;
140
+ }
141
+ async function executeIteration(workspaceRoot, beforeState, options) {
142
+ const planOptions = { planId: options.planId };
143
+ const paths = (0, workspace_1.getPlanningPackPaths)(workspaceRoot, planOptions);
144
+ const prompt = await (0, workspace_1.readText)(paths.nextPrompt);
145
+ const targetStepId = beforeState.currentPosition.nextRecommended;
146
+ const stepLabel = (0, execution_controls_1.formatStepLabel)(beforeState.nextStepSummary, beforeState.currentPosition.nextRecommended);
147
+ let firstAttempt;
148
+ try {
149
+ const result = await (0, agent_1.runNextPrompt)(workspaceRoot, prompt, {
150
+ agentId: options.agentId,
151
+ planId: beforeState.planId
152
+ });
153
+ firstAttempt = { ok: true, message: result };
154
+ }
155
+ catch (error) {
156
+ firstAttempt = { ok: false, message: error instanceof Error ? error.message : String(error) };
157
+ }
158
+ const firstAfterState = await (0, planning_pack_state_1.readPlanningPackState)(workspaceRoot, planOptions);
159
+ const firstReconciled = hasTrackerAdvanced(beforeState, firstAfterState, targetStepId);
160
+ if (firstReconciled) {
161
+ const summary = firstAttempt.ok
162
+ ? firstAttempt.message
163
+ : `Reconciled success after an execution error because the tracker advanced for ${targetStepId ?? "the active step"}.`;
164
+ await (0, execution_state_1.saveExecutionState)(workspaceRoot, "success", options.source, summary, planOptions);
165
+ await (0, execution_state_1.appendExecutionLog)(workspaceRoot, "success", options.source, summary, {
166
+ planId: beforeState.planId,
167
+ stepLabel
168
+ });
169
+ return {
170
+ success: true,
171
+ summary: `Completed ${stepLabel ?? targetStepId ?? "the current step"} and advanced the tracker.`,
172
+ afterState: firstAfterState
173
+ };
174
+ }
175
+ await emit(options, `No tracker advancement detected for ${stepLabel ?? targetStepId ?? "the current step"}; retrying once.`);
176
+ try {
177
+ const retryResult = await (0, agent_1.runNextPrompt)(workspaceRoot, prompt, {
178
+ agentId: options.agentId,
179
+ planId: beforeState.planId
180
+ });
181
+ const retryAfterState = await (0, planning_pack_state_1.readPlanningPackState)(workspaceRoot, planOptions);
182
+ if (hasTrackerAdvanced(beforeState, retryAfterState, targetStepId)) {
183
+ await (0, execution_state_1.saveExecutionState)(workspaceRoot, "success", options.source, retryResult, planOptions);
184
+ await (0, execution_state_1.appendExecutionLog)(workspaceRoot, "success", options.source, retryResult, {
185
+ planId: beforeState.planId,
186
+ stepLabel
187
+ });
188
+ return {
189
+ success: true,
190
+ summary: `Completed ${stepLabel ?? targetStepId ?? "the current step"} after one reconciliation retry.`,
191
+ afterState: retryAfterState
192
+ };
193
+ }
194
+ const failureSummary = `Auto mode failed because ${targetStepId ?? "the current step"} did not advance after one retry.`;
195
+ await (0, execution_state_1.saveExecutionState)(workspaceRoot, "failure", options.source, failureSummary, planOptions);
196
+ await (0, execution_state_1.appendExecutionLog)(workspaceRoot, "failure", options.source, failureSummary, {
197
+ planId: beforeState.planId,
198
+ stepLabel
199
+ });
200
+ return {
201
+ success: false,
202
+ summary: failureSummary,
203
+ afterState: retryAfterState
204
+ };
205
+ }
206
+ catch (error) {
207
+ const retryAfterState = await (0, planning_pack_state_1.readPlanningPackState)(workspaceRoot, planOptions);
208
+ if (hasTrackerAdvanced(beforeState, retryAfterState, targetStepId)) {
209
+ const summary = `Reconciled success after a retry failure because the tracker advanced for ${targetStepId ?? "the active step"}.`;
210
+ await (0, execution_state_1.saveExecutionState)(workspaceRoot, "success", options.source, summary, planOptions);
211
+ await (0, execution_state_1.appendExecutionLog)(workspaceRoot, "success", options.source, summary, {
212
+ planId: beforeState.planId,
213
+ stepLabel
214
+ });
215
+ return {
216
+ success: true,
217
+ summary: `Completed ${stepLabel ?? targetStepId ?? "the current step"} after reconciliation.`,
218
+ afterState: retryAfterState
219
+ };
220
+ }
221
+ const failureSummary = `Auto mode failed because ${targetStepId ?? "the current step"} did not advance after one retry. Reason: ${error instanceof Error ? error.message : String(error)}`;
222
+ await (0, execution_state_1.saveExecutionState)(workspaceRoot, "failure", options.source, failureSummary, planOptions);
223
+ await (0, execution_state_1.appendExecutionLog)(workspaceRoot, "failure", options.source, failureSummary, {
224
+ planId: beforeState.planId,
225
+ stepLabel
226
+ });
227
+ return {
228
+ success: false,
229
+ summary: failureSummary,
230
+ afterState: retryAfterState
231
+ };
232
+ }
233
+ }
234
+ function hasTrackerAdvanced(beforeState, afterState, targetStepId) {
235
+ if (!targetStepId) {
236
+ return false;
237
+ }
238
+ if (afterState.currentPosition.nextRecommended && afterState.currentPosition.nextRecommended !== targetStepId) {
239
+ return true;
240
+ }
241
+ if (afterState.currentPosition.lastCompleted === targetStepId) {
242
+ return true;
243
+ }
244
+ if (afterState.nextStepSummary && afterState.nextStepSummary.id === targetStepId) {
245
+ const status = afterState.nextStepSummary.status.toLowerCase();
246
+ if (status === "done" || status === "skipped") {
247
+ return true;
248
+ }
249
+ }
250
+ return false;
251
+ }
252
+ async function finalizeAutoRun(workspaceRoot, status, reason, options, updates = {}) {
253
+ const nextState = await (0, auto_run_state_1.updateAutoRunState)(workspaceRoot, {
254
+ ...updates,
255
+ status,
256
+ endedAt: new Date().toISOString(),
257
+ stopReason: reason
258
+ }, { planId: options.planId });
259
+ await (0, execution_state_1.appendExecutionLog)(workspaceRoot, status === "failed" ? "failure" : "success", options.source, reason, {
260
+ planId: nextState.planId,
261
+ stepLabel: "auto-run summary"
262
+ });
263
+ await emit(options, reason);
264
+ return nextState;
265
+ }
266
+ async function emit(options, line) {
267
+ if (options.onMessage) {
268
+ await options.onMessage(line);
269
+ }
270
+ }
@@ -40,7 +40,7 @@ async function detectClaude() {
40
40
  };
41
41
  }
42
42
  }
43
- async function requestPlannerReply(workspaceRoot, messages) {
43
+ async function requestPlannerReply(workspaceRoot, messages, _options = {}) {
44
44
  const result = await runClaudeExec({
45
45
  cwd: workspaceRoot,
46
46
  prompt: (0, prompts_1.buildPlannerPrompt)(messages, workspaceRoot),
@@ -49,16 +49,16 @@ async function requestPlannerReply(workspaceRoot, messages) {
49
49
  });
50
50
  return result.lastMessage.trim();
51
51
  }
52
- async function writePlanningPack(workspaceRoot, messages) {
53
- const planningEpoch = await (0, planning_epochs_1.preparePlanningPackForWrite)(workspaceRoot);
52
+ async function writePlanningPack(workspaceRoot, messages, options = {}) {
53
+ const planningEpoch = await (0, planning_epochs_1.preparePlanningPackForWrite)(workspaceRoot, options);
54
54
  const claudeStatus = await detectClaude();
55
55
  if (!claudeStatus.available) {
56
- return appendPlanningEpochSummary(planningEpoch, await (0, local_pack_1.writePlanningPackFallback)(workspaceRoot, messages, claudeStatus.error ?? "Claude Code CLI is unavailable", "Claude Code"));
56
+ return appendPlanningEpochSummary(planningEpoch, await (0, local_pack_1.writePlanningPackFallback)(workspaceRoot, messages, claudeStatus.error ?? "Claude Code CLI is unavailable", "Claude Code", options));
57
57
  }
58
58
  try {
59
59
  const result = await runClaudeExec({
60
60
  cwd: workspaceRoot,
61
- prompt: await (0, prompts_1.buildPackWriterPrompt)(messages, workspaceRoot),
61
+ prompt: await (0, prompts_1.buildPackWriterPrompt)(messages, workspaceRoot, options),
62
62
  permissionMode: "acceptEdits",
63
63
  allowedTools: CLAUDE_WRITE_ALLOW_TOOLS,
64
64
  maxTurns: 24
@@ -68,7 +68,7 @@ async function writePlanningPack(workspaceRoot, messages) {
68
68
  catch (error) {
69
69
  if (isClaudeUnavailableError(error)) {
70
70
  const message = error instanceof Error ? error.message : "Claude Code CLI is unavailable";
71
- return appendPlanningEpochSummary(planningEpoch, await (0, local_pack_1.writePlanningPackFallback)(workspaceRoot, messages, message, "Claude Code"));
71
+ return appendPlanningEpochSummary(planningEpoch, await (0, local_pack_1.writePlanningPackFallback)(workspaceRoot, messages, message, "Claude Code", options));
72
72
  }
73
73
  const message = error instanceof Error ? error.message : String(error);
74
74
  const epochSummary = (0, planning_epochs_1.formatPlanningEpochSummary)(planningEpoch);
@@ -78,7 +78,7 @@ async function writePlanningPack(workspaceRoot, messages) {
78
78
  throw error;
79
79
  }
80
80
  }
81
- async function runNextPrompt(workspaceRoot, prompt) {
81
+ async function runNextPrompt(workspaceRoot, prompt, _options = {}) {
82
82
  const result = await runClaudeExec({
83
83
  cwd: workspaceRoot,
84
84
  prompt,
@@ -37,7 +37,7 @@ async function detectCodex() {
37
37
  };
38
38
  }
39
39
  }
40
- async function requestPlannerReply(workspaceRoot, messages) {
40
+ async function requestPlannerReply(workspaceRoot, messages, _options = {}) {
41
41
  const result = await runCodexExec({
42
42
  cwd: workspaceRoot,
43
43
  prompt: (0, prompts_1.buildPlannerPrompt)(messages, workspaceRoot),
@@ -47,16 +47,16 @@ async function requestPlannerReply(workspaceRoot, messages) {
47
47
  });
48
48
  return result.lastMessage.trim();
49
49
  }
50
- async function writePlanningPack(workspaceRoot, messages) {
51
- const planningEpoch = await (0, planning_epochs_1.preparePlanningPackForWrite)(workspaceRoot);
50
+ async function writePlanningPack(workspaceRoot, messages, options = {}) {
51
+ const planningEpoch = await (0, planning_epochs_1.preparePlanningPackForWrite)(workspaceRoot, options);
52
52
  const codexStatus = await detectCodex();
53
53
  if (!codexStatus.available) {
54
- return appendPlanningEpochSummary(planningEpoch, await (0, local_pack_1.writePlanningPackFallback)(workspaceRoot, messages, codexStatus.error ?? "Codex is unavailable", "Codex"));
54
+ return appendPlanningEpochSummary(planningEpoch, await (0, local_pack_1.writePlanningPackFallback)(workspaceRoot, messages, codexStatus.error ?? "Codex is unavailable", "Codex", options));
55
55
  }
56
56
  try {
57
57
  const result = await runCodexExec({
58
58
  cwd: workspaceRoot,
59
- prompt: await (0, prompts_1.buildPackWriterPrompt)(messages, workspaceRoot),
59
+ prompt: await (0, prompts_1.buildPackWriterPrompt)(messages, workspaceRoot, options),
60
60
  allowWrite: true,
61
61
  skipGitRepoCheck: true,
62
62
  ephemeral: false
@@ -66,7 +66,7 @@ async function writePlanningPack(workspaceRoot, messages) {
66
66
  catch (error) {
67
67
  if (isCodexUnavailableError(error)) {
68
68
  const message = error instanceof Error ? error.message : "Codex is unavailable";
69
- return appendPlanningEpochSummary(planningEpoch, await (0, local_pack_1.writePlanningPackFallback)(workspaceRoot, messages, message, "Codex"));
69
+ return appendPlanningEpochSummary(planningEpoch, await (0, local_pack_1.writePlanningPackFallback)(workspaceRoot, messages, message, "Codex", options));
70
70
  }
71
71
  const message = error instanceof Error ? error.message : String(error);
72
72
  const epochSummary = (0, planning_epochs_1.formatPlanningEpochSummary)(planningEpoch);
@@ -76,7 +76,7 @@ async function writePlanningPack(workspaceRoot, messages) {
76
76
  throw error;
77
77
  }
78
78
  }
79
- async function runNextPrompt(workspaceRoot, prompt) {
79
+ async function runNextPrompt(workspaceRoot, prompt, _options = {}) {
80
80
  const result = await runCodexExec({
81
81
  cwd: workspaceRoot,
82
82
  prompt,
@@ -5,8 +5,8 @@ exports.saveExecutionState = saveExecutionState;
5
5
  exports.appendExecutionLog = appendExecutionLog;
6
6
  const promises_1 = require("node:fs/promises");
7
7
  const workspace_1 = require("./workspace");
8
- async function loadExecutionState(workspaceRoot) {
9
- const paths = (0, workspace_1.getPlanningPackPaths)(workspaceRoot);
8
+ async function loadExecutionState(workspaceRoot, options = {}) {
9
+ const paths = (0, workspace_1.getPlanningPackPaths)(workspaceRoot, options);
10
10
  const exists = await (0, workspace_1.fileExists)(paths.executionState);
11
11
  if (!exists) {
12
12
  return null;
@@ -33,8 +33,8 @@ async function loadExecutionState(workspaceRoot) {
33
33
  return null;
34
34
  }
35
35
  }
36
- async function saveExecutionState(workspaceRoot, status, source, summary) {
37
- const paths = await (0, workspace_1.ensurePlanningDir)(workspaceRoot);
36
+ async function saveExecutionState(workspaceRoot, status, source, summary, options = {}) {
37
+ const paths = await (0, workspace_1.ensurePlanningDir)(workspaceRoot, options);
38
38
  const payload = {
39
39
  version: 1,
40
40
  updatedAt: new Date().toISOString(),
@@ -45,7 +45,7 @@ async function saveExecutionState(workspaceRoot, status, source, summary) {
45
45
  await (0, workspace_1.writeText)(paths.executionState, JSON.stringify(payload, null, 2));
46
46
  }
47
47
  async function appendExecutionLog(workspaceRoot, status, source, summary, options = {}) {
48
- const paths = await (0, workspace_1.ensurePlanningDir)(workspaceRoot);
48
+ const paths = await (0, workspace_1.ensurePlanningDir)(workspaceRoot, options);
49
49
  const entry = buildExecutionLogEntry(status, source, summary, options);
50
50
  const exists = await (0, workspace_1.fileExists)(paths.executionLog);
51
51
  if (!exists) {
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.writePlanningPackFallback = writePlanningPackFallback;
4
+ const planning_state_1 = require("./planning-state");
4
5
  const templates_1 = require("./templates");
5
6
  const workspace_1 = require("./workspace");
6
- async function writePlanningPackFallback(workspaceRoot, messages, reason, agentLabel = "Codex") {
7
- const paths = await (0, workspace_1.ensurePlanningDir)(workspaceRoot);
7
+ async function writePlanningPackFallback(workspaceRoot, messages, reason, agentLabel = "Codex", options = {}) {
8
+ const paths = await (0, workspace_1.ensurePlanningDir)(workspaceRoot, options);
8
9
  const templates = (0, templates_1.getInitialTemplates)(paths);
9
10
  const createdFiles = [];
10
11
  const preservedFiles = [];
@@ -30,6 +31,7 @@ async function writePlanningPackFallback(workspaceRoot, messages, reason, agentL
30
31
  ? `Tracker remains on next recommended step: ${currentPosition.nextRecommended}`
31
32
  : "Tracker next step is not yet available."
32
33
  ];
34
+ await (0, planning_state_1.ensurePlanningPackState)(workspaceRoot, "scaffolded", options);
33
35
  return summary.join("\n");
34
36
  }
35
37
  function buildFallbackEntry(messages, reason, createdFiles, preservedFiles, currentPosition, agentLabel) {
@@ -106,17 +108,18 @@ function appendFallbackEntry(context, entry) {
106
108
  return `${context.trimEnd()}\n\n## Handoff Log\n\n${entry}\n`;
107
109
  }
108
110
  function toPackLabel(paths, filePath) {
111
+ const prefix = `${paths.relativeDir}/`;
109
112
  if (filePath === paths.plan) {
110
- return ".srgical/01-product-plan.md";
113
+ return `${prefix}01-product-plan.md`;
111
114
  }
112
115
  if (filePath === paths.context) {
113
- return ".srgical/02-agent-context-kickoff.md";
116
+ return `${prefix}02-agent-context-kickoff.md`;
114
117
  }
115
118
  if (filePath === paths.tracker) {
116
- return ".srgical/03-detailed-implementation-plan.md";
119
+ return `${prefix}03-detailed-implementation-plan.md`;
117
120
  }
118
121
  if (filePath === paths.nextPrompt) {
119
- return ".srgical/04-next-agent-prompt.md";
122
+ return `${prefix}04-next-agent-prompt.md`;
120
123
  }
121
124
  return filePath;
122
125
  }
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.readInstalledPackageInfo = readInstalledPackageInfo;
7
+ exports.readLocalChangelog = readLocalChangelog;
8
+ exports.isPlaceholderChangelog = isPlaceholderChangelog;
9
+ const node_fs_1 = require("node:fs");
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ function readInstalledPackageInfo() {
12
+ const packageRoot = resolvePackageRoot();
13
+ const packageJsonPath = node_path_1.default.join(packageRoot, "package.json");
14
+ const packageJson = JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, "utf8"));
15
+ const repositoryUrl = normalizeRepositoryUrl(packageJson.repository);
16
+ const releasesUrl = repositoryUrl ? `${repositoryUrl}/releases` : undefined;
17
+ const version = packageJson.version ?? "0.0.0";
18
+ return {
19
+ packageRoot,
20
+ name: packageJson.name ?? "srgical",
21
+ version,
22
+ description: packageJson.description ?? "Local-first AI planning and execution orchestration.",
23
+ homepage: packageJson.homepage,
24
+ repositoryUrl,
25
+ issuesUrl: packageJson.bugs?.url,
26
+ releasesUrl,
27
+ releaseNotesUrl: releasesUrl ? `${releasesUrl}/tag/v${version}` : undefined,
28
+ changelogPath: node_path_1.default.join(packageRoot, "CHANGELOG.md")
29
+ };
30
+ }
31
+ function readLocalChangelog() {
32
+ const info = readInstalledPackageInfo();
33
+ try {
34
+ return (0, node_fs_1.readFileSync)(info.changelogPath, "utf8").trim();
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ function isPlaceholderChangelog(content) {
41
+ if (!content) {
42
+ return true;
43
+ }
44
+ const normalized = content.replace(/\r\n/g, "\n").trim();
45
+ return (normalized ===
46
+ "# Changelog\n\nRelease history is tracked through git tags, GitHub Releases, GitHub Packages, and npm.\n\nThe repo keeps a base version line in `package.json`, and CI computes the next patch version at release time.");
47
+ }
48
+ function resolvePackageRoot() {
49
+ return node_path_1.default.resolve(__dirname, "..", "..");
50
+ }
51
+ function normalizeRepositoryUrl(repository) {
52
+ const raw = typeof repository === "string"
53
+ ? repository
54
+ : repository && typeof repository === "object"
55
+ ? repository.url
56
+ : undefined;
57
+ if (!raw) {
58
+ return undefined;
59
+ }
60
+ return raw.replace(/^git\+/, "").replace(/\.git$/, "");
61
+ }
@@ -10,6 +10,7 @@ exports.listArchivedPackFileNames = listArchivedPackFileNames;
10
10
  const promises_1 = require("node:fs/promises");
11
11
  const node_path_1 = __importDefault(require("node:path"));
12
12
  const planning_pack_state_1 = require("./planning-pack-state");
13
+ const planning_state_1 = require("./planning-state");
13
14
  const templates_1 = require("./templates");
14
15
  const workspace_1 = require("./workspace");
15
16
  const ARCHIVED_PACK_FILE_NAMES = [
@@ -18,11 +19,13 @@ const ARCHIVED_PACK_FILE_NAMES = [
18
19
  "03-detailed-implementation-plan.md",
19
20
  "04-next-agent-prompt.md",
20
21
  "studio-session.json",
22
+ "planning-state.json",
23
+ "auto-run-state.json",
21
24
  "execution-state.json",
22
25
  "execution-log.md"
23
26
  ];
24
- async function preparePlanningPackForWrite(workspaceRoot) {
25
- const packState = await (0, planning_pack_state_1.readPlanningPackState)(workspaceRoot);
27
+ async function preparePlanningPackForWrite(workspaceRoot, options = {}) {
28
+ const packState = await (0, planning_pack_state_1.readPlanningPackState)(workspaceRoot, options);
26
29
  if (!packState.packPresent || packState.currentPosition.nextRecommended) {
27
30
  return {
28
31
  archived: false,
@@ -30,7 +33,7 @@ async function preparePlanningPackForWrite(workspaceRoot) {
30
33
  archivedFiles: []
31
34
  };
32
35
  }
33
- const paths = await (0, workspace_1.ensurePlanningDir)(workspaceRoot);
36
+ const paths = await (0, workspace_1.ensurePlanningDir)(workspaceRoot, options);
34
37
  const archiveDirName = await nextPlanningEpochName(paths.dir);
35
38
  const archiveDir = node_path_1.default.join(paths.dir, archiveDirName);
36
39
  await (0, promises_1.mkdir)(archiveDir, { recursive: false });
@@ -69,7 +72,9 @@ async function archiveActivePlanningFiles(paths, archiveDir) {
69
72
  async function resetActivePlanningPack(paths) {
70
73
  const templates = (0, templates_1.getInitialTemplates)(paths);
71
74
  await Promise.all(Object.entries(templates).map(([filePath, content]) => (0, workspace_1.writeText)(filePath, content)));
75
+ await (0, planning_state_1.savePlanningState)(paths.root, "scaffolded", { planId: paths.planId });
72
76
  await Promise.all([
77
+ (0, promises_1.rm)(paths.autoRunState, { force: true }),
73
78
  (0, promises_1.rm)(paths.executionState, { force: true }),
74
79
  (0, promises_1.rm)(paths.executionLog, { force: true })
75
80
  ]);
@@ -81,6 +86,8 @@ function listArchivablePaths(paths) {
81
86
  paths.tracker,
82
87
  paths.nextPrompt,
83
88
  paths.studioSession,
89
+ paths.planningState,
90
+ paths.autoRunState,
84
91
  paths.executionState,
85
92
  paths.executionLog
86
93
  ];