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 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
- await initFlow(root, {
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: one('port') !== undefined ? parseInt(one('port'), 10) : undefined,
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
- const tourDir = `${root}/.docugate/tour`;
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
@@ -39,7 +39,7 @@ export function init(root, opts = {}) {
39
39
  }
40
40
  return { created, kept, docsDir };
41
41
  }
42
- function makeDefaultIO() {
42
+ export function makeDefaultIO() {
43
43
  const isTTY = Boolean(process.stdin.isTTY);
44
44
  return {
45
45
  isTTY,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "docugate",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Command-line tools for DocuGate: set up, check and prepare the documentation DocuGate reads straight from your repository.",
5
5
  "type": "module",
6
6
  "bin": {