@webship.co/workspace 0.0.0-stage → 1.0.0-beta1
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/PLUGINS.md +249 -0
- package/README.md +379 -2
- package/WORKSPACES.md +69 -0
- package/actions/ai-items.js +293 -0
- package/actions/audio.js +48 -0
- package/actions/build-order.js +79 -0
- package/actions/checks.js +95 -0
- package/actions/claude-session.js +104 -0
- package/actions/commands-center.js +258 -0
- package/actions/composer.js +267 -0
- package/actions/ddev-addons.js +90 -0
- package/actions/ddev-mail.js +80 -0
- package/actions/ddev.js +237 -0
- package/actions/folders.js +165 -0
- package/actions/images-svg.js +33 -0
- package/actions/images.js +145 -0
- package/actions/navigation.js +190 -0
- package/actions/node.js +222 -0
- package/actions/notes.js +55 -0
- package/actions/plugins.js +36 -0
- package/actions/project-make.js +28 -0
- package/actions/rag.js +202 -0
- package/actions/row-actions.js +262 -0
- package/actions/screens.js +270 -0
- package/actions/testing.js +121 -0
- package/actions/video-edit.js +54 -0
- package/ai-inventory.js +182 -0
- package/ai-items.js +202 -0
- package/assistant-cast.js +176 -0
- package/assistant-suggestions.js +91 -0
- package/assistant.js +484 -0
- package/audio-voice.js +528 -0
- package/auth-google.js +260 -0
- package/build-ai.js +52 -0
- package/build-order-page.js +191 -0
- package/build-order.js +313 -0
- package/builder-args.js +117 -0
- package/changelog.js +302 -0
- package/chat-threads.js +134 -0
- package/checks.js +105 -0
- package/claude-args.js +282 -0
- package/claude-sessions.js +129 -0
- package/command-author.js +117 -0
- package/command-block.js +20 -0
- package/commands/defaults.yml +159 -0
- package/commands-page.js +460 -0
- package/commands.js +568 -0
- package/cucumber.js +43 -0
- package/ddev-addons-page.js +124 -0
- package/ddev-addons.js +154 -0
- package/ddev-custom-commands.js +96 -0
- package/ddev-domains.js +84 -0
- package/ddev-import.js +93 -0
- package/ddev-mail-page.js +167 -0
- package/ddev-mail.js +110 -0
- package/ddev-options.js +145 -0
- package/ddev-snapshots.js +126 -0
- package/ddev.js +145 -0
- package/docs/DEVELOPER-GUIDE.md +224 -0
- package/docs/README.md +252 -0
- package/docs/REFERENCE.md +684 -0
- package/docs/USER-GUIDE.md +697 -0
- package/docs/screenshots/assistant/avatar-board.png +0 -0
- package/docs/screenshots/assistant/avatar-coffee.png +0 -0
- package/docs/screenshots/assistant/avatar-colours.png +0 -0
- package/docs/screenshots/assistant/avatar-icons.png +0 -0
- package/docs/screenshots/assistant/avatar-moves.png +0 -0
- package/docs/screenshots/assistant/avatar-pick-cookieman.png +0 -0
- package/docs/screenshots/assistant/avatar-settings-voices.png +0 -0
- package/docs/screenshots/assistant/avatar-status.png +0 -0
- package/docs/screenshots/create-card/create-card.png +0 -0
- package/docs/screenshots/create-card/start-ai.png +0 -0
- package/docs/screenshots/guide-clone-address.png +0 -0
- package/docs/screenshots/guide-clone-worktree-off.png +0 -0
- package/docs/screenshots/guide-clone-worktree-on.png +0 -0
- package/docs/screenshots/guide-ddev-menu.png +0 -0
- package/docs/screenshots/guide-domains.png +0 -0
- package/docs/screenshots/guide-home.png +0 -0
- package/docs/screenshots/guide-ide-menu.png +0 -0
- package/docs/screenshots/guide-remove-refusal.png +0 -0
- package/docs/screenshots/guide-rows-worktree.png +0 -0
- package/docs/screenshots/guide-screens.png +0 -0
- package/docs/screenshots/guide-settings.png +0 -0
- package/docs/screenshots/guide-workspace-page.png +0 -0
- package/docs/screenshots/home/card-settings.png +0 -0
- package/docs/screenshots/home/drag-reorder.png +0 -0
- package/docs/screenshots/home/edit-card.png +0 -0
- package/docs/screenshots/images/claude-code-image.png +0 -0
- package/docs/screenshots/images/edit-with-ai.png +0 -0
- package/docs/screenshots/images/gallery.png +0 -0
- package/docs/screenshots/images/generate-description.png +0 -0
- package/docs/screenshots/images/generate-plan.png +0 -0
- package/docs/screenshots/images/providers.png +0 -0
- package/docs/screenshots/images/svg-form.png +0 -0
- package/docs/screenshots/images/svg-result.png +0 -0
- package/docs/screenshots/images/upload.png +0 -0
- package/docs/screenshots/new-folder/2-form.png +0 -0
- package/docs/screenshots/new-folder/8-ddev-options.png +0 -0
- package/docs/screenshots/new-folder/files-folder.png +0 -0
- package/docs/screenshots/projects/ddev-custom-commands.png +0 -0
- package/docs/screenshots/projects/state-chip-stop.png +0 -0
- package/docs/screenshots/readme/dashboard-dark.png +0 -0
- package/docs/screenshots/readme/dashboard-light.png +0 -0
- package/docs/screenshots/readme/dev-dark.png +0 -0
- package/docs/screenshots/readme/dev-light.png +0 -0
- package/docs/screenshots/readme/docs-dark.png +0 -0
- package/docs/screenshots/readme/docs-light.png +0 -0
- package/docs/screenshots/readme/icons/ai.svg +4 -0
- package/docs/screenshots/readme/icons/code.svg +4 -0
- package/docs/screenshots/readme/icons/docs.svg +4 -0
- package/docs/screenshots/readme/icons/services.svg +4 -0
- package/docs/screenshots/readme/icons/sites.svg +4 -0
- package/docs/screenshots/readme/test-report-dark.png +0 -0
- package/docs/screenshots/readme/test-report-light.png +0 -0
- package/docs/screenshots/readme/test-scenarios.png +0 -0
- package/docs/screenshots/readme/test-steps.png +0 -0
- package/docs/screenshots/readme/videos-dark.png +0 -0
- package/docs/screenshots/readme/videos-light.png +0 -0
- package/docs/screenshots/screens-menu.png +0 -0
- package/docs/screenshots/screens-new.png +0 -0
- package/docs/screenshots/settings/auth-google-lists.png +0 -0
- package/docs/screenshots/settings/delete-1-row.png +0 -0
- package/docs/screenshots/settings/delete-2-confirm.png +0 -0
- package/docs/screenshots/settings/delete-3-type-name.png +0 -0
- package/docs/screenshots/settings/delete-4-type-yes.png +0 -0
- package/event-log.js +59 -0
- package/files-browser.js +247 -0
- package/folders.js +121 -0
- package/format.js +73 -0
- package/git-info.js +81 -0
- package/github-auth.js +62 -0
- package/html.js +10 -0
- package/icons.js +83 -0
- package/images-ai.js +447 -0
- package/images-create.js +226 -0
- package/images-page.js +417 -0
- package/images-records.js +39 -0
- package/images-render.js +36 -0
- package/images-svg-core.js +214 -0
- package/images-svg-sanitize.js +188 -0
- package/images-svg.js +241 -0
- package/images.js +270 -0
- package/jobs.js +430 -0
- package/linger.js +21 -0
- package/lists.js +292 -0
- package/media-info.js +136 -0
- package/navigation-page.js +264 -0
- package/navigation.js +394 -0
- package/notes.js +0 -0
- package/package.json +47 -4
- package/palette-index.js +46 -0
- package/playwright.config.js +23 -0
- package/plugin-install.js +239 -0
- package/plugin-loader.js +466 -0
- package/plugin-manifest.js +83 -0
- package/plugin-settings.js +44 -0
- package/plugins/workspace-notes/index.js +59 -0
- package/plugins-page.js +103 -0
- package/project-make.js +241 -0
- package/project-name.js +210 -0
- package/public/assistant-avatar-moves.js +646 -0
- package/public/assistant-avatar-ui.js +1223 -0
- package/public/assistant-avatar.js +530 -0
- package/public/avatar/druplicon.vrm +0 -0
- package/public/css/base.css +260 -0
- package/public/css/components/ai-assistant.css +263 -0
- package/public/css/components/assistant-avatar.css +279 -0
- package/public/css/components/assistant-views.css +198 -0
- package/public/css/components/build-order.css +74 -0
- package/public/css/components/clone-as-a-git-worktree.css +30 -0
- package/public/css/components/command-palette.css +61 -0
- package/public/css/components/commands-center.css +139 -0
- package/public/css/components/confirm-dialog.css +40 -0
- package/public/css/components/create-card.css +8 -0
- package/public/css/components/ddev-menu.css +23 -0
- package/public/css/components/deep-chat.css +17 -0
- package/public/css/components/density.css +11 -0
- package/public/css/components/floating-assistant-workspace-pages.css +55 -0
- package/public/css/components/folders.css +5 -0
- package/public/css/components/full-height-left-assistant-sidebar-all-pages.css +39 -0
- package/public/css/components/full-height-right-actions-rail-pages-that-have-actions.css +267 -0
- package/public/css/components/grid-and-list.css +203 -0
- package/public/css/components/help-page.css +36 -0
- package/public/css/components/hero.css +16 -0
- package/public/css/components/images.css +70 -0
- package/public/css/components/layout-rhythm-and-spacing-polish.css +139 -0
- package/public/css/components/mic-on-any-field-that-wants-typing.css +416 -0
- package/public/css/components/modal-fit.css +113 -0
- package/public/css/components/page-width.css +23 -0
- package/public/css/components/plugins-page.css +9 -0
- package/public/css/components/project-cards.css +256 -0
- package/public/css/components/project-rows.css +390 -0
- package/public/css/components/reordering-the-workspace-cards.css +85 -0
- package/public/css/components/responsive-home-and-the-workspace-pages.css +457 -0
- package/public/css/components/running-commands-as-toasts.css +327 -0
- package/public/css/components/settings-editor-core-config-yml.css +828 -0
- package/public/css/components/short-results-as-a-toast-at-the-top.css +203 -0
- package/public/css/components/sound-player.css +84 -0
- package/public/css/components/suggest-agents-skills-commands.css +112 -0
- package/public/css/components/tab-modal.css +142 -0
- package/public/css/components/terminals.css +244 -0
- package/public/css/components/test-report-media-one-file-per-row-paged.css +144 -0
- package/public/css/components/top-toolbar-logo-breadcrumb.css +107 -0
- package/public/css/components/video-edit.css +6 -0
- package/public/css/components/web-ide-open-with.css +23 -0
- package/public/css/components/working-indicators.css +158 -0
- package/public/css/components/workspace-cards.css +79 -0
- package/public/favicon.ico +0 -0
- package/public/favicon.png +0 -0
- package/public/htmx.min.js +1 -0
- package/public/logo.png +0 -0
- package/public/media-player.js +215 -0
- package/public/mic.js +255 -0
- package/public/narration.js +110 -0
- package/public/palette.js +278 -0
- package/public/sortable.js +251 -0
- package/public/suggest.js +337 -0
- package/public/terminal.js +903 -0
- package/public/themes/default/theme.css +267 -0
- package/public/themes/ember/theme.css +180 -0
- package/public/themes/press/theme.css +290 -0
- package/public/themes/slate/theme.css +182 -0
- package/public/touch-icon.png +0 -0
- package/public/ui.js +2721 -0
- package/public/vendor/ace/LICENSE.txt +24 -0
- package/public/vendor/ace/ace.js +23 -0
- package/public/vendor/ace/ext-language_tools.js +8 -0
- package/public/vendor/ace/ext-searchbox.js +8 -0
- package/public/vendor/ace/mode-css.js +8 -0
- package/public/vendor/ace/mode-html.js +8 -0
- package/public/vendor/ace/mode-javascript.js +8 -0
- package/public/vendor/ace/mode-markdown.js +8 -0
- package/public/vendor/ace/mode-sh.js +8 -0
- package/public/vendor/ace/mode-yaml.js +8 -0
- package/public/vendor/ace/theme-textmate.js +8 -0
- package/public/vendor/ace/theme-tomorrow_night.js +8 -0
- package/public/vendor/ace/worker-yaml.js +1 -0
- package/public/vendor/deep-chat.LICENSE +21 -0
- package/public/vendor/deep-chat.bundle.js +1 -0
- package/public/vendor/fonts/dm-serif-text-LICENSE.txt +93 -0
- package/public/vendor/fonts/dm-serif-text-latin-400-italic.woff2 +0 -0
- package/public/vendor/fonts/dm-serif-text-latin-400-normal.woff2 +0 -0
- package/public/vendor/fonts/figtree-LICENSE.txt +93 -0
- package/public/vendor/fonts/figtree-latin-400-italic.woff2 +0 -0
- package/public/vendor/fonts/figtree-latin-400-normal.woff2 +0 -0
- package/public/vendor/fonts/figtree-latin-600-italic.woff2 +0 -0
- package/public/vendor/fonts/figtree-latin-600-normal.woff2 +0 -0
- package/public/vendor/fonts/jetbrains-mono-LICENSE.txt +93 -0
- package/public/vendor/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
- package/public/vendor/fonts/ubuntu-mono-LICENSE.txt +98 -0
- package/public/vendor/fonts/ubuntu-mono-latin-wght-normal.woff2 +0 -0
- package/public/vendor/tabler-LICENSE.txt +21 -0
- package/public/vendor/tabler-sprite.svg +1 -0
- package/public/vendor/three/LICENSE +21 -0
- package/public/vendor/three/addons/loaders/GLTFLoader.js +4860 -0
- package/public/vendor/three/addons/utils/BufferGeometryUtils.js +1501 -0
- package/public/vendor/three/addons/utils/SkeletonUtils.js +496 -0
- package/public/vendor/three/three.core.min.js +6 -0
- package/public/vendor/three/three.module.min.js +6 -0
- package/public/vendor/three-vrm/LICENSE +22 -0
- package/public/vendor/three-vrm/three-vrm.module.min.js +983 -0
- package/public/vendor/uikit-icons.min.js +1 -0
- package/public/vendor/uikit.min.css +1 -0
- package/public/vendor/uikit.min.js +1 -0
- package/public/vendor/webship-icons/ui/bookmark-outlined.svg +1 -0
- package/public/vendor/webship-icons/ui/headset.svg +1 -0
- package/public/vendor/webship-icons/ui/menu.svg +1 -0
- package/public/vendor/webship-icons/ui/pause.svg +1 -0
- package/public/vendor/webship-icons/ui/play.svg +1 -0
- package/public/vendor/webship-icons/ui/share.svg +1 -0
- package/public/vendor/webship-icons/ui/sound-off.svg +1 -0
- package/public/vendor/webship-icons/ui/sound-on.svg +1 -0
- package/public/vendor/webship-icons/ui/stop.svg +1 -0
- package/public/vendor/xterm/addon-fit.js +2 -0
- package/public/vendor/xterm/addon-unicode11.js +2 -0
- package/public/vendor/xterm/addon-web-links.js +2 -0
- package/public/vendor/xterm/xterm.css +218 -0
- package/public/vendor/xterm/xterm.js +2 -0
- package/rag.js +169 -0
- package/reader.js +132 -0
- package/repo-blobs.js +66 -0
- package/report-pdf.js +337 -0
- package/row-layout.js +1439 -0
- package/screenrc +37 -0
- package/screens.js +1063 -0
- package/scripts/code-server-start.sh +190 -0
- package/scripts/images-claude-finish.js +107 -0
- package/scripts/screen-host.sh +114 -0
- package/scripts/screen-runner.js +362 -0
- package/scripts/screen-then.js +47 -0
- package/scripts/update.sh +350 -0
- package/server.js +7923 -0
- package/settings-file.js +423 -0
- package/speech.js +297 -0
- package/tab-modal.js +75 -0
- package/test-reports.js +260 -0
- package/themes.js +381 -0
- package/transcripts.js +168 -0
- package/urls.js +13 -0
- package/validate.js +18 -0
- package/version-check.js +94 -0
- package/video-edit.js +588 -0
- package/waiting.js +85 -0
- package/workspace-card-tools.js +41 -0
- package/workspace-delete.js +139 -0
- package/workspace-types.js +85 -0
- package/workspaces.js +553 -0
|
@@ -0,0 +1,684 @@
|
|
|
1
|
+
# Webship Workspace: reference
|
|
2
|
+
|
|
3
|
+
> **The full reference.** Every command, every flag and how the tooling is built. The short introduction is the
|
|
4
|
+
> [README](../../../README.md); the day-one walkthrough is the [user guide](USER-GUIDE.md). Paths in this file
|
|
5
|
+
> are relative to the repository root (`~/workspace`).
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
The Webship team's Drupal development workspace: manage the base-code development work cycle for Webship's distributions, recipes, profiles, and starter-kit templates on top of [DDEV](https://ddev.com) — no host-level Apache, PHP, or MySQL required.
|
|
9
|
+
|
|
10
|
+
Ships builders for Webship plus plain Drupal:
|
|
11
|
+
|
|
12
|
+
| Distribution | Versions | Project template |
|
|
13
|
+
| --- | --- | --- |
|
|
14
|
+
| [Webship](https://www.drupal.org/project/webship) | 9.1, 9.2, 10.0, 10.1, 11.0 (`x` + pinned) | `drupal/webship_project` |
|
|
15
|
+
| [Website Starter](https://www.drupal.org/project/website_starter) · [Haven](https://www.drupal.org/project/haven) site templates | 1.0.x on Webship 11 | `drupal/webship_project` + the recipe |
|
|
16
|
+
| [Drupal](https://www.drupal.org/project/drupal) | latest 11 | `drupal/recommended-project` |
|
|
17
|
+
| [Drupal CMS](https://www.drupal.org/project/cms) | latest 2 | `drupal/cms` |
|
|
18
|
+
|
|
19
|
+
## Layout
|
|
20
|
+
|
|
21
|
+
Every folder in `~/workspace` is a **workspace**: its own `cmd-*.sh` commands and its own page in the
|
|
22
|
+
dashboard. A builder run from one creates a project in a subdirectory of it, with its own DDEV
|
|
23
|
+
containers and its own database — nothing is shared on the host.
|
|
24
|
+
|
|
25
|
+
| | |
|
|
26
|
+
| --- | --- |
|
|
27
|
+
| **Sites you build** | `dev` `test` `sandboxes` `demos` `projects` |
|
|
28
|
+
| **Code we maintain**, as git clones | `products` `modules` `themes` `profiles` `recipes` `site-templates` |
|
|
29
|
+
| **AI items** — drafts that install into the Claude Code CLI | `ai-agents` `ai-skills` `ai-commands` `ai-prompts` |
|
|
30
|
+
| **Documents** | `docs` `worklogs` `specs` `videos` `audio` |
|
|
31
|
+
| **Services** | `designs` (Penpot) `rag` (Milvus) `graphs` (graphify) |
|
|
32
|
+
|
|
33
|
+
`core/` holds the whole build chain — `core/scripts` (the libraries every `cmd-*.sh` sources) and
|
|
34
|
+
`core/config` (`settings.yml` plus one file per workspace). The `workspaces:` list in `settings.yml`
|
|
35
|
+
is what registers a folder; adding one is two entries and a directory, and the dashboard picks it up
|
|
36
|
+
with no restart. Settings → `workspaces:` adds one from the browser, and deletes one that nothing uses
|
|
37
|
+
after asking three times.
|
|
38
|
+
|
|
39
|
+
## Get started
|
|
40
|
+
|
|
41
|
+
Four steps, in this order. Everything after them can be done from the dashboard.
|
|
42
|
+
|
|
43
|
+
### 1. Get the files
|
|
44
|
+
|
|
45
|
+
Open **[github.com/webship/workspace](https://github.com/webship/workspace)** (sign in — it is a
|
|
46
|
+
private repository), switch the branch selector to **`1.0.x`**, then **Code ▾ → Download ZIP**.
|
|
47
|
+
|
|
48
|
+
Unzip it and rename the extracted `workspace-1.0.x` folder to **`workspace`** in your home
|
|
49
|
+
directory, so you end up with `~/workspace`.
|
|
50
|
+
|
|
51
|
+
### 2. Install the tools
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
bash ~/workspace/core/scripts/install.sh
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
It reports what is missing and installs it — everything the workspace needs, and nothing else:
|
|
58
|
+
|
|
59
|
+
| | |
|
|
60
|
+
|---|---|
|
|
61
|
+
| Runs the sites | Docker, [DDEV](https://ddev.readthedocs.io/en/stable/users/install/) |
|
|
62
|
+
| Runs the tooling | git, gh, Node.js (npm, npx — also the [skills.sh](https://skills.sh) CLI), jq, rsync, python3, gawk, sed, screen |
|
|
63
|
+
| Runs the agents | [Claude Code](https://code.claude.com/docs/en/quickstart) |
|
|
64
|
+
| Trusted https | mkcert, libnss3-tools / nss-tools |
|
|
65
|
+
| Shell and build basics | curl, wget, unzip, zip, p7zip, diffutils, vim, links, lynx, htop, gcc, g++, make |
|
|
66
|
+
| Pipelines locally | gitlab-ci-local |
|
|
67
|
+
|
|
68
|
+
It also **trusts the local https certificates** — every workspace URL is https, and without that
|
|
69
|
+
trust the browser refuses each one with `ERR_CERT_AUTHORITY_INVALID`. Snap browsers each get their
|
|
70
|
+
own store; see `core/scripts/trust-https.sh`.
|
|
71
|
+
|
|
72
|
+
This script is the only installer there is: it lives here, in this repository, so what a machine
|
|
73
|
+
gets is whatever this checkout says. Nothing is fetched from another repository to bootstrap it.
|
|
74
|
+
|
|
75
|
+
Idempotent, so it is also the update path. `--check` reports and changes nothing; `-y` skips the
|
|
76
|
+
per-group prompts. It installs nothing at the OS level beyond those tools and writes nothing to
|
|
77
|
+
your `~/.bashrc`.
|
|
78
|
+
|
|
79
|
+
**On a fresh Ubuntu, one thing needs you afterwards.** Installing Docker adds you to the
|
|
80
|
+
`docker` group, and a group is applied at **login** — so the shell you ran the installer in still
|
|
81
|
+
cannot reach Docker, and step 3 would fail with:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Docker error: permission denied while trying to connect to the docker API at unix:///var/run/docker.sock
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
That is a session that predates a group, not a broken tool. **Log out and back in.** The installer
|
|
88
|
+
tries Docker for real at the end and tells you which of these you are in:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
Next steps:
|
|
92
|
+
1. LOG OUT AND BACK IN. You are in the docker group, but a group only
|
|
93
|
+
applies at login, so this shell still cannot reach Docker …
|
|
94
|
+
2. gh auth login
|
|
95
|
+
3. cd core/workspace-app && ddev start
|
|
96
|
+
4. Open https://workspace.ddev.site
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Then sign in to GitHub, which the release and PR tooling needs:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
gh auth login
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 3. Start the dashboard
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
cd ~/workspace/core/workspace-app
|
|
109
|
+
ddev start
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The first start does three things for you, so a fresh machine needs no per-machine edits:
|
|
113
|
+
|
|
114
|
+
- **Builds the container** with the docker group this host actually uses, so the dashboard can see
|
|
115
|
+
what Docker is doing. Get this wrong and every project reads as Stopped forever while running
|
|
116
|
+
perfectly well — `bash core/scripts/docker-gid.sh --check` reports it, and step 2 already set it.
|
|
117
|
+
- **Trusts the https certificate** through the project's own `post-start` hook, and names any
|
|
118
|
+
browser that was open before the CA arrived (a trust store is read once, at startup).
|
|
119
|
+
- **Publishes every workspace hostname**, so `<project>.<workspace>.workspace.ddev.site` resolves
|
|
120
|
+
without touching `/etc/hosts`.
|
|
121
|
+
|
|
122
|
+
### 4. Open it
|
|
123
|
+
|
|
124
|
+
**https://workspace.ddev.site** — and build your first site from the **Build** form.
|
|
125
|
+
|
|
126
|
+
That is the whole setup. Building, starting, stopping, backing up, restoring and removing projects
|
|
127
|
+
are all done from there.
|
|
128
|
+
|
|
129
|
+
### Make it come back after a reboot
|
|
130
|
+
|
|
131
|
+
Worth doing once, because nothing else will:
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
bash ~/workspace/core/scripts/autostart.sh --enable
|
|
135
|
+
sudo loginctl enable-linger $USER
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
A DDEV project's containers carry `restart: no`, so after a reboot the dashboard is simply not
|
|
139
|
+
running and **every workspace URL answers 404** from a router with nothing behind it. That is not
|
|
140
|
+
a fault to debug; it is the default. `--enable` installs a systemd *user* service that runs
|
|
141
|
+
`ddev start` once Docker is up. The `enable-linger` line is the difference between starting at
|
|
142
|
+
**boot** and starting when you next log in, and it is the one step that needs your password.
|
|
143
|
+
|
|
144
|
+
It also starts the **screen runner** each time, which is what the Screens page and every
|
|
145
|
+
item-sync button use. Sessions run on your machine rather than in the dashboard's container — so
|
|
146
|
+
`screen -r <session>` works in your own terminal, and a browser an agent drives opens on your
|
|
147
|
+
desktop — and a container cannot start a host process. Without the boot service, start it once with
|
|
148
|
+
`bash core/workspace-app/scripts/screen-host.sh --start`.
|
|
149
|
+
|
|
150
|
+
Check it any time with `bash core/scripts/autostart.sh` — it prints the service state, whether
|
|
151
|
+
lingering is on, and exactly which projects will come back.
|
|
152
|
+
|
|
153
|
+
**Which projects come back** is `dashboard.autostart` in `core/config/settings.yml`. It takes a
|
|
154
|
+
word, not just a list, because a hand-kept list is wrong within a week — you build a project and
|
|
155
|
+
never think about this file again:
|
|
156
|
+
|
|
157
|
+
| Value | What starts |
|
|
158
|
+
|---|---|
|
|
159
|
+
| `workspace` | Just the dashboard. The default: boots in seconds, and everything else is one click away from it. |
|
|
160
|
+
| `running` | Whatever was running when the machine last shut down cleanly. What most people mean by "bring my work back". |
|
|
161
|
+
| `all` | Every project DDEV has registered. Honest about the cost — each one is a web + db container competing for RAM at boot. |
|
|
162
|
+
| `dev1,test2` | Exactly those, in that order. |
|
|
163
|
+
|
|
164
|
+
The dashboard is always started first and is always included, whatever the value says: a boot that
|
|
165
|
+
brings back four sites and no dashboard is worse than one that brings back only the dashboard.
|
|
166
|
+
|
|
167
|
+
### Notes on the four steps
|
|
168
|
+
|
|
169
|
+
- **Platforms.** Linux (Debian/Ubuntu apt, Fedora dnf) and macOS ([Homebrew](https://brew.sh);
|
|
170
|
+
Docker via Docker Desktop or OrbStack) install directly. On Windows, do all of this inside
|
|
171
|
+
[WSL2](https://learn.microsoft.com/windows/wsl/install) — `wsl --install -d Ubuntu`, reboot, then
|
|
172
|
+
step 2 in Ubuntu; the script detects a native Windows shell and says exactly this.
|
|
173
|
+
- **The location is yours.** Every script finds the tooling from its own path, so `/srv/workspace`,
|
|
174
|
+
`~/Sites/webship` or a second copy beside the first all work. The folder name only decides whether
|
|
175
|
+
the URLs in this README match what you see.
|
|
176
|
+
- **Jira (optional).** The JIRA button on a project row, the tasks modal and the Jira agents all
|
|
177
|
+
drive the **Teamwork Graph CLI**, `twg` — [teamworkgraph.com/cli](https://teamworkgraph.com/cli) ·
|
|
178
|
+
[developer.atlassian.com/cloud/twg-cli](https://developer.atlassian.com/cloud/twg-cli/). Step 2
|
|
179
|
+
offers to install it; by hand it is:
|
|
180
|
+
```bash
|
|
181
|
+
curl -fsSL --retry 2 https://teamwork-graph.atlassian.com/cli/install | bash
|
|
182
|
+
~/.local/bin/twg doctor # signs you in through the browser, then checks the setup
|
|
183
|
+
```
|
|
184
|
+
It installs into `~/.local/bin` and holds one OAuth session per person, which is why it is
|
|
185
|
+
offered rather than assumed. Then fill in `jira:` in `core/config/settings.yml` (`site`,
|
|
186
|
+
`account`, `default_project`) and `ddev restart` so the dashboard can see the binary.
|
|
187
|
+
|
|
188
|
+
Configured Jira but no button? The button is there, disabled, and its tooltip says which half is
|
|
189
|
+
missing — the settings and the CLI are separate things.
|
|
190
|
+
- **https, if a browser still complains.** A browser reads its trust store **once, at startup**,
|
|
191
|
+
so one that was already open when the CA arrived keeps refusing every workspace URL — a reload
|
|
192
|
+
or a cache clear will not do it. Step 2 and every `ddev start` name the browsers in that state
|
|
193
|
+
and how to restart each without losing tabs (`chrome://restart`, `brave://restart`).
|
|
194
|
+
`bash core/scripts/trust-https.sh` reports and fixes the stores themselves, and
|
|
195
|
+
`--restart-browsers` closes the stale ones for you. A snap browser (Brave, Chromium) is confined
|
|
196
|
+
to its own store, so it needs the CA separately from a packaged Chrome.
|
|
197
|
+
- **Changing the tooling?** Keep a git clone for that, separate from the live tree above, and open
|
|
198
|
+
pull requests from it:
|
|
199
|
+
```
|
|
200
|
+
git clone --branch '1.0.x' https://github.com/webship/workspace.git ~/workspace/products/workspace
|
|
201
|
+
```
|
|
202
|
+
After a PR merges, `bash core/scripts/sync-tooling.sh --pull` copies the scripts, the
|
|
203
|
+
dashboard and the per-workspace settings into the live tree — and deliberately leaves
|
|
204
|
+
`core/config/settings.yml` alone, since that file holds your real account details and API keys.
|
|
205
|
+
|
|
206
|
+
### Update — same place as the install
|
|
207
|
+
|
|
208
|
+
Installing brings the machine up to date; updating keeps it there. One command per thing that
|
|
209
|
+
moves, and neither touches `core/config/settings.yml`, which holds your real account details and
|
|
210
|
+
API keys:
|
|
211
|
+
|
|
212
|
+
| What | Command | What it does |
|
|
213
|
+
| --- | --- | --- |
|
|
214
|
+
| The tools | `bash core/scripts/install.sh --check` | Reports what is missing, then installs it without `--check`. Idempotent, so it is also the update path for git, gh, Node.js, Docker, DDEV and Claude Code. |
|
|
215
|
+
| The dashboard app, and the prompt templates | `bash core/workspace-app/scripts/update.sh --check` | Compares the installed version with the newest release; without `--check` it updates to it. |
|
|
216
|
+
| The `cmd-*.sh` tooling (clone only) | `bash core/scripts/sync-tooling.sh --pull` | Copies the scripts, the dashboard and the per-workspace settings out of the clone into the live tree. |
|
|
217
|
+
|
|
218
|
+
The dashboard updater is self-contained — plain bash, `curl`/`gh`, `tar` and `rsync`, no workspace
|
|
219
|
+
bootstrap — because it has to keep working while replacing the tooling around it:
|
|
220
|
+
|
|
221
|
+
```
|
|
222
|
+
bash core/workspace-app/scripts/update.sh --check # installed vs the newest release
|
|
223
|
+
bash core/workspace-app/scripts/update.sh # update to it
|
|
224
|
+
bash core/workspace-app/scripts/update.sh --tag 1.0.0 # pin a release
|
|
225
|
+
bash core/workspace-app/scripts/update.sh --dry-run # itemize, change nothing
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Runtime state survives an update: `node_modules` is kept unless `package.json` changed (then
|
|
229
|
+
`npm install` runs in DDEV), and `actions.log`, screenshots and test reports stay where they are.
|
|
230
|
+
|
|
231
|
+
It also brings the release's **prompt templates** into `prompts/`, because the New screen form and
|
|
232
|
+
the Jira verbs offer them — a release that improves a prompt is no use if the prompt never reaches
|
|
233
|
+
the machine. That folder is where prompts are written as well as installed, so a prompt *you* have
|
|
234
|
+
edited is never overwritten:
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
new prompt: webship-canvas-component.md
|
|
238
|
+
updated: review.md
|
|
239
|
+
yours, kept: explain.md
|
|
240
|
+
Prompts: 1 new, 1 updated, 1 left as yours.
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Edited means edited, not "differs from the new release": each update records the checksum of every
|
|
244
|
+
prompt as it shipped, so one still matching the installed version is refreshed and only one you
|
|
245
|
+
changed is kept. Add `--force-prompts` to take the release's copy of those too, or `--no-prompts`
|
|
246
|
+
to skip the step.
|
|
247
|
+
|
|
248
|
+
### First build
|
|
249
|
+
|
|
250
|
+
A build is one command — or the **Build** form on the dashboard:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
cd ~/workspace/dev
|
|
254
|
+
bash cmd-webship11-0-x-project.sh webship11c1 --install
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Settings
|
|
258
|
+
|
|
259
|
+
Set your own webmaster account and any extras in the settings file — either from the dashboard's
|
|
260
|
+
**Settings** page (https://workspace.ddev.site/settings), or by editing it directly:
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
vim ~/workspace/core/config/settings.yml
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
```yaml
|
|
267
|
+
host: 127.0.0.1
|
|
268
|
+
web: http://127.0.0.1/core
|
|
269
|
+
protocol: http
|
|
270
|
+
account:
|
|
271
|
+
name: webmaster
|
|
272
|
+
pass: CHANGE_ME
|
|
273
|
+
mail: info@webship.co
|
|
274
|
+
contributor:
|
|
275
|
+
name: CHANGE_ME # who commits/files issues from this machine (#32)
|
|
276
|
+
email: CHANGE_ME
|
|
277
|
+
ai_providers: # keys for the AI stack of the sites you build
|
|
278
|
+
openai:
|
|
279
|
+
api_key: sk-change-this
|
|
280
|
+
anthropic:
|
|
281
|
+
api_key: sk-change-this
|
|
282
|
+
gemini:
|
|
283
|
+
api_key: sk-change-this
|
|
284
|
+
workspaces:
|
|
285
|
+
- products
|
|
286
|
+
- dev
|
|
287
|
+
- test
|
|
288
|
+
- demos
|
|
289
|
+
- sandboxes
|
|
290
|
+
- profiles
|
|
291
|
+
- modules
|
|
292
|
+
- themes
|
|
293
|
+
- libraries
|
|
294
|
+
- recipes
|
|
295
|
+
- components
|
|
296
|
+
- agents
|
|
297
|
+
- skills
|
|
298
|
+
- prompts
|
|
299
|
+
- docs
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Keep real passwords and API keys in your own copy — never commit them back.
|
|
303
|
+
|
|
304
|
+
`ai_providers` feeds the AI stack of the sites you build: after an install, `set_ai_provider_keys` stores each real key on the site through the Key module and points the matching `ai_provider_<name>` module at it (Drupal CMS AI, Webship AI). Placeholders are skipped, values travel over STDIN (never a command line), and everything runs inside the project's own DDEV containers.
|
|
305
|
+
|
|
306
|
+
No paths are listed: `root`, `path`, `scripts`, `config` and `backups` are derived from the checkout (`backups/` is created on first run). Add them to `settings.yml`, or export `WORKSPACE_ROOT` / `_PATH` / `_SCRIPTS` / `_CONFIG`, only to point the tooling somewhere else.
|
|
307
|
+
|
|
308
|
+
There is no `database:` section either: every DDEV project manages its own isolated database, and DDEV's `settings.ddev.php` owns the connection.
|
|
309
|
+
|
|
310
|
+
## Web dashboard (workspace.ddev.site)
|
|
311
|
+
|
|
312
|
+
A visual dashboard + AI assistant for the whole workspace lives in
|
|
313
|
+
`core/workspace-app` (basic Node.js + HTMX, served through DDEV):
|
|
314
|
+
|
|
315
|
+
```
|
|
316
|
+
cd ~/workspace/core/workspace-app
|
|
317
|
+
ddev start
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Then open **https://workspace.ddev.site** — workspace cards with live project
|
|
321
|
+
counts, per-workspace pages (`/dev`, `/test`, …) with build/backup/remove
|
|
322
|
+
actions, and an AI assistant on every page. See
|
|
323
|
+
[`core/workspace-app/README.md`](../../../core/workspace-app/README.md) for details.
|
|
324
|
+
|
|
325
|
+
### Domains
|
|
326
|
+
|
|
327
|
+
The dashboard manages a hierarchical domain scheme by default:
|
|
328
|
+
|
|
329
|
+
- `https://workspace.ddev.site` — the dashboard home
|
|
330
|
+
- `https://<workspace>.workspace.ddev.site` — that workspace's page
|
|
331
|
+
(e.g. `dev.workspace.ddev.site`, `test.workspace.ddev.site`)
|
|
332
|
+
- `https://<project>.<workspace>.workspace.ddev.site` — the project's real
|
|
333
|
+
site (e.g. `webship11demo.dev.workspace.ddev.site`); the **Launch**
|
|
334
|
+
button uses these, and the canonical `https://<project>.ddev.site`
|
|
335
|
+
always keeps working
|
|
336
|
+
|
|
337
|
+
No per-project configuration is needed — wildcard hostnames + an nginx
|
|
338
|
+
tier in `core/workspace-app/.ddev/` route everything with valid TLS.
|
|
339
|
+
|
|
340
|
+
All navigation links and the Launch buttons follow this scheme by
|
|
341
|
+
default, and they are all built from **one field** — `hub_domain:` in
|
|
342
|
+
`core/config/settings.yml`. Its first label is the DDEV project name and
|
|
343
|
+
the rest is the project TLD.
|
|
344
|
+
|
|
345
|
+
Change it through the command, not by hand, so the dashboard's links and
|
|
346
|
+
DDEV's routing cannot drift apart:
|
|
347
|
+
|
|
348
|
+
```
|
|
349
|
+
cd ~/workspace/products
|
|
350
|
+
bash core/scripts/autostart.sh --domain workspace.ddev.site
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
The TLD is set **globally**, with `ddev config global --project-tld`, so
|
|
354
|
+
one field moves everything together: the dashboard, every workspace page
|
|
355
|
+
under it, and each project's own canonical `<project>.<tld>`. No project
|
|
356
|
+
in this tree carries its own `project_tld`, so they all inherit it — and
|
|
357
|
+
any that does is named in the output as one that will not follow.
|
|
358
|
+
|
|
359
|
+
Projects already running keep answering on the old name until they
|
|
360
|
+
restart, since their containers were started against the previous TLD.
|
|
361
|
+
They are listed rather than restarted for you (restarting a site
|
|
362
|
+
mid-build is how a half-written database happens); `--restart-all` does
|
|
363
|
+
it when nothing is in flight.
|
|
364
|
+
|
|
365
|
+
It refuses two changes rather than half-applying them:
|
|
366
|
+
|
|
367
|
+
- **A TLD with no wildcard DNS.** `*.ddev.site` resolves to `127.0.0.1`
|
|
368
|
+
*at any depth*, which is the only reason the nested scheme above works
|
|
369
|
+
with an empty `/etc/hosts`. `/etc/hosts` cannot hold wildcards, so a
|
|
370
|
+
custom TLD needs one hand-added line per hostname, with sudo, forever —
|
|
371
|
+
and every new project 404s until someone adds it.
|
|
372
|
+
- **A first label that differs from the project name.** That is a rename,
|
|
373
|
+
not a domain change: DDEV keys its volumes on the project name, so it
|
|
374
|
+
strands the database and builds an empty one.
|
|
375
|
+
|
|
376
|
+
Both are allowed with `--force` once you mean them.
|
|
377
|
+
|
|
378
|
+
**On a Docker host or a dedicated server** the same system runs as one
|
|
379
|
+
shared **development workspace hub on a real domain** —
|
|
380
|
+
`workspace.example.com` → `dev.workspace.example.com` →
|
|
381
|
+
`myproject.dev.workspace.example.com`. There the custom TLD is the normal
|
|
382
|
+
case, not the exception, and the DNS check above passes on its own
|
|
383
|
+
because the record is real:
|
|
384
|
+
|
|
385
|
+
```
|
|
386
|
+
# 1. Point *.workspace.example.com at the host in your DNS. One wildcard
|
|
387
|
+
# record covers every workspace and every project, forever.
|
|
388
|
+
# 2. Then:
|
|
389
|
+
cd ~/workspace/products
|
|
390
|
+
bash core/scripts/autostart.sh --domain workspace.example.com
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
One more thing is needed there, and the command says so rather than
|
|
394
|
+
leaving you to find it: DDEV binds its router to `127.0.0.1`, so on a
|
|
395
|
+
server the ports are open, the DNS resolves, and every request from
|
|
396
|
+
outside times out with nothing in any log. Open it deliberately, with a
|
|
397
|
+
firewall in front:
|
|
398
|
+
|
|
399
|
+
```
|
|
400
|
+
ddev config global --router-bind-all-interfaces=true
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
That exposes **every** DDEV project on the machine, and they are dev
|
|
404
|
+
sites. Put it behind a firewall or a reverse proxy. `core/scripts/autostart.sh`
|
|
405
|
+
reports which of the two situations a machine is in, so you are never
|
|
406
|
+
guessing:
|
|
407
|
+
|
|
408
|
+
```
|
|
409
|
+
reachable : this machine only (ddev.site, router on 127.0.0.1)
|
|
410
|
+
reachable : from the network — shared hub, router on all interfaces
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Examples
|
|
414
|
+
|
|
415
|
+
Things you can do from the dashboard UI:
|
|
416
|
+
|
|
417
|
+
- `/dev` → pick **"Webship 11.0.x"** from the Build dropdown, name it
|
|
418
|
+
`blog1`, press **Build** — and watch the real terminal output stream
|
|
419
|
+
until the site is installed at `https://blog1.ddev.site`.
|
|
420
|
+
- Press **Stop** / **Start** / **Launch** on any project row (buttons follow
|
|
421
|
+
the live DDEV status), **Backup** to archive it, or open
|
|
422
|
+
`/dev/backups` to **Restore** an archive (files + automatic DB import).
|
|
423
|
+
- `/agents` → **Generate with AI** → describe the agent you want; then
|
|
424
|
+
**Install** it into `~/.claude/agents/` for Claude Code.
|
|
425
|
+
- `/docs` → write a doc, press **PDF** or **HTML** to render it, or
|
|
426
|
+
**Screenshot a site** to capture any URL into `docs/`.
|
|
427
|
+
|
|
428
|
+
Things you can ask the Webship Workspace AI Assistant (it really does them):
|
|
429
|
+
|
|
430
|
+
- "Build a Webship 11 site named webship11c1"
|
|
431
|
+
- "Create a Drupal 11.4 site called d114test"
|
|
432
|
+
- "can you back up my webship11c1 site please, then show me the backups page"
|
|
433
|
+
- "what's running right now?"
|
|
434
|
+
- "Generate an agent that reviews cmd- scripts and save it as cmd-linter"
|
|
435
|
+
- "Write a doc about demo1 and make a PDF"
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
## Building a project
|
|
439
|
+
|
|
440
|
+
```
|
|
441
|
+
cd ~/workspace/dev/
|
|
442
|
+
bash cmd-webship11-0-x-project.sh webship11c1 --install --add-users
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
### Drupal and Drupal CMS, for example:
|
|
446
|
+
```
|
|
447
|
+
cd ~/workspace/dev/
|
|
448
|
+
bash cmd-drupal11-recommended-project.sh d11c1 --install
|
|
449
|
+
bash cmd-drupalcms2-x-project.sh cms1 --install
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### Drupal CMS site templates:
|
|
453
|
+
```
|
|
454
|
+
cd ~/workspace/site-templates/
|
|
455
|
+
bash cmd-healthcare-project.sh healthcare1 --install
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
Builds Drupal CMS, requires the template package, and with `--install` installs it (answering the installer's site-template step non-interactively), then prints both URLs:
|
|
459
|
+
|
|
460
|
+
```
|
|
461
|
+
https://healthcare1.site-templates.workspace.ddev.site
|
|
462
|
+
https://healthcare1.ddev.site
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
One command per free template from [new.drupal.org/browse/site-templates](https://new.drupal.org/browse/site-templates): `healthcare`, `byte`, `haven`, `archimedes`, `everbright`, `provus_edu`, `convene`, `caresphere`, `convivial_gov`, `mercury_demo`, `local`, plus the four Webship ones below (`haven`, `website_starter`, `pulse`, `website_starter`). Without `--install` the build stops at the codebase and you pick the template in the browser installer. See [`site-templates/README.md`](../../../site-templates/README.md).
|
|
466
|
+
|
|
467
|
+
### Webship site templates (Website Starter, Website Starter, Haven, Pulse)
|
|
468
|
+
|
|
469
|
+
The Drupal CMS installer lists all four (Website Starter's card is named "Webship") and downloads the package when one is picked, so a stock Drupal CMS is enough:
|
|
470
|
+
|
|
471
|
+
```
|
|
472
|
+
ddev config --project-type=drupal11 --docroot=web
|
|
473
|
+
ddev composer create-project drupal/cms
|
|
474
|
+
ddev launch # then pick the template
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
```
|
|
478
|
+
cd ~/workspace/dev/
|
|
479
|
+
bash cmd-drupalcms2-x-website_starter1-0-0-project.sh website_starter1 # on Drupal CMS, released line, pick it in the browser
|
|
480
|
+
bash cmd-drupalcms2-x-website_starter1-0-0-project.sh website_starter1 --install # on Drupal CMS, released line, installed by drush
|
|
481
|
+
bash cmd-website_starter1-0-0-project.sh website_starter2 # on Webship ~11, released line
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Every folder that builds sites carries each template on both bases its project page publishes, one builder per line: `1-0-0` is the released template (`~1`) and `1-0-x` the development branch (`1.0.x-dev`). Pulse has `1-0-0` on Drupal CMS only; its Webship builders are `1-0-x`.
|
|
485
|
+
|
|
486
|
+
| | Drupal CMS — `cmd-drupalcms2-x-<template>1-0-?-project.sh` | Webship — `cmd-<template>1-0-?-project.sh` |
|
|
487
|
+
| --- | --- | --- |
|
|
488
|
+
| Base | `drupal/cms`, PHP 8.4 | `drupal/webship_project:~11` for the released lines, `11.0.x-dev` for the development lines, PHP 8.4 |
|
|
489
|
+
| Released line | nothing required, the installer fetches it; `--install` requires `drupal/<template>:~1`, the root's stability left as shipped | `drupal/<template>:~1` |
|
|
490
|
+
| Development line | `minimum-stability dev`, then `drupal/<template>:1.0.x-dev` | `drupal/<template>:1.0.x-dev` |
|
|
491
|
+
|
|
492
|
+
Without `--install` a builder stops at a codebase and prints the installer URL; with it the site template is installed non-interactively. A `composer` step that fails stops the build with the resolver output, rather than reporting the site as ready.
|
|
493
|
+
|
|
494
|
+
`test/` also carries `cmd-automated-testing-<template>1-0-?-project.sh` for Website Starter, Haven and Pulse, which add the Playwright suite on top of the same build.
|
|
495
|
+
|
|
496
|
+
Run any builder with `--help` for its full argument list.
|
|
497
|
+
|
|
498
|
+
Each of these scripts creates the project folder, runs `ddev config` + `ddev start`, then `ddev composer create-project` and `ddev drush site:install` inside that project's own containers.
|
|
499
|
+
|
|
500
|
+
## Agents, skills and prompts: three sources
|
|
501
|
+
|
|
502
|
+
`agents/`, `skills/` and `prompts/` show what you have here, what is installed in `~/.claude` (what a Claude Code session actually loads), and what is in [webship/ai-agents](https://github.com/webship/ai-agents) — merged into one list, so it is obvious what is only a draft, only installed, or only shared.
|
|
503
|
+
|
|
504
|
+
```
|
|
505
|
+
cd ~/workspace/ai-skills/
|
|
506
|
+
bash cmd-tools-ai-items.sh # the three counts
|
|
507
|
+
bash cmd-tools-ai-items.sh --list-remote # what the shared repo has
|
|
508
|
+
bash cmd-tools-ai-items.sh webship-install --fetch # repo -> ~/.claude (use it now)
|
|
509
|
+
bash cmd-tools-ai-items.sh webship-install --pull # repo -> here (read or edit it)
|
|
510
|
+
bash cmd-tools-ai-items.sh --pull --source claude # this machine -> here (webship-* only)
|
|
511
|
+
bash cmd-tools-ai-items.sh my-draft --install # here -> ~/.claude
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
Omit the name to act on all of them. On the dashboard the same rows carry **installed** / **workspace only** / **shared** labels, and anything that exists only in the shared repo gets **Fetch to ~/.claude** and **Copy here to edit** buttons. Restart your Claude Code session to pick up a fetch.
|
|
515
|
+
|
|
516
|
+
Sharing the other way — a draft here becoming a PR on dev-ai-agents — stays a deliberate act through the issue/PR agents, never automatic.
|
|
517
|
+
|
|
518
|
+
## GitLab CI locally (the green-gate)
|
|
519
|
+
|
|
520
|
+
Before pushing anything to git.drupalcode.org, the pipeline runs locally:
|
|
521
|
+
|
|
522
|
+
```
|
|
523
|
+
cd ~/workspace/modules/
|
|
524
|
+
bash cmd-tools-gitlab-ci-local.sh <project> --doctor # setup check (installs the drupal-ci-local wrapper)
|
|
525
|
+
bash cmd-tools-gitlab-ci-local.sh <project> --list # what jobs exist
|
|
526
|
+
bash cmd-tools-gitlab-ci-local.sh <project> phpcs # one job
|
|
527
|
+
bash cmd-tools-gitlab-ci-local.sh <project> --slim # the project's .gitlab-ci-local.yml subset
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
Green = push; red = fix first, never mask with `allow_failure` or `|| true`. Note: the **full** drupal/gitlab_templates pipeline currently cannot run under gitlab-ci-local at all ([firecow/gitlab-ci-local#1893](https://github.com/firecow/gitlab-ci-local/issues/1893) — the templates' `$variable`-in-regex rules crash its evaluator on every ref). The command detects that crash and explains it; until it's fixed upstream, `--slim` is the runnable path and template-only jobs gate on the remote pipeline.
|
|
531
|
+
|
|
532
|
+
## Upsun: the cloud side of a project
|
|
533
|
+
|
|
534
|
+
Workspace projects run locally on DDEV and, when they graduate, on [Upsun](https://upsun.com) — client demos, sandboxes, the public Webship demo. `cmd-tools-upsun.sh` in the `projects`, `demos` and `sandboxes` workspaces is the bridge:
|
|
535
|
+
|
|
536
|
+
```
|
|
537
|
+
cd ~/workspace/demos/
|
|
538
|
+
bash cmd-tools-upsun.sh dcms2b1 # status: linked ID, environments
|
|
539
|
+
bash cmd-tools-upsun.sh mydemo --link abc123xyz # upsun project:set-remote
|
|
540
|
+
bash cmd-tools-upsun.sh mydemo --init # scaffold .upsun/config.yaml
|
|
541
|
+
bash cmd-tools-upsun.sh mydemo --push # deploy the current branch
|
|
542
|
+
bash cmd-tools-upsun.sh mydemo --activities # last 10 Upsun activities
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
The default is read-only status. `--link` refuses to silently relink a project that already points at a different Upsun ID (use `--force`), `--push` goes through upsun's own confirmation, and nothing here ever creates or deletes an Upsun project or environment. The `upsun` CLI must be installed and authenticated (`upsun auth:browser-login`); the tool tells you how if it is missing.
|
|
546
|
+
|
|
547
|
+
Upsun's official AI toolkit ([upsun/ai](https://github.com/upsun/ai), MIT) complements this: an `upsun` agent skill with per-framework `.upsun/config.yaml` starters (including Drupal), a Claude Code plugin (`/plugin marketplace add upsun/ai`), and an MCP server (`claude mcp add --transport http upsun https://mcp.upsun.com/mcp` — token via the `upsun-api-token` header, writes disabled by default). The LLM-readable doc index is [developer.upsun.com/llms.txt](https://developer.upsun.com/llms.txt). For CI, use an API token with `UPSUN_CLI_NO_INTERACTION=1`.
|
|
548
|
+
|
|
549
|
+
## Syncing the tooling after a merged PR
|
|
550
|
+
|
|
551
|
+
Two checkouts exist: `~/workspace/products/workspace` is the git clone where commits and PRs happen, `~/workspace` is the live tree where projects are built. After a PR merges, pull the clone and copy the tooling across:
|
|
552
|
+
|
|
553
|
+
```
|
|
554
|
+
cd ~/workspace/products/
|
|
555
|
+
bash core/scripts/sync-tooling.sh --pull
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
That syncs `core/scripts`, the per-workspace settings files, `core/workspace-app`, and every workspace folder's `cmd-*.sh` / `README.md` / `*.code-workspace`; prunes commands the clone no longer ships; and runs the smoke test. Built project content is never touched. `--dry-run` shows what would change.
|
|
559
|
+
|
|
560
|
+
`core/config/settings.yml` is deliberately **not** synced — your copy holds the real account password and API keys, while the committed one ships `CHANGE_ME` placeholders. The command reports any workspace missing from your `workspaces:` list instead of editing the file.
|
|
561
|
+
|
|
562
|
+
If the dashboard's `.ddev/` config or Dockerfile changed, finish with `ddev restart` in `~/workspace/core/workspace-app`; for a `server.js` change alone, `docker exec ddev-workspace-web supervisorctl restart webextradaemons:workspace-app` is enough.
|
|
563
|
+
|
|
564
|
+
## Knowledge graph of a project (graphify)
|
|
565
|
+
|
|
566
|
+
[graphify](https://github.com/Graphify-Labs/graphify) parses a project with tree-sitter into a knowledge graph you query instead of grepping — local, deterministic, no vector store. Every project workspace has a `cmd-tools-graphify.sh`:
|
|
567
|
+
|
|
568
|
+
```
|
|
569
|
+
cd ~/workspace/dev/
|
|
570
|
+
bash cmd-tools-graphify.sh webship11c1
|
|
571
|
+
bash cmd-tools-graphify.sh webship11c1 --query "what does this controller depend on?"
|
|
572
|
+
```
|
|
573
|
+
|
|
574
|
+
It writes `webship11c1/graphify-out/` — `graph.html` (clickable graph), `GRAPH_REPORT.md` (key concepts, suggested questions) and `graph.json` (queried by `graphify query|path|explain|god-nodes`). The default pass is code-only: local AST, no API key, nothing leaves the machine.
|
|
575
|
+
|
|
576
|
+
**What it covers on a Drupal project, honestly.** graphify maps PHP classes under `src/` — methods, `use` imports, `extends`, `implements`, trait `use`, and constructor-injected services — plus JS, SQL and Markdown. It does **not** cover hooks in `*.module` / `*.theme` / `*.install` (those extensions are not in its dispatch table), Twig templates, or the Drupal wiring YAML (`*.info.yml`, `*.services.yml`, `*.routing.yml`, `*.component.yml`, `recipe.yml`), and it has no PHP-attribute support, so plugin-id → class never appears. Useful for "what does this service depend on"; no use for "which route hits this controller". `--deep` adds a semantic pass over docs and PDFs but does not close that gap — it builds a parallel document graph.
|
|
577
|
+
|
|
578
|
+
Third-party trees (`vendor/`, `core/`, `contrib`, `libraries`, `node_modules`) are skipped by default. On a Webship 11 build that is the difference between 1,236 nodes in 11s and 20,618 nodes in 139s, 84% of them vendored JS. `--all` disables the skipping, `--exclude` adds more paths.
|
|
579
|
+
|
|
580
|
+
The CLI is installed on first use (`uv tool install graphifyy==0.9.28`), and it ships in the dashboard image. On the dashboard, every project row has a **Graph** button and, once a graph exists, **Open graph** and **Report** links. `graph.html` loads vis-network from unpkg.com, so it needs internet to render.
|
|
581
|
+
|
|
582
|
+
## Second storage: workspaces on another disk
|
|
583
|
+
|
|
584
|
+
A workspace without DDEV projects can live on another disk as a symlink. Set the folder on that disk in `core/config/settings.yml` (per machine, never synced):
|
|
585
|
+
|
|
586
|
+
```yaml
|
|
587
|
+
storage:
|
|
588
|
+
second: /mnt/workspace-storage/workspace
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
```
|
|
592
|
+
bash core/scripts/storage.sh # status: local or second storage, links, free space
|
|
593
|
+
bash core/scripts/storage.sh --move videos # copy, verify by checksum, swap to a symlink
|
|
594
|
+
bash core/scripts/storage.sh --remove-pre-move videos # free the kept local copy
|
|
595
|
+
bash core/scripts/storage.sh --back videos # the reverse; the drive copy is kept
|
|
596
|
+
bash core/scripts/storage.sh --mounts # let the dashboard container follow the links
|
|
597
|
+
bash core/scripts/storage.sh --relink --mounts # after the drive got a new mount point
|
|
598
|
+
```
|
|
599
|
+
|
|
600
|
+
`--mounts` writes `core/workspace-app/.ddev/docker-compose.second-storage.yaml`; restart the dashboard (`ddev restart` in `core/workspace-app`) when it says so, once no build is running. `--dry-run` says what would happen. On a `/run/media` automount, the status prints an fstab line by UUID to a fixed mount point: run it with sudo yourself.
|
|
601
|
+
|
|
602
|
+
## Removing / backing up a project
|
|
603
|
+
|
|
604
|
+
```
|
|
605
|
+
cd ~/workspace/dev/
|
|
606
|
+
bash cmd-tools-remove.sh myproject
|
|
607
|
+
bash cmd-tools-backup-dev.sh myproject
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
`cmd-tools-remove.sh` runs `ddev delete -y -O` before removing the folder. `cmd-tools-backup-*.sh` tars the project folder and runs `ddev export-db` for the database dump — no host MySQL client involved.
|
|
611
|
+
|
|
612
|
+
## Add your own commands
|
|
613
|
+
|
|
614
|
+
The dashboard's **Commands** page (`/commands`, in the rail) is where commands are added, and most need no script at all.
|
|
615
|
+
|
|
616
|
+
### A command
|
|
617
|
+
|
|
618
|
+
A command is one line and what it runs on: a workspace folder, a project, a folder or a file. Add one from **Commands → New**, or in `core/config/commands.yml`. The built-in commands ship in `core/workspace-app/commands/defaults.yml`, and one of yours with a built-in id replaces it.
|
|
619
|
+
|
|
620
|
+
```yaml
|
|
621
|
+
commands:
|
|
622
|
+
- id: rebuild-caches
|
|
623
|
+
label: Rebuild caches
|
|
624
|
+
group: Drupal
|
|
625
|
+
on: project # workspace | project | folder | file
|
|
626
|
+
when: [ddev, composer] # which folders it is for; ! negates, workspace:<name> names one
|
|
627
|
+
run: ddev drush cr
|
|
628
|
+
- id: php-lint
|
|
629
|
+
label: Check PHP syntax
|
|
630
|
+
on: file
|
|
631
|
+
when: [ddev]
|
|
632
|
+
run: ddev exec --dir /var/www/html php -l {{file}}
|
|
633
|
+
- id: switch-to-branch
|
|
634
|
+
label: Switch to a branch
|
|
635
|
+
on: project
|
|
636
|
+
when: [git]
|
|
637
|
+
confirm: true # ask in a dialog before it runs
|
|
638
|
+
options:
|
|
639
|
+
- { name: branch, value: main, regex: '^[A-Za-z0-9._/-]+$', required: true }
|
|
640
|
+
run: git fetch --prune && git switch {{opt.branch}}
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
A line gets values only as `{{workspace}}`, `{{project}}`, `{{folder}}`, `{{file}}`, `{{path}}` and `{{opt.<name>}}`, each single-quoted for you, and it cannot contain `$` or a backtick. **Run** asks for the workspace, the project and the folder or file, and runs the command in a screen session. **Definition** shows your commands as YAML, and **Check** says what loading a pasted list would change.
|
|
644
|
+
|
|
645
|
+
### A script, when one line is not enough
|
|
646
|
+
|
|
647
|
+
**Commands → New → New script** (or **Generate a script with AI**) scaffolds a `cmd-*.sh` in the workspace folder it belongs to, and so does the CLI:
|
|
648
|
+
|
|
649
|
+
```bash
|
|
650
|
+
bash ~/workspace/commands/cmd-tools-commands.sh --new cmd-tools-list-sites.sh --workspace dev --label "List Sites"
|
|
651
|
+
```
|
|
652
|
+
|
|
653
|
+
The scaffold already has what every command needs:
|
|
654
|
+
- the `# workspace-name:` header that the smoke test and the Build dropdown read;
|
|
655
|
+
- a bootstrap that finds `core/scripts` from the script's own path, so a fresh clone needs no setup;
|
|
656
|
+
- the workspace's settings;
|
|
657
|
+
- an `argparse` block.
|
|
658
|
+
|
|
659
|
+
Write what it does (DDEV only: `ddev composer`, `ddev drush`, `ddev export-db`), then check it:
|
|
660
|
+
|
|
661
|
+
```bash
|
|
662
|
+
bash ~/workspace/core/scripts/tests/cmd-smoke-test.sh
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
Settings of your own go in YAML and are read as shell variables: `eval $(parse_yaml path/to/file.yml)` turns `distribution.webroot` into `$distribution_webroot`. The scripts under `dev/`, `themes/` and `profiles/` are the examples to read. Every script is listed on the Commands page with a page of its own, where **Use in a command** makes a command that calls it (`script: dev/cmd-tools-list-sites.sh`, `args: '{{project}}'`).
|
|
666
|
+
|
|
667
|
+
### On a project row
|
|
668
|
+
|
|
669
|
+
A command can go on any button of the project rows: **Add to a button** on its page, or **Use a command** under **Commands → Buttons → Add an action**. The steps of an action, kept in `core/config/row-actions.yml`, can mix command lines with `use: <command id>`:
|
|
670
|
+
|
|
671
|
+
```yaml
|
|
672
|
+
custom:
|
|
673
|
+
- id: refresh-the-site
|
|
674
|
+
label: Refresh the site
|
|
675
|
+
button: ddev
|
|
676
|
+
group: Drupal
|
|
677
|
+
when: [ddev, composer]
|
|
678
|
+
steps:
|
|
679
|
+
- use: git-switch-branch
|
|
680
|
+
- ddev composer install
|
|
681
|
+
- use: drush-update-database
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
A used command runs on the row's project, asks for its own options, and keeps its own `when`.
|