@launch11/srgical 0.0.1

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,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_STUDIO_MESSAGES = void 0;
4
+ exports.loadStudioSession = loadStudioSession;
5
+ exports.loadStudioSessionState = loadStudioSessionState;
6
+ exports.saveStudioSession = saveStudioSession;
7
+ exports.loadStoredActiveAgentId = loadStoredActiveAgentId;
8
+ exports.saveStoredActiveAgentId = saveStoredActiveAgentId;
9
+ const workspace_1 = require("./workspace");
10
+ exports.DEFAULT_STUDIO_MESSAGES = [
11
+ {
12
+ role: "assistant",
13
+ content: "Describe what you are building, what is already true in the repo, or the next decision you need to make. I will help turn it into a disciplined `.srgical/` execution pack, and `/write` will update the repo files when you are ready."
14
+ }
15
+ ];
16
+ async function loadStudioSession(workspaceRoot) {
17
+ return (await loadStudioSessionState(workspaceRoot)).messages;
18
+ }
19
+ async function loadStudioSessionState(workspaceRoot) {
20
+ const paths = (0, workspace_1.getPlanningPackPaths)(workspaceRoot);
21
+ const exists = await (0, workspace_1.fileExists)(paths.studioSession);
22
+ if (!exists) {
23
+ return createDefaultSessionState();
24
+ }
25
+ try {
26
+ const raw = await (0, workspace_1.readText)(paths.studioSession);
27
+ const parsed = JSON.parse(raw);
28
+ const messages = Array.isArray(parsed.messages) ? sanitizeMessages(parsed.messages) : [];
29
+ return {
30
+ messages: messages.length > 0 ? messages : cloneMessages(exports.DEFAULT_STUDIO_MESSAGES),
31
+ activeAgentId: sanitizeActiveAgentId(parsed.activeAgentId)
32
+ };
33
+ }
34
+ catch {
35
+ return createDefaultSessionState();
36
+ }
37
+ }
38
+ async function saveStudioSession(workspaceRoot, messages) {
39
+ const currentState = await loadStudioSessionState(workspaceRoot);
40
+ await writeStudioSession(workspaceRoot, {
41
+ messages,
42
+ activeAgentId: currentState.activeAgentId
43
+ });
44
+ }
45
+ async function loadStoredActiveAgentId(workspaceRoot) {
46
+ return (await loadStudioSessionState(workspaceRoot)).activeAgentId;
47
+ }
48
+ async function saveStoredActiveAgentId(workspaceRoot, activeAgentId) {
49
+ const currentState = await loadStudioSessionState(workspaceRoot);
50
+ await writeStudioSession(workspaceRoot, {
51
+ messages: currentState.messages,
52
+ activeAgentId
53
+ });
54
+ }
55
+ async function writeStudioSession(workspaceRoot, state) {
56
+ const paths = await (0, workspace_1.ensurePlanningDir)(workspaceRoot);
57
+ const payload = {
58
+ version: 2,
59
+ updatedAt: new Date().toISOString(),
60
+ messages: sanitizeMessages(state.messages),
61
+ activeAgentId: sanitizeActiveAgentId(state.activeAgentId)
62
+ };
63
+ await (0, workspace_1.writeText)(paths.studioSession, JSON.stringify(payload, null, 2));
64
+ }
65
+ function sanitizeMessages(messages) {
66
+ return messages
67
+ .filter((message) => {
68
+ if (!message || typeof message !== "object") {
69
+ return false;
70
+ }
71
+ return isRole(message.role) && typeof message.content === "string" && message.content.trim().length > 0;
72
+ })
73
+ .map((message) => ({
74
+ role: message.role,
75
+ content: message.content
76
+ }));
77
+ }
78
+ function cloneMessages(messages) {
79
+ return messages.map((message) => ({
80
+ role: message.role,
81
+ content: message.content
82
+ }));
83
+ }
84
+ function createDefaultSessionState() {
85
+ return {
86
+ messages: cloneMessages(exports.DEFAULT_STUDIO_MESSAGES),
87
+ activeAgentId: null
88
+ };
89
+ }
90
+ function sanitizeActiveAgentId(value) {
91
+ if (typeof value !== "string") {
92
+ return null;
93
+ }
94
+ const normalized = value.trim().toLowerCase();
95
+ return normalized.length > 0 ? normalized : null;
96
+ }
97
+ function isRole(value) {
98
+ return value === "user" || value === "assistant" || value === "system";
99
+ }
@@ -0,0 +1,189 @@
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.buildPlanTemplate = buildPlanTemplate;
7
+ exports.buildContextTemplate = buildContextTemplate;
8
+ exports.buildTrackerTemplate = buildTrackerTemplate;
9
+ exports.buildNextPromptTemplate = buildNextPromptTemplate;
10
+ exports.getInitialTemplates = getInitialTemplates;
11
+ const node_path_1 = __importDefault(require("node:path"));
12
+ function projectNameFromRoot(root) {
13
+ return node_path_1.default.basename(root);
14
+ }
15
+ function buildPlanTemplate(root) {
16
+ const projectName = projectNameFromRoot(root);
17
+ return `# ${projectName} Product Plan
18
+
19
+ Updated: ${new Date().toISOString().slice(0, 10)}
20
+
21
+ ## Purpose
22
+
23
+ This file is the stable high-level plan for the current project. It should capture the architecture direction, the
24
+ workflow shape, and the non-negotiable product rules that each execution slice must preserve.
25
+
26
+ ## Mission
27
+
28
+ Define and ship a local-first CLI that helps a user:
29
+
30
+ 1. plan a project with an AI inside a dedicated interface,
31
+ 2. write a tracker pack into the repo,
32
+ 3. execute the next eligible delivery slice with AI support,
33
+ 4. keep progress incremental, validated, and resumable.
34
+
35
+ ## Locked Decisions
36
+
37
+ - planning packs live under \`.srgical/\`
38
+ - the workflow remains markdown-first and repo-visible
39
+ - AI actions remain explicit and user-triggered
40
+ - execution should happen in small validated slices
41
+ - the interface should feel intentionally designed, not merely functional
42
+
43
+ ## Primary Workflow To Optimize
44
+
45
+ 1. open a studio
46
+ 2. talk to the planner
47
+ 3. trigger plan-pack generation
48
+ 4. run the next eligible step block
49
+ 5. review validation and continue
50
+
51
+ ## Target End State
52
+
53
+ - the tool owns the planning ritual instead of relying on repeated prompt pastes
54
+ - the pack format stays readable by humans and agents
55
+ - agent execution can resume cleanly from repo state
56
+ - the UI feels like a sharp creative control room
57
+ `;
58
+ }
59
+ function buildContextTemplate() {
60
+ return `# Agent Context Kickoff
61
+
62
+ Updated: ${new Date().toISOString()}
63
+ Updated By: srgical
64
+
65
+ ## Mission
66
+
67
+ Continue the current project from the planning pack in \`.srgical/\`. Read the stable plan, the tracker, and the next
68
+ agent prompt before making changes.
69
+
70
+ ## Working Agreements
71
+
72
+ - execute only the next eligible step or contiguous low-risk step block
73
+ - keep changes incremental and validated
74
+ - update the tracker and this handoff log after each completed block
75
+ - stop when a blocker changes scope materially
76
+
77
+ ## Current Position
78
+
79
+ - Last Completed: \`BOOT-001\`
80
+ - Next Recommended: \`PLAN-001\`
81
+ - Updated At: \`${new Date().toISOString()}\`
82
+ - Updated By: \`srgical\`
83
+
84
+ ## Handoff Log
85
+
86
+ ### ${new Date().toISOString().slice(0, 10)} - BOOT-001 - srgical
87
+
88
+ - Created the initial \`.srgical/\` planning pack.
89
+ - Validation: confirmed the four planning-pack files were written.
90
+ - Blockers: none.
91
+ - Next recommended work: \`PLAN-001\`.
92
+ `;
93
+ }
94
+ function buildTrackerTemplate() {
95
+ return `# Detailed Implementation Plan
96
+
97
+ Updated: ${new Date().toISOString()}
98
+ Updated By: srgical
99
+
100
+ ## Status Legend
101
+
102
+ - \`pending\`: not started
103
+ - \`in_progress\`: currently being executed
104
+ - \`done\`: completed and validated
105
+ - \`blocked\`: cannot proceed without resolving a blocker
106
+ - \`skipped\`: intentionally skipped by an explicit design decision
107
+
108
+ ## Current Position
109
+
110
+ - Last Completed: \`BOOT-001\`
111
+ - Next Recommended: \`PLAN-001\`
112
+ - Updated At: \`${new Date().toISOString()}\`
113
+ - Updated By: \`srgical\`
114
+
115
+ ## Step Rules
116
+
117
+ - Work 1 to 2 contiguous steps only when they stay in the same subsystem and still fit comfortably in context.
118
+ - Do not mark a step \`done\` without recording validation notes.
119
+ - Update the current position and handoff log after each completed block.
120
+ - Stop immediately when a blocker changes scope materially.
121
+
122
+ ## Bootstrap
123
+
124
+ | ID | Status | Depends On | Scope | Acceptance | Notes |
125
+ | --- | --- | --- | --- | --- | --- |
126
+ | BOOT-001 | done | - | Create the planning-pack scaffold. | The \`.srgical/\` pack exists. | Completed during \`srgical init\`. |
127
+
128
+ ## Planning
129
+
130
+ | ID | Status | Depends On | Scope | Acceptance | Notes |
131
+ | --- | --- | --- | --- | --- | --- |
132
+ | PLAN-001 | pending | BOOT-001 | Convert the planning conversation into a stable product plan, kickoff log, tracker, and next-agent prompt. | The pack reflects the real project direction and is ready for execution. | Pending planner write. |
133
+
134
+ ## Delivery
135
+
136
+ | ID | Status | Depends On | Scope | Acceptance | Notes |
137
+ | --- | --- | --- | --- | --- | --- |
138
+ | EXEC-001 | pending | PLAN-001 | Execute the next eligible implementation slice from the tracker. | The selected slice is complete, validated, and logged. | Pending tracker detail. |
139
+ `;
140
+ }
141
+ function buildNextPromptTemplate() {
142
+ return `# Next Agent Prompt
143
+
144
+ You are continuing the current project from the existing repo state. Do not restart product design or casually rewrite
145
+ the whole codebase.
146
+
147
+ ## Read Order
148
+
149
+ 1. Read \`.srgical/02-agent-context-kickoff.md\`.
150
+ 2. Read \`.srgical/01-product-plan.md\`.
151
+ 3. Read \`.srgical/03-detailed-implementation-plan.md\`.
152
+ 4. Execute only the next eligible step block.
153
+
154
+ ## What To Determine Before Editing
155
+
156
+ 1. Identify \`Last Completed\` and \`Next Recommended\` in the tracker.
157
+ 2. Confirm the next eligible step or contiguous low-risk step block.
158
+ 3. Keep scope incremental and validation-aware.
159
+
160
+ ## Execution Rules
161
+
162
+ 1. Announce the chosen step ID or step IDs before making substantive edits.
163
+ 2. Execute the step block end-to-end.
164
+ 3. Preserve the locked product decisions from the plan.
165
+ 4. Run validation appropriate to the step block.
166
+ 5. Update the tracker and kickoff log when the block is complete.
167
+
168
+ ## Required Updates After Execution
169
+
170
+ 1. Update \`.srgical/03-detailed-implementation-plan.md\`.
171
+ 2. Mark finished steps \`done\` only if validation passed.
172
+ 3. Update the \`Current Position\` section.
173
+ 4. Append a dated handoff entry to \`.srgical/02-agent-context-kickoff.md\`.
174
+
175
+ ## Stop Conditions
176
+
177
+ - Stop after finishing the chosen step block.
178
+ - Stop before broadening into a different subsystem unless the tracker explicitly calls for it.
179
+ - Stop and record a blocker if new architecture work is required.
180
+ `;
181
+ }
182
+ function getInitialTemplates(paths) {
183
+ return {
184
+ [paths.plan]: buildPlanTemplate(paths.root),
185
+ [paths.context]: buildContextTemplate(),
186
+ [paths.tracker]: buildTrackerTemplate(),
187
+ [paths.nextPrompt]: buildNextPromptTemplate()
188
+ };
189
+ }
@@ -0,0 +1,67 @@
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.PLAN_DIR = void 0;
7
+ exports.resolveWorkspace = resolveWorkspace;
8
+ exports.getPlanningPackPaths = getPlanningPackPaths;
9
+ exports.ensurePlanningDir = ensurePlanningDir;
10
+ exports.fileExists = fileExists;
11
+ exports.planningPackExists = planningPackExists;
12
+ exports.readText = readText;
13
+ exports.writeText = writeText;
14
+ exports.isGitRepo = isGitRepo;
15
+ const promises_1 = require("node:fs/promises");
16
+ const node_path_1 = __importDefault(require("node:path"));
17
+ exports.PLAN_DIR = ".srgical";
18
+ function resolveWorkspace(input) {
19
+ return node_path_1.default.resolve(input ?? process.cwd());
20
+ }
21
+ function getPlanningPackPaths(root) {
22
+ const dir = node_path_1.default.join(root, exports.PLAN_DIR);
23
+ return {
24
+ root,
25
+ dir,
26
+ plan: node_path_1.default.join(dir, "01-product-plan.md"),
27
+ context: node_path_1.default.join(dir, "02-agent-context-kickoff.md"),
28
+ tracker: node_path_1.default.join(dir, "03-detailed-implementation-plan.md"),
29
+ nextPrompt: node_path_1.default.join(dir, "04-next-agent-prompt.md"),
30
+ studioSession: node_path_1.default.join(dir, "studio-session.json"),
31
+ executionState: node_path_1.default.join(dir, "execution-state.json"),
32
+ executionLog: node_path_1.default.join(dir, "execution-log.md")
33
+ };
34
+ }
35
+ async function ensurePlanningDir(root) {
36
+ const paths = getPlanningPackPaths(root);
37
+ await (0, promises_1.mkdir)(paths.dir, { recursive: true });
38
+ return paths;
39
+ }
40
+ async function fileExists(filePath) {
41
+ try {
42
+ await (0, promises_1.access)(filePath);
43
+ return true;
44
+ }
45
+ catch {
46
+ return false;
47
+ }
48
+ }
49
+ async function planningPackExists(root) {
50
+ const paths = getPlanningPackPaths(root);
51
+ const checks = await Promise.all([
52
+ fileExists(paths.plan),
53
+ fileExists(paths.context),
54
+ fileExists(paths.tracker),
55
+ fileExists(paths.nextPrompt)
56
+ ]);
57
+ return checks.every(Boolean);
58
+ }
59
+ async function readText(filePath) {
60
+ return (0, promises_1.readFile)(filePath, "utf8");
61
+ }
62
+ async function writeText(filePath, content) {
63
+ await (0, promises_1.writeFile)(filePath, content, "utf8");
64
+ }
65
+ async function isGitRepo(root) {
66
+ return fileExists(node_path_1.default.join(root, ".git"));
67
+ }
package/dist/index.js ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = __importDefault(require("node:path"));
9
+ const commander_1 = require("commander");
10
+ const doctor_1 = require("./commands/doctor");
11
+ const init_1 = require("./commands/init");
12
+ const run_next_1 = require("./commands/run-next");
13
+ const studio_1 = require("./commands/studio");
14
+ const program = new commander_1.Command();
15
+ const packageVersion = readPackageVersion();
16
+ program
17
+ .name("srgical")
18
+ .description("Local-first AI planning and execution orchestration.")
19
+ .version(packageVersion);
20
+ program
21
+ .command("doctor")
22
+ .description("Inspect the workspace and local agent availability.")
23
+ .argument("[workspace]", "Workspace path")
24
+ .action(async (workspace) => {
25
+ await (0, doctor_1.runDoctorCommand)(workspace);
26
+ });
27
+ program
28
+ .command("init")
29
+ .description("Create a local .srgical planning pack scaffold.")
30
+ .argument("[workspace]", "Workspace path")
31
+ .option("-f, --force", "Overwrite an existing planning pack")
32
+ .action(async (workspace, options) => {
33
+ await (0, init_1.runInitCommand)(workspace, Boolean(options.force));
34
+ });
35
+ program
36
+ .command("studio")
37
+ .description("Open the planning studio.")
38
+ .argument("[workspace]", "Workspace path")
39
+ .action(async (workspace) => {
40
+ await (0, studio_1.runStudioCommand)(workspace);
41
+ });
42
+ program
43
+ .command("run-next")
44
+ .description("Run the current next-agent prompt through the active agent adapter.")
45
+ .argument("[workspace]", "Workspace path")
46
+ .option("--dry-run", "Preview the current execution prompt without invoking the active agent")
47
+ .option("--agent <id>", "Temporarily override the active agent for this run only")
48
+ .action(async (workspace, options) => {
49
+ await (0, run_next_1.runRunNextCommand)(workspace, { dryRun: Boolean(options.dryRun), agent: options.agent });
50
+ });
51
+ program.parseAsync(process.argv).catch((error) => {
52
+ const message = error instanceof Error ? error.message : String(error);
53
+ process.stderr.write(`${message}\n`);
54
+ process.exitCode = 1;
55
+ });
56
+ function readPackageVersion() {
57
+ const packageJsonPath = node_path_1.default.resolve(__dirname, "..", "package.json");
58
+ const packageJson = JSON.parse((0, node_fs_1.readFileSync)(packageJsonPath, "utf8"));
59
+ return packageJson.version ?? "0.0.0";
60
+ }