@webship.co/workspace 1.0.0-beta1 → 1.0.0-beta2

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 (630) hide show
  1. package/LICENSE +339 -0
  2. package/README.md +28 -364
  3. package/core/bin/workspace.js +135 -0
  4. package/core/config/settings.labels.yml +514 -0
  5. package/core/config/settings.template.yml +292 -0
  6. package/core/config/style.yml +53 -0
  7. package/core/config/theme.default.yml +161 -0
  8. package/core/config/theme.dispatch.yml +166 -0
  9. package/core/config/theme.drupal.yml +175 -0
  10. package/core/config/theme.ember.yml +160 -0
  11. package/core/config/theme.github.yml +172 -0
  12. package/core/config/theme.gitlab.yml +168 -0
  13. package/core/config/theme.press.yml +161 -0
  14. package/core/config/theme.slate.yml +160 -0
  15. package/core/config/theme.upsun.yml +174 -0
  16. package/core/docs/architecture.svg +65 -0
  17. package/core/docs/getting-started.md +51 -0
  18. package/core/docs/plugins.md +27 -0
  19. package/core/docs/releases.md +23 -0
  20. package/core/docs/testing.md +15 -0
  21. package/core/docs/workspaces.md +25 -0
  22. package/core/scripts/args/arg-ai-items.sh +65 -0
  23. package/core/scripts/args/arg-autostart.sh +31 -0
  24. package/core/scripts/args/arg-avatar-agent.sh +28 -0
  25. package/core/scripts/args/arg-avatar-catalog.sh +12 -0
  26. package/core/scripts/args/arg-avatar-character.sh +68 -0
  27. package/core/scripts/args/arg-avatar-voice.sh +24 -0
  28. package/core/scripts/args/arg-avatar.sh +22 -0
  29. package/core/scripts/args/arg-checks.sh +36 -0
  30. package/core/scripts/args/arg-clone.sh +42 -0
  31. package/core/scripts/args/arg-commands.sh +51 -0
  32. package/core/scripts/args/arg-cucumber.sh +34 -0
  33. package/core/scripts/args/arg-distribution.sh +30 -0
  34. package/core/scripts/args/arg-drupal.sh +39 -0
  35. package/core/scripts/args/arg-drupal_cms.sh +18 -0
  36. package/core/scripts/args/arg-gitlab-ci-local.sh +25 -0
  37. package/core/scripts/args/arg-graphify.sh +36 -0
  38. package/core/scripts/args/arg-graphs.sh +12 -0
  39. package/core/scripts/args/arg-hostnames.sh +23 -0
  40. package/core/scripts/args/arg-milvus-backup.sh +8 -0
  41. package/core/scripts/args/arg-milvus-mcp.sh +12 -0
  42. package/core/scripts/args/arg-milvus.sh +32 -0
  43. package/core/scripts/args/arg-obsidian.sh +17 -0
  44. package/core/scripts/args/arg-odoo.sh +18 -0
  45. package/core/scripts/args/arg-penpot-backup.sh +8 -0
  46. package/core/scripts/args/arg-penpot-mcp.sh +15 -0
  47. package/core/scripts/args/arg-penpot-token.sh +17 -0
  48. package/core/scripts/args/arg-penpot.sh +44 -0
  49. package/core/scripts/args/arg-rag.sh +21 -0
  50. package/core/scripts/args/arg-ragify.sh +35 -0
  51. package/core/scripts/args/arg-reclaim.sh +18 -0
  52. package/core/scripts/args/arg-release.sh +21 -0
  53. package/core/scripts/args/arg-screen.sh +28 -0
  54. package/core/scripts/args/arg-site-template.sh +13 -0
  55. package/core/scripts/args/arg-spdd.sh +16 -0
  56. package/core/scripts/args/arg-specs.sh +22 -0
  57. package/core/scripts/args/arg-storage.sh +36 -0
  58. package/core/scripts/args/arg-testing.sh +36 -0
  59. package/core/scripts/args/arg-webship.sh +34 -0
  60. package/core/scripts/args/arg-webships-project.sh +22 -0
  61. package/core/scripts/args/arg-webships-site-template.sh +17 -0
  62. package/core/scripts/args/arg-webships.sh +34 -0
  63. package/core/scripts/args/arg-website-site-template.sh +17 -0
  64. package/core/scripts/args/arg-website.sh +25 -0
  65. package/core/scripts/args/arg-wordpress.sh +18 -0
  66. package/core/scripts/autostart-run.sh +162 -0
  67. package/core/scripts/autostart-stop.sh +30 -0
  68. package/core/scripts/autostart-watch.sh +43 -0
  69. package/core/scripts/autostart.sh +26 -0
  70. package/core/scripts/bootstrap-functions.sh +117 -0
  71. package/core/scripts/bootstrap-libraries.sh +10 -0
  72. package/core/scripts/bootstrap.sh +71 -0
  73. package/core/scripts/ddev-shim/ddev +122 -0
  74. package/core/scripts/docker-gid.sh +119 -0
  75. package/core/scripts/functions/arg-site-template.sh +28 -0
  76. package/core/scripts/functions/fun-ai-items-lock.sh +175 -0
  77. package/core/scripts/functions/fun-ai-items-sources.sh +298 -0
  78. package/core/scripts/functions/fun-ai-items.sh +621 -0
  79. package/core/scripts/functions/fun-ai-providers.sh +72 -0
  80. package/core/scripts/functions/fun-autostart.sh +429 -0
  81. package/core/scripts/functions/fun-avatar.sh +441 -0
  82. package/core/scripts/functions/fun-backup-item.sh +50 -0
  83. package/core/scripts/functions/fun-build-distribution.sh +226 -0
  84. package/core/scripts/functions/fun-build-site-template.sh +104 -0
  85. package/core/scripts/functions/fun-build-webships.sh +161 -0
  86. package/core/scripts/functions/fun-build-website.sh +199 -0
  87. package/core/scripts/functions/fun-checks.sh +243 -0
  88. package/core/scripts/functions/fun-clone-project.sh +289 -0
  89. package/core/scripts/functions/fun-commands.sh +521 -0
  90. package/core/scripts/functions/fun-database.sh +63 -0
  91. package/core/scripts/functions/fun-ddev-hostnames.sh +213 -0
  92. package/core/scripts/functions/fun-ddev-nodejs.sh +15 -0
  93. package/core/scripts/functions/fun-ddev-telemetry.sh +15 -0
  94. package/core/scripts/functions/fun-default-settings.sh +28 -0
  95. package/core/scripts/functions/fun-distribution-cucumber.sh +45 -0
  96. package/core/scripts/functions/fun-distribution-drupal.sh +25 -0
  97. package/core/scripts/functions/fun-distribution-drupal_cms.sh +35 -0
  98. package/core/scripts/functions/fun-distribution-webship.sh +28 -0
  99. package/core/scripts/functions/fun-distribution-webships.sh +33 -0
  100. package/core/scripts/functions/fun-distribution-website.sh +19 -0
  101. package/core/scripts/functions/fun-drush.sh +48 -0
  102. package/core/scripts/functions/fun-elevenlabs.sh +179 -0
  103. package/core/scripts/functions/fun-files.sh +19 -0
  104. package/core/scripts/functions/fun-git-worktrees.sh +142 -0
  105. package/core/scripts/functions/fun-gitlab-ci.sh +156 -0
  106. package/core/scripts/functions/fun-hostnames-cli.sh +88 -0
  107. package/core/scripts/functions/fun-milvus.sh +584 -0
  108. package/core/scripts/functions/fun-odoo.sh +121 -0
  109. package/core/scripts/functions/fun-penpot.sh +724 -0
  110. package/core/scripts/functions/fun-project-name.sh +20 -0
  111. package/core/scripts/functions/fun-rag.sh +253 -0
  112. package/core/scripts/functions/fun-ragify.sh +165 -0
  113. package/core/scripts/functions/fun-reclaim.sh +297 -0
  114. package/core/scripts/functions/fun-release.sh +159 -0
  115. package/core/scripts/functions/fun-remove-project.sh +319 -0
  116. package/core/scripts/functions/fun-screen.sh +96 -0
  117. package/core/scripts/functions/fun-spdd.sh +676 -0
  118. package/core/scripts/functions/fun-specs-share.sh +237 -0
  119. package/core/scripts/functions/fun-storage.sh +347 -0
  120. package/core/scripts/functions/fun-testing.sh +329 -0
  121. package/core/scripts/functions/fun-users.sh +87 -0
  122. package/core/scripts/functions/fun-version.sh +72 -0
  123. package/core/scripts/functions/fun-video-edit.sh +48 -0
  124. package/core/scripts/functions/fun-voice.sh +45 -0
  125. package/core/scripts/functions/fun-wordpress.sh +59 -0
  126. package/core/scripts/host-mounts.sh +161 -0
  127. package/core/scripts/install.sh +602 -0
  128. package/core/scripts/libs/__pycache__/video_edit.cpython-312.pyc +0 -0
  129. package/core/scripts/libs/argparse.sh +93 -0
  130. package/core/scripts/libs/bash-yaml.sh +52 -0
  131. package/core/scripts/libs/checks_plan.js +312 -0
  132. package/core/scripts/libs/elevenlabs.py +627 -0
  133. package/core/scripts/libs/progress-bar.sh +19 -0
  134. package/core/scripts/libs/rag_index.py +446 -0
  135. package/core/scripts/libs/video_edit.py +636 -0
  136. package/core/scripts/libs/voice.py +430 -0
  137. package/core/scripts/plugins/jira/host-install.sh +119 -0
  138. package/core/scripts/plugins/jira/host-mounts.txt +2 -0
  139. package/core/scripts/plugins/upsun/args/arg-upsun.sh +51 -0
  140. package/core/scripts/plugins/upsun/functions/fun-upsun.sh +304 -0
  141. package/core/scripts/plugins/upsun/host-install.sh +99 -0
  142. package/core/scripts/plugins/upsun/host-mounts.txt +1 -0
  143. package/core/scripts/plugins/upsun/upsun-ai.sh +133 -0
  144. package/core/scripts/plugins.sh +152 -0
  145. package/core/scripts/release.sh +69 -0
  146. package/core/scripts/storage.sh +39 -0
  147. package/core/scripts/sync-tooling.sh +246 -0
  148. package/core/scripts/tests/cmd-smoke-test.sh +109 -0
  149. package/core/scripts/trust-https.sh +257 -0
  150. package/core/workspace-app/.ddev/commands/web/test-dashboard +49 -0
  151. package/core/workspace-app/.ddev/config.yaml +400 -0
  152. package/core/workspace-app/.ddev/docker-compose.dood.yaml +45 -0
  153. package/core/workspace-app/.ddev/docker-compose.plugin-jira-twg.yaml +26 -0
  154. package/core/workspace-app/.ddev/docker-compose.plugin-upsun-upsun-cli.yaml +8 -0
  155. package/core/workspace-app/.ddev/docker-compose.screens.yaml +15 -0
  156. package/core/workspace-app/.ddev/nginx_full/nginx-site.conf +114 -0
  157. package/core/workspace-app/.ddev/web-build/Dockerfile.workspace-app +203 -0
  158. package/core/workspace-app/.ddev/web-build/ddev-shim-ddev +122 -0
  159. package/core/workspace-app/README.md +380 -0
  160. package/{actions → core/workspace-app/actions}/ddev.js +0 -1
  161. package/{actions → core/workspace-app/actions}/rag.js +0 -1
  162. package/{actions → core/workspace-app/actions}/testing.js +0 -1
  163. package/{assistant.js → core/workspace-app/assistant.js} +1 -10
  164. package/{git-info.js → core/workspace-app/git-info.js} +17 -1
  165. package/core/workspace-app/package.json +29 -0
  166. package/core/workspace-app/plugin-catalog.js +50 -0
  167. package/{plugins-page.js → core/workspace-app/plugins-page.js} +28 -2
  168. package/{server.js → core/workspace-app/server.js} +18 -0
  169. package/core/workspace-app/tests/features/actions-rail.feature +44 -0
  170. package/core/workspace-app/tests/features/ai-items.feature +23 -0
  171. package/core/workspace-app/tests/features/assistant-speech.feature +63 -0
  172. package/core/workspace-app/tests/features/checks.feature +39 -0
  173. package/core/workspace-app/tests/features/clone-project.feature +30 -0
  174. package/core/workspace-app/tests/features/command-authoring.feature +58 -0
  175. package/core/workspace-app/tests/features/dashboard.feature +57 -0
  176. package/core/workspace-app/tests/features/menus.feature +29 -0
  177. package/core/workspace-app/tests/features/plugins/jira/jira.feature +47 -0
  178. package/core/workspace-app/tests/features/plugins.feature +20 -0
  179. package/core/workspace-app/tests/features/project-actions.feature +40 -0
  180. package/core/workspace-app/tests/features/screens.feature +29 -0
  181. package/core/workspace-app/tests/features/settings.feature +46 -0
  182. package/core/workspace-app/tests/features/test-reports.feature +32 -0
  183. package/core/workspace-app/tests/features/theme.feature +40 -0
  184. package/core/workspace-app/tests/step-definitions/actions-post.steps.js +25 -0
  185. package/core/workspace-app/tests/step-definitions/assistant-speech.steps.js +152 -0
  186. package/core/workspace-app/tests/step-definitions/preconditions.steps.js +100 -0
  187. package/core/workspace-app/tests/unit/_isolated-config.js +31 -0
  188. package/core/workspace-app/tests/unit/accessibility.test.js +124 -0
  189. package/core/workspace-app/tests/unit/actions-rail-ux.test.js +56 -0
  190. package/core/workspace-app/tests/unit/actions-rail.test.js +51 -0
  191. package/core/workspace-app/tests/unit/ai-inventory.test.js +64 -0
  192. package/core/workspace-app/tests/unit/app-docs.test.js +64 -0
  193. package/core/workspace-app/tests/unit/assistant-avatar.test.js +110 -0
  194. package/core/workspace-app/tests/unit/assistant-cast.test.js +105 -0
  195. package/core/workspace-app/tests/unit/assistant-send-animation.test.js +15 -0
  196. package/core/workspace-app/tests/unit/assistant-suggestions.test.js +112 -0
  197. package/core/workspace-app/tests/unit/assistant-switches.test.js +53 -0
  198. package/core/workspace-app/tests/unit/assistant-views.test.js +146 -0
  199. package/core/workspace-app/tests/unit/assistant-working-indicator.test.js +49 -0
  200. package/core/workspace-app/tests/unit/assistant.test.js +61 -0
  201. package/core/workspace-app/tests/unit/audio-player.test.js +147 -0
  202. package/core/workspace-app/tests/unit/audio-voice.test.js +634 -0
  203. package/core/workspace-app/tests/unit/auth-google.test.js +180 -0
  204. package/core/workspace-app/tests/unit/autostart-watch.test.js +76 -0
  205. package/core/workspace-app/tests/unit/browsers.test.js +76 -0
  206. package/core/workspace-app/tests/unit/build-distribution.test.js +125 -0
  207. package/core/workspace-app/tests/unit/build-order.test.js +153 -0
  208. package/core/workspace-app/tests/unit/builder-args.test.js +113 -0
  209. package/core/workspace-app/tests/unit/builders.test.js +158 -0
  210. package/core/workspace-app/tests/unit/card-state-toggle.test.js +29 -0
  211. package/core/workspace-app/tests/unit/changelog.test.js +177 -0
  212. package/core/workspace-app/tests/unit/chat-thread.test.js +92 -0
  213. package/core/workspace-app/tests/unit/checks-plan.test.js +205 -0
  214. package/core/workspace-app/tests/unit/claude-args.test.js +182 -0
  215. package/core/workspace-app/tests/unit/claude-code-here.test.js +15 -0
  216. package/core/workspace-app/tests/unit/claude-resume.test.js +147 -0
  217. package/core/workspace-app/tests/unit/claude-screen-options.test.js +84 -0
  218. package/core/workspace-app/tests/unit/claude-session.test.js +41 -0
  219. package/core/workspace-app/tests/unit/command-flags.test.js +45 -0
  220. package/core/workspace-app/tests/unit/command-palette.test.js +105 -0
  221. package/core/workspace-app/tests/unit/commands-center.test.js +338 -0
  222. package/core/workspace-app/tests/unit/composer-menu.test.js +187 -0
  223. package/core/workspace-app/tests/unit/config-yaml.test.js +116 -0
  224. package/core/workspace-app/tests/unit/confirm-dialog.test.js +69 -0
  225. package/core/workspace-app/tests/unit/create-card.test.js +85 -0
  226. package/core/workspace-app/tests/unit/ddev-addons.test.js +144 -0
  227. package/core/workspace-app/tests/unit/ddev-auth-ssh.test.js +40 -0
  228. package/core/workspace-app/tests/unit/ddev-custom-commands.test.js +56 -0
  229. package/core/workspace-app/tests/unit/ddev-diagnose.test.js +57 -0
  230. package/core/workspace-app/tests/unit/ddev-domains.test.js +153 -0
  231. package/core/workspace-app/tests/unit/ddev-hostnames.test.js +143 -0
  232. package/core/workspace-app/tests/unit/ddev-import.test.js +82 -0
  233. package/core/workspace-app/tests/unit/ddev-mail.test.js +135 -0
  234. package/core/workspace-app/tests/unit/ddev-menu-and-create.test.js +28 -0
  235. package/core/workspace-app/tests/unit/ddev-mutagen.test.js +37 -0
  236. package/core/workspace-app/tests/unit/ddev-options.test.js +51 -0
  237. package/core/workspace-app/tests/unit/ddev-share.test.js +40 -0
  238. package/core/workspace-app/tests/unit/ddev-shim.test.js +57 -0
  239. package/core/workspace-app/tests/unit/ddev-snapshots.test.js +142 -0
  240. package/core/workspace-app/tests/unit/ddev-start-daemons.test.js +62 -0
  241. package/core/workspace-app/tests/unit/ddev-xdebug.test.js +41 -0
  242. package/core/workspace-app/tests/unit/deep-chat-origin.test.js +38 -0
  243. package/core/workspace-app/tests/unit/density.test.js +52 -0
  244. package/core/workspace-app/tests/unit/elevenlabs.test.js +453 -0
  245. package/core/workspace-app/tests/unit/event-log.test.js +102 -0
  246. package/core/workspace-app/tests/unit/favicon.test.js +68 -0
  247. package/core/workspace-app/tests/unit/files-browser.test.js +224 -0
  248. package/core/workspace-app/tests/unit/git-info.test.js +26 -0
  249. package/core/workspace-app/tests/unit/grid-and-list.test.js +103 -0
  250. package/core/workspace-app/tests/unit/host-tool-wrapper.test.js +18 -0
  251. package/core/workspace-app/tests/unit/html-patterns.test.js +51 -0
  252. package/core/workspace-app/tests/unit/ide-infra.test.js +28 -0
  253. package/core/workspace-app/tests/unit/images-ai.test.js +201 -0
  254. package/core/workspace-app/tests/unit/images-create.test.js +59 -0
  255. package/core/workspace-app/tests/unit/images-providers.test.js +248 -0
  256. package/core/workspace-app/tests/unit/images-svg.test.js +213 -0
  257. package/core/workspace-app/tests/unit/images-workspace.test.js +144 -0
  258. package/core/workspace-app/tests/unit/jobs-fragment.test.js +66 -0
  259. package/core/workspace-app/tests/unit/media-ux.test.js +164 -0
  260. package/core/workspace-app/tests/unit/modal-fit.test.js +87 -0
  261. package/core/workspace-app/tests/unit/modules-load.test.js +23 -0
  262. package/core/workspace-app/tests/unit/narration.test.js +186 -0
  263. package/core/workspace-app/tests/unit/navigation-editor.test.js +260 -0
  264. package/core/workspace-app/tests/unit/navigation.test.js +254 -0
  265. package/core/workspace-app/tests/unit/new-folder.test.js +121 -0
  266. package/core/workspace-app/tests/unit/new-screen-form.test.js +149 -0
  267. package/core/workspace-app/tests/unit/node-menu.test.js +161 -0
  268. package/core/workspace-app/tests/unit/notes.test.js +128 -0
  269. package/core/workspace-app/tests/unit/page-structure.test.js +40 -0
  270. package/core/workspace-app/tests/unit/page-width.test.js +59 -0
  271. package/core/workspace-app/tests/unit/php-version.test.js +90 -0
  272. package/core/workspace-app/tests/unit/plan-card.test.js +44 -0
  273. package/core/workspace-app/tests/unit/plugin-catalog.test.js +31 -0
  274. package/core/workspace-app/tests/unit/plugin-system.test.js +251 -0
  275. package/core/workspace-app/tests/unit/plugins-page.test.js +28 -0
  276. package/core/workspace-app/tests/unit/plugins.test.js +58 -0
  277. package/core/workspace-app/tests/unit/project-activity-filter.test.js +180 -0
  278. package/core/workspace-app/tests/unit/project-make.test.js +143 -0
  279. package/core/workspace-app/tests/unit/project-name.test.js +202 -0
  280. package/core/workspace-app/tests/unit/reader.test.js +62 -0
  281. package/core/workspace-app/tests/unit/release.test.js +92 -0
  282. package/core/workspace-app/tests/unit/remove-confirm.test.js +37 -0
  283. package/core/workspace-app/tests/unit/report-pdf.test.js +171 -0
  284. package/core/workspace-app/tests/unit/round-11.test.js +31 -0
  285. package/core/workspace-app/tests/unit/round-12.test.js +37 -0
  286. package/core/workspace-app/tests/unit/row-layout.test.js +585 -0
  287. package/core/workspace-app/tests/unit/row-menus-fold.test.js +29 -0
  288. package/core/workspace-app/tests/unit/rows-add-modal.test.js +68 -0
  289. package/core/workspace-app/tests/unit/screen-runner-queue.test.js +41 -0
  290. package/core/workspace-app/tests/unit/screen-window.test.js +116 -0
  291. package/core/workspace-app/tests/unit/screens-beside-running.test.js +19 -0
  292. package/core/workspace-app/tests/unit/screens-columns.test.js +79 -0
  293. package/core/workspace-app/tests/unit/screens-menu.test.js +84 -0
  294. package/core/workspace-app/tests/unit/screens-modal-overlay.test.js +14 -0
  295. package/core/workspace-app/tests/unit/screens-waiting.test.js +129 -0
  296. package/core/workspace-app/tests/unit/screens.test.js +74 -0
  297. package/core/workspace-app/tests/unit/second-storage.test.js +218 -0
  298. package/core/workspace-app/tests/unit/session-name.test.js +64 -0
  299. package/core/workspace-app/tests/unit/settings-file.test.js +173 -0
  300. package/core/workspace-app/tests/unit/settings-nested-list.test.js +54 -0
  301. package/core/workspace-app/tests/unit/settings-raw.test.js +177 -0
  302. package/core/workspace-app/tests/unit/shared-prefs.test.js +49 -0
  303. package/core/workspace-app/tests/unit/speech.test.js +290 -0
  304. package/core/workspace-app/tests/unit/static-caching.test.js +39 -0
  305. package/core/workspace-app/tests/unit/status-language.test.js +47 -0
  306. package/core/workspace-app/tests/unit/tab-modal.test.js +69 -0
  307. package/core/workspace-app/tests/unit/tab-title.test.js +37 -0
  308. package/core/workspace-app/tests/unit/template-literals.test.js +52 -0
  309. package/core/workspace-app/tests/unit/terminal-scrollback.test.js +61 -0
  310. package/core/workspace-app/tests/unit/terminal-size.test.js +103 -0
  311. package/core/workspace-app/tests/unit/terminal-style.test.js +84 -0
  312. package/core/workspace-app/tests/unit/terminal-windows.test.js +154 -0
  313. package/core/workspace-app/tests/unit/themes.test.js +453 -0
  314. package/core/workspace-app/tests/unit/tool-labels.test.js +34 -0
  315. package/core/workspace-app/tests/unit/topbar-icons.test.js +47 -0
  316. package/core/workspace-app/tests/unit/update-docker-gid.test.js +51 -0
  317. package/core/workspace-app/tests/unit/user-guide.test.js +60 -0
  318. package/core/workspace-app/tests/unit/version-check.test.js +98 -0
  319. package/core/workspace-app/tests/unit/version-link.test.js +50 -0
  320. package/core/workspace-app/tests/unit/video-borrow.test.js +198 -0
  321. package/core/workspace-app/tests/unit/video-edit-ask.test.js +93 -0
  322. package/core/workspace-app/tests/unit/video-edit-short.test.js +42 -0
  323. package/core/workspace-app/tests/unit/video-edit.test.js +417 -0
  324. package/core/workspace-app/tests/unit/video-transcript.test.js +237 -0
  325. package/core/workspace-app/tests/unit/waiting.test.js +48 -0
  326. package/core/workspace-app/tests/unit/wordpress-odoo-builders.test.js +38 -0
  327. package/core/workspace-app/tests/unit/workspace-bin.test.js +48 -0
  328. package/core/workspace-app/tests/unit/workspace-card-tools.test.js +30 -0
  329. package/core/workspace-app/tests/unit/workspace-delete.test.js +77 -0
  330. package/core/workspace-app/tests/unit/workspace-types.test.js +68 -0
  331. package/core/workspace-app/tests/unit/worktree-clone.test.js +250 -0
  332. package/package.json +38 -36
  333. /package/{PLUGINS.md → core/workspace-app/PLUGINS.md} +0 -0
  334. /package/{WORKSPACES.md → core/workspace-app/WORKSPACES.md} +0 -0
  335. /package/{actions → core/workspace-app/actions}/ai-items.js +0 -0
  336. /package/{actions → core/workspace-app/actions}/audio.js +0 -0
  337. /package/{actions → core/workspace-app/actions}/build-order.js +0 -0
  338. /package/{actions → core/workspace-app/actions}/checks.js +0 -0
  339. /package/{actions → core/workspace-app/actions}/claude-session.js +0 -0
  340. /package/{actions → core/workspace-app/actions}/commands-center.js +0 -0
  341. /package/{actions → core/workspace-app/actions}/composer.js +0 -0
  342. /package/{actions → core/workspace-app/actions}/ddev-addons.js +0 -0
  343. /package/{actions → core/workspace-app/actions}/ddev-mail.js +0 -0
  344. /package/{actions → core/workspace-app/actions}/folders.js +0 -0
  345. /package/{actions → core/workspace-app/actions}/images-svg.js +0 -0
  346. /package/{actions → core/workspace-app/actions}/images.js +0 -0
  347. /package/{actions → core/workspace-app/actions}/navigation.js +0 -0
  348. /package/{actions → core/workspace-app/actions}/node.js +0 -0
  349. /package/{actions → core/workspace-app/actions}/notes.js +0 -0
  350. /package/{actions → core/workspace-app/actions}/plugins.js +0 -0
  351. /package/{actions → core/workspace-app/actions}/project-make.js +0 -0
  352. /package/{actions → core/workspace-app/actions}/row-actions.js +0 -0
  353. /package/{actions → core/workspace-app/actions}/screens.js +0 -0
  354. /package/{actions → core/workspace-app/actions}/video-edit.js +0 -0
  355. /package/{ai-inventory.js → core/workspace-app/ai-inventory.js} +0 -0
  356. /package/{ai-items.js → core/workspace-app/ai-items.js} +0 -0
  357. /package/{assistant-cast.js → core/workspace-app/assistant-cast.js} +0 -0
  358. /package/{assistant-suggestions.js → core/workspace-app/assistant-suggestions.js} +0 -0
  359. /package/{audio-voice.js → core/workspace-app/audio-voice.js} +0 -0
  360. /package/{auth-google.js → core/workspace-app/auth-google.js} +0 -0
  361. /package/{build-ai.js → core/workspace-app/build-ai.js} +0 -0
  362. /package/{build-order-page.js → core/workspace-app/build-order-page.js} +0 -0
  363. /package/{build-order.js → core/workspace-app/build-order.js} +0 -0
  364. /package/{builder-args.js → core/workspace-app/builder-args.js} +0 -0
  365. /package/{changelog.js → core/workspace-app/changelog.js} +0 -0
  366. /package/{chat-threads.js → core/workspace-app/chat-threads.js} +0 -0
  367. /package/{checks.js → core/workspace-app/checks.js} +0 -0
  368. /package/{claude-args.js → core/workspace-app/claude-args.js} +0 -0
  369. /package/{claude-sessions.js → core/workspace-app/claude-sessions.js} +0 -0
  370. /package/{command-author.js → core/workspace-app/command-author.js} +0 -0
  371. /package/{command-block.js → core/workspace-app/command-block.js} +0 -0
  372. /package/{commands → core/workspace-app/commands}/defaults.yml +0 -0
  373. /package/{commands-page.js → core/workspace-app/commands-page.js} +0 -0
  374. /package/{commands.js → core/workspace-app/commands.js} +0 -0
  375. /package/{cucumber.js → core/workspace-app/cucumber.js} +0 -0
  376. /package/{ddev-addons-page.js → core/workspace-app/ddev-addons-page.js} +0 -0
  377. /package/{ddev-addons.js → core/workspace-app/ddev-addons.js} +0 -0
  378. /package/{ddev-custom-commands.js → core/workspace-app/ddev-custom-commands.js} +0 -0
  379. /package/{ddev-domains.js → core/workspace-app/ddev-domains.js} +0 -0
  380. /package/{ddev-import.js → core/workspace-app/ddev-import.js} +0 -0
  381. /package/{ddev-mail-page.js → core/workspace-app/ddev-mail-page.js} +0 -0
  382. /package/{ddev-mail.js → core/workspace-app/ddev-mail.js} +0 -0
  383. /package/{ddev-options.js → core/workspace-app/ddev-options.js} +0 -0
  384. /package/{ddev-snapshots.js → core/workspace-app/ddev-snapshots.js} +0 -0
  385. /package/{ddev.js → core/workspace-app/ddev.js} +0 -0
  386. /package/{docs → core/workspace-app/docs}/DEVELOPER-GUIDE.md +0 -0
  387. /package/{docs → core/workspace-app/docs}/README.md +0 -0
  388. /package/{docs → core/workspace-app/docs}/REFERENCE.md +0 -0
  389. /package/{docs → core/workspace-app/docs}/USER-GUIDE.md +0 -0
  390. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-board.png +0 -0
  391. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-coffee.png +0 -0
  392. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-colours.png +0 -0
  393. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-icons.png +0 -0
  394. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-moves.png +0 -0
  395. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-pick-cookieman.png +0 -0
  396. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-settings-voices.png +0 -0
  397. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-status.png +0 -0
  398. /package/{docs → core/workspace-app/docs}/screenshots/create-card/create-card.png +0 -0
  399. /package/{docs → core/workspace-app/docs}/screenshots/create-card/start-ai.png +0 -0
  400. /package/{docs → core/workspace-app/docs}/screenshots/guide-clone-address.png +0 -0
  401. /package/{docs → core/workspace-app/docs}/screenshots/guide-clone-worktree-off.png +0 -0
  402. /package/{docs → core/workspace-app/docs}/screenshots/guide-clone-worktree-on.png +0 -0
  403. /package/{docs → core/workspace-app/docs}/screenshots/guide-ddev-menu.png +0 -0
  404. /package/{docs → core/workspace-app/docs}/screenshots/guide-domains.png +0 -0
  405. /package/{docs → core/workspace-app/docs}/screenshots/guide-home.png +0 -0
  406. /package/{docs → core/workspace-app/docs}/screenshots/guide-ide-menu.png +0 -0
  407. /package/{docs → core/workspace-app/docs}/screenshots/guide-remove-refusal.png +0 -0
  408. /package/{docs → core/workspace-app/docs}/screenshots/guide-rows-worktree.png +0 -0
  409. /package/{docs → core/workspace-app/docs}/screenshots/guide-screens.png +0 -0
  410. /package/{docs → core/workspace-app/docs}/screenshots/guide-settings.png +0 -0
  411. /package/{docs → core/workspace-app/docs}/screenshots/guide-workspace-page.png +0 -0
  412. /package/{docs → core/workspace-app/docs}/screenshots/home/card-settings.png +0 -0
  413. /package/{docs → core/workspace-app/docs}/screenshots/home/drag-reorder.png +0 -0
  414. /package/{docs → core/workspace-app/docs}/screenshots/home/edit-card.png +0 -0
  415. /package/{docs → core/workspace-app/docs}/screenshots/images/claude-code-image.png +0 -0
  416. /package/{docs → core/workspace-app/docs}/screenshots/images/edit-with-ai.png +0 -0
  417. /package/{docs → core/workspace-app/docs}/screenshots/images/gallery.png +0 -0
  418. /package/{docs → core/workspace-app/docs}/screenshots/images/generate-description.png +0 -0
  419. /package/{docs → core/workspace-app/docs}/screenshots/images/generate-plan.png +0 -0
  420. /package/{docs → core/workspace-app/docs}/screenshots/images/providers.png +0 -0
  421. /package/{docs → core/workspace-app/docs}/screenshots/images/svg-form.png +0 -0
  422. /package/{docs → core/workspace-app/docs}/screenshots/images/svg-result.png +0 -0
  423. /package/{docs → core/workspace-app/docs}/screenshots/images/upload.png +0 -0
  424. /package/{docs → core/workspace-app/docs}/screenshots/new-folder/2-form.png +0 -0
  425. /package/{docs → core/workspace-app/docs}/screenshots/new-folder/8-ddev-options.png +0 -0
  426. /package/{docs → core/workspace-app/docs}/screenshots/new-folder/files-folder.png +0 -0
  427. /package/{docs → core/workspace-app/docs}/screenshots/projects/ddev-custom-commands.png +0 -0
  428. /package/{docs → core/workspace-app/docs}/screenshots/projects/state-chip-stop.png +0 -0
  429. /package/{docs → core/workspace-app/docs}/screenshots/readme/dashboard-dark.png +0 -0
  430. /package/{docs → core/workspace-app/docs}/screenshots/readme/dashboard-light.png +0 -0
  431. /package/{docs → core/workspace-app/docs}/screenshots/readme/dev-dark.png +0 -0
  432. /package/{docs → core/workspace-app/docs}/screenshots/readme/dev-light.png +0 -0
  433. /package/{docs → core/workspace-app/docs}/screenshots/readme/docs-dark.png +0 -0
  434. /package/{docs → core/workspace-app/docs}/screenshots/readme/docs-light.png +0 -0
  435. /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/ai.svg +0 -0
  436. /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/code.svg +0 -0
  437. /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/docs.svg +0 -0
  438. /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/services.svg +0 -0
  439. /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/sites.svg +0 -0
  440. /package/{docs → core/workspace-app/docs}/screenshots/readme/test-report-dark.png +0 -0
  441. /package/{docs → core/workspace-app/docs}/screenshots/readme/test-report-light.png +0 -0
  442. /package/{docs → core/workspace-app/docs}/screenshots/readme/test-scenarios.png +0 -0
  443. /package/{docs → core/workspace-app/docs}/screenshots/readme/test-steps.png +0 -0
  444. /package/{docs → core/workspace-app/docs}/screenshots/readme/videos-dark.png +0 -0
  445. /package/{docs → core/workspace-app/docs}/screenshots/readme/videos-light.png +0 -0
  446. /package/{docs → core/workspace-app/docs}/screenshots/screens-menu.png +0 -0
  447. /package/{docs → core/workspace-app/docs}/screenshots/screens-new.png +0 -0
  448. /package/{docs → core/workspace-app/docs}/screenshots/settings/auth-google-lists.png +0 -0
  449. /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-1-row.png +0 -0
  450. /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-2-confirm.png +0 -0
  451. /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-3-type-name.png +0 -0
  452. /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-4-type-yes.png +0 -0
  453. /package/{event-log.js → core/workspace-app/event-log.js} +0 -0
  454. /package/{files-browser.js → core/workspace-app/files-browser.js} +0 -0
  455. /package/{folders.js → core/workspace-app/folders.js} +0 -0
  456. /package/{format.js → core/workspace-app/format.js} +0 -0
  457. /package/{github-auth.js → core/workspace-app/github-auth.js} +0 -0
  458. /package/{html.js → core/workspace-app/html.js} +0 -0
  459. /package/{icons.js → core/workspace-app/icons.js} +0 -0
  460. /package/{images-ai.js → core/workspace-app/images-ai.js} +0 -0
  461. /package/{images-create.js → core/workspace-app/images-create.js} +0 -0
  462. /package/{images-page.js → core/workspace-app/images-page.js} +0 -0
  463. /package/{images-records.js → core/workspace-app/images-records.js} +0 -0
  464. /package/{images-render.js → core/workspace-app/images-render.js} +0 -0
  465. /package/{images-svg-core.js → core/workspace-app/images-svg-core.js} +0 -0
  466. /package/{images-svg-sanitize.js → core/workspace-app/images-svg-sanitize.js} +0 -0
  467. /package/{images-svg.js → core/workspace-app/images-svg.js} +0 -0
  468. /package/{images.js → core/workspace-app/images.js} +0 -0
  469. /package/{jobs.js → core/workspace-app/jobs.js} +0 -0
  470. /package/{linger.js → core/workspace-app/linger.js} +0 -0
  471. /package/{lists.js → core/workspace-app/lists.js} +0 -0
  472. /package/{media-info.js → core/workspace-app/media-info.js} +0 -0
  473. /package/{navigation-page.js → core/workspace-app/navigation-page.js} +0 -0
  474. /package/{navigation.js → core/workspace-app/navigation.js} +0 -0
  475. /package/{notes.js → core/workspace-app/notes.js} +0 -0
  476. /package/{palette-index.js → core/workspace-app/palette-index.js} +0 -0
  477. /package/{playwright.config.js → core/workspace-app/playwright.config.js} +0 -0
  478. /package/{plugin-install.js → core/workspace-app/plugin-install.js} +0 -0
  479. /package/{plugin-loader.js → core/workspace-app/plugin-loader.js} +0 -0
  480. /package/{plugin-manifest.js → core/workspace-app/plugin-manifest.js} +0 -0
  481. /package/{plugin-settings.js → core/workspace-app/plugin-settings.js} +0 -0
  482. /package/{plugins → core/workspace-app/plugins}/workspace-notes/index.js +0 -0
  483. /package/{project-make.js → core/workspace-app/project-make.js} +0 -0
  484. /package/{project-name.js → core/workspace-app/project-name.js} +0 -0
  485. /package/{public → core/workspace-app/public}/assistant-avatar-moves.js +0 -0
  486. /package/{public → core/workspace-app/public}/assistant-avatar-ui.js +0 -0
  487. /package/{public → core/workspace-app/public}/assistant-avatar.js +0 -0
  488. /package/{public → core/workspace-app/public}/avatar/druplicon.vrm +0 -0
  489. /package/{public → core/workspace-app/public}/css/base.css +0 -0
  490. /package/{public → core/workspace-app/public}/css/components/ai-assistant.css +0 -0
  491. /package/{public → core/workspace-app/public}/css/components/assistant-avatar.css +0 -0
  492. /package/{public → core/workspace-app/public}/css/components/assistant-views.css +0 -0
  493. /package/{public → core/workspace-app/public}/css/components/build-order.css +0 -0
  494. /package/{public → core/workspace-app/public}/css/components/clone-as-a-git-worktree.css +0 -0
  495. /package/{public → core/workspace-app/public}/css/components/command-palette.css +0 -0
  496. /package/{public → core/workspace-app/public}/css/components/commands-center.css +0 -0
  497. /package/{public → core/workspace-app/public}/css/components/confirm-dialog.css +0 -0
  498. /package/{public → core/workspace-app/public}/css/components/create-card.css +0 -0
  499. /package/{public → core/workspace-app/public}/css/components/ddev-menu.css +0 -0
  500. /package/{public → core/workspace-app/public}/css/components/deep-chat.css +0 -0
  501. /package/{public → core/workspace-app/public}/css/components/density.css +0 -0
  502. /package/{public → core/workspace-app/public}/css/components/floating-assistant-workspace-pages.css +0 -0
  503. /package/{public → core/workspace-app/public}/css/components/folders.css +0 -0
  504. /package/{public → core/workspace-app/public}/css/components/full-height-left-assistant-sidebar-all-pages.css +0 -0
  505. /package/{public → core/workspace-app/public}/css/components/full-height-right-actions-rail-pages-that-have-actions.css +0 -0
  506. /package/{public → core/workspace-app/public}/css/components/grid-and-list.css +0 -0
  507. /package/{public → core/workspace-app/public}/css/components/help-page.css +0 -0
  508. /package/{public → core/workspace-app/public}/css/components/hero.css +0 -0
  509. /package/{public → core/workspace-app/public}/css/components/images.css +0 -0
  510. /package/{public → core/workspace-app/public}/css/components/layout-rhythm-and-spacing-polish.css +0 -0
  511. /package/{public → core/workspace-app/public}/css/components/mic-on-any-field-that-wants-typing.css +0 -0
  512. /package/{public → core/workspace-app/public}/css/components/modal-fit.css +0 -0
  513. /package/{public → core/workspace-app/public}/css/components/page-width.css +0 -0
  514. /package/{public → core/workspace-app/public}/css/components/plugins-page.css +0 -0
  515. /package/{public → core/workspace-app/public}/css/components/project-cards.css +0 -0
  516. /package/{public → core/workspace-app/public}/css/components/project-rows.css +0 -0
  517. /package/{public → core/workspace-app/public}/css/components/reordering-the-workspace-cards.css +0 -0
  518. /package/{public → core/workspace-app/public}/css/components/responsive-home-and-the-workspace-pages.css +0 -0
  519. /package/{public → core/workspace-app/public}/css/components/running-commands-as-toasts.css +0 -0
  520. /package/{public → core/workspace-app/public}/css/components/settings-editor-core-config-yml.css +0 -0
  521. /package/{public → core/workspace-app/public}/css/components/short-results-as-a-toast-at-the-top.css +0 -0
  522. /package/{public → core/workspace-app/public}/css/components/sound-player.css +0 -0
  523. /package/{public → core/workspace-app/public}/css/components/suggest-agents-skills-commands.css +0 -0
  524. /package/{public → core/workspace-app/public}/css/components/tab-modal.css +0 -0
  525. /package/{public → core/workspace-app/public}/css/components/terminals.css +0 -0
  526. /package/{public → core/workspace-app/public}/css/components/test-report-media-one-file-per-row-paged.css +0 -0
  527. /package/{public → core/workspace-app/public}/css/components/top-toolbar-logo-breadcrumb.css +0 -0
  528. /package/{public → core/workspace-app/public}/css/components/video-edit.css +0 -0
  529. /package/{public → core/workspace-app/public}/css/components/web-ide-open-with.css +0 -0
  530. /package/{public → core/workspace-app/public}/css/components/working-indicators.css +0 -0
  531. /package/{public → core/workspace-app/public}/css/components/workspace-cards.css +0 -0
  532. /package/{public → core/workspace-app/public}/favicon.ico +0 -0
  533. /package/{public → core/workspace-app/public}/favicon.png +0 -0
  534. /package/{public → core/workspace-app/public}/htmx.min.js +0 -0
  535. /package/{public → core/workspace-app/public}/logo.png +0 -0
  536. /package/{public → core/workspace-app/public}/media-player.js +0 -0
  537. /package/{public → core/workspace-app/public}/mic.js +0 -0
  538. /package/{public → core/workspace-app/public}/narration.js +0 -0
  539. /package/{public → core/workspace-app/public}/palette.js +0 -0
  540. /package/{public → core/workspace-app/public}/sortable.js +0 -0
  541. /package/{public → core/workspace-app/public}/suggest.js +0 -0
  542. /package/{public → core/workspace-app/public}/terminal.js +0 -0
  543. /package/{public → core/workspace-app/public}/themes/default/theme.css +0 -0
  544. /package/{public → core/workspace-app/public}/themes/ember/theme.css +0 -0
  545. /package/{public → core/workspace-app/public}/themes/press/theme.css +0 -0
  546. /package/{public → core/workspace-app/public}/themes/slate/theme.css +0 -0
  547. /package/{public → core/workspace-app/public}/touch-icon.png +0 -0
  548. /package/{public → core/workspace-app/public}/ui.js +0 -0
  549. /package/{public → core/workspace-app/public}/vendor/ace/LICENSE.txt +0 -0
  550. /package/{public → core/workspace-app/public}/vendor/ace/ace.js +0 -0
  551. /package/{public → core/workspace-app/public}/vendor/ace/ext-language_tools.js +0 -0
  552. /package/{public → core/workspace-app/public}/vendor/ace/ext-searchbox.js +0 -0
  553. /package/{public → core/workspace-app/public}/vendor/ace/mode-css.js +0 -0
  554. /package/{public → core/workspace-app/public}/vendor/ace/mode-html.js +0 -0
  555. /package/{public → core/workspace-app/public}/vendor/ace/mode-javascript.js +0 -0
  556. /package/{public → core/workspace-app/public}/vendor/ace/mode-markdown.js +0 -0
  557. /package/{public → core/workspace-app/public}/vendor/ace/mode-sh.js +0 -0
  558. /package/{public → core/workspace-app/public}/vendor/ace/mode-yaml.js +0 -0
  559. /package/{public → core/workspace-app/public}/vendor/ace/theme-textmate.js +0 -0
  560. /package/{public → core/workspace-app/public}/vendor/ace/theme-tomorrow_night.js +0 -0
  561. /package/{public → core/workspace-app/public}/vendor/ace/worker-yaml.js +0 -0
  562. /package/{public → core/workspace-app/public}/vendor/deep-chat.LICENSE +0 -0
  563. /package/{public → core/workspace-app/public}/vendor/deep-chat.bundle.js +0 -0
  564. /package/{public → core/workspace-app/public}/vendor/fonts/dm-serif-text-LICENSE.txt +0 -0
  565. /package/{public → core/workspace-app/public}/vendor/fonts/dm-serif-text-latin-400-italic.woff2 +0 -0
  566. /package/{public → core/workspace-app/public}/vendor/fonts/dm-serif-text-latin-400-normal.woff2 +0 -0
  567. /package/{public → core/workspace-app/public}/vendor/fonts/figtree-LICENSE.txt +0 -0
  568. /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-400-italic.woff2 +0 -0
  569. /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-400-normal.woff2 +0 -0
  570. /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-600-italic.woff2 +0 -0
  571. /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-600-normal.woff2 +0 -0
  572. /package/{public → core/workspace-app/public}/vendor/fonts/jetbrains-mono-LICENSE.txt +0 -0
  573. /package/{public → core/workspace-app/public}/vendor/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  574. /package/{public → core/workspace-app/public}/vendor/fonts/ubuntu-mono-LICENSE.txt +0 -0
  575. /package/{public → core/workspace-app/public}/vendor/fonts/ubuntu-mono-latin-wght-normal.woff2 +0 -0
  576. /package/{public → core/workspace-app/public}/vendor/tabler-LICENSE.txt +0 -0
  577. /package/{public → core/workspace-app/public}/vendor/tabler-sprite.svg +0 -0
  578. /package/{public → core/workspace-app/public}/vendor/three/LICENSE +0 -0
  579. /package/{public → core/workspace-app/public}/vendor/three/addons/loaders/GLTFLoader.js +0 -0
  580. /package/{public → core/workspace-app/public}/vendor/three/addons/utils/BufferGeometryUtils.js +0 -0
  581. /package/{public → core/workspace-app/public}/vendor/three/addons/utils/SkeletonUtils.js +0 -0
  582. /package/{public → core/workspace-app/public}/vendor/three/three.core.min.js +0 -0
  583. /package/{public → core/workspace-app/public}/vendor/three/three.module.min.js +0 -0
  584. /package/{public → core/workspace-app/public}/vendor/three-vrm/LICENSE +0 -0
  585. /package/{public → core/workspace-app/public}/vendor/three-vrm/three-vrm.module.min.js +0 -0
  586. /package/{public → core/workspace-app/public}/vendor/uikit-icons.min.js +0 -0
  587. /package/{public → core/workspace-app/public}/vendor/uikit.min.css +0 -0
  588. /package/{public → core/workspace-app/public}/vendor/uikit.min.js +0 -0
  589. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/bookmark-outlined.svg +0 -0
  590. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/headset.svg +0 -0
  591. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/menu.svg +0 -0
  592. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/pause.svg +0 -0
  593. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/play.svg +0 -0
  594. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/share.svg +0 -0
  595. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/sound-off.svg +0 -0
  596. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/sound-on.svg +0 -0
  597. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/stop.svg +0 -0
  598. /package/{public → core/workspace-app/public}/vendor/xterm/addon-fit.js +0 -0
  599. /package/{public → core/workspace-app/public}/vendor/xterm/addon-unicode11.js +0 -0
  600. /package/{public → core/workspace-app/public}/vendor/xterm/addon-web-links.js +0 -0
  601. /package/{public → core/workspace-app/public}/vendor/xterm/xterm.css +0 -0
  602. /package/{public → core/workspace-app/public}/vendor/xterm/xterm.js +0 -0
  603. /package/{rag.js → core/workspace-app/rag.js} +0 -0
  604. /package/{reader.js → core/workspace-app/reader.js} +0 -0
  605. /package/{repo-blobs.js → core/workspace-app/repo-blobs.js} +0 -0
  606. /package/{report-pdf.js → core/workspace-app/report-pdf.js} +0 -0
  607. /package/{row-layout.js → core/workspace-app/row-layout.js} +0 -0
  608. /package/{screenrc → core/workspace-app/screenrc} +0 -0
  609. /package/{screens.js → core/workspace-app/screens.js} +0 -0
  610. /package/{scripts → core/workspace-app/scripts}/code-server-start.sh +0 -0
  611. /package/{scripts → core/workspace-app/scripts}/images-claude-finish.js +0 -0
  612. /package/{scripts → core/workspace-app/scripts}/screen-host.sh +0 -0
  613. /package/{scripts → core/workspace-app/scripts}/screen-runner.js +0 -0
  614. /package/{scripts → core/workspace-app/scripts}/screen-then.js +0 -0
  615. /package/{scripts → core/workspace-app/scripts}/update.sh +0 -0
  616. /package/{settings-file.js → core/workspace-app/settings-file.js} +0 -0
  617. /package/{speech.js → core/workspace-app/speech.js} +0 -0
  618. /package/{tab-modal.js → core/workspace-app/tab-modal.js} +0 -0
  619. /package/{test-reports.js → core/workspace-app/test-reports.js} +0 -0
  620. /package/{themes.js → core/workspace-app/themes.js} +0 -0
  621. /package/{transcripts.js → core/workspace-app/transcripts.js} +0 -0
  622. /package/{urls.js → core/workspace-app/urls.js} +0 -0
  623. /package/{validate.js → core/workspace-app/validate.js} +0 -0
  624. /package/{version-check.js → core/workspace-app/version-check.js} +0 -0
  625. /package/{video-edit.js → core/workspace-app/video-edit.js} +0 -0
  626. /package/{waiting.js → core/workspace-app/waiting.js} +0 -0
  627. /package/{workspace-card-tools.js → core/workspace-app/workspace-card-tools.js} +0 -0
  628. /package/{workspace-delete.js → core/workspace-app/workspace-delete.js} +0 -0
  629. /package/{workspace-types.js → core/workspace-app/workspace-types.js} +0 -0
  630. /package/{workspaces.js → core/workspace-app/workspaces.js} +0 -0
package/README.md CHANGED
@@ -1,380 +1,44 @@
1
- # workspace-app
1
+ # Webship Workspace
2
2
 
3
- The **workspace** web dashboard — a visual UI + AI assistant for this tooling,
4
- served at **https://workspace.ddev.site** through DDEV.
3
+ A container-based development workspace with a web dashboard, for Webship projects: Drupal, Drupal CMS, the Webship products, and whatever else your folders hold. The core ships **empty**. Everything else is a plugin you add when you need it.
5
4
 
6
- Basic Node.js (`node:http`, no framework) + [HTMX](https://htmx.org) (vendored
7
- in `public/htmx.min.js`). All pages are server-rendered; interactions swap in
8
- HTML fragments. Destructive actions ask in one shared confirm dialog — Wait!
9
- Are you sure you want to proceed with this action? — and fire on its Yes alone.
5
+ ![The core, its families and the plugins](core/docs/architecture.svg)
10
6
 
11
- ## What version is this machine on?
12
-
13
- The toolbar says, beside the product name, and `core/workspace-app/scripts/update.sh --check`
14
- says the same thing. Both read **`core/workspace-app/.app-version`**, a file holding a tag and
15
- nothing else.
16
-
17
- It is written by all three things that install this tree, which is the point:
18
-
19
- | | writes the stamp |
20
- | --- | --- |
21
- | `core/scripts/install.sh` | the latest release tag, read from the repository |
22
- | `core/scripts/sync-tooling.sh --pull` | the tag the clone is sitting on |
23
- | `core/workspace-app/scripts/update.sh` | the tag it just installed |
24
-
25
- Before that only the **updater** wrote it, so a machine installed any other way answered
26
- `Installed: (untracked)` and was told an update was available to the version it already had —
27
- for ever. With one person that is a curiosity; across a team it is the support question nobody
28
- can answer, and an update prompt everyone learns to ignore.
29
-
30
- **When it cannot be told, it says so** — `version unknown` in the toolbar, with the three
31
- commands that would set it in the tooltip. A wrong version is worse than an absent one, because
32
- it stops the question being asked.
33
-
34
- `package.json`'s `"version"` is **not** it. That is npm metadata for an app that is never
35
- published, it has said `1.0.0` since the first commit, and a unit test fails if anything starts
36
- displaying it.
37
-
38
- ## One `ddev start` at a time
39
-
40
- Every router-mutating verb — `start`, `stop`, `restart`, `poweroff`, `delete` — tears down the
41
- **one shared** `ddev-router` and rebuilds it with the routes of whatever is running. Two at once
42
- race on a single container, and the loser can leave it removed: every `*.ddev.site` address dies,
43
- the hub included, with healthy web containers behind it, and DDEV then refuses to start anything
44
- until `ddev poweroff`. Five clicks in thirty-eight seconds did exactly that.
45
-
46
- `core/scripts/ddev-shim/ddev` is a wrapper that holds a lock for those five verbs and `exec`s the
47
- real binary for everything else. It is **first on PATH inside the dashboard's container**
48
- (`/usr/local/sbin` precedes `/usr/local/bin`), so it covers the assistant's Bash calls, the
49
- `cmd-*.sh` scripts, the Web IDE's terminals and anyone in `ddev ssh` — not just the buttons.
50
- `install.sh` offers the same file on the host, where it needs root.
51
-
52
- Four rules it lives by, because a wrong wrapper breaks *every* `ddev` call including the
53
- dashboard's own twenty-second status reads:
54
-
55
- 1. the real binary is found by **absolute path** and checked not to be the wrapper — resolving
56
- through PATH would find the wrapper again and fork for ever;
57
- 2. anything that is not a router verb is `exec`'d with **no lock and no subshell** —
58
- `ddev list --json-output` costs what it always cost, and read-only verbs still run in parallel;
59
- 3. **nothing is fatal** — a missing `flock`, an uncreatable lock file, and it says so once and runs
60
- the command anyway, because refusing to run `ddev` is worse than the fault being prevented;
61
- 4. it **never re-locks a lock already held**. The dashboard wraps its own calls, and taking the same
62
- lock from inside deadlocks for the full 1800s timeout — proven by experiment before
63
- `DDEV_ROUTER_LOCK_HELD` existed. Whoever holds the lock sets it; the wrapper exports it onward.
64
-
65
- The shim exists twice, because Docker cannot `COPY` from outside its build context:
66
- `core/scripts/ddev-shim/ddev` is the source, `.ddev/web-build/ddev-shim-ddev` is the copy the image
67
- takes, and a unit test fails if they differ.
68
-
69
- ## The Web IDE (code-server)
70
-
71
- Every project row carries a **Codebase** menu, right after SCREENS, and every document
72
- workspace (`docs`, `worklogs`, `specs`, the `ai-*` folders) carries a **Files** one. Both offer
73
- the same three destinations, and the split is the point — it is GitLab's, and it is what stops
74
- a link that silently does nothing:
75
-
76
- | | opens | needs |
77
- | --- | --- | --- |
78
- | **Web IDE** | VS Code in the browser, at `https://ide.<hub_domain>/?folder=<path>` | nothing — works from any device |
79
- | **Visual Studio Code** | `vscode://file<path>` — the VS Code on the machine the *browser* is running on | the `vscode://` handler, which VS Code registers on install |
80
- | **IntelliJ IDEA** | `jetbrains://idea/open?file=<path>` — likewise, IDEA on that machine | the JetBrains Toolbox URL handler |
81
- | **Copy the path** | the path, for `code <path>` or `idea <path>` in a terminal | nothing |
82
-
83
- **It is code-server, pinned, on its own hostname.** `4.135.0` is baked into
84
- `.ddev/web-build/Dockerfile.workspace-app` from the standalone tarball — pinned because an
85
- editor that changes under people between image rebuilds is a support question nobody can
86
- answer. It runs as a `web_extra_daemon` bound to **127.0.0.1:8443**, and
87
- `.ddev/nginx_full/nginx-site.conf` proxies `ide.workspace.ddev.site` to it. Loopback plus that
88
- one vhost is the whole access control.
89
-
90
- A **hostname, not a subpath**: code-server is a single-page app that builds absolute URLs for
91
- its workers, its websocket and its static assets, and upstream's guidance is a dedicated
92
- (sub)domain. It costs nothing here — `*.workspace` is already in `additional_hostnames`, so
93
- DDEV's router routes it and the project certificate already covers it. The vhost uses an
94
- **exact** `server_name` so it wins over the regex block that sends everything else to the Node
95
- app, and carries the websocket `Upgrade`/`Connection` headers plus long read timeouts —
96
- without those the editor loads and then hangs "reconnecting…", because the terminal, the
97
- extension host and the file watcher are all websockets.
98
-
99
- **Its state lives in the workspace tree**, at `.code-server/` (gitignored): settings,
100
- keybindings and installed extensions survive an image rebuild, which they would not if they
101
- sat in the container.
102
-
103
- **When it is down the menu says so** rather than offering a dead link — a cached loopback
104
- probe, warmed at boot so the first render after a restart already knows. The note names the
105
- fix: `ddev restart`, or `docker exec ddev-workspace-web supervisorctl status`.
106
-
107
- ### What makes it work — the actual options
108
-
109
- **Serving it** (`scripts/code-server-start.sh`, run as a `web_extra_daemon`):
110
-
111
- | flag | why |
112
- | --- | --- |
113
- | `--bind-addr 127.0.0.1:8443` | loopback only; the `ide.*` vhost is the whole access control |
114
- | `--auth none` | see the security note below — not a casual choice |
115
- | `--user-data-dir`, `--extensions-dir` under `.code-server/` | settings and extensions survive an image rebuild |
116
- | `--disable-telemetry`, `--disable-update-check` | nothing phones home; the version is pinned in the image |
117
- | `--app-name 'Webship Workspace IDE'` | the title bar and welcome page say where you are |
118
-
119
- **Nginx**, in `.ddev/nginx_full/nginx-site.conf`: an **exact** `server_name ide.workspace.ddev.site`
120
- (beats the regex block that routes everything else to the Node app), `proxy_set_header Upgrade` +
121
- `Connection $connection_upgrade` with a `map` for it, `proxy_read_timeout 86400s`,
122
- `proxy_buffering off`, `client_max_body_size 0`. The websocket headers are not optional: the
123
- terminal, the extension host and the file watcher are all websockets, and without them the editor
124
- loads and then hangs *reconnecting…*.
125
-
126
- **Editor settings**, seeded once into `.code-server/data/User/settings.json` (never overwritten, so
127
- your own changes stick):
128
-
129
- | setting | why |
130
- | --- | --- |
131
- | `security.workspace.trust.enabled: false` | VS Code opens every folder in **Restricted Mode** and refuses to start a terminal until you answer *"Do you trust the authors…"*. That prompt is for code you downloaded; here every folder is a project on this machine, opened from a dashboard that already offers a shell |
132
- | `terminal.integrated.profiles.linux` → **Claude Code**, **Claude Code (accept edits)** | the terminal dropdown offers them by name, so agents and skills are one click away instead of requiring you to know to type `claude` |
133
- | `files.associations` → `.module`, `.install`, `.theme`, `.profile`, `.engine`, `.inc` as PHP | without it the editor treats the files a Drupal developer opens most as plain text: no highlighting, no outline |
134
- | `files.exclude` / `search.exclude` → `node_modules`, `vendor`, `web/core`, `web/modules/contrib` | a Drupal site is ~21,000 PHP files of which almost none are yours; search is useless otherwise |
135
- | `files.watcherExclude` → the same trees plus `.git/objects`, `graphify-out`, `.ddev` | **one** built Drupal project is ~21,000 directories, 11,800 of them in those three trees, against a kernel limit of 65,536 watches **shared across the machine**. Without this, two open projects and the editor reports *Unable to watch for file changes* and silently stops noticing edits made outside it — a `composer install`, a `git checkout`, an agent |
136
- | `extensions.autoUpdate: "off"` | the same reason code-server is pinned |
137
- | `workbench.startupEditor: "none"`, `update.mode: "none"`, `telemetry.telemetryLevel: "off"` | no welcome page, no update nag, no telemetry |
138
-
139
- ### Claude Code is in the editor, when it is configured
140
-
141
- The official extension (**`Anthropic.claude-code`**, on Open VSX — which is the registry
142
- code-server queries, so no marketplace switch and no `.vsix` juggling) is installed by
143
- `scripts/code-server-start.sh` on first start, and appears in the activity bar with its own
144
- chat (`Ctrl+Alt+I`).
145
-
146
- **Gated on Claude Code being usable here**, which means two things: the `claude` CLI on PATH, and
147
- a credentials file in `~/.claude` (the container bind-mounts it from the host). On a machine where
148
- Claude Code has never been logged in, installing it would put a panel in the editor whose only
149
- behaviour is to ask for a login that belongs on the host — so there the IDE keeps the terminal
150
- profiles and nothing else, and the script says so. Log in on the host with `claude`, then
151
- `ddev restart`.
152
-
153
- Installed **once**, when missing, with a timeout, and never fatally: an editor that will not start
154
- because a registry was slow is worse than an editor without one extension. `extensions.autoUpdate`
155
- is `"off"` for the same reason the code-server version is pinned.
156
-
157
- ### Agents and skills are already loaded
158
-
159
- Nothing to install per project. The IDE runs **inside the dashboard's container**, which bind-mounts
160
- `~/.claude` — so a terminal there has the `claude` CLI with the **same agents, skills and commands as
161
- a session on the host** (86 / 42 / 6 on this machine), and Claude Code reads `CLAUDE.md` and
162
- `AGENTS.md` from the working directory upwards, so the folder's own rules apply automatically.
163
-
164
- In the IDE: **Terminal → new terminal dropdown → Claude Code**. Or type `claude` in any terminal.
165
- Inside it, `@` and `/` list the same items the dashboard's assistant offers, because they are the
166
- same files.
167
-
168
- **For local VS Code / IntelliJ** (the other two entries in the menu) nothing is configured — they
169
- open the folder on your own machine, with your own settings and your own extensions. Agents and
170
- skills come from your own `~/.claude` there, which is the point of that split.
171
-
172
- ### Security posture, stated plainly
173
-
174
- **This dashboard has no authentication, and that is only safe because it is loopback-only.**
175
- It runs shell commands, serves an interactive terminal at `/terminal/<session>`, and a Web IDE
176
- with write access to the whole tree and a terminal of its own — in a container that mounts the
177
- Docker socket and the DDEV registry. Anyone who can reach the port has all of it.
178
-
179
- What keeps that acceptable is that nothing is reachable from the network: DDEV's router binds
180
- `127.0.0.1` (`router_bind_all_interfaces: false`, its default) and the machine answers nothing
181
- on its LAN address.
182
-
183
- **Two settings end that**, and both get changed for a good-looking reason:
184
-
185
- | setting | why someone changes it |
186
- | --- | --- |
187
- | `router_bind_all_interfaces: true` | DDEV documents it for Let's Encrypt, and for reaching a project from a phone |
188
- | `hub_domain: <a public domain>` | this README says the same system runs as a remote hub |
189
-
190
- So both are watched for, in the two places a person will be:
191
-
192
- - **`install.sh --check`** prints `✓ exposure loopback only` or a block naming the setting that
193
- changed and what is reachable because of it;
194
- - **the dashboard itself** shows a banner on every page, not dismissible, because the person who
195
- flips that setting a month later is not running the installer.
196
-
197
- If the hub is ever put on a public domain, the dashboard **and** the IDE need real
198
- authentication in front of them. One decision, not two.
199
-
200
- ### Other things the security pass fixed
201
-
202
- - `core/config/settings.yml` (real API keys) and `.screens/.runner-token` (the screen runner's
203
- entire access control) were **world-readable at `775`** while the CLI-managed secrets beside
204
- them were correctly `600`. Both are `600` now.
205
- - One **high-severity** dependency advisory (`js-yaml`, exponential parsing → DoS) — fixed.
206
- - Security headers were set at **three** `writeHead` sites out of fifty-six, so every page but
207
- the graph viewer went without. They are set once in the request handler now: `nosniff`,
208
- `no-referrer`, `SAMEORIGIN`.
209
-
210
- ### The IDE’s own posture
211
-
212
- `--auth none`. The dashboard has no login of its own until Sign in with Google (`auth.google`) is
213
- turned on, and it already serves a real interactive terminal at `/terminal/<session>`, so a second
214
- password in front of one door would be theatre.
215
- What this means concretely: **anyone who can reach the dashboard's origin can edit any file in
216
- `~/workspace` and run commands in that container**, which has the Docker socket and the DDEV
217
- registry mounted.
218
-
219
- That is acceptable for a local tool on `*.ddev.site` and **not** acceptable on a public
220
- `hub_domain`. If the hub is ever put on a public domain, the IDE *and* the dashboard need real
221
- authentication in front of them — the same decision, not two.
222
-
223
- ## What it does
224
-
225
- - **Home** (`/`): the workspace cards grid — one card per folder in
226
- `core/config/settings.yml`'s `workspaces:` list (read live, so adding a
227
- workspace there shows up without code changes), with live project counts.
228
- - **Per-workspace pages** (`/dev`, `/test`, `/demos`, …): each workspace's own
229
- project list with per-project **Backup / Filemode / Remove** actions, plus a
230
- **Build** form listing that folder's `cmd-*-project.sh` builder scripts.
231
- - **AI Assistant** on every page (inline on home, floating 🤖 widget on
232
- workspace pages): quick actions (New Drupal 11, New Webship, Status) and a
233
- free-text chat backed by the local `claude` CLI in restricted, tool-free
234
- print mode.
235
- - All actions run the real `cmd-*.sh` scripts (and `ddev`) against
236
- `~/workspace` — this is a control panel, not a mock.
237
-
238
- ## Setup
239
-
240
- You need the workspace files and DDEV. The quickest way to the files is the ZIP — no git, no
241
- clone: on [github.com/webship/workspace](https://github.com/webship/workspace) switch to the `1.0.x`
242
- branch, press **Code ▾ → Download ZIP**, unzip it and rename the folder to `~/workspace` (the full
243
- walkthrough, and two other ways, are in the [root README](docs/REFERENCE.md#get-started)).
244
-
245
- Then, once:
7
+ ## Install
246
8
 
247
9
  ```bash
248
- cd ~/workspace/core/workspace-app
249
- ddev start
10
+ # 1. Node.js 20 or newer, Docker, and DDEV (https://ddev.readthedocs.io)
11
+ # 2. The workspace, from npm
12
+ npm install -g @webship.co/workspace
13
+ webship-workspace init ~/workspace # the core, an empty settings file, the dashboard started
250
14
  ```
251
15
 
252
- Then open https://workspace.ddev.site. Everything else — building, starting, stopping, backing up,
253
- restoring and removing projects — can be done from there without another command.
254
-
255
- ### How it runs
256
-
257
- The Node app runs **inside** the DDEV web container as a `web_extra_daemon`,
258
- with Docker-outside-of-Docker so it can manage sibling DDEV projects:
259
-
260
- - `.ddev/docker-compose.dood.yaml` bind-mounts the host's
261
- `/var/run/docker.sock` and your `~/workspace` tree (at the same absolute
262
- path, via `${HOME}` interpolation).
263
- - `.ddev/web-build/Dockerfile.workspace-app` installs the `docker` CLI and the
264
- `ddev` binary in the web image, and aligns the container's `docker` group
265
- GID with the host's.
266
- - `.ddev/nginx_full/nginx-site.conf` proxies the site to the app on
267
- `127.0.0.1:3000` inside the container.
16
+ Open https://workspace.ddev.site. It is empty: no workspace folders, no plugins. Add what you need, one package at a time, from **Settings → Plugins** (the catalogue) or the command line:
268
17
 
269
- ### Per-machine adjustments
270
-
271
- - **docker group GID — handled for you.** The container has to share this
272
- host's docker GID or every `ddev` command inside it fails with a permission
273
- error, and the symptom is a dashboard where every project reads as Stopped
274
- forever while running perfectly well. Two files carry the number: the
275
- `groupmod`/`usermod` line in `.ddev/web-build/Dockerfile.workspace-app`
276
- (which is what `sg docker` in the supervisord command resolves) and
277
- `group_add` in `.ddev/docker-compose.dood.yaml` (which is what actually puts
278
- the running process in the group — DDEV pins `user: 1000:1000`, so a
279
- build-time `usermod` never reaches it).
280
-
281
- `core/scripts/docker-gid.sh` writes both from the host's socket.
282
- `core/scripts/install.sh` runs it at setup and reports it in its survey, and
283
- `core/scripts/sync-tooling.sh` runs it **after** mirroring — this directory is
284
- mirrored wholesale, so a hand edit would be overwritten by the next `--pull`.
285
- Check it any time:
286
-
287
- ```
288
- bash core/scripts/docker-gid.sh --check
289
- ```
290
- - **The DDEV project registry** (`~/.ddev`) is bind-mounted in, so `ddev list`
291
- in here sees the same projects as the host. Without it the container has its
292
- own empty registry and reports one project — itself — which produces the same
293
- "everything is Stopped" symptom by a different route.
294
- - **Bind-mounted host paths are a trap Docker sets.** A bind mount whose source
295
- does not exist is *created* — as a directory, owned by root. Every optional tool
296
- the dashboard shares from the host is such a source, so on a machine without
297
- `twg` the first start used to create `~/.local/bin/twg` **and `~/.local/bin`**
298
- as root: the JIRA button then never appeared however complete `jira:` was, and
299
- nothing could install a user binary there any more, including the
300
- `drupal-ci-local` wrapper the GitLab CI green-gate writes.
301
-
302
- `core/scripts/host-mounts.sh` creates each of those paths as you before Docker
303
- can, and comments the `twg` volume out of `.ddev/docker-compose.twg.yaml` while
304
- `twg` is not installed — restoring it the moment it is. It runs from the
305
- project's own `pre-start` hook and from `install.sh`. `--check` reports without
306
- changing anything, and it names the paths only root can hand back.
307
- - **Jira** needs the Teamwork Graph CLI on the host:
308
- [teamworkgraph.com/cli](https://teamworkgraph.com/cli) ·
309
- [developer.atlassian.com/cloud/twg-cli](https://developer.atlassian.com/cloud/twg-cli/)
310
- ```
311
- curl -fsSL --retry 2 https://teamwork-graph.atlassian.com/cli/install | bash
312
- ~/.local/bin/twg doctor
313
- ```
314
- It is mounted in rather than installed in the image: one binary, one OAuth
315
- session, and `twg login` on the host reaches the container instantly. When it is
316
- absent the JIRA button renders **disabled**, with the reason in its tooltip,
317
- rather than vanishing.
318
- - **Upsun** needs its CLI on the host, mounted in the same way and for the same
319
- reason as `twg` — one binary, one session:
320
- [developer.upsun.com/cli](https://developer.upsun.com/cli)
321
-
322
- Upsun's own installer sets up an apt repository, so it needs root and an
323
- interactive password; in a pipe it fails with *"sudo: A terminal is required to
324
- authenticate"*. `install.sh` therefore prefers the **release tarball** — one
325
- static binary into `~/.local/bin`, no root at all — and falls back to the
326
- official installer only if GitHub is unreachable:
18
+ ```bash
19
+ webship-workspace plugin require dev # npm install @webship.co/workspace-dev into the dashboard
20
+ webship-workspace plugin activate dev # on the workspaces list
21
+ webship-workspace plugin install dev # the folder, its settings file, its commands
22
+ webship-workspace catalog # everything you can add
23
+ ```
327
24
 
328
- ```
329
- ver=$(wget -qO- https://api.github.com/repos/upsun/cli/releases/latest \
330
- | sed -n 's/.*"tag_name": *"v\([^"]*\)".*/\1/p' | head -1)
331
- wget -qO- https://github.com/upsun/cli/releases/download/v$ver/upsun_${ver}_linux_amd64.tar.gz \
332
- | tar -xz -C /tmp upsun && install -m 0755 /tmp/upsun ~/.local/bin/upsun
333
- upsun login # browser OAuth; writes SSH certificates
334
- ```
25
+ Nothing is added to `package.json` until you ask for it. The skeleton and the management stay in the core.
335
26
 
336
- **The dashboard needs its own credential, and this is not optional.** `upsun login`
337
- writes a session into the host keyring, and a container cannot reach a keyring — so
338
- every UPSUN action in the dashboard (the environment list, the live URLs, *Get
339
- database & files*) authenticates with an API **token** instead:
27
+ ## What a plugin is
340
28
 
341
- ```yaml
342
- # core/config/settings.yml
343
- upsun:
344
- cli_token: … # Upsun console → My profile → API tokens
345
- ```
29
+ An npm package `@webship.co/workspace-<name>` (repository `github.com/webship/workspace-<name>`, branch `1.0.x`), written in TypeScript against `@webship.co/workspace-plugin-api`. Families share a base: hosting providers (`upsun`, `acquia`, `digitalocean`, `cpanel`, `aws`, `azure`, `godaddy`), git forges (`github`, `gitlab`, `bitbucket`), container runtimes (`docker`, `lando`, `docksal`, `podman`, `kubernetes`), and every workspace folder (`dev`, `test`, `drupal-modules`, `drupal-themes`, `docs`, `images`, `ai-agents`, …) is a plugin too.
346
30
 
347
- `upsunJobEnv()` injects it as `UPSUN_CLI_TOKEN` for each CLI call. Without it the
348
- actions answer *"No Upsun API token configured"*; with the wrong **kind** of token
349
- they answer *"The request could not be authorized. Unable to authenticate the
350
- provided API token"* — which reads like an expiry. An **Atlassian** token in that
351
- field, recognisable because they start `ATATT`, produces exactly that message.
352
- `bash core/scripts/install.sh --check` reports the field by shape, never its value.
31
+ ## Read more
353
32
 
354
- Two related details worth keeping:
33
+ **New here?** The dashboard's own guide is in [core/workspace-app/docs](core/workspace-app/docs): the [user guide](core/workspace-app/docs/USER-GUIDE.md) for the pages and what each button does (also served at `/help`), and the [developer guide](core/workspace-app/docs/DEVELOPER-GUIDE.md) for how the app is built.
355
34
 
356
- - **The CLI prints the reason FIRST and a usage synopsis LAST.** These errors are
357
- rendered through `cliError()` in `format.js`, which drops the synopsis and keeps
358
- the head — a tail slice showed a list of flags and threw the reason away.
359
- - **It hard-wraps mid-word.** The real output is `provided AP` / newline / `I token.`,
360
- so matching its text has to survive the wrap; the check in `actions/upsun.js` does.
361
- - **Chat**: the assistant chat shells out to the `claude` CLI **inside the
362
- container** (installed in the web image via `npm install -g
363
- @anthropic-ai/claude-code`); it authenticates through your host's
364
- `~/.claude` + `~/.claude.json`, which are bind-mounted in. If you've never
365
- logged in to Claude Code on the host, run `claude` there once first.
366
- - **Voice input**: the mic button uses the browser's Web Speech API
367
- (Chrome/Edge; hidden automatically on browsers without support).
35
+ - [Getting started](core/docs/getting-started.md) — the first hour: install, add a workspace folder, build a site.
36
+ - [Plugins](core/docs/plugins.md) — the four steps, the families, writing one.
37
+ - [Workspaces](core/docs/workspaces.md) — folders, types, builders and the `cmd-*.sh` commands.
38
+ - [Testing](core/docs/testing.md) — unit tests and the webship-js browser suite.
39
+ - [Releases](core/docs/releases.md) — versions, npm, and how changes land (issues and pull requests).
40
+ - [The plugin contract](core/workspace-app/PLUGINS.md) — the manifest and the api, for plugin authors.
368
41
 
369
- ## Security note
42
+ ## License
370
43
 
371
- This app executes shell scripts with real side effects (build, backup,
372
- **delete**) and has host-Docker access. The AI assistant runs in **agent
373
- mode**: its `claude -p` calls are allowed Bash/Read/Glob/Grep inside the
374
- container (Write/Edit stay disallowed, and its instructions forbid deleting
375
- anything unasked), so a chat message can really build, start, stop, back up
376
- and open projects — and steer the page afterwards via NAVIGATE/OPEN/REFRESH
377
- directives. Every action and chat message is appended to `actions.log`.
378
- It binds only to the DDEV-internal port and is meant for local development
379
- machines — do not expose `workspace.ddev.site` beyond localhost without
380
- adding authentication.
44
+ GPL-2.0-or-later. Made by [Webship](https://webship.co).
@@ -0,0 +1,135 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * webship-workspace — install and manage a Webship Workspace from npm.
4
+ *
5
+ * webship-workspace init [dir] make a workspace at dir (default ~/workspace): the core, an
6
+ * empty settings file, the dashboard installed and started
7
+ * webship-workspace plugin <verb> <name> require | activate | install | configure | deactivate | uninstall | list
8
+ * webship-workspace catalog the plugins you can add, by family
9
+ * webship-workspace update [dir] refresh the core of an existing workspace from this package
10
+ *
11
+ * The core ships empty: no workspace folders, no plugins. Everything is added later, one npm package
12
+ * at a time, when you ask for it (`plugin require <name>` is `npm install @webship.co/workspace-<name>`
13
+ * into the dashboard's package.json). The skeleton and the management stay in the core.
14
+ *
15
+ * Plain Node, no dependencies: this runs before anything is installed. Env for tests:
16
+ * WEBSHIP_WORKSPACE_SKIP_NPM=1 do not run npm install in the dashboard
17
+ * WEBSHIP_WORKSPACE_SKIP_DDEV=1 do not start the dashboard
18
+ */
19
+
20
+ const fs = require('fs');
21
+ const os = require('os');
22
+ const path = require('path');
23
+ const { spawnSync } = require('child_process');
24
+
25
+ const PKG_ROOT = path.resolve(__dirname, '..', '..'); // the package: core/, README.md, LICENSE
26
+ const CORE_SRC = path.join(PKG_ROOT, 'core');
27
+
28
+ const say = (s) => process.stdout.write(`${s}\n`);
29
+ const fail = (s, code = 1) => { process.stderr.write(`${s}\n`); process.exit(code); };
30
+
31
+ function run(cmd, args, cwd, env = {}) {
32
+ const r = spawnSync(cmd, args, { cwd, stdio: 'inherit', env: { ...process.env, ...env } });
33
+ if (r.error) fail(`${cmd} could not be run: ${r.error.message}`);
34
+ return r.status === 0;
35
+ }
36
+
37
+ /** Copy core/ into the workspace, skipping what belongs to a running install, never overwriting a settings file. */
38
+ function copyCore(dest) {
39
+ const SKIP = new Set(['node_modules', 'actions.log', 'package-lock.json']);
40
+ // This machine's own files are never copied from the package: settings.yml comes from the lean
41
+ // template (once), workspace and plugin settings come with their plugins, the install record is local.
42
+ const NEVER = /^core\/config\/(settings\.yml|workspace\..*\.settings\.yml|plugin\..*\.settings\.yml|plugins\.installed\.yml)$|^core\/workspace-app\/\.ddev\/config\.local\.yaml$/;
43
+ const KEEP_IF_PRESENT = /^core\/config\/style\.yml$/;
44
+ const walk = (src, rel) => {
45
+ for (const e of fs.readdirSync(src, { withFileTypes: true })) {
46
+ if (SKIP.has(e.name)) continue;
47
+ const from = path.join(src, e.name);
48
+ const relPath = path.join(rel, e.name);
49
+ const to = path.join(dest, relPath);
50
+ if (e.isDirectory()) { fs.mkdirSync(to, { recursive: true }); walk(from, relPath); continue; }
51
+ if (NEVER.test(relPath)) continue;
52
+ if (KEEP_IF_PRESENT.test(relPath) && fs.existsSync(to)) continue;
53
+ fs.mkdirSync(path.dirname(to), { recursive: true });
54
+ fs.copyFileSync(from, to);
55
+ fs.chmodSync(to, fs.statSync(from).mode & 0o777);
56
+ }
57
+ };
58
+ walk(CORE_SRC, 'core');
59
+ // The dashboard's version chip reads this file, never package.json (an installation is not the package).
60
+ fs.writeFileSync(path.join(dest, 'core', 'workspace-app', '.app-version'), require(path.join(PKG_ROOT, 'package.json')).version + '\n');
61
+ for (const f of ['README.md', 'LICENSE']) if (fs.existsSync(path.join(PKG_ROOT, f)) && !fs.existsSync(path.join(dest, f))) fs.copyFileSync(path.join(PKG_ROOT, f), path.join(dest, f));
62
+ }
63
+
64
+ /** settings.yml from the lean template: an empty workspaces list, no plugins, the placeholders to fill. */
65
+ function writeSettings(dest) {
66
+ const file = path.join(dest, 'core', 'config', 'settings.yml');
67
+ if (fs.existsSync(file)) return false;
68
+ const template = path.join(CORE_SRC, 'config', 'settings.template.yml');
69
+ fs.copyFileSync(template, file);
70
+ fs.chmodSync(file, 0o600);
71
+ return true;
72
+ }
73
+
74
+ function catalogText() {
75
+ const { FAMILIES, SCOPE } = require(path.join(CORE_SRC, 'workspace-app', 'plugin-catalog.js'));
76
+ const lines = ['What you can add (one npm package each; nothing is installed until you ask):', ''];
77
+ for (const f of FAMILIES) {
78
+ lines.push(`${f.label} — ${f.about}`);
79
+ for (const [name, label] of f.plugins) lines.push(` ${name.padEnd(24)} ${label} (${SCOPE}/workspace-${name})`);
80
+ lines.push('');
81
+ }
82
+ lines.push('Add one: webship-workspace plugin require <name> then activate, install, configure — or Settings → Plugins in the dashboard.');
83
+ return lines.join('\n');
84
+ }
85
+
86
+ function init(dirArg, { update = false } = {}) {
87
+ const dest = path.resolve(dirArg || process.env.WEBSHIP_WORKSPACE_DIR || path.join(os.homedir(), 'workspace'));
88
+ fs.mkdirSync(dest, { recursive: true });
89
+ say(`${update ? 'Updating' : 'Making'} the Webship Workspace at ${dest}`);
90
+ copyCore(dest);
91
+ const wroteSettings = writeSettings(dest);
92
+ say(wroteSettings ? ' core/config/settings.yml written (empty: no workspaces, no plugins yet)' : ' core/config/settings.yml kept as it is');
93
+ const app = path.join(dest, 'core', 'workspace-app');
94
+ if (!process.env.WEBSHIP_WORKSPACE_SKIP_NPM) {
95
+ say(' installing the dashboard (npm install in core/workspace-app)…');
96
+ if (!run('npm', ['install', '--no-audit', '--no-fund'], app)) fail('npm install failed in core/workspace-app.');
97
+ }
98
+ if (!process.env.WEBSHIP_WORKSPACE_SKIP_DDEV) {
99
+ const ddev = spawnSync('ddev', ['--version'], { encoding: 'utf8' });
100
+ if (ddev.error || ddev.status !== 0) {
101
+ say(' DDEV is not installed: the dashboard runs in a DDEV project. Install it (https://ddev.readthedocs.io) and run: webship-workspace init ' + (dirArg || ''));
102
+ } else {
103
+ say(' starting the dashboard (ddev start in core/workspace-app)…');
104
+ run('ddev', ['start', '-y'], app);
105
+ }
106
+ }
107
+ say('');
108
+ say(`Done. The dashboard: https://workspace.ddev.site (the tooling: ${dest}/core/scripts)`);
109
+ say('');
110
+ say(catalogText());
111
+ }
112
+
113
+ function plugin(verb, name) {
114
+ const verbs = ['require', 'activate', 'install', 'configure', 'deactivate', 'uninstall', 'list', 'restart'];
115
+ if (!verbs.includes(verb)) fail(`plugin <${verbs.join('|')}> [name]`);
116
+ const root = process.env.WORKSPACE_ROOT || path.resolve(process.env.WEBSHIP_WORKSPACE_DIR || path.join(os.homedir(), 'workspace'));
117
+ const script = path.join(root, 'core', 'scripts', 'plugins.sh');
118
+ if (!fs.existsSync(script)) fail(`No workspace at ${root} (core/scripts/plugins.sh is missing). Run: webship-workspace init`);
119
+ // A bare name means the npm package of that name: `plugin require git` is `npm install @webship.co/workspace-git`.
120
+ const spec = verb === 'require' && name && !/[@:/]/.test(name) ? `@webship.co/workspace-${name}` : name;
121
+ const args = [script, `--${verb}`];
122
+ if (spec) args.push(spec);
123
+ process.exit(run('bash', args, root) ? 0 : 1);
124
+ }
125
+
126
+ const [cmd, ...rest] = process.argv.slice(2);
127
+ switch (cmd) {
128
+ case 'init': init(rest[0]); break;
129
+ case 'update': init(rest[0], { update: true }); break;
130
+ case 'plugin': plugin(rest[0], rest[1]); break;
131
+ case 'catalog': say(catalogText()); break;
132
+ default:
133
+ say(fs.readFileSync(__filename, 'utf8').split('\n').slice(2, 14).map((l) => l.replace(/^ \* ?/, '')).join('\n'));
134
+ process.exit(cmd ? 1 : 0);
135
+ }