@wpmoo/odoo 0.8.69 → 0.9.1

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.
Files changed (47) hide show
  1. package/bin/wpmoo.js +10 -0
  2. package/package.json +11 -45
  3. package/LICENSE +0 -22
  4. package/README.md +0 -510
  5. package/dist/addons-yaml.js +0 -59
  6. package/dist/args.js +0 -259
  7. package/dist/cli.js +0 -996
  8. package/dist/cockpit/command-palette.js +0 -23
  9. package/dist/cockpit/command-registry.js +0 -91
  10. package/dist/cockpit/daily-prompts.js +0 -177
  11. package/dist/cockpit/menu.js +0 -96
  12. package/dist/cockpit/safety.js +0 -22
  13. package/dist/compose-layout.js +0 -118
  14. package/dist/daily-actions.js +0 -190
  15. package/dist/doctor.js +0 -519
  16. package/dist/environment-context.js +0 -10
  17. package/dist/environment-version.js +0 -5
  18. package/dist/environment.js +0 -136
  19. package/dist/external-assets.js +0 -153
  20. package/dist/external-templates.js +0 -86
  21. package/dist/git.js +0 -98
  22. package/dist/github.js +0 -87
  23. package/dist/help.js +0 -151
  24. package/dist/menu-navigation.js +0 -67
  25. package/dist/module-actions.js +0 -114
  26. package/dist/odoo-versions.js +0 -1
  27. package/dist/path-validation.js +0 -50
  28. package/dist/prompt-copy.js +0 -8
  29. package/dist/prompt-repositories.js +0 -34
  30. package/dist/prompts/index.js +0 -149
  31. package/dist/repo-actions.js +0 -158
  32. package/dist/repo-url.js +0 -27
  33. package/dist/repository-preflight.js +0 -46
  34. package/dist/safe-reset.js +0 -217
  35. package/dist/scaffold.js +0 -161
  36. package/dist/source-actions.js +0 -65
  37. package/dist/source-manifest.js +0 -338
  38. package/dist/status.js +0 -239
  39. package/dist/templates.js +0 -749
  40. package/dist/types.js +0 -1
  41. package/dist/update-check.js +0 -106
  42. package/dist/version.js +0 -19
  43. package/docs/assets/patreon-donate.png +0 -0
  44. package/docs/assets/wpmoo-banner.png +0 -0
  45. package/docs/external-resources.md +0 -136
  46. package/docs/generated-environment-verification.md +0 -140
  47. package/docs/handoff.md +0 -29
package/dist/templates.js DELETED
@@ -1,749 +0,0 @@
1
- import { packageName, packageVersion } from './version.js';
2
- function fallbackPackageSpec() {
3
- return `${packageName()}@${packageVersion()}`;
4
- }
5
- export function defaultCommunityAddons(product) {
6
- return [product];
7
- }
8
- export function defaultProAddons(product) {
9
- return [`${product}_pro`];
10
- }
11
- function titleizeProduct(product) {
12
- return product
13
- .split(/[_-]+/)
14
- .filter(Boolean)
15
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
16
- .join(' ');
17
- }
18
- function yamlList(items) {
19
- return items.map((item) => ` - ${item}`).join('\n');
20
- }
21
- function allAddons(options) {
22
- return options.sourceRepos.flatMap((repo) => repo.addons);
23
- }
24
- function hasSourceRepos(options) {
25
- return options.sourceRepos.length > 0;
26
- }
27
- function sourceTypeOf(repo) {
28
- return repo.sourceType ?? 'private';
29
- }
30
- function sourceRepoRelativePath(repo) {
31
- return `odoo/custom/src/${sourceTypeOf(repo)}/${repo.path}`;
32
- }
33
- function repositoryLayout(options) {
34
- const sourceRepoRows = hasSourceRepos(options)
35
- ? options.sourceRepos
36
- .map((repo, index) => {
37
- const connector = index === options.sourceRepos.length - 1 ? '└──' : '├──';
38
- return `│ │ │ ${connector} ${repo.path}/ # Project-owned addon source repository`;
39
- })
40
- .join('\n')
41
- : '│ │ │ └── (add project-owned repos with ./moo add-repo)';
42
- return `${options.devRepo}/ # Development environment root
43
- ├── compose.yaml # Base Docker Compose file
44
- ├── compose/ # Compose overlays for each workflow
45
- │ ├── dev.yaml # Local development services
46
- │ ├── debug.yaml # Debug tooling and debug-friendly settings
47
- │ ├── test.yaml # Test runner services and test database setup
48
- │ ├── stage.yaml # Staging-like deployment overlay
49
- │ ├── prod.yaml # Production deployment overlay
50
- │ ├── proxy.yaml # Reverse proxy / edge routing overlay
51
- │ └── tools.yaml # Optional maintenance and helper tools
52
- ├── config/ # Runtime configuration mounted into containers
53
- │ ├── odoo/ # Odoo server configuration
54
- │ │ ├── odoo.conf # Main Odoo configuration file
55
- │ │ └── requirements.txt # Extra Python dependencies for the Odoo container
56
- │ └── logrotate/ # Log rotation configuration
57
- │ └── odoo # Logrotate rules for Odoo logs
58
- ├── resources/ # Container-side helper resources
59
- │ └── odoo/ # Resources specific to the Odoo service
60
- │ └── entrypoint.sh # Container startup script that discovers addons
61
- ├── moo # Local command hub shortcut
62
- ├── scripts/ # Shell scripts used by the local command hub
63
- ├── odoo/ # Odoo workspace data and custom source tree
64
- │ └── custom/ # Custom addon layer for this environment
65
- │ ├── src/ # Source repository checkout root
66
- │ │ ├── private/ # Project-owned/private addon repositories
67
- ${sourceRepoRows}
68
- │ │ ├── oca/ # OCA addon repositories
69
- │ │ └── external/ # Non-OCA third-party addon repositories
70
- │ ├── patches/ # Local patches for upstream repositories
71
- │ └── manifests/ # Source manifests, locks, and pinned revisions
72
- ├── docs/ # Project-specific documentation
73
- │ ├── appstore-release.md # Odoo App Store release checklist and notes
74
- │ └── compose.md # Compose layout and operations reference
75
- ├── .env.example # Template for local environment variables
76
- ├── README.md # This environment overview
77
- └── AGENTS.md # Agent instructions for this environment`;
78
- }
79
- function sourceRepoDocs(options) {
80
- if (!hasSourceRepos(options)) {
81
- return `This environment was scaffolded without source repository submodules.
82
- Add source repositories later from the cockpit or with \`npx @wpmoo/odoo add-repo\`.
83
- They can be organized under:
84
-
85
- \`odoo/custom/src/private\` for project-owned/private addon repositories,
86
- \`odoo/custom/src/oca\` for OCA repositories, and
87
- \`odoo/custom/src/external\` for non-OCA third-party repositories.
88
-
89
- Pinned external manifests and local patches should live under
90
- \`odoo/custom/manifests\` and \`odoo/custom/patches\` respectively.`;
91
- }
92
- return options.sourceRepos
93
- .map((repo) => `### ${repo.path}
94
-
95
- URL:
96
-
97
- \`\`\`text
98
- ${repo.url}
99
- \`\`\`
100
-
101
- Submodule path:
102
-
103
- \`\`\`text
104
- ${sourceRepoRelativePath(repo)}
105
- \`\`\`
106
-
107
- Source manifest entry:
108
-
109
- \`\`\`text
110
- odoo/custom/manifests/sources.yaml
111
- \`\`\`
112
-
113
- Expected addon layout:
114
-
115
- \`\`\`text
116
- ${repo.path}/
117
- ${repo.addons.map((addon) => `├── ${addon}/`).join('\n')}
118
- \`\`\``)
119
- .join('\n\n');
120
- }
121
- function cloneDocs(options) {
122
- if (!hasSourceRepos(options)) {
123
- return `## Local Folder
124
-
125
- This environment is ready in this folder:
126
-
127
- \`\`\`bash
128
- cd ${options.devRepo}
129
- \`\`\`
130
-
131
- If you later connect it to Git, commit the generated files after reviewing them.
132
- `;
133
- }
134
- return `## Clone
135
-
136
- Clone with submodules:
137
-
138
- \`\`\`bash
139
- git clone --recurse-submodules ${options.devRepoUrl}
140
- cd ${options.devRepo}
141
- \`\`\`
142
-
143
- If already cloned:
144
-
145
- \`\`\`bash
146
- git submodule update --init --recursive
147
- \`\`\`
148
- `;
149
- }
150
- function optionalAgentSkillsReadme(options) {
151
- if (!options.agentSkillsTemplateUrl)
152
- return '';
153
- return `
154
- ## Agent Skills
155
-
156
- This environment is configured to install project-local Agent Skills from:
157
-
158
- \`\`\`text
159
- ${options.agentSkillsTemplateUrl}${options.agentSkillsTemplateRef ? `#${options.agentSkillsTemplateRef}` : ''}
160
- \`\`\`
161
-
162
- After external resource installation, skills normally live under:
163
-
164
- \`\`\`text
165
- .agents/skills/
166
- \`\`\`
167
-
168
- Agents that support the Agent Skills standard can load them on demand.
169
- `;
170
- }
171
- function optionalAgentSkillsAgentsSection(options) {
172
- if (!options.agentSkillsTemplateUrl)
173
- return '';
174
- return `
175
- ## Active Agent Skills
176
-
177
- When using an agent that supports Agent Skills, prefer the project-local skills
178
- installed under \`.agents/skills/\`. They are sourced from:
179
-
180
- \`\`\`text
181
- ${options.agentSkillsTemplateUrl}${options.agentSkillsTemplateRef ? `#${options.agentSkillsTemplateRef}` : ''}
182
- \`\`\`
183
- `;
184
- }
185
- function environmentKind() {
186
- return 'Docker Compose';
187
- }
188
- function repoDuplicationNote() {
189
- return 'Keep source repositories under the relevant source directory (`private`, `oca`, or `external`); the Compose entrypoint exposes discovered addons through `/mnt/wpmoo-addons`.';
190
- }
191
- function verificationCommand(options) {
192
- const firstAddon = allAddons(options)[0] ?? options.product;
193
- return `./moo test ${firstAddon}`;
194
- }
195
- function environmentUsageDocs(options) {
196
- return `## Docker Compose Notes
197
-
198
- This environment uses the compact WPMoo Compose layout:
199
-
200
- \`\`\`text
201
- compose.yaml
202
- compose/dev.yaml
203
- compose/stage.yaml
204
- compose/prod.yaml
205
- config/odoo/odoo.conf
206
- resources/odoo/entrypoint.sh
207
- \`\`\`
208
-
209
- Development uses compose.yaml plus compose/dev.yaml by default.
210
- Set WPMOO_ENV=stage or WPMOO_ENV=prod only after providing production-grade secrets and volumes.
211
-
212
- If copied from the standalone resource, additional compose notes are in
213
- \`docs/compose.md\`.
214
-
215
- Source repositories stay under \`odoo/custom/src/{private,oca,external}\` when
216
- configured. At
217
- container startup, \`entrypoint.sh\` scans those repositories for addons and
218
- exposes them through \`/mnt/wpmoo-addons\`.
219
-
220
- ## Daily Command Hub (\`./moo\`)
221
-
222
- \`./moo\` routes day-to-day service and module workflows to local scripts in
223
- \`./scripts/\` (for example \`start\`, \`logs\`, \`update\`, \`test\`, \`snapshot\`).
224
- \`./moo status\` and \`./moo doctor\` are package fallback commands that run via
225
- \`npx --yes ${fallbackPackageSpec()} ...\`.
226
-
227
- ### Start And Inspect Services
228
-
229
- \`\`\`bash
230
- cp .env.example .env
231
- ./moo start
232
- ./moo logs odoo
233
- ./moo shell
234
- ./moo psql postgres
235
- ./moo stop
236
- \`\`\`
237
-
238
- ### Run, Update, And Test Modules
239
-
240
- \`\`\`bash
241
- ./moo install ${allAddons(options)[0] ?? options.product}
242
- ./moo update ${allAddons(options)[0] ?? options.product}
243
- ./moo test ${allAddons(options)[0] ?? options.product}
244
- \`\`\`
245
-
246
- ### Snapshot And Restore
247
-
248
- \`\`\`bash
249
- ./moo snapshot devel before-update
250
- ./moo restore-snapshot --dry-run before-update devel
251
- ./moo restore-snapshot before-update devel
252
- \`\`\`
253
-
254
- ### Lint
255
-
256
- \`\`\`bash
257
- ./moo lint
258
- \`\`\`
259
-
260
- ### Export Translations
261
-
262
- \`\`\`bash
263
- ./moo pot ${allAddons(options)[0] ?? options.product} devel i18n/${allAddons(options)[0] ?? options.product}.pot
264
- \`\`\`
265
-
266
- ### Recover / Reset
267
-
268
- \`\`\`bash
269
- ./moo doctor
270
- ./moo status
271
- ./moo resetdb devel ${allAddons(options)[0] ?? options.product}
272
- \`\`\`
273
- `;
274
- }
275
- const BANNER_GRADIENT_START = [31, 151, 231];
276
- const BANNER_GRADIENT_END = [209, 95, 127];
277
- const ANSI_BOLD = '\u001B[1m';
278
- const ANSI_RESET = '\u001B[0m';
279
- function gradientColor(column, width) {
280
- const ratio = width <= 1 ? 0 : column / (width - 1);
281
- const [startR, startG, startB] = BANNER_GRADIENT_START;
282
- const [endR, endG, endB] = BANNER_GRADIENT_END;
283
- const r = Math.round(startR + (endR - startR) * ratio);
284
- const g = Math.round(startG + (endG - startG) * ratio);
285
- const b = Math.round(startB + (endB - startB) * ratio);
286
- return `\u001B[38;2;${r};${g};${b}m`;
287
- }
288
- function applyBannerGradient(banner) {
289
- const lines = banner.split('\n');
290
- const width = Math.max(...lines.map((line) => line.length));
291
- return lines
292
- .map((line) => Array.from(line)
293
- .map((character, column) => `${gradientColor(column, width)}${character}`)
294
- .join(''))
295
- .join('\n');
296
- }
297
- export function renderBanner() {
298
- const banner = String.raw `
299
-
300
- ╭────────────────────────────────────────────╮
301
- │ WPMoo │
302
- │ Workflow Platform · Micro Object Oriented │
303
- ╰────────────────────────────────────────────╯
304
- `;
305
- return `${ANSI_BOLD}${applyBannerGradient(banner)}${ANSI_RESET}`;
306
- }
307
- export function renderGitignore() {
308
- return `# macOS/editor noise
309
- .DS_Store
310
- .idea/
311
- .vscode/*.log
312
-
313
- # Node/local package files
314
- node_modules/
315
- dist/
316
- coverage/
317
- *.log
318
-
319
- # Python/cache files
320
- __pycache__/
321
- *.py[cod]
322
- .pytest_cache/
323
- .mypy_cache/
324
- .ruff_cache/
325
-
326
- # Local environment files
327
- .env
328
- .env.*
329
- !.env.example
330
- *.local
331
-
332
- # Local generated files
333
- *.code-workspace
334
- addons/
335
- auto/
336
- backups/
337
- data/
338
- filestore/
339
- postgresql/
340
- sessions/
341
- odoo/custom/auto/
342
- odoo/custom/src/*/.git-aggregate-cache/
343
-
344
- # Backups and archives
345
- *.bak
346
- *.backup
347
- *.dump
348
- *.sql
349
- *.zip
350
- *.tar
351
- *.tar.gz
352
- `;
353
- }
354
- export function renderMooDelegationScript() {
355
- return `#!/usr/bin/env bash
356
- set -euo pipefail
357
-
358
- script_dir="$(cd -- "$(dirname -- "\${BASH_SOURCE[0]}")" && pwd)"
359
- cd "$script_dir"
360
-
361
- usage() {
362
- case "$1" in
363
- "start") echo "Usage: ./moo start" ;;
364
- "stop") echo "Usage: ./moo stop" ;;
365
- "logs") echo "Usage: ./moo logs [service]" ;;
366
- "restart") echo "Usage: ./moo restart" ;;
367
- "shell") echo "Usage: ./moo shell" ;;
368
- "psql") echo "Usage: ./moo psql [db]" ;;
369
- "install") echo "Usage: ./moo install <module[,module]> [db]" ;;
370
- "update") echo "Usage: ./moo update <module[,module]> [db]" ;;
371
- "test") echo "Usage: ./moo test <module[,module]> [--db <db>] [--mode init|update] [--tags <tags>]" ;;
372
- "resetdb") echo "Usage: ./moo resetdb [db] [module[,module]]" ;;
373
- "snapshot") echo "Usage: ./moo snapshot [db] [snapshot-name]" ;;
374
- "restore-snapshot") echo "Usage: ./moo restore-snapshot [--dry-run] <snapshot-name> [db]" ;;
375
- "lint") echo "Usage: ./moo lint" ;;
376
- "pot") echo "Usage: ./moo pot <module[,module]> [db] [output]" ;;
377
- esac
378
- }
379
-
380
- fail_usage() {
381
- usage "$1" >&2
382
- exit 2
383
- }
384
-
385
- require_no_args() {
386
- local command="$1"
387
- shift
388
- if [[ "$#" -ne 0 ]]; then
389
- fail_usage "$command"
390
- fi
391
- }
392
-
393
- optional_single_arg() {
394
- local command="$1"
395
- local fallback="$2"
396
- shift 2
397
- if [[ "$#" -gt 1 ]]; then
398
- fail_usage "$command"
399
- fi
400
- printf '%s\\n' "\${1:-$fallback}"
401
- }
402
-
403
- require_module_args() {
404
- local command="$1"
405
- shift
406
- if [[ "$#" -lt 1 || "\${1:-}" == -* || "$#" -gt 2 ]]; then
407
- fail_usage "$command"
408
- fi
409
- }
410
-
411
- positional_args() {
412
- local command="$1"
413
- local min="$2"
414
- local max="$3"
415
- shift 3
416
- if [[ "$#" -lt "$min" || "$#" -gt "$max" ]]; then
417
- fail_usage "$command"
418
- fi
419
- for arg in "$@"; do
420
- if [[ "$arg" == -* ]]; then
421
- fail_usage "$command"
422
- fi
423
- done
424
- }
425
-
426
- validate_test_args() {
427
- if [[ "$#" -lt 1 || "\${1:-}" == -* ]]; then
428
- fail_usage "test"
429
- fi
430
-
431
- shift
432
- while [[ "$#" -gt 0 ]]; do
433
- case "$1" in
434
- "--db"|"--tags")
435
- if [[ "$#" -lt 2 || "\${2:-}" == --* ]]; then
436
- echo "Missing value for $1" >&2
437
- exit 2
438
- fi
439
- shift 2
440
- ;;
441
- "--mode")
442
- if [[ "$#" -lt 2 || "\${2:-}" == --* ]]; then
443
- echo "Missing value for --mode" >&2
444
- exit 2
445
- fi
446
- if [[ "$2" != "init" && "$2" != "update" ]]; then
447
- echo "Invalid value for --mode: expected init or update" >&2
448
- exit 2
449
- fi
450
- shift 2
451
- ;;
452
- *)
453
- echo "Unknown option for ./moo test: $1" >&2
454
- exit 2
455
- ;;
456
- esac
457
- done
458
- }
459
-
460
- run_script() {
461
- local script="$1"
462
- shift
463
- if [[ ! -x "$script" ]]; then
464
- echo "Missing daily action script: \${script#./}" >&2
465
- exit 1
466
- fi
467
- exec "$script" "$@"
468
- }
469
-
470
- command="\${1:-}"
471
- case "$command" in
472
- "start")
473
- shift
474
- require_no_args "$command" "$@"
475
- run_script ./scripts/up.sh
476
- ;;
477
- "stop")
478
- shift
479
- require_no_args "$command" "$@"
480
- run_script ./scripts/down.sh
481
- ;;
482
- "logs")
483
- shift
484
- service="$(optional_single_arg "$command" "odoo" "$@")"
485
- run_script ./scripts/logs.sh "$service"
486
- ;;
487
- "restart")
488
- shift
489
- require_no_args "$command" "$@"
490
- run_script ./scripts/restart.sh
491
- ;;
492
- "shell")
493
- shift
494
- require_no_args "$command" "$@"
495
- run_script ./scripts/shell.sh
496
- ;;
497
- "psql")
498
- shift
499
- db="$(optional_single_arg "$command" "postgres" "$@")"
500
- run_script ./scripts/psql.sh "$db"
501
- ;;
502
- "install")
503
- shift
504
- require_module_args "$command" "$@"
505
- run_script ./scripts/install.sh "$@"
506
- ;;
507
- "update")
508
- shift
509
- require_module_args "$command" "$@"
510
- run_script ./scripts/update.sh "$@"
511
- ;;
512
- "test")
513
- shift
514
- validate_test_args "$@"
515
- run_script ./scripts/test.sh "$@"
516
- ;;
517
- "resetdb")
518
- shift
519
- positional_args "$command" 0 2 "$@"
520
- run_script ./scripts/resetdb.sh "$@"
521
- ;;
522
- "snapshot")
523
- shift
524
- positional_args "$command" 0 2 "$@"
525
- run_script ./scripts/snapshot.sh "$@"
526
- ;;
527
- "restore-snapshot")
528
- shift
529
- restore_args=()
530
- if [[ "\${1:-}" == "--dry-run" ]]; then
531
- restore_args+=("--dry-run")
532
- shift
533
- fi
534
- positional_args "$command" 1 2 "$@"
535
- restore_args+=("$@")
536
- run_script ./scripts/restore-snapshot.sh "\${restore_args[@]}"
537
- ;;
538
- "lint")
539
- shift
540
- require_no_args "$command" "$@"
541
- run_script ./scripts/lint.sh
542
- ;;
543
- "pot")
544
- shift
545
- positional_args "$command" 1 3 "$@"
546
- run_script ./scripts/pot.sh "$@"
547
- ;;
548
- *)
549
- exec npx --yes ${fallbackPackageSpec()} "$@"
550
- ;;
551
- esac
552
- `;
553
- }
554
- export function renderAddonsYaml(options) {
555
- return `# Addons activated from source submodules.
556
- #
557
- # Source repos are managed as Git submodules under odoo/custom/src/private.
558
- # Do not duplicate these same repos in repos.yaml.
559
-
560
- ${options.sourceRepos.map((repo) => `${sourceTypeOf(repo)}/${repo.path}:\n${yamlList(repo.addons)}`).join('\n\n')}
561
- `;
562
- }
563
- export function renderReposYaml(options) {
564
- return `# git-aggregator repositories.
565
- #
566
- # Project source repositories are intentionally not listed here because
567
- # they are pinned as Git submodules:
568
- #
569
- ${options.sourceRepos.map((repo) => `# - ${sourceTypeOf(repo)}/${repo.path}`).join('\n')}
570
- #
571
- # Keep this file for upstream/OCA repositories that should be aggregated.
572
-
573
- odoo:
574
- defaults:
575
- depth: $DEPTH_MERGE
576
- remotes:
577
- origin: https://github.com/OCA/OCB.git
578
- odoo: https://github.com/odoo/odoo.git
579
- target: origin $ODOO_VERSION
580
- merges:
581
- - origin $ODOO_VERSION
582
- `;
583
- }
584
- export function renderReadme(options) {
585
- const title = titleizeProduct(options.product);
586
- return `# ${title} Development Environment
587
-
588
- Private ${environmentKind()} development environment for the ${title} product.
589
-
590
- This folder owns the development environment only. Product source code lives
591
- in source repository submodules under \`odoo/custom/src/private\`,
592
- \`odoo/custom/src/oca\`, or \`odoo/custom/src/external\` when source
593
- repositories are connected.
594
-
595
- ## Repository Layout
596
-
597
- \`\`\`text
598
- ${repositoryLayout(options)}
599
- \`\`\`
600
-
601
- ${cloneDocs(options)}
602
-
603
- ## WPMoo CLI Shortcut
604
-
605
- This environment includes a local \`moo\` shortcut script. From the repository
606
- root:
607
-
608
- \`\`\`bash
609
- ./moo
610
- ./moo start
611
- ./moo stop
612
- ./moo restart
613
- ./moo doctor
614
- ./moo add-module
615
- \`\`\`
616
-
617
- Optionally, if this repository root is on your \`PATH\`, you can run \`moo ...\`
618
- from anywhere and the script will return to this environment root first.
619
- ${optionalAgentSkillsReadme(options)}
620
- ## Source Repositories
621
-
622
- ${sourceRepoDocs(options)}
623
-
624
- ${environmentUsageDocs(options)}
625
- ## Branching
626
-
627
- Use Odoo major-version branches in source repositories when you add them:
628
-
629
- \`\`\`text
630
- ${options.odooVersion}
631
- \`\`\`
632
-
633
- If this environment is connected to Git, the dev repository can stay on \`main\`
634
- and pin exact source commits through submodule references.
635
- `;
636
- }
637
- export function renderAgents(options) {
638
- const repoList = hasSourceRepos(options)
639
- ? options.sourceRepos.map((repo) => `- \`${repo.path}\`: \`${repo.url}\``).join('\n')
640
- : '- No source repositories are configured yet.';
641
- const sourceLayout = hasSourceRepos(options)
642
- ? `Product repositories are Git submodules. They are listed under the private
643
- source directory below for this environment:
644
-
645
- \`\`\`text
646
- ${options.sourceRepos.map(sourceRepoRelativePath).join('\n')}
647
- \`\`\`
648
-
649
- ${repoDuplicationNote()}`
650
- : 'No source repositories are configured yet. Use `./moo add-repo` or the cockpit Repositories menu before module-specific work.';
651
- const addonList = hasSourceRepos(options)
652
- ? options.sourceRepos
653
- .map((repo) => `\`${repo.path}\` addons:\n${repo.addons.map((addon) => `- \`${addon}\``).join('\n')}`)
654
- .join('\n\n')
655
- : 'No addon boundaries are known yet. Add source repositories before module-specific implementation.';
656
- return `# AGENTS.md
657
-
658
- ## Project
659
-
660
- Private ${environmentKind()} development environment for the ${titleizeProduct(options.product)} product.
661
-
662
- ## Repository Roles
663
-
664
- - \`${options.devRepo}\`: environment/config only, private.
665
- ${repoList}
666
-
667
- ## Source Layout
668
-
669
- ${sourceLayout}
670
- ${optionalAgentSkillsAgentsSection(options)}
671
- ## Addon Boundaries
672
-
673
- ${addonList}
674
-
675
- Public/community addons must not depend on private paid addons. Private paid
676
- addons may depend on public/community addons.
677
-
678
- ## Odoo 19 Rules
679
-
680
- - Use \`<list>\` instead of \`<tree>\`.
681
- - Use direct view expressions such as \`invisible="..."\` instead of \`attrs\`.
682
- - Use \`models.Constraint\` instead of \`_sql_constraints\`.
683
- - Use \`@api.ondelete(at_uninstall=False)\` for delete validation.
684
- - Avoid \`default_*\` field names in \`res.config.settings\`.
685
- - Keep core/community installable without any pro modules.
686
-
687
- ## Verification
688
-
689
- Use the environment's addon test/update command:
690
-
691
- \`\`\`bash
692
- ${verificationCommand(options)}
693
- \`\`\`
694
-
695
- Useful maintenance commands:
696
-
697
- \`\`\`bash
698
- ./moo lint
699
- ./moo resetdb [db] [module[,module]]
700
- ./moo snapshot [db] [snapshot-name]
701
- ./moo restore-snapshot [--dry-run] <snapshot-name> [db]
702
- ./moo pot <module[,module]> [db] [output]
703
- \`\`\`
704
-
705
- Daily script delegation vs package fallback:
706
- - \`./moo start\`, \`logs\`, \`install\`, \`update\`, \`test\`, \`snapshot\`, and related runtime tasks delegate to local \`./scripts/*.sh\`.
707
- - \`./moo status\` and \`./moo doctor\` are package fallback commands routed to \`npx --yes ${fallbackPackageSpec()} ...\`.
708
-
709
- Only report completion after the relevant update/test/lint command exits cleanly.
710
- `;
711
- }
712
- export function renderAppstoreRelease(options) {
713
- return `# Odoo Apps Release Notes
714
-
715
- Paid addons can live together in a private source repository during development.
716
- Each paid addon still needs its own App Store metadata.
717
-
718
- Per addon checklist:
719
-
720
- - \`__manifest__.py\` has correct \`name\`, \`summary\`, \`version\`, \`depends\`,
721
- \`license\`, \`price\`, \`currency\`, and \`support\`.
722
- - \`license\` is appropriate for paid distribution, typically \`OPL-1\`.
723
- - \`static/description/icon.png\` exists.
724
- - \`static/description/index.html\` exists.
725
- - Screenshots are stored under \`static/description/\`.
726
- - Community dependency versions are compatible with the target Odoo major
727
- version.
728
-
729
- Recommended release flow:
730
-
731
- 1. Develop in the relevant private source repository.
732
- 2. Update the addon manifest version.
733
- 3. Run update/test commands in this dev environment.
734
- 4. Tag the source commit.
735
- 5. Prepare an App Store publish package or publish mirror per paid addon.
736
- 6. Trigger Odoo Apps repository scan/update.
737
-
738
- If App Store scan coupling becomes a problem, create separate private publish
739
- mirror repositories for each paid addon. Keep development in
740
- \`odoo/custom/src/private\`; mirrors should be generated artifacts, not
741
- hand-edited source repositories.
742
- `;
743
- }
744
- export function renderPlaceholder(title, body) {
745
- return `# ${title}
746
-
747
- ${body}
748
- `;
749
- }