workos 0.1.2 → 0.2.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.
Files changed (52) hide show
  1. package/dist/src/commands/login.js +1 -1
  2. package/dist/src/commands/login.js.map +1 -1
  3. package/dist/src/lib/adapters/cli-adapter.d.ts +21 -0
  4. package/dist/src/lib/adapters/cli-adapter.js +165 -21
  5. package/dist/src/lib/adapters/cli-adapter.js.map +1 -1
  6. package/dist/src/lib/adapters/dashboard-adapter.js +13 -0
  7. package/dist/src/lib/adapters/dashboard-adapter.js.map +1 -1
  8. package/dist/src/lib/ai-content.d.ts +10 -0
  9. package/dist/src/lib/ai-content.js +68 -0
  10. package/dist/src/lib/ai-content.js.map +1 -0
  11. package/dist/src/lib/credential-discovery.d.ts +42 -0
  12. package/dist/src/lib/credential-discovery.js +100 -0
  13. package/dist/src/lib/credential-discovery.js.map +1 -0
  14. package/dist/src/lib/credentials.d.ts +22 -0
  15. package/dist/src/lib/credentials.js +29 -0
  16. package/dist/src/lib/credentials.js.map +1 -1
  17. package/dist/src/lib/device-auth.d.ts +44 -0
  18. package/dist/src/lib/device-auth.js +137 -0
  19. package/dist/src/lib/device-auth.js.map +1 -0
  20. package/dist/src/lib/events.d.ts +75 -0
  21. package/dist/src/lib/events.js.map +1 -1
  22. package/dist/src/lib/post-install.d.ts +8 -0
  23. package/dist/src/lib/post-install.js +51 -0
  24. package/dist/src/lib/post-install.js.map +1 -0
  25. package/dist/src/lib/run-with-core.js +107 -1
  26. package/dist/src/lib/run-with-core.js.map +1 -1
  27. package/dist/src/lib/staging-api.d.ts +22 -0
  28. package/dist/src/lib/staging-api.js +74 -0
  29. package/dist/src/lib/staging-api.js.map +1 -0
  30. package/dist/src/lib/wizard-core.d.ts +300 -8
  31. package/dist/src/lib/wizard-core.js +622 -27
  32. package/dist/src/lib/wizard-core.js.map +1 -1
  33. package/dist/src/lib/wizard-core.types.d.ts +64 -1
  34. package/dist/src/lib/wizard-core.types.js.map +1 -1
  35. package/dist/src/run.d.ts +1 -0
  36. package/dist/src/run.js +1 -0
  37. package/dist/src/run.js.map +1 -1
  38. package/dist/src/utils/debug.js +15 -9
  39. package/dist/src/utils/debug.js.map +1 -1
  40. package/dist/src/utils/git-utils.d.ts +23 -0
  41. package/dist/src/utils/git-utils.js +86 -0
  42. package/dist/src/utils/git-utils.js.map +1 -0
  43. package/dist/src/utils/types.d.ts +4 -0
  44. package/dist/src/utils/types.js.map +1 -1
  45. package/package.json +6 -6
  46. package/skills/workos-authkit-base/SKILL.md +24 -14
  47. package/skills/workos-authkit-nextjs/SKILL.md +12 -1
  48. package/skills/workos-authkit-react/SKILL.md +4 -4
  49. package/skills/workos-authkit-react-router/SKILL.md +11 -10
  50. package/skills/workos-authkit-tanstack-start/SKILL.md +8 -6
  51. package/skills/workos-authkit-vanilla-js/SKILL.md +10 -8
  52. package/dist/package.json +0 -87
@@ -1,4 +1,6 @@
1
1
  import { setup, assign, fromPromise } from 'xstate';
2
+ import { getManualPrInstructions } from './post-install.js';
3
+ import { hasGhCli } from '../utils/git-utils.js';
2
4
  export const wizardMachine = setup({
3
5
  types: {
4
6
  context: {},
@@ -51,6 +53,32 @@ export const wizardMachine = setup({
51
53
  emitGitCancelled: ({ context }) => {
52
54
  context.emitter.emit('git:dirty:cancelled', {});
53
55
  },
56
+ emitBranchChecking: ({ context }) => {
57
+ context.emitter.emit('branch:checking', {});
58
+ },
59
+ emitBranchProtected: ({ context }) => {
60
+ if (context.currentBranch) {
61
+ context.emitter.emit('branch:protected', { branch: context.currentBranch });
62
+ context.emitter.emit('branch:prompt', { branch: context.currentBranch });
63
+ }
64
+ },
65
+ emitBranchCreated: ({ context }, params) => {
66
+ context.emitter.emit('branch:created', { branch: params.branch });
67
+ },
68
+ emitBranchCreateFailed: ({ context }) => {
69
+ const message = context.error?.message ?? 'Failed to create branch';
70
+ context.emitter.emit('branch:create:failed', { error: message });
71
+ },
72
+ assignBranchResult: assign({
73
+ currentBranch: ({ event }) => {
74
+ const doneEvent = event;
75
+ return doneEvent.output?.branch ?? undefined;
76
+ },
77
+ isProtectedBranch: ({ event }) => {
78
+ const doneEvent = event;
79
+ return doneEvent.output?.isProtected ?? false;
80
+ },
81
+ }),
54
82
  emitCredentialsGathering: ({ context }) => {
55
83
  const requiresApiKey = ['nextjs', 'tanstack-start', 'react-router'].includes(context.integration ?? '');
56
84
  context.emitter.emit('credentials:gathering', { requiresApiKey });
@@ -59,6 +87,44 @@ export const wizardMachine = setup({
59
87
  emitCredentialsFound: ({ context }) => {
60
88
  context.emitter.emit('credentials:found', {});
61
89
  },
90
+ emitEnvDetected: ({ context }) => {
91
+ context.emitter.emit('credentials:env:detected', { files: context.envFilesDetected ?? [] });
92
+ },
93
+ emitEnvScanPrompt: ({ context }) => {
94
+ context.emitter.emit('credentials:env:prompt', { files: context.envFilesDetected ?? [] });
95
+ },
96
+ emitEnvScanning: ({ context }) => {
97
+ context.emitter.emit('credentials:env:scanning', {});
98
+ },
99
+ emitEnvCredentialsFound: ({ context }) => {
100
+ context.emitter.emit('credentials:env:found', { sourcePath: context.envCredentialPath ?? '.env' });
101
+ },
102
+ emitEnvNotFound: ({ context }) => {
103
+ context.emitter.emit('credentials:env:notfound', {});
104
+ },
105
+ emitDeviceAuthStart: () => {
106
+ // Emitted by actor when it has verification URL
107
+ },
108
+ emitDeviceAuthSuccess: ({ context }) => {
109
+ context.emitter.emit('device:success', { email: undefined });
110
+ },
111
+ emitDeviceAuthError: ({ context }) => {
112
+ const message = context.error?.message ?? 'Device authorization failed';
113
+ context.emitter.emit('device:error', { message });
114
+ },
115
+ emitDeviceTimeout: ({ context }) => {
116
+ context.emitter.emit('device:timeout', {});
117
+ },
118
+ emitStagingFetching: ({ context }) => {
119
+ context.emitter.emit('staging:fetching', {});
120
+ },
121
+ emitStagingSuccess: ({ context }) => {
122
+ context.emitter.emit('staging:success', {});
123
+ },
124
+ emitStagingError: ({ context }) => {
125
+ const message = context.error?.message ?? 'Failed to fetch staging credentials';
126
+ context.emitter.emit('staging:error', { message });
127
+ },
62
128
  emitConfigStart: ({ context }) => {
63
129
  context.emitter.emit('config:start', {});
64
130
  },
@@ -121,12 +187,93 @@ export const wizardMachine = setup({
121
187
  context.emitter.emit('error', { message, stack: context.error?.stack });
122
188
  context.emitter.emit('complete', { success: false, summary: message });
123
189
  },
190
+ // Post-install actions
191
+ assignChangedFiles: assign({
192
+ changedFiles: ({ event }) => {
193
+ const doneEvent = event;
194
+ return doneEvent.output?.files ?? [];
195
+ },
196
+ }),
197
+ emitChangesDetected: ({ context }) => {
198
+ context.emitter.emit('postinstall:changes', { files: context.changedFiles ?? [] });
199
+ },
200
+ emitNoChanges: ({ context }) => {
201
+ context.emitter.emit('postinstall:nochanges', {});
202
+ },
203
+ emitCommitPrompt: ({ context }) => {
204
+ context.emitter.emit('postinstall:commit:prompt', {});
205
+ },
206
+ emitGeneratingCommitMessage: ({ context }) => {
207
+ context.emitter.emit('postinstall:commit:generating', {});
208
+ },
209
+ assignCommitMessage: assign({
210
+ commitMessage: ({ event }) => {
211
+ const doneEvent = event;
212
+ return doneEvent.output;
213
+ },
214
+ }),
215
+ emitCommitting: ({ context }) => {
216
+ context.emitter.emit('postinstall:commit:committing', { message: context.commitMessage ?? '' });
217
+ },
218
+ emitCommitSuccess: ({ context }) => {
219
+ context.emitter.emit('postinstall:commit:success', { message: context.commitMessage ?? '' });
220
+ },
221
+ emitCommitFailed: ({ context }) => {
222
+ const message = context.error?.message ?? 'Commit failed';
223
+ context.emitter.emit('postinstall:commit:failed', { error: message });
224
+ },
225
+ emitPrPrompt: ({ context }) => {
226
+ context.emitter.emit('postinstall:pr:prompt', {});
227
+ },
228
+ emitGeneratingPrDescription: ({ context }) => {
229
+ context.emitter.emit('postinstall:pr:generating', {});
230
+ },
231
+ assignPrDescription: assign({
232
+ prDescription: ({ event }) => {
233
+ const doneEvent = event;
234
+ return doneEvent.output;
235
+ },
236
+ }),
237
+ emitPushing: ({ context }) => {
238
+ context.emitter.emit('postinstall:pr:pushing', {});
239
+ },
240
+ emitPushFailed: ({ context }) => {
241
+ const message = context.error?.message ?? 'Push failed';
242
+ context.emitter.emit('postinstall:push:failed', { error: message });
243
+ },
244
+ emitCreatingPr: ({ context }) => {
245
+ context.emitter.emit('postinstall:pr:creating', {});
246
+ },
247
+ assignPrUrl: assign({
248
+ prUrl: ({ event }) => {
249
+ const doneEvent = event;
250
+ return doneEvent.output;
251
+ },
252
+ }),
253
+ emitPrCreated: ({ context }) => {
254
+ context.emitter.emit('postinstall:pr:success', { url: context.prUrl ?? '' });
255
+ },
256
+ emitPrFailed: ({ context }) => {
257
+ const message = context.error?.message ?? 'PR creation failed';
258
+ context.emitter.emit('postinstall:pr:failed', { error: message });
259
+ },
260
+ emitManualInstructions: ({ context }) => {
261
+ const branch = context.currentBranch ?? 'HEAD';
262
+ const instructions = getManualPrInstructions(branch);
263
+ context.emitter.emit('postinstall:manual', { instructions });
264
+ },
265
+ emitComplete: ({ context }) => {
266
+ const summary = context.agentSummary ?? 'WorkOS AuthKit installed successfully!';
267
+ context.emitter.emit('complete', { success: true, summary });
268
+ },
124
269
  },
125
270
  guards: {
126
271
  shouldSkipAuth: ({ context }) => context.options.skipAuth === true,
127
272
  gitIsClean: ({ context }) => context.gitIsClean === true,
128
273
  hasCredentials: ({ context }) => context.options.apiKey !== undefined && context.options.clientId !== undefined,
129
274
  hasIntegration: ({ context }) => context.integration !== undefined,
275
+ shouldSkipPostInstall: ({ context }) => context.options.noCommit === true,
276
+ hasGhCli: () => hasGhCli(),
130
277
  },
131
278
  actors: {
132
279
  checkAuthentication: fromPromise(async () => {
@@ -144,6 +291,48 @@ export const wizardMachine = setup({
144
291
  runAgent: fromPromise(async () => {
145
292
  throw new Error('runAgent not implemented - provide via machine.provide()');
146
293
  }),
294
+ // Credential discovery actors
295
+ detectEnvFiles: fromPromise(async () => {
296
+ throw new Error('detectEnvFiles not implemented - provide via machine.provide()');
297
+ }),
298
+ scanEnvFiles: fromPromise(async () => {
299
+ throw new Error('scanEnvFiles not implemented - provide via machine.provide()');
300
+ }),
301
+ checkStoredAuth: fromPromise(async () => {
302
+ throw new Error('checkStoredAuth not implemented - provide via machine.provide()');
303
+ }),
304
+ runDeviceAuth: fromPromise(async () => {
305
+ throw new Error('runDeviceAuth not implemented - provide via machine.provide()');
306
+ }),
307
+ fetchStagingCredentials: fromPromise(async () => {
308
+ throw new Error('fetchStagingCredentials not implemented - provide via machine.provide()');
309
+ }),
310
+ // Branch check actors
311
+ checkBranch: fromPromise(async () => {
312
+ throw new Error('checkBranch not implemented - provide via machine.provide()');
313
+ }),
314
+ createBranch: fromPromise(async () => {
315
+ throw new Error('createBranch not implemented - provide via machine.provide()');
316
+ }),
317
+ // Post-install actors
318
+ detectChanges: fromPromise(async () => {
319
+ throw new Error('detectChanges not implemented - provide via machine.provide()');
320
+ }),
321
+ generateCommitMessage: fromPromise(async () => {
322
+ throw new Error('generateCommitMessage not implemented - provide via machine.provide()');
323
+ }),
324
+ commitChanges: fromPromise(async () => {
325
+ throw new Error('commitChanges not implemented - provide via machine.provide()');
326
+ }),
327
+ generatePrDescription: fromPromise(async () => {
328
+ throw new Error('generatePrDescription not implemented - provide via machine.provide()');
329
+ }),
330
+ pushBranch: fromPromise(async () => {
331
+ throw new Error('pushBranch not implemented - provide via machine.provide()');
332
+ }),
333
+ createPr: fromPromise(async () => {
334
+ throw new Error('createPr not implemented - provide via machine.provide()');
335
+ }),
147
336
  },
148
337
  }).createMachine({
149
338
  id: 'wizard',
@@ -278,6 +467,73 @@ export const wizardMachine = setup({
278
467
  },
279
468
  },
280
469
  },
470
+ branchCheck: {
471
+ initial: 'running',
472
+ states: {
473
+ running: {
474
+ entry: ['emitBranchChecking'],
475
+ invoke: {
476
+ id: 'checkBranch',
477
+ src: 'checkBranch',
478
+ onDone: [
479
+ {
480
+ target: 'awaitingConfirmation',
481
+ guard: ({ event }) => event.output.isProtected,
482
+ actions: ['assignBranchResult', 'emitBranchProtected'],
483
+ },
484
+ {
485
+ target: 'done',
486
+ actions: ['assignBranchResult'],
487
+ },
488
+ ],
489
+ onError: {
490
+ // Branch check failure is non-fatal
491
+ target: 'done',
492
+ },
493
+ },
494
+ },
495
+ awaitingConfirmation: {
496
+ on: {
497
+ BRANCH_CREATE: {
498
+ target: 'creating',
499
+ },
500
+ BRANCH_CONTINUE: {
501
+ target: 'done',
502
+ },
503
+ BRANCH_CANCEL: {
504
+ target: '#wizard.cancelled',
505
+ },
506
+ },
507
+ },
508
+ creating: {
509
+ invoke: {
510
+ id: 'createBranch',
511
+ src: 'createBranch',
512
+ input: () => ({
513
+ name: 'feat/add-workos-authkit',
514
+ fallbackName: `feat/add-workos-authkit-${Date.now()}`,
515
+ }),
516
+ onDone: {
517
+ target: 'done',
518
+ actions: [
519
+ {
520
+ type: 'emitBranchCreated',
521
+ params: ({ event }) => ({ branch: event.output.branch }),
522
+ },
523
+ ],
524
+ },
525
+ onError: {
526
+ // Branch creation failure is non-fatal
527
+ target: 'done',
528
+ actions: ['assignError', 'emitBranchCreateFailed'],
529
+ },
530
+ },
531
+ },
532
+ done: {
533
+ type: 'final',
534
+ },
535
+ },
536
+ },
281
537
  },
282
538
  onDone: [
283
539
  {
@@ -296,26 +552,194 @@ export const wizardMachine = setup({
296
552
  },
297
553
  gatheringCredentials: {
298
554
  entry: [{ type: 'emitStateEnter', params: { state: 'gatheringCredentials' } }],
299
- initial: 'checking',
555
+ initial: 'checkingCliFlags',
300
556
  states: {
301
- checking: {
557
+ // Step 1: Check CLI flags (highest priority)
558
+ checkingCliFlags: {
302
559
  always: [
303
560
  {
304
561
  target: '#wizard.configuring',
305
562
  guard: 'hasCredentials',
306
- actions: ['emitCredentialsFound', { type: 'emitStateExit', params: { state: 'gatheringCredentials' } }],
307
- },
308
- {
309
- target: 'prompting',
563
+ actions: [
564
+ assign({ credentialSource: () => 'cli' }),
565
+ 'emitCredentialsFound',
566
+ { type: 'emitStateExit', params: { state: 'gatheringCredentials' } },
567
+ ],
310
568
  },
569
+ { target: 'detectingEnvFiles' },
311
570
  ],
312
571
  },
313
- prompting: {
572
+ // Step 2: Check if env files exist (don't read yet)
573
+ detectingEnvFiles: {
574
+ invoke: {
575
+ id: 'detectEnvFiles',
576
+ src: 'detectEnvFiles',
577
+ input: ({ context }) => ({ installDir: context.options.installDir }),
578
+ onDone: [
579
+ {
580
+ target: 'promptingEnvScan',
581
+ guard: ({ event }) => {
582
+ const output = event.output;
583
+ return output.exists;
584
+ },
585
+ actions: [
586
+ assign({
587
+ envFilesDetected: ({ event }) => {
588
+ const output = event.output;
589
+ return output.files;
590
+ },
591
+ }),
592
+ 'emitEnvDetected',
593
+ ],
594
+ },
595
+ { target: 'checkingStoredAuth' },
596
+ ],
597
+ onError: {
598
+ target: 'checkingStoredAuth', // Non-fatal, continue
599
+ },
600
+ },
601
+ },
602
+ // Step 3: Ask user for consent to scan env files
603
+ promptingEnvScan: {
604
+ entry: ['emitEnvScanPrompt'],
605
+ on: {
606
+ ENV_SCAN_APPROVED: {
607
+ target: 'scanningEnvFiles',
608
+ actions: assign({ envScanConsent: () => true }),
609
+ },
610
+ ENV_SCAN_DECLINED: {
611
+ target: 'checkingStoredAuth',
612
+ actions: assign({ envScanConsent: () => false }),
613
+ },
614
+ CANCEL: {
615
+ target: '#wizard.cancelled',
616
+ actions: { type: 'emitStateExit', params: { state: 'gatheringCredentials' } },
617
+ },
618
+ },
619
+ },
620
+ // Step 4: Scan env files for credentials (with consent)
621
+ scanningEnvFiles: {
622
+ entry: ['emitEnvScanning'],
623
+ invoke: {
624
+ id: 'scanEnvFiles',
625
+ src: 'scanEnvFiles',
626
+ input: ({ context }) => ({ installDir: context.options.installDir }),
627
+ onDone: [
628
+ {
629
+ target: '#wizard.configuring',
630
+ guard: ({ event }) => {
631
+ const result = event.output;
632
+ return result.found && !!result.clientId;
633
+ },
634
+ actions: [
635
+ assign({
636
+ credentials: ({ event }) => {
637
+ const result = event.output;
638
+ return { clientId: result.clientId, apiKey: result.apiKey };
639
+ },
640
+ credentialSource: () => 'env',
641
+ envCredentialPath: ({ event }) => event.output.sourcePath,
642
+ }),
643
+ 'emitEnvCredentialsFound',
644
+ { type: 'emitStateExit', params: { state: 'gatheringCredentials' } },
645
+ ],
646
+ },
647
+ {
648
+ target: 'checkingStoredAuth',
649
+ actions: ['emitEnvNotFound'],
650
+ },
651
+ ],
652
+ onError: {
653
+ target: 'checkingStoredAuth',
654
+ },
655
+ },
656
+ },
657
+ // Step 5: Check for stored auth token
658
+ checkingStoredAuth: {
659
+ invoke: {
660
+ id: 'checkStoredAuth',
661
+ src: 'checkStoredAuth',
662
+ onDone: [
663
+ {
664
+ target: 'fetchingStagingCredentials',
665
+ guard: ({ event }) => event.output === true,
666
+ },
667
+ { target: 'runningDeviceAuth' },
668
+ ],
669
+ onError: {
670
+ target: 'runningDeviceAuth',
671
+ },
672
+ },
673
+ },
674
+ // Step 6: Run device authorization flow
675
+ runningDeviceAuth: {
676
+ entry: ['emitDeviceAuthStart'],
677
+ invoke: {
678
+ id: 'runDeviceAuth',
679
+ src: 'runDeviceAuth',
680
+ input: ({ context }) => ({ emitter: context.emitter }),
681
+ onDone: {
682
+ target: 'fetchingStagingCredentials',
683
+ actions: [
684
+ 'emitDeviceAuthSuccess',
685
+ assign({
686
+ deviceAuth: ({ event }) => {
687
+ const output = event.output;
688
+ return {
689
+ verificationUri: output.deviceAuth.verification_uri,
690
+ verificationUriComplete: output.deviceAuth.verification_uri_complete,
691
+ userCode: output.deviceAuth.user_code,
692
+ };
693
+ },
694
+ }),
695
+ ],
696
+ },
697
+ onError: {
698
+ target: 'promptingManual',
699
+ actions: ['assignError', 'emitDeviceAuthError'],
700
+ },
701
+ },
702
+ },
703
+ // Step 7: Fetch staging credentials from API
704
+ fetchingStagingCredentials: {
705
+ entry: ['emitStagingFetching'],
706
+ invoke: {
707
+ id: 'fetchStagingCredentials',
708
+ src: 'fetchStagingCredentials',
709
+ onDone: {
710
+ target: '#wizard.configuring',
711
+ actions: [
712
+ assign({
713
+ credentials: ({ event }) => {
714
+ const staging = event.output;
715
+ return { clientId: staging.clientId, apiKey: staging.apiKey };
716
+ },
717
+ credentialSource: ({ context }) => context.deviceAuth ? 'device' : 'stored',
718
+ }),
719
+ 'emitStagingSuccess',
720
+ { type: 'emitStateExit', params: { state: 'gatheringCredentials' } },
721
+ ],
722
+ },
723
+ onError: {
724
+ target: 'promptingManual',
725
+ actions: ['assignError', 'emitStagingError'],
726
+ },
727
+ },
728
+ },
729
+ // Step 8: Manual fallback
730
+ promptingManual: {
314
731
  entry: ['emitCredentialsGathering'],
315
732
  on: {
316
733
  CREDENTIALS_SUBMITTED: {
317
734
  target: '#wizard.configuring',
318
- actions: ['assignCredentials', { type: 'emitStateExit', params: { state: 'gatheringCredentials' } }],
735
+ actions: [
736
+ 'assignCredentials',
737
+ assign({ credentialSource: () => 'manual' }),
738
+ { type: 'emitStateExit', params: { state: 'gatheringCredentials' } },
739
+ ],
740
+ },
741
+ RETRY_AUTH: {
742
+ target: 'runningDeviceAuth',
319
743
  },
320
744
  CANCEL: {
321
745
  target: '#wizard.cancelled',
@@ -347,37 +771,208 @@ export const wizardMachine = setup({
347
771
  id: 'runAgent',
348
772
  src: 'runAgent',
349
773
  input: ({ context }) => ({ context }),
350
- onDone: {
351
- target: 'complete',
352
- actions: [
353
- ({ context, event }) => {
774
+ onDone: [
775
+ {
776
+ target: 'error',
777
+ guard: ({ event }) => {
354
778
  const output = event.output;
355
- if (output.success) {
356
- context.emitter.emit('agent:success', { summary: output.summary });
357
- context.emitter.emit('complete', { success: true, summary: output.summary });
358
- }
359
- else {
779
+ return !output.success;
780
+ },
781
+ actions: [
782
+ ({ context, event }) => {
783
+ const output = event.output;
360
784
  context.emitter.emit('agent:failure', {
361
785
  message: output.error?.message ?? 'Agent failed',
362
786
  });
363
- context.emitter.emit('complete', {
364
- success: false,
365
- summary: output.error?.message,
366
- });
367
- }
368
- },
369
- { type: 'emitStateExit', params: { state: 'runningAgent' } },
370
- ],
371
- },
787
+ },
788
+ assign({
789
+ error: ({ event }) => {
790
+ const output = event.output;
791
+ return output.error ?? new Error('Agent failed');
792
+ },
793
+ }),
794
+ { type: 'emitStateExit', params: { state: 'runningAgent' } },
795
+ ],
796
+ },
797
+ {
798
+ target: 'postInstall',
799
+ actions: [
800
+ assign({
801
+ agentSummary: ({ event }) => {
802
+ const output = event.output;
803
+ return output.summary;
804
+ },
805
+ }),
806
+ ({ context, event }) => {
807
+ const output = event.output;
808
+ context.emitter.emit('agent:success', { summary: output.summary });
809
+ },
810
+ { type: 'emitStateExit', params: { state: 'runningAgent' } },
811
+ ],
812
+ },
813
+ ],
372
814
  onError: {
373
815
  target: 'error',
374
816
  actions: ['assignError', 'emitAgentFailure', { type: 'emitStateExit', params: { state: 'runningAgent' } }],
375
817
  },
376
818
  },
377
819
  },
820
+ postInstall: {
821
+ initial: 'checking',
822
+ entry: [{ type: 'emitStateEnter', params: { state: 'postInstall' } }],
823
+ states: {
824
+ checking: {
825
+ always: [
826
+ {
827
+ target: '#wizard.complete',
828
+ guard: 'shouldSkipPostInstall',
829
+ },
830
+ { target: 'detectingChanges' },
831
+ ],
832
+ },
833
+ detectingChanges: {
834
+ invoke: {
835
+ id: 'detectChanges',
836
+ src: 'detectChanges',
837
+ onDone: [
838
+ {
839
+ target: 'promptingCommit',
840
+ guard: ({ event }) => event.output.hasChanges,
841
+ actions: ['assignChangedFiles', 'emitChangesDetected'],
842
+ },
843
+ {
844
+ target: 'done',
845
+ actions: ['emitNoChanges'],
846
+ },
847
+ ],
848
+ onError: { target: 'done' },
849
+ },
850
+ },
851
+ promptingCommit: {
852
+ entry: ['emitCommitPrompt'],
853
+ on: {
854
+ COMMIT_APPROVED: { target: 'generatingCommitMessage' },
855
+ COMMIT_DECLINED: { target: 'done' },
856
+ CANCEL: { target: '#wizard.cancelled' },
857
+ },
858
+ },
859
+ generatingCommitMessage: {
860
+ entry: ['emitGeneratingCommitMessage'],
861
+ invoke: {
862
+ id: 'generateCommitMessage',
863
+ src: 'generateCommitMessage',
864
+ input: ({ context }) => ({
865
+ integration: context.integration ?? 'project',
866
+ files: context.changedFiles ?? [],
867
+ }),
868
+ onDone: {
869
+ target: 'committing',
870
+ actions: ['assignCommitMessage'],
871
+ },
872
+ },
873
+ },
874
+ committing: {
875
+ entry: ['emitCommitting'],
876
+ invoke: {
877
+ id: 'commitChanges',
878
+ src: 'commitChanges',
879
+ input: ({ context }) => ({
880
+ message: context.commitMessage ?? '',
881
+ cwd: context.options.installDir,
882
+ }),
883
+ onDone: {
884
+ target: 'checkingGhCli',
885
+ actions: ['emitCommitSuccess'],
886
+ },
887
+ onError: {
888
+ target: 'done',
889
+ actions: ['assignError', 'emitCommitFailed'],
890
+ },
891
+ },
892
+ },
893
+ checkingGhCli: {
894
+ always: [
895
+ {
896
+ target: 'promptingPr',
897
+ guard: 'hasGhCli',
898
+ },
899
+ {
900
+ target: 'showingManualInstructions',
901
+ },
902
+ ],
903
+ },
904
+ promptingPr: {
905
+ entry: ['emitPrPrompt'],
906
+ on: {
907
+ PR_APPROVED: { target: 'generatingPrDescription' },
908
+ PR_DECLINED: { target: 'done' },
909
+ CANCEL: { target: '#wizard.cancelled' },
910
+ },
911
+ },
912
+ generatingPrDescription: {
913
+ entry: ['emitGeneratingPrDescription'],
914
+ invoke: {
915
+ id: 'generatePrDescription',
916
+ src: 'generatePrDescription',
917
+ input: ({ context }) => ({
918
+ integration: context.integration ?? 'project',
919
+ files: context.changedFiles ?? [],
920
+ commitMessage: context.commitMessage ?? '',
921
+ }),
922
+ onDone: {
923
+ target: 'pushing',
924
+ actions: ['assignPrDescription'],
925
+ },
926
+ },
927
+ },
928
+ pushing: {
929
+ entry: ['emitPushing'],
930
+ invoke: {
931
+ id: 'pushBranch',
932
+ src: 'pushBranch',
933
+ input: ({ context }) => ({ cwd: context.options.installDir }),
934
+ onDone: { target: 'creatingPr' },
935
+ onError: {
936
+ target: 'showingManualInstructions',
937
+ actions: ['assignError', 'emitPushFailed'],
938
+ },
939
+ },
940
+ },
941
+ creatingPr: {
942
+ entry: ['emitCreatingPr'],
943
+ invoke: {
944
+ id: 'createPr',
945
+ src: 'createPr',
946
+ input: ({ context }) => ({
947
+ title: context.commitMessage ?? '',
948
+ body: context.prDescription ?? '',
949
+ cwd: context.options.installDir,
950
+ }),
951
+ onDone: {
952
+ target: 'done',
953
+ actions: ['assignPrUrl', 'emitPrCreated'],
954
+ },
955
+ onError: {
956
+ target: 'done',
957
+ actions: ['assignError', 'emitPrFailed'],
958
+ },
959
+ },
960
+ },
961
+ showingManualInstructions: {
962
+ entry: ['emitManualInstructions'],
963
+ always: { target: 'done' },
964
+ },
965
+ done: {
966
+ type: 'final',
967
+ },
968
+ },
969
+ onDone: {
970
+ target: 'complete',
971
+ },
972
+ },
378
973
  complete: {
379
974
  type: 'final',
380
- entry: { type: 'emitStateEnter', params: { state: 'complete' } },
975
+ entry: [{ type: 'emitStateEnter', params: { state: 'complete' } }, 'emitComplete'],
381
976
  },
382
977
  cancelled: {
383
978
  type: 'final',