@webship.co/workspace 1.0.0-alpha1 → 1.0.0-beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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} +1 -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/{plugin-loader.js → core/workspace-app/plugin-loader.js} +19 -1
- package/{plugins-page.js → core/workspace-app/plugins-page.js} +28 -2
- package/{row-layout.js → core/workspace-app/row-layout.js} +0 -1
- package/{server.js → core/workspace-app/server.js} +26 -225
- 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/{workspace-types.js → core/workspace-app/workspace-types.js} +2 -2
- package/{workspaces.js → core/workspace-app/workspaces.js} +1 -5
- package/package.json +38 -36
- package/actions/graphs.js +0 -107
- package/actions/obsidian.js +0 -59
- package/graphs.js +0 -104
- package/obsidian.js +0 -405
- /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-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/{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
|
@@ -58,7 +58,6 @@ const BUILTIN_BUTTONS = [
|
|
|
58
58
|
// Single buttons, with no menu inside to arrange or to add actions to.
|
|
59
59
|
{ id: 'backup', label: 'Backup', row: 1, menu: false },
|
|
60
60
|
{ id: 'clone', label: 'Clone', row: 1, menu: false },
|
|
61
|
-
{ id: 'graph', label: 'Graph', row: 1 },
|
|
62
61
|
{ id: 'rag', label: 'RAG', row: 1 },
|
|
63
62
|
{ id: 'more', label: 'More', row: 1 },
|
|
64
63
|
];
|
|
@@ -26,7 +26,6 @@ const {
|
|
|
26
26
|
workspaceDir,
|
|
27
27
|
findBackupScript,
|
|
28
28
|
findRemoveScript,
|
|
29
|
-
findGraphifyScript,
|
|
30
29
|
findRagifyScript,
|
|
31
30
|
findBuilderScripts,
|
|
32
31
|
listBackups,
|
|
@@ -85,7 +84,7 @@ const {
|
|
|
85
84
|
// Optional features workspaces turn on from settings.yml `plugins:` — see PLUGINS.md.
|
|
86
85
|
const {
|
|
87
86
|
pluginActions, pluginFragment, pluginPage, pluginPageActionGroups, pluginProjectActionsHtml,
|
|
88
|
-
pluginRowMenus, pluginOpenWith, pluginFolderLinks, pluginProjectChipsHtml, pluginLabels,
|
|
87
|
+
pluginRowMenus, pluginWorkspaceView, pluginOpenWith, pluginFolderLinks, pluginProjectChipsHtml, pluginLabels,
|
|
89
88
|
pluginProjectBadgesHtml, pluginSettingsOptions, pluginWorkKeyLink, pluginWorkPrompt,
|
|
90
89
|
} = require('./plugin-loader');
|
|
91
90
|
// How a project row is arranged — the order of its buttons and of what is inside their menus (Commands → Buttons).
|
|
@@ -133,7 +132,6 @@ const {
|
|
|
133
132
|
const { commandAuthorPrompt, commandEditPrompt } = require('./command-author');
|
|
134
133
|
const { checksCaption, checksDeclaredOf, checksRowsOf } = require('./checks');
|
|
135
134
|
const { testReportPdfHtml } = require('./report-pdf');
|
|
136
|
-
const { graphStoreDir, hasGraph, graphCounts, listGraphs } = require('./graphs');
|
|
137
135
|
const {
|
|
138
136
|
milvusProjectName, milvusRestBase, ragInstances, ragBindings, ragInstanceFor, ragWriteBinding,
|
|
139
137
|
ragCollectionName, milvusPost, ragCollections, ragInvalidate,
|
|
@@ -143,7 +141,6 @@ const {
|
|
|
143
141
|
ddevProjectName, listProjects, listProjectsDetailed,
|
|
144
142
|
startInScreen, screenStartedHtml, screenAction, screenSessionName,
|
|
145
143
|
} = require('./jobs');
|
|
146
|
-
const { vaultDir, indexNote, vaultView, vaultCanvas, vaultFrame, obsidianMenuItems } = require('./obsidian');
|
|
147
144
|
const { assembleCss, cssVersion, listThemes, themeLabel, createTheme, themePreview, isYamlOnlyTheme } = require('./themes');
|
|
148
145
|
const NAME_RE = /^[a-zA-Z0-9_\-]+$/;
|
|
149
146
|
|
|
@@ -2887,7 +2884,8 @@ function homeCardsHtml(message) {
|
|
|
2887
2884
|
const workspaces = loadWorkspaces();
|
|
2888
2885
|
const keys = Object.keys(workspaces);
|
|
2889
2886
|
const cards = Object.values(workspaces).map((w) => {
|
|
2890
|
-
const
|
|
2887
|
+
const view = pluginWorkspaceView(w.key);
|
|
2888
|
+
const projectCount = view && view.count ? view.count()
|
|
2891
2889
|
: w.kind === 'files' ? listItems(w.key).length : listProjects(w.dir).length;
|
|
2892
2890
|
const hasBuilders = w.kind === 'files' || !w.typeActions.has('build') ? false : findBuilderScripts(w.dir).length > 0;
|
|
2893
2891
|
const backupCount = listBackups(w.key).length;
|
|
@@ -2922,6 +2920,24 @@ function homeCardsHtml(message) {
|
|
|
2922
2920
|
uk-grid data-sortable=".ws-card-wrap" data-sortable-view="home"
|
|
2923
2921
|
data-order="${esc(keys.join(','))}" data-file="settings.yml" data-key="workspaces">${cards}</div>
|
|
2924
2922
|
${message || ''}
|
|
2923
|
+
${keys.length ? '' : emptyWorkspaceHtml()}
|
|
2924
|
+
</div>`;
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
// A fresh workspace has no folders and no plugins: that is the design, not a fault, and the first
|
|
2928
|
+
// thing to see is what can be added and how.
|
|
2929
|
+
function emptyWorkspaceHtml() {
|
|
2930
|
+
const { FAMILIES } = require('./plugin-catalog');
|
|
2931
|
+
const families = FAMILIES.map((f) => `<li><strong>${esc(f.label)}</strong> <span class="uk-text-meta">${esc(f.plugins.map(([n]) => n).join(' · '))}</span></li>`).join('');
|
|
2932
|
+
return `<div class="uk-card uk-card-default uk-card-body uk-margin-small-top empty-workspace">
|
|
2933
|
+
<h2 class="uk-h4">Empty, on purpose</h2>
|
|
2934
|
+
<p>This workspace has no folders and no plugins yet. Everything is an npm package <code>@webship.co/workspace-<name></code>,
|
|
2935
|
+
added one at a time when you ask for it — from <a href="/settings/plugins">Settings → Plugins</a>, or:</p>
|
|
2936
|
+
<pre class="uk-background-muted uk-padding-small">webship-workspace plugin require dev
|
|
2937
|
+
webship-workspace plugin activate dev
|
|
2938
|
+
webship-workspace plugin install dev</pre>
|
|
2939
|
+
<ul class="uk-list uk-list-collapse">${families}</ul>
|
|
2940
|
+
<p class="uk-text-meta"><a href="/settings/plugins">Open the catalogue</a> · the full list: <code>webship-workspace catalog</code></p>
|
|
2925
2941
|
</div>`;
|
|
2926
2942
|
}
|
|
2927
2943
|
|
|
@@ -3144,7 +3160,6 @@ async function projectRowsHtml(key, dir, state) {
|
|
|
3144
3160
|
const canBackup = allowed.has('backup') && !!findBackupScript(dir);
|
|
3145
3161
|
const canClone = allowed.has('clone') && fs.existsSync(path.join(dir, 'cmd-tools-clone.sh'));
|
|
3146
3162
|
const canRemove = allowed.has('remove') && !!findRemoveScript(dir);
|
|
3147
|
-
const canGraphify = allowed.has('graphify') && !!findGraphifyScript(dir);
|
|
3148
3163
|
const canRagify = allowed.has('ragify') && !!findRagifyScript(dir);
|
|
3149
3164
|
const canTest = allowed.has('tests') && fs.existsSync(path.join(dir, 'cmd-tools-testing.sh'));
|
|
3150
3165
|
const canChecks = allowed.has('checks') && fs.existsSync(path.join(dir, 'cmd-tools-checks.sh'));
|
|
@@ -3459,25 +3474,6 @@ async function projectRowsHtml(key, dir, state) {
|
|
|
3459
3474
|
hx-get="/fragments/projects/clone-form/${encodeURIComponent(key)}/${encodeURIComponent(p)}" hx-target="#editor-modal-body" hx-swap="innerHTML"
|
|
3460
3475
|
hx-on::after:request="UIkit.modal('#editor-modal').show()"
|
|
3461
3476
|
title="Clone this ${esc(meta.noun)} — a copy, or a git worktree sharing its history"><span uk-icon="icon: copy; ratio: .7"></span> Clone</button>` : '';
|
|
3462
|
-
const graphMenu = canGraphify ? (() => {
|
|
3463
|
-
const built = hasGraph(key, p, 'graph.json') || hasGraph(key, p, 'graph.html');
|
|
3464
|
-
const busy = !!runningJobKey(`graphify:${key}/${p}`);
|
|
3465
|
-
return `<span class="act-with-status"><div class="uk-inline act-menu act-menu-graph">
|
|
3466
|
-
<button class="uk-button uk-button-default uk-button-small" type="button" title="Knowledge graph"><span uk-icon="icon: git-fork; ratio: .7"></span> Graph <span uk-icon="icon: chevron-down; ratio: .6"></span></button>
|
|
3467
|
-
|
|
3468
|
-
<div uk-dropdown="mode: click; pos: bottom-right"><ul class="uk-nav uk-dropdown-nav">
|
|
3469
|
-
<li data-entry="build the graph"><a href hx-post="/actions/graphify" ${vals()} class="${busy ? 'uk-disabled' : ''}"><span uk-icon="icon: play; ratio: .7"></span> ${built ? 'Rebuild the graph' : 'Build the graph'}${busy ? ' (running…)' : ''}</a></li>
|
|
3470
|
-
${built ? `<li class="uk-nav-divider"></li>
|
|
3471
|
-
${hasGraph(key, p, 'graph.html') ? `<li><a href="/graph/${esc(key)}/${esc(p)}" target="_blank" title="Loads vis-network from unpkg.com, so it needs internet"><span uk-icon="icon: image; ratio: .7"></span> Open the graph</a></li>` : ''}
|
|
3472
|
-
${hasGraph(key, p, 'GRAPH_REPORT.md') ? `<li><a href="/graph/${esc(key)}/${esc(p)}/report" target="_blank"><span uk-icon="icon: file-text; ratio: .7"></span> Read the report</a></li>` : ''}
|
|
3473
|
-
<li><a href="/graph/${esc(key)}/${esc(p)}/download" title="The graph as a .tar.gz, to hand to another workspace"><span uk-icon="icon: download; ratio: .7"></span> Download to share</a></li>
|
|
3474
|
-
<li><a href hx-post="/actions/graph-mcp-command" ${vals()}><span uk-icon="icon: link; ratio: .7"></span> Connect over MCP…</a></li>
|
|
3475
|
-
${obsidianMenuItems(key, p, vals, busy)}
|
|
3476
|
-
<li class="uk-nav-divider"></li>
|
|
3477
|
-
<li><a href class="uk-text-danger arm-step" hx-post="/actions/graph-remove" ${vals(',"confirm":"yes"')} hx-trigger="confirmed-remove"><span uk-icon="icon: trash; ratio: .7"></span> Delete the graph</a></li>` : ''}
|
|
3478
|
-
</ul></div>
|
|
3479
|
-
</div><span class="act-status uk-text-meta">${built ? 'built' : 'none'}</span></span>`;
|
|
3480
|
-
})() : '';
|
|
3481
3477
|
const ragMenu = canRagify ? (() => {
|
|
3482
3478
|
// The RAG index: the same shape as the Graph menu next to it, because it answers the
|
|
3483
3479
|
// half of the tree the graph does not — prose, templates and configuration.
|
|
@@ -3559,7 +3555,7 @@ async function projectRowsHtml(key, dir, state) {
|
|
|
3559
3555
|
// The menus activated plugins bring, in the slots they registered (UPSUN, …).
|
|
3560
3556
|
...pluginRowMenus({ key, project: p, dir, meta, allowed, vals }),
|
|
3561
3557
|
screens: screensOnTools, composer: composerMenu, node: nodeMenu, backup: backupButton, clone: cloneButton,
|
|
3562
|
-
|
|
3558
|
+
rag: ragMenu, more: moreMenu,
|
|
3563
3559
|
}, rowCtx, { preArranged: new Set(['ddev', 'more']) });
|
|
3564
3560
|
// What is written down about this folder, read once: the name it is called by is the heading, the
|
|
3565
3561
|
// paragraph is the row's tooltip, and the pen that edits both sits in the card's own corner.
|
|
@@ -3840,7 +3836,7 @@ function pageActionGroups(context) {
|
|
|
3840
3836
|
groups.push({ id: 'go-to', label: 'Go to', items: [
|
|
3841
3837
|
link('default', 'arrow-left', `Back to ${meta.label}`, wsUrl(key)),
|
|
3842
3838
|
] });
|
|
3843
|
-
} else if (meta && meta.kind === 'files' && key
|
|
3839
|
+
} else if (meta && meta.kind === 'files' && !(pluginWorkspaceView(key) || {}).noFilesActions) {
|
|
3844
3840
|
// Audio makes things rather than writes them, so each kind of thing is its own action and its own modal.
|
|
3845
3841
|
// Each is a modal, not an inline form: the result of generating stays in the window that asked for it.
|
|
3846
3842
|
const modal = 'hx-target="#editor-modal-body" hx-swap="innerHTML"';
|
|
@@ -4324,57 +4320,6 @@ function commandsShell(title, subtitle, active, body, context = 'commands') {
|
|
|
4324
4320
|
</main>`, context);
|
|
4325
4321
|
}
|
|
4326
4322
|
|
|
4327
|
-
function graphRowsHtml(state) {
|
|
4328
|
-
const all = listGraphs();
|
|
4329
|
-
const st = state;
|
|
4330
|
-
const filtered = st.q
|
|
4331
|
-
? all.filter((g) => g.name.toLowerCase().includes(st.q.toLowerCase()))
|
|
4332
|
-
: all;
|
|
4333
|
-
const sorted = filtered.slice().sort((SORTS[st.sort] || SORTS[defaultSort()] || SORTS.newest).cmp);
|
|
4334
|
-
const p = paginate(sorted, st);
|
|
4335
|
-
|
|
4336
|
-
const rows = p.slice.map((g) => `
|
|
4337
|
-
<div class="uk-card uk-card-default uk-card-small uk-card-body uk-margin-small project-row">
|
|
4338
|
-
<div class="item-row-body">
|
|
4339
|
-
<span class="uk-text-bold">${iconHtml('tabler:hierarchy-2', 0.8)} ${esc(g.project)}
|
|
4340
|
-
<span class="uk-text-meta item-machine" title="The workspace the project lives in">${esc(g.workspace)}</span></span>
|
|
4341
|
-
<div class="item-meta-line">
|
|
4342
|
-
<span class="uk-text-meta item-time">${esc(humanTime(g.mtime))}</span>
|
|
4343
|
-
<span class="uk-text-meta">· ${esc(humanSize(g.size))}</span>
|
|
4344
|
-
${g.nodes != null ? `<span class="uk-label" title="Nodes and edges, from graphify's own build file">${g.nodes} nodes${g.links != null ? ` · ${g.links} edges` : ''}</span>` : ''}
|
|
4345
|
-
${g.projectExists ? '' : '<span class="uk-label" title="The project is gone — the graph outlived it, and is safe to delete">project removed</span>'}
|
|
4346
|
-
</div>
|
|
4347
|
-
<div class="project-actions">
|
|
4348
|
-
${g.hasHtml ? `<a class="uk-button uk-button-default uk-button-small" href="/graph/${esc(g.workspace)}/${esc(g.project)}" target="_blank" title="Loads vis-network from unpkg.com, so it needs internet"><span uk-icon="icon: image; ratio: .7"></span> Open</a>` : ''}
|
|
4349
|
-
${g.hasReport ? `<a class="uk-button uk-button-default uk-button-small" href="/graph/${esc(g.workspace)}/${esc(g.project)}/report" target="_blank"><span uk-icon="icon: file-text; ratio: .7"></span> Report</a>` : ''}
|
|
4350
|
-
<a class="uk-button uk-button-default uk-button-small" href="/graph/${esc(g.workspace)}/${esc(g.project)}/download"><span uk-icon="icon: download; ratio: .7"></span> Download</a>
|
|
4351
|
-
${g.projectExists ? `<button class="uk-button uk-button-secondary uk-button-small" hx-post="/actions/graphify" hx-vals='{"workspace":"${esc(g.workspace)}","projectName":"${esc(g.project)}"}' hx-target="#webship-workspace-output" hx-swap="innerHTML" title="Re-extract and re-cluster from the project"><span uk-icon="icon: refresh; ratio: .7"></span> Rebuild</button>` : ''}
|
|
4352
|
-
<button class="uk-button uk-button-danger uk-button-small arm-step" hx-post="/actions/graph-remove" hx-vals='{"workspace":"${esc(g.workspace)}","projectName":"${esc(g.project)}","confirm":"yes"}' hx-target="#webship-workspace-output" hx-swap="innerHTML" hx-trigger="confirmed-remove"><span uk-icon="icon: trash; ratio: .7"></span> Delete</button>
|
|
4353
|
-
</div>
|
|
4354
|
-
</div>
|
|
4355
|
-
</div>`).join('');
|
|
4356
|
-
|
|
4357
|
-
// The controls get the BARE URL: htmx appends the included inputs without deduping, and
|
|
4358
|
-
// readPageState reads the FIRST q/sort — a URL already carrying ?q= made the search box a no-op.
|
|
4359
|
-
// The pager keeps the qs form so page links preserve the current search.
|
|
4360
|
-
const bareUrl = '/fragments/graphs/list';
|
|
4361
|
-
const qs = new URLSearchParams();
|
|
4362
|
-
if (st.q) qs.set('q', st.q);
|
|
4363
|
-
if (st.sort !== defaultSort()) qs.set('sort', st.sort);
|
|
4364
|
-
const url = `${bareUrl}${qs.toString() ? `?${qs}` : ''}`;
|
|
4365
|
-
const pager = listPagerHtml(url, '#webship-workspace-projects', p, st, 'graphs');
|
|
4366
|
-
|
|
4367
|
-
return `
|
|
4368
|
-
<h3 class="uk-margin-small-bottom">Graphs <span class="uk-badge">${all.length}</span></h3>
|
|
4369
|
-
<p class="uk-text-meta uk-margin-small-bottom">One directory per project in <code>${esc(path.join(ROOT, 'graphs'))}/<workspace>/<project>/</code>,
|
|
4370
|
-
built by <code>cmd-tools-graphify.sh</code> from the project's workspace folder. Query one with
|
|
4371
|
-
<code>graphify query "…" --graph ${esc(path.join(ROOT, 'graphs'))}/<workspace>/<project>/graph.json</code>.</p>
|
|
4372
|
-
${listControlsHtml(bareUrl, '#webship-workspace-projects', st, 'graphs')}
|
|
4373
|
-
${pager}
|
|
4374
|
-
${rows || '<p class="uk-text-meta">No graphs yet — build one from the Graph menu on any project row.</p>'}
|
|
4375
|
-
${pager}`;
|
|
4376
|
-
}
|
|
4377
|
-
|
|
4378
4323
|
async function workspacePage(key, state) {
|
|
4379
4324
|
await refreshLiveSessions();
|
|
4380
4325
|
const workspaces = loadWorkspaces();
|
|
@@ -4384,12 +4329,8 @@ async function workspacePage(key, state) {
|
|
|
4384
4329
|
const builders = isFiles || !meta.typeActions.has('build') ? [] : findBuilderScripts(dir);
|
|
4385
4330
|
const builderOptions = builders.map((s) => `<option value="${esc(s)}">${esc(builderLabel(dir, s))}</option>`).join('');
|
|
4386
4331
|
|
|
4387
|
-
const
|
|
4388
|
-
|
|
4389
|
-
${graphRowsHtml(state)}
|
|
4390
|
-
</div>
|
|
4391
|
-
|
|
4392
|
-
` : meta.kind === 'commands' ? `
|
|
4332
|
+
const view = pluginWorkspaceView(key);
|
|
4333
|
+
const listSection = view && view.listHtml ? view.listHtml(state) : meta.kind === 'commands' ? `
|
|
4393
4334
|
<div id="webship-workspace-projects" hx-get="/fragments/cc/list" hx-trigger="refresh-projects from:body">
|
|
4394
4335
|
${await commandCatalogHtml(state)}
|
|
4395
4336
|
</div>
|
|
@@ -4517,8 +4458,6 @@ const ACTIONS = {
|
|
|
4517
4458
|
...require('./actions/ddev'),
|
|
4518
4459
|
...require('./actions/ddev-mail').make({ mailpitFor: ddevMail.mailpitFor(ddevStatusMap) }),
|
|
4519
4460
|
...require('./actions/ddev-addons'),
|
|
4520
|
-
...require('./actions/graphs'),
|
|
4521
|
-
...require('./actions/obsidian'),
|
|
4522
4461
|
...require('./actions/rag'),
|
|
4523
4462
|
...require('./actions/testing'),
|
|
4524
4463
|
...require('./actions/checks'),
|
|
@@ -5660,80 +5599,6 @@ const server = http.createServer(async (req, res) => {
|
|
|
5660
5599
|
const out = path.join(tmp, 'report.pdf');
|
|
5661
5600
|
const cleanup = () => { try { fs.rmSync(tmp, { recursive: true, force: true }); } catch (_) { /* gone */ } };
|
|
5662
5601
|
|
|
5663
|
-
// The vault: its index note, and the whole thing as an archive. Same symlink discipline
|
|
5664
|
-
// as the graph routes below — a project directory that is a link would otherwise read
|
|
5665
|
-
// outside the workspace, and this container bind-mounts ~/.claude as well as ~/workspace.
|
|
5666
|
-
const vaultMatch = pathname.match(/^\/obsidian\/([a-z0-9_-]+)\/([a-zA-Z0-9_.-]+)\/(index|download|view|canvas|frame)$/);
|
|
5667
|
-
if (vaultMatch && isValidWorkspace(vaultMatch[1])) {
|
|
5668
|
-
const [, wsKey, project, what] = vaultMatch;
|
|
5669
|
-
if (project.includes('..')) { res.writeHead(400); return res.end('bad name'); }
|
|
5670
|
-
let real;
|
|
5671
|
-
try {
|
|
5672
|
-
real = fs.realpathSync(vaultDir(wsKey, project));
|
|
5673
|
-
const base = fs.realpathSync(path.join(ROOT, 'graphs'));
|
|
5674
|
-
if (!real.startsWith(base + path.sep) || !fs.statSync(real).isDirectory()) throw new Error('outside');
|
|
5675
|
-
} catch (_) {
|
|
5676
|
-
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
5677
|
-
return res.end('No vault yet — build one from the Graph menu on the project row.');
|
|
5678
|
-
}
|
|
5679
|
-
|
|
5680
|
-
if (what === 'frame') {
|
|
5681
|
-
const wanted = String(new URL(req.url, 'http://localhost').searchParams.get('what') || 'view');
|
|
5682
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
5683
|
-
return res.end(vaultFrame(wsKey, project, wanted));
|
|
5684
|
-
}
|
|
5685
|
-
|
|
5686
|
-
if (what === 'view' || what === 'canvas') {
|
|
5687
|
-
// Built before the head is written: a throw after writeHead becomes a 200 with an
|
|
5688
|
-
// empty body, which reads as "the vault is empty" rather than "this broke".
|
|
5689
|
-
let page;
|
|
5690
|
-
try {
|
|
5691
|
-
const themed = cssVersion(styleSettings().theme);
|
|
5692
|
-
page = what === 'view'
|
|
5693
|
-
? vaultView(wsKey, project, String(new URL(req.url, 'http://localhost').searchParams.get('note') || ''), themed)
|
|
5694
|
-
: vaultCanvas(wsKey, project, themed);
|
|
5695
|
-
} catch (e) {
|
|
5696
|
-
res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
5697
|
-
return res.end(`Could not read the vault: ${e.message}`);
|
|
5698
|
-
}
|
|
5699
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
5700
|
-
return res.end(page);
|
|
5701
|
-
}
|
|
5702
|
-
|
|
5703
|
-
if (what === 'index') {
|
|
5704
|
-
// Read before the head is written: computing after writeHead turns a throw into a
|
|
5705
|
-
// 200 with an empty body, which reads as "it worked and there is nothing there".
|
|
5706
|
-
let md;
|
|
5707
|
-
try {
|
|
5708
|
-
md = fs.readFileSync(path.join(real, indexNote(project)), 'utf8');
|
|
5709
|
-
} catch (_) {
|
|
5710
|
-
res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
5711
|
-
return res.end('<div class="msg error">The vault has no index note. Rebuild it.</div>');
|
|
5712
|
-
}
|
|
5713
|
-
const vaultUri = `obsidian://open?path=${encodeURIComponent(real)}`;
|
|
5714
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
5715
|
-
return res.end(`<h3>${esc(project)} <span class="uk-text-meta">Obsidian vault</span></h3>
|
|
5716
|
-
<p class="uk-text-meta">${esc(real)}</p>
|
|
5717
|
-
<p><a class="uk-button uk-button-primary uk-button-small" href="${esc(vaultUri)}">Open in Obsidian</a>
|
|
5718
|
-
<a class="uk-button uk-button-default uk-button-small" href="/obsidian/${esc(wsKey)}/${esc(project)}/download">Download</a></p>
|
|
5719
|
-
<pre class="uk-background-muted uk-padding-small" style="white-space:pre-wrap">${esc(md)}</pre>`);
|
|
5720
|
-
}
|
|
5721
|
-
|
|
5722
|
-
const vaultArchive = `${wsKey}--${project}--obsidian.tar.gz`;
|
|
5723
|
-
res.writeHead(200, {
|
|
5724
|
-
'Content-Type': 'application/gzip',
|
|
5725
|
-
'Content-Disposition': `attachment; filename="${vaultArchive.replace(/[^A-Za-z0-9._-]/g, '_')}"`,
|
|
5726
|
-
'X-Content-Type-Options': 'nosniff',
|
|
5727
|
-
});
|
|
5728
|
-
const vtar = spawn('tar', ['-czf', '-', '-C', path.dirname(real), path.basename(real)],
|
|
5729
|
-
{ stdio: ['ignore', 'pipe', 'pipe'] });
|
|
5730
|
-
vtar.stdout.pipe(res);
|
|
5731
|
-
vtar.stderr.resume();
|
|
5732
|
-
vtar.on('error', () => { try { res.destroy(); } catch (_) { /* client gone */ } });
|
|
5733
|
-
res.on('close', () => { try { vtar.kill(); } catch (_) { /* already exited */ } });
|
|
5734
|
-
return;
|
|
5735
|
-
}
|
|
5736
|
-
|
|
5737
5602
|
// Rendered from the run's JSON through our own print stylesheet, not from
|
|
5738
5603
|
// cucumber-html-reporter's page: that page's feature and scenario bodies are Bootstrap
|
|
5739
5604
|
// collapsibles which print CLOSED — a PDF of nothing but headers — and its CSS comes from
|
|
@@ -5779,66 +5644,6 @@ const server = http.createServer(async (req, res) => {
|
|
|
5779
5644
|
});
|
|
5780
5645
|
return;
|
|
5781
5646
|
}
|
|
5782
|
-
const graphDlMatch = pathname.match(/^\/graph\/([a-z0-9_-]+)\/([a-zA-Z0-9_.\-]+)\/download$/);
|
|
5783
|
-
if (graphDlMatch && isValidWorkspace(graphDlMatch[1])) {
|
|
5784
|
-
const [, wsKey, project] = graphDlMatch;
|
|
5785
|
-
if (project.includes('..')) { res.writeHead(400); return res.end('bad name'); }
|
|
5786
|
-
const out = graphStoreDir(wsKey, project);
|
|
5787
|
-
let real;
|
|
5788
|
-
try {
|
|
5789
|
-
real = fs.realpathSync(out);
|
|
5790
|
-
const base = fs.realpathSync(path.join(ROOT, 'graphs'));
|
|
5791
|
-
if (!real.startsWith(base + path.sep) || !fs.statSync(real).isDirectory()) throw new Error('nope');
|
|
5792
|
-
} catch (_) {
|
|
5793
|
-
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
5794
|
-
return res.end('No graph yet — build one from the Graph menu on the project row.');
|
|
5795
|
-
}
|
|
5796
|
-
// Streamed straight from tar: a graph runs to tens of MB and buffering it would hold
|
|
5797
|
-
// the whole thing in the app's memory.
|
|
5798
|
-
const name = `${wsKey}--${project}--graph.tar.gz`;
|
|
5799
|
-
res.writeHead(200, {
|
|
5800
|
-
'Content-Type': 'application/gzip',
|
|
5801
|
-
'Content-Disposition': `attachment; filename="${name.replace(/[^A-Za-z0-9._-]/g, '_')}"`,
|
|
5802
|
-
'X-Content-Type-Options': 'nosniff',
|
|
5803
|
-
});
|
|
5804
|
-
const tar = spawn('tar', ['-czf', '-', '-C', path.dirname(real), path.basename(real)],
|
|
5805
|
-
{ stdio: ['ignore', 'pipe', 'pipe'] });
|
|
5806
|
-
tar.stdout.pipe(res);
|
|
5807
|
-
tar.stderr.resume();
|
|
5808
|
-
tar.on('error', () => { try { res.destroy(); } catch (_) { /* client gone */ } });
|
|
5809
|
-
res.on('close', () => { try { tar.kill(); } catch (_) { /* already exited */ } });
|
|
5810
|
-
return;
|
|
5811
|
-
}
|
|
5812
|
-
const graphMatch = pathname.match(/^\/graph\/([a-z0-9_-]+)\/([a-zA-Z0-9_\-]+)(\/report)?$/);
|
|
5813
|
-
if (graphMatch && isValidWorkspace(graphMatch[1])) {
|
|
5814
|
-
const wantsReport = !!graphMatch[3];
|
|
5815
|
-
const dir = path.join(ROOT, 'graphs');
|
|
5816
|
-
const file = path.join(graphStoreDir(graphMatch[1], graphMatch[2]),
|
|
5817
|
-
wantsReport ? 'GRAPH_REPORT.md' : 'graph.html');
|
|
5818
|
-
// Resolve symlinks before trusting the path: a project directory that
|
|
5819
|
-
// is a symlink would otherwise read outside the workspace, and this
|
|
5820
|
-
// container bind-mounts ~/.claude as well as ~/workspace.
|
|
5821
|
-
let real = null;
|
|
5822
|
-
try {
|
|
5823
|
-
const base = fs.realpathSync(dir);
|
|
5824
|
-
real = fs.realpathSync(file);
|
|
5825
|
-
if (real !== base && !real.startsWith(base + path.sep)) real = null;
|
|
5826
|
-
if (real && !fs.statSync(real).isFile()) real = null;
|
|
5827
|
-
} catch (_) { real = null; }
|
|
5828
|
-
if (!real) {
|
|
5829
|
-
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
|
|
5830
|
-
return res.end('No graph yet — press Graph on the project row to build one.');
|
|
5831
|
-
}
|
|
5832
|
-
// graph.html is generated from the project's own code: serve it with
|
|
5833
|
-
// scripts sandboxed away from this origin, and stream it (it runs to
|
|
5834
|
-
// tens of MB on a large codebase).
|
|
5835
|
-
res.writeHead(200, {
|
|
5836
|
-
'Content-Type': wantsReport ? 'text/plain; charset=utf-8' : 'text/html; charset=utf-8',
|
|
5837
|
-
'X-Content-Type-Options': 'nosniff',
|
|
5838
|
-
'Content-Security-Policy': 'sandbox allow-scripts allow-popups;',
|
|
5839
|
-
});
|
|
5840
|
-
return fs.createReadStream(real).pipe(res);
|
|
5841
|
-
}
|
|
5842
5647
|
const jobMatch = pathname.match(/^\/fragments\/job\/([a-z0-9-]+)$/);
|
|
5843
5648
|
if (jobMatch) {
|
|
5844
5649
|
const frag = jobFragment(jobMatch[1]);
|
|
@@ -6092,7 +5897,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
6092
5897
|
return res.end(made.html);
|
|
6093
5898
|
}
|
|
6094
5899
|
const newMatch = pathname.match(/^\/fragments\/([a-z0-9_-]+)\/new$/);
|
|
6095
|
-
if (newMatch && newMatch[1]
|
|
5900
|
+
if (newMatch && !(pluginWorkspaceView(newMatch[1]) || {}).noNewForm && isValidWorkspace(newMatch[1]) && loadWorkspaces()[newMatch[1]].kind === 'files') {
|
|
6096
5901
|
const key = newMatch[1];
|
|
6097
5902
|
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
6098
5903
|
return res.end(editorFormHtml(key, '', (ITEM_TEMPLATES[key] || ITEM_TEMPLATES.docs)('my-' + loadWorkspaces()[key].noun), true));
|
|
@@ -6534,10 +6339,6 @@ const server = http.createServer(async (req, res) => {
|
|
|
6534
6339
|
}
|
|
6535
6340
|
// The images public/ actually holds, as tiles. A settings value has to match a file
|
|
6536
6341
|
// exactly, so this shows what is there rather than asking you to remember a filename.
|
|
6537
|
-
if (pathname === '/fragments/graphs/list') {
|
|
6538
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
6539
|
-
return res.end(graphRowsHtml(readPageState(req)));
|
|
6540
|
-
}
|
|
6541
6342
|
if (pathname === '/fragments/jobs/inline') {
|
|
6542
6343
|
const rows = [...jobs.entries()].filter(([, j]) => !j.done && j.inline).map(([id, j]) => `
|
|
6543
6344
|
<div class="uk-flex uk-flex-middle uk-flex-between uk-margin-small-bottom">
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Feature: The actions rail
|
|
2
|
+
The rail on the right of every page collapses to its icons and remembers the choice.
|
|
3
|
+
|
|
4
|
+
# This exists because the feature was broken by having TWO of it. A delegated handler near the
|
|
5
|
+
# top of ui.js toggled the class and wrote `actions-collapsed`; a second implementation at
|
|
6
|
+
# the bottom, from another line of work, bound its own listener to the same button, read the
|
|
7
|
+
# already-toggled class and toggled it straight back. Every click undid itself a millisecond
|
|
8
|
+
# later, so the rail simply did not move. Nothing in the suite noticed, because nothing asserted
|
|
9
|
+
# what a click DOES — only that the button was on the page.
|
|
10
|
+
#
|
|
11
|
+
# So these assert the state after the click, in both directions, and that it is remembered.
|
|
12
|
+
|
|
13
|
+
Scenario: The rail starts collapsed, because the page wants the width more than the labels do
|
|
14
|
+
Given I am on "/dev"
|
|
15
|
+
Then the element "#actions-rail" should be displayed
|
|
16
|
+
And the element ".actions-toggle" should be displayed
|
|
17
|
+
And the element "html" with the attribute "class" and the value containing "actions-collapsed" should exist
|
|
18
|
+
And the element ".actions-toggle" with the attribute "aria-expanded" and the value "false" should exist
|
|
19
|
+
|
|
20
|
+
Scenario: Clicking the toggle expands it
|
|
21
|
+
Given I am on "/dev"
|
|
22
|
+
When I click on the element ".actions-toggle"
|
|
23
|
+
Then the element "html" with the attribute "class" and the value containing "actions-collapsed" should not exist
|
|
24
|
+
And the element ".actions-toggle" with the attribute "aria-expanded" and the value "true" should exist
|
|
25
|
+
And I should see "All workspaces"
|
|
26
|
+
|
|
27
|
+
Scenario: Clicking it again collapses it — the click is not undone by a second handler
|
|
28
|
+
Given I am on "/dev"
|
|
29
|
+
When I click on the element ".actions-toggle"
|
|
30
|
+
And I click on the element ".actions-toggle"
|
|
31
|
+
Then the element "html" with the attribute "class" and the value containing "actions-collapsed" should exist
|
|
32
|
+
And the element ".actions-toggle" with the attribute "aria-expanded" and the value "false" should exist
|
|
33
|
+
|
|
34
|
+
# A layout preference that resets on every navigation is one you set on every page.
|
|
35
|
+
Scenario: The choice survives a navigation
|
|
36
|
+
Given I am on "/dev"
|
|
37
|
+
When I click on the element ".actions-toggle"
|
|
38
|
+
And I am on "/settings"
|
|
39
|
+
Then the element "html" with the attribute "class" and the value containing "actions-collapsed" should not exist
|
|
40
|
+
|
|
41
|
+
Scenario: The rail is on the settings page too, not only on a workspace page
|
|
42
|
+
Given I am on "/settings"
|
|
43
|
+
Then the element "#actions-rail" should be displayed
|
|
44
|
+
And the element ".actions-toggle" should be displayed
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
Feature: Installing agents, skills and prompts
|
|
2
|
+
|
|
3
|
+
Scenario: An item can be installed into the global Claude Code, or into one project
|
|
4
|
+
Given I am on "/ai-agents"
|
|
5
|
+
Then "select[name='toWorkspace']" should be attached
|
|
6
|
+
And "select[name='toProject']" should be attached
|
|
7
|
+
And "[hx-post='/actions/install-item']" should be attached
|
|
8
|
+
|
|
9
|
+
# htmx 4 fires after:swap on the element that MADE the request, not on the one
|
|
10
|
+
# swapped — so a listener reading e.target saw the button and never opened the
|
|
11
|
+
# modal. The content had loaded; nothing appeared.
|
|
12
|
+
Scenario: Editing a prompt opens the editor with its text in it
|
|
13
|
+
Given I am on "/ai-prompts"
|
|
14
|
+
When I click on the element "[hx-get^='/fragments/ai-prompts/edit/'] >> nth=0"
|
|
15
|
+
Then "#editor-modal.uk-open" should be visible
|
|
16
|
+
And "#editor-modal .ace_editor" should be visible
|
|
17
|
+
And "#editor-modal form[hx-post='/actions/save-item']" should be attached
|
|
18
|
+
|
|
19
|
+
Scenario: The same Edit works on the agents workspace
|
|
20
|
+
Given I am on "/ai-agents"
|
|
21
|
+
When I click on the element "[hx-get^='/fragments/ai-agents/edit/'] >> nth=0"
|
|
22
|
+
Then "#editor-modal.uk-open" should be visible
|
|
23
|
+
And "#editor-modal .ace_editor" should be visible
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Feature: Talking to the assistant
|
|
2
|
+
The panel takes dictation and reads its answer back. Both are the browser's own — no key, no
|
|
3
|
+
service, nothing leaves the machine — so what is asserted here is that the component was actually
|
|
4
|
+
handed a working configuration, not that a remote service replied.
|
|
5
|
+
|
|
6
|
+
# Asserting the button EXISTS, not that speech works: a scenario cannot speak, and a browser will
|
|
7
|
+
# not grant a microphone to an automated run. What can go wrong without anyone noticing is the
|
|
8
|
+
# button being absent, or present with a config deep-chat silently ignored — so that is the target.
|
|
9
|
+
Scenario: The assistant offers a microphone
|
|
10
|
+
Given I am on "/"
|
|
11
|
+
Then "deep-chat" should be attached
|
|
12
|
+
And the assistant should offer voice input
|
|
13
|
+
And the assistant should read its replies aloud
|
|
14
|
+
|
|
15
|
+
# The microphone is what says voice is available. It used to be said in the placeholder as well
|
|
16
|
+
# ("Ask about dev… (or use voice)"), but the composer ships with no placeholder at all now: an
|
|
17
|
+
# empty field with a cursor in it already says "type here", and a prompt that suggests what to ask
|
|
18
|
+
# narrows what gets asked. So the button has to be there AND have a name — an icon-only control
|
|
19
|
+
# with no accessible name is a button a screen reader announces as nothing.
|
|
20
|
+
Scenario: The microphone is there, and it is named
|
|
21
|
+
Given I am on "/"
|
|
22
|
+
Then the assistant should show a named microphone button
|
|
23
|
+
|
|
24
|
+
# Nothing drawn in the box, and the box still has a name. These are one scenario because they are
|
|
25
|
+
# in tension: deep-chat resolves the placeholder as `text || "Ask me anything!"`, so an empty
|
|
26
|
+
# string does not remove its placeholder, it restores deep-chat's — and the text it is given also
|
|
27
|
+
# becomes the composer's aria-label. Removing what is drawn without removing the name is the whole
|
|
28
|
+
# trick, and either half alone is a bug.
|
|
29
|
+
Scenario: The composer shows no placeholder, and is still named
|
|
30
|
+
Given I am on "/"
|
|
31
|
+
Then the assistant composer should draw no placeholder
|
|
32
|
+
And the assistant composer should have an accessible name
|
|
33
|
+
|
|
34
|
+
# The recogniser's language is the setting that decides whether dictation works in a second
|
|
35
|
+
# language at all: left on the wrong one it does not fail, it returns confident nonsense. So a
|
|
36
|
+
# language is always pinned rather than inherited — en-US ships, and the dropdown offers the rest.
|
|
37
|
+
Scenario: A dictation language is always pinned, never left to chance
|
|
38
|
+
Given I am on "/"
|
|
39
|
+
Then the assistant speech language should be pinned
|
|
40
|
+
|
|
41
|
+
# An empty phrase is not a disabled command. If `commands` were built from blank strings, a
|
|
42
|
+
# command could fire on almost anything dictated — so with none configured the key must be absent.
|
|
43
|
+
Scenario: No voice commands are armed unless one is configured
|
|
44
|
+
Given I am on "/"
|
|
45
|
+
Then the assistant should have no voice commands
|
|
46
|
+
|
|
47
|
+
Scenario: Voice styling follows the theme rather than deep-chat's stock colours
|
|
48
|
+
Given I am on "/"
|
|
49
|
+
Then the assistant speech colours should be design tokens
|
|
50
|
+
|
|
51
|
+
# The panel is on every workspace page, not only the home page, and its context travels with it.
|
|
52
|
+
Scenario: A workspace page gets the same microphone
|
|
53
|
+
Given I am on "/dev"
|
|
54
|
+
Then "deep-chat" should be attached
|
|
55
|
+
And the assistant should offer voice input
|
|
56
|
+
|
|
57
|
+
# A browser with no synthesis voices accepts speak(), fires error: synthesis-failed, and is silent.
|
|
58
|
+
# Nothing reported it, so "read replies aloud" looked switched on and did nothing at all — the worst
|
|
59
|
+
# state a setting can be in.
|
|
60
|
+
Scenario: The settings page says which voices this browser actually has
|
|
61
|
+
Given I am on "/settings"
|
|
62
|
+
Then "[data-voice-name]" should be attached
|
|
63
|
+
And the voice list should report what this browser has
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Feature: The checks a project already declares
|
|
2
|
+
Every package here carries its own quality scripts. The dashboard offers them without inventing any.
|
|
3
|
+
|
|
4
|
+
# One quality menu, not two. On a packages workspace there is no browser suite at all, and on a
|
|
5
|
+
# site there was no checks control — a separate button would have been the only one present in
|
|
6
|
+
# each case. They live together under Tests, with the checks nested inside it.
|
|
7
|
+
Scenario: A package row offers its checks inside the Tests menu
|
|
8
|
+
Given I am on "/products"
|
|
9
|
+
Then the element ".project-row .act-menu-tests" should be displayed
|
|
10
|
+
And ".act-menu-tests .act-menu-checks" should be attached
|
|
11
|
+
And I should see "Tests"
|
|
12
|
+
|
|
13
|
+
Scenario: The button says what the package covers without running anything
|
|
14
|
+
Given I am on "/products"
|
|
15
|
+
Then the element ".act-menu-tests + .act-status" should be displayed
|
|
16
|
+
And "[hx-post='/actions/checks-plan']" should be attached
|
|
17
|
+
|
|
18
|
+
# The pair is the point: the canonical name is what you type (--only js), the code beside it is
|
|
19
|
+
# the script the package itself declared. Listing them together is how the mapping is checkable.
|
|
20
|
+
Scenario: The nested menu lists each alias against the script it runs
|
|
21
|
+
Given I am on "/products"
|
|
22
|
+
Then ".checks-sub" should be attached
|
|
23
|
+
And ".checks-sub .checks-alias" should be attached
|
|
24
|
+
And ".checks-sub .checks-script" should be attached
|
|
25
|
+
|
|
26
|
+
@needs-check-aliases
|
|
27
|
+
Scenario: Each alias can be run on its own, and so can all of them
|
|
28
|
+
Given I am on "/products"
|
|
29
|
+
Then "[hx-post='/actions/checks']" should be attached
|
|
30
|
+
And "[hx-vals*='only']" should be attached
|
|
31
|
+
|
|
32
|
+
# A site gets the same nested list: its package.json declares the same vocabulary, and its
|
|
33
|
+
# ddev-dev-tools add-on adds the PHP and Twig checks on top.
|
|
34
|
+
Scenario: A site keeps its testing verbs and gains the checks beside them
|
|
35
|
+
Given I am on "/dev"
|
|
36
|
+
Then the element ".project-row .act-menu-tests" should be displayed
|
|
37
|
+
And "[hx-post='/actions/testing-configure']" should be attached
|
|
38
|
+
And "[hx-post='/actions/testing-run']" should be attached
|
|
39
|
+
And ".act-menu-tests .act-menu-checks" should be attached
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Feature: Cloning a project
|
|
2
|
+
The clone modal validates before anything runs, and never clones over an
|
|
3
|
+
existing project or a name DDEV already tracks.
|
|
4
|
+
|
|
5
|
+
Scenario: The DDEV menu offers the clone
|
|
6
|
+
Given I am on "/dev"
|
|
7
|
+
Then "[hx-get^='/fragments/projects/clone-form/dev/']" should be attached
|
|
8
|
+
|
|
9
|
+
Scenario: The form arrives prefilled, with the live check wired
|
|
10
|
+
Given I am on "/fragments/projects/clone-form/dev/v11x00b1i18n"
|
|
11
|
+
Then "input[name='to'][value='v11x00b1i18n-copy']" should be attached
|
|
12
|
+
And "select[name='toWorkspace']" should be attached
|
|
13
|
+
And "[hx-get='/fragments/projects/clone-check']" should be attached
|
|
14
|
+
And "textarea[name='prompt']" should be attached
|
|
15
|
+
|
|
16
|
+
Scenario: The live check refuses an existing project
|
|
17
|
+
Given I am on "/fragments/projects/clone-check?to=v11x00b1i18n&toWorkspace=dev"
|
|
18
|
+
Then I should see "already exists"
|
|
19
|
+
|
|
20
|
+
Scenario: The live check blesses a free name
|
|
21
|
+
Given I am on "/fragments/projects/clone-check?to=surely-free-name-zz&toWorkspace=dev"
|
|
22
|
+
Then I should see "is free"
|
|
23
|
+
|
|
24
|
+
Scenario: Cloning over an existing project is refused server-side too
|
|
25
|
+
When I post "/actions/clone-project" with '{"workspace":"dev","projectName":"v11x00b1i18n","to":"v11x00b1i18n","toWorkspace":"dev"}'
|
|
26
|
+
Then the action response should contain "already exists"
|
|
27
|
+
|
|
28
|
+
Scenario: A source that does not exist is refused
|
|
29
|
+
When I post "/actions/clone-project" with '{"workspace":"dev","projectName":"no-such-src","to":"whatever-zz","toWorkspace":"dev"}'
|
|
30
|
+
Then the action response should contain "Project not found"
|