fraim 2.0.167 → 2.0.168

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 (54) hide show
  1. package/dist/src/ai-hub/catalog.js +28 -14
  2. package/dist/src/ai-hub/server.js +10 -403
  3. package/dist/src/cli/commands/init-project.js +1 -98
  4. package/dist/src/cli/commands/manager.js +40 -0
  5. package/dist/src/cli/commands/sync.js +17 -21
  6. package/dist/src/cli/fraim.js +2 -0
  7. package/dist/src/cli/utils/github-workflow-sync.js +12 -146
  8. package/dist/src/cli/utils/manager-pack-sync.js +188 -0
  9. package/dist/src/cli/utils/manager-publish.js +76 -0
  10. package/dist/src/cli/utils/user-config.js +20 -0
  11. package/dist/src/core/fraim-config-schema.generated.js +85 -10
  12. package/dist/src/core/manager-pack.js +26 -0
  13. package/dist/src/first-run/install-state.js +1 -0
  14. package/dist/src/first-run/server.js +9 -0
  15. package/dist/src/first-run/session-service.js +117 -23
  16. package/dist/src/first-run/types.js +2 -5
  17. package/dist/src/local-mcp-server/learning-context-builder.js +45 -8
  18. package/dist/src/local-mcp-server/stdio-server.js +28 -0
  19. package/index.js +1 -1
  20. package/package.json +1 -2
  21. package/public/ai-hub/index.html +0 -81
  22. package/public/ai-hub/powerpoint-taskpane/index.html +236 -236
  23. package/public/ai-hub/powerpoint-taskpane/manifest.xml +29 -29
  24. package/public/ai-hub/script.js +3 -219
  25. package/public/ai-hub/styles.css +8 -36
  26. package/public/first-run/index.html +1 -1
  27. package/public/first-run/script.js +459 -530
  28. package/public/first-run/styles.css +288 -73
  29. package/public/portfolio/ashley.html +1 -1
  30. package/public/portfolio/casey.html +1 -1
  31. package/public/portfolio/celia.html +1 -1
  32. package/public/portfolio/gautam.html +1 -1
  33. package/public/portfolio/hari.html +1 -1
  34. package/public/portfolio/maestro.html +1 -1
  35. package/public/portfolio/mandy.html +1 -1
  36. package/public/portfolio/pam.html +6 -6
  37. package/public/portfolio/qasm.html +1 -1
  38. package/public/portfolio/sade.html +1 -1
  39. package/public/portfolio/sam.html +1 -1
  40. package/public/portfolio/swen.html +6 -6
  41. package/dist/src/ai-hub/word-sideload.js +0 -95
  42. package/dist/src/cli/commands/test-mcp.js +0 -171
  43. package/dist/src/cli/setup/first-run.js +0 -242
  44. package/dist/src/config/ai-manager-hiring.js +0 -121
  45. package/dist/src/config/compat.js +0 -16
  46. package/dist/src/config/feature-flags.js +0 -25
  47. package/dist/src/config/persona-capability-bundles.js +0 -273
  48. package/dist/src/config/persona-hiring.js +0 -270
  49. package/dist/src/config/portfolio-slug-overrides.js +0 -17
  50. package/dist/src/config/pricing.js +0 -37
  51. package/dist/src/config/stripe.js +0 -43
  52. package/dist/src/core/config-writer.js +0 -75
  53. package/dist/src/core/utils/job-aliases.js +0 -47
  54. package/dist/src/core/utils/workflow-parser.js +0 -174
@@ -421,14 +421,209 @@ body {
421
421
  flex-direction: column;
422
422
  }
423
423
 
424
- .recruit-container,
425
- .start-container {
426
- gap: 12px;
427
- }
428
-
429
- .start-container {
430
- gap: 14px;
431
- }
424
+ .setup-shell {
425
+ list-style: none;
426
+ margin: 0;
427
+ padding: 0;
428
+ display: grid;
429
+ grid-template-columns: minmax(190px, 0.85fr) minmax(0, 2fr);
430
+ gap: 20px;
431
+ }
432
+ .setup-steps {
433
+ display: flex;
434
+ flex-direction: column;
435
+ gap: 8px;
436
+ border-right: 1px solid var(--line);
437
+ padding-right: 16px;
438
+ }
439
+ .setup-step {
440
+ width: 100%;
441
+ min-height: 44px;
442
+ display: flex;
443
+ align-items: center;
444
+ gap: 10px;
445
+ border: 1px solid var(--line);
446
+ border-radius: 8px;
447
+ background: var(--surface);
448
+ color: var(--text);
449
+ padding: 9px 10px;
450
+ font: inherit;
451
+ font-weight: 600;
452
+ text-align: left;
453
+ cursor: pointer;
454
+ }
455
+ .setup-step[aria-current="step"] {
456
+ border-color: var(--accent);
457
+ background: var(--accent-soft);
458
+ }
459
+ .setup-step:disabled {
460
+ opacity: 0.55;
461
+ cursor: not-allowed;
462
+ }
463
+ .step-dot {
464
+ width: 24px;
465
+ height: 24px;
466
+ border-radius: 50%;
467
+ display: inline-flex;
468
+ align-items: center;
469
+ justify-content: center;
470
+ background: var(--line);
471
+ color: var(--muted);
472
+ font-size: 12px;
473
+ flex: 0 0 auto;
474
+ }
475
+ .setup-step[data-status="done"] .step-dot {
476
+ background: var(--accent);
477
+ color: #fff;
478
+ }
479
+ .setup-pane {
480
+ min-width: 0;
481
+ display: flex;
482
+ flex-direction: column;
483
+ gap: 14px;
484
+ }
485
+ .setup-pane h2 {
486
+ margin: 0;
487
+ font-size: 18px;
488
+ font-weight: 650;
489
+ }
490
+ .pane-copy,
491
+ .locked-note {
492
+ margin: 0;
493
+ color: var(--muted);
494
+ font-size: 14px;
495
+ }
496
+ .locked-note { color: var(--warn); }
497
+ .row-list {
498
+ list-style: none;
499
+ margin: 0;
500
+ padding: 0;
501
+ border: 1px solid var(--line);
502
+ border-radius: 10px;
503
+ overflow: hidden;
504
+ }
505
+ .row-list .row {
506
+ display: flex;
507
+ gap: 10px;
508
+ align-items: center;
509
+ padding: 12px;
510
+ border-bottom: 1px solid var(--line);
511
+ }
512
+ .row-list .row:last-child { border-bottom: 0; }
513
+ .agent-grid,
514
+ .choice-grid {
515
+ display: grid;
516
+ grid-template-columns: repeat(2, minmax(0, 1fr));
517
+ gap: 12px;
518
+ }
519
+ .ready-strip {
520
+ background: var(--accent-soft);
521
+ border: 1px solid var(--accent);
522
+ color: var(--accent-strong);
523
+ border-radius: 8px;
524
+ padding: 10px 12px;
525
+ font-size: 13px;
526
+ font-weight: 600;
527
+ }
528
+ .ready-strip--muted {
529
+ background: var(--soft);
530
+ border-color: var(--line);
531
+ color: var(--muted);
532
+ }
533
+ .ready-strip--error {
534
+ background: #fff1f2;
535
+ border-color: #fb7185;
536
+ color: #9f1239;
537
+ }
538
+ .btn {
539
+ border-radius: 8px;
540
+ padding: 9px 14px;
541
+ font: inherit;
542
+ font-weight: 600;
543
+ cursor: pointer;
544
+ border: 1px solid var(--line);
545
+ align-self: flex-start;
546
+ }
547
+ .btn:disabled {
548
+ opacity: 0.55;
549
+ cursor: not-allowed;
550
+ }
551
+ .btn-primary {
552
+ background: var(--accent);
553
+ border-color: var(--accent);
554
+ color: #fff;
555
+ }
556
+ .btn-primary:hover { background: var(--accent-strong); }
557
+ .btn-secondary {
558
+ background: var(--surface);
559
+ color: var(--accent-strong);
560
+ }
561
+ .btn-secondary:hover {
562
+ border-color: var(--accent);
563
+ background: var(--soft);
564
+ }
565
+ .btn-ghost {
566
+ background: transparent;
567
+ color: var(--muted);
568
+ }
569
+ .modal-backdrop {
570
+ position: fixed;
571
+ inset: 0;
572
+ z-index: 1000;
573
+ display: flex;
574
+ align-items: center;
575
+ justify-content: center;
576
+ padding: 18px;
577
+ background: rgba(31, 42, 36, 0.36);
578
+ }
579
+ .modal {
580
+ width: min(520px, 100%);
581
+ background: var(--surface);
582
+ border: 1px solid var(--line);
583
+ border-radius: 12px;
584
+ box-shadow: var(--shadow-lg);
585
+ padding: 22px;
586
+ display: flex;
587
+ flex-direction: column;
588
+ gap: 14px;
589
+ }
590
+ .modal h2 {
591
+ margin: 0;
592
+ font-size: 19px;
593
+ }
594
+ .install-status {
595
+ margin: 0;
596
+ border: 1px solid var(--line);
597
+ background: var(--soft);
598
+ border-radius: 8px;
599
+ padding: 10px 12px;
600
+ color: var(--muted);
601
+ }
602
+ .install-status[data-tone="error"] {
603
+ color: var(--danger);
604
+ background: #fbf1f1;
605
+ border-color: var(--danger);
606
+ }
607
+ .modal-help {
608
+ margin: -4px 0 0;
609
+ color: var(--muted);
610
+ font-size: 13px;
611
+ line-height: 1.45;
612
+ }
613
+ .install-actions {
614
+ display: flex;
615
+ flex-wrap: wrap;
616
+ gap: 8px;
617
+ }
618
+
619
+ .recruit-container,
620
+ .start-container {
621
+ gap: 12px;
622
+ }
623
+
624
+ .start-container {
625
+ gap: 14px;
626
+ }
432
627
 
433
628
  .user-type-card {
434
629
  background: var(--surface);
@@ -448,23 +643,23 @@ body {
448
643
  border-color: var(--accent);
449
644
  background: var(--accent-soft);
450
645
  }
451
- .user-type-card--featured:hover {
452
- box-shadow: 0 4px 20px rgba(61, 138, 110, 0.18);
453
- }
454
-
455
- .user-type-card--ide-default {
456
- padding: 24px;
457
- gap: 18px;
458
- }
459
-
460
- .user-type-card--compact {
461
- padding: 16px 18px;
462
- gap: 12px;
463
- }
464
-
465
- .user-type-card--alpha {
466
- background: linear-gradient(180deg, #fbfcfa 0%, #f4f7f2 100%);
467
- }
646
+ .user-type-card--featured:hover {
647
+ box-shadow: 0 4px 20px rgba(61, 138, 110, 0.18);
648
+ }
649
+
650
+ .user-type-card--ide-default {
651
+ padding: 24px;
652
+ gap: 18px;
653
+ }
654
+
655
+ .user-type-card--compact {
656
+ padding: 16px 18px;
657
+ gap: 12px;
658
+ }
659
+
660
+ .user-type-card--alpha {
661
+ background: linear-gradient(180deg, #fbfcfa 0%, #f4f7f2 100%);
662
+ }
468
663
 
469
664
  .card-header {
470
665
  display: flex;
@@ -492,38 +687,38 @@ body {
492
687
  border-color: var(--accent);
493
688
  }
494
689
 
495
- .card-title {
496
- display: block;
497
- font-size: 15px;
498
- font-weight: 600;
499
- color: var(--text);
500
- margin-bottom: 3px;
501
- }
502
- .card-desc { margin: 0; font-size: 13px; color: var(--muted); line-height: 1.45; }
503
-
504
- .card-eyebrow {
505
- display: inline-flex;
506
- align-self: flex-start;
507
- padding: 4px 10px;
508
- border-radius: 999px;
509
- background: var(--accent-soft);
510
- color: var(--accent-strong);
511
- font-size: 11px;
512
- font-weight: 700;
513
- letter-spacing: 0.06em;
514
- text-transform: uppercase;
515
- }
516
-
517
- .route-note {
518
- margin: 0;
519
- color: var(--muted);
520
- font-size: 13px;
521
- line-height: 1.5;
522
- }
523
-
524
- .route-note--compact {
525
- font-size: 12px;
526
- }
690
+ .card-title {
691
+ display: block;
692
+ font-size: 15px;
693
+ font-weight: 600;
694
+ color: var(--text);
695
+ margin-bottom: 3px;
696
+ }
697
+ .card-desc { margin: 0; font-size: 13px; color: var(--muted); line-height: 1.45; }
698
+
699
+ .card-eyebrow {
700
+ display: inline-flex;
701
+ align-self: flex-start;
702
+ padding: 4px 10px;
703
+ border-radius: 999px;
704
+ background: var(--accent-soft);
705
+ color: var(--accent-strong);
706
+ font-size: 11px;
707
+ font-weight: 700;
708
+ letter-spacing: 0.06em;
709
+ text-transform: uppercase;
710
+ }
711
+
712
+ .route-note {
713
+ margin: 0;
714
+ color: var(--muted);
715
+ font-size: 13px;
716
+ line-height: 1.5;
717
+ }
718
+
719
+ .route-note--compact {
720
+ font-size: 12px;
721
+ }
527
722
 
528
723
  .btn {
529
724
  display: inline-flex;
@@ -567,14 +762,25 @@ body {
567
762
  .recruit-card {
568
763
  cursor: default;
569
764
  }
765
+
766
+ .byoa-card {
767
+ grid-column: 1 / -1;
768
+ }
769
+
770
+ .byoa-card .cmd-block {
771
+ align-self: flex-start;
772
+ display: inline-block;
773
+ white-space: nowrap;
774
+ word-break: normal;
775
+ }
570
776
  .recruit-card:hover {
571
777
  box-shadow: none;
572
778
  border-color: var(--line);
573
779
  }
574
780
 
575
- /* IDE command display — shown after choosing "In my IDE". */
576
- .cmd-block {
577
- background: #0d1410;
781
+ /* IDE command display — shown after choosing "In my IDE". */
782
+ .cmd-block {
783
+ background: #0d1410;
578
784
  color: #c8d3cd;
579
785
  font-family: "JetBrains Mono", "Cascadia Code", Consolas, monospace;
580
786
  font-size: 14px;
@@ -612,16 +818,25 @@ body {
612
818
  * want the surface to degrade gracefully for users who happen to open it
613
819
  * in a narrow window. Stack the label / verb / change link vertically and
614
820
  * let the row breathe. */
615
- @media (max-width: 600px) {
616
- .page { padding: 24px 16px 24px; }
617
- .checklist .row { gap: 8px; padding: 12px 14px; }
618
- .row .label { min-width: 0; }
619
- .row .verb { flex: 1 1 100%; }
620
- .row .change-link { margin-left: auto; }
621
- .row .project-picker { gap: 8px; }
622
- .row .project-picker input { width: 100%; min-width: 0; }
623
- .user-type-card--ide-default,
624
- .user-type-card--compact {
625
- padding: 18px 16px;
626
- }
627
- }
821
+ @media (max-width: 600px) {
822
+ .page { padding: 24px 16px 24px; }
823
+ .setup-shell { grid-template-columns: 1fr; }
824
+ .setup-steps {
825
+ border-right: 0;
826
+ border-bottom: 1px solid var(--line);
827
+ padding-right: 0;
828
+ padding-bottom: 12px;
829
+ }
830
+ .agent-grid,
831
+ .choice-grid { grid-template-columns: 1fr; }
832
+ .checklist .row { gap: 8px; padding: 12px 14px; }
833
+ .row .label { min-width: 0; }
834
+ .row .verb { flex: 1 1 100%; }
835
+ .row .change-link { margin-left: auto; }
836
+ .row .project-picker { gap: 8px; }
837
+ .row .project-picker input { width: 100%; min-width: 0; }
838
+ .user-type-card--ide-default,
839
+ .user-type-card--compact {
840
+ padding: 18px 16px;
841
+ }
842
+ }
@@ -518,6 +518,6 @@ function selectSlot(el, num) {
518
518
  document.getElementById('inviteSent').textContent = '✓ Invite sent';
519
519
  }
520
520
  </script>
521
-
521
+
522
522
  </body>
523
523
  </html>
@@ -563,6 +563,6 @@ function toggleCard(num) {
563
563
  if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
564
564
  }
565
565
  </script>
566
-
566
+
567
567
  </body>
568
568
  </html>
@@ -485,6 +485,6 @@ function toggleCard(num) {
485
485
  if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
486
486
  }
487
487
  </script>
488
-
488
+
489
489
  </body>
490
490
  </html>
@@ -592,6 +592,6 @@ if (document.readyState !== 'loading') {
592
592
  renderSlide(0);
593
593
  }
594
594
  </script>
595
-
595
+
596
596
  </body>
597
597
  </html>
@@ -464,6 +464,6 @@ function toggleCard(num) {
464
464
  if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
465
465
  }
466
466
  </script>
467
-
467
+
468
468
  </body>
469
469
  </html>
@@ -513,6 +513,6 @@ function toggleCard(num) {
513
513
  if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
514
514
  }
515
515
  </script>
516
-
516
+
517
517
  </body>
518
518
  </html>
@@ -585,6 +585,6 @@ function toggleCard(num) {
585
585
  if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
586
586
  }
587
587
  </script>
588
-
588
+
589
589
  </body>
590
590
  </html>
@@ -434,7 +434,7 @@ body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--tex
434
434
  <div class="brand-logo">F</div>
435
435
  <span class="brand-name">FRAIM</span>
436
436
  </a>
437
- <div class="header-actions">
437
+ <div class="header-actions">
438
438
  <button class="theme-btn" onclick="toggleTheme()" title="Toggle dark mode">☾</button>
439
439
  </div>
440
440
  </header>
@@ -445,8 +445,8 @@ body { font-family: 'Inter', sans-serif; background: var(--bg); color: var(--tex
445
445
  </div>
446
446
  <div class="role-chip">AI Product Manager</div>
447
447
  <h1>Specs that ship,<br>not <span>slide decks</span></h1>
448
- <p>PaM turns vague ideas into traceable requirements, phased roadmaps, and acceptance criteria that engineers can execute on — without ambiguity, without meetings.</p>
449
- </section>
448
+ <p>PaM turns vague ideas into traceable requirements, phased roadmaps, and acceptance criteria that engineers can execute on — without ambiguity, without meetings.</p>
449
+ </section>
450
450
 
451
451
  <div class="section-label">
452
452
  <h2>Selected Work</h2>
@@ -792,8 +792,8 @@ await ceq.track(<span class="snippet-string">'purchase'</span>, { memberId, amou
792
792
 
793
793
  </div>
794
794
 
795
- <footer class="portfolio-footer">
796
- <div class="footer-sub">
795
+ <footer class="portfolio-footer">
796
+ <div class="footer-sub">
797
797
  Part of the <a href="/">FRAIM</a> · 18 AI employees available ·
798
798
  <a href="/">View all employees</a>
799
799
  </div>
@@ -882,6 +882,6 @@ function updateWizard() {
882
882
  // Init brand scale on load
883
883
  document.addEventListener('DOMContentLoaded', () => setBrand('#6366f1','#6366f1'));
884
884
  </script>
885
-
885
+
886
886
  </body>
887
887
  </html>
@@ -564,6 +564,6 @@ function toggleCard(num) {
564
564
  if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
565
565
  }
566
566
  </script>
567
-
567
+
568
568
  </body>
569
569
  </html>
@@ -555,6 +555,6 @@ function toggleCard(num) {
555
555
  if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
556
556
  }
557
557
  </script>
558
-
558
+
559
559
  </body>
560
560
  </html>
@@ -649,6 +649,6 @@ function toggleCard(num) {
649
649
  if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
650
650
  }
651
651
  </script>
652
-
652
+
653
653
  </body>
654
654
  </html>
@@ -245,7 +245,7 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
245
245
  <div class="brand-logo">F</div>
246
246
  <span class="brand-name">FRAIM</span>
247
247
  </a>
248
- <div class="header-actions">
248
+ <div class="header-actions">
249
249
  <button class="theme-btn" onclick="toggleTheme()" title="Toggle dark mode">☾</button>
250
250
  </div>
251
251
  </header>
@@ -256,8 +256,8 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
256
256
  </div>
257
257
  <div class="role-chip">AI Software Engineer</div>
258
258
  <h1>Ships clean code,<br>not <span>promises</span></h1>
259
- <p>SWEn delivers production-ready implementations: type-safe APIs, test coverage, real artifacts in the codebase — not prototype code masquerading as ship-ready work.</p>
260
- </section>
259
+ <p>SWEn delivers production-ready implementations: type-safe APIs, test coverage, real artifacts in the codebase — not prototype code masquerading as ship-ready work.</p>
260
+ </section>
261
261
 
262
262
  <div class="section-label">
263
263
  <h2>Selected Work</h2>
@@ -571,8 +571,8 @@ code, pre, .mono { font-family: 'JetBrains Mono', 'Fira Code', monospace; }
571
571
 
572
572
  </div>
573
573
 
574
- <footer class="portfolio-footer">
575
- <div class="footer-sub">
574
+ <footer class="portfolio-footer">
575
+ <div class="footer-sub">
576
576
  Part of the <a href="/">FRAIM</a> · 18 AI employees available ·
577
577
  <a href="/">View all employees</a>
578
578
  </div>
@@ -596,6 +596,6 @@ function toggleCard(num) {
596
596
  if (!isOpen) { card.classList.add('open'); card.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
597
597
  }
598
598
  </script>
599
-
599
+
600
600
  </body>
601
601
  </html>
@@ -1,95 +0,0 @@
1
- "use strict";
2
- /**
3
- * Sideloads the Word add-in manifest so it appears in Word's Developer Add-ins
4
- * list without admin rights or AppSource publishing.
5
- *
6
- * Windows: writes a registry value under HKCU\SOFTWARE\Microsoft\Office\16.0\WEF\Developer
7
- * macOS: writes an entry to ~/Library/Containers/com.microsoft.Word/Data/Documents/wef/
8
- *
9
- * Both paths are non-admin and survive app updates (keyed by manifest GUID).
10
- * Safe to call multiple times — checks before writing.
11
- */
12
- var __importDefault = (this && this.__importDefault) || function (mod) {
13
- return (mod && mod.__esModule) ? mod : { "default": mod };
14
- };
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.isSideloaded = isSideloaded;
17
- exports.sideloadManifest = sideloadManifest;
18
- exports.removeSideload = removeSideload;
19
- const fs_1 = __importDefault(require("fs"));
20
- const path_1 = __importDefault(require("path"));
21
- const os_1 = __importDefault(require("os"));
22
- const child_process_1 = require("child_process");
23
- const MANIFEST_GUID = 'd1090951-50cf-4cf2-9d12-b0f8541d265c';
24
- function resolveManifestPath(projectPath) {
25
- const candidates = [
26
- path_1.default.resolve(projectPath, 'extensions/office-word/manifest.xml'),
27
- path_1.default.resolve(__dirname, '..', '..', 'extensions/office-word/manifest.xml'),
28
- path_1.default.resolve(__dirname, '..', '..', '..', 'extensions/office-word/manifest.xml'),
29
- ];
30
- return candidates.find(c => fs_1.default.existsSync(c)) ?? null;
31
- }
32
- function isSideloaded() {
33
- if (process.platform === 'win32') {
34
- const result = (0, child_process_1.spawnSync)('reg', [
35
- 'query',
36
- `HKCU\\SOFTWARE\\Microsoft\\Office\\16.0\\WEF\\Developer`,
37
- '/v', MANIFEST_GUID,
38
- ], { encoding: 'utf8' });
39
- return result.status === 0 && result.stdout.includes(MANIFEST_GUID);
40
- }
41
- if (process.platform === 'darwin') {
42
- const wefDir = path_1.default.join(os_1.default.homedir(), 'Library', 'Containers', 'com.microsoft.Word', 'Data', 'Documents', 'wef');
43
- return fs_1.default.existsSync(path_1.default.join(wefDir, `${MANIFEST_GUID}.xml`));
44
- }
45
- return false;
46
- }
47
- function sideloadManifest(projectPath) {
48
- const manifestPath = resolveManifestPath(projectPath);
49
- if (!manifestPath) {
50
- return { ok: false, reason: 'Manifest file not found — is extensions/office-word/ present?' };
51
- }
52
- if (process.platform === 'win32') {
53
- const result = (0, child_process_1.spawnSync)('reg', [
54
- 'add',
55
- `HKCU\\SOFTWARE\\Microsoft\\Office\\16.0\\WEF\\Developer`,
56
- '/v', MANIFEST_GUID,
57
- '/t', 'REG_SZ',
58
- '/d', manifestPath,
59
- '/f',
60
- ], { encoding: 'utf8' });
61
- if (result.status !== 0) {
62
- return { ok: false, reason: result.stderr || 'reg add failed' };
63
- }
64
- return { ok: true };
65
- }
66
- if (process.platform === 'darwin') {
67
- const wefDir = path_1.default.join(os_1.default.homedir(), 'Library', 'Containers', 'com.microsoft.Word', 'Data', 'Documents', 'wef');
68
- try {
69
- fs_1.default.mkdirSync(wefDir, { recursive: true });
70
- fs_1.default.copyFileSync(manifestPath, path_1.default.join(wefDir, `${MANIFEST_GUID}.xml`));
71
- return { ok: true };
72
- }
73
- catch (err) {
74
- return { ok: false, reason: String(err) };
75
- }
76
- }
77
- return { ok: false, reason: `Unsupported platform: ${process.platform}` };
78
- }
79
- function removeSideload() {
80
- if (process.platform === 'win32') {
81
- (0, child_process_1.spawnSync)('reg', [
82
- 'delete',
83
- `HKCU\\SOFTWARE\\Microsoft\\Office\\16.0\\WEF\\Developer`,
84
- '/v', MANIFEST_GUID,
85
- '/f',
86
- ], { encoding: 'utf8' });
87
- return;
88
- }
89
- if (process.platform === 'darwin') {
90
- const wefDir = path_1.default.join(os_1.default.homedir(), 'Library', 'Containers', 'com.microsoft.Word', 'Data', 'Documents', 'wef');
91
- const target = path_1.default.join(wefDir, `${MANIFEST_GUID}.xml`);
92
- if (fs_1.default.existsSync(target))
93
- fs_1.default.unlinkSync(target);
94
- }
95
- }