@spotpatch/runtime 1.15.1 → 1.15.2

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.
@@ -11,4 +11,4 @@ export {
11
11
  registerExternalHandoffExtension,
12
12
  getExternalHandoffExtension
13
13
  };
14
- //# sourceMappingURL=chunk-ASRUAKA5.js.map
14
+ //# sourceMappingURL=chunk-TEH2CCO3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ui/external-handoff-contract.ts"],"sourcesContent":["import type {\n DispatchSummary,\n ErrorCode,\n ExternalAgentControlStatus,\n ExternalAgentManagedResult,\n ExternalHandoffCapability,\n ExternalHandoffPublishResult,\n ExternalHandoffStatusResult,\n ExternalHandoffFramework,\n SpotAnnotation,\n SpotPatchLocale,\n} from \"@spotpatch/shared/external-handoff-browser\";\n\nexport interface ExternalHandoffPanel {\n readonly cancelManagedButton: HTMLButtonElement;\n readonly connectButton: HTMLButtonElement;\n readonly readModel: () => string | undefined;\n readonly disconnectButton: HTMLButtonElement;\n readonly refreshButton: HTMLButtonElement;\n readonly root: HTMLElement;\n readonly sendButton: HTMLButtonElement;\n readonly styles: HTMLStyleElement;\n readonly confirmDisclosure: (annotation: SpotAnnotation) => Promise<boolean>;\n readonly dispose: () => void;\n readonly renderCapability: (capability: ExternalHandoffCapability) => void;\n readonly renderControlUnavailable: () => void;\n readonly renderControlStatus: (status: ExternalAgentControlStatus) => void;\n readonly renderError: (code?: ErrorCode, retryable?: boolean) => void;\n readonly renderPublishResult: (result: ExternalHandoffPublishResult) => void;\n readonly renderPublishing: () => void;\n readonly renderManagedResult: (result: ExternalAgentManagedResult) => void;\n readonly renderStatus: (result: ExternalHandoffStatusResult) => void;\n readonly resolveButton: HTMLButtonElement;\n readonly revokeButton: HTMLButtonElement;\n readonly setBusy: (busy: boolean) => void;\n readonly setControlBusy: (busy: boolean) => void;\n readonly setContextReady: (ready: boolean) => void;\n readonly setSelectionVisible: (visible: boolean) => void;\n}\n\nexport interface ExternalHandoffWorkflow {\n readonly cancelPending: () => void;\n readonly dispose: () => void;\n readonly mount: () => void;\n}\n\nexport interface ExternalHandoffExtension {\n readonly createPanel: (\n document: Document,\n framework: ExternalHandoffFramework,\n locale: () => SpotPatchLocale,\n sessionId: string,\n subscribeLocale: (listener: () => void) => () => void,\n onViewChange: () => void,\n onDispatchChange?: (dispatch: DispatchSummary | null) => void,\n onControlChange?: (status: ExternalAgentControlStatus | undefined) => void,\n ) => ExternalHandoffPanel;\n readonly createWorkflow: (\n fetch: typeof globalThis.fetch,\n panel: ExternalHandoffPanel,\n selectedAnnotation: () => SpotAnnotation | undefined,\n sessionToken: string,\n window: Window,\n ) => ExternalHandoffWorkflow;\n}\n\nconst EXTERNAL_HANDOFF_EXTENSION_KEY = Symbol.for(\"spotpatch.external-handoff.v1\");\ntype ExtensionStore = Partial<Record<symbol, ExternalHandoffExtension>>;\n\nexport function registerExternalHandoffExtension(\n extension: ExternalHandoffExtension,\n): void {\n (globalThis as ExtensionStore)[EXTERNAL_HANDOFF_EXTENSION_KEY] = extension;\n}\n\nexport function getExternalHandoffExtension(): ExternalHandoffExtension | undefined {\n return (globalThis as ExtensionStore)[EXTERNAL_HANDOFF_EXTENSION_KEY];\n}\n"],"mappings":";AAkEA,IAAM,iCAAiC,uBAAO,IAAI,+BAA+B;AAG1E,SAAS,iCACd,WACM;AACN,EAAC,WAA8B,8BAA8B,IAAI;AACnE;AAEO,SAAS,8BAAoE;AAClF,SAAQ,WAA8B,8BAA8B;AACtE;","names":[]}
@@ -197,6 +197,9 @@ function parseTask(value) {
197
197
  ...value.resultExpiresAt === void 0 ? {} : { resultExpiresAt: value.resultExpiresAt }
198
198
  });
199
199
  }
200
+ function validModel(value) {
201
+ return typeof value === "string" && value.length > 0 && value.length <= import_external_handoff_browser.EXTERNAL_AGENT_CONTROL_LIMITS.maximumModelCharacters && value.trim() === value;
202
+ }
200
203
  function parseExternalAgentControlStatus(value) {
201
204
  if (!record(value) || !optionalKeys(
202
205
  value,
@@ -210,8 +213,8 @@ function parseExternalAgentControlStatus(value) {
210
213
  "sequence",
211
214
  "updatedAt"
212
215
  ],
213
- ["effectiveModel", "error", "requestedModel", "task"]
214
- ) || value.schemaVersion !== 1 || !integer(value.sequence) || !member(import_external_handoff_browser.EXTERNAL_AGENT_MODES, value.mode) || !member(import_external_handoff_browser.EXTERNAL_AGENT_CONNECTION_STATES, value.connectionState) || !member(import_external_handoff_browser.EXTERNAL_AGENT_AUTH_READINESS, value.authReadiness) || !member(import_external_handoff_browser.EXTERNAL_AGENT_GRANT_STATES, value.grantState) || !validTimestamp(value.updatedAt) || value.requestedModel !== void 0 && (typeof value.requestedModel !== "string" || value.requestedModel.length === 0 || value.requestedModel.length > 128) || value.effectiveModel !== void 0 && (typeof value.effectiveModel !== "string" || value.effectiveModel.length === 0 || value.effectiveModel.length > 128) || !record(value.adapter) || !exactKeys(value.adapter, ["availability", "kind", "maturity"]) || value.adapter.kind !== "codex" || value.adapter.maturity !== "experimental" || value.adapter.availability !== "available" && value.adapter.availability !== "unavailable") {
216
+ ["effectiveModel", "error", "requestedModel", "task", "models"]
217
+ ) || value.schemaVersion !== 1 || !integer(value.sequence) || !member(import_external_handoff_browser.EXTERNAL_AGENT_MODES, value.mode) || !member(import_external_handoff_browser.EXTERNAL_AGENT_CONNECTION_STATES, value.connectionState) || !member(import_external_handoff_browser.EXTERNAL_AGENT_AUTH_READINESS, value.authReadiness) || !member(import_external_handoff_browser.EXTERNAL_AGENT_GRANT_STATES, value.grantState) || !validTimestamp(value.updatedAt) || value.requestedModel !== void 0 && !validModel(value.requestedModel) || value.effectiveModel !== void 0 && !validModel(value.effectiveModel) || value.models !== void 0 && (!Array.isArray(value.models) || value.models.length === 0 || value.models.length > import_external_handoff_browser.EXTERNAL_AGENT_CONTROL_LIMITS.maximumModels || !value.models.every(validModel) || new Set(value.models).size !== value.models.length) || !record(value.adapter) || !exactKeys(value.adapter, ["availability", "kind", "maturity"]) || value.adapter.kind !== "codex" || value.adapter.maturity !== "experimental" || value.adapter.availability !== "available" && value.adapter.availability !== "unavailable") {
215
218
  throw new TypeError("Invalid external Agent control status.");
216
219
  }
217
220
  let error;
@@ -238,6 +241,7 @@ function parseExternalAgentControlStatus(value) {
238
241
  connectionState: value.connectionState,
239
242
  authReadiness: value.authReadiness,
240
243
  grantState: value.grantState,
244
+ ...value.models === void 0 ? {} : { models: Object.freeze([...value.models]) },
241
245
  ...value.requestedModel === void 0 ? {} : { requestedModel: value.requestedModel },
242
246
  ...value.effectiveModel === void 0 ? {} : { effectiveModel: value.effectiveModel },
243
247
  ...value.task === void 0 ? {} : { task: parseTask(value.task) },
@@ -736,11 +740,13 @@ function createExternalHandoffWorkflow(fetch, panel, selectedAnnotation, session
736
740
  }
737
741
  };
738
742
  const handleConnectClick = () => {
743
+ const model = options.panel.readModel();
739
744
  void performControlAction(
740
745
  () => controlClient.connect({
741
746
  requestId: createRequestId(options.window),
742
747
  adapterKind: "codex",
743
- profile: import_external_handoff_browser2.EXTERNAL_AGENT_MANAGED_PROFILE
748
+ profile: import_external_handoff_browser2.EXTERNAL_AGENT_MANAGED_PROFILE,
749
+ ...model === void 0 ? {} : { model }
744
750
  })
745
751
  );
746
752
  };
@@ -1029,6 +1035,10 @@ var MESSAGES = Object.freeze({
1029
1035
  "en-US": Object.freeze({
1030
1036
  title: "External Agent connection",
1031
1037
  agentLabel: "Agent",
1038
+ modelLabel: "Managed Codex model",
1039
+ modelLoading: "Connect to load available models",
1040
+ modelHint: "Applies only to this managed connection, not API Key settings. Apply changes before publishing; switching reconnects Codex.",
1041
+ applyModel: "Apply model",
1032
1042
  codexManaged: "Codex \xB7 managed (experimental)",
1033
1043
  connectManaged: "Connect Codex",
1034
1044
  disconnectManaged: "Disconnect",
@@ -1067,7 +1077,7 @@ var MESSAGES = Object.freeze({
1067
1077
  "install-agent": "Install Codex and retry.",
1068
1078
  "use-supported-version": "Use a schema-compatible Codex version.",
1069
1079
  "sign-in": "Sign in with Codex, then retry.",
1070
- "choose-available-model": "Choose an available model in Codex configuration.",
1080
+ "choose-available-model": "Choose an available model and reconnect Codex.",
1071
1081
  "use-inbox": "Continue with the Agent inbox fallback.",
1072
1082
  "confirm-managed-access": "Revoke the invalid grant and confirm access again.",
1073
1083
  "review-candidate-diff": "Review the candidate diff and validation output.",
@@ -1116,6 +1126,10 @@ var MESSAGES = Object.freeze({
1116
1126
  "zh-CN": Object.freeze({
1117
1127
  title: "\u5916\u90E8 Agent \u8FDE\u63A5",
1118
1128
  agentLabel: "Agent",
1129
+ modelLabel: "\u53D7\u7BA1 Codex \u6A21\u578B",
1130
+ modelLoading: "\u8FDE\u63A5\u540E\u52A0\u8F7D\u53EF\u7528\u6A21\u578B",
1131
+ modelHint: "\u4EC5\u4F5C\u7528\u4E8E\u6B64\u53D7\u7BA1\u8FDE\u63A5\uFF0C\u4E0D\u4FEE\u6539 API Key \u914D\u7F6E\u3002\u66F4\u6362\u540E\u8BF7\u5148\u5E94\u7528\u6A21\u578B\uFF0C\u518D\u53D1\u5E03\u4EFB\u52A1\uFF1B\u5E94\u7528\u65F6\u4F1A\u91CD\u65B0\u8FDE\u63A5 Codex\u3002",
1132
+ applyModel: "\u5E94\u7528\u6A21\u578B",
1119
1133
  codexManaged: "Codex \xB7 \u53D7\u7BA1\u6A21\u5F0F\uFF08\u5B9E\u9A8C\u6027\uFF09",
1120
1134
  connectManaged: "\u8FDE\u63A5 Codex",
1121
1135
  disconnectManaged: "\u65AD\u5F00\u8FDE\u63A5",
@@ -1154,7 +1168,7 @@ var MESSAGES = Object.freeze({
1154
1168
  "install-agent": "\u5B89\u88C5 Codex \u540E\u91CD\u8BD5\u3002",
1155
1169
  "use-supported-version": "\u6539\u7528 Schema \u517C\u5BB9\u7684 Codex \u7248\u672C\u3002",
1156
1170
  "sign-in": "\u767B\u5F55 Codex \u540E\u91CD\u8BD5\u3002",
1157
- "choose-available-model": "\u5728 Codex \u914D\u7F6E\u4E2D\u9009\u62E9\u53EF\u7528\u6A21\u578B\u3002",
1171
+ "choose-available-model": "\u9009\u62E9\u53EF\u7528\u6A21\u578B\u540E\u91CD\u65B0\u8FDE\u63A5 Codex\u3002",
1158
1172
  "use-inbox": "\u7EE7\u7EED\u4F7F\u7528 Agent \u6536\u4EF6\u7BB1\u964D\u7EA7\u8DEF\u5F84\u3002",
1159
1173
  "confirm-managed-access": "\u64A4\u9500\u65E0\u6548\u6388\u6743\u5E76\u91CD\u65B0\u786E\u8BA4\u3002",
1160
1174
  "review-candidate-diff": "\u68C0\u67E5\u5019\u9009 diff \u548C\u9A8C\u8BC1\u8F93\u51FA\u3002",
@@ -1376,6 +1390,11 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
1376
1390
  codexOption.value = "codex";
1377
1391
  agentSelect.append(codexOption);
1378
1392
  agentLabel.append(agentLabelText, agentSelect);
1393
+ const modelLabel = createMarkedElement(document, "label");
1394
+ const modelLabelText = createMarkedElement(document, "span");
1395
+ const modelSelect = createMarkedElement(document, "select");
1396
+ const modelHint = createMarkedElement(document, "p");
1397
+ modelLabel.append(modelLabelText, modelSelect);
1379
1398
  const controlStatus = createMarkedElement(document, "p");
1380
1399
  controlStatus.className = "spotpatch-external-control-status";
1381
1400
  controlStatus.setAttribute("role", "status");
@@ -1398,7 +1417,14 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
1398
1417
  const managedResultSummary = createMarkedElement(document, "p");
1399
1418
  const managedResultDiff = createMarkedElement(document, "pre");
1400
1419
  managedResult.append(managedResultTitle, managedResultSummary, managedResultDiff);
1401
- controlRoot.append(agentLabel, controlStatus, controlActions, managedResult);
1420
+ controlRoot.append(
1421
+ agentLabel,
1422
+ modelLabel,
1423
+ modelHint,
1424
+ controlStatus,
1425
+ controlActions,
1426
+ managedResult
1427
+ );
1402
1428
  const resolveButton = createButton(document, "", "spotpatch-external-resolve");
1403
1429
  resolveButton.hidden = true;
1404
1430
  const settings = createMarkedElement(document, "details");
@@ -1455,15 +1481,19 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
1455
1481
  } catch {
1456
1482
  }
1457
1483
  };
1484
+ const modelPending = () => control?.mode === "managed" && modelSelect.value !== "" && modelSelect.value !== control.requestedModel;
1485
+ const controlPending = () => controlOperationBusy || control?.connectionState === "diagnosing" || control?.connectionState === "connecting" || control?.connectionState === "disconnecting";
1458
1486
  const refreshActions = () => {
1459
1487
  sendButton.textContent = retryable ? messages.retry : activeAdapter?.canDispatch === true ? messages.send : messages.inboxSend;
1460
- sendButton.disabled = !visible || !brokerReady || !contextReady || operationBusy || !retryable && dispatchBlocksSend;
1488
+ sendButton.disabled = !visible || !brokerReady || !contextReady || operationBusy || controlPending() || modelPending() || !retryable && dispatchBlocksSend;
1461
1489
  sendButton.setAttribute("aria-busy", String(operationBusy));
1462
1490
  refreshButton.disabled = !visible || operationBusy;
1463
1491
  resolveButton.hidden = !unknownDelivery;
1464
1492
  resolveButton.disabled = !visible || operationBusy || !unknownDelivery;
1465
1493
  };
1466
1494
  const refreshControlActions = () => {
1495
+ connectButton.textContent = modelPending() ? messages.applyModel : messages.connectManaged;
1496
+ modelSelect.disabled = true;
1467
1497
  if (control === void 0) {
1468
1498
  connectButton.disabled = true;
1469
1499
  disconnectButton.disabled = true;
@@ -1472,8 +1502,9 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
1472
1502
  return;
1473
1503
  }
1474
1504
  const state = control.connectionState;
1475
- const operationPending = controlOperationBusy || state === "diagnosing" || state === "connecting" || state === "disconnecting";
1476
- connectButton.disabled = operationPending || state === "ready" || state === "busy";
1505
+ const operationPending = controlPending();
1506
+ modelSelect.disabled = operationPending || state === "busy" || !control.models?.length;
1507
+ connectButton.disabled = operationPending || state === "ready" && !modelPending() || state === "busy";
1477
1508
  disconnectButton.disabled = operationPending || state === "disconnected";
1478
1509
  revokeButton.disabled = operationPending || control.grantState !== "valid";
1479
1510
  const phase = control.task?.managedPhase;
@@ -1524,6 +1555,11 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
1524
1555
  disclosureProvider.textContent = messages.disclosureProvider;
1525
1556
  disclosureNoGuarantee.textContent = messages.disclosureNoGuarantee;
1526
1557
  agentLabelText.textContent = messages.agentLabel;
1558
+ modelLabelText.textContent = messages.modelLabel;
1559
+ modelHint.textContent = messages.modelHint;
1560
+ if (modelSelect.options.length === 1 && modelSelect.options[0]?.value === "") {
1561
+ modelSelect.options[0].textContent = messages.modelLoading;
1562
+ }
1527
1563
  codexOption.textContent = messages.codexManaged;
1528
1564
  connectButton.textContent = messages.connectManaged;
1529
1565
  disconnectButton.textContent = messages.disconnectManaged;
@@ -1555,6 +1591,25 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
1555
1591
  disclosure.addEventListener("keydown", handleDisclosureKeydown);
1556
1592
  settings.addEventListener("toggle", options.onViewChange);
1557
1593
  managedResult.addEventListener("toggle", options.onViewChange);
1594
+ const handleModelChange = () => {
1595
+ refreshControlActions();
1596
+ refreshActions();
1597
+ };
1598
+ modelSelect.addEventListener("change", handleModelChange);
1599
+ const renderModels = () => {
1600
+ const previous = modelSelect.value;
1601
+ const models = control?.models ?? [];
1602
+ modelSelect.replaceChildren(
1603
+ ...(models.length ? models : [""]).map((model) => {
1604
+ const option = createMarkedElement(document, "option");
1605
+ option.value = model;
1606
+ option.textContent = model || messages.modelLoading;
1607
+ return option;
1608
+ })
1609
+ );
1610
+ modelSelect.value = models.includes(previous) ? previous : control?.requestedModel ?? models[0] ?? "";
1611
+ };
1612
+ renderModels();
1558
1613
  const unsubscribeLocale = options.subscribeLocale(applyMessages);
1559
1614
  applyMessages();
1560
1615
  status.textContent = messages.ready;
@@ -1597,6 +1652,7 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
1597
1652
  resolveButton,
1598
1653
  cancelManagedButton,
1599
1654
  connectButton,
1655
+ readModel: () => modelSelect.value || void 0,
1600
1656
  disconnectButton,
1601
1657
  revokeButton,
1602
1658
  confirmDisclosure(annotation) {
@@ -1653,20 +1709,24 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
1653
1709
  },
1654
1710
  renderControlStatus(value) {
1655
1711
  control = value;
1712
+ renderModels();
1656
1713
  controlStatus.textContent = controlStatusText(value, messages, framework);
1657
1714
  controlStatus.dataset.state = value.connectionState;
1658
1715
  disclosureNoGuarantee.textContent = value.mode === "managed" ? messages.disclosureManagedGuarantee : messages.disclosureNoGuarantee;
1659
1716
  refreshControlActions();
1717
+ refreshActions();
1660
1718
  options.onControlChange?.(value);
1661
1719
  options.onViewChange();
1662
1720
  },
1663
1721
  renderControlUnavailable() {
1664
1722
  control = void 0;
1723
+ renderModels();
1665
1724
  controlStatus.dataset.state = "unavailable";
1666
1725
  controlStatus.textContent = messages.controlUnavailable;
1667
1726
  disclosureNoGuarantee.textContent = messages.disclosureNoGuarantee;
1668
1727
  refreshControlActions();
1669
1728
  options.onControlChange?.(void 0);
1729
+ refreshActions();
1670
1730
  options.onViewChange();
1671
1731
  },
1672
1732
  renderManagedResult(result) {
@@ -1694,6 +1754,7 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
1694
1754
  setControlBusy(nextBusy) {
1695
1755
  controlOperationBusy = nextBusy;
1696
1756
  refreshControlActions();
1757
+ refreshActions();
1697
1758
  },
1698
1759
  setContextReady(ready) {
1699
1760
  contextReady = ready;
@@ -1711,6 +1772,7 @@ function createExternalHandoffPanel(document, framework, locale, sessionId, subs
1711
1772
  disclosure.removeEventListener("keydown", handleDisclosureKeydown);
1712
1773
  settings.removeEventListener("toggle", options.onViewChange);
1713
1774
  managedResult.removeEventListener("toggle", options.onViewChange);
1775
+ modelSelect.removeEventListener("change", handleModelChange);
1714
1776
  unsubscribeLocale();
1715
1777
  }
1716
1778
  });