@castari/cli 0.0.1 → 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 ADDED
@@ -0,0 +1,20 @@
1
+ # @castari/cli
2
+
3
+ The Command Line Interface for Castari.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install -g @castari/cli
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ See the [CLI Reference](../../docs/cli-reference.md) for detailed documentation.
14
+
15
+ ```bash
16
+ castari init # Create a new agent
17
+ castari dev # Run locally
18
+ castari deploy # Deploy to Platform
19
+ castari start # Start sandbox
20
+ ```
@@ -1,12 +1,7 @@
1
- import { Daytona, Image } from '@daytonaio/sdk';
2
1
  import { readFile } from 'fs/promises';
3
2
  import chalk from 'chalk';
3
+ import AdmZip from 'adm-zip';
4
4
  export async function deploy(options) {
5
- const apiKey = process.env.DAYTONA_API_KEY;
6
- if (!apiKey) {
7
- console.error(chalk.red('Error: DAYTONA_API_KEY is required.'));
8
- process.exit(1);
9
- }
10
5
  // Read package.json to get default snapshot name
11
6
  let snapshotName = options.snapshot;
12
7
  if (!snapshotName) {
@@ -23,42 +18,45 @@ export async function deploy(options) {
23
18
  console.error(chalk.red('Error: Snapshot name is required (via --snapshot or package.json name).'));
24
19
  process.exit(1);
25
20
  }
26
- console.log(chalk.blue(`🧱 Building Daytona snapshot "${snapshotName}"...`));
27
- const daytona = new Daytona({
28
- apiKey,
29
- apiUrl: process.env.DAYTONA_API_URL,
30
- target: process.env.DAYTONA_TARGET,
31
- });
21
+ console.log(chalk.blue(`šŸ“¦ Packaging source code...`));
22
+ const zip = new AdmZip();
32
23
  const projectRoot = process.cwd();
33
- const workspaceMount = '/home/daytona/agent-workspace';
34
- // Use official Bun image
35
- const image = Image.base('oven/bun:1.3.1')
36
- .addLocalDir(projectRoot, '/home/daytona/app')
37
- .workdir('/home/daytona/app')
38
- .runCommands('apt-get update && apt-get install -y git', 'bun install', `mkdir -p ${workspaceMount}`)
39
- .entrypoint(['sleep', 'infinity']);
24
+ // Add local files, respecting a simple ignore list for now
25
+ // Ideally we'd parse .gitignore, but for MVP let's just ignore common heavy folders
26
+ const ignoreList = ['node_modules', '.git', 'dist', '.daytona', '.env'];
27
+ zip.addLocalFolder(projectRoot, undefined, (filename) => {
28
+ // Simple filter: return false to exclude
29
+ // filename is the relative path in the zip? No, it seems to be the absolute path or filename.
30
+ // AdmZip filter is a bit tricky. Let's assume it passes the name.
31
+ // Actually addLocalFolder filter takes a RegExp or function.
32
+ // If function: (filename: string) => boolean.
33
+ // Note: filename passed to filter is usually the relative path.
34
+ // Let's try to be safe and just add everything except node_modules at the root.
35
+ // Actually, addLocalFolder adds everything.
36
+ // We might want to use addLocalFile loop or similar if we want strict control.
37
+ // But let's try the filter.
38
+ return !ignoreList.some(ignore => filename.includes(ignore));
39
+ });
40
+ const zipBuffer = zip.toBuffer();
41
+ console.log(chalk.blue(`šŸš€ Uploading to Castari Platform...`));
42
+ const platformUrl = process.env.CASTARI_PLATFORM_URL || 'http://localhost:3000';
43
+ const formData = new FormData();
44
+ formData.append('file', new Blob([zipBuffer]), 'source.zip');
45
+ formData.append('snapshot', snapshotName);
40
46
  try {
41
- // Try to delete existing snapshot to allow overwrite
42
- try {
43
- await daytona.snapshot.delete(snapshotName);
44
- console.log(chalk.yellow(`šŸ—‘ļø Deleted existing snapshot "${snapshotName}"`));
45
- }
46
- catch (e) {
47
- // Ignore delete error (e.g. not found)
48
- }
49
- await daytona.snapshot.create({
50
- name: snapshotName,
51
- image,
52
- }, {
53
- onLogs: log => {
54
- if (log)
55
- process.stdout.write(log);
56
- },
47
+ const response = await fetch(`${platformUrl}/deploy`, {
48
+ method: 'POST',
49
+ body: formData,
57
50
  });
58
- console.log(chalk.green(`āœ… Snapshot "${snapshotName}" created successfully!`));
51
+ if (!response.ok) {
52
+ const errorText = await response.text();
53
+ throw new Error(`Platform error (${response.status}): ${errorText}`);
54
+ }
55
+ const result = await response.json();
56
+ console.log(chalk.green(`āœ… Snapshot "${result.snapshot}" created successfully!`));
59
57
  }
60
58
  catch (err) {
61
- console.error(chalk.red('Snapshot build failed:'), err.message || err);
59
+ console.error(chalk.red('Deploy failed:'), err.message || err);
62
60
  process.exit(1);
63
61
  }
64
62
  }
@@ -22,7 +22,7 @@ export async function init() {
22
22
  start: 'castari start',
23
23
  },
24
24
  dependencies: {
25
- '@castari/sdk': 'workspace:*',
25
+ '@castari/sdk': '^0.0.4',
26
26
  '@anthropic-ai/claude-agent-sdk': '^0.1.44',
27
27
  },
28
28
  castari: {
@@ -62,7 +62,7 @@ serve({
62
62
  systemPrompt: 'You are a helpful Castari agent.',
63
63
  })
64
64
  `;
65
- const envExample = `ANTHROPIC_API_KEY=sk-ant-...\nDAYTONA_API_KEY=...\n`;
65
+ const envExample = `ANTHROPIC_API_KEY=sk-ant-...\n# CASTARI_PLATFORM_URL=https://api.castari.com\n`;
66
66
  await writeFile('package.json', JSON.stringify(packageJson, null, 2));
67
67
  await writeFile('tsconfig.json', JSON.stringify(tsConfig, null, 2));
68
68
  await writeFile('.env.example', envExample);
@@ -5,11 +5,6 @@ import dotenv from 'dotenv';
5
5
  export async function start(options) {
6
6
  // Load .env from current directory
7
7
  dotenv.config();
8
- const apiKey = process.env.DAYTONA_API_KEY;
9
- if (!apiKey) {
10
- console.error(chalk.red('Error: DAYTONA_API_KEY is required.'));
11
- process.exit(1);
12
- }
13
8
  // Read package.json for defaults
14
9
  let snapshotName = options.snapshot;
15
10
  let volumeName = options.volume;
@@ -31,11 +26,13 @@ export async function start(options) {
31
26
  if (volumeName) {
32
27
  console.log(chalk.blue(`šŸ“¦ Using volume: ${volumeName}`));
33
28
  }
29
+ const platformUrl = process.env.CASTARI_PLATFORM_URL;
34
30
  const client = new CastariClient({
35
31
  snapshot: snapshotName,
36
32
  volume: volumeName,
37
- daytonaApiKey: apiKey,
33
+ platformUrl,
38
34
  debug: true, // Enable debug logs for CLI
35
+ anthropicApiKey: process.env.ANTHROPIC_API_KEY
39
36
  });
40
37
  try {
41
38
  await client.start();
@@ -78,6 +75,14 @@ export async function start(options) {
78
75
  console.error(chalk.red('Error:'), msg.error);
79
76
  }
80
77
  });
78
+ // Add signal handlers for graceful shutdown
79
+ const cleanup = async () => {
80
+ console.log(chalk.yellow('\nšŸ›‘ Shutting down...'));
81
+ await client.stop({ delete: true });
82
+ process.exit(0);
83
+ };
84
+ process.on('SIGINT', cleanup);
85
+ process.on('SIGTERM', cleanup);
81
86
  }
82
87
  catch (err) {
83
88
  console.error(chalk.red('Failed to start agent:'), err.message || err);
package/dist/index.js CHANGED
@@ -9,11 +9,11 @@ cli
9
9
  .command('init', 'Initialize a new Castari agent project')
10
10
  .action(init);
11
11
  cli
12
- .command('deploy', 'Build and deploy the agent snapshot to Daytona')
12
+ .command('deploy', 'Deploy the agent to the Castari Platform')
13
13
  .option('--snapshot <name>', 'Snapshot name (overrides package.json)')
14
14
  .action(deploy);
15
15
  cli
16
- .command('start', 'Start a Daytona sandbox for the agent')
16
+ .command('start', 'Start a sandbox for the agent')
17
17
  .option('--snapshot <name>', 'Snapshot name')
18
18
  .option('--volume <name>', 'Volume name for persistence')
19
19
  .option('--id <id>', 'Custom sandbox ID')
@@ -22,5 +22,5 @@ cli
22
22
  .command('dev', 'Run the agent locally for development')
23
23
  .action(dev);
24
24
  cli.help();
25
- cli.version('0.0.1');
25
+ cli.version('0.0.4');
26
26
  cli.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@castari/cli",
3
- "version": "0.0.1",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "castari": "./dist/index.js"
@@ -17,15 +17,18 @@
17
17
  "dev": "bun run src/index.ts"
18
18
  },
19
19
  "dependencies": {
20
+ "@anthropic-ai/claude-agent-sdk": "^0.1.44",
21
+ "@castari/sdk": "^0.0.4",
22
+ "adm-zip": "^0.5.16",
20
23
  "cac": "^6.7.14",
21
- "inquirer": "^9.2.12",
22
24
  "chalk": "^5.3.0",
23
25
  "dotenv": "^16.3.1",
24
- "@daytonaio/sdk": "^0.115.2",
25
- "@castari/sdk": "^0.0.1",
26
- "@anthropic-ai/claude-agent-sdk": "^0.1.44"
26
+ "form-data": "^4.0.5",
27
+ "inquirer": "^9.2.12"
27
28
  },
28
29
  "devDependencies": {
30
+ "@types/adm-zip": "^0.5.7",
31
+ "@types/form-data": "^2.5.2",
29
32
  "@types/inquirer": "^9.0.7",
30
33
  "@types/node": "^20.10.0",
31
34
  "typescript": "^5.6.3"