@launch11/srgical 0.0.2 → 0.0.4

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/README.md CHANGED
@@ -7,9 +7,9 @@
7
7
  3. repeatedly execute the next eligible step,
8
8
  4. force validation and handoff updates every time.
9
9
 
10
- The current launch slice supports both local `codex` and local `claude` CLI installs through the same `.srgical/`
11
- workflow. `srgical` detects which supported tools are actually installed, keeps the planning pack agent-neutral, and
12
- lets you choose the active agent for the current workspace session.
10
+ The current launch slice supports local `codex`, local `claude`, and local `auggie` installs through the same
11
+ `.srgical/` workflow. `srgical` detects which supported tools are actually installed, keeps the planning pack
12
+ agent-neutral, and lets you choose the active agent for the current workspace session.
13
13
 
14
14
  ## Why This Exists
15
15
 
@@ -46,8 +46,11 @@ This repo currently ships the foundation for:
46
46
  - `claude`
47
47
  Supported through the same adapter seam for planning, pack writing, and execution when the local Claude Code CLI is
48
48
  installed and available on `PATH`.
49
+ - `augment`
50
+ Supported through the same adapter seam by targeting the local `auggie` binary for planning, pack writing, and
51
+ execution when Augment CLI automation is available on the current machine.
49
52
 
50
- If only one supported agent is installed, `srgical` can auto-select it for the workspace session. If both are
53
+ If only one supported agent is installed, `srgical` can auto-select it for the workspace session. If more than one is
51
54
  installed, you can keep the stored choice in the studio and still override a single execution with
52
55
  `srgical run-next --agent <id>`.
53
56
 
@@ -145,6 +148,7 @@ To override the active workspace agent for one execution only:
145
148
  ```bash
146
149
  node dist/index.js run-next --agent codex
147
150
  node dist/index.js run-next --agent claude
151
+ node dist/index.js run-next --agent augment
148
152
  ```
149
153
 
150
154
  ## Current Claude Caveat
@@ -155,8 +159,22 @@ uses `plan` mode for planner replies and `acceptEdits` with allowlisted local to
155
159
  If the Claude CLI is not installed locally, `doctor`, the studio, and `run-next --agent claude` all report that
156
160
  honestly instead of falling back to a fake Claude path.
157
161
 
162
+ ## Current Augment Caveat
163
+
164
+ Augment support is wired to the documented `auggie` automation flags: `--print`, `--quiet`, `--instruction-file`,
165
+ `--workspace-root`, `--rules`, `--allow-indexing`, `--wait-for-indexing`, `--max-turns`, and `--ask` for planner-only
166
+ runs.
167
+
168
+ The defaults deliberately force workspace indexing and append srgical-specific Augment rules so the agent stays biased
169
+ toward incremental planning, validated execution, and clear next-step handoffs. Session history is also left on so
170
+ workspace iterations can accumulate inside Auggie instead of being treated as throwaway runs.
171
+
172
+ That means successful Augment execution still depends on a real Augment CLI install, an authenticated session such as
173
+ `auggie login` or `AUGMENT_SESSION_AUTH`, and whatever automation entitlements or local permission policies your
174
+ account requires.
175
+
158
176
  ## Planned Next Steps
159
177
 
160
178
  - deepen the studio experience without weakening the terminal-first workflow
161
- - keep dual-agent docs and validation honest as Claude runtime behavior gets more live coverage
179
+ - keep multi-agent docs and validation honest as Claude and Augment runtime behavior get more live coverage
162
180
  - expand release outputs from npm tarballs into standalone binaries and wrapper package-manager installers
@@ -12,6 +12,7 @@ exports.runNextPrompt = runNextPrompt;
12
12
  exports.selectPrimaryAgent = selectPrimaryAgent;
13
13
  exports.resetAgentAdaptersForTesting = resetAgentAdaptersForTesting;
14
14
  exports.setAgentAdaptersForTesting = setAgentAdaptersForTesting;
15
+ const augment_1 = require("./augment");
15
16
  const claude_1 = require("./claude");
16
17
  const codex_1 = require("./codex");
17
18
  const studio_session_1 = require("./studio-session");
@@ -51,7 +52,25 @@ const claudeAdapter = {
51
52
  writePlanningPack: claude_1.writePlanningPack,
52
53
  runNextPrompt: claude_1.runNextPrompt
53
54
  };
54
- const defaultAgentAdapters = [codexAdapter, claudeAdapter];
55
+ const augmentAdapter = {
56
+ id: "augment",
57
+ label: "Augment CLI",
58
+ async detectStatus() {
59
+ const status = await (0, augment_1.detectAugment)();
60
+ return {
61
+ id: "augment",
62
+ label: "Augment CLI",
63
+ available: status.available,
64
+ command: status.command,
65
+ version: status.version,
66
+ error: status.error
67
+ };
68
+ },
69
+ requestPlannerReply: augment_1.requestPlannerReply,
70
+ writePlanningPack: augment_1.writePlanningPack,
71
+ runNextPrompt: augment_1.runNextPrompt
72
+ };
73
+ const defaultAgentAdapters = [codexAdapter, claudeAdapter, augmentAdapter];
55
74
  let registeredAgentAdapters = [...defaultAgentAdapters];
56
75
  let primaryAgentId = registeredAgentAdapters[0].id;
57
76
  function getSupportedAgentAdapters() {
@@ -0,0 +1,278 @@
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.detectAugment = detectAugment;
7
+ exports.requestPlannerReply = requestPlannerReply;
8
+ exports.writePlanningPack = writePlanningPack;
9
+ exports.runNextPrompt = runNextPrompt;
10
+ exports.setAugmentRuntimeForTesting = setAugmentRuntimeForTesting;
11
+ exports.resetAugmentRuntimeForTesting = resetAugmentRuntimeForTesting;
12
+ const node_child_process_1 = require("node:child_process");
13
+ const promises_1 = require("node:fs/promises");
14
+ const node_os_1 = __importDefault(require("node:os"));
15
+ const node_path_1 = __importDefault(require("node:path"));
16
+ const local_pack_1 = require("./local-pack");
17
+ const planning_epochs_1 = require("./planning-epochs");
18
+ const prompts_1 = require("./prompts");
19
+ const AUGMENT_INSTALL_HINT = "install Augment CLI to enable";
20
+ const AUGMENT_DEFAULT_RULES = `You are operating inside srgical, a local-first planning and iteration machine.
21
+
22
+ Default behavior:
23
+ - Ground decisions in the current repository state and the current .srgical files when they exist.
24
+ - Prefer small validated steps over broad speculative rewrites.
25
+ - Preserve a clear next-step handoff after each meaningful change.
26
+ - Treat planning as preparation for execution, not open-ended brainstorming.
27
+ - Keep outputs practical, explicit, and ready for the next iteration.`;
28
+ let augmentCommandPromise;
29
+ let forcedAugmentCommand = null;
30
+ let spawnAndCaptureImpl = spawnAndCaptureBase;
31
+ async function detectAugment() {
32
+ try {
33
+ const command = await resolveAugmentCommand();
34
+ const version = await spawnAndCaptureImpl(command, ["--version"], process.cwd());
35
+ return {
36
+ available: true,
37
+ command,
38
+ version: version.stdout.trim()
39
+ };
40
+ }
41
+ catch (error) {
42
+ return {
43
+ available: false,
44
+ command: process.platform === "win32" ? "auggie.exe" : "auggie",
45
+ error: normalizeAugmentDetectionError(error)
46
+ };
47
+ }
48
+ }
49
+ async function requestPlannerReply(workspaceRoot, messages) {
50
+ const result = await runAugmentExec({
51
+ cwd: workspaceRoot,
52
+ prompt: (0, prompts_1.buildPlannerPrompt)(messages, workspaceRoot),
53
+ askMode: true,
54
+ maxTurns: 4
55
+ });
56
+ return result.lastMessage.trim();
57
+ }
58
+ async function writePlanningPack(workspaceRoot, messages) {
59
+ const planningEpoch = await (0, planning_epochs_1.preparePlanningPackForWrite)(workspaceRoot);
60
+ const augmentStatus = await detectAugment();
61
+ if (!augmentStatus.available) {
62
+ return appendPlanningEpochSummary(planningEpoch, await (0, local_pack_1.writePlanningPackFallback)(workspaceRoot, messages, augmentStatus.error ?? "Augment CLI is unavailable", "Augment CLI"));
63
+ }
64
+ try {
65
+ const result = await runAugmentExec({
66
+ cwd: workspaceRoot,
67
+ prompt: await (0, prompts_1.buildPackWriterPrompt)(messages, workspaceRoot),
68
+ maxTurns: 24
69
+ });
70
+ return appendPlanningEpochSummary(planningEpoch, result.lastMessage.trim());
71
+ }
72
+ catch (error) {
73
+ if (isAugmentUnavailableError(error)) {
74
+ const message = error instanceof Error ? error.message : "Augment CLI is unavailable";
75
+ return appendPlanningEpochSummary(planningEpoch, await (0, local_pack_1.writePlanningPackFallback)(workspaceRoot, messages, message, "Augment CLI"));
76
+ }
77
+ const message = error instanceof Error ? error.message : String(error);
78
+ const epochSummary = (0, planning_epochs_1.formatPlanningEpochSummary)(planningEpoch);
79
+ if (epochSummary) {
80
+ throw new Error(`${epochSummary}\n${message}`);
81
+ }
82
+ throw error;
83
+ }
84
+ }
85
+ async function runNextPrompt(workspaceRoot, prompt) {
86
+ const result = await runAugmentExec({
87
+ cwd: workspaceRoot,
88
+ prompt,
89
+ maxTurns: 24
90
+ });
91
+ return result.lastMessage.trim();
92
+ }
93
+ function setAugmentRuntimeForTesting(options) {
94
+ if (Object.prototype.hasOwnProperty.call(options, "command")) {
95
+ forcedAugmentCommand = options.command ?? null;
96
+ augmentCommandPromise = undefined;
97
+ }
98
+ if (options.spawnAndCapture) {
99
+ spawnAndCaptureImpl = options.spawnAndCapture;
100
+ }
101
+ }
102
+ function resetAugmentRuntimeForTesting() {
103
+ forcedAugmentCommand = null;
104
+ augmentCommandPromise = undefined;
105
+ spawnAndCaptureImpl = spawnAndCaptureBase;
106
+ }
107
+ async function runAugmentExec(options) {
108
+ const tempDir = await (0, promises_1.mkdtemp)(node_path_1.default.join(node_os_1.default.tmpdir(), "srgical-augment-"));
109
+ const promptFile = node_path_1.default.join(tempDir, "prompt.txt");
110
+ const rulesFile = node_path_1.default.join(tempDir, "rules.md");
111
+ const command = await resolveAugmentCommand();
112
+ const args = [
113
+ "--print",
114
+ "--quiet",
115
+ "--workspace-root",
116
+ options.cwd,
117
+ "--instruction-file",
118
+ promptFile,
119
+ "--rules",
120
+ rulesFile,
121
+ "--allow-indexing",
122
+ "--wait-for-indexing"
123
+ ];
124
+ if (options.askMode) {
125
+ args.push("--ask");
126
+ }
127
+ if (options.maxTurns) {
128
+ args.push("--max-turns", String(options.maxTurns));
129
+ }
130
+ await (0, promises_1.writeFile)(promptFile, options.prompt, "utf8");
131
+ await (0, promises_1.writeFile)(rulesFile, AUGMENT_DEFAULT_RULES, "utf8");
132
+ try {
133
+ const result = await spawnAndCaptureImpl(command, args, options.cwd);
134
+ return {
135
+ stdout: result.stdout,
136
+ stderr: result.stderr,
137
+ lastMessage: result.stdout.trim()
138
+ };
139
+ }
140
+ finally {
141
+ await (0, promises_1.rm)(tempDir, { recursive: true, force: true });
142
+ }
143
+ }
144
+ async function resolveAugmentCommand() {
145
+ if (forcedAugmentCommand) {
146
+ return forcedAugmentCommand;
147
+ }
148
+ if (!augmentCommandPromise) {
149
+ augmentCommandPromise = loadAugmentCommand();
150
+ }
151
+ return augmentCommandPromise;
152
+ }
153
+ async function loadAugmentCommand() {
154
+ if (process.platform !== "win32") {
155
+ return "auggie";
156
+ }
157
+ const result = await spawnAndCaptureImpl("where.exe", ["auggie"], process.cwd());
158
+ const matches = result.stdout
159
+ .split(/\r?\n/)
160
+ .map((line) => line.trim())
161
+ .filter(Boolean);
162
+ const shim = matches.find((line) => {
163
+ const lower = line.toLowerCase();
164
+ return lower.endsWith(".cmd") || lower.endsWith(".bat");
165
+ });
166
+ if (shim) {
167
+ return shim;
168
+ }
169
+ const executable = matches.find((line) => line.toLowerCase().endsWith(".exe"));
170
+ if (executable) {
171
+ return executable;
172
+ }
173
+ for (const candidate of matches) {
174
+ const siblingShim = await resolveSiblingShim(candidate);
175
+ if (siblingShim) {
176
+ return siblingShim;
177
+ }
178
+ }
179
+ if (matches.length > 0) {
180
+ return matches[0];
181
+ }
182
+ throw new Error("Unable to resolve an Augment executable path.");
183
+ }
184
+ function spawnAndCaptureBase(command, args, cwd, stdinText) {
185
+ return new Promise((resolve, reject) => {
186
+ const spec = buildSpawnSpec(command, args, cwd);
187
+ const child = (0, node_child_process_1.spawn)(spec.command, spec.args, spec.options);
188
+ let stdout = "";
189
+ let stderr = "";
190
+ child.stdout.on("data", (chunk) => {
191
+ stdout += chunk.toString();
192
+ });
193
+ child.stderr.on("data", (chunk) => {
194
+ stderr += chunk.toString();
195
+ });
196
+ child.on("error", reject);
197
+ child.on("close", (code) => {
198
+ if (code === 0) {
199
+ resolve({ stdout, stderr });
200
+ return;
201
+ }
202
+ reject(new Error(stderr.trim() || stdout.trim() || `${command} exited with code ${code}`));
203
+ });
204
+ if (stdinText) {
205
+ child.stdin.write(stdinText);
206
+ }
207
+ child.stdin.end();
208
+ });
209
+ }
210
+ function buildSpawnSpec(command, args, cwd) {
211
+ const lower = command.toLowerCase();
212
+ if (lower.endsWith(".cmd") || lower.endsWith(".bat")) {
213
+ const commandLine = [quoteForShell(command), ...args.map(quoteForShell)].join(" ");
214
+ return {
215
+ command: commandLine,
216
+ args: [],
217
+ options: {
218
+ cwd,
219
+ env: process.env,
220
+ shell: true
221
+ }
222
+ };
223
+ }
224
+ return {
225
+ command,
226
+ args,
227
+ options: {
228
+ cwd,
229
+ env: process.env
230
+ }
231
+ };
232
+ }
233
+ async function resolveSiblingShim(candidate) {
234
+ const extension = node_path_1.default.extname(candidate);
235
+ if (extension) {
236
+ return null;
237
+ }
238
+ for (const suffix of [".cmd", ".bat", ".exe"]) {
239
+ const sibling = `${candidate}${suffix}`;
240
+ try {
241
+ await (0, promises_1.access)(sibling);
242
+ return sibling;
243
+ }
244
+ catch {
245
+ continue;
246
+ }
247
+ }
248
+ return null;
249
+ }
250
+ function quoteForShell(value) {
251
+ if (/^[A-Za-z0-9_:\\/.=-]+$/.test(value)) {
252
+ return value;
253
+ }
254
+ const escaped = value.replace(/"/g, '""');
255
+ return `"${escaped}"`;
256
+ }
257
+ function normalizeAugmentDetectionError(error) {
258
+ const message = error instanceof Error ? error.message : "Failed to run auggie";
259
+ const normalized = message.toLowerCase();
260
+ if (normalized.includes("could not find files for the given pattern") ||
261
+ normalized.includes("unable to resolve an augment executable path") ||
262
+ normalized.includes("'auggie' is not recognized") ||
263
+ normalized.includes("enoent")) {
264
+ return AUGMENT_INSTALL_HINT;
265
+ }
266
+ return message;
267
+ }
268
+ function isAugmentUnavailableError(error) {
269
+ const message = error instanceof Error ? error.message.toLowerCase() : String(error).toLowerCase();
270
+ return (message.includes("unable to resolve an augment executable path") ||
271
+ message.includes("'auggie' is not recognized") ||
272
+ message.includes("enoent") ||
273
+ message.includes("failed to run auggie"));
274
+ }
275
+ function appendPlanningEpochSummary(preparation, summary) {
276
+ const epochSummary = (0, planning_epochs_1.formatPlanningEpochSummary)(preparation);
277
+ return [epochSummary, summary].filter(Boolean).join("\n");
278
+ }
package/dist/ui/studio.js CHANGED
@@ -335,7 +335,7 @@ async function launchStudio(options = {}) {
335
335
  await appendMessage({
336
336
  role: "system",
337
337
  content: [
338
- "Usage: `/agent codex` or `/agent claude`",
338
+ buildAgentUsageMessage(),
339
339
  "",
340
340
  renderAgentSelectionMessage(agentState.status, agentState.statuses)
341
341
  ].join("\n")
@@ -650,6 +650,19 @@ function renderAgentSelectionMessage(activeAgent, statuses) {
650
650
  ...statuses.map((status) => formatAgentStatusLine(status, status.id === activeAgent.id))
651
651
  ].join("\n");
652
652
  }
653
+ function buildAgentUsageMessage() {
654
+ const usages = (0, agent_1.getSupportedAgentAdapters)().map((adapter) => `\`/agent ${adapter.id}\``);
655
+ if (usages.length === 0) {
656
+ return "Usage: `/agent <id>`";
657
+ }
658
+ if (usages.length === 1) {
659
+ return `Usage: ${usages[0]}`;
660
+ }
661
+ if (usages.length === 2) {
662
+ return `Usage: ${usages[0]} or ${usages[1]}`;
663
+ }
664
+ return `Usage: ${usages.slice(0, -1).join(", ")}, or ${usages[usages.length - 1]}`;
665
+ }
653
666
  function formatAgentStatusLine(status, selected) {
654
667
  const prefix = selected ? "*" : "-";
655
668
  const detail = status.available ? `ready (${status.version ?? "version unknown"})` : formatUnavailableAgentDetail(status);
@@ -6,9 +6,9 @@ The current production release channels are GitHub Packages for npm, the public
6
6
  Versioning is tag-driven from git history, which means the repo carries a base major/minor line and CI computes the
7
7
  next patch version during release instead of committing a version bump back to `main`.
8
8
 
9
- The npm package does not bundle `codex` or `claude`. Users still need at least one supported local agent CLI installed
10
- separately and available on `PATH`, and `srgical doctor` remains the truthful way to confirm which agents are usable on
11
- the current machine.
9
+ The npm package does not bundle `codex`, `claude`, or `auggie`. Users still need at least one supported local agent CLI
10
+ installed separately and available on `PATH`, and `srgical doctor` remains the truthful way to confirm which agents are
11
+ usable on the current machine.
12
12
 
13
13
  ## Release Flow
14
14
 
@@ -76,8 +76,8 @@ After installing the package, run:
76
76
  srgical doctor
77
77
  ```
78
78
 
79
- That verifies the workspace state, shows the active agent, and reports whether `codex` and `claude` are locally
80
- available or missing.
79
+ That verifies the workspace state, shows the active agent, and reports whether `codex`, `claude`, and `auggie` are
80
+ locally available or missing.
81
81
 
82
82
  ## Artifact Strategy
83
83
 
@@ -96,7 +96,7 @@ npm install -g @launch11/srgical
96
96
 
97
97
  - Required local prerequisites after install:
98
98
  - authenticated access to GitHub Packages
99
- - `codex` and/or `claude` installed separately
99
+ - `codex`, `claude`, and/or `auggie` installed separately
100
100
  - available on `PATH` for the current shell session
101
101
 
102
102
  - Local install smoke test from a generated tarball:
@@ -27,7 +27,7 @@ time.
27
27
 
28
28
  ## V1 Scope
29
29
 
30
- - Two launch-scope agent adapters: `codex` and `claude`
30
+ - Three launch-scope agent adapters: `codex`, `claude`, and `augment`
31
31
  - One planning-pack format under `.srgical/`
32
32
  - One full-screen TUI for planning conversation
33
33
  - One execution command that runs the current next-step prompt through the active workspace agent
@@ -24,8 +24,9 @@ real bugs.
24
24
 
25
25
  ### Tier 3: Adapter and Agent behavior
26
26
 
27
- - primary-agent status detection must degrade cleanly when Codex is unavailable.
28
- - planner, pack-writing, and execution adapters must preserve today's Codex-first behavior.
27
+ - primary-agent status detection must degrade cleanly when any supported adapter is unavailable.
28
+ - planner, pack-writing, and execution adapters must preserve today's multi-agent behavior across Codex, Claude Code,
29
+ and Augment CLI.
29
30
  - Windows command resolution and shell-shim launching must stay covered because that path has already broken once.
30
31
 
31
32
  ### Tier 4: Release confidence
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@launch11/srgical",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "A polished local-first CLI for planning and executing long AI-driven delivery sequences.",
5
5
  "files": [
6
6
  "dist",