create-workframe 0.1.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 (415) hide show
  1. package/.dockerignore +22 -0
  2. package/.gitignore +73 -0
  3. package/LICENSE +201 -0
  4. package/NOTICE +12 -0
  5. package/README.md +111 -0
  6. package/SECURITY.md +40 -0
  7. package/bin/create-workframe.js +2814 -0
  8. package/bin/workframe.js +329 -0
  9. package/docs/workspace-instructions/WORKFRAME_DISCORD.md +20 -0
  10. package/docs/workspace-instructions/WORKFRAME_DOCUMENTS_AND_ARTIFACTS.md +20 -0
  11. package/docs/workspace-instructions/WORKFRAME_KANBAN.md +20 -0
  12. package/docs/workspace-instructions/WORKFRAME_ONBOARDING.md +21 -0
  13. package/docs/workspace-instructions/WORKFRAME_ROUTING.md +29 -0
  14. package/docs/workspace-instructions/WORKFRAME_TELEGRAM.md +19 -0
  15. package/package.json +67 -0
  16. package/profiles/README.md +15 -0
  17. package/profiles/architect/AGENTS.md +29 -0
  18. package/profiles/architect/SOUL.md +44 -0
  19. package/profiles/architect/skills/devops/kanban-worker/SKILL.md +27 -0
  20. package/profiles/designer/AGENTS.md +26 -0
  21. package/profiles/designer/SOUL.md +31 -0
  22. package/profiles/designer/skills/devops/kanban-worker/SKILL.md +27 -0
  23. package/profiles/dev/AGENTS.md +28 -0
  24. package/profiles/dev/SOUL.md +31 -0
  25. package/profiles/dev/skills/devops/kanban-worker/SKILL.md +27 -0
  26. package/profiles/docs/AGENTS.md +27 -0
  27. package/profiles/docs/SOUL.md +30 -0
  28. package/profiles/docs/skills/devops/kanban-worker/SKILL.md +27 -0
  29. package/profiles/research/AGENTS.md +26 -0
  30. package/profiles/research/SOUL.md +31 -0
  31. package/profiles/research/skills/devops/kanban-worker/SKILL.md +27 -0
  32. package/profiles/visionary/AGENTS.md +25 -0
  33. package/profiles/visionary/SOUL.md +31 -0
  34. package/profiles/visionary/skills/devops/kanban-worker/SKILL.md +27 -0
  35. package/profiles/workframe-agent/AGENTS.md +37 -0
  36. package/profiles/workframe-agent/SETUP.md +185 -0
  37. package/profiles/workframe-agent/SOUL.md +61 -0
  38. package/profiles/workframe-agent/skills/devops/botfather/SKILL.md +85 -0
  39. package/profiles/workframe-agent/skills/devops/kanban-handoff-pattern/SKILL.md +58 -0
  40. package/profiles/workframe-agent/skills/devops/workframe-cohort/SKILL.md +54 -0
  41. package/prompts/WORKFRAME_PROMPT_TEMPLATES.md +16 -0
  42. package/rules/.hermes.md +11 -0
  43. package/rules/AGENTS.md +22 -0
  44. package/rules/workspace-README.md +5 -0
  45. package/scripts/apply-update-hermes.sh +17 -0
  46. package/scripts/apply-update-workframe.sh +77 -0
  47. package/scripts/bootstrap-workspace-link.sh +8 -0
  48. package/scripts/bundle-workframe-ui.mjs +77 -0
  49. package/scripts/compose-docker-host.sh +37 -0
  50. package/scripts/create_workframe_scaffold.py +648 -0
  51. package/scripts/ensure-compose-host-paths.mjs +51 -0
  52. package/scripts/fix-zk-encryption-key.sh +35 -0
  53. package/scripts/lib/install-identity.mjs +212 -0
  54. package/scripts/lib/workframe-registry.mjs +290 -0
  55. package/scripts/new-project.mjs +68 -0
  56. package/scripts/restart-gateway-hermes.sh +12 -0
  57. package/scripts/security_audit.py +156 -0
  58. package/scripts/select_agent_pack.py +31 -0
  59. package/scripts/set-compose-public-url.mjs +92 -0
  60. package/scripts/setup-stack-secrets.sh +50 -0
  61. package/scripts/sync-canonical-to-package.mjs +146 -0
  62. package/scripts/test-scaffold.mjs +390 -0
  63. package/scripts/verify-public-deploy.sh +105 -0
  64. package/shared/WORKFRAME_AGENT_LIBRARY.md +31 -0
  65. package/shared/WORKFRAME_AGENT_OPERATIONS.md +29 -0
  66. package/shared/WORKFRAME_AGENT_PACKS.json +64 -0
  67. package/shared/WORKFRAME_AGENT_PACKS.yaml +20 -0
  68. package/shared/WORKFRAME_CHAT_PERMISSION_MODEL.md +20 -0
  69. package/shared/WORKFRAME_HANDOFF_SCHEMA.md +25 -0
  70. package/shared/WORKFRAME_SKILL_CURATION.md +27 -0
  71. package/shared/agent-avatars/ada.png +0 -0
  72. package/shared/agent-avatars/aibert.png +0 -0
  73. package/shared/agent-avatars/amelia.png +0 -0
  74. package/shared/agent-avatars/andy.png +0 -0
  75. package/shared/agent-avatars/arc.png +0 -0
  76. package/shared/agent-avatars/bob.png +0 -0
  77. package/shared/agent-avatars/buzz.png +0 -0
  78. package/shared/agent-avatars/carl.png +0 -0
  79. package/shared/agent-avatars/catalog.json +171 -0
  80. package/shared/agent-avatars/corbu.png +0 -0
  81. package/shared/agent-avatars/diana.png +0 -0
  82. package/shared/agent-avatars/ella.png +0 -0
  83. package/shared/agent-avatars/elvis.png +0 -0
  84. package/shared/agent-avatars/f1.png +0 -0
  85. package/shared/agent-avatars/f2.png +0 -0
  86. package/shared/agent-avatars/f3.png +0 -0
  87. package/shared/agent-avatars/f4.png +0 -0
  88. package/shared/agent-avatars/f5.png +0 -0
  89. package/shared/agent-avatars/f6.png +0 -0
  90. package/shared/agent-avatars/frida.png +0 -0
  91. package/shared/agent-avatars/george.png +0 -0
  92. package/shared/agent-avatars/grace.png +0 -0
  93. package/shared/agent-avatars/hedy.png +0 -0
  94. package/shared/agent-avatars/hermes.png +0 -0
  95. package/shared/agent-avatars/isaac.png +0 -0
  96. package/shared/agent-avatars/jes.png +0 -0
  97. package/shared/agent-avatars/john.png +0 -0
  98. package/shared/agent-avatars/joni.png +0 -0
  99. package/shared/agent-avatars/leo.png +0 -0
  100. package/shared/agent-avatars/louis.png +0 -0
  101. package/shared/agent-avatars/ludwig.png +0 -0
  102. package/shared/agent-avatars/m1.png +0 -0
  103. package/shared/agent-avatars/m2.png +0 -0
  104. package/shared/agent-avatars/m3.png +0 -0
  105. package/shared/agent-avatars/m4.png +0 -0
  106. package/shared/agent-avatars/m5.png +0 -0
  107. package/shared/agent-avatars/m6.png +0 -0
  108. package/shared/agent-avatars/marie.png +0 -0
  109. package/shared/agent-avatars/marilyn.png +0 -0
  110. package/shared/agent-avatars/neil.png +0 -0
  111. package/shared/agent-avatars/nikola.png +0 -0
  112. package/shared/agent-avatars/nina.png +0 -0
  113. package/shared/agent-avatars/paul.png +0 -0
  114. package/shared/agent-avatars/ringo.png +0 -0
  115. package/shared/agent-avatars/rosie.png +0 -0
  116. package/shared/agent-avatars/ste.png +0 -0
  117. package/shared/agent-avatars/steve.png +0 -0
  118. package/shared/agent-avatars/sun.png +0 -0
  119. package/shared/agent-avatars/tom.png +0 -0
  120. package/shared/agent-avatars/warren.png +0 -0
  121. package/shared/agent-avatars/woz.png +0 -0
  122. package/shared/agent-avatars/zaha.png +0 -0
  123. package/workframe-api/Dockerfile +14 -0
  124. package/workframe-api/README.md +28 -0
  125. package/workframe-api/action_proxy.py +131 -0
  126. package/workframe-api/auth_rate_limit.py +49 -0
  127. package/workframe-api/catalog/avatar-catalog.json +171 -0
  128. package/workframe-api/catalog/logo-catalog.json +86 -0
  129. package/workframe-api/catalog/user-avatar-catalog.json +171 -0
  130. package/workframe-api/credential_vault.py +445 -0
  131. package/workframe-api/data/.gitkeep +0 -0
  132. package/workframe-api/data/avatar-catalog.json +41 -0
  133. package/workframe-api/data/logo-catalog.json +14 -0
  134. package/workframe-api/data/user-avatar-catalog.json +18 -0
  135. package/workframe-api/email_sender.py +220 -0
  136. package/workframe-api/google_auth.py +90 -0
  137. package/workframe-api/install_api.py +359 -0
  138. package/workframe-api/internal_proxy_auth.py +150 -0
  139. package/workframe-api/llm_proxy.py +277 -0
  140. package/workframe-api/oidc_jwt.py +108 -0
  141. package/workframe-api/package.json +13 -0
  142. package/workframe-api/platform_auth.py +194 -0
  143. package/workframe-api/profile_secret_policy.py +86 -0
  144. package/workframe-api/public/assets/index-DPXu_lGn.css +1 -0
  145. package/workframe-api/public/assets/index-DYnLrCZZ.js +9 -0
  146. package/workframe-api/public/assets/index-DglUqFB_.js +9 -0
  147. package/workframe-api/public/index.html +12 -0
  148. package/workframe-api/requirements.txt +2 -0
  149. package/workframe-api/server.py +19646 -0
  150. package/workframe-api/site_meta.py +271 -0
  151. package/workframe-api/stack_config.py +427 -0
  152. package/workframe-api/tests/__init__.py +0 -0
  153. package/workframe-api/tests/db_setup.py +13 -0
  154. package/workframe-api/tests/test_admin_updates_gated.py +30 -0
  155. package/workframe-api/tests/test_agent_dm_bootstrap.py +196 -0
  156. package/workframe-api/tests/test_agent_profile_sync.py +76 -0
  157. package/workframe-api/tests/test_auth_email.py +222 -0
  158. package/workframe-api/tests/test_auth_hole_fix_selfcheck.py +99 -0
  159. package/workframe-api/tests/test_auth_rate_limit.py +19 -0
  160. package/workframe-api/tests/test_avatar_resolve.py +77 -0
  161. package/workframe-api/tests/test_child_soul_template.py +71 -0
  162. package/workframe-api/tests/test_credential_canary.py +135 -0
  163. package/workframe-api/tests/test_credential_isolation.py +448 -0
  164. package/workframe-api/tests/test_credential_resolution.py +206 -0
  165. package/workframe-api/tests/test_device_oauth.py +108 -0
  166. package/workframe-api/tests/test_doctor_repair.py +103 -0
  167. package/workframe-api/tests/test_ensure_profile_api.py +77 -0
  168. package/workframe-api/tests/test_gateway_compose_security.py +136 -0
  169. package/workframe-api/tests/test_install_secure_host.py +39 -0
  170. package/workframe-api/tests/test_internal_proxy_auth.py +125 -0
  171. package/workframe-api/tests/test_invite_runtime_bootstrap.py +72 -0
  172. package/workframe-api/tests/test_kanban_delegation.py +185 -0
  173. package/workframe-api/tests/test_llm_proxy.py +155 -0
  174. package/workframe-api/tests/test_login_access_policy.py +183 -0
  175. package/workframe-api/tests/test_mvp_model_bootstrap.py +75 -0
  176. package/workframe-api/tests/test_onboarding_bootstrap.py +248 -0
  177. package/workframe-api/tests/test_platform_auth.py +47 -0
  178. package/workframe-api/tests/test_profile_config_path.py +56 -0
  179. package/workframe-api/tests/test_profile_config_yaml_repair.py +63 -0
  180. package/workframe-api/tests/test_profile_create.py +72 -0
  181. package/workframe-api/tests/test_profile_identity_overlay.py +61 -0
  182. package/workframe-api/tests/test_profile_install_health.py +45 -0
  183. package/workframe-api/tests/test_profile_secret_policy.py +57 -0
  184. package/workframe-api/tests/test_profile_workspace_cwd.py +34 -0
  185. package/workframe-api/tests/test_provider_bootstrap.py +75 -0
  186. package/workframe-api/tests/test_provider_connect.py +54 -0
  187. package/workframe-api/tests/test_room_crud.py +192 -0
  188. package/workframe-api/tests/test_room_tenancy.py +701 -0
  189. package/workframe-api/tests/test_runtime_identity_backfill.py +34 -0
  190. package/workframe-api/tests/test_site_meta.py +81 -0
  191. package/workframe-api/tests/test_soul_stub.py +42 -0
  192. package/workframe-api/tests/test_space_member_sync.py +99 -0
  193. package/workframe-api/tests/test_stripe_stack_config.py +37 -0
  194. package/workframe-api/tests/test_supervisor_lifecycle.py +52 -0
  195. package/workframe-api/tests/test_turn_credential_vault.py +125 -0
  196. package/workframe-api/tests/test_updates.py +176 -0
  197. package/workframe-api/tests/test_user_cohort.py +113 -0
  198. package/workframe-api/tests/test_vault_envelope.py +110 -0
  199. package/workframe-api/tests/test_workspace_members.py +183 -0
  200. package/workframe-api/tests/test_workspace_messaging_sync.py +125 -0
  201. package/workframe-api/tests/test_workspace_provider_list.py +57 -0
  202. package/workframe-api/time-bind-chat.py +99 -0
  203. package/workframe-api/turn_credentials.py +226 -0
  204. package/workframe-api/updates.py +417 -0
  205. package/workframe-api/vault_kek.py +159 -0
  206. package/workframe-api/zk_auth.py +633 -0
  207. package/workframe-supervisor/Dockerfile +11 -0
  208. package/workframe-supervisor/profile_secret_policy.py +76 -0
  209. package/workframe-supervisor/server.py +787 -0
  210. package/workframe-supervisor/tests/test_exec_guard.py +42 -0
  211. package/workframe-supervisor/tests/test_server_import.py +21 -0
  212. package/workframe-ui/docker/nginx.conf +85 -0
  213. package/workframe-ui/public/assets/1-DLJbBkOb.png +0 -0
  214. package/workframe-ui/public/assets/10-uwRwj5ce.png +0 -0
  215. package/workframe-ui/public/assets/11-5OuV9F_e.png +0 -0
  216. package/workframe-ui/public/assets/12-u_axjxW-.png +0 -0
  217. package/workframe-ui/public/assets/13-ldSvcMsH.png +0 -0
  218. package/workframe-ui/public/assets/14-xdcALEYD.png +0 -0
  219. package/workframe-ui/public/assets/15-aZ4snEFB.png +0 -0
  220. package/workframe-ui/public/assets/16-L_5-DttY.png +0 -0
  221. package/workframe-ui/public/assets/2-zOPZTppD.png +0 -0
  222. package/workframe-ui/public/assets/3-Dc3WoVu5.png +0 -0
  223. package/workframe-ui/public/assets/4-C50hk7_m.png +0 -0
  224. package/workframe-ui/public/assets/5-Eweetkq4.png +0 -0
  225. package/workframe-ui/public/assets/6-5sOXgfkw.png +0 -0
  226. package/workframe-ui/public/assets/7-BqRBCbiC.png +0 -0
  227. package/workframe-ui/public/assets/8-DEDKS94h.png +0 -0
  228. package/workframe-ui/public/assets/9-DNj34GW-.png +0 -0
  229. package/workframe-ui/public/assets/ada-DsvuOc9n.png +0 -0
  230. package/workframe-ui/public/assets/aibert-BCz8Lo8H.png +0 -0
  231. package/workframe-ui/public/assets/amelia-DUf3EBGu.png +0 -0
  232. package/workframe-ui/public/assets/andy-Cpymuhhx.png +0 -0
  233. package/workframe-ui/public/assets/arc-CBDYvkAF.js +1 -0
  234. package/workframe-ui/public/assets/architecture-7EHR7CIX-CtbQKTuT.js +1 -0
  235. package/workframe-ui/public/assets/architectureDiagram-3BPJPVTR-XnBRKeW0.js +36 -0
  236. package/workframe-ui/public/assets/array-BifhSqXX.js +1 -0
  237. package/workframe-ui/public/assets/avatars/ada.png +0 -0
  238. package/workframe-ui/public/assets/avatars/aibert.png +0 -0
  239. package/workframe-ui/public/assets/avatars/amelia.png +0 -0
  240. package/workframe-ui/public/assets/avatars/andy.png +0 -0
  241. package/workframe-ui/public/assets/avatars/bob.png +0 -0
  242. package/workframe-ui/public/assets/avatars/buzz.png +0 -0
  243. package/workframe-ui/public/assets/avatars/carl.png +0 -0
  244. package/workframe-ui/public/assets/avatars/catalog.json +171 -0
  245. package/workframe-ui/public/assets/avatars/corbu.png +0 -0
  246. package/workframe-ui/public/assets/avatars/diana.png +0 -0
  247. package/workframe-ui/public/assets/avatars/elvis.png +0 -0
  248. package/workframe-ui/public/assets/avatars/frida.png +0 -0
  249. package/workframe-ui/public/assets/avatars/george.png +0 -0
  250. package/workframe-ui/public/assets/avatars/grace.png +0 -0
  251. package/workframe-ui/public/assets/avatars/hedy.png +0 -0
  252. package/workframe-ui/public/assets/avatars/hermes.png +0 -0
  253. package/workframe-ui/public/assets/avatars/isaac.png +0 -0
  254. package/workframe-ui/public/assets/avatars/john.png +0 -0
  255. package/workframe-ui/public/assets/avatars/joni.png +0 -0
  256. package/workframe-ui/public/assets/avatars/leo.png +0 -0
  257. package/workframe-ui/public/assets/avatars/louis.png +0 -0
  258. package/workframe-ui/public/assets/avatars/ludwig.png +0 -0
  259. package/workframe-ui/public/assets/avatars/marie.png +0 -0
  260. package/workframe-ui/public/assets/avatars/marilyn.png +0 -0
  261. package/workframe-ui/public/assets/avatars/nikola.png +0 -0
  262. package/workframe-ui/public/assets/avatars/nina.png +0 -0
  263. package/workframe-ui/public/assets/avatars/paul.png +0 -0
  264. package/workframe-ui/public/assets/avatars/ringo.png +0 -0
  265. package/workframe-ui/public/assets/avatars/rosie.png +0 -0
  266. package/workframe-ui/public/assets/avatars/steve.png +0 -0
  267. package/workframe-ui/public/assets/avatars/sun.png +0 -0
  268. package/workframe-ui/public/assets/avatars/warren.png +0 -0
  269. package/workframe-ui/public/assets/avatars/woz.png +0 -0
  270. package/workframe-ui/public/assets/avatars/zaha.png +0 -0
  271. package/workframe-ui/public/assets/blockDiagram-GPEHLZMM-VYHUfVhd.js +132 -0
  272. package/workframe-ui/public/assets/bob-DRz-48Id.png +0 -0
  273. package/workframe-ui/public/assets/branding/banner.png +0 -0
  274. package/workframe-ui/public/assets/branding/og-default.png +0 -0
  275. package/workframe-ui/public/assets/branding/workframe'white.png +0 -0
  276. package/workframe-ui/public/assets/branding/workframe-1.png +0 -0
  277. package/workframe-ui/public/assets/branding/workframe-2.png +0 -0
  278. package/workframe-ui/public/assets/branding/workframe-3.png +0 -0
  279. package/workframe-ui/public/assets/branding/workframe-4.png +0 -0
  280. package/workframe-ui/public/assets/branding/workframe-5.png +0 -0
  281. package/workframe-ui/public/assets/branding/workframe-banner.png +0 -0
  282. package/workframe-ui/public/assets/branding/workframe-logo-horizontal-mini.png +0 -0
  283. package/workframe-ui/public/assets/branding/workframe-logo-horizontal-nano.png +0 -0
  284. package/workframe-ui/public/assets/branding/workframe-logo-horizontal.png +0 -0
  285. package/workframe-ui/public/assets/branding/workframe-logo-vertical-alt.png +0 -0
  286. package/workframe-ui/public/assets/branding/workframe-logo-vertical.png +0 -0
  287. package/workframe-ui/public/assets/branding/workframe.png +0 -0
  288. package/workframe-ui/public/assets/buzz-mC4PtMvC.png +0 -0
  289. package/workframe-ui/public/assets/c4Diagram-AAUBKEIU-BTjUcJpm.js +10 -0
  290. package/workframe-ui/public/assets/carl-CtE74db_.png +0 -0
  291. package/workframe-ui/public/assets/channel-Dy4Z4-jn.js +1 -0
  292. package/workframe-ui/public/assets/chunk-2J33WTMH-w7uu7R-b.js +1 -0
  293. package/workframe-ui/public/assets/chunk-3OPIFGDE-Cb9LtnDX.js +62 -0
  294. package/workframe-ui/public/assets/chunk-4BX2VUAB-DiQ-qCwH.js +1 -0
  295. package/workframe-ui/public/assets/chunk-55IACEB6-C-mLFr7z.js +1 -0
  296. package/workframe-ui/public/assets/chunk-5ZQYHXKU-DOesfiCI.js +2 -0
  297. package/workframe-ui/public/assets/chunk-727SXJPM-BJ3oBZuz.js +206 -0
  298. package/workframe-ui/public/assets/chunk-AQP2D5EJ-CCA6xpGs.js +231 -0
  299. package/workframe-ui/public/assets/chunk-BSJP7CBP-a0cMNFb2.js +1 -0
  300. package/workframe-ui/public/assets/chunk-CSCIHK7Q-kuqN8EIY.js +122 -0
  301. package/workframe-ui/public/assets/chunk-FMBD7UC4-DyPgYHCg.js +15 -0
  302. package/workframe-ui/public/assets/chunk-KSCS5N6A-CdUuvR0V.js +10 -0
  303. package/workframe-ui/public/assets/chunk-L5ZTLDWV-Dq9NoWmK.js +1 -0
  304. package/workframe-ui/public/assets/chunk-LZXEDZCA-p74rddlO.js +2 -0
  305. package/workframe-ui/public/assets/chunk-ND2GUHAM-DBD2u1Gz.js +1 -0
  306. package/workframe-ui/public/assets/chunk-NNHCCRGN-DlpIbxXb.js +159 -0
  307. package/workframe-ui/public/assets/chunk-NZK2D7GU-BeIeYFnd.js +1 -0
  308. package/workframe-ui/public/assets/chunk-O5CBEL6O-ClHc56ib.js +70 -0
  309. package/workframe-ui/public/assets/chunk-QZHKN3VN-CtBEchFK.js +1 -0
  310. package/workframe-ui/public/assets/chunk-WU5MYG2G-B9pBtriN.js +1 -0
  311. package/workframe-ui/public/assets/chunk-XPW4576I-EFr8R_1p.js +32 -0
  312. package/workframe-ui/public/assets/classDiagram-4FO5ZUOK-BMAEA8jI.js +1 -0
  313. package/workframe-ui/public/assets/classDiagram-v2-Q7XG4LA2-BMAEA8jI.js +1 -0
  314. package/workframe-ui/public/assets/corbu-KiaMXzXQ.png +0 -0
  315. package/workframe-ui/public/assets/cose-bilkent-S5V4N54A-C7aPBODd.js +1 -0
  316. package/workframe-ui/public/assets/cytoscape.esm-h6BdjjI9.js +321 -0
  317. package/workframe-ui/public/assets/dagre-BM42HDAG-BdU1Rv-H.js +4 -0
  318. package/workframe-ui/public/assets/dagre-Bx709z4p.js +1 -0
  319. package/workframe-ui/public/assets/defaultLocale-C8Fc0cco.js +1 -0
  320. package/workframe-ui/public/assets/diagram-2AECGRRQ-DWowSo85.js +43 -0
  321. package/workframe-ui/public/assets/diagram-5GNKFQAL-MnxBbceO.js +10 -0
  322. package/workframe-ui/public/assets/diagram-KO2AKTUF-DQaLRXFf.js +3 -0
  323. package/workframe-ui/public/assets/diagram-LMA3HP47-CQaBud9k.js +24 -0
  324. package/workframe-ui/public/assets/diagram-OG6HWLK6-D8bAXbY9.js +24 -0
  325. package/workframe-ui/public/assets/diana-DW0MsL38.png +0 -0
  326. package/workframe-ui/public/assets/dist-DGpTLHr_.js +1 -0
  327. package/workframe-ui/public/assets/elvis-LCFaZIcT.png +0 -0
  328. package/workframe-ui/public/assets/erDiagram-TEJ5UH35-1E-xSvBK.js +85 -0
  329. package/workframe-ui/public/assets/eventmodeling-FCH6USID-D75cstNT.js +1 -0
  330. package/workframe-ui/public/assets/flowDiagram-I6XJVG4X-CgOVD5hu.js +162 -0
  331. package/workframe-ui/public/assets/frida-CXFA0w3F.png +0 -0
  332. package/workframe-ui/public/assets/ganttDiagram-6RSMTGT7-JFYAIauo.js +292 -0
  333. package/workframe-ui/public/assets/george-DBSH2Sm2.png +0 -0
  334. package/workframe-ui/public/assets/gitGraph-WXDBUCRP-B9REenIl.js +1 -0
  335. package/workframe-ui/public/assets/gitGraphDiagram-PVQCEYII-BQ7NcMSn.js +106 -0
  336. package/workframe-ui/public/assets/grace-BhV0UPc0.png +0 -0
  337. package/workframe-ui/public/assets/graphlib-B8gBHxth.js +1 -0
  338. package/workframe-ui/public/assets/hedy-BR2IHift.png +0 -0
  339. package/workframe-ui/public/assets/hermes-CqCzcE0y.png +0 -0
  340. package/workframe-ui/public/assets/index-Dnw6vjqb.js +133 -0
  341. package/workframe-ui/public/assets/index-DpAGxump.css +1 -0
  342. package/workframe-ui/public/assets/info-J43DQDTF-CL6-eTjH.js +1 -0
  343. package/workframe-ui/public/assets/infoDiagram-5YYISTIA-LJTODW4W.js +2 -0
  344. package/workframe-ui/public/assets/init-D6jRqBbL.js +1 -0
  345. package/workframe-ui/public/assets/isaac-D1nhJAuv.png +0 -0
  346. package/workframe-ui/public/assets/ishikawaDiagram-YF4QCWOH-bchrQVuo.js +70 -0
  347. package/workframe-ui/public/assets/john-zSPWwNi4.png +0 -0
  348. package/workframe-ui/public/assets/joni-BFLoyfJP.png +0 -0
  349. package/workframe-ui/public/assets/journeyDiagram-JHISSGLW-DkrvYuxP.js +139 -0
  350. package/workframe-ui/public/assets/kanban-definition-UN3LZRKU-DFRbj0IG.js +89 -0
  351. package/workframe-ui/public/assets/katex-Vhh-h91d.js +257 -0
  352. package/workframe-ui/public/assets/leo-C_3IOL11.png +0 -0
  353. package/workframe-ui/public/assets/line-Vd48P7-O.js +1 -0
  354. package/workframe-ui/public/assets/linear-Ckizh2G7.js +1 -0
  355. package/workframe-ui/public/assets/louis-DEEECFSX.png +0 -0
  356. package/workframe-ui/public/assets/ludwig-_hoKhhyK.png +0 -0
  357. package/workframe-ui/public/assets/marie-DET6MsfO.png +0 -0
  358. package/workframe-ui/public/assets/marilyn-DTqwt8Yh.png +0 -0
  359. package/workframe-ui/public/assets/mermaid-parser.core-Bkimsnqj.js +4 -0
  360. package/workframe-ui/public/assets/mermaid.core-x0TvVuPo.js +9 -0
  361. package/workframe-ui/public/assets/mindmap-definition-RKZ34NQL-6ykAFPEz.js +96 -0
  362. package/workframe-ui/public/assets/nikola-B4PtHrJv.png +0 -0
  363. package/workframe-ui/public/assets/nina-BYbrOn0d.png +0 -0
  364. package/workframe-ui/public/assets/ordinal-hYBb2elL.js +1 -0
  365. package/workframe-ui/public/assets/packet-YPE3B663-Dw3xgMDt.js +1 -0
  366. package/workframe-ui/public/assets/path-BWPyau1x.js +1 -0
  367. package/workframe-ui/public/assets/paul-CGURYQIn.png +0 -0
  368. package/workframe-ui/public/assets/pie-LRSECV5Y-DATysawG.js +1 -0
  369. package/workframe-ui/public/assets/pieDiagram-4H26LBE5-SJKD1S0S.js +30 -0
  370. package/workframe-ui/public/assets/project-logos/1.png +0 -0
  371. package/workframe-ui/public/assets/project-logos/10.png +0 -0
  372. package/workframe-ui/public/assets/project-logos/11.png +0 -0
  373. package/workframe-ui/public/assets/project-logos/12.png +0 -0
  374. package/workframe-ui/public/assets/project-logos/13.png +0 -0
  375. package/workframe-ui/public/assets/project-logos/14.png +0 -0
  376. package/workframe-ui/public/assets/project-logos/15.png +0 -0
  377. package/workframe-ui/public/assets/project-logos/16.png +0 -0
  378. package/workframe-ui/public/assets/project-logos/2.png +0 -0
  379. package/workframe-ui/public/assets/project-logos/3.png +0 -0
  380. package/workframe-ui/public/assets/project-logos/4.png +0 -0
  381. package/workframe-ui/public/assets/project-logos/5.png +0 -0
  382. package/workframe-ui/public/assets/project-logos/6.png +0 -0
  383. package/workframe-ui/public/assets/project-logos/7.png +0 -0
  384. package/workframe-ui/public/assets/project-logos/8.png +0 -0
  385. package/workframe-ui/public/assets/project-logos/9.png +0 -0
  386. package/workframe-ui/public/assets/project-logos/catalog.json +86 -0
  387. package/workframe-ui/public/assets/quadrantDiagram-W4KKPZXB-BrYDZX8q.js +7 -0
  388. package/workframe-ui/public/assets/radar-GUYGQ44K-BmWYPCds.js +1 -0
  389. package/workframe-ui/public/assets/requirementDiagram-4Y6WPE33-DwL9Mc8e.js +84 -0
  390. package/workframe-ui/public/assets/ringo-WhfUNOyY.png +0 -0
  391. package/workframe-ui/public/assets/rosie-CAtcIf87.png +0 -0
  392. package/workframe-ui/public/assets/rough.esm-CSKSodPl.js +1 -0
  393. package/workframe-ui/public/assets/sankeyDiagram-5OEKKPKP-DYIFsL8h.js +40 -0
  394. package/workframe-ui/public/assets/sequenceDiagram-3UESZ5HK-0-FPkFk8.js +162 -0
  395. package/workframe-ui/public/assets/src-B_od6b6h.js +1 -0
  396. package/workframe-ui/public/assets/stateDiagram-AJRCARHV-BQCiBk6u.js +1 -0
  397. package/workframe-ui/public/assets/stateDiagram-v2-BHNVJYJU-B89jAMFF.js +1 -0
  398. package/workframe-ui/public/assets/steve-CgXXJ9EZ.png +0 -0
  399. package/workframe-ui/public/assets/sun-BLNAhoZd.png +0 -0
  400. package/workframe-ui/public/assets/timeline-definition-PNZ67QCA-DS3tFcXj.js +120 -0
  401. package/workframe-ui/public/assets/treeView-BLDUP644-DSyUCKLY.js +1 -0
  402. package/workframe-ui/public/assets/treemap-LRROVOQU-CEZaNh5Y.js +1 -0
  403. package/workframe-ui/public/assets/vennDiagram-CIIHVFJN-CD-Vc9NF.js +34 -0
  404. package/workframe-ui/public/assets/wardley-L42UT6IY-Drq5w1Mc.js +1 -0
  405. package/workframe-ui/public/assets/wardleyDiagram-YWT4CUSO-DouXDJoF.js +78 -0
  406. package/workframe-ui/public/assets/warren-DIH7UKMY.png +0 -0
  407. package/workframe-ui/public/assets/woz-D2yleG-V.png +0 -0
  408. package/workframe-ui/public/assets/xychartDiagram-2RQKCTM6-DDf_Lol5.js +7 -0
  409. package/workframe-ui/public/assets/zaha-wersOEq9.png +0 -0
  410. package/workframe-ui/public/favicon.ico +0 -0
  411. package/workframe-ui/public/favicon.svg +7 -0
  412. package/workframe-ui/public/icons.svg +24 -0
  413. package/workframe-ui/public/index.html +50 -0
  414. package/workframe-ui/public/manifest.webmanifest +18 -0
  415. package/workframe-ui/public/workframe-config.json +4 -0
@@ -0,0 +1,648 @@
1
+ #!/usr/bin/env python3
2
+ """DEV/CI helper — NOT the canonical installer.
3
+
4
+ Canonical scaffold: bin/create-workframe.js (npm / npx create-workframe).
5
+ This script exists for Python-only smoke tests and security audit workflows.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import argparse
11
+ import json
12
+ import re
13
+ import shutil
14
+ from datetime import datetime, timezone
15
+ from pathlib import Path
16
+
17
+ SCRIPT_DIR = Path(__file__).resolve().parent
18
+ PKG_ROOT = SCRIPT_DIR.parent
19
+ PACKS_JSON = PKG_ROOT / 'shared' / 'WORKFRAME_AGENT_PACKS.json'
20
+ WORKSPACE_DOCS = PKG_ROOT / 'docs' / 'workspace-instructions'
21
+
22
+ PROJECT_AGENT_SLOT = 'project-agent'
23
+ NATIVE_SOUL_TEMPLATE = 'workframe-agent'
24
+
25
+ PROFILE_DESCRIPTIONS = {
26
+ 'visionary': 'Clarifies product purpose, positioning, strategy, user value, and long-term alignment.',
27
+ 'architect': 'Defines system design, technical boundaries, implementation plans, and code-review standards.',
28
+ 'docs': 'Maintains AGENTS.md, .hermes.md, docs indexes, source-of-truth maps, and change summaries.',
29
+ 'dev': 'Builds and modifies project files, scripts, tests, and implementation artifacts.',
30
+ 'research': 'Performs technical research, market research, references, competitive analysis, and R&D notes.',
31
+ 'designer': 'Handles UI direction, design docs, visual assets, image prompts, brand direction, and layout feedback.',
32
+ }
33
+
34
+ SHARED_DOCS = ['WORKFRAME_AGENT_LIBRARY.md', 'WORKFRAME_HANDOFF_SCHEMA.md']
35
+
36
+ GITIGNORE = """# Runtime state: do not commit instance data
37
+ Agents/
38
+ **/Agents/
39
+ *.db
40
+ *.db-shm
41
+ *.db-wal
42
+ *.log
43
+ logs/
44
+ cache/
45
+ memories/
46
+ sessions/
47
+ kanban/
48
+ state/
49
+
50
+ # Bootstrap seed (optional cleanup after profile bootstrap)
51
+ scripts/seed/
52
+
53
+ # Secrets
54
+ .env
55
+ .env.local
56
+ .env.*.local
57
+ *.pem
58
+ *.key
59
+ *.p12
60
+ *.pfx
61
+ secrets/
62
+
63
+ # Build/tool noise
64
+ node_modules/
65
+ .venv/
66
+ __pycache__/
67
+ .pytest_cache/
68
+ .DS_Store
69
+ Thumbs.db
70
+ .vscode/
71
+ .idea/
72
+ """
73
+
74
+ DOCKERIGNORE = """.git
75
+ .gitignore
76
+ node_modules
77
+ .venv
78
+ __pycache__
79
+ .pytest_cache
80
+ *.pyc
81
+ *.pyo
82
+ *.db
83
+ *.db-shm
84
+ *.db-wal
85
+ *.log
86
+ .env
87
+ .env.*
88
+ Agents
89
+ cache
90
+ logs
91
+ memories
92
+ sessions
93
+ kanban
94
+ state
95
+ scripts/seed
96
+ """
97
+
98
+
99
+ def slugify(name: str) -> str:
100
+ slug = re.sub(r'[^a-z0-9]+', '-', name.lower()).strip('-')
101
+ return slug or 'workframe'
102
+
103
+
104
+ def native_profile_slug(project_name: str) -> str:
105
+ return f'{slugify(project_name)}-agent'
106
+
107
+
108
+ def native_agent_name(project_name: str) -> str:
109
+ return f'{project_name} Agent'
110
+
111
+
112
+ def render_context(project_name: str) -> dict[str, str]:
113
+ return {
114
+ 'projectName': project_name,
115
+ 'nativeProfileSlug': native_profile_slug(project_name),
116
+ 'nativeAgentName': native_agent_name(project_name),
117
+ }
118
+
119
+
120
+ def render_placeholders(text: str, ctx: dict[str, str] | str) -> str:
121
+ context = render_context(ctx) if isinstance(ctx, str) else ctx
122
+ out = text
123
+ for key, value in context.items():
124
+ out = out.replace(f'{{{key}}}', value)
125
+ return out
126
+
127
+
128
+ def resolve_pack_profiles(base_profiles: list[str], project_name: str) -> list[str]:
129
+ native = native_profile_slug(project_name)
130
+ seen: set[str] = set()
131
+ resolved: list[str] = []
132
+ for profile in base_profiles:
133
+ slug = native if profile == PROJECT_AGENT_SLOT else profile
134
+ if slug not in seen:
135
+ seen.add(slug)
136
+ resolved.append(slug)
137
+ return resolved
138
+
139
+
140
+ def profile_description(profile: str, project_name: str) -> str:
141
+ if profile == native_profile_slug(project_name):
142
+ return (
143
+ f'{native_agent_name(project_name)}: host, concierge, project manager, '
144
+ 'orchestrator, and Workframe admin.'
145
+ )
146
+ return PROFILE_DESCRIPTIONS.get(profile, f'{profile} specialist profile.')
147
+
148
+
149
+ def profile_soul_source(profile: str, project_name: str) -> Path:
150
+ template_dir = NATIVE_SOUL_TEMPLATE if profile == native_profile_slug(project_name) else profile
151
+ return PKG_ROOT / 'profiles' / template_dir / 'SOUL.md'
152
+
153
+
154
+ def docker_container_names(project_name: str) -> dict:
155
+ slug = slugify(project_name)
156
+ stack = slug
157
+ return {
158
+ 'slug': slug,
159
+ 'stack': stack,
160
+ 'image': 'nousresearch/hermes-agent:latest',
161
+ 'network': f'{stack}-net',
162
+ 'gateway': f'{stack}-gateway',
163
+ 'dashboard': f'{stack}-dashboard',
164
+ 'workframe_api': f'{stack}-workframe-api',
165
+ 'workframe': f'{stack}-workframe',
166
+ 'chat': f'{stack}-chat',
167
+ 'setup': f'{stack}-setup',
168
+ 'bootstrap_use': f'{stack}-bootstrap-use',
169
+ 'bootstrap_list': f'{stack}-bootstrap-list',
170
+ 'profile_dashboard': lambda profile: f'{stack}-dashboard-{profile}',
171
+ }
172
+
173
+
174
+ def hermes_service_volumes_block() -> str:
175
+ return """ volumes:
176
+ - ./Agents:/opt/data
177
+ - ./Files:/workspace
178
+ - ./scripts:/opt/install/scripts:ro"""
179
+
180
+
181
+ def profile_dashboard_service_yaml(profile: str, docker: dict, label_project: str, network: str) -> str:
182
+ profile_esc = profile.replace('"', '\\"')
183
+ return f"""
184
+ dashboard-{profile}:
185
+ image: {docker['image']}
186
+ container_name: {docker['profile_dashboard'](profile)}
187
+ restart: unless-stopped
188
+ command: ["hermes", "-p", "{profile_esc}", "dashboard", "--host", "0.0.0.0", "--insecure", "--tui"]
189
+ labels:
190
+ com.workframe.project: "{label_project}"
191
+ com.workframe.role: profile-dashboard
192
+ com.workframe.profile: "{profile_esc}"
193
+ expose:
194
+ - "9119"
195
+ {hermes_service_volumes_block()}
196
+ environment:
197
+ - GATEWAY_HEALTH_URL=http://gateway:8642
198
+ - HERMES_DASHBOARD_TUI=1
199
+ depends_on:
200
+ - gateway
201
+ networks:
202
+ - {network}"""
203
+
204
+
205
+ def docker_compose_yaml(project_name: str, docker: dict, native_profile: str, _pack_profiles: list[str]) -> str:
206
+ label_project = project_name.replace('\\', '\\\\').replace('"', '\\"')
207
+ profile_esc = native_profile.replace('"', '\\"')
208
+ dashboard_profiles = [native_profile]
209
+ profile_services = ''.join(
210
+ profile_dashboard_service_yaml(p, docker, label_project, docker['network']) for p in dashboard_profiles
211
+ )
212
+ profile_depends = ''.join(f'\n - dashboard-{p}' for p in pack_profiles)
213
+ volumes = hermes_service_volumes_block()
214
+ return f"""name: {docker['stack']}
215
+
216
+ services:
217
+ gateway:
218
+ image: {docker['image']}
219
+ container_name: {docker['gateway']}
220
+ restart: unless-stopped
221
+ command: ["hermes", "-p", "{profile_esc}", "gateway", "run"]
222
+ labels:
223
+ com.workframe.project: "{label_project}"
224
+ com.workframe.role: gateway
225
+ ports:
226
+ - "127.0.0.1:18642:8642"
227
+ {volumes}
228
+ networks:
229
+ - {docker['network']}
230
+
231
+ dashboard:
232
+ image: {docker['image']}
233
+ container_name: {docker['dashboard']}
234
+ restart: unless-stopped
235
+ command: dashboard --host 0.0.0.0 --insecure --tui
236
+ labels:
237
+ com.workframe.project: "{label_project}"
238
+ com.workframe.role: dashboard
239
+ ports:
240
+ - "127.0.0.1:19119:9119"
241
+ {volumes}
242
+ environment:
243
+ - GATEWAY_HEALTH_URL=http://gateway:8642
244
+ - HERMES_DASHBOARD_TUI=1
245
+ depends_on:
246
+ - gateway
247
+ networks:
248
+ - {docker['network']}
249
+ {profile_services}
250
+
251
+ networks:
252
+ {docker['network']}:
253
+ driver: bridge
254
+ """
255
+
256
+
257
+ def setup_sh() -> str:
258
+ return """#!/usr/bin/env bash
259
+ set -euo pipefail
260
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
261
+ cd "$ROOT"
262
+
263
+ mkdir -p Agents Files
264
+
265
+ echo "Pulling Hermes image..."
266
+ docker pull nousresearch/hermes-agent:latest
267
+
268
+ echo ""
269
+ echo "Run Hermes setup (interactive):"
270
+ echo " docker run --rm -it --entrypoint hermes \\\\"
271
+ echo " -v \\"\\$PWD/Agents:/opt/data\\" \\\\"
272
+ echo " -v \\"\\$PWD/Files:/workspace\\" \\\\"
273
+ echo " nousresearch/hermes-agent:latest setup"
274
+ echo ""
275
+ echo "Then bootstrap profiles:"
276
+ echo " ./scripts/bootstrap-profiles.sh"
277
+ echo ""
278
+ echo "Start gateway + dashboard:"
279
+ echo " docker compose up -d"
280
+ """
281
+
282
+
283
+ def setup_ps1() -> str:
284
+ return """$ErrorActionPreference = 'Stop'
285
+ $Root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
286
+ Set-Location $Root
287
+
288
+ New-Item -ItemType Directory -Force -Path Agents, Files | Out-Null
289
+
290
+ Write-Host 'Pulling Hermes image...'
291
+ docker pull nousresearch/hermes-agent:latest
292
+
293
+ Write-Host ''
294
+ Write-Host 'Run Hermes setup (interactive):'
295
+ Write-Host ' docker run --rm -it --entrypoint hermes `'
296
+ Write-Host ' -v "$PWD\\Agents:/opt/data" `'
297
+ Write-Host ' -v "$PWD\\Files:/workspace" `'
298
+ Write-Host ' nousresearch/hermes-agent:latest setup'
299
+ Write-Host ''
300
+ Write-Host 'Then bootstrap profiles:'
301
+ Write-Host ' .\\scripts\\bootstrap-profiles.ps1'
302
+ Write-Host ''
303
+ Write-Host 'Start gateway + dashboard:'
304
+ Write-Host ' docker compose up -d'
305
+ """
306
+
307
+
308
+ def bootstrap_profiles_sh(profiles: list[str], project_name: str, native_profile: str, docker: dict) -> str:
309
+ blocks = []
310
+ for p in profiles:
311
+ desc = profile_description(p, project_name).replace('"', '\\"')
312
+ create_name = f"{docker['stack']}-bootstrap-{p}"
313
+ show_name = f"{create_name}-show"
314
+ blocks.append(f"""echo "Creating profile: {p}"
315
+ docker run --rm --name "{create_name}" --entrypoint hermes \\
316
+ -v "$ROOT/Agents:/opt/data" \\
317
+ -v "$ROOT/Files:/workspace" \\
318
+ {docker['image']} profile create {p} --clone --description "{desc}" || true
319
+
320
+ if [ -f "$ROOT/scripts/seed/profiles/{p}/SOUL.md" ]; then
321
+ mkdir -p "$ROOT/Agents/profiles/{p}"
322
+ cp "$ROOT/scripts/seed/profiles/{p}/SOUL.md" "$ROOT/Agents/profiles/{p}/SOUL.md"
323
+ fi
324
+ """)
325
+ body = '\n'.join(blocks)
326
+ return f"""#!/usr/bin/env bash
327
+ set -euo pipefail
328
+ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
329
+ cd "$ROOT"
330
+
331
+ if [ ! -d "$ROOT/Agents" ]; then
332
+ echo "Agents/ missing. Run Hermes setup first."
333
+ exit 1
334
+ fi
335
+
336
+ {body}
337
+ echo "Setting default profile to {native_profile}..."
338
+ docker run --rm --name "{docker['bootstrap_use']}" --entrypoint hermes \\
339
+ -v "$ROOT/Agents:/opt/data" \\
340
+ -v "$ROOT/Files:/workspace" \\
341
+ {docker['image']} profile use {native_profile}
342
+
343
+ echo "Profile bootstrap complete."
344
+ docker run --rm --name "{docker['bootstrap_list']}" --entrypoint hermes \\
345
+ -v "$ROOT/Agents:/opt/data" \\
346
+ -v "$ROOT/Files:/workspace" \\
347
+ {docker['image']} profile list
348
+ """
349
+
350
+
351
+ def bootstrap_profiles_ps1(profiles: list[str], project_name: str, native_profile: str, docker: dict) -> str:
352
+ blocks = []
353
+ for p in profiles:
354
+ desc = profile_description(p, project_name).replace('"', '`"')
355
+ create_name = f"{docker['stack']}-bootstrap-{p}"
356
+ blocks.append(f"""Write-Host "Creating profile: {p}"
357
+ docker run --rm --name "{create_name}" --entrypoint hermes `
358
+ -v "$Root\\Agents:/opt/data" `
359
+ -v "$Root\\Files:/workspace" `
360
+ {docker['image']} profile create {p} --clone --description "{desc}" 2>$null
361
+
362
+ $seed = Join-Path $Root "scripts\\seed\\profiles\\{p}\\SOUL.md"
363
+ $destDir = Join-Path $Root "Agents\\profiles\\{p}"
364
+ if (Test-Path $seed) {{
365
+ New-Item -ItemType Directory -Force -Path $destDir | Out-Null
366
+ Copy-Item $seed (Join-Path $destDir "SOUL.md") -Force
367
+ }}
368
+ """)
369
+ body = '\n'.join(blocks)
370
+ return f"""$ErrorActionPreference = 'Stop'
371
+ $Root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
372
+ Set-Location $Root
373
+
374
+ if (-not (Test-Path "$Root\\Agents")) {{
375
+ throw "Agents/ missing. Run Hermes setup first."
376
+ }}
377
+
378
+ {body}
379
+ Write-Host "Setting default profile to {native_profile}..."
380
+ docker run --rm --name "{docker['bootstrap_use']}" --entrypoint hermes `
381
+ -v "$Root\\Agents:/opt/data" `
382
+ -v "$Root\\Files:/workspace" `
383
+ {docker['image']} profile use {native_profile}
384
+
385
+ Write-Host "Profile bootstrap complete."
386
+ docker run --rm --name "{docker['bootstrap_list']}" --entrypoint hermes `
387
+ -v "$Root\\Agents:/opt/data" `
388
+ -v "$Root\\Files:/workspace" `
389
+ {docker['image']} profile list
390
+ """
391
+
392
+
393
+ CI_WORKFLOW = """name: workframe-security
394
+
395
+ on:
396
+ push:
397
+ pull_request:
398
+
399
+ jobs:
400
+ security-and-scaffold:
401
+ runs-on: ubuntu-latest
402
+ steps:
403
+ - uses: actions/checkout@v4
404
+ - uses: actions/setup-python@v5
405
+ with:
406
+ python-version: '3.12'
407
+ - uses: actions/setup-node@v4
408
+ with:
409
+ node-version: '20'
410
+
411
+ - name: Run security audit
412
+ run: python3 scripts/security_audit.py
413
+ working-directory: packages/create-workframe
414
+
415
+ - name: Generate scaffold with Python
416
+ run: python3 scripts/create_workframe_scaffold.py CiDemo --pack core --output /tmp --force
417
+ working-directory: packages/create-workframe
418
+
419
+ - name: Generate scaffold with Node installer
420
+ run: node bin/create-workframe.js --name CiNodeDemo --pack core --out /tmp --ci --force
421
+ working-directory: packages/create-workframe
422
+
423
+ - name: Verify generated layout
424
+ run: |
425
+ test -f /tmp/CiDemo/Files/AGENTS.md
426
+ test -f /tmp/CiDemo/docker-compose.yml
427
+ test -f /tmp/CiNodeDemo/Files/docs/SETUP.md
428
+ test -f /tmp/CiNodeDemo/scripts/bootstrap-profiles.sh
429
+ """
430
+
431
+
432
+ def load_packs(path: Path) -> dict:
433
+ data = json.loads(path.read_text())
434
+ packs = data.get('packs', {})
435
+ if not packs:
436
+ raise SystemExit(f'No packs found in {path}')
437
+ return packs
438
+
439
+
440
+ def copy_tree(src: Path, dst: Path) -> None:
441
+ if not src.exists():
442
+ return
443
+ for p in src.rglob('*'):
444
+ if p.is_file():
445
+ rel = p.relative_to(src)
446
+ out = dst / rel
447
+ out.parent.mkdir(parents=True, exist_ok=True)
448
+ shutil.copy2(p, out)
449
+
450
+
451
+ def make_setup_doc(project_name: str, pack: str, profiles: list[str], telegram: bool, discord: bool) -> str:
452
+ tg = 'Enabled in plan (optional integration chosen).' if telegram else 'Skipped (can enable later).'
453
+ dc = 'Enabled in plan (optional integration chosen).' if discord else 'Skipped (can enable later).'
454
+ return (
455
+ f"# {project_name} setup\n\n"
456
+ "## 1) Hermes base\n"
457
+ "- Run `./scripts/setup.sh` or `./scripts/setup.ps1`\n"
458
+ "- Then Hermes setup (interactive):\n"
459
+ "```bash\n"
460
+ "docker run --rm -it --entrypoint hermes \\\n"
461
+ ' -v "${PWD}/Agents:/opt/data" \\\n'
462
+ ' -v "${PWD}/Files:/workspace" \\\n'
463
+ " nousresearch/hermes-agent:latest setup\n"
464
+ "```\n\n"
465
+ "## 2) Bootstrap agent profiles\n"
466
+ "- `./scripts/bootstrap-profiles.sh` or `./scripts/bootstrap-profiles.ps1`\n\n"
467
+ "## 3) API/model keys\n"
468
+ "- `hermes auth add <provider>` at runtime\n\n"
469
+ "## 4) Start gateway + dashboard\n"
470
+ "- `docker compose up -d`\n\n"
471
+ "## 5) Chat integrations (optional)\n"
472
+ f"- Telegram: {tg}\n"
473
+ f"- Discord: {dc}\n\n"
474
+ "## 6) Agent pack\n"
475
+ f"- Pack: **{pack}**\n"
476
+ f"- Profiles: {', '.join(profiles)}\n"
477
+ )
478
+
479
+
480
+ def docs_index() -> str:
481
+ return (
482
+ "# Docs Index\n\n"
483
+ "- SETUP.md — first-run onboarding\n"
484
+ "- WORKFRAME_ONBOARDING.md — concierge loop\n"
485
+ "- WORKFRAME_ROUTING.md — lane routing\n"
486
+ "- WORKFRAME_KANBAN.md — execution + handoffs\n"
487
+ "- WORKFRAME_DOCUMENTS_AND_ARTIFACTS.md — file conventions\n"
488
+ "- WORKFRAME_TELEGRAM.md — optional Telegram\n"
489
+ "- WORKFRAME_DISCORD.md — optional Discord\n"
490
+ "- WORKFRAME_AGENT_LIBRARY.md — crew model\n"
491
+ "- WORKFRAME_HANDOFF_SCHEMA.md — task handoff fields\n"
492
+ )
493
+
494
+
495
+ def generate(
496
+ project_name: str,
497
+ pack: str,
498
+ output_root: Path,
499
+ force: bool,
500
+ telegram: bool,
501
+ discord: bool,
502
+ ) -> Path:
503
+ packs = load_packs(PACKS_JSON)
504
+ if pack not in packs:
505
+ raise SystemExit(f"Unknown pack '{pack}'. Available: {', '.join(sorted(packs.keys()))}")
506
+
507
+ profiles = resolve_pack_profiles(packs[pack]['profiles'], project_name)
508
+ native_slug = native_profile_slug(project_name)
509
+ native_name = native_agent_name(project_name)
510
+ ctx = render_context(project_name)
511
+ docker = docker_container_names(project_name)
512
+ target = output_root / project_name
513
+ files_root = target / 'Files'
514
+ slug = slugify(project_name)
515
+
516
+ if target.exists():
517
+ if not force:
518
+ raise SystemExit(f'Target exists: {target}. Use --force to overwrite.')
519
+ shutil.rmtree(target)
520
+
521
+ target.mkdir(parents=True, exist_ok=True)
522
+ (target / 'Agents').mkdir(parents=True, exist_ok=True)
523
+ files_root.mkdir(parents=True, exist_ok=True)
524
+ (files_root / 'artifacts').mkdir(parents=True, exist_ok=True)
525
+ (files_root / 'docs').mkdir(parents=True, exist_ok=True)
526
+ (files_root / 'prompts').mkdir(parents=True, exist_ok=True)
527
+ (target / 'Agents' / '.gitkeep').write_text('')
528
+ (files_root / '.gitkeep').write_text('')
529
+
530
+ rules_agents = PKG_ROOT / 'rules' / 'AGENTS.md'
531
+ rules_hermes = PKG_ROOT / 'rules' / '.hermes.md'
532
+ (files_root / 'AGENTS.md').write_text(render_placeholders(rules_agents.read_text(), ctx))
533
+ (files_root / '.hermes.md').write_text(render_placeholders(rules_hermes.read_text(), ctx))
534
+ (files_root / 'README.md').write_text(
535
+ f"# {project_name}\n\nProject workspace (`/workspace` in Hermes).\n\nStart: `docs/SETUP.md`\n"
536
+ )
537
+
538
+ copy_tree(WORKSPACE_DOCS, files_root / 'docs')
539
+ (files_root / 'docs' / 'SETUP.md').write_text(make_setup_doc(project_name, pack, profiles, telegram, discord))
540
+ (files_root / 'docs' / 'INDEX.md').write_text(docs_index())
541
+
542
+ for doc in SHARED_DOCS:
543
+ src = PKG_ROOT / 'shared' / doc
544
+ if src.exists():
545
+ (files_root / 'docs' / doc).write_text(render_placeholders(src.read_text(), ctx))
546
+
547
+ copy_tree(PKG_ROOT / 'prompts', files_root / 'prompts')
548
+
549
+ for prof in profiles:
550
+ src = profile_soul_source(prof, project_name)
551
+ if not src.exists():
552
+ raise SystemExit(f'Missing profile template: {src}')
553
+ seed = target / 'scripts' / 'seed' / 'profiles' / prof / 'SOUL.md'
554
+ seed.parent.mkdir(parents=True, exist_ok=True)
555
+ seed.write_text(render_placeholders(src.read_text(), ctx))
556
+
557
+ (target / '.gitignore').write_text(GITIGNORE)
558
+ (target / '.dockerignore').write_text(DOCKERIGNORE)
559
+ (target / '.env.example').write_text(
560
+ '# Do not commit .env\n# Add provider creds at runtime via hermes auth add <provider>\n'
561
+ )
562
+ (target / 'docker-compose.yml').write_text(docker_compose_yaml(project_name, docker, native_slug, [native_slug]))
563
+ (target / 'README.md').write_text(
564
+ f"# {project_name}\n\nGenerated by create-workframe.\n\n"
565
+ "Quick start: see `Files/docs/SETUP.md`\n"
566
+ )
567
+
568
+ scripts = target / 'scripts'
569
+ scripts.mkdir(parents=True, exist_ok=True)
570
+ (scripts / 'setup.sh').write_text(setup_sh())
571
+ (scripts / 'setup.sh').chmod(0o755)
572
+ (scripts / 'setup.ps1').write_text(setup_ps1())
573
+ (scripts / 'bootstrap-profiles.sh').write_text(bootstrap_profiles_sh(profiles, project_name, native_slug, docker))
574
+ (scripts / 'bootstrap-profiles.sh').chmod(0o755)
575
+ (scripts / 'bootstrap-profiles.ps1').write_text(bootstrap_profiles_ps1(profiles, project_name, native_slug, docker))
576
+
577
+ wf = target / '.github' / 'workflows'
578
+ wf.mkdir(parents=True, exist_ok=True)
579
+ (wf / 'workframe-security.yml').write_text(CI_WORKFLOW)
580
+
581
+ manifest = {
582
+ 'generator': 'workframe/scripts/create_workframe_scaffold.py',
583
+ 'generated_at_utc': datetime.now(timezone.utc).isoformat(),
584
+ 'project_name': project_name,
585
+ 'project_slug': slug,
586
+ 'pack': pack,
587
+ 'profiles': profiles,
588
+ 'native_agent': {
589
+ 'display_name': native_name,
590
+ 'profile_slug': native_slug,
591
+ },
592
+ 'docker': {
593
+ 'image': docker['image'],
594
+ 'stack': docker['stack'],
595
+ 'network': docker['network'],
596
+ 'containers': {
597
+ 'gateway': docker['gateway'],
598
+ 'dashboard': docker['dashboard'],
599
+ 'chat': docker['chat'],
600
+ 'setup': docker['setup'],
601
+ },
602
+ },
603
+ 'integrations': {'telegram': telegram, 'discord': discord},
604
+ 'layout': {'workspace': 'Files', 'runtime': 'Agents'},
605
+ 'security': {
606
+ 'no_instance_data_in_template': True,
607
+ 'runtime_state_directory': 'Agents',
608
+ },
609
+ }
610
+ (target / 'workframe-manifest.json').write_text(json.dumps(manifest, indent=2) + '\n')
611
+ return target
612
+
613
+
614
+ def main() -> None:
615
+ ap = argparse.ArgumentParser(description='Generate minimal project workspace from Workframe package')
616
+ ap.add_argument('project_name', nargs='?', help='Project folder name to generate')
617
+ ap.add_argument('--pack', default='vanilla', help='Starter pack: vanilla/core/product/engineering/full')
618
+ ap.add_argument('--output', default='/workspace/generated', help='Output root directory')
619
+ ap.add_argument('--force', action='store_true', help='Overwrite target if exists')
620
+ ap.add_argument('--ci', action='store_true', help='Non-interactive strict mode')
621
+ ap.add_argument('--telegram', action='store_true', help='Include Telegram onboarding steps')
622
+ ap.add_argument('--discord', action='store_true', help='Include Discord onboarding steps')
623
+ ap.add_argument('--list-packs', action='store_true', help='List available packs')
624
+ args = ap.parse_args()
625
+
626
+ packs = load_packs(PACKS_JSON)
627
+
628
+ if args.list_packs:
629
+ for name, info in packs.items():
630
+ print(f"{name}: {info.get('description', '')}")
631
+ return
632
+
633
+ if not args.project_name:
634
+ raise SystemExit('project_name is required unless --list-packs is used')
635
+
636
+ target = generate(
637
+ args.project_name,
638
+ args.pack,
639
+ Path(args.output),
640
+ args.force,
641
+ args.telegram,
642
+ args.discord,
643
+ )
644
+ print(target)
645
+
646
+
647
+ if __name__ == '__main__':
648
+ main()
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Ensure WORKFRAME_HOST_* paths exist in compose .env (VPS in-app publish/sync).
4
+ * Usage: node ensure-compose-host-paths.mjs --project-root /opt/workframe/ProjectX [--env path]
5
+ */
6
+ import fs from 'node:fs';
7
+ import path from 'node:path';
8
+
9
+ const args = process.argv.slice(2);
10
+ const rootFlag = args.indexOf('--project-root');
11
+ const envFlag = args.indexOf('--env');
12
+ const projectRoot =
13
+ rootFlag >= 0 ? args[rootFlag + 1] : '/opt/workframe/ProjectX';
14
+ const envPath =
15
+ envFlag >= 0
16
+ ? args[envFlag + 1]
17
+ : path.join(projectRoot, 'infra/compose/workframe/.env');
18
+ const composeDir = path.join(projectRoot, 'infra/compose/workframe');
19
+
20
+ function setIfEmpty(text, key, val) {
21
+ const esc = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
22
+ const re = new RegExp(`^${esc}=(.*)$`, 'm');
23
+ const m = text.match(re);
24
+ if (m && String(m[1] || '').trim()) return text;
25
+ const line = `${key}=${val}`;
26
+ if (m) return text.replace(re, line);
27
+ return `${text}${text.endsWith('\n') || !text ? '' : '\n'}${line}\n`;
28
+ }
29
+
30
+ if (!fs.existsSync(envPath)) {
31
+ console.error(`Missing env file: ${envPath}`);
32
+ process.exit(1);
33
+ }
34
+
35
+ let text = fs.readFileSync(envPath, 'utf8');
36
+ text = setIfEmpty(text, 'WORKFRAME_HOST_PROJECT_ROOT', projectRoot.replace(/\\/g, '/'));
37
+ text = setIfEmpty(text, 'WORKFRAME_HOST_COMPOSE_DIR', composeDir.replace(/\\/g, '/'));
38
+ fs.writeFileSync(envPath, text);
39
+
40
+ console.log(
41
+ JSON.stringify(
42
+ {
43
+ ok: true,
44
+ env: envPath,
45
+ project_root: projectRoot.replace(/\\/g, '/'),
46
+ compose_dir: composeDir.replace(/\\/g, '/'),
47
+ },
48
+ null,
49
+ 2,
50
+ ),
51
+ );