@songsid/agend 2.3.0-beta.11 → 2.3.0-beta.13
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 +6 -0
- package/README.zh-TW.md +6 -0
- package/dist/agent-whats-new.js +14 -9
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/channel/adapters/discord-client-retirement.d.ts +5 -0
- package/dist/channel/adapters/discord-client-retirement.js +57 -0
- package/dist/channel/adapters/discord-client-retirement.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +2 -0
- package/dist/channel/adapters/discord.js +14 -4
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/cli.js +12 -79
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +12 -0
- package/dist/config.js +13 -4
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +3 -0
- package/dist/daemon.js +25 -0
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +44 -2
- package/dist/fleet-manager.js +229 -63
- package/dist/fleet-manager.js.map +1 -1
- package/dist/fleet-process-handlers.d.ts +18 -0
- package/dist/fleet-process-handlers.js +69 -0
- package/dist/fleet-process-handlers.js.map +1 -0
- package/dist/general-knowledge/skills/fleet-config/SKILL.md +2 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +20 -3
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +27 -5
- package/dist/instance-lifecycle.d.ts +2 -0
- package/dist/instance-lifecycle.js +11 -6
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/outbound-schemas.d.ts +14 -1
- package/dist/outbound-schemas.js +8 -2
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +4 -0
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/restart-progress.d.ts +16 -1
- package/dist/restart-progress.js +74 -15
- package/dist/restart-progress.js.map +1 -1
- package/dist/settings-api.d.ts +4 -0
- package/dist/settings-api.js +27 -1
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-confirmation.d.ts +3 -1
- package/dist/settings-confirmation.js +2 -0
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-effect.js +2 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.d.ts +11 -0
- package/dist/settings-http-confirmation.js +10 -0
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/ui/app-effects.js +13 -1
- package/dist/ui/chat-effects.js +10 -3
- package/dist/ui/chat-store.js +32 -10
- package/dist/ui/chat-strings.js +18 -0
- package/dist/ui/chat-thread.js +5 -2
- package/dist/ui/effects-waker.js +70 -0
- package/dist/ui/fleet-canvas-layout.js +10 -4
- package/dist/ui/fleet-canvas.js +32 -2
- package/dist/ui/fleet-route-scene.js +207 -0
- package/dist/ui/fleet-route-worker.js +21 -0
- package/dist/ui/fleet-route.js +88 -0
- package/dist/ui/fleet-traffic.js +27 -11
- package/dist/ui/fleet-usage.js +35 -1
- package/dist/ui/panel-chat.js +67 -26
- package/dist/ui/panel-fleet.js +3 -3
- package/dist/ui/panel-settings.js +24 -0
- package/dist/ui/settings-appearance.js +2 -1
- package/dist/ui/settings-apply.js +3 -3
- package/dist/ui/settings-confirm.js +7 -2
- package/dist/ui/settings-owner-effects.js +6 -4
- package/dist/ui/settings-strings.js +2 -0
- package/dist/ui/shared/app-i18n.js +4 -0
- package/dist/ui/shared/app-prefs.js +12 -0
- package/dist/ui/shared/app-shell.js +38 -2
- package/dist/ui/shared/app-themes.js +116 -1
- package/dist/ui/shared/app.css +47 -3
- package/dist/ui/shared/card-strings.js +4 -0
- package/dist/ui/shared/effect-owner-source.js +8 -1
- package/dist/ui/shared/effect-registry.js +10 -2
- package/dist/ui/shared/identity-card.js +24 -6
- package/dist/ui/shared/identity-color.js +11 -7
- package/dist/ui/shared/owner-css.js +30 -1
- package/dist/ui/shared/ui-icons.js +2 -0
- package/dist/ui/shared/ui-menu.js +9 -3
- package/dist/ui/shared/web-authorize.js +47 -0
- package/dist/web-api.d.ts +6 -2
- package/dist/web-api.js +68 -15
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance.js +3 -1
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-effect.d.ts +1 -1
- package/dist/web-host-guard.d.ts +11 -0
- package/dist/web-host-guard.js +11 -0
- package/dist/web-host-guard.js.map +1 -1
- package/dist/web-libavoid.d.ts +14 -0
- package/dist/web-libavoid.js +46 -0
- package/dist/web-libavoid.js.map +1 -0
- package/dist/web-owner-css-store.d.ts +44 -1
- package/dist/web-owner-css-store.js +70 -9
- package/dist/web-owner-css-store.js.map +1 -1
- package/dist/web-prefs.js +13 -0
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-settings-tools.d.ts +5 -0
- package/dist/web-settings-tools.js +38 -7
- package/dist/web-settings-tools.js.map +1 -1
- package/dist/web-theme.d.ts +29 -0
- package/dist/web-theme.js +89 -1
- package/dist/web-theme.js.map +1 -1
- package/dist/yaml-shared-nodes.d.ts +25 -0
- package/dist/yaml-shared-nodes.js +185 -0
- package/dist/yaml-shared-nodes.js.map +1 -0
- package/package.json +2 -1
package/dist/web-api.js
CHANGED
|
@@ -21,7 +21,8 @@ import { formatWebChannelEcho } from "./web-channel-echo.js";
|
|
|
21
21
|
import { t } from "./locale.js";
|
|
22
22
|
import { isSafeInstanceName } from "./web-shell-routes.js";
|
|
23
23
|
import { MAX_COMMAND_ARGS } from "./web-commands.js";
|
|
24
|
-
import { sendPanelHtml } from "./web-host-guard.js";
|
|
24
|
+
import { ROUTE_WORKER_CSP, ROUTE_WORKER_PATH, sendPanelHtml } from "./web-host-guard.js";
|
|
25
|
+
import { libavoidFile } from "./web-libavoid.js";
|
|
25
26
|
import { shellRoute } from "./web-shell-routes.js";
|
|
26
27
|
import { createReadStream, createWriteStream, readFileSync } from "node:fs";
|
|
27
28
|
import { join, dirname } from "node:path";
|
|
@@ -280,7 +281,7 @@ function handleOwnerCss(req, res, url, ctx, path, method) {
|
|
|
280
281
|
json(res, removed.ok ? 200 : removed.status, removed.ok ? { ok: true } : { error: removed.error });
|
|
281
282
|
return true;
|
|
282
283
|
}
|
|
283
|
-
if (method !== "POST" || !["/ui/owner-css", "/ui/owner-css/keep", "/ui/owner-css/revert", "/ui/owner-css/restore", "/ui/owner-css/asset"].includes(path)) {
|
|
284
|
+
if (method !== "POST" || !["/ui/owner-css", "/ui/owner-css/shown", "/ui/owner-css/keep", "/ui/owner-css/revert", "/ui/owner-css/restore", "/ui/owner-css/asset"].includes(path)) {
|
|
284
285
|
json(res, 404, { error: "not found" });
|
|
285
286
|
return true;
|
|
286
287
|
}
|
|
@@ -329,6 +330,17 @@ function handleOwnerCss(req, res, url, ctx, path, method) {
|
|
|
329
330
|
announce();
|
|
330
331
|
json(res, 200, { sha: saved.sha, previous: saved.previous, trial: saved.trial });
|
|
331
332
|
}
|
|
333
|
+
else if (path === "/ui/owner-css/shown") {
|
|
334
|
+
// #2198: this page shows the trial (its stylesheet loaded): an agent's waiting trial starts its keep window now.
|
|
335
|
+
const shown = store.shown(person, body.trial);
|
|
336
|
+
if (!shown.ok) {
|
|
337
|
+
json(res, shown.status, { error: shown.error });
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
if (shown.started)
|
|
341
|
+
announce(); // the person's other devices take the new deadline
|
|
342
|
+
json(res, 200, { remaining_ms: shown.remaining_ms });
|
|
343
|
+
}
|
|
332
344
|
else if (path === "/ui/owner-css/keep") {
|
|
333
345
|
const kept = store.keep(person, body.trial);
|
|
334
346
|
if (!kept.ok) {
|
|
@@ -1010,6 +1022,9 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
1010
1022
|
try {
|
|
1011
1023
|
const js = readFileSync(join(__dirname, "ui", fileName), "utf-8");
|
|
1012
1024
|
res.setHeader("Content-Type", "application/javascript; charset=utf-8");
|
|
1025
|
+
// #2182: the route worker's own, narrower-reaching policy (ROUTE_WORKER_CSP); every other file keeps the page's.
|
|
1026
|
+
if (path === ROUTE_WORKER_PATH)
|
|
1027
|
+
res.setHeader("Content-Security-Policy", ROUTE_WORKER_CSP);
|
|
1013
1028
|
res.writeHead(200);
|
|
1014
1029
|
res.end(js);
|
|
1015
1030
|
}
|
|
@@ -1018,6 +1033,19 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
1018
1033
|
}
|
|
1019
1034
|
return true;
|
|
1020
1035
|
}
|
|
1036
|
+
// #2182: libavoid (libavoid-js, LGPL-2.1-or-later) — the npm package's own two files, unmodified, at a versioned path.
|
|
1037
|
+
const vendor = method === "GET" ? libavoidFile(path) : null;
|
|
1038
|
+
if (vendor) {
|
|
1039
|
+
try {
|
|
1040
|
+
const body = readFileSync(vendor.file);
|
|
1041
|
+
res.writeHead(200, { "Content-Type": vendor.type, "Cache-Control": "private, max-age=31536000, immutable" });
|
|
1042
|
+
res.end(body);
|
|
1043
|
+
}
|
|
1044
|
+
catch {
|
|
1045
|
+
json(res, 404, { error: "File not found" });
|
|
1046
|
+
}
|
|
1047
|
+
return true;
|
|
1048
|
+
}
|
|
1021
1049
|
// ── Backend detection ─────────────────────────────────
|
|
1022
1050
|
// #2072: the model a Settings field offers — the cached catalog of that backend (that instance's account's). Read only.
|
|
1023
1051
|
if (method === "GET" && path === "/ui/models") {
|
|
@@ -1908,7 +1936,7 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
1908
1936
|
return true;
|
|
1909
1937
|
}
|
|
1910
1938
|
// Own keys only: "constructor" is in every object and names no instance.
|
|
1911
|
-
const known = (ctx
|
|
1939
|
+
const known = registeredChatInstance(ctx, name) || ctx.daemons.has(name);
|
|
1912
1940
|
if (!ctx.cancelInstance || !known) {
|
|
1913
1941
|
json(res, 404, { error: `Instance not found: ${name}` });
|
|
1914
1942
|
return true;
|
|
@@ -2578,6 +2606,27 @@ function webEchoPreview(message, names) {
|
|
|
2578
2606
|
const truncated = message.length > 500 || preview.length > 1400;
|
|
2579
2607
|
return wellFormed(preview.slice(0, 1400)) + (truncated ? ` … (${t("web.echo_full_text")})` : "");
|
|
2580
2608
|
}
|
|
2609
|
+
/** Registration and liveness are different: a paused CLI may have neither daemon nor IPC. */
|
|
2610
|
+
function registeredChatInstance(ctx, name) {
|
|
2611
|
+
return (!!ctx.fleetConfig && Object.hasOwn(ctx.fleetConfig.instances, name)) || ctx.isClassicInstance?.(name) === true;
|
|
2612
|
+
}
|
|
2613
|
+
function uploadRecipient(ctx, name) {
|
|
2614
|
+
return registeredChatInstance(ctx, name)
|
|
2615
|
+
&& (ctx.instanceIpcClients.has(name) || ctx.getInstanceStatus?.(name) === "paused");
|
|
2616
|
+
}
|
|
2617
|
+
/** Closed, path-free explanations; arbitrary launch errors stay in the host log. */
|
|
2618
|
+
function webDeliveryFailure(err) {
|
|
2619
|
+
const message = err instanceof Error ? err.message : "";
|
|
2620
|
+
if (/No warm slot is free/.test(message))
|
|
2621
|
+
return { reason: "wake_capacity", error: "No slot is free to wake this instance. Retry when another instance is idle." };
|
|
2622
|
+
if (/login|log in|sign in|\bauth(?:entication|orization)?\b|credential|api.?key/i.test(message))
|
|
2623
|
+
return { reason: "wake_credentials", error: "The instance could not sign in. Check its account on the host, then retry." };
|
|
2624
|
+
if (/timed? out|timeout/i.test(message))
|
|
2625
|
+
return { reason: "wake_timeout", error: "The instance did not become ready in time. Retry, or check its status on the host." };
|
|
2626
|
+
if (/Cannot wake stopped|no longer configured/.test(message))
|
|
2627
|
+
return { reason: "instance_stopped", error: "This instance was stopped or removed. Start it on the host before retrying." };
|
|
2628
|
+
return { reason: "delivery_unavailable", error: "The instance could not receive this message. Check its status on the host, then retry." };
|
|
2629
|
+
}
|
|
2581
2630
|
/** Handle POST /ui/send — extracted for readability. */
|
|
2582
2631
|
function handleSendMessage(req, res, ctx) {
|
|
2583
2632
|
const arrival = webAuthorityOf(req, new URL(req.url ?? "/", "http://localhost"), ctx); // #1939 §3: again after the body
|
|
@@ -2615,8 +2664,8 @@ function handleSendMessage(req, res, ctx) {
|
|
|
2615
2664
|
json(res, 403, { error: "guest_no_commands" });
|
|
2616
2665
|
return;
|
|
2617
2666
|
}
|
|
2618
|
-
const
|
|
2619
|
-
if (!
|
|
2667
|
+
const registered = registeredChatInstance(ctx, instance);
|
|
2668
|
+
if (!registered && !ctx.instanceIpcClients.has(instance)) {
|
|
2620
2669
|
json(res, 404, { error: `Instance not found: ${instance}` });
|
|
2621
2670
|
return;
|
|
2622
2671
|
}
|
|
@@ -2639,6 +2688,12 @@ function handleSendMessage(req, res, ctx) {
|
|
|
2639
2688
|
json(res, 403, { error: t("web.raw_public_refused") });
|
|
2640
2689
|
return;
|
|
2641
2690
|
}
|
|
2691
|
+
// Recheck the same admission all the way through a wake, before the facade's actual IPC handoff.
|
|
2692
|
+
const requestUrl = new URL(req.url ?? "/", "http://localhost");
|
|
2693
|
+
const admission = admissionOf(req, requestUrl, ctx);
|
|
2694
|
+
const stillCurrent = () => !res.destroyed && admission !== null && admissionOf(req, requestUrl, ctx) === admission
|
|
2695
|
+
&& (!guest || (guest.current() && !guestChatRefusal(guest, instance)))
|
|
2696
|
+
&& (registered ? registeredChatInstance(ctx, instance) : ctx.instanceIpcClients.has(instance));
|
|
2642
2697
|
const message = typed;
|
|
2643
2698
|
// #1827: who is writing — the name agents and chats see, and the id they tell people apart by. Asked now that the
|
|
2644
2699
|
// body is in: a session revoked meanwhile sends nothing (not as the operator).
|
|
@@ -2685,8 +2740,8 @@ function handleSendMessage(req, res, ctx) {
|
|
|
2685
2740
|
let delivered;
|
|
2686
2741
|
try {
|
|
2687
2742
|
const deliver = (name, payload) => ctx.deliverHumanToInstance
|
|
2688
|
-
? ctx.deliverHumanToInstance(name, payload, webHumanOrigin(false, authority), typed)
|
|
2689
|
-
: ctx.deliverToInstance(name, payload);
|
|
2743
|
+
? ctx.deliverHumanToInstance(name, payload, webHumanOrigin(false, authority), typed, { stillCurrent })
|
|
2744
|
+
: ctx.deliverToInstance(name, payload, { stillCurrent });
|
|
2690
2745
|
delivered = await deliver(instance, {
|
|
2691
2746
|
type: "fleet_inbound",
|
|
2692
2747
|
content: delivery.text,
|
|
@@ -2712,7 +2767,7 @@ function handleSendMessage(req, res, ctx) {
|
|
|
2712
2767
|
settleClassicEcho?.(false);
|
|
2713
2768
|
ctx.webFiles?.release(files); // not delivered: the same ids can be sent again
|
|
2714
2769
|
ctx.logger.error({ err, instance }, "Web message delivery failed");
|
|
2715
|
-
json(res, 503,
|
|
2770
|
+
json(res, 503, webDeliveryFailure(err));
|
|
2716
2771
|
return;
|
|
2717
2772
|
}
|
|
2718
2773
|
if (delivered === false) {
|
|
@@ -2720,7 +2775,7 @@ function handleSendMessage(req, res, ctx) {
|
|
|
2720
2775
|
settleClassicEcho?.(false);
|
|
2721
2776
|
ctx.webFiles?.release(files);
|
|
2722
2777
|
ctx.logger.error({ instance }, "Web message not delivered (the instance went away or restarted)");
|
|
2723
|
-
json(res, 503, { error: "
|
|
2778
|
+
json(res, 503, { reason: "delivery_changed", error: "The session or instance changed before this message was sent. Sign in again if needed, then retry." });
|
|
2724
2779
|
return;
|
|
2725
2780
|
}
|
|
2726
2781
|
settleEcho?.(true);
|
|
@@ -2767,7 +2822,7 @@ function handleUpload(req, res, url, ctx) {
|
|
|
2767
2822
|
json(res, guestRefused.status, { error: guestRefused.error });
|
|
2768
2823
|
return;
|
|
2769
2824
|
}
|
|
2770
|
-
if (!instance || instance.length > 128 || !safeInstanceSegment(instance) || !ctx
|
|
2825
|
+
if (!instance || instance.length > 128 || !safeInstanceSegment(instance) || !uploadRecipient(ctx, instance)) {
|
|
2771
2826
|
json(res, 404, { error: `Instance not found: ${instance}` });
|
|
2772
2827
|
return;
|
|
2773
2828
|
}
|
|
@@ -2830,11 +2885,9 @@ function handleUpload(req, res, url, ctx) {
|
|
|
2830
2885
|
req.on("error", () => drop()); // the client went away
|
|
2831
2886
|
req.on("close", () => { if (!over && req.complete === false)
|
|
2832
2887
|
drop(); });
|
|
2833
|
-
//
|
|
2834
|
-
//
|
|
2835
|
-
|
|
2836
|
-
// in fleet.yaml, or as a ClassicBot room in classicBot.yaml. Asked when the body ends and again just before storing.
|
|
2837
|
-
const deliverable = () => ctx.instanceIpcClients.has(instance) && (!!ctx.fleetConfig?.instances?.[instance] || ctx.isClassicInstance?.(instance) === true);
|
|
2888
|
+
// Recheck registration and delivery readiness after both waits. A paused recipient may have no IPC;
|
|
2889
|
+
// staging a file never wakes it. A stopped or deleted recipient must not regain an upload id.
|
|
2890
|
+
const deliverable = () => uploadRecipient(ctx, instance);
|
|
2838
2891
|
const gone = () => drop(() => json(res, 404, { error: `Instance not found: ${instance}` }));
|
|
2839
2892
|
req.on("end", () => {
|
|
2840
2893
|
if (over)
|