@wpmoo/odoo 0.8.30

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 ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 WPMoo.org
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,231 @@
1
+ # @wpmoo/odoo
2
+
3
+ ![WPMoo Odoo lifecycle tooling across development, staging, and production](https://cdn.jsdelivr.net/npm/@wpmoo/odoo/docs/assets/wpmoo-banner.png)
4
+
5
+ [![CI](https://github.com/wpmoo-org/wpmoo-odoo/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/wpmoo-org/wpmoo-odoo/actions/workflows/ci.yml)
6
+
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
+
9
+ WPMoo Odoo lifecycle tooling for development, staging, and production workflows.
10
+
11
+ The CLI currently creates Docker Compose based Odoo environments, adds source
12
+ repositories as Git submodules, and stages the result with `git add .`. It does
13
+ not commit. Staging and production workflows will build on the same package and
14
+ command surface.
15
+
16
+ Compose resources and project-local Agent Skills are copied from standalone
17
+ repositories, so large Docker/skill assets do not need to be embedded in the
18
+ TypeScript CLI. The compose resource uses static version-specific files such as
19
+ `docker-compose_19.0.yml` so it can also be used standalone.
20
+
21
+ For a product named `odoo_sample_module`, create these repositories first:
22
+
23
+ ```text
24
+ odoo_sample_module_dev # private development environment repo
25
+ odoo_sample_module # source repo
26
+ ```
27
+
28
+ The CLI writes into `./odoo_sample_module_dev`. If that directory does not exist
29
+ locally, it clones the dev repo URL you provide.
30
+
31
+ When GitHub CLI is installed and authenticated, the interactive wizard detects
32
+ your GitHub username and organizations. If multiple accounts are available, it
33
+ asks where the repos should live and uses that owner for the default repo URLs.
34
+ The wizard also checks whether the dev and source repositories are accessible.
35
+ If they are not accessible, it can create them for you after confirmation.
36
+
37
+ ```bash
38
+ brew install gh
39
+ gh auth login
40
+ ```
41
+
42
+ Use cloneable repository URLs such as
43
+ `https://github.com/example-org/odoo_sample_module.git`. If a GitHub
44
+ organization page URL like `https://github.com/orgs/example-org/odoo_sample_module`
45
+ is entered, the CLI normalizes it to the cloneable form.
46
+
47
+ ## Usage
48
+
49
+ Interactive wizard:
50
+
51
+ ```bash
52
+ npx @wpmoo/odoo
53
+ ```
54
+
55
+ The wizard is context-aware. If the current directory is not already a WPMoo
56
+ Odoo development environment, it starts the create flow directly.
57
+
58
+ Inside an existing environment, it shows maintenance actions:
59
+
60
+ ```text
61
+ Add source repo
62
+ Remove source repo
63
+ Add module to source repo
64
+ Remove module from source repo
65
+ Safe reset environment
66
+ ```
67
+
68
+ Non-interactive:
69
+
70
+ ```bash
71
+ npx @wpmoo/odoo create \
72
+ --product odoo_sample_module \
73
+ --odoo-version 19.0 \
74
+ --dev-repo-url https://github.com/example-org/odoo_sample_module_dev.git \
75
+ --source-repo-url https://github.com/example-org/odoo_sample_module.git \
76
+ --create-missing-repos \
77
+ --init-empty-repos
78
+ ```
79
+
80
+ Multiple source repositories:
81
+
82
+ ```bash
83
+ npx @wpmoo/odoo create \
84
+ --product odoo_sample_module \
85
+ --dev-repo-url https://github.com/example-org/odoo_sample_module_dev.git \
86
+ --source-repo-url https://github.com/example-org/odoo_sample_module.git \
87
+ --source-addons odoo_sample_module,odoo_sample_module_portal \
88
+ --source-repo-url git@github.com:example-org/odoo_sample_module_reports.git \
89
+ --source-path odoo_sample_module_reports \
90
+ --source-addons odoo_sample_module_reports
91
+ ```
92
+
93
+ Dry run:
94
+
95
+ ```bash
96
+ npx @wpmoo/odoo create \
97
+ --product odoo_sample_module \
98
+ --dev-repo-url https://github.com/example-org/odoo_sample_module_dev.git \
99
+ --source-repo-url https://github.com/example-org/odoo_sample_module.git \
100
+ --dry-run
101
+ ```
102
+
103
+ Default Docker Compose engine through an external standalone compose resource:
104
+
105
+ ```bash
106
+ npx @wpmoo/odoo create \
107
+ --product odoo_sample_module \
108
+ --dev-repo-url https://github.com/example-org/odoo_sample_module_dev.git \
109
+ --source-repo-url https://github.com/example-org/odoo_sample_module.git \
110
+ --agent-skills-template
111
+ ```
112
+
113
+ During local resource development, point to local clones of the standalone repos:
114
+
115
+ ```bash
116
+ git clone https://github.com/wpmoo-org/odoo-docker-compose ../odoo-docker-compose
117
+ git clone https://github.com/wpmoo-org/odoo-skills ../odoo-skills
118
+
119
+ npx @wpmoo/odoo create \
120
+ --engine compose \
121
+ --compose-template-url ../odoo-docker-compose \
122
+ --agent-skills-template \
123
+ --agent-skills-template-url ../odoo-skills \
124
+ --product odoo_sample_module \
125
+ --source-repo-url https://github.com/example-org/odoo_sample_module.git
126
+ ```
127
+
128
+ Add a source repository later from inside the dev environment:
129
+
130
+ ```bash
131
+ npx @wpmoo/odoo
132
+ ```
133
+
134
+ Choose `Add source repo`, then enter only the repository name, such as
135
+ `odoo_sample_module_reports`. The CLI uses the environment's GitHub owner and
136
+ Odoo version, checks whether the repository exists, can create it with GitHub
137
+ CLI when needed, and initializes empty repositories with the environment Odoo
138
+ branch automatically.
139
+
140
+ Non-interactive URL form:
141
+
142
+ ```bash
143
+ npx @wpmoo/odoo add-repo \
144
+ --repo-url https://github.com/example-org/odoo_sample_module_reports.git \
145
+ --odoo-version 19.0 \
146
+ --init-empty-repos
147
+ ```
148
+
149
+ When run inside a generated environment, maintenance actions use the environment
150
+ Odoo version from `.wpmoo/odoo.json`. Pass `--odoo-version` only when you
151
+ need an explicit override.
152
+
153
+ Remove a source repository from the dev environment:
154
+
155
+ ```bash
156
+ npx @wpmoo/odoo remove-repo --repo odoo_sample_module_reports
157
+ ```
158
+
159
+ Add a minimal Odoo module skeleton to a selected source repository:
160
+
161
+ ```bash
162
+ npx @wpmoo/odoo add-module \
163
+ --repo odoo_sample_module \
164
+ --module odoo_sample_module_base \
165
+ --odoo-version 19.0
166
+ ```
167
+
168
+ Remove a module registration without deleting source files:
169
+
170
+ ```bash
171
+ npx @wpmoo/odoo remove-module \
172
+ --repo odoo_sample_module \
173
+ --module odoo_sample_module_base
174
+ ```
175
+
176
+ Refresh generated environment files without deleting module source code:
177
+
178
+ ```bash
179
+ npx @wpmoo/odoo reset
180
+ ```
181
+
182
+ ## Defaults
183
+
184
+ Each source repo can contain one or many Odoo modules. For example:
185
+
186
+ ```text
187
+ odoo/custom/src/private/odoo_sample_module/
188
+ ├── odoo_sample_module_base/
189
+ └── odoo_sample_module_another_module/
190
+
191
+ odoo/custom/src/private/odoo_sample_module_pro/
192
+ ├── odoo_sample_module_payment/
193
+ └── odoo_sample_module_analytics/
194
+ ```
195
+
196
+ If the project has portal, demo, payment, reports, or other addons, pass
197
+ `--source-addons` in non-interactive advanced usage or add modules later with the
198
+ CLI.
199
+
200
+ ## WPMoo Development Guidelines
201
+
202
+ The CLI keeps environment creation focused on Docker Compose resources, source
203
+ submodules, and WPMoo metadata. It does not install agent tools, editor setup,
204
+ doctor scripts, or other optional development packs.
205
+
206
+ If you want agent-assisted workflows inside a generated environment, install
207
+ and manage them manually in that environment. For example, Agentic Stack can be
208
+ installed separately:
209
+
210
+ ```bash
211
+ brew tap codejunkie99/agentic-stack https://github.com/codejunkie99/agentic-stack
212
+ brew install agentic-stack
213
+ agentic-stack codex --yes
214
+ ```
215
+
216
+ Keep these files under normal project review, just like any other generated or
217
+ tool-owned development guideline files.
218
+
219
+ ## Notes
220
+
221
+ - V1 is overlay-first and uses WPMoo's Docker Compose resources by default.
222
+ - Product source repositories are managed as Git submodules under
223
+ `odoo/custom/src/private`.
224
+ - Product source repositories are discovered from `odoo/custom/src/private` by
225
+ the compose entrypoint and exposed through `/mnt/wpmoo-addons`.
226
+ - Empty source repos can be initialized with an empty commit and the selected
227
+ Odoo branch when `--init-empty-repos` is provided.
228
+ - Missing GitHub repositories can be created with GitHub CLI when
229
+ `--create-missing-repos` is provided, or through the interactive wizard.
230
+ - Legacy `--org`, `--community-repo`, and `--pro-repo` flags are still accepted
231
+ when no `--source-repo-url` flags are provided.
@@ -0,0 +1,59 @@
1
+ function escapeRegExp(value) {
2
+ return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
3
+ }
4
+ function ensureFinalNewline(value) {
5
+ return value.endsWith('\n') ? value : `${value}\n`;
6
+ }
7
+ function yamlList(items) {
8
+ return items.map((item) => ` - ${item}`).join('\n');
9
+ }
10
+ function renderSourceRepoBlock(repo) {
11
+ return `private/${repo.path}:\n${yamlList(repo.addons)}\n`;
12
+ }
13
+ export function addSourceRepoToAddonsYaml(content, repo) {
14
+ const blockPattern = new RegExp(`^private/${escapeRegExp(repo.path)}:\\s*$`, 'm');
15
+ if (blockPattern.test(content)) {
16
+ return content;
17
+ }
18
+ const base = ensureFinalNewline(content.trimEnd());
19
+ return `${base}\n${renderSourceRepoBlock(repo)}`;
20
+ }
21
+ export function removeSourceRepoFromAddonsYaml(content, repoPath) {
22
+ const blockPattern = new RegExp(`(^|\\n)private/${escapeRegExp(repoPath)}:\\n(?:[ \\t].*(?:\\n|$))*`, 'g');
23
+ const updated = content
24
+ .replace(blockPattern, (match, prefix) => (prefix === '\n' && match.endsWith('\n') ? '\n' : ''))
25
+ .replace(/\n{3,}/g, '\n\n');
26
+ return ensureFinalNewline(updated.trimEnd());
27
+ }
28
+ function sourceRepoBlockPattern(repoPath) {
29
+ return new RegExp(`(^private/${escapeRegExp(repoPath)}:\\n)((?:[ \\t].*(?:\\n|$))*)`, 'm');
30
+ }
31
+ function parseYamlListItems(blockBody) {
32
+ return blockBody
33
+ .split('\n')
34
+ .map((line) => line.trim().match(/^-\s+(.+)$/)?.[1]?.trim())
35
+ .filter((item) => Boolean(item));
36
+ }
37
+ export function addModuleToSourceRepoInAddonsYaml(content, repoPath, moduleName) {
38
+ const blockPattern = sourceRepoBlockPattern(repoPath);
39
+ const match = content.match(blockPattern);
40
+ if (!match) {
41
+ return addSourceRepoToAddonsYaml(content, { path: repoPath, addons: [moduleName] });
42
+ }
43
+ const addons = parseYamlListItems(match[2]);
44
+ if (addons.includes(moduleName)) {
45
+ return content;
46
+ }
47
+ const replacement = `${match[1]}${yamlList([...addons, moduleName])}\n`;
48
+ return content.replace(blockPattern, replacement);
49
+ }
50
+ export function removeModuleFromSourceRepoInAddonsYaml(content, repoPath, moduleName) {
51
+ const blockPattern = sourceRepoBlockPattern(repoPath);
52
+ const match = content.match(blockPattern);
53
+ if (!match) {
54
+ return content;
55
+ }
56
+ const addons = parseYamlListItems(match[2]).filter((addon) => addon !== moduleName);
57
+ const replacement = `${match[1]}${addons.length ? `${yamlList(addons)}\n` : ''}`;
58
+ return ensureFinalNewline(content.replace(blockPattern, replacement).trimEnd());
59
+ }
package/dist/args.js ADDED
@@ -0,0 +1,247 @@
1
+ import { basename, resolve } from 'node:path';
2
+ import { supportedOdooVersions } from './odoo-versions.js';
3
+ import { defaultAgentSkillsTemplateUrl, defaultComposeTemplateUrl } from './external-templates.js';
4
+ import { defaultCommunityAddons, defaultProAddons } from './templates.js';
5
+ import { validateAddonName, validateRepoPath } from './path-validation.js';
6
+ import { inferGitHubOwner, inferRepoPath, normalizeRepositoryUrl } from './repo-url.js';
7
+ const commandNames = new Set(['create', 'add-repo', 'remove-repo', 'add-module', 'remove-module', 'reset']);
8
+ const internalFlags = new Set(['--no-update-check']);
9
+ export function isUpdateCheckFlag(arg) {
10
+ return internalFlags.has(arg);
11
+ }
12
+ export function stripInternalFlags(argv) {
13
+ return argv.filter((arg) => !isUpdateCheckFlag(arg));
14
+ }
15
+ export function commandFromArgs(argv) {
16
+ if (argv.length === 0) {
17
+ return { command: 'menu', argv: [] };
18
+ }
19
+ const [first, ...rest] = argv;
20
+ if (commandNames.has(first)) {
21
+ return { command: first, argv: rest };
22
+ }
23
+ if (first.startsWith('--') || first === '-h' || first === '-v') {
24
+ return { command: 'create', argv };
25
+ }
26
+ throw new Error(`Unknown command: ${first}`);
27
+ }
28
+ export function parseArgs(argv) {
29
+ const values = {};
30
+ for (let index = 0; index < argv.length; index += 1) {
31
+ const arg = argv[index];
32
+ if (!arg.startsWith('--')) {
33
+ throw new Error(`Unexpected argument: ${arg}`);
34
+ }
35
+ const [rawKey, inlineValue] = arg.slice(2).split('=', 2);
36
+ const key = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
37
+ if (inlineValue !== undefined) {
38
+ values[key] = inlineValue;
39
+ continue;
40
+ }
41
+ const next = argv[index + 1];
42
+ if (!next || next.startsWith('--')) {
43
+ values[key] = true;
44
+ continue;
45
+ }
46
+ values[key] = next;
47
+ index += 1;
48
+ }
49
+ return { values };
50
+ }
51
+ function stringValue(values, key) {
52
+ const value = values[key];
53
+ return typeof value === 'string' ? value : undefined;
54
+ }
55
+ function listValue(value, fallback) {
56
+ if (!value)
57
+ return fallback;
58
+ return value
59
+ .split(',')
60
+ .map((item) => item.trim())
61
+ .filter(Boolean);
62
+ }
63
+ function validateAddons(addons) {
64
+ return addons.map(validateAddonName);
65
+ }
66
+ function valueAfter(argv, index, key) {
67
+ const arg = argv[index];
68
+ const inlineValue = arg.includes('=') ? arg.slice(arg.indexOf('=') + 1) : undefined;
69
+ if (inlineValue !== undefined) {
70
+ return { value: inlineValue, nextIndex: index };
71
+ }
72
+ const next = argv[index + 1];
73
+ if (!next || next.startsWith('--')) {
74
+ throw new Error(`Missing value for --${key}`);
75
+ }
76
+ return { value: next, nextIndex: index + 1 };
77
+ }
78
+ function parseSourceRepos(argv) {
79
+ const repos = [];
80
+ for (let index = 0; index < argv.length; index += 1) {
81
+ const arg = argv[index];
82
+ if (!arg.startsWith('--'))
83
+ continue;
84
+ const rawKey = arg.slice(2).split('=', 1)[0];
85
+ const key = rawKey.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
86
+ if (key === 'sourceRepoUrl') {
87
+ const parsed = valueAfter(argv, index, rawKey);
88
+ repos.push({ url: normalizeRepositoryUrl(parsed.value) });
89
+ index = parsed.nextIndex;
90
+ continue;
91
+ }
92
+ if (key === 'sourcePath') {
93
+ const current = repos.at(-1);
94
+ if (!current)
95
+ throw new Error('--source-path must follow --source-repo-url');
96
+ const parsed = valueAfter(argv, index, rawKey);
97
+ current.path = parsed.value;
98
+ index = parsed.nextIndex;
99
+ continue;
100
+ }
101
+ if (key === 'sourceAddons') {
102
+ const current = repos.at(-1);
103
+ if (!current)
104
+ throw new Error('--source-addons must follow --source-repo-url');
105
+ const parsed = valueAfter(argv, index, rawKey);
106
+ current.addons = listValue(parsed.value, []);
107
+ index = parsed.nextIndex;
108
+ }
109
+ }
110
+ return repos.map((repo) => {
111
+ const path = validateRepoPath(repo.path?.trim() || inferRepoPath(repo.url));
112
+ return {
113
+ url: repo.url,
114
+ path,
115
+ addons: validateAddons(repo.addons?.length ? repo.addons : [path]),
116
+ };
117
+ });
118
+ }
119
+ function booleanValue(values, key, fallback) {
120
+ const value = values[key];
121
+ if (value === undefined)
122
+ return fallback;
123
+ if (typeof value === 'boolean')
124
+ return value;
125
+ const normalized = value.toLowerCase().trim();
126
+ if (['true', '1', 'yes', 'y'].includes(normalized))
127
+ return true;
128
+ if (['false', '0', 'no', 'n'].includes(normalized))
129
+ return false;
130
+ throw new Error(`Invalid boolean value for --${key}: ${value}`);
131
+ }
132
+ function visibilityValue(values) {
133
+ const value = stringValue(values, 'repoVisibility') ?? 'private';
134
+ if (value === 'private' || value === 'public') {
135
+ return value;
136
+ }
137
+ throw new Error(`Invalid value for --repo-visibility: ${value}`);
138
+ }
139
+ function engineValue(values) {
140
+ const value = stringValue(values, 'engine') ?? 'compose';
141
+ if (value === 'compose') {
142
+ return value;
143
+ }
144
+ throw new Error(`Invalid value for --engine: ${value}`);
145
+ }
146
+ function assertNoRemovedDevelopmentPackFlags(argv) {
147
+ for (const arg of argv) {
148
+ const rawKey = arg.startsWith('--') ? arg.slice(2).split('=', 1)[0] : '';
149
+ if (rawKey === 'pack' || rawKey === 'no-packs') {
150
+ throw new Error('Optional development packs were removed. See the WPMoo Development Guidelines in README.md.');
151
+ }
152
+ }
153
+ }
154
+ export function defaultTargetForProduct(product, cwd = process.cwd()) {
155
+ const devRepo = `${product}_dev`;
156
+ return basename(cwd) === devRepo ? cwd : resolve(cwd, devRepo);
157
+ }
158
+ export function optionsFromArgs(argv) {
159
+ assertNoRemovedDevelopmentPackFlags(argv);
160
+ const { values } = parseArgs(argv);
161
+ const product = stringValue(values, 'product');
162
+ if (!product) {
163
+ return undefined;
164
+ }
165
+ const parsedSourceRepos = parseSourceRepos(argv);
166
+ const hasLegacySourceConfig = [
167
+ 'org',
168
+ 'communityRepo',
169
+ 'communityRepoUrl',
170
+ 'communityAddons',
171
+ 'proRepo',
172
+ 'proRepoUrl',
173
+ 'proAddons',
174
+ ].some((key) => values[key] !== undefined);
175
+ if (parsedSourceRepos.length === 0 && !hasLegacySourceConfig) {
176
+ throw new Error('Missing --source-repo-url. Provide at least one source repository URL.');
177
+ }
178
+ const org = stringValue(values, 'org') ?? inferGitHubOwner(parsedSourceRepos[0]?.url ?? '') ?? 'example-org';
179
+ const odooVersion = stringValue(values, 'odooVersion') ?? supportedOdooVersions[0];
180
+ const engine = engineValue(values);
181
+ const installAgentSkillsTemplate = booleanValue(values, 'agentSkillsTemplate', values.agentSkillsTemplateUrl !== undefined);
182
+ const devRepoUrl = normalizeRepositoryUrl(stringValue(values, 'devRepoUrl') ?? `https://github.com/${org}/${product}_dev.git`);
183
+ const devRepo = stringValue(values, 'devRepo') ?? inferRepoPath(devRepoUrl);
184
+ const communityRepo = validateRepoPath(stringValue(values, 'communityRepo') ?? product);
185
+ const proRepo = validateRepoPath(stringValue(values, 'proRepo') ?? `${product}_pro`);
186
+ const targetValue = stringValue(values, 'target');
187
+ const target = targetValue ? resolve(targetValue) : defaultTargetForProduct(product);
188
+ const communityRepoUrl = normalizeRepositoryUrl(stringValue(values, 'communityRepoUrl') ?? `https://github.com/${org}/${communityRepo}.git`);
189
+ const proRepoUrl = normalizeRepositoryUrl(stringValue(values, 'proRepoUrl') ?? `https://github.com/${org}/${proRepo}.git`);
190
+ const communityAddons = validateAddons(listValue(stringValue(values, 'communityAddons'), defaultCommunityAddons(product)));
191
+ const proAddons = validateAddons(listValue(stringValue(values, 'proAddons'), defaultProAddons(product)));
192
+ const hasExplicitProRepo = values.proRepo !== undefined || values.proRepoUrl !== undefined || values.proAddons !== undefined;
193
+ const sourceRepos = parsedSourceRepos.length > 0
194
+ ? parsedSourceRepos
195
+ : [
196
+ {
197
+ url: communityRepoUrl,
198
+ path: communityRepo,
199
+ addons: communityAddons,
200
+ },
201
+ ...(hasExplicitProRepo
202
+ ? [
203
+ {
204
+ url: proRepoUrl,
205
+ path: proRepo,
206
+ addons: proAddons,
207
+ },
208
+ ]
209
+ : []),
210
+ ].filter((repo) => repo.url && repo.path && repo.addons.length);
211
+ return {
212
+ product,
213
+ org,
214
+ odooVersion,
215
+ engine,
216
+ composeTemplateUrl: stringValue(values, 'composeTemplateUrl') ?? defaultComposeTemplateUrl,
217
+ composeTemplateRef: stringValue(values, 'composeTemplateRef'),
218
+ agentSkillsTemplateUrl: installAgentSkillsTemplate
219
+ ? stringValue(values, 'agentSkillsTemplateUrl') ?? defaultAgentSkillsTemplateUrl
220
+ : undefined,
221
+ agentSkillsTemplateRef: stringValue(values, 'agentSkillsTemplateRef'),
222
+ postgresVersion: stringValue(values, 'postgresVersion'),
223
+ httpPort: stringValue(values, 'httpPort'),
224
+ geventPort: stringValue(values, 'geventPort'),
225
+ devRepo,
226
+ devRepoUrl,
227
+ communityRepo,
228
+ proRepo,
229
+ communityRepoUrl,
230
+ proRepoUrl,
231
+ communityAddons,
232
+ proAddons,
233
+ sourceRepos,
234
+ target,
235
+ dryRun: booleanValue(values, 'dryRun', false),
236
+ initEmptyRepos: booleanValue(values, 'initEmptyRepos', false),
237
+ stage: booleanValue(values, 'stage', true),
238
+ createMissingRepos: booleanValue(values, 'createMissingRepos', false),
239
+ repoVisibility: visibilityValue(values),
240
+ };
241
+ }
242
+ export function isHelpRequested(argv) {
243
+ return argv.includes('--help') || argv.includes('-h');
244
+ }
245
+ export function isVersionRequested(argv) {
246
+ return argv.includes('--version') || argv.includes('-v');
247
+ }