create-windy 0.3.2 → 0.3.5

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 (343) hide show
  1. package/README.md +27 -9
  2. package/dist/cli.js +825 -117
  3. package/package.json +1 -1
  4. package/template/.agents/skills/windy-business-module/SKILL.md +16 -3
  5. package/template/.windy-template.json +2 -2
  6. package/template/AGENTS.md +4 -0
  7. package/template/README.md +18 -11
  8. package/template/_gitignore +1 -0
  9. package/template/apps/agent-server/README.md +2 -0
  10. package/template/apps/agent-server/pyproject.toml +8 -0
  11. package/template/apps/agent-server/src/southwind_agent_server/adk_adapter.py +87 -10
  12. package/template/apps/agent-server/src/southwind_agent_server/adk_model.py +18 -3
  13. package/template/apps/agent-server/src/southwind_agent_server/adk_tools.py +78 -11
  14. package/template/apps/agent-server/src/southwind_agent_server/app.py +120 -115
  15. package/template/apps/agent-server/src/southwind_agent_server/artifact_input.py +153 -0
  16. package/template/apps/agent-server/src/southwind_agent_server/config.py +29 -0
  17. package/template/apps/agent-server/src/southwind_agent_server/contracts.py +81 -1
  18. package/template/apps/agent-server/src/southwind_agent_server/deterministic.py +8 -0
  19. package/template/apps/agent-server/src/southwind_agent_server/engine.py +28 -0
  20. package/template/apps/agent-server/src/southwind_agent_server/fingerprint.py +41 -0
  21. package/template/apps/agent-server/src/southwind_agent_server/http_helpers.py +62 -0
  22. package/template/apps/agent-server/src/southwind_agent_server/lease.py +15 -0
  23. package/template/apps/agent-server/src/southwind_agent_server/multimodal.py +76 -0
  24. package/template/apps/agent-server/src/southwind_agent_server/openai_engine.py +112 -20
  25. package/template/apps/agent-server/src/southwind_agent_server/openai_provider.py +14 -1
  26. package/template/apps/agent-server/src/southwind_agent_server/postgres_store.py +329 -0
  27. package/template/apps/agent-server/src/southwind_agent_server/postgres_store_backend.py +332 -0
  28. package/template/apps/agent-server/src/southwind_agent_server/provider_governance.py +64 -3
  29. package/template/apps/agent-server/src/southwind_agent_server/runtime_factory.py +68 -0
  30. package/template/apps/agent-server/src/southwind_agent_server/service.py +218 -56
  31. package/template/apps/agent-server/src/southwind_agent_server/signal_events.py +36 -0
  32. package/template/apps/agent-server/src/southwind_agent_server/sqlite_catalog.py +107 -0
  33. package/template/apps/agent-server/src/southwind_agent_server/sqlite_schema.py +65 -0
  34. package/template/apps/agent-server/src/southwind_agent_server/sqlite_serialization.py +16 -0
  35. package/template/apps/agent-server/src/southwind_agent_server/sqlite_store.py +89 -57
  36. package/template/apps/agent-server/src/southwind_agent_server/store.py +105 -2
  37. package/template/apps/agent-server/src/southwind_agent_server/store_cipher.py +40 -0
  38. package/template/apps/agent-server/src/southwind_agent_server/telemetry.py +89 -0
  39. package/template/apps/agent-server/src/southwind_agent_server/tool_host.py +72 -0
  40. package/template/apps/agent-server/tests/test_adk_adapter.py +6 -2
  41. package/template/apps/agent-server/tests/test_api.py +24 -1
  42. package/template/apps/agent-server/tests/test_artifact_input.py +110 -0
  43. package/template/apps/agent-server/tests/test_config.py +4 -0
  44. package/template/apps/agent-server/tests/test_fingerprint.py +10 -0
  45. package/template/apps/agent-server/tests/test_multimodal.py +51 -0
  46. package/template/apps/agent-server/tests/test_openai_provider.py +6 -2
  47. package/template/apps/agent-server/tests/test_postgres_store.py +131 -0
  48. package/template/apps/agent-server/tests/test_provider_governance.py +61 -0
  49. package/template/apps/agent-server/tests/test_sqlite_store.py +95 -10
  50. package/template/apps/agent-server/tests/test_telemetry.py +25 -0
  51. package/template/apps/agent-server/tests/test_tool_approval.py +28 -0
  52. package/template/apps/agent-server/uv.lock +165 -0
  53. package/template/apps/document-server/Dockerfile +19 -0
  54. package/template/apps/document-server/pyproject.toml +43 -0
  55. package/template/apps/document-server/src/southwind_document_server/__init__.py +1 -0
  56. package/template/apps/document-server/src/southwind_document_server/adapter.py +337 -0
  57. package/template/apps/document-server/src/southwind_document_server/app.py +151 -0
  58. package/template/apps/document-server/src/southwind_document_server/config.py +94 -0
  59. package/template/apps/document-server/src/southwind_document_server/contracts.py +103 -0
  60. package/template/apps/document-server/src/southwind_document_server/service.py +149 -0
  61. package/template/apps/document-server/src/southwind_document_server/store.py +185 -0
  62. package/template/apps/document-server/tests/__init__.py +1 -0
  63. package/template/apps/document-server/tests/test_config.py +42 -0
  64. package/template/apps/document-server/tests/test_service.py +140 -0
  65. package/template/apps/document-server/uv.lock +430 -0
  66. package/template/apps/embedding-server/Dockerfile +17 -0
  67. package/template/apps/embedding-server/pyproject.toml +44 -0
  68. package/template/apps/embedding-server/src/southwind_embedding_server/__init__.py +1 -0
  69. package/template/apps/embedding-server/src/southwind_embedding_server/adapter.py +254 -0
  70. package/template/apps/embedding-server/src/southwind_embedding_server/app.py +119 -0
  71. package/template/apps/embedding-server/src/southwind_embedding_server/config.py +120 -0
  72. package/template/apps/embedding-server/src/southwind_embedding_server/contracts.py +106 -0
  73. package/template/apps/embedding-server/src/southwind_embedding_server/error.py +6 -0
  74. package/template/apps/embedding-server/src/southwind_embedding_server/image_input.py +87 -0
  75. package/template/apps/embedding-server/tests/__init__.py +1 -0
  76. package/template/apps/embedding-server/tests/test_adapter.py +92 -0
  77. package/template/apps/embedding-server/tests/test_config.py +38 -0
  78. package/template/apps/embedding-server/uv.lock +449 -0
  79. package/template/apps/server/src/agent/background-operation-port.ts +37 -0
  80. package/template/apps/server/src/agent/background-operation.test.ts +231 -0
  81. package/template/apps/server/src/agent/background-operation.ts +252 -0
  82. package/template/apps/server/src/agent/drizzle-run-binding-repository.ts +114 -0
  83. package/template/apps/server/src/agent/execution-grants.ts +7 -1
  84. package/template/apps/server/src/agent/fake-runtime.test-support.ts +43 -0
  85. package/template/apps/server/src/agent/idempotency-key.test.ts +28 -0
  86. package/template/apps/server/src/agent/idempotency-key.ts +11 -0
  87. package/template/apps/server/src/agent/remote-runtime.test.ts +115 -1
  88. package/template/apps/server/src/agent/remote-runtime.ts +173 -5
  89. package/template/apps/server/src/agent/run-authorization.test-support.ts +9 -0
  90. package/template/apps/server/src/agent/run-authorization.test.ts +126 -0
  91. package/template/apps/server/src/agent/run-authorization.ts +180 -0
  92. package/template/apps/server/src/agent/run-binding-repository.ts +93 -0
  93. package/template/apps/server/src/agent/run-contracts.ts +88 -1
  94. package/template/apps/server/src/agent/run-definition-support.ts +58 -0
  95. package/template/apps/server/src/agent/run-errors.ts +25 -0
  96. package/template/apps/server/src/agent/run-facade.test.ts +57 -46
  97. package/template/apps/server/src/agent/run-facade.ts +185 -65
  98. package/template/apps/server/src/agent/run-release.ts +78 -0
  99. package/template/apps/server/src/agent/run-route-input.ts +169 -0
  100. package/template/apps/server/src/agent/run-routes.ts +63 -76
  101. package/template/apps/server/src/agent/runtime-bootstrap.ts +169 -13
  102. package/template/apps/server/src/agent/sandbox-client.ts +200 -0
  103. package/template/apps/server/src/agent/sandbox-protocol.ts +76 -0
  104. package/template/apps/server/src/agent/sandbox-registry.ts +205 -0
  105. package/template/apps/server/src/agent/sandbox-runtime.test.ts +137 -0
  106. package/template/apps/server/src/agent/sandbox-worker-server.ts +195 -0
  107. package/template/apps/server/src/agent/sandbox-worker.ts +12 -0
  108. package/template/apps/server/src/agent/tool-approval.test.ts +75 -0
  109. package/template/apps/server/src/agent/tool-approval.ts +115 -0
  110. package/template/apps/server/src/agent/tool-audit.ts +62 -0
  111. package/template/apps/server/src/agent/tool-host.test.ts +39 -11
  112. package/template/apps/server/src/agent/tool-host.ts +184 -17
  113. package/template/apps/server/src/agent/tool-registry.ts +52 -47
  114. package/template/apps/server/src/agent/vision-facade.test.ts +256 -0
  115. package/template/apps/server/src/agent/vision-input.ts +120 -0
  116. package/template/apps/server/src/ai-artifact/codec.test.ts +44 -0
  117. package/template/apps/server/src/ai-artifact/codec.ts +137 -0
  118. package/template/apps/server/src/ai-artifact/routes.ts +37 -0
  119. package/template/apps/server/src/ai-artifact/runtime.ts +205 -0
  120. package/template/apps/server/src/application-services.ts +62 -2
  121. package/template/apps/server/src/auth/reauthentication.test.ts +40 -0
  122. package/template/apps/server/src/auth/reauthentication.ts +19 -0
  123. package/template/apps/server/src/auth/runtime.ts +9 -1
  124. package/template/apps/server/src/data-access/context.ts +6 -4
  125. package/template/apps/server/src/data-access/scope-snapshot.ts +27 -0
  126. package/template/apps/server/src/data-governance/export/approval-port.ts +6 -3
  127. package/template/apps/server/src/data-governance/export/authorization-port.test.ts +23 -4
  128. package/template/apps/server/src/data-governance/export/authorization-port.ts +89 -25
  129. package/template/apps/server/src/data-governance/export/drizzle-repository.integration.test.ts +2 -0
  130. package/template/apps/server/src/data-governance/export/drizzle-repository.ts +1 -0
  131. package/template/apps/server/src/data-governance/export/job-runtime.test.ts +15 -4
  132. package/template/apps/server/src/data-governance/export/job-runtime.ts +68 -15
  133. package/template/apps/server/src/data-governance/export/ndjson-stream.ts +25 -6
  134. package/template/apps/server/src/data-governance/export/postgres-recovery.integration.test.ts +4 -2
  135. package/template/apps/server/src/data-governance/export/renderer-job-runtime.test.ts +235 -0
  136. package/template/apps/server/src/data-governance/export/renderer-runtime.ts +293 -0
  137. package/template/apps/server/src/data-governance/export/renderer-selection.test.ts +67 -0
  138. package/template/apps/server/src/data-governance/export/repository.test.ts +2 -0
  139. package/template/apps/server/src/data-governance/export/request-fingerprint.test.ts +13 -0
  140. package/template/apps/server/src/data-governance/export/request-fingerprint.ts +2 -0
  141. package/template/apps/server/src/data-governance/export/routes.ts +11 -1
  142. package/template/apps/server/src/data-governance/export/scope-snapshot.ts +6 -18
  143. package/template/apps/server/src/data-governance/export/service-support.ts +188 -0
  144. package/template/apps/server/src/data-governance/export/service.ts +90 -113
  145. package/template/apps/server/src/data-governance/export/source.ts +101 -0
  146. package/template/apps/server/src/data-governance/export/types.ts +27 -0
  147. package/template/apps/server/src/document/contracts.ts +76 -0
  148. package/template/apps/server/src/document/facade.ts +339 -0
  149. package/template/apps/server/src/document/remote-runtime.test.ts +96 -0
  150. package/template/apps/server/src/document/remote-runtime.ts +223 -0
  151. package/template/apps/server/src/document/routes.ts +193 -0
  152. package/template/apps/server/src/embedding/contracts.ts +83 -0
  153. package/template/apps/server/src/embedding/error.ts +10 -0
  154. package/template/apps/server/src/embedding/facade.ts +217 -0
  155. package/template/apps/server/src/embedding/input.ts +172 -0
  156. package/template/apps/server/src/embedding/remote-runtime.test.ts +66 -0
  157. package/template/apps/server/src/embedding/remote-runtime.ts +218 -0
  158. package/template/apps/server/src/embedding/routes.ts +152 -0
  159. package/template/apps/server/src/index.ts +40 -43
  160. package/template/apps/server/src/jobs/artifact-service.test.ts +14 -2
  161. package/template/apps/server/src/jobs/artifact-service.ts +10 -0
  162. package/template/apps/server/src/jobs/drizzle-execution-repository.ts +17 -18
  163. package/template/apps/server/src/jobs/drizzle-execution.integration.test.ts +19 -1
  164. package/template/apps/server/src/jobs/drizzle-mappers.ts +4 -1
  165. package/template/apps/server/src/jobs/drizzle-recovery-repository.ts +49 -2
  166. package/template/apps/server/src/jobs/drizzle-repository.ts +1 -0
  167. package/template/apps/server/src/jobs/execution-repository.ts +17 -0
  168. package/template/apps/server/src/jobs/execution.test.ts +34 -0
  169. package/template/apps/server/src/jobs/in-memory-control.ts +135 -0
  170. package/template/apps/server/src/jobs/in-memory-execution.ts +34 -65
  171. package/template/apps/server/src/jobs/legacy-service-runtime.ts +5 -2
  172. package/template/apps/server/src/jobs/repository.ts +3 -0
  173. package/template/apps/server/src/jobs/worker.ts +80 -41
  174. package/template/apps/server/src/module-host/ai-operation-port.ts +170 -0
  175. package/template/apps/server/src/module-host/durable-context.test.ts +312 -0
  176. package/template/apps/server/src/module-host/durable-context.ts +124 -0
  177. package/template/apps/server/src/module-host/durable-handler-registration.ts +72 -0
  178. package/template/apps/server/src/module-host/governed-export-route-support.ts +171 -0
  179. package/template/apps/server/src/module-host/governed-export-routes.test.ts +327 -0
  180. package/template/apps/server/src/module-host/governed-export-routes.ts +238 -0
  181. package/template/apps/server/src/module-host/governed-renderer-registration.test.ts +247 -0
  182. package/template/apps/server/src/module-host/governed-resource-routes.ts +331 -0
  183. package/template/apps/server/src/module-host/governed-resources.test.ts +344 -0
  184. package/template/apps/server/src/module-host/governed-resources.ts +203 -0
  185. package/template/apps/server/src/module-host/http-runtime.ts +95 -0
  186. package/template/apps/server/src/module-host/initialize-contracts.ts +14 -0
  187. package/template/apps/server/src/module-host/initialize.test.ts +49 -1
  188. package/template/apps/server/src/module-host/initialize.ts +39 -16
  189. package/template/apps/server/src/module-host/job-port.test.ts +262 -0
  190. package/template/apps/server/src/module-host/job-port.ts +334 -0
  191. package/template/apps/server/src/module-host/request-context.test.ts +88 -2
  192. package/template/apps/server/src/module-host/request-context.ts +56 -22
  193. package/template/apps/server/src/module-host/route-installer.test.ts +10 -0
  194. package/template/apps/server/src/module-host/route-installer.ts +36 -1
  195. package/template/apps/server/src/module-host/sandbox-tool-registration.ts +42 -0
  196. package/template/apps/server/src/module-host/tool-handlers.ts +67 -31
  197. package/template/apps/server/src/module-host.ts +1 -0
  198. package/template/apps/server/src/module-runtime-validation.ts +7 -3
  199. package/template/apps/server/src/speech/contracts.ts +76 -0
  200. package/template/apps/server/src/speech/facade.ts +316 -0
  201. package/template/apps/server/src/speech/remote-runtime.test.ts +88 -0
  202. package/template/apps/server/src/speech/remote-runtime.ts +227 -0
  203. package/template/apps/server/src/speech/routes.ts +180 -0
  204. package/template/apps/server/src/system/actor.ts +39 -0
  205. package/template/apps/server/src/system/route-helpers.ts +1 -0
  206. package/template/apps/server/src/workflow/service.ts +2 -1
  207. package/template/apps/speech-server/Dockerfile +22 -0
  208. package/template/apps/speech-server/pyproject.toml +43 -0
  209. package/template/apps/speech-server/src/southwind_speech_server/__init__.py +1 -0
  210. package/template/apps/speech-server/src/southwind_speech_server/adapter.py +249 -0
  211. package/template/apps/speech-server/src/southwind_speech_server/app.py +183 -0
  212. package/template/apps/speech-server/src/southwind_speech_server/config.py +100 -0
  213. package/template/apps/speech-server/src/southwind_speech_server/contracts.py +103 -0
  214. package/template/apps/speech-server/src/southwind_speech_server/errors.py +6 -0
  215. package/template/apps/speech-server/src/southwind_speech_server/normalizer.py +108 -0
  216. package/template/apps/speech-server/src/southwind_speech_server/output_validation.py +128 -0
  217. package/template/apps/speech-server/src/southwind_speech_server/service.py +162 -0
  218. package/template/apps/speech-server/src/southwind_speech_server/store.py +209 -0
  219. package/template/apps/speech-server/tests/__init__.py +1 -0
  220. package/template/apps/speech-server/tests/test_config.py +33 -0
  221. package/template/apps/speech-server/tests/test_service.py +154 -0
  222. package/template/apps/speech-server/uv.lock +430 -0
  223. package/template/apps/web/src/app/business-routes.ts +22 -0
  224. package/template/apps/web/src/components/common/AccessSnapshotBoundary.vue +112 -0
  225. package/template/apps/web/src/components/common/AccessSnapshotBoundary.webtest.ts +130 -0
  226. package/template/apps/web/src/components/common/AccessSnapshotNotice.vue +117 -0
  227. package/template/apps/web/src/components/common/FormDialog.vue +6 -0
  228. package/template/apps/web/src/components/common/ModalLayout.webtest.ts +13 -0
  229. package/template/apps/web/src/composables/access-snapshot-change.ts +131 -0
  230. package/template/apps/web/src/composables/access-snapshot-change.webtest.ts +103 -0
  231. package/template/apps/web/src/composables/useAccessSnapshot.ts +48 -2
  232. package/template/apps/web/src/composables/useAccessSnapshot.webtest.ts +54 -0
  233. package/template/apps/web/src/composables/useAccessSnapshotMonitor.ts +42 -0
  234. package/template/apps/web/src/layout/AppShell.vue +28 -25
  235. package/template/apps/web/src/layout/AppShell.webtest.ts +1 -0
  236. package/template/apps/web/src/router/business-routes.ts +68 -0
  237. package/template/apps/web/src/router/business-routes.webtest.ts +85 -0
  238. package/template/apps/web/src/router/index.ts +7 -0
  239. package/template/apps/web/src/router/shared-scaffold-neutrality.webtest.ts +12 -0
  240. package/template/apps/web/src/services/access-api.ts +5 -1
  241. package/template/apps/web/src/services/access-api.webtest.ts +35 -0
  242. package/template/docker-compose.yml +127 -0
  243. package/template/docs/architecture/ai-egress.md +12 -9
  244. package/template/docs/architecture/ai-runtime.md +23 -11
  245. package/template/docs/architecture/durable-jobs.md +25 -3
  246. package/template/docs/architecture/foundation-infrastructure.md +163 -0
  247. package/template/docs/architecture/module-host.md +115 -0
  248. package/template/docs/architecture/server-module-interface.md +39 -0
  249. package/template/docs/architecture/web-access-snapshot-resilience.md +60 -0
  250. package/template/docs/development/business-web-routes.md +66 -0
  251. package/template/docs/development/custom-login-page.md +3 -3
  252. package/template/docs/development/module-lifecycle.md +71 -0
  253. package/template/docs/operations/observability.md +5 -1
  254. package/template/docs/platform/agent-runtime.md +21 -11
  255. package/template/docs/platform/agent-tool-sandbox.md +58 -0
  256. package/template/docs/platform/agent-tools.md +5 -0
  257. package/template/docs/platform/document-ai-runtime.md +204 -0
  258. package/template/docs/platform/governed-export-renderers.md +132 -0
  259. package/template/docs/platform/navigation-registry.md +5 -0
  260. package/template/docs/platform/organization-membership.md +2 -1
  261. package/template/docs/platform/speech-ai-runtime.md +156 -0
  262. package/template/docs/platform/system-crud-api.md +7 -1
  263. package/template/docs/platform/vision-ai-runtime.md +97 -0
  264. package/template/docs/platform/web-system-crud.md +6 -0
  265. package/template/package.json +16 -2
  266. package/template/packages/ai-client/index.ts +4 -0
  267. package/template/packages/ai-client/package.json +5 -2
  268. package/template/packages/ai-client/src/agent/client/artifact.ts +26 -0
  269. package/template/packages/ai-client/src/agent/client/attach.test.ts +124 -0
  270. package/template/packages/ai-client/src/agent/client/client.ts +119 -7
  271. package/template/packages/ai-client/src/agent/client/run.ts +14 -0
  272. package/template/packages/ai-client/src/agent/client/types.ts +18 -0
  273. package/template/packages/ai-client/src/agent/client/vision.test.ts +53 -0
  274. package/template/packages/ai-client/src/agent/contracts/contracts.test.ts +1 -0
  275. package/template/packages/ai-client/src/agent/contracts/events.ts +33 -0
  276. package/template/packages/ai-client/src/agent/contracts/runs.ts +71 -0
  277. package/template/packages/ai-client/src/agent/index.ts +1 -0
  278. package/template/packages/ai-client/src/artifact-ref.ts +8 -0
  279. package/template/packages/ai-client/src/document/client.test.ts +114 -0
  280. package/template/packages/ai-client/src/document/client.ts +134 -0
  281. package/template/packages/ai-client/src/document/contracts.ts +152 -0
  282. package/template/packages/ai-client/src/document/error.ts +43 -0
  283. package/template/packages/ai-client/src/document/index.ts +3 -0
  284. package/template/packages/ai-client/src/document/run.ts +104 -0
  285. package/template/packages/ai-client/src/document/validation.ts +115 -0
  286. package/template/packages/ai-client/src/embedding/client.test.ts +77 -0
  287. package/template/packages/ai-client/src/embedding/client.ts +96 -0
  288. package/template/packages/ai-client/src/embedding/contracts.ts +46 -0
  289. package/template/packages/ai-client/src/embedding/error.ts +61 -0
  290. package/template/packages/ai-client/src/embedding/index.ts +3 -0
  291. package/template/packages/ai-client/src/embedding/validation.ts +117 -0
  292. package/template/packages/ai-client/src/speech/client.test.ts +135 -0
  293. package/template/packages/ai-client/src/speech/client.ts +104 -0
  294. package/template/packages/ai-client/src/speech/contracts.ts +129 -0
  295. package/template/packages/ai-client/src/speech/error.ts +43 -0
  296. package/template/packages/ai-client/src/speech/index.ts +3 -0
  297. package/template/packages/ai-client/src/speech/run.ts +133 -0
  298. package/template/packages/ai-client/src/speech/validation.ts +132 -0
  299. package/template/packages/config/package.json +2 -2
  300. package/template/packages/database/drizzle/0039_early_ezekiel_stane.sql +1 -0
  301. package/template/packages/database/drizzle/0040_colossal_baron_strucker.sql +63 -0
  302. package/template/packages/database/drizzle/0041_yummy_prowler.sql +21 -0
  303. package/template/packages/database/drizzle/0042_puzzling_rumiko_fujikawa.sql +27 -0
  304. package/template/packages/database/drizzle/meta/0039_snapshot.json +7755 -0
  305. package/template/packages/database/drizzle/meta/0040_snapshot.json +8150 -0
  306. package/template/packages/database/drizzle/meta/0041_snapshot.json +8323 -0
  307. package/template/packages/database/drizzle/meta/0042_snapshot.json +8541 -0
  308. package/template/packages/database/drizzle/meta/_journal.json +28 -0
  309. package/template/packages/database/package.json +2 -2
  310. package/template/packages/database/src/agent-runtime-schema.test.ts +54 -0
  311. package/template/packages/database/src/schema/agent-runtime.ts +149 -0
  312. package/template/packages/database/src/schema/common.ts +2 -14
  313. package/template/packages/database/src/schema/durable-jobs.ts +5 -0
  314. package/template/packages/database/src/schema/governed-exports.ts +17 -5
  315. package/template/packages/database/src/schema/index.ts +3 -0
  316. package/template/packages/database/src/schema-durable-recovery.test.ts +31 -0
  317. package/template/packages/database/src/schema-governed-exports.test.ts +21 -1
  318. package/template/packages/database/src/schema.test.ts +6 -23
  319. package/template/packages/jobs/package.json +3 -2
  320. package/template/packages/jobs/src/handlers.test.ts +13 -0
  321. package/template/packages/jobs/src/handlers.ts +7 -1
  322. package/template/packages/jobs/src/types.ts +4 -0
  323. package/template/packages/modules/package.json +2 -2
  324. package/template/packages/modules/src/ai-operation-composition.test-support.ts +165 -0
  325. package/template/packages/modules/src/ai-operation-composition.test.ts +91 -127
  326. package/template/packages/modules/src/ai-operation-composition.ts +59 -1
  327. package/template/packages/modules/src/manifest.ts +25 -1
  328. package/template/packages/modules/src/tool-composition.ts +18 -0
  329. package/template/packages/server-sdk/index.ts +50 -0
  330. package/template/packages/server-sdk/package.json +10 -4
  331. package/template/packages/server-sdk/src/ai-artifact-port.ts +34 -0
  332. package/template/packages/server-sdk/src/ai-operation-port.ts +65 -0
  333. package/template/packages/server-sdk/src/ai-operation-registration.ts +42 -1
  334. package/template/packages/server-sdk/src/background-ai-port.ts +43 -0
  335. package/template/packages/server-sdk/src/data-governance-registration.ts +116 -0
  336. package/template/packages/server-sdk/src/durable-handler.ts +29 -0
  337. package/template/packages/server-sdk/src/jobs-port.ts +69 -0
  338. package/template/packages/server-sdk/src/module-host.ts +16 -2
  339. package/template/packages/server-sdk/src/request-context.ts +6 -2
  340. package/template/packages/server-sdk/src/sandbox-tool.ts +21 -0
  341. package/template/packages/server-sdk/src/tool-registration.ts +2 -0
  342. package/template/packages/shared/package.json +1 -1
  343. package/template/packages/shared/src/rbac.ts +30 -0
@@ -274,6 +274,34 @@
274
274
  "when": 1785013875842,
275
275
  "tag": "0038_uneven_wasp",
276
276
  "breakpoints": true
277
+ },
278
+ {
279
+ "idx": 39,
280
+ "version": "7",
281
+ "when": 1785093639918,
282
+ "tag": "0039_early_ezekiel_stane",
283
+ "breakpoints": true
284
+ },
285
+ {
286
+ "idx": 40,
287
+ "version": "7",
288
+ "when": 1785100685405,
289
+ "tag": "0040_colossal_baron_strucker",
290
+ "breakpoints": true
291
+ },
292
+ {
293
+ "idx": 41,
294
+ "version": "7",
295
+ "when": 1785102272102,
296
+ "tag": "0041_yummy_prowler",
297
+ "breakpoints": true
298
+ },
299
+ {
300
+ "idx": 42,
301
+ "version": "7",
302
+ "when": 1785151819729,
303
+ "tag": "0042_puzzling_rumiko_fujikawa",
304
+ "breakpoints": true
277
305
  }
278
306
  ]
279
307
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@southwind-ai/database",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "engines": {
@@ -15,7 +15,7 @@
15
15
  "typecheck": "tsc --noEmit --project tsconfig.json"
16
16
  },
17
17
  "dependencies": {
18
- "@southwind-ai/shared": "workspace:*",
18
+ "@southwind-ai/shared": "workspace:^",
19
19
  "drizzle-orm": "^0.45.2"
20
20
  },
21
21
  "exports": {
@@ -0,0 +1,54 @@
1
+ import { expect, test } from "bun:test";
2
+ import { getTableConfig } from "drizzle-orm/pg-core";
3
+ import {
4
+ agentEvaluationResults,
5
+ agentOperationReleases,
6
+ agentRunBindings,
7
+ agentRuntimeEvents,
8
+ agentRuntimeRuns,
9
+ } from "./schema/index.js";
10
+
11
+ test("Agent Run 固定不可变 Release 并持久化恢复租约", async () => {
12
+ expect(getTableConfig(agentOperationReleases).name).toBe(
13
+ "agent_operation_releases",
14
+ );
15
+ expect(agentOperationReleases.snapshotJson.notNull).toBe(true);
16
+ expect(getTableConfig(agentRuntimeRuns).name).toBe("agent_runtime_runs");
17
+ expect(agentRuntimeRuns.invocationCipher.notNull).toBe(false);
18
+ expect(agentRuntimeRuns.releaseId.notNull).toBe(true);
19
+ expect(agentRuntimeRuns.traceId.notNull).toBe(true);
20
+ expect(
21
+ getTableConfig(agentRuntimeRuns).indexes.some(
22
+ (index) =>
23
+ index.config.name === "uk_agent_runtime_runs_idempotency" &&
24
+ index.config.unique,
25
+ ),
26
+ ).toBe(true);
27
+ expect(getTableConfig(agentRuntimeEvents).name).toBe("agent_runtime_events");
28
+ expect(agentRuntimeEvents.eventCipher.notNull).toBe(true);
29
+ expect(getTableConfig(agentEvaluationResults).name).toBe(
30
+ "agent_evaluation_results",
31
+ );
32
+ expect(getTableConfig(agentRunBindings).name).toBe("agent_run_bindings");
33
+ expect(agentRunBindings.scopeSnapshot.notNull).toBe(true);
34
+ expect(agentRunBindings.authorizationSnapshot.notNull).toBe(true);
35
+
36
+ const migration = await Bun.file(
37
+ new URL("../drizzle/0040_colossal_baron_strucker.sql", import.meta.url),
38
+ ).text();
39
+ expect(migration).toContain('CREATE TABLE "agent_operation_releases"');
40
+ expect(migration).toContain('CREATE TABLE "agent_runtime_runs"');
41
+ expect(migration).toContain(
42
+ 'CREATE UNIQUE INDEX "uk_agent_evaluation_release_set"',
43
+ );
44
+ expect(migration).toContain(
45
+ 'CREATE TRIGGER "trg_agent_operation_releases_immutable"',
46
+ );
47
+ const bindingMigration = await Bun.file(
48
+ new URL("../drizzle/0041_yummy_prowler.sql", import.meta.url),
49
+ ).text();
50
+ expect(bindingMigration).toContain('CREATE TABLE "agent_run_bindings"');
51
+ expect(bindingMigration).toContain(
52
+ 'CREATE UNIQUE INDEX "uk_agent_run_bindings_token"',
53
+ );
54
+ });
@@ -0,0 +1,149 @@
1
+ import { sql } from "drizzle-orm";
2
+ import {
3
+ check,
4
+ doublePrecision,
5
+ index,
6
+ integer,
7
+ jsonb,
8
+ pgTable,
9
+ primaryKey,
10
+ text,
11
+ uniqueIndex,
12
+ varchar,
13
+ } from "drizzle-orm/pg-core";
14
+ import type {
15
+ AgentRunAuthorizationSnapshot,
16
+ AuthorizationScopeSnapshot,
17
+ } from "@southwind-ai/shared";
18
+
19
+ export const agentOperationReleases = pgTable(
20
+ "agent_operation_releases",
21
+ {
22
+ releaseId: varchar("release_id", { length: 80 }).primaryKey(),
23
+ operationKey: varchar("operation_key", { length: 200 }).notNull(),
24
+ snapshotJson: jsonb("snapshot_json")
25
+ .$type<Record<string, unknown>>()
26
+ .notNull(),
27
+ createdAt: doublePrecision("created_at").notNull(),
28
+ },
29
+ (table) => [
30
+ index("idx_agent_releases_operation").on(
31
+ table.operationKey,
32
+ table.createdAt,
33
+ ),
34
+ ],
35
+ );
36
+
37
+ export const agentRuntimeRuns = pgTable(
38
+ "agent_runtime_runs",
39
+ {
40
+ runId: varchar("run_id", { length: 80 }).primaryKey(),
41
+ operationKey: varchar("operation_key", { length: 200 }).notNull(),
42
+ idempotencyKey: varchar("idempotency_key", { length: 200 }).notNull(),
43
+ fingerprint: varchar("fingerprint", { length: 64 }).notNull(),
44
+ status: varchar("status", { length: 32 }).notNull(),
45
+ invocationCipher: text("invocation_cipher"),
46
+ outputCipher: text("output_cipher"),
47
+ releaseId: varchar("release_id", { length: 80 })
48
+ .notNull()
49
+ .references(() => agentOperationReleases.releaseId, {
50
+ onDelete: "restrict",
51
+ }),
52
+ releaseJson: jsonb("release_json")
53
+ .$type<Record<string, unknown>>()
54
+ .notNull(),
55
+ traceId: varchar("trace_id", { length: 160 }).notNull(),
56
+ leaseOwner: varchar("lease_owner", { length: 80 }),
57
+ leaseUntil: doublePrecision("lease_until").notNull().default(0),
58
+ createdAt: doublePrecision("created_at").notNull(),
59
+ updatedAt: doublePrecision("updated_at").notNull(),
60
+ expiresAt: doublePrecision("expires_at").notNull(),
61
+ },
62
+ (table) => [
63
+ uniqueIndex("uk_agent_runtime_runs_idempotency").on(table.idempotencyKey),
64
+ index("idx_agent_runtime_runs_recovery").on(table.status, table.leaseUntil),
65
+ index("idx_agent_runtime_runs_release").on(
66
+ table.releaseId,
67
+ table.createdAt,
68
+ ),
69
+ index("idx_agent_runtime_runs_expiry").on(table.status, table.expiresAt),
70
+ check(
71
+ "ck_agent_runtime_runs_status",
72
+ sql`${table.status} in ('accepted', 'running', 'awaiting-approval', 'completed', 'failed', 'cancelled')`,
73
+ ),
74
+ ],
75
+ );
76
+
77
+ export const agentRuntimeEvents = pgTable(
78
+ "agent_runtime_events",
79
+ {
80
+ runId: varchar("run_id", { length: 80 })
81
+ .notNull()
82
+ .references(() => agentRuntimeRuns.runId, { onDelete: "cascade" }),
83
+ sequence: integer("sequence").notNull(),
84
+ eventCipher: text("event_cipher").notNull(),
85
+ },
86
+ (table) => [
87
+ primaryKey({ columns: [table.runId, table.sequence] }),
88
+ check("ck_agent_runtime_events_sequence", sql`${table.sequence} > 0`),
89
+ ],
90
+ );
91
+
92
+ export const agentEvaluationResults = pgTable(
93
+ "agent_evaluation_results",
94
+ {
95
+ evaluationId: varchar("evaluation_id", { length: 80 }).primaryKey(),
96
+ releaseId: varchar("release_id", { length: 80 })
97
+ .notNull()
98
+ .references(() => agentOperationReleases.releaseId, {
99
+ onDelete: "restrict",
100
+ }),
101
+ evaluationSetKey: varchar("evaluation_set_key", {
102
+ length: 160,
103
+ }).notNull(),
104
+ evaluationSetVersion: varchar("evaluation_set_version", {
105
+ length: 80,
106
+ }).notNull(),
107
+ metricsJson: jsonb("metrics_json")
108
+ .$type<Record<string, number>>()
109
+ .notNull(),
110
+ createdAt: doublePrecision("created_at").notNull(),
111
+ },
112
+ (table) => [
113
+ uniqueIndex("uk_agent_evaluation_release_set").on(
114
+ table.releaseId,
115
+ table.evaluationSetKey,
116
+ table.evaluationSetVersion,
117
+ ),
118
+ ],
119
+ );
120
+
121
+ export const agentRunBindings = pgTable(
122
+ "agent_run_bindings",
123
+ {
124
+ bindingId: varchar("binding_id", { length: 80 }).primaryKey(),
125
+ runId: varchar("run_id", { length: 80 }),
126
+ operationKey: varchar("operation_key", { length: 200 }).notNull(),
127
+ actorId: varchar("actor_id", { length: 64 }).notNull(),
128
+ idempotencyHash: varchar("idempotency_hash", { length: 64 }).notNull(),
129
+ tokenHash: varchar("token_hash", { length: 64 }).notNull(),
130
+ scopeHash: varchar("scope_hash", { length: 64 }).notNull(),
131
+ scopeSnapshot: jsonb("scope_snapshot")
132
+ .$type<AuthorizationScopeSnapshot>()
133
+ .notNull(),
134
+ authorizationSnapshot: jsonb("authorization_snapshot")
135
+ .$type<AgentRunAuthorizationSnapshot>()
136
+ .notNull(),
137
+ releaseId: varchar("release_id", { length: 80 }).notNull(),
138
+ createdAt: doublePrecision("created_at").notNull(),
139
+ boundAt: doublePrecision("bound_at"),
140
+ expiresAt: doublePrecision("expires_at").notNull(),
141
+ },
142
+ (table) => [
143
+ uniqueIndex("uk_agent_run_bindings_run").on(table.runId),
144
+ uniqueIndex("uk_agent_run_bindings_idempotency").on(table.idempotencyHash),
145
+ uniqueIndex("uk_agent_run_bindings_token").on(table.tokenHash),
146
+ index("idx_agent_run_bindings_actor").on(table.actorId, table.expiresAt),
147
+ index("idx_agent_run_bindings_expiry").on(table.expiresAt),
148
+ ],
149
+ );
@@ -1,3 +1,4 @@
1
+ import type { AuthorizationScopeSnapshot } from "@southwind-ai/shared";
1
2
  import { timestamp, varchar } from "drizzle-orm/pg-core";
2
3
 
3
4
  export const idColumn = (name = "id") => varchar(name, { length: 64 });
@@ -17,17 +18,4 @@ export const auditColumns = {
17
18
  deletedBy: varchar("deleted_by", { length: 64 }),
18
19
  };
19
20
 
20
- export interface GovernedExportScopeSnapshot {
21
- tenantId: "single-tenant";
22
- actorId: string;
23
- departmentId?: string;
24
- grants: Array<
25
- | { scope: "all" | "tenant" | "self" }
26
- | {
27
- scope: "department" | "department-and-children";
28
- departmentId?: string;
29
- }
30
- | { scope: "custom"; dimension: string; values: string[] }
31
- >;
32
- roleIds: string[];
33
- }
21
+ export type GovernedExportScopeSnapshot = AuthorizationScopeSnapshot;
@@ -1,4 +1,5 @@
1
1
  import { sql } from "drizzle-orm";
2
+ import type { AuthorizationScopeSnapshot } from "@southwind-ai/shared";
2
3
  import {
3
4
  boolean,
4
5
  check,
@@ -23,6 +24,9 @@ export const durableJobs = pgTable(
23
24
  payload: jsonb("payload").$type<Record<string, unknown>>().notNull(),
24
25
  priority: integer("priority").notNull().default(0),
25
26
  requestedBy: varchar("requested_by", { length: 64 }).notNull(),
27
+ authorizationScope: jsonb(
28
+ "authorization_scope",
29
+ ).$type<AuthorizationScopeSnapshot>(),
26
30
  maxAttempts: integer("max_attempts").notNull().default(3),
27
31
  timeoutSeconds: integer("timeout_seconds").notNull().default(900),
28
32
  availableAt: timestamp("available_at", { withTimezone: true }).notNull(),
@@ -201,6 +205,7 @@ export const durableJobArtifacts = pgTable(
201
205
  byteSize: integer("byte_size").notNull(),
202
206
  sha256: varchar("sha256", { length: 64 }).notNull(),
203
207
  ownerId: varchar("owner_id", { length: 64 }).notNull(),
208
+ metadata: jsonb("metadata").$type<Record<string, unknown>>(),
204
209
  expiresAt: timestamp("expires_at", { withTimezone: true }),
205
210
  createdAt: timestamp("created_at", { withTimezone: true })
206
211
  .notNull()
@@ -1,5 +1,5 @@
1
1
  import { sql } from "drizzle-orm";
2
- import type { LifecycleStatus } from "@southwind-ai/shared";
2
+ import type { JsonValue } from "@southwind-ai/shared";
3
3
  import {
4
4
  boolean,
5
5
  check,
@@ -14,10 +14,19 @@ import type { GovernedExportScopeSnapshot } from "./common.js";
14
14
  import { durableJobs } from "./durable-jobs.js";
15
15
 
16
16
  export interface GovernedExportQuerySnapshot {
17
- q?: string;
18
- status?: LifecycleStatus;
19
- includeDeleted: boolean;
20
- sort?: Array<{ field: string; order: "asc" | "desc" }>;
17
+ readonly [key: string]: JsonValue | undefined;
18
+ }
19
+
20
+ export interface GovernedExportRendererSnapshot {
21
+ formatKey: string;
22
+ templateKey: string;
23
+ templateVersion: string;
24
+ inputSchemaKey: string;
25
+ contentType: string;
26
+ filenameExtension: string;
27
+ maxRecords: number;
28
+ maxOutputBytes: number;
29
+ timeoutSeconds: number;
21
30
  }
22
31
 
23
32
  export const governedExportRequests = pgTable(
@@ -42,6 +51,9 @@ export const governedExportRequests = pgTable(
42
51
  querySnapshot: jsonb("query_snapshot")
43
52
  .$type<GovernedExportQuerySnapshot>()
44
53
  .notNull(),
54
+ renderer: jsonb("renderer")
55
+ .$type<GovernedExportRendererSnapshot>()
56
+ .notNull(),
45
57
  status: varchar("status", { length: 32 }).notNull(),
46
58
  approvalRequired: boolean("approval_required").notNull(),
47
59
  approvalId: varchar("approval_id", { length: 64 }),
@@ -28,3 +28,6 @@ export * from "./scheduler.js";
28
28
  // @windy-module system.workflow begin
29
29
  export * from "./workflow.js";
30
30
  // @windy-module system.workflow end
31
+ // @windy-module system.agent begin
32
+ export * from "./agent-runtime.js";
33
+ // @windy-module system.agent end
@@ -0,0 +1,31 @@
1
+ // @windy-module system.scheduler begin
2
+ import { describe, expect, test } from "bun:test";
3
+ import { getTableConfig } from "drizzle-orm/pg-core";
4
+ import { durableJobRecoveries } from "./schema/index.js";
5
+
6
+ describe("durable job recovery schema", () => {
7
+ test("人工恢复事实按任务与外部请求幂等", async () => {
8
+ expect(getTableConfig(durableJobRecoveries).name).toBe(
9
+ "durable_job_recoveries",
10
+ );
11
+ expect(durableJobRecoveries.reason.notNull).toBe(true);
12
+ expect(getTableConfig(durableJobRecoveries).foreignKeys[0]?.onDelete).toBe(
13
+ "restrict",
14
+ );
15
+ expect(
16
+ getTableConfig(durableJobRecoveries).indexes.some(
17
+ (index) =>
18
+ index.config.name === "uk_durable_job_recoveries_idempotency" &&
19
+ index.config.unique,
20
+ ),
21
+ ).toBe(true);
22
+ const migration = await Bun.file(
23
+ new URL("../drizzle/0024_misty_lizard.sql", import.meta.url),
24
+ ).text();
25
+ expect(migration).toContain('CREATE TABLE "durable_job_recoveries"');
26
+ expect(migration).toContain(
27
+ 'CREATE UNIQUE INDEX "uk_durable_job_recoveries_idempotency"',
28
+ );
29
+ });
30
+ });
31
+ // @windy-module system.scheduler end
@@ -1,6 +1,9 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
  import { getTableConfig } from "drizzle-orm/pg-core";
3
- import { governedExportRequests } from "./schema/index.js";
3
+ import {
4
+ durableJobArtifacts,
5
+ governedExportRequests,
6
+ } from "./schema/index.js";
4
7
 
5
8
  describe("governed export schema", () => {
6
9
  test("申请以 owner/resource/idempotency 唯一并受 Durable Job 外键约束", async () => {
@@ -9,6 +12,7 @@ describe("governed export schema", () => {
9
12
  expect(config.name).toBe("governed_export_requests");
10
13
  expect(governedExportRequests.scopeSnapshot.notNull).toBe(true);
11
14
  expect(governedExportRequests.requestFingerprint.notNull).toBe(true);
15
+ expect(governedExportRequests.renderer.notNull).toBe(true);
12
16
  expect(governedExportRequests.durableJobId.notNull).toBe(false);
13
17
  expect(config.foreignKeys[0]?.onDelete).toBe("restrict");
14
18
  expect(
@@ -45,5 +49,21 @@ describe("governed export schema", () => {
45
49
  expect(constraintMigration).toContain(
46
50
  'VALIDATE CONSTRAINT "ck_governed_exports_approval_job_state"',
47
51
  );
52
+ const rendererMigration = await Bun.file(
53
+ new URL(
54
+ "../drizzle/0042_puzzling_rumiko_fujikawa.sql",
55
+ import.meta.url,
56
+ ),
57
+ ).text();
58
+ expect(rendererMigration).toContain(
59
+ 'UPDATE "governed_export_requests"',
60
+ );
61
+ expect(rendererMigration).toContain(
62
+ 'ALTER COLUMN "renderer" SET NOT NULL',
63
+ );
64
+ expect(rendererMigration).toContain(
65
+ 'UPDATE "durable_job_artifacts" AS artifact',
66
+ );
67
+ expect(durableJobArtifacts.metadata.notNull).toBe(false);
48
68
  });
49
69
  });
@@ -11,7 +11,6 @@ import {
11
11
  durableJobFailures,
12
12
  durableJobLeases,
13
13
  durableJobProgress,
14
- durableJobRecoveries,
15
14
  durableJobStages,
16
15
  durableJobs,
17
16
  scheduledTaskRuns,
@@ -263,6 +262,7 @@ describe("database schema", () => {
263
262
  test("durable job 七类事实具备幂等、租约和不可变历史约束", async () => {
264
263
  expect(getTableConfig(durableJobs).name).toBe("durable_jobs");
265
264
  expect(durableJobs.payload.notNull).toBe(true);
265
+ expect(durableJobs.authorizationScope).toBeDefined();
266
266
  expect(
267
267
  getTableConfig(durableJobs).indexes.some(
268
268
  (index) =>
@@ -315,30 +315,13 @@ describe("database schema", () => {
315
315
  expect(migration).toContain(
316
316
  'CREATE UNIQUE INDEX "uk_durable_job_leases_active_stage"',
317
317
  );
318
- });
319
-
320
- test("durable job 人工恢复事实按任务与外部请求幂等", async () => {
321
- expect(getTableConfig(durableJobRecoveries).name).toBe(
322
- "durable_job_recoveries",
323
- );
324
- expect(durableJobRecoveries.reason.notNull).toBe(true);
325
- expect(getTableConfig(durableJobRecoveries).foreignKeys[0]?.onDelete).toBe(
326
- "restrict",
327
- );
328
- expect(
329
- getTableConfig(durableJobRecoveries).indexes.some(
330
- (index) =>
331
- index.config.name === "uk_durable_job_recoveries_idempotency" &&
332
- index.config.unique,
333
- ),
334
- ).toBe(true);
335
- const migration = await Bun.file(
336
- new URL("../drizzle/0024_misty_lizard.sql", import.meta.url),
318
+ const authorizationMigration = await Bun.file(
319
+ new URL("../drizzle/0039_early_ezekiel_stane.sql", import.meta.url),
337
320
  ).text();
338
- expect(migration).toContain('CREATE TABLE "durable_job_recoveries"');
339
- expect(migration).toContain(
340
- 'CREATE UNIQUE INDEX "uk_durable_job_recoveries_idempotency"',
321
+ expect(authorizationMigration).toContain(
322
+ 'ALTER TABLE "durable_jobs" ADD COLUMN "authorization_scope" jsonb',
341
323
  );
342
324
  });
325
+
343
326
  // @windy-module system.scheduler end
344
327
  });
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@southwind-ai/jobs",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "engines": {
@@ -16,7 +16,8 @@
16
16
  "typecheck": "tsc --noEmit --project tsconfig.json"
17
17
  },
18
18
  "dependencies": {
19
- "@southwind-ai/storage": "workspace:*"
19
+ "@southwind-ai/shared": "workspace:^",
20
+ "@southwind-ai/storage": "workspace:^"
20
21
  },
21
22
  "exports": {
22
23
  ".": "./index.ts",
@@ -57,6 +57,19 @@ describe("DurableHandlerRegistry", () => {
57
57
  "任务 handler 重复注册:example.sync",
58
58
  );
59
59
  });
60
+
61
+ test("保留宿主颁发的模块归属供 Worker 重建受限上下文", () => {
62
+ const registry = new DurableHandlerRegistry().register(
63
+ {
64
+ key: "evidence.parse",
65
+ payload: { parse: () => ({}) },
66
+ execute: () => undefined,
67
+ },
68
+ { moduleName: "evidence" },
69
+ );
70
+
71
+ expect(registry.get("evidence.parse")?.moduleName).toBe("evidence");
72
+ });
60
73
  });
61
74
 
62
75
  function createContext(): DurableHandlerContext {
@@ -25,6 +25,7 @@ export interface DurableHandlerContext {
25
25
  sha256: string;
26
26
  ownerId: string;
27
27
  expiresAt?: string;
28
+ metadata?: Record<string, unknown>;
28
29
  }): Promise<void>;
29
30
  }
30
31
 
@@ -36,6 +37,7 @@ export interface DurableHandlerDefinition<T> {
36
37
 
37
38
  export interface RegisteredDurableHandler {
38
39
  key: string;
40
+ moduleName?: string;
39
41
  execute(
40
42
  payload: Record<string, unknown>,
41
43
  context: DurableHandlerContext,
@@ -45,13 +47,17 @@ export interface RegisteredDurableHandler {
45
47
  export class DurableHandlerRegistry {
46
48
  private readonly handlers = new Map<string, RegisteredDurableHandler>();
47
49
 
48
- register<T>(definition: DurableHandlerDefinition<T>): this {
50
+ register<T>(
51
+ definition: DurableHandlerDefinition<T>,
52
+ metadata: { moduleName?: string } = {},
53
+ ): this {
49
54
  if (!definition.key.trim()) throw new Error("任务 handler key 不能为空");
50
55
  if (this.handlers.has(definition.key)) {
51
56
  throw new Error(`任务 handler 重复注册:${definition.key}`);
52
57
  }
53
58
  this.handlers.set(definition.key, {
54
59
  key: definition.key,
60
+ moduleName: metadata.moduleName,
55
61
  execute: async (payload, context) => {
56
62
  await definition.execute(definition.payload.parse(payload), context);
57
63
  },
@@ -1,4 +1,5 @@
1
1
  import type { ArtifactRef } from "@southwind-ai/storage";
2
+ import type { AuthorizationScopeSnapshot } from "@southwind-ai/shared";
2
3
 
3
4
  export type DurableJobStatus =
4
5
  | "queued"
@@ -31,6 +32,7 @@ export interface DurableJob {
31
32
  payload: Record<string, unknown>;
32
33
  priority: number;
33
34
  requestedBy: string;
35
+ authorizationScope?: AuthorizationScopeSnapshot;
34
36
  maxAttempts: number;
35
37
  timeoutSeconds: number;
36
38
  availableAt: string;
@@ -108,6 +110,7 @@ export interface DurableJobArtifact {
108
110
  sha256: string;
109
111
  ownerId: string;
110
112
  expiresAt?: string;
113
+ metadata?: Record<string, unknown>;
111
114
  createdAt: string;
112
115
  }
113
116
 
@@ -166,6 +169,7 @@ export interface SubmitDurableJob {
166
169
  idempotencyKey: string;
167
170
  payload: Record<string, unknown>;
168
171
  requestedBy: string;
172
+ authorizationScope?: AuthorizationScopeSnapshot;
169
173
  queue?: string;
170
174
  priority?: number;
171
175
  maxAttempts?: number;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@southwind-ai/modules",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "engines": {
@@ -12,7 +12,7 @@
12
12
  "!src/**/*.test.ts"
13
13
  ],
14
14
  "dependencies": {
15
- "@southwind-ai/shared": "workspace:*"
15
+ "@southwind-ai/shared": "workspace:^"
16
16
  },
17
17
  "exports": {
18
18
  ".": "./index.ts"