@wpmoo/toolkit 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +22 -0
- package/README.md +519 -0
- package/dist/addons-yaml.js +59 -0
- package/dist/args.js +259 -0
- package/dist/cli.js +1039 -0
- package/dist/cockpit/command-palette.js +23 -0
- package/dist/cockpit/command-registry.js +91 -0
- package/dist/cockpit/daily-prompts.js +177 -0
- package/dist/cockpit/menu.js +99 -0
- package/dist/cockpit/safety.js +22 -0
- package/dist/compose-layout.js +118 -0
- package/dist/daily-actions.js +190 -0
- package/dist/doctor.js +519 -0
- package/dist/environment-context.js +10 -0
- package/dist/environment-version.js +5 -0
- package/dist/environment.js +136 -0
- package/dist/external-assets.js +153 -0
- package/dist/external-templates.js +86 -0
- package/dist/git.js +98 -0
- package/dist/github.js +87 -0
- package/dist/help.js +157 -0
- package/dist/menu-navigation.js +67 -0
- package/dist/module-actions.js +114 -0
- package/dist/odoo-versions.js +1 -0
- package/dist/path-validation.js +50 -0
- package/dist/prompt-copy.js +8 -0
- package/dist/prompt-repositories.js +34 -0
- package/dist/prompts/index.js +174 -0
- package/dist/repo-actions.js +158 -0
- package/dist/repo-url.js +27 -0
- package/dist/repository-preflight.js +46 -0
- package/dist/safe-reset.js +217 -0
- package/dist/scaffold.js +161 -0
- package/dist/source-actions.js +65 -0
- package/dist/source-manifest.js +338 -0
- package/dist/status.js +239 -0
- package/dist/templates.js +758 -0
- package/dist/types.js +1 -0
- package/dist/update-check.js +106 -0
- package/dist/version.js +19 -0
- package/docs/assets/patreon-donate.png +0 -0
- package/docs/assets/wpmoo-banner.png +0 -0
- package/docs/external-resources.md +136 -0
- package/docs/generated-environment-verification.md +140 -0
- package/docs/handoff.md +29 -0
- package/package.json +65 -0
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
export const realNpm = {
|
|
4
|
+
async run(args) {
|
|
5
|
+
const result = await execa('npm', args, args[0] === 'view' ? { timeout: 5000 } : {});
|
|
6
|
+
return { stdout: result.stdout, stderr: result.stderr };
|
|
7
|
+
},
|
|
8
|
+
};
|
|
9
|
+
function truthyEnv(value) {
|
|
10
|
+
return value !== undefined && ['1', 'true', 'yes', 'y'].includes(value.toLowerCase().trim());
|
|
11
|
+
}
|
|
12
|
+
export function isUpdateCheckSkipped(argv, env = process.env) {
|
|
13
|
+
if (argv.includes('--no-update-check'))
|
|
14
|
+
return true;
|
|
15
|
+
if (truthyEnv(env.WPMOO_SKIP_UPDATE_CHECK))
|
|
16
|
+
return true;
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
function numericParts(version) {
|
|
20
|
+
return version
|
|
21
|
+
.replace(/^v/, '')
|
|
22
|
+
.split('-', 1)[0]
|
|
23
|
+
.split('.')
|
|
24
|
+
.map((part) => Number.parseInt(part, 10) || 0);
|
|
25
|
+
}
|
|
26
|
+
export function compareVersions(currentVersion, latestVersion) {
|
|
27
|
+
const current = numericParts(currentVersion);
|
|
28
|
+
const latest = numericParts(latestVersion);
|
|
29
|
+
const length = Math.max(current.length, latest.length);
|
|
30
|
+
for (let index = 0; index < length; index += 1) {
|
|
31
|
+
const currentPart = current[index] ?? 0;
|
|
32
|
+
const latestPart = latest[index] ?? 0;
|
|
33
|
+
if (currentPart !== latestPart) {
|
|
34
|
+
return currentPart - latestPart;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
function parseNpmPackageInfo(stdout) {
|
|
40
|
+
const trimmed = stdout.trim();
|
|
41
|
+
if (!trimmed) {
|
|
42
|
+
throw new Error('npm did not return package metadata');
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(trimmed);
|
|
46
|
+
if (typeof parsed === 'object' && parsed !== null) {
|
|
47
|
+
const record = parsed;
|
|
48
|
+
const version = typeof record.version === 'string' ? record.version.trim() : '';
|
|
49
|
+
const dist = record.dist;
|
|
50
|
+
const nestedTarball = typeof dist === 'object' && dist !== null && typeof dist.tarball === 'string'
|
|
51
|
+
? String(dist.tarball).trim()
|
|
52
|
+
: '';
|
|
53
|
+
const dottedTarball = typeof record['dist.tarball'] === 'string' ? record['dist.tarball'].trim() : '';
|
|
54
|
+
const tarball = nestedTarball || dottedTarball;
|
|
55
|
+
if (version && tarball) {
|
|
56
|
+
return { version, tarball };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Fall through to the validation error below.
|
|
62
|
+
}
|
|
63
|
+
throw new Error('npm did not return a package version and tarball');
|
|
64
|
+
}
|
|
65
|
+
async function viewPackageInfo(packageSpecValue, runner) {
|
|
66
|
+
const result = await runner.run(['view', packageSpecValue, 'version', 'dist.tarball', '--json']);
|
|
67
|
+
return parseNpmPackageInfo(result.stdout);
|
|
68
|
+
}
|
|
69
|
+
export async function checkForUpdate(packageName, currentVersion, runner = realNpm) {
|
|
70
|
+
try {
|
|
71
|
+
const latest = await viewPackageInfo(packageSpec(packageName, 'latest'), runner);
|
|
72
|
+
if (compareVersions(currentVersion, latest.version) < 0) {
|
|
73
|
+
const exact = await viewPackageInfo(packageSpec(packageName, latest.version), runner);
|
|
74
|
+
if (exact.version !== latest.version || !exact.tarball) {
|
|
75
|
+
throw new Error(`npm metadata for ${packageSpec(packageName, latest.version)} did not validate`);
|
|
76
|
+
}
|
|
77
|
+
return { status: 'update-available', currentVersion, latestVersion: exact.version, tarball: exact.tarball };
|
|
78
|
+
}
|
|
79
|
+
return { status: 'current', currentVersion, latestVersion: latest.version };
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return { status: 'unavailable', currentVersion };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
export function packageSpec(packageName, version) {
|
|
86
|
+
return `${packageName}@${version}`;
|
|
87
|
+
}
|
|
88
|
+
export async function installLatestPackage(packageName, version, runner = realNpm) {
|
|
89
|
+
await runner.run(['install', '-g', packageSpec(packageName, version)]);
|
|
90
|
+
}
|
|
91
|
+
export function restartArgs(packageName, version, argv) {
|
|
92
|
+
return ['exec', '--yes', '--package', packageSpec(packageName, version), '--', 'wpmoo', ...argv];
|
|
93
|
+
}
|
|
94
|
+
export function restartEnvironment(env = process.env) {
|
|
95
|
+
return { ...env, WPMOO_SKIP_UPDATE_CHECK: '1' };
|
|
96
|
+
}
|
|
97
|
+
export async function restartCli(packageName, version, argv) {
|
|
98
|
+
const child = spawn('npm', restartArgs(packageName, version, argv), {
|
|
99
|
+
env: restartEnvironment(),
|
|
100
|
+
stdio: 'inherit',
|
|
101
|
+
});
|
|
102
|
+
return new Promise((resolve, reject) => {
|
|
103
|
+
child.on('error', reject);
|
|
104
|
+
child.on('exit', (code) => resolve(code));
|
|
105
|
+
});
|
|
106
|
+
}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
function readPackageJson() {
|
|
3
|
+
return JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
4
|
+
}
|
|
5
|
+
export function packageVersion() {
|
|
6
|
+
return readPackageJson().version;
|
|
7
|
+
}
|
|
8
|
+
export function renderVersion() {
|
|
9
|
+
const packageJson = readPackageJson();
|
|
10
|
+
return `${packageJson.name} ${packageJson.version}`;
|
|
11
|
+
}
|
|
12
|
+
export function packageName() {
|
|
13
|
+
return readPackageJson().name;
|
|
14
|
+
}
|
|
15
|
+
export function renderVersionTag(latestVersion) {
|
|
16
|
+
const current = packageVersion();
|
|
17
|
+
const updateSuffix = latestVersion ? ` -> v.${latestVersion} available` : '';
|
|
18
|
+
return `\u001B[33mv.${current}${updateSuffix}\u001B[0m`;
|
|
19
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# External Resources
|
|
2
|
+
|
|
3
|
+
WPMoo does not embed large Docker Compose resources or Agent Skill text inside
|
|
4
|
+
the TypeScript CLI. The CLI copies standalone external resources from their own
|
|
5
|
+
repositories/packages into generated environments, while those resources can also
|
|
6
|
+
be used independently.
|
|
7
|
+
|
|
8
|
+
## Repositories/packages
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
gh:wpmoo-org/odoo-docker-compose
|
|
12
|
+
npm:@wpmoo/odoo-skills
|
|
13
|
+
gh:wpmoo-org/odoo-skills
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Compose resource
|
|
17
|
+
|
|
18
|
+
`wpmoo-org/odoo-docker-compose` now exposes a compact generated-environment payload
|
|
19
|
+
under `resources/generated-env/`:
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
compose.yaml
|
|
23
|
+
compose/dev.yaml
|
|
24
|
+
compose/stage.yaml
|
|
25
|
+
compose/prod.yaml
|
|
26
|
+
config/odoo/odoo.conf
|
|
27
|
+
resources/odoo/entrypoint.sh
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`@wpmoo/toolkit` prefers that compact payload first when copying compose assets.
|
|
31
|
+
For pinned older refs that do not provide `resources/generated-env/`, the CLI
|
|
32
|
+
falls back to the legacy repository-root layout (`docker-compose_<version>.yml`
|
|
33
|
+
and related files) for compatibility.
|
|
34
|
+
|
|
35
|
+
Standalone usage with the compact payload:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
git clone https://github.com/wpmoo-org/odoo-docker-compose
|
|
39
|
+
cd odoo-docker-compose
|
|
40
|
+
mkdir -p ../my_product_dev
|
|
41
|
+
cp -R resources/generated-env/. ../my_product_dev/
|
|
42
|
+
cp .env.example ../my_product_dev/.env
|
|
43
|
+
cd ../my_product_dev
|
|
44
|
+
./scripts/up.sh
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
WPMoo CLI usage with the default remote source:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx @wpmoo/toolkit create \
|
|
51
|
+
--engine compose \
|
|
52
|
+
--product my_product \
|
|
53
|
+
--source-repo-url https://github.com/example-org/my_product.git
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
During resource development, use a local clone:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
git clone https://github.com/wpmoo-org/odoo-docker-compose ../odoo-docker-compose
|
|
60
|
+
|
|
61
|
+
npx @wpmoo/toolkit create \
|
|
62
|
+
--engine compose \
|
|
63
|
+
--compose-template-url ../odoo-docker-compose \
|
|
64
|
+
--product my_product \
|
|
65
|
+
--source-repo-url https://github.com/example-org/my_product.git
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Agent Skills resource
|
|
69
|
+
|
|
70
|
+
`@wpmoo/odoo-skills` is generic and intentionally not project-specific:
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
skills/odoo-oca/SKILL.md
|
|
74
|
+
skills/odoo-open-core/SKILL.md
|
|
75
|
+
skills/odoo-porting/SKILL.md
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Standalone Pi package usage:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pi install npm:@wpmoo/odoo-skills
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Standalone npx project-local install:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx @wpmoo/odoo-skills --target /path/to/project
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
WPMoo CLI can also copy those skills into generated environments from the default
|
|
91
|
+
remote source:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npx @wpmoo/toolkit create \
|
|
95
|
+
--product my_product \
|
|
96
|
+
--source-repo-url https://github.com/example-org/my_product.git \
|
|
97
|
+
--agent-skills-template
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
During skill development, use a local clone:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
git clone https://github.com/wpmoo-org/odoo-skills ../odoo-skills
|
|
104
|
+
|
|
105
|
+
npx @wpmoo/toolkit create \
|
|
106
|
+
--product my_product \
|
|
107
|
+
--source-repo-url https://github.com/example-org/my_product.git \
|
|
108
|
+
--agent-skills-template \
|
|
109
|
+
--agent-skills-template-url ../odoo-skills
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Generated project-local skills are placed under:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
.agents/skills/
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Project or module-specific guidance should live in that project/module's own
|
|
119
|
+
`AGENTS.md` or custom skill files.
|
|
120
|
+
|
|
121
|
+
## References and pins
|
|
122
|
+
|
|
123
|
+
Remote Git sources can be pinned with refs:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
npx @wpmoo/toolkit create \
|
|
127
|
+
--engine compose \
|
|
128
|
+
--compose-template-ref v0.1.0 \
|
|
129
|
+
--agent-skills-template \
|
|
130
|
+
--agent-skills-template-ref v0.1.0 \
|
|
131
|
+
--product my_product \
|
|
132
|
+
--source-repo-url https://github.com/example-org/my_product.git
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The CLI supports local directories and Git-style resource sources such as
|
|
136
|
+
`gh:owner/repo`, HTTPS Git URLs, and SSH Git URLs.
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# Generated Environment Verification
|
|
2
|
+
|
|
3
|
+
## Scope
|
|
4
|
+
|
|
5
|
+
This matrix covers disposable generated development environments only. It is for
|
|
6
|
+
local and CI verification of generated artifacts and command behavior. It does
|
|
7
|
+
not validate staging or production deployments.
|
|
8
|
+
|
|
9
|
+
## Command split
|
|
10
|
+
|
|
11
|
+
- Use `npx @wpmoo/toolkit ...` for package/operator commands (`create`,
|
|
12
|
+
`add-repo`, `remove-repo`, `add-module`, `remove-module`, `doctor`, `reset`).
|
|
13
|
+
- Use `./moo ...` inside a generated environment for daily local compose
|
|
14
|
+
actions delegated to `./scripts/*.sh`.
|
|
15
|
+
|
|
16
|
+
## Verification matrix
|
|
17
|
+
|
|
18
|
+
| Area | Contract | Primary command(s) |
|
|
19
|
+
| --- | --- | --- |
|
|
20
|
+
| Scaffold files and metadata | Generated environment includes expected files and `.wpmoo/odoo.json` metadata. | `npx @wpmoo/toolkit create ...` |
|
|
21
|
+
| Compose resource files | Compact compose layout is present (`compose.yaml` + environment overlays under `compose/`), plus config/resources/scripts. | `npx @wpmoo/toolkit create ...` |
|
|
22
|
+
| `./moo` delegation | `./moo` dispatches fixed daily actions to the matching script and preserves argument pass-through. | `./moo <action> ...` |
|
|
23
|
+
| Doctor checks | Metadata, compose files, scripts, source repo paths, and local tooling checks behave as expected. | `npx @wpmoo/toolkit doctor` or `./moo doctor` |
|
|
24
|
+
| Doctor safe fixes | Safe file-level fixes are applied only with `--fix`, then doctor runs again and reports any remaining manual issues. | `npx @wpmoo/toolkit doctor --fix` |
|
|
25
|
+
| Generated Postgres checks | For PostgreSQL 18 environments, doctor validates db mount targets avoid old PG image-specific paths and can normalize safe targets with `--fix`. | `npx @wpmoo/toolkit doctor`, `npx @wpmoo/toolkit doctor --fix` |
|
|
26
|
+
| Source repo add/remove | Source repository registration and submodule lifecycle behave correctly. | `npx @wpmoo/toolkit add-repo ...`, `npx @wpmoo/toolkit remove-repo ...` |
|
|
27
|
+
| Source manifest sync | Source repo metadata, `.gitmodules`, and `odoo/custom/manifests/sources.yaml` stay aligned. | `npx @wpmoo/toolkit source list`, `npx @wpmoo/toolkit source sync` |
|
|
28
|
+
| Module add/remove | Module registration changes are applied to the selected source repo config. | `npx @wpmoo/toolkit add-module ...`, `npx @wpmoo/toolkit remove-module ...` |
|
|
29
|
+
| Safe reset | Generated files are refreshed (including `compose.yaml` overlays and env example) without deleting source module code. Local runtime/data directories and custom source layout content are preserved; legacy user-editable paths from older templates may remain and are reported for manual cleanup. | `npx @wpmoo/toolkit reset --dry-run`, `npx @wpmoo/toolkit reset` |
|
|
30
|
+
| Snapshot/restore and lint/pot | These actions are delegated by `./moo` to compose scripts. Restore preview, snapshot retention, and stage/prod destructive guards are preserved by the package argument layer. | `./moo snapshot ...`, `./moo restore-snapshot --dry-run ...`, `./moo restore-snapshot ...`, `./moo lint`, `./moo pot ...` |
|
|
31
|
+
|
|
32
|
+
## Compact compose checks
|
|
33
|
+
|
|
34
|
+
Verify the generated environment includes at least:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
compose.yaml
|
|
38
|
+
compose/dev.yaml
|
|
39
|
+
compose/stage.yaml
|
|
40
|
+
compose/prod.yaml
|
|
41
|
+
config/odoo/odoo.conf
|
|
42
|
+
resources/odoo/entrypoint.sh
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Default local development uses `compose.yaml` plus `compose/dev.yaml`.
|
|
46
|
+
`WPMOO_ENV=stage` or `WPMOO_ENV=prod` must only be used after production-grade
|
|
47
|
+
secrets and volumes are configured.
|
|
48
|
+
|
|
49
|
+
When `WPMOO_ENV=stage` or `WPMOO_ENV=prod`, generated compose scripts refuse
|
|
50
|
+
destructive database actions such as `resetdb` and real `restore-snapshot`
|
|
51
|
+
unless `.env` explicitly sets `WPMOO_ALLOW_DESTRUCTIVE=1`.
|
|
52
|
+
|
|
53
|
+
For PostgreSQL 18 environments (including `POSTGRES_IMAGE=postgres:18`), ensure db
|
|
54
|
+
volume and tmpfs mount targets use `/var/lib/postgresql` directly:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
- volumes:
|
|
58
|
+
- db_data:/var/lib/postgresql
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Paths such as `/var/lib/postgresql/data` and `/var/lib/postgresql/18/docker` are
|
|
62
|
+
no longer accepted by the package `doctor` check.
|
|
63
|
+
|
|
64
|
+
`doctor --fix` may rewrite these safe mount targets to `/var/lib/postgresql`.
|
|
65
|
+
It does not upgrade existing database data; if a real PostgreSQL major upgrade
|
|
66
|
+
is involved, use PostgreSQL upgrade tooling first.
|
|
67
|
+
|
|
68
|
+
## Safe reset policy
|
|
69
|
+
|
|
70
|
+
Safe reset intentionally avoids deleting user-editable legacy paths from old
|
|
71
|
+
compose templates. Preview output must warn when these paths may remain:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
docs/assets/
|
|
75
|
+
test/
|
|
76
|
+
.github/
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
In addition, safe reset preserves local runtime and source-data state while refreshing
|
|
80
|
+
generated and compose assets:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
.env
|
|
84
|
+
data/
|
|
85
|
+
backups/
|
|
86
|
+
odoo/custom/src/oca/
|
|
87
|
+
odoo/custom/src/external/
|
|
88
|
+
odoo/custom/patches/
|
|
89
|
+
odoo/custom/manifests/
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Run `npx @wpmoo/toolkit reset --dry-run` before writing changes when you need to
|
|
93
|
+
review the generated file refresh plan.
|
|
94
|
+
|
|
95
|
+
## Snapshot policy
|
|
96
|
+
|
|
97
|
+
Use restore preview before a destructive restore:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
./moo restore-snapshot --dry-run <snapshot-name> [db]
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
`WPMOO_SNAPSHOT_RETENTION_COUNT` may be set to a positive integer to prune old
|
|
104
|
+
snapshot manifests and their matching dump/filestore files after a new snapshot
|
|
105
|
+
is written.
|
|
106
|
+
|
|
107
|
+
## Source manifest checks
|
|
108
|
+
|
|
109
|
+
Generated environments include `odoo/custom/manifests/sources.yaml`. The manifest
|
|
110
|
+
records each source repository's type (`private`, `oca`, or `external`), path,
|
|
111
|
+
URL, Odoo branch, and addon boundaries.
|
|
112
|
+
|
|
113
|
+
Use `source list` to inspect the current manifest view:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
npx @wpmoo/toolkit source list
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Use `source sync` after manual submodule or metadata repair to regenerate the
|
|
120
|
+
manifest and normalize `.wpmoo/odoo.json` source entries:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npx @wpmoo/toolkit source sync
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
`doctor` fails when manifest entries, metadata entries, and registered source
|
|
127
|
+
submodule paths diverge. `doctor --fix` can regenerate
|
|
128
|
+
`odoo/custom/manifests/sources.yaml` from metadata plus `.gitmodules` when the
|
|
129
|
+
manifest is missing, unreadable, or stale.
|
|
130
|
+
|
|
131
|
+
## Local verification commands
|
|
132
|
+
|
|
133
|
+
Run from the `wpmoo-toolkit` repository root:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
npm run typecheck
|
|
137
|
+
npm test
|
|
138
|
+
npm run test:coverage
|
|
139
|
+
npm run build
|
|
140
|
+
```
|
package/docs/handoff.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Historical Handoff Notes
|
|
2
|
+
|
|
3
|
+
This file is an archive pointer for pre-0.8.37 handoff notes. Those notes
|
|
4
|
+
included a stale direct publish attempt and must not be used as current release
|
|
5
|
+
guidance.
|
|
6
|
+
|
|
7
|
+
Current release path:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm run release:check
|
|
11
|
+
npm run typecheck
|
|
12
|
+
npm test
|
|
13
|
+
npm run build
|
|
14
|
+
VERSION="$(node -p "require('./package.json').version")"
|
|
15
|
+
git tag -a "v$VERSION" -m "Release v$VERSION"
|
|
16
|
+
git push origin "v$VERSION"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
If `npm run release:check` bumps `package.json` and `package-lock.json`, commit
|
|
20
|
+
and push that version bump first, then rerun the release check before tagging.
|
|
21
|
+
|
|
22
|
+
Publishing is handled by the `Publish` GitHub Actions workflow through npm
|
|
23
|
+
Trusted Publishing after the tag is pushed. Do not run `npm publish` manually
|
|
24
|
+
unless a coordinator explicitly requests a fallback.
|
|
25
|
+
|
|
26
|
+
Current command standard:
|
|
27
|
+
|
|
28
|
+
- Use `npx @wpmoo/toolkit ...` for package/operator commands.
|
|
29
|
+
- Use generated environment `./moo ...` for local compose daily commands.
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wpmoo/toolkit",
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "WPMoo Toolkit for development, staging, and production lifecycle workflows.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/wpmoo-org/wpmoo-toolkit.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/wpmoo-org/wpmoo-toolkit",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/wpmoo-org/wpmoo-toolkit/issues"
|
|
13
|
+
},
|
|
14
|
+
"readmeFilename": "README.md",
|
|
15
|
+
"main": "./dist/cli.js",
|
|
16
|
+
"exports": "./dist/cli.js",
|
|
17
|
+
"keywords": [
|
|
18
|
+
"odoo",
|
|
19
|
+
"wpmoo",
|
|
20
|
+
"wpmoo toolkit",
|
|
21
|
+
"toolkit",
|
|
22
|
+
"odoo development",
|
|
23
|
+
"odoo cli",
|
|
24
|
+
"odoo lifecycle",
|
|
25
|
+
"odoo dev workflow",
|
|
26
|
+
"odoo staging workflow",
|
|
27
|
+
"odoo production workflow",
|
|
28
|
+
"odoo docker",
|
|
29
|
+
"odoo docker compose",
|
|
30
|
+
"odoo skills"
|
|
31
|
+
],
|
|
32
|
+
"bin": {
|
|
33
|
+
"wpmoo": "dist/cli.js"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"docs/assets",
|
|
38
|
+
"docs/*.md"
|
|
39
|
+
],
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=20.17"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"prebuild": "node -e \"require('node:fs').rmSync('dist', { recursive: true, force: true })\"",
|
|
45
|
+
"build": "tsc -p tsconfig.build.json",
|
|
46
|
+
"release:check": "bash scripts/release-check.sh",
|
|
47
|
+
"smoke:published": "bash scripts/smoke-published.sh",
|
|
48
|
+
"test": "vitest run",
|
|
49
|
+
"test:coverage": "vitest run --coverage",
|
|
50
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
51
|
+
},
|
|
52
|
+
"dependencies": {
|
|
53
|
+
"@inquirer/prompts": "^8.4.3",
|
|
54
|
+
"@inquirer/search": "^4.1.9",
|
|
55
|
+
"@inquirer/select": "^5.1.5",
|
|
56
|
+
"execa": "^9.6.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/node": "^24.0.0",
|
|
60
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
61
|
+
"typescript": "^5.8.0",
|
|
62
|
+
"vitest": "^3.0.0"
|
|
63
|
+
},
|
|
64
|
+
"license": "MIT"
|
|
65
|
+
}
|