@aixnn/aixautots 0.0.0-stage → 0.5.3
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 +222 -2
- package/dist/chunk-5BMFMDQR.js +18 -0
- package/dist/chunk-64Q7BBIQ.js +1347 -0
- package/dist/chunk-BSHHYM72.js +1074 -0
- package/dist/chunk-CVV7FOMQ.js +175 -0
- package/dist/chunk-EVHTAXQG.js +273 -0
- package/dist/chunk-FW23FLAF.js +56 -0
- package/dist/chunk-IJVNII5N.js +668 -0
- package/dist/chunk-NWFYTFMI.js +65 -0
- package/dist/chunk-O34SNDQB.js +2042 -0
- package/dist/chunk-OEZFYKL6.js +1 -0
- package/dist/chunk-OXIM6EYO.js +410 -0
- package/dist/chunk-SVK2AY3J.js +412 -0
- package/dist/chunk-TATL3HTE.js +1511 -0
- package/dist/chunk-UINEPEIE.js +217 -0
- package/dist/chunk-V4MXFPDX.js +341 -0
- package/dist/chunk-XNKC6HU3.js +866 -0
- package/dist/chunk-YOT7HZBU.js +5744 -0
- package/dist/core/index.js +5 -0
- package/dist/device-session-W7I3WQXF.js +2 -0
- package/dist/i18n/index.js +1 -0
- package/dist/nav/index.js +1 -0
- package/dist/react/index.js +7 -0
- package/dist/ui/billing.js +425 -0
- package/dist/ui/device-create.js +9 -0
- package/dist/ui/device-mirror.js +10 -0
- package/dist/ui/devices.js +15 -0
- package/dist/ui/editor.js +344 -0
- package/dist/ui/index.js +665 -0
- package/dist/ui/inspector.js +1250 -0
- package/dist/ui/market.js +60 -0
- package/dist/ui/mirror.js +3 -0
- package/dist/ui/primitives/index.js +1 -0
- package/dist/ui/script-studio.js +10 -0
- package/dist/ui/scripts.js +210 -0
- package/dist/ui/tasks.js +1039 -0
- package/package.json +75 -4
- package/styles.css +97 -0
- package/tailwind-preset.cjs +84 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import { ScriptStudio } from '../chunk-XNKC6HU3.js';
|
|
2
|
+
import { useAixNav } from '../chunk-5BMFMDQR.js';
|
|
3
|
+
import { useAixT } from '../chunk-64Q7BBIQ.js';
|
|
4
|
+
import '../chunk-FW23FLAF.js';
|
|
5
|
+
import { Select, cn } from '../chunk-EVHTAXQG.js';
|
|
6
|
+
import '../chunk-O34SNDQB.js';
|
|
7
|
+
import '../chunk-V4MXFPDX.js';
|
|
8
|
+
import '../chunk-IJVNII5N.js';
|
|
9
|
+
import { useClient } from '../chunk-UINEPEIE.js';
|
|
10
|
+
import '../chunk-OXIM6EYO.js';
|
|
11
|
+
import '../chunk-TATL3HTE.js';
|
|
12
|
+
import '../chunk-NWFYTFMI.js';
|
|
13
|
+
import { useState, useEffect, useRef, useCallback } from 'react';
|
|
14
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
15
|
+
|
|
16
|
+
function AgentPanel({
|
|
17
|
+
scriptId,
|
|
18
|
+
deviceId,
|
|
19
|
+
code,
|
|
20
|
+
onReplace,
|
|
21
|
+
onOpenInspector,
|
|
22
|
+
onInsert,
|
|
23
|
+
runner
|
|
24
|
+
}) {
|
|
25
|
+
const t = useAixT();
|
|
26
|
+
const client = useClient();
|
|
27
|
+
const available = runner.available;
|
|
28
|
+
const [agent, setAgent] = useState("claude");
|
|
29
|
+
const [messages, setMessages] = useState([]);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
void runner.defaults?.().then((d) => {
|
|
32
|
+
if (d.agent) setAgent(d.agent);
|
|
33
|
+
});
|
|
34
|
+
}, [runner]);
|
|
35
|
+
const [input, setInput] = useState("");
|
|
36
|
+
const [running, setRunning] = useState(false);
|
|
37
|
+
const scrollRef = useRef(null);
|
|
38
|
+
const inputRef = useRef(null);
|
|
39
|
+
const liveRef = useRef("");
|
|
40
|
+
const [apps, setApps] = useState(null);
|
|
41
|
+
const [appsLoading, setAppsLoading] = useState(false);
|
|
42
|
+
const [appsErr, setAppsErr] = useState(null);
|
|
43
|
+
const loadApps = useCallback(async () => {
|
|
44
|
+
if (!deviceId) {
|
|
45
|
+
setAppsErr(t("agent.selectDeviceFirst"));
|
|
46
|
+
setApps([]);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
setAppsLoading(true);
|
|
50
|
+
setAppsErr(null);
|
|
51
|
+
try {
|
|
52
|
+
const list = await client.devices.op(deviceId, { op: "app_list" });
|
|
53
|
+
setApps(list ?? []);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
setAppsErr(String(e));
|
|
56
|
+
setApps([]);
|
|
57
|
+
} finally {
|
|
58
|
+
setAppsLoading(false);
|
|
59
|
+
}
|
|
60
|
+
}, [deviceId, client, t]);
|
|
61
|
+
const autosize = useCallback(() => {
|
|
62
|
+
const el = inputRef.current;
|
|
63
|
+
if (!el) return;
|
|
64
|
+
el.style.height = "auto";
|
|
65
|
+
el.style.height = `${Math.min(el.scrollHeight, 160)}px`;
|
|
66
|
+
}, []);
|
|
67
|
+
useEffect(autosize, [input, autosize]);
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight });
|
|
70
|
+
}, [messages]);
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (!available) return;
|
|
73
|
+
const unsub = runner.subscribe((p) => {
|
|
74
|
+
if (p.scriptId !== (scriptId ?? "")) return;
|
|
75
|
+
if (p.stream === "stdout" && p.chunk) {
|
|
76
|
+
liveRef.current += p.chunk + "\n";
|
|
77
|
+
setMessages((m) => upsertAgent(m, liveRef.current));
|
|
78
|
+
} else if (p.stream === "done") {
|
|
79
|
+
setRunning(false);
|
|
80
|
+
liveRef.current = "";
|
|
81
|
+
if (typeof p.script === "string" && p.script.length > 0 && p.script !== code) {
|
|
82
|
+
onReplace(p.script);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return unsub;
|
|
87
|
+
}, [available, runner, scriptId]);
|
|
88
|
+
const send = useCallback(
|
|
89
|
+
async (text) => {
|
|
90
|
+
const msg = text.trim();
|
|
91
|
+
if (!msg || running || !available) return;
|
|
92
|
+
if (!deviceId) {
|
|
93
|
+
setMessages((m) => [...m, { role: "agent", text: t("agent.needDevice") }]);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
setMessages((m) => [...m, { role: "user", text: msg }, { role: "agent", text: "\u2026" }]);
|
|
97
|
+
const isFirst = messages.length === 0;
|
|
98
|
+
setInput("");
|
|
99
|
+
setRunning(true);
|
|
100
|
+
liveRef.current = "";
|
|
101
|
+
try {
|
|
102
|
+
await runner.send({ agent, scriptId: scriptId ?? "", code, deviceId, userMsg: msg, isFirst });
|
|
103
|
+
} catch (e) {
|
|
104
|
+
setRunning(false);
|
|
105
|
+
setMessages((m) => upsertAgent(m, t("agent.startFailed", { err: String(e) })));
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
[agent, code, deviceId, messages.length, running, scriptId, available, runner, t]
|
|
109
|
+
);
|
|
110
|
+
const stop = useCallback(async () => {
|
|
111
|
+
if (!available) return;
|
|
112
|
+
try {
|
|
113
|
+
await runner.stop(scriptId ?? "");
|
|
114
|
+
} finally {
|
|
115
|
+
setRunning(false);
|
|
116
|
+
}
|
|
117
|
+
}, [scriptId, available, runner]);
|
|
118
|
+
if (!available) {
|
|
119
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
|
|
120
|
+
/* @__PURE__ */ jsx("div", { className: "px-3 py-2 border-b border-border text-body-sm font-semibold", children: "Agent" }),
|
|
121
|
+
/* @__PURE__ */ jsx("div", { className: "flex-1 flex items-center justify-center text-muted-foreground text-body-sm px-6 text-center", children: t("agent.unavailable") })
|
|
122
|
+
] });
|
|
123
|
+
}
|
|
124
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col", children: [
|
|
125
|
+
/* @__PURE__ */ jsxs("div", { className: "px-3 py-2 border-b border-border flex items-center justify-between gap-2", children: [
|
|
126
|
+
/* @__PURE__ */ jsx("span", { className: "text-body-sm font-semibold", children: "Agent" }),
|
|
127
|
+
/* @__PURE__ */ jsx("div", { className: "w-28", children: /* @__PURE__ */ jsx(
|
|
128
|
+
Select,
|
|
129
|
+
{
|
|
130
|
+
value: agent,
|
|
131
|
+
onChange: (v) => setAgent(v),
|
|
132
|
+
options: [
|
|
133
|
+
{ value: "claude", label: "claude" },
|
|
134
|
+
{ value: "codex", label: "codex" }
|
|
135
|
+
],
|
|
136
|
+
placeholder: ""
|
|
137
|
+
}
|
|
138
|
+
) })
|
|
139
|
+
] }),
|
|
140
|
+
/* @__PURE__ */ jsxs("div", { ref: scrollRef, className: "flex-1 overflow-auto px-3 py-2 space-y-2", children: [
|
|
141
|
+
messages.length === 0 && /* @__PURE__ */ jsx("p", { className: "text-body-sm text-muted-foreground text-center pt-6", children: t("agent.emptyHint") }),
|
|
142
|
+
messages.map((m, i) => /* @__PURE__ */ jsx(
|
|
143
|
+
"div",
|
|
144
|
+
{
|
|
145
|
+
className: cn(
|
|
146
|
+
"rounded px-2 py-1.5 text-body-sm whitespace-pre-wrap break-words",
|
|
147
|
+
m.role === "user" ? "bg-primary/10 text-foreground ml-6" : "bg-secondary text-muted-foreground mr-2 font-mono text-code-sm"
|
|
148
|
+
),
|
|
149
|
+
children: m.text
|
|
150
|
+
},
|
|
151
|
+
i
|
|
152
|
+
))
|
|
153
|
+
] }),
|
|
154
|
+
apps !== null && /* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 border-t border-border max-h-40 overflow-auto space-y-0.5", children: [
|
|
155
|
+
appsErr && /* @__PURE__ */ jsx("div", { className: "text-xs text-destructive", children: appsErr }),
|
|
156
|
+
!appsErr && apps.length === 0 && /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground", children: t("agent.noApps") }),
|
|
157
|
+
apps.map((a) => /* @__PURE__ */ jsxs(
|
|
158
|
+
"button",
|
|
159
|
+
{
|
|
160
|
+
onClick: () => {
|
|
161
|
+
onInsert(`await device.launchApp(${JSON.stringify(a.package)});`);
|
|
162
|
+
setApps(null);
|
|
163
|
+
},
|
|
164
|
+
className: "flex w-full items-center justify-between gap-2 rounded px-2 py-0.5 text-left text-xs text-foreground hover:bg-secondary",
|
|
165
|
+
children: [
|
|
166
|
+
/* @__PURE__ */ jsx("span", { className: "truncate", children: a.label || a.package }),
|
|
167
|
+
/* @__PURE__ */ jsx("span", { className: "shrink-0 font-mono text-[10px] text-muted-foreground", children: a.package })
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
a.package
|
|
171
|
+
))
|
|
172
|
+
] }),
|
|
173
|
+
/* @__PURE__ */ jsxs("div", { className: "px-3 py-1.5 flex flex-wrap gap-1 border-t border-border", children: [
|
|
174
|
+
/* @__PURE__ */ jsx(
|
|
175
|
+
"button",
|
|
176
|
+
{
|
|
177
|
+
disabled: running,
|
|
178
|
+
onClick: onOpenInspector,
|
|
179
|
+
className: "rounded-full bg-secondary px-2 py-0.5 text-xs text-muted-foreground hover:text-foreground disabled:opacity-50",
|
|
180
|
+
children: t("agent.useInspector")
|
|
181
|
+
}
|
|
182
|
+
),
|
|
183
|
+
/* @__PURE__ */ jsx(
|
|
184
|
+
"button",
|
|
185
|
+
{
|
|
186
|
+
disabled: running || appsLoading,
|
|
187
|
+
onClick: () => apps !== null ? setApps(null) : void loadApps(),
|
|
188
|
+
className: "rounded-full bg-secondary px-2 py-0.5 text-xs text-muted-foreground hover:text-foreground disabled:opacity-50",
|
|
189
|
+
children: appsLoading ? t("agent.loading") : apps !== null ? t("agent.closeApps") : t("agent.pickApp")
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
] }),
|
|
193
|
+
/* @__PURE__ */ jsxs("div", { className: "p-2 border-t border-border flex gap-2 items-end", children: [
|
|
194
|
+
/* @__PURE__ */ jsx(
|
|
195
|
+
"textarea",
|
|
196
|
+
{
|
|
197
|
+
ref: inputRef,
|
|
198
|
+
rows: 1,
|
|
199
|
+
className: "flex-1 resize-none bg-secondary rounded px-2 py-1 text-body-sm outline-none disabled:opacity-50 max-h-40 overflow-y-auto",
|
|
200
|
+
placeholder: t("agent.placeholder"),
|
|
201
|
+
value: input,
|
|
202
|
+
disabled: running,
|
|
203
|
+
onChange: (e) => setInput(e.target.value),
|
|
204
|
+
onKeyDown: (e) => {
|
|
205
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
206
|
+
e.preventDefault();
|
|
207
|
+
void send(input);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
),
|
|
212
|
+
running ? /* @__PURE__ */ jsx(
|
|
213
|
+
"button",
|
|
214
|
+
{
|
|
215
|
+
onClick: () => void stop(),
|
|
216
|
+
className: "rounded bg-destructive/15 text-destructive px-3 text-body-sm",
|
|
217
|
+
children: t("agent.stop")
|
|
218
|
+
}
|
|
219
|
+
) : /* @__PURE__ */ jsx(
|
|
220
|
+
"button",
|
|
221
|
+
{
|
|
222
|
+
onClick: () => void send(input),
|
|
223
|
+
disabled: !input.trim(),
|
|
224
|
+
className: "rounded bg-primary text-primary-foreground px-3 text-body-sm disabled:opacity-50",
|
|
225
|
+
children: t("agent.send")
|
|
226
|
+
}
|
|
227
|
+
)
|
|
228
|
+
] })
|
|
229
|
+
] });
|
|
230
|
+
}
|
|
231
|
+
function upsertAgent(messages, text) {
|
|
232
|
+
const next = [...messages];
|
|
233
|
+
for (let i = next.length - 1; i >= 0; i--) {
|
|
234
|
+
if (next[i]?.role === "agent") {
|
|
235
|
+
next[i] = { role: "agent", text };
|
|
236
|
+
return next;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
next.push({ role: "agent", text });
|
|
240
|
+
return next;
|
|
241
|
+
}
|
|
242
|
+
function ScriptEditorPage({
|
|
243
|
+
scriptId,
|
|
244
|
+
agentRunner,
|
|
245
|
+
renderAgentPanel,
|
|
246
|
+
renderInspector,
|
|
247
|
+
headerExtra
|
|
248
|
+
}) {
|
|
249
|
+
const { navigate } = useAixNav();
|
|
250
|
+
const agentSlot = renderAgentPanel ?? (agentRunner ? (ctx) => /* @__PURE__ */ jsx(
|
|
251
|
+
AgentPanel,
|
|
252
|
+
{
|
|
253
|
+
scriptId: ctx.scriptId,
|
|
254
|
+
deviceId: ctx.deviceId,
|
|
255
|
+
code: ctx.code,
|
|
256
|
+
onReplace: ctx.setCode,
|
|
257
|
+
onOpenInspector: ctx.openInspector,
|
|
258
|
+
onInsert: ctx.insertSnippet,
|
|
259
|
+
runner: agentRunner
|
|
260
|
+
}
|
|
261
|
+
) : void 0);
|
|
262
|
+
return /* @__PURE__ */ jsx(
|
|
263
|
+
ScriptStudio,
|
|
264
|
+
{
|
|
265
|
+
scriptId,
|
|
266
|
+
onScriptIdChange: (id) => navigate(`/editor/${encodeURIComponent(id)}`, { replace: true }),
|
|
267
|
+
renderAgentPanel: agentSlot,
|
|
268
|
+
renderInspector,
|
|
269
|
+
headerExtra
|
|
270
|
+
}
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/ui/editor/backend-agent-runner.ts
|
|
275
|
+
function createBackendAgentRunner(client, opts = {}) {
|
|
276
|
+
const base = (opts.basePath ?? "/api/agent").replace(/\/$/, "");
|
|
277
|
+
return {
|
|
278
|
+
available: true,
|
|
279
|
+
async defaults() {
|
|
280
|
+
try {
|
|
281
|
+
return await client.http.get(`${base}/defaults`) ?? {};
|
|
282
|
+
} catch {
|
|
283
|
+
return {};
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
async send(req) {
|
|
287
|
+
await client.http.post(`${base}/${req.isFirst ? "start" : "send"}`, req);
|
|
288
|
+
},
|
|
289
|
+
async stop(scriptId) {
|
|
290
|
+
await client.http.post(`${base}/stop`, { scriptId });
|
|
291
|
+
},
|
|
292
|
+
subscribe(on) {
|
|
293
|
+
const ctrl = new AbortController();
|
|
294
|
+
void streamSse(
|
|
295
|
+
client,
|
|
296
|
+
`${base}/stream`,
|
|
297
|
+
ctrl.signal,
|
|
298
|
+
(raw) => on({
|
|
299
|
+
scriptId: raw.script_id ?? raw.scriptId ?? "",
|
|
300
|
+
stream: raw.stream,
|
|
301
|
+
chunk: raw.chunk,
|
|
302
|
+
script: raw.script
|
|
303
|
+
})
|
|
304
|
+
);
|
|
305
|
+
return () => ctrl.abort();
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
async function streamSse(client, path, signal, onEvent) {
|
|
310
|
+
const url = client.cfg.baseUrl.replace(/\/$/, "") + path;
|
|
311
|
+
let resp;
|
|
312
|
+
try {
|
|
313
|
+
const headers = { ...await client.cfg.auth.headers("caller"), Accept: "text/event-stream" };
|
|
314
|
+
resp = await client.cfg.fetchFn(url, { headers, signal });
|
|
315
|
+
} catch {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const body = resp.body;
|
|
319
|
+
if (!body || typeof body.getReader !== "function") return;
|
|
320
|
+
const reader = body.getReader();
|
|
321
|
+
const decoder = new TextDecoder();
|
|
322
|
+
let buf = "";
|
|
323
|
+
try {
|
|
324
|
+
for (; ; ) {
|
|
325
|
+
const { value, done } = await reader.read();
|
|
326
|
+
if (done) break;
|
|
327
|
+
buf += decoder.decode(value, { stream: true });
|
|
328
|
+
let sep;
|
|
329
|
+
while ((sep = buf.indexOf("\n\n")) !== -1) {
|
|
330
|
+
const frame = buf.slice(0, sep);
|
|
331
|
+
buf = buf.slice(sep + 2);
|
|
332
|
+
const data = frame.split("\n").filter((l) => l.startsWith("data:")).map((l) => l.slice(5).trim()).join("\n");
|
|
333
|
+
if (!data) continue;
|
|
334
|
+
try {
|
|
335
|
+
onEvent(JSON.parse(data));
|
|
336
|
+
} catch {
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
} catch {
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export { AgentPanel, ScriptEditorPage, createBackendAgentRunner };
|