@webship.co/workspace 1.0.0-alpha1 → 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 (634) 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/{PLUGINS.md → core/workspace-app/PLUGINS.md} +1 -1
  160. package/core/workspace-app/README.md +380 -0
  161. package/{actions → core/workspace-app/actions}/ddev.js +0 -1
  162. package/{actions → core/workspace-app/actions}/rag.js +0 -1
  163. package/{actions → core/workspace-app/actions}/testing.js +0 -1
  164. package/{assistant.js → core/workspace-app/assistant.js} +1 -10
  165. package/{git-info.js → core/workspace-app/git-info.js} +17 -1
  166. package/core/workspace-app/package.json +29 -0
  167. package/core/workspace-app/plugin-catalog.js +50 -0
  168. package/{plugin-loader.js → core/workspace-app/plugin-loader.js} +19 -1
  169. package/{plugins-page.js → core/workspace-app/plugins-page.js} +28 -2
  170. package/{row-layout.js → core/workspace-app/row-layout.js} +0 -1
  171. package/{server.js → core/workspace-app/server.js} +26 -225
  172. package/core/workspace-app/tests/features/actions-rail.feature +44 -0
  173. package/core/workspace-app/tests/features/ai-items.feature +23 -0
  174. package/core/workspace-app/tests/features/assistant-speech.feature +63 -0
  175. package/core/workspace-app/tests/features/checks.feature +39 -0
  176. package/core/workspace-app/tests/features/clone-project.feature +30 -0
  177. package/core/workspace-app/tests/features/command-authoring.feature +58 -0
  178. package/core/workspace-app/tests/features/dashboard.feature +57 -0
  179. package/core/workspace-app/tests/features/menus.feature +29 -0
  180. package/core/workspace-app/tests/features/plugins/jira/jira.feature +47 -0
  181. package/core/workspace-app/tests/features/plugins.feature +20 -0
  182. package/core/workspace-app/tests/features/project-actions.feature +40 -0
  183. package/core/workspace-app/tests/features/screens.feature +29 -0
  184. package/core/workspace-app/tests/features/settings.feature +46 -0
  185. package/core/workspace-app/tests/features/test-reports.feature +32 -0
  186. package/core/workspace-app/tests/features/theme.feature +40 -0
  187. package/core/workspace-app/tests/step-definitions/actions-post.steps.js +25 -0
  188. package/core/workspace-app/tests/step-definitions/assistant-speech.steps.js +152 -0
  189. package/core/workspace-app/tests/step-definitions/preconditions.steps.js +100 -0
  190. package/core/workspace-app/tests/unit/_isolated-config.js +31 -0
  191. package/core/workspace-app/tests/unit/accessibility.test.js +124 -0
  192. package/core/workspace-app/tests/unit/actions-rail-ux.test.js +56 -0
  193. package/core/workspace-app/tests/unit/actions-rail.test.js +51 -0
  194. package/core/workspace-app/tests/unit/ai-inventory.test.js +64 -0
  195. package/core/workspace-app/tests/unit/app-docs.test.js +64 -0
  196. package/core/workspace-app/tests/unit/assistant-avatar.test.js +110 -0
  197. package/core/workspace-app/tests/unit/assistant-cast.test.js +105 -0
  198. package/core/workspace-app/tests/unit/assistant-send-animation.test.js +15 -0
  199. package/core/workspace-app/tests/unit/assistant-suggestions.test.js +112 -0
  200. package/core/workspace-app/tests/unit/assistant-switches.test.js +53 -0
  201. package/core/workspace-app/tests/unit/assistant-views.test.js +146 -0
  202. package/core/workspace-app/tests/unit/assistant-working-indicator.test.js +49 -0
  203. package/core/workspace-app/tests/unit/assistant.test.js +61 -0
  204. package/core/workspace-app/tests/unit/audio-player.test.js +147 -0
  205. package/core/workspace-app/tests/unit/audio-voice.test.js +634 -0
  206. package/core/workspace-app/tests/unit/auth-google.test.js +180 -0
  207. package/core/workspace-app/tests/unit/autostart-watch.test.js +76 -0
  208. package/core/workspace-app/tests/unit/browsers.test.js +76 -0
  209. package/core/workspace-app/tests/unit/build-distribution.test.js +125 -0
  210. package/core/workspace-app/tests/unit/build-order.test.js +153 -0
  211. package/core/workspace-app/tests/unit/builder-args.test.js +113 -0
  212. package/core/workspace-app/tests/unit/builders.test.js +158 -0
  213. package/core/workspace-app/tests/unit/card-state-toggle.test.js +29 -0
  214. package/core/workspace-app/tests/unit/changelog.test.js +177 -0
  215. package/core/workspace-app/tests/unit/chat-thread.test.js +92 -0
  216. package/core/workspace-app/tests/unit/checks-plan.test.js +205 -0
  217. package/core/workspace-app/tests/unit/claude-args.test.js +182 -0
  218. package/core/workspace-app/tests/unit/claude-code-here.test.js +15 -0
  219. package/core/workspace-app/tests/unit/claude-resume.test.js +147 -0
  220. package/core/workspace-app/tests/unit/claude-screen-options.test.js +84 -0
  221. package/core/workspace-app/tests/unit/claude-session.test.js +41 -0
  222. package/core/workspace-app/tests/unit/command-flags.test.js +45 -0
  223. package/core/workspace-app/tests/unit/command-palette.test.js +105 -0
  224. package/core/workspace-app/tests/unit/commands-center.test.js +338 -0
  225. package/core/workspace-app/tests/unit/composer-menu.test.js +187 -0
  226. package/core/workspace-app/tests/unit/config-yaml.test.js +116 -0
  227. package/core/workspace-app/tests/unit/confirm-dialog.test.js +69 -0
  228. package/core/workspace-app/tests/unit/create-card.test.js +85 -0
  229. package/core/workspace-app/tests/unit/ddev-addons.test.js +144 -0
  230. package/core/workspace-app/tests/unit/ddev-auth-ssh.test.js +40 -0
  231. package/core/workspace-app/tests/unit/ddev-custom-commands.test.js +56 -0
  232. package/core/workspace-app/tests/unit/ddev-diagnose.test.js +57 -0
  233. package/core/workspace-app/tests/unit/ddev-domains.test.js +153 -0
  234. package/core/workspace-app/tests/unit/ddev-hostnames.test.js +143 -0
  235. package/core/workspace-app/tests/unit/ddev-import.test.js +82 -0
  236. package/core/workspace-app/tests/unit/ddev-mail.test.js +135 -0
  237. package/core/workspace-app/tests/unit/ddev-menu-and-create.test.js +28 -0
  238. package/core/workspace-app/tests/unit/ddev-mutagen.test.js +37 -0
  239. package/core/workspace-app/tests/unit/ddev-options.test.js +51 -0
  240. package/core/workspace-app/tests/unit/ddev-share.test.js +40 -0
  241. package/core/workspace-app/tests/unit/ddev-shim.test.js +57 -0
  242. package/core/workspace-app/tests/unit/ddev-snapshots.test.js +142 -0
  243. package/core/workspace-app/tests/unit/ddev-start-daemons.test.js +62 -0
  244. package/core/workspace-app/tests/unit/ddev-xdebug.test.js +41 -0
  245. package/core/workspace-app/tests/unit/deep-chat-origin.test.js +38 -0
  246. package/core/workspace-app/tests/unit/density.test.js +52 -0
  247. package/core/workspace-app/tests/unit/elevenlabs.test.js +453 -0
  248. package/core/workspace-app/tests/unit/event-log.test.js +102 -0
  249. package/core/workspace-app/tests/unit/favicon.test.js +68 -0
  250. package/core/workspace-app/tests/unit/files-browser.test.js +224 -0
  251. package/core/workspace-app/tests/unit/git-info.test.js +26 -0
  252. package/core/workspace-app/tests/unit/grid-and-list.test.js +103 -0
  253. package/core/workspace-app/tests/unit/host-tool-wrapper.test.js +18 -0
  254. package/core/workspace-app/tests/unit/html-patterns.test.js +51 -0
  255. package/core/workspace-app/tests/unit/ide-infra.test.js +28 -0
  256. package/core/workspace-app/tests/unit/images-ai.test.js +201 -0
  257. package/core/workspace-app/tests/unit/images-create.test.js +59 -0
  258. package/core/workspace-app/tests/unit/images-providers.test.js +248 -0
  259. package/core/workspace-app/tests/unit/images-svg.test.js +213 -0
  260. package/core/workspace-app/tests/unit/images-workspace.test.js +144 -0
  261. package/core/workspace-app/tests/unit/jobs-fragment.test.js +66 -0
  262. package/core/workspace-app/tests/unit/media-ux.test.js +164 -0
  263. package/core/workspace-app/tests/unit/modal-fit.test.js +87 -0
  264. package/core/workspace-app/tests/unit/modules-load.test.js +23 -0
  265. package/core/workspace-app/tests/unit/narration.test.js +186 -0
  266. package/core/workspace-app/tests/unit/navigation-editor.test.js +260 -0
  267. package/core/workspace-app/tests/unit/navigation.test.js +254 -0
  268. package/core/workspace-app/tests/unit/new-folder.test.js +121 -0
  269. package/core/workspace-app/tests/unit/new-screen-form.test.js +149 -0
  270. package/core/workspace-app/tests/unit/node-menu.test.js +161 -0
  271. package/core/workspace-app/tests/unit/notes.test.js +128 -0
  272. package/core/workspace-app/tests/unit/page-structure.test.js +40 -0
  273. package/core/workspace-app/tests/unit/page-width.test.js +59 -0
  274. package/core/workspace-app/tests/unit/php-version.test.js +90 -0
  275. package/core/workspace-app/tests/unit/plan-card.test.js +44 -0
  276. package/core/workspace-app/tests/unit/plugin-catalog.test.js +31 -0
  277. package/core/workspace-app/tests/unit/plugin-system.test.js +251 -0
  278. package/core/workspace-app/tests/unit/plugins-page.test.js +28 -0
  279. package/core/workspace-app/tests/unit/plugins.test.js +58 -0
  280. package/core/workspace-app/tests/unit/project-activity-filter.test.js +180 -0
  281. package/core/workspace-app/tests/unit/project-make.test.js +143 -0
  282. package/core/workspace-app/tests/unit/project-name.test.js +202 -0
  283. package/core/workspace-app/tests/unit/reader.test.js +62 -0
  284. package/core/workspace-app/tests/unit/release.test.js +92 -0
  285. package/core/workspace-app/tests/unit/remove-confirm.test.js +37 -0
  286. package/core/workspace-app/tests/unit/report-pdf.test.js +171 -0
  287. package/core/workspace-app/tests/unit/round-11.test.js +31 -0
  288. package/core/workspace-app/tests/unit/round-12.test.js +37 -0
  289. package/core/workspace-app/tests/unit/row-layout.test.js +585 -0
  290. package/core/workspace-app/tests/unit/row-menus-fold.test.js +29 -0
  291. package/core/workspace-app/tests/unit/rows-add-modal.test.js +68 -0
  292. package/core/workspace-app/tests/unit/screen-runner-queue.test.js +41 -0
  293. package/core/workspace-app/tests/unit/screen-window.test.js +116 -0
  294. package/core/workspace-app/tests/unit/screens-beside-running.test.js +19 -0
  295. package/core/workspace-app/tests/unit/screens-columns.test.js +79 -0
  296. package/core/workspace-app/tests/unit/screens-menu.test.js +84 -0
  297. package/core/workspace-app/tests/unit/screens-modal-overlay.test.js +14 -0
  298. package/core/workspace-app/tests/unit/screens-waiting.test.js +129 -0
  299. package/core/workspace-app/tests/unit/screens.test.js +74 -0
  300. package/core/workspace-app/tests/unit/second-storage.test.js +218 -0
  301. package/core/workspace-app/tests/unit/session-name.test.js +64 -0
  302. package/core/workspace-app/tests/unit/settings-file.test.js +173 -0
  303. package/core/workspace-app/tests/unit/settings-nested-list.test.js +54 -0
  304. package/core/workspace-app/tests/unit/settings-raw.test.js +177 -0
  305. package/core/workspace-app/tests/unit/shared-prefs.test.js +49 -0
  306. package/core/workspace-app/tests/unit/speech.test.js +290 -0
  307. package/core/workspace-app/tests/unit/static-caching.test.js +39 -0
  308. package/core/workspace-app/tests/unit/status-language.test.js +47 -0
  309. package/core/workspace-app/tests/unit/tab-modal.test.js +69 -0
  310. package/core/workspace-app/tests/unit/tab-title.test.js +37 -0
  311. package/core/workspace-app/tests/unit/template-literals.test.js +52 -0
  312. package/core/workspace-app/tests/unit/terminal-scrollback.test.js +61 -0
  313. package/core/workspace-app/tests/unit/terminal-size.test.js +103 -0
  314. package/core/workspace-app/tests/unit/terminal-style.test.js +84 -0
  315. package/core/workspace-app/tests/unit/terminal-windows.test.js +154 -0
  316. package/core/workspace-app/tests/unit/themes.test.js +453 -0
  317. package/core/workspace-app/tests/unit/tool-labels.test.js +34 -0
  318. package/core/workspace-app/tests/unit/topbar-icons.test.js +47 -0
  319. package/core/workspace-app/tests/unit/update-docker-gid.test.js +51 -0
  320. package/core/workspace-app/tests/unit/user-guide.test.js +60 -0
  321. package/core/workspace-app/tests/unit/version-check.test.js +98 -0
  322. package/core/workspace-app/tests/unit/version-link.test.js +50 -0
  323. package/core/workspace-app/tests/unit/video-borrow.test.js +198 -0
  324. package/core/workspace-app/tests/unit/video-edit-ask.test.js +93 -0
  325. package/core/workspace-app/tests/unit/video-edit-short.test.js +42 -0
  326. package/core/workspace-app/tests/unit/video-edit.test.js +417 -0
  327. package/core/workspace-app/tests/unit/video-transcript.test.js +237 -0
  328. package/core/workspace-app/tests/unit/waiting.test.js +48 -0
  329. package/core/workspace-app/tests/unit/wordpress-odoo-builders.test.js +38 -0
  330. package/core/workspace-app/tests/unit/workspace-bin.test.js +48 -0
  331. package/core/workspace-app/tests/unit/workspace-card-tools.test.js +30 -0
  332. package/core/workspace-app/tests/unit/workspace-delete.test.js +77 -0
  333. package/core/workspace-app/tests/unit/workspace-types.test.js +68 -0
  334. package/core/workspace-app/tests/unit/worktree-clone.test.js +250 -0
  335. package/{workspace-types.js → core/workspace-app/workspace-types.js} +2 -2
  336. package/{workspaces.js → core/workspace-app/workspaces.js} +1 -5
  337. package/package.json +38 -36
  338. package/actions/graphs.js +0 -107
  339. package/actions/obsidian.js +0 -59
  340. package/graphs.js +0 -104
  341. package/obsidian.js +0 -405
  342. /package/{WORKSPACES.md → core/workspace-app/WORKSPACES.md} +0 -0
  343. /package/{actions → core/workspace-app/actions}/ai-items.js +0 -0
  344. /package/{actions → core/workspace-app/actions}/audio.js +0 -0
  345. /package/{actions → core/workspace-app/actions}/build-order.js +0 -0
  346. /package/{actions → core/workspace-app/actions}/checks.js +0 -0
  347. /package/{actions → core/workspace-app/actions}/claude-session.js +0 -0
  348. /package/{actions → core/workspace-app/actions}/commands-center.js +0 -0
  349. /package/{actions → core/workspace-app/actions}/composer.js +0 -0
  350. /package/{actions → core/workspace-app/actions}/ddev-addons.js +0 -0
  351. /package/{actions → core/workspace-app/actions}/ddev-mail.js +0 -0
  352. /package/{actions → core/workspace-app/actions}/folders.js +0 -0
  353. /package/{actions → core/workspace-app/actions}/images-svg.js +0 -0
  354. /package/{actions → core/workspace-app/actions}/images.js +0 -0
  355. /package/{actions → core/workspace-app/actions}/navigation.js +0 -0
  356. /package/{actions → core/workspace-app/actions}/node.js +0 -0
  357. /package/{actions → core/workspace-app/actions}/notes.js +0 -0
  358. /package/{actions → core/workspace-app/actions}/plugins.js +0 -0
  359. /package/{actions → core/workspace-app/actions}/project-make.js +0 -0
  360. /package/{actions → core/workspace-app/actions}/row-actions.js +0 -0
  361. /package/{actions → core/workspace-app/actions}/screens.js +0 -0
  362. /package/{actions → core/workspace-app/actions}/video-edit.js +0 -0
  363. /package/{ai-inventory.js → core/workspace-app/ai-inventory.js} +0 -0
  364. /package/{ai-items.js → core/workspace-app/ai-items.js} +0 -0
  365. /package/{assistant-cast.js → core/workspace-app/assistant-cast.js} +0 -0
  366. /package/{assistant-suggestions.js → core/workspace-app/assistant-suggestions.js} +0 -0
  367. /package/{audio-voice.js → core/workspace-app/audio-voice.js} +0 -0
  368. /package/{auth-google.js → core/workspace-app/auth-google.js} +0 -0
  369. /package/{build-ai.js → core/workspace-app/build-ai.js} +0 -0
  370. /package/{build-order-page.js → core/workspace-app/build-order-page.js} +0 -0
  371. /package/{build-order.js → core/workspace-app/build-order.js} +0 -0
  372. /package/{builder-args.js → core/workspace-app/builder-args.js} +0 -0
  373. /package/{changelog.js → core/workspace-app/changelog.js} +0 -0
  374. /package/{chat-threads.js → core/workspace-app/chat-threads.js} +0 -0
  375. /package/{checks.js → core/workspace-app/checks.js} +0 -0
  376. /package/{claude-args.js → core/workspace-app/claude-args.js} +0 -0
  377. /package/{claude-sessions.js → core/workspace-app/claude-sessions.js} +0 -0
  378. /package/{command-author.js → core/workspace-app/command-author.js} +0 -0
  379. /package/{command-block.js → core/workspace-app/command-block.js} +0 -0
  380. /package/{commands → core/workspace-app/commands}/defaults.yml +0 -0
  381. /package/{commands-page.js → core/workspace-app/commands-page.js} +0 -0
  382. /package/{commands.js → core/workspace-app/commands.js} +0 -0
  383. /package/{cucumber.js → core/workspace-app/cucumber.js} +0 -0
  384. /package/{ddev-addons-page.js → core/workspace-app/ddev-addons-page.js} +0 -0
  385. /package/{ddev-addons.js → core/workspace-app/ddev-addons.js} +0 -0
  386. /package/{ddev-custom-commands.js → core/workspace-app/ddev-custom-commands.js} +0 -0
  387. /package/{ddev-domains.js → core/workspace-app/ddev-domains.js} +0 -0
  388. /package/{ddev-import.js → core/workspace-app/ddev-import.js} +0 -0
  389. /package/{ddev-mail-page.js → core/workspace-app/ddev-mail-page.js} +0 -0
  390. /package/{ddev-mail.js → core/workspace-app/ddev-mail.js} +0 -0
  391. /package/{ddev-options.js → core/workspace-app/ddev-options.js} +0 -0
  392. /package/{ddev-snapshots.js → core/workspace-app/ddev-snapshots.js} +0 -0
  393. /package/{ddev.js → core/workspace-app/ddev.js} +0 -0
  394. /package/{docs → core/workspace-app/docs}/DEVELOPER-GUIDE.md +0 -0
  395. /package/{docs → core/workspace-app/docs}/README.md +0 -0
  396. /package/{docs → core/workspace-app/docs}/REFERENCE.md +0 -0
  397. /package/{docs → core/workspace-app/docs}/USER-GUIDE.md +0 -0
  398. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-board.png +0 -0
  399. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-coffee.png +0 -0
  400. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-colours.png +0 -0
  401. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-icons.png +0 -0
  402. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-moves.png +0 -0
  403. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-pick-cookieman.png +0 -0
  404. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-settings-voices.png +0 -0
  405. /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-status.png +0 -0
  406. /package/{docs → core/workspace-app/docs}/screenshots/create-card/create-card.png +0 -0
  407. /package/{docs → core/workspace-app/docs}/screenshots/create-card/start-ai.png +0 -0
  408. /package/{docs → core/workspace-app/docs}/screenshots/guide-clone-address.png +0 -0
  409. /package/{docs → core/workspace-app/docs}/screenshots/guide-clone-worktree-off.png +0 -0
  410. /package/{docs → core/workspace-app/docs}/screenshots/guide-clone-worktree-on.png +0 -0
  411. /package/{docs → core/workspace-app/docs}/screenshots/guide-ddev-menu.png +0 -0
  412. /package/{docs → core/workspace-app/docs}/screenshots/guide-domains.png +0 -0
  413. /package/{docs → core/workspace-app/docs}/screenshots/guide-home.png +0 -0
  414. /package/{docs → core/workspace-app/docs}/screenshots/guide-ide-menu.png +0 -0
  415. /package/{docs → core/workspace-app/docs}/screenshots/guide-remove-refusal.png +0 -0
  416. /package/{docs → core/workspace-app/docs}/screenshots/guide-rows-worktree.png +0 -0
  417. /package/{docs → core/workspace-app/docs}/screenshots/guide-screens.png +0 -0
  418. /package/{docs → core/workspace-app/docs}/screenshots/guide-settings.png +0 -0
  419. /package/{docs → core/workspace-app/docs}/screenshots/guide-workspace-page.png +0 -0
  420. /package/{docs → core/workspace-app/docs}/screenshots/home/card-settings.png +0 -0
  421. /package/{docs → core/workspace-app/docs}/screenshots/home/drag-reorder.png +0 -0
  422. /package/{docs → core/workspace-app/docs}/screenshots/home/edit-card.png +0 -0
  423. /package/{docs → core/workspace-app/docs}/screenshots/images/claude-code-image.png +0 -0
  424. /package/{docs → core/workspace-app/docs}/screenshots/images/edit-with-ai.png +0 -0
  425. /package/{docs → core/workspace-app/docs}/screenshots/images/gallery.png +0 -0
  426. /package/{docs → core/workspace-app/docs}/screenshots/images/generate-description.png +0 -0
  427. /package/{docs → core/workspace-app/docs}/screenshots/images/generate-plan.png +0 -0
  428. /package/{docs → core/workspace-app/docs}/screenshots/images/providers.png +0 -0
  429. /package/{docs → core/workspace-app/docs}/screenshots/images/svg-form.png +0 -0
  430. /package/{docs → core/workspace-app/docs}/screenshots/images/svg-result.png +0 -0
  431. /package/{docs → core/workspace-app/docs}/screenshots/images/upload.png +0 -0
  432. /package/{docs → core/workspace-app/docs}/screenshots/new-folder/2-form.png +0 -0
  433. /package/{docs → core/workspace-app/docs}/screenshots/new-folder/8-ddev-options.png +0 -0
  434. /package/{docs → core/workspace-app/docs}/screenshots/new-folder/files-folder.png +0 -0
  435. /package/{docs → core/workspace-app/docs}/screenshots/projects/ddev-custom-commands.png +0 -0
  436. /package/{docs → core/workspace-app/docs}/screenshots/projects/state-chip-stop.png +0 -0
  437. /package/{docs → core/workspace-app/docs}/screenshots/readme/dashboard-dark.png +0 -0
  438. /package/{docs → core/workspace-app/docs}/screenshots/readme/dashboard-light.png +0 -0
  439. /package/{docs → core/workspace-app/docs}/screenshots/readme/dev-dark.png +0 -0
  440. /package/{docs → core/workspace-app/docs}/screenshots/readme/dev-light.png +0 -0
  441. /package/{docs → core/workspace-app/docs}/screenshots/readme/docs-dark.png +0 -0
  442. /package/{docs → core/workspace-app/docs}/screenshots/readme/docs-light.png +0 -0
  443. /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/ai.svg +0 -0
  444. /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/code.svg +0 -0
  445. /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/docs.svg +0 -0
  446. /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/services.svg +0 -0
  447. /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/sites.svg +0 -0
  448. /package/{docs → core/workspace-app/docs}/screenshots/readme/test-report-dark.png +0 -0
  449. /package/{docs → core/workspace-app/docs}/screenshots/readme/test-report-light.png +0 -0
  450. /package/{docs → core/workspace-app/docs}/screenshots/readme/test-scenarios.png +0 -0
  451. /package/{docs → core/workspace-app/docs}/screenshots/readme/test-steps.png +0 -0
  452. /package/{docs → core/workspace-app/docs}/screenshots/readme/videos-dark.png +0 -0
  453. /package/{docs → core/workspace-app/docs}/screenshots/readme/videos-light.png +0 -0
  454. /package/{docs → core/workspace-app/docs}/screenshots/screens-menu.png +0 -0
  455. /package/{docs → core/workspace-app/docs}/screenshots/screens-new.png +0 -0
  456. /package/{docs → core/workspace-app/docs}/screenshots/settings/auth-google-lists.png +0 -0
  457. /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-1-row.png +0 -0
  458. /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-2-confirm.png +0 -0
  459. /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-3-type-name.png +0 -0
  460. /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-4-type-yes.png +0 -0
  461. /package/{event-log.js → core/workspace-app/event-log.js} +0 -0
  462. /package/{files-browser.js → core/workspace-app/files-browser.js} +0 -0
  463. /package/{folders.js → core/workspace-app/folders.js} +0 -0
  464. /package/{format.js → core/workspace-app/format.js} +0 -0
  465. /package/{github-auth.js → core/workspace-app/github-auth.js} +0 -0
  466. /package/{html.js → core/workspace-app/html.js} +0 -0
  467. /package/{icons.js → core/workspace-app/icons.js} +0 -0
  468. /package/{images-ai.js → core/workspace-app/images-ai.js} +0 -0
  469. /package/{images-create.js → core/workspace-app/images-create.js} +0 -0
  470. /package/{images-page.js → core/workspace-app/images-page.js} +0 -0
  471. /package/{images-records.js → core/workspace-app/images-records.js} +0 -0
  472. /package/{images-render.js → core/workspace-app/images-render.js} +0 -0
  473. /package/{images-svg-core.js → core/workspace-app/images-svg-core.js} +0 -0
  474. /package/{images-svg-sanitize.js → core/workspace-app/images-svg-sanitize.js} +0 -0
  475. /package/{images-svg.js → core/workspace-app/images-svg.js} +0 -0
  476. /package/{images.js → core/workspace-app/images.js} +0 -0
  477. /package/{jobs.js → core/workspace-app/jobs.js} +0 -0
  478. /package/{linger.js → core/workspace-app/linger.js} +0 -0
  479. /package/{lists.js → core/workspace-app/lists.js} +0 -0
  480. /package/{media-info.js → core/workspace-app/media-info.js} +0 -0
  481. /package/{navigation-page.js → core/workspace-app/navigation-page.js} +0 -0
  482. /package/{navigation.js → core/workspace-app/navigation.js} +0 -0
  483. /package/{notes.js → core/workspace-app/notes.js} +0 -0
  484. /package/{palette-index.js → core/workspace-app/palette-index.js} +0 -0
  485. /package/{playwright.config.js → core/workspace-app/playwright.config.js} +0 -0
  486. /package/{plugin-install.js → core/workspace-app/plugin-install.js} +0 -0
  487. /package/{plugin-manifest.js → core/workspace-app/plugin-manifest.js} +0 -0
  488. /package/{plugin-settings.js → core/workspace-app/plugin-settings.js} +0 -0
  489. /package/{plugins → core/workspace-app/plugins}/workspace-notes/index.js +0 -0
  490. /package/{project-make.js → core/workspace-app/project-make.js} +0 -0
  491. /package/{project-name.js → core/workspace-app/project-name.js} +0 -0
  492. /package/{public → core/workspace-app/public}/assistant-avatar-moves.js +0 -0
  493. /package/{public → core/workspace-app/public}/assistant-avatar-ui.js +0 -0
  494. /package/{public → core/workspace-app/public}/assistant-avatar.js +0 -0
  495. /package/{public → core/workspace-app/public}/avatar/druplicon.vrm +0 -0
  496. /package/{public → core/workspace-app/public}/css/base.css +0 -0
  497. /package/{public → core/workspace-app/public}/css/components/ai-assistant.css +0 -0
  498. /package/{public → core/workspace-app/public}/css/components/assistant-avatar.css +0 -0
  499. /package/{public → core/workspace-app/public}/css/components/assistant-views.css +0 -0
  500. /package/{public → core/workspace-app/public}/css/components/build-order.css +0 -0
  501. /package/{public → core/workspace-app/public}/css/components/clone-as-a-git-worktree.css +0 -0
  502. /package/{public → core/workspace-app/public}/css/components/command-palette.css +0 -0
  503. /package/{public → core/workspace-app/public}/css/components/commands-center.css +0 -0
  504. /package/{public → core/workspace-app/public}/css/components/confirm-dialog.css +0 -0
  505. /package/{public → core/workspace-app/public}/css/components/create-card.css +0 -0
  506. /package/{public → core/workspace-app/public}/css/components/ddev-menu.css +0 -0
  507. /package/{public → core/workspace-app/public}/css/components/deep-chat.css +0 -0
  508. /package/{public → core/workspace-app/public}/css/components/density.css +0 -0
  509. /package/{public → core/workspace-app/public}/css/components/floating-assistant-workspace-pages.css +0 -0
  510. /package/{public → core/workspace-app/public}/css/components/folders.css +0 -0
  511. /package/{public → core/workspace-app/public}/css/components/full-height-left-assistant-sidebar-all-pages.css +0 -0
  512. /package/{public → core/workspace-app/public}/css/components/full-height-right-actions-rail-pages-that-have-actions.css +0 -0
  513. /package/{public → core/workspace-app/public}/css/components/grid-and-list.css +0 -0
  514. /package/{public → core/workspace-app/public}/css/components/help-page.css +0 -0
  515. /package/{public → core/workspace-app/public}/css/components/hero.css +0 -0
  516. /package/{public → core/workspace-app/public}/css/components/images.css +0 -0
  517. /package/{public → core/workspace-app/public}/css/components/layout-rhythm-and-spacing-polish.css +0 -0
  518. /package/{public → core/workspace-app/public}/css/components/mic-on-any-field-that-wants-typing.css +0 -0
  519. /package/{public → core/workspace-app/public}/css/components/modal-fit.css +0 -0
  520. /package/{public → core/workspace-app/public}/css/components/page-width.css +0 -0
  521. /package/{public → core/workspace-app/public}/css/components/plugins-page.css +0 -0
  522. /package/{public → core/workspace-app/public}/css/components/project-cards.css +0 -0
  523. /package/{public → core/workspace-app/public}/css/components/project-rows.css +0 -0
  524. /package/{public → core/workspace-app/public}/css/components/reordering-the-workspace-cards.css +0 -0
  525. /package/{public → core/workspace-app/public}/css/components/responsive-home-and-the-workspace-pages.css +0 -0
  526. /package/{public → core/workspace-app/public}/css/components/running-commands-as-toasts.css +0 -0
  527. /package/{public → core/workspace-app/public}/css/components/settings-editor-core-config-yml.css +0 -0
  528. /package/{public → core/workspace-app/public}/css/components/short-results-as-a-toast-at-the-top.css +0 -0
  529. /package/{public → core/workspace-app/public}/css/components/sound-player.css +0 -0
  530. /package/{public → core/workspace-app/public}/css/components/suggest-agents-skills-commands.css +0 -0
  531. /package/{public → core/workspace-app/public}/css/components/tab-modal.css +0 -0
  532. /package/{public → core/workspace-app/public}/css/components/terminals.css +0 -0
  533. /package/{public → core/workspace-app/public}/css/components/test-report-media-one-file-per-row-paged.css +0 -0
  534. /package/{public → core/workspace-app/public}/css/components/top-toolbar-logo-breadcrumb.css +0 -0
  535. /package/{public → core/workspace-app/public}/css/components/video-edit.css +0 -0
  536. /package/{public → core/workspace-app/public}/css/components/web-ide-open-with.css +0 -0
  537. /package/{public → core/workspace-app/public}/css/components/working-indicators.css +0 -0
  538. /package/{public → core/workspace-app/public}/css/components/workspace-cards.css +0 -0
  539. /package/{public → core/workspace-app/public}/favicon.ico +0 -0
  540. /package/{public → core/workspace-app/public}/favicon.png +0 -0
  541. /package/{public → core/workspace-app/public}/htmx.min.js +0 -0
  542. /package/{public → core/workspace-app/public}/logo.png +0 -0
  543. /package/{public → core/workspace-app/public}/media-player.js +0 -0
  544. /package/{public → core/workspace-app/public}/mic.js +0 -0
  545. /package/{public → core/workspace-app/public}/narration.js +0 -0
  546. /package/{public → core/workspace-app/public}/palette.js +0 -0
  547. /package/{public → core/workspace-app/public}/sortable.js +0 -0
  548. /package/{public → core/workspace-app/public}/suggest.js +0 -0
  549. /package/{public → core/workspace-app/public}/terminal.js +0 -0
  550. /package/{public → core/workspace-app/public}/themes/default/theme.css +0 -0
  551. /package/{public → core/workspace-app/public}/themes/ember/theme.css +0 -0
  552. /package/{public → core/workspace-app/public}/themes/press/theme.css +0 -0
  553. /package/{public → core/workspace-app/public}/themes/slate/theme.css +0 -0
  554. /package/{public → core/workspace-app/public}/touch-icon.png +0 -0
  555. /package/{public → core/workspace-app/public}/ui.js +0 -0
  556. /package/{public → core/workspace-app/public}/vendor/ace/LICENSE.txt +0 -0
  557. /package/{public → core/workspace-app/public}/vendor/ace/ace.js +0 -0
  558. /package/{public → core/workspace-app/public}/vendor/ace/ext-language_tools.js +0 -0
  559. /package/{public → core/workspace-app/public}/vendor/ace/ext-searchbox.js +0 -0
  560. /package/{public → core/workspace-app/public}/vendor/ace/mode-css.js +0 -0
  561. /package/{public → core/workspace-app/public}/vendor/ace/mode-html.js +0 -0
  562. /package/{public → core/workspace-app/public}/vendor/ace/mode-javascript.js +0 -0
  563. /package/{public → core/workspace-app/public}/vendor/ace/mode-markdown.js +0 -0
  564. /package/{public → core/workspace-app/public}/vendor/ace/mode-sh.js +0 -0
  565. /package/{public → core/workspace-app/public}/vendor/ace/mode-yaml.js +0 -0
  566. /package/{public → core/workspace-app/public}/vendor/ace/theme-textmate.js +0 -0
  567. /package/{public → core/workspace-app/public}/vendor/ace/theme-tomorrow_night.js +0 -0
  568. /package/{public → core/workspace-app/public}/vendor/ace/worker-yaml.js +0 -0
  569. /package/{public → core/workspace-app/public}/vendor/deep-chat.LICENSE +0 -0
  570. /package/{public → core/workspace-app/public}/vendor/deep-chat.bundle.js +0 -0
  571. /package/{public → core/workspace-app/public}/vendor/fonts/dm-serif-text-LICENSE.txt +0 -0
  572. /package/{public → core/workspace-app/public}/vendor/fonts/dm-serif-text-latin-400-italic.woff2 +0 -0
  573. /package/{public → core/workspace-app/public}/vendor/fonts/dm-serif-text-latin-400-normal.woff2 +0 -0
  574. /package/{public → core/workspace-app/public}/vendor/fonts/figtree-LICENSE.txt +0 -0
  575. /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-400-italic.woff2 +0 -0
  576. /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-400-normal.woff2 +0 -0
  577. /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-600-italic.woff2 +0 -0
  578. /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-600-normal.woff2 +0 -0
  579. /package/{public → core/workspace-app/public}/vendor/fonts/jetbrains-mono-LICENSE.txt +0 -0
  580. /package/{public → core/workspace-app/public}/vendor/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
  581. /package/{public → core/workspace-app/public}/vendor/fonts/ubuntu-mono-LICENSE.txt +0 -0
  582. /package/{public → core/workspace-app/public}/vendor/fonts/ubuntu-mono-latin-wght-normal.woff2 +0 -0
  583. /package/{public → core/workspace-app/public}/vendor/tabler-LICENSE.txt +0 -0
  584. /package/{public → core/workspace-app/public}/vendor/tabler-sprite.svg +0 -0
  585. /package/{public → core/workspace-app/public}/vendor/three/LICENSE +0 -0
  586. /package/{public → core/workspace-app/public}/vendor/three/addons/loaders/GLTFLoader.js +0 -0
  587. /package/{public → core/workspace-app/public}/vendor/three/addons/utils/BufferGeometryUtils.js +0 -0
  588. /package/{public → core/workspace-app/public}/vendor/three/addons/utils/SkeletonUtils.js +0 -0
  589. /package/{public → core/workspace-app/public}/vendor/three/three.core.min.js +0 -0
  590. /package/{public → core/workspace-app/public}/vendor/three/three.module.min.js +0 -0
  591. /package/{public → core/workspace-app/public}/vendor/three-vrm/LICENSE +0 -0
  592. /package/{public → core/workspace-app/public}/vendor/three-vrm/three-vrm.module.min.js +0 -0
  593. /package/{public → core/workspace-app/public}/vendor/uikit-icons.min.js +0 -0
  594. /package/{public → core/workspace-app/public}/vendor/uikit.min.css +0 -0
  595. /package/{public → core/workspace-app/public}/vendor/uikit.min.js +0 -0
  596. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/bookmark-outlined.svg +0 -0
  597. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/headset.svg +0 -0
  598. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/menu.svg +0 -0
  599. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/pause.svg +0 -0
  600. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/play.svg +0 -0
  601. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/share.svg +0 -0
  602. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/sound-off.svg +0 -0
  603. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/sound-on.svg +0 -0
  604. /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/stop.svg +0 -0
  605. /package/{public → core/workspace-app/public}/vendor/xterm/addon-fit.js +0 -0
  606. /package/{public → core/workspace-app/public}/vendor/xterm/addon-unicode11.js +0 -0
  607. /package/{public → core/workspace-app/public}/vendor/xterm/addon-web-links.js +0 -0
  608. /package/{public → core/workspace-app/public}/vendor/xterm/xterm.css +0 -0
  609. /package/{public → core/workspace-app/public}/vendor/xterm/xterm.js +0 -0
  610. /package/{rag.js → core/workspace-app/rag.js} +0 -0
  611. /package/{reader.js → core/workspace-app/reader.js} +0 -0
  612. /package/{repo-blobs.js → core/workspace-app/repo-blobs.js} +0 -0
  613. /package/{report-pdf.js → core/workspace-app/report-pdf.js} +0 -0
  614. /package/{screenrc → core/workspace-app/screenrc} +0 -0
  615. /package/{screens.js → core/workspace-app/screens.js} +0 -0
  616. /package/{scripts → core/workspace-app/scripts}/code-server-start.sh +0 -0
  617. /package/{scripts → core/workspace-app/scripts}/images-claude-finish.js +0 -0
  618. /package/{scripts → core/workspace-app/scripts}/screen-host.sh +0 -0
  619. /package/{scripts → core/workspace-app/scripts}/screen-runner.js +0 -0
  620. /package/{scripts → core/workspace-app/scripts}/screen-then.js +0 -0
  621. /package/{scripts → core/workspace-app/scripts}/update.sh +0 -0
  622. /package/{settings-file.js → core/workspace-app/settings-file.js} +0 -0
  623. /package/{speech.js → core/workspace-app/speech.js} +0 -0
  624. /package/{tab-modal.js → core/workspace-app/tab-modal.js} +0 -0
  625. /package/{test-reports.js → core/workspace-app/test-reports.js} +0 -0
  626. /package/{themes.js → core/workspace-app/themes.js} +0 -0
  627. /package/{transcripts.js → core/workspace-app/transcripts.js} +0 -0
  628. /package/{urls.js → core/workspace-app/urls.js} +0 -0
  629. /package/{validate.js → core/workspace-app/validate.js} +0 -0
  630. /package/{version-check.js → core/workspace-app/version-check.js} +0 -0
  631. /package/{video-edit.js → core/workspace-app/video-edit.js} +0 -0
  632. /package/{waiting.js → core/workspace-app/waiting.js} +0 -0
  633. /package/{workspace-card-tools.js → core/workspace-app/workspace-card-tools.js} +0 -0
  634. /package/{workspace-delete.js → core/workspace-app/workspace-delete.js} +0 -0
@@ -0,0 +1,250 @@
1
+ /**
2
+ * The worktree half of cmd-tools-clone.sh, tested where it is cheap to test: the
3
+ * shell contract and the shape of the DDEV config it produces. The end-to-end run
4
+ * (git worktree add, ddev start, import-db) needs Docker and a real project, so it
5
+ * is exercised by hand and recorded in the PR; what is asserted here is everything
6
+ * that can silently rot — the flags, the git detection that must work for a
7
+ * worktree OF a worktree, and the one key whose removal is the whole feature.
8
+ */
9
+
10
+ const assert = require('node:assert');
11
+ const { test } = require('node:test');
12
+ const fs = require('fs');
13
+ const os = require('os');
14
+ const path = require('path');
15
+ const { execFileSync, spawnSync } = require('child_process');
16
+
17
+ const ROOT = path.join(__dirname, '..', '..', '..', '..');
18
+ const FUN = path.join(ROOT, 'core', 'scripts', 'functions', 'fun-clone-project.sh');
19
+ const ARGS = path.join(ROOT, 'core', 'scripts', 'args', 'arg-clone.sh');
20
+
21
+ /** Run a bash snippet with the clone functions sourced. */
22
+ function withFunctions(snippet) {
23
+ return execFileSync('bash', ['-c', `source ${JSON.stringify(FUN)} ; ${snippet}`],
24
+ { encoding: 'utf8' }).trim();
25
+ }
26
+
27
+ test('the function file is valid bash', () => {
28
+ assert.strictEqual(spawnSync('bash', ['-n', FUN]).status, 0);
29
+ assert.strictEqual(spawnSync('bash', ['-n', ARGS]).status, 0);
30
+ });
31
+
32
+ test('the worktree flags are all declared, and the worktree-only ones say so', () => {
33
+ const args = fs.readFileSync(ARGS, 'utf8');
34
+ for (const flag of ['--worktree', '--branch', '--no-build-copy', '--no-db']) {
35
+ assert.ok(args.includes(`'${flag}'`), `${flag} is not declared`);
36
+ }
37
+ // A flag that quietly does nothing on the copying path is worse than one that
38
+ // refuses, so each worktree-only flag has to be labelled in its own help.
39
+ for (const flag of ['--branch', '--no-build-copy']) {
40
+ const help = args.slice(args.indexOf(`'${flag}'`));
41
+ assert.match(help.slice(0, 400), /Worktree only/, `${flag} does not say it is worktree only`);
42
+ }
43
+ });
44
+
45
+ test('project_has_git is true for a checkout, a worktree of one, and false otherwise', () => {
46
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'wt-'));
47
+ try {
48
+ const repo = path.join(tmp, 'repo');
49
+ fs.mkdirSync(repo);
50
+ const git = (...a) => execFileSync('git', ['-C', repo, ...a], { encoding: 'utf8' });
51
+ execFileSync('git', ['init', '-q', '-b', 'main', repo]);
52
+ git('config', 'user.email', 't@t'); git('config', 'user.name', 'T');
53
+ fs.writeFileSync(path.join(repo, 'a'), 'a');
54
+ git('add', '-A'); git('commit', '-qm', 'init');
55
+
56
+ assert.strictEqual(withFunctions(`project_has_git ${JSON.stringify(repo)} && echo yes || echo no`), 'yes');
57
+
58
+ // The case a `.git` directory test gets wrong: a worktree carries .git as a FILE.
59
+ const wt = path.join(tmp, 'wt');
60
+ git('worktree', 'add', '-q', '-b', 'side', wt);
61
+ assert.ok(fs.statSync(path.join(wt, '.git')).isFile(), '.git in a worktree should be a file');
62
+ assert.strictEqual(withFunctions(`project_has_git ${JSON.stringify(wt)} && echo yes || echo no`), 'yes');
63
+
64
+ const plain = path.join(tmp, 'plain');
65
+ fs.mkdirSync(plain);
66
+ // Guard against the ambient repository: a plain dir under /tmp is outside one.
67
+ assert.strictEqual(withFunctions(`project_has_git ${JSON.stringify(plain)} && echo yes || echo no`), 'no');
68
+ assert.strictEqual(withFunctions('project_has_git && echo yes || echo no'), 'no');
69
+ } finally { fs.rmSync(tmp, { recursive: true, force: true }); }
70
+ });
71
+
72
+ test('ddev_config_drop_name removes the top-level name and nothing else', () => {
73
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'wt-'));
74
+ try {
75
+ const cfg = path.join(tmp, 'config.yaml');
76
+ // A nested `name:` belongs to a service or a hook and must survive: dropping it
77
+ // would silently break the project's own configuration.
78
+ fs.writeFileSync(cfg, [
79
+ 'name: source-project',
80
+ 'docroot: web',
81
+ 'hooks:',
82
+ ' post-start:',
83
+ ' - exec: echo hi',
84
+ 'web_environment:',
85
+ ' - name: KEEP_ME',
86
+ ''].join('\n'));
87
+ withFunctions(`ddev_config_drop_name ${JSON.stringify(cfg)}`);
88
+ const out = fs.readFileSync(cfg, 'utf8');
89
+ assert.ok(!/^name:/m.test(out), 'the top-level name: should be gone');
90
+ assert.match(out, /- name: KEEP_ME/, 'a nested name: must survive');
91
+ assert.match(out, /docroot: web/);
92
+ // Absent file: a no-op, not a failure.
93
+ withFunctions(`ddev_config_drop_name ${JSON.stringify(path.join(tmp, 'nope.yaml'))}`);
94
+ } finally { fs.rmSync(tmp, { recursive: true, force: true }); }
95
+ });
96
+
97
+ test('project_ddev_docroot reads the declared docroot, quoted or bare', () => {
98
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'wt-'));
99
+ try {
100
+ const dir = path.join(tmp, 'p'); fs.mkdirSync(path.join(dir, '.ddev'), { recursive: true });
101
+ const cfg = path.join(dir, '.ddev', 'config.yaml');
102
+ fs.writeFileSync(cfg, 'name: p\ndocroot: web\n');
103
+ assert.strictEqual(withFunctions(`project_ddev_docroot ${JSON.stringify(dir)}`), 'web');
104
+ fs.writeFileSync(cfg, 'name: p\ndocroot: "docroot"\n');
105
+ assert.strictEqual(withFunctions(`project_ddev_docroot ${JSON.stringify(dir)}`), 'docroot');
106
+ fs.writeFileSync(cfg, 'name: p\n');
107
+ assert.strictEqual(withFunctions(`project_ddev_docroot ${JSON.stringify(dir)}`), '');
108
+ } finally { fs.rmSync(tmp, { recursive: true, force: true }); }
109
+ });
110
+
111
+ test('the build copy never carries DDEV per-project generated state', () => {
112
+ // wtsrc.crt copied into wtcopy makes every ddev start warn "unexpected
113
+ // #ddev-generated", and DDEV regenerates all of it anyway. Found by running it.
114
+ const fun = fs.readFileSync(FUN, 'utf8');
115
+ const filter = fun.slice(fun.indexOf('git ls-files --others --ignored'));
116
+ for (const excluded of ['\\.ddev/traefik', '\\.ddev/db_snapshots', '\\.ddev/\\.', '\\.tarballs']) {
117
+ assert.ok(filter.includes(excluded), `the build copy does not exclude ${excluded}`);
118
+ }
119
+ // …and config.yaml must NOT be filtered out: in a project that git-ignores
120
+ // .ddev/ it is the one file the clone cannot start without.
121
+ assert.ok(!/-e '\^\\\.ddev\/\[\^\/\]\*\\\.yaml\$'/.test(filter), 'config.yaml must not be excluded');
122
+ });
123
+
124
+ test('every clone command documents the worktree option', () => {
125
+ const folders = ['demos', 'dev', 'products', 'profiles', 'projects', 'sandboxes', 'site-templates', 'test'];
126
+ for (const f of folders) {
127
+ const p = path.join(ROOT, f, 'cmd-tools-clone.sh');
128
+ if (!fs.existsSync(p)) continue;
129
+ assert.match(fs.readFileSync(p, 'utf8'), /--worktree/, `${f}/cmd-tools-clone.sh does not mention --worktree`);
130
+ }
131
+ });
132
+
133
+ test('the dashboard offers the worktree only for a git checkout', () => {
134
+ // The git questions live in git-info.js now (shared with the GIT plugin through api.lib); the forms stay in server.js.
135
+ const server = fs.readFileSync(path.join(__dirname, '..', '..', 'server.js'), 'utf8') + fs.readFileSync(path.join(__dirname, '..', '..', 'git-info.js'), 'utf8');
136
+ assert.match(server, /function projectHasGit/);
137
+ assert.match(server, /rev-parse', '--git-dir'/);
138
+ // The control is absent, not disabled, when there is no repository.
139
+ assert.match(server, /projectHasGit\(srcDir\) \? `/);
140
+ // And the endpoint refuses the flag rather than trusting the form.
141
+ assert.match(server, /is not a git checkout, so there is no repository to add a worktree to/);
142
+ });
143
+
144
+ /* --- the removal guards ------------------------------------------------------
145
+ * These are the destructive half. Deleting the main checkout takes the only copy
146
+ * of the repository with it, and deleting a worktree can take commits nobody
147
+ * pushed — so the refusals are asserted against real repositories rather than by
148
+ * reading the script.
149
+ */
150
+
151
+ const GUARDS = path.join(ROOT, 'core', 'scripts', 'functions', 'fun-git-worktrees.sh');
152
+
153
+ function withGuards(snippet) {
154
+ return execFileSync('bash', ['-c', `source ${JSON.stringify(GUARDS)} ; ${snippet}`],
155
+ { encoding: 'utf8' }).trim();
156
+ }
157
+
158
+ /** A repo with an optional linked worktree, in a temp dir. */
159
+ function makeRepo(withWorktree) {
160
+ const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'wtg-'));
161
+ const main = path.join(tmp, 'main');
162
+ fs.mkdirSync(main);
163
+ const git = (...a) => execFileSync('git', ['-C', main, ...a], { encoding: 'utf8' });
164
+ execFileSync('git', ['init', '-q', '-b', 'main', main]);
165
+ git('config', 'user.email', 't@t'); git('config', 'user.name', 'T');
166
+ fs.writeFileSync(path.join(main, 'a'), 'a');
167
+ git('add', '-A'); git('commit', '-qm', 'init');
168
+ let wt = '';
169
+ if (withWorktree) {
170
+ wt = path.join(tmp, 'side');
171
+ git('worktree', 'add', '-q', '-b', 'side', wt);
172
+ }
173
+ return { tmp, main, wt };
174
+ }
175
+
176
+ test('git_worktree_role: plain, primary and linked are told apart', () => {
177
+ const { tmp, main, wt } = makeRepo(true);
178
+ try {
179
+ assert.strictEqual(withGuards(`git_worktree_role ${JSON.stringify(main)}`), 'primary');
180
+ assert.strictEqual(withGuards(`git_worktree_role ${JSON.stringify(wt)}`), 'linked');
181
+ // Remove the dependent and the same folder is merely 'plain' — the role is
182
+ // about what depends on it, not about what it is on disk.
183
+ execFileSync('git', ['-C', main, 'worktree', 'remove', '--force', wt]);
184
+ assert.strictEqual(withGuards(`git_worktree_role ${JSON.stringify(main)}`), 'plain');
185
+ assert.strictEqual(withGuards(`git_worktree_role ${JSON.stringify(tmp)}`), 'none');
186
+ } finally { fs.rmSync(tmp, { recursive: true, force: true }); }
187
+ });
188
+
189
+ test('git_worktree_others lists the dependents and excludes the folder itself', () => {
190
+ const { tmp, main, wt } = makeRepo(true);
191
+ try {
192
+ const others = withGuards(`git_worktree_others ${JSON.stringify(main)}`).split('\n').filter(Boolean);
193
+ assert.strictEqual(others.length, 1);
194
+ assert.strictEqual(fs.realpathSync(others[0]), fs.realpathSync(wt));
195
+ const back = withGuards(`git_worktree_others ${JSON.stringify(wt)}`).split('\n').filter(Boolean);
196
+ assert.strictEqual(back.length, 1, 'a worktree should see the main checkout as its other');
197
+ } finally { fs.rmSync(tmp, { recursive: true, force: true }); }
198
+ });
199
+
200
+ test('git_worktree_unpushed and _dirty count what a delete would destroy', () => {
201
+ const { tmp, main } = makeRepo(false);
202
+ try {
203
+ // No remote at all: every commit is unpushed, which is the honest answer.
204
+ assert.strictEqual(withGuards(`git_worktree_unpushed ${JSON.stringify(main)}`), '1');
205
+ assert.strictEqual(withGuards(`git_worktree_dirty ${JSON.stringify(main)}`), '0');
206
+ fs.writeFileSync(path.join(main, 'b'), 'b');
207
+ // A single number, not two: `grep -c` prints 0 AND exits 1 on no match, so an
208
+ // `|| echo 0` fallback printed a second zero and the caller read "0 0".
209
+ const dirty = withGuards(`git_worktree_dirty ${JSON.stringify(main)}`);
210
+ assert.strictEqual(dirty, '1');
211
+ assert.ok(!dirty.includes('\n'), 'dirty must be one number');
212
+ } finally { fs.rmSync(tmp, { recursive: true, force: true }); }
213
+ });
214
+
215
+ test('remove refuses the main checkout, and --force is the only way past', () => {
216
+ const fun = fs.readFileSync(path.join(ROOT, 'core', 'scripts', 'functions', 'fun-remove-project.sh'), 'utf8');
217
+ assert.match(fun, /REFUSING to remove \$\{project\}: it is the MAIN checkout/);
218
+ assert.match(fun, /REFUSING to remove \$\{project\}: it holds work that is nowhere else/);
219
+ // The guard runs BEFORE anything is deleted — after ddev delete would be too late.
220
+ const guardAt = fun.indexOf('remove_project_worktree_guard "${workspace_dir}/${project}"');
221
+ // The REAL call, not the `ddev delete` quoted in the file's header comment —
222
+ // which is what the first version of this assertion matched, and it failed on
223
+ // correct code.
224
+ const deleteAt = fun.indexOf('( cd "${workspace_dir}/${project}" && ddev delete -y -O )');
225
+ assert.ok(guardAt > 0 && guardAt < deleteAt, 'the guard must run before ddev delete');
226
+ // FORCE may be unset entirely: remove_project is called from the dashboard and
227
+ // from other scripts that know nothing about it.
228
+ assert.ok(!/\[ "\$\{FORCE\}"/.test(fun), 'FORCE must be read as ${FORCE:-}');
229
+ // And the stale registration is pruned afterwards, or a re-clone to the same
230
+ // path is refused by git.
231
+ assert.match(fun, /remove_project_worktree_after/);
232
+ });
233
+
234
+ test('every remove command offers --force', () => {
235
+ for (const f of fs.readdirSync(ROOT)) {
236
+ const p = path.join(ROOT, f, 'cmd-tools-remove.sh');
237
+ if (!fs.existsSync(p)) continue;
238
+ assert.match(fs.readFileSync(p, 'utf8'), /'-f', '--force'/, `${f}/cmd-tools-remove.sh has no --force`);
239
+ }
240
+ });
241
+
242
+ test('the dashboard asks git the same questions the script does', () => {
243
+ // The git questions live in git-info.js now (shared with the GIT plugin through api.lib); the forms stay in server.js.
244
+ const server = fs.readFileSync(path.join(__dirname, '..', '..', 'server.js'), 'utf8') + fs.readFileSync(path.join(__dirname, '..', '..', 'git-info.js'), 'utf8');
245
+ assert.match(server, /function gitWorktreeInfo/);
246
+ // The warning is shown before the confirm, and force is forwarded, never assumed.
247
+ assert.match(server, /This is the main git checkout/);
248
+ assert.match(server, /This holds work that is nowhere else/);
249
+ assert.match(server, /form\.force === 'yes' \? ' --force' : ''/);
250
+ });
@@ -23,12 +23,12 @@ const TYPES = {
23
23
  sites: {
24
24
  label: 'Sites — DDEV projects',
25
25
  description: 'Built Drupal sites: DDEV controls, tests, users, the full toolbelt.',
26
- actions: ['build', 'folder', 'ddev', 'backup', 'clone', 'remove', 'graphify', 'ragify', 'tests', 'checks', 'users'],
26
+ actions: ['build', 'folder', 'ddev', 'backup', 'clone', 'remove', 'ragify', 'tests', 'checks', 'users'],
27
27
  },
28
28
  code: {
29
29
  label: 'Code — packages and repositories',
30
30
  description: 'Modules, themes, libraries, recipes: quality checks and knowledge tools, no site controls.',
31
- actions: ['build', 'folder', 'backup', 'remove', 'graphify', 'ragify', 'checks'],
31
+ actions: ['build', 'folder', 'backup', 'remove', 'ragify', 'checks'],
32
32
  },
33
33
  files: {
34
34
  label: 'Files — documents and drafts',
@@ -256,10 +256,6 @@ function findRemoveScript(dir) {
256
256
  return findScript(dir, [/^cmd-tools-remove\.sh$/]);
257
257
  }
258
258
 
259
- function findGraphifyScript(dir) {
260
- return findScript(dir, [/^cmd-tools?-graphify\.sh$/]);
261
- }
262
-
263
259
  function findRagifyScript(dir) {
264
260
  return findScript(dir, [/^cmd-tools?-ragify\.sh$/]);
265
261
  }
@@ -549,7 +545,7 @@ module.exports = {
549
545
  workspaceDir,
550
546
  findBackupScript,
551
547
  findRemoveScript,
552
- findGraphifyScript,
548
+ findScript,
553
549
  findRagifyScript,
554
550
  findBuilderScripts,
555
551
  builderLabel,
package/package.json CHANGED
@@ -1,49 +1,51 @@
1
1
  {
2
2
  "name": "@webship.co/workspace",
3
- "version": "1.0.0-alpha1",
4
- "description": "The Webship Workspace dashboard: a lean core (workspaces, builders, settings, the assistant shell, the plugin system) that every feature joins as a @webship.co/workspace-<name> plugin \u2014 required with npm, then activated, installed and configured.",
5
- "license": "ISC",
3
+ "version": "1.0.0-beta2",
4
+ "description": "Webship Workspace: a container-based development workspace with a web dashboard. The core ships empty; workspace folders, hosting providers, git forges, container runtimes and features are @webship.co/workspace-<name> plugins you add one at a time.",
5
+ "license": "GPL-2.0-or-later",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/webship/workspace.git",
9
- "directory": "core/workspace-app"
8
+ "url": "https://github.com/webship/workspace.git"
9
+ },
10
+ "homepage": "https://github.com/webship/workspace#readme",
11
+ "bin": {
12
+ "webship-workspace": "core/bin/workspace.js"
10
13
  },
11
- "main": "server.js",
12
14
  "files": [
13
- "*.js",
14
- "actions",
15
- "commands",
16
- "docs",
17
- "public",
18
- "scripts",
19
- "plugins/workspace-notes",
20
- "screenrc",
21
- "PLUGINS.md",
22
- "WORKSPACES.md",
23
- "README.md"
15
+ "core/bin",
16
+ "core/config/settings.template.yml",
17
+ "core/config/style.yml",
18
+ "core/config/settings.labels.yml",
19
+ "core/config/theme.*.yml",
20
+ "core/docs",
21
+ "core/scripts",
22
+ "core/workspace-app/*.js",
23
+ "core/workspace-app/actions",
24
+ "core/workspace-app/commands",
25
+ "core/workspace-app/docs",
26
+ "core/workspace-app/public",
27
+ "core/workspace-app/scripts",
28
+ "core/workspace-app/plugins/workspace-notes",
29
+ "core/workspace-app/tests",
30
+ "core/workspace-app/.ddev",
31
+ "core/workspace-app/package.json",
32
+ "core/workspace-app/cucumber.js",
33
+ "core/workspace-app/playwright.config.js",
34
+ "core/workspace-app/screenrc",
35
+ "core/workspace-app/PLUGINS.md",
36
+ "core/workspace-app/WORKSPACES.md",
37
+ "core/workspace-app/README.md",
38
+ "README.md",
39
+ "LICENSE"
24
40
  ],
25
41
  "scripts": {
26
- "start": "node server.js",
27
- "test": "npm run test:unit && npm run test:browser",
28
- "test:unit": "node --test \"tests/unit/*.test.js\" \"plugins/*/tests/*.test.js\"",
29
- "test:browser": "cucumber-js --config cucumber.js"
30
- },
31
- "dependencies": {
32
- "@xterm/addon-fit": "^0.10.0",
33
- "@xterm/addon-unicode11": "^0.9.0",
34
- "@xterm/addon-web-links": "^0.11.0",
35
- "@xterm/xterm": "^5.5.0",
36
- "ace-builds": "^1.44.0",
37
- "htmx.org": "^4.0.0",
38
- "js-yaml": "^5.2.1",
39
- "ws": "^8.21.3"
40
- },
41
- "devDependencies": {
42
- "webship-js": "^2.0.4"
42
+ "test": "node --test core/workspace-app/tests/unit/workspace-bin.test.js",
43
+ "postinstall": "node -e \"console.log('Webship Workspace: run webship-workspace init [dir] to make a workspace (empty), then add plugins one at a time.')\""
43
44
  },
44
45
  "publishConfig": {
45
46
  "access": "public"
46
47
  },
47
- "keywords": [],
48
- "author": ""
48
+ "engines": {
49
+ "node": ">=20"
50
+ }
49
51
  }
package/actions/graphs.js DELETED
@@ -1,107 +0,0 @@
1
- /**
2
- * Building a project's knowledge graph, and what you do with it afterwards.
3
- *
4
- * One module per area of the dashboard, each exporting the handlers it owns keyed by the path that
5
- * reaches them. server.js merges the maps and dispatches; nothing here knows about routing, and
6
- * adding an action is adding an entry rather than another branch in a 1,250-line function.
7
- *
8
- * Every handler takes the same context: the parsed form, the response, a `send` that writes an HTML
9
- * fragment, and the workspace the request named.
10
- */
11
-
12
- const fs = require('fs');
13
- const path = require('path');
14
-
15
- const { esc } = require('../html');
16
- const { humanSize, humanTime } = require('../format');
17
- const { ROOT, loadWorkspaces, workspaceDir } = require('../workspaces');
18
- const {
19
- run, jobFragment, runningJobKey, startJob, ddevProjectName, listProjects,
20
- startInScreen, screenStartedHtml,
21
- } = require('../jobs');
22
- const { graphStoreDir } = require('../graphs');
23
- const {
24
- milvusProjectName, ragInstances, ragBindings, ragInstanceFor, ragWriteBinding,
25
- ragCollectionName, milvusPost, ragCollections, ragInvalidate,
26
- } = require('../rag');
27
- const {
28
- findTestReports, testReportFor, invalidateTestReports, testMediaHtml, testingStackOf,
29
- } = require('../test-reports');
30
- const { NAME_RE, SCRIPT_RE } = require('../validate');
31
- const { commandBlock } = require('../command-block');
32
- const { wsUrl } = require('../urls');
33
- const { findGraphifyScript, findRagifyScript } = require('../workspaces');
34
- const { DDEV_ACTIONS } = require('../ddev');
35
-
36
- async function graphify({ form, res, send, workspace, pathname }) {
37
- const dir = workspaceDir(workspace);
38
- const script = findGraphifyScript(dir);
39
- const projectName = String(form.projectName || '');
40
- if (!script) return send('<div class="msg error">No graphify script in this workspace.</div>', 400);
41
- if (!NAME_RE.test(projectName) || !listProjects(dir).includes(projectName)) {
42
- return send('<div class="msg error">Unknown project.</div>', 400);
43
- }
44
- // graphify has no cross-process lock: two runs against one graphify-out/
45
- // race on manifest.json, graph.json and cache/ast, and the loser's atomic
46
- // replace silently wins, corrupting the incremental gate.
47
- const jobKey = `graphify:${workspace}/${projectName}`;
48
- if (runningJobKey(jobKey)) {
49
- return send('<div class="msg error">A graph is already being built for this project.</div>', 409);
50
- }
51
- // Local AST extraction only: no API key, nothing leaves the machine. Big
52
- // codebases take a while, so it gets the long build timeout.
53
- const started = await startInScreen({ workspace, project: projectName, projectDir: dir, ownerDir: path.join(dir, projectName), verb: 'graphify',
54
- cmdLine: `bash ${JSON.stringify(script)} ${JSON.stringify(projectName)}`, label: 'graphify' });
55
- return send(screenStartedHtml(started, 'graphify', projectName), started.ok ? 200 : (started.already ? 409 : 500));
56
- }
57
-
58
- // Commands the dashboard SHOWS rather than runs, with a copy button each.
59
- //
60
- // Two kinds end up here. `claude mcp add` writes ~/.claude.json — the CLI configuration of the
61
- // person at the keyboard, not of this web request. The Upsun pulls need cloud credentials this
62
- // container does not have and replace local data. Both are worth reading before they happen.
63
- async function graph_mcp_command({ form, res, send, workspace, pathname }) {
64
- const projectName = String(form.projectName || '');
65
- if (!NAME_RE.test(projectName)) return send('<div class="msg error">Unknown project.</div>', 400);
66
- const graph = path.join(graphStoreDir(workspace, projectName), 'graph.json');
67
- if (!fs.existsSync(graph)) return send('<div class="msg error">No graph yet — build it first.</div>', 409);
68
- return send(commandBlock(
69
- `Serve the ${workspace}/${projectName} graph to the Claude Code CLI`,
70
- [`cd ${ROOT}/graphs && bash cmd-tools-graphs.sh ${workspace}/${projectName} -a mcp-register`,
71
- `claude mcp add --scope user graph-${workspace}-${projectName} -- graphify-mcp ${graph.replace(ROOT, '~/workspace')}`],
72
- 'Run either one <strong>on the host</strong>, in a terminal. The first is the workspace command; '
73
- + 'the second is what it runs. stdio, so there is no port and no daemon — the CLI starts the server '
74
- + 'when a session needs it. Open a NEW session to see the tools; rebuilding the graph needs no '
75
- + 're-registration.'));
76
- }
77
-
78
- // Delete a project's graph. Bounded to graphs/<workspace>/<project> — the whole point is that a
79
- // graph is regenerable, so this is the one cheap thing to throw away. The project itself is
80
- // never touched: nothing of the graph lives in it.
81
- async function graph_remove({ form, res, send, workspace, pathname }) {
82
- if (form.confirm !== 'yes') return send('<div class="msg error">Deleting requires confirmation.</div>', 400);
83
- const projectName = String(form.projectName || '');
84
- // The project may be gone — a graph outlives it, and that is exactly a graph worth deleting.
85
- if (!NAME_RE.test(projectName)) {
86
- return send('<div class="msg error">Unknown project.</div>', 400);
87
- }
88
- if (runningJobKey(`graphify:${workspace}/${projectName}`)) {
89
- return send('<div class="msg error">A graph run is in progress for this project — wait for it to finish.</div>', 409);
90
- }
91
- const out = graphStoreDir(workspace, projectName);
92
- let real;
93
- try {
94
- real = fs.realpathSync(out);
95
- const base = fs.realpathSync(path.join(ROOT, 'graphs'));
96
- if (!real.startsWith(base + path.sep)) throw new Error('outside');
97
- } catch (_) { return send('<div class="msg assistant">No graph to delete.</div>'); }
98
- fs.rmSync(real, { recursive: true, force: true });
99
- res.setHeader('HX-Trigger', 'refresh-projects');
100
- return send(`<div class="msg assistant">🗑️ Deleted the graph for <strong>${esc(projectName)}</strong>. Rebuild it any time from the Graph menu.</div>`);
101
- }
102
-
103
- module.exports = {
104
- '/actions/graphify': graphify,
105
- '/actions/graph-mcp-command': graph_mcp_command,
106
- '/actions/graph-remove': graph_remove,
107
- };
@@ -1,59 +0,0 @@
1
- /**
2
- * Building and removing a project's Obsidian vault.
3
- *
4
- * Both shell out to `cmd-tools-obsidian.sh` in the project's own workspace rather than
5
- * reimplementing the conversion, for the same reason every other action here does: the button and
6
- * the command line cannot then drift apart.
7
- */
8
-
9
- const fs = require('fs');
10
- const path = require('path');
11
-
12
- const { listProjects, workspaceDir } = require('../workspaces');
13
- const { esc } = require('../html');
14
- const { jobFragment, runningJobKey, startJob } = require('../jobs');
15
- const { NAME_RE } = require('../validate');
16
- const { graphStoreDir } = require('../graphs');
17
- const { vaultDir } = require('../obsidian');
18
-
19
- module.exports = {
20
- '/actions/obsidian': async ({ form, res, send, workspace, req }) => {
21
- const dir = workspaceDir(workspace);
22
- const script = 'cmd-tools-obsidian.sh';
23
- const projectName = String(form.projectName || '');
24
- if (!fs.existsSync(path.join(dir, script))) return send('<div class="msg error">This workspace has no Obsidian script.</div>', 400);
25
- if (!NAME_RE.test(projectName) || !listProjects(dir).includes(projectName)) {
26
- return send('<div class="msg error">Unknown project.</div>', 400);
27
- }
28
- // Said here rather than left to the script, because the menu is reached from a row that may
29
- // have had its graph deleted since the page was drawn.
30
- if (!fs.existsSync(path.join(graphStoreDir(workspace, projectName), 'graph.json'))) {
31
- return send('<div class="msg error">No graph to convert yet — build the graph first, from the same menu.</div>', 409);
32
- }
33
- // One writer per vault: the build writes to a sibling directory and swaps it in, so two runs
34
- // would race on that swap and the loser's vault would vanish under it.
35
- const jobKey = `obsidian:${workspace}/${projectName}`;
36
- if (runningJobKey(jobKey)) {
37
- return send('<div class="msg error">A vault is already being built for this project.</div>', 409);
38
- }
39
- const id = startJob(`🗂️ Obsidian <strong>${esc(projectName)}</strong>`, 'bash', [script, projectName], dir,
40
- { timeoutMs: 10 * 60 * 1000, echoLine: `bash ${script} ${projectName}`, key: jobKey });
41
- return send(jobFragment(id).html);
42
- },
43
-
44
- '/actions/obsidian-remove': async ({ form, res, send, workspace }) => {
45
- if (form.confirm !== 'yes') return send('<div class="msg error">Deleting requires confirmation.</div>', 400);
46
- const projectName = String(form.projectName || '');
47
- // The project may be long gone — a vault outlives it, and that is exactly a vault worth
48
- // throwing away. So the name is validated but not looked up.
49
- if (!NAME_RE.test(projectName)) return send('<div class="msg error">Unknown project.</div>', 400);
50
- const dir = vaultDir(workspace, projectName);
51
- if (!fs.existsSync(dir)) return send('<div class="msg">There was no vault to delete.</div>');
52
- try {
53
- fs.rmSync(dir, { recursive: true, force: true });
54
- } catch (e) {
55
- return send(`<div class="msg error">Could not delete the vault: ${esc(e.message)}</div>`, 500);
56
- }
57
- return send('<div class="msg">Vault deleted. The graph it was made from is untouched.</div>');
58
- },
59
- };
package/graphs.js DELETED
@@ -1,104 +0,0 @@
1
- /**
2
- * Where a project's knowledge graph lives, and what is in it.
3
- *
4
- * The graph is kept in the graphs workspace rather than inside the project — it is tens of MB, it
5
- * re-diffs entirely on every rebuild, and half the projects worth mapping are repositories we ship.
6
- * Everything here reads that store; building one is `cmd-tools-graphify.sh`.
7
- */
8
-
9
- const fs = require('fs');
10
- const path = require('path');
11
-
12
- const { ROOT } = require('./workspaces');
13
-
14
- // Where a project's graph lives: the graphs workspace, never inside the project. graphify only
15
- // writes <project>/graphify-out, so cmd-tools-graphify.sh moves the result here — a graph is tens
16
- // of MB, it re-diffs entirely on every rebuild, and half the projects worth mapping are
17
- // repositories we ship.
18
- function graphStoreDir(wsKey, project) {
19
- return path.join(ROOT, 'graphs', wsKey, project);
20
- }
21
-
22
- // Graph lookups per project row, memoised for 2s: projectRowsHtml is
23
- // re-rendered on every job poll.
24
- let _graphCache = new Map();
25
- let _graphCacheAt = 0;
26
- function hasGraph(wsKey, project, file) {
27
- const now = Date.now();
28
- if (now - _graphCacheAt > 2000) { _graphCache = new Map(); _graphCacheAt = now; }
29
- const k = `${wsKey}/${project}/${file}`;
30
- if (!_graphCache.has(k)) _graphCache.set(k, fs.existsSync(path.join(graphStoreDir(wsKey, project), file)));
31
- return _graphCache.get(k);
32
- }
33
-
34
- // Node and edge counts, memoised on the graph file's identity so paging a long list re-reads
35
- // nothing. Keyed on mtime+size: a rebuild changes both.
36
- const _graphCounts = new Map();
37
- function graphCounts(file, stat) {
38
- if (!stat) return { nodes: null, links: null };
39
- const key = `${file}:${stat.mtimeMs}:${stat.size}`;
40
- if (_graphCounts.has(key)) return _graphCounts.get(key);
41
- let counts = { nodes: null, links: null };
42
- try {
43
- const d = JSON.parse(fs.readFileSync(file, 'utf8'));
44
- counts = { nodes: (d.nodes || []).length, links: (d.links || d.edges || []).length };
45
- } catch (_) { /* unreadable or half-written */ }
46
- _graphCounts.set(key, counts);
47
- return counts;
48
- }
49
-
50
- // Every graph in the store, as <workspace>/<project> rows. Reads the two levels the build writes
51
- // and nothing else, so a stray file in graphs/ cannot become a row.
52
- function listGraphs() {
53
- const base = path.join(ROOT, 'graphs');
54
- const rows = [];
55
- let workspaces = [];
56
- try {
57
- workspaces = fs.readdirSync(base, { withFileTypes: true }).filter((e) => e.isDirectory());
58
- } catch (_) {
59
- return rows;
60
- }
61
- for (const ws of workspaces) {
62
- let projects = [];
63
- try {
64
- projects = fs.readdirSync(path.join(base, ws.name), { withFileTypes: true }).filter((e) => e.isDirectory());
65
- } catch (_) { continue; }
66
- for (const pr of projects) {
67
- const dir = path.join(base, ws.name, pr.name);
68
- const stat = (f) => { try { return fs.statSync(path.join(dir, f)); } catch (_) { return null; } };
69
- const json = stat('graph.json');
70
- // The counts come from graph.json itself — .graphify_build.json carries only the excludes,
71
- // so the numbers were rendering empty. Parsing is cheap enough (20ms for a 2,430-node graph)
72
- // and the result is memoised on the file's mtime and size, so a re-render costs nothing.
73
- const nodes_links = graphCounts(path.join(dir, 'graph.json'), json);
74
- const nodes = nodes_links.nodes;
75
- const links = nodes_links.links;
76
- let size = 0;
77
- const walk = (d) => {
78
- let entries = [];
79
- try { entries = fs.readdirSync(d, { withFileTypes: true }); } catch (_) { return; }
80
- for (const e of entries) {
81
- const full = path.join(d, e.name);
82
- if (e.isDirectory()) walk(full);
83
- else { try { size += fs.statSync(full).size; } catch (_) { /* gone */ } }
84
- }
85
- };
86
- walk(dir);
87
- rows.push({
88
- workspace: ws.name,
89
- project: pr.name,
90
- name: `${ws.name}/${pr.name}`,
91
- mtime: json ? json.mtime : new Date(0),
92
- size,
93
- nodes,
94
- links,
95
- hasHtml: !!stat('graph.html'),
96
- hasReport: !!stat('GRAPH_REPORT.md'),
97
- projectExists: fs.existsSync(path.join(ROOT, ws.name, pr.name)),
98
- });
99
- }
100
- }
101
- return rows;
102
- }
103
-
104
- module.exports = { graphStoreDir, hasGraph, graphCounts, listGraphs };