@hexabot-ai/cli 3.2.2-alpha.11 → 3.2.2-alpha.13
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/AGENTS.md +2 -2
- package/README.md +2 -2
- package/dist/commands/__tests__/create.test.js +33 -1
- package/dist/commands/create.js +26 -14
- package/package.json +1 -1
- package/src/commands/__tests__/create.test.ts +54 -1
- package/src/commands/create.ts +48 -21
package/AGENTS.md
CHANGED
|
@@ -26,7 +26,7 @@ This file is the authoritative cheat-sheet for the Hexabot CLI. It summarizes th
|
|
|
26
26
|
| Command | Responsibilities | Options & IO | Implementation Notes |
|
|
27
27
|
| --- | --- | --- | --- |
|
|
28
28
|
| `check [--docker-only] [--no-docker]` | Run diagnostics for local Node version, Hexabot project detection, env files, and optionally Docker. | Flags narrow which checks run; outputs PASS/FAIL rows and sets exit code 1 if any check fails. | `src/commands/check.ts` calls `checkNodeVersion()`, `isHexabotProject()`, `loadProjectConfig()`, `listEnvStatus()`, and `checkDocker()` in sequence and prints results with chalk. |
|
|
29
|
-
| `create <projectName>` | Scaffold a project from a GitHub template, configure package manager, bootstrap env files, install deps, and optionally start dev mode. | `--template`, `--pm`, `--no-install`, `--dev`, `--docker`, `--force`. Writes `hexabot.config.json
|
|
29
|
+
| `create <projectName>` | Scaffold a project from a GitHub template, configure package manager, bootstrap env files, install deps, and optionally start dev mode. | `--template`, `--pm`, `--no-install`, `--dev`, `--docker`, `--force`. Writes `hexabot.config.json`, bootstraps local and Docker env files, persists initial admin seed credentials, installs deps (unless skipped), and can immediately run `hexabot dev`. | `src/commands/create.ts` validates the slug, downloads the latest release zip of `hexastack/hexabot-template-*` via `downloadAndExtractTemplate()`, ensures config/env files exist, installs dependencies via `installDependencies()`, and optionally calls `runDev()` for the new project. |
|
|
30
30
|
| `config show` | Print the effective `hexabot.config.json` after merging defaults. | No flags; emits pretty-printed JSON. | `src/commands/config.ts` resolves the project root, asserts the workspace, and calls `loadProjectConfig()`. |
|
|
31
31
|
| `config set <key> <value>` | Update nested config values via dot notation with type-aware parsing. | Supports booleans, numbers, JSON literals, comma lists (for `*Services` keys), and package-manager normalization. | Uses `parseValue()` + `buildOverride()` to construct overrides, writes via `updateProjectConfig()`, and echoes the new config. |
|
|
32
32
|
| `dev [--docker] [--services] [-d] [--env] [--no-env-bootstrap] [--pm]` | Run the project in development mode using either the package script or Docker compose stack. | When not using Docker it runs the configured dev script (`dev` default) after optional env bootstrapping. Docker mode bootstraps the docker env file, resolves compose overlays, and runs `docker compose ... up --build [-d]`. | `src/commands/dev.ts` auto-detects the package manager, persists it into the config, handles env bootstrapping (local or docker), then either calls `runPackageScript()` or `runDockerDev()` (which uses `generateComposeFiles()` with mode `dev`). |
|
|
@@ -46,7 +46,7 @@ This file is the authoritative cheat-sheet for the Hexabot CLI. It summarizes th
|
|
|
46
46
|
|
|
47
47
|
## Typical Workflow
|
|
48
48
|
|
|
49
|
-
1. `hexabot create my-bot
|
|
49
|
+
1. `hexabot create my-bot` — scaffold a workspace, persist the preferred package manager into `hexabot.config.json`, bootstrap both local and Docker env files, capture initial admin credentials, and install dependencies.
|
|
50
50
|
2. `cd my-bot`
|
|
51
51
|
3. `hexabot check` — confirm Node/Docker availability, project structure, and env files before running heavier commands.
|
|
52
52
|
4. `hexabot env init` — re-run if you need to refresh `.env` files (use `--docker` to target docker envs).
|
package/README.md
CHANGED
|
@@ -41,10 +41,10 @@ Common options:
|
|
|
41
41
|
- `--pm <npm|pnpm|yarn|bun>` – force a package manager (auto-detected otherwise).
|
|
42
42
|
- `--no-install` – skip running the package manager after scaffolding.
|
|
43
43
|
- `--dev` – immediately run `hexabot dev` once creation is complete.
|
|
44
|
-
- `--docker` –
|
|
44
|
+
- `--docker` – show Docker-first next steps and use Docker mode when combined with `--dev`.
|
|
45
45
|
- `--force` – allow scaffolding into a non-empty directory.
|
|
46
46
|
|
|
47
|
-
The command downloads the latest template release, installs dependencies (unless `--no-install`), and bootstraps `.env`
|
|
47
|
+
The command downloads the latest template release, installs dependencies (unless `--no-install`), and bootstraps `.env` plus `.env.docker` when their example files are present.
|
|
48
48
|
|
|
49
49
|
#### `dev`
|
|
50
50
|
|
|
@@ -86,6 +86,7 @@ beforeEach(() => {
|
|
|
86
86
|
setTTY(true);
|
|
87
87
|
validateProjectName.mockReturnValue(true);
|
|
88
88
|
detectPackageManager.mockReturnValue('pnpm');
|
|
89
|
+
bootstrapEnvFile.mockReturnValue(true);
|
|
89
90
|
normalizePackageManager.mockImplementation((value) => {
|
|
90
91
|
return typeof value === 'string' ? value.toLowerCase() : undefined;
|
|
91
92
|
});
|
|
@@ -113,7 +114,7 @@ afterEach(() => {
|
|
|
113
114
|
jest.restoreAllMocks();
|
|
114
115
|
});
|
|
115
116
|
describe('registerCreateCommand', () => {
|
|
116
|
-
it('prompts admin credentials and persists them to local env values', async () => {
|
|
117
|
+
it('prompts admin credentials and persists them to local and Docker env values', async () => {
|
|
117
118
|
input
|
|
118
119
|
.mockResolvedValueOnce('Anis')
|
|
119
120
|
.mockResolvedValueOnce('Bot')
|
|
@@ -136,15 +137,46 @@ describe('registerCreateCommand', () => {
|
|
|
136
137
|
expect(templateUrl).toBe('https://github.com/marrouchi/hexabot-v3-template/archive/refs/tags/v1.0.0.zip');
|
|
137
138
|
expect(projectPath.endsWith(`${path.sep}anisbot`)).toBe(true);
|
|
138
139
|
expect(bootstrapEnvFile).toHaveBeenCalledWith(projectPath, '.env.example', '.env', { quiet: true });
|
|
140
|
+
expect(bootstrapEnvFile).toHaveBeenCalledWith(projectPath, '.env.docker.example', '.env.docker', { quiet: true });
|
|
139
141
|
expect(upsertEnvVariables).toHaveBeenCalledWith(projectPath, '.env', {
|
|
140
142
|
SEED_ADMIN_FIRST_NAME: 'Anis',
|
|
141
143
|
SEED_ADMIN_LAST_NAME: 'Bot',
|
|
142
144
|
SEED_ADMIN_EMAIL: 'anis@example.com',
|
|
143
145
|
SEED_ADMIN_PASSWORD: 'Admin#123',
|
|
144
146
|
});
|
|
147
|
+
expect(upsertEnvVariables).toHaveBeenCalledWith(projectPath, '.env.docker', {
|
|
148
|
+
SEED_ADMIN_FIRST_NAME: 'Anis',
|
|
149
|
+
SEED_ADMIN_LAST_NAME: 'Bot',
|
|
150
|
+
SEED_ADMIN_EMAIL: 'anis@example.com',
|
|
151
|
+
SEED_ADMIN_PASSWORD: 'Admin#123',
|
|
152
|
+
});
|
|
145
153
|
expect(exitSpy).not.toHaveBeenCalled();
|
|
146
154
|
expect(input).toHaveBeenCalledTimes(3);
|
|
147
155
|
expect(password).toHaveBeenCalledTimes(2);
|
|
156
|
+
expect(bootstrapEnvFile).toHaveBeenCalledTimes(2);
|
|
157
|
+
expect(upsertEnvVariables).toHaveBeenCalledTimes(2);
|
|
158
|
+
});
|
|
159
|
+
it('skips Docker admin credentials when the Docker env file is unavailable', async () => {
|
|
160
|
+
bootstrapEnvFile.mockImplementation((_projectRoot, _exampleFile, targetFile) => targetFile === '.env');
|
|
161
|
+
input
|
|
162
|
+
.mockResolvedValueOnce('Anis')
|
|
163
|
+
.mockResolvedValueOnce('Bot')
|
|
164
|
+
.mockResolvedValueOnce('anis@example.com');
|
|
165
|
+
password
|
|
166
|
+
.mockResolvedValueOnce('Admin#123')
|
|
167
|
+
.mockResolvedValueOnce('Admin#123');
|
|
168
|
+
const program = new Command();
|
|
169
|
+
registerCreateCommand(program);
|
|
170
|
+
await program.parseAsync(['node', 'test', 'create', 'anisbot']);
|
|
171
|
+
const [, projectPath] = downloadAndExtractTemplate.mock.calls[0];
|
|
172
|
+
expect(bootstrapEnvFile).toHaveBeenCalledWith(projectPath, '.env.docker.example', '.env.docker', { quiet: true });
|
|
173
|
+
expect(upsertEnvVariables).toHaveBeenCalledTimes(1);
|
|
174
|
+
expect(upsertEnvVariables).toHaveBeenCalledWith(projectPath, '.env', {
|
|
175
|
+
SEED_ADMIN_FIRST_NAME: 'Anis',
|
|
176
|
+
SEED_ADMIN_LAST_NAME: 'Bot',
|
|
177
|
+
SEED_ADMIN_EMAIL: 'anis@example.com',
|
|
178
|
+
SEED_ADMIN_PASSWORD: 'Admin#123',
|
|
179
|
+
});
|
|
148
180
|
});
|
|
149
181
|
it('fails cleanly when create runs in a non-interactive terminal', async () => {
|
|
150
182
|
setTTY(false);
|
package/dist/commands/create.js
CHANGED
|
@@ -22,7 +22,7 @@ export const registerCreateCommand = (program) => {
|
|
|
22
22
|
.option('--pm <npm|pnpm|yarn|bun>', 'Preferred package manager')
|
|
23
23
|
.option('--no-install', 'Skip installing dependencies')
|
|
24
24
|
.option('--dev', 'Run hexabot dev after creation')
|
|
25
|
-
.option('--docker', '
|
|
25
|
+
.option('--docker', 'Use Docker-oriented next steps and --dev startup')
|
|
26
26
|
.option('--force', 'Allow scaffolding into a non-empty directory')
|
|
27
27
|
.action(async (projectName, options) => {
|
|
28
28
|
await createProject(projectName, options);
|
|
@@ -49,19 +49,9 @@ const createProject = async (projectName, options) => {
|
|
|
49
49
|
};
|
|
50
50
|
ensureProjectConfig(projectPath, configOverrides);
|
|
51
51
|
const config = loadProjectConfig(projectPath);
|
|
52
|
-
|
|
53
|
-
quiet: true,
|
|
54
|
-
});
|
|
55
|
-
if (options.docker) {
|
|
56
|
-
bootstrapEnvFile(projectPath, config.env.dockerExample, config.env.docker, { quiet: true });
|
|
57
|
-
}
|
|
52
|
+
const dockerEnvBootstrapped = bootstrapCreateEnvFiles(projectPath, config);
|
|
58
53
|
const adminCredentials = await promptSeedAdminCredentials();
|
|
59
|
-
|
|
60
|
-
SEED_ADMIN_FIRST_NAME: adminCredentials.firstName,
|
|
61
|
-
SEED_ADMIN_LAST_NAME: adminCredentials.lastName,
|
|
62
|
-
SEED_ADMIN_EMAIL: adminCredentials.email,
|
|
63
|
-
SEED_ADMIN_PASSWORD: adminCredentials.password,
|
|
64
|
-
});
|
|
54
|
+
persistAdminSeedCredentials(projectPath, config, adminCredentials, dockerEnvBootstrapped);
|
|
65
55
|
if (options.noInstall) {
|
|
66
56
|
console.log(chalk.yellow('Skipping dependency installation (--no-install).'));
|
|
67
57
|
}
|
|
@@ -117,6 +107,28 @@ const fetchLatestReleaseTag = async (templateRepo) => {
|
|
|
117
107
|
}
|
|
118
108
|
return data.tag_name;
|
|
119
109
|
};
|
|
110
|
+
const bootstrapCreateEnvFiles = (projectPath, config) => {
|
|
111
|
+
bootstrapEnvFile(projectPath, config.env.localExample, config.env.local, {
|
|
112
|
+
quiet: true,
|
|
113
|
+
});
|
|
114
|
+
return bootstrapEnvFile(projectPath, config.env.dockerExample, config.env.docker, { quiet: true });
|
|
115
|
+
};
|
|
116
|
+
const buildAdminSeedVariables = (credentials) => {
|
|
117
|
+
return {
|
|
118
|
+
SEED_ADMIN_FIRST_NAME: credentials.firstName,
|
|
119
|
+
SEED_ADMIN_LAST_NAME: credentials.lastName,
|
|
120
|
+
SEED_ADMIN_EMAIL: credentials.email,
|
|
121
|
+
SEED_ADMIN_PASSWORD: credentials.password,
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
const persistAdminSeedCredentials = (projectPath, config, credentials, dockerEnvBootstrapped) => {
|
|
125
|
+
const seedVariables = buildAdminSeedVariables(credentials);
|
|
126
|
+
upsertEnvVariables(projectPath, config.env.local, seedVariables);
|
|
127
|
+
if (dockerEnvBootstrapped ||
|
|
128
|
+
fs.existsSync(path.join(projectPath, config.env.docker))) {
|
|
129
|
+
upsertEnvVariables(projectPath, config.env.docker, seedVariables);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
120
132
|
const requireValue = (label) => {
|
|
121
133
|
return (value) => {
|
|
122
134
|
if (!value.trim()) {
|
|
@@ -209,7 +221,7 @@ const logSuccessMessage = (projectName, options) => {
|
|
|
209
221
|
}
|
|
210
222
|
console.log(chalk.gray(`3. Explore docker helpers if needed:`));
|
|
211
223
|
console.log(chalk.yellow(` hexabot docker up --services postgres`));
|
|
212
|
-
console.log(chalk.gray(`
|
|
224
|
+
console.log(chalk.gray(`Env bootstrap completed.`));
|
|
213
225
|
console.log('\n');
|
|
214
226
|
console.log(chalk.blue('Optional: Install Hexabot skills'));
|
|
215
227
|
console.log(chalk.gray('You can add official skills to accelerate your workflow:'));
|
package/package.json
CHANGED
|
@@ -104,6 +104,7 @@ beforeEach(() => {
|
|
|
104
104
|
|
|
105
105
|
validateProjectName.mockReturnValue(true);
|
|
106
106
|
detectPackageManager.mockReturnValue('pnpm');
|
|
107
|
+
bootstrapEnvFile.mockReturnValue(true);
|
|
107
108
|
(normalizePackageManager as any).mockImplementation((value: unknown) => {
|
|
108
109
|
return typeof value === 'string' ? value.toLowerCase() : undefined;
|
|
109
110
|
});
|
|
@@ -133,7 +134,7 @@ afterEach(() => {
|
|
|
133
134
|
});
|
|
134
135
|
|
|
135
136
|
describe('registerCreateCommand', () => {
|
|
136
|
-
it('prompts admin credentials and persists them to local env values', async () => {
|
|
137
|
+
it('prompts admin credentials and persists them to local and Docker env values', async () => {
|
|
137
138
|
(input as any)
|
|
138
139
|
.mockResolvedValueOnce('Anis')
|
|
139
140
|
.mockResolvedValueOnce('Bot')
|
|
@@ -166,15 +167,67 @@ describe('registerCreateCommand', () => {
|
|
|
166
167
|
'.env',
|
|
167
168
|
{ quiet: true },
|
|
168
169
|
);
|
|
170
|
+
expect(bootstrapEnvFile).toHaveBeenCalledWith(
|
|
171
|
+
projectPath,
|
|
172
|
+
'.env.docker.example',
|
|
173
|
+
'.env.docker',
|
|
174
|
+
{ quiet: true },
|
|
175
|
+
);
|
|
169
176
|
expect(upsertEnvVariables).toHaveBeenCalledWith(projectPath, '.env', {
|
|
170
177
|
SEED_ADMIN_FIRST_NAME: 'Anis',
|
|
171
178
|
SEED_ADMIN_LAST_NAME: 'Bot',
|
|
172
179
|
SEED_ADMIN_EMAIL: 'anis@example.com',
|
|
173
180
|
SEED_ADMIN_PASSWORD: 'Admin#123',
|
|
174
181
|
});
|
|
182
|
+
expect(upsertEnvVariables).toHaveBeenCalledWith(
|
|
183
|
+
projectPath,
|
|
184
|
+
'.env.docker',
|
|
185
|
+
{
|
|
186
|
+
SEED_ADMIN_FIRST_NAME: 'Anis',
|
|
187
|
+
SEED_ADMIN_LAST_NAME: 'Bot',
|
|
188
|
+
SEED_ADMIN_EMAIL: 'anis@example.com',
|
|
189
|
+
SEED_ADMIN_PASSWORD: 'Admin#123',
|
|
190
|
+
},
|
|
191
|
+
);
|
|
175
192
|
expect(exitSpy).not.toHaveBeenCalled();
|
|
176
193
|
expect(input).toHaveBeenCalledTimes(3);
|
|
177
194
|
expect(password).toHaveBeenCalledTimes(2);
|
|
195
|
+
expect(bootstrapEnvFile).toHaveBeenCalledTimes(2);
|
|
196
|
+
expect(upsertEnvVariables).toHaveBeenCalledTimes(2);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('skips Docker admin credentials when the Docker env file is unavailable', async () => {
|
|
200
|
+
(bootstrapEnvFile as any).mockImplementation(
|
|
201
|
+
(_projectRoot: string, _exampleFile: string, targetFile: string) =>
|
|
202
|
+
targetFile === '.env',
|
|
203
|
+
);
|
|
204
|
+
(input as any)
|
|
205
|
+
.mockResolvedValueOnce('Anis')
|
|
206
|
+
.mockResolvedValueOnce('Bot')
|
|
207
|
+
.mockResolvedValueOnce('anis@example.com');
|
|
208
|
+
(password as any)
|
|
209
|
+
.mockResolvedValueOnce('Admin#123')
|
|
210
|
+
.mockResolvedValueOnce('Admin#123');
|
|
211
|
+
|
|
212
|
+
const program = new Command();
|
|
213
|
+
registerCreateCommand(program);
|
|
214
|
+
|
|
215
|
+
await program.parseAsync(['node', 'test', 'create', 'anisbot']);
|
|
216
|
+
|
|
217
|
+
const [, projectPath] = (downloadAndExtractTemplate as any).mock.calls[0];
|
|
218
|
+
expect(bootstrapEnvFile).toHaveBeenCalledWith(
|
|
219
|
+
projectPath,
|
|
220
|
+
'.env.docker.example',
|
|
221
|
+
'.env.docker',
|
|
222
|
+
{ quiet: true },
|
|
223
|
+
);
|
|
224
|
+
expect(upsertEnvVariables).toHaveBeenCalledTimes(1);
|
|
225
|
+
expect(upsertEnvVariables).toHaveBeenCalledWith(projectPath, '.env', {
|
|
226
|
+
SEED_ADMIN_FIRST_NAME: 'Anis',
|
|
227
|
+
SEED_ADMIN_LAST_NAME: 'Bot',
|
|
228
|
+
SEED_ADMIN_EMAIL: 'anis@example.com',
|
|
229
|
+
SEED_ADMIN_PASSWORD: 'Admin#123',
|
|
230
|
+
});
|
|
178
231
|
});
|
|
179
232
|
|
|
180
233
|
it('fails cleanly when create runs in a non-interactive terminal', async () => {
|
package/src/commands/create.ts
CHANGED
|
@@ -52,7 +52,7 @@ export const registerCreateCommand = (program: Command) => {
|
|
|
52
52
|
.option('--pm <npm|pnpm|yarn|bun>', 'Preferred package manager')
|
|
53
53
|
.option('--no-install', 'Skip installing dependencies')
|
|
54
54
|
.option('--dev', 'Run hexabot dev after creation')
|
|
55
|
-
.option('--docker', '
|
|
55
|
+
.option('--docker', 'Use Docker-oriented next steps and --dev startup')
|
|
56
56
|
.option('--force', 'Allow scaffolding into a non-empty directory')
|
|
57
57
|
.action(async (projectName: string, options: CreateCommandOptions) => {
|
|
58
58
|
await createProject(projectName, options);
|
|
@@ -92,26 +92,14 @@ const createProject = async (
|
|
|
92
92
|
|
|
93
93
|
ensureProjectConfig(projectPath, configOverrides);
|
|
94
94
|
const config = loadProjectConfig(projectPath);
|
|
95
|
-
|
|
96
|
-
bootstrapEnvFile(projectPath, config.env.localExample, config.env.local, {
|
|
97
|
-
quiet: true,
|
|
98
|
-
});
|
|
99
|
-
if (options.docker) {
|
|
100
|
-
bootstrapEnvFile(
|
|
101
|
-
projectPath,
|
|
102
|
-
config.env.dockerExample,
|
|
103
|
-
config.env.docker,
|
|
104
|
-
{ quiet: true },
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
95
|
+
const dockerEnvBootstrapped = bootstrapCreateEnvFiles(projectPath, config);
|
|
108
96
|
const adminCredentials = await promptSeedAdminCredentials();
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
97
|
+
persistAdminSeedCredentials(
|
|
98
|
+
projectPath,
|
|
99
|
+
config,
|
|
100
|
+
adminCredentials,
|
|
101
|
+
dockerEnvBootstrapped,
|
|
102
|
+
);
|
|
115
103
|
|
|
116
104
|
if (options.noInstall) {
|
|
117
105
|
console.log(
|
|
@@ -185,6 +173,45 @@ const fetchLatestReleaseTag = async (templateRepo: string) => {
|
|
|
185
173
|
|
|
186
174
|
return data.tag_name;
|
|
187
175
|
};
|
|
176
|
+
const bootstrapCreateEnvFiles = (
|
|
177
|
+
projectPath: string,
|
|
178
|
+
config: ReturnType<typeof loadProjectConfig>,
|
|
179
|
+
) => {
|
|
180
|
+
bootstrapEnvFile(projectPath, config.env.localExample, config.env.local, {
|
|
181
|
+
quiet: true,
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
return bootstrapEnvFile(
|
|
185
|
+
projectPath,
|
|
186
|
+
config.env.dockerExample,
|
|
187
|
+
config.env.docker,
|
|
188
|
+
{ quiet: true },
|
|
189
|
+
);
|
|
190
|
+
};
|
|
191
|
+
const buildAdminSeedVariables = (credentials: AdminSeedCredentials) => {
|
|
192
|
+
return {
|
|
193
|
+
SEED_ADMIN_FIRST_NAME: credentials.firstName,
|
|
194
|
+
SEED_ADMIN_LAST_NAME: credentials.lastName,
|
|
195
|
+
SEED_ADMIN_EMAIL: credentials.email,
|
|
196
|
+
SEED_ADMIN_PASSWORD: credentials.password,
|
|
197
|
+
};
|
|
198
|
+
};
|
|
199
|
+
const persistAdminSeedCredentials = (
|
|
200
|
+
projectPath: string,
|
|
201
|
+
config: ReturnType<typeof loadProjectConfig>,
|
|
202
|
+
credentials: AdminSeedCredentials,
|
|
203
|
+
dockerEnvBootstrapped: boolean,
|
|
204
|
+
) => {
|
|
205
|
+
const seedVariables = buildAdminSeedVariables(credentials);
|
|
206
|
+
upsertEnvVariables(projectPath, config.env.local, seedVariables);
|
|
207
|
+
|
|
208
|
+
if (
|
|
209
|
+
dockerEnvBootstrapped ||
|
|
210
|
+
fs.existsSync(path.join(projectPath, config.env.docker))
|
|
211
|
+
) {
|
|
212
|
+
upsertEnvVariables(projectPath, config.env.docker, seedVariables);
|
|
213
|
+
}
|
|
214
|
+
};
|
|
188
215
|
const requireValue = (label: string) => {
|
|
189
216
|
return (value: string) => {
|
|
190
217
|
if (!value.trim()) {
|
|
@@ -304,7 +331,7 @@ const logSuccessMessage = (
|
|
|
304
331
|
}
|
|
305
332
|
console.log(chalk.gray(`3. Explore docker helpers if needed:`));
|
|
306
333
|
console.log(chalk.yellow(` hexabot docker up --services postgres`));
|
|
307
|
-
console.log(chalk.gray(`
|
|
334
|
+
console.log(chalk.gray(`Env bootstrap completed.`));
|
|
308
335
|
console.log('\n');
|
|
309
336
|
console.log(chalk.blue('Optional: Install Hexabot skills'));
|
|
310
337
|
console.log(
|