@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
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env bash
2
+
3
+ ################################################################################
4
+ ## Webship Workspace — align the dashboard's docker group with this host
5
+ ################################################################################
6
+ ## The dashboard runs in its own DDEV web container with Docker-outside-of-Docker:
7
+ ## the host's /var/run/docker.sock is bind-mounted in, and that socket is
8
+ ## root:docker with the HOST's docker GID. The container's web user therefore has
9
+ ## to share that exact GID, or every `ddev` command inside the dashboard fails:
10
+ ##
11
+ ## Docker error: permission denied while trying to connect to the docker API
12
+ ##
13
+ ## which does not look like a permissions problem from the outside. It looks like
14
+ ## a dashboard where every project is "Stopped" forever, no Start/Stop/Drush item
15
+ ## ever appears, and pressing Start seems to do nothing — while the project is in
16
+ ## fact running perfectly well on the host.
17
+ ##
18
+ ## bash core/scripts/docker-gid.sh align it, if it differs
19
+ ## bash core/scripts/docker-gid.sh --check report, change nothing
20
+ ## bash core/scripts/docker-gid.sh --quiet only speak when something changed
21
+ ##
22
+ ## The GID has to be baked at BUILD time, in
23
+ ## .ddev/web-build/Dockerfile.workspace-app: the container's main process runs as
24
+ ## uid 1000 (`Config.User=1000:1000`), so no entrypoint script can groupmod its
25
+ ## way out of it, and supervisord launches the app without calling initgroups() —
26
+ ## so it must be the web user's PRIMARY group, not a supplementary one.
27
+ ##
28
+ ## Which means the value in that file is machine-specific, in a file that
29
+ ## cmd-tools sync-tooling.sh mirrors wholesale. That is why this exists as a
30
+ ## script rather than a note in the README: install.sh runs it during setup, and
31
+ ## sync-tooling.sh runs it after mirroring, so a pull cannot leave the dashboard
32
+ ## blind to Docker.
33
+ ################################################################################
34
+
35
+ set -u
36
+
37
+ CHECK_ONLY='no'
38
+ QUIET='no'
39
+ while [ $# -gt 0 ]; do
40
+ case "$1" in
41
+ -c|--check) CHECK_ONLY='yes'; shift ;;
42
+ -q|--quiet) QUIET='yes'; shift ;;
43
+ -h|--help) sed -n '3,34p' "${BASH_SOURCE[0]}" | sed 's/^## \{0,1\}//'; exit 0 ;;
44
+ *) echo "Unknown option: $1 (see --help)"; exit 1 ;;
45
+ esac
46
+ done
47
+
48
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
49
+ DOCKERFILE="${ROOT}/core/workspace-app/.ddev/web-build/Dockerfile.workspace-app"
50
+ COMPOSE="${ROOT}/core/workspace-app/.ddev/docker-compose.dood.yaml"
51
+
52
+ function say() { [ "${QUIET}" == 'yes' ] || echo "$@" ; }
53
+ function warn() { echo "$@" ; }
54
+
55
+ if [ ! -f "${DOCKERFILE}" ] ; then
56
+ warn " ✗ No ${DOCKERFILE#${ROOT}/} — nothing to align."
57
+ exit 1
58
+ fi
59
+
60
+ # The socket is the authority when it is there: it is the thing the container has
61
+ # to reach. Fall back to the docker group, for a machine where Docker is not up.
62
+ host_gid=''
63
+ if [ -S /var/run/docker.sock ] ; then
64
+ host_gid="$(stat -c %g /var/run/docker.sock 2>/dev/null)"
65
+ fi
66
+ if [ -z "${host_gid}" ] ; then
67
+ host_gid="$(getent group docker 2>/dev/null | cut -d: -f3)"
68
+ fi
69
+ if [ -z "${host_gid}" ] ; then
70
+ warn " ✗ No docker group and no /var/run/docker.sock — is Docker installed?"
71
+ exit 1
72
+ fi
73
+
74
+ # Both numbers in the file are the same GID: the group, then the web user's primary group.
75
+ baked="$(grep -oE 'groupmod -g [0-9]+ docker' "${DOCKERFILE}" | grep -oE '[0-9]+' | head -1)"
76
+ if [ -z "${baked}" ] ; then
77
+ warn " ✗ Could not find the docker GID in ${DOCKERFILE##*/} — has that line changed?"
78
+ exit 1
79
+ fi
80
+
81
+ # The build-time GID makes the group exist in the image; the compose group_add is
82
+ # what puts the running process in it. Both have to be right, and they are the same
83
+ # number, so they are checked and written together.
84
+ granted=""
85
+ if [ -f "${COMPOSE}" ] ; then
86
+ granted="$(sed -n '/group_add:/,/^[^ ]/p' "${COMPOSE}" | grep -oE '"[0-9]+"' | tr -d '"' | head -1)"
87
+ fi
88
+
89
+ if [ "${baked}" == "${host_gid}" ] && { [ -z "${granted}" ] || [ "${granted}" == "${host_gid}" ]; } ; then
90
+ say " ✓ dashboard docker GID ${baked} matches this host"
91
+ exit 0
92
+ fi
93
+
94
+ if [ "${CHECK_ONLY}" == 'yes' ] ; then
95
+ warn " ✗ dashboard docker GID is ${baked}${granted:+ (granted ${granted})}, this host's docker socket is ${host_gid}"
96
+ warn " Every ddev command inside the dashboard fails, so every project reads as Stopped."
97
+ warn " Fix it: bash core/scripts/docker-gid.sh && (cd core/workspace-app && ddev restart)"
98
+ exit 1
99
+ fi
100
+
101
+ # Rewrite both occurrences on that one line, and nothing else in the file.
102
+ sed -i -E "s/groupmod -g [0-9]+ docker/groupmod -g ${host_gid} docker/; s/groupadd -g [0-9]+ docker/groupadd -g ${host_gid} docker/; s/usermod -g [0-9]+ \\\$username/usermod -g ${host_gid} \$username/" "${DOCKERFILE}"
103
+
104
+ # group_add in the compose override: the one the running process actually gets.
105
+ if [ -f "${COMPOSE}" ] && [ -n "${granted}" ] ; then
106
+ sed -i -E "/group_add:/,/^[^ ]/ s/\"${granted}\"/\"${host_gid}\"/" "${COMPOSE}"
107
+ fi
108
+
109
+ after="$(grep -oE 'groupmod -g [0-9]+ docker' "${DOCKERFILE}" | grep -oE '[0-9]+' | head -1)"
110
+ if [ "${after}" != "${host_gid}" ] ; then
111
+ warn " ✗ Tried to set the docker GID to ${host_gid} and the file still says ${after}."
112
+ warn " Edit ${DOCKERFILE#${ROOT}/} by hand — the line is near the end."
113
+ exit 1
114
+ fi
115
+
116
+ warn " ✓ dashboard docker GID ${baked} → ${host_gid} (this host's docker socket)"
117
+ warn " The image carries the old GID until it is rebuilt:"
118
+ warn " cd ${ROOT}/core/workspace-app && ddev restart"
119
+ exit 0
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+
3
+ argparse "$@" <<ARGEOF || exit 1
4
+ parser.add_argument('PROJECT_NAME',
5
+ help='The name of the project. It becomes https://<PROJECT_NAME>.ddev.site')
6
+ parser.add_argument('-v', '--site-template-version',
7
+ default="",
8
+ help='Composer constraint for the site template. Example: --site-template-version "^1.0". Default: the latest release.')
9
+ parser.add_argument('-p', '--php-version',
10
+ default="8.3",
11
+ help='PHP version for the DDEV project [default %(default)s].')
12
+ parser.add_argument('-i', '--install',
13
+ action='store_true',
14
+ default=False,
15
+ help='Install the site with this template after building it. Without this the build stops at a codebase, exactly as every other builder in the workspace does, and you pick the template in the browser installer.')
16
+ parser.add_argument('-s', '--skip-install',
17
+ action='store_true',
18
+ default=False,
19
+ help='Explicitly stop at the codebase. That is already what happens without --install; the flag exists so a script that passes it keeps working.')
20
+ parser.add_argument('-l', '--launch',
21
+ action='store_true',
22
+ default=False,
23
+ help='Open the site in a browser when it is ready.')
24
+ parser.add_argument('-r', '--require',
25
+ default="_none_",
26
+ nargs='+',
27
+ help='Require more packages by composer. Example: --require "drupal/token:~1.0"')
28
+ ARGEOF
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Tracks what ai-items installed where, so a later run can tell "is this stale"
4
+ # without re-copying anything. One lock file per .claude root (global ~/.claude,
5
+ # or a project's own .claude/), covering agents, skills and prompts together.
6
+ #
7
+ # Two kinds of source get two kinds of hash, same split as skills.sh:
8
+ # repo-sourced (ai_items_fetch, dest claude) -> the git object sha for that
9
+ # path at the fetched ref. We already hold a local clone when fetching, so
10
+ # `git rev-parse <ref>:<path>` gets it for free — no extra network call.
11
+ # workspace-sourced (install_ai_item) -> a local content hash of the
12
+ # workspace draft, recomputed on check with no network at all.
13
+ #
14
+ # ai_items_check reads the lock and, only for entries still claiming a repo
15
+ # source, fetches the WHOLE remote tree once (one `gh api` call covers every
16
+ # item being checked) rather than one call per item.
17
+
18
+ function ai_items_lock_file() {
19
+ local install_dir="$1";
20
+ echo "$(dirname "${install_dir}")/.ai-items-lock.json" ;
21
+ }
22
+
23
+ # Local content hash: sha256 of a file, or a sorted hash-of-hashes for a directory.
24
+ # Deterministic across runs on the same content; not meant to match any external hash.
25
+ function ai_items_local_hash() {
26
+ local path="$1";
27
+ if [ -f "${path}" ]; then
28
+ sha256sum "${path}" | awk '{print $1}' ;
29
+ elif [ -d "${path}" ]; then
30
+ find "${path}" -type f | LC_ALL=C sort | xargs sha256sum 2>/dev/null | sha256sum | awk '{print $1}' ;
31
+ fi
32
+ }
33
+
34
+ # Add or update one item's entry in the lock file next to `install_dir`.
35
+ function ai_items_lock_set() {
36
+ local install_dir="$1" kind="$2" name="$3" source="$4" source_type="$5" source_path="$6" hash="$7";
37
+ local lock_file; lock_file=$(ai_items_lock_file "${install_dir}") ;
38
+ python3 - "${lock_file}" "${kind}" "${name}" "${source}" "${source_type}" "${source_path}" "${hash}" <<'PYEOF'
39
+ import json, sys, pathlib, datetime
40
+ lock_file, kind, name, source, source_type, source_path, hash_ = sys.argv[1:8]
41
+ p = pathlib.Path(lock_file)
42
+ try:
43
+ data = json.loads(p.read_text())
44
+ except Exception:
45
+ data = {"version": 1, "items": {}}
46
+ data.setdefault("items", {})
47
+ key = f"{kind}:{name}"
48
+ now = datetime.datetime.now(datetime.timezone.utc).isoformat()
49
+ existing = data["items"].get(key, {})
50
+ data["items"][key] = {
51
+ "kind": kind,
52
+ "name": name,
53
+ "source": source,
54
+ "sourceType": source_type,
55
+ "sourcePath": source_path,
56
+ "hash": hash_,
57
+ "installedAt": existing.get("installedAt", now),
58
+ "updatedAt": now,
59
+ }
60
+ p.parent.mkdir(parents=True, exist_ok=True)
61
+ p.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n")
62
+ PYEOF
63
+ }
64
+
65
+ # Rows of "name\tsourceType\tsource\tsourcePath\thash" for entries of one kind
66
+ # (optionally one name), read straight out of the lock file.
67
+ function ai_items_lock_rows() {
68
+ local lock_file="$1" kind="$2" name="${3:-}";
69
+ [ -f "${lock_file}" ] || return 0 ;
70
+ python3 - "${lock_file}" "${kind}" "${name}" <<'PYEOF'
71
+ import json, sys
72
+ lock_file, kind, name = sys.argv[1:4]
73
+ try:
74
+ data = json.loads(open(lock_file).read())
75
+ except Exception:
76
+ data = {"items": {}}
77
+ for _, entry in sorted(data.get("items", {}).items()):
78
+ if entry.get("kind") != kind:
79
+ continue
80
+ if name and name not in ("", "_all_") and entry.get("name") != name:
81
+ continue
82
+ print("\t".join([
83
+ entry.get("name", ""), entry.get("sourceType", ""), entry.get("source", ""),
84
+ entry.get("sourcePath", ""), entry.get("hash", ""),
85
+ ]))
86
+ PYEOF
87
+ }
88
+
89
+ # Compare the lock against reality for one install location, without touching
90
+ # the installed files. Repo-sourced entries are checked against ONE fetched
91
+ # remote tree (whichever ref the entry itself recorded); workspace-sourced
92
+ # entries are checked against the current workspace draft, purely locally.
93
+ function ai_items_check() {
94
+ local kind="$1" name="${2:-}" to="${3:-}";
95
+ local target; target=$(ai_items_install_path "${kind}" "${to}") || return 1 ;
96
+ if [ ! -d "${target}" ]; then
97
+ echo "Nothing installed at ${target}." ;
98
+ return 1 ;
99
+ fi
100
+ local lock_file; lock_file=$(ai_items_lock_file "${target}") ;
101
+ if [ ! -f "${lock_file}" ]; then
102
+ echo "No lock file at ${lock_file} — nothing workspace-tracked yet (installed before checking existed, or copied by hand).";
103
+ ai_items_skills_cli_check "${kind}" "${to}" ;
104
+ return 0 ;
105
+ fi
106
+
107
+ echo "*---------------------------------------------------------------------*";
108
+ echo " ${kind} — ${target}";
109
+ echo "*---------------------------------------------------------------------*";
110
+
111
+ local rows; rows=$(ai_items_lock_rows "${lock_file}" "${kind}" "${name}") ;
112
+ if [ -z "${rows}" ]; then
113
+ echo " Nothing workspace-tracked for '${name:-_all_}'.";
114
+ ai_items_skills_cli_check "${kind}" "${to}" ;
115
+ return 0 ;
116
+ fi
117
+
118
+ local tree_json="" repo_checked="";
119
+ local item_name source_type source source_path hash status remote_hash;
120
+
121
+ while IFS=$'\t' read -r item_name source_type source source_path hash ; do
122
+ [ -z "${item_name}" ] && continue ;
123
+ status="unknown";
124
+ if [ "${source_type}" == 'repo' ] ; then
125
+ # One recursive tree fetch covers every repo-sourced item being checked —
126
+ # cached per <repo>@<ref>, not re-fetched per item.
127
+ if [ "${repo_checked}" != "${source}" ] ; then
128
+ ensure_gh_cli > /dev/null 2>&1 ;
129
+ local repo="${source%@*}" ref="${source##*@}";
130
+ tree_json=$(gh api "repos/${repo}/git/trees/${ref}?recursive=1" 2>/dev/null) ;
131
+ repo_checked="${source}";
132
+ fi
133
+ if [ -z "${tree_json}" ] ; then
134
+ status="could not reach ${source}";
135
+ else
136
+ remote_hash=$(echo "${tree_json}" | jq -r --arg p "${source_path}" '.tree[]? | select(.path==$p) | .sha' 2>/dev/null) ;
137
+ if [ -z "${remote_hash}" ] ; then
138
+ status="removed upstream";
139
+ elif [ "${remote_hash}" == "${hash}" ] ; then
140
+ status="up to date";
141
+ else
142
+ status="update available";
143
+ fi
144
+ fi
145
+ else
146
+ # Workspace-sourced: recompute the draft's current hash, no network.
147
+ local draft_path="${WORKSPACE_ROOT}/${source_path}";
148
+ if [ ! -e "${draft_path}" ] ; then
149
+ status="draft removed (${draft_path})";
150
+ else
151
+ remote_hash=$(ai_items_local_hash "${draft_path}") ;
152
+ if [ "${remote_hash}" == "${hash}" ] ; then
153
+ status="up to date";
154
+ else
155
+ status="draft changed since install";
156
+ fi
157
+ fi
158
+ fi
159
+ printf " %-32s %-14s %s\n" "${item_name}" "(${source_type})" "${status}";
160
+ done <<< "${rows}"
161
+
162
+ ai_items_skills_cli_check "${kind}" "${to}" ;
163
+ return 0 ;
164
+ }
165
+
166
+ # Skills the skills.sh CLI installed live in ITS lock — its own `check` covers them.
167
+ # Global scope only: that CLI's check reads ~/.agents/.skill-lock.json, not a project's.
168
+ function ai_items_skills_cli_check() {
169
+ local kind="$1" to="$2";
170
+ [ "${kind}" == 'ai-skills' ] || return 0 ;
171
+ ai_items_skills_cli_available || return 0 ;
172
+ if [ -n "${to}" ] && [ ! "${to}" == '_none_' ] && [ ! "${to}" == 'claude' ] ; then return 0 ; fi
173
+ echo "skills.sh CLI (npx skills check):" ;
174
+ DISABLE_TELEMETRY=1 npx -y skills check || echo " (skills.sh CLI check failed — the workspace-tracked report above stands)" ;
175
+ }
@@ -0,0 +1,298 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # `--add <source>` and `--update`: the skills.sh verbs, on top of the lock file.
4
+ #
5
+ # add any GitHub repo -> ~/.claude (or one project's .claude/) + lock entry
6
+ # update re-copy every lock entry whose source moved, nothing else
7
+ #
8
+ # The Webship repo keeps its own dedicated verb (--fetch, curated + filtered);
9
+ # --add is for everything else: a public skills repo, a client's repo, a fork.
10
+
11
+ # Normalize a source into "owner/repo<TAB>ref<TAB>subpath" (ref/subpath may be empty).
12
+ # Accepts: owner/repo, owner/repo@ref, https://github.com/owner/repo[.git],
13
+ # and https://github.com/owner/repo/tree/ref[/subpath].
14
+ function ai_items_parse_source() {
15
+ local input="$1" owner_repo="" ref="" subpath="";
16
+
17
+ case "${input}" in
18
+ *github.com/*)
19
+ local path="${input#*github.com/}"; path="${path%/}";
20
+ if [[ "${path}" == */tree/* ]] ; then
21
+ owner_repo="${path%%/tree/*}";
22
+ local rest="${path#*/tree/}";
23
+ ref="${rest%%/*}";
24
+ [ "${rest}" != "${ref}" ] && subpath="${rest#*/}";
25
+ else
26
+ owner_repo="${path}";
27
+ fi
28
+ owner_repo="${owner_repo%.git}";
29
+ ;;
30
+ */*)
31
+ owner_repo="${input}";
32
+ if [[ "${owner_repo}" == *@* ]] ; then
33
+ ref="${owner_repo##*@}"; owner_repo="${owner_repo%@*}";
34
+ fi
35
+ ;;
36
+ *)
37
+ echo "Not a source I can read: '${input}'. Use owner/repo, owner/repo@ref, or a github.com URL." >&2 ;
38
+ return 1 ;
39
+ ;;
40
+ esac
41
+
42
+ if ! echo "${owner_repo}" | grep -qE '^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$' ; then
43
+ echo "Not a source I can read: '${input}'. Use owner/repo, owner/repo@ref, or a github.com URL." >&2 ;
44
+ return 1 ;
45
+ fi
46
+ if [[ "${subpath}" == *..* ]] ; then
47
+ echo "Refusing subpath with '..': ${subpath}" >&2 ;
48
+ return 1 ;
49
+ fi
50
+ printf '%s\t%s\t%s\n' "${owner_repo}" "${ref}" "${subpath}" ;
51
+ }
52
+
53
+ # Shallow-clone one repo@ref into a temp dir and print the dir. gh's credential
54
+ # helper covers private repos the caller can read; public ones need nothing.
55
+ function ai_items_clone_source() {
56
+ local owner_repo="$1" ref="$2" tmp;
57
+ tmp=$(mktemp -d) ;
58
+ ensure_git_github_auth ;
59
+ local ref_args=() ;
60
+ [ -n "${ref}" ] && ref_args=(--branch "${ref}") ;
61
+ if ! git clone --quiet --depth 1 "${ref_args[@]}" "https://github.com/${owner_repo}.git" "${tmp}/repo" 2>/dev/null ; then
62
+ echo "Could not clone ${owner_repo}${ref:+@${ref}} — check the name, ref and access." >&2 ;
63
+ rm -rf "${tmp}" ;
64
+ return 1 ;
65
+ fi
66
+ echo "${tmp}/repo" ;
67
+ }
68
+
69
+ # Discover items of one kind in a checkout, as "name<TAB>path-in-repo" rows.
70
+ # Skills are directories holding a SKILL.md; agents and prompts are .md files.
71
+ # Container dirs cover the skills.sh conventions plus this workspace's own.
72
+ function ai_items_discover() {
73
+ local kind="$1" root="$2" base="${3:-}";
74
+ local search="${root}${base:+/${base}}";
75
+ [ -d "${search}" ] || return 0 ;
76
+
77
+ if [ "${kind}" == 'ai-skills' ] ; then
78
+ # A subpath pointing straight at one skill.
79
+ if [ -f "${search}/SKILL.md" ] && [ -n "${base}" ] ; then
80
+ printf '%s\t%s\n' "$(basename "${search}")" "${base}" ;
81
+ return 0 ;
82
+ fi
83
+ local d container;
84
+ for container in "" "skills" ".claude/skills" ".agents/skills" ; do
85
+ local dir="${search}${container:+/${container}}";
86
+ [ -d "${dir}" ] || continue ;
87
+ for d in "${dir}"/*/ ; do
88
+ [ -f "${d}SKILL.md" ] || continue ;
89
+ local rel="${d#${root}/}"; rel="${rel%/}";
90
+ printf '%s\t%s\n' "$(basename "${d}")" "${rel}" ;
91
+ done
92
+ done
93
+ else
94
+ local container_names;
95
+ if [ "${kind}" == 'ai-agents' ] ; then
96
+ container_names=".claude/agents agents";
97
+ else
98
+ container_names=".claude/commands commands prompts";
99
+ fi
100
+ local f container;
101
+ for container in ${container_names} ; do
102
+ local dir="${search}/${container}";
103
+ [ -d "${dir}" ] || continue ;
104
+ for f in "${dir}"/*.md ; do
105
+ [ -f "${f}" ] || continue ;
106
+ case "$(basename "${f}")" in README.md|AGENTS.md|CLAUDE.md|RULES.md) continue ;; esac
107
+ local rel="${f#${root}/}";
108
+ printf '%s\t%s\n' "$(basename "${f}" .md)" "${rel}" ;
109
+ done
110
+ done
111
+ fi | sort -u ;
112
+ }
113
+
114
+ # The skills.sh CLI (github.com/vercel-labs/skills) is the ecosystem's own installer
115
+ # for the skills kind — same SKILL.md format, richer source support, its own lock and
116
+ # `update`. Delegate to it when node is here; agents and prompts stay on the bash path
117
+ # because that CLI only handles skills. AI_ITEMS_NO_SKILLS_CLI=1 opts out.
118
+ function ai_items_skills_cli_available() {
119
+ [ -n "${AI_ITEMS_NO_SKILLS_CLI}" ] && return 1 ;
120
+ command -v npx > /dev/null 2>&1 ;
121
+ }
122
+
123
+ # DISABLE_TELEMETRY: the CLI reports installed skill names to skills.sh for its
124
+ # leaderboard — fine for public repos, not for client or private ones, so off always.
125
+ function ai_items_skills_cli_add() {
126
+ local name="$1" source="$2" to="$3";
127
+ local skill_filter="${name:-*}";
128
+ [ "${skill_filter}" == '_all_' ] && skill_filter='*' ;
129
+ echo "Using the skills.sh CLI (npx skills add) — its own lock manages these; agents and prompts stay on the workspace tooling." ;
130
+ if [ -z "${to}" ] || [ "${to}" == '_none_' ] || [ "${to}" == 'claude' ] ; then
131
+ DISABLE_TELEMETRY=1 npx -y skills add "${source}" --skill "${skill_filter}" -a claude-code --copy -g -y ;
132
+ else
133
+ local project_dir="${WORKSPACE_ROOT}/${to}";
134
+ [ -d "${project_dir}" ] || { echo "No ${to}." >&2 ; return 1 ; }
135
+ ( cd "${project_dir}" && DISABLE_TELEMETRY=1 npx -y skills add "${source}" --skill "${skill_filter}" -a claude-code --copy -y ) ;
136
+ fi
137
+ }
138
+
139
+ function ai_items_skills_cli_update() {
140
+ local to="$1";
141
+ if [ -z "${to}" ] || [ "${to}" == '_none_' ] || [ "${to}" == 'claude' ] ; then
142
+ DISABLE_TELEMETRY=1 npx -y skills update -g -y ;
143
+ else
144
+ local project_dir="${WORKSPACE_ROOT}/${to}";
145
+ [ -d "${project_dir}" ] || return 0 ;
146
+ ( cd "${project_dir}" && DISABLE_TELEMETRY=1 npx -y skills update -p -y ) ;
147
+ fi
148
+ }
149
+
150
+ # Install items of one kind from any GitHub repo, and lock what was copied.
151
+ # name one item, or _all_/empty for everything discovered
152
+ # source owner/repo[@ref] or a github.com URL (tree URLs carry ref + subpath)
153
+ # to empty for ~/.claude, or <workspace>/<project>
154
+ function ai_items_add() {
155
+ local kind="$1" name="$2" source="$3" to="${4:-}";
156
+ name=$(ai_items_sanitize_name "${name}") || return 1 ;
157
+
158
+ if [ "${kind}" == 'ai-skills' ] && ai_items_skills_cli_available ; then
159
+ if ai_items_skills_cli_add "${name}" "${source}" "${to}" ; then
160
+ return 0 ;
161
+ fi
162
+ echo "skills.sh CLI could not add it — falling back to the workspace installer." ;
163
+ fi
164
+
165
+ local parsed owner_repo ref subpath;
166
+ parsed=$(ai_items_parse_source "${source}") || return 1 ;
167
+ IFS=$'\t' read -r owner_repo ref subpath <<< "${parsed}" ;
168
+
169
+ local target; target=$(ai_items_install_path "${kind}" "${to}") || return 1 ;
170
+ local checkout; checkout=$(ai_items_clone_source "${owner_repo}" "${ref}") || return 1 ;
171
+ local tmp_root; tmp_root=$(dirname "${checkout}") ;
172
+ local ref_name; ref_name=$(git -C "${checkout}" rev-parse --abbrev-ref HEAD 2>/dev/null) ;
173
+
174
+ local rows; rows=$(ai_items_discover "${kind}" "${checkout}" "${subpath}") ;
175
+ if [ -z "${rows}" ]; then
176
+ echo "No ${kind} found in ${owner_repo}${ref:+@${ref}}${subpath:+ under ${subpath}}." ;
177
+ rm -rf "${tmp_root}" ;
178
+ return 1 ;
179
+ fi
180
+
181
+ mkdir -p "${target}" ;
182
+ local copied=0 skipped=0 item path;
183
+ while IFS=$'\t' read -r item path ; do
184
+ [ -z "${item}" ] && continue ;
185
+ if [ -n "${name}" ] && [ "${name}" != '_all_' ] && [ "${item}" != "${name}" ] ; then continue ; fi
186
+ # Discovered names come from a remote repo: same character rule as everywhere else.
187
+ if ! echo "${item}" | grep -qE '^[a-zA-Z0-9_.-]+$' ; then
188
+ echo " skipping '${item}': unsafe name." ; skipped=$((skipped+1)) ; continue ;
189
+ fi
190
+ local sha; sha=$(git -C "${checkout}" rev-parse "HEAD:${path}" 2>/dev/null) ;
191
+ if [ "${kind}" == 'ai-skills' ] ; then
192
+ rsync -a --delete "${checkout}/${path}/" "${target}/${item}/" || { skipped=$((skipped+1)) ; continue ; }
193
+ else
194
+ cp "${checkout}/${path}" "${target}/" || { skipped=$((skipped+1)) ; continue ; }
195
+ fi
196
+ copied=$((copied+1)) ;
197
+ [ -n "${sha}" ] && ai_items_lock_set "${target}" "${kind}" "${item}" \
198
+ "${owner_repo}@${ref_name}" "repo" "${path}" "${sha}" ;
199
+ echo " + ${item}" ;
200
+ done <<< "${rows}"
201
+ rm -rf "${tmp_root}" ;
202
+
203
+ if [ "${copied}" -eq 0 ]; then
204
+ echo "No ${kind%s} '${name}' in ${owner_repo}${ref:+@${ref}} — nothing installed." ;
205
+ return 1 ;
206
+ fi
207
+ echo "Added ${copied} ${kind} from ${owner_repo}${ref:+@${ref}} into ${target}." ;
208
+ echo "Review third-party ${kind} before use — a session runs them with its full permissions." ;
209
+ echo "Restart your Claude Code session to pick it up." ;
210
+ }
211
+
212
+ # Re-copy every lock entry of one kind whose source moved. Repo entries are
213
+ # grouped so each repo@ref clones once; workspace entries re-install from the
214
+ # draft. Nothing is touched when the recorded hash still matches.
215
+ function ai_items_update() {
216
+ local kind="$1" name="${2:-}" to="${3:-}";
217
+ local target; target=$(ai_items_install_path "${kind}" "${to}") || return 1 ;
218
+ local lock_file; lock_file=$(ai_items_lock_file "${target}") ;
219
+
220
+ # No workspace-tracked entries is not "nothing to do" for skills: the
221
+ # skills.sh CLI keeps its own lock, and its update below still runs.
222
+ local rows="";
223
+ if [ -f "${lock_file}" ]; then
224
+ rows=$(ai_items_lock_rows "${lock_file}" "${kind}" "${name}") ;
225
+ fi
226
+ if [ -z "${rows}" ]; then
227
+ echo "Nothing workspace-tracked for '${name:-_all_}' at ${target}." ;
228
+ fi
229
+
230
+ local updated=0 checked=0 current_source="" checkout="" tmp_root="";
231
+ local item_name source_type source source_path hash;
232
+
233
+ # Sorting by source groups repo entries so one clone serves all of them.
234
+ while IFS=$'\t' read -r item_name source_type source source_path hash ; do
235
+ [ -z "${item_name}" ] && continue ;
236
+ checked=$((checked+1)) ;
237
+
238
+ if [ "${source_type}" == 'repo' ] ; then
239
+ if [ "${source}" != "${current_source}" ] ; then
240
+ [ -n "${tmp_root}" ] && rm -rf "${tmp_root}" ;
241
+ checkout=$(ai_items_clone_source "${source%@*}" "${source##*@}") || { checkout=""; tmp_root=""; current_source="${source}"; continue ; }
242
+ tmp_root=$(dirname "${checkout}") ;
243
+ current_source="${source}";
244
+ fi
245
+ [ -n "${checkout}" ] || { printf " %-32s %s\n" "${item_name}" "source unreachable" ; continue ; }
246
+ local sha; sha=$(git -C "${checkout}" rev-parse "HEAD:${source_path}" 2>/dev/null) ;
247
+ if [ -z "${sha}" ] ; then
248
+ printf " %-32s %s\n" "${item_name}" "removed upstream — left as is" ;
249
+ elif [ "${sha}" == "${hash}" ] ; then
250
+ printf " %-32s %s\n" "${item_name}" "up to date" ;
251
+ else
252
+ if [ "${kind}" == 'ai-skills' ] ; then
253
+ rsync -a --delete "${checkout}/${source_path}/" "${target}/${item_name}/" ;
254
+ else
255
+ cp "${checkout}/${source_path}" "${target}/" ;
256
+ fi
257
+ ai_items_lock_set "${target}" "${kind}" "${item_name}" "${source}" "repo" "${source_path}" "${sha}" ;
258
+ updated=$((updated+1)) ;
259
+ printf " %-32s %s\n" "${item_name}" "updated" ;
260
+ fi
261
+ else
262
+ local draft_path="${WORKSPACE_ROOT}/${source_path}";
263
+ if [ ! -e "${draft_path}" ] ; then
264
+ printf " %-32s %s\n" "${item_name}" "draft removed — left as is" ;
265
+ continue ;
266
+ fi
267
+ local new_hash; new_hash=$(ai_items_local_hash "${draft_path}") ;
268
+ if [ "${new_hash}" == "${hash}" ] ; then
269
+ printf " %-32s %s\n" "${item_name}" "up to date" ;
270
+ else
271
+ if [ "${kind}" == 'ai-skills' ] ; then
272
+ rsync -a "${draft_path}/" "${target}/${item_name}/" ;
273
+ else
274
+ cp "${draft_path}" "${target}/" ;
275
+ fi
276
+ ai_items_lock_set "${target}" "${kind}" "${item_name}" "workspace" "workspace" "${source_path}" "${new_hash}" ;
277
+ updated=$((updated+1)) ;
278
+ printf " %-32s %s\n" "${item_name}" "updated from draft" ;
279
+ fi
280
+ fi
281
+ done <<< "$(echo "${rows}" | sort -t$'\t' -k3,3)"
282
+
283
+ [ -n "${tmp_root}" ] && rm -rf "${tmp_root}" ;
284
+ echo "Checked ${checked}, updated ${updated}.";
285
+
286
+ # Skills the skills.sh CLI installed live in ITS lock, not this one — its own
287
+ # update covers them, after the workspace-tracked entries above. Its update has
288
+ # no per-skill filter, so a NAMED update stays on the workspace lock alone
289
+ # rather than refreshing every CLI-tracked skill as a side effect.
290
+ if [ "${kind}" == 'ai-skills' ] && ai_items_skills_cli_available \
291
+ && { [ -z "${name}" ] || [ "${name}" == '_all_' ] ; } ; then
292
+ echo "skills.sh CLI (npx skills update):" ;
293
+ ai_items_skills_cli_update "${to}" || echo " (skills.sh CLI update failed — workspace-tracked items above are done)" ;
294
+ fi
295
+
296
+ [ "${updated}" -gt 0 ] && echo "Restart your Claude Code session to pick the updates up." ;
297
+ return 0 ;
298
+ }