@inneranimalmedia/agentsam-sdk 1.0.1 → 1.1.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.
package/DEVELOPMENT.md ADDED
@@ -0,0 +1,55 @@
1
+ # Developing agentsam-sdk with Inner Animal Media
2
+
3
+ ## Local smoke test
4
+
5
+ ```bash
6
+ cd agentsam-sdk
7
+ npm test
8
+ ```
9
+
10
+ ## Link into a scaffolded project
11
+
12
+ ```bash
13
+ cd agentsam-sdk && npm link
14
+ cd /path/to/your-project && npm link @inneranimalmedia/agentsam-sdk
15
+ npm run dev
16
+ ```
17
+
18
+ ## Link into inneranimalmedia (monorepo-style)
19
+
20
+ From the platform repo:
21
+
22
+ ```bash
23
+ cd inneranimalmedia
24
+ npm link ../agentsam-sdk
25
+ ```
26
+
27
+ Then in any Worker or script:
28
+
29
+ ```js
30
+ import { AgentSam } from '@inneranimalmedia/agentsam-sdk';
31
+ ```
32
+
33
+ ## Non-interactive init (CI / smoke)
34
+
35
+ ```bash
36
+ npx agentsam init \
37
+ --name my-agent \
38
+ --lane fullstack \
39
+ --provider cloudflare \
40
+ --agent orchestrator \
41
+ --yes
42
+ ```
43
+
44
+ ## Publish checklist
45
+
46
+ 1. `npm test` passes
47
+ 2. Bump version in `package.json`
48
+ 3. `npm publish --access public`
49
+ 4. Tag: `git tag v1.1.1 && git push origin v1.1.1`
50
+
51
+ ## Known gaps (roadmap)
52
+
53
+ - `agentsam deploy`, `status`, `logs` — not implemented yet
54
+ - CMS lane in README — CLI has 4 lanes today (Full Stack, Data, CRM, Creative)
55
+ - Published API route may differ; stub mode works without `AGENTSAM_API_KEY`
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Inner Animal Media
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # Agent Sam SDK
2
+
3
+ > The AI agent layer for developers who need more than a chatbot.
4
+
5
+ Agent Sam is a full-stack autonomous agent SDK built on Cloudflare Workers, D1, Supabase, Durable Objects, and MCP — designed to converse, plan, and execute real work across your entire stack. CMS websites, full-stack applications, data pipelines, creative workflows, terminal execution, deployments, and multi-step agentic pipelines — all through one unified agent interface.
6
+
7
+ ---
8
+
9
+ ## What is Agent Sam?
10
+
11
+ Agent Sam is a platform operator AI. It sits on top of your infrastructure and can:
12
+
13
+ - **Understand intent** — natural language in, real actions out
14
+ - **Execute across surfaces** — terminal, database, browser, CAD, deploy, MCP tools
15
+ - **Route intelligently** — local machine, cloud VM, or sandboxed environment based on context
16
+ - **Gate high-risk actions** — approval flows before anything destructive runs
17
+ - **Leave an audit trail** — every tool call, command run, and decision is logged
18
+
19
+ It is not a wrapper around a chat API. It is a command fabric with a conversation interface.
20
+
21
+ ---
22
+
23
+ ## Quickstart
24
+
25
+ \`\`\`bash
26
+ npx @inneranimalmedia/agentsam-sdk init
27
+ \`\`\`
28
+
29
+ Non-interactive (CI / scripts):
30
+
31
+ \`\`\`bash
32
+ npx @inneranimalmedia/agentsam-sdk init \\
33
+ --name my-agent \\
34
+ --lane fullstack \\
35
+ --provider cloudflare \\
36
+ --agent orchestrator \\
37
+ --yes
38
+ \`\`\`
39
+
40
+ Scaffolded workers expose \`GET /health\` and \`POST /chat\` immediately (stub mode without an API key).
41
+
42
+ See [DEVELOPMENT.md](./DEVELOPMENT.md) for linking the SDK into Inner Animal Media locally.
43
+
44
+ ---
45
+
46
+ ## Installation
47
+
48
+ \`\`\`bash
49
+ npm install @inneranimalmedia/agentsam-sdk
50
+ \`\`\`
51
+
52
+ ---
53
+
54
+ ## Lanes
55
+
56
+ | Lane | Best For |
57
+ |------|----------|
58
+ | **Full Stack** | End-to-end apps — agent chat, terminal, deploy, D1, R2, Durable Objects, KV |
59
+ | **CMS** | Content-managed websites — pages, assets, themes, navigation, live edit |
60
+ | **Data Solutions** | Database ops, migrations, queries, Supabase pgvector, Hyperdrive pipelines |
61
+ | **Customer Management** | CRM, contacts, billing, client workflows, multi-tenant isolation |
62
+ | **Creative & Design** | CAD, 3D, media generation, content pipelines |
63
+
64
+ ---
65
+
66
+ ## Agents
67
+
68
+ | Agent | Role |
69
+ |-------|------|
70
+ | **Orchestrator** | General purpose — routes across all lanes and tools |
71
+ | **CMS Agent** | Pages, sections, assets, themes, publishing workflows |
72
+ | **Data Agent** | D1, Supabase, Hyperdrive, migrations, vector search |
73
+ | **CRM Agent** | Customer records, contacts, billing, client isolation |
74
+ | **Creative Agent** | Design commands, 3D generation, CAD, media pipelines |
75
+
76
+ ---
77
+
78
+ ## How It Works
79
+
80
+ \`\`\`
81
+ User Intent (chat or CLI)
82
+
83
+ Agent Sam — intent classification + command match
84
+
85
+ Tool Catalog (D1) — policy check + approval gate
86
+
87
+ Execution — terminal / D1 / Supabase / R2 / KV / DO / browser / deploy / MCP
88
+
89
+ Telemetry — every action logged, measured, improvable
90
+ \`\`\`
91
+
92
+ Capabilities are data-driven — new tools are added via D1, not Worker redeployments. The same tool catalog powers the dashboard, the CLI, and any MCP-connected client like Cursor or Claude Desktop.
93
+
94
+ ---
95
+
96
+ ## Infrastructure
97
+
98
+ Agent Sam scaffolds and operates across the full Cloudflare + Supabase stack:
99
+
100
+ | Layer | Technology | Role |
101
+ |-------|------------|------|
102
+ | **Compute** | Cloudflare Workers | Edge runtime, API, agent dispatch |
103
+ | **Relational DB** | D1 (SQLite) | Tool catalog, sessions, telemetry, CMS, auth |
104
+ | **Vector DB** | Supabase pgvector via Hyperdrive | RAG, semantic search, agent memory |
105
+ | **Object Storage** | R2 | Assets, media, bundles, CMS content |
106
+ | **Key-Value** | Workers KV | Cache, CMS drafts, feature flags |
107
+ | **Stateful Sessions** | Durable Objects | Terminal sessions, collab, real-time state |
108
+ | **Terminal** | ExecOS over cloudflared tunnel | Shell execution, deploy, git, wrangler |
109
+ | **AI Router** | Anthropic + OpenAI | Adaptive Thompson sampling across models |
110
+ | **Protocol** | MCP (Model Context Protocol) | External agent surface for Cursor, Claude, etc. |
111
+
112
+ ---
113
+
114
+ ## Execution Lanes
115
+
116
+ Agent Sam routes work to the right environment automatically:
117
+
118
+ | Lane | Environment | When |
119
+ |------|-------------|------|
120
+ | Local | Your machine | Fastest dev loop |
121
+ | Cloud | Always-on VM via tunnel | Machine asleep or offsite |
122
+ | Sandbox | Isolated workspace | Safe experiments, tenant isolation |
123
+
124
+ ---
125
+
126
+ ## What Gets Scaffolded
127
+
128
+ Running \`agentsam init\` generates a production-ready project for your lane:
129
+
130
+ **All lanes include:**
131
+ - \`agentsam.config.js\` — project config, lane, provider, agent
132
+ - \`wrangler.toml\` — Worker, D1, R2, KV, Durable Object bindings
133
+ - \`.env.example\` — all required secrets pre-listed
134
+ - \`src/index.js\` — Worker entry point wired to your agent
135
+ - \`README.md\` — setup and deploy instructions
136
+
137
+ **CMS lane adds:**
138
+ - Page, section, asset, and theme schema migrations
139
+ - CMS worker with live edit, draft/publish, and R2 asset pipeline
140
+
141
+ **Data lane adds:**
142
+ - D1 + Supabase Hyperdrive connection config
143
+ - Vector embedding pipeline scaffold
144
+ - Migration templates for core data models
145
+
146
+ **Full Stack adds:**
147
+ - Durable Object session scaffold
148
+ - Auth tables and session management
149
+ - Full agent chat + tool loop worker
150
+
151
+ ---
152
+
153
+ ## Multi-Tenant & Client Policy
154
+
155
+ Agent Sam is built for isolation from the ground up:
156
+
157
+ - Each user or client gets a scoped workspace
158
+ - Terminal execution is path-isolated — no cross-tenant access
159
+ - AI usage is policy-gated — BYOK, managed, or disabled per client
160
+ - D1 and R2 are scoped per tenant at the binding level
161
+ - Every action produces an audit trail
162
+
163
+ ---
164
+
165
+ ## Roadmap
166
+
167
+ - [ ] \`agentsam deploy\` — push your project from CLI
168
+ - [ ] \`agentsam status\` — live agent and infrastructure health
169
+ - [ ] \`agentsam logs\` — tail tool call and command logs
170
+ - [ ] \`agentsam kit\` — install pre-built capability kits
171
+ - [ ] Kit marketplace — CMS, ecommerce, nonprofit, SaaS starters
172
+ - [ ] BYOK AI key support per project
173
+
174
+ ---
175
+
176
+ ## Built By
177
+
178
+ [Inner Animal Media](https://inneranimalmedia.com) — Agent Sam is the operator brain behind the Inner Animal Media platform. The SDK is how we share that infrastructure with other developers.
179
+
180
+ ---
181
+
182
+ ## License
183
+
184
+ MIT
package/package.json CHANGED
@@ -1,14 +1,33 @@
1
1
  {
2
2
  "name": "@inneranimalmedia/agentsam-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "Agent Sam is a full-stack AI agent SDK for autonomous task execution — covering data management, creative workflows, design commands, and multi-step agentic pipelines.",
5
- "main": "src/index.js",
6
5
  "type": "module",
6
+ "main": "./src/index.js",
7
+ "exports": {
8
+ ".": "./src/index.js",
9
+ "./package.json": "./package.json"
10
+ },
7
11
  "bin": {
8
- "agentsam": "src/cli.js"
12
+ "agentsam": "./src/cli.js"
9
13
  },
14
+ "files": [
15
+ "src",
16
+ "test",
17
+ "README.md",
18
+ "LICENSE",
19
+ "DEVELOPMENT.md"
20
+ ],
10
21
  "scripts": {
11
- "test": "node src/index.js"
22
+ "test": "node test/smoke.mjs",
23
+ "smoke": "node test/smoke.mjs",
24
+ "prepublishOnly": "npm test"
25
+ },
26
+ "engines": {
27
+ "node": ">=20"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
12
31
  },
13
32
  "repository": {
14
33
  "type": "git",
@@ -0,0 +1,67 @@
1
+ import { json, notFound, readJson } from './lib/responses.js';
2
+ import { createSession, getSession } from './lib/sessions.js';
3
+ import { routeIntent } from './lib/router.js';
4
+ import { getToolCatalog } from './lib/tools.js';
5
+
6
+ export class AgentSam {
7
+ constructor(options = {}) {
8
+ this.env = options.env ?? {};
9
+ this.agent = options.agent ?? 'orchestrator';
10
+ this.lane = options.lane ?? 'fullstack';
11
+ this.project = options.project ?? 'agentsam-project';
12
+ }
13
+
14
+ async handle(request) {
15
+ const url = new URL(request.url);
16
+ const path = url.pathname.replace(/\/$/, '') || '/';
17
+
18
+ if (request.method === 'GET' && path === '/api/health') {
19
+ return json({ ok: true, service: 'AgentSam', agent: this.agent, lane: this.lane, status: 'online' });
20
+ }
21
+
22
+ if (request.method === 'GET' && path === '/api/agentsam/info') {
23
+ return json({
24
+ ok: true,
25
+ name: 'AgentSam SDK',
26
+ project: this.project,
27
+ agent: this.agent,
28
+ lane: this.lane,
29
+ capabilities: getToolCatalog(this.lane).map((tool) => tool.name),
30
+ });
31
+ }
32
+
33
+ if (request.method === 'POST' && path === '/api/agentsam/session') {
34
+ const body = await readJson(request);
35
+ const session = await createSession({ env: this.env, agent: this.agent, lane: this.lane, goal: body.goal });
36
+ return json({ ok: true, session });
37
+ }
38
+
39
+ if (request.method === 'GET' && path.startsWith('/api/agentsam/session/')) {
40
+ const sessionId = path.split('/').pop();
41
+ const session = await getSession({ env: this.env, sessionId });
42
+ if (!session) return json({ ok: false, error: 'session_not_found' }, 404);
43
+ return json({ ok: true, session });
44
+ }
45
+
46
+ if (request.method === 'POST' && path === '/api/agentsam/message') {
47
+ const body = await readJson(request);
48
+ const result = routeIntent({
49
+ message: body.message ?? body.goal ?? '',
50
+ agent: body.agent ?? this.agent,
51
+ lane: body.lane ?? this.lane,
52
+ });
53
+
54
+ return json({
55
+ ok: true,
56
+ session_id: body.session_id ?? null,
57
+ agent: result.agent,
58
+ lane: result.lane,
59
+ intent: result.intent,
60
+ next_steps: result.next_steps,
61
+ requires_approval: result.requires_approval,
62
+ });
63
+ }
64
+
65
+ return notFound();
66
+ }
67
+ }
package/src/cli.js CHANGED
@@ -1,16 +1,265 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const command = process.argv[2];
3
+ import readline from 'readline';
4
+ import pkg from '../package.json' with { type: 'json' };
5
+ import { scaffoldProject } from './lib/scaffold.js';
4
6
 
5
- if (command === 'init') {
6
- console.log('Initializing Agent Sam project...');
7
- } else {
7
+ const VERSION = pkg.version;
8
+
9
+ function createPrompt() {
10
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
11
+ return {
12
+ ask: (q) => new Promise((resolve) => rl.question(q, resolve)),
13
+ close: () => rl.close(),
14
+ };
15
+ }
16
+
17
+ const LANES = {
18
+ '1': 'Full Stack',
19
+ '2': 'CMS',
20
+ '3': 'Data Solutions',
21
+ '4': 'Customer Management',
22
+ '5': 'Creative & Design',
23
+ };
24
+
25
+ const LANE_BY_SLUG = {
26
+ fullstack: 'Full Stack',
27
+ cms: 'CMS',
28
+ data: 'Data Solutions',
29
+ crm: 'Customer Management',
30
+ creative: 'Creative & Design',
31
+ };
32
+
33
+ const PROVIDERS = {
34
+ '1': 'Cloudflare Workers',
35
+ '2': 'GitHub + Cloudflare',
36
+ '3': 'Local / Self-hosted',
37
+ };
38
+
39
+ const PROVIDER_BY_SLUG = {
40
+ cloudflare: 'Cloudflare Workers',
41
+ github: 'GitHub + Cloudflare',
42
+ local: 'Local / Self-hosted',
43
+ };
44
+
45
+ const AGENTS = {
46
+ '1': 'orchestrator',
47
+ '2': 'cms',
48
+ '3': 'data',
49
+ '4': 'crm',
50
+ '5': 'creative',
51
+ };
52
+
53
+ function laneKeyFromLabel(label) {
54
+ const entry = Object.entries(LANES).find(([, v]) => v === label);
55
+ return entry?.[0] ?? '1';
56
+ }
57
+
58
+ function printHelp() {
8
59
  console.log(`
9
- Agent Sam SDK — CLI
60
+ Agent Sam SDK — CLI v${VERSION}
10
61
 
11
- Usage:
12
- agentsam init Initialize a new Agent Sam project
62
+ Usage:
63
+ agentsam init [options] Scaffold a new Agent Sam project
64
+ agentsam --version Print version
65
+ agentsam --help Show this help
13
66
 
14
- Version: 1.0.0
67
+ Init options (non-interactive):
68
+ --name <name> Project directory name
69
+ --lane <fullstack|cms|data|crm|creative>
70
+ --provider <cloudflare|github|local>
71
+ --agent <orchestrator|cms|data|crm|creative>
72
+ --cf-account <id> Cloudflare account ID
73
+ --yes Skip confirmation prompt
15
74
  `);
16
75
  }
76
+
77
+ function parseInitArgs(argv) {
78
+ const opts = {
79
+ projectName: '',
80
+ lane: '',
81
+ provider: '',
82
+ agent: '',
83
+ cfAccountId: '',
84
+ yes: false,
85
+ };
86
+
87
+ for (let i = 0; i < argv.length; i += 1) {
88
+ const arg = argv[i];
89
+ if (arg === '--yes' || arg === '-y') opts.yes = true;
90
+ else if (arg === '--name') opts.projectName = argv[++i] || '';
91
+ else if (arg === '--lane') {
92
+ const slug = argv[++i] || '';
93
+ opts.lane = LANE_BY_SLUG[slug] || slug;
94
+ } else if (arg === '--provider') {
95
+ const slug = argv[++i] || '';
96
+ opts.provider = PROVIDER_BY_SLUG[slug] || slug;
97
+ } else if (arg === '--agent') opts.agent = argv[++i] || '';
98
+ else if (arg === '--cf-account') opts.cfAccountId = argv[++i] || '';
99
+ }
100
+
101
+ return opts;
102
+ }
103
+
104
+ async function runInit(config) {
105
+ const {
106
+ projectName,
107
+ lane,
108
+ provider,
109
+ agent,
110
+ cfAccountId = '',
111
+ yes = false,
112
+ prompt = null,
113
+ } = config;
114
+
115
+ const safeDir = projectName.trim();
116
+ console.log(`
117
+ ┌─────────────────────────────────────┐
118
+ │ Agent Sam Project Config │
119
+ ├─────────────────────────────────────┤
120
+ │ Project: ${safeDir.padEnd(25)}│
121
+ │ Lane: ${lane.padEnd(25)}│
122
+ │ Provider: ${provider.padEnd(25)}│
123
+ │ Agent: ${agent.padEnd(25)}│
124
+ │ CF Acct: ${(cfAccountId || 'not set').padEnd(25)}│
125
+ └─────────────────────────────────────┘
126
+ `);
127
+
128
+ let confirm = 'y';
129
+ if (!yes && prompt) {
130
+ confirm = await prompt.ask(' Scaffold project? (y/n): ');
131
+ }
132
+
133
+ if (confirm.toLowerCase() === 'y') {
134
+ try {
135
+ const dir = scaffoldProject({
136
+ projectName: safeDir,
137
+ lane,
138
+ provider,
139
+ agent,
140
+ cfAccountId,
141
+ sdkVersion: VERSION,
142
+ });
143
+ console.log(`
144
+ ✓ Project created at ${dir}
145
+
146
+ Next steps:
147
+ cd ${dir.split('/').pop()}
148
+ cp .env.example .env
149
+ npm install
150
+ npm run smoke
151
+ npm run dev
152
+ `);
153
+ } catch (error) {
154
+ console.error(`\n ✗ ${error.message}\n`);
155
+ process.exitCode = 1;
156
+ }
157
+ } else {
158
+ console.log('\n Cancelled.\n');
159
+ }
160
+ }
161
+
162
+ async function initInteractive(partial = {}) {
163
+ const prompt = createPrompt();
164
+
165
+ console.log(`
166
+ ╔═══════════════════════════════════╗
167
+ ║ Agent Sam SDK — Init ║
168
+ ╚═══════════════════════════════════╝
169
+ `);
170
+
171
+ const projectName = partial.projectName || (await prompt.ask(' Project name: '));
172
+
173
+ if (!partial.lane) {
174
+ console.log(`
175
+ Select a lane:
176
+ 1) Full Stack
177
+ 2) CMS
178
+ 3) Data Solutions
179
+ 4) Customer Management
180
+ 5) Creative & Design
181
+ `);
182
+ }
183
+ const laneKey = partial.lane ? laneKeyFromLabel(partial.lane) : await prompt.ask(' Lane [1-5]: ');
184
+ const lane = partial.lane || LANES[laneKey] || 'Full Stack';
185
+
186
+ console.log(`
187
+ Select a provider:
188
+ 1) Cloudflare Workers
189
+ 2) GitHub + Cloudflare
190
+ 3) Local / Self-hosted
191
+ `);
192
+ const providerKey = partial.provider
193
+ ? Object.entries(PROVIDERS).find(([, v]) => v === partial.provider)?.[0] || '1'
194
+ : await prompt.ask(' Provider [1-3]: ');
195
+ const provider = partial.provider || PROVIDERS[providerKey] || 'Cloudflare Workers';
196
+
197
+ if (!partial.agent) {
198
+ console.log(`
199
+ Select your default Agent Sam:
200
+ 1) Orchestrator — general purpose, routes to all lanes
201
+ 2) CMS Agent — pages, sections, assets, publishing workflows
202
+ 3) Data Agent — database ops, migrations, queries
203
+ 4) CRM Agent — customer management, contacts, billing
204
+ 5) Creative Agent — design, 3D, media, content
205
+ `);
206
+ }
207
+ const agentKey = partial.agent
208
+ ? Object.entries(AGENTS).find(([, v]) => v === partial.agent)?.[0] || '1'
209
+ : await prompt.ask(' Agent [1-5]: ');
210
+ const agent = partial.agent || AGENTS[agentKey] || 'orchestrator';
211
+
212
+ const cfAccountId =
213
+ partial.cfAccountId !== undefined && partial.cfAccountId !== ''
214
+ ? partial.cfAccountId
215
+ : await prompt.ask(' Cloudflare Account ID (enter to skip): ');
216
+
217
+ await runInit({
218
+ projectName,
219
+ lane,
220
+ provider,
221
+ agent,
222
+ cfAccountId,
223
+ yes: partial.yes,
224
+ prompt,
225
+ });
226
+
227
+ prompt.close();
228
+ }
229
+
230
+ async function initFromArgs(argv) {
231
+ const opts = parseInitArgs(argv);
232
+ if (!opts.projectName) {
233
+ console.error('\n ✗ --name is required for non-interactive init.\n');
234
+ process.exit(1);
235
+ }
236
+ await runInit({
237
+ projectName: opts.projectName,
238
+ lane: opts.lane || 'Full Stack',
239
+ provider: opts.provider || 'Cloudflare Workers',
240
+ agent: opts.agent || 'orchestrator',
241
+ cfAccountId: opts.cfAccountId,
242
+ yes: true,
243
+ prompt: null,
244
+ });
245
+ }
246
+
247
+ const command = process.argv[2];
248
+ const rest = process.argv.slice(3);
249
+
250
+ if (command === '--version' || command === '-v') {
251
+ console.log(VERSION);
252
+ } else if (command === '--help' || command === '-h' || !command) {
253
+ printHelp();
254
+ } else if (command === 'init') {
255
+ const hasFlags = rest.some((a) => a.startsWith('--'));
256
+ if (hasFlags) {
257
+ await initFromArgs(rest);
258
+ } else {
259
+ await initInteractive({});
260
+ }
261
+ } else {
262
+ console.error(`\n Unknown command: ${command}\n`);
263
+ printHelp();
264
+ process.exit(1);
265
+ }
package/src/index.js CHANGED
@@ -1,5 +1,11 @@
1
- // @inneranimalmedia/agentsam-sdk
2
- // Agent Sam SDK — entry point
1
+ // @inneranimalmedia/agentsam-sdk — public API
3
2
 
4
- export const version = '1.0.0';
5
- export const name = 'agentsam-sdk';
3
+ import pkg from '../package.json' with { type: 'json' };
4
+
5
+ export { AgentSam } from './AgentSam.js';
6
+ export { routeIntent } from './lib/router.js';
7
+ export { getToolCatalog } from './lib/tools.js';
8
+ export { scaffoldProject } from './lib/scaffold.js';
9
+
10
+ export const version = pkg.version;
11
+ export const name = pkg.name;
@@ -0,0 +1,21 @@
1
+ export function json(data, status = 200, headers = {}) {
2
+ return new Response(JSON.stringify(data, null, 2), {
3
+ status,
4
+ headers: {
5
+ 'content-type': 'application/json; charset=utf-8',
6
+ ...headers,
7
+ },
8
+ });
9
+ }
10
+
11
+ export function notFound() {
12
+ return json({ ok: false, error: 'not_found' }, 404);
13
+ }
14
+
15
+ export async function readJson(request) {
16
+ try {
17
+ return await request.json();
18
+ } catch {
19
+ return {};
20
+ }
21
+ }
@@ -0,0 +1,51 @@
1
+ export function routeIntent({ message = '', agent = 'orchestrator', lane = 'fullstack' }) {
2
+ const text = String(message).toLowerCase();
3
+
4
+ if (/delete|drop table|destroy|wipe|purge|production/.test(text)) {
5
+ return {
6
+ agent,
7
+ lane,
8
+ intent: 'high_risk_action',
9
+ requires_approval: true,
10
+ next_steps: ['Summarize intended change', 'Request explicit approval', 'Run only after approval'],
11
+ };
12
+ }
13
+
14
+ if (/page|cms|publish|section|hero|content/.test(text)) {
15
+ return {
16
+ agent: 'cms',
17
+ lane: 'cms',
18
+ intent: 'cms_build',
19
+ requires_approval: false,
20
+ next_steps: ['Create page outline', 'Attach visual assets', 'Prepare draft for preview'],
21
+ };
22
+ }
23
+
24
+ if (/database|sql|query|migration|schema|supabase|d1/.test(text)) {
25
+ return {
26
+ agent: 'data',
27
+ lane: 'data',
28
+ intent: 'data_task',
29
+ requires_approval: false,
30
+ next_steps: ['Inspect schema', 'Draft safe query or migration', 'Return reviewable plan'],
31
+ };
32
+ }
33
+
34
+ if (/design|3d|cad|media|video|image|creative/.test(text)) {
35
+ return {
36
+ agent: 'creative',
37
+ lane: 'creative',
38
+ intent: 'creative_task',
39
+ requires_approval: false,
40
+ next_steps: ['Create production brief', 'Identify assets needed', 'Prepare generation or build steps'],
41
+ };
42
+ }
43
+
44
+ return {
45
+ agent,
46
+ lane,
47
+ intent: 'general_build',
48
+ requires_approval: false,
49
+ next_steps: ['Understand goal', 'Plan the work', 'Route to the right specialist'],
50
+ };
51
+ }
@@ -0,0 +1,260 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+
4
+ const LANE_KEYS = {
5
+ 'Full Stack': 'fullstack',
6
+ CMS: 'cms',
7
+ 'Data Solutions': 'data',
8
+ 'Customer Management': 'crm',
9
+ 'Creative & Design': 'creative',
10
+ };
11
+
12
+ const AGENT_FOR_LANE = {
13
+ fullstack: 'orchestrator',
14
+ cms: 'cms',
15
+ data: 'data',
16
+ crm: 'crm',
17
+ creative: 'creative',
18
+ };
19
+
20
+ function write(file, content) {
21
+ fs.mkdirSync(path.dirname(file), { recursive: true });
22
+ fs.writeFileSync(file, content.trimStart());
23
+ }
24
+
25
+ function slugify(value) {
26
+ return String(value || 'agentsam-project')
27
+ .trim()
28
+ .toLowerCase()
29
+ .replace(/[^a-z0-9-]+/g, '-')
30
+ .replace(/^-+|-+$/g, '') || 'agentsam-project';
31
+ }
32
+
33
+ function workerTemplate({ projectName, laneKey, agent }) {
34
+ return `
35
+ import { AgentSam } from '@inneranimalmedia/agentsam-sdk';
36
+
37
+ export default {
38
+ async fetch(request, env, ctx) {
39
+ const agent = new AgentSam({
40
+ env,
41
+ ctx,
42
+ project: '${projectName}',
43
+ lane: '${laneKey}',
44
+ agent: '${agent}',
45
+ });
46
+
47
+ return agent.handle(request);
48
+ },
49
+ };
50
+ `;
51
+ }
52
+
53
+ function migrationTemplate({ projectName, laneKey }) {
54
+ return `
55
+ -- AgentSam core schema for ${projectName}
56
+ CREATE TABLE IF NOT EXISTS agent_sessions (
57
+ id TEXT PRIMARY KEY,
58
+ agent TEXT NOT NULL,
59
+ lane TEXT NOT NULL,
60
+ goal TEXT,
61
+ status TEXT NOT NULL DEFAULT 'created',
62
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
63
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
64
+ );
65
+
66
+ CREATE TABLE IF NOT EXISTS agent_messages (
67
+ id TEXT PRIMARY KEY,
68
+ session_id TEXT NOT NULL,
69
+ role TEXT NOT NULL,
70
+ content TEXT NOT NULL,
71
+ metadata_json TEXT,
72
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
73
+ FOREIGN KEY (session_id) REFERENCES agent_sessions(id)
74
+ );
75
+
76
+ CREATE TABLE IF NOT EXISTS agent_tool_calls (
77
+ id TEXT PRIMARY KEY,
78
+ session_id TEXT NOT NULL,
79
+ tool_name TEXT NOT NULL,
80
+ status TEXT NOT NULL DEFAULT 'queued',
81
+ input_json TEXT,
82
+ output_json TEXT,
83
+ requires_approval INTEGER NOT NULL DEFAULT 0,
84
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
85
+ completed_at TEXT,
86
+ FOREIGN KEY (session_id) REFERENCES agent_sessions(id)
87
+ );
88
+
89
+ ${laneKey === 'cms' ? `
90
+ CREATE TABLE IF NOT EXISTS cms_pages (
91
+ id TEXT PRIMARY KEY,
92
+ slug TEXT NOT NULL UNIQUE,
93
+ title TEXT NOT NULL,
94
+ status TEXT NOT NULL DEFAULT 'draft',
95
+ hero_asset_key TEXT,
96
+ content_json TEXT NOT NULL DEFAULT '{}',
97
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
98
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
99
+ );
100
+
101
+ CREATE TABLE IF NOT EXISTS cms_assets (
102
+ id TEXT PRIMARY KEY,
103
+ r2_key TEXT NOT NULL UNIQUE,
104
+ title TEXT,
105
+ alt_text TEXT,
106
+ metadata_json TEXT,
107
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
108
+ );
109
+ ` : ''}
110
+ `;
111
+ }
112
+
113
+ function readmeTemplate({ projectName, lane, provider, agent }) {
114
+ return `
115
+ # ${projectName}
116
+
117
+ Scaffolded with [@inneranimalmedia/agentsam-sdk](https://www.npmjs.com/package/@inneranimalmedia/agentsam-sdk).
118
+
119
+ ## Lane
120
+
121
+ **${lane}** — ${agent} agent, ${provider}
122
+
123
+ ## Setup
124
+
125
+ \`\`\`bash
126
+ cp .env.example .env
127
+ npm install
128
+ \`\`\`
129
+
130
+ ## Dev
131
+
132
+ \`\`\`bash
133
+ npm run dev
134
+ npm run smoke
135
+ \`\`\`
136
+
137
+ ## Deploy
138
+
139
+ \`\`\`bash
140
+ npm run deploy
141
+ \`\`\`
142
+
143
+ ## Endpoints
144
+
145
+ - \`GET /api/health\`
146
+ - \`GET /api/agentsam/info\`
147
+ - \`POST /api/agentsam/session\`
148
+ - \`POST /api/agentsam/message\`
149
+ `;
150
+ }
151
+
152
+ export function scaffoldProject({
153
+ projectName,
154
+ lane,
155
+ provider,
156
+ agent,
157
+ cfAccountId,
158
+ sdkVersion = '1.1.1',
159
+ }) {
160
+ const safeName = slugify(projectName);
161
+ const dir = path.resolve(process.cwd(), safeName);
162
+ const laneKey = LANE_KEYS[lane] ?? 'fullstack';
163
+ const selectedAgent = agent || AGENT_FOR_LANE[laneKey] || 'orchestrator';
164
+ const sdkRange = `^${sdkVersion.split('.').slice(0, 2).join('.')}.0`;
165
+
166
+ if (fs.existsSync(dir)) {
167
+ throw new Error(`Directory "${safeName}" already exists.`);
168
+ }
169
+
170
+ fs.mkdirSync(dir, { recursive: true });
171
+ fs.mkdirSync(`${dir}/src`, { recursive: true });
172
+ fs.mkdirSync(`${dir}/migrations`, { recursive: true });
173
+
174
+ write(`${dir}/agentsam.config.js`, `
175
+ export default {
176
+ project: '${safeName}',
177
+ lane: '${laneKey}',
178
+ provider: '${provider}',
179
+ agent: '${selectedAgent}',
180
+ cloudflare: {
181
+ accountId: '${cfAccountId || ''}',
182
+ },
183
+ api: {
184
+ baseUrl: '/api/agentsam',
185
+ },
186
+ };
187
+ `);
188
+
189
+ write(`${dir}/.env.example`, `
190
+ AGENTSAM_API_KEY=
191
+ CLOUDFLARE_ACCOUNT_ID=${cfAccountId || ''}
192
+ CLOUDFLARE_API_TOKEN=
193
+ `);
194
+
195
+ write(`${dir}/.gitignore`, `
196
+ node_modules/
197
+ .env
198
+ .dev.vars
199
+ dist/
200
+ .wrangler/
201
+ `);
202
+
203
+ write(`${dir}/package.json`, `${JSON.stringify({
204
+ name: safeName,
205
+ version: '0.1.0',
206
+ type: 'module',
207
+ private: true,
208
+ scripts: {
209
+ dev: 'wrangler dev',
210
+ deploy: 'wrangler deploy',
211
+ smoke: 'node ./scripts/smoke.mjs',
212
+ },
213
+ dependencies: {
214
+ '@inneranimalmedia/agentsam-sdk': sdkRange,
215
+ },
216
+ devDependencies: {
217
+ wrangler: '^4.0.0',
218
+ },
219
+ }, null, 2)}\n`);
220
+
221
+ write(`${dir}/wrangler.toml`, `
222
+ name = "${safeName}"
223
+ main = "src/index.js"
224
+ compatibility_date = "2026-06-27"
225
+
226
+ [[d1_databases]]
227
+ binding = "DB"
228
+ database_name = "${safeName}-db"
229
+ database_id = "REPLACE_WITH_D1_DATABASE_ID"
230
+
231
+ [[kv_namespaces]]
232
+ binding = "KV"
233
+ id = "REPLACE_WITH_KV_NAMESPACE_ID"
234
+
235
+ [[r2_buckets]]
236
+ binding = "R2"
237
+ bucket_name = "${safeName}"
238
+ `);
239
+
240
+ write(`${dir}/migrations/0001_agentsam_core.sql`, migrationTemplate({ projectName: safeName, laneKey }));
241
+ write(`${dir}/src/index.js`, workerTemplate({ projectName: safeName, laneKey, agent: selectedAgent }));
242
+ write(`${dir}/README.md`, readmeTemplate({ projectName: safeName, lane, provider, agent: selectedAgent }));
243
+
244
+ write(`${dir}/scripts/smoke.mjs`, `
245
+ import { AgentSam } from '@inneranimalmedia/agentsam-sdk';
246
+
247
+ const app = new AgentSam({ project: '${safeName}', lane: '${laneKey}', agent: '${selectedAgent}' });
248
+ const res = await app.handle(new Request('https://example.com/api/health'));
249
+ const data = await res.json();
250
+
251
+ if (!data.ok) {
252
+ console.error(data);
253
+ process.exit(1);
254
+ }
255
+
256
+ console.log('AgentSam smoke test passed:', data);
257
+ `);
258
+
259
+ return dir;
260
+ }
@@ -0,0 +1,53 @@
1
+ export async function createSession({ env, agent, lane, goal }) {
2
+ const now = new Date().toISOString();
3
+ const session = {
4
+ id: crypto.randomUUID(),
5
+ agent,
6
+ lane,
7
+ goal: goal ?? null,
8
+ status: 'created',
9
+ created_at: now,
10
+ updated_at: now,
11
+ };
12
+
13
+ if (env?.KV?.put) {
14
+ await env.KV.put(`agentsam:session:${session.id}`, JSON.stringify(session), { expirationTtl: 60 * 60 * 24 * 7 });
15
+ }
16
+
17
+ if (env?.DB?.prepare) {
18
+ await env.DB.prepare(
19
+ `CREATE TABLE IF NOT EXISTS agent_sessions (
20
+ id TEXT PRIMARY KEY,
21
+ agent TEXT NOT NULL,
22
+ lane TEXT NOT NULL,
23
+ goal TEXT,
24
+ status TEXT NOT NULL,
25
+ created_at TEXT NOT NULL,
26
+ updated_at TEXT NOT NULL
27
+ )`
28
+ ).run();
29
+
30
+ await env.DB.prepare(
31
+ `INSERT INTO agent_sessions (id, agent, lane, goal, status, created_at, updated_at)
32
+ VALUES (?, ?, ?, ?, ?, ?, ?)`
33
+ ).bind(session.id, session.agent, session.lane, session.goal, session.status, session.created_at, session.updated_at).run();
34
+ }
35
+
36
+ return session;
37
+ }
38
+
39
+ export async function getSession({ env, sessionId }) {
40
+ if (!sessionId) return null;
41
+
42
+ if (env?.KV?.get) {
43
+ const raw = await env.KV.get(`agentsam:session:${sessionId}`);
44
+ if (raw) return JSON.parse(raw);
45
+ }
46
+
47
+ if (env?.DB?.prepare) {
48
+ const row = await env.DB.prepare('SELECT * FROM agent_sessions WHERE id = ?').bind(sessionId).first();
49
+ if (row) return row;
50
+ }
51
+
52
+ return null;
53
+ }
@@ -0,0 +1,38 @@
1
+ const CATALOG = {
2
+ fullstack: [
3
+ { name: 'plan', description: 'Break a goal into implementation steps.' },
4
+ { name: 'code', description: 'Generate or revise application code.' },
5
+ { name: 'deploy', description: 'Prepare deployment steps and checks.' },
6
+ ],
7
+ cms: [
8
+ { name: 'page', description: 'Create and revise pages.' },
9
+ { name: 'asset', description: 'Attach cover images and media.' },
10
+ { name: 'publish', description: 'Draft, preview, and publish content.' },
11
+ ],
12
+ data: [
13
+ { name: 'schema', description: 'Inspect and plan database schemas.' },
14
+ { name: 'query', description: 'Draft safe SQL queries.' },
15
+ { name: 'migration', description: 'Plan D1 or Postgres migrations.' },
16
+ ],
17
+ crm: [
18
+ { name: 'contact', description: 'Organize contacts and accounts.' },
19
+ { name: 'workflow', description: 'Coordinate customer workflows.' },
20
+ ],
21
+ creative: [
22
+ { name: 'brief', description: 'Turn creative intent into a production brief.' },
23
+ { name: 'asset', description: 'Plan media, 3D, and design assets.' },
24
+ ],
25
+ };
26
+
27
+ export function normalizeLane(lane = 'fullstack') {
28
+ return String(lane).toLowerCase().replace(/\s+/g, '').replace('&', '');
29
+ }
30
+
31
+ export function getToolCatalog(lane = 'fullstack') {
32
+ const key = normalizeLane(lane);
33
+ if (key.includes('cms')) return CATALOG.cms;
34
+ if (key.includes('data')) return CATALOG.data;
35
+ if (key.includes('customer') || key.includes('crm')) return CATALOG.crm;
36
+ if (key.includes('creative') || key.includes('design')) return CATALOG.creative;
37
+ return CATALOG.fullstack;
38
+ }
@@ -0,0 +1,2 @@
1
+ export const LANES = ['fullstack', 'cms', 'data', 'crm', 'creative'];
2
+ export const AGENTS = ['orchestrator', 'cms', 'data', 'crm', 'creative'];
package/test/smoke.mjs ADDED
@@ -0,0 +1,38 @@
1
+ import assert from 'node:assert/strict';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { AgentSam, routeIntent, getToolCatalog } from '../src/index.js';
6
+ import { scaffoldProject } from '../src/lib/scaffold.js';
7
+
8
+ const app = new AgentSam({ project: 'smoke', lane: 'cms', agent: 'cms' });
9
+ let res = await app.handle(new Request('https://example.com/api/health'));
10
+ assert.equal(res.status, 200);
11
+ assert.equal((await res.json()).ok, true);
12
+
13
+ res = await app.handle(new Request('https://example.com/api/agentsam/info'));
14
+ const info = await res.json();
15
+ assert.equal(info.agent, 'cms');
16
+ assert.ok(info.capabilities.includes('page'));
17
+
18
+ res = await app.handle(new Request('https://example.com/api/agentsam/message', {
19
+ method: 'POST',
20
+ body: JSON.stringify({ message: 'create an analytics page in the cms' }),
21
+ }));
22
+ const message = await res.json();
23
+ assert.equal(message.agent, 'cms');
24
+ assert.equal(message.intent, 'cms_build');
25
+
26
+ assert.equal(routeIntent({ message: 'drop table users' }).requires_approval, true);
27
+ assert.ok(getToolCatalog('Data Solutions').some((tool) => tool.name === 'query'));
28
+
29
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'agentsam-sdk-test-'));
30
+ const cwd = process.cwd();
31
+ process.chdir(tmp);
32
+ const dir = scaffoldProject({ projectName: 'CMS Demo', lane: 'CMS', provider: 'Cloudflare Workers', agent: 'cms' });
33
+ process.chdir(cwd);
34
+ assert.ok(fs.existsSync(path.join(dir, 'src/index.js')));
35
+ assert.ok(fs.readFileSync(path.join(dir, 'migrations/0001_agentsam_core.sql'), 'utf8').includes('cms_pages'));
36
+ assert.ok(fs.readFileSync(path.join(dir, 'package.json'), 'utf8').includes('wrangler'));
37
+
38
+ console.log('SDK smoke tests passed');