@pentoshi/clai 4.11.26 → 4.11.28
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/dist/agent/compaction/summary-execution.js +11 -1
- package/dist/agent/compaction/summary-execution.js.map +1 -1
- package/dist/agent/context-manager.d.ts +0 -1
- package/dist/agent/context-manager.js +0 -1
- package/dist/agent/context-manager.js.map +1 -1
- package/dist/agent/events.d.ts +1 -5
- package/dist/agent/plan/actions/plan-clear.js +1 -1
- package/dist/agent/plan/actions/plan-clear.js.map +1 -1
- package/dist/agent/plan/actions/plan-create.js +38 -17
- package/dist/agent/plan/actions/plan-create.js.map +1 -1
- package/dist/agent/plan/actions/task-add.js +15 -4
- package/dist/agent/plan/actions/task-add.js.map +1 -1
- package/dist/agent/plan/actions/task-move.js +16 -5
- package/dist/agent/plan/actions/task-move.js.map +1 -1
- package/dist/agent/plan/handle-plan-tool.js +20 -6
- package/dist/agent/plan/handle-plan-tool.js.map +1 -1
- package/dist/agent/reliability-policy.d.ts +0 -10
- package/dist/agent/reliability-policy.js +0 -23
- package/dist/agent/reliability-policy.js.map +1 -1
- package/dist/agent/request-accounting.js +10 -10
- package/dist/agent/request-accounting.js.map +1 -1
- package/dist/agent/request-budget.d.ts +11 -18
- package/dist/agent/request-budget.js +14 -53
- package/dist/agent/request-budget.js.map +1 -1
- package/dist/agent/runner.js +16 -12
- package/dist/agent/runner.js.map +1 -1
- package/dist/agent/stream-recovery.d.ts +1 -2
- package/dist/agent/stream-recovery.js +5 -10
- package/dist/agent/stream-recovery.js.map +1 -1
- package/dist/agent/subagents/worker.js +3 -2
- package/dist/agent/subagents/worker.js.map +1 -1
- package/dist/agent/turn/automatic-compaction-execution.js +2 -2
- package/dist/agent/turn/automatic-compaction-execution.js.map +1 -1
- package/dist/agent/turn/compaction-admission.d.ts +2 -2
- package/dist/agent/turn/compaction-admission.js +14 -17
- package/dist/agent/turn/compaction-admission.js.map +1 -1
- package/dist/agent/turn/compaction-coordinator.d.ts +2 -1
- package/dist/agent/turn/compaction-coordinator.js +12 -7
- package/dist/agent/turn/compaction-coordinator.js.map +1 -1
- package/dist/agent/turn/compaction-durable-envelope.js +1 -1
- package/dist/agent/turn/compaction-durable-envelope.js.map +1 -1
- package/dist/agent/turn/compaction-replay-selection.js +2 -3
- package/dist/agent/turn/compaction-replay-selection.js.map +1 -1
- package/dist/agent/turn/compaction-summarizer.js +1 -1
- package/dist/agent/turn/compaction-summarizer.js.map +1 -1
- package/dist/agent/turn/loop/answer-path.js +2 -2
- package/dist/agent/turn/loop/answer-path.js.map +1 -1
- package/dist/agent/turn/loop/completion-interpretation.d.ts +0 -1
- package/dist/agent/turn/loop/completion-interpretation.js +2 -7
- package/dist/agent/turn/loop/completion-interpretation.js.map +1 -1
- package/dist/agent/turn/loop/deps.d.ts +1 -0
- package/dist/agent/turn/loop/empty-response.d.ts +1 -1
- package/dist/agent/turn/loop/empty-response.js +2 -4
- package/dist/agent/turn/loop/empty-response.js.map +1 -1
- package/dist/agent/turn/loop/output-budget.d.ts +0 -1
- package/dist/agent/turn/loop/output-budget.js +4 -9
- package/dist/agent/turn/loop/output-budget.js.map +1 -1
- package/dist/agent/turn/loop/request-assembly.d.ts +1 -3
- package/dist/agent/turn/loop/request-assembly.js +15 -15
- package/dist/agent/turn/loop/request-assembly.js.map +1 -1
- package/dist/agent/turn/loop/round-request.js +1 -6
- package/dist/agent/turn/loop/round-request.js.map +1 -1
- package/dist/agent/turn/loop/run-rounds.js +9 -15
- package/dist/agent/turn/loop/run-rounds.js.map +1 -1
- package/dist/agent/turn/loop/state.d.ts +2 -3
- package/dist/agent/turn/loop/state.js +1 -2
- package/dist/agent/turn/loop/state.js.map +1 -1
- package/dist/agent/turn/loop/stream-failure.d.ts +0 -1
- package/dist/agent/turn/loop/stream-failure.js +5 -5
- package/dist/agent/turn/loop/stream-failure.js.map +1 -1
- package/dist/agent/turn/loop/stream-request.d.ts +0 -1
- package/dist/agent/turn/loop/stream-request.js +1 -3
- package/dist/agent/turn/loop/stream-request.js.map +1 -1
- package/dist/agent/turn/plan-persistence.d.ts +4 -5
- package/dist/agent/turn/plan-persistence.js +13 -4
- package/dist/agent/turn/plan-persistence.js.map +1 -1
- package/dist/agent/turn/provider-measurement.d.ts +6 -0
- package/dist/agent/turn/provider-measurement.js +19 -0
- package/dist/agent/turn/provider-measurement.js.map +1 -0
- package/dist/agent/turn/responder-job-linkage.js +2 -2
- package/dist/agent/turn/responder-job-linkage.js.map +1 -1
- package/dist/agent/turn/setup/compaction-services.d.ts +2 -1
- package/dist/agent/turn/setup/compaction-services.js +2 -1
- package/dist/agent/turn/setup/compaction-services.js.map +1 -1
- package/dist/agent/turn/setup/task-gate-setup.d.ts +3 -3
- package/dist/agent/turn/setup/task-gate-setup.js.map +1 -1
- package/dist/agent/turn/task-autostart.d.ts +2 -2
- package/dist/agent/turn/task-autostart.js +7 -9
- package/dist/agent/turn/task-autostart.js.map +1 -1
- package/dist/agent/turn/task-credit.d.ts +2 -2
- package/dist/agent/turn/task-credit.js +8 -5
- package/dist/agent/turn/task-credit.js.map +1 -1
- package/dist/agent/turn/tool-execution/deps.d.ts +3 -3
- package/dist/agent/turn/tool-execution/dispatch.js +3 -5
- package/dist/agent/turn/tool-execution/dispatch.js.map +1 -1
- package/dist/agent/turn/tool-execution/meta-tools.d.ts +1 -1
- package/dist/agent/turn/tool-execution/meta-tools.js +13 -11
- package/dist/agent/turn/tool-execution/meta-tools.js.map +1 -1
- package/dist/agent/turn/tool-execution/plan-tool-ledger.d.ts +2 -2
- package/dist/agent/turn/tool-execution/plan-tool-ledger.js +6 -6
- package/dist/agent/turn/tool-execution/plan-tool-ledger.js.map +1 -1
- package/dist/agent/turn/tool-execution/result-framing.d.ts +1 -1
- package/dist/agent/turn/tool-execution/result-framing.js +1 -2
- package/dist/agent/turn/tool-execution/result-framing.js.map +1 -1
- package/dist/agent/turn/tool-execution/single-tool.js +28 -16
- package/dist/agent/turn/tool-execution/single-tool.js.map +1 -1
- package/dist/app/adapters/agent-event-adapter.js +7 -7
- package/dist/app/adapters/agent-event-adapter.js.map +1 -1
- package/dist/app/controllers/plan-controller.js +4 -1
- package/dist/app/controllers/plan-controller.js.map +1 -1
- package/dist/app/controllers/session-compact-helper.js +11 -8
- package/dist/app/controllers/session-compact-helper.js.map +1 -1
- package/dist/app/controllers/session-context-usage.d.ts +6 -4
- package/dist/app/controllers/session-context-usage.js +94 -33
- package/dist/app/controllers/session-context-usage.js.map +1 -1
- package/dist/app/controllers/session-controller.d.ts +5 -6
- package/dist/app/controllers/session-controller.js +48 -40
- package/dist/app/controllers/session-controller.js.map +1 -1
- package/dist/app/controllers/session-responder.d.ts +2 -0
- package/dist/app/controllers/session-responder.js +18 -0
- package/dist/app/controllers/session-responder.js.map +1 -1
- package/dist/app/events/app-event.d.ts +3 -5
- package/dist/app/events/app-event.js.map +1 -1
- package/dist/classic/panels/pager-panel.js +3 -2
- package/dist/classic/panels/pager-panel.js.map +1 -1
- package/dist/commands/providers.d.ts +2 -0
- package/dist/commands/providers.js +49 -7
- package/dist/commands/providers.js.map +1 -1
- package/dist/llm/anthropic.d.ts +1 -0
- package/dist/llm/anthropic.js +20 -21
- package/dist/llm/anthropic.js.map +1 -1
- package/dist/llm/capabilities.d.ts +1 -4
- package/dist/llm/capabilities.js +24 -19
- package/dist/llm/capabilities.js.map +1 -1
- package/dist/llm/capability/state.js +0 -17
- package/dist/llm/capability/state.js.map +1 -1
- package/dist/llm/catalog-facts.js +40 -11
- package/dist/llm/catalog-facts.js.map +1 -1
- package/dist/llm/catalog-prefetch.js +9 -6
- package/dist/llm/catalog-prefetch.js.map +1 -1
- package/dist/llm/context-snapshot.d.ts +7 -3
- package/dist/llm/context-snapshot.js +35 -14
- package/dist/llm/context-snapshot.js.map +1 -1
- package/dist/llm/context-windows.d.ts +16 -0
- package/dist/llm/context-windows.js +54 -19
- package/dist/llm/context-windows.js.map +1 -1
- package/dist/llm/custom-providers.js +5 -4
- package/dist/llm/custom-providers.js.map +1 -1
- package/dist/llm/explabs.js +35 -26
- package/dist/llm/explabs.js.map +1 -1
- package/dist/llm/free.d.ts +1 -1
- package/dist/llm/free.js +26 -18
- package/dist/llm/free.js.map +1 -1
- package/dist/llm/gemini.js +25 -12
- package/dist/llm/gemini.js.map +1 -1
- package/dist/llm/kiro-auth.d.ts +34 -3
- package/dist/llm/kiro-auth.js +315 -144
- package/dist/llm/kiro-auth.js.map +1 -1
- package/dist/llm/kiro-import-sources.d.ts +10 -0
- package/dist/llm/kiro-import-sources.js +117 -0
- package/dist/llm/kiro-import-sources.js.map +1 -0
- package/dist/llm/kiro-reasoning.d.ts +28 -0
- package/dist/llm/kiro-reasoning.js +150 -0
- package/dist/llm/kiro-reasoning.js.map +1 -0
- package/dist/llm/kiro-social-device.d.ts +21 -0
- package/dist/llm/kiro-social-device.js +101 -0
- package/dist/llm/kiro-social-device.js.map +1 -0
- package/dist/llm/kiro.d.ts +3 -1
- package/dist/llm/kiro.js +653 -187
- package/dist/llm/kiro.js.map +1 -1
- package/dist/llm/learned-capabilities.js +1 -3
- package/dist/llm/learned-capabilities.js.map +1 -1
- package/dist/llm/merge-gateway.js +18 -13
- package/dist/llm/merge-gateway.js.map +1 -1
- package/dist/llm/meta-effort.d.ts +4 -0
- package/dist/llm/meta-effort.js +29 -0
- package/dist/llm/meta-effort.js.map +1 -0
- package/dist/llm/meta.js +13 -6
- package/dist/llm/meta.js.map +1 -1
- package/dist/llm/model-limit-store.d.ts +15 -0
- package/dist/llm/model-limit-store.js +121 -0
- package/dist/llm/model-limit-store.js.map +1 -0
- package/dist/llm/nvidia.d.ts +1 -0
- package/dist/llm/nvidia.js +15 -17
- package/dist/llm/nvidia.js.map +1 -1
- package/dist/llm/ollama-model-limits.d.ts +4 -0
- package/dist/llm/ollama-model-limits.js +91 -0
- package/dist/llm/ollama-model-limits.js.map +1 -0
- package/dist/llm/ollama.js +2 -1
- package/dist/llm/ollama.js.map +1 -1
- package/dist/llm/orcarouter.d.ts +1 -0
- package/dist/llm/orcarouter.js +8 -1
- package/dist/llm/orcarouter.js.map +1 -1
- package/dist/llm/provider-context-usage.d.ts +9 -0
- package/dist/llm/provider-context-usage.js +39 -0
- package/dist/llm/provider-context-usage.js.map +1 -0
- package/dist/llm/provider-info-text.js +3 -2
- package/dist/llm/provider-info-text.js.map +1 -1
- package/dist/llm/qwen-cloud.d.ts +1 -0
- package/dist/llm/qwen-cloud.js +44 -9
- package/dist/llm/qwen-cloud.js.map +1 -1
- package/dist/llm/reasoning-errors.d.ts +1 -0
- package/dist/llm/reasoning-errors.js +6 -0
- package/dist/llm/reasoning-errors.js.map +1 -1
- package/dist/llm/responses-config.d.ts +1 -1
- package/dist/llm/responses-config.js.map +1 -1
- package/dist/llm/responses-request.js +1 -1
- package/dist/llm/responses-request.js.map +1 -1
- package/dist/llm/routing/attempt-complete.js +9 -2
- package/dist/llm/routing/attempt-complete.js.map +1 -1
- package/dist/llm/routing/attempt-request.d.ts +1 -0
- package/dist/llm/routing/attempt-request.js +23 -0
- package/dist/llm/routing/attempt-request.js.map +1 -1
- package/dist/llm/routing/attempt-stream.js +15 -2
- package/dist/llm/routing/attempt-stream.js.map +1 -1
- package/dist/llm/token-estimate-calibration.js +1 -2
- package/dist/llm/token-estimate-calibration.js.map +1 -1
- package/dist/llm/token-usage.d.ts +2 -0
- package/dist/llm/token-usage.js +1 -1
- package/dist/llm/token-usage.js.map +1 -1
- package/dist/llm/wire/anthropic-model-catalog.d.ts +1 -0
- package/dist/llm/wire/anthropic-model-catalog.js +30 -0
- package/dist/llm/wire/anthropic-model-catalog.js.map +1 -0
- package/dist/llm/wire/dashscope-model-catalog.d.ts +1 -0
- package/dist/llm/wire/dashscope-model-catalog.js +53 -0
- package/dist/llm/wire/dashscope-model-catalog.js.map +1 -0
- package/dist/llm/wire/orcarouter-model-catalog.d.ts +2 -0
- package/dist/llm/wire/orcarouter-model-catalog.js +91 -0
- package/dist/llm/wire/orcarouter-model-catalog.js.map +1 -0
- package/dist/llm/wire/reasoning-payload.js +2 -8
- package/dist/llm/wire/reasoning-payload.js.map +1 -1
- package/dist/noninteractive/stream-blocks.d.ts +0 -3
- package/dist/noninteractive/stream-blocks.js +0 -9
- package/dist/noninteractive/stream-blocks.js.map +1 -1
- package/dist/noninteractive/stream-renderer.js +1 -4
- package/dist/noninteractive/stream-renderer.js.map +1 -1
- package/dist/store/config/endpoints.d.ts +0 -6
- package/dist/store/config/endpoints.js +1 -35
- package/dist/store/config/endpoints.js.map +1 -1
- package/dist/store/context-limits.d.ts +4 -0
- package/dist/store/context-limits.js +29 -0
- package/dist/store/context-limits.js.map +1 -0
- package/dist/store/plan/jsonl-backend.js +1 -4
- package/dist/store/plan/jsonl-backend.js.map +1 -1
- package/dist/store/plan/mutation.js +31 -1
- package/dist/store/plan/mutation.js.map +1 -1
- package/dist/store/plan/sqlite-backend.js +27 -9
- package/dist/store/plan/sqlite-backend.js.map +1 -1
- package/dist/tui-v2/components/pager/pager-line.d.ts +2 -0
- package/dist/tui-v2/components/pager/pager-line.js +1 -2
- package/dist/tui-v2/components/pager/pager-line.js.map +1 -1
- package/dist/tui-v2/components/pager/pager.js +5 -2
- package/dist/tui-v2/components/pager/pager.js.map +1 -1
- package/dist/tui-v2/components/transcript/tool-card.js +1 -1
- package/dist/tui-v2/components/transcript/tool-card.js.map +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/types.js.map +1 -1
- package/dist/ui-core/bootstrap/composition-root.js +8 -5
- package/dist/ui-core/bootstrap/composition-root.js.map +1 -1
- package/dist/ui-core/bootstrap/session-resume.js +1 -2
- package/dist/ui-core/bootstrap/session-resume.js.map +1 -1
- package/dist/ui-core/commands/key-commands.d.ts +2 -0
- package/dist/ui-core/commands/key-commands.js +76 -20
- package/dist/ui-core/commands/key-commands.js.map +1 -1
- package/dist/ui-core/commands/session-commands.js +33 -9
- package/dist/ui-core/commands/session-commands.js.map +1 -1
- package/dist/ui-core/rendering/batch-sections.js +10 -1
- package/dist/ui-core/rendering/batch-sections.js.map +1 -1
- package/dist/ui-core/rendering/context-limit.d.ts +0 -1
- package/dist/ui-core/rendering/context-limit.js +2 -2
- package/dist/ui-core/rendering/context-limit.js.map +1 -1
- package/dist/ui-core/rendering/subagent-presentation.d.ts +2 -0
- package/dist/ui-core/rendering/subagent-presentation.js +20 -7
- package/dist/ui-core/rendering/subagent-presentation.js.map +1 -1
- package/dist/ui-core/rendering/subagent-source.js +15 -8
- package/dist/ui-core/rendering/subagent-source.js.map +1 -1
- package/dist/ui-core/state/transcript/apply-app-event.js +0 -1
- package/dist/ui-core/state/transcript/apply-app-event.js.map +1 -1
- package/dist/ui-core/state/transcript-types.js +1 -1
- package/dist/ui-core/state/transcript-types.js.map +1 -1
- package/dist/version.generated.d.ts +2 -2
- package/dist/version.generated.js +2 -2
- package/package.json +1 -1
- package/dist/app/controllers/session-context-limits.d.ts +0 -8
- package/dist/app/controllers/session-context-limits.js +0 -35
- package/dist/app/controllers/session-context-limits.js.map +0 -1
- package/dist/store/config/compaction.d.ts +0 -1
- package/dist/store/config/compaction.js +0 -2
- package/dist/store/config/compaction.js.map +0 -1
package/dist/llm/kiro-auth.js
CHANGED
|
@@ -3,6 +3,7 @@ import { join } from "node:path";
|
|
|
3
3
|
import { readFile, readdir } from "node:fs/promises";
|
|
4
4
|
import { randomBytes, createHash } from "node:crypto";
|
|
5
5
|
import { createServer } from "node:http";
|
|
6
|
+
import { linkedSsoClientRegistration, normalizeIdpScope, parseStoredExpiry, preferKiroSsoTokenFiles, readKiroIdeProfileArn, validateExternalIdpTokenEndpoint, } from "./kiro-import-sources.js";
|
|
6
7
|
export const KIRO_DEFAULT_REGION = "us-east-1";
|
|
7
8
|
export const KIRO_AUTH_SERVICE = "https://prod.us-east-1.auth.desktop.kiro.dev";
|
|
8
9
|
export const KIRO_START_URL = "https://view.awsapps.com/start";
|
|
@@ -16,6 +17,22 @@ export const KIRO_CLI_CALLBACK_PATH = "/oauth/callback";
|
|
|
16
17
|
export const KIRO_CLI_SIGNIN_CALLBACK_PATH = "/signin/callback";
|
|
17
18
|
export const KIRO_DESKTOP_UA_VERSION = "0.7.45";
|
|
18
19
|
export const AWS_REGION_PATTERN = /^[a-z]{2}-[a-z]+-\d{1,2}$/;
|
|
20
|
+
const KIRO_API_REGION_MAP = {
|
|
21
|
+
"us-west-1": "us-east-1",
|
|
22
|
+
"us-west-2": "us-east-1",
|
|
23
|
+
"us-east-2": "us-east-1",
|
|
24
|
+
"ap-southeast-1": "us-east-1",
|
|
25
|
+
"ap-southeast-2": "us-east-1",
|
|
26
|
+
"ap-northeast-1": "us-east-1",
|
|
27
|
+
"ap-south-1": "us-east-1",
|
|
28
|
+
"eu-west-1": "eu-central-1",
|
|
29
|
+
"eu-west-2": "eu-central-1",
|
|
30
|
+
"eu-west-3": "eu-central-1",
|
|
31
|
+
"eu-north-1": "eu-central-1",
|
|
32
|
+
"eu-south-1": "eu-central-1",
|
|
33
|
+
"eu-south-2": "eu-central-1",
|
|
34
|
+
"eu-central-2": "eu-central-1",
|
|
35
|
+
};
|
|
19
36
|
export function assertValidAwsRegion(region) {
|
|
20
37
|
const value = (region ?? KIRO_DEFAULT_REGION).trim().toLowerCase();
|
|
21
38
|
if (!AWS_REGION_PATTERN.test(value)) {
|
|
@@ -23,6 +40,16 @@ export function assertValidAwsRegion(region) {
|
|
|
23
40
|
}
|
|
24
41
|
return value;
|
|
25
42
|
}
|
|
43
|
+
export function resolveKiroApiRegion(region) {
|
|
44
|
+
const value = assertValidAwsRegion(region);
|
|
45
|
+
return KIRO_API_REGION_MAP[value] ?? value;
|
|
46
|
+
}
|
|
47
|
+
export function resolveKiroRuntimeRegion(credential) {
|
|
48
|
+
const arnRegion = credential.profileArn?.split(":")[3];
|
|
49
|
+
if (arnRegion && AWS_REGION_PATTERN.test(arnRegion))
|
|
50
|
+
return arnRegion;
|
|
51
|
+
return resolveKiroApiRegion(credential.region);
|
|
52
|
+
}
|
|
26
53
|
function asRecord(value) {
|
|
27
54
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
28
55
|
? value
|
|
@@ -59,6 +86,8 @@ export function encodeKiroKey(credential) {
|
|
|
59
86
|
s: credential.clientSecret ?? "",
|
|
60
87
|
u: credential.startUrl ?? "",
|
|
61
88
|
k: credential.apiKey ?? "",
|
|
89
|
+
...(credential.tokenEndpoint ? { t: credential.tokenEndpoint } : {}),
|
|
90
|
+
...(credential.scope ? { o: credential.scope } : {}),
|
|
62
91
|
};
|
|
63
92
|
return (KIRO_KEY_PREFIX +
|
|
64
93
|
Buffer.from(JSON.stringify(payload), "utf8").toString("base64url"));
|
|
@@ -82,6 +111,8 @@ export function decodeKiroKey(value) {
|
|
|
82
111
|
clientSecret: typeof json?.s === "string" && json.s ? json.s : undefined,
|
|
83
112
|
startUrl: typeof json?.u === "string" && json.u ? json.u : undefined,
|
|
84
113
|
apiKey: typeof json?.k === "string" && json.k ? json.k : undefined,
|
|
114
|
+
...(typeof json?.t === "string" && json.t ? { tokenEndpoint: json.t } : {}),
|
|
115
|
+
...(typeof json?.o === "string" && json.o ? { scope: json.o } : {}),
|
|
85
116
|
};
|
|
86
117
|
}
|
|
87
118
|
catch {
|
|
@@ -212,7 +243,7 @@ export async function pollKiroDeviceAuth(start, options = {}) {
|
|
|
212
243
|
const expiresAt = Date.now() + expiresIn * 1000;
|
|
213
244
|
let profileArn;
|
|
214
245
|
try {
|
|
215
|
-
profileArn = await
|
|
246
|
+
profileArn = await discoverKiroProfileArn(accessToken, start.region);
|
|
216
247
|
}
|
|
217
248
|
catch {
|
|
218
249
|
profileArn = undefined;
|
|
@@ -430,6 +461,8 @@ export function kiroDesktopUserAgent() {
|
|
|
430
461
|
return `KiroIDE-${KIRO_DESKTOP_UA_VERSION}-${kiroMachineFingerprint()}`;
|
|
431
462
|
}
|
|
432
463
|
export function isHeadlessEnvironment() {
|
|
464
|
+
if (process.env.CLAI_NO_BROWSER || process.env.BROWSER === "none")
|
|
465
|
+
return true;
|
|
433
466
|
if (process.env.SSH_CONNECTION || process.env.SSH_CLIENT || process.env.SSH_TTY) {
|
|
434
467
|
return true;
|
|
435
468
|
}
|
|
@@ -490,7 +523,7 @@ export function parseKiroCliCallback(input) {
|
|
|
490
523
|
}
|
|
491
524
|
const loginOption = pairs.get("login_option");
|
|
492
525
|
if (!loginOption) {
|
|
493
|
-
throw new Error("missing Kiro login_option");
|
|
526
|
+
throw new Error("missing Kiro login_option — paste the complete redirect URL from the browser address bar");
|
|
494
527
|
}
|
|
495
528
|
const state = pairs.get("state") || undefined;
|
|
496
529
|
return { code, loginOption, state, path };
|
|
@@ -624,61 +657,65 @@ export function listenForKiroCliCallback(options) {
|
|
|
624
657
|
},
|
|
625
658
|
};
|
|
626
659
|
}
|
|
627
|
-
export
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
"Content-Type": "application/json",
|
|
636
|
-
Accept: "application/json",
|
|
637
|
-
},
|
|
638
|
-
body: JSON.stringify({
|
|
639
|
-
clientId,
|
|
640
|
-
clientSecret,
|
|
641
|
-
refreshToken,
|
|
642
|
-
grantType: "refresh_token",
|
|
643
|
-
}),
|
|
644
|
-
signal: AbortSignal.timeout(30_000),
|
|
645
|
-
});
|
|
646
|
-
if (!response.ok) {
|
|
647
|
-
const errorText = await response.text();
|
|
648
|
-
throw new Error(`Kiro token refresh failed (${response.status}): ${errorText}`);
|
|
649
|
-
}
|
|
650
|
-
const json = asRecord(await response.json().catch(() => ({})));
|
|
651
|
-
const accessToken = typeof json?.accessToken === "string" ? json.accessToken : "";
|
|
652
|
-
if (!accessToken) {
|
|
653
|
-
throw new Error("Invalid token refresh response from AWS OIDC");
|
|
654
|
-
}
|
|
655
|
-
const newRefreshToken = typeof json?.refreshToken === "string"
|
|
656
|
-
? json.refreshToken
|
|
657
|
-
: refreshToken;
|
|
658
|
-
const expiresIn = typeof json?.expiresIn === "number" ? json.expiresIn : 3600;
|
|
659
|
-
let profileArn = options.profileArn;
|
|
660
|
-
if (!profileArn) {
|
|
661
|
-
try {
|
|
662
|
-
profileArn = await listAvailableProfiles(accessToken, safeRegion);
|
|
663
|
-
}
|
|
664
|
-
catch {
|
|
665
|
-
profileArn = undefined;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
return {
|
|
669
|
-
accessToken,
|
|
670
|
-
refreshToken: newRefreshToken,
|
|
671
|
-
profileArn,
|
|
672
|
-
expiresAt: Date.now() + expiresIn * 1000,
|
|
673
|
-
authMethod: options.authMethod ?? "builder-id",
|
|
674
|
-
region: safeRegion,
|
|
675
|
-
clientId,
|
|
676
|
-
clientSecret,
|
|
677
|
-
startUrl: options.startUrl,
|
|
678
|
-
};
|
|
660
|
+
export class KiroRefreshError extends Error {
|
|
661
|
+
status;
|
|
662
|
+
reauthRequired;
|
|
663
|
+
constructor(message, status, reauthRequired) {
|
|
664
|
+
super(message);
|
|
665
|
+
this.status = status;
|
|
666
|
+
this.reauthRequired = reauthRequired;
|
|
667
|
+
this.name = "KiroRefreshError";
|
|
679
668
|
}
|
|
680
|
-
|
|
681
|
-
|
|
669
|
+
}
|
|
670
|
+
const UNRECOVERABLE_REFRESH = /invalid_grant|InvalidGrantException|ExpiredTokenException|invalid_client|InvalidClientException|UnauthorizedClientException/i;
|
|
671
|
+
async function refreshFailure(response) {
|
|
672
|
+
const errorText = await response.text().catch(() => "");
|
|
673
|
+
const reauthRequired = UNRECOVERABLE_REFRESH.test(errorText) ||
|
|
674
|
+
response.status === 400 ||
|
|
675
|
+
response.status === 401;
|
|
676
|
+
const hint = reauthRequired ? " — run `clai auth kiro` to sign in again" : "";
|
|
677
|
+
return new KiroRefreshError(`Kiro token refresh failed (${response.status})${hint}: ${errorText.slice(0, 300)}`, response.status, reauthRequired);
|
|
678
|
+
}
|
|
679
|
+
async function refreshViaOidc(refreshToken, options) {
|
|
680
|
+
const safeRegion = assertValidAwsRegion(options.region);
|
|
681
|
+
const response = await fetch(`https://oidc.${safeRegion}.amazonaws.com/token`, {
|
|
682
|
+
method: "POST",
|
|
683
|
+
headers: {
|
|
684
|
+
"Content-Type": "application/json",
|
|
685
|
+
Accept: "application/json",
|
|
686
|
+
},
|
|
687
|
+
body: JSON.stringify({
|
|
688
|
+
clientId: options.clientId,
|
|
689
|
+
clientSecret: options.clientSecret,
|
|
690
|
+
refreshToken,
|
|
691
|
+
grantType: "refresh_token",
|
|
692
|
+
}),
|
|
693
|
+
signal: AbortSignal.timeout(30_000),
|
|
694
|
+
});
|
|
695
|
+
if (!response.ok)
|
|
696
|
+
throw await refreshFailure(response);
|
|
697
|
+
const json = asRecord(await response.json().catch(() => ({})));
|
|
698
|
+
const accessToken = typeof json?.accessToken === "string" ? json.accessToken : "";
|
|
699
|
+
if (!accessToken) {
|
|
700
|
+
throw new Error("Invalid token refresh response from AWS OIDC");
|
|
701
|
+
}
|
|
702
|
+
const expiresIn = typeof json?.expiresIn === "number" ? json.expiresIn : 3600;
|
|
703
|
+
const profileArn = options.profileArn ??
|
|
704
|
+
await discoverKiroProfileArn(accessToken, safeRegion).catch(() => undefined);
|
|
705
|
+
return {
|
|
706
|
+
accessToken,
|
|
707
|
+
refreshToken: typeof json?.refreshToken === "string" ? json.refreshToken : refreshToken,
|
|
708
|
+
profileArn,
|
|
709
|
+
expiresAt: Date.now() + expiresIn * 1000,
|
|
710
|
+
authMethod: options.authMethod ?? "builder-id",
|
|
711
|
+
region: safeRegion,
|
|
712
|
+
clientId: options.clientId,
|
|
713
|
+
clientSecret: options.clientSecret,
|
|
714
|
+
startUrl: options.startUrl,
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
async function refreshViaSocial(refreshToken, options) {
|
|
718
|
+
const response = await fetch(`${KIRO_AUTH_SERVICE}/refreshToken`, {
|
|
682
719
|
method: "POST",
|
|
683
720
|
headers: {
|
|
684
721
|
"Content-Type": "application/json",
|
|
@@ -688,29 +725,100 @@ export async function refreshKiroToken(refreshToken, options = {}) {
|
|
|
688
725
|
body: JSON.stringify({ refreshToken }),
|
|
689
726
|
signal: AbortSignal.timeout(30_000),
|
|
690
727
|
});
|
|
691
|
-
if (!response.ok)
|
|
692
|
-
|
|
693
|
-
throw new Error(`Kiro token refresh failed (${response.status}): ${errorText}`);
|
|
694
|
-
}
|
|
728
|
+
if (!response.ok)
|
|
729
|
+
throw await refreshFailure(response);
|
|
695
730
|
const json = asRecord(await response.json().catch(() => ({})));
|
|
696
731
|
const accessToken = typeof json?.accessToken === "string" ? json.accessToken : "";
|
|
697
732
|
if (!accessToken) {
|
|
698
733
|
throw new Error("Invalid token refresh response from Kiro service");
|
|
699
734
|
}
|
|
700
|
-
const newRefreshToken = typeof json?.refreshToken === "string" ? json.refreshToken : refreshToken;
|
|
701
|
-
const profileArn = typeof json?.profileArn === "string"
|
|
702
|
-
? json.profileArn
|
|
703
|
-
: options.profileArn;
|
|
704
735
|
const expiresIn = typeof json?.expiresIn === "number" ? json.expiresIn : 3600;
|
|
705
736
|
return {
|
|
706
737
|
accessToken,
|
|
707
|
-
refreshToken:
|
|
708
|
-
profileArn,
|
|
738
|
+
refreshToken: typeof json?.refreshToken === "string" ? json.refreshToken : refreshToken,
|
|
739
|
+
profileArn: typeof json?.profileArn === "string" ? json.profileArn : options.profileArn,
|
|
709
740
|
expiresAt: Date.now() + expiresIn * 1000,
|
|
710
741
|
authMethod: options.authMethod ?? "imported",
|
|
711
742
|
region: options.region ?? KIRO_DEFAULT_REGION,
|
|
712
743
|
};
|
|
713
744
|
}
|
|
745
|
+
function usesSocialRefresh(authMethod) {
|
|
746
|
+
return authMethod === "google" || authMethod === "github";
|
|
747
|
+
}
|
|
748
|
+
async function refreshViaExternalIdp(refreshToken, options) {
|
|
749
|
+
if (!options.clientId || !options.tokenEndpoint) {
|
|
750
|
+
throw new KiroRefreshError("Kiro external IdP credential is missing clientId or tokenEndpoint — sign in again in Kiro and re-import", 400, true);
|
|
751
|
+
}
|
|
752
|
+
const endpoint = validateExternalIdpTokenEndpoint(options.tokenEndpoint);
|
|
753
|
+
const body = new URLSearchParams({
|
|
754
|
+
grant_type: "refresh_token",
|
|
755
|
+
client_id: options.clientId,
|
|
756
|
+
refresh_token: refreshToken,
|
|
757
|
+
...(options.scope ? { scope: options.scope } : {}),
|
|
758
|
+
});
|
|
759
|
+
const response = await fetch(endpoint, {
|
|
760
|
+
method: "POST",
|
|
761
|
+
headers: {
|
|
762
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
763
|
+
Accept: "application/json",
|
|
764
|
+
},
|
|
765
|
+
body: body.toString(),
|
|
766
|
+
signal: AbortSignal.timeout(30_000),
|
|
767
|
+
});
|
|
768
|
+
if (!response.ok)
|
|
769
|
+
throw await refreshFailure(response);
|
|
770
|
+
const json = asRecord(await response.json().catch(() => ({})));
|
|
771
|
+
const accessToken = typeof json?.access_token === "string" ? json.access_token : "";
|
|
772
|
+
if (!accessToken) {
|
|
773
|
+
throw new Error("Invalid token refresh response from external identity provider");
|
|
774
|
+
}
|
|
775
|
+
const expiresIn = typeof json?.expires_in === "number" ? json.expires_in : 3600;
|
|
776
|
+
return {
|
|
777
|
+
accessToken,
|
|
778
|
+
refreshToken: typeof json?.refresh_token === "string" ? json.refresh_token : refreshToken,
|
|
779
|
+
profileArn: options.profileArn,
|
|
780
|
+
expiresAt: Date.now() + expiresIn * 1000,
|
|
781
|
+
authMethod: "external_idp",
|
|
782
|
+
region: options.region ?? KIRO_DEFAULT_REGION,
|
|
783
|
+
clientId: options.clientId,
|
|
784
|
+
tokenEndpoint: endpoint,
|
|
785
|
+
scope: options.scope,
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
export async function refreshKiroToken(refreshToken, options = {}) {
|
|
789
|
+
if (options.authMethod === "external_idp") {
|
|
790
|
+
return refreshViaExternalIdp(refreshToken, options);
|
|
791
|
+
}
|
|
792
|
+
const { clientId, clientSecret } = options;
|
|
793
|
+
if (!clientId || !clientSecret || usesSocialRefresh(options.authMethod)) {
|
|
794
|
+
return refreshViaSocial(refreshToken, options);
|
|
795
|
+
}
|
|
796
|
+
try {
|
|
797
|
+
return await refreshViaOidc(refreshToken, { ...options, clientId, clientSecret });
|
|
798
|
+
}
|
|
799
|
+
catch (error) {
|
|
800
|
+
const canTrySocial = options.authMethod === "imported" &&
|
|
801
|
+
error instanceof KiroRefreshError &&
|
|
802
|
+
error.reauthRequired;
|
|
803
|
+
if (!canTrySocial)
|
|
804
|
+
throw error;
|
|
805
|
+
return refreshViaSocial(refreshToken, options);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
const KIRO_PROFILE_REGIONS = ["us-east-1", "eu-central-1"];
|
|
809
|
+
export async function discoverKiroProfileArn(accessToken, region) {
|
|
810
|
+
const regions = [...new Set([
|
|
811
|
+
...(region && AWS_REGION_PATTERN.test(region) ? [region] : []),
|
|
812
|
+
...KIRO_PROFILE_REGIONS,
|
|
813
|
+
])];
|
|
814
|
+
for (const candidate of regions) {
|
|
815
|
+
const profileArn = await listAvailableProfiles(accessToken, candidate)
|
|
816
|
+
.catch(() => undefined);
|
|
817
|
+
if (profileArn)
|
|
818
|
+
return profileArn;
|
|
819
|
+
}
|
|
820
|
+
return undefined;
|
|
821
|
+
}
|
|
714
822
|
export async function listAvailableProfiles(accessToken, region = KIRO_DEFAULT_REGION) {
|
|
715
823
|
const safeRegion = assertValidAwsRegion(region);
|
|
716
824
|
const endpoint = `https://codewhisperer.${safeRegion}.amazonaws.com`;
|
|
@@ -742,36 +850,13 @@ export async function listAvailableProfiles(accessToken, region = KIRO_DEFAULT_R
|
|
|
742
850
|
return arnOf(match) ?? undefined;
|
|
743
851
|
}
|
|
744
852
|
export async function listAvailableApiKeyModels(apiKey, region = KIRO_DEFAULT_REGION) {
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
headers: {
|
|
751
|
-
Authorization: `Bearer ${apiKey}`,
|
|
752
|
-
TokenType: "API_KEY",
|
|
753
|
-
Accept: "application/json",
|
|
754
|
-
"User-Agent": "AWS-SDK-JS/3.0.0 kiro-ide/1.0.0",
|
|
755
|
-
"X-Amz-User-Agent": "aws-sdk-js/3.0.0 kiro-ide/1.0.0",
|
|
756
|
-
},
|
|
757
|
-
signal: AbortSignal.timeout(20_000),
|
|
853
|
+
const models = await listKiroModelsDetailed({
|
|
854
|
+
accessToken: apiKey,
|
|
855
|
+
apiKey,
|
|
856
|
+
authMethod: "api_key",
|
|
857
|
+
region,
|
|
758
858
|
});
|
|
759
|
-
|
|
760
|
-
const errorText = await response.text();
|
|
761
|
-
throw new Error(`Failed to list API key models (${response.status}): ${errorText}`);
|
|
762
|
-
}
|
|
763
|
-
const json = asRecord(await response.json().catch(() => ({})));
|
|
764
|
-
const models = Array.isArray(json?.models) ? json.models : [];
|
|
765
|
-
return models
|
|
766
|
-
.map((m) => {
|
|
767
|
-
const rec = asRecord(m);
|
|
768
|
-
return typeof rec?.modelId === "string"
|
|
769
|
-
? rec.modelId
|
|
770
|
-
: typeof rec?.id === "string"
|
|
771
|
-
? rec.id
|
|
772
|
-
: "";
|
|
773
|
-
})
|
|
774
|
-
.filter(Boolean);
|
|
859
|
+
return models.map((model) => model.modelId);
|
|
775
860
|
}
|
|
776
861
|
export async function validateKiroApiKey(apiKey, region = KIRO_DEFAULT_REGION) {
|
|
777
862
|
try {
|
|
@@ -802,10 +887,8 @@ export async function candidateKiroCredentialPaths() {
|
|
|
802
887
|
const ssoCacheDir = join(home, ".aws", "sso", "cache");
|
|
803
888
|
try {
|
|
804
889
|
const files = await readdir(ssoCacheDir);
|
|
805
|
-
for (const file of files) {
|
|
806
|
-
|
|
807
|
-
paths.push(join(ssoCacheDir, file));
|
|
808
|
-
}
|
|
890
|
+
for (const file of preferKiroSsoTokenFiles(files)) {
|
|
891
|
+
paths.push(join(ssoCacheDir, file));
|
|
809
892
|
}
|
|
810
893
|
}
|
|
811
894
|
catch { }
|
|
@@ -836,36 +919,44 @@ export async function readKiroStoredAuth() {
|
|
|
836
919
|
: undefined;
|
|
837
920
|
if (!accessToken && !refreshToken)
|
|
838
921
|
continue;
|
|
839
|
-
const
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
const
|
|
845
|
-
?
|
|
846
|
-
:
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
922
|
+
const provider = typeof rec.provider === "string" ? rec.provider.toLowerCase() : "";
|
|
923
|
+
const externalIdp = provider === "externalidp" ||
|
|
924
|
+
(typeof rec.authMethod === "string" &&
|
|
925
|
+
rec.authMethod.toLowerCase() === "external_idp");
|
|
926
|
+
const socialProvider = provider === "google" || provider === "github" ? provider : undefined;
|
|
927
|
+
const linked = externalIdp || socialProvider
|
|
928
|
+
? undefined
|
|
929
|
+
: await linkedSsoClientRegistration(path, rec);
|
|
930
|
+
const clientId = linked?.clientId ??
|
|
931
|
+
(typeof rec.clientId === "string"
|
|
932
|
+
? rec.clientId
|
|
933
|
+
: typeof rec.client_id === "string"
|
|
934
|
+
? rec.client_id
|
|
935
|
+
: undefined);
|
|
936
|
+
const clientSecret = linked?.clientSecret ??
|
|
937
|
+
(typeof rec.clientSecret === "string"
|
|
938
|
+
? rec.clientSecret
|
|
939
|
+
: typeof rec.client_secret === "string"
|
|
940
|
+
? rec.client_secret
|
|
941
|
+
: undefined);
|
|
942
|
+
const region = typeof rec.region === "string" && AWS_REGION_PATTERN.test(rec.region)
|
|
850
943
|
? rec.region
|
|
851
944
|
: KIRO_DEFAULT_REGION;
|
|
852
|
-
const
|
|
945
|
+
const storedProfileArn = typeof rec.profileArn === "string"
|
|
853
946
|
? rec.profileArn
|
|
854
947
|
: typeof rec.profile_arn === "string"
|
|
855
948
|
? rec.profile_arn
|
|
856
949
|
: undefined;
|
|
950
|
+
const profileArn = storedProfileArn ?? await readKiroIdeProfileArn();
|
|
857
951
|
const startUrl = typeof rec.startUrl === "string"
|
|
858
952
|
? rec.startUrl
|
|
859
953
|
: typeof rec.start_url === "string"
|
|
860
954
|
? rec.start_url
|
|
861
955
|
: undefined;
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
else if (typeof rec.expires_at === "string") {
|
|
867
|
-
expiresAt = Date.parse(rec.expires_at);
|
|
868
|
-
}
|
|
956
|
+
const expiresAt = parseStoredExpiry(rec.expiresAt) ?? parseStoredExpiry(rec.expires_at);
|
|
957
|
+
const authMethod = externalIdp
|
|
958
|
+
? "external_idp"
|
|
959
|
+
: socialProvider ?? (clientId && clientSecret ? "builder-id" : "imported");
|
|
869
960
|
return {
|
|
870
961
|
accessToken,
|
|
871
962
|
refreshToken,
|
|
@@ -873,9 +964,13 @@ export async function readKiroStoredAuth() {
|
|
|
873
964
|
expiresAt,
|
|
874
965
|
region,
|
|
875
966
|
clientId,
|
|
876
|
-
clientSecret,
|
|
967
|
+
clientSecret: externalIdp ? undefined : clientSecret,
|
|
877
968
|
startUrl,
|
|
878
|
-
authMethod
|
|
969
|
+
authMethod,
|
|
970
|
+
...(externalIdp && typeof rec.tokenEndpoint === "string"
|
|
971
|
+
? { tokenEndpoint: rec.tokenEndpoint }
|
|
972
|
+
: {}),
|
|
973
|
+
...(externalIdp ? { scope: normalizeIdpScope(rec.scopes ?? rec.scope) } : {}),
|
|
879
974
|
};
|
|
880
975
|
}
|
|
881
976
|
const home = homedir();
|
|
@@ -913,10 +1008,14 @@ export async function readKiroStoredAuth() {
|
|
|
913
1008
|
"codewhisperer:oidc:device-registration",
|
|
914
1009
|
"codewhisperer:odic:device-registration",
|
|
915
1010
|
];
|
|
916
|
-
const
|
|
917
|
-
if (!
|
|
1011
|
+
const tokenKey = tokenKeys.find((k) => byKey.get(k));
|
|
1012
|
+
if (!tokenKey)
|
|
918
1013
|
continue;
|
|
919
|
-
const
|
|
1014
|
+
const tokenRaw = byKey.get(tokenKey);
|
|
1015
|
+
const socialToken = tokenKey.includes(":social:");
|
|
1016
|
+
const deviceRaw = socialToken
|
|
1017
|
+
? undefined
|
|
1018
|
+
: deviceKeys.map((k) => byKey.get(k)).find((v) => v);
|
|
920
1019
|
try {
|
|
921
1020
|
const parsed = JSON.parse(tokenRaw);
|
|
922
1021
|
const device = deviceRaw
|
|
@@ -964,13 +1063,14 @@ export async function readKiroStoredAuth() {
|
|
|
964
1063
|
: clientId && clientSecret
|
|
965
1064
|
? "builder-id"
|
|
966
1065
|
: "imported";
|
|
1066
|
+
const storedRegion = [parsed.region, device?.region].find((value) => typeof value === "string" && AWS_REGION_PATTERN.test(value));
|
|
967
1067
|
return {
|
|
968
1068
|
accessToken,
|
|
969
1069
|
refreshToken,
|
|
970
1070
|
expiresAt,
|
|
971
1071
|
profileArn,
|
|
972
1072
|
authMethod,
|
|
973
|
-
region: KIRO_DEFAULT_REGION,
|
|
1073
|
+
region: storedRegion ?? KIRO_DEFAULT_REGION,
|
|
974
1074
|
clientId,
|
|
975
1075
|
clientSecret,
|
|
976
1076
|
};
|
|
@@ -989,9 +1089,7 @@ export async function importExistingKiroAuth() {
|
|
|
989
1089
|
const stored = await readKiroStoredAuth();
|
|
990
1090
|
if (!stored)
|
|
991
1091
|
return undefined;
|
|
992
|
-
if (stored.refreshToken &&
|
|
993
|
-
stored.expiresAt !== undefined &&
|
|
994
|
-
stored.expiresAt < Date.now()) {
|
|
1092
|
+
if (stored.refreshToken && kiroCredentialNeedsRefresh(stored)) {
|
|
995
1093
|
try {
|
|
996
1094
|
return await refreshKiroToken(stored.refreshToken, stored);
|
|
997
1095
|
}
|
|
@@ -1001,16 +1099,35 @@ export async function importExistingKiroAuth() {
|
|
|
1001
1099
|
}
|
|
1002
1100
|
return stored;
|
|
1003
1101
|
}
|
|
1004
|
-
export
|
|
1102
|
+
export const KIRO_REFRESH_SKEW_MS = 5 * 60 * 1000;
|
|
1103
|
+
export function kiroCredentialNeedsRefresh(credential, now = Date.now()) {
|
|
1104
|
+
return (credential.expiresAt !== undefined &&
|
|
1105
|
+
Number.isFinite(credential.expiresAt) &&
|
|
1106
|
+
credential.expiresAt - now < KIRO_REFRESH_SKEW_MS);
|
|
1107
|
+
}
|
|
1108
|
+
const inflightKiroRefreshes = new Map();
|
|
1109
|
+
export function maybeRefreshKiroCredential(key, storedRefreshToken) {
|
|
1005
1110
|
const decoded = decodeKiroKey(key);
|
|
1006
1111
|
const refreshToken = decoded?.refreshToken || storedRefreshToken;
|
|
1007
1112
|
if (!refreshToken)
|
|
1008
|
-
return undefined;
|
|
1113
|
+
return Promise.resolve(undefined);
|
|
1114
|
+
const inflight = inflightKiroRefreshes.get(refreshToken);
|
|
1115
|
+
if (inflight)
|
|
1116
|
+
return inflight;
|
|
1117
|
+
const pending = refreshKiroKey(refreshToken, decoded).finally(() => {
|
|
1118
|
+
inflightKiroRefreshes.delete(refreshToken);
|
|
1119
|
+
});
|
|
1120
|
+
inflightKiroRefreshes.set(refreshToken, pending);
|
|
1121
|
+
return pending;
|
|
1122
|
+
}
|
|
1123
|
+
async function refreshKiroKey(refreshToken, decoded) {
|
|
1009
1124
|
try {
|
|
1010
1125
|
const refreshed = await refreshKiroToken(refreshToken, decoded);
|
|
1011
1126
|
return encodeKiroKey(refreshed);
|
|
1012
1127
|
}
|
|
1013
|
-
catch {
|
|
1128
|
+
catch (error) {
|
|
1129
|
+
if (error instanceof KiroRefreshError && error.reauthRequired)
|
|
1130
|
+
throw error;
|
|
1014
1131
|
return undefined;
|
|
1015
1132
|
}
|
|
1016
1133
|
}
|
|
@@ -1032,6 +1149,8 @@ function parseModelInfo(value) {
|
|
|
1032
1149
|
const inputTypes = Array.isArray(rec.supportedInputTypes)
|
|
1033
1150
|
? rec.supportedInputTypes
|
|
1034
1151
|
: undefined;
|
|
1152
|
+
const promptCaching = asRecord(rec.promptCaching);
|
|
1153
|
+
const requestFieldsSchema = asRecord(rec.additionalModelRequestFieldsSchema);
|
|
1035
1154
|
return {
|
|
1036
1155
|
modelId,
|
|
1037
1156
|
modelName: typeof rec.modelName === "string" ? rec.modelName : undefined,
|
|
@@ -1042,6 +1161,14 @@ function parseModelInfo(value) {
|
|
|
1042
1161
|
supportsImages: inputTypes
|
|
1043
1162
|
? inputTypes.some((t) => typeof t === "string" && t.toUpperCase() === "IMAGE")
|
|
1044
1163
|
: undefined,
|
|
1164
|
+
promptCaching: promptCaching && typeof promptCaching.supportsPromptCaching === "boolean"
|
|
1165
|
+
? {
|
|
1166
|
+
supportsPromptCaching: promptCaching.supportsPromptCaching,
|
|
1167
|
+
maximumCacheCheckpointsPerRequest: optionalNumber(promptCaching.maximumCacheCheckpointsPerRequest),
|
|
1168
|
+
minimumTokensPerCacheCheckpoint: optionalNumber(promptCaching.minimumTokensPerCacheCheckpoint),
|
|
1169
|
+
}
|
|
1170
|
+
: undefined,
|
|
1171
|
+
additionalModelRequestFieldsSchema: requestFieldsSchema ?? undefined,
|
|
1045
1172
|
};
|
|
1046
1173
|
}
|
|
1047
1174
|
function kiroCatalogHeaders(credential) {
|
|
@@ -1062,22 +1189,66 @@ function kiroCatalogHeaders(credential) {
|
|
|
1062
1189
|
}
|
|
1063
1190
|
return headers;
|
|
1064
1191
|
}
|
|
1065
|
-
export async function
|
|
1066
|
-
const
|
|
1192
|
+
export async function discoverKiroModelsDetailed(credential) {
|
|
1193
|
+
const legacyRegion = assertValidAwsRegion(credential.region);
|
|
1194
|
+
const apiRegion = resolveKiroRuntimeRegion(credential);
|
|
1067
1195
|
const params = new URLSearchParams({ origin: "AI_EDITOR" });
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1196
|
+
if (credential.profileArn)
|
|
1197
|
+
params.set("profileArn", credential.profileArn);
|
|
1198
|
+
const baseHeaders = kiroCatalogHeaders(credential);
|
|
1199
|
+
const requests = [
|
|
1200
|
+
{
|
|
1201
|
+
generation: "modern",
|
|
1202
|
+
url: `https://management.${apiRegion}.kiro.dev/`,
|
|
1203
|
+
init: {
|
|
1204
|
+
method: "POST",
|
|
1205
|
+
headers: {
|
|
1206
|
+
...baseHeaders,
|
|
1207
|
+
"Content-Type": "application/x-amz-json-1.0",
|
|
1208
|
+
"X-Amz-Target": "AmazonCodeWhispererService.ListAvailableModels",
|
|
1209
|
+
},
|
|
1210
|
+
body: JSON.stringify({
|
|
1211
|
+
origin: "KIRO_CLI",
|
|
1212
|
+
...(credential.profileArn ? { profileArn: credential.profileArn } : {}),
|
|
1213
|
+
}),
|
|
1214
|
+
},
|
|
1215
|
+
},
|
|
1216
|
+
{
|
|
1217
|
+
generation: "legacy",
|
|
1218
|
+
url: `https://q.${legacyRegion}.amazonaws.com/ListAvailableModels?${params.toString()}`,
|
|
1219
|
+
init: { method: "GET", headers: baseHeaders },
|
|
1220
|
+
},
|
|
1221
|
+
];
|
|
1222
|
+
let lastStatus;
|
|
1223
|
+
let lastError;
|
|
1224
|
+
for (const request of requests) {
|
|
1225
|
+
try {
|
|
1226
|
+
const response = await fetch(request.url, {
|
|
1227
|
+
...request.init,
|
|
1228
|
+
signal: AbortSignal.timeout(15_000),
|
|
1229
|
+
});
|
|
1230
|
+
if (!response.ok) {
|
|
1231
|
+
lastStatus = response.status;
|
|
1232
|
+
continue;
|
|
1233
|
+
}
|
|
1234
|
+
const json = asRecord(await response.json().catch(() => ({})));
|
|
1235
|
+
const models = Array.isArray(json?.models) ? json.models : [];
|
|
1236
|
+
return {
|
|
1237
|
+
models: models
|
|
1238
|
+
.map(parseModelInfo)
|
|
1239
|
+
.filter((info) => info !== undefined),
|
|
1240
|
+
generation: request.generation,
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
catch (error) {
|
|
1244
|
+
lastError = error;
|
|
1245
|
+
}
|
|
1075
1246
|
}
|
|
1076
|
-
const
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1247
|
+
const detail = lastError instanceof Error ? `: ${lastError.message}` : "";
|
|
1248
|
+
throw new Error(`ListAvailableModels failed${lastStatus ? ` (HTTP ${lastStatus})` : ""}${detail}`);
|
|
1249
|
+
}
|
|
1250
|
+
export async function listKiroModelsDetailed(credential) {
|
|
1251
|
+
return (await discoverKiroModelsDetailed(credential)).models;
|
|
1081
1252
|
}
|
|
1082
1253
|
export async function getKiroUsageLimits(credential) {
|
|
1083
1254
|
const region = assertValidAwsRegion(credential.region);
|