@inneranimalmedia/agentsam-sdk 1.1.0 → 1.2.0
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 +58 -0
- package/LICENSE +21 -0
- package/README.md +202 -0
- package/docs/CLI_SHELL.md +90 -0
- package/examples/gorilla-shell/App.tsx +540 -0
- package/examples/gorilla-shell/README.md +22 -0
- package/examples/gorilla-shell/index.html +15 -0
- package/examples/gorilla-shell/main.jsx +9 -0
- package/examples/gorilla-shell/package.json +19 -0
- package/examples/gorilla-shell/vite.config.js +10 -0
- package/package.json +24 -3
- package/src/AgentSam.js +67 -0
- package/src/cli.js +232 -56
- package/src/index.js +16 -4
- package/src/lib/responses.js +21 -0
- package/src/lib/router.js +51 -0
- package/src/lib/scaffold.js +208 -110
- package/src/lib/sessions.js +53 -0
- package/src/lib/slash-commands.js +40 -0
- package/src/lib/tools.js +38 -0
- package/src/schemas/config.js +2 -0
- package/test/smoke.mjs +42 -0
package/src/lib/scaffold.js
CHANGED
|
@@ -1,162 +1,260 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
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`;
|
|
6
165
|
|
|
7
166
|
if (fs.existsSync(dir)) {
|
|
8
|
-
|
|
9
|
-
process.exit(1);
|
|
167
|
+
throw new Error(`Directory "${safeName}" already exists.`);
|
|
10
168
|
}
|
|
11
169
|
|
|
12
170
|
fs.mkdirSync(dir, { recursive: true });
|
|
13
171
|
fs.mkdirSync(`${dir}/src`, { recursive: true });
|
|
172
|
+
fs.mkdirSync(`${dir}/migrations`, { recursive: true });
|
|
14
173
|
|
|
15
|
-
|
|
16
|
-
fs.writeFileSync(`${dir}/agentsam.config.js`, `
|
|
174
|
+
write(`${dir}/agentsam.config.js`, `
|
|
17
175
|
export default {
|
|
18
|
-
project: '${
|
|
19
|
-
lane: '${
|
|
176
|
+
project: '${safeName}',
|
|
177
|
+
lane: '${laneKey}',
|
|
20
178
|
provider: '${provider}',
|
|
21
|
-
agent: '${
|
|
179
|
+
agent: '${selectedAgent}',
|
|
22
180
|
cloudflare: {
|
|
23
181
|
accountId: '${cfAccountId || ''}',
|
|
24
182
|
},
|
|
25
183
|
api: {
|
|
26
|
-
baseUrl: '
|
|
184
|
+
baseUrl: '/api/agentsam',
|
|
27
185
|
},
|
|
28
186
|
};
|
|
29
|
-
|
|
187
|
+
`);
|
|
30
188
|
|
|
31
|
-
|
|
32
|
-
fs.writeFileSync(`${dir}/.env.example`, `
|
|
189
|
+
write(`${dir}/.env.example`, `
|
|
33
190
|
AGENTSAM_API_KEY=
|
|
34
191
|
CLOUDFLARE_ACCOUNT_ID=${cfAccountId || ''}
|
|
35
192
|
CLOUDFLARE_API_TOKEN=
|
|
36
|
-
|
|
193
|
+
`);
|
|
37
194
|
|
|
38
|
-
|
|
39
|
-
fs.writeFileSync(`${dir}/.gitignore`, `
|
|
195
|
+
write(`${dir}/.gitignore`, `
|
|
40
196
|
node_modules/
|
|
41
197
|
.env
|
|
42
198
|
.dev.vars
|
|
43
199
|
dist/
|
|
44
|
-
|
|
200
|
+
.wrangler/
|
|
201
|
+
`);
|
|
45
202
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
name: projectName,
|
|
203
|
+
write(`${dir}/package.json`, `${JSON.stringify({
|
|
204
|
+
name: safeName,
|
|
49
205
|
version: '0.1.0',
|
|
50
206
|
type: 'module',
|
|
207
|
+
private: true,
|
|
51
208
|
scripts: {
|
|
52
209
|
dev: 'wrangler dev',
|
|
53
210
|
deploy: 'wrangler deploy',
|
|
211
|
+
smoke: 'node ./scripts/smoke.mjs',
|
|
54
212
|
},
|
|
55
213
|
dependencies: {
|
|
56
|
-
'@inneranimalmedia/agentsam-sdk':
|
|
214
|
+
'@inneranimalmedia/agentsam-sdk': sdkRange,
|
|
57
215
|
},
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
fs.mkdirSync(`${dir}/migrations`, { recursive: true });
|
|
63
|
-
fs.writeFileSync(`${dir}/migrations/0001_init.sql`, `
|
|
64
|
-
-- Initial schema for ${projectName}
|
|
65
|
-
CREATE TABLE IF NOT EXISTS agent_sessions (
|
|
66
|
-
id TEXT PRIMARY KEY,
|
|
67
|
-
user_id TEXT NOT NULL,
|
|
68
|
-
created_at INTEGER DEFAULT (unixepoch())
|
|
69
|
-
);
|
|
70
|
-
`.trimStart());
|
|
71
|
-
}
|
|
216
|
+
devDependencies: {
|
|
217
|
+
wrangler: '^4.0.0',
|
|
218
|
+
},
|
|
219
|
+
}, null, 2)}\n`);
|
|
72
220
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
name = "${projectName}"
|
|
221
|
+
write(`${dir}/wrangler.toml`, `
|
|
222
|
+
name = "${safeName}"
|
|
76
223
|
main = "src/index.js"
|
|
77
|
-
compatibility_date = "
|
|
224
|
+
compatibility_date = "2026-06-27"
|
|
78
225
|
|
|
79
226
|
[[d1_databases]]
|
|
80
227
|
binding = "DB"
|
|
81
|
-
database_name = "${
|
|
82
|
-
database_id = ""
|
|
83
|
-
`.trimStart());
|
|
84
|
-
}
|
|
228
|
+
database_name = "${safeName}-db"
|
|
229
|
+
database_id = "REPLACE_WITH_D1_DATABASE_ID"
|
|
85
230
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
import { AgentSam } from '@inneranimalmedia/agentsam-sdk';
|
|
231
|
+
[[kv_namespaces]]
|
|
232
|
+
binding = "KV"
|
|
233
|
+
id = "REPLACE_WITH_KV_NAMESPACE_ID"
|
|
90
234
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
},
|
|
96
|
-
};
|
|
97
|
-
`,
|
|
98
|
-
'Data Solutions': `
|
|
99
|
-
import { AgentSam } from '@inneranimalmedia/agentsam-sdk';
|
|
235
|
+
[[r2_buckets]]
|
|
236
|
+
binding = "R2"
|
|
237
|
+
bucket_name = "${safeName}"
|
|
238
|
+
`);
|
|
100
239
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
return agent.handle(request);
|
|
105
|
-
},
|
|
106
|
-
};
|
|
107
|
-
`,
|
|
108
|
-
'Customer Management': `
|
|
109
|
-
import { AgentSam } from '@inneranimalmedia/agentsam-sdk';
|
|
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 }));
|
|
110
243
|
|
|
111
|
-
|
|
112
|
-
async fetch(request, env, ctx) {
|
|
113
|
-
const agent = new AgentSam({ env, agent: 'crm' });
|
|
114
|
-
return agent.handle(request);
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
`,
|
|
118
|
-
'Creative & Design': `
|
|
244
|
+
write(`${dir}/scripts/smoke.mjs`, `
|
|
119
245
|
import { AgentSam } from '@inneranimalmedia/agentsam-sdk';
|
|
120
246
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
return agent.handle(request);
|
|
125
|
-
},
|
|
126
|
-
};
|
|
127
|
-
`,
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
fs.writeFileSync(`${dir}/src/index.js`, workers[lane].trimStart());
|
|
131
|
-
|
|
132
|
-
// README
|
|
133
|
-
fs.writeFileSync(`${dir}/README.md`, `
|
|
134
|
-
# ${projectName}
|
|
135
|
-
|
|
136
|
-
Scaffolded with [Agent Sam SDK](https://www.npmjs.com/package/@inneranimalmedia/agentsam-sdk).
|
|
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();
|
|
137
250
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
\`\`\`bash
|
|
144
|
-
cp .env.example .env
|
|
145
|
-
npm install
|
|
146
|
-
\`\`\`
|
|
147
|
-
|
|
148
|
-
## Dev
|
|
149
|
-
|
|
150
|
-
\`\`\`bash
|
|
151
|
-
npm run dev
|
|
152
|
-
\`\`\`
|
|
153
|
-
|
|
154
|
-
## Deploy
|
|
251
|
+
if (!data.ok) {
|
|
252
|
+
console.error(data);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
155
255
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
\`\`\`
|
|
159
|
-
`.trimStart());
|
|
256
|
+
console.log('AgentSam smoke test passed:', data);
|
|
257
|
+
`);
|
|
160
258
|
|
|
161
259
|
return dir;
|
|
162
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,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical slash-command surface for Agent Sam SDK CLI / shell UX.
|
|
3
|
+
* Consumed by the gorilla-shell example and future `agentsam shell` PTY bridge.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const SHELL_THEMES = ['NIGHT', 'DAY', 'LAVA', 'VOID'];
|
|
7
|
+
|
|
8
|
+
/** @type {Array<{ cmd: string, description: string, lane?: string }>} */
|
|
9
|
+
export const SLASH_COMMANDS = [
|
|
10
|
+
{ cmd: '/cd', description: 'Change working directory', lane: 'terminal' },
|
|
11
|
+
{ cmd: '/pwd', description: 'Print working directory', lane: 'terminal' },
|
|
12
|
+
{ cmd: '/gh', description: 'GitHub operations (status, PR, issue)', lane: 'git' },
|
|
13
|
+
{ cmd: '/wrangler', description: 'Wrangler deploy and bindings', lane: 'deploy' },
|
|
14
|
+
{ cmd: '/workspace', description: 'Switch or show active workspace', lane: 'platform' },
|
|
15
|
+
{ cmd: '/samiam', description: 'Agent Sam quick invoke', lane: 'agent' },
|
|
16
|
+
{ cmd: '/claude', description: 'Route prompt to Claude arm', lane: 'agent' },
|
|
17
|
+
{ cmd: '/codex', description: 'Route prompt to Codex arm', lane: 'agent' },
|
|
18
|
+
{ cmd: '/tail', description: 'Tail worker logs', lane: 'observability' },
|
|
19
|
+
{ cmd: '/d1', description: 'D1 query helper', lane: 'data' },
|
|
20
|
+
{ cmd: '/deploy', description: 'Deploy worker (sandbox or prod gate)', lane: 'deploy' },
|
|
21
|
+
{ cmd: '/buddy', description: 'Open Agent Sam buddy panel (MCP)', lane: 'agent' },
|
|
22
|
+
{ cmd: '/status', description: 'Platform + project health', lane: 'platform' },
|
|
23
|
+
{ cmd: '/diagnostics', description: 'Run diagnostic scenario', lane: 'platform' },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/** Shell UX rollout phases (gorilla-shell → SDK default CLI experience). */
|
|
27
|
+
export const SHELL_PHASES = [
|
|
28
|
+
{ id: '0-prototype', label: 'Visual prototype + demo scenarios', status: 'complete' },
|
|
29
|
+
{ id: 'pty-connection', label: 'ExecOS / iam-pty WebSocket bridge', status: 'next' },
|
|
30
|
+
{ id: 'hud-layer', label: 'Quest log, tool gate, XP HUD', status: 'planned' },
|
|
31
|
+
{ id: 'buddy-system', label: 'In-shell Agent Sam via MCP', status: 'planned' },
|
|
32
|
+
{ id: 'dashboard-embed', label: 'Embeddable shell for IAM dashboard', status: 'planned' },
|
|
33
|
+
{ id: 'standalone-pwa', label: 'Installable PWA / SDK default shell', status: 'planned' },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
export function listSlashCommands(opts = {}) {
|
|
37
|
+
const lane = opts.lane ? String(opts.lane).trim().toLowerCase() : '';
|
|
38
|
+
if (!lane) return [...SLASH_COMMANDS];
|
|
39
|
+
return SLASH_COMMANDS.filter((row) => !row.lane || row.lane === lane);
|
|
40
|
+
}
|
package/src/lib/tools.js
ADDED
|
@@ -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
|
+
}
|
package/test/smoke.mjs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
import { SLASH_COMMANDS, listSlashCommands } from '../src/lib/slash-commands.js';
|
|
39
|
+
assert.ok(SLASH_COMMANDS.some((c) => c.cmd === '/deploy'));
|
|
40
|
+
assert.equal(listSlashCommands({ lane: 'deploy' }).length, 2);
|
|
41
|
+
|
|
42
|
+
console.log('SDK smoke tests passed');
|