@webship.co/workspace 1.0.0-beta1 → 1.0.0-rc1
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/{PLUGINS.md → core/workspace-app/PLUGINS.md} +9 -1
- 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 +40 -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 +41 -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 +157 -0
- package/core/workspace-app/tests/step-definitions/clone-project.steps.js +47 -0
- package/core/workspace-app/tests/step-definitions/preconditions.steps.js +168 -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 +223 -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 +179 -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/preconditions.test.js +21 -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 +93 -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 +220 -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 +436 -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/{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,297 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Reclaim the disk that removed projects left behind.
|
|
4
|
+
#
|
|
5
|
+
# Deleting a project directory does not delete its Docker footprint. DDEV keeps the database in a
|
|
6
|
+
# named volume, the built web and db images per project, a snapshots volume, and the container — and
|
|
7
|
+
# none of it goes when the folder does. On a machine that builds and throws away sites all day that
|
|
8
|
+
# accumulates into tens of gigabytes of data belonging to projects that no longer exist.
|
|
9
|
+
#
|
|
10
|
+
# THE ONE RULE THIS COMMAND IS BUILT AROUND: if a project's folder is still on disk, nothing
|
|
11
|
+
# belonging to it is touched. Not its database, not its snapshots, not its images — even when the
|
|
12
|
+
# project is stopped, even when the volume is attached to nothing. A stopped project is a project you
|
|
13
|
+
# are coming back to.
|
|
14
|
+
#
|
|
15
|
+
# That rule is why this never uses `docker volume prune` or `docker image prune -a`. Those decide by
|
|
16
|
+
# "is anything using it right now", which on this machine is the wrong question: 23 of the 30
|
|
17
|
+
# unattached volumes here belong to projects whose folders are present, so a prune would delete 23
|
|
18
|
+
# live databases. Every removal below is by explicit name, after the folder check.
|
|
19
|
+
#
|
|
20
|
+
# Two more guards on top of it:
|
|
21
|
+
# * dry run by default — `--apply` is the arming step, because every action here is a deletion;
|
|
22
|
+
# * an age floor (`--keep-days`, default 7) — a project you deleted an hour ago may be one you
|
|
23
|
+
# want back this afternoon.
|
|
24
|
+
#
|
|
25
|
+
# DDEV name normalisation matters and is easy to get wrong: DDEV replaces `_` with `-` in the
|
|
26
|
+
# resources it creates, so the project `v11x00b1figma2drupalai_claude_agent_sdk` owns the volume
|
|
27
|
+
# `v11x00b1figma2drupalai-claude-agent-sdk-mariadb`. Matching the raw directory name alone reports a
|
|
28
|
+
# live project as gone and offers to delete its database. Both spellings go into the protected set.
|
|
29
|
+
|
|
30
|
+
# Every project name that must never be touched, one per line:
|
|
31
|
+
# * every directory anywhere under the workspace tree that carries a .ddev/ — at any depth, since
|
|
32
|
+
# projects live at <workspace>/<project> and sometimes deeper;
|
|
33
|
+
# * both the raw name and the DDEV-normalised one;
|
|
34
|
+
# * every name DDEV still has in its own registry, whatever its status.
|
|
35
|
+
function reclaim_protected_names() {
|
|
36
|
+
{
|
|
37
|
+
find "${WORKSPACE_ROOT}" -mindepth 2 -maxdepth 5 -name '.ddev' -type d -prune 2>/dev/null \
|
|
38
|
+
| sed 's|/\.ddev$||' \
|
|
39
|
+
| while read -r p ; do b="$(basename "$p")" ; printf '%s\n%s\n' "$b" "$(printf '%s' "$b" | tr '_' '-')" ; done
|
|
40
|
+
ddev list --json-output 2>/dev/null | jq -r '.raw[]?.name // empty' 2>/dev/null
|
|
41
|
+
# The shared infrastructure is not a project and has no folder to find. It is what makes every
|
|
42
|
+
# build fast; deleting it is a self-inflicted hour of re-downloading.
|
|
43
|
+
printf 'ddev-global-cache\nddev-ssh-agent\n'
|
|
44
|
+
} | sed '/^$/d' | sort -u ;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Is this resource owned by a protected project? Conservative on purpose: it strips the pieces DDEV
|
|
48
|
+
# appends, then also accepts a protected name as a PREFIX, so a compose-created volume like
|
|
49
|
+
# `penpot_penpot_assets` is protected by the project `penpot`. When in doubt this answers "yes".
|
|
50
|
+
function reclaim_is_protected() {
|
|
51
|
+
local resource="$1" protected_file="$2" stem ;
|
|
52
|
+
# Delimiter is # rather than | : the alternation below IS a |, and sed would read the first one as
|
|
53
|
+
# the end of the s command.
|
|
54
|
+
stem="$(printf '%s' "${resource}" \
|
|
55
|
+
| sed -E 's#^ddev-##; s#-(snapshots|mariadb|postgres|mysql|solr|elasticsearch|redis)$##; s#:.*$##')" ;
|
|
56
|
+
grep -qxF "${stem}" "${protected_file}" && return 0 ;
|
|
57
|
+
# `local pname`, not `name`: this loop runs INSIDE the caller's own `while read -r name` loops, and
|
|
58
|
+
# an unlocalised `name` here overwrites theirs — which printed every container with a blank name.
|
|
59
|
+
#
|
|
60
|
+
# Underscore only, never hyphen. docker-compose prefixes its volumes with the project and an
|
|
61
|
+
# underscore (`penpot` owns `penpot_penpot_assets`), so that one has to be honoured. A hyphen
|
|
62
|
+
# prefix must NOT be: DDEV project names share prefixes, so `website_starter` would protect
|
|
63
|
+
# `website_starter-committed-0726-mariadb` — a different, genuinely dead project. The suffix strip above
|
|
64
|
+
# already handles `<project>-mariadb` and `ddev-<project>-snapshots` by exact match.
|
|
65
|
+
local pname ;
|
|
66
|
+
while read -r pname ; do
|
|
67
|
+
[ -z "${pname}" ] && continue ;
|
|
68
|
+
case "${resource#ddev-}" in
|
|
69
|
+
"${pname}"|"${pname}"_*) return 0 ;;
|
|
70
|
+
esac
|
|
71
|
+
done < "${protected_file}" ;
|
|
72
|
+
return 1 ;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
# Docker reports sizes as human strings ("337.6MB"); this turns one into bytes so the report can add
|
|
76
|
+
# them up. Unknown or empty reads as 0 rather than failing the sweep.
|
|
77
|
+
function reclaim_to_bytes() {
|
|
78
|
+
printf '%s' "${1:-0}" | awk '
|
|
79
|
+
/[0-9]/ {
|
|
80
|
+
v = $0 ; sub(/[A-Za-z]+$/, "", v) ; u = $0 ; sub(/^[0-9.]+/, "", u) ;
|
|
81
|
+
m = 1 ;
|
|
82
|
+
if (u ~ /^kB?$/) m = 1000 ; else if (u ~ /^MB?$/) m = 1000000 ;
|
|
83
|
+
else if (u ~ /^GB?$/) m = 1000000000 ; else if (u ~ /^TB?$/) m = 1000000000000 ;
|
|
84
|
+
printf "%d", v * m ; exit
|
|
85
|
+
}
|
|
86
|
+
{ print 0 }' ;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function reclaim_human() {
|
|
90
|
+
awk -v b="${1:-0}" 'BEGIN { s="B KB MB GB TB"; split(s,u," "); i=1;
|
|
91
|
+
while (b >= 1000 && i < 5) { b /= 1000; i++ } printf "%.1f %s", b, u[i] }' ;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
# A project DDEV still knows about, whose directory is gone: let DDEV remove it.
|
|
95
|
+
#
|
|
96
|
+
# `ddev delete --omit-snapshot --yes <name>` is the complete operation and raw docker calls are not —
|
|
97
|
+
# it drops the registry entry in ~/.ddev/project_list.yaml, the containers, the database and snapshot
|
|
98
|
+
# volumes, the router configuration and the hosts entries, in the right order. Removing the volume by
|
|
99
|
+
# hand leaves the registry entry behind, which is what makes `ddev list` accumulate rows reading
|
|
100
|
+
# "project directory missing" that outlive anyone's memory of what they were.
|
|
101
|
+
#
|
|
102
|
+
# --omit-snapshot on purpose: the folder is already gone, so there is no codebase for a parting
|
|
103
|
+
# database dump to belong to, and writing one would be reclaiming disk by spending it.
|
|
104
|
+
#
|
|
105
|
+
# This runs BEFORE the docker passes, so whatever DDEV handles here is simply not found by them.
|
|
106
|
+
function reclaim_ddev_orphans() {
|
|
107
|
+
local apply="$1" ;
|
|
108
|
+
local list="${HOME}/.ddev/project_list.yaml" ;
|
|
109
|
+
local name="" approot found=0 ;
|
|
110
|
+
|
|
111
|
+
echo "→ DDEV projects still registered whose directory is gone" ;
|
|
112
|
+
[ -f "${list}" ] || { echo " (no ${list} — DDEV has no registry here)" ; echo "" ; return 0 ; }
|
|
113
|
+
|
|
114
|
+
# The registry file rather than `ddev list`: a row whose approot has vanished is exactly what is
|
|
115
|
+
# being looked for, and `ddev list` is slower and can refuse outright on a broken entry.
|
|
116
|
+
while IFS= read -r line ; do
|
|
117
|
+
case "${line}" in
|
|
118
|
+
[a-zA-Z0-9]*:) name="${line%:}" ;;
|
|
119
|
+
*approot:*)
|
|
120
|
+
approot="$(printf '%s' "${line}" | sed -E 's/.*approot:[[:space:]]*//')" ;
|
|
121
|
+
[ -z "${name}" ] && continue ;
|
|
122
|
+
[ -d "${approot}" ] && continue ;
|
|
123
|
+
found=$(( found + 1 )) ;
|
|
124
|
+
printf " %-42s %s\n" "${name}" "${approot} (gone)" ;
|
|
125
|
+
if [ "${apply}" == 'yes' ] ; then
|
|
126
|
+
ddev delete --omit-snapshot --yes "${name}" > /dev/null 2>&1 \
|
|
127
|
+
&& echo " removed with ddev delete — registry, containers and volumes together" \
|
|
128
|
+
|| echo " ddev delete refused; the docker passes below will catch what is left" ;
|
|
129
|
+
fi
|
|
130
|
+
;;
|
|
131
|
+
esac
|
|
132
|
+
done < "${list}" ;
|
|
133
|
+
|
|
134
|
+
[ "${found}" -eq 0 ] && echo " none — every registered project still has its directory" ;
|
|
135
|
+
echo "" ;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function reclaim_command() {
|
|
139
|
+
local apply="${APPLY}" cats="${ONLY}" keep_days="${KEEP_DAYS}" ;
|
|
140
|
+
local protected freed=0 ;
|
|
141
|
+
|
|
142
|
+
command -v docker > /dev/null 2>&1 || { echo "docker is not on PATH — nothing to sweep." ; return 1 ; }
|
|
143
|
+
|
|
144
|
+
protected="$(mktemp)" ; trap 'rm -f "${protected}"' RETURN ;
|
|
145
|
+
reclaim_protected_names > "${protected}" ;
|
|
146
|
+
|
|
147
|
+
if [ "${LIST_PROTECTED}" == 'yes' ] ; then
|
|
148
|
+
echo "" ;
|
|
149
|
+
echo "Protected — nothing belonging to any of these can be removed:" ;
|
|
150
|
+
nl -ba "${protected}" | sed 's/^/ /' ;
|
|
151
|
+
echo "" ;
|
|
152
|
+
echo " $(wc -l < "${protected}") names, from the folders under ${WORKSPACE_ROOT} and DDEV's own registry." ;
|
|
153
|
+
echo "" ;
|
|
154
|
+
return 0 ;
|
|
155
|
+
fi
|
|
156
|
+
|
|
157
|
+
[ "${cats}" == '_none_' ] && cats="cache,volumes,images,containers" ;
|
|
158
|
+
local want_cache=0 want_vol=0 want_img=0 want_con=0 ;
|
|
159
|
+
case ",${cats}," in *,cache,*) want_cache=1 ;; esac ;
|
|
160
|
+
case ",${cats}," in *,volumes,*) want_vol=1 ;; esac ;
|
|
161
|
+
case ",${cats}," in *,images,*) want_img=1 ;; esac ;
|
|
162
|
+
case ",${cats}," in *,containers,*) want_con=1 ;; esac ;
|
|
163
|
+
|
|
164
|
+
echo "" ;
|
|
165
|
+
echo "── Reclaim ──────────────────────────────────────────────────────────" ;
|
|
166
|
+
df -h / | awk 'NR==2 {printf " disk: %s used of %s (%s), %s free\n", $3, $2, $5, $4}' ;
|
|
167
|
+
echo " protecting $(wc -l < "${protected}") project name(s); anything with a folder is off limits" ;
|
|
168
|
+
echo " age floor: nothing younger than ${keep_days} day(s)" ;
|
|
169
|
+
[ "${apply}" == 'yes' ] && echo " MODE: applying — things will be deleted" \
|
|
170
|
+
|| echo " MODE: dry run — nothing will be deleted (add --apply)" ;
|
|
171
|
+
echo "" ;
|
|
172
|
+
|
|
173
|
+
# ---- DDEV first: it removes a registered project completely; docker cannot ----
|
|
174
|
+
reclaim_ddev_orphans "${apply}" ;
|
|
175
|
+
|
|
176
|
+
# ---- containers: exited, and not owned by a protected project -----------------
|
|
177
|
+
if [ "${want_con}" -eq 1 ] ; then
|
|
178
|
+
echo "→ exited containers" ;
|
|
179
|
+
# Ownership comes from DDEV's own label, not from the container name. Guessing the project out of
|
|
180
|
+
# `ddev-milvus-milvus-standalone` by stripping a service suffix cannot work — milvus names its
|
|
181
|
+
# services `milvus-standalone` and `milvus-attu` — and getting it wrong offers a live project's
|
|
182
|
+
# container for removal. `com.ddev.site-name` is the answer DDEV itself uses. Containers that
|
|
183
|
+
# carry no such label are not DDEV's, and fall back to the name check.
|
|
184
|
+
while IFS=$'\t' read -r name size labels ; do
|
|
185
|
+
[ -z "${name}" ] && continue ;
|
|
186
|
+
# `.Labels` is a comma-joined STRING in docker ps --format, not a map, so `index` errors on it;
|
|
187
|
+
# the value is pulled out of the string. It is empty on non-DDEV containers.
|
|
188
|
+
local owner ; owner="$(printf '%s' "${labels}" | sed -n 's/.*com\.ddev\.site-name=\([^,]*\).*/\1/p')" ;
|
|
189
|
+
if [ -n "${owner}" ] && grep -qxF "${owner}" "${protected}" ; then continue ; fi
|
|
190
|
+
if reclaim_is_protected "${name#ddev-}" "${protected}" ; then continue ; fi
|
|
191
|
+
printf " %-52s %s\n" "${name}" "${size}" ;
|
|
192
|
+
freed=$(( freed + $(reclaim_to_bytes "${size%% *}") )) ;
|
|
193
|
+
[ "${apply}" == 'yes' ] && docker rm "${name}" > /dev/null 2>&1 ;
|
|
194
|
+
done < <(docker ps -a --filter status=exited \
|
|
195
|
+
--format '{{.Names}}\t{{.Size}}\t{{.Labels}}' 2>/dev/null) ;
|
|
196
|
+
echo "" ;
|
|
197
|
+
fi
|
|
198
|
+
|
|
199
|
+
# ---- volumes: attached to nothing, no folder, no registry entry ---------------
|
|
200
|
+
if [ "${want_vol}" -eq 1 ] ; then
|
|
201
|
+
echo "→ volumes of projects that no longer exist" ;
|
|
202
|
+
local attached ; attached="$(mktemp)" ;
|
|
203
|
+
docker ps -aq 2>/dev/null | xargs -r docker inspect --format \
|
|
204
|
+
'{{range .Mounts}}{{if eq .Type "volume"}}{{.Name}}{{"\n"}}{{end}}{{end}}' 2>/dev/null \
|
|
205
|
+
| sed '/^$/d' | sort -u > "${attached}" ;
|
|
206
|
+
while read -r vol ; do
|
|
207
|
+
[ -z "${vol}" ] && continue ;
|
|
208
|
+
grep -qxF "${vol}" "${attached}" && continue ; # in use by a container
|
|
209
|
+
reclaim_is_protected "${vol}" "${protected}" && continue ; # its project still exists
|
|
210
|
+
local size ; size="$(docker system df -v 2>/dev/null | awk -v v="${vol}" '$1==v {print $3; exit}')" ;
|
|
211
|
+
printf " %-52s %s\n" "${vol}" "${size:-?}" ;
|
|
212
|
+
freed=$(( freed + $(reclaim_to_bytes "${size}") )) ;
|
|
213
|
+
[ "${apply}" == 'yes' ] && docker volume rm "${vol}" > /dev/null 2>&1 ;
|
|
214
|
+
done < <(docker volume ls -q 2>/dev/null) ;
|
|
215
|
+
rm -f "${attached}" ;
|
|
216
|
+
echo "" ;
|
|
217
|
+
fi
|
|
218
|
+
|
|
219
|
+
# ---- images: DDEV's per-project built images, for projects that are gone ------
|
|
220
|
+
if [ "${want_img}" -eq 1 ] ; then
|
|
221
|
+
echo "→ per-project DDEV images of projects that no longer exist" ;
|
|
222
|
+
while IFS=$'\t' read -r img size ; do
|
|
223
|
+
[ -z "${img}" ] && continue ;
|
|
224
|
+
# ddev/ddev-webserver:v1.25.2-<project>-built → <project>
|
|
225
|
+
local proj ; proj="$(printf '%s' "${img}" | sed -E 's#^.*:v[0-9]+\.[0-9]+\.[0-9]+-##; s#-built$##')" ;
|
|
226
|
+
[ "${proj}" == "${img}" ] && continue ; # not a per-project image
|
|
227
|
+
reclaim_is_protected "${proj}" "${protected}" && continue ;
|
|
228
|
+
printf " %-58s %s\n" "${img}" "${size}" ;
|
|
229
|
+
freed=$(( freed + $(reclaim_to_bytes "${size}") )) ;
|
|
230
|
+
[ "${apply}" == 'yes' ] && docker rmi "${img}" > /dev/null 2>&1 ;
|
|
231
|
+
done < <(docker images --format '{{.Repository}}:{{.Tag}}\t{{.Size}}' 2>/dev/null | grep -E ':v[0-9.]+-.*-built') ;
|
|
232
|
+
echo "" ;
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
# ---- images left behind by a DDEV UPGRADE ------------------------------------
|
|
236
|
+
# A different question from the one above, and a bigger answer. These belong to projects that are
|
|
237
|
+
# perfectly alive; what is dead is the DDEV version they were built for. `ddev start` rebuilds
|
|
238
|
+
# against the installed version and never looks at the old tag again, so every
|
|
239
|
+
# ddev/*:v<old>-<project>-built and every ddev/*:v<old> base image is weight that will not be used
|
|
240
|
+
# — 12 images and about 10 GB on this machine after one upgrade.
|
|
241
|
+
#
|
|
242
|
+
# The installed version is read from ddev itself rather than assumed. A container still running on
|
|
243
|
+
# an old image holds it, and `docker rmi` refuses in that case: that refusal is the safety net, not
|
|
244
|
+
# an error, so it is reported quietly rather than treated as a failure.
|
|
245
|
+
if [ "${want_img}" -eq 1 ] ; then
|
|
246
|
+
local ddev_version ;
|
|
247
|
+
ddev_version="$(ddev --version 2>/dev/null | grep -oE 'v[0-9]+\.[0-9]+\.[0-9]+' | head -1)";
|
|
248
|
+
echo "→ DDEV images from a superseded version (installed: ${ddev_version:-unknown})" ;
|
|
249
|
+
if [ -z "${ddev_version}" ] ; then
|
|
250
|
+
echo " could not read the DDEV version — skipped rather than guessing" ;
|
|
251
|
+
else
|
|
252
|
+
local held=0 ;
|
|
253
|
+
while IFS=$'\t' read -r img size ; do
|
|
254
|
+
[ -z "${img}" ] && continue ;
|
|
255
|
+
case "${img}" in *:"${ddev_version}"|*:"${ddev_version}"-*) continue ;; esac ;
|
|
256
|
+
printf " %-62s %s\n" "${img}" "${size}" ;
|
|
257
|
+
freed=$(( freed + $(reclaim_to_bytes "${size}") )) ;
|
|
258
|
+
if [ "${apply}" == 'yes' ] ; then
|
|
259
|
+
docker rmi "${img}" > /dev/null 2>&1 || { held=$(( held + 1 )) ; } ;
|
|
260
|
+
fi
|
|
261
|
+
done < <(docker images --format '{{.Repository}}:{{.Tag}}\t{{.Size}}' 2>/dev/null \
|
|
262
|
+
| grep -E '^ddev/[^:]*:v[0-9]+\.[0-9]+\.[0-9]+') ;
|
|
263
|
+
[ "${held}" -gt 0 ] && echo " ${held} still held by a container — they go on its next ddev start" ;
|
|
264
|
+
fi
|
|
265
|
+
echo "" ;
|
|
266
|
+
fi
|
|
267
|
+
|
|
268
|
+
# ---- build cache: belongs to no project at all -------------------------------
|
|
269
|
+
# Last, and reported separately: it is not project data, it is Docker's layer cache. Removing it
|
|
270
|
+
# costs one slower rebuild and nothing else, which usually makes it the largest safe win.
|
|
271
|
+
if [ "${want_cache}" -eq 1 ] ; then
|
|
272
|
+
echo "→ Docker build cache older than ${keep_days} day(s)" ;
|
|
273
|
+
docker system df 2>/dev/null | awk '/^Build Cache/ {printf " total %s, reclaimable %s\n", $5, $6}' ;
|
|
274
|
+
if [ "${apply}" == 'yes' ] ; then
|
|
275
|
+
if docker buildx version > /dev/null 2>&1 ; then
|
|
276
|
+
docker buildx prune --force --filter "until=$(( keep_days * 24 ))h" 2>/dev/null | tail -2 ;
|
|
277
|
+
else
|
|
278
|
+
docker builder prune --force --filter "until=$(( keep_days * 24 ))h" 2>/dev/null | tail -2 ;
|
|
279
|
+
fi
|
|
280
|
+
else
|
|
281
|
+
echo " (dry run — add --apply to prune it)" ;
|
|
282
|
+
fi
|
|
283
|
+
echo "" ;
|
|
284
|
+
fi
|
|
285
|
+
|
|
286
|
+
echo "── Summary ──────────────────────────────────────────────────────────" ;
|
|
287
|
+
if [ "${apply}" == 'yes' ] ; then
|
|
288
|
+
echo " reclaimed about $(reclaim_human "${freed}") from named resources, plus any build cache above." ;
|
|
289
|
+
df -h / | awk 'NR==2 {printf " disk now: %s used of %s (%s), %s free\n", $3, $2, $5, $4}' ;
|
|
290
|
+
else
|
|
291
|
+
echo " would reclaim about $(reclaim_human "${freed}") from named resources, plus the build cache above." ;
|
|
292
|
+
echo " Nothing was deleted. Re-run with --apply to do it:" ;
|
|
293
|
+
echo " bash cmd-tools-reclaim.sh --apply" ;
|
|
294
|
+
fi
|
|
295
|
+
echo " Anything with a folder under ${WORKSPACE_ROOT} was left alone. See --list-protected." ;
|
|
296
|
+
echo "" ;
|
|
297
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
################################################################################
|
|
4
|
+
## Cutting a release of this tooling, with the version stamped BEFORE the tag.
|
|
5
|
+
################################################################################
|
|
6
|
+
## Releasing used to be a sequence somebody remembered: work out the next tag,
|
|
7
|
+
## `git tag -a`, push it, write the release notes, and then — separately, later,
|
|
8
|
+
## if at all — get the machines onto it. The stamp was the part that fell off.
|
|
9
|
+
## `core/workspace-app/.app-version` is what the dashboard reads to say which
|
|
10
|
+
## release it runs and which notes to link to, and nothing in the release wrote
|
|
11
|
+
## it, so the machine that cut 1.0.13 went on reporting 1.0.12 until someone
|
|
12
|
+
## thought to run the updater against a release they had just made themselves.
|
|
13
|
+
##
|
|
14
|
+
## A version that lags its own release is worse than no version: the rail shows a
|
|
15
|
+
## number, the number is wrong, and it links to the wrong notes.
|
|
16
|
+
##
|
|
17
|
+
## So the stamp is written first and the tag is cut from it. The order matters —
|
|
18
|
+
## if the tag went first and the stamp failed, the release would exist with the
|
|
19
|
+
## machines still reporting the old one, which is exactly the state this fixes.
|
|
20
|
+
##
|
|
21
|
+
## Nothing here is Webship-specific: the repository comes from `sources: tooling:`
|
|
22
|
+
## in settings.yml, so a fork releases itself.
|
|
23
|
+
################################################################################
|
|
24
|
+
|
|
25
|
+
# The repository this tooling releases to, from settings.yml rather than hardcoded.
|
|
26
|
+
function release_repo() {
|
|
27
|
+
local host repo
|
|
28
|
+
host="${sources_tooling_host:-github.com}"
|
|
29
|
+
repo="${sources_tooling_repo:-}"
|
|
30
|
+
repo="$(echo "${repo}" | tr -d '"'"'"'')"
|
|
31
|
+
[ -n "${repo}" ] || { echo "No sources.tooling.repo in settings.yml." >&2 ; return 1 ; }
|
|
32
|
+
[ "${host}" = 'github.com' ] || { echo "Only github.com is released to today; this tree points at ${host}." >&2 ; return 1 ; }
|
|
33
|
+
echo "${repo}"
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# The newest tag in the clone, by version order. Empty on a repository with none.
|
|
37
|
+
function release_current_tag() {
|
|
38
|
+
local clone="${1:-}"
|
|
39
|
+
git -C "${clone}" tag --sort=-v:refname 2>/dev/null | head -1
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# The next tag: the last segment of the newest one, plus one. 1.0.12 -> 1.0.13.
|
|
43
|
+
# Never invents a shape — a tag this cannot read is refused rather than guessed at,
|
|
44
|
+
# because a tag is permanent and a wrong one cannot be taken back.
|
|
45
|
+
function release_next_tag() {
|
|
46
|
+
local current="${1:-}"
|
|
47
|
+
[ -n "${current}" ] || { echo "" ; return 1 ; }
|
|
48
|
+
case "${current}" in
|
|
49
|
+
*[!0-9.]*) echo "" ; return 1 ;;
|
|
50
|
+
esac
|
|
51
|
+
local head tail
|
|
52
|
+
head="${current%.*}"
|
|
53
|
+
tail="${current##*.}"
|
|
54
|
+
[ "${head}" != "${current}" ] || { echo "" ; return 1 ; }
|
|
55
|
+
[ -n "${tail}" ] || { echo "" ; return 1 ; }
|
|
56
|
+
echo "${head}.$((tail + 1))"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Is this clone releasable: on the branch, clean, and level with the remote?
|
|
60
|
+
# Each answer is printed, because "it refused" without the reason is a worse
|
|
61
|
+
# message than no message.
|
|
62
|
+
function release_ready() {
|
|
63
|
+
local clone="${1}" branch="${2}" remote="${3:-github}" ok=0
|
|
64
|
+
local on ahead behind
|
|
65
|
+
on="$(git -C "${clone}" rev-parse --abbrev-ref HEAD 2>/dev/null)"
|
|
66
|
+
if [ "${on}" != "${branch}" ]; then
|
|
67
|
+
echo " ✗ the clone is on ${on:-nothing}, not ${branch}" ; ok=1
|
|
68
|
+
else
|
|
69
|
+
echo " ✓ on ${branch}"
|
|
70
|
+
fi
|
|
71
|
+
if [ -n "$(git -C "${clone}" status --porcelain 2>/dev/null)" ]; then
|
|
72
|
+
echo " ✗ the clone has uncommitted changes — a tag would not say what is in it" ; ok=1
|
|
73
|
+
else
|
|
74
|
+
echo " ✓ nothing uncommitted"
|
|
75
|
+
fi
|
|
76
|
+
git -C "${clone}" fetch -q "${remote}" 2>/dev/null
|
|
77
|
+
ahead="$(git -C "${clone}" rev-list --count "${remote}/${branch}..HEAD" 2>/dev/null || echo '?')"
|
|
78
|
+
behind="$(git -C "${clone}" rev-list --count "HEAD..${remote}/${branch}" 2>/dev/null || echo '?')"
|
|
79
|
+
if [ "${ahead}" = '0' ] && [ "${behind}" = '0' ]; then
|
|
80
|
+
echo " ✓ level with ${remote}/${branch}"
|
|
81
|
+
else
|
|
82
|
+
echo " ✗ ${ahead} ahead / ${behind} behind ${remote}/${branch} — push or pull first" ; ok=1
|
|
83
|
+
fi
|
|
84
|
+
return ${ok}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# The gate: the smoke test over every cmd-*.sh, and the dashboard's unit tests.
|
|
88
|
+
# A release that has not been run is a release nobody has tested.
|
|
89
|
+
function release_gate() {
|
|
90
|
+
local clone="${1}" ok=0
|
|
91
|
+
echo "Running the gate…"
|
|
92
|
+
if bash "${WORKSPACE_SCRIPTS}/tests/cmd-smoke-test.sh" > /tmp/workspace-release-smoke.$$ 2>&1 ; then
|
|
93
|
+
echo " ✓ $(tail -2 /tmp/workspace-release-smoke.$$ | head -1 | sed 's/^ *//')"
|
|
94
|
+
else
|
|
95
|
+
echo " ✗ the cmd smoke test failed:" ; tail -5 /tmp/workspace-release-smoke.$$ | sed 's/^/ /' ; ok=1
|
|
96
|
+
fi
|
|
97
|
+
rm -f /tmp/workspace-release-smoke.$$
|
|
98
|
+
if [ -d "${WORKSPACE_PATH}/workspace-app/node_modules" ]; then
|
|
99
|
+
if ( cd "${WORKSPACE_PATH}/workspace-app" && npm run --silent test:unit ) > /tmp/workspace-release-unit.$$ 2>&1 ; then
|
|
100
|
+
echo " ✓ dashboard unit tests: $(awk '/^ℹ pass/ {print $3; exit}' /tmp/workspace-release-unit.$$) passed"
|
|
101
|
+
else
|
|
102
|
+
echo " ✗ the dashboard unit tests failed:" ; grep -E '^✖' /tmp/workspace-release-unit.$$ | head -5 | sed 's/^/ /' ; ok=1
|
|
103
|
+
fi
|
|
104
|
+
rm -f /tmp/workspace-release-unit.$$
|
|
105
|
+
else
|
|
106
|
+
echo " · dashboard unit tests skipped (no node_modules in the live tree)"
|
|
107
|
+
fi
|
|
108
|
+
return ${ok}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
# What a release WOULD do. Printed on its own by default: tagging and publishing
|
|
112
|
+
# are public and irreversible, so they are never a side effect of asking.
|
|
113
|
+
function release_plan() {
|
|
114
|
+
local clone="${1}" branch="${2}" current="${3}" next="${4}" repo="${5}"
|
|
115
|
+
echo ""
|
|
116
|
+
echo "Release plan"
|
|
117
|
+
echo " repository ${repo}"
|
|
118
|
+
echo " branch ${branch} at $(git -C "${clone}" rev-parse --short "${branch}" 2>/dev/null)"
|
|
119
|
+
echo " current tag ${current:-none}"
|
|
120
|
+
echo " next tag ${next}"
|
|
121
|
+
echo " stamp $(workspace_version_file) → ${next}"
|
|
122
|
+
echo ""
|
|
123
|
+
echo " Since ${current:-the beginning}:"
|
|
124
|
+
git -C "${clone}" log --oneline "${current}..${branch}" 2>/dev/null | sed 's/^/ /'
|
|
125
|
+
echo ""
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
# Cut it. The stamp is written BEFORE the tag: if the stamp fails, nothing is
|
|
129
|
+
# published, and the tree is still honestly on the old release.
|
|
130
|
+
function release_cut() {
|
|
131
|
+
local clone="${1}" branch="${2}" next="${3}" repo="${4}" notes="${5:-}" remote="${6:-github}"
|
|
132
|
+
|
|
133
|
+
echo "Stamping this tree as ${next}…"
|
|
134
|
+
workspace_version_stamp "${next}" || { echo "Could not write $(workspace_version_file) — nothing was tagged." >&2 ; return 1 ; }
|
|
135
|
+
echo " ✓ $(workspace_version_file)"
|
|
136
|
+
|
|
137
|
+
local message
|
|
138
|
+
message="$(printf 'Webship Workspace %s\n\n%s\n' "${next}" "$(git -C "${clone}" log --format=' %s' "$(release_current_tag "${clone}")..${branch}" 2>/dev/null)")"
|
|
139
|
+
echo "Tagging ${next}…"
|
|
140
|
+
git -C "${clone}" tag -a "${next}" "${branch}" -m "${message}" || { echo "The tag was refused — the stamp is written, the release is not." >&2 ; return 1 ; }
|
|
141
|
+
git -C "${clone}" push -q "${remote}" "${next}" || { echo "The tag could not be pushed." >&2 ; return 1 ; }
|
|
142
|
+
echo " ✓ ${next} pushed to ${remote}"
|
|
143
|
+
|
|
144
|
+
if command -v gh > /dev/null 2>&1 ; then
|
|
145
|
+
if [ -n "${notes}" ] && [ -f "${notes}" ]; then
|
|
146
|
+
gh release create "${next}" --repo "${repo}" --title "${next}" --notes-file "${notes}" --latest \
|
|
147
|
+
&& echo " ✓ release published with your notes"
|
|
148
|
+
else
|
|
149
|
+
gh release create "${next}" --repo "${repo}" --title "${next}" --generate-notes --latest \
|
|
150
|
+
&& echo " ✓ release published with generated notes — write the real ones over them"
|
|
151
|
+
fi
|
|
152
|
+
else
|
|
153
|
+
echo " · gh is not installed: the tag is pushed, the release page is not created."
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
echo ""
|
|
157
|
+
echo "Done. The dashboard reports ${next} on its next page load; other machines get it with:"
|
|
158
|
+
echo " bash core/workspace-app/scripts/update.sh"
|
|
159
|
+
}
|