@songsid/agend 2.2.0-beta.9 → 2.3.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -24
- package/README.zh-TW.md +40 -24
- package/dist/agent-cli.js +248 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.d.ts +2 -0
- package/dist/agent-endpoint.js +28 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/agent-file-read.d.ts +30 -0
- package/dist/agent-file-read.js +129 -0
- package/dist/agent-file-read.js.map +1 -0
- package/dist/agent-whats-new.js +20 -1
- package/dist/agent-whats-new.js.map +1 -1
- package/dist/atomic-write.js +9 -1
- package/dist/atomic-write.js.map +1 -1
- package/dist/auth-api.d.ts +3 -1
- package/dist/auth-api.js +32 -1
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/antigravity.d.ts +33 -0
- package/dist/backend/antigravity.js +129 -21
- 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/muse.js +10 -2
- package/dist/backend/muse.js.map +1 -1
- 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 +14 -0
- package/dist/channel/adapters/discord.js +66 -4
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +26 -1
- package/dist/channel/adapters/telegram.js +98 -7
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/mcp-tools.js +36 -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 +31 -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 +55 -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 +394 -29
- 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 +12 -0
- package/dist/fleet-manager.d.ts +247 -9
- package/dist/fleet-manager.js +1227 -142
- 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/general-knowledge/skills/web-appearance/SKILL.md +258 -0
- 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 +15 -8
- package/dist/instance-avatar.js.map +1 -1
- package/dist/instance-config-impact.js +3 -0
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.js +9 -4
- package/dist/instance-lifecycle.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/needs-you-hub.d.ts +4 -0
- package/dist/needs-you-hub.js +31 -6
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +1 -13
- package/dist/needs-you.js +3 -37
- package/dist/needs-you.js.map +1 -1
- package/dist/outbound-handlers.d.ts +32 -0
- package/dist/outbound-handlers.js +150 -45
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +76 -0
- package/dist/outbound-schemas.js +65 -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 +25 -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/repo-worktree-guard.d.ts +36 -0
- package/dist/repo-worktree-guard.js +143 -0
- package/dist/repo-worktree-guard.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/scheduler/scheduler.d.ts +58 -1
- package/dist/scheduler/scheduler.js +176 -10
- package/dist/scheduler/scheduler.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/settings-api.js +74 -1
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +8 -0
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +16 -2
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-http-confirmation.js +5 -0
- package/dist/settings-http-confirmation.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 +53 -3
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.d.ts +72 -2
- package/dist/topic-commands.js +156 -38
- package/dist/topic-commands.js.map +1 -1
- package/dist/topic-link.d.ts +128 -0
- package/dist/topic-link.js +269 -0
- package/dist/topic-link.js.map +1 -0
- 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 +21 -0
- package/dist/ui/app-effects.js +187 -0
- package/dist/ui/chat-commands.js +1 -0
- package/dist/ui/chat-effect-posters.js +42 -0
- package/dist/ui/chat-effects.js +72 -0
- package/dist/ui/chat-live-replies.js +58 -0
- package/dist/ui/chat-render.js +59 -14
- package/dist/ui/chat-store.js +78 -8
- package/dist/ui/chat-strings.js +43 -16
- package/dist/ui/chat-thread.js +175 -31
- package/dist/ui/chat-tour.js +18 -15
- package/dist/ui/effect-trial-controller.js +119 -0
- package/dist/ui/effect-trial-offer.js +31 -0
- package/dist/ui/effect-trial-panel.js +37 -0
- package/dist/ui/image-lightbox.js +1 -1
- package/dist/ui/panel-chat.js +101 -27
- package/dist/ui/panel-details.js +18 -5
- package/dist/ui/panel-fleet.js +18 -5
- package/dist/ui/panel-log.js +10 -10
- package/dist/ui/panel-needs.js +13 -10
- package/dist/ui/panel-settings.js +66 -12
- package/dist/ui/preview-panel.js +25 -9
- package/dist/ui/settings-appearance.js +325 -0
- package/dist/ui/settings-dialogs.js +11 -6
- package/dist/ui/settings-effects.js +201 -0
- package/dist/ui/settings-model.js +3 -1
- package/dist/ui/settings-mods.js +257 -0
- package/dist/ui/settings-owner-effects.js +80 -0
- package/dist/ui/settings-strings.js +269 -10
- package/dist/ui/settings-token.js +7 -0
- package/dist/ui/settings-wizard.js +5 -3
- package/dist/ui/shared/agend-auth.js +27 -3
- package/dist/ui/shared/agent-widget.js +248 -0
- package/dist/ui/shared/app-i18n.js +3 -1
- package/dist/ui/shared/app-prefs.js +30 -10
- package/dist/ui/shared/app-route.js +23 -1
- package/dist/ui/shared/app-session.js +1 -1
- package/dist/ui/shared/app-shell.js +29 -16
- package/dist/ui/shared/app-store.js +2 -0
- package/dist/ui/shared/app-stream.js +15 -7
- package/dist/ui/shared/app-themes.js +188 -0
- package/dist/ui/shared/app.css +266 -11
- package/dist/ui/shared/app.js +6 -0
- package/dist/ui/shared/card-strings.js +28 -0
- package/dist/ui/shared/effect-app-runtime.js +248 -0
- package/dist/ui/shared/effect-baseline.js +64 -0
- package/dist/ui/shared/effect-chat-runtime.js +154 -0
- package/dist/ui/shared/effect-cursor.js +125 -0
- package/dist/ui/shared/effect-frame.js +127 -0
- package/dist/ui/shared/effect-geometry.js +122 -0
- package/dist/ui/shared/effect-host-style.js +10 -0
- package/dist/ui/shared/effect-owner-regions.js +74 -0
- package/dist/ui/shared/effect-owner-source.js +115 -0
- package/dist/ui/shared/effect-policy.js +137 -0
- package/dist/ui/shared/effect-poster-reader.js +98 -0
- package/dist/ui/shared/effect-posters.js +117 -0
- package/dist/ui/shared/effect-profiler.js +162 -0
- package/dist/ui/shared/effect-profiles.js +65 -0
- package/dist/ui/shared/effect-registry.js +496 -0
- package/dist/ui/shared/effect-runtime-loader.js +234 -0
- package/dist/ui/shared/effect-safety.js +153 -0
- package/dist/ui/shared/effect-stock-snapshot.js +34 -0
- package/dist/ui/shared/effect-stock-trust.js +165 -0
- package/dist/ui/shared/effect-trial-source.js +103 -0
- package/dist/ui/shared/effect-trial-stage.js +147 -0
- package/dist/ui/shared/header-tools.js +35 -15
- package/dist/ui/shared/identity-card.js +202 -0
- package/dist/ui/shared/identity-color.js +261 -0
- package/dist/ui/shared/instance-nav.js +22 -14
- package/dist/ui/shared/instance-switch.js +5 -2
- package/dist/ui/shared/owner-css.js +221 -0
- package/dist/ui/shared/owner-effect-prefs.js +117 -0
- package/dist/ui/shared/panel-view.js +96 -12
- package/dist/ui/shared/signin.js +17 -9
- package/dist/ui/shared/ui-dialog.js +1 -1
- package/dist/ui/shared/ui-icons.js +3 -0
- package/dist/ui/shared/ui-menu.js +1 -1
- package/dist/ui/shared/ui-toast.js +1 -1
- package/dist/ui/shared/view-strings.js +40 -2
- package/dist/ui/signin.html +9 -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.d.ts +29 -0
- package/dist/view-api.js +214 -17
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.d.ts +86 -2
- package/dist/web-api.js +1160 -92
- package/dist/web-api.js.map +1 -1
- package/dist/web-appearance-limits.d.ts +82 -0
- package/dist/web-appearance-limits.js +83 -0
- package/dist/web-appearance-limits.js.map +1 -0
- package/dist/web-appearance-policy.d.ts +66 -0
- package/dist/web-appearance-policy.js +94 -0
- package/dist/web-appearance-policy.js.map +1 -0
- package/dist/web-appearance-tools.d.ts +50 -0
- package/dist/web-appearance-tools.js +105 -0
- package/dist/web-appearance-tools.js.map +1 -0
- package/dist/web-appearance-view.d.ts +99 -0
- package/dist/web-appearance-view.js +163 -0
- package/dist/web-appearance-view.js.map +1 -0
- package/dist/web-appearance.d.ts +79 -0
- package/dist/web-appearance.js +298 -0
- package/dist/web-appearance.js.map +1 -0
- package/dist/web-asset-parts.d.ts +98 -0
- package/dist/web-asset-parts.js +133 -0
- package/dist/web-asset-parts.js.map +1 -0
- package/dist/web-auth.js +17 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-card.d.ts +96 -0
- package/dist/web-card.js +232 -0
- package/dist/web-card.js.map +1 -0
- package/dist/web-chat-history.d.ts +39 -1
- package/dist/web-chat-history.js +69 -9
- 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-effect-bundle.d.ts +28 -0
- package/dist/web-effect-bundle.js +126 -0
- package/dist/web-effect-bundle.js.map +1 -0
- package/dist/web-effect-canonical.d.ts +8 -0
- package/dist/web-effect-canonical.js +27 -0
- package/dist/web-effect-canonical.js.map +1 -0
- package/dist/web-effect-library.d.ts +114 -0
- package/dist/web-effect-library.js +530 -0
- package/dist/web-effect-library.js.map +1 -0
- package/dist/web-effect-poster.d.ts +8 -0
- package/dist/web-effect-poster.js +52 -0
- package/dist/web-effect-poster.js.map +1 -0
- package/dist/web-effect-profiles.d.ts +118 -0
- package/dist/web-effect-profiles.js +180 -0
- package/dist/web-effect-profiles.js.map +1 -0
- package/dist/web-effect-service.d.ts +86 -0
- package/dist/web-effect-service.js +312 -0
- package/dist/web-effect-service.js.map +1 -0
- package/dist/web-effect-tools.d.ts +47 -0
- package/dist/web-effect-tools.js +126 -0
- package/dist/web-effect-tools.js.map +1 -0
- package/dist/web-effect-trials.d.ts +86 -0
- package/dist/web-effect-trials.js +204 -0
- package/dist/web-effect-trials.js.map +1 -0
- package/dist/web-effect-upload.d.ts +29 -0
- package/dist/web-effect-upload.js +190 -0
- package/dist/web-effect-upload.js.map +1 -0
- package/dist/web-effect-worker.d.ts +8 -0
- package/dist/web-effect-worker.js +170 -0
- package/dist/web-effect-worker.js.map +1 -0
- package/dist/web-effect.d.ts +89 -0
- package/dist/web-effect.js +132 -0
- package/dist/web-effect.js.map +1 -0
- package/dist/web-identity-color.d.ts +87 -0
- package/dist/web-identity-color.js +209 -0
- package/dist/web-identity-color.js.map +1 -0
- package/dist/web-identity-palette.d.ts +113 -0
- package/dist/web-identity-palette.js +84 -0
- package/dist/web-identity-palette.js.map +1 -0
- package/dist/web-image-meta.d.ts +25 -0
- package/dist/web-image-meta.js +200 -0
- package/dist/web-image-meta.js.map +1 -0
- 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-mod-agent.d.ts +50 -0
- package/dist/web-mod-agent.js +203 -0
- package/dist/web-mod-agent.js.map +1 -0
- package/dist/web-mod-bundle.d.ts +144 -0
- package/dist/web-mod-bundle.js +464 -0
- package/dist/web-mod-bundle.js.map +1 -0
- package/dist/web-mod-export.d.ts +59 -0
- package/dist/web-mod-export.js +79 -0
- package/dist/web-mod-export.js.map +1 -0
- package/dist/web-mod-store.d.ts +283 -0
- package/dist/web-mod-store.js +624 -0
- package/dist/web-mod-store.js.map +1 -0
- package/dist/web-org.d.ts +3 -3
- package/dist/web-org.js +11 -17
- package/dist/web-org.js.map +1 -1
- package/dist/web-owner-css-store.d.ts +180 -0
- package/dist/web-owner-css-store.js +384 -0
- package/dist/web-owner-css-store.js.map +1 -0
- package/dist/web-owner-css.d.ts +58 -0
- package/dist/web-owner-css.js +552 -0
- package/dist/web-owner-css.js.map +1 -0
- package/dist/web-prefs.d.ts +66 -0
- package/dist/web-prefs.js +243 -35
- package/dist/web-prefs.js.map +1 -1
- package/dist/web-preview.d.ts +9 -1
- package/dist/web-preview.js +24 -7
- package/dist/web-preview.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-settings-patch.d.ts +18 -0
- package/dist/web-settings-patch.js +51 -0
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/web-shell-routes.d.ts +1 -1
- package/dist/web-shell-routes.js +1 -1
- package/dist/web-shell-routes.js.map +1 -1
- package/dist/web-theme-store.d.ts +218 -0
- package/dist/web-theme-store.js +516 -0
- package/dist/web-theme-store.js.map +1 -0
- package/dist/web-theme.d.ts +121 -0
- package/dist/web-theme.js +407 -0
- package/dist/web-theme.js.map +1 -0
- package/dist/web-upload.d.ts +119 -4
- package/dist/web-upload.js +252 -39
- package/dist/web-upload.js.map +1 -1
- package/dist/web-widget.d.ts +72 -0
- package/dist/web-widget.js +245 -0
- package/dist/web-widget.js.map +1 -0
- package/launcher/install-admission.cjs +61 -6
- package/package.json +3 -3
package/dist/daemon.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { AGENT_WHATS_NEW, agendVersion, planWhatsNew, readWhatsNewRecord, recordWhatsNew, whatsNewNotice } from "./agent-whats-new.js";
|
|
2
|
-
import { join, dirname,
|
|
2
|
+
import { join, dirname, resolve } from "node:path";
|
|
3
|
+
import { checkoutTarget, readCheckouts, releaseCandidate, reposRoot, verifyWorktree, writeCheckouts } from "./repo-worktree-guard.js";
|
|
3
4
|
import { mkdirSync, writeFileSync, readFileSync, readdirSync, existsSync, unlinkSync, rmSync, appendFileSync, statSync, renameSync } from "node:fs";
|
|
5
|
+
import { COMPACT_WATCH_TIMEOUT_MS, launchIdentity } from "./compact-watch.js";
|
|
6
|
+
import { KIRO_COMPACT_PANE_LINES, KiroCompactPaneFollower } from "./kiro-compact-pane.js";
|
|
4
7
|
import { fileURLToPath } from "node:url";
|
|
5
8
|
import { ensureInstanceDir } from "./private-dir.js";
|
|
6
9
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
@@ -17,6 +20,9 @@ import { TranscriptTurnLedger } from "./transcript-turns.js";
|
|
|
17
20
|
import { credentialProfileStoreHome, resolveCredentialProfile } from "./backend/credential-profile.js";
|
|
18
21
|
import { resolveToolSet } from "./tool-permissions.js";
|
|
19
22
|
import { getAgendHome } from "./paths.js";
|
|
23
|
+
import { readAgentEffect, sendEffectInParts } from "./web-effect-upload.js";
|
|
24
|
+
import { readAgentFile } from "./agent-file-read.js";
|
|
25
|
+
import { ASSET_UPLOAD_MAX_BYTES, MOD_FILE, MOD_MAX_PARTS, MOD_UPLOAD_MAX_BYTES, receiveFiles, receivePreview, sendAssetInParts, writeModFile, writePreview } from "./web-asset-parts.js";
|
|
20
26
|
import { LOGIN_FLOWS } from "./login-flows.js";
|
|
21
27
|
import { ProgressAccumulator, summarizeProgress } from "./tool-progress.js";
|
|
22
28
|
import { assembleSystemPrompt, resolveWorkflowText } from "./prompt-file-ref.js";
|
|
@@ -53,6 +59,26 @@ import { unrecognisedPromptShape } from "./unrecognised-prompt.js";
|
|
|
53
59
|
const __filename = fileURLToPath(import.meta.url);
|
|
54
60
|
const __dirname = dirname(__filename);
|
|
55
61
|
// Tool routing sets — module-level to avoid re-creation on every handleToolCall
|
|
62
|
+
/** #1629: the caller's own web theme tools, each its own typed IPC message (one tool per type, for the permission check). */
|
|
63
|
+
const WEB_THEME_IPC = Object.freeze({
|
|
64
|
+
get_web_theme: "fleet_get_web_theme", set_web_theme: "fleet_set_web_theme",
|
|
65
|
+
set_web_theme_asset: "fleet_set_web_theme_asset", reset_web_theme: "fleet_reset_web_theme",
|
|
66
|
+
// r4 §1: how it appears — read-only; a preview's files are written here, on the agent's side.
|
|
67
|
+
get_web_appearance: "fleet_get_web_appearance", preview_web_appearance: "fleet_preview_web_appearance",
|
|
68
|
+
// r4-4: its own declarative widgets.
|
|
69
|
+
set_web_widget: "fleet_set_web_widget", remove_web_widget: "fleet_remove_web_widget",
|
|
70
|
+
// r4-5b: mods — an export's file is written here, a proposal's file read here (on the agent's side).
|
|
71
|
+
export_web_mod: "fleet_export_web_mod", propose_web_mod: "fleet_propose_web_mod",
|
|
72
|
+
upload_web_effect: "fleet_upload_web_effect",
|
|
73
|
+
list_web_effects: "fleet_list_web_effects",
|
|
74
|
+
preview_web_effect: "fleet_preview_web_effect",
|
|
75
|
+
profile_web_effect: "fleet_profile_web_effect",
|
|
76
|
+
apply_web_effect: "fleet_apply_web_effect",
|
|
77
|
+
remove_web_effect: "fleet_remove_web_effect",
|
|
78
|
+
delete_web_effect: "fleet_delete_web_effect",
|
|
79
|
+
});
|
|
80
|
+
/** The largest picture any slot may take (a card slot's ceiling; the fleet checks the limit in force): read no more. */
|
|
81
|
+
const WEB_THEME_ASSET_MAX_BYTES = ASSET_UPLOAD_MAX_BYTES;
|
|
56
82
|
const CROSS_INSTANCE_TOOLS = new Set(["send_to_instance", "broadcast", "list_instances", "start_instance", "restart_instance", "create_instance", "delete_instance", "replace_instance", "request_information", "delegate_task", "report_result", "delivery_status", "describe_instance"]);
|
|
57
83
|
const SCHEDULE_TOOLS = new Set(["create_schedule", "list_schedules", "update_schedule", "delete_schedule"]);
|
|
58
84
|
const DECISION_TOOLS = new Set(["post_decision", "list_decisions", "update_decision"]);
|
|
@@ -102,7 +128,7 @@ export function buildInstructionReloadNotice(binaryName, instanceName, instanceD
|
|
|
102
128
|
: binaryName === "kiro-cli"
|
|
103
129
|
? `.kiro/steering/agend-${instanceName}.md`
|
|
104
130
|
: binaryName === "agy"
|
|
105
|
-
? ".agents/
|
|
131
|
+
? ".agents/AGENTS.md"
|
|
106
132
|
: join(instanceDir, "fleet-instructions.md");
|
|
107
133
|
return `[system] Your AgEnD instructions have been updated. Reload only ${source}; do not scan other instruction directories. Do not reply to this message.`;
|
|
108
134
|
}
|
|
@@ -138,6 +164,8 @@ export const DEFAULT_STATE_IDLE_DEBOUNCE_MS = 2_000;
|
|
|
138
164
|
export const DEFAULT_STATE_SAFETY_SWEEP_MS = 60_000;
|
|
139
165
|
/** Coalesce one cosmetic-redraw burst before comparing the visible pane. */
|
|
140
166
|
export const PERIODIC_REDRAW_PROBE_MS = 25;
|
|
167
|
+
/** Board 907c7899: how often a kiro /compact's pane is read (TUI V2's "too short" shows for about ten seconds). */
|
|
168
|
+
const KIRO_COMPACT_PANE_POLL_MS = 1_000;
|
|
141
169
|
/** Do not turn a streaming Codex turn into one capture-pane per burst. */
|
|
142
170
|
export const STRUCTURED_IDLE_PROBE_MS = 500;
|
|
143
171
|
/**
|
|
@@ -645,6 +673,10 @@ export function channelStatus(meta) {
|
|
|
645
673
|
// they are the dashboard's ticks (the fleet routes them by the message id, never to a platform).
|
|
646
674
|
if (!messageId || (!chatId && meta.source !== "web"))
|
|
647
675
|
return undefined;
|
|
676
|
+
// #1823: a notice from AgEnD itself (a poll's results) names its chat so the answer goes there, but its message id
|
|
677
|
+
// is AgEnD's own, not a platform message: there is nothing to react to.
|
|
678
|
+
if (meta.source === "agend-system")
|
|
679
|
+
return undefined;
|
|
648
680
|
if (!chatId)
|
|
649
681
|
return { chatId: "", messageId };
|
|
650
682
|
const threadId = meta.thread_id || undefined;
|
|
@@ -1065,7 +1097,7 @@ export class BlockingProcessDetector {
|
|
|
1065
1097
|
/** Response types the fleet sends back for tool calls the daemon forwarded. */
|
|
1066
1098
|
const FLEET_RESPONSE_TYPES = new Set([
|
|
1067
1099
|
"fleet_schedule_response", "fleet_outbound_response", "fleet_decision_response", "fleet_task_response",
|
|
1068
|
-
"fleet_display_name_response", "fleet_description_response", "fleet_persona_emoji_response",
|
|
1100
|
+
"fleet_display_name_response", "fleet_description_response", "fleet_persona_emoji_response", "fleet_web_theme_response",
|
|
1069
1101
|
]);
|
|
1070
1102
|
export class Daemon extends EventEmitter {
|
|
1071
1103
|
name;
|
|
@@ -3767,6 +3799,42 @@ export class Daemon extends EventEmitter {
|
|
|
3767
3799
|
: Math.max(this.deliveryEpoch, fleetEpoch);
|
|
3768
3800
|
this.logger.info({ deliveryEpoch: this.deliveryEpoch }, "Pending delivery queue cleared by user cancel");
|
|
3769
3801
|
}
|
|
3802
|
+
/** Board 907c7899: the layout a web /compact's end can be read from on this pane (kiro classic or TUI V2), or null. */
|
|
3803
|
+
compactPaneUi() {
|
|
3804
|
+
return this.backend?.compactPaneUi?.() ?? null;
|
|
3805
|
+
}
|
|
3806
|
+
/**
|
|
3807
|
+
* Board 907c7899: follow a /compact written to this pane until the pane says how it ended, then say so once
|
|
3808
|
+
* (`compact_pane_result`). Bound to the launch it was written under: another launch, or no pane, ends the look
|
|
3809
|
+
* silently (the fleet's watch sees the launch change and calls it lost); the fleet's deadline is the same.
|
|
3810
|
+
*/
|
|
3811
|
+
async followCompactPane(id, owner, follower) {
|
|
3812
|
+
const tmux = this.tmux;
|
|
3813
|
+
if (!tmux || owner === null)
|
|
3814
|
+
return;
|
|
3815
|
+
// Monotonic, and asked after every await: a result past the deadline is not said (the fleet's watch has timed out).
|
|
3816
|
+
const deadline = performance.now() + COMPACT_WATCH_TIMEOUT_MS;
|
|
3817
|
+
const standing = () => this.tmux === tmux && launchIdentity(this.interactionOwner()) === owner && performance.now() < deadline;
|
|
3818
|
+
while (standing()) {
|
|
3819
|
+
await new Promise(resolve => { setTimeout(resolve, KIRO_COMPACT_PANE_POLL_MS).unref?.(); });
|
|
3820
|
+
if (!standing())
|
|
3821
|
+
return;
|
|
3822
|
+
let pane;
|
|
3823
|
+
try {
|
|
3824
|
+
pane = await tmux.capturePaneWithHistory(KIRO_COMPACT_PANE_LINES);
|
|
3825
|
+
}
|
|
3826
|
+
catch {
|
|
3827
|
+
continue;
|
|
3828
|
+
}
|
|
3829
|
+
if (!standing())
|
|
3830
|
+
return;
|
|
3831
|
+
const outcome = follower.look(pane);
|
|
3832
|
+
if (outcome) {
|
|
3833
|
+
this.ipcServer?.broadcast({ type: "compact_pane_result", id, owner, outcome });
|
|
3834
|
+
return;
|
|
3835
|
+
}
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3770
3838
|
captureDeliveryEpoch(value) {
|
|
3771
3839
|
const epoch = typeof value === "number" && Number.isSafeInteger(value) && value >= 0
|
|
3772
3840
|
? value
|
|
@@ -3778,21 +3846,55 @@ export class Daemon extends EventEmitter {
|
|
|
3778
3846
|
isDeliveryEpochCurrent(epoch) {
|
|
3779
3847
|
return epoch === this.deliveryEpoch;
|
|
3780
3848
|
}
|
|
3781
|
-
queueRawPaste(rawText, deliveryEpoch = this.deliveryEpoch, confirmClear = false, durableAttempt, ownSwitch) {
|
|
3849
|
+
queueRawPaste(rawText, deliveryEpoch = this.deliveryEpoch, confirmClear = false, durableAttempt, ownSwitch, notifyWritten) {
|
|
3782
3850
|
const reportSwitch = (result) => {
|
|
3783
3851
|
if (!ownSwitch)
|
|
3784
3852
|
return;
|
|
3785
3853
|
this.ipcServer?.broadcast({ type: "runtime_switch_result", id: ownSwitch.id, ...result });
|
|
3786
3854
|
};
|
|
3855
|
+
// Board 003648ac: the fleet follows a web /compact from just before its paste is written: the transcript's end then
|
|
3856
|
+
// (taken here, under this launch, before the write) and the launch it was written under ride with the notice — once.
|
|
3857
|
+
// The checkpoint and the launch are taken together, right before the paste (each attempt takes them again); the
|
|
3858
|
+
// notice carries those — never the launch at notice time, which a respawn in between would relabel.
|
|
3859
|
+
let told = false;
|
|
3860
|
+
let checkpoint = null;
|
|
3861
|
+
let owner = null;
|
|
3862
|
+
// Board 907c7899: kiro says how a /compact ended only on its own pane; read from the pane just before this write.
|
|
3863
|
+
let paneFollower = null;
|
|
3864
|
+
const tellWritten = (written) => {
|
|
3865
|
+
if (!notifyWritten || told)
|
|
3866
|
+
return;
|
|
3867
|
+
told = true;
|
|
3868
|
+
this.ipcServer?.broadcast({ type: "raw_paste_written", id: notifyWritten, outcome: written ? "written" : "not_written",
|
|
3869
|
+
...(written ? { owner, checkpoint, ...(paneFollower ? { pane: true } : {}) } : {}) });
|
|
3870
|
+
if (written && paneFollower)
|
|
3871
|
+
void this.followCompactPane(notifyWritten, owner, paneFollower);
|
|
3872
|
+
};
|
|
3873
|
+
const takeCheckpoint = () => {
|
|
3874
|
+
owner = launchIdentity(this.interactionOwner());
|
|
3875
|
+
const path = this.logTranscriptPath();
|
|
3876
|
+
checkpoint = null;
|
|
3877
|
+
if (!path)
|
|
3878
|
+
return;
|
|
3879
|
+
try {
|
|
3880
|
+
const st = statSync(path);
|
|
3881
|
+
checkpoint = { path, ino: st.ino, size: st.size };
|
|
3882
|
+
}
|
|
3883
|
+
catch {
|
|
3884
|
+
checkpoint = null;
|
|
3885
|
+
}
|
|
3886
|
+
};
|
|
3787
3887
|
if (!this.tmux || !this.isDeliveryEpochCurrent(deliveryEpoch)) {
|
|
3788
3888
|
if (durableAttempt)
|
|
3789
3889
|
this.retryDurableDeliveryBeforeBegin(durableAttempt, "raw_paste target unavailable before pane queue");
|
|
3790
3890
|
reportSwitch({ outcome: "not_sent" });
|
|
3891
|
+
tellWritten(false);
|
|
3791
3892
|
return;
|
|
3792
3893
|
}
|
|
3793
3894
|
this.pasteLock = this.pasteLock.then(async () => {
|
|
3794
3895
|
if (!this.isDeliveryEpochCurrent(deliveryEpoch)) {
|
|
3795
3896
|
reportSwitch({ outcome: "not_sent" });
|
|
3897
|
+
tellWritten(false);
|
|
3796
3898
|
this.logger.info("Pending raw delivery dropped by user cancel");
|
|
3797
3899
|
if (durableAttempt)
|
|
3798
3900
|
this.retryDurableDeliveryBeforeBegin(durableAttempt, "raw_paste epoch changed while queued");
|
|
@@ -3805,8 +3907,16 @@ export class Daemon extends EventEmitter {
|
|
|
3805
3907
|
if (durableAttempt)
|
|
3806
3908
|
this.retryDurableDeliveryBeforeBegin(durableAttempt, "raw_paste epoch changed while waking");
|
|
3807
3909
|
reportSwitch({ outcome: "not_sent" }); // #1690: cancelled before anything was typed — said at once, nothing saved
|
|
3910
|
+
tellWritten(false);
|
|
3808
3911
|
return;
|
|
3809
3912
|
}
|
|
3913
|
+
// Board 907c7899: the pane just before this attempt's paste — after its readiness wait, last capture and fence,
|
|
3914
|
+
// under the paste lock (no other input lands in between). Each attempt looks again.
|
|
3915
|
+
const lookBefore = async () => {
|
|
3916
|
+
const ui = this.backend?.compactPaneUi?.() ?? null;
|
|
3917
|
+
const before = ui ? await this.tmux?.capturePaneWithHistory(KIRO_COMPACT_PANE_LINES).catch(() => null) : null;
|
|
3918
|
+
paneFollower = ui && typeof before === "string" ? new KiroCompactPaneFollower(ui, before) : null;
|
|
3919
|
+
};
|
|
3810
3920
|
const delivered = await this.deliverMessage(rawText, undefined, {
|
|
3811
3921
|
deliveryEpoch,
|
|
3812
3922
|
verdict,
|
|
@@ -3814,8 +3924,11 @@ export class Daemon extends EventEmitter {
|
|
|
3814
3924
|
preserveExactBytes: true,
|
|
3815
3925
|
// #1690: our own /model holds every other delivery from its write on — before the lock is released, so a steer
|
|
3816
3926
|
// or /btw waiting on it cannot type into the gap before claude paints "Switch model?" (default cursor: Yes).
|
|
3817
|
-
...(ownSwitch ? { onPaneWritten: () => {
|
|
3927
|
+
...(ownSwitch || notifyWritten ? { onPaneWritten: () => { if (ownSwitch)
|
|
3928
|
+
this.ownSwitch = ownSwitch; tellWritten(true); } } : {}),
|
|
3929
|
+
...(notifyWritten ? { beforePaneWrite: takeCheckpoint, ...(this.backend?.compactPaneUi?.() ? { lookBeforePaneWrite: lookBefore } : {}) } : {}),
|
|
3818
3930
|
});
|
|
3931
|
+
tellWritten(false); // never written (once told, this says nothing)
|
|
3819
3932
|
if (delivered)
|
|
3820
3933
|
this.finishDurableSubmission(durableAttempt ?? null, verdict);
|
|
3821
3934
|
else if (durableAttempt && verdict.paneWriteStarted) {
|
|
@@ -3852,6 +3965,7 @@ export class Daemon extends EventEmitter {
|
|
|
3852
3965
|
this.ownSwitch = null;
|
|
3853
3966
|
reportSwitch({ outcome: "not_confirmed" });
|
|
3854
3967
|
}
|
|
3968
|
+
tellWritten(false);
|
|
3855
3969
|
return;
|
|
3856
3970
|
}
|
|
3857
3971
|
if (confirmClear)
|
|
@@ -3893,7 +4007,8 @@ export class Daemon extends EventEmitter {
|
|
|
3893
4007
|
const sw = msg.runtime_switch;
|
|
3894
4008
|
const ownSwitch = sw && typeof sw.id === "string" && sw.kind === "model" && typeof sw.requested === "string"
|
|
3895
4009
|
? { id: sw.id, kind: "model", requested: sw.requested } : undefined;
|
|
3896
|
-
|
|
4010
|
+
const notifyWritten = typeof msg.notify_written === "string" && /^[0-9a-f]{16}$/.test(msg.notify_written) ? msg.notify_written : undefined;
|
|
4011
|
+
this.queueRawPaste(msg.content, this.captureDeliveryEpoch(msg.delivery_epoch), msg.confirm_clear === true, durableAttempt ? { ...durableAttempt, submissionMode: "raw_paste", silentSchedule: msg.silent_schedule === true } : undefined, ownSwitch, notifyWritten);
|
|
3897
4012
|
}
|
|
3898
4013
|
/**
|
|
3899
4014
|
* #1690 (the user's choice A): after AgEnD's own `/model <name>`, claude may ask "Switch model?" (a warm cache for
|
|
@@ -5332,8 +5447,9 @@ export class Daemon extends EventEmitter {
|
|
|
5332
5447
|
* every delivery parked behind it. It recovers when the backend sees its own live, EMPTY composer with no busy, queued
|
|
5333
5448
|
* or dialog marker (isStableUnknownLayoutIdlePane) AND the transcript shows no open turn — or, with no transcript to
|
|
5334
5449
|
* ask, that same composer held unchanged for UNKNOWN_LAYOUT_STABLE_MS (#978's rule). An open turn never recovers.
|
|
5450
|
+
* #1865: `hold` makes the closed-turn case wait out that window too (a `working` reading, recovered before the stuck deadline).
|
|
5335
5451
|
*/
|
|
5336
|
-
recoverStuck(pane, snapshot, changeAt, turn) {
|
|
5452
|
+
recoverStuck(pane, snapshot, changeAt, turn, hold = false) {
|
|
5337
5453
|
const machine = this.instanceStateMachine;
|
|
5338
5454
|
const idleComposer = this.backend?.isStableUnknownLayoutIdlePane?.(pane) === true;
|
|
5339
5455
|
// The resume load (#1031: `Resuming session…` over the same composer) is input that is not open yet (#1641 R1).
|
|
@@ -5349,7 +5465,7 @@ export class Daemon extends EventEmitter {
|
|
|
5349
5465
|
this.stuckRecoveryKey = key;
|
|
5350
5466
|
this.stuckRecoverySince = mono;
|
|
5351
5467
|
}
|
|
5352
|
-
if (turn === "unknown" && mono - this.stuckRecoverySince < UNKNOWN_LAYOUT_STABLE_MS)
|
|
5468
|
+
if ((turn === "unknown" || hold) && mono - this.stuckRecoverySince < UNKNOWN_LAYOUT_STABLE_MS)
|
|
5353
5469
|
return snapshot;
|
|
5354
5470
|
// A footer this build cannot read stays unreadable: the same still pane reads stuck again at every sweep and is
|
|
5355
5471
|
// recovered again. Only the edge into idle is news.
|
|
@@ -5918,6 +6034,13 @@ export class Daemon extends EventEmitter {
|
|
|
5918
6034
|
}
|
|
5919
6035
|
if (snapshot.state === "stuck")
|
|
5920
6036
|
snapshot = this.recoverStuck(pane, snapshot, observedChangeAt, transcriptTurn);
|
|
6037
|
+
// #1865: a resumed codex can paint its footer without the Context item (sol after the beta.13 restart), so its
|
|
6038
|
+
// idle composer reads `working` for the whole stuck window. Its own rollout says no turn is open: the sweep needs
|
|
6039
|
+
// no deadline for that — the same composer held still for UNKNOWN_LAYOUT_STABLE_MS is enough.
|
|
6040
|
+
else if (snapshot.state === "working" && reason === "safety_sweep" && transcriptTurn === "closed"
|
|
6041
|
+
&& this.backend?.binaryName === "codex") {
|
|
6042
|
+
snapshot = this.recoverStuck(pane, snapshot, observedChangeAt, transcriptTurn, true);
|
|
6043
|
+
}
|
|
5921
6044
|
this.applyInstanceStateSnapshot(snapshot, pane);
|
|
5922
6045
|
// Backends without a transcript feed can still say what they are doing, if
|
|
5923
6046
|
// their TUI names it. Free-riding on a capture that already happened: no
|
|
@@ -6957,7 +7080,7 @@ export class Daemon extends EventEmitter {
|
|
|
6957
7080
|
return stale();
|
|
6958
7081
|
if (residue !== "clear")
|
|
6959
7082
|
return this.failDelivery(verdict, status, "input-residue", residue);
|
|
6960
|
-
const written = await this.writeMessageToPane(formatted, windowId, handingOffToNativeQueue, status, opts?.submissionId, verdict, opts?.durableAttempt, opts?.steer === true, writeCurrent, opts?.humanVerificationId);
|
|
7083
|
+
const written = await this.writeMessageToPane(formatted, windowId, handingOffToNativeQueue, status, opts?.submissionId, verdict, opts?.durableAttempt, opts?.steer === true, writeCurrent, opts?.humanVerificationId, opts?.beforePaneWrite, opts?.lookBeforePaneWrite);
|
|
6961
7084
|
// #1690: still under the lock — whatever waits on it next must already see what this write started.
|
|
6962
7085
|
if (verdict.paneWriteStarted)
|
|
6963
7086
|
opts?.onPaneWritten?.();
|
|
@@ -8473,7 +8596,11 @@ export class Daemon extends EventEmitter {
|
|
|
8473
8596
|
verdict = { reached: false }, durableAttempt, steer = false,
|
|
8474
8597
|
// #829: the caller's fence, asked once more after the last await before the
|
|
8475
8598
|
// first side effect. Stale means unwritten: false, with no failure verdict.
|
|
8476
|
-
stillCurrent, humanVerificationId
|
|
8599
|
+
stillCurrent, humanVerificationId,
|
|
8600
|
+
// Board 003648ac: called synchronously right before each paste — after the last await and fence of that attempt.
|
|
8601
|
+
beforePaste,
|
|
8602
|
+
// Board 907c7899: awaited each attempt after its last capture, begin and fence; the fence is asked again after it.
|
|
8603
|
+
lookBeforePaste) {
|
|
8477
8604
|
const signature = this.submissionSignature(formatted, humanVerificationId ?? submissionId, humanVerificationId !== undefined);
|
|
8478
8605
|
const rawPaste = durableAttempt?.submissionMode === "raw_paste";
|
|
8479
8606
|
const humanAttempt = verdict.humanReceipt;
|
|
@@ -8576,13 +8703,41 @@ export class Daemon extends EventEmitter {
|
|
|
8576
8703
|
}
|
|
8577
8704
|
}
|
|
8578
8705
|
}
|
|
8579
|
-
if (
|
|
8706
|
+
if (lookBeforePaste) {
|
|
8707
|
+
await lookBeforePaste();
|
|
8708
|
+
// The look awaited: this attempt is still this write's — the same fence, tmux and launch — or nothing is written.
|
|
8709
|
+
if (!steerCurrent()) {
|
|
8710
|
+
verdict.fenced = !verdict.durableBeginCommitted;
|
|
8711
|
+
return false;
|
|
8712
|
+
}
|
|
8713
|
+
}
|
|
8714
|
+
if (rawPaste) {
|
|
8580
8715
|
verdict.paneWriteStarted = true;
|
|
8716
|
+
// #1843: this write starts silent work even if its submission proof later stays uncertain.
|
|
8717
|
+
// Retire the preceding human guard before the first write, not after proof: its idle callback must never
|
|
8718
|
+
// turn a silent heartbeat into a channel reply or a reply-required recovery prompt. This may also retire a
|
|
8719
|
+
// genuine missed human reply still awaiting confirmation/recovery; log that tradeoff instead of notifying.
|
|
8720
|
+
if (durableAttempt?.silentSchedule) {
|
|
8721
|
+
this.clearReplyGuardConfirm();
|
|
8722
|
+
const previous = this.turnReplyGuard.snapshot();
|
|
8723
|
+
if (previous) {
|
|
8724
|
+
this.turnReplyGuard.complete(previous.generation);
|
|
8725
|
+
this.logger.info({
|
|
8726
|
+
correlationId: previous.target.correlationId ?? null,
|
|
8727
|
+
generation: previous.generation,
|
|
8728
|
+
phase: previous.phase,
|
|
8729
|
+
reason: "silent_schedule_delivery",
|
|
8730
|
+
deliveryId: durableAttempt.deliveryId,
|
|
8731
|
+
}, "Reply guard retired before silent schedule write");
|
|
8732
|
+
}
|
|
8733
|
+
}
|
|
8734
|
+
}
|
|
8581
8735
|
// For raw commands the paste itself may alter the live composer. Treat a
|
|
8582
8736
|
// failed/throwing write as uncertain rather than retrying bytes into the
|
|
8583
8737
|
// same pane; the write-ahead Enter marker later separates safe pre-Enter
|
|
8584
8738
|
// recovery from a possibly executed command.
|
|
8585
8739
|
const pasteGeneration = this.spawnGeneration;
|
|
8740
|
+
beforePaste?.();
|
|
8586
8741
|
const pasted = await this.tmux.pasteBuffer(formatted);
|
|
8587
8742
|
if (pasted)
|
|
8588
8743
|
this.rememberPaste(formatted, pasteGeneration);
|
|
@@ -9814,6 +9969,169 @@ export class Daemon extends EventEmitter {
|
|
|
9814
9969
|
});
|
|
9815
9970
|
return;
|
|
9816
9971
|
}
|
|
9972
|
+
// #1629: the caller's own web theme. set_web_theme_asset's file is read HERE, on the agent's side (in its working
|
|
9973
|
+
// directory, no symlink, size-capped): the fleet receives bytes, never a workspace path.
|
|
9974
|
+
if (Object.hasOwn(WEB_THEME_IPC, tool)) {
|
|
9975
|
+
// Answered exactly once, whatever happens on the way (#1887 review: a throw here once left the call unanswered).
|
|
9976
|
+
let answered = false;
|
|
9977
|
+
const reply = (result, error) => { if (answered)
|
|
9978
|
+
return; answered = true; respond(result, error); };
|
|
9979
|
+
// One fleet request; resolves with its answer, or an error string (never rejects).
|
|
9980
|
+
const ask = (payload) => new Promise((resolve) => {
|
|
9981
|
+
const fleetReqId = `theme_${++this.fleetRequestSeq}_${requestId}`;
|
|
9982
|
+
const timeout = setTimeout(() => {
|
|
9983
|
+
this.pendingIpcRequests.delete(fleetReqId);
|
|
9984
|
+
resolve({ result: null, error: `${tool} timed out` });
|
|
9985
|
+
}, daemonBudgetMs(tool));
|
|
9986
|
+
this.pendingIpcRequests.set(fleetReqId, (respMsg) => {
|
|
9987
|
+
clearTimeout(timeout);
|
|
9988
|
+
resolve({ result: respMsg.result, error: respMsg.error });
|
|
9989
|
+
});
|
|
9990
|
+
this.ipcServer?.broadcast({ type: WEB_THEME_IPC[tool], payload, meta: { instance_name: this.name }, fleetRequestId: fleetReqId });
|
|
9991
|
+
});
|
|
9992
|
+
void (async () => {
|
|
9993
|
+
if (tool === "preview_web_appearance") {
|
|
9994
|
+
// The fleet builds the SVGs (whole, or in parts); they are written here, in the working directory.
|
|
9995
|
+
const first = await ask({ ...(args.modes !== undefined ? { modes: args.modes } : {}) });
|
|
9996
|
+
if (first.error) {
|
|
9997
|
+
reply(null, first.error);
|
|
9998
|
+
return;
|
|
9999
|
+
}
|
|
10000
|
+
let failed;
|
|
10001
|
+
const got = await receivePreview((first.result && typeof first.result === "object" ? first.result : {}), async (payload) => {
|
|
10002
|
+
const r = await ask(payload);
|
|
10003
|
+
if (r.error) {
|
|
10004
|
+
failed = r.error;
|
|
10005
|
+
return { error: r.error };
|
|
10006
|
+
}
|
|
10007
|
+
return (r.result && typeof r.result === "object" ? r.result : {});
|
|
10008
|
+
});
|
|
10009
|
+
if (failed) {
|
|
10010
|
+
reply(null, failed);
|
|
10011
|
+
return;
|
|
10012
|
+
}
|
|
10013
|
+
if ("error" in got) {
|
|
10014
|
+
reply(got, undefined);
|
|
10015
|
+
return;
|
|
10016
|
+
}
|
|
10017
|
+
const written = await writePreview(got.files, { workspace: this.config.working_directory, stateDir: getAgendHome() });
|
|
10018
|
+
if ("error" in written) {
|
|
10019
|
+
reply(null, `preview_web_appearance: ${written.error}`);
|
|
10020
|
+
return;
|
|
10021
|
+
}
|
|
10022
|
+
reply(written, undefined);
|
|
10023
|
+
return;
|
|
10024
|
+
}
|
|
10025
|
+
if (tool === "export_web_mod") {
|
|
10026
|
+
// The fleet builds the file (whole, or in parts); it is written here, in the working directory.
|
|
10027
|
+
const first = await ask(args);
|
|
10028
|
+
if (first.error) {
|
|
10029
|
+
reply(null, first.error);
|
|
10030
|
+
return;
|
|
10031
|
+
}
|
|
10032
|
+
let failed;
|
|
10033
|
+
const firstResult = (first.result && typeof first.result === "object" ? first.result : {});
|
|
10034
|
+
const got = await receiveFiles(firstResult, async (payload) => {
|
|
10035
|
+
const r = await ask(payload);
|
|
10036
|
+
if (r.error) {
|
|
10037
|
+
failed = r.error;
|
|
10038
|
+
return { error: r.error };
|
|
10039
|
+
}
|
|
10040
|
+
return (r.result && typeof r.result === "object" ? r.result : {});
|
|
10041
|
+
}, { name: MOD_FILE, idKey: "transfer", what: "export", maxParts: MOD_MAX_PARTS });
|
|
10042
|
+
if (failed) {
|
|
10043
|
+
reply(null, failed);
|
|
10044
|
+
return;
|
|
10045
|
+
}
|
|
10046
|
+
if ("error" in got) {
|
|
10047
|
+
reply(got, undefined);
|
|
10048
|
+
return;
|
|
10049
|
+
}
|
|
10050
|
+
const written = await writeModFile(got.files, { workspace: this.config.working_directory, stateDir: getAgendHome() });
|
|
10051
|
+
if ("error" in written) {
|
|
10052
|
+
reply(null, `export_web_mod: ${written.error}`);
|
|
10053
|
+
return;
|
|
10054
|
+
}
|
|
10055
|
+
reply({ ...written, ...(firstResult.effects_omitted ? { effects_omitted: firstResult.effects_omitted } : {}) }, undefined);
|
|
10056
|
+
return;
|
|
10057
|
+
}
|
|
10058
|
+
if (tool === "propose_web_mod") {
|
|
10059
|
+
const read = await readAgentFile(args.file, { workspace: this.config.working_directory, stateDir: getAgendHome(), maxBytes: MOD_UPLOAD_MAX_BYTES });
|
|
10060
|
+
const named = typeof args.file === "string" ? args.file.slice(0, 200) : "the file argument";
|
|
10061
|
+
if (!read.ok) {
|
|
10062
|
+
reply(null, `propose_web_mod: ${named} — ${read.reason}`);
|
|
10063
|
+
return;
|
|
10064
|
+
}
|
|
10065
|
+
let failed;
|
|
10066
|
+
const answer = await sendAssetInParts("mod", read.bytes, async (payload) => {
|
|
10067
|
+
const r = await ask(payload);
|
|
10068
|
+
if (r.error) {
|
|
10069
|
+
failed = r.error;
|
|
10070
|
+
return { error: r.error };
|
|
10071
|
+
}
|
|
10072
|
+
return (r.result && typeof r.result === "object" ? r.result : {});
|
|
10073
|
+
});
|
|
10074
|
+
reply(failed ? null : answer, failed);
|
|
10075
|
+
return;
|
|
10076
|
+
}
|
|
10077
|
+
if (tool === "upload_web_effect") {
|
|
10078
|
+
const owner = { fence: this.launchFenceEpoch, spawn: this.spawnGeneration, boot: this.bootId, ipc: this.ipcServer };
|
|
10079
|
+
const current = () => !!owner.ipc && owner.ipc === this.ipcServer && owner.fence === this.launchFenceEpoch && owner.spawn === this.spawnGeneration && owner.boot === this.bootId && !this.deliveryWritesStopping && !this.startupAborted;
|
|
10080
|
+
if (!current()) {
|
|
10081
|
+
reply(null, "upload_web_effect: launch no longer current");
|
|
10082
|
+
return;
|
|
10083
|
+
}
|
|
10084
|
+
const read = await readAgentEffect(args.dir, { workspace: this.config.working_directory, stateDir: getAgendHome() });
|
|
10085
|
+
if (!current()) {
|
|
10086
|
+
reply(null, "upload_web_effect: launch no longer current");
|
|
10087
|
+
return;
|
|
10088
|
+
}
|
|
10089
|
+
if (!read.ok) {
|
|
10090
|
+
reply(null, `upload_web_effect: ${read.reason}`);
|
|
10091
|
+
return;
|
|
10092
|
+
}
|
|
10093
|
+
let failed;
|
|
10094
|
+
const answer = await sendEffectInParts(read.files, async (payload) => {
|
|
10095
|
+
if (!current()) {
|
|
10096
|
+
failed = "upload_web_effect: launch no longer current";
|
|
10097
|
+
return { error: failed };
|
|
10098
|
+
}
|
|
10099
|
+
const r = await ask(payload);
|
|
10100
|
+
if (r.error) {
|
|
10101
|
+
failed = r.error;
|
|
10102
|
+
return { error: r.error };
|
|
10103
|
+
}
|
|
10104
|
+
return (r.result && typeof r.result === "object" ? r.result : {});
|
|
10105
|
+
});
|
|
10106
|
+
reply(failed ? null : answer, failed);
|
|
10107
|
+
return;
|
|
10108
|
+
}
|
|
10109
|
+
if (tool !== "set_web_theme_asset") {
|
|
10110
|
+
const r = await ask(args);
|
|
10111
|
+
reply(r.result, r.error);
|
|
10112
|
+
return;
|
|
10113
|
+
}
|
|
10114
|
+
const read = await readAgentFile(args.file, { workspace: this.config.working_directory, stateDir: getAgendHome(), maxBytes: WEB_THEME_ASSET_MAX_BYTES });
|
|
10115
|
+
// The path as the agent gave it — only a string is shown (an object from raw JSON args is never coerced).
|
|
10116
|
+
const named = typeof args.file === "string" ? args.file.slice(0, 200) : "the file argument";
|
|
10117
|
+
if (!read.ok) {
|
|
10118
|
+
reply(null, `set_web_theme_asset: ${named} — ${read.reason}`);
|
|
10119
|
+
return;
|
|
10120
|
+
}
|
|
10121
|
+
// A picture larger than one IPC message goes up in parts (r4 §1: a card portrait may be megabytes).
|
|
10122
|
+
let failed;
|
|
10123
|
+
const answer = await sendAssetInParts(args.slot, read.bytes, async (payload) => {
|
|
10124
|
+
const r = await ask(payload);
|
|
10125
|
+
if (r.error) {
|
|
10126
|
+
failed = r.error;
|
|
10127
|
+
return { error: r.error };
|
|
10128
|
+
}
|
|
10129
|
+
return (r.result && typeof r.result === "object" ? r.result : {});
|
|
10130
|
+
});
|
|
10131
|
+
reply(failed ? null : answer, failed);
|
|
10132
|
+
})().catch((err) => reply(null, `${tool} failed: ${err instanceof Error ? err.message : "error"}`));
|
|
10133
|
+
return;
|
|
10134
|
+
}
|
|
9817
10135
|
if (tool === TASK_TOOL) {
|
|
9818
10136
|
const fleetReqId = `task_${++this.fleetRequestSeq}_${requestId}`;
|
|
9819
10137
|
const timeout = setTimeout(() => {
|
|
@@ -9994,6 +10312,11 @@ export class Daemon extends EventEmitter {
|
|
|
9994
10312
|
respond(null, `reply: ${buttons.error}`);
|
|
9995
10313
|
return;
|
|
9996
10314
|
}
|
|
10315
|
+
// #1823: a poll's results need the fleet's store and outbox; as text it would never close.
|
|
10316
|
+
if (args.poll !== undefined && args.poll !== null) {
|
|
10317
|
+
respond(null, "reply: a poll needs AgEnD's fleet; send the question without poll");
|
|
10318
|
+
return;
|
|
10319
|
+
}
|
|
9997
10320
|
if (buttons) {
|
|
9998
10321
|
routed = { ...args, text: `${String(args.text)}\n\n${replyButtonsFallbackText(buttons.buttons)}` };
|
|
9999
10322
|
delete routed.buttons;
|
|
@@ -11208,6 +11531,11 @@ export class Daemon extends EventEmitter {
|
|
|
11208
11531
|
this.logger.warn({ warning: launchWarning }, "Backend launch fell back");
|
|
11209
11532
|
this.emit("backend_launch_warning", { name: this.name, message: launchWarning });
|
|
11210
11533
|
}
|
|
11534
|
+
// #1811: what the launch left out and why (an effort this CLI or model does not take) — the Log tab, not the chat.
|
|
11535
|
+
for (const note of this.backend.consumeQuietLaunchNotes?.() ?? []) {
|
|
11536
|
+
this.logger.info({ note }, "Launch note");
|
|
11537
|
+
this.emit("backend_launch_warning", { name: this.name, message: note, quiet: true });
|
|
11538
|
+
}
|
|
11211
11539
|
// Ensure tmux session exists (may have been destroyed if all windows died)
|
|
11212
11540
|
await TmuxManager.ensureSession(this.tmuxSessionName);
|
|
11213
11541
|
if (this.stormWindow?.observeServerAlive(await TmuxManager.getServerPid(this.tmuxSessionName))) {
|
|
@@ -11914,16 +12242,29 @@ export class Daemon extends EventEmitter {
|
|
|
11914
12242
|
respond(null, `Not a git repository: ${source}`);
|
|
11915
12243
|
return;
|
|
11916
12244
|
}
|
|
11917
|
-
|
|
11918
|
-
|
|
11919
|
-
const
|
|
11920
|
-
|
|
12245
|
+
mkdirSync(join(this.instanceDir, "repos"), { recursive: true });
|
|
12246
|
+
// Only a fresh direct child of a real repos/ directory (never through a symlinked repos/, never an existing path).
|
|
12247
|
+
const target = checkoutTarget(this.instanceDir, source, branch);
|
|
12248
|
+
if (!target.ok) {
|
|
12249
|
+
respond(null, `checkout_repo: ${target.reason}`);
|
|
12250
|
+
return;
|
|
12251
|
+
}
|
|
12252
|
+
const worktreePath = target.path;
|
|
11921
12253
|
try {
|
|
11922
|
-
// Resolve branch/ref to verify it exists.
|
|
11923
|
-
//
|
|
11924
|
-
|
|
11925
|
-
await execFileAsync("git", ["
|
|
12254
|
+
// Resolve branch/ref to verify it exists. `--end-of-options` keeps git from ever reading branch as an option
|
|
12255
|
+
// flag (defense in depth on top of the regex above). Not `--`: rev-parse then reads branch as a path, and
|
|
12256
|
+
// `--verify` fails for every ref ("Needed a single revision"), which broke checkout_repo entirely.
|
|
12257
|
+
await execFileAsync("git", ["rev-parse", "--verify", "--end-of-options", `${branch}^{commit}`], { cwd: source });
|
|
12258
|
+
await execFileAsync("git", ["worktree", "add", "--detach", worktreePath, "--end-of-options", branch], { cwd: source });
|
|
11926
12259
|
const { stdout: commitHash } = await execFileAsync("git", ["rev-parse", "--short", "HEAD"], { cwd: worktreePath });
|
|
12260
|
+
// Recorded so release_repo can tell this instance's checkout of this repository from anything else.
|
|
12261
|
+
try {
|
|
12262
|
+
const { stdout: common } = await execFileAsync("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], { cwd: worktreePath });
|
|
12263
|
+
const root = reposRoot(this.instanceDir);
|
|
12264
|
+
if (root.ok)
|
|
12265
|
+
writeCheckouts(root.path, { ...readCheckouts(root.path), [worktreePath]: common.trim() });
|
|
12266
|
+
}
|
|
12267
|
+
catch { /* unrecorded: release still requires a listed linked worktree */ }
|
|
11927
12268
|
respond({ path: worktreePath, branch, source, commit: commitHash.trim() });
|
|
11928
12269
|
}
|
|
11929
12270
|
catch (err) {
|
|
@@ -11931,26 +12272,50 @@ export class Daemon extends EventEmitter {
|
|
|
11931
12272
|
}
|
|
11932
12273
|
}
|
|
11933
12274
|
async handleReleaseRepo(args, respond) {
|
|
11934
|
-
|
|
11935
|
-
|
|
11936
|
-
|
|
11937
|
-
if (!
|
|
11938
|
-
respond(null, `Cannot release
|
|
12275
|
+
// Containment first (real paths, strictly inside this instance's repos/), then proof it is a git worktree.
|
|
12276
|
+
// Nothing that fails either check is ever removed.
|
|
12277
|
+
const candidate = releaseCandidate(this.instanceDir, args.path);
|
|
12278
|
+
if (!candidate.ok) {
|
|
12279
|
+
respond(null, `Cannot release: ${candidate.reason}`);
|
|
11939
12280
|
return;
|
|
11940
12281
|
}
|
|
12282
|
+
const root = reposRoot(this.instanceDir);
|
|
12283
|
+
if (!root.ok) {
|
|
12284
|
+
respond(null, `Cannot release: ${root.reason}`);
|
|
12285
|
+
return;
|
|
12286
|
+
}
|
|
12287
|
+
const { execFile: execFileCb } = await import("node:child_process");
|
|
12288
|
+
const { promisify } = await import("node:util");
|
|
12289
|
+
const execFileAsync = promisify(execFileCb);
|
|
12290
|
+
const git = async (gitArgs, cwd) => (await execFileAsync("git", gitArgs, { cwd })).stdout;
|
|
12291
|
+
const worktree = await verifyWorktree(root.path, candidate.path, git);
|
|
12292
|
+
if (!worktree.ok) {
|
|
12293
|
+
respond(null, `Cannot release: ${worktree.reason}`);
|
|
12294
|
+
return;
|
|
12295
|
+
}
|
|
12296
|
+
const repoPath = candidate.path;
|
|
11941
12297
|
try {
|
|
11942
|
-
|
|
11943
|
-
const { promisify } = await import("node:util");
|
|
11944
|
-
const execFileAsync = promisify(execFileCb);
|
|
11945
|
-
await execFileAsync("git", ["worktree", "remove", "--force", repoPath]);
|
|
12298
|
+
await git(["--git-dir", worktree.commonDir, "worktree", "remove", "--force", repoPath], worktree.commonDir);
|
|
11946
12299
|
}
|
|
11947
12300
|
catch {
|
|
11948
|
-
// Fallback
|
|
12301
|
+
// Fallback for a verified worktree only: remove it, then let its repository forget it.
|
|
11949
12302
|
try {
|
|
11950
12303
|
rmSync(repoPath, { recursive: true, force: true });
|
|
11951
12304
|
}
|
|
11952
12305
|
catch { /* best effort */ }
|
|
12306
|
+
try {
|
|
12307
|
+
await git(["--git-dir", worktree.commonDir, "worktree", "prune"], worktree.commonDir);
|
|
12308
|
+
}
|
|
12309
|
+
catch { /* best effort */ }
|
|
12310
|
+
}
|
|
12311
|
+
try {
|
|
12312
|
+
const records = readCheckouts(root.path);
|
|
12313
|
+
if (repoPath in records) {
|
|
12314
|
+
delete records[repoPath];
|
|
12315
|
+
writeCheckouts(root.path, records);
|
|
12316
|
+
}
|
|
11953
12317
|
}
|
|
12318
|
+
catch { /* the worktree is gone; a stale record only refuses a later, different repo at this path */ }
|
|
11954
12319
|
respond({ released: true, path: repoPath });
|
|
11955
12320
|
}
|
|
11956
12321
|
buildSnapshotPrompt() {
|