@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,441 @@
1
+ #!/usr/bin/env bash
2
+ # Avatars: talking AI characters as DDEV projects, in the avatars workspace.
3
+ #
4
+ # An avatar project is the avatar app (avatar.repo in workspace.avatars.settings.yml): a Node app on
5
+ # DDEV with no database, a VRM character, Claude Code as its mind, and browser, Piper or ElevenLabs
6
+ # voices. These functions build one, add characters to it (characters/<id>.json), give a character its
7
+ # own Claude Code agent, and set up voices. Each command wraps one of them:
8
+ #
9
+ # cmd-avatar-project.sh build_avatar
10
+ # cmd-tools-avatar-character.sh avatar_character
11
+ # cmd-tools-avatar-agent.sh avatar_agent
12
+ # cmd-tools-avatar-voice.sh avatar_voice
13
+ # cmd-tools-avatar-catalog.sh avatar_catalog
14
+ #
15
+ # DDEV only: the app runs in its web container; nothing here installs Node on the host. Writing JSON
16
+ # and reading registries goes through python3, with every value passed in the environment, never
17
+ # spliced into code.
18
+
19
+ # A setting from the avatar: block, one layer of quotes stripped (parse_yaml keeps them) and a
20
+ # leading ~ expanded.
21
+ function avatar_setting() {
22
+ local value="${!1:-$2}";
23
+ value="${value#\"}"; value="${value%\"}";
24
+ value="${value#\'}"; value="${value%\'}";
25
+ [[ "${value}" == "~"* ]] && value="${HOME}${value:1}";
26
+ echo "${value}";
27
+ }
28
+
29
+ function avatar_dir() {
30
+ echo "${WORKSPACE_ROOT}/avatars/${1}";
31
+ }
32
+
33
+ # The project, or a clear refusal: it must be a folder holding the avatar app.
34
+ function avatar_require() {
35
+ local project="$1";
36
+ if [[ -z "${project}" || "${project}" == "_none_" ]]; then
37
+ echo "Name the avatar project, e.g. my-avatar." >&2 ;
38
+ return 1 ;
39
+ fi
40
+ if [[ ! -f "$(avatar_dir "${project}")/avatars.js" ]]; then
41
+ echo "No avatar project at $(avatar_dir "${project}") (no avatars.js there)." >&2 ;
42
+ return 1 ;
43
+ fi
44
+ }
45
+
46
+ # Restart only the app process (a web_extra_daemon), so new characters and agents are read. Quicker
47
+ # than ddev restart and leaves the container alone. Does nothing when the project is stopped.
48
+ function avatar_restart_app() {
49
+ local dir="$1";
50
+ ( cd "${dir}" && ddev exec supervisorctl restart webextradaemons:avatar >/dev/null 2>&1 ) \
51
+ && echo "Restarted the avatar app." \
52
+ || echo "The project is not running; the change applies on the next ddev start." ;
53
+ }
54
+
55
+ # Build a new avatar project from the avatar app repository.
56
+ function build_avatar() {
57
+ local project; project="$( [[ "${PROJECT_NAME}" == "_settings_" ]] && avatar_setting avatar_project my-avatar || echo "${PROJECT_NAME}" )";
58
+ local repo; repo="$( [[ "${REPO}" == "_settings_" ]] && avatar_setting avatar_repo || echo "${REPO}" )";
59
+ if [[ -z "${repo}" || "${repo}" == "CHANGE_ME" ]]; then
60
+ echo "Set avatar.repo in core/config/workspace.avatars.settings.yml to the avatar app repository, or pass --repo <url>." >&2 ;
61
+ return 1 ;
62
+ fi
63
+ local branch; branch="$( [[ "${BRANCH}" == "_settings_" ]] && avatar_setting avatar_branch main || echo "${BRANCH}" )";
64
+ local dir; dir="$(avatar_dir "${project}")";
65
+
66
+ if [[ ! "${project}" =~ ^[a-z0-9][a-z0-9-]{1,62}$ ]]; then
67
+ echo "The project name becomes a hostname: lowercase letters, digits and hyphens only." >&2 ;
68
+ return 1 ;
69
+ fi
70
+ if [[ -e "${dir}" ]]; then
71
+ echo "${dir} already exists. Pick another name, or remove it first: bash cmd-tools-remove.sh ${project}" >&2 ;
72
+ return 1 ;
73
+ fi
74
+ # Names AND extra hostnames anywhere in the tree: a project's alias is as much a hostname as a name.
75
+ local owner; owner="$(ddev_hostname_owner "${project}")";
76
+ if [[ -n "${owner}" ]] || ddev describe "${project}" >/dev/null 2>&1; then
77
+ echo "${project}.ddev.site is already taken${owner:+ by ${owner}}. Pick another name." >&2 ;
78
+ return 1 ;
79
+ fi
80
+
81
+ echo "Cloning ${repo} (${branch}) into ${dir}" ;
82
+ git clone --branch "${branch}" "${repo}" "${dir}" || { echo "Clone failed. The repository is private: check your GitHub access." >&2 ; return 1 ; }
83
+
84
+ cd "${dir}" || return 1 ;
85
+ # The name comes from the folder. Any extra hostname the repository declares belongs to its first
86
+ # checkout only: two projects on one hostname is a router conflict where the last to start wins.
87
+ ddev config --project-name="${project}" --additional-hostnames="" >/dev/null || return 1 ;
88
+
89
+ ddev start -y || return 1 ;
90
+
91
+ if [[ "${LINK_AGENTS}" == "yes" ]]; then
92
+ avatar_link_agents "${dir}" ;
93
+ else
94
+ echo "Agents not linked. Link this project's agents into ~/.claude with: bash cmd-tools-avatar-agent.sh ${project} -a link" ;
95
+ fi
96
+
97
+ echo "" ;
98
+ echo "Ready: https://${project}.ddev.site and https://${project}.avatars.${hub_domain:-workspace.ddev.site}" ;
99
+ echo "Voices: bash cmd-tools-avatar-voice.sh ${project} Characters: bash cmd-tools-avatar-character.sh ${project} -a list" ;
100
+ [[ "${LAUNCH}" == "yes" ]] && ddev launch ;
101
+ return 0 ;
102
+ }
103
+
104
+ # --- Characters -------------------------------------------------------------------------------------
105
+
106
+ # Download a model into public/models/<id>.<ext>. SOURCE is an https URL, or osa:<name or id> from the
107
+ # Open Source Avatars registry. Sets AVATAR_FETCHED_MODEL, AVATAR_FETCHED_CREDIT and AVATAR_FETCHED_LICENSE.
108
+ function avatar_fetch_model() {
109
+ local dir="$1" id="$2" source="$3" url credit="" license="" registry_id="";
110
+ AVATAR_FETCHED_MODEL=""; AVATAR_FETCHED_CREDIT=""; AVATAR_FETCHED_LICENSE=""; AVATAR_FETCHED_REGISTRY_ID="";
111
+
112
+ if [[ "${source}" == osa:* ]]; then
113
+ local found;
114
+ found="$(OSA_URL="$(avatar_setting avatar_osa_index_url)" OSA_WANT="${source#osa:}" python3 - <<'PY'
115
+ import json, os, sys, urllib.request
116
+ base, want = os.environ['OSA_URL'], os.environ['OSA_WANT'].strip().lower()
117
+ get = lambda name: json.load(urllib.request.urlopen(f'{base}/{name}', timeout=30))
118
+ # Each collection lists its own avatars (avatar_data_file); its licence is on the collection.
119
+ hits = []
120
+ for p in get('projects.json'):
121
+ if not p.get('is_public') or not p.get('avatar_data_file'):
122
+ continue
123
+ for a in get(p['avatar_data_file']):
124
+ if a.get('format') == 'VRM' and a.get('is_public') and (a['id'].lower() == want or a['name'].lower() == want):
125
+ hits.append((a, p))
126
+ if not hits:
127
+ sys.exit(1)
128
+ a, p = hits[0]
129
+ print(a['model_file_url'])
130
+ print(a['id'])
131
+ print(f"{a['name']} from {p.get('name', 'Open Source Avatars')} by {p.get('creator_id', 'unknown')}, via opensourceavatars.com")
132
+ print(p.get('license', 'unknown'))
133
+ PY
134
+ )" || { echo "No public VRM called '${source#osa:}' in the Open Source Avatars registry. List them: bash cmd-tools-avatar-catalog.sh -a avatars" >&2 ; return 1 ; }
135
+ url="$(sed -n 1p <<<"${found}")"; registry_id="$(sed -n 2p <<<"${found}")";
136
+ credit="$(sed -n 3p <<<"${found}")"; license="$(sed -n 4p <<<"${found}")";
137
+ elif [[ "${source}" == https://* ]]; then
138
+ url="${source}";
139
+ else
140
+ echo "A model is an https URL or osa:<name>, or --model-file for a file already in public/models/." >&2 ;
141
+ return 1 ;
142
+ fi
143
+
144
+ mkdir -p "${dir}/public/models" ;
145
+ local target="${dir}/public/models/${id}.vrm" tmp;
146
+ tmp="$(mktemp)";
147
+ echo "Downloading the model for ${id}" ;
148
+ if ! curl -fsSL --proto '=https' --max-filesize 104857600 -o "${tmp}" "${url}"; then
149
+ rm -f "${tmp}" ; echo "Download failed: ${url}" >&2 ; return 1 ;
150
+ fi
151
+ # A VRM is a binary glTF: the first four bytes are "glTF". Anything else is not a model.
152
+ if [[ "$(head -c 4 "${tmp}")" != "glTF" ]]; then
153
+ rm -f "${tmp}" ; echo "That file is not a VRM/glTF model (no glTF header)." >&2 ; return 1 ;
154
+ fi
155
+ mv "${tmp}" "${target}" && chmod 644 "${target}" ;
156
+ AVATAR_FETCHED_MODEL="/models/${id}.vrm"; AVATAR_FETCHED_CREDIT="${credit}"; AVATAR_FETCHED_LICENSE="${license}";
157
+ AVATAR_FETCHED_REGISTRY_ID="${registry_id}";
158
+ }
159
+
160
+ function avatar_character() {
161
+ avatar_require "${PROJECT_NAME}" || return 1 ;
162
+ local dir; dir="$(avatar_dir "${PROJECT_NAME}")";
163
+ mkdir -p "${dir}/characters" ;
164
+
165
+ case "${ACTION}" in
166
+ list)
167
+ ( cd "${dir}" && DIR="${dir}" python3 - <<'PY'
168
+ import json, os, re
169
+ d = os.environ['DIR']
170
+ src = open(os.path.join(d, 'avatars.js'), encoding='utf8').read()
171
+ for m in re.finditer(r"\n id: '([^']+)',\n name: '([^']+)'", src):
172
+ print(f" {m.group(1):<20} {m.group(2):<20} built in (avatars.js)")
173
+ for f in sorted(os.listdir(os.path.join(d, 'characters'))):
174
+ if f.endswith('.json'):
175
+ try:
176
+ c = json.load(open(os.path.join(d, 'characters', f), encoding='utf8'))
177
+ v = c.get('voice', {})
178
+ print(f" {c.get('id', '?'):<20} {c.get('name', '?'):<20} characters/{f} voice: {v.get('engine')}/{v.get('voice')} agent: {c.get('agent', '-')}")
179
+ except Exception as e:
180
+ print(f" {f}: unreadable ({e})")
181
+ PY
182
+ ) ;;
183
+ add)
184
+ if [[ "${ID}" == "_none_" || ! "${ID}" =~ ^[a-z0-9][a-z0-9-]{0,39}$ ]]; then
185
+ echo "--id is required: lowercase letters, digits and hyphens, e.g. ada." >&2 ; return 1 ;
186
+ fi
187
+ [[ "${NAME}" == "_none_" ]] && { echo "--name is required." >&2 ; return 1 ; }
188
+ if [[ -e "${dir}/characters/${ID}.json" && "${REPLACE}" != "yes" ]]; then
189
+ echo "characters/${ID}.json exists. Pass --replace to overwrite it." >&2 ; return 1 ;
190
+ fi
191
+
192
+ local model="" credit="${CREDIT}" license="" registry_id="";
193
+ if [[ "${MODEL_FILE}" != "_none_" ]]; then
194
+ [[ -f "${dir}/public/models/${MODEL_FILE}" ]] || { echo "No public/models/${MODEL_FILE} in the project." >&2 ; return 1 ; }
195
+ model="/models/${MODEL_FILE}";
196
+ elif [[ "${MODEL}" != "_none_" ]]; then
197
+ avatar_fetch_model "${dir}" "${ID}" "${MODEL}" || return 1 ;
198
+ model="${AVATAR_FETCHED_MODEL}"; license="${AVATAR_FETCHED_LICENSE}"; registry_id="${AVATAR_FETCHED_REGISTRY_ID}";
199
+ [[ "${credit}" == "_none_" ]] && credit="${AVATAR_FETCHED_CREDIT}";
200
+ else
201
+ echo "Give the character a model: --model <https URL | osa:<name>> or --model-file <file in public/models/>." >&2 ;
202
+ return 1 ;
203
+ fi
204
+
205
+ # Free voices by default: the settings' engine and voice, unless the command names others.
206
+ local engine="${VOICE_ENGINE}" voice="${VOICE}";
207
+ [[ "${engine}" == "_settings_" ]] && engine="$(avatar_setting avatar_voice_engine piper)";
208
+ if [[ "${voice}" == "_settings_" ]]; then
209
+ if [[ "${engine}" == "piper" ]]; then voice="$(avatar_setting avatar_voice en_US-lessac-medium)"; else voice=""; fi
210
+ fi
211
+ if [[ "${engine}" == "elevenlabs" && -z "${voice}" ]]; then
212
+ echo "An ElevenLabs voice needs --voice <voice id>; ElevenLabs spends credits for every sentence." >&2 ; return 1 ;
213
+ fi
214
+
215
+ local persona="";
216
+ if [[ "${PERSONA_FILE}" != "_none_" ]]; then
217
+ [[ -f "${PERSONA_FILE}" ]] || { echo "No persona file at ${PERSONA_FILE}." >&2 ; return 1 ; }
218
+ persona="$(cat "${PERSONA_FILE}")";
219
+ fi
220
+
221
+ C_DIR="${dir}" C_ID="${ID}" C_NAME="${NAME}" C_MODEL="${model}" C_CREDIT="$([[ "${credit}" == "_none_" ]] || echo "${credit}")" \
222
+ C_LICENSE="${license}" C_REGISTRY="${registry_id}" C_LANG="${LANGUAGE}" C_GENDER="$([[ "${GENDER}" == "_none_" ]] || echo "${GENDER}")" \
223
+ C_ENGINE="${engine}" C_VOICE="${voice}" C_PERSONA="${persona}" \
224
+ C_AGENT="$([[ "${AGENT}" == "_none_" ]] || echo "${AGENT}")" python3 - <<'PY' || return 1
225
+ import json, os
226
+ e = os.environ
227
+ c = {'id': e['C_ID'], 'name': e['C_NAME'], 'title': e['C_NAME'], 'model': e['C_MODEL'], 'language': e['C_LANG'],
228
+ 'voice': {'engine': e['C_ENGINE'], 'voice': e['C_VOICE'], 'rate': 1, 'pitch': 1},
229
+ 'fallback': {'engine': 'browser', 'voice': '', 'rate': 1, 'pitch': 1}}
230
+ for key, env in (('gender', 'C_GENDER'), ('agent', 'C_AGENT'), ('persona', 'C_PERSONA'), ('registryId', 'C_REGISTRY')):
231
+ if e.get(env):
232
+ c[key] = e[env]
233
+ credit = e.get('C_CREDIT', '')
234
+ if e.get('C_LICENSE'):
235
+ credit = f"{credit}. Licence: {e['C_LICENSE']} (as the registry lists it; confirm on the avatar's page)".lstrip('. ')
236
+ if credit:
237
+ c['credit'] = credit
238
+ path = os.path.join(e['C_DIR'], 'characters', f"{c['id']}.json")
239
+ with open(path, 'w', encoding='utf8') as f:
240
+ json.dump(c, f, ensure_ascii=False, indent=2)
241
+ f.write('\n')
242
+ print(f"Wrote characters/{c['id']}.json")
243
+ PY
244
+ [[ -n "${license}" ]] && echo "Licence from the registry: ${license}. Confirm it on the avatar's own page before you share it." ;
245
+ avatar_restart_app "${dir}" ;
246
+ echo "Give ${NAME} a mind of its own: bash cmd-tools-avatar-agent.sh ${PROJECT_NAME} -a create --id ${ID}" ;
247
+ ;;
248
+ remove)
249
+ [[ -f "${dir}/characters/${ID}.json" ]] || { echo "No characters/${ID}.json in ${PROJECT_NAME}." >&2 ; return 1 ; }
250
+ # The JSON is moved aside, not deleted, and the model file is left where it is.
251
+ mv "${dir}/characters/${ID}.json" "${dir}/characters/${ID}.json.removed" ;
252
+ echo "Moved characters/${ID}.json to characters/${ID}.json.removed (its model in public/models/ is kept)." ;
253
+ avatar_restart_app "${dir}" ;
254
+ ;;
255
+ esac
256
+ }
257
+
258
+ # --- Agents -----------------------------------------------------------------------------------------
259
+
260
+ # Link the agents a project keeps in claude/agents/ (and its knowledge files in claude/) into ~/.claude,
261
+ # where Claude Code reads them; or only the files given after the project folder. A real file already
262
+ # there is kept aside as .bak. A link that points at ANOTHER project's copy is left alone unless
263
+ # REPLACE=yes: every avatar project is a clone of the same app, so each one carries the app's own
264
+ # agents, and linking them all would silently move those agents to whichever copy was linked last.
265
+ function avatar_link_agents() {
266
+ local dir="$1"; shift;
267
+ local files=("$@") f dest current;
268
+ [[ ${#files[@]} -eq 0 ]] && files=("${dir}"/claude/agents/*.md "${dir}"/claude/*.md);
269
+ mkdir -p "${HOME}/.claude/agents" ;
270
+ for f in "${files[@]}"; do
271
+ [[ -f "${f}" ]] || continue ;
272
+ dest="${HOME}/.claude/${f#"${dir}/claude/"}";
273
+ current="$(readlink "${dest}" 2>/dev/null)";
274
+ if [[ -n "${current}" && "${current}" != "${f}" && -e "${current}" && "${REPLACE}" != "yes" ]]; then
275
+ echo "left ${dest}: it links to ${current} (pass --replace to point it here)" ;
276
+ continue ;
277
+ fi
278
+ if [[ -e "${dest}" && ! -L "${dest}" ]]; then mv "${dest}" "${dest}.bak"; echo "kept the old ${dest} as ${dest}.bak"; fi
279
+ ln -sfn "${f}" "${dest}" && echo "linked ${dest}" ;
280
+ done
281
+ }
282
+
283
+ function avatar_agent() {
284
+ avatar_require "${PROJECT_NAME}" || return 1 ;
285
+ local dir; dir="$(avatar_dir "${PROJECT_NAME}")";
286
+ local prefix; prefix="$(avatar_setting avatar_agent_prefix avatar-)";
287
+
288
+ case "${ACTION}" in
289
+ list)
290
+ local f name target;
291
+ for f in "${dir}"/claude/agents/*.md; do
292
+ [[ -f "${f}" ]] || continue ;
293
+ name="$(basename "${f}" .md)";
294
+ target="$(readlink "${HOME}/.claude/agents/${name}.md" 2>/dev/null)";
295
+ if [[ "${target}" == "${f}" ]]; then echo " ${name} linked"; elif [[ -n "${target}" ]]; then echo " ${name} linked to ANOTHER copy: ${target}"; else echo " ${name} not linked"; fi
296
+ done ;;
297
+ link)
298
+ avatar_link_agents "${dir}" ;
299
+ avatar_restart_app "${dir}" ;;
300
+ create)
301
+ [[ "${ID}" == "_none_" ]] && { echo "--id is required: the character the agent is the mind of." >&2 ; return 1 ; }
302
+ local character="${dir}/characters/${ID}.json" agent="${prefix}${ID}";
303
+ [[ -f "${character}" ]] || { echo "No characters/${ID}.json. Add the character first: bash cmd-tools-avatar-character.sh ${PROJECT_NAME} -a add --id ${ID} ..." >&2 ; return 1 ; }
304
+ local file="${dir}/claude/agents/${agent}.md";
305
+ if [[ -e "${file}" && "${REPLACE}" != "yes" ]]; then
306
+ echo "claude/agents/${agent}.md exists. Pass --replace to write it again." >&2 ; return 1 ;
307
+ fi
308
+ mkdir -p "${dir}/claude/agents" ;
309
+ A_CHAR="${character}" A_FILE="${file}" A_NAME="${agent}" A_HOST="${PROJECT_NAME}.ddev.site" python3 - <<'PY' || return 1
310
+ import json, os
311
+ e = os.environ
312
+ c = json.load(open(e['A_CHAR'], encoding='utf8'))
313
+ name, who = e['A_NAME'], c['name']
314
+ persona = c.get('persona') or f"You are {who}, a friendly guide who answers questions clearly and kindly."
315
+ body = f"""---
316
+ name: {name}
317
+ description: Use this agent to be {who}, the talking character of the avatar at https://{e['A_HOST']} (speaking, moving, lip-synced), and in a terminal. Invoke for "talk to {who}" or "{who}, ...".
318
+ tools: Read, Glob, Grep, Skill
319
+ ---
320
+
321
+ {persona}
322
+
323
+ ## How you speak
324
+
325
+ - You are heard, not read: short sentences, one idea each, no lists or headings, no Markdown.
326
+ - Answer in the language the user writes in.
327
+ - Keep gesture tags such as [wave], [think] or [cheer] for the start of a sentence; the avatar plays them.
328
+ - You can read files in the workspace to answer, but you never change anything.
329
+ """
330
+ open(e['A_FILE'], 'w', encoding='utf8').write(body)
331
+ c['agent'] = name
332
+ json.dump(c, open(e['A_CHAR'], 'w', encoding='utf8'), ensure_ascii=False, indent=2)
333
+ print(f"Wrote claude/agents/{name}.md and set \"agent\": \"{name}\" in characters/{c['id']}.json")
334
+ PY
335
+ avatar_link_agents "${dir}" "${file}" ;
336
+ avatar_restart_app "${dir}" ;
337
+ echo "Edit the agent to give ${ID} its voice and knowledge: ${file}" ;;
338
+ check)
339
+ echo "Claude Code in the container:" ;
340
+ ( cd "${dir}" && ddev exec claude --version 2>/dev/null ) || echo " not available: is the project running? (ddev start)" ;
341
+ ( cd "${dir}" && ddev exec test -s "${HOME}/.claude/.credentials.json" 2>/dev/null ) \
342
+ && echo " logged in (your ~/.claude is mounted)" \
343
+ || echo " no login found in the container: run claude once on this machine and log in, then ddev restart" ;
344
+ ACTION=list avatar_agent ;;
345
+ esac
346
+ }
347
+
348
+ # --- Voices -----------------------------------------------------------------------------------------
349
+
350
+ function avatar_voice() {
351
+ local piper_dir; piper_dir="$(avatar_setting avatar_piper_voices_dir "${HOME}/.local/share/piper-voices")";
352
+ local dir="";
353
+ if [[ "${ACTION}" != "piper-list" && "${ACTION}" != "piper-install" ]]; then
354
+ avatar_require "${PROJECT_NAME}" || return 1 ;
355
+ dir="$(avatar_dir "${PROJECT_NAME}")";
356
+ fi
357
+
358
+ case "${ACTION}" in
359
+ status)
360
+ echo "Voices for ${PROJECT_NAME}:" ;
361
+ echo " browser free, always available (the browser's own voices)" ;
362
+ local count; count="$(find "${piper_dir}" -name '*.onnx' 2>/dev/null | wc -l)";
363
+ echo " piper free, offline: ${count} voice(s) in ${piper_dir}" ;
364
+ if grep -q '^ELEVENLABS_API_KEY=.' "${dir}/.ddev/.env.web" 2>/dev/null; then
365
+ echo " elevenlabs key linked (spends credits per sentence)" ;
366
+ else
367
+ echo " elevenlabs no key linked: bash cmd-tools-avatar-voice.sh ${PROJECT_NAME} -a elevenlabs-link" ;
368
+ fi ;;
369
+ piper-list)
370
+ find "${piper_dir}" -name '*.onnx' 2>/dev/null | sed "s#${piper_dir}/##; s#\.onnx\$##" | sort | sed 's/^/ /' ;
371
+ [[ -d "${piper_dir}" ]] || echo " none yet: bash cmd-tools-avatar-voice.sh -a piper-install --voice en_GB-alba-medium" ;;
372
+ piper-install)
373
+ # en_GB-alba-medium lives at en/en_GB/alba/medium/en_GB-alba-medium.onnx (+ .onnx.json).
374
+ if [[ ! "${VOICE}" =~ ^([a-z]{2,3})_([A-Z]{2})-([a-z0-9_]+)-(x_low|low|medium|high)$ ]]; then
375
+ echo "--voice is a Piper voice name such as en_GB-alba-medium or ar_JO-kareem-medium." >&2 ; return 1 ;
376
+ fi
377
+ local lang="${BASH_REMATCH[1]}" region="${BASH_REMATCH[1]}_${BASH_REMATCH[2]}" speaker="${BASH_REMATCH[3]}" quality="${BASH_REMATCH[4]}";
378
+ local base; base="$(avatar_setting avatar_piper_voices_url)/${lang}/${region}/${speaker}/${quality}/${VOICE}";
379
+ mkdir -p "${piper_dir}" ;
380
+ local f;
381
+ for f in onnx onnx.json; do
382
+ curl -fsSL --proto '=https' -o "${piper_dir}/${VOICE}.${f}.part" "${base}.${f}" \
383
+ && mv "${piper_dir}/${VOICE}.${f}.part" "${piper_dir}/${VOICE}.${f}" \
384
+ || { rm -f "${piper_dir}/${VOICE}.${f}.part" ; echo "Could not download ${VOICE}.${f}: check the name at https://huggingface.co/rhasspy/piper-voices" >&2 ; return 1 ; }
385
+ done
386
+ echo "Installed ${VOICE} into ${piper_dir}. Check its MODEL_CARD on the model page for its licence." ;
387
+ echo "Avatar projects see it after a restart (the folder is mounted read-only)." ;;
388
+ elevenlabs-link)
389
+ ( cd "${dir}" && ./link-elevenlabs.sh ) || return 1 ;
390
+ avatar_restart_app "${dir}" ;;
391
+ elevenlabs-unlink)
392
+ ( cd "${dir}" && ./link-elevenlabs.sh --remove ) || return 1 ;
393
+ avatar_restart_app "${dir}" ;;
394
+ esac
395
+ }
396
+
397
+ # --- Catalog ----------------------------------------------------------------------------------------
398
+
399
+ # What can give an avatar a body or a voice, with the licence and whether the avatar app speaks it
400
+ # today. Licences are as their own projects state them (checked October 2026); a model or voice
401
+ # inside a collection can carry its own terms.
402
+ function avatar_catalog() {
403
+ case "${ACTION}" in
404
+ voices)
405
+ cat <<'TXT'
406
+ Voices Licence In the avatar app
407
+ Browser (Web Speech) the browser's yes: engine "browser", free
408
+ Piper voices MIT model card; per voice yes: engine "piper", free, offline (-a piper-install)
409
+ (code: rhasspy/piper MIT, archived; OHF-Voice/piper1-gpl GPL-3.0)
410
+ ElevenLabs paid service, per credits yes: engine "elevenlabs" (-a elevenlabs-link)
411
+ Kokoro-82M Apache-2.0 not yet: free, runs locally (kokoro-js); no Arabic
412
+ Chatterbox (Resemble) MIT not yet: free, local, needs a GPU to be quick
413
+ MeloTTS (MyShell) MIT not yet: free, local, CPU-friendly
414
+ Coqui XTTS-v2 CPML, non-commercial only avoid for anything shared or commercial
415
+ TXT
416
+ ;;
417
+ avatars)
418
+ cat <<'TXT'
419
+ Avatar libraries Licence How to use one
420
+ Open Source Avatars per collection: mostly CC0, --model osa:<name> (licence and credit saved with it)
421
+ (opensourceavatars.com) VIPE Heroes CC-BY
422
+ VRoid Hub set by each creator download what the creator allows, then --model-file
423
+ VRoid Studio your own model make one, export VRM, then --model-file
424
+ Ready Player Me service ended 31 January 2026 existing GLB exports still load; no new ones
425
+ TXT
426
+ if [[ "${LIST}" == "yes" ]]; then
427
+ echo "" ; echo "Open Source Avatars registry (public VRMs):" ;
428
+ OSA_URL="$(avatar_setting avatar_osa_index_url)" python3 - <<'PY'
429
+ import json, os, urllib.request
430
+ base = os.environ['OSA_URL']
431
+ get = lambda name: json.load(urllib.request.urlopen(f'{base}/{name}', timeout=30))
432
+ for p in get('projects.json'):
433
+ if not p.get('is_public') or not p.get('avatar_data_file'):
434
+ continue
435
+ for a in get(p['avatar_data_file']):
436
+ if a.get('format') == 'VRM' and a.get('is_public'):
437
+ print(f" osa:{a['name']:<28} {p.get('license', '?'):<6} {p.get('name', '')}")
438
+ PY
439
+ fi ;;
440
+ esac
441
+ }
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # One backup implementation for every workspace, because what an "item" is
4
+ # differs by workspace and that difference used to be silently wrong:
5
+ #
6
+ # projects, demos, dev, test, sandboxes,
7
+ # recipes, modules, components, products an item is a DIRECTORY
8
+ # skills an item is a DIRECTORY (<name>/SKILL.md)
9
+ # agents, prompts, docs, worklogs an item is a FILE (<name>.md)
10
+ #
11
+ # Every backup script used to archive `${PROJECT_NAME}` as if it were always a
12
+ # directory. On the file workspaces tar therefore failed with "Cannot stat" —
13
+ # and still left a ~45 byte archive behind, so `backups/agents/` filled up with
14
+ # plausibly-named files that contained nothing. A backup that looks real and is
15
+ # empty is worse than no backup at all, so: resolve the name first, and never
16
+ # keep an archive that tar did not actually write.
17
+
18
+ # Resolve what an item name points at, relative to the current workspace folder.
19
+ # Echoes the path, or returns 1 when the name matches nothing.
20
+ function resolve_workspace_item() {
21
+ local name="$1";
22
+ if [ -e "${name}" ]; then echo "${name}"; return 0 ; fi
23
+ if [ -e "${name}.md" ]; then echo "${name}.md"; return 0 ; fi
24
+ return 1 ;
25
+ }
26
+
27
+ # Archive one workspace item into backups/<workspace>/.
28
+ # Sets BACKUP_TIME and BACKUP_ARCHIVE for callers that need to name a sibling
29
+ # file (the project workspaces write a database dump next to the tarball).
30
+ function backup_workspace_item() {
31
+ local name="$1";
32
+ local target;
33
+
34
+ if ! target=$(resolve_workspace_item "${name}") ; then
35
+ echo "Nothing to back up: no '${name}' in $(pwd)." ;
36
+ return 1 ;
37
+ fi
38
+
39
+ BACKUP_TIME=$( date '+%Y-%m-%d_%H-%M-%S' );
40
+ BACKUP_ARCHIVE="${backups}/${doc_name}/${doc_name}---${name}--${BACKUP_TIME}.tar.gz";
41
+ mkdir -p "${backups}/${doc_name}" ;
42
+
43
+ if ! tar -cvzf "${BACKUP_ARCHIVE}" "${target}" ; then
44
+ rm -f "${BACKUP_ARCHIVE}" ;
45
+ echo "Backup failed for '${target}' — removed the incomplete archive." ;
46
+ return 1 ;
47
+ fi
48
+
49
+ echo "Backed up ${target} to ${BACKUP_ARCHIVE}." ;
50
+ }