@wrongstack/tui 0.296.2 → 0.296.3
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/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 +1503 -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 || !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,381 @@ 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 { checkCodebaseIndexServerHealth, getIndexState as getIndexState2 } from "@wrongstack/tools";
|
|
29096
|
+
async function collectConnectionsHealth(projectRoot) {
|
|
29097
|
+
const services = await Promise.all([
|
|
29098
|
+
chronicleHealth(projectRoot),
|
|
29099
|
+
codebaseIndexHealth(projectRoot),
|
|
29100
|
+
sageHealth(projectRoot),
|
|
29101
|
+
kanbanHealth(projectRoot),
|
|
29102
|
+
mailboxHealth(projectRoot)
|
|
29103
|
+
]);
|
|
29104
|
+
const required = services.filter((s2) => s2.required);
|
|
29105
|
+
const overall = required.some((s2) => s2.status === "error") ? "error" : required.some((s2) => s2.status !== "healthy") ? "degraded" : "healthy";
|
|
29106
|
+
return { checkedAt: Date.now(), overall, services };
|
|
29107
|
+
}
|
|
29108
|
+
async function chronicleHealth(projectRoot) {
|
|
29109
|
+
const startedAt = Date.now();
|
|
29110
|
+
let access;
|
|
29111
|
+
try {
|
|
29112
|
+
access = createChronicleProjectAccess({ projectRoot });
|
|
29113
|
+
const health2 = await access.call("ping", {}, { timeoutMs: 5e3 });
|
|
29114
|
+
const quarantined = health2.quarantinedFamilies ?? [];
|
|
29115
|
+
return {
|
|
29116
|
+
id: "chronicle",
|
|
29117
|
+
label: "Chronicle telemetry",
|
|
29118
|
+
status: quarantined.length > 0 ? "degraded" : access.mode === "server" ? "healthy" : "degraded",
|
|
29119
|
+
required: true,
|
|
29120
|
+
mode: access.mode,
|
|
29121
|
+
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.",
|
|
29122
|
+
ownerPid: health2.pid,
|
|
29123
|
+
endpoint: health2.endpoint,
|
|
29124
|
+
storage: health2.chronicleDirectory,
|
|
29125
|
+
uptimeMs: health2.uptimeMs,
|
|
29126
|
+
latencyMs: Date.now() - startedAt,
|
|
29127
|
+
clients: health2.clients,
|
|
29128
|
+
activeRequests: health2.activeRequests,
|
|
29129
|
+
queuedWork: health2.journal.pendingEvents,
|
|
29130
|
+
watcher: { active: health2.watcher.active, watchedFiles: health2.watcher.watchedFiles },
|
|
29131
|
+
...quarantined[0] ? { lastError: quarantined[0].reason } : health2.watcher.lastError ? { lastError: health2.watcher.lastError } : {}
|
|
29132
|
+
};
|
|
29133
|
+
} catch (error) {
|
|
29134
|
+
return failureService("chronicle", "Chronicle telemetry", true, access?.mode ?? "unavailable", error, Date.now() - startedAt);
|
|
29135
|
+
} finally {
|
|
29136
|
+
await access?.close();
|
|
29137
|
+
}
|
|
29138
|
+
}
|
|
29139
|
+
async function codebaseIndexHealth(projectRoot) {
|
|
29140
|
+
const startedAt = Date.now();
|
|
29141
|
+
try {
|
|
29142
|
+
const health2 = await checkCodebaseIndexServerHealth(projectRoot, void 0, { timeoutMs: 2e3 });
|
|
29143
|
+
const connection = getIndexState2().server;
|
|
29144
|
+
return {
|
|
29145
|
+
id: "codebase-index",
|
|
29146
|
+
label: "Codebase index",
|
|
29147
|
+
status: health2.status === "unresponsive" ? "error" : health2.status,
|
|
29148
|
+
required: false,
|
|
29149
|
+
mode: "project-server",
|
|
29150
|
+
detail: health2.server?.activity.indexing ? `Indexing ${health2.server.activity.currentFile}/${health2.server.activity.totalFiles}.` : "Shared symbol index is ready for project queries.",
|
|
29151
|
+
ownerPid: connection.pid,
|
|
29152
|
+
endpoint: connection.endpoint,
|
|
29153
|
+
storage: connection.indexDir ?? resolveWstackPaths5({ projectRoot }).projectCodebaseIndex,
|
|
29154
|
+
uptimeMs: health2.server?.uptimeMs,
|
|
29155
|
+
latencyMs: health2.latencyMs ?? Date.now() - startedAt,
|
|
29156
|
+
clients: health2.server?.clients,
|
|
29157
|
+
activeRequests: health2.server?.activeRequests,
|
|
29158
|
+
queuedWork: health2.server?.queuedWrites,
|
|
29159
|
+
watcher: health2.server ? { active: health2.server.watchingExternal, watchedFiles: health2.server.watchingClients } : void 0
|
|
29160
|
+
};
|
|
29161
|
+
} catch (error) {
|
|
29162
|
+
if (isOfflineConnectionError(error)) {
|
|
29163
|
+
return {
|
|
29164
|
+
...failureService("codebase-index", "Codebase index", false, "on-demand project-server", error, Date.now() - startedAt),
|
|
29165
|
+
status: "offline",
|
|
29166
|
+
detail: "Not running for this project; it starts on demand when indexing is used."
|
|
29167
|
+
};
|
|
29168
|
+
}
|
|
29169
|
+
return failureService("codebase-index", "Codebase index", false, "project-server", error, Date.now() - startedAt);
|
|
29170
|
+
}
|
|
29171
|
+
}
|
|
29172
|
+
async function sageHealth(projectRoot) {
|
|
29173
|
+
const startedAt = Date.now();
|
|
29174
|
+
if (!isSageProjectServerAvailable()) {
|
|
29175
|
+
return {
|
|
29176
|
+
id: "sage",
|
|
29177
|
+
label: "SAGE memory",
|
|
29178
|
+
status: "unavailable",
|
|
29179
|
+
required: false,
|
|
29180
|
+
mode: "unavailable",
|
|
29181
|
+
detail: "The packaged SAGE project server is unavailable in this runtime."
|
|
29182
|
+
};
|
|
29183
|
+
}
|
|
29184
|
+
const connection = new SageProjectServerConnection(projectRoot);
|
|
29185
|
+
try {
|
|
29186
|
+
const status = await connection.status();
|
|
29187
|
+
if (!status) {
|
|
29188
|
+
return {
|
|
29189
|
+
id: "sage",
|
|
29190
|
+
label: "SAGE memory",
|
|
29191
|
+
status: "offline",
|
|
29192
|
+
required: false,
|
|
29193
|
+
mode: "on-demand project-server",
|
|
29194
|
+
detail: "Not running for this project; it starts on demand when memory is used.",
|
|
29195
|
+
endpoint: connection.getState().endpoint,
|
|
29196
|
+
latencyMs: Date.now() - startedAt
|
|
29197
|
+
};
|
|
29198
|
+
}
|
|
29199
|
+
const healthStatus = status.health.status === "ready" ? "healthy" : status.health.status === "degraded" ? "degraded" : "error";
|
|
29200
|
+
return {
|
|
29201
|
+
id: "sage",
|
|
29202
|
+
label: "SAGE memory",
|
|
29203
|
+
status: healthStatus,
|
|
29204
|
+
required: false,
|
|
29205
|
+
mode: "project-server",
|
|
29206
|
+
detail: `Persistent project memory backend: ${status.health.backend}.`,
|
|
29207
|
+
ownerPid: status.pid,
|
|
29208
|
+
endpoint: status.endpoint,
|
|
29209
|
+
storage: status.storageRoot,
|
|
29210
|
+
latencyMs: Date.now() - startedAt,
|
|
29211
|
+
clients: status.clients,
|
|
29212
|
+
activeRequests: status.pendingRequests
|
|
29213
|
+
};
|
|
29214
|
+
} catch (error) {
|
|
29215
|
+
return failureService("sage", "SAGE memory", false, "project-server", error, Date.now() - startedAt);
|
|
29216
|
+
} finally {
|
|
29217
|
+
connection.close();
|
|
29218
|
+
}
|
|
29219
|
+
}
|
|
29220
|
+
async function kanbanHealth(projectRoot) {
|
|
29221
|
+
const startedAt = Date.now();
|
|
29222
|
+
if (process.env["WRONGSTACK_KANBAN_SERVER"] === "0") {
|
|
29223
|
+
return {
|
|
29224
|
+
id: "kanban",
|
|
29225
|
+
label: "Kanban IPC",
|
|
29226
|
+
status: "unavailable",
|
|
29227
|
+
required: false,
|
|
29228
|
+
mode: "disabled",
|
|
29229
|
+
detail: "Kanban IPC daemon is disabled via WRONGSTACK_KANBAN_SERVER=0."
|
|
29230
|
+
};
|
|
29231
|
+
}
|
|
29232
|
+
let connection;
|
|
29233
|
+
try {
|
|
29234
|
+
connection = await getKanbanServerConnection(projectRoot);
|
|
29235
|
+
} catch (error) {
|
|
29236
|
+
return failureService("kanban", "Kanban IPC", false, "project-server", error, Date.now() - startedAt);
|
|
29237
|
+
}
|
|
29238
|
+
if (!connection) {
|
|
29239
|
+
return {
|
|
29240
|
+
id: "kanban",
|
|
29241
|
+
label: "Kanban IPC",
|
|
29242
|
+
status: "unavailable",
|
|
29243
|
+
required: false,
|
|
29244
|
+
mode: "disabled",
|
|
29245
|
+
detail: "Kanban IPC daemon is disabled in this runtime."
|
|
29246
|
+
};
|
|
29247
|
+
}
|
|
29248
|
+
try {
|
|
29249
|
+
const status = await connection.request("ping", {}, { timeoutMs: 5e3 });
|
|
29250
|
+
return {
|
|
29251
|
+
id: "kanban",
|
|
29252
|
+
label: "Kanban IPC",
|
|
29253
|
+
status: "healthy",
|
|
29254
|
+
required: true,
|
|
29255
|
+
mode: "project-server",
|
|
29256
|
+
detail: `Single shared project-server owns kanban state (v${status.protocolVersion}).`,
|
|
29257
|
+
ownerPid: status.pid,
|
|
29258
|
+
endpoint: status.endpoint,
|
|
29259
|
+
storage: status.databasePath,
|
|
29260
|
+
latencyMs: Date.now() - startedAt,
|
|
29261
|
+
clients: status.clients,
|
|
29262
|
+
activeRequests: status.pendingRequests,
|
|
29263
|
+
uptimeMs: Date.now() - new Date(status.startedAt).getTime()
|
|
29264
|
+
};
|
|
29265
|
+
} catch (error) {
|
|
29266
|
+
return failureService("kanban", "Kanban IPC", true, "project-server", error, Date.now() - startedAt);
|
|
29267
|
+
}
|
|
29268
|
+
}
|
|
29269
|
+
async function mailboxHealth(projectRoot) {
|
|
29270
|
+
const startedAt = Date.now();
|
|
29271
|
+
if (!isMailboxProjectServerAvailable()) {
|
|
29272
|
+
return {
|
|
29273
|
+
id: "mailbox",
|
|
29274
|
+
label: "Mailbox IPC",
|
|
29275
|
+
status: "unavailable",
|
|
29276
|
+
required: false,
|
|
29277
|
+
mode: "unavailable",
|
|
29278
|
+
detail: "The packaged mailbox project server is unavailable in this runtime."
|
|
29279
|
+
};
|
|
29280
|
+
}
|
|
29281
|
+
const connection = new MailboxProjectServerConnection(
|
|
29282
|
+
resolveWstackPaths5({ projectRoot }).projectDir
|
|
29283
|
+
);
|
|
29284
|
+
try {
|
|
29285
|
+
const status = await connection.probeStatus();
|
|
29286
|
+
if (!status) {
|
|
29287
|
+
return {
|
|
29288
|
+
id: "mailbox",
|
|
29289
|
+
label: "Mailbox IPC",
|
|
29290
|
+
status: "offline",
|
|
29291
|
+
required: false,
|
|
29292
|
+
mode: "on-demand project-server",
|
|
29293
|
+
detail: "Not running for this project; it starts on demand when mailbox is used.",
|
|
29294
|
+
endpoint: connection.getState().endpoint,
|
|
29295
|
+
latencyMs: Date.now() - startedAt
|
|
29296
|
+
};
|
|
29297
|
+
}
|
|
29298
|
+
return {
|
|
29299
|
+
id: "mailbox",
|
|
29300
|
+
label: "Mailbox IPC",
|
|
29301
|
+
status: "healthy",
|
|
29302
|
+
required: true,
|
|
29303
|
+
mode: "project-server",
|
|
29304
|
+
detail: `Single shared project-server owns inter-agent mailbox state (v${status.protocolVersion}).`,
|
|
29305
|
+
ownerPid: status.pid,
|
|
29306
|
+
endpoint: status.endpoint,
|
|
29307
|
+
storage: status.databasePath,
|
|
29308
|
+
latencyMs: Date.now() - startedAt,
|
|
29309
|
+
clients: status.clients,
|
|
29310
|
+
activeRequests: status.pendingRequests,
|
|
29311
|
+
uptimeMs: Date.now() - new Date(status.startedAt).getTime()
|
|
29312
|
+
};
|
|
29313
|
+
} catch (error) {
|
|
29314
|
+
return failureService("mailbox", "Mailbox IPC", true, "project-server", error, Date.now() - startedAt);
|
|
29315
|
+
} finally {
|
|
29316
|
+
connection.close();
|
|
29317
|
+
}
|
|
29318
|
+
}
|
|
29319
|
+
function isOfflineConnectionError(error) {
|
|
29320
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
29321
|
+
return /(?:ENOENT|ECONNREFUSED|not found|not running|unavailable|connect failed)/iu.test(message);
|
|
29322
|
+
}
|
|
29323
|
+
function failureService(id, label, required, mode, error, latencyMs) {
|
|
29324
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
29325
|
+
return {
|
|
29326
|
+
id,
|
|
29327
|
+
label,
|
|
29328
|
+
status: "error",
|
|
29329
|
+
required,
|
|
29330
|
+
mode,
|
|
29331
|
+
detail: message,
|
|
29332
|
+
lastError: message,
|
|
29333
|
+
...latencyMs === void 0 ? {} : { latencyMs }
|
|
29334
|
+
};
|
|
29335
|
+
}
|
|
29336
|
+
|
|
29337
|
+
// src/components/connections-panel.tsx
|
|
29338
|
+
import { jsx as jsx48, jsxs as jsxs47 } from "react/jsx-runtime";
|
|
29339
|
+
var REFRESH_MS = 8e3;
|
|
29340
|
+
var STATUS_GLYPH = {
|
|
29341
|
+
healthy: "\u25CF",
|
|
29342
|
+
degraded: "\u25D0",
|
|
29343
|
+
offline: "\u25CB",
|
|
29344
|
+
unavailable: "\u2298",
|
|
29345
|
+
error: "\u2717"
|
|
29346
|
+
};
|
|
29347
|
+
var STATUS_COLOR2 = {
|
|
29348
|
+
healthy: "green",
|
|
29349
|
+
degraded: "yellow",
|
|
29350
|
+
offline: "gray",
|
|
29351
|
+
unavailable: "gray",
|
|
29352
|
+
error: "red"
|
|
29353
|
+
};
|
|
29354
|
+
var OVERALL_COLOR = {
|
|
29355
|
+
healthy: "green",
|
|
29356
|
+
degraded: "yellow",
|
|
29357
|
+
error: "red"
|
|
29358
|
+
};
|
|
29359
|
+
function formatUptime(ms) {
|
|
29360
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
29361
|
+
const s2 = Math.floor(ms / 1e3);
|
|
29362
|
+
if (s2 < 60) return `${s2}s`;
|
|
29363
|
+
const m = Math.floor(s2 / 60);
|
|
29364
|
+
if (m < 60) return `${m}m`;
|
|
29365
|
+
const h = Math.floor(m / 60);
|
|
29366
|
+
return h < 24 ? `${h}h` : `${Math.floor(h / 24)}d`;
|
|
29367
|
+
}
|
|
29368
|
+
function formatLatency(ms) {
|
|
29369
|
+
if (ms === void 0) return null;
|
|
29370
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
29371
|
+
return `${(ms / 1e3).toFixed(1)}s`;
|
|
29372
|
+
}
|
|
29373
|
+
function ServiceRow({ service }) {
|
|
29374
|
+
const glyph2 = STATUS_GLYPH[service.status];
|
|
29375
|
+
const color = STATUS_COLOR2[service.status];
|
|
29376
|
+
const latency = formatLatency(service.latencyMs);
|
|
29377
|
+
const metaParts = [];
|
|
29378
|
+
if (service.ownerPid !== void 0) metaParts.push(`PID ${service.ownerPid}`);
|
|
29379
|
+
if (service.clients !== void 0) metaParts.push(`${service.clients} client${service.clients === 1 ? "" : "s"}`);
|
|
29380
|
+
if (service.activeRequests !== void 0 && service.activeRequests > 0) {
|
|
29381
|
+
metaParts.push(`${service.activeRequests} active`);
|
|
29382
|
+
}
|
|
29383
|
+
if (service.uptimeMs !== void 0) metaParts.push(`up ${formatUptime(service.uptimeMs)}`);
|
|
29384
|
+
if (latency) metaParts.push(`${latency}`);
|
|
29385
|
+
if (service.queuedWork !== void 0 && service.queuedWork > 0) {
|
|
29386
|
+
metaParts.push(`${service.queuedWork} queued`);
|
|
29387
|
+
}
|
|
29388
|
+
return /* @__PURE__ */ jsxs47(Box, { flexDirection: "column", marginTop: 0, children: [
|
|
29389
|
+
/* @__PURE__ */ jsxs47(Box, { gap: 1, children: [
|
|
29390
|
+
/* @__PURE__ */ jsx48(Text, { color, children: glyph2 }),
|
|
29391
|
+
/* @__PURE__ */ jsx48(Text, { bold: true, children: service.label }),
|
|
29392
|
+
service.required ? /* @__PURE__ */ jsx48(Text, { dimColor: true, children: "required" }) : null,
|
|
29393
|
+
/* @__PURE__ */ jsxs47(Text, { dimColor: true, children: [
|
|
29394
|
+
"\xB7 ",
|
|
29395
|
+
service.mode
|
|
29396
|
+
] })
|
|
29397
|
+
] }),
|
|
29398
|
+
/* @__PURE__ */ jsx48(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx48(Text, { dimColor: true, children: service.detail }) }),
|
|
29399
|
+
metaParts.length > 0 ? /* @__PURE__ */ jsx48(Box, { marginLeft: 2, children: /* @__PURE__ */ jsx48(Text, { dimColor: true, children: metaParts.join(" \xB7 ") }) }) : null
|
|
29400
|
+
] });
|
|
29401
|
+
}
|
|
29402
|
+
function ConnectionsPanel({ projectRoot, onClose }) {
|
|
29403
|
+
const [report, setReport] = useState34(null);
|
|
29404
|
+
const [loading, setLoading] = useState34(true);
|
|
29405
|
+
const [error, setError] = useState34(null);
|
|
29406
|
+
const cancelledRef = useRef33(false);
|
|
29407
|
+
const fetch = useCallback24(async () => {
|
|
29408
|
+
try {
|
|
29409
|
+
const r = await collectConnectionsHealth(projectRoot);
|
|
29410
|
+
if (cancelledRef.current) return;
|
|
29411
|
+
setReport(r);
|
|
29412
|
+
setError(null);
|
|
29413
|
+
} catch (e) {
|
|
29414
|
+
if (cancelledRef.current) return;
|
|
29415
|
+
setError(e instanceof Error ? e.message : String(e));
|
|
29416
|
+
} finally {
|
|
29417
|
+
if (!cancelledRef.current) setLoading(false);
|
|
29418
|
+
}
|
|
29419
|
+
}, [projectRoot]);
|
|
29420
|
+
useEffect61(() => {
|
|
29421
|
+
cancelledRef.current = false;
|
|
29422
|
+
void fetch();
|
|
29423
|
+
const timer = setInterval(() => void fetch(), REFRESH_MS);
|
|
29424
|
+
return () => {
|
|
29425
|
+
cancelledRef.current = true;
|
|
29426
|
+
clearInterval(timer);
|
|
29427
|
+
};
|
|
29428
|
+
}, [fetch]);
|
|
29429
|
+
useInput((_input, key) => {
|
|
29430
|
+
if (key.escape || _input === "q") onClose();
|
|
29431
|
+
if (_input === "r") void fetch();
|
|
29432
|
+
});
|
|
29433
|
+
const overallLabel = report ? report.overall === "healthy" ? "All required services healthy" : report.overall === "degraded" ? "Some services degraded" : "Service errors detected" : "Checking\u2026";
|
|
29434
|
+
return /* @__PURE__ */ jsxs47(Box, { flexDirection: "column", borderStyle: "round", borderColor: report ? OVERALL_COLOR[report.overall] : "gray", paddingX: 1, marginY: 0, flexShrink: 0, children: [
|
|
29435
|
+
/* @__PURE__ */ jsxs47(Box, { justifyContent: "space-between", children: [
|
|
29436
|
+
/* @__PURE__ */ jsxs47(Box, { gap: 1, children: [
|
|
29437
|
+
/* @__PURE__ */ jsx48(Text, { bold: true, children: "Service Connections" }),
|
|
29438
|
+
report ? /* @__PURE__ */ jsxs47(Text, { color: OVERALL_COLOR[report.overall], children: [
|
|
29439
|
+
"\u25CF ",
|
|
29440
|
+
overallLabel
|
|
29441
|
+
] }) : null
|
|
29442
|
+
] }),
|
|
29443
|
+
/* @__PURE__ */ jsx48(Text, { dimColor: true, children: "Esc/q close \xB7 r refresh" })
|
|
29444
|
+
] }),
|
|
29445
|
+
loading && !report ? /* @__PURE__ */ jsx48(Box, { paddingY: 1, children: /* @__PURE__ */ jsx48(Text, { dimColor: true, children: "Checking service health\u2026" }) }) : null,
|
|
29446
|
+
error ? /* @__PURE__ */ jsx48(Box, { paddingY: 1, children: /* @__PURE__ */ jsxs47(Text, { color: "red", children: [
|
|
29447
|
+
"Error: ",
|
|
29448
|
+
error
|
|
29449
|
+
] }) }) : null,
|
|
29450
|
+
report ? /* @__PURE__ */ jsx48(Box, { flexDirection: "column", marginTop: 0, children: report.services.map((s2) => /* @__PURE__ */ jsx48(ServiceRow, { service: s2 }, s2.id)) }) : null,
|
|
29451
|
+
report ? /* @__PURE__ */ jsx48(Box, { marginTop: 0, children: /* @__PURE__ */ jsxs47(Text, { dimColor: true, children: [
|
|
29452
|
+
"Last checked ",
|
|
29453
|
+
new Date(report.checkedAt).toLocaleTimeString()
|
|
29454
|
+
] }) }) : null
|
|
29455
|
+
] });
|
|
29456
|
+
}
|
|
29457
|
+
|
|
29151
29458
|
// src/components/continue-confirm-panel.tsx
|
|
29152
29459
|
import React7 from "react";
|
|
29153
29460
|
import { jsx as jsx49, jsxs as jsxs48 } from "react/jsx-runtime";
|
|
@@ -29858,101 +30165,23 @@ function ExitConfirmPanel({
|
|
|
29858
30165
|
] });
|
|
29859
30166
|
}
|
|
29860
30167
|
|
|
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
30168
|
// src/components/file-picker.tsx
|
|
29940
|
-
import { jsx as
|
|
30169
|
+
import { jsx as jsx55, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
29941
30170
|
function FilePicker({ query, matches, selected }) {
|
|
29942
30171
|
if (matches.length === 0) {
|
|
29943
|
-
return /* @__PURE__ */
|
|
30172
|
+
return /* @__PURE__ */ jsx55(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: /* @__PURE__ */ jsxs54(Text, { dimColor: true, children: [
|
|
29944
30173
|
"@",
|
|
29945
30174
|
query,
|
|
29946
30175
|
" \u2014 no matches"
|
|
29947
30176
|
] }) });
|
|
29948
30177
|
}
|
|
29949
|
-
return /* @__PURE__ */
|
|
29950
|
-
/* @__PURE__ */
|
|
30178
|
+
return /* @__PURE__ */ jsxs54(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
30179
|
+
/* @__PURE__ */ jsxs54(Text, { dimColor: true, children: [
|
|
29951
30180
|
"@",
|
|
29952
30181
|
query || "\u2026",
|
|
29953
30182
|
" \u2014 \u2191/\u2193 select, Enter attach, Esc cancel"
|
|
29954
30183
|
] }),
|
|
29955
|
-
matches.map((m, i) => /* @__PURE__ */
|
|
30184
|
+
matches.map((m, i) => /* @__PURE__ */ jsxs54(Text, { inverse: i === selected, ...i === selected ? { color: "cyan" } : {}, children: [
|
|
29956
30185
|
i === selected ? "\u203A " : " ",
|
|
29957
30186
|
highlight(m, query)
|
|
29958
30187
|
] }, m))
|
|
@@ -29963,7 +30192,7 @@ function highlight(path11, _query) {
|
|
|
29963
30192
|
}
|
|
29964
30193
|
|
|
29965
30194
|
// src/components/help-panel.tsx
|
|
29966
|
-
import { Fragment as Fragment18, jsx as
|
|
30195
|
+
import { Fragment as Fragment18, jsx as jsx56, jsxs as jsxs55 } from "react/jsx-runtime";
|
|
29967
30196
|
var CATEGORY_ORDER2 = ["Run", "Session", "Inspect", "Agent", "Config", "App"];
|
|
29968
30197
|
var CHROME_ROWS3 = 7;
|
|
29969
30198
|
function normalizeQuery(raw) {
|
|
@@ -30036,29 +30265,29 @@ function HelpPanel({
|
|
|
30036
30265
|
const hiddenAbove = start;
|
|
30037
30266
|
const hiddenBelow = rows.length - end;
|
|
30038
30267
|
const hasFilter = query.length > 0;
|
|
30039
|
-
return /* @__PURE__ */
|
|
30040
|
-
/* @__PURE__ */
|
|
30041
|
-
/* @__PURE__ */
|
|
30042
|
-
/* @__PURE__ */
|
|
30268
|
+
return /* @__PURE__ */ jsxs55(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
30269
|
+
/* @__PURE__ */ jsx56(Text, { bold: true, color: "cyan", children: "\u2501\u2501 Help / Command Palette \u2501\u2501" }),
|
|
30270
|
+
/* @__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" }),
|
|
30271
|
+
/* @__PURE__ */ jsx56(Box, { marginTop: 1, flexDirection: "column", children: filtered.length === 0 ? /* @__PURE__ */ jsxs55(Text, { dimColor: true, children: [
|
|
30043
30272
|
'No commands match "',
|
|
30044
30273
|
filter,
|
|
30045
30274
|
'".'
|
|
30046
|
-
] }) : /* @__PURE__ */
|
|
30047
|
-
hiddenAbove > 0 && !hasFilter ? /* @__PURE__ */
|
|
30048
|
-
contextHeader && !hasFilter ? /* @__PURE__ */
|
|
30275
|
+
] }) : /* @__PURE__ */ jsxs55(Fragment18, { children: [
|
|
30276
|
+
hiddenAbove > 0 && !hasFilter ? /* @__PURE__ */ jsx56(Text, { dimColor: true, children: ` \u2191 ${hiddenAbove} more` }) : null,
|
|
30277
|
+
contextHeader && !hasFilter ? /* @__PURE__ */ jsxs55(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
30049
30278
|
" ",
|
|
30050
30279
|
contextHeader
|
|
30051
30280
|
] }) : null,
|
|
30052
30281
|
visible.map((row) => {
|
|
30053
30282
|
if (row.type === "header") {
|
|
30054
|
-
return /* @__PURE__ */
|
|
30283
|
+
return /* @__PURE__ */ jsxs55(Text, { bold: true, color: "yellow", dimColor: true, children: [
|
|
30055
30284
|
" ",
|
|
30056
30285
|
row.category
|
|
30057
30286
|
] }, `cat-${row.category}`);
|
|
30058
30287
|
}
|
|
30059
30288
|
const { entry, index } = row;
|
|
30060
30289
|
const isSelected = index === focus;
|
|
30061
|
-
return /* @__PURE__ */
|
|
30290
|
+
return /* @__PURE__ */ jsxs55(
|
|
30062
30291
|
Text,
|
|
30063
30292
|
{
|
|
30064
30293
|
inverse: isSelected,
|
|
@@ -30066,20 +30295,20 @@ function HelpPanel({
|
|
|
30066
30295
|
wrap: "truncate-end",
|
|
30067
30296
|
children: [
|
|
30068
30297
|
isSelected ? "\u203A " : " ",
|
|
30069
|
-
/* @__PURE__ */
|
|
30298
|
+
/* @__PURE__ */ jsxs55(Text, { bold: true, children: [
|
|
30070
30299
|
"/",
|
|
30071
30300
|
entry.name
|
|
30072
30301
|
] }),
|
|
30073
|
-
entry.aliases && entry.aliases.length > 0 ? /* @__PURE__ */
|
|
30302
|
+
entry.aliases && entry.aliases.length > 0 ? /* @__PURE__ */ jsxs55(Text, { dimColor: true, children: [
|
|
30074
30303
|
" (",
|
|
30075
30304
|
entry.aliases.map((a) => `/${a}`).join(", "),
|
|
30076
30305
|
")"
|
|
30077
30306
|
] }) : null,
|
|
30078
|
-
/* @__PURE__ */
|
|
30307
|
+
/* @__PURE__ */ jsxs55(Text, { dimColor: true, children: [
|
|
30079
30308
|
" \u2014 ",
|
|
30080
30309
|
entry.description
|
|
30081
30310
|
] }),
|
|
30082
|
-
entry.argsHint ? /* @__PURE__ */
|
|
30311
|
+
entry.argsHint ? /* @__PURE__ */ jsxs55(Text, { dimColor: true, children: [
|
|
30083
30312
|
" ",
|
|
30084
30313
|
entry.argsHint
|
|
30085
30314
|
] }) : null
|
|
@@ -30088,30 +30317,30 @@ function HelpPanel({
|
|
|
30088
30317
|
entry.name
|
|
30089
30318
|
);
|
|
30090
30319
|
}),
|
|
30091
|
-
hiddenBelow > 0 && !hasFilter ? /* @__PURE__ */
|
|
30320
|
+
hiddenBelow > 0 && !hasFilter ? /* @__PURE__ */ jsx56(Text, { dimColor: true, children: ` \u2193 ${hiddenBelow} more` }) : null
|
|
30092
30321
|
] }) }),
|
|
30093
|
-
hint ? /* @__PURE__ */
|
|
30322
|
+
hint ? /* @__PURE__ */ jsx56(Box, { marginTop: 1, children: /* @__PURE__ */ jsx56(Text, { dimColor: true, children: hint }) }) : null
|
|
30094
30323
|
] });
|
|
30095
30324
|
}
|
|
30096
30325
|
|
|
30097
30326
|
// src/components/mcp-picker.tsx
|
|
30098
|
-
import { Fragment as Fragment19, jsx as
|
|
30327
|
+
import { Fragment as Fragment19, jsx as jsx57, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
30099
30328
|
var CHROME_ROWS4 = 17;
|
|
30100
30329
|
function statusBadge(status, enabled) {
|
|
30101
|
-
if (!enabled) return /* @__PURE__ */
|
|
30330
|
+
if (!enabled) return /* @__PURE__ */ jsx57(Text, { dimColor: true, children: "\u25CB disabled" });
|
|
30102
30331
|
switch (status) {
|
|
30103
30332
|
case "connected":
|
|
30104
|
-
return /* @__PURE__ */
|
|
30333
|
+
return /* @__PURE__ */ jsx57(Text, { color: "green", children: "\u25CF connected" });
|
|
30105
30334
|
case "connecting":
|
|
30106
|
-
return /* @__PURE__ */
|
|
30335
|
+
return /* @__PURE__ */ jsx57(Text, { color: "cyan", children: "\u25D0 connecting" });
|
|
30107
30336
|
case "reconnecting":
|
|
30108
|
-
return /* @__PURE__ */
|
|
30337
|
+
return /* @__PURE__ */ jsx57(Text, { color: "cyan", children: "\u25D1 reconnecting" });
|
|
30109
30338
|
case "disconnected":
|
|
30110
|
-
return /* @__PURE__ */
|
|
30339
|
+
return /* @__PURE__ */ jsx57(Text, { dimColor: true, children: "\u25CB disconnected" });
|
|
30111
30340
|
case "failed":
|
|
30112
|
-
return /* @__PURE__ */
|
|
30341
|
+
return /* @__PURE__ */ jsx57(Text, { color: "red", children: "\u2717 failed" });
|
|
30113
30342
|
default:
|
|
30114
|
-
return /* @__PURE__ */
|
|
30343
|
+
return /* @__PURE__ */ jsx57(Text, { dimColor: true, children: status });
|
|
30115
30344
|
}
|
|
30116
30345
|
}
|
|
30117
30346
|
function McpPicker({
|
|
@@ -30128,36 +30357,36 @@ function McpPicker({
|
|
|
30128
30357
|
const windowEnd = Math.min(windowStart + maxVisible, total);
|
|
30129
30358
|
const above = windowStart;
|
|
30130
30359
|
const below = total - windowEnd;
|
|
30131
|
-
return /* @__PURE__ */
|
|
30132
|
-
/* @__PURE__ */
|
|
30133
|
-
/* @__PURE__ */
|
|
30134
|
-
/* @__PURE__ */
|
|
30135
|
-
above > 0 ? /* @__PURE__ */
|
|
30360
|
+
return /* @__PURE__ */ jsxs56(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
30361
|
+
/* @__PURE__ */ jsx57(Text, { bold: true, color: "cyan", children: "MCP Servers" }),
|
|
30362
|
+
/* @__PURE__ */ jsx57(Text, { dimColor: true, children: "\u2191/\u2193 select \xB7 Enter/\u2190/\u2192 toggle enable \xB7 r restart \xB7 Esc close" }),
|
|
30363
|
+
/* @__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: [
|
|
30364
|
+
above > 0 ? /* @__PURE__ */ jsx57(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
30136
30365
|
items.slice(windowStart, windowEnd).map((item, i) => {
|
|
30137
30366
|
const index = windowStart + i;
|
|
30138
30367
|
const focused = index === selected;
|
|
30139
30368
|
const marker = focused ? "\u203A" : " ";
|
|
30140
|
-
return /* @__PURE__ */
|
|
30369
|
+
return /* @__PURE__ */ jsxs56(Text, { color: focused ? "cyan" : void 0, wrap: "truncate-end", children: [
|
|
30141
30370
|
marker,
|
|
30142
30371
|
" ",
|
|
30143
30372
|
statusBadge(item.status, item.enabled),
|
|
30144
30373
|
" ",
|
|
30145
|
-
/* @__PURE__ */
|
|
30146
|
-
/* @__PURE__ */
|
|
30374
|
+
/* @__PURE__ */ jsx57(Text, { bold: true, children: item.name.padEnd(18) }),
|
|
30375
|
+
/* @__PURE__ */ jsxs56(Text, { dimColor: true, children: [
|
|
30147
30376
|
item.transport.padEnd(14),
|
|
30148
30377
|
item.toolCount > 0 ? `${item.toolCount} tools` : "",
|
|
30149
30378
|
item.lazy ? " lazy" : ""
|
|
30150
30379
|
] })
|
|
30151
30380
|
] }, item.name);
|
|
30152
30381
|
}),
|
|
30153
|
-
below > 0 ? /* @__PURE__ */
|
|
30382
|
+
below > 0 ? /* @__PURE__ */ jsx57(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
30154
30383
|
] }) }),
|
|
30155
|
-
hint ? /* @__PURE__ */
|
|
30384
|
+
hint ? /* @__PURE__ */ jsx57(Box, { marginTop: 1, children: /* @__PURE__ */ jsx57(Text, { dimColor: true, children: hint }) }) : null
|
|
30156
30385
|
] });
|
|
30157
30386
|
}
|
|
30158
30387
|
|
|
30159
30388
|
// src/components/model-picker.tsx
|
|
30160
|
-
import { jsx as
|
|
30389
|
+
import { jsx as jsx58, jsxs as jsxs57 } from "react/jsx-runtime";
|
|
30161
30390
|
var MAX_VISIBLE2 = 10;
|
|
30162
30391
|
function getVisibleWindow2(selected, total) {
|
|
30163
30392
|
const half = Math.floor(MAX_VISIBLE2 / 2);
|
|
@@ -30185,27 +30414,27 @@ function ModelPicker({
|
|
|
30185
30414
|
}) {
|
|
30186
30415
|
const title = titleLabel ?? "Switch model";
|
|
30187
30416
|
if (step === "provider") {
|
|
30188
|
-
return /* @__PURE__ */
|
|
30189
|
-
/* @__PURE__ */
|
|
30190
|
-
/* @__PURE__ */
|
|
30191
|
-
providerOptions.length === 0 ? /* @__PURE__ */
|
|
30417
|
+
return /* @__PURE__ */ jsxs57(Box, { flexDirection: "column", borderStyle: "round", borderColor: UI_COLORS.border, paddingX: 1, children: [
|
|
30418
|
+
/* @__PURE__ */ jsx58(Text, { color: UI_COLORS.title, bold: true, children: `\u2501\u2501 ${title} \u2014 Step 1/2: Pick provider \u2501\u2501` }),
|
|
30419
|
+
/* @__PURE__ */ jsx58(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc cancel \xB7 Ctrl+C exit" }),
|
|
30420
|
+
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
30421
|
const isSelected = i === selected;
|
|
30193
30422
|
const famColor = colorForFamily(p.family);
|
|
30194
|
-
return /* @__PURE__ */
|
|
30423
|
+
return /* @__PURE__ */ jsxs57(
|
|
30195
30424
|
Text,
|
|
30196
30425
|
{
|
|
30197
30426
|
inverse: isSelected,
|
|
30198
30427
|
...isSelected ? { color: UI_COLORS.focused } : {},
|
|
30199
30428
|
children: [
|
|
30200
30429
|
isSelected ? "\u203A " : " ",
|
|
30201
|
-
/* @__PURE__ */
|
|
30202
|
-
/* @__PURE__ */
|
|
30430
|
+
/* @__PURE__ */ jsx58(Text, { bold: true, color: isSelected ? void 0 : famColor, children: p.id.padEnd(28) }),
|
|
30431
|
+
/* @__PURE__ */ jsxs57(Text, { color: isSelected ? void 0 : famColor, dimColor: !isSelected, children: [
|
|
30203
30432
|
" ",
|
|
30204
30433
|
"[",
|
|
30205
30434
|
p.family,
|
|
30206
30435
|
"]"
|
|
30207
30436
|
] }),
|
|
30208
|
-
/* @__PURE__ */
|
|
30437
|
+
/* @__PURE__ */ jsxs57(Text, { dimColor: true, children: [
|
|
30209
30438
|
" ",
|
|
30210
30439
|
p.models.length,
|
|
30211
30440
|
" model",
|
|
@@ -30216,15 +30445,15 @@ function ModelPicker({
|
|
|
30216
30445
|
p.id
|
|
30217
30446
|
);
|
|
30218
30447
|
}) }),
|
|
30219
|
-
hint ? /* @__PURE__ */
|
|
30448
|
+
hint ? /* @__PURE__ */ jsx58(Text, { color: UI_COLORS.hint, children: hint }) : null
|
|
30220
30449
|
] });
|
|
30221
30450
|
}
|
|
30222
30451
|
const total = filteredOptions.length;
|
|
30223
30452
|
const { start, end } = getVisibleWindow2(selected, total);
|
|
30224
30453
|
const visibleItems = filteredOptions.slice(start, end);
|
|
30225
30454
|
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__ */
|
|
30455
|
+
return /* @__PURE__ */ jsxs57(Box, { flexDirection: "column", borderStyle: "round", borderColor: UI_COLORS.border, paddingX: 1, children: [
|
|
30456
|
+
/* @__PURE__ */ jsxs57(Text, { color: UI_COLORS.title, bold: true, children: [
|
|
30228
30457
|
`\u2501\u2501 ${title} \u2014 Step 2/2: Pick model `,
|
|
30229
30458
|
"(",
|
|
30230
30459
|
pickedProviderId,
|
|
@@ -30232,9 +30461,9 @@ function ModelPicker({
|
|
|
30232
30461
|
")",
|
|
30233
30462
|
" \u2501\u2501"
|
|
30234
30463
|
] }),
|
|
30235
|
-
/* @__PURE__ */
|
|
30236
|
-
total === 0 ? /* @__PURE__ */
|
|
30237
|
-
start > 0 && /* @__PURE__ */
|
|
30464
|
+
/* @__PURE__ */ jsx58(Text, { dimColor: true, children: "\u2191/\u2193 navigate \xB7 Enter select \xB7 Esc back \xB7 Ctrl+C exit \xB7 type to filter" }),
|
|
30465
|
+
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: [
|
|
30466
|
+
start > 0 && /* @__PURE__ */ jsxs57(Text, { dimColor: true, children: [
|
|
30238
30467
|
"\u25B2 ",
|
|
30239
30468
|
start,
|
|
30240
30469
|
" above"
|
|
@@ -30242,7 +30471,7 @@ function ModelPicker({
|
|
|
30242
30471
|
visibleItems.map((id, vi) => {
|
|
30243
30472
|
const absoluteIndex = start + vi;
|
|
30244
30473
|
const isSelected = absoluteIndex === selected;
|
|
30245
|
-
return /* @__PURE__ */
|
|
30474
|
+
return /* @__PURE__ */ jsxs57(
|
|
30246
30475
|
Text,
|
|
30247
30476
|
{
|
|
30248
30477
|
inverse: isSelected,
|
|
@@ -30256,20 +30485,20 @@ function ModelPicker({
|
|
|
30256
30485
|
);
|
|
30257
30486
|
}),
|
|
30258
30487
|
Array.from({ length: MAX_VISIBLE2 - visibleItems.length }).map(
|
|
30259
|
-
(_, i) => /* @__PURE__ */
|
|
30488
|
+
(_, i) => /* @__PURE__ */ jsx58(Text, { children: " " }, `pad-${i}`)
|
|
30260
30489
|
),
|
|
30261
|
-
end < total && /* @__PURE__ */
|
|
30490
|
+
end < total && /* @__PURE__ */ jsxs57(Text, { dimColor: true, children: [
|
|
30262
30491
|
"\u25BC ",
|
|
30263
30492
|
total - end,
|
|
30264
30493
|
" below"
|
|
30265
30494
|
] })
|
|
30266
30495
|
] }),
|
|
30267
|
-
hint ? /* @__PURE__ */
|
|
30496
|
+
hint ? /* @__PURE__ */ jsx58(Text, { color: UI_COLORS.hint, children: hint }) : null
|
|
30268
30497
|
] });
|
|
30269
30498
|
}
|
|
30270
30499
|
|
|
30271
30500
|
// src/components/plugin-picker.tsx
|
|
30272
|
-
import { Fragment as Fragment20, jsx as
|
|
30501
|
+
import { Fragment as Fragment20, jsx as jsx59, jsxs as jsxs58 } from "react/jsx-runtime";
|
|
30273
30502
|
var CHROME_ROWS5 = 17;
|
|
30274
30503
|
var MAX_PICKER_ITEMS = 15;
|
|
30275
30504
|
function PluginPicker({
|
|
@@ -30287,15 +30516,15 @@ function PluginPicker({
|
|
|
30287
30516
|
const above = windowStart;
|
|
30288
30517
|
const below = total - windowEnd;
|
|
30289
30518
|
const hasLockedRows = items.some((item) => item.lockable === false);
|
|
30290
|
-
return /* @__PURE__ */
|
|
30291
|
-
/* @__PURE__ */
|
|
30292
|
-
/* @__PURE__ */
|
|
30519
|
+
return /* @__PURE__ */ jsxs58(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 1, children: [
|
|
30520
|
+
/* @__PURE__ */ jsx59(Text, { bold: true, color: "cyan", children: "Plugin menu" }),
|
|
30521
|
+
/* @__PURE__ */ jsxs58(Text, { dimColor: true, children: [
|
|
30293
30522
|
"\u2191/\u2193 select \xB7 Enter/\u2190/\u2192 toggle",
|
|
30294
30523
|
hasLockedRows ? " \xB7 \u{1F512} = locked" : "",
|
|
30295
30524
|
" \xB7 Esc close"
|
|
30296
30525
|
] }),
|
|
30297
|
-
/* @__PURE__ */
|
|
30298
|
-
above > 0 ? /* @__PURE__ */
|
|
30526
|
+
/* @__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: [
|
|
30527
|
+
above > 0 ? /* @__PURE__ */ jsx59(Text, { dimColor: true, children: ` \u2191 ${above} more` }) : null,
|
|
30299
30528
|
items.slice(windowStart, windowEnd).map((item, i) => {
|
|
30300
30529
|
const index = windowStart + i;
|
|
30301
30530
|
const focused = index === selected;
|
|
@@ -30304,16 +30533,16 @@ function PluginPicker({
|
|
|
30304
30533
|
const state = item.enabled ? "\u25CF on " : "\u25CB off";
|
|
30305
30534
|
const color = item.enabled ? "green" : "gray";
|
|
30306
30535
|
const lock = isLocked ? "\u{1F512}" : " ";
|
|
30307
|
-
return /* @__PURE__ */
|
|
30536
|
+
return /* @__PURE__ */ jsxs58(Text, { color: focused ? "cyan" : void 0, wrap: "truncate-end", children: [
|
|
30308
30537
|
marker,
|
|
30309
30538
|
" ",
|
|
30310
|
-
/* @__PURE__ */
|
|
30539
|
+
/* @__PURE__ */ jsx59(Text, { color, children: state }),
|
|
30311
30540
|
" ",
|
|
30312
30541
|
item.name.padEnd(18),
|
|
30313
30542
|
" ",
|
|
30314
|
-
/* @__PURE__ */
|
|
30543
|
+
/* @__PURE__ */ jsx59(Text, { color: isLocked ? "yellow" : void 0, children: lock }),
|
|
30315
30544
|
" ",
|
|
30316
|
-
/* @__PURE__ */
|
|
30545
|
+
/* @__PURE__ */ jsxs58(Text, { dimColor: true, children: [
|
|
30317
30546
|
"risk=",
|
|
30318
30547
|
item.risk.padEnd(6)
|
|
30319
30548
|
] }),
|
|
@@ -30321,14 +30550,14 @@ function PluginPicker({
|
|
|
30321
30550
|
item.summary
|
|
30322
30551
|
] }, item.name);
|
|
30323
30552
|
}),
|
|
30324
|
-
below > 0 ? /* @__PURE__ */
|
|
30553
|
+
below > 0 ? /* @__PURE__ */ jsx59(Text, { dimColor: true, children: ` \u2193 ${below} more` }) : null
|
|
30325
30554
|
] }) }),
|
|
30326
|
-
hint ? /* @__PURE__ */
|
|
30555
|
+
hint ? /* @__PURE__ */ jsx59(Box, { marginTop: 1, children: /* @__PURE__ */ jsx59(Text, { dimColor: true, children: hint }) }) : null
|
|
30327
30556
|
] });
|
|
30328
30557
|
}
|
|
30329
30558
|
|
|
30330
30559
|
// src/components/project-picker.tsx
|
|
30331
|
-
import { jsx as
|
|
30560
|
+
import { jsx as jsx60, jsxs as jsxs59 } from "react/jsx-runtime";
|
|
30332
30561
|
function actionIcon(key) {
|
|
30333
30562
|
if (key === "new-session") return glyphs.sessions;
|
|
30334
30563
|
if (key === "prev-sessions") return glyphs.clock;
|
|
@@ -30348,71 +30577,71 @@ function ProjectPicker({
|
|
|
30348
30577
|
const window = panelWindow(items.length, selected, limit);
|
|
30349
30578
|
const visible = items.slice(window.start, window.end);
|
|
30350
30579
|
const labelWidth = Math.max(12, size.contentWidth - 16);
|
|
30351
|
-
return /* @__PURE__ */
|
|
30580
|
+
return /* @__PURE__ */ jsxs59(
|
|
30352
30581
|
MonitorShell,
|
|
30353
30582
|
{
|
|
30354
30583
|
accent: theme.accent,
|
|
30355
30584
|
icon: glyphs.folder,
|
|
30356
30585
|
title: "PROJECTS",
|
|
30357
30586
|
kicker: size.columns >= 58 ? "workspace switcher" : void 0,
|
|
30358
|
-
right: /* @__PURE__ */
|
|
30587
|
+
right: /* @__PURE__ */ jsxs59(Text, { color: theme.textMuted, children: [
|
|
30359
30588
|
projectCount,
|
|
30360
30589
|
" project",
|
|
30361
30590
|
projectCount === 1 ? "" : "s"
|
|
30362
30591
|
] }),
|
|
30363
|
-
footer: /* @__PURE__ */
|
|
30364
|
-
/* @__PURE__ */
|
|
30365
|
-
/* @__PURE__ */
|
|
30366
|
-
size.columns >= 64 ? /* @__PURE__ */
|
|
30592
|
+
footer: /* @__PURE__ */ jsxs59(Box, { gap: 2, children: [
|
|
30593
|
+
/* @__PURE__ */ jsx60(KeyCap, { keyName: "\u2191\u2193", label: "navigate" }),
|
|
30594
|
+
/* @__PURE__ */ jsx60(KeyCap, { keyName: "Enter", label: "open", color: theme.success }),
|
|
30595
|
+
size.columns >= 64 ? /* @__PURE__ */ jsx60(KeyCap, { keyName: "Esc", label: "close", color: theme.error }) : null
|
|
30367
30596
|
] }),
|
|
30368
30597
|
children: [
|
|
30369
|
-
/* @__PURE__ */
|
|
30370
|
-
/* @__PURE__ */
|
|
30598
|
+
/* @__PURE__ */ jsxs59(Box, { height: 1, marginTop: 1, children: [
|
|
30599
|
+
/* @__PURE__ */ jsxs59(Text, { color: filter ? theme.warn : theme.textMuted, children: [
|
|
30371
30600
|
glyphs.prompt,
|
|
30372
30601
|
" "
|
|
30373
30602
|
] }),
|
|
30374
|
-
/* @__PURE__ */
|
|
30375
|
-
filter ? /* @__PURE__ */
|
|
30376
|
-
/* @__PURE__ */
|
|
30377
|
-
/* @__PURE__ */
|
|
30603
|
+
/* @__PURE__ */ jsx60(Text, { color: filter ? theme.textPrimary : theme.textMuted, children: filter || "Type to filter projects and actions" }),
|
|
30604
|
+
filter ? /* @__PURE__ */ jsx60(Text, { color: theme.accent, children: "\u2588" }) : null,
|
|
30605
|
+
/* @__PURE__ */ jsx60(Box, { flexGrow: 1 }),
|
|
30606
|
+
/* @__PURE__ */ jsxs59(Text, { color: theme.textMuted, children: [
|
|
30378
30607
|
selectableCount,
|
|
30379
30608
|
" choices"
|
|
30380
30609
|
] })
|
|
30381
30610
|
] }),
|
|
30382
|
-
window.above > 0 ? /* @__PURE__ */
|
|
30611
|
+
window.above > 0 ? /* @__PURE__ */ jsxs59(Text, { color: theme.textMuted, children: [
|
|
30383
30612
|
" \u2191 ",
|
|
30384
30613
|
window.above,
|
|
30385
30614
|
" hidden"
|
|
30386
30615
|
] }) : null,
|
|
30387
|
-
visible.length === 0 ? /* @__PURE__ */
|
|
30616
|
+
visible.length === 0 ? /* @__PURE__ */ jsx60(
|
|
30388
30617
|
EmptyPanelState,
|
|
30389
30618
|
{
|
|
30390
30619
|
icon: glyphs.folder,
|
|
30391
30620
|
title: "No matching projects",
|
|
30392
30621
|
detail: "Clear the filter or add a project with /project add."
|
|
30393
30622
|
}
|
|
30394
|
-
) : /* @__PURE__ */
|
|
30623
|
+
) : /* @__PURE__ */ jsx60(Box, { flexDirection: "column", marginTop: 1, children: visible.map((item, offset) => {
|
|
30395
30624
|
const index = window.start + offset;
|
|
30396
30625
|
const isSelected = index === selected;
|
|
30397
30626
|
if (item.key === "__divider__") {
|
|
30398
|
-
return /* @__PURE__ */
|
|
30627
|
+
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
30628
|
}
|
|
30400
30629
|
const icon = item.kind === "project" ? glyphs.folder : actionIcon(item.key);
|
|
30401
30630
|
const accent = item.kind === "project" ? theme.accent : theme.warn;
|
|
30402
|
-
return /* @__PURE__ */
|
|
30631
|
+
return /* @__PURE__ */ jsxs59(
|
|
30403
30632
|
Box,
|
|
30404
30633
|
{
|
|
30405
30634
|
flexDirection: "column",
|
|
30406
30635
|
...isSelected && theme.supportsBackground ? { backgroundColor: theme.surfaceRaised } : {},
|
|
30407
30636
|
children: [
|
|
30408
|
-
/* @__PURE__ */
|
|
30409
|
-
/* @__PURE__ */
|
|
30410
|
-
/* @__PURE__ */
|
|
30637
|
+
/* @__PURE__ */ jsxs59(Box, { height: 1, children: [
|
|
30638
|
+
/* @__PURE__ */ jsx60(Text, { color: isSelected ? accent : theme.textMuted, children: isSelected ? "\u258E" : " " }),
|
|
30639
|
+
/* @__PURE__ */ jsxs59(Text, { color: accent, children: [
|
|
30411
30640
|
" ",
|
|
30412
30641
|
icon,
|
|
30413
30642
|
" "
|
|
30414
30643
|
] }),
|
|
30415
|
-
/* @__PURE__ */
|
|
30644
|
+
/* @__PURE__ */ jsx60(
|
|
30416
30645
|
Text,
|
|
30417
30646
|
{
|
|
30418
30647
|
color: isSelected ? theme.textPrimary : theme.textSecondary,
|
|
@@ -30420,24 +30649,24 @@ function ProjectPicker({
|
|
|
30420
30649
|
children: truncatePanelText(item.label, labelWidth)
|
|
30421
30650
|
}
|
|
30422
30651
|
),
|
|
30423
|
-
/* @__PURE__ */
|
|
30424
|
-
item.meta ? /* @__PURE__ */
|
|
30652
|
+
/* @__PURE__ */ jsx60(Box, { flexGrow: 1 }),
|
|
30653
|
+
item.meta ? /* @__PURE__ */ jsx60(Text, { color: isSelected ? accent : theme.textMuted, children: truncatePanelText(item.meta, 18) }) : null
|
|
30425
30654
|
] }),
|
|
30426
|
-
item.subtitle ? /* @__PURE__ */
|
|
30427
|
-
/* @__PURE__ */
|
|
30428
|
-
/* @__PURE__ */
|
|
30655
|
+
item.subtitle ? /* @__PURE__ */ jsxs59(Box, { height: 1, children: [
|
|
30656
|
+
/* @__PURE__ */ jsx60(Text, { color: isSelected ? accent : theme.textMuted, children: " \u2514\u2500 " }),
|
|
30657
|
+
/* @__PURE__ */ jsx60(Text, { color: theme.textMuted, children: truncatePanelText(item.subtitle, labelWidth) })
|
|
30429
30658
|
] }) : null
|
|
30430
30659
|
]
|
|
30431
30660
|
},
|
|
30432
30661
|
item.key
|
|
30433
30662
|
);
|
|
30434
30663
|
}) }),
|
|
30435
|
-
window.below > 0 ? /* @__PURE__ */
|
|
30664
|
+
window.below > 0 ? /* @__PURE__ */ jsxs59(Text, { color: theme.textMuted, children: [
|
|
30436
30665
|
" \u2193 ",
|
|
30437
30666
|
window.below,
|
|
30438
30667
|
" hidden"
|
|
30439
30668
|
] }) : null,
|
|
30440
|
-
hint ? /* @__PURE__ */
|
|
30669
|
+
hint ? /* @__PURE__ */ jsxs59(Text, { color: theme.warn, children: [
|
|
30441
30670
|
glyphs.warning,
|
|
30442
30671
|
" ",
|
|
30443
30672
|
hint
|
|
@@ -30447,9 +30676,94 @@ function ProjectPicker({
|
|
|
30447
30676
|
);
|
|
30448
30677
|
}
|
|
30449
30678
|
|
|
30679
|
+
// src/components/refine-countdown-panel.tsx
|
|
30680
|
+
import { useEffect as useEffect64, useRef as useRef35, useState as useState37 } from "react";
|
|
30681
|
+
import { jsx as jsx61, jsxs as jsxs60 } from "react/jsx-runtime";
|
|
30682
|
+
function RefineCountdownPanel({
|
|
30683
|
+
original,
|
|
30684
|
+
seconds,
|
|
30685
|
+
onDecision,
|
|
30686
|
+
providerId,
|
|
30687
|
+
model
|
|
30688
|
+
}) {
|
|
30689
|
+
const [remaining, setRemaining] = useState37(Math.max(1, seconds));
|
|
30690
|
+
const resolvedRef = useRef35(false);
|
|
30691
|
+
useEffect64(() => {
|
|
30692
|
+
const id = setInterval(() => {
|
|
30693
|
+
setRemaining((prev) => {
|
|
30694
|
+
if (prev <= 1) {
|
|
30695
|
+
clearInterval(id);
|
|
30696
|
+
if (!resolvedRef.current) {
|
|
30697
|
+
resolvedRef.current = true;
|
|
30698
|
+
onDecision("proceed");
|
|
30699
|
+
}
|
|
30700
|
+
return 0;
|
|
30701
|
+
}
|
|
30702
|
+
return prev - 1;
|
|
30703
|
+
});
|
|
30704
|
+
}, 1e3);
|
|
30705
|
+
return () => clearInterval(id);
|
|
30706
|
+
}, []);
|
|
30707
|
+
useInput((_input, key) => {
|
|
30708
|
+
if (resolvedRef.current) return;
|
|
30709
|
+
resolvedRef.current = true;
|
|
30710
|
+
if (key.escape) onDecision("cancel");
|
|
30711
|
+
else if (key.return) onDecision("proceed");
|
|
30712
|
+
else onDecision("skip");
|
|
30713
|
+
});
|
|
30714
|
+
const preview = wrapRefinementPreview(original, 60, 2);
|
|
30715
|
+
return /* @__PURE__ */ jsxs60(
|
|
30716
|
+
Box,
|
|
30717
|
+
{
|
|
30718
|
+
alignSelf: "stretch",
|
|
30719
|
+
width: "100%",
|
|
30720
|
+
flexDirection: "column",
|
|
30721
|
+
borderStyle: "round",
|
|
30722
|
+
borderColor: theme.brand,
|
|
30723
|
+
paddingX: 1,
|
|
30724
|
+
children: [
|
|
30725
|
+
/* @__PURE__ */ jsxs60(Box, { height: 1, children: [
|
|
30726
|
+
/* @__PURE__ */ jsxs60(Text, { color: theme.brand, bold: true, children: [
|
|
30727
|
+
glyphs.brain,
|
|
30728
|
+
" PROMPT REFINER"
|
|
30729
|
+
] }),
|
|
30730
|
+
providerId && model ? /* @__PURE__ */ jsxs60(Text, { color: theme.textMuted, children: [
|
|
30731
|
+
" ",
|
|
30732
|
+
"on ",
|
|
30733
|
+
providerId,
|
|
30734
|
+
"/",
|
|
30735
|
+
model
|
|
30736
|
+
] }) : null,
|
|
30737
|
+
/* @__PURE__ */ jsx61(Box, { flexGrow: 1 }),
|
|
30738
|
+
/* @__PURE__ */ jsxs60(Text, { color: theme.brand, children: [
|
|
30739
|
+
"refining in ",
|
|
30740
|
+
remaining,
|
|
30741
|
+
"s\u2026"
|
|
30742
|
+
] })
|
|
30743
|
+
] }),
|
|
30744
|
+
/* @__PURE__ */ jsx61(Box, { flexDirection: "column", marginTop: 1, children: preview.map((line, index) => /* @__PURE__ */ jsxs60(Box, { height: 1, children: [
|
|
30745
|
+
/* @__PURE__ */ jsx61(Text, { color: theme.brand, children: "\u258E" }),
|
|
30746
|
+
/* @__PURE__ */ jsxs60(Text, { color: theme.textSecondary, children: [
|
|
30747
|
+
" ",
|
|
30748
|
+
line
|
|
30749
|
+
] })
|
|
30750
|
+
] }, `refine-countdown-preview-${index}`)) }),
|
|
30751
|
+
/* @__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" }) })
|
|
30752
|
+
]
|
|
30753
|
+
}
|
|
30754
|
+
);
|
|
30755
|
+
}
|
|
30756
|
+
|
|
30450
30757
|
// src/components/refine-failure-panel.tsx
|
|
30451
|
-
import { useState as useState38 } from "react";
|
|
30758
|
+
import { useState as useState38, useMemo as useMemo12 } from "react";
|
|
30452
30759
|
import { jsx as jsx62, jsxs as jsxs61 } from "react/jsx-runtime";
|
|
30760
|
+
function filterRefineModels(models, query) {
|
|
30761
|
+
const normalized = query.trim().toLowerCase();
|
|
30762
|
+
if (!normalized) return models;
|
|
30763
|
+
return models.filter(
|
|
30764
|
+
(candidate) => candidate.providerId.toLowerCase().includes(normalized) || candidate.model.toLowerCase().includes(normalized) || candidate.label?.toLowerCase().includes(normalized)
|
|
30765
|
+
);
|
|
30766
|
+
}
|
|
30453
30767
|
var PICK_WINDOW = 8;
|
|
30454
30768
|
function useColumns() {
|
|
30455
30769
|
const { stdout } = useStdout();
|
|
@@ -30466,17 +30780,26 @@ function RefineFailurePanel({
|
|
|
30466
30780
|
const columns = useColumns();
|
|
30467
30781
|
const [view, setView] = useState38("options");
|
|
30468
30782
|
const [cursor, setCursor] = useState38(0);
|
|
30783
|
+
const [query, setQuery] = useState38("");
|
|
30784
|
+
const filteredModels = useMemo12(() => filterRefineModels(models, query), [models, query]);
|
|
30469
30785
|
const width = Math.max(30, columns - 4);
|
|
30470
30786
|
const canPick = models.length > 0;
|
|
30471
30787
|
const canFallback = !!fallbackRef;
|
|
30472
30788
|
useInput((input, key) => {
|
|
30473
30789
|
if (view === "pick") {
|
|
30474
30790
|
if (key.escape) {
|
|
30791
|
+
if (query) {
|
|
30792
|
+
setQuery("");
|
|
30793
|
+
return;
|
|
30794
|
+
}
|
|
30475
30795
|
setView("options");
|
|
30796
|
+
setQuery("");
|
|
30797
|
+
setCursor(0);
|
|
30476
30798
|
return;
|
|
30477
30799
|
}
|
|
30478
30800
|
if (key.downArrow) {
|
|
30479
|
-
|
|
30801
|
+
const n = filteredModels.length;
|
|
30802
|
+
if (n > 0) setCursor((c) => Math.min(c + 1, n - 1));
|
|
30480
30803
|
return;
|
|
30481
30804
|
}
|
|
30482
30805
|
if (key.upArrow) {
|
|
@@ -30484,11 +30807,21 @@ function RefineFailurePanel({
|
|
|
30484
30807
|
return;
|
|
30485
30808
|
}
|
|
30486
30809
|
if (key.return) {
|
|
30487
|
-
const chosen =
|
|
30810
|
+
const chosen = filteredModels[cursor];
|
|
30488
30811
|
if (chosen)
|
|
30489
30812
|
onDecision({ kind: "pick", providerId: chosen.providerId, model: chosen.model });
|
|
30490
30813
|
return;
|
|
30491
30814
|
}
|
|
30815
|
+
if (key.backspace || key.delete) {
|
|
30816
|
+
setQuery((q) => q.slice(0, -1));
|
|
30817
|
+
setCursor(0);
|
|
30818
|
+
return;
|
|
30819
|
+
}
|
|
30820
|
+
if (input && input.length === 1 && input.charCodeAt(0) >= 32 && input.charCodeAt(0) < 127) {
|
|
30821
|
+
setQuery((q) => q + input);
|
|
30822
|
+
setCursor(0);
|
|
30823
|
+
return;
|
|
30824
|
+
}
|
|
30492
30825
|
return;
|
|
30493
30826
|
}
|
|
30494
30827
|
if (key.return) {
|
|
@@ -30503,17 +30836,19 @@ function RefineFailurePanel({
|
|
|
30503
30836
|
if (ch === "m" && canFallback) onDecision({ kind: "fallback" });
|
|
30504
30837
|
else if (ch === "p" && canPick) {
|
|
30505
30838
|
setCursor(0);
|
|
30839
|
+
setQuery("");
|
|
30506
30840
|
setView("pick");
|
|
30507
30841
|
} else if (ch === "s") onDecision({ kind: "original" });
|
|
30508
30842
|
else if (ch === "e") onDecision({ kind: "edit" });
|
|
30509
30843
|
});
|
|
30510
30844
|
if (view === "pick") {
|
|
30845
|
+
const total = filteredModels.length;
|
|
30511
30846
|
const start = Math.max(
|
|
30512
30847
|
0,
|
|
30513
|
-
Math.min(cursor - Math.floor(PICK_WINDOW / 2),
|
|
30848
|
+
Math.min(cursor - Math.floor(PICK_WINDOW / 2), total - PICK_WINDOW)
|
|
30514
30849
|
);
|
|
30515
30850
|
const windowStart = Math.max(0, start);
|
|
30516
|
-
const visible =
|
|
30851
|
+
const visible = filteredModels.slice(windowStart, windowStart + PICK_WINDOW);
|
|
30517
30852
|
return /* @__PURE__ */ jsxs61(
|
|
30518
30853
|
Box,
|
|
30519
30854
|
{
|
|
@@ -30531,12 +30866,17 @@ function RefineFailurePanel({
|
|
|
30531
30866
|
] }),
|
|
30532
30867
|
/* @__PURE__ */ jsx62(Box, { flexGrow: 1 }),
|
|
30533
30868
|
/* @__PURE__ */ jsxs61(Text, { color: theme.textMuted, children: [
|
|
30534
|
-
models.length
|
|
30869
|
+
query ? `${total}/${models.length}` : `${models.length}`,
|
|
30535
30870
|
" model",
|
|
30536
|
-
models.length === 1 ? "" : "s"
|
|
30871
|
+
(query ? total : models.length) === 1 ? "" : "s"
|
|
30537
30872
|
] })
|
|
30538
30873
|
] }),
|
|
30539
|
-
/* @__PURE__ */ jsx62(Box, {
|
|
30874
|
+
/* @__PURE__ */ jsx62(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */ jsx62(Text, { color: theme.textMuted, children: query ? `\u{1F50D} ${query} ` : "\u{1F50D} type to filter" }) }),
|
|
30875
|
+
total === 0 ? /* @__PURE__ */ jsx62(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */ jsxs61(Text, { color: theme.textMuted, children: [
|
|
30876
|
+
'(no models match "',
|
|
30877
|
+
query,
|
|
30878
|
+
'")'
|
|
30879
|
+
] }) }) : /* @__PURE__ */ jsx62(Box, { flexDirection: "column", marginTop: 1, children: visible.map((m, i) => {
|
|
30540
30880
|
const idx = windowStart + i;
|
|
30541
30881
|
const selected = idx === cursor;
|
|
30542
30882
|
const label = m.label && m.label !== m.model ? ` ${m.label}` : "";
|
|
@@ -30546,7 +30886,11 @@ function RefineFailurePanel({
|
|
|
30546
30886
|
/* @__PURE__ */ jsx62(Text, { color: theme.textMuted, children: label })
|
|
30547
30887
|
] }, `${m.providerId}/${m.model}`);
|
|
30548
30888
|
}) }),
|
|
30549
|
-
/* @__PURE__ */ jsx62(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */
|
|
30889
|
+
/* @__PURE__ */ jsx62(Box, { height: 1, marginTop: 1, children: /* @__PURE__ */ jsxs61(Text, { color: theme.textMuted, children: [
|
|
30890
|
+
"\u2191/\u2193 choose \xB7 Enter refine \xB7 ",
|
|
30891
|
+
query ? "Esc clear \xB7 " : "",
|
|
30892
|
+
"Esc back"
|
|
30893
|
+
] }) })
|
|
30550
30894
|
]
|
|
30551
30895
|
}
|
|
30552
30896
|
);
|
|
@@ -30712,7 +31056,7 @@ import {
|
|
|
30712
31056
|
useCallback as useCallback25,
|
|
30713
31057
|
useEffect as useEffect67,
|
|
30714
31058
|
useLayoutEffect as useLayoutEffect2,
|
|
30715
|
-
useMemo as
|
|
31059
|
+
useMemo as useMemo14,
|
|
30716
31060
|
useRef as useRef37,
|
|
30717
31061
|
useState as useState40
|
|
30718
31062
|
} from "react";
|
|
@@ -31153,7 +31497,7 @@ import { Fragment as Fragment21, jsx as jsx65, jsxs as jsxs63 } from "react/jsx-
|
|
|
31153
31497
|
var MAX_TOOL_GROUP_ENTRIES = 12;
|
|
31154
31498
|
var STRUCTURED_DIFF_TOOLS = /* @__PURE__ */ new Set(["edit", "write", "replace", "diff", "patch"]);
|
|
31155
31499
|
function hasInjectedMemory(entry) {
|
|
31156
|
-
return
|
|
31500
|
+
return resolveEntrySage(entry.output, entry.sageLines).sageLines.length > 0;
|
|
31157
31501
|
}
|
|
31158
31502
|
function renderGroupId(group) {
|
|
31159
31503
|
return group.type === "tool-group" ? group.data.entries[0]?.id ?? 0 : group.entry.id;
|
|
@@ -31163,30 +31507,66 @@ function estimateTextRows(text, contentWidth, maxRows) {
|
|
|
31163
31507
|
if (!text) return 1;
|
|
31164
31508
|
const width = Math.max(16, contentWidth);
|
|
31165
31509
|
let rows = 0;
|
|
31166
|
-
let
|
|
31167
|
-
for (
|
|
31168
|
-
if (
|
|
31169
|
-
|
|
31170
|
-
|
|
31171
|
-
|
|
31510
|
+
let lineWidth = 0;
|
|
31511
|
+
for (const char of text) {
|
|
31512
|
+
if (char === "\n") {
|
|
31513
|
+
rows += Math.max(1, Math.ceil(lineWidth / width));
|
|
31514
|
+
if (rows >= maxRows) return maxRows;
|
|
31515
|
+
lineWidth = 0;
|
|
31516
|
+
continue;
|
|
31517
|
+
}
|
|
31518
|
+
lineWidth += displayWidth(char);
|
|
31172
31519
|
}
|
|
31173
|
-
|
|
31520
|
+
rows += Math.max(1, Math.ceil(lineWidth / width));
|
|
31521
|
+
return Math.min(maxRows, Math.max(1, rows));
|
|
31522
|
+
}
|
|
31523
|
+
function estimateSageKvRows(cells, contentWidth) {
|
|
31524
|
+
if (cells.length === 0) return 0;
|
|
31525
|
+
const gap = 2;
|
|
31526
|
+
let rows = 1;
|
|
31527
|
+
let usedColumns = 0;
|
|
31528
|
+
for (const cell of cells) {
|
|
31529
|
+
const cellWidth = displayWidth(cell) + gap;
|
|
31530
|
+
if (usedColumns > 0 && usedColumns + cellWidth > contentWidth) {
|
|
31531
|
+
rows += 1;
|
|
31532
|
+
usedColumns = cellWidth;
|
|
31533
|
+
} else {
|
|
31534
|
+
usedColumns += cellWidth;
|
|
31535
|
+
}
|
|
31536
|
+
}
|
|
31537
|
+
return rows;
|
|
31174
31538
|
}
|
|
31175
31539
|
function estimateRenderGroupRows(group, contentWidth) {
|
|
31176
31540
|
if (group.type === "tool-group") return group.data.entries.length + 2;
|
|
31177
31541
|
const { entry } = group;
|
|
31178
31542
|
if (entry.kind === "tool") {
|
|
31179
|
-
const { cleanOutput, sageLines } =
|
|
31543
|
+
const { cleanOutput, sageLines } = resolveEntrySage(entry.output, entry.sageLines);
|
|
31180
31544
|
const memoryLines = sageLines.slice(1);
|
|
31181
31545
|
const panelContentWidth = Math.max(16, contentWidth - 4);
|
|
31182
31546
|
const sagePanelRows = memoryLines.length > 0 ? 2 + estimateTextRows(
|
|
31183
|
-
`\u{1F9E0} SAGE MEMORY INJECTED \xB7 ${entry.name} ${memoryLines.length} ${memoryLines.length === 1 ? "memory" : "memories"}`,
|
|
31547
|
+
`\u{1F9E0} SAGE MEMORY INJECTED \xB7 ${entry.name} ${memoryLines.length} ${memoryLines.length === 1 ? "memory" : "memories"}${entry.sageStats ? ` \xB7 ${entry.sageStats}` : ""}`,
|
|
31184
31548
|
panelContentWidth,
|
|
31185
31549
|
MAX_TEXT_ESTIMATE_ROWS
|
|
31186
|
-
) + memoryLines.reduce(
|
|
31187
|
-
|
|
31188
|
-
|
|
31189
|
-
|
|
31550
|
+
) + memoryLines.reduce((rows, line) => {
|
|
31551
|
+
const parsed = parseSageMemoryLine(line);
|
|
31552
|
+
if (!parsed) {
|
|
31553
|
+
return rows + estimateTextRows(line, panelContentWidth, MAX_TEXT_ESTIMATE_ROWS);
|
|
31554
|
+
}
|
|
31555
|
+
const labelRow = estimateTextRows(
|
|
31556
|
+
parsed.labels.length > 0 ? parsed.labels.map((l) => `[${l}]`).join("") : "[memory]",
|
|
31557
|
+
panelContentWidth,
|
|
31558
|
+
MAX_TEXT_ESTIMATE_ROWS
|
|
31559
|
+
);
|
|
31560
|
+
const bodyRow = estimateTextRows(parsed.text, panelContentWidth, MAX_TEXT_ESTIMATE_ROWS);
|
|
31561
|
+
const kvCells = [];
|
|
31562
|
+
kvCells.push(`id: ${parsed.id}`);
|
|
31563
|
+
if (parsed.anchor) kvCells.push(`anchor: ${parsed.anchor}`);
|
|
31564
|
+
if (parsed.relation) kvCells.push(`relation: ${parsed.relation}`);
|
|
31565
|
+
if (parsed.tags && parsed.tags.length > 0) kvCells.push(`tags: ${parsed.tags.join(", ")}`);
|
|
31566
|
+
const kvRows = estimateSageKvRows(kvCells, panelContentWidth);
|
|
31567
|
+
const gap = rows > 0 ? 1 : 0;
|
|
31568
|
+
return rows + labelRow + bodyRow + kvRows + gap;
|
|
31569
|
+
}, 0) : 0;
|
|
31190
31570
|
if (entry.resultRenderMode === "simple") return 3 + sagePanelRows;
|
|
31191
31571
|
if (STRUCTURED_DIFF_TOOLS.has(entry.name)) {
|
|
31192
31572
|
const previewCap = entry.name === "replace" || entry.name === "diff" || entry.name === "patch" ? MULTI_DIFF_MAX_ROWS : DIFF_MAX_LINES;
|
|
@@ -31371,7 +31751,7 @@ import { memo as memo2, useEffect as useEffect66, useRef as useRef36, useState a
|
|
|
31371
31751
|
// src/components/history/entry.tsx
|
|
31372
31752
|
import { hasOpenTodos } from "@wrongstack/core/utils";
|
|
31373
31753
|
import { parseNextSteps } from "@wrongstack/tools/next-steps";
|
|
31374
|
-
import React8, { useEffect as useEffect65, useMemo as
|
|
31754
|
+
import React8, { useEffect as useEffect65, useMemo as useMemo13 } from "react";
|
|
31375
31755
|
|
|
31376
31756
|
// src/markdown-table.ts
|
|
31377
31757
|
import { expectDefined as expectDefined4 } from "@wrongstack/core/utils";
|
|
@@ -32359,8 +32739,28 @@ function ToolCard({
|
|
|
32359
32739
|
] });
|
|
32360
32740
|
}
|
|
32361
32741
|
|
|
32742
|
+
// src/history-entry.ts
|
|
32743
|
+
import {
|
|
32744
|
+
DEFAULT_MIN_IMPORTANCE as DEFAULT_MIN_IMPORTANCE2,
|
|
32745
|
+
DEFAULT_MIN_SCORE as DEFAULT_MIN_SCORE2,
|
|
32746
|
+
MIN_RELATION_STRENGTH as MIN_RELATION_STRENGTH2
|
|
32747
|
+
} from "@wrongstack/sage";
|
|
32748
|
+
var MEMORY_GATE_DEFAULTS = {
|
|
32749
|
+
minScore: DEFAULT_MIN_SCORE2,
|
|
32750
|
+
minImportance: DEFAULT_MIN_IMPORTANCE2,
|
|
32751
|
+
relationFloor: MIN_RELATION_STRENGTH2
|
|
32752
|
+
};
|
|
32753
|
+
|
|
32362
32754
|
// src/components/history/entry.tsx
|
|
32363
32755
|
import { Fragment as Fragment24, jsx as jsx70, jsxs as jsxs68 } from "react/jsx-runtime";
|
|
32756
|
+
var MAX_MEMORY_PROOF_ROWS = 4;
|
|
32757
|
+
function formatScoreTerms(terms) {
|
|
32758
|
+
if (terms.length === 0) return "no score breakdown (emitted by an older core build)";
|
|
32759
|
+
return terms.map((term) => {
|
|
32760
|
+
const magnitude = Math.abs(term.value).toFixed(2);
|
|
32761
|
+
return `${term.label} ${term.value < 0 ? "\u2212" : "+"}${magnitude}`;
|
|
32762
|
+
}).join(" \u2502 ");
|
|
32763
|
+
}
|
|
32364
32764
|
function brainStatusStyle(status) {
|
|
32365
32765
|
switch (status) {
|
|
32366
32766
|
case "thinking":
|
|
@@ -32428,7 +32828,7 @@ var Entry = React8.memo(function Entry2({
|
|
|
32428
32828
|
showModelReasoning
|
|
32429
32829
|
}) {
|
|
32430
32830
|
const openTodos = hasOpenTodos(todos);
|
|
32431
|
-
const nextSteps =
|
|
32831
|
+
const nextSteps = useMemo13(() => {
|
|
32432
32832
|
if (entry.kind !== "assistant") return { steps: [], stripped: "" };
|
|
32433
32833
|
return parseNextSteps(entry.text, true);
|
|
32434
32834
|
}, [entry.kind, entry.text]);
|
|
@@ -32547,7 +32947,7 @@ var Entry = React8.memo(function Entry2({
|
|
|
32547
32947
|
}
|
|
32548
32948
|
case "tool": {
|
|
32549
32949
|
const { glyph: glyph2, color } = getToolVisual(entry.name);
|
|
32550
|
-
const { argSummary, outLines, sageLines, visualLines, diff, multiDiffs, sizeChip, mutation } =
|
|
32950
|
+
const { argSummary, outLines, sageLines, visualLines, diff, multiDiffs, sizeChip, mutation } = useMemo13(() => {
|
|
32551
32951
|
const argSummary2 = formatToolArgs(entry.name, entry.input);
|
|
32552
32952
|
const {
|
|
32553
32953
|
cleanOutput: outputForFormatting,
|
|
@@ -32558,7 +32958,8 @@ var Entry = React8.memo(function Entry2({
|
|
|
32558
32958
|
entry.output,
|
|
32559
32959
|
entry.ok,
|
|
32560
32960
|
entry.outputBytes,
|
|
32561
|
-
entry.outputLines
|
|
32961
|
+
entry.outputLines,
|
|
32962
|
+
entry.sageLines
|
|
32562
32963
|
);
|
|
32563
32964
|
const visualLines2 = formatToolVisualOutput(
|
|
32564
32965
|
entry.name,
|
|
@@ -32617,6 +33018,7 @@ var Entry = React8.memo(function Entry2({
|
|
|
32617
33018
|
}, [
|
|
32618
33019
|
entry.name,
|
|
32619
33020
|
entry.output,
|
|
33021
|
+
entry.sageLines,
|
|
32620
33022
|
entry.input,
|
|
32621
33023
|
entry.ok,
|
|
32622
33024
|
entry.outputBytes,
|
|
@@ -32684,7 +33086,14 @@ var Entry = React8.memo(function Entry2({
|
|
|
32684
33086
|
]
|
|
32685
33087
|
}
|
|
32686
33088
|
),
|
|
32687
|
-
/* @__PURE__ */ jsx70(
|
|
33089
|
+
/* @__PURE__ */ jsx70(
|
|
33090
|
+
SageMemoryBlock,
|
|
33091
|
+
{
|
|
33092
|
+
sageLines,
|
|
33093
|
+
toolName: entry.name,
|
|
33094
|
+
stats: entry.sageStats
|
|
33095
|
+
}
|
|
33096
|
+
)
|
|
32688
33097
|
] });
|
|
32689
33098
|
}
|
|
32690
33099
|
const toolContentWidth = Math.max(20, termWidth - 2);
|
|
@@ -32764,14 +33173,16 @@ var Entry = React8.memo(function Entry2({
|
|
|
32764
33173
|
]
|
|
32765
33174
|
}
|
|
32766
33175
|
),
|
|
32767
|
-
/* @__PURE__ */ jsx70(SageMemoryBlock, { sageLines, toolName: entry.name })
|
|
33176
|
+
/* @__PURE__ */ jsx70(SageMemoryBlock, { sageLines, toolName: entry.name, stats: entry.sageStats })
|
|
32768
33177
|
] });
|
|
32769
33178
|
}
|
|
32770
33179
|
case "memory-activation": {
|
|
33180
|
+
if (!entry.error) return null;
|
|
32771
33181
|
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
|
|
33182
|
+
const injected = entry.outcome === "error" ? entry.activated : entry.activated.filter((memory) => entry.injectedIds.includes(memory.id));
|
|
33183
|
+
const shown = injected.slice(0, MAX_MEMORY_PROOF_ROWS);
|
|
33184
|
+
const overflow = injected.length - shown.length;
|
|
33185
|
+
const thresholds = entry.thresholds ?? MEMORY_GATE_DEFAULTS;
|
|
32775
33186
|
return /* @__PURE__ */ jsxs68(Box, { flexDirection: "column", borderStyle: "single", borderColor: "magenta", paddingX: 1, children: [
|
|
32776
33187
|
/* @__PURE__ */ jsxs68(Box, { flexDirection: "row", children: [
|
|
32777
33188
|
/* @__PURE__ */ jsx70(Text, { bold: true, color: "magenta", children: "\u{1F9E0} MEMORY INJECTOR " }),
|
|
@@ -32779,17 +33190,23 @@ var Entry = React8.memo(function Entry2({
|
|
|
32779
33190
|
/* @__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
33191
|
] }),
|
|
32781
33192
|
entry.error ? /* @__PURE__ */ jsx70(Text, { color: "red", children: `error: ${entry.error}` }) : null,
|
|
32782
|
-
|
|
32783
|
-
|
|
32784
|
-
|
|
32785
|
-
|
|
32786
|
-
|
|
32787
|
-
|
|
32788
|
-
|
|
32789
|
-
|
|
32790
|
-
|
|
32791
|
-
|
|
32792
|
-
|
|
33193
|
+
entry.queryPreview ? /* @__PURE__ */ jsx70(Text, { dimColor: true, wrap: "truncate-end", children: `query: ${entry.queryPreview}` }) : null,
|
|
33194
|
+
shown.map((memory) => {
|
|
33195
|
+
const scorePass = memory.score >= thresholds.minScore;
|
|
33196
|
+
const relationPass = memory.relationStrength >= thresholds.relationFloor;
|
|
33197
|
+
const reason = memory.activationReasons[0] ?? "no recorded reason";
|
|
33198
|
+
return /* @__PURE__ */ jsxs68(Box, { flexDirection: "column", children: [
|
|
33199
|
+
/* @__PURE__ */ jsxs68(Text, { wrap: "truncate-end", children: [
|
|
33200
|
+
/* @__PURE__ */ jsx70(Text, { color: "green", children: `${memory.id} ` }),
|
|
33201
|
+
/* @__PURE__ */ jsx70(Text, { color: scorePass ? "green" : "red", children: `${memory.score.toFixed(2)} ${scorePass ? "\u2713" : "\u2717"} ${thresholds.minScore.toFixed(2)}` }),
|
|
33202
|
+
/* @__PURE__ */ jsx70(Text, { dimColor: true, children: " \xB7 relation " }),
|
|
33203
|
+
/* @__PURE__ */ jsx70(Text, { color: relationPass ? "green" : "red", children: `${memory.relationStrength.toFixed(2)} ${relationPass ? "\u2713" : "\u2717"} ${thresholds.relationFloor.toFixed(2)}` }),
|
|
33204
|
+
/* @__PURE__ */ jsx70(Text, { dimColor: true, children: ` \xB7 ${reason}` })
|
|
33205
|
+
] }),
|
|
33206
|
+
/* @__PURE__ */ jsx70(Text, { dimColor: true, wrap: "truncate-end", children: ` ${formatScoreTerms(memory.scoreTerms ?? [])}` })
|
|
33207
|
+
] }, memory.id);
|
|
33208
|
+
}),
|
|
33209
|
+
overflow > 0 ? /* @__PURE__ */ jsx70(Text, { dimColor: true, children: ` +${overflow} more injected` }) : null,
|
|
32793
33210
|
rejected ? /* @__PURE__ */ jsx70(Text, { dimColor: true, children: `filtered: ${rejected}` }) : null
|
|
32794
33211
|
] });
|
|
32795
33212
|
}
|
|
@@ -32968,8 +33385,10 @@ var Entry = React8.memo(function Entry2({
|
|
|
32968
33385
|
});
|
|
32969
33386
|
function SageMemoryBlock({
|
|
32970
33387
|
sageLines,
|
|
32971
|
-
toolName
|
|
33388
|
+
toolName,
|
|
33389
|
+
stats
|
|
32972
33390
|
}) {
|
|
33391
|
+
if (!sageLines || sageLines.length < 2) return null;
|
|
32973
33392
|
const memoryLines = sageLines.slice(1);
|
|
32974
33393
|
if (memoryLines.length === 0) return null;
|
|
32975
33394
|
return /* @__PURE__ */ jsxs68(
|
|
@@ -32984,19 +33403,42 @@ function SageMemoryBlock({
|
|
|
32984
33403
|
children: [
|
|
32985
33404
|
/* @__PURE__ */ jsxs68(Box, { flexDirection: "row", children: [
|
|
32986
33405
|
/* @__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
|
-
)
|
|
33406
|
+
/* @__PURE__ */ jsx70(Text, { dimColor: true, children: `${memoryLines.length} ${memoryLines.length === 1 ? "memory" : "memories"}${stats ? ` \xB7 ${stats}` : ""}` })
|
|
32994
33407
|
] }),
|
|
32995
|
-
memoryLines.map((line, i) =>
|
|
33408
|
+
memoryLines.map((line, i) => {
|
|
33409
|
+
const parsed = parseSageMemoryLine(line);
|
|
33410
|
+
if (!parsed) {
|
|
33411
|
+
return /* @__PURE__ */ jsx70(Text, { color: theme.accent, dimColor: true, wrap: "truncate-end", children: line }, i);
|
|
33412
|
+
}
|
|
33413
|
+
return /* @__PURE__ */ jsx70(SageMemoryRow, { parsed, index: i }, i);
|
|
33414
|
+
})
|
|
32996
33415
|
]
|
|
32997
33416
|
}
|
|
32998
33417
|
);
|
|
32999
33418
|
}
|
|
33419
|
+
function SageMemoryRow({
|
|
33420
|
+
parsed,
|
|
33421
|
+
index
|
|
33422
|
+
}) {
|
|
33423
|
+
const labelText = parsed.labels.length > 0 ? parsed.labels.map((l) => `[${l}]`).join("") : "[memory]";
|
|
33424
|
+
const tagText = parsed.tags && parsed.tags.length > 0 ? parsed.tags.join(", ") : void 0;
|
|
33425
|
+
return /* @__PURE__ */ jsxs68(Box, { flexDirection: "column", marginTop: index > 0 ? 1 : 0, children: [
|
|
33426
|
+
/* @__PURE__ */ jsx70(Text, { bold: true, color: theme.accent, children: labelText }),
|
|
33427
|
+
/* @__PURE__ */ jsx70(Text, { color: theme.textPrimary, children: parsed.text }),
|
|
33428
|
+
/* @__PURE__ */ jsxs68(Box, { flexDirection: "row", flexWrap: "wrap", children: [
|
|
33429
|
+
/* @__PURE__ */ jsx70(SageKv, { label: "id", value: parsed.id }),
|
|
33430
|
+
parsed.anchor ? /* @__PURE__ */ jsx70(SageKv, { label: "anchor", value: parsed.anchor }) : null,
|
|
33431
|
+
parsed.relation ? /* @__PURE__ */ jsx70(SageKv, { label: "relation", value: parsed.relation }) : null,
|
|
33432
|
+
tagText ? /* @__PURE__ */ jsx70(SageKv, { label: "tags", value: tagText }) : null
|
|
33433
|
+
] })
|
|
33434
|
+
] });
|
|
33435
|
+
}
|
|
33436
|
+
function SageKv({ label, value }) {
|
|
33437
|
+
return /* @__PURE__ */ jsxs68(Box, { flexDirection: "row", marginRight: 2, children: [
|
|
33438
|
+
/* @__PURE__ */ jsx70(Text, { dimColor: true, children: `${label}: ` }),
|
|
33439
|
+
/* @__PURE__ */ jsx70(Text, { color: theme.textSecondary, children: value })
|
|
33440
|
+
] });
|
|
33441
|
+
}
|
|
33000
33442
|
|
|
33001
33443
|
// src/components/history/index.tsx
|
|
33002
33444
|
import { Fragment as Fragment25, jsx as jsx71, jsxs as jsxs69 } from "react/jsx-runtime";
|
|
@@ -33243,7 +33685,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
|
|
|
33243
33685
|
return maxWidth ? Math.min(raw, maxWidth) : raw;
|
|
33244
33686
|
}, [stdout, maxWidth]);
|
|
33245
33687
|
const [viewportWidth, setViewportWidth] = useState40(resolveViewportWidth);
|
|
33246
|
-
const termWidth =
|
|
33688
|
+
const termWidth = useMemo14(
|
|
33247
33689
|
() => Math.max(1, viewportWidth - SCROLLBAR_HIT_WIDTH),
|
|
33248
33690
|
[viewportWidth]
|
|
33249
33691
|
);
|
|
@@ -33258,8 +33700,8 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
|
|
|
33258
33700
|
}, [stdout, resolveViewportWidth]);
|
|
33259
33701
|
const toolTail = toolStream?.text ? tailForDisplay(toolStream.text, MAX_STREAM_DISPLAY_CHARS) : "";
|
|
33260
33702
|
const toolTailHeight = toolTail && toolStream ? toolStreamBoxHeight(toolStream.name) : 0;
|
|
33261
|
-
const groupedEntries =
|
|
33262
|
-
const groupIds =
|
|
33703
|
+
const groupedEntries = useMemo14(() => groupEntries(entries), [entries]);
|
|
33704
|
+
const groupIds = useMemo14(() => groupedEntries.map(renderGroupId), [groupedEntries]);
|
|
33263
33705
|
const groupIdsKey = groupIds.join(",");
|
|
33264
33706
|
const heightCacheRef = useRef37(null);
|
|
33265
33707
|
if (heightCacheRef.current === null) heightCacheRef.current = new EntryHeightCache();
|
|
@@ -33351,7 +33793,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
|
|
|
33351
33793
|
viewportRows: vp,
|
|
33352
33794
|
tailRows: toolTailHeight
|
|
33353
33795
|
};
|
|
33354
|
-
const groupIndexById =
|
|
33796
|
+
const groupIndexById = useMemo14(() => {
|
|
33355
33797
|
const indexes = /* @__PURE__ */ new Map();
|
|
33356
33798
|
groupIds.forEach((id, index) => {
|
|
33357
33799
|
indexes.set(id, index);
|
|
@@ -33383,7 +33825,7 @@ var ScrollableHistory = memo3(function ScrollableHistory2({
|
|
|
33383
33825
|
setAnchor(normalized && nextId !== void 0 ? { id: nextId, clip: normalized.clip } : null);
|
|
33384
33826
|
setMountBump(0);
|
|
33385
33827
|
}, []);
|
|
33386
|
-
const controller =
|
|
33828
|
+
const controller = useMemo14(
|
|
33387
33829
|
() => ({
|
|
33388
33830
|
scrollBy: (deltaUp) => {
|
|
33389
33831
|
applyAnchor(scrollAnchorBy(geometryRef.current, effectiveAnchorRef.current, deltaUp));
|
|
@@ -34029,22 +34471,9 @@ function AppView({ host, runtime }) {
|
|
|
34029
34471
|
enhanceDelayMs,
|
|
34030
34472
|
layoutStore
|
|
34031
34473
|
} = 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;
|
|
34474
|
+
const { nowTick, workingTimeMs, enhanceDots } = activity;
|
|
34475
|
+
const { setYoloLive, autonomyLive } = environment;
|
|
34476
|
+
const { inputHint, composerStatus, composerAnimationStyle, inputHeight, hideInput } = viewState;
|
|
34048
34477
|
return (
|
|
34049
34478
|
/* Hard viewport cap. The managed layout aims for exactly termRows
|
|
34050
34479
|
(history vp + measured bottom region), but the bottom region grows a
|
|
@@ -34230,6 +34659,7 @@ function AppView({ host, runtime }) {
|
|
|
34230
34659
|
breakerAutoKillResetMs: state.settingsPicker.breakerAutoKillResetMs,
|
|
34231
34660
|
showModelReasoning: state.settingsPicker.showModelReasoning,
|
|
34232
34661
|
showAgentSwarmPanel: state.settingsPicker.showAgentSwarmPanel,
|
|
34662
|
+
readSymbols: state.settingsPicker.readSymbols,
|
|
34233
34663
|
filter: state.settingsPicker.filter,
|
|
34234
34664
|
hint: state.settingsPicker.hint
|
|
34235
34665
|
}
|
|
@@ -35827,7 +36257,10 @@ function routeBusyInterruptKey(host, key) {
|
|
|
35827
36257
|
const fleetTag = subagentsTerminated > 0 ? ` \xB7 stopped ${subagentsTerminated} subagent${subagentsTerminated === 1 ? "" : "s"}` : "";
|
|
35828
36258
|
dispatch({
|
|
35829
36259
|
type: "addEntry",
|
|
35830
|
-
entry: {
|
|
36260
|
+
entry: {
|
|
36261
|
+
kind: "warn",
|
|
36262
|
+
text: `\u21AF Interrupted${droppedTag}${fleetTag}. Type your new direction.`
|
|
36263
|
+
}
|
|
35831
36264
|
});
|
|
35832
36265
|
return true;
|
|
35833
36266
|
}
|
|
@@ -35949,7 +36382,8 @@ function routeSettingsOverlayKey(host, input, key, isEnter) {
|
|
|
35949
36382
|
breakerEnabled: config.breakerEnabled ?? false,
|
|
35950
36383
|
breakerAutoKillResetMs: config.breakerAutoKillResetMs ?? 6e4,
|
|
35951
36384
|
showModelReasoning: config.showModelReasoning ?? true,
|
|
35952
|
-
showAgentSwarmPanel: config.showAgentSwarmPanel ?? true
|
|
36385
|
+
showAgentSwarmPanel: config.showAgentSwarmPanel ?? true,
|
|
36386
|
+
readSymbols: config.readSymbols ?? false
|
|
35953
36387
|
});
|
|
35954
36388
|
return true;
|
|
35955
36389
|
}
|