@songsid/agend 2.3.3 → 2.3.4-beta.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/README.md +3 -3
- package/README.zh-TW.md +3 -3
- package/dist/agent-cli-instructions.md +1 -1
- package/dist/auth-api.d.ts +16 -3
- package/dist/auth-api.js +22 -6
- package/dist/auth-api.js.map +1 -1
- package/dist/authority/web-authority.d.ts +15 -1
- package/dist/authority/web-authority.js +27 -10
- package/dist/authority/web-authority.js.map +1 -1
- package/dist/backend/claude-code.js +11 -1
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.js +12 -0
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/types.d.ts +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/config-validator.js +18 -1
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.js +8 -1
- package/dist/daemon.js.map +1 -1
- package/dist/env-file.d.ts +2 -0
- package/dist/env-file.js +13 -8
- package/dist/env-file.js.map +1 -1
- package/dist/fleet-manager.d.ts +25 -1
- package/dist/fleet-manager.js +150 -21
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +1 -1
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +4 -0
- package/dist/general-knowledge/skills/worker-collaboration/SKILL.md +1 -1
- package/dist/instance-config-impact.js +1 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +2 -0
- package/dist/instance-lifecycle.js +23 -7
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +1 -1
- package/dist/instructions.js +1 -1
- package/dist/instructions.js.map +1 -1
- package/dist/interaction-observation.d.ts +1 -0
- package/dist/interaction-observation.js +1 -1
- package/dist/interaction-observation.js.map +1 -1
- package/dist/locale.js +48 -0
- package/dist/locale.js.map +1 -1
- package/dist/next-steps.d.ts +12 -2
- package/dist/next-steps.js +19 -3
- package/dist/next-steps.js.map +1 -1
- package/dist/office-share-service.d.ts +57 -0
- package/dist/office-share-service.js +76 -11
- package/dist/office-share-service.js.map +1 -1
- package/dist/office-share.d.ts +8 -0
- package/dist/office-share.js +34 -0
- package/dist/office-share.js.map +1 -1
- package/dist/outbound-schemas.js +1 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/page-share.d.ts +122 -0
- package/dist/page-share.js +199 -0
- package/dist/page-share.js.map +1 -0
- package/dist/public-preview.d.ts +4 -0
- package/dist/public-preview.js +5 -4
- package/dist/public-preview.js.map +1 -1
- package/dist/public-web-gateway.js +5 -0
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart-api.d.ts +5 -0
- package/dist/quickstart-api.js +1 -1
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +40 -0
- package/dist/quickstart.js +174 -28
- package/dist/quickstart.js.map +1 -1
- package/dist/remote-card-answer.js +2 -0
- package/dist/remote-card-answer.js.map +1 -1
- package/dist/remote-card-prompt.js +4 -2
- package/dist/remote-card-prompt.js.map +1 -1
- package/dist/selection-card.d.ts +21 -0
- package/dist/selection-card.js +129 -0
- package/dist/selection-card.js.map +1 -0
- package/dist/settings-api.js +4 -0
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +5 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +2 -0
- package/dist/settings-effect.js.map +1 -1
- package/dist/setup-host.js +2 -2
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +2 -2
- package/dist/setup-wizard.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/ui/chat-store.js +8 -1
- package/dist/ui/chat-strings.js +36 -0
- package/dist/ui/page-share-dialog.js +191 -0
- package/dist/ui/panel-chat.js +14 -0
- package/dist/ui/panel-notices.js +98 -0
- package/dist/ui/panel-settings.js +9 -2
- package/dist/ui/preview-pages.js +41 -0
- package/dist/ui/preview-panel-actions.js +161 -0
- package/dist/ui/preview-panel.js +209 -28
- package/dist/ui/preview-versions.js +155 -0
- package/dist/ui/preview.js +88 -3
- package/dist/ui/settings-registry.js +1 -0
- package/dist/ui/settings-strings.js +4 -0
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-route.js +4 -0
- package/dist/ui/shared/app-shell.js +5 -3
- package/dist/ui/shared/app-store.js +71 -1
- package/dist/ui/shared/app-stream.js +1 -1
- package/dist/ui/shared/app.css +43 -1
- package/dist/ui/shared/app.js +22 -1
- package/dist/ui/shared/signin.js +12 -1
- package/dist/ui/shared/ui-icons.js +3 -0
- package/dist/ui/shared/web-authorize.js +3 -1
- package/dist/web-api.d.ts +26 -0
- package/dist/web-api.js +180 -1
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +7 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-login.d.ts +2 -0
- package/dist/web-login.js +3 -1
- package/dist/web-login.js.map +1 -1
- package/dist/web-notices.d.ts +51 -0
- package/dist/web-notices.js +118 -0
- package/dist/web-notices.js.map +1 -0
- package/dist/web-only-fleet.d.ts +22 -0
- package/dist/web-only-fleet.js +13 -0
- package/dist/web-only-fleet.js.map +1 -0
- package/dist/web-preview.d.ts +32 -3
- package/dist/web-preview.js +52 -19
- package/dist/web-preview.js.map +1 -1
- package/dist/web-session.d.ts +7 -0
- package/dist/web-session.js +2 -0
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +3 -1
- package/dist/web-settings-patch.js +4 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +2 -0
- package/dist/web-shell-routes.js +3 -0
- package/dist/web-shell-routes.js.map +1 -1
- package/package.json +1 -1
package/dist/web-api.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { CANVAS_WORKER_EXPERIMENTAL_MESSAGE } from "./web-experimental.js";
|
|
2
|
+
import { daemonTopicMode } from "./web-only-fleet.js";
|
|
2
3
|
import { webHumanOrigin } from "./human-delivery-receipts.js";
|
|
3
4
|
import { classifyWebPeer, confirmAfterBody, noAuthority } from "./authority/web-authority.js";
|
|
4
5
|
import { guestChatRefusal, guestCommandText, guestDeliveries, GUEST_PREF_MAX_BYTES, GUEST_SEARCHES, guestFrameData, guestHistory, guestMessages, guestOwnPrefs, guestPollBody, guestPrefs, guestRequestOf, guestSeesMessage, guestStatus } from "./web-guest-access.js";
|
|
@@ -40,6 +41,7 @@ import { z } from "zod";
|
|
|
40
41
|
import { evaluateWebRequest, isPassiveWebRead, isSecureRequest, isWebRequestAuthorized, WEB_TOKEN_INVALID_MESSAGE } from "./web-auth.js";
|
|
41
42
|
import { dashboardOriginFor } from "./web-preview.js";
|
|
42
43
|
import { WEB_CHAT_CARDS_OVERFLOW, newWebMessageId, parseLastEventId, webChatReplyRef, webChatReplyText } from "./web-chat-history.js";
|
|
44
|
+
import { PAGE_SHARE_LIMITS, htmlFences, htmlTitle } from "./page-share.js";
|
|
43
45
|
import { attachmentDelivery, createPartFile, displayName, fileTooLargeText, INLINE_MIME, isFileId, MEDIA_RANGE_MAX, publicAttachment, UPLOAD_LIMITS, UPLOAD_MAX_MS, UPLOAD_STALL_MS, UploadSniffer, uploadLimits, wellFormed } from "./web-upload.js";
|
|
44
46
|
import { getAgendHome } from "./paths.js";
|
|
45
47
|
import { OPERATOR, isOwnerEffectKey } from "./web-prefs.js";
|
|
@@ -539,6 +541,140 @@ function handleOfficeShare(req, res, url, ctx, path, method) {
|
|
|
539
541
|
});
|
|
540
542
|
return true;
|
|
541
543
|
}
|
|
544
|
+
/**
|
|
545
|
+
* #2911 item 8: page share links — GET /ui/page-share (the open ones, and whether this fleet offers them), POST
|
|
546
|
+
* { instance, boot, id, fence | att, minutes? } (a new one: the server reads the HTML itself — the n-th complete ```html
|
|
547
|
+
* fence of that agent message, or its .html attachment — and answers the URL once the tunnel is up), DELETE
|
|
548
|
+
* /ui/page-share/<id|all>. The same admin check as the Office share's (handleOfficeShare): an admin session, directly
|
|
549
|
+
* or over the /web public link; never the CLI token, a read-only session or a guest. Asked again once the body is in.
|
|
550
|
+
*/
|
|
551
|
+
function handlePageShare(req, res, url, ctx, path, method) {
|
|
552
|
+
const service = ctx.officeShares;
|
|
553
|
+
if (!service?.createPage || !service.listPages || !service.revokePage || !service.pagesEnabled) {
|
|
554
|
+
json(res, 404, { error: "Page share links are not kept on this fleet" });
|
|
555
|
+
return true;
|
|
556
|
+
}
|
|
557
|
+
const one = /^\/ui\/page-share\/([0-9a-f]{8}|all)$/.exec(path);
|
|
558
|
+
const known = (method === "GET" && path === "/ui/page-share") || (method === "POST" && path === "/ui/page-share") || (method === "DELETE" && !!one);
|
|
559
|
+
if (!known) {
|
|
560
|
+
json(res, 404, { error: "not found" });
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
const who = () => {
|
|
564
|
+
const verdict = evaluateWebRequest(req, url, ctx.webToken ?? null, ctx.webSessions, { touch: false });
|
|
565
|
+
if (verdict.kind !== "allow")
|
|
566
|
+
return { status: 401 };
|
|
567
|
+
if (verdict.via !== "session" || verdict.session?.tier !== "admin")
|
|
568
|
+
return { status: 403 };
|
|
569
|
+
const owner = verdict.session.owner;
|
|
570
|
+
return { person: owner ? webPersonKey(owner) : "admin-session", name: owner ? ctx.webPerson?.(owner)?.name ?? owner.userId : "admin" };
|
|
571
|
+
};
|
|
572
|
+
const refuse = (status) => json(res, status, { error: status === 401 ? WEB_TOKEN_INVALID_MESSAGE : "page_share_needs_an_admin_session" });
|
|
573
|
+
const first = who();
|
|
574
|
+
if ("status" in first) {
|
|
575
|
+
refuse(first.status);
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
578
|
+
res.setHeader("Cache-Control", "no-store");
|
|
579
|
+
// `cdn`: whether a share made now may load the preview's CDN libraries (the confirm dialog says so).
|
|
580
|
+
if (method === "GET") {
|
|
581
|
+
json(res, 200, { enabled: service.pagesEnabled(), cdn: service.pagesCdn?.() === true, shares: service.listPages() });
|
|
582
|
+
return true;
|
|
583
|
+
}
|
|
584
|
+
if (method === "DELETE") {
|
|
585
|
+
// Its end is said in the instance's channel by the service's change listener (as an expiry is).
|
|
586
|
+
const n = service.revokePage(one[1]).length;
|
|
587
|
+
json(res, n ? 200 : 404, n ? { revoked: n } : { error: "not_found" });
|
|
588
|
+
return true;
|
|
589
|
+
}
|
|
590
|
+
(async () => {
|
|
591
|
+
let body;
|
|
592
|
+
try {
|
|
593
|
+
body = await parseBody(req);
|
|
594
|
+
}
|
|
595
|
+
catch {
|
|
596
|
+
json(res, 400, { error: "Invalid JSON" });
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
if (!permitWebContinuation(req, res, ctx))
|
|
600
|
+
return;
|
|
601
|
+
const now = who();
|
|
602
|
+
if ("status" in now) {
|
|
603
|
+
refuse(now.status);
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
const fence = body?.fence, att = body?.att;
|
|
607
|
+
if (!body || typeof body !== "object" || Array.isArray(body) || typeof body.instance !== "string" || !body.instance
|
|
608
|
+
|| typeof body.boot !== "string" || !/^[0-9a-f]{1,32}$/.test(body.boot) || !Number.isSafeInteger(body.id) || body.id < 1
|
|
609
|
+
|| (fence === undefined) === (att === undefined)
|
|
610
|
+
|| (fence !== undefined && (!Number.isInteger(fence) || fence < 0 || fence > 999))
|
|
611
|
+
|| (att !== undefined && (typeof att !== "string" || !isFileId(att)))
|
|
612
|
+
|| (body.minutes !== undefined && typeof body.minutes !== "number")) {
|
|
613
|
+
json(res, 400, { error: "instance, boot, id, and fence (number) or att (file id); minutes? (number)" });
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
const msg = ctx.webChatHistory?.find(body.instance, body.boot, body.id) ?? null;
|
|
617
|
+
if (!msg || msg.instance !== body.instance) {
|
|
618
|
+
json(res, 404, { error: "message_gone" });
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
if (msg.role !== "agent") {
|
|
622
|
+
json(res, 400, { error: "not_an_agent_page" });
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
let html, name = "";
|
|
626
|
+
if (fence !== undefined) {
|
|
627
|
+
const f = htmlFences(msg.text)[fence];
|
|
628
|
+
if (!f || !f.terminated) {
|
|
629
|
+
json(res, 404, { error: "page_gone" });
|
|
630
|
+
return;
|
|
631
|
+
}
|
|
632
|
+
html = f.code;
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
const a = (msg.attachments ?? []).find((x) => !("gone" in x) && x.id === att);
|
|
636
|
+
if (!a || a.kind === "photo" || !/\.html?$/i.test(a.name.trim())) {
|
|
637
|
+
json(res, 404, { error: "page_gone" });
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
const served = ctx.webFiles?.servedFile?.(a.id) ?? null;
|
|
641
|
+
if (!served) {
|
|
642
|
+
json(res, 404, { error: "page_gone" });
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
if (served.size > PAGE_SHARE_LIMITS.maxBytes) {
|
|
646
|
+
json(res, 413, { error: "too_large" });
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
const read = ctx.webFiles?.read?.(a.id) ?? null;
|
|
650
|
+
if (!read) {
|
|
651
|
+
json(res, 404, { error: "page_gone" });
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
html = read.bytes.toString("utf8");
|
|
655
|
+
name = a.name;
|
|
656
|
+
}
|
|
657
|
+
const from = { boot: body.boot, id: body.id, ...(fence !== undefined ? { fence: fence } : { att: att }) };
|
|
658
|
+
// The caller is asked again once the tunnel is up (#2917 review P2): the same admin, the session still live.
|
|
659
|
+
const stillAllowed = () => { const currentCaller = who(); return !("status" in currentCaller) && currentCaller.person === now.person; };
|
|
660
|
+
const made = await service.createPage({ html, instance: body.instance, title: htmlTitle(html) || name, owner: now.person, from, stillAllowed,
|
|
661
|
+
...(typeof body.minutes === "number" ? { minutes: body.minutes } : {}) });
|
|
662
|
+
if (!made.ok) {
|
|
663
|
+
const status = made.error === "disabled" ? 404 : made.error === "tunnel" ? 503 : made.error === "too_many" ? 409 : made.error === "too_large" ? 413 : made.error === "not_allowed" ? 403 : 400;
|
|
664
|
+
json(res, status, { error: made.error, ...(made.reason ? { reason: made.reason } : {}) });
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
ctx.pageShareNotice?.(now.name, made.share);
|
|
668
|
+
json(res, 200, { share: made.share, url: made.url });
|
|
669
|
+
})().catch(err => {
|
|
670
|
+
ctx.logger.error({ err: err.message }, "Page share failed");
|
|
671
|
+
try {
|
|
672
|
+
json(res, 500, { error: "Page share failed" });
|
|
673
|
+
}
|
|
674
|
+
catch { /* already answered */ }
|
|
675
|
+
});
|
|
676
|
+
return true;
|
|
677
|
+
}
|
|
542
678
|
/**
|
|
543
679
|
* #2513: the Office view's skin packs (web-office-skins.ts). The reads are the offices' (GET /ui/offices): whoever may
|
|
544
680
|
* open the org chart, the public link too (its manifest lists them; a guest's routes do not): the list, a pack's
|
|
@@ -2400,6 +2536,8 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
2400
2536
|
return handleOfficePackChanges(req, res, url, ctx, path, method);
|
|
2401
2537
|
if (path === "/ui/office-share" || path.startsWith("/ui/office-share/"))
|
|
2402
2538
|
return handleOfficeShare(req, res, url, ctx, path, method);
|
|
2539
|
+
if (path === "/ui/page-share" || path.startsWith("/ui/page-share/"))
|
|
2540
|
+
return handlePageShare(req, res, url, ctx, path, method);
|
|
2403
2541
|
// ── #1630: avatars and Discord server emoji, same-origin (the page never loads a platform's CDN; img-src stays 'self') ──
|
|
2404
2542
|
const imageMatch = path.match(/^\/ui\/img\/(bot|avatar|emoji)\/([^/]+)$/);
|
|
2405
2543
|
if (method === "GET" && imageMatch) {
|
|
@@ -2741,6 +2879,47 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
2741
2879
|
return handleBackendLogin(req, res, url, ctx, path, method);
|
|
2742
2880
|
// #1386: Acknowledge a "Needs you" delivery item — a session write (CSRF, checked by the gate) or the CLI's header
|
|
2743
2881
|
// token. Who did it is recorded by principal: the session's public handle, never the session id or a credential.
|
|
2882
|
+
// #2910 D2: a web-only fleet's Notices — what General would have said. Admins only (never a guest: not in
|
|
2883
|
+
// GUEST_ROUTES). GET /ui/notices/list lists them; POST /ui/notices/seen {id} marks everything up to it read (a session write).
|
|
2884
|
+
if (path === "/ui/notices/list" && method === "GET") {
|
|
2885
|
+
const feed = ctx.webNoticesFeed?.() ?? null;
|
|
2886
|
+
res.setHeader("Cache-Control", "no-store");
|
|
2887
|
+
json(res, 200, feed ? { enabled: true, ...feed.view() } : { enabled: false, items: [], seen: 0, unread: 0 });
|
|
2888
|
+
return true;
|
|
2889
|
+
}
|
|
2890
|
+
if (path === "/ui/notices/seen" && method === "POST") {
|
|
2891
|
+
(async () => {
|
|
2892
|
+
let body;
|
|
2893
|
+
try {
|
|
2894
|
+
body = await parseBody(req);
|
|
2895
|
+
}
|
|
2896
|
+
catch {
|
|
2897
|
+
json(res, 400, { error: "Invalid JSON" });
|
|
2898
|
+
return;
|
|
2899
|
+
}
|
|
2900
|
+
if (!permitWebContinuation(req, res, ctx))
|
|
2901
|
+
return;
|
|
2902
|
+
const id = body && typeof body === "object" ? body.id : undefined;
|
|
2903
|
+
if (typeof id !== "number" || !Number.isSafeInteger(id) || id < 0) {
|
|
2904
|
+
json(res, 400, { error: "id required" });
|
|
2905
|
+
return;
|
|
2906
|
+
}
|
|
2907
|
+
const feed = ctx.webNoticesFeed?.() ?? null;
|
|
2908
|
+
if (!feed) {
|
|
2909
|
+
json(res, 404, { error: "No notices here" });
|
|
2910
|
+
return;
|
|
2911
|
+
}
|
|
2912
|
+
const seen = feed.markSeen(id);
|
|
2913
|
+
json(res, 200, { seen, unread: feed.unread() });
|
|
2914
|
+
})().catch(err => {
|
|
2915
|
+
ctx.logger.error({ err: err.message }, "Notices mark-read failed");
|
|
2916
|
+
try {
|
|
2917
|
+
json(res, 500, { error: "Mark read failed" });
|
|
2918
|
+
}
|
|
2919
|
+
catch { /* already answered */ }
|
|
2920
|
+
});
|
|
2921
|
+
return true;
|
|
2922
|
+
}
|
|
2744
2923
|
if (method === "POST" && path === "/ui/needs/ack") {
|
|
2745
2924
|
if (!ctx.acknowledgeNeedsItem) {
|
|
2746
2925
|
json(res, 404, { error: "Nothing to acknowledge here" });
|
|
@@ -2979,7 +3158,7 @@ export function handleWebRequest(req, res, url, ctx) {
|
|
|
2979
3158
|
json(res, 404, { error: `Instance not found: ${name}` });
|
|
2980
3159
|
return true;
|
|
2981
3160
|
}
|
|
2982
|
-
const topicMode = ctx.fleetConfig
|
|
3161
|
+
const topicMode = daemonTopicMode(ctx.fleetConfig);
|
|
2983
3162
|
(async () => {
|
|
2984
3163
|
let held = false;
|
|
2985
3164
|
try {
|