@webship.co/workspace-joomla 0.0.0-stage → 1.0.8

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.
@@ -0,0 +1,230 @@
1
+ ---
2
+ name: joomla-scenarios
3
+ description: Write and run webship-js scenarios for a Joomla site of the Webship Workspace with the Joomla step pack (`@webship-js/joomla-steps`) — the phrases of the pack by area (the administrator and its pages, lists and content, users and groups, the public site, the site login, search), the handles of the users registry, and the workspace command that runs them in the site's container. Use when asked to "write a scenario for this Joomla site", "test the manager account", "which step is there for an article", "add a feature for the search", or when a `.feature` file of a Joomla project is being written or fixed.
4
+ argument-hint: '<site> [what to cover]'
5
+ ---
6
+
7
+ # joomla-scenarios
8
+
9
+ Scenarios for a Joomla site of a Webship Workspace (`~/workspace`, container-based, DDEV by
10
+ default), written from the steps of [`@webship-js/joomla-steps`](https://github.com/webship/joomla-steps)
11
+ and of [webship-js](https://github.com/webship/webship-js) itself, and run in the site's container
12
+ by the workspace's own command. It comes with the Joomla plugin (`@webship.co/workspace-joomla`),
13
+ like the builder (`cmd-joomla-project.sh`), the CLI tool (`cmd-tools-joomla-cli.sh`) and the
14
+ agents `joomla-site-builder` and `joomla-tester`.
15
+
16
+ ## Where everything is
17
+
18
+ | What | Where |
19
+ | --- | --- |
20
+ | The site | `~/workspace/<folder>/<site>`, at `https://<site>.ddev.site`, the administrator at `/administrator` (`<folder>` is a sites folder: `dev`, `test`, `sandboxes`, `demos`) |
21
+ | The suite's configuration | `<site>/cucumber.js`: the step definitions it loads and the users registry (`worldParameters.users`) |
22
+ | The features | `<site>/tests/features/*.feature` (`site.feature` is the first one the setup wrote) |
23
+ | The pack's steps | `<site>/node_modules/@webship-js/joomla-steps/tests/step-definitions/*.steps.js` |
24
+ | webship-js's steps | `<site>/node_modules/webship-js/tests/step-definitions/*.js` |
25
+ | The reports | `<site>/tests/reports/` |
26
+
27
+ ## The order of work
28
+
29
+ 1. **Make sure the testing stack is there.** From the sites folder:
30
+ ```bash
31
+ cd ~/workspace/<folder>
32
+ bash cmd-tools-testing.sh <site>
33
+ ```
34
+ It adds webship-js, the step pack, the users registry and `tests/features/site.feature`, and
35
+ makes sure the default accounts are on the site. It is safe to run again: it adds what is
36
+ missing and keeps what was changed.
37
+ 2. **Read the installed steps before writing a phrase.** They are the source of truth: the pack
38
+ moves, and a phrase from memory is a guess.
39
+ ```bash
40
+ cd ~/workspace/<folder>/<site>
41
+ grep -hE "^(Given|When|Then)\(" node_modules/@webship-js/joomla-steps/tests/step-definitions/*.steps.js
42
+ ```
43
+ Every step carries a comment block with examples above it; open the file when a phrase is not
44
+ obvious.
45
+ 3. **Look at the page first** (the Playwright MCP browser, a tab of your own) when the scenario
46
+ is about a page you have not seen. A scenario written without having seen the page asserts
47
+ what you imagine.
48
+ 4. **Write the feature** in `<site>/tests/features/`, from phrases that exist (the lists below).
49
+ 5. **Match every step without a browser**, then run the feature, then the suite:
50
+ ```bash
51
+ cd ~/workspace/<folder>
52
+ bash cmd-tools-testing.sh <site> --dry-run --path tests/features/<name>.feature
53
+ bash cmd-tools-testing.sh <site> --run --path tests/features/<name>.feature
54
+ bash cmd-tools-testing.sh <site> --run --tags "@critical"
55
+ bash cmd-tools-testing.sh <site> --run
56
+ ```
57
+ A dry run says `Undefined` for a phrase no definition matches: fix the phrase, do not write a
58
+ step for it.
59
+
60
+ ## Accounts: a handle, never a password
61
+
62
+ A scenario logs in by a handle of the users registry. The administrator and the site have a
63
+ login each, and a step for each. The default accounts are on the site already
64
+ (`bash cmd-tools-joomla-cli.sh <site> --add-users` adds them again if they were removed):
65
+
66
+ | Handle | Account | User group | Logs in to |
67
+ | --- | --- | --- | --- |
68
+ | `admin` | `administrator` | Super Users | the administrator and the site |
69
+ | `manager` | `manager` | Manager | the administrator and the site |
70
+ | `editor` | `editor` | Editor | the site |
71
+ | `member` | `member` | Registered | the site |
72
+
73
+ ```gherkin
74
+ Given I am a logged in user with the "manager" user
75
+ Then I should see the administrator dashboard
76
+ Given I am logged in to the site with the "member" user
77
+ Then I should be logged in to the site as "member"
78
+ ```
79
+
80
+ ## The phrases, by area
81
+
82
+ Each line is a phrase the pack defines, and each one passed on a site built with
83
+ `bash cmd-joomla-project.sh <site> --install --add-users --sample-data` (the names in quotes are
84
+ that site's). Most `should` steps also take the negative: `should not see`, `should not be`,
85
+ `should not exist`.
86
+
87
+ ### The administrator: session, pages, menu
88
+
89
+ ```gherkin
90
+ Given I am on the administrator login page
91
+ Given I am a logged in user with the "manager" user
92
+ When I log out of the administrator panel
93
+ Then I should be on the administrator login page
94
+ Then I should see the administrator dashboard
95
+ Then I should be logged in to the administrator panel as "Manager"
96
+ Then I should see the administrator menu
97
+ Then I should see the administrator menu item "Content"
98
+ Then I should not see the administrator menu item "System"
99
+ When I go to the administrator "Articles" page
100
+ Then I should be on the administrator "Articles" page
101
+ Then I should see the administrator page title "Articles"
102
+ Then I should see the "New" toolbar button
103
+ ```
104
+
105
+ ### Lists and content
106
+
107
+ ```gherkin
108
+ When I create an article titled "An article written by a scenario" with the text "Written by the suite."
109
+ Then the article "An article written by a scenario" should exist
110
+ Then the article "An article written by a scenario" should be published
111
+ When I unpublish the article "An article written by a scenario"
112
+ When I trash the article "An article written by a scenario"
113
+ Then the article "An article written by a scenario" should be trashed
114
+ When I delete the article "An article written by a scenario" permanently
115
+ When I create a category titled "A category written by a scenario"
116
+ When I trash the category "A category written by a scenario"
117
+ When I delete the category "A category written by a scenario" permanently
118
+ When I create a menu titled "A menu written by a scenario"
119
+ Then the menu "A menu written by a scenario" should exist
120
+ When I delete the menu "A menu written by a scenario"
121
+ When I search the list for "no such article anywhere"
122
+ Then I should see an empty list
123
+ Then I should see a success message
124
+ ```
125
+
126
+ ### Users, groups and the system
127
+
128
+ ```gherkin
129
+ Then the user "manager" should exist
130
+ Then the user "manager" should be in the "Manager" group
131
+ Then the access level "Special" should include the "Manager" group
132
+ Then the group "Manager" should have 1 enabled user
133
+ When I clear all caches
134
+ Then there should not be checked out items
135
+ ```
136
+
137
+ ### The public site, its login and the search
138
+
139
+ ```gherkin
140
+ Given I am on the login page
141
+ Given I am on the password reset page
142
+ Given I am on the username reminder page
143
+ Given I am on the profile page
144
+ Then I should see the login form
145
+ Then I should see the password reset form
146
+ Then I should see the username reminder form
147
+ Given I am logged in to the site with the "member" user
148
+ When I log out of the site
149
+ Then I should be logged in to the site as "member"
150
+ Then I should not be logged in to the site
151
+ Then I should see the "Blog" menu item
152
+ When I open the "Blog" menu item
153
+ Then the breadcrumb should show "Home > Blog"
154
+ Then I should see no system messages
155
+ When I search the site for a word from the first article
156
+ Then I should see that word in the search results
157
+ Then I should see at least 1 search result
158
+ When I search the site for "nosuchwordanywhere"
159
+ Then I should see no search results
160
+ ```
161
+
162
+ `I am an anonymous user`, `I am on the homepage`, `the page should have a title`,
163
+ `I should see "<text>"` and `the response status code should be 200` are webship-js's own steps;
164
+ its status codes, classes, landmarks and accessibility audits are used as they are and never
165
+ redefined for this platform.
166
+
167
+ ## Traps found on a real site
168
+
169
+ - **Two logins, two steps.** `I am a logged in user with the "<handle>" user` is the
170
+ administrator's login, `I am logged in to the site with the "<handle>" user` the site's.
171
+ `editor` and `member` have no administrator: use the site's step for them.
172
+ - **The administrator shows the account's name, not its username.**
173
+ `I should be logged in to the administrator panel as "manager"` fails; the header says
174
+ `Manager`. The site's step (`logged in to the site as "member"`) takes the handle, and the user
175
+ steps (`the user "manager" should be in the "Manager" group`) take the username.
176
+ - **A page a group may not open answers 403**: a manager on the administrator `"Users"` page.
177
+ Assert the status code; the administrator menu of a manager does not list `System` either.
178
+ - **The breadcrumb is the whole trail**: `Home > Blog`, not `Blog`.
179
+ - **The search step needs a page that lists articles first.**
180
+ `I search the site for a word from the first article` reads the word from the page on screen:
181
+ open the homepage before it.
182
+ - **What the sample data brings is not on every site.** The `Blog` menu item, the articles and
183
+ the search index are there only when the site was built with `--sample-data`. A site built
184
+ without it has an empty front page: a scenario about them fails there.
185
+ - **Trashing is not deleting.** A trashed article or category is still on the site:
186
+ `I delete the article "<title>" permanently` after the trash step, or the next run finds it.
187
+ - **`I check in all items` fails when nothing is checked out.** Assert
188
+ `there should not be checked out items` instead, and check in only after a scenario left a
189
+ form open.
190
+ - **Two phrases of the pack name the platform** (the version and the "running" check). They
191
+ break the rule below: leave them out of a suite, and read the version with
192
+ `bash cmd-tools-joomla-cli.sh <site>`.
193
+
194
+ ## Rules
195
+
196
+ - **No account is created in a suite.** No `user:add` in a hook, no registration scenario that
197
+ leaves an account behind. A group the registry does not have is asked for, not made.
198
+ - **Never the workspace account.** The site's own Super User is not in the registry; `admin` is
199
+ the `administrator` default account.
200
+ - **No password in a feature file**, except where a wrong password is the subject.
201
+ - **No platform name in a step phrase**: `I am on the administrator login page`, never a phrase
202
+ that names the platform. The same holds for a custom step.
203
+ - **No selector and no address when a step says it**: `the administrator "Users" page`, not the
204
+ address of the page.
205
+ - **What a scenario creates, it removes** in the same scenario, under a title nobody else uses.
206
+ - **A custom step is the last resort**: look in the pack and in webship-js first, write it in
207
+ `<site>/tests/step-definitions/` with a comment block and examples, and say it may belong in
208
+ the pack.
209
+ - **Everything runs in the container**, through `cmd-tools-testing.sh`. Never `npx cucumber-js`
210
+ or `npx playwright` on the host.
211
+ - **A failing scenario is a result.** No `@wip`, no longer timeout, no looser assertion to turn a
212
+ run green: say what the site did.
213
+
214
+ ## Examples that run
215
+
216
+ `examples/` holds three features that pass on a site built with
217
+ `bash cmd-joomla-project.sh <site> --install --add-users --sample-data`. Copy one into the suite
218
+ and run it:
219
+
220
+ ```bash
221
+ cp ~/workspace/ai-skills/joomla-scenarios/examples/groups-and-pages.feature ~/workspace/<folder>/<site>/tests/features/
222
+ cd ~/workspace/<folder>
223
+ bash cmd-tools-testing.sh <site> --run --path tests/features/groups-and-pages.feature
224
+ ```
225
+
226
+ | Feature | What it shows |
227
+ | --- | --- |
228
+ | `examples/groups-and-pages.feature` | Each default account logging in where its group may, the menu and the pages of a manager, the groups and access levels |
229
+ | `examples/article-lifecycle.feature` | A manager writing, unpublishing, trashing and deleting an article; a category and a menu added and deleted |
230
+ | `examples/site-and-search.feature` | The menu, the breadcrumb, the account pages and the search of the public site (needs `--sample-data`) |
@@ -0,0 +1,36 @@
1
+ Feature: A manager writes an article and removes it again
2
+ As a manager
3
+ I want to write, unpublish, trash and delete an article
4
+ So that the suite proves the content screens work and leaves the site as it found it
5
+
6
+ # Trashing is not deleting: the scenario deletes permanently, or the next run finds the item.
7
+
8
+ Scenario: The manager writes an article, takes it down and deletes it
9
+ Given I am a logged in user with the "manager" user
10
+ When I create an article titled "An article written by a scenario" with the text "This article is written and removed by the suite."
11
+ Then I should see a success message
12
+ And the article "An article written by a scenario" should be published
13
+ When I unpublish the article "An article written by a scenario"
14
+ Then the article "An article written by a scenario" should be unpublished
15
+ When I trash the article "An article written by a scenario"
16
+ Then the article "An article written by a scenario" should be trashed
17
+ When I delete the article "An article written by a scenario" permanently
18
+ Then the article "An article written by a scenario" should not exist
19
+
20
+ Scenario: An administrator adds a category and a menu and deletes them
21
+ Given I am a logged in user with the "admin" user
22
+ When I create a category titled "A category written by a scenario"
23
+ Then the category "A category written by a scenario" should exist
24
+ When I trash the category "A category written by a scenario"
25
+ And I delete the category "A category written by a scenario" permanently
26
+ Then the category "A category written by a scenario" should not exist
27
+ When I create a menu titled "A menu written by a scenario"
28
+ Then the menu "A menu written by a scenario" should exist
29
+ When I delete the menu "A menu written by a scenario"
30
+ Then the menu "A menu written by a scenario" should not exist
31
+
32
+ Scenario: A search of the list that finds nothing shows an empty list
33
+ Given I am a logged in user with the "manager" user
34
+ When I go to the administrator "Articles" page
35
+ And I search the list for "no such article anywhere"
36
+ Then I should see an empty list
@@ -0,0 +1,41 @@
1
+ Feature: Each account reaches what its user group may use
2
+ As the owner of the site
3
+ I want every default account to log in where its group may and to be refused the rest
4
+ So that a change of permissions is caught by the suite
5
+
6
+ # The accounts are the default ones; a scenario logs in by a handle of the users registry.
7
+ # The administrator and the site have a login each, and a step for each.
8
+
9
+ Scenario: A manager gets the administrator, with the menu of a manager
10
+ Given I am a logged in user with the "manager" user
11
+ Then I should see the administrator dashboard
12
+ And I should be logged in to the administrator panel as "Manager"
13
+ And I should see the administrator menu item "Content"
14
+ And I should not see the administrator menu item "System"
15
+
16
+ Scenario: A manager opens the articles and is refused the users
17
+ Given I am a logged in user with the "manager" user
18
+ When I go to the administrator "Articles" page
19
+ Then the response status code should be 200
20
+ And I should see the "New" toolbar button
21
+ When I go to the administrator "Users" page
22
+ Then the response status code should be 403
23
+
24
+ Scenario: An editor logs in to the site and has no administrator
25
+ Given I am logged in to the site with the "editor" user
26
+ Then I should be logged in to the site as "editor"
27
+ Given I am on the administrator login page
28
+ Then I should not see the administrator dashboard
29
+
30
+ Scenario: The groups and the access levels are the ones the accounts rely on
31
+ Given I am a logged in user with the "admin" user
32
+ Then the user "manager" should be in the "Manager" group
33
+ And the user "member" should not be in the "Manager" group
34
+ And the access level "Special" should include the "Manager" group
35
+ And the group "Manager" should have 1 enabled user
36
+
37
+ Scenario: A visitor is asked to log in before the profile
38
+ Given I am not logged in
39
+ And I am on the profile page
40
+ Then I should see the login form
41
+ And I should not be logged in to the site
@@ -0,0 +1,33 @@
1
+ Feature: A visitor finds their way around the site
2
+ As a visitor
3
+ I want the menu, the breadcrumb, the account pages and the search to work
4
+ So that a broken template or search index is caught by the suite
5
+
6
+ # For a site built with --sample-data: the "Blog" menu item, the articles and the search index
7
+ # come from the blog sample data. On a site built without it these scenarios fail.
8
+
9
+ Scenario: The menu leads to the blog, and the breadcrumb says where
10
+ Given I am an anonymous user
11
+ And I am on the homepage
12
+ Then the response status code should be 200
13
+ And I should see the "Blog" menu item
14
+ And I should see no system messages
15
+ When I open the "Blog" menu item
16
+ Then the breadcrumb should show "Home > Blog"
17
+
18
+ Scenario: The account pages are served with their forms
19
+ Given I am on the login page
20
+ Then I should see the login form
21
+ Given I am on the password reset page
22
+ Then I should see the password reset form
23
+ Given I am on the username reminder page
24
+ Then I should see the username reminder form
25
+
26
+ Scenario: The search finds a word of an article, and nothing for a word nobody wrote
27
+ Given I am an anonymous user
28
+ And I am on the homepage
29
+ When I search the site for a word from the first article
30
+ Then I should see that word in the search results
31
+ And I should see at least 1 search result
32
+ When I search the site for "nosuchwordanywhere"
33
+ Then I should see no search results
@@ -0,0 +1,33 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # workspace-name: Joomla (latest)
4
+
5
+ # Installed by the Joomla plugin (plugins.sh --install joomla); __WORKSPACE__ is the workspace it was installed into.
6
+ #
7
+ # Build a Joomla site in a container: the latest stable release, or the one --version names, at
8
+ # https://<name>.ddev.site. With --install the site is installed with the workspace account as its
9
+ # Super User; with --add-users it also gets the default accounts, one per user group.
10
+
11
+ # Bootstrap.
12
+ # Find the workspace tooling from this script, so a fresh clone needs no setup.
13
+ WORKSPACE_SCRIPTS="${WORKSPACE_SCRIPTS:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../core/scripts" && pwd)}";
14
+ source ${WORKSPACE_SCRIPTS}/bootstrap.sh || exit 1 ;
15
+
16
+ # Load workspace settings.
17
+ eval $(parse_yaml ${WORKSPACE_CONFIG}/workspace.__WORKSPACE__.settings.yml);
18
+
19
+ # Set site version.
20
+ site_version="latest";
21
+
22
+ # Distribution.
23
+ distribution_name="joomla";
24
+ distribution_title="Joomla";
25
+ distribution_webroot="public";
26
+
27
+ ARGPARSE_DESCRIPTION="Build a ${distribution_title} project in __WORKSPACE__"
28
+ # The args file comes with the plugin: core/scripts/plugins/joomla/ is where plugins.sh --install puts it.
29
+ source ${WORKSPACE_SCRIPTS}/plugins/joomla/args/arg-joomla.sh || exit 1 ;
30
+
31
+ shift $#;
32
+
33
+ joomla_build ;
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Installed by the Joomla plugin (plugins.sh --install joomla); __WORKSPACE__ is the workspace it was installed into.
4
+ #
5
+ # The Joomla CLI (cli/joomla.php) for one Joomla project of this workspace, in its container: say
6
+ # what the site is, run a CLI command, update the core, look for updates, add or remove the default
7
+ # accounts. Nothing here runs on the host.
8
+
9
+ # Bootstrap.
10
+ # Find the workspace tooling from this script, so a fresh clone needs no setup.
11
+ WORKSPACE_SCRIPTS="${WORKSPACE_SCRIPTS:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../core/scripts" && pwd)}";
12
+ source ${WORKSPACE_SCRIPTS}/bootstrap.sh || exit 1 ;
13
+
14
+ # Load workspace settings.
15
+ eval $(parse_yaml ${WORKSPACE_CONFIG}/workspace.__WORKSPACE__.settings.yml);
16
+
17
+ # Distribution.
18
+ distribution_name="joomla";
19
+
20
+ ARGPARSE_DESCRIPTION="Run the Joomla CLI on a Joomla project of __WORKSPACE__: status, a command, updates, the default accounts"
21
+ # The args file comes with the plugin: core/scripts/plugins/joomla/ is where plugins.sh --install puts it.
22
+ source ${WORKSPACE_SCRIPTS}/plugins/joomla/args/arg-joomla-cli.sh || exit 1 ;
23
+
24
+ shift $#;
25
+
26
+ joomla_cli_tool ;
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Joomla for Webship Workspace: a platform plugin.
3
+ *
4
+ * What the package carries is placed by the installer from the manifest: the builder and the
5
+ * Joomla CLI tool in the sites folders, their functions and argparse under core/scripts/plugins/joomla/,
6
+ * its AI items (ai/ in this package) in the folder of their kind:
7
+ * the agents in AI Agents, the skill in AI Skills, the command in AI Commands, the prompt in AI Prompts.
8
+ * The dashboard needs nothing drawn for it: the builder is in the
9
+ * Build list because it is a cmd-*-project.sh, the row menus are the core's, the AI items are listed
10
+ * like any other. What register() adds is what the assistant is told.
11
+ *
12
+ * Everything the dashboard is asked for goes through `api`; this package requires nothing from the
13
+ * dashboard's own files, so it can be installed from npm and removed without a trace.
14
+ */
15
+ import type { PluginApi } from '@webship.co/workspace-plugin-api';
16
+ /** The plugin's name, which its functions and its user list are named after. */
17
+ export declare const PLATFORM = "joomla";
18
+ /** The commands the installer places in every sites folder. */
19
+ export declare const COMMANDS: string[];
20
+ /** The agents the installer places in the AI Agents folder. */
21
+ export declare const AGENTS: string[];
22
+ /** The skill the installer places in the AI Skills folder (a folder each, with its SKILL.md). */
23
+ export declare const SKILLS: string[];
24
+ /** The slash command the installer places in the AI Commands folder. */
25
+ export declare const AI_COMMANDS: string[];
26
+ /** The prompt the installer places in the AI Prompts folder: each a whole launch command for a new session. */
27
+ export declare const PROMPTS: string[];
28
+ /** What the assistant is told about Joomla in this workspace. */
29
+ export declare function assistantContext(): string;
30
+ export declare function register(api: PluginApi): void;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * Joomla for Webship Workspace: a platform plugin.
4
+ *
5
+ * What the package carries is placed by the installer from the manifest: the builder and the
6
+ * Joomla CLI tool in the sites folders, their functions and argparse under core/scripts/plugins/joomla/,
7
+ * its AI items (ai/ in this package) in the folder of their kind:
8
+ * the agents in AI Agents, the skill in AI Skills, the command in AI Commands, the prompt in AI Prompts.
9
+ * The dashboard needs nothing drawn for it: the builder is in the
10
+ * Build list because it is a cmd-*-project.sh, the row menus are the core's, the AI items are listed
11
+ * like any other. What register() adds is what the assistant is told.
12
+ *
13
+ * Everything the dashboard is asked for goes through `api`; this package requires nothing from the
14
+ * dashboard's own files, so it can be installed from npm and removed without a trace.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.PROMPTS = exports.AI_COMMANDS = exports.SKILLS = exports.AGENTS = exports.COMMANDS = exports.PLATFORM = void 0;
18
+ exports.assistantContext = assistantContext;
19
+ exports.register = register;
20
+ /** The plugin's name, which its functions and its user list are named after. */
21
+ exports.PLATFORM = 'joomla';
22
+ /** The commands the installer places in every sites folder. */
23
+ exports.COMMANDS = ['cmd-joomla-project.sh', 'cmd-tools-joomla-cli.sh'];
24
+ /** The agents the installer places in the AI Agents folder. */
25
+ exports.AGENTS = ['joomla-site-builder', 'joomla-tester'];
26
+ /** The skill the installer places in the AI Skills folder (a folder each, with its SKILL.md). */
27
+ exports.SKILLS = ['joomla-scenarios'];
28
+ /** The slash command the installer places in the AI Commands folder. */
29
+ exports.AI_COMMANDS = ['joomla-test'];
30
+ /** The prompt the installer places in the AI Prompts folder: each a whole launch command for a new session. */
31
+ exports.PROMPTS = ['joomla-build-and-test'];
32
+ /** What the assistant is told about Joomla in this workspace. */
33
+ function assistantContext() {
34
+ return [
35
+ 'Joomla (a plugin, @webship.co/workspace-joomla): a Joomla site is built with',
36
+ '`bash cmd-joomla-project.sh <name> --install --add-users` from a sites folder (dev, test, sandboxes, demos),',
37
+ 'in a container like every other project, at https://<name>.ddev.site (the administrator at /administrator).',
38
+ '`bash cmd-tools-joomla-cli.sh <name>` says what the site is; `--run "<command>"` runs the Joomla CLI (cli/joomla.php) in it,',
39
+ '`--update` updates the core, `--check` looks for updates, `--add-users` adds the default accounts (one per user group).',
40
+ '`bash cmd-tools-add-users.sh <name> joomla` adds the same accounts.',
41
+ '`bash cmd-tools-testing.sh <name>` sets up webship-js with the Joomla step pack; `--run` runs the suite.',
42
+ `For Joomla work, hand over to the agents ${exports.AGENTS.map((a) => `\`${a}\``).join(' and ')}.`,
43
+ `The plugin also places the skill ${exports.SKILLS.map((a) => `\`${a}\``).join(', ')} (the step pack's phrases, by area) in ai-skills/,`,
44
+ `the command ${exports.AI_COMMANDS.map((a) => `\`/${a} <site>\``).join(', ')} in ai-commands/ and the prompt ${exports.PROMPTS.map((a) => `\`${a}\``).join(' and ')} in ai-prompts/.`,
45
+ 'Never run php, composer, npm or mysql on the host for a project.',
46
+ ].join(' ');
47
+ }
48
+ function register(api) {
49
+ api.addAssistantContext(assistantContext);
50
+ }
51
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;;AAuBH,4CAcC;AAED,4BAEC;AArCD,gFAAgF;AACnE,QAAA,QAAQ,GAAG,QAAQ,CAAC;AAEjC,+DAA+D;AAClD,QAAA,QAAQ,GAAG,CAAC,uBAAuB,EAAE,yBAAyB,CAAC,CAAC;AAE7E,+DAA+D;AAClD,QAAA,MAAM,GAAG,CAAC,qBAAqB,EAAE,eAAe,CAAC,CAAC;AAE/D,iGAAiG;AACpF,QAAA,MAAM,GAAG,CAAC,kBAAkB,CAAC,CAAC;AAE3C,wEAAwE;AAC3D,QAAA,WAAW,GAAG,CAAC,aAAa,CAAC,CAAC;AAE3C,+GAA+G;AAClG,QAAA,OAAO,GAAG,CAAC,uBAAuB,CAAC,CAAC;AAEjD,iEAAiE;AACjE,SAAgB,gBAAgB;IAC9B,OAAO;QACL,8EAA8E;QAC9E,8GAA8G;QAC9G,6GAA6G;QAC7G,8HAA8H;QAC9H,yHAAyH;QACzH,qEAAqE;QACrE,0GAA0G;QAC1G,4CAA4C,cAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG;QAC1F,oCAAoC,cAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,oDAAoD;QAChI,eAAe,mBAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,mCAAmC,eAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,kBAAkB;QACrK,kEAAkE;KACnE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAED,SAAgB,QAAQ,CAAC,GAAc;IACrC,GAAG,CAAC,mBAAmB,CAAC,gBAAgB,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,150 @@
1
+ # A plugin carries its own items
2
+
3
+ Every `@webship.co/workspace-<name>` plugin manages what belongs to it: its `cmd-*.sh` commands and
4
+ its AI items (agents, skills, commands, prompts). The package holds them, the manifest names them,
5
+ and `plugins.sh --install <name>` lists each one in the workspace folder of its kind, when that
6
+ folder is an active workspace folder. `--uninstall` takes them away again. The reference is
7
+ [`@webship.co/workspace-wordpress`](https://github.com/webship/workspace-wordpress), and this plugin
8
+ follows it; below, `<p>` is the plugin's name.
9
+
10
+ ## The layout
11
+
12
+ ```text
13
+ commands/cmd-<p>-project.sh cmd-*.sh scripts only: builders and tools, placed in workspace folders
14
+ commands/cmd-tools-<p>-cli.sh
15
+ ai/agents/<p>-<role>.md one file per agent
16
+ ai/skills/<p>-<topic>/SKILL.md one folder per skill; every file in it is placed (examples/, references/)
17
+ ai/commands/<p>-<verb>.md one file per slash command
18
+ ai/prompts/<p>-<task>.md one file per prompt
19
+ tests/items.test.ts the shape of every item, and that it names nothing that does not exist
20
+ tests/fixtures/step-definitions.txt the step definitions the items' phrases are checked against (a plugin with a step pack)
21
+ ```
22
+
23
+ `commands/` is taken by the `cmd-*.sh` scripts, so the AI items live under `ai/`, one folder per
24
+ kind, named like the manifest's `ai` keys. The installer places an item by the last part of its
25
+ path, whatever folder the package keeps it in, so a plugin that kept its agents in `agents/` moves
26
+ them with `git mv agents ai/agents` and changes two lines of its manifest.
27
+
28
+ ## The manifest
29
+
30
+ ```json
31
+ "files": ["dist/src", "ai", "commands", "docs", "features", "scripts", "testing", "README.md"],
32
+ "workspacePlugin": {
33
+ "name": "<p>",
34
+ "needs": [["dev", "test", "sandboxes", "demos"], "ai-agents", "ai-skills", "ai-commands", "ai-prompts"],
35
+ "commands": { "types": ["sites"], "workspaces": ["dev", "test", "sandboxes", "demos"],
36
+ "files": ["commands/cmd-<p>-project.sh", "commands/cmd-tools-<p>-cli.sh"] },
37
+ "ai": {
38
+ "agents": ["ai/agents/<p>-site-builder.md", "ai/agents/<p>-tester.md"],
39
+ "skills": ["ai/skills/<p>-scenarios"],
40
+ "commands": ["ai/commands/<p>-test.md"],
41
+ "prompts": ["ai/prompts/<p>-build-and-test.md"]
42
+ }
43
+ }
44
+ ```
45
+
46
+ - `ai` is in `files`, or the items are not in the published package.
47
+ - A skill is named by its folder, with no `/SKILL.md` and no trailing slash.
48
+ - `needs` names the folder of every kind the plugin ships, after the folder its commands need. A
49
+ plugin with no `cmd-*.sh` for a sites folder leaves the first entry out; a kind it does not ship
50
+ is left out of `ai` and of `needs`.
51
+
52
+ | Kind | Lands in | Claude Code reads it from |
53
+ | --- | --- | --- |
54
+ | `commands.files` | every active folder `commands.workspaces` names, else every active folder of `commands.types` | the folder itself: `bash cmd-….sh` |
55
+ | `ai.agents` | `ai-agents/<name>.md` | `~/.claude/agents`, after Install |
56
+ | `ai.skills` | `ai-skills/<name>/` | `~/.claude/skills`, after Install |
57
+ | `ai.commands` | `ai-commands/<name>.md` | `~/.claude/commands`, after Install: `/<name>` |
58
+ | `ai.prompts` | `ai-prompts/<name>.md` | nothing: the New screen form lists it as a template for a new session |
59
+
60
+ ## The shape of each kind
61
+
62
+ | Kind | Shape |
63
+ | --- | --- |
64
+ | Agent | Frontmatter `name` (the file's name), `description` (when to use it, with the phrases a person says), `model: fable`, `tools`; then what it does, the commands it runs, its rules |
65
+ | Skill | `SKILL.md` with frontmatter `name` (the folder's name) and `description` (what it does, then `Use when …`); files beside it for what is too long or is meant to be copied |
66
+ | Command | Frontmatter `description` and `argument-hint`, no `name` (the file names it); the body reads what was typed from `$ARGUMENTS` |
67
+ | Prompt | No frontmatter. One sentence that says what it is for, then a fenced block holding the whole launch command: `claude --permission-mode bypassPermissions """` … `"""`, with `<placeholders>` to fill in and a `#` line that says where it runs |
68
+
69
+ Names start with the plugin's name (`<p>-…`): an item that is already in the folder under the same
70
+ name is kept, so a name another plugin could also choose would never be placed. A command and a
71
+ prompt never share a name: both end in `~/.claude/commands`.
72
+
73
+ ## What an item may say
74
+
75
+ Nothing generic and nothing invented. An item is about what this plugin does in the workspace, and
76
+ every command, flag, path and step phrase in it exists:
77
+
78
+ - commands and flags: the plugin's own (`scripts/args/*.sh`) and the workspace's (`cmd-tools-testing.sh`
79
+ and its flags, `cmd-tools-remove.sh`, `cmd-tools-clone.sh --to`, `cmd-tools-ai-items.sh --install`);
80
+ - step phrases: the plugin's step pack and webship-js, as installed in a real project;
81
+ - the body is for any AI CLI, Claude Code being the default shape: plain Markdown ("run this
82
+ command", "read this file", "the AI assistant") that names no tool or feature of one CLI; the
83
+ frontmatter and a prompt's `claude …` launch line stay, with one line saying that the text between
84
+ the quotes can be given to another AI CLI as it is; a command keeps `$ARGUMENTS` and says in
85
+ words what the arguments are;
86
+ - the workspace is container-based (DDEV by default); no platform name in a step phrase; no
87
+ account created by a scenario; no password, no personal path, addresses at `example.com`.
88
+
89
+ Run every command an item tells its reader to run, and every scenario it shows, on a real site
90
+ before it is pushed. Two of the three example features of the reference failed on their first real
91
+ run, each on a phrase that exists and matched in a dry run.
92
+
93
+ ## The tests to copy
94
+
95
+ `tests/items.test.ts` checks, with no site and no network:
96
+
97
+ 1. the manifest: one list per kind, each item under `ai/<kind>/`, in the package, named `<p>-…`,
98
+ `ai` in `files`, the folder of each kind in `needs`, no command and prompt of the same name;
99
+ 2. the shape of each kind (the table above; the two expressions the dashboard reads a prompt with);
100
+ 3. every `cmd-*.sh` an item names is the plugin's or the workspace's, with flags that exist;
101
+ 4. every step in a `gherkin` block or a `.feature` file matches a definition in
102
+ `tests/fixtures/step-definitions.txt`, names no platform and carries no password;
103
+ 5. the words: container-based, no personal value, the README lists every item.
104
+
105
+ Refresh the fixture from a project whose testing stack is set up, whenever the pack's release
106
+ line changes (`<pack>` is the plugin's step pack):
107
+
108
+ ```bash
109
+ cd ~/workspace/<folder>/<site>
110
+ { echo "# <pack> <version> and webship-js <version>" ;
111
+ grep -hE "^(Given|When|Then)\(/" node_modules/<pack>/tests/step-definitions/*.steps.js node_modules/webship-js/tests/step-definitions/*.steps.js \
112
+ | sed -nE 's/^(Given|When|Then)\(\/(.*)\/, (\{[^}]*\}, )?(async )?function.*/\2/p' | sort -u ; } > step-definitions.txt
113
+ ```
114
+
115
+ `tests/needs.test.ts` holds the exact `needs` list, and `tests/plugin.test.ts` that every file the
116
+ manifest names ships.
117
+
118
+ ## Prove it on a fresh workspace
119
+
120
+ Never in a workspace somebody works in. `webship-workspace init <folder>` makes an empty one.
121
+
122
+ ```bash
123
+ npm pack # in the plugin: the tarball of the branch
124
+ cd <the fresh workspace>
125
+ bash core/scripts/plugins.sh --require <path>/webship.co-workspace-<p>-<version>.tgz # says what it needs
126
+ bash core/scripts/plugins.sh --activate <p> # stops: lists what is not here, changes nothing
127
+ bash core/scripts/plugins.sh --activate <p> --with-needs # adds the folders, then activates
128
+ bash core/scripts/plugins.sh --install <p> # "placed …" once per file
129
+ ls dev ai-agents ai-skills ai-commands ai-prompts # each item in its folder
130
+ bash core/scripts/plugins.sh --list # needs: … met by …
131
+ bash core/scripts/plugins.sh --uninstall <p> # "removed …" once per file
132
+ grep -c "<p>" core/config/plugins.installed.yml # 0: the record is gone
133
+ ```
134
+
135
+ Then, installed again: build one site with the builder, run each command the items name, copy the
136
+ skill's examples into the suite and run them, look at the four AI folders on the dashboard, and
137
+ remove the site with `cmd-tools-remove.sh`.
138
+
139
+ ## What was found on the way
140
+
141
+ - A phrase that matches in a dry run can still fail: a step may need another one before it
142
+ (`I should see the page title` needs `Given I am on a page`), or assert something the site does
143
+ not do as built. Only a real run tells.
144
+ - Content a failed scenario created stays on the site. Name it so it is found, and remove it
145
+ through the CLI tool before the next run (an entry in the trash is not in a list of every status).
146
+ - A folder that is not active gets nothing: the install says `skipped <n> <kind>` for it, and
147
+ places the items when the folder is added. With the folder in `needs`, `--activate` and
148
+ `--install` stop before that and offer to add it.
149
+ - An item a person edited in its folder is kept by `--install` and by `--uninstall`: the record
150
+ holds the hash of what was placed.