@wrongstack/tui 0.296.2 → 0.296.4
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/app-action-type.d.ts +6 -5
- package/dist/app-action-type.d.ts.map +1 -1
- package/dist/app-initial-state.d.ts +1 -1
- package/dist/app-initial-state.d.ts.map +1 -1
- package/dist/app-settings-type.d.ts +2 -0
- package/dist/app-settings-type.d.ts.map +1 -1
- package/dist/app-state.d.ts +6 -4
- package/dist/app-state.d.ts.map +1 -1
- package/dist/app-view.d.ts.map +1 -1
- package/dist/components/history/entry.d.ts.map +1 -1
- package/dist/components/history/sage-output-format.d.ts +38 -0
- package/dist/components/history/sage-output-format.d.ts.map +1 -1
- package/dist/components/history/tool-group.d.ts.map +1 -1
- package/dist/components/history/utils.d.ts +4 -2
- package/dist/components/history/utils.d.ts.map +1 -1
- package/dist/components/refine-failure-panel.d.ts +2 -1
- package/dist/components/refine-failure-panel.d.ts.map +1 -1
- package/dist/components/settings-picker-model.d.ts +2 -1
- package/dist/components/settings-picker-model.d.ts.map +1 -1
- package/dist/components/settings-picker.d.ts +4 -2
- package/dist/components/settings-picker.d.ts.map +1 -1
- package/dist/connections-health.d.ts.map +1 -1
- package/dist/history-archive.d.ts +0 -1
- package/dist/history-archive.d.ts.map +1 -1
- package/dist/history-entry.d.ts +50 -0
- package/dist/history-entry.d.ts.map +1 -1
- package/dist/hooks/use-git-session-status.d.ts.map +1 -1
- package/dist/hooks/use-panel-controllers.d.ts +1 -1
- package/dist/hooks/use-panel-controllers.d.ts.map +1 -1
- package/dist/hooks/use-provider-event-bridge.d.ts.map +1 -1
- package/dist/hooks/use-settings-auto-save.d.ts +1 -1
- package/dist/hooks/use-settings-auto-save.d.ts.map +1 -1
- package/dist/hooks/use-statusbar-view-model.d.ts.map +1 -1
- package/dist/hooks/use-subagent-events.d.ts.map +1 -1
- package/dist/index.js +1520 -1069
- package/dist/index.js.map +4 -4
- package/dist/layout-engine.d.ts +4 -0
- package/dist/layout-engine.d.ts.map +1 -1
- package/dist/memory-context-monitor.d.ts +6 -0
- package/dist/memory-context-monitor.d.ts.map +1 -1
- package/dist/overlay-key-router.d.ts +1 -1
- package/dist/overlay-key-router.d.ts.map +1 -1
- package/dist/reducers/settings-panel.d.ts.map +1 -1
- package/dist/reducers/settings-values.d.ts.map +1 -1
- package/dist/settings-contracts.d.ts +5 -0
- package/dist/settings-contracts.d.ts.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -636,6 +636,7 @@ function applyMemoryInjectorRun(state, payload) {
|
|
|
636
636
|
kind: stringValue(item.kind) ?? "unknown",
|
|
637
637
|
text: capMemoryDetailText(stringValue(item.text) ?? ""),
|
|
638
638
|
score: numberValue(item.score),
|
|
639
|
+
relationStrength: numberValue(item.relationStrength),
|
|
639
640
|
confidence: numberValue(item.confidence),
|
|
640
641
|
freshness: numberValue(item.freshness),
|
|
641
642
|
importance: numberValue(item.importance),
|
|
@@ -731,6 +732,7 @@ function placeholder(id, at, state) {
|
|
|
731
732
|
kind: "unknown",
|
|
732
733
|
text: "Details unavailable in this TUI process.",
|
|
733
734
|
score: 0,
|
|
735
|
+
relationStrength: 0,
|
|
734
736
|
confidence: 0,
|
|
735
737
|
freshness: 0,
|
|
736
738
|
importance: 0,
|
|
@@ -3459,62 +3461,6 @@ function cyclePreset(presets, current, delta) {
|
|
|
3459
3461
|
return presets[next];
|
|
3460
3462
|
}
|
|
3461
3463
|
|
|
3462
|
-
// src/components/settings-picker-jumps.ts
|
|
3463
|
-
var SETTINGS_PICKER_JUMP_CHORDS = Object.freeze([
|
|
3464
|
-
{ mod: "ctrl", letter: "i", field: 20, label: "Index on session start" },
|
|
3465
|
-
{ mod: "ctrl", letter: "m", field: 21, label: "Multi-diff summary" },
|
|
3466
|
-
{ mod: "ctrl", letter: "w", field: 22, label: "Thinking word" },
|
|
3467
|
-
{ mod: "ctrl", letter: "r", field: 17, label: "Refine preview countdown" },
|
|
3468
|
-
{ mod: "ctrl", letter: "e", field: 18, label: "Refine" },
|
|
3469
|
-
{ mod: "ctrl", letter: "n", field: 23, label: "Reasoning mode" },
|
|
3470
|
-
{ mod: "ctrl", letter: "l", field: 30, label: "Max concurrent" },
|
|
3471
|
-
{ mod: "ctrl", letter: "d", field: 34, label: "Statusline" },
|
|
3472
|
-
{ mod: "alt", letter: "a", field: 0, label: "Default autonomy mode" },
|
|
3473
|
-
{ mod: "alt", letter: "y", field: 3, label: "YOLO mode" },
|
|
3474
|
-
{ mod: "alt", letter: "c", field: 5, label: "Completion chime" },
|
|
3475
|
-
{ mod: "alt", letter: "s", field: 6, label: "Confirm before exit" },
|
|
3476
|
-
{ mod: "alt", letter: "t", field: 13, label: "Token-saving mode" },
|
|
3477
|
-
{ mod: "alt", letter: "x", field: 29, label: "Context mode" },
|
|
3478
|
-
{ mod: "alt-shift", letter: "l", field: 31, label: "Log level" },
|
|
3479
|
-
{ mod: "alt-shift", letter: "a", field: 32, label: "Audit level" },
|
|
3480
|
-
{ mod: "alt-shift", letter: "b", field: 33, label: "Stream debug logging" },
|
|
3481
|
-
{ mod: "alt-shift", letter: "g", field: 35, label: "Config scope" },
|
|
3482
|
-
{ mod: "alt", letter: "n", field: 36, label: "Animation" },
|
|
3483
|
-
{ mod: "alt", letter: "p", field: 40, label: "Show agent swarm panel" },
|
|
3484
|
-
{ mod: "alt", letter: "r", field: 41, label: "Pre-refine countdown" }
|
|
3485
|
-
]);
|
|
3486
|
-
function settingsPickerJumpField(mod, letter) {
|
|
3487
|
-
const lower = letter.toLowerCase();
|
|
3488
|
-
const chord = SETTINGS_PICKER_JUMP_CHORDS.find((c) => c.mod === mod && c.letter === lower);
|
|
3489
|
-
return chord?.field;
|
|
3490
|
-
}
|
|
3491
|
-
function settingsPickerSlug(label) {
|
|
3492
|
-
return label.toLowerCase().replace(/\s+/g, "-");
|
|
3493
|
-
}
|
|
3494
|
-
function settingsPickerJumpByName(name) {
|
|
3495
|
-
const query = settingsPickerSlug(name);
|
|
3496
|
-
if (!query) return void 0;
|
|
3497
|
-
const exact = SETTINGS_PICKER_JUMP_CHORDS.find((c) => settingsPickerSlug(c.label) === query);
|
|
3498
|
-
if (exact) return exact.field;
|
|
3499
|
-
const queryTokens = query.split("-");
|
|
3500
|
-
for (const c of SETTINGS_PICKER_JUMP_CHORDS) {
|
|
3501
|
-
const labelTokens = settingsPickerSlug(c.label).split("-");
|
|
3502
|
-
if (queryTokens.every((t, i) => labelTokens[i] === t)) {
|
|
3503
|
-
return c.field;
|
|
3504
|
-
}
|
|
3505
|
-
}
|
|
3506
|
-
for (const c of SETTINGS_PICKER_JUMP_CHORDS) {
|
|
3507
|
-
const labelTokens = settingsPickerSlug(c.label).split("-");
|
|
3508
|
-
if (labelTokens.some((t) => t === query || t.startsWith(`${query}-`))) {
|
|
3509
|
-
return c.field;
|
|
3510
|
-
}
|
|
3511
|
-
}
|
|
3512
|
-
return void 0;
|
|
3513
|
-
}
|
|
3514
|
-
function settingsPickerJumpNames() {
|
|
3515
|
-
return SETTINGS_PICKER_JUMP_CHORDS.map((c) => settingsPickerSlug(c.label));
|
|
3516
|
-
}
|
|
3517
|
-
|
|
3518
3464
|
// src/components/settings-picker-filter.ts
|
|
3519
3465
|
function fuzzyMatch(haystack, needle) {
|
|
3520
3466
|
const lower = haystack.toLowerCase();
|
|
@@ -3614,75 +3560,60 @@ function buildSettingsFilterState(filter, chords) {
|
|
|
3614
3560
|
};
|
|
3615
3561
|
}
|
|
3616
3562
|
|
|
3617
|
-
// src/components/settings-picker-
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3563
|
+
// src/components/settings-picker-jumps.ts
|
|
3564
|
+
var SETTINGS_PICKER_JUMP_CHORDS = Object.freeze([
|
|
3565
|
+
{ mod: "ctrl", letter: "i", field: 20, label: "Index on session start" },
|
|
3566
|
+
{ mod: "ctrl", letter: "m", field: 21, label: "Multi-diff summary" },
|
|
3567
|
+
{ mod: "ctrl", letter: "w", field: 22, label: "Thinking word" },
|
|
3568
|
+
{ mod: "ctrl", letter: "r", field: 17, label: "Refine preview countdown" },
|
|
3569
|
+
{ mod: "ctrl", letter: "e", field: 18, label: "Refine" },
|
|
3570
|
+
{ mod: "ctrl", letter: "n", field: 23, label: "Reasoning mode" },
|
|
3571
|
+
{ mod: "ctrl", letter: "l", field: 30, label: "Max concurrent" },
|
|
3572
|
+
{ mod: "ctrl", letter: "d", field: 34, label: "Statusline" },
|
|
3573
|
+
{ mod: "alt", letter: "a", field: 0, label: "Default autonomy mode" },
|
|
3574
|
+
{ mod: "alt", letter: "y", field: 3, label: "YOLO mode" },
|
|
3575
|
+
{ mod: "alt", letter: "c", field: 5, label: "Completion chime" },
|
|
3576
|
+
{ mod: "alt", letter: "s", field: 6, label: "Confirm before exit" },
|
|
3577
|
+
{ mod: "alt", letter: "t", field: 13, label: "Token-saving mode" },
|
|
3578
|
+
{ mod: "alt", letter: "x", field: 29, label: "Context mode" },
|
|
3579
|
+
{ mod: "alt-shift", letter: "l", field: 31, label: "Log level" },
|
|
3580
|
+
{ mod: "alt-shift", letter: "a", field: 32, label: "Audit level" },
|
|
3581
|
+
{ mod: "alt-shift", letter: "b", field: 33, label: "Stream debug logging" },
|
|
3582
|
+
{ mod: "alt-shift", letter: "g", field: 35, label: "Config scope" },
|
|
3583
|
+
{ mod: "alt", letter: "n", field: 36, label: "Animation" },
|
|
3584
|
+
{ mod: "alt", letter: "p", field: 40, label: "Show agent swarm panel" },
|
|
3585
|
+
{ mod: "alt", letter: "r", field: 41, label: "Pre-refine countdown" }
|
|
3586
|
+
]);
|
|
3587
|
+
function settingsPickerJumpField(mod, letter) {
|
|
3588
|
+
const lower = letter.toLowerCase();
|
|
3589
|
+
const chord = SETTINGS_PICKER_JUMP_CHORDS.find((c) => c.mod === mod && c.letter === lower);
|
|
3590
|
+
return chord?.field;
|
|
3632
3591
|
}
|
|
3633
|
-
function
|
|
3634
|
-
|
|
3635
|
-
let curHeader = -1;
|
|
3636
|
-
for (let i = 0; i < rows.length; i++) {
|
|
3637
|
-
if (rows[i]?.section) curHeader = i;
|
|
3638
|
-
else if (curHeader >= 0) {
|
|
3639
|
-
const fieldIdx = fieldRowIndex.indexOf(i);
|
|
3640
|
-
if (fieldIdx === -1) continue;
|
|
3641
|
-
const entry = sectionFields.find((s2) => s2.headerIdx === curHeader);
|
|
3642
|
-
if (entry) {
|
|
3643
|
-
entry.fieldEnd = fieldIdx + 1;
|
|
3644
|
-
} else {
|
|
3645
|
-
sectionFields.push({ headerIdx: curHeader, fieldStart: fieldIdx, fieldEnd: fieldIdx + 1 });
|
|
3646
|
-
}
|
|
3647
|
-
}
|
|
3648
|
-
}
|
|
3649
|
-
return new Set(
|
|
3650
|
-
sectionFields.filter((section) => section.fieldStart < windowEnd && section.fieldEnd > windowStart).map((section) => section.headerIdx)
|
|
3651
|
-
);
|
|
3592
|
+
function settingsPickerSlug(label) {
|
|
3593
|
+
return label.toLowerCase().replace(/\s+/g, "-");
|
|
3652
3594
|
}
|
|
3653
|
-
function
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
return /* @__PURE__ */ jsx8(Fragment4, { children: rankedResults.map((result) => {
|
|
3665
|
-
const fieldIdx = result.chord.field;
|
|
3666
|
-
const rowIdx = fieldRowIndex[fieldIdx] ?? -1;
|
|
3667
|
-
const row = rows[rowIdx];
|
|
3668
|
-
if (!row?.label) return null;
|
|
3669
|
-
return renderPickerRow(row, fieldIdx, fieldIdx === field, true, highlightSegments);
|
|
3670
|
-
}) });
|
|
3595
|
+
function settingsPickerJumpByName(name) {
|
|
3596
|
+
const query = settingsPickerSlug(name);
|
|
3597
|
+
if (!query) return void 0;
|
|
3598
|
+
const exact = SETTINGS_PICKER_JUMP_CHORDS.find((c) => settingsPickerSlug(c.label) === query);
|
|
3599
|
+
if (exact) return exact.field;
|
|
3600
|
+
const queryTokens = query.split("-");
|
|
3601
|
+
for (const c of SETTINGS_PICKER_JUMP_CHORDS) {
|
|
3602
|
+
const labelTokens = settingsPickerSlug(c.label).split("-");
|
|
3603
|
+
if (queryTokens.every((t, i) => labelTokens[i] === t)) {
|
|
3604
|
+
return c.field;
|
|
3605
|
+
}
|
|
3671
3606
|
}
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
if (!visibleSections.has(i)) return null;
|
|
3677
|
-
return /* @__PURE__ */ jsxs7(Text, { bold: true, color: "green", children: [
|
|
3678
|
-
"\u2500\u2500 ",
|
|
3679
|
-
row.section,
|
|
3680
|
-
" \u2500\u2500"
|
|
3681
|
-
] }, `section-${row.section ?? i}`);
|
|
3607
|
+
for (const c of SETTINGS_PICKER_JUMP_CHORDS) {
|
|
3608
|
+
const labelTokens = settingsPickerSlug(c.label).split("-");
|
|
3609
|
+
if (labelTokens.some((t) => t === query || t.startsWith(`${query}-`))) {
|
|
3610
|
+
return c.field;
|
|
3682
3611
|
}
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3612
|
+
}
|
|
3613
|
+
return void 0;
|
|
3614
|
+
}
|
|
3615
|
+
function settingsPickerJumpNames() {
|
|
3616
|
+
return SETTINGS_PICKER_JUMP_CHORDS.map((c) => settingsPickerSlug(c.label));
|
|
3686
3617
|
}
|
|
3687
3618
|
|
|
3688
3619
|
// src/components/settings-picker-model.ts
|
|
@@ -3699,7 +3630,15 @@ var CONTEXT_MODE_DESCS = {
|
|
|
3699
3630
|
};
|
|
3700
3631
|
var STATUSLINE_MODES = ["minimum", "detailed", "no-color"];
|
|
3701
3632
|
var REASONING_MODES = ["auto", "on", "off"];
|
|
3702
|
-
var REASONING_EFFORTS = [
|
|
3633
|
+
var REASONING_EFFORTS = [
|
|
3634
|
+
"none",
|
|
3635
|
+
"minimal",
|
|
3636
|
+
"low",
|
|
3637
|
+
"medium",
|
|
3638
|
+
"high",
|
|
3639
|
+
"xhigh",
|
|
3640
|
+
"max"
|
|
3641
|
+
];
|
|
3703
3642
|
var CACHE_TTLS = ["default", "5m", "1h"];
|
|
3704
3643
|
var STATUSLINE_MODE_DESCS = {
|
|
3705
3644
|
minimum: "Single line with essential chips only",
|
|
@@ -3718,7 +3657,14 @@ function formatBreakerTimeout(ms) {
|
|
|
3718
3657
|
}
|
|
3719
3658
|
var MULTI_DIFF_SUMMARY_THRESHOLD_PRESETS = [3, 5, 8, 10, 15, 0];
|
|
3720
3659
|
var ENHANCE_LANGUAGES = ["original", "english"];
|
|
3721
|
-
var TOKEN_SAVING_TIERS = [
|
|
3660
|
+
var TOKEN_SAVING_TIERS = [
|
|
3661
|
+
"auto",
|
|
3662
|
+
"off",
|
|
3663
|
+
"minimal",
|
|
3664
|
+
"light",
|
|
3665
|
+
"medium",
|
|
3666
|
+
"aggressive"
|
|
3667
|
+
];
|
|
3722
3668
|
var TOKEN_SAVING_TIER_DESCS = {
|
|
3723
3669
|
auto: "By window \u2014 full tools, lean prompt on small models (cache-safe)",
|
|
3724
3670
|
off: "All tools enabled (full prompt)",
|
|
@@ -3762,7 +3708,7 @@ var MODE_DESC = {
|
|
|
3762
3708
|
suggest: "Shows next-step suggestions after each turn",
|
|
3763
3709
|
auto: "Self-driving \u2014 agent continues automatically"
|
|
3764
3710
|
};
|
|
3765
|
-
var SETTINGS_FIELD_COUNT =
|
|
3711
|
+
var SETTINGS_FIELD_COUNT = 43;
|
|
3766
3712
|
var THINKING_WORD_FIELD = 22;
|
|
3767
3713
|
var THINKING_WORD_PRESETS = [
|
|
3768
3714
|
"thinking",
|
|
@@ -3863,8 +3809,10 @@ var SETTINGS_FIELD_LABELS = [
|
|
|
3863
3809
|
// 39
|
|
3864
3810
|
"Show agent swarm panel",
|
|
3865
3811
|
// 40
|
|
3866
|
-
"Pre-refine countdown"
|
|
3812
|
+
"Pre-refine countdown",
|
|
3867
3813
|
// 41
|
|
3814
|
+
"Read symbols"
|
|
3815
|
+
// 42
|
|
3868
3816
|
];
|
|
3869
3817
|
function resolveSettingsFieldValue(field, input) {
|
|
3870
3818
|
const raw = input.trim().toLowerCase();
|
|
@@ -3888,15 +3836,26 @@ function resolveSettingsFieldValue(field, input) {
|
|
|
3888
3836
|
[33, "debugStream"],
|
|
3889
3837
|
[37, "breakerEnabled"],
|
|
3890
3838
|
[39, "showModelReasoning"],
|
|
3891
|
-
[40, "showAgentSwarmPanel"]
|
|
3839
|
+
[40, "showAgentSwarmPanel"],
|
|
3840
|
+
[42, "readSymbols"]
|
|
3892
3841
|
]);
|
|
3893
3842
|
const boolKey = BOOL_FIELDS.get(field);
|
|
3894
3843
|
if (boolKey) {
|
|
3895
3844
|
if (["on", "true", "yes", "1"].includes(raw)) {
|
|
3896
|
-
return {
|
|
3845
|
+
return {
|
|
3846
|
+
ok: true,
|
|
3847
|
+
patch: { [boolKey]: true },
|
|
3848
|
+
label,
|
|
3849
|
+
displayValue: "on"
|
|
3850
|
+
};
|
|
3897
3851
|
}
|
|
3898
3852
|
if (["off", "false", "no", "0"].includes(raw)) {
|
|
3899
|
-
return {
|
|
3853
|
+
return {
|
|
3854
|
+
ok: true,
|
|
3855
|
+
patch: { [boolKey]: false },
|
|
3856
|
+
label,
|
|
3857
|
+
displayValue: "off"
|
|
3858
|
+
};
|
|
3900
3859
|
}
|
|
3901
3860
|
return { ok: false, error: `Invalid value "${input}" for ${label}. Use on or off.` };
|
|
3902
3861
|
}
|
|
@@ -3904,7 +3863,12 @@ function resolveSettingsFieldValue(field, input) {
|
|
|
3904
3863
|
const legacy = ["on", "true", "yes", "1"].includes(raw) ? "full" : ["false", "no", "0"].includes(raw) ? "off" : void 0;
|
|
3905
3864
|
const match = FLEET_CHAT_MODES.includes(raw) ? raw : legacy;
|
|
3906
3865
|
if (match) {
|
|
3907
|
-
return {
|
|
3866
|
+
return {
|
|
3867
|
+
ok: true,
|
|
3868
|
+
patch: { fleetChat: match },
|
|
3869
|
+
label,
|
|
3870
|
+
displayValue: match
|
|
3871
|
+
};
|
|
3908
3872
|
}
|
|
3909
3873
|
return {
|
|
3910
3874
|
ok: false,
|
|
@@ -3930,7 +3894,12 @@ function resolveSettingsFieldValue(field, input) {
|
|
|
3930
3894
|
if (field !== f) continue;
|
|
3931
3895
|
const match = values.find((v) => v.toLowerCase() === raw);
|
|
3932
3896
|
if (match) {
|
|
3933
|
-
return {
|
|
3897
|
+
return {
|
|
3898
|
+
ok: true,
|
|
3899
|
+
patch: { [key]: match },
|
|
3900
|
+
label,
|
|
3901
|
+
displayValue: match
|
|
3902
|
+
};
|
|
3934
3903
|
}
|
|
3935
3904
|
return {
|
|
3936
3905
|
ok: false,
|
|
@@ -3944,7 +3913,12 @@ function resolveSettingsFieldValue(field, input) {
|
|
|
3944
3913
|
[16, "autoProceedMaxIterations", AUTO_PROCEED_MAX_PRESETS, (n) => formatMaxIterations(n)],
|
|
3945
3914
|
[17, "enhanceDelayMs", ENHANCE_DELAY_PRESETS, (n) => formatEnhanceDelay(n)],
|
|
3946
3915
|
[41, "preRefineSeconds", PRE_REFINE_SECONDS_PRESETS, (n) => formatPreRefineSeconds(n)],
|
|
3947
|
-
[
|
|
3916
|
+
[
|
|
3917
|
+
21,
|
|
3918
|
+
"multiDiffSummaryThreshold",
|
|
3919
|
+
MULTI_DIFF_SUMMARY_THRESHOLD_PRESETS,
|
|
3920
|
+
(n) => formatMultiDiffSummaryThreshold(n)
|
|
3921
|
+
],
|
|
3948
3922
|
[30, "maxConcurrent", MAX_CONCURRENT_PRESETS, (n) => presetLabel(n, "runtime default")],
|
|
3949
3923
|
[38, "breakerAutoKillResetMs", BREAKER_TIMEOUT_PRESETS, (n) => formatBreakerTimeout(n)]
|
|
3950
3924
|
];
|
|
@@ -3952,11 +3926,21 @@ function resolveSettingsFieldValue(field, input) {
|
|
|
3952
3926
|
if (field !== f) continue;
|
|
3953
3927
|
const asNum = Number.parseInt(raw, 10);
|
|
3954
3928
|
if (!Number.isNaN(asNum) && presets.includes(asNum)) {
|
|
3955
|
-
return {
|
|
3929
|
+
return {
|
|
3930
|
+
ok: true,
|
|
3931
|
+
patch: { [key]: asNum },
|
|
3932
|
+
label,
|
|
3933
|
+
displayValue: fmt2(asNum)
|
|
3934
|
+
};
|
|
3956
3935
|
}
|
|
3957
3936
|
const byName = presets.find((p) => fmt2(p).toLowerCase() === raw);
|
|
3958
3937
|
if (byName !== void 0) {
|
|
3959
|
-
return {
|
|
3938
|
+
return {
|
|
3939
|
+
ok: true,
|
|
3940
|
+
patch: { [key]: byName },
|
|
3941
|
+
label,
|
|
3942
|
+
displayValue: fmt2(byName)
|
|
3943
|
+
};
|
|
3960
3944
|
}
|
|
3961
3945
|
const options = presets.map((p) => fmt2(p)).join(", ");
|
|
3962
3946
|
return {
|
|
@@ -4003,7 +3987,8 @@ function getSettingsFieldValue(values, field) {
|
|
|
4003
3987
|
[33, "debugStream"],
|
|
4004
3988
|
[37, "breakerEnabled"],
|
|
4005
3989
|
[39, "showModelReasoning"],
|
|
4006
|
-
[40, "showAgentSwarmPanel"]
|
|
3990
|
+
[40, "showAgentSwarmPanel"],
|
|
3991
|
+
[42, "readSymbols"]
|
|
4007
3992
|
];
|
|
4008
3993
|
for (const [f, key] of BOOL_KEYS) {
|
|
4009
3994
|
if (field !== f) continue;
|
|
@@ -4064,7 +4049,7 @@ var SETTINGS_SECTIONS = [
|
|
|
4064
4049
|
},
|
|
4065
4050
|
{
|
|
4066
4051
|
name: "Tools",
|
|
4067
|
-
fields: [15, 16, 17, 18, 19, 20, 21, 22]
|
|
4052
|
+
fields: [15, 16, 17, 18, 19, 20, 21, 22, 42]
|
|
4068
4053
|
},
|
|
4069
4054
|
{
|
|
4070
4055
|
name: "Reasoning",
|
|
@@ -4153,7 +4138,8 @@ var SETTINGS_DEFAULTS = Object.freeze({
|
|
|
4153
4138
|
breakerEnabled: false,
|
|
4154
4139
|
breakerAutoKillResetMs: 6e4,
|
|
4155
4140
|
showModelReasoning: true,
|
|
4156
|
-
showAgentSwarmPanel: true
|
|
4141
|
+
showAgentSwarmPanel: true,
|
|
4142
|
+
readSymbols: false
|
|
4157
4143
|
});
|
|
4158
4144
|
function resetSettingsFieldValue(field) {
|
|
4159
4145
|
const result = getSettingsFieldValue(SETTINGS_DEFAULTS, field);
|
|
@@ -4205,7 +4191,8 @@ function buildResetPatch(field) {
|
|
|
4205
4191
|
[38, "breakerAutoKillResetMs"],
|
|
4206
4192
|
[39, "showModelReasoning"],
|
|
4207
4193
|
[40, "showAgentSwarmPanel"],
|
|
4208
|
-
[41, "preRefineSeconds"]
|
|
4194
|
+
[41, "preRefineSeconds"],
|
|
4195
|
+
[42, "readSymbols"]
|
|
4209
4196
|
];
|
|
4210
4197
|
for (const [f, key] of KEY_MAP) {
|
|
4211
4198
|
if (f === field) {
|
|
@@ -4215,6 +4202,77 @@ function buildResetPatch(field) {
|
|
|
4215
4202
|
return null;
|
|
4216
4203
|
}
|
|
4217
4204
|
|
|
4205
|
+
// src/components/settings-picker-row-list.tsx
|
|
4206
|
+
import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
4207
|
+
function renderPickerRow(row, fieldIdx, selected, filterActive, highlightSegments) {
|
|
4208
|
+
const labelStr = row.label ?? "";
|
|
4209
|
+
const segments = highlightSegments(labelStr);
|
|
4210
|
+
const padNeeded = Math.max(0, 26 - labelStr.length);
|
|
4211
|
+
return /* @__PURE__ */ jsxs7(Text, { inverse: selected, ...selected ? { color: "yellow" } : {}, children: [
|
|
4212
|
+
selected ? "\u203A " : " ",
|
|
4213
|
+
filterActive ? /* @__PURE__ */ jsxs7(Fragment4, { children: [
|
|
4214
|
+
segments.map((seg, j) => /* @__PURE__ */ jsx8(Text, { bold: true, ...seg.match ? { color: "yellow" } : { dimColor: true }, children: seg.text }, j)),
|
|
4215
|
+
/* @__PURE__ */ jsx8(Text, { bold: true, dimColor: true, children: " ".repeat(padNeeded) })
|
|
4216
|
+
] }) : /* @__PURE__ */ jsx8(Text, { bold: true, children: labelStr.padEnd(26) }),
|
|
4217
|
+
/* @__PURE__ */ jsx8(Text, { color: "cyan", children: String(row.value ?? "").padEnd(12) }),
|
|
4218
|
+
/* @__PURE__ */ jsx8(Text, { dimColor: true, children: row.detail ?? "" })
|
|
4219
|
+
] }, `row-${row.label ?? fieldIdx}`);
|
|
4220
|
+
}
|
|
4221
|
+
function buildVisibleSectionHeaders(rows, fieldRowIndex, windowStart, windowEnd) {
|
|
4222
|
+
const sectionFields = [];
|
|
4223
|
+
let curHeader = -1;
|
|
4224
|
+
for (let i = 0; i < rows.length; i++) {
|
|
4225
|
+
if (rows[i]?.section) curHeader = i;
|
|
4226
|
+
else if (curHeader >= 0) {
|
|
4227
|
+
const fieldIdx = fieldRowIndex.indexOf(i);
|
|
4228
|
+
if (fieldIdx === -1) continue;
|
|
4229
|
+
const entry = sectionFields.find((s2) => s2.headerIdx === curHeader);
|
|
4230
|
+
if (entry) {
|
|
4231
|
+
entry.fieldEnd = fieldIdx + 1;
|
|
4232
|
+
} else {
|
|
4233
|
+
sectionFields.push({ headerIdx: curHeader, fieldStart: fieldIdx, fieldEnd: fieldIdx + 1 });
|
|
4234
|
+
}
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
return new Set(
|
|
4238
|
+
sectionFields.filter((section) => section.fieldStart < windowEnd && section.fieldEnd > windowStart).map((section) => section.headerIdx)
|
|
4239
|
+
);
|
|
4240
|
+
}
|
|
4241
|
+
function SettingsPickerRowList({
|
|
4242
|
+
rows,
|
|
4243
|
+
field,
|
|
4244
|
+
fieldRowIndex,
|
|
4245
|
+
filterActive,
|
|
4246
|
+
rankedResults,
|
|
4247
|
+
highlightSegments,
|
|
4248
|
+
windowStart,
|
|
4249
|
+
windowEnd
|
|
4250
|
+
}) {
|
|
4251
|
+
if (filterActive) {
|
|
4252
|
+
return /* @__PURE__ */ jsx8(Fragment4, { children: rankedResults.map((result) => {
|
|
4253
|
+
const fieldIdx = result.chord.field;
|
|
4254
|
+
const rowIdx = fieldRowIndex[fieldIdx] ?? -1;
|
|
4255
|
+
const row = rows[rowIdx];
|
|
4256
|
+
if (!row?.label) return null;
|
|
4257
|
+
return renderPickerRow(row, fieldIdx, fieldIdx === field, true, highlightSegments);
|
|
4258
|
+
}) });
|
|
4259
|
+
}
|
|
4260
|
+
const visibleSections = buildVisibleSectionHeaders(rows, fieldRowIndex, windowStart, windowEnd);
|
|
4261
|
+
return /* @__PURE__ */ jsx8(Fragment4, { children: rows.map((row, i) => {
|
|
4262
|
+
const fieldAtRow = fieldRowIndex.indexOf(i);
|
|
4263
|
+
if (fieldAtRow === -1) {
|
|
4264
|
+
if (!visibleSections.has(i)) return null;
|
|
4265
|
+
return /* @__PURE__ */ jsxs7(Text, { bold: true, color: "green", children: [
|
|
4266
|
+
"\u2500\u2500 ",
|
|
4267
|
+
row.section,
|
|
4268
|
+
" \u2500\u2500"
|
|
4269
|
+
] }, `section-${row.section ?? i}`);
|
|
4270
|
+
}
|
|
4271
|
+
if (fieldAtRow < windowStart || fieldAtRow >= windowEnd) return null;
|
|
4272
|
+
return renderPickerRow(row, fieldAtRow, fieldAtRow === field, false, highlightSegments);
|
|
4273
|
+
}) });
|
|
4274
|
+
}
|
|
4275
|
+
|
|
4218
4276
|
// src/components/settings-picker.tsx
|
|
4219
4277
|
import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
4220
4278
|
function SettingsPicker({
|
|
@@ -4265,6 +4323,7 @@ function SettingsPicker({
|
|
|
4265
4323
|
breakerAutoKillResetMs,
|
|
4266
4324
|
showModelReasoning,
|
|
4267
4325
|
showAgentSwarmPanel,
|
|
4326
|
+
readSymbols,
|
|
4268
4327
|
hint
|
|
4269
4328
|
}) {
|
|
4270
4329
|
const boolVal = (v) => v ? "on" : "off";
|
|
@@ -4496,6 +4555,13 @@ function SettingsPicker({
|
|
|
4496
4555
|
label: "Pre-refine countdown",
|
|
4497
4556
|
value: formatPreRefineSeconds(preRefineSeconds),
|
|
4498
4557
|
detail: "Grace period before refiner starts (0 = skip)"
|
|
4558
|
+
},
|
|
4559
|
+
// Appended to preserve the established field indices used by settings
|
|
4560
|
+
// reducers, slash commands, and persisted lastSettingsField values.
|
|
4561
|
+
{
|
|
4562
|
+
label: "Read symbols",
|
|
4563
|
+
value: boolVal(readSymbols),
|
|
4564
|
+
detail: "Include codebase-index symbols in read tool results"
|
|
4499
4565
|
}
|
|
4500
4566
|
];
|
|
4501
4567
|
const fieldRowIndex = [];
|
|
@@ -4513,7 +4579,14 @@ function SettingsPicker({
|
|
|
4513
4579
|
const hasBelow = windowEnd < totalFields;
|
|
4514
4580
|
return /* @__PURE__ */ jsxs8(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
4515
4581
|
/* @__PURE__ */ jsx9(Text, { color: "cyan", bold: true, children: "\u2501\u2501 Settings \u2501\u2501" }),
|
|
4516
|
-
filterActive ? /* @__PURE__ */ jsx9(
|
|
4582
|
+
filterActive ? /* @__PURE__ */ jsx9(
|
|
4583
|
+
Text,
|
|
4584
|
+
{
|
|
4585
|
+
color: "yellow",
|
|
4586
|
+
bold: true,
|
|
4587
|
+
children: `Filter: ${filter} (${filteredFieldIndices.length} match${filteredFieldIndices.length === 1 ? "" : "es"})`
|
|
4588
|
+
}
|
|
4589
|
+
) : /* @__PURE__ */ jsx9(Text, { dimColor: true, children: "\u2191/\u2193 field \xB7 \u2190/\u2192 change + autosave \xB7 `/` to search \xB7 F5 to close" }),
|
|
4517
4590
|
hasAbove && !filterActive ? /* @__PURE__ */ jsx9(Text, { dimColor: true, children: ` \u2191 ${windowStart} field${windowStart === 1 ? "" : "s"} above` }) : null,
|
|
4518
4591
|
filterActive && filteredFieldIndices.length === 0 ? /* @__PURE__ */ jsx9(Text, { dimColor: true, italic: true, children: "No matching settings rows." }) : null,
|
|
4519
4592
|
/* @__PURE__ */ jsx9(
|
|
@@ -4529,7 +4602,13 @@ function SettingsPicker({
|
|
|
4529
4602
|
windowEnd
|
|
4530
4603
|
}
|
|
4531
4604
|
),
|
|
4532
|
-
hasBelow && !filterActive ? /* @__PURE__ */ jsx9(
|
|
4605
|
+
hasBelow && !filterActive ? /* @__PURE__ */ jsx9(
|
|
4606
|
+
Text,
|
|
4607
|
+
{
|
|
4608
|
+
dimColor: true,
|
|
4609
|
+
children: ` \u2193 ${totalFields - windowEnd} field${totalFields - windowEnd === 1 ? "" : "s"} below`
|
|
4610
|
+
}
|
|
4611
|
+
) : null,
|
|
4533
4612
|
/* @__PURE__ */ jsx9(Text, { dimColor: true, children: configScope === "project" ? "Persisted to <project>/.wrongstack/config.json" : `Persisted to ${profileConfigPath}` }),
|
|
4534
4613
|
hint ? /* @__PURE__ */ jsx9(Text, { color: "yellow", children: hint }) : null
|
|
4535
4614
|
] });
|
|
@@ -10317,6 +10396,35 @@ function useAppRuntimeRefs(attachments, state) {
|
|
|
10317
10396
|
// src/hooks/use-app-session-state.ts
|
|
10318
10397
|
import { useEffect as useEffect18, useMemo as useMemo6, useReducer } from "react";
|
|
10319
10398
|
|
|
10399
|
+
// src/checkpoint-retention.ts
|
|
10400
|
+
var TUI_CHECKPOINTS_MAX_ENTRIES = 200;
|
|
10401
|
+
var TUI_CHECKPOINTS_MAX_BYTES = 256 * 1024;
|
|
10402
|
+
function entryBytes(entry) {
|
|
10403
|
+
try {
|
|
10404
|
+
return Buffer.byteLength(JSON.stringify(entry), "utf8");
|
|
10405
|
+
} catch {
|
|
10406
|
+
return TUI_CHECKPOINTS_MAX_BYTES + 1;
|
|
10407
|
+
}
|
|
10408
|
+
}
|
|
10409
|
+
function retainCheckpoints(checkpoints, budget = {}) {
|
|
10410
|
+
const maxEntries = Math.max(1, Math.floor(budget.maxEntries ?? TUI_CHECKPOINTS_MAX_ENTRIES));
|
|
10411
|
+
const maxBytes = Math.max(1, Math.floor(budget.maxBytes ?? TUI_CHECKPOINTS_MAX_BYTES));
|
|
10412
|
+
let keepFrom = checkpoints.length;
|
|
10413
|
+
let retainedBytes = 0;
|
|
10414
|
+
let retainedCount = 0;
|
|
10415
|
+
while (keepFrom > 0 && retainedCount < maxEntries) {
|
|
10416
|
+
const next = checkpoints[keepFrom - 1];
|
|
10417
|
+
if (!next) break;
|
|
10418
|
+
const bytes = entryBytes(next);
|
|
10419
|
+
if (retainedCount > 0 && retainedBytes + bytes > maxBytes) break;
|
|
10420
|
+
retainedBytes += bytes;
|
|
10421
|
+
retainedCount += 1;
|
|
10422
|
+
keepFrom -= 1;
|
|
10423
|
+
}
|
|
10424
|
+
if (keepFrom === 0) return checkpoints;
|
|
10425
|
+
return checkpoints.slice(keepFrom);
|
|
10426
|
+
}
|
|
10427
|
+
|
|
10320
10428
|
// src/components/history/replay.ts
|
|
10321
10429
|
import { SESSION_MARKER_EVENT_TYPES, sessionEventToMarker } from "@wrongstack/core/types";
|
|
10322
10430
|
var MARKER_EVENT_TYPES = SESSION_MARKER_EVENT_TYPES;
|
|
@@ -10526,79 +10634,6 @@ function eventToEntry(ev, pendingTools, completedTools) {
|
|
|
10526
10634
|
}
|
|
10527
10635
|
}
|
|
10528
10636
|
|
|
10529
|
-
// src/rehydrate-history.ts
|
|
10530
|
-
function contentBlocksText(content) {
|
|
10531
|
-
if (typeof content === "string") return content;
|
|
10532
|
-
if (!Array.isArray(content)) return "";
|
|
10533
|
-
return content.filter(
|
|
10534
|
-
(block) => !!block && typeof block === "object" && block.type === "text" && typeof block.text === "string"
|
|
10535
|
-
).map((block) => block.text).join("");
|
|
10536
|
-
}
|
|
10537
|
-
function rehydrateHistory(messages, startId, toolCalls) {
|
|
10538
|
-
const entries = [];
|
|
10539
|
-
const toolCallsById = /* @__PURE__ */ new Map();
|
|
10540
|
-
if (toolCalls) {
|
|
10541
|
-
for (const tc of toolCalls) {
|
|
10542
|
-
if (!toolCallsById.has(tc.id)) toolCallsById.set(tc.id, tc);
|
|
10543
|
-
}
|
|
10544
|
-
}
|
|
10545
|
-
const consumed = /* @__PURE__ */ new Set();
|
|
10546
|
-
const fallback = [];
|
|
10547
|
-
let nextId = startId;
|
|
10548
|
-
const textOf = (msg) => contentBlocksText(msg.content);
|
|
10549
|
-
const toolEntryFor = (tc) => ({
|
|
10550
|
-
id: nextId++,
|
|
10551
|
-
kind: "tool",
|
|
10552
|
-
name: tc.name,
|
|
10553
|
-
durationMs: tc.durationMs,
|
|
10554
|
-
ok: tc.ok,
|
|
10555
|
-
outputBytes: tc.outputBytes,
|
|
10556
|
-
outputTokens: tc.outputTokens,
|
|
10557
|
-
outputLines: tc.outputLines
|
|
10558
|
-
});
|
|
10559
|
-
const pushAssistantText = (parts) => {
|
|
10560
|
-
const text = parts.join("").trim();
|
|
10561
|
-
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
10562
|
-
parts.length = 0;
|
|
10563
|
-
};
|
|
10564
|
-
for (const msg of messages) {
|
|
10565
|
-
if (msg.role === "system") continue;
|
|
10566
|
-
if (msg.role === "user") {
|
|
10567
|
-
const text = textOf(msg).trim();
|
|
10568
|
-
if (text) entries.push({ id: nextId++, kind: "user", text });
|
|
10569
|
-
continue;
|
|
10570
|
-
}
|
|
10571
|
-
if (msg.role === "assistant") {
|
|
10572
|
-
if (!Array.isArray(msg.content)) {
|
|
10573
|
-
const text = textOf(msg).trim();
|
|
10574
|
-
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
10575
|
-
continue;
|
|
10576
|
-
}
|
|
10577
|
-
const textParts = [];
|
|
10578
|
-
for (const block of msg.content) {
|
|
10579
|
-
if (block.type === "text") {
|
|
10580
|
-
textParts.push(block.text);
|
|
10581
|
-
continue;
|
|
10582
|
-
}
|
|
10583
|
-
if (block.type !== "tool_use") continue;
|
|
10584
|
-
pushAssistantText(textParts);
|
|
10585
|
-
const tc = toolCallsById.get(block.id);
|
|
10586
|
-
if (!tc) continue;
|
|
10587
|
-
entries.push(toolEntryFor(tc));
|
|
10588
|
-
consumed.add(block.id);
|
|
10589
|
-
}
|
|
10590
|
-
pushAssistantText(textParts);
|
|
10591
|
-
}
|
|
10592
|
-
}
|
|
10593
|
-
if (toolCalls) {
|
|
10594
|
-
for (const tc of toolCalls) {
|
|
10595
|
-
if (!consumed.has(tc.id)) fallback.push(toolEntryFor(tc));
|
|
10596
|
-
}
|
|
10597
|
-
}
|
|
10598
|
-
entries.push(...fallback);
|
|
10599
|
-
return entries;
|
|
10600
|
-
}
|
|
10601
|
-
|
|
10602
10637
|
// src/history-retention.ts
|
|
10603
10638
|
var TUI_HISTORY_MAX_ENTRIES = 400;
|
|
10604
10639
|
var TUI_HISTORY_MAX_BYTES = 1024 * 1024;
|
|
@@ -10612,7 +10647,7 @@ function omittedCount(entry) {
|
|
|
10612
10647
|
const count = Number(match[1]);
|
|
10613
10648
|
return Number.isSafeInteger(count) && count > 0 ? count : null;
|
|
10614
10649
|
}
|
|
10615
|
-
function
|
|
10650
|
+
function entryBytes2(entry) {
|
|
10616
10651
|
try {
|
|
10617
10652
|
return Buffer.byteLength(JSON.stringify(entry), "utf8");
|
|
10618
10653
|
} catch {
|
|
@@ -10627,8 +10662,8 @@ function oversizedEntryMarker(entry) {
|
|
|
10627
10662
|
};
|
|
10628
10663
|
}
|
|
10629
10664
|
function retainTextWithinEntryBudget(value, maxBytes, createEntry, original) {
|
|
10630
|
-
if (
|
|
10631
|
-
if (
|
|
10665
|
+
if (entryBytes2(createEntry(value)) <= maxBytes) return createEntry(value);
|
|
10666
|
+
if (entryBytes2(createEntry(ENTRY_TRUNCATION_MARKER)) > maxBytes) {
|
|
10632
10667
|
return oversizedEntryMarker(original);
|
|
10633
10668
|
}
|
|
10634
10669
|
let low = 0;
|
|
@@ -10636,7 +10671,7 @@ function retainTextWithinEntryBudget(value, maxBytes, createEntry, original) {
|
|
|
10636
10671
|
while (low < high) {
|
|
10637
10672
|
const middle = Math.ceil((low + high) / 2);
|
|
10638
10673
|
const candidate = `${value.slice(0, middle)}${ENTRY_TRUNCATION_MARKER}`;
|
|
10639
|
-
if (
|
|
10674
|
+
if (entryBytes2(createEntry(candidate)) <= maxBytes) low = middle;
|
|
10640
10675
|
else high = middle - 1;
|
|
10641
10676
|
}
|
|
10642
10677
|
let end = low;
|
|
@@ -10645,7 +10680,7 @@ function retainTextWithinEntryBudget(value, maxBytes, createEntry, original) {
|
|
|
10645
10680
|
return createEntry(`${value.slice(0, end)}${ENTRY_TRUNCATION_MARKER}`);
|
|
10646
10681
|
}
|
|
10647
10682
|
function retainTuiHistoryEntry(entry, maxBytes = TUI_HISTORY_MAX_ENTRY_BYTES) {
|
|
10648
|
-
if (
|
|
10683
|
+
if (entryBytes2(entry) <= maxBytes) return entry;
|
|
10649
10684
|
switch (entry.kind) {
|
|
10650
10685
|
case "user":
|
|
10651
10686
|
return retainTextWithinEntryBudget(
|
|
@@ -10693,7 +10728,7 @@ function retainTuiHistoryEntry(entry, maxBytes = TUI_HISTORY_MAX_ENTRY_BYTES) {
|
|
|
10693
10728
|
model: truncate3(entry.model),
|
|
10694
10729
|
cwd: truncate3(entry.cwd)
|
|
10695
10730
|
};
|
|
10696
|
-
return
|
|
10731
|
+
return entryBytes2(compact) <= maxBytes ? compact : oversizedEntryMarker(entry);
|
|
10697
10732
|
}
|
|
10698
10733
|
default:
|
|
10699
10734
|
return oversizedEntryMarker(entry);
|
|
@@ -10734,7 +10769,7 @@ function retainTuiHistory(entries, budget = {}) {
|
|
|
10734
10769
|
while (keepFrom > 0 && retainedCount < maxEntries) {
|
|
10735
10770
|
const next = transcript[keepFrom - 1];
|
|
10736
10771
|
if (!next) break;
|
|
10737
|
-
const bytes =
|
|
10772
|
+
const bytes = entryBytes2(next);
|
|
10738
10773
|
if (retainedCount > 0 && retainedBytes + bytes > maxBytes) break;
|
|
10739
10774
|
retainedBytes += bytes;
|
|
10740
10775
|
retainedCount += 1;
|
|
@@ -10759,33 +10794,77 @@ function retainTuiHistory(entries, budget = {}) {
|
|
|
10759
10794
|
return retained;
|
|
10760
10795
|
}
|
|
10761
10796
|
|
|
10762
|
-
// src/
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10768
|
-
|
|
10769
|
-
return TUI_CHECKPOINTS_MAX_BYTES + 1;
|
|
10770
|
-
}
|
|
10797
|
+
// src/rehydrate-history.ts
|
|
10798
|
+
function contentBlocksText(content) {
|
|
10799
|
+
if (typeof content === "string") return content;
|
|
10800
|
+
if (!Array.isArray(content)) return "";
|
|
10801
|
+
return content.filter(
|
|
10802
|
+
(block) => !!block && typeof block === "object" && block.type === "text" && typeof block.text === "string"
|
|
10803
|
+
).map((block) => block.text).join("");
|
|
10771
10804
|
}
|
|
10772
|
-
function
|
|
10773
|
-
const
|
|
10774
|
-
const
|
|
10775
|
-
|
|
10776
|
-
|
|
10777
|
-
|
|
10778
|
-
|
|
10779
|
-
const next = checkpoints[keepFrom - 1];
|
|
10780
|
-
if (!next) break;
|
|
10781
|
-
const bytes = entryBytes2(next);
|
|
10782
|
-
if (retainedCount > 0 && retainedBytes + bytes > maxBytes) break;
|
|
10783
|
-
retainedBytes += bytes;
|
|
10784
|
-
retainedCount += 1;
|
|
10785
|
-
keepFrom -= 1;
|
|
10805
|
+
function rehydrateHistory(messages, startId, toolCalls) {
|
|
10806
|
+
const entries = [];
|
|
10807
|
+
const toolCallsById = /* @__PURE__ */ new Map();
|
|
10808
|
+
if (toolCalls) {
|
|
10809
|
+
for (const tc of toolCalls) {
|
|
10810
|
+
if (!toolCallsById.has(tc.id)) toolCallsById.set(tc.id, tc);
|
|
10811
|
+
}
|
|
10786
10812
|
}
|
|
10787
|
-
|
|
10788
|
-
|
|
10813
|
+
const consumed = /* @__PURE__ */ new Set();
|
|
10814
|
+
const fallback = [];
|
|
10815
|
+
let nextId = startId;
|
|
10816
|
+
const textOf = (msg) => contentBlocksText(msg.content);
|
|
10817
|
+
const toolEntryFor = (tc) => ({
|
|
10818
|
+
id: nextId++,
|
|
10819
|
+
kind: "tool",
|
|
10820
|
+
name: tc.name,
|
|
10821
|
+
durationMs: tc.durationMs,
|
|
10822
|
+
ok: tc.ok,
|
|
10823
|
+
outputBytes: tc.outputBytes,
|
|
10824
|
+
outputTokens: tc.outputTokens,
|
|
10825
|
+
outputLines: tc.outputLines
|
|
10826
|
+
});
|
|
10827
|
+
const pushAssistantText = (parts) => {
|
|
10828
|
+
const text = parts.join("").trim();
|
|
10829
|
+
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
10830
|
+
parts.length = 0;
|
|
10831
|
+
};
|
|
10832
|
+
for (const msg of messages) {
|
|
10833
|
+
if (msg.role === "system") continue;
|
|
10834
|
+
if (msg.role === "user") {
|
|
10835
|
+
const text = textOf(msg).trim();
|
|
10836
|
+
if (text) entries.push({ id: nextId++, kind: "user", text });
|
|
10837
|
+
continue;
|
|
10838
|
+
}
|
|
10839
|
+
if (msg.role === "assistant") {
|
|
10840
|
+
if (!Array.isArray(msg.content)) {
|
|
10841
|
+
const text = textOf(msg).trim();
|
|
10842
|
+
if (text) entries.push({ id: nextId++, kind: "assistant", text });
|
|
10843
|
+
continue;
|
|
10844
|
+
}
|
|
10845
|
+
const textParts = [];
|
|
10846
|
+
for (const block of msg.content) {
|
|
10847
|
+
if (block.type === "text") {
|
|
10848
|
+
textParts.push(block.text);
|
|
10849
|
+
continue;
|
|
10850
|
+
}
|
|
10851
|
+
if (block.type !== "tool_use") continue;
|
|
10852
|
+
pushAssistantText(textParts);
|
|
10853
|
+
const tc = toolCallsById.get(block.id);
|
|
10854
|
+
if (!tc) continue;
|
|
10855
|
+
entries.push(toolEntryFor(tc));
|
|
10856
|
+
consumed.add(block.id);
|
|
10857
|
+
}
|
|
10858
|
+
pushAssistantText(textParts);
|
|
10859
|
+
}
|
|
10860
|
+
}
|
|
10861
|
+
if (toolCalls) {
|
|
10862
|
+
for (const tc of toolCalls) {
|
|
10863
|
+
if (!consumed.has(tc.id)) fallback.push(toolEntryFor(tc));
|
|
10864
|
+
}
|
|
10865
|
+
}
|
|
10866
|
+
entries.push(...fallback);
|
|
10867
|
+
return entries;
|
|
10789
10868
|
}
|
|
10790
10869
|
|
|
10791
10870
|
// src/app-initial-state.ts
|
|
@@ -10969,7 +11048,8 @@ function createInitialState(options) {
|
|
|
10969
11048
|
breakerEnabled: false,
|
|
10970
11049
|
breakerAutoKillResetMs: 6e4,
|
|
10971
11050
|
showModelReasoning: true,
|
|
10972
|
-
showAgentSwarmPanel: true
|
|
11051
|
+
showAgentSwarmPanel: true,
|
|
11052
|
+
readSymbols: false
|
|
10973
11053
|
},
|
|
10974
11054
|
statuslinePicker: {
|
|
10975
11055
|
open: false,
|
|
@@ -10980,10 +11060,31 @@ function createInitialState(options) {
|
|
|
10980
11060
|
},
|
|
10981
11061
|
pluginPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0 },
|
|
10982
11062
|
mcpPicker: { open: false, items: [], selected: 0, busy: false, hint: void 0 },
|
|
10983
|
-
toolsPicker: {
|
|
10984
|
-
|
|
11063
|
+
toolsPicker: {
|
|
11064
|
+
open: false,
|
|
11065
|
+
items: [],
|
|
11066
|
+
selected: 0,
|
|
11067
|
+
busy: false,
|
|
11068
|
+
hint: void 0,
|
|
11069
|
+
filter: void 0
|
|
11070
|
+
},
|
|
11071
|
+
brainPanel: {
|
|
11072
|
+
open: false,
|
|
11073
|
+
riskLevel: "medium",
|
|
11074
|
+
log: [],
|
|
11075
|
+
selected: 0,
|
|
11076
|
+
hint: void 0,
|
|
11077
|
+
view: "settings",
|
|
11078
|
+
settings: void 0,
|
|
11079
|
+
row: 0,
|
|
11080
|
+
busy: false
|
|
11081
|
+
},
|
|
10985
11082
|
helpPanel: { open: false, entries: [], selected: 0, filter: "", hint: void 0 },
|
|
10986
|
-
shadowPanel: {
|
|
11083
|
+
shadowPanel: {
|
|
11084
|
+
open: false,
|
|
11085
|
+
shadow: { activeId: null, running: false, model: "", intervalMs: 3e4 },
|
|
11086
|
+
hint: void 0
|
|
11087
|
+
},
|
|
10987
11088
|
authPanel: AUTH_PANEL_INITIAL,
|
|
10988
11089
|
projectPicker: {
|
|
10989
11090
|
open: false,
|
|
@@ -13242,6 +13343,7 @@ function reduceSettingsPanel(state, action) {
|
|
|
13242
13343
|
breakerAutoKillResetMs: action.breakerAutoKillResetMs,
|
|
13243
13344
|
showModelReasoning: action.showModelReasoning,
|
|
13244
13345
|
showAgentSwarmPanel: action.showAgentSwarmPanel,
|
|
13346
|
+
readSymbols: action.readSymbols,
|
|
13245
13347
|
hint: void 0
|
|
13246
13348
|
}
|
|
13247
13349
|
};
|
|
@@ -13671,6 +13773,24 @@ function reduceSettingsValues(state, action) {
|
|
|
13671
13773
|
...state,
|
|
13672
13774
|
settingsPicker: { ...sp, showAgentSwarmPanel: !sp.showAgentSwarmPanel, hint: void 0 }
|
|
13673
13775
|
};
|
|
13776
|
+
if (f === 41) {
|
|
13777
|
+
const j = PRE_REFINE_SECONDS_PRESETS.indexOf(sp.preRefineSeconds);
|
|
13778
|
+
const base = j < 0 ? 0 : j;
|
|
13779
|
+
const next = (base + action.delta + PRE_REFINE_SECONDS_PRESETS.length) % PRE_REFINE_SECONDS_PRESETS.length;
|
|
13780
|
+
return {
|
|
13781
|
+
...state,
|
|
13782
|
+
settingsPicker: {
|
|
13783
|
+
...sp,
|
|
13784
|
+
preRefineSeconds: expectDefined2(PRE_REFINE_SECONDS_PRESETS[next]),
|
|
13785
|
+
hint: void 0
|
|
13786
|
+
}
|
|
13787
|
+
};
|
|
13788
|
+
}
|
|
13789
|
+
if (f === 42)
|
|
13790
|
+
return {
|
|
13791
|
+
...state,
|
|
13792
|
+
settingsPicker: { ...sp, readSymbols: !sp.readSymbols, hint: void 0 }
|
|
13793
|
+
};
|
|
13674
13794
|
return state;
|
|
13675
13795
|
}
|
|
13676
13796
|
case "settingsValueSet": {
|
|
@@ -14075,6 +14195,7 @@ function visibleChars(text) {
|
|
|
14075
14195
|
const cleaned = text.replace(/\x1b\[[0-9;]*m/g, "");
|
|
14076
14196
|
return cleaned.length;
|
|
14077
14197
|
}
|
|
14198
|
+
var MAX_MEMORY_PROOF_ENTRIES = 4;
|
|
14078
14199
|
function computeEntryRows(kind, text, termWidth, meta) {
|
|
14079
14200
|
const w = Math.max(MIN_CONTENT_WIDTH, termWidth);
|
|
14080
14201
|
switch (kind) {
|
|
@@ -14165,10 +14286,17 @@ function computeEntryRows(kind, text, termWidth, meta) {
|
|
|
14165
14286
|
return rows;
|
|
14166
14287
|
}
|
|
14167
14288
|
// ── Memory activation ──
|
|
14168
|
-
// Bordered card: top (1) + header
|
|
14169
|
-
// optional
|
|
14289
|
+
// Bordered card: top (1) + header (1) + bottom (1) + margin (1), plus an
|
|
14290
|
+
// optional query line, two rows per shown memory (verdict + score terms),
|
|
14291
|
+
// an optional overflow line, and an optional rejected line. Every added
|
|
14292
|
+
// line renders with wrap="truncate-end", so each is exactly one row at
|
|
14293
|
+
// any terminal width — keep it that way or this count drifts.
|
|
14170
14294
|
case "memory-activation": {
|
|
14171
14295
|
let rows = 4;
|
|
14296
|
+
if (meta?.memoryHasQuery) rows += 1;
|
|
14297
|
+
const proofs = Math.min(meta?.memoryInjectedCount ?? 0, MAX_MEMORY_PROOF_ENTRIES);
|
|
14298
|
+
rows += proofs * 2;
|
|
14299
|
+
if ((meta?.memoryInjectedCount ?? 0) > MAX_MEMORY_PROOF_ENTRIES) rows += 1;
|
|
14172
14300
|
if (text) rows += 1;
|
|
14173
14301
|
return rows;
|
|
14174
14302
|
}
|
|
@@ -14802,7 +14930,7 @@ function useGitSessionStatus({
|
|
|
14802
14930
|
}
|
|
14803
14931
|
]
|
|
14804
14932
|
};
|
|
14805
|
-
agent.ctx.
|
|
14933
|
+
agent.ctx.state.appendMessage(message);
|
|
14806
14934
|
void import("@wrongstack/core/storage").then(({ getSessionRegistry }) => getSessionRegistry()?.updateAgents([])).catch(() => void 0);
|
|
14807
14935
|
}
|
|
14808
14936
|
previousBranchRef.current = info.branch;
|
|
@@ -15513,9 +15641,7 @@ ${GROUNDED_NO_PROGRESS_STEER}` : suggestion;
|
|
|
15513
15641
|
|
|
15514
15642
|
// src/hooks/use-panel-controllers.ts
|
|
15515
15643
|
import { toErrorMessage as toErrorMessage5 } from "@wrongstack/core/utils";
|
|
15516
|
-
import React2, {
|
|
15517
|
-
useEffect as useEffect28
|
|
15518
|
-
} from "react";
|
|
15644
|
+
import React2, { useEffect as useEffect28 } from "react";
|
|
15519
15645
|
|
|
15520
15646
|
// src/on-panel-open.ts
|
|
15521
15647
|
function createPanelOpenDispatcher(deps) {
|
|
@@ -15729,7 +15855,8 @@ function usePanelControllers({
|
|
|
15729
15855
|
breakerEnabled: s2.breakerEnabled ?? false,
|
|
15730
15856
|
breakerAutoKillResetMs: s2.breakerAutoKillResetMs ?? 6e4,
|
|
15731
15857
|
showModelReasoning: s2.showModelReasoning ?? true,
|
|
15732
|
-
showAgentSwarmPanel: s2.showAgentSwarmPanel ?? true
|
|
15858
|
+
showAgentSwarmPanel: s2.showAgentSwarmPanel ?? true,
|
|
15859
|
+
readSymbols: s2.readSymbols ?? false
|
|
15733
15860
|
});
|
|
15734
15861
|
}, [getSettings]);
|
|
15735
15862
|
const refreshPluginPicker = React2.useCallback(() => {
|
|
@@ -16191,6 +16318,11 @@ function usePromptPicker({
|
|
|
16191
16318
|
|
|
16192
16319
|
// src/hooks/use-provider-event-bridge.ts
|
|
16193
16320
|
import { tuiStreamFlushMs } from "@wrongstack/core/utils";
|
|
16321
|
+
import {
|
|
16322
|
+
DEFAULT_MIN_IMPORTANCE,
|
|
16323
|
+
DEFAULT_MIN_SCORE,
|
|
16324
|
+
MIN_RELATION_STRENGTH
|
|
16325
|
+
} from "@wrongstack/sage";
|
|
16194
16326
|
import {
|
|
16195
16327
|
useEffect as useEffect29
|
|
16196
16328
|
} from "react";
|
|
@@ -16373,6 +16505,13 @@ function canonicalStreamSegments(content) {
|
|
|
16373
16505
|
}
|
|
16374
16506
|
return segments;
|
|
16375
16507
|
}
|
|
16508
|
+
function formatSageInjectionStats(run) {
|
|
16509
|
+
const parts = [`+${run.injectedChars} chars`];
|
|
16510
|
+
if (run.contextPressure >= 0.65) {
|
|
16511
|
+
parts.push(`ctx ${Math.round(run.contextPressure * 100)}%`);
|
|
16512
|
+
}
|
|
16513
|
+
return parts.join(" \xB7 ");
|
|
16514
|
+
}
|
|
16376
16515
|
function useProviderEventBridge({
|
|
16377
16516
|
events,
|
|
16378
16517
|
agent,
|
|
@@ -16389,6 +16528,7 @@ function useProviderEventBridge({
|
|
|
16389
16528
|
useEffect29(() => {
|
|
16390
16529
|
const FLUSH_MS2 = tuiStreamFlushMs();
|
|
16391
16530
|
let pendingToolStream = null;
|
|
16531
|
+
const pendingSageStats = /* @__PURE__ */ new Map();
|
|
16392
16532
|
const appendStreamSegment = (kind, text) => {
|
|
16393
16533
|
const last = streamSegmentsRef.current.at(-1);
|
|
16394
16534
|
if (last?.kind === kind) {
|
|
@@ -16489,6 +16629,10 @@ function useProviderEventBridge({
|
|
|
16489
16629
|
ok: e.ok,
|
|
16490
16630
|
input: e.input,
|
|
16491
16631
|
output: e.output,
|
|
16632
|
+
// SAGE-injected memory travels beside the output preview so it
|
|
16633
|
+
// always renders as a memory block, never as tool text.
|
|
16634
|
+
sageLines: e.sage,
|
|
16635
|
+
...pendingSageStats.has(e.name) ? { sageStats: pendingSageStats.get(e.name) } : {},
|
|
16492
16636
|
// Real model-visible sizes — forwarded so the size chip beside
|
|
16493
16637
|
// the tool header can show what the model paid for instead of
|
|
16494
16638
|
// the misleading preview-byte count we used to surface.
|
|
@@ -16498,6 +16642,7 @@ function useProviderEventBridge({
|
|
|
16498
16642
|
}
|
|
16499
16643
|
});
|
|
16500
16644
|
}
|
|
16645
|
+
pendingSageStats.delete(e.name);
|
|
16501
16646
|
dispatch({ type: "toolEnded", ...e.id !== void 0 ? { id: e.id } : {}, name: e.name });
|
|
16502
16647
|
dispatch({ type: "toolStreamClear", name: e.name });
|
|
16503
16648
|
dispatch({ type: "leaderToolEnd", name: e.name, ok: e.ok, durationMs: e.durationMs });
|
|
@@ -16634,6 +16779,38 @@ function useProviderEventBridge({
|
|
|
16634
16779
|
setMemoryContextMonitor(
|
|
16635
16780
|
(current) => applyMemoryInjectorRun(current, e)
|
|
16636
16781
|
);
|
|
16782
|
+
if (e.injected.length > 0) {
|
|
16783
|
+
pendingSageStats.set(e.toolName, formatSageInjectionStats(e));
|
|
16784
|
+
}
|
|
16785
|
+
if (!e.error) return;
|
|
16786
|
+
dispatch({
|
|
16787
|
+
type: "addEntry",
|
|
16788
|
+
entry: {
|
|
16789
|
+
kind: "memory-activation",
|
|
16790
|
+
trigger: e.trigger,
|
|
16791
|
+
outcome: e.outcome,
|
|
16792
|
+
candidates: e.candidates,
|
|
16793
|
+
contextPressure: e.contextPressure,
|
|
16794
|
+
injectedChars: e.injectedChars,
|
|
16795
|
+
// The core event payload types declare these as REQUIRED, so the
|
|
16796
|
+
// `??` defaults are a stream-boundary fallback for legacy emitters
|
|
16797
|
+
// that omit them — not a current-build safety net.
|
|
16798
|
+
queryPreview: e.queryPreview ?? "",
|
|
16799
|
+
thresholds: e.thresholds ?? {
|
|
16800
|
+
minScore: DEFAULT_MIN_SCORE,
|
|
16801
|
+
minImportance: DEFAULT_MIN_IMPORTANCE,
|
|
16802
|
+
relationFloor: MIN_RELATION_STRENGTH
|
|
16803
|
+
},
|
|
16804
|
+
activated: e.activated.map((item) => ({
|
|
16805
|
+
...item,
|
|
16806
|
+
metadataScore: item.metadataScore ?? 0,
|
|
16807
|
+
scoreTerms: item.scoreTerms ?? []
|
|
16808
|
+
})),
|
|
16809
|
+
injectedIds: e.injected.map((item) => item.id),
|
|
16810
|
+
rejected: e.rejected,
|
|
16811
|
+
...e.error ? { error: e.error } : {}
|
|
16812
|
+
}
|
|
16813
|
+
});
|
|
16637
16814
|
});
|
|
16638
16815
|
const offMemoryContextSnapshot = events.onPattern(
|
|
16639
16816
|
"memory.context_snapshot",
|
|
@@ -16648,6 +16825,7 @@ function useProviderEventBridge({
|
|
|
16648
16825
|
const eventSessionId = payload?.sessionId;
|
|
16649
16826
|
if (typeof eventSessionId !== "string" || eventSessionId !== agent.ctx.session.id) return;
|
|
16650
16827
|
setMemoryContextMonitor(emptyMemoryContextMonitor());
|
|
16828
|
+
pendingSageStats.clear();
|
|
16651
16829
|
});
|
|
16652
16830
|
const offMemoryLifecycle = events.onPattern("memory.*", (event, payload) => {
|
|
16653
16831
|
const lifecycle = memoryLifecycleEntry(event, payload);
|
|
@@ -17087,7 +17265,8 @@ function useSettingsAutoSave(state, saveSettings, dispatch) {
|
|
|
17087
17265
|
breakerEnabled: sp.breakerEnabled,
|
|
17088
17266
|
breakerAutoKillResetMs: sp.breakerAutoKillResetMs,
|
|
17089
17267
|
showModelReasoning: sp.showModelReasoning,
|
|
17090
|
-
showAgentSwarmPanel: sp.showAgentSwarmPanel
|
|
17268
|
+
showAgentSwarmPanel: sp.showAgentSwarmPanel,
|
|
17269
|
+
readSymbols: sp.readSymbols
|
|
17091
17270
|
})
|
|
17092
17271
|
).then((err) => {
|
|
17093
17272
|
if (err) dispatch({ type: "settingsHint", text: err });
|
|
@@ -17136,6 +17315,7 @@ function useSettingsAutoSave(state, saveSettings, dispatch) {
|
|
|
17136
17315
|
state.settingsPicker.breakerAutoKillResetMs,
|
|
17137
17316
|
state.settingsPicker.showModelReasoning,
|
|
17138
17317
|
state.settingsPicker.showAgentSwarmPanel,
|
|
17318
|
+
state.settingsPicker.readSymbols,
|
|
17139
17319
|
saveSettings
|
|
17140
17320
|
]);
|
|
17141
17321
|
}
|
|
@@ -17248,6 +17428,25 @@ function useStableKeyHandler(handleKey) {
|
|
|
17248
17428
|
import * as fs3 from "node:fs/promises";
|
|
17249
17429
|
import { getContextBreakdown } from "@wrongstack/core/utils";
|
|
17250
17430
|
import { useEffect as useEffect35, useMemo as useMemo7, useState as useState14 } from "react";
|
|
17431
|
+
|
|
17432
|
+
// src/context-fill.ts
|
|
17433
|
+
function resolveContextFill(inputs) {
|
|
17434
|
+
const { loopReportedTokens, perRequestTokens, localEstimate, maxContext } = inputs;
|
|
17435
|
+
const ceiling = maxContext > 0 ? maxContext : Number.POSITIVE_INFINITY;
|
|
17436
|
+
const clamp2 = (n) => Math.max(0, Math.min(n, ceiling));
|
|
17437
|
+
if (typeof loopReportedTokens === "number" && loopReportedTokens > 0) {
|
|
17438
|
+
return { used: clamp2(loopReportedTokens), needsLocalEstimate: false, source: "loop" };
|
|
17439
|
+
}
|
|
17440
|
+
if (perRequestTokens > 0 && perRequestTokens <= ceiling) {
|
|
17441
|
+
return { used: clamp2(perRequestTokens), needsLocalEstimate: false, source: "provider" };
|
|
17442
|
+
}
|
|
17443
|
+
if (typeof localEstimate === "number" && localEstimate > 0) {
|
|
17444
|
+
return { used: clamp2(localEstimate), needsLocalEstimate: true, source: "local" };
|
|
17445
|
+
}
|
|
17446
|
+
return { used: 0, needsLocalEstimate: true, source: "none" };
|
|
17447
|
+
}
|
|
17448
|
+
|
|
17449
|
+
// src/hooks/use-statusbar-view-model.ts
|
|
17251
17450
|
function samePlanCounts(a, b) {
|
|
17252
17451
|
return a === b || a !== null && b !== null && a.open === b.open && a.inProgress === b.inProgress && a.done === b.done;
|
|
17253
17452
|
}
|
|
@@ -17267,22 +17466,35 @@ function useStatusbarViewModel({
|
|
|
17267
17466
|
const maxContext = activeMaxContext ?? agent.ctx.provider.capabilities.maxContext;
|
|
17268
17467
|
const perRequest = tokenCounter?.currentRequestTokens();
|
|
17269
17468
|
const perRequestTokens = (perRequest?.input ?? 0) + (perRequest?.cacheRead ?? 0) + (perRequest?.cacheWrite ?? 0);
|
|
17270
|
-
const
|
|
17271
|
-
const
|
|
17272
|
-
const
|
|
17273
|
-
const
|
|
17469
|
+
const loopReportedTokens = state.leader.ctxTokens;
|
|
17470
|
+
const cheapFill = resolveContextFill({ loopReportedTokens, perRequestTokens, maxContext });
|
|
17471
|
+
const needLocalEstimate = cheapFill.needsLocalEstimate;
|
|
17472
|
+
const panelWantsBreakdown = state.contextPanelOpen;
|
|
17473
|
+
const needBreakdown = needLocalEstimate || panelWantsBreakdown;
|
|
17474
|
+
const conversationRevision = agent.ctx.state?.revision ?? 0;
|
|
17475
|
+
const messageCount = agent.ctx.messages?.length ?? 0;
|
|
17476
|
+
const toolDefCount = agent.ctx.tools?.length ?? 0;
|
|
17274
17477
|
const contextBreakdown = useMemo7(() => {
|
|
17275
|
-
if (!
|
|
17478
|
+
if (!needBreakdown) return void 0;
|
|
17276
17479
|
try {
|
|
17277
17480
|
return getContextBreakdown(agent.ctx);
|
|
17278
17481
|
} catch {
|
|
17279
17482
|
return void 0;
|
|
17280
17483
|
}
|
|
17281
|
-
}, [
|
|
17282
|
-
|
|
17283
|
-
|
|
17484
|
+
}, [
|
|
17485
|
+
agent.ctx,
|
|
17486
|
+
needBreakdown,
|
|
17487
|
+
state.contextChipVersion,
|
|
17488
|
+
conversationRevision,
|
|
17489
|
+
messageCount,
|
|
17490
|
+
toolDefCount
|
|
17491
|
+
]);
|
|
17492
|
+
const currentContextTokens = needLocalEstimate ? resolveContextFill({
|
|
17493
|
+
loopReportedTokens,
|
|
17494
|
+
perRequestTokens,
|
|
17495
|
+
localEstimate: contextBreakdown?.total,
|
|
17284
17496
|
maxContext
|
|
17285
|
-
);
|
|
17497
|
+
}).used : cheapFill.used;
|
|
17286
17498
|
const contextWindow = useMemo7(() => {
|
|
17287
17499
|
void state.contextChipVersion;
|
|
17288
17500
|
return maxContext > 0 ? { used: currentContextTokens, max: maxContext } : void 0;
|
|
@@ -18275,6 +18487,9 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
18275
18487
|
/* @__PURE__ */ new Map()
|
|
18276
18488
|
);
|
|
18277
18489
|
const leaderCtxDispatchRef = useRef29(void 0);
|
|
18490
|
+
const leaderCtxFlushRef = useRef29(void 0);
|
|
18491
|
+
const latestLeaderCtxPctRef = useRef29(void 0);
|
|
18492
|
+
const ctxFlushRef = useRef29(/* @__PURE__ */ new Map());
|
|
18278
18493
|
const gate = useFleetGenerationGate(sessionGenerationRef);
|
|
18279
18494
|
const lbl = useCallback19(
|
|
18280
18495
|
(id, name) => labelFor2(labelsRef, id, name),
|
|
@@ -18375,6 +18590,11 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
18375
18590
|
seen.delete(e.subagentId);
|
|
18376
18591
|
labelsRef.current.delete(e.subagentId);
|
|
18377
18592
|
ctxDispatchRef.current.delete(e.subagentId);
|
|
18593
|
+
const pendingFlush = ctxFlushRef.current.get(e.subagentId);
|
|
18594
|
+
if (pendingFlush) {
|
|
18595
|
+
clearTimeout(pendingFlush);
|
|
18596
|
+
ctxFlushRef.current.delete(e.subagentId);
|
|
18597
|
+
}
|
|
18378
18598
|
gate.forget(e.subagentId);
|
|
18379
18599
|
dispatch({ type: "fleetRemove", id: e.subagentId });
|
|
18380
18600
|
});
|
|
@@ -18454,22 +18674,41 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
18454
18674
|
if (!isCurrentSession(e.sessionId)) return;
|
|
18455
18675
|
if (!gate.isLive(e.subagentId)) return;
|
|
18456
18676
|
seen.add(e.subagentId);
|
|
18457
|
-
const
|
|
18677
|
+
const emit = () => {
|
|
18678
|
+
ctxDispatchRef.current.set(e.subagentId, {
|
|
18679
|
+
at: Date.now(),
|
|
18680
|
+
load: e.load,
|
|
18681
|
+
tokens: e.tokens,
|
|
18682
|
+
max: e.maxContext
|
|
18683
|
+
});
|
|
18684
|
+
dispatch({
|
|
18685
|
+
type: "fleetCtxPct",
|
|
18686
|
+
id: e.subagentId,
|
|
18687
|
+
load: e.load,
|
|
18688
|
+
tokens: e.tokens,
|
|
18689
|
+
maxContext: e.maxContext
|
|
18690
|
+
});
|
|
18691
|
+
};
|
|
18458
18692
|
const previous = ctxDispatchRef.current.get(e.subagentId);
|
|
18459
|
-
|
|
18460
|
-
|
|
18461
|
-
|
|
18462
|
-
|
|
18463
|
-
|
|
18464
|
-
|
|
18465
|
-
|
|
18466
|
-
|
|
18467
|
-
|
|
18468
|
-
|
|
18469
|
-
|
|
18470
|
-
|
|
18471
|
-
|
|
18472
|
-
|
|
18693
|
+
const elapsed = previous ? Date.now() - previous.at : Number.POSITIVE_INFINITY;
|
|
18694
|
+
if (elapsed < 250) {
|
|
18695
|
+
const pending2 = ctxFlushRef.current.get(e.subagentId);
|
|
18696
|
+
if (pending2) clearTimeout(pending2);
|
|
18697
|
+
const timer = setTimeout(() => {
|
|
18698
|
+
ctxFlushRef.current.delete(e.subagentId);
|
|
18699
|
+
if (!gate.isLive(e.subagentId)) return;
|
|
18700
|
+
emit();
|
|
18701
|
+
}, 250 - elapsed);
|
|
18702
|
+
timer.unref?.();
|
|
18703
|
+
ctxFlushRef.current.set(e.subagentId, timer);
|
|
18704
|
+
return;
|
|
18705
|
+
}
|
|
18706
|
+
const pending = ctxFlushRef.current.get(e.subagentId);
|
|
18707
|
+
if (pending) {
|
|
18708
|
+
clearTimeout(pending);
|
|
18709
|
+
ctxFlushRef.current.delete(e.subagentId);
|
|
18710
|
+
}
|
|
18711
|
+
emit();
|
|
18473
18712
|
});
|
|
18474
18713
|
const offConcurrencyChanged = events.on("concurrency.changed", (e) => {
|
|
18475
18714
|
const { n, sessionId } = e;
|
|
@@ -18480,17 +18719,40 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
18480
18719
|
});
|
|
18481
18720
|
const offLeaderCtxPct = events.on("ctx.pct", (e) => {
|
|
18482
18721
|
if (!isCurrentSession(e.sessionId)) return;
|
|
18483
|
-
|
|
18484
|
-
const
|
|
18485
|
-
|
|
18486
|
-
|
|
18487
|
-
|
|
18488
|
-
|
|
18489
|
-
|
|
18490
|
-
|
|
18722
|
+
latestLeaderCtxPctRef.current = e;
|
|
18723
|
+
const emit = () => {
|
|
18724
|
+
const latest = latestLeaderCtxPctRef.current ?? e;
|
|
18725
|
+
leaderCtxDispatchRef.current = {
|
|
18726
|
+
at: Date.now(),
|
|
18727
|
+
load: latest.load,
|
|
18728
|
+
tokens: latest.tokens,
|
|
18729
|
+
max: latest.maxContext
|
|
18730
|
+
};
|
|
18731
|
+
setActiveMaxContext(latest.maxContext);
|
|
18732
|
+
dispatch({
|
|
18733
|
+
type: "leaderCtxPct",
|
|
18734
|
+
load: latest.load,
|
|
18735
|
+
tokens: latest.tokens,
|
|
18736
|
+
maxContext: latest.maxContext
|
|
18737
|
+
});
|
|
18491
18738
|
};
|
|
18492
|
-
|
|
18493
|
-
|
|
18739
|
+
const previous = leaderCtxDispatchRef.current;
|
|
18740
|
+
const elapsed = previous ? Date.now() - previous.at : Number.POSITIVE_INFINITY;
|
|
18741
|
+
if (elapsed < 250) {
|
|
18742
|
+
if (leaderCtxFlushRef.current) clearTimeout(leaderCtxFlushRef.current);
|
|
18743
|
+
const timer = setTimeout(() => {
|
|
18744
|
+
leaderCtxFlushRef.current = void 0;
|
|
18745
|
+
emit();
|
|
18746
|
+
}, 250 - elapsed);
|
|
18747
|
+
timer.unref?.();
|
|
18748
|
+
leaderCtxFlushRef.current = timer;
|
|
18749
|
+
return;
|
|
18750
|
+
}
|
|
18751
|
+
if (leaderCtxFlushRef.current) {
|
|
18752
|
+
clearTimeout(leaderCtxFlushRef.current);
|
|
18753
|
+
leaderCtxFlushRef.current = void 0;
|
|
18754
|
+
}
|
|
18755
|
+
emit();
|
|
18494
18756
|
});
|
|
18495
18757
|
const offLeaderMaxContext = events.on("ctx.max_context", (e) => {
|
|
18496
18758
|
if (!isCurrentSession(e.sessionId)) return;
|
|
@@ -18527,6 +18789,12 @@ function useSubagentEvents(events, dispatch, setActiveMaxContext, getSessionId,
|
|
|
18527
18789
|
offLeaderMaxContext();
|
|
18528
18790
|
offCompactionFired();
|
|
18529
18791
|
offTool();
|
|
18792
|
+
if (leaderCtxFlushRef.current) {
|
|
18793
|
+
clearTimeout(leaderCtxFlushRef.current);
|
|
18794
|
+
leaderCtxFlushRef.current = void 0;
|
|
18795
|
+
}
|
|
18796
|
+
for (const timer of ctxFlushRef.current.values()) clearTimeout(timer);
|
|
18797
|
+
ctxFlushRef.current.clear();
|
|
18530
18798
|
for (const id of seen) {
|
|
18531
18799
|
labelsRef.current.delete(id);
|
|
18532
18800
|
ctxDispatchRef.current.delete(id);
|
|
@@ -25213,383 +25481,8 @@ function AuthPanel({ panel }) {
|
|
|
25213
25481
|
] });
|
|
25214
25482
|
}
|
|
25215
25483
|
|
|
25216
|
-
// src/components/connections-panel.tsx
|
|
25217
|
-
import { useCallback as useCallback24, useEffect as useEffect61, useRef as useRef33, useState as useState34 } from "react";
|
|
25218
|
-
|
|
25219
|
-
// src/connections-health.ts
|
|
25220
|
-
import { createChronicleProjectAccess } from "@wrongstack/core/chronicle";
|
|
25221
|
-
import {
|
|
25222
|
-
isMailboxProjectServerAvailable,
|
|
25223
|
-
MailboxProjectServerConnection
|
|
25224
|
-
} from "@wrongstack/core/coordination";
|
|
25225
|
-
import { resolveWstackPaths as resolveWstackPaths5 } from "@wrongstack/core/utils";
|
|
25226
|
-
import { getKanbanServerConnection } from "@wrongstack/kanban";
|
|
25227
|
-
import { isSageProjectServerAvailable, SageProjectServerConnection } from "@wrongstack/sage";
|
|
25228
|
-
import { checkCodebaseIndexServerHealth, getIndexState as getIndexState2 } from "@wrongstack/tools";
|
|
25229
|
-
async function collectConnectionsHealth(projectRoot) {
|
|
25230
|
-
const services = await Promise.all([
|
|
25231
|
-
chronicleHealth(projectRoot),
|
|
25232
|
-
codebaseIndexHealth(projectRoot),
|
|
25233
|
-
sageHealth(projectRoot),
|
|
25234
|
-
kanbanHealth(projectRoot),
|
|
25235
|
-
mailboxHealth(projectRoot)
|
|
25236
|
-
]);
|
|
25237
|
-
const required = services.filter((s2) => s2.required);
|
|
25238
|
-
const overall = required.some((s2) => s2.status === "error") ? "error" : required.some((s2) => s2.status !== "healthy") ? "degraded" : "healthy";
|
|
25239
|
-
return { checkedAt: Date.now(), overall, services };
|
|
25240
|
-
}
|
|
25241
|
-
async function chronicleHealth(projectRoot) {
|
|
25242
|
-
const startedAt = Date.now();
|
|
25243
|
-
let access;
|
|
25244
|
-
try {
|
|
25245
|
-
access = createChronicleProjectAccess({ projectRoot });
|
|
25246
|
-
const health2 = await access.call("ping", {}, { timeoutMs: 5e3 });
|
|
25247
|
-
const quarantined = health2.quarantinedFamilies ?? [];
|
|
25248
|
-
return {
|
|
25249
|
-
id: "chronicle",
|
|
25250
|
-
label: "Chronicle telemetry",
|
|
25251
|
-
status: quarantined.length > 0 ? "degraded" : access.mode === "server" ? "healthy" : "degraded",
|
|
25252
|
-
required: true,
|
|
25253
|
-
mode: access.mode,
|
|
25254
|
-
detail: quarantined.length > 0 ? `Serving, but ${quarantined.length} day(s) were quarantined for a broken chain: ${quarantined.map((family) => family.day).join(", ")}.` : access.mode === "server" ? "One project owner collects, processes, stores, and serves telemetry." : "Inline fallback is active; ownership is not shared across clients.",
|
|
25255
|
-
ownerPid: health2.pid,
|
|
25256
|
-
endpoint: health2.endpoint,
|
|
25257
|
-
storage: health2.chronicleDirectory,
|
|
25258
|
-
uptimeMs: health2.uptimeMs,
|
|
25259
|
-
latencyMs: Date.now() - startedAt,
|
|
25260
|
-
clients: health2.clients,
|
|
25261
|
-
activeRequests: health2.activeRequests,
|
|
25262
|
-
queuedWork: health2.journal.pendingEvents,
|
|
25263
|
-
watcher: { active: health2.watcher.active, watchedFiles: health2.watcher.watchedFiles },
|
|
25264
|
-
...quarantined[0] ? { lastError: quarantined[0].reason } : health2.watcher.lastError ? { lastError: health2.watcher.lastError } : {}
|
|
25265
|
-
};
|
|
25266
|
-
} catch (error) {
|
|
25267
|
-
return failureService("chronicle", "Chronicle telemetry", true, access?.mode ?? "unavailable", error, Date.now() - startedAt);
|
|
25268
|
-
} finally {
|
|
25269
|
-
await access?.close();
|
|
25270
|
-
}
|
|
25271
|
-
}
|
|
25272
|
-
async function codebaseIndexHealth(projectRoot) {
|
|
25273
|
-
const startedAt = Date.now();
|
|
25274
|
-
try {
|
|
25275
|
-
const health2 = await checkCodebaseIndexServerHealth(projectRoot, void 0, { timeoutMs: 2e3 });
|
|
25276
|
-
const connection = getIndexState2().server;
|
|
25277
|
-
return {
|
|
25278
|
-
id: "codebase-index",
|
|
25279
|
-
label: "Codebase index",
|
|
25280
|
-
status: health2.status === "unresponsive" ? "error" : health2.status,
|
|
25281
|
-
required: false,
|
|
25282
|
-
mode: "project-server",
|
|
25283
|
-
detail: health2.server?.activity.indexing ? `Indexing ${health2.server.activity.currentFile}/${health2.server.activity.totalFiles}.` : "Shared symbol index is ready for project queries.",
|
|
25284
|
-
ownerPid: connection.pid,
|
|
25285
|
-
endpoint: connection.endpoint,
|
|
25286
|
-
storage: connection.indexDir ?? resolveWstackPaths5({ projectRoot }).projectCodebaseIndex,
|
|
25287
|
-
uptimeMs: health2.server?.uptimeMs,
|
|
25288
|
-
latencyMs: health2.latencyMs ?? Date.now() - startedAt,
|
|
25289
|
-
clients: health2.server?.clients,
|
|
25290
|
-
activeRequests: health2.server?.activeRequests,
|
|
25291
|
-
queuedWork: health2.server?.queuedWrites,
|
|
25292
|
-
watcher: health2.server ? { active: health2.server.watchingExternal, watchedFiles: health2.server.watchingClients } : void 0
|
|
25293
|
-
};
|
|
25294
|
-
} catch (error) {
|
|
25295
|
-
if (isOfflineConnectionError(error)) {
|
|
25296
|
-
return {
|
|
25297
|
-
...failureService("codebase-index", "Codebase index", false, "on-demand project-server", error, Date.now() - startedAt),
|
|
25298
|
-
status: "offline",
|
|
25299
|
-
detail: "Not running for this project; it starts on demand when indexing is used."
|
|
25300
|
-
};
|
|
25301
|
-
}
|
|
25302
|
-
return failureService("codebase-index", "Codebase index", false, "project-server", error, Date.now() - startedAt);
|
|
25303
|
-
}
|
|
25304
|
-
}
|
|
25305
|
-
async function sageHealth(projectRoot) {
|
|
25306
|
-
const startedAt = Date.now();
|
|
25307
|
-
if (!isSageProjectServerAvailable()) {
|
|
25308
|
-
return {
|
|
25309
|
-
id: "sage",
|
|
25310
|
-
label: "SAGE memory",
|
|
25311
|
-
status: "unavailable",
|
|
25312
|
-
required: false,
|
|
25313
|
-
mode: "unavailable",
|
|
25314
|
-
detail: "The packaged SAGE project server is unavailable in this runtime."
|
|
25315
|
-
};
|
|
25316
|
-
}
|
|
25317
|
-
const connection = new SageProjectServerConnection(projectRoot);
|
|
25318
|
-
try {
|
|
25319
|
-
const status = await connection.status();
|
|
25320
|
-
if (!status) {
|
|
25321
|
-
return {
|
|
25322
|
-
id: "sage",
|
|
25323
|
-
label: "SAGE memory",
|
|
25324
|
-
status: "offline",
|
|
25325
|
-
required: false,
|
|
25326
|
-
mode: "on-demand project-server",
|
|
25327
|
-
detail: "Not running for this project; it starts on demand when memory is used.",
|
|
25328
|
-
endpoint: connection.getState().endpoint,
|
|
25329
|
-
latencyMs: Date.now() - startedAt
|
|
25330
|
-
};
|
|
25331
|
-
}
|
|
25332
|
-
const healthStatus = status.health.status === "ready" ? "healthy" : status.health.status === "degraded" ? "degraded" : "error";
|
|
25333
|
-
return {
|
|
25334
|
-
id: "sage",
|
|
25335
|
-
label: "SAGE memory",
|
|
25336
|
-
status: healthStatus,
|
|
25337
|
-
required: false,
|
|
25338
|
-
mode: "project-server",
|
|
25339
|
-
detail: `Persistent project memory backend: ${status.health.backend}.`,
|
|
25340
|
-
ownerPid: status.pid,
|
|
25341
|
-
endpoint: status.endpoint,
|
|
25342
|
-
storage: status.storageRoot,
|
|
25343
|
-
latencyMs: Date.now() - startedAt,
|
|
25344
|
-
clients: status.clients,
|
|
25345
|
-
activeRequests: status.pendingRequests
|
|
25346
|
-
};
|
|
25347
|
-
} catch (error) {
|
|
25348
|
-
return failureService("sage", "SAGE memory", false, "project-server", error, Date.now() - startedAt);
|
|
25349
|
-
} finally {
|
|
25350
|
-
connection.close();
|
|
25351
|
-
}
|
|
25352
|
-
}
|
|
25353
|
-
async function kanbanHealth(projectRoot) {
|
|
25354
|
-
const startedAt = Date.now();
|
|
25355
|
-
if (process.env["WRONGSTACK_KANBAN_SERVER"] === "0") {
|
|
25356
|
-
return {
|
|
25357
|
-
id: "kanban",
|
|
25358
|
-
label: "Kanban IPC",
|
|
25359
|
-
status: "unavailable",
|
|
25360
|
-
required: false,
|
|
25361
|
-
mode: "disabled",
|
|
25362
|
-
detail: "Kanban IPC daemon is disabled via WRONGSTACK_KANBAN_SERVER=0."
|
|
25363
|
-
};
|
|
25364
|
-
}
|
|
25365
|
-
let connection;
|
|
25366
|
-
try {
|
|
25367
|
-
connection = await getKanbanServerConnection(projectRoot);
|
|
25368
|
-
} catch (error) {
|
|
25369
|
-
return failureService("kanban", "Kanban IPC", false, "project-server", error, Date.now() - startedAt);
|
|
25370
|
-
}
|
|
25371
|
-
if (!connection) {
|
|
25372
|
-
return {
|
|
25373
|
-
id: "kanban",
|
|
25374
|
-
label: "Kanban IPC",
|
|
25375
|
-
status: "unavailable",
|
|
25376
|
-
required: false,
|
|
25377
|
-
mode: "disabled",
|
|
25378
|
-
detail: "Kanban IPC daemon is disabled in this runtime."
|
|
25379
|
-
};
|
|
25380
|
-
}
|
|
25381
|
-
try {
|
|
25382
|
-
const status = await connection.request("ping", {}, { timeoutMs: 5e3 });
|
|
25383
|
-
return {
|
|
25384
|
-
id: "kanban",
|
|
25385
|
-
label: "Kanban IPC",
|
|
25386
|
-
status: "healthy",
|
|
25387
|
-
required: true,
|
|
25388
|
-
mode: "project-server",
|
|
25389
|
-
detail: `Single shared project-server owns kanban state (v${status.protocolVersion}).`,
|
|
25390
|
-
ownerPid: status.pid,
|
|
25391
|
-
endpoint: status.endpoint,
|
|
25392
|
-
storage: status.databasePath,
|
|
25393
|
-
latencyMs: Date.now() - startedAt,
|
|
25394
|
-
clients: status.clients,
|
|
25395
|
-
activeRequests: status.pendingRequests,
|
|
25396
|
-
uptimeMs: Date.now() - new Date(status.startedAt).getTime()
|
|
25397
|
-
};
|
|
25398
|
-
} catch (error) {
|
|
25399
|
-
return failureService("kanban", "Kanban IPC", true, "project-server", error, Date.now() - startedAt);
|
|
25400
|
-
}
|
|
25401
|
-
}
|
|
25402
|
-
async function mailboxHealth(projectRoot) {
|
|
25403
|
-
const startedAt = Date.now();
|
|
25404
|
-
if (!isMailboxProjectServerAvailable()) {
|
|
25405
|
-
return {
|
|
25406
|
-
id: "mailbox",
|
|
25407
|
-
label: "Mailbox IPC",
|
|
25408
|
-
status: "unavailable",
|
|
25409
|
-
required: false,
|
|
25410
|
-
mode: "unavailable",
|
|
25411
|
-
detail: "The packaged mailbox project server is unavailable in this runtime."
|
|
25412
|
-
};
|
|
25413
|
-
}
|
|
25414
|
-
const connection = new MailboxProjectServerConnection(
|
|
25415
|
-
resolveWstackPaths5({ projectRoot }).projectDir
|
|
25416
|
-
);
|
|
25417
|
-
try {
|
|
25418
|
-
const status = await connection.probeStatus();
|
|
25419
|
-
if (!status) {
|
|
25420
|
-
return {
|
|
25421
|
-
id: "mailbox",
|
|
25422
|
-
label: "Mailbox IPC",
|
|
25423
|
-
status: "offline",
|
|
25424
|
-
required: false,
|
|
25425
|
-
mode: "on-demand project-server",
|
|
25426
|
-
detail: "Not running for this project; it starts on demand when mailbox is used.",
|
|
25427
|
-
endpoint: connection.getState().endpoint,
|
|
25428
|
-
latencyMs: Date.now() - startedAt
|
|
25429
|
-
};
|
|
25430
|
-
}
|
|
25431
|
-
return {
|
|
25432
|
-
id: "mailbox",
|
|
25433
|
-
label: "Mailbox IPC",
|
|
25434
|
-
status: "healthy",
|
|
25435
|
-
required: true,
|
|
25436
|
-
mode: "project-server",
|
|
25437
|
-
detail: `Single shared project-server owns inter-agent mailbox state (v${status.protocolVersion}).`,
|
|
25438
|
-
ownerPid: status.pid,
|
|
25439
|
-
endpoint: status.endpoint,
|
|
25440
|
-
storage: status.databasePath,
|
|
25441
|
-
latencyMs: Date.now() - startedAt,
|
|
25442
|
-
clients: status.clients,
|
|
25443
|
-
activeRequests: status.pendingRequests,
|
|
25444
|
-
uptimeMs: Date.now() - new Date(status.startedAt).getTime()
|
|
25445
|
-
};
|
|
25446
|
-
} catch (error) {
|
|
25447
|
-
return failureService("mailbox", "Mailbox IPC", true, "project-server", error, Date.now() - startedAt);
|
|
25448
|
-
} finally {
|
|
25449
|
-
connection.close();
|
|
25450
|
-
}
|
|
25451
|
-
}
|
|
25452
|
-
function isOfflineConnectionError(error) {
|
|
25453
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
25454
|
-
return /(?:ENOENT|ECONNREFUSED|not found|not running|unavailable|connect failed)/iu.test(message);
|
|
25455
|
-
}
|
|
25456
|
-
function failureService(id, label, required, mode, error, latencyMs) {
|
|
25457
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
25458
|
-
return {
|
|
25459
|
-
id,
|
|
25460
|
-
label,
|
|
25461
|
-
status: "error",
|
|
25462
|
-
required,
|
|
25463
|
-
mode,
|
|
25464
|
-
detail: message,
|
|
25465
|
-
lastError: message,
|
|
25466
|
-
...latencyMs === void 0 ? {} : { latencyMs }
|
|
25467
|
-
};
|
|
25468
|
-
}
|
|
25469
|
-
|
|
25470
|
-
// src/components/connections-panel.tsx
|
|
25471
|
-
import { jsx as jsx40, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
25472
|
-
var REFRESH_MS = 8e3;
|
|
25473
|
-
var STATUS_GLYPH = {
|
|
25474
|
-
healthy: "\u25CF",
|
|
25475
|
-
degraded: "\u25D0",
|
|
25476
|
-
offline: "\u25CB",
|
|
25477
|
-
unavailable: "\u2298",
|
|
25478
|
-
error: "\u2717"
|
|
25479
|
-
};
|
|
25480
|
-
var STATUS_COLOR2 = {
|
|
25481
|
-
healthy: "green",
|
|
25482
|
-
degraded: "yellow",
|
|
25483
|
-
offline: "gray",
|
|
25484
|
-
unavailable: "gray",
|
|
25485
|
-
error: "red"
|
|
25486
|
-
};
|
|
25487
|
-
var OVERALL_COLOR = {
|
|
25488
|
-
healthy: "green",
|
|
25489
|
-
degraded: "yellow",
|
|
25490
|
-
error: "red"
|
|
25491
|
-
};
|
|
25492
|
-
function formatUptime(ms) {
|
|
25493
|
-
if (ms < 1e3) return `${ms}ms`;
|
|
25494
|
-
const s2 = Math.floor(ms / 1e3);
|
|
25495
|
-
if (s2 < 60) return `${s2}s`;
|
|
25496
|
-
const m = Math.floor(s2 / 60);
|
|
25497
|
-
if (m < 60) return `${m}m`;
|
|
25498
|
-
const h = Math.floor(m / 60);
|
|
25499
|
-
return h < 24 ? `${h}h` : `${Math.floor(h / 24)}d`;
|
|
25500
|
-
}
|
|
25501
|
-
function formatLatency(ms) {
|
|
25502
|
-
if (ms === void 0) return null;
|
|
25503
|
-
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
25504
|
-
return `${(ms / 1e3).toFixed(1)}s`;
|
|
25505
|
-
}
|
|
25506
|
-
function ServiceRow({ service }) {
|
|
25507
|
-
const glyph2 = STATUS_GLYPH[service.status];
|
|
25508
|
-
const color = STATUS_COLOR2[service.status];
|
|
25509
|
-
const latency = formatLatency(service.latencyMs);
|
|
25510
|
-
const metaParts = [];
|
|
25511
|
-
if (service.ownerPid !== void 0) metaParts.push(`PID ${service.ownerPid}`);
|
|
25512
|
-
if (service.clients !== void 0) metaParts.push(`${service.clients} client${service.clients === 1 ? "" : "s"}`);
|
|
25513
|
-
if (service.activeRequests !== void 0 && service.activeRequests > 0) {
|
|
25514
|
-
metaParts.push(`${service.activeRequests} active`);
|
|
25515
|
-
}
|
|
25516
|
-
if (service.uptimeMs !== void 0) metaParts.push(`up ${formatUptime(service.uptimeMs)}`);
|
|
25517
|
-
if (latency) metaParts.push(`${latency}`);
|
|
25518
|
-
if (service.queuedWork !== void 0 && service.queuedWork > 0) {
|
|
25519
|
-
metaParts.push(`${service.queuedWork} queued`);
|
|
25520
|
-
}
|
|
25521
|
-
return /* @__PURE__ */ jsxs39(Box, { flexDirection: "column", marginTop: 0, children: [
|
|
25522
|
-
/* @__PURE__ */ jsxs39(Box, { gap: 1, children: [
|
|
25523
|
-
/* @__PURE__ */ jsx40(Text, { color, children: glyph2 }),
|
|
25524
|
-
/* @__PURE__ */ jsx40(Text, { bold: true, children: service.label }),
|
|
25525
|
-
service.required ? /* @__PURE__ */ jsx40(Text, { dimColor: true, children: "required" }) : null,
|
|
25526
|
-
/* @__PURE__ */ jsxs39(Text, { dimColor: true, children: [
|
|
25527
|
-
"\xB7 ",
|
|
25528
|
-
service.mode
|
|
25529
|
-
] })
|
|
25530
|
-
] }),
|
|
25531
|
-
/* @__PURE__ */ jsx40(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx40(Text, { dimColor: true, children: service.detail }) }),
|
|
25532
|
-
metaParts.length > 0 ? /* @__PURE__ */ jsx40(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx40(Text, { dimColor: true, children: metaParts.join(" \xB7 ") }) }) : null
|
|
25533
|
-
] });
|
|
25534
|
-
}
|
|
25535
|
-
function ConnectionsPanel({ projectRoot, onClose }) {
|
|
25536
|
-
const [report, setReport] = useState34(null);
|
|
25537
|
-
const [loading, setLoading] = useState34(true);
|
|
25538
|
-
const [error, setError] = useState34(null);
|
|
25539
|
-
const cancelledRef = useRef33(false);
|
|
25540
|
-
const fetch = useCallback24(async () => {
|
|
25541
|
-
try {
|
|
25542
|
-
const r = await collectConnectionsHealth(projectRoot);
|
|
25543
|
-
if (cancelledRef.current) return;
|
|
25544
|
-
setReport(r);
|
|
25545
|
-
setError(null);
|
|
25546
|
-
} catch (e) {
|
|
25547
|
-
if (cancelledRef.current) return;
|
|
25548
|
-
setError(e instanceof Error ? e.message : String(e));
|
|
25549
|
-
} finally {
|
|
25550
|
-
if (!cancelledRef.current) setLoading(false);
|
|
25551
|
-
}
|
|
25552
|
-
}, [projectRoot]);
|
|
25553
|
-
useEffect61(() => {
|
|
25554
|
-
cancelledRef.current = false;
|
|
25555
|
-
void fetch();
|
|
25556
|
-
const timer = setInterval(() => void fetch(), REFRESH_MS);
|
|
25557
|
-
return () => {
|
|
25558
|
-
cancelledRef.current = true;
|
|
25559
|
-
clearInterval(timer);
|
|
25560
|
-
};
|
|
25561
|
-
}, [fetch]);
|
|
25562
|
-
useInput((_input, key) => {
|
|
25563
|
-
if (key.escape || _input === "q") onClose();
|
|
25564
|
-
if (_input === "r") void fetch();
|
|
25565
|
-
});
|
|
25566
|
-
const overallLabel = report ? report.overall === "healthy" ? "All required services healthy" : report.overall === "degraded" ? "Some services degraded" : "Service errors detected" : "Checking\u2026";
|
|
25567
|
-
return /* @__PURE__ */ jsxs39(Box, { flexDirection: "column", borderStyle: "round", borderColor: report ? OVERALL_COLOR[report.overall] : "gray", paddingX: 1, marginY: 0, flexShrink: 0, children: [
|
|
25568
|
-
/* @__PURE__ */ jsxs39(Box, { justifyContent: "space-between", children: [
|
|
25569
|
-
/* @__PURE__ */ jsxs39(Box, { gap: 1, children: [
|
|
25570
|
-
/* @__PURE__ */ jsx40(Text, { bold: true, children: "Service Connections" }),
|
|
25571
|
-
report ? /* @__PURE__ */ jsxs39(Text, { color: OVERALL_COLOR[report.overall], children: [
|
|
25572
|
-
"\u25CF ",
|
|
25573
|
-
overallLabel
|
|
25574
|
-
] }) : null
|
|
25575
|
-
] }),
|
|
25576
|
-
/* @__PURE__ */ jsx40(Text, { dimColor: true, children: "Esc/q close \xB7 r refresh" })
|
|
25577
|
-
] }),
|
|
25578
|
-
loading && !report ? /* @__PURE__ */ jsx40(Box, { paddingY: 1, children: /* @__PURE__ */ jsx40(Text, { dimColor: true, children: "Checking service health\u2026" }) }) : null,
|
|
25579
|
-
error ? /* @__PURE__ */ jsx40(Box, { paddingY: 1, children: /* @__PURE__ */ jsxs39(Text, { color: "red", children: [
|
|
25580
|
-
"Error: ",
|
|
25581
|
-
error
|
|
25582
|
-
] }) }) : null,
|
|
25583
|
-
report ? /* @__PURE__ */ jsx40(Box, { flexDirection: "column", marginTop: 0, children: report.services.map((s2) => /* @__PURE__ */ jsx40(ServiceRow, { service: s2 }, s2.id)) }) : null,
|
|
25584
|
-
report ? /* @__PURE__ */ jsx40(Box, { marginTop: 0, children: /* @__PURE__ */ jsxs39(Text, { dimColor: true, children: [
|
|
25585
|
-
"Last checked ",
|
|
25586
|
-
new Date(report.checkedAt).toLocaleTimeString()
|
|
25587
|
-
] }) }) : null
|
|
25588
|
-
] });
|
|
25589
|
-
}
|
|
25590
|
-
|
|
25591
25484
|
// src/components/brain-decision-prompt.tsx
|
|
25592
|
-
import { jsx as
|
|
25485
|
+
import { jsx as jsx40, jsxs as jsxs39 } from "react/jsx-runtime";
|
|
25593
25486
|
function riskColor(risk) {
|
|
25594
25487
|
switch (risk) {
|
|
25595
25488
|
case "low":
|
|
@@ -25634,54 +25527,54 @@ function BrainDecisionPrompt({
|
|
|
25634
25527
|
const option = Number.isInteger(index) && index >= 0 ? options[index] : void 0;
|
|
25635
25528
|
if (option) onAnswer({ id: requestId, optionId: option.id, text: option.label });
|
|
25636
25529
|
});
|
|
25637
|
-
return /* @__PURE__ */
|
|
25638
|
-
/* @__PURE__ */
|
|
25639
|
-
/* @__PURE__ */
|
|
25640
|
-
/* @__PURE__ */
|
|
25641
|
-
/* @__PURE__ */
|
|
25642
|
-
/* @__PURE__ */
|
|
25643
|
-
/* @__PURE__ */
|
|
25530
|
+
return /* @__PURE__ */ jsxs39(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
|
|
25531
|
+
/* @__PURE__ */ jsx40(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx40(Text, { bold: true, color: "magenta", children: "\u{1F9E0} BRAIN REQUIRES HUMAN DECISION" }) }),
|
|
25532
|
+
/* @__PURE__ */ jsxs39(Box, { flexDirection: "row", gap: 1, children: [
|
|
25533
|
+
/* @__PURE__ */ jsx40(Text, { dimColor: true, children: "Source:" }),
|
|
25534
|
+
/* @__PURE__ */ jsx40(Text, { children: source }),
|
|
25535
|
+
/* @__PURE__ */ jsx40(Text, { dimColor: true, children: "Risk:" }),
|
|
25536
|
+
/* @__PURE__ */ jsx40(Text, { color, children: risk })
|
|
25644
25537
|
] }),
|
|
25645
|
-
/* @__PURE__ */
|
|
25646
|
-
ctx.length > 0 ? /* @__PURE__ */
|
|
25647
|
-
/* @__PURE__ */
|
|
25648
|
-
ctx.map((line, index) => /* @__PURE__ */
|
|
25649
|
-
dropped > 0 ? /* @__PURE__ */
|
|
25538
|
+
/* @__PURE__ */ jsx40(Text, { color: "white", children: question }),
|
|
25539
|
+
ctx.length > 0 ? /* @__PURE__ */ jsxs39(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
25540
|
+
/* @__PURE__ */ jsx40(Text, { dimColor: true, children: "Context:" }),
|
|
25541
|
+
ctx.map((line, index) => /* @__PURE__ */ jsx40(Text, { dimColor: true, children: line }, index)),
|
|
25542
|
+
dropped > 0 ? /* @__PURE__ */ jsxs39(Text, { dimColor: true, children: [
|
|
25650
25543
|
"\u2026 (",
|
|
25651
25544
|
dropped,
|
|
25652
25545
|
" more)"
|
|
25653
25546
|
] }) : null
|
|
25654
25547
|
] }) : null,
|
|
25655
|
-
options.length > 0 ? /* @__PURE__ */
|
|
25656
|
-
/* @__PURE__ */
|
|
25548
|
+
options.length > 0 ? /* @__PURE__ */ jsxs39(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
25549
|
+
/* @__PURE__ */ jsx40(Text, { dimColor: true, children: "Options:" }),
|
|
25657
25550
|
options.slice(0, 6).map((option, index) => {
|
|
25658
25551
|
const key = optionKey(index);
|
|
25659
25552
|
const optionColor = riskColor(String(option.risk ?? risk));
|
|
25660
|
-
return /* @__PURE__ */
|
|
25661
|
-
/* @__PURE__ */
|
|
25662
|
-
/* @__PURE__ */
|
|
25553
|
+
return /* @__PURE__ */ jsxs39(Box, { flexDirection: "column", children: [
|
|
25554
|
+
/* @__PURE__ */ jsxs39(Text, { children: [
|
|
25555
|
+
/* @__PURE__ */ jsxs39(Text, { bold: true, color: "yellow", children: [
|
|
25663
25556
|
"[",
|
|
25664
25557
|
key,
|
|
25665
25558
|
"]"
|
|
25666
25559
|
] }),
|
|
25667
25560
|
" ",
|
|
25668
|
-
/* @__PURE__ */
|
|
25669
|
-
option.recommended ? /* @__PURE__ */
|
|
25561
|
+
/* @__PURE__ */ jsx40(Text, { color: optionColor, children: option.label }),
|
|
25562
|
+
option.recommended ? /* @__PURE__ */ jsx40(Text, { color: "green", children: " recommended" }) : null
|
|
25670
25563
|
] }),
|
|
25671
|
-
option.consequence ? /* @__PURE__ */
|
|
25564
|
+
option.consequence ? /* @__PURE__ */ jsxs39(Text, { dimColor: true, children: [
|
|
25672
25565
|
" ",
|
|
25673
25566
|
option.consequence
|
|
25674
25567
|
] }) : null
|
|
25675
25568
|
] }, option.id);
|
|
25676
25569
|
})
|
|
25677
25570
|
] }) : null,
|
|
25678
|
-
/* @__PURE__ */
|
|
25679
|
-
/* @__PURE__ */
|
|
25571
|
+
/* @__PURE__ */ jsx40(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
25572
|
+
/* @__PURE__ */ jsx40(Text, { dimColor: true, children: "Press A/B/C or 1/2/3 to answer; Esc or D denies with the safe default." })
|
|
25680
25573
|
] });
|
|
25681
25574
|
}
|
|
25682
25575
|
|
|
25683
25576
|
// src/components/brain-panel.tsx
|
|
25684
|
-
import { Fragment as Fragment14, jsx as
|
|
25577
|
+
import { Fragment as Fragment14, jsx as jsx41, jsxs as jsxs40 } from "react/jsx-runtime";
|
|
25685
25578
|
var CHROME_ROWS2 = 14;
|
|
25686
25579
|
var RISK_DESCS = {
|
|
25687
25580
|
off: "Human decides everything",
|
|
@@ -25911,19 +25804,19 @@ function BrainPanel({
|
|
|
25911
25804
|
const above = windowStart;
|
|
25912
25805
|
const below = total - windowEnd;
|
|
25913
25806
|
const headerHint = activeView === "settings" ? "\u2191/\u2193 row \xB7 \u2190/\u2192 change \xB7 Enter pick/toggle \xB7 d remove \xB7 Tab log \xB7 Esc close" : editable ? "\u2191/\u2193 navigate log \xB7 Tab settings \xB7 Esc close" : "\u2191/\u2193 navigate log \xB7 \u2190/\u2192 change risk \xB7 Esc close";
|
|
25914
|
-
return /* @__PURE__ */
|
|
25915
|
-
/* @__PURE__ */
|
|
25916
|
-
/* @__PURE__ */
|
|
25917
|
-
activeView === "settings" && settings ? /* @__PURE__ */
|
|
25807
|
+
return /* @__PURE__ */ jsxs40(Box, { flexDirection: "column", borderStyle: "round", borderColor: "magenta", paddingX: 1, children: [
|
|
25808
|
+
/* @__PURE__ */ jsx41(Text, { bold: true, color: "magenta", children: `\u2501\u2501 Brain \u2501\u2501${busy ? " \u2026" : ""}` }),
|
|
25809
|
+
/* @__PURE__ */ jsx41(Text, { dimColor: true, children: headerHint }),
|
|
25810
|
+
activeView === "settings" && settings ? /* @__PURE__ */ jsxs40(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
25918
25811
|
brainPanelRows(settings).map((r, i) => {
|
|
25919
25812
|
const focused = i === (row ?? 0);
|
|
25920
25813
|
const readOnly = BRAIN_READONLY_ROW_KINDS.has(r.kind);
|
|
25921
25814
|
const { label, value, dim } = rowText(r, settings);
|
|
25922
25815
|
const key = `${r.kind}-${"index" in r ? r.index : "key" in r ? r.key : 0}`;
|
|
25923
|
-
return /* @__PURE__ */
|
|
25924
|
-
focused ? /* @__PURE__ */
|
|
25925
|
-
/* @__PURE__ */
|
|
25926
|
-
/* @__PURE__ */
|
|
25816
|
+
return /* @__PURE__ */ jsxs40(Text, { wrap: "truncate-end", children: [
|
|
25817
|
+
focused ? /* @__PURE__ */ jsx41(Text, { color: "magenta", children: "\u203A " }) : " ",
|
|
25818
|
+
/* @__PURE__ */ jsx41(Text, { bold: focused, dimColor: readOnly, children: label.padEnd(18) }),
|
|
25819
|
+
/* @__PURE__ */ jsx41(
|
|
25927
25820
|
Text,
|
|
25928
25821
|
{
|
|
25929
25822
|
color: r.kind === "risk" ? RISK_COLORS2[settings.riskLevel] : focused && !readOnly ? "cyan" : void 0,
|
|
@@ -25933,24 +25826,24 @@ function BrainPanel({
|
|
|
25933
25826
|
children: value
|
|
25934
25827
|
}
|
|
25935
25828
|
),
|
|
25936
|
-
dim ? /* @__PURE__ */
|
|
25829
|
+
dim ? /* @__PURE__ */ jsx41(Text, { dimColor: true, children: ` ${dim}` }) : null
|
|
25937
25830
|
] }, key);
|
|
25938
25831
|
}),
|
|
25939
|
-
/* @__PURE__ */
|
|
25940
|
-
] }) : /* @__PURE__ */
|
|
25941
|
-
/* @__PURE__ */
|
|
25942
|
-
/* @__PURE__ */
|
|
25943
|
-
/* @__PURE__ */
|
|
25944
|
-
/* @__PURE__ */
|
|
25832
|
+
/* @__PURE__ */ jsx41(Box, { marginTop: 1, children: /* @__PURE__ */ jsx41(Text, { dimColor: true, children: "changes apply live and persist to the active profile config" }) })
|
|
25833
|
+
] }) : /* @__PURE__ */ jsxs40(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
25834
|
+
/* @__PURE__ */ jsxs40(Box, { children: [
|
|
25835
|
+
/* @__PURE__ */ jsx41(Text, { bold: true, children: "Risk ceiling: " }),
|
|
25836
|
+
/* @__PURE__ */ jsx41(Text, { color: RISK_COLORS2[riskLevel], bold: true, children: riskLevel.toUpperCase() }),
|
|
25837
|
+
/* @__PURE__ */ jsx41(Text, { dimColor: true, children: ` ${RISK_DESCS[riskLevel]}` })
|
|
25945
25838
|
] }),
|
|
25946
|
-
/* @__PURE__ */
|
|
25947
|
-
/* @__PURE__ */
|
|
25948
|
-
total === 0 ? /* @__PURE__ */
|
|
25949
|
-
above > 0 ? /* @__PURE__ */
|
|
25839
|
+
/* @__PURE__ */ jsxs40(Box, { marginTop: 1, flexDirection: "column", children: [
|
|
25840
|
+
/* @__PURE__ */ jsx41(Text, { bold: true, color: "blue", children: "Recent decisions" }),
|
|
25841
|
+
total === 0 ? /* @__PURE__ */ jsx41(Text, { dimColor: true, children: " No decisions recorded yet this session." }) : /* @__PURE__ */ jsxs40(Fragment14, { children: [
|
|
25842
|
+
above > 0 ? /* @__PURE__ */ jsx41(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
25950
25843
|
log.slice(windowStart, windowEnd).map((entry, i) => {
|
|
25951
25844
|
const index = windowStart + i;
|
|
25952
25845
|
const focused = index === selected;
|
|
25953
|
-
return /* @__PURE__ */
|
|
25846
|
+
return /* @__PURE__ */ jsxs40(
|
|
25954
25847
|
Text,
|
|
25955
25848
|
{
|
|
25956
25849
|
inverse: focused,
|
|
@@ -25958,25 +25851,25 @@ function BrainPanel({
|
|
|
25958
25851
|
wrap: "truncate-end",
|
|
25959
25852
|
children: [
|
|
25960
25853
|
focused ? "\u203A " : " ",
|
|
25961
|
-
/* @__PURE__ */
|
|
25962
|
-
/* @__PURE__ */
|
|
25963
|
-
/* @__PURE__ */
|
|
25964
|
-
entry.outcome ? /* @__PURE__ */
|
|
25854
|
+
/* @__PURE__ */ jsx41(Text, { dimColor: true, children: entry.age.padEnd(8) }),
|
|
25855
|
+
/* @__PURE__ */ jsx41(Text, { color: "cyan", children: entry.kind.padEnd(12) }),
|
|
25856
|
+
/* @__PURE__ */ jsx41(Text, { children: entry.question.length > 60 ? `${entry.question.slice(0, 57)}\u2026` : entry.question }),
|
|
25857
|
+
entry.outcome ? /* @__PURE__ */ jsx41(Text, { dimColor: true, children: ` \u2192 ${entry.outcome.length > 20 ? `${entry.outcome.slice(0, 17)}\u2026` : entry.outcome}` }) : null
|
|
25965
25858
|
]
|
|
25966
25859
|
},
|
|
25967
25860
|
`${entry.kind}-${i}`
|
|
25968
25861
|
);
|
|
25969
25862
|
}),
|
|
25970
|
-
below > 0 ? /* @__PURE__ */
|
|
25863
|
+
below > 0 ? /* @__PURE__ */ jsx41(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
25971
25864
|
] })
|
|
25972
25865
|
] })
|
|
25973
25866
|
] }),
|
|
25974
|
-
hint ? /* @__PURE__ */
|
|
25867
|
+
hint ? /* @__PURE__ */ jsx41(Box, { marginTop: 1, children: /* @__PURE__ */ jsx41(Text, { dimColor: true, children: hint }) }) : null
|
|
25975
25868
|
] });
|
|
25976
25869
|
}
|
|
25977
25870
|
|
|
25978
25871
|
// src/components/checkpoint-timeline.tsx
|
|
25979
|
-
import { jsx as
|
|
25872
|
+
import { jsx as jsx42, jsxs as jsxs41 } from "react/jsx-runtime";
|
|
25980
25873
|
function CheckpointTimeline({
|
|
25981
25874
|
checkpoints,
|
|
25982
25875
|
selected,
|
|
@@ -25995,22 +25888,22 @@ function CheckpointTimeline({
|
|
|
25995
25888
|
onConfirm(selected);
|
|
25996
25889
|
}
|
|
25997
25890
|
});
|
|
25998
|
-
return /* @__PURE__ */
|
|
25999
|
-
/* @__PURE__ */
|
|
26000
|
-
/* @__PURE__ */
|
|
26001
|
-
/* @__PURE__ */
|
|
25891
|
+
return /* @__PURE__ */ jsxs41(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, children: [
|
|
25892
|
+
/* @__PURE__ */ jsxs41(Box, { marginBottom: 1, children: [
|
|
25893
|
+
/* @__PURE__ */ jsx42(Text, { bold: true, color: "cyan", children: "\u27F2 Session Rewind" }),
|
|
25894
|
+
/* @__PURE__ */ jsx42(Text, { dimColor: true, children: " \u2014 \u2191/\u2193 navigate \xB7 Enter rewind \xB7 Esc cancel" })
|
|
26002
25895
|
] }),
|
|
26003
|
-
checkpoints.length === 0 ? /* @__PURE__ */
|
|
25896
|
+
checkpoints.length === 0 ? /* @__PURE__ */ jsx42(Text, { dimColor: true, children: "No checkpoints in this session." }) : checkpoints.map((cp, i) => {
|
|
26004
25897
|
const isSelected = i === selected;
|
|
26005
25898
|
const label = `[${cp.promptIndex}] ${cp.promptPreview}`;
|
|
26006
|
-
return /* @__PURE__ */
|
|
26007
|
-
/* @__PURE__ */
|
|
26008
|
-
/* @__PURE__ */
|
|
26009
|
-
/* @__PURE__ */
|
|
25899
|
+
return /* @__PURE__ */ jsxs41(Box, { children: [
|
|
25900
|
+
/* @__PURE__ */ jsx42(Text, { bold: isSelected, ...isSelected ? { color: "cyan" } : {}, children: isSelected ? "\u25B8 " : " " }),
|
|
25901
|
+
/* @__PURE__ */ jsx42(Text, { bold: isSelected, ...isSelected ? { color: "cyan" } : {}, children: label }),
|
|
25902
|
+
/* @__PURE__ */ jsxs41(Text, { dimColor: true, children: [
|
|
26010
25903
|
" ",
|
|
26011
25904
|
new Date(cp.ts).toLocaleTimeString()
|
|
26012
25905
|
] }),
|
|
26013
|
-
cp.fileCount > 0 && /* @__PURE__ */
|
|
25906
|
+
cp.fileCount > 0 && /* @__PURE__ */ jsxs41(Text, { dimColor: true, children: [
|
|
26014
25907
|
" ",
|
|
26015
25908
|
"\xB7 ",
|
|
26016
25909
|
cp.fileCount,
|
|
@@ -26023,7 +25916,7 @@ function CheckpointTimeline({
|
|
|
26023
25916
|
}
|
|
26024
25917
|
|
|
26025
25918
|
// src/components/clear-confirm-panel.tsx
|
|
26026
|
-
import { jsx as
|
|
25919
|
+
import { jsx as jsx43, jsxs as jsxs42 } from "react/jsx-runtime";
|
|
26027
25920
|
function isClearConfirmation(value) {
|
|
26028
25921
|
return value === "YES";
|
|
26029
25922
|
}
|
|
@@ -26049,30 +25942,30 @@ function ClearConfirmPanel({
|
|
|
26049
25942
|
leaderActive ? "leader run" : null,
|
|
26050
25943
|
subagentCount > 0 ? `${subagentCount} sub-agent${subagentCount === 1 ? "" : "s"}` : null
|
|
26051
25944
|
].filter((part) => part !== null);
|
|
26052
|
-
return /* @__PURE__ */
|
|
26053
|
-
/* @__PURE__ */
|
|
26054
|
-
/* @__PURE__ */
|
|
26055
|
-
/* @__PURE__ */
|
|
25945
|
+
return /* @__PURE__ */ jsxs42(Box, { flexDirection: "column", borderStyle: "double", borderColor: "red", paddingX: 1, marginY: 1, children: [
|
|
25946
|
+
/* @__PURE__ */ jsx43(Text, { bold: true, color: "red", children: "\u26A0 CLEAR BLOCKED \u2014 ACTIVE WORK" }),
|
|
25947
|
+
/* @__PURE__ */ jsxs42(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
25948
|
+
/* @__PURE__ */ jsxs42(Text, { children: [
|
|
26056
25949
|
"Still running:",
|
|
26057
25950
|
" ",
|
|
26058
|
-
/* @__PURE__ */
|
|
25951
|
+
/* @__PURE__ */ jsx43(Text, { bold: true, color: "yellow", children: activeParts.join(" + ") })
|
|
26059
25952
|
] }),
|
|
26060
|
-
/* @__PURE__ */
|
|
25953
|
+
/* @__PURE__ */ jsx43(Text, { dimColor: true, children: "Clearing will stop this work and permanently reset the current session." })
|
|
26061
25954
|
] }),
|
|
26062
|
-
/* @__PURE__ */
|
|
25955
|
+
/* @__PURE__ */ jsx43(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs42(Text, { children: [
|
|
26063
25956
|
"Type",
|
|
26064
25957
|
" ",
|
|
26065
|
-
/* @__PURE__ */
|
|
25958
|
+
/* @__PURE__ */ jsx43(Text, { bold: true, color: "green", children: "YES" }),
|
|
26066
25959
|
" ",
|
|
26067
25960
|
"and press Enter to clear, or press ",
|
|
26068
|
-
/* @__PURE__ */
|
|
25961
|
+
/* @__PURE__ */ jsx43(Text, { bold: true, children: "Esc" }),
|
|
26069
25962
|
" to cancel."
|
|
26070
25963
|
] }) }),
|
|
26071
|
-
/* @__PURE__ */
|
|
25964
|
+
/* @__PURE__ */ jsxs42(Text, { children: [
|
|
26072
25965
|
"Confirmation:",
|
|
26073
25966
|
" ",
|
|
26074
|
-
/* @__PURE__ */
|
|
26075
|
-
/* @__PURE__ */
|
|
25967
|
+
/* @__PURE__ */ jsx43(Text, { bold: true, color: isClearConfirmation(value) ? "green" : "yellow", children: value }),
|
|
25968
|
+
/* @__PURE__ */ jsx43(Text, { color: "cyan", children: "\u2588" })
|
|
26076
25969
|
] })
|
|
26077
25970
|
] });
|
|
26078
25971
|
}
|
|
@@ -26616,7 +26509,7 @@ function formatMatchHit(hit) {
|
|
|
26616
26509
|
|
|
26617
26510
|
// src/components/history/stream-box.tsx
|
|
26618
26511
|
import React5 from "react";
|
|
26619
|
-
import { jsx as
|
|
26512
|
+
import { jsx as jsx44, jsxs as jsxs43 } from "react/jsx-runtime";
|
|
26620
26513
|
var MAX_STREAM_DISPLAY_CHARS = 480;
|
|
26621
26514
|
var MAX_STREAM_LINES = 8;
|
|
26622
26515
|
var WRITE_CREATE_STREAM_LINES = 3;
|
|
@@ -26656,7 +26549,7 @@ var ToolStreamBox = React5.memo(function ToolStreamBox2({
|
|
|
26656
26549
|
const contentWidth = Math.max(20, Math.min(termWidth - 4, 100));
|
|
26657
26550
|
const rows = streamBoxRows(text, streamLines, contentWidth);
|
|
26658
26551
|
const isWritePreview = name === "write";
|
|
26659
|
-
return /* @__PURE__ */
|
|
26552
|
+
return /* @__PURE__ */ jsxs43(
|
|
26660
26553
|
Box,
|
|
26661
26554
|
{
|
|
26662
26555
|
flexDirection: "column",
|
|
@@ -26668,16 +26561,16 @@ var ToolStreamBox = React5.memo(function ToolStreamBox2({
|
|
|
26668
26561
|
borderColor: color,
|
|
26669
26562
|
paddingLeft: 1,
|
|
26670
26563
|
children: [
|
|
26671
|
-
/* @__PURE__ */
|
|
26672
|
-
/* @__PURE__ */
|
|
26564
|
+
/* @__PURE__ */ jsxs43(Box, { flexDirection: "row", children: [
|
|
26565
|
+
/* @__PURE__ */ jsxs43(Text, { color, children: [
|
|
26673
26566
|
glyph2,
|
|
26674
26567
|
" "
|
|
26675
26568
|
] }),
|
|
26676
|
-
/* @__PURE__ */
|
|
26677
|
-
/* @__PURE__ */
|
|
26678
|
-
hidden > 0 ? /* @__PURE__ */
|
|
26569
|
+
/* @__PURE__ */ jsx44(Text, { bold: true, color, children: isWritePreview ? "write \xB7 creating file" : name }),
|
|
26570
|
+
/* @__PURE__ */ jsx44(Text, { dimColor: true, children: ` \u23F1 ${fmtDuration2(elapsedMs)}` }),
|
|
26571
|
+
hidden > 0 ? /* @__PURE__ */ jsx44(Text, { dimColor: true, children: ` (${totalLines} lines, showing last ${streamLines})` }) : null
|
|
26679
26572
|
] }),
|
|
26680
|
-
/* @__PURE__ */
|
|
26573
|
+
/* @__PURE__ */ jsx44(Box, { flexDirection: "column", marginLeft: 1, children: rows.map((r, i) => /* @__PURE__ */ jsx44(
|
|
26681
26574
|
Text,
|
|
26682
26575
|
{
|
|
26683
26576
|
color: isWritePreview ? "gray" : void 0,
|
|
@@ -26702,27 +26595,27 @@ function tailForDisplay(text, maxChars) {
|
|
|
26702
26595
|
}
|
|
26703
26596
|
|
|
26704
26597
|
// src/components/history/visual-lines.tsx
|
|
26705
|
-
import { Fragment as Fragment15, jsx as
|
|
26598
|
+
import { Fragment as Fragment15, jsx as jsx45, jsxs as jsxs44 } from "react/jsx-runtime";
|
|
26706
26599
|
var VISUAL_TEXT_BUDGET = 92;
|
|
26707
26600
|
function ToolOutputLines({
|
|
26708
26601
|
lines,
|
|
26709
26602
|
hasFollowingBlock
|
|
26710
26603
|
}) {
|
|
26711
|
-
return /* @__PURE__ */
|
|
26604
|
+
return /* @__PURE__ */ jsx45(Fragment15, { children: lines.map((line, i) => {
|
|
26712
26605
|
const branch = i === lines.length - 1 && !hasFollowingBlock ? " \u2514\u2500 " : " \u251C\u2500 ";
|
|
26713
26606
|
const color = colorForVisualKind(line.kind);
|
|
26714
|
-
return /* @__PURE__ */
|
|
26715
|
-
/* @__PURE__ */
|
|
26716
|
-
line.marker ? /* @__PURE__ */
|
|
26717
|
-
line.path ? /* @__PURE__ */
|
|
26718
|
-
/* @__PURE__ */
|
|
26719
|
-
/* @__PURE__ */
|
|
26607
|
+
return /* @__PURE__ */ jsxs44(Text, { children: [
|
|
26608
|
+
/* @__PURE__ */ jsx45(Text, { dimColor: true, children: branch }),
|
|
26609
|
+
line.marker ? /* @__PURE__ */ jsx45(Text, { color, bold: true, children: line.marker }) : null,
|
|
26610
|
+
line.path ? /* @__PURE__ */ jsxs44(Fragment15, { children: [
|
|
26611
|
+
/* @__PURE__ */ jsx45(Text, { color: "cyan", children: shortenPath(line.path, 56) }),
|
|
26612
|
+
/* @__PURE__ */ jsx45(Text, { dimColor: true, children: " " })
|
|
26720
26613
|
] }) : null,
|
|
26721
|
-
line.lineNo ? /* @__PURE__ */
|
|
26722
|
-
/* @__PURE__ */
|
|
26723
|
-
/* @__PURE__ */
|
|
26614
|
+
line.lineNo ? /* @__PURE__ */ jsxs44(Fragment15, { children: [
|
|
26615
|
+
/* @__PURE__ */ jsx45(Text, { color: "yellow", children: String(line.lineNo).padStart(4, " ") }),
|
|
26616
|
+
/* @__PURE__ */ jsx45(Text, { dimColor: true, children: " \u2502 " })
|
|
26724
26617
|
] }) : null,
|
|
26725
|
-
/* @__PURE__ */
|
|
26618
|
+
/* @__PURE__ */ jsx45(Text, { color, dimColor: line.kind === "meta" || line.kind === "stdout", children: truncMid(line.text, VISUAL_TEXT_BUDGET) })
|
|
26726
26619
|
] }, `${line.kind}-${i}`);
|
|
26727
26620
|
}) });
|
|
26728
26621
|
}
|
|
@@ -27554,14 +27447,44 @@ var SAGE_INJECTOR_HEADINGS = /* @__PURE__ */ new Set([
|
|
|
27554
27447
|
"--- SAGE: related project knowledge (Memory Injector) ---"
|
|
27555
27448
|
]);
|
|
27556
27449
|
var SAGE_MEMORY_LINE = /^- \[[^\]]+\](?:\[[^\]]+\])* <memory id="[^"]+">.*<\/memory>(?: .*)?$/;
|
|
27450
|
+
var SAGE_MEMORY_LINE_TRUNCATED = /^- \[[^\]]+\](?:\[[^\]]+\])* <memory id="[^"]+">.*…$/;
|
|
27451
|
+
var SAGE_MEMORY_DETAIL = /^- (?<labels>\[[^\]]+\](?:\[[^\]]+\])*) <memory id="(?<id>[^"]+)">(?<text>.*?)<\/memory>(?: \((?<anchor>[^)]+)\))?(?: \[(?<meta>[^\]]+)\])?$/;
|
|
27452
|
+
function unescapeFenceBody(value) {
|
|
27453
|
+
return value.replace(/'/g, "'").replace(/"/g, '"').replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&");
|
|
27454
|
+
}
|
|
27455
|
+
function parseMeta(meta) {
|
|
27456
|
+
if (!meta) return {};
|
|
27457
|
+
const relationMatch = /relation=([^;\]]+)/.exec(meta);
|
|
27458
|
+
const tagsMatch = /tags=([^;\]]+)/.exec(meta);
|
|
27459
|
+
return {
|
|
27460
|
+
relation: relationMatch?.[1]?.trim(),
|
|
27461
|
+
tags: tagsMatch?.[1]?.split(",").map((tag) => tag.trim()).filter(Boolean)
|
|
27462
|
+
};
|
|
27463
|
+
}
|
|
27464
|
+
function parseSageMemoryLine(line) {
|
|
27465
|
+
const match = SAGE_MEMORY_DETAIL.exec(line);
|
|
27466
|
+
if (!match?.groups) return null;
|
|
27467
|
+
const rawLabels = match.groups["labels"] ?? "";
|
|
27468
|
+
const labels = Array.from(rawLabels.matchAll(/\[([^\]]+)\]/g)).map((m) => m[1] ?? "").filter(Boolean);
|
|
27469
|
+
return {
|
|
27470
|
+
id: match.groups["id"] ?? "",
|
|
27471
|
+
text: unescapeFenceBody(match.groups["text"] ?? ""),
|
|
27472
|
+
labels,
|
|
27473
|
+
anchor: match.groups["anchor"]?.trim() || void 0,
|
|
27474
|
+
...parseMeta(match.groups["meta"])
|
|
27475
|
+
};
|
|
27476
|
+
}
|
|
27557
27477
|
function extractSageBlock(output) {
|
|
27558
27478
|
const lines = output.split("\n");
|
|
27559
27479
|
for (let sageIdx = lines.length - 1; sageIdx >= 0; sageIdx--) {
|
|
27560
27480
|
if (!SAGE_INJECTOR_HEADINGS.has(lines[sageIdx] ?? "")) continue;
|
|
27561
27481
|
const candidate = lines.slice(sageIdx);
|
|
27562
27482
|
if (candidate.length < 2) continue;
|
|
27563
|
-
const
|
|
27564
|
-
|
|
27483
|
+
const rawMemoryLines = candidate.slice(1);
|
|
27484
|
+
const memoryLines = rawMemoryLines.filter((line) => line.trim().length > 0);
|
|
27485
|
+
if (memoryLines.length === 0 || !memoryLines.every(
|
|
27486
|
+
(line, index) => SAGE_MEMORY_LINE.test(line) || index === memoryLines.length - 1 && SAGE_MEMORY_LINE_TRUNCATED.test(line)
|
|
27487
|
+
)) {
|
|
27565
27488
|
continue;
|
|
27566
27489
|
}
|
|
27567
27490
|
let end = candidate.length;
|
|
@@ -27573,16 +27496,24 @@ function extractSageBlock(output) {
|
|
|
27573
27496
|
}
|
|
27574
27497
|
return { cleanOutput: output, sageLines: [] };
|
|
27575
27498
|
}
|
|
27499
|
+
function resolveEntrySage(output, sageLines) {
|
|
27500
|
+
if (sageLines && sageLines.length > 0) {
|
|
27501
|
+
return { cleanOutput: output ?? "", sageLines: [...sageLines] };
|
|
27502
|
+
}
|
|
27503
|
+
return extractSageBlock(output ?? "");
|
|
27504
|
+
}
|
|
27576
27505
|
function formatToolOutputSageWith(input) {
|
|
27577
27506
|
const { toolName, output, ok, outputBytes, outputLines, formatToolOutput: formatToolOutput2 } = input;
|
|
27578
27507
|
if (!output) {
|
|
27579
27508
|
return {
|
|
27580
27509
|
cleanOutput: "",
|
|
27581
27510
|
outLines: formatToolOutput2(toolName, output, ok, outputBytes, outputLines),
|
|
27582
|
-
|
|
27511
|
+
// A tool can return nothing and still get memory injected, so the
|
|
27512
|
+
// structured lines are honoured even with an empty body.
|
|
27513
|
+
sageLines: input.sageLines ? [...input.sageLines] : []
|
|
27583
27514
|
};
|
|
27584
27515
|
}
|
|
27585
|
-
const { cleanOutput, sageLines } =
|
|
27516
|
+
const { cleanOutput, sageLines } = resolveEntrySage(output, input.sageLines);
|
|
27586
27517
|
const text = cleanOutput || (sageLines.length > 0 ? "" : output);
|
|
27587
27518
|
return {
|
|
27588
27519
|
cleanOutput: text,
|
|
@@ -27826,11 +27757,12 @@ function formatToolArgs(toolName, input) {
|
|
|
27826
27757
|
}
|
|
27827
27758
|
|
|
27828
27759
|
// src/components/history/utils.tsx
|
|
27829
|
-
function formatToolOutputSage(toolName, output, ok, outputBytes, outputLines) {
|
|
27760
|
+
function formatToolOutputSage(toolName, output, ok, outputBytes, outputLines, sageLines) {
|
|
27830
27761
|
return formatToolOutputSageWith({
|
|
27831
27762
|
toolName,
|
|
27832
27763
|
output,
|
|
27833
27764
|
ok,
|
|
27765
|
+
sageLines,
|
|
27834
27766
|
outputBytes,
|
|
27835
27767
|
outputLines,
|
|
27836
27768
|
formatToolOutput
|
|
@@ -28666,7 +28598,7 @@ function extractPatchHeaderPath(diffText) {
|
|
|
28666
28598
|
}
|
|
28667
28599
|
|
|
28668
28600
|
// src/components/history/code-block.tsx
|
|
28669
|
-
import { Fragment as Fragment16, jsx as
|
|
28601
|
+
import { Fragment as Fragment16, jsx as jsx46, jsxs as jsxs45 } from "react/jsx-runtime";
|
|
28670
28602
|
var MAX_CODE_LINES = 80;
|
|
28671
28603
|
var DIFF_MAX_LINES = 200;
|
|
28672
28604
|
var MULTI_DIFF_MAX_FILES = 20;
|
|
@@ -28708,7 +28640,7 @@ function CodeBlock({
|
|
|
28708
28640
|
carry = r.carry;
|
|
28709
28641
|
return r.tokens;
|
|
28710
28642
|
});
|
|
28711
|
-
return /* @__PURE__ */
|
|
28643
|
+
return /* @__PURE__ */ jsxs45(
|
|
28712
28644
|
Box,
|
|
28713
28645
|
{
|
|
28714
28646
|
flexDirection: "column",
|
|
@@ -28720,10 +28652,10 @@ function CodeBlock({
|
|
|
28720
28652
|
borderColor: theme.borderDefault,
|
|
28721
28653
|
paddingX: 1,
|
|
28722
28654
|
children: [
|
|
28723
|
-
lang !== "plain" ? /* @__PURE__ */
|
|
28724
|
-
rows.map((tokens, i) => /* @__PURE__ */
|
|
28725
|
-
/* @__PURE__ */
|
|
28726
|
-
tokens.length === 0 ? " " : tokens.map((t, j) => /* @__PURE__ */
|
|
28655
|
+
lang !== "plain" ? /* @__PURE__ */ jsx46(Text, { dimColor: true, children: lang }) : null,
|
|
28656
|
+
rows.map((tokens, i) => /* @__PURE__ */ jsxs45(Text, { children: [
|
|
28657
|
+
/* @__PURE__ */ jsx46(Text, { dimColor: true, children: `${String(i + 1).padStart(gutterW, " ")} ` }),
|
|
28658
|
+
tokens.length === 0 ? " " : tokens.map((t, j) => /* @__PURE__ */ jsx46(
|
|
28727
28659
|
Text,
|
|
28728
28660
|
{
|
|
28729
28661
|
dimColor: Boolean(t.dim),
|
|
@@ -28734,7 +28666,7 @@ function CodeBlock({
|
|
|
28734
28666
|
j
|
|
28735
28667
|
))
|
|
28736
28668
|
] }, i)),
|
|
28737
|
-
hidden > 0 ? /* @__PURE__ */
|
|
28669
|
+
hidden > 0 ? /* @__PURE__ */ jsx46(Text, { dimColor: true, italic: true, children: `\u2026 +${hidden} more line${hidden === 1 ? "" : "s"}` }) : null
|
|
28738
28670
|
]
|
|
28739
28671
|
}
|
|
28740
28672
|
);
|
|
@@ -28795,9 +28727,9 @@ function DiffFileBlock({
|
|
|
28795
28727
|
useColor = true,
|
|
28796
28728
|
contentWidth
|
|
28797
28729
|
}) {
|
|
28798
|
-
return /* @__PURE__ */
|
|
28799
|
-
/* @__PURE__ */
|
|
28800
|
-
/* @__PURE__ */
|
|
28730
|
+
return /* @__PURE__ */ jsxs45(Box, { flexDirection: "column", marginTop: 1, children: [
|
|
28731
|
+
/* @__PURE__ */ jsx46(Text, { dimColor: true, italic: true, children: path11 }),
|
|
28732
|
+
/* @__PURE__ */ jsx46(
|
|
28801
28733
|
DiffBlock,
|
|
28802
28734
|
{
|
|
28803
28735
|
rows: preview.rows,
|
|
@@ -28831,7 +28763,7 @@ function applyWashTokens(tokens, onWash) {
|
|
|
28831
28763
|
function renderTokens(tokens, onWash = false) {
|
|
28832
28764
|
const effective = applyWashTokens(tokens, onWash);
|
|
28833
28765
|
if (effective.length === 0) return " ";
|
|
28834
|
-
return effective.map((t, j) => /* @__PURE__ */
|
|
28766
|
+
return effective.map((t, j) => /* @__PURE__ */ jsx46(
|
|
28835
28767
|
Text,
|
|
28836
28768
|
{
|
|
28837
28769
|
dimColor: Boolean(t.dim),
|
|
@@ -28909,19 +28841,19 @@ function DiffBlock({
|
|
|
28909
28841
|
const hiddenStats = [];
|
|
28910
28842
|
if (hiddenAdded > 0) hiddenStats.push(`+${hiddenAdded}`);
|
|
28911
28843
|
if (hiddenRemoved > 0) hiddenStats.push(`-${hiddenRemoved}`);
|
|
28912
|
-
return /* @__PURE__ */
|
|
28913
|
-
stats ? /* @__PURE__ */
|
|
28914
|
-
/* @__PURE__ */
|
|
28915
|
-
/* @__PURE__ */
|
|
28844
|
+
return /* @__PURE__ */ jsxs45(Box, { flexDirection: "column", marginLeft: 2, marginTop: 0, children: [
|
|
28845
|
+
stats ? /* @__PURE__ */ jsxs45(Text, { children: [
|
|
28846
|
+
/* @__PURE__ */ jsx46(Text, { dimColor: true, children: "\u23BF " }),
|
|
28847
|
+
/* @__PURE__ */ jsx46(Text, { children: stats })
|
|
28916
28848
|
] }) : null,
|
|
28917
28849
|
rows.map((row, i) => {
|
|
28918
28850
|
const key = i;
|
|
28919
28851
|
if (row.kind === "hunk") {
|
|
28920
28852
|
if (i === 0) return null;
|
|
28921
|
-
return /* @__PURE__ */
|
|
28853
|
+
return /* @__PURE__ */ jsx46(Text, { dimColor: true, children: ` ${blank} \u22EF` }, key);
|
|
28922
28854
|
}
|
|
28923
28855
|
if (row.kind === "meta") {
|
|
28924
|
-
return /* @__PURE__ */
|
|
28856
|
+
return /* @__PURE__ */ jsx46(Text, { dimColor: true, children: ` ${blank} ${row.text}` }, key);
|
|
28925
28857
|
}
|
|
28926
28858
|
const n = lineNoOf(row);
|
|
28927
28859
|
const ln = typeof n === "number" ? String(n).padStart(gutterWidth, " ") : blank;
|
|
@@ -28929,8 +28861,8 @@ function DiffBlock({
|
|
|
28929
28861
|
const tokens = highlightLine(body, lang).tokens;
|
|
28930
28862
|
const segments = wrapTokens(tokens, bodyBudget);
|
|
28931
28863
|
if (row.kind === "ctx") {
|
|
28932
|
-
return /* @__PURE__ */
|
|
28933
|
-
/* @__PURE__ */
|
|
28864
|
+
return /* @__PURE__ */ jsx46(Box, { flexDirection: "column", children: segments.map((seg, si) => /* @__PURE__ */ jsxs45(Text, { children: [
|
|
28865
|
+
/* @__PURE__ */ jsx46(Text, { dimColor: true, children: si === 0 ? ` ${ln} ` : contPrefix }),
|
|
28934
28866
|
renderTokens(seg)
|
|
28935
28867
|
] }, si)) }, key);
|
|
28936
28868
|
}
|
|
@@ -28938,29 +28870,29 @@ function DiffBlock({
|
|
|
28938
28870
|
const markerColor = row.kind === "add" ? theme.success : theme.error;
|
|
28939
28871
|
if (useColor) {
|
|
28940
28872
|
const bg = row.kind === "add" ? theme.diffAddBg : theme.diffDelBg;
|
|
28941
|
-
return /* @__PURE__ */
|
|
28873
|
+
return /* @__PURE__ */ jsx46(Box, { flexDirection: "column", children: segments.map((seg, si) => {
|
|
28942
28874
|
const pad = padBody(seg);
|
|
28943
|
-
return /* @__PURE__ */
|
|
28944
|
-
si === 0 ? /* @__PURE__ */
|
|
28945
|
-
/* @__PURE__ */
|
|
28946
|
-
/* @__PURE__ */
|
|
28947
|
-
/* @__PURE__ */
|
|
28948
|
-
] }) : /* @__PURE__ */
|
|
28875
|
+
return /* @__PURE__ */ jsxs45(Text, { backgroundColor: bg, children: [
|
|
28876
|
+
si === 0 ? /* @__PURE__ */ jsxs45(Fragment16, { children: [
|
|
28877
|
+
/* @__PURE__ */ jsx46(Text, { dimColor: true, children: ` ${ln} ` }),
|
|
28878
|
+
/* @__PURE__ */ jsx46(Text, { color: markerColor, bold: true, children: marker }),
|
|
28879
|
+
/* @__PURE__ */ jsx46(Text, { children: " " })
|
|
28880
|
+
] }) : /* @__PURE__ */ jsx46(Text, { dimColor: true, children: contPrefix }),
|
|
28949
28881
|
renderTokens(seg, true),
|
|
28950
|
-
pad > 0 ? /* @__PURE__ */
|
|
28882
|
+
pad > 0 ? /* @__PURE__ */ jsx46(Text, { children: " ".repeat(pad) }) : null
|
|
28951
28883
|
] }, si);
|
|
28952
28884
|
}) }, key);
|
|
28953
28885
|
}
|
|
28954
|
-
return /* @__PURE__ */
|
|
28955
|
-
si === 0 ? /* @__PURE__ */
|
|
28956
|
-
/* @__PURE__ */
|
|
28957
|
-
/* @__PURE__ */
|
|
28958
|
-
/* @__PURE__ */
|
|
28959
|
-
] }) : /* @__PURE__ */
|
|
28886
|
+
return /* @__PURE__ */ jsx46(Box, { flexDirection: "column", children: segments.map((seg, si) => /* @__PURE__ */ jsxs45(Text, { children: [
|
|
28887
|
+
si === 0 ? /* @__PURE__ */ jsxs45(Fragment16, { children: [
|
|
28888
|
+
/* @__PURE__ */ jsx46(Text, { dimColor: true, children: ` ${ln} ` }),
|
|
28889
|
+
/* @__PURE__ */ jsx46(Text, { color: markerColor, bold: true, children: marker }),
|
|
28890
|
+
/* @__PURE__ */ jsx46(Text, { children: " " })
|
|
28891
|
+
] }) : /* @__PURE__ */ jsx46(Text, { dimColor: true, children: contPrefix }),
|
|
28960
28892
|
renderTokens(seg)
|
|
28961
28893
|
] }, si)) }, key);
|
|
28962
28894
|
}),
|
|
28963
|
-
hidden > 0 ? /* @__PURE__ */
|
|
28895
|
+
hidden > 0 ? /* @__PURE__ */ jsx46(Text, { dimColor: true, italic: true, children: ` ${blank} \u2026 ${hidden} more line${hidden === 1 ? "" : "s"}${hiddenStats.length > 0 ? ` (${hiddenStats.join(" ")} hidden)` : ""}` }) : null
|
|
28964
28896
|
] });
|
|
28965
28897
|
}
|
|
28966
28898
|
function parseUnifiedDiff(diff, maxLines) {
|
|
@@ -29028,7 +28960,7 @@ function extractMultiFileDiffs(toolName, output, input) {
|
|
|
29028
28960
|
}
|
|
29029
28961
|
|
|
29030
28962
|
// src/components/confirm-prompt.tsx
|
|
29031
|
-
import { jsx as
|
|
28963
|
+
import { jsx as jsx47, jsxs as jsxs46 } from "react/jsx-runtime";
|
|
29032
28964
|
var BUTTON_COLOR = {
|
|
29033
28965
|
yes: "green",
|
|
29034
28966
|
no: "red",
|
|
@@ -29059,7 +28991,7 @@ function hasDiff(input) {
|
|
|
29059
28991
|
var CONFIRM_DIFF_MAX_LINES = 20;
|
|
29060
28992
|
function renderDiffLine(line) {
|
|
29061
28993
|
const prefix = line.startsWith("+") ? "green" : line.startsWith("-") ? "red" : line.startsWith("@@") ? "cyan" : void 0;
|
|
29062
|
-
return /* @__PURE__ */
|
|
28994
|
+
return /* @__PURE__ */ jsxs46(Text, { ...prefix ? { color: prefix } : {}, children: [
|
|
29063
28995
|
line,
|
|
29064
28996
|
"\n"
|
|
29065
28997
|
] }, line);
|
|
@@ -29067,7 +28999,7 @@ function renderDiffLine(line) {
|
|
|
29067
28999
|
function renderDiff(diff, path11) {
|
|
29068
29000
|
const preview = parseUnifiedDiff(diff, CONFIRM_DIFF_MAX_LINES);
|
|
29069
29001
|
if (preview.rows.length > 0) {
|
|
29070
|
-
return /* @__PURE__ */
|
|
29002
|
+
return /* @__PURE__ */ jsx47(
|
|
29071
29003
|
DiffBlock,
|
|
29072
29004
|
{
|
|
29073
29005
|
rows: preview.rows,
|
|
@@ -29082,7 +29014,7 @@ function renderDiff(diff, path11) {
|
|
|
29082
29014
|
);
|
|
29083
29015
|
}
|
|
29084
29016
|
const lines = diff.split("\n").filter((l) => l.length > 0).slice(0, CONFIRM_DIFF_MAX_LINES);
|
|
29085
|
-
return /* @__PURE__ */
|
|
29017
|
+
return /* @__PURE__ */ jsx47(Box, { flexDirection: "column", paddingX: 2, children: lines.map((l) => renderDiffLine(l)) });
|
|
29086
29018
|
}
|
|
29087
29019
|
function ConfirmPrompt({
|
|
29088
29020
|
toolName,
|
|
@@ -29118,28 +29050,28 @@ function ConfirmPrompt({
|
|
|
29118
29050
|
const inp = input;
|
|
29119
29051
|
const diff = typeof inp?.diff === "string" ? inp.diff : "";
|
|
29120
29052
|
const diffPath = typeof inp?.path === "string" ? inp.path : void 0;
|
|
29121
|
-
return /* @__PURE__ */
|
|
29122
|
-
/* @__PURE__ */
|
|
29123
|
-
/* @__PURE__ */
|
|
29124
|
-
/* @__PURE__ */
|
|
29125
|
-
/* @__PURE__ */
|
|
29053
|
+
return /* @__PURE__ */ jsxs46(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [
|
|
29054
|
+
/* @__PURE__ */ jsxs46(Box, { flexDirection: "row", children: [
|
|
29055
|
+
/* @__PURE__ */ jsx47(Text, { bold: true, color: "yellow", children: "\u26A0 APPROVAL REQUIRED" }),
|
|
29056
|
+
/* @__PURE__ */ jsx47(Text, { children: " " }),
|
|
29057
|
+
/* @__PURE__ */ jsx47(Text, { bold: true, color: "white", children: toolName })
|
|
29126
29058
|
] }),
|
|
29127
|
-
inputSummary ? /* @__PURE__ */
|
|
29128
|
-
boundaryReason ? /* @__PURE__ */
|
|
29059
|
+
inputSummary ? /* @__PURE__ */ jsx47(Text, { dimColor: true, children: inputSummary }) : null,
|
|
29060
|
+
boundaryReason ? /* @__PURE__ */ jsxs46(Text, { color: "yellow", children: [
|
|
29129
29061
|
"KANBAN BOUNDARY: ",
|
|
29130
29062
|
boundaryReason
|
|
29131
29063
|
] }) : null,
|
|
29132
|
-
showDiff && diff ? /* @__PURE__ */
|
|
29133
|
-
/* @__PURE__ */
|
|
29134
|
-
/* @__PURE__ */
|
|
29135
|
-
/* @__PURE__ */
|
|
29136
|
-
/* @__PURE__ */
|
|
29064
|
+
showDiff && diff ? /* @__PURE__ */ jsx47(Box, { flexDirection: "column", marginY: 1, children: renderDiff(diff, diffPath) }) : null,
|
|
29065
|
+
/* @__PURE__ */ jsx47(Text, { dimColor: true, children: "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500" }),
|
|
29066
|
+
/* @__PURE__ */ jsx47(Box, { flexDirection: "row", children: /* @__PURE__ */ jsx47(Text, { children: buttonLabels(suggestedPattern).map((l) => /* @__PURE__ */ jsxs46(React6.Fragment, { children: [
|
|
29067
|
+
/* @__PURE__ */ jsx47(Text, { bold: true, color: BUTTON_COLOR[l.decision], children: l.bracket }),
|
|
29068
|
+
/* @__PURE__ */ jsx47(Text, { dimColor: true, children: l.rest })
|
|
29137
29069
|
] }, l.decision)) }) }),
|
|
29138
|
-
!boundaryReason ? /* @__PURE__ */
|
|
29070
|
+
!boundaryReason ? /* @__PURE__ */ jsx47(Box, { marginTop: 1, children: /* @__PURE__ */ jsxs46(Text, { dimColor: true, children: [
|
|
29139
29071
|
" ",
|
|
29140
29072
|
"Tip: press",
|
|
29141
29073
|
" ",
|
|
29142
|
-
/* @__PURE__ */
|
|
29074
|
+
/* @__PURE__ */ jsx47(Text, { bold: true, color: "yellow", children: "Y" }),
|
|
29143
29075
|
" ",
|
|
29144
29076
|
"to enable YOLO mode",
|
|
29145
29077
|
destructive ? " (skips this and future approvals)" : " (skips future approvals)",
|
|
@@ -29148,6 +29080,398 @@ function ConfirmPrompt({
|
|
|
29148
29080
|
] });
|
|
29149
29081
|
}
|
|
29150
29082
|
|
|
29083
|
+
// src/components/connections-panel.tsx
|
|
29084
|
+
import { useCallback as useCallback24, useEffect as useEffect61, useRef as useRef33, useState as useState34 } from "react";
|
|
29085
|
+
|
|
29086
|
+
// src/connections-health.ts
|
|
29087
|
+
import { createChronicleProjectAccess } from "@wrongstack/core/chronicle";
|
|
29088
|
+
import {
|
|
29089
|
+
isMailboxProjectServerAvailable,
|
|
29090
|
+
MailboxProjectServerConnection
|
|
29091
|
+
} from "@wrongstack/core/coordination";
|
|
29092
|
+
import { resolveWstackPaths as resolveWstackPaths5 } from "@wrongstack/core/utils";
|
|
29093
|
+
import { getKanbanServerConnection } from "@wrongstack/kanban";
|
|
29094
|
+
import { isSageProjectServerAvailable, SageProjectServerConnection } from "@wrongstack/sage";
|
|
29095
|
+
import {
|
|
29096
|
+
checkCodebaseIndexServerHealth,
|
|
29097
|
+
getIndexState as getIndexState2,
|
|
29098
|
+
resolveProjectIndexDaemonAvailability
|
|
29099
|
+
} from "@wrongstack/tools";
|
|
29100
|
+
async function collectConnectionsHealth(projectRoot) {
|
|
29101
|
+
const services = await Promise.all([
|
|
29102
|
+
chronicleHealth(projectRoot),
|
|
29103
|
+
codebaseIndexHealth(projectRoot),
|
|
29104
|
+
sageHealth(projectRoot),
|
|
29105
|
+
kanbanHealth(projectRoot),
|
|
29106
|
+
mailboxHealth(projectRoot)
|
|
29107
|
+
]);
|
|
29108
|
+
const required = services.filter((s2) => s2.required);
|
|
29109
|
+
const overall = required.some((s2) => s2.status === "error") ? "error" : required.some((s2) => s2.status !== "healthy") ? "degraded" : "healthy";
|
|
29110
|
+
return { checkedAt: Date.now(), overall, services };
|
|
29111
|
+
}
|
|
29112
|
+
async function chronicleHealth(projectRoot) {
|
|
29113
|
+
const startedAt = Date.now();
|
|
29114
|
+
let access;
|
|
29115
|
+
try {
|
|
29116
|
+
access = createChronicleProjectAccess({ projectRoot });
|
|
29117
|
+
const health2 = await access.call("ping", {}, { timeoutMs: 5e3 });
|
|
29118
|
+
const quarantined = health2.quarantinedFamilies ?? [];
|
|
29119
|
+
return {
|
|
29120
|
+
id: "chronicle",
|
|
29121
|
+
label: "Chronicle telemetry",
|
|
29122
|
+
status: quarantined.length > 0 ? "degraded" : access.mode === "server" ? "healthy" : "degraded",
|
|
29123
|
+
required: true,
|
|
29124
|
+
mode: access.mode,
|
|
29125
|
+
detail: quarantined.length > 0 ? `Serving, but ${quarantined.length} day(s) were quarantined for a broken chain: ${quarantined.map((family) => family.day).join(", ")}.` : access.mode === "server" ? "One project owner collects, processes, stores, and serves telemetry." : "Inline fallback is active; ownership is not shared across clients.",
|
|
29126
|
+
ownerPid: health2.pid,
|
|
29127
|
+
endpoint: health2.endpoint,
|
|
29128
|
+
storage: health2.chronicleDirectory,
|
|
29129
|
+
uptimeMs: health2.uptimeMs,
|
|
29130
|
+
latencyMs: Date.now() - startedAt,
|
|
29131
|
+
clients: health2.clients,
|
|
29132
|
+
activeRequests: health2.activeRequests,
|
|
29133
|
+
queuedWork: health2.journal.pendingEvents,
|
|
29134
|
+
watcher: { active: health2.watcher.active, watchedFiles: health2.watcher.watchedFiles },
|
|
29135
|
+
...quarantined[0] ? { lastError: quarantined[0].reason } : health2.watcher.lastError ? { lastError: health2.watcher.lastError } : {}
|
|
29136
|
+
};
|
|
29137
|
+
} catch (error) {
|
|
29138
|
+
return failureService("chronicle", "Chronicle telemetry", true, access?.mode ?? "unavailable", error, Date.now() - startedAt);
|
|
29139
|
+
} finally {
|
|
29140
|
+
await access?.close();
|
|
29141
|
+
}
|
|
29142
|
+
}
|
|
29143
|
+
async function codebaseIndexHealth(projectRoot) {
|
|
29144
|
+
const startedAt = Date.now();
|
|
29145
|
+
const availability = resolveProjectIndexDaemonAvailability(projectRoot);
|
|
29146
|
+
if (availability.kind === "endpoint-invalid") {
|
|
29147
|
+
return {
|
|
29148
|
+
id: "codebase-index",
|
|
29149
|
+
label: "Codebase index",
|
|
29150
|
+
status: "unavailable",
|
|
29151
|
+
required: false,
|
|
29152
|
+
mode: "endpoint-invalid",
|
|
29153
|
+
detail: `Socket path is ${availability.byteLength} bytes \u2014 over this platform's ${availability.maxBytes}-byte sun_path limit. Queries fall back to a process-local index. Set a shorter TMPDIR to restore the shared daemon.`,
|
|
29154
|
+
endpoint: availability.endpoint,
|
|
29155
|
+
latencyMs: Date.now() - startedAt
|
|
29156
|
+
};
|
|
29157
|
+
}
|
|
29158
|
+
try {
|
|
29159
|
+
const health2 = await checkCodebaseIndexServerHealth(projectRoot, void 0, { timeoutMs: 2e3 });
|
|
29160
|
+
const connection = getIndexState2().server;
|
|
29161
|
+
return {
|
|
29162
|
+
id: "codebase-index",
|
|
29163
|
+
label: "Codebase index",
|
|
29164
|
+
status: health2.status === "unresponsive" ? "error" : health2.status,
|
|
29165
|
+
required: false,
|
|
29166
|
+
mode: "project-server",
|
|
29167
|
+
detail: health2.server?.activity.indexing ? `Indexing ${health2.server.activity.currentFile}/${health2.server.activity.totalFiles}.` : "Shared symbol index is ready for project queries.",
|
|
29168
|
+
ownerPid: connection.pid,
|
|
29169
|
+
endpoint: connection.endpoint,
|
|
29170
|
+
storage: connection.indexDir ?? resolveWstackPaths5({ projectRoot }).projectCodebaseIndex,
|
|
29171
|
+
uptimeMs: health2.server?.uptimeMs,
|
|
29172
|
+
latencyMs: health2.latencyMs ?? Date.now() - startedAt,
|
|
29173
|
+
clients: health2.server?.clients,
|
|
29174
|
+
activeRequests: health2.server?.activeRequests,
|
|
29175
|
+
queuedWork: health2.server?.queuedWrites,
|
|
29176
|
+
watcher: health2.server ? { active: health2.server.watchingExternal, watchedFiles: health2.server.watchingClients } : void 0
|
|
29177
|
+
};
|
|
29178
|
+
} catch (error) {
|
|
29179
|
+
if (isOfflineConnectionError(error)) {
|
|
29180
|
+
return {
|
|
29181
|
+
...failureService("codebase-index", "Codebase index", false, "on-demand project-server", error, Date.now() - startedAt),
|
|
29182
|
+
status: "offline",
|
|
29183
|
+
detail: "Not running for this project; it starts on demand when indexing is used."
|
|
29184
|
+
};
|
|
29185
|
+
}
|
|
29186
|
+
return failureService("codebase-index", "Codebase index", false, "project-server", error, Date.now() - startedAt);
|
|
29187
|
+
}
|
|
29188
|
+
}
|
|
29189
|
+
async function sageHealth(projectRoot) {
|
|
29190
|
+
const startedAt = Date.now();
|
|
29191
|
+
if (!isSageProjectServerAvailable()) {
|
|
29192
|
+
return {
|
|
29193
|
+
id: "sage",
|
|
29194
|
+
label: "SAGE memory",
|
|
29195
|
+
status: "unavailable",
|
|
29196
|
+
required: false,
|
|
29197
|
+
mode: "unavailable",
|
|
29198
|
+
detail: "The packaged SAGE project server is unavailable in this runtime."
|
|
29199
|
+
};
|
|
29200
|
+
}
|
|
29201
|
+
const connection = new SageProjectServerConnection(projectRoot);
|
|
29202
|
+
try {
|
|
29203
|
+
const status = await connection.status();
|
|
29204
|
+
if (!status) {
|
|
29205
|
+
return {
|
|
29206
|
+
id: "sage",
|
|
29207
|
+
label: "SAGE memory",
|
|
29208
|
+
status: "offline",
|
|
29209
|
+
required: false,
|
|
29210
|
+
mode: "on-demand project-server",
|
|
29211
|
+
detail: "Not running for this project; it starts on demand when memory is used.",
|
|
29212
|
+
endpoint: connection.getState().endpoint,
|
|
29213
|
+
latencyMs: Date.now() - startedAt
|
|
29214
|
+
};
|
|
29215
|
+
}
|
|
29216
|
+
const healthStatus = status.health.status === "ready" ? "healthy" : status.health.status === "degraded" ? "degraded" : "error";
|
|
29217
|
+
return {
|
|
29218
|
+
id: "sage",
|
|
29219
|
+
label: "SAGE memory",
|
|
29220
|
+
status: healthStatus,
|
|
29221
|
+
required: false,
|
|
29222
|
+
mode: "project-server",
|
|
29223
|
+
detail: `Persistent project memory backend: ${status.health.backend}.`,
|
|
29224
|
+
ownerPid: status.pid,
|
|
29225
|
+
endpoint: status.endpoint,
|
|
29226
|
+
storage: status.storageRoot,
|
|
29227
|
+
latencyMs: Date.now() - startedAt,
|
|
29228
|
+
clients: status.clients,
|
|
29229
|
+
activeRequests: status.pendingRequests
|
|
29230
|
+
};
|
|
29231
|
+
} catch (error) {
|
|
29232
|
+
return failureService("sage", "SAGE memory", false, "project-server", error, Date.now() - startedAt);
|
|
29233
|
+
} finally {
|
|
29234
|
+
connection.close();
|
|
29235
|
+
}
|
|
29236
|
+
}
|
|
29237
|
+
async function kanbanHealth(projectRoot) {
|
|
29238
|
+
const startedAt = Date.now();
|
|
29239
|
+
if (process.env["WRONGSTACK_KANBAN_SERVER"] === "0") {
|
|
29240
|
+
return {
|
|
29241
|
+
id: "kanban",
|
|
29242
|
+
label: "Kanban IPC",
|
|
29243
|
+
status: "unavailable",
|
|
29244
|
+
required: false,
|
|
29245
|
+
mode: "disabled",
|
|
29246
|
+
detail: "Kanban IPC daemon is disabled via WRONGSTACK_KANBAN_SERVER=0."
|
|
29247
|
+
};
|
|
29248
|
+
}
|
|
29249
|
+
let connection;
|
|
29250
|
+
try {
|
|
29251
|
+
connection = await getKanbanServerConnection(projectRoot);
|
|
29252
|
+
} catch (error) {
|
|
29253
|
+
return failureService("kanban", "Kanban IPC", false, "project-server", error, Date.now() - startedAt);
|
|
29254
|
+
}
|
|
29255
|
+
if (!connection) {
|
|
29256
|
+
return {
|
|
29257
|
+
id: "kanban",
|
|
29258
|
+
label: "Kanban IPC",
|
|
29259
|
+
status: "unavailable",
|
|
29260
|
+
required: false,
|
|
29261
|
+
mode: "disabled",
|
|
29262
|
+
detail: "Kanban IPC daemon is disabled in this runtime."
|
|
29263
|
+
};
|
|
29264
|
+
}
|
|
29265
|
+
try {
|
|
29266
|
+
const status = await connection.request("ping", {}, { timeoutMs: 5e3 });
|
|
29267
|
+
return {
|
|
29268
|
+
id: "kanban",
|
|
29269
|
+
label: "Kanban IPC",
|
|
29270
|
+
status: "healthy",
|
|
29271
|
+
required: true,
|
|
29272
|
+
mode: "project-server",
|
|
29273
|
+
detail: `Single shared project-server owns kanban state (v${status.protocolVersion}).`,
|
|
29274
|
+
ownerPid: status.pid,
|
|
29275
|
+
endpoint: status.endpoint,
|
|
29276
|
+
storage: status.databasePath,
|
|
29277
|
+
latencyMs: Date.now() - startedAt,
|
|
29278
|
+
clients: status.clients,
|
|
29279
|
+
activeRequests: status.pendingRequests,
|
|
29280
|
+
uptimeMs: Date.now() - new Date(status.startedAt).getTime()
|
|
29281
|
+
};
|
|
29282
|
+
} catch (error) {
|
|
29283
|
+
return failureService("kanban", "Kanban IPC", true, "project-server", error, Date.now() - startedAt);
|
|
29284
|
+
}
|
|
29285
|
+
}
|
|
29286
|
+
async function mailboxHealth(projectRoot) {
|
|
29287
|
+
const startedAt = Date.now();
|
|
29288
|
+
if (!isMailboxProjectServerAvailable()) {
|
|
29289
|
+
return {
|
|
29290
|
+
id: "mailbox",
|
|
29291
|
+
label: "Mailbox IPC",
|
|
29292
|
+
status: "unavailable",
|
|
29293
|
+
required: false,
|
|
29294
|
+
mode: "unavailable",
|
|
29295
|
+
detail: "The packaged mailbox project server is unavailable in this runtime."
|
|
29296
|
+
};
|
|
29297
|
+
}
|
|
29298
|
+
const connection = new MailboxProjectServerConnection(
|
|
29299
|
+
resolveWstackPaths5({ projectRoot }).projectDir
|
|
29300
|
+
);
|
|
29301
|
+
try {
|
|
29302
|
+
const status = await connection.probeStatus();
|
|
29303
|
+
if (!status) {
|
|
29304
|
+
return {
|
|
29305
|
+
id: "mailbox",
|
|
29306
|
+
label: "Mailbox IPC",
|
|
29307
|
+
status: "offline",
|
|
29308
|
+
required: false,
|
|
29309
|
+
mode: "on-demand project-server",
|
|
29310
|
+
detail: "Not running for this project; it starts on demand when mailbox is used.",
|
|
29311
|
+
endpoint: connection.getState().endpoint,
|
|
29312
|
+
latencyMs: Date.now() - startedAt
|
|
29313
|
+
};
|
|
29314
|
+
}
|
|
29315
|
+
return {
|
|
29316
|
+
id: "mailbox",
|
|
29317
|
+
label: "Mailbox IPC",
|
|
29318
|
+
status: "healthy",
|
|
29319
|
+
required: true,
|
|
29320
|
+
mode: "project-server",
|
|
29321
|
+
detail: `Single shared project-server owns inter-agent mailbox state (v${status.protocolVersion}).`,
|
|
29322
|
+
ownerPid: status.pid,
|
|
29323
|
+
endpoint: status.endpoint,
|
|
29324
|
+
storage: status.databasePath,
|
|
29325
|
+
latencyMs: Date.now() - startedAt,
|
|
29326
|
+
clients: status.clients,
|
|
29327
|
+
activeRequests: status.pendingRequests,
|
|
29328
|
+
uptimeMs: Date.now() - new Date(status.startedAt).getTime()
|
|
29329
|
+
};
|
|
29330
|
+
} catch (error) {
|
|
29331
|
+
return failureService("mailbox", "Mailbox IPC", true, "project-server", error, Date.now() - startedAt);
|
|
29332
|
+
} finally {
|
|
29333
|
+
connection.close();
|
|
29334
|
+
}
|
|
29335
|
+
}
|
|
29336
|
+
function isOfflineConnectionError(error) {
|
|
29337
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
29338
|
+
return /(?:ENOENT|ECONNREFUSED|not found|not running|unavailable|connect failed)/iu.test(message);
|
|
29339
|
+
}
|
|
29340
|
+
function failureService(id, label, required, mode, error, latencyMs) {
|
|
29341
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
29342
|
+
return {
|
|
29343
|
+
id,
|
|
29344
|
+
label,
|
|
29345
|
+
status: "error",
|
|
29346
|
+
required,
|
|
29347
|
+
mode,
|
|
29348
|
+
detail: message,
|
|
29349
|
+
lastError: message,
|
|
29350
|
+
...latencyMs === void 0 ? {} : { latencyMs }
|
|
29351
|
+
};
|
|
29352
|
+
}
|
|
29353
|
+
|
|
29354
|
+
// src/components/connections-panel.tsx
|
|
29355
|
+
import { jsx as jsx48, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
29356
|
+
var REFRESH_MS = 8e3;
|
|
29357
|
+
var STATUS_GLYPH = {
|
|
29358
|
+
healthy: "\u25CF",
|
|
29359
|
+
degraded: "\u25D0",
|
|
29360
|
+
offline: "\u25CB",
|
|
29361
|
+
unavailable: "\u2298",
|
|
29362
|
+
error: "\u2717"
|
|
29363
|
+
};
|
|
29364
|
+
var STATUS_COLOR2 = {
|
|
29365
|
+
healthy: "green",
|
|
29366
|
+
degraded: "yellow",
|
|
29367
|
+
offline: "gray",
|
|
29368
|
+
unavailable: "gray",
|
|
29369
|
+
error: "red"
|
|
29370
|
+
};
|
|
29371
|
+
var OVERALL_COLOR = {
|
|
29372
|
+
healthy: "green",
|
|
29373
|
+
degraded: "yellow",
|
|
29374
|
+
error: "red"
|
|
29375
|
+
};
|
|
29376
|
+
function formatUptime(ms) {
|
|
29377
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
29378
|
+
const s2 = Math.floor(ms / 1e3);
|
|
29379
|
+
if (s2 < 60) return `${s2}s`;
|
|
29380
|
+
const m = Math.floor(s2 / 60);
|
|
29381
|
+
if (m < 60) return `${m}m`;
|
|
29382
|
+
const h = Math.floor(m / 60);
|
|
29383
|
+
return h < 24 ? `${h}h` : `${Math.floor(h / 24)}d`;
|
|
29384
|
+
}
|
|
29385
|
+
function formatLatency(ms) {
|
|
29386
|
+
if (ms === void 0) return null;
|
|
29387
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
29388
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
29389
|
+
}
|
|
29390
|
+
function ServiceRow({ service }) {
|
|
29391
|
+
const glyph2 = STATUS_GLYPH[service.status];
|
|
29392
|
+
const color = STATUS_COLOR2[service.status];
|
|
29393
|
+
const latency = formatLatency(service.latencyMs);
|
|
29394
|
+
const metaParts = [];
|
|
29395
|
+
if (service.ownerPid !== void 0) metaParts.push(`PID ${service.ownerPid}`);
|
|
29396
|
+
if (service.clients !== void 0) metaParts.push(`${service.clients} client${service.clients === 1 ? "" : "s"}`);
|
|
29397
|
+
if (service.activeRequests !== void 0 && service.activeRequests > 0) {
|
|
29398
|
+
metaParts.push(`${service.activeRequests} active`);
|
|
29399
|
+
}
|
|
29400
|
+
if (service.uptimeMs !== void 0) metaParts.push(`up ${formatUptime(service.uptimeMs)}`);
|
|
29401
|
+
if (latency) metaParts.push(`${latency}`);
|
|
29402
|
+
if (service.queuedWork !== void 0 && service.queuedWork > 0) {
|
|
29403
|
+
metaParts.push(`${service.queuedWork} queued`);
|
|
29404
|
+
}
|
|
29405
|
+
return /* @__PURE__ */ jsxs47(Box, { flexDirection: "column", marginTop: 0, children: [
|
|
29406
|
+
/* @__PURE__ */ jsxs47(Box, { gap: 1, children: [
|
|
29407
|
+
/* @__PURE__ */ jsx48(Text, { color, children: glyph2 }),
|
|
29408
|
+
/* @__PURE__ */ jsx48(Text, { bold: true, children: service.label }),
|
|
29409
|
+
service.required ? /* @__PURE__ */ jsx48(Text, { dimColor: true, children: "required" }) : null,
|
|
29410
|
+
/* @__PURE__ */ jsxs47(Text, { dimColor: true, children: [
|
|
29411
|
+
"\xB7 ",
|
|
29412
|
+
service.mode
|
|
29413
|
+
] })
|
|
29414
|
+
] }),
|
|
29415
|
+
/* @__PURE__ */ jsx48(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx48(Text, { dimColor: true, children: service.detail }) }),
|
|
29416
|
+
metaParts.length > 0 ? /* @__PURE__ */ jsx48(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx48(Text, { dimColor: true, children: metaParts.join(" \xB7 ") }) }) : null
|
|
29417
|
+
] });
|
|
29418
|
+
}
|
|
29419
|
+
function ConnectionsPanel({ projectRoot, onClose }) {
|
|
29420
|
+
const [report, setReport] = useState34(null);
|
|
29421
|
+
const [loading, setLoading] = useState34(true);
|
|
29422
|
+
const [error, setError] = useState34(null);
|
|
29423
|
+
const cancelledRef = useRef33(false);
|
|
29424
|
+
const fetch = useCallback24(async () => {
|
|
29425
|
+
try {
|
|
29426
|
+
const r = await collectConnectionsHealth(projectRoot);
|
|
29427
|
+
if (cancelledRef.current) return;
|
|
29428
|
+
setReport(r);
|
|
29429
|
+
setError(null);
|
|
29430
|
+
} catch (e) {
|
|
29431
|
+
if (cancelledRef.current) return;
|
|
29432
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
29433
|
+
} finally {
|
|
29434
|
+
if (!cancelledRef.current) setLoading(false);
|
|
29435
|
+
}
|
|
29436
|
+
}, [projectRoot]);
|
|
29437
|
+
useEffect61(() => {
|
|
29438
|
+
cancelledRef.current = false;
|
|
29439
|
+
void fetch();
|
|
29440
|
+
const timer = setInterval(() => void fetch(), REFRESH_MS);
|
|
29441
|
+
return () => {
|
|
29442
|
+
cancelledRef.current = true;
|
|
29443
|
+
clearInterval(timer);
|
|
29444
|
+
};
|
|
29445
|
+
}, [fetch]);
|
|
29446
|
+
useInput((_input, key) => {
|
|
29447
|
+
if (key.escape || _input === "q") onClose();
|
|
29448
|
+
if (_input === "r") void fetch();
|
|
29449
|
+
});
|
|
29450
|
+
const overallLabel = report ? report.overall === "healthy" ? "All required services healthy" : report.overall === "degraded" ? "Some services degraded" : "Service errors detected" : "Checking\u2026";
|
|
29451
|
+
return /* @__PURE__ */ jsxs47(Box, { flexDirection: "column", borderStyle: "round", borderColor: report ? OVERALL_COLOR[report.overall] : "gray", paddingX: 1, marginY: 0, flexShrink: 0, children: [
|
|
29452
|
+
/* @__PURE__ */ jsxs47(Box, { justifyContent: "space-between", children: [
|
|
29453
|
+
/* @__PURE__ */ jsxs47(Box, { gap: 1, children: [
|
|
29454
|
+
/* @__PURE__ */ jsx48(Text, { bold: true, children: "Service Connections" }),
|
|
29455
|
+
report ? /* @__PURE__ */ jsxs47(Text, { color: OVERALL_COLOR[report.overall], children: [
|
|
29456
|
+
"\u25CF ",
|
|
29457
|
+
overallLabel
|
|
29458
|
+
] }) : null
|
|
29459
|
+
] }),
|
|
29460
|
+
/* @__PURE__ */ jsx48(Text, { dimColor: true, children: "Esc/q close \xB7 r refresh" })
|
|
29461
|
+
] }),
|
|
29462
|
+
loading && !report ? /* @__PURE__ */ jsx48(Box, { paddingY: 1, children: /* @__PURE__ */ jsx48(Text, { dimColor: true, children: "Checking service health\u2026" }) }) : null,
|
|
29463
|
+
error ? /* @__PURE__ */ jsx48(Box, { paddingY: 1, children: /* @__PURE__ */ jsxs47(Text, { color: "red", children: [
|
|
29464
|
+
"Error: ",
|
|
29465
|
+
error
|
|
29466
|
+
] }) }) : null,
|
|
29467
|
+
report ? /* @__PURE__ */ jsx48(Box, { flexDirection: "column", marginTop: 0, children: report.services.map((s2) => /* @__PURE__ */ jsx48(ServiceRow, { service: s2 }, s2.id)) }) : null,
|
|
29468
|
+
report ? /* @__PURE__ */ jsx48(Box, { marginTop: 0, children: /* @__PURE__ */ jsxs47(Text, { dimColor: true, children: [
|
|
29469
|
+
"Last checked ",
|
|
29470
|
+
new Date(report.checkedAt).toLocaleTimeString()
|
|
29471
|
+
] }) }) : null
|
|
29472
|
+
] });
|
|
29473
|
+
}
|
|
29474
|
+
|
|
29151
29475
|
// src/components/continue-confirm-panel.tsx
|
|
29152
29476
|
import React7 from "react";
|
|
29153
29477
|
import { jsx as jsx49, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
@@ -29858,101 +30182,23 @@ function ExitConfirmPanel({
|
|
|
29858
30182
|
] });
|
|
29859
30183
|
}
|
|
29860
30184
|
|
|
29861
|
-
// src/components/refine-countdown-panel.tsx
|
|
29862
|
-
import { useEffect as useEffect64, useRef as useRef35, useState as useState37 } from "react";
|
|
29863
|
-
import { jsx as jsx55, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
29864
|
-
function RefineCountdownPanel({
|
|
29865
|
-
original,
|
|
29866
|
-
seconds,
|
|
29867
|
-
onDecision,
|
|
29868
|
-
providerId,
|
|
29869
|
-
model
|
|
29870
|
-
}) {
|
|
29871
|
-
const [remaining, setRemaining] = useState37(Math.max(1, seconds));
|
|
29872
|
-
const resolvedRef = useRef35(false);
|
|
29873
|
-
useEffect64(() => {
|
|
29874
|
-
const id = setInterval(() => {
|
|
29875
|
-
setRemaining((prev) => {
|
|
29876
|
-
if (prev <= 1) {
|
|
29877
|
-
clearInterval(id);
|
|
29878
|
-
if (!resolvedRef.current) {
|
|
29879
|
-
resolvedRef.current = true;
|
|
29880
|
-
onDecision("proceed");
|
|
29881
|
-
}
|
|
29882
|
-
return 0;
|
|
29883
|
-
}
|
|
29884
|
-
return prev - 1;
|
|
29885
|
-
});
|
|
29886
|
-
}, 1e3);
|
|
29887
|
-
return () => clearInterval(id);
|
|
29888
|
-
}, []);
|
|
29889
|
-
useInput((_input, key) => {
|
|
29890
|
-
if (resolvedRef.current) return;
|
|
29891
|
-
resolvedRef.current = true;
|
|
29892
|
-
if (key.escape) onDecision("cancel");
|
|
29893
|
-
else if (key.return) onDecision("proceed");
|
|
29894
|
-
else onDecision("skip");
|
|
29895
|
-
});
|
|
29896
|
-
const preview = wrapRefinementPreview(original, 60, 2);
|
|
29897
|
-
return /* @__PURE__ */ jsxs54(
|
|
29898
|
-
Box,
|
|
29899
|
-
{
|
|
29900
|
-
alignSelf: "stretch",
|
|
29901
|
-
width: "100%",
|
|
29902
|
-
flexDirection: "column",
|
|
29903
|
-
borderStyle: "round",
|
|
29904
|
-
borderColor: theme.brand,
|
|
29905
|
-
paddingX: 1,
|
|
29906
|
-
children: [
|
|
29907
|
-
/* @__PURE__ */ jsxs54(Box, { height: 1, children: [
|
|
29908
|
-
/* @__PURE__ */ jsxs54(Text, { color: theme.brand, bold: true, children: [
|
|
29909
|
-
glyphs.brain,
|
|
29910
|
-
" PROMPT REFINER"
|
|
29911
|
-
] }),
|
|
29912
|
-
providerId && model ? /* @__PURE__ */ jsxs54(Text, { color: theme.textMuted, children: [
|
|
29913
|
-
" ",
|
|
29914
|
-
"on ",
|
|
29915
|
-
providerId,
|
|
29916
|
-
"/",
|
|
29917
|
-
model
|
|
29918
|
-
] }) : null,
|
|
29919
|
-
/* @__PURE__ */ jsx55(Box, { flexGrow: 1 }),
|
|
29920
|
-
/* @__PURE__ */ jsxs54(Text, { color: theme.brand, children: [
|
|
29921
|
-
"refining in ",
|
|
29922
|
-
remaining,
|
|
29923
|
-
"s\u2026"
|
|
29924
|
-
] })
|
|
29925
|
-
] }),
|
|
29926
|
-
/* @__PURE__ */ jsx55(Box, { flexDirection: "column", marginTop: 1, children: preview.map((line, index) => /* @__PURE__ */ jsxs54(Box, { height: 1, children: [
|
|
29927
|
-
/* @__PURE__ */ jsx55(Text, { color: theme.brand, children: "\u258E" }),
|
|
29928
|
-
/* @__PURE__ */ jsxs54(Text, { color: theme.textSecondary, children: [
|
|
29929
|
-
" ",
|
|
29930
|
-
line
|
|
29931
|
-
] })
|
|
29932
|
-
] }, `refine-countdown-preview-${index}`)) }),
|
|
29933
|
-
/* @__PURE__ */ jsx55(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */ jsx55(Text, { color: theme.textMuted, children: "Enter refines now \xB7 any key sends as-is \xB7 Esc cancels" }) })
|
|
29934
|
-
]
|
|
29935
|
-
}
|
|
29936
|
-
);
|
|
29937
|
-
}
|
|
29938
|
-
|
|
29939
30185
|
// src/components/file-picker.tsx
|
|
29940
|
-
import { jsx as
|
|
30186
|
+
import { jsx as jsx55, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
29941
30187
|
function FilePicker({ query, matches, selected }) {
|
|
29942
30188
|
if (matches.length === 0) {
|
|
29943
|
-
return /* @__PURE__ */
|
|
30189
|
+
return /* @__PURE__ */ jsx55(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsxs54(Text, { dimColor: true, children: [
|
|
29944
30190
|
"@",
|
|
29945
30191
|
query,
|
|
29946
30192
|
" \u2014 no matches"
|
|
29947
30193
|
] }) });
|
|
29948
30194
|
}
|
|
29949
|
-
return /* @__PURE__ */
|
|
29950
|
-
/* @__PURE__ */
|
|
30195
|
+
return /* @__PURE__ */ jsxs54(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
30196
|
+
/* @__PURE__ */ jsxs54(Text, { dimColor: true, children: [
|
|
29951
30197
|
"@",
|
|
29952
30198
|
query || "\u2026",
|
|
29953
30199
|
" \u2014 \u2191/\u2193 select, Enter attach, Esc cancel"
|
|
29954
30200
|
] }),
|
|
29955
|
-
matches.map((m, i) => /* @__PURE__ */
|
|
30201
|
+
matches.map((m, i) => /* @__PURE__ */ jsxs54(Text, { inverse: i === selected, ...i === selected ? { color: "cyan" } : {}, children: [
|
|
29956
30202
|
i === selected ? "\u203A " : " ",
|
|
29957
30203
|
highlight(m, query)
|
|
29958
30204
|
] }, m))
|
|
@@ -29963,7 +30209,7 @@ function highlight(path11, _query) {
|
|
|
29963
30209
|
}
|
|
29964
30210
|
|
|
29965
30211
|
// src/components/help-panel.tsx
|
|
29966
|
-
import { Fragment as Fragment18, jsx as
|
|
30212
|
+
import { Fragment as Fragment18, jsx as jsx56, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
29967
30213
|
var CATEGORY_ORDER2 = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
|
|
29968
30214
|
var CHROME_ROWS3 = 7;
|
|
29969
30215
|
function normalizeQuery(raw) {
|
|
@@ -30036,29 +30282,29 @@ function HelpPanel({
|
|
|
30036
30282
|
const hiddenAbove = start;
|
|
30037
30283
|
const hiddenBelow = rows.length - end;
|
|
30038
30284
|
const hasFilter = query.length > 0;
|
|
30039
|
-
return /* @__PURE__ */
|
|
30040
|
-
/* @__PURE__ */
|
|
30041
|
-
/* @__PURE__ */
|
|
30042
|
-
/* @__PURE__ */
|
|
30285
|
+
return /* @__PURE__ */ jsxs55(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
30286
|
+
/* @__PURE__ */ jsx56(Text, { bold: true, color: "cyan", children: "\u2501\u2501 Help / Command Palette \u2501\u2501" }),
|
|
30287
|
+
/* @__PURE__ */ jsx56(Text, { dimColor: true, children: hasFilter ? `Filter: ${filter} (${filtered.length} match${filtered.length === 1 ? "" : "es"})` : "\u2191/\u2193 navigate \xB7 Enter run \xB7 Tab fill \xB7 type to filter \xB7 Esc close" }),
|
|
30288
|
+
/* @__PURE__ */ jsx56(Box, { marginTop: 1, flexDirection: "column", children: filtered.length === 0 ? /* @__PURE__ */ jsxs55(Text, { dimColor: true, children: [
|
|
30043
30289
|
'No commands match "',
|
|
30044
30290
|
filter,
|
|
30045
30291
|
'".'
|
|
30046
|
-
] }) : /* @__PURE__ */
|
|
30047
|
-
hiddenAbove > 0 && !hasFilter ? /* @__PURE__ */
|
|
30048
|
-
contextHeader && !hasFilter ? /* @__PURE__ */
|
|
30292
|
+
] }) : /* @__PURE__ */ jsxs55(Fragment18, { children: [
|
|
30293
|
+
hiddenAbove > 0 && !hasFilter ? /* @__PURE__ */ jsx56(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }) : null,
|
|
30294
|
+
contextHeader && !hasFilter ? /* @__PURE__ */ jsxs55(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
30049
30295
|
" ",
|
|
30050
30296
|
contextHeader
|
|
30051
30297
|
] }) : null,
|
|
30052
30298
|
visible.map((row) => {
|
|
30053
30299
|
if (row.type === "header") {
|
|
30054
|
-
return /* @__PURE__ */
|
|
30300
|
+
return /* @__PURE__ */ jsxs55(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
30055
30301
|
" ",
|
|
30056
30302
|
row.category
|
|
30057
30303
|
] }, `cat-${row.category}`);
|
|
30058
30304
|
}
|
|
30059
30305
|
const { entry, index } = row;
|
|
30060
30306
|
const isSelected = index === focus;
|
|
30061
|
-
return /* @__PURE__ */
|
|
30307
|
+
return /* @__PURE__ */ jsxs55(
|
|
30062
30308
|
Text,
|
|
30063
30309
|
{
|
|
30064
30310
|
inverse: isSelected,
|
|
@@ -30066,20 +30312,20 @@ function HelpPanel({
|
|
|
30066
30312
|
wrap: "truncate-end",
|
|
30067
30313
|
children: [
|
|
30068
30314
|
isSelected ? "\u203A " : " ",
|
|
30069
|
-
/* @__PURE__ */
|
|
30315
|
+
/* @__PURE__ */ jsxs55(Text, { bold: true, children: [
|
|
30070
30316
|
"/",
|
|
30071
30317
|
entry.name
|
|
30072
30318
|
] }),
|
|
30073
|
-
entry.aliases && entry.aliases.length > 0 ? /* @__PURE__ */
|
|
30319
|
+
entry.aliases && entry.aliases.length > 0 ? /* @__PURE__ */ jsxs55(Text, { dimColor: true, children: [
|
|
30074
30320
|
" (",
|
|
30075
30321
|
entry.aliases.map((a) => `/${a}`).join(", "),
|
|
30076
30322
|
")"
|
|
30077
30323
|
] }) : null,
|
|
30078
|
-
/* @__PURE__ */
|
|
30324
|
+
/* @__PURE__ */ jsxs55(Text, { dimColor: true, children: [
|
|
30079
30325
|
" \u2014 ",
|
|
30080
30326
|
entry.description
|
|
30081
30327
|
] }),
|
|
30082
|
-
entry.argsHint ? /* @__PURE__ */
|
|
30328
|
+
entry.argsHint ? /* @__PURE__ */ jsxs55(Text, { dimColor: true, children: [
|
|
30083
30329
|
" ",
|
|
30084
30330
|
entry.argsHint
|
|
30085
30331
|
] }) : null
|
|
@@ -30088,30 +30334,30 @@ function HelpPanel({
|
|
|
30088
30334
|
entry.name
|
|
30089
30335
|
);
|
|
30090
30336
|
}),
|
|
30091
|
-
hiddenBelow > 0 && !hasFilter ? /* @__PURE__ */
|
|
30337
|
+
hiddenBelow > 0 && !hasFilter ? /* @__PURE__ */ jsx56(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }) : null
|
|
30092
30338
|
] }) }),
|
|
30093
|
-
hint ? /* @__PURE__ */
|
|
30339
|
+
hint ? /* @__PURE__ */ jsx56(Box, { marginTop: 1, children: /* @__PURE__ */ jsx56(Text, { dimColor: true, children: hint }) }) : null
|
|
30094
30340
|
] });
|
|
30095
30341
|
}
|
|
30096
30342
|
|
|
30097
30343
|
// src/components/mcp-picker.tsx
|
|
30098
|
-
import { Fragment as Fragment19, jsx as
|
|
30344
|
+
import { Fragment as Fragment19, jsx as jsx57, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
30099
30345
|
var CHROME_ROWS4 = 17;
|
|
30100
30346
|
function statusBadge(status, enabled) {
|
|
30101
|
-
if (!enabled) return /* @__PURE__ */
|
|
30347
|
+
if (!enabled) return /* @__PURE__ */ jsx57(Text, { dimColor: true, children: "\u25CB disabled" });
|
|
30102
30348
|
switch (status) {
|
|
30103
30349
|
case "connected":
|
|
30104
|
-
return /* @__PURE__ */
|
|
30350
|
+
return /* @__PURE__ */ jsx57(Text, { color: "green", children: "\u25CF connected" });
|
|
30105
30351
|
case "connecting":
|
|
30106
|
-
return /* @__PURE__ */
|
|
30352
|
+
return /* @__PURE__ */ jsx57(Text, { color: "cyan", children: "\u25D0 connecting" });
|
|
30107
30353
|
case "reconnecting":
|
|
30108
|
-
return /* @__PURE__ */
|
|
30354
|
+
return /* @__PURE__ */ jsx57(Text, { color: "cyan", children: "\u25D1 reconnecting" });
|
|
30109
30355
|
case "disconnected":
|
|
30110
|
-
return /* @__PURE__ */
|
|
30356
|
+
return /* @__PURE__ */ jsx57(Text, { dimColor: true, children: "\u25CB disconnected" });
|
|
30111
30357
|
case "failed":
|
|
30112
|
-
return /* @__PURE__ */
|
|
30358
|
+
return /* @__PURE__ */ jsx57(Text, { color: "red", children: "\u2717 failed" });
|
|
30113
30359
|
default:
|
|
30114
|
-
return /* @__PURE__ */
|
|
30360
|
+
return /* @__PURE__ */ jsx57(Text, { dimColor: true, children: status });
|
|
30115
30361
|
}
|
|
30116
30362
|
}
|
|
30117
30363
|
function McpPicker({
|
|
@@ -30128,36 +30374,36 @@ function McpPicker({
|
|
|
30128
30374
|
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
30129
30375
|
const above = windowStart;
|
|
30130
30376
|
const below = total - windowEnd;
|
|
30131
|
-
return /* @__PURE__ */
|
|
30132
|
-
/* @__PURE__ */
|
|
30133
|
-
/* @__PURE__ */
|
|
30134
|
-
/* @__PURE__ */
|
|
30135
|
-
above > 0 ? /* @__PURE__ */
|
|
30377
|
+
return /* @__PURE__ */ jsxs56(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
30378
|
+
/* @__PURE__ */ jsx57(Text, { bold: true, color: "cyan", children: "MCP Servers" }),
|
|
30379
|
+
/* @__PURE__ */ jsx57(Text, { dimColor: true, children: "\u2191/\u2193 select \xB7 Enter/\u2190/\u2192 toggle enable \xB7 r restart \xB7 Esc close" }),
|
|
30380
|
+
/* @__PURE__ */ jsx57(Box, { marginTop: 1, flexDirection: "column", children: items.length === 0 ? /* @__PURE__ */ jsx57(Text, { dimColor: true, children: busy ? "Loading servers\u2026" : "No MCP servers configured." }) : /* @__PURE__ */ jsxs56(Fragment19, { children: [
|
|
30381
|
+
above > 0 ? /* @__PURE__ */ jsx57(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
30136
30382
|
items.slice(windowStart, windowEnd).map((item, i) => {
|
|
30137
30383
|
const index = windowStart + i;
|
|
30138
30384
|
const focused = index === selected;
|
|
30139
30385
|
const marker = focused ? "\u203A" : " ";
|
|
30140
|
-
return /* @__PURE__ */
|
|
30386
|
+
return /* @__PURE__ */ jsxs56(Text, { color: focused ? "cyan" : void 0, wrap: "truncate-end", children: [
|
|
30141
30387
|
marker,
|
|
30142
30388
|
" ",
|
|
30143
30389
|
statusBadge(item.status, item.enabled),
|
|
30144
30390
|
" ",
|
|
30145
|
-
/* @__PURE__ */
|
|
30146
|
-
/* @__PURE__ */
|
|
30391
|
+
/* @__PURE__ */ jsx57(Text, { bold: true, children: item.name.padEnd(18) }),
|
|
30392
|
+
/* @__PURE__ */ jsxs56(Text, { dimColor: true, children: [
|
|
30147
30393
|
item.transport.padEnd(14),
|
|
30148
30394
|
item.toolCount > 0 ? `${item.toolCount} tools` : "",
|
|
30149
30395
|
item.lazy ? " lazy" : ""
|
|
30150
30396
|
] })
|
|
30151
30397
|
] }, item.name);
|
|
30152
30398
|
}),
|
|
30153
|
-
below > 0 ? /* @__PURE__ */
|
|
30399
|
+
below > 0 ? /* @__PURE__ */ jsx57(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
30154
30400
|
] }) }),
|
|
30155
|
-
hint ? /* @__PURE__ */
|
|
30401
|
+
hint ? /* @__PURE__ */ jsx57(Box, { marginTop: 1, children: /* @__PURE__ */ jsx57(Text, { dimColor: true, children: hint }) }) : null
|
|
30156
30402
|
] });
|
|
30157
30403
|
}
|
|
30158
30404
|
|
|
30159
30405
|
// src/components/model-picker.tsx
|
|
30160
|
-
import { jsx as
|
|
30406
|
+
import { jsx as jsx58, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
30161
30407
|
var MAX_VISIBLE2 = 10;
|
|
30162
30408
|
function getVisibleWindow2(selected, total) {
|
|
30163
30409
|
const half = Math.floor(MAX_VISIBLE2 / 2);
|
|
@@ -30185,27 +30431,27 @@ function ModelPicker({
|
|
|
30185
30431
|
}) {
|
|
30186
30432
|
const title = titleLabel ?? "Switch model";
|
|
30187
30433
|
if (step === "provider") {
|
|
30188
|
-
return /* @__PURE__ */
|
|
30189
|
-
/* @__PURE__ */
|
|
30190
|
-
/* @__PURE__ */
|
|
30191
|
-
providerOptions.length === 0 ? /* @__PURE__ */
|
|
30434
|
+
return /* @__PURE__ */ jsxs57(Box, { flexDirection: "column", borderStyle: "round", borderColor: UI_COLORS.border, paddingX: 1, children: [
|
|
30435
|
+
/* @__PURE__ */ jsx58(Text, { color: UI_COLORS.title, bold: true, children: `\u2501\u2501 ${title} \u2014 Step 1/2: Pick provider \u2501\u2501` }),
|
|
30436
|
+
/* @__PURE__ */ jsx58(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
|
|
30437
|
+
providerOptions.length === 0 ? /* @__PURE__ */ jsx58(Text, { dimColor: true, children: "(no providers with keys \u2014 add one via `wstack auth`)" }) : /* @__PURE__ */ jsx58(Box, { flexDirection: "column", minHeight: providerOptions.length, children: providerOptions.map((p, i) => {
|
|
30192
30438
|
const isSelected = i === selected;
|
|
30193
30439
|
const famColor = colorForFamily(p.family);
|
|
30194
|
-
return /* @__PURE__ */
|
|
30440
|
+
return /* @__PURE__ */ jsxs57(
|
|
30195
30441
|
Text,
|
|
30196
30442
|
{
|
|
30197
30443
|
inverse: isSelected,
|
|
30198
30444
|
...isSelected ? { color: UI_COLORS.focused } : {},
|
|
30199
30445
|
children: [
|
|
30200
30446
|
isSelected ? "\u203A " : " ",
|
|
30201
|
-
/* @__PURE__ */
|
|
30202
|
-
/* @__PURE__ */
|
|
30447
|
+
/* @__PURE__ */ jsx58(Text, { bold: true, color: isSelected ? void 0 : famColor, children: p.id.padEnd(28) }),
|
|
30448
|
+
/* @__PURE__ */ jsxs57(Text, { color: isSelected ? void 0 : famColor, dimColor: !isSelected, children: [
|
|
30203
30449
|
" ",
|
|
30204
30450
|
"[",
|
|
30205
30451
|
p.family,
|
|
30206
30452
|
"]"
|
|
30207
30453
|
] }),
|
|
30208
|
-
/* @__PURE__ */
|
|
30454
|
+
/* @__PURE__ */ jsxs57(Text, { dimColor: true, children: [
|
|
30209
30455
|
" ",
|
|
30210
30456
|
p.models.length,
|
|
30211
30457
|
" model",
|
|
@@ -30216,15 +30462,15 @@ function ModelPicker({
|
|
|
30216
30462
|
p.id
|
|
30217
30463
|
);
|
|
30218
30464
|
}) }),
|
|
30219
|
-
hint ? /* @__PURE__ */
|
|
30465
|
+
hint ? /* @__PURE__ */ jsx58(Text, { color: UI_COLORS.hint, children: hint }) : null
|
|
30220
30466
|
] });
|
|
30221
30467
|
}
|
|
30222
30468
|
const total = filteredOptions.length;
|
|
30223
30469
|
const { start, end } = getVisibleWindow2(selected, total);
|
|
30224
30470
|
const visibleItems = filteredOptions.slice(start, end);
|
|
30225
30471
|
const searchHint = searchQuery ? ` | filter:"${searchQuery}" \u2192 ${total} match${total === 1 ? "" : "es"}` : total > MAX_VISIBLE2 ? ` (${total} models \u2014 type to filter)` : "";
|
|
30226
|
-
return /* @__PURE__ */
|
|
30227
|
-
/* @__PURE__ */
|
|
30472
|
+
return /* @__PURE__ */ jsxs57(Box, { flexDirection: "column", borderStyle: "round", borderColor: UI_COLORS.border, paddingX: 1, children: [
|
|
30473
|
+
/* @__PURE__ */ jsxs57(Text, { color: UI_COLORS.title, bold: true, children: [
|
|
30228
30474
|
`\u2501\u2501 ${title} \u2014 Step 2/2: Pick model `,
|
|
30229
30475
|
"(",
|
|
30230
30476
|
pickedProviderId,
|
|
@@ -30232,9 +30478,9 @@ function ModelPicker({
|
|
|
30232
30478
|
")",
|
|
30233
30479
|
" \u2501\u2501"
|
|
30234
30480
|
] }),
|
|
30235
|
-
/* @__PURE__ */
|
|
30236
|
-
total === 0 ? /* @__PURE__ */
|
|
30237
|
-
start > 0 && /* @__PURE__ */
|
|
30481
|
+
/* @__PURE__ */ jsx58(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc back \xB7 Ctrl+C exit \xB7 type to filter" }),
|
|
30482
|
+
total === 0 ? /* @__PURE__ */ jsx58(Text, { dimColor: true, children: searchQuery ? `(no models match "${searchQuery}")` : "(no models known for this provider)" }) : /* @__PURE__ */ jsxs57(Box, { flexDirection: "column", minHeight: MAX_VISIBLE2 + 2, children: [
|
|
30483
|
+
start > 0 && /* @__PURE__ */ jsxs57(Text, { dimColor: true, children: [
|
|
30238
30484
|
"\u25B2 ",
|
|
30239
30485
|
start,
|
|
30240
30486
|
" above"
|
|
@@ -30242,7 +30488,7 @@ function ModelPicker({
|
|
|
30242
30488
|
visibleItems.map((id, vi) => {
|
|
30243
30489
|
const absoluteIndex = start + vi;
|
|
30244
30490
|
const isSelected = absoluteIndex === selected;
|
|
30245
|
-
return /* @__PURE__ */
|
|
30491
|
+
return /* @__PURE__ */ jsxs57(
|
|
30246
30492
|
Text,
|
|
30247
30493
|
{
|
|
30248
30494
|
inverse: isSelected,
|
|
@@ -30256,20 +30502,20 @@ function ModelPicker({
|
|
|
30256
30502
|
);
|
|
30257
30503
|
}),
|
|
30258
30504
|
Array.from({ length: MAX_VISIBLE2 - visibleItems.length }).map(
|
|
30259
|
-
(_, i) => /* @__PURE__ */
|
|
30505
|
+
(_, i) => /* @__PURE__ */ jsx58(Text, { children: " " }, `pad-${i}`)
|
|
30260
30506
|
),
|
|
30261
|
-
end < total && /* @__PURE__ */
|
|
30507
|
+
end < total && /* @__PURE__ */ jsxs57(Text, { dimColor: true, children: [
|
|
30262
30508
|
"\u25BC ",
|
|
30263
30509
|
total - end,
|
|
30264
30510
|
" below"
|
|
30265
30511
|
] })
|
|
30266
30512
|
] }),
|
|
30267
|
-
hint ? /* @__PURE__ */
|
|
30513
|
+
hint ? /* @__PURE__ */ jsx58(Text, { color: UI_COLORS.hint, children: hint }) : null
|
|
30268
30514
|
] });
|
|
30269
30515
|
}
|
|
30270
30516
|
|
|
30271
30517
|
// src/components/plugin-picker.tsx
|
|
30272
|
-
import { Fragment as Fragment20, jsx as
|
|
30518
|
+
import { Fragment as Fragment20, jsx as jsx59, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
30273
30519
|
var CHROME_ROWS5 = 17;
|
|
30274
30520
|
var MAX_PICKER_ITEMS = 15;
|
|
30275
30521
|
function PluginPicker({
|
|
@@ -30287,15 +30533,15 @@ function PluginPicker({
|
|
|
30287
30533
|
const above = windowStart;
|
|
30288
30534
|
const below = total - windowEnd;
|
|
30289
30535
|
const hasLockedRows = items.some((item) => item.lockable === false);
|
|
30290
|
-
return /* @__PURE__ */
|
|
30291
|
-
/* @__PURE__ */
|
|
30292
|
-
/* @__PURE__ */
|
|
30536
|
+
return /* @__PURE__ */ jsxs58(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
30537
|
+
/* @__PURE__ */ jsx59(Text, { bold: true, color: "cyan", children: "Plugin menu" }),
|
|
30538
|
+
/* @__PURE__ */ jsxs58(Text, { dimColor: true, children: [
|
|
30293
30539
|
"\u2191/\u2193 select \xB7 Enter/\u2190/\u2192 toggle",
|
|
30294
30540
|
hasLockedRows ? " \xB7 \u{1F512} = locked" : "",
|
|
30295
30541
|
" \xB7 Esc close"
|
|
30296
30542
|
] }),
|
|
30297
|
-
/* @__PURE__ */
|
|
30298
|
-
above > 0 ? /* @__PURE__ */
|
|
30543
|
+
/* @__PURE__ */ jsx59(Box, { marginTop: 1, flexDirection: "column", children: items.length === 0 ? /* @__PURE__ */ jsx59(Text, { dimColor: true, children: busy ? "Loading plugins\u2026" : "No plugins available." }) : /* @__PURE__ */ jsxs58(Fragment20, { children: [
|
|
30544
|
+
above > 0 ? /* @__PURE__ */ jsx59(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
30299
30545
|
items.slice(windowStart, windowEnd).map((item, i) => {
|
|
30300
30546
|
const index = windowStart + i;
|
|
30301
30547
|
const focused = index === selected;
|
|
@@ -30304,16 +30550,16 @@ function PluginPicker({
|
|
|
30304
30550
|
const state = item.enabled ? "\u25CF on " : "\u25CB off";
|
|
30305
30551
|
const color = item.enabled ? "green" : "gray";
|
|
30306
30552
|
const lock = isLocked ? "\u{1F512}" : " ";
|
|
30307
|
-
return /* @__PURE__ */
|
|
30553
|
+
return /* @__PURE__ */ jsxs58(Text, { color: focused ? "cyan" : void 0, wrap: "truncate-end", children: [
|
|
30308
30554
|
marker,
|
|
30309
30555
|
" ",
|
|
30310
|
-
/* @__PURE__ */
|
|
30556
|
+
/* @__PURE__ */ jsx59(Text, { color, children: state }),
|
|
30311
30557
|
" ",
|
|
30312
30558
|
item.name.padEnd(18),
|
|
30313
30559
|
" ",
|
|
30314
|
-
/* @__PURE__ */
|
|
30560
|
+
/* @__PURE__ */ jsx59(Text, { color: isLocked ? "yellow" : void 0, children: lock }),
|
|
30315
30561
|
" ",
|
|
30316
|
-
/* @__PURE__ */
|
|
30562
|
+
/* @__PURE__ */ jsxs58(Text, { dimColor: true, children: [
|
|
30317
30563
|
"risk=",
|
|
30318
30564
|
item.risk.padEnd(6)
|
|
30319
30565
|
] }),
|
|
@@ -30321,14 +30567,14 @@ function PluginPicker({
|
|
|
30321
30567
|
item.summary
|
|
30322
30568
|
] }, item.name);
|
|
30323
30569
|
}),
|
|
30324
|
-
below > 0 ? /* @__PURE__ */
|
|
30570
|
+
below > 0 ? /* @__PURE__ */ jsx59(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
30325
30571
|
] }) }),
|
|
30326
|
-
hint ? /* @__PURE__ */
|
|
30572
|
+
hint ? /* @__PURE__ */ jsx59(Box, { marginTop: 1, children: /* @__PURE__ */ jsx59(Text, { dimColor: true, children: hint }) }) : null
|
|
30327
30573
|
] });
|
|
30328
30574
|
}
|
|
30329
30575
|
|
|
30330
30576
|
// src/components/project-picker.tsx
|
|
30331
|
-
import { jsx as
|
|
30577
|
+
import { jsx as jsx60, jsxs as jsxs59 } from "react/jsx-runtime";
|
|
30332
30578
|
function actionIcon(key) {
|
|
30333
30579
|
if (key === "new-session") return glyphs.sessions;
|
|
30334
30580
|
if (key === "prev-sessions") return glyphs.clock;
|
|
@@ -30348,71 +30594,71 @@ function ProjectPicker({
|
|
|
30348
30594
|
const window = panelWindow(items.length, selected, limit);
|
|
30349
30595
|
const visible = items.slice(window.start, window.end);
|
|
30350
30596
|
const labelWidth = Math.max(12, size.contentWidth - 16);
|
|
30351
|
-
return /* @__PURE__ */
|
|
30597
|
+
return /* @__PURE__ */ jsxs59(
|
|
30352
30598
|
MonitorShell,
|
|
30353
30599
|
{
|
|
30354
30600
|
accent: theme.accent,
|
|
30355
30601
|
icon: glyphs.folder,
|
|
30356
30602
|
title: "PROJECTS",
|
|
30357
30603
|
kicker: size.columns >= 58 ? "workspace switcher" : void 0,
|
|
30358
|
-
right: /* @__PURE__ */
|
|
30604
|
+
right: /* @__PURE__ */ jsxs59(Text, { color: theme.textMuted, children: [
|
|
30359
30605
|
projectCount,
|
|
30360
30606
|
" project",
|
|
30361
30607
|
projectCount === 1 ? "" : "s"
|
|
30362
30608
|
] }),
|
|
30363
|
-
footer: /* @__PURE__ */
|
|
30364
|
-
/* @__PURE__ */
|
|
30365
|
-
/* @__PURE__ */
|
|
30366
|
-
size.columns >= 64 ? /* @__PURE__ */
|
|
30609
|
+
footer: /* @__PURE__ */ jsxs59(Box, { gap: 2, children: [
|
|
30610
|
+
/* @__PURE__ */ jsx60(KeyCap, { keyName: "\u2191\u2193", label: "navigate" }),
|
|
30611
|
+
/* @__PURE__ */ jsx60(KeyCap, { keyName: "Enter", label: "open", color: theme.success }),
|
|
30612
|
+
size.columns >= 64 ? /* @__PURE__ */ jsx60(KeyCap, { keyName: "Esc", label: "close", color: theme.error }) : null
|
|
30367
30613
|
] }),
|
|
30368
30614
|
children: [
|
|
30369
|
-
/* @__PURE__ */
|
|
30370
|
-
/* @__PURE__ */
|
|
30615
|
+
/* @__PURE__ */ jsxs59(Box, { height: 1, marginTop: 1, children: [
|
|
30616
|
+
/* @__PURE__ */ jsxs59(Text, { color: filter ? theme.warn : theme.textMuted, children: [
|
|
30371
30617
|
glyphs.prompt,
|
|
30372
30618
|
" "
|
|
30373
30619
|
] }),
|
|
30374
|
-
/* @__PURE__ */
|
|
30375
|
-
filter ? /* @__PURE__ */
|
|
30376
|
-
/* @__PURE__ */
|
|
30377
|
-
/* @__PURE__ */
|
|
30620
|
+
/* @__PURE__ */ jsx60(Text, { color: filter ? theme.textPrimary : theme.textMuted, children: filter || "Type to filter projects and actions" }),
|
|
30621
|
+
filter ? /* @__PURE__ */ jsx60(Text, { color: theme.accent, children: "\u2588" }) : null,
|
|
30622
|
+
/* @__PURE__ */ jsx60(Box, { flexGrow: 1 }),
|
|
30623
|
+
/* @__PURE__ */ jsxs59(Text, { color: theme.textMuted, children: [
|
|
30378
30624
|
selectableCount,
|
|
30379
30625
|
" choices"
|
|
30380
30626
|
] })
|
|
30381
30627
|
] }),
|
|
30382
|
-
window.above > 0 ? /* @__PURE__ */
|
|
30628
|
+
window.above > 0 ? /* @__PURE__ */ jsxs59(Text, { color: theme.textMuted, children: [
|
|
30383
30629
|
" \u2191 ",
|
|
30384
30630
|
window.above,
|
|
30385
30631
|
" hidden"
|
|
30386
30632
|
] }) : null,
|
|
30387
|
-
visible.length === 0 ? /* @__PURE__ */
|
|
30633
|
+
visible.length === 0 ? /* @__PURE__ */ jsx60(
|
|
30388
30634
|
EmptyPanelState,
|
|
30389
30635
|
{
|
|
30390
30636
|
icon: glyphs.folder,
|
|
30391
30637
|
title: "No matching projects",
|
|
30392
30638
|
detail: "Clear the filter or add a project with /project add."
|
|
30393
30639
|
}
|
|
30394
|
-
) : /* @__PURE__ */
|
|
30640
|
+
) : /* @__PURE__ */ jsx60(Box, { flexDirection: "column", marginTop: 1, children: visible.map((item, offset) => {
|
|
30395
30641
|
const index = window.start + offset;
|
|
30396
30642
|
const isSelected = index === selected;
|
|
30397
30643
|
if (item.key === "__divider__") {
|
|
30398
|
-
return /* @__PURE__ */
|
|
30644
|
+
return /* @__PURE__ */ jsx60(Box, { height: 1, children: /* @__PURE__ */ jsx60(Text, { color: theme.textMuted, children: "\u2500".repeat(Math.min(32, size.contentWidth)) }) }, `${item.key}-${index}`);
|
|
30399
30645
|
}
|
|
30400
30646
|
const icon = item.kind === "project" ? glyphs.folder : actionIcon(item.key);
|
|
30401
30647
|
const accent = item.kind === "project" ? theme.accent : theme.warn;
|
|
30402
|
-
return /* @__PURE__ */
|
|
30648
|
+
return /* @__PURE__ */ jsxs59(
|
|
30403
30649
|
Box,
|
|
30404
30650
|
{
|
|
30405
30651
|
flexDirection: "column",
|
|
30406
30652
|
...isSelected && theme.supportsBackground ? { backgroundColor: theme.surfaceRaised } : {},
|
|
30407
30653
|
children: [
|
|
30408
|
-
/* @__PURE__ */
|
|
30409
|
-
/* @__PURE__ */
|
|
30410
|
-
/* @__PURE__ */
|
|
30654
|
+
/* @__PURE__ */ jsxs59(Box, { height: 1, children: [
|
|
30655
|
+
/* @__PURE__ */ jsx60(Text, { color: isSelected ? accent : theme.textMuted, children: isSelected ? "\u258E" : " " }),
|
|
30656
|
+
/* @__PURE__ */ jsxs59(Text, { color: accent, children: [
|
|
30411
30657
|
" ",
|
|
30412
30658
|
icon,
|
|
30413
30659
|
" "
|
|
30414
30660
|
] }),
|
|
30415
|
-
/* @__PURE__ */
|
|
30661
|
+
/* @__PURE__ */ jsx60(
|
|
30416
30662
|
Text,
|
|
30417
30663
|
{
|
|
30418
30664
|
color: isSelected ? theme.textPrimary : theme.textSecondary,
|
|
@@ -30420,24 +30666,24 @@ function ProjectPicker({
|
|
|
30420
30666
|
children: truncatePanelText(item.label, labelWidth)
|
|
30421
30667
|
}
|
|
30422
30668
|
),
|
|
30423
|
-
/* @__PURE__ */
|
|
30424
|
-
item.meta ? /* @__PURE__ */
|
|
30669
|
+
/* @__PURE__ */ jsx60(Box, { flexGrow: 1 }),
|
|
30670
|
+
item.meta ? /* @__PURE__ */ jsx60(Text, { color: isSelected ? accent : theme.textMuted, children: truncatePanelText(item.meta, 18) }) : null
|
|
30425
30671
|
] }),
|
|
30426
|
-
item.subtitle ? /* @__PURE__ */
|
|
30427
|
-
/* @__PURE__ */
|
|
30428
|
-
/* @__PURE__ */
|
|
30672
|
+
item.subtitle ? /* @__PURE__ */ jsxs59(Box, { height: 1, children: [
|
|
30673
|
+
/* @__PURE__ */ jsx60(Text, { color: isSelected ? accent : theme.textMuted, children: " \u2514\u2500 " }),
|
|
30674
|
+
/* @__PURE__ */ jsx60(Text, { color: theme.textMuted, children: truncatePanelText(item.subtitle, labelWidth) })
|
|
30429
30675
|
] }) : null
|
|
30430
30676
|
]
|
|
30431
30677
|
},
|
|
30432
30678
|
item.key
|
|
30433
30679
|
);
|
|
30434
30680
|
}) }),
|
|
30435
|
-
window.below > 0 ? /* @__PURE__ */
|
|
30681
|
+
window.below > 0 ? /* @__PURE__ */ jsxs59(Text, { color: theme.textMuted, children: [
|
|
30436
30682
|
" \u2193 ",
|
|
30437
30683
|
window.below,
|
|
30438
30684
|
" hidden"
|
|
30439
30685
|
] }) : null,
|
|
30440
|
-
hint ? /* @__PURE__ */
|
|
30686
|
+
hint ? /* @__PURE__ */ jsxs59(Text, { color: theme.warn, children: [
|
|
30441
30687
|
glyphs.warning,
|
|
30442
30688
|
" ",
|
|
30443
30689
|
hint
|
|
@@ -30447,9 +30693,94 @@ function ProjectPicker({
|
|
|
30447
30693
|
);
|
|
30448
30694
|
}
|
|
30449
30695
|
|
|
30696
|
+
// src/components/refine-countdown-panel.tsx
|
|
30697
|
+
import { useEffect as useEffect64, useRef as useRef35, useState as useState37 } from "react";
|
|
30698
|
+
import { jsx as jsx61, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
30699
|
+
function RefineCountdownPanel({
|
|
30700
|
+
original,
|
|
30701
|
+
seconds,
|
|
30702
|
+
onDecision,
|
|
30703
|
+
providerId,
|
|
30704
|
+
model
|
|
30705
|
+
}) {
|
|
30706
|
+
const [remaining, setRemaining] = useState37(Math.max(1, seconds));
|
|
30707
|
+
const resolvedRef = useRef35(false);
|
|
30708
|
+
useEffect64(() => {
|
|
30709
|
+
const id = setInterval(() => {
|
|
30710
|
+
setRemaining((prev) => {
|
|
30711
|
+
if (prev <= 1) {
|
|
30712
|
+
clearInterval(id);
|
|
30713
|
+
if (!resolvedRef.current) {
|
|
30714
|
+
resolvedRef.current = true;
|
|
30715
|
+
onDecision("proceed");
|
|
30716
|
+
}
|
|
30717
|
+
return 0;
|
|
30718
|
+
}
|
|
30719
|
+
return prev - 1;
|
|
30720
|
+
});
|
|
30721
|
+
}, 1e3);
|
|
30722
|
+
return () => clearInterval(id);
|
|
30723
|
+
}, []);
|
|
30724
|
+
useInput((_input, key) => {
|
|
30725
|
+
if (resolvedRef.current) return;
|
|
30726
|
+
resolvedRef.current = true;
|
|
30727
|
+
if (key.escape) onDecision("cancel");
|
|
30728
|
+
else if (key.return) onDecision("proceed");
|
|
30729
|
+
else onDecision("skip");
|
|
30730
|
+
});
|
|
30731
|
+
const preview = wrapRefinementPreview(original, 60, 2);
|
|
30732
|
+
return /* @__PURE__ */ jsxs60(
|
|
30733
|
+
Box,
|
|
30734
|
+
{
|
|
30735
|
+
alignSelf: "stretch",
|
|
30736
|
+
width: "100%",
|
|
30737
|
+
flexDirection: "column",
|
|
30738
|
+
borderStyle: "round",
|
|
30739
|
+
borderColor: theme.brand,
|
|
30740
|
+
paddingX: 1,
|
|
30741
|
+
children: [
|
|
30742
|
+
/* @__PURE__ */ jsxs60(Box, { height: 1, children: [
|
|
30743
|
+
/* @__PURE__ */ jsxs60(Text, { color: theme.brand, bold: true, children: [
|
|
30744
|
+
glyphs.brain,
|
|
30745
|
+
" PROMPT REFINER"
|
|
30746
|
+
] }),
|
|
30747
|
+
providerId && model ? /* @__PURE__ */ jsxs60(Text, { color: theme.textMuted, children: [
|
|
30748
|
+
" ",
|
|
30749
|
+
"on ",
|
|
30750
|
+
providerId,
|
|
30751
|
+
"/",
|
|
30752
|
+
model
|
|
30753
|
+
] }) : null,
|
|
30754
|
+
/* @__PURE__ */ jsx61(Box, { flexGrow: 1 }),
|
|
30755
|
+
/* @__PURE__ */ jsxs60(Text, { color: theme.brand, children: [
|
|
30756
|
+
"refining in ",
|
|
30757
|
+
remaining,
|
|
30758
|
+
"s\u2026"
|
|
30759
|
+
] })
|
|
30760
|
+
] }),
|
|
30761
|
+
/* @__PURE__ */ jsx61(Box, { flexDirection: "column", marginTop: 1, children: preview.map((line, index) => /* @__PURE__ */ jsxs60(Box, { height: 1, children: [
|
|
30762
|
+
/* @__PURE__ */ jsx61(Text, { color: theme.brand, children: "\u258E" }),
|
|
30763
|
+
/* @__PURE__ */ jsxs60(Text, { color: theme.textSecondary, children: [
|
|
30764
|
+
" ",
|
|
30765
|
+
line
|
|
30766
|
+
] })
|
|
30767
|
+
] }, `refine-countdown-preview-${index}`)) }),
|
|
30768
|
+
/* @__PURE__ */ jsx61(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */ jsx61(Text, { color: theme.textMuted, children: "Enter refines now \xB7 any key sends as-is \xB7 Esc cancels" }) })
|
|
30769
|
+
]
|
|
30770
|
+
}
|
|
30771
|
+
);
|
|
30772
|
+
}
|
|
30773
|
+
|
|
30450
30774
|
// src/components/refine-failure-panel.tsx
|
|
30451
|
-
import { useState as useState38 } from "react";
|
|
30775
|
+
import { useState as useState38, useMemo as useMemo12 } from "react";
|
|
30452
30776
|
import { jsx as jsx62, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
30777
|
+
function filterRefineModels(models, query) {
|
|
30778
|
+
const normalized = query.trim().toLowerCase();
|
|
30779
|
+
if (!normalized) return models;
|
|
30780
|
+
return models.filter(
|
|
30781
|
+
(candidate) => candidate.providerId.toLowerCase().includes(normalized) || candidate.model.toLowerCase().includes(normalized) || candidate.label?.toLowerCase().includes(normalized)
|
|
30782
|
+
);
|
|
30783
|
+
}
|
|
30453
30784
|
var PICK_WINDOW = 8;
|
|
30454
30785
|
function useColumns() {
|
|
30455
30786
|
const { stdout } = useStdout();
|
|
@@ -30466,17 +30797,26 @@ function RefineFailurePanel({
|
|
|
30466
30797
|
const columns = useColumns();
|
|
30467
30798
|
const [view, setView] = useState38("options");
|
|
30468
30799
|
const [cursor, setCursor] = useState38(0);
|
|
30800
|
+
const [query, setQuery] = useState38("");
|
|
30801
|
+
const filteredModels = useMemo12(() => filterRefineModels(models, query), [models, query]);
|
|
30469
30802
|
const width = Math.max(30, columns - 4);
|
|
30470
30803
|
const canPick = models.length > 0;
|
|
30471
30804
|
const canFallback = !!fallbackRef;
|
|
30472
30805
|
useInput((input, key) => {
|
|
30473
30806
|
if (view === "pick") {
|
|
30474
30807
|
if (key.escape) {
|
|
30808
|
+
if (query) {
|
|
30809
|
+
setQuery("");
|
|
30810
|
+
return;
|
|
30811
|
+
}
|
|
30475
30812
|
setView("options");
|
|
30813
|
+
setQuery("");
|
|
30814
|
+
setCursor(0);
|
|
30476
30815
|
return;
|
|
30477
30816
|
}
|
|
30478
30817
|
if (key.downArrow) {
|
|
30479
|
-
|
|
30818
|
+
const n = filteredModels.length;
|
|
30819
|
+
if (n > 0) setCursor((c) => Math.min(c + 1, n - 1));
|
|
30480
30820
|
return;
|
|
30481
30821
|
}
|
|
30482
30822
|
if (key.upArrow) {
|
|
@@ -30484,11 +30824,21 @@ function RefineFailurePanel({
|
|
|
30484
30824
|
return;
|
|
30485
30825
|
}
|
|
30486
30826
|
if (key.return) {
|
|
30487
|
-
const chosen =
|
|
30827
|
+
const chosen = filteredModels[cursor];
|
|
30488
30828
|
if (chosen)
|
|
30489
30829
|
onDecision({ kind: "pick", providerId: chosen.providerId, model: chosen.model });
|
|
30490
30830
|
return;
|
|
30491
30831
|
}
|
|
30832
|
+
if (key.backspace || key.delete) {
|
|
30833
|
+
setQuery((q) => q.slice(0, -1));
|
|
30834
|
+
setCursor(0);
|
|
30835
|
+
return;
|
|
30836
|
+
}
|
|
30837
|
+
if (input && input.length === 1 && input.charCodeAt(0) >= 32 && input.charCodeAt(0) < 127) {
|
|
30838
|
+
setQuery((q) => q + input);
|
|
30839
|
+
setCursor(0);
|
|
30840
|
+
return;
|
|
30841
|
+
}
|
|
30492
30842
|
return;
|
|
30493
30843
|
}
|
|
30494
30844
|
if (key.return) {
|
|
@@ -30503,17 +30853,19 @@ function RefineFailurePanel({
|
|
|
30503
30853
|
if (ch === "m" && canFallback) onDecision({ kind: "fallback" });
|
|
30504
30854
|
else if (ch === "p" && canPick) {
|
|
30505
30855
|
setCursor(0);
|
|
30856
|
+
setQuery("");
|
|
30506
30857
|
setView("pick");
|
|
30507
30858
|
} else if (ch === "s") onDecision({ kind: "original" });
|
|
30508
30859
|
else if (ch === "e") onDecision({ kind: "edit" });
|
|
30509
30860
|
});
|
|
30510
30861
|
if (view === "pick") {
|
|
30862
|
+
const total = filteredModels.length;
|
|
30511
30863
|
const start = Math.max(
|
|
30512
30864
|
0,
|
|
30513
|
-
Math.min(cursor - Math.floor(PICK_WINDOW / 2),
|
|
30865
|
+
Math.min(cursor - Math.floor(PICK_WINDOW / 2), total - PICK_WINDOW)
|
|
30514
30866
|
);
|
|
30515
30867
|
const windowStart = Math.max(0, start);
|
|
30516
|
-
const visible =
|
|
30868
|
+
const visible = filteredModels.slice(windowStart, windowStart + PICK_WINDOW);
|
|
30517
30869
|
return /* @__PURE__ */ jsxs61(
|
|
30518
30870
|
Box,
|
|
30519
30871
|
{
|
|
@@ -30531,12 +30883,17 @@ function RefineFailurePanel({
|
|
|
30531
30883
|
] }),
|
|
30532
30884
|
/* @__PURE__ */ jsx62(Box, { flexGrow: 1 }),
|
|
30533
30885
|
/* @__PURE__ */ jsxs61(Text, { color: theme.textMuted, children: [
|
|
30534
|
-
models.length
|
|
30886
|
+
query ? `${total}/${models.length}` : `${models.length}`,
|
|
30535
30887
|
" model",
|
|
30536
|
-
models.length === 1 ? "" : "s"
|
|
30888
|
+
(query ? total : models.length) === 1 ? "" : "s"
|
|
30537
30889
|
] })
|
|
30538
30890
|
] }),
|
|
30539
|
-
/* @__PURE__ */ jsx62(Box, {
|
|
30891
|
+
/* @__PURE__ */ jsx62(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */ jsx62(Text, { color: theme.textMuted, children: query ? `\u{1F50D} ${query} ` : "\u{1F50D} type to filter" }) }),
|
|
30892
|
+
total === 0 ? /* @__PURE__ */ jsx62(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */ jsxs61(Text, { color: theme.textMuted, children: [
|
|
30893
|
+
'(no models match "',
|
|
30894
|
+
query,
|
|
30895
|
+
'")'
|
|
30896
|
+
] }) }) : /* @__PURE__ */ jsx62(Box, { flexDirection: "column", marginTop: 1, children: visible.map((m, i) => {
|
|
30540
30897
|
const idx = windowStart + i;
|
|
30541
30898
|
const selected = idx === cursor;
|
|
30542
30899
|
const label = m.label && m.label !== m.model ? ` ${m.label}` : "";
|
|
@@ -30546,7 +30903,11 @@ function RefineFailurePanel({
|
|
|
30546
30903
|
/* @__PURE__ */ jsx62(Text, { color: theme.textMuted, children: label })
|
|
30547
30904
|
] }, `${m.providerId}/${m.model}`);
|
|
30548
30905
|
}) }),
|
|
30549
|
-
/* @__PURE__ */ jsx62(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */
|
|
30906
|
+
/* @__PURE__ */ jsx62(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */ jsxs61(Text, { color: theme.textMuted, children: [
|
|
30907
|
+
"\u2191/\u2193 choose \xB7 Enter refine \xB7 ",
|
|
30908
|
+
query ? "Esc clear \xB7 " : "",
|
|
30909
|
+
"Esc back"
|
|
30910
|
+
] }) })
|
|
30550
30911
|
]
|
|
30551
30912
|
}
|
|
30552
30913
|
);
|
|
@@ -30712,7 +31073,7 @@ import {
|
|
|
30712
31073
|
useCallback as useCallback25,
|
|
30713
31074
|
useEffect as useEffect67,
|
|
30714
31075
|
useLayoutEffect as useLayoutEffect2,
|
|
30715
|
-
useMemo as
|
|
31076
|
+
useMemo as useMemo14,
|
|
30716
31077
|
useRef as useRef37,
|
|
30717
31078
|
useState as useState40
|
|
30718
31079
|
} from "react";
|
|
@@ -31153,7 +31514,7 @@ import { Fragment as Fragment21, jsx as jsx65, jsxs as jsxs63 } from "react/jsx-
|
|
|
31153
31514
|
var MAX_TOOL_GROUP_ENTRIES = 12;
|
|
31154
31515
|
var STRUCTURED_DIFF_TOOLS = /* @__PURE__ */ new Set(["edit", "write", "replace", "diff", "patch"]);
|
|
31155
31516
|
function hasInjectedMemory(entry) {
|
|
31156
|
-
return
|
|
31517
|
+
return resolveEntrySage(entry.output, entry.sageLines).sageLines.length > 0;
|
|
31157
31518
|
}
|
|
31158
31519
|
function renderGroupId(group) {
|
|
31159
31520
|
return group.type === "tool-group" ? group.data.entries[0]?.id ?? 0 : group.entry.id;
|
|
@@ -31163,30 +31524,66 @@ function estimateTextRows(text, contentWidth, maxRows) {
|
|
|
31163
31524
|
if (!text) return 1;
|
|
31164
31525
|
const width = Math.max(16, contentWidth);
|
|
31165
31526
|
let rows = 0;
|
|
31166
|
-
let
|
|
31167
|
-
for (
|
|
31168
|
-
if (
|
|
31169
|
-
|
|
31170
|
-
|
|
31171
|
-
|
|
31527
|
+
let lineWidth = 0;
|
|
31528
|
+
for (const char of text) {
|
|
31529
|
+
if (char === "\n") {
|
|
31530
|
+
rows += Math.max(1, Math.ceil(lineWidth / width));
|
|
31531
|
+
if (rows >= maxRows) return maxRows;
|
|
31532
|
+
lineWidth = 0;
|
|
31533
|
+
continue;
|
|
31534
|
+
}
|
|
31535
|
+
lineWidth += displayWidth(char);
|
|
31172
31536
|
}
|
|
31173
|
-
|
|
31537
|
+
rows += Math.max(1, Math.ceil(lineWidth / width));
|
|
31538
|
+
return Math.min(maxRows, Math.max(1, rows));
|
|
31539
|
+
}
|
|
31540
|
+
function estimateSageKvRows(cells, contentWidth) {
|
|
31541
|
+
if (cells.length === 0) return 0;
|
|
31542
|
+
const gap = 2;
|
|
31543
|
+
let rows = 1;
|
|
31544
|
+
let usedColumns = 0;
|
|
31545
|
+
for (const cell of cells) {
|
|
31546
|
+
const cellWidth = displayWidth(cell) + gap;
|
|
31547
|
+
if (usedColumns > 0 && usedColumns + cellWidth > contentWidth) {
|
|
31548
|
+
rows += 1;
|
|
31549
|
+
usedColumns = cellWidth;
|
|
31550
|
+
} else {
|
|
31551
|
+
usedColumns += cellWidth;
|
|
31552
|
+
}
|
|
31553
|
+
}
|
|
31554
|
+
return rows;
|
|
31174
31555
|
}
|
|
31175
31556
|
function estimateRenderGroupRows(group, contentWidth) {
|
|
31176
31557
|
if (group.type === "tool-group") return group.data.entries.length + 2;
|
|
31177
31558
|
const { entry } = group;
|
|
31178
31559
|
if (entry.kind === "tool") {
|
|
31179
|
-
const { cleanOutput, sageLines } =
|
|
31560
|
+
const { cleanOutput, sageLines } = resolveEntrySage(entry.output, entry.sageLines);
|
|
31180
31561
|
const memoryLines = sageLines.slice(1);
|
|
31181
31562
|
const panelContentWidth = Math.max(16, contentWidth - 4);
|
|
31182
31563
|
const sagePanelRows = memoryLines.length > 0 ? 2 + estimateTextRows(
|
|
31183
|
-
`\u{1F9E0} SAGE MEMORY INJECTED \xB7 ${entry.name} ${memoryLines.length} ${memoryLines.length === 1 ? "memory" : "memories"}`,
|
|
31564
|
+
`\u{1F9E0} SAGE MEMORY INJECTED \xB7 ${entry.name} ${memoryLines.length} ${memoryLines.length === 1 ? "memory" : "memories"}${entry.sageStats ? ` \xB7 ${entry.sageStats}` : ""}`,
|
|
31184
31565
|
panelContentWidth,
|
|
31185
31566
|
MAX_TEXT_ESTIMATE_ROWS
|
|
31186
|
-
) + memoryLines.reduce(
|
|
31187
|
-
|
|
31188
|
-
|
|
31189
|
-
|
|
31567
|
+
) + memoryLines.reduce((rows, line) => {
|
|
31568
|
+
const parsed = parseSageMemoryLine(line);
|
|
31569
|
+
if (!parsed) {
|
|
31570
|
+
return rows + estimateTextRows(line, panelContentWidth, MAX_TEXT_ESTIMATE_ROWS);
|
|
31571
|
+
}
|
|
31572
|
+
const labelRow = estimateTextRows(
|
|
31573
|
+
parsed.labels.length > 0 ? parsed.labels.map((l) => `[${l}]`).join("") : "[memory]",
|
|
31574
|
+
panelContentWidth,
|
|
31575
|
+
MAX_TEXT_ESTIMATE_ROWS
|
|
31576
|
+
);
|
|
31577
|
+
const bodyRow = estimateTextRows(parsed.text, panelContentWidth, MAX_TEXT_ESTIMATE_ROWS);
|
|
31578
|
+
const kvCells = [];
|
|
31579
|
+
kvCells.push(`id: ${parsed.id}`);
|
|
31580
|
+
if (parsed.anchor) kvCells.push(`anchor: ${parsed.anchor}`);
|
|
31581
|
+
if (parsed.relation) kvCells.push(`relation: ${parsed.relation}`);
|
|
31582
|
+
if (parsed.tags && parsed.tags.length > 0) kvCells.push(`tags: ${parsed.tags.join(", ")}`);
|
|
31583
|
+
const kvRows = estimateSageKvRows(kvCells, panelContentWidth);
|
|
31584
|
+
const gap = rows > 0 ? 1 : 0;
|
|
31585
|
+
return rows + labelRow + bodyRow + kvRows + gap;
|
|
31586
|
+
}, 0) : 0;
|
|
31190
31587
|
if (entry.resultRenderMode === "simple") return 3 + sagePanelRows;
|
|
31191
31588
|
if (STRUCTURED_DIFF_TOOLS.has(entry.name)) {
|
|
31192
31589
|
const previewCap = entry.name === "replace" || entry.name === "diff" || entry.name === "patch" ? MULTI_DIFF_MAX_ROWS : DIFF_MAX_LINES;
|
|
@@ -31371,7 +31768,7 @@ import { memo as memo2, useEffect as useEffect66, useRef as useRef36, useState a
|
|
|
31371
31768
|
// src/components/history/entry.tsx
|
|
31372
31769
|
import { hasOpenTodos } from "@wrongstack/core/utils";
|
|
31373
31770
|
import { parseNextSteps } from "@wrongstack/tools/next-steps";
|
|
31374
|
-
import React8, { useEffect as useEffect65, useMemo as
|
|
31771
|
+
import React8, { useEffect as useEffect65, useMemo as useMemo13 } from "react";
|
|
31375
31772
|
|
|
31376
31773
|
// src/markdown-table.ts
|
|
31377
31774
|
import { expectDefined as expectDefined4 } from "@wrongstack/core/utils";
|
|
@@ -32359,8 +32756,28 @@ function ToolCard({
|
|
|
32359
32756
|
] });
|
|
32360
32757
|
}
|
|
32361
32758
|
|
|
32759
|
+
// src/history-entry.ts
|
|
32760
|
+
import {
|
|
32761
|
+
DEFAULT_MIN_IMPORTANCE as DEFAULT_MIN_IMPORTANCE2,
|
|
32762
|
+
DEFAULT_MIN_SCORE as DEFAULT_MIN_SCORE2,
|
|
32763
|
+
MIN_RELATION_STRENGTH as MIN_RELATION_STRENGTH2
|
|
32764
|
+
} from "@wrongstack/sage";
|
|
32765
|
+
var MEMORY_GATE_DEFAULTS = {
|
|
32766
|
+
minScore: DEFAULT_MIN_SCORE2,
|
|
32767
|
+
minImportance: DEFAULT_MIN_IMPORTANCE2,
|
|
32768
|
+
relationFloor: MIN_RELATION_STRENGTH2
|
|
32769
|
+
};
|
|
32770
|
+
|
|
32362
32771
|
// src/components/history/entry.tsx
|
|
32363
32772
|
import { Fragment as Fragment24, jsx as jsx70, jsxs as jsxs68 } from "react/jsx-runtime";
|
|
32773
|
+
var MAX_MEMORY_PROOF_ROWS = 4;
|
|
32774
|
+
function formatScoreTerms(terms) {
|
|
32775
|
+
if (terms.length === 0) return "no score breakdown (emitted by an older core build)";
|
|
32776
|
+
return terms.map((term) => {
|
|
32777
|
+
const magnitude = Math.abs(term.value).toFixed(2);
|
|
32778
|
+
return `${term.label} ${term.value < 0 ? "\u2212" : "+"}${magnitude}`;
|
|
32779
|
+
}).join(" \u2502 ");
|
|
32780
|
+
}
|
|
32364
32781
|
function brainStatusStyle(status) {
|
|
32365
32782
|
switch (status) {
|
|
32366
32783
|
case "thinking":
|
|
@@ -32428,7 +32845,7 @@ var Entry = React8.memo(function Entry2({
|
|
|
32428
32845
|
showModelReasoning
|
|
32429
32846
|
}) {
|
|
32430
32847
|
const openTodos = hasOpenTodos(todos);
|
|
32431
|
-
const nextSteps =
|
|
32848
|
+
const nextSteps = useMemo13(() => {
|
|
32432
32849
|
if (entry.kind !== "assistant") return { steps: [], stripped: "" };
|
|
32433
32850
|
return parseNextSteps(entry.text, true);
|
|
32434
32851
|
}, [entry.kind, entry.text]);
|
|
@@ -32547,7 +32964,7 @@ var Entry = React8.memo(function Entry2({
|
|
|
32547
32964
|
}
|
|
32548
32965
|
case "tool": {
|
|
32549
32966
|
const { glyph: glyph2, color } = getToolVisual(entry.name);
|
|
32550
|
-
const { argSummary, outLines, sageLines, visualLines, diff, multiDiffs, sizeChip, mutation } =
|
|
32967
|
+
const { argSummary, outLines, sageLines, visualLines, diff, multiDiffs, sizeChip, mutation } = useMemo13(() => {
|
|
32551
32968
|
const argSummary2 = formatToolArgs(entry.name, entry.input);
|
|
32552
32969
|
const {
|
|
32553
32970
|
cleanOutput: outputForFormatting,
|
|
@@ -32558,7 +32975,8 @@ var Entry = React8.memo(function Entry2({
|
|
|
32558
32975
|
entry.output,
|
|
32559
32976
|
entry.ok,
|
|
32560
32977
|
entry.outputBytes,
|
|
32561
|
-
entry.outputLines
|
|
32978
|
+
entry.outputLines,
|
|
32979
|
+
entry.sageLines
|
|
32562
32980
|
);
|
|
32563
32981
|
const visualLines2 = formatToolVisualOutput(
|
|
32564
32982
|
entry.name,
|
|
@@ -32617,6 +33035,7 @@ var Entry = React8.memo(function Entry2({
|
|
|
32617
33035
|
}, [
|
|
32618
33036
|
entry.name,
|
|
32619
33037
|
entry.output,
|
|
33038
|
+
entry.sageLines,
|
|
32620
33039
|
entry.input,
|
|
32621
33040
|
entry.ok,
|
|
32622
33041
|
entry.outputBytes,
|
|
@@ -32684,7 +33103,14 @@ var Entry = React8.memo(function Entry2({
|
|
|
32684
33103
|
]
|
|
32685
33104
|
}
|
|
32686
33105
|
),
|
|
32687
|
-
/* @__PURE__ */ jsx70(
|
|
33106
|
+
/* @__PURE__ */ jsx70(
|
|
33107
|
+
SageMemoryBlock,
|
|
33108
|
+
{
|
|
33109
|
+
sageLines,
|
|
33110
|
+
toolName: entry.name,
|
|
33111
|
+
stats: entry.sageStats
|
|
33112
|
+
}
|
|
33113
|
+
)
|
|
32688
33114
|
] });
|
|
32689
33115
|
}
|
|
32690
33116
|
const toolContentWidth = Math.max(20, termWidth - 2);
|
|
@@ -32764,14 +33190,16 @@ var Entry = React8.memo(function Entry2({
|
|
|
32764
33190
|
]
|
|
32765
33191
|
}
|
|
32766
33192
|
),
|
|
32767
|
-
/* @__PURE__ */ jsx70(SageMemoryBlock, { sageLines, toolName: entry.name })
|
|
33193
|
+
/* @__PURE__ */ jsx70(SageMemoryBlock, { sageLines, toolName: entry.name, stats: entry.sageStats })
|
|
32768
33194
|
] });
|
|
32769
33195
|
}
|
|
32770
33196
|
case "memory-activation": {
|
|
33197
|
+
if (!entry.error) return null;
|
|
32771
33198
|
const rejected = Object.entries(entry.rejected).filter(([, count]) => count > 0).map(([reason, count]) => `${reason} ${count}`).join(" \xB7 ");
|
|
32772
|
-
const injected = entry.activated.filter((memory) => entry.injectedIds.includes(memory.id));
|
|
32773
|
-
const
|
|
32774
|
-
const
|
|
33199
|
+
const injected = entry.outcome === "error" ? entry.activated : entry.activated.filter((memory) => entry.injectedIds.includes(memory.id));
|
|
33200
|
+
const shown = injected.slice(0, MAX_MEMORY_PROOF_ROWS);
|
|
33201
|
+
const overflow = injected.length - shown.length;
|
|
33202
|
+
const thresholds = entry.thresholds ?? MEMORY_GATE_DEFAULTS;
|
|
32775
33203
|
return /* @__PURE__ */ jsxs68(Box, { flexDirection: "column", borderStyle: "single", borderColor: "magenta", paddingX: 1, children: [
|
|
32776
33204
|
/* @__PURE__ */ jsxs68(Box, { flexDirection: "row", children: [
|
|
32777
33205
|
/* @__PURE__ */ jsx70(Text, { bold: true, color: "magenta", children: "\u{1F9E0} MEMORY INJECTOR " }),
|
|
@@ -32779,17 +33207,23 @@ var Entry = React8.memo(function Entry2({
|
|
|
32779
33207
|
/* @__PURE__ */ jsx70(Text, { dimColor: true, children: ` ${entry.activated.length} activated \u2192 ${entry.injectedIds.length} injected / ${entry.candidates} \xB7 ctx ${Math.round(entry.contextPressure * 100)}% \xB7 +${entry.injectedChars} chars` })
|
|
32780
33208
|
] }),
|
|
32781
33209
|
entry.error ? /* @__PURE__ */ jsx70(Text, { color: "red", children: `error: ${entry.error}` }) : null,
|
|
32782
|
-
|
|
32783
|
-
|
|
32784
|
-
|
|
32785
|
-
|
|
32786
|
-
|
|
32787
|
-
|
|
32788
|
-
|
|
32789
|
-
|
|
32790
|
-
|
|
32791
|
-
|
|
32792
|
-
|
|
33210
|
+
entry.queryPreview ? /* @__PURE__ */ jsx70(Text, { dimColor: true, wrap: "truncate-end", children: `query: ${entry.queryPreview}` }) : null,
|
|
33211
|
+
shown.map((memory) => {
|
|
33212
|
+
const scorePass = memory.score >= thresholds.minScore;
|
|
33213
|
+
const relationPass = memory.relationStrength >= thresholds.relationFloor;
|
|
33214
|
+
const reason = memory.activationReasons[0] ?? "no recorded reason";
|
|
33215
|
+
return /* @__PURE__ */ jsxs68(Box, { flexDirection: "column", children: [
|
|
33216
|
+
/* @__PURE__ */ jsxs68(Text, { wrap: "truncate-end", children: [
|
|
33217
|
+
/* @__PURE__ */ jsx70(Text, { color: "green", children: `${memory.id} ` }),
|
|
33218
|
+
/* @__PURE__ */ jsx70(Text, { color: scorePass ? "green" : "red", children: `${memory.score.toFixed(2)} ${scorePass ? "\u2713" : "\u2717"} ${thresholds.minScore.toFixed(2)}` }),
|
|
33219
|
+
/* @__PURE__ */ jsx70(Text, { dimColor: true, children: " \xB7 relation " }),
|
|
33220
|
+
/* @__PURE__ */ jsx70(Text, { color: relationPass ? "green" : "red", children: `${memory.relationStrength.toFixed(2)} ${relationPass ? "\u2713" : "\u2717"} ${thresholds.relationFloor.toFixed(2)}` }),
|
|
33221
|
+
/* @__PURE__ */ jsx70(Text, { dimColor: true, children: ` \xB7 ${reason}` })
|
|
33222
|
+
] }),
|
|
33223
|
+
/* @__PURE__ */ jsx70(Text, { dimColor: true, wrap: "truncate-end", children: ` ${formatScoreTerms(memory.scoreTerms ?? [])}` })
|
|
33224
|
+
] }, memory.id);
|
|
33225
|
+
}),
|
|
33226
|
+
overflow > 0 ? /* @__PURE__ */ jsx70(Text, { dimColor: true, children: ` +${overflow} more injected` }) : null,
|
|
32793
33227
|
rejected ? /* @__PURE__ */ jsx70(Text, { dimColor: true, children: `filtered: ${rejected}` }) : null
|
|
32794
33228
|
] });
|
|
32795
33229
|
}
|
|
@@ -32968,8 +33402,10 @@ var Entry = React8.memo(function Entry2({
|
|
|
32968
33402
|
});
|
|
32969
33403
|
function SageMemoryBlock({
|
|
32970
33404
|
sageLines,
|
|
32971
|
-
toolName
|
|
33405
|
+
toolName,
|
|
33406
|
+
stats
|
|
32972
33407
|
}) {
|
|
33408
|
+
if (!sageLines || sageLines.length < 2) return null;
|
|
32973
33409
|
const memoryLines = sageLines.slice(1);
|
|
32974
33410
|
if (memoryLines.length === 0) return null;
|
|
32975
33411
|
return /* @__PURE__ */ jsxs68(
|
|
@@ -32984,19 +33420,42 @@ function SageMemoryBlock({
|
|
|
32984
33420
|
children: [
|
|
32985
33421
|
/* @__PURE__ */ jsxs68(Box, { flexDirection: "row", children: [
|
|
32986
33422
|
/* @__PURE__ */ jsx70(Text, { bold: true, color: theme.accent, children: `\u{1F9E0} SAGE MEMORY INJECTED \xB7 ${toolName} ` }),
|
|
32987
|
-
/* @__PURE__ */ jsx70(
|
|
32988
|
-
Text,
|
|
32989
|
-
{
|
|
32990
|
-
dimColor: true,
|
|
32991
|
-
children: `${memoryLines.length} ${memoryLines.length === 1 ? "memory" : "memories"}`
|
|
32992
|
-
}
|
|
32993
|
-
)
|
|
33423
|
+
/* @__PURE__ */ jsx70(Text, { dimColor: true, children: `${memoryLines.length} ${memoryLines.length === 1 ? "memory" : "memories"}${stats ? ` \xB7 ${stats}` : ""}` })
|
|
32994
33424
|
] }),
|
|
32995
|
-
memoryLines.map((line, i) =>
|
|
33425
|
+
memoryLines.map((line, i) => {
|
|
33426
|
+
const parsed = parseSageMemoryLine(line);
|
|
33427
|
+
if (!parsed) {
|
|
33428
|
+
return /* @__PURE__ */ jsx70(Text, { color: theme.accent, dimColor: true, wrap: "truncate-end", children: line }, i);
|
|
33429
|
+
}
|
|
33430
|
+
return /* @__PURE__ */ jsx70(SageMemoryRow, { parsed, index: i }, i);
|
|
33431
|
+
})
|
|
32996
33432
|
]
|
|
32997
33433
|
}
|
|
32998
33434
|
);
|
|
32999
33435
|
}
|
|
33436
|
+
function SageMemoryRow({
|
|
33437
|
+
parsed,
|
|
33438
|
+
index
|
|
33439
|
+
}) {
|
|
33440
|
+
const labelText = parsed.labels.length > 0 ? parsed.labels.map((l) => `[${l}]`).join("") : "[memory]";
|
|
33441
|
+
const tagText = parsed.tags && parsed.tags.length > 0 ? parsed.tags.join(", ") : void 0;
|
|
33442
|
+
return /* @__PURE__ */ jsxs68(Box, { flexDirection: "column", marginTop: index > 0 ? 1 : 0, children: [
|
|
33443
|
+
/* @__PURE__ */ jsx70(Text, { bold: true, color: theme.accent, children: labelText }),
|
|
33444
|
+
/* @__PURE__ */ jsx70(Text, { color: theme.textPrimary, children: parsed.text }),
|
|
33445
|
+
/* @__PURE__ */ jsxs68(Box, { flexDirection: "row", flexWrap: "wrap", children: [
|
|
33446
|
+
/* @__PURE__ */ jsx70(SageKv, { label: "id", value: parsed.id }),
|
|
33447
|
+
parsed.anchor ? /* @__PURE__ */ jsx70(SageKv, { label: "anchor", value: parsed.anchor }) : null,
|
|
33448
|
+
parsed.relation ? /* @__PURE__ */ jsx70(SageKv, { label: "relation", value: parsed.relation }) : null,
|
|
33449
|
+
tagText ? /* @__PURE__ */ jsx70(SageKv, { label: "tags", value: tagText }) : null
|
|
33450
|
+
] })
|
|
33451
|
+
] });
|
|
33452
|
+
}
|
|
33453
|
+
function SageKv({ label, value }) {
|
|
33454
|
+
return /* @__PURE__ */ jsxs68(Box, { flexDirection: "row", marginRight: 2, children: [
|
|
33455
|
+
/* @__PURE__ */ jsx70(Text, { dimColor: true, children: `${label}: ` }),
|
|
33456
|
+
/* @__PURE__ */ jsx70(Text, { color: theme.textSecondary, children: value })
|
|
33457
|
+
] });
|
|
33458
|
+
}
|
|
33000
33459
|
|
|
33001
33460
|
// src/components/history/index.tsx
|
|
33002
33461
|
import { Fragment as Fragment25, jsx as jsx71, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
@@ -33243,7 +33702,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
|
|
|
33243
33702
|
return maxWidth ? Math.min(raw, maxWidth) : raw;
|
|
33244
33703
|
}, [stdout, maxWidth]);
|
|
33245
33704
|
const [viewportWidth, setViewportWidth] = useState40(resolveViewportWidth);
|
|
33246
|
-
const termWidth =
|
|
33705
|
+
const termWidth = useMemo14(
|
|
33247
33706
|
() => Math.max(1, viewportWidth - SCROLLBAR_HIT_WIDTH),
|
|
33248
33707
|
[viewportWidth]
|
|
33249
33708
|
);
|
|
@@ -33258,8 +33717,8 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
|
|
|
33258
33717
|
}, [stdout, resolveViewportWidth]);
|
|
33259
33718
|
const toolTail = toolStream?.text ? tailForDisplay(toolStream.text, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
33260
33719
|
const toolTailHeight = toolTail && toolStream ? toolStreamBoxHeight(toolStream.name) : 0;
|
|
33261
|
-
const groupedEntries =
|
|
33262
|
-
const groupIds =
|
|
33720
|
+
const groupedEntries = useMemo14(() => groupEntries(entries), [entries]);
|
|
33721
|
+
const groupIds = useMemo14(() => groupedEntries.map(renderGroupId), [groupedEntries]);
|
|
33263
33722
|
const groupIdsKey = groupIds.join(",");
|
|
33264
33723
|
const heightCacheRef = useRef37(null);
|
|
33265
33724
|
if (heightCacheRef.current === null) heightCacheRef.current = new EntryHeightCache();
|
|
@@ -33351,7 +33810,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
|
|
|
33351
33810
|
viewportRows: vp,
|
|
33352
33811
|
tailRows: toolTailHeight
|
|
33353
33812
|
};
|
|
33354
|
-
const groupIndexById =
|
|
33813
|
+
const groupIndexById = useMemo14(() => {
|
|
33355
33814
|
const indexes = /* @__PURE__ */ new Map();
|
|
33356
33815
|
groupIds.forEach((id, index) => {
|
|
33357
33816
|
indexes.set(id, index);
|
|
@@ -33383,7 +33842,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
|
|
|
33383
33842
|
setAnchor(normalized && nextId !== void 0 ? { id: nextId, clip: normalized.clip } : null);
|
|
33384
33843
|
setMountBump(0);
|
|
33385
33844
|
}, []);
|
|
33386
|
-
const controller =
|
|
33845
|
+
const controller = useMemo14(
|
|
33387
33846
|
() => ({
|
|
33388
33847
|
scrollBy: (deltaUp) => {
|
|
33389
33848
|
applyAnchor(scrollAnchorBy(geometryRef.current, effectiveAnchorRef.current, deltaUp));
|
|
@@ -34029,22 +34488,9 @@ function AppView({ host, runtime }) {
|
|
|
34029
34488
|
enhanceDelayMs,
|
|
34030
34489
|
layoutStore
|
|
34031
34490
|
} = runtime;
|
|
34032
|
-
const {
|
|
34033
|
-
|
|
34034
|
-
|
|
34035
|
-
enhanceDots
|
|
34036
|
-
} = activity;
|
|
34037
|
-
const {
|
|
34038
|
-
setYoloLive,
|
|
34039
|
-
autonomyLive
|
|
34040
|
-
} = environment;
|
|
34041
|
-
const {
|
|
34042
|
-
inputHint,
|
|
34043
|
-
composerStatus,
|
|
34044
|
-
composerAnimationStyle,
|
|
34045
|
-
inputHeight,
|
|
34046
|
-
hideInput
|
|
34047
|
-
} = viewState;
|
|
34491
|
+
const { nowTick, workingTimeMs, enhanceDots } = activity;
|
|
34492
|
+
const { setYoloLive, autonomyLive } = environment;
|
|
34493
|
+
const { inputHint, composerStatus, composerAnimationStyle, inputHeight, hideInput } = viewState;
|
|
34048
34494
|
return (
|
|
34049
34495
|
/* Hard viewport cap. The managed layout aims for exactly termRows
|
|
34050
34496
|
(history vp + measured bottom region), but the bottom region grows a
|
|
@@ -34230,6 +34676,7 @@ function AppView({ host, runtime }) {
|
|
|
34230
34676
|
breakerAutoKillResetMs: state.settingsPicker.breakerAutoKillResetMs,
|
|
34231
34677
|
showModelReasoning: state.settingsPicker.showModelReasoning,
|
|
34232
34678
|
showAgentSwarmPanel: state.settingsPicker.showAgentSwarmPanel,
|
|
34679
|
+
readSymbols: state.settingsPicker.readSymbols,
|
|
34233
34680
|
filter: state.settingsPicker.filter,
|
|
34234
34681
|
hint: state.settingsPicker.hint
|
|
34235
34682
|
}
|
|
@@ -35827,7 +36274,10 @@ function routeBusyInterruptKey(host, key) {
|
|
|
35827
36274
|
const fleetTag = subagentsTerminated > 0 ? ` \xB7 stopped ${subagentsTerminated} subagent${subagentsTerminated === 1 ? "" : "s"}` : "";
|
|
35828
36275
|
dispatch({
|
|
35829
36276
|
type: "addEntry",
|
|
35830
|
-
entry: {
|
|
36277
|
+
entry: {
|
|
36278
|
+
kind: "warn",
|
|
36279
|
+
text: `\u21AF Interrupted${droppedTag}${fleetTag}. Type your new direction.`
|
|
36280
|
+
}
|
|
35831
36281
|
});
|
|
35832
36282
|
return true;
|
|
35833
36283
|
}
|
|
@@ -35949,7 +36399,8 @@ function routeSettingsOverlayKey(host, input, key, isEnter) {
|
|
|
35949
36399
|
breakerEnabled: config.breakerEnabled ?? false,
|
|
35950
36400
|
breakerAutoKillResetMs: config.breakerAutoKillResetMs ?? 6e4,
|
|
35951
36401
|
showModelReasoning: config.showModelReasoning ?? true,
|
|
35952
|
-
showAgentSwarmPanel: config.showAgentSwarmPanel ?? true
|
|
36402
|
+
showAgentSwarmPanel: config.showAgentSwarmPanel ?? true,
|
|
36403
|
+
readSymbols: config.readSymbols ?? false
|
|
35953
36404
|
});
|
|
35954
36405
|
return true;
|
|
35955
36406
|
}
|