@songsid/agend 2.3.2-beta.1 → 2.3.2-beta.10
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/THIRD_PARTY_NOTICES.md +40 -0
- package/dist/agent-cli.js +21 -2
- package/dist/agent-cli.js.map +1 -1
- package/dist/agent-endpoint.js +5 -0
- package/dist/agent-endpoint.js.map +1 -1
- package/dist/antigravity-usage-scan.d.ts +58 -0
- package/dist/antigravity-usage-scan.js +257 -0
- package/dist/antigravity-usage-scan.js.map +1 -0
- package/dist/antigravity-usage-worker.d.ts +1 -0
- package/dist/antigravity-usage-worker.js +10 -0
- package/dist/antigravity-usage-worker.js.map +1 -0
- package/dist/auth-api.js +4 -0
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/kiro-identity.d.ts +64 -0
- package/dist/backend/kiro-identity.js +101 -0
- package/dist/backend/kiro-identity.js.map +1 -1
- package/dist/backend/kiro-retired-model.d.ts +62 -0
- package/dist/backend/kiro-retired-model.js +160 -0
- package/dist/backend/kiro-retired-model.js.map +1 -0
- package/dist/backend/kiro.d.ts +71 -2
- package/dist/backend/kiro.js +352 -11
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +59 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/backend-signin-guide.d.ts +1 -0
- package/dist/backend-signin-guide.js +9 -0
- package/dist/backend-signin-guide.js.map +1 -0
- package/dist/backend-signin-pending.d.ts +10 -0
- package/dist/backend-signin-pending.js +44 -0
- package/dist/backend-signin-pending.js.map +1 -0
- package/dist/browser-backend-signins.d.ts +56 -0
- package/dist/browser-backend-signins.js +189 -0
- package/dist/browser-backend-signins.js.map +1 -0
- package/dist/cache-ledger.d.ts +38 -2
- package/dist/cache-ledger.js +133 -8
- package/dist/cache-ledger.js.map +1 -1
- package/dist/cache-prices.d.ts +2 -1
- package/dist/cache-prices.js +5 -2
- package/dist/cache-prices.js.map +1 -1
- package/dist/cache-service.d.ts +68 -0
- package/dist/cache-service.js +355 -13
- package/dist/cache-service.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +11 -0
- package/dist/channel/adapters/discord.js +71 -14
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/mcp-tools.js +29 -2
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/tool-router.js +2 -1
- package/dist/channel/tool-router.js.map +1 -1
- package/dist/classic-channel-manager.d.ts +11 -0
- package/dist/classic-channel-manager.js +39 -1
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +21 -2
- package/dist/cli.js.map +1 -1
- package/dist/config-validator.d.ts +7 -1
- package/dist/config-validator.js +53 -10
- package/dist/config-validator.js.map +1 -1
- package/dist/config.d.ts +19 -0
- package/dist/config.js +31 -1
- package/dist/config.js.map +1 -1
- package/dist/cpu-quota.d.ts +23 -0
- package/dist/cpu-quota.js +86 -0
- package/dist/cpu-quota.js.map +1 -0
- package/dist/daemon.d.ts +23 -0
- package/dist/daemon.js +106 -7
- package/dist/daemon.js.map +1 -1
- package/dist/dashboard-permissions.d.ts +20 -6
- package/dist/dashboard-permissions.js +58 -9
- package/dist/dashboard-permissions.js.map +1 -1
- package/dist/doctor.js +2 -1
- package/dist/doctor.js.map +1 -1
- package/dist/fleet-manager.d.ts +72 -0
- package/dist/fleet-manager.js +507 -89
- package/dist/fleet-manager.js.map +1 -1
- package/dist/forged-envelope-scan.d.ts +9 -0
- package/dist/forged-envelope-scan.js +30 -5
- package/dist/forged-envelope-scan.js.map +1 -1
- package/dist/general-knowledge/skills/credential-profiles/SKILL.md +5 -2
- package/dist/general-knowledge/skills/kiro-engine-migration/SKILL.md +14 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +24 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +24 -1
- package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +37 -9
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +44 -11
- package/dist/instance-config-impact.js +10 -5
- package/dist/instance-config-impact.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +19 -0
- package/dist/instance-lifecycle.js +55 -12
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/kiro-db-reader.d.ts +5 -0
- package/dist/kiro-db-reader.js +18 -0
- package/dist/kiro-db-reader.js.map +1 -1
- package/dist/kiro-engine-status.d.ts +2 -0
- package/dist/kiro-engine-status.js +9 -0
- package/dist/kiro-engine-status.js.map +1 -1
- package/dist/kiro-migrate.d.ts +49 -0
- package/dist/kiro-migrate.js +105 -0
- package/dist/kiro-migrate.js.map +1 -0
- package/dist/kiro-transcript-lane.d.ts +2 -0
- package/dist/kiro-transcript-lane.js.map +1 -1
- package/dist/kiro-transcript-worker.js +1 -0
- package/dist/kiro-transcript-worker.js.map +1 -1
- package/dist/kiro-tui-forensic.d.ts +7 -0
- package/dist/kiro-tui-forensic.js +110 -0
- package/dist/kiro-tui-forensic.js.map +1 -0
- package/dist/kiro-usage-run.d.ts +7 -0
- package/dist/kiro-usage-run.js +39 -0
- package/dist/kiro-usage-run.js.map +1 -0
- package/dist/kiro-usage-scan.d.ts +49 -0
- package/dist/kiro-usage-scan.js +223 -0
- package/dist/kiro-usage-scan.js.map +1 -0
- package/dist/kiro-usage-worker.d.ts +1 -0
- package/dist/kiro-usage-worker.js +10 -0
- package/dist/kiro-usage-worker.js.map +1 -0
- package/dist/kiro-usage.d.ts +58 -0
- package/dist/kiro-usage.js +310 -0
- package/dist/kiro-usage.js.map +1 -0
- package/dist/locale.js +88 -8
- package/dist/locale.js.map +1 -1
- package/dist/log-service.js +1 -1
- package/dist/log-service.js.map +1 -1
- package/dist/login-url.d.ts +4 -0
- package/dist/login-url.js +22 -0
- package/dist/login-url.js.map +1 -0
- package/dist/needs-you-hub.d.ts +2 -1
- package/dist/needs-you-hub.js +1 -1
- package/dist/needs-you-hub.js.map +1 -1
- package/dist/needs-you.d.ts +8 -2
- package/dist/needs-you.js +6 -0
- package/dist/needs-you.js.map +1 -1
- package/dist/notice-delivery.d.ts +16 -0
- package/dist/notice-delivery.js +35 -0
- package/dist/notice-delivery.js.map +1 -0
- package/dist/office-share-page.d.ts +16 -0
- package/dist/office-share-page.js +85 -0
- package/dist/office-share-page.js.map +1 -0
- package/dist/office-share-service.d.ts +91 -0
- package/dist/office-share-service.js +176 -0
- package/dist/office-share-service.js.map +1 -0
- package/dist/office-share.d.ts +258 -0
- package/dist/office-share.js +549 -0
- package/dist/office-share.js.map +1 -0
- package/dist/opencode-usage-scan.d.ts +28 -0
- package/dist/opencode-usage-scan.js +92 -0
- package/dist/opencode-usage-scan.js.map +1 -0
- package/dist/opencode-usage-worker.d.ts +1 -0
- package/dist/opencode-usage-worker.js +10 -0
- package/dist/opencode-usage-worker.js.map +1 -0
- package/dist/outbound-handlers.js +22 -2
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +26 -2
- package/dist/outbound-schemas.js +27 -2
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/public-web-gateway.js +7 -1
- package/dist/public-web-gateway.js.map +1 -1
- package/dist/quickstart-api.js +13 -2
- package/dist/quickstart-api.js.map +1 -1
- package/dist/quickstart.js +2 -1
- package/dist/quickstart.js.map +1 -1
- package/dist/remote-card-answer.d.ts +83 -0
- package/dist/remote-card-answer.js +208 -0
- package/dist/remote-card-answer.js.map +1 -0
- package/dist/reply-triggers.d.ts +2 -0
- package/dist/reply-triggers.js +3 -0
- package/dist/reply-triggers.js.map +1 -0
- package/dist/settings-api.d.ts +2 -0
- package/dist/settings-api.js +41 -16
- package/dist/settings-api.js.map +1 -1
- package/dist/settings-change.js +17 -14
- package/dist/settings-change.js.map +1 -1
- package/dist/settings-effect.js +7 -1
- package/dist/settings-effect.js.map +1 -1
- package/dist/settings-instance-patch.js +4 -1
- package/dist/settings-instance-patch.js.map +1 -1
- package/dist/setup-form.d.ts +1 -1
- package/dist/setup-form.js +55 -6
- package/dist/setup-form.js.map +1 -1
- package/dist/setup-host.d.ts +9 -0
- package/dist/setup-host.js +127 -6
- package/dist/setup-host.js.map +1 -1
- package/dist/setup-signin-assets.d.ts +2 -0
- package/dist/setup-signin-assets.js +6 -0
- package/dist/setup-signin-assets.js.map +1 -0
- package/dist/setup-wizard.js +2 -0
- package/dist/setup-wizard.js.map +1 -1
- package/dist/structured-signin-transport.d.ts +8 -0
- package/dist/structured-signin-transport.js +79 -0
- package/dist/structured-signin-transport.js.map +1 -0
- package/dist/structured-signin.d.ts +131 -0
- package/dist/structured-signin.js +388 -0
- package/dist/structured-signin.js.map +1 -0
- package/dist/tool-permissions.js +12 -0
- package/dist/tool-permissions.js.map +1 -1
- package/dist/topic-commands.js +6 -2
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-sources.d.ts +26 -2
- package/dist/transcript-sources.js +103 -40
- package/dist/transcript-sources.js.map +1 -1
- package/dist/turn-reply-guard.d.ts +1 -1
- package/dist/turn-reply-guard.js +1 -1
- package/dist/turn-reply-guard.js.map +1 -1
- package/dist/types.d.ts +28 -8
- package/dist/ui/backend-signin.js +63 -10
- package/dist/ui/chat-strings.js +2 -2
- package/dist/ui/fleet-office-editor.js +14 -9
- package/dist/ui/fleet-office-layout.js +70 -32
- package/dist/ui/fleet-office-model.js +6 -3
- package/dist/ui/fleet-office-overview.js +167 -0
- package/dist/ui/fleet-office-pack.d.ts +7 -2
- package/dist/ui/fleet-office-pack.js +119 -15
- package/dist/ui/fleet-office-skin.js +98 -23
- package/dist/ui/fleet-office-store.js +39 -5
- package/dist/ui/fleet-office-view.js +5 -4
- package/dist/ui/fleet-office-zones.js +172 -12
- package/dist/ui/fleet-office.js +547 -186
- package/dist/ui/fleet-usage.js +19 -15
- package/dist/ui/office-share-dialog.js +145 -0
- package/dist/ui/office-share-page.js +164 -0
- package/dist/ui/panel-chat.js +8 -1
- package/dist/ui/panel-log.js +2 -2
- package/dist/ui/panel-needs.js +4 -4
- package/dist/ui/panel-settings.js +37 -11
- package/dist/ui/settings-dialogs.js +8 -1
- package/dist/ui/settings-guests.js +17 -7
- package/dist/ui/settings-model.js +14 -6
- package/dist/ui/settings-registry.js +4 -0
- package/dist/ui/settings-strings.js +16 -2
- package/dist/ui/shared/app-i18n.js +4 -2
- package/dist/ui/shared/app-shell.js +14 -6
- package/dist/ui/shared/app-stream.js +2 -1
- package/dist/ui/shared/app.css +67 -2
- package/dist/ui/shared/office/cozy.png +0 -0
- package/dist/ui/shared/side-panel.js +95 -0
- package/dist/ui/structured-signin.js +115 -0
- package/dist/usage-report.d.ts +20 -0
- package/dist/usage-report.js +54 -17
- package/dist/usage-report.js.map +1 -1
- package/dist/usage-rollup.d.ts +9 -1
- package/dist/usage-rollup.js +20 -4
- package/dist/usage-rollup.js.map +1 -1
- package/dist/web-api.d.ts +18 -0
- package/dist/web-api.js +201 -0
- package/dist/web-api.js.map +1 -1
- package/dist/web-auth.js +1 -1
- package/dist/web-auth.js.map +1 -1
- package/dist/web-backend-login.d.ts +1 -7
- package/dist/web-backend-login.js +2 -24
- package/dist/web-backend-login.js.map +1 -1
- package/dist/web-office-acts.d.ts +173 -0
- package/dist/web-office-acts.js +285 -0
- package/dist/web-office-acts.js.map +1 -0
- package/dist/web-office-skins.d.ts +3 -2
- package/dist/web-office-skins.js +3 -2
- package/dist/web-office-skins.js.map +1 -1
- package/dist/web-office-store.js +40 -7
- package/dist/web-office-store.js.map +1 -1
- package/dist/web-settings-patch.d.ts +2 -1
- package/dist/web-settings-patch.js +4 -1
- package/dist/web-settings-patch.js.map +1 -1
- package/dist/working-recovery.d.ts +2 -2
- package/dist/working-recovery.js +43 -8
- package/dist/working-recovery.js.map +1 -1
- package/dist/working-state-journal.d.ts +2 -0
- package/dist/working-state-journal.js +16 -1
- package/dist/working-state-journal.js.map +1 -1
- package/package.json +3 -2
- package/templates/windows-shortcuts.ps1 +155 -140
package/dist/backend/kiro.js
CHANGED
|
@@ -5,7 +5,7 @@ import { homedir } from "node:os";
|
|
|
5
5
|
import { getAgendHome } from "../paths.js";
|
|
6
6
|
import { credentialHomeSpec, credentialProfileHome, credentialProfileStoreHome, prepareCredentialProfileHome, resolveCredentialProfile, } from "./credential-profile.js";
|
|
7
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";
|
|
8
|
+
import { resolveKiroIdentity, listKiroV1Sessions, listKiroV2Sessions, confirmKiroAgentSwitch, kiroAgentConfirmed, forgetKiroIdentity, kiroIdentityNeedsStore, kiroRecordedConversation, kiroCanonicalDirectory, KiroIdentityError, kiroEngineFloor, } from "./kiro-identity.js";
|
|
9
9
|
import { readKiroLedger, kiroHasNoLaunchRecord } from "./kiro-engine-ledger.js";
|
|
10
10
|
import { execFileSync } from "node:child_process";
|
|
11
11
|
import { writeFileSync, chmodSync, statSync } from "node:fs";
|
|
@@ -13,6 +13,7 @@ import { UnsupportedCliError, resolveBinary, shellQuote, validateEffort, validat
|
|
|
13
13
|
import { PIE_CLASS } from "../tui-glyphs.js";
|
|
14
14
|
import { KIRO_EXPIRED_LOGIN_SCREEN } from "../login-flows.js";
|
|
15
15
|
import { t } from "../locale.js";
|
|
16
|
+
import { decideKiroModelError, readKiroKnownModels, readKiroModelRecords, readKiroV1SavedModel, readKiroV2SavedModel, writeKiroModelRecords, KIRO_FALLBACK_MODEL } from "./kiro-retired-model.js";
|
|
16
17
|
import { recordKiroLaunch } from "./kiro-engine-ledger.js";
|
|
17
18
|
import { forgetKiroV3Identity, resolveKiroV3Resume } from "./kiro-v3-identity.js";
|
|
18
19
|
// Kiro CLI feature gates. These are deliberately separate: the flags shipped
|
|
@@ -40,7 +41,7 @@ export const KIRO_INSTANCE_AGENT_MIN = "2.21.0";
|
|
|
40
41
|
* the binary's own --help instead of the version table, and the operator is
|
|
41
42
|
* told the version is unverified.
|
|
42
43
|
*/
|
|
43
|
-
export const KIRO_TESTED_MAX = "2.
|
|
44
|
+
export const KIRO_TESTED_MAX = "2.34.0";
|
|
44
45
|
/**
|
|
45
46
|
* kiro-cli versions, per TUI front-end, whose mid-turn steering AgEnD drives (#1405). Only kiro's TUI steers — typed
|
|
46
47
|
* input while a turn runs is injected into it ("steer", the default) or held for its end ("queue", Ctrl+S toggles); the
|
|
@@ -48,10 +49,13 @@ export const KIRO_TESTED_MAX = "2.33.0";
|
|
|
48
49
|
* queued message mid-tool — has been captured (tests/fixtures/kiro-steer-1405, 2026-10-08: 2.27.1 `--tui
|
|
49
50
|
* --agent-engine=v2` and `--v3`, 2.28.0 `--tui --agent-engine=v2`; identical rows on all three). Any other version,
|
|
50
51
|
* 2.28.0's v3, the legacy UI and an undetected version all deliver a steer as an ordinary message after the turn.
|
|
52
|
+
* 2.34.0 TUI was checked on the user-authorized #2598 D5 run (tests/fixtures/kiro-2.34.0-tui-d5):
|
|
53
|
+
* native steer during a read-only tool, a fleet message queued mid-tool, and a native queue entry in the busy turn.
|
|
51
54
|
*/
|
|
52
55
|
export const KIRO_STEER_VERIFIED = {
|
|
53
56
|
"2.27.1": ["tui", "v3"],
|
|
54
57
|
"2.28.0": ["tui"],
|
|
58
|
+
"2.34.0": ["tui"],
|
|
55
59
|
};
|
|
56
60
|
/**
|
|
57
61
|
* The TUI composer's interrupt mode, read off its own row: the LAST row starting at column 0 with `›` (transcript user
|
|
@@ -133,11 +137,12 @@ const warnedVersionGateCacheKeys = new Set();
|
|
|
133
137
|
* This broad test is only a safety hold: it must never select an option or
|
|
134
138
|
* claim a service outage. A ready prompt below the picker makes it history.
|
|
135
139
|
*/
|
|
140
|
+
const KIRO_MODEL_PICKER_HEADER = /^\s*Select model(?: \(type to search\):|:\s+type to search)\s*$/m;
|
|
136
141
|
function kiroModelPickerAtTail(pane) {
|
|
137
142
|
const lines = pane.replace(/\r/g, "").split("\n");
|
|
138
143
|
let pickerIndex = -1;
|
|
139
144
|
for (let index = lines.length - 1; index >= 0; index--) {
|
|
140
|
-
if (
|
|
145
|
+
if (KIRO_MODEL_PICKER_HEADER.test(lines[index])) {
|
|
141
146
|
pickerIndex = index;
|
|
142
147
|
break;
|
|
143
148
|
}
|
|
@@ -145,7 +150,8 @@ function kiroModelPickerAtTail(pane) {
|
|
|
145
150
|
if (pickerIndex < 0)
|
|
146
151
|
return false;
|
|
147
152
|
const tail = lines.slice(pickerIndex + 1);
|
|
148
|
-
|
|
153
|
+
const composer = readKiroSteerComposer(tail.join("\n"));
|
|
154
|
+
if (tail.some(line => /^\s*\d+%[^\n]*[!❯>]\s+\S/.test(line)) || (composer !== null && composer !== "text"))
|
|
149
155
|
return false;
|
|
150
156
|
return tail.some(line => /^\s*[>❯›]\s*\*?\s*\S/.test(line));
|
|
151
157
|
}
|
|
@@ -330,6 +336,205 @@ function kiroWorkspaceTrustDialogs(trustAll) {
|
|
|
330
336
|
},
|
|
331
337
|
];
|
|
332
338
|
}
|
|
339
|
+
const KIRO_MCP_INPUT_HEADER = /^\s*Input requested · \S.*$/;
|
|
340
|
+
const KIRO_MCP_INPUT_FOOTER = /^\s*esc to cancel · ↑↓ to navigate · enter to select(?: · ctrl\+s to submit)?$/;
|
|
341
|
+
/**
|
|
342
|
+
* #2587: kiro-cli 2.34.0's V3 engine answers an MCP server's `elicitation/create` (a tool asking the user for input)
|
|
343
|
+
* with a card in place of the composer: a divider, `Input requested · <server>`, a divider, the server's message and
|
|
344
|
+
* one row per form field then Submit / Decline (form mode) — or Host, URL and Open in browser / Copy URL / I'll open it
|
|
345
|
+
* myself / Decline / Cancel (url mode) — with exactly one `❯` cursor row, a divider, and the key hints as the last row
|
|
346
|
+
* (tests/fixtures/kiro-2.34.0-audit). Bottom-anchored: the card is live only while it is what the pane ends with. The
|
|
347
|
+
* answer can carry credentials or a sign-in, so it is the person's: never a key, and no delivery's Enter may land in it.
|
|
348
|
+
*/
|
|
349
|
+
export function kiroMcpInputRequestActive(pane) {
|
|
350
|
+
const rows = pane.replace(/\r/g, "").split("\n").map(row => row.trimEnd());
|
|
351
|
+
let last = rows.length - 1;
|
|
352
|
+
while (last >= 0 && !rows[last].trim())
|
|
353
|
+
last--;
|
|
354
|
+
if (last < 0 || !KIRO_MCP_INPUT_FOOTER.test(rows[last]))
|
|
355
|
+
return false;
|
|
356
|
+
const divider = (row) => row !== undefined && /^─{3,}$/.test(row.trim());
|
|
357
|
+
if (!divider(rows[last - 1]))
|
|
358
|
+
return false;
|
|
359
|
+
let header = -1;
|
|
360
|
+
for (let index = last - 2; index >= 1; index--) {
|
|
361
|
+
if (KIRO_MCP_INPUT_HEADER.test(rows[index])) {
|
|
362
|
+
header = index;
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
if (header < 0 || !divider(rows[header - 1]) || !divider(rows[header + 1]))
|
|
367
|
+
return false;
|
|
368
|
+
const body = rows.slice(header + 2, last - 1);
|
|
369
|
+
// A V3 composer (`›` at column 0) inside means the card is history. A lone `>` is a form field's own input caret.
|
|
370
|
+
if (body.some(row => divider(row) || /^›(?:[ \t]|$)/.test(row)))
|
|
371
|
+
return false;
|
|
372
|
+
return body.filter(row => /^\s*❯\s+\S/.test(row)).length === 1;
|
|
373
|
+
}
|
|
374
|
+
const KIRO_QUESTION_HEADER = /^\s*(?:\S.* > )?Question$/;
|
|
375
|
+
const KIRO_QUESTION_FOOTER = /^\s*esc to (?:cancel|go back) · ↑↓ to navigate(?: · space to toggle)? · ↵ to submit$/;
|
|
376
|
+
/**
|
|
377
|
+
* #2592: kiro's V3 engine shows the agent's question to the user (`question_request`) as a card in place of the
|
|
378
|
+
* composer: a divider, `Question` (or `<name> > Question`), the question, numbered options (a description row under
|
|
379
|
+
* one, `(recommended)` after one) and `Type a different answer…`, a divider, and the key hints as the last row — or, in
|
|
380
|
+
* an option's sub-options, `[✓] <title>` rows and `esc to go back · … · space to toggle · ↵ to submit`
|
|
381
|
+
* (tests/fixtures/kiro-question-2592; unchanged from 2.33.1 to 2.34.0). Any typed character turns the card into a free
|
|
382
|
+
* answer and Enter submits it, so a delivered message would become the answer to a question nobody read. The person
|
|
383
|
+
* answers it in the pane (the user's decision on #2592); it is never keyed. Bottom-anchored like
|
|
384
|
+
* kiroMcpInputRequestActive: the header is the row right under the nearest divider above the key hints' divider.
|
|
385
|
+
*/
|
|
386
|
+
export function kiroQuestionCardActive(pane) {
|
|
387
|
+
const rows = pane.replace(/\r/g, "").split("\n").map(row => row.trimEnd());
|
|
388
|
+
let last = rows.length - 1;
|
|
389
|
+
while (last >= 0 && !rows[last].trim())
|
|
390
|
+
last--;
|
|
391
|
+
if (last < 0 || !KIRO_QUESTION_FOOTER.test(rows[last]))
|
|
392
|
+
return false;
|
|
393
|
+
const divider = (row) => row !== undefined && /^─{3,}$/.test(row.trim());
|
|
394
|
+
if (!divider(rows[last - 1]))
|
|
395
|
+
return false;
|
|
396
|
+
let top = last - 2;
|
|
397
|
+
while (top >= 0 && !divider(rows[top]))
|
|
398
|
+
top--;
|
|
399
|
+
if (top < 0 || !KIRO_QUESTION_HEADER.test(rows[top + 1] ?? ""))
|
|
400
|
+
return false;
|
|
401
|
+
const body = rows.slice(top + 2, last - 1);
|
|
402
|
+
// The question, then the options: a V3 composer (`›` at column 0) among them means the card is history.
|
|
403
|
+
if (body.length < 2 || body.some(row => /^›(?:[ \t]|$)/.test(row)))
|
|
404
|
+
return false;
|
|
405
|
+
return body.filter(row => /^\s*❯\s+\S/.test(row)).length === 1;
|
|
406
|
+
}
|
|
407
|
+
/** #2675: the live card's rows — the header row, the body between it and the key hints' divider, and the key hints. */
|
|
408
|
+
function kiroCardRows(pane, headerAt) {
|
|
409
|
+
const rows = pane.replace(/\r/g, "").split("\n").map(row => row.trimEnd());
|
|
410
|
+
let last = rows.length - 1;
|
|
411
|
+
while (last >= 0 && !rows[last].trim())
|
|
412
|
+
last--;
|
|
413
|
+
const header = headerAt(rows, last);
|
|
414
|
+
return header < 0 ? null : { header: rows[header].trim(), body: rows.slice(header + 1, last - 1), footer: rows[last].trim(), width: rows[last - 1].trim().length };
|
|
415
|
+
}
|
|
416
|
+
const KIRO_QUESTION_OPTION_ROW = /^ (❯| ) (\d+)\. (.*?)( \(recommended\))?$/;
|
|
417
|
+
const KIRO_QUESTION_SUBOPTION_ROW = /^ (❯| ) \[(✓| )\] (.*)$/;
|
|
418
|
+
const KIRO_QUESTION_FREE_ROW = /^ (❯| ) (Type a different answer…|or type feedback to request changes)$/;
|
|
419
|
+
/**
|
|
420
|
+
* #2675: the live Question card (see kiroQuestionCardActive), read for a person to answer from the chat: the question,
|
|
421
|
+
* the numbered options (`(recommended)` and the description row under one), the typed-answer row, and where the `❯`
|
|
422
|
+
* is (tui.js `A0`; tests/fixtures/kiro-question-2592). On a sub-options page the rows are the `[✓]` boxes; while an
|
|
423
|
+
* answer is being typed the last row is `❯ <text>`. A row the shapes above do not account for is a wrapped title (the
|
|
424
|
+
* card's own indent) or description (deeper), joined to the row it continues; one before any option belongs to the
|
|
425
|
+
* question. Null when the card is not live, or when it is in a shape this reader does not know.
|
|
426
|
+
*/
|
|
427
|
+
export function readKiroQuestionCard(pane) {
|
|
428
|
+
if (!kiroQuestionCardActive(pane))
|
|
429
|
+
return null;
|
|
430
|
+
const card = kiroCardRows(pane, (rows, last) => {
|
|
431
|
+
let top = last - 2;
|
|
432
|
+
while (top >= 0 && !/^─{3,}$/.test(rows[top].trim()))
|
|
433
|
+
top--;
|
|
434
|
+
return top + 1;
|
|
435
|
+
});
|
|
436
|
+
if (!card)
|
|
437
|
+
return null;
|
|
438
|
+
const page = /space to toggle/.test(card.footer) ? "suboptions" : "options";
|
|
439
|
+
const question = [];
|
|
440
|
+
const options = [];
|
|
441
|
+
let cursor = null, freeText = false, typed = null, freeRow = false;
|
|
442
|
+
for (const row of card.body) {
|
|
443
|
+
const option = page === "options" ? KIRO_QUESTION_OPTION_ROW.exec(row) : null;
|
|
444
|
+
const sub = page === "suboptions" ? KIRO_QUESTION_SUBOPTION_ROW.exec(row) : null;
|
|
445
|
+
const free = page === "options" ? KIRO_QUESTION_FREE_ROW.exec(row) : null;
|
|
446
|
+
if (freeRow)
|
|
447
|
+
return null; // nothing follows the typed-answer row
|
|
448
|
+
if (option && Number(option[2]) === options.length + 1) {
|
|
449
|
+
if (option[1] === "❯")
|
|
450
|
+
cursor = options.length;
|
|
451
|
+
options.push({ n: options.length + 1, title: option[3], recommended: option[4] !== undefined, description: null });
|
|
452
|
+
}
|
|
453
|
+
else if (sub) {
|
|
454
|
+
if (sub[1] === "❯")
|
|
455
|
+
cursor = options.length;
|
|
456
|
+
options.push({ n: options.length + 1, title: sub[3], recommended: false, description: null, checked: sub[2] === "✓" });
|
|
457
|
+
}
|
|
458
|
+
else if (free) {
|
|
459
|
+
freeText = true;
|
|
460
|
+
freeRow = true;
|
|
461
|
+
if (free[1] === "❯")
|
|
462
|
+
cursor = options.length;
|
|
463
|
+
}
|
|
464
|
+
else if (page === "options" && options.length > 0 && /^ ❯ /.test(row)) {
|
|
465
|
+
freeText = true;
|
|
466
|
+
freeRow = true;
|
|
467
|
+
typed = row.slice(3);
|
|
468
|
+
}
|
|
469
|
+
else if (!row.trim()) {
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
else if (options.length === 0) {
|
|
473
|
+
question.push(row.replace(/^ /, ""));
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
const lastOption = options[options.length - 1];
|
|
477
|
+
if (/^ {5,}\S/.test(row))
|
|
478
|
+
lastOption.description = lastOption.description === null ? row.trim() : `${lastOption.description} ${row.trim()}`;
|
|
479
|
+
else if (lastOption.description === null)
|
|
480
|
+
lastOption.title = `${lastOption.title} ${row.trim()}`;
|
|
481
|
+
else
|
|
482
|
+
return null;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
if (options.length === 0 || question.length === 0)
|
|
486
|
+
return null;
|
|
487
|
+
const typing = typed !== null;
|
|
488
|
+
if (typing ? cursor !== null : cursor === null)
|
|
489
|
+
return null;
|
|
490
|
+
const titles = options.map(option => `${option.n}. ${option.title}`).join("\n");
|
|
491
|
+
return {
|
|
492
|
+
kind: "question", identity: `${card.header}\n${question.join("\n")}\n${page === "suboptions" ? "sub" : "options"}\n${titles}`,
|
|
493
|
+
title: card.header, question: question.join("\n").trim(), page: typing ? "freetext" : page, options, freeText, cursor, typed, rowWidth: card.width,
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
const KIRO_MCP_INPUT_ACTIONS = new Set(["Submit", "Decline", "Open in browser", "Copy URL", "I'll open it myself", "Cancel"]);
|
|
497
|
+
/**
|
|
498
|
+
* #2675: the live MCP `Input requested` card (see kiroMcpInputRequestActive), read for the chat: the server, the body
|
|
499
|
+
* as painted, with the `URL:` row masked (a sign-in link stays in the pane), its action rows, and the `❯` row. Its
|
|
500
|
+
* identity is the server, the mode, the message's first row and the actions: moving or filling in a field keeps it.
|
|
501
|
+
*/
|
|
502
|
+
export function readKiroMcpInputCard(pane) {
|
|
503
|
+
if (!kiroMcpInputRequestActive(pane))
|
|
504
|
+
return null;
|
|
505
|
+
const card = kiroCardRows(pane, (rows, last) => {
|
|
506
|
+
for (let index = last - 2; index >= 1; index--)
|
|
507
|
+
if (KIRO_MCP_INPUT_HEADER.test(rows[index]))
|
|
508
|
+
return index;
|
|
509
|
+
return -1;
|
|
510
|
+
});
|
|
511
|
+
if (!card)
|
|
512
|
+
return null;
|
|
513
|
+
// The URL row is masked, and so is every row after it up to the next action row: a long URL wraps (#2677 review).
|
|
514
|
+
let inUrl = false;
|
|
515
|
+
const body = card.body.slice(1).flatMap(row => {
|
|
516
|
+
if (/^\s*URL: /.test(row)) {
|
|
517
|
+
inUrl = true;
|
|
518
|
+
return [row.replace(/URL: .*$/, "URL: (shown in the instance pane)")];
|
|
519
|
+
}
|
|
520
|
+
if (inUrl && KIRO_MCP_INPUT_ACTIONS.has(row.replace(/^ ❯ /, " ").trim()))
|
|
521
|
+
inUrl = false;
|
|
522
|
+
return inUrl ? [] : [row];
|
|
523
|
+
});
|
|
524
|
+
const strip = (row) => row.replace(/^ ❯ /, " ").trim();
|
|
525
|
+
const cursorRow = body.find(row => /^\s*❯\s+\S/.test(row));
|
|
526
|
+
if (!cursorRow)
|
|
527
|
+
return null;
|
|
528
|
+
return {
|
|
529
|
+
kind: "input", server: card.header.replace(/^Input requested · /, ""),
|
|
530
|
+
mode: /ctrl\+s to submit/.test(card.footer) ? "form" : "url",
|
|
531
|
+
rows: body.map(row => row.replace(/^ ❯ /, " ").replace(/^ {3}/, "")).filter(row => row.trim()),
|
|
532
|
+
actions: body.map(strip).filter(row => KIRO_MCP_INPUT_ACTIONS.has(row)),
|
|
533
|
+
cursorRow: strip(cursorRow),
|
|
534
|
+
// The focused field paints extra rows (its value, its caret) and a typed value changes its row: neither is another request.
|
|
535
|
+
identity: `${card.header}\n${/ctrl\+s to submit/.test(card.footer) ? "form" : "url"}\n${strip(body[0] ?? "")}\n${body.map(strip).filter(row => KIRO_MCP_INPUT_ACTIONS.has(row)).join("|")}`,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
333
538
|
/**
|
|
334
539
|
* Kiro's service-unavailable path opens the same picker as `/model`, but only
|
|
335
540
|
* the former needs incident escalation. The runtime scanner and delivery gate
|
|
@@ -342,7 +547,7 @@ export function kiroUnavailableModelPickerActive(pane) {
|
|
|
342
547
|
const lines = pane.replace(/\r/g, "").split("\n");
|
|
343
548
|
let pickerIndex = -1;
|
|
344
549
|
for (let i = lines.length - 1; i >= 0; i--) {
|
|
345
|
-
if (
|
|
550
|
+
if (KIRO_MODEL_PICKER_HEADER.test(lines[i])) {
|
|
346
551
|
pickerIndex = i;
|
|
347
552
|
break;
|
|
348
553
|
}
|
|
@@ -634,6 +839,17 @@ function compatibilityFromHelp(version, help) {
|
|
|
634
839
|
source: "help",
|
|
635
840
|
};
|
|
636
841
|
}
|
|
842
|
+
/**
|
|
843
|
+
* #2598 (D1): kiro-cli-chat skips its self-update when this is set (2.30.0 and 2.34.0 both read it). AgEnD pins the
|
|
844
|
+
* kiro version it has audited; an in-place update can swap the engine a running fleet depends on (3.0 drops legacy).
|
|
845
|
+
* Every chat AgEnD starts carries it: the instance launch (a shell prefix) and the probes (their child env). The
|
|
846
|
+
* host-wide `app.disableAutoupdates` setting is the operator's half; this holds even where that was never set.
|
|
847
|
+
*/
|
|
848
|
+
export const KIRO_NO_AUTO_UPDATE = "KIRO_NO_AUTO_UPDATE";
|
|
849
|
+
/** A kiro child's environment: the given one (default: ours) with self-update off. */
|
|
850
|
+
export function kiroChildEnv(base = process.env) {
|
|
851
|
+
return { ...base, [KIRO_NO_AUTO_UPDATE]: "1" };
|
|
852
|
+
}
|
|
637
853
|
/**
|
|
638
854
|
* Probe once per binary generation. A version AgEnD has run (<= TESTED_MAX)
|
|
639
855
|
* is answered from the table without a second CLI call; anything newer, or a
|
|
@@ -645,6 +861,7 @@ export function probeKiroCliCompatibility(binaryPath, run = (binary, args) => me
|
|
|
645
861
|
encoding: "utf-8",
|
|
646
862
|
timeout: 5000,
|
|
647
863
|
stdio: ["ignore", "pipe", "ignore"],
|
|
864
|
+
env: kiroChildEnv(),
|
|
648
865
|
}))) {
|
|
649
866
|
return measureSyncWork("kiro.compatibilitySync", () => probeKiroCliCompatibilitySync(binaryPath, run));
|
|
650
867
|
}
|
|
@@ -673,6 +890,8 @@ function nextPatch(version) {
|
|
|
673
890
|
const [major, minor, patch] = parseSemver(version);
|
|
674
891
|
return `${major}.${minor}.${patch + 1}`;
|
|
675
892
|
}
|
|
893
|
+
/** #2598 B3: engines in the order a conversation can move between them (never back). */
|
|
894
|
+
const KIRO_ENGINE_RANK = { legacy: 1, tui: 2, v3: 3 };
|
|
676
895
|
/** Binary generations already told they cannot isolate (once each). */
|
|
677
896
|
const warnedNoInstanceAgentKeys = new Set();
|
|
678
897
|
/** Instances already told about an untagged steering file (once each). */
|
|
@@ -913,6 +1132,8 @@ export class KiroBackend {
|
|
|
913
1132
|
activeTrustAll = true;
|
|
914
1133
|
/** Version-gate notice for the launch just built (consumeLaunchWarning). */
|
|
915
1134
|
launchWarning = null;
|
|
1135
|
+
/** #2648: what this launch's model came from, for a model error to be judged by (decideKiroModelError). */
|
|
1136
|
+
launchModels = null;
|
|
916
1137
|
/**
|
|
917
1138
|
* What this launch attempt resumes and as which agent (#906), resolved once per attempt in writeConfig — it claims
|
|
918
1139
|
* conversations and records fresh starts — and read by the buildCommand that follows it.
|
|
@@ -923,6 +1144,8 @@ export class KiroBackend {
|
|
|
923
1144
|
/** #1218: the last launch built in full (cleared when a build starts, set only when it returns). */
|
|
924
1145
|
builtLaunch = null;
|
|
925
1146
|
preparedV2Store = null;
|
|
1147
|
+
/** #2648: the saved model of the v2 conversation this instance has recorded, read in prepareLaunch (off the loop). */
|
|
1148
|
+
preparedV2Model = null;
|
|
926
1149
|
storePreparation = 0;
|
|
927
1150
|
storeKey(config) {
|
|
928
1151
|
return JSON.stringify([config.instanceName, config.workingDirectory, kiroCanonicalDirectory(config.workingDirectory), config.kiroUi,
|
|
@@ -939,6 +1162,7 @@ export class KiroBackend {
|
|
|
939
1162
|
async prepareLaunch(config) {
|
|
940
1163
|
const preparation = ++this.storePreparation;
|
|
941
1164
|
this.preparedV2Store = null;
|
|
1165
|
+
this.preparedV2Model = null;
|
|
942
1166
|
if (!config || config.kiroUi !== "tui")
|
|
943
1167
|
return;
|
|
944
1168
|
if (!this.fixedCompatibility)
|
|
@@ -954,6 +1178,14 @@ export class KiroBackend {
|
|
|
954
1178
|
if (preparation === this.storePreparation && key === this.storeKey(config))
|
|
955
1179
|
this.preparedV2Store = { key, store };
|
|
956
1180
|
}
|
|
1181
|
+
// #2648: only for an instance with no model of its own, and only the conversation it has recorded (the resolver
|
|
1182
|
+
// in writeConfig may pick another — then nothing is foreseen, and a model error is handled after the launch).
|
|
1183
|
+
const recorded = !config.model && !config.skipResume ? kiroRecordedConversation(opts) : null;
|
|
1184
|
+
if (recorded) {
|
|
1185
|
+
const model = await readKiroV2SavedModel(kiroV2SessionsDir(), recorded);
|
|
1186
|
+
if (preparation === this.storePreparation && key === this.storeKey(config))
|
|
1187
|
+
this.preparedV2Model = { key, id: recorded, model };
|
|
1188
|
+
}
|
|
957
1189
|
}
|
|
958
1190
|
constructor(instanceDir, compatibility) {
|
|
959
1191
|
this.instanceDir = instanceDir;
|
|
@@ -1055,6 +1287,12 @@ export class KiroBackend {
|
|
|
1055
1287
|
this.replyGuardOptedIn = false;
|
|
1056
1288
|
this.builtLaunch = null;
|
|
1057
1289
|
const ui = config.kiroUi ?? "legacy";
|
|
1290
|
+
// #2598 B3: never back onto an older engine than this instance has run on — that resumes the frozen copy and loses
|
|
1291
|
+
// everything done since. Before any probe: no kiro-cli flag or version changes the answer.
|
|
1292
|
+
const floor = kiroEngineFloor(getAgendHome(), config.instanceName);
|
|
1293
|
+
if (floor && KIRO_ENGINE_RANK[ui] < KIRO_ENGINE_RANK[floor === "v2" ? "tui" : "v3"]) {
|
|
1294
|
+
throw new UnsupportedCliError(t("kiro.engine_floor", config.instanceName, ui, floor === "v2" ? "tui" : "v3"));
|
|
1295
|
+
}
|
|
1058
1296
|
// Every launch re-reads the binary generation: a crash-respawn reuses this
|
|
1059
1297
|
// backend, and kiro-cli may have replaced itself in place since the last
|
|
1060
1298
|
// launch (an auto-update to a release without this instance's engine).
|
|
@@ -1075,7 +1313,8 @@ export class KiroBackend {
|
|
|
1075
1313
|
const plan = planKiroLaunch(ui, this.compatibility);
|
|
1076
1314
|
if (plan.kind === "refuse")
|
|
1077
1315
|
throw new UnsupportedCliError(plan.reason);
|
|
1078
|
-
|
|
1316
|
+
// #2598: a shell assignment, so it reaches kiro-cli-chat through `kiro-cli chat` and any credential-home prefix.
|
|
1317
|
+
let cmd = `${KIRO_NO_AUTO_UPDATE}=1 ${this.binaryPath} chat`;
|
|
1079
1318
|
for (const flag of plan.flags)
|
|
1080
1319
|
cmd += ` ${flag}`;
|
|
1081
1320
|
this.noteVersionGate();
|
|
@@ -1119,17 +1358,32 @@ export class KiroBackend {
|
|
|
1119
1358
|
if (id)
|
|
1120
1359
|
cmd += ` --resume-id ${shellQuote(id)}`;
|
|
1121
1360
|
}
|
|
1122
|
-
else if (!config.skipResume) {
|
|
1123
|
-
// Legacy mode, classic
|
|
1361
|
+
else if (!config.skipResume && ui === "legacy") {
|
|
1362
|
+
// Legacy mode, classic: the boolean form — kiro resumes the directory's newest conversation. Not isolated
|
|
1124
1363
|
// between instances sharing the directory (#1410); an instance launches like this only without the
|
|
1125
1364
|
// per-instance plan (an old kiro-cli, or a conversation store AgEnD could not read on adoption).
|
|
1126
1365
|
cmd += " --resume";
|
|
1127
1366
|
}
|
|
1367
|
+
else if (!config.skipResume && ui === "tui") {
|
|
1368
|
+
// #2598 B3: never the boolean form under the TUI — it takes the directory's newest conversation from EITHER
|
|
1369
|
+
// engine, and on a classic one makes a TUI fork of it (the wrong conversation, possibly another instance's). A
|
|
1370
|
+
// TUI launch without its per-instance plan starts fresh instead, and says so.
|
|
1371
|
+
this.addLaunchWarning(t("kiro.tui_no_plan_fresh"));
|
|
1372
|
+
}
|
|
1373
|
+
const resumed = lp.mode === "resume" && lp.id && (lp.engine === "v1" || lp.engine === "v2") ? { engine: lp.engine, id: lp.id } : null;
|
|
1374
|
+
const fallbackModel = !config.model && resumed && config.instanceDir
|
|
1375
|
+
? this.retiredModelFallback(config, resumed, credentialProfile) : null;
|
|
1376
|
+
this.launchModels = config.instanceDir
|
|
1377
|
+
? { instanceDir: config.instanceDir, ownModel: config.model ?? null, launchModel: config.model ?? fallbackModel, conversation: resumed?.id ?? null }
|
|
1378
|
+
: null;
|
|
1128
1379
|
if (config.model) {
|
|
1129
1380
|
const model = validateModel(config.model);
|
|
1130
1381
|
warnIfModelMismatch("kiro-cli", model);
|
|
1131
1382
|
cmd += ` --model ${shellQuote(model)}`;
|
|
1132
1383
|
}
|
|
1384
|
+
else if (fallbackModel) {
|
|
1385
|
+
cmd += ` --model ${shellQuote(validateModel(fallbackModel))}`;
|
|
1386
|
+
}
|
|
1133
1387
|
if (config.effort) {
|
|
1134
1388
|
const effort = validateEffort(config.effort);
|
|
1135
1389
|
if (this.compatibility.supportsEffortFlag) {
|
|
@@ -1290,6 +1544,59 @@ export class KiroBackend {
|
|
|
1290
1544
|
this.addLaunchWarning(t("kiro.untagged_steering"));
|
|
1291
1545
|
}
|
|
1292
1546
|
}
|
|
1547
|
+
/**
|
|
1548
|
+
* #2648 steps 1 and 3: the model a resumed conversation is launched on instead of its saved one, or null to launch as
|
|
1549
|
+
* before. Only for an instance with no model of its own. The conversation's current saved model decides, every
|
|
1550
|
+
* launch: one kiro's cached list no longer has is switched to kiro's default; one it has — or, without a list, one
|
|
1551
|
+
* other than the model that failed (a later /model choice, or the default kiro saved after a switch) — is launched
|
|
1552
|
+
* as saved, even after an earlier switch (#2649 review). Only when the saved model cannot be read does a recorded
|
|
1553
|
+
* switch (step 2's restart) still apply. Announced once per conversation; the record also keeps that dedupe.
|
|
1554
|
+
*/
|
|
1555
|
+
retiredModelFallback(config, resumed, credentialProfile) {
|
|
1556
|
+
const records = readKiroModelRecords(config.instanceDir);
|
|
1557
|
+
let entry = records.switched[resumed.id];
|
|
1558
|
+
const known = readKiroKnownModels(getAgendHome());
|
|
1559
|
+
const prepared = this.preparedV2Model;
|
|
1560
|
+
const saved = resumed.engine === "v1"
|
|
1561
|
+
? readKiroV1SavedModel({ id: resumed.id, workingDirectory: config.workingDirectory, dbPath: kiroV1DbPath(credentialProfile) })
|
|
1562
|
+
: prepared && prepared.key === this.storeKey(config) && prepared.id === resumed.id ? prepared.model : null;
|
|
1563
|
+
if (saved) {
|
|
1564
|
+
// Step 2's restart recorded no model: the one saved now is the one that failed — unless it is the default the
|
|
1565
|
+
// switch put there (kiro saves the model a launch ran on).
|
|
1566
|
+
if (entry && entry.from === null && saved !== entry.to)
|
|
1567
|
+
entry.from = saved;
|
|
1568
|
+
const supported = known ? known.models.has(saved) : !!entry && (saved === entry.to || (entry.from !== null && saved !== entry.from));
|
|
1569
|
+
if (supported || (!known && !entry)) {
|
|
1570
|
+
if (entry && entry.from !== saved)
|
|
1571
|
+
this.saveModelRecords(config.instanceDir, records);
|
|
1572
|
+
return null;
|
|
1573
|
+
}
|
|
1574
|
+
if (!entry || entry.from !== saved)
|
|
1575
|
+
entry = records.switched[resumed.id] = { from: saved, to: known?.defaultModel ?? entry?.to ?? KIRO_FALLBACK_MODEL, announced: entry?.announced ?? false };
|
|
1576
|
+
}
|
|
1577
|
+
else if (!entry) {
|
|
1578
|
+
return null;
|
|
1579
|
+
}
|
|
1580
|
+
if (!entry.announced) {
|
|
1581
|
+
this.addLaunchWarning(t("kiro.retired_model_switched", config.instanceName, entry.from ?? t("kiro.retired_model_unknown"), entry.to));
|
|
1582
|
+
entry.announced = true;
|
|
1583
|
+
}
|
|
1584
|
+
this.saveModelRecords(config.instanceDir, records);
|
|
1585
|
+
return entry.to;
|
|
1586
|
+
}
|
|
1587
|
+
saveModelRecords(instanceDir, records) {
|
|
1588
|
+
try {
|
|
1589
|
+
writeKiroModelRecords(instanceDir, records);
|
|
1590
|
+
}
|
|
1591
|
+
catch { /* the next launch decides again; at worst it says so again */ }
|
|
1592
|
+
}
|
|
1593
|
+
/** #2648 steps 2 and 4: what a model error on this launch should do (records it); null before any launch. */
|
|
1594
|
+
onModelError() {
|
|
1595
|
+
const m = this.launchModels;
|
|
1596
|
+
if (!m)
|
|
1597
|
+
return null;
|
|
1598
|
+
return decideKiroModelError(m.instanceDir, m, readKiroKnownModels(getAgendHome())?.defaultModel ?? KIRO_FALLBACK_MODEL);
|
|
1599
|
+
}
|
|
1293
1600
|
addLaunchWarning(message) {
|
|
1294
1601
|
this.launchWarning = this.launchWarning ? `${this.launchWarning}\n${message}` : message;
|
|
1295
1602
|
}
|
|
@@ -1656,7 +1963,7 @@ export class KiroBackend {
|
|
|
1656
1963
|
// picker. Its choices range across credit multipliers and capability
|
|
1657
1964
|
// tiers, so this must be a human decision, never an automatic Enter or
|
|
1658
1965
|
// Escape. The ordinary /model menu alone is intentionally not matched.
|
|
1659
|
-
pattern:
|
|
1966
|
+
pattern: KIRO_MODEL_PICKER_HEADER,
|
|
1660
1967
|
keys: [],
|
|
1661
1968
|
description: "Kiro model unavailable — choose a replacement model in the instance pane",
|
|
1662
1969
|
blocksDelivery: true,
|
|
@@ -1668,7 +1975,7 @@ export class KiroBackend {
|
|
|
1668
1975
|
// Any active /model picker owns stdin, even if a future Kiro release
|
|
1669
1976
|
// changes the exact warning, credit wording or row layout. Keep this
|
|
1670
1977
|
// after the verified-outage case: it never labels /model as an outage.
|
|
1671
|
-
pattern:
|
|
1978
|
+
pattern: KIRO_MODEL_PICKER_HEADER,
|
|
1672
1979
|
keys: [],
|
|
1673
1980
|
description: "Kiro model picker — manual selection required",
|
|
1674
1981
|
blocksDelivery: true,
|
|
@@ -1676,6 +1983,30 @@ export class KiroBackend {
|
|
|
1676
1983
|
inputBlocked: true,
|
|
1677
1984
|
isActive: kiroModelPickerAtTail,
|
|
1678
1985
|
},
|
|
1986
|
+
{
|
|
1987
|
+
// #2587: an MCP server's input request (kiro-cli 2.34.0 V3) owns stdin until the person answers or cancels it.
|
|
1988
|
+
pattern: KIRO_MCP_INPUT_HEADER,
|
|
1989
|
+
keys: [],
|
|
1990
|
+
description: "Kiro MCP server is asking for input — answer it in the instance pane",
|
|
1991
|
+
blocksDelivery: true,
|
|
1992
|
+
holdOnly: true,
|
|
1993
|
+
inputBlocked: true,
|
|
1994
|
+
isActive: kiroMcpInputRequestActive,
|
|
1995
|
+
requestIdentity: pane => readKiroMcpInputCard(pane)?.identity ?? null,
|
|
1996
|
+
remoteCard: readKiroMcpInputCard,
|
|
1997
|
+
},
|
|
1998
|
+
{
|
|
1999
|
+
// #2592: the agent's question to the user owns stdin until the person answers or cancels it.
|
|
2000
|
+
pattern: KIRO_QUESTION_HEADER,
|
|
2001
|
+
keys: [],
|
|
2002
|
+
description: "Kiro agent is asking a question — answer it in the instance pane",
|
|
2003
|
+
blocksDelivery: true,
|
|
2004
|
+
holdOnly: true,
|
|
2005
|
+
inputBlocked: true,
|
|
2006
|
+
isActive: kiroQuestionCardActive,
|
|
2007
|
+
requestIdentity: pane => readKiroQuestionCard(pane)?.identity ?? null,
|
|
2008
|
+
remoteCard: readKiroQuestionCard,
|
|
2009
|
+
},
|
|
1679
2010
|
...kiroTrustPromptDialogs(this.activeTrustAll),
|
|
1680
2011
|
...kiroWorkspaceTrustDialogs(this.activeTrustAll),
|
|
1681
2012
|
];
|
|
@@ -1684,6 +2015,16 @@ export class KiroBackend {
|
|
|
1684
2015
|
return null;
|
|
1685
2016
|
}
|
|
1686
2017
|
logLaunch() { return this.builtLaunch ? { ...this.builtLaunch } : null; }
|
|
2018
|
+
/**
|
|
2019
|
+
* #2598 B1: the store is the launch's engine's (v1 = the classic sqlite store, v2 = the TUI's session files), and the
|
|
2020
|
+
* conversation is the one the launch resumed by id. A fresh or legacy-mode launch owns no id yet.
|
|
2021
|
+
*/
|
|
2022
|
+
transcriptLaunch() {
|
|
2023
|
+
const built = this.builtLaunch, plan = this.activePlan;
|
|
2024
|
+
if (!built)
|
|
2025
|
+
return null;
|
|
2026
|
+
return { engine: built.engine, sessionId: plan?.mode === "resume" && plan.id ? plan.id : null };
|
|
2027
|
+
}
|
|
1687
2028
|
getSessionId() {
|
|
1688
2029
|
// Kiro manages sessions internally via SQLite keyed by working directory.
|
|
1689
2030
|
// No external session ID needed — --resume handles it automatically.
|
|
@@ -1709,7 +2050,7 @@ export class KiroBackend {
|
|
|
1709
2050
|
*/
|
|
1710
2051
|
readModelsPayload() {
|
|
1711
2052
|
try {
|
|
1712
|
-
const out = execFileSync(this.binaryPath, ["chat", "--list-models", "--format", "json"], { encoding: "utf-8", timeout: 5000, stdio: ["ignore", "pipe", "ignore"] });
|
|
2053
|
+
const out = execFileSync(this.binaryPath, ["chat", "--list-models", "--format", "json"], { encoding: "utf-8", timeout: 5000, stdio: ["ignore", "pipe", "ignore"], env: kiroChildEnv() });
|
|
1713
2054
|
const parsed = JSON.parse(out);
|
|
1714
2055
|
const arr = Array.isArray(parsed) ? parsed : (parsed?.models ?? []);
|
|
1715
2056
|
const models = arr.map((m) => {
|