@songsid/agend 2.2.0-beta.9 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -24
- package/README.zh-TW.md +40 -24
- package/dist/agent-endpoint.js +3 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-whats-new.js +7 -1
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/auth-api.d.ts +3 -1
- package/dist/auth-api.js +15 -1
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/antigravity.d.ts +33 -0
- package/dist/backend/antigravity.js +126 -18
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.d.ts +3 -0
- package/dist/backend/claude-code.js +9 -0
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-metadata.d.ts +33 -0
- package/dist/backend/codex-metadata.js +122 -18
- package/dist/backend/codex-metadata.js.map +1 -1
- package/dist/backend/codex.d.ts +3 -0
- package/dist/backend/codex.js +17 -1
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/effort-metadata.d.ts +37 -1
- package/dist/backend/effort-metadata.js +86 -15
- package/dist/backend/effort-metadata.js.map +1 -1
- package/dist/backend/grok.d.ts +3 -0
- package/dist/backend/grok.js +9 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +3 -1
- package/dist/backend/kiro.js +7 -3
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/launch-effort.d.ts +61 -0
- package/dist/backend/launch-effort.js +170 -0
- package/dist/backend/launch-effort.js.map +1 -0
- package/dist/backend/types.d.ts +24 -0
- package/dist/backend/types.js +12 -1
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-command.d.ts +91 -0
- package/dist/backend-command.js +122 -0
- package/dist/backend-command.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +12 -0
- package/dist/channel/adapters/discord.js +49 -2
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +18 -0
- package/dist/channel/adapters/telegram.js +24 -3
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +2 -0
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/tool-router.d.ts +2 -0
- package/dist/channel/tool-router.js +1 -1
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/channel/types.d.ts +16 -0
- package/dist/cli.js +124 -24
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +2 -2
- package/dist/command-table.js +5 -2
- package/dist/command-table.js.map +1 -1
- package/dist/compact-watch.d.ts +86 -0
- package/dist/compact-watch.js +288 -0
- package/dist/compact-watch.js.map +1 -0
- package/dist/config-validator.js +39 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +9 -0
- package/dist/daemon.js +150 -9
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.d.ts +8 -1
- package/dist/delivery-outbox.js +6 -2
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/doctor.js +7 -0
- package/dist/doctor.js.map +1 -1
- package/dist/fleet-context.d.ts +7 -0
- package/dist/fleet-manager.d.ts +158 -9
- package/dist/fleet-manager.js +827 -118
- package/dist/fleet-manager.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +4 -3
- package/dist/forged-envelope-scan.js +4 -3
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +4 -1
- package/dist/install-lock.d.ts +18 -1
- package/dist/install-lock.js +30 -3
- package/dist/install-lock.js.map +1 -1
- package/dist/instance-avatar.d.ts +5 -4
- package/dist/instance-avatar.js +12 -8
- package/dist/instance-avatar.js.map +1 -1
- package/dist/instructions.js +2 -2
- package/dist/instructions.js.map +1 -1
- package/dist/kiro-compact-pane.d.ts +38 -0
- package/dist/kiro-compact-pane.js +57 -0
- package/dist/kiro-compact-pane.js.map +1 -0
- package/dist/launchd-handoff.d.ts +43 -0
- package/dist/launchd-handoff.js +56 -0
- package/dist/launchd-handoff.js.map +1 -0
- package/dist/locale.js +202 -30
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +10 -2
- package/dist/log-service.js.map +1 -1
- package/dist/login-shell.d.ts +21 -0
- package/dist/login-shell.js +98 -0
- package/dist/login-shell.js.map +1 -0
- package/dist/outbound-handlers.d.ts +27 -0
- package/dist/outbound-handlers.js +120 -36
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +12 -0
- package/dist/outbound-schemas.js +15 -4
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/provider-probe.d.ts +29 -0
- package/dist/provider-probe.js +198 -2
- package/dist/provider-probe.js.map +1 -1
- package/dist/public-web-gateway.d.ts +2 -0
- package/dist/public-web-gateway.js +11 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart-api.d.ts +1 -1
- package/dist/quickstart-api.js +8 -6
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +12 -0
- package/dist/quickstart.js +36 -6
- package/dist/quickstart.js.map +1 -1
- package/dist/reply-buttons-controller.d.ts +86 -5
- package/dist/reply-buttons-controller.js +271 -7
- package/dist/reply-buttons-controller.js.map +1 -1
- package/dist/reply-buttons.d.ts +48 -3
- package/dist/reply-buttons.js +105 -10
- package/dist/reply-buttons.js.map +1 -1
- package/dist/reply-polls.d.ts +85 -0
- package/dist/reply-polls.js +154 -0
- package/dist/reply-polls.js.map +1 -0
- package/dist/restart-guard.d.ts +6 -3
- package/dist/restart-guard.js +6 -3
- package/dist/restart-guard.js.map +1 -1
- package/dist/restart-progress.d.ts +0 -2
- package/dist/restart-progress.js +0 -2
- package/dist/restart-progress.js.map +1 -1
- package/dist/sd-notify.d.ts +22 -1
- package/dist/sd-notify.js +63 -10
- package/dist/sd-notify.js.map +1 -1
- package/dist/service-activation.d.ts +15 -7
- package/dist/service-activation.js +42 -26
- package/dist/service-activation.js.map +1 -1
- package/dist/service-installer.d.ts +24 -0
- package/dist/service-installer.js +49 -1
- package/dist/service-installer.js.map +1 -1
- package/dist/service-plan.d.ts +11 -0
- package/dist/service-plan.js +23 -0
- package/dist/service-plan.js.map +1 -1
- package/dist/systemd-peer-bus.d.ts +95 -0
- package/dist/systemd-peer-bus.js +430 -0
- package/dist/systemd-peer-bus.js.map +1 -0
- package/dist/systemd-runtime.d.ts +27 -1
- package/dist/systemd-runtime.js +69 -7
- package/dist/systemd-runtime.js.map +1 -1
- package/dist/tool-permissions.js +3 -3
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +68 -2
- package/dist/topic-commands.js +141 -27
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-jsonl.d.ts +7 -2
- package/dist/transcript-jsonl.js +13 -7
- package/dist/transcript-jsonl.js.map +1 -1
- package/dist/transcript-sources.js +6 -1
- package/dist/transcript-sources.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/ui/chat-commands.js +1 -0
- package/dist/ui/chat-render.js +55 -10
- package/dist/ui/chat-store.js +69 -5
- package/dist/ui/chat-strings.js +28 -16
- package/dist/ui/chat-thread.js +132 -14
- package/dist/ui/chat-tour.js +17 -14
- package/dist/ui/panel-chat.js +16 -10
- package/dist/ui/panel-fleet.js +15 -2
- package/dist/ui/panel-log.js +4 -4
- package/dist/ui/panel-needs.js +10 -7
- package/dist/ui/panel-settings.js +58 -7
- package/dist/ui/settings-dialogs.js +11 -6
- package/dist/ui/settings-model.js +3 -1
- package/dist/ui/settings-strings.js +24 -10
- package/dist/ui/settings-token.js +7 -0
- package/dist/ui/settings-wizard.js +5 -3
- package/dist/ui/shared/app-i18n.js +1 -1
- package/dist/ui/shared/app-stream.js +4 -1
- package/dist/ui/shared/app.css +52 -10
- package/dist/ui/shared/header-tools.js +34 -14
- package/dist/ui/shared/instance-switch.js +5 -2
- package/dist/ui/shared/panel-view.js +15 -4
- package/dist/ui/shared/signin.js +15 -9
- package/dist/ui/shared/ui-icons.js +1 -0
- package/dist/ui/shared/view-strings.js +10 -2
- package/dist/ui/signin.html +8 -3
- package/dist/update-check.d.ts +31 -0
- package/dist/update-check.js +47 -0
- package/dist/update-check.js.map +1 -1
- package/dist/update-launch.d.ts +48 -1
- package/dist/update-launch.js +159 -5
- package/dist/update-launch.js.map +1 -1
- package/dist/usage/providers.d.ts +28 -8
- package/dist/usage/providers.js +96 -41
- package/dist/usage/providers.js.map +1 -1
- package/dist/view-api.js +26 -9
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +44 -2
- package/dist/web-api.js +265 -57
- package/dist/web-api.js.map +1 -1
- package/dist/web-chat-history.d.ts +26 -1
- package/dist/web-chat-history.js +47 -8
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-commands.d.ts +39 -3
- package/dist/web-commands.js +22 -5
- package/dist/web-commands.js.map +1 -1
- package/dist/web-login.d.ts +14 -0
- package/dist/web-login.js +4 -2
- package/dist/web-login.js.map +1 -1
- package/dist/web-prefs.d.ts +18 -0
- package/dist/web-prefs.js +36 -4
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-profile.d.ts +32 -0
- package/dist/web-profile.js +132 -0
- package/dist/web-profile.js.map +1 -0
- package/dist/web-session.d.ts +14 -0
- package/dist/web-session.js +10 -0
- package/dist/web-session.js.map +1 -1
- package/dist/web-upload.d.ts +119 -4
- package/dist/web-upload.js +252 -39
- package/dist/web-upload.js.map +1 -1
- package/launcher/install-admission.cjs +61 -6
- package/package.json +3 -3
package/dist/backend/types.d.ts
CHANGED
|
@@ -182,9 +182,22 @@ export interface CliEnv {
|
|
|
182
182
|
* read and lists none (the fallback applies); absent: the help could not be read.
|
|
183
183
|
*/
|
|
184
184
|
effortLevels?: string[];
|
|
185
|
+
/**
|
|
186
|
+
* The binary file the probe ran (antigravity, #1825): what is at `path`, by size and mtime. While that same file is
|
|
187
|
+
* installed, its catalog and levels still describe it past the TTL — the launch and /effort read them by it.
|
|
188
|
+
*/
|
|
189
|
+
binary?: CliBinaryIdentity;
|
|
185
190
|
/** Epoch ms the probe ran (drives the cache TTL). */
|
|
186
191
|
probedAt: number;
|
|
187
192
|
}
|
|
193
|
+
/** A binary file, as `stat` sees it (no CLI runs): its path, size and mtime. */
|
|
194
|
+
export interface CliBinaryIdentity {
|
|
195
|
+
path: string;
|
|
196
|
+
size: number;
|
|
197
|
+
mtimeMs: number;
|
|
198
|
+
}
|
|
199
|
+
/** The identity of the file at `path`, or null when it cannot be stat'ed. */
|
|
200
|
+
export declare function cliBinaryIdentity(path: string): CliBinaryIdentity | null;
|
|
188
201
|
/** Backends whose installed CLI versions are surfaced by `/sysinfo`. */
|
|
189
202
|
export declare const SYSINFO_BACKEND_IDS: readonly ["claude-code", "codex", "kiro-cli", "grok", "antigravity", "muse"];
|
|
190
203
|
export type SysInfoBackendId = typeof SYSINFO_BACKEND_IDS[number];
|
|
@@ -530,6 +543,16 @@ export interface CliBackend {
|
|
|
530
543
|
* session DB was unreadable and the launch fell back, #984). Cleared on read.
|
|
531
544
|
*/
|
|
532
545
|
consumeLaunchWarning?(): string | null;
|
|
546
|
+
/**
|
|
547
|
+
* Board 907c7899: the pane layout a /compact's end can be read from in this launch (kiro-compact-pane.ts), or null
|
|
548
|
+
* when it can't. Only kiro has one; every other backend's compaction is followed through its transcript or not at all.
|
|
549
|
+
*/
|
|
550
|
+
compactPaneUi?(): "legacy" | "tui" | null;
|
|
551
|
+
/**
|
|
552
|
+
* #1811: notes about the last buildCommand that go to daemon.log and the Log tab only, never to a channel (an effort
|
|
553
|
+
* the launch could not pass, and why). Cleared on read.
|
|
554
|
+
*/
|
|
555
|
+
consumeQuietLaunchNotes?(): string[];
|
|
533
556
|
/**
|
|
534
557
|
* #1218 (kiro): the last launch this backend built in full — its engine, how it chose its conversation, its credential
|
|
535
558
|
* profile — or null (none, or the last build threw). For the Log's reason only: it never selects what is read.
|
|
@@ -749,6 +772,7 @@ export interface CliBackend {
|
|
|
749
772
|
currentModel?: string;
|
|
750
773
|
models: ModelOption[];
|
|
751
774
|
effortLevels?: string[];
|
|
775
|
+
binary?: CliBinaryIdentity;
|
|
752
776
|
}>;
|
|
753
777
|
/**
|
|
754
778
|
* Ask the CLI to refresh its OWN model catalog before the next probe reads it.
|
package/dist/backend/types.js
CHANGED
|
@@ -18,6 +18,16 @@ export class UnsupportedCliError extends Error {
|
|
|
18
18
|
}
|
|
19
19
|
/** How long a cached CLI env (`<AGEND_HOME>/cli-env/<backend>.json`) is valid; after that nothing may read it. */
|
|
20
20
|
export const CLI_ENV_TTL_MS = 24 * 60 * 60 * 1000;
|
|
21
|
+
/** The identity of the file at `path`, or null when it cannot be stat'ed. */
|
|
22
|
+
export function cliBinaryIdentity(path) {
|
|
23
|
+
try {
|
|
24
|
+
const st = statSync(path);
|
|
25
|
+
return st.isFile() ? { path, size: st.size, mtimeMs: st.mtimeMs } : null;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
21
31
|
/** Backends whose installed CLI versions are surfaced by `/sysinfo`. */
|
|
22
32
|
export const SYSINFO_BACKEND_IDS = ["claude-code", "codex", "kiro-cli", "grok", "antigravity", "muse"];
|
|
23
33
|
/** Timeout on the `<binary> --version` step of a CLI env probe. */
|
|
@@ -168,7 +178,8 @@ const BACKEND_MODEL_PATTERNS = {
|
|
|
168
178
|
};
|
|
169
179
|
/** Check if a model name is compatible with the given backend. */
|
|
170
180
|
export function isModelCompatible(backendName, model) {
|
|
171
|
-
|
|
181
|
+
// Own keys only: "__proto__" or "toString" names no backend (#1815 review).
|
|
182
|
+
const pattern = Object.prototype.hasOwnProperty.call(BACKEND_MODEL_PATTERNS, backendName) ? BACKEND_MODEL_PATTERNS[backendName] : undefined;
|
|
172
183
|
if (!pattern)
|
|
173
184
|
return true; // unknown backend — pass through
|
|
174
185
|
return pattern.test(model);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/backend/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAE9D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA8C1C;;;;;;GAMG;AACH,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAwGD,kHAAkH;AAClH,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/backend/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* #1806: `/backend` — move an instance to another CLI backend from chat, choosing its model and effort on the way.
|
|
3
|
+
*
|
|
4
|
+
* backend → model → effort → confirm, then ONE config write and ONE relaunch: update_instance_config's backend switch
|
|
5
|
+
* (`applyInstanceConfigPatch`), which starts the new backend fresh (#1217) and keeps its credential-profile login gate.
|
|
6
|
+
* Nothing is written or restarted between the steps — a backend restarted on the old model, then again on the new
|
|
7
|
+
* one, is two chances to fail instead of one.
|
|
8
|
+
*
|
|
9
|
+
* This file is the steps only, and it is pure: for the arguments chosen so far, the next question (with its choices),
|
|
10
|
+
* the confirmation, or a refusal. Every check runs on every call, so the typed form (`/backend codex gpt-5 high`) and
|
|
11
|
+
* each click of a menu are judged the same way, and a refusal comes before anything is written. Discord, Telegram and
|
|
12
|
+
* the web chat only present it (fleet-manager.ts, web-commands.ts).
|
|
13
|
+
*/
|
|
14
|
+
import type { ModelOption } from "./backend/types.js";
|
|
15
|
+
/** The word that picks the inherited value of a model or an effort, in the typed form and in the menus. */
|
|
16
|
+
export declare const BACKEND_DEFAULT = "default";
|
|
17
|
+
export interface BackendCommandDeps {
|
|
18
|
+
/** The backend the instance runs now. */
|
|
19
|
+
currentBackend(instance: string): string;
|
|
20
|
+
/** What the instance runs on now, as a reply shows it: "claude-code · opus". */
|
|
21
|
+
currentDisplay(instance: string): string;
|
|
22
|
+
/** Backends whose CLI is installed on this host, found the way the launch finds it; never removed or test-only ones. */
|
|
23
|
+
installedBackends(): string[];
|
|
24
|
+
/** The models `/model` would offer on that backend; empty when none are known. */
|
|
25
|
+
models(backend: string): Promise<ModelOption[]>;
|
|
26
|
+
/** A name the backend accepts beyond its list (claude-code's aliases and account catalog). */
|
|
27
|
+
modelKnown(backend: string, model: string): boolean;
|
|
28
|
+
/** `/effort`'s levels on that backend for this model (codex's differ per model; null: the CLI's own default model). */
|
|
29
|
+
effortLevels(backend: string, model: string | null): string[];
|
|
30
|
+
/** The model or effort the instance inherits when it has none of its own (fleet defaults). */
|
|
31
|
+
inherited(key: "model" | "effort"): string | undefined;
|
|
32
|
+
/** Whether a model name looks like one of this backend's (advisory, as `/model`'s warning). */
|
|
33
|
+
modelCompatible(backend: string, model: string): boolean;
|
|
34
|
+
/** Whether the instance runs now, and is in a turn. */
|
|
35
|
+
state(instance: string): {
|
|
36
|
+
running: boolean;
|
|
37
|
+
busy: boolean;
|
|
38
|
+
status: string;
|
|
39
|
+
};
|
|
40
|
+
t(key: string, ...args: string[]): string;
|
|
41
|
+
}
|
|
42
|
+
/** What a confirmed `/backend` writes: `null` = the inherited value (no override of the instance's own). */
|
|
43
|
+
export interface BackendPlan {
|
|
44
|
+
backend: string;
|
|
45
|
+
model: string | null;
|
|
46
|
+
effort: string | null;
|
|
47
|
+
}
|
|
48
|
+
/** One choice of a step. `token` is the argument it adds; `label` what the button says. */
|
|
49
|
+
export interface BackendChoice {
|
|
50
|
+
token: string;
|
|
51
|
+
label: string;
|
|
52
|
+
}
|
|
53
|
+
export type BackendStep = {
|
|
54
|
+
kind: "choose";
|
|
55
|
+
step: "backend" | "model" | "effort";
|
|
56
|
+
args: string[];
|
|
57
|
+
text: string;
|
|
58
|
+
choices: BackendChoice[];
|
|
59
|
+
current: string | null;
|
|
60
|
+
} | {
|
|
61
|
+
kind: "confirm";
|
|
62
|
+
args: string[];
|
|
63
|
+
plan: BackendPlan;
|
|
64
|
+
from: string;
|
|
65
|
+
text: string;
|
|
66
|
+
}
|
|
67
|
+
/** `noop`: not a refusal of bad input — the instance already runs that backend, so there is nothing to do. */
|
|
68
|
+
| {
|
|
69
|
+
kind: "refuse";
|
|
70
|
+
text: string;
|
|
71
|
+
noop?: boolean;
|
|
72
|
+
};
|
|
73
|
+
/** How a plan's model and effort read in the reply after it is applied ("—": the backend has no effort setting). */
|
|
74
|
+
export declare function planDisplay(deps: BackendCommandDeps, plan: BackendPlan): {
|
|
75
|
+
model: string;
|
|
76
|
+
effort: string;
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Split a typed argument string the way every surface does: on whitespace, except inside double quotes — a model can
|
|
80
|
+
* have spaces in its name (antigravity's "Gemini 3.5 Flash (High)").
|
|
81
|
+
*/
|
|
82
|
+
export declare function backendArgs(text: string): string[];
|
|
83
|
+
/** The arguments as one string that backendArgs splits back into the same tokens (the web's choice ids). */
|
|
84
|
+
export declare function joinBackendArgs(args: readonly string[]): string;
|
|
85
|
+
/**
|
|
86
|
+
* A model name the backend's launch line can carry. Antigravity's builder shell-quotes the name whole (its catalog
|
|
87
|
+
* has display names); every other builder runs validateModel's rule. Never a control character or a double quote.
|
|
88
|
+
*/
|
|
89
|
+
export declare function modelNameCarried(backend: string, model: string): boolean;
|
|
90
|
+
/** The next step for these arguments: `[]`, `[backend]`, `[backend, model]` or `[backend, model, effort]`. */
|
|
91
|
+
export declare function backendStep(deps: BackendCommandDeps, instance: string, args: readonly string[]): Promise<BackendStep>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/** The word that picks the inherited value of a model or an effort, in the typed form and in the menus. */
|
|
2
|
+
export const BACKEND_DEFAULT = "default";
|
|
3
|
+
/** The most choices one step offers: a Discord select menu's 25, less "default". */
|
|
4
|
+
const MAX_MODEL_CHOICES = 24;
|
|
5
|
+
/** A chosen model or effort as a reply says it; `null` is the inherited one, named. */
|
|
6
|
+
function shown(deps, key, value) {
|
|
7
|
+
if (value !== null)
|
|
8
|
+
return value;
|
|
9
|
+
const inherited = deps.inherited(key);
|
|
10
|
+
return inherited ? deps.t("backend.default_inherited", inherited) : deps.t("backend.default_cli");
|
|
11
|
+
}
|
|
12
|
+
/** How a plan's model and effort read in the reply after it is applied ("—": the backend has no effort setting). */
|
|
13
|
+
export function planDisplay(deps, plan) {
|
|
14
|
+
const levels = deps.effortLevels(plan.backend, plan.model ?? deps.inherited("model") ?? null);
|
|
15
|
+
return { model: shown(deps, "model", plan.model), effort: levels.length ? shown(deps, "effort", plan.effort) : "—" };
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Split a typed argument string the way every surface does: on whitespace, except inside double quotes — a model can
|
|
19
|
+
* have spaces in its name (antigravity's "Gemini 3.5 Flash (High)").
|
|
20
|
+
*/
|
|
21
|
+
export function backendArgs(text) {
|
|
22
|
+
return [...text.matchAll(/"([^"]*)"|(\S+)/g)].map(m => m[1] ?? m[2]).filter(Boolean);
|
|
23
|
+
}
|
|
24
|
+
/** The arguments as one string that backendArgs splits back into the same tokens (the web's choice ids). */
|
|
25
|
+
export function joinBackendArgs(args) {
|
|
26
|
+
return args.map(a => /\s/.test(a) ? `"${a}"` : a).join(" ");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A model name the backend's launch line can carry. Antigravity's builder shell-quotes the name whole (its catalog
|
|
30
|
+
* has display names); every other builder runs validateModel's rule. Never a control character or a double quote.
|
|
31
|
+
*/
|
|
32
|
+
export function modelNameCarried(backend, model) {
|
|
33
|
+
if (!model || /[\x00-\x1f\x7f"]/.test(model) || model.trim() !== model)
|
|
34
|
+
return false;
|
|
35
|
+
return backend === "antigravity" || /^[A-Za-z0-9._:/[\]-]+$/.test(model);
|
|
36
|
+
}
|
|
37
|
+
/** The next step for these arguments: `[]`, `[backend]`, `[backend, model]` or `[backend, model, effort]`. */
|
|
38
|
+
export async function backendStep(deps, instance, args) {
|
|
39
|
+
const { t } = deps;
|
|
40
|
+
if (args.length > 3)
|
|
41
|
+
return { kind: "refuse", text: t("backend.usage") };
|
|
42
|
+
const from = deps.currentBackend(instance);
|
|
43
|
+
const installed = deps.installedBackends();
|
|
44
|
+
if (args.length === 0) {
|
|
45
|
+
return {
|
|
46
|
+
kind: "choose", step: "backend", args: [], current: from,
|
|
47
|
+
text: t("backend.menu", deps.currentDisplay(instance)),
|
|
48
|
+
choices: installed.map(b => ({ token: b, label: b === from ? `✓ ${b}` : b })),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const backend = args[0].toLowerCase();
|
|
52
|
+
if (!installed.includes(backend)) {
|
|
53
|
+
return { kind: "refuse", text: t("backend.not_installed", args[0], installed.join(", ") || "—") };
|
|
54
|
+
}
|
|
55
|
+
// The same backend is not a switch: nothing to restart for. A model or effort on it is /model's and /effort's job.
|
|
56
|
+
if (backend === from)
|
|
57
|
+
return { kind: "refuse", text: t("backend.same", instance, backend), noop: true };
|
|
58
|
+
const models = await deps.models(backend);
|
|
59
|
+
const defaultModel = deps.inherited("model");
|
|
60
|
+
const modelDisplay = (m) => shown(deps, "model", m);
|
|
61
|
+
if (args.length === 1) {
|
|
62
|
+
const listed = models.slice(0, MAX_MODEL_CHOICES).map(o => ({ token: o.id, label: o.description ? `${o.label} — ${o.description}` : o.label }));
|
|
63
|
+
return {
|
|
64
|
+
kind: "choose", step: "model", args: [backend], current: null,
|
|
65
|
+
text: t(models.length ? "backend.model_menu" : "backend.model_menu_empty", backend),
|
|
66
|
+
choices: [{ token: BACKEND_DEFAULT, label: `${t("backend.default")} (${modelDisplay(null)})` }, ...listed],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
const modelArg = args[1];
|
|
70
|
+
let model = null;
|
|
71
|
+
if (modelArg.toLowerCase() !== BACKEND_DEFAULT) {
|
|
72
|
+
// Only a name this backend's launch line can carry (validateModel's rule, or antigravity's quoting), then known.
|
|
73
|
+
const known = modelNameCarried(backend, modelArg)
|
|
74
|
+
&& (models.some(o => o.id === modelArg) || deps.modelKnown(backend, modelArg));
|
|
75
|
+
if (!known) {
|
|
76
|
+
const names = [BACKEND_DEFAULT, ...models.slice(0, MAX_MODEL_CHOICES).map(o => o.id)].join(", ");
|
|
77
|
+
return { kind: "refuse", text: t("backend.unknown_model", modelArg, backend, names) };
|
|
78
|
+
}
|
|
79
|
+
model = modelArg;
|
|
80
|
+
}
|
|
81
|
+
// The levels of the model that will run: the one chosen, else the inherited one, else the CLI's default (#1806 review).
|
|
82
|
+
const levels = deps.effortLevels(backend, model ?? defaultModel ?? null);
|
|
83
|
+
const effortDisplay = (e) => shown(deps, "effort", e);
|
|
84
|
+
if (args.length === 2 && levels.length > 0) {
|
|
85
|
+
return {
|
|
86
|
+
kind: "choose", step: "effort", args: [backend, modelArg], current: null,
|
|
87
|
+
text: t("backend.effort_menu", backend, modelDisplay(model)),
|
|
88
|
+
choices: [{ token: BACKEND_DEFAULT, label: `${t("backend.default")} (${effortDisplay(null)})` }, ...levels.map(l => ({ token: l, label: l }))],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
let effort = null;
|
|
92
|
+
if (args.length === 3) {
|
|
93
|
+
const effortArg = args[2].toLowerCase();
|
|
94
|
+
if (levels.length === 0)
|
|
95
|
+
return { kind: "refuse", text: t("backend.no_effort", backend) };
|
|
96
|
+
if (effortArg !== BACKEND_DEFAULT) {
|
|
97
|
+
if (!levels.includes(effortArg))
|
|
98
|
+
return { kind: "refuse", text: t("backend.unknown_effort", args[2], backend, [BACKEND_DEFAULT, ...levels].join(", ")) };
|
|
99
|
+
effort = effortArg;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const plan = { backend, model, effort };
|
|
103
|
+
const effectiveModel = model ?? defaultModel;
|
|
104
|
+
const lines = [
|
|
105
|
+
t("backend.confirm_head", instance, deps.currentDisplay(instance), backend),
|
|
106
|
+
t("backend.confirm_model", modelDisplay(model)),
|
|
107
|
+
levels.length ? t("backend.confirm_effort", effortDisplay(effort)) : t("backend.confirm_no_effort", backend),
|
|
108
|
+
...(effectiveModel && !deps.modelCompatible(backend, effectiveModel) ? [t("model.pattern_warning", effectiveModel, backend).trim()] : []),
|
|
109
|
+
"",
|
|
110
|
+
];
|
|
111
|
+
const state = deps.state(instance);
|
|
112
|
+
if (state.running) {
|
|
113
|
+
lines.push(t("backend.confirm_restart", instance), t("backend.confirm_fresh", backend));
|
|
114
|
+
lines.push(state.busy ? t("backend.confirm_busy", instance) : t("backend.confirm_turn"));
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
lines.push(t("backend.confirm_not_running", instance, state.status, backend));
|
|
118
|
+
}
|
|
119
|
+
const confirmedArgs = [backend, model ?? BACKEND_DEFAULT, ...(levels.length ? [effort ?? BACKEND_DEFAULT] : [])];
|
|
120
|
+
return { kind: "confirm", args: confirmedArgs, plan, from, text: lines.join("\n") };
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=backend-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend-command.js","sourceRoot":"","sources":["../src/backend-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ import { EventEmitter } from "node:events";
|
|
|
2
2
|
import { Client, ActionRowBuilder, ButtonBuilder } from "discord.js";
|
|
3
3
|
import type { ChannelAdapter, ApprovalHandle, SendOpts, ReplyButtonsOutcome, SentMessage, PermissionPrompt, Choice, AlertData, AdapterHealthSnapshot, TopicPresence, StickerInfo, StickerList, StickerPreview, StickerTarget } from "../types.js";
|
|
4
4
|
import type { AccessManager } from "../access-manager.js";
|
|
5
|
+
import { type PollRender } from "../../reply-polls.js";
|
|
5
6
|
/** Curated ClassicBot backends for Discord's native slash-option dropdown. */
|
|
6
7
|
export declare const DISCORD_START_BACKEND_CHOICES: readonly [{
|
|
7
8
|
readonly name: "Claude Code";
|
|
@@ -53,6 +54,11 @@ export declare function buttonRows(choices: ReadonlyArray<{
|
|
|
53
54
|
id: string;
|
|
54
55
|
label: string;
|
|
55
56
|
}>): ActionRowBuilder<ButtonBuilder>[];
|
|
57
|
+
/**
|
|
58
|
+
* #1823: a poll's components — its options (disabled once closed, each with its count then), and a last row holding
|
|
59
|
+
* one disabled status button ("N answered"; at close the closed line).
|
|
60
|
+
*/
|
|
61
|
+
export declare function discordPollRows(poll: PollRender): ActionRowBuilder<ButtonBuilder>[];
|
|
56
62
|
/**
|
|
57
63
|
* #1235 part 2: the discord.js REST connection survives idle gaps.
|
|
58
64
|
* undici's default keepAliveTimeout is 4 s, so the first deferReply after any
|
|
@@ -200,6 +206,12 @@ export declare class DiscordAdapter extends EventEmitter implements ChannelAdapt
|
|
|
200
206
|
get supportsReplyButtons(): boolean;
|
|
201
207
|
/** #1266: the same buttons, all disabled; the chosen one is marked and names who chose it. */
|
|
202
208
|
settleReplyButtons(chatId: string, messageId: string, threadId: string | undefined, labels: readonly string[], outcome: ReplyButtonsOutcome): Promise<void>;
|
|
209
|
+
/** #1823: polls — the options as buttons, a disabled status button, and a deadline line Discord counts down itself. */
|
|
210
|
+
get supportsPolls(): boolean;
|
|
211
|
+
/** #1823: at most one poll redraw per channel every 2 s: inside Discord's 5 edits per 5 s. */
|
|
212
|
+
get pollEditIntervalMs(): number;
|
|
213
|
+
/** #1823: redraw a poll's buttons; at close, also its deadline line, which becomes "closed". */
|
|
214
|
+
renderPoll(chatId: string, messageId: string, threadId: string | undefined, poll: PollRender): Promise<void>;
|
|
203
215
|
sendFile(chatId: string, filePath: string, opts?: SendOpts): Promise<SentMessage>;
|
|
204
216
|
/** #1651: `_opts.format` changes nothing here — Discord always renders Markdown (as sendText ignores it too). */
|
|
205
217
|
editMessage(chatId: string, messageId: string, text: string, threadId?: string, _opts?: {
|
|
@@ -15,6 +15,7 @@ import { downloadStickerImage } from "../sticker-download.js";
|
|
|
15
15
|
import { MessageQueue } from "../message-queue.js";
|
|
16
16
|
import { splitTextFenceAware, truncatePreview, fenceBlock } from "../markdown-chunk.js";
|
|
17
17
|
import { CROSS_INSTANCE_VISIBILITY_MODES } from "../../cross-instance-notice.js";
|
|
18
|
+
import { POLL_STATUS_CALLBACK } from "../../reply-polls.js";
|
|
18
19
|
const DISCORD_MAX_LENGTH = 2000;
|
|
19
20
|
const GATEWAY_WATCHDOG_INTERVAL_MS = 30_000;
|
|
20
21
|
const GATEWAY_STALE_MIN_MS = 180_000;
|
|
@@ -53,6 +54,26 @@ export function buttonRows(choices) {
|
|
|
53
54
|
}
|
|
54
55
|
return rows;
|
|
55
56
|
}
|
|
57
|
+
/** #1823: the deadline line under a poll's text, and how a closed poll's line is found again. */
|
|
58
|
+
function discordPollLine(deadline) {
|
|
59
|
+
return `\n\n⏳ ${t("poll.closes")} <t:${Math.ceil(deadline / 1000)}:R>`;
|
|
60
|
+
}
|
|
61
|
+
const DISCORD_POLL_LINE = /\n\n⏳ [^\n]*<t:\d+:R>$/;
|
|
62
|
+
/**
|
|
63
|
+
* #1823: a poll's components — its options (disabled once closed, each with its count then), and a last row holding
|
|
64
|
+
* one disabled status button ("N answered"; at close the closed line).
|
|
65
|
+
*/
|
|
66
|
+
export function discordPollRows(poll) {
|
|
67
|
+
const rows = [];
|
|
68
|
+
for (let i = 0; i < poll.options.length; i += BUTTONS_PER_ROW) {
|
|
69
|
+
rows.push(new ActionRowBuilder().addComponents(poll.options.slice(i, i + BUTTONS_PER_ROW).map(o => new ButtonBuilder()
|
|
70
|
+
.setCustomId(o.id).setLabel(o.label.length > 80 ? `${o.label.slice(0, 79)}…` : o.label)
|
|
71
|
+
.setStyle(ButtonStyle.Secondary).setDisabled(poll.closed))));
|
|
72
|
+
}
|
|
73
|
+
rows.push(new ActionRowBuilder().addComponents(new ButtonBuilder()
|
|
74
|
+
.setCustomId(POLL_STATUS_CALLBACK).setLabel(poll.status.slice(0, 80)).setStyle(ButtonStyle.Secondary).setDisabled(true)));
|
|
75
|
+
return rows;
|
|
76
|
+
}
|
|
56
77
|
/**
|
|
57
78
|
* The click's acknowledgement (#1133). The click itself was acknowledged on
|
|
58
79
|
* arrival (deferUpdate, inside Discord's 3 s window); a notice — why nothing
|
|
@@ -1235,6 +1256,16 @@ export class DiscordAdapter extends EventEmitter {
|
|
|
1235
1256
|
{
|
|
1236
1257
|
name: "model", description: slashLock("model") + t("slash.model"),
|
|
1237
1258
|
},
|
|
1259
|
+
{
|
|
1260
|
+
// #1806: no option is required — with none, a menu of the installed CLIs opens (a static choice list
|
|
1261
|
+
// here would offer backends this host cannot run).
|
|
1262
|
+
name: "backend", description: slashLock("backend") + t("slash.backend"),
|
|
1263
|
+
options: [
|
|
1264
|
+
{ name: "backend", description: t("slash.option.backend_name"), type: ApplicationCommandOptionType.String, required: false },
|
|
1265
|
+
{ name: "model", description: t("slash.option.backend_model"), type: ApplicationCommandOptionType.String, required: false },
|
|
1266
|
+
{ name: "effort", description: t("slash.option.backend_effort"), type: ApplicationCommandOptionType.String, required: false },
|
|
1267
|
+
],
|
|
1268
|
+
},
|
|
1238
1269
|
{
|
|
1239
1270
|
name: "effort", description: slashLock("effort") + t("slash.effort"),
|
|
1240
1271
|
options: [{
|
|
@@ -1386,7 +1417,8 @@ export class DiscordAdapter extends EventEmitter {
|
|
|
1386
1417
|
const channelId = opts?.threadId ?? chatId;
|
|
1387
1418
|
const channel = await this._fetchTextChannel(channelId);
|
|
1388
1419
|
const chunkLimit = opts?.chunkLimit ?? DISCORD_MAX_LENGTH;
|
|
1389
|
-
|
|
1420
|
+
// #1823: a poll's deadline as a line Discord counts down by itself, on every client.
|
|
1421
|
+
const chunks = splitTextFenceAware(opts?.replyPoll ? `${text}${discordPollLine(opts.replyPoll.deadline)}` : text, chunkLimit);
|
|
1390
1422
|
if (chunks.length === 0)
|
|
1391
1423
|
throw new Error("Empty text");
|
|
1392
1424
|
// Await every platform POST before reporting success. Previously only the
|
|
@@ -1395,7 +1427,7 @@ export class DiscordAdapter extends EventEmitter {
|
|
|
1395
1427
|
let first;
|
|
1396
1428
|
let last;
|
|
1397
1429
|
// #1266: a reply's buttons go on the last part (built first: too many buttons is an error before anything is sent).
|
|
1398
|
-
const replyRows = opts?.replyButtons?.length ? buttonRows(opts.replyButtons) : null;
|
|
1430
|
+
const replyRows = opts?.replyPoll ? discordPollRows(opts.replyPoll) : opts?.replyButtons?.length ? buttonRows(opts.replyButtons) : null;
|
|
1399
1431
|
for (const [i, chunk] of chunks.entries()) {
|
|
1400
1432
|
const components = replyRows && i === chunks.length - 1 ? { components: replyRows } : {};
|
|
1401
1433
|
const sent = await channel.send(opts?.disablePreview || opts?.allowedMentions || replyRows
|
|
@@ -1428,6 +1460,21 @@ export class DiscordAdapter extends EventEmitter {
|
|
|
1428
1460
|
}
|
|
1429
1461
|
await msg.edit({ components: rows });
|
|
1430
1462
|
}
|
|
1463
|
+
/** #1823: polls — the options as buttons, a disabled status button, and a deadline line Discord counts down itself. */
|
|
1464
|
+
get supportsPolls() { return true; }
|
|
1465
|
+
/** #1823: at most one poll redraw per channel every 2 s: inside Discord's 5 edits per 5 s. */
|
|
1466
|
+
get pollEditIntervalMs() { return 2_000; }
|
|
1467
|
+
/** #1823: redraw a poll's buttons; at close, also its deadline line, which becomes "closed". */
|
|
1468
|
+
async renderPoll(chatId, messageId, threadId, poll) {
|
|
1469
|
+
const channel = await this._fetchTextChannel(threadId ?? chatId);
|
|
1470
|
+
if (!poll.closed) {
|
|
1471
|
+
await channel.messages.edit(messageId, { components: discordPollRows(poll) });
|
|
1472
|
+
return;
|
|
1473
|
+
}
|
|
1474
|
+
const msg = await channel.messages.fetch(messageId);
|
|
1475
|
+
const content = msg.content.replace(DISCORD_POLL_LINE, `\n\n${t("poll.closed_line")}`);
|
|
1476
|
+
await msg.edit({ components: discordPollRows(poll), ...(content !== msg.content ? { content } : {}) });
|
|
1477
|
+
}
|
|
1431
1478
|
async sendFile(chatId, filePath, opts) {
|
|
1432
1479
|
const channelId = opts?.threadId ?? chatId;
|
|
1433
1480
|
const channel = await this._fetchTextChannel(channelId);
|