@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.
- package/LICENSE +339 -0
- package/README.md +28 -364
- package/core/bin/workspace.js +135 -0
- package/core/config/settings.labels.yml +514 -0
- package/core/config/settings.template.yml +292 -0
- package/core/config/style.yml +53 -0
- package/core/config/theme.default.yml +161 -0
- package/core/config/theme.dispatch.yml +166 -0
- package/core/config/theme.drupal.yml +175 -0
- package/core/config/theme.ember.yml +160 -0
- package/core/config/theme.github.yml +172 -0
- package/core/config/theme.gitlab.yml +168 -0
- package/core/config/theme.press.yml +161 -0
- package/core/config/theme.slate.yml +160 -0
- package/core/config/theme.upsun.yml +174 -0
- package/core/docs/architecture.svg +65 -0
- package/core/docs/getting-started.md +51 -0
- package/core/docs/plugins.md +27 -0
- package/core/docs/releases.md +23 -0
- package/core/docs/testing.md +15 -0
- package/core/docs/workspaces.md +25 -0
- package/core/scripts/args/arg-ai-items.sh +65 -0
- package/core/scripts/args/arg-autostart.sh +31 -0
- package/core/scripts/args/arg-avatar-agent.sh +28 -0
- package/core/scripts/args/arg-avatar-catalog.sh +12 -0
- package/core/scripts/args/arg-avatar-character.sh +68 -0
- package/core/scripts/args/arg-avatar-voice.sh +24 -0
- package/core/scripts/args/arg-avatar.sh +22 -0
- package/core/scripts/args/arg-checks.sh +36 -0
- package/core/scripts/args/arg-clone.sh +42 -0
- package/core/scripts/args/arg-commands.sh +51 -0
- package/core/scripts/args/arg-cucumber.sh +34 -0
- package/core/scripts/args/arg-distribution.sh +30 -0
- package/core/scripts/args/arg-drupal.sh +39 -0
- package/core/scripts/args/arg-drupal_cms.sh +18 -0
- package/core/scripts/args/arg-gitlab-ci-local.sh +25 -0
- package/core/scripts/args/arg-graphify.sh +36 -0
- package/core/scripts/args/arg-graphs.sh +12 -0
- package/core/scripts/args/arg-hostnames.sh +23 -0
- package/core/scripts/args/arg-milvus-backup.sh +8 -0
- package/core/scripts/args/arg-milvus-mcp.sh +12 -0
- package/core/scripts/args/arg-milvus.sh +32 -0
- package/core/scripts/args/arg-obsidian.sh +17 -0
- package/core/scripts/args/arg-odoo.sh +18 -0
- package/core/scripts/args/arg-penpot-backup.sh +8 -0
- package/core/scripts/args/arg-penpot-mcp.sh +15 -0
- package/core/scripts/args/arg-penpot-token.sh +17 -0
- package/core/scripts/args/arg-penpot.sh +44 -0
- package/core/scripts/args/arg-rag.sh +21 -0
- package/core/scripts/args/arg-ragify.sh +35 -0
- package/core/scripts/args/arg-reclaim.sh +18 -0
- package/core/scripts/args/arg-release.sh +21 -0
- package/core/scripts/args/arg-screen.sh +28 -0
- package/core/scripts/args/arg-site-template.sh +13 -0
- package/core/scripts/args/arg-spdd.sh +16 -0
- package/core/scripts/args/arg-specs.sh +22 -0
- package/core/scripts/args/arg-storage.sh +36 -0
- package/core/scripts/args/arg-testing.sh +36 -0
- package/core/scripts/args/arg-webship.sh +34 -0
- package/core/scripts/args/arg-webships-project.sh +22 -0
- package/core/scripts/args/arg-webships-site-template.sh +17 -0
- package/core/scripts/args/arg-webships.sh +34 -0
- package/core/scripts/args/arg-website-site-template.sh +17 -0
- package/core/scripts/args/arg-website.sh +25 -0
- package/core/scripts/args/arg-wordpress.sh +18 -0
- package/core/scripts/autostart-run.sh +162 -0
- package/core/scripts/autostart-stop.sh +30 -0
- package/core/scripts/autostart-watch.sh +43 -0
- package/core/scripts/autostart.sh +26 -0
- package/core/scripts/bootstrap-functions.sh +117 -0
- package/core/scripts/bootstrap-libraries.sh +10 -0
- package/core/scripts/bootstrap.sh +71 -0
- package/core/scripts/ddev-shim/ddev +122 -0
- package/core/scripts/docker-gid.sh +119 -0
- package/core/scripts/functions/arg-site-template.sh +28 -0
- package/core/scripts/functions/fun-ai-items-lock.sh +175 -0
- package/core/scripts/functions/fun-ai-items-sources.sh +298 -0
- package/core/scripts/functions/fun-ai-items.sh +621 -0
- package/core/scripts/functions/fun-ai-providers.sh +72 -0
- package/core/scripts/functions/fun-autostart.sh +429 -0
- package/core/scripts/functions/fun-avatar.sh +441 -0
- package/core/scripts/functions/fun-backup-item.sh +50 -0
- package/core/scripts/functions/fun-build-distribution.sh +226 -0
- package/core/scripts/functions/fun-build-site-template.sh +104 -0
- package/core/scripts/functions/fun-build-webships.sh +161 -0
- package/core/scripts/functions/fun-build-website.sh +199 -0
- package/core/scripts/functions/fun-checks.sh +243 -0
- package/core/scripts/functions/fun-clone-project.sh +289 -0
- package/core/scripts/functions/fun-commands.sh +521 -0
- package/core/scripts/functions/fun-database.sh +63 -0
- package/core/scripts/functions/fun-ddev-hostnames.sh +213 -0
- package/core/scripts/functions/fun-ddev-nodejs.sh +15 -0
- package/core/scripts/functions/fun-ddev-telemetry.sh +15 -0
- package/core/scripts/functions/fun-default-settings.sh +28 -0
- package/core/scripts/functions/fun-distribution-cucumber.sh +45 -0
- package/core/scripts/functions/fun-distribution-drupal.sh +25 -0
- package/core/scripts/functions/fun-distribution-drupal_cms.sh +35 -0
- package/core/scripts/functions/fun-distribution-webship.sh +28 -0
- package/core/scripts/functions/fun-distribution-webships.sh +33 -0
- package/core/scripts/functions/fun-distribution-website.sh +19 -0
- package/core/scripts/functions/fun-drush.sh +48 -0
- package/core/scripts/functions/fun-elevenlabs.sh +179 -0
- package/core/scripts/functions/fun-files.sh +19 -0
- package/core/scripts/functions/fun-git-worktrees.sh +142 -0
- package/core/scripts/functions/fun-gitlab-ci.sh +156 -0
- package/core/scripts/functions/fun-hostnames-cli.sh +88 -0
- package/core/scripts/functions/fun-milvus.sh +584 -0
- package/core/scripts/functions/fun-odoo.sh +121 -0
- package/core/scripts/functions/fun-penpot.sh +724 -0
- package/core/scripts/functions/fun-project-name.sh +20 -0
- package/core/scripts/functions/fun-rag.sh +253 -0
- package/core/scripts/functions/fun-ragify.sh +165 -0
- package/core/scripts/functions/fun-reclaim.sh +297 -0
- package/core/scripts/functions/fun-release.sh +159 -0
- package/core/scripts/functions/fun-remove-project.sh +319 -0
- package/core/scripts/functions/fun-screen.sh +96 -0
- package/core/scripts/functions/fun-spdd.sh +676 -0
- package/core/scripts/functions/fun-specs-share.sh +237 -0
- package/core/scripts/functions/fun-storage.sh +347 -0
- package/core/scripts/functions/fun-testing.sh +329 -0
- package/core/scripts/functions/fun-users.sh +87 -0
- package/core/scripts/functions/fun-version.sh +72 -0
- package/core/scripts/functions/fun-video-edit.sh +48 -0
- package/core/scripts/functions/fun-voice.sh +45 -0
- package/core/scripts/functions/fun-wordpress.sh +59 -0
- package/core/scripts/host-mounts.sh +161 -0
- package/core/scripts/install.sh +602 -0
- package/core/scripts/libs/__pycache__/video_edit.cpython-312.pyc +0 -0
- package/core/scripts/libs/argparse.sh +93 -0
- package/core/scripts/libs/bash-yaml.sh +52 -0
- package/core/scripts/libs/checks_plan.js +312 -0
- package/core/scripts/libs/elevenlabs.py +627 -0
- package/core/scripts/libs/progress-bar.sh +19 -0
- package/core/scripts/libs/rag_index.py +446 -0
- package/core/scripts/libs/video_edit.py +636 -0
- package/core/scripts/libs/voice.py +430 -0
- package/core/scripts/plugins/jira/host-install.sh +119 -0
- package/core/scripts/plugins/jira/host-mounts.txt +2 -0
- package/core/scripts/plugins/upsun/args/arg-upsun.sh +51 -0
- package/core/scripts/plugins/upsun/functions/fun-upsun.sh +304 -0
- package/core/scripts/plugins/upsun/host-install.sh +99 -0
- package/core/scripts/plugins/upsun/host-mounts.txt +1 -0
- package/core/scripts/plugins/upsun/upsun-ai.sh +133 -0
- package/core/scripts/plugins.sh +152 -0
- package/core/scripts/release.sh +69 -0
- package/core/scripts/storage.sh +39 -0
- package/core/scripts/sync-tooling.sh +246 -0
- package/core/scripts/tests/cmd-smoke-test.sh +109 -0
- package/core/scripts/trust-https.sh +257 -0
- package/core/workspace-app/.ddev/commands/web/test-dashboard +49 -0
- package/core/workspace-app/.ddev/config.yaml +400 -0
- package/core/workspace-app/.ddev/docker-compose.dood.yaml +45 -0
- package/core/workspace-app/.ddev/docker-compose.plugin-jira-twg.yaml +26 -0
- package/core/workspace-app/.ddev/docker-compose.plugin-upsun-upsun-cli.yaml +8 -0
- package/core/workspace-app/.ddev/docker-compose.screens.yaml +15 -0
- package/core/workspace-app/.ddev/nginx_full/nginx-site.conf +114 -0
- package/core/workspace-app/.ddev/web-build/Dockerfile.workspace-app +203 -0
- package/core/workspace-app/.ddev/web-build/ddev-shim-ddev +122 -0
- package/core/workspace-app/README.md +380 -0
- package/{actions → core/workspace-app/actions}/ddev.js +0 -1
- package/{actions → core/workspace-app/actions}/rag.js +0 -1
- package/{actions → core/workspace-app/actions}/testing.js +0 -1
- package/{assistant.js → core/workspace-app/assistant.js} +1 -10
- package/{git-info.js → core/workspace-app/git-info.js} +17 -1
- package/core/workspace-app/package.json +29 -0
- package/core/workspace-app/plugin-catalog.js +50 -0
- package/{plugins-page.js → core/workspace-app/plugins-page.js} +28 -2
- package/{server.js → core/workspace-app/server.js} +18 -0
- package/core/workspace-app/tests/features/actions-rail.feature +44 -0
- package/core/workspace-app/tests/features/ai-items.feature +23 -0
- package/core/workspace-app/tests/features/assistant-speech.feature +63 -0
- package/core/workspace-app/tests/features/checks.feature +39 -0
- package/core/workspace-app/tests/features/clone-project.feature +30 -0
- package/core/workspace-app/tests/features/command-authoring.feature +58 -0
- package/core/workspace-app/tests/features/dashboard.feature +57 -0
- package/core/workspace-app/tests/features/menus.feature +29 -0
- package/core/workspace-app/tests/features/plugins/jira/jira.feature +47 -0
- package/core/workspace-app/tests/features/plugins.feature +20 -0
- package/core/workspace-app/tests/features/project-actions.feature +40 -0
- package/core/workspace-app/tests/features/screens.feature +29 -0
- package/core/workspace-app/tests/features/settings.feature +46 -0
- package/core/workspace-app/tests/features/test-reports.feature +32 -0
- package/core/workspace-app/tests/features/theme.feature +40 -0
- package/core/workspace-app/tests/step-definitions/actions-post.steps.js +25 -0
- package/core/workspace-app/tests/step-definitions/assistant-speech.steps.js +152 -0
- package/core/workspace-app/tests/step-definitions/preconditions.steps.js +100 -0
- package/core/workspace-app/tests/unit/_isolated-config.js +31 -0
- package/core/workspace-app/tests/unit/accessibility.test.js +124 -0
- package/core/workspace-app/tests/unit/actions-rail-ux.test.js +56 -0
- package/core/workspace-app/tests/unit/actions-rail.test.js +51 -0
- package/core/workspace-app/tests/unit/ai-inventory.test.js +64 -0
- package/core/workspace-app/tests/unit/app-docs.test.js +64 -0
- package/core/workspace-app/tests/unit/assistant-avatar.test.js +110 -0
- package/core/workspace-app/tests/unit/assistant-cast.test.js +105 -0
- package/core/workspace-app/tests/unit/assistant-send-animation.test.js +15 -0
- package/core/workspace-app/tests/unit/assistant-suggestions.test.js +112 -0
- package/core/workspace-app/tests/unit/assistant-switches.test.js +53 -0
- package/core/workspace-app/tests/unit/assistant-views.test.js +146 -0
- package/core/workspace-app/tests/unit/assistant-working-indicator.test.js +49 -0
- package/core/workspace-app/tests/unit/assistant.test.js +61 -0
- package/core/workspace-app/tests/unit/audio-player.test.js +147 -0
- package/core/workspace-app/tests/unit/audio-voice.test.js +634 -0
- package/core/workspace-app/tests/unit/auth-google.test.js +180 -0
- package/core/workspace-app/tests/unit/autostart-watch.test.js +76 -0
- package/core/workspace-app/tests/unit/browsers.test.js +76 -0
- package/core/workspace-app/tests/unit/build-distribution.test.js +125 -0
- package/core/workspace-app/tests/unit/build-order.test.js +153 -0
- package/core/workspace-app/tests/unit/builder-args.test.js +113 -0
- package/core/workspace-app/tests/unit/builders.test.js +158 -0
- package/core/workspace-app/tests/unit/card-state-toggle.test.js +29 -0
- package/core/workspace-app/tests/unit/changelog.test.js +177 -0
- package/core/workspace-app/tests/unit/chat-thread.test.js +92 -0
- package/core/workspace-app/tests/unit/checks-plan.test.js +205 -0
- package/core/workspace-app/tests/unit/claude-args.test.js +182 -0
- package/core/workspace-app/tests/unit/claude-code-here.test.js +15 -0
- package/core/workspace-app/tests/unit/claude-resume.test.js +147 -0
- package/core/workspace-app/tests/unit/claude-screen-options.test.js +84 -0
- package/core/workspace-app/tests/unit/claude-session.test.js +41 -0
- package/core/workspace-app/tests/unit/command-flags.test.js +45 -0
- package/core/workspace-app/tests/unit/command-palette.test.js +105 -0
- package/core/workspace-app/tests/unit/commands-center.test.js +338 -0
- package/core/workspace-app/tests/unit/composer-menu.test.js +187 -0
- package/core/workspace-app/tests/unit/config-yaml.test.js +116 -0
- package/core/workspace-app/tests/unit/confirm-dialog.test.js +69 -0
- package/core/workspace-app/tests/unit/create-card.test.js +85 -0
- package/core/workspace-app/tests/unit/ddev-addons.test.js +144 -0
- package/core/workspace-app/tests/unit/ddev-auth-ssh.test.js +40 -0
- package/core/workspace-app/tests/unit/ddev-custom-commands.test.js +56 -0
- package/core/workspace-app/tests/unit/ddev-diagnose.test.js +57 -0
- package/core/workspace-app/tests/unit/ddev-domains.test.js +153 -0
- package/core/workspace-app/tests/unit/ddev-hostnames.test.js +143 -0
- package/core/workspace-app/tests/unit/ddev-import.test.js +82 -0
- package/core/workspace-app/tests/unit/ddev-mail.test.js +135 -0
- package/core/workspace-app/tests/unit/ddev-menu-and-create.test.js +28 -0
- package/core/workspace-app/tests/unit/ddev-mutagen.test.js +37 -0
- package/core/workspace-app/tests/unit/ddev-options.test.js +51 -0
- package/core/workspace-app/tests/unit/ddev-share.test.js +40 -0
- package/core/workspace-app/tests/unit/ddev-shim.test.js +57 -0
- package/core/workspace-app/tests/unit/ddev-snapshots.test.js +142 -0
- package/core/workspace-app/tests/unit/ddev-start-daemons.test.js +62 -0
- package/core/workspace-app/tests/unit/ddev-xdebug.test.js +41 -0
- package/core/workspace-app/tests/unit/deep-chat-origin.test.js +38 -0
- package/core/workspace-app/tests/unit/density.test.js +52 -0
- package/core/workspace-app/tests/unit/elevenlabs.test.js +453 -0
- package/core/workspace-app/tests/unit/event-log.test.js +102 -0
- package/core/workspace-app/tests/unit/favicon.test.js +68 -0
- package/core/workspace-app/tests/unit/files-browser.test.js +224 -0
- package/core/workspace-app/tests/unit/git-info.test.js +26 -0
- package/core/workspace-app/tests/unit/grid-and-list.test.js +103 -0
- package/core/workspace-app/tests/unit/host-tool-wrapper.test.js +18 -0
- package/core/workspace-app/tests/unit/html-patterns.test.js +51 -0
- package/core/workspace-app/tests/unit/ide-infra.test.js +28 -0
- package/core/workspace-app/tests/unit/images-ai.test.js +201 -0
- package/core/workspace-app/tests/unit/images-create.test.js +59 -0
- package/core/workspace-app/tests/unit/images-providers.test.js +248 -0
- package/core/workspace-app/tests/unit/images-svg.test.js +213 -0
- package/core/workspace-app/tests/unit/images-workspace.test.js +144 -0
- package/core/workspace-app/tests/unit/jobs-fragment.test.js +66 -0
- package/core/workspace-app/tests/unit/media-ux.test.js +164 -0
- package/core/workspace-app/tests/unit/modal-fit.test.js +87 -0
- package/core/workspace-app/tests/unit/modules-load.test.js +23 -0
- package/core/workspace-app/tests/unit/narration.test.js +186 -0
- package/core/workspace-app/tests/unit/navigation-editor.test.js +260 -0
- package/core/workspace-app/tests/unit/navigation.test.js +254 -0
- package/core/workspace-app/tests/unit/new-folder.test.js +121 -0
- package/core/workspace-app/tests/unit/new-screen-form.test.js +149 -0
- package/core/workspace-app/tests/unit/node-menu.test.js +161 -0
- package/core/workspace-app/tests/unit/notes.test.js +128 -0
- package/core/workspace-app/tests/unit/page-structure.test.js +40 -0
- package/core/workspace-app/tests/unit/page-width.test.js +59 -0
- package/core/workspace-app/tests/unit/php-version.test.js +90 -0
- package/core/workspace-app/tests/unit/plan-card.test.js +44 -0
- package/core/workspace-app/tests/unit/plugin-catalog.test.js +31 -0
- package/core/workspace-app/tests/unit/plugin-system.test.js +251 -0
- package/core/workspace-app/tests/unit/plugins-page.test.js +28 -0
- package/core/workspace-app/tests/unit/plugins.test.js +58 -0
- package/core/workspace-app/tests/unit/project-activity-filter.test.js +180 -0
- package/core/workspace-app/tests/unit/project-make.test.js +143 -0
- package/core/workspace-app/tests/unit/project-name.test.js +202 -0
- package/core/workspace-app/tests/unit/reader.test.js +62 -0
- package/core/workspace-app/tests/unit/release.test.js +92 -0
- package/core/workspace-app/tests/unit/remove-confirm.test.js +37 -0
- package/core/workspace-app/tests/unit/report-pdf.test.js +171 -0
- package/core/workspace-app/tests/unit/round-11.test.js +31 -0
- package/core/workspace-app/tests/unit/round-12.test.js +37 -0
- package/core/workspace-app/tests/unit/row-layout.test.js +585 -0
- package/core/workspace-app/tests/unit/row-menus-fold.test.js +29 -0
- package/core/workspace-app/tests/unit/rows-add-modal.test.js +68 -0
- package/core/workspace-app/tests/unit/screen-runner-queue.test.js +41 -0
- package/core/workspace-app/tests/unit/screen-window.test.js +116 -0
- package/core/workspace-app/tests/unit/screens-beside-running.test.js +19 -0
- package/core/workspace-app/tests/unit/screens-columns.test.js +79 -0
- package/core/workspace-app/tests/unit/screens-menu.test.js +84 -0
- package/core/workspace-app/tests/unit/screens-modal-overlay.test.js +14 -0
- package/core/workspace-app/tests/unit/screens-waiting.test.js +129 -0
- package/core/workspace-app/tests/unit/screens.test.js +74 -0
- package/core/workspace-app/tests/unit/second-storage.test.js +218 -0
- package/core/workspace-app/tests/unit/session-name.test.js +64 -0
- package/core/workspace-app/tests/unit/settings-file.test.js +173 -0
- package/core/workspace-app/tests/unit/settings-nested-list.test.js +54 -0
- package/core/workspace-app/tests/unit/settings-raw.test.js +177 -0
- package/core/workspace-app/tests/unit/shared-prefs.test.js +49 -0
- package/core/workspace-app/tests/unit/speech.test.js +290 -0
- package/core/workspace-app/tests/unit/static-caching.test.js +39 -0
- package/core/workspace-app/tests/unit/status-language.test.js +47 -0
- package/core/workspace-app/tests/unit/tab-modal.test.js +69 -0
- package/core/workspace-app/tests/unit/tab-title.test.js +37 -0
- package/core/workspace-app/tests/unit/template-literals.test.js +52 -0
- package/core/workspace-app/tests/unit/terminal-scrollback.test.js +61 -0
- package/core/workspace-app/tests/unit/terminal-size.test.js +103 -0
- package/core/workspace-app/tests/unit/terminal-style.test.js +84 -0
- package/core/workspace-app/tests/unit/terminal-windows.test.js +154 -0
- package/core/workspace-app/tests/unit/themes.test.js +453 -0
- package/core/workspace-app/tests/unit/tool-labels.test.js +34 -0
- package/core/workspace-app/tests/unit/topbar-icons.test.js +47 -0
- package/core/workspace-app/tests/unit/update-docker-gid.test.js +51 -0
- package/core/workspace-app/tests/unit/user-guide.test.js +60 -0
- package/core/workspace-app/tests/unit/version-check.test.js +98 -0
- package/core/workspace-app/tests/unit/version-link.test.js +50 -0
- package/core/workspace-app/tests/unit/video-borrow.test.js +198 -0
- package/core/workspace-app/tests/unit/video-edit-ask.test.js +93 -0
- package/core/workspace-app/tests/unit/video-edit-short.test.js +42 -0
- package/core/workspace-app/tests/unit/video-edit.test.js +417 -0
- package/core/workspace-app/tests/unit/video-transcript.test.js +237 -0
- package/core/workspace-app/tests/unit/waiting.test.js +48 -0
- package/core/workspace-app/tests/unit/wordpress-odoo-builders.test.js +38 -0
- package/core/workspace-app/tests/unit/workspace-bin.test.js +48 -0
- package/core/workspace-app/tests/unit/workspace-card-tools.test.js +30 -0
- package/core/workspace-app/tests/unit/workspace-delete.test.js +77 -0
- package/core/workspace-app/tests/unit/workspace-types.test.js +68 -0
- package/core/workspace-app/tests/unit/worktree-clone.test.js +250 -0
- package/package.json +38 -36
- /package/{PLUGINS.md → core/workspace-app/PLUGINS.md} +0 -0
- /package/{WORKSPACES.md → core/workspace-app/WORKSPACES.md} +0 -0
- /package/{actions → core/workspace-app/actions}/ai-items.js +0 -0
- /package/{actions → core/workspace-app/actions}/audio.js +0 -0
- /package/{actions → core/workspace-app/actions}/build-order.js +0 -0
- /package/{actions → core/workspace-app/actions}/checks.js +0 -0
- /package/{actions → core/workspace-app/actions}/claude-session.js +0 -0
- /package/{actions → core/workspace-app/actions}/commands-center.js +0 -0
- /package/{actions → core/workspace-app/actions}/composer.js +0 -0
- /package/{actions → core/workspace-app/actions}/ddev-addons.js +0 -0
- /package/{actions → core/workspace-app/actions}/ddev-mail.js +0 -0
- /package/{actions → core/workspace-app/actions}/folders.js +0 -0
- /package/{actions → core/workspace-app/actions}/images-svg.js +0 -0
- /package/{actions → core/workspace-app/actions}/images.js +0 -0
- /package/{actions → core/workspace-app/actions}/navigation.js +0 -0
- /package/{actions → core/workspace-app/actions}/node.js +0 -0
- /package/{actions → core/workspace-app/actions}/notes.js +0 -0
- /package/{actions → core/workspace-app/actions}/plugins.js +0 -0
- /package/{actions → core/workspace-app/actions}/project-make.js +0 -0
- /package/{actions → core/workspace-app/actions}/row-actions.js +0 -0
- /package/{actions → core/workspace-app/actions}/screens.js +0 -0
- /package/{actions → core/workspace-app/actions}/video-edit.js +0 -0
- /package/{ai-inventory.js → core/workspace-app/ai-inventory.js} +0 -0
- /package/{ai-items.js → core/workspace-app/ai-items.js} +0 -0
- /package/{assistant-cast.js → core/workspace-app/assistant-cast.js} +0 -0
- /package/{assistant-suggestions.js → core/workspace-app/assistant-suggestions.js} +0 -0
- /package/{audio-voice.js → core/workspace-app/audio-voice.js} +0 -0
- /package/{auth-google.js → core/workspace-app/auth-google.js} +0 -0
- /package/{build-ai.js → core/workspace-app/build-ai.js} +0 -0
- /package/{build-order-page.js → core/workspace-app/build-order-page.js} +0 -0
- /package/{build-order.js → core/workspace-app/build-order.js} +0 -0
- /package/{builder-args.js → core/workspace-app/builder-args.js} +0 -0
- /package/{changelog.js → core/workspace-app/changelog.js} +0 -0
- /package/{chat-threads.js → core/workspace-app/chat-threads.js} +0 -0
- /package/{checks.js → core/workspace-app/checks.js} +0 -0
- /package/{claude-args.js → core/workspace-app/claude-args.js} +0 -0
- /package/{claude-sessions.js → core/workspace-app/claude-sessions.js} +0 -0
- /package/{command-author.js → core/workspace-app/command-author.js} +0 -0
- /package/{command-block.js → core/workspace-app/command-block.js} +0 -0
- /package/{commands → core/workspace-app/commands}/defaults.yml +0 -0
- /package/{commands-page.js → core/workspace-app/commands-page.js} +0 -0
- /package/{commands.js → core/workspace-app/commands.js} +0 -0
- /package/{cucumber.js → core/workspace-app/cucumber.js} +0 -0
- /package/{ddev-addons-page.js → core/workspace-app/ddev-addons-page.js} +0 -0
- /package/{ddev-addons.js → core/workspace-app/ddev-addons.js} +0 -0
- /package/{ddev-custom-commands.js → core/workspace-app/ddev-custom-commands.js} +0 -0
- /package/{ddev-domains.js → core/workspace-app/ddev-domains.js} +0 -0
- /package/{ddev-import.js → core/workspace-app/ddev-import.js} +0 -0
- /package/{ddev-mail-page.js → core/workspace-app/ddev-mail-page.js} +0 -0
- /package/{ddev-mail.js → core/workspace-app/ddev-mail.js} +0 -0
- /package/{ddev-options.js → core/workspace-app/ddev-options.js} +0 -0
- /package/{ddev-snapshots.js → core/workspace-app/ddev-snapshots.js} +0 -0
- /package/{ddev.js → core/workspace-app/ddev.js} +0 -0
- /package/{docs → core/workspace-app/docs}/DEVELOPER-GUIDE.md +0 -0
- /package/{docs → core/workspace-app/docs}/README.md +0 -0
- /package/{docs → core/workspace-app/docs}/REFERENCE.md +0 -0
- /package/{docs → core/workspace-app/docs}/USER-GUIDE.md +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-board.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-coffee.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-colours.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-icons.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-moves.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-pick-cookieman.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-settings-voices.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/assistant/avatar-status.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/create-card/create-card.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/create-card/start-ai.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-clone-address.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-clone-worktree-off.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-clone-worktree-on.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-ddev-menu.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-domains.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-home.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-ide-menu.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-remove-refusal.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-rows-worktree.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-screens.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-settings.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/guide-workspace-page.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/home/card-settings.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/home/drag-reorder.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/home/edit-card.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/images/claude-code-image.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/images/edit-with-ai.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/images/gallery.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/images/generate-description.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/images/generate-plan.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/images/providers.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/images/svg-form.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/images/svg-result.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/images/upload.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/new-folder/2-form.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/new-folder/8-ddev-options.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/new-folder/files-folder.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/projects/ddev-custom-commands.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/projects/state-chip-stop.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/dashboard-dark.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/dashboard-light.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/dev-dark.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/dev-light.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/docs-dark.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/docs-light.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/ai.svg +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/code.svg +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/docs.svg +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/services.svg +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/icons/sites.svg +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/test-report-dark.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/test-report-light.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/test-scenarios.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/test-steps.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/videos-dark.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/readme/videos-light.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/screens-menu.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/screens-new.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/settings/auth-google-lists.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-1-row.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-2-confirm.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-3-type-name.png +0 -0
- /package/{docs → core/workspace-app/docs}/screenshots/settings/delete-4-type-yes.png +0 -0
- /package/{event-log.js → core/workspace-app/event-log.js} +0 -0
- /package/{files-browser.js → core/workspace-app/files-browser.js} +0 -0
- /package/{folders.js → core/workspace-app/folders.js} +0 -0
- /package/{format.js → core/workspace-app/format.js} +0 -0
- /package/{github-auth.js → core/workspace-app/github-auth.js} +0 -0
- /package/{html.js → core/workspace-app/html.js} +0 -0
- /package/{icons.js → core/workspace-app/icons.js} +0 -0
- /package/{images-ai.js → core/workspace-app/images-ai.js} +0 -0
- /package/{images-create.js → core/workspace-app/images-create.js} +0 -0
- /package/{images-page.js → core/workspace-app/images-page.js} +0 -0
- /package/{images-records.js → core/workspace-app/images-records.js} +0 -0
- /package/{images-render.js → core/workspace-app/images-render.js} +0 -0
- /package/{images-svg-core.js → core/workspace-app/images-svg-core.js} +0 -0
- /package/{images-svg-sanitize.js → core/workspace-app/images-svg-sanitize.js} +0 -0
- /package/{images-svg.js → core/workspace-app/images-svg.js} +0 -0
- /package/{images.js → core/workspace-app/images.js} +0 -0
- /package/{jobs.js → core/workspace-app/jobs.js} +0 -0
- /package/{linger.js → core/workspace-app/linger.js} +0 -0
- /package/{lists.js → core/workspace-app/lists.js} +0 -0
- /package/{media-info.js → core/workspace-app/media-info.js} +0 -0
- /package/{navigation-page.js → core/workspace-app/navigation-page.js} +0 -0
- /package/{navigation.js → core/workspace-app/navigation.js} +0 -0
- /package/{notes.js → core/workspace-app/notes.js} +0 -0
- /package/{palette-index.js → core/workspace-app/palette-index.js} +0 -0
- /package/{playwright.config.js → core/workspace-app/playwright.config.js} +0 -0
- /package/{plugin-install.js → core/workspace-app/plugin-install.js} +0 -0
- /package/{plugin-loader.js → core/workspace-app/plugin-loader.js} +0 -0
- /package/{plugin-manifest.js → core/workspace-app/plugin-manifest.js} +0 -0
- /package/{plugin-settings.js → core/workspace-app/plugin-settings.js} +0 -0
- /package/{plugins → core/workspace-app/plugins}/workspace-notes/index.js +0 -0
- /package/{project-make.js → core/workspace-app/project-make.js} +0 -0
- /package/{project-name.js → core/workspace-app/project-name.js} +0 -0
- /package/{public → core/workspace-app/public}/assistant-avatar-moves.js +0 -0
- /package/{public → core/workspace-app/public}/assistant-avatar-ui.js +0 -0
- /package/{public → core/workspace-app/public}/assistant-avatar.js +0 -0
- /package/{public → core/workspace-app/public}/avatar/druplicon.vrm +0 -0
- /package/{public → core/workspace-app/public}/css/base.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/ai-assistant.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/assistant-avatar.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/assistant-views.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/build-order.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/clone-as-a-git-worktree.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/command-palette.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/commands-center.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/confirm-dialog.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/create-card.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/ddev-menu.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/deep-chat.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/density.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/floating-assistant-workspace-pages.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/folders.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/full-height-left-assistant-sidebar-all-pages.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/full-height-right-actions-rail-pages-that-have-actions.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/grid-and-list.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/help-page.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/hero.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/images.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/layout-rhythm-and-spacing-polish.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/mic-on-any-field-that-wants-typing.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/modal-fit.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/page-width.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/plugins-page.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/project-cards.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/project-rows.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/reordering-the-workspace-cards.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/responsive-home-and-the-workspace-pages.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/running-commands-as-toasts.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/settings-editor-core-config-yml.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/short-results-as-a-toast-at-the-top.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/sound-player.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/suggest-agents-skills-commands.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/tab-modal.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/terminals.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/test-report-media-one-file-per-row-paged.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/top-toolbar-logo-breadcrumb.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/video-edit.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/web-ide-open-with.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/working-indicators.css +0 -0
- /package/{public → core/workspace-app/public}/css/components/workspace-cards.css +0 -0
- /package/{public → core/workspace-app/public}/favicon.ico +0 -0
- /package/{public → core/workspace-app/public}/favicon.png +0 -0
- /package/{public → core/workspace-app/public}/htmx.min.js +0 -0
- /package/{public → core/workspace-app/public}/logo.png +0 -0
- /package/{public → core/workspace-app/public}/media-player.js +0 -0
- /package/{public → core/workspace-app/public}/mic.js +0 -0
- /package/{public → core/workspace-app/public}/narration.js +0 -0
- /package/{public → core/workspace-app/public}/palette.js +0 -0
- /package/{public → core/workspace-app/public}/sortable.js +0 -0
- /package/{public → core/workspace-app/public}/suggest.js +0 -0
- /package/{public → core/workspace-app/public}/terminal.js +0 -0
- /package/{public → core/workspace-app/public}/themes/default/theme.css +0 -0
- /package/{public → core/workspace-app/public}/themes/ember/theme.css +0 -0
- /package/{public → core/workspace-app/public}/themes/press/theme.css +0 -0
- /package/{public → core/workspace-app/public}/themes/slate/theme.css +0 -0
- /package/{public → core/workspace-app/public}/touch-icon.png +0 -0
- /package/{public → core/workspace-app/public}/ui.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/LICENSE.txt +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/ace.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/ext-language_tools.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/ext-searchbox.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/mode-css.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/mode-html.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/mode-javascript.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/mode-markdown.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/mode-sh.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/mode-yaml.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/theme-textmate.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/theme-tomorrow_night.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/ace/worker-yaml.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/deep-chat.LICENSE +0 -0
- /package/{public → core/workspace-app/public}/vendor/deep-chat.bundle.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/dm-serif-text-LICENSE.txt +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/dm-serif-text-latin-400-italic.woff2 +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/dm-serif-text-latin-400-normal.woff2 +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/figtree-LICENSE.txt +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-400-italic.woff2 +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-400-normal.woff2 +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-600-italic.woff2 +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/figtree-latin-600-normal.woff2 +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/jetbrains-mono-LICENSE.txt +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/ubuntu-mono-LICENSE.txt +0 -0
- /package/{public → core/workspace-app/public}/vendor/fonts/ubuntu-mono-latin-wght-normal.woff2 +0 -0
- /package/{public → core/workspace-app/public}/vendor/tabler-LICENSE.txt +0 -0
- /package/{public → core/workspace-app/public}/vendor/tabler-sprite.svg +0 -0
- /package/{public → core/workspace-app/public}/vendor/three/LICENSE +0 -0
- /package/{public → core/workspace-app/public}/vendor/three/addons/loaders/GLTFLoader.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/three/addons/utils/BufferGeometryUtils.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/three/addons/utils/SkeletonUtils.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/three/three.core.min.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/three/three.module.min.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/three-vrm/LICENSE +0 -0
- /package/{public → core/workspace-app/public}/vendor/three-vrm/three-vrm.module.min.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/uikit-icons.min.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/uikit.min.css +0 -0
- /package/{public → core/workspace-app/public}/vendor/uikit.min.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/bookmark-outlined.svg +0 -0
- /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/headset.svg +0 -0
- /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/menu.svg +0 -0
- /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/pause.svg +0 -0
- /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/play.svg +0 -0
- /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/share.svg +0 -0
- /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/sound-off.svg +0 -0
- /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/sound-on.svg +0 -0
- /package/{public → core/workspace-app/public}/vendor/webship-icons/ui/stop.svg +0 -0
- /package/{public → core/workspace-app/public}/vendor/xterm/addon-fit.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/xterm/addon-unicode11.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/xterm/addon-web-links.js +0 -0
- /package/{public → core/workspace-app/public}/vendor/xterm/xterm.css +0 -0
- /package/{public → core/workspace-app/public}/vendor/xterm/xterm.js +0 -0
- /package/{rag.js → core/workspace-app/rag.js} +0 -0
- /package/{reader.js → core/workspace-app/reader.js} +0 -0
- /package/{repo-blobs.js → core/workspace-app/repo-blobs.js} +0 -0
- /package/{report-pdf.js → core/workspace-app/report-pdf.js} +0 -0
- /package/{row-layout.js → core/workspace-app/row-layout.js} +0 -0
- /package/{screenrc → core/workspace-app/screenrc} +0 -0
- /package/{screens.js → core/workspace-app/screens.js} +0 -0
- /package/{scripts → core/workspace-app/scripts}/code-server-start.sh +0 -0
- /package/{scripts → core/workspace-app/scripts}/images-claude-finish.js +0 -0
- /package/{scripts → core/workspace-app/scripts}/screen-host.sh +0 -0
- /package/{scripts → core/workspace-app/scripts}/screen-runner.js +0 -0
- /package/{scripts → core/workspace-app/scripts}/screen-then.js +0 -0
- /package/{scripts → core/workspace-app/scripts}/update.sh +0 -0
- /package/{settings-file.js → core/workspace-app/settings-file.js} +0 -0
- /package/{speech.js → core/workspace-app/speech.js} +0 -0
- /package/{tab-modal.js → core/workspace-app/tab-modal.js} +0 -0
- /package/{test-reports.js → core/workspace-app/test-reports.js} +0 -0
- /package/{themes.js → core/workspace-app/themes.js} +0 -0
- /package/{transcripts.js → core/workspace-app/transcripts.js} +0 -0
- /package/{urls.js → core/workspace-app/urls.js} +0 -0
- /package/{validate.js → core/workspace-app/validate.js} +0 -0
- /package/{version-check.js → core/workspace-app/version-check.js} +0 -0
- /package/{video-edit.js → core/workspace-app/video-edit.js} +0 -0
- /package/{waiting.js → core/workspace-app/waiting.js} +0 -0
- /package/{workspace-card-tools.js → core/workspace-app/workspace-card-tools.js} +0 -0
- /package/{workspace-delete.js → core/workspace-app/workspace-delete.js} +0 -0
- /package/{workspace-types.js → core/workspace-app/workspace-types.js} +0 -0
- /package/{workspaces.js → core/workspace-app/workspaces.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
|
+
}
|