@songsid/agend 2.3.2-beta.2 → 2.3.2-beta.4
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 +21 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +5 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/auth-api.js +2 -0
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/kiro.d.ts +21 -1
- package/dist/backend/kiro.js +89 -1
- package/dist/backend/kiro.js.map +1 -1
- package/dist/channel/adapters/discord.js +7 -4
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-tools.js +4 -0
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +5 -0
- package/dist/classic-channel-manager.js +14 -1
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/config-validator.js +22 -5
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +6 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon.js +16 -4
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard-permissions.d.ts +20 -6
- package/dist/dashboard-permissions.js +58 -9
- package/dist/dashboard-permissions.js.map +1 -1
- package/dist/fleet-manager.d.ts +16 -1
- package/dist/fleet-manager.js +183 -21
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +24 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +24 -1
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +8 -3
- package/dist/instance-config-impact.js +10 -5
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +8 -0
- package/dist/instance-lifecycle.js +5 -3
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +2 -6
- package/dist/locale.js.map +1 -1
- package/dist/notice-delivery.d.ts +15 -0
- package/dist/notice-delivery.js +37 -0
- package/dist/notice-delivery.js.map +1 -0
- package/dist/outbound-schemas.d.ts +20 -0
- package/dist/outbound-schemas.js +17 -0
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +1 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart.js +2 -0
- package/dist/quickstart.js.map +1 -1
- package/dist/reply-triggers.d.ts +2 -0
- package/dist/reply-triggers.js +3 -0
- package/dist/reply-triggers.js.map +1 -0
- package/dist/settings-api.js +27 -4
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +17 -14
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +7 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-instance-patch.js +4 -1
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/setup-host.js +2 -1
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +2 -0
- package/dist/setup-wizard.js.map +1 -1
- package/dist/tool-permissions.js +10 -0
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.js +2 -1
- package/dist/topic-commands.js.map +1 -1
- package/dist/turn-reply-guard.d.ts +1 -1
- package/dist/turn-reply-guard.js +1 -1
- package/dist/turn-reply-guard.js.map +1 -1
- package/dist/types.d.ts +16 -6
- package/dist/ui/chat-strings.js +2 -2
- package/dist/ui/fleet-office-editor.js +10 -6
- package/dist/ui/fleet-office-layout.js +34 -28
- package/dist/ui/fleet-office-model.js +6 -3
- package/dist/ui/fleet-office-overview.js +2 -2
- package/dist/ui/fleet-office-pack.d.ts +3 -1
- package/dist/ui/fleet-office-pack.js +58 -7
- package/dist/ui/fleet-office-skin.js +13 -4
- package/dist/ui/fleet-office-store.js +27 -1
- package/dist/ui/fleet-office-view.js +5 -4
- package/dist/ui/fleet-office-zones.js +155 -6
- package/dist/ui/fleet-office.js +169 -41
- package/dist/ui/panel-chat.js +8 -1
- package/dist/ui/panel-settings.js +32 -10
- package/dist/ui/settings-dialogs.js +8 -1
- package/dist/ui/settings-model.js +14 -6
- package/dist/ui/settings-registry.js +4 -0
- package/dist/ui/settings-strings.js +14 -0
- package/dist/ui/shared/app-i18n.js +2 -0
- package/dist/ui/shared/app-shell.js +14 -6
- package/dist/ui/shared/app-stream.js +2 -1
- package/dist/ui/shared/app.css +20 -2
- package/dist/ui/shared/side-panel.js +95 -0
- package/dist/web-api.d.ts +3 -0
- package/dist/web-api.js +11 -0
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +1 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-office-acts.d.ts +173 -0
- package/dist/web-office-acts.js +285 -0
- package/dist/web-office-acts.js.map +1 -0
- package/dist/web-office-skins.d.ts +1 -1
- package/dist/web-office-skins.js +1 -1
- package/dist/web-office-skins.js.map +1 -1
- package/dist/web-settings-patch.d.ts +2 -1
- package/dist/web-settings-patch.js +4 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/package.json +1 -1
- package/templates/windows-shortcuts.ps1 +11 -2
|
@@ -6,17 +6,23 @@
|
|
|
6
6
|
*
|
|
7
7
|
* - `appearance`: its own look on the dashboard — theme, pictures, widgets, ambient, effects, mods it proposes;
|
|
8
8
|
* - `task_board`: the task board (`task`, and `agend task …`);
|
|
9
|
-
* - `web_settings`: Settings → Web appearance for the person (`get_web_settings`, `set_web_settings`)
|
|
9
|
+
* - `web_settings`: Settings → Web appearance for the person (`get_web_settings`, `set_web_settings`);
|
|
10
|
+
* - `office` (#2578), stored separately as `office_access`: its own character in Fleet → Org chart → Office — walking, a speech bubble, a pose
|
|
11
|
+
* (`office_view`, `office_set`).
|
|
10
12
|
*
|
|
11
13
|
* Unset is allowed: a fleet that switches nothing off works as before, and the profile still decides what an agent
|
|
12
|
-
* has. `false` takes the feature's tools away whatever the profile carries: refused at the fleet's checks
|
|
14
|
+
* has — except for a feature in OFF_UNLESS_ON (`office`), which is off until a person sets it true. `false` takes the feature's tools away whatever the profile carries: refused at the fleet's checks
|
|
13
15
|
* (tool-permissions.ts's sinks, read at each call — no restart) and left out of the agent's tool menu from its next
|
|
14
16
|
* start (AGEND_DASHBOARD_OFF, read by mcp-server). Like a profile, policy protection for the resolved identity, not
|
|
15
17
|
* isolation between same-uid agents with a shell.
|
|
16
18
|
*/
|
|
17
|
-
export declare const DASHBOARD_FEATURES: readonly ["appearance", "task_board", "web_settings"];
|
|
19
|
+
export declare const DASHBOARD_FEATURES: readonly ["appearance", "task_board", "web_settings", "office"];
|
|
18
20
|
export type DashboardFeature = typeof DASHBOARD_FEATURES[number];
|
|
19
|
-
/**
|
|
21
|
+
/** The features a person switches on (#2578): absent (or null) is off for these, never allowed. */
|
|
22
|
+
export declare const OFF_UNLESS_ON: ReadonlySet<DashboardFeature>;
|
|
23
|
+
/** What a feature is when nothing (not the instance, not the defaults) says: allowed, or off for OFF_UNLESS_ON. */
|
|
24
|
+
export declare const dashboardFeatureDefault: (feature: string) => boolean;
|
|
25
|
+
/** As written in fleet.yaml: each feature true (allowed), false (switched off) or absent (allowed; off for OFF_UNLESS_ON). */
|
|
20
26
|
export type DashboardAccess = Partial<Record<DashboardFeature, boolean>>;
|
|
21
27
|
/**
|
|
22
28
|
* What a NEW fleet.yaml says about the features (the user's decision, 2026-10-22): the task board is off until the
|
|
@@ -29,7 +35,7 @@ export declare const NEW_FLEET_DASHBOARD: Readonly<DashboardAccess>;
|
|
|
29
35
|
export declare const DASHBOARD_FEATURE_TOOLS: Readonly<Record<DashboardFeature, readonly string[]>>;
|
|
30
36
|
/** The feature a tool belongs to, or null for a tool no switch governs. */
|
|
31
37
|
export declare function dashboardFeatureOf(tool: string): DashboardFeature | null;
|
|
32
|
-
/** The features switched off
|
|
38
|
+
/** The features switched off in an instance's `dashboard` as resolved: `false`, and an OFF_UNLESS_ON one not `true`. */
|
|
33
39
|
export declare function dashboardFeaturesOff(access: unknown): DashboardFeature[];
|
|
34
40
|
/** The refusal for `tool` when its feature is switched off in this resolved `dashboard` mapping, else null. */
|
|
35
41
|
export declare function dashboardRefusal(access: unknown, tool: string): string | null;
|
|
@@ -52,9 +58,17 @@ export declare function dashboardAccessProblem(value: unknown): string | null;
|
|
|
52
58
|
* the default — the same as absent (#2391 review: a literal `task_board: null` must not hide the default's `false`).
|
|
53
59
|
*/
|
|
54
60
|
export declare function dashboardSwitches(value: unknown): DashboardAccess;
|
|
61
|
+
/** Office lives beside dashboard so published rollback validators never see a new feature in that closed map. */
|
|
62
|
+
export declare function officeAccessValue(config: any): unknown;
|
|
63
|
+
export declare function dashboardAccessOf(config: any): DashboardAccess;
|
|
64
|
+
/** Transitional dashboard.office input is accepted, but never written by a managed save. Canonical values win. */
|
|
65
|
+
export declare function normalizeOfficeStorage(fleet: any): void;
|
|
66
|
+
/** Accept an older Settings client, but project/save its Office edit using the canonical field. */
|
|
67
|
+
export declare function officeInputPatch(value: Record<string, any>): Record<string, any>;
|
|
68
|
+
export declare function hasLegacyOffice(fleet: any): boolean;
|
|
55
69
|
/**
|
|
56
70
|
* The features switched off in a fleet config for `name`: each feature's own switch where the instance has one, else
|
|
57
|
-
* the default's, else allowed. `name` with no own `instances` entry (a ClassicBot identity) gets the defaults'.
|
|
71
|
+
* the default's, else allowed (off for OFF_UNLESS_ON). `name` with no own `instances` entry (a ClassicBot identity) gets the defaults'.
|
|
58
72
|
*/
|
|
59
73
|
export declare function dashboardFeaturesOffIn(fleet: unknown, name: string): DashboardFeature[];
|
|
60
74
|
/**
|
|
@@ -6,15 +6,21 @@
|
|
|
6
6
|
*
|
|
7
7
|
* - `appearance`: its own look on the dashboard — theme, pictures, widgets, ambient, effects, mods it proposes;
|
|
8
8
|
* - `task_board`: the task board (`task`, and `agend task …`);
|
|
9
|
-
* - `web_settings`: Settings → Web appearance for the person (`get_web_settings`, `set_web_settings`)
|
|
9
|
+
* - `web_settings`: Settings → Web appearance for the person (`get_web_settings`, `set_web_settings`);
|
|
10
|
+
* - `office` (#2578), stored separately as `office_access`: its own character in Fleet → Org chart → Office — walking, a speech bubble, a pose
|
|
11
|
+
* (`office_view`, `office_set`).
|
|
10
12
|
*
|
|
11
13
|
* Unset is allowed: a fleet that switches nothing off works as before, and the profile still decides what an agent
|
|
12
|
-
* has. `false` takes the feature's tools away whatever the profile carries: refused at the fleet's checks
|
|
14
|
+
* has — except for a feature in OFF_UNLESS_ON (`office`), which is off until a person sets it true. `false` takes the feature's tools away whatever the profile carries: refused at the fleet's checks
|
|
13
15
|
* (tool-permissions.ts's sinks, read at each call — no restart) and left out of the agent's tool menu from its next
|
|
14
16
|
* start (AGEND_DASHBOARD_OFF, read by mcp-server). Like a profile, policy protection for the resolved identity, not
|
|
15
17
|
* isolation between same-uid agents with a shell.
|
|
16
18
|
*/
|
|
17
|
-
export const DASHBOARD_FEATURES = ["appearance", "task_board", "web_settings"];
|
|
19
|
+
export const DASHBOARD_FEATURES = ["appearance", "task_board", "web_settings", "office"];
|
|
20
|
+
/** The features a person switches on (#2578): absent (or null) is off for these, never allowed. */
|
|
21
|
+
export const OFF_UNLESS_ON = new Set(["office"]);
|
|
22
|
+
/** What a feature is when nothing (not the instance, not the defaults) says: allowed, or off for OFF_UNLESS_ON. */
|
|
23
|
+
export const dashboardFeatureDefault = (feature) => !OFF_UNLESS_ON.has(feature);
|
|
18
24
|
/**
|
|
19
25
|
* What a NEW fleet.yaml says about the features (the user's decision, 2026-10-22): the task board is off until the
|
|
20
26
|
* person switches it on (Settings → defaults, or per agent). Written, visibly, by every path that creates the file —
|
|
@@ -34,6 +40,7 @@ export const DASHBOARD_FEATURE_TOOLS = {
|
|
|
34
40
|
],
|
|
35
41
|
task_board: ["task"],
|
|
36
42
|
web_settings: ["get_web_settings", "set_web_settings"],
|
|
43
|
+
office: ["office_view", "office_set"],
|
|
37
44
|
};
|
|
38
45
|
const FEATURE_OF = new Map(DASHBOARD_FEATURES.flatMap((f) => DASHBOARD_FEATURE_TOOLS[f].map((tool) => [tool, f])));
|
|
39
46
|
/** The feature a tool belongs to, or null for a tool no switch governs. */
|
|
@@ -41,17 +48,20 @@ export function dashboardFeatureOf(tool) {
|
|
|
41
48
|
return FEATURE_OF.get(tool) ?? null;
|
|
42
49
|
}
|
|
43
50
|
const isFeature = (k) => DASHBOARD_FEATURES.includes(k);
|
|
44
|
-
/** The features switched off
|
|
51
|
+
/** The features switched off in an instance's `dashboard` as resolved: `false`, and an OFF_UNLESS_ON one not `true`. */
|
|
45
52
|
export function dashboardFeaturesOff(access) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return DASHBOARD_FEATURES.filter((f) => access[f] === false);
|
|
53
|
+
const a = access && typeof access === "object" && !Array.isArray(access) ? access : {};
|
|
54
|
+
return DASHBOARD_FEATURES.filter((f) => (OFF_UNLESS_ON.has(f) ? a[f] !== true : a[f] === false));
|
|
49
55
|
}
|
|
50
56
|
/** The refusal for `tool` when its feature is in `off`, else null. */
|
|
51
57
|
function refusalFor(off, tool) {
|
|
52
58
|
const feature = dashboardFeatureOf(tool);
|
|
53
59
|
if (!feature || !off.includes(feature))
|
|
54
60
|
return null;
|
|
61
|
+
if (OFF_UNLESS_ON.has(feature)) {
|
|
62
|
+
return `${tool} is not available to this instance: its dashboard feature "${feature}" is off until the person switches it on (${feature === "office" ? "office_access" : `dashboard.${feature}`}: true). `
|
|
63
|
+
+ "Do not retry it; tell the person if you need it.";
|
|
64
|
+
}
|
|
55
65
|
return `${tool} is not available to this instance: the person switched its dashboard feature "${feature}" off (dashboard.${feature}: false). `
|
|
56
66
|
+ "Do not retry it; tell the person if you need it.";
|
|
57
67
|
}
|
|
@@ -106,15 +116,54 @@ export function dashboardSwitches(value) {
|
|
|
106
116
|
}
|
|
107
117
|
return out;
|
|
108
118
|
}
|
|
119
|
+
/** Office lives beside dashboard so published rollback validators never see a new feature in that closed map. */
|
|
120
|
+
export function officeAccessValue(config) {
|
|
121
|
+
return config && Object.hasOwn(config, "office_access") ? config.office_access : config?.dashboard?.office;
|
|
122
|
+
}
|
|
123
|
+
export function dashboardAccessOf(config) {
|
|
124
|
+
const access = dashboardSwitches(config?.dashboard), office = officeAccessValue(config);
|
|
125
|
+
delete access.office;
|
|
126
|
+
if (typeof office === "boolean")
|
|
127
|
+
access.office = office;
|
|
128
|
+
return access;
|
|
129
|
+
}
|
|
130
|
+
/** Transitional dashboard.office input is accepted, but never written by a managed save. Canonical values win. */
|
|
131
|
+
export function normalizeOfficeStorage(fleet) {
|
|
132
|
+
for (const config of [fleet?.defaults, ...Object.values(fleet?.instances ?? {})]) {
|
|
133
|
+
if (!config || typeof config !== "object" || Array.isArray(config))
|
|
134
|
+
continue;
|
|
135
|
+
const item = config;
|
|
136
|
+
if (!item.dashboard || typeof item.dashboard !== "object" || !Object.hasOwn(item.dashboard, "office"))
|
|
137
|
+
continue;
|
|
138
|
+
if (!Object.hasOwn(item, "office_access") && typeof item.dashboard.office === "boolean")
|
|
139
|
+
item.office_access = item.dashboard.office;
|
|
140
|
+
const { office: _office, ...dashboard } = item.dashboard;
|
|
141
|
+
item.dashboard = dashboard;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Accept an older Settings client, but project/save its Office edit using the canonical field. */
|
|
145
|
+
export function officeInputPatch(value) {
|
|
146
|
+
const result = { ...value };
|
|
147
|
+
if (value.dashboard && typeof value.dashboard === "object" && !Array.isArray(value.dashboard) && Object.hasOwn(value.dashboard, "office")) {
|
|
148
|
+
const { office, ...dashboard } = value.dashboard;
|
|
149
|
+
result.dashboard = dashboard;
|
|
150
|
+
if (!Object.hasOwn(value, "office_access"))
|
|
151
|
+
result.office_access = office;
|
|
152
|
+
}
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
export function hasLegacyOffice(fleet) {
|
|
156
|
+
return [fleet?.defaults, ...Object.values(fleet?.instances ?? {})].some((item) => item?.dashboard && Object.hasOwn(item.dashboard, "office"));
|
|
157
|
+
}
|
|
109
158
|
/**
|
|
110
159
|
* The features switched off in a fleet config for `name`: each feature's own switch where the instance has one, else
|
|
111
|
-
* the default's, else allowed. `name` with no own `instances` entry (a ClassicBot identity) gets the defaults'.
|
|
160
|
+
* the default's, else allowed (off for OFF_UNLESS_ON). `name` with no own `instances` entry (a ClassicBot identity) gets the defaults'.
|
|
112
161
|
*/
|
|
113
162
|
export function dashboardFeaturesOffIn(fleet, name) {
|
|
114
163
|
const f = fleet && typeof fleet === "object" ? fleet : {};
|
|
115
164
|
const instances = f.instances && typeof f.instances === "object" ? f.instances : {};
|
|
116
165
|
const inst = Object.hasOwn(instances, name) ? instances[name] : undefined; // a name is a key of its own, never an inherited one
|
|
117
|
-
return dashboardFeaturesOff({ ...
|
|
166
|
+
return dashboardFeaturesOff({ ...dashboardAccessOf(f.defaults), ...dashboardAccessOf(inst) });
|
|
118
167
|
}
|
|
119
168
|
/**
|
|
120
169
|
* (a) An agent without the task board is not told to use it: the built-in workflow's task board section ("## Progress
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dashboard-permissions.js","sourceRoot":"","sources":["../src/dashboard-permissions.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"dashboard-permissions.js","sourceRoot":"","sources":["../src/dashboard-permissions.ts"],"names":[],"mappings":"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"}
|
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -65,6 +65,7 @@ import { OwnerCssStore } from "./web-owner-css-store.js";
|
|
|
65
65
|
import { ThemeStore } from "./web-theme-store.js";
|
|
66
66
|
import { OfficeStore, OfficeWriteLimiter } from "./web-office-store.js";
|
|
67
67
|
import { OfficeSkinStore } from "./web-office-skins.js";
|
|
68
|
+
import { OfficeActs } from "./web-office-acts.js";
|
|
68
69
|
import { WebAppearance } from "./web-appearance.js";
|
|
69
70
|
import { WebEffectLibrary } from "./web-effect-library.js";
|
|
70
71
|
import { WebEffectTrials } from "./web-effect-trials.js";
|
|
@@ -658,6 +659,14 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
658
659
|
readonly officeSkinWrites: OfficeWriteLimiter;
|
|
659
660
|
/** How often a person may save the offices (PUT /ui/offices); memory only, as the appearance limiter. */
|
|
660
661
|
readonly officeWrites: OfficeWriteLimiter;
|
|
662
|
+
private officeActsInstance?;
|
|
663
|
+
/** #2578: the agents' acts in the Office view (office_view / office_set), memory only; every change is `office_acts`. */
|
|
664
|
+
get officeActs(): OfficeActs;
|
|
665
|
+
/**
|
|
666
|
+
* #2578: each instance's state as the org chart shows it (fleet-org.js orgState, from the same fields the status
|
|
667
|
+
* frame and the Needs-you list carry) and its display name (resolveInstanceIdentity, as getUiStatus) — read once.
|
|
668
|
+
*/
|
|
669
|
+
private officePeople;
|
|
661
670
|
/** #1629: the theme tools, a person's reset and lock, and the one appearance rate limiter (shared with effects). */
|
|
662
671
|
get webAppearance(): WebAppearance;
|
|
663
672
|
private effectLibraryInstance?;
|
|
@@ -1633,6 +1642,10 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
1633
1642
|
remainingSeconds?: number;
|
|
1634
1643
|
noExpiry?: true;
|
|
1635
1644
|
};
|
|
1645
|
+
/** Notices use the first explicit admin of the owning connection; never a guest/paired account. */
|
|
1646
|
+
private noticeAdmin;
|
|
1647
|
+
/** Best-effort private delivery. The caller retains its existing topic fallback and authority fences. */
|
|
1648
|
+
private tryNoticeDm;
|
|
1636
1649
|
confirmPublicWebLogin(info: {
|
|
1637
1650
|
label: string;
|
|
1638
1651
|
handle: string;
|
|
@@ -2405,6 +2418,8 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
2405
2418
|
*/
|
|
2406
2419
|
private logConfigWarningsAtStartup;
|
|
2407
2420
|
/** One-time upgrade migration; invalid YAML is never rewritten. */
|
|
2421
|
+
private migrateNoticeDeliveryStorage;
|
|
2422
|
+
private migrateOfficeStorage;
|
|
2408
2423
|
private slimFleetConfigAtStartup;
|
|
2409
2424
|
private writeFleetConfigBackup;
|
|
2410
2425
|
private patchFleetDocument;
|
|
@@ -2994,7 +3009,7 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
2994
3009
|
/** Persistently enable advanced tips through the admin-only slash command. */
|
|
2995
3010
|
unlockAdvancedTips(userId: string): boolean;
|
|
2996
3011
|
/** Post one fresh nonce-armed tip in a known General channel. */
|
|
2997
|
-
promptTip(generalName: string, adapter: ChannelAdapter, chatId: string, threadId?: string): Promise<"posted" | "empty" | "unavailable">;
|
|
3012
|
+
promptTip(generalName: string, adapter: ChannelAdapter, chatId: string, threadId?: string, directUserId?: string): Promise<"posted" | "empty" | "unavailable">;
|
|
2998
3013
|
private promptAdvancedTipUnlock;
|
|
2999
3014
|
private sendTipToGeneral;
|
|
3000
3015
|
private handleTipDismiss;
|
package/dist/fleet-manager.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { hasLegacyOffice, normalizeOfficeStorage } from "./dashboard-permissions.js";
|
|
2
|
+
import { loginNoticeMode, tipNoticeMode, normalizeNoticeDelivery, setNoticeMode } from "./notice-delivery.js";
|
|
3
|
+
import { DEFAULT_REPLY_TRIGGERS } from "./reply-triggers.js";
|
|
1
4
|
import { WorkingRecoveryCoordinator, WORKING_RECOVERY_KIND, buildWorkingRecoveryPrompt } from "./working-recovery.js";
|
|
2
5
|
import { PUBLIC_TUNNEL_TOKEN_ENV, PUBLIC_TUNNEL_TOKEN_HINT, normalizePublicTunnelToken } from "./public-tunnel-config.js";
|
|
3
6
|
import { humanOwnerObjectId, webHumanOrigin } from "./human-delivery-receipts.js";
|
|
@@ -160,6 +163,7 @@ import { OwnerCssStore } from "./web-owner-css-store.js";
|
|
|
160
163
|
import { ThemeStore } from "./web-theme-store.js";
|
|
161
164
|
import { OfficeStore, OfficeWriteLimiter } from "./web-office-store.js";
|
|
162
165
|
import { OfficeSkinStore } from "./web-office-skins.js";
|
|
166
|
+
import { OfficeActs } from "./web-office-acts.js";
|
|
163
167
|
import { WebAppearance } from "./web-appearance.js";
|
|
164
168
|
import { WebEffectLibrary } from "./web-effect-library.js";
|
|
165
169
|
import { WebEffectTrials } from "./web-effect-trials.js";
|
|
@@ -1147,6 +1151,53 @@ export class FleetManager {
|
|
|
1147
1151
|
officeSkinWrites = new OfficeWriteLimiter(undefined, { perWindow: 10, windowMs: 60_000 });
|
|
1148
1152
|
/** How often a person may save the offices (PUT /ui/offices); memory only, as the appearance limiter. */
|
|
1149
1153
|
officeWrites = new OfficeWriteLimiter();
|
|
1154
|
+
officeActsInstance;
|
|
1155
|
+
/** #2578: the agents' acts in the Office view (office_view / office_set), memory only; every change is `office_acts`. */
|
|
1156
|
+
get officeActs() {
|
|
1157
|
+
return (this.officeActsInstance ??= new OfficeActs({
|
|
1158
|
+
offices: () => this.officeStore.list().offices,
|
|
1159
|
+
pack: id => this.officeSkins.pack(id),
|
|
1160
|
+
chart: () => { const c = this.orgChart(); return { names: Object.keys(c.instances), teams: c.teams }; },
|
|
1161
|
+
people: () => this.officePeople(),
|
|
1162
|
+
changed: acts => this.emitSseEvent("office_acts", { acts, now: Date.now() }),
|
|
1163
|
+
}));
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* #2578: each instance's state as the org chart shows it (fleet-org.js orgState, from the same fields the status
|
|
1167
|
+
* frame and the Needs-you list carry) and its display name (resolveInstanceIdentity, as getUiStatus) — read once.
|
|
1168
|
+
*/
|
|
1169
|
+
officePeople() {
|
|
1170
|
+
const needs = new Map();
|
|
1171
|
+
for (const item of this.needsYouItems())
|
|
1172
|
+
needs.set(item.instance, (needs.get(item.instance) ?? 0) + 1);
|
|
1173
|
+
const classicRooms = new Map((this.classicChannels?.getAll() ?? []).map(ch => [ch.instanceName, ch]));
|
|
1174
|
+
let profiles = null;
|
|
1175
|
+
return {
|
|
1176
|
+
stateOf: name => {
|
|
1177
|
+
if (!this.isKnownInstance(name))
|
|
1178
|
+
return "missing";
|
|
1179
|
+
const p = this.instancePresentation(name), status = this.getInstanceStatus(name);
|
|
1180
|
+
if (p.state === "awaiting_input" || (needs.get(name) ?? 0) > 0)
|
|
1181
|
+
return "needs";
|
|
1182
|
+
if (p.startup_phase === "queued" || p.startup_phase === "starting")
|
|
1183
|
+
return p.startup_phase;
|
|
1184
|
+
if (status === "crashed" || status === "paused")
|
|
1185
|
+
return status;
|
|
1186
|
+
if (status !== "running")
|
|
1187
|
+
return "stopped";
|
|
1188
|
+
return p.execution_state === "stuck" || p.execution_state === "working" ? p.execution_state : "idle";
|
|
1189
|
+
},
|
|
1190
|
+
displayName: name => {
|
|
1191
|
+
try {
|
|
1192
|
+
profiles ??= profileIdentities(this.dataDir);
|
|
1193
|
+
return resolveInstanceIdentity({ cfg: this.fleetConfig?.instances[name], classic: classicRooms.get(name), profile: profiles.get(name) }).display_name || undefined;
|
|
1194
|
+
}
|
|
1195
|
+
catch {
|
|
1196
|
+
return undefined;
|
|
1197
|
+
}
|
|
1198
|
+
},
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1150
1201
|
/** #1629: the theme tools, a person's reset and lock, and the one appearance rate limiter (shared with effects). */
|
|
1151
1202
|
get webAppearance() {
|
|
1152
1203
|
return (this.webAppearanceService ??= new WebAppearance(this.themeStore, () => this.fleetConfig?.web ?? null, () => { try {
|
|
@@ -3308,7 +3359,7 @@ export class FleetManager {
|
|
|
3308
3359
|
await data.respond(t("permission.denied"));
|
|
3309
3360
|
return;
|
|
3310
3361
|
}
|
|
3311
|
-
this.fleetConfig
|
|
3362
|
+
setNoticeMode(this.fleetConfig, "tips", mode === "on");
|
|
3312
3363
|
this.saveFleetConfig();
|
|
3313
3364
|
await data.respond(t(mode === "on" ? "tips.enabled" : "tips.disabled"));
|
|
3314
3365
|
return;
|
|
@@ -5098,6 +5149,7 @@ export class FleetManager {
|
|
|
5098
5149
|
}
|
|
5099
5150
|
classicBehaviorUpdate(instanceName) {
|
|
5100
5151
|
return {
|
|
5152
|
+
reply_triggers: this.classicChannels?.getReplyTriggersByInstance(instanceName, this.fleetConfig?.defaults?.reply_triggers) ?? DEFAULT_REPLY_TRIGGERS,
|
|
5101
5153
|
tool_progress: this.classicChannels?.getToolProgressByInstance(instanceName, this.fleetConfig?.defaults?.tool_progress) ?? "off",
|
|
5102
5154
|
reply_completion_guard: this.classicChannels?.getReplyCompletionGuardByInstance(instanceName, this.fleetConfig?.defaults?.reply_completion_guard) ?? true,
|
|
5103
5155
|
};
|
|
@@ -6446,11 +6498,33 @@ export class FleetManager {
|
|
|
6446
6498
|
getPublicWebStatus() {
|
|
6447
6499
|
return this.publicWebLink?.status() ?? { state: "closed" };
|
|
6448
6500
|
}
|
|
6501
|
+
/** Notices use the first explicit admin of the owning connection; never a guest/paired account. */
|
|
6502
|
+
noticeAdmin(adapterId) {
|
|
6503
|
+
return this.adminListOf(adapterId)?.find(id => id.length > 0);
|
|
6504
|
+
}
|
|
6505
|
+
/** Best-effort private delivery. The caller retains its existing topic fallback and authority fences. */
|
|
6506
|
+
async tryNoticeDm(adapter, userId, text) {
|
|
6507
|
+
if (!userId || !adapter?.sendDirect)
|
|
6508
|
+
return false;
|
|
6509
|
+
try {
|
|
6510
|
+
await withinBudget(adapter.sendDirect(userId, text, { disablePreview: true }), performance.now() + 2_000);
|
|
6511
|
+
return true;
|
|
6512
|
+
}
|
|
6513
|
+
catch {
|
|
6514
|
+
this.logger.info({ adapterId: adapter.id }, "Fleet notice DM failed; falling back to the topic");
|
|
6515
|
+
return false;
|
|
6516
|
+
}
|
|
6517
|
+
}
|
|
6449
6518
|
async confirmPublicWebLogin(info, current) {
|
|
6450
6519
|
if (!current() || !this.publicOwnerCurrent(info.owner))
|
|
6451
6520
|
throw new Error("public owner unavailable");
|
|
6452
6521
|
const adapter = info.owner.binding;
|
|
6453
|
-
|
|
6522
|
+
const text = t("web.public_login_notice", info.label, info.handle.slice(0, 8));
|
|
6523
|
+
if (loginNoticeMode(this.fleetConfig?.web) !== "dm" || !await this.tryNoticeDm(adapter, info.owner.userId, text)) {
|
|
6524
|
+
if (!current() || !this.publicOwnerCurrent(info.owner))
|
|
6525
|
+
throw new Error("public owner changed");
|
|
6526
|
+
await adapter.sendText(info.owner.chatId, text, { threadId: info.owner.threadId, allowedMentions: { parse: [] } });
|
|
6527
|
+
}
|
|
6454
6528
|
if (!current() || !this.publicOwnerCurrent(info.owner))
|
|
6455
6529
|
throw new Error("public owner changed");
|
|
6456
6530
|
}
|
|
@@ -6468,7 +6542,12 @@ export class FleetManager {
|
|
|
6468
6542
|
if (!open)
|
|
6469
6543
|
throw new Error("guest public sign-in unavailable");
|
|
6470
6544
|
const adapter = open.owner.binding;
|
|
6471
|
-
|
|
6545
|
+
const text = t("web.guest_public_login_notice", this.webPerson(info.account).name, info.label, this.guestScope(info.account).size, info.handle.slice(0, 8));
|
|
6546
|
+
if (loginNoticeMode(this.fleetConfig?.web) !== "dm" || !await this.tryNoticeDm(adapter, open.owner.userId, text)) {
|
|
6547
|
+
if (!admitted())
|
|
6548
|
+
throw new Error("guest public sign-in changed");
|
|
6549
|
+
await adapter.sendText(open.owner.chatId, text, { threadId: open.owner.threadId, allowedMentions: { parse: [] } });
|
|
6550
|
+
}
|
|
6472
6551
|
if (!admitted())
|
|
6473
6552
|
throw new Error("guest public sign-in changed");
|
|
6474
6553
|
}
|
|
@@ -7306,17 +7385,26 @@ export class FleetManager {
|
|
|
7306
7385
|
}
|
|
7307
7386
|
/** Called by the sign-in endpoint: a login the operator did not make should be visible to them. */
|
|
7308
7387
|
onWebLogin(info) {
|
|
7309
|
-
//
|
|
7310
|
-
|
|
7311
|
-
if (
|
|
7312
|
-
|
|
7388
|
+
// Keep the existing false policy: guest and public-link security notices remain mandatory.
|
|
7389
|
+
const guest = info.tier === "guest" && info.owner;
|
|
7390
|
+
if (!guest && this.fleetConfig?.web?.notify_login === false)
|
|
7391
|
+
return;
|
|
7392
|
+
const text = guest
|
|
7393
|
+
? t("web.guest_login_notice", this.webPerson(info.owner).name, info.label, this.guestScope(info.owner).size, info.handle.slice(0, 8))
|
|
7394
|
+
: t("web.login_notice", info.label, info.surface, info.handle.slice(0, 8));
|
|
7395
|
+
if (loginNoticeMode(this.fleetConfig?.web) === "dm") {
|
|
7396
|
+
const adapterId = info.owner?.adapterId;
|
|
7397
|
+
const adapter = adapterId ? this.adapters.get(adapterId) : undefined;
|
|
7398
|
+
// A local guest's own account must never receive the admin's security notice.
|
|
7399
|
+
const userId = guest ? (adapterId ? this.noticeAdmin(adapterId) : undefined)
|
|
7400
|
+
: info.owner && this.isFleetAdmin(info.owner.userId, adapterId) ? info.owner.userId : undefined;
|
|
7401
|
+
void this.tryNoticeDm(adapter, userId, text).then(sent => { if (!sent)
|
|
7402
|
+
this.notifyFleetError(text); })
|
|
7403
|
+
.catch(() => this.logger.warn("Web sign-in notice could not be delivered"));
|
|
7313
7404
|
return;
|
|
7314
7405
|
}
|
|
7315
|
-
|
|
7316
|
-
|
|
7317
|
-
// The session handle makes each notice distinct: notifyFleetError throttles by text, and a second
|
|
7318
|
-
// sign-in from the same kind of browser is exactly the one the operator most needs to hear about.
|
|
7319
|
-
this.notifyFleetError(t("web.login_notice", info.label, info.surface, info.handle.slice(0, 8)));
|
|
7406
|
+
// Exactly the old topic path, including the session-handle throttle key.
|
|
7407
|
+
this.notifyFleetError(text);
|
|
7320
7408
|
}
|
|
7321
7409
|
getDashboardAccess() {
|
|
7322
7410
|
return { ready: this.healthServerListening, token: this.webToken };
|
|
@@ -11122,7 +11210,7 @@ export class FleetManager {
|
|
|
11122
11210
|
if (!ipc || !fleetRequestId)
|
|
11123
11211
|
return;
|
|
11124
11212
|
const type = String(msg.type);
|
|
11125
|
-
const responseType = isCanvasWorkerTool(type.replace(/^fleet_/, "")) ? "fleet_web_theme_response"
|
|
11213
|
+
const responseType = isCanvasWorkerTool(type.replace(/^fleet_/, "")) || type === "fleet_office_view" || type === "fleet_office_set" ? "fleet_web_theme_response"
|
|
11126
11214
|
: type.startsWith("fleet_schedule_") ? "fleet_schedule_response"
|
|
11127
11215
|
: type.startsWith("fleet_decision_") ? "fleet_decision_response"
|
|
11128
11216
|
: type === "fleet_task" ? "fleet_task_response"
|
|
@@ -11176,7 +11264,8 @@ export class FleetManager {
|
|
|
11176
11264
|
|| type === "fleet_get_web_appearance" || type === "fleet_preview_web_appearance"
|
|
11177
11265
|
|| type === "fleet_set_web_widget" || type === "fleet_remove_web_widget"
|
|
11178
11266
|
|| type === "fleet_set_web_ambient" || type === "fleet_clear_web_ambient"
|
|
11179
|
-
|| type === "fleet_export_web_mod" || type === "fleet_propose_web_mod"
|
|
11267
|
+
|| type === "fleet_export_web_mod" || type === "fleet_propose_web_mod"
|
|
11268
|
+
|| type === "fleet_office_view" || type === "fleet_office_set") {
|
|
11180
11269
|
this.handleWebTheme(name, msg);
|
|
11181
11270
|
return;
|
|
11182
11271
|
}
|
|
@@ -11197,7 +11286,8 @@ export class FleetManager {
|
|
|
11197
11286
|
const result = tool === "get_web_appearance" || tool === "preview_web_appearance"
|
|
11198
11287
|
? this.appearanceTools.handle(instanceName, tool, args)
|
|
11199
11288
|
: tool === "export_web_mod" || tool === "propose_web_mod" ? this.agentMods.handle(instanceName, tool, args)
|
|
11200
|
-
: this.
|
|
11289
|
+
: tool === "office_view" || tool === "office_set" ? this.officeActs.handle(instanceName, tool, args)
|
|
11290
|
+
: this.webAppearance.handleTool(instanceName, tool, args);
|
|
11201
11291
|
ipc.send({ type: "fleet_web_theme_response", fleetRequestId, result });
|
|
11202
11292
|
}
|
|
11203
11293
|
catch (err) {
|
|
@@ -11633,6 +11723,8 @@ export class FleetManager {
|
|
|
11633
11723
|
return this.appearanceTools.handle(instance, tool, args);
|
|
11634
11724
|
if (tool === "export_web_mod" || tool === "propose_web_mod")
|
|
11635
11725
|
return this.agentMods.handle(instance, tool, args);
|
|
11726
|
+
if (tool === "office_view" || tool === "office_set")
|
|
11727
|
+
return this.officeActs.handle(instance, tool, args); // #2578
|
|
11636
11728
|
return this.webAppearance.handleTool(instance, tool, args);
|
|
11637
11729
|
}
|
|
11638
11730
|
async handlePreviewEmojisHttp(instance, args) {
|
|
@@ -12067,6 +12159,23 @@ export class FleetManager {
|
|
|
12067
12159
|
return;
|
|
12068
12160
|
if (!this.savedFleetConfigSnapshot)
|
|
12069
12161
|
this.savedFleetConfigSnapshot = structuredClone(this.fleetConfig);
|
|
12162
|
+
normalizeNoticeDelivery(this.fleetConfig);
|
|
12163
|
+
normalizeOfficeStorage(this.fleetConfig);
|
|
12164
|
+
explicitPatches = explicitPatches.flatMap(patch => {
|
|
12165
|
+
const path = patch.path;
|
|
12166
|
+
if (path.at(-2) === "dashboard" && path.at(-1) === "office" && !patch.remove) {
|
|
12167
|
+
return [{ ...patch, path: [...path.slice(0, -2), "office_access"] }, { path, remove: true }];
|
|
12168
|
+
}
|
|
12169
|
+
if (path.at(-1) === "dashboard" && patch.value && typeof patch.value === "object" && Object.hasOwn(patch.value, "office")) {
|
|
12170
|
+
const { office, ...dashboard } = patch.value;
|
|
12171
|
+
return [{ ...patch, value: dashboard }, { path: [...path.slice(0, -1), "office_access"], value: office, remove: office === null }];
|
|
12172
|
+
}
|
|
12173
|
+
if (patch.path.join(".") === "web.notify_login" && patch.value === "dm")
|
|
12174
|
+
return [{ ...patch, value: true }, { path: ["web", "notice_delivery", "login"], value: "dm" }];
|
|
12175
|
+
if (patch.path.join(".") === "defaults.tips" && patch.value === "dm")
|
|
12176
|
+
return [{ ...patch, value: true }, { path: ["web", "notice_delivery", "tips"], value: "dm" }];
|
|
12177
|
+
return [patch];
|
|
12178
|
+
});
|
|
12070
12179
|
// Re-read immediately before patching so an unrelated concurrent/manual
|
|
12071
12180
|
// edit is retained. Invalid concurrent YAML is never overwritten.
|
|
12072
12181
|
const source = existsSync(this.configPath) ? readFileSync(this.configPath, "utf-8") : "{}\n";
|
|
@@ -12182,7 +12291,43 @@ export class FleetManager {
|
|
|
12182
12291
|
this.logger.warn({ path: w.path }, `fleet.yaml: ${w.path ? `${w.path}: ` : ""}${w.message}`);
|
|
12183
12292
|
}
|
|
12184
12293
|
/** One-time upgrade migration; invalid YAML is never rewritten. */
|
|
12294
|
+
migrateNoticeDeliveryStorage() {
|
|
12295
|
+
if (this.fleetConfig && this.configPath && (this.fleetConfig.web?.notify_login === "dm" || this.fleetConfig.defaults.tips === "dm")
|
|
12296
|
+
&& validateFleetConfig(this.rawFleetConfig).valid) {
|
|
12297
|
+
try {
|
|
12298
|
+
this.writeFleetConfigBackup(readFileSync(this.configPath, "utf8"));
|
|
12299
|
+
this.saveFleetConfig();
|
|
12300
|
+
this.logger.info("Stored DM notice routing with downgrade-safe boolean fields");
|
|
12301
|
+
}
|
|
12302
|
+
catch (err) {
|
|
12303
|
+
this.logger.warn({ err }, "Could not migrate DM notice routing; keeping the original file");
|
|
12304
|
+
}
|
|
12305
|
+
}
|
|
12306
|
+
}
|
|
12307
|
+
migrateOfficeStorage() {
|
|
12308
|
+
if (!this.fleetConfig || !this.configPath || !hasLegacyOffice(this.rawFleetConfig) || !validateFleetConfig(this.rawFleetConfig).valid)
|
|
12309
|
+
return;
|
|
12310
|
+
try {
|
|
12311
|
+
this.writeFleetConfigBackup(readFileSync(this.configPath, "utf8"));
|
|
12312
|
+
const patches = [];
|
|
12313
|
+
const raw = this.rawFleetConfig;
|
|
12314
|
+
for (const [path, item] of [[["defaults"], raw.defaults], ...Object.entries(raw.instances ?? {}).map(([name, value]) => [["instances", name], value])]) {
|
|
12315
|
+
if (!item?.dashboard || !Object.hasOwn(item.dashboard, "office"))
|
|
12316
|
+
continue;
|
|
12317
|
+
patches.push({ path: [...path, "dashboard", "office"], remove: true });
|
|
12318
|
+
if (!Object.hasOwn(item, "office_access") && typeof item.dashboard.office === "boolean")
|
|
12319
|
+
patches.push({ path: [...path, "office_access"], value: item.dashboard.office });
|
|
12320
|
+
}
|
|
12321
|
+
this.saveFleetConfig(patches);
|
|
12322
|
+
this.logger.info("Stored Office access outside dashboard for downgrade compatibility");
|
|
12323
|
+
}
|
|
12324
|
+
catch (err) {
|
|
12325
|
+
this.logger.warn({ err }, "Could not migrate Office access; keeping the original file");
|
|
12326
|
+
}
|
|
12327
|
+
}
|
|
12185
12328
|
slimFleetConfigAtStartup() {
|
|
12329
|
+
this.migrateOfficeStorage();
|
|
12330
|
+
this.migrateNoticeDeliveryStorage();
|
|
12186
12331
|
const redundantPaths = collectRedundantInstanceDefaultPaths(this.rawFleetConfig);
|
|
12187
12332
|
if (redundantPaths.length === 0)
|
|
12188
12333
|
return;
|
|
@@ -12405,6 +12550,7 @@ export class FleetManager {
|
|
|
12405
12550
|
this.effectToolsService?.forget(name);
|
|
12406
12551
|
this.mods.forgetInstance(name);
|
|
12407
12552
|
this.agentMods.forget(name);
|
|
12553
|
+
this.officeActsInstance?.forget(name);
|
|
12408
12554
|
}
|
|
12409
12555
|
catch (err) {
|
|
12410
12556
|
this.logger.warn({ err: err.message, name }, "Dropping a removed instance's web theme failed");
|
|
@@ -14782,14 +14928,14 @@ export class FleetManager {
|
|
|
14782
14928
|
}
|
|
14783
14929
|
}
|
|
14784
14930
|
/** Post one fresh nonce-armed tip in a known General channel. */
|
|
14785
|
-
async promptTip(generalName, adapter, chatId, threadId) {
|
|
14931
|
+
async promptTip(generalName, adapter, chatId, threadId, directUserId) {
|
|
14786
14932
|
const state = this.readTipState();
|
|
14787
14933
|
if (!state)
|
|
14788
14934
|
return "unavailable";
|
|
14789
14935
|
if (!state.advancedUnlocked
|
|
14790
14936
|
&& visibleTipLevels(true).has("advanced")
|
|
14791
14937
|
&& canUnlockAdvancedTips(state.dismissed)) {
|
|
14792
|
-
return await this.promptAdvancedTipUnlock(generalName, adapter, chatId, threadId)
|
|
14938
|
+
return await this.promptAdvancedTipUnlock(generalName, adapter, chatId, threadId, directUserId)
|
|
14793
14939
|
? "posted"
|
|
14794
14940
|
: "unavailable";
|
|
14795
14941
|
}
|
|
@@ -14805,6 +14951,7 @@ export class FleetManager {
|
|
|
14805
14951
|
chatId,
|
|
14806
14952
|
threadId,
|
|
14807
14953
|
message: this.formatTip(tip),
|
|
14954
|
+
...(directUserId ? { deliver: (choices) => withinBudget(adapter.sendDirect(directUserId, this.formatTip(tip), { choices, disablePreview: true }), performance.now() + 5_000) } : {}),
|
|
14808
14955
|
choices: [
|
|
14809
14956
|
{ action: "dismiss", label: t("tips.dismiss") },
|
|
14810
14957
|
{ action: "confused", label: t("tips.confused") },
|
|
@@ -14816,7 +14963,7 @@ export class FleetManager {
|
|
|
14816
14963
|
});
|
|
14817
14964
|
return nonce ? "posted" : "unavailable";
|
|
14818
14965
|
}
|
|
14819
|
-
async promptAdvancedTipUnlock(generalName, adapter, chatId, threadId) {
|
|
14966
|
+
async promptAdvancedTipUnlock(generalName, adapter, chatId, threadId, directUserId) {
|
|
14820
14967
|
const nonce = await this.postNonceButtonPrompt({
|
|
14821
14968
|
prefix: TIP_UNLOCK_CALLBACK_PREFIX,
|
|
14822
14969
|
alertType: "tip",
|
|
@@ -14826,6 +14973,7 @@ export class FleetManager {
|
|
|
14826
14973
|
chatId,
|
|
14827
14974
|
threadId,
|
|
14828
14975
|
message: t("tips.advanced.unlock_prompt"),
|
|
14976
|
+
...(directUserId ? { deliver: (choices) => withinBudget(adapter.sendDirect(directUserId, t("tips.advanced.unlock_prompt"), { choices, disablePreview: true }), performance.now() + 5_000) } : {}),
|
|
14829
14977
|
choices: [{ action: "unlock", label: t("tips.advanced.unlock") }],
|
|
14830
14978
|
expiredText: t("tips.advanced.expired"),
|
|
14831
14979
|
// No allowAnyUser: unlocking changes a persistent setting, which typed and slash `/tips advanced on` reserve for a
|
|
@@ -14845,6 +14993,15 @@ export class FleetManager {
|
|
|
14845
14993
|
const topicId = this.fleetConfig?.instances[generalName]?.topic_id;
|
|
14846
14994
|
if (!adapter || !chatId)
|
|
14847
14995
|
return;
|
|
14996
|
+
if (this.fleetConfig && tipNoticeMode(this.fleetConfig) === "dm" && adapter.sendDirect) {
|
|
14997
|
+
const userId = this.noticeAdmin(adapter.id);
|
|
14998
|
+
if (userId) {
|
|
14999
|
+
const result = await this.promptTip(generalName, adapter, userId, undefined, userId);
|
|
15000
|
+
if (result !== "unavailable")
|
|
15001
|
+
return;
|
|
15002
|
+
// The failed prompt disarmed its nonce; a new topic prompt is safe.
|
|
15003
|
+
}
|
|
15004
|
+
}
|
|
14848
15005
|
const result = await this.promptTip(generalName, adapter, chatId, topicId != null ? String(topicId) : undefined);
|
|
14849
15006
|
if (result === "unavailable") {
|
|
14850
15007
|
this.logger.warn({ generalName }, "Daily tip could not be posted");
|
|
@@ -17067,7 +17224,7 @@ export class FleetManager {
|
|
|
17067
17224
|
// session only judges that verdict; it does not read the output for URLs or prompts.
|
|
17068
17225
|
const flow = {
|
|
17069
17226
|
backend,
|
|
17070
|
-
command: info.install,
|
|
17227
|
+
command: info.unattended ?? info.install,
|
|
17071
17228
|
successPattern: /$^/,
|
|
17072
17229
|
timeoutMs: 10 * 60 * 1000,
|
|
17073
17230
|
};
|
|
@@ -18068,8 +18225,11 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
18068
18225
|
// its ping in the reference, not the text). One hop only: a reply to a message of ours that itself answered a bot
|
|
18069
18226
|
// (or the sender) is a chain of bots answering each other — a mention still carries it on. A reply to our answer
|
|
18070
18227
|
// to a person is the ordinary handoff, and is addressed.
|
|
18071
|
-
const
|
|
18072
|
-
const
|
|
18228
|
+
const replyTriggers = this.classicChannels?.getReplyTriggers(channelId, msg.adapterId, this.fleetConfig?.defaults?.reply_triggers) ?? DEFAULT_REPLY_TRIGGERS;
|
|
18229
|
+
const repliesToUs = replyTriggers && !!adapterBotUserId && msg.replyToAuthorId === adapterBotUserId && msg.replyToChain !== true;
|
|
18230
|
+
// Snapshot/quoted content is context, never the forwarder's own mention.
|
|
18231
|
+
const addressText = msg.source === "discord" ? (msg.humanOriginalBody ?? text) : text;
|
|
18232
|
+
const isMentioned = (mentionTag && addressText.includes(mentionTag)) || repliesToUs;
|
|
18073
18233
|
if (!isMentioned) {
|
|
18074
18234
|
// Bare attachment (no @mention) — already saved above; just acknowledge.
|
|
18075
18235
|
if (saved) {
|
|
@@ -20792,6 +20952,8 @@ Plus the operational skills (fleet-health, instance-lifecycle, scheduling, sessi
|
|
|
20792
20952
|
// mark every row done and tell the user "changes applied".
|
|
20793
20953
|
return { rejected: why };
|
|
20794
20954
|
}
|
|
20955
|
+
this.migrateOfficeStorage();
|
|
20956
|
+
this.migrateNoticeDeliveryStorage();
|
|
20795
20957
|
if (canvasWorkerEnabled(oldConfig?.web) !== this.canvasWorkerEnabled()) {
|
|
20796
20958
|
this.canvasWorkerSettingChanged();
|
|
20797
20959
|
}
|