openwork-server 0.18.50 → 0.18.56

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.
Files changed (92) hide show
  1. package/README.md +1 -1
  2. package/bin/openwork-server.mjs +28 -22
  3. package/bin/platform.mjs +28 -0
  4. package/dist/opencode-plugin-deps-1.18.30.tgz +0 -0
  5. package/dist/opencode-plugins/openwork-context-v2.js +84 -0
  6. package/dist/opencode-plugins/openwork-extensions-preview.js +589 -268
  7. package/dist/opencode-plugins/openwork-gateway-quota-v2.js +12 -1
  8. package/dist/opencode-plugins/openwork-gateway-quota.js +12 -1
  9. package/dist/opencode-plugins/openwork-mcp-results-v2.js +154 -0
  10. package/dist/opencode-plugins/openwork-office-attachments.js +135 -130
  11. package/dist/opencode-plugins/openwork-provider-adapters.js +2 -2
  12. package/dist/opencode-plugins/openwork-provider-filters-v2.js +69 -0
  13. package/dist/opencode-plugins/openwork-read-transport.js +2 -0
  14. package/dist/opencode-plugins/openwork-spreadsheets.js +136 -2
  15. package/dist/openwork-server.mjs +114735 -0
  16. package/dist/pdfium.wasm +0 -0
  17. package/package.json +7 -1
  18. package/web/assets/{abnfDiagram-VCTEODGH-BgnyE_Jl.js → abnfDiagram-VCTEODGH-Dr1YMfll.js} +1 -1
  19. package/web/assets/{app-CyCqD289.js → app-D9Nvta88.js} +474 -424
  20. package/web/assets/{arc-jSgX49-e.js → arc-7SoIBvT7.js} +1 -1
  21. package/web/assets/{architectureDiagram-5GKGNRK7-DD_aGn4v.js → architectureDiagram-5GKGNRK7-BZwevfH9.js} +1 -1
  22. package/web/assets/{artifact-code-view-DFIq0k-c.js → artifact-code-view-WLwX_I1h.js} +1 -1
  23. package/web/assets/{artifact-spreadsheet-editor-DFVCYrL7.js → artifact-spreadsheet-editor-BvEnxKsm.js} +1 -1
  24. package/web/assets/{artifact-text-editor-DBngc6bx.js → artifact-text-editor-BHyVrNyR.js} +1 -1
  25. package/web/assets/{blockDiagram-OSKFZWR5-CBcZLjLp.js → blockDiagram-OSKFZWR5-Cvqr9DPi.js} +1 -1
  26. package/web/assets/{c4Diagram-7LVT6UL2-DMrhFCLj.js → c4Diagram-7LVT6UL2-CWTWC9C1.js} +1 -1
  27. package/web/assets/channel-BkgEJbR-.js +1 -0
  28. package/web/assets/{chunk-2Q5K7J3B-Ce1X-FJQ.js → chunk-2Q5K7J3B-DpJkzZ5x.js} +1 -1
  29. package/web/assets/{chunk-5VM5RSS4-BS48ZtVI.js → chunk-5VM5RSS4-BtTBnr9m.js} +1 -1
  30. package/web/assets/{chunk-F27PBJKO-COdFZJ-M.js → chunk-F27PBJKO-BbAvFJAg.js} +1 -1
  31. package/web/assets/{chunk-HLEWEB6X-Cdw4ABX3.js → chunk-HLEWEB6X-DX5mKBrj.js} +1 -1
  32. package/web/assets/{chunk-JWPE2WC7-FVVDYZmE.js → chunk-JWPE2WC7-CugB1e5O.js} +1 -1
  33. package/web/assets/{chunk-POPQ4Y6H-C7acdUF3.js → chunk-POPQ4Y6H-BQ-bWmmo.js} +1 -1
  34. package/web/assets/{chunk-SVP7TREG-BUun0UWD.js → chunk-SVP7TREG-szCI_Kz9.js} +1 -1
  35. package/web/assets/{chunk-XXDRQBXY-DLgpJmat.js → chunk-XXDRQBXY-C5UTO899.js} +1 -1
  36. package/web/assets/{chunk-ZLD2IHE6-BdMQ5Cr0.js → chunk-ZLD2IHE6-D5v_jiDg.js} +1 -1
  37. package/web/assets/classDiagram-CYGNFDIV-BHINh3-f.js +1 -0
  38. package/web/assets/classDiagram-v2-TLXNO2FR-BHINh3-f.js +1 -0
  39. package/web/assets/{cose-bilkent-JH36ORCC-CqWy3Swy.js → cose-bilkent-JH36ORCC-BhG_zAfo.js} +1 -1
  40. package/web/assets/{cynefin-OW5HDTMX-DslesE5Y.js → cynefin-OW5HDTMX-DSTjm6jO.js} +1 -1
  41. package/web/assets/{cynefinDiagram-5FMLGOSQ-B54uZJn_.js → cynefinDiagram-5FMLGOSQ-Dqkgb6tF.js} +1 -1
  42. package/web/assets/{dagre-OS7QT2EB-Bkahh4gZ.js → dagre-OS7QT2EB-BZMseQyA.js} +1 -1
  43. package/web/assets/{diagram-S7CK7UJ4-CXQl7SfF.js → diagram-S7CK7UJ4-Cs2hsmEJ.js} +1 -1
  44. package/web/assets/{diagram-UQ7AKVKN-BA0V8tjK.js → diagram-UQ7AKVKN-CDnRP_yz.js} +1 -1
  45. package/web/assets/{diagram-VSXAHHWV-DlcR8qeO.js → diagram-VSXAHHWV-DxKXQXAC.js} +1 -1
  46. package/web/assets/{diagram-VX7I27RA-ewm16zDI.js → diagram-VX7I27RA-BJKoseDf.js} +1 -1
  47. package/web/assets/{diagram-Z3DM3KII-Bc2lRc88.js → diagram-Z3DM3KII-DDcMvRxo.js} +1 -1
  48. package/web/assets/{ebnfDiagram-PWID7BFC-JwCaf6cT.js → ebnfDiagram-PWID7BFC-C2uUm-CC.js} +1 -1
  49. package/web/assets/{erDiagram-2YWLMYGG-DOqO-9Yf.js → erDiagram-2YWLMYGG-B0Mdv5WO.js} +1 -1
  50. package/web/assets/{flowDiagram-T62WH6J4-CCZxvIjW.js → flowDiagram-T62WH6J4-CUnt9AMo.js} +1 -1
  51. package/web/assets/{ganttDiagram-EL5Y4UJY-BczG7RIu.js → ganttDiagram-EL5Y4UJY-CENsUToC.js} +1 -1
  52. package/web/assets/{gitGraphDiagram-WWUBYQGX-GOecDN3g.js → gitGraphDiagram-WWUBYQGX-CrbKh94B.js} +1 -1
  53. package/web/assets/index-CyyMNIC_.css +1 -0
  54. package/web/assets/{infoDiagram-FKFFQAWI-BbgIVsQp.js → infoDiagram-FKFFQAWI-B-U-x_qU.js} +1 -1
  55. package/web/assets/{ishikawaDiagram-5VMMS53U-xutQo5Ip.js → ishikawaDiagram-5VMMS53U-jNVSJSu1.js} +1 -1
  56. package/web/assets/{journeyDiagram-EYS64GPL-BIbzPGaa.js → journeyDiagram-EYS64GPL-De3j0gPh.js} +1 -1
  57. package/web/assets/{kanban-definition-UXKFOSKX-BCTiRzck.js → kanban-definition-UXKFOSKX-Bbc8wjhq.js} +1 -1
  58. package/web/assets/{layout-Wpfi54TB.js → layout-BIjP2nup.js} +1 -1
  59. package/web/assets/{linear-DLJHPikh.js → linear-lvQZOiHM.js} +1 -1
  60. package/web/assets/{mermaid.core-CDRJkis7.js → mermaid.core-LJPf4T7o.js} +5 -5
  61. package/web/assets/{mindmap-definition-THT77NOG-DtphSFs_.js → mindmap-definition-THT77NOG-DiboHsg8.js} +1 -1
  62. package/web/assets/{overlay-zA9qjYXH.js → overlay-DA5SOee-.js} +1 -1
  63. package/web/assets/{pegDiagram-XKGWAZYB-CzbjpqK7.js → pegDiagram-XKGWAZYB-DO_edVtr.js} +1 -1
  64. package/web/assets/{pieDiagram-E7YTZNPT-tjxtWWT7.js → pieDiagram-E7YTZNPT-bPvBuBuG.js} +1 -1
  65. package/web/assets/{quadrantDiagram-AXDQQJYC-CFC1qey-.js → quadrantDiagram-AXDQQJYC-BGyrQhlH.js} +1 -1
  66. package/web/assets/{railroadDiagram-O6MQD6OU-73_BXhNP.js → railroadDiagram-O6MQD6OU-XhPIuoOE.js} +1 -1
  67. package/web/assets/{requirementDiagram-IS5BZ75X-B8i4BL2A.js → requirementDiagram-IS5BZ75X-atdASt4G.js} +1 -1
  68. package/web/assets/{sankeyDiagram-P5KCCOFB-Dll4Naj0.js → sankeyDiagram-P5KCCOFB-BV9prEKy.js} +1 -1
  69. package/web/assets/{sequenceDiagram-WJ2MYXX4-B8Rvjhb5.js → sequenceDiagram-WJ2MYXX4-Csfm-fZ-.js} +1 -1
  70. package/web/assets/{sizeCapture-INFHLROL-h8YDF-c3.js → sizeCapture-INFHLROL-CLmH-AjF.js} +1 -1
  71. package/web/assets/{stateDiagram-XQSTLZYL-COorU6Ga.js → stateDiagram-XQSTLZYL-yiSt2fJK.js} +1 -1
  72. package/web/assets/stateDiagram-v2-IH3M54BS-BEhxOujx.js +1 -0
  73. package/web/assets/{swimlanes-V6O3JKXN-CAghInFw.js → swimlanes-V6O3JKXN-BpXNggx9.js} +1 -1
  74. package/web/assets/swimlanesDiagram-JKAHXJPX-DWqwFv9F.js +8 -0
  75. package/web/assets/{timeline-definition-24CTP7MA-Dum2N-ex.js → timeline-definition-24CTP7MA-C8X71OnL.js} +1 -1
  76. package/web/assets/{vennDiagram-4TSXK5OY-D-JeJumX.js → vennDiagram-4TSXK5OY-BZo-99ra.js} +1 -1
  77. package/web/assets/{wardleyDiagram-VM6X3IG4-d99FKQIG.js → wardleyDiagram-VM6X3IG4-BHwH6ZLg.js} +1 -1
  78. package/web/assets/{workspace-file-tree-CAuhntUr.js → workspace-file-tree-C8iSfvPt.js} +3 -3
  79. package/web/assets/{xychartDiagram-S5SC5T6Z-DdmevfkD.js → xychartDiagram-S5SC5T6Z-BieEi319.js} +1 -1
  80. package/web/ext-github.svg +1 -0
  81. package/web/ext-hubspot.svg +1 -0
  82. package/web/ext-slack.svg +1 -0
  83. package/web/index.html +4 -3
  84. package/web/overlay.html +3 -3
  85. package/dist/bin/openwork-server +0 -4
  86. package/web/assets/channel-BE8JEd1U.js +0 -1
  87. package/web/assets/classDiagram-CYGNFDIV-Cy8V0GW-.js +0 -1
  88. package/web/assets/classDiagram-v2-TLXNO2FR-Cy8V0GW-.js +0 -1
  89. package/web/assets/index-BZgplq0g.css +0 -1
  90. package/web/assets/stateDiagram-v2-IH3M54BS-BAu05WuT.js +0 -1
  91. package/web/assets/swimlanesDiagram-JKAHXJPX-CpJNl3pn.js +0 -8
  92. /package/web/assets/{index-_gYIQM_z.js → index-D6FUvVB1.js} +0 -0
@@ -13608,6 +13608,12 @@ var gatewayUsagePolicyWriteSchema = exports_external.object({
13608
13608
  }).strict()).min(1).max(3).refine((limits) => new Set(limits.map((limit) => limit.timeframe)).size === limits.length, "Timeframes must be unique.")
13609
13609
  }).strict();
13610
13610
  var gatewayUsageProvenanceSchema = exports_external.discriminatedUnion("kind", [
13611
+ exports_external.object({
13612
+ kind: exports_external.literal("organization"),
13613
+ assignmentId: exports_external.string(),
13614
+ memberId: exports_external.null(),
13615
+ teamId: exports_external.null()
13616
+ }).strict(),
13611
13617
  exports_external.object({
13612
13618
  kind: exports_external.literal("direct"),
13613
13619
  assignmentId: exports_external.string(),
@@ -13630,7 +13636,12 @@ var gatewayUsageLimitPolicySchema = exports_external.object({
13630
13636
  allowRequestReset: exports_external.boolean(),
13631
13637
  revision: exports_external.number().int(),
13632
13638
  limits: exports_external.array(exports_external.object({ timeframe: gatewayUsageTimeframeSchema, costLimitMicroUsd: moneySchema })),
13633
- assignments: exports_external.array(exports_external.object({ id: exports_external.string(), memberId: exports_external.string().nullable(), teamId: exports_external.string().nullable() })),
13639
+ assignments: exports_external.array(exports_external.object({
13640
+ id: exports_external.string(),
13641
+ memberId: exports_external.string().nullable(),
13642
+ teamId: exports_external.string().nullable(),
13643
+ organization: exports_external.boolean().default(false)
13644
+ })),
13634
13645
  archivedAt: exports_external.iso.datetime().nullable().optional()
13635
13646
  });
13636
13647
  var gatewayUsageStatusSchema = exports_external.object({
@@ -13922,6 +13922,12 @@ var gatewayUsagePolicyWriteSchema = exports_external.object({
13922
13922
  }).strict()).min(1).max(3).refine((limits) => new Set(limits.map((limit) => limit.timeframe)).size === limits.length, "Timeframes must be unique.")
13923
13923
  }).strict();
13924
13924
  var gatewayUsageProvenanceSchema = exports_external.discriminatedUnion("kind", [
13925
+ exports_external.object({
13926
+ kind: exports_external.literal("organization"),
13927
+ assignmentId: exports_external.string(),
13928
+ memberId: exports_external.null(),
13929
+ teamId: exports_external.null()
13930
+ }).strict(),
13925
13931
  exports_external.object({
13926
13932
  kind: exports_external.literal("direct"),
13927
13933
  assignmentId: exports_external.string(),
@@ -13944,7 +13950,12 @@ var gatewayUsageLimitPolicySchema = exports_external.object({
13944
13950
  allowRequestReset: exports_external.boolean(),
13945
13951
  revision: exports_external.number().int(),
13946
13952
  limits: exports_external.array(exports_external.object({ timeframe: gatewayUsageTimeframeSchema, costLimitMicroUsd: moneySchema })),
13947
- assignments: exports_external.array(exports_external.object({ id: exports_external.string(), memberId: exports_external.string().nullable(), teamId: exports_external.string().nullable() })),
13953
+ assignments: exports_external.array(exports_external.object({
13954
+ id: exports_external.string(),
13955
+ memberId: exports_external.string().nullable(),
13956
+ teamId: exports_external.string().nullable(),
13957
+ organization: exports_external.boolean().default(false)
13958
+ })),
13948
13959
  archivedAt: exports_external.iso.datetime().nullable().optional()
13949
13960
  });
13950
13961
  var gatewayUsageStatusSchema = exports_external.object({
@@ -0,0 +1,154 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
12
+ var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
20
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
21
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
+ for (let key of __getOwnPropNames(mod))
23
+ if (!__hasOwnProp.call(to, key))
24
+ __defProp(to, key, {
25
+ get: __accessProp.bind(mod, key),
26
+ enumerable: true
27
+ });
28
+ if (canCache)
29
+ cache.set(mod, to);
30
+ return to;
31
+ };
32
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
33
+ var __returnValue = (v) => v;
34
+ function __exportSetter(name, newValue) {
35
+ this[name] = __returnValue.bind(null, newValue);
36
+ }
37
+ var __export = (target, all) => {
38
+ for (var name in all)
39
+ __defProp(target, name, {
40
+ get: all[name],
41
+ enumerable: true,
42
+ configurable: true,
43
+ set: __exportSetter.bind(all, name)
44
+ });
45
+ };
46
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
47
+
48
+ // src/opencode-plugins/openwork-mcp-results-v2.ts
49
+ var OPENWORK_CLOUD_TOOL = /^(?:openwork|openwork-cloud)_/;
50
+ var MAX_ENTRY_BYTES = 64 * 1024;
51
+ var MAX_ENTRIES = 20;
52
+ var MAX_OPEN_CALLS = 200;
53
+ function isRecord(value) {
54
+ return typeof value === "object" && value !== null && !Array.isArray(value);
55
+ }
56
+ function parseRecord(text) {
57
+ const start = text.indexOf("{");
58
+ const end = text.lastIndexOf("}");
59
+ if (start < 0 || end <= start || end - start > MAX_ENTRY_BYTES)
60
+ return null;
61
+ try {
62
+ const parsed = JSON.parse(text.slice(start, end + 1));
63
+ return isRecord(parsed) ? parsed : null;
64
+ } catch {
65
+ return null;
66
+ }
67
+ }
68
+ function reportsConnection(value) {
69
+ if (!isRecord(value))
70
+ return false;
71
+ if ("connectionStatus" in value || "connectionAction" in value)
72
+ return true;
73
+ if (typeof value.connectionId === "string" && typeof value.state === "string")
74
+ return true;
75
+ return Array.isArray(value.matches) && value.matches.some((match) => isRecord(match) && typeof match.connectionId === "string");
76
+ }
77
+ function errorText(error) {
78
+ if (error instanceof Error)
79
+ return error.message;
80
+ if (isRecord(error) && typeof error.message === "string")
81
+ return error.message;
82
+ return String(error);
83
+ }
84
+ function jsonCopy(value) {
85
+ try {
86
+ return value === undefined ? {} : JSON.parse(JSON.stringify(value));
87
+ } catch {
88
+ return {};
89
+ }
90
+ }
91
+ function normalizedTool(tool) {
92
+ return tool.replace(/^(openwork(?:-cloud)?)\./, "$1_");
93
+ }
94
+ function preservedEntry(rawEvent) {
95
+ const event = { ...rawEvent, tool: normalizedTool(rawEvent.tool) };
96
+ if (!OPENWORK_CLOUD_TOOL.test(event.tool))
97
+ return null;
98
+ const appBuilder = /_(?:search_capabilities|prepare_app|create_app|update_app)$/.test(event.tool);
99
+ const appLaunch = event.status === "completed" && isRecord(event.result.output) && isRecord(event.result.output.launch);
100
+ const input = jsonCopy(event.input);
101
+ const entry = event.status === "completed" ? appBuilder || appLaunch || reportsConnection(event.result.output) ? { tool: event.tool, input, status: "completed", output: jsonCopy(event.result.output) } : null : appBuilder || reportsConnection(parseRecord(errorText(event.error))) ? { tool: event.tool, input, status: "error", error: errorText(event.error) } : null;
102
+ if (!entry)
103
+ return null;
104
+ return new TextEncoder().encode(JSON.stringify(entry)).byteLength <= MAX_ENTRY_BYTES ? entry : null;
105
+ }
106
+ function createMcpResultsCollector() {
107
+ const open = new Map;
108
+ const key = (event) => `${event.messageID}\x00${event.id}`;
109
+ return {
110
+ before(event) {
111
+ if (event.tool !== "execute")
112
+ return;
113
+ if (open.size >= MAX_OPEN_CALLS) {
114
+ const oldest = open.keys().next().value;
115
+ if (oldest !== undefined)
116
+ open.delete(oldest);
117
+ }
118
+ open.set(key(event), []);
119
+ },
120
+ after(event) {
121
+ const list = open.get(key(event));
122
+ if (event.tool === "execute") {
123
+ open.delete(key(event));
124
+ if (event.status === "completed" && list && list.length > 0) {
125
+ event.result.metadata = { ...event.result.metadata ?? {}, openworkMcpResults: list };
126
+ }
127
+ return;
128
+ }
129
+ if (!list || list.length >= MAX_ENTRIES)
130
+ return;
131
+ const entry = preservedEntry(event);
132
+ if (entry)
133
+ list.push(entry);
134
+ }
135
+ };
136
+ }
137
+ var openwork_mcp_results_v2_default = {
138
+ id: "openwork.mcp-results",
139
+ async setup(context) {
140
+ const collector = createMcpResultsCollector();
141
+ const before = await context.tool.hook("execute.before", (event) => collector.before(event));
142
+ const after = await context.tool.hook("execute.after", (event) => collector.after(event));
143
+ return async () => {
144
+ await before.dispose();
145
+ await after.dispose();
146
+ };
147
+ }
148
+ };
149
+ export {
150
+ reportsConnection,
151
+ preservedEntry,
152
+ openwork_mcp_results_v2_default as default,
153
+ createMcpResultsCollector
154
+ };
@@ -2492,6 +2492,140 @@ async function writeXlsxWorkbook(input) {
2492
2492
  sheets: sheets.map((sheet, index) => ({ name: sheet.name, rows: worksheets[index].rows, columns: worksheets[index].columns }))
2493
2493
  };
2494
2494
  }
2495
+ // ../../packages/workbook/src/office-text.ts
2496
+ var DOCX_MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
2497
+ var PPTX_MIME = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
2498
+ var XLSX_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
2499
+ var MAX_OFFICE_TEXT_CHARS = 24000;
2500
+ var GENERIC_MIME = "application/octet-stream";
2501
+ var MAX_XLSX_PREVIEW_CELLS = 1200;
2502
+ var MAX_XLSX_PREVIEW_ROWS_PER_SHEET = 25;
2503
+ var MAX_XLSX_PREVIEW_COLUMNS = 16;
2504
+ var MAX_XLSX_PREVIEW_CELL_CHARS = 60;
2505
+ function extensionOf(filename) {
2506
+ const name = (filename.split(/[\\/]/).pop() ?? "").toLowerCase();
2507
+ const dot = name.lastIndexOf(".");
2508
+ return dot > 0 ? name.slice(dot + 1) : "";
2509
+ }
2510
+ function officeKindFromMimeOrFilename(mime, filename) {
2511
+ if (mime === DOCX_MIME)
2512
+ return "docx";
2513
+ if (mime === PPTX_MIME)
2514
+ return "pptx";
2515
+ if (mime === XLSX_MIME)
2516
+ return "xlsx";
2517
+ if (mime !== "" && mime !== GENERIC_MIME)
2518
+ return null;
2519
+ const extension = extensionOf(filename);
2520
+ if (extension === "docx")
2521
+ return "docx";
2522
+ if (extension === "pptx")
2523
+ return "pptx";
2524
+ if (extension === "xlsx")
2525
+ return "xlsx";
2526
+ return null;
2527
+ }
2528
+ function relevantXmlEntry(kind, name) {
2529
+ if (!name.endsWith(".xml"))
2530
+ return false;
2531
+ if (kind === "docx") {
2532
+ return name === "word/document.xml" || /^word\/header\d+\.xml$/.test(name) || /^word\/footer\d+\.xml$/.test(name) || name === "word/footnotes.xml" || name === "word/endnotes.xml" || name === "word/comments.xml";
2533
+ }
2534
+ return /^ppt\/slides\/slide\d+\.xml$/.test(name) || /^ppt\/notesSlides\/notesSlide\d+\.xml$/.test(name);
2535
+ }
2536
+ function compareEntryName(left, right) {
2537
+ return left.name.localeCompare(right.name, undefined, { numeric: true, sensitivity: "base" });
2538
+ }
2539
+ function quoted(value) {
2540
+ const encoded = JSON.stringify(value.length > 500 ? `${value.slice(0, 500)}…` : value);
2541
+ return typeof encoded === "string" ? encoded : '""';
2542
+ }
2543
+ function sheetSummaryLine(sheet, total) {
2544
+ const facts = [
2545
+ sheet.dimension ? `dimension ${sheet.dimension}` : "",
2546
+ sheet.cells.length ? `${sheet.cells.length} cells in rows ${sheet.firstRow}-${sheet.lastRow}, columns ${columnLetters(sheet.firstColumn)}-${columnLetters(sheet.lastColumn)}` : "no cell values",
2547
+ sheet.formulaCount ? `${sheet.formulaCount} formula${sheet.formulaCount === 1 ? "" : "s"}` : "",
2548
+ sheet.mergedRanges.length ? `merged ${sheet.mergedRanges.slice(0, 8).join(", ")}${sheet.mergedRanges.length > 8 ? ", …" : ""}` : "",
2549
+ sheet.info.hidden ? "hidden" : ""
2550
+ ].filter(Boolean);
2551
+ return `sheet ${quoted(sheet.info.name)} (${sheet.info.position} of ${total}): ${facts.join("; ")}`;
2552
+ }
2553
+ async function extractXlsxText(bytes, options) {
2554
+ const tool = options.spreadsheetReadTool;
2555
+ const workbook = await openXlsxWorkbook(bytes);
2556
+ const total = workbook.sheets.length;
2557
+ const lines = [
2558
+ "xlsx_workbook:",
2559
+ ` sheet_count: ${total}`,
2560
+ ` sheet_names: ${workbook.sheets.map((sheet) => quoted(sheet.name)).join(", ")}`,
2561
+ ` shared_string_count: ${workbook.sharedStringCount}`,
2562
+ ` style_count: ${workbook.styleCount}`,
2563
+ ...workbook.date1904 ? [" date_system: 1904"] : [],
2564
+ ...workbook.omittedSheets ? [` omitted_sheets: ${workbook.omittedSheets} beyond the first ${total} are not shown`] : []
2565
+ ];
2566
+ let remainingCells = MAX_XLSX_PREVIEW_CELLS;
2567
+ for (const info of workbook.sheets) {
2568
+ let sheet;
2569
+ try {
2570
+ sheet = await workbook.readSheet(info);
2571
+ } catch (cause) {
2572
+ lines.push(`sheet ${quoted(info.name)} (${info.position} of ${total}): error: ${cause instanceof Error ? cause.message : String(cause)}`);
2573
+ continue;
2574
+ }
2575
+ lines.push(sheetSummaryLine(sheet, total));
2576
+ if (sheet.cells.length === 0)
2577
+ continue;
2578
+ if (remainingCells <= 0) {
2579
+ lines.push(tool ? ` preview omitted: cell budget used by earlier sheets; read it with ${tool}.` : " preview omitted: cell budget used by earlier sheets.");
2580
+ continue;
2581
+ }
2582
+ const maxRows = Math.max(1, Math.min(MAX_XLSX_PREVIEW_ROWS_PER_SHEET, Math.floor(remainingCells / Math.min(MAX_XLSX_PREVIEW_COLUMNS, Math.max(1, sheet.lastColumn - sheet.firstColumn + 1)))));
2583
+ const table = renderSheetTable(sheet, { maxRows, maxColumns: MAX_XLSX_PREVIEW_COLUMNS, maxCellChars: MAX_XLSX_PREVIEW_CELL_CHARS });
2584
+ remainingCells -= table.renderedRows * table.columns.length;
2585
+ lines.push(table.text);
2586
+ if (table.truncatedColumns > 0)
2587
+ lines.push(` more_columns: ${table.truncatedColumns} not shown`);
2588
+ if (table.nextStartRow !== null) {
2589
+ lines.push(tool ? ` more_rows: continue with ${tool}(sheet: ${quoted(sheet.info.name)}, startRow: ${table.nextStartRow})` : ` more_rows: rows from ${table.nextStartRow} are not shown`);
2590
+ }
2591
+ if (sheet.omittedCells > 0)
2592
+ lines.push(` omitted_cells: ${sheet.omittedCells}`);
2593
+ const formulas = formulaSummary(sheet, 12);
2594
+ if (formulas.length)
2595
+ lines.push(` formulas: ${formulas.join("; ")}${sheet.formulaCount > formulas.length ? `; … ${sheet.formulaCount - formulas.length} more` : ""}`);
2596
+ const formats = numberFormatSummary(sheet);
2597
+ if (formats.length)
2598
+ lines.push(` number_formats: ${formats.join("; ")}`);
2599
+ }
2600
+ return lines.join(`
2601
+ `).slice(0, MAX_OFFICE_TEXT_CHARS);
2602
+ }
2603
+ async function extractOfficeText(kind, bytes, options = {}) {
2604
+ if (kind === "xlsx")
2605
+ return await extractXlsxText(bytes, options);
2606
+ const entries = listZipEntries(bytes).filter((entry) => relevantXmlEntry(kind, entry.name)).sort(compareEntryName);
2607
+ if (entries.length === 0)
2608
+ throw new Error("No supported Office XML text entries were found.");
2609
+ const pieces = [];
2610
+ let remaining = MAX_OFFICE_TEXT_CHARS;
2611
+ for (const entry of entries) {
2612
+ if (remaining <= 0)
2613
+ break;
2614
+ const text = xmlText(utf8Text(await readZipEntryData(bytes, entry)));
2615
+ if (!text)
2616
+ continue;
2617
+ const chunk = text.slice(0, remaining);
2618
+ pieces.push(`[${entry.name}]
2619
+ ${chunk}`);
2620
+ remaining -= chunk.length;
2621
+ }
2622
+ const combined = pieces.join(`
2623
+
2624
+ `).slice(0, MAX_OFFICE_TEXT_CHARS);
2625
+ if (!combined)
2626
+ throw new Error("Office XML text entries contained no extractable text.");
2627
+ return combined;
2628
+ }
2495
2629
  // src/opencode-plugins/workspace-file-identity.ts
2496
2630
  import { constants } from "node:fs";
2497
2631
  import { lstat, open, realpath, rm } from "node:fs/promises";
@@ -2604,15 +2738,6 @@ async function openWorkspaceFileForWriting(realRoot, path, expected, label) {
2604
2738
  }
2605
2739
 
2606
2740
  // src/opencode-plugins/openwork-office-attachments.ts
2607
- var DOCX_MIME = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
2608
- var PPTX_MIME = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
2609
- var XLSX_MIME = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
2610
- var GENERIC_MIME = "application/octet-stream";
2611
- var MAX_EXTRACTED_TEXT_CHARS = 24000;
2612
- var MAX_XLSX_PREVIEW_CELLS = 1200;
2613
- var MAX_XLSX_PREVIEW_ROWS_PER_SHEET = 25;
2614
- var MAX_XLSX_PREVIEW_COLUMNS = 16;
2615
- var MAX_XLSX_PREVIEW_CELL_CHARS = 60;
2616
2741
  var MATERIALIZED_DIR = join(".opencode", "openwork", "inbox", "chat-attachments");
2617
2742
  function isRecord(value) {
2618
2743
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -2643,27 +2768,6 @@ function extensionFromFilename(filename) {
2643
2768
  const dot = name.lastIndexOf(".");
2644
2769
  return dot > 0 ? name.slice(dot + 1) : "";
2645
2770
  }
2646
- function isGenericMime(mime) {
2647
- return mime === "" || mime === GENERIC_MIME;
2648
- }
2649
- function officeKindFromMimeOrFilename(mime, filename) {
2650
- if (mime === DOCX_MIME)
2651
- return "docx";
2652
- if (mime === PPTX_MIME)
2653
- return "pptx";
2654
- if (mime === XLSX_MIME)
2655
- return "xlsx";
2656
- if (!isGenericMime(mime))
2657
- return null;
2658
- const extension = extensionFromFilename(filename);
2659
- if (extension === "docx")
2660
- return "docx";
2661
- if (extension === "pptx")
2662
- return "pptx";
2663
- if (extension === "xlsx")
2664
- return "xlsx";
2665
- return null;
2666
- }
2667
2771
  function canonicalMime(kind) {
2668
2772
  if (kind === "docx")
2669
2773
  return DOCX_MIME;
@@ -2839,105 +2943,6 @@ async function materializeAttachment(root, filename, kind, bytes) {
2839
2943
  }
2840
2944
  throw new Error("A different Office attachment already exists at the materialized path.");
2841
2945
  }
2842
- function relevantXmlEntry(kind, name) {
2843
- if (!name.endsWith(".xml"))
2844
- return false;
2845
- if (kind === "docx") {
2846
- return name === "word/document.xml" || /^word\/header\d+\.xml$/.test(name) || /^word\/footer\d+\.xml$/.test(name) || name === "word/footnotes.xml" || name === "word/endnotes.xml" || name === "word/comments.xml";
2847
- }
2848
- return /^ppt\/slides\/slide\d+\.xml$/.test(name) || /^ppt\/notesSlides\/notesSlide\d+\.xml$/.test(name);
2849
- }
2850
- function compareEntryName(left, right) {
2851
- return left.name.localeCompare(right.name, undefined, { numeric: true, sensitivity: "base" });
2852
- }
2853
- function quoted(value) {
2854
- const encoded = JSON.stringify(value.length > 500 ? `${value.slice(0, 500)}…` : value);
2855
- return typeof encoded === "string" ? encoded : '""';
2856
- }
2857
- function sheetSummaryLine(sheet, total) {
2858
- const facts = [
2859
- sheet.dimension ? `dimension ${sheet.dimension}` : "",
2860
- sheet.cells.length ? `${sheet.cells.length} cells in rows ${sheet.firstRow}-${sheet.lastRow}, columns ${columnLetters(sheet.firstColumn)}-${columnLetters(sheet.lastColumn)}` : "no cell values",
2861
- sheet.formulaCount ? `${sheet.formulaCount} formula${sheet.formulaCount === 1 ? "" : "s"}` : "",
2862
- sheet.mergedRanges.length ? `merged ${sheet.mergedRanges.slice(0, 8).join(", ")}${sheet.mergedRanges.length > 8 ? ", …" : ""}` : "",
2863
- sheet.info.hidden ? "hidden" : ""
2864
- ].filter(Boolean);
2865
- return `sheet ${quoted(sheet.info.name)} (${sheet.info.position} of ${total}): ${facts.join("; ")}`;
2866
- }
2867
- async function extractXlsxText(bytes) {
2868
- const workbook = await openXlsxWorkbook(bytes);
2869
- const total = workbook.sheets.length;
2870
- const lines = [
2871
- "xlsx_workbook:",
2872
- ` sheet_count: ${total}`,
2873
- ` sheet_names: ${workbook.sheets.map((sheet) => quoted(sheet.name)).join(", ")}`,
2874
- ` shared_string_count: ${workbook.sharedStringCount}`,
2875
- ` style_count: ${workbook.styleCount}`,
2876
- ...workbook.date1904 ? [" date_system: 1904"] : [],
2877
- ...workbook.omittedSheets ? [` omitted_sheets: ${workbook.omittedSheets} beyond the first ${total} are not shown`] : []
2878
- ];
2879
- let remainingCells = MAX_XLSX_PREVIEW_CELLS;
2880
- for (const info of workbook.sheets) {
2881
- let sheet;
2882
- try {
2883
- sheet = await workbook.readSheet(info);
2884
- } catch (cause) {
2885
- lines.push(`sheet ${quoted(info.name)} (${info.position} of ${total}): error: ${cause instanceof Error ? cause.message : String(cause)}`);
2886
- continue;
2887
- }
2888
- lines.push(sheetSummaryLine(sheet, total));
2889
- if (sheet.cells.length === 0)
2890
- continue;
2891
- if (remainingCells <= 0) {
2892
- lines.push(" preview omitted: cell budget used by earlier sheets; read it with spreadsheet_read.");
2893
- continue;
2894
- }
2895
- const maxRows = Math.max(1, Math.min(MAX_XLSX_PREVIEW_ROWS_PER_SHEET, Math.floor(remainingCells / Math.min(MAX_XLSX_PREVIEW_COLUMNS, Math.max(1, sheet.lastColumn - sheet.firstColumn + 1)))));
2896
- const table = renderSheetTable(sheet, { maxRows, maxColumns: MAX_XLSX_PREVIEW_COLUMNS, maxCellChars: MAX_XLSX_PREVIEW_CELL_CHARS });
2897
- remainingCells -= table.renderedRows * table.columns.length;
2898
- lines.push(table.text);
2899
- if (table.truncatedColumns > 0)
2900
- lines.push(` more_columns: ${table.truncatedColumns} not shown`);
2901
- if (table.nextStartRow !== null)
2902
- lines.push(` more_rows: continue with spreadsheet_read(sheet: ${quoted(sheet.info.name)}, startRow: ${table.nextStartRow})`);
2903
- if (sheet.omittedCells > 0)
2904
- lines.push(` omitted_cells: ${sheet.omittedCells}`);
2905
- const formulas = formulaSummary(sheet, 12);
2906
- if (formulas.length)
2907
- lines.push(` formulas: ${formulas.join("; ")}${sheet.formulaCount > formulas.length ? `; … ${sheet.formulaCount - formulas.length} more` : ""}`);
2908
- const formats = numberFormatSummary(sheet);
2909
- if (formats.length)
2910
- lines.push(` number_formats: ${formats.join("; ")}`);
2911
- }
2912
- return lines.join(`
2913
- `).slice(0, MAX_EXTRACTED_TEXT_CHARS);
2914
- }
2915
- async function extractOfficeText(kind, bytes) {
2916
- if (kind === "xlsx")
2917
- return await extractXlsxText(bytes);
2918
- const entries = listZipEntries(bytes).filter((entry) => relevantXmlEntry(kind, entry.name)).sort(compareEntryName);
2919
- if (entries.length === 0)
2920
- throw new Error("No supported Office XML text entries were found.");
2921
- const pieces = [];
2922
- let remaining = MAX_EXTRACTED_TEXT_CHARS;
2923
- for (const entry of entries) {
2924
- if (remaining <= 0)
2925
- break;
2926
- const text = xmlText(utf8Text(await readZipEntryData(bytes, entry)));
2927
- if (!text)
2928
- continue;
2929
- const chunk = text.slice(0, remaining);
2930
- pieces.push(`[${entry.name}]
2931
- ${chunk}`);
2932
- remaining -= chunk.length;
2933
- }
2934
- const combined = pieces.join(`
2935
-
2936
- `).slice(0, MAX_EXTRACTED_TEXT_CHARS);
2937
- if (!combined)
2938
- throw new Error("Office XML text entries contained no extractable text.");
2939
- return combined;
2940
- }
2941
2946
  function basePartIds(part) {
2942
2947
  const result = {};
2943
2948
  for (const key of ["id", "sessionID", "messageID", "sessionId", "messageId"]) {
@@ -2969,7 +2974,7 @@ async function normalizeOfficePart(part, root) {
2969
2974
  const bytes = await bytesFromPart(part, root);
2970
2975
  const materialized = await materializeAttachment(root, part.filename, part.kind, bytes);
2971
2976
  try {
2972
- const extractedText = await extractOfficeText(part.kind, bytes);
2977
+ const extractedText = await extractOfficeText(part.kind, bytes, { spreadsheetReadTool: "spreadsheet_read" });
2973
2978
  return textPartFrom(part, normalizedText(part, materialized, extractedText));
2974
2979
  } catch (cause) {
2975
2980
  const message = cause instanceof Error ? cause.message : String(cause);
@@ -103,7 +103,7 @@ function sessionContribution() {
103
103
  id: "session.search",
104
104
  kind: "query",
105
105
  title: "Find sessions",
106
- description: "Search session titles and transcripts without changing the visible workbench. Every root session's title is matched; transcripts are scanned for the `scanLimit` newest sessions only, so when the result's `truncated` is true, retry with a larger `scanLimit` (max 500). Title and phrase matches rank first, then newest `updatedAt`. Each result carries `createdAt`, `archived` and `parentId`.",
106
+ description: "Search session titles and transcripts without changing the visible workbench. Every root session's title is matched; transcripts are scanned for the `scanLimit` newest sessions only, so when the result's `truncated` is true, retry with a larger `scanLimit` (max 500). Title and phrase matches rank first, then newest `updatedAt`. Each result carries `createdAt`, `archived`, `parentId` and `engine` (v1 or v2, the engine that holds the session).",
107
107
  provider,
108
108
  arguments: [
109
109
  argument("query", "string", true, "Text to find in session titles or messages."),
@@ -122,7 +122,7 @@ function sessionContribution() {
122
122
  id: "session.read",
123
123
  kind: "query",
124
124
  title: "Read a session transcript",
125
- description: "Read messages from a session without opening it. The result also carries `createdAt`, `archived`, `parentId`, `status` (idle, busy, retry, waiting), `working` (check it before session.archive), and `model` ({ providerId, modelId, variant, displayName?, providerName? } the session is bound to, variant being its reasoning effort; null before a model is bound). Pass `summary: true` to get only the first user message and the last assistant message (what was asked, what was concluded) in one call. Both modes include `lastError` ({ code, message } or null) from the latest assistant info.error before text filtering: end reads inspect only the fetched newest `count` messages; start/summary inspect the whole transcript, even outside displayed text. Null means no assistant error observed in that window; a later assistant without an error clears it. Codes are allowlisted error names (otherwise UnknownError); messages are fixed labels under 160 characters, never arbitrary provider details. Snapshot errors only: event-only failures, including pre-assistant model-not-found, are not observable here.",
125
+ description: "Read messages from a session without opening it. Finds the session on either engine. The result also carries `engine` (v1 or v2), `createdAt`, `archived`, `parentId`, `status` (idle, busy, retry, waiting), `working` (check it before session.archive), and `model` ({ providerId, modelId, variant, displayName?, providerName? } the session is bound to, variant being its reasoning effort; null before a model is bound). Pass `summary: true` to get only the first user message and the last assistant message (what was asked, what was concluded) in one call. Both modes include `lastError` ({ code, message } or null) from the latest assistant info.error before text filtering: end reads inspect only the fetched newest `count` messages; start/summary inspect the whole transcript, even outside displayed text. Null means no assistant error observed in that window; a later assistant without an error clears it. Codes are allowlisted error names (otherwise UnknownError); messages are fixed labels under 160 characters, never arbitrary provider details. Snapshot errors only: event-only failures, including pre-assistant model-not-found, are not observable here.",
126
126
  provider,
127
127
  arguments: [
128
128
  argument("sessionId", "string", true, "Session id returned by session.search."),
@@ -0,0 +1,69 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
12
+ var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
20
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
21
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
22
+ for (let key of __getOwnPropNames(mod))
23
+ if (!__hasOwnProp.call(to, key))
24
+ __defProp(to, key, {
25
+ get: __accessProp.bind(mod, key),
26
+ enumerable: true
27
+ });
28
+ if (canCache)
29
+ cache.set(mod, to);
30
+ return to;
31
+ };
32
+ var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
33
+ var __returnValue = (v) => v;
34
+ function __exportSetter(name, newValue) {
35
+ this[name] = __returnValue.bind(null, newValue);
36
+ }
37
+ var __export = (target, all) => {
38
+ for (var name in all)
39
+ __defProp(target, name, {
40
+ get: all[name],
41
+ enumerable: true,
42
+ configurable: true,
43
+ set: __exportSetter.bind(all, name)
44
+ });
45
+ };
46
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
47
+
48
+ // src/opencode-plugins/openwork-provider-filters-v2.ts
49
+ var openwork_provider_filters_v2_default = {
50
+ id: "openwork.provider-filters",
51
+ async setup(context) {
52
+ const registration = await context.catalog.transform((catalog) => {
53
+ for (const { provider, models } of catalog.provider.list()) {
54
+ const rule = context.options.providers?.[provider.id];
55
+ if (!rule)
56
+ continue;
57
+ for (const id of models.keys()) {
58
+ if (rule.whitelist !== undefined && !rule.whitelist.includes(id) || rule.blacklist?.includes(id)) {
59
+ catalog.model.remove(provider.id, id);
60
+ }
61
+ }
62
+ }
63
+ });
64
+ return () => registration.dispose();
65
+ }
66
+ };
67
+ export {
68
+ openwork_provider_filters_v2_default as default
69
+ };
@@ -0,0 +1,2 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ export const openworkReadTransport = new AsyncLocalStorage();