@sandagent/runner-cli 0.2.8 → 0.2.10

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
@@ -156,6 +156,32 @@ The CLI is designed to:
156
156
  3. Stream AI SDK UI messages directly to stdout
157
157
  4. Support both SSE stream and JSON output formats
158
158
 
159
+ ## 🐳 Docker Image Build
160
+
161
+ Build Docker images with agent templates baked in:
162
+
163
+ ```bash
164
+ # Build image
165
+ sandagent image build --name vikadata/sandagent-seo --tag 0.1.0 --template ./templates/seo-agent
166
+
167
+ # Build and push
168
+ sandagent image build --name vikadata/sandagent-seo --tag 0.1.0 --template ./templates/seo-agent --push
169
+
170
+ # Without template
171
+ sandagent image build --name vikadata/sandagent --tag 0.1.0
172
+ ```
173
+
174
+ ### Image Build Options
175
+
176
+ | Option | Description | Default |
177
+ |--------|-------------|---------|
178
+ | `--name <name>` | Full image name (e.g. `vikadata/sandagent-seo`) | `sandagent` |
179
+ | `--tag <tag>` | Image tag | `latest` |
180
+ | `--image <full>` | Full image name override (e.g. `myorg/myimage:v1`) | - |
181
+ | `--platform <plat>` | Build platform | `linux/amd64` |
182
+ | `--template <path>` | Path to agent template directory | - |
183
+ | `--push` | Push image to registry after build | `false` |
184
+
159
185
  ## Related Documentation
160
186
 
161
187
  - [Claude Agent SDK](https://platform.claude.com/docs/agent-sdk/typescript)
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=build-image.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-image.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/build-image.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,145 @@
1
+ import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync, } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
+ // Mock child_process so we never actually run docker
5
+ vi.mock("node:child_process", () => ({
6
+ execSync: vi.fn((cmd) => {
7
+ // docker info check — pretend docker is running
8
+ if (cmd === "docker info")
9
+ return Buffer.from("");
10
+ // Record the command for assertions
11
+ return Buffer.from("");
12
+ }),
13
+ }));
14
+ import { execSync } from "node:child_process";
15
+ import { buildImage } from "../build-image.js";
16
+ const mockedExecSync = vi.mocked(execSync);
17
+ const TEST_DIR = join(process.cwd(), ".test-build-image");
18
+ const BUILD_CONTEXT = join(TEST_DIR, ".docker-staging");
19
+ beforeEach(() => {
20
+ mkdirSync(TEST_DIR, { recursive: true });
21
+ mockedExecSync.mockClear();
22
+ });
23
+ afterEach(() => {
24
+ rmSync(TEST_DIR, { recursive: true, force: true });
25
+ rmSync(BUILD_CONTEXT, { recursive: true, force: true });
26
+ // Also clean up the default build context location
27
+ rmSync(join(process.cwd(), ".docker-staging"), {
28
+ recursive: true,
29
+ force: true,
30
+ });
31
+ });
32
+ describe("buildImage", () => {
33
+ it("builds a plain image without template", async () => {
34
+ await buildImage({
35
+ name: "myorg/sandagent",
36
+ tag: "0.1.0",
37
+ platform: "linux/amd64",
38
+ push: false,
39
+ });
40
+ // Should have called docker info + docker build
41
+ const calls = mockedExecSync.mock.calls.map((c) => c[0]);
42
+ expect(calls.some((c) => c === "docker info")).toBe(true);
43
+ expect(calls.some((c) => c.includes("docker build"))).toBe(true);
44
+ // docker build should reference the correct image name
45
+ const buildCmd = calls.find((c) => c.includes("docker build"));
46
+ expect(buildCmd).toContain("-t myorg/sandagent:0.1.0");
47
+ expect(buildCmd).toContain("--platform=linux/amd64");
48
+ // Should NOT have called docker push
49
+ expect(calls.some((c) => c.includes("docker push"))).toBe(false);
50
+ });
51
+ it("generates Dockerfile in build context", async () => {
52
+ await buildImage({
53
+ name: "myorg/sandagent",
54
+ tag: "1.0.0",
55
+ platform: "linux/amd64",
56
+ push: false,
57
+ });
58
+ const contextDir = join(process.cwd(), ".docker-staging");
59
+ const dockerfilePath = join(contextDir, "Dockerfile");
60
+ expect(existsSync(dockerfilePath)).toBe(true);
61
+ const content = readFileSync(dockerfilePath, "utf8");
62
+ expect(content).toContain("FROM node:20-slim");
63
+ expect(content).toContain("@sandagent/runner-cli");
64
+ expect(content).toContain('CMD ["sleep", "infinity"]');
65
+ });
66
+ it("uses --image override when provided", async () => {
67
+ await buildImage({
68
+ name: "sandagent",
69
+ tag: "latest",
70
+ image: "custom/image:v2",
71
+ platform: "linux/amd64",
72
+ push: false,
73
+ });
74
+ const calls = mockedExecSync.mock.calls.map((c) => c[0]);
75
+ const buildCmd = calls.find((c) => c.includes("docker build"));
76
+ expect(buildCmd).toContain("-t custom/image:v2");
77
+ });
78
+ it("builds with template and injects COPY instructions", async () => {
79
+ // Create a fake template directory
80
+ const templateDir = join(TEST_DIR, "my-agent");
81
+ mkdirSync(templateDir, { recursive: true });
82
+ writeFileSync(join(templateDir, "CLAUDE.md"), "# My Agent");
83
+ const claudeDir = join(templateDir, ".claude");
84
+ mkdirSync(claudeDir, { recursive: true });
85
+ writeFileSync(join(claudeDir, "settings.json"), '{"max_tokens": 4096}');
86
+ await buildImage({
87
+ name: "myorg/sandagent",
88
+ tag: "0.1.0",
89
+ platform: "linux/amd64",
90
+ template: templateDir,
91
+ push: false,
92
+ });
93
+ // Image name should include template name
94
+ const calls = mockedExecSync.mock.calls.map((c) => c[0]);
95
+ const buildCmd = calls.find((c) => c.includes("docker build"));
96
+ expect(buildCmd).toContain("-t myorg/sandagent:0.1.0");
97
+ // Generated Dockerfile should have template COPY lines
98
+ const contextDir = join(process.cwd(), ".docker-staging");
99
+ const dockerfile = readFileSync(join(contextDir, "Dockerfile"), "utf8");
100
+ expect(dockerfile).toContain("COPY templates/my-agent/CLAUDE.md");
101
+ expect(dockerfile).toContain("COPY templates/my-agent/.claude");
102
+ expect(dockerfile).toContain("mkdir -p /opt/sandagent/templates");
103
+ // Template files should be copied into build context
104
+ expect(existsSync(join(contextDir, "templates", "my-agent", "CLAUDE.md"))).toBe(true);
105
+ expect(existsSync(join(contextDir, "templates", "my-agent", ".claude", "settings.json"))).toBe(true);
106
+ });
107
+ it("pushes when --push is set", async () => {
108
+ await buildImage({
109
+ name: "myorg/sandagent",
110
+ tag: "0.1.0",
111
+ platform: "linux/amd64",
112
+ push: true,
113
+ });
114
+ const calls = mockedExecSync.mock.calls.map((c) => c[0]);
115
+ expect(calls.some((c) => c.includes("docker push"))).toBe(true);
116
+ expect(calls.some((c) => c.includes("docker push myorg/sandagent:0.1.0"))).toBe(true);
117
+ });
118
+ it("fails push when name has no namespace", async () => {
119
+ const mockExit = vi.spyOn(process, "exit").mockImplementation(() => {
120
+ throw new Error("process.exit");
121
+ });
122
+ const mockError = vi.spyOn(console, "error").mockImplementation(() => { });
123
+ await expect(buildImage({
124
+ name: "sandagent",
125
+ tag: "0.1.0",
126
+ platform: "linux/amd64",
127
+ push: true,
128
+ })).rejects.toThrow("process.exit");
129
+ expect(mockError).toHaveBeenCalledWith(expect.stringContaining("--push requires --name to include namespace"));
130
+ mockExit.mockRestore();
131
+ mockError.mockRestore();
132
+ });
133
+ it("does not push when --push is false", async () => {
134
+ await buildImage({
135
+ name: "myorg/sandagent",
136
+ tag: "0.1.0",
137
+ platform: "linux/amd64",
138
+ push: false,
139
+ });
140
+ const calls = mockedExecSync.mock.calls.map((c) => c[0]);
141
+ expect(calls.some((c) => c.includes("docker push"))).toBe(false);
142
+ expect(calls.some((c) => c.includes("docker tag"))).toBe(false);
143
+ });
144
+ });
145
+ //# sourceMappingURL=build-image.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-image.test.js","sourceRoot":"","sources":["../../src/__tests__/build-image.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export interface BuildImageOptions {
2
+ /** Image name, e.g. "vikadata/sandagent-seo" */
3
+ name: string;
4
+ /** Image tag, e.g. "0.1.0" */
5
+ tag: string;
6
+ /** Full image override, e.g. "myorg/myimage:v1" */
7
+ image?: string;
8
+ /** Docker platform (default: linux/amd64) */
9
+ platform: string;
10
+ /** Path to agent template directory to bake into the image */
11
+ template?: string;
12
+ /** Push image to registry after build */
13
+ push: boolean;
14
+ }
15
+ export declare function buildImage(opts: BuildImageOptions): Promise<void>;
16
+ //# sourceMappingURL=build-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-image.d.ts","sourceRoot":"","sources":["../src/build-image.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,iBAAiB;IAChC,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,IAAI,EAAE,OAAO,CAAC;CACf;AA2ED,wBAAsB,UAAU,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiEvE"}
@@ -0,0 +1,114 @@
1
+ import { execSync } from "node:child_process";
2
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync, } from "node:fs";
3
+ import { basename, dirname, join, resolve } from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ // ---------------------------------------------------------------------------
6
+ // Helpers
7
+ // ---------------------------------------------------------------------------
8
+ function getPackageRoot() {
9
+ const thisDir = dirname(fileURLToPath(import.meta.url));
10
+ return resolve(thisDir, "..");
11
+ }
12
+ function getShippedDockerfile() {
13
+ // Look for Dockerfile in several locations:
14
+ // 1. Package root (apps/runner-cli/Dockerfile) — shipped with npm package
15
+ // 2. docker/sandagent-claude/Dockerfile — monorepo development
16
+ const packageRoot = getPackageRoot();
17
+ const candidates = [
18
+ join(packageRoot, "Dockerfile"),
19
+ resolve(packageRoot, "..", "..", "docker", "sandagent-claude", "Dockerfile"),
20
+ ];
21
+ for (const p of candidates) {
22
+ if (existsSync(p))
23
+ return p;
24
+ }
25
+ console.error(`❌ Dockerfile not found. Searched:\n${candidates.map((c) => ` ${c}`).join("\n")}`);
26
+ process.exit(1);
27
+ }
28
+ function run(cmd, cwd) {
29
+ execSync(cmd, { stdio: "inherit", cwd });
30
+ }
31
+ function ensureDocker() {
32
+ try {
33
+ execSync("docker info", { stdio: "ignore" });
34
+ }
35
+ catch {
36
+ console.error("❌ Docker is not running. Please start Docker first.");
37
+ process.exit(1);
38
+ }
39
+ }
40
+ function resolveTemplatePath(template) {
41
+ const abs = resolve(process.cwd(), template);
42
+ if (!existsSync(abs)) {
43
+ console.error(`❌ Template directory not found: ${abs}`);
44
+ process.exit(1);
45
+ }
46
+ return abs;
47
+ }
48
+ function copyDirSync(src, dest) {
49
+ mkdirSync(dest, { recursive: true });
50
+ for (const entry of readdirSync(src)) {
51
+ const srcPath = join(src, entry);
52
+ const destPath = join(dest, entry);
53
+ if (statSync(srcPath).isDirectory()) {
54
+ copyDirSync(srcPath, destPath);
55
+ }
56
+ else {
57
+ copyFileSync(srcPath, destPath);
58
+ }
59
+ }
60
+ }
61
+ // ---------------------------------------------------------------------------
62
+ // Build (and optionally push)
63
+ // ---------------------------------------------------------------------------
64
+ export async function buildImage(opts) {
65
+ const templatePath = opts.template
66
+ ? resolveTemplatePath(opts.template)
67
+ : null;
68
+ const templateName = templatePath ? basename(templatePath) : null;
69
+ const localImage = opts.image ?? `${opts.name}:${opts.tag}`;
70
+ console.log("📦 SandAgent Docker Image Builder");
71
+ console.log("========================");
72
+ console.log(` Image: ${localImage}`);
73
+ console.log(` Platform: ${opts.platform}`);
74
+ console.log(` Template: ${templateName ?? "(none)"}`);
75
+ console.log(` Push: ${opts.push}`);
76
+ console.log("");
77
+ ensureDocker();
78
+ const buildContext = join(process.cwd(), ".docker-staging");
79
+ mkdirSync(buildContext, { recursive: true });
80
+ let dockerfile = readFileSync(getShippedDockerfile(), "utf8");
81
+ if (templatePath && templateName) {
82
+ const destDir = join(buildContext, "templates", templateName);
83
+ mkdirSync(destDir, { recursive: true });
84
+ const claudeMd = join(templatePath, "CLAUDE.md");
85
+ if (existsSync(claudeMd))
86
+ copyFileSync(claudeMd, join(destDir, "CLAUDE.md"));
87
+ const claudeDir = join(templatePath, ".claude");
88
+ if (existsSync(claudeDir))
89
+ copyDirSync(claudeDir, join(destDir, ".claude"));
90
+ let copyLines = "\n# Template files\nRUN mkdir -p /opt/sandagent/templates";
91
+ if (existsSync(join(destDir, "CLAUDE.md"))) {
92
+ copyLines += `\nCOPY templates/${templateName}/CLAUDE.md /opt/sandagent/templates/CLAUDE.md`;
93
+ }
94
+ if (existsSync(join(destDir, ".claude"))) {
95
+ copyLines += `\nCOPY templates/${templateName}/.claude /opt/sandagent/templates/.claude`;
96
+ }
97
+ dockerfile = dockerfile.replace(/^CMD /m, `${copyLines}\n\nCMD `);
98
+ console.log("🧩 Injected template files into Dockerfile");
99
+ }
100
+ writeFileSync(join(buildContext, "Dockerfile"), dockerfile);
101
+ console.log("🐳 Building Docker image...");
102
+ run(`docker build --platform=${opts.platform} -t ${localImage} -f ${join(buildContext, "Dockerfile")} ${buildContext}`);
103
+ console.log(`\n✅ Image built: ${localImage}`);
104
+ if (!opts.push)
105
+ return;
106
+ if (!localImage.includes("/")) {
107
+ console.error("❌ --push requires --name to include namespace (e.g. vikadata/sandagent-seo)");
108
+ process.exit(1);
109
+ }
110
+ console.log("🚀 Pushing image...");
111
+ run(`docker push ${localImage}`);
112
+ console.log(`\n✅ Image pushed: ${localImage}`);
113
+ }
114
+ //# sourceMappingURL=build-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-image.js","sourceRoot":"","sources":["../src/build-image.ts"],"names":[],"mappings":"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"}
package/dist/bundle.mjs CHANGED
@@ -3,9 +3,136 @@
3
3
  // src/cli.ts
4
4
  import { parseArgs } from "node:util";
5
5
 
6
+ // src/build-image.ts
7
+ import { execSync } from "node:child_process";
8
+ import {
9
+ copyFileSync,
10
+ existsSync,
11
+ mkdirSync,
12
+ readFileSync,
13
+ readdirSync,
14
+ statSync,
15
+ writeFileSync
16
+ } from "node:fs";
17
+ import { basename, dirname, join, resolve } from "node:path";
18
+ import { fileURLToPath } from "node:url";
19
+ function getPackageRoot() {
20
+ const thisDir = dirname(fileURLToPath(import.meta.url));
21
+ return resolve(thisDir, "..");
22
+ }
23
+ function getShippedDockerfile() {
24
+ const packageRoot = getPackageRoot();
25
+ const candidates = [
26
+ join(packageRoot, "Dockerfile"),
27
+ resolve(
28
+ packageRoot,
29
+ "..",
30
+ "..",
31
+ "docker",
32
+ "sandagent-claude",
33
+ "Dockerfile"
34
+ )
35
+ ];
36
+ for (const p of candidates) {
37
+ if (existsSync(p)) return p;
38
+ }
39
+ console.error(
40
+ `\u274C Dockerfile not found. Searched:
41
+ ${candidates.map((c) => ` ${c}`).join("\n")}`
42
+ );
43
+ process.exit(1);
44
+ }
45
+ function run(cmd, cwd) {
46
+ execSync(cmd, { stdio: "inherit", cwd });
47
+ }
48
+ function ensureDocker() {
49
+ try {
50
+ execSync("docker info", { stdio: "ignore" });
51
+ } catch {
52
+ console.error("\u274C Docker is not running. Please start Docker first.");
53
+ process.exit(1);
54
+ }
55
+ }
56
+ function resolveTemplatePath(template) {
57
+ const abs = resolve(process.cwd(), template);
58
+ if (!existsSync(abs)) {
59
+ console.error(`\u274C Template directory not found: ${abs}`);
60
+ process.exit(1);
61
+ }
62
+ return abs;
63
+ }
64
+ function copyDirSync(src, dest) {
65
+ mkdirSync(dest, { recursive: true });
66
+ for (const entry of readdirSync(src)) {
67
+ const srcPath = join(src, entry);
68
+ const destPath = join(dest, entry);
69
+ if (statSync(srcPath).isDirectory()) {
70
+ copyDirSync(srcPath, destPath);
71
+ } else {
72
+ copyFileSync(srcPath, destPath);
73
+ }
74
+ }
75
+ }
76
+ async function buildImage(opts) {
77
+ const templatePath = opts.template ? resolveTemplatePath(opts.template) : null;
78
+ const templateName = templatePath ? basename(templatePath) : null;
79
+ const localImage = opts.image ?? `${opts.name}:${opts.tag}`;
80
+ console.log("\u{1F4E6} SandAgent Docker Image Builder");
81
+ console.log("========================");
82
+ console.log(` Image: ${localImage}`);
83
+ console.log(` Platform: ${opts.platform}`);
84
+ console.log(` Template: ${templateName ?? "(none)"}`);
85
+ console.log(` Push: ${opts.push}`);
86
+ console.log("");
87
+ ensureDocker();
88
+ const buildContext = join(process.cwd(), ".docker-staging");
89
+ mkdirSync(buildContext, { recursive: true });
90
+ let dockerfile = readFileSync(getShippedDockerfile(), "utf8");
91
+ if (templatePath && templateName) {
92
+ const destDir = join(buildContext, "templates", templateName);
93
+ mkdirSync(destDir, { recursive: true });
94
+ const claudeMd = join(templatePath, "CLAUDE.md");
95
+ if (existsSync(claudeMd))
96
+ copyFileSync(claudeMd, join(destDir, "CLAUDE.md"));
97
+ const claudeDir = join(templatePath, ".claude");
98
+ if (existsSync(claudeDir)) copyDirSync(claudeDir, join(destDir, ".claude"));
99
+ let copyLines = "\n# Template files\nRUN mkdir -p /opt/sandagent/templates";
100
+ if (existsSync(join(destDir, "CLAUDE.md"))) {
101
+ copyLines += `
102
+ COPY templates/${templateName}/CLAUDE.md /opt/sandagent/templates/CLAUDE.md`;
103
+ }
104
+ if (existsSync(join(destDir, ".claude"))) {
105
+ copyLines += `
106
+ COPY templates/${templateName}/.claude /opt/sandagent/templates/.claude`;
107
+ }
108
+ dockerfile = dockerfile.replace(/^CMD /m, `${copyLines}
109
+
110
+ CMD `);
111
+ console.log("\u{1F9E9} Injected template files into Dockerfile");
112
+ }
113
+ writeFileSync(join(buildContext, "Dockerfile"), dockerfile);
114
+ console.log("\u{1F433} Building Docker image...");
115
+ run(
116
+ `docker build --platform=${opts.platform} -t ${localImage} -f ${join(buildContext, "Dockerfile")} ${buildContext}`
117
+ );
118
+ console.log(`
119
+ \u2705 Image built: ${localImage}`);
120
+ if (!opts.push) return;
121
+ if (!localImage.includes("/")) {
122
+ console.error(
123
+ "\u274C --push requires --name to include namespace (e.g. vikadata/sandagent-seo)"
124
+ );
125
+ process.exit(1);
126
+ }
127
+ console.log("\u{1F680} Pushing image...");
128
+ run(`docker push ${localImage}`);
129
+ console.log(`
130
+ \u2705 Image pushed: ${localImage}`);
131
+ }
132
+
6
133
  // ../../packages/runner-claude/dist/ai-sdk-stream.js
7
134
  import { writeFile } from "node:fs/promises";
8
- import { join } from "node:path";
135
+ import { join as join2 } from "node:path";
9
136
  var UNKNOWN_TOOL_NAME = "unknown-tool";
10
137
  function formatDataStream(data) {
11
138
  return `data: ${JSON.stringify(data)}
@@ -233,7 +360,7 @@ var AISDKStreamConverter = class {
233
360
  } finally {
234
361
  if (debugMessages.length > 0 && process.env.DEBUG === "true") {
235
362
  const debugDir = options?.cwd ?? process.cwd();
236
- const debugFile = join(debugDir, `claude-message-stream-debug.json`);
363
+ const debugFile = join2(debugDir, `claude-message-stream-debug.json`);
237
364
  writeFile(debugFile, JSON.stringify(debugMessages, null, 2), "utf-8").catch((writeError) => {
238
365
  console.error(`[AISDKStream] Failed to write debug file:`, writeError);
239
366
  });
@@ -260,23 +387,20 @@ function createCanUseToolCallback(claudeOptions) {
260
387
  }
261
388
  const cwd = claudeOptions.cwd || process.cwd();
262
389
  try {
263
- const { execSync } = await import("node:child_process");
390
+ const fs = await import("node:fs");
264
391
  const path = await import("node:path");
265
392
  const approvalDir = path.join(cwd, ".sandagent", "approvals");
266
393
  const approvalFile = path.join(approvalDir, `${toolUseID}.json`);
267
- execSync(`mkdir -p "${approvalDir}"`);
268
394
  const timeout = Date.now() + 6e4;
269
395
  let lastApproval = null;
270
396
  while (Date.now() < timeout) {
271
397
  try {
272
- const data = execSync(`cat "${approvalFile}" 2>/dev/null`, {
273
- encoding: "utf-8"
274
- });
398
+ const data = fs.readFileSync(approvalFile, "utf-8");
275
399
  const approval = JSON.parse(data);
276
400
  lastApproval = approval;
277
401
  if (approval.status === "completed") {
278
402
  try {
279
- execSync(`rm "${approvalFile}" 2>/dev/null`);
403
+ fs.unlinkSync(approvalFile);
280
404
  } catch {
281
405
  }
282
406
  return {
@@ -289,10 +413,10 @@ function createCanUseToolCallback(claudeOptions) {
289
413
  }
290
414
  } catch {
291
415
  }
292
- await new Promise((resolve) => setTimeout(resolve, 500));
416
+ await new Promise((resolve2) => setTimeout(resolve2, 500));
293
417
  }
294
418
  try {
295
- execSync(`rm "${approvalFile}" 2>/dev/null`);
419
+ fs.unlinkSync(approvalFile);
296
420
  } catch {
297
421
  }
298
422
  if (lastApproval && Object.keys(lastApproval.answers).length > 0) {
@@ -509,7 +633,7 @@ Documentation: https://platform.claude.com/docs/en/agent-sdk/typescript-v2-previ
509
633
  id: textId,
510
634
  delta: word + " "
511
635
  });
512
- await new Promise((resolve) => setTimeout(resolve, 20));
636
+ await new Promise((resolve2) => setTimeout(resolve2, 20));
513
637
  }
514
638
  yield formatDataStream({ type: "text-end", id: textId });
515
639
  yield formatDataStream({
@@ -597,14 +721,41 @@ async function runAgent(options) {
597
721
  }
598
722
 
599
723
  // src/cli.ts
600
- function parseCliArgs() {
724
+ function getSubcommand() {
725
+ for (let i = 2; i < process.argv.length; i++) {
726
+ const a = process.argv[i];
727
+ if (a === "--") break;
728
+ if (!a.startsWith("-")) return a;
729
+ }
730
+ return void 0;
731
+ }
732
+ function getSubSubcommand() {
733
+ let found = 0;
734
+ for (let i = 2; i < process.argv.length; i++) {
735
+ const a = process.argv[i];
736
+ if (a === "--") break;
737
+ if (!a.startsWith("-")) {
738
+ found++;
739
+ if (found === 2) return a;
740
+ }
741
+ }
742
+ return void 0;
743
+ }
744
+ function argsAfterPositionals(n) {
745
+ let found = 0;
746
+ for (let i = 2; i < process.argv.length; i++) {
747
+ if (!process.argv[i].startsWith("-") && process.argv[i] !== "--") {
748
+ found++;
749
+ if (found === n) return process.argv.slice(i + 1);
750
+ }
751
+ }
752
+ return [];
753
+ }
754
+ function parseRunArgs() {
601
755
  const { values, positionals } = parseArgs({
756
+ args: argsAfterPositionals(1),
602
757
  options: {
603
- runner: {
604
- type: "string",
605
- short: "r",
606
- default: "claude"
607
- },
758
+ runner: { type: "string", short: "r", default: "claude" },
608
759
  model: {
609
760
  type: "string",
610
761
  short: "m",
@@ -615,49 +766,26 @@ function parseCliArgs() {
615
766
  short: "c",
616
767
  default: process.env.SANDAGENT_WORKSPACE ?? process.cwd()
617
768
  },
618
- "system-prompt": {
619
- type: "string",
620
- short: "s"
621
- },
622
- "max-turns": {
623
- type: "string",
624
- short: "t"
625
- },
626
- "allowed-tools": {
627
- type: "string",
628
- short: "a"
629
- },
630
- resume: {
631
- type: "string",
632
- short: "r"
633
- },
634
- "output-format": {
635
- type: "string",
636
- short: "o"
637
- },
638
- help: {
639
- type: "boolean",
640
- short: "h"
641
- }
769
+ "system-prompt": { type: "string", short: "s" },
770
+ "max-turns": { type: "string", short: "t" },
771
+ "allowed-tools": { type: "string", short: "a" },
772
+ resume: { type: "string" },
773
+ "output-format": { type: "string", short: "o" },
774
+ help: { type: "boolean", short: "h" }
642
775
  },
643
776
  allowPositionals: true,
644
777
  strict: true
645
778
  });
646
779
  if (values.help) {
647
- printHelp();
780
+ printRunHelp();
648
781
  process.exit(0);
649
782
  }
650
- if (positionals[0] !== "run") {
651
- console.error('Error: Expected "run" command');
652
- console.error('Usage: sandagent run [options] -- "<user input>"');
653
- process.exit(1);
654
- }
655
783
  const dashIndex = process.argv.indexOf("--");
656
784
  let userInput = "";
657
785
  if (dashIndex !== -1 && dashIndex < process.argv.length - 1) {
658
786
  userInput = process.argv.slice(dashIndex + 1).join(" ");
659
- } else if (positionals.length > 1) {
660
- userInput = positionals.slice(1).join(" ");
787
+ } else if (positionals.length > 0) {
788
+ userInput = positionals.join(" ");
661
789
  }
662
790
  if (!userInput) {
663
791
  console.error("Error: User input is required");
@@ -690,57 +818,156 @@ function parseCliArgs() {
690
818
  userInput
691
819
  };
692
820
  }
693
- function printHelp() {
821
+ function parseImageBuildArgs() {
822
+ const { values } = parseArgs({
823
+ args: argsAfterPositionals(2),
824
+ options: {
825
+ name: { type: "string", default: "sandagent" },
826
+ tag: { type: "string", default: "latest" },
827
+ image: { type: "string" },
828
+ platform: { type: "string", default: "linux/amd64" },
829
+ template: { type: "string" },
830
+ push: { type: "boolean", default: false },
831
+ help: { type: "boolean", short: "h" }
832
+ },
833
+ allowPositionals: false,
834
+ strict: true
835
+ });
836
+ if (values.help) {
837
+ printImageBuildHelp();
838
+ process.exit(0);
839
+ }
840
+ return {
841
+ name: values.name,
842
+ tag: values.tag,
843
+ image: values.image,
844
+ platform: values.platform,
845
+ template: values.template,
846
+ push: values.push ?? false
847
+ };
848
+ }
849
+ function printRunHelp() {
694
850
  console.log(`
695
- \u{1F916} SandAgent Runner CLI
851
+ \u{1F916} SandAgent Runner CLI \u2014 run
696
852
 
697
- Like gemini-cli or claude-code - runs locally in your terminal.
698
- Streams AI SDK UI messages directly to stdout.
853
+ Runs an agent locally in your terminal, streaming AI SDK UI messages to stdout.
699
854
 
700
855
  Usage:
701
856
  sandagent run [options] -- "<user input>"
702
857
 
703
858
  Options:
704
- -r, --runner <runner> Runner to use: claude, codex, copilot (default: claude)
705
- -m, --model <model> Model to use (default: claude-sonnet-4-20250514)
706
- -c, --cwd <path> Working directory (default: current directory)
859
+ -r, --runner <runner> Runner: claude, codex, copilot (default: claude)
860
+ -m, --model <model> Model (default: claude-sonnet-4-20250514)
861
+ -c, --cwd <path> Working directory (default: cwd)
707
862
  -s, --system-prompt <prompt> Custom system prompt
708
- -t, --max-turns <n> Maximum conversation turns
709
- -a, --allowed-tools <tools> Comma-separated list of allowed tools
710
- -r, --resume <session-id> Resume a previous session
711
- -o, --output-format <format> Output format (default: stream)
712
- Available: text, json(single result), stream-json(realtime streaming), stream(ai sdk ui sse format)
713
- -h, --help Show this help message
863
+ -t, --max-turns <n> Max conversation turns
864
+ -a, --allowed-tools <tools> Comma-separated allowed tools
865
+ --resume <session-id> Resume a previous session
866
+ -o, --output-format <fmt> text | json | stream-json | stream (default: stream)
867
+ -h, --help Show this help
868
+
869
+ Environment:
870
+ ANTHROPIC_API_KEY Anthropic API key (required)
871
+ SANDAGENT_WORKSPACE Default workspace path
872
+ `);
873
+ }
874
+ function printImageBuildHelp() {
875
+ console.log(`
876
+ \u{1F433} SandAgent Runner CLI \u2014 image build
877
+
878
+ Build (and optionally push) a SandAgent Docker image.
879
+ The image includes Claude Agent SDK + runner-cli pre-installed.
714
880
 
715
- Environment Variables:
716
- ANTHROPIC_API_KEY Anthropic API key (required)
717
- SANDAGENT_WORKSPACE Default workspace path
718
- SANDAGENT_LOG_LEVEL Logging level (debug, info, warn, error)
881
+ Usage:
882
+ sandagent image build [options]
883
+
884
+ Options:
885
+ --name <name> Image name, e.g. vikadata/sandagent-seo (default: sandagent)
886
+ --tag <tag> Image tag (default: latest)
887
+ --image <full> Full image name override (e.g. myorg/myimage:v1)
888
+ --platform <plat> Build platform (default: linux/amd64)
889
+ --template <path> Path to agent template directory to bake into the image
890
+ --push Push image to registry after build
891
+ -h, --help Show this help
719
892
 
720
893
  Examples:
721
- # Run with default settings
722
- sandagent run -- "Create a hello world script"
894
+ sandagent image build --name vikadata/sandagent-seo --tag 0.1.0
895
+ sandagent image build --name vikadata/sandagent-seo --tag 0.1.0 --template ./templates/seo-agent
896
+ sandagent image build --name vikadata/sandagent-seo --tag 0.1.0 --template ./templates/seo-agent --push
897
+ `);
898
+ }
899
+ function printImageHelp() {
900
+ console.log(`
901
+ \u{1F433} SandAgent Runner CLI \u2014 image
723
902
 
724
- # Run with custom system prompt
725
- sandagent run --system-prompt "You are a coding assistant" -- "Build a REST API with Express"
903
+ Manage SandAgent Docker images.
726
904
 
727
- # Specify working directory
728
- sandagent run --cwd ./my-project -- "Fix the bug in main.ts"
905
+ Usage:
906
+ sandagent image <subcommand> [options]
907
+
908
+ Subcommands:
909
+ build Build (and optionally push) a Docker image
910
+
911
+ Run "sandagent image build --help" for build options.
912
+ `);
913
+ }
914
+ function printGlobalHelp() {
915
+ console.log(`
916
+ \u{1F916} SandAgent Runner CLI
917
+
918
+ Usage:
919
+ sandagent <command> [options]
920
+
921
+ Commands:
922
+ run Run an agent locally (streams AI SDK UI messages to stdout)
923
+ image build Build a SandAgent Docker image (with optional --push)
924
+
925
+ Run "sandagent <command> --help" for command-specific options.
729
926
  `);
730
927
  }
731
928
  async function main() {
732
- const args = parseCliArgs();
733
- process.chdir(args.cwd);
734
- await runAgent({
735
- runner: args.runner,
736
- model: args.model,
737
- userInput: args.userInput,
738
- systemPrompt: args.systemPrompt,
739
- maxTurns: args.maxTurns,
740
- allowedTools: args.allowedTools,
741
- resume: args.resume,
742
- outputFormat: args.outputFormat
743
- });
929
+ const sub = getSubcommand();
930
+ if (!sub || sub === "--help" || sub === "-h") {
931
+ printGlobalHelp();
932
+ process.exit(0);
933
+ }
934
+ switch (sub) {
935
+ case "run": {
936
+ const args = parseRunArgs();
937
+ process.chdir(args.cwd);
938
+ await runAgent({
939
+ runner: args.runner,
940
+ model: args.model,
941
+ userInput: args.userInput,
942
+ systemPrompt: args.systemPrompt,
943
+ maxTurns: args.maxTurns,
944
+ allowedTools: args.allowedTools,
945
+ resume: args.resume,
946
+ outputFormat: args.outputFormat
947
+ });
948
+ break;
949
+ }
950
+ case "image": {
951
+ const subSub = getSubSubcommand();
952
+ if (!subSub || subSub === "--help" || subSub === "-h") {
953
+ printImageHelp();
954
+ process.exit(0);
955
+ }
956
+ if (subSub === "build") {
957
+ const args = parseImageBuildArgs();
958
+ await buildImage(args);
959
+ } else {
960
+ console.error(`Unknown image subcommand: ${subSub}`);
961
+ printImageHelp();
962
+ process.exit(1);
963
+ }
964
+ break;
965
+ }
966
+ default:
967
+ console.error(`Unknown command: ${sub}`);
968
+ printGlobalHelp();
969
+ process.exit(1);
970
+ }
744
971
  }
745
972
  main().catch((error) => {
746
973
  console.error("Fatal error:", error.message);
package/dist/cli.d.ts CHANGED
@@ -2,14 +2,9 @@
2
2
  /**
3
3
  * SandAgent Runner CLI
4
4
  *
5
- * Like gemini-cli or claude-code - runs locally in your terminal.
6
- * Streams AI SDK UI messages directly to stdout.
7
- *
8
- * Usage:
9
- * sandagent run [options] -- "<user input>"
10
- *
11
- * The CLI is designed to be executed in a specific working directory
12
- * and outputs AI SDK UI messages directly.
5
+ * Subcommands:
6
+ * sandagent run [options] -- "<user input>" Run an agent locally
7
+ * sandagent image build [options] Build (and optionally push) a Docker image
13
8
  */
14
9
  export {};
15
10
  //# sourceMappingURL=cli.d.ts.map
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;GAWG"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG"}
package/dist/cli.js CHANGED
@@ -2,25 +2,59 @@
2
2
  /**
3
3
  * SandAgent Runner CLI
4
4
  *
5
- * Like gemini-cli or claude-code - runs locally in your terminal.
6
- * Streams AI SDK UI messages directly to stdout.
7
- *
8
- * Usage:
9
- * sandagent run [options] -- "<user input>"
10
- *
11
- * The CLI is designed to be executed in a specific working directory
12
- * and outputs AI SDK UI messages directly.
5
+ * Subcommands:
6
+ * sandagent run [options] -- "<user input>" Run an agent locally
7
+ * sandagent image build [options] Build (and optionally push) a Docker image
13
8
  */
14
9
  import { parseArgs } from "node:util";
10
+ import { buildImage } from "./build-image.js";
15
11
  import { runAgent } from "./runner.js";
16
- function parseCliArgs() {
12
+ // ---------------------------------------------------------------------------
13
+ // Shared helpers
14
+ // ---------------------------------------------------------------------------
15
+ /** Get the first positional arg (top-level subcommand). */
16
+ function getSubcommand() {
17
+ for (let i = 2; i < process.argv.length; i++) {
18
+ const a = process.argv[i];
19
+ if (a === "--")
20
+ break;
21
+ if (!a.startsWith("-"))
22
+ return a;
23
+ }
24
+ return undefined;
25
+ }
26
+ /** Get the second positional arg (sub-subcommand, e.g. "build" in "image build"). */
27
+ function getSubSubcommand() {
28
+ let found = 0;
29
+ for (let i = 2; i < process.argv.length; i++) {
30
+ const a = process.argv[i];
31
+ if (a === "--")
32
+ break;
33
+ if (!a.startsWith("-")) {
34
+ found++;
35
+ if (found === 2)
36
+ return a;
37
+ }
38
+ }
39
+ return undefined;
40
+ }
41
+ /** Slice process.argv to args after N positionals. */
42
+ function argsAfterPositionals(n) {
43
+ let found = 0;
44
+ for (let i = 2; i < process.argv.length; i++) {
45
+ if (!process.argv[i].startsWith("-") && process.argv[i] !== "--") {
46
+ found++;
47
+ if (found === n)
48
+ return process.argv.slice(i + 1);
49
+ }
50
+ }
51
+ return [];
52
+ }
53
+ function parseRunArgs() {
17
54
  const { values, positionals } = parseArgs({
55
+ args: argsAfterPositionals(1),
18
56
  options: {
19
- runner: {
20
- type: "string",
21
- short: "r",
22
- default: "claude",
23
- },
57
+ runner: { type: "string", short: "r", default: "claude" },
24
58
  model: {
25
59
  type: "string",
26
60
  short: "m",
@@ -31,65 +65,38 @@ function parseCliArgs() {
31
65
  short: "c",
32
66
  default: process.env.SANDAGENT_WORKSPACE ?? process.cwd(),
33
67
  },
34
- "system-prompt": {
35
- type: "string",
36
- short: "s",
37
- },
38
- "max-turns": {
39
- type: "string",
40
- short: "t",
41
- },
42
- "allowed-tools": {
43
- type: "string",
44
- short: "a",
45
- },
46
- resume: {
47
- type: "string",
48
- short: "r",
49
- },
50
- "output-format": {
51
- type: "string",
52
- short: "o",
53
- },
54
- help: {
55
- type: "boolean",
56
- short: "h",
57
- },
68
+ "system-prompt": { type: "string", short: "s" },
69
+ "max-turns": { type: "string", short: "t" },
70
+ "allowed-tools": { type: "string", short: "a" },
71
+ resume: { type: "string" },
72
+ "output-format": { type: "string", short: "o" },
73
+ help: { type: "boolean", short: "h" },
58
74
  },
59
75
  allowPositionals: true,
60
76
  strict: true,
61
77
  });
62
78
  if (values.help) {
63
- printHelp();
79
+ printRunHelp();
64
80
  process.exit(0);
65
81
  }
66
- // Check for "run" command
67
- if (positionals[0] !== "run") {
68
- console.error('Error: Expected "run" command');
69
- console.error('Usage: sandagent run [options] -- "<user input>"');
70
- process.exit(1);
71
- }
72
- // Get user input from positionals after "--"
73
82
  const dashIndex = process.argv.indexOf("--");
74
83
  let userInput = "";
75
84
  if (dashIndex !== -1 && dashIndex < process.argv.length - 1) {
76
85
  userInput = process.argv.slice(dashIndex + 1).join(" ");
77
86
  }
78
- else if (positionals.length > 1) {
79
- userInput = positionals.slice(1).join(" ");
87
+ else if (positionals.length > 0) {
88
+ userInput = positionals.join(" ");
80
89
  }
81
90
  if (!userInput) {
82
91
  console.error("Error: User input is required");
83
92
  console.error('Usage: sandagent run [options] -- "<user input>"');
84
93
  process.exit(1);
85
94
  }
86
- // Validate runner
87
95
  const runner = values.runner;
88
96
  if (!["claude", "codex", "copilot"].includes(runner)) {
89
97
  console.error('Error: --runner must be one of: "claude", "codex", "copilot"');
90
98
  process.exit(1);
91
99
  }
92
- // Validate output-format
93
100
  const outputFormat = values["output-format"];
94
101
  if (outputFormat &&
95
102
  !["text", "json", "stream-json", "stream"].includes(outputFormat)) {
@@ -110,62 +117,165 @@ function parseCliArgs() {
110
117
  userInput,
111
118
  };
112
119
  }
113
- function printHelp() {
120
+ function parseImageBuildArgs() {
121
+ const { values } = parseArgs({
122
+ args: argsAfterPositionals(2),
123
+ options: {
124
+ name: { type: "string", default: "sandagent" },
125
+ tag: { type: "string", default: "latest" },
126
+ image: { type: "string" },
127
+ platform: { type: "string", default: "linux/amd64" },
128
+ template: { type: "string" },
129
+ push: { type: "boolean", default: false },
130
+ help: { type: "boolean", short: "h" },
131
+ },
132
+ allowPositionals: false,
133
+ strict: true,
134
+ });
135
+ if (values.help) {
136
+ printImageBuildHelp();
137
+ process.exit(0);
138
+ }
139
+ return {
140
+ name: values.name,
141
+ tag: values.tag,
142
+ image: values.image,
143
+ platform: values.platform,
144
+ template: values.template,
145
+ push: values.push ?? false,
146
+ };
147
+ }
148
+ // ---------------------------------------------------------------------------
149
+ // Help text
150
+ // ---------------------------------------------------------------------------
151
+ function printRunHelp() {
114
152
  console.log(`
115
- 🤖 SandAgent Runner CLI
153
+ 🤖 SandAgent Runner CLI — run
116
154
 
117
- Like gemini-cli or claude-code - runs locally in your terminal.
118
- Streams AI SDK UI messages directly to stdout.
155
+ Runs an agent locally in your terminal, streaming AI SDK UI messages to stdout.
119
156
 
120
157
  Usage:
121
158
  sandagent run [options] -- "<user input>"
122
159
 
123
160
  Options:
124
- -r, --runner <runner> Runner to use: claude, codex, copilot (default: claude)
125
- -m, --model <model> Model to use (default: claude-sonnet-4-20250514)
126
- -c, --cwd <path> Working directory (default: current directory)
161
+ -r, --runner <runner> Runner: claude, codex, copilot (default: claude)
162
+ -m, --model <model> Model (default: claude-sonnet-4-20250514)
163
+ -c, --cwd <path> Working directory (default: cwd)
127
164
  -s, --system-prompt <prompt> Custom system prompt
128
- -t, --max-turns <n> Maximum conversation turns
129
- -a, --allowed-tools <tools> Comma-separated list of allowed tools
130
- -r, --resume <session-id> Resume a previous session
131
- -o, --output-format <format> Output format (default: stream)
132
- Available: text, json(single result), stream-json(realtime streaming), stream(ai sdk ui sse format)
133
- -h, --help Show this help message
165
+ -t, --max-turns <n> Max conversation turns
166
+ -a, --allowed-tools <tools> Comma-separated allowed tools
167
+ --resume <session-id> Resume a previous session
168
+ -o, --output-format <fmt> text | json | stream-json | stream (default: stream)
169
+ -h, --help Show this help
170
+
171
+ Environment:
172
+ ANTHROPIC_API_KEY Anthropic API key (required)
173
+ SANDAGENT_WORKSPACE Default workspace path
174
+ `);
175
+ }
176
+ function printImageBuildHelp() {
177
+ console.log(`
178
+ 🐳 SandAgent Runner CLI — image build
134
179
 
135
- Environment Variables:
136
- ANTHROPIC_API_KEY Anthropic API key (required)
137
- SANDAGENT_WORKSPACE Default workspace path
138
- SANDAGENT_LOG_LEVEL Logging level (debug, info, warn, error)
180
+ Build (and optionally push) a SandAgent Docker image.
181
+ The image includes Claude Agent SDK + runner-cli pre-installed.
182
+
183
+ Usage:
184
+ sandagent image build [options]
185
+
186
+ Options:
187
+ --name <name> Image name, e.g. vikadata/sandagent-seo (default: sandagent)
188
+ --tag <tag> Image tag (default: latest)
189
+ --image <full> Full image name override (e.g. myorg/myimage:v1)
190
+ --platform <plat> Build platform (default: linux/amd64)
191
+ --template <path> Path to agent template directory to bake into the image
192
+ --push Push image to registry after build
193
+ -h, --help Show this help
139
194
 
140
195
  Examples:
141
- # Run with default settings
142
- sandagent run -- "Create a hello world script"
196
+ sandagent image build --name vikadata/sandagent-seo --tag 0.1.0
197
+ sandagent image build --name vikadata/sandagent-seo --tag 0.1.0 --template ./templates/seo-agent
198
+ sandagent image build --name vikadata/sandagent-seo --tag 0.1.0 --template ./templates/seo-agent --push
199
+ `);
200
+ }
201
+ function printImageHelp() {
202
+ console.log(`
203
+ 🐳 SandAgent Runner CLI — image
143
204
 
144
- # Run with custom system prompt
145
- sandagent run --system-prompt "You are a coding assistant" -- "Build a REST API with Express"
205
+ Manage SandAgent Docker images.
146
206
 
147
- # Specify working directory
148
- sandagent run --cwd ./my-project -- "Fix the bug in main.ts"
207
+ Usage:
208
+ sandagent image <subcommand> [options]
209
+
210
+ Subcommands:
211
+ build Build (and optionally push) a Docker image
212
+
213
+ Run "sandagent image build --help" for build options.
149
214
  `);
150
215
  }
216
+ function printGlobalHelp() {
217
+ console.log(`
218
+ 🤖 SandAgent Runner CLI
219
+
220
+ Usage:
221
+ sandagent <command> [options]
222
+
223
+ Commands:
224
+ run Run an agent locally (streams AI SDK UI messages to stdout)
225
+ image build Build a SandAgent Docker image (with optional --push)
226
+
227
+ Run "sandagent <command> --help" for command-specific options.
228
+ `);
229
+ }
230
+ // ---------------------------------------------------------------------------
231
+ // Main
232
+ // ---------------------------------------------------------------------------
151
233
  async function main() {
152
- const args = parseCliArgs();
153
- // Change to the specified working directory
154
- process.chdir(args.cwd);
155
- // Run the agent and stream output to stdout
156
- await runAgent({
157
- runner: args.runner,
158
- model: args.model,
159
- userInput: args.userInput,
160
- systemPrompt: args.systemPrompt,
161
- maxTurns: args.maxTurns,
162
- allowedTools: args.allowedTools,
163
- resume: args.resume,
164
- outputFormat: args.outputFormat,
165
- });
234
+ const sub = getSubcommand();
235
+ if (!sub || sub === "--help" || sub === "-h") {
236
+ printGlobalHelp();
237
+ process.exit(0);
238
+ }
239
+ switch (sub) {
240
+ case "run": {
241
+ const args = parseRunArgs();
242
+ process.chdir(args.cwd);
243
+ await runAgent({
244
+ runner: args.runner,
245
+ model: args.model,
246
+ userInput: args.userInput,
247
+ systemPrompt: args.systemPrompt,
248
+ maxTurns: args.maxTurns,
249
+ allowedTools: args.allowedTools,
250
+ resume: args.resume,
251
+ outputFormat: args.outputFormat,
252
+ });
253
+ break;
254
+ }
255
+ case "image": {
256
+ const subSub = getSubSubcommand();
257
+ if (!subSub || subSub === "--help" || subSub === "-h") {
258
+ printImageHelp();
259
+ process.exit(0);
260
+ }
261
+ if (subSub === "build") {
262
+ const args = parseImageBuildArgs();
263
+ await buildImage(args);
264
+ }
265
+ else {
266
+ console.error(`Unknown image subcommand: ${subSub}`);
267
+ printImageHelp();
268
+ process.exit(1);
269
+ }
270
+ break;
271
+ }
272
+ default:
273
+ console.error(`Unknown command: ${sub}`);
274
+ printGlobalHelp();
275
+ process.exit(1);
276
+ }
166
277
  }
167
278
  main().catch((error) => {
168
- // Errors go to stderr, not stdout
169
279
  console.error("Fatal error:", error.message);
170
280
  process.exit(1);
171
281
  });
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;GAMG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E,2DAA2D;AAC3D,SAAS,aAAa;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,KAAK,IAAI;YAAE,MAAM;QACtB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,qFAAqF;AACrF,SAAS,gBAAgB;IACvB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1B,IAAI,CAAC,KAAK,IAAI;YAAE,MAAM;QACtB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAO,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,sDAAsD;AACtD,SAAS,oBAAoB,CAAC,CAAS;IACrC,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACjE,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC;gBAAE,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAkBD,SAAS,YAAY;IACnB,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,SAAS,CAAC;QACxC,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC;QAC7B,OAAO,EAAE;YACP,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE;YACzD,KAAK,EAAE;gBACL,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,GAAG;gBACV,OAAO,EAAE,0BAA0B;aACpC;YACD,GAAG,EAAE;gBACH,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,GAAG;gBACV,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,EAAE;aAC1D;YACD,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;YAC/C,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;YAC3C,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;YAC/C,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC1B,eAAe,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;YAC/C,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;SACtC;QACD,gBAAgB,EAAE,IAAI;QACtB,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,YAAY,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,IAAI,SAAS,KAAK,CAAC,CAAC,IAAI,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5D,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1D,CAAC;SAAM,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,SAAS,GAAG,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,CAAC,CAAC;QAC/C,OAAO,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAC;QAClE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAO,CAAC;IAC9B,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACrD,OAAO,CAAC,KAAK,CACX,8DAA8D,CAC/D,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,YAAY,GAAG,MAAM,CAAC,eAAe,CAA6B,CAAC;IACzE,IACE,YAAY;QACZ,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,EACjE,CAAC;QACD,OAAO,CAAC,KAAK,CACX,gFAAgF,CACjF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO;QACL,MAAM;QACN,KAAK,EAAE,MAAM,CAAC,KAAM;QACpB,GAAG,EAAE,MAAM,CAAC,GAAI;QAChB,YAAY,EAAE,MAAM,CAAC,eAAe,CAAC;QACrC,QAAQ,EAAE,MAAM,CAAC,WAAW,CAAC;YAC3B,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;YAC1C,CAAC,CAAC,SAAS;QACb,YAAY,EAAE,MAAM,CAAC,eAAe,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACtE,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,YAAY,EAAG,YAA6B,IAAI,QAAQ;QACxD,SAAS;KACV,CAAC;AACJ,CAAC;AAeD,SAAS,mBAAmB;IAC1B,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC;QAC7B,OAAO,EAAE;YACP,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE;YAC9C,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE;YAC1C,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YACzB,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE;YACpD,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;YAC5B,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;YACzC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;SACtC;QACD,gBAAgB,EAAE,KAAK;QACvB,MAAM,EAAE,IAAI;KACb,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,mBAAmB,EAAE,CAAC;QACtB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAK;QAClB,GAAG,EAAE,MAAM,CAAC,GAAI;QAChB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,QAAQ,EAAE,MAAM,CAAC,QAAS;QAC1B,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,KAAK;KAC3B,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,SAAS,YAAY;IACnB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;CAsBb,CAAC,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB;IAC1B,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;CAsBb,CAAC,CAAC;AACH,CAAC;AAED,SAAS,cAAc;IACrB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;CAYb,CAAC,CAAC;AACH,CAAC;AAED,SAAS,eAAe;IACtB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;CAWb,CAAC,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,OAAO;AACP,8EAA8E;AAE9E,KAAK,UAAU,IAAI;IACjB,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAE5B,IAAI,CAAC,GAAG,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QAC7C,eAAe,EAAE,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,QAAQ,GAAG,EAAE,CAAC;QACZ,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACxB,MAAM,QAAQ,CAAC;gBACb,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,QAAQ,EAAE,IAAI,CAAC,QAAQ;gBACvB,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,MAAM,EAAE,IAAI,CAAC,MAAM;gBACnB,YAAY,EAAE,IAAI,CAAC,YAAY;aAChC,CAAC,CAAC;YACH,MAAM;QACR,CAAC;QACD,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;YAClC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;gBACtD,cAAc,EAAE,CAAC;gBACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;gBACvB,MAAM,IAAI,GAAG,mBAAmB,EAAE,CAAC;gBACnC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;YACzB,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,6BAA6B,MAAM,EAAE,CAAC,CAAC;gBACrD,cAAc,EAAE,CAAC;gBACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM;QACR,CAAC;QACD;YACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAC;YACzC,eAAe,EAAE,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export { runAgent, type RunAgentOptions } from "./runner.js";
2
+ export { buildImage, type BuildImageOptions } from "./build-image.js";
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export { runAgent } from "./runner.js";
2
+ export { buildImage } from "./build-image.js";
2
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAC7D,OAAO,EAAE,UAAU,EAA0B,MAAM,kBAAkB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sandagent/runner-cli",
3
- "version": "0.2.8",
3
+ "version": "0.2.10",
4
4
  "description": "SandAgent Runner CLI - Like gemini-cli or claude-code, runs in your local terminal with AI SDK UI streaming",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,8 @@
16
16
  }
17
17
  },
18
18
  "files": [
19
- "dist"
19
+ "dist",
20
+ "Dockerfile"
20
21
  ],
21
22
  "repository": {
22
23
  "type": "git",