@oyolincc/create 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (448) hide show
  1. package/dist/index.d.mts +2 -2
  2. package/dist/index.mjs +2 -2
  3. package/dist/index.mjs.map +1 -1
  4. package/package.json +29 -13
  5. package/templates/hono-fullstack/.agents/skills/ask-matt/PHASE-BOUNDARIES.md +55 -0
  6. package/templates/hono-fullstack/.agents/skills/ask-matt/SKILL.md +90 -0
  7. package/templates/hono-fullstack/.agents/skills/ask-matt/agents/openai.yaml +5 -0
  8. package/templates/hono-fullstack/.agents/skills/code-review/SKILL.md +87 -0
  9. package/templates/hono-fullstack/.agents/skills/code-review/agents/openai.yaml +3 -0
  10. package/templates/hono-fullstack/.agents/skills/codebase-design/DEEPENING.md +37 -0
  11. package/templates/hono-fullstack/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  12. package/templates/hono-fullstack/.agents/skills/codebase-design/SKILL.md +114 -0
  13. package/templates/hono-fullstack/.agents/skills/codebase-design/agents/openai.yaml +3 -0
  14. package/templates/hono-fullstack/.agents/skills/confirm-requirements/SKILL.md +25 -0
  15. package/templates/hono-fullstack/.agents/skills/diagnosing-bugs/SKILL.md +140 -0
  16. package/templates/hono-fullstack/.agents/skills/diagnosing-bugs/agents/openai.yaml +3 -0
  17. package/templates/hono-fullstack/.agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  18. package/templates/hono-fullstack/.agents/skills/domain-modeling/ADR-FORMAT.md +47 -0
  19. package/templates/hono-fullstack/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  20. package/templates/hono-fullstack/.agents/skills/domain-modeling/SKILL.md +74 -0
  21. package/templates/hono-fullstack/.agents/skills/domain-modeling/agents/openai.yaml +3 -0
  22. package/templates/hono-fullstack/.agents/skills/grill-me/SKILL.md +7 -0
  23. package/templates/hono-fullstack/.agents/skills/grill-me/agents/openai.yaml +5 -0
  24. package/templates/hono-fullstack/.agents/skills/grilling/SKILL.md +22 -0
  25. package/templates/hono-fullstack/.agents/skills/grilling/agents/openai.yaml +3 -0
  26. package/templates/hono-fullstack/.agents/skills/implement/SKILL.md +15 -0
  27. package/templates/hono-fullstack/.agents/skills/implement/agents/openai.yaml +5 -0
  28. package/templates/hono-fullstack/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
  29. package/templates/hono-fullstack/.agents/skills/improve-codebase-architecture/SKILL.md +71 -0
  30. package/templates/hono-fullstack/.agents/skills/improve-codebase-architecture/agents/openai.yaml +5 -0
  31. package/templates/hono-fullstack/.agents/skills/prototype/LOGIC.md +67 -0
  32. package/templates/hono-fullstack/.agents/skills/prototype/SKILL.md +26 -0
  33. package/templates/hono-fullstack/.agents/skills/prototype/UI.md +112 -0
  34. package/templates/hono-fullstack/.agents/skills/prototype/agents/openai.yaml +3 -0
  35. package/templates/hono-fullstack/.agents/skills/research/SKILL.md +12 -0
  36. package/templates/hono-fullstack/.agents/skills/research/agents/openai.yaml +3 -0
  37. package/templates/hono-fullstack/.agents/skills/resolving-merge-conflicts/SKILL.md +14 -0
  38. package/templates/hono-fullstack/.agents/skills/resolving-merge-conflicts/agents/openai.yaml +3 -0
  39. package/templates/hono-fullstack/.agents/skills/scoped-code-review/SKILL.md +113 -0
  40. package/templates/hono-fullstack/.agents/skills/setup-matt-pocock-skills/SKILL.md +116 -0
  41. package/templates/hono-fullstack/.agents/skills/setup-matt-pocock-skills/agents/openai.yaml +5 -0
  42. package/templates/hono-fullstack/.agents/skills/setup-matt-pocock-skills/domain.md +51 -0
  43. package/templates/hono-fullstack/.agents/skills/setup-matt-pocock-skills/issue-tracker-github.md +45 -0
  44. package/templates/hono-fullstack/.agents/skills/setup-matt-pocock-skills/issue-tracker-gitlab.md +46 -0
  45. package/templates/hono-fullstack/.agents/skills/setup-matt-pocock-skills/issue-tracker-local.md +30 -0
  46. package/templates/hono-fullstack/.agents/skills/setup-matt-pocock-skills/triage-labels.md +15 -0
  47. package/templates/hono-fullstack/.agents/skills/tdd/SKILL.md +38 -0
  48. package/templates/hono-fullstack/.agents/skills/tdd/agents/openai.yaml +3 -0
  49. package/templates/hono-fullstack/.agents/skills/tdd/mocking.md +59 -0
  50. package/templates/hono-fullstack/.agents/skills/tdd/tests.md +77 -0
  51. package/templates/hono-fullstack/.agents/skills/teach/GLOSSARY-FORMAT.md +35 -0
  52. package/templates/hono-fullstack/.agents/skills/teach/LEARNING-RECORD-FORMAT.md +46 -0
  53. package/templates/hono-fullstack/.agents/skills/teach/MISSION-FORMAT.md +31 -0
  54. package/templates/hono-fullstack/.agents/skills/teach/RESOURCES-FORMAT.md +32 -0
  55. package/templates/hono-fullstack/.agents/skills/teach/SKILL.md +140 -0
  56. package/templates/hono-fullstack/.agents/skills/teach/agents/openai.yaml +5 -0
  57. package/templates/hono-fullstack/.agents/skills/to-questionnaire/SKILL.md +53 -0
  58. package/templates/hono-fullstack/.agents/skills/to-questionnaire/agents/openai.yaml +5 -0
  59. package/templates/hono-fullstack/.agents/skills/triage/AGENT-BRIEF.md +207 -0
  60. package/templates/hono-fullstack/.agents/skills/triage/OUT-OF-SCOPE.md +105 -0
  61. package/templates/hono-fullstack/.agents/skills/triage/SKILL.md +112 -0
  62. package/templates/hono-fullstack/.agents/skills/triage/agents/openai.yaml +5 -0
  63. package/templates/hono-fullstack/.agents/skills/wait-what/SKILL.md +7 -0
  64. package/templates/hono-fullstack/.agents/skills/wait-what/agents/openai.yaml +5 -0
  65. package/templates/hono-fullstack/.agents/skills/wayfinder/SKILL.md +128 -0
  66. package/templates/hono-fullstack/.agents/skills/wayfinder/agents/openai.yaml +5 -0
  67. package/templates/hono-fullstack/.agents/skills/wizard/SKILL.md +44 -0
  68. package/templates/hono-fullstack/.agents/skills/wizard/agents/openai.yaml +3 -0
  69. package/templates/hono-fullstack/.agents/skills/wizard/template.sh +204 -0
  70. package/templates/hono-fullstack/.agents/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
  71. package/templates/hono-fullstack/.agents/skills/writing-for-agents/SKILL.md +81 -0
  72. package/templates/hono-fullstack/.agents/skills/writing-for-agents/agents/openai.yaml +3 -0
  73. package/templates/hono-fullstack/.changeset/README.md +8 -0
  74. package/templates/hono-fullstack/.changeset/config.json +11 -0
  75. package/templates/hono-fullstack/.editorconfig +31 -0
  76. package/templates/hono-fullstack/.gitattributes +39 -0
  77. package/templates/hono-fullstack/.vscode/extensions.json +5 -0
  78. package/templates/hono-fullstack/.vscode/launch.json +36 -0
  79. package/templates/hono-fullstack/.vscode/settings.json +26 -0
  80. package/templates/hono-fullstack/AGENTS.md +50 -0
  81. package/templates/hono-fullstack/README.md +51 -0
  82. package/templates/hono-fullstack/_gitignore +35 -0
  83. package/templates/hono-fullstack/apps/server/.dev.vars.example +9 -0
  84. package/templates/hono-fullstack/apps/server/package.json +63 -0
  85. package/templates/hono-fullstack/apps/server/src/adapters/cloudflare/entry.ts +36 -0
  86. package/templates/hono-fullstack/apps/server/src/adapters/nodejs/bootstrap.ts +61 -0
  87. package/templates/hono-fullstack/apps/server/src/adapters/nodejs/entry.ts +62 -0
  88. package/templates/hono-fullstack/apps/server/src/app.ts +43 -0
  89. package/templates/hono-fullstack/apps/server/src/config.ts +47 -0
  90. package/templates/hono-fullstack/apps/server/src/infra/logger/getter.ts +74 -0
  91. package/templates/hono-fullstack/apps/server/src/infra/logger/pino.ts +126 -0
  92. package/templates/hono-fullstack/apps/server/src/infra/work-runner/constants.ts +23 -0
  93. package/templates/hono-fullstack/apps/server/src/infra/work-runner/errors.ts +40 -0
  94. package/templates/hono-fullstack/apps/server/src/infra/work-runner/example/worker-entry.ts +13 -0
  95. package/templates/hono-fullstack/apps/server/src/infra/work-runner/pass-through/runner.ts +42 -0
  96. package/templates/hono-fullstack/apps/server/src/infra/work-runner/piscina/runner.ts +185 -0
  97. package/templates/hono-fullstack/apps/server/src/infra/work-runner/types.ts +118 -0
  98. package/templates/hono-fullstack/apps/server/src/infra/work-runner/utils/business-error.ts +19 -0
  99. package/templates/hono-fullstack/apps/server/src/infra/work-runner/utils/message.ts +49 -0
  100. package/templates/hono-fullstack/apps/server/src/infra/work-runner/utils/transfer.ts +144 -0
  101. package/templates/hono-fullstack/apps/server/src/middlewares/cors.ts +26 -0
  102. package/templates/hono-fullstack/apps/server/src/modules/example/contracts.ts +9 -0
  103. package/templates/hono-fullstack/apps/server/src/modules/example/routes.ts +73 -0
  104. package/templates/hono-fullstack/apps/server/src/modules/example/work-task/tasks.test.ts +49 -0
  105. package/templates/hono-fullstack/apps/server/src/modules/example/work-task/tasks.ts +58 -0
  106. package/templates/hono-fullstack/apps/server/src/shared/app/types.ts +44 -0
  107. package/templates/hono-fullstack/apps/server/src/shared/errors/constants.ts +152 -0
  108. package/templates/hono-fullstack/apps/server/src/shared/errors/defs/index.ts +15 -0
  109. package/templates/hono-fullstack/apps/server/src/shared/errors/handler.ts +16 -0
  110. package/templates/hono-fullstack/apps/server/src/shared/errors/log.ts +67 -0
  111. package/templates/hono-fullstack/apps/server/src/shared/errors/proto.ts +42 -0
  112. package/templates/hono-fullstack/apps/server/src/shared/errors/types.ts +29 -0
  113. package/templates/hono-fullstack/apps/server/src/shared/network/fetcher.ts +35 -0
  114. package/templates/hono-fullstack/apps/server/src/shared/network/openapi/index.ts +50 -0
  115. package/templates/hono-fullstack/apps/server/src/shared/network/openapi/res-defs.ts +39 -0
  116. package/templates/hono-fullstack/apps/server/src/shared/network/types.ts +3 -0
  117. package/templates/hono-fullstack/apps/server/src/shared/network/utils.ts +36 -0
  118. package/templates/hono-fullstack/apps/server/src/shared/network/validator.ts +28 -0
  119. package/templates/hono-fullstack/apps/server/src/shared/utils/index.ts +30 -0
  120. package/templates/hono-fullstack/apps/server/src/virtual-modules.d.ts +5 -0
  121. package/templates/hono-fullstack/apps/server/tsconfig.json +17 -0
  122. package/templates/hono-fullstack/apps/server/vite.config.ts +87 -0
  123. package/templates/hono-fullstack/apps/server/wrangler.jsonc +29 -0
  124. package/templates/hono-fullstack/apps/stack/backend/cloudflare.ts +5 -0
  125. package/templates/hono-fullstack/apps/stack/backend/node.ts +3 -0
  126. package/templates/hono-fullstack/apps/stack/frontend/components/general/ErrorMessage.tsx +4 -0
  127. package/templates/hono-fullstack/apps/stack/frontend/components/layouts/AppLayout.tsx +11 -0
  128. package/templates/hono-fullstack/apps/stack/frontend/components/layouts/Header.tsx +7 -0
  129. package/templates/hono-fullstack/apps/stack/frontend/components/layouts/Page.tsx +5 -0
  130. package/templates/hono-fullstack/apps/stack/frontend/components/layouts/PageContainer.tsx +5 -0
  131. package/templates/hono-fullstack/apps/stack/frontend/modules/example/api.ts +13 -0
  132. package/templates/hono-fullstack/apps/stack/frontend/modules/example/components/ExampleForm.tsx +45 -0
  133. package/templates/hono-fullstack/apps/stack/frontend/modules/example/components/ExampleList.tsx +13 -0
  134. package/templates/hono-fullstack/apps/stack/frontend/modules/example/hooks/api-hooks.ts +14 -0
  135. package/templates/hono-fullstack/apps/stack/frontend/modules/example/stores/index.ts +3 -0
  136. package/templates/hono-fullstack/apps/stack/frontend/routeTree.gen.ts +73 -0
  137. package/templates/hono-fullstack/apps/stack/frontend/router.tsx +22 -0
  138. package/templates/hono-fullstack/apps/stack/frontend/routes/__root.tsx +61 -0
  139. package/templates/hono-fullstack/apps/stack/frontend/routes/api/$.ts +18 -0
  140. package/templates/hono-fullstack/apps/stack/frontend/routes/index.tsx +50 -0
  141. package/templates/hono-fullstack/apps/stack/frontend/shared/network/client.ts +19 -0
  142. package/templates/hono-fullstack/apps/stack/frontend/shared/network/constants.ts +1 -0
  143. package/templates/hono-fullstack/apps/stack/frontend/shared/network/errors.ts +33 -0
  144. package/templates/hono-fullstack/apps/stack/frontend/styles.css +23 -0
  145. package/templates/hono-fullstack/apps/stack/frontend/vite-env.d.ts +6 -0
  146. package/templates/hono-fullstack/apps/stack/package.json +59 -0
  147. package/templates/hono-fullstack/apps/stack/tsconfig.json +13 -0
  148. package/templates/hono-fullstack/apps/stack/tsr.config.json +5 -0
  149. package/templates/hono-fullstack/apps/stack/vite.config.ts +82 -0
  150. package/templates/hono-fullstack/apps/stack/wrangler.jsonc +20 -0
  151. package/templates/hono-fullstack/docs/agents/domain.md +41 -0
  152. package/templates/hono-fullstack/docs/agents/issue-tracker.md +30 -0
  153. package/templates/hono-fullstack/docs/agents/triage-labels.md +15 -0
  154. package/templates/hono-fullstack/envs/.env.example.server +12 -0
  155. package/templates/hono-fullstack/envs/.env.example.sqlite +1 -0
  156. package/templates/hono-fullstack/envs/.env.example.sqlite-d1 +3 -0
  157. package/templates/hono-fullstack/libs/db/drizzle-kit/sqlite-d1.config.ts +22 -0
  158. package/templates/hono-fullstack/libs/db/drizzle-kit/sqlite.config.ts +22 -0
  159. package/templates/hono-fullstack/libs/db/package.json +42 -0
  160. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/client.ts +35 -0
  161. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/d1-client.ts +12 -0
  162. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/schema/columns.ts +37 -0
  163. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/schema/index.ts +7 -0
  164. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/schema/modules/examples/examples.ts +22 -0
  165. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/schema/relations.ts +5 -0
  166. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/schema/tables.ts +5 -0
  167. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/schema/types.ts +7 -0
  168. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/schema/vo.ts +1 -0
  169. package/templates/hono-fullstack/libs/db/src/dialects/sqlite/utils.ts +8 -0
  170. package/templates/hono-fullstack/libs/db/src/shared/types.ts +26 -0
  171. package/templates/hono-fullstack/libs/db/tsconfig.json +10 -0
  172. package/templates/hono-fullstack/libs/db/vite.config.ts +25 -0
  173. package/templates/hono-fullstack/libs/definition/package.json +30 -0
  174. package/templates/hono-fullstack/libs/definition/src/backend.ts +2 -0
  175. package/templates/hono-fullstack/libs/definition/src/configs/defs/log.ts +53 -0
  176. package/templates/hono-fullstack/libs/definition/src/configs/defs/middleware.ts +16 -0
  177. package/templates/hono-fullstack/libs/definition/src/configs/defs/runtime.ts +12 -0
  178. package/templates/hono-fullstack/libs/definition/src/configs/defs/sqlite.ts +26 -0
  179. package/templates/hono-fullstack/libs/definition/src/configs/defs/worker.ts +29 -0
  180. package/templates/hono-fullstack/libs/definition/src/configs/index.ts +5 -0
  181. package/templates/hono-fullstack/libs/definition/src/configs/proto.ts +81 -0
  182. package/templates/hono-fullstack/libs/definition/src/configs/schema.ts +23 -0
  183. package/templates/hono-fullstack/libs/definition/src/frontend.ts +1 -0
  184. package/templates/hono-fullstack/libs/definition/src/modules/example/index.ts +16 -0
  185. package/templates/hono-fullstack/libs/definition/src/modules/index.ts +1 -0
  186. package/templates/hono-fullstack/libs/definition/tsconfig.json +5 -0
  187. package/templates/hono-fullstack/libs/definition/vite.config.ts +16 -0
  188. package/templates/hono-fullstack/oyo.config.json +13 -0
  189. package/templates/hono-fullstack/package.json +25 -0
  190. package/templates/hono-fullstack/pnpm-workspace.yaml +84 -0
  191. package/templates/hono-fullstack/tsconfig.json +4 -0
  192. package/templates/hono-fullstack/turbo.json +36 -0
  193. package/templates/hono-fullstack/vite.config.ts +14 -0
  194. package/templates/hono-server/.agents/skills/ask-matt/PHASE-BOUNDARIES.md +55 -0
  195. package/templates/hono-server/.agents/skills/ask-matt/SKILL.md +90 -0
  196. package/templates/hono-server/.agents/skills/ask-matt/agents/openai.yaml +5 -0
  197. package/templates/hono-server/.agents/skills/code-review/SKILL.md +87 -0
  198. package/templates/hono-server/.agents/skills/code-review/agents/openai.yaml +3 -0
  199. package/templates/hono-server/.agents/skills/codebase-design/DEEPENING.md +37 -0
  200. package/templates/hono-server/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  201. package/templates/hono-server/.agents/skills/codebase-design/SKILL.md +114 -0
  202. package/templates/hono-server/.agents/skills/codebase-design/agents/openai.yaml +3 -0
  203. package/templates/hono-server/.agents/skills/confirm-requirements/SKILL.md +25 -0
  204. package/templates/hono-server/.agents/skills/diagnosing-bugs/SKILL.md +140 -0
  205. package/templates/hono-server/.agents/skills/diagnosing-bugs/agents/openai.yaml +3 -0
  206. package/templates/hono-server/.agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  207. package/templates/hono-server/.agents/skills/domain-modeling/ADR-FORMAT.md +47 -0
  208. package/templates/hono-server/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  209. package/templates/hono-server/.agents/skills/domain-modeling/SKILL.md +74 -0
  210. package/templates/hono-server/.agents/skills/domain-modeling/agents/openai.yaml +3 -0
  211. package/templates/hono-server/.agents/skills/grill-me/SKILL.md +7 -0
  212. package/templates/hono-server/.agents/skills/grill-me/agents/openai.yaml +5 -0
  213. package/templates/hono-server/.agents/skills/grilling/SKILL.md +22 -0
  214. package/templates/hono-server/.agents/skills/grilling/agents/openai.yaml +3 -0
  215. package/templates/hono-server/.agents/skills/implement/SKILL.md +15 -0
  216. package/templates/hono-server/.agents/skills/implement/agents/openai.yaml +5 -0
  217. package/templates/hono-server/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
  218. package/templates/hono-server/.agents/skills/improve-codebase-architecture/SKILL.md +71 -0
  219. package/templates/hono-server/.agents/skills/improve-codebase-architecture/agents/openai.yaml +5 -0
  220. package/templates/hono-server/.agents/skills/prototype/LOGIC.md +67 -0
  221. package/templates/hono-server/.agents/skills/prototype/SKILL.md +26 -0
  222. package/templates/hono-server/.agents/skills/prototype/UI.md +112 -0
  223. package/templates/hono-server/.agents/skills/prototype/agents/openai.yaml +3 -0
  224. package/templates/hono-server/.agents/skills/research/SKILL.md +12 -0
  225. package/templates/hono-server/.agents/skills/research/agents/openai.yaml +3 -0
  226. package/templates/hono-server/.agents/skills/resolving-merge-conflicts/SKILL.md +14 -0
  227. package/templates/hono-server/.agents/skills/resolving-merge-conflicts/agents/openai.yaml +3 -0
  228. package/templates/hono-server/.agents/skills/scoped-code-review/SKILL.md +113 -0
  229. package/templates/hono-server/.agents/skills/setup-matt-pocock-skills/SKILL.md +116 -0
  230. package/templates/hono-server/.agents/skills/setup-matt-pocock-skills/agents/openai.yaml +5 -0
  231. package/templates/hono-server/.agents/skills/setup-matt-pocock-skills/domain.md +51 -0
  232. package/templates/hono-server/.agents/skills/setup-matt-pocock-skills/issue-tracker-github.md +45 -0
  233. package/templates/hono-server/.agents/skills/setup-matt-pocock-skills/issue-tracker-gitlab.md +46 -0
  234. package/templates/hono-server/.agents/skills/setup-matt-pocock-skills/issue-tracker-local.md +30 -0
  235. package/templates/hono-server/.agents/skills/setup-matt-pocock-skills/triage-labels.md +15 -0
  236. package/templates/hono-server/.agents/skills/tdd/SKILL.md +38 -0
  237. package/templates/hono-server/.agents/skills/tdd/agents/openai.yaml +3 -0
  238. package/templates/hono-server/.agents/skills/tdd/mocking.md +59 -0
  239. package/templates/hono-server/.agents/skills/tdd/tests.md +77 -0
  240. package/templates/hono-server/.agents/skills/teach/GLOSSARY-FORMAT.md +35 -0
  241. package/templates/hono-server/.agents/skills/teach/LEARNING-RECORD-FORMAT.md +46 -0
  242. package/templates/hono-server/.agents/skills/teach/MISSION-FORMAT.md +31 -0
  243. package/templates/hono-server/.agents/skills/teach/RESOURCES-FORMAT.md +32 -0
  244. package/templates/hono-server/.agents/skills/teach/SKILL.md +140 -0
  245. package/templates/hono-server/.agents/skills/teach/agents/openai.yaml +5 -0
  246. package/templates/hono-server/.agents/skills/to-questionnaire/SKILL.md +53 -0
  247. package/templates/hono-server/.agents/skills/to-questionnaire/agents/openai.yaml +5 -0
  248. package/templates/hono-server/.agents/skills/triage/AGENT-BRIEF.md +207 -0
  249. package/templates/hono-server/.agents/skills/triage/OUT-OF-SCOPE.md +105 -0
  250. package/templates/hono-server/.agents/skills/triage/SKILL.md +112 -0
  251. package/templates/hono-server/.agents/skills/triage/agents/openai.yaml +5 -0
  252. package/templates/hono-server/.agents/skills/wait-what/SKILL.md +7 -0
  253. package/templates/hono-server/.agents/skills/wait-what/agents/openai.yaml +5 -0
  254. package/templates/hono-server/.agents/skills/wayfinder/SKILL.md +128 -0
  255. package/templates/hono-server/.agents/skills/wayfinder/agents/openai.yaml +5 -0
  256. package/templates/hono-server/.agents/skills/wizard/SKILL.md +44 -0
  257. package/templates/hono-server/.agents/skills/wizard/agents/openai.yaml +3 -0
  258. package/templates/hono-server/.agents/skills/wizard/template.sh +204 -0
  259. package/templates/hono-server/.agents/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
  260. package/templates/hono-server/.agents/skills/writing-for-agents/SKILL.md +81 -0
  261. package/templates/hono-server/.agents/skills/writing-for-agents/agents/openai.yaml +3 -0
  262. package/templates/hono-server/.changeset/README.md +8 -0
  263. package/templates/hono-server/.changeset/config.json +11 -0
  264. package/templates/hono-server/.editorconfig +31 -0
  265. package/templates/hono-server/.gitattributes +39 -0
  266. package/templates/hono-server/.vscode/extensions.json +5 -0
  267. package/templates/hono-server/.vscode/launch.json +29 -0
  268. package/templates/hono-server/.vscode/settings.json +26 -0
  269. package/templates/hono-server/AGENTS.md +50 -0
  270. package/templates/hono-server/README.md +44 -0
  271. package/templates/hono-server/_gitignore +35 -0
  272. package/templates/hono-server/apps/server/.dev.vars.example +9 -0
  273. package/templates/hono-server/apps/server/package.json +64 -0
  274. package/templates/hono-server/apps/server/src/adapters/cloudflare/entry.ts +36 -0
  275. package/templates/hono-server/apps/server/src/adapters/nodejs/bootstrap.ts +61 -0
  276. package/templates/hono-server/apps/server/src/adapters/nodejs/entry.ts +62 -0
  277. package/templates/hono-server/apps/server/src/app.ts +43 -0
  278. package/templates/hono-server/apps/server/src/config.ts +47 -0
  279. package/templates/hono-server/apps/server/src/infra/logger/getter.ts +74 -0
  280. package/templates/hono-server/apps/server/src/infra/logger/pino.ts +126 -0
  281. package/templates/hono-server/apps/server/src/infra/work-runner/constants.ts +23 -0
  282. package/templates/hono-server/apps/server/src/infra/work-runner/errors.ts +40 -0
  283. package/templates/hono-server/apps/server/src/infra/work-runner/example/worker-entry.ts +13 -0
  284. package/templates/hono-server/apps/server/src/infra/work-runner/pass-through/runner.ts +42 -0
  285. package/templates/hono-server/apps/server/src/infra/work-runner/piscina/runner.ts +185 -0
  286. package/templates/hono-server/apps/server/src/infra/work-runner/types.ts +118 -0
  287. package/templates/hono-server/apps/server/src/infra/work-runner/utils/business-error.ts +19 -0
  288. package/templates/hono-server/apps/server/src/infra/work-runner/utils/message.ts +49 -0
  289. package/templates/hono-server/apps/server/src/infra/work-runner/utils/transfer.ts +144 -0
  290. package/templates/hono-server/apps/server/src/middlewares/cors.ts +26 -0
  291. package/templates/hono-server/apps/server/src/modules/example/contracts.ts +9 -0
  292. package/templates/hono-server/apps/server/src/modules/example/routes.ts +73 -0
  293. package/templates/hono-server/apps/server/src/modules/example/work-task/tasks.test.ts +49 -0
  294. package/templates/hono-server/apps/server/src/modules/example/work-task/tasks.ts +58 -0
  295. package/templates/hono-server/apps/server/src/shared/app/types.ts +44 -0
  296. package/templates/hono-server/apps/server/src/shared/errors/constants.ts +152 -0
  297. package/templates/hono-server/apps/server/src/shared/errors/defs/index.ts +15 -0
  298. package/templates/hono-server/apps/server/src/shared/errors/handler.ts +16 -0
  299. package/templates/hono-server/apps/server/src/shared/errors/log.ts +67 -0
  300. package/templates/hono-server/apps/server/src/shared/errors/proto.ts +42 -0
  301. package/templates/hono-server/apps/server/src/shared/errors/types.ts +29 -0
  302. package/templates/hono-server/apps/server/src/shared/network/fetcher.ts +35 -0
  303. package/templates/hono-server/apps/server/src/shared/network/openapi/index.ts +50 -0
  304. package/templates/hono-server/apps/server/src/shared/network/openapi/res-defs.ts +39 -0
  305. package/templates/hono-server/apps/server/src/shared/network/types.ts +3 -0
  306. package/templates/hono-server/apps/server/src/shared/network/utils.ts +36 -0
  307. package/templates/hono-server/apps/server/src/shared/network/validator.ts +28 -0
  308. package/templates/hono-server/apps/server/src/shared/utils/index.ts +30 -0
  309. package/templates/hono-server/apps/server/src/virtual-modules.d.ts +5 -0
  310. package/templates/hono-server/apps/server/tsconfig.json +17 -0
  311. package/templates/hono-server/apps/server/vite.config.ts +87 -0
  312. package/templates/hono-server/apps/server/wrangler.jsonc +29 -0
  313. package/templates/hono-server/docker/.env.example +4 -0
  314. package/templates/hono-server/docker/README.md +5 -0
  315. package/templates/hono-server/docker/local/compose.local.app.yml +21 -0
  316. package/templates/hono-server/docker/local/local-app-deploy.sh +8 -0
  317. package/templates/hono-server/docker/local/local-app-down.sh +8 -0
  318. package/templates/hono-server/docker/prod/.env.example.server +11 -0
  319. package/templates/hono-server/docker/prod/compose.prod.stack.yml +21 -0
  320. package/templates/hono-server/docker/prod/update.sh +7 -0
  321. package/templates/hono-server/docker/server.Dockerfile +38 -0
  322. package/templates/hono-server/docker/server.Dockerfile.dockerignore +23 -0
  323. package/templates/hono-server/docs/agents/domain.md +41 -0
  324. package/templates/hono-server/docs/agents/issue-tracker.md +30 -0
  325. package/templates/hono-server/docs/agents/triage-labels.md +15 -0
  326. package/templates/hono-server/envs/.env.example.server +12 -0
  327. package/templates/hono-server/envs/.env.example.sqlite +1 -0
  328. package/templates/hono-server/envs/.env.example.sqlite-d1 +3 -0
  329. package/templates/hono-server/libs/db/drizzle-kit/sqlite-d1.config.ts +22 -0
  330. package/templates/hono-server/libs/db/drizzle-kit/sqlite.config.ts +22 -0
  331. package/templates/hono-server/libs/db/package.json +42 -0
  332. package/templates/hono-server/libs/db/src/dialects/sqlite/client.ts +35 -0
  333. package/templates/hono-server/libs/db/src/dialects/sqlite/d1-client.ts +12 -0
  334. package/templates/hono-server/libs/db/src/dialects/sqlite/schema/columns.ts +37 -0
  335. package/templates/hono-server/libs/db/src/dialects/sqlite/schema/index.ts +7 -0
  336. package/templates/hono-server/libs/db/src/dialects/sqlite/schema/modules/examples/examples.ts +22 -0
  337. package/templates/hono-server/libs/db/src/dialects/sqlite/schema/relations.ts +5 -0
  338. package/templates/hono-server/libs/db/src/dialects/sqlite/schema/tables.ts +5 -0
  339. package/templates/hono-server/libs/db/src/dialects/sqlite/schema/types.ts +7 -0
  340. package/templates/hono-server/libs/db/src/dialects/sqlite/schema/vo.ts +1 -0
  341. package/templates/hono-server/libs/db/src/dialects/sqlite/utils.ts +8 -0
  342. package/templates/hono-server/libs/db/src/shared/types.ts +26 -0
  343. package/templates/hono-server/libs/db/tsconfig.json +10 -0
  344. package/templates/hono-server/libs/db/vite.config.ts +25 -0
  345. package/templates/hono-server/libs/definition/package.json +29 -0
  346. package/templates/hono-server/libs/definition/src/backend.ts +2 -0
  347. package/templates/hono-server/libs/definition/src/configs/defs/log.ts +53 -0
  348. package/templates/hono-server/libs/definition/src/configs/defs/middleware.ts +16 -0
  349. package/templates/hono-server/libs/definition/src/configs/defs/runtime.ts +12 -0
  350. package/templates/hono-server/libs/definition/src/configs/defs/sqlite.ts +26 -0
  351. package/templates/hono-server/libs/definition/src/configs/defs/worker.ts +29 -0
  352. package/templates/hono-server/libs/definition/src/configs/index.ts +5 -0
  353. package/templates/hono-server/libs/definition/src/configs/proto.ts +81 -0
  354. package/templates/hono-server/libs/definition/src/configs/schema.ts +23 -0
  355. package/templates/hono-server/libs/definition/src/modules/example/index.ts +16 -0
  356. package/templates/hono-server/libs/definition/src/modules/index.ts +1 -0
  357. package/templates/hono-server/libs/definition/tsconfig.json +5 -0
  358. package/templates/hono-server/libs/definition/vite.config.ts +15 -0
  359. package/templates/hono-server/oyo.config.json +13 -0
  360. package/templates/hono-server/package.json +25 -0
  361. package/templates/hono-server/pnpm-workspace.yaml +66 -0
  362. package/templates/hono-server/scripts/.env.example.docker +4 -0
  363. package/templates/hono-server/scripts/build-docker-server.sh +13 -0
  364. package/templates/hono-server/scripts/common.sh +20 -0
  365. package/templates/hono-server/tsconfig.json +4 -0
  366. package/templates/hono-server/turbo.json +36 -0
  367. package/templates/hono-server/vite.config.ts +14 -0
  368. package/templates/monorepo/.agents/skills/ask-matt/PHASE-BOUNDARIES.md +55 -0
  369. package/templates/monorepo/.agents/skills/ask-matt/SKILL.md +90 -0
  370. package/templates/monorepo/.agents/skills/ask-matt/agents/openai.yaml +5 -0
  371. package/templates/monorepo/.agents/skills/code-review/SKILL.md +87 -0
  372. package/templates/monorepo/.agents/skills/code-review/agents/openai.yaml +3 -0
  373. package/templates/monorepo/.agents/skills/codebase-design/DEEPENING.md +37 -0
  374. package/templates/monorepo/.agents/skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  375. package/templates/monorepo/.agents/skills/codebase-design/SKILL.md +114 -0
  376. package/templates/monorepo/.agents/skills/codebase-design/agents/openai.yaml +3 -0
  377. package/templates/monorepo/.agents/skills/confirm-requirements/SKILL.md +25 -0
  378. package/templates/monorepo/.agents/skills/diagnosing-bugs/SKILL.md +140 -0
  379. package/templates/monorepo/.agents/skills/diagnosing-bugs/agents/openai.yaml +3 -0
  380. package/templates/monorepo/.agents/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +44 -0
  381. package/templates/monorepo/.agents/skills/domain-modeling/ADR-FORMAT.md +47 -0
  382. package/templates/monorepo/.agents/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  383. package/templates/monorepo/.agents/skills/domain-modeling/SKILL.md +74 -0
  384. package/templates/monorepo/.agents/skills/domain-modeling/agents/openai.yaml +3 -0
  385. package/templates/monorepo/.agents/skills/grill-me/SKILL.md +7 -0
  386. package/templates/monorepo/.agents/skills/grill-me/agents/openai.yaml +5 -0
  387. package/templates/monorepo/.agents/skills/grilling/SKILL.md +22 -0
  388. package/templates/monorepo/.agents/skills/grilling/agents/openai.yaml +3 -0
  389. package/templates/monorepo/.agents/skills/implement/SKILL.md +15 -0
  390. package/templates/monorepo/.agents/skills/implement/agents/openai.yaml +5 -0
  391. package/templates/monorepo/.agents/skills/improve-codebase-architecture/HTML-REPORT.md +123 -0
  392. package/templates/monorepo/.agents/skills/improve-codebase-architecture/SKILL.md +71 -0
  393. package/templates/monorepo/.agents/skills/improve-codebase-architecture/agents/openai.yaml +5 -0
  394. package/templates/monorepo/.agents/skills/prototype/LOGIC.md +67 -0
  395. package/templates/monorepo/.agents/skills/prototype/SKILL.md +26 -0
  396. package/templates/monorepo/.agents/skills/prototype/UI.md +112 -0
  397. package/templates/monorepo/.agents/skills/prototype/agents/openai.yaml +3 -0
  398. package/templates/monorepo/.agents/skills/research/SKILL.md +12 -0
  399. package/templates/monorepo/.agents/skills/research/agents/openai.yaml +3 -0
  400. package/templates/monorepo/.agents/skills/resolving-merge-conflicts/SKILL.md +14 -0
  401. package/templates/monorepo/.agents/skills/resolving-merge-conflicts/agents/openai.yaml +3 -0
  402. package/templates/monorepo/.agents/skills/scoped-code-review/SKILL.md +113 -0
  403. package/templates/monorepo/.agents/skills/setup-matt-pocock-skills/SKILL.md +116 -0
  404. package/templates/monorepo/.agents/skills/setup-matt-pocock-skills/agents/openai.yaml +5 -0
  405. package/templates/monorepo/.agents/skills/setup-matt-pocock-skills/domain.md +51 -0
  406. package/templates/monorepo/.agents/skills/setup-matt-pocock-skills/issue-tracker-github.md +45 -0
  407. package/templates/monorepo/.agents/skills/setup-matt-pocock-skills/issue-tracker-gitlab.md +46 -0
  408. package/templates/monorepo/.agents/skills/setup-matt-pocock-skills/issue-tracker-local.md +30 -0
  409. package/templates/monorepo/.agents/skills/setup-matt-pocock-skills/triage-labels.md +15 -0
  410. package/templates/monorepo/.agents/skills/tdd/SKILL.md +38 -0
  411. package/templates/monorepo/.agents/skills/tdd/agents/openai.yaml +3 -0
  412. package/templates/monorepo/.agents/skills/tdd/mocking.md +59 -0
  413. package/templates/monorepo/.agents/skills/tdd/tests.md +77 -0
  414. package/templates/monorepo/.agents/skills/teach/GLOSSARY-FORMAT.md +35 -0
  415. package/templates/monorepo/.agents/skills/teach/LEARNING-RECORD-FORMAT.md +46 -0
  416. package/templates/monorepo/.agents/skills/teach/MISSION-FORMAT.md +31 -0
  417. package/templates/monorepo/.agents/skills/teach/RESOURCES-FORMAT.md +32 -0
  418. package/templates/monorepo/.agents/skills/teach/SKILL.md +140 -0
  419. package/templates/monorepo/.agents/skills/teach/agents/openai.yaml +5 -0
  420. package/templates/monorepo/.agents/skills/to-questionnaire/SKILL.md +53 -0
  421. package/templates/monorepo/.agents/skills/to-questionnaire/agents/openai.yaml +5 -0
  422. package/templates/monorepo/.agents/skills/triage/AGENT-BRIEF.md +207 -0
  423. package/templates/monorepo/.agents/skills/triage/OUT-OF-SCOPE.md +105 -0
  424. package/templates/monorepo/.agents/skills/triage/SKILL.md +112 -0
  425. package/templates/monorepo/.agents/skills/triage/agents/openai.yaml +5 -0
  426. package/templates/monorepo/.agents/skills/wait-what/SKILL.md +7 -0
  427. package/templates/monorepo/.agents/skills/wait-what/agents/openai.yaml +5 -0
  428. package/templates/monorepo/.agents/skills/wayfinder/SKILL.md +128 -0
  429. package/templates/monorepo/.agents/skills/wayfinder/agents/openai.yaml +5 -0
  430. package/templates/monorepo/.agents/skills/wizard/SKILL.md +44 -0
  431. package/templates/monorepo/.agents/skills/wizard/agents/openai.yaml +3 -0
  432. package/templates/monorepo/.agents/skills/wizard/template.sh +204 -0
  433. package/templates/monorepo/.agents/skills/writing-for-agents/SKILL-MECHANICS.md +22 -0
  434. package/templates/monorepo/.agents/skills/writing-for-agents/SKILL.md +81 -0
  435. package/templates/monorepo/.agents/skills/writing-for-agents/agents/openai.yaml +3 -0
  436. package/templates/monorepo/.vscode/extensions.json +5 -0
  437. package/templates/monorepo/.vscode/launch.json +0 -3
  438. package/templates/monorepo/.vscode/settings.json +3 -1
  439. package/templates/monorepo/AGENTS.md +50 -0
  440. package/templates/monorepo/README.md +27 -0
  441. package/templates/monorepo/_gitignore +5 -0
  442. package/templates/monorepo/docs/agents/domain.md +41 -0
  443. package/templates/monorepo/docs/agents/issue-tracker.md +30 -0
  444. package/templates/monorepo/docs/agents/triage-labels.md +15 -0
  445. package/templates/monorepo/package.json +4 -3
  446. package/templates/monorepo/pnpm-workspace.yaml +23 -26
  447. package/templates/monorepo/turbo.json +27 -3
  448. package/templates/monorepo/vite.config.ts +1 -0
@@ -0,0 +1,185 @@
1
+ import { type WorkerConfig } from '@repo/definition/backend'
2
+ import type {
3
+ AppWorkRunner,
4
+ RunnerTaskInvocation,
5
+ RunnerTaskParams,
6
+ RunnerTaskRunOptions,
7
+ RunnerTaskRunResult,
8
+ WorkerMessage,
9
+ } from '../types'
10
+ import { WorkerErrorCode, WorkSubject } from '../constants'
11
+ import { isWorkerTaskError, WorkerTaskError } from '../errors'
12
+ import Piscina from 'piscina'
13
+ import path from 'node:path'
14
+ import { MessageChannel, type MessagePort } from 'node:worker_threads'
15
+ import workersDir from 'virtual:workers'
16
+ import { getLogger } from '@/infra/logger/getter'
17
+ import type * as ExampleWorker from '../example/worker-entry'
18
+ import { handleWorkerMessage } from '../utils/message'
19
+
20
+ const taskNameMap = {
21
+ [WorkSubject.PROCESS_EXAMPLE]: 'executeExampleTask',
22
+ } satisfies Partial<Record<WorkSubject, keyof typeof ExampleWorker>>
23
+
24
+ export class PiscinaWorkRunner implements AppWorkRunner {
25
+ static #instance: PiscinaWorkRunner | null = null
26
+ readonly #pool: Piscina
27
+ readonly #config: WorkerConfig
28
+
29
+ private constructor(config: WorkerConfig) {
30
+ if (!config) {
31
+ throw new Error('[PiscinaWorkRunner] config is required')
32
+ }
33
+ this.#pool = new Piscina({
34
+ filename: path.join(workersDir, 'example-worker.mjs'),
35
+ minThreads: config.minThreads,
36
+ maxThreads: config.maxThreads,
37
+ concurrentTasksPerWorker: config.concurrentTasksPerWorker,
38
+ maxQueue: config.maxQueue,
39
+ })
40
+ this.#config = config
41
+ }
42
+
43
+ public static getInstance(config: WorkerConfig): PiscinaWorkRunner {
44
+ if (!this.#instance) {
45
+ getLogger().info({ worker: config }, 'PiscinaWorkRunner initialized')
46
+ this.#instance = new PiscinaWorkRunner(config)
47
+ }
48
+ return this.#instance
49
+ }
50
+
51
+ async run<TSubject extends WorkSubject>(
52
+ taskParams: RunnerTaskParams<TSubject>,
53
+ options?: RunnerTaskRunOptions,
54
+ ): Promise<RunnerTaskRunResult<TSubject>> {
55
+ const targetName = taskNameMap[taskParams.subject]
56
+ if (!targetName) {
57
+ throw new Error(`[PiscinaWorkRunner] task name not found: ${taskParams.subject}`)
58
+ }
59
+
60
+ let timeoutTimer: ReturnType<typeof setTimeout> | undefined
61
+ let result: RunnerTaskRunResult<TSubject>
62
+ let workerMessagePort: MessagePort | undefined
63
+
64
+ const { signal: optSignal, transferList } = options || {}
65
+ const logger = getLogger()
66
+ // pool当前状态
67
+ const poolStats = {
68
+ idleThreads: this.#pool.idleThreads,
69
+ threads: this.#pool.threads.length,
70
+ queueSize: this.#pool.queueSize,
71
+ }
72
+ logger.assign({
73
+ pool: poolStats,
74
+ subject: taskParams.subject,
75
+ })
76
+
77
+ try {
78
+ optSignal?.throwIfAborted()
79
+
80
+ // 判断队列已满
81
+ const enableQueue = this.#pool.options.maxQueue > 0
82
+ if (
83
+ (enableQueue && poolStats.queueSize >= this.#pool.options.maxQueue) ||
84
+ (!enableQueue && poolStats.idleThreads <= 0)
85
+ ) {
86
+ throw new WorkerTaskError(WorkerErrorCode.QUEUE_FULL, 'Worker queue is full', {
87
+ enableQueue,
88
+ queueSize: poolStats.queueSize,
89
+ maxQueue: this.#config.maxQueue,
90
+ })
91
+ }
92
+
93
+ logger.debug('Worker task dispatching')
94
+
95
+ // 建立收发端
96
+ const { port1: messagePort, port2 } = new MessageChannel()
97
+ workerMessagePort = port2
98
+ messagePort.on('message', (message: WorkerMessage) =>
99
+ handleWorkerMessage(message, logger, { subject: taskParams.subject }),
100
+ )
101
+ messagePort.unref()
102
+
103
+ // 设置任务信号和超时
104
+ let taskSignal = optSignal
105
+ let timeoutPromise: Promise<never> | undefined
106
+ if (this.#config.workerTaskTimeoutMs > 0) {
107
+ const timeoutController = new AbortController()
108
+ taskSignal = optSignal
109
+ ? AbortSignal.any([optSignal, timeoutController.signal])
110
+ : timeoutController.signal
111
+ timeoutPromise = new Promise<never>((_, reject) => {
112
+ timeoutTimer = setTimeout(() => {
113
+ const error = new WorkerTaskError(
114
+ WorkerErrorCode.TASK_TIMEOUT,
115
+ `Worker task timed out after ${this.#config.workerTaskTimeoutMs}ms`,
116
+ { timeoutMs: this.#config.workerTaskTimeoutMs },
117
+ )
118
+ reject(error)
119
+ timeoutController.abort(error)
120
+ }, this.#config.workerTaskTimeoutMs)
121
+ timeoutTimer.unref()
122
+ })
123
+ }
124
+
125
+ // 开始调用
126
+ const invocation: RunnerTaskInvocation<(typeof taskParams)['input']> = {
127
+ input: taskParams.input,
128
+ messagePort: workerMessagePort,
129
+ }
130
+ const taskPromise = this.#pool.run(invocation, {
131
+ name: targetName,
132
+ signal: taskSignal,
133
+ transferList: [...(transferList || []), workerMessagePort],
134
+ }) as Promise<RunnerTaskRunResult<TSubject>>
135
+
136
+ result = timeoutPromise
137
+ ? await Promise.race([taskPromise, timeoutPromise])
138
+ : await taskPromise
139
+ } catch (error) {
140
+ if (isWorkerTaskError(error)) {
141
+ result = {
142
+ ok: false,
143
+ error: error.serialize(),
144
+ }
145
+ } else if (error instanceof Error && error.name === 'AbortError') {
146
+ result = {
147
+ ok: false,
148
+ error: new WorkerTaskError(
149
+ WorkerErrorCode.TASK_ABORTED,
150
+ error.message,
151
+ undefined,
152
+ ).serialize(),
153
+ }
154
+ } else {
155
+ result = {
156
+ ok: false,
157
+ error: new WorkerTaskError(
158
+ WorkerErrorCode.UNKNOWN,
159
+ 'Worker task failed unexpectedly',
160
+ undefined,
161
+ error,
162
+ ).serialize(),
163
+ }
164
+ }
165
+ } finally {
166
+ if (timeoutTimer) clearTimeout(timeoutTimer)
167
+ try {
168
+ workerMessagePort?.close()
169
+ } catch {
170
+ // 忽略已 transfer/detached 端口的 close 异常
171
+ }
172
+ }
173
+
174
+ logger[result.ok ? 'info' : 'error'](
175
+ { subject: taskParams.subject, ok: result.ok },
176
+ `Worker task ${result.ok ? 'completed' : 'failed'}`,
177
+ )
178
+ return result
179
+ }
180
+
181
+ async shutdown(): Promise<void> {
182
+ await this.#pool.close()
183
+ if (PiscinaWorkRunner.#instance === this) PiscinaWorkRunner.#instance = null
184
+ }
185
+ }
@@ -0,0 +1,118 @@
1
+ import type { ExampleRunnerTaskModel } from '@/modules/example/work-task/tasks'
2
+ import type { Transferable } from 'node:worker_threads'
3
+ import type { WorkerErrorCode, WorkSubject } from './constants'
4
+
5
+ // export const WorkerInvocationType = Object.freeze({
6
+ // READY: 'READY',
7
+ // TASK: 'TASK',
8
+ // } as const)
9
+ // export type WorkerInvocationType = (typeof WorkerInvocationType)[keyof typeof WorkerInvocationType]
10
+
11
+ // export const WorkerSignalType = Object.freeze({
12
+ // STARTED: 'started',
13
+ // } as const)
14
+ // export type WorkerSignalType = (typeof WorkerSignalType)[keyof typeof WorkerSignalType]
15
+
16
+ export type DefineRunnerTaskModel<
17
+ TSubject extends WorkSubject,
18
+ TInput,
19
+ TOutput,
20
+ TTaskErrorCode extends string = string,
21
+ > = {
22
+ subject: TSubject
23
+ input: TInput
24
+ output: TOutput
25
+ errorCode: TTaskErrorCode | WorkerErrorCode
26
+ }
27
+
28
+ export type AnyRunnerTaskModel = ExampleRunnerTaskModel
29
+
30
+ export type GetRunnerTaskModel<TSubject extends WorkSubject> = Extract<
31
+ AnyRunnerTaskModel,
32
+ { subject: TSubject }
33
+ >
34
+
35
+ export type RunnerTaskParams<TSubject extends WorkSubject> = Pick<
36
+ GetRunnerTaskModel<TSubject>,
37
+ 'input' | 'subject'
38
+ >
39
+ export type RunnerTaskInput<TSubject extends WorkSubject> = GetRunnerTaskModel<TSubject>['input']
40
+ export type RunnerTaskOutput<TSubject extends WorkSubject> = GetRunnerTaskModel<TSubject>['output']
41
+ export type RunnerTaskErrorCode<TSubject extends WorkSubject> =
42
+ GetRunnerTaskModel<TSubject>['errorCode']
43
+
44
+ export type RunnerTaskInvocation<TInput> = {
45
+ input: TInput
46
+ messagePort: WorkerMessagePort
47
+ }
48
+
49
+ export type RunnerTaskJsonValue =
50
+ | string
51
+ | number
52
+ | boolean
53
+ | null
54
+ | readonly RunnerTaskJsonValue[]
55
+ | { readonly [key: string]: RunnerTaskJsonValue }
56
+
57
+ /** Worker 通信中的错误详情必须保持为可结构化克隆、可 JSON 序列化的普通数据。 */
58
+ export type RunnerTaskErrorDetails = Readonly<Record<string, RunnerTaskJsonValue>>
59
+
60
+ export type WorkerMessage =
61
+ | {
62
+ type: 'log'
63
+ level: 'debug' | 'info' | 'warn' | 'error'
64
+ message: string
65
+ data?: RunnerTaskErrorDetails
66
+ }
67
+ | {
68
+ type: 'progress'
69
+ value: number
70
+ message?: string
71
+ }
72
+ | {
73
+ type: 'result'
74
+ data: RunnerTaskJsonValue
75
+ }
76
+ | {
77
+ type: 'error'
78
+ error: RunnerTaskError
79
+ }
80
+
81
+ export interface WorkerMessagePort {
82
+ postMessage(message: WorkerMessage): void
83
+ close(): void
84
+ }
85
+
86
+ export type RunnerTaskError<TCode extends string = string> = {
87
+ code: TCode
88
+ /** 仅供服务端诊断,不应直接作为 HTTP 响应文案。 */
89
+ message: string
90
+ details?: RunnerTaskErrorDetails
91
+ cause?: unknown
92
+ }
93
+
94
+ export type RunnerTaskResult<TData, TCode extends string = string> =
95
+ | { ok: true; data: TData }
96
+ | { ok: false; error: RunnerTaskError<TCode> }
97
+
98
+ export type RunnerTaskRunResult<TSubject extends WorkSubject> = RunnerTaskResult<
99
+ RunnerTaskOutput<TSubject>,
100
+ RunnerTaskErrorCode<TSubject>
101
+ >
102
+
103
+ export type RunnerTaskRunOptions = {
104
+ signal?: AbortSignal
105
+ transferList?: Transferable[]
106
+ }
107
+
108
+ export interface AppWorkRunner {
109
+ run<TSubject extends WorkSubject>(
110
+ task: RunnerTaskParams<TSubject>,
111
+ options?: RunnerTaskRunOptions,
112
+ ): Promise<RunnerTaskRunResult<TSubject>>
113
+ shutdown(): Promise<void>
114
+ }
115
+
116
+ // 已识别的公共 Worker 错误 Code 由具体任务与业务错误 Code 组合:
117
+ // 队列满、任务超时、Worker 暂不可用等返回失败 DTO;
118
+ // 未识别的 Piscina 异常和程序缺陷仍保持 Promise rejection,不能在此兜底吞掉。
@@ -0,0 +1,19 @@
1
+ import { hasProp } from '@/shared/utils'
2
+ import type { RunnerTaskErrorDetails } from '../types'
3
+
4
+ export class WorkerTaskBusinessError extends Error {
5
+ readonly details?: RunnerTaskErrorDetails
6
+
7
+ constructor(message: string, details?: RunnerTaskErrorDetails, cause?: unknown) {
8
+ super(message, { cause })
9
+ this.name = 'WorkerTaskBusinessError'
10
+ this.details = details
11
+ }
12
+ }
13
+
14
+ export function isWorkerTaskBusinessError(error: unknown): error is WorkerTaskBusinessError {
15
+ return (
16
+ error instanceof WorkerTaskBusinessError ||
17
+ (error instanceof Error && hasProp(error, 'name') && error.name === 'WorkerTaskBusinessError')
18
+ )
19
+ }
@@ -0,0 +1,49 @@
1
+ import type { AppLogger } from '@/shared/app/types'
2
+ import type { RunnerTaskErrorDetails, WorkerMessage, WorkerMessagePort } from '../types'
3
+ import type { WorkSubject } from '../constants'
4
+
5
+ export function workerLog(
6
+ messagePort: WorkerMessagePort,
7
+ level: Extract<WorkerMessage, { type: 'log' }>['level'],
8
+ message: string,
9
+ data?: RunnerTaskErrorDetails,
10
+ ): void {
11
+ messagePort.postMessage({ type: 'log', level, message, data } satisfies WorkerMessage)
12
+ }
13
+
14
+ export function workerProgress(
15
+ messagePort: WorkerMessagePort,
16
+ value: number,
17
+ message?: string,
18
+ ): void {
19
+ messagePort.postMessage({ type: 'progress', value, message } satisfies WorkerMessage)
20
+ }
21
+
22
+ export function handleWorkerMessage(
23
+ message: WorkerMessage,
24
+ logger: AppLogger,
25
+ context: {
26
+ subject: WorkSubject
27
+ },
28
+ ): void {
29
+ switch (message.type) {
30
+ case 'log':
31
+ logger[message.level]({ subject: context.subject, worker: message.data }, message.message)
32
+ break
33
+ case 'progress':
34
+ logger.debug(
35
+ { subject: context.subject, progress: message.value },
36
+ message.message || 'Worker progress',
37
+ )
38
+ break
39
+ case 'result':
40
+ logger.debug({ subject: context.subject }, 'Worker result delivered')
41
+ break
42
+ case 'error':
43
+ logger.warn(
44
+ { subject: context.subject, workerError: message.error },
45
+ 'Worker error delivered',
46
+ )
47
+ break
48
+ }
49
+ }
@@ -0,0 +1,144 @@
1
+ import { isMarkedAsUntransferable } from 'node:worker_threads'
2
+
3
+ export interface TransferableResult<T> {
4
+ value: T
5
+ transferable?: ArrayBuffer
6
+ }
7
+
8
+ /**
9
+ * 排除不需要遍历其属性的原生系统对象(交由 V8 结构化克隆内部处理)
10
+ */
11
+ function isCloneableLeaf(value: unknown): boolean {
12
+ return (
13
+ value instanceof Date ||
14
+ value instanceof RegExp ||
15
+ value instanceof Error ||
16
+ (typeof URL !== 'undefined' && value instanceof URL)
17
+ )
18
+ }
19
+
20
+ /**
21
+ * 转换 ArrayBufferView
22
+ */
23
+ export function toTransferable<T extends ArrayBufferView>(view: T): TransferableResult<T> {
24
+ const buffer = view.buffer
25
+
26
+ // 1. SharedArrayBuffer 或已显式标记为不可转移的 Buffer,原样返回(由系统克隆)
27
+ if (!(buffer instanceof ArrayBuffer) || isMarkedAsUntransferable(buffer)) {
28
+ return { value: view }
29
+ }
30
+
31
+ // 2. 独占且干净的 Buffer:直接转移,零拷贝
32
+ if (view.byteOffset === 0 && view.byteLength === buffer.byteLength) {
33
+ return { value: view, transferable: buffer }
34
+ }
35
+
36
+ // 3. 处于切片/池化状态:切片降级,提取独立 ArrayBuffer
37
+ const newBuffer = buffer.slice(view.byteOffset, view.byteOffset + view.byteLength)
38
+
39
+ // 4. 重新包装 View,修复 Node.js Buffer 的构造函数废弃警告
40
+ let newView: T
41
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer(view)) {
42
+ newView = Buffer.from(newBuffer) as unknown as T
43
+ } else {
44
+ const Ctor = view.constructor as new (buf: ArrayBuffer) => T
45
+ newView = new Ctor(newBuffer)
46
+ }
47
+
48
+ return {
49
+ value: newView,
50
+ transferable: newBuffer,
51
+ }
52
+ }
53
+
54
+ /**
55
+ * 【主入口】:深层提取 Transferables
56
+ */
57
+ export function extractTransferables(input: any): {
58
+ input: any
59
+ transferList: ArrayBuffer[]
60
+ } {
61
+ const transferables = new Set<ArrayBuffer>()
62
+ const extracted = new WeakMap<object, unknown>()
63
+
64
+ function extract(value: any): any {
65
+ if (!value || typeof value !== 'object') return value
66
+
67
+ // 命中缓存(环状引用 / 重复对象)
68
+ const cached = extracted.get(value)
69
+ if (cached !== undefined) return cached
70
+
71
+ // 裸 ArrayBuffer
72
+ if (value instanceof ArrayBuffer) {
73
+ if (!isMarkedAsUntransferable(value)) {
74
+ transferables.add(value)
75
+ }
76
+ extracted.set(value, value)
77
+ return value
78
+ }
79
+
80
+ // ArrayBufferView (Buffer, TypedArray, DataView)
81
+ if (ArrayBuffer.isView(value)) {
82
+ const { value: transferableView, transferable } = toTransferable(value)
83
+ if (transferable) {
84
+ transferables.add(transferable)
85
+ }
86
+ extracted.set(value, transferableView)
87
+ return transferableView
88
+ }
89
+
90
+ // 遇到原生特殊对象,直接跳过深入遍历
91
+ if (isCloneableLeaf(value)) {
92
+ extracted.set(value, value)
93
+ return value
94
+ }
95
+
96
+ // 场景 4:普通数组
97
+ if (Array.isArray(value)) {
98
+ const array: unknown[] = []
99
+ extracted.set(value, array)
100
+ for (let i = 0; i < value.length; i++) {
101
+ array.push(extract(value[i]))
102
+ }
103
+ return array
104
+ }
105
+
106
+ // 场景 5:Map 和 Set
107
+ if (value instanceof Map) {
108
+ const map = new Map()
109
+ extracted.set(value, map)
110
+ for (const [k, v] of value) {
111
+ map.set(extract(k), extract(v))
112
+ }
113
+ return map
114
+ }
115
+ if (value instanceof Set) {
116
+ const set = new Set()
117
+ extracted.set(value, set)
118
+ for (const v of value) {
119
+ set.add(extract(v))
120
+ }
121
+ return set
122
+ }
123
+
124
+ // 场景 6:普通对象 & 自定义类实例(支持 Symbol 键)
125
+ const proto = Object.getPrototypeOf(value)
126
+ if (proto === null || proto === Object.prototype || (proto && proto.constructor !== Object)) {
127
+ const object: Record<string | symbol, unknown> = {}
128
+ extracted.set(value, object)
129
+
130
+ const keys = Reflect.ownKeys(value)
131
+ for (const key of keys) {
132
+ object[key] = extract(value[key as keyof typeof value])
133
+ }
134
+ return object
135
+ }
136
+
137
+ return value
138
+ }
139
+
140
+ return {
141
+ input: extract(input),
142
+ transferList: [...transferables],
143
+ }
144
+ }
@@ -0,0 +1,26 @@
1
+ import type { AppEnv } from '@/shared/app/types'
2
+ import { cors } from 'hono/cors'
3
+ import { createMiddleware } from 'hono/factory'
4
+
5
+ export const corsMiddleware = () => {
6
+ return createMiddleware<AppEnv>(async (c, next) => {
7
+ const corsConfig = c.get('appConfig')
8
+ const domains = corsConfig.middleware.cors.domains
9
+ const middleware = cors({
10
+ origin: (origin) => {
11
+ const isAllowedDomain = domains.some((domain) => {
12
+ try {
13
+ return domain === '*' || new URL(origin).host === domain
14
+ } catch {
15
+ return false
16
+ }
17
+ })
18
+ return isAllowedDomain ? origin : null
19
+ },
20
+ allowHeaders: ['Content-Type'],
21
+ allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
22
+ credentials: true,
23
+ })
24
+ return middleware(c, next)
25
+ })
26
+ }
@@ -0,0 +1,9 @@
1
+ import * as v from 'valibot'
2
+
3
+ export const processExampleInputSchema = v.object({
4
+ message: v.pipe(v.string(), v.minLength(1)),
5
+ })
6
+
7
+ export const createExampleInputSchema = v.object({
8
+ message: v.pipe(v.string(), v.trim(), v.minLength(1), v.maxLength(500)),
9
+ })
@@ -0,0 +1,73 @@
1
+ import { type Context, Hono } from 'hono'
2
+ import { describeRoute } from 'hono-openapi'
3
+ import * as v from 'valibot'
4
+ import { examples, vcExamples, type SqliteDBType } from '@repo/db/sqlite/schema'
5
+ import type { AppEnv } from '@/shared/app/types'
6
+ import { WorkSubject } from '@/infra/work-runner/constants'
7
+ import { E } from '@/shared/errors/defs'
8
+ import { jsonResponse, OpenApiTags } from '@/shared/network/openapi'
9
+ import { successJson } from '@/shared/network/utils'
10
+ import { generalValidator } from '@/shared/network/validator'
11
+ import { createExampleInputSchema, processExampleInputSchema } from './contracts'
12
+
13
+ const getDb = (context: Context<AppEnv>) => context.get('db') as SqliteDBType
14
+
15
+ export const exampleRoutes = new Hono<AppEnv>()
16
+ .get(
17
+ '/health',
18
+ describeRoute({
19
+ operationId: 'getHealth',
20
+ tags: [OpenApiTags.System],
21
+ summary: 'Health check',
22
+ responses: { 200: jsonResponse(v.object({ data: v.object({ status: v.string() }) })) },
23
+ }),
24
+ (c) => successJson(c, { status: 'ok' }),
25
+ )
26
+ .get(
27
+ '/examples',
28
+ describeRoute({
29
+ operationId: 'listExamples',
30
+ tags: [OpenApiTags.Example],
31
+ summary: 'List example rows',
32
+ responses: { 200: { description: 'Example rows' } },
33
+ }),
34
+ async (c) => successJson(c, await getDb(c).select(vcExamples.default).from(examples)),
35
+ )
36
+ .post(
37
+ '/examples',
38
+ describeRoute({
39
+ operationId: 'createExample',
40
+ tags: [OpenApiTags.Example],
41
+ summary: 'Create an example row',
42
+ responses: { 200: { description: 'Created example row' } },
43
+ }),
44
+ generalValidator('json', createExampleInputSchema),
45
+ async (c) => {
46
+ const input = c.req.valid('json')
47
+ const [row] = await getDb(c).insert(examples).values(input).returning(vcExamples.default)
48
+ return successJson(c, row)
49
+ },
50
+ )
51
+ .post(
52
+ '/examples/process',
53
+ describeRoute({
54
+ operationId: 'processExample',
55
+ tags: [OpenApiTags.Example],
56
+ summary: 'Process an example message in the worker pool',
57
+ responses: { 200: jsonResponse(v.object({ data: v.object({ normalized: v.string() }) })) },
58
+ }),
59
+ generalValidator('json', processExampleInputSchema),
60
+ async (c) => {
61
+ const result = await c.get('workRunner').run({
62
+ subject: WorkSubject.PROCESS_EXAMPLE,
63
+ input: c.req.valid('json'),
64
+ })
65
+ if (!result.ok) {
66
+ throw E.NORMAL.INTERNAL.create({
67
+ cause: result.error,
68
+ extensions: { workerCode: result.error.code },
69
+ })
70
+ }
71
+ return successJson(c, result.data)
72
+ },
73
+ )
@@ -0,0 +1,49 @@
1
+ import { MessageChannel } from 'node:worker_threads'
2
+ import { describe, expect, it } from 'vite-plus/test'
3
+ import { executeExampleTask } from './tasks'
4
+
5
+ describe('Example worker task', () => {
6
+ it('normalizes a message and reports progress', async () => {
7
+ const { port1, port2 } = new MessageChannel()
8
+ const messages: unknown[] = []
9
+ port1.on('message', (message) => messages.push(message))
10
+ const result = await executeExampleTask({ message: ' hello worker ' }, port2)
11
+ await new Promise<void>((resolve) => setImmediate(resolve))
12
+
13
+ expect(result).toEqual({
14
+ ok: true,
15
+ data: { original: ' hello worker ', normalized: 'hello worker', length: 12 },
16
+ })
17
+ expect(messages).toEqual(
18
+ expect.arrayContaining([
19
+ expect.objectContaining({ type: 'log' }),
20
+ expect.objectContaining({ type: 'progress', value: 100 }),
21
+ expect.objectContaining({ type: 'result' }),
22
+ ]),
23
+ )
24
+ port1.close()
25
+ port2.close()
26
+ })
27
+
28
+ it('serializes a business exception and reports it', async () => {
29
+ const { port1, port2 } = new MessageChannel()
30
+ const messages: unknown[] = []
31
+ port1.on('message', (message) => messages.push(message))
32
+ const result = await executeExampleTask({ message: ' ' }, port2)
33
+ await new Promise<void>((resolve) => setImmediate(resolve))
34
+
35
+ expect(result).toEqual({
36
+ ok: false,
37
+ error: {
38
+ code: 'EXAMPLE_PROCESS_FAILED',
39
+ message: 'Message must not be empty',
40
+ details: { field: 'message' },
41
+ },
42
+ })
43
+ expect(messages).toEqual(
44
+ expect.arrayContaining([expect.objectContaining({ type: 'error' })]),
45
+ )
46
+ port1.close()
47
+ port2.close()
48
+ })
49
+ })