@webship.co/workspace-odoo 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,234 @@
1
+ ---
2
+ name: odoo-scenarios
3
+ description: Write and run webship-js scenarios for an Odoo Community site of the Webship Workspace with the Odoo step pack (`@webship-js/odoo-steps`) — the phrases of the pack by area (sessions, apps and menus, views and search, records, dialogs and the chatter, the website with its blog, shop, events and jobs), 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 Odoo site", "test the salesperson account", "which step is there for a kanban column", "add a feature for creating a contact", or when a `.feature` file of an Odoo project is being written or fixed.
4
+ argument-hint: '<site> [what to cover]'
5
+ ---
6
+
7
+ # odoo-scenarios
8
+
9
+ Scenarios for an Odoo Community site of a Webship Workspace (`~/workspace`, container-based, DDEV
10
+ by default), written from the steps of [`@webship-js/odoo-steps`](https://github.com/webship/odoo-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 Odoo plugin (`@webship.co/workspace-odoo`), like
13
+ the builder (`cmd-odoo-project.sh`), the odoo-bin tool (`cmd-tools-odoo-cli.sh`) and the agents
14
+ `odoo-site-builder` and `odoo-tester`. The site is the Community edition, never the Enterprise
15
+ edition.
16
+
17
+ ## Where everything is
18
+
19
+ | What | Where |
20
+ | --- | --- |
21
+ | The site | `~/workspace/<folder>/<site>`, at `https://<site>.ddev.site`, the login at `/web/login` (`<folder>` is a sites folder: `dev`, `test`, `sandboxes`, `demos`) |
22
+ | The suite's configuration | `<site>/cucumber.js`: the step definitions it loads and the users registry (`worldParameters.users`) |
23
+ | The features | `<site>/tests/features/*.feature` (`site.feature` is the first one the setup wrote) |
24
+ | The pack's steps | `<site>/node_modules/@webship-js/odoo-steps/tests/step-definitions/*.steps.js` |
25
+ | webship-js's steps | `<site>/node_modules/webship-js/tests/step-definitions/*.js` |
26
+ | The reports | `<site>/tests/reports/` |
27
+
28
+ ## The order of work
29
+
30
+ 1. **Make sure the testing stack is there.** From the sites folder:
31
+ ```bash
32
+ cd ~/workspace/<folder>
33
+ bash cmd-tools-testing.sh <site>
34
+ ```
35
+ It adds webship-js, the step pack, the users registry and `tests/features/site.feature`, and
36
+ makes sure the default accounts are on the site. It is safe to run again: it adds what is
37
+ missing and keeps what was changed.
38
+ 2. **Know which apps the site has.** A scenario about an app that is not installed fails at its
39
+ first step:
40
+ ```bash
41
+ bash cmd-tools-odoo-cli.sh <site> # the version, the apps, the accounts
42
+ bash cmd-tools-odoo-cli.sh <site> --install-apps project # only when an app is asked for
43
+ ```
44
+ 3. **Read the installed steps before writing a phrase.** They are the source of truth: the pack
45
+ moves, and a phrase from memory is a guess.
46
+ ```bash
47
+ cd ~/workspace/<folder>/<site>
48
+ grep -hE "^(Given|When|Then)\(" node_modules/@webship-js/odoo-steps/tests/step-definitions/*.steps.js
49
+ ```
50
+ Every step carries a comment block with five examples above it; open the file when a phrase
51
+ is not obvious.
52
+ 4. **Look at the screen first** (the Playwright MCP browser, a tab of your own) when the scenario
53
+ is about a screen you have not seen: the label of a field, the name of a column and the items
54
+ of a menu are the site's own words, and a form does not always label its first field.
55
+ 5. **Write the feature** in `<site>/tests/features/`, from phrases that exist (the lists below).
56
+ 6. **Match every step without a browser**, then run the feature, then the suite:
57
+ ```bash
58
+ cd ~/workspace/<folder>
59
+ bash cmd-tools-testing.sh <site> --dry-run --path tests/features/<name>.feature
60
+ bash cmd-tools-testing.sh <site> --run --path tests/features/<name>.feature
61
+ bash cmd-tools-testing.sh <site> --run --tags "@critical"
62
+ bash cmd-tools-testing.sh <site> --run
63
+ ```
64
+ A dry run says `Undefined` for a phrase no definition matches: fix the phrase, do not write a
65
+ step for it.
66
+
67
+ ## Accounts: a handle, never a password
68
+
69
+ A scenario logs in by a handle of the users registry. The default accounts are on the site
70
+ already (`bash cmd-tools-odoo-cli.sh <site> --add-users` adds them again if they were removed):
71
+
72
+ | Handle | Account | What it may do |
73
+ | --- | --- | --- |
74
+ | `admin` | `administrator` | Every installed app, and the settings |
75
+ | `salesperson` | `salesperson` | Sales and CRM, own documents only; no Invoicing |
76
+ | `accountant` | `accountant` | Invoicing; no Sales, no CRM |
77
+ | `employee` | `employee` | An internal user with no app of a role |
78
+ | `portal` | `portal` | A portal user: the website and `/my`, never the web client |
79
+
80
+ ```gherkin
81
+ Given I am a logged in user with the "salesperson" user
82
+ Then I should be logged in as "salesperson"
83
+ And I should be in the web client
84
+ ```
85
+
86
+ ## The phrases, by area
87
+
88
+ Each line is a phrase the pack defines, and each one passed on a site built with
89
+ `bash cmd-odoo-project.sh <site> --install --add-users` (the default apps with demo data; the
90
+ names in quotes are that site's). Most `should` steps also take the negative.
91
+
92
+ ### Sessions
93
+
94
+ ```gherkin
95
+ Given I am not logged in
96
+ Given I am on the login page
97
+ Given I am a logged in user with the "salesperson" user
98
+ When I log in as "salesperson" with password "not-the-password"
99
+ When I log out
100
+ Then I should see the login form
101
+ Then I should see a login error
102
+ Then I should be logged in as "salesperson"
103
+ Then I should not be logged in
104
+ Then I should be in the web client
105
+ Then I should be in the portal
106
+ When I open the user menu
107
+ Then I should see "Log out" in the user menu
108
+ ```
109
+
110
+ ### Apps, menus and views
111
+
112
+ ```gherkin
113
+ Then I should see the "CRM" app
114
+ Then I should not see the "Invoicing" app
115
+ When I open the "CRM" app
116
+ Then I should be in the "CRM" app
117
+ Then I should see the "Orders" menu
118
+ Then I should see "Quotations" in the breadcrumb
119
+ When I go back to "Contacts" in the breadcrumb
120
+ Then I should see the kanban view
121
+ When I switch to the list view
122
+ Then I should see the list view
123
+ Then I should see the "New" column
124
+ ```
125
+
126
+ ### Records, search, dialogs and the chatter
127
+
128
+ ```gherkin
129
+ When I create a new record
130
+ When I set the "Email" field to "suite-contact@example.com"
131
+ Then the form should have unsaved changes
132
+ When I save the record
133
+ Then the form should not have unsaved changes
134
+ Then the "Email" field should be "suite-contact@example.com"
135
+ Then I should see the chatter
136
+ When I log the note "Written by the suite."
137
+ Then I should see "Written by the suite." in the chatter
138
+ When I search the records for "A contact from the suite"
139
+ Then I should see the "A contact from the suite" record
140
+ Then I should see 1 record
141
+ When I select the "A contact from the suite" record
142
+ Then I should see 1 selected record
143
+ When I choose "Delete" in the Actions menu
144
+ Then I should see a dialog
145
+ When I confirm the dialog
146
+ Then I should see no records
147
+ ```
148
+
149
+ ### The website
150
+
151
+ ```gherkin
152
+ Then I should be on a website page
153
+ Then I should see the menu
154
+ Then I should see the footer
155
+ Then I should be on the blog page
156
+ Then I should be on the shop page
157
+ When I search the shop for "desk"
158
+ Then I should see shop search results for "desk"
159
+ When I open the first product in the shop
160
+ Then I should be on a product page
161
+ When I add the product to the cart
162
+ Then I should see "1" item in the cart
163
+ Then I should be on the events page
164
+ Then I should be on the jobs page
165
+ Then I should see job openings
166
+ Given I am on the contact page
167
+ Then I should see the contact form
168
+ Then I should be on the 404 page
169
+ Then I should be able to edit the website
170
+ ```
171
+
172
+ `I am an anonymous user`, `I am on the homepage`, `I go to "/shop"`, `I should see "<text>"` and
173
+ `the response status code should be 200` are webship-js's own steps; its status codes, classes,
174
+ landmarks and accessibility audits are used as they are and never redefined for this platform.
175
+
176
+ ## Traps found on a real site
177
+
178
+ - **A field is named by what the form shows, and the first field of a contact shows no label.**
179
+ `When I set the "Name" field to "…"` failed in Contacts: the form labels `Email`, `Phone`,
180
+ `Tags` and the others, and the name is a placeholder. The technical name passed:
181
+ `When I set the "name" field to "A contact from the suite"`. The failure message lists the
182
+ labels the form has.
183
+ - **`I should be able to edit the website` is a step for an internal user.** For a visitor,
184
+ `I should not be able to edit the website` does not pass as "no": it fails with `Expected the
185
+ website preview of the web client`. Log in first, or leave it out of a visitor's scenario.
186
+ - **Deleting a record is done from the list.** Search for it, switch to the list view, select
187
+ it, choose `Delete` in the Actions menu and confirm the dialog, as the example does.
188
+ - **A product in the cart is a quotation in Sales.** `When I add the product to the cart` passed
189
+ for a visitor and left a quotation behind that a visitor cannot remove. The examples stop at
190
+ the product page; a cart scenario belongs in a site that is rebuilt for the run.
191
+ - **The pages are the default apps'.** `/blog`, `/shop`, `/event`, `/jobs` and the pipeline
192
+ columns `New` and `Won` come with the apps and the demo data the builder installs. A site built
193
+ with `--apps` or `--without-demo` has its own.
194
+ - **The demo data has its own `portal` user.** The handle `portal` logs in as that account, with
195
+ the groups and the password of the default list.
196
+
197
+ ## Rules
198
+
199
+ - **No account is created in a suite.** No user is added by a scenario or a hook. A role the
200
+ registry does not have is asked for, not made.
201
+ - **Never the workspace account.** The site's own administrator is not in the registry; `admin`
202
+ is the `administrator` default account.
203
+ - **No password in a feature file**, except where a wrong password is the subject.
204
+ - **No platform name in a step phrase**: `I open the "CRM" app`, `I should be in the web client`,
205
+ never a phrase that names the product. The same holds for a custom step.
206
+ - **No selector and no address when a step says it**: `the "Sales" app`, not the path of its
207
+ action.
208
+ - **What a scenario creates, it removes** in the same scenario, under a name nobody else uses.
209
+ - **Community only.** No scenario needs an app of another edition, a trial or a vendor account,
210
+ and nothing is sent to an outside service.
211
+ - **A custom step is the last resort**: look in the pack and in webship-js first, write it in
212
+ `<site>/tests/step-definitions/` with a comment block and examples, and say it may belong in
213
+ the pack.
214
+ - **Everything runs in the container**, through `cmd-tools-testing.sh`. Never `npx cucumber-js`
215
+ or `npx playwright` on the host.
216
+ - **A failing scenario is a result.** No `@wip`, no longer timeout, no looser assertion to turn a
217
+ run green: say what the site did.
218
+
219
+ ## Examples that run
220
+
221
+ `examples/` holds three features that pass on a site built with
222
+ `bash cmd-odoo-project.sh <site> --install --add-users`. Copy one into the suite and run it:
223
+
224
+ ```bash
225
+ cp ~/workspace/ai-skills/odoo-scenarios/examples/apps-and-views.feature ~/workspace/<folder>/<site>/tests/features/
226
+ cd ~/workspace/<folder>
227
+ bash cmd-tools-testing.sh <site> --run --path tests/features/apps-and-views.feature
228
+ ```
229
+
230
+ | Feature | What it shows |
231
+ | --- | --- |
232
+ | `examples/apps-and-views.feature` | A salesperson in the pipeline and in the quotations, an employee with no app of a role, the user menu |
233
+ | `examples/contact-lifecycle.feature` | An administrator creating a contact, logging a note, finding it and deleting it: a record a scenario creates and removes |
234
+ | `examples/website.feature` | A visitor on the front page, the blog, the shop, the events, the jobs and the contact page, an address with no page, and a portal user kept out of the web client |
@@ -0,0 +1,36 @@
1
+ Feature: Each account works in the apps of its role
2
+ As the owner of the site
3
+ I want every account to open the apps of its role, with their views and menus
4
+ So that a change of groups or of an app 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
+
8
+ Scenario: A salesperson works in the pipeline
9
+ Given I am a logged in user with the "salesperson" user
10
+ When I open the "CRM" app
11
+ Then I should be in the "CRM" app
12
+ And I should see the kanban view
13
+ And I should see the "New" column
14
+ And I should see the "Won" column
15
+ When I switch to the list view
16
+ Then I should see the list view
17
+
18
+ Scenario: A salesperson opens the quotations
19
+ Given I am a logged in user with the "salesperson" user
20
+ When I open the "Sales" app
21
+ Then I should be in the "Sales" app
22
+ And I should see "Quotations" in the breadcrumb
23
+ And I should see the "Orders" menu
24
+
25
+ Scenario: An employee has the web client and no app of a role
26
+ Given I am a logged in user with the "employee" user
27
+ Then I should be in the web client
28
+ But I should not see the "Sales" app
29
+ And I should not see the "Settings" app
30
+
31
+ Scenario: The user menu ends the session
32
+ Given I am a logged in user with the "accountant" user
33
+ When I open the user menu
34
+ Then I should see "Log out" in the user menu
35
+ When I log out
36
+ Then I should not be logged in
@@ -0,0 +1,29 @@
1
+ Feature: A contact is written and removed again
2
+ As an administrator
3
+ I want to create a contact, note something on it, find it and delete it
4
+ So that the suite proves records, the chatter and the search work, and leaves the site as it found it
5
+
6
+ Scenario: The administrator creates a contact, finds it in the list and deletes it
7
+ Given I am a logged in user with the "admin" user
8
+ When I open the "Contacts" app
9
+ And I create a new record
10
+ And I set the "name" field to "A contact written by a scenario"
11
+ And I set the "Email" field to "scenario-contact@example.com"
12
+ Then the form should have unsaved changes
13
+ When I save the record
14
+ Then the form should not have unsaved changes
15
+ And the "Email" field should be "scenario-contact@example.com"
16
+ And I should see the chatter
17
+ When I log the note "Written and removed by the suite."
18
+ Then I should see "Written and removed by the suite." in the chatter
19
+ When I go back to "Contacts" in the breadcrumb
20
+ And I search the records for "A contact written by a scenario"
21
+ Then I should see the "A contact written by a scenario" record
22
+ And I should see 1 record
23
+ When I switch to the list view
24
+ And I select the "A contact written by a scenario" record
25
+ Then I should see 1 selected record
26
+ When I choose "Delete" in the Actions menu
27
+ Then I should see a dialog
28
+ When I confirm the dialog
29
+ Then I should see no records
@@ -0,0 +1,43 @@
1
+ Feature: A visitor reads the website
2
+ As the owner of the site
3
+ I want the pages of the website apps to be served to a visitor
4
+ So that an app or a theme that breaks the website is caught by the suite
5
+
6
+ # For a site built with the default apps: the blog, the shop, the events and the jobs.
7
+
8
+ Scenario: The front page has its menu and its footer
9
+ Given I am an anonymous user
10
+ And I am on the homepage
11
+ Then I should be on a website page
12
+ And I should see the menu
13
+ And I should see the footer
14
+
15
+ Scenario: Each website app has its page
16
+ Given I am an anonymous user
17
+ When I go to "/blog"
18
+ Then I should be on the blog page
19
+ When I go to "/event"
20
+ Then I should be on the events page
21
+ When I go to "/jobs"
22
+ Then I should be on the jobs page
23
+ And I should see job openings
24
+ Given I am on the contact page
25
+ Then I should see the contact form
26
+
27
+ Scenario: The shop lists products and finds one
28
+ Given I am an anonymous user
29
+ When I go to "/shop"
30
+ Then I should be on the shop page
31
+ When I search the shop for "desk"
32
+ Then I should see shop search results for "desk"
33
+ When I open the first product in the shop
34
+ Then I should be on a product page
35
+
36
+ Scenario: An address with no page is not found, and a portal user stays out of the web client
37
+ Given I am an anonymous user
38
+ When I go to "/this-page-does-not-exist"
39
+ Then I should be on the 404 page
40
+ Given I am a logged in user with the "portal" user
41
+ When I go to "/web"
42
+ Then I should be in the portal
43
+ And I should not be in the web client
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # workspace-name: Odoo 17 Community (apps, accounts, tests)
4
+
5
+ # Installed by the Odoo plugin (plugins.sh --install odoo); __WORKSPACE__ is the workspace it was installed into.
6
+ #
7
+ # Build an Odoo Community site in a container: Odoo 17.0, or the release --version names, on
8
+ # PostgreSQL, at https://<name>.ddev.site. With --install the database is created with the apps
9
+ # and Odoo's demo data, and the workspace account is its administrator; with --add-users it also
10
+ # gets the default accounts. Community only: no Enterprise, no vendor account.
11
+
12
+ # Bootstrap.
13
+ # Find the workspace tooling from this script, so a fresh clone needs no setup.
14
+ WORKSPACE_SCRIPTS="${WORKSPACE_SCRIPTS:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../core/scripts" && pwd)}";
15
+ source ${WORKSPACE_SCRIPTS}/bootstrap.sh || exit 1 ;
16
+
17
+ # Load workspace settings.
18
+ eval $(parse_yaml ${WORKSPACE_CONFIG}/workspace.__WORKSPACE__.settings.yml);
19
+
20
+ # Set site version.
21
+ site_version="17.0";
22
+
23
+ # Distribution.
24
+ distribution_name="odoo";
25
+ distribution_title="Odoo Community";
26
+ distribution_webroot="";
27
+
28
+ ARGPARSE_DESCRIPTION="Build an ${distribution_title} project in __WORKSPACE__"
29
+ # The args file comes with the plugin: core/scripts/plugins/odoo/ is where plugins.sh --install puts it.
30
+ source ${WORKSPACE_SCRIPTS}/plugins/odoo/args/arg-odoo.sh || exit 1 ;
31
+
32
+ shift $#;
33
+
34
+ odoo_build ;
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bash
2
+
3
+ # Installed by the Odoo plugin (plugins.sh --install odoo); __WORKSPACE__ is the workspace it was installed into.
4
+ #
5
+ # odoo-bin for one Odoo project of this workspace, in its container: say what the site is, run
6
+ # an odoo-bin command, install apps, update the installed modules, restart Odoo, add or remove
7
+ # the default 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="odoo";
19
+
20
+ ARGPARSE_DESCRIPTION="Run odoo-bin on an Odoo project of __WORKSPACE__: status, a command, apps, an update, a restart, the default accounts"
21
+ # The args file comes with the plugin: core/scripts/plugins/odoo/ is where plugins.sh --install puts it.
22
+ source ${WORKSPACE_SCRIPTS}/plugins/odoo/args/arg-odoo-cli.sh || exit 1 ;
23
+
24
+ shift $#;
25
+
26
+ odoo_cli_tool ;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Odoo Community 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
+ * odoo-bin tool in the sites folders, their functions, argparse and the accounts script under
6
+ * core/scripts/plugins/odoo/, its AI items (ai/) in the AI folders. The dashboard needs nothing
7
+ * drawn for it: the builder is in the Build list because it is a cmd-*-project.sh, the row menus
8
+ * are the core's, the AI items are listed like any other. What register() adds is what the
9
+ * assistant is told.
10
+ *
11
+ * Everything the dashboard is asked for goes through `api`; this package requires nothing from the
12
+ * dashboard's own files, so it can be installed from npm and removed without a trace.
13
+ */
14
+ import type { PluginApi } from '@webship.co/workspace-plugin-api';
15
+ /** The plugin's name, which its functions are named after. */
16
+ export declare const PLATFORM = "odoo";
17
+ /** The commands the installer places in every sites folder. */
18
+ export declare const COMMANDS: string[];
19
+ /** The agents the installer places in the AI Agents folder. */
20
+ export declare const AGENTS: string[];
21
+ /** The skill the installer places in the AI Skills folder (a folder each, with its SKILL.md). */
22
+ export declare const SKILLS: string[];
23
+ /** The slash command the installer places in the AI Commands folder. */
24
+ export declare const AI_COMMANDS: string[];
25
+ /** The prompt the installer places in the AI Prompts folder: a whole launch command for a new session. */
26
+ export declare const PROMPTS: string[];
27
+ /** What the assistant is told about Odoo in this workspace. */
28
+ export declare function assistantContext(): string;
29
+ export declare function register(api: PluginApi): void;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ /**
3
+ * Odoo Community 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
+ * odoo-bin tool in the sites folders, their functions, argparse and the accounts script under
7
+ * core/scripts/plugins/odoo/, its AI items (ai/) in the AI folders. The dashboard needs nothing
8
+ * drawn for it: the builder is in the Build list because it is a cmd-*-project.sh, the row menus
9
+ * are the core's, the AI items are listed like any other. What register() adds is what the
10
+ * 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
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.PROMPTS = exports.AI_COMMANDS = exports.SKILLS = exports.AGENTS = exports.COMMANDS = exports.PLATFORM = void 0;
17
+ exports.assistantContext = assistantContext;
18
+ exports.register = register;
19
+ /** The plugin's name, which its functions are named after. */
20
+ exports.PLATFORM = 'odoo';
21
+ /** The commands the installer places in every sites folder. */
22
+ exports.COMMANDS = ['cmd-odoo-project.sh', 'cmd-tools-odoo-cli.sh'];
23
+ /** The agents the installer places in the AI Agents folder. */
24
+ exports.AGENTS = ['odoo-site-builder', 'odoo-tester'];
25
+ /** The skill the installer places in the AI Skills folder (a folder each, with its SKILL.md). */
26
+ exports.SKILLS = ['odoo-scenarios'];
27
+ /** The slash command the installer places in the AI Commands folder. */
28
+ exports.AI_COMMANDS = ['odoo-test'];
29
+ /** The prompt the installer places in the AI Prompts folder: a whole launch command for a new session. */
30
+ exports.PROMPTS = ['odoo-build-and-test'];
31
+ /** What the assistant is told about Odoo in this workspace. */
32
+ function assistantContext() {
33
+ return [
34
+ 'Odoo Community (a plugin, @webship.co/workspace-odoo): an Odoo site is built with',
35
+ '`bash cmd-odoo-project.sh <name> --install --add-users` from a sites folder (dev, test, sandboxes, demos),',
36
+ 'in containers like every other project, at https://<name>.ddev.site (the login at /web/login).',
37
+ '`bash cmd-tools-odoo-cli.sh <name>` says what the site is; `--run "<odoo-bin arguments>"` runs odoo-bin on its database,',
38
+ '`--install-apps <a,b>` installs apps, `--update` updates the installed modules, `--restart` starts Odoo again,',
39
+ '`--add-users` adds the default accounts (one per kind of user).',
40
+ '`bash cmd-tools-testing.sh <name>` sets up webship-js with the Odoo step pack; `--run` runs the suite.',
41
+ `For Odoo work, hand over to the agents ${exports.AGENTS.map((a) => `\`${a}\``).join(' and ')}.`,
42
+ `The plugin also places the skill ${exports.SKILLS.map((a) => `\`${a}\``).join(', ')} (the step pack's phrases, by area) in ai-skills/,`,
43
+ `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/.`,
44
+ 'Community only: never the Enterprise edition, never a vendor account. Never run odoo, python or psql on the host for a project.',
45
+ 'The example builder cmd-odoo20-project.sh of a sites folder is a different, simpler build; this plugin leaves it as it is.',
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;;;;;;;;;;;;GAYG;;;AAuBH,4CAeC;AAED,4BAEC;AAtCD,8DAA8D;AACjD,QAAA,QAAQ,GAAG,MAAM,CAAC;AAE/B,+DAA+D;AAClD,QAAA,QAAQ,GAAG,CAAC,qBAAqB,EAAE,uBAAuB,CAAC,CAAC;AAEzE,+DAA+D;AAClD,QAAA,MAAM,GAAG,CAAC,mBAAmB,EAAE,aAAa,CAAC,CAAC;AAE3D,iGAAiG;AACpF,QAAA,MAAM,GAAG,CAAC,gBAAgB,CAAC,CAAC;AAEzC,wEAAwE;AAC3D,QAAA,WAAW,GAAG,CAAC,WAAW,CAAC,CAAC;AAEzC,0GAA0G;AAC7F,QAAA,OAAO,GAAG,CAAC,qBAAqB,CAAC,CAAC;AAE/C,+DAA+D;AAC/D,SAAgB,gBAAgB;IAC9B,OAAO;QACL,mFAAmF;QACnF,4GAA4G;QAC5G,gGAAgG;QAChG,0HAA0H;QAC1H,gHAAgH;QAChH,iEAAiE;QACjE,wGAAwG;QACxG,0CAA0C,cAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG;QACxF,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,iIAAiI;QACjI,4HAA4H;KAC7H,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,145 @@
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 workspace is container-based (DDEV by default); no platform name in a step phrase; no
82
+ account created by a scenario; no password, no personal path, addresses at `example.com`.
83
+
84
+ Run every command an item tells its reader to run, and every scenario it shows, on a real site
85
+ before it is pushed. Two of the three example features of the reference failed on their first real
86
+ run, each on a phrase that exists and matched in a dry run.
87
+
88
+ ## The tests to copy
89
+
90
+ `tests/items.test.ts` checks, with no site and no network:
91
+
92
+ 1. the manifest: one list per kind, each item under `ai/<kind>/`, in the package, named `<p>-…`,
93
+ `ai` in `files`, the folder of each kind in `needs`, no command and prompt of the same name;
94
+ 2. the shape of each kind (the table above; the two expressions the dashboard reads a prompt with);
95
+ 3. every `cmd-*.sh` an item names is the plugin's or the workspace's, with flags that exist;
96
+ 4. every step in a `gherkin` block or a `.feature` file matches a definition in
97
+ `tests/fixtures/step-definitions.txt`, names no platform and carries no password;
98
+ 5. the words: container-based, no personal value, the README lists every item.
99
+
100
+ Refresh the fixture from a project whose testing stack is set up, whenever the pack's release
101
+ line changes (`<pack>` is the plugin's step pack):
102
+
103
+ ```bash
104
+ cd ~/workspace/<folder>/<site>
105
+ { echo "# <pack> <version> and webship-js <version>" ;
106
+ grep -hE "^(Given|When|Then)\(/" node_modules/<pack>/tests/step-definitions/*.steps.js node_modules/webship-js/tests/step-definitions/*.steps.js \
107
+ | sed -nE 's/^(Given|When|Then)\(\/(.*)\/, (async )?function.*/\2/p' | sort -u ; } > step-definitions.txt
108
+ ```
109
+
110
+ `tests/needs.test.ts` holds the exact `needs` list, and `tests/plugin.test.ts` that every file the
111
+ manifest names ships.
112
+
113
+ ## Prove it on a fresh workspace
114
+
115
+ Never in a workspace somebody works in. `webship-workspace init <folder>` makes an empty one.
116
+
117
+ ```bash
118
+ npm pack # in the plugin: the tarball of the branch
119
+ cd <the fresh workspace>
120
+ bash core/scripts/plugins.sh --require <path>/webship.co-workspace-<p>-<version>.tgz # says what it needs
121
+ bash core/scripts/plugins.sh --activate <p> # stops: lists what is not here, changes nothing
122
+ bash core/scripts/plugins.sh --activate <p> --with-needs # adds the folders, then activates
123
+ bash core/scripts/plugins.sh --install <p> # "placed …" once per file
124
+ ls dev ai-agents ai-skills ai-commands ai-prompts # each item in its folder
125
+ bash core/scripts/plugins.sh --list # needs: … met by …
126
+ bash core/scripts/plugins.sh --uninstall <p> # "removed …" once per file
127
+ grep -c "<p>" core/config/plugins.installed.yml # 0: the record is gone
128
+ ```
129
+
130
+ Then, installed again: build one site with the builder, run each command the items name, copy the
131
+ skill's examples into the suite and run them, look at the four AI folders on the dashboard, and
132
+ remove the site with `cmd-tools-remove.sh`.
133
+
134
+ ## What was found on the way
135
+
136
+ - A phrase that matches in a dry run can still fail: a step may need another one before it
137
+ (`I should see the page title` needs `Given I am on a page`), or assert something the site does
138
+ not do as built. Only a real run tells.
139
+ - Content a failed scenario created stays on the site. Name it so it is found, and remove it
140
+ through the CLI tool before the next run (an entry in the trash is not in a list of every status).
141
+ - A folder that is not active gets nothing: the install says `skipped <n> <kind>` for it, and
142
+ places the items when the folder is added. With the folder in `needs`, `--activate` and
143
+ `--install` stop before that and offer to add it.
144
+ - An item a person edited in its folder is kept by `--install` and by `--uninstall`: the record
145
+ holds the hash of what was placed.