@songsid/agend 2.3.3-beta.4 → 2.3.3-beta.6
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/dist/agent-cli.js +13 -112
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +0 -1
- package/dist/agent-endpoint.js +1 -9
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-whats-new.d.ts +3 -6
- package/dist/agent-whats-new.js +7 -18
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.d.ts +0 -7
- package/dist/auth-api.js +1 -15
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/claude-code.js +4 -2
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.d.ts +1 -0
- package/dist/backend/codex.js +106 -15
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok.js +57 -11
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/types.d.ts +35 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/bundled-skills.d.ts +4 -6
- package/dist/bundled-skills.js +10 -14
- package/dist/bundled-skills.js.map +1 -1
- package/dist/channel/mcp-server.js +5 -5
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.d.ts +1 -3
- package/dist/channel/mcp-tools.js +4 -58
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.js +6 -3
- package/dist/config-validator.js.map +1 -1
- package/dist/daemon.d.ts +17 -3
- package/dist/daemon.js +76 -107
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard-live.d.ts +1 -1
- package/dist/dashboard-live.js +3 -3
- package/dist/dashboard-live.js.map +1 -1
- package/dist/dashboard-permissions.d.ts +1 -1
- package/dist/dashboard-permissions.js +1 -3
- package/dist/dashboard-permissions.js.map +1 -1
- package/dist/fleet-manager.d.ts +31 -44
- package/dist/fleet-manager.js +94 -227
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +11 -1
- package/dist/general-knowledge/skills/session-management/SKILL.md +6 -0
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +13 -204
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +26 -63
- package/dist/instance-lifecycle.d.ts +6 -0
- package/dist/instance-lifecycle.js +20 -4
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +14 -4
- package/dist/locale.js.map +1 -1
- package/dist/outbound-handlers.js +19 -7
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +0 -62
- package/dist/outbound-schemas.js +3 -42
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +0 -9
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/public-web-link.d.ts +2 -0
- package/dist/public-web-link.js +5 -0
- package/dist/public-web-link.js.map +1 -1
- package/dist/search/search-docs.d.ts +1 -1
- package/dist/search/search-docs.js +2 -2
- package/dist/search/search-docs.js.map +1 -1
- package/dist/settings-api.d.ts +6 -0
- package/dist/settings-api.js +14 -2
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +3 -1
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-confirmation.d.ts +17 -3
- package/dist/settings-confirmation.js +8 -5
- package/dist/settings-confirmation.js.map +1 -1
- package/dist/settings-http-confirmation.js +31 -1
- package/dist/settings-http-confirmation.js.map +1 -1
- package/dist/tool-permissions.js +3 -10
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +27 -7
- package/dist/topic-commands.js +94 -36
- package/dist/topic-commands.js.map +1 -1
- package/dist/types.d.ts +2 -1
- package/dist/ui/chat-ambient.js +4 -4
- package/dist/ui/chat-commands.js +3 -2
- package/dist/ui/chat-store.js +4 -1
- package/dist/ui/chat-strings.js +12 -46
- package/dist/ui/chat-thread.js +51 -59
- package/dist/ui/fleet-office-skin.js +37 -14
- package/dist/ui/fleet-office.js +31 -7
- package/dist/ui/html-attachment.js +22 -8
- package/dist/ui/panel-chat.js +21 -50
- package/dist/ui/preview-panel.js +12 -21
- package/dist/ui/preview.js +10 -3
- package/dist/ui/search-dialog.js +30 -14
- package/dist/ui/settings-appearance.js +1 -3
- package/dist/ui/settings-confirm.js +18 -0
- package/dist/ui/settings-guests.js +13 -4
- package/dist/ui/settings-learn.js +1 -1
- package/dist/ui/settings-mods.js +5 -12
- package/dist/ui/settings-registry.js +0 -1
- package/dist/ui/settings-strings.js +6 -6
- package/dist/ui/shared/app-i18n.js +13 -2
- package/dist/ui/shared/app-prefs.js +17 -17
- package/dist/ui/shared/app-shell.js +47 -9
- package/dist/ui/shared/app-store.js +6 -2
- package/dist/ui/shared/app.css +19 -36
- package/dist/ui/shared/app.js +5 -4
- package/dist/ui/shared/instance-nav.js +9 -9
- package/dist/ui/shared/instance-switch.js +8 -2
- package/dist/ui/shared/panel-view.js +22 -8
- package/dist/ui/shared/view-strings.js +6 -0
- package/dist/usage/usage-api.d.ts +3 -0
- package/dist/usage/usage-api.js +5 -1
- package/dist/usage/usage-api.js.map +1 -1
- package/dist/view-api.d.ts +2 -0
- package/dist/view-api.js +64 -0
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +9 -17
- package/dist/web-api.js +255 -371
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-tools.d.ts +0 -2
- package/dist/web-appearance-tools.js +2 -5
- package/dist/web-appearance-tools.js.map +1 -1
- package/dist/web-appearance-view.d.ts +0 -6
- package/dist/web-appearance-view.js +0 -1
- package/dist/web-appearance-view.js.map +1 -1
- package/dist/web-appearance.d.ts +14 -7
- package/dist/web-appearance.js +5 -6
- package/dist/web-appearance.js.map +1 -1
- package/dist/web-asset-parts.d.ts +1 -17
- package/dist/web-asset-parts.js +1 -15
- package/dist/web-asset-parts.js.map +1 -1
- package/dist/web-auth.js +1 -7
- package/dist/web-auth.js.map +1 -1
- package/dist/web-chat-history.d.ts +3 -7
- package/dist/web-chat-history.js +10 -17
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +9 -1
- package/dist/web-commands.js +13 -0
- package/dist/web-commands.js.map +1 -1
- package/dist/web-experimental.d.ts +2 -11
- package/dist/web-experimental.js +8 -36
- package/dist/web-experimental.js.map +1 -1
- package/dist/web-guest-access.d.ts +40 -2
- package/dist/web-guest-access.js +50 -14
- package/dist/web-guest-access.js.map +1 -1
- package/dist/web-mod-bundle.d.ts +2 -45
- package/dist/web-mod-bundle.js +15 -63
- package/dist/web-mod-bundle.js.map +1 -1
- package/dist/web-mod-store.d.ts +3 -48
- package/dist/web-mod-store.js +30 -97
- package/dist/web-mod-store.js.map +1 -1
- package/dist/web-prefs.d.ts +13 -0
- package/dist/web-prefs.js +38 -0
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +6 -13
- package/dist/web-preview.js +12 -23
- package/dist/web-preview.js.map +1 -1
- package/dist/web-session.d.ts +11 -3
- package/dist/web-session.js +22 -11
- package/dist/web-session.js.map +1 -1
- package/dist/web-settings-patch.d.ts +1 -0
- package/dist/web-settings-patch.js +6 -3
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-settings-tools.d.ts +0 -13
- package/dist/web-settings-tools.js +12 -84
- package/dist/web-settings-tools.js.map +1 -1
- package/package.json +1 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +0 -376
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +0 -672
- package/dist/ui/app-effects.js +0 -251
- package/dist/ui/chat-effect-posters.js +0 -42
- package/dist/ui/chat-effects.js +0 -167
- package/dist/ui/effect-trial-controller.js +0 -124
- package/dist/ui/effect-trial-offer.js +0 -2
- package/dist/ui/effect-trial-panel.js +0 -40
- package/dist/ui/effects-waker.js +0 -2
- package/dist/ui/settings-effects.js +0 -202
- package/dist/ui/settings-owner-effects.js +0 -82
- package/dist/ui/shared/effect-app-runtime.js +0 -299
- package/dist/ui/shared/effect-baseline.js +0 -64
- package/dist/ui/shared/effect-chat-runtime.js +0 -162
- package/dist/ui/shared/effect-cursor.js +0 -126
- package/dist/ui/shared/effect-display-metadata.js +0 -39
- package/dist/ui/shared/effect-frame.js +0 -146
- package/dist/ui/shared/effect-geometry.js +0 -137
- package/dist/ui/shared/effect-host-style.js +0 -10
- package/dist/ui/shared/effect-owner-regions.js +0 -74
- package/dist/ui/shared/effect-owner-source.js +0 -122
- package/dist/ui/shared/effect-policy.js +0 -151
- package/dist/ui/shared/effect-poster-reader.js +0 -98
- package/dist/ui/shared/effect-posters.js +0 -117
- package/dist/ui/shared/effect-profiler.js +0 -184
- package/dist/ui/shared/effect-profiles.js +0 -65
- package/dist/ui/shared/effect-registry.js +0 -545
- package/dist/ui/shared/effect-runtime-loader.js +0 -236
- package/dist/ui/shared/effect-safety.js +0 -153
- package/dist/ui/shared/effect-stock-snapshot.js +0 -43
- package/dist/ui/shared/effect-stock-trust.js +0 -217
- package/dist/ui/shared/effect-trial-shadow.js +0 -62
- package/dist/ui/shared/effect-trial-source.js +0 -103
- package/dist/ui/shared/effect-trial-stage.js +0 -170
- package/dist/ui/shared/effect-trial.css +0 -40
- package/dist/ui/shared/feature-flags.js +0 -127
- package/dist/ui/shared/owner-effect-prefs.js +0 -117
- package/dist/web-effect-bootstrap.d.ts +0 -12
- package/dist/web-effect-bootstrap.js +0 -49
- package/dist/web-effect-bootstrap.js.map +0 -1
- package/dist/web-effect-bundle.d.ts +0 -28
- package/dist/web-effect-bundle.js +0 -171
- package/dist/web-effect-bundle.js.map +0 -1
- package/dist/web-effect-canonical.d.ts +0 -8
- package/dist/web-effect-canonical.js +0 -27
- package/dist/web-effect-canonical.js.map +0 -1
- package/dist/web-effect-library.d.ts +0 -114
- package/dist/web-effect-library.js +0 -530
- package/dist/web-effect-library.js.map +0 -1
- package/dist/web-effect-playback.d.ts +0 -30
- package/dist/web-effect-playback.js +0 -71
- package/dist/web-effect-playback.js.map +0 -1
- package/dist/web-effect-poster.d.ts +0 -8
- package/dist/web-effect-poster.js +0 -52
- package/dist/web-effect-poster.js.map +0 -1
- package/dist/web-effect-profiles.d.ts +0 -118
- package/dist/web-effect-profiles.js +0 -181
- package/dist/web-effect-profiles.js.map +0 -1
- package/dist/web-effect-service.d.ts +0 -93
- package/dist/web-effect-service.js +0 -335
- package/dist/web-effect-service.js.map +0 -1
- package/dist/web-effect-tools.d.ts +0 -48
- package/dist/web-effect-tools.js +0 -129
- package/dist/web-effect-tools.js.map +0 -1
- package/dist/web-effect-trials.d.ts +0 -86
- package/dist/web-effect-trials.js +0 -204
- package/dist/web-effect-trials.js.map +0 -1
- package/dist/web-effect-upload.d.ts +0 -27
- package/dist/web-effect-upload.js +0 -185
- package/dist/web-effect-upload.js.map +0 -1
- package/dist/web-effect-worker.d.ts +0 -8
- package/dist/web-effect-worker.js +0 -170
- package/dist/web-effect-worker.js.map +0 -1
- package/dist/web-effect.d.ts +0 -103
- package/dist/web-effect.js +0 -153
- package/dist/web-effect.js.map +0 -1
- package/dist/web-experimental-http.d.ts +0 -2
- package/dist/web-experimental-http.js +0 -12
- package/dist/web-experimental-http.js.map +0 -1
- package/dist/web-mod-agent.d.ts +0 -50
- package/dist/web-mod-agent.js +0 -207
- package/dist/web-mod-agent.js.map +0 -1
package/dist/fleet-manager.js
CHANGED
|
@@ -176,13 +176,6 @@ import { OfficeSkinStore } from "./web-office-skins.js";
|
|
|
176
176
|
import { OfficeActs } from "./web-office-acts.js";
|
|
177
177
|
import { OFFICE_PACK_TOOLS, OfficePackTools } from "./web-office-pack-tools.js";
|
|
178
178
|
import { WebAppearance } from "./web-appearance.js";
|
|
179
|
-
import { WebEffectLibrary } from "./web-effect-library.js";
|
|
180
|
-
import { WebEffectTrials } from "./web-effect-trials.js";
|
|
181
|
-
import { WebEffectService } from "./web-effect-service.js";
|
|
182
|
-
import { WebEffectProfiles } from "./web-effect-profiles.js";
|
|
183
|
-
import { WebEffectTools, WEB_EFFECT_TOOLS } from "./web-effect-tools.js";
|
|
184
|
-
import { resolveEffectParams } from "./web-effect.js";
|
|
185
|
-
import { cw1EffectChecker } from "./web-mod-bundle.js";
|
|
186
179
|
import { effectiveAppearanceLimits } from "./web-appearance-limits.js";
|
|
187
180
|
import { WEB_NAME_FALLBACK, safeWebName, validateWebName, webNameInUse, webPersonKey } from "./web-profile.js";
|
|
188
181
|
import { ReplyButtonStore, parseReplyButtons, replyButtonClickText, replyButtonsFallbackText, REPLY_BUTTON_PREFIX } from "./reply-buttons.js";
|
|
@@ -195,7 +188,6 @@ import { autoIdentityColor } from "./web-identity-color.js";
|
|
|
195
188
|
import { AppearanceTools } from "./web-appearance-tools.js";
|
|
196
189
|
import { cardVersion, resolveCard } from "./web-card.js";
|
|
197
190
|
import { ModStore } from "./web-mod-store.js";
|
|
198
|
-
import { AgentMods } from "./web-mod-agent.js";
|
|
199
191
|
import { downloadStickerImage } from "./channel/sticker-download.js";
|
|
200
192
|
import { WebImageCache, imageMimeForFile, WEB_IMAGE_MAX_AGE_MS, WEB_IMAGE_MAX_BYTES, WEB_IMAGE_RETRY_MS } from "./web-images.js";
|
|
201
193
|
import { accentColor, avatarFor, ownBotConnections } from "./instance-avatar.js";
|
|
@@ -214,7 +206,7 @@ import { crossInstanceVisibility, runVisibilityCommand, xmsgVisibility } from ".
|
|
|
214
206
|
import { SEARCH_RETENTION_DAYS, SearchIndex } from "./search/search-index.js";
|
|
215
207
|
import { chatDoc, taskDoc, xmsgDoc } from "./search/search-docs.js";
|
|
216
208
|
import { WebSettingsTools } from "./web-settings-tools.js";
|
|
217
|
-
import { bindGuestRequest, guestRouteDecision } from "./web-guest-access.js";
|
|
209
|
+
import { GUEST_COMMAND_RUNS, GUEST_PREF_WRITES, GUEST_SEARCHES, bindGuestRequest, guestRouteDecision } from "./web-guest-access.js";
|
|
218
210
|
import { GUEST_ROOM_TICK_MS, GuestRoomMembership, guestGroupRooms } from "./web-guest-rooms.js";
|
|
219
211
|
import { Delegations, TrafficLog, trafficItem } from "./fleet-traffic.js";
|
|
220
212
|
import { installedChannel, updateNoticeKey } from "./update-check.js";
|
|
@@ -259,14 +251,14 @@ import { buildOrgChart } from "./web-org.js";
|
|
|
259
251
|
import { topMemoryHogs } from "./memory-hogs.js";
|
|
260
252
|
import { GENERAL_POINTING_REFUSALS, SNOWFLAKE, hasPlaceRefs, placeRef, webRoute, webTextLinks, placeSuffix, renderPlaceRefs, stripPlaceRefs, topicUrl, worldPlaceOf } from "./topic-link.js";
|
|
261
253
|
import { CacheService, cacheWindow } from "./cache-service.js";
|
|
262
|
-
import { runWebCommand } from "./web-commands.js";
|
|
254
|
+
import { guestWebCommands, runWebCommand } from "./web-commands.js";
|
|
263
255
|
import { CompactWatch, launchIdentity } from "./compact-watch.js";
|
|
264
256
|
import { agyLegacyAgentsFile, danglingSymlink, migrateAgyAgentsFile } from "./backend/antigravity.js";
|
|
265
257
|
import { claudeConfigDirFor, claudeProjectKey } from "./backend/claude-code.js";
|
|
266
258
|
import { sharedRolloutIndex } from "./rollout-index.js";
|
|
267
259
|
import { TASK_BOARD_ON_NOTICE, dashboardRefusalIn, taskBoardSwitchedOn } from "./dashboard-permissions.js";
|
|
268
260
|
import { mayUseTool, resolveToolSet, scheduleOpRefusal, toolForIpcType, toolRefusedMessage, } from "./tool-permissions.js";
|
|
269
|
-
import { authorizeSession, decideWebGate, loadOrCreateWebToken, readWebToken, sessionCookieUpgrade } from "./web-auth.js";
|
|
261
|
+
import { authorizeSession, decideWebGate, loadOrCreateWebToken, readSessionCookies, readWebToken, sessionCookieUpgrade } from "./web-auth.js";
|
|
270
262
|
import { bypassesWebGate, handleAuthRequest, serveGuestRefusedPage, serveSigninPage } from "./auth-api.js";
|
|
271
263
|
import { isWebPageNavigation } from "./web-shell-routes.js";
|
|
272
264
|
import { guestSessionPolicy, localSessionPolicy, tokenEpoch, WebSessionStore } from "./web-session.js";
|
|
@@ -279,10 +271,8 @@ import { decisionListAnswer } from "./decision-list.js";
|
|
|
279
271
|
import { CodeRequestLimiter, ReturningDevices } from "./web-returning-device.js";
|
|
280
272
|
import { allowedHostNames, applyWebSecurityHeaders, hostnameOf, isHostAllowed, LOOPBACK_HOST_NAMES, WEB_HOST_REJECTED_MESSAGE } from "./web-host-guard.js";
|
|
281
273
|
import { createPreviewListener, normalizeOrigin, previewAvailability, previewSettings } from "./web-preview.js";
|
|
282
|
-
import {
|
|
283
|
-
import { isCanvasWorkerHttpPath } from "./web-experimental-http.js";
|
|
274
|
+
import { isCanvasWorkerTool, CANVAS_WORKER_EXPERIMENTAL_MESSAGE } from "./web-experimental.js";
|
|
284
275
|
import { bundledSkillContents } from "./bundled-skills.js";
|
|
285
|
-
import { createEffectBootstrap } from "./web-effect-bootstrap.js";
|
|
286
276
|
import { fleetLevelDifferences, fleetLevelSignature, appendedConnections } from "./fleet-level-config.js";
|
|
287
277
|
import { checkSelfRestartAllowance, recordSelfRestartAttempt } from "./self-restart-limit.js";
|
|
288
278
|
import { SecretStore } from "./secret-store.js";
|
|
@@ -988,11 +978,6 @@ export class FleetManager {
|
|
|
988
978
|
collabInstances = new Set();
|
|
989
979
|
// Health endpoint
|
|
990
980
|
healthServer = null;
|
|
991
|
-
/** #2118: independent of HTML preview availability/port; fixed bootstrap only, no effect resources. */
|
|
992
|
-
effectBootstrap = createEffectBootstrap();
|
|
993
|
-
/** Fixed trusted document coherence, independent of the HTML preview listener; never a resource grant. */
|
|
994
|
-
get effectBoot() { return this.effectBootstrap.boot; }
|
|
995
|
-
canvasWorkerEnabled() { return canvasWorkerEnabled(this.fleetConfig?.web); }
|
|
996
981
|
healthServerDrain = null;
|
|
997
982
|
/** #1306: the preview listener (health_port + 1 by default), and whether it is listening. */
|
|
998
983
|
previewListener = null;
|
|
@@ -1171,7 +1156,7 @@ export class FleetManager {
|
|
|
1171
1156
|
/** #1629: every instance's theme, placements, assets and lock (web-themes.json). */
|
|
1172
1157
|
get themeStore() {
|
|
1173
1158
|
// r4.1 Q3 (b): the card's limits are read from fleet.yaml at each upload (a change applies without a restart).
|
|
1174
|
-
return (this.themeStoreInstance ??= new ThemeStore(this.dataDir, { limits: () => effectiveAppearanceLimits(this.fleetConfig?.web?.appearance).limits
|
|
1159
|
+
return (this.themeStoreInstance ??= new ThemeStore(this.dataDir, { limits: () => effectiveAppearanceLimits(this.fleetConfig?.web?.appearance).limits }));
|
|
1175
1160
|
}
|
|
1176
1161
|
officeStoreInstance;
|
|
1177
1162
|
/** Fleet → Org chart → Office: the offices people made (web-offices.json, beside web-themes.json). */
|
|
@@ -1183,6 +1168,12 @@ export class FleetManager {
|
|
|
1183
1168
|
officeSkinWrites = new OfficeWriteLimiter(undefined, { perWindow: 10, windowMs: 60_000 });
|
|
1184
1169
|
/** How often a person may save the offices (PUT /ui/offices); memory only, as the appearance limiter. */
|
|
1185
1170
|
officeWrites = new OfficeWriteLimiter();
|
|
1171
|
+
/** #2855: a guest's preference saves, per account. */
|
|
1172
|
+
guestPrefWrites = new OfficeWriteLimiter(undefined, GUEST_PREF_WRITES);
|
|
1173
|
+
/** #2855: a guest's commands, per account. */
|
|
1174
|
+
guestCommandRuns = new OfficeWriteLimiter(undefined, GUEST_COMMAND_RUNS);
|
|
1175
|
+
/** #2855: a trusted guest's searches, per account. */
|
|
1176
|
+
guestSearches = new OfficeWriteLimiter(undefined, { perWindow: GUEST_SEARCHES.perWindow, windowMs: GUEST_SEARCHES.windowMs });
|
|
1186
1177
|
officeSharesInstance;
|
|
1187
1178
|
/**
|
|
1188
1179
|
* #2636: Office share links — the live Office view for people outside the fleet, read-only, on a quick tunnel of
|
|
@@ -1378,96 +1369,16 @@ export class FleetManager {
|
|
|
1378
1369
|
}
|
|
1379
1370
|
catch { /* the next frame carries the rev */ } }));
|
|
1380
1371
|
}
|
|
1381
|
-
effectLibraryInstance;
|
|
1382
|
-
effectTrialsInstance;
|
|
1383
|
-
/** Lazy, single-owner storage. Register every host reference source before any operation can collect. */
|
|
1384
|
-
get effectLibrary() {
|
|
1385
|
-
if (!this.effectLibraryInstance) {
|
|
1386
|
-
const library = new WebEffectLibrary(this.dataDir);
|
|
1387
|
-
// Providers are lazy; publish only after every registration succeeds.
|
|
1388
|
-
library.registerReferenceSource("themes", () => {
|
|
1389
|
-
if (!this.themeStore.readable())
|
|
1390
|
-
throw new Error("themes_unreadable");
|
|
1391
|
-
return this.themeStore.placedEffects().flatMap(row => row.ids.map(id => ({ id, holder: `instance:${row.name}` })));
|
|
1392
|
-
});
|
|
1393
|
-
library.registerReferenceSource("prefs", () => this.webPrefs.ownerEffectReferences());
|
|
1394
|
-
library.registerReferenceSource("mods", () => {
|
|
1395
|
-
const mods = this.mods.list();
|
|
1396
|
-
if (mods.unreadable)
|
|
1397
|
-
throw new Error("mods_unreadable");
|
|
1398
|
-
return mods.mods.flatMap(mod => mod.effects.map(effect => ({ id: effect.id, holder: `mod:${mod.id}` })));
|
|
1399
|
-
});
|
|
1400
|
-
this.effectTrialsInstance = new WebEffectTrials({ library, known: name => this.isKnownInstance(name) });
|
|
1401
|
-
this.effectLibraryInstance = library;
|
|
1402
|
-
}
|
|
1403
|
-
return this.effectLibraryInstance;
|
|
1404
|
-
}
|
|
1405
|
-
/** Volatile Try offers and session-bound runs share this library. */
|
|
1406
|
-
get effectTrials() { if (!this.effectTrialsInstance)
|
|
1407
|
-
void this.effectLibrary; return this.effectTrialsInstance; }
|
|
1408
|
-
effectProfilesInstance;
|
|
1409
|
-
get effectProfiles() { return (this.effectProfilesInstance ??= new WebEffectProfiles(this.dataDir)); }
|
|
1410
|
-
effectServiceInstance;
|
|
1411
|
-
get effectService() {
|
|
1412
|
-
return (this.effectServiceInstance ??= new WebEffectService({ library: this.effectLibrary, themes: this.themeStore, profiles: this.effectProfiles, prefs: this.webPrefs, trials: this.effectTrials,
|
|
1413
|
-
known: name => this.isKnownInstance(name), changed: () => { try {
|
|
1414
|
-
this.emitSseEvent("status", this.getUiStatus());
|
|
1415
|
-
}
|
|
1416
|
-
catch { /* next status carries revision */ } } }));
|
|
1417
|
-
}
|
|
1418
|
-
effectToolsService;
|
|
1419
|
-
/** Caller identity is supplied only by the owned IPC connection / verified agent endpoint token. */
|
|
1420
|
-
get effectTools() {
|
|
1421
|
-
return (this.effectToolsService ??= new WebEffectTools({
|
|
1422
|
-
library: this.effectLibrary, limiter: this.webAppearance.limiter,
|
|
1423
|
-
authorize: (name, buckets) => !this.isKnownInstance(name) ? { error: "unknown_instance" } : this.webAppearance.authorizeEffect(name, buckets),
|
|
1424
|
-
placed: name => this.themeStore.get(name).placements.effects,
|
|
1425
|
-
place: (name, effects) => {
|
|
1426
|
-
const before = this.themeStore.get(name).placements.effects;
|
|
1427
|
-
const explicit = new Set(effects.filter(e => typeof e !== "string").map(e => e.id));
|
|
1428
|
-
const w = this.themeStore.setPlacements(name, { effects }, "agent", what => {
|
|
1429
|
-
// An unchanged human/private placement may be retained, never exposed or newly acquired by an agent.
|
|
1430
|
-
const r = explicit.has(what.id) ? this.effectLibrary.read(what.id, { kind: "agent", id: name })
|
|
1431
|
-
: this.effectLibrary.readReferenced(what.id, `instance:${name}`);
|
|
1432
|
-
if (!r.ok)
|
|
1433
|
-
return r.error;
|
|
1434
|
-
const params = explicit.has(what.id) ? what.params : before.find(e => e.id === what.id)?.params;
|
|
1435
|
-
return resolveEffectParams(r.entry.manifest, params ?? {}).ok ? null : "effect_params";
|
|
1436
|
-
});
|
|
1437
|
-
return w.ok ? { ok: true, rev: w.rev } : { ok: false, error: w.error };
|
|
1438
|
-
},
|
|
1439
|
-
changed: () => { try {
|
|
1440
|
-
this.emitSseEvent("status", this.getUiStatus());
|
|
1441
|
-
}
|
|
1442
|
-
catch { /* later status carries placements */ } },
|
|
1443
|
-
// A nonmutating own/shared offer is not an appearance write. Only an explicit non-public admin-session click may start it.
|
|
1444
|
-
preview: async (instance, id) => {
|
|
1445
|
-
const result = this.effectTrials.offer(instance, id);
|
|
1446
|
-
if (!result.ok)
|
|
1447
|
-
return { error: "not_found" };
|
|
1448
|
-
const present = this.webChatHistory.list(instance).some(row => row.effectTrial?.offer === result.offer.offer);
|
|
1449
|
-
if (!present && !this.publishEffectTrial(instance, result.offer))
|
|
1450
|
-
return { error: "trial_unavailable" };
|
|
1451
|
-
return { id, status: "offered", expiresAt: result.offer.expiresAt, message: "A trial card is in your web chat. A signed-in admin outside the public link can start it; nothing was applied." };
|
|
1452
|
-
},
|
|
1453
|
-
profiles: id => this.effectProfiles.read(id),
|
|
1454
|
-
profileSummary: id => this.effectService.profileSummary(id),
|
|
1455
|
-
profileSummaries: ids => this.effectService.profileSummaries(ids),
|
|
1456
|
-
playbackSummary: (name, id) => this.effectService.playbackSummary(name, id),
|
|
1457
|
-
}));
|
|
1458
|
-
}
|
|
1459
1372
|
appearanceToolsService;
|
|
1460
1373
|
/** #1629 r4 §1: get_web_appearance / preview_web_appearance — the caller's own look, resolved as the page resolves it. */
|
|
1461
1374
|
get appearanceTools() {
|
|
1462
1375
|
return (this.appearanceToolsService ??= new AppearanceTools({
|
|
1463
|
-
canvasWorkerEnabled: () => this.canvasWorkerEnabled(),
|
|
1464
1376
|
frame: (name) => (this.getUiStatus().instances.find(i => i.name === name) ?? { name }),
|
|
1465
1377
|
theme: (name) => {
|
|
1466
1378
|
const r = this.themeStore.get(name);
|
|
1467
1379
|
return { theme: r.theme, locked: r.locked, widgets: r.placements.widgets, ambient: r.placements.ambient,
|
|
1468
1380
|
glyphAsset: (id) => this.themeStore.asset(name, id) };
|
|
1469
1381
|
},
|
|
1470
|
-
effects: name => this.themeStore.readable() ? this.themeStore.get(name).placements.effects.map(p => ({ id: p.id, by: p.by, ...(p.params ? { params: p.params } : {}), playback: this.effectService.playbackSummary(name, p.id) })) : [],
|
|
1471
1382
|
card: (name) => resolveCard(name, humanCards(this.dataDir).get(name), this.themeStore.get(name).theme.card),
|
|
1472
1383
|
// #1958: the host's identity-colour settings, as the page reads them (an unreadable prefs file: the defaults).
|
|
1473
1384
|
colorPrefs: () => { try {
|
|
@@ -1496,49 +1407,17 @@ export class FleetManager {
|
|
|
1496
1407
|
return Object.hasOwn(this.fleetConfig?.instances ?? {}, name) || (this.classicChannels?.getAll() ?? []).some((ch) => ch.instanceName === name);
|
|
1497
1408
|
}
|
|
1498
1409
|
modStore;
|
|
1499
|
-
/**
|
|
1500
|
-
* #1629 r4-5 / B2: installed mods use the same validated library and scoped holder claims as direct uploads.
|
|
1501
|
-
*/
|
|
1410
|
+
/** #1629 r4-5: installed mods (#2799: a bundle that carries Canvas Worker effects is refused). */
|
|
1502
1411
|
get mods() {
|
|
1503
1412
|
return (this.modStore ??= new ModStore(this.dataDir, {
|
|
1504
1413
|
themes: this.themeStore,
|
|
1505
1414
|
prefs: this.webPrefs,
|
|
1506
1415
|
ownerCss: this.ownerCss,
|
|
1507
|
-
|
|
1508
|
-
canvasWorkerEnabled: () => this.canvasWorkerEnabled(),
|
|
1509
|
-
context: () => ({ agendVersion: agendVersion(), limits: this.themeStore.limits(), effects: cw1EffectChecker() }),
|
|
1416
|
+
context: () => ({ agendVersion: agendVersion(), limits: this.themeStore.limits() }),
|
|
1510
1417
|
isKnownInstance: (name) => this.isKnownInstance(name),
|
|
1511
1418
|
prefsIdentity: OPERATOR,
|
|
1512
1419
|
}));
|
|
1513
1420
|
}
|
|
1514
|
-
agentModsService;
|
|
1515
|
-
/** #1629 r4-5b: export_web_mod / propose_web_mod — the caller's own look as a file, and a proposal for a person. */
|
|
1516
|
-
get agentMods() {
|
|
1517
|
-
return (this.agentModsService ??= new AgentMods({
|
|
1518
|
-
themes: this.themeStore, mods: this.mods, limiter: this.webAppearance.limiter,
|
|
1519
|
-
webConfig: () => this.fleetConfig?.web ?? null,
|
|
1520
|
-
// The mod store's own: a proposal is checked exactly as the person's import of it will be.
|
|
1521
|
-
context: () => this.mods.checkContext(),
|
|
1522
|
-
readOwnEffect: (instance, id) => { const r = this.effectLibrary.read(id, { kind: "agent", id: instance }); return r.ok ? { name: r.entry.manifest.name, files: r.entry.files } : null; },
|
|
1523
|
-
notice: (instance, text) => { try {
|
|
1524
|
-
this.emitSseEvent("message", { instance, sender: instance, role: "status", text, ts: new Date().toISOString() });
|
|
1525
|
-
}
|
|
1526
|
-
catch { /* the page reads it from Settings too */ } },
|
|
1527
|
-
changed: () => { try {
|
|
1528
|
-
this.emitSseEvent("status", this.getUiStatus());
|
|
1529
|
-
}
|
|
1530
|
-
catch { /* the next frame */ } },
|
|
1531
|
-
}));
|
|
1532
|
-
}
|
|
1533
|
-
/**
|
|
1534
|
-
* #1629 r4-5c: an effect as this person may carry it away in an export — their own claim, or one a person shared —
|
|
1535
|
-
* read with their principal (Sol's ACL). Being able to view or run a placed effect never grants packaging someone
|
|
1536
|
-
* else's private claim: the library's reference read is runtime access, not an export path. Null: not theirs.
|
|
1537
|
-
*/
|
|
1538
|
-
modPlacedEffect(person, id) {
|
|
1539
|
-
const r = this.effectLibrary.read(id, { kind: "human", id: person });
|
|
1540
|
-
return r.ok ? { name: r.entry.manifest.name, files: r.entry.files } : null;
|
|
1541
|
-
}
|
|
1542
1421
|
/** #1629 r4-5: an instance's card text as every viewer sees it (a person's fields over the agent's). */
|
|
1543
1422
|
modCardText(name) {
|
|
1544
1423
|
const card = resolveCard(name, humanCards(this.dataDir).get(name), this.themeStore.get(name).theme.card);
|
|
@@ -1561,8 +1440,7 @@ export class FleetManager {
|
|
|
1561
1440
|
*/
|
|
1562
1441
|
get webSettings() {
|
|
1563
1442
|
return (this.webSettingsToolsService ??= new WebSettingsTools({
|
|
1564
|
-
|
|
1565
|
-
prefs: this.webPrefs, ownerCss: this.ownerCss, mods: this.mods, effects: this.effectService,
|
|
1443
|
+
prefs: this.webPrefs, ownerCss: this.ownerCss,
|
|
1566
1444
|
instances: () => [...Object.keys(this.fleetConfig?.instances ?? {}),
|
|
1567
1445
|
...(this.classicChannels?.getAll() ?? []).map((ch) => ch.instanceName).filter((n) => !Object.hasOwn(this.fleetConfig?.instances ?? {}, n))],
|
|
1568
1446
|
colour: (name) => personIdentityColour(this.dataDir, name),
|
|
@@ -1571,7 +1449,6 @@ export class FleetManager {
|
|
|
1571
1449
|
bannerFocus: (name) => personBannerFocus(this.dataDir, name),
|
|
1572
1450
|
setBannerFocus: (name, focus) => { const w = setPersonBannerFocus(this.dataDir, name, focus); if (w.ok)
|
|
1573
1451
|
this.identityChanged(); return w; },
|
|
1574
|
-
placements: (name) => this.themeStore.get(name).placements.effects.map((e) => (typeof e === "string" ? { id: e } : e)),
|
|
1575
1452
|
ambient: (name) => Object.fromEntries(Object.entries(this.themeStore.get(name).placements.ambient).flatMap(([k, a]) => a ? [[k, { spec: a.spec, by: a.by }]] : [])),
|
|
1576
1453
|
setAmbient: (name, spec, which) => this.webAppearance.humanSetAmbient(name, spec, which),
|
|
1577
1454
|
announce: () => { try {
|
|
@@ -1885,7 +1762,7 @@ export class FleetManager {
|
|
|
1885
1762
|
retire();
|
|
1886
1763
|
continue;
|
|
1887
1764
|
}
|
|
1888
|
-
if (store.attachPrompt(view.id, retire))
|
|
1765
|
+
if (store.attachPrompt(view.id, retire, { platform: adapter.type, connection: adapterId }))
|
|
1889
1766
|
return;
|
|
1890
1767
|
}
|
|
1891
1768
|
catch {
|
|
@@ -6652,10 +6529,12 @@ export class FleetManager {
|
|
|
6652
6529
|
dataDir: this.dataDir,
|
|
6653
6530
|
onWarn: message => this.logger.warn(message),
|
|
6654
6531
|
// #1620: fleet.yaml's web.session.local, read at every check — a Settings save or a reload applies at once
|
|
6655
|
-
// (shortening ends the sessions it now outlives). The public link's
|
|
6532
|
+
// (shortening ends the sessions it now outlives). The public link's own cap stays fixed.
|
|
6656
6533
|
localPolicy: () => localSessionPolicy(this.fleetConfig?.web?.session?.local),
|
|
6657
6534
|
// #1920 §5.4: a guest's, from web.guests.session (never longer than the surface's own).
|
|
6658
6535
|
guestPolicy: () => guestSessionPolicy(this.fleetConfig?.web?.guests?.session),
|
|
6536
|
+
// A session over the temporary link ends with the link (its TTL, at most 8 h on a quick tunnel).
|
|
6537
|
+
exposureEnd: id => this.publicWebLink?.endOf(id) ?? null,
|
|
6659
6538
|
});
|
|
6660
6539
|
this.enforceGuestSwitch(); // #1920: guests off while the fleet was down
|
|
6661
6540
|
}
|
|
@@ -7299,7 +7178,7 @@ export class FleetManager {
|
|
|
7299
7178
|
return { ...a, name: badge.name, platform: badge.platform, scope: [...this.guestScope(owner)].sort(), reach: [...this.guestReach(owner)].sort(),
|
|
7300
7179
|
devices: devices.get(k) ?? 0, narrow: own(cfg?.narrow, `${a.adapterId}:${a.userId}`) ?? null,
|
|
7301
7180
|
// #2348: the grant as fleet.yaml has it (null: none), and the last code an admin sent from Settings.
|
|
7302
|
-
grant: grant ? { ...(grant.name ? { name: grant.name } : {}), instances: [...grant.instances] } : null,
|
|
7181
|
+
grant: grant ? { ...(grant.name ? { name: grant.name } : {}), instances: [...grant.instances], ...(grant.level === "trusted" ? { level: "trusted" } : {}) } : null,
|
|
7303
7182
|
...(sent ? { code: { at: sent.at, outcome: sent.outcome.kind, ...(sent.outcome.kind === "sent" ? { expiresAt: sent.at + sent.outcome.expiresInMs } : {}),
|
|
7304
7183
|
...(sent.outcome.kind === "dm_failed" ? { reason: sent.outcome.reason, platform: sent.outcome.platform, ...(sent.outcome.startUrl ? { startUrl: sent.outcome.startUrl } : {}) } : {}) } } : {}) };
|
|
7305
7184
|
}).sort((x, y) => (y.lastSeen ?? -1) - (x.lastSeen ?? -1));
|
|
@@ -7347,7 +7226,7 @@ export class FleetManager {
|
|
|
7347
7226
|
const when = Date.parse(r.created_at.includes("T") ? r.created_at : `${r.created_at.replace(" ", "T")}Z`);
|
|
7348
7227
|
return r.event_type === "guest_grant_changed"
|
|
7349
7228
|
? [{ kind: "grant", at: when, account, name, via: p.via === "confirmed" ? "confirmed" : "direct", added: names(p.added), removed: names(p.removed),
|
|
7350
|
-
endedSessions: typeof p.endedSessions === "number" ? p.endedSessions : 0 }]
|
|
7229
|
+
endedSessions: typeof p.endedSessions === "number" ? p.endedSessions : 0, ...(p.level === "chat" || p.level === "trusted" ? { level: p.level } : {}) }]
|
|
7351
7230
|
: [{ kind: "code", at: when, account, name, outcome: typeof p.outcome === "string" ? p.outcome : "unknown" }];
|
|
7352
7231
|
});
|
|
7353
7232
|
}
|
|
@@ -7386,7 +7265,7 @@ export class FleetManager {
|
|
|
7386
7265
|
* confirmed in General, the agents added and taken away, and the sessions a removal ended. Never message content.
|
|
7387
7266
|
*/
|
|
7388
7267
|
noteGuestGrantChange(change) {
|
|
7389
|
-
this.logger.info({ account: change.account, via: change.via, added: change.added.length, removed: change.removed.length }, "Guest access changed in Settings");
|
|
7268
|
+
this.logger.info({ account: change.account, via: change.via, added: change.added.length, removed: change.removed.length, ...(change.level ? { level: change.level } : {}) }, "Guest access changed in Settings");
|
|
7390
7269
|
try {
|
|
7391
7270
|
this.eventLog?.insert("fleet", "guest_grant_changed", { ...change });
|
|
7392
7271
|
}
|
|
@@ -7471,6 +7350,8 @@ export class FleetManager {
|
|
|
7471
7350
|
* #1920 §5.4: a guest's own `/web revoke` — its sessions and its outstanding code; nobody else's (an admin's revokes
|
|
7472
7351
|
* everyone's, as before).
|
|
7473
7352
|
*/
|
|
7353
|
+
/** #2855: the admin removed a guest — its own preferences (theme, language, favourites, sort, filter) go too. */
|
|
7354
|
+
forgetGuestPrefs(owner) { this.webPrefs.forgetGuest(webPersonKey(owner)); }
|
|
7474
7355
|
revokeGuestWebSessions(owner) {
|
|
7475
7356
|
this.initializeWebSessions();
|
|
7476
7357
|
const key = `${owner.adapterId}\u0000${owner.userId}`;
|
|
@@ -10364,6 +10245,11 @@ export class FleetManager {
|
|
|
10364
10245
|
}
|
|
10365
10246
|
return;
|
|
10366
10247
|
}
|
|
10248
|
+
// #2870 (the user's choice): in a private chat, a command from someone ClassicBot does not serve here — not an
|
|
10249
|
+
// allowed user, not a ClassicBot admin, not a fleet admin, no room in this chat — gets no answer at all. /start
|
|
10250
|
+
// above still asks for access; a guest's /web is handled before it.
|
|
10251
|
+
if (isPrivateChat && text.startsWith("/") && this.isClassicPrivateStranger(msg.userId, chatId, msg.adapterId))
|
|
10252
|
+
return;
|
|
10367
10253
|
// Handle /stop command
|
|
10368
10254
|
if (text === "/stop" || text.startsWith("/stop ")) {
|
|
10369
10255
|
if (!this.classicChannels.isAdmin(msg.userId)) {
|
|
@@ -10838,8 +10724,8 @@ export class FleetManager {
|
|
|
10838
10724
|
}
|
|
10839
10725
|
}
|
|
10840
10726
|
checkToolPermission(sink, instanceName, tool) {
|
|
10841
|
-
if (isCanvasWorkerTool(tool)
|
|
10842
|
-
return { allowed: false, message: CANVAS_WORKER_EXPERIMENTAL_MESSAGE };
|
|
10727
|
+
if (isCanvasWorkerTool(tool))
|
|
10728
|
+
return { allowed: false, message: CANVAS_WORKER_EXPERIMENTAL_MESSAGE }; // #2799: removed
|
|
10843
10729
|
const profile = resolveToolSet(this.fleetConfig?.instances[instanceName], instanceName);
|
|
10844
10730
|
const allowed = mayUseTool(profile, tool);
|
|
10845
10731
|
if (!allowed) {
|
|
@@ -11572,19 +11458,6 @@ export class FleetManager {
|
|
|
11572
11458
|
}
|
|
11573
11459
|
dispatchTypedIpc(name, msg) {
|
|
11574
11460
|
const type = String(msg.type);
|
|
11575
|
-
if (type.startsWith("fleet_") && WEB_EFFECT_TOOLS.has(type.slice(6))) {
|
|
11576
|
-
const ipc = this.instanceIpcClients.get(name), fleetRequestId = msg.fleetRequestId;
|
|
11577
|
-
if (!ipc || typeof fleetRequestId !== "string")
|
|
11578
|
-
return;
|
|
11579
|
-
void this.handleWebThemeHttp(name, type.slice(6), (msg.payload ?? {})).then(result => {
|
|
11580
|
-
if (this.instanceIpcClients.get(name) === ipc)
|
|
11581
|
-
ipc.send({ type: "fleet_web_theme_response", fleetRequestId, result });
|
|
11582
|
-
}, err => {
|
|
11583
|
-
if (this.instanceIpcClients.get(name) === ipc)
|
|
11584
|
-
ipc.send({ type: "fleet_web_theme_response", fleetRequestId, error: err instanceof Error ? err.message : "Effect operation failed" });
|
|
11585
|
-
}).catch(err => this.logger.debug({ err }, "Effect tool response could not be written"));
|
|
11586
|
-
return;
|
|
11587
|
-
}
|
|
11588
11461
|
if (type.startsWith("fleet_schedule_")) {
|
|
11589
11462
|
this.handleScheduleCrud(name, msg);
|
|
11590
11463
|
return;
|
|
@@ -11638,10 +11511,9 @@ export class FleetManager {
|
|
|
11638
11511
|
const args = (msg.payload ?? {});
|
|
11639
11512
|
const result = tool === "get_web_appearance" || tool === "preview_web_appearance"
|
|
11640
11513
|
? this.appearanceTools.handle(instanceName, tool, args)
|
|
11641
|
-
: tool === "
|
|
11642
|
-
: tool
|
|
11643
|
-
:
|
|
11644
|
-
: this.webAppearance.handleTool(instanceName, tool, args);
|
|
11514
|
+
: tool === "office_view" || tool === "office_set" ? this.officeActs.handle(instanceName, tool, args)
|
|
11515
|
+
: OFFICE_PACK_IPC.has(`fleet_${tool}`) ? this.officePackTools.handle(instanceName, tool, args)
|
|
11516
|
+
: this.webAppearance.handleTool(instanceName, tool, args);
|
|
11645
11517
|
ipc.send({ type: "fleet_web_theme_response", fleetRequestId, result });
|
|
11646
11518
|
}
|
|
11647
11519
|
catch (err) {
|
|
@@ -12066,17 +11938,10 @@ export class FleetManager {
|
|
|
12066
11938
|
}
|
|
12067
11939
|
/** #1629: `agend-agent theme …` — the same service as the tools; `instance` is the token's. */
|
|
12068
11940
|
async handleWebThemeHttp(instance, tool, args) {
|
|
12069
|
-
if (isCanvasWorkerTool(tool)
|
|
12070
|
-
return { error: "canvas_worker_experimental", message: CANVAS_WORKER_EXPERIMENTAL_MESSAGE };
|
|
12071
|
-
if (WEB_EFFECT_TOOLS.has(tool)) {
|
|
12072
|
-
if (!this.isKnownInstance(instance))
|
|
12073
|
-
return { error: "unknown_instance" };
|
|
12074
|
-
return this.effectTools.handle(instance, tool, args);
|
|
12075
|
-
}
|
|
11941
|
+
if (isCanvasWorkerTool(tool))
|
|
11942
|
+
return { error: "canvas_worker_experimental", message: CANVAS_WORKER_EXPERIMENTAL_MESSAGE }; // #2799: removed
|
|
12076
11943
|
if (tool === "get_web_appearance" || tool === "preview_web_appearance")
|
|
12077
11944
|
return this.appearanceTools.handle(instance, tool, args);
|
|
12078
|
-
if (tool === "export_web_mod" || tool === "propose_web_mod")
|
|
12079
|
-
return this.agentMods.handle(instance, tool, args);
|
|
12080
11945
|
if (tool === "office_view" || tool === "office_set")
|
|
12081
11946
|
return this.officeActs.handle(instance, tool, args); // #2578
|
|
12082
11947
|
if (OFFICE_PACK_IPC.has(`fleet_${tool}`))
|
|
@@ -12960,9 +12825,7 @@ export class FleetManager {
|
|
|
12960
12825
|
this.themeStore.forget(name);
|
|
12961
12826
|
this.webAppearance.forget(name);
|
|
12962
12827
|
this.appearanceTools.forget(name);
|
|
12963
|
-
this.effectToolsService?.forget(name);
|
|
12964
12828
|
this.mods.forgetInstance(name);
|
|
12965
|
-
this.agentMods.forget(name);
|
|
12966
12829
|
this.officeActsInstance?.forget(name);
|
|
12967
12830
|
this.officePackToolsInstance?.forget(name);
|
|
12968
12831
|
}
|
|
@@ -15855,6 +15718,16 @@ export class FleetManager {
|
|
|
15855
15718
|
return result;
|
|
15856
15719
|
}
|
|
15857
15720
|
/** #1269: an instance's chat command from the web chat (web-commands.ts); `publicLink`: a gateway request. */
|
|
15721
|
+
/** #2855: the table scope of an instance the web chat may command (a fleet instance or a ClassicBot room), else null. */
|
|
15722
|
+
webCommandScope(instance) {
|
|
15723
|
+
// Own entries only: a name like "__proto__" or "constructor" must not be found on the prototype (#1476 review).
|
|
15724
|
+
const instances = this.fleetConfig?.instances;
|
|
15725
|
+
if (instances && Object.prototype.hasOwnProperty.call(instances, instance))
|
|
15726
|
+
return isGeneralInstance(this.fleetConfig, instance) ? "general" : "fleet";
|
|
15727
|
+
return this.classicChannels?.getChannelIdByInstance(instance) !== undefined ? "classic" : null;
|
|
15728
|
+
}
|
|
15729
|
+
/** #2855: the platform an instance's channel is on, for the command table's cell (a web-only fleet: Discord's). */
|
|
15730
|
+
commandPlatform(instance) { return this.getAdapterForInstance(instance)?.type === "telegram" ? "telegram" : "discord"; }
|
|
15858
15731
|
webCommand(input, opts) {
|
|
15859
15732
|
const webMeta = (instance) => {
|
|
15860
15733
|
const topicId = this.fleetConfig?.instances[instance]?.topic_id;
|
|
@@ -15863,6 +15736,7 @@ export class FleetManager {
|
|
|
15863
15736
|
chatId: this.getGroupIdForInstance(instance) || "", messageId: newWebMessageId(),
|
|
15864
15737
|
username: opts.person?.name ?? WEB_NAME_FALLBACK, userId: opts.person?.userId ?? WEB_NAME_FALLBACK,
|
|
15865
15738
|
threadId: topicId != null ? String(topicId) : undefined, adapterId: this.getAdapterForInstance(instance)?.id ?? "", source: "web", humanOrigin: webHumanOrigin(true, opts.authority),
|
|
15739
|
+
...(opts.guest ? { webGuest: true } : {}), // #2855: a guest's /steer or /btw reaches the agent as a guest's
|
|
15866
15740
|
};
|
|
15867
15741
|
};
|
|
15868
15742
|
const choicesFromCache = (instance) => {
|
|
@@ -15874,13 +15748,8 @@ export class FleetManager {
|
|
|
15874
15748
|
return { current, options: this.withCurrentModel(cached.models, current).map(o => ({ id: o.id, label: this.modelChoiceLabel(o, current) })) };
|
|
15875
15749
|
};
|
|
15876
15750
|
return runWebCommand({
|
|
15877
|
-
|
|
15878
|
-
|
|
15879
|
-
const instances = this.fleetConfig?.instances;
|
|
15880
|
-
if (instances && Object.prototype.hasOwnProperty.call(instances, instance))
|
|
15881
|
-
return isGeneralInstance(this.fleetConfig, instance) ? "general" : "fleet";
|
|
15882
|
-
return this.classicChannels?.getChannelIdByInstance(instance) !== undefined ? "classic" : null;
|
|
15883
|
-
},
|
|
15751
|
+
scope: (instance) => this.webCommandScope(instance),
|
|
15752
|
+
platform: (instance) => this.commandPlatform(instance),
|
|
15884
15753
|
ctx: (instance) => this.topicCommands.getCtxText(instance),
|
|
15885
15754
|
// Board 003648ac: a watch for the paste, armed when the daemon says it was written (raw_paste_written); one
|
|
15886
15755
|
// for a command that was not handed over is dropped.
|
|
@@ -17557,6 +17426,13 @@ export class FleetManager {
|
|
|
17557
17426
|
lines.push(t(admin === "added" ? "classic.approve_done_admin" : "classic.approve_done_admin_already", adminUserId ?? ""));
|
|
17558
17427
|
}
|
|
17559
17428
|
this.notifyInstanceTopic(entry.instanceName, lines.join("\n"));
|
|
17429
|
+
// #2870: the chat just allowed — and the new ClassicBot admin's own chat — get the ClassicBot menu now, not at the
|
|
17430
|
+
// bot's next start (Telegram only; the menu is per chat there).
|
|
17431
|
+
const reply = entry.classicReplyTo;
|
|
17432
|
+
if (reply && reply.adapter.type === "telegram" && scope !== "guild") {
|
|
17433
|
+
for (const chat of new Set([groupId, ...(adminUserId ? [adminUserId] : [])]))
|
|
17434
|
+
void this.topicCommands.addClassicMenuChat(reply.adapterId, chat);
|
|
17435
|
+
}
|
|
17560
17436
|
await this.notifyClassicRequester(entry, "classic.request_allowed");
|
|
17561
17437
|
}
|
|
17562
17438
|
async notifyClassicRequester(entry, key) {
|
|
@@ -18156,14 +18032,6 @@ export class FleetManager {
|
|
|
18156
18032
|
const room = this.classicChannels?.getAll().find(c => c.instanceName === name);
|
|
18157
18033
|
return room ? `room:${room.channelId}:${room.adapterId ?? ""}` : null;
|
|
18158
18034
|
}
|
|
18159
|
-
/** The only Try-card publisher: no arbitrary SSE sender/role can manufacture this metadata. */
|
|
18160
|
-
publishEffectTrial(instance, offer) {
|
|
18161
|
-
const row = this.webChatHistory.recordEffectTrial(instance, offer, new Date().toISOString());
|
|
18162
|
-
if (!row)
|
|
18163
|
-
return false;
|
|
18164
|
-
broadcastSseEvent(this.sseClients, "message", row, err => this.logger.debug({ err }, "SSE client write failed; evicting"), this.webChatHistory.cursorOf(row));
|
|
18165
|
-
return true;
|
|
18166
|
-
}
|
|
18167
18035
|
/** Push an SSE event to all connected Web UI clients. */
|
|
18168
18036
|
emitSseEvent(event, data) {
|
|
18169
18037
|
// #1386: a prompt opened or closed, or an instance's state moved — "Needs you" may have changed.
|
|
@@ -18471,27 +18339,6 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
18471
18339
|
this.syncRoleSkills(workDir, backend, "general", knowledgeDir);
|
|
18472
18340
|
this.logger.debug({ knowledgeDir, workDir, backend }, "Synced general knowledge files");
|
|
18473
18341
|
}
|
|
18474
|
-
/** Update only AgEnD-managed skill copies; no launch or restart is needed for an experimental switch. */
|
|
18475
|
-
canvasWorkerSettingChanged() {
|
|
18476
|
-
this.refreshExperimentalSkills();
|
|
18477
|
-
this.emitSseEvent("status", this.getUiStatus());
|
|
18478
|
-
}
|
|
18479
|
-
refreshExperimentalSkills() {
|
|
18480
|
-
for (const [name, daemon] of this.daemons) {
|
|
18481
|
-
try {
|
|
18482
|
-
const cfg = daemon.getConfigSnapshot();
|
|
18483
|
-
const backend = cfg.backend ?? this.fleetConfig?.defaults?.backend ?? "claude-code";
|
|
18484
|
-
const workDir = this.resolveKnowledgeWorkDir(cfg.working_directory, backend, name);
|
|
18485
|
-
const classic = this.classicChannels?.getAll().some(ch => ch.instanceName === name) === true;
|
|
18486
|
-
if (classic && !insideManagedWorkspaces(workDir))
|
|
18487
|
-
continue;
|
|
18488
|
-
this.syncRoleSkills(workDir, backend, classic ? "classic" : cfg.general_topic ? "general" : "worker");
|
|
18489
|
-
}
|
|
18490
|
-
catch (err) {
|
|
18491
|
-
this.logger.warn({ name, err }, "Could not refresh experimental skill visibility");
|
|
18492
|
-
}
|
|
18493
|
-
}
|
|
18494
|
-
}
|
|
18495
18342
|
/** Publish only the bundled skills eligible for an instance role. */
|
|
18496
18343
|
syncRoleSkills(workDir, backend, role, knowledgeDir) {
|
|
18497
18344
|
const skillSegments = FleetManager.SKILLS_DIR_SEGMENTS[backend];
|
|
@@ -18696,7 +18543,7 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
18696
18543
|
continue;
|
|
18697
18544
|
}
|
|
18698
18545
|
managed.push(name);
|
|
18699
|
-
const newContent = bundledSkillContents(join(srcSkills, name)
|
|
18546
|
+
const newContent = bundledSkillContents(join(srcSkills, name));
|
|
18700
18547
|
if (refuse(dest))
|
|
18701
18548
|
continue;
|
|
18702
18549
|
try {
|
|
@@ -20854,6 +20701,17 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
20854
20701
|
return (adapterId ? generals.find(([name, cfg]) => (cfg.channel_id ?? this.getInstanceAdapterId(name)) === adapterId) : undefined)?.[0]
|
|
20855
20702
|
?? generals[0]?.[0];
|
|
20856
20703
|
}
|
|
20704
|
+
/**
|
|
20705
|
+
* #2870: someone ClassicBot does not serve in this private chat: not on allowed_users, not a ClassicBot admin, not a
|
|
20706
|
+
* fleet admin of this bot, and no ClassicBot room here. Their commands other than /start get no answer.
|
|
20707
|
+
*/
|
|
20708
|
+
isClassicPrivateStranger(userId, chatId, adapterId) {
|
|
20709
|
+
const classic = this.classicChannels;
|
|
20710
|
+
if (!classic)
|
|
20711
|
+
return false;
|
|
20712
|
+
return !classic.isAdmin(userId) && !classic.isUserAllowed(userId) && !this.isFleetAdmin(userId, adapterId ?? "")
|
|
20713
|
+
&& !classic.isClassicChannel(chatId, adapterId);
|
|
20714
|
+
}
|
|
20857
20715
|
/** Return a user-facing blocker without mutating ClassicBot state. */
|
|
20858
20716
|
validateClassicStart(channelId, userId, guildId, adapterId) {
|
|
20859
20717
|
const classic = this.classicChannels;
|
|
@@ -21136,7 +20994,6 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21136
20994
|
try {
|
|
21137
20995
|
this.themeStore.forget(ch.instanceName);
|
|
21138
20996
|
this.webAppearance.limiter.forget(ch.instanceName);
|
|
21139
|
-
this.effectToolsService?.forget(ch.instanceName);
|
|
21140
20997
|
}
|
|
21141
20998
|
catch (err) {
|
|
21142
20999
|
this.logger.warn({ err: err.message, instanceName: ch.instanceName }, "Dropping a removed room's web theme failed");
|
|
@@ -21643,9 +21500,6 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
21643
21500
|
this.getConfigHistory().accepted("fleet.yaml", this.configPath, this.loadedFleetSource);
|
|
21644
21501
|
this.migrateOfficeStorage();
|
|
21645
21502
|
this.migrateNoticeDeliveryStorage();
|
|
21646
|
-
if (canvasWorkerEnabled(oldConfig?.web) !== this.canvasWorkerEnabled()) {
|
|
21647
|
-
this.canvasWorkerSettingChanged();
|
|
21648
|
-
}
|
|
21649
21503
|
// Classic behavior settings share the fleet defaults but are not entries
|
|
21650
21504
|
// in fleet.yaml. Snapshot the old effective chain before reloading the
|
|
21651
21505
|
// Classic file so SIGHUP can hot-apply either source without waiting for
|
|
@@ -23512,6 +23366,21 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
23512
23366
|
}
|
|
23513
23367
|
return scope.size ? scope : NO_GUEST_SCOPE;
|
|
23514
23368
|
}
|
|
23369
|
+
/** #2855: whether a request carries a guest's live session (its cookie; checked without counting as activity). */
|
|
23370
|
+
presentsGuestSession(req) {
|
|
23371
|
+
if (!this.webToken || !this.webSessions)
|
|
23372
|
+
return false;
|
|
23373
|
+
const epoch = tokenEpoch(this.webToken);
|
|
23374
|
+
return readSessionCookies(req, this.webToken).some(id => this.webSessions.authenticate(id, epoch, { touch: false })?.tier === "guest");
|
|
23375
|
+
}
|
|
23376
|
+
/** #2855: whether the admin made this guest Trusted — only an explicit grant can (web.guests.grants[account].level). */
|
|
23377
|
+
guestTrusted(owner) {
|
|
23378
|
+
const guests = this.fleetConfig?.web?.guests;
|
|
23379
|
+
if (guests?.enabled !== true || !guests.grants)
|
|
23380
|
+
return false;
|
|
23381
|
+
const key = `${owner.adapterId}:${owner.userId}`;
|
|
23382
|
+
return Object.hasOwn(guests.grants, key) && guests.grants[key]?.level === "trusted";
|
|
23383
|
+
}
|
|
23515
23384
|
/**
|
|
23516
23385
|
* #1920 (#2104 review): what an account reaches before an admin's narrowing — its connection's topics (an open one's
|
|
23517
23386
|
* named agents), its own Telegram private room, its verified group rooms. Narrowing can only take from this set, so it
|
|
@@ -23690,13 +23559,6 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
23690
23559
|
return;
|
|
23691
23560
|
}
|
|
23692
23561
|
const requestPath = new URL(req.url ?? "/", `http://localhost:${port}`).pathname;
|
|
23693
|
-
if (!this.canvasWorkerEnabled() && isCanvasWorkerHttpPath(requestPath)) {
|
|
23694
|
-
res.writeHead(403, { "Content-Type": "application/json", "Cache-Control": "no-store" });
|
|
23695
|
-
res.end(JSON.stringify({ error: "canvas_worker_experimental", message: CANVAS_WORKER_EXPERIMENTAL_MESSAGE }));
|
|
23696
|
-
return;
|
|
23697
|
-
}
|
|
23698
|
-
if (this.effectBootstrap.handle(req, res))
|
|
23699
|
-
return;
|
|
23700
23562
|
// Branding is public, after Host admission: automatic favicon requests
|
|
23701
23563
|
// must not become noisy web-token 401s in the browser console.
|
|
23702
23564
|
// #2308: the icon routes and the pages' icon links follow the app icon set in Settings.
|
|
@@ -23704,8 +23566,9 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
23704
23566
|
if (handleWebIconRequest(req, res, requestPath))
|
|
23705
23567
|
return;
|
|
23706
23568
|
// Public: the health probe, /agent (instance-token auth of its own), the
|
|
23707
|
-
// sign-in surface, and /view's reads unless web.view_access says otherwise
|
|
23708
|
-
|
|
23569
|
+
// sign-in surface, and /view's reads unless web.view_access says otherwise (#2855: never a guest's, which go
|
|
23570
|
+
// through the guest gate and its limits on either listener).
|
|
23571
|
+
if (bypassesWebGate(req, requestPath, this.fleetConfig, p => !gatewayRequestContext(req) && (isViewPath(p) || isUsagePath(p)) && !this.presentsGuestSession(req))) {
|
|
23709
23572
|
// fall through to the handlers below
|
|
23710
23573
|
}
|
|
23711
23574
|
else {
|
|
@@ -23771,7 +23634,9 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
23771
23634
|
streamOpened: () => { void this.refreshGuestRooms(owner, { mode: "force" }); },
|
|
23772
23635
|
history: () => this.webChatHistory,
|
|
23773
23636
|
// #1920 §5.1: guests chat unless the host made them read-only (web.guests.chat: false).
|
|
23774
|
-
chat: () => this.fleetConfig?.web?.guests?.chat !== false
|
|
23637
|
+
chat: () => this.fleetConfig?.web?.guests?.chat !== false,
|
|
23638
|
+
// #2855: the admin's level for this guest, read at each request (a change applies at once).
|
|
23639
|
+
trusted: () => this.guestTrusted(owner) });
|
|
23775
23640
|
}
|
|
23776
23641
|
if (decision.via === "session" && this.webToken) {
|
|
23777
23642
|
const upgrade = sessionCookieUpgrade(req, this.webToken, decision.session);
|
|
@@ -24177,7 +24042,6 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
24177
24042
|
return;
|
|
24178
24043
|
}
|
|
24179
24044
|
const listener = createPreviewListener({ settings, healthPort: boundPort, config: this.fleetConfig,
|
|
24180
|
-
canvasWorkerEnabled: () => this.canvasWorkerEnabled(),
|
|
24181
24045
|
// #1723: with a web.preview_origin, the open public link's dashboard frames this listener's preview too.
|
|
24182
24046
|
extraOrigins: () => { const o = settings.origin ? this.publicWebLink?.openDashboardOrigin() : null; return o ? [o] : []; } });
|
|
24183
24047
|
this.previewListener = listener;
|
|
@@ -24354,8 +24218,6 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
24354
24218
|
catch {
|
|
24355
24219
|
return {};
|
|
24356
24220
|
} })(),
|
|
24357
|
-
// #2118: only this Chat's placement content; guest projection drops global revisions.
|
|
24358
|
-
effect_chat_v: this.canvasWorkerEnabled() ? createHash("sha256").update(JSON.stringify(this.themeStore.get(name).placements.effects)).digest("hex").slice(0, 32) : null,
|
|
24359
24221
|
// #1958: the identity colour's tiers (the page resolves them: the agent's only while it shows agents' themes).
|
|
24360
24222
|
color: { ...(colors.get(name)?.color ? { person: colors.get(name).color } : {}), ...(image.agentColor ? { agent: image.agentColor } : {}),
|
|
24361
24223
|
...(image.roleColor ? { role: image.roleColor } : {}), auto: autoIdentityColor(name) },
|
|
@@ -24366,6 +24228,12 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
24366
24228
|
tags: identity.tags,
|
|
24367
24229
|
teams: instanceTeams(this.fleetConfig?.teams, name), // #2172: the sidebar groups a team's members under it
|
|
24368
24230
|
last_reply: this.webChatHistory.lastAgentReply(name) ?? undefined, // #2179: its last reply to a person (ISO)
|
|
24231
|
+
// #2855: its last reply that reached the channel — the only reply time a guest's sidebar gets (guestStatus).
|
|
24232
|
+
last_reply_channel: this.webChatHistory.lastAgentReply(name, { channel: true }) ?? undefined,
|
|
24233
|
+
// #2855: the web commands a guest may run here — the table's "anyone" cells for this channel (guestWebCommands);
|
|
24234
|
+
// only while guests are on (no guest reads it otherwise).
|
|
24235
|
+
...(this.fleetConfig?.web?.guests?.enabled === true
|
|
24236
|
+
? { guest_commands: (() => { const scope = this.webCommandScope(name); return scope ? guestWebCommands(scope, this.commandPlatform(name)) : []; })() } : {}),
|
|
24369
24237
|
status: this.getInstanceStatus(name),
|
|
24370
24238
|
// `state` (presentation: may be awaiting_input) and `execution_state` (working / idle / stuck, or null —
|
|
24371
24239
|
// what the dashboard's activity events carry) come from instancePresentation (#1212).
|
|
@@ -24382,7 +24250,6 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
24382
24250
|
};
|
|
24383
24251
|
});
|
|
24384
24252
|
return {
|
|
24385
|
-
canvas_worker: this.canvasWorkerEnabled(),
|
|
24386
24253
|
instances,
|
|
24387
24254
|
startup: this.startupDashboard?.snapshot() ?? null,
|
|
24388
24255
|
publicLink: this.getPublicWebStatus(),
|