@songsid/agend 2.1.12 → 2.2.0-alpha.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 +2 -2
- package/README.zh-TW.md +2 -2
- 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/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/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 +83 -7
- package/dist/backend/kiro.js +418 -91
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +45 -3
- package/dist/backend/types.js.map +1 -1
- 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.js +225 -127
- 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 +89 -4
- package/dist/daemon.js +661 -77
- 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-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-level-config.d.ts +2 -2
- package/dist/fleet-level-config.js +6 -1
- package/dist/fleet-level-config.js.map +1 -1
- package/dist/fleet-manager.d.ts +293 -12
- package/dist/fleet-manager.js +2364 -449
- package/dist/fleet-manager.js.map +1 -1
- package/dist/host-memory.d.ts +4 -0
- package/dist/host-memory.js.map +1 -1
- package/dist/instance-config-impact.js +5 -0
- 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 +150 -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/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 +6 -2
- package/dist/quickstart.js.map +1 -1
- package/dist/scheduler/db.d.ts +7 -1
- package/dist/scheduler/db.js +38 -0
- 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 +110 -0
- package/dist/service-activation.js +302 -0
- package/dist/service-activation.js.map +1 -0
- package/dist/service-installer.d.ts +7 -0
- package/dist/service-installer.js +7 -4
- package/dist/service-installer.js.map +1 -1
- 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 +175 -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 +133 -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 +197 -32
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-wizard.js +3 -0
- 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/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 +35 -5
- package/dist/tmux-control.js +291 -57
- 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 +191 -58
- 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-render.js +478 -0
- package/dist/ui/chat-store.js +289 -0
- package/dist/ui/chat-strings.js +69 -0
- package/dist/ui/chat-thread.js +209 -0
- package/dist/ui/chat-tour.js +116 -0
- package/dist/ui/fleet-org.js +142 -0
- package/dist/ui/panel-chat.js +418 -0
- package/dist/ui/panel-fleet.js +413 -0
- package/dist/ui/panel-needs.js +202 -0
- package/dist/ui/panel-settings.js +750 -0
- package/dist/ui/preview.js +266 -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 +652 -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 +344 -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 +676 -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 +130 -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 +61 -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 +51 -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-install.d.ts +71 -0
- package/dist/update-install.js +162 -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 +71 -14
- package/dist/web-api.js +492 -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-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/package.json +8 -5
- package/scripts/preinstall-guard.cjs +36 -0
- package/dist/ui/dashboard.html +0 -774
- package/dist/ui/settings.html +0 -2165
- package/dist/ui/view.html +0 -1139
package/dist/backend/kiro.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { measureSyncWork } from "../sync-work-attribution.js";
|
|
2
2
|
import { EFFORT_CAPABILITIES } from "./effort-metadata.js";
|
|
3
|
-
import { join } from "node:path";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
4
5
|
import { getAgendHome } from "../paths.js";
|
|
5
|
-
import { credentialHomeSpec, credentialProfileHome, prepareCredentialProfileHome, resolveCredentialProfile, } from "./credential-profile.js";
|
|
6
|
+
import { credentialHomeSpec, credentialProfileHome, credentialProfileStoreHome, prepareCredentialProfileHome, resolveCredentialProfile, } from "./credential-profile.js";
|
|
7
|
+
import { kiroAgentName, kiroFleetTag, writeKiroAgent, removeKiroAgent, writeSharedKiroMcpEntries, removeSharedKiroMcpEntries, writeTaggedKiroSteering, removeTaggedKiroSteering, } from "./kiro-agent.js";
|
|
8
|
+
import { resolveKiroIdentity, listKiroV1Sessions, listKiroV2Sessions, confirmKiroAgentSwitch, kiroAgentConfirmed, forgetKiroIdentity, kiroIdentityNeedsStore, kiroCanonicalDirectory, KiroIdentityError, } from "./kiro-identity.js";
|
|
9
|
+
import { readKiroLedger } from "./kiro-engine-ledger.js";
|
|
6
10
|
import { execFileSync } from "node:child_process";
|
|
7
|
-
import {
|
|
11
|
+
import { writeFileSync, chmodSync, statSync } from "node:fs";
|
|
8
12
|
import { UnsupportedCliError, resolveBinary, shellQuote, validateEffort, validateModel, warnIfModelMismatch } from "./types.js";
|
|
9
13
|
import { PIE_CLASS } from "../tui-glyphs.js";
|
|
10
14
|
import { KIRO_EXPIRED_LOGIN_SCREEN } from "../login-flows.js";
|
|
11
15
|
import { t } from "../locale.js";
|
|
12
16
|
import { recordKiroLaunch } from "./kiro-engine-ledger.js";
|
|
13
|
-
import { resolveKiroV3Resume } from "./kiro-v3-identity.js";
|
|
17
|
+
import { forgetKiroV3Identity, resolveKiroV3Resume } from "./kiro-v3-identity.js";
|
|
14
18
|
// Kiro CLI feature gates. These are deliberately separate: the flags shipped
|
|
15
19
|
// in different releases, so one broad "old Kiro" check would still crash some
|
|
16
20
|
// supported versions with an unknown argument. Every row below was read from
|
|
@@ -26,18 +30,98 @@ export const KIRO_LEGACY_UI_MIN = "1.27.0";
|
|
|
26
30
|
export const KIRO_EFFORT_FLAG_MIN = "2.6.0";
|
|
27
31
|
/** Oldest kiro-cli AgEnD claims: older ones still launch, with a warning. */
|
|
28
32
|
export const KIRO_SUPPORTED_MIN = "2.21.0";
|
|
33
|
+
/**
|
|
34
|
+
* Lowest version whose `--agent` and `--resume-id` the per-instance agent and conversation (#906) were verified on
|
|
35
|
+
* (2.21.0 and 2.28.0, docs/design/kiro-per-instance-agent.md). Below it an instance launches as before.
|
|
36
|
+
*/
|
|
37
|
+
export const KIRO_INSTANCE_AGENT_MIN = "2.21.0";
|
|
29
38
|
/**
|
|
30
39
|
* Newest kiro-cli run live under AgEnD. Above it the launch flags come from
|
|
31
40
|
* the binary's own --help instead of the version table, and the operator is
|
|
32
41
|
* told the version is unverified.
|
|
33
42
|
*/
|
|
34
43
|
export const KIRO_TESTED_MAX = "2.27.0";
|
|
44
|
+
/**
|
|
45
|
+
* kiro-cli versions, per TUI front-end, whose mid-turn steering AgEnD drives (#1405). Only kiro's TUI steers — typed
|
|
46
|
+
* input while a turn runs is injected into it ("steer", the default) or held for its end ("queue", Ctrl+S toggles); the
|
|
47
|
+
* legacy UI swallows it. A version/front-end is listed once a live run of it — a real account, a steer and a
|
|
48
|
+
* queued message mid-tool — has been captured (tests/fixtures/kiro-steer-1405, 2026-10-08: 2.27.1 `--tui
|
|
49
|
+
* --agent-engine=v2` and `--v3`, 2.28.0 `--tui --agent-engine=v2`; identical rows on all three). Any other version,
|
|
50
|
+
* 2.28.0's v3, the legacy UI and an undetected version all deliver a steer as an ordinary message after the turn.
|
|
51
|
+
*/
|
|
52
|
+
export const KIRO_STEER_VERIFIED = {
|
|
53
|
+
"2.27.1": ["tui", "v3"],
|
|
54
|
+
"2.28.0": ["tui"],
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* The TUI composer's interrupt mode, read off its own row: the LAST row starting at column 0 with `›` (transcript user
|
|
58
|
+
* rows are indented), below which only blank rows or right-aligned hints (`/copy to clipboard`) may follow. Its text is
|
|
59
|
+
* the empty composer's placeholder (tui.js, identical in 2.21.0, 2.27.1 and 2.28.0; 2.21.0 shows no elapsed time):
|
|
60
|
+
*
|
|
61
|
+
* `› Kiro is working · 12s · Type to steer · Ctrl+S to queue` → "steer"
|
|
62
|
+
* `› Kiro is working · 12s · Type to queue · Ctrl+S to steer` → "queue" (also `· Type to queue` alone: a spec task run)
|
|
63
|
+
* `› ask a question or describe a task ↵` → "idle" (exactly; also plan mode's and tangent's
|
|
64
|
+
* complete forms — never a prefix of typed text)
|
|
65
|
+
*
|
|
66
|
+
* Any other text on the composer's row is typed text: "text" — positive evidence the box holds something. The goal,
|
|
67
|
+
* editing, initializing, spec-description and shell placeholders are other modes, and the ASCII glyph set (`.`/`enter`,
|
|
68
|
+
* never seen on a real pane of ours) is not read: null, like a screen with no composer row (a dialog) — null is never
|
|
69
|
+
* evidence of either an empty or a full box. The toggle key's label is whatever the user bound; it is read past, never
|
|
70
|
+
* pressed.
|
|
71
|
+
*/
|
|
72
|
+
function readKiroComposer(pane) {
|
|
73
|
+
const rows = pane.split("\n").map(row => row.replace(/\s+$/, ""));
|
|
74
|
+
let i = rows.length - 1;
|
|
75
|
+
while (i >= 0 && (rows[i] === "" || /^[ \t]{20,}\S/.test(rows[i])))
|
|
76
|
+
i--;
|
|
77
|
+
// Typed text of more than one line continues below the `›` row, each row indented two spaces (live, 2.27.1 and
|
|
78
|
+
// 2.28.0, TUI v2 and v3): the composer starts at the `›` row above them.
|
|
79
|
+
let continued = 0;
|
|
80
|
+
while (i >= 0 && /^ {2,19}\S/.test(rows[i])) {
|
|
81
|
+
i--;
|
|
82
|
+
continued++;
|
|
83
|
+
}
|
|
84
|
+
const row = rows[i];
|
|
85
|
+
if (row === undefined || !/^›[ \t]+\S/.test(row))
|
|
86
|
+
return null;
|
|
87
|
+
// A placeholder is one row: with continuation rows below it, this is typed text — unless its first row is another
|
|
88
|
+
// mode's placeholder, which is then not ours to read.
|
|
89
|
+
if (continued > 0) {
|
|
90
|
+
if (/^›[ \t]+(?:Kiro is working\b|ask a question or describe a task\b|Goal (?:Active|Paused):|Editing queued message \d|Initializing\b|describe what "|running shell command\b)/.test(row))
|
|
91
|
+
return null;
|
|
92
|
+
return { mode: "text", text: row.replace(/^›[ \t]+/, "") };
|
|
93
|
+
}
|
|
94
|
+
const working = String.raw `^›[ \t]+Kiro is working(?:[ \t]+·[ \t]+[^·]+?)?[ \t]+·[ \t]+`;
|
|
95
|
+
const text = row.replace(/^›[ \t]+/, "");
|
|
96
|
+
if (new RegExp(`${working}Type to steer[ \\t]+·[ \\t]+[^·]+?[ \\t]+to queue$`).test(row))
|
|
97
|
+
return { mode: "steer", text };
|
|
98
|
+
if (new RegExp(`${working}Type to queue(?:[ \\t]+·[ \\t]+[^·]+?[ \\t]+to steer)?$`).test(row))
|
|
99
|
+
return { mode: "queue", text };
|
|
100
|
+
const idle = String.raw `^›[ \t]+ask a question or describe a task`;
|
|
101
|
+
if (new RegExp(`${idle}[ \\t]+↵$`).test(row)
|
|
102
|
+
|| new RegExp(`${idle}[ \\t]+↵[ \\t]+·[ \\t]+exit plan mode: shift\\+tab$`).test(row)
|
|
103
|
+
|| new RegExp(`${idle}[ \\t]+·[ \\t]+/tangent to go back[ \\t]+·[ \\t]+/tangent ls to view$`).test(row))
|
|
104
|
+
return { mode: "idle", text };
|
|
105
|
+
// Other placeholders (and anything the ASCII glyph set paints) are not typed text.
|
|
106
|
+
if (/^›[ \t]+(?:Kiro is working\b|Goal (?:Active|Paused):|Editing queued message \d|Initializing\b|describe what "|running shell command\b|ask a question or describe a task (?:\.|enter\b))/.test(row))
|
|
107
|
+
return null;
|
|
108
|
+
return { mode: "text", text };
|
|
109
|
+
}
|
|
110
|
+
export function readKiroSteerComposer(pane) {
|
|
111
|
+
return readKiroComposer(pane)?.mode ?? null;
|
|
112
|
+
}
|
|
113
|
+
/** The typed text on the composer's row when it reads "text" (its first row, as kiro paints it); else null. */
|
|
114
|
+
export function readKiroComposerText(pane) {
|
|
115
|
+
const c = readKiroComposer(pane);
|
|
116
|
+
return c?.mode === "text" ? c.text : null;
|
|
117
|
+
}
|
|
35
118
|
const UNKNOWN_KIRO_COMPATIBILITY = {
|
|
36
119
|
supportsLegacyUi: false,
|
|
37
120
|
supportsTui: false,
|
|
38
121
|
supportsV3: false,
|
|
39
122
|
agentEngines: null,
|
|
40
123
|
supportsEffortFlag: false,
|
|
124
|
+
supportsInstanceAgent: false,
|
|
41
125
|
source: "unknown",
|
|
42
126
|
};
|
|
43
127
|
const compatibilityCache = new Map();
|
|
@@ -346,6 +430,7 @@ function compatibilityFromVersion(version, parsed) {
|
|
|
346
430
|
: has("2.3.0") ? ["rust", "kas"]
|
|
347
431
|
: null,
|
|
348
432
|
supportsEffortFlag: has(KIRO_EFFORT_FLAG_MIN),
|
|
433
|
+
supportsInstanceAgent: has(KIRO_INSTANCE_AGENT_MIN),
|
|
349
434
|
source: "version",
|
|
350
435
|
};
|
|
351
436
|
}
|
|
@@ -359,6 +444,10 @@ function compatibilityFromHelp(version, help) {
|
|
|
359
444
|
supportsV3: helpAdvertisesFlag(help, "--v3"),
|
|
360
445
|
agentEngines: parseKiroAgentEngines(help),
|
|
361
446
|
supportsEffortFlag: helpAdvertisesFlag(help, "--effort"),
|
|
447
|
+
// The flags are listed long before 2.21, but the behaviour #906 relies on was verified from 2.21 on: an unknown or
|
|
448
|
+
// older version keeps today's command.
|
|
449
|
+
supportsInstanceAgent: helpAdvertisesFlag(help, "--agent") && helpAdvertisesFlag(help, "--resume-id")
|
|
450
|
+
&& (() => { const v = parseSemver(version); return !!v && versionAtLeast(v, KIRO_INSTANCE_AGENT_MIN); })(),
|
|
362
451
|
source: "help",
|
|
363
452
|
};
|
|
364
453
|
}
|
|
@@ -401,14 +490,78 @@ function nextPatch(version) {
|
|
|
401
490
|
const [major, minor, patch] = parseSemver(version);
|
|
402
491
|
return `${major}.${minor}.${patch + 1}`;
|
|
403
492
|
}
|
|
493
|
+
/** Binary generations already told they cannot isolate (once each). */
|
|
494
|
+
const warnedNoInstanceAgentKeys = new Set();
|
|
495
|
+
/** Instances already told about an untagged steering file (once each). */
|
|
496
|
+
const warnedUntaggedSteering = new Set();
|
|
497
|
+
/** The classic (v1) conversation store an instance launches with: its credential profile's, else the shared one. */
|
|
498
|
+
export function kiroV1DbPath(credentialProfile) {
|
|
499
|
+
const home = credentialProfile
|
|
500
|
+
? credentialProfileStoreHome(getAgendHome(), "kiro-cli", credentialProfile)
|
|
501
|
+
: join(process.env.XDG_DATA_HOME || join(homedir(), ".local", "share"), "kiro-cli");
|
|
502
|
+
return join(home, "data.sqlite3");
|
|
503
|
+
}
|
|
504
|
+
/** The TUI (v2) session files: `<KIRO_HOME or ~/.kiro>/sessions/cli` — not per credential profile. */
|
|
505
|
+
export function kiroV2SessionsDir() {
|
|
506
|
+
return join(process.env.KIRO_HOME?.trim() || join(homedir(), ".kiro"), "sessions", "cli");
|
|
507
|
+
}
|
|
404
508
|
/**
|
|
405
|
-
*
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
* conversation lives in its engine's store — classic sqlite, V2 JSON, V3 KAS —
|
|
409
|
-
* and moving between them forks it one way, so a launch AgEnD cannot pin to
|
|
410
|
-
* the instance's own engine is refused, never run on whatever kiro defaults to.
|
|
509
|
+
* Adoption evidence (#906 §2): the engine ledger shows this instance launched here — same directory, credential
|
|
510
|
+
* profile and engine — before #906 (no "--agent" in that launch). A new instance has no such record and starts fresh
|
|
511
|
+
* instead of taking a sibling's conversation.
|
|
411
512
|
*/
|
|
513
|
+
export function kiroLaunchedHereBefore(instance, workingDirectory, credentialProfile, engine, ledgerPath) {
|
|
514
|
+
const entry = readKiroLedger(ledgerPath)[instance];
|
|
515
|
+
if (!entry || resolve(entry.workingDirectory) !== resolve(workingDirectory) || entry.credentialProfile !== credentialProfile)
|
|
516
|
+
return false;
|
|
517
|
+
return entry.lastLaunch.ui === (engine === "v1" ? "legacy" : "tui") && !entry.lastLaunch.flags.includes("--agent");
|
|
518
|
+
}
|
|
519
|
+
/** The legacy UI's prompt row: an optional `[agent]`, the context percentage, an optional mode glyph, the marker. */
|
|
520
|
+
const LEGACY_PROMPT_ROW = /^\s*(?:\[([^\]]+)\]\s*)?\d+%\s*(?:[^\s\d%!❯>]{1,2}\s+)?(?:!\s?[❯>]|❯|>)/;
|
|
521
|
+
/** A TUI status row: `<agent> · <model> · …`. */
|
|
522
|
+
const TUI_STATUS_ROW = /^\s*(\S+) · /;
|
|
523
|
+
const RULE_ROW = /^[\s─━│┃╭╮╰╯┌┐└┘]*$/;
|
|
524
|
+
/** The right-aligned hint under the TUI input row: far right, a slash command or two. */
|
|
525
|
+
const TUI_HINT_ROW = /^\s{20,}\/[\w-]+(?: [\w-]+)*(?: · \/[\w-]+(?: [\w-]+)*)*$/;
|
|
526
|
+
/**
|
|
527
|
+
* The agent the live layout shows (#906 §3) — never a name quoted in the conversation above it:
|
|
528
|
+
* - legacy: the pane's last non-empty row, only when it is the prompt row; `[name]` on it, or the default agent;
|
|
529
|
+
* - TUI / v3: the status row directly above the input row (the last `›` row; earlier `›` rows are the user's past
|
|
530
|
+
* messages, which sit above it), skipping rule rows.
|
|
531
|
+
* Null when the layout cannot be read.
|
|
532
|
+
*/
|
|
533
|
+
export function readActiveKiroAgent(pane, ui) {
|
|
534
|
+
const rows = pane.split("\n").map(r => r.replace(/\s+$/, ""));
|
|
535
|
+
if (ui === "legacy") {
|
|
536
|
+
const last = [...rows].reverse().find(r => r.trim() !== "");
|
|
537
|
+
const m = last ? LEGACY_PROMPT_ROW.exec(last) : null;
|
|
538
|
+
return m ? (m[1] ?? "kiro_default") : null;
|
|
539
|
+
}
|
|
540
|
+
let input = -1;
|
|
541
|
+
for (let i = rows.length - 1; i >= 0; i--)
|
|
542
|
+
if (/^\s*›/.test(rows[i])) {
|
|
543
|
+
input = i;
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
546
|
+
if (input < 0)
|
|
547
|
+
return null;
|
|
548
|
+
// The live bottom layout ends with the input row: below it only blank or rule rows and the right-aligned hint
|
|
549
|
+
// (`/copy to clipboard`, `/sessions to resume · …`). Anything else — a modal, a panel, output — means the pair
|
|
550
|
+
// above it is not the live one (#1416 review).
|
|
551
|
+
for (let i = input + 1; i < rows.length; i++) {
|
|
552
|
+
const row = rows[i];
|
|
553
|
+
if (row.trim() === "" || RULE_ROW.test(row) || TUI_HINT_ROW.test(row))
|
|
554
|
+
continue;
|
|
555
|
+
return null;
|
|
556
|
+
}
|
|
557
|
+
for (let i = input - 1; i >= 0; i--) {
|
|
558
|
+
if (RULE_ROW.test(rows[i]))
|
|
559
|
+
continue;
|
|
560
|
+
const m = TUI_STATUS_ROW.exec(rows[i]);
|
|
561
|
+
return m ? m[1] : null;
|
|
562
|
+
}
|
|
563
|
+
return null;
|
|
564
|
+
}
|
|
412
565
|
export function planKiroLaunch(ui, compat) {
|
|
413
566
|
const version = compat.version ?? "of unknown version";
|
|
414
567
|
if (ui === "v3")
|
|
@@ -539,6 +692,46 @@ export class KiroBackend {
|
|
|
539
692
|
activeTrustAll = true;
|
|
540
693
|
/** Version-gate notice for the launch just built (consumeLaunchWarning). */
|
|
541
694
|
launchWarning = null;
|
|
695
|
+
/**
|
|
696
|
+
* What this launch attempt resumes and as which agent (#906), resolved once per attempt in writeConfig — it claims
|
|
697
|
+
* conversations and records fresh starts — and read by the buildCommand that follows it.
|
|
698
|
+
*/
|
|
699
|
+
launchPlan = null;
|
|
700
|
+
/** The plan of the command last built: what agentSwitch() works from. */
|
|
701
|
+
activePlan = null;
|
|
702
|
+
preparedV2Store = null;
|
|
703
|
+
storePreparation = 0;
|
|
704
|
+
storeKey(config) {
|
|
705
|
+
return JSON.stringify([config.instanceName, config.workingDirectory, kiroCanonicalDirectory(config.workingDirectory), config.kiroUi,
|
|
706
|
+
resolveCredentialProfile(config.backendOptions), !!config.skipResume, getAgendHome(), kiroV2SessionsDir(), kiroCanonicalDirectory(kiroV2SessionsDir())]);
|
|
707
|
+
}
|
|
708
|
+
readPreparedV2Store(config) {
|
|
709
|
+
if (this.preparedV2Store?.key !== this.storeKey(config)) {
|
|
710
|
+
throw new KiroIdentityError("v2 session discovery was not prepared for this launch");
|
|
711
|
+
}
|
|
712
|
+
return this.preparedV2Store.store;
|
|
713
|
+
}
|
|
714
|
+
/** Metadata only: identity claims/config writes remain synchronous, after
|
|
715
|
+
* the daemon rechecks its launch admission following this await. */
|
|
716
|
+
async prepareLaunch(config) {
|
|
717
|
+
const preparation = ++this.storePreparation;
|
|
718
|
+
this.preparedV2Store = null;
|
|
719
|
+
if (!config || config.kiroUi !== "tui")
|
|
720
|
+
return;
|
|
721
|
+
if (!this.fixedCompatibility)
|
|
722
|
+
this.compatibility = cachedKiroCliCompatibility(this.binaryPath).compatibility;
|
|
723
|
+
const key = this.storeKey(config);
|
|
724
|
+
const plan = planKiroLaunch("tui", this.compatibility);
|
|
725
|
+
if (plan.kind !== "launch" || !plan.flags.includes("--agent-engine=v2") || !this.compatibility.supportsInstanceAgent)
|
|
726
|
+
return;
|
|
727
|
+
const opts = { instance: config.instanceName, engine: "v2", workingDirectory: config.workingDirectory,
|
|
728
|
+
credentialProfile: resolveCredentialProfile(config.backendOptions), skipResume: config.skipResume, agendHome: getAgendHome() };
|
|
729
|
+
if (kiroIdentityNeedsStore(opts)) {
|
|
730
|
+
const store = await listKiroV2Sessions(config.workingDirectory, kiroV2SessionsDir());
|
|
731
|
+
if (preparation === this.storePreparation && key === this.storeKey(config))
|
|
732
|
+
this.preparedV2Store = { key, store };
|
|
733
|
+
}
|
|
734
|
+
}
|
|
542
735
|
constructor(instanceDir, compatibility) {
|
|
543
736
|
this.instanceDir = instanceDir;
|
|
544
737
|
this.binaryPath = resolveBinary("kiro-cli");
|
|
@@ -577,6 +770,22 @@ export class KiroBackend {
|
|
|
577
770
|
// their ready marker is verified.
|
|
578
771
|
return this.activeUi === "legacy" && this.activeTrustAll;
|
|
579
772
|
}
|
|
773
|
+
/** #1405: the TUI front-end this instance was launched with, on a version listed in KIRO_STEER_VERIFIED. */
|
|
774
|
+
supportsSteer() {
|
|
775
|
+
if (this.activeUi === "legacy")
|
|
776
|
+
return false;
|
|
777
|
+
// compatibility.version is kiro-cli's own `--version` line ("kiro-cli 2.27.1").
|
|
778
|
+
const version = parseSemver(this.compatibility.version)?.join(".");
|
|
779
|
+
return version !== undefined && Object.hasOwn(KIRO_STEER_VERIFIED, version)
|
|
780
|
+
&& KIRO_STEER_VERIFIED[version].includes(this.activeUi);
|
|
781
|
+
}
|
|
782
|
+
/** #1405: the TUI composer's mode; never read on the legacy UI, whose prompt row has no such mode. */
|
|
783
|
+
readSteerComposer(pane) {
|
|
784
|
+
return this.activeUi === "legacy" ? null : readKiroSteerComposer(pane);
|
|
785
|
+
}
|
|
786
|
+
readSteerComposerText(pane) {
|
|
787
|
+
return this.activeUi === "legacy" ? null : readKiroComposerText(pane);
|
|
788
|
+
}
|
|
580
789
|
/**
|
|
581
790
|
* Live evidence (kiro-cli 2.21.0, 2026-09-03): `--resume` prints nothing
|
|
582
791
|
* until the conversation comes back from the backend ("Picking up where we
|
|
@@ -647,13 +856,21 @@ export class KiroBackend {
|
|
|
647
856
|
cmd += ` ${flag}`;
|
|
648
857
|
this.noteVersionGate();
|
|
649
858
|
const credentialProfile = resolveCredentialProfile(config.backendOptions);
|
|
859
|
+
// #906: the plan writeConfig resolved for this attempt (a direct buildCommand, as in tests, resolves its own).
|
|
860
|
+
const lp = this.launchPlan && this.launchPlan.cwd === config.workingDirectory && this.launchPlan.skipResume === !!config.skipResume
|
|
861
|
+
? this.launchPlan : this.planInstanceLaunch(config);
|
|
862
|
+
this.launchPlan = null;
|
|
863
|
+
this.activePlan = lp;
|
|
864
|
+
this.activeSpec = lp.mode === "legacy" ? null : this.agentSpec(config);
|
|
865
|
+
this.activeInstance = config.instanceName;
|
|
650
866
|
recordKiroLaunch({
|
|
651
867
|
instance: config.instanceName,
|
|
652
868
|
workingDirectory: config.workingDirectory,
|
|
653
869
|
credentialProfile,
|
|
654
870
|
kiroVersion: this.compatibility.version ?? null,
|
|
655
871
|
ui,
|
|
656
|
-
|
|
872
|
+
// "--agent" marks a launch made after #906: such an instance is never adopted again (kiroLaunchedHereBefore).
|
|
873
|
+
flags: lp.mode !== "legacy" ? [...plan.flags, "--agent"] : plan.flags,
|
|
657
874
|
});
|
|
658
875
|
// Record what is actually being launched for the delivery gate (see
|
|
659
876
|
// dropsEnterWhileBusy): the legacy prompt row exists only under
|
|
@@ -662,30 +879,24 @@ export class KiroBackend {
|
|
|
662
879
|
this.activeTrustAll = config.skipPermissions !== false;
|
|
663
880
|
if (config.skipPermissions !== false)
|
|
664
881
|
cmd += " --trust-all-tools";
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
// launch. Switching profiles also skips resume outright (crash-state
|
|
676
|
-
// resumeDisabled), so this never fires against a store that just changed.
|
|
677
|
-
//
|
|
678
|
-
// V3 is the exception, and resumes only the session it owns, by id: its
|
|
679
|
-
// `--resume` takes the newest conversation in the directory from ANY
|
|
680
|
-
// engine and converts a classic one into a new V3 copy — on every launch.
|
|
681
|
-
// A skipped resume is recorded there too, so the session given up is not
|
|
682
|
-
// taken back on the next launch. See kiro-v3-identity.ts.
|
|
683
|
-
if (ui === "v3") {
|
|
882
|
+
if (lp.mode !== "legacy") {
|
|
883
|
+
// Its own agent: on a fresh start it takes effect at once; on a resume kiro brings back the conversation's saved
|
|
884
|
+
// agent instead (E6), and the daemon switches it on screen (agentSwitch).
|
|
885
|
+
cmd += ` --agent ${shellQuote(lp.agent)}`;
|
|
886
|
+
if (lp.mode === "resume")
|
|
887
|
+
cmd += ` --resume-id ${shellQuote(lp.id)}`;
|
|
888
|
+
}
|
|
889
|
+
else if (ui === "v3") {
|
|
890
|
+
// Legacy mode, V3: it resumes only the session it owns, by id (kiro-v3-identity.ts) — its `--resume` would take
|
|
891
|
+
// the newest conversation in the directory from ANY engine and convert a classic one into a new V3 copy.
|
|
684
892
|
const id = resolveKiroV3Resume(config.instanceName, config.workingDirectory, credentialProfile, { skipResume: config.skipResume });
|
|
685
893
|
if (id)
|
|
686
894
|
cmd += ` --resume-id ${shellQuote(id)}`;
|
|
687
895
|
}
|
|
688
896
|
else if (!config.skipResume) {
|
|
897
|
+
// Legacy mode, classic/TUI: the boolean form — kiro resumes the directory's newest conversation. Not isolated
|
|
898
|
+
// between instances sharing the directory (#1410); an instance launches like this only without the
|
|
899
|
+
// per-instance plan (an old kiro-cli, or a conversation store AgEnD could not read on adoption).
|
|
689
900
|
cmd += " --resume";
|
|
690
901
|
}
|
|
691
902
|
if (config.model) {
|
|
@@ -756,7 +967,8 @@ export class KiroBackend {
|
|
|
756
967
|
if (!warning)
|
|
757
968
|
return;
|
|
758
969
|
warnedVersionGateCacheKeys.add(key);
|
|
759
|
-
this.
|
|
970
|
+
// Appended: the launch's isolation warnings (#906, recorded by writeConfig) must not be overwritten by this one.
|
|
971
|
+
this.addLaunchWarning(warning);
|
|
760
972
|
}
|
|
761
973
|
consumeLaunchWarning() {
|
|
762
974
|
const warning = this.launchWarning;
|
|
@@ -776,36 +988,11 @@ export class KiroBackend {
|
|
|
776
988
|
return true;
|
|
777
989
|
}
|
|
778
990
|
writeConfig(config) {
|
|
779
|
-
//
|
|
780
|
-
//
|
|
781
|
-
//
|
|
782
|
-
// WORKAROUND: kiro-cli ignores the "env" block in mcp.json — the MCP server
|
|
783
|
-
// subprocess inherits the fleet manager's process env, which has a stale
|
|
784
|
-
// AGEND_SOCKET_PATH from whichever daemon wrote to it last.
|
|
785
|
-
// Fix: generate a wrapper script that exports the correct env vars before
|
|
786
|
-
// exec-ing the real MCP server.
|
|
787
|
-
const mcpDir = join(config.workingDirectory, ".kiro", "settings");
|
|
788
|
-
mkdirSync(mcpDir, { recursive: true });
|
|
789
|
-
const mcpConfigPath = join(mcpDir, "mcp.json");
|
|
790
|
-
let mcpConfig = {};
|
|
791
|
-
try {
|
|
792
|
-
mcpConfig = JSON.parse(readFileSync(mcpConfigPath, "utf-8"));
|
|
793
|
-
}
|
|
794
|
-
catch { /* new file */ }
|
|
795
|
-
const servers = (mcpConfig.mcpServers ?? {});
|
|
796
|
-
// Remove stale agend entries whose wrapper scripts no longer exist
|
|
797
|
-
for (const [key, val] of Object.entries(servers)) {
|
|
798
|
-
if (key.startsWith("agend-")) {
|
|
799
|
-
const cmd = val?.command;
|
|
800
|
-
if (typeof cmd === "string" && !existsSync(cmd)) {
|
|
801
|
-
delete servers[key];
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
}
|
|
991
|
+
// WORKAROUND: kiro-cli ignores the "env" block of an MCP server entry — the server subprocess inherits the fleet
|
|
992
|
+
// manager's env, with a stale AGEND_SOCKET_PATH from whichever daemon wrote last. Each server therefore runs
|
|
993
|
+
// through a wrapper script that exports this instance's env and execs the real server.
|
|
805
994
|
for (const [name, entry] of Object.entries(config.mcpServers)) {
|
|
806
|
-
const instanceKey = `${name}-${config.instanceName}`;
|
|
807
995
|
const allEnv = { ...entry.env, AGEND_INSTANCE_NAME: config.instanceName };
|
|
808
|
-
// Write a wrapper script that sets env vars explicitly
|
|
809
996
|
const wrapperPath = join(this.instanceDir, `mcp-wrapper-${name}.sh`);
|
|
810
997
|
const envExports = Object.entries(allEnv)
|
|
811
998
|
.map(([k, v]) => `export ${k}='${String(v).replace(/'/g, "'\\''")}'`)
|
|
@@ -817,25 +1004,166 @@ export class KiroBackend {
|
|
|
817
1004
|
// Re-chmod in case the file already existed with looser permissions (writeFileSync's
|
|
818
1005
|
// mode only applies on create).
|
|
819
1006
|
chmodSync(wrapperPath, 0o700);
|
|
820
|
-
servers[instanceKey] = {
|
|
821
|
-
command: wrapperPath,
|
|
822
|
-
args: [],
|
|
823
|
-
};
|
|
824
1007
|
}
|
|
825
|
-
//
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
1008
|
+
// #906: which conversation this attempt resumes, and as which agent — resolved once, here.
|
|
1009
|
+
const plan = this.planInstanceLaunch(config);
|
|
1010
|
+
this.preparedV2Store = null;
|
|
1011
|
+
this.launchPlan = plan;
|
|
1012
|
+
const spec = this.agentSpec(config);
|
|
1013
|
+
const root = dirname(this.instanceDir);
|
|
1014
|
+
if (plan.mode === "legacy") {
|
|
1015
|
+
// Not isolated (an old kiro-cli, or adoption with an unreadable store): the shared files as before, each
|
|
1016
|
+
// written only where it is free, and removed only by provenance.
|
|
1017
|
+
if (plan.reason)
|
|
1018
|
+
this.addLaunchWarning(plan.reason);
|
|
1019
|
+
this.noteShared("mcp.json", writeSharedKiroMcpEntries(spec));
|
|
1020
|
+
if (config.instructions)
|
|
1021
|
+
this.noteShared("steering", writeTaggedKiroSteering(spec, config.instructions));
|
|
1022
|
+
this.noteShared("mcp.json", removeSharedKiroMcpEntries(spec, root, false));
|
|
1023
|
+
return;
|
|
1024
|
+
}
|
|
1025
|
+
// Throws when a file that is not this instance's agent is in the way: never overwritten, launch refused.
|
|
1026
|
+
writeKiroAgent(spec, config.instructions);
|
|
1027
|
+
if (plan.mode === "resume" && !plan.agentConfirmed) {
|
|
1028
|
+
// The resumed conversation comes back as its saved agent (`--agent` is ignored on resume), so until the switch
|
|
1029
|
+
// is confirmed on screen it gets its AgEnD server and instructions from the shared files (design §3).
|
|
1030
|
+
this.noteShared("mcp.json", writeSharedKiroMcpEntries(spec));
|
|
1031
|
+
if (config.instructions)
|
|
1032
|
+
this.noteShared("steering", writeTaggedKiroSteering(spec, config.instructions));
|
|
1033
|
+
this.noteShared("mcp.json", removeSharedKiroMcpEntries(spec, root, false));
|
|
1034
|
+
return;
|
|
1035
|
+
}
|
|
1036
|
+
// Running as its own agent: nothing of this instance belongs in the shared files any more.
|
|
1037
|
+
this.noteShared("mcp.json", removeSharedKiroMcpEntries(spec, root, true));
|
|
1038
|
+
this.noteShared("steering", removeTaggedKiroSteering(spec));
|
|
1039
|
+
}
|
|
1040
|
+
/** This instance's agent, by its fleet and its own wrapper scripts. */
|
|
1041
|
+
agentSpec(config) {
|
|
1042
|
+
return {
|
|
1043
|
+
workingDirectory: config.workingDirectory,
|
|
1044
|
+
instance: config.instanceName,
|
|
1045
|
+
fleet: kiroFleetTag(getAgendHome()),
|
|
1046
|
+
instanceDir: this.instanceDir,
|
|
1047
|
+
serverNames: Object.keys(config.mcpServers),
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
/** A shared file AgEnD could not bring to the state isolation needs: said, never reported as isolated. */
|
|
1051
|
+
noteShared(file, outcome) {
|
|
1052
|
+
if (outcome === "conflict")
|
|
1053
|
+
this.addLaunchWarning(t("kiro.shared_conflict", file));
|
|
1054
|
+
else if (outcome === "unreadable" || outcome === "failed")
|
|
1055
|
+
this.addLaunchWarning(t("kiro.shared_unreadable", file));
|
|
1056
|
+
else if (outcome === "untagged-legacy" && !warnedUntaggedSteering.has(this.instanceDir)) {
|
|
1057
|
+
warnedUntaggedSteering.add(this.instanceDir);
|
|
1058
|
+
this.addLaunchWarning(t("kiro.untagged_steering"));
|
|
837
1059
|
}
|
|
838
1060
|
}
|
|
1061
|
+
addLaunchWarning(message) {
|
|
1062
|
+
this.launchWarning = this.launchWarning ? `${this.launchWarning}\n${message}` : message;
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* The launch plan of one attempt (#906, design §2/§5): the engine the plan pins, and — when this kiro-cli has
|
|
1066
|
+
* `--agent` and `--resume-id` — the conversation this instance owns and whether it already runs as its agent.
|
|
1067
|
+
* Anything else is legacy mode: today's command, not isolated.
|
|
1068
|
+
*/
|
|
1069
|
+
planInstanceLaunch(config) {
|
|
1070
|
+
const ui = config.kiroUi ?? "legacy";
|
|
1071
|
+
if (!this.fixedCompatibility) {
|
|
1072
|
+
const current = cachedKiroCliCompatibility(this.binaryPath);
|
|
1073
|
+
this.compatibility = current.compatibility;
|
|
1074
|
+
this.compatibilityCacheKey = current.cacheKey;
|
|
1075
|
+
}
|
|
1076
|
+
const plan = planKiroLaunch(ui, this.compatibility);
|
|
1077
|
+
const flags = plan.kind === "launch" ? plan.flags : [];
|
|
1078
|
+
const engine = flags.includes("--agent-engine=v1") ? "v1"
|
|
1079
|
+
: flags.includes("--agent-engine=v2") ? "v2" : ui === "v3" ? "v3" : null;
|
|
1080
|
+
const credentialProfile = resolveCredentialProfile(config.backendOptions);
|
|
1081
|
+
const base = { cwd: config.workingDirectory, skipResume: !!config.skipResume, engine, credentialProfile };
|
|
1082
|
+
const legacy = (reason) => ({ ...base, mode: "legacy", reason, agent: null, agentConfirmed: false });
|
|
1083
|
+
if (plan.kind !== "launch" || this.compatibility.source === "unknown")
|
|
1084
|
+
return legacy(null); // buildCommand refuses
|
|
1085
|
+
if (!this.compatibility.supportsInstanceAgent || !engine) {
|
|
1086
|
+
const key = this.compatibilityCacheKey ?? this.binaryPath;
|
|
1087
|
+
if (warnedNoInstanceAgentKeys.has(key))
|
|
1088
|
+
return legacy(null);
|
|
1089
|
+
warnedNoInstanceAgentKeys.add(key);
|
|
1090
|
+
return legacy(t("kiro.no_instance_agent", this.compatibility.version ?? "?", KIRO_INSTANCE_AGENT_MIN));
|
|
1091
|
+
}
|
|
1092
|
+
const agent = kiroAgentName(config.instanceName, kiroFleetTag(getAgendHome()));
|
|
1093
|
+
const agendHome = getAgendHome();
|
|
1094
|
+
let decision;
|
|
1095
|
+
if (engine === "v3") {
|
|
1096
|
+
// V3 keeps its own identity (kiro-v3-identity.ts); only whether it runs as the agent is recorded here.
|
|
1097
|
+
const id = resolveKiroV3Resume(config.instanceName, config.workingDirectory, credentialProfile, { skipResume: config.skipResume });
|
|
1098
|
+
decision = id
|
|
1099
|
+
? { mode: "resume", id, agentConfirmed: kiroAgentConfirmed(agendHome, config.instanceName, "v3", config.workingDirectory, credentialProfile, id) }
|
|
1100
|
+
: { mode: "fresh" };
|
|
1101
|
+
}
|
|
1102
|
+
else {
|
|
1103
|
+
decision = resolveKiroIdentity({
|
|
1104
|
+
instance: config.instanceName,
|
|
1105
|
+
engine,
|
|
1106
|
+
workingDirectory: config.workingDirectory,
|
|
1107
|
+
credentialProfile,
|
|
1108
|
+
skipResume: config.skipResume,
|
|
1109
|
+
agendHome,
|
|
1110
|
+
readStore: () => engine === "v1"
|
|
1111
|
+
? listKiroV1Sessions(config.workingDirectory, kiroV1DbPath(credentialProfile))
|
|
1112
|
+
: this.readPreparedV2Store(config),
|
|
1113
|
+
launchedBefore: () => kiroLaunchedHereBefore(config.instanceName, config.workingDirectory, credentialProfile, engine),
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
if (decision.mode === "legacy")
|
|
1117
|
+
return legacy(t("kiro.identity_legacy", decision.reason));
|
|
1118
|
+
return decision.mode === "resume"
|
|
1119
|
+
? { ...base, mode: "resume", id: decision.id, agent, agentConfirmed: decision.agentConfirmed, reason: null }
|
|
1120
|
+
: { ...base, mode: "fresh", agent, agentConfirmed: true, reason: null };
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* After a resume as the instance's agent (#906 §3): what the daemon needs to read the active agent off the live
|
|
1124
|
+
* layout and, when it is not ours, switch to it with `/agent swap` and confirm. Null when there is nothing to do.
|
|
1125
|
+
*/
|
|
1126
|
+
agentSwitch() {
|
|
1127
|
+
const plan = this.activePlan;
|
|
1128
|
+
if (!plan || plan.mode !== "resume" || !plan.agent || !plan.id || !plan.engine)
|
|
1129
|
+
return null;
|
|
1130
|
+
const { agent, id, engine, cwd, credentialProfile } = plan;
|
|
1131
|
+
const ui = this.activeUi;
|
|
1132
|
+
return {
|
|
1133
|
+
agent,
|
|
1134
|
+
alreadyConfirmed: plan.agentConfirmed,
|
|
1135
|
+
readActive: (pane) => readActiveKiroAgent(pane, ui),
|
|
1136
|
+
command: `/agent swap ${agent}`,
|
|
1137
|
+
confirm: () => {
|
|
1138
|
+
const warnings = [];
|
|
1139
|
+
if (!this.activeInstance || !confirmKiroAgentSwitch(getAgendHome(), this.activeInstance, engine, cwd, credentialProfile, id)) {
|
|
1140
|
+
warnings.push(t("kiro.switch_unrecorded"));
|
|
1141
|
+
return warnings;
|
|
1142
|
+
}
|
|
1143
|
+
plan.agentConfirmed = true;
|
|
1144
|
+
const spec = this.activeSpec;
|
|
1145
|
+
if (spec) {
|
|
1146
|
+
const mcp = removeSharedKiroMcpEntries(spec, dirname(this.instanceDir), true);
|
|
1147
|
+
if (mcp === "unreadable" || mcp === "failed")
|
|
1148
|
+
warnings.push(t("kiro.shared_unreadable", "mcp.json"));
|
|
1149
|
+
const steering = removeTaggedKiroSteering(spec);
|
|
1150
|
+
if (steering === "failed" || steering === "unreadable")
|
|
1151
|
+
warnings.push(t("kiro.shared_unreadable", "steering"));
|
|
1152
|
+
}
|
|
1153
|
+
return warnings;
|
|
1154
|
+
},
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
/**
|
|
1158
|
+
* An instance running as its own agent reads its instructions from the agent file's prompt (#906). Until a resumed
|
|
1159
|
+
* conversation's switch is confirmed it still runs as its saved agent, reading the steering file (the default).
|
|
1160
|
+
*/
|
|
1161
|
+
instructionsSource() {
|
|
1162
|
+
const plan = this.activePlan;
|
|
1163
|
+
return plan && plan.mode !== "legacy" && plan.agent && plan.agentConfirmed ? `.kiro/agents/${plan.agent}.json (its "prompt" field)` : null;
|
|
1164
|
+
}
|
|
1165
|
+
activeSpec = null;
|
|
1166
|
+
activeInstance = null;
|
|
839
1167
|
getReadyPattern() {
|
|
840
1168
|
// Startup: trust/banner text. Daily prompt: "22% !>" / "8% ❯";
|
|
841
1169
|
// Kiro may insert mode glyphs between them, e.g. "20% λ !>".
|
|
@@ -1138,26 +1466,25 @@ export class KiroBackend {
|
|
|
1138
1466
|
getEffortStrategy() { return EFFORT_CAPABILITIES["kiro-cli"].strategy; }
|
|
1139
1467
|
getEffortLevels() { return [...EFFORT_CAPABILITIES["kiro-cli"].levels]; }
|
|
1140
1468
|
cleanup(config) {
|
|
1141
|
-
//
|
|
1142
|
-
//
|
|
1469
|
+
// By provenance only (#906 §4/§6): the agent file and its .bak when they are this instance's, the shared mcp.json
|
|
1470
|
+
// entries run by this instance's own wrappers, and a steering file carrying this fleet's tag for it. The user's,
|
|
1471
|
+
// another fleet's, and untagged steering from before the tag existed are kept.
|
|
1143
1472
|
try {
|
|
1144
|
-
const
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1473
|
+
const spec = this.agentSpec(config);
|
|
1474
|
+
removeKiroAgent(spec);
|
|
1475
|
+
removeSharedKiroMcpEntries(spec, dirname(this.instanceDir), true);
|
|
1476
|
+
removeTaggedKiroSteering(spec);
|
|
1477
|
+
}
|
|
1478
|
+
catch { /* best effort */ }
|
|
1479
|
+
}
|
|
1480
|
+
/** Delete or replace: forget which conversations this instance owns (they stay in kiro's store). */
|
|
1481
|
+
forget(instanceName) {
|
|
1482
|
+
try {
|
|
1483
|
+
forgetKiroIdentity(getAgendHome(), instanceName);
|
|
1154
1484
|
}
|
|
1155
1485
|
catch { /* best effort */ }
|
|
1156
|
-
// Remove fleet instructions steering file
|
|
1157
1486
|
try {
|
|
1158
|
-
|
|
1159
|
-
if (existsSync(steeringFile))
|
|
1160
|
-
unlinkSync(steeringFile);
|
|
1487
|
+
forgetKiroV3Identity(instanceName, getAgendHome());
|
|
1161
1488
|
}
|
|
1162
1489
|
catch { /* best effort */ }
|
|
1163
1490
|
}
|