@workflow-code/cli 0.2.4-20261013005.codex-studio-integration → 0.2.4-20261013007.codex-studio-integration

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/index.js CHANGED
@@ -24,7 +24,7 @@ async function main(argv = process.argv.slice(2)) {
24
24
  const prepared = prepareCliInvocation(argv);
25
25
  argv = prepared.argv;
26
26
  if (argv[0] === "web") {
27
- const webCli = await import("./web-H4CP4OQC.js");
27
+ const webCli = await import("./web-HG5S3AUN.js");
28
28
  return webCli.main(argv.slice(1));
29
29
  }
30
30
  if (argv[0] === "workspace") {
@@ -1044,6 +1044,30 @@ main {
1044
1044
  height: 100%;
1045
1045
  object-fit: cover;
1046
1046
  }
1047
+ .attachment-image {
1048
+ position: relative;
1049
+ padding: 0;
1050
+ border: 0;
1051
+ background: transparent;
1052
+ }
1053
+ .attachment-image .attachment-preview {
1054
+ width: 88px;
1055
+ height: 88px;
1056
+ background: transparent;
1057
+ }
1058
+ .message .attachment-image .attachment-preview {
1059
+ width: 120px;
1060
+ height: 120px;
1061
+ }
1062
+ .attachment-image .attachment-preview img {
1063
+ object-fit: contain;
1064
+ }
1065
+ .attachment-image > .icon-button {
1066
+ position: absolute;
1067
+ top: 0;
1068
+ right: 0;
1069
+ background: var(--vscode-editor-background);
1070
+ }
1047
1071
  #draft-attachments {
1048
1072
  padding: 0 16px;
1049
1073
  }
@@ -1702,6 +1726,7 @@ textarea::placeholder {
1702
1726
  }
1703
1727
  .param-action:has(.param-action-summary:not([hidden])) .param-action-label {
1704
1728
  flex-shrink: 0;
1729
+ max-width: 50%;
1705
1730
  font-weight: 500;
1706
1731
  }
1707
1732
  .param-action-ai {
@@ -12608,6 +12608,7 @@
12608
12608
  "{1} in {0}": "{0} \u4E2D {1}",
12609
12609
  "Account balance ${0}": "\u8D26\u6237\u4F59\u989D ${0}",
12610
12610
  "Account balance": "\u8D26\u6237\u4F59\u989D",
12611
+ "Account changed. Refresh usage.": "\u8D26\u53F7\u5DF2\u5207\u6362\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6\u7528\u91CF\u3002",
12611
12612
  "AI usage": "AI \u7528\u91CF",
12612
12613
  All: "\u5168\u90E8",
12613
12614
  "Basic information": "\u57FA\u672C\u4FE1\u606F",
@@ -14400,14 +14401,14 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14400
14401
  DocumentFragment,
14401
14402
  HTMLTemplateElement,
14402
14403
  Node,
14403
- Element,
14404
+ Element: Element2,
14404
14405
  NodeFilter,
14405
14406
  NamedNodeMap = window2.NamedNodeMap || window2.MozNamedAttrMap,
14406
14407
  HTMLFormElement,
14407
14408
  DOMParser,
14408
14409
  trustedTypes
14409
14410
  } = window2;
14410
- const ElementPrototype = Element.prototype;
14411
+ const ElementPrototype = Element2.prototype;
14411
14412
  const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
14412
14413
  const remove = lookupGetter(ElementPrototype, "remove");
14413
14414
  const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
@@ -14861,7 +14862,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14861
14862
  _forceRemove(currentNode);
14862
14863
  return true;
14863
14864
  }
14864
- if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
14865
+ if (currentNode instanceof Element2 && !_checkValidNamespace(currentNode)) {
14865
14866
  _forceRemove(currentNode);
14866
14867
  return true;
14867
14868
  }
@@ -15870,6 +15871,28 @@ ${state2.user?.avatarUrl ?? ""}`;
15870
15871
  }
15871
15872
  };
15872
15873
 
15874
+ // src/web/ui/edit-commands.ts
15875
+ function pasteHostClipboard(clipboard) {
15876
+ if (typeof clipboard.text !== "string" || clipboard.image !== void 0 && !ArrayBuffer.isView(clipboard.image)) {
15877
+ return;
15878
+ }
15879
+ const target = document.activeElement;
15880
+ if (!(target instanceof HTMLElement) || !target.matches("textarea, input, [contenteditable=true]") || target.matches(":disabled, [readonly]")) {
15881
+ return;
15882
+ }
15883
+ const transfer = new DataTransfer();
15884
+ transfer.setData("text/plain", clipboard.text);
15885
+ if (clipboard.image && clipboard.image.byteLength) {
15886
+ const image = new Uint8Array(clipboard.image.buffer, clipboard.image.byteOffset, clipboard.image.byteLength);
15887
+ transfer.items.add(new File([new Uint8Array(image)], "clipboard.png", { type: "image/png" }));
15888
+ }
15889
+ const event = new ClipboardEvent("paste", { bubbles: true, cancelable: true, clipboardData: transfer });
15890
+ target.dispatchEvent(event);
15891
+ if (!event.defaultPrevented && clipboard.text) {
15892
+ document.execCommand("insertText", false, clipboard.text);
15893
+ }
15894
+ }
15895
+
15873
15896
  // src/web/ui/host.ts
15874
15897
  function acquireWorkflowHost(options = {}) {
15875
15898
  const embedded = globalThis.acquireVsCodeApi;
@@ -15891,13 +15914,62 @@ ${state2.user?.avatarUrl ?? ""}`;
15891
15914
  window.parent.postMessage(message, "*");
15892
15915
  }
15893
15916
  });
15894
- let resourceHost = false;
15917
+ let resourceHost = false, editHost = false, nativePasteHost = false;
15918
+ let contextInput, lastInput;
15919
+ const captureInput = (input) => {
15920
+ const field = input;
15921
+ return { element: input, selection: typeof field.selectionStart === "number" && typeof field.selectionEnd === "number" ? { start: field.selectionStart, end: field.selectionEnd, direction: field.selectionDirection ?? "none", value: field.value } : void 0 };
15922
+ };
15923
+ const rememberInput = () => {
15924
+ const input = document.activeElement;
15925
+ if (input instanceof HTMLElement && input.matches("textarea, input, [contenteditable=true]")) {
15926
+ lastInput = captureInput(input);
15927
+ }
15928
+ };
15895
15929
  const clipboard = new ClipboardBridge(
15896
15930
  (message) => window.parent.postMessage(message, "*"),
15897
15931
  (text2) => navigator.clipboard.writeText(text2),
15898
15932
  window.parent !== window && document.body.dataset.accountHost === "true"
15899
15933
  );
15900
15934
  addEventListener("pagehide", () => clipboard.dispose());
15935
+ addEventListener("keydown", (event) => {
15936
+ if (!editHost || !nativePasteHost || event.defaultPrevented || event.key.toLowerCase() !== "v" || !(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey || !(event.target instanceof Element) || !event.target.closest("textarea, input, [contenteditable=true]")) {
15937
+ return;
15938
+ }
15939
+ event.preventDefault();
15940
+ contextInput = void 0;
15941
+ rememberInput();
15942
+ window.parent.postMessage({ type: "workflow-edit", version: 1, command: "paste" }, "*");
15943
+ });
15944
+ addEventListener("contextmenu", (event) => {
15945
+ if (!editHost || event.defaultPrevented || !(event.target instanceof Element)) {
15946
+ return;
15947
+ }
15948
+ const input = event.target.closest("textarea, input, [contenteditable=true]");
15949
+ if (!input) {
15950
+ return;
15951
+ }
15952
+ event.preventDefault();
15953
+ input.focus({ preventScroll: true });
15954
+ contextInput = lastInput = captureInput(input);
15955
+ window.parent.postMessage({ type: "workflow-contextmenu", version: 1, x: event.clientX, y: event.clientY }, "*");
15956
+ });
15957
+ addEventListener("focusin", (event) => {
15958
+ if (event.target instanceof Element && event.target !== contextInput?.element && event.target.matches("textarea, input, [contenteditable=true]")) {
15959
+ contextInput = void 0;
15960
+ }
15961
+ rememberInput();
15962
+ });
15963
+ addEventListener("input", rememberInput);
15964
+ addEventListener("selectionchange", rememberInput, true);
15965
+ addEventListener("pointerdown", (event) => {
15966
+ if (event.button !== 2) {
15967
+ contextInput = void 0;
15968
+ }
15969
+ if (event.target instanceof Element && !event.target.closest("textarea, input, [contenteditable=true]")) {
15970
+ lastInput = void 0;
15971
+ }
15972
+ });
15901
15973
  const connection = new BrowserConnection((message) => {
15902
15974
  if (message.type === "state" && message.account) {
15903
15975
  accountPanel.update(message.account);
@@ -15922,17 +15994,37 @@ ${state2.user?.avatarUrl ?? ""}`;
15922
15994
  }
15923
15995
  if (event.data.clipboardVersion !== void 0) {
15924
15996
  clipboard.enable(event.data.clipboardVersion);
15925
- if (event.data.clipboardVersion === 1) {
15997
+ editHost = event.data.clipboardVersion === 1;
15998
+ if (editHost) {
15926
15999
  window.parent.postMessage({ type: "workflow-edit", version: 1 }, "*");
15927
16000
  }
15928
16001
  }
15929
16002
  if (event.data.resourceVersion === 1) {
15930
16003
  resourceHost = true;
15931
16004
  }
16005
+ if (event.data.nativePasteVersion !== void 0) {
16006
+ nativePasteHost = event.data.nativePasteVersion === 1;
16007
+ }
15932
16008
  if (event.data.resourceError) {
15933
16009
  emit(event.data.resourceError);
15934
16010
  }
15935
- if (["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
16011
+ if ((event.data.restoreFocus === true || event.data.clipboardData && document.activeElement === document.body) && ["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
16012
+ const context = contextInput ?? lastInput;
16013
+ contextInput = void 0;
16014
+ if (context) {
16015
+ const input = context.element;
16016
+ if (!input.isConnected || context.selection && input.value !== context.selection.value) {
16017
+ return;
16018
+ }
16019
+ input.focus({ preventScroll: true });
16020
+ if (context.selection) {
16021
+ input.setSelectionRange(context.selection.start, context.selection.end, context.selection.direction);
16022
+ }
16023
+ }
16024
+ }
16025
+ if (event.data.editCommand === "paste" && event.data.clipboardData) {
16026
+ pasteHostClipboard(event.data.clipboardData);
16027
+ } else if (["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
15936
16028
  document.execCommand(event.data.editCommand);
15937
16029
  }
15938
16030
  clipboard.receive(event.data.clipboard);
@@ -16826,6 +16918,7 @@ ${state2.user?.avatarUrl ?? ""}`;
16826
16918
  body = document.createElement("div");
16827
16919
  title = document.createElement("h2");
16828
16920
  usageOpen = false;
16921
+ usageRequestId;
16829
16922
  refresh;
16830
16923
  constructor() {
16831
16924
  this.dialog.className = "conversation-dialog";
@@ -16852,9 +16945,15 @@ ${state2.user?.avatarUrl ?? ""}`;
16852
16945
  close() {
16853
16946
  this.dialog.close();
16854
16947
  this.usageOpen = false;
16948
+ this.usageRequestId = void 0;
16855
16949
  this.refresh?.remove();
16856
16950
  this.refresh = void 0;
16857
16951
  }
16952
+ closeUsage() {
16953
+ if (this.usageOpen) {
16954
+ this.close();
16955
+ }
16956
+ }
16858
16957
  show(title) {
16859
16958
  this.close();
16860
16959
  this.title.textContent = title;
@@ -16961,10 +17060,11 @@ ${state2.user?.avatarUrl ?? ""}`;
16961
17060
  if (this.refresh) {
16962
17061
  this.refresh.disabled = true;
16963
17062
  }
16964
- load();
17063
+ this.usageRequestId = crypto.randomUUID();
17064
+ load(this.usageRequestId);
16965
17065
  }
16966
- usageResult(data, error) {
16967
- if (!this.usageOpen) {
17066
+ usageResult(requestId, data, error) {
17067
+ if (!this.usageOpen || requestId !== this.usageRequestId) {
16968
17068
  return;
16969
17069
  }
16970
17070
  this.body.replaceChildren();
@@ -17848,7 +17948,7 @@ ${state2.user?.avatarUrl ?? ""}`;
17848
17948
  controls();
17849
17949
  }
17850
17950
  };
17851
- element("usage").onclick = () => dialogs.usage(() => host.postMessage({ type: "usage" }));
17951
+ element("usage").onclick = () => dialogs.usage((requestId) => host.postMessage({ type: "usage", requestId }));
17852
17952
  element("project-info").onclick = () => {
17853
17953
  if (project) {
17854
17954
  dialogs.projectInfo(project);
@@ -17933,6 +18033,7 @@ ${state2.user?.avatarUrl ?? ""}`;
17933
18033
  saveTimer = setTimeout(() => void save().catch(showError), 250);
17934
18034
  }
17935
18035
  } else {
18036
+ dialogs.closeUsage();
17936
18037
  for (const waiting of pending.values()) {
17937
18038
  clearTimeout(waiting.timer);
17938
18039
  waiting.reject(new Error(t2("Connection interrupted.")));
@@ -17949,15 +18050,16 @@ ${state2.user?.avatarUrl ?? ""}`;
17949
18050
  if (authRevision !== message.authenticationRevision) {
17950
18051
  authRevision = message.authenticationRevision;
17951
18052
  previewKey = "";
18053
+ dialogs.closeUsage();
17952
18054
  }
17953
18055
  element("usage").hidden = message.account.status !== "authenticated";
17954
18056
  update(message.kanban);
17955
18057
  }
17956
18058
  if (message.type === "usage") {
17957
- dialogs.usageResult(message.usage);
18059
+ dialogs.usageResult(message.requestId, message.usage);
17958
18060
  }
17959
18061
  if (message.type === "error" && message.requestType === "usage") {
17960
- dialogs.usageResult(void 0, message.message);
18062
+ dialogs.usageResult(message.requestId, void 0, message.message);
17961
18063
  return;
17962
18064
  }
17963
18065
  if (message.type === "error" && !message.silent && !message.requestId) {
@@ -1044,6 +1044,30 @@ main {
1044
1044
  height: 100%;
1045
1045
  object-fit: cover;
1046
1046
  }
1047
+ .attachment-image {
1048
+ position: relative;
1049
+ padding: 0;
1050
+ border: 0;
1051
+ background: transparent;
1052
+ }
1053
+ .attachment-image .attachment-preview {
1054
+ width: 88px;
1055
+ height: 88px;
1056
+ background: transparent;
1057
+ }
1058
+ .message .attachment-image .attachment-preview {
1059
+ width: 120px;
1060
+ height: 120px;
1061
+ }
1062
+ .attachment-image .attachment-preview img {
1063
+ object-fit: contain;
1064
+ }
1065
+ .attachment-image > .icon-button {
1066
+ position: absolute;
1067
+ top: 0;
1068
+ right: 0;
1069
+ background: var(--vscode-editor-background);
1070
+ }
1047
1071
  #draft-attachments {
1048
1072
  padding: 0 16px;
1049
1073
  }
@@ -1702,6 +1726,7 @@ textarea::placeholder {
1702
1726
  }
1703
1727
  .param-action:has(.param-action-summary:not([hidden])) .param-action-label {
1704
1728
  flex-shrink: 0;
1729
+ max-width: 50%;
1705
1730
  font-weight: 500;
1706
1731
  }
1707
1732
  .param-action-ai {
@@ -12608,6 +12608,7 @@
12608
12608
  "{1} in {0}": "{0} \u4E2D {1}",
12609
12609
  "Account balance ${0}": "\u8D26\u6237\u4F59\u989D ${0}",
12610
12610
  "Account balance": "\u8D26\u6237\u4F59\u989D",
12611
+ "Account changed. Refresh usage.": "\u8D26\u53F7\u5DF2\u5207\u6362\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6\u7528\u91CF\u3002",
12611
12612
  "AI usage": "AI \u7528\u91CF",
12612
12613
  All: "\u5168\u90E8",
12613
12614
  "Basic information": "\u57FA\u672C\u4FE1\u606F",
@@ -14400,14 +14401,14 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14400
14401
  DocumentFragment,
14401
14402
  HTMLTemplateElement,
14402
14403
  Node,
14403
- Element,
14404
+ Element: Element2,
14404
14405
  NodeFilter,
14405
14406
  NamedNodeMap = window2.NamedNodeMap || window2.MozNamedAttrMap,
14406
14407
  HTMLFormElement,
14407
14408
  DOMParser,
14408
14409
  trustedTypes
14409
14410
  } = window2;
14410
- const ElementPrototype = Element.prototype;
14411
+ const ElementPrototype = Element2.prototype;
14411
14412
  const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
14412
14413
  const remove = lookupGetter(ElementPrototype, "remove");
14413
14414
  const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
@@ -14861,7 +14862,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14861
14862
  _forceRemove(currentNode);
14862
14863
  return true;
14863
14864
  }
14864
- if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
14865
+ if (currentNode instanceof Element2 && !_checkValidNamespace(currentNode)) {
14865
14866
  _forceRemove(currentNode);
14866
14867
  return true;
14867
14868
  }
@@ -15870,6 +15871,28 @@ ${state.user?.avatarUrl ?? ""}`;
15870
15871
  }
15871
15872
  };
15872
15873
 
15874
+ // src/web/ui/edit-commands.ts
15875
+ function pasteHostClipboard(clipboard) {
15876
+ if (typeof clipboard.text !== "string" || clipboard.image !== void 0 && !ArrayBuffer.isView(clipboard.image)) {
15877
+ return;
15878
+ }
15879
+ const target = document.activeElement;
15880
+ if (!(target instanceof HTMLElement) || !target.matches("textarea, input, [contenteditable=true]") || target.matches(":disabled, [readonly]")) {
15881
+ return;
15882
+ }
15883
+ const transfer = new DataTransfer();
15884
+ transfer.setData("text/plain", clipboard.text);
15885
+ if (clipboard.image && clipboard.image.byteLength) {
15886
+ const image = new Uint8Array(clipboard.image.buffer, clipboard.image.byteOffset, clipboard.image.byteLength);
15887
+ transfer.items.add(new File([new Uint8Array(image)], "clipboard.png", { type: "image/png" }));
15888
+ }
15889
+ const event = new ClipboardEvent("paste", { bubbles: true, cancelable: true, clipboardData: transfer });
15890
+ target.dispatchEvent(event);
15891
+ if (!event.defaultPrevented && clipboard.text) {
15892
+ document.execCommand("insertText", false, clipboard.text);
15893
+ }
15894
+ }
15895
+
15873
15896
  // src/web/ui/host.ts
15874
15897
  function acquireWorkflowHost(options = {}) {
15875
15898
  const embedded = globalThis.acquireVsCodeApi;
@@ -15891,13 +15914,62 @@ ${state.user?.avatarUrl ?? ""}`;
15891
15914
  window.parent.postMessage(message, "*");
15892
15915
  }
15893
15916
  });
15894
- let resourceHost = false;
15917
+ let resourceHost = false, editHost = false, nativePasteHost = false;
15918
+ let contextInput, lastInput;
15919
+ const captureInput = (input) => {
15920
+ const field = input;
15921
+ return { element: input, selection: typeof field.selectionStart === "number" && typeof field.selectionEnd === "number" ? { start: field.selectionStart, end: field.selectionEnd, direction: field.selectionDirection ?? "none", value: field.value } : void 0 };
15922
+ };
15923
+ const rememberInput = () => {
15924
+ const input = document.activeElement;
15925
+ if (input instanceof HTMLElement && input.matches("textarea, input, [contenteditable=true]")) {
15926
+ lastInput = captureInput(input);
15927
+ }
15928
+ };
15895
15929
  const clipboard = new ClipboardBridge(
15896
15930
  (message) => window.parent.postMessage(message, "*"),
15897
15931
  (text2) => navigator.clipboard.writeText(text2),
15898
15932
  window.parent !== window && document.body.dataset.accountHost === "true"
15899
15933
  );
15900
15934
  addEventListener("pagehide", () => clipboard.dispose());
15935
+ addEventListener("keydown", (event) => {
15936
+ if (!editHost || !nativePasteHost || event.defaultPrevented || event.key.toLowerCase() !== "v" || !(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey || !(event.target instanceof Element) || !event.target.closest("textarea, input, [contenteditable=true]")) {
15937
+ return;
15938
+ }
15939
+ event.preventDefault();
15940
+ contextInput = void 0;
15941
+ rememberInput();
15942
+ window.parent.postMessage({ type: "workflow-edit", version: 1, command: "paste" }, "*");
15943
+ });
15944
+ addEventListener("contextmenu", (event) => {
15945
+ if (!editHost || event.defaultPrevented || !(event.target instanceof Element)) {
15946
+ return;
15947
+ }
15948
+ const input = event.target.closest("textarea, input, [contenteditable=true]");
15949
+ if (!input) {
15950
+ return;
15951
+ }
15952
+ event.preventDefault();
15953
+ input.focus({ preventScroll: true });
15954
+ contextInput = lastInput = captureInput(input);
15955
+ window.parent.postMessage({ type: "workflow-contextmenu", version: 1, x: event.clientX, y: event.clientY }, "*");
15956
+ });
15957
+ addEventListener("focusin", (event) => {
15958
+ if (event.target instanceof Element && event.target !== contextInput?.element && event.target.matches("textarea, input, [contenteditable=true]")) {
15959
+ contextInput = void 0;
15960
+ }
15961
+ rememberInput();
15962
+ });
15963
+ addEventListener("input", rememberInput);
15964
+ addEventListener("selectionchange", rememberInput, true);
15965
+ addEventListener("pointerdown", (event) => {
15966
+ if (event.button !== 2) {
15967
+ contextInput = void 0;
15968
+ }
15969
+ if (event.target instanceof Element && !event.target.closest("textarea, input, [contenteditable=true]")) {
15970
+ lastInput = void 0;
15971
+ }
15972
+ });
15901
15973
  const connection = new BrowserConnection((message) => {
15902
15974
  if (message.type === "state" && message.account) {
15903
15975
  accountPanel.update(message.account);
@@ -15922,17 +15994,37 @@ ${state.user?.avatarUrl ?? ""}`;
15922
15994
  }
15923
15995
  if (event.data.clipboardVersion !== void 0) {
15924
15996
  clipboard.enable(event.data.clipboardVersion);
15925
- if (event.data.clipboardVersion === 1) {
15997
+ editHost = event.data.clipboardVersion === 1;
15998
+ if (editHost) {
15926
15999
  window.parent.postMessage({ type: "workflow-edit", version: 1 }, "*");
15927
16000
  }
15928
16001
  }
15929
16002
  if (event.data.resourceVersion === 1) {
15930
16003
  resourceHost = true;
15931
16004
  }
16005
+ if (event.data.nativePasteVersion !== void 0) {
16006
+ nativePasteHost = event.data.nativePasteVersion === 1;
16007
+ }
15932
16008
  if (event.data.resourceError) {
15933
16009
  emit(event.data.resourceError);
15934
16010
  }
15935
- if (["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
16011
+ if ((event.data.restoreFocus === true || event.data.clipboardData && document.activeElement === document.body) && ["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
16012
+ const context = contextInput ?? lastInput;
16013
+ contextInput = void 0;
16014
+ if (context) {
16015
+ const input = context.element;
16016
+ if (!input.isConnected || context.selection && input.value !== context.selection.value) {
16017
+ return;
16018
+ }
16019
+ input.focus({ preventScroll: true });
16020
+ if (context.selection) {
16021
+ input.setSelectionRange(context.selection.start, context.selection.end, context.selection.direction);
16022
+ }
16023
+ }
16024
+ }
16025
+ if (event.data.editCommand === "paste" && event.data.clipboardData) {
16026
+ pasteHostClipboard(event.data.clipboardData);
16027
+ } else if (["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
15936
16028
  document.execCommand(event.data.editCommand);
15937
16029
  }
15938
16030
  clipboard.receive(event.data.clipboard);
@@ -1044,6 +1044,30 @@ main {
1044
1044
  height: 100%;
1045
1045
  object-fit: cover;
1046
1046
  }
1047
+ .attachment-image {
1048
+ position: relative;
1049
+ padding: 0;
1050
+ border: 0;
1051
+ background: transparent;
1052
+ }
1053
+ .attachment-image .attachment-preview {
1054
+ width: 88px;
1055
+ height: 88px;
1056
+ background: transparent;
1057
+ }
1058
+ .message .attachment-image .attachment-preview {
1059
+ width: 120px;
1060
+ height: 120px;
1061
+ }
1062
+ .attachment-image .attachment-preview img {
1063
+ object-fit: contain;
1064
+ }
1065
+ .attachment-image > .icon-button {
1066
+ position: absolute;
1067
+ top: 0;
1068
+ right: 0;
1069
+ background: var(--vscode-editor-background);
1070
+ }
1047
1071
  #draft-attachments {
1048
1072
  padding: 0 16px;
1049
1073
  }
@@ -1702,6 +1726,7 @@ textarea::placeholder {
1702
1726
  }
1703
1727
  .param-action:has(.param-action-summary:not([hidden])) .param-action-label {
1704
1728
  flex-shrink: 0;
1729
+ max-width: 50%;
1705
1730
  font-weight: 500;
1706
1731
  }
1707
1732
  .param-action-ai {
@@ -12608,6 +12608,7 @@
12608
12608
  "{1} in {0}": "{0} \u4E2D {1}",
12609
12609
  "Account balance ${0}": "\u8D26\u6237\u4F59\u989D ${0}",
12610
12610
  "Account balance": "\u8D26\u6237\u4F59\u989D",
12611
+ "Account changed. Refresh usage.": "\u8D26\u53F7\u5DF2\u5207\u6362\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6\u7528\u91CF\u3002",
12611
12612
  "AI usage": "AI \u7528\u91CF",
12612
12613
  All: "\u5168\u90E8",
12613
12614
  "Basic information": "\u57FA\u672C\u4FE1\u606F",
@@ -14896,14 +14897,14 @@ Please report this to https://github.com/markedjs/marked.`, e) {
14896
14897
  DocumentFragment,
14897
14898
  HTMLTemplateElement,
14898
14899
  Node: Node2,
14899
- Element,
14900
+ Element: Element2,
14900
14901
  NodeFilter: NodeFilter2,
14901
14902
  NamedNodeMap = window2.NamedNodeMap || window2.MozNamedAttrMap,
14902
14903
  HTMLFormElement,
14903
14904
  DOMParser,
14904
14905
  trustedTypes
14905
14906
  } = window2;
14906
- const ElementPrototype = Element.prototype;
14907
+ const ElementPrototype = Element2.prototype;
14907
14908
  const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
14908
14909
  const remove = lookupGetter(ElementPrototype, "remove");
14909
14910
  const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
@@ -15357,7 +15358,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
15357
15358
  _forceRemove(currentNode);
15358
15359
  return true;
15359
15360
  }
15360
- if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
15361
+ if (currentNode instanceof Element2 && !_checkValidNamespace(currentNode)) {
15361
15362
  _forceRemove(currentNode);
15362
15363
  return true;
15363
15364
  }
@@ -16058,6 +16059,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
16058
16059
  body = document.createElement("div");
16059
16060
  title = document.createElement("h2");
16060
16061
  usageOpen = false;
16062
+ usageRequestId;
16061
16063
  refresh;
16062
16064
  constructor() {
16063
16065
  this.dialog.className = "conversation-dialog";
@@ -16084,9 +16086,15 @@ Please report this to https://github.com/markedjs/marked.`, e) {
16084
16086
  close() {
16085
16087
  this.dialog.close();
16086
16088
  this.usageOpen = false;
16089
+ this.usageRequestId = void 0;
16087
16090
  this.refresh?.remove();
16088
16091
  this.refresh = void 0;
16089
16092
  }
16093
+ closeUsage() {
16094
+ if (this.usageOpen) {
16095
+ this.close();
16096
+ }
16097
+ }
16090
16098
  show(title) {
16091
16099
  this.close();
16092
16100
  this.title.textContent = title;
@@ -16193,10 +16201,11 @@ Please report this to https://github.com/markedjs/marked.`, e) {
16193
16201
  if (this.refresh) {
16194
16202
  this.refresh.disabled = true;
16195
16203
  }
16196
- load();
16204
+ this.usageRequestId = crypto.randomUUID();
16205
+ load(this.usageRequestId);
16197
16206
  }
16198
- usageResult(data, error) {
16199
- if (!this.usageOpen) {
16207
+ usageResult(requestId, data, error) {
16208
+ if (!this.usageOpen || requestId !== this.usageRequestId) {
16200
16209
  return;
16201
16210
  }
16202
16211
  this.body.replaceChildren();
@@ -17826,6 +17835,28 @@ ${state.user?.avatarUrl ?? ""}`;
17826
17835
  }
17827
17836
  };
17828
17837
 
17838
+ // src/web/ui/edit-commands.ts
17839
+ function pasteHostClipboard(clipboard) {
17840
+ if (typeof clipboard.text !== "string" || clipboard.image !== void 0 && !ArrayBuffer.isView(clipboard.image)) {
17841
+ return;
17842
+ }
17843
+ const target = document.activeElement;
17844
+ if (!(target instanceof HTMLElement) || !target.matches("textarea, input, [contenteditable=true]") || target.matches(":disabled, [readonly]")) {
17845
+ return;
17846
+ }
17847
+ const transfer = new DataTransfer();
17848
+ transfer.setData("text/plain", clipboard.text);
17849
+ if (clipboard.image && clipboard.image.byteLength) {
17850
+ const image = new Uint8Array(clipboard.image.buffer, clipboard.image.byteOffset, clipboard.image.byteLength);
17851
+ transfer.items.add(new File([new Uint8Array(image)], "clipboard.png", { type: "image/png" }));
17852
+ }
17853
+ const event = new ClipboardEvent("paste", { bubbles: true, cancelable: true, clipboardData: transfer });
17854
+ target.dispatchEvent(event);
17855
+ if (!event.defaultPrevented && clipboard.text) {
17856
+ document.execCommand("insertText", false, clipboard.text);
17857
+ }
17858
+ }
17859
+
17829
17860
  // src/web/ui/host.ts
17830
17861
  function acquireWorkflowHost(options = {}) {
17831
17862
  const embedded = globalThis.acquireVsCodeApi;
@@ -17847,13 +17878,62 @@ ${state.user?.avatarUrl ?? ""}`;
17847
17878
  window.parent.postMessage(message, "*");
17848
17879
  }
17849
17880
  });
17850
- let resourceHost = false;
17881
+ let resourceHost = false, editHost = false, nativePasteHost = false;
17882
+ let contextInput, lastInput;
17883
+ const captureInput = (input) => {
17884
+ const field = input;
17885
+ return { element: input, selection: typeof field.selectionStart === "number" && typeof field.selectionEnd === "number" ? { start: field.selectionStart, end: field.selectionEnd, direction: field.selectionDirection ?? "none", value: field.value } : void 0 };
17886
+ };
17887
+ const rememberInput = () => {
17888
+ const input = document.activeElement;
17889
+ if (input instanceof HTMLElement && input.matches("textarea, input, [contenteditable=true]")) {
17890
+ lastInput = captureInput(input);
17891
+ }
17892
+ };
17851
17893
  const clipboard = new ClipboardBridge(
17852
17894
  (message) => window.parent.postMessage(message, "*"),
17853
17895
  (text3) => navigator.clipboard.writeText(text3),
17854
17896
  window.parent !== window && document.body.dataset.accountHost === "true"
17855
17897
  );
17856
17898
  addEventListener("pagehide", () => clipboard.dispose());
17899
+ addEventListener("keydown", (event) => {
17900
+ if (!editHost || !nativePasteHost || event.defaultPrevented || event.key.toLowerCase() !== "v" || !(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey || !(event.target instanceof Element) || !event.target.closest("textarea, input, [contenteditable=true]")) {
17901
+ return;
17902
+ }
17903
+ event.preventDefault();
17904
+ contextInput = void 0;
17905
+ rememberInput();
17906
+ window.parent.postMessage({ type: "workflow-edit", version: 1, command: "paste" }, "*");
17907
+ });
17908
+ addEventListener("contextmenu", (event) => {
17909
+ if (!editHost || event.defaultPrevented || !(event.target instanceof Element)) {
17910
+ return;
17911
+ }
17912
+ const input = event.target.closest("textarea, input, [contenteditable=true]");
17913
+ if (!input) {
17914
+ return;
17915
+ }
17916
+ event.preventDefault();
17917
+ input.focus({ preventScroll: true });
17918
+ contextInput = lastInput = captureInput(input);
17919
+ window.parent.postMessage({ type: "workflow-contextmenu", version: 1, x: event.clientX, y: event.clientY }, "*");
17920
+ });
17921
+ addEventListener("focusin", (event) => {
17922
+ if (event.target instanceof Element && event.target !== contextInput?.element && event.target.matches("textarea, input, [contenteditable=true]")) {
17923
+ contextInput = void 0;
17924
+ }
17925
+ rememberInput();
17926
+ });
17927
+ addEventListener("input", rememberInput);
17928
+ addEventListener("selectionchange", rememberInput, true);
17929
+ addEventListener("pointerdown", (event) => {
17930
+ if (event.button !== 2) {
17931
+ contextInput = void 0;
17932
+ }
17933
+ if (event.target instanceof Element && !event.target.closest("textarea, input, [contenteditable=true]")) {
17934
+ lastInput = void 0;
17935
+ }
17936
+ });
17857
17937
  const connection = new BrowserConnection((message) => {
17858
17938
  if (message.type === "state" && message.account) {
17859
17939
  accountPanel.update(message.account);
@@ -17878,17 +17958,37 @@ ${state.user?.avatarUrl ?? ""}`;
17878
17958
  }
17879
17959
  if (event.data.clipboardVersion !== void 0) {
17880
17960
  clipboard.enable(event.data.clipboardVersion);
17881
- if (event.data.clipboardVersion === 1) {
17961
+ editHost = event.data.clipboardVersion === 1;
17962
+ if (editHost) {
17882
17963
  window.parent.postMessage({ type: "workflow-edit", version: 1 }, "*");
17883
17964
  }
17884
17965
  }
17885
17966
  if (event.data.resourceVersion === 1) {
17886
17967
  resourceHost = true;
17887
17968
  }
17969
+ if (event.data.nativePasteVersion !== void 0) {
17970
+ nativePasteHost = event.data.nativePasteVersion === 1;
17971
+ }
17888
17972
  if (event.data.resourceError) {
17889
17973
  emit(event.data.resourceError);
17890
17974
  }
17891
- if (["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
17975
+ if ((event.data.restoreFocus === true || event.data.clipboardData && document.activeElement === document.body) && ["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
17976
+ const context = contextInput ?? lastInput;
17977
+ contextInput = void 0;
17978
+ if (context) {
17979
+ const input = context.element;
17980
+ if (!input.isConnected || context.selection && input.value !== context.selection.value) {
17981
+ return;
17982
+ }
17983
+ input.focus({ preventScroll: true });
17984
+ if (context.selection) {
17985
+ input.setSelectionRange(context.selection.start, context.selection.end, context.selection.direction);
17986
+ }
17987
+ }
17988
+ }
17989
+ if (event.data.editCommand === "paste" && event.data.clipboardData) {
17990
+ pasteHostClipboard(event.data.clipboardData);
17991
+ } else if (["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
17892
17992
  document.execCommand(event.data.editCommand);
17893
17993
  }
17894
17994
  clipboard.receive(event.data.clipboard);
@@ -18627,31 +18727,36 @@ ${state.user?.avatarUrl ?? ""}`;
18627
18727
  container.replaceChildren();
18628
18728
  container.hidden = !attachments.length;
18629
18729
  for (const file of attachments) {
18730
+ const isImage = file.kind === "image";
18630
18731
  const item = document.createElement("div");
18631
- item.className = "attachment";
18732
+ item.className = `attachment${isImage ? " attachment-image" : ""}`;
18632
18733
  const preview = document.createElement("button");
18633
18734
  preview.type = "button";
18634
18735
  preview.className = "attachment-preview";
18635
- preview.title = file.name;
18636
- if (file.kind === "image" && file.previewUrl) {
18736
+ preview.title = isImage ? t2("Image") : file.name;
18737
+ preview.setAttribute("aria-label", preview.title);
18738
+ if (isImage && file.previewUrl) {
18637
18739
  const image = document.createElement("img");
18638
18740
  image.src = file.previewUrl;
18639
- image.alt = file.name;
18741
+ image.alt = t2("Image");
18640
18742
  preview.append(image);
18641
18743
  } else {
18642
18744
  preview.innerHTML = iconHtml(file.mimeType.startsWith("audio/") ? "unmute" : file.mimeType.startsWith("video/") ? "device-camera-video" : "file");
18643
18745
  }
18644
18746
  preview.addEventListener("click", () => {
18645
- if (file.kind === "image" && file.previewUrl) {
18646
- dialogs.image(file.previewUrl, file.name);
18747
+ if (isImage && file.previewUrl) {
18748
+ dialogs.image(file.previewUrl, t2("Image"));
18647
18749
  } else {
18648
18750
  post({ type: "open-file", id: file.id });
18649
18751
  }
18650
18752
  });
18651
- const name = document.createElement("span");
18652
- name.textContent = file.name;
18653
- name.title = file.name;
18654
- item.append(preview, name);
18753
+ item.append(preview);
18754
+ if (!isImage) {
18755
+ const name = document.createElement("span");
18756
+ name.textContent = file.name;
18757
+ name.title = file.name;
18758
+ item.append(name);
18759
+ }
18655
18760
  if (removable) {
18656
18761
  item.append(iconButton("close", t2("Remove attachment"), () => {
18657
18762
  draftFiles = draftFiles.filter((entry) => entry.id !== file.id);
@@ -18879,6 +18984,9 @@ ${state.user?.avatarUrl ?? ""}`;
18879
18984
  folder.title = next.project.assistant?.workdir ?? "";
18880
18985
  const switching = projectChanged || renderedSession !== next.activeId;
18881
18986
  const authenticationChanged = previous && (previous.authenticationRevision !== next.authenticationRevision || previous.parameterRevision !== next.parameterRevision);
18987
+ if (previous && previous.authenticationRevision !== next.authenticationRevision) {
18988
+ dialogs.closeUsage();
18989
+ }
18882
18990
  if (authenticationChanged) {
18883
18991
  ++requestId;
18884
18992
  resolving = false;
@@ -19063,7 +19171,7 @@ ${state.user?.avatarUrl ?? ""}`;
19063
19171
  document.querySelector("#attach").addEventListener("click", () => post({ type: "attach" }));
19064
19172
  document.querySelector("#cancel-queue-edit").addEventListener("click", () => post({ type: "queue-cancel-edit" }));
19065
19173
  document.querySelector("#tools").addEventListener("click", () => dialogs.permissions(currentParameters(), currentSession()?.toolPermissionPolicies ?? {}, (policies) => post({ type: "tool-policy", entrypointId: entrypoint.value, policies })));
19066
- document.querySelector("#usage").addEventListener("click", () => dialogs.usage(() => post({ type: "usage" })));
19174
+ document.querySelector("#usage").addEventListener("click", () => dialogs.usage((requestId2) => post({ type: "usage", requestId: requestId2 })));
19067
19175
  document.querySelector("#parameter-login").addEventListener("click", () => vscode.postMessage({ type: "login" }));
19068
19176
  document.querySelector("#menu-toggle").addEventListener("click", () => showMenu(true));
19069
19177
  document.querySelector("#hide-menu").addEventListener("click", () => showMenu(false));
@@ -19205,6 +19313,7 @@ ${state.user?.avatarUrl ?? ""}`;
19205
19313
  if (!connectionAvailable) {
19206
19314
  resolving = false;
19207
19315
  requestId++;
19316
+ dialogs.closeUsage();
19208
19317
  }
19209
19318
  sendButton.disabled = !connectionAvailable || sendButton.disabled;
19210
19319
  updateControls();
@@ -19294,7 +19403,7 @@ ${state.user?.avatarUrl ?? ""}`;
19294
19403
  updateControls();
19295
19404
  textarea.focus();
19296
19405
  } else if (message.type === "usage" && message.sessionId === state?.activeId) {
19297
- dialogs.usageResult(message.usage);
19406
+ dialogs.usageResult(message.requestId, message.usage);
19298
19407
  } else if (message.type === "exported" && message.sessionId === state?.activeId) {
19299
19408
  const button = messages.get(message.messageId)?.root.querySelector(".export-message");
19300
19409
  if (button) {
@@ -19302,14 +19411,15 @@ ${state.user?.avatarUrl ?? ""}`;
19302
19411
  button.innerHTML = iconHtml("export");
19303
19412
  }
19304
19413
  } else if (message.type === "error" && (!message.sessionId || message.sessionId === state?.activeId)) {
19414
+ if (message.requestType === "usage") {
19415
+ dialogs.usageResult(message.requestId, void 0, message.message);
19416
+ return;
19417
+ }
19305
19418
  if (message.requestType === "resume" && messages.get(message.messageId)?.prompt?.request.requestId !== message.requestId) {
19306
19419
  return;
19307
19420
  }
19308
19421
  submitting = false;
19309
19422
  uploading = Math.max(0, uploading - 1);
19310
- if (message.requestType === "usage") {
19311
- dialogs.usageResult(void 0, message.message);
19312
- }
19313
19423
  if (message.requestType === "resume") {
19314
19424
  messages.get(message.messageId)?.prompt?.setBusy(false, message.message);
19315
19425
  }
@@ -1044,6 +1044,30 @@ main {
1044
1044
  height: 100%;
1045
1045
  object-fit: cover;
1046
1046
  }
1047
+ .attachment-image {
1048
+ position: relative;
1049
+ padding: 0;
1050
+ border: 0;
1051
+ background: transparent;
1052
+ }
1053
+ .attachment-image .attachment-preview {
1054
+ width: 88px;
1055
+ height: 88px;
1056
+ background: transparent;
1057
+ }
1058
+ .message .attachment-image .attachment-preview {
1059
+ width: 120px;
1060
+ height: 120px;
1061
+ }
1062
+ .attachment-image .attachment-preview img {
1063
+ object-fit: contain;
1064
+ }
1065
+ .attachment-image > .icon-button {
1066
+ position: absolute;
1067
+ top: 0;
1068
+ right: 0;
1069
+ background: var(--vscode-editor-background);
1070
+ }
1047
1071
  #draft-attachments {
1048
1072
  padding: 0 16px;
1049
1073
  }
@@ -1702,6 +1726,7 @@ textarea::placeholder {
1702
1726
  }
1703
1727
  .param-action:has(.param-action-summary:not([hidden])) .param-action-label {
1704
1728
  flex-shrink: 0;
1729
+ max-width: 50%;
1705
1730
  font-weight: 500;
1706
1731
  }
1707
1732
  .param-action-ai {
@@ -16137,6 +16137,7 @@
16137
16137
  "{1} in {0}": "{0} \u4E2D {1}",
16138
16138
  "Account balance ${0}": "\u8D26\u6237\u4F59\u989D ${0}",
16139
16139
  "Account balance": "\u8D26\u6237\u4F59\u989D",
16140
+ "Account changed. Refresh usage.": "\u8D26\u53F7\u5DF2\u5207\u6362\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6\u7528\u91CF\u3002",
16140
16141
  "AI usage": "AI \u7528\u91CF",
16141
16142
  All: "\u5168\u90E8",
16142
16143
  "Basic information": "\u57FA\u672C\u4FE1\u606F",
@@ -17929,14 +17930,14 @@ Please report this to https://github.com/markedjs/marked.`, e) {
17929
17930
  DocumentFragment,
17930
17931
  HTMLTemplateElement,
17931
17932
  Node,
17932
- Element,
17933
+ Element: Element2,
17933
17934
  NodeFilter,
17934
17935
  NamedNodeMap = window2.NamedNodeMap || window2.MozNamedAttrMap,
17935
17936
  HTMLFormElement,
17936
17937
  DOMParser,
17937
17938
  trustedTypes
17938
17939
  } = window2;
17939
- const ElementPrototype = Element.prototype;
17940
+ const ElementPrototype = Element2.prototype;
17940
17941
  const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
17941
17942
  const remove = lookupGetter(ElementPrototype, "remove");
17942
17943
  const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
@@ -18390,7 +18391,7 @@ Please report this to https://github.com/markedjs/marked.`, e) {
18390
18391
  _forceRemove(currentNode);
18391
18392
  return true;
18392
18393
  }
18393
- if (currentNode instanceof Element && !_checkValidNamespace(currentNode)) {
18394
+ if (currentNode instanceof Element2 && !_checkValidNamespace(currentNode)) {
18394
18395
  _forceRemove(currentNode);
18395
18396
  return true;
18396
18397
  }
@@ -19414,6 +19415,28 @@ ${state2.user?.avatarUrl ?? ""}`;
19414
19415
  }
19415
19416
  };
19416
19417
 
19418
+ // src/web/ui/edit-commands.ts
19419
+ function pasteHostClipboard(clipboard) {
19420
+ if (typeof clipboard.text !== "string" || clipboard.image !== void 0 && !ArrayBuffer.isView(clipboard.image)) {
19421
+ return;
19422
+ }
19423
+ const target = document.activeElement;
19424
+ if (!(target instanceof HTMLElement) || !target.matches("textarea, input, [contenteditable=true]") || target.matches(":disabled, [readonly]")) {
19425
+ return;
19426
+ }
19427
+ const transfer = new DataTransfer();
19428
+ transfer.setData("text/plain", clipboard.text);
19429
+ if (clipboard.image && clipboard.image.byteLength) {
19430
+ const image = new Uint8Array(clipboard.image.buffer, clipboard.image.byteOffset, clipboard.image.byteLength);
19431
+ transfer.items.add(new File([new Uint8Array(image)], "clipboard.png", { type: "image/png" }));
19432
+ }
19433
+ const event = new ClipboardEvent("paste", { bubbles: true, cancelable: true, clipboardData: transfer });
19434
+ target.dispatchEvent(event);
19435
+ if (!event.defaultPrevented && clipboard.text) {
19436
+ document.execCommand("insertText", false, clipboard.text);
19437
+ }
19438
+ }
19439
+
19417
19440
  // src/web/ui/host.ts
19418
19441
  function acquireWorkflowHost(options = {}) {
19419
19442
  const embedded = globalThis.acquireVsCodeApi;
@@ -19435,13 +19458,62 @@ ${state2.user?.avatarUrl ?? ""}`;
19435
19458
  window.parent.postMessage(message, "*");
19436
19459
  }
19437
19460
  });
19438
- let resourceHost = false;
19461
+ let resourceHost = false, editHost = false, nativePasteHost = false;
19462
+ let contextInput, lastInput;
19463
+ const captureInput = (input) => {
19464
+ const field = input;
19465
+ return { element: input, selection: typeof field.selectionStart === "number" && typeof field.selectionEnd === "number" ? { start: field.selectionStart, end: field.selectionEnd, direction: field.selectionDirection ?? "none", value: field.value } : void 0 };
19466
+ };
19467
+ const rememberInput = () => {
19468
+ const input = document.activeElement;
19469
+ if (input instanceof HTMLElement && input.matches("textarea, input, [contenteditable=true]")) {
19470
+ lastInput = captureInput(input);
19471
+ }
19472
+ };
19439
19473
  const clipboard = new ClipboardBridge(
19440
19474
  (message) => window.parent.postMessage(message, "*"),
19441
19475
  (text3) => navigator.clipboard.writeText(text3),
19442
19476
  window.parent !== window && document.body.dataset.accountHost === "true"
19443
19477
  );
19444
19478
  addEventListener("pagehide", () => clipboard.dispose());
19479
+ addEventListener("keydown", (event) => {
19480
+ if (!editHost || !nativePasteHost || event.defaultPrevented || event.key.toLowerCase() !== "v" || !(event.ctrlKey || event.metaKey) || event.altKey || event.shiftKey || !(event.target instanceof Element) || !event.target.closest("textarea, input, [contenteditable=true]")) {
19481
+ return;
19482
+ }
19483
+ event.preventDefault();
19484
+ contextInput = void 0;
19485
+ rememberInput();
19486
+ window.parent.postMessage({ type: "workflow-edit", version: 1, command: "paste" }, "*");
19487
+ });
19488
+ addEventListener("contextmenu", (event) => {
19489
+ if (!editHost || event.defaultPrevented || !(event.target instanceof Element)) {
19490
+ return;
19491
+ }
19492
+ const input = event.target.closest("textarea, input, [contenteditable=true]");
19493
+ if (!input) {
19494
+ return;
19495
+ }
19496
+ event.preventDefault();
19497
+ input.focus({ preventScroll: true });
19498
+ contextInput = lastInput = captureInput(input);
19499
+ window.parent.postMessage({ type: "workflow-contextmenu", version: 1, x: event.clientX, y: event.clientY }, "*");
19500
+ });
19501
+ addEventListener("focusin", (event) => {
19502
+ if (event.target instanceof Element && event.target !== contextInput?.element && event.target.matches("textarea, input, [contenteditable=true]")) {
19503
+ contextInput = void 0;
19504
+ }
19505
+ rememberInput();
19506
+ });
19507
+ addEventListener("input", rememberInput);
19508
+ addEventListener("selectionchange", rememberInput, true);
19509
+ addEventListener("pointerdown", (event) => {
19510
+ if (event.button !== 2) {
19511
+ contextInput = void 0;
19512
+ }
19513
+ if (event.target instanceof Element && !event.target.closest("textarea, input, [contenteditable=true]")) {
19514
+ lastInput = void 0;
19515
+ }
19516
+ });
19445
19517
  const connection = new BrowserConnection((message) => {
19446
19518
  if (message.type === "state" && message.account) {
19447
19519
  accountPanel.update(message.account);
@@ -19466,17 +19538,37 @@ ${state2.user?.avatarUrl ?? ""}`;
19466
19538
  }
19467
19539
  if (event.data.clipboardVersion !== void 0) {
19468
19540
  clipboard.enable(event.data.clipboardVersion);
19469
- if (event.data.clipboardVersion === 1) {
19541
+ editHost = event.data.clipboardVersion === 1;
19542
+ if (editHost) {
19470
19543
  window.parent.postMessage({ type: "workflow-edit", version: 1 }, "*");
19471
19544
  }
19472
19545
  }
19473
19546
  if (event.data.resourceVersion === 1) {
19474
19547
  resourceHost = true;
19475
19548
  }
19549
+ if (event.data.nativePasteVersion !== void 0) {
19550
+ nativePasteHost = event.data.nativePasteVersion === 1;
19551
+ }
19476
19552
  if (event.data.resourceError) {
19477
19553
  emit(event.data.resourceError);
19478
19554
  }
19479
- if (["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
19555
+ if ((event.data.restoreFocus === true || event.data.clipboardData && document.activeElement === document.body) && ["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
19556
+ const context = contextInput ?? lastInput;
19557
+ contextInput = void 0;
19558
+ if (context) {
19559
+ const input = context.element;
19560
+ if (!input.isConnected || context.selection && input.value !== context.selection.value) {
19561
+ return;
19562
+ }
19563
+ input.focus({ preventScroll: true });
19564
+ if (context.selection) {
19565
+ input.setSelectionRange(context.selection.start, context.selection.end, context.selection.direction);
19566
+ }
19567
+ }
19568
+ }
19569
+ if (event.data.editCommand === "paste" && event.data.clipboardData) {
19570
+ pasteHostClipboard(event.data.clipboardData);
19571
+ } else if (["paste", "copy", "cut", "selectAll", "undo", "redo"].includes(event.data.editCommand)) {
19480
19572
  document.execCommand(event.data.editCommand);
19481
19573
  }
19482
19574
  clipboard.receive(event.data.clipboard);
@@ -21483,6 +21575,7 @@ ${JSON.stringify(output2.details, null, 2)}` : "");
21483
21575
  body = document.createElement("div");
21484
21576
  title = document.createElement("h2");
21485
21577
  usageOpen = false;
21578
+ usageRequestId;
21486
21579
  refresh;
21487
21580
  constructor() {
21488
21581
  this.dialog.className = "conversation-dialog";
@@ -21509,9 +21602,15 @@ ${JSON.stringify(output2.details, null, 2)}` : "");
21509
21602
  close() {
21510
21603
  this.dialog.close();
21511
21604
  this.usageOpen = false;
21605
+ this.usageRequestId = void 0;
21512
21606
  this.refresh?.remove();
21513
21607
  this.refresh = void 0;
21514
21608
  }
21609
+ closeUsage() {
21610
+ if (this.usageOpen) {
21611
+ this.close();
21612
+ }
21613
+ }
21515
21614
  show(title) {
21516
21615
  this.close();
21517
21616
  this.title.textContent = title;
@@ -21618,10 +21717,11 @@ ${JSON.stringify(output2.details, null, 2)}` : "");
21618
21717
  if (this.refresh) {
21619
21718
  this.refresh.disabled = true;
21620
21719
  }
21621
- load();
21720
+ this.usageRequestId = crypto.randomUUID();
21721
+ load(this.usageRequestId);
21622
21722
  }
21623
- usageResult(data, error) {
21624
- if (!this.usageOpen) {
21723
+ usageResult(requestId2, data, error) {
21724
+ if (!this.usageOpen || requestId2 !== this.usageRequestId) {
21625
21725
  return;
21626
21726
  }
21627
21727
  this.body.replaceChildren();
@@ -22127,7 +22227,9 @@ ${JSON.stringify(output2.details, null, 2)}` : "");
22127
22227
  element("entrypoints").hidden = !!run;
22128
22228
  element("run-detail").hidden = !run;
22129
22229
  if (!run) {
22130
- fields.close();
22230
+ if (renderedRun) {
22231
+ fields.close();
22232
+ }
22131
22233
  renderedRun = "";
22132
22234
  controls();
22133
22235
  return;
@@ -22200,6 +22302,9 @@ ${JSON.stringify(output2.details, null, 2)}` : "");
22200
22302
  const authChanged = revision !== next.authenticationRevision;
22201
22303
  revision = next.authenticationRevision;
22202
22304
  state = next;
22305
+ if (authChanged) {
22306
+ dialogs.closeUsage();
22307
+ }
22203
22308
  if (!draftsLoaded) {
22204
22309
  for (const key of Object.keys(drafts)) {
22205
22310
  delete drafts[key];
@@ -22293,7 +22398,7 @@ ${JSON.stringify(output2.details, null, 2)}` : "");
22293
22398
  draft().policies = structuredClone(policies);
22294
22399
  post({ type: "tool-policy", policies });
22295
22400
  });
22296
- element("usage").onclick = () => dialogs.usage(() => post({ type: "usage" }));
22401
+ element("usage").onclick = () => dialogs.usage((requestId2) => post({ type: "usage", requestId: requestId2 }));
22297
22402
  element("project-info").onclick = () => {
22298
22403
  if (state) {
22299
22404
  fields.close();
@@ -22311,6 +22416,9 @@ ${JSON.stringify(output2.details, null, 2)}` : "");
22311
22416
  if (restored) {
22312
22417
  resolve();
22313
22418
  }
22419
+ if (!connected) {
22420
+ dialogs.closeUsage();
22421
+ }
22314
22422
  } else if (message?.type === "params" && message.requestId === requestId && message.entrypointId === entrypointId) {
22315
22423
  resolving = false;
22316
22424
  if (message.error) {
@@ -22335,8 +22443,12 @@ ${JSON.stringify(output2.details, null, 2)}` : "");
22335
22443
  }
22336
22444
  }
22337
22445
  } else if (message?.type === "usage") {
22338
- dialogs.usageResult(message.usage);
22446
+ dialogs.usageResult(message.requestId, message.usage);
22339
22447
  } else if (message?.type === "error") {
22448
+ if (message.requestType === "usage") {
22449
+ dialogs.usageResult(message.requestId, void 0, message.message);
22450
+ return;
22451
+ }
22340
22452
  submitting = false;
22341
22453
  resolving = false;
22342
22454
  controls();
@@ -22347,9 +22459,6 @@ ${JSON.stringify(output2.details, null, 2)}` : "");
22347
22459
  if (message.requestType === "workflow-resume") {
22348
22460
  prompt?.setBusy(false, message.message);
22349
22461
  }
22350
- if (message.requestType === "usage") {
22351
- dialogs.usageResult(void 0, message.message);
22352
- }
22353
22462
  }
22354
22463
  });
22355
22464
  host.postMessage({ type: "ready" });
@@ -65,6 +65,7 @@ var messages_zh_cn_default = {
65
65
  "{1} in {0}": "{0} \u4E2D {1}",
66
66
  "Account balance ${0}": "\u8D26\u6237\u4F59\u989D ${0}",
67
67
  "Account balance": "\u8D26\u6237\u4F59\u989D",
68
+ "Account changed. Refresh usage.": "\u8D26\u53F7\u5DF2\u5207\u6362\uFF0C\u8BF7\u91CD\u65B0\u83B7\u53D6\u7528\u91CF\u3002",
68
69
  "AI usage": "AI \u7528\u91CF",
69
70
  All: "\u5168\u90E8",
70
71
  "Basic information": "\u57FA\u672C\u4FE1\u606F",
@@ -3589,12 +3590,16 @@ ${token}`;
3589
3590
  if (!connection) {
3590
3591
  throw new Error("Workflow Server login is not configured.");
3591
3592
  }
3593
+ const revision = authRevision;
3592
3594
  const response = await fetch(`${connection.serverUrl}/api/auth/sub2api/catalog`, { headers: { Authorization: `Bearer ${connection.accessToken}` }, signal: AbortSignal.timeout(15e3), redirect: "error" });
3593
3595
  const result = await response.json();
3596
+ if (revision !== authRevision) {
3597
+ throw new Error(t("Account changed. Refresh usage."));
3598
+ }
3594
3599
  if (!response.ok || result.errCode !== 0) {
3595
3600
  throw new Error(result.errMessage || "Cannot load usage.");
3596
3601
  }
3597
- replies.push({ type: "usage", sessionId: current?.id, usage: result.data });
3602
+ replies.push({ type: "usage", requestId: message.requestId, sessionId: current?.id, usage: result.data });
3598
3603
  break;
3599
3604
  }
3600
3605
  case "login": {
@@ -3748,7 +3753,7 @@ ${token}`;
3748
3753
  const operation = () => handleMessage(message).then((value2) => {
3749
3754
  messages = value2;
3750
3755
  });
3751
- const concurrent = ["resolve", "ready", "resource", "resource-data", "resource-refresh", "resource-select", "resource-bridge", "kanban-bridge", "kanban-method-state", "kanban-method-reply", "kanban-methods"].includes(message.type);
3756
+ const concurrent = ["resolve", "ready", "usage", "resource", "resource-data", "resource-refresh", "resource-select", "resource-bridge", "kanban-bridge", "kanban-method-state", "kanban-method-reply", "kanban-methods"].includes(message.type);
3752
3757
  const task = concurrent ? operation() : mutations.catch(() => void 0).then(operation);
3753
3758
  if (!concurrent) {
3754
3759
  mutations = task;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workflow-code/cli",
3
- "version": "0.2.4-20261013005.codex-studio-integration",
3
+ "version": "0.2.4-20261013007.codex-studio-integration",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "workflow-code": "./dist/index.js"