agent-nuvira 3.3.1 → 3.3.4

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 (466) hide show
  1. package/README.md +18 -13
  2. package/dist/agent-sdk/src/agent.d.ts +2 -0
  3. package/dist/agent-sdk/src/agent.d.ts.map +1 -1
  4. package/dist/agent-sdk/src/define.d.ts +64 -0
  5. package/dist/agent-sdk/src/define.d.ts.map +1 -0
  6. package/dist/agent-sdk/src/define.js +76 -0
  7. package/dist/agent-sdk/src/define.js.map +1 -0
  8. package/dist/agent-sdk/src/index.d.ts +9 -0
  9. package/dist/agent-sdk/src/index.d.ts.map +1 -1
  10. package/dist/agent-sdk/src/index.js +9 -0
  11. package/dist/agent-sdk/src/index.js.map +1 -1
  12. package/dist/agent-sdk/src/scaffold.d.ts +11 -0
  13. package/dist/agent-sdk/src/scaffold.d.ts.map +1 -1
  14. package/dist/agent-sdk/src/scaffold.js +16 -6
  15. package/dist/agent-sdk/src/scaffold.js.map +1 -1
  16. package/dist/agents/agents/runner.d.ts +9 -0
  17. package/dist/agents/agents/runner.d.ts.map +1 -1
  18. package/dist/agents/agents/runner.js +34 -12
  19. package/dist/agents/agents/runner.js.map +1 -1
  20. package/dist/agents/agents/writer-tool-calling.d.ts.map +1 -1
  21. package/dist/agents/agents/writer-tool-calling.js +7 -2
  22. package/dist/agents/agents/writer-tool-calling.js.map +1 -1
  23. package/dist/agents/agents/writer.d.ts.map +1 -1
  24. package/dist/agents/agents/writer.js +7 -1
  25. package/dist/agents/agents/writer.js.map +1 -1
  26. package/dist/agents/artifact-verification.d.ts +102 -0
  27. package/dist/agents/artifact-verification.d.ts.map +1 -0
  28. package/dist/agents/artifact-verification.js +216 -0
  29. package/dist/agents/artifact-verification.js.map +1 -0
  30. package/dist/agents/checkpoint-store.d.ts +73 -0
  31. package/dist/agents/checkpoint-store.d.ts.map +1 -1
  32. package/dist/agents/checkpoint-store.js +161 -0
  33. package/dist/agents/checkpoint-store.js.map +1 -1
  34. package/dist/agents/credential-store.d.ts +120 -0
  35. package/dist/agents/credential-store.d.ts.map +1 -1
  36. package/dist/agents/credential-store.js +358 -19
  37. package/dist/agents/credential-store.js.map +1 -1
  38. package/dist/agents/long-form-plan.d.ts.map +1 -1
  39. package/dist/agents/long-form-plan.js +2 -1
  40. package/dist/agents/long-form-plan.js.map +1 -1
  41. package/dist/agents/orchestrator.d.ts +10 -1
  42. package/dist/agents/orchestrator.d.ts.map +1 -1
  43. package/dist/agents/orchestrator.js +239 -79
  44. package/dist/agents/orchestrator.js.map +1 -1
  45. package/dist/agents/phase-engine.d.ts +61 -0
  46. package/dist/agents/phase-engine.d.ts.map +1 -1
  47. package/dist/agents/phase-engine.js +68 -2
  48. package/dist/agents/phase-engine.js.map +1 -1
  49. package/dist/agents/prompt-assembly.d.ts +11 -0
  50. package/dist/agents/prompt-assembly.d.ts.map +1 -1
  51. package/dist/agents/prompt-assembly.js +17 -0
  52. package/dist/agents/prompt-assembly.js.map +1 -1
  53. package/dist/agents/release-preflight.d.ts +121 -0
  54. package/dist/agents/release-preflight.d.ts.map +1 -0
  55. package/dist/agents/release-preflight.js +259 -0
  56. package/dist/agents/release-preflight.js.map +1 -0
  57. package/dist/agents/release-runner.d.ts +157 -0
  58. package/dist/agents/release-runner.d.ts.map +1 -0
  59. package/dist/agents/release-runner.js +719 -0
  60. package/dist/agents/release-runner.js.map +1 -0
  61. package/dist/agents/step-handoff.d.ts +190 -0
  62. package/dist/agents/step-handoff.d.ts.map +1 -0
  63. package/dist/agents/step-handoff.js +443 -0
  64. package/dist/agents/step-handoff.js.map +1 -0
  65. package/dist/cli/agent.d.ts +2 -2
  66. package/dist/cli/agent.js +10 -10
  67. package/dist/cli/benchmark.d.ts.map +1 -1
  68. package/dist/cli/benchmark.js +11 -4
  69. package/dist/cli/benchmark.js.map +1 -1
  70. package/dist/cli/chat.d.ts +94 -0
  71. package/dist/cli/chat.d.ts.map +1 -1
  72. package/dist/cli/chat.js +379 -24
  73. package/dist/cli/chat.js.map +1 -1
  74. package/dist/cli/cli-program.d.ts.map +1 -1
  75. package/dist/cli/cli-program.js +8 -0
  76. package/dist/cli/cli-program.js.map +1 -1
  77. package/dist/cli/config.d.ts.map +1 -1
  78. package/dist/cli/config.js +9 -1
  79. package/dist/cli/config.js.map +1 -1
  80. package/dist/cli/credentials.d.ts +28 -0
  81. package/dist/cli/credentials.d.ts.map +1 -0
  82. package/dist/cli/credentials.js +213 -0
  83. package/dist/cli/credentials.js.map +1 -0
  84. package/dist/cli/doctor.d.ts.map +1 -1
  85. package/dist/cli/doctor.js +3 -2
  86. package/dist/cli/doctor.js.map +1 -1
  87. package/dist/cli/edit.js +2 -2
  88. package/dist/cli/eval.d.ts +17 -0
  89. package/dist/cli/eval.d.ts.map +1 -1
  90. package/dist/cli/eval.js +105 -2
  91. package/dist/cli/eval.js.map +1 -1
  92. package/dist/cli/execute.d.ts +16 -1
  93. package/dist/cli/execute.d.ts.map +1 -1
  94. package/dist/cli/execute.js +192 -22
  95. package/dist/cli/execute.js.map +1 -1
  96. package/dist/cli/failover-runner.d.ts.map +1 -1
  97. package/dist/cli/failover-runner.js +9 -3
  98. package/dist/cli/failover-runner.js.map +1 -1
  99. package/dist/cli/loop-executor.d.ts +55 -0
  100. package/dist/cli/loop-executor.d.ts.map +1 -1
  101. package/dist/cli/loop-executor.js +285 -19
  102. package/dist/cli/loop-executor.js.map +1 -1
  103. package/dist/cli/model.d.ts.map +1 -1
  104. package/dist/cli/model.js +9 -8
  105. package/dist/cli/model.js.map +1 -1
  106. package/dist/cli/models.d.ts +1 -1
  107. package/dist/cli/models.js +4 -4
  108. package/dist/cli/nlu.d.ts.map +1 -1
  109. package/dist/cli/nlu.js +8 -2
  110. package/dist/cli/nlu.js.map +1 -1
  111. package/dist/cli/parity.d.ts +85 -0
  112. package/dist/cli/parity.d.ts.map +1 -0
  113. package/dist/cli/parity.js +506 -0
  114. package/dist/cli/parity.js.map +1 -0
  115. package/dist/cli/plan.d.ts.map +1 -1
  116. package/dist/cli/plan.js +2 -1
  117. package/dist/cli/plan.js.map +1 -1
  118. package/dist/cli/publish.d.ts +22 -0
  119. package/dist/cli/publish.d.ts.map +1 -1
  120. package/dist/cli/publish.js +109 -13
  121. package/dist/cli/publish.js.map +1 -1
  122. package/dist/cli/retrieval.d.ts.map +1 -1
  123. package/dist/cli/retrieval.js +5 -4
  124. package/dist/cli/retrieval.js.map +1 -1
  125. package/dist/cli/sdk.js +4 -4
  126. package/dist/cli/sdk.js.map +1 -1
  127. package/dist/cli/trace.d.ts.map +1 -1
  128. package/dist/cli/trace.js +2 -1
  129. package/dist/cli/trace.js.map +1 -1
  130. package/dist/cli/workflow.js +2 -2
  131. package/dist/cli/workflow.js.map +1 -1
  132. package/dist/config/live-credentials.d.ts +57 -0
  133. package/dist/config/live-credentials.d.ts.map +1 -0
  134. package/dist/config/live-credentials.js +126 -0
  135. package/dist/config/live-credentials.js.map +1 -0
  136. package/dist/config/paths.d.ts +18 -0
  137. package/dist/config/paths.d.ts.map +1 -1
  138. package/dist/config/paths.js +25 -0
  139. package/dist/config/paths.js.map +1 -1
  140. package/dist/config/types.d.ts +44 -0
  141. package/dist/config/types.d.ts.map +1 -1
  142. package/dist/federation/a2a-types.js +1 -1
  143. package/dist/federation/a2a-types.js.map +1 -1
  144. package/dist/findings/verdicts.d.ts +241 -0
  145. package/dist/findings/verdicts.d.ts.map +1 -0
  146. package/dist/findings/verdicts.js +284 -0
  147. package/dist/findings/verdicts.js.map +1 -0
  148. package/dist/gateway/adapters.d.ts +65 -0
  149. package/dist/gateway/adapters.d.ts.map +1 -1
  150. package/dist/gateway/adapters.js +216 -10
  151. package/dist/gateway/adapters.js.map +1 -1
  152. package/dist/gateway/channel-directory.d.ts +31 -0
  153. package/dist/gateway/channel-directory.d.ts.map +1 -1
  154. package/dist/gateway/channel-directory.js +40 -0
  155. package/dist/gateway/channel-directory.js.map +1 -1
  156. package/dist/gateway/gateway-log.d.ts +1 -1
  157. package/dist/gateway/gateway-log.d.ts.map +1 -1
  158. package/dist/gateway/gateway-log.js.map +1 -1
  159. package/dist/gateway/hooks.d.ts +87 -19
  160. package/dist/gateway/hooks.d.ts.map +1 -1
  161. package/dist/gateway/hooks.js +62 -23
  162. package/dist/gateway/hooks.js.map +1 -1
  163. package/dist/gateway/inbound-media.d.ts +147 -0
  164. package/dist/gateway/inbound-media.d.ts.map +1 -0
  165. package/dist/gateway/inbound-media.js +317 -0
  166. package/dist/gateway/inbound-media.js.map +1 -0
  167. package/dist/gateway/inbox.d.ts +8 -1
  168. package/dist/gateway/inbox.d.ts.map +1 -1
  169. package/dist/gateway/inbox.js.map +1 -1
  170. package/dist/gateway/platform-config.d.ts +14 -0
  171. package/dist/gateway/platform-config.d.ts.map +1 -1
  172. package/dist/gateway/platform-config.js +26 -8
  173. package/dist/gateway/platform-config.js.map +1 -1
  174. package/dist/gateway/realtime.d.ts +114 -0
  175. package/dist/gateway/realtime.d.ts.map +1 -0
  176. package/dist/gateway/realtime.js +402 -0
  177. package/dist/gateway/realtime.js.map +1 -0
  178. package/dist/gateway/registry.d.ts +31 -0
  179. package/dist/gateway/registry.d.ts.map +1 -1
  180. package/dist/gateway/registry.js +224 -4
  181. package/dist/gateway/registry.js.map +1 -1
  182. package/dist/gateway/whatsapp/baileys-bridge.d.ts +11 -1
  183. package/dist/gateway/whatsapp/baileys-bridge.d.ts.map +1 -1
  184. package/dist/gateway/whatsapp/baileys-bridge.js +123 -4
  185. package/dist/gateway/whatsapp/baileys-bridge.js.map +1 -1
  186. package/dist/gateway/whatsapp/bridge.d.ts +6 -2
  187. package/dist/gateway/whatsapp/bridge.d.ts.map +1 -1
  188. package/dist/gateway/whatsapp/bridge.js.map +1 -1
  189. package/dist/index.js +8 -0
  190. package/dist/index.js.map +1 -1
  191. package/dist/inference/factory.d.ts +14 -0
  192. package/dist/inference/factory.d.ts.map +1 -1
  193. package/dist/inference/factory.js +17 -0
  194. package/dist/inference/factory.js.map +1 -1
  195. package/dist/inference/groq-adapter.d.ts +2 -0
  196. package/dist/inference/groq-adapter.d.ts.map +1 -1
  197. package/dist/inference/groq-adapter.js +16 -6
  198. package/dist/inference/groq-adapter.js.map +1 -1
  199. package/dist/inference/model-validator.d.ts +6 -1
  200. package/dist/inference/model-validator.d.ts.map +1 -1
  201. package/dist/inference/model-validator.js +7 -2
  202. package/dist/inference/model-validator.js.map +1 -1
  203. package/dist/inference/route-resolver.d.ts +116 -0
  204. package/dist/inference/route-resolver.d.ts.map +1 -0
  205. package/dist/inference/route-resolver.js +159 -0
  206. package/dist/inference/route-resolver.js.map +1 -0
  207. package/dist/inference/tools.d.ts.map +1 -1
  208. package/dist/inference/tools.js +29 -0
  209. package/dist/inference/tools.js.map +1 -1
  210. package/dist/learning/autonomy-policy.d.ts +18 -0
  211. package/dist/learning/autonomy-policy.d.ts.map +1 -1
  212. package/dist/learning/autonomy-policy.js +35 -0
  213. package/dist/learning/autonomy-policy.js.map +1 -1
  214. package/dist/learning/benchmark.d.ts.map +1 -1
  215. package/dist/learning/benchmark.js +3 -2
  216. package/dist/learning/benchmark.js.map +1 -1
  217. package/dist/learning/continuation.d.ts.map +1 -1
  218. package/dist/learning/continuation.js +2 -1
  219. package/dist/learning/continuation.js.map +1 -1
  220. package/dist/learning/cost-tracker.d.ts.map +1 -1
  221. package/dist/learning/cost-tracker.js +2 -1
  222. package/dist/learning/cost-tracker.js.map +1 -1
  223. package/dist/learning/deferred-task.d.ts.map +1 -1
  224. package/dist/learning/deferred-task.js +13 -4
  225. package/dist/learning/deferred-task.js.map +1 -1
  226. package/dist/learning/eval-framework.d.ts.map +1 -1
  227. package/dist/learning/eval-framework.js +2 -1
  228. package/dist/learning/eval-framework.js.map +1 -1
  229. package/dist/learning/long-form.d.ts.map +1 -1
  230. package/dist/learning/long-form.js +2 -1
  231. package/dist/learning/long-form.js.map +1 -1
  232. package/dist/learning/model-registry.d.ts.map +1 -1
  233. package/dist/learning/model-registry.js +2 -1
  234. package/dist/learning/model-registry.js.map +1 -1
  235. package/dist/learning/reasoning-cache.d.ts.map +1 -1
  236. package/dist/learning/reasoning-cache.js +2 -1
  237. package/dist/learning/reasoning-cache.js.map +1 -1
  238. package/dist/learning/reasoning-trace.d.ts +38 -2
  239. package/dist/learning/reasoning-trace.d.ts.map +1 -1
  240. package/dist/learning/reasoning-trace.js +91 -1
  241. package/dist/learning/reasoning-trace.js.map +1 -1
  242. package/dist/learning/resilient-call.d.ts.map +1 -1
  243. package/dist/learning/resilient-call.js +31 -18
  244. package/dist/learning/resilient-call.js.map +1 -1
  245. package/dist/learning/retrieval.d.ts.map +1 -1
  246. package/dist/learning/retrieval.js +2 -1
  247. package/dist/learning/retrieval.js.map +1 -1
  248. package/dist/learning/seeded-benchmark.d.ts +160 -0
  249. package/dist/learning/seeded-benchmark.d.ts.map +1 -0
  250. package/dist/learning/seeded-benchmark.js +321 -0
  251. package/dist/learning/seeded-benchmark.js.map +1 -0
  252. package/dist/learning/seeded-bugs.d.ts +142 -0
  253. package/dist/learning/seeded-bugs.d.ts.map +1 -0
  254. package/dist/learning/seeded-bugs.js +535 -0
  255. package/dist/learning/seeded-bugs.js.map +1 -0
  256. package/dist/learning/skill-store.d.ts.map +1 -1
  257. package/dist/learning/skill-store.js +30 -9
  258. package/dist/learning/skill-store.js.map +1 -1
  259. package/dist/learning/step-checkpoint.d.ts +127 -0
  260. package/dist/learning/step-checkpoint.d.ts.map +1 -0
  261. package/dist/learning/step-checkpoint.js +244 -0
  262. package/dist/learning/step-checkpoint.js.map +1 -0
  263. package/dist/mcp/catalog.js +2 -3
  264. package/dist/mcp/catalog.js.map +1 -1
  265. package/dist/mcp/manager.d.ts.map +1 -1
  266. package/dist/mcp/manager.js +5 -3
  267. package/dist/mcp/manager.js.map +1 -1
  268. package/dist/nlu/intent-confirm.d.ts +23 -1
  269. package/dist/nlu/intent-confirm.d.ts.map +1 -1
  270. package/dist/nlu/intent-confirm.js +85 -2
  271. package/dist/nlu/intent-confirm.js.map +1 -1
  272. package/dist/nlu/learnings.d.ts +7 -0
  273. package/dist/nlu/learnings.d.ts.map +1 -1
  274. package/dist/nlu/learnings.js +7 -0
  275. package/dist/nlu/learnings.js.map +1 -1
  276. package/dist/observability/debug-log.d.ts +250 -0
  277. package/dist/observability/debug-log.d.ts.map +1 -0
  278. package/dist/observability/debug-log.js +500 -0
  279. package/dist/observability/debug-log.js.map +1 -0
  280. package/dist/observability/event-bus.d.ts.map +1 -1
  281. package/dist/observability/event-bus.js +4 -1
  282. package/dist/observability/event-bus.js.map +1 -1
  283. package/dist/observability/otel.d.ts +278 -0
  284. package/dist/observability/otel.d.ts.map +1 -0
  285. package/dist/observability/otel.js +590 -0
  286. package/dist/observability/otel.js.map +1 -0
  287. package/dist/parity/drivers.d.ts +99 -0
  288. package/dist/parity/drivers.d.ts.map +1 -0
  289. package/dist/parity/drivers.js +1362 -0
  290. package/dist/parity/drivers.js.map +1 -0
  291. package/dist/parity/graph.d.ts +73 -0
  292. package/dist/parity/graph.d.ts.map +1 -0
  293. package/dist/parity/graph.js +162 -0
  294. package/dist/parity/graph.js.map +1 -0
  295. package/dist/parity/matrix.d.ts +105 -0
  296. package/dist/parity/matrix.d.ts.map +1 -0
  297. package/dist/parity/matrix.js +352 -0
  298. package/dist/parity/matrix.js.map +1 -0
  299. package/dist/parity/observation.d.ts +444 -0
  300. package/dist/parity/observation.d.ts.map +1 -0
  301. package/dist/parity/observation.js +333 -0
  302. package/dist/parity/observation.js.map +1 -0
  303. package/dist/parity/scenarios.d.ts +229 -0
  304. package/dist/parity/scenarios.d.ts.map +1 -0
  305. package/dist/parity/scenarios.js +175 -0
  306. package/dist/parity/scenarios.js.map +1 -0
  307. package/dist/parity/surfaces.d.ts +122 -0
  308. package/dist/parity/surfaces.d.ts.map +1 -0
  309. package/dist/parity/surfaces.js +190 -0
  310. package/dist/parity/surfaces.js.map +1 -0
  311. package/dist/runtime/fault-injection.d.ts +173 -0
  312. package/dist/runtime/fault-injection.d.ts.map +1 -0
  313. package/dist/runtime/fault-injection.js +281 -0
  314. package/dist/runtime/fault-injection.js.map +1 -0
  315. package/dist/skills/secret-capture.d.ts.map +1 -1
  316. package/dist/skills/secret-capture.js +9 -4
  317. package/dist/skills/secret-capture.js.map +1 -1
  318. package/dist/tools/child-agent-entry.d.ts +23 -0
  319. package/dist/tools/child-agent-entry.d.ts.map +1 -0
  320. package/dist/tools/child-agent-entry.js +129 -0
  321. package/dist/tools/child-agent-entry.js.map +1 -0
  322. package/dist/tools/child-agent-runtime.d.ts +124 -0
  323. package/dist/tools/child-agent-runtime.d.ts.map +1 -0
  324. package/dist/tools/child-agent-runtime.js +704 -0
  325. package/dist/tools/child-agent-runtime.js.map +1 -0
  326. package/dist/tools/coding-tools.d.ts.map +1 -1
  327. package/dist/tools/coding-tools.js +82 -10
  328. package/dist/tools/coding-tools.js.map +1 -1
  329. package/dist/tools/credentials-tool.d.ts +24 -0
  330. package/dist/tools/credentials-tool.d.ts.map +1 -0
  331. package/dist/tools/credentials-tool.js +125 -0
  332. package/dist/tools/credentials-tool.js.map +1 -0
  333. package/dist/tools/delegation-system.d.ts +31 -0
  334. package/dist/tools/delegation-system.d.ts.map +1 -1
  335. package/dist/tools/delegation-system.js +70 -9
  336. package/dist/tools/delegation-system.js.map +1 -1
  337. package/dist/tools/extract/docx.d.ts +27 -0
  338. package/dist/tools/extract/docx.d.ts.map +1 -0
  339. package/dist/tools/extract/docx.js +48 -0
  340. package/dist/tools/extract/docx.js.map +1 -0
  341. package/dist/tools/extract/html-text.d.ts +27 -0
  342. package/dist/tools/extract/html-text.d.ts.map +1 -0
  343. package/dist/tools/extract/html-text.js +86 -0
  344. package/dist/tools/extract/html-text.js.map +1 -0
  345. package/dist/tools/extract/pdf-ocr.d.ts +58 -0
  346. package/dist/tools/extract/pdf-ocr.d.ts.map +1 -0
  347. package/dist/tools/extract/pdf-ocr.js +116 -0
  348. package/dist/tools/extract/pdf-ocr.js.map +1 -0
  349. package/dist/tools/extract/pdf.d.ts +65 -0
  350. package/dist/tools/extract/pdf.d.ts.map +1 -0
  351. package/dist/tools/extract/pdf.js +197 -0
  352. package/dist/tools/extract/pdf.js.map +1 -0
  353. package/dist/tools/extract/pptx.d.ts +32 -0
  354. package/dist/tools/extract/pptx.d.ts.map +1 -0
  355. package/dist/tools/extract/pptx.js +77 -0
  356. package/dist/tools/extract/pptx.js.map +1 -0
  357. package/dist/tools/extract/xlsx.d.ts +47 -0
  358. package/dist/tools/extract/xlsx.d.ts.map +1 -0
  359. package/dist/tools/extract/xlsx.js +111 -0
  360. package/dist/tools/extract/xlsx.js.map +1 -0
  361. package/dist/tools/finding-tool.d.ts +76 -0
  362. package/dist/tools/finding-tool.d.ts.map +1 -0
  363. package/dist/tools/finding-tool.js +125 -0
  364. package/dist/tools/finding-tool.js.map +1 -0
  365. package/dist/tools/git-tool.d.ts +25 -7
  366. package/dist/tools/git-tool.d.ts.map +1 -1
  367. package/dist/tools/git-tool.js +155 -15
  368. package/dist/tools/git-tool.js.map +1 -1
  369. package/dist/tools/loop-project-context.d.ts.map +1 -1
  370. package/dist/tools/loop-project-context.js +16 -0
  371. package/dist/tools/loop-project-context.js.map +1 -1
  372. package/dist/tools/loop-route-feed.d.ts +57 -0
  373. package/dist/tools/loop-route-feed.d.ts.map +1 -0
  374. package/dist/tools/loop-route-feed.js +101 -0
  375. package/dist/tools/loop-route-feed.js.map +1 -0
  376. package/dist/tools/messaging-tools.d.ts +41 -11
  377. package/dist/tools/messaging-tools.d.ts.map +1 -1
  378. package/dist/tools/messaging-tools.js +104 -55
  379. package/dist/tools/messaging-tools.js.map +1 -1
  380. package/dist/tools/neutts-synth.d.ts +27 -3
  381. package/dist/tools/neutts-synth.d.ts.map +1 -1
  382. package/dist/tools/neutts-synth.js +57 -13
  383. package/dist/tools/neutts-synth.js.map +1 -1
  384. package/dist/tools/pipeline-tool.d.ts +43 -1
  385. package/dist/tools/pipeline-tool.d.ts.map +1 -1
  386. package/dist/tools/pipeline-tool.js +21 -4
  387. package/dist/tools/pipeline-tool.js.map +1 -1
  388. package/dist/tools/publish-tool.d.ts.map +1 -1
  389. package/dist/tools/publish-tool.js +76 -10
  390. package/dist/tools/publish-tool.js.map +1 -1
  391. package/dist/tools/read-extract.d.ts +116 -45
  392. package/dist/tools/read-extract.d.ts.map +1 -1
  393. package/dist/tools/read-extract.js +494 -158
  394. package/dist/tools/read-extract.js.map +1 -1
  395. package/dist/tools/registry.d.ts +23 -3
  396. package/dist/tools/registry.d.ts.map +1 -1
  397. package/dist/tools/registry.js +196 -29
  398. package/dist/tools/registry.js.map +1 -1
  399. package/dist/tools/run-terminal.d.ts +9 -0
  400. package/dist/tools/run-terminal.d.ts.map +1 -1
  401. package/dist/tools/run-terminal.js +80 -2
  402. package/dist/tools/run-terminal.js.map +1 -1
  403. package/dist/tools/subagent-refusal.d.ts +15 -0
  404. package/dist/tools/subagent-refusal.d.ts.map +1 -0
  405. package/dist/tools/subagent-refusal.js +18 -0
  406. package/dist/tools/subagent-refusal.js.map +1 -0
  407. package/dist/tools/subagent-spawner.d.ts +122 -0
  408. package/dist/tools/subagent-spawner.d.ts.map +1 -1
  409. package/dist/tools/subagent-spawner.js +249 -28
  410. package/dist/tools/subagent-spawner.js.map +1 -1
  411. package/dist/tools/tool-hooks.d.ts +177 -0
  412. package/dist/tools/tool-hooks.d.ts.map +1 -0
  413. package/dist/tools/tool-hooks.js +427 -0
  414. package/dist/tools/tool-hooks.js.map +1 -0
  415. package/dist/tools/tool-loop.d.ts +94 -5
  416. package/dist/tools/tool-loop.d.ts.map +1 -1
  417. package/dist/tools/tool-loop.js +315 -9
  418. package/dist/tools/tool-loop.js.map +1 -1
  419. package/dist/tools/tool-refusal.d.ts +68 -0
  420. package/dist/tools/tool-refusal.d.ts.map +1 -0
  421. package/dist/tools/tool-refusal.js +78 -0
  422. package/dist/tools/tool-refusal.js.map +1 -0
  423. package/dist/tools/toolsets.d.ts +8 -0
  424. package/dist/tools/toolsets.d.ts.map +1 -1
  425. package/dist/tools/toolsets.js +14 -4
  426. package/dist/tools/toolsets.js.map +1 -1
  427. package/dist/tools/vision-tools.d.ts +88 -83
  428. package/dist/tools/vision-tools.d.ts.map +1 -1
  429. package/dist/tools/vision-tools.js +134 -103
  430. package/dist/tools/vision-tools.js.map +1 -1
  431. package/dist/tools/worktree.d.ts +210 -0
  432. package/dist/tools/worktree.d.ts.map +1 -0
  433. package/dist/tools/worktree.js +374 -0
  434. package/dist/tools/worktree.js.map +1 -0
  435. package/dist/utils/format.d.ts +3 -0
  436. package/dist/utils/format.d.ts.map +1 -0
  437. package/dist/utils/format.js +32 -0
  438. package/dist/utils/format.js.map +1 -0
  439. package/dist/web-dashboard/attachment-extract.d.ts +64 -0
  440. package/dist/web-dashboard/attachment-extract.d.ts.map +1 -0
  441. package/dist/web-dashboard/attachment-extract.js +154 -0
  442. package/dist/web-dashboard/attachment-extract.js.map +1 -0
  443. package/dist/web-dashboard/chat-console.d.ts +108 -1
  444. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  445. package/dist/web-dashboard/chat-console.js +36 -0
  446. package/dist/web-dashboard/chat-console.js.map +1 -1
  447. package/dist/web-dashboard/hub-data.d.ts +37 -0
  448. package/dist/web-dashboard/hub-data.d.ts.map +1 -1
  449. package/dist/web-dashboard/hub-data.js +61 -1
  450. package/dist/web-dashboard/hub-data.js.map +1 -1
  451. package/dist/web-dashboard/server.d.ts +14 -0
  452. package/dist/web-dashboard/server.d.ts.map +1 -1
  453. package/dist/web-dashboard/server.js +247 -13
  454. package/dist/web-dashboard/server.js.map +1 -1
  455. package/dist/web-dashboard/src/types.d.ts +196 -48
  456. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  457. package/dist/workflow/registry.js +1 -1
  458. package/dist/workflow/registry.js.map +1 -1
  459. package/package.json +22 -6
  460. package/src/web-dashboard/public/assets/{index-Cyd6tIew.css → index-XJjj2cBX.css} +1 -1
  461. package/src/web-dashboard/public/assets/index-YWF9FpwQ.js +207 -0
  462. package/src/web-dashboard/public/assets/index-YWF9FpwQ.js.map +1 -0
  463. package/src/web-dashboard/public/index.html +2 -2
  464. package/dist/tools/child-agent-worker.js +0 -212
  465. package/src/web-dashboard/public/assets/index-CjvoBhlz.js +0 -207
  466. package/src/web-dashboard/public/assets/index-CjvoBhlz.js.map +0 -1
@@ -1,34 +1,102 @@
1
1
  /**
2
2
  * read_extract — Document-to-text extraction.
3
3
  *
4
- * Extracts text from various document formats:
5
- * - PDF documents
6
- * - Microsoft Word (DOCX)
7
- * - Microsoft Excel (XLSX)
8
- * - Microsoft PowerPoint (PPTX)
9
- * - Plain text files
10
- * - Markdown files
11
- * - HTML files
4
+ * IMPLEMENTED:
5
+ * - Text-ish: plain text, Markdown, HTML, CSV, JSON, XML, YAML (no dependency)
6
+ * - PDF — `pdfjs-dist/legacy` with geometry-based row reconstruction (extract/pdf.ts)
7
+ * - DOCX — `mammoth`, HTML output flattened structure-preservingly (extract/docx.ts)
8
+ * - XLSX — SheetJS with cell number formats applied (extract/xlsx.ts)
9
+ * - PPTX — `fflate` + direct `<a:t>` reading (extract/pptx.ts)
10
+ *
11
+ * NOT IMPLEMENTED — refused with a typed `unsupported_format` and alternatives:
12
+ * legacy binary Office formats (.doc/.xls/.ppt), .rtf, .odt — see PENDING_FORMATS.
13
+ *
14
+ * History: this module used to read a PDF and a DOCX by `readFileSync(path, 'utf-8')`
15
+ * and stripping non-printable bytes, then report `success: true`. A PDF stores its
16
+ * text inside compressed content streams and a DOCX is a ZIP of XML parts, so that
17
+ * path could only ever return the container. On 2026-09-27 exactly that reached the
18
+ * model as a health report it then could not assess, with no signal that extraction
19
+ * had failed. Every extractor below either does the real work or refuses.
20
+ *
21
+ * The container readers are imported dynamically: pdf.js and SheetJS are megabytes
22
+ * that the CLI, the dashboard server and the tool registry should not pay for at
23
+ * startup, and a failure to load one is reported as `not_configured` rather than
24
+ * silently degrading.
25
+ *
26
+ * See TOOL_TRUTHFULNESS_TRACKER.md (P0.1, P0.2, P1.2–P1.5).
12
27
  */
13
28
  import * as fs from 'fs';
14
29
  import * as path from 'path';
30
+ import { refusalFields } from './tool-refusal.js';
31
+ import { htmlToText } from './extract/html-text.js';
32
+ // ─── Budgets ────────────────────────────────────────────────────────────────
33
+ /**
34
+ * Character budget for one extraction. Documents are unbounded input flowing into
35
+ * a bounded context window, so the output is capped and `metadata.truncated` says
36
+ * whether it was hit — a partial document is never presented as the whole one.
37
+ */
38
+ const MAX_EXTRACT_CHARS = 40_000;
39
+ // ─── Format model ───────────────────────────────────────────────────────────
40
+ /** Formats with a working extractor. */
41
+ const IMPLEMENTED_FORMATS = new Set([
42
+ '.txt', '.md', '.markdown', '.text', '.log',
43
+ '.html', '.htm', '.csv', '.tsv', '.json', '.xml', '.yaml', '.yml',
44
+ '.pdf', '.docx', '.xlsx', '.pptx',
45
+ ]);
46
+ /**
47
+ * Formats the tool does not read, with the reason surfaced to the model. Kept as a
48
+ * map so the gap is explicit and greppable rather than implied by a missing `case`.
49
+ */
50
+ const PENDING_FORMATS = new Map([
51
+ ['.doc', 'Legacy binary Word (.doc) is not supported — only the OOXML .docx container.'],
52
+ ['.xls', 'Legacy binary Excel (.xls) is not supported — only the OOXML .xlsx container.'],
53
+ ['.ppt', 'Legacy binary PowerPoint (.ppt) is not supported — only the OOXML .pptx container.'],
54
+ ['.rtf', 'RTF is not supported.'],
55
+ ['.odt', 'ODF (.odt) is not supported — only OOXML .docx.'],
56
+ ['.ods', 'ODF (.ods) is not supported — only OOXML .xlsx.'],
57
+ ]);
58
+ /** What to do instead, per unsupported format. */
59
+ const PENDING_ALTERNATIVES = {
60
+ '.doc': ['Save as .docx and read that', 'Convert with LibreOffice (`soffice --convert-to docx`)'],
61
+ '.xls': ['Save as .xlsx or CSV and read that'],
62
+ '.ppt': ['Save as .pptx and read that'],
63
+ '.rtf': ['Save as .docx or plain text and read that'],
64
+ '.odt': ['Save as .docx and read that'],
65
+ '.ods': ['Save as .xlsx or CSV and read that'],
66
+ };
67
+ /** Container formats whose reader is loaded on demand. */
68
+ const CONTAINER_FORMATS = new Set(['.pdf', '.docx', '.xlsx', '.pptx']);
15
69
  // ─── Read Extract Manager ───────────────────────────────────────────────────
16
70
  class ReadExtractManager {
17
- supportedFormats = new Set([
18
- '.txt', '.md', '.markdown', '.html', '.htm', '.csv', '.json', '.xml', '.yaml', '.yml',
19
- '.pdf', '.docx', '.xlsx', '.pptx',
20
- ]);
21
71
  /**
22
- * Extract text from a file.
72
+ * Extract text from a file. Never throws: an unreadable, unsupported or
73
+ * package-less format comes back as `success: false` with a typed `code`.
23
74
  */
24
- async extract(filePath) {
75
+ async extract(filePath, opts = {}) {
25
76
  const ext = path.extname(filePath).toLowerCase();
26
- if (!this.supportedFormats.has(ext)) {
77
+ if (PENDING_FORMATS.has(ext)) {
78
+ return this.refused(ext, PENDING_FORMATS.get(ext), PENDING_ALTERNATIVES[ext] ?? []);
79
+ }
80
+ if (!IMPLEMENTED_FORMATS.has(ext)) {
81
+ // An image is a common arrival here (usually from a chat attachment). The reader
82
+ // cannot transcribe it, but a vision backend can — so say that plainly rather
83
+ // than only listing the formats this module knows.
84
+ const isImage = /^\.(png|jpe?g|gif|webp|bmp|tiff?)$/i.test(ext);
85
+ return this.refused(ext || '(no extension)', `Unsupported format: ${ext || '(no extension)'}.`, isImage
86
+ ? [
87
+ 'Use describe_image — a vision backend can read this image directly',
88
+ `Readable text formats: ${this.getSupportedFormats().join(', ')}`,
89
+ ]
90
+ : [`Readable formats: ${this.getSupportedFormats().join(', ')}`]);
91
+ }
92
+ if (!fs.existsSync(filePath)) {
27
93
  return {
28
94
  text: '',
29
95
  format: ext,
30
96
  success: false,
31
- error: `Unsupported format: ${ext}. Supported: ${Array.from(this.supportedFormats).join(', ')}`,
97
+ code: 'no_data',
98
+ error: `No such file: ${filePath}`,
99
+ alternatives: ['Check the path (it is resolved relative to the workspace)'],
32
100
  };
33
101
  }
34
102
  try {
@@ -36,12 +104,15 @@ class ReadExtractManager {
36
104
  case '.txt':
37
105
  case '.md':
38
106
  case '.markdown':
107
+ case '.text':
108
+ case '.log':
39
109
  return this.extractPlainText(filePath);
40
110
  case '.html':
41
111
  case '.htm':
42
112
  return this.extractHTML(filePath);
43
113
  case '.csv':
44
- return this.extractCSV(filePath);
114
+ case '.tsv':
115
+ return this.extractDelimited(filePath, ext === '.tsv' ? '\t' : ',');
45
116
  case '.json':
46
117
  return this.extractJSON(filePath);
47
118
  case '.xml':
@@ -50,15 +121,15 @@ class ReadExtractManager {
50
121
  case '.yml':
51
122
  return this.extractYAML(filePath);
52
123
  case '.pdf':
53
- return this.extractPDF(filePath);
124
+ return await this.extractPdf(filePath, opts);
54
125
  case '.docx':
55
- return this.extractDOCX(filePath);
126
+ return await this.extractDocx(filePath);
56
127
  case '.xlsx':
57
- return this.extractXLSX(filePath);
128
+ return await this.extractXlsx(filePath);
58
129
  case '.pptx':
59
- return this.extractPPTX(filePath);
130
+ return await this.extractPptx(filePath);
60
131
  default:
61
- return { text: '', format: ext, success: false, error: 'Unknown format' };
132
+ return this.refused(ext, `Unsupported format: ${ext}`, []);
62
133
  }
63
134
  }
64
135
  catch (err) {
@@ -66,200 +137,465 @@ class ReadExtractManager {
66
137
  text: '',
67
138
  format: ext,
68
139
  success: false,
69
- error: err.message,
140
+ code: 'unavailable',
141
+ error: err?.message ? String(err.message) : String(err),
70
142
  };
71
143
  }
72
144
  }
73
- /**
74
- * Extract plain text.
75
- */
76
- extractPlainText(filePath) {
77
- const content = fs.readFileSync(filePath, 'utf-8');
78
- return {
79
- text: content,
80
- format: 'text',
81
- success: true,
82
- metadata: {
83
- words: content.split(/\s+/).length,
84
- },
85
- };
86
- }
87
- /**
88
- * Extract HTML to text.
89
- */
90
- extractHTML(filePath) {
91
- const content = fs.readFileSync(filePath, 'utf-8');
92
- // Simple HTML to text conversion
93
- const text = content
94
- .replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '')
95
- .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, '')
96
- .replace(/<[^>]+>/g, ' ')
97
- .replace(/\s+/g, ' ')
98
- .trim();
99
- return {
100
- text,
101
- format: 'html',
102
- success: true,
103
- metadata: {
104
- words: text.split(/\s+/).length,
105
- },
106
- };
107
- }
108
- /**
109
- * Extract CSV to text.
110
- */
111
- extractCSV(filePath) {
112
- const content = fs.readFileSync(filePath, 'utf-8');
113
- const lines = content.split('\n').filter((l) => l.trim());
114
- // Simple CSV to text
115
- const text = lines.map((line) => {
116
- const cells = line.split(',').map((c) => c.trim());
117
- return cells.join(' | ');
118
- }).join('\n');
145
+ // ─── Container extractors ─────────────────────────────────────────────────
146
+ async extractPdf(filePath, opts = {}) {
147
+ let mod;
148
+ try {
149
+ mod = await import('./extract/pdf.js');
150
+ }
151
+ catch (err) {
152
+ return this.notConfigured('.pdf', 'the PDF reader (pdfjs-dist)', err);
153
+ }
154
+ let result;
155
+ try {
156
+ result = await mod.extractPdfText(new Uint8Array(fs.readFileSync(filePath)), {
157
+ maxChars: MAX_EXTRACT_CHARS,
158
+ });
159
+ }
160
+ catch (err) {
161
+ const encrypted = err instanceof mod.PdfExtractError && err.encrypted;
162
+ return {
163
+ text: '',
164
+ format: 'pdf',
165
+ success: false,
166
+ code: 'unavailable',
167
+ error: err instanceof Error ? err.message : String(err),
168
+ alternatives: encrypted
169
+ ? ['Remove the password (print/export to a new PDF) and read that']
170
+ : ['Re-export the PDF', 'Send the pages as screenshots so describe_image can read them'],
171
+ };
172
+ }
173
+ // No page yielded text: a scanned document, not an empty one. Reported as a
174
+ // typed refusal because "success with empty text" is the defect this workstream
175
+ // removed — a caller cannot act on it.
176
+ if (result.pagesWithText === 0) {
177
+ return this.scannedPdfResult(filePath, result, opts);
178
+ }
119
179
  return {
120
- text,
121
- format: 'csv',
180
+ text: result.text,
181
+ format: 'pdf',
122
182
  success: true,
123
183
  metadata: {
124
- words: text.split(/\s+/).length,
184
+ pages: result.pages,
185
+ pagesWithText: result.pagesWithText,
186
+ words: countWords(result.text),
187
+ truncated: result.truncated,
188
+ ...(result.pagesWithoutText.length > 0
189
+ ? { warnings: [`Page(s) ${result.pagesWithoutText.join(', ')} have no text layer (scanned images).`] }
190
+ : {}),
125
191
  },
126
192
  };
127
193
  }
128
- /**
129
- * Extract JSON to text.
130
- */
131
- extractJSON(filePath) {
132
- const content = fs.readFileSync(filePath, 'utf-8');
194
+ async extractDocx(filePath) {
195
+ let mod;
133
196
  try {
134
- const data = JSON.parse(content);
135
- const text = JSON.stringify(data, null, 2);
197
+ mod = await import('./extract/docx.js');
198
+ }
199
+ catch (err) {
200
+ return this.notConfigured('.docx', 'the DOCX reader (mammoth)', err);
201
+ }
202
+ try {
203
+ const result = await mod.extractDocxText(fs.readFileSync(filePath), { maxChars: MAX_EXTRACT_CHARS });
136
204
  return {
137
- text,
138
- format: 'json',
205
+ text: result.text,
206
+ format: 'docx',
139
207
  success: true,
208
+ metadata: {
209
+ words: countWords(result.text),
210
+ truncated: result.truncated,
211
+ ...(result.warnings.length > 0 ? { warnings: result.warnings } : {}),
212
+ },
140
213
  };
141
214
  }
142
- catch {
215
+ catch (err) {
143
216
  return {
144
- text: content,
145
- format: 'json',
146
- success: true,
217
+ text: '',
218
+ format: 'docx',
219
+ success: false,
220
+ code: 'unavailable',
221
+ error: err instanceof Error ? err.message : String(err),
222
+ alternatives: ['Re-export the document', 'Save it as .txt or .md and read that'],
147
223
  };
148
224
  }
149
225
  }
150
- /**
151
- * Extract XML to text.
152
- */
153
- extractXML(filePath) {
154
- const content = fs.readFileSync(filePath, 'utf-8');
155
- // Simple XML to text
156
- const text = content
157
- .replace(/<[^>]+>/g, ' ')
158
- .replace(/\s+/g, ' ')
159
- .trim();
160
- return {
161
- text,
162
- format: 'xml',
163
- success: true,
164
- };
165
- }
166
- /**
167
- * Extract YAML to text.
168
- */
169
- extractYAML(filePath) {
170
- const content = fs.readFileSync(filePath, 'utf-8');
171
- return {
172
- text: content,
173
- format: 'yaml',
174
- success: true,
175
- };
226
+ async extractXlsx(filePath) {
227
+ let mod;
228
+ try {
229
+ mod = await import('./extract/xlsx.js');
230
+ }
231
+ catch (err) {
232
+ return this.notConfigured('.xlsx', 'the spreadsheet reader (SheetJS)', err);
233
+ }
234
+ try {
235
+ const result = await mod.extractXlsxText(fs.readFileSync(filePath), { maxChars: MAX_EXTRACT_CHARS });
236
+ if (result.text.trim().length === 0) {
237
+ return {
238
+ text: '',
239
+ format: 'xlsx',
240
+ success: false,
241
+ code: 'no_data',
242
+ error: `The workbook has ${result.sheets.length} sheet(s) but no non-empty cells.`,
243
+ alternatives: ['Check the sheet is not empty, or export it as CSV'],
244
+ metadata: { sheets: result.sheets },
245
+ };
246
+ }
247
+ return {
248
+ text: result.text,
249
+ format: 'xlsx',
250
+ success: true,
251
+ metadata: {
252
+ sheets: result.sheets,
253
+ rows: result.rows,
254
+ words: countWords(result.text),
255
+ truncated: result.truncated,
256
+ ...(result.skippedSheets.length > 0
257
+ ? { warnings: [`Sheet(s) not read (character budget): ${result.skippedSheets.join(', ')}`] }
258
+ : {}),
259
+ },
260
+ };
261
+ }
262
+ catch (err) {
263
+ return {
264
+ text: '',
265
+ format: 'xlsx',
266
+ success: false,
267
+ code: 'unavailable',
268
+ error: err instanceof Error ? err.message : String(err),
269
+ alternatives: ['Re-export the workbook', 'Export the sheet as CSV and read that'],
270
+ };
271
+ }
176
272
  }
177
- /**
178
- * Extract PDF (simplified - actual PDF extraction requires pdf-parse library).
179
- */
180
- extractPDF(filePath) {
181
- // Simplified PDF extraction
182
- // In production, use pdf-parse library
273
+ async extractPptx(filePath) {
274
+ let mod;
183
275
  try {
184
- const content = fs.readFileSync(filePath, 'utf-8');
185
- // Attempt to extract readable text
186
- const text = content
187
- .replace(/[^\x20-\x7E\n]/g, ' ')
188
- .replace(/\s+/g, ' ')
189
- .trim();
276
+ mod = await import('./extract/pptx.js');
277
+ }
278
+ catch (err) {
279
+ return this.notConfigured('.pptx', 'the ZIP reader (fflate)', err);
280
+ }
281
+ try {
282
+ const result = await mod.extractPptxText(fs.readFileSync(filePath), { maxChars: MAX_EXTRACT_CHARS });
283
+ if (result.text.trim().length === 0) {
284
+ return {
285
+ text: '',
286
+ format: 'pptx',
287
+ success: false,
288
+ code: 'no_data',
289
+ error: `All ${result.slides} slide(s) are text-free (images only).`,
290
+ alternatives: ['Send the slides as screenshots so the vision model can read them'],
291
+ metadata: { slides: result.slides },
292
+ };
293
+ }
190
294
  return {
191
- text: text.slice(0, 10000), // Limit to 10K chars
192
- format: 'pdf',
295
+ text: result.text,
296
+ format: 'pptx',
193
297
  success: true,
194
298
  metadata: {
195
- words: text.split(/\s+/).length,
299
+ slides: result.slides,
300
+ words: countWords(result.text),
301
+ truncated: result.truncated,
302
+ ...(result.emptySlides.length > 0
303
+ ? { warnings: [`Slide(s) with no text: ${result.emptySlides.join(', ')}`] }
304
+ : {}),
196
305
  },
197
306
  };
198
307
  }
199
- catch {
308
+ catch (err) {
200
309
  return {
201
310
  text: '',
202
- format: 'pdf',
311
+ format: 'pptx',
203
312
  success: false,
204
- error: 'PDF extraction requires pdf-parse library',
313
+ code: 'unavailable',
314
+ error: err instanceof Error ? err.message : String(err),
315
+ alternatives: ['Re-export the presentation', 'Export the slides as images'],
205
316
  };
206
317
  }
207
318
  }
208
319
  /**
209
- * Extract DOCX (simplified - actual DOCX extraction requires docx library).
320
+ * A PDF with no text layer: either transcribe it (when the caller asked for OCR and
321
+ * the route is available) or refuse with the way to ask. Both outcomes are explicit.
210
322
  */
211
- extractDOCX(filePath) {
212
- // Simplified DOCX extraction
213
- // In production, use docx or mammoth library
323
+ async scannedPdfResult(filePath, result, opts) {
324
+ const base = {
325
+ pages: result.pages,
326
+ pagesWithText: 0,
327
+ truncated: result.truncated,
328
+ };
329
+ const alternatives = [
330
+ opts.ocr
331
+ ? 'Install a PDF rasteriser (Poppler: pdftoppm/pdftocairo) and configure a vision backend'
332
+ : 'Call read_extract again with ocr:true to transcribe the pages with the vision model',
333
+ 'Send the page as a screenshot so the vision model can read it (describe_image)',
334
+ 'Paste the report text',
335
+ ];
336
+ if (!opts.ocr) {
337
+ return {
338
+ text: '',
339
+ format: 'pdf',
340
+ success: false,
341
+ code: 'no_data',
342
+ error: `The PDF has ${result.pages} page(s) but no text layer — it is a scan/image, so there is no text to extract.`,
343
+ alternatives,
344
+ metadata: base,
345
+ };
346
+ }
347
+ // OCR was requested — attempt it, and if a prerequisite is missing say WHICH.
214
348
  try {
215
- const content = fs.readFileSync(filePath, 'utf-8');
216
- const text = content
217
- .replace(/<[^>]+>/g, ' ')
218
- .replace(/\s+/g, ' ')
219
- .trim();
349
+ const ocr = await import('./extract/pdf-ocr.js');
350
+ const transcribed = await ocr.ocrScannedPdf(filePath, result.pages, opts.ocrOptions ?? {});
220
351
  return {
221
- text: text.slice(0, 10000),
222
- format: 'docx',
352
+ text: transcribed.text,
353
+ format: 'pdf',
223
354
  success: true,
355
+ metadata: {
356
+ ...base,
357
+ ocr: true,
358
+ ocrRenderer: transcribed.renderer,
359
+ words: countWords(transcribed.text),
360
+ truncated: transcribed.truncated,
361
+ warnings: [
362
+ 'Text recovered by OCR from rendered page images — a transcription, not a parsed '
363
+ + 'text layer. Verify digits (lab values, dates, doses) against the original.',
364
+ ],
365
+ },
224
366
  };
225
367
  }
226
- catch {
368
+ catch (err) {
369
+ const ocr = await import('./extract/pdf-ocr.js');
370
+ const code = err instanceof ocr.PdfOcrError ? err.code : 'unavailable';
227
371
  return {
228
372
  text: '',
229
- format: 'docx',
373
+ format: 'pdf',
230
374
  success: false,
231
- error: 'DOCX extraction requires mammoth library',
375
+ code,
376
+ error: err instanceof Error ? err.message : String(err),
377
+ alternatives,
378
+ metadata: base,
232
379
  };
233
380
  }
234
381
  }
235
- /**
236
- * Extract XLSX (simplified).
237
- */
238
- extractXLSX(filePath) {
382
+ /** An optional reader that failed to load is a typed refusal, never a silent gap. */
383
+ notConfigured(format, what, err) {
239
384
  return {
240
385
  text: '',
241
- format: 'xlsx',
386
+ format,
242
387
  success: false,
243
- error: 'XLSX extraction requires xlsx library',
388
+ error: `${what} is not available in this install, so ${format} could not be read (${err instanceof Error ? err.message : String(err)}).`,
389
+ ...refusalFields('not_configured', [`Reinstall dependencies (npm install) to restore ${what}`]),
244
390
  };
245
391
  }
246
- /**
247
- * Extract PPTX (simplified).
248
- */
249
- extractPPTX(filePath) {
392
+ /** A refusal in the module's result shape (empty text, no fabricated metadata). */
393
+ refused(format, reason, alternatives) {
250
394
  return {
251
395
  text: '',
252
- format: 'pptx',
396
+ format,
253
397
  success: false,
254
- error: 'PPTX extraction requires pptx library',
398
+ error: reason,
399
+ ...refusalFields('unsupported_format', alternatives),
400
+ };
401
+ }
402
+ // ─── Text extractors ──────────────────────────────────────────────────────
403
+ /**
404
+ * A NUL byte in the first 8 KB means the file is not text, whatever extension it
405
+ * carries — the same probe `read_file` uses (`coding-tools.ts:looksBinary`). Without
406
+ * it a mislabelled binary reaches the model as mojibake, which is the very class
407
+ * of defect this module now refuses.
408
+ */
409
+ looksBinary(filePath) {
410
+ const fd = fs.openSync(filePath, 'r');
411
+ try {
412
+ const probe = Buffer.alloc(8192);
413
+ const read = fs.readSync(fd, probe, 0, probe.length, 0);
414
+ return probe.subarray(0, read).includes(0);
415
+ }
416
+ finally {
417
+ fs.closeSync(fd);
418
+ }
419
+ }
420
+ extractPlainText(filePath) {
421
+ if (this.looksBinary(filePath)) {
422
+ return this.refused('text', `'${path.basename(filePath)}' looks binary (a text/Markdown file with NUL bytes) — its bytes are not text.`, ['Check the real file type and use the matching reader']);
423
+ }
424
+ const content = fs.readFileSync(filePath, 'utf-8');
425
+ const truncated = content.length > MAX_EXTRACT_CHARS;
426
+ return {
427
+ text: truncated ? `${content.slice(0, MAX_EXTRACT_CHARS)}\n…[truncated]` : content,
428
+ format: 'text',
429
+ success: true,
430
+ metadata: {
431
+ words: countWords(content),
432
+ truncated,
433
+ },
434
+ };
435
+ }
436
+ /**
437
+ * HTML → text. Structure-preserving (`htmlToText`): cells stay on one line so a
438
+ * table's value/column pairing survives. Layout (CSS) is not reconstructed and is
439
+ * not claimed to be.
440
+ */
441
+ extractHTML(filePath) {
442
+ const text = htmlToText(fs.readFileSync(filePath, 'utf-8'));
443
+ const truncated = text.length > MAX_EXTRACT_CHARS;
444
+ return {
445
+ text: truncated ? `${text.slice(0, MAX_EXTRACT_CHARS)}\n…[truncated]` : text,
446
+ format: 'html',
447
+ success: true,
448
+ metadata: {
449
+ words: countWords(text),
450
+ truncated,
451
+ },
255
452
  };
256
453
  }
257
454
  /**
258
- * Get supported formats.
455
+ * CSV/TSV → text, with RFC 4180 quoting rules rather than `split(',')`. The naive
456
+ * split silently corrupted any row containing a quoted separator — a lab row like
457
+ * `Glucose,112,"HIGH, range 70-99"` became four fields with the reference range torn
458
+ * apart, while the result still reported success.
259
459
  */
460
+ extractDelimited(filePath, delimiter) {
461
+ const content = fs.readFileSync(filePath, 'utf-8');
462
+ const lines = content.split(/\r?\n/).filter((l) => l.trim());
463
+ const rows = lines.map((line) => parseDelimitedRow(line, delimiter));
464
+ // Rows stay themselves — separated by newlines, cells by ` | ` — so the table
465
+ // shape the file encoded is the shape the model reads.
466
+ const text = rows.map((cells) => cells.join(' | ')).join('\n');
467
+ const truncated = text.length > MAX_EXTRACT_CHARS;
468
+ return {
469
+ text: truncated ? `${text.slice(0, MAX_EXTRACT_CHARS)}\n…[truncated]` : text,
470
+ format: delimiter === '\t' ? 'tsv' : 'csv',
471
+ success: true,
472
+ metadata: {
473
+ words: countWords(text),
474
+ rows: rows.length,
475
+ truncated,
476
+ },
477
+ };
478
+ }
479
+ extractJSON(filePath) {
480
+ const content = fs.readFileSync(filePath, 'utf-8');
481
+ let text;
482
+ let valid = true;
483
+ try {
484
+ text = JSON.stringify(JSON.parse(content), null, 2);
485
+ }
486
+ catch {
487
+ // Not valid JSON — return the raw text, and say so rather than implying a parse.
488
+ text = content;
489
+ valid = false;
490
+ }
491
+ const truncated = text.length > MAX_EXTRACT_CHARS;
492
+ return {
493
+ text: truncated ? `${text.slice(0, MAX_EXTRACT_CHARS)}\n…[truncated]` : text,
494
+ format: 'json',
495
+ success: true,
496
+ metadata: {
497
+ truncated,
498
+ // A success result never carries an `error` string: the two together are
499
+ // exactly the ambiguity ("did it work?") this module removes.
500
+ ...(valid ? {} : { warnings: ['File is not valid JSON — raw text returned'] }),
501
+ },
502
+ };
503
+ }
504
+ extractXML(filePath) {
505
+ const content = fs.readFileSync(filePath, 'utf-8');
506
+ const text = htmlToText(content);
507
+ const truncated = text.length > MAX_EXTRACT_CHARS;
508
+ return {
509
+ text: truncated ? `${text.slice(0, MAX_EXTRACT_CHARS)}\n…[truncated]` : text,
510
+ format: 'xml',
511
+ success: true,
512
+ metadata: { words: countWords(text), truncated },
513
+ };
514
+ }
515
+ extractYAML(filePath) {
516
+ const content = fs.readFileSync(filePath, 'utf-8');
517
+ const truncated = content.length > MAX_EXTRACT_CHARS;
518
+ return {
519
+ text: truncated ? `${content.slice(0, MAX_EXTRACT_CHARS)}\n…[truncated]` : content,
520
+ format: 'yaml',
521
+ success: true,
522
+ metadata: { words: countWords(content), truncated },
523
+ };
524
+ }
525
+ // ─── Capability surface ───────────────────────────────────────────────────
526
+ /** Formats with a working extractor. Feeds the tool description. */
260
527
  getSupportedFormats() {
261
- return Array.from(this.supportedFormats);
528
+ return Array.from(IMPLEMENTED_FORMATS);
529
+ }
530
+ /** Formats the description does not advertise because nothing reads them. */
531
+ getPendingFormats() {
532
+ return Array.from(PENDING_FORMATS, ([format, reason]) => ({ format, reason }));
533
+ }
534
+ /** Whether a specific path's extension has a working extractor. */
535
+ isFormatAvailable(filePath) {
536
+ return IMPLEMENTED_FORMATS.has(path.extname(filePath).toLowerCase());
537
+ }
538
+ /** Whether a path's format needs a heavy on-demand reader. */
539
+ isContainerFormat(filePath) {
540
+ return CONTAINER_FORMATS.has(path.extname(filePath).toLowerCase());
541
+ }
542
+ }
543
+ // ─── Helpers ────────────────────────────────────────────────────────────────
544
+ function countWords(text) {
545
+ return text.split(/\s+/).filter(Boolean).length;
546
+ }
547
+ /**
548
+ * Split one delimited line into fields, honouring `"…"` quoting and escaped `""`.
549
+ * Exported for tests. `parseCsvRow` is kept as the comma-specific alias.
550
+ */
551
+ export function parseDelimitedRow(line, delimiter = ',') {
552
+ const cells = [];
553
+ let field = '';
554
+ let inQuotes = false;
555
+ for (let i = 0; i < line.length; i++) {
556
+ const ch = line[i];
557
+ if (inQuotes) {
558
+ if (ch === '"') {
559
+ if (line[i + 1] === '"') {
560
+ field += '"';
561
+ i++;
562
+ }
563
+ else
564
+ inQuotes = false;
565
+ }
566
+ else {
567
+ field += ch;
568
+ }
569
+ }
570
+ else if (ch === '"') {
571
+ inQuotes = true;
572
+ }
573
+ else if (ch === delimiter) {
574
+ cells.push(field.trim());
575
+ field = '';
576
+ }
577
+ else {
578
+ field += ch;
579
+ }
262
580
  }
581
+ cells.push(field.trim());
582
+ return cells;
583
+ }
584
+ /** CSV-specific alias (kept for callers/tests that name the comma case). */
585
+ export function parseCsvRow(line) {
586
+ return parseDelimitedRow(line, ',');
587
+ }
588
+ /**
589
+ * Probe mirrored into the `read_extract` tool description: true when the path's
590
+ * format can actually be extracted. Callers use it to choose a tool *before*
591
+ * spending a step on a refusal.
592
+ */
593
+ export function isReadExtractAvailable(filePath) {
594
+ return getReadExtractManager().isFormatAvailable(filePath);
595
+ }
596
+ /** Formats with a working extractor (module-level convenience). */
597
+ export function getReadExtractFormats() {
598
+ return getReadExtractManager().getSupportedFormats();
263
599
  }
264
600
  // ─── Singleton ──────────────────────────────────────────────────────────────
265
601
  let _instance = null;
@@ -268,5 +604,5 @@ export function getReadExtractManager() {
268
604
  _instance = new ReadExtractManager();
269
605
  return _instance;
270
606
  }
271
- export { ReadExtractManager };
607
+ export { ReadExtractManager, MAX_EXTRACT_CHARS };
272
608
  //# sourceMappingURL=read-extract.js.map