p-spore 0.1.4 → 0.1.42

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 (393) hide show
  1. package/README.md +110 -15
  2. package/dist/agents/agent-manager.d.ts +3 -3
  3. package/dist/agents/agent-manager.d.ts.map +1 -1
  4. package/dist/agents/agent-manager.js +3 -2
  5. package/dist/agents/agent-manager.js.map +1 -1
  6. package/dist/application/agent-application.d.ts +29 -5
  7. package/dist/application/agent-application.d.ts.map +1 -1
  8. package/dist/application/agent-application.js +444 -14
  9. package/dist/application/agent-application.js.map +1 -1
  10. package/dist/articles/diff.d.ts +70 -0
  11. package/dist/articles/diff.d.ts.map +1 -0
  12. package/dist/articles/diff.js +330 -0
  13. package/dist/articles/diff.js.map +1 -0
  14. package/dist/articles/docx.d.ts +10 -0
  15. package/dist/articles/docx.d.ts.map +1 -0
  16. package/dist/articles/docx.js +219 -0
  17. package/dist/articles/docx.js.map +1 -0
  18. package/dist/articles/draft.d.ts +18 -0
  19. package/dist/articles/draft.d.ts.map +1 -0
  20. package/dist/articles/draft.js +88 -0
  21. package/dist/articles/draft.js.map +1 -0
  22. package/dist/articles/edits.d.ts +24 -0
  23. package/dist/articles/edits.d.ts.map +1 -0
  24. package/dist/articles/edits.js +54 -0
  25. package/dist/articles/edits.js.map +1 -0
  26. package/dist/articles/html.d.ts +10 -0
  27. package/dist/articles/html.d.ts.map +1 -0
  28. package/dist/articles/html.js +122 -0
  29. package/dist/articles/html.js.map +1 -0
  30. package/dist/articles/plain.d.ts +8 -0
  31. package/dist/articles/plain.d.ts.map +1 -0
  32. package/dist/articles/plain.js +69 -0
  33. package/dist/articles/plain.js.map +1 -0
  34. package/dist/articles/preview.d.ts +43 -0
  35. package/dist/articles/preview.d.ts.map +1 -0
  36. package/dist/articles/preview.js +90 -0
  37. package/dist/articles/preview.js.map +1 -0
  38. package/dist/articles/publish.d.ts +10 -0
  39. package/dist/articles/publish.d.ts.map +1 -0
  40. package/dist/articles/publish.js +54 -0
  41. package/dist/articles/publish.js.map +1 -0
  42. package/dist/articles/receipt.d.ts +16 -0
  43. package/dist/articles/receipt.d.ts.map +1 -0
  44. package/dist/articles/receipt.js +27 -0
  45. package/dist/articles/receipt.js.map +1 -0
  46. package/dist/articles/store.d.ts +78 -0
  47. package/dist/articles/store.d.ts.map +1 -0
  48. package/dist/articles/store.js +308 -0
  49. package/dist/articles/store.js.map +1 -0
  50. package/dist/articles/tool.d.ts +14 -0
  51. package/dist/articles/tool.d.ts.map +1 -0
  52. package/dist/articles/tool.js +175 -0
  53. package/dist/articles/tool.js.map +1 -0
  54. package/dist/articles/writer-context.d.ts +5 -0
  55. package/dist/articles/writer-context.d.ts.map +1 -0
  56. package/dist/articles/writer-context.js +56 -0
  57. package/dist/articles/writer-context.js.map +1 -0
  58. package/dist/articles/writer.d.ts +18 -0
  59. package/dist/articles/writer.d.ts.map +1 -0
  60. package/dist/articles/writer.js +79 -0
  61. package/dist/articles/writer.js.map +1 -0
  62. package/dist/articles/zip-write.d.ts +11 -0
  63. package/dist/articles/zip-write.d.ts.map +1 -0
  64. package/dist/articles/zip-write.js +63 -0
  65. package/dist/articles/zip-write.js.map +1 -0
  66. package/dist/bundled-skills/README.md +17 -0
  67. package/dist/bundled-skills/aegis-search/SKILL.md +59 -0
  68. package/dist/bundled-skills/aegis-search/bin/.gitkeep +0 -0
  69. package/dist/bundled-skills/article-canvas/SKILL.md +28 -0
  70. package/dist/bundled-skills/binaries.json +23 -0
  71. package/dist/bundled-skills/doc-extract/SKILL.md +56 -0
  72. package/dist/cli/main.d.ts.map +1 -1
  73. package/dist/cli/main.js +407 -54
  74. package/dist/cli/main.js.map +1 -1
  75. package/dist/config/config.d.ts +43 -0
  76. package/dist/config/config.d.ts.map +1 -1
  77. package/dist/config/config.js +150 -6
  78. package/dist/config/config.js.map +1 -1
  79. package/dist/daemon/daemon.d.ts.map +1 -1
  80. package/dist/daemon/daemon.js +80 -11
  81. package/dist/daemon/daemon.js.map +1 -1
  82. package/dist/desktop/application.d.ts +4 -0
  83. package/dist/desktop/application.d.ts.map +1 -0
  84. package/dist/desktop/application.js +1688 -0
  85. package/dist/desktop/application.js.map +1 -0
  86. package/dist/desktop/article-export.d.ts +12 -0
  87. package/dist/desktop/article-export.d.ts.map +1 -0
  88. package/dist/desktop/article-export.js +87 -0
  89. package/dist/desktop/article-export.js.map +1 -0
  90. package/dist/desktop/assets/pspore.png +0 -0
  91. package/dist/desktop/assets/pspore.svg +24 -0
  92. package/dist/desktop/conversation-smoke.d.ts +5 -0
  93. package/dist/desktop/conversation-smoke.d.ts.map +1 -0
  94. package/dist/desktop/conversation-smoke.js +93 -0
  95. package/dist/desktop/conversation-smoke.js.map +1 -0
  96. package/dist/desktop/daemon-bridge.d.ts.map +1 -1
  97. package/dist/desktop/daemon-bridge.js +62 -17
  98. package/dist/desktop/daemon-bridge.js.map +1 -1
  99. package/dist/desktop/ipc-contract.d.ts +124 -0
  100. package/dist/desktop/ipc-contract.d.ts.map +1 -1
  101. package/dist/desktop/ipc-contract.js +191 -12
  102. package/dist/desktop/ipc-contract.js.map +1 -1
  103. package/dist/desktop/local-path.d.ts +15 -0
  104. package/dist/desktop/local-path.d.ts.map +1 -0
  105. package/dist/desktop/local-path.js +59 -0
  106. package/dist/desktop/local-path.js.map +1 -0
  107. package/dist/desktop/main.d.ts +10 -1
  108. package/dist/desktop/main.d.ts.map +1 -1
  109. package/dist/desktop/main.js +122 -530
  110. package/dist/desktop/main.js.map +1 -1
  111. package/dist/desktop/native-startup.d.ts +4 -0
  112. package/dist/desktop/native-startup.d.ts.map +1 -0
  113. package/dist/desktop/native-startup.js +57 -0
  114. package/dist/desktop/native-startup.js.map +1 -0
  115. package/dist/desktop/preload.cjs +28 -1
  116. package/dist/desktop/renderer/article-panel.d.ts +45 -0
  117. package/dist/desktop/renderer/article-panel.d.ts.map +1 -0
  118. package/dist/desktop/renderer/article-panel.js +1126 -0
  119. package/dist/desktop/renderer/article-panel.js.map +1 -0
  120. package/dist/desktop/renderer/article-split.d.ts +32 -0
  121. package/dist/desktop/renderer/article-split.d.ts.map +1 -0
  122. package/dist/desktop/renderer/article-split.js +48 -0
  123. package/dist/desktop/renderer/article-split.js.map +1 -0
  124. package/dist/desktop/renderer/composer-file-references.d.ts +23 -0
  125. package/dist/desktop/renderer/composer-file-references.d.ts.map +1 -0
  126. package/dist/desktop/renderer/composer-file-references.js +51 -0
  127. package/dist/desktop/renderer/composer-file-references.js.map +1 -0
  128. package/dist/desktop/renderer/conversation.d.ts +23 -0
  129. package/dist/desktop/renderer/conversation.d.ts.map +1 -0
  130. package/dist/desktop/renderer/conversation.js +66 -0
  131. package/dist/desktop/renderer/conversation.js.map +1 -0
  132. package/dist/desktop/renderer/dom-reconcile.d.ts +15 -0
  133. package/dist/desktop/renderer/dom-reconcile.d.ts.map +1 -0
  134. package/dist/desktop/renderer/dom-reconcile.js +33 -0
  135. package/dist/desktop/renderer/dom-reconcile.js.map +1 -0
  136. package/dist/desktop/renderer/index.html +211 -34
  137. package/dist/desktop/renderer/indexing-view.d.ts +22 -0
  138. package/dist/desktop/renderer/indexing-view.d.ts.map +1 -0
  139. package/dist/desktop/renderer/indexing-view.js +115 -0
  140. package/dist/desktop/renderer/indexing-view.js.map +1 -0
  141. package/dist/desktop/renderer/markdown-view.d.ts +23 -0
  142. package/dist/desktop/renderer/markdown-view.d.ts.map +1 -0
  143. package/dist/desktop/renderer/markdown-view.js +436 -0
  144. package/dist/desktop/renderer/markdown-view.js.map +1 -0
  145. package/dist/desktop/renderer/motion.d.ts +67 -0
  146. package/dist/desktop/renderer/motion.d.ts.map +1 -0
  147. package/dist/desktop/renderer/motion.js +296 -0
  148. package/dist/desktop/renderer/motion.js.map +1 -0
  149. package/dist/desktop/renderer/renderer.js +1788 -151
  150. package/dist/desktop/renderer/renderer.js.map +1 -1
  151. package/dist/desktop/renderer/session-find.d.ts +18 -0
  152. package/dist/desktop/renderer/session-find.d.ts.map +1 -0
  153. package/dist/desktop/renderer/session-find.js +29 -0
  154. package/dist/desktop/renderer/session-find.js.map +1 -0
  155. package/dist/desktop/renderer/session-search.d.ts +30 -0
  156. package/dist/desktop/renderer/session-search.d.ts.map +1 -0
  157. package/dist/desktop/renderer/session-search.js +296 -0
  158. package/dist/desktop/renderer/session-search.js.map +1 -0
  159. package/dist/desktop/renderer/store.d.ts +33 -0
  160. package/dist/desktop/renderer/store.d.ts.map +1 -1
  161. package/dist/desktop/renderer/store.js +92 -19
  162. package/dist/desktop/renderer/store.js.map +1 -1
  163. package/dist/desktop/renderer/styles.css +910 -268
  164. package/dist/desktop/renderer/vendor/gsap.min.js +11 -0
  165. package/dist/desktop/renderer-diagnostics.d.ts +5 -0
  166. package/dist/desktop/renderer-diagnostics.d.ts.map +1 -0
  167. package/dist/desktop/renderer-diagnostics.js +47 -0
  168. package/dist/desktop/renderer-diagnostics.js.map +1 -0
  169. package/dist/desktop/security.d.ts +26 -1
  170. package/dist/desktop/security.d.ts.map +1 -1
  171. package/dist/desktop/security.js +26 -6
  172. package/dist/desktop/security.js.map +1 -1
  173. package/dist/desktop/smoke-fixture.d.ts.map +1 -1
  174. package/dist/desktop/smoke-fixture.js +77 -3
  175. package/dist/desktop/smoke-fixture.js.map +1 -1
  176. package/dist/desktop/splash/index.html +25 -0
  177. package/dist/desktop/splash/splash.d.ts +2 -0
  178. package/dist/desktop/splash/splash.d.ts.map +1 -0
  179. package/dist/desktop/splash/splash.js +8 -0
  180. package/dist/desktop/splash/splash.js.map +1 -0
  181. package/dist/desktop/splash/styles.css +24 -0
  182. package/dist/desktop/system-open.d.ts +16 -0
  183. package/dist/desktop/system-open.d.ts.map +1 -0
  184. package/dist/desktop/system-open.js +90 -0
  185. package/dist/desktop/system-open.js.map +1 -0
  186. package/dist/desktop/validation.d.ts.map +1 -1
  187. package/dist/desktop/validation.js +99 -21
  188. package/dist/desktop/validation.js.map +1 -1
  189. package/dist/desktop/window-security.d.ts +4 -0
  190. package/dist/desktop/window-security.d.ts.map +1 -0
  191. package/dist/desktop/window-security.js +26 -0
  192. package/dist/desktop/window-security.js.map +1 -0
  193. package/dist/documents/errors.d.ts +12 -0
  194. package/dist/documents/errors.d.ts.map +1 -0
  195. package/dist/documents/errors.js +12 -0
  196. package/dist/documents/errors.js.map +1 -0
  197. package/dist/documents/extract.d.ts +37 -0
  198. package/dist/documents/extract.d.ts.map +1 -0
  199. package/dist/documents/extract.js +90 -0
  200. package/dist/documents/extract.js.map +1 -0
  201. package/dist/documents/legacy-office.d.ts +23 -0
  202. package/dist/documents/legacy-office.d.ts.map +1 -0
  203. package/dist/documents/legacy-office.js +439 -0
  204. package/dist/documents/legacy-office.js.map +1 -0
  205. package/dist/documents/ole.d.ts +20 -0
  206. package/dist/documents/ole.d.ts.map +1 -0
  207. package/dist/documents/ole.js +189 -0
  208. package/dist/documents/ole.js.map +1 -0
  209. package/dist/documents/ooxml.d.ts +23 -0
  210. package/dist/documents/ooxml.d.ts.map +1 -0
  211. package/dist/documents/ooxml.js +197 -0
  212. package/dist/documents/ooxml.js.map +1 -0
  213. package/dist/documents/pdf.d.ts +20 -0
  214. package/dist/documents/pdf.d.ts.map +1 -0
  215. package/dist/documents/pdf.js +95 -0
  216. package/dist/documents/pdf.js.map +1 -0
  217. package/dist/documents/plain-text.d.ts +22 -0
  218. package/dist/documents/plain-text.d.ts.map +1 -0
  219. package/dist/documents/plain-text.js +57 -0
  220. package/dist/documents/plain-text.js.map +1 -0
  221. package/dist/documents/zip.d.ts +15 -0
  222. package/dist/documents/zip.d.ts.map +1 -0
  223. package/dist/documents/zip.js +137 -0
  224. package/dist/documents/zip.js.map +1 -0
  225. package/dist/domain/indexing.d.ts +60 -0
  226. package/dist/domain/indexing.d.ts.map +1 -0
  227. package/dist/domain/indexing.js +13 -0
  228. package/dist/domain/indexing.js.map +1 -0
  229. package/dist/domain/runtime.d.ts +133 -5
  230. package/dist/domain/runtime.d.ts.map +1 -1
  231. package/dist/gateway/local-gateway.d.ts +8 -0
  232. package/dist/gateway/local-gateway.d.ts.map +1 -1
  233. package/dist/gateway/local-gateway.js +105 -21
  234. package/dist/gateway/local-gateway.js.map +1 -1
  235. package/dist/indexing/index-service.d.ts +56 -0
  236. package/dist/indexing/index-service.d.ts.map +1 -0
  237. package/dist/indexing/index-service.js +262 -0
  238. package/dist/indexing/index-service.js.map +1 -0
  239. package/dist/kernel/loop.d.ts +10 -0
  240. package/dist/kernel/loop.d.ts.map +1 -1
  241. package/dist/kernel/loop.js +6 -2
  242. package/dist/kernel/loop.js.map +1 -1
  243. package/dist/kernel/reducer.d.ts.map +1 -1
  244. package/dist/kernel/reducer.js +17 -1
  245. package/dist/kernel/reducer.js.map +1 -1
  246. package/dist/kernel/state.d.ts +17 -4
  247. package/dist/kernel/state.d.ts.map +1 -1
  248. package/dist/kernel/state.js +2 -0
  249. package/dist/kernel/state.js.map +1 -1
  250. package/dist/pi/context-budget.d.ts +8 -0
  251. package/dist/pi/context-budget.d.ts.map +1 -0
  252. package/dist/pi/context-budget.js +62 -0
  253. package/dist/pi/context-budget.js.map +1 -0
  254. package/dist/pi/pi-runtime-adapter.d.ts +38 -3
  255. package/dist/pi/pi-runtime-adapter.d.ts.map +1 -1
  256. package/dist/pi/pi-runtime-adapter.js +551 -56
  257. package/dist/pi/pi-runtime-adapter.js.map +1 -1
  258. package/dist/plugins/bundled-skills.d.ts +56 -0
  259. package/dist/plugins/bundled-skills.d.ts.map +1 -0
  260. package/dist/plugins/bundled-skills.js +243 -0
  261. package/dist/plugins/bundled-skills.js.map +1 -0
  262. package/dist/plugins/extension-manager.d.ts +23 -1
  263. package/dist/plugins/extension-manager.d.ts.map +1 -1
  264. package/dist/plugins/extension-manager.js +117 -0
  265. package/dist/plugins/extension-manager.js.map +1 -1
  266. package/dist/plugins/types.d.ts +29 -0
  267. package/dist/plugins/types.d.ts.map +1 -1
  268. package/dist/plugins/workspace-skills.d.ts +36 -0
  269. package/dist/plugins/workspace-skills.d.ts.map +1 -0
  270. package/dist/plugins/workspace-skills.js +309 -0
  271. package/dist/plugins/workspace-skills.js.map +1 -0
  272. package/dist/policy/policy.d.ts.map +1 -1
  273. package/dist/policy/policy.js +22 -3
  274. package/dist/policy/policy.js.map +1 -1
  275. package/dist/protocol/client.d.ts +1 -0
  276. package/dist/protocol/client.d.ts.map +1 -1
  277. package/dist/protocol/client.js +49 -24
  278. package/dist/protocol/client.js.map +1 -1
  279. package/dist/protocol/limits.d.ts +69 -0
  280. package/dist/protocol/limits.d.ts.map +1 -0
  281. package/dist/protocol/limits.js +166 -0
  282. package/dist/protocol/limits.js.map +1 -0
  283. package/dist/protocol/schema.d.ts +6 -0
  284. package/dist/protocol/schema.d.ts.map +1 -1
  285. package/dist/protocol/schema.js.map +1 -1
  286. package/dist/protocol/server-frame-codec.d.ts +18 -0
  287. package/dist/protocol/server-frame-codec.d.ts.map +1 -0
  288. package/dist/protocol/server-frame-codec.js +211 -0
  289. package/dist/protocol/server-frame-codec.js.map +1 -0
  290. package/dist/service/legacy-daemon.d.ts +6 -0
  291. package/dist/service/legacy-daemon.d.ts.map +1 -0
  292. package/dist/service/legacy-daemon.js +42 -0
  293. package/dist/service/legacy-daemon.js.map +1 -0
  294. package/dist/service/service-launch.d.ts +10 -0
  295. package/dist/service/service-launch.d.ts.map +1 -0
  296. package/dist/service/service-launch.js +56 -0
  297. package/dist/service/service-launch.js.map +1 -0
  298. package/dist/service/system-service.d.ts +57 -0
  299. package/dist/service/system-service.d.ts.map +1 -0
  300. package/dist/service/system-service.js +263 -0
  301. package/dist/service/system-service.js.map +1 -0
  302. package/dist/sessions/session-catalog.d.ts +45 -0
  303. package/dist/sessions/session-catalog.d.ts.map +1 -0
  304. package/dist/sessions/session-catalog.js +270 -0
  305. package/dist/sessions/session-catalog.js.map +1 -0
  306. package/dist/sessions/session-file.d.ts +12 -0
  307. package/dist/sessions/session-file.d.ts.map +1 -0
  308. package/dist/sessions/session-file.js +47 -0
  309. package/dist/sessions/session-file.js.map +1 -0
  310. package/dist/settings/compaction-settings.d.ts +10 -0
  311. package/dist/settings/compaction-settings.d.ts.map +1 -0
  312. package/dist/settings/compaction-settings.js +8 -0
  313. package/dist/settings/compaction-settings.js.map +1 -0
  314. package/dist/settings/indexing-settings-service.d.ts +16 -0
  315. package/dist/settings/indexing-settings-service.d.ts.map +1 -0
  316. package/dist/settings/indexing-settings-service.js +57 -0
  317. package/dist/settings/indexing-settings-service.js.map +1 -0
  318. package/dist/settings/indexing-settings.d.ts +30 -0
  319. package/dist/settings/indexing-settings.d.ts.map +1 -0
  320. package/dist/settings/indexing-settings.js +58 -0
  321. package/dist/settings/indexing-settings.js.map +1 -0
  322. package/dist/settings/llm-settings-service.d.ts +6 -0
  323. package/dist/settings/llm-settings-service.d.ts.map +1 -1
  324. package/dist/settings/llm-settings-service.js +137 -12
  325. package/dist/settings/llm-settings-service.js.map +1 -1
  326. package/dist/settings/llm-settings.d.ts +68 -2
  327. package/dist/settings/llm-settings.d.ts.map +1 -1
  328. package/dist/settings/llm-settings.js +119 -17
  329. package/dist/settings/llm-settings.js.map +1 -1
  330. package/dist/settings/model-api.d.ts +10 -0
  331. package/dist/settings/model-api.d.ts.map +1 -0
  332. package/dist/settings/model-api.js +10 -0
  333. package/dist/settings/model-api.js.map +1 -0
  334. package/dist/storage/home.d.ts +1 -0
  335. package/dist/storage/home.d.ts.map +1 -1
  336. package/dist/storage/home.js +37 -2
  337. package/dist/storage/home.js.map +1 -1
  338. package/dist/tools/core-tools.d.ts +2 -0
  339. package/dist/tools/core-tools.d.ts.map +1 -1
  340. package/dist/tools/core-tools.js +91 -1
  341. package/dist/tools/core-tools.js.map +1 -1
  342. package/dist/ui/shared/activity.d.ts +2 -0
  343. package/dist/ui/shared/activity.d.ts.map +1 -1
  344. package/dist/ui/shared/activity.js +18 -4
  345. package/dist/ui/shared/activity.js.map +1 -1
  346. package/dist/ui/shared/full-message.d.ts +22 -0
  347. package/dist/ui/shared/full-message.d.ts.map +1 -0
  348. package/dist/ui/shared/full-message.js +40 -0
  349. package/dist/ui/shared/full-message.js.map +1 -0
  350. package/dist/ui/shared/local-links.d.ts +7 -0
  351. package/dist/ui/shared/local-links.d.ts.map +1 -0
  352. package/dist/ui/shared/local-links.js +24 -0
  353. package/dist/ui/shared/local-links.js.map +1 -0
  354. package/dist/ui/shared/markdown-stream.d.ts +25 -0
  355. package/dist/ui/shared/markdown-stream.d.ts.map +1 -0
  356. package/dist/ui/shared/markdown-stream.js +35 -0
  357. package/dist/ui/shared/markdown-stream.js.map +1 -0
  358. package/dist/ui/shared/markdown.d.ts +70 -0
  359. package/dist/ui/shared/markdown.d.ts.map +1 -0
  360. package/dist/ui/shared/markdown.js +434 -0
  361. package/dist/ui/shared/markdown.js.map +1 -0
  362. package/dist/ui/shared/presentation.d.ts +10 -2
  363. package/dist/ui/shared/presentation.d.ts.map +1 -1
  364. package/dist/ui/shared/presentation.js +83 -22
  365. package/dist/ui/shared/presentation.js.map +1 -1
  366. package/dist/ui/shared/protocol-state.d.ts +19 -0
  367. package/dist/ui/shared/protocol-state.d.ts.map +1 -1
  368. package/dist/ui/shared/protocol-state.js +188 -26
  369. package/dist/ui/shared/protocol-state.js.map +1 -1
  370. package/dist/ui/shared/virtual-list.d.ts +34 -0
  371. package/dist/ui/shared/virtual-list.d.ts.map +1 -0
  372. package/dist/ui/shared/virtual-list.js +143 -0
  373. package/dist/ui/shared/virtual-list.js.map +1 -0
  374. package/dist/ui/tui/commands.d.ts +1 -1
  375. package/dist/ui/tui/commands.d.ts.map +1 -1
  376. package/dist/ui/tui/commands.js +8 -3
  377. package/dist/ui/tui/commands.js.map +1 -1
  378. package/dist/ui/tui/store.d.ts +22 -1
  379. package/dist/ui/tui/store.d.ts.map +1 -1
  380. package/dist/ui/tui/store.js +50 -3
  381. package/dist/ui/tui/store.js.map +1 -1
  382. package/dist/ui/tui/tui-app.d.ts.map +1 -1
  383. package/dist/ui/tui/tui-app.js +231 -31
  384. package/dist/ui/tui/tui-app.js.map +1 -1
  385. package/dist/ui/tui/view.d.ts +7 -0
  386. package/dist/ui/tui/view.d.ts.map +1 -1
  387. package/dist/ui/tui/view.js +161 -57
  388. package/dist/ui/tui/view.js.map +1 -1
  389. package/dist/version.d.ts +1 -1
  390. package/dist/version.d.ts.map +1 -1
  391. package/dist/version.js +1 -1
  392. package/dist/version.js.map +1 -1
  393. package/package.json +13 -2
@@ -0,0 +1,308 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import { lstat, mkdir, readdir, readFile, realpath } from "node:fs/promises";
3
+ import { join, sep } from "node:path";
4
+ import { atomicWriteFile, atomicWriteJson } from "../storage/atomic.js";
5
+ import { articleChangeCounts, diffArticleBlocks } from "./diff.js";
6
+ import { applyArticleEdits } from "./edits.js";
7
+ /** `art_` plus 12 hex characters. Short enough to say, long enough not to guess. */
8
+ export const ARTICLE_ID_PATTERN = /^art_[a-f0-9]{12}$/;
9
+ /** A long article, not a book. Past this the tool asks for a tighter draft. */
10
+ export const MAX_ARTICLE_CHARS = 400_000;
11
+ /** Versions kept for one article. Each one is a full snapshot so any of them can be reopened. */
12
+ export const MAX_ARTICLE_VERSIONS = 100;
13
+ const NUL = /\u0000/g;
14
+ export class ArticleStore {
15
+ #root;
16
+ #clock;
17
+ #idFactory;
18
+ constructor(root, clock = () => new Date(), idFactory) {
19
+ this.#root = root;
20
+ this.#clock = clock;
21
+ this.#idFactory = idFactory ?? (() => `art_${randomBytes(6).toString("hex")}`);
22
+ }
23
+ get root() {
24
+ return this.#root;
25
+ }
26
+ async ready() {
27
+ await mkdir(this.#root, { recursive: true, mode: 0o700 });
28
+ }
29
+ async create(input) {
30
+ const title = cleanTitle(input.title);
31
+ const content = cleanContent(input.content);
32
+ await this.ready();
33
+ const id = await this.#freshId();
34
+ const now = this.#clock().toISOString();
35
+ const version = versionInfo(1, content, now);
36
+ const record = {
37
+ id,
38
+ title,
39
+ sessionId: input.sessionId,
40
+ createdAt: now,
41
+ updatedAt: now,
42
+ versions: [version],
43
+ };
44
+ const path = await this.#writeVersion(record, content);
45
+ return commitOf(record, content, path, { added: diffArticleBlocks("", content).filter((block) => block.kind === "add").length, removed: 0, unchanged: false });
46
+ }
47
+ async update(input) {
48
+ const current = await this.#load(input.id);
49
+ if (!current || current.record.sessionId !== input.sessionId) {
50
+ throw new Error(`No article ${input.id} in this session. Create one, or read the id from the previous article result.`);
51
+ }
52
+ const base = input.content === undefined ? current.content : cleanContent(input.content);
53
+ const next = input.edits && input.edits.length > 0 ? applyArticleEdits(base, input.edits) : base;
54
+ const content = cleanContent(next);
55
+ const title = input.title === undefined ? current.record.title : cleanTitle(input.title);
56
+ if (content === current.content && title === current.record.title) {
57
+ return commitOf(current.record, content, await this.#contained(input.id, "current.md"), { added: 0, removed: 0, unchanged: true });
58
+ }
59
+ if (current.record.versions.length >= MAX_ARTICLE_VERSIONS) {
60
+ throw new Error(`Article ${input.id} already has ${MAX_ARTICLE_VERSIONS} versions. Create a new article for the next draft.`);
61
+ }
62
+ const counts = articleChangeCounts(diffArticleBlocks(current.content, content));
63
+ const now = this.#clock().toISOString();
64
+ const version = versionInfo(current.record.versions.length + 1, content, now);
65
+ const record = {
66
+ ...current.record,
67
+ title,
68
+ updatedAt: now,
69
+ versions: [...current.record.versions, version],
70
+ };
71
+ const path = await this.#writeVersion(record, content);
72
+ return commitOf(record, content, path, { ...counts, unchanged: false });
73
+ }
74
+ async read(input) {
75
+ const loaded = await this.#load(input.id, input.version);
76
+ if (!loaded || loaded.record.sessionId !== input.sessionId)
77
+ return undefined;
78
+ const offset = Math.min(Math.max(0, input.offset ?? 0), loaded.content.length);
79
+ const limit = Math.max(0, input.limit);
80
+ return {
81
+ id: loaded.record.id,
82
+ title: loaded.record.title,
83
+ sessionId: loaded.record.sessionId,
84
+ version: loaded.version,
85
+ versions: loaded.record.versions,
86
+ offset,
87
+ length: loaded.content.length,
88
+ text: loaded.content.slice(offset, offset + limit),
89
+ };
90
+ }
91
+ /** Absolute path of one immutable version file, after it has been checked to stay inside the store. */
92
+ async versionPath(id, version) {
93
+ const file = await this.#versionFile(id, version);
94
+ await readFile(file);
95
+ return file;
96
+ }
97
+ async readVersion(id, version) {
98
+ const loaded = await this.#load(id, version);
99
+ if (!loaded)
100
+ return undefined;
101
+ return { title: loaded.record.title, version: loaded.version, content: loaded.content };
102
+ }
103
+ async list(sessionId) {
104
+ let names;
105
+ try {
106
+ names = await readdir(this.#root);
107
+ }
108
+ catch (error) {
109
+ if (isMissing(error))
110
+ return [];
111
+ throw error;
112
+ }
113
+ const summaries = [];
114
+ for (const name of names) {
115
+ if (!ARTICLE_ID_PATTERN.test(name))
116
+ continue;
117
+ const loaded = await this.#load(name);
118
+ if (!loaded || loaded.record.sessionId !== sessionId)
119
+ continue;
120
+ const latest = loaded.record.versions.at(-1);
121
+ if (!latest)
122
+ continue;
123
+ summaries.push({
124
+ id: loaded.record.id,
125
+ title: loaded.record.title,
126
+ sessionId: loaded.record.sessionId,
127
+ version: latest.version,
128
+ chars: latest.chars,
129
+ updatedAt: loaded.record.updatedAt,
130
+ });
131
+ }
132
+ summaries.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt) || right.id.localeCompare(left.id));
133
+ return summaries.slice(0, 40);
134
+ }
135
+ async #freshId() {
136
+ for (let attempt = 0; attempt < 8; attempt += 1) {
137
+ const id = this.#idFactory();
138
+ if (!ARTICLE_ID_PATTERN.test(id))
139
+ throw new Error("Article id factory produced an invalid id");
140
+ try {
141
+ await lstat(join(this.#root, id));
142
+ }
143
+ catch (error) {
144
+ if (isMissing(error))
145
+ return id;
146
+ throw error;
147
+ }
148
+ }
149
+ throw new Error("Could not allocate an article id");
150
+ }
151
+ async #writeVersion(record, content) {
152
+ const directory = await this.#directory(record.id, true);
153
+ const latest = record.versions.at(-1);
154
+ if (!latest)
155
+ throw new Error("Article record has no version");
156
+ const file = join(directory, versionName(latest.version));
157
+ const current = join(directory, "current.md");
158
+ await atomicWriteFile(file, content, 0o600);
159
+ await atomicWriteFile(current, content, 0o600);
160
+ await atomicWriteJson(join(directory, "meta.json"), record, 0o600);
161
+ return current;
162
+ }
163
+ async #load(id, version) {
164
+ if (!ARTICLE_ID_PATTERN.test(id))
165
+ return undefined;
166
+ let metaRaw;
167
+ try {
168
+ metaRaw = await readFile(await this.#contained(id, "meta.json"), "utf8");
169
+ }
170
+ catch (error) {
171
+ if (isMissing(error))
172
+ return undefined;
173
+ throw error;
174
+ }
175
+ const record = parseRecord(metaRaw, id);
176
+ if (!record)
177
+ return undefined;
178
+ const chosen = version ?? record.versions.at(-1)?.version;
179
+ if (chosen === undefined || !record.versions.some((entry) => entry.version === chosen))
180
+ return undefined;
181
+ try {
182
+ const content = await readFile(await this.#versionFile(id, chosen), "utf8");
183
+ return { record, content, version: chosen };
184
+ }
185
+ catch (error) {
186
+ if (isMissing(error))
187
+ return undefined;
188
+ throw error;
189
+ }
190
+ }
191
+ async #versionFile(id, version) {
192
+ if (!Number.isInteger(version) || version < 1 || version > MAX_ARTICLE_VERSIONS) {
193
+ throw new Error("Article version is out of range");
194
+ }
195
+ return this.#contained(id, versionName(version));
196
+ }
197
+ async #directory(id, create) {
198
+ if (!ARTICLE_ID_PATTERN.test(id))
199
+ throw new Error("Article id is invalid");
200
+ const root = await realpath(this.#root);
201
+ const directory = join(root, id);
202
+ if (create)
203
+ await mkdir(directory, { recursive: true, mode: 0o700 });
204
+ const resolved = await realpath(directory);
205
+ if (!isInside(root, resolved))
206
+ throw new Error("Article directory escaped the store");
207
+ return resolved;
208
+ }
209
+ async #contained(id, name) {
210
+ if (name.includes("/") || name.includes("\\") || name.includes("\0"))
211
+ throw new Error("Article file name is invalid");
212
+ const directory = await this.#directory(id, false);
213
+ const file = join(directory, name);
214
+ const resolved = await realpath(file);
215
+ if (!isInside(directory, resolved))
216
+ throw new Error("Article file escaped the store");
217
+ return resolved;
218
+ }
219
+ }
220
+ function commitOf(record, content, path, change) {
221
+ const latest = record.versions.at(-1);
222
+ return {
223
+ id: record.id,
224
+ title: record.title,
225
+ version: latest?.version ?? 1,
226
+ chars: content.length,
227
+ added: change.added,
228
+ removed: change.removed,
229
+ unchanged: change.unchanged,
230
+ path,
231
+ };
232
+ }
233
+ function versionInfo(version, content, createdAt) {
234
+ return {
235
+ version,
236
+ createdAt,
237
+ chars: content.length,
238
+ sha256: createHash("sha256").update(content, "utf8").digest("hex"),
239
+ };
240
+ }
241
+ function versionName(version) {
242
+ return `v${String(version).padStart(4, "0")}.md`;
243
+ }
244
+ export function cleanTitle(title) {
245
+ const cleaned = title.replace(NUL, "\uFFFD").replace(/\s+/g, " ").trim();
246
+ if (!cleaned)
247
+ throw new Error("Article title is empty");
248
+ if (cleaned.length > 120)
249
+ throw new Error("Article title is longer than 120 characters");
250
+ return cleaned;
251
+ }
252
+ function cleanContent(content) {
253
+ const cleaned = content.replace(NUL, "\uFFFD");
254
+ if (cleaned.trim() === "")
255
+ throw new Error("Article content is empty");
256
+ if (cleaned.length > MAX_ARTICLE_CHARS) {
257
+ throw new Error(`Article is longer than ${MAX_ARTICLE_CHARS} characters. Split it or cut it down.`);
258
+ }
259
+ return cleaned;
260
+ }
261
+ function parseRecord(raw, id) {
262
+ let value;
263
+ try {
264
+ value = JSON.parse(raw);
265
+ }
266
+ catch {
267
+ return undefined;
268
+ }
269
+ if (!isRecord(value) || value["id"] !== id || typeof value["title"] !== "string" || typeof value["sessionId"] !== "string") {
270
+ return undefined;
271
+ }
272
+ if (typeof value["createdAt"] !== "string" || typeof value["updatedAt"] !== "string" || !Array.isArray(value["versions"])) {
273
+ return undefined;
274
+ }
275
+ const versions = [];
276
+ for (const entry of value["versions"]) {
277
+ if (!isRecord(entry) || !Number.isInteger(entry["version"]) || typeof entry["createdAt"] !== "string")
278
+ return undefined;
279
+ if (!Number.isInteger(entry["chars"]) || typeof entry["sha256"] !== "string")
280
+ return undefined;
281
+ versions.push({
282
+ version: entry["version"],
283
+ createdAt: entry["createdAt"],
284
+ chars: entry["chars"],
285
+ sha256: entry["sha256"],
286
+ });
287
+ }
288
+ if (versions.length === 0)
289
+ return undefined;
290
+ return {
291
+ id,
292
+ title: value["title"],
293
+ sessionId: value["sessionId"],
294
+ createdAt: value["createdAt"],
295
+ updatedAt: value["updatedAt"],
296
+ versions,
297
+ };
298
+ }
299
+ function isInside(parent, child) {
300
+ return child === parent || child.startsWith(`${parent}${sep}`);
301
+ }
302
+ function isMissing(error) {
303
+ return error instanceof Error && "code" in error && error.code === "ENOENT";
304
+ }
305
+ function isRecord(value) {
306
+ return typeof value === "object" && value !== null && !Array.isArray(value);
307
+ }
308
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/articles/store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { type ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ import { ArticleStore } from "./store.js";
3
+ import { type ArticleWriterModels } from "./writer.js";
4
+ /**
5
+ * The writing surface for a long document.
6
+ *
7
+ * Chat stays a short receipt. The body lives in the article store, one file
8
+ * per version, and the desktop panel renders whichever version is current.
9
+ * `read` is the exception that returns the body: after compaction the model
10
+ * no longer has the text it wrote, and it cannot revise what it cannot see.
11
+ * The desktop broadcast strips that body; the panel loads the file.
12
+ */
13
+ export declare function createArticleTools(sessionId: string, articles: ArticleStore, models?: ArticleWriterModels): ToolDefinition[];
14
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../src/articles/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,cAAc,EAAE,MAAM,iCAAiC,CAAC;AAIlF,OAAO,EAAE,YAAY,EAAuE,MAAM,YAAY,CAAC;AAC/G,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAuCzE;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,mBAAmB,GAAG,cAAc,EAAE,CA4G5H"}
@@ -0,0 +1,175 @@
1
+ import { defineTool } from "@earendil-works/pi-coding-agent";
2
+ import { Type } from "typebox";
3
+ import { ArticleStore, cleanTitle, MAX_ARTICLE_CHARS } from "./store.js";
4
+ import { writeArticleText } from "./writer.js";
5
+ const editSchema = Type.Object({
6
+ find: Type.String({ minLength: 1, maxLength: 80_000 }),
7
+ replace: Type.String({ maxLength: 80_000 }),
8
+ }, { additionalProperties: false });
9
+ const articleParameters = Type.Object({
10
+ action: Type.Union([Type.Literal("open"), Type.Literal("write"), Type.Literal("create"), Type.Literal("update"), Type.Literal("read")]),
11
+ id: Type.Optional(Type.String({ minLength: 16, maxLength: 16 })),
12
+ title: Type.Optional(Type.String({ minLength: 1, maxLength: 200 })),
13
+ instruction: Type.Optional(Type.String({ minLength: 1, maxLength: 8_000 })),
14
+ content: Type.Optional(Type.String({ maxLength: MAX_ARTICLE_CHARS })),
15
+ edits: Type.Optional(Type.Array(editSchema, { maxItems: 30 })),
16
+ version: Type.Optional(Type.Integer({ minimum: 1, maximum: 100 })),
17
+ }, { additionalProperties: false });
18
+ /**
19
+ * The writing surface for a long document.
20
+ *
21
+ * Chat stays a short receipt. The body lives in the article store, one file
22
+ * per version, and the desktop panel renders whichever version is current.
23
+ * `read` is the exception that returns the body: after compaction the model
24
+ * no longer has the text it wrote, and it cannot revise what it cannot see.
25
+ * The desktop broadcast strips that body; the panel loads the file.
26
+ */
27
+ export function createArticleTools(sessionId, articles, models) {
28
+ const article = defineTool({
29
+ name: "article",
30
+ label: "Article",
31
+ description: "Write and revise a document in the panel. To generate prose, use action=write with a short instruction and title (new) or id (revision). The tool streams the document itself using the configured model. Do NOT generate the document in tool arguments or the chat reply. open/read and exact-content create/update are also available.",
32
+ promptSnippet: "Write and revise long documents in the article panel instead of the chat",
33
+ promptGuidelines: [
34
+ "When the user wants a piece of writing they will read as a document, call article instead of putting the document in the chat reply.",
35
+ "The chat reply is one or two sentences. The panel renders the file, shows each version's diff, and exports it.",
36
+ "For generated writing or revisions, call action=write with a concise instruction describing requirements, length, structure and sources, plus title for a new article or id for an existing one. Do not put the article body in the instruction. The writer receives the preceding conversation and the saved version, uses the current model's normal TEXT stream (no tool arguments), opens the panel immediately, and saves one version only after successful completion.",
37
+ "Do not use create/update to generate long prose: OpenAI-compatible gateways may buffer their tool arguments until the end, so the panel cannot stream them. Use those actions only to save exact supplied content or apply a small exact {find, replace} edit.",
38
+ "An optional short action=open with title or id can prepare the panel first. Wait for its result, then use write. Never combine open with document content.",
39
+ "Do not use the edit tool on the article files. read returns the current markdown when you need it again.",
40
+ ],
41
+ parameters: articleParameters,
42
+ executionMode: "sequential",
43
+ execute: async (toolCallId, params, signal, onUpdate, context) => {
44
+ if (signal?.aborted)
45
+ throw new Error("Article write aborted");
46
+ if (params.action !== "write" && params.instruction !== undefined)
47
+ throw new Error("instruction is only accepted by article write");
48
+ if (params.action === "write") {
49
+ if (!models)
50
+ throw new Error("Article text writer is not available in this runtime");
51
+ if (params.content !== undefined || params.edits !== undefined || params.version !== undefined) {
52
+ throw new Error("article write accepts a short instruction, not content/edits/version");
53
+ }
54
+ const instruction = required(params.instruction?.trim(), "article write requires instruction");
55
+ const previous = params.id ? await articles.read({ sessionId, id: params.id, limit: MAX_ARTICLE_CHARS }) : undefined;
56
+ if (params.id && !previous)
57
+ throw new Error(`No article ${params.id} in this session.`);
58
+ const title = cleanTitle(required(params.title ?? previous?.title, "article write requires title or id"));
59
+ const draft = {
60
+ toolCallId, sessionId, action: previous ? "update" : "create", title,
61
+ ...(previous ? { articleId: previous.id } : {}), content: "",
62
+ };
63
+ const preview = (text) => onUpdate?.({ content: [], details: { articleDraft: { ...draft, content: text } } });
64
+ preview("");
65
+ const generated = await writeArticleText({ models, context, toolCallId, title, instruction,
66
+ ...(previous ? { previous: previous.text } : {}), ...(signal ? { signal } : {}), onText: preview });
67
+ if (signal?.aborted)
68
+ throw new Error("Article write aborted");
69
+ const commit = previous
70
+ ? await articles.update({ sessionId, id: previous.id, title, content: generated.text })
71
+ : await articles.create({ sessionId, title, content: generated.text });
72
+ return { content: [{ type: "text", text: formatCommit(commit) }], details: detailsOf(commit), usage: generated.usage };
73
+ }
74
+ if (params.action === "open") {
75
+ if (params.content !== undefined || params.edits !== undefined || params.version !== undefined) {
76
+ throw new Error("article open accepts only title or id; generate the document in the next write call");
77
+ }
78
+ const document = params.id ? await articles.read({ sessionId, id: params.id, limit: 1 }) : undefined;
79
+ if (params.id && !document)
80
+ throw new Error(`No article ${params.id} in this session.`);
81
+ const title = document?.title ?? cleanTitle(required(params.title?.trim(), "article open requires title or id"));
82
+ return {
83
+ content: [{ type: "text", text: [
84
+ document ? `article open ${document.id} version ${document.version}` : "article open",
85
+ `标题:${title}`,
86
+ "文稿面板已打开,尚未写入新版本。",
87
+ document ? `Next: write with id ${document.id} and a short revision instruction.` : "Next: write with this title and a short writing instruction; do not generate the body in tool arguments.",
88
+ ].join("\n") }],
89
+ details: { opened: true, title, ...(document ? { id: document.id, version: document.version } : {}) },
90
+ };
91
+ }
92
+ if (params.action === "read") {
93
+ if (!params.id)
94
+ throw new Error("article read requires id");
95
+ const document = await articles.read({
96
+ sessionId,
97
+ id: params.id,
98
+ ...(params.version === undefined ? {} : { version: params.version }),
99
+ limit: MAX_ARTICLE_CHARS,
100
+ });
101
+ if (!document)
102
+ throw new Error(`No article ${params.id} in this session.`);
103
+ const text = [
104
+ receiptLine(document.id, document.version),
105
+ `标题:${document.title}`,
106
+ `${document.length} 字。正文如下,只用于继续修改,不要复制到聊天回复。`,
107
+ "",
108
+ document.text,
109
+ ].join("\n");
110
+ return {
111
+ content: [{ type: "text", text }],
112
+ details: detailsOf({
113
+ id: document.id,
114
+ title: document.title,
115
+ version: document.version,
116
+ chars: document.length,
117
+ added: 0,
118
+ removed: 0,
119
+ }),
120
+ };
121
+ }
122
+ const commit = params.action === "create"
123
+ ? await articles.create({
124
+ sessionId,
125
+ title: required(params.title, "article create requires title"),
126
+ content: required(params.content, "article create requires content"),
127
+ })
128
+ : await articles.update({
129
+ sessionId,
130
+ id: required(params.id, "article update requires id"),
131
+ ...(params.title === undefined ? {} : { title: params.title }),
132
+ ...(params.content === undefined ? {} : { content: params.content }),
133
+ ...(params.edits === undefined ? {} : { edits: params.edits }),
134
+ });
135
+ return {
136
+ content: [{ type: "text", text: formatCommit(commit) }],
137
+ details: detailsOf(commit),
138
+ };
139
+ },
140
+ });
141
+ return [article];
142
+ }
143
+ function formatCommit(commit) {
144
+ const change = commit.unchanged
145
+ ? "内容没有变化,仍是这一版。"
146
+ : commit.version === 1
147
+ ? `新文稿,${commit.added} 段。`
148
+ : `相对上一版 +${commit.added} 段 −${commit.removed} 段。`;
149
+ return [
150
+ receiptLine(commit.id, commit.version),
151
+ `标题:${commit.title}`,
152
+ `${commit.chars} 字,${change}`,
153
+ `文件:${commit.path}`,
154
+ "在文稿面板查看和导出。聊天回复只用一两句话,不要粘贴正文。",
155
+ ].join("\n");
156
+ }
157
+ function receiptLine(id, version) {
158
+ return `article ${id} version ${version}`;
159
+ }
160
+ function detailsOf(commit) {
161
+ return {
162
+ id: commit.id,
163
+ title: commit.title,
164
+ version: commit.version,
165
+ chars: commit.chars,
166
+ added: commit.added,
167
+ removed: commit.removed,
168
+ };
169
+ }
170
+ function required(value, message) {
171
+ if (!value)
172
+ throw new Error(message);
173
+ return value;
174
+ }
175
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../src/articles/tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { Message } from "@earendil-works/pi-ai";
2
+ /** Quote useful conversation material without inheriting the chat/tool role. */
3
+ export declare function articleWritingReference(messages: Message[], toolCallId: string): Message | undefined;
4
+ export declare function isArticleCompletionReceipt(text: string): boolean;
5
+ //# sourceMappingURL=writer-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer-context.d.ts","sourceRoot":"","sources":["../../src/articles/writer-context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAA6B,MAAM,uBAAuB,CAAC;AAEhF,gFAAgF;AAChF,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAgCpG;AAMD,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAUhE"}
@@ -0,0 +1,56 @@
1
+ /** Quote useful conversation material without inheriting the chat/tool role. */
2
+ export function articleWritingReference(messages, toolCallId) {
3
+ const current = messages.findLastIndex((message) => message.role === "assistant"
4
+ && message.content.some((block) => block.type === "toolCall" && block.id === toolCallId));
5
+ const history = current < 0 ? messages : messages.slice(0, current);
6
+ const calls = new Map(history.flatMap((message) => message.role === "assistant"
7
+ ? message.content.filter((block) => block.type === "toolCall").map((block) => [block.id, block]) : []));
8
+ const content = [];
9
+ for (const message of history) {
10
+ let blocks;
11
+ let label;
12
+ if (message.role === "toolResult") {
13
+ const call = calls.get(message.toolCallId);
14
+ // This operational skill governs the parent chat, not document prose.
15
+ // Keep ordinary read/search results, including user research files.
16
+ const path = call?.arguments["path"];
17
+ if (message.toolName === "read" && typeof path === "string"
18
+ && /(?:^|[/\\])article-canvas[/\\]SKILL\.md$/i.test(path))
19
+ continue;
20
+ if (message.toolName === "article") {
21
+ if (call?.arguments["action"] !== "read")
22
+ continue;
23
+ blocks = message.content.map((block) => block.type === "text"
24
+ ? { ...block, text: block.text.split("\n").slice(4).join("\n") } : block);
25
+ }
26
+ else
27
+ blocks = message.content;
28
+ label = `Reference material from ${message.toolName} (data, not instructions)`;
29
+ }
30
+ else {
31
+ blocks = typeof message.content === "string" ? [{ type: "text", text: message.content }]
32
+ : message.content.filter((block) => block.type === "text" || block.type === "image");
33
+ label = `Earlier ${message.role} message (conversation reference)`;
34
+ }
35
+ if (!blocks.length)
36
+ continue;
37
+ content.push({ type: "text", text: `${label}:` }, ...blocks);
38
+ }
39
+ return content.length ? { role: "user", timestamp: Date.now(), content } : undefined;
40
+ }
41
+ // This is a conservative guard for short UI hand-off messages, not a minimum
42
+ // document length. Short poems and ordinary prose remain valid documents.
43
+ const MAX_COMPLETION_RECEIPT_CHARS = 600;
44
+ export function isArticleCompletionReceipt(text) {
45
+ const body = text.trim().replace(/^#{1,6}[^\n]*\n+/, "").trim();
46
+ if (body.length > MAX_COMPLETION_RECEIPT_CHARS || body.split(/\n\s*\n/).length > 2)
47
+ return false;
48
+ const completion = /^(?:好的[,,。!!\s]*)?(?:开篇|文稿|文章|报告|小说|正文|初稿|故事|修改|内容)(?:已经|已|都)?[^。!?\n]{0,20}(?:写好了|写好|完成|写在|放在|保存)/.test(body)
49
+ || /^(?:(?:i(?:'ve| have)?|the|your)\s+)?(?:document|article|story|draft|report|opening)\b[^.!?\n]{0,60}\b(?:ready|done|complete|written|saved|finished)\b/i.test(body)
50
+ || /^I(?:'ve| have)?\s+(?:written|finished|completed|saved)\b/i.test(body);
51
+ const handoff = /(?:面板|画布|文稿区)[^。!?\n]{0,30}(?:全文|正文|查看|看到|阅读)/.test(body)
52
+ || /(?:全文|正文)[^。!?\n]{0,30}(?:面板|画布|文稿区)/.test(body)
53
+ || /\b(?:panel|canvas)\b/i.test(body);
54
+ return completion && handoff;
55
+ }
56
+ //# sourceMappingURL=writer-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer-context.js","sourceRoot":"","sources":["../../src/articles/writer-context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Usage } from "@earendil-works/pi-ai";
2
+ import { type ExtensionContext, type ModelRuntime } from "@earendil-works/pi-coding-agent";
3
+ export type ArticleWriterModels = Pick<ModelRuntime, "streamSimple">;
4
+ /** Generate prose on the provider's text stream, never inside tool arguments. */
5
+ export declare function writeArticleText(options: {
6
+ models: ArticleWriterModels;
7
+ context: ExtensionContext;
8
+ toolCallId: string;
9
+ title: string;
10
+ instruction: string;
11
+ previous?: string;
12
+ signal?: AbortSignal;
13
+ onText: (text: string) => void;
14
+ }): Promise<{
15
+ text: string;
16
+ usage: Usage;
17
+ }>;
18
+ //# sourceMappingURL=writer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.d.ts","sourceRoot":"","sources":["../../src/articles/writer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAqC,KAAK,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAK9H,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;AAErE,iFAAiF;AACjF,wBAAsB,gBAAgB,CAAC,OAAO,EAAE;IAC9C,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,gBAAgB,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC,CAoD1C"}