fraim 2.0.162 → 2.0.164
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/src/ai-hub/desktop-main.js +4 -1
- package/dist/src/ai-hub/hosts.js +97 -12
- package/dist/src/ai-hub/preferences.js +1 -1
- package/dist/src/ai-hub/server.js +49 -123
- package/dist/src/cli/commands/init-project.js +15 -14
- package/dist/src/cli/commands/sync.js +38 -0
- package/dist/src/cli/doctor/check-runner.js +3 -1
- package/dist/src/cli/doctor/checks/mcp-connectivity-checks.js +261 -2
- package/dist/src/cli/utils/git-org-sync.js +56 -0
- package/dist/src/cli/utils/org-migration.js +50 -0
- package/dist/src/cli/utils/org-pack-sync.js +208 -0
- package/dist/src/cli/utils/project-bootstrap.js +20 -7
- package/dist/src/cli/utils/user-config.js +68 -0
- package/dist/src/core/fraim-config-schema.generated.js +10 -0
- package/dist/src/first-run/types.js +8 -0
- package/dist/src/local-mcp-server/agent-token-prices.js +30 -0
- package/dist/src/local-mcp-server/learning-context-builder.js +78 -29
- package/dist/src/local-mcp-server/stdio-server.js +30 -0
- package/index.js +1 -1
- package/package.json +2 -3
- package/public/ai-hub/index.html +5 -5
- package/public/ai-hub/powerpoint-taskpane/index.html +236 -236
- package/public/ai-hub/powerpoint-taskpane/manifest.xml +29 -29
- package/public/ai-hub/review.css +15 -15
- package/public/ai-hub/script.js +254 -195
- package/public/ai-hub/styles.css +206 -16
- package/public/first-run/styles.css +73 -73
- package/dist/src/ai-hub/word-sideload.js +0 -95
- package/dist/src/cli/commands/test-mcp.js +0 -171
- package/dist/src/cli/setup/first-run.js +0 -242
- package/dist/src/core/config-writer.js +0 -75
- package/dist/src/core/utils/job-aliases.js +0 -47
- package/dist/src/core/utils/workflow-parser.js +0 -174
package/public/ai-hub/styles.css
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
:root {
|
|
2
2
|
color-scheme: light dark;
|
|
3
|
+
/* #ai-hub-polish: allow block-size:auto to animate (accordion open/close). */
|
|
4
|
+
interpolate-size: allow-keywords;
|
|
3
5
|
/* Light theme — Apple-style near-white */
|
|
4
6
|
--bg: #f5f5f7;
|
|
5
7
|
--surface: #ffffff;
|
|
@@ -495,6 +497,19 @@ img.conv-employee-avatar {
|
|
|
495
497
|
background: var(--accent-soft);
|
|
496
498
|
border-color: rgba(0,113,227,.28);
|
|
497
499
|
}
|
|
500
|
+
/* Issue #550: Watercooler Conversations group modifier */
|
|
501
|
+
/* R4: dashed avatar placeholder — no image or persona initials */
|
|
502
|
+
.conv-employee-avatar--adhoc {
|
|
503
|
+
border-style: dashed;
|
|
504
|
+
border-color: var(--muted);
|
|
505
|
+
background: transparent;
|
|
506
|
+
color: transparent;
|
|
507
|
+
}
|
|
508
|
+
/* R5: muted label color for the Watercooler group header */
|
|
509
|
+
.conv-employee-group--adhoc .conv-employee-tab-label {
|
|
510
|
+
color: var(--muted);
|
|
511
|
+
font-weight: 600;
|
|
512
|
+
}
|
|
498
513
|
.conv-employee-list {
|
|
499
514
|
display: grid;
|
|
500
515
|
gap: 8px;
|
|
@@ -588,6 +603,8 @@ img.conv-employee-avatar {
|
|
|
588
603
|
.conv-status.working { color: var(--state-working); }
|
|
589
604
|
.conv-status.waiting { color: var(--state-waiting); }
|
|
590
605
|
.conv-status.complete { color: var(--state-complete); }
|
|
606
|
+
/* #549 R4: Amber label for manager-stopped runs in the conversation rail. */
|
|
607
|
+
.conv-status.stopped { color: var(--warn); }
|
|
591
608
|
.state-dot {
|
|
592
609
|
display: inline-block;
|
|
593
610
|
width: 8px;
|
|
@@ -765,6 +782,11 @@ img.conv-employee-avatar {
|
|
|
765
782
|
background: color-mix(in srgb, var(--done) 14%, transparent);
|
|
766
783
|
color: var(--done);
|
|
767
784
|
}
|
|
785
|
+
/* #549 R3: Amber STOPPED pill — intentional pause, distinct from red WAITING ON YOU. */
|
|
786
|
+
.run-state-pill.stopped {
|
|
787
|
+
background: color-mix(in srgb, var(--warn) 15%, transparent);
|
|
788
|
+
color: var(--warn);
|
|
789
|
+
}
|
|
768
790
|
.run-state-pill.approved {
|
|
769
791
|
background: color-mix(in srgb, #2e7d32 18%, transparent);
|
|
770
792
|
color: #2e7d32;
|
|
@@ -835,6 +857,11 @@ img.conv-employee-avatar {
|
|
|
835
857
|
flex-shrink: 0;
|
|
836
858
|
}
|
|
837
859
|
.panel-details[open] > summary::before { transform: rotate(90deg); }
|
|
860
|
+
.panel-details:not([open]) > .panel-body,
|
|
861
|
+
.panel-details:not([open]) > .messages,
|
|
862
|
+
.panel-details:not([open]) > .micro-log {
|
|
863
|
+
display: none;
|
|
864
|
+
}
|
|
838
865
|
.panel-summary-copy {
|
|
839
866
|
display: flex;
|
|
840
867
|
flex-direction: column;
|
|
@@ -1170,6 +1197,16 @@ img.coach-employee-avatar { object-fit: cover; border-radius: 4px; }
|
|
|
1170
1197
|
}
|
|
1171
1198
|
.typing-dot:nth-child(2) { animation-delay: 120ms; }
|
|
1172
1199
|
.typing-dot:nth-child(3) { animation-delay: 240ms; }
|
|
1200
|
+
/* #549 R1: Static dash shown in the working-indicator bubble while stop is in-flight.
|
|
1201
|
+
Replaces the animated typing-dots to signal "stopping in progress, please wait". */
|
|
1202
|
+
.stopping-dash {
|
|
1203
|
+
display: inline-flex;
|
|
1204
|
+
align-items: center;
|
|
1205
|
+
justify-content: center;
|
|
1206
|
+
font-size: 14px;
|
|
1207
|
+
color: var(--muted);
|
|
1208
|
+
line-height: 1;
|
|
1209
|
+
}
|
|
1173
1210
|
@keyframes typing-bounce {
|
|
1174
1211
|
0%, 80%, 100% { opacity: 0.35; transform: translateY(0); }
|
|
1175
1212
|
40% { opacity: 0.9; transform: translateY(-3px); }
|
|
@@ -1284,13 +1321,18 @@ img.coach-employee-avatar { object-fit: cover; border-radius: 4px; }
|
|
|
1284
1321
|
|
|
1285
1322
|
.micro {
|
|
1286
1323
|
margin-top: 0;
|
|
1324
|
+
border-color: color-mix(in srgb, var(--accent) 38%, var(--line));
|
|
1325
|
+
background: color-mix(in srgb, var(--accent-soft) 48%, var(--soft));
|
|
1287
1326
|
/* Removed: position:sticky / bottom:0 / z-index:2 — sticky caused the
|
|
1288
1327
|
micro-manage label to float over the coach section in the flex column.
|
|
1289
1328
|
It's now a normal flow element at the bottom of the support-stack. */
|
|
1290
1329
|
}
|
|
1330
|
+
.micro .panel-kicker {
|
|
1331
|
+
color: var(--accent-strong);
|
|
1332
|
+
}
|
|
1291
1333
|
.micro summary {
|
|
1292
1334
|
cursor: pointer;
|
|
1293
|
-
color: var(--
|
|
1335
|
+
color: var(--text);
|
|
1294
1336
|
font-size: 14px;
|
|
1295
1337
|
list-style: none;
|
|
1296
1338
|
display: flex;
|
|
@@ -2374,7 +2416,7 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
|
|
|
2374
2416
|
.syn-row { display: flex; align-items: flex-start; gap: 14px; padding: 12px 18px; border-bottom: 1px solid var(--line); }
|
|
2375
2417
|
.syn-row:last-child { border-bottom: none; }
|
|
2376
2418
|
.syn-label { font-size: 12px; font-weight: 600; color: var(--muted); width: 90px; flex-shrink: 0; padding-top: 1px; }
|
|
2377
|
-
.syn-val { flex: 1; font-size: 13px; color: var(--text); line-height: 1.5; }
|
|
2419
|
+
.syn-val { flex: 1; min-width: 0; overflow-wrap: break-word; font-size: 13px; color: var(--text); line-height: 1.5; }
|
|
2378
2420
|
.syn-edit { font-size: 12px; color: var(--accent); font-weight: 500; background: none; border: none; cursor: pointer; flex-shrink: 0; }
|
|
2379
2421
|
|
|
2380
2422
|
/* Learnings */
|
|
@@ -2437,7 +2479,22 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
|
|
|
2437
2479
|
.ctx-acc > summary .ca-chev { font-size: 10px; color: var(--muted); transition: transform .15s; }
|
|
2438
2480
|
.ctx-acc[open] > summary .ca-chev { transform: rotate(90deg); }
|
|
2439
2481
|
.ctx-acc > summary .ca-note { font-weight: 400; text-transform: none; letter-spacing: 0; font-size: 11px; color: var(--muted); }
|
|
2440
|
-
|
|
2482
|
+
/* #ai-hub-polish F2: a long section must not bury the others. Cap the body and
|
|
2483
|
+
let it scroll internally so every accordion header stays reachable. */
|
|
2484
|
+
.ctx-acc-body { padding: 4px 14px 14px; max-height: min(62vh, 620px); overflow-y: auto; }
|
|
2485
|
+
|
|
2486
|
+
/* #ai-hub-polish F1: ease the open/close instead of snapping. Animate the
|
|
2487
|
+
<details> content slot; interpolate-size lets block-size animate to/from auto.
|
|
2488
|
+
@supports keeps older engines on the instant (pre-polish) behavior, and the
|
|
2489
|
+
prefers-reduced-motion block above neutralizes the transition. */
|
|
2490
|
+
@supports selector(::details-content) {
|
|
2491
|
+
.ctx-acc::details-content {
|
|
2492
|
+
block-size: 0;
|
|
2493
|
+
overflow: clip;
|
|
2494
|
+
transition: block-size .24s ease, content-visibility .24s allow-discrete;
|
|
2495
|
+
}
|
|
2496
|
+
.ctx-acc[open]::details-content { block-size: auto; }
|
|
2497
|
+
}
|
|
2441
2498
|
|
|
2442
2499
|
/* #521: project-onboarding loop banner inside the Brief — "team is processing /
|
|
2443
2500
|
here's their understanding to review". */
|
|
@@ -2582,6 +2639,9 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
|
|
|
2582
2639
|
.dot-amber { background: var(--state-working) !important; }
|
|
2583
2640
|
.dot-green { background: var(--state-complete) !important; }
|
|
2584
2641
|
.dot-grey { background: var(--line) !important; }
|
|
2642
|
+
/* #549 R4: amber-static — same amber colour as dot-amber but no pulse animation.
|
|
2643
|
+
Used for manager-stopped runs to distinguish intentional pause from active work. */
|
|
2644
|
+
.dot-amber-static { background: var(--warn) !important; }
|
|
2585
2645
|
|
|
2586
2646
|
/* Workspace conversation pane */
|
|
2587
2647
|
.workspace-conv { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: var(--bg); }
|
|
@@ -2606,26 +2666,115 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
|
|
|
2606
2666
|
padding: 16px 18px;
|
|
2607
2667
|
}
|
|
2608
2668
|
|
|
2609
|
-
/* Conversation view (full height):
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2669
|
+
/* Conversation view (full height): the open panels SHARE the available real
|
|
2670
|
+
estate instead of being pinned to fixed caps. Each open panel grows to fill its
|
|
2671
|
+
slice and scrolls internally when its content overflows (its own scrollbar).
|
|
2672
|
+
#active-conv keeps overflow-y:auto only as a fallback for very short windows
|
|
2673
|
+
where the panels' min-heights can't all fit. */
|
|
2613
2674
|
.workspace-conv #active-conv {
|
|
2675
|
+
overflow-y: auto;
|
|
2676
|
+
display: flex;
|
|
2677
|
+
flex-direction: column;
|
|
2678
|
+
gap: 8px;
|
|
2679
|
+
min-height: 0;
|
|
2680
|
+
}
|
|
2681
|
+
.workspace-conv #active-conv > .conv-topline,
|
|
2682
|
+
.workspace-conv #active-conv > .conversation-status { flex: 0 0 auto; }
|
|
2683
|
+
|
|
2684
|
+
/* Manager/employee thread — the primary conversation. The "Ready for review"
|
|
2685
|
+
card lives inside #messages, so it scrolls with the thread. Open thread grows
|
|
2686
|
+
to fill spare height; collapsed it is just its summary bar. */
|
|
2687
|
+
.workspace-conv #thread-panel { flex: 0 0 auto; min-height: 0; }
|
|
2688
|
+
/* Open thread is the sole space-filler: it grows to take all height the support
|
|
2689
|
+
stack does not need, and scrolls #messages internally. Collapsed it is just
|
|
2690
|
+
its summary bar. */
|
|
2691
|
+
.workspace-conv #thread-panel[open] {
|
|
2692
|
+
flex: 1 1 0;
|
|
2693
|
+
display: flex;
|
|
2694
|
+
flex-direction: column;
|
|
2695
|
+
min-height: 120px;
|
|
2696
|
+
}
|
|
2697
|
+
.workspace-conv #thread-panel > summary { flex: 0 0 auto; }
|
|
2698
|
+
/* Chromium wraps <details> content in a ::details-content slot, so #messages is
|
|
2699
|
+
not a direct flex child of the panel. Make the slot a column flex container
|
|
2700
|
+
that fills the panel; then #messages can flex-grow and scroll inside it. */
|
|
2701
|
+
.workspace-conv #thread-panel[open]::details-content {
|
|
2702
|
+
flex: 1 1 0;
|
|
2703
|
+
min-height: 0;
|
|
2704
|
+
display: flex;
|
|
2705
|
+
flex-direction: column;
|
|
2614
2706
|
overflow: hidden;
|
|
2615
|
-
display: grid;
|
|
2616
|
-
grid-template-rows: auto auto minmax(200px, 1fr) auto;
|
|
2617
2707
|
}
|
|
2618
|
-
.workspace-conv #thread-panel[open] {
|
|
2619
|
-
|
|
2620
|
-
|
|
2708
|
+
.workspace-conv #thread-panel[open] #messages {
|
|
2709
|
+
flex: 1 1 0;
|
|
2710
|
+
min-height: 0;
|
|
2711
|
+
max-height: none;
|
|
2712
|
+
overflow-y: auto;
|
|
2713
|
+
}
|
|
2714
|
+
.workspace-conv #thread-panel:not([open]) #messages { display: none; }
|
|
2715
|
+
|
|
2716
|
+
/* Support stack: Coach (input) + Micro-manage (log). It sizes to its content and
|
|
2717
|
+
never grows past it, so the thread keeps the spare real estate. Each open body
|
|
2718
|
+
has a viewport-relative cap and scrolls internally, so it shows more on bigger
|
|
2719
|
+
screens (and far more than the old 1-line peek) without crowding the thread. */
|
|
2621
2720
|
.workspace-conv .support-stack {
|
|
2622
|
-
display:
|
|
2721
|
+
display: flex;
|
|
2722
|
+
flex-direction: column;
|
|
2723
|
+
gap: 8px;
|
|
2623
2724
|
min-height: 0;
|
|
2624
|
-
|
|
2725
|
+
flex: 0 1 auto;
|
|
2726
|
+
}
|
|
2727
|
+
.workspace-conv .support-stack > .panel-details--coach { flex: 0 0 auto; }
|
|
2728
|
+
.workspace-conv .support-stack > .panel-details--coach[open] > .panel-body {
|
|
2729
|
+
max-height: clamp(140px, 24vh, 260px);
|
|
2730
|
+
overflow-y: auto;
|
|
2731
|
+
}
|
|
2732
|
+
.workspace-conv .panel-details--coach .panel-body { padding-bottom: 8px; }
|
|
2733
|
+
.workspace-conv .coach-input textarea {
|
|
2734
|
+
min-height: 44px;
|
|
2735
|
+
padding-top: 9px;
|
|
2736
|
+
padding-bottom: 9px;
|
|
2737
|
+
}
|
|
2738
|
+
.workspace-conv .coach-note { display: none; }
|
|
2739
|
+
.workspace-conv .quick-coach-row { gap: 5px; margin-bottom: 8px; }
|
|
2740
|
+
.workspace-conv .quick-coach-btn { padding: 4px 9px; }
|
|
2741
|
+
|
|
2742
|
+
.workspace-conv .support-stack > .micro { flex: 0 0 auto; min-height: 0; }
|
|
2743
|
+
.workspace-conv .support-stack > .micro[open] > .micro-log {
|
|
2744
|
+
max-height: clamp(120px, 24vh, 260px);
|
|
2625
2745
|
overflow-y: auto;
|
|
2626
2746
|
}
|
|
2627
2747
|
.workspace-conv .support-stack > .panel-details,
|
|
2628
|
-
.workspace-conv .support-stack > .micro { margin-bottom:
|
|
2748
|
+
.workspace-conv .support-stack > .micro { margin-bottom: 0; }
|
|
2749
|
+
|
|
2750
|
+
@media (max-width: 820px) {
|
|
2751
|
+
/* On narrow screens drop the fill model: panels flow naturally and the page
|
|
2752
|
+
scrolls, with each open body keeping a viewport-relative scroll cap. */
|
|
2753
|
+
.workspace-conv #active-conv {
|
|
2754
|
+
display: flex;
|
|
2755
|
+
flex-direction: column;
|
|
2756
|
+
overflow: visible;
|
|
2757
|
+
}
|
|
2758
|
+
.workspace-conv #thread-panel[open],
|
|
2759
|
+
.workspace-conv .support-stack,
|
|
2760
|
+
.workspace-conv .support-stack:has(.micro[open]),
|
|
2761
|
+
.workspace-conv .support-stack > .micro[open] {
|
|
2762
|
+
flex: 0 0 auto;
|
|
2763
|
+
display: block;
|
|
2764
|
+
min-height: 0;
|
|
2765
|
+
}
|
|
2766
|
+
.workspace-conv #thread-panel[open] #messages,
|
|
2767
|
+
.workspace-conv .support-stack > .micro[open] > .micro-log {
|
|
2768
|
+
flex: initial;
|
|
2769
|
+
height: auto;
|
|
2770
|
+
max-height: clamp(140px, 32vh, 280px);
|
|
2771
|
+
overflow-y: auto;
|
|
2772
|
+
}
|
|
2773
|
+
.workspace-conv .support-stack > .panel-details[open] > .panel-body {
|
|
2774
|
+
max-height: clamp(140px, 32vh, 280px);
|
|
2775
|
+
overflow-y: auto;
|
|
2776
|
+
}
|
|
2777
|
+
}
|
|
2629
2778
|
|
|
2630
2779
|
@media (max-width: 640px) {
|
|
2631
2780
|
body.hub-shell { overflow-x: hidden; }
|
|
@@ -2852,6 +3001,39 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
|
|
|
2852
3001
|
.workspace-conv > .page { overflow: hidden; }
|
|
2853
3002
|
.workspace-conv .layout { display: flex; gap: 0; min-height: 0; flex: 1; overflow: hidden; }
|
|
2854
3003
|
|
|
3004
|
+
@media (max-width: 820px) {
|
|
3005
|
+
body.hub-shell {
|
|
3006
|
+
height: auto;
|
|
3007
|
+
min-height: 100vh;
|
|
3008
|
+
overflow: auto;
|
|
3009
|
+
}
|
|
3010
|
+
.hub-area,
|
|
3011
|
+
.area-main,
|
|
3012
|
+
#proj-workspace,
|
|
3013
|
+
.workspace-conv,
|
|
3014
|
+
.workspace-conv > .page,
|
|
3015
|
+
.workspace-conv .layout {
|
|
3016
|
+
overflow: visible;
|
|
3017
|
+
}
|
|
3018
|
+
}
|
|
3019
|
+
|
|
3020
|
+
/* #ai-hub-polish F3: Company & Manager areas had no narrow-width layout — the
|
|
3021
|
+
fixed 244px rail pushed the main column off the right edge (horizontal scroll).
|
|
3022
|
+
Below the Projects-workspace breakpoint, stack the rail above the content and
|
|
3023
|
+
let the page shrink so nothing overflows. 2-column stays intact on tablets. */
|
|
3024
|
+
@media (max-width: 640px) {
|
|
3025
|
+
body.hub-shell { overflow-x: hidden; }
|
|
3026
|
+
.area-shell { flex-direction: column; }
|
|
3027
|
+
.area-rail {
|
|
3028
|
+
width: 100%;
|
|
3029
|
+
flex-shrink: 0;
|
|
3030
|
+
max-height: 200px;
|
|
3031
|
+
border-right: none;
|
|
3032
|
+
border-bottom: 1px solid var(--line);
|
|
3033
|
+
}
|
|
3034
|
+
.hub-area-page { padding: 22px 16px 40px; min-width: 0; max-width: 100%; }
|
|
3035
|
+
}
|
|
3036
|
+
|
|
2855
3037
|
|
|
2856
3038
|
/* ── #512 Round 2: actual class names from rendered HTML ────────────────── */
|
|
2857
3039
|
|
|
@@ -2866,8 +3048,16 @@ body.hub-shell { display: flex; flex-direction: column; height: 100vh; overflow:
|
|
|
2866
3048
|
.syn-row { display: flex; align-items: flex-start; gap: 14px; padding: 13px 18px; border-bottom: 1px solid var(--line); }
|
|
2867
3049
|
.syn-row:last-child { border-bottom: none; }
|
|
2868
3050
|
.syn-label { font-size: 12px; font-weight: 600; color: var(--muted); width: 88px; flex-shrink: 0; padding-top: 2px; }
|
|
2869
|
-
.syn-val { flex: 1; font-size: 13px; color: var(--text); line-height: 1.5; }
|
|
3051
|
+
.syn-val { flex: 1; min-width: 0; overflow-wrap: break-word; font-size: 13px; color: var(--text); line-height: 1.5; }
|
|
2870
3052
|
.syn-edit { font-size: 12px; color: var(--accent); font-weight: 500; background: none; border: none; cursor: pointer; flex-shrink: 0; }
|
|
3053
|
+
/* #ai-hub-polish: at phone widths the fixed label column starves the value and
|
|
3054
|
+
forces mid-word wraps. Stack label over value so the value gets full width.
|
|
3055
|
+
Placed after the duplicate .syn-* block above so source order lets it win. */
|
|
3056
|
+
@media (max-width: 560px) {
|
|
3057
|
+
.syn-row { flex-wrap: wrap; gap: 4px 12px; }
|
|
3058
|
+
.syn-label { width: 100%; }
|
|
3059
|
+
.syn-val { flex: 1 1 100%; }
|
|
3060
|
+
}
|
|
2871
3061
|
|
|
2872
3062
|
/* Issue #512 R3/R8 — Team Context inline editor. */
|
|
2873
3063
|
/* ctx-content is now a div with rendered markdown (formatEmployeeText), not a raw <pre> */
|
|
@@ -421,14 +421,14 @@ 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
|
+
.recruit-container,
|
|
425
|
+
.start-container {
|
|
426
|
+
gap: 12px;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.start-container {
|
|
430
|
+
gap: 14px;
|
|
431
|
+
}
|
|
432
432
|
|
|
433
433
|
.user-type-card {
|
|
434
434
|
background: var(--surface);
|
|
@@ -448,23 +448,23 @@ body {
|
|
|
448
448
|
border-color: var(--accent);
|
|
449
449
|
background: var(--accent-soft);
|
|
450
450
|
}
|
|
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
|
-
}
|
|
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
|
+
}
|
|
468
468
|
|
|
469
469
|
.card-header {
|
|
470
470
|
display: flex;
|
|
@@ -492,38 +492,38 @@ body {
|
|
|
492
492
|
border-color: var(--accent);
|
|
493
493
|
}
|
|
494
494
|
|
|
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
|
-
}
|
|
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
|
+
}
|
|
527
527
|
|
|
528
528
|
.btn {
|
|
529
529
|
display: inline-flex;
|
|
@@ -572,9 +572,9 @@ body {
|
|
|
572
572
|
border-color: var(--line);
|
|
573
573
|
}
|
|
574
574
|
|
|
575
|
-
/* IDE command display — shown after choosing "In my IDE". */
|
|
576
|
-
.cmd-block {
|
|
577
|
-
background: #0d1410;
|
|
575
|
+
/* IDE command display — shown after choosing "In my IDE". */
|
|
576
|
+
.cmd-block {
|
|
577
|
+
background: #0d1410;
|
|
578
578
|
color: #c8d3cd;
|
|
579
579
|
font-family: "JetBrains Mono", "Cascadia Code", Consolas, monospace;
|
|
580
580
|
font-size: 14px;
|
|
@@ -612,16 +612,16 @@ body {
|
|
|
612
612
|
* want the surface to degrade gracefully for users who happen to open it
|
|
613
613
|
* in a narrow window. Stack the label / verb / change link vertically and
|
|
614
614
|
* 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
|
-
}
|
|
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
|
+
}
|
|
@@ -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
|
-
}
|