@fission-ai/openspec 1.14.0 → 1.14.2

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.
Files changed (58) hide show
  1. package/README.md +15 -31
  2. package/dist/cli/commands/config.d.ts +8 -0
  3. package/dist/cli/commands/config.js +88 -0
  4. package/dist/cli/commands/context.d.ts +3 -0
  5. package/dist/cli/commands/context.js +20 -0
  6. package/dist/cli/commands/doctor.d.ts +3 -0
  7. package/dist/cli/commands/doctor.js +18 -0
  8. package/dist/cli/commands/schema.d.ts +6 -0
  9. package/dist/cli/commands/schema.js +57 -0
  10. package/dist/cli/commands/spec.d.ts +3 -0
  11. package/dist/cli/commands/spec.js +42 -0
  12. package/dist/cli/commands/store.d.ts +3 -0
  13. package/dist/cli/commands/store.js +130 -0
  14. package/dist/cli/commands/workset.d.ts +3 -0
  15. package/dist/cli/commands/workset.js +96 -0
  16. package/dist/cli/index.d.ts +5 -0
  17. package/dist/cli/index.js +86 -43
  18. package/dist/commands/completion.js +4 -1
  19. package/dist/commands/config.d.ts +16 -7
  20. package/dist/commands/config.js +342 -395
  21. package/dist/commands/context.d.ts +8 -2
  22. package/dist/commands/context.js +22 -37
  23. package/dist/commands/doctor.d.ts +6 -7
  24. package/dist/commands/doctor.js +14 -27
  25. package/dist/commands/schema.d.ts +19 -5
  26. package/dist/commands/schema.js +662 -702
  27. package/dist/commands/spec.d.ts +13 -4
  28. package/dist/commands/spec.js +91 -120
  29. package/dist/commands/store.d.ts +27 -2
  30. package/dist/commands/store.js +1 -120
  31. package/dist/commands/workflow/default-schema.d.ts +2 -0
  32. package/dist/commands/workflow/default-schema.js +4 -0
  33. package/dist/commands/workflow/instructions.js +1 -1
  34. package/dist/commands/workflow/shared.d.ts +1 -1
  35. package/dist/commands/workflow/shared.js +1 -1
  36. package/dist/commands/workset.d.ts +22 -2
  37. package/dist/commands/workset.js +1 -88
  38. package/dist/core/archive.js +32 -12
  39. package/dist/core/artifact-graph/outputs.js +39 -1
  40. package/dist/core/completion-tip.js +3 -1
  41. package/dist/core/completions/completion-provider.js +4 -2
  42. package/dist/core/config-schema.d.ts +1 -1
  43. package/dist/core/parsers/requirement-blocks.d.ts +11 -0
  44. package/dist/core/parsers/requirement-blocks.js +57 -0
  45. package/dist/core/specs-apply.js +5 -1
  46. package/dist/core/templates/workflows/apply-change.js +4 -3
  47. package/dist/core/templates/workflows/continue-change.js +17 -0
  48. package/dist/core/templates/workflows/explore.js +8 -4
  49. package/dist/core/templates/workflows/update-change.js +4 -4
  50. package/dist/core/templates/workflows/verify-change.js +26 -20
  51. package/dist/core/validation/validator.js +23 -2
  52. package/dist/core/view.js +2 -26
  53. package/dist/utils/change-metadata.d.ts +17 -0
  54. package/dist/utils/change-metadata.js +27 -2
  55. package/dist/utils/file-system.d.ts +7 -0
  56. package/dist/utils/file-system.js +25 -0
  57. package/package.json +1 -1
  58. package/schemas/spec-driven/schema.yaml +28 -4
package/dist/cli/index.js CHANGED
@@ -1,34 +1,22 @@
1
- import { asStatus } from '../commands/shared-output.js';
2
1
  import { Command, Option } from 'commander';
3
2
  import { createRequire } from 'module';
4
- import ora from 'ora';
5
3
  import path from 'path';
6
4
  import { fileURLToPath } from 'url';
7
5
  import { existsSync, promises as fs } from 'fs';
8
6
  import { AI_TOOLS, TOOL_ID_ALIASES } from '../core/config.js';
9
- import { UpdateCommand } from '../core/update.js';
10
- import { getAvailableCliUpdate, displayCliUpdateNote, shouldOfferUpgrade, getInstallDir, offerCliUpgrade, rerunUpdateWithUpgradedCli, displayUpgradeCommand, isSourceCheckout, checkForCliUpdate, getCliInstallInfo, getCliUpdateCommand, canSelfUpgrade, buildVersionReportLines, } from '../core/version-check.js';
11
- import { ListCommand } from '../core/list.js';
12
- import { ArchiveCommand } from '../core/archive.js';
13
- import { ViewCommand } from '../core/view.js';
14
- import { resolveRootForCommand, toRootOutput } from '../core/root-selection.js';
15
- import { registerSpecCommand } from '../commands/spec.js';
16
- import { ChangeCommand } from '../commands/change.js';
17
- import { ValidateCommand } from '../commands/validate.js';
18
- import { ShowCommand } from '../commands/show.js';
19
- import { CompletionCommand } from '../commands/completion.js';
20
- import { FeedbackCommand } from '../commands/feedback.js';
21
- import { registerConfigCommand } from '../commands/config.js';
22
- import { registerSchemaCommand } from '../commands/schema.js';
23
- import { registerStoreCommand } from '../commands/store.js';
24
- import { registerDoctorCommand } from '../commands/doctor.js';
25
- import { registerContextCommand } from '../commands/context.js';
26
- import { registerWorksetCommand } from '../commands/workset.js';
27
- import { statusCommand, BATCH_STATUS_FAILURE_PAYLOAD, instructionsCommand, applyInstructionsCommand, archiveInstructionsCommand, templatesCommand, schemasCommand, newChangeCommand, DEFAULT_SCHEMA, } from '../commands/workflow/index.js';
28
- import { maybeShowTelemetryNotice, trackCommand, shutdown } from '../telemetry/index.js';
29
- import { maybeShowCompletionTip } from '../core/completion-tip.js';
7
+ import { registerSpecCommand } from './commands/spec.js';
8
+ import { registerConfigCommand } from './commands/config.js';
9
+ import { registerSchemaCommand } from './commands/schema.js';
10
+ import { registerStoreCommand } from './commands/store.js';
11
+ import { registerDoctorCommand } from './commands/doctor.js';
12
+ import { registerContextCommand } from './commands/context.js';
13
+ import { registerWorksetCommand } from './commands/workset.js';
14
+ import { DEFAULT_SCHEMA } from '../commands/workflow/default-schema.js';
30
15
  import { COMMON_FLAGS } from '../core/completions/shared-flags.js';
31
- import { isInteractive } from '../utils/interactive.js';
16
+ // Startup cost: every command's implementation, and the packages it uses,
17
+ // loads with `await import()` inside its action. This module and
18
+ // ./commands/ only define commands (names, options, help), so `--version`,
19
+ // `--help`, and each command load no other command's implementation.
32
20
  const STORE_OPTION_DESCRIPTION = COMMON_FLAGS.store.description;
33
21
  // Deliberate rejection path: --store-path stays registered (hidden) so the
34
22
  // resolver can explain that registering the path is the supported route,
@@ -37,14 +25,16 @@ const STORE_OPTION_DESCRIPTION = COMMON_FLAGS.store.description;
37
25
  function hiddenStorePathOption() {
38
26
  return new Option('--store-path <path>', 'Not supported; register the path with "openspec store register <path>" and use --store <id>').hideHelp();
39
27
  }
40
- function failWithError(error, json) {
28
+ async function failWithError(error, json) {
41
29
  // The agent contract: every --json failure leaves exactly one JSON
42
30
  // document on stdout (the command's null-shape plus a status array).
43
31
  if (json?.enabled) {
32
+ const { asStatus } = await import('../commands/shared-output.js');
44
33
  console.log(JSON.stringify({ ...(json.payload ?? {}), status: [asStatus(error, json.fallbackCode ?? 'command_error')] }, null, 2));
45
34
  process.exitCode = 1;
46
35
  return;
47
36
  }
37
+ const { default: ora } = await import('ora');
48
38
  ora().fail(`Error: ${error.message}`);
49
39
  // Resolution and store errors carry a pasteable fix - never drop it.
50
40
  const fix = error.diagnostic?.fix;
@@ -100,6 +90,13 @@ export function isJsonRun(command) {
100
90
  export function isCompletionRun(commandPath) {
101
91
  return commandPath.split(':')[0] === 'completion' || commandPath === '__complete';
102
92
  }
93
+ /**
94
+ * True for the hidden `__complete` resolver alone. It runs on every Tab press,
95
+ * so the hooks skip telemetry and the completion tip for it entirely.
96
+ */
97
+ export function isTabCompletionRun(commandPath) {
98
+ return commandPath === '__complete';
99
+ }
103
100
  /**
104
101
  * True when the first-run completions tip must be deferred rather than shown.
105
102
  *
@@ -124,6 +121,7 @@ program
124
121
  .option('--json', 'Output as JSON')
125
122
  .option('--check', 'Check the registry for a newer version')
126
123
  .action(async (options) => {
124
+ const { getCliInstallInfo, checkForCliUpdate, getCliUpdateCommand, canSelfUpgrade, buildVersionReportLines, } = await import('../core/version-check.js');
127
125
  const install = getCliInstallInfo();
128
126
  const update = options.check ? await checkForCliUpdate() : undefined;
129
127
  const command = update?.status === 'available' ? getCliUpdateCommand(install) : null;
@@ -158,9 +156,16 @@ program.hook('preAction', async (thisCommand, actionCommand) => {
158
156
  if (opts.color === false) {
159
157
  process.env.NO_COLOR = '1';
160
158
  }
159
+ // `__complete` runs on every Tab press, with stderr sent to /dev/null by the
160
+ // generated scripts. Tracking it would hold each press open for the request,
161
+ // and the first-run notice would be marked seen without anyone reading it.
162
+ if (isTabCompletionRun(getCommandPath(actionCommand))) {
163
+ return;
164
+ }
161
165
  // Show first-run telemetry notice (if not seen). It's written to stderr, so it
162
166
  // never pollutes stdout — but --json runs still defer it (see isJsonRun) so the
163
167
  // very first invocation stays free of any incidental output on either stream.
168
+ const { maybeShowTelemetryNotice, trackCommand } = await import('../telemetry/index.js');
164
169
  await maybeShowTelemetryNotice({ silent: isJsonRun(actionCommand) });
165
170
  // Track command execution (use actionCommand to get the actual subcommand)
166
171
  const commandPath = getCommandPath(actionCommand);
@@ -168,6 +173,11 @@ program.hook('preAction', async (thisCommand, actionCommand) => {
168
173
  });
169
174
  // Shutdown telemetry after command completes
170
175
  program.hook('postAction', async (_thisCommand, actionCommand) => {
176
+ // Nothing to flush (preAction tracked nothing), and the tip is always
177
+ // deferred for completion runs, so skip loading either module.
178
+ if (isTabCompletionRun(getCommandPath(actionCommand))) {
179
+ return;
180
+ }
171
181
  // Show the first-run shell-completions tip (on stderr, so piped stdout stays
172
182
  // clean). postAction, not preAction: the tip trails the command's own output
173
183
  // instead of pushing an error message or `init`'s setup summary down the
@@ -175,6 +185,7 @@ program.hook('postAction', async (_thisCommand, actionCommand) => {
175
185
  // `openspec completion ...`, and a stderr that is not a terminal (agents and
176
186
  // pipes would otherwise silently burn the user's one-shot tip).
177
187
  try {
188
+ const { maybeShowCompletionTip } = await import('../core/completion-tip.js');
178
189
  await maybeShowCompletionTip({
179
190
  silent: shouldDeferCompletionTip(actionCommand, Boolean(process.stderr.isTTY)),
180
191
  });
@@ -182,6 +193,7 @@ program.hook('postAction', async (_thisCommand, actionCommand) => {
182
193
  finally {
183
194
  // The flush runs even if the hint throws: parse() is synchronous, so a
184
195
  // rejection here has no catch anywhere above it.
196
+ const { shutdown } = await import('../telemetry/index.js');
185
197
  await shutdown();
186
198
  }
187
199
  });
@@ -236,7 +248,7 @@ program
236
248
  await initCommand.execute(targetPath);
237
249
  }
238
250
  catch (error) {
239
- failWithError(error);
251
+ await failWithError(error);
240
252
  process.exit(1);
241
253
  }
242
254
  });
@@ -257,7 +269,7 @@ program
257
269
  await initCommand.execute('.');
258
270
  }
259
271
  catch (error) {
260
- failWithError(error);
272
+ await failWithError(error);
261
273
  process.exit(1);
262
274
  }
263
275
  });
@@ -267,6 +279,11 @@ program
267
279
  .option('--force', 'Force update even when tools are up to date')
268
280
  .action(async (targetPath = '.', options) => {
269
281
  try {
282
+ const [{ getInstallDir, isSourceCheckout, getAvailableCliUpdate, shouldOfferUpgrade, displayCliUpdateNote, offerCliUpgrade, rerunUpdateWithUpgradedCli, displayUpgradeCommand, }, { isInteractive }, { UpdateCommand },] = await Promise.all([
283
+ import('../core/version-check.js'),
284
+ import('../utils/interactive.js'),
285
+ import('../core/update.js'),
286
+ ]);
270
287
  const installDir = getInstallDir();
271
288
  // Running from a clone: the version is whatever the branch says, so any
272
289
  // upgrade advice would be noise. Decided before the request, so a
@@ -318,7 +335,7 @@ program
318
335
  }
319
336
  }
320
337
  catch (error) {
321
- failWithError(error);
338
+ await failWithError(error);
322
339
  process.exit(1);
323
340
  }
324
341
  });
@@ -338,6 +355,10 @@ program
338
355
  if (options?.specs && (options.archived || options.all)) {
339
356
  throw new Error('--archived and --all can only be used when listing changes.');
340
357
  }
358
+ const [{ resolveRootForCommand, toRootOutput }, { ListCommand }] = await Promise.all([
359
+ import('../core/root-selection.js'),
360
+ import('../core/list.js'),
361
+ ]);
341
362
  const root = await resolveRootForCommand(options ?? {}, {
342
363
  json: options?.json,
343
364
  failurePayload: options?.specs ? { specs: [], root: null } : { changes: [], root: null },
@@ -360,7 +381,7 @@ program
360
381
  });
361
382
  }
362
383
  catch (error) {
363
- failWithError(error, {
384
+ await failWithError(error, {
364
385
  enabled: options?.json,
365
386
  payload: options?.specs ? { specs: [], root: null } : { changes: [], root: null },
366
387
  fallbackCode: 'list_error',
@@ -378,6 +399,10 @@ program
378
399
  // Implicit cwd fallback stays enabled so `view` keeps accepting the same
379
400
  // directories as `list`/`status` — notably pre-config.yaml `openspec/`
380
401
  // dirs. ViewCommand still reports a missing openspec/ directory itself.
402
+ const [{ resolveRootForCommand }, { ViewCommand }] = await Promise.all([
403
+ import('../core/root-selection.js'),
404
+ import('../core/view.js'),
405
+ ]);
381
406
  const root = await resolveRootForCommand(options ?? {});
382
407
  if (!root) {
383
408
  return;
@@ -386,7 +411,7 @@ program
386
411
  await viewCommand.execute(root.path);
387
412
  }
388
413
  catch (error) {
389
- failWithError(error);
414
+ await failWithError(error);
390
415
  process.exit(1);
391
416
  }
392
417
  });
@@ -408,6 +433,7 @@ changeCmd
408
433
  .option('--no-interactive', 'Disable interactive prompts')
409
434
  .action(async (changeName, options) => {
410
435
  try {
436
+ const { ChangeCommand } = await import('../commands/change.js');
411
437
  const changeCommand = new ChangeCommand();
412
438
  await changeCommand.show(changeName, options);
413
439
  }
@@ -424,6 +450,7 @@ changeCmd
424
450
  .action(async (options) => {
425
451
  try {
426
452
  console.error('Warning: "openspec change list" is deprecated. Use "openspec list".');
453
+ const { ChangeCommand } = await import('../commands/change.js');
427
454
  const changeCommand = new ChangeCommand();
428
455
  await changeCommand.list(options);
429
456
  }
@@ -440,6 +467,7 @@ changeCmd
440
467
  .option('--no-interactive', 'Disable interactive prompts')
441
468
  .action(async (changeName, options) => {
442
469
  try {
470
+ const { ChangeCommand } = await import('../commands/change.js');
443
471
  const changeCommand = new ChangeCommand();
444
472
  // validate() already sets process.exitCode, and Node honours it at
445
473
  // natural exit. Calling process.exit() here would skip commander's
@@ -464,11 +492,12 @@ program
464
492
  .addOption(hiddenStorePathOption())
465
493
  .action(async (changeName, options) => {
466
494
  try {
495
+ const { ArchiveCommand } = await import('../core/archive.js');
467
496
  const archiveCommand = new ArchiveCommand();
468
497
  await archiveCommand.execute(changeName, options);
469
498
  }
470
499
  catch (error) {
471
- failWithError(error);
500
+ await failWithError(error);
472
501
  process.exit(1);
473
502
  }
474
503
  });
@@ -497,11 +526,12 @@ program
497
526
  .addOption(hiddenStorePathOption())
498
527
  .action(async (itemName, options) => {
499
528
  try {
529
+ const { ValidateCommand } = await import('../commands/validate.js');
500
530
  const validateCommand = new ValidateCommand();
501
531
  await validateCommand.execute(itemName, options);
502
532
  }
503
533
  catch (error) {
504
- failWithError(error, { enabled: options?.json, fallbackCode: 'validate_error' });
534
+ await failWithError(error, { enabled: options?.json, fallbackCode: 'validate_error' });
505
535
  process.exit(1);
506
536
  }
507
537
  });
@@ -528,11 +558,12 @@ program
528
558
  .allowUnknownOption(true)
529
559
  .action(async (itemName, options) => {
530
560
  try {
561
+ const { ShowCommand } = await import('../commands/show.js');
531
562
  const showCommand = new ShowCommand();
532
563
  await showCommand.execute(itemName, options ?? {});
533
564
  }
534
565
  catch (error) {
535
- failWithError(error, { enabled: options?.json, fallbackCode: 'show_error' });
566
+ await failWithError(error, { enabled: options?.json, fallbackCode: 'show_error' });
536
567
  process.exit(1);
537
568
  }
538
569
  });
@@ -543,11 +574,12 @@ program
543
574
  .option('--body <text>', 'Detailed description for the feedback')
544
575
  .action(async (message, options) => {
545
576
  try {
577
+ const { FeedbackCommand } = await import('../commands/feedback.js');
546
578
  const feedbackCommand = new FeedbackCommand();
547
579
  await feedbackCommand.execute(message, options);
548
580
  }
549
581
  catch (error) {
550
- failWithError(error);
582
+ await failWithError(error);
551
583
  process.exit(1);
552
584
  }
553
585
  });
@@ -560,11 +592,12 @@ completionCmd
560
592
  .description('Generate completion script for a shell (outputs to stdout)')
561
593
  .action(async (shell) => {
562
594
  try {
595
+ const { CompletionCommand } = await import('../commands/completion.js');
563
596
  const completionCommand = new CompletionCommand();
564
597
  await completionCommand.generate({ shell });
565
598
  }
566
599
  catch (error) {
567
- failWithError(error);
600
+ await failWithError(error);
568
601
  process.exit(1);
569
602
  }
570
603
  });
@@ -574,11 +607,12 @@ completionCmd
574
607
  .option('--verbose', 'Show detailed installation output')
575
608
  .action(async (shell, options) => {
576
609
  try {
610
+ const { CompletionCommand } = await import('../commands/completion.js');
577
611
  const completionCommand = new CompletionCommand();
578
612
  await completionCommand.install({ shell, verbose: options?.verbose });
579
613
  }
580
614
  catch (error) {
581
- failWithError(error);
615
+ await failWithError(error);
582
616
  process.exit(1);
583
617
  }
584
618
  });
@@ -588,11 +622,12 @@ completionCmd
588
622
  .option('-y, --yes', 'Skip confirmation prompts')
589
623
  .action(async (shell, options) => {
590
624
  try {
625
+ const { CompletionCommand } = await import('../commands/completion.js');
591
626
  const completionCommand = new CompletionCommand();
592
627
  await completionCommand.uninstall({ shell, yes: options?.yes });
593
628
  }
594
629
  catch (error) {
595
- failWithError(error);
630
+ await failWithError(error);
596
631
  process.exit(1);
597
632
  }
598
633
  });
@@ -602,6 +637,7 @@ program
602
637
  .description('Output completion data in machine-readable format (internal use)')
603
638
  .action(async (type) => {
604
639
  try {
640
+ const { CompletionCommand } = await import('../commands/completion.js');
605
641
  const completionCommand = new CompletionCommand();
606
642
  await completionCommand.complete({ type });
607
643
  }
@@ -625,14 +661,17 @@ program
625
661
  .addOption(hiddenStorePathOption())
626
662
  .action(async (options) => {
627
663
  try {
664
+ const { statusCommand } = await import('../commands/workflow/status.js');
628
665
  await statusCommand(options);
629
666
  }
630
667
  catch (error) {
631
- failWithError(error, {
668
+ await failWithError(error, {
632
669
  enabled: options.json,
633
670
  // The batch null-shape; the single-change failure shape is
634
671
  // pre-existing contract and stays payload-free.
635
- payload: options.all ? BATCH_STATUS_FAILURE_PAYLOAD : undefined,
672
+ payload: options.all
673
+ ? (await import('../commands/workflow/status.js')).BATCH_STATUS_FAILURE_PAYLOAD
674
+ : undefined,
636
675
  fallbackCode: 'change_error',
637
676
  });
638
677
  process.exit(1);
@@ -649,6 +688,7 @@ program
649
688
  .addOption(hiddenStorePathOption())
650
689
  .action(async (artifactId, options) => {
651
690
  try {
691
+ const { applyInstructionsCommand, archiveInstructionsCommand, instructionsCommand } = await import('../commands/workflow/instructions.js');
652
692
  // Workflow instruction surfaces are reserved command branches, not artifacts.
653
693
  if (artifactId === 'apply') {
654
694
  await applyInstructionsCommand(options);
@@ -661,7 +701,7 @@ program
661
701
  }
662
702
  }
663
703
  catch (error) {
664
- failWithError(error, { enabled: options.json, fallbackCode: 'change_error' });
704
+ await failWithError(error, { enabled: options.json, fallbackCode: 'change_error' });
665
705
  process.exit(1);
666
706
  }
667
707
  });
@@ -673,10 +713,11 @@ program
673
713
  .option('--json', 'Output as JSON mapping artifact IDs to template paths')
674
714
  .action(async (options) => {
675
715
  try {
716
+ const { templatesCommand } = await import('../commands/workflow/templates.js');
676
717
  await templatesCommand(options);
677
718
  }
678
719
  catch (error) {
679
- failWithError(error);
720
+ await failWithError(error);
680
721
  process.exit(1);
681
722
  }
682
723
  });
@@ -689,10 +730,11 @@ program
689
730
  .addOption(hiddenStorePathOption())
690
731
  .action(async (options) => {
691
732
  try {
733
+ const { schemasCommand } = await import('../commands/workflow/schemas.js');
692
734
  await schemasCommand(options);
693
735
  }
694
736
  catch (error) {
695
- failWithError(error, {
737
+ await failWithError(error, {
696
738
  enabled: options.json,
697
739
  payload: { schemas: [], root: null },
698
740
  fallbackCode: 'schemas_error',
@@ -717,10 +759,11 @@ newCmd
717
759
  .addOption(new Option('--areas <names>', 'No longer supported').hideHelp())
718
760
  .action(async (name, options) => {
719
761
  try {
762
+ const { newChangeCommand } = await import('../commands/workflow/new-change.js');
720
763
  await newChangeCommand(name, options);
721
764
  }
722
765
  catch (error) {
723
- failWithError(error);
766
+ await failWithError(error);
724
767
  process.exit(1);
725
768
  }
726
769
  });
@@ -1,4 +1,3 @@
1
- import ora from 'ora';
2
1
  import { CompletionFactory } from '../core/completions/factory.js';
3
2
  import { COMMAND_REGISTRY } from '../core/completions/command-registry.js';
4
3
  import { detectShell } from '../utils/shell-detection.js';
@@ -93,6 +92,9 @@ export class CompletionCommand {
93
92
  async installForShell(shell, verbose) {
94
93
  const generator = CompletionFactory.createGenerator(shell);
95
94
  const installer = CompletionFactory.createInstaller(shell);
95
+ // Loaded here, not at the top: `__complete` shares this module and runs on
96
+ // every Tab press, so it must not pay for the spinner.
97
+ const { default: ora } = await import('ora');
96
98
  const spinner = ora(`Installing ${shell} completion script...`).start();
97
99
  try {
98
100
  // Generate the completion script
@@ -187,6 +189,7 @@ export class CompletionCommand {
187
189
  return;
188
190
  }
189
191
  }
192
+ const { default: ora } = await import('ora');
190
193
  const spinner = ora(`Uninstalling ${shell} completion script...`).start();
191
194
  try {
192
195
  const result = await installer.uninstall();
@@ -1,4 +1,3 @@
1
- import { Command } from 'commander';
2
1
  import { GlobalConfig } from '../core/global-config.js';
3
2
  import type { Profile, Delivery } from '../core/global-config.js';
4
3
  /**
@@ -40,11 +39,21 @@ export declare function formatWorkflowSummary(workflows: readonly string[], prof
40
39
  * Build a user-facing diff summary between two profile states.
41
40
  */
42
41
  export declare function diffProfileState(before: ProfileState, after: ProfileState): ProfileStateDiff;
43
- /**
44
- * Register the config command and all its subcommands.
45
- *
46
- * @param program - The Commander program instance
47
- */
48
- export declare function registerConfigCommand(program: Command): void;
42
+ export declare function configPathCommand(): void;
43
+ export declare function configListCommand(options: {
44
+ json?: boolean;
45
+ }): void;
46
+ export declare function configGetCommand(key: string): void;
47
+ export declare function configSetCommand(key: string, value: string, options: {
48
+ string?: boolean;
49
+ allowUnknown?: boolean;
50
+ }): void;
51
+ export declare function configUnsetCommand(key: string): void;
52
+ export declare function configResetCommand(options: {
53
+ all?: boolean;
54
+ yes?: boolean;
55
+ }): Promise<void>;
56
+ export declare function configEditCommand(): Promise<void>;
57
+ export declare function configProfileCommand(preset?: string): Promise<void>;
49
58
  export {};
50
59
  //# sourceMappingURL=config.d.ts.map