ns-omp-provider 0.1.0 → 0.3.0

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/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0
4
+
5
+ - **Breaking: `kiro` is now opt-in.** By default only `devin` and `grok` (+ `grok-sdk`)
6
+ are registered, so this package no longer shadows the dedicated
7
+ [`ns-omp-provider-kiro`](https://www.npmjs.com/package/ns-omp-provider-kiro) plugin
8
+ (the recommended Kiro path in OMP). Opt in with `NS_OMP_PROVIDER_ENABLE=kiro` or by
9
+ listing it in `NS_OMP_PROVIDERS` (e.g. `NS_OMP_PROVIDERS=devin,grok,kiro`).
10
+ `NS_OMP_PROVIDER_DISABLE` still works and is applied last; the old
11
+ `NS_OMP_PROVIDER_DISABLE=kiro` workaround is no longer needed.
12
+ - Bundles `@ngosangns/ns-pi-provider@0.2.1`: Kiro now honours `metadataEvent` stop
13
+ reasons — `MAX_TOKENS` → `length` (OMP skips truncated tool calls instead of running
14
+ them with partial arguments), `CONTENT_FILTERED` / `MODEL_CONTEXT_WINDOW_EXCEEDED` /
15
+ `PAUSE_TURN` and mid-stream exception frames end as errors, and reported token usage
16
+ is read. Only relevant when `kiro` is opted in.
17
+
18
+ ## 0.2.0
19
+
20
+ Bundles `@ngosangns/ns-pi-provider@0.2.0` (was 0.1.7).
21
+
22
+ - **Breaking (kiro):** the Kiro catalog now comes only from `ListAvailableModels`.
23
+ Without a Kiro credential or a saved catalog snapshot the `kiro` provider
24
+ registers with zero models, and derived `-1m` variants (e.g.
25
+ `claude-sonnet-4-6-1m`) are gone. Wire model ids are sent in Kiro's dot form
26
+ (`claude-sonnet-4.5`), fixing `INVALID_MODEL_ID` on discovered models. Users
27
+ with `NS_OMP_PROVIDER_DISABLE=kiro` are unaffected.
28
+ - fix(grok): `session_shutdown` disposes only that session's Grok ACP agent
29
+ (upstream pi-grok-sdk `45fde95`); switching or closing one session no longer
30
+ kills other sessions' agents, and one process-exit hook is installed per
31
+ process instead of per registration.
32
+ - No compat-shim changes needed: 0.2.0 adds no new `@earendil-works/pi-ai`
33
+ runtime imports.
34
+
3
35
  ## 0.1.0
4
36
 
5
37
  - Initial release: OMP wrapper around `@ngosangns/ns-pi-provider` 0.1.7.
package/README.md CHANGED
@@ -10,7 +10,7 @@ compat layer.
10
10
 
11
11
  | Provider | Auth | Notes |
12
12
  |----------|------|-------|
13
- | `kiro` | OAuth (`/login kiro`) + `KIRO_API_KEY` / SSO cache | Overlaps with [`ns-omp-provider-kiro`](https://www.npmjs.com/package/ns-omp-provider-kiro) — see below |
13
+ | `kiro` (**opt-in**) | OAuth (`/login kiro`) + `KIRO_API_KEY` / SSO cache | Off by default — use [`ns-omp-provider-kiro`](https://www.npmjs.com/package/ns-omp-provider-kiro); see below |
14
14
  | `devin` | OAuth (`/login devin`) + `credentials.toml` / env | Swe-2 catalog when authenticated |
15
15
  | `grok` (+ `grok-sdk` alias) | Local `grok` CLI / `~/.grok` / `XAI_API_KEY` | Commands: `/grok status \| models \| refresh` |
16
16
 
@@ -19,7 +19,7 @@ Shared command: `/ns-pi status | refresh [all\|kiro\|devin\|grok]`.
19
19
  ## Install
20
20
 
21
21
  ```bash
22
- # from npm (after first publish)
22
+ # from npm
23
23
  omp plugin install ns-omp-provider
24
24
 
25
25
  # from git
@@ -36,17 +36,24 @@ omp -e ./dist/index.js ...
36
36
  Then `/login kiro` or `/login devin` as needed. Grok uses the local `grok`
37
37
  CLI / `~/.grok` auth (or `XAI_API_KEY`).
38
38
 
39
- ### Avoiding a duplicate `kiro` provider
39
+ ### Choosing providers (`kiro` is opt-in)
40
40
 
41
- If you already use [`ns-omp-provider-kiro`](https://www.npmjs.com/package/ns-omp-provider-kiro),
42
- disable this package's kiro registration:
41
+ By default this package registers **`devin`** and **`grok`** (+ `grok-sdk`) only.
42
+ For Kiro in OMP, the recommended path is the dedicated
43
+ [`ns-omp-provider-kiro`](https://www.npmjs.com/package/ns-omp-provider-kiro) plugin;
44
+ this package's `kiro` stays off so it never shadows that plugin.
43
45
 
44
46
  ```bash
45
- # in the shell that launches omp, or via your shell profile / omp env
46
- export NS_OMP_PROVIDER_DISABLE=kiro
47
+ # opt in to this package's kiro (in the environment that launches omp)
48
+ export NS_OMP_PROVIDER_ENABLE=kiro
49
+ # or allow-list exactly what you want
50
+ export NS_OMP_PROVIDERS=devin,grok,kiro
51
+ # deny-list, applied last (e.g. drop grok)
52
+ export NS_OMP_PROVIDER_DISABLE=grok
47
53
  ```
48
54
 
49
- Or allow-list only what you want: `NS_OMP_PROVIDERS=devin,grok`.
55
+ Don't opt in to `kiro` while `ns-omp-provider-kiro` is installed — both would
56
+ register the same `kiro` provider id.
50
57
 
51
58
  ## How the wrapper works
52
59
 
@@ -72,12 +79,16 @@ Or allow-list only what you want: `NS_OMP_PROVIDERS=devin,grok`.
72
79
 
73
80
  - **`session_info_changed`** — OMP has no equivalent; the grok handler is a
74
81
  documented no-op (name changes do not re-key the agent pool).
75
- - **Duplicate `kiro`** — see `NS_OMP_PROVIDER_DISABLE` above.
82
+ - **Duplicate `kiro`** — `kiro` is opt-in; don't enable it alongside `ns-omp-provider-kiro`.
76
83
  - **Unauthenticated catalogs** — without credentials, OMP may hide a provider's
77
84
  models from `omp models` even though the provider is registered. After
78
85
  `/login` (or with CLI creds present) the live catalog, including Devin
79
86
  `swe-2-*`, appears via `fetchDynamicModels`.
80
- - **Upstream pin** — this release bundles `@ngosangns/ns-pi-provider@0.1.7`.
87
+ - **Kiro catalog** (when opted in) — models come only from Kiro's `ListAvailableModels`
88
+ (since ns-pi-provider 0.2.0): with no Kiro credential and no saved catalog
89
+ snapshot, `kiro` registers zero models, and `-1m` long-context variants are
90
+ not offered.
91
+ - **Upstream pin** — this release bundles `@ngosangns/ns-pi-provider@0.2.1`.
81
92
  Bumping it is a deliberate change (rebuild + retest).
82
93
 
83
94
  ## Development
@@ -95,14 +106,14 @@ your real `~/.omp`.
95
106
 
96
107
  ## Publish
97
108
 
98
- Push a tag matching `package.json` (e.g. `v0.1.0`) to run
109
+ Push a tag matching `package.json` (e.g. `v0.3.0`) to run
99
110
  [`.github/workflows/publish.yml`](.github/workflows/publish.yml), which
100
111
  publishes with **provenance** from a GitHub-hosted runner:
101
112
 
102
113
  ```bash
103
114
  # bump "version" in package.json first, then
104
115
  npm run check
105
- git tag v0.1.0 && git push origin v0.1.0
116
+ git tag v0.3.0 && git push origin v0.3.0
106
117
  ```
107
118
 
108
119
  Auth, in the order npm tries it:
package/dist/config.d.ts CHANGED
@@ -3,8 +3,17 @@ export declare const PROVIDER_KEYS: readonly ["kiro", "devin", "grok"];
3
3
  export type ProviderKey = (typeof PROVIDER_KEYS)[number];
4
4
  export type ProviderSelection = Record<ProviderKey, boolean>;
5
5
  /**
6
- * - `NS_OMP_PROVIDERS=devin,grok` — allow-list (only these are registered).
7
- * - `NS_OMP_PROVIDER_DISABLE=kiro` — deny-list, applied after the allow-list.
8
- * Default: all three.
6
+ * Providers that stay off unless explicitly requested. `kiro` is opt-in because
7
+ * the dedicated `ns-omp-provider-kiro` plugin is the recommended Kiro path in
8
+ * OMP; registering a second `kiro` here would shadow it.
9
+ */
10
+ export declare const OPT_IN_PROVIDERS: ReadonlySet<ProviderKey>;
11
+ /**
12
+ * - `NS_OMP_PROVIDERS=devin,grok,kiro` — allow-list (only these are registered;
13
+ * listing `kiro` here opts it in).
14
+ * - `NS_OMP_PROVIDER_ENABLE=kiro` — opt in to opt-in providers on top of the
15
+ * default set (or the allow-list).
16
+ * - `NS_OMP_PROVIDER_DISABLE=grok` — deny-list, applied last.
17
+ * Default: `devin` and `grok`; `kiro` is opt-in.
9
18
  */
10
19
  export declare function resolveProviderSelection(env?: NodeJS.ProcessEnv): ProviderSelection;
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // ns-omp-provider 0.1.0 — bundles @ngosangns/ns-pi-provider@0.1.7 (MIT). See NOTICE.
1
+ // ns-omp-provider 0.3.0 — bundles @ngosangns/ns-pi-provider@0.2.1 (MIT). See NOTICE.
2
2
  import { createRequire as __nsOmpCreateRequire } from 'node:module';
3
3
  const require = __nsOmpCreateRequire(import.meta.url);
4
4
  var __defProp = Object.defineProperty;
@@ -696,9 +696,10 @@ function omitInternalKiroHeaders(headers) {
696
696
  return Object.keys(filtered).length > 0 ? filtered : void 0;
697
697
  }
698
698
  function buildRequest(model, context, config, options) {
699
- const { history, currentMessage } = convertMessages(context, model.id);
699
+ const wireModelId = model.id.replace(/(\d)-(\d)/g, "$1.$2");
700
+ const { history, currentMessage } = convertMessages(context, wireModelId);
700
701
  const firstContent = firstUserConversationContent(history, currentMessage);
701
- prependSystemInstructionHistory(history, buildSystemPrefix(context), model.id);
702
+ prependSystemInstructionHistory(history, buildSystemPrefix(context), wireModelId);
702
703
  const amazonQEndpoint = isAmazonQEndpoint(config);
703
704
  if (amazonQEndpoint) setUserMessageOrigin(history, currentMessage, "KIRO_CLI");
704
705
  const profileArn = getHeaderCaseInsensitive(options?.headers, KIRO_PROFILE_ARN_HEADER) ?? config.profileArn;
@@ -881,6 +882,65 @@ function buildUsage(model, tokens) {
881
882
  calculateCost(model, usage);
882
883
  return usage;
883
884
  }
885
+ function optionalCount(value2) {
886
+ return typeof value2 === "number" && Number.isFinite(value2) && value2 >= 0 ? value2 : void 0;
887
+ }
888
+ function firstCount(record2, keys) {
889
+ for (const key of keys) {
890
+ const value2 = optionalCount(record2[key]);
891
+ if (value2 !== void 0) return value2;
892
+ }
893
+ return void 0;
894
+ }
895
+ function applyKiroMetadata(state2, model, payload) {
896
+ const metadata = isRecord(payload.metadataEvent) ? payload.metadataEvent : payload;
897
+ const stopReason = nonEmptyString(metadata.stopReason);
898
+ if (stopReason) state2.wireStopReason = stopReason;
899
+ if (isRecord(metadata.stopDetails)) state2.wireStopDetails = metadata.stopDetails;
900
+ const tokenUsage = isRecord(metadata.tokenUsage) ? metadata.tokenUsage : void 0;
901
+ if (!tokenUsage) return;
902
+ const percentage2 = numberFrom(tokenUsage.contextUsagePercentage);
903
+ if (percentage2 > 0) state2.contextUsagePercentage = percentage2;
904
+ const next = {
905
+ input: optionalCount(tokenUsage.uncachedInputTokens) ?? optionalCount(tokenUsage.inputTokens),
906
+ output: optionalCount(tokenUsage.outputTokens),
907
+ cacheRead: firstCount(tokenUsage, CACHE_READ_KEYS),
908
+ cacheWrite: firstCount(tokenUsage, CACHE_WRITE_KEYS)
909
+ };
910
+ const merged = { ...state2.wireTokens ?? {} };
911
+ for (const [key, value2] of Object.entries(next)) {
912
+ if (value2 !== void 0) merged[key] = value2;
913
+ }
914
+ state2.wireTokens = merged;
915
+ const tokens = { input: merged.input ?? 0, output: merged.output ?? 0, cacheRead: merged.cacheRead ?? 0, cacheWrite: merged.cacheWrite ?? 0 };
916
+ if (tokens.input > 0 || tokens.output > 0 || tokens.cacheRead > 0 || tokens.cacheWrite > 0) {
917
+ state2.usage = buildUsage(model, tokens);
918
+ }
919
+ }
920
+ function clampForDiagnostic(text2) {
921
+ return text2.length <= DIAGNOSTIC_QUOTE_LIMIT ? text2 : `${text2.slice(0, DIAGNOSTIC_QUOTE_LIMIT)}\u2026 (truncated)`;
922
+ }
923
+ function throwOnTerminalWireStop(state2) {
924
+ switch (state2.wireStopReason) {
925
+ case "MODEL_CONTEXT_WINDOW_EXCEEDED":
926
+ throw new Error("Kiro API error: context_length_exceeded (MODEL_CONTEXT_WINDOW_EXCEEDED): the model context window exceeded its limit");
927
+ case "CONTENT_FILTERED":
928
+ throw new Error(`Kiro content filtered (CONTENT_FILTERED): ${clampForDiagnostic(redactSensitiveString(JSON.stringify(state2.wireStopDetails ?? {})))}`);
929
+ case "PAUSE_TURN":
930
+ throw new Error("Kiro paused the turn (PAUSE_TURN); automatic continuation is not supported");
931
+ }
932
+ }
933
+ function resolveStopReason(state2) {
934
+ if (state2.wireStopReason === "MAX_TOKENS") return "length";
935
+ return state2.hasToolCalls ? "toolUse" : "stop";
936
+ }
937
+ function throwOnExceptionFrame(headers, payload) {
938
+ const messageType = headers[":message-type"];
939
+ if (messageType !== "exception" && messageType !== "error") return;
940
+ const kind = headers[":exception-type"] ?? headers[":error-code"] ?? "error";
941
+ const message2 = (payload ? nonEmptyString(payload.message) ?? nonEmptyString(payload.Message) ?? nonEmptyString(payload.error) : void 0) ?? headers[":error-message"] ?? "";
942
+ throw new Error(`Kiro stream ${kind}: ${clampForDiagnostic(redactSensitiveString(message2 || "no details"))}`);
943
+ }
884
944
  function usageFromMetrics(model, metrics) {
885
945
  const input = numberFrom(metrics.inputTokens);
886
946
  const output = numberFrom(metrics.outputTokens);
@@ -1064,6 +1124,10 @@ function handleEvent(stream, output, state2, model, eventType, payload) {
1064
1124
  if (percentage2 > 0) state2.contextUsagePercentage = percentage2;
1065
1125
  return;
1066
1126
  }
1127
+ if (eventType === "metadataEvent") {
1128
+ applyKiroMetadata(state2, model, payload);
1129
+ return;
1130
+ }
1067
1131
  if (eventType === "metricsEvent") {
1068
1132
  const metrics = isRecord(payload.metricsEvent) ? payload.metricsEvent : payload;
1069
1133
  state2.usage = usageFromMetrics(model, metrics);
@@ -1091,15 +1155,17 @@ async function consumeKiroEventStream(response, stream, output, model, logger) {
1091
1155
  if (!frameBytes) break;
1092
1156
  const frame = parseEventFrame(frameBytes, logger);
1093
1157
  if (!frame) continue;
1158
+ throwOnExceptionFrame(frame.headers, frame.payload);
1094
1159
  handleEvent(stream, output, state2, model, frame.headers[":event-type"] ?? "", frame.payload);
1095
1160
  }
1096
1161
  if (iterations >= 1e3) logger.warn("eventstream_iteration_limit_reached", { remainingBytes: queue.length });
1097
1162
  }
1163
+ throwOnTerminalWireStop(state2);
1098
1164
  closeThinkingBlock(stream, output, state2);
1099
1165
  closeTextBlock(stream, output, state2);
1100
1166
  closeToolCalls(stream, output, state2);
1101
1167
  output.usage = state2.usage ?? estimatedUsage(model, state2) ?? output.usage;
1102
- output.stopReason = state2.hasToolCalls ? "toolUse" : "stop";
1168
+ output.stopReason = resolveStopReason(state2);
1103
1169
  stream.push({ type: "done", reason: output.stopReason, message: output });
1104
1170
  stream.end(output);
1105
1171
  }
@@ -1146,7 +1212,7 @@ function createKiroStream(config, _runtime, logger) {
1146
1212
  return stream;
1147
1213
  };
1148
1214
  }
1149
- var ENV_VAR_PATTERN, DEFAULT_MAX_OUTPUT_TOKENS, API_MAX_OUTPUT_TOKENS, KIRO_NAMESPACE, KIRO_STREAMING_TARGET, KIRO_CODEWHISPERER_SDK_USER_AGENT, KIRO_CODEWHISPERER_AMZ_USER_AGENT, KIRO_Q_SDK_USER_AGENT, KIRO_Q_AMZ_USER_AGENT, KIRO_CLI_CONTEXT_BLOCK_PATTERN, KIRO_CLI_USER_MESSAGE_PATTERN, KiroAuthFailureError;
1215
+ var ENV_VAR_PATTERN, DEFAULT_MAX_OUTPUT_TOKENS, API_MAX_OUTPUT_TOKENS, KIRO_NAMESPACE, KIRO_STREAMING_TARGET, KIRO_CODEWHISPERER_SDK_USER_AGENT, KIRO_CODEWHISPERER_AMZ_USER_AGENT, KIRO_Q_SDK_USER_AGENT, KIRO_Q_AMZ_USER_AGENT, KIRO_CLI_CONTEXT_BLOCK_PATTERN, KIRO_CLI_USER_MESSAGE_PATTERN, KiroAuthFailureError, CACHE_READ_KEYS, CACHE_WRITE_KEYS, DIAGNOSTIC_QUOTE_LIMIT;
1150
1216
  var init_stream_oauth = __esm({
1151
1217
  "node_modules/@ngosangns/ns-pi-provider/src/kiro/stream-oauth.ts"() {
1152
1218
  init_pi_ai();
@@ -1173,6 +1239,9 @@ var init_stream_oauth = __esm({
1173
1239
  this.kiroAuth = { ...metadata };
1174
1240
  }
1175
1241
  };
1242
+ CACHE_READ_KEYS = ["cacheReadInputTokens", "cache_read_input_tokens", "cacheReadTokens"];
1243
+ CACHE_WRITE_KEYS = ["cacheWriteInputTokens", "cache_creation_input_tokens", "cacheCreationInputTokens", "cacheCreationTokens"];
1244
+ DIAGNOSTIC_QUOTE_LIMIT = 500;
1176
1245
  }
1177
1246
  });
1178
1247
 
@@ -1368,9 +1437,6 @@ import { readFileSync as readFileSync2 } from "node:fs";
1368
1437
  import { join as join2 } from "node:path";
1369
1438
  var KIRO_API = "kiro";
1370
1439
  var KIRO_MAX_OUTPUT_TOKENS = 32e3;
1371
- var KIRO_PROMPT_CACHING_1024 = { supportsPromptCaching: true, maximumCacheCheckpointsPerRequest: 4, minimumTokensPerCacheCheckpoint: 1024 };
1372
- var KIRO_PROMPT_CACHING_4096 = { supportsPromptCaching: true, maximumCacheCheckpointsPerRequest: 4, minimumTokensPerCacheCheckpoint: 4096 };
1373
- var KIRO_PROMPT_CACHING_DISABLED = { supportsPromptCaching: false };
1374
1440
  var ANTHROPIC_REASONING_MAP = { off: "disabled", minimal: "low", low: "low", medium: "medium", high: "high", xhigh: null };
1375
1441
  var ANTHROPIC_OPUS_4_7_REASONING_MAP = { ...ANTHROPIC_REASONING_MAP, xhigh: "xhigh" };
1376
1442
  var ANTHROPIC_MAX_REASONING_MAP = { ...ANTHROPIC_REASONING_MAP, xhigh: "max" };
@@ -1380,21 +1446,6 @@ function defaultThinkingLevelMapForModel(id, name) {
1380
1446
  if (/claude[-\s_/]*(?:opus|sonnet)[-\s_/]*4[.-]?6\b/.test(identity)) return { ...ANTHROPIC_MAX_REASONING_MAP };
1381
1447
  return void 0;
1382
1448
  }
1383
- var DEFAULT_MODELS = [
1384
- { id: "auto", name: "Auto", reasoning: true, contextWindow: 1e6, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 1, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_1024, importOwnership: "model-discovery" },
1385
- { id: "claude-opus-4.7", name: "Claude Opus 4.7", reasoning: true, thinkingLevelMap: ANTHROPIC_OPUS_4_7_REASONING_MAP, contextWindow: 1e6, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 2.2, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_4096, importOwnership: "model-discovery" },
1386
- { id: "claude-opus-4.6", name: "Claude Opus 4.6", reasoning: true, thinkingLevelMap: ANTHROPIC_MAX_REASONING_MAP, contextWindow: 1e6, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 2.2, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_4096, importOwnership: "model-discovery" },
1387
- { id: "claude-sonnet-4.6", name: "Claude Sonnet 4.6", reasoning: true, thinkingLevelMap: ANTHROPIC_MAX_REASONING_MAP, contextWindow: 1e6, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 1.3, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_1024, importOwnership: "model-discovery" },
1388
- { id: "claude-opus-4.5", name: "Claude Opus 4.5", reasoning: true, contextWindow: 2e5, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 2.2, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_4096, importOwnership: "model-discovery" },
1389
- { id: "claude-sonnet-4.5", name: "Claude Sonnet 4.5", reasoning: true, contextWindow: 2e5, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 1.3, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_1024, importOwnership: "model-discovery" },
1390
- { id: "claude-sonnet-4", name: "Claude Sonnet 4", reasoning: true, contextWindow: 2e5, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 1.3, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_1024, importOwnership: "model-discovery" },
1391
- { id: "claude-haiku-4.5", name: "Claude Haiku 4.5", reasoning: true, contextWindow: 2e5, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 0.4, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_4096, importOwnership: "model-discovery" },
1392
- { id: "deepseek-3.2", name: "DeepSeek 3.2", reasoning: true, contextWindow: 164e3, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 0.25, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_DISABLED, importOwnership: "model-discovery" },
1393
- { id: "minimax-m2.5", name: "MiniMax M2.5", reasoning: true, contextWindow: 196e3, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 0.25, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_DISABLED, importOwnership: "model-discovery" },
1394
- { id: "minimax-m2.1", name: "MiniMax M2.1", reasoning: true, contextWindow: 196e3, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 0.15, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_DISABLED, importOwnership: "model-discovery" },
1395
- { id: "glm-5", name: "GLM-5", reasoning: true, contextWindow: 2e5, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 0.5, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_DISABLED, importOwnership: "model-discovery" },
1396
- { id: "qwen3-coder-next", name: "Qwen3 Coder Next", reasoning: true, contextWindow: 256e3, maxTokens: KIRO_MAX_OUTPUT_TOKENS, rateMultiplier: 0.05, rateUnit: "Credit", promptCaching: KIRO_PROMPT_CACHING_DISABLED, importOwnership: "model-discovery" }
1397
- ];
1398
1449
  var DEFAULT_MODEL_DEFAULTS = {
1399
1450
  reasoning: true,
1400
1451
  input: ["text"],
@@ -1602,11 +1653,7 @@ function loadConfig(extensionRoot) {
1602
1653
  const warnings = [];
1603
1654
  const raw = readRawConfig(extensionRoot, warnings);
1604
1655
  const defaults = modelDefaultsFrom(raw, warnings);
1605
- const models = normalizeModelList(Array.isArray(raw.models) ? raw.models : DEFAULT_MODELS, defaults, warnings);
1606
- if (models.length === 0) {
1607
- warnings.push("No valid models were configured; using the default Kiro model list.");
1608
- models.push(...normalizeModelList(DEFAULT_MODELS, defaults, warnings));
1609
- }
1656
+ const models = normalizeModelList(Array.isArray(raw.models) ? raw.models : [], defaults, warnings);
1610
1657
  const upstreamUrl = stringOr(raw.upstreamUrl, "https://codewhisperer.us-east-1.amazonaws.com/generateAssistantResponse");
1611
1658
  return {
1612
1659
  config: {
@@ -2273,244 +2320,20 @@ var log = {
2273
2320
  isDebug: () => enabled("debug")
2274
2321
  };
2275
2322
 
2276
- // node_modules/@ngosangns/ns-pi-provider/src/kiro/transform.ts
2277
- var KIRO_ORIGIN = "AI_EDITOR";
2278
-
2279
- // node_modules/@ngosangns/ns-pi-provider/src/kiro/models.ts
2280
- var discoveredModelIds = /* @__PURE__ */ new Set();
2281
- function setDiscoveredModelIds(kiroIds) {
2282
- discoveredModelIds.clear();
2283
- for (const id of kiroIds) discoveredModelIds.add(id);
2284
- }
2285
- var BASE_URL = "https://q.us-east-1.amazonaws.com/";
2286
- var ZERO_COST = Object.freeze({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0 });
2287
- var KIRO_DEFAULTS = {
2288
- api: "kiro-api",
2289
- provider: "kiro",
2290
- baseUrl: BASE_URL,
2291
- cost: ZERO_COST
2292
- };
2293
- var MULTIMODAL = ["text", "image"];
2294
- var TEXT_ONLY = ["text"];
2295
- var kiroModels = [
2296
- {
2297
- ...KIRO_DEFAULTS,
2298
- id: "claude-opus-4-8",
2299
- name: "Claude Opus 4.8",
2300
- reasoning: true,
2301
- reasoningHidden: true,
2302
- input: MULTIMODAL,
2303
- contextWindow: 1e6,
2304
- maxTokens: 128e3,
2305
- firstTokenTimeout: 18e4
2306
- },
2307
- {
2308
- ...KIRO_DEFAULTS,
2309
- id: "claude-opus-4-7",
2310
- name: "Claude Opus 4.7",
2311
- reasoning: true,
2312
- reasoningHidden: true,
2313
- input: MULTIMODAL,
2314
- contextWindow: 1e6,
2315
- maxTokens: 128e3,
2316
- firstTokenTimeout: 18e4
2317
- },
2318
- {
2319
- ...KIRO_DEFAULTS,
2320
- id: "claude-opus-4-6",
2321
- name: "Claude Opus 4.6",
2322
- reasoning: true,
2323
- input: MULTIMODAL,
2324
- contextWindow: 2e5,
2325
- maxTokens: 32768
2326
- },
2327
- {
2328
- ...KIRO_DEFAULTS,
2329
- id: "claude-opus-4-6-1m",
2330
- name: "Claude Opus 4.6 (1M)",
2331
- reasoning: true,
2332
- input: MULTIMODAL,
2333
- contextWindow: 1e6,
2334
- maxTokens: 32768
2335
- },
2336
- {
2337
- ...KIRO_DEFAULTS,
2338
- id: "claude-sonnet-4-6",
2339
- name: "Claude Sonnet 4.6",
2340
- reasoning: true,
2341
- input: MULTIMODAL,
2342
- contextWindow: 2e5,
2343
- maxTokens: 65536
2344
- },
2345
- {
2346
- ...KIRO_DEFAULTS,
2347
- id: "claude-sonnet-4-6-1m",
2348
- name: "Claude Sonnet 4.6 (1M)",
2349
- reasoning: true,
2350
- input: MULTIMODAL,
2351
- contextWindow: 1e6,
2352
- maxTokens: 65536
2353
- },
2354
- {
2355
- ...KIRO_DEFAULTS,
2356
- id: "claude-opus-4-5",
2357
- name: "Claude Opus 4.5",
2358
- reasoning: true,
2359
- input: MULTIMODAL,
2360
- contextWindow: 2e5,
2361
- maxTokens: 32768
2362
- },
2363
- {
2364
- ...KIRO_DEFAULTS,
2365
- id: "claude-sonnet-4-5",
2366
- name: "Claude Sonnet 4.5",
2367
- reasoning: true,
2368
- input: MULTIMODAL,
2369
- contextWindow: 2e5,
2370
- maxTokens: 65536
2371
- },
2372
- {
2373
- ...KIRO_DEFAULTS,
2374
- id: "claude-sonnet-4-5-1m",
2375
- name: "Claude Sonnet 4.5 (1M)",
2376
- reasoning: true,
2377
- input: MULTIMODAL,
2378
- contextWindow: 1e6,
2379
- maxTokens: 65536
2380
- },
2381
- {
2382
- ...KIRO_DEFAULTS,
2383
- id: "claude-sonnet-4",
2384
- name: "Claude Sonnet 4",
2385
- reasoning: true,
2386
- input: MULTIMODAL,
2387
- contextWindow: 2e5,
2388
- maxTokens: 65536
2389
- },
2390
- {
2391
- ...KIRO_DEFAULTS,
2392
- id: "claude-haiku-4-5",
2393
- name: "Claude Haiku 4.5",
2394
- reasoning: false,
2395
- input: MULTIMODAL,
2396
- contextWindow: 2e5,
2397
- maxTokens: 65536
2398
- },
2399
- {
2400
- ...KIRO_DEFAULTS,
2401
- id: "deepseek-3-2",
2402
- name: "DeepSeek 3.2",
2403
- reasoning: true,
2404
- input: TEXT_ONLY,
2405
- contextWindow: 128e3,
2406
- maxTokens: 8192
2407
- },
2408
- {
2409
- ...KIRO_DEFAULTS,
2410
- id: "kimi-k2-5",
2411
- name: "Kimi K2.5",
2412
- reasoning: true,
2413
- input: TEXT_ONLY,
2414
- contextWindow: 2e5,
2415
- maxTokens: 8192
2416
- },
2417
- {
2418
- ...KIRO_DEFAULTS,
2419
- id: "minimax-m2-5",
2420
- name: "MiniMax M2.5",
2421
- reasoning: false,
2422
- input: TEXT_ONLY,
2423
- contextWindow: 2e5,
2424
- maxTokens: 8192
2425
- },
2426
- {
2427
- ...KIRO_DEFAULTS,
2428
- id: "minimax-m2-1",
2429
- name: "MiniMax M2.1",
2430
- reasoning: false,
2431
- input: TEXT_ONLY,
2432
- contextWindow: 2e5,
2433
- maxTokens: 8192
2434
- },
2435
- {
2436
- ...KIRO_DEFAULTS,
2437
- id: "glm-4-7",
2438
- name: "GLM 4.7",
2439
- reasoning: true,
2440
- input: TEXT_ONLY,
2441
- contextWindow: 128e3,
2442
- maxTokens: 8192
2443
- },
2444
- {
2445
- ...KIRO_DEFAULTS,
2446
- id: "glm-4-7-flash",
2447
- name: "GLM 4.7 Flash",
2448
- reasoning: false,
2449
- input: TEXT_ONLY,
2450
- contextWindow: 128e3,
2451
- maxTokens: 8192
2452
- },
2453
- {
2454
- ...KIRO_DEFAULTS,
2455
- id: "qwen3-coder-next",
2456
- name: "Qwen3 Coder Next",
2457
- reasoning: true,
2458
- input: TEXT_ONLY,
2459
- contextWindow: 256e3,
2460
- maxTokens: 8192
2461
- },
2462
- {
2463
- ...KIRO_DEFAULTS,
2464
- id: "qwen3-coder-480b",
2465
- name: "Qwen3 Coder 480B",
2466
- reasoning: true,
2467
- input: TEXT_ONLY,
2468
- contextWindow: 128e3,
2469
- maxTokens: 8192
2470
- },
2471
- {
2472
- ...KIRO_DEFAULTS,
2473
- id: "agi-nova-beta-1m",
2474
- name: "AGI Nova Beta (1M)",
2475
- reasoning: true,
2476
- input: MULTIMODAL,
2477
- contextWindow: 1e6,
2478
- maxTokens: 65536
2479
- },
2480
- {
2481
- ...KIRO_DEFAULTS,
2482
- id: "auto",
2483
- name: "Auto",
2484
- reasoning: true,
2485
- input: MULTIMODAL,
2486
- contextWindow: 2e5,
2487
- maxTokens: 65536
2488
- }
2489
- ];
2490
-
2491
2323
  // node_modules/@ngosangns/ns-pi-provider/src/kiro/discover.ts
2324
+ var KIRO_ORIGIN = "AI_EDITOR";
2492
2325
  var LIST_TARGET = "AmazonCodeWhispererService.ListAvailableModels";
2493
2326
  var LIST_TIMEOUT_MS = 15e3;
2494
2327
  function buildUserAgent() {
2495
2328
  const mid = crypto.randomUUID().replace(/-/g, "");
2496
2329
  return `aws-sdk-rust/1.0.0 ua/2.1 os/other lang/rust api/codewhispererstreaming#1.28.3 m/E app/AmazonQ-For-CLI md/appVersion-1.28.3-${mid}`;
2497
2330
  }
2498
- var BEHAVIOR_BY_KIRO_ID = Object.fromEntries(
2499
- kiroModels.map((m) => [
2500
- m.id.replace(/(\d)-(\d)/g, "$1.$2"),
2501
- {
2502
- ...m.reasoningHidden ? { reasoningHidden: true } : {},
2503
- ...m.firstTokenTimeout ? { firstTokenTimeout: m.firstTokenTimeout } : {}
2504
- }
2505
- ])
2506
- );
2507
- var ONE_M_SUFFIX = "-1m";
2508
- var ONE_M_CONTEXT = 1e6;
2509
2331
  function toPiId(kiroId) {
2510
2332
  return kiroId.replace(/(\d)\.(\d)/g, "$1-$2");
2511
2333
  }
2512
2334
  function toKiroModel(api, baseUrl) {
2513
2335
  const piId = toPiId(api.modelId);
2336
+ const thinkingLevelMap = defaultThinkingLevelMapForModel(piId, api.modelName ?? piId);
2514
2337
  const types = api.supportedInputTypes ?? ["TEXT"];
2515
2338
  const input = types.some((t) => t.toUpperCase() === "IMAGE") ? ["text", "image"] : ["text"];
2516
2339
  return {
@@ -2520,39 +2343,18 @@ function toKiroModel(api, baseUrl) {
2520
2343
  provider: "kiro",
2521
2344
  baseUrl,
2522
2345
  // The API reports no reasoning capability flag. Treat every model as
2523
- // reasoning-capable: stream.ts gates the `<thinking_mode>` directive on
2524
- // this, and an unnecessary directive is far cheaper than suppressing
2525
- // reasoning on a model that supports it.
2346
+ // reasoning-capable: an over-eager `reasoning` flag is far cheaper than
2347
+ // suppressing reasoning on a model that supports it.
2526
2348
  reasoning: true,
2527
2349
  input,
2528
2350
  // Kiro bills in credits via rateMultiplier, not per-token USD. There is
2529
- // no token price to report, so cost stays zero and the multiplier is
2530
- // surfaced in the model name instead.
2351
+ // no token price to report, so cost stays zero.
2531
2352
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
2532
2353
  contextWindow: api.tokenLimits?.maxInputTokens ?? 2e5,
2533
2354
  maxTokens: api.tokenLimits?.maxOutputTokens ?? 8192,
2534
- ...BEHAVIOR_BY_KIRO_ID[api.modelId]
2355
+ ...thinkingLevelMap ? { thinkingLevelMap } : {}
2535
2356
  };
2536
2357
  }
2537
- function deriveLongContextVariants(discovered, baseUrl) {
2538
- const present = new Set(discovered.map((m) => m.id));
2539
- const out = [];
2540
- for (const staticModel of kiroModels) {
2541
- if (!staticModel.id.endsWith(ONE_M_SUFFIX)) continue;
2542
- if (present.has(staticModel.id)) continue;
2543
- const baseId = staticModel.id.slice(0, -ONE_M_SUFFIX.length);
2544
- const base = discovered.find((m) => m.id === baseId);
2545
- if (!base) continue;
2546
- out.push({
2547
- ...base,
2548
- id: staticModel.id,
2549
- name: `${base.name} (1M)`,
2550
- contextWindow: ONE_M_CONTEXT,
2551
- ...BEHAVIOR_BY_KIRO_ID[staticModel.id.replace(/(\d)-(\d)/g, "$1.$2")]
2552
- });
2553
- }
2554
- return out;
2555
- }
2556
2358
  async function discoverKiroModels(apiKey, baseUrl, signal) {
2557
2359
  const ua = buildUserAgent();
2558
2360
  const timeout = AbortSignal.timeout(LIST_TIMEOUT_MS);
@@ -2606,13 +2408,10 @@ async function discoverKiroModels(apiKey, baseUrl, signal) {
2606
2408
  "Kiro model discovery returned no models for this API key. The key may lack model entitlements, or be scoped to another region."
2607
2409
  );
2608
2410
  }
2609
- const discovered = apiModels.filter((m) => typeof m.modelId === "string" && m.modelId.length > 0).map((m) => toKiroModel(m, baseUrl));
2610
- const models = [...discovered, ...deriveLongContextVariants(discovered, baseUrl)];
2611
- setDiscoveredModelIds(models.map((m) => m.id.replace(/(\d)-(\d)/g, "$1.$2")));
2411
+ const models = apiModels.filter((m) => typeof m.modelId === "string" && m.modelId.length > 0).map((m) => toKiroModel(m, baseUrl));
2612
2412
  log.info("discover.ok", {
2613
2413
  count: models.length,
2614
- discovered: discovered.map((m) => m.id),
2615
- derived: models.length - discovered.length,
2414
+ discovered: models.map((m) => m.id),
2616
2415
  defaultModel: payload.defaultModel?.modelId
2617
2416
  });
2618
2417
  return models;
@@ -2817,9 +2616,10 @@ async function refreshKiroModels(options = {}) {
2817
2616
  input: m.input,
2818
2617
  cost: ensureCacheCost(m.cost),
2819
2618
  contextWindow: m.contextWindow,
2820
- maxTokens: m.maxTokens
2619
+ maxTokens: m.maxTokens,
2620
+ ...m.thinkingLevelMap ? { thinkingLevelMap: m.thinkingLevelMap } : {}
2821
2621
  }));
2822
- return { models, version: "kiro-list-v1" };
2622
+ return { models, version: "kiro-list-v2" };
2823
2623
  },
2824
2624
  { force: options.force }
2825
2625
  );
@@ -2830,7 +2630,7 @@ async function refreshKiroModels(options = {}) {
2830
2630
  return { models: fallback, fromCache: false };
2831
2631
  }
2832
2632
  }
2833
- function registerKiroProvider(pi) {
2633
+ async function registerKiroProvider(pi) {
2834
2634
  const { config, warnings } = loadConfig(EXTENSION_ROOT);
2835
2635
  const logger = new DebugLogger({ extensionRoot: EXTENSION_ROOT, debug: config.debug });
2836
2636
  for (const warning of warnings) logger.warn("config_warning", { warning });
@@ -2858,7 +2658,10 @@ function registerKiroProvider(pi) {
2858
2658
  const runtime = {};
2859
2659
  const streamSimple = createLazyKiroStream(config, runtime, logger);
2860
2660
  const providerHeaders = omitAuthorizationHeaders(config.headers);
2861
- let currentModels = toProviderModels(fallbackCatalogModels(config), config);
2661
+ let currentModels = toProviderModels(
2662
+ (await refreshKiroModels({ fallback: fallbackCatalogModels(config) })).models,
2663
+ config
2664
+ );
2862
2665
  const buildConfig = (models) => ({
2863
2666
  name: config.displayName || "Kiro",
2864
2667
  baseUrl: config.upstreamUrl,
@@ -3691,14 +3494,14 @@ function formatResetTime(epoch) {
3691
3494
  // node_modules/@ngosangns/ns-pi-provider/src/devin/register.ts
3692
3495
  var DEVIN_PROVIDER_ID = "devin";
3693
3496
  var API = "devin-cloud";
3694
- var BASE_URL2 = "https://server.codeium.com";
3497
+ var BASE_URL = "https://server.codeium.com";
3695
3498
  var FALLBACK_MODELS = [
3696
3499
  {
3697
3500
  id: "swe-1-7",
3698
3501
  name: "SWE-1.7",
3699
3502
  api: API,
3700
3503
  provider: DEVIN_PROVIDER_ID,
3701
- baseUrl: BASE_URL2,
3504
+ baseUrl: BASE_URL,
3702
3505
  reasoning: true,
3703
3506
  input: ["text"],
3704
3507
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
@@ -3710,7 +3513,7 @@ var FALLBACK_MODELS = [
3710
3513
  name: "SWE-1.6",
3711
3514
  api: API,
3712
3515
  provider: DEVIN_PROVIDER_ID,
3713
- baseUrl: BASE_URL2,
3516
+ baseUrl: BASE_URL,
3714
3517
  reasoning: true,
3715
3518
  input: ["text"],
3716
3519
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
@@ -3738,7 +3541,7 @@ function fromCatalog(models) {
3738
3541
  name: m.name,
3739
3542
  api: m.api || API,
3740
3543
  provider: DEVIN_PROVIDER_ID,
3741
- baseUrl: m.baseUrl ?? BASE_URL2,
3544
+ baseUrl: m.baseUrl ?? BASE_URL,
3742
3545
  reasoning: m.reasoning ?? true,
3743
3546
  input: m.input ?? ["text"],
3744
3547
  cost: ensureCacheCost(m.cost),
@@ -3813,7 +3616,7 @@ function providerConfig(currentModels, apiKey) {
3813
3616
  return {
3814
3617
  name: "Devin",
3815
3618
  api: API,
3816
- baseUrl: BASE_URL2,
3619
+ baseUrl: BASE_URL,
3817
3620
  models: currentModels,
3818
3621
  // When CLI credentials.toml (or env) already has a token, set apiKey so Pi
3819
3622
  // marks the provider configured for --list-models without auth.json /login.
@@ -4475,15 +4278,23 @@ var state = {
4475
4278
  };
4476
4279
  var nextGeneration = 1;
4477
4280
  var scopeGenerations = /* @__PURE__ */ new Map([[ANONYMOUS_SCOPE, 0]]);
4478
- var onScopeChange;
4479
4281
  function getSessionCwd() {
4480
4282
  return state.cwd;
4481
4283
  }
4482
4284
  function getSessionScopeKey() {
4483
- if (state.sessionFile) return state.sessionFile;
4484
- if (state.sessionId) return `${EPHEMERAL_PREFIX}${state.sessionId}`;
4285
+ return scopeKeyFrom(state.sessionFile, state.sessionId);
4286
+ }
4287
+ function scopeKeyFrom(sessionFile, sessionId) {
4288
+ if (sessionFile) return sessionFile;
4289
+ if (sessionId) return `${EPHEMERAL_PREFIX}${sessionId}`;
4485
4290
  return ANONYMOUS_SCOPE;
4486
4291
  }
4292
+ function scopeKeyFromCtx(ctx) {
4293
+ return scopeKeyFrom(
4294
+ ctx.sessionManager?.getSessionFile?.() ?? void 0,
4295
+ ctx.sessionManager?.getSessionId?.() ?? void 0
4296
+ );
4297
+ }
4487
4298
  function setScope(cwd, sessionFile, sessionId) {
4488
4299
  state.cwd = cwd;
4489
4300
  state.sessionFile = sessionFile;
@@ -4491,20 +4302,13 @@ function setScope(cwd, sessionFile, sessionId) {
4491
4302
  state.generation = nextGeneration++;
4492
4303
  scopeGenerations.set(getSessionScopeKey(), state.generation);
4493
4304
  }
4494
- function onSessionScopeKeyChange(handler) {
4495
- onScopeChange = handler;
4496
- }
4497
4305
  function registerSessionScope(pi) {
4498
4306
  pi.on("session_start", async (_event, ctx) => {
4499
- const previousScopeKey = getSessionScopeKey();
4500
4307
  setScope(
4501
4308
  ctx.cwd,
4502
4309
  ctx.sessionManager?.getSessionFile?.() ?? void 0,
4503
4310
  ctx.sessionManager?.getSessionId?.() ?? void 0
4504
4311
  );
4505
- if (previousScopeKey !== getSessionScopeKey()) {
4506
- await onScopeChange?.(previousScopeKey);
4507
- }
4508
4312
  });
4509
4313
  pi.on("session_info_changed", async () => {
4510
4314
  });
@@ -5116,6 +4920,7 @@ function streamGrokAgent(model, context, options) {
5116
4920
  }
5117
4921
 
5118
4922
  // node_modules/@ngosangns/ns-pi-provider/src/grok/register.ts
4923
+ var exitHookInstalled = false;
5119
4924
  var GROK_PROVIDER_ID = "grok";
5120
4925
  var GROK_SDK_PROVIDER_ID = "grok-sdk";
5121
4926
  var GROK_API = "grok-cli";
@@ -5199,19 +5004,18 @@ function createProviderConfig(models) {
5199
5004
  }
5200
5005
  function registerGrokProvider(pi) {
5201
5006
  registerSessionScope(pi);
5202
- onSessionScopeKeyChange((previousKey) => {
5203
- disposeSessionAgentsForScope(previousKey);
5007
+ pi.on("session_shutdown", async (_event, ctx) => {
5008
+ disposeSessionAgentsForScope(scopeKeyFromCtx(ctx));
5204
5009
  });
5205
- pi.on("session_shutdown", async () => {
5206
- disposeAllSessionAgents();
5207
- });
5208
- const cleanup = () => {
5209
- try {
5210
- disposeAllSessionAgents();
5211
- } catch {
5212
- }
5213
- };
5214
- process.once("exit", cleanup);
5010
+ if (!exitHookInstalled) {
5011
+ exitHookInstalled = true;
5012
+ process.once("exit", () => {
5013
+ try {
5014
+ disposeAllSessionAgents();
5015
+ } catch {
5016
+ }
5017
+ });
5018
+ }
5215
5019
  let binary;
5216
5020
  let binaryError;
5217
5021
  try {
@@ -5294,7 +5098,7 @@ async function registerAllProviders(pi, options = {}) {
5294
5098
  const enableGrok = options.grok !== false;
5295
5099
  if (enableKiro) {
5296
5100
  try {
5297
- registerKiroProvider(pi);
5101
+ await registerKiroProvider(pi);
5298
5102
  } catch (err) {
5299
5103
  console.warn(
5300
5104
  `[ns-pi-provider] kiro registration failed: ${err instanceof Error ? err.message : String(err)}`
@@ -5460,12 +5264,15 @@ function parseList(value2) {
5460
5264
  value2.split(/[\s,]+/).map((item) => item.trim().toLowerCase()).filter(Boolean)
5461
5265
  );
5462
5266
  }
5267
+ var OPT_IN_PROVIDERS = /* @__PURE__ */ new Set(["kiro"]);
5463
5268
  function resolveProviderSelection(env = process.env) {
5464
5269
  const allow = parseList(env.NS_OMP_PROVIDERS);
5270
+ const enable = parseList(env.NS_OMP_PROVIDER_ENABLE) ?? /* @__PURE__ */ new Set();
5465
5271
  const deny = parseList(env.NS_OMP_PROVIDER_DISABLE) ?? /* @__PURE__ */ new Set();
5466
5272
  const selection = {};
5467
5273
  for (const key of PROVIDER_KEYS) {
5468
- selection[key] = (allow ? allow.has(key) : true) && !deny.has(key);
5274
+ const base = allow ? allow.has(key) : !OPT_IN_PROVIDERS.has(key);
5275
+ selection[key] = (base || enable.has(key)) && !deny.has(key);
5469
5276
  }
5470
5277
  return selection;
5471
5278
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ns-omp-provider",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "OMP (oh-my-pi) plugin: Kiro, Devin, and Grok providers from @ngosangns/ns-pi-provider, wrapped for OMP's provider/extension API.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -70,7 +70,7 @@
70
70
  }
71
71
  },
72
72
  "devDependencies": {
73
- "@ngosangns/ns-pi-provider": "0.1.7",
73
+ "@ngosangns/ns-pi-provider": "0.2.1",
74
74
  "@types/node": "^22.18.6",
75
75
  "esbuild": "^0.28.2",
76
76
  "typescript": "^5.9.2",