@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
|
@@ -0,0 +1,540 @@
|
|
|
1
|
+
import { useState, useEffect, useRef, useMemo, useCallback } from "react";
|
|
2
|
+
|
|
3
|
+
const PS = 5;
|
|
4
|
+
const PAL = ['transparent','#060e1a','#0f2040','#1a3568','#6a6a90','#9898b8','#2a1006','#8a5830','#ff1a1a','#ffd88a','#0e0400','#ffffff','#ffd700','#ffaa00','#ff6600','#ff2200','#9B6E14','#6B4808','#3a2604','#c09030','#ffee44','#cc8800','#44ff88','#ff4444'];
|
|
5
|
+
|
|
6
|
+
const GORILLA = [
|
|
7
|
+
[0,0,0,2,2,2,2,2,2,2,2,2,2,2,0,0,0,0],
|
|
8
|
+
[0,0,2,3,3,3,3,3,3,3,3,3,3,2,2,0,0,0],
|
|
9
|
+
[0,2,2,3,3,3,3,3,3,3,3,3,3,3,2,2,0,0],
|
|
10
|
+
[0,2,3,3,7,7,3,3,3,7,7,3,3,3,2,0,0,0],
|
|
11
|
+
[2,2,3,7,7,8,7,3,3,7,8,7,7,3,3,2,2,0],
|
|
12
|
+
[2,2,3,7,7,7,7,7,7,7,7,7,7,3,3,2,2,0],
|
|
13
|
+
[2,3,3,7,6,10,6,7,7,6,10,6,7,3,3,3,2,0],
|
|
14
|
+
[2,3,3,7,7,7,9,9,9,9,7,7,7,3,3,3,2,0],
|
|
15
|
+
[0,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,0],
|
|
16
|
+
[0,2,2,3,4,4,4,4,4,4,4,4,4,3,2,2,0,0],
|
|
17
|
+
[2,2,2,3,4,5,5,5,5,5,5,5,4,3,3,2,2,2],
|
|
18
|
+
[2,3,2,3,4,5,5,5,5,5,5,5,4,3,2,3,2,2],
|
|
19
|
+
[2,3,3,3,3,4,4,5,5,4,4,3,3,3,3,3,2,0],
|
|
20
|
+
[0,2,3,3,3,3,3,3,3,3,3,3,3,3,2,2,0,0],
|
|
21
|
+
[0,0,2,3,3,3,3,3,3,3,3,3,3,2,2,0,0,0],
|
|
22
|
+
[0,0,2,2,3,3,3,3,3,3,3,3,2,2,0,0,0,0],
|
|
23
|
+
[0,0,0,2,2,3,3,0,0,3,3,2,2,0,0,0,0,0],
|
|
24
|
+
[0,0,0,2,2,2,2,0,0,2,2,2,2,0,0,0,0,0],
|
|
25
|
+
[0,0,0,0,2,2,2,0,0,2,2,2,0,0,0,0,0,0],
|
|
26
|
+
[0,0,0,0,2,3,2,0,0,2,3,2,0,0,0,0,0,0],
|
|
27
|
+
];
|
|
28
|
+
const GORILLA_PUMP = GORILLA.map((r,i) => {
|
|
29
|
+
if (i===8) return [2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,0];
|
|
30
|
+
if (i===9) return [2,2,3,4,5,5,5,5,5,5,5,5,5,4,3,2,2,0];
|
|
31
|
+
if (i===10) return [0,2,3,4,5,5,5,5,5,5,5,5,5,4,3,2,0,0];
|
|
32
|
+
if (i===11) return [0,2,3,3,4,5,5,5,5,5,5,5,4,3,3,2,0,0];
|
|
33
|
+
return r;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const COIN = [[0,12,12,12,12,12,0],[12,20,20,20,20,20,12],[12,20,12,20,12,20,12],[12,20,20,20,20,20,12],[0,12,12,12,12,12,0],[0,0,21,21,0,0,0]];
|
|
37
|
+
const FLAME_FRAMES = [
|
|
38
|
+
[[0,0,14,0,0],[0,14,15,14,0],[14,15,13,14,0],[14,13,20,14,0],[0,14,13,14,0],[0,13,14,13,0]],
|
|
39
|
+
[[0,14,0,14,0],[14,15,14,0,0],[14,13,15,14,0],[0,14,13,14,0],[0,13,14,0,0],[0,14,13,0,0]],
|
|
40
|
+
[[0,14,14,0,0],[0,14,15,14,0],[14,15,13,15,0],[14,13,14,13,0],[0,14,13,14,0],[0,0,14,13,0]],
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const THEMES = {
|
|
44
|
+
NIGHT: { bg:'#030a14', panel:'rgba(4,12,26,.97)', accent:'#00e5ff', dim:'#00e5ff22', glow:'0 0 14px #00e5ff55', border:'#00e5ff33' },
|
|
45
|
+
DAY: { bg:'#071a0a', panel:'rgba(6,20,10,.97)', accent:'#44ff88', dim:'#44ff8822', glow:'0 0 14px #44ff8855', border:'#44ff8833' },
|
|
46
|
+
LAVA: { bg:'#0e0003', panel:'rgba(18,2,4,.97)', accent:'#ff4400', dim:'#ff440022', glow:'0 0 14px #ff440055', border:'#ff440033' },
|
|
47
|
+
VOID: { bg:'#06001a', panel:'rgba(8,2,28,.97)', accent:'#aa44ff', dim:'#aa44ff22', glow:'0 0 14px #aa44ff55', border:'#aa44ff33' },
|
|
48
|
+
};
|
|
49
|
+
const TKEYS = Object.keys(THEMES);
|
|
50
|
+
|
|
51
|
+
// ── Line colors ───────────────────────────────────────────────────────────────
|
|
52
|
+
const LC = {
|
|
53
|
+
cmd: '#00e5ff',
|
|
54
|
+
success: '#44ff88',
|
|
55
|
+
error: '#ff4444',
|
|
56
|
+
warn: '#ffcc00',
|
|
57
|
+
info: '#88bbff',
|
|
58
|
+
muted: 'rgba(255,255,255,.45)',
|
|
59
|
+
dim: 'rgba(255,255,255,.18)',
|
|
60
|
+
white: 'rgba(255,255,255,.9)',
|
|
61
|
+
sam: '#cc88ff',
|
|
62
|
+
table: '#ffdd88',
|
|
63
|
+
pass: '#44ff88',
|
|
64
|
+
fail: '#ff4444',
|
|
65
|
+
accent: '#00e5ff',
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// ── Scenario Builders ─────────────────────────────────────────────────────────
|
|
69
|
+
const BENCH_TESTS = [
|
|
70
|
+
['health_check',13],['auth_superadmin',8],['auth_regular',9],['d1_query_basic',45],
|
|
71
|
+
['d1_query_join',67],['d1_write_record',38],['mcp_tool_routing',23],['mcp_auth_bearer',11],
|
|
72
|
+
['mcp_audit_log',19],['agent_context_load',88],['r2_upload_asset',54],['r2_fetch_asset',31],
|
|
73
|
+
['kv_read_hit',7],['kv_write_ttl',14],['queue_publish',28],['worker_ai_t0',112],
|
|
74
|
+
['gemini_flash_lite',189],['haiku_route',145],['sonnet_route',234],['budget_check',6],
|
|
75
|
+
['cicd_sandbox_gate',17],['cicd_benchmark_gate',22],['deploy_record_insert',33],
|
|
76
|
+
['workspace_switch',12],['terminal_session_resume',19],['rag_cosine_query',78],
|
|
77
|
+
['tool_intent_match',15],['client_workflow_run',44],['project_context_load',29],
|
|
78
|
+
['skill_lookup',11],['cicd_pipeline_e2e',156],
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
function buildDeploy() {
|
|
82
|
+
let d = 0; const L = (text, color, gap=120) => { d+=gap; return {text,color,delay:d}; };
|
|
83
|
+
return [
|
|
84
|
+
L('gorilla@inneranimal ~ % /deploy sandbox','cmd',0),
|
|
85
|
+
L('','dim',60),
|
|
86
|
+
L(' ./scripts/with-cloudflare-env.sh npx wrangler deploy','muted',80),
|
|
87
|
+
L(' –config wrangler.sandbox.toml','muted',40),
|
|
88
|
+
L('','dim',80),
|
|
89
|
+
L(' Bundling worker…','muted',300),
|
|
90
|
+
L(' esbuild: scanning 847 modules…','muted',500),
|
|
91
|
+
L(' Tree-shaking complete: 284kb','muted',400),
|
|
92
|
+
L(' Build time: 1.24s','muted',200),
|
|
93
|
+
L('','dim',80),
|
|
94
|
+
L(' Uploading script…','muted',350),
|
|
95
|
+
L('','dim',60),
|
|
96
|
+
L(' Worker inneranimal-dashboard','info',200),
|
|
97
|
+
L(' Compat date 2026-04-08','info',60),
|
|
98
|
+
L(' D1 binding inneranimalmedia-business [cf87b717]','info',60),
|
|
99
|
+
L(' R2 binding agent-sam-sandbox-cicd','info',60),
|
|
100
|
+
L(' KV binding IAM_KV, RATE_LIMIT_KV','info',60),
|
|
101
|
+
L(' Queues DEPLOY_QUEUE, AGENT_QUEUE','info',60),
|
|
102
|
+
L('','dim',80),
|
|
103
|
+
L(' Routing table:','muted',200),
|
|
104
|
+
L(' dashboard.inneranimalmedia.com /* -> inneranimal-dashboard','dim',60),
|
|
105
|
+
L('','dim',80),
|
|
106
|
+
L(' [OK] Deployed successfully 3.41s','success',400),
|
|
107
|
+
L(' >> https://inneranimal-dashboard.samprimeaux.workers.dev','accent',80),
|
|
108
|
+
L('','dim',100),
|
|
109
|
+
L(' Next: run /benchmark to proceed to prod','warn',200),
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function buildBenchmark() {
|
|
114
|
+
let d = 0; const L = (text, color, gap=80) => { d+=gap; return {text,color,delay:d}; };
|
|
115
|
+
const lines = [
|
|
116
|
+
L('gorilla@inneranimal ~ % /benchmark','cmd',0),
|
|
117
|
+
L('','dim',60),
|
|
118
|
+
L(' Running 31 tests against inneranimal-dashboard…','muted',200),
|
|
119
|
+
L('','dim',60),
|
|
120
|
+
];
|
|
121
|
+
BENCH_TESTS.forEach(([name, ms], i) => {
|
|
122
|
+
const num = String(i+1).padStart(2,'0');
|
|
123
|
+
const dots = '.'.repeat(Math.max(2, 36 - name.length));
|
|
124
|
+
lines.push(L(` [${num}/31] ${name} ${dots} PASS ${ms}ms`,'pass',75));
|
|
125
|
+
});
|
|
126
|
+
lines.push(L('','dim',100));
|
|
127
|
+
lines.push(L(' '+'-'.repeat(52),'dim',100));
|
|
128
|
+
lines.push(L(' RESULTS 31 / 31 PASSED avg 47ms total 1.46s','success',200));
|
|
129
|
+
lines.push(L(' '+'-'.repeat(52),'dim',60));
|
|
130
|
+
lines.push(L('','dim',80));
|
|
131
|
+
lines.push(L(' [GATE PASSED] Cleared for production promote','success',300));
|
|
132
|
+
return lines;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function buildD1() {
|
|
136
|
+
let d = 0; const L = (text, color, gap=100) => { d+=gap; return {text,color,delay:d}; };
|
|
137
|
+
const SEP = ' +—————————+———+———————+';
|
|
138
|
+
const rows = [
|
|
139
|
+
['inneranimalmedia','success','2026-04-07 23:10:56'],
|
|
140
|
+
['inneranimal-dashboard','success','2026-04-07 22:55:15'],
|
|
141
|
+
['inneranimal-dashboard','success','2026-04-07 22:06:28'],
|
|
142
|
+
['inneranimalmedia','success','2026-04-06 18:32:11'],
|
|
143
|
+
['inneranimal-dashboard','error','2026-04-06 17:44:03'],
|
|
144
|
+
];
|
|
145
|
+
return [
|
|
146
|
+
L('gorilla@inneranimal ~ % /d1 SELECT name, status, created_at FROM deployments ORDER BY created_at DESC LIMIT 5','cmd',0),
|
|
147
|
+
L('','dim',60),
|
|
148
|
+
L(' DB: inneranimalmedia-business','muted',150),
|
|
149
|
+
L(' ID: cf87b717-d4e2-4cf8-bab0-a81268e32d49','dim',60),
|
|
150
|
+
L('','dim',100),
|
|
151
|
+
L(SEP,'table',200),
|
|
152
|
+
L(' | name | status | created_at |','table',60),
|
|
153
|
+
L(SEP,'table',60),
|
|
154
|
+
…rows.map(([n,s,t]) => L(
|
|
155
|
+
` | ${n.padEnd(25)} | ${s.padEnd(7)} | ${t} |`,
|
|
156
|
+
s==='error'?'error':'white', 90
|
|
157
|
+
)),
|
|
158
|
+
L(SEP,'table',90),
|
|
159
|
+
L(' 5 rows | 2ms','dim',100),
|
|
160
|
+
];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function buildTail() {
|
|
164
|
+
let d = 0; const L = (text, color, gap=280) => { d+=gap; return {text,color,delay:d}; };
|
|
165
|
+
const reqs = [
|
|
166
|
+
['GET ','/ ','200','14ms',''],
|
|
167
|
+
['POST','/api/agent/chat ','200','234ms',''],
|
|
168
|
+
['GET ','/api/workspace/status ','200','8ms',''],
|
|
169
|
+
['POST','/mcp ','200','45ms','[MCP]'],
|
|
170
|
+
['GET ','/api/deployments ','200','12ms',''],
|
|
171
|
+
['POST','/api/agent/chat ','200','891ms','[LLM]'],
|
|
172
|
+
['GET ','/health ','200','2ms',''],
|
|
173
|
+
['POST','/api/d1/query ','200','34ms',''],
|
|
174
|
+
['GET ','/api/workspace/list ','200','18ms',''],
|
|
175
|
+
['POST','/api/agent/chat ','500','12ms','[ERR]'],
|
|
176
|
+
];
|
|
177
|
+
const delays = [0,320,180,260,400,350,220,310,280,450];
|
|
178
|
+
return [
|
|
179
|
+
L('gorilla@inneranimal ~ % /tail inneranimalmedia','cmd',0),
|
|
180
|
+
L('','dim',60),
|
|
181
|
+
L(' npx wrangler tail inneranimalmedia –format pretty','muted',100),
|
|
182
|
+
L(' Streaming live logs… (CTRL+C to stop)','dim',300),
|
|
183
|
+
L('','dim',100),
|
|
184
|
+
…reqs.map(([m,p,s,t,tag],i) => L(
|
|
185
|
+
` [10:23:${41+i}] ${m} ${p.padEnd(30)}${s} ${t.padEnd(8)}${tag}`,
|
|
186
|
+
s==='500'?'error': tag==='[LLM]'?'warn': tag==='[MCP]'?'info': 'muted',
|
|
187
|
+
delays[i] || 300
|
|
188
|
+
)),
|
|
189
|
+
L('','dim',200),
|
|
190
|
+
L(' 1 error detected – POST /api/agent/chat returned 500','error',200),
|
|
191
|
+
L(' Tip: run /samiam to diagnose','warn',200),
|
|
192
|
+
];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function buildSamIAm() {
|
|
196
|
+
let d = 0; const L = (text, color, gap=80) => { d+=gap; return {text,color,delay:d}; };
|
|
197
|
+
return [
|
|
198
|
+
L('gorilla@inneranimal ~ % /samiam how is our terminal setup','cmd',0),
|
|
199
|
+
L('','dim',60),
|
|
200
|
+
L(' >> AGENT SAM ACTIVATED','sam',200),
|
|
201
|
+
L(' >> Workspace: ws_inneranimalmedia','sam',100),
|
|
202
|
+
L(' >> PTY context: injecting last 30 lines','sam',100),
|
|
203
|
+
L(' >> Routing: claude-sonnet-4-6 (T2)','sam',100),
|
|
204
|
+
L('','dim',200),
|
|
205
|
+
L(' [SAM] Terminal PTY is running clean. Your xterm.js','sam',400),
|
|
206
|
+
L(' bridge is connected to iam-pty via WebSocket.','sam',150),
|
|
207
|
+
L(' gorilla-mode shell is rendering on top of it.','sam',150),
|
|
208
|
+
L('','dim',80),
|
|
209
|
+
L(' [SAM] One issue flagging: 50 open errors in status','sam',300),
|
|
210
|
+
L(' bar – traced to mcp_services table having 30','sam',150),
|
|
211
|
+
L(' rows all pointing to same endpoint, NULL last_used.','sam',150),
|
|
212
|
+
L(' Table is never read by Worker – safe to truncate.','sam',150),
|
|
213
|
+
L('','dim',80),
|
|
214
|
+
L(' [SAM] Also: terminal_sessions user_id backfill is','sam',300),
|
|
215
|
+
L(' still needed in register INSERT (hardcoded sam).','sam',150),
|
|
216
|
+
L('','dim',80),
|
|
217
|
+
L(' [1] Show me the mcp_services cleanup query','white',300),
|
|
218
|
+
L(' [2] Run /d1 truncate mcp_services directly','white',80),
|
|
219
|
+
L(' [3] Open the terminal_sessions bug in Cursor','white',80),
|
|
220
|
+
L(' [esc] Skip for now','dim',80),
|
|
221
|
+
];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function buildWrangler() {
|
|
225
|
+
let d = 0; const L = (text, color, gap=100) => { d+=gap; return {text,color,delay:d}; };
|
|
226
|
+
return [
|
|
227
|
+
L('gorilla@inneranimal ~ % /wrangler tail inneranimalmedia','cmd',0),
|
|
228
|
+
L('','dim',60),
|
|
229
|
+
L(' [GATE] About to run:','warn',150),
|
|
230
|
+
L(' ./scripts/with-cloudflare-env.sh npx wrangler tail inneranimalmedia','white',80),
|
|
231
|
+
L('','dim',80),
|
|
232
|
+
L(' PROCEED? [1] YES [esc] NO','warn',200),
|
|
233
|
+
L('','dim',100),
|
|
234
|
+
L(' >> 1','cmd',600),
|
|
235
|
+
L('','dim',60),
|
|
236
|
+
L(' Connecting to worker: inneranimalmedia','muted',200),
|
|
237
|
+
L(' Account: Inner Animal Media (6f2a…)','muted',80),
|
|
238
|
+
L(' Zone: inneranimalmedia.com','muted',80),
|
|
239
|
+
L('','dim',100),
|
|
240
|
+
L(' [STREAM] Listening for events…','success',300),
|
|
241
|
+
L('','dim',80),
|
|
242
|
+
L(' 10:31:04 GET / 200 11ms','dim',400),
|
|
243
|
+
L(' 10:31:06 POST /api/agent/chat 200 445ms','dim',350),
|
|
244
|
+
L(' 10:31:07 GET /api/status 200 6ms','dim',250),
|
|
245
|
+
L(' 10:31:09 POST /mcp 200 88ms [MCP]','info',380),
|
|
246
|
+
L(' 10:31:11 POST /api/agent/chat 200 1201ms [LLM]','warn',620),
|
|
247
|
+
L('','dim',200),
|
|
248
|
+
L(' LLM call latency spike: 1201ms – check Sonnet routing','warn',200),
|
|
249
|
+
];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const SCENARIOS = [
|
|
253
|
+
{ key:'deploy', label:'/deploy', fn:buildDeploy, status:'DEPLOYING', coins:6, pump:true, errAt:null },
|
|
254
|
+
{ key:'benchmark', label:'/benchmark', fn:buildBenchmark, status:'BENCHMARKING',coins:12, pump:true, errAt:null },
|
|
255
|
+
{ key:'d1', label:'/d1 query', fn:buildD1, status:'QUERYING D1',coins:3, pump:false, errAt:null },
|
|
256
|
+
{ key:'tail', label:'/tail', fn:buildTail, status:'TAILING', coins:0, pump:false, errAt:9 },
|
|
257
|
+
{ key:'samiam', label:'/samiam', fn:buildSamIAm, status:'SAM ACTIVE', coins:4, pump:true, errAt:null },
|
|
258
|
+
{ key:'wrangler', label:'/wrangler', fn:buildWrangler, status:'CF GATE', coins:2, pump:false, errAt:null },
|
|
259
|
+
];
|
|
260
|
+
|
|
261
|
+
// ── Sprite Renderer ───────────────────────────────────────────────────────────
|
|
262
|
+
function Sprite({ data, scale=1 }) {
|
|
263
|
+
const ps = PS * scale;
|
|
264
|
+
return (
|
|
265
|
+
<svg width={data[0].length*ps} height={data.length*ps} style={{imageRendering:'pixelated',display:'block'}}>
|
|
266
|
+
{data.flatMap((row,y) => row.map((c,x) =>
|
|
267
|
+
c ? <rect key={`${x},${y}`} x={x*ps} y={y*ps} width={ps} height={ps} fill={PAL[c]}/> : null
|
|
268
|
+
))}
|
|
269
|
+
</svg>
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// ── Bar ───────────────────────────────────────────────────────────────────────
|
|
274
|
+
function Bar({ pct, color, label, val }) {
|
|
275
|
+
return (
|
|
276
|
+
<div style={{marginBottom:10}}>
|
|
277
|
+
<div style={{display:'flex',justifyContent:'space-between',fontSize:9,letterSpacing:2,color:'rgba(255,255,255,.4)',marginBottom:3}}>
|
|
278
|
+
<span>{label}</span><span style={{color}}>{val}</span>
|
|
279
|
+
</div>
|
|
280
|
+
<div style={{height:6,background:'rgba(255,255,255,.07)',position:'relative'}}>
|
|
281
|
+
<div style={{position:'absolute',top:0,left:0,height:'100%',width:`${pct}%`,background:color,transition:'width .4s ease',boxShadow:`0 0 6px ${color}`}}/>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// ── Main ──────────────────────────────────────────────────────────────────────
|
|
288
|
+
export default function GorillaMode() {
|
|
289
|
+
const [themeIdx, setThemeIdx] = useState(0);
|
|
290
|
+
const [lines, setLines] = useState([{text:'gorilla@inneranimal ~ % ready. select a demo below.', color:'dim', delay:0}]);
|
|
291
|
+
const [running, setRunning] = useState(false);
|
|
292
|
+
const [status, setStatus] = useState('READY');
|
|
293
|
+
const [progress, setProgress] = useState(0);
|
|
294
|
+
const [pump, setPump] = useState(false);
|
|
295
|
+
const [errorFlash, setError] = useState(false);
|
|
296
|
+
const [coinCount, setCoinCount] = useState(0);
|
|
297
|
+
const [floatCoins, setFloat] = useState([]);
|
|
298
|
+
const [flameTick, setFlameTick] = useState(0);
|
|
299
|
+
const [booted, setBooted] = useState(false);
|
|
300
|
+
const [bootLine, setBootLine] = useState('');
|
|
301
|
+
const [activeScenario, setActive] = useState(null);
|
|
302
|
+
const termRef = useRef(null);
|
|
303
|
+
const timerRefs = useRef([]);
|
|
304
|
+
|
|
305
|
+
const T = THEMES[TKEYS[themeIdx]];
|
|
306
|
+
|
|
307
|
+
// Boot
|
|
308
|
+
useEffect(() => {
|
|
309
|
+
const BOOT = ['GORILLA MODE v0.1','>> D1: inneranimalmedia-business','>> MCP TOOLS: 98 LOADED','>> AGENT SAM: ONLINE','>> READY'];
|
|
310
|
+
let i = 0;
|
|
311
|
+
const t = setInterval(() => { if(i<BOOT.length){setBootLine(BOOT[i]);i++;}else{clearInterval(t);setTimeout(()=>setBooted(true),400);}}, 340);
|
|
312
|
+
return () => clearInterval(t);
|
|
313
|
+
}, []);
|
|
314
|
+
|
|
315
|
+
// Flame tick
|
|
316
|
+
useEffect(() => {
|
|
317
|
+
const t = setInterval(() => setFlameTick(n => (n+1)%3), 190);
|
|
318
|
+
return () => clearInterval(t);
|
|
319
|
+
}, []);
|
|
320
|
+
|
|
321
|
+
// Auto-scroll terminal
|
|
322
|
+
useEffect(() => {
|
|
323
|
+
if (termRef.current) termRef.current.scrollTop = termRef.current.scrollHeight;
|
|
324
|
+
}, [lines]);
|
|
325
|
+
|
|
326
|
+
const stars = useMemo(() =>
|
|
327
|
+
Array.from({length:40},(_,i) => ({id:i,x:Math.random()*100,y:Math.random()*45,s:Math.random()<.2?2:1,d:Math.random()*4}))
|
|
328
|
+
,[]);
|
|
329
|
+
|
|
330
|
+
const spawnCoins = useCallback((n) => {
|
|
331
|
+
if (!n) return;
|
|
332
|
+
const batch = Array.from({length:n},(_,i) => ({id:Date.now()+i,x:15+Math.random()*30,y:40+Math.random()*15,dx:(Math.random()-.5)*50}));
|
|
333
|
+
setFloat(p=>[…p,…batch]);
|
|
334
|
+
setCoinCount(c=>c+n);
|
|
335
|
+
setTimeout(()=>setFloat(p=>p.filter(c=>!batch.find(b=>b.id===c.id))),1400);
|
|
336
|
+
},[]);
|
|
337
|
+
|
|
338
|
+
const runScenario = useCallback((s) => {
|
|
339
|
+
if (running) return;
|
|
340
|
+
timerRefs.current.forEach(clearTimeout);
|
|
341
|
+
timerRefs.current = [];
|
|
342
|
+
const scenario = SCENARIOS.find(x=>x.key===s);
|
|
343
|
+
if (!scenario) return;
|
|
344
|
+
const sceneLines = scenario.fn();
|
|
345
|
+
const maxDelay = Math.max(…sceneLines.map(l=>l.delay));
|
|
346
|
+
setLines([]);
|
|
347
|
+
setRunning(true);
|
|
348
|
+
setStatus(scenario.status);
|
|
349
|
+
setProgress(0);
|
|
350
|
+
setActive(s);
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
sceneLines.forEach((line,i) => {
|
|
354
|
+
const t = setTimeout(() => {
|
|
355
|
+
setLines(p=>[...p,line]);
|
|
356
|
+
setProgress(Math.round(((i+1)/sceneLines.length)*100));
|
|
357
|
+
if (line.color==='error'||line.color==='fail') {
|
|
358
|
+
setError(true); setTimeout(()=>setError(false),600);
|
|
359
|
+
}
|
|
360
|
+
}, line.delay);
|
|
361
|
+
timerRefs.current.push(t);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
const done = setTimeout(() => {
|
|
365
|
+
setRunning(false);
|
|
366
|
+
setStatus('READY');
|
|
367
|
+
setProgress(100);
|
|
368
|
+
if (scenario.pump) { setPump(true); setTimeout(()=>setPump(false),700); }
|
|
369
|
+
spawnCoins(scenario.coins);
|
|
370
|
+
}, maxDelay + 400);
|
|
371
|
+
timerRefs.current.push(done);
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
}, [running, spawnCoins]);
|
|
375
|
+
|
|
376
|
+
const CSS = `@keyframes idle {0%,100%{transform:translateY(0)} 50%{transform:translateY(-4px)}} @keyframes pump {0%{transform:scale(1)} 30%{transform:scale(1.12) translateY(-7px)} 70%{transform:scale(.97)} 100%{transform:scale(1)}} @keyframes shake {0%,100%{transform:translateX(0)} 20%{transform:translateX(-4px)} 40%{transform:translateX(4px)} 60%{transform:translateX(-3px)} 80%{transform:translateX(3px)}} @keyframes rise {0%{transform:translateY(0) scale(1);opacity:1} 100%{transform:translateY(-80px) scale(.3);opacity:0}} @keyframes blink {0%,100%{opacity:1} 50%{opacity:0}} @keyframes twinkle {0%,100%{opacity:.7} 50%{opacity:.1}} @keyframes flicker {0%,100%{transform:scaleY(1)} 50%{transform:scaleY(1.12) scaleX(.9)}} @keyframes scan {0%{opacity:.02} 50%{opacity:.05} 100%{opacity:.02}} @keyframes fadein {from{opacity:0;transform:translateY(6px)} to{opacity:1;transform:none}} @keyframes errflash{0%,100%{box-shadow:none} 50%{box-shadow:0 0 30px #ff444488 inset}} .scen-btn{cursor:pointer;transition:all .12s;font-family:"Courier New",monospace;} .scen-btn:hover{transform:translateY(-1px);} .scen-btn:disabled{opacity:.35;cursor:not-allowed;transform:none;}`;
|
|
377
|
+
|
|
378
|
+
if (!booted) return (
|
|
379
|
+
<div style={{width:'100%',height:'100vh',background:'#030a14',display:'flex',flexDirection:'column',alignItems:'center',justifyContent:'center',fontFamily:'"Courier New",monospace',color:'#00e5ff'}}>
|
|
380
|
+
<style>{CSS}</style>
|
|
381
|
+
<div style={{fontSize:10,letterSpacing:6,opacity:.35,marginBottom:14}}>INNERANIMAL MEDIA</div>
|
|
382
|
+
<div style={{fontSize:15,letterSpacing:2,textShadow:'0 0 10px #00e5ff'}}>
|
|
383
|
+
{bootLine}<span style={{animation:'blink .7s infinite'}}>_</span>
|
|
384
|
+
</div>
|
|
385
|
+
</div>
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
return (
|
|
389
|
+
<div style={{width:'100%',minHeight:'100vh',background:`linear-gradient(160deg,${T.bg} 0%,#030a14 100%)`,fontFamily:'"Courier New",monospace',position:'relative',overflow:'hidden'}}>
|
|
390
|
+
<style>{CSS}</style>
|
|
391
|
+
|
|
392
|
+
```
|
|
393
|
+
{/* Scanlines */}
|
|
394
|
+
<div style={{position:'absolute',inset:0,pointerEvents:'none',zIndex:99,
|
|
395
|
+
backgroundImage:`repeating-linear-gradient(0deg,${T.dim.replace('22','06')} 0,${T.dim.replace('22','06')} 1px,transparent 1px,transparent 3px)`,
|
|
396
|
+
animation:'scan 5s infinite'}}/>
|
|
397
|
+
|
|
398
|
+
{/* Stars */}
|
|
399
|
+
{stars.map(s=>(
|
|
400
|
+
<div key={s.id} style={{position:'absolute',left:`${s.x}%`,top:`${s.y}%`,width:s.s,height:s.s,background:'#fff',
|
|
401
|
+
animation:`twinkle ${2+s.d}s infinite`,animationDelay:`${s.d}s`,pointerEvents:'none'}}/>
|
|
402
|
+
))}
|
|
403
|
+
|
|
404
|
+
{/* Floating coins */}
|
|
405
|
+
{floatCoins.map(c=>(
|
|
406
|
+
<div key={c.id} style={{position:'absolute',left:`${c.x}%`,top:`${c.y}%`,
|
|
407
|
+
animation:'rise 1.3s ease-out forwards',transform:`translateX(${c.dx}px)`,pointerEvents:'none',zIndex:60}}>
|
|
408
|
+
<Sprite data={COIN} scale={.9}/>
|
|
409
|
+
</div>
|
|
410
|
+
))}
|
|
411
|
+
|
|
412
|
+
{/* Top bar */}
|
|
413
|
+
<div style={{display:'flex',alignItems:'center',justifyContent:'space-between',
|
|
414
|
+
padding:'10px 18px 8px',borderBottom:`1px solid ${T.border}`,background:T.panel}}>
|
|
415
|
+
<div>
|
|
416
|
+
<span style={{fontSize:9,letterSpacing:5,color:T.accent,opacity:.6}}>INNERANIMAL MEDIA // </span>
|
|
417
|
+
<span style={{fontSize:12,fontWeight:900,letterSpacing:4,color:'#fff',textShadow:T.glow}}>GORILLA MODE</span>
|
|
418
|
+
</div>
|
|
419
|
+
<div style={{display:'flex',alignItems:'center',gap:16}}>
|
|
420
|
+
<div style={{display:'flex',alignItems:'center',gap:6,background:'rgba(0,0,0,.5)',border:`1px solid ${T.accent}`,padding:'3px 10px'}}>
|
|
421
|
+
<Sprite data={COIN} scale={.45}/>
|
|
422
|
+
<span style={{color:T.accent,fontSize:11,letterSpacing:2}}>x {coinCount}</span>
|
|
423
|
+
</div>
|
|
424
|
+
<button className="scen-btn" onClick={()=>setThemeIdx(i=>(i+1)%TKEYS.length)}
|
|
425
|
+
style={{padding:'4px 10px',background:'transparent',border:`1px solid ${T.border}`,color:T.accent,fontSize:9,letterSpacing:2}}>
|
|
426
|
+
{TKEYS[themeIdx]}
|
|
427
|
+
</button>
|
|
428
|
+
</div>
|
|
429
|
+
</div>
|
|
430
|
+
|
|
431
|
+
{/* Main split */}
|
|
432
|
+
<div style={{display:'flex',height:'calc(100vh - 130px)',minHeight:400}}>
|
|
433
|
+
|
|
434
|
+
{/* LEFT: Gorilla + HUD */}
|
|
435
|
+
<div style={{width:200,minWidth:180,borderRight:`1px solid ${T.border}`,background:T.panel,
|
|
436
|
+
display:'flex',flexDirection:'column',alignItems:'center',padding:'16px 14px',gap:0,flexShrink:0}}>
|
|
437
|
+
|
|
438
|
+
{/* Gorilla */}
|
|
439
|
+
<div style={{
|
|
440
|
+
animation: errorFlash ? 'shake .5s ease' : pump ? 'pump .6s ease' : 'idle 2.8s ease-in-out infinite',
|
|
441
|
+
filter: errorFlash ? 'brightness(1.5) saturate(2) hue-rotate(-20deg)' : 'none',
|
|
442
|
+
marginBottom:8,
|
|
443
|
+
}}>
|
|
444
|
+
<Sprite data={pump ? GORILLA_PUMP : GORILLA} scale={1.05}/>
|
|
445
|
+
</div>
|
|
446
|
+
|
|
447
|
+
{/* Flames */}
|
|
448
|
+
<div style={{display:'flex',justifyContent:'center',gap:60,marginTop:-4}}>
|
|
449
|
+
{[0,1].map(i=>(
|
|
450
|
+
<div key={i} style={{animation:'flicker .45s infinite',animationDelay:`${i*.2}s`}}>
|
|
451
|
+
<Sprite data={FLAME_FRAMES[flameTick]} scale={.9}/>
|
|
452
|
+
</div>
|
|
453
|
+
))}
|
|
454
|
+
</div>
|
|
455
|
+
|
|
456
|
+
{/* Status */}
|
|
457
|
+
<div style={{width:'100%',marginTop:14,paddingTop:12,borderTop:`1px solid ${T.border}`}}>
|
|
458
|
+
<div style={{fontSize:9,letterSpacing:3,color:T.accent,marginBottom:10,textAlign:'center',textShadow:T.glow}}>
|
|
459
|
+
{status}
|
|
460
|
+
{running && <span style={{animation:'blink .7s infinite',marginLeft:4}}>_</span>}
|
|
461
|
+
</div>
|
|
462
|
+
|
|
463
|
+
<Bar pct={progress} color={T.accent} label="PROGRESS" val={`${progress}%`}/>
|
|
464
|
+
<Bar pct={Math.max(0,100-progress)} color="#ff4444" label="ERRORS" val="50"/>
|
|
465
|
+
<Bar pct={running?65:100} color="#44ff88" label="AGENT" val={running?'BUSY':'READY'}/>
|
|
466
|
+
|
|
467
|
+
<div style={{marginTop:12,paddingTop:10,borderTop:`1px solid ${T.border}`,fontSize:9,color:'rgba(255,255,255,.3)',letterSpacing:1,lineHeight:1.8}}>
|
|
468
|
+
<div>ws_inneranimalmedia</div>
|
|
469
|
+
<div>branch: main {running&&<span style={{color:T.accent}}>*</span>}</div>
|
|
470
|
+
<div style={{color:activeScenario?T.accent:'inherit'}}>
|
|
471
|
+
{activeScenario ? `> ${activeScenario}` : '> idle'}
|
|
472
|
+
</div>
|
|
473
|
+
</div>
|
|
474
|
+
</div>
|
|
475
|
+
</div>
|
|
476
|
+
|
|
477
|
+
{/* RIGHT: Terminal */}
|
|
478
|
+
<div style={{flex:1,display:'flex',flexDirection:'column',overflow:'hidden'}}>
|
|
479
|
+
|
|
480
|
+
{/* Terminal header */}
|
|
481
|
+
<div style={{padding:'7px 16px',borderBottom:`1px solid ${T.border}`,background:'rgba(0,0,0,.4)',
|
|
482
|
+
display:'flex',alignItems:'center',gap:8}}>
|
|
483
|
+
<div style={{width:8,height:8,borderRadius:'50%',background:running?T.accent:'#ffffff22',boxShadow:running?T.glow:'none',transition:'all .3s'}}/>
|
|
484
|
+
<span style={{fontSize:9,letterSpacing:2,color:'rgba(255,255,255,.3)'}}>TERMINAL OUTPUT</span>
|
|
485
|
+
<span style={{marginLeft:'auto',fontSize:9,color:'rgba(255,255,255,.2)',letterSpacing:1}}>{lines.length} lines</span>
|
|
486
|
+
</div>
|
|
487
|
+
|
|
488
|
+
{/* Output */}
|
|
489
|
+
<div ref={termRef} style={{flex:1,overflowY:'auto',padding:'14px 18px',
|
|
490
|
+
animation: errorFlash ? 'errflash .5s ease' : 'none',
|
|
491
|
+
scrollbarWidth:'thin',scrollbarColor:`${T.accent}33 transparent`}}>
|
|
492
|
+
{lines.map((line, i) => (
|
|
493
|
+
<div key={i} style={{
|
|
494
|
+
fontFamily:'"Courier New",monospace',fontSize:12,lineHeight:1.65,
|
|
495
|
+
whiteSpace:'pre',color: LC[line.color] || LC.white,
|
|
496
|
+
animation: i===lines.length-1 ? 'fadein .15s ease' : 'none',
|
|
497
|
+
}}>
|
|
498
|
+
{line.text || '\u00A0'}
|
|
499
|
+
</div>
|
|
500
|
+
))}
|
|
501
|
+
{running && (
|
|
502
|
+
<div style={{color:T.accent,fontSize:12,animation:'blink .7s infinite',marginTop:2}}>_</div>
|
|
503
|
+
)}
|
|
504
|
+
</div>
|
|
505
|
+
|
|
506
|
+
{/* Input line */}
|
|
507
|
+
<div style={{padding:'8px 16px',borderTop:`1px solid ${T.border}`,background:'rgba(0,0,0,.5)',
|
|
508
|
+
display:'flex',alignItems:'center',gap:8}}>
|
|
509
|
+
<span style={{color:T.accent,fontSize:12,whiteSpace:'nowrap'}}>gorilla@inneranimal ~ %</span>
|
|
510
|
+
<div style={{flex:1,fontSize:12,color:'rgba(255,255,255,.7)',letterSpacing:.5}}>
|
|
511
|
+
{running ? (
|
|
512
|
+
<span style={{color:'rgba(255,255,255,.3)'}}>running... <span style={{animation:'blink .5s infinite'}}>|</span></span>
|
|
513
|
+
) : (
|
|
514
|
+
<span style={{color:'rgba(255,255,255,.3)'}}>type /help or select demo below<span style={{animation:'blink 1s infinite'}}>|</span></span>
|
|
515
|
+
)}
|
|
516
|
+
</div>
|
|
517
|
+
</div>
|
|
518
|
+
</div>
|
|
519
|
+
</div>
|
|
520
|
+
|
|
521
|
+
{/* Scenario buttons */}
|
|
522
|
+
<div style={{borderTop:`1px solid ${T.border}`,background:T.panel,
|
|
523
|
+
display:'flex',flexWrap:'wrap',gap:0}}>
|
|
524
|
+
{SCENARIOS.map(s=>(
|
|
525
|
+
<button key={s.key} className="scen-btn" disabled={running}
|
|
526
|
+
onClick={()=>runScenario(s.key)}
|
|
527
|
+
style={{flex:'1 1 0',padding:'10px 8px',minWidth:100,
|
|
528
|
+
background: activeScenario===s.key ? T.dim : 'transparent',
|
|
529
|
+
border:'none',borderRight:`1px solid ${T.border}`,
|
|
530
|
+
color: activeScenario===s.key ? T.accent : 'rgba(255,255,255,.5)',
|
|
531
|
+
fontSize:11,letterSpacing:1.5,textShadow: activeScenario===s.key ? T.glow : 'none'}}>
|
|
532
|
+
{s.label}
|
|
533
|
+
</button>
|
|
534
|
+
))}
|
|
535
|
+
</div>
|
|
536
|
+
</div>
|
|
537
|
+
```
|
|
538
|
+
|
|
539
|
+
);
|
|
540
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Gorilla Shell (Phase 0)
|
|
2
|
+
|
|
3
|
+
Game-feel terminal UI prototype — consolidated from [InnerAnimal/gorilla-mode](https://github.com/InnerAnimal/gorilla-mode) into **Agent Sam SDK**.
|
|
4
|
+
|
|
5
|
+
This is the **unique install experience** layer: pixel HUD, themed moods, slash-command demos, deploy/benchmark scenarios. Phase 1 connects real PTY via ExecOS.
|
|
6
|
+
|
|
7
|
+
## Run locally
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd examples/gorilla-shell
|
|
11
|
+
npm install
|
|
12
|
+
npm run dev
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## What you see
|
|
16
|
+
|
|
17
|
+
- Gorilla launch screen + sprite reactions
|
|
18
|
+
- Themes: NIGHT, DAY, LAVA, VOID
|
|
19
|
+
- Six demo scenarios (deploy, benchmark, D1, tail, samiam, wrangler)
|
|
20
|
+
- Slash command registry lives in `../../src/lib/slash-commands.js`
|
|
21
|
+
|
|
22
|
+
Full architecture: [docs/CLI_SHELL.md](../../docs/CLI_SHELL.md)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>Agent Sam Shell — Gorilla Mode</title>
|
|
7
|
+
<style>
|
|
8
|
+
html, body, #root { margin: 0; height: 100%; background: #030a14; }
|
|
9
|
+
</style>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="root"></div>
|
|
13
|
+
<script type="module" src="/main.jsx"></script>
|
|
14
|
+
</body>
|
|
15
|
+
</html>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@inneranimalmedia/agentsam-shell-example",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Phase 0 Gorilla Shell — game-feel CLI UX prototype for Agent Sam SDK",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"react": "^19.1.0",
|
|
13
|
+
"react-dom": "^19.1.0"
|
|
14
|
+
},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@vitejs/plugin-react": "^4.5.2",
|
|
17
|
+
"vite": "^6.3.5"
|
|
18
|
+
}
|
|
19
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@inneranimalmedia/agentsam-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
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
12
|
"agentsam": "src/cli.js"
|
|
9
13
|
},
|
|
14
|
+
"files": [
|
|
15
|
+
"src",
|
|
16
|
+
"docs",
|
|
17
|
+
"examples",
|
|
18
|
+
"test",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE",
|
|
21
|
+
"DEVELOPMENT.md"
|
|
22
|
+
],
|
|
10
23
|
"scripts": {
|
|
11
|
-
"test": "node
|
|
24
|
+
"test": "node test/smoke.mjs",
|
|
25
|
+
"smoke": "node test/smoke.mjs",
|
|
26
|
+
"prepublishOnly": "npm test"
|
|
27
|
+
},
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=20"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
12
33
|
},
|
|
13
34
|
"repository": {
|
|
14
35
|
"type": "git",
|