@songsid/agend 2.1.12 → 2.2.0-alpha.2
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 +4 -2
- package/README.zh-TW.md +4 -2
- package/dist/agent-cli.js +6 -1
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +68 -12
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-token-header.d.ts +13 -0
- package/dist/agent-token-header.js +16 -0
- package/dist/agent-token-header.js.map +1 -0
- package/dist/auth/one-time-code.d.ts +19 -0
- package/dist/auth/one-time-code.js +49 -0
- package/dist/auth/one-time-code.js.map +1 -0
- package/dist/auth-api.d.ts +52 -0
- package/dist/auth-api.js +346 -0
- package/dist/auth-api.js.map +1 -0
- package/dist/backend/antigravity.js +4 -3
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.d.ts +4 -0
- package/dist/backend/claude-code.js +97 -0
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.js +59 -30
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok.js +1 -1
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro-agent.d.ts +66 -0
- package/dist/backend/kiro-agent.js +302 -0
- package/dist/backend/kiro-agent.js.map +1 -0
- package/dist/backend/kiro-identity.d.ts +80 -0
- package/dist/backend/kiro-identity.js +537 -0
- package/dist/backend/kiro-identity.js.map +1 -0
- package/dist/backend/kiro-v2-store-worker.d.ts +1 -0
- package/dist/backend/kiro-v2-store-worker.js +87 -0
- package/dist/backend/kiro-v2-store-worker.js.map +1 -0
- package/dist/backend/kiro-v2-store.d.ts +54 -0
- package/dist/backend/kiro-v2-store.js +131 -0
- package/dist/backend/kiro-v2-store.js.map +1 -0
- package/dist/backend/kiro-v3-identity.d.ts +5 -0
- package/dist/backend/kiro-v3-identity.js +22 -0
- package/dist/backend/kiro-v3-identity.js.map +1 -1
- package/dist/backend/kiro.d.ts +90 -7
- package/dist/backend/kiro.js +500 -124
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/muse.js +1 -1
- package/dist/backend/muse.js.map +1 -1
- package/dist/backend/types.d.ts +51 -3
- package/dist/backend/types.js.map +1 -1
- package/dist/cache-analysis.d.ts +92 -0
- package/dist/cache-analysis.js +147 -0
- package/dist/cache-analysis.js.map +1 -0
- package/dist/cache-ledger.d.ts +108 -0
- package/dist/cache-ledger.js +230 -0
- package/dist/cache-ledger.js.map +1 -0
- package/dist/cache-prices.d.ts +32 -0
- package/dist/cache-prices.js +73 -0
- package/dist/cache-prices.js.map +1 -0
- package/dist/cache-scan.d.ts +39 -0
- package/dist/cache-scan.js +115 -0
- package/dist/cache-scan.js.map +1 -0
- package/dist/cache-service.d.ts +115 -0
- package/dist/cache-service.js +417 -0
- package/dist/cache-service.js.map +1 -0
- package/dist/channel/adapters/discord.d.ts +1 -0
- package/dist/channel/adapters/discord.js +29 -10
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +1 -0
- package/dist/channel/adapters/telegram.js +13 -1
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/types.d.ts +9 -1
- package/dist/classic-channel-manager.d.ts +18 -10
- package/dist/classic-channel-manager.js +45 -18
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli-entry.d.ts +19 -0
- package/dist/cli-entry.js +36 -0
- package/dist/cli-entry.js.map +1 -0
- package/dist/cli.js +471 -146
- package/dist/cli.js.map +1 -1
- package/dist/command-table.d.ts +5 -3
- package/dist/command-table.js +29 -27
- package/dist/command-table.js.map +1 -1
- package/dist/config-validator.js +46 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +12 -0
- package/dist/config.js.map +1 -1
- package/dist/connection-secrets.d.ts +6 -0
- package/dist/connection-secrets.js +4 -0
- package/dist/connection-secrets.js.map +1 -1
- package/dist/daemon.d.ts +95 -4
- package/dist/daemon.js +748 -111
- package/dist/daemon.js.map +1 -1
- package/dist/darwin-memory.d.ts +6 -1
- package/dist/darwin-memory.js +17 -6
- package/dist/darwin-memory.js.map +1 -1
- package/dist/delivery-consumed-watch.d.ts +85 -0
- package/dist/delivery-consumed-watch.js +244 -0
- package/dist/delivery-consumed-watch.js.map +1 -0
- package/dist/delivery-outbox.d.ts +61 -0
- package/dist/delivery-outbox.js +120 -2
- package/dist/delivery-outbox.js.map +1 -1
- package/dist/delivery-reconciliation.d.ts +14 -5
- package/dist/delivery-reconciliation.js +27 -4
- package/dist/delivery-reconciliation.js.map +1 -1
- package/dist/delivery-reconciliation.test.js +35 -1
- package/dist/delivery-reconciliation.test.js.map +1 -1
- package/dist/event-log.d.ts +4 -1
- package/dist/event-log.js +6 -3
- package/dist/event-log.js.map +1 -1
- package/dist/event-loop-watch.d.ts +28 -0
- package/dist/event-loop-watch.js +75 -3
- package/dist/event-loop-watch.js.map +1 -1
- package/dist/fleet-context.d.ts +22 -2
- package/dist/fleet-control-audit.d.ts +5 -0
- package/dist/fleet-control-audit.js +7 -0
- package/dist/fleet-control-audit.js.map +1 -1
- package/dist/fleet-level-config.d.ts +2 -2
- package/dist/fleet-level-config.js +28 -1
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-manager.d.ts +339 -12
- package/dist/fleet-manager.js +2623 -461
- package/dist/fleet-manager.js.map +1 -1
- package/dist/full-restart.js +2 -3
- package/dist/full-restart.js.map +1 -1
- package/dist/general-knowledge/skills/persona-emoji/SKILL.md +3 -1
- package/dist/host-memory.d.ts +4 -0
- package/dist/host-memory.js.map +1 -1
- package/dist/install-lock.d.ts +49 -0
- package/dist/install-lock.js +200 -0
- package/dist/install-lock.js.map +1 -0
- package/dist/instance-config-impact.js +8 -2
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +10 -5
- package/dist/instance-lifecycle.js +162 -53
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +164 -16
- package/dist/locale.js.map +1 -1
- package/dist/login-controller.d.ts +2 -0
- package/dist/login-controller.js +17 -5
- package/dist/login-controller.js.map +1 -1
- package/dist/memory-pressure.d.ts +7 -8
- package/dist/memory-pressure.js +76 -15
- package/dist/memory-pressure.js.map +1 -1
- package/dist/monotonic-budget.d.ts +2 -0
- package/dist/monotonic-budget.js +28 -0
- package/dist/monotonic-budget.js.map +1 -0
- package/dist/needs-you-hub.d.ts +114 -0
- package/dist/needs-you-hub.js +370 -0
- package/dist/needs-you-hub.js.map +1 -0
- package/dist/needs-you-live.d.ts +116 -0
- package/dist/needs-you-live.js +228 -0
- package/dist/needs-you-live.js.map +1 -0
- package/dist/needs-you.d.ts +132 -0
- package/dist/needs-you.js +164 -0
- package/dist/needs-you.js.map +1 -0
- package/dist/node-version-guard.d.ts +30 -0
- package/dist/node-version-guard.js +50 -0
- package/dist/node-version-guard.js.map +1 -0
- package/dist/operator-control-paths.d.ts +4 -0
- package/dist/operator-control-paths.js +24 -0
- package/dist/operator-control-paths.js.map +1 -0
- package/dist/outbound-handlers.d.ts +2 -0
- package/dist/outbound-handlers.js +9 -2
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +5 -5
- package/dist/outbound-schemas.js +1 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/package-preimage.d.ts +26 -0
- package/dist/package-preimage.js +96 -0
- package/dist/package-preimage.js.map +1 -0
- package/dist/profile-control.js +4 -20
- package/dist/profile-control.js.map +1 -1
- package/dist/public-web-gateway.d.ts +18 -0
- package/dist/public-web-gateway.js +141 -0
- package/dist/public-web-gateway.js.map +1 -0
- package/dist/public-web-link.d.ts +53 -0
- package/dist/public-web-link.js +175 -0
- package/dist/public-web-link.js.map +1 -0
- package/dist/quickstart-api.d.ts +8 -1
- package/dist/quickstart-api.js +86 -48
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.d.ts +1 -0
- package/dist/quickstart.js +16 -6
- package/dist/quickstart.js.map +1 -1
- package/dist/restart-guard.d.ts +52 -0
- package/dist/restart-guard.js +109 -0
- package/dist/restart-guard.js.map +1 -0
- package/dist/scheduler/db.d.ts +7 -1
- package/dist/scheduler/db.js +44 -2
- package/dist/scheduler/db.js.map +1 -1
- package/dist/scheduler/index.d.ts +1 -1
- package/dist/scheduler/retry-label.d.ts +11 -0
- package/dist/scheduler/retry-label.js +24 -0
- package/dist/scheduler/retry-label.js.map +1 -0
- package/dist/scheduler/scheduler.d.ts +55 -2
- package/dist/scheduler/scheduler.js +220 -8
- package/dist/scheduler/scheduler.js.map +1 -1
- package/dist/scheduler/types.d.ts +22 -0
- package/dist/scheduler/types.js.map +1 -1
- package/dist/secret-store.d.ts +5 -0
- package/dist/secret-store.js +20 -0
- package/dist/secret-store.js.map +1 -1
- package/dist/service-activation.d.ts +152 -0
- package/dist/service-activation.js +407 -0
- package/dist/service-activation.js.map +1 -0
- package/dist/service-installer.d.ts +63 -1
- package/dist/service-installer.js +141 -16
- package/dist/service-installer.js.map +1 -1
- package/dist/service-plan.d.ts +65 -0
- package/dist/service-plan.js +108 -0
- package/dist/service-plan.js.map +1 -0
- package/dist/service-restart-selection.d.ts +6 -5
- package/dist/service-restart-selection.js +6 -5
- package/dist/service-restart-selection.js.map +1 -1
- package/dist/settings-api.d.ts +10 -2
- package/dist/settings-api.js +216 -72
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-baseline.d.ts +20 -0
- package/dist/settings-baseline.js +104 -0
- package/dist/settings-baseline.js.map +1 -0
- package/dist/settings-change.d.ts +21 -0
- package/dist/settings-change.js +161 -0
- package/dist/settings-change.js.map +1 -0
- package/dist/settings-confirmation.d.ts +105 -0
- package/dist/settings-confirmation.js +232 -0
- package/dist/settings-confirmation.js.map +1 -0
- package/dist/settings-control.d.ts +41 -0
- package/dist/settings-control.js +294 -0
- package/dist/settings-control.js.map +1 -0
- package/dist/settings-effect.d.ts +24 -0
- package/dist/settings-effect.js +169 -0
- package/dist/settings-effect.js.map +1 -0
- package/dist/settings-http-confirmation.d.ts +29 -0
- package/dist/settings-http-confirmation.js +123 -0
- package/dist/settings-http-confirmation.js.map +1 -0
- package/dist/settings-instance-patch.d.ts +4 -0
- package/dist/settings-instance-patch.js +26 -0
- package/dist/settings-instance-patch.js.map +1 -0
- package/dist/settings-request-capability.d.ts +16 -0
- package/dist/settings-request-capability.js +32 -0
- package/dist/settings-request-capability.js.map +1 -0
- package/dist/settings-transaction.d.ts +65 -0
- package/dist/settings-transaction.js +223 -0
- package/dist/settings-transaction.js.map +1 -0
- package/dist/setup-auth.d.ts +10 -18
- package/dist/setup-auth.js +14 -38
- package/dist/setup-auth.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +75 -18
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-guide.d.ts +13 -0
- package/dist/setup-guide.js +25 -0
- package/dist/setup-guide.js.map +1 -0
- package/dist/setup-host.d.ts +16 -0
- package/dist/setup-host.js +199 -35
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +5 -1
- package/dist/setup-wizard.js.map +1 -1
- package/dist/slash-authz.d.ts +17 -3
- package/dist/slash-authz.js +5 -0
- package/dist/slash-authz.js.map +1 -1
- package/dist/spawn-gate.js +3 -3
- package/dist/spawn-gate.js.map +1 -1
- package/dist/sqlite-open-errors.d.ts +12 -0
- package/dist/sqlite-open-errors.js +13 -0
- package/dist/sqlite-open-errors.js.map +1 -0
- package/dist/statusline-watcher.d.ts +5 -0
- package/dist/statusline-watcher.js +2 -0
- package/dist/statusline-watcher.js.map +1 -1
- package/dist/steer-capability.d.ts +6 -0
- package/dist/steer-capability.js +8 -0
- package/dist/steer-capability.js.map +1 -1
- package/dist/sync-work-attribution.d.ts +14 -0
- package/dist/sync-work-attribution.js +43 -8
- package/dist/sync-work-attribution.js.map +1 -1
- package/dist/tips.js +10 -5
- package/dist/tips.js.map +1 -1
- package/dist/tmux-control.d.ts +57 -5
- package/dist/tmux-control.js +379 -61
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-manager.d.ts +20 -6
- package/dist/tmux-manager.js +90 -47
- package/dist/tmux-manager.js.map +1 -1
- package/dist/tmux-read.d.ts +59 -0
- package/dist/tmux-read.js +213 -0
- package/dist/tmux-read.js.map +1 -0
- package/dist/topic-commands.d.ts +21 -10
- package/dist/topic-commands.js +205 -63
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-delta-reader.js +2 -1
- package/dist/transcript-delta-reader.js.map +1 -1
- package/dist/tunnel/cloudflared-install.d.ts +2 -0
- package/dist/tunnel/cloudflared-install.js +1 -1
- package/dist/tunnel/cloudflared-install.js.map +1 -1
- package/dist/tunnel/purpose-lane.d.ts +14 -0
- package/dist/tunnel/purpose-lane.js +43 -0
- package/dist/tunnel/purpose-lane.js.map +1 -0
- package/dist/turn-reply-guard.d.ts +2 -0
- package/dist/turn-reply-guard.js +10 -1
- package/dist/turn-reply-guard.js.map +1 -1
- package/dist/types.d.ts +33 -0
- package/dist/ui/app.html +18 -0
- package/dist/ui/chat-commands.js +43 -0
- package/dist/ui/chat-render.js +478 -0
- package/dist/ui/chat-store.js +318 -0
- package/dist/ui/chat-strings.js +89 -0
- package/dist/ui/chat-thread.js +246 -0
- package/dist/ui/chat-tour.js +116 -0
- package/dist/ui/fleet-cache.js +168 -0
- package/dist/ui/fleet-org.js +142 -0
- package/dist/ui/panel-chat.js +504 -0
- package/dist/ui/panel-fleet.js +427 -0
- package/dist/ui/panel-needs.js +202 -0
- package/dist/ui/panel-settings.js +754 -0
- package/dist/ui/preview-panel.js +202 -0
- package/dist/ui/preview.js +270 -0
- package/dist/ui/settings-apply.js +239 -0
- package/dist/ui/settings-confirm.js +186 -0
- package/dist/ui/settings-dialogs.js +546 -0
- package/dist/ui/settings-model.js +277 -0
- package/dist/ui/settings-strings.js +654 -0
- package/dist/ui/settings-wizard.js +140 -0
- package/dist/ui/shared/agend-auth.js +93 -0
- package/dist/ui/shared/app-ctx.js +80 -0
- package/dist/ui/shared/app-html.js +9 -0
- package/dist/ui/shared/app-i18n.js +95 -0
- package/dist/ui/shared/app-nav.js +73 -0
- package/dist/ui/shared/app-needs.js +114 -0
- package/dist/ui/shared/app-route.js +73 -0
- package/dist/ui/shared/app-session.js +66 -0
- package/dist/ui/shared/app-shell.js +346 -0
- package/dist/ui/shared/app-store.js +51 -0
- package/dist/ui/shared/app-stream.js +201 -0
- package/dist/ui/shared/app.css +820 -0
- package/dist/ui/shared/app.js +88 -0
- package/dist/ui/shared/fonts/OFL.txt +92 -0
- package/dist/ui/shared/fonts/README.md +21 -0
- package/dist/ui/shared/fonts/inter.woff2 +0 -0
- package/dist/ui/shared/htm.module.js +1 -0
- package/dist/ui/shared/panel-view.js +655 -0
- package/dist/ui/shared/preact-hooks.module.js +2 -0
- package/dist/ui/shared/preact.module.js +2 -0
- package/dist/ui/shared/signin.js +142 -0
- package/dist/ui/shared/theme.js +29 -0
- package/dist/ui/shared/tokens.css +153 -0
- package/dist/ui/shared/ui-confirm.js +43 -0
- package/dist/ui/shared/ui-dialog.js +45 -0
- package/dist/ui/shared/ui-icons.js +63 -0
- package/dist/ui/shared/ui-menu.js +39 -0
- package/dist/ui/shared/ui-states.js +20 -0
- package/dist/ui/shared/ui-toast.js +18 -0
- package/dist/ui/shared/vendor/htm.LICENSE +202 -0
- package/dist/ui/shared/vendor/preact.LICENSE +21 -0
- package/dist/ui/shared/vendor/vendor.json +39 -0
- package/dist/ui/shared/view-strings.js +309 -0
- package/dist/ui/signin.html +52 -0
- package/dist/update-check.d.ts +6 -2
- package/dist/update-check.js +12 -3
- package/dist/update-check.js.map +1 -1
- package/dist/update-dispatch.d.ts +28 -0
- package/dist/update-dispatch.js +73 -0
- package/dist/update-dispatch.js.map +1 -0
- package/dist/update-install.d.ts +129 -0
- package/dist/update-install.js +262 -0
- package/dist/update-install.js.map +1 -0
- package/dist/upgrade-notices.d.ts +17 -0
- package/dist/upgrade-notices.js +93 -0
- package/dist/upgrade-notices.js.map +1 -0
- package/dist/usage/statusline-usage.d.ts +2 -0
- package/dist/usage/statusline-usage.js +14 -10
- package/dist/usage/statusline-usage.js.map +1 -1
- package/dist/view-api.d.ts +6 -1
- package/dist/view-api.js +62 -51
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +85 -14
- package/dist/web-api.js +557 -77
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.d.ts +71 -27
- package/dist/web-auth.js +169 -69
- package/dist/web-auth.js.map +1 -1
- package/dist/web-body.d.ts +3 -0
- package/dist/web-body.js +55 -0
- package/dist/web-body.js.map +1 -0
- package/dist/web-channel-echo.d.ts +9 -0
- package/dist/web-channel-echo.js +55 -0
- package/dist/web-channel-echo.js.map +1 -0
- package/dist/web-chat-history.d.ts +125 -0
- package/dist/web-chat-history.js +184 -0
- package/dist/web-chat-history.js.map +1 -0
- package/dist/web-commands.d.ts +77 -0
- package/dist/web-commands.js +81 -0
- package/dist/web-commands.js.map +1 -0
- package/dist/web-continuation.d.ts +7 -0
- package/dist/web-continuation.js +22 -0
- package/dist/web-continuation.js.map +1 -0
- package/dist/web-host-guard.d.ts +34 -0
- package/dist/web-host-guard.js +57 -1
- package/dist/web-host-guard.js.map +1 -1
- package/dist/web-login.d.ts +72 -0
- package/dist/web-login.js +132 -0
- package/dist/web-login.js.map +1 -0
- package/dist/web-org.d.ts +55 -0
- package/dist/web-org.js +67 -0
- package/dist/web-org.js.map +1 -0
- package/dist/web-preview.d.ts +77 -0
- package/dist/web-preview.js +240 -0
- package/dist/web-preview.js.map +1 -0
- package/dist/web-request-context.d.ts +10 -0
- package/dist/web-request-context.js +13 -0
- package/dist/web-request-context.js.map +1 -0
- package/dist/web-session.d.ts +167 -0
- package/dist/web-session.js +389 -0
- package/dist/web-session.js.map +1 -0
- package/dist/web-shell-routes.d.ts +59 -0
- package/dist/web-shell-routes.js +96 -0
- package/dist/web-shell-routes.js.map +1 -0
- package/dist/web-upload.d.ts +183 -0
- package/dist/web-upload.js +468 -0
- package/dist/web-upload.js.map +1 -0
- package/dist/website-tips-renderer.d.ts +2 -2
- package/dist/website-tips-renderer.js +3 -3
- package/dist/website-tips-renderer.js.map +1 -1
- package/launcher/agend +110 -0
- package/launcher/agend-agent +110 -0
- package/launcher/agend-agent.cjs +4 -0
- package/launcher/agend.cjs +4 -0
- package/launcher/install-admission.cjs +105 -0
- package/launcher/launch.cjs +64 -0
- package/launcher/postinstall.cjs +114 -0
- package/launcher/run-in-process.cjs +13 -0
- package/launcher/runtime-platform.cjs +86 -0
- package/launcher/runtime-select.cjs +217 -0
- package/package.json +18 -7
- package/scripts/preinstall-guard.cjs +55 -0
- package/templates/launchd.plist.ejs +2 -2
- package/templates/systemd.service.ejs +1 -1
- package/dist/ui/dashboard.html +0 -774
- package/dist/ui/settings.html +0 -2165
- package/dist/ui/view.html +0 -1139
package/dist/topic-commands.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { measureSyncWork } from "./sync-work-attribution.js";
|
|
2
|
+
import { LOOPBACK_HOST_NAMES } from "./web-host-guard.js";
|
|
3
|
+
import { WEB_REMOTE_DOCS_URL } from "./upgrade-notices.js";
|
|
2
4
|
import { readFileSync, existsSync } from "node:fs";
|
|
3
5
|
import { exec, execFileSync } from "node:child_process";
|
|
4
6
|
import { promisify } from "node:util";
|
|
@@ -11,14 +13,15 @@ import { formatCents } from "./cost-guard.js";
|
|
|
11
13
|
import { truncateDisplay, MODEL_DISPLAY_WIDTH_MAX } from "./ls-rows.js";
|
|
12
14
|
import { getTmuxSocketName, getTmuxSessionName } from "./paths.js";
|
|
13
15
|
import { t, getLocale } from "./locale.js";
|
|
14
|
-
import { telegramMenu } from "./command-table.js";
|
|
16
|
+
import { commandSpec, decideCommand, telegramMenu } from "./command-table.js";
|
|
15
17
|
import { runVisibilityCommand } from "./cross-instance-notice.js";
|
|
16
18
|
import { clampContextPercent, parseContextPercent, parseTokenContextRatio, } from "./context-percent.js";
|
|
17
19
|
import { isGeneralInstance } from "./general-instance.js";
|
|
18
|
-
import {
|
|
20
|
+
import { instanceSupportsSteer } from "./steer-capability.js";
|
|
19
21
|
import { SYSINFO_BACKEND_IDS } from "./backend/types.js";
|
|
20
22
|
import { recordInternalRequest, withOrigin } from "./fleet-control-audit.js";
|
|
21
|
-
import {
|
|
23
|
+
import { resolveInstalledAgend, updateCommand } from "./update-dispatch.js";
|
|
24
|
+
import { selfCommand } from "./cli-entry.js";
|
|
22
25
|
export { parseContextPercent, parseTokenContextRatio } from "./context-percent.js";
|
|
23
26
|
/** Longest one setMyCommands call may take. */
|
|
24
27
|
const TELEGRAM_COMMANDS_TIMEOUT_MS = 10_000;
|
|
@@ -455,12 +458,89 @@ export function resolveInstanceContext(dataDir, instanceName, backend, opts) {
|
|
|
455
458
|
refreshPaneContext(instanceName, backend);
|
|
456
459
|
return hit ? { context: hit.context, tokenRatio: hit.tokenRatio } : { context: null, tokenRatio: null };
|
|
457
460
|
}
|
|
461
|
+
const PROFILE_RE = /^\/profile(?:@\w+)?(?:\s+([\s\S]*))?$/;
|
|
462
|
+
const RESTART_RE = /^\/restart(?:@[A-Za-z0-9_]*)?(?:\s+(.*))?$/i;
|
|
463
|
+
const LEGACY_INSTALL_RE = /^\/install[-_]cli(?:@\S+)?(?:\s+([\s\S]*))?$/;
|
|
464
|
+
const VISIBILITY_RE = /^\/visibility(?:@\S+)?(?:\s+([\s\S]*))?$/i;
|
|
465
|
+
/** `/name` or `/name@bot`. */
|
|
466
|
+
const bare = (name) => (text) => text === `/${name}` || text.startsWith(`/${name}@`);
|
|
467
|
+
/** `/name`, `/name@bot`, or `/name <args>`. */
|
|
468
|
+
const withArgs = (name) => (text) => bare(name)(text) || text.startsWith(`/${name} `);
|
|
469
|
+
/**
|
|
470
|
+
* The typed forms each dispatcher runs, in its order. The one recognizer for both the command-table gate and the
|
|
471
|
+
* dispatch (#1399 review): a form no handler runs (`/STATUS`, `/status report`, `/pause one two`) is text for the
|
|
472
|
+
* agent, and the table never answers it either.
|
|
473
|
+
*/
|
|
474
|
+
const GENERAL_FORMS = [
|
|
475
|
+
["profile", (text, source) => source === "telegram" && PROFILE_RE.test(text)],
|
|
476
|
+
["status", bare("status")],
|
|
477
|
+
["restart", text => RESTART_RE.test(text)],
|
|
478
|
+
["sysinfo", text => bare("sysinfo")(text) || text === "/sys-info" || text === "/sys_info"],
|
|
479
|
+
["doctor", bare("doctor")],
|
|
480
|
+
["usage", bare("usage")],
|
|
481
|
+
["tips", withArgs("tips")],
|
|
482
|
+
["login", withArgs("login")],
|
|
483
|
+
["install-cli", text => LEGACY_INSTALL_RE.test(text)],
|
|
484
|
+
["update", bare("update")],
|
|
485
|
+
["dashboard", withArgs("dashboard")],
|
|
486
|
+
["visibility", text => VISIBILITY_RE.test(text)],
|
|
487
|
+
];
|
|
488
|
+
const INSTANCE_FORMS = [
|
|
489
|
+
["tips", withArgs("tips")],
|
|
490
|
+
["pause", text => parsePauseWakeCommand(text)?.action === "pause"],
|
|
491
|
+
["wake", text => parsePauseWakeCommand(text)?.action === "wake"],
|
|
492
|
+
["collab", bare("collab")],
|
|
493
|
+
["effort", withArgs("effort")],
|
|
494
|
+
["model", withArgs("model")],
|
|
495
|
+
["compact", text => parseCompactCommand(text) !== null],
|
|
496
|
+
["steer", withArgs("steer")],
|
|
497
|
+
["btw", withArgs("btw")],
|
|
498
|
+
["clear", bare("clear")],
|
|
499
|
+
["cancel", bare("cancel")],
|
|
500
|
+
["save", withArgs("save")],
|
|
501
|
+
["raw", text => text === "/raw" || text.startsWith("/raw ")],
|
|
502
|
+
["ctx", bare("ctx")],
|
|
503
|
+
];
|
|
504
|
+
const typedCommand = (forms, text, source) => forms.find(([, matches]) => matches(text, source))?.[0];
|
|
505
|
+
/** A typed name that is another spelling of a command-table entry. */
|
|
506
|
+
const TELEGRAM_COMMAND_ALIASES = { "install-cli": "login" };
|
|
458
507
|
export class TopicCommands {
|
|
459
508
|
ctx;
|
|
460
509
|
constructor(ctx) {
|
|
461
510
|
this.ctx = ctx;
|
|
462
511
|
}
|
|
463
512
|
/** Get the adapter that should reply to a given inbound message */
|
|
513
|
+
/**
|
|
514
|
+
* #754: who may run a typed Telegram command is decided by the command table — the same rule a Discord slash
|
|
515
|
+
* command goes through (`decideCommand`), here with its Telegram column — before any handler runs. `msg.adapterId`
|
|
516
|
+
* is the topic's owning adapter (ownedCopy), so the admin it asks about is that bot's. A command the table does not
|
|
517
|
+
* know (`/raw`) or does not handle here (a passthrough cell) is left to the handlers below. `command` is what the
|
|
518
|
+
* dispatcher recognized (GENERAL_FORMS / INSTANCE_FORMS), so the table judges exactly what would run.
|
|
519
|
+
*
|
|
520
|
+
* Synchronous on purpose (#1399 review): the decision, the handler's own checks and the command's effect run in one
|
|
521
|
+
* stretch, so the instance cannot be rebound to another bot between the check and the act. The refusal, if any.
|
|
522
|
+
*/
|
|
523
|
+
tableRefusal(msg, command, scope) {
|
|
524
|
+
const spec = command ? commandSpec(TELEGRAM_COMMAND_ALIASES[command] ?? command) : undefined;
|
|
525
|
+
if (!spec)
|
|
526
|
+
return null;
|
|
527
|
+
const fleetAdmin = () => this.ctx.isFleetAdmin(msg.userId, msg.adapterId) ? "ok"
|
|
528
|
+
: this.ctx.hasFleetAdmins && !this.ctx.hasFleetAdmins(msg.adapterId) ? "disabled" : "denied";
|
|
529
|
+
const decision = decideCommand(spec, scope, {
|
|
530
|
+
fleetAdmin,
|
|
531
|
+
// In a fleet topic the channel's own admin IS the owning bot's fleet admin.
|
|
532
|
+
channelAdmin: () => fleetAdmin() === "ok",
|
|
533
|
+
classicAdmin: () => false,
|
|
534
|
+
}, "telegram");
|
|
535
|
+
if (decision.allow || "passthrough" in decision)
|
|
536
|
+
return null;
|
|
537
|
+
return decision.reply;
|
|
538
|
+
}
|
|
539
|
+
async sendRefusal(msg, [key, ...args]) {
|
|
540
|
+
const adapter = this.getReplyAdapter(msg);
|
|
541
|
+
if (adapter)
|
|
542
|
+
await adapter.sendText(msg.chatId, t(key, ...args), { threadId: msg.threadId }).catch(() => { });
|
|
543
|
+
}
|
|
464
544
|
getReplyAdapter(msg) {
|
|
465
545
|
if (msg.adapterId && this.ctx.adapters) {
|
|
466
546
|
return this.ctx.adapters.get(msg.adapterId) ?? this.ctx.adapter;
|
|
@@ -495,47 +575,50 @@ export class TopicCommands {
|
|
|
495
575
|
const text = msg.text?.trim();
|
|
496
576
|
if (!text)
|
|
497
577
|
return false;
|
|
498
|
-
const
|
|
499
|
-
|
|
500
|
-
|
|
578
|
+
const command = typedCommand(GENERAL_FORMS, text, msg.source);
|
|
579
|
+
const refusal = this.tableRefusal(msg, command, "general");
|
|
580
|
+
if (refusal) {
|
|
581
|
+
await this.sendRefusal(msg, refusal);
|
|
501
582
|
return true;
|
|
502
583
|
}
|
|
503
|
-
if (
|
|
584
|
+
if (command === "profile") {
|
|
585
|
+
await this.ctx.runProfileCommand?.(msg, text.match(PROFILE_RE)[1]?.trim());
|
|
586
|
+
return true;
|
|
587
|
+
}
|
|
588
|
+
if (command === "status") {
|
|
504
589
|
await this.handleStatusCommand(msg);
|
|
505
590
|
return true;
|
|
506
591
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
const mode = restart[1]?.trim().toLowerCase();
|
|
592
|
+
if (command === "restart") {
|
|
593
|
+
const mode = text.match(RESTART_RE)[1]?.trim().toLowerCase();
|
|
510
594
|
await this.handleRestartCommand(msg, mode);
|
|
511
595
|
return true;
|
|
512
596
|
}
|
|
513
|
-
if (
|
|
514
|
-
|| text === "/sys-info" || text === "/sys_info") {
|
|
597
|
+
if (command === "sysinfo") {
|
|
515
598
|
await this.handleSysInfoCommand(msg);
|
|
516
599
|
return true;
|
|
517
600
|
}
|
|
518
|
-
if (
|
|
601
|
+
if (command === "doctor") {
|
|
519
602
|
await this.handleDoctorCommand(msg);
|
|
520
603
|
return true;
|
|
521
604
|
}
|
|
522
|
-
if (
|
|
605
|
+
if (command === "usage") {
|
|
523
606
|
await this.handleUsageCommand(msg);
|
|
524
607
|
return true;
|
|
525
608
|
}
|
|
526
|
-
if (
|
|
609
|
+
if (command === "tips") {
|
|
527
610
|
await this.handleTipsCommand(msg);
|
|
528
611
|
return true;
|
|
529
612
|
}
|
|
530
|
-
if (
|
|
613
|
+
if (command === "login") {
|
|
531
614
|
await this.handleLoginCommand(msg);
|
|
532
615
|
return true;
|
|
533
616
|
}
|
|
534
617
|
// `/install-cli` became part of `/login` (#1131). Typed, it still works for
|
|
535
618
|
// one release (2.1.10) — with a line saying where it went — and is in no
|
|
536
619
|
// command menu. Both spellings: Telegram command names cannot contain "-".
|
|
537
|
-
|
|
538
|
-
|
|
620
|
+
if (command === "install-cli") {
|
|
621
|
+
const legacyInstall = text.match(LEGACY_INSTALL_RE);
|
|
539
622
|
const adapter = this.getReplyAdapter(msg);
|
|
540
623
|
if (adapter)
|
|
541
624
|
await adapter.sendText(msg.chatId, t("login.install_cli_moved"), { threadId: msg.threadId }).catch(() => { });
|
|
@@ -544,50 +627,48 @@ export class TopicCommands {
|
|
|
544
627
|
await this.handleLoginCommand({ ...msg, text: mapped });
|
|
545
628
|
return true;
|
|
546
629
|
}
|
|
547
|
-
if (
|
|
630
|
+
if (command === "update") {
|
|
548
631
|
await this.handleUpdateCommand(msg);
|
|
549
632
|
return true;
|
|
550
633
|
}
|
|
551
|
-
if (
|
|
634
|
+
if (command === "dashboard") {
|
|
552
635
|
await this.handleDashboardCommand(msg);
|
|
553
636
|
return true;
|
|
554
637
|
}
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
await this.handleVisibilityCommand(msg, visibility[1] ?? "");
|
|
638
|
+
if (command === "visibility") {
|
|
639
|
+
await this.handleVisibilityCommand(msg, text.match(VISIBILITY_RE)[1] ?? "");
|
|
558
640
|
return true;
|
|
559
641
|
}
|
|
560
642
|
return false;
|
|
561
643
|
}
|
|
562
644
|
/**
|
|
563
|
-
*
|
|
564
|
-
*
|
|
565
|
-
* Telegram HTML spoiler (`<tg-spoiler>`) so the token isn't shown in the clear
|
|
566
|
-
* in a shared topic (the caller must send with format: "html"). /view is
|
|
567
|
-
* public, so it's never spoilered. DC uses the plain form (ephemeral reply).
|
|
645
|
+
* Pure, secret-free dashboard/menu copy. Issuance belongs to the private
|
|
646
|
+
* delivery action; rendering or previewing this text cannot retire a code.
|
|
568
647
|
*/
|
|
569
|
-
getDashboardText(
|
|
648
|
+
getDashboardText(_htmlSpoiler = false, showRemoteHint = true) {
|
|
570
649
|
const port = this.ctx.fleetConfig?.health_port ?? 19280;
|
|
571
650
|
const host = this.ctx.fleetConfig?.hostname || "localhost";
|
|
572
651
|
const access = this.ctx.getDashboardAccess?.();
|
|
573
652
|
if (!access?.ready || !access.token)
|
|
574
653
|
return t("dashboard.starting");
|
|
575
|
-
const token = access.token;
|
|
576
654
|
const base = `http://${host}:${port}`;
|
|
577
|
-
const hide = (u) => htmlSpoiler ? `<tg-spoiler>${u}</tg-spoiler>` : u;
|
|
578
655
|
return [
|
|
579
656
|
t("dashboard.title"),
|
|
580
657
|
"",
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
`•
|
|
584
|
-
`•
|
|
658
|
+
t("dashboard.signin", base),
|
|
659
|
+
"",
|
|
660
|
+
`• View: ${base}/view`,
|
|
661
|
+
`• Dashboard: ${base}/ui`,
|
|
662
|
+
`• Settings: ${base}/settings`,
|
|
663
|
+
"",
|
|
664
|
+
t("dashboard.code_help"),
|
|
665
|
+
// #1366: a loopback address does not open on a phone — say where the way in is documented.
|
|
666
|
+
...(showRemoteHint && (LOOPBACK_HOST_NAMES.includes(host.toLowerCase()) || host === "::1") ? ["", t("dashboard.remote_hint", WEB_REMOTE_DOCS_URL)] : []),
|
|
585
667
|
].join("\n");
|
|
586
668
|
}
|
|
587
669
|
/**
|
|
588
|
-
* /dashboard (TG): admin-only
|
|
589
|
-
*
|
|
590
|
-
* the clear (the adapter supports plain/HTML, not MarkdownV2's `||…||`).
|
|
670
|
+
* /dashboard (TG): admin-only menu in General; codes are sent privately.
|
|
671
|
+
* `/dashboard revoke` also closes the public link and signs browsers out.
|
|
591
672
|
*/
|
|
592
673
|
async handleDashboardCommand(msg) {
|
|
593
674
|
const adapter = this.getReplyAdapter(msg);
|
|
@@ -604,7 +685,17 @@ export class TopicCommands {
|
|
|
604
685
|
await adapter.sendText(chatId, t("not_authorized"), { threadId });
|
|
605
686
|
return;
|
|
606
687
|
}
|
|
607
|
-
|
|
688
|
+
const arg = (msg.text ?? "").trim().replace(/^\/dashboard(?:@\S+)?/i, "").trim().toLowerCase();
|
|
689
|
+
if (arg === "revoke") {
|
|
690
|
+
const result = this.ctx.revokeWebSessions?.() ?? { count: 0, durable: true };
|
|
691
|
+
// Not durable: they are signed out now, but a restart may bring them back — say so, never "done".
|
|
692
|
+
await adapter.sendText(chatId, result.durable ? t("dashboard.revoked", result.count) : t("dashboard.revoked_not_durable", result.count), { threadId });
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
if (msg.source === "telegram")
|
|
696
|
+
await this.ctx.dashboardMenu?.(msg);
|
|
697
|
+
else
|
|
698
|
+
await adapter.sendText(chatId, this.getDashboardText(), { threadId });
|
|
608
699
|
}
|
|
609
700
|
/** Handle /ctx or /compact in any instance topic — returns true if handled */
|
|
610
701
|
async handleInstanceCommand(msg, instanceName) {
|
|
@@ -615,15 +706,25 @@ export class TopicCommands {
|
|
|
615
706
|
const text = msg.text?.trim();
|
|
616
707
|
if (!text)
|
|
617
708
|
return false;
|
|
709
|
+
const inGeneral = !!this.ctx.fleetConfig?.instances[instanceName]?.general_topic;
|
|
710
|
+
// A General command typed in an instance topic is recognized too, in its General forms only: the table points it
|
|
711
|
+
// to General (#1148) instead of handing it to the agent. No branch below runs it.
|
|
712
|
+
const command = typedCommand(INSTANCE_FORMS, text, msg.source)
|
|
713
|
+
?? (inGeneral ? undefined : typedCommand(GENERAL_FORMS, text, msg.source));
|
|
714
|
+
const refusal = this.tableRefusal(msg, command, inGeneral ? "general" : "fleet");
|
|
715
|
+
if (refusal) {
|
|
716
|
+
await this.sendRefusal(msg, refusal);
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
618
719
|
// Tips are informational and should appear where requested, including a
|
|
619
720
|
// worker topic. This also keeps Telegram text commands aligned with
|
|
620
721
|
// Discord's channel-local slash-command behavior.
|
|
621
|
-
if (
|
|
722
|
+
if (command === "tips") {
|
|
622
723
|
await this.handleTipsCommand(msg);
|
|
623
724
|
return true;
|
|
624
725
|
}
|
|
625
|
-
|
|
626
|
-
|
|
726
|
+
if (command === "pause" || command === "wake") {
|
|
727
|
+
const pauseWake = parsePauseWakeCommand(text);
|
|
627
728
|
const adapter = this.getReplyAdapter(msg);
|
|
628
729
|
if (!adapter)
|
|
629
730
|
return false;
|
|
@@ -631,7 +732,7 @@ export class TopicCommands {
|
|
|
631
732
|
await adapter.sendText(msg.chatId, t("permission.denied"), { threadId: msg.threadId });
|
|
632
733
|
return true;
|
|
633
734
|
}
|
|
634
|
-
const isGeneral =
|
|
735
|
+
const isGeneral = inGeneral;
|
|
635
736
|
if (isGeneral && !pauseWake.instance) {
|
|
636
737
|
await adapter.sendText(msg.chatId, t(`${pauseWake.action}.usage`), { threadId: msg.threadId });
|
|
637
738
|
return true;
|
|
@@ -641,6 +742,11 @@ export class TopicCommands {
|
|
|
641
742
|
await adapter.sendText(msg.chatId, t("instance.not_found", target), { threadId: msg.threadId });
|
|
642
743
|
return true;
|
|
643
744
|
}
|
|
745
|
+
// #754 audit: a General speaks for its own bot's instances only — an admin of this bot is not one of another's.
|
|
746
|
+
if (isGeneral && this.ctx.getInstanceAdapterId && this.ctx.getInstanceAdapterId(target) !== msg.adapterId) {
|
|
747
|
+
await adapter.sendText(msg.chatId, t("instance.other_bot", target), { threadId: msg.threadId });
|
|
748
|
+
return true;
|
|
749
|
+
}
|
|
644
750
|
if (pauseWake.action === "pause" && isGeneralInstance(this.ctx.fleetConfig, target)) {
|
|
645
751
|
await adapter.sendText(msg.chatId, t("general.pause_forbidden"), { threadId: msg.threadId });
|
|
646
752
|
return true;
|
|
@@ -648,17 +754,22 @@ export class TopicCommands {
|
|
|
648
754
|
await adapter.sendText(msg.chatId, await this.runPauseWake(target, pauseWake.action), { threadId: msg.threadId });
|
|
649
755
|
return true;
|
|
650
756
|
}
|
|
651
|
-
if (
|
|
757
|
+
if (command === "collab") {
|
|
652
758
|
const adapter = this.getReplyAdapter(msg);
|
|
653
759
|
if (!adapter)
|
|
654
760
|
return false;
|
|
761
|
+
// Channel-admin, as the Discord slash command (#754 audit): it changes how the instance is reached.
|
|
762
|
+
if (!this.ctx.isFleetAdmin(msg.userId, msg.adapterId)) {
|
|
763
|
+
await adapter.sendText(msg.chatId, t("permission.denied"), { threadId: msg.threadId });
|
|
764
|
+
return true;
|
|
765
|
+
}
|
|
655
766
|
const isCollab = this.ctx.toggleFleetCollab(instanceName);
|
|
656
767
|
await adapter.sendText(msg.chatId, isCollab
|
|
657
768
|
? t("collab.on")
|
|
658
769
|
: t("collab.off"), { threadId: msg.threadId });
|
|
659
770
|
return true;
|
|
660
771
|
}
|
|
661
|
-
if (
|
|
772
|
+
if (command === "effort") {
|
|
662
773
|
const adapter = this.getReplyAdapter(msg);
|
|
663
774
|
if (!adapter)
|
|
664
775
|
return false;
|
|
@@ -674,13 +785,13 @@ export class TopicCommands {
|
|
|
674
785
|
}
|
|
675
786
|
else if (this.ctx.promptEffortMenu) {
|
|
676
787
|
// No arg → inline keyboard menu (TG), same shape as /model.
|
|
677
|
-
const fallback = await this.ctx.promptEffortMenu(instanceName, msg.userId, msg.threadId ?? msg.chatId, adapter, msg.chatId, msg.threadId);
|
|
788
|
+
const fallback = await this.ctx.promptEffortMenu(instanceName, msg.userId, msg.threadId ?? msg.chatId, adapter, msg.chatId, msg.threadId, msg.adapterId);
|
|
678
789
|
if (fallback)
|
|
679
790
|
await adapter.sendText(msg.chatId, fallback, { threadId: msg.threadId });
|
|
680
791
|
}
|
|
681
792
|
return true;
|
|
682
793
|
}
|
|
683
|
-
if (
|
|
794
|
+
if (command === "model") {
|
|
684
795
|
const adapter = this.getReplyAdapter(msg);
|
|
685
796
|
if (!adapter)
|
|
686
797
|
return false;
|
|
@@ -695,7 +806,7 @@ export class TopicCommands {
|
|
|
695
806
|
}
|
|
696
807
|
else if (this.ctx.promptModelMenu) {
|
|
697
808
|
// No arg → inline keyboard menu (TG)
|
|
698
|
-
const fallback = await this.ctx.promptModelMenu(instanceName, msg.userId, msg.threadId ?? msg.chatId, adapter, msg.chatId, msg.threadId);
|
|
809
|
+
const fallback = await this.ctx.promptModelMenu(instanceName, msg.userId, msg.threadId ?? msg.chatId, adapter, msg.chatId, msg.threadId, msg.adapterId);
|
|
699
810
|
if (fallback)
|
|
700
811
|
await adapter.sendText(msg.chatId, fallback, { threadId: msg.threadId });
|
|
701
812
|
}
|
|
@@ -704,16 +815,21 @@ export class TopicCommands {
|
|
|
704
815
|
}
|
|
705
816
|
return true;
|
|
706
817
|
}
|
|
707
|
-
|
|
708
|
-
|
|
818
|
+
if (command === "compact") {
|
|
819
|
+
const compact = parseCompactCommand(text);
|
|
709
820
|
const adapter = this.getReplyAdapter(msg);
|
|
710
821
|
if (!adapter)
|
|
711
822
|
return false;
|
|
823
|
+
// Channel-admin, as the Discord slash command (#754 audit): it rewrites the instance's context.
|
|
824
|
+
if (!this.ctx.isFleetAdmin(msg.userId, msg.adapterId)) {
|
|
825
|
+
await adapter.sendText(msg.chatId, t("permission.denied"), { threadId: msg.threadId });
|
|
826
|
+
return true;
|
|
827
|
+
}
|
|
712
828
|
const result = await this.sendCompact(instanceName, compact.instructions);
|
|
713
829
|
await adapter.sendText(msg.chatId, result, { threadId: msg.threadId });
|
|
714
830
|
return true;
|
|
715
831
|
}
|
|
716
|
-
if (
|
|
832
|
+
if (command === "steer") {
|
|
717
833
|
const adapter = this.getReplyAdapter(msg);
|
|
718
834
|
if (!adapter)
|
|
719
835
|
return false;
|
|
@@ -730,7 +846,7 @@ export class TopicCommands {
|
|
|
730
846
|
await adapter.sendText(msg.chatId, result, { threadId: msg.threadId });
|
|
731
847
|
return true;
|
|
732
848
|
}
|
|
733
|
-
if (
|
|
849
|
+
if (command === "btw") {
|
|
734
850
|
const adapter = this.getReplyAdapter(msg);
|
|
735
851
|
if (!adapter)
|
|
736
852
|
return false;
|
|
@@ -746,7 +862,7 @@ export class TopicCommands {
|
|
|
746
862
|
await adapter.sendText(msg.chatId, result, { threadId: msg.threadId });
|
|
747
863
|
return true;
|
|
748
864
|
}
|
|
749
|
-
if (
|
|
865
|
+
if (command === "clear") {
|
|
750
866
|
const adapter = this.getReplyAdapter(msg);
|
|
751
867
|
if (!adapter)
|
|
752
868
|
return false;
|
|
@@ -763,7 +879,7 @@ export class TopicCommands {
|
|
|
763
879
|
await adapter.sendText(msg.chatId, fallback, { threadId: msg.threadId });
|
|
764
880
|
return true;
|
|
765
881
|
}
|
|
766
|
-
if (
|
|
882
|
+
if (command === "cancel") {
|
|
767
883
|
const adapter = this.getReplyAdapter(msg);
|
|
768
884
|
if (!adapter)
|
|
769
885
|
return false;
|
|
@@ -771,10 +887,15 @@ export class TopicCommands {
|
|
|
771
887
|
await adapter.sendText(msg.chatId, ok ? t("cancel.sent", instanceName) : t("cancel.not_running", instanceName), { threadId: msg.threadId });
|
|
772
888
|
return true;
|
|
773
889
|
}
|
|
774
|
-
if (
|
|
890
|
+
if (command === "save") {
|
|
775
891
|
const adapter = this.getReplyAdapter(msg);
|
|
776
892
|
if (!adapter)
|
|
777
893
|
return false;
|
|
894
|
+
// Channel-admin, as the Discord slash command (#754 audit): it writes a file in the instance's directory.
|
|
895
|
+
if (!this.ctx.isFleetAdmin(msg.userId, msg.adapterId)) {
|
|
896
|
+
await adapter.sendText(msg.chatId, t("permission.denied"), { threadId: msg.threadId });
|
|
897
|
+
return true;
|
|
898
|
+
}
|
|
778
899
|
const filename = parseSaveFilename(text);
|
|
779
900
|
if (!filename) {
|
|
780
901
|
await adapter.sendText(msg.chatId, t("save.usage"), { threadId: msg.threadId });
|
|
@@ -788,7 +909,17 @@ export class TopicCommands {
|
|
|
788
909
|
await adapter.sendText(msg.chatId, result, { threadId: msg.threadId });
|
|
789
910
|
return true;
|
|
790
911
|
}
|
|
791
|
-
|
|
912
|
+
// `/raw <text>` is pasted into the CLI as typed, with no [user:] envelope (daemon.ts): it is CLI input, so only
|
|
913
|
+
// the owning bot's fleet admin may send it (#754 audit). An admin's falls through to delivery unchanged.
|
|
914
|
+
if (command === "raw") {
|
|
915
|
+
if (this.ctx.isFleetAdmin(msg.userId, msg.adapterId))
|
|
916
|
+
return false;
|
|
917
|
+
const adapter = this.getReplyAdapter(msg);
|
|
918
|
+
if (adapter)
|
|
919
|
+
await adapter.sendText(msg.chatId, t("permission.denied"), { threadId: msg.threadId });
|
|
920
|
+
return true;
|
|
921
|
+
}
|
|
922
|
+
if (command !== "ctx")
|
|
792
923
|
return false;
|
|
793
924
|
const adapter = this.getReplyAdapter(msg);
|
|
794
925
|
if (!adapter)
|
|
@@ -946,14 +1077,17 @@ export class TopicCommands {
|
|
|
946
1077
|
* Backends whose TUI accepts a busy-pane paste as steering input,
|
|
947
1078
|
* live-verified: claude-code and codex buffer-then-submit at the turn
|
|
948
1079
|
* boundary, grok accepts it in its input line. kiro's legacy TUI swallows
|
|
949
|
-
* the paste outright
|
|
1080
|
+
* the paste outright; its TUI front-ends steer, so kiro answers per launch
|
|
1081
|
+
* (#1405). opencode/antigravity are unverified — for those
|
|
950
1082
|
* the user gets an honest "not supported" instead of a silent queue
|
|
951
1083
|
* fallback that looks like a steer but behaves like a normal message.
|
|
952
1084
|
*/
|
|
953
1085
|
sendSteer(instanceName, content, msg) {
|
|
954
1086
|
const backend = this.effectiveBackend(instanceName);
|
|
955
|
-
|
|
956
|
-
|
|
1087
|
+
const launchSupportsSteer = this.ctx.instanceLaunchSupportsSteer?.(instanceName);
|
|
1088
|
+
if (!instanceSupportsSteer(backend, launchSupportsSteer)) {
|
|
1089
|
+
// A backend that answers per launch (kiro, #1405) can steer, just not as this instance runs now.
|
|
1090
|
+
return launchSupportsSteer === false ? t("steer.unsupported_launch", backend) : t("steer.unsupported", backend);
|
|
957
1091
|
}
|
|
958
1092
|
const ipc = this.ctx.instanceIpcClients.get(instanceName);
|
|
959
1093
|
if (!ipc?.connected)
|
|
@@ -1402,12 +1536,18 @@ export class TopicCommands {
|
|
|
1402
1536
|
}
|
|
1403
1537
|
const sent = await adapter.sendText(chatId, t("update.progress.preparing", 0), { threadId });
|
|
1404
1538
|
this.ctx.beginUpdateProgress?.(adapter, chatId, threadId, sent.messageId);
|
|
1405
|
-
// The CLI picks the channel from the installed version it replaces; see UPDATE_COMMAND.
|
|
1406
|
-
|
|
1539
|
+
// The CLI picks the channel from the installed version it replaces; see UPDATE_COMMAND. #1450 C5: the INSTALLED
|
|
1540
|
+
// agend, verified by identity, by absolute path — or a refusal, never whatever `agend` is first on PATH.
|
|
1541
|
+
const installed = await resolveInstalledAgend();
|
|
1542
|
+
if (!installed.ok) {
|
|
1543
|
+
this.ctx.failUpdateProgress?.(`/update cannot verify the installed AgEnD (${installed.reason}). Run \`agend update\` from a shell.`);
|
|
1544
|
+
return;
|
|
1545
|
+
}
|
|
1407
1546
|
const { spawn } = await import("node:child_process");
|
|
1408
1547
|
const origin = `command /update by ${msg.adapterId}:${msg.userId}`;
|
|
1409
1548
|
recordInternalRequest(this.ctx.dataDir, "update", origin);
|
|
1410
|
-
const
|
|
1549
|
+
const { command, args } = updateCommand(installed.agend);
|
|
1550
|
+
const child = spawn(command, args, {
|
|
1411
1551
|
detached: true, stdio: "ignore", env: withOrigin(origin),
|
|
1412
1552
|
});
|
|
1413
1553
|
child.once("error", err => this.ctx.failUpdateProgress?.(err.message));
|
|
@@ -1447,7 +1587,9 @@ export class TopicCommands {
|
|
|
1447
1587
|
try {
|
|
1448
1588
|
const { execFile } = await import("node:child_process");
|
|
1449
1589
|
const { promisify } = await import("node:util");
|
|
1450
|
-
|
|
1590
|
+
// This CLI on this Node, not whichever `agend` is first on PATH (#1450 C5).
|
|
1591
|
+
const doctor = selfCommand(["backend", "doctor", backend]);
|
|
1592
|
+
const { stdout } = await promisify(execFile)(doctor.command, doctor.args, {
|
|
1451
1593
|
timeout: 30_000,
|
|
1452
1594
|
encoding: "utf-8",
|
|
1453
1595
|
});
|