onbuzz 4.9.13 → 4.10.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 (451) hide show
  1. package/node_modules/glob/README.md +31 -5
  2. package/node_modules/glob/dist/commonjs/glob.d.ts +8 -0
  3. package/node_modules/glob/dist/commonjs/glob.d.ts.map +1 -1
  4. package/node_modules/glob/dist/commonjs/glob.js +2 -1
  5. package/node_modules/glob/dist/commonjs/glob.js.map +1 -1
  6. package/node_modules/glob/dist/commonjs/index.min.js +3 -3
  7. package/node_modules/glob/dist/commonjs/index.min.js.map +4 -4
  8. package/node_modules/glob/dist/commonjs/pattern.d.ts +3 -0
  9. package/node_modules/glob/dist/commonjs/pattern.d.ts.map +1 -1
  10. package/node_modules/glob/dist/commonjs/pattern.js +4 -0
  11. package/node_modules/glob/dist/commonjs/pattern.js.map +1 -1
  12. package/node_modules/glob/dist/esm/glob.d.ts +8 -0
  13. package/node_modules/glob/dist/esm/glob.d.ts.map +1 -1
  14. package/node_modules/glob/dist/esm/glob.js +2 -1
  15. package/node_modules/glob/dist/esm/glob.js.map +1 -1
  16. package/node_modules/glob/dist/esm/index.min.js +3 -3
  17. package/node_modules/glob/dist/esm/index.min.js.map +4 -4
  18. package/node_modules/glob/dist/esm/pattern.d.ts +3 -0
  19. package/node_modules/glob/dist/esm/pattern.d.ts.map +1 -1
  20. package/node_modules/glob/dist/esm/pattern.js +4 -0
  21. package/node_modules/glob/dist/esm/pattern.js.map +1 -1
  22. package/node_modules/{@isaacs → glob/node_modules}/balanced-match/README.md +7 -10
  23. package/node_modules/{@isaacs → glob/node_modules}/balanced-match/package.json +7 -18
  24. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/README.md +3 -6
  25. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.js +6 -4
  26. package/node_modules/glob/node_modules/brace-expansion/dist/commonjs/index.js.map +1 -0
  27. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.js +6 -4
  28. package/node_modules/glob/node_modules/brace-expansion/dist/esm/index.js.map +1 -0
  29. package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/package.json +11 -7
  30. package/node_modules/glob/node_modules/minimatch/README.md +76 -1
  31. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts +1 -1
  32. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.d.ts.map +1 -1
  33. package/node_modules/glob/node_modules/minimatch/dist/commonjs/assert-valid-pattern.js.map +1 -1
  34. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts +4 -2
  35. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.d.ts.map +1 -1
  36. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js +309 -55
  37. package/node_modules/glob/node_modules/minimatch/dist/commonjs/ast.js.map +1 -1
  38. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.d.ts.map +1 -1
  39. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js +2 -4
  40. package/node_modules/glob/node_modules/minimatch/dist/commonjs/brace-expressions.js.map +1 -1
  41. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts +1 -1
  42. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.d.ts.map +1 -1
  43. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js +4 -4
  44. package/node_modules/glob/node_modules/minimatch/dist/commonjs/escape.js.map +1 -1
  45. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts +81 -1
  46. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.d.ts.map +1 -1
  47. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js +232 -134
  48. package/node_modules/glob/node_modules/minimatch/dist/commonjs/index.js.map +1 -1
  49. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts +1 -1
  50. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.d.ts.map +1 -1
  51. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js +8 -8
  52. package/node_modules/glob/node_modules/minimatch/dist/commonjs/unescape.js.map +1 -1
  53. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts +1 -1
  54. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.d.ts.map +1 -1
  55. package/node_modules/glob/node_modules/minimatch/dist/esm/assert-valid-pattern.js.map +1 -1
  56. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts +4 -2
  57. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.d.ts.map +1 -1
  58. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js +309 -55
  59. package/node_modules/glob/node_modules/minimatch/dist/esm/ast.js.map +1 -1
  60. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.d.ts.map +1 -1
  61. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js +2 -4
  62. package/node_modules/glob/node_modules/minimatch/dist/esm/brace-expressions.js.map +1 -1
  63. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts +1 -1
  64. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.d.ts.map +1 -1
  65. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js +4 -4
  66. package/node_modules/glob/node_modules/minimatch/dist/esm/escape.js.map +1 -1
  67. package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts +81 -1
  68. package/node_modules/glob/node_modules/minimatch/dist/esm/index.d.ts.map +1 -1
  69. package/node_modules/glob/node_modules/minimatch/dist/esm/index.js +232 -134
  70. package/node_modules/glob/node_modules/minimatch/dist/esm/index.js.map +1 -1
  71. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts +1 -1
  72. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.d.ts.map +1 -1
  73. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js +8 -8
  74. package/node_modules/glob/node_modules/minimatch/dist/esm/unescape.js.map +1 -1
  75. package/node_modules/glob/node_modules/minimatch/package.json +17 -11
  76. package/node_modules/glob/package.json +10 -13
  77. package/node_modules/minipass/LICENSE.md +55 -0
  78. package/node_modules/minipass/dist/commonjs/index.d.ts +12 -16
  79. package/node_modules/minipass/dist/commonjs/index.d.ts.map +1 -1
  80. package/node_modules/minipass/dist/commonjs/index.js +13 -3
  81. package/node_modules/minipass/dist/commonjs/index.js.map +1 -1
  82. package/node_modules/minipass/dist/esm/index.d.ts +12 -16
  83. package/node_modules/minipass/dist/esm/index.d.ts.map +1 -1
  84. package/node_modules/minipass/dist/esm/index.js +3 -1
  85. package/node_modules/minipass/dist/esm/index.js.map +1 -1
  86. package/node_modules/minipass/package.json +9 -14
  87. package/node_modules/path-scurry/node_modules/lru-cache/README.md +96 -10
  88. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.d.ts.map +1 -0
  89. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel-browser.js.map +1 -0
  90. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.d.ts +5 -0
  91. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/diagnostics-channel.js +7 -0
  92. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts +1400 -0
  93. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.d.ts.map +1 -0
  94. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js +1726 -0
  95. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.js.map +1 -0
  96. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js +2 -0
  97. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/index.min.js.map +7 -0
  98. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts +12 -0
  99. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.d.ts.map +1 -0
  100. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js +10 -0
  101. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/browser/perf.js.map +1 -0
  102. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.cjs.map +1 -0
  103. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel-cjs.d.cts.map +1 -0
  104. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.d.ts +5 -0
  105. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/diagnostics-channel.js +7 -0
  106. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts +109 -32
  107. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.d.ts.map +1 -1
  108. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js +334 -197
  109. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.js.map +1 -1
  110. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js +1 -1
  111. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/index.min.js.map +4 -4
  112. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.d.ts.map +1 -0
  113. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel-node.js.map +1 -0
  114. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.d.ts +5 -0
  115. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/diagnostics-channel.js +9 -0
  116. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts +1400 -0
  117. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.d.ts.map +1 -0
  118. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js +1726 -0
  119. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.js.map +1 -0
  120. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js +2 -0
  121. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/index.min.js.map +7 -0
  122. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts +12 -0
  123. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.d.ts.map +1 -0
  124. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js +10 -0
  125. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/node/perf.js.map +1 -0
  126. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts +12 -0
  127. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.d.ts.map +1 -0
  128. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js +10 -0
  129. package/node_modules/path-scurry/node_modules/lru-cache/dist/commonjs/perf.js.map +1 -0
  130. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.d.ts.map +1 -0
  131. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel-browser.js.map +1 -0
  132. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.d.ts +5 -0
  133. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/diagnostics-channel.js +4 -0
  134. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts +1400 -0
  135. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.d.ts.map +1 -0
  136. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js +1722 -0
  137. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.js.map +1 -0
  138. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js +2 -0
  139. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/index.min.js.map +7 -0
  140. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts +12 -0
  141. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.d.ts.map +1 -0
  142. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js +7 -0
  143. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/browser/perf.js.map +1 -0
  144. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.d.mts.map +1 -0
  145. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel-esm.mjs.map +1 -0
  146. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.d.ts +5 -0
  147. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/diagnostics-channel.js +19 -0
  148. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts +109 -32
  149. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.d.ts.map +1 -1
  150. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js +333 -196
  151. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.js.map +1 -1
  152. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js +1 -1
  153. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/index.min.js.map +4 -4
  154. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.d.ts.map +1 -0
  155. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel-node.js.map +1 -0
  156. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.d.ts +5 -0
  157. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/diagnostics-channel.js +6 -0
  158. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts +1400 -0
  159. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.d.ts.map +1 -0
  160. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js +1722 -0
  161. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.js.map +1 -0
  162. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js +2 -0
  163. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/index.min.js.map +7 -0
  164. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts +12 -0
  165. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.d.ts.map +1 -0
  166. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js +7 -0
  167. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/node/perf.js.map +1 -0
  168. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts +12 -0
  169. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.d.ts.map +1 -0
  170. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js +7 -0
  171. package/node_modules/path-scurry/node_modules/lru-cache/dist/esm/perf.js.map +1 -0
  172. package/node_modules/path-scurry/node_modules/lru-cache/package.json +71 -18
  173. package/node_modules/path-scurry/package.json +8 -24
  174. package/package.json +1 -1
  175. package/scripts/debug-balance-probe.mjs +35 -35
  176. package/scripts/push-image.sh +43 -43
  177. package/scripts/setup-acr.sh +65 -65
  178. package/scripts/verify-optional-deps.js +96 -1
  179. package/src/__tests__/composioCliFlags.test.js +239 -239
  180. package/src/analyzers/CSSAnalyzer.js +298 -297
  181. package/src/analyzers/ConfigValidator.js +691 -690
  182. package/src/analyzers/ESLintAnalyzer.js +320 -320
  183. package/src/analyzers/JavaScriptAnalyzer.js +260 -261
  184. package/src/analyzers/PrettierFormatter.js +246 -247
  185. package/src/analyzers/PythonAnalyzer.js +283 -283
  186. package/src/analyzers/SecurityAnalyzer.js +729 -729
  187. package/src/analyzers/SparrowAnalyzer.js +341 -341
  188. package/src/analyzers/TypeScriptAnalyzer.js +247 -247
  189. package/src/analyzers/__tests__/CSSAnalyzer.test.js +41 -41
  190. package/src/analyzers/__tests__/ConfigValidator.test.js +362 -362
  191. package/src/analyzers/__tests__/JavaScriptAnalyzer.test.js +40 -40
  192. package/src/analyzers/__tests__/PythonAnalyzer.test.js +205 -208
  193. package/src/analyzers/__tests__/SecurityAnalyzer.test.js +303 -303
  194. package/src/analyzers/__tests__/TypeScriptAnalyzer.test.js +187 -187
  195. package/src/analyzers/codeCloneDetector/analyzer.js +344 -344
  196. package/src/analyzers/codeCloneDetector/detector.js +250 -250
  197. package/src/analyzers/codeCloneDetector/index.js +194 -192
  198. package/src/analyzers/codeCloneDetector/parser.js +199 -199
  199. package/src/core/__tests__/agentPool.test.js +866 -866
  200. package/src/core/__tests__/agentPoolAutoResume.test.js +209 -209
  201. package/src/core/__tests__/agentPoolWakeOnMessage.test.js +315 -315
  202. package/src/core/__tests__/agentScheduler.emptyResponseChatStall.test.js +213 -213
  203. package/src/core/__tests__/agentScheduler.errorCategorisation.test.js +246 -246
  204. package/src/core/__tests__/agentScheduler.firstChunkTimeout.test.js +138 -138
  205. package/src/core/__tests__/agentScheduler.modeTransitions.test.js +233 -233
  206. package/src/core/__tests__/agentScheduler.nativePromptPick.test.js +319 -319
  207. package/src/core/__tests__/agentScheduler.taskLifecycleInstruction.test.js +78 -78
  208. package/src/core/__tests__/agentScheduler.visualizer.test.js +258 -258
  209. package/src/core/__tests__/flowCheckpointStore.test.js +140 -140
  210. package/src/core/__tests__/flowEndToEnd.test.js +565 -565
  211. package/src/core/__tests__/flowFieldMapping.test.js +188 -189
  212. package/src/core/__tests__/flowLintClientMirror.test.js +96 -98
  213. package/src/core/__tests__/flowSavePayload.test.js +170 -169
  214. package/src/core/__tests__/flowTemplates.test.js +311 -311
  215. package/src/core/__tests__/flowVersionStore.test.js +123 -123
  216. package/src/core/__tests__/messageProcessor.test.js +669 -669
  217. package/src/core/__tests__/stateManager.test.js +0 -1
  218. package/src/core/agentPool.js +2474 -2475
  219. package/src/core/agentScheduler.js +1 -4
  220. package/src/core/contextManager.js +708 -708
  221. package/src/core/flowExecutor.js +1510 -1510
  222. package/src/core/flowFieldMapping.js +136 -138
  223. package/src/core/messageProcessor.js +953 -954
  224. package/src/core/orchestrator.js +593 -595
  225. package/src/core/stateManager.js +1765 -1752
  226. package/src/index.js +1221 -1221
  227. package/src/interfaces/__tests__/archivedAgentDelete.test.js +207 -207
  228. package/src/interfaces/__tests__/bulkAgentRoute.test.js +361 -361
  229. package/src/interfaces/__tests__/imageServing.test.js +228 -228
  230. package/src/interfaces/__tests__/remoteSessionAuth.test.js +308 -308
  231. package/src/interfaces/__tests__/videoJobsRoutes.test.js +178 -179
  232. package/src/interfaces/__tests__/webServer.marketplace.test.js +629 -629
  233. package/src/interfaces/schedulerRoutes.js +50 -50
  234. package/src/interfaces/terminal/__tests__/smoke/connection.test.js +341 -350
  235. package/src/interfaces/terminal/__tests__/smoke/enhancements.test.js +156 -156
  236. package/src/interfaces/terminal/__tests__/smoke/imports.test.js +325 -330
  237. package/src/interfaces/terminal/__tests__/smoke/tools.test.js +385 -388
  238. package/src/interfaces/terminal/api/session.js +265 -266
  239. package/src/interfaces/terminal/api/websocket.js +496 -497
  240. package/src/interfaces/terminal/components/AgentCreator.js +691 -705
  241. package/src/interfaces/terminal/components/AgentEditor.js +676 -678
  242. package/src/interfaces/terminal/components/AgentSwitcher.js +331 -330
  243. package/src/interfaces/terminal/components/ErrorPanel.js +263 -264
  244. package/src/interfaces/terminal/components/Header.js +28 -28
  245. package/src/interfaces/terminal/components/Layout.js +598 -603
  246. package/src/interfaces/terminal/components/MessageList.js +280 -281
  247. package/src/interfaces/terminal/components/SettingsPanel.js +410 -415
  248. package/src/interfaces/terminal/components/StatusBar.js +2 -0
  249. package/src/interfaces/terminal/index.js +168 -168
  250. package/src/interfaces/terminal/state/useAgentControl.js +496 -496
  251. package/src/interfaces/terminal/state/useAgents.js +537 -537
  252. package/src/interfaces/terminal/state/useMessages.js +629 -630
  253. package/src/interfaces/terminal/state/useTools.js +554 -554
  254. package/src/interfaces/terminal/utils/debugLogger.js +44 -44
  255. package/src/interfaces/terminal/utils/settingsStorage.js +232 -232
  256. package/src/interfaces/webServer.js +7578 -7579
  257. package/src/interfaces/webServer.js.bak +7046 -7046
  258. package/src/modules/fileExplorer/__tests__/zipDownload.test.js +237 -237
  259. package/src/modules/fileExplorer/controller.js +470 -469
  260. package/src/modules/fileExplorer/routes.js +285 -286
  261. package/src/modules/widget/__tests__/isDisabled.test.js +41 -41
  262. package/src/modules/widget/__tests__/routes.test.js +677 -678
  263. package/src/modules/widget/__tests__/runtime.test.js +401 -401
  264. package/src/modules/widget/__tests__/versioning.test.js +309 -309
  265. package/src/modules/widget/__tests__/webComponentRuntime.test.js +565 -565
  266. package/src/modules/widget/__tests__/widgetTool.test.js +316 -316
  267. package/src/modules/widget/routes.js +435 -435
  268. package/src/modules/widget/runtime/bundle.js +640 -640
  269. package/src/modules/widget/runtime/webComponentBundle.js +470 -470
  270. package/src/modules/widget/schema.js +182 -181
  271. package/src/modules/widget/widgetTool.js +1389 -1389
  272. package/src/services/__tests__/agentActivityService.test.js +401 -402
  273. package/src/services/__tests__/benchmarkService.test.js +184 -184
  274. package/src/services/__tests__/contextInjectionService.test.js +246 -246
  275. package/src/services/__tests__/conversationQuery.test.js +721 -723
  276. package/src/services/__tests__/credentialVault.test.js +469 -469
  277. package/src/services/__tests__/discordService.integration.test.js +638 -639
  278. package/src/services/__tests__/flowContextService.test.js +590 -590
  279. package/src/services/__tests__/memoryService.test.js +1 -1
  280. package/src/services/__tests__/messageSource.test.js +380 -380
  281. package/src/services/__tests__/modelRouterNaming.test.js +111 -111
  282. package/src/services/__tests__/projectDetector.test.js +34 -34
  283. package/src/services/__tests__/promptService.test.js +242 -242
  284. package/src/services/__tests__/telegramService.test.js +941 -941
  285. package/src/services/__tests__/tokenCountingService.test.js +48 -48
  286. package/src/services/agentActivityService.js +419 -420
  287. package/src/services/aiService.js +2997 -3001
  288. package/src/services/apiKeyManager.js +359 -359
  289. package/src/services/benchmarkService.js +196 -196
  290. package/src/services/codebaseKnowledgeService.js +2 -2
  291. package/src/services/composioService.js +738 -738
  292. package/src/services/conversationCompactionService.js +1258 -1257
  293. package/src/services/credentialVault.js +685 -685
  294. package/src/services/discordService.js +792 -793
  295. package/src/services/embeddings/__tests__/azureCustomProvider.test.js +232 -232
  296. package/src/services/embeddings/__tests__/embeddingService.test.js +417 -417
  297. package/src/services/embeddings/__tests__/localProvider.test.js +263 -263
  298. package/src/services/embeddings/autoRecall.js +218 -219
  299. package/src/services/embeddings/indexers/__tests__/agentIndexer.test.js +232 -232
  300. package/src/services/embeddings/indexers/__tests__/memoryIndexer.test.js +418 -418
  301. package/src/services/embeddings/indexers/__tests__/reminisceIndexer.test.js +356 -357
  302. package/src/services/embeddings/indexers/__tests__/skillsIndexer.test.js +145 -145
  303. package/src/services/embeddings/indexers/__tests__/taskIndexer.test.js +146 -146
  304. package/src/services/embeddings/indexers/composioIndexer.js +279 -279
  305. package/src/services/embeddings/providerInterface.js +206 -206
  306. package/src/services/embeddings/providers/localProvider.js +11 -7
  307. package/src/services/embeddings/providers/openaiProvider.js +101 -101
  308. package/src/services/embeddings/vectorStore/inMemoryJsonStore.js +356 -356
  309. package/src/services/errorHandler.js +809 -809
  310. package/src/services/flowContextService.js +586 -586
  311. package/src/services/grounding/MockAdapter.js +125 -125
  312. package/src/services/modelRouterService.js +26 -31
  313. package/src/services/modelsService.js +322 -322
  314. package/src/services/ollamaService.js +452 -452
  315. package/src/services/projectDetector.js +403 -404
  316. package/src/services/promptService.js +418 -418
  317. package/src/services/qualityInspector.js +795 -795
  318. package/src/services/scheduleService.js +726 -726
  319. package/src/services/serviceRegistry.js +386 -386
  320. package/src/services/telegrafBot.js +174 -174
  321. package/src/services/telegramService.js +1972 -1972
  322. package/src/services/visualEditorBridge.js +1033 -1033
  323. package/src/services/visualEditorServer.js +1769 -1774
  324. package/src/services/whatsappService.js +667 -668
  325. package/src/tools/__tests__/agentCommunicationTool.findAgent.test.js +226 -226
  326. package/src/tools/__tests__/agentCommunicationTool.test.js +3 -3
  327. package/src/tools/__tests__/agentDelayTool.test.js +342 -342
  328. package/src/tools/__tests__/baseTool.test.js +3 -3
  329. package/src/tools/__tests__/codeMapTool.test.js +915 -915
  330. package/src/tools/__tests__/fileContentReplaceTool.test.js +309 -309
  331. package/src/tools/__tests__/fileTreeTool.test.js +274 -274
  332. package/src/tools/__tests__/filesystemTool.test.js +815 -815
  333. package/src/tools/__tests__/foundryWebSearchTool.test.js +252 -252
  334. package/src/tools/__tests__/imageTool.validator.test.js +194 -194
  335. package/src/tools/__tests__/jobDoneTool.test.js +580 -581
  336. package/src/tools/__tests__/memoryTool.forgetStale.test.js +272 -272
  337. package/src/tools/__tests__/memoryTool.reminisce.test.js +2 -2
  338. package/src/tools/__tests__/memoryTool.reminisceSemanticSearch.test.js +301 -301
  339. package/src/tools/__tests__/memoryTool.semanticSearch.test.js +405 -405
  340. package/src/tools/__tests__/memoryTool.teamPool.test.js +293 -293
  341. package/src/tools/__tests__/memoryTool.test.js +1 -1
  342. package/src/tools/__tests__/seekTool.test.js +282 -282
  343. package/src/tools/__tests__/skillsTool.search.test.js +164 -164
  344. package/src/tools/__tests__/skillsTool.test.js +226 -226
  345. package/src/tools/__tests__/staticAnalysisTool.test.js +509 -509
  346. package/src/tools/__tests__/taskManagerTool.discipline.test.js +137 -137
  347. package/src/tools/__tests__/taskManagerTool.search.test.js +143 -143
  348. package/src/tools/__tests__/taskManagerTool.test.js +866 -866
  349. package/src/tools/__tests__/terminalTool.test.js +448 -448
  350. package/src/tools/__tests__/toolShapeForgiveness.test.js +259 -260
  351. package/src/tools/__tests__/userPromptTool.test.js +297 -297
  352. package/src/tools/__tests__/videoTool.jobs.test.js +147 -147
  353. package/src/tools/__tests__/webTool.e2e.test.js +609 -603
  354. package/src/tools/__tests__/webTool.unit.test.js +195 -195
  355. package/src/tools/__tests__/webTool.visionModel.test.js +75 -75
  356. package/src/tools/agentCommunicationTool.js +8 -10
  357. package/src/tools/agentDelayTool.js +496 -497
  358. package/src/tools/asyncToolManager.js +602 -603
  359. package/src/tools/baseTool.js +12 -11
  360. package/src/tools/cloneDetectionTool.js +576 -581
  361. package/src/tools/codeMapTool.js +0 -6
  362. package/src/tools/composioTool.js +617 -617
  363. package/src/tools/dependencyResolverTool.js +1211 -1212
  364. package/src/tools/desktop/DesktopTool.js +629 -638
  365. package/src/tools/desktop/__tests__/DesktopTool.e2e.test.js +306 -306
  366. package/src/tools/desktop/__tests__/DesktopTool.test.js +507 -507
  367. package/src/tools/desktop/__tests__/osController.test.js +364 -364
  368. package/src/tools/desktop/osController.js +491 -491
  369. package/src/tools/docxTool.js +623 -623
  370. package/src/tools/excelTool.js +636 -636
  371. package/src/tools/fileContentReplaceTool.js +5 -7
  372. package/src/tools/fileSystemTool.js +12 -19
  373. package/src/tools/fileTreeTool.js +840 -840
  374. package/src/tools/foundryWebSearchTool.js +273 -273
  375. package/src/tools/helpTool.js +198 -198
  376. package/src/tools/imageTool.js +1397 -1397
  377. package/src/tools/importAnalyzerTool.js +1056 -1056
  378. package/src/tools/jobDoneTool.js +495 -495
  379. package/src/tools/memoryTool.js +1 -1
  380. package/src/tools/office/pres/__tests__/presSystem.test.js +365 -365
  381. package/src/tools/office/pres/archetypes/agenda.js +61 -61
  382. package/src/tools/office/pres/archetypes/bentoGrid.js +218 -219
  383. package/src/tools/office/pres/archetypes/bigStat.js +140 -142
  384. package/src/tools/office/pres/archetypes/closing.js +70 -70
  385. package/src/tools/office/pres/archetypes/hero.js +70 -70
  386. package/src/tools/office/pres/archetypes/productHero.js +93 -94
  387. package/src/tools/office/pres/archetypes/table.js +73 -74
  388. package/src/tools/office/pres/backgrounds/orb.js +66 -66
  389. package/src/tools/office/pres/components.js +422 -423
  390. package/src/tools/officeTool.js +441 -441
  391. package/src/tools/pdfTool.js +625 -627
  392. package/src/tools/platformControlTool.js +1081 -1081
  393. package/src/tools/seekTool.js +917 -918
  394. package/src/tools/skillsTool.js +1 -1
  395. package/src/tools/staticAnalysisTool.js +2143 -2146
  396. package/src/tools/taskManagerTool.js +3324 -3324
  397. package/src/tools/terminalTool.js +2615 -2618
  398. package/src/tools/videoTool.js +1303 -1303
  399. package/src/tools/visionTool.js +508 -508
  400. package/src/tools/visualEditorTool.js +1289 -1290
  401. package/src/tools/webTool.js +3368 -3368
  402. package/src/tools/whatsappTool.js +464 -464
  403. package/src/types/__tests__/agent.test.js +499 -499
  404. package/src/types/__tests__/contextReference.test.js +606 -606
  405. package/src/types/__tests__/conversation.test.js +555 -555
  406. package/src/types/__tests__/toolCommand.test.js +584 -584
  407. package/src/types/contextReference.js +974 -971
  408. package/src/types/conversation.js +729 -729
  409. package/src/types/toolCommand.js +746 -746
  410. package/src/utilities/__tests__/attachmentValidator.test.js +80 -80
  411. package/src/utilities/__tests__/auditReport.test.js +328 -328
  412. package/src/utilities/__tests__/directoryAccessManager.test.js +388 -388
  413. package/src/utilities/__tests__/jsonRepair.test.js +103 -104
  414. package/src/utilities/__tests__/modeTransitionReasons.test.js +105 -105
  415. package/src/utilities/__tests__/platformUtils.test.js +80 -87
  416. package/src/utilities/__tests__/structuredFileValidator.test.js +261 -263
  417. package/src/utilities/__tests__/toolConstants.test.js +92 -94
  418. package/src/utilities/__tests__/useIsTouchDevice.detect.test.js +114 -114
  419. package/src/utilities/__tests__/webUiUtilSync.test.js +117 -117
  420. package/src/utilities/attachmentValidator.js +284 -288
  421. package/src/utilities/authCache.js.backup-1779570472481 +121 -121
  422. package/src/utilities/browserStealth.js +631 -630
  423. package/src/utilities/configManager.js +616 -617
  424. package/src/utilities/directoryAccessManager.js +564 -565
  425. package/src/utilities/fileProcessor.js +308 -307
  426. package/src/utilities/humanBehavior.js +454 -453
  427. package/src/utilities/logger.js +479 -479
  428. package/src/utilities/structuredFileValidator.js +696 -699
  429. package/src/utilities/tagParser.js +5 -10
  430. package/src/utilities/userDataDir.js +308 -308
  431. package/node_modules/@isaacs/brace-expansion/dist/commonjs/index.js.map +0 -1
  432. package/node_modules/@isaacs/brace-expansion/dist/esm/index.js.map +0 -1
  433. package/node_modules/minipass/LICENSE +0 -15
  434. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/LICENSE.md +0 -0
  435. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts +0 -0
  436. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.d.ts.map +0 -0
  437. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js +0 -0
  438. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/index.js.map +0 -0
  439. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/commonjs/package.json +0 -0
  440. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts +0 -0
  441. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.d.ts.map +0 -0
  442. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js +0 -0
  443. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/index.js.map +0 -0
  444. /package/node_modules/{@isaacs → glob/node_modules}/balanced-match/dist/esm/package.json +0 -0
  445. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/LICENSE +0 -0
  446. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts +0 -0
  447. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/index.d.ts.map +0 -0
  448. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/commonjs/package.json +0 -0
  449. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts +0 -0
  450. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/index.d.ts.map +0 -0
  451. /package/node_modules/{@isaacs → glob/node_modules}/brace-expansion/dist/esm/package.json +0 -0
@@ -1,423 +1,422 @@
1
- /**
2
- * pres/components — reusable UI primitives the archetypes compose.
3
- *
4
- * Modern decks lean on small, repeatable components: pill buttons, tag
5
- * chips, KPI cards with delta arrows, section progress dots, decorative
6
- * arcs in corners, huge backdrop numerals behind content. These are
7
- * those primitives — every archetype can call them so the design
8
- * vocabulary stays consistent across slide types.
9
- *
10
- * Every component reads colour from the palette by SEMANTIC ROLE
11
- * (palette.primary, palette.highlight, etc) — never accepts raw hex —
12
- * so swapping palettes restyles every component everywhere.
13
- */
14
- import { cardShape, shapeOpts } from './shapes.js';
15
- import { textStyle } from './typography.js';
16
- import { SLIDE_DIMENSIONS } from './grid.js';
17
- import { shade } from './palettes.js';
18
-
19
- /* ─── PILL BUTTON ────────────────────────────────────────────────────
20
- * A rounded-rect button you'd recognise from a SaaS landing page.
21
- * Used by closing slides, callouts, and the "Update" bar of UI mockup
22
- * slides. Auto-sizes to its label. */
23
- export function pillButton(slide, resolved, { x, y, label, kind = 'primary', size = 'md', icon }) {
24
- const palette = resolved.palette;
25
- const fill = kind === 'primary' ? palette.primary
26
- : kind === 'highlight' ? palette.highlight
27
- : kind === 'accent' ? palette.accent
28
- : kind === 'ghost' ? palette.surface
29
- : palette.primary;
30
- const labelColor = kind === 'ghost' ? palette.text
31
- : kind === 'highlight' ? palette.ink
32
- : 'FFFFFF';
33
- const dims = size === 'sm' ? { h: 0.36, padX: 0.28, fz: 11 }
34
- : size === 'lg' ? { h: 0.6, padX: 0.45, fz: 16 }
35
- : { h: 0.46, padX: 0.34, fz: 13 };
36
-
37
- // Estimate width from label length (PPTX has no measure-text API).
38
- const labelWidth = Math.max(0.7, label.length * dims.fz * 0.013);
39
- const w = labelWidth + dims.padX * 2;
40
-
41
- slide.addShape('roundRect', {
42
- x, y, w, h: dims.h,
43
- rectRadius: dims.h / 2, // proper pill
44
- fill: { color: fill },
45
- line: kind === 'ghost' ? { color: palette.subtle, width: 0.5 } : { type: 'none' },
46
- shadow: kind === 'primary' ? { type: 'outer', blur: 8, offset: 2, angle: 90, color: '000000', opacity: 0.15 } : undefined,
47
- });
48
- slide.addText(label, {
49
- x, y, w, h: dims.h,
50
- fontFace: resolved.typography.body.fontFace,
51
- fontSize: dims.fz,
52
- bold: true,
53
- color: labelColor,
54
- align: 'center',
55
- valign: 'middle',
56
- charSpacing: 0.5,
57
- });
58
- return { x, y, w, h: dims.h };
59
- }
60
-
61
- /* ─── TAG CHIP ──────────────────────────────────────────────────────
62
- * Smaller than a pill button, used for category labels, status badges,
63
- * "5 min read"-style metadata. Subtle background + highlight text. */
64
- export function tag(slide, resolved, { x, y, label, kind = 'subtle' }) {
65
- const palette = resolved.palette;
66
- const fill = kind === 'highlight' ? palette.highlight
67
- : kind === 'accent' ? palette.accent
68
- : kind === 'primary' ? palette.primary
69
- : shade(palette.bg, palette.family === 'tech' ? 15 : -10);
70
- const labelColor = kind === 'subtle' ? palette.text
71
- : kind === 'highlight' ? palette.ink
72
- : 'FFFFFF';
73
- const fz = 11;
74
- const padX = 0.18;
75
- const h = 0.3;
76
- const labelWidth = Math.max(0.4, label.length * fz * 0.012);
77
- const w = labelWidth + padX * 2;
78
-
79
- slide.addShape('roundRect', {
80
- x, y, w, h, rectRadius: h / 2,
81
- fill: { color: fill, transparency: kind === 'subtle' ? 20 : 0 },
82
- line: { type: 'none' },
83
- });
84
- slide.addText(label, {
85
- x, y, w, h,
86
- fontFace: resolved.typography.body.fontFace,
87
- fontSize: fz,
88
- bold: true,
89
- color: labelColor,
90
- align: 'center',
91
- valign: 'middle',
92
- charSpacing: 1,
93
- });
94
- return { x, y, w, h };
95
- }
96
-
97
- /* ─── GLASS CARD ────────────────────────────────────────────────────
98
- * Apple "liquid glass" surface. The recipe in pptxgenjs primitives:
99
- * 1. Two-stop subtle vertical gradient fill at high transparency
100
- * (lighter at top, baseline at bottom) — fakes the glass-on-blur
101
- * look without a real backdrop-filter.
102
- * 2. A 0.5pt inner stroke at 20% opacity in pure white the bright
103
- * edge that signals "this is glass" in every WWDC slide deck.
104
- *
105
- * On light themes the gradient inverts (slightly darker top, baseline
106
- * surface bottom) so the card still reads as raised. On dark themes
107
- * the stroke shines; on light it disappears (we hide it) so the card
108
- * doesn't have an awkward white outline.
109
- *
110
- * glassCard(slide, resolved, { x, y, w, h, tint?: 'primary' })
111
- *
112
- * `tint` lets the agent push a faint colour wash into the glass — used
113
- * by hero stat tiles to subtly colour-code without losing the glass feel.
114
- */
115
- export function glassCard(slide, resolved, { x, y, w, h, tint }) {
116
- const palette = resolved.palette;
117
- const isDark = palette.family === 'tech' && isDarkHexLocal(palette.bg);
118
-
119
- // Pre-paint the surface fill so the stroke sits on top.
120
- const topStop = isDark ? 'FFFFFF' : palette.subtle;
121
- const botStop = isDark ? palette.surface : palette.surface;
122
- slide.addShape(resolved.shape.cornerRadius > 0 ? 'roundRect' : 'rect', {
123
- x, y, w, h,
124
- ...(resolved.shape.cornerRadius > 0 ? { rectRadius: resolved.shape.cornerRadius } : {}),
125
- fill: {
126
- type: 'gradient',
127
- gradientType: 'linear',
128
- angle: 90,
129
- stops: [
130
- { pos: 0, color: topStop, transparency: isDark ? 88 : 92 },
131
- { pos: 100, color: botStop, transparency: isDark ? 70 : 60 },
132
- ],
133
- },
134
- line: isDark
135
- ? { color: 'FFFFFF', width: 0.5, transparency: 78 }
136
- : { color: palette.subtle, width: 0.5, transparency: 78 },
137
- shadow: resolved.shape.shadow || undefined,
138
- });
139
-
140
- // Optional tint wash a colour-keyed soft fill at very high
141
- // transparency, sitting on top of the glass base.
142
- if (tint) {
143
- const tintColor = palette[tint] || palette.primary;
144
- slide.addShape(resolved.shape.cornerRadius > 0 ? 'roundRect' : 'rect', {
145
- x, y, w, h,
146
- ...(resolved.shape.cornerRadius > 0 ? { rectRadius: resolved.shape.cornerRadius } : {}),
147
- fill: { color: tintColor, transparency: 90 },
148
- line: { type: 'none' },
149
- });
150
- }
151
- }
152
-
153
- function isDarkHexLocal(hex) {
154
- const s = String(hex).replace(/^#/, '');
155
- if (!/^[0-9A-Fa-f]{6}$/.test(s)) return false;
156
- const r = parseInt(s.slice(0, 2), 16);
157
- const g = parseInt(s.slice(2, 4), 16);
158
- const b = parseInt(s.slice(4, 6), 16);
159
- return (0.299 * r + 0.587 * g + 0.114 * b) < 110;
160
- }
161
-
162
- /* ─── KPI CARD ──────────────────────────────────────────────────────
163
- * A surface-coloured card holding: small label, big number, optional
164
- * up/down delta with colour-coded arrow. The unit of a dashboard. */
165
- export function kpiCard(slide, resolved, { x, y, w, h, label, value, unit, delta, deltaDirection }) {
166
- const palette = resolved.palette;
167
-
168
- // Card background.
169
- slide.addShape(cardShape(resolved.shape), {
170
- x, y, w, h,
171
- ...shapeOpts(resolved.shape, 'card', palette.surface),
172
- });
173
-
174
- const pad = 0.25;
175
-
176
- // Label on top.
177
- slide.addText(String(label || '').toUpperCase(), {
178
- x: x + pad, y: y + pad, w: w - pad * 2, h: 0.3,
179
- fontFace: resolved.typography.eyebrow.fontFace,
180
- fontSize: resolved.typography.eyebrow.fontSize,
181
- bold: true,
182
- color: palette.subtle,
183
- align: 'left',
184
- valign: 'top',
185
- charSpacing: 2,
186
- });
187
-
188
- // Value (big) + unit (smaller, baseline-aligned). One-line layout —
189
- // the value must not wrap, and the unit sits next to it. We give
190
- // pptxgenjs `fit: 'shrink'` so if the value+unit are wider than the
191
- // card, the type shrinks instead of wrapping (which would otherwise
192
- // push the value into the delta row).
193
- const valY = y + 0.62;
194
- const valH = h - 1.3;
195
- const valFrame = { x: x + pad, y: valY, w: w - pad * 2, h: valH };
196
- // Conservative font sizing: smaller of (card-derived) and (~50% of
197
- // card height), so a wide-card / short-card never overflows.
198
- const valueFontSize = Math.min(Math.max(28, valH * 36), Math.max(28, w * 16));
199
- if (unit) {
200
- slide.addText([
201
- { text: String(value ?? ''), options: {
202
- fontFace: resolved.typography.display.fontFace,
203
- fontSize: valueFontSize,
204
- bold: true,
205
- color: palette.ink,
206
- charSpacing: -2,
207
- } },
208
- { text: ' ' + unit, options: {
209
- fontFace: resolved.typography.body.fontFace,
210
- fontSize: Math.max(14, valueFontSize * 0.36),
211
- bold: true,
212
- color: palette.subtle,
213
- } },
214
- ], { ...valFrame, align: 'left', valign: 'middle', fit: 'shrink', wrap: false });
215
- } else {
216
- slide.addText(String(value ?? ''), {
217
- ...valFrame,
218
- fontFace: resolved.typography.display.fontFace,
219
- fontSize: valueFontSize,
220
- bold: true,
221
- color: palette.ink,
222
- align: 'left',
223
- valign: 'middle',
224
- charSpacing: -2,
225
- fit: 'shrink',
226
- wrap: false,
227
- });
228
- }
229
-
230
- // Delta row with colour-coded arrow.
231
- if (delta !== undefined && delta !== null && delta !== '') {
232
- const dir = deltaDirection || (String(delta).trim().startsWith('-') ? 'down' : 'up');
233
- const dColor = dir === 'down' ? palette.highlight : palette.primary;
234
- const arrow = dir === 'down' ? '▼' : '▲';
235
- slide.addText(`${arrow} ${delta}`, {
236
- x: x + pad, y: y + h - 0.45,
237
- w: w - pad * 2, h: 0.32,
238
- fontFace: resolved.typography.body.fontFace,
239
- fontSize: 13,
240
- bold: true,
241
- color: dColor,
242
- align: 'left',
243
- valign: 'middle',
244
- });
245
- }
246
- }
247
-
248
- /* ─── SECTION PROGRESS DOTS ─────────────────────────────────────────
249
- * A row of N small dots showing which section the deck is in. Filled
250
- * dot = current, hollow = other. Lives in the top-right of every
251
- * content slide via the slide master. */
252
- export function sectionProgress(slide, resolved, { sections, currentIdx, x, y }) {
253
- const palette = resolved.palette;
254
- const dotR = 0.07;
255
- const gap = 0.18;
256
- for (let i = 0; i < sections; i++) {
257
- const filled = i === currentIdx;
258
- slide.addShape('ellipse', {
259
- x: x + i * (dotR * 2 + gap),
260
- y, w: dotR * 2, h: dotR * 2,
261
- fill: filled ? { color: palette.primary } : { color: palette.subtle, transparency: 60 },
262
- line: { type: 'none' },
263
- });
264
- }
265
- }
266
-
267
- /* ─── DECORATIVE CORNER ARC ─────────────────────────────────────────
268
- * A quarter-circle accent in a slide corner. Used by section-headers
269
- * + hero slides for editorial-style flourish without taking content
270
- * real-estate. */
271
- export function cornerArc(slide, resolved, { corner = 'tr', size = 4, color, transparency = 70 }) {
272
- const palette = resolved.palette;
273
- const fill = color || palette.accent;
274
- const w = SLIDE_DIMENSIONS.width;
275
- const h = SLIDE_DIMENSIONS.height;
276
- // Place ellipse so only the desired quarter is visible on the slide.
277
- const positions = {
278
- tr: { x: w - size, y: -size, },
279
- tl: { x: -size, y: -size, },
280
- br: { x: w - size, y: h - size, },
281
- bl: { x: -size, y: h - size, },
282
- };
283
- const p = positions[corner] || positions.tr;
284
- slide.addShape('ellipse', {
285
- x: p.x, y: p.y,
286
- w: size * 2, h: size * 2,
287
- fill: { color: fill, transparency },
288
- line: { type: 'none' },
289
- });
290
- }
291
-
292
- /* ─── BIG BACKDROP NUMERAL ──────────────────────────────────────────
293
- * A huge ghosted number sitting behind content used by section
294
- * headers and bigStat. Adds drama without competing with foreground
295
- * text. */
296
- export function backdropNumeral(slide, resolved, { text, x, y, w, h, color, transparency = 88, size }) {
297
- const palette = resolved.palette;
298
- slide.addText(String(text), {
299
- x, y, w, h,
300
- fontFace: resolved.typography.display.fontFace,
301
- fontSize: size || 480,
302
- bold: true,
303
- color: color || palette.primary,
304
- align: 'left',
305
- valign: 'top',
306
- charSpacing: -10,
307
- transparency,
308
- });
309
- }
310
-
311
- /* ─── SIDE METADATA RAIL ────────────────────────────────────────────
312
- * A thin column down one edge with section name + small page number.
313
- * The kind of editorial flourish that signals "designed deck". Used
314
- * by the slide master. */
315
- export function sideRail(slide, resolved, { side = 'right', sectionName, pageLabel }) {
316
- const palette = resolved.palette;
317
- const m = resolved.spacing.pageMargin;
318
- const x = side === 'right' ? SLIDE_DIMENSIONS.width - m * 0.6 : m * 0.2;
319
-
320
- if (sectionName) {
321
- // Render vertical-looking text by spacing characters with breaks.
322
- slide.addText(String(sectionName).toUpperCase().split('').join('\n'), {
323
- x, y: m, w: 0.4, h: SLIDE_DIMENSIONS.height - m * 2 - 0.6,
324
- fontFace: resolved.typography.eyebrow.fontFace,
325
- fontSize: 9,
326
- bold: true,
327
- color: palette.subtle,
328
- align: 'center',
329
- valign: 'top',
330
- charSpacing: 2,
331
- });
332
- }
333
-
334
- if (pageLabel) {
335
- slide.addText(String(pageLabel), {
336
- x, y: SLIDE_DIMENSIONS.height - m - 0.4,
337
- w: 0.4, h: 0.3,
338
- fontFace: resolved.typography.eyebrow.fontFace,
339
- fontSize: 10,
340
- bold: true,
341
- color: palette.subtle,
342
- align: 'center',
343
- valign: 'middle',
344
- });
345
- }
346
- }
347
-
348
- /* ─── HEADER CHROME ─────────────────────────────────────────────────
349
- * Thin accent line + deck-section label + slide number at top of
350
- * content slides. The slide-master baseline; hero/section/closing
351
- * archetypes skip it. */
352
- export function headerChrome(slide, resolved, { sectionName, slideNumber, totalSlides }) {
353
- const palette = resolved.palette;
354
- const m = resolved.spacing.pageMargin;
355
- const w = SLIDE_DIMENSIONS.width;
356
-
357
- // Top hairline accent stripe.
358
- slide.addShape('rect', {
359
- x: 0, y: 0, w, h: 0.04,
360
- fill: { color: palette.primary },
361
- line: { type: 'none' },
362
- });
363
-
364
- // Section name top-left.
365
- if (sectionName) {
366
- slide.addText(String(sectionName).toUpperCase(), {
367
- x: m, y: 0.18, w: 6, h: 0.25,
368
- fontFace: resolved.typography.eyebrow.fontFace,
369
- fontSize: 9,
370
- bold: true,
371
- color: palette.subtle,
372
- align: 'left',
373
- charSpacing: 2,
374
- });
375
- }
376
-
377
- // Page number top-right.
378
- if (slideNumber) {
379
- const label = totalSlides ? `${String(slideNumber).padStart(2, '0')} / ${String(totalSlides).padStart(2, '0')}`
380
- : String(slideNumber).padStart(2, '0');
381
- slide.addText(label, {
382
- x: w - m - 1.5, y: 0.18, w: 1.5, h: 0.25,
383
- fontFace: resolved.typography.mono.fontFace,
384
- fontSize: 9,
385
- bold: true,
386
- color: palette.subtle,
387
- align: 'right',
388
- });
389
- }
390
- }
391
-
392
- /* ─── FOOTER CHROME ─────────────────────────────────────────────────
393
- * Brand name (left) + section progress dots (right) at the bottom of
394
- * content slides. Tied to the slide master. */
395
- export function footerChrome(slide, resolved, { brand, sectionTotal, currentSectionIdx }) {
396
- const palette = resolved.palette;
397
- const m = resolved.spacing.pageMargin;
398
- const w = SLIDE_DIMENSIONS.width;
399
- const h = SLIDE_DIMENSIONS.height;
400
- const footY = h - 0.35;
401
-
402
- if (brand) {
403
- slide.addText(String(brand), {
404
- x: m, y: footY, w: 4, h: 0.25,
405
- fontFace: resolved.typography.eyebrow.fontFace,
406
- fontSize: 9,
407
- bold: true,
408
- color: palette.subtle,
409
- align: 'left',
410
- charSpacing: 1.5,
411
- });
412
- }
413
-
414
- if (sectionTotal && sectionTotal > 0) {
415
- const dotsW = (sectionTotal * 0.07 * 2) + ((sectionTotal - 1) * 0.18);
416
- sectionProgress(slide, resolved, {
417
- sections: sectionTotal,
418
- currentIdx: currentSectionIdx || 0,
419
- x: w - m - dotsW,
420
- y: footY + 0.08,
421
- });
422
- }
423
- }
1
+ /**
2
+ * pres/components — reusable UI primitives the archetypes compose.
3
+ *
4
+ * Modern decks lean on small, repeatable components: pill buttons, tag
5
+ * chips, KPI cards with delta arrows, section progress dots, decorative
6
+ * arcs in corners, huge backdrop numerals behind content. These are
7
+ * those primitives — every archetype can call them so the design
8
+ * vocabulary stays consistent across slide types.
9
+ *
10
+ * Every component reads colour from the palette by SEMANTIC ROLE
11
+ * (palette.primary, palette.highlight, etc) — never accepts raw hex —
12
+ * so swapping palettes restyles every component everywhere.
13
+ */
14
+ import { cardShape, shapeOpts } from './shapes.js';
15
+ import { SLIDE_DIMENSIONS } from './grid.js';
16
+ import { shade } from './palettes.js';
17
+
18
+ /* ─── PILL BUTTON ────────────────────────────────────────────────────
19
+ * A rounded-rect button you'd recognise from a SaaS landing page.
20
+ * Used by closing slides, callouts, and the "Update" bar of UI mockup
21
+ * slides. Auto-sizes to its label. */
22
+ export function pillButton(slide, resolved, { x, y, label, kind = 'primary', size = 'md' }) {
23
+ const palette = resolved.palette;
24
+ const fill = kind === 'primary' ? palette.primary
25
+ : kind === 'highlight' ? palette.highlight
26
+ : kind === 'accent' ? palette.accent
27
+ : kind === 'ghost' ? palette.surface
28
+ : palette.primary;
29
+ const labelColor = kind === 'ghost' ? palette.text
30
+ : kind === 'highlight' ? palette.ink
31
+ : 'FFFFFF';
32
+ const dims = size === 'sm' ? { h: 0.36, padX: 0.28, fz: 11 }
33
+ : size === 'lg' ? { h: 0.6, padX: 0.45, fz: 16 }
34
+ : { h: 0.46, padX: 0.34, fz: 13 };
35
+
36
+ // Estimate width from label length (PPTX has no measure-text API).
37
+ const labelWidth = Math.max(0.7, label.length * dims.fz * 0.013);
38
+ const w = labelWidth + dims.padX * 2;
39
+
40
+ slide.addShape('roundRect', {
41
+ x, y, w, h: dims.h,
42
+ rectRadius: dims.h / 2, // proper pill
43
+ fill: { color: fill },
44
+ line: kind === 'ghost' ? { color: palette.subtle, width: 0.5 } : { type: 'none' },
45
+ shadow: kind === 'primary' ? { type: 'outer', blur: 8, offset: 2, angle: 90, color: '000000', opacity: 0.15 } : undefined,
46
+ });
47
+ slide.addText(label, {
48
+ x, y, w, h: dims.h,
49
+ fontFace: resolved.typography.body.fontFace,
50
+ fontSize: dims.fz,
51
+ bold: true,
52
+ color: labelColor,
53
+ align: 'center',
54
+ valign: 'middle',
55
+ charSpacing: 0.5,
56
+ });
57
+ return { x, y, w, h: dims.h };
58
+ }
59
+
60
+ /* ─── TAG CHIP ──────────────────────────────────────────────────────
61
+ * Smaller than a pill button, used for category labels, status badges,
62
+ * "5 min read"-style metadata. Subtle background + highlight text. */
63
+ export function tag(slide, resolved, { x, y, label, kind = 'subtle' }) {
64
+ const palette = resolved.palette;
65
+ const fill = kind === 'highlight' ? palette.highlight
66
+ : kind === 'accent' ? palette.accent
67
+ : kind === 'primary' ? palette.primary
68
+ : shade(palette.bg, palette.family === 'tech' ? 15 : -10);
69
+ const labelColor = kind === 'subtle' ? palette.text
70
+ : kind === 'highlight' ? palette.ink
71
+ : 'FFFFFF';
72
+ const fz = 11;
73
+ const padX = 0.18;
74
+ const h = 0.3;
75
+ const labelWidth = Math.max(0.4, label.length * fz * 0.012);
76
+ const w = labelWidth + padX * 2;
77
+
78
+ slide.addShape('roundRect', {
79
+ x, y, w, h, rectRadius: h / 2,
80
+ fill: { color: fill, transparency: kind === 'subtle' ? 20 : 0 },
81
+ line: { type: 'none' },
82
+ });
83
+ slide.addText(label, {
84
+ x, y, w, h,
85
+ fontFace: resolved.typography.body.fontFace,
86
+ fontSize: fz,
87
+ bold: true,
88
+ color: labelColor,
89
+ align: 'center',
90
+ valign: 'middle',
91
+ charSpacing: 1,
92
+ });
93
+ return { x, y, w, h };
94
+ }
95
+
96
+ /* ─── GLASS CARD ────────────────────────────────────────────────────
97
+ * Apple "liquid glass" surface. The recipe in pptxgenjs primitives:
98
+ * 1. Two-stop subtle vertical gradient fill at high transparency
99
+ * (lighter at top, baseline at bottom) fakes the glass-on-blur
100
+ * look without a real backdrop-filter.
101
+ * 2. A 0.5pt inner stroke at 20% opacity in pure white — the bright
102
+ * edge that signals "this is glass" in every WWDC slide deck.
103
+ *
104
+ * On light themes the gradient inverts (slightly darker top, baseline
105
+ * surface bottom) so the card still reads as raised. On dark themes
106
+ * the stroke shines; on light it disappears (we hide it) so the card
107
+ * doesn't have an awkward white outline.
108
+ *
109
+ * glassCard(slide, resolved, { x, y, w, h, tint?: 'primary' })
110
+ *
111
+ * `tint` lets the agent push a faint colour wash into the glass — used
112
+ * by hero stat tiles to subtly colour-code without losing the glass feel.
113
+ */
114
+ export function glassCard(slide, resolved, { x, y, w, h, tint }) {
115
+ const palette = resolved.palette;
116
+ const isDark = palette.family === 'tech' && isDarkHexLocal(palette.bg);
117
+
118
+ // Pre-paint the surface fill so the stroke sits on top.
119
+ const topStop = isDark ? 'FFFFFF' : palette.subtle;
120
+ const botStop = isDark ? palette.surface : palette.surface;
121
+ slide.addShape(resolved.shape.cornerRadius > 0 ? 'roundRect' : 'rect', {
122
+ x, y, w, h,
123
+ ...(resolved.shape.cornerRadius > 0 ? { rectRadius: resolved.shape.cornerRadius } : {}),
124
+ fill: {
125
+ type: 'gradient',
126
+ gradientType: 'linear',
127
+ angle: 90,
128
+ stops: [
129
+ { pos: 0, color: topStop, transparency: isDark ? 88 : 92 },
130
+ { pos: 100, color: botStop, transparency: isDark ? 70 : 60 },
131
+ ],
132
+ },
133
+ line: isDark
134
+ ? { color: 'FFFFFF', width: 0.5, transparency: 78 }
135
+ : { color: palette.subtle, width: 0.5, transparency: 78 },
136
+ shadow: resolved.shape.shadow || undefined,
137
+ });
138
+
139
+ // Optional tint wash — a colour-keyed soft fill at very high
140
+ // transparency, sitting on top of the glass base.
141
+ if (tint) {
142
+ const tintColor = palette[tint] || palette.primary;
143
+ slide.addShape(resolved.shape.cornerRadius > 0 ? 'roundRect' : 'rect', {
144
+ x, y, w, h,
145
+ ...(resolved.shape.cornerRadius > 0 ? { rectRadius: resolved.shape.cornerRadius } : {}),
146
+ fill: { color: tintColor, transparency: 90 },
147
+ line: { type: 'none' },
148
+ });
149
+ }
150
+ }
151
+
152
+ function isDarkHexLocal(hex) {
153
+ const s = String(hex).replace(/^#/, '');
154
+ if (!/^[0-9A-Fa-f]{6}$/.test(s)) return false;
155
+ const r = parseInt(s.slice(0, 2), 16);
156
+ const g = parseInt(s.slice(2, 4), 16);
157
+ const b = parseInt(s.slice(4, 6), 16);
158
+ return (0.299 * r + 0.587 * g + 0.114 * b) < 110;
159
+ }
160
+
161
+ /* ─── KPI CARD ──────────────────────────────────────────────────────
162
+ * A surface-coloured card holding: small label, big number, optional
163
+ * up/down delta with colour-coded arrow. The unit of a dashboard. */
164
+ export function kpiCard(slide, resolved, { x, y, w, h, label, value, unit, delta, deltaDirection }) {
165
+ const palette = resolved.palette;
166
+
167
+ // Card background.
168
+ slide.addShape(cardShape(resolved.shape), {
169
+ x, y, w, h,
170
+ ...shapeOpts(resolved.shape, 'card', palette.surface),
171
+ });
172
+
173
+ const pad = 0.25;
174
+
175
+ // Label on top.
176
+ slide.addText(String(label || '').toUpperCase(), {
177
+ x: x + pad, y: y + pad, w: w - pad * 2, h: 0.3,
178
+ fontFace: resolved.typography.eyebrow.fontFace,
179
+ fontSize: resolved.typography.eyebrow.fontSize,
180
+ bold: true,
181
+ color: palette.subtle,
182
+ align: 'left',
183
+ valign: 'top',
184
+ charSpacing: 2,
185
+ });
186
+
187
+ // Value (big) + unit (smaller, baseline-aligned). One-line layout —
188
+ // the value must not wrap, and the unit sits next to it. We give
189
+ // pptxgenjs `fit: 'shrink'` so if the value+unit are wider than the
190
+ // card, the type shrinks instead of wrapping (which would otherwise
191
+ // push the value into the delta row).
192
+ const valY = y + 0.62;
193
+ const valH = h - 1.3;
194
+ const valFrame = { x: x + pad, y: valY, w: w - pad * 2, h: valH };
195
+ // Conservative font sizing: smaller of (card-derived) and (~50% of
196
+ // card height), so a wide-card / short-card never overflows.
197
+ const valueFontSize = Math.min(Math.max(28, valH * 36), Math.max(28, w * 16));
198
+ if (unit) {
199
+ slide.addText([
200
+ { text: String(value ?? ''), options: {
201
+ fontFace: resolved.typography.display.fontFace,
202
+ fontSize: valueFontSize,
203
+ bold: true,
204
+ color: palette.ink,
205
+ charSpacing: -2,
206
+ } },
207
+ { text: ' ' + unit, options: {
208
+ fontFace: resolved.typography.body.fontFace,
209
+ fontSize: Math.max(14, valueFontSize * 0.36),
210
+ bold: true,
211
+ color: palette.subtle,
212
+ } },
213
+ ], { ...valFrame, align: 'left', valign: 'middle', fit: 'shrink', wrap: false });
214
+ } else {
215
+ slide.addText(String(value ?? ''), {
216
+ ...valFrame,
217
+ fontFace: resolved.typography.display.fontFace,
218
+ fontSize: valueFontSize,
219
+ bold: true,
220
+ color: palette.ink,
221
+ align: 'left',
222
+ valign: 'middle',
223
+ charSpacing: -2,
224
+ fit: 'shrink',
225
+ wrap: false,
226
+ });
227
+ }
228
+
229
+ // Delta row with colour-coded arrow.
230
+ if (delta !== undefined && delta !== null && delta !== '') {
231
+ const dir = deltaDirection || (String(delta).trim().startsWith('-') ? 'down' : 'up');
232
+ const dColor = dir === 'down' ? palette.highlight : palette.primary;
233
+ const arrow = dir === 'down' ? '▼' : '▲';
234
+ slide.addText(`${arrow} ${delta}`, {
235
+ x: x + pad, y: y + h - 0.45,
236
+ w: w - pad * 2, h: 0.32,
237
+ fontFace: resolved.typography.body.fontFace,
238
+ fontSize: 13,
239
+ bold: true,
240
+ color: dColor,
241
+ align: 'left',
242
+ valign: 'middle',
243
+ });
244
+ }
245
+ }
246
+
247
+ /* ─── SECTION PROGRESS DOTS ─────────────────────────────────────────
248
+ * A row of N small dots showing which section the deck is in. Filled
249
+ * dot = current, hollow = other. Lives in the top-right of every
250
+ * content slide via the slide master. */
251
+ export function sectionProgress(slide, resolved, { sections, currentIdx, x, y }) {
252
+ const palette = resolved.palette;
253
+ const dotR = 0.07;
254
+ const gap = 0.18;
255
+ for (let i = 0; i < sections; i++) {
256
+ const filled = i === currentIdx;
257
+ slide.addShape('ellipse', {
258
+ x: x + i * (dotR * 2 + gap),
259
+ y, w: dotR * 2, h: dotR * 2,
260
+ fill: filled ? { color: palette.primary } : { color: palette.subtle, transparency: 60 },
261
+ line: { type: 'none' },
262
+ });
263
+ }
264
+ }
265
+
266
+ /* ─── DECORATIVE CORNER ARC ─────────────────────────────────────────
267
+ * A quarter-circle accent in a slide corner. Used by section-headers
268
+ * + hero slides for editorial-style flourish without taking content
269
+ * real-estate. */
270
+ export function cornerArc(slide, resolved, { corner = 'tr', size = 4, color, transparency = 70 }) {
271
+ const palette = resolved.palette;
272
+ const fill = color || palette.accent;
273
+ const w = SLIDE_DIMENSIONS.width;
274
+ const h = SLIDE_DIMENSIONS.height;
275
+ // Place ellipse so only the desired quarter is visible on the slide.
276
+ const positions = {
277
+ tr: { x: w - size, y: -size, },
278
+ tl: { x: -size, y: -size, },
279
+ br: { x: w - size, y: h - size, },
280
+ bl: { x: -size, y: h - size, },
281
+ };
282
+ const p = positions[corner] || positions.tr;
283
+ slide.addShape('ellipse', {
284
+ x: p.x, y: p.y,
285
+ w: size * 2, h: size * 2,
286
+ fill: { color: fill, transparency },
287
+ line: { type: 'none' },
288
+ });
289
+ }
290
+
291
+ /* ─── BIG BACKDROP NUMERAL ──────────────────────────────────────────
292
+ * A huge ghosted number sitting behind content — used by section
293
+ * headers and bigStat. Adds drama without competing with foreground
294
+ * text. */
295
+ export function backdropNumeral(slide, resolved, { text, x, y, w, h, color, transparency = 88, size }) {
296
+ const palette = resolved.palette;
297
+ slide.addText(String(text), {
298
+ x, y, w, h,
299
+ fontFace: resolved.typography.display.fontFace,
300
+ fontSize: size || 480,
301
+ bold: true,
302
+ color: color || palette.primary,
303
+ align: 'left',
304
+ valign: 'top',
305
+ charSpacing: -10,
306
+ transparency,
307
+ });
308
+ }
309
+
310
+ /* ─── SIDE METADATA RAIL ────────────────────────────────────────────
311
+ * A thin column down one edge with section name + small page number.
312
+ * The kind of editorial flourish that signals "designed deck". Used
313
+ * by the slide master. */
314
+ export function sideRail(slide, resolved, { side = 'right', sectionName, pageLabel }) {
315
+ const palette = resolved.palette;
316
+ const m = resolved.spacing.pageMargin;
317
+ const x = side === 'right' ? SLIDE_DIMENSIONS.width - m * 0.6 : m * 0.2;
318
+
319
+ if (sectionName) {
320
+ // Render vertical-looking text by spacing characters with breaks.
321
+ slide.addText(String(sectionName).toUpperCase().split('').join('\n'), {
322
+ x, y: m, w: 0.4, h: SLIDE_DIMENSIONS.height - m * 2 - 0.6,
323
+ fontFace: resolved.typography.eyebrow.fontFace,
324
+ fontSize: 9,
325
+ bold: true,
326
+ color: palette.subtle,
327
+ align: 'center',
328
+ valign: 'top',
329
+ charSpacing: 2,
330
+ });
331
+ }
332
+
333
+ if (pageLabel) {
334
+ slide.addText(String(pageLabel), {
335
+ x, y: SLIDE_DIMENSIONS.height - m - 0.4,
336
+ w: 0.4, h: 0.3,
337
+ fontFace: resolved.typography.eyebrow.fontFace,
338
+ fontSize: 10,
339
+ bold: true,
340
+ color: palette.subtle,
341
+ align: 'center',
342
+ valign: 'middle',
343
+ });
344
+ }
345
+ }
346
+
347
+ /* ─── HEADER CHROME ─────────────────────────────────────────────────
348
+ * Thin accent line + deck-section label + slide number at top of
349
+ * content slides. The slide-master baseline; hero/section/closing
350
+ * archetypes skip it. */
351
+ export function headerChrome(slide, resolved, { sectionName, slideNumber, totalSlides }) {
352
+ const palette = resolved.palette;
353
+ const m = resolved.spacing.pageMargin;
354
+ const w = SLIDE_DIMENSIONS.width;
355
+
356
+ // Top hairline accent stripe.
357
+ slide.addShape('rect', {
358
+ x: 0, y: 0, w, h: 0.04,
359
+ fill: { color: palette.primary },
360
+ line: { type: 'none' },
361
+ });
362
+
363
+ // Section name top-left.
364
+ if (sectionName) {
365
+ slide.addText(String(sectionName).toUpperCase(), {
366
+ x: m, y: 0.18, w: 6, h: 0.25,
367
+ fontFace: resolved.typography.eyebrow.fontFace,
368
+ fontSize: 9,
369
+ bold: true,
370
+ color: palette.subtle,
371
+ align: 'left',
372
+ charSpacing: 2,
373
+ });
374
+ }
375
+
376
+ // Page number top-right.
377
+ if (slideNumber) {
378
+ const label = totalSlides ? `${String(slideNumber).padStart(2, '0')} / ${String(totalSlides).padStart(2, '0')}`
379
+ : String(slideNumber).padStart(2, '0');
380
+ slide.addText(label, {
381
+ x: w - m - 1.5, y: 0.18, w: 1.5, h: 0.25,
382
+ fontFace: resolved.typography.mono.fontFace,
383
+ fontSize: 9,
384
+ bold: true,
385
+ color: palette.subtle,
386
+ align: 'right',
387
+ });
388
+ }
389
+ }
390
+
391
+ /* ─── FOOTER CHROME ─────────────────────────────────────────────────
392
+ * Brand name (left) + section progress dots (right) at the bottom of
393
+ * content slides. Tied to the slide master. */
394
+ export function footerChrome(slide, resolved, { brand, sectionTotal, currentSectionIdx }) {
395
+ const palette = resolved.palette;
396
+ const m = resolved.spacing.pageMargin;
397
+ const w = SLIDE_DIMENSIONS.width;
398
+ const h = SLIDE_DIMENSIONS.height;
399
+ const footY = h - 0.35;
400
+
401
+ if (brand) {
402
+ slide.addText(String(brand), {
403
+ x: m, y: footY, w: 4, h: 0.25,
404
+ fontFace: resolved.typography.eyebrow.fontFace,
405
+ fontSize: 9,
406
+ bold: true,
407
+ color: palette.subtle,
408
+ align: 'left',
409
+ charSpacing: 1.5,
410
+ });
411
+ }
412
+
413
+ if (sectionTotal && sectionTotal > 0) {
414
+ const dotsW = (sectionTotal * 0.07 * 2) + ((sectionTotal - 1) * 0.18);
415
+ sectionProgress(slide, resolved, {
416
+ sections: sectionTotal,
417
+ currentIdx: currentSectionIdx || 0,
418
+ x: w - m - dotsW,
419
+ y: footY + 0.08,
420
+ });
421
+ }
422
+ }