@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,676 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Structured-Prompt-Driven Development (martinfowler.com/articles/structured-prompt-driven) for
|
|
4
|
+
# this workspace: the prompt for a change is an artifact that is written, reviewed, versioned and
|
|
5
|
+
# kept in sync with the code — not something typed into a chat and lost.
|
|
6
|
+
#
|
|
7
|
+
# One spec is a directory:
|
|
8
|
+
#
|
|
9
|
+
# specs/<workspace>/<project>/NNN-topic/
|
|
10
|
+
# 01-story.md the ask: problem, definition of done, acceptance criteria
|
|
11
|
+
# 02-analysis.md what already exists, what it touches, what could go wrong
|
|
12
|
+
# 03-canvas.md the REASONS Canvas — the contract the change is generated from
|
|
13
|
+
# 04-tests.md what proves it works
|
|
14
|
+
# spec.yml stage, links, and the commit the canvas was last true for
|
|
15
|
+
#
|
|
16
|
+
# The stages are gates, not decoration: analysis needs a story, a canvas needs an analysis. Each
|
|
17
|
+
# one is a file a person reads and edits before the next one is asked for — which is the whole
|
|
18
|
+
# method. The AI writes drafts; the gate is a human deciding the draft is right.
|
|
19
|
+
#
|
|
20
|
+
# THE RULE, from the article and enforced by `-a drift`: when reality diverges, fix the prompt
|
|
21
|
+
# first, then the code. A canvas that no longer describes the tree is worse than no canvas — it is
|
|
22
|
+
# a document people trust.
|
|
23
|
+
#
|
|
24
|
+
# What makes this workspace a good host for the method: SPDD's weakest step is analysis ("scan the
|
|
25
|
+
# codebase"). Here a project may already have a graphify knowledge graph (structure) and a Milvus
|
|
26
|
+
# RAG index (its prose, templates and configuration), and `spdd_context` feeds both into the
|
|
27
|
+
# analysis rather than asking a model to guess.
|
|
28
|
+
|
|
29
|
+
SPDD_STAGES="story analysis canvas tests done";
|
|
30
|
+
|
|
31
|
+
# Where the specs live. Outside every project, like the graphs store, and for the same reason:
|
|
32
|
+
# a repository we ship must not gain a spec directory because somebody planned a change to it.
|
|
33
|
+
function spdd_root() {
|
|
34
|
+
printf '%s/specs' "${WORKSPACE_ROOT}";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# specs/<workspace>/<project> — the target a spec is about. A spec for the tooling itself uses the
|
|
38
|
+
# `workspace` pseudo-project, which is the one case where the target is not a built site.
|
|
39
|
+
function spdd_target_dir() {
|
|
40
|
+
printf '%s/%s' "$(spdd_root)" "$1";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# A slug that is safe as a directory name and still readable a month later.
|
|
44
|
+
function spdd_slug() {
|
|
45
|
+
printf '%s' "$1" | tr '[:upper:]' '[:lower:]' | sed -e 's/[^a-z0-9]\+/-/g' -e 's/^-//' -e 's/-$//' | cut -c1-48 ;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
# The next spec number for a target, zero-padded. Per target rather than global: the numbers are
|
|
49
|
+
# for reading, and "the third change to website_starter" is more useful than "the 47th spec".
|
|
50
|
+
function spdd_next_number() {
|
|
51
|
+
local dir="$1" last;
|
|
52
|
+
last="$(ls -1 "${dir}" 2>/dev/null | sed -n 's/^\([0-9]\{3\}\)-.*$/\1/p' | sort -n | tail -1)";
|
|
53
|
+
printf '%03d' "$(( 10#${last:-0} + 1 ))";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# Resolve a spec by number, slug, or <workspace>/<project>/NNN-slug. Ambiguity is refused rather
|
|
57
|
+
# than guessed: the next command writes into whatever this returns.
|
|
58
|
+
function spdd_resolve() {
|
|
59
|
+
local wanted="$1" base matches;
|
|
60
|
+
base="$(spdd_root)";
|
|
61
|
+
[ -d "${base}" ] || return 0 ;
|
|
62
|
+
case "${wanted}" in
|
|
63
|
+
*..*) return 0 ;;
|
|
64
|
+
*/*/*) [ -d "${base}/${wanted}" ] && printf '%s' "${base}/${wanted}" ; return 0 ;;
|
|
65
|
+
esac
|
|
66
|
+
matches="$(find "${base}" -mindepth 3 -maxdepth 3 -type d \( -name "${wanted}" -o -name "${wanted}-*" -o -name "*-${wanted}" \) 2>/dev/null | sort)";
|
|
67
|
+
printf '%s' "${matches}";
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function spdd_stage_of() {
|
|
71
|
+
local spec="$1";
|
|
72
|
+
sed -n 's/^stage:[[:space:]]*\([a-z]*\).*/\1/p' "${spec}/spec.yml" 2>/dev/null | head -1 ;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function spdd_field() {
|
|
76
|
+
sed -n "s/^$2:[[:space:]]*//p" "$1/spec.yml" 2>/dev/null | head -1 ;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function spdd_set_field() {
|
|
80
|
+
local spec="$1" field="$2" value="$3" tmp;
|
|
81
|
+
tmp="$(mktemp)";
|
|
82
|
+
if grep -q "^${field}:" "${spec}/spec.yml" 2>/dev/null ; then
|
|
83
|
+
sed "s|^${field}:.*|${field}: ${value}|" "${spec}/spec.yml" > "${tmp}" && mv "${tmp}" "${spec}/spec.yml" ;
|
|
84
|
+
else
|
|
85
|
+
cp "${spec}/spec.yml" "${tmp}" 2>/dev/null ; printf '%s: %s\n' "${field}" "${value}" >> "${tmp}" ; mv "${tmp}" "${spec}/spec.yml" ;
|
|
86
|
+
fi
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# The governance block every generated artifact is written against, straight out of
|
|
90
|
+
# core/config/norms.yml so a rule is stated once.
|
|
91
|
+
function spdd_norms_block() {
|
|
92
|
+
local file="${WORKSPACE_CONFIG}/norms.yml";
|
|
93
|
+
if [ ! -f "${file}" ] ; then
|
|
94
|
+
echo "(core/config/norms.yml is missing — the change has no stated norms or safeguards.)";
|
|
95
|
+
return 0 ;
|
|
96
|
+
fi
|
|
97
|
+
cat "${file}";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
# What the model is allowed to know about the target before it writes anything.
|
|
101
|
+
#
|
|
102
|
+
# Deterministic sources first, and clearly labelled: the graph is structure, the index is prose,
|
|
103
|
+
# and the tree listing is what actually exists. A model told "here is the structure" invents less
|
|
104
|
+
# than one told "figure out the structure".
|
|
105
|
+
function spdd_context() {
|
|
106
|
+
local target="$1" workspace project project_path graph;
|
|
107
|
+
workspace="${target%%/*}";
|
|
108
|
+
project="${target##*/}";
|
|
109
|
+
project_path="${WORKSPACE_ROOT}/${workspace}/${project}";
|
|
110
|
+
|
|
111
|
+
echo "## The target";
|
|
112
|
+
echo "";
|
|
113
|
+
echo "${target} (${project_path})";
|
|
114
|
+
echo "";
|
|
115
|
+
|
|
116
|
+
if [ -d "${project_path}" ] ; then
|
|
117
|
+
echo "### Top-level layout";
|
|
118
|
+
echo '```';
|
|
119
|
+
ls -1 "${project_path}" 2>/dev/null | head -40 ;
|
|
120
|
+
echo '```';
|
|
121
|
+
echo "";
|
|
122
|
+
fi
|
|
123
|
+
|
|
124
|
+
graph="${WORKSPACE_ROOT}/graphs/${workspace}/${project}/graph.json";
|
|
125
|
+
if [ -f "${graph}" ] ; then
|
|
126
|
+
echo "### Structure (graphify knowledge graph)";
|
|
127
|
+
echo "";
|
|
128
|
+
echo "A graph exists at ${graph}. It maps PHP classes under src/, JS and SQL — NOT hooks in";
|
|
129
|
+
echo "*.module/*.install, NOT Twig, NOT any *.yml. Query it with:";
|
|
130
|
+
echo '```';
|
|
131
|
+
echo "graphify query \"...\" --graph ${graph}";
|
|
132
|
+
echo '```';
|
|
133
|
+
echo "";
|
|
134
|
+
fi
|
|
135
|
+
|
|
136
|
+
# The RAG index covers exactly what the graph does not: prose, templates and configuration.
|
|
137
|
+
# It is an enrichment, not a dependency: this workspace has no rag workspace yet, so the block
|
|
138
|
+
# is skipped unless those functions are loaded. Checked explicitly rather than relying on the
|
|
139
|
+
# errors being swallowed, so a missing index is a skipped section and not a hidden failure.
|
|
140
|
+
if declare -f rag_resolve_instance > /dev/null 2>&1 \
|
|
141
|
+
&& command -v docker > /dev/null 2>&1 && [ -n "${SPDD_QUERY}" ] ; then
|
|
142
|
+
local instance uri collection hits;
|
|
143
|
+
instance="$(rag_resolve_instance "${workspace}" "${project}" '_settings_' 2>/dev/null)";
|
|
144
|
+
if [ -n "${instance}" ] && docker ps --format '{{.Names}}' 2>/dev/null | grep -qx "ddev-${instance}-milvus-standalone" ; then
|
|
145
|
+
collection="$(rag_collection_name "${workspace}" "${project}")";
|
|
146
|
+
local doc_name_saved="${doc_name}"; doc_name="rag";
|
|
147
|
+
uri="$(milvus_uri "${instance}")";
|
|
148
|
+
doc_name="${doc_name_saved}";
|
|
149
|
+
hits="$(rag_python --uri "${uri}" --token "$(milvus_token)" search --collection "${collection}" \
|
|
150
|
+
--query "${SPDD_QUERY}" --limit 6 --context 14 2>/dev/null)";
|
|
151
|
+
if [ -n "${hits}" ] ; then
|
|
152
|
+
echo "### What the tree already says about this (RAG index, BM25)";
|
|
153
|
+
echo '```';
|
|
154
|
+
printf '%s\n' "${hits}";
|
|
155
|
+
echo '```';
|
|
156
|
+
echo "";
|
|
157
|
+
fi
|
|
158
|
+
fi
|
|
159
|
+
fi
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
# Ask the Claude Code CLI for a draft, with the prompt on STDIN.
|
|
163
|
+
#
|
|
164
|
+
# Printed rather than run when the CLI is missing: a draft nobody can reproduce is not an
|
|
165
|
+
# artifact, and the point of the method is that the prompt is the thing you keep.
|
|
166
|
+
function spdd_draft() {
|
|
167
|
+
local outfile="$1" title="$2";
|
|
168
|
+
if ! command -v claude > /dev/null 2>&1 ; then
|
|
169
|
+
echo "The claude CLI is not on PATH — writing the prompt to ${outfile}.prompt instead.";
|
|
170
|
+
cat > "${outfile}.prompt";
|
|
171
|
+
echo "Run it yourself with: claude -p \"\$(cat ${outfile}.prompt)\" > ${outfile}";
|
|
172
|
+
return 1 ;
|
|
173
|
+
fi
|
|
174
|
+
echo "Drafting ${title} — this calls the local Claude Code CLI and takes a minute.";
|
|
175
|
+
# Tool-free print mode: this step writes a document, and a step that could also edit the tree
|
|
176
|
+
# would blur which artifact the change came from.
|
|
177
|
+
claude -p --allowed-tools "" > "${outfile}" || return 1 ;
|
|
178
|
+
[ -s "${outfile}" ] || { echo "The draft came back empty — nothing written."; rm -f "${outfile}"; return 1 ; }
|
|
179
|
+
return 0 ;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
# ---------------------------------------------------------------------------
|
|
183
|
+
# The stages. Each one refuses to run until the one before it exists, because a
|
|
184
|
+
# canvas written from an unread analysis is the failure the method exists to prevent.
|
|
185
|
+
# ---------------------------------------------------------------------------
|
|
186
|
+
|
|
187
|
+
# Stage 1 — the story. Written by hand from a sentence, not by a model: the ask is the one thing
|
|
188
|
+
# nobody should be generating.
|
|
189
|
+
function spdd_story() {
|
|
190
|
+
local target="${TARGET}" topic="${TOPIC}" dir slug number spec;
|
|
191
|
+
if [ "${topic}" == '_none_' ] || [ -z "${topic}" ] ; then
|
|
192
|
+
echo "Say what the change is: bash cmd-spdd.sh ${target} \"index a project into Milvus\"";
|
|
193
|
+
return 1 ;
|
|
194
|
+
fi
|
|
195
|
+
case "${target}" in
|
|
196
|
+
*/*) : ;;
|
|
197
|
+
*) echo "The target is <workspace>/<project>, e.g. products/webship_core or dev/myproject." ; return 1 ;;
|
|
198
|
+
esac
|
|
199
|
+
|
|
200
|
+
dir="$(spdd_target_dir "${target}")";
|
|
201
|
+
mkdir -p "${dir}" ;
|
|
202
|
+
slug="$(spdd_slug "${topic}")";
|
|
203
|
+
number="$(spdd_next_number "${dir}")";
|
|
204
|
+
spec="${dir}/${number}-${slug}";
|
|
205
|
+
|
|
206
|
+
if [ -d "${spec}" ] ; then
|
|
207
|
+
echo "${spec} already exists.";
|
|
208
|
+
return 1 ;
|
|
209
|
+
fi
|
|
210
|
+
mkdir -p "${spec}" ;
|
|
211
|
+
|
|
212
|
+
cat > "${spec}/spec.yml" <<YMLEOF
|
|
213
|
+
# What this spec is about, and how far it has got. Written by cmd-spdd.sh; edit by hand freely.
|
|
214
|
+
target: ${target}
|
|
215
|
+
topic: ${topic}
|
|
216
|
+
stage: story
|
|
217
|
+
created: $(date +%Y-%m-%d)
|
|
218
|
+
# The commit of the target the canvas was last true for; -a drift compares against it.
|
|
219
|
+
# (No backticks in this heredoc: it interpolates \${target}, so a backtick would run as a command.)
|
|
220
|
+
synced_commit:
|
|
221
|
+
# Fill these in when they exist, so a merged change can be traced back to the prompt it came from.
|
|
222
|
+
issue:
|
|
223
|
+
pull_request:
|
|
224
|
+
YMLEOF
|
|
225
|
+
|
|
226
|
+
cat > "${spec}/01-story.md" <<STORYEOF
|
|
227
|
+
# ${topic}
|
|
228
|
+
|
|
229
|
+
## Problem / motivation
|
|
230
|
+
|
|
231
|
+
<!-- What is wrong or missing today, for whom, and why it is worth doing. Write it as if the
|
|
232
|
+
reader has not been in the conversation this came from — in six months that reader is you. -->
|
|
233
|
+
|
|
234
|
+
## Scope
|
|
235
|
+
|
|
236
|
+
**In:**
|
|
237
|
+
-
|
|
238
|
+
|
|
239
|
+
**Out:**
|
|
240
|
+
-
|
|
241
|
+
|
|
242
|
+
## Definition of done
|
|
243
|
+
|
|
244
|
+
<!-- Observable outcomes, not tasks. "The dashboard row shows the bound server" — not
|
|
245
|
+
"add a badge". Each of these becomes an acceptance criterion the Canvas maps operations to. -->
|
|
246
|
+
- [ ]
|
|
247
|
+
- [ ]
|
|
248
|
+
|
|
249
|
+
## Acceptance criteria
|
|
250
|
+
|
|
251
|
+
| # | Given | When | Then |
|
|
252
|
+
| - | ----- | ---- | ---- |
|
|
253
|
+
| 1 | | | |
|
|
254
|
+
STORYEOF
|
|
255
|
+
|
|
256
|
+
echo "";
|
|
257
|
+
echo "*---------------------------------------------------------------------*";
|
|
258
|
+
echo " Spec ${number}-${slug} started for ${target}.";
|
|
259
|
+
echo "";
|
|
260
|
+
echo " ${spec}/01-story.md";
|
|
261
|
+
echo "";
|
|
262
|
+
echo " Write the story yourself — the ask is the one artifact nobody should generate.";
|
|
263
|
+
echo " Then: bash cmd-spdd.sh ${target}/${number}-${slug} -a analysis";
|
|
264
|
+
echo "*---------------------------------------------------------------------*";
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
# Stage 2 — the analysis. What already exists, what this touches, what could go wrong. Seeded with
|
|
268
|
+
# the graph and the RAG index rather than with a model's memory of the tree.
|
|
269
|
+
function spdd_analysis() {
|
|
270
|
+
local spec="$1" target stage;
|
|
271
|
+
target="$(spdd_field "${spec}" target)";
|
|
272
|
+
stage="$(spdd_stage_of "${spec}")";
|
|
273
|
+
[ -s "${spec}/01-story.md" ] || { echo "No story yet in ${spec}." ; return 1 ; }
|
|
274
|
+
if grep -q '^## Problem / motivation$' "${spec}/01-story.md" && ! grep -qv '^\s*\(#\|<!--\|-\||\|\[\|$\)' "${spec}/01-story.md" ; then
|
|
275
|
+
echo "01-story.md is still the empty template — write the ask before asking for an analysis.";
|
|
276
|
+
return 1 ;
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
SPDD_QUERY="$(spdd_field "${spec}" topic)";
|
|
280
|
+
{
|
|
281
|
+
echo "You are analysing a proposed change to the Webship Workspace, a DDEV-only Drupal";
|
|
282
|
+
echo "development harness. Produce ONLY a markdown analysis document — no preamble, no code.";
|
|
283
|
+
echo "";
|
|
284
|
+
echo "Write these sections, and nothing else:";
|
|
285
|
+
echo " ## What exists today — what is already there that this change touches or duplicates.";
|
|
286
|
+
echo " ## Domain vocabulary — the words this change is about, as this codebase uses them.";
|
|
287
|
+
echo " ## What it touches — files, commands and settings, as a list, with why each.";
|
|
288
|
+
echo " ## Risks — what could break, and what is easy to get subtly wrong.";
|
|
289
|
+
echo " ## Open questions — what a person must decide before a design is possible.";
|
|
290
|
+
echo "";
|
|
291
|
+
echo "State plainly when the provided context does not answer something. Do not invent a file";
|
|
292
|
+
echo "path, a function name or a command that is not shown to you.";
|
|
293
|
+
echo "";
|
|
294
|
+
echo "# The ask";
|
|
295
|
+
echo "";
|
|
296
|
+
cat "${spec}/01-story.md";
|
|
297
|
+
echo "";
|
|
298
|
+
spdd_context "${target}";
|
|
299
|
+
echo "# The rules this workspace holds to";
|
|
300
|
+
echo "";
|
|
301
|
+
spdd_norms_block;
|
|
302
|
+
} | spdd_draft "${spec}/02-analysis.md" "the analysis" || return 1 ;
|
|
303
|
+
|
|
304
|
+
spdd_set_field "${spec}" stage analysis ;
|
|
305
|
+
echo "";
|
|
306
|
+
echo " Read and correct ${spec}/02-analysis.md — it is the input to the contract.";
|
|
307
|
+
echo " Then: bash cmd-spdd.sh $(spdd_field "${spec}" target)/$(basename "${spec}") -a canvas";
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
# Stage 3 — the REASONS Canvas. The contract: requirements, entities, approach, structure,
|
|
311
|
+
# operations, norms, safeguards. Everything after this is generated FROM it.
|
|
312
|
+
function spdd_canvas() {
|
|
313
|
+
local spec="$1" target;
|
|
314
|
+
target="$(spdd_field "${spec}" target)";
|
|
315
|
+
[ -s "${spec}/02-analysis.md" ] || { echo "No analysis yet — run -a analysis first." ; return 1 ; }
|
|
316
|
+
|
|
317
|
+
SPDD_QUERY="$(spdd_field "${spec}" topic)";
|
|
318
|
+
{
|
|
319
|
+
echo "Write a REASONS Canvas for this change: the contract an implementation is generated from.";
|
|
320
|
+
echo "Output ONLY the markdown document, starting at '# REASONS Canvas —'.";
|
|
321
|
+
echo "";
|
|
322
|
+
echo "Sections, in this order, each a '## ' heading:";
|
|
323
|
+
echo " ## R — Requirements the why, the scope boundary, and the definition of done";
|
|
324
|
+
echo " ## E — Entities the things involved and how they relate (a mermaid classDiagram";
|
|
325
|
+
echo " when there is real structure; a table when there is not)";
|
|
326
|
+
echo " ## A — Approach the strategy chosen, and what was rejected and why";
|
|
327
|
+
echo " ## S — Structure which files, commands and settings, and how they fit what exists";
|
|
328
|
+
echo " ## O — Operations ordered, individually reviewable steps. Each names the file it";
|
|
329
|
+
echo " touches and states how it is verified. No step may be 'and so on'.";
|
|
330
|
+
echo " ## N — Norms the standards below, as they apply HERE — not copied verbatim";
|
|
331
|
+
echo " ## S — Safeguards the boundaries below, as they apply HERE, plus any specific to";
|
|
332
|
+
echo " this change (what must not be deleted, what must stay reversible)";
|
|
333
|
+
echo "";
|
|
334
|
+
echo "Rules for you: every operation must trace to a definition-of-done item. If the analysis";
|
|
335
|
+
echo "leaves a question open, say so in Requirements as an assumption rather than inventing an";
|
|
336
|
+
echo "answer. Do not write an operation the analysis gives you no evidence is possible.";
|
|
337
|
+
echo "";
|
|
338
|
+
echo "# The ask";
|
|
339
|
+
echo "";
|
|
340
|
+
cat "${spec}/01-story.md";
|
|
341
|
+
echo "";
|
|
342
|
+
echo "# The analysis (already reviewed by a person)";
|
|
343
|
+
echo "";
|
|
344
|
+
cat "${spec}/02-analysis.md";
|
|
345
|
+
echo "";
|
|
346
|
+
spdd_context "${target}";
|
|
347
|
+
echo "# The rules this workspace holds to";
|
|
348
|
+
echo "";
|
|
349
|
+
spdd_norms_block;
|
|
350
|
+
} | spdd_draft "${spec}/03-canvas.md" "the REASONS Canvas" || return 1 ;
|
|
351
|
+
|
|
352
|
+
spdd_set_field "${spec}" stage canvas ;
|
|
353
|
+
spdd_set_field "${spec}" synced_commit "$(spdd_head_of "${target}")" ;
|
|
354
|
+
echo "";
|
|
355
|
+
echo " Review ${spec}/03-canvas.md as a contract, not a draft: the operations are what gets built.";
|
|
356
|
+
echo " Then implement it — by hand, or by giving the canvas to a session:";
|
|
357
|
+
echo " claude \"Implement the operations in $(basename "${spec}")/03-canvas.md, one at a time.\"";
|
|
358
|
+
echo " And when the code and the canvas diverge: -a drift then -a sync";
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
# The commit a target is at, when it is a git repository. A built Drupal site is not one, and that
|
|
362
|
+
# is fine — drift detection simply has nothing to compare and says so.
|
|
363
|
+
function spdd_head_of() {
|
|
364
|
+
local target="$1" path;
|
|
365
|
+
path="${WORKSPACE_ROOT}/${target}";
|
|
366
|
+
git -C "${path}" rev-parse --short HEAD 2>/dev/null;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
# Has the tree moved since the canvas was written? THE rule of the method is "fix the prompt
|
|
370
|
+
# first", and this is the only part of it a script can do: notice, and refuse to be quiet.
|
|
371
|
+
function spdd_drift() {
|
|
372
|
+
local spec="$1" target synced now;
|
|
373
|
+
target="$(spdd_field "${spec}" target)";
|
|
374
|
+
synced="$(spdd_field "${spec}" synced_commit)";
|
|
375
|
+
now="$(spdd_head_of "${target}")";
|
|
376
|
+
|
|
377
|
+
echo "";
|
|
378
|
+
echo " spec: $(basename "${spec}")";
|
|
379
|
+
echo " target: ${target}";
|
|
380
|
+
if [ -z "${now}" ] ; then
|
|
381
|
+
echo " status: the target is not a git repository — drift cannot be measured here.";
|
|
382
|
+
echo " Re-read the canvas against the tree yourself before trusting it.";
|
|
383
|
+
return 0 ;
|
|
384
|
+
fi
|
|
385
|
+
if [ -z "${synced}" ] ; then
|
|
386
|
+
echo " status: no synced commit recorded. Set it once the canvas matches the tree:";
|
|
387
|
+
echo " bash cmd-spdd.sh $(basename "${spec}") -a sync";
|
|
388
|
+
return 0 ;
|
|
389
|
+
fi
|
|
390
|
+
if [ "${synced}" == "${now}" ] ; then
|
|
391
|
+
echo " status: in sync at ${now}.";
|
|
392
|
+
return 0 ;
|
|
393
|
+
fi
|
|
394
|
+
echo " status: DRIFTED — canvas is true for ${synced}, the target is at ${now}.";
|
|
395
|
+
echo "";
|
|
396
|
+
git -C "${WORKSPACE_ROOT}/${target}" log --oneline "${synced}..${now}" 2>/dev/null | head -10 ;
|
|
397
|
+
echo "";
|
|
398
|
+
echo " Fix the PROMPT first, then the code:";
|
|
399
|
+
echo " 1. edit 03-canvas.md so it describes what is now true";
|
|
400
|
+
echo " 2. bash cmd-spdd.sh $(basename "${spec}") -a sync";
|
|
401
|
+
return 1 ;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
# Record that the canvas has been made true again. Deliberately a separate, explicit act: a script
|
|
405
|
+
# that stamped this automatically would be recording an opinion nobody formed.
|
|
406
|
+
function spdd_sync() {
|
|
407
|
+
local spec="$1" target now;
|
|
408
|
+
target="$(spdd_field "${spec}" target)";
|
|
409
|
+
now="$(spdd_head_of "${target}")";
|
|
410
|
+
if [ -z "${now}" ] ; then
|
|
411
|
+
echo "The target is not a git repository — nothing to stamp.";
|
|
412
|
+
return 1 ;
|
|
413
|
+
fi
|
|
414
|
+
spdd_set_field "${spec}" synced_commit "${now}" ;
|
|
415
|
+
echo "$(basename "${spec}") is recorded as true for ${target} at ${now}.";
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
function spdd_list() {
|
|
419
|
+
local base spec target stage topic;
|
|
420
|
+
base="$(spdd_root)";
|
|
421
|
+
if [ -z "$(find "${base}" -mindepth 3 -maxdepth 3 -type d 2>/dev/null)" ] ; then
|
|
422
|
+
echo "No specs yet. Start one from its target's workspace:";
|
|
423
|
+
echo " cd ${WORKSPACE_ROOT}/specs && bash cmd-spdd.sh <workspace>/<project> \"what the change is\"";
|
|
424
|
+
return 0 ;
|
|
425
|
+
fi
|
|
426
|
+
printf '%-34s %-26s %-9s %s\n' "SPEC" "TARGET" "STAGE" "TOPIC";
|
|
427
|
+
while read -r spec ; do
|
|
428
|
+
[ -n "${spec}" ] || continue ;
|
|
429
|
+
target="$(spdd_field "${spec}" target)";
|
|
430
|
+
stage="$(spdd_stage_of "${spec}")";
|
|
431
|
+
topic="$(spdd_field "${spec}" topic)";
|
|
432
|
+
printf '%-34s %-26s %-9s %s\n' "$(basename "${spec}")" "${target}" "${stage:-?}" "${topic}";
|
|
433
|
+
done <<< "$(find "${base}" -mindepth 3 -maxdepth 3 -type d 2>/dev/null | sort)"
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
# One spec, or a sentence saying why not. Sets SPDD_SPEC.
|
|
437
|
+
function spdd_require_spec() {
|
|
438
|
+
local matches count;
|
|
439
|
+
if [ "${SPEC_NAME}" == '_all_' ] || [ -z "${SPEC_NAME}" ] ; then
|
|
440
|
+
echo "Name the spec: bash cmd-spdd.sh <spec> -a ${SPDD_ACTION} ( -a list shows them )";
|
|
441
|
+
return 1 ;
|
|
442
|
+
fi
|
|
443
|
+
matches="$(spdd_resolve "${SPEC_NAME}")";
|
|
444
|
+
count="$(printf '%s' "${matches}" | grep -c . )";
|
|
445
|
+
if [ "${count}" -eq 0 ] ; then echo "No spec matches '${SPEC_NAME}'." ; return 1 ; fi
|
|
446
|
+
if [ "${count}" -gt 1 ] ; then
|
|
447
|
+
echo "'${SPEC_NAME}' matches ${count} specs — name the target too:";
|
|
448
|
+
while read -r m ; do printf ' %s\n' "${m#$(spdd_root)/}" ; done <<< "${matches}"
|
|
449
|
+
return 1 ;
|
|
450
|
+
fi
|
|
451
|
+
SPDD_SPEC="${matches}";
|
|
452
|
+
return 0 ;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
# ---------------------------------------------------------------------------
|
|
457
|
+
# Writing, reading, reviewing — the three things the published method leaves to
|
|
458
|
+
# somebody's discipline, and the three that decide whether any of it is kept up.
|
|
459
|
+
# ---------------------------------------------------------------------------
|
|
460
|
+
|
|
461
|
+
# Where the shared templates live. A template that is a FILE can be reviewed, improved and shared;
|
|
462
|
+
# one that is a heredoc in this script can only be edited by whoever is willing to edit this script.
|
|
463
|
+
function spdd_default_template() {
|
|
464
|
+
local name="$1" file;
|
|
465
|
+
file="${WORKSPACE_ROOT}/specs/_defaults/${name}";
|
|
466
|
+
[ -f "${file}" ] && echo "${file}" ;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
# The general spec of a product: what it is, who for, what it must never become.
|
|
470
|
+
#
|
|
471
|
+
# SPDD as published has no such layer — it goes straight to a story — and the tool comparison
|
|
472
|
+
# (martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html) names the gap: every tool separates
|
|
473
|
+
# a "memory bank" of durable project context from the task-specific spec, and the ones that do not
|
|
474
|
+
# make people restate the context in every spec. Spec Kit calls it a constitution; so does this.
|
|
475
|
+
#
|
|
476
|
+
# It is a file per product, written by a person, revised rarely. This verb creates it from the
|
|
477
|
+
# template and otherwise gets out of the way — the one artifact nobody should generate is what the
|
|
478
|
+
# product IS.
|
|
479
|
+
function spdd_constitution() {
|
|
480
|
+
local target="${SPEC_NAME}" dir file template;
|
|
481
|
+
case "${target}" in
|
|
482
|
+
*/*) : ;;
|
|
483
|
+
*) echo "Which product? bash cmd-spdd.sh products/webship -a constitution" ; return 1 ;;
|
|
484
|
+
esac
|
|
485
|
+
dir="$(spdd_target_dir "${target}")";
|
|
486
|
+
file="${dir}/00-constitution.md";
|
|
487
|
+
|
|
488
|
+
if [ -f "${file}" ] ; then
|
|
489
|
+
echo "${file}";
|
|
490
|
+
echo "";
|
|
491
|
+
sed -n '1,40p' "${file}";
|
|
492
|
+
echo "";
|
|
493
|
+
echo " (read it in full before writing any spec against ${target})";
|
|
494
|
+
return 0 ;
|
|
495
|
+
fi
|
|
496
|
+
|
|
497
|
+
template="$(spdd_default_template 00-constitution.md)";
|
|
498
|
+
if [ -z "${template}" ] ; then
|
|
499
|
+
echo "No template at specs/_defaults/00-constitution.md — pull the shared specs first:";
|
|
500
|
+
echo " cd ${WORKSPACE_ROOT}/specs && bash cmd-tools-specs.sh --pull";
|
|
501
|
+
return 1 ;
|
|
502
|
+
fi
|
|
503
|
+
mkdir -p "${dir}" ;
|
|
504
|
+
sed "s|<Product>|${target##*/}|g" "${template}" > "${file}" ;
|
|
505
|
+
echo "";
|
|
506
|
+
echo "*---------------------------------------------------------------------*";
|
|
507
|
+
echo " Constitution started for ${target}.";
|
|
508
|
+
echo "";
|
|
509
|
+
echo " ${file}";
|
|
510
|
+
echo "";
|
|
511
|
+
echo " Write it yourself. A constitution is the one document that outlives every";
|
|
512
|
+
echo " change to the product, and a generated one governs nothing.";
|
|
513
|
+
echo "*---------------------------------------------------------------------*";
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
# Everything a session needs to implement this spec, as ONE document, in reading order.
|
|
517
|
+
#
|
|
518
|
+
# This is the "using" half, and it is the half that decides whether the artifacts were worth
|
|
519
|
+
# writing. A spec spread over four files is read by nobody at the moment it matters; `-a read`
|
|
520
|
+
# prints the constitution, the story, the analysis and the canvas in order, so the thing handed to
|
|
521
|
+
# a session — or to a person on their first day — is complete and in one piece.
|
|
522
|
+
function spdd_read() {
|
|
523
|
+
local spec="$1" target constitution f;
|
|
524
|
+
target="$(spdd_field "${spec}" target)";
|
|
525
|
+
echo "# ${target} — $(spdd_field "${spec}" topic)";
|
|
526
|
+
echo "";
|
|
527
|
+
echo "_Stage: $(spdd_stage_of "${spec}"). Read in this order: what the product is, then the ask,";
|
|
528
|
+
echo "then what the tree says, then the contract._";
|
|
529
|
+
echo "";
|
|
530
|
+
|
|
531
|
+
constitution="$(spdd_target_dir "${target}")/00-constitution.md";
|
|
532
|
+
if [ -f "${constitution}" ] ; then
|
|
533
|
+
echo "---";
|
|
534
|
+
echo "";
|
|
535
|
+
cat "${constitution}" ;
|
|
536
|
+
echo "";
|
|
537
|
+
else
|
|
538
|
+
echo "> **No constitution for ${target}.** Nothing states what this product is, who it is for or";
|
|
539
|
+
echo "> what it must never become, so nothing can say whether this change belongs in it.";
|
|
540
|
+
echo "> Start one: bash cmd-spdd.sh ${target} -a constitution";
|
|
541
|
+
echo "";
|
|
542
|
+
fi
|
|
543
|
+
|
|
544
|
+
for f in 01-story.md 02-analysis.md 03-canvas.md ; do
|
|
545
|
+
if [ -f "${spec}/${f}" ] ; then
|
|
546
|
+
echo "---";
|
|
547
|
+
echo "";
|
|
548
|
+
cat "${spec}/${f}" ;
|
|
549
|
+
echo "";
|
|
550
|
+
fi
|
|
551
|
+
done
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
# The mechanical half of specs/_defaults/REVIEW.md.
|
|
555
|
+
#
|
|
556
|
+
# It never says "approved". A checklist can see that a section is missing, not that it is right —
|
|
557
|
+
# and the tool comparison's sharpest complaint is the review burden ("I'd rather review code than
|
|
558
|
+
# all these markdown files"), which is made worse, not better, by a tool that pretends to have done
|
|
559
|
+
# the reading. What this does is the part a person should not be spending attention on: is the
|
|
560
|
+
# scope boundary there, does every definition-of-done item have an operation, are all seven canvas
|
|
561
|
+
# sections present. What it cannot judge, it lists as what is left for the reviewer.
|
|
562
|
+
function spdd_review() {
|
|
563
|
+
local spec="$1" target stage story canvas problems=0 notes=0 line;
|
|
564
|
+
target="$(spdd_field "${spec}" target)";
|
|
565
|
+
stage="$(spdd_stage_of "${spec}")";
|
|
566
|
+
story="${spec}/01-story.md";
|
|
567
|
+
canvas="${spec}/03-canvas.md";
|
|
568
|
+
|
|
569
|
+
echo "";
|
|
570
|
+
echo "Review — $(spdd_field "${spec}" topic)";
|
|
571
|
+
echo " ${spec}";
|
|
572
|
+
echo " target ${target}, stage ${stage}";
|
|
573
|
+
echo "";
|
|
574
|
+
|
|
575
|
+
# Gate 0 — the constitution.
|
|
576
|
+
if [ -f "$(spdd_target_dir "${target}")/00-constitution.md" ] ; then
|
|
577
|
+
echo " ok ${target} has a constitution to check this against";
|
|
578
|
+
else
|
|
579
|
+
echo " NOTE ${target} has no 00-constitution.md — nothing says whether this change belongs";
|
|
580
|
+
notes=$((notes + 1));
|
|
581
|
+
fi
|
|
582
|
+
|
|
583
|
+
# Gate 1 — the story.
|
|
584
|
+
if [ -f "${story}" ] ; then
|
|
585
|
+
grep -q '^\*\*Out:\*\*' "${story}" && echo " ok the story has an Out list" || {
|
|
586
|
+
echo " MISS the story has no **Out:** list — an In list alone constrains nothing";
|
|
587
|
+
problems=$((problems + 1)); }
|
|
588
|
+
if grep -qE '^- \[[ x]\]' "${story}" ; then
|
|
589
|
+
echo " ok the story has a definition of done";
|
|
590
|
+
else
|
|
591
|
+
echo " MISS the story has no definition of done"; problems=$((problems + 1));
|
|
592
|
+
fi
|
|
593
|
+
grep -q 'Given | When | Then' "${story}" && echo " ok the story has acceptance criteria" || {
|
|
594
|
+
echo " MISS the story has no Given/When/Then acceptance criteria"; problems=$((problems + 1)); }
|
|
595
|
+
else
|
|
596
|
+
echo " MISS no 01-story.md"; problems=$((problems + 1));
|
|
597
|
+
fi
|
|
598
|
+
|
|
599
|
+
# Gate 3 — the canvas: all seven sections, and every D-item served.
|
|
600
|
+
if [ -f "${canvas}" ] ; then
|
|
601
|
+
local missing='';
|
|
602
|
+
for sec in 'R — Requirements' 'E — Entities' 'A — Approach' 'S — Structure' \
|
|
603
|
+
'O — Operations' 'N — Norms' 'S — Safeguards' ; do
|
|
604
|
+
grep -q "^## ${sec}" "${canvas}" || missing="${missing} ${sec%% *}";
|
|
605
|
+
done
|
|
606
|
+
if [ -z "${missing}" ] ; then
|
|
607
|
+
echo " ok the canvas has all seven REASONS sections";
|
|
608
|
+
else
|
|
609
|
+
echo " MISS the canvas is missing section(s):${missing}"; problems=$((problems + 1));
|
|
610
|
+
fi
|
|
611
|
+
|
|
612
|
+
# Every D-item named in the canvas should be served by at least one operation row.
|
|
613
|
+
local d unserved='';
|
|
614
|
+
for d in $(grep -oE '^\| D[0-9]+' "${canvas}" | tr -d '| ' | sort -u) ; do
|
|
615
|
+
grep -q "${d}" <(sed -n '/^## O — Operations/,/^## N —/p' "${canvas}") || unserved="${unserved} ${d}";
|
|
616
|
+
done
|
|
617
|
+
if [ -n "${unserved}" ] ; then
|
|
618
|
+
echo " MISS no operation serves:${unserved} — out of scope, or forgotten? Decide in writing";
|
|
619
|
+
problems=$((problems + 1));
|
|
620
|
+
elif grep -q '^## O — Operations' "${canvas}" ; then
|
|
621
|
+
echo " ok every definition-of-done item is served by an operation";
|
|
622
|
+
fi
|
|
623
|
+
elif [ "${stage}" == 'canvas' ] ; then
|
|
624
|
+
echo " MISS stage says canvas, but there is no 03-canvas.md"; problems=$((problems + 1));
|
|
625
|
+
fi
|
|
626
|
+
|
|
627
|
+
# Has the tree moved under it? The drift check is part of the review, not a separate errand.
|
|
628
|
+
local synced head;
|
|
629
|
+
synced="$(spdd_field "${spec}" synced_commit)";
|
|
630
|
+
if [ -n "${synced}" ] ; then
|
|
631
|
+
head="$(spdd_head_of "${target}")";
|
|
632
|
+
if [ -n "${head}" ] && [ "${head}" != "${synced}" ] ; then
|
|
633
|
+
echo " NOTE the target has moved since the canvas was stamped (${synced} → ${head}) — -a drift";
|
|
634
|
+
notes=$((notes + 1));
|
|
635
|
+
fi
|
|
636
|
+
fi
|
|
637
|
+
|
|
638
|
+
echo "";
|
|
639
|
+
echo " What this cannot judge, and a reviewer must:";
|
|
640
|
+
echo " · is the problem stated as a problem, or already as its solution?";
|
|
641
|
+
echo " · does the analysis CONTRADICT the story anywhere? one that agrees with everything";
|
|
642
|
+
echo " was not an analysis";
|
|
643
|
+
echo " · does the approach name the alternatives it rejected, and why?";
|
|
644
|
+
echo " · is the ask inside the constitution's In-scope column?";
|
|
645
|
+
echo "";
|
|
646
|
+
if [ "${problems}" -gt 0 ] ; then
|
|
647
|
+
echo " ${problems} thing(s) to fix before this is ready to be read by somebody else.";
|
|
648
|
+
else
|
|
649
|
+
echo " Nothing mechanical is missing. The reading above is still yours to do.";
|
|
650
|
+
fi
|
|
651
|
+
echo " The full checklist: ${WORKSPACE_ROOT}/specs/_defaults/REVIEW.md";
|
|
652
|
+
echo "";
|
|
653
|
+
return 0 ;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function spdd_command() {
|
|
657
|
+
case "${SPDD_ACTION}" in
|
|
658
|
+
list) spdd_list ;;
|
|
659
|
+
story) TARGET="${SPEC_NAME}" ; spdd_story ;;
|
|
660
|
+
# Takes a TARGET rather than a spec: a constitution is about the product, not about a change.
|
|
661
|
+
constitution) spdd_constitution ;;
|
|
662
|
+
analysis|canvas|drift|sync|show|read|review)
|
|
663
|
+
spdd_require_spec || return 1 ;
|
|
664
|
+
case "${SPDD_ACTION}" in
|
|
665
|
+
analysis) spdd_analysis "${SPDD_SPEC}" ;;
|
|
666
|
+
canvas) spdd_canvas "${SPDD_SPEC}" ;;
|
|
667
|
+
drift) spdd_drift "${SPDD_SPEC}" ;;
|
|
668
|
+
sync) spdd_sync "${SPDD_SPEC}" ;;
|
|
669
|
+
read) spdd_read "${SPDD_SPEC}" ;;
|
|
670
|
+
review) spdd_review "${SPDD_SPEC}" ;;
|
|
671
|
+
show) echo "${SPDD_SPEC}" ; ls -1 "${SPDD_SPEC}" ;;
|
|
672
|
+
esac
|
|
673
|
+
;;
|
|
674
|
+
*) echo "Unknown action '${SPDD_ACTION}'." ; return 1 ;;
|
|
675
|
+
esac
|
|
676
|
+
}
|