docugate 0.2.2 → 0.2.3
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/dist/cli.js +45 -22
- package/dist/init.js +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
3
4
|
import { check } from './check.js';
|
|
4
5
|
import { loadConfig } from './config.js';
|
|
5
|
-
import { initFlow } from './init.js';
|
|
6
|
+
import { choose, initFlow, makeDefaultIO } from './init.js';
|
|
6
7
|
import { buildOpenApi, isCurrent, writeOpenApi } from './openapi.js';
|
|
7
8
|
import { BobKeyMissingError, BobMissingError, tourInit } from './tour-init.js';
|
|
8
9
|
import { tourInstall, hasPillSnippet, pillSnippetLine, DEFAULT_PORT } from './tour-install.js';
|
|
@@ -197,13 +198,27 @@ async function main() {
|
|
|
197
198
|
if (roleFlag && !['frontend', 'backend', 'both'].includes(roleFlag)) {
|
|
198
199
|
fail(`--role must be frontend, backend, or both.`);
|
|
199
200
|
}
|
|
200
|
-
|
|
201
|
+
const port = one('port') !== undefined ? parseInt(one('port'), 10) : DEFAULT_PORT;
|
|
202
|
+
const result = await initFlow(root, {
|
|
201
203
|
dir: one('dir'),
|
|
202
204
|
title: one('title'),
|
|
203
205
|
role: roleFlag,
|
|
204
206
|
yes: args.bools.has('yes'),
|
|
205
|
-
port
|
|
207
|
+
port,
|
|
206
208
|
});
|
|
209
|
+
// The pill only shows while the tour server runs, so setup ends by
|
|
210
|
+
// offering to start it rather than leaving one more command to remember.
|
|
211
|
+
const where = result.alreadySetUp ?? root;
|
|
212
|
+
const hasTour = result.role === 'frontend' || result.role === 'both';
|
|
213
|
+
if (hasTour && process.stdin.isTTY && !args.bools.has('yes')) {
|
|
214
|
+
const io = makeDefaultIO();
|
|
215
|
+
const pick = await choose(io, 'Start the tour server now, so the pill shows in your app?', [
|
|
216
|
+
'Yes, start it (leave this terminal open, then run your app as usual)',
|
|
217
|
+
'Later: docugate tour serve',
|
|
218
|
+
]);
|
|
219
|
+
if (pick === 1)
|
|
220
|
+
await serveTour(where, port);
|
|
221
|
+
}
|
|
207
222
|
return;
|
|
208
223
|
}
|
|
209
224
|
case 'check': {
|
|
@@ -329,24 +344,7 @@ ${dim(`Bob: ${parts.join(', ')}`)}`);
|
|
|
329
344
|
return;
|
|
330
345
|
}
|
|
331
346
|
case 'serve': {
|
|
332
|
-
|
|
333
|
-
if (!existsSync(tourDir)) {
|
|
334
|
-
console.error(`${red('error')} .docugate/tour/ not found. Run ${green('docugate tour init')} first.`);
|
|
335
|
-
process.exit(2);
|
|
336
|
-
}
|
|
337
|
-
const port = parseInt(one('port') ?? '4178', 10);
|
|
338
|
-
const server = await startTourServer(root, port);
|
|
339
|
-
const url = `http://localhost:${server.port}`;
|
|
340
|
-
const screens = loadTours(root);
|
|
341
|
-
console.log(`${green('Tour server')} ${url}`);
|
|
342
|
-
console.log(`${plural(screens.length, 'screen')} loaded from .docugate/tour/`);
|
|
343
|
-
if (!hasPillSnippet(root)) {
|
|
344
|
-
console.log(`${dim('Hint: run')} ${green('docugate tour install')} ${dim('to add the pill to your app automatically.')}`);
|
|
345
|
-
}
|
|
346
|
-
// Keep the process alive; Ctrl-C will stop it.
|
|
347
|
-
process.on('SIGINT', () => { server.close(); process.exit(0); });
|
|
348
|
-
process.on('SIGTERM', () => { server.close(); process.exit(0); });
|
|
349
|
-
await new Promise(() => { });
|
|
347
|
+
await serveTour(root, parseInt(one('port') ?? '4178', 10));
|
|
350
348
|
return;
|
|
351
349
|
}
|
|
352
350
|
case 'export': {
|
|
@@ -371,3 +369,28 @@ main().catch((error) => {
|
|
|
371
369
|
console.error(`${red('error')} ${error.message}`);
|
|
372
370
|
process.exit(1);
|
|
373
371
|
});
|
|
372
|
+
/**
|
|
373
|
+
* Serves the tour to the pill until Ctrl-C. Starts even when there is no tour
|
|
374
|
+
* yet: the pill then shows on every page, and its inspector writes the first
|
|
375
|
+
* step, so a failed or skipped AI step never leaves the app without it.
|
|
376
|
+
*/
|
|
377
|
+
async function serveTour(root, port) {
|
|
378
|
+
mkdirSync(join(root, '.docugate', 'tour'), { recursive: true });
|
|
379
|
+
const server = await startTourServer(root, port);
|
|
380
|
+
const url = `http://localhost:${server.port}`;
|
|
381
|
+
const screens = loadTours(root);
|
|
382
|
+
console.log(`${green('Tour server')} ${url}`);
|
|
383
|
+
if (screens.length) {
|
|
384
|
+
console.log(`${plural(screens.length, 'screen')} loaded from .docugate/tour/`);
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
console.log(`No tour yet. Open your app: the pill shows on every page, and its Inspector adds the first step.`);
|
|
388
|
+
}
|
|
389
|
+
if (!hasPillSnippet(root)) {
|
|
390
|
+
console.log(`${dim('Hint: run')} ${green('docugate tour install')} ${dim('to add the pill to your app automatically.')}`);
|
|
391
|
+
}
|
|
392
|
+
console.log(dim('Leave this running while you work. Ctrl-C stops it.'));
|
|
393
|
+
process.on('SIGINT', () => { server.close(); process.exit(0); });
|
|
394
|
+
process.on('SIGTERM', () => { server.close(); process.exit(0); });
|
|
395
|
+
await new Promise(() => { });
|
|
396
|
+
}
|
package/dist/init.js
CHANGED
package/package.json
CHANGED