create-windy 0.8.3 → 0.9.1

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 (505) hide show
  1. package/dist/cli.js +838 -560
  2. package/package.json +1 -1
  3. package/template/.windy-template.json +2 -2
  4. package/template/apps/agent-server/Dockerfile +92 -22
  5. package/template/apps/agent-server/README.md +47 -85
  6. package/template/apps/agent-server/documents/office.py +216 -0
  7. package/template/apps/agent-server/documents/query_report.py +136 -0
  8. package/template/apps/agent-server/documents/smoke.py +177 -0
  9. package/template/apps/agent-server/documents/test_boundaries.py +185 -0
  10. package/template/apps/agent-server/host-contracts.ts +56 -0
  11. package/template/apps/agent-server/install-native.ts +167 -0
  12. package/template/apps/agent-server/main.ts +179 -0
  13. package/template/apps/agent-server/native/EXTENSIONS.md +46 -0
  14. package/template/apps/agent-server/native/admission.ts +73 -0
  15. package/template/apps/agent-server/native/authorization.test.ts +176 -0
  16. package/template/apps/agent-server/native/authorization.ts +118 -0
  17. package/template/apps/agent-server/native/boundary-io.ts +93 -0
  18. package/template/apps/agent-server/native/boundary-product.ts +107 -0
  19. package/template/apps/agent-server/native/boundary-project.test.ts +247 -0
  20. package/template/apps/agent-server/native/boundary-project.ts +188 -0
  21. package/template/apps/agent-server/native/boundary.ts +188 -0
  22. package/template/apps/agent-server/native/compaction-policy.test.ts +175 -0
  23. package/template/apps/agent-server/native/config.ts +95 -0
  24. package/template/apps/agent-server/native/conversation-instructions.ts +9 -0
  25. package/template/apps/agent-server/native/extensions.test.ts +190 -0
  26. package/template/apps/agent-server/native/extensions.ts +31 -0
  27. package/template/apps/agent-server/native/host-profile.test.ts +91 -0
  28. package/template/apps/agent-server/native/host-profile.ts +33 -0
  29. package/template/apps/agent-server/native/host-test-fixture.ts +13 -0
  30. package/template/apps/agent-server/native/http.ts +129 -0
  31. package/template/apps/agent-server/native/lifecycle.test.ts +285 -0
  32. package/template/apps/agent-server/native/lifecycle.ts +136 -0
  33. package/template/apps/agent-server/native/manager.ts +292 -0
  34. package/template/apps/agent-server/native/native.test.ts +207 -0
  35. package/template/apps/agent-server/native/office-preview.test.ts +50 -0
  36. package/template/apps/agent-server/native/office-preview.ts +25 -0
  37. package/template/apps/agent-server/native/parallel-harness.ts +242 -0
  38. package/template/apps/agent-server/native/parallel-mcp-fixture.ts +97 -0
  39. package/template/apps/agent-server/native/parallel.test.ts +256 -0
  40. package/template/apps/agent-server/native/profile-composition.test.ts +147 -0
  41. package/template/apps/agent-server/native/profile.ts +307 -0
  42. package/template/apps/agent-server/native/request.ts +61 -0
  43. package/template/apps/agent-server/native/session-conflict.test.ts +235 -0
  44. package/template/apps/agent-server/native/session-conflict.ts +21 -0
  45. package/template/apps/agent-server/native/shared-skills.test.ts +128 -0
  46. package/template/apps/agent-server/native/shared-skills.ts +240 -0
  47. package/template/apps/agent-server/native/socket-lifecycle.test.ts +48 -0
  48. package/template/apps/agent-server/native/socket.ts +130 -0
  49. package/template/apps/agent-server/native/storage-lifecycle.test.ts +217 -0
  50. package/template/apps/agent-server/native/storage.ts +188 -0
  51. package/template/apps/agent-server/native/stream-authorization.test.ts +89 -0
  52. package/template/apps/agent-server/native/worker.ts +77 -0
  53. package/template/apps/agent-server/native-download.test.ts +119 -0
  54. package/template/apps/agent-server/native-download.ts +145 -0
  55. package/template/apps/agent-server/package.json +63 -0
  56. package/template/apps/agent-server/plugins/access.mjs +126 -0
  57. package/template/apps/agent-server/plugins/branding/README.md +9 -0
  58. package/template/apps/agent-server/plugins/branding/brand.css +85 -0
  59. package/template/apps/agent-server/plugins/branding/client.js +338 -0
  60. package/template/apps/agent-server/plugins/branding/index.mjs +35 -0
  61. package/template/apps/agent-server/plugins/branding/loading.d.mts +2 -0
  62. package/template/apps/agent-server/plugins/branding/loading.mjs +66 -0
  63. package/template/apps/agent-server/plugins/branding/loading.test.ts +89 -0
  64. package/template/apps/agent-server/plugins/branding/package.json +21 -0
  65. package/template/apps/agent-server/plugins/branding.test.ts +294 -0
  66. package/template/apps/agent-server/plugins/compaction.mjs +83 -0
  67. package/template/apps/agent-server/plugins/compaction.test.ts +91 -0
  68. package/template/apps/agent-server/plugins/confine-network.py +57 -0
  69. package/template/apps/agent-server/plugins/default-skills.test.ts +62 -0
  70. package/template/apps/agent-server/plugins/downloads/README.md +28 -0
  71. package/template/apps/agent-server/plugins/downloads/client.js +126 -0
  72. package/template/apps/agent-server/plugins/downloads/downloads.test.ts +222 -0
  73. package/template/apps/agent-server/plugins/downloads/index.d.mts +19 -0
  74. package/template/apps/agent-server/plugins/downloads/index.mjs +180 -0
  75. package/template/apps/agent-server/plugins/downloads/package.json +20 -0
  76. package/template/apps/agent-server/plugins/drop-overlay/README.md +24 -0
  77. package/template/apps/agent-server/plugins/drop-overlay/drop-overlay.test.ts +199 -0
  78. package/template/apps/agent-server/plugins/drop-overlay/index.d.mts +8 -0
  79. package/template/apps/agent-server/plugins/drop-overlay/index.mjs +12 -0
  80. package/template/apps/agent-server/plugins/drop-overlay/style.css +102 -0
  81. package/template/apps/agent-server/plugins/locale/client.js +61 -0
  82. package/template/apps/agent-server/plugins/locale/index.d.mts +9 -0
  83. package/template/apps/agent-server/plugins/locale/index.mjs +16 -0
  84. package/template/apps/agent-server/plugins/locale/locale.test.ts +217 -0
  85. package/template/apps/agent-server/plugins/locale/package.json +19 -0
  86. package/template/apps/agent-server/plugins/parallel.mjs +146 -0
  87. package/template/apps/agent-server/plugins/preset-registry.d.mts +2 -0
  88. package/template/apps/agent-server/plugins/preset-registry.mjs +41 -0
  89. package/template/apps/agent-server/plugins/preset-registry.test.ts +46 -0
  90. package/template/apps/agent-server/plugins/questions.d.mts +25 -0
  91. package/template/apps/agent-server/plugins/questions.mjs +142 -0
  92. package/template/apps/agent-server/plugins/questions.test.ts +105 -0
  93. package/template/apps/agent-server/plugins/settings/README.md +17 -0
  94. package/template/apps/agent-server/plugins/settings/client.js +102 -0
  95. package/template/apps/agent-server/plugins/settings/index.mjs +17 -0
  96. package/template/apps/agent-server/plugins/settings/package.json +19 -0
  97. package/template/apps/agent-server/plugins/settings/settings.test.ts +129 -0
  98. package/template/apps/agent-server/plugins/settings-controller.d.mts +4 -0
  99. package/template/apps/agent-server/plugins/settings-controller.mjs +31 -0
  100. package/template/apps/agent-server/plugins/settings-controller.test.ts +17 -0
  101. package/template/apps/agent-server/plugins/settings-dispatch.test.ts +34 -0
  102. package/template/apps/agent-server/plugins/shared-skills.d.mts +15 -0
  103. package/template/apps/agent-server/plugins/shared-skills.mjs +82 -0
  104. package/template/apps/agent-server/plugins/shared-skills.test.ts +51 -0
  105. package/template/apps/agent-server/plugins/skill-library/README.md +11 -0
  106. package/template/apps/agent-server/plugins/skill-library/archive.test.ts +43 -0
  107. package/template/apps/agent-server/plugins/skill-library/bundle.mjs +234 -0
  108. package/template/apps/agent-server/plugins/skill-library/client-chunks.test.ts +107 -0
  109. package/template/apps/agent-server/plugins/skill-library/client-form-mount.test.ts +139 -0
  110. package/template/apps/agent-server/plugins/skill-library/client-form.test.ts +261 -0
  111. package/template/apps/agent-server/plugins/skill-library/client-ui.test.ts +268 -0
  112. package/template/apps/agent-server/plugins/skill-library/client-use.test.ts +158 -0
  113. package/template/apps/agent-server/plugins/skill-library/client.editor.js +93 -0
  114. package/template/apps/agent-server/plugins/skill-library/client.form.js +316 -0
  115. package/template/apps/agent-server/plugins/skill-library/client.js +348 -0
  116. package/template/apps/agent-server/plugins/skill-library/client.request.js +52 -0
  117. package/template/apps/agent-server/plugins/skill-library/client.transfer.js +48 -0
  118. package/template/apps/agent-server/plugins/skill-library/client.use.js +46 -0
  119. package/template/apps/agent-server/plugins/skill-library/default-roots.test.ts +84 -0
  120. package/template/apps/agent-server/plugins/skill-library/draft.d.mts +17 -0
  121. package/template/apps/agent-server/plugins/skill-library/draft.mjs +152 -0
  122. package/template/apps/agent-server/plugins/skill-library/draft.test.ts +287 -0
  123. package/template/apps/agent-server/plugins/skill-library/index.d.mts +49 -0
  124. package/template/apps/agent-server/plugins/skill-library/index.mjs +226 -0
  125. package/template/apps/agent-server/plugins/skill-library/package.json +24 -0
  126. package/template/apps/agent-server/plugins/skill-library/presentation/README.md +27 -0
  127. package/template/apps/agent-server/plugins/skill-library/presentation/UPSTREAM.md +54 -0
  128. package/template/apps/agent-server/plugins/skill-library/presentation/boot.test.ts +150 -0
  129. package/template/apps/agent-server/plugins/skill-library/presentation/client.js +146 -0
  130. package/template/apps/agent-server/plugins/skill-library/presentation/client.test.ts +195 -0
  131. package/template/apps/agent-server/plugins/skill-library/presentation/index.d.mts +9 -0
  132. package/template/apps/agent-server/plugins/skill-library/presentation/index.mjs +30 -0
  133. package/template/apps/agent-server/plugins/skill-library/presentation/metadata.test.ts +82 -0
  134. package/template/apps/agent-server/plugins/skill-library/presentation/package.json +21 -0
  135. package/template/apps/agent-server/plugins/skill-library/presentation/react-boot.test.ts +162 -0
  136. package/template/apps/agent-server/plugins/skill-library/skills.test.ts +342 -0
  137. package/template/apps/agent-server/plugins/skill-library/storage.mjs +293 -0
  138. package/template/apps/agent-server/plugins/skill-library/style.css +229 -0
  139. package/template/apps/agent-server/plugins/skill-library/test-fixture.ts +77 -0
  140. package/template/apps/agent-server/plugins/skill-library/workflow.d.mts +18 -0
  141. package/template/apps/agent-server/plugins/skill-library/workflow.mjs +189 -0
  142. package/template/apps/agent-server/plugins/skill-library/workflow.test.ts +164 -0
  143. package/template/apps/agent-server/plugins/skills/README.md +5 -0
  144. package/template/apps/agent-server/plugins/skills/windy-data-summary/SKILL.md +14 -0
  145. package/template/apps/agent-server/plugins/skills/windy-extension-guide/SKILL.md +14 -0
  146. package/template/apps/agent-server/plugins/skills/windy-office/SKILL.md +14 -0
  147. package/template/apps/agent-server/plugins/skills/windy-skill-capture/SKILL.md +14 -0
  148. package/template/apps/agent-server/plugins/skills/windy-source-compare/SKILL.md +14 -0
  149. package/template/apps/agent-server/plugins/subprocess.mjs +40 -0
  150. package/template/apps/agent-server/plugins/theme/README.md +18 -0
  151. package/template/apps/agent-server/plugins/theme/client.js +18 -0
  152. package/template/apps/agent-server/plugins/theme/index.d.mts +9 -0
  153. package/template/apps/agent-server/plugins/theme/index.mjs +18 -0
  154. package/template/apps/agent-server/plugins/theme/package.json +19 -0
  155. package/template/apps/agent-server/plugins/theme/source-tokens.ts +82 -0
  156. package/template/apps/agent-server/plugins/theme/sync-tokens.ts +12 -0
  157. package/template/apps/agent-server/plugins/theme/theme.test.ts +193 -0
  158. package/template/apps/agent-server/plugins/theme/tokens.json +166 -0
  159. package/template/apps/agent-server/plugins/tool-catalog/README.md +79 -0
  160. package/template/apps/agent-server/plugins/tool-catalog/categories.mjs +111 -0
  161. package/template/apps/agent-server/plugins/tool-catalog/categories.test.ts +118 -0
  162. package/template/apps/agent-server/plugins/tool-catalog/client-cache.test.ts +264 -0
  163. package/template/apps/agent-server/plugins/tool-catalog/client.js +333 -0
  164. package/template/apps/agent-server/plugins/tool-catalog/client.test.ts +136 -0
  165. package/template/apps/agent-server/plugins/tool-catalog/discovery.d.mts +42 -0
  166. package/template/apps/agent-server/plugins/tool-catalog/discovery.mjs +242 -0
  167. package/template/apps/agent-server/plugins/tool-catalog/discovery.test.ts +229 -0
  168. package/template/apps/agent-server/plugins/tool-catalog/index.d.mts +5 -0
  169. package/template/apps/agent-server/plugins/tool-catalog/index.mjs +91 -0
  170. package/template/apps/agent-server/plugins/tool-catalog/package.json +23 -0
  171. package/template/apps/agent-server/plugins/tool-catalog/presentation.d.mts +21 -0
  172. package/template/apps/agent-server/plugins/tool-catalog/presentation.mjs +153 -0
  173. package/template/apps/agent-server/plugins/tool-catalog/presentation.test.ts +166 -0
  174. package/template/apps/agent-server/plugins/tool-catalog/routes.test.ts +209 -0
  175. package/template/apps/agent-server/plugins/tool-catalog/style.css +155 -0
  176. package/template/apps/agent-server/plugins/tool-catalog/use-tool.test.ts +160 -0
  177. package/template/apps/agent-server/plugins/tool-presentation/README.md +7 -0
  178. package/template/apps/agent-server/plugins/tool-presentation/build-client.ts +29 -0
  179. package/template/apps/agent-server/plugins/tool-presentation/client.js +312 -0
  180. package/template/apps/agent-server/plugins/tool-presentation/client.results.js +9 -0
  181. package/template/apps/agent-server/plugins/tool-presentation/client.test.ts +178 -0
  182. package/template/apps/agent-server/plugins/tool-presentation/index.mjs +10 -0
  183. package/template/apps/agent-server/plugins/tool-presentation/package.json +24 -0
  184. package/template/apps/agent-server/plugins/tool-presentation/result-discovery.mjs +43 -0
  185. package/template/apps/agent-server/plugins/tool-presentation/result-model.d.mts +51 -0
  186. package/template/apps/agent-server/plugins/tool-presentation/result-model.mjs +96 -0
  187. package/template/apps/agent-server/plugins/workspace/README.md +5 -0
  188. package/template/apps/agent-server/plugins/workspace/index.mjs +8 -0
  189. package/template/apps/agent-server/plugins/workspace/package.json +10 -0
  190. package/template/apps/agent-server/plugins/workspace/style.css +124 -0
  191. package/template/apps/agent-server/project/host.ts +13 -0
  192. package/template/apps/agent-server/runtime/artifacts.ts +115 -0
  193. package/template/apps/agent-server/runtime/audit.nodecheck.ts +60 -0
  194. package/template/apps/agent-server/runtime/capacity.ts +61 -0
  195. package/template/apps/agent-server/runtime/client-completion-budget.nodecheck.ts +92 -0
  196. package/template/apps/agent-server/runtime/compatibility.ts +33 -0
  197. package/template/apps/agent-server/runtime/completions.ts +320 -0
  198. package/template/apps/agent-server/runtime/config.ts +246 -0
  199. package/template/apps/agent-server/runtime/context-budget.ts +70 -0
  200. package/template/apps/agent-server/runtime/context-plugin.ts +306 -0
  201. package/template/apps/agent-server/runtime/context.nodecheck.ts +241 -0
  202. package/template/apps/agent-server/runtime/contracts.ts +201 -0
  203. package/template/apps/agent-server/runtime/dsh-engine.ts +196 -0
  204. package/template/apps/agent-server/runtime/evaluation-plugin.ts +115 -0
  205. package/template/apps/agent-server/runtime/evaluation.nodecheck.ts +194 -0
  206. package/template/apps/agent-server/runtime/events.ts +71 -0
  207. package/template/apps/agent-server/runtime/governance.ts +194 -0
  208. package/template/apps/agent-server/runtime/index.ts +339 -0
  209. package/template/apps/agent-server/runtime/internal-output.ts +37 -0
  210. package/template/apps/agent-server/runtime/isolation.nodecheck.ts +287 -0
  211. package/template/apps/agent-server/runtime/model-payload.ts +97 -0
  212. package/template/apps/agent-server/runtime/model-plugin.ts +308 -0
  213. package/template/apps/agent-server/runtime/model-route.ts +34 -0
  214. package/template/apps/agent-server/runtime/model-usage.ts +51 -0
  215. package/template/apps/agent-server/runtime/model-wire.ts +45 -0
  216. package/template/apps/agent-server/runtime/native-authorization.nodecheck.ts +126 -0
  217. package/template/apps/agent-server/runtime/native-completion.nodecheck.ts +81 -0
  218. package/template/apps/agent-server/runtime/output-validation.ts +66 -0
  219. package/template/apps/agent-server/runtime/production-capacity.nodecheck.ts +121 -0
  220. package/template/apps/agent-server/runtime/questions-workflow.nodecheck.ts +249 -0
  221. package/template/apps/agent-server/runtime/report-breakdown.ts +79 -0
  222. package/template/apps/agent-server/runtime/reporting.ts +219 -0
  223. package/template/apps/agent-server/runtime/run-completion.ts +39 -0
  224. package/template/apps/agent-server/runtime/run-request-digest.ts +18 -0
  225. package/template/apps/agent-server/runtime/runtime-test-fixtures.ts +264 -0
  226. package/template/apps/agent-server/runtime/runtime.nodecheck.ts +150 -0
  227. package/template/apps/agent-server/runtime/store-idempotency.nodecheck.ts +74 -0
  228. package/template/apps/agent-server/runtime/store.ts +324 -0
  229. package/template/apps/agent-server/runtime/structured-output-mode.nodecheck.ts +51 -0
  230. package/template/apps/agent-server/runtime/tool-name.ts +6 -0
  231. package/template/apps/agent-server/runtime/tool-plugin.ts +201 -0
  232. package/template/apps/agent-server/runtime/vision-readiness.ts +200 -0
  233. package/template/apps/agent-server/scripts/confinement-check.mjs +103 -0
  234. package/template/apps/agent-server/scripts/coordinator-check.mjs +344 -0
  235. package/template/apps/agent-server/scripts/documents-delivery-check.mjs +309 -0
  236. package/template/apps/agent-server/scripts/office-preview-check.mjs +92 -0
  237. package/template/apps/agent-server/scripts/test-confinement.ts +58 -0
  238. package/template/apps/agent-server/scripts/test-coordinator.ts +36 -0
  239. package/template/apps/agent-server/scripts/test-runtime.ts +46 -0
  240. package/template/apps/agent-server/tsconfig.json +21 -0
  241. package/template/apps/server/Dockerfile +3 -0
  242. package/template/apps/server/package.json +5 -1
  243. package/template/apps/server/scripts/check-dsh-platform-example.ts +251 -0
  244. package/template/apps/server/src/agent/dsh-runtime-wire.test.ts +33 -0
  245. package/template/apps/server/src/agent/governance-runtime.ts +41 -0
  246. package/template/apps/server/src/agent/remote-runtime-response.ts +1 -1
  247. package/template/apps/server/src/agent/run-contracts.ts +1 -0
  248. package/template/apps/server/src/agent/run-definition-support.ts +9 -0
  249. package/template/apps/server/src/agent/runtime-tool-composition.ts +2 -0
  250. package/template/apps/server/src/agent/workflow-runtime-bootstrap.ts +9 -0
  251. package/template/apps/server/src/agent-skills/access.ts +88 -0
  252. package/template/apps/server/src/agent-skills/bootstrap.ts +49 -0
  253. package/template/apps/server/src/agent-skills/builtin-registration.ts +83 -0
  254. package/template/apps/server/src/agent-skills/builtins.ts +19 -0
  255. package/template/apps/server/src/agent-skills/bundle-zip.ts +163 -0
  256. package/template/apps/server/src/agent-skills/bundle.test.ts +79 -0
  257. package/template/apps/server/src/agent-skills/bundle.ts +133 -0
  258. package/template/apps/server/src/agent-skills/contracts.ts +46 -0
  259. package/template/apps/server/src/agent-skills/drizzle-repository.ts +125 -0
  260. package/template/apps/server/src/agent-skills/input.ts +29 -0
  261. package/template/apps/server/src/agent-skills/postgres.integration.test.ts +348 -0
  262. package/template/apps/server/src/agent-skills/read-routes.test.ts +116 -0
  263. package/template/apps/server/src/agent-skills/reader.ts +108 -0
  264. package/template/apps/server/src/agent-skills/repository.ts +105 -0
  265. package/template/apps/server/src/agent-skills/routes.ts +176 -0
  266. package/template/apps/server/src/agent-skills/service.test.ts +295 -0
  267. package/template/apps/server/src/agent-skills/service.ts +301 -0
  268. package/template/apps/server/src/agent-workflow/preset-registry.test.ts +137 -0
  269. package/template/apps/server/src/agent-workflow/preset-registry.ts +191 -0
  270. package/template/apps/server/src/agent-workflow/preset-routes.test.ts +94 -0
  271. package/template/apps/server/src/agent-workflow/preset-routes.ts +45 -0
  272. package/template/apps/server/src/ai-runtime-report/service.test.ts +10 -7
  273. package/template/apps/server/src/ai-runtime-report/service.ts +1 -1
  274. package/template/apps/server/src/app/agent-workflow-presets.ts +4 -0
  275. package/template/apps/server/src/app/dsh-skill-draft-audit.test.ts +195 -0
  276. package/template/apps/server/src/app/dsh-skill-draft-audit.ts +115 -0
  277. package/template/apps/server/src/app/dsh-workbench-audit.test.ts +71 -0
  278. package/template/apps/server/src/app/dsh-workbench-audit.ts +34 -0
  279. package/template/apps/server/src/app/dsh-workbench-handshake.test.ts +63 -0
  280. package/template/apps/server/src/app/dsh-workbench-handshake.ts +48 -0
  281. package/template/apps/server/src/app/dsh-workbench-http.test.ts +96 -0
  282. package/template/apps/server/src/app/dsh-workbench-lan-origin.test.ts +114 -0
  283. package/template/apps/server/src/app/dsh-workbench-launch.test.ts +70 -0
  284. package/template/apps/server/src/app/dsh-workbench-origin.test.ts +54 -0
  285. package/template/apps/server/src/app/dsh-workbench-proxy.ts +205 -0
  286. package/template/apps/server/src/app/dsh-workbench-session-conflict.test.ts +61 -0
  287. package/template/apps/server/src/app/dsh-workbench-session.ts +59 -0
  288. package/template/apps/server/src/app/dsh-workbench-socket-audit.test.ts +115 -0
  289. package/template/apps/server/src/app/dsh-workbench-socket.test.ts +246 -0
  290. package/template/apps/server/src/app/dsh-workbench-socket.ts +272 -0
  291. package/template/apps/server/src/app/dsh-workbench-test-support.ts +158 -0
  292. package/template/apps/server/src/app/dsh-workbench.test.ts +213 -0
  293. package/template/apps/server/src/app/dsh-workbench.ts +279 -0
  294. package/template/apps/server/src/app/workbench-public-origin.ts +16 -0
  295. package/template/apps/server/src/data-governance/user-plaintext-routes.test.ts +3 -0
  296. package/template/apps/server/src/http-app.ts +31 -0
  297. package/template/apps/server/src/mcp/adapter.ts +1 -0
  298. package/template/apps/server/src/module-composition.test.ts +23 -0
  299. package/template/apps/server/src/module-composition.ts +9 -2
  300. package/template/apps/server/src/observability/bootstrap.ts +12 -0
  301. package/template/apps/server/src/observability/diagnostic-failure-recorder.ts +94 -0
  302. package/template/apps/server/src/observability/diagnostic-http-contract.test.ts +42 -0
  303. package/template/apps/server/src/observability/diagnostic-index.test.ts +89 -0
  304. package/template/apps/server/src/observability/diagnostic-index.ts +88 -0
  305. package/template/apps/server/src/observability/diagnostic-repository.ts +67 -0
  306. package/template/apps/server/src/platform-app-bootstrap.ts +42 -0
  307. package/template/apps/server/src/platform-http-runtime.ts +6 -0
  308. package/template/apps/server/src/runtime-development.test.ts +25 -0
  309. package/template/apps/server/src/runtime-development.ts +6 -44
  310. package/template/apps/server/src/system/diagnostic-routes.test.ts +78 -0
  311. package/template/apps/server/src/system/diagnostic-routes.ts +66 -0
  312. package/template/apps/web/Dockerfile +9 -1
  313. package/template/apps/web/dev/start.ts +21 -10
  314. package/template/apps/web/dsh-workbench-location.ts +21 -0
  315. package/template/apps/web/dsh-workbench-proxy.test.ts +121 -0
  316. package/template/apps/web/dsh-workbench-proxy.ts +194 -0
  317. package/template/apps/web/package.json +3 -1
  318. package/template/apps/web/server.ts +27 -6
  319. package/template/apps/web/src/composables/useLoginFlow.ts +13 -1
  320. package/template/apps/web/src/pages/errors/PlatformErrorPage.vue +6 -0
  321. package/template/apps/web/src/pages/errors/PlatformErrorPage.webtest.ts +14 -1
  322. package/template/apps/web/src/pages/errors/error-page-extension.ts +1 -0
  323. package/template/apps/web/src/pages/system/AgentNativePage.vue +44 -0
  324. package/template/apps/web/src/pages/system/AgentWorkflowPage.vue +20 -7
  325. package/template/apps/web/src/pages/system/DiagnosticLookupPage.vue +56 -0
  326. package/template/apps/web/src/pages/system/DiagnosticLookupPage.webtest.ts +99 -0
  327. package/template/apps/web/src/pages/system/SystemAgentSkillsPage.vue +88 -0
  328. package/template/apps/web/src/pages/system/components/DiagnosticRecordDetails.vue +52 -0
  329. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillDetailDialog.vue +166 -0
  330. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillGovernanceActionDialog.vue +51 -0
  331. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillImportDialog.vue +320 -0
  332. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillImportDialog.webtest.ts +96 -0
  333. package/template/apps/web/src/pages/system/components/agent-skills/AgentSkillsTable.vue +69 -0
  334. package/template/apps/web/src/pages/system/components/agent-workflow/WorkflowPresetCatalog.vue +82 -0
  335. package/template/apps/web/src/pages/system/components/agent-workflow/WorkflowPresetCatalog.webtest.ts +57 -0
  336. package/template/apps/web/src/pages/system/composables/useAgentSkillsGovernance.ts +105 -0
  337. package/template/apps/web/src/pages/system/composables/useAgentWorkflowPresets.ts +44 -0
  338. package/template/apps/web/src/pages/system/composables/useDiagnosticLookup.ts +64 -0
  339. package/template/apps/web/src/router/error-navigation.ts +3 -1
  340. package/template/apps/web/src/router/error-navigation.webtest.ts +14 -2
  341. package/template/apps/web/src/router/index.ts +8 -49
  342. package/template/apps/web/src/router/platform-admin-pages.ts +79 -0
  343. package/template/apps/web/src/router/platform-admin-route-bindings.ts +8 -0
  344. package/template/apps/web/src/services/agent-skills-api.ts +55 -0
  345. package/template/apps/web/src/services/agent-workflow-api.ts +12 -0
  346. package/template/apps/web/src/services/diagnostics-api.ts +12 -0
  347. package/template/apps/web/src/services/http.ts +18 -0
  348. package/template/apps/web/src/services/http.webtest.ts +51 -0
  349. package/template/apps/web/vite.config.ts +39 -0
  350. package/template/deploy/dsh/README.md +5 -0
  351. package/template/deploy/dsh/documents/README.md +9 -0
  352. package/template/deploy/dsh/documents/requirements.in +6 -0
  353. package/template/deploy/dsh/documents/requirements.lock +72 -0
  354. package/template/docker-compose.yml +24 -10
  355. package/template/docs/adr/0004-embedded-dsh-runtime.md +9 -0
  356. package/template/docs/architecture/agent-admin-workbench-implementation.md +73 -0
  357. package/template/docs/architecture/agent-admin-workbench-plan.md +41 -0
  358. package/template/docs/architecture/agent-harness.md +2 -0
  359. package/template/docs/architecture/agent-runtime-compatibility.md +2 -0
  360. package/template/docs/architecture/embedded-dsh-integration.md +44 -0
  361. package/template/docs/development/dsh-plugins.md +55 -0
  362. package/template/docs/operations/dsh-agent-migration.md +98 -0
  363. package/template/docs/platform/agent-production-store.md +5 -78
  364. package/template/docs/platform/agent-runtime-observability.md +2 -0
  365. package/template/docs/platform/agent-runtime.md +2 -0
  366. package/template/docs/platform/agent-skills.md +25 -0
  367. package/template/package.json +4 -3
  368. package/template/packages/database/drizzle/0064_dsh_skills_diagnostics.sql +42 -0
  369. package/template/packages/database/drizzle/meta/0064_snapshot.json +15349 -0
  370. package/template/packages/database/drizzle/meta/_journal.json +7 -0
  371. package/template/packages/database/package.json +2 -2
  372. package/template/packages/database/src/schema/agent-skills.ts +65 -0
  373. package/template/packages/database/src/schema/diagnostics.ts +27 -0
  374. package/template/packages/database/src/schema/index.ts +8 -0
  375. package/template/packages/modules/package.json +1 -1
  376. package/template/packages/modules/src/system-admin-routes.ts +24 -0
  377. package/template/packages/modules/src/system-admin-ui-catalog.ts +17 -10
  378. package/template/packages/modules/src/system-agent-admin-bindings.ts +2 -0
  379. package/template/packages/modules/src/system-agent-admin-menus.ts +20 -0
  380. package/template/packages/modules/src/system-agent-audit-actions.ts +3 -0
  381. package/template/packages/modules/src/system-agent-dsh.ts +119 -0
  382. package/template/packages/modules/src/system-api-permissions.ts +9 -0
  383. package/template/packages/modules/src/system-audit-actions.ts +11 -0
  384. package/template/packages/modules/src/system-features.ts +5 -0
  385. package/template/packages/modules/src/system-module-audit-selection.ts +25 -0
  386. package/template/packages/modules/src/system-module-catalog.ts +12 -32
  387. package/template/packages/modules/src/system-modules.ts +14 -3
  388. package/template/packages/modules/src/system-permissions.ts +10 -0
  389. package/template/packages/server-sdk/package.json +2 -2
  390. package/template/packages/shared/index.ts +12 -0
  391. package/template/packages/shared/package.json +1 -1
  392. package/template/packages/shared/src/agent-skills.ts +68 -0
  393. package/template/packages/shared/src/agent-workflow-presets.ts +26 -0
  394. package/template/packages/shared/src/diagnostics.ts +13 -0
  395. package/template/packages/shared/src/rbac.ts +1 -0
  396. package/template/apps/agent-server/install-python-dependencies.sh +0 -92
  397. package/template/apps/agent-server/pyproject.toml +0 -51
  398. package/template/apps/agent-server/src/southwind_agent_server/__init__.py +0 -5
  399. package/template/apps/agent-server/src/southwind_agent_server/app.py +0 -344
  400. package/template/apps/agent-server/src/southwind_agent_server/approval_resolution.py +0 -30
  401. package/template/apps/agent-server/src/southwind_agent_server/artifact_input.py +0 -153
  402. package/template/apps/agent-server/src/southwind_agent_server/asgi.py +0 -8
  403. package/template/apps/agent-server/src/southwind_agent_server/attempt_context.py +0 -199
  404. package/template/apps/agent-server/src/southwind_agent_server/attempt_context_projection.py +0 -203
  405. package/template/apps/agent-server/src/southwind_agent_server/client_completion_contracts.py +0 -61
  406. package/template/apps/agent-server/src/southwind_agent_server/client_completion_governance.py +0 -82
  407. package/template/apps/agent-server/src/southwind_agent_server/client_completion_routes.py +0 -121
  408. package/template/apps/agent-server/src/southwind_agent_server/client_completion_runtime.py +0 -158
  409. package/template/apps/agent-server/src/southwind_agent_server/config.py +0 -267
  410. package/template/apps/agent-server/src/southwind_agent_server/context_message_digest.py +0 -24
  411. package/template/apps/agent-server/src/southwind_agent_server/context_version_contracts.py +0 -71
  412. package/template/apps/agent-server/src/southwind_agent_server/context_version_port.py +0 -307
  413. package/template/apps/agent-server/src/southwind_agent_server/contracts.py +0 -297
  414. package/template/apps/agent-server/src/southwind_agent_server/deterministic.py +0 -63
  415. package/template/apps/agent-server/src/southwind_agent_server/engine.py +0 -134
  416. package/template/apps/agent-server/src/southwind_agent_server/engine_capacity.py +0 -31
  417. package/template/apps/agent-server/src/southwind_agent_server/engine_identity.py +0 -2
  418. package/template/apps/agent-server/src/southwind_agent_server/fingerprint.py +0 -61
  419. package/template/apps/agent-server/src/southwind_agent_server/health_routes.py +0 -93
  420. package/template/apps/agent-server/src/southwind_agent_server/http_helpers.py +0 -62
  421. package/template/apps/agent-server/src/southwind_agent_server/lease.py +0 -15
  422. package/template/apps/agent-server/src/southwind_agent_server/multimodal.py +0 -76
  423. package/template/apps/agent-server/src/southwind_agent_server/openai_engine.py +0 -329
  424. package/template/apps/agent-server/src/southwind_agent_server/openai_engine_validation.py +0 -165
  425. package/template/apps/agent-server/src/southwind_agent_server/openai_provider.py +0 -345
  426. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_insert.py +0 -37
  427. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_queries.py +0 -235
  428. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_replay.py +0 -44
  429. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_status.py +0 -83
  430. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_store.py +0 -336
  431. package/template/apps/agent-server/src/southwind_agent_server/postgres_report_summary.py +0 -304
  432. package/template/apps/agent-server/src/southwind_agent_server/postgres_store.py +0 -335
  433. package/template/apps/agent-server/src/southwind_agent_server/postgres_store_backend.py +0 -333
  434. package/template/apps/agent-server/src/southwind_agent_server/provider_audit.py +0 -144
  435. package/template/apps/agent-server/src/southwind_agent_server/provider_governance.py +0 -309
  436. package/template/apps/agent-server/src/southwind_agent_server/provider_output_guidance.py +0 -34
  437. package/template/apps/agent-server/src/southwind_agent_server/readiness_pin.py +0 -37
  438. package/template/apps/agent-server/src/southwind_agent_server/report_lifecycle.py +0 -218
  439. package/template/apps/agent-server/src/southwind_agent_server/report_metrics.py +0 -149
  440. package/template/apps/agent-server/src/southwind_agent_server/report_presenter.py +0 -300
  441. package/template/apps/agent-server/src/southwind_agent_server/report_routes.py +0 -132
  442. package/template/apps/agent-server/src/southwind_agent_server/report_store.py +0 -298
  443. package/template/apps/agent-server/src/southwind_agent_server/report_store_protocol.py +0 -75
  444. package/template/apps/agent-server/src/southwind_agent_server/report_types.py +0 -118
  445. package/template/apps/agent-server/src/southwind_agent_server/run_admission.py +0 -64
  446. package/template/apps/agent-server/src/southwind_agent_server/run_capacity.py +0 -59
  447. package/template/apps/agent-server/src/southwind_agent_server/runtime_budget.py +0 -74
  448. package/template/apps/agent-server/src/southwind_agent_server/runtime_compatibility.py +0 -89
  449. package/template/apps/agent-server/src/southwind_agent_server/runtime_factory.py +0 -105
  450. package/template/apps/agent-server/src/southwind_agent_server/runtime_logging.py +0 -57
  451. package/template/apps/agent-server/src/southwind_agent_server/service.py +0 -325
  452. package/template/apps/agent-server/src/southwind_agent_server/service_control.py +0 -64
  453. package/template/apps/agent-server/src/southwind_agent_server/service_errors.py +0 -4
  454. package/template/apps/agent-server/src/southwind_agent_server/service_execution.py +0 -34
  455. package/template/apps/agent-server/src/southwind_agent_server/service_tasks.py +0 -34
  456. package/template/apps/agent-server/src/southwind_agent_server/signal_events.py +0 -53
  457. package/template/apps/agent-server/src/southwind_agent_server/sqlite_catalog.py +0 -118
  458. package/template/apps/agent-server/src/southwind_agent_server/sqlite_errors.py +0 -2
  459. package/template/apps/agent-server/src/southwind_agent_server/sqlite_schema.py +0 -73
  460. package/template/apps/agent-server/src/southwind_agent_server/sqlite_serialization.py +0 -16
  461. package/template/apps/agent-server/src/southwind_agent_server/sqlite_store.py +0 -350
  462. package/template/apps/agent-server/src/southwind_agent_server/sse.py +0 -41
  463. package/template/apps/agent-server/src/southwind_agent_server/store.py +0 -255
  464. package/template/apps/agent-server/src/southwind_agent_server/store_cipher.py +0 -40
  465. package/template/apps/agent-server/src/southwind_agent_server/structured_logging.py +0 -145
  466. package/template/apps/agent-server/src/southwind_agent_server/telemetry.py +0 -93
  467. package/template/apps/agent-server/src/southwind_agent_server/tool_host.py +0 -152
  468. package/template/apps/agent-server/src/southwind_agent_server/trajectory.py +0 -137
  469. package/template/apps/agent-server/src/southwind_agent_server/unavailable_engine.py +0 -58
  470. package/template/apps/agent-server/src/southwind_agent_server/vision_probe.py +0 -87
  471. package/template/apps/agent-server/src/southwind_agent_server/vision_requirement.py +0 -28
  472. package/template/apps/agent-server/src/southwind_agent_server/vlm_readiness.py +0 -247
  473. package/template/apps/agent-server/tests/__init__.py +0 -1
  474. package/template/apps/agent-server/tests/openai_provider_test_support.py +0 -131
  475. package/template/apps/agent-server/tests/test_api.py +0 -305
  476. package/template/apps/agent-server/tests/test_artifact_input.py +0 -110
  477. package/template/apps/agent-server/tests/test_client_completion.py +0 -230
  478. package/template/apps/agent-server/tests/test_config.py +0 -106
  479. package/template/apps/agent-server/tests/test_fingerprint.py +0 -10
  480. package/template/apps/agent-server/tests/test_multimodal.py +0 -81
  481. package/template/apps/agent-server/tests/test_openai_provider.py +0 -320
  482. package/template/apps/agent-server/tests/test_postgres_report_status.py +0 -59
  483. package/template/apps/agent-server/tests/test_postgres_report_summary.py +0 -298
  484. package/template/apps/agent-server/tests/test_postgres_store.py +0 -135
  485. package/template/apps/agent-server/tests/test_provider_attempt_reporting.py +0 -140
  486. package/template/apps/agent-server/tests/test_provider_governance.py +0 -276
  487. package/template/apps/agent-server/tests/test_report_attempt_lifecycle.py +0 -126
  488. package/template/apps/agent-server/tests/test_report_resilience.py +0 -183
  489. package/template/apps/agent-server/tests/test_report_routes.py +0 -143
  490. package/template/apps/agent-server/tests/test_report_store.py +0 -347
  491. package/template/apps/agent-server/tests/test_report_summary_parity.py +0 -116
  492. package/template/apps/agent-server/tests/test_report_terminal_sync.py +0 -177
  493. package/template/apps/agent-server/tests/test_run_capacity.py +0 -112
  494. package/template/apps/agent-server/tests/test_run_operational_logging.py +0 -114
  495. package/template/apps/agent-server/tests/test_runtime_compatibility.py +0 -119
  496. package/template/apps/agent-server/tests/test_runtime_factory_readiness.py +0 -52
  497. package/template/apps/agent-server/tests/test_sqlite_store.py +0 -182
  498. package/template/apps/agent-server/tests/test_structured_logging.py +0 -142
  499. package/template/apps/agent-server/tests/test_telemetry.py +0 -25
  500. package/template/apps/agent-server/tests/test_tool_approval.py +0 -28
  501. package/template/apps/agent-server/tests/test_tool_structured_output.py +0 -347
  502. package/template/apps/agent-server/tests/test_trajectory.py +0 -91
  503. package/template/apps/agent-server/tests/test_vision_readiness_enforcement.py +0 -72
  504. package/template/apps/agent-server/tests/test_vlm_readiness.py +0 -106
  505. package/template/apps/agent-server/uv.lock +0 -831
@@ -0,0 +1,177 @@
1
+ """Synthetic local file round-trips, not a DSH/model/customer acceptance test."""
2
+
3
+ import argparse
4
+ import copy
5
+ import json
6
+ import platform
7
+ from datetime import datetime
8
+ from decimal import Decimal
9
+ from importlib.metadata import version
10
+ from pathlib import Path
11
+ from tempfile import mkdtemp
12
+
13
+ from docx import Document
14
+ from openpyxl import Workbook, load_workbook
15
+ from openpyxl.xml import DEFUSEDXML
16
+ from reportlab.pdfbase import pdfmetrics
17
+ from reportlab.pdfbase.cidfonts import UnicodeCIDFont
18
+ from reportlab.pdfgen.canvas import Canvas
19
+
20
+ from office import digest, read_text, save_new, summarize_excel, write_revision
21
+ from query_report import generate_report, validate_snapshot
22
+
23
+
24
+ def require(condition: bool, message: str) -> None:
25
+ if not condition:
26
+ raise AssertionError(message)
27
+
28
+
29
+ def rejects(action, message: str) -> None:
30
+ try:
31
+ action()
32
+ except (ValueError, FileExistsError):
33
+ return
34
+ raise AssertionError(message)
35
+
36
+
37
+ def fixture_snapshot() -> dict:
38
+ return {
39
+ "schemaVersion": 1,
40
+ "source": {"kind": "synthetic-fixture", "tool": "fixture.query",
41
+ "queryId": "synthetic-query-001", "capturedAt": "2026-10-15T08:00:00Z",
42
+ "scope": "合成案件 SYNTHETIC-001", "unit": "元", "query": "合成记录,金额单位为元"},
43
+ "complete": True, "errors": [], "total": 3,
44
+ "pages": [
45
+ {"cursor": None, "nextCursor": "page-2", "status": "success", "truncated": False,
46
+ "records": [{"id": "001", "label": "样例甲", "amount": "10.10",
47
+ "sourceRef": "fixture://SYNTHETIC-001/001"},
48
+ {"id": "002", "label": "样例乙", "amount": "20.20",
49
+ "sourceRef": "fixture://SYNTHETIC-001/002"}]},
50
+ {"cursor": "page-2", "nextCursor": None, "status": "success", "truncated": False,
51
+ "records": [{"id": "003", "label": "样例丙", "amount": "0.03",
52
+ "sourceRef": "fixture://SYNTHETIC-001/003"}]},
53
+ ],
54
+ }
55
+
56
+
57
+ def document_checks(directory: Path) -> dict:
58
+ original = directory / "original.docx"
59
+ document = Document()
60
+ document.add_heading("合成材料", 0)
61
+ document.add_paragraph("初稿:甲事项尚待整理。")
62
+ save_new(document, original)
63
+ source_hash = digest(original)
64
+ revision, continued = directory / "revision-1.docx", directory / "revision-2.docx"
65
+ write_revision(original, revision, read_text(original).replace("尚待整理", "已完成整理"), "修订稿")
66
+ write_revision(revision, continued, read_text(revision) + "\n续改:补充核对记录。", "续改稿")
67
+ require("已完成整理" in read_text(continued) and "补充核对记录" in read_text(continued),
68
+ "DOCX continuation did not round-trip")
69
+ require(digest(original) == source_hash, "original DOCX was modified")
70
+ rejects(lambda: write_revision(original, original, "覆盖", "覆盖"), "original overwrite accepted")
71
+ rejects(lambda: write_revision(original, revision, "覆盖", "覆盖"), "revision overwrite accepted")
72
+ pdf = directory / "original.pdf"
73
+ pdfmetrics.registerFont(UnicodeCIDFont("STSong-Light"))
74
+ canvas = Canvas(str(pdf), invariant=1)
75
+ canvas.setFont("STSong-Light", 12)
76
+ canvas.drawString(72, 750, "合成 PDF:金额 30.33 元。")
77
+ canvas.save()
78
+ pdf_hash = digest(pdf)
79
+ extracted = read_text(pdf)
80
+ require("30.33" in extracted and "合成" in extracted, "PDF text extraction failed")
81
+ pdf_revision = directory / "pdf-revision.docx"
82
+ write_revision(pdf, pdf_revision, extracted + "\n已核对金额与来源。", "PDF 改写稿")
83
+ require("已核对金额" in read_text(pdf_revision), "PDF-to-DOCX read-back failed")
84
+ require(digest(pdf) == pdf_hash, "original PDF was modified")
85
+ return {"docxContinuation": "passed", "pdfTextToDocx": "passed",
86
+ "sourcePreservation": "passed", "existingOutputRefusal": "passed"}
87
+
88
+
89
+ def excel_checks(directory: Path) -> dict:
90
+ original, result = directory / "original.xlsx", directory / "summary.xlsx"
91
+ workbook = Workbook()
92
+ sheet = workbook.active
93
+ sheet.append(["编号", "名称", "日期", "金额"])
94
+ for identifier, label, amount in (("000001", "样例甲", "10.10"),
95
+ ("000002", "样例乙", "20.20"),
96
+ ("000003", "样例丙", "0.03")):
97
+ sheet.append([identifier, label, datetime(2026, 10, 15), amount])
98
+ sheet.cell(sheet.max_row, 1).number_format = "@"
99
+ sheet.cell(sheet.max_row, 3).number_format = "yyyy-mm-dd"
100
+ save_new(workbook, original)
101
+ original_hash = digest(original)
102
+ require(summarize_excel(original, result, unit="元") == Decimal("30.33"), "decimal total mismatch")
103
+ check = load_workbook(result, read_only=True, data_only=True)
104
+ try:
105
+ rows = list(check.active.values)
106
+ require(rows[1][0] == "000001" and rows[1][1] == "样例甲", "Chinese/leading zeros lost")
107
+ require(rows[1][2] == datetime(2026, 10, 15), "Excel date lost")
108
+ require(rows[-1][3] == "30.33", "decimal summary did not round-trip exactly")
109
+ finally:
110
+ check.close()
111
+ require(digest(original) == original_hash, "original Excel was modified")
112
+ sheet["D2"] = "=1+2"
113
+ formula = directory / "formula.xlsx"
114
+ save_new(workbook, formula)
115
+ rejects(lambda: summarize_excel(formula, directory / "formula-result.xlsx", unit="元"),
116
+ "unverified formula engine accepted")
117
+ return {"chineseDateLeadingZeros": "passed", "decimalTotal": "30.33",
118
+ "formulaRefusal": "passed"}
119
+
120
+
121
+ def query_checks(directory: Path) -> dict:
122
+ snapshot = fixture_snapshot()
123
+ source, output = directory / "query-snapshot.json", directory / "query-report.docx"
124
+ source.write_text(json.dumps(snapshot, ensure_ascii=False, indent=2), encoding="utf-8")
125
+ result = generate_report(source, output)
126
+ text = read_text(output)
127
+ require(result["records"] == 3 and result["total"] == "30.33", "query totals differ")
128
+ require(digest(source) in text and "fixture://SYNTHETIC-001/003" in text,
129
+ "report source attribution missing")
130
+ require("金额合计:30.33 元" in text, "source unit was not preserved")
131
+ invalid = []
132
+ for field, value in (("complete", False), ("errors", ["failed page"]), ("total", 4)):
133
+ candidate = copy.deepcopy(snapshot)
134
+ candidate[field] = value
135
+ invalid.append(candidate)
136
+ for field, value in (("truncated", True), ("status", "failed"),
137
+ ("cursor", "missing-page"), ("nextCursor", "not-finished")):
138
+ candidate = copy.deepcopy(snapshot)
139
+ candidate["pages"][-1][field] = value
140
+ invalid.append(candidate)
141
+ duplicate = copy.deepcopy(snapshot)
142
+ duplicate["pages"][-1]["records"][0]["id"] = "001"
143
+ invalid.append(duplicate)
144
+ missing_unit = copy.deepcopy(snapshot)
145
+ del missing_unit["source"]["unit"]
146
+ invalid.append(missing_unit)
147
+ for candidate in invalid:
148
+ rejects(lambda: validate_snapshot(candidate), "incomplete/invalid query export accepted")
149
+ return {"sourceCoverage": "passed", "invalidSnapshotsRejected": len(invalid), **result}
150
+
151
+
152
+ def main() -> None:
153
+ parser = argparse.ArgumentParser(description=__doc__)
154
+ parser.add_argument("--output-dir", type=Path,
155
+ help="must be new; defaults to an isolated directory under /tmp")
156
+ arguments = parser.parse_args()
157
+ directory = arguments.output_dir or Path(mkdtemp(prefix="dsh-documents-"))
158
+ if arguments.output_dir:
159
+ directory.mkdir(parents=True, exist_ok=False)
160
+ require(DEFUSEDXML, "openpyxl must use installed defusedxml protection")
161
+ checks = {"documents": document_checks(directory), "excel": excel_checks(directory),
162
+ "queryReport": query_checks(directory)}
163
+ evidence = {"validation": "synthetic-library-round-trip", "outputDirectory": str(directory),
164
+ "runtime": {"python": platform.python_version(), "platform": platform.platform(),
165
+ "packages": {name: version(name) for name in (
166
+ "python-docx", "openpyxl", "pypdf", "reportlab", "defusedxml",
167
+ "lxml", "typing-extensions", "et-xmlfile", "pillow", "charset-normalizer")}},
168
+ "checks": checks, "visualQuality": "not-verified", "realModel": "not-invoked",
169
+ "liveMcpAuthorization": "not-verified", "automaticBusinessArchive": False,
170
+ "files": {file.name: digest(file) for file in directory.iterdir() if file.is_file()}}
171
+ (directory / "evidence.json").write_text(json.dumps(evidence, ensure_ascii=False, indent=2),
172
+ encoding="utf-8")
173
+ print(json.dumps(evidence, ensure_ascii=False, indent=2))
174
+
175
+
176
+ if __name__ == "__main__":
177
+ main()
@@ -0,0 +1,185 @@
1
+ """Focused document regressions; no model, server, browser, or live MCP is involved."""
2
+
3
+ import copy
4
+ import json
5
+ import re
6
+ import tempfile
7
+ import unittest
8
+ from datetime import datetime
9
+ from decimal import Decimal
10
+ from pathlib import Path
11
+ from zipfile import ZipFile
12
+
13
+ from docx import Document
14
+ from openpyxl import Workbook, load_workbook
15
+ from reportlab.pdfgen.canvas import Canvas
16
+
17
+ from office import digest, read_text, save_new, summarize_excel, write_revision
18
+ from query_report import generate_report, validate_snapshot
19
+ from smoke import fixture_snapshot
20
+
21
+
22
+ class DocumentBoundaries(unittest.TestCase):
23
+ def setUp(self):
24
+ self.temporary = tempfile.TemporaryDirectory(prefix="dsh-document-boundaries-")
25
+ self.directory = Path(self.temporary.name)
26
+
27
+ def tearDown(self):
28
+ self.temporary.cleanup()
29
+
30
+ def workbook(self, path: Path, *, literal: bool = False, formula: bool = False):
31
+ workbook = Workbook()
32
+ sheet = workbook.active
33
+ sheet.title = "来源数据"
34
+ sheet.append(["编号", "名称", "日期", "金额"])
35
+ sheet.append(["000001", '=HYPERLINK("https://example.invalid/","样例")',
36
+ datetime(2026, 10, 16), "10.10"])
37
+ sheet["B2"].data_type = "s" if literal else "f"
38
+ if not literal and not formula:
39
+ sheet["B2"] = "普通样例"
40
+ sheet.append(["000002", "第二行", datetime(2026, 10, 16), "20.20"])
41
+ save_new(workbook, path)
42
+
43
+ def test_literal_equals_text_stays_text_with_source_and_unit(self):
44
+ source, output = self.directory / "source.xlsx", self.directory / "summary.xlsx"
45
+ self.workbook(source, literal=True)
46
+ before = digest(source)
47
+ self.assertEqual(summarize_excel(source, output, unit="万元"), Decimal("30.30"))
48
+ workbook = load_workbook(output, data_only=False)
49
+ try:
50
+ self.assertEqual(workbook.active["B2"].data_type, "s")
51
+ self.assertEqual(workbook.active["B2"].value,
52
+ '=HYPERLINK("https://example.invalid/","样例")')
53
+ self.assertEqual(workbook.active["A2"].value, "000001")
54
+ self.assertIn("万元", workbook.active["D1"].comment.text)
55
+ provenance = dict(workbook["来源说明"].values)
56
+ self.assertEqual(provenance["金额单位"], "万元")
57
+ self.assertEqual(provenance["单位转换"], "未转换")
58
+ self.assertEqual(provenance["来源 SHA256"], before)
59
+ self.assertEqual(provenance["来源范围"], "来源数据!A1:D3")
60
+ self.assertEqual(provenance["Decimal 合计"], "30.30")
61
+ finally:
62
+ workbook.close()
63
+ self.assertEqual(digest(source), before)
64
+
65
+ def test_real_formula_and_missing_unit_are_rejected_without_output(self):
66
+ source, output = self.directory / "formula.xlsx", self.directory / "rejected.xlsx"
67
+ self.workbook(source, formula=True)
68
+ with self.assertRaisesRegex(ValueError, "formula"):
69
+ summarize_excel(source, output, unit="元")
70
+ self.assertFalse(output.exists())
71
+ with self.assertRaisesRegex(ValueError, "unit"):
72
+ summarize_excel(source, output, unit="")
73
+ self.assertFalse(output.exists())
74
+
75
+ def test_false_xlsx_dimensions_do_not_silently_drop_rows(self):
76
+ source = self.directory / "source.xlsx"
77
+ self.workbook(source)
78
+ forged = self.directory / "understated-dimensions.xlsx"
79
+ with ZipFile(source) as original, ZipFile(forged, "w") as target:
80
+ for entry in original.infolist():
81
+ content = original.read(entry.filename)
82
+ if entry.filename == "xl/worksheets/sheet1.xml":
83
+ content = re.sub(rb'<dimension ref="[^"]+"', b'<dimension ref="A1:D1"', content)
84
+ target.writestr(entry, content)
85
+ output = self.directory / "complete-summary.xlsx"
86
+ self.assertEqual(summarize_excel(forged, output, unit="元"), Decimal("30.30"))
87
+ workbook = load_workbook(output, read_only=True)
88
+ try:
89
+ self.assertEqual(workbook.active["A3"].value, "000002")
90
+ self.assertEqual(dict(workbook["来源说明"].values)["数据行数"], "2")
91
+ finally:
92
+ workbook.close()
93
+
94
+ def test_excel_error_cell_is_rejected_but_literal_error_name_is_kept(self):
95
+ source = self.directory / "error.xlsx"
96
+ self.workbook(source)
97
+ workbook = load_workbook(source)
98
+ try:
99
+ workbook.active["B2"] = "#REF!"
100
+ error_file = self.directory / "actual-error.xlsx"
101
+ save_new(workbook, error_file)
102
+ with self.assertRaisesRegex(ValueError, "error cells"):
103
+ summarize_excel(error_file, self.directory / "rejected-error.xlsx", unit="元")
104
+ workbook.active["B2"].data_type = "s"
105
+ literal_file = self.directory / "literal-error.xlsx"
106
+ save_new(workbook, literal_file)
107
+ finally:
108
+ workbook.close()
109
+ output = self.directory / "literal-error-result.xlsx"
110
+ summarize_excel(literal_file, output, unit="元")
111
+ result = load_workbook(output, data_only=False)
112
+ try:
113
+ self.assertEqual((result.active["B2"].value, result.active["B2"].data_type), ("#REF!", "s"))
114
+ finally:
115
+ result.close()
116
+
117
+ def test_docx_body_table_order_and_original_revision_are_preserved(self):
118
+ source = self.directory / "source.docx"
119
+ document = Document()
120
+ document.add_paragraph("正文前段")
121
+ document.add_table(rows=1, cols=1).cell(0, 0).text = "表格中段"
122
+ document.add_paragraph("正文后段")
123
+ save_new(document, source)
124
+ text = read_text(source)
125
+ self.assertLess(text.index("正文前段"), text.index("表格中段"))
126
+ self.assertLess(text.index("表格中段"), text.index("正文后段"))
127
+ before = digest(source)
128
+ revision, continued = self.directory / "v1.docx", self.directory / "v2.docx"
129
+ write_revision(source, revision, text + "\n首轮修改", "首轮")
130
+ revision_before = digest(revision)
131
+ write_revision(revision, continued, read_text(revision) + "\n续改", "续改")
132
+ with self.assertRaises(FileExistsError):
133
+ write_revision(source, revision, "不得覆盖", "错误覆盖")
134
+ self.assertEqual(digest(source), before)
135
+ self.assertEqual(digest(revision), revision_before)
136
+ self.assertIn(revision_before, Document(continued).core_properties.subject)
137
+
138
+ def test_pdf_page_without_text_cannot_be_claimed_as_complete_read(self):
139
+ source = self.directory / "mixed-pages.pdf"
140
+ canvas = Canvas(str(source))
141
+ canvas.drawString(72, 720, "Readable first page")
142
+ canvas.showPage()
143
+ canvas.rect(72, 600, 200, 100)
144
+ canvas.showPage()
145
+ canvas.save()
146
+ with self.assertRaisesRegex(ValueError, "without extractable text"):
147
+ read_text(source)
148
+
149
+ def test_query_coverage_and_mixed_units_fail_before_output(self):
150
+ for mutation in ("partial", "truncated", "mixed-unit"):
151
+ snapshot = copy.deepcopy(fixture_snapshot())
152
+ if mutation == "mixed-unit":
153
+ snapshot["pages"][0]["records"][0]["unit"] = "万元"
154
+ else:
155
+ snapshot[mutation] = True
156
+ source = self.directory / f"{mutation}.json"
157
+ source.write_text(json.dumps(snapshot), encoding="utf-8")
158
+ output = self.directory / f"{mutation}.docx"
159
+ with self.subTest(mutation=mutation), self.assertRaises(ValueError):
160
+ generate_report(source, output)
161
+ self.assertFalse(output.exists())
162
+
163
+ def test_declared_unit_is_kept_without_conversion(self):
164
+ snapshot = fixture_snapshot()
165
+ snapshot["source"]["unit"] = "万元"
166
+ snapshot["pages"][0]["records"][0]["unit"] = "万元"
167
+ self.assertEqual(validate_snapshot(snapshot)[2], Decimal("30.33"))
168
+ source, output = self.directory / "wan.json", self.directory / "wan.docx"
169
+ source.write_text(json.dumps(snapshot), encoding="utf-8")
170
+ self.assertEqual(generate_report(source, output)["unit"], "万元")
171
+ self.assertIn("金额合计:30.33 万元", read_text(output))
172
+
173
+ def test_oversized_output_is_rejected_before_file_is_created(self):
174
+ class OversizedDocument:
175
+ def save(self, stream):
176
+ stream.write(b"x" * (20 * 1024 * 1024 + 1))
177
+
178
+ output = self.directory / "too-large.docx"
179
+ with self.assertRaisesRegex(ValueError, "download budget"):
180
+ save_new(OversizedDocument(), output)
181
+ self.assertFalse(output.exists())
182
+
183
+
184
+ if __name__ == "__main__":
185
+ unittest.main()
@@ -0,0 +1,56 @@
1
+ /** Deployment-owned extension points. Secrets and authorization remain in the Host. */
2
+ export interface DshHostConfiguration {
3
+ /** Stable deployment preset identity; retain it when adopting existing sessions. */
4
+ readonly presetId?: string;
5
+ readonly assistantName: string;
6
+ readonly assistantDescription: string;
7
+ readonly workspaceLabel: string;
8
+ readonly instructions: readonly string[];
9
+ /** Read-only, deployment-owned skill roots relative to the Agent Server. */
10
+ readonly skillDirectories: readonly string[];
11
+ /** Additional trusted Host plugins; use public DSH services and lifecycle effects. */
12
+ readonly plugins: readonly {
13
+ readonly key: string;
14
+ readonly path: string;
15
+ readonly config?: Readonly<Record<string, unknown>>;
16
+ readonly replaces?: readonly "session-controller"[];
17
+ }[];
18
+ /** Fixed project endpoints behind the current worker identity. */
19
+ readonly boundaryRoutes?: readonly DshBoundaryRoute[];
20
+ }
21
+
22
+ export interface DshBoundaryRequest {
23
+ readonly method: "GET" | "POST";
24
+ readonly path: string;
25
+ readonly parameters: Readonly<Record<string, string>>;
26
+ readonly searchParams: URLSearchParams;
27
+ readonly body: Uint8Array;
28
+ readonly signal: AbortSignal;
29
+ }
30
+
31
+ export interface DshProductRequest {
32
+ readonly method?: "GET" | "POST";
33
+ readonly body?: string | Uint8Array;
34
+ readonly contentType?: "application/json" | "application/octet-stream";
35
+ }
36
+
37
+ export interface DshBoundaryContext {
38
+ readonly actorId: string;
39
+ readonly signal: AbortSignal;
40
+ /** Fixed product origin, current login, no caller-selected credentials or redirects. */
41
+ fetchProduct(path: string, input?: DshProductRequest): Promise<Response>;
42
+ }
43
+
44
+ export interface DshBoundaryRoute {
45
+ readonly key: string;
46
+ readonly method: "GET" | "POST";
47
+ /** Literal path segments and optional :identifier parameters; no wildcards. */
48
+ readonly path: string;
49
+ readonly maxBodyBytes?: number;
50
+ readonly maxResponseBytes?: number;
51
+ readonly timeoutMs?: number;
52
+ readonly handle: (
53
+ request: DshBoundaryRequest,
54
+ context: DshBoundaryContext,
55
+ ) => Promise<Response>;
56
+ }
@@ -0,0 +1,167 @@
1
+ import { downloadNativePackage } from "./native-download";
2
+ import { createHash } from "node:crypto";
3
+ import {
4
+ mkdtemp,
5
+ mkdir,
6
+ readFile,
7
+ rename,
8
+ rm,
9
+ writeFile,
10
+ } from "node:fs/promises";
11
+ import { join, dirname } from "node:path";
12
+ import { tmpdir } from "node:os";
13
+
14
+ interface NativePackage {
15
+ name: string;
16
+ version: string;
17
+ integrity: string;
18
+ archive: string;
19
+ }
20
+ type Lock = { packages: Record<string, [string, string, unknown, string]> };
21
+
22
+ /** Fixed Debian prerequisites, including the official Linux Office WASM engine. */
23
+ export function nativePackages(
24
+ lock: Lock,
25
+ architecture: string,
26
+ ): NativePackage[] {
27
+ if (!["arm64", "x64"].includes(architecture))
28
+ throw new Error("Unsupported H1 native architecture");
29
+ const names = [
30
+ `node-addon-require-builtin-linux-${architecture}-gnu`,
31
+ `@deepseek-ai/node-addon-system-linux-${architecture}`,
32
+ `@koromix/koffi-linux-${architecture}`,
33
+ `@vscode/ripgrep-linux-${architecture}`,
34
+ `@img/sharp-linux-${architecture}`,
35
+ `@img/sharp-libvips-linux-${architecture}`,
36
+ "@deepseek-ai/libreoffice-kit-wasm",
37
+ ];
38
+ return names.map((name) => {
39
+ const item = lock.packages[name];
40
+ const version = item?.[0].slice(name.length + 1);
41
+ if (
42
+ !item ||
43
+ !item[0].startsWith(name + "@") ||
44
+ !/^[0-9A-Za-z.+-]+$/.test(version ?? "") ||
45
+ !/^sha512-[A-Za-z0-9+/]+=*$/.test(item[3])
46
+ )
47
+ throw new Error(
48
+ "Native dependency must be fixed by the existing runtime lock",
49
+ );
50
+ return {
51
+ name,
52
+ version,
53
+ integrity: item[3],
54
+ archive: name.replaceAll("/", "-") + ".tgz",
55
+ };
56
+ });
57
+ }
58
+
59
+ async function tar(args: string[]) {
60
+ const child = Bun.spawn(["tar", ...args], { stdout: "pipe", stderr: "pipe" });
61
+ const [output, , code] = await Promise.all([
62
+ new Response(child.stdout).text(),
63
+ new Response(child.stderr).text(),
64
+ child.exited,
65
+ ]);
66
+ if (code !== 0) throw new Error("Invalid native package archive");
67
+ return output;
68
+ }
69
+
70
+ export async function installNativePackage(
71
+ pkg: NativePackage,
72
+ root: string,
73
+ bytes: Uint8Array,
74
+ ) {
75
+ if (
76
+ bytes.length > 64 * 1024 * 1024 ||
77
+ "sha512-" + createHash("sha512").update(bytes).digest("base64") !==
78
+ pkg.integrity
79
+ )
80
+ throw new Error("Native package integrity mismatch");
81
+ const temporary = await mkdtemp(join(tmpdir(), "dsh-native-"));
82
+ try {
83
+ const archive = join(temporary, "package.tgz");
84
+ await writeFile(archive, bytes);
85
+ const paths = (await tar(["-tzf", archive])).trim().split("\n");
86
+ if (
87
+ !paths.length ||
88
+ paths.length > 10000 ||
89
+ paths.some(
90
+ (path) =>
91
+ !path.startsWith("package/") ||
92
+ path.includes("\\") ||
93
+ path.split("/").some((part) => part === ".." || part === "."),
94
+ )
95
+ )
96
+ throw new Error("Native package archive path denied");
97
+ const details = (await tar(["--numeric-owner", "-tvzf", archive]))
98
+ .trim()
99
+ .split("\n");
100
+ let total = 0;
101
+ for (const line of details) {
102
+ if (!["-", "d"].includes(line[0]))
103
+ throw new Error("Native package links or special files denied");
104
+ const columns = line.trim().split(/\s+/);
105
+ const size = Number(columns[1].includes("/") ? columns[2] : columns[4]);
106
+ if (!Number.isSafeInteger(size) || size < 0)
107
+ throw new Error("Invalid native package entry size");
108
+ total += size;
109
+ }
110
+ if (total > 256 * 1024 * 1024)
111
+ throw new Error("Native package expansion budget exceeded");
112
+ const unpacked = join(temporary, "unpacked");
113
+ await mkdir(unpacked);
114
+ await tar([
115
+ "-xzf",
116
+ archive,
117
+ "--no-same-owner",
118
+ "--no-same-permissions",
119
+ "--strip-components=1",
120
+ "-C",
121
+ unpacked,
122
+ ]);
123
+ const metadata = JSON.parse(
124
+ await readFile(join(unpacked, "package.json"), "utf8"),
125
+ );
126
+ if (metadata.name !== pkg.name || metadata.version !== pkg.version)
127
+ throw new Error("Native package identity mismatch");
128
+ const destination = join(root, "node_modules", pkg.name);
129
+ await mkdir(dirname(destination), { recursive: true });
130
+ await rename(unpacked, destination);
131
+ } finally {
132
+ await rm(temporary, { recursive: true, force: true });
133
+ }
134
+ }
135
+
136
+ export async function installNative(
137
+ root: string,
138
+ architecture: string,
139
+ archiveDirectory?: string,
140
+ ) {
141
+ const lock = Bun.JSONC.parse(
142
+ await readFile(join(root, "bun.lock"), "utf8"),
143
+ ) as Lock;
144
+ for (const pkg of nativePackages(lock, architecture)) {
145
+ let bytes: Uint8Array;
146
+ if (archiveDirectory)
147
+ bytes = new Uint8Array(
148
+ await readFile(join(archiveDirectory, pkg.archive)),
149
+ );
150
+ else
151
+ bytes = await downloadNativePackage(pkg, {
152
+ cacheDirectory: process.env.DSH_NATIVE_CACHE_DIR,
153
+ registry: process.env.DSH_NATIVE_REGISTRY,
154
+ });
155
+ await installNativePackage(pkg, root, bytes);
156
+ console.info(
157
+ `Installed pinned native prerequisite: ${pkg.name}@${pkg.version}`,
158
+ );
159
+ }
160
+ }
161
+
162
+ if (import.meta.main)
163
+ await installNative(
164
+ process.cwd(),
165
+ process.arch,
166
+ process.env.DSH_NATIVE_ARCHIVE_DIR,
167
+ );