pi-outpost 0.53.0 → 0.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/dist/contract/validate-structured-exchange.mjs +1 -1
  3. package/dist/pi-outpost-tools.mjs +400 -179
  4. package/dist/pi-outpost.mjs +635 -409
  5. package/dist/pi-outpost.sea.mjs +2 -2
  6. package/dist/sea-prep.blob +2 -2
  7. package/dist/web/assets/{CodeEditor-DAcPD-_i.js → CodeEditor-D_DnkSDs.js} +2 -2
  8. package/dist/web/assets/{PdfViewer-9MYqcCvn.js → PdfViewer-DSwznpLY.js} +2 -2
  9. package/dist/web/assets/{abnfDiagram-WEYOIA3C-BCtYxjG_.js → abnfDiagram-WEYOIA3C-CXeSUpSi.js} +1 -1
  10. package/dist/web/assets/{architecture-WOLXFQ4H-B3Q5jGv3.js → architecture-WOLXFQ4H-DBKgNCr7.js} +1 -1
  11. package/dist/web/assets/{architectureDiagram-ZHVYKT53-BzI6t3xu.js → architectureDiagram-ZHVYKT53-Br_4ox9E.js} +1 -1
  12. package/dist/web/assets/{blockDiagram-RJAE7QA3-CShkoCN2.js → blockDiagram-RJAE7QA3-Ba5GEjWw.js} +1 -1
  13. package/dist/web/assets/{c4Diagram-XDPPPE54-DYjcbTQt.js → c4Diagram-XDPPPE54-BNMpE5pO.js} +1 -1
  14. package/dist/web/assets/channel-CjDc0CNg.js +1 -0
  15. package/dist/web/assets/{chunk-2E7WHVMD-CwxZ6Cu3.js → chunk-2E7WHVMD-CXB0Hur_.js} +1 -1
  16. package/dist/web/assets/{chunk-4EMNKR2T-CMqWF6q6.js → chunk-4EMNKR2T-LkOyBzIG.js} +1 -1
  17. package/dist/web/assets/{chunk-55XCU76K-KeCgObu3.js → chunk-55XCU76K-CjGSk-KU.js} +1 -1
  18. package/dist/web/assets/{chunk-7S6XSTFO-vlFD1BTE.js → chunk-7S6XSTFO-BE3TFbRS.js} +1 -1
  19. package/dist/web/assets/{chunk-AQDTSKZB-CyIWjUUv.js → chunk-AQDTSKZB-CZRCYLaJ.js} +1 -1
  20. package/dist/web/assets/{chunk-DSNLSHJZ-BS23wZjm.js → chunk-DSNLSHJZ-_5UfeqbB.js} +3 -3
  21. package/dist/web/assets/{chunk-HAGFOTED-CDsO194Q.js → chunk-HAGFOTED-BBUiADox.js} +1 -1
  22. package/dist/web/assets/{chunk-HNE4Q36P-9MGA8Lxn.js → chunk-HNE4Q36P-KEgxpWZp.js} +1 -1
  23. package/dist/web/assets/{chunk-NQOKRVIF-CJeSCVvb.js → chunk-NQOKRVIF-Uez9IqgC.js} +1 -1
  24. package/dist/web/assets/{chunk-UHW7PFBP-KYxtONP0.js → chunk-UHW7PFBP-b7QvteKk.js} +1 -1
  25. package/dist/web/assets/{chunk-VQ5W62QI-W3SB7hEf.js → chunk-VQ5W62QI-Dj4wENBA.js} +1 -1
  26. package/dist/web/assets/{chunk-WQQL4CDK-CNamaf9C.js → chunk-WQQL4CDK-BrmsiMeC.js} +1 -1
  27. package/dist/web/assets/{chunk-YZO67HFG-DO20Acd4.js → chunk-YZO67HFG-D4ZGgvkZ.js} +1 -1
  28. package/dist/web/assets/{chunk-ZAUX2LTX-D6FsNM_5.js → chunk-ZAUX2LTX-aaTc0CFo.js} +1 -1
  29. package/dist/web/assets/{chunk-ZCHMQSOR-BfcHEnMA.js → chunk-ZCHMQSOR-C_EgS4-q.js} +1 -1
  30. package/dist/web/assets/{classDiagram-v2-4MYWR3UA-DiASa7Gn.js → classDiagram-v2-4MYWR3UA-DPq2CbaB.js} +1 -1
  31. package/dist/web/assets/{conversationExport-DJcjFVgt.js → conversationExport-Bhw2v55L.js} +1 -1
  32. package/dist/web/assets/{cynefin-EF2NZ3EQ-DssLVxab.js → cynefin-EF2NZ3EQ-B66Vpodo.js} +1 -1
  33. package/dist/web/assets/{cynefinDiagram-WF24UDRP-Dm1m0E0v.js → cynefinDiagram-WF24UDRP-RlQ3tIf1.js} +1 -1
  34. package/dist/web/assets/{dagre-NK4GIZVX-DufOq6D2.js → dagre-NK4GIZVX-DlxajDfi.js} +1 -1
  35. package/dist/web/assets/{diagram-CBK3MWTC-vYaMux2T.js → diagram-CBK3MWTC-DNMmua53.js} +1 -1
  36. package/dist/web/assets/{diagram-I5XIIV2D-BJ99vzOs.js → diagram-I5XIIV2D-CekTBCzw.js} +1 -1
  37. package/dist/web/assets/{diagram-ODIL2UCW-CGVswgnu.js → diagram-ODIL2UCW-R5IOCx00.js} +1 -1
  38. package/dist/web/assets/{diagram-PFBEJUXE-B_e-wnT3.js → diagram-PFBEJUXE-oNaOmsvF.js} +1 -1
  39. package/dist/web/assets/{diagram-RJA3I4VV-1U0PgVND.js → diagram-RJA3I4VV-bZUykvoo.js} +1 -1
  40. package/dist/web/assets/{diagram-TYUNFSNR-CVNigH7h.js → diagram-TYUNFSNR-DpisXU_Q.js} +1 -1
  41. package/dist/web/assets/{dist-qseUiMAf.js → dist-7QVqXE5P.js} +1 -1
  42. package/dist/web/assets/{dist-BkQYaiyz.js → dist-B1aSvv3v.js} +1 -1
  43. package/dist/web/assets/{dist-ZA2dGoPv.js → dist-C30MXivr.js} +1 -1
  44. package/dist/web/assets/{dist-DFoGwbWE.js → dist-CNtvW7Zh.js} +1 -1
  45. package/dist/web/assets/{dist-CLynH-Q3.js → dist-CoNIopDr.js} +1 -1
  46. package/dist/web/assets/{dist-GhS9C_8q.js → dist-D7kvoeYu.js} +1 -1
  47. package/dist/web/assets/{dist-CKBeQJE7.js → dist-a3ahXAvf.js} +1 -1
  48. package/dist/web/assets/{docxExport-B41axMYh.js → docxExport-CnFO6fab.js} +1 -1
  49. package/dist/web/assets/{ebnfDiagram-V4P3TTPT-sDszCU-j.js → ebnfDiagram-V4P3TTPT-DmG79yxU.js} +1 -1
  50. package/dist/web/assets/{elk-QONTBCTQ-BQmlM0nM.js → elk-QONTBCTQ-BM90ftf_.js} +1 -1
  51. package/dist/web/assets/{erDiagram-KYQIGQAA-CmEZrQsd.js → erDiagram-KYQIGQAA-RDkoxg1T.js} +1 -1
  52. package/dist/web/assets/{eventmodeling-K75KTNOO-CECfkVF0.js → eventmodeling-K75KTNOO-BjH3Nnf4.js} +1 -1
  53. package/dist/web/assets/flowDiagram-IUGLLWBU-BlawSU0b.js +1 -0
  54. package/dist/web/assets/{ganttDiagram-R7GPNTJY-Bg7jP-NU.js → ganttDiagram-R7GPNTJY-BTTaeo1u.js} +1 -1
  55. package/dist/web/assets/{gitGraph-VSP46ZUC-DH225hC9.js → gitGraph-VSP46ZUC-BP6iqTQ8.js} +1 -1
  56. package/dist/web/assets/{gitGraphDiagram-PDYL7XHY-D2iGr5VD.js → gitGraphDiagram-PDYL7XHY-uvMl9DlU.js} +1 -1
  57. package/dist/web/assets/{info-OHQRW6UA-3Jtyj0h2.js → info-OHQRW6UA-O0NhC6ee.js} +1 -1
  58. package/dist/web/assets/{infoDiagram-MVDRKAX5-C_J7aASN.js → infoDiagram-MVDRKAX5-cH4ItnGr.js} +1 -1
  59. package/dist/web/assets/{ishikawaDiagram-HPEHV2GE-CakX-ts_.js → ishikawaDiagram-HPEHV2GE-DwcbWVVj.js} +1 -1
  60. package/dist/web/assets/{journeyDiagram-BOSHW7O7-NplnNN89.js → journeyDiagram-BOSHW7O7-GH2rU2gb.js} +1 -1
  61. package/dist/web/assets/{kanban-definition-FNSA4HC5-BCZgjmGc.js → kanban-definition-FNSA4HC5-CyKzVmRS.js} +1 -1
  62. package/dist/web/assets/{line-Ceokqo7e.js → line-C2vjUtym.js} +1 -1
  63. package/dist/web/assets/{loadReferencedImage-Ds7S3_l5.js → loadReferencedImage-DxLtBpK7.js} +1 -1
  64. package/dist/web/assets/main-C16da5ba.css +2 -0
  65. package/dist/web/assets/{main-gf8FJt-H.js → main-Ue5R5tNZ.js} +88 -88
  66. package/dist/web/assets/{mermaid-parser.core-Y67AMHL1.js → mermaid-parser.core-tG1BmUd-.js} +3 -3
  67. package/dist/web/assets/{mermaid.core-Dv6g3-u3.js → mermaid.core-DXyBUqxj.js} +4 -4
  68. package/dist/web/assets/{mermaidToImage-C271Is6Y.js → mermaidToImage-Bv4MHZ2W.js} +3 -3
  69. package/dist/web/assets/{mindmap-definition-6OY57UG3-BqTUTX_J.js → mindmap-definition-6OY57UG3-BaeozbIU.js} +1 -1
  70. package/dist/web/assets/{packet-JDAUHWVQ-DGAsrwl6.js → packet-JDAUHWVQ-CWKCLoBY.js} +1 -1
  71. package/dist/web/assets/{pdf-CWXG1qJ1.js → pdf-BKHnllic.js} +1 -1
  72. package/dist/web/assets/{pegDiagram-ECIUJNBX-CY1FWJXJ.js → pegDiagram-ECIUJNBX-MLVZ1a7j.js} +1 -1
  73. package/dist/web/assets/{pie-XZMESJXO-Bj93p5lt.js → pie-XZMESJXO-BW5np6my.js} +1 -1
  74. package/dist/web/assets/{pieDiagram-GNMPY74T-CaEKMfrS.js → pieDiagram-GNMPY74T-Kv51qwWS.js} +1 -1
  75. package/dist/web/assets/{quadrantDiagram-D57K4MC3-BmVQ62PC.js → quadrantDiagram-D57K4MC3-BMK2ozor.js} +1 -1
  76. package/dist/web/assets/{radar-ABXABTNO-CXb-wx8c.js → radar-ABXABTNO-D_8EVs7_.js} +1 -1
  77. package/dist/web/assets/{railroad-I3PHUGI6-bic4HrF1.js → railroad-I3PHUGI6-B5s-cVPp.js} +1 -1
  78. package/dist/web/assets/{railroad-abnf-LNEFI6M7-BGnpw65W.js → railroad-abnf-LNEFI6M7-DlLoruFg.js} +1 -1
  79. package/dist/web/assets/{railroad-ebnf-DWYD2UWJ-BN1C-gh_.js → railroad-ebnf-DWYD2UWJ-D7gWw3v2.js} +1 -1
  80. package/dist/web/assets/{railroad-peg-JR7BVNR7-D3Ik9xFQ.js → railroad-peg-JR7BVNR7-ma1Am_iU.js} +1 -1
  81. package/dist/web/assets/{railroadDiagram-Y72NRBL7-tvHc4WUa.js → railroadDiagram-Y72NRBL7-ZKdyT5HU.js} +1 -1
  82. package/dist/web/assets/{requirementDiagram-EQYSW5RA-BQVcJlMK.js → requirementDiagram-EQYSW5RA-BkKzYQdn.js} +1 -1
  83. package/dist/web/assets/{sankeyDiagram-SY24JHO5-CcGVbRdU.js → sankeyDiagram-SY24JHO5-BkP8s83Q.js} +1 -1
  84. package/dist/web/assets/{sequenceDiagram-BLEHNHQU-BIOwiUpA.js → sequenceDiagram-BLEHNHQU-B-_Ee3qq.js} +1 -1
  85. package/dist/web/assets/{stateDiagram-v2-A6IESKWZ-Bcwlq84T.js → stateDiagram-v2-A6IESKWZ-BxXyNx86.js} +1 -1
  86. package/dist/web/assets/{swimlanes-B3ENRKFQ-DjSwkYnv.js → swimlanes-B3ENRKFQ-CWBFcBNi.js} +1 -1
  87. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-CV9FijB4.js +8 -0
  88. package/dist/web/assets/{timeline-definition-JXYKGLGB-CRf5WLLQ.js → timeline-definition-JXYKGLGB-J5LYF--U.js} +1 -1
  89. package/dist/web/assets/{treeView-D4JQ5SDB-BY1ZiAEq.js → treeView-D4JQ5SDB-CyNlstbH.js} +1 -1
  90. package/dist/web/assets/{treemap-SAJKECNS-BDzbCU2P.js → treemap-SAJKECNS-CUtZCzov.js} +1 -1
  91. package/dist/web/assets/{usecaseDiagram-WPOLBNNX-D9dhxtV7.js → usecaseDiagram-WPOLBNNX-DKVr3wqB.js} +1 -1
  92. package/dist/web/assets/{vennDiagram-Q3Y3IDCW-dTYkJ71A.js → vennDiagram-Q3Y3IDCW-CbfiWVKK.js} +1 -1
  93. package/dist/web/assets/{wardley-7MLQ67FV-CakH6UaC.js → wardley-7MLQ67FV-Cmh7icRv.js} +1 -1
  94. package/dist/web/assets/{wardleyDiagram-IVAIDKWA-9aGLYKei.js → wardleyDiagram-IVAIDKWA-BLoVZPg_.js} +1 -1
  95. package/dist/web/assets/{xychartDiagram-4URNHDU4-BmzxdakH.js → xychartDiagram-4URNHDU4-DFwZczby.js} +1 -1
  96. package/dist/web/index.html +2 -2
  97. package/package.json +1 -1
  98. package/dist/web/assets/channel-B9MEgUyj.js +0 -1
  99. package/dist/web/assets/flowDiagram-IUGLLWBU-BjCYoJgR.js +0 -1
  100. package/dist/web/assets/main-C6IHKUqy.css +0 -2
  101. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-CL8F2C8N.js +0 -8
@@ -99494,6 +99494,174 @@ var require_extend = __commonJS({
99494
99494
  // ../server/src/piOutpostTools.ts
99495
99495
  import fs21 from "node:fs/promises";
99496
99496
 
99497
+ // ../shared/src/structuredExchangeProfile.ts
99498
+ var STRUCTURED_EXCHANGE_PROFILE_REGISTRY_SCHEMA_V2 = "urn:structured-exchange-profile-registry:2";
99499
+ var STRUCTURED_EXCHANGE_PROFILE_REGISTRY_PATH = ".pi-outpost/structured-exchange.json";
99500
+ var STRUCTURED_EXCHANGE_CONFORMITY_REPORT_PROFILE = "urn:structured-exchange-conformity-report:1";
99501
+ var STRUCTURED_EXCHANGE_RULES_REGISTER_PROFILE = "urn:structured-exchange-rules-register:1";
99502
+ var STRUCTURED_EXCHANGE_RULE_PATTERNS_PROFILE = "urn:structured-exchange-rule-patterns:1";
99503
+ var RESERVED_PROFILE_IDENTIFIERS = /* @__PURE__ */ new Set([
99504
+ STRUCTURED_EXCHANGE_CONFORMITY_REPORT_PROFILE,
99505
+ STRUCTURED_EXCHANGE_RULES_REGISTER_PROFILE,
99506
+ STRUCTURED_EXCHANGE_RULE_PATTERNS_PROFILE
99507
+ ]);
99508
+ var STRUCTURED_EXCHANGE_PROFILE_CEILINGS = {
99509
+ /** A profile's identifier, bounded like the `profile` a document names it by. */
99510
+ id: 200,
99511
+ label: 500,
99512
+ description: 2e3,
99513
+ /** Kinds per vocabulary, as a document's `kindsPerVocabulary`. */
99514
+ kindsPerVocabulary: 64,
99515
+ /** Attributes one kind declares, as a document's `attributesPerItem`. */
99516
+ attributesPerKind: 50,
99517
+ attributeName: 200,
99518
+ /**
99519
+ * Values one enumeration lists. Generous: a requirements tool's enumerations
99520
+ * include long ones — components, suppliers — and a profile that cannot hold its
99521
+ * model's is a profile nobody can finish.
99522
+ */
99523
+ enumerationValues: 500,
99524
+ /** One enumeration value, as a document's `attributeString`. */
99525
+ enumerationValue: 1e3,
99526
+ viewpoints: 20,
99527
+ /** Profiles one registry lists. */
99528
+ profilesPerRegistry: 20,
99529
+ profilePath: 500,
99530
+ /** Bytes read from a profile file before it is parsed. */
99531
+ profileBytes: 1048576,
99532
+ /** Bytes read from a registry file before it is parsed. */
99533
+ registryBytes: 65536
99534
+ };
99535
+ function profileListing(profile) {
99536
+ const lines = [`Profile ${profile.id} \u2014 ${profile.label}`];
99537
+ if (profile.description !== void 0) lines.push(profile.description);
99538
+ const vocabulary = (heading3, kinds, relationships) => {
99539
+ const declared = kinds ?? [];
99540
+ lines.push("", `${heading3}: ${declared.length}`);
99541
+ for (const declaration of declared) {
99542
+ lines.push(` ${declaration.kind}`);
99543
+ if (declaration.description !== void 0) lines.push(` ${declaration.description}`);
99544
+ if (relationships) {
99545
+ lines.push(` source: ${declaration.from?.join(", ") ?? "any element kind"}`);
99546
+ lines.push(` target: ${declaration.to?.join(", ") ?? "any element kind"}`);
99547
+ }
99548
+ const attributes2 = declaration.attributes ?? [];
99549
+ if (attributes2.length === 0) lines.push(" (no attributes)");
99550
+ for (const attribute of attributes2) {
99551
+ const traits = [
99552
+ attribute.list === true ? `list of ${attribute.type}` : attribute.type,
99553
+ ...attribute.type === "enumeration" ? [attribute.closed === true ? "closed" : "open"] : [],
99554
+ attribute.required === true ? "required" : "optional"
99555
+ ];
99556
+ const count = attribute.type === "enumeration" ? ` \u2014 ${(attribute.values ?? []).length} values` : "";
99557
+ lines.push(` ${attribute.name}: ${traits.join(", ")}${count}`);
99558
+ if (attribute.description !== void 0) lines.push(` ${attribute.description}`);
99559
+ for (const value of attribute.values ?? []) lines.push(` - ${value}`);
99560
+ }
99561
+ }
99562
+ };
99563
+ vocabulary("Element kinds (graph elements and table rows)", profile.elementKinds, false);
99564
+ vocabulary("Relationship kinds (graph relationships and table relations)", profile.relationshipKinds, true);
99565
+ const viewpoints = profile.viewpoints ?? [];
99566
+ lines.push("", `Viewpoints: ${viewpoints.length}`);
99567
+ for (const viewpoint of viewpoints) {
99568
+ lines.push(` ${viewpoint.id} \u2014 ${viewpoint.label}: ${viewpoint.concern}`);
99569
+ if (viewpoint.elementKinds !== void 0) lines.push(` element kinds: ${viewpoint.elementKinds.join(", ")}`);
99570
+ if (viewpoint.relationshipKinds !== void 0) lines.push(` relationship kinds: ${viewpoint.relationshipKinds.join(", ")}`);
99571
+ }
99572
+ return `${lines.join("\n")}
99573
+ `;
99574
+ }
99575
+ function describeConditions(set) {
99576
+ return Object.entries(set ?? {}).map(([name, values]) => `${name} \u2208 {${values.map((value) => JSON.stringify(value)).join(", ")}}`).join(" and ") || "always";
99577
+ }
99578
+ function describeLinkConditions(set) {
99579
+ const parts = [
99580
+ set?.from === void 0 ? void 0 : `source ${describeConditions(set.from)}`,
99581
+ set?.to === void 0 ? void 0 : `target ${describeConditions(set.to)}`
99582
+ ].filter((part) => part !== void 0);
99583
+ return parts.length === 0 ? "always" : parts.join(" and ");
99584
+ }
99585
+ function rulesListing(profileId, rules) {
99586
+ const conditions = describeConditions;
99587
+ const ends = describeLinkConditions;
99588
+ const lines = [`Rules for ${profileId}: ${rules.length}`];
99589
+ for (const rule of rules) {
99590
+ lines.push("", ` ${rule.id} \u2014 ${rule.level}${rule.source === void 0 ? "" : ` \u2014 ${rule.source}`}`, ` ${rule.statement}`);
99591
+ if (rule.element !== void 0) {
99592
+ lines.push(` applies to: element ${rule.element}`, ` when: ${conditions(rule.when)}`);
99593
+ lines.push(` then: ${rule.then === "forbidden" ? "forbidden" : conditions(rule.then)}`);
99594
+ } else {
99595
+ lines.push(` applies to: relationship ${rule.relationship}`, ` when: ${ends(rule.when)}`);
99596
+ lines.push(` then: ${rule.then === "forbidden" ? "forbidden" : ends(rule.then)}`);
99597
+ }
99598
+ }
99599
+ return `${lines.join("\n")}
99600
+ `;
99601
+ }
99602
+ var STRUCTURED_EXCHANGE_RULES_CEILINGS = {
99603
+ rulesPerFile: 200,
99604
+ ruleId: 200,
99605
+ statement: 2e3,
99606
+ source: 500,
99607
+ /** Conditions in one set — `when`, `then`, or one end of a link. */
99608
+ conditionsPerSet: 20,
99609
+ /** Values one condition allows, as `enumerationValues`. */
99610
+ valuesPerCondition: 500,
99611
+ /** One value, as `enumerationValue`. */
99612
+ value: 1e3,
99613
+ attributeName: 200,
99614
+ kind: 100,
99615
+ /** Rules files one registry lists. */
99616
+ rulesFilesPerRegistry: 20,
99617
+ /** Bytes read from a rules file before it is parsed. */
99618
+ rulesBytes: 1048576
99619
+ };
99620
+
99621
+ // ../server/src/projectModelTool.ts
99622
+ var PROJECT_MODEL_TOOL = "present_project_model";
99623
+
99624
+ // ../server/src/documentTools.ts
99625
+ var PRESENTATION_TOOLS = ["pptx_layouts", "pptx_create", "pptx_update", "pptx_render"];
99626
+ var WORD_TOOLS = ["docx_styles", "docx_create", "docx_update", "docx_restyle", "docx_render"];
99627
+ var WORD_COMPARE_TOOL = "docx_compare";
99628
+ var EXTRACTORS = {
99629
+ // `pdf_render` travels with the extractor because it is the answer to something the
99630
+ // extractor says: a page carrying neither text nor an image tells the caller to draw
99631
+ // it, and that advice is worthless if the tool it names was never offered.
99632
+ pdf: ["pdf_extract", "pdf_render"],
99633
+ // A Word document may be read, updated, or be the template a new one is written from.
99634
+ docx: ["docx_extract", ...WORD_TOOLS],
99635
+ // A .dotx is only ever a template.
99636
+ dotx: WORD_TOOLS,
99637
+ xlsx: ["xlsx_extract"],
99638
+ // A deck may be read, or be the template a new one is built from.
99639
+ pptx: ["pptx_extract", ...PRESENTATION_TOOLS],
99640
+ // A .potx is only ever a template.
99641
+ potx: PRESENTATION_TOOLS,
99642
+ // A message is read by one tool, which also unpacks what it carries. The
99643
+ // extractors for those attachments are published when they are *written*, not
99644
+ // here: naming a `.msg` says nothing about what is inside it.
99645
+ msg: ["mail_extract"],
99646
+ eml: ["mail_extract"],
99647
+ emlx: ["mail_extract"]
99648
+ };
99649
+ var DOCUMENT_TOOLS = [...new Set(Object.values(EXTRACTORS).flat()), WORD_COMPARE_TOOL];
99650
+ var TOOL_SEARCH_TOOL = "tool_search";
99651
+ var DEFERRED_TOOLS = [
99652
+ ...DOCUMENT_TOOLS,
99653
+ PROJECT_MODEL_TOOL,
99654
+ "drawio_check",
99655
+ "poster_check",
99656
+ "poster_pictures",
99657
+ "compare_timelines",
99658
+ "write_structure_figure",
99659
+ "write_structure_table"
99660
+ ];
99661
+ function deferOnDemandTools(tools) {
99662
+ return tools.map((tool) => DEFERRED_TOOLS.includes(tool.name) ? { ...tool, exposure: "deferred" } : tool);
99663
+ }
99664
+
99497
99665
  // ../server/src/posterPictureHooks.ts
99498
99666
  import { readFile } from "node:fs/promises";
99499
99667
  import os from "node:os";
@@ -99702,6 +99870,177 @@ function registerPosterPictureHooks(pi) {
99702
99870
  });
99703
99871
  }
99704
99872
 
99873
+ // ../server/src/btwExtension.ts
99874
+ import { randomUUID } from "node:crypto";
99875
+ var BTW_WIDGET = "btw";
99876
+ var BTW_TITLE = "Side answer \xB7 not part of the conversation";
99877
+ var DEFAULT_BTW_BUDGET = 6e4;
99878
+ var TOOL_TEXT_LIMIT = 2e3;
99879
+ var LEFT_OUT = "[Earlier conversation left out.]";
99880
+ var SYSTEM_PROMPT = [
99881
+ "You answer a side question about a conversation between a user and a coding agent, which may still be working.",
99882
+ "Answer only from the conversation shown. You have no tools: you cannot read files, run commands or look anything up.",
99883
+ "If the conversation does not show the answer, say so. Never add a reason, a fact or a detail the conversation does not state.",
99884
+ "Earlier side questions, when given, are the user's previous questions to you, and the new question may follow up on them.",
99885
+ "Answer briefly, in the language of the question."
99886
+ ].join(" ");
99887
+ function cut(text7, limit) {
99888
+ return text7.length <= limit ? text7 : `${text7.slice(0, limit)}\u2026 [cut]`;
99889
+ }
99890
+ function textOf(content3) {
99891
+ if (typeof content3 === "string") return content3;
99892
+ if (!Array.isArray(content3)) return "";
99893
+ return content3.flatMap((block) => block?.type === "text" && typeof block.text === "string" ? [block.text] : block?.type === "image" ? ["[image]"] : []).join("\n").trim();
99894
+ }
99895
+ function sectionOf(entry) {
99896
+ const message = entry.type === "message" ? entry.message : void 0;
99897
+ if (!message) return void 0;
99898
+ if (message.role === "user") {
99899
+ const text7 = textOf(message.content);
99900
+ return text7 ? `User: ${text7}` : void 0;
99901
+ }
99902
+ if (message.role === "assistant") {
99903
+ const lines = [];
99904
+ const text7 = textOf(message.content);
99905
+ if (text7) lines.push(`Assistant: ${text7}`);
99906
+ if (Array.isArray(message.content)) {
99907
+ for (const block of message.content) {
99908
+ if (block?.type !== "toolCall" || typeof block.name !== "string") continue;
99909
+ lines.push(`Assistant called ${block.name} ${cut(JSON.stringify(block.arguments ?? {}), TOOL_TEXT_LIMIT)}`);
99910
+ }
99911
+ }
99912
+ return lines.length > 0 ? lines.join("\n") : void 0;
99913
+ }
99914
+ if (message.role === "toolResult") {
99915
+ const label = `${message.isError ? "Error from" : "Result of"} ${message.toolName ?? "tool"}`;
99916
+ return `${label}: ${cut(textOf(message.content), TOOL_TEXT_LIMIT)}`;
99917
+ }
99918
+ return void 0;
99919
+ }
99920
+ function serialiseBranch(entries, budget = DEFAULT_BTW_BUDGET) {
99921
+ let start = 0;
99922
+ let summary;
99923
+ const compaction = entries.findLastIndex((entry) => entry.type === "compaction");
99924
+ if (compaction !== -1) {
99925
+ const entry = entries[compaction];
99926
+ summary = `Summary of the conversation before this point: ${entry.summary ?? ""}`;
99927
+ const kept2 = entries.findIndex((candidate) => candidate.id === entry.firstKeptEntryId);
99928
+ start = kept2 !== -1 && kept2 < compaction ? kept2 : compaction + 1;
99929
+ }
99930
+ const sections = entries.slice(start).flatMap((entry) => {
99931
+ const section2 = sectionOf(entry);
99932
+ return section2 === void 0 ? [] : [section2];
99933
+ });
99934
+ const separator = "\n\n";
99935
+ const head = summary === void 0 ? [] : [cut(summary, Math.floor(budget / 2))];
99936
+ const whole = [...head, ...sections].join(separator);
99937
+ if (whole.length <= budget) return whole;
99938
+ head.push(LEFT_OUT);
99939
+ const room = budget - head.join(separator).length;
99940
+ const kept = [];
99941
+ let used = 0;
99942
+ for (let i2 = sections.length - 1; i2 >= 0; i2--) {
99943
+ const cost = separator.length + sections[i2].length;
99944
+ if (used + cost > room) break;
99945
+ kept.unshift(sections[i2]);
99946
+ used += cost;
99947
+ }
99948
+ if (kept.length === 0 && sections.length > 0) {
99949
+ const last = sections[sections.length - 1];
99950
+ kept.push(last.slice(last.length - Math.max(0, room - separator.length)));
99951
+ }
99952
+ return [...head, ...kept].join(separator);
99953
+ }
99954
+ function serialiseThread(thread, limit) {
99955
+ const parts = thread.map(({ question, answer: answer3 }) => `Side question: ${question}
99956
+ Side answer: ${answer3}`);
99957
+ while (parts.length > 0 && parts.join("\n\n").length > limit) parts.shift();
99958
+ return parts.join("\n\n");
99959
+ }
99960
+ function sideQuestionContext(entries, question, budget = DEFAULT_BTW_BUDGET, thread = []) {
99961
+ const earlier = serialiseThread(thread, Math.floor(budget / 2));
99962
+ const conversation = serialiseBranch(entries, Math.max(0, budget - question.length - earlier.length));
99963
+ const now = Date.now();
99964
+ const text7 = `<conversation>
99965
+ ${conversation}
99966
+ </conversation>${earlier ? `
99967
+
99968
+ <earlier_side_questions>
99969
+ ${earlier}
99970
+ </earlier_side_questions>` : ""}`;
99971
+ return {
99972
+ systemPrompt: SYSTEM_PROMPT,
99973
+ messages: [
99974
+ { role: "user", content: [{ type: "text", text: text7 }], timestamp: now },
99975
+ { role: "user", content: [{ type: "text", text: question }], timestamp: now }
99976
+ ]
99977
+ };
99978
+ }
99979
+ var QUESTION_MARK = "\u203A ";
99980
+ function panel(question, body, earlier) {
99981
+ const exchanges = earlier.flatMap((exchange) => [`${QUESTION_MARK}${exchange.question}`, ...exchange.answer.split(/\r?\n/), ""]);
99982
+ return [BTW_TITLE, ...exchanges, `${QUESTION_MARK}${question}`, ...body];
99983
+ }
99984
+ function show(ctx, lines) {
99985
+ try {
99986
+ ctx.ui.setWidget(BTW_WIDGET, lines, { placement: "aboveEditor" });
99987
+ } catch {
99988
+ }
99989
+ }
99990
+ async function answer(ctx, question, budget, thread, signal) {
99991
+ const model = ctx.model;
99992
+ if (!model) return { answered: false, reason: "no model is selected" };
99993
+ if (!ctx.modelRegistry.hasConfiguredAuth(model)) return { answered: false, reason: `${model.provider}/${model.id} has no credentials` };
99994
+ const context = sideQuestionContext(ctx.sessionManager.getBranch(), question, budget, thread);
99995
+ const reply = await ctx.modelRegistry.streamSimple(model, context, { signal, cacheRetention: "none", sessionId: randomUUID() }).result();
99996
+ if (reply.stopReason === "error") return { answered: false, reason: reply.errorMessage ?? "the provider failed" };
99997
+ const text7 = textOf(reply.content);
99998
+ return text7 ? { answered: true, text: text7 } : { answered: false, reason: "the model returned nothing" };
99999
+ }
100000
+ function createBtwExtension(options2 = {}) {
100001
+ const budget = options2.budget ?? DEFAULT_BTW_BUDGET;
100002
+ return function btw(pi) {
100003
+ let pending;
100004
+ let thread = [];
100005
+ const cancel = () => {
100006
+ pending?.abort();
100007
+ pending = void 0;
100008
+ };
100009
+ const close2 = (ctx) => {
100010
+ cancel();
100011
+ thread = [];
100012
+ show(ctx, void 0);
100013
+ };
100014
+ pi.registerCommand("btw", {
100015
+ description: "Ask a side question about the conversation, without interrupting the agent or entering the conversation",
100016
+ handler: async (args, ctx) => {
100017
+ const question = args.trim();
100018
+ if (!question) {
100019
+ close2(ctx);
100020
+ return;
100021
+ }
100022
+ cancel();
100023
+ const controller = new AbortController();
100024
+ pending = controller;
100025
+ const earlier = [...thread];
100026
+ show(ctx, panel(question, ["Answering\u2026"], earlier));
100027
+ void answer(ctx, question, budget, earlier, controller.signal).catch((error) => ({ answered: false, reason: error instanceof Error ? error.message : String(error) })).then((outcome) => {
100028
+ if (pending !== controller) return;
100029
+ pending = void 0;
100030
+ if (outcome.answered) thread = [...earlier, { question, answer: outcome.text }];
100031
+ const body = outcome.answered ? outcome.text.split(/\r?\n/) : [`No answer: ${outcome.reason}.`];
100032
+ show(ctx, panel(question, body, earlier));
100033
+ });
100034
+ }
100035
+ });
100036
+ pi.on("session_start", (_event, ctx) => close2(ctx));
100037
+ pi.on("session_shutdown", () => {
100038
+ cancel();
100039
+ thread = [];
100040
+ });
100041
+ };
100042
+ }
100043
+
99705
100044
  // ../server/src/docxTool.ts
99706
100045
  import fs19 from "node:fs/promises";
99707
100046
  import path23 from "node:path";
@@ -105223,7 +105562,7 @@ var CHANGE_RECORD = /^w:\w+(?:Pr|PrEx|Grid)Change$/;
105223
105562
  var REVISION_PRECEDENCE = ["del", "moveFrom", "moveTo", "ins"];
105224
105563
  function parseBody(xml, deadline, pictureMarkerFor, review) {
105225
105564
  const blocks = [];
105226
- const show = review?.show === true;
105565
+ const show2 = review?.show === true;
105227
105566
  let paragraph2 = [];
105228
105567
  let paragraphHeading;
105229
105568
  let styleId;
@@ -105318,9 +105657,9 @@ function parseBody(xml, deadline, pictureMarkerFor, review) {
105318
105657
  return removes(revision) ? { open: DELETE_OPEN, close: DELETE_CLOSE + referenceSentinel(id) } : { open: INSERT_OPEN, close: INSERT_CLOSE + referenceSentinel(id) };
105319
105658
  };
105320
105659
  const emit = (raw, revision) => {
105321
- const text7 = show ? raw.replace(/[\u0001\u0002]/g, "") : raw;
105660
+ const text7 = show2 ? raw.replace(/[\u0001\u0002]/g, "") : raw;
105322
105661
  const markers = note(text7, revision);
105323
- target().push(show && markers !== void 0 ? { text: text7, format: runFormat, revision: markers } : { text: text7, format: runFormat });
105662
+ target().push(show2 && markers !== void 0 ? { text: text7, format: runFormat, revision: markers } : { text: text7, format: runFormat });
105324
105663
  };
105325
105664
  const pushRaw = (text7) => target().push({ text: text7, format: 0, raw: true });
105326
105665
  const noteComment = (layer, id) => {
@@ -105340,7 +105679,7 @@ function parseBody(xml, deadline, pictureMarkerFor, review) {
105340
105679
  const flushParagraph = () => {
105341
105680
  const text7 = renderSpans(paragraph2).replace(/\s+/g, " ").trim();
105342
105681
  const heading3 = paragraphHeading;
105343
- const plain = show && heading3 !== void 0 ? acceptedText(paragraph2) : void 0;
105682
+ const plain = show2 && heading3 !== void 0 ? acceptedText(paragraph2) : void 0;
105344
105683
  paragraph2 = [];
105345
105684
  paragraphHeading = void 0;
105346
105685
  styleId = void 0;
@@ -105417,14 +105756,14 @@ function parseBody(xml, deadline, pictureMarkerFor, review) {
105417
105756
  if (review === void 0 || id === void 0 || review.replies.has(id)) break;
105418
105757
  rangedComments.add(id);
105419
105758
  noteComment(review, id);
105420
- if (show && openComments.size === 0 && paragraphDepth > 0) pushRaw(ANCHOR_OPEN);
105759
+ if (show2 && openComments.size === 0 && paragraphDepth > 0) pushRaw(ANCHOR_OPEN);
105421
105760
  openComments.add(id);
105422
105761
  break;
105423
105762
  }
105424
105763
  case "w:commentRangeEnd": {
105425
105764
  const id = event.attributes["w:id"];
105426
105765
  if (id === void 0 || !openComments.delete(id)) break;
105427
- if (!show) break;
105766
+ if (!show2) break;
105428
105767
  if (paragraphDepth > 0) {
105429
105768
  if (openComments.size === 0) pushRaw(ANCHOR_CLOSE);
105430
105769
  pushRaw(referenceSentinel(`c:${id}`));
@@ -105437,7 +105776,7 @@ function parseBody(xml, deadline, pictureMarkerFor, review) {
105437
105776
  const id = event.attributes["w:id"];
105438
105777
  if (review === void 0 || id === void 0 || review.replies.has(id) || rangedComments.has(id)) break;
105439
105778
  noteComment(review, id);
105440
- if (show) pushRaw(referenceSentinel(`c:${id}`));
105779
+ if (show2) pushRaw(referenceSentinel(`c:${id}`));
105441
105780
  break;
105442
105781
  }
105443
105782
  case "w:tbl":
@@ -105468,7 +105807,7 @@ function parseBody(xml, deadline, pictureMarkerFor, review) {
105468
105807
  paragraph2 = [];
105469
105808
  paragraphHeading = void 0;
105470
105809
  }
105471
- if (show && openComments.size > 0) pushRaw(ANCHOR_OPEN);
105810
+ if (show2 && openComments.size > 0) pushRaw(ANCHOR_OPEN);
105472
105811
  break;
105473
105812
  case "w:pStyle":
105474
105813
  styleId = event.attributes["w:val"];
@@ -105498,7 +105837,7 @@ function parseBody(xml, deadline, pictureMarkerFor, review) {
105498
105837
  case "w:t":
105499
105838
  case "w:delText": {
105500
105839
  const revision = effectiveRevision();
105501
- if (removes(revision) ? show : event.name === "w:t") {
105840
+ if (removes(revision) ? show2 : event.name === "w:t") {
105502
105841
  textTarget = inCell ? "cell" : "paragraph";
105503
105842
  textRevision = revision;
105504
105843
  } else if (removes(revision)) {
@@ -105530,7 +105869,7 @@ function parseBody(xml, deadline, pictureMarkerFor, review) {
105530
105869
  case "w:br":
105531
105870
  case "w:cr": {
105532
105871
  const revision = effectiveRevision();
105533
- if (!removes(revision) || show) emit(" ", revision);
105872
+ if (!removes(revision) || show2) emit(" ", revision);
105534
105873
  break;
105535
105874
  }
105536
105875
  default:
@@ -105597,7 +105936,7 @@ function parseBody(xml, deadline, pictureMarkerFor, review) {
105597
105936
  break;
105598
105937
  case "w:p":
105599
105938
  if (paragraphDepth > 0) paragraphDepth--;
105600
- if (show && openComments.size > 0) pushRaw(ANCHOR_CLOSE);
105939
+ if (show2 && openComments.size > 0) pushRaw(ANCHOR_CLOSE);
105601
105940
  group = void 0;
105602
105941
  if (inCell) cell.push({ text: " ", format: 0 });
105603
105942
  else {
@@ -105612,7 +105951,7 @@ function parseBody(xml, deadline, pictureMarkerFor, review) {
105612
105951
  }
105613
105952
  break;
105614
105953
  case "w:tr":
105615
- if (tableDepth === 1 && !(rowDeleted && !show)) rows.push(row);
105954
+ if (tableDepth === 1 && !(rowDeleted && !show2)) rows.push(row);
105616
105955
  if (tableDepth === 1 && rowRevision !== void 0) {
105617
105956
  revisions.splice(revisions.indexOf(rowRevision), 1);
105618
105957
  rowRevision = void 0;
@@ -105886,10 +106225,10 @@ async function extractDocx(bytes, options2 = {}) {
105886
106225
  if (documentXml === null) {
105887
106226
  throw new DocxError("unreadable", `This package has no ${DOCUMENT_PART}: it is not a Word document.`);
105888
106227
  }
105889
- const show = options2.review === true;
105890
- const comments = readComments(buffer, limits, show);
106228
+ const show2 = options2.review === true;
106229
+ const comments = readComments(buffer, limits, show2);
105891
106230
  const layer = {
105892
- show,
106231
+ show: show2,
105893
106232
  replies: new Set([...comments.values()].filter((comment) => comment.parentId !== void 0).map((comment) => comment.id)),
105894
106233
  entries: /* @__PURE__ */ new Map()
105895
106234
  };
@@ -105904,15 +106243,15 @@ async function extractDocx(bytes, options2 = {}) {
105904
106243
  const blockCount = blocks.length;
105905
106244
  if (blockCount === 0) {
105906
106245
  return {
105907
- markdown: "_This document has no extractable body content._\n\n" + (show ? "> Headers, footers, footnotes and text boxes are not read by this tool." : "> Headers, footers, footnotes, comments and text boxes are not read by this tool."),
106246
+ markdown: "_This document has no extractable body content._\n\n" + (show2 ? "> Headers, footers, footnotes and text boxes are not read by this tool." : "> Headers, footers, footnotes, comments and text boxes are not read by this tool."),
105908
106247
  blocks: [],
105909
106248
  blockCount: 0,
105910
106249
  pictures,
105911
- ...show ? { review: reviewCounts(layer) } : {}
106250
+ ...show2 ? { review: reviewCounts(layer) } : {}
105912
106251
  };
105913
106252
  }
105914
106253
  const requested = options2.blocks ? parseBlockRange(options2.blocks, blockCount) : rangeTo(blockCount);
105915
- const labels = show ? numberReferences(blocks) : /* @__PURE__ */ new Map();
106254
+ const labels = show2 ? numberReferences(blocks) : /* @__PURE__ */ new Map();
105916
106255
  const shown2 = [];
105917
106256
  const pieces = [];
105918
106257
  const covered = [];
@@ -105931,7 +106270,7 @@ async function extractDocx(bytes, options2 = {}) {
105931
106270
  }
105932
106271
  deadline();
105933
106272
  let rendered = renderBlock(blocks[number2 - 1], mode);
105934
- if (show) {
106273
+ if (show2) {
105935
106274
  const resolved2 = resolveSentinels(rendered, labels);
105936
106275
  rendered = resolved2.text;
105937
106276
  for (const id of resolved2.references) if (!shown2.includes(id)) shown2.push(id);
@@ -105953,7 +106292,7 @@ async function extractDocx(bytes, options2 = {}) {
105953
106292
  );
105954
106293
  }
105955
106294
  const leads = [struckThroughNotice(pieces.join("\n\n")), reviewNotice(layer, shown2, labels)].filter((line) => line !== "");
105956
- const list3 = show && shown2.length > 0 ? [reviewList(shown2, layer, labels, headingPaths(blocks), comments)] : [];
106295
+ const list3 = show2 && shown2.length > 0 ? [reviewList(shown2, layer, labels, headingPaths(blocks), comments)] : [];
105957
106296
  const markdown = [...leads, ...pieces, ...list3, ...notes].join("\n\n");
105958
106297
  if (full && markdown.length > ABSOLUTE_MAX_CHARS) {
105959
106298
  throw new DocxError(
@@ -105967,7 +106306,7 @@ async function extractDocx(bytes, options2 = {}) {
105967
106306
  ...nextBlock === void 0 ? {} : { nextBlock },
105968
106307
  blockCount,
105969
106308
  pictures,
105970
- ...show ? { review: reviewCounts(layer) } : {}
106309
+ ...show2 ? { review: reviewCounts(layer) } : {}
105971
106310
  };
105972
106311
  }
105973
106312
  function readComments(buffer, limits, review) {
@@ -106379,10 +106718,10 @@ function commentsOf(annotations, pieces) {
106379
106718
  return { comments: top, count: count(top) };
106380
106719
  }
106381
106720
  function quoted(remark, indent2) {
106382
- const cut = remark.length > MAX_REMARK_CHARS;
106383
- const text7 = cut ? remark.slice(0, MAX_REMARK_CHARS) : remark;
106721
+ const cut2 = remark.length > MAX_REMARK_CHARS;
106722
+ const text7 = cut2 ? remark.slice(0, MAX_REMARK_CHARS) : remark;
106384
106723
  const lines = text7.split("\n").map((line) => line.trim() === "" ? `${indent2}>` : `${indent2}> ${line}`);
106385
- if (cut) lines.push(`${indent2}> _[remark cut at ${MAX_REMARK_CHARS} characters]_`);
106724
+ if (cut2) lines.push(`${indent2}> _[remark cut at ${MAX_REMARK_CHARS} characters]_`);
106386
106725
  return lines;
106387
106726
  }
106388
106727
  function heading(comment) {
@@ -107940,11 +108279,11 @@ function serialToDate(serial, epoch1904) {
107940
108279
  function pad(value, width) {
107941
108280
  return String(value).padStart(width, "0");
107942
108281
  }
107943
- function formatDateParts(parts, show) {
108282
+ function formatDateParts(parts, show2) {
107944
108283
  const date = `${pad(parts.year, 4)}-${pad(parts.month, 2)}-${pad(parts.day, 2)}`;
107945
108284
  const time = `${pad(parts.hours, 2)}:${pad(parts.minutes, 2)}:${pad(parts.seconds, 2)}`;
107946
- if (show.date && show.time) return `${date} ${time}`;
107947
- if (show.time) return time;
108285
+ if (show2.date && show2.time) return `${date} ${time}`;
108286
+ if (show2.time) return time;
107948
108287
  return date;
107949
108288
  }
107950
108289
  function generalNumber(value) {
@@ -108561,7 +108900,7 @@ var parameters = typebox_exports.Object({
108561
108900
  )
108562
108901
  });
108563
108902
  var DESCRIPTION = [
108564
- "Extract a spreadsheet (.xlsx) as markdown tables: one table per sheet, with the workbook's own column letters and row numbers so cells stay addressable.",
108903
+ "Extract an Excel spreadsheet (.xlsx) as markdown tables: one table per sheet, with the workbook's own column letters and row numbers so cells stay addressable.",
108565
108904
  "If the user wants the workbook saved, converted, or written anywhere, pass output_path: it writes every visible sheet there in one call and returns a short summary.",
108566
108905
  "Do not return the content and then write it yourself \u2014 that spends the context twice.",
108567
108906
  "Without sheet, every visible sheet is read in workbook order; hidden sheets and hidden columns are not read and are reported.",
@@ -111193,22 +111532,22 @@ function createMailExtractToolDefinition(options2) {
111193
111532
  `This message's body is ${message.body?.markdown.length} characters, past the ${ABSOLUTE_MAX_BODY_CHARS}-character ceiling for one call. Pass output_path to write it to a file instead.`
111194
111533
  );
111195
111534
  }
111196
- const answer2 = assembleAnswer(message, unpacked, {
111535
+ const answer3 = assembleAnswer(message, unpacked, {
111197
111536
  maxBodyChars: wholeMessage ? ABSOLUTE_MAX_BODY_CHARS : MAX_BODY_CHARS
111198
111537
  });
111199
111538
  if (destination === void 0) {
111200
- const text7 = answer2.text.length > LARGE_ANSWER_CHARS3 ? `${answer2.text}
111539
+ const text7 = answer3.text.length > LARGE_ANSWER_CHARS3 ? `${answer3.text}
111201
111540
 
111202
- > This answer is ${answer2.text.length} characters. For a message this size, pass output_path next time to write it to a file instead.` : answer2.text;
111541
+ > This answer is ${answer3.text.length} characters. For a message this size, pass output_path next time to write it to a file instead.` : answer3.text;
111203
111542
  return { content: [{ type: "text", text: text7 }], details: void 0 };
111204
111543
  }
111205
- const file = await writeExtraction(destination, answer2.text, {
111544
+ const file = await writeExtraction(destination, answer3.text, {
111206
111545
  cwd: options2.cwd,
111207
111546
  writableRoot: options2.writableRoot
111208
111547
  });
111209
111548
  const summary = extractionSummary(file, {
111210
- covered: `the whole message (${answer2.bodyChars} characters of body, ${message.attachments.length} attachment${message.attachments.length === 1 ? "" : "s"})`,
111211
- excerpt: excerptOf(answer2.text)
111549
+ covered: `the whole message (${answer3.bodyChars} characters of body, ${message.attachments.length} attachment${message.attachments.length === 1 ? "" : "s"})`,
111550
+ excerpt: excerptOf(answer3.text)
111212
111551
  });
111213
111552
  const unpackedText = describeUnpacked(unpacked);
111214
111553
  return {
@@ -125115,7 +125454,7 @@ var textOfRunContent = (element) => {
125115
125454
  return "";
125116
125455
  }
125117
125456
  };
125118
- var textOf = (paragraph2) => {
125457
+ var textOf2 = (paragraph2) => {
125119
125458
  const fields = [];
125120
125459
  const read = (element) => {
125121
125460
  const name = nameOf$3(element);
@@ -125163,7 +125502,7 @@ var paragraphDetailsOf = (paragraphs, followBookmarks) => {
125163
125502
  element,
125164
125503
  styleId: attributeOf(childOf(properties, "w:pStyle"), "w:val"),
125165
125504
  outlineLevel: numberAttributeOf(childOf(properties, "w:outlineLvl"), "w:val"),
125166
- text: textOf(element),
125505
+ text: textOf2(element),
125167
125506
  bookmarks: (_bookmarks$index = bookmarks[index4]) !== null && _bookmarks$index !== void 0 ? _bookmarks$index : /* @__PURE__ */ new Set()
125168
125507
  };
125169
125508
  });
@@ -164595,11 +164934,11 @@ var SECTION_ORDER = [
164595
164934
  "printerSettings",
164596
164935
  "sectPrChange"
164597
164936
  ];
164598
- function textOf2(xml) {
164937
+ function textOf3(xml) {
164599
164938
  return [...xml.matchAll(/<w:t(?:\s[^>]*)?>([^<]*)<\/w:t>/g)].map((match) => match[1]).join("");
164600
164939
  }
164601
164940
  function assertTextUnchanged(part, before, after) {
164602
- if (textOf2(before) !== textOf2(after)) throw new WordTemplateError(`restyling would have changed the text of ${part}; nothing was written`);
164941
+ if (textOf3(before) !== textOf3(after)) throw new WordTemplateError(`restyling would have changed the text of ${part}; nothing was written`);
164603
164942
  }
164604
164943
  function mathSpans(xml) {
164605
164944
  return [...xml.matchAll(/<m:oMath\b[\s\S]*?<\/m:oMath>/g)].map((match) => [match.index, match.index + match[0].length]);
@@ -165852,7 +166191,7 @@ function layoutTimeline(data, today, options2 = {}) {
165852
166191
  else years.push({ label: String(segment4.year), x: band.x, width: band.width });
165853
166192
  });
165854
166193
  const unit = timelineHeaderUnit(px, options2.unit);
165855
- const cut = (starts, label) => starts.map((day, index4) => {
166194
+ const cut2 = (starts, label) => starts.map((day, index4) => {
165856
166195
  const next = index4 + 1 < starts.length ? starts[index4 + 1] : end + 1;
165857
166196
  return { label: label(day), x: xOf(day), width: (next - day) * px };
165858
166197
  });
@@ -165861,7 +166200,7 @@ function layoutTimeline(data, today, options2 = {}) {
165861
166200
  if (unit === "week") {
165862
166201
  const mondays = [];
165863
166202
  for (let day = start - weekday(start) + 7; day <= end; day += 7) mondays.push(day);
165864
- lower = cut([start, ...mondays], (day) => `W${isoWeek(day)}`);
166203
+ lower = cut2([start, ...mondays], (day) => `W${isoWeek(day)}`);
165865
166204
  upper = months.map((month) => ({ label: `${month.label} ${month.year}`, x: month.x, width: month.width }));
165866
166205
  } else if (unit === "quarter") {
165867
166206
  const quarterStarts = segments.filter((segment4, index4) => index4 === 0 || segment4.month % 3 === 0);
@@ -169364,14 +169703,14 @@ function roundedPath(points, radius) {
169364
169703
  if (toPrevious === 0 || toNext === 0) continue;
169365
169704
  const turn = ((corner.x - previous4.x) * (next.y - corner.y) - (corner.y - previous4.y) * (next.x - corner.x)) / (toPrevious * toNext);
169366
169705
  if (Math.abs(turn) < 0.02) continue;
169367
- const cut = Math.min(radius, toPrevious / 2, toNext / 2);
169706
+ const cut2 = Math.min(radius, toPrevious / 2, toNext / 2);
169368
169707
  const entry = {
169369
- x: corner.x - (corner.x - previous4.x) / toPrevious * cut,
169370
- y: corner.y - (corner.y - previous4.y) / toPrevious * cut
169708
+ x: corner.x - (corner.x - previous4.x) / toPrevious * cut2,
169709
+ y: corner.y - (corner.y - previous4.y) / toPrevious * cut2
169371
169710
  };
169372
169711
  const exit3 = {
169373
- x: corner.x + (next.x - corner.x) / toNext * cut,
169374
- y: corner.y + (next.y - corner.y) / toNext * cut
169712
+ x: corner.x + (next.x - corner.x) / toNext * cut2,
169713
+ y: corner.y + (next.y - corner.y) / toNext * cut2
169375
169714
  };
169376
169715
  parts.push(`L ${entry.x} ${entry.y}`, `Q ${corner.x} ${corner.y} ${exit3.x} ${exit3.y}`);
169377
169716
  }
@@ -177996,130 +178335,6 @@ var checkStructuredExchangeSchema = (document4) => {
177996
178335
  return [...misplacedEnvelopeIssues(document4), ...issues.sort((left, right) => right.path.split("/").length - left.path.split("/").length)];
177997
178336
  };
177998
178337
 
177999
- // ../shared/src/structuredExchangeProfile.ts
178000
- var STRUCTURED_EXCHANGE_PROFILE_REGISTRY_SCHEMA_V2 = "urn:structured-exchange-profile-registry:2";
178001
- var STRUCTURED_EXCHANGE_PROFILE_REGISTRY_PATH = ".pi-outpost/structured-exchange.json";
178002
- var STRUCTURED_EXCHANGE_CONFORMITY_REPORT_PROFILE = "urn:structured-exchange-conformity-report:1";
178003
- var STRUCTURED_EXCHANGE_RULES_REGISTER_PROFILE = "urn:structured-exchange-rules-register:1";
178004
- var STRUCTURED_EXCHANGE_RULE_PATTERNS_PROFILE = "urn:structured-exchange-rule-patterns:1";
178005
- var RESERVED_PROFILE_IDENTIFIERS = /* @__PURE__ */ new Set([
178006
- STRUCTURED_EXCHANGE_CONFORMITY_REPORT_PROFILE,
178007
- STRUCTURED_EXCHANGE_RULES_REGISTER_PROFILE,
178008
- STRUCTURED_EXCHANGE_RULE_PATTERNS_PROFILE
178009
- ]);
178010
- var STRUCTURED_EXCHANGE_PROFILE_CEILINGS = {
178011
- /** A profile's identifier, bounded like the `profile` a document names it by. */
178012
- id: 200,
178013
- label: 500,
178014
- description: 2e3,
178015
- /** Kinds per vocabulary, as a document's `kindsPerVocabulary`. */
178016
- kindsPerVocabulary: 64,
178017
- /** Attributes one kind declares, as a document's `attributesPerItem`. */
178018
- attributesPerKind: 50,
178019
- attributeName: 200,
178020
- /**
178021
- * Values one enumeration lists. Generous: a requirements tool's enumerations
178022
- * include long ones — components, suppliers — and a profile that cannot hold its
178023
- * model's is a profile nobody can finish.
178024
- */
178025
- enumerationValues: 500,
178026
- /** One enumeration value, as a document's `attributeString`. */
178027
- enumerationValue: 1e3,
178028
- viewpoints: 20,
178029
- /** Profiles one registry lists. */
178030
- profilesPerRegistry: 20,
178031
- profilePath: 500,
178032
- /** Bytes read from a profile file before it is parsed. */
178033
- profileBytes: 1048576,
178034
- /** Bytes read from a registry file before it is parsed. */
178035
- registryBytes: 65536
178036
- };
178037
- function profileListing(profile) {
178038
- const lines = [`Profile ${profile.id} \u2014 ${profile.label}`];
178039
- if (profile.description !== void 0) lines.push(profile.description);
178040
- const vocabulary = (heading3, kinds, relationships) => {
178041
- const declared = kinds ?? [];
178042
- lines.push("", `${heading3}: ${declared.length}`);
178043
- for (const declaration of declared) {
178044
- lines.push(` ${declaration.kind}`);
178045
- if (declaration.description !== void 0) lines.push(` ${declaration.description}`);
178046
- if (relationships) {
178047
- lines.push(` source: ${declaration.from?.join(", ") ?? "any element kind"}`);
178048
- lines.push(` target: ${declaration.to?.join(", ") ?? "any element kind"}`);
178049
- }
178050
- const attributes2 = declaration.attributes ?? [];
178051
- if (attributes2.length === 0) lines.push(" (no attributes)");
178052
- for (const attribute of attributes2) {
178053
- const traits = [
178054
- attribute.list === true ? `list of ${attribute.type}` : attribute.type,
178055
- ...attribute.type === "enumeration" ? [attribute.closed === true ? "closed" : "open"] : [],
178056
- attribute.required === true ? "required" : "optional"
178057
- ];
178058
- const count = attribute.type === "enumeration" ? ` \u2014 ${(attribute.values ?? []).length} values` : "";
178059
- lines.push(` ${attribute.name}: ${traits.join(", ")}${count}`);
178060
- if (attribute.description !== void 0) lines.push(` ${attribute.description}`);
178061
- for (const value of attribute.values ?? []) lines.push(` - ${value}`);
178062
- }
178063
- }
178064
- };
178065
- vocabulary("Element kinds (graph elements and table rows)", profile.elementKinds, false);
178066
- vocabulary("Relationship kinds (graph relationships and table relations)", profile.relationshipKinds, true);
178067
- const viewpoints = profile.viewpoints ?? [];
178068
- lines.push("", `Viewpoints: ${viewpoints.length}`);
178069
- for (const viewpoint of viewpoints) {
178070
- lines.push(` ${viewpoint.id} \u2014 ${viewpoint.label}: ${viewpoint.concern}`);
178071
- if (viewpoint.elementKinds !== void 0) lines.push(` element kinds: ${viewpoint.elementKinds.join(", ")}`);
178072
- if (viewpoint.relationshipKinds !== void 0) lines.push(` relationship kinds: ${viewpoint.relationshipKinds.join(", ")}`);
178073
- }
178074
- return `${lines.join("\n")}
178075
- `;
178076
- }
178077
- function describeConditions(set) {
178078
- return Object.entries(set ?? {}).map(([name, values]) => `${name} \u2208 {${values.map((value) => JSON.stringify(value)).join(", ")}}`).join(" and ") || "always";
178079
- }
178080
- function describeLinkConditions(set) {
178081
- const parts = [
178082
- set?.from === void 0 ? void 0 : `source ${describeConditions(set.from)}`,
178083
- set?.to === void 0 ? void 0 : `target ${describeConditions(set.to)}`
178084
- ].filter((part) => part !== void 0);
178085
- return parts.length === 0 ? "always" : parts.join(" and ");
178086
- }
178087
- function rulesListing(profileId, rules) {
178088
- const conditions = describeConditions;
178089
- const ends = describeLinkConditions;
178090
- const lines = [`Rules for ${profileId}: ${rules.length}`];
178091
- for (const rule of rules) {
178092
- lines.push("", ` ${rule.id} \u2014 ${rule.level}${rule.source === void 0 ? "" : ` \u2014 ${rule.source}`}`, ` ${rule.statement}`);
178093
- if (rule.element !== void 0) {
178094
- lines.push(` applies to: element ${rule.element}`, ` when: ${conditions(rule.when)}`);
178095
- lines.push(` then: ${rule.then === "forbidden" ? "forbidden" : conditions(rule.then)}`);
178096
- } else {
178097
- lines.push(` applies to: relationship ${rule.relationship}`, ` when: ${ends(rule.when)}`);
178098
- lines.push(` then: ${rule.then === "forbidden" ? "forbidden" : ends(rule.then)}`);
178099
- }
178100
- }
178101
- return `${lines.join("\n")}
178102
- `;
178103
- }
178104
- var STRUCTURED_EXCHANGE_RULES_CEILINGS = {
178105
- rulesPerFile: 200,
178106
- ruleId: 200,
178107
- statement: 2e3,
178108
- source: 500,
178109
- /** Conditions in one set — `when`, `then`, or one end of a link. */
178110
- conditionsPerSet: 20,
178111
- /** Values one condition allows, as `enumerationValues`. */
178112
- valuesPerCondition: 500,
178113
- /** One value, as `enumerationValue`. */
178114
- value: 1e3,
178115
- attributeName: 200,
178116
- kind: 100,
178117
- /** Rules files one registry lists. */
178118
- rulesFilesPerRegistry: 20,
178119
- /** Bytes read from a rules file before it is parsed. */
178120
- rulesBytes: 1048576
178121
- };
178122
-
178123
178338
  // ../shared/src/structuredExchangeDocumentItems.ts
178124
178339
  function effective(raw, path25) {
178125
178340
  const set = raw.set ?? void 0;
@@ -181620,7 +181835,7 @@ var DESCRIPTION10 = [
181620
181835
  "Reading a poster shows each picture the user put in as a marker, poster-picture:N, and neither the marker nor its frame's name tells you what the picture shows.",
181621
181836
  "Call this before describing, captioning, choosing or moving a picture: it answers each picture as an image after its marker."
181622
181837
  ].join(" ");
181623
- var answer = (content3, isError = false) => ({ content: content3, details: void 0, ...isError ? { isError: true } : {} });
181838
+ var answer2 = (content3, isError = false) => ({ content: content3, details: void 0, ...isError ? { isError: true } : {} });
181624
181839
  function createPosterPicturesToolDefinition(options2) {
181625
181840
  return {
181626
181841
  name: "poster_pictures",
@@ -181633,25 +181848,25 @@ function createPosterPicturesToolDefinition(options2) {
181633
181848
  parameters: parameters10,
181634
181849
  async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
181635
181850
  const { path: target, pictures: wanted } = params;
181636
- if (!target.toLowerCase().endsWith(POSTER_SUFFIX)) return answer([{ type: "text", text: `"${target}" is not a poster: give a ${POSTER_SUFFIX} file.` }], true);
181851
+ if (!target.toLowerCase().endsWith(POSTER_SUFFIX)) return answer2([{ type: "text", text: `"${target}" is not a poster: give a ${POSTER_SUFFIX} file.` }], true);
181637
181852
  const resolved2 = await realResolve(path19.resolve(options2.cwd, target));
181638
181853
  if (!isWithinAny(options2.allowedRoots, resolved2)) {
181639
181854
  throw new Error(`Access denied: "${target}" is outside the sandbox (${options2.allowedRoots[0]})`);
181640
181855
  }
181641
181856
  const stat = await fs15.stat(resolved2).catch(() => null);
181642
- if (stat === null || !stat.isFile()) return answer([{ type: "text", text: `No such file: ${target}` }], true);
181643
- if (stat.size > MAX_POSTER_BYTES + 64 * 1024) return answer([{ type: "text", text: `"${target}" is larger than a poster may be.` }], true);
181857
+ if (stat === null || !stat.isFile()) return answer2([{ type: "text", text: `No such file: ${target}` }], true);
181858
+ if (stat.size > MAX_POSTER_BYTES + 64 * 1024) return answer2([{ type: "text", text: `"${target}" is larger than a poster may be.` }], true);
181644
181859
  const text7 = await fs15.readFile(resolved2, "utf8");
181645
181860
  try {
181646
181861
  readPage(text7);
181647
181862
  } catch (error) {
181648
- if (error instanceof PosterRefusal) return answer([{ type: "text", text: `"${target}" cannot be looked at: ${error.message}. Run poster_check on it.` }], true);
181863
+ if (error instanceof PosterRefusal) return answer2([{ type: "text", text: `"${target}" cannot be looked at: ${error.message}. Run poster_check on it.` }], true);
181649
181864
  throw error;
181650
181865
  }
181651
181866
  const { pictures } = hidePictures(text7, "");
181652
- if (pictures.length === 0) return answer([{ type: "text", text: `"${target}" holds no picture: its frames, if any, are empty.` }]);
181867
+ if (pictures.length === 0) return answer2([{ type: "text", text: `"${target}" holds no picture: its frames, if any, are empty.` }]);
181653
181868
  if (ctx?.model && !ctx.model.input.includes("image")) {
181654
- return answer([{ type: "text", text: `"${target}" holds ${pictures.length} picture(s), but the model in use (${ctx.model.id}) does not take images, so they cannot be shown. Do not guess what they show from their frames' names; ask the user.` }], true);
181869
+ return answer2([{ type: "text", text: `"${target}" holds ${pictures.length} picture(s), but the model in use (${ctx.model.id}) does not take images, so they cannot be shown. Do not guess what they show from their frames' names; ask the user.` }], true);
181655
181870
  }
181656
181871
  const numbers2 = (wanted?.length ? wanted : pictures.map((_picture, index4) => index4 + 1)).slice(0, MAX_SEEN_PICTURES);
181657
181872
  const content3 = [{ type: "text", text: `"${target}" holds ${pictures.length} picture(s); shown here: ${numbers2.map((n) => `poster-picture:${n}`).join(", ")}.` }];
@@ -181670,7 +181885,7 @@ function createPosterPicturesToolDefinition(options2) {
181670
181885
  }
181671
181886
  const unseen = (wanted?.length ? wanted.length : pictures.length) - numbers2.length;
181672
181887
  if (unseen > 0) content3.push({ type: "text", text: `${unseen} more picture(s) not shown: ask for them by number.` });
181673
- return answer(content3);
181888
+ return answer2(content3);
181674
181889
  }
181675
181890
  };
181676
181891
  }
@@ -181947,7 +182162,7 @@ var parameters12 = typebox_exports.Object({
181947
182162
  images: imagesParameter
181948
182163
  });
181949
182164
  var DESCRIPTION12 = [
181950
- "Extract a Word (.docx) document as markdown: paragraphs, headings, and tables with the rows and columns the document declares.",
182165
+ "Read a Word document (.docx): extract its text, headings and tables as Markdown, preserving the rows and columns the Word document declares.",
181951
182166
  "If the user wants the document saved, converted, or written anywhere, pass output_path: it writes the whole document there in one call and returns a short summary.",
181952
182167
  "Do not return the content and then write it yourself \u2014 that spends the context twice.",
181953
182168
  "Otherwise output is capped per call \u2014 when it is truncated it says so and names the block range to ask for next, or pass full:true to get everything at once.",
@@ -182935,8 +183150,14 @@ async function createPiOutpostTools(settings2) {
182935
183150
  }
182936
183151
  async function piOutpostTools_default(pi) {
182937
183152
  const tools = await createPiOutpostTools(parseToolsSettings(process.env[TOOLS_ENV_VAR]));
182938
- for (const tool of tools) pi.registerTool(tool);
183153
+ for (const tool of deferOnDemandTools(tools)) pi.registerTool(tool);
183154
+ pi.on("session_start", () => {
183155
+ const active = pi.getActiveTools();
183156
+ if (active.includes(TOOL_SEARCH_TOOL) || !pi.getAllTools().some((tool) => tool.name === TOOL_SEARCH_TOOL)) return;
183157
+ pi.setActiveTools([...active, TOOL_SEARCH_TOOL]);
183158
+ });
182939
183159
  registerPosterPictureHooks(pi);
183160
+ createBtwExtension()(pi);
182940
183161
  }
182941
183162
  export {
182942
183163
  TOOLS_ENV_VAR,