dhti-cli 0.8.0 → 1.1.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/README.md +83 -111
- package/dist/commands/compose.d.ts +4 -0
- package/dist/commands/compose.js +119 -0
- package/dist/commands/conch.d.ts +2 -6
- package/dist/commands/conch.js +167 -215
- package/dist/commands/elixir.d.ts +2 -0
- package/dist/commands/elixir.js +346 -45
- package/dist/resources/docker-compose-master.yml +4 -2
- package/dist/resources/spa/README.md +3 -0
- package/dist/resources/spa/config-schema.ts +53 -0
- package/dist/resources/spa/glycemic.component.tsx +86 -0
- package/dist/resources/spa/glycemic.scss +44 -0
- package/dist/resources/spa/hooks/useDhti.ts +69 -0
- package/dist/resources/spa/hooks/usePatient.ts +61 -0
- package/dist/resources/spa/index.ts +17 -0
- package/dist/resources/spa/models/card.ts +80 -0
- package/dist/resources/spa/models/request.ts +42 -0
- package/dist/resources/spa/routes.json +17 -0
- package/oclif.manifest.json +66 -53
- package/package.json +3 -1
- package/dist/resources/spa/Dockerfile +0 -16
- package/dist/resources/spa/def/importmap.json +0 -39
- package/dist/resources/spa/def/routes.registry.json +0 -1599
- package/dist/resources/spa/def/spa-assemble-config.json +0 -40
package/dist/commands/conch.js
CHANGED
|
@@ -1,268 +1,220 @@
|
|
|
1
1
|
import { Args, Command, Flags } from '@oclif/core';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import { exec } from 'node:child_process';
|
|
3
|
+
import { exec, spawn } from 'node:child_process';
|
|
4
4
|
import fs from 'node:fs';
|
|
5
5
|
import os from 'node:os';
|
|
6
6
|
import path from 'node:path';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
function escapeShellArg(arg) {
|
|
10
|
-
return `'${arg.replaceAll("'", "'\\''")}'`;
|
|
11
|
-
}
|
|
7
|
+
import { promisify } from 'node:util';
|
|
8
|
+
const execAsync = promisify(exec);
|
|
12
9
|
export default class Conch extends Command {
|
|
13
10
|
static args = {
|
|
14
|
-
op: Args.string({ description: 'Operation to perform (install,
|
|
11
|
+
op: Args.string({ description: 'Operation to perform (init, install, or start)' }),
|
|
15
12
|
};
|
|
16
|
-
static description = '
|
|
17
|
-
static examples = [
|
|
13
|
+
static description = 'Initialize, install, or start OpenMRS frontend development';
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> <%= command.id %> install -n my-app -w ~/projects',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> init -n my-app -w ~/projects',
|
|
17
|
+
'<%= config.bin %> <%= command.id %> start -n my-app -w ~/projects',
|
|
18
|
+
'<%= config.bin %> <%= command.id %> start -n my-app -w ~/projects -s packages/chatbot -s packages/utils',
|
|
19
|
+
];
|
|
18
20
|
static flags = {
|
|
19
|
-
branch: Flags.string({
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
description: 'Name of the container to copy the conch to while in dev mode',
|
|
21
|
+
branch: Flags.string({
|
|
22
|
+
char: 'b',
|
|
23
|
+
default: 'develop',
|
|
24
|
+
description: 'Branch to install from (for install operation)',
|
|
24
25
|
}),
|
|
25
|
-
dev: Flags.string({ char: 'd', default: 'none', description: 'Dev folder to install' }),
|
|
26
26
|
'dry-run': Flags.boolean({
|
|
27
27
|
default: false,
|
|
28
28
|
description: 'Show what changes would be made without actually making them',
|
|
29
29
|
}),
|
|
30
|
-
git: Flags.string({
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
git: Flags.string({
|
|
31
|
+
char: 'g',
|
|
32
|
+
default: 'dermatologist/openmrs-esm-dhti-template',
|
|
33
|
+
description: 'GitHub repository to install (for install operation)',
|
|
34
|
+
}),
|
|
35
|
+
local: Flags.string({
|
|
36
|
+
char: 'l',
|
|
37
|
+
description: 'Local path to use instead of calculated workdir/name path (for start operation)',
|
|
35
38
|
}),
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
repoVersion: Flags.string({ char: 'v', default: '1.0.0', description: 'Version of the conch' }),
|
|
39
|
-
subdirectory: Flags.string({
|
|
39
|
+
name: Flags.string({ char: 'n', description: 'Name of the conch' }),
|
|
40
|
+
sources: Flags.string({
|
|
40
41
|
char: 's',
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
description: 'Additional sources to include when starting (e.g., packages/esm-chatbot-agent, packages/esm-another-app)',
|
|
43
|
+
multiple: true,
|
|
43
44
|
}),
|
|
44
45
|
workdir: Flags.string({
|
|
45
46
|
char: 'w',
|
|
46
47
|
default: `${os.homedir()}/dhti`,
|
|
47
|
-
description: 'Working directory
|
|
48
|
+
description: 'Working directory for the conch',
|
|
48
49
|
}),
|
|
49
50
|
};
|
|
50
51
|
async run() {
|
|
51
52
|
const { args, flags } = await this.parse(Conch);
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if (args.op === 'dev') {
|
|
64
|
-
const buildCommand = `cd ${flags.dev} && yarn build && docker cp dist/. ${flags.container}:/usr/share/nginx/html/${flags.name}-${flags.repoVersion}`;
|
|
65
|
-
const restartCommand = `docker restart ${flags.container}`;
|
|
53
|
+
if (args.op === 'init') {
|
|
54
|
+
// Validate required flags
|
|
55
|
+
if (!flags.workdir) {
|
|
56
|
+
console.error(chalk.red('Error: workdir flag is required for init operation'));
|
|
57
|
+
this.exit(1);
|
|
58
|
+
}
|
|
59
|
+
if (!flags.name) {
|
|
60
|
+
console.error(chalk.red('Error: name flag is required for init operation'));
|
|
61
|
+
this.exit(1);
|
|
62
|
+
}
|
|
63
|
+
const targetDir = path.join(flags.workdir, 'openmrs-esm-dhti');
|
|
66
64
|
if (flags['dry-run']) {
|
|
67
|
-
console.log(chalk.yellow('[DRY RUN] Would execute
|
|
68
|
-
console.log(chalk.cyan(` ${
|
|
69
|
-
console.log(chalk.cyan(` ${
|
|
65
|
+
console.log(chalk.yellow('[DRY RUN] Would execute init operation:'));
|
|
66
|
+
console.log(chalk.cyan(` npx degit dermatologist/openmrs-esm-dhti ${targetDir}`));
|
|
67
|
+
console.log(chalk.cyan(` Copy ${targetDir}/packages/esm-starter-app to ${targetDir}/packages/${flags.name}`));
|
|
70
68
|
return;
|
|
71
69
|
}
|
|
72
|
-
console.log(buildCommand);
|
|
73
70
|
try {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
console.
|
|
89
|
-
}
|
|
71
|
+
// Run npx degit to clone the dhti template
|
|
72
|
+
console.log(chalk.blue(`Initializing DHTI template in ${targetDir}...`));
|
|
73
|
+
const degitCommand = `npx degit dermatologist/openmrs-esm-dhti ${targetDir}`;
|
|
74
|
+
await execAsync(degitCommand);
|
|
75
|
+
console.log(chalk.green('✓ DHTI template cloned successfully'));
|
|
76
|
+
// Copy packages/esm-starter-app subdirectory to packages/<name>
|
|
77
|
+
const starterAppSource = path.join(targetDir, 'packages', 'esm-starter-app');
|
|
78
|
+
const targetPackageDir = path.join(targetDir, 'packages', flags.name);
|
|
79
|
+
if (fs.existsSync(starterAppSource)) {
|
|
80
|
+
console.log(chalk.blue(`Copying esm-starter-app to packages/${flags.name}...`));
|
|
81
|
+
fs.cpSync(starterAppSource, targetPackageDir, { recursive: true });
|
|
82
|
+
console.log(chalk.green(`✓ esm-starter-app copied to packages/${flags.name}`));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.log(chalk.yellow(`Warning: esm-starter-app not found at ${starterAppSource}`));
|
|
86
|
+
}
|
|
87
|
+
console.log(chalk.green(`\n✓ Initialization complete! Your workspace is ready at ${targetDir}`));
|
|
88
|
+
console.log(chalk.blue(`\nTo start development, run:`));
|
|
89
|
+
const startCmd = `dhti-cli conch start -w ${flags.workdir} -n ${flags.name}`;
|
|
90
|
+
console.log(chalk.cyan(` ${startCmd}`));
|
|
90
91
|
}
|
|
91
92
|
catch (error) {
|
|
92
|
-
console.
|
|
93
|
+
console.error(chalk.red('Error during initialization:'), error);
|
|
94
|
+
this.exit(1);
|
|
93
95
|
}
|
|
94
96
|
return;
|
|
95
97
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (flags
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
if (flags['dry-run']) {
|
|
106
|
-
console.log(chalk.yellow(`[DRY RUN] Would copy resources from ${RESOURCES_DIR}/spa to ${flags.workdir}/conch`));
|
|
107
|
-
}
|
|
108
|
-
else {
|
|
109
|
-
fs.cpSync(path.join(RESOURCES_DIR, 'spa'), `${flags.workdir}/conch`, { recursive: true });
|
|
110
|
-
}
|
|
111
|
-
// Rewrite files
|
|
112
|
-
const rewrite = () => {
|
|
113
|
-
flags.name = flags.name ?? 'openmrs-esm-genai';
|
|
114
|
-
if (flags['dry-run']) {
|
|
115
|
-
console.log(chalk.yellow('[DRY RUN] Would update configuration files:'));
|
|
116
|
-
console.log(chalk.cyan(` - ${flags.workdir}/conch/def/importmap.json`));
|
|
117
|
-
if (args.op === 'install') {
|
|
118
|
-
console.log(chalk.green(` Add import: ${flags.name.replace('openmrs-', '@openmrs/')} -> ./${flags.name}-${flags.repoVersion}/${flags.name}.js`));
|
|
119
|
-
}
|
|
120
|
-
if (args.op === 'uninstall') {
|
|
121
|
-
console.log(chalk.green(` Remove import: ${flags.name.replace('openmrs-', '@openmrs/')}`));
|
|
122
|
-
}
|
|
123
|
-
console.log(chalk.cyan(` - ${flags.workdir}/conch/def/spa-assemble-config.json`));
|
|
124
|
-
if (args.op === 'install') {
|
|
125
|
-
console.log(chalk.green(` Add module: ${flags.name.replace('openmrs-', '@openmrs/')} = ${flags.repoVersion}`));
|
|
126
|
-
}
|
|
127
|
-
if (args.op === 'uninstall') {
|
|
128
|
-
console.log(chalk.green(` Remove module: ${flags.name.replace('openmrs-', '@openmrs/')}`));
|
|
129
|
-
}
|
|
130
|
-
console.log(chalk.cyan(` - ${flags.workdir}/conch/Dockerfile`));
|
|
131
|
-
console.log(chalk.green(` Update with conch=${flags.name}, version=${flags.repoVersion}, image=${flags.image}`));
|
|
132
|
-
console.log(chalk.cyan(` - ${flags.workdir}/conch/def/routes.registry.json`));
|
|
133
|
-
if (args.op === 'install') {
|
|
134
|
-
console.log(chalk.green(` Add routes for ${flags.name.replace('openmrs-', '@openmrs/')}`));
|
|
98
|
+
if (args.op === 'start') {
|
|
99
|
+
// Validate required flags
|
|
100
|
+
if (!flags.local) {
|
|
101
|
+
// If --local is not provided, require workdir and name
|
|
102
|
+
if (!flags.workdir) {
|
|
103
|
+
console.error(chalk.red('Error: workdir flag is required for start operation (unless --local is provided)'));
|
|
104
|
+
this.exit(1);
|
|
135
105
|
}
|
|
136
|
-
if (
|
|
137
|
-
console.
|
|
106
|
+
if (!flags.name) {
|
|
107
|
+
console.error(chalk.red('Error: name flag is required for start operation (unless --local is provided)'));
|
|
108
|
+
this.exit(1);
|
|
138
109
|
}
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
// Read and process importmap.json
|
|
142
|
-
const importmap = JSON.parse(fs.readFileSync(`${flags.workdir}/conch/def/importmap.json`, 'utf8'));
|
|
143
|
-
if (args.op === 'install')
|
|
144
|
-
importmap.imports[flags.name.replace('openmrs-', '@openmrs/')] = `./${flags.name}-${flags.repoVersion}/${flags.name}.js`;
|
|
145
|
-
if (args.op === 'uninstall')
|
|
146
|
-
delete importmap.imports[flags.name.replace('openmrs-', '@openmrs/')];
|
|
147
|
-
fs.writeFileSync(`${flags.workdir}/conch/def/importmap.json`, JSON.stringify(importmap, null, 2));
|
|
148
|
-
// Read and process spa-assemble-config.json
|
|
149
|
-
const spaAssembleConfig = JSON.parse(fs.readFileSync(`${flags.workdir}/conch/def/spa-assemble-config.json`, 'utf8'));
|
|
150
|
-
if (args.op === 'install')
|
|
151
|
-
spaAssembleConfig.frontendModules[flags.name.replace('openmrs-', '@openmrs/')] = `${flags.repoVersion}`;
|
|
152
|
-
if (args.op === 'uninstall')
|
|
153
|
-
delete spaAssembleConfig.frontendModules[flags.name.replace('openmrs-', '@openmrs/')];
|
|
154
|
-
fs.writeFileSync(`${flags.workdir}/conch/def/spa-assemble-config.json`, JSON.stringify(spaAssembleConfig, null, 2));
|
|
155
|
-
// Read and process Dockerfile
|
|
156
|
-
let dockerfile = fs.readFileSync(`${flags.workdir}/conch/Dockerfile`, 'utf8');
|
|
157
|
-
dockerfile = dockerfile
|
|
158
|
-
.replaceAll('conch', flags.name)
|
|
159
|
-
.replaceAll('version', flags.repoVersion)
|
|
160
|
-
.replaceAll('server-image', flags.image);
|
|
161
|
-
fs.writeFileSync(`${flags.workdir}/conch/Dockerfile`, dockerfile);
|
|
162
|
-
// Read routes.json
|
|
163
|
-
const routes = JSON.parse(fs.readFileSync(`${flags.workdir}/conch/${flags.name}/src/routes.json`, 'utf8'));
|
|
164
|
-
// Add to routes.registry.json
|
|
165
|
-
const registry = JSON.parse(fs.readFileSync(`${flags.workdir}/conch/def/routes.registry.json`, 'utf8'));
|
|
166
|
-
if (args.op === 'install')
|
|
167
|
-
registry[flags.name.replace('openmrs-', '@openmrs/')] = routes;
|
|
168
|
-
if (args.op === 'uninstall')
|
|
169
|
-
delete registry[flags.name.replace('openmrs-', '@openmrs/')];
|
|
170
|
-
fs.writeFileSync(`${flags.workdir}/conch/def/routes.registry.json`, JSON.stringify(registry, null, 2));
|
|
171
|
-
};
|
|
172
|
-
if (flags.git !== 'none') {
|
|
173
|
-
let cloneCommand;
|
|
174
|
-
let checkoutCommand;
|
|
175
|
-
if (flags.subdirectory === 'none') {
|
|
176
|
-
cloneCommand = `git clone ${escapeShellArg(flags.git)} ${escapeShellArg(`${flags.workdir}/conch/${flags.name}`)}`;
|
|
177
|
-
checkoutCommand = `cd ${escapeShellArg(`${flags.workdir}/conch/${flags.name}`)} && git checkout ${escapeShellArg(flags.branch)}`;
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
// Use sparse checkout for subdirectory - broken into steps for readability and security
|
|
181
|
-
const targetDir = `${flags.workdir}/conch/${flags.name}`;
|
|
182
|
-
const escapedDir = escapeShellArg(targetDir);
|
|
183
|
-
const escapedGit = escapeShellArg(flags.git);
|
|
184
|
-
const escapedBranch = escapeShellArg(flags.branch);
|
|
185
|
-
const escapedSubdir = escapeShellArg(flags.subdirectory);
|
|
186
|
-
// Build sparse checkout command with proper escaping
|
|
187
|
-
const initCommand = `mkdir -p ${escapedDir} && cd ${escapedDir} && git init`;
|
|
188
|
-
const remoteCommand = `git remote add origin ${escapedGit}`;
|
|
189
|
-
const sparseCommand = `git config core.sparseCheckout true`;
|
|
190
|
-
// Don't escape the glob pattern itself, only the subdirectory name
|
|
191
|
-
const patternCommand = `echo ${escapedSubdir}/'*' >> .git/info/sparse-checkout`;
|
|
192
|
-
const fetchCommand = `git fetch --depth=1 origin ${escapedBranch}`;
|
|
193
|
-
const checkoutCmd = `git checkout ${escapedBranch}`;
|
|
194
|
-
// Use bash's dotglob to include hidden files, and handle the case when no files exist
|
|
195
|
-
const moveCommand = `bash -c "shopt -s dotglob; if [ -d ${escapedSubdir} ]; then mv ${escapedSubdir}/* . 2>/dev/null || true; fi"`;
|
|
196
|
-
const cleanupCommand = `rm -rf ${escapedSubdir}`;
|
|
197
|
-
cloneCommand = `${initCommand} && ${remoteCommand} && ${sparseCommand} && ${patternCommand} && ${fetchCommand} && ${checkoutCmd} && ${moveCommand} && ${cleanupCommand}`;
|
|
198
|
-
checkoutCommand = `cd ${escapedDir} && echo "Sparse checkout complete"`;
|
|
199
110
|
}
|
|
111
|
+
const targetDir = flags.local || path.join(flags.workdir, flags.name);
|
|
200
112
|
if (flags['dry-run']) {
|
|
201
|
-
console.log(chalk.yellow('[DRY RUN] Would execute
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
113
|
+
console.log(chalk.yellow('[DRY RUN] Would execute start operation:'));
|
|
114
|
+
console.log(chalk.cyan(` cd ${targetDir}`));
|
|
115
|
+
let dryRunCommand = 'corepack enable && yarn install && yarn start';
|
|
116
|
+
if (flags.sources && flags.sources.length > 0) {
|
|
117
|
+
for (const source of flags.sources) {
|
|
118
|
+
dryRunCommand += ` --sources '${source}'`;
|
|
119
|
+
}
|
|
208
120
|
}
|
|
209
|
-
|
|
121
|
+
console.log(chalk.cyan(` ${dryRunCommand}`));
|
|
210
122
|
return;
|
|
211
123
|
}
|
|
212
|
-
//
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
124
|
+
// Check if directory exists (not in dry-run mode)
|
|
125
|
+
if (!fs.existsSync(targetDir)) {
|
|
126
|
+
console.error(chalk.red(`Error: Directory does not exist: ${targetDir}`));
|
|
127
|
+
if (!flags.local) {
|
|
128
|
+
console.log(chalk.yellow(`Run 'dhti-cli conch init -n ${flags.name} -w ${flags.workdir}' first`));
|
|
217
129
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
130
|
+
this.exit(1);
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
console.log(chalk.blue(`Starting OpenMRS development server in ${targetDir}...`));
|
|
134
|
+
console.log(chalk.yellow('Press Ctrl-C to stop\n'));
|
|
135
|
+
// Build the start command with sources flag if provided
|
|
136
|
+
let startCommand = 'corepack enable && yarn install && yarn start';
|
|
137
|
+
if (flags.sources && flags.sources.length > 0) {
|
|
138
|
+
for (const source of flags.sources) {
|
|
139
|
+
startCommand += ` --sources '${source}'`;
|
|
223
140
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
141
|
+
}
|
|
142
|
+
// Spawn corepack enable && yarn install && yarn start with stdio inheritance to show output and allow Ctrl-C
|
|
143
|
+
const child = spawn(startCommand, {
|
|
144
|
+
cwd: targetDir,
|
|
145
|
+
shell: true,
|
|
146
|
+
stdio: 'inherit',
|
|
147
|
+
});
|
|
148
|
+
// Handle process exit
|
|
149
|
+
child.on('exit', (code) => {
|
|
150
|
+
if (code === 0) {
|
|
151
|
+
console.log(chalk.green('\n✓ Development server stopped'));
|
|
152
|
+
}
|
|
153
|
+
else if (code !== null) {
|
|
154
|
+
console.log(chalk.yellow(`\nDevelopment server exited with code ${code}`));
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
// Handle errors
|
|
158
|
+
child.on('error', (error) => {
|
|
159
|
+
console.error(chalk.red('Error starting development server:'), error);
|
|
160
|
+
this.exit(1);
|
|
161
|
+
});
|
|
162
|
+
// Wait for the child process to complete
|
|
163
|
+
await new Promise((resolve) => {
|
|
164
|
+
child.on('close', () => resolve());
|
|
227
165
|
});
|
|
228
|
-
console.log(`stdout: ${stdout}`);
|
|
229
|
-
console.error(`stderr: ${stderr}`);
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
// If flags.dev is not none, copy the dev folder to the conch directory
|
|
233
|
-
if (flags.dev !== 'none' && args.op !== 'dev') {
|
|
234
|
-
if (flags['dry-run']) {
|
|
235
|
-
console.log(chalk.yellow(`[DRY RUN] Would copy ${flags.dev} to ${flags.workdir}/conch/${flags.name}`));
|
|
236
|
-
rewrite();
|
|
237
166
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
167
|
+
catch (error) {
|
|
168
|
+
console.error(chalk.red('Error during start:'), error);
|
|
169
|
+
this.exit(1);
|
|
241
170
|
}
|
|
171
|
+
return;
|
|
242
172
|
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
173
|
+
if (args.op === 'install') {
|
|
174
|
+
// Validate required flags
|
|
175
|
+
if (!flags.workdir) {
|
|
176
|
+
console.error(chalk.red('Error: workdir flag is required for install operation'));
|
|
177
|
+
this.exit(1);
|
|
178
|
+
}
|
|
179
|
+
if (!flags.name) {
|
|
180
|
+
console.error(chalk.red('Error: name flag is required for install operation'));
|
|
181
|
+
this.exit(1);
|
|
182
|
+
}
|
|
183
|
+
// Warn if sources flag is used with install (not applicable)
|
|
184
|
+
if (flags.sources && flags.sources.length > 0) {
|
|
185
|
+
console.warn(chalk.yellow('Warning: --sources flag is not applicable for install operation. It will be ignored.'));
|
|
186
|
+
console.warn(chalk.yellow('Use --sources with the start operation instead.'));
|
|
257
187
|
}
|
|
188
|
+
const targetDir = path.join(flags.workdir, flags.name);
|
|
189
|
+
const degitSource = `${flags.git}#${flags.branch}`;
|
|
258
190
|
if (flags['dry-run']) {
|
|
259
|
-
console.log(chalk.yellow(
|
|
260
|
-
|
|
191
|
+
console.log(chalk.yellow('[DRY RUN] Would execute install operation:'));
|
|
192
|
+
console.log(chalk.cyan(` npx degit ${degitSource} ${targetDir}`));
|
|
193
|
+
return;
|
|
261
194
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
195
|
+
try {
|
|
196
|
+
console.log(chalk.blue(`Installing from ${degitSource} to ${targetDir}...`));
|
|
197
|
+
const degitCommand = `npx degit ${degitSource} ${targetDir}`;
|
|
198
|
+
await execAsync(degitCommand);
|
|
199
|
+
console.log(chalk.green('✓ Repository cloned successfully'));
|
|
200
|
+
console.log(chalk.green(`\n✓ Installation complete! Your app is ready at ${targetDir}`));
|
|
201
|
+
console.log(chalk.blue(`\nTo start development, run:`));
|
|
202
|
+
let startCmd = `dhti-cli conch start -n ${flags.name} -w ${flags.workdir}`;
|
|
203
|
+
if (flags.sources && flags.sources.length > 0) {
|
|
204
|
+
for (const source of flags.sources) {
|
|
205
|
+
startCmd += ` -s '${source}'`;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
console.log(chalk.cyan(` ${startCmd}`));
|
|
265
209
|
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
console.error(chalk.red('Error during installation:'), error);
|
|
212
|
+
this.exit(1);
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
266
215
|
}
|
|
216
|
+
// If no valid operation is provided
|
|
217
|
+
console.error(chalk.red('Error: Invalid operation. Use "install", "init", or "start"'));
|
|
218
|
+
this.exit(1);
|
|
267
219
|
}
|
|
268
220
|
}
|
|
@@ -10,6 +10,8 @@ export default class Elixir extends Command {
|
|
|
10
10
|
container: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
11
|
dev: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
12
|
'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
elixir: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
fhir: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
15
|
git: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
16
|
local: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
17
|
name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|