synabun 2026.4.21 → 2026.4.25-beta.2
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/CHANGELOG.md +175 -881
- package/README.md +1 -1
- package/hooks/claude-code/prompt-submit.mjs +39 -18
- package/hooks/claude-code/session-start.mjs +10 -3
- package/hooks/claude-code/shared.mjs +39 -2
- package/hooks/claude-code/stop.mjs +33 -6
- package/mcp-server/src/index.ts +9 -1
- package/mcp-server/src/services/neural-interface.ts +42 -14
- package/mcp-server/src/services/profiles.ts +8 -7
- package/mcp-server/src/tools/browser-advanced.ts +12 -10
- package/mcp-server/src/tools/browser-interact.ts +39 -38
- package/mcp-server/src/tools/browser-navigate.ts +12 -4
- package/mcp-server/src/tools/loop.ts +7 -3
- package/mcp-server/src/tools/profile.ts +19 -1
- package/neural-interface/lib/loop-logger.js +103 -0
- package/neural-interface/lib/mcp-installer.js +109 -0
- package/neural-interface/lib/plugin-installer.js +264 -0
- package/neural-interface/package.json +1 -1
- package/neural-interface/public/shared/api.js +66 -17
- package/neural-interface/public/shared/cdx/cdx-icons.js +5 -4
- package/neural-interface/public/shared/cdx/cdx-panel.js +117 -14
- package/neural-interface/public/shared/cdx/cdx-render.js +170 -43
- package/neural-interface/public/shared/cdx/cdx-styles.js +55 -10
- package/neural-interface/public/shared/cdx/cdx-tabs.js +394 -72
- package/neural-interface/public/shared/cli-status.js +157 -0
- package/neural-interface/public/shared/constants.js +3 -2
- package/neural-interface/public/shared/html-shell.js +32 -11
- package/neural-interface/public/shared/ocp/ocp-panel.js +127 -28
- package/neural-interface/public/shared/ocp/ocp-render.js +52 -44
- package/neural-interface/public/shared/ocp/ocp-styles.js +33 -0
- package/neural-interface/public/shared/ocp/ocp-tabs.js +693 -82
- package/neural-interface/public/shared/styles.css +635 -0
- package/neural-interface/public/shared/ui-automation-studio.js +38 -12
- package/neural-interface/public/shared/ui-claude-panel.js +322 -15
- package/neural-interface/public/shared/ui-file-explorer.js +38 -18
- package/neural-interface/public/shared/ui-menubar.js +34 -10
- package/neural-interface/public/shared/ui-navbar.js +8 -6
- package/neural-interface/public/shared/ui-schedules-studio.js +1464 -0
- package/neural-interface/public/shared/ui-settings.js +274 -50
- package/neural-interface/public/shared/ui-sidepanel-layout.js +18 -7
- package/neural-interface/public/shared/ui-sidepanel-tray.js +287 -0
- package/neural-interface/public/shared/ui-sync.js +9 -5
- package/neural-interface/public/shared/ui-terminal.js +76 -27
- package/neural-interface/public/shared/ui-tool-updates.js +49 -15
- package/neural-interface/public/shared/ui-tutorial-steps.js +4 -2
- package/neural-interface/public/shared/ui-tutorial.js +24 -18
- package/neural-interface/public/shared/ui-whiteboard.js +79 -31
- package/neural-interface/public/shared/vterm-buffer.js +9 -8
- package/neural-interface/public/variant/2d/main.js +9 -7
- package/neural-interface/public/variant/3d/main.js +10 -8
- package/neural-interface/server.js +1292 -255
- package/package.json +1 -1
- package/skills/leonardo/SKILL.md +5 -1
- package/skills/leonardo/modules/image-prompter.md +5 -1
- package/skills/leonardo/modules/video-prompter.md +5 -1
- package/skills/synabun/SKILL.md +44 -26
- package/skills/synabun/modules/audit.md +40 -36
- package/skills/synabun/modules/changelog.md +22 -18
- package/skills/synabun/modules/memorize.md +19 -15
- package/skills/synabun/modules/schedule.md +285 -0
- package/CLAUDE.md +0 -217
|
@@ -109,7 +109,7 @@ function extractCompactAssistantSummary(text) {
|
|
|
109
109
|
.replace(/\s+/g, ' ')
|
|
110
110
|
.trim();
|
|
111
111
|
if (!value) return 'Working through the next step';
|
|
112
|
-
return value
|
|
112
|
+
return value;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
// ═══════════════════════════════════════════
|
|
@@ -1091,8 +1091,8 @@ export function createMessageShell(kind, label, { phase = '' } = {}) {
|
|
|
1091
1091
|
head.appendChild(labelEl);
|
|
1092
1092
|
const phaseEl = document.createElement('div');
|
|
1093
1093
|
phaseEl.className = 'cxp-msg-phase';
|
|
1094
|
-
phaseEl.hidden =
|
|
1095
|
-
phaseEl.textContent = normalizedPhase === '
|
|
1094
|
+
phaseEl.hidden = normalizedPhase !== 'final_answer';
|
|
1095
|
+
phaseEl.textContent = normalizedPhase === 'final_answer' ? 'Final' : '';
|
|
1096
1096
|
head.appendChild(phaseEl);
|
|
1097
1097
|
card.appendChild(head);
|
|
1098
1098
|
|
|
@@ -1181,18 +1181,19 @@ export function renderPostPlanActions(tab = _ctx.boundTab, headerText = null) {
|
|
|
1181
1181
|
|
|
1182
1182
|
const note = document.createElement('div');
|
|
1183
1183
|
note.className = 'cxp-post-plan-note';
|
|
1184
|
-
note.textContent = 'Plan ready. Continue into implementation,
|
|
1184
|
+
note.textContent = 'Plan ready. Continue into implementation, keep planning, compact, or reopen the plan in the editor.';
|
|
1185
1185
|
card.appendChild(note);
|
|
1186
1186
|
|
|
1187
1187
|
const actions = document.createElement('div');
|
|
1188
1188
|
actions.className = 'cxp-post-plan-actions';
|
|
1189
1189
|
|
|
1190
1190
|
const continueBtn = _ctx.createRequestButton('Continue with implementation', 'primary');
|
|
1191
|
+
const continuePlanningBtn = _ctx.createRequestButton('Continue planning', 'secondary');
|
|
1191
1192
|
const compactBtn = _ctx.createRequestButton('Compact context', 'secondary');
|
|
1192
1193
|
const editBtn = _ctx.createRequestButton('Edit plan', 'secondary');
|
|
1193
1194
|
|
|
1194
1195
|
const setBusy = (busy) => {
|
|
1195
|
-
[continueBtn, compactBtn, editBtn].forEach((btn) => { btn.disabled = busy; });
|
|
1196
|
+
[continueBtn, continuePlanningBtn, compactBtn, editBtn].forEach((btn) => { btn.disabled = busy; });
|
|
1196
1197
|
card.style.opacity = busy ? '0.55' : '1';
|
|
1197
1198
|
card.style.pointerEvents = busy ? 'none' : 'auto';
|
|
1198
1199
|
};
|
|
@@ -1205,15 +1206,23 @@ export function renderPostPlanActions(tab = _ctx.boundTab, headerText = null) {
|
|
|
1205
1206
|
: 'Continue with the implementation based on the approved plan.';
|
|
1206
1207
|
tab.planMode = false;
|
|
1207
1208
|
tab.showPostPlanActions = false;
|
|
1209
|
+
tab.planApprovalPending = false;
|
|
1210
|
+
tab.planTurnActive = false;
|
|
1211
|
+
tab.lastPlanTurnId = '';
|
|
1208
1212
|
tab.postPlanHeader = 'PLAN COMPLETE';
|
|
1209
1213
|
if (typeof _ctx.setShowPostPlanActions === 'function') _ctx.setShowPostPlanActions(false);
|
|
1214
|
+
if (typeof _ctx.setPlanApprovalPending === 'function') _ctx.setPlanApprovalPending(false);
|
|
1215
|
+
if (typeof _ctx.setPlanTurnActive === 'function') _ctx.setPlanTurnActive(false);
|
|
1216
|
+
if (typeof _ctx.setLastPlanTurnId === 'function') _ctx.setLastPlanTurnId('');
|
|
1210
1217
|
if (typeof _ctx.setPostPlanHeader === 'function') _ctx.setPostPlanHeader('PLAN COMPLETE');
|
|
1211
1218
|
_ctx.syncToolbarState();
|
|
1212
1219
|
const sent = _ctx.dispatchPrompt(finalPrompt, { tab, forcePlanModePrefix: false });
|
|
1213
1220
|
if (!sent) {
|
|
1214
1221
|
tab.planMode = true;
|
|
1215
1222
|
tab.showPostPlanActions = true;
|
|
1223
|
+
tab.planApprovalPending = true;
|
|
1216
1224
|
if (typeof _ctx.setShowPostPlanActions === 'function') _ctx.setShowPostPlanActions(true);
|
|
1225
|
+
if (typeof _ctx.setPlanApprovalPending === 'function') _ctx.setPlanApprovalPending(true);
|
|
1217
1226
|
_ctx.syncToolbarState();
|
|
1218
1227
|
renderPostPlanActions(tab);
|
|
1219
1228
|
return;
|
|
@@ -1223,6 +1232,22 @@ export function renderPostPlanActions(tab = _ctx.boundTab, headerText = null) {
|
|
|
1223
1232
|
});
|
|
1224
1233
|
});
|
|
1225
1234
|
|
|
1235
|
+
continuePlanningBtn.addEventListener('click', () => {
|
|
1236
|
+
_ctx.withTab(tab, () => {
|
|
1237
|
+
if (_ctx.running) return;
|
|
1238
|
+
tab.showPostPlanActions = false;
|
|
1239
|
+
if (typeof _ctx.setShowPostPlanActions === 'function') _ctx.setShowPostPlanActions(false);
|
|
1240
|
+
_ctx.syncToolbarState();
|
|
1241
|
+
removePostPlanCards(tab.messagesEl);
|
|
1242
|
+
updatePostPlanTranscriptMeta(tab);
|
|
1243
|
+
const planText = tab.planContent || '';
|
|
1244
|
+
const prompt = planText
|
|
1245
|
+
? `Continue refining the plan below based on new requirements or feedback:\n\n${planText}`
|
|
1246
|
+
: 'Continue planning. Please extend or revise the current plan based on new requirements or feedback.';
|
|
1247
|
+
_ctx.dispatchPrompt(prompt, { tab, forcePlanModePrefix: true });
|
|
1248
|
+
});
|
|
1249
|
+
});
|
|
1250
|
+
|
|
1226
1251
|
compactBtn.addEventListener('click', () => {
|
|
1227
1252
|
_ctx.withTab(tab, () => {
|
|
1228
1253
|
if (_ctx.running || _ctx.startingThread || _ctx.compacting) return;
|
|
@@ -1240,22 +1265,29 @@ export function renderPostPlanActions(tab = _ctx.boundTab, headerText = null) {
|
|
|
1240
1265
|
try {
|
|
1241
1266
|
let filePath = tab.planFilePath || '';
|
|
1242
1267
|
if (!filePath) {
|
|
1243
|
-
|
|
1244
|
-
if (!
|
|
1245
|
-
|
|
1246
|
-
|
|
1268
|
+
filePath = typeof _ctx.ensurePlanFile === 'function' ? await _ctx.ensurePlanFile(tab) : '';
|
|
1269
|
+
if (!filePath) {
|
|
1270
|
+
const planText = _ctx.capturePlanContent(tab);
|
|
1271
|
+
if (!planText) {
|
|
1272
|
+
noFile();
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
const res = await fetch('/api/create-plan', {
|
|
1276
|
+
method: 'POST',
|
|
1277
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1278
|
+
body: JSON.stringify({ content: planText, cwd: tab.project || _ctx.project || '' }),
|
|
1279
|
+
});
|
|
1280
|
+
const result = await res.json();
|
|
1281
|
+
if (!res.ok || !result?.ok || !result.path) {
|
|
1282
|
+
noFile();
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
filePath = result.path;
|
|
1247
1286
|
}
|
|
1248
|
-
|
|
1249
|
-
method: 'POST',
|
|
1250
|
-
headers: { 'Content-Type': 'application/json' },
|
|
1251
|
-
body: JSON.stringify({ content: planText }),
|
|
1252
|
-
});
|
|
1253
|
-
const result = await res.json();
|
|
1254
|
-
if (!res.ok || !result?.ok || !result.path) {
|
|
1287
|
+
if (!filePath) {
|
|
1255
1288
|
noFile();
|
|
1256
1289
|
return;
|
|
1257
1290
|
}
|
|
1258
|
-
filePath = result.path;
|
|
1259
1291
|
tab.planFilePath = filePath;
|
|
1260
1292
|
if (_ctx.isActiveTab(tab)) {
|
|
1261
1293
|
if (typeof _ctx.setPlanFilePath === 'function') _ctx.setPlanFilePath(filePath);
|
|
@@ -1268,7 +1300,7 @@ export function renderPostPlanActions(tab = _ctx.boundTab, headerText = null) {
|
|
|
1268
1300
|
}
|
|
1269
1301
|
});
|
|
1270
1302
|
|
|
1271
|
-
actions.append(continueBtn, compactBtn, editBtn);
|
|
1303
|
+
actions.append(continueBtn, continuePlanningBtn, compactBtn, editBtn);
|
|
1272
1304
|
card.appendChild(actions);
|
|
1273
1305
|
body.appendChild(card);
|
|
1274
1306
|
cardWrap.appendChild(body);
|
|
@@ -1492,6 +1524,76 @@ function hasOwnField(value, key) {
|
|
|
1492
1524
|
return !!value && Object.prototype.hasOwnProperty.call(value, key);
|
|
1493
1525
|
}
|
|
1494
1526
|
|
|
1527
|
+
function normalizeReasoningText(value) {
|
|
1528
|
+
if (typeof value === 'string') return value;
|
|
1529
|
+
if (value == null) return '';
|
|
1530
|
+
if (Array.isArray(value)) {
|
|
1531
|
+
return value.map(normalizeReasoningText).filter(Boolean).join('\n');
|
|
1532
|
+
}
|
|
1533
|
+
if (typeof value === 'object') {
|
|
1534
|
+
for (const key of ['text', 'summaryText', 'summary_text', 'content', 'message']) {
|
|
1535
|
+
if (typeof value[key] === 'string') return value[key];
|
|
1536
|
+
}
|
|
1537
|
+
return extractStructuredText(value);
|
|
1538
|
+
}
|
|
1539
|
+
return String(value);
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
function normalizeReasoningLines(value) {
|
|
1543
|
+
if (value == null) return [];
|
|
1544
|
+
const values = Array.isArray(value) ? value : [value];
|
|
1545
|
+
return values
|
|
1546
|
+
.map((entry) => normalizeReasoningText(entry).trim())
|
|
1547
|
+
.filter(Boolean);
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
function reasoningTextFromKeys(item, keys) {
|
|
1551
|
+
if (!item || typeof item !== 'object') return [];
|
|
1552
|
+
for (const key of keys) {
|
|
1553
|
+
if (!hasOwnField(item, key)) continue;
|
|
1554
|
+
const lines = normalizeReasoningLines(item[key]);
|
|
1555
|
+
if (lines.length) return lines;
|
|
1556
|
+
}
|
|
1557
|
+
return [];
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
function isCompleteStatus(status) {
|
|
1561
|
+
if (!status) return false;
|
|
1562
|
+
if (typeof status === 'string') {
|
|
1563
|
+
return /^(complete|completed|done|success|failed|errored)$/i.test(status.trim());
|
|
1564
|
+
}
|
|
1565
|
+
if (typeof status === 'object') {
|
|
1566
|
+
return Object.keys(status).some((key) => isCompleteStatus(key));
|
|
1567
|
+
}
|
|
1568
|
+
return false;
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
function isReasoningComplete(item, hasIncomingText = false) {
|
|
1572
|
+
return isCompleteStatus(item?.status)
|
|
1573
|
+
|| !!item?.completedAt
|
|
1574
|
+
|| !!item?.completed_at
|
|
1575
|
+
|| item?.durationMs != null
|
|
1576
|
+
|| item?.duration_ms != null
|
|
1577
|
+
|| (hasIncomingText && !_ctx.running);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
function getReasoningPreviewText(state) {
|
|
1581
|
+
const summaryText = Array.isArray(state?.summaryLines)
|
|
1582
|
+
? state.summaryLines.map((line) => String(line || '').trim()).filter(Boolean).join(' ')
|
|
1583
|
+
: '';
|
|
1584
|
+
const contentText = Array.isArray(state?.contentLines)
|
|
1585
|
+
? state.contentLines.map((line) => String(line || '').trim()).filter(Boolean).join(' ')
|
|
1586
|
+
: '';
|
|
1587
|
+
return _ctx.cleanPreview(summaryText || contentText || 'Working through the next step');
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
function updateReasoningChrome(state, { complete = false } = {}) {
|
|
1591
|
+
if (!state) return;
|
|
1592
|
+
if (state.summaryEl) state.summaryEl.textContent = getReasoningPreviewText(state);
|
|
1593
|
+
if (state.pillEl) state.pillEl.textContent = complete ? 'complete' : 'live';
|
|
1594
|
+
if (state.el) state.el.classList.toggle('cxp-reasoning-done', !!complete);
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1495
1597
|
function cacheCollapsedCardState(state, item, itemType) {
|
|
1496
1598
|
if (!state || !item) return;
|
|
1497
1599
|
switch (itemType) {
|
|
@@ -1774,8 +1876,8 @@ export function ensureReasoningState(item) {
|
|
|
1774
1876
|
summary.innerHTML = `
|
|
1775
1877
|
<span class="cxp-card-icon">${ICON_SPARK}</span>
|
|
1776
1878
|
<span class="cxp-card-titles">
|
|
1777
|
-
<span class="cxp-card-title">Reasoning</span>
|
|
1778
|
-
<span class="cxp-card-subtitle">
|
|
1879
|
+
<span class="cxp-card-title">Reasoning Summary</span>
|
|
1880
|
+
<span class="cxp-card-subtitle">Working through the next step</span>
|
|
1779
1881
|
</span>
|
|
1780
1882
|
<span class="cxp-think-dots"><span></span><span></span><span></span></span>
|
|
1781
1883
|
<span class="cxp-status-pill">live</span>
|
|
@@ -1789,6 +1891,7 @@ export function ensureReasoningState(item) {
|
|
|
1789
1891
|
details.open = true;
|
|
1790
1892
|
details.addEventListener('toggle', () => {
|
|
1791
1893
|
details.dataset.expanded = details.open ? '1' : '0';
|
|
1894
|
+
if (state && !state.suppressToggleTracking) state.userToggled = true;
|
|
1792
1895
|
_ctx.scheduleThreadSnapshotSave(_ctx.boundTab);
|
|
1793
1896
|
});
|
|
1794
1897
|
|
|
@@ -1797,9 +1900,12 @@ export function ensureReasoningState(item) {
|
|
|
1797
1900
|
type: 'reasoning',
|
|
1798
1901
|
el: details,
|
|
1799
1902
|
bodyEl: body,
|
|
1800
|
-
summaryEl: summary.querySelector('.cxp-
|
|
1903
|
+
summaryEl: summary.querySelector('.cxp-card-subtitle'),
|
|
1904
|
+
pillEl: summary.querySelector('.cxp-status-pill'),
|
|
1801
1905
|
summaryLines: [],
|
|
1802
1906
|
contentLines: [],
|
|
1907
|
+
userToggled: false,
|
|
1908
|
+
suppressToggleTracking: false,
|
|
1803
1909
|
};
|
|
1804
1910
|
_ctx.items.set(item.id, state);
|
|
1805
1911
|
return state;
|
|
@@ -2146,30 +2252,36 @@ export function updateItemFromData(item) {
|
|
|
2146
2252
|
if (phase) state.el.dataset.phase = phase;
|
|
2147
2253
|
else delete state.el.dataset.phase;
|
|
2148
2254
|
}
|
|
2149
|
-
if (state.labelEl) state.labelEl.textContent =
|
|
2255
|
+
if (state.labelEl) state.labelEl.textContent = 'Codex';
|
|
2150
2256
|
if (state.phaseEl) {
|
|
2151
|
-
state.phaseEl.hidden =
|
|
2152
|
-
state.phaseEl.textContent = phase === '
|
|
2257
|
+
state.phaseEl.hidden = phase !== 'final_answer';
|
|
2258
|
+
state.phaseEl.textContent = phase === 'final_answer' ? 'Final' : '';
|
|
2153
2259
|
}
|
|
2154
2260
|
setMarkdownBuffer(state, resolveFinalMarkdownText(state, item.text), true);
|
|
2155
2261
|
break;
|
|
2156
2262
|
}
|
|
2157
2263
|
case 'reasoning': {
|
|
2158
|
-
const
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
state
|
|
2165
|
-
state.
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
state.bodyEl.textContent = getReasoningBodyText(state);
|
|
2169
|
-
if (state.el) {
|
|
2170
|
-
state.el.classList.add('cxp-reasoning-done');
|
|
2264
|
+
const incomingSummaryLines = reasoningTextFromKeys(item, ['summary', 'summaryText', 'summary_text']);
|
|
2265
|
+
const incomingContentLines = reasoningTextFromKeys(item, ['content', 'text']);
|
|
2266
|
+
const hasIncomingText = incomingSummaryLines.length > 0 || incomingContentLines.length > 0;
|
|
2267
|
+
if (incomingSummaryLines.length) state.summaryLines = incomingSummaryLines;
|
|
2268
|
+
if (incomingContentLines.length) state.contentLines = incomingContentLines;
|
|
2269
|
+
const complete = isReasoningComplete(item, hasIncomingText);
|
|
2270
|
+
updateReasoningChrome(state, { complete });
|
|
2271
|
+
if (state.bodyEl) state.bodyEl.textContent = getReasoningBodyText(state, { complete });
|
|
2272
|
+
if (state.el && complete && !state.userToggled) {
|
|
2273
|
+
state.suppressToggleTracking = true;
|
|
2171
2274
|
state.el.open = false;
|
|
2172
2275
|
state.el.dataset.expanded = '0';
|
|
2276
|
+
setTimeout(() => { state.suppressToggleTracking = false; }, 0);
|
|
2277
|
+
} else if (state.el && !complete) {
|
|
2278
|
+
state.el.classList.remove('cxp-reasoning-done');
|
|
2279
|
+
if (!state.userToggled) {
|
|
2280
|
+
state.suppressToggleTracking = true;
|
|
2281
|
+
state.el.open = true;
|
|
2282
|
+
state.el.dataset.expanded = '1';
|
|
2283
|
+
setTimeout(() => { state.suppressToggleTracking = false; }, 0);
|
|
2284
|
+
}
|
|
2173
2285
|
}
|
|
2174
2286
|
break;
|
|
2175
2287
|
}
|
|
@@ -2346,25 +2458,33 @@ export function appendPlanDelta(itemId, delta) {
|
|
|
2346
2458
|
setMarkdownBuffer(state, state.buffer, false);
|
|
2347
2459
|
}
|
|
2348
2460
|
|
|
2349
|
-
export function getReasoningBodyText(state) {
|
|
2350
|
-
if (!state) return '(reasoning complete)';
|
|
2461
|
+
export function getReasoningBodyText(state, { complete = false } = {}) {
|
|
2462
|
+
if (!state) return complete ? '(reasoning complete)' : 'Waiting for reasoning summary...';
|
|
2351
2463
|
const contentText = Array.isArray(state.contentLines) ? state.contentLines.join('').trim() : '';
|
|
2352
2464
|
if (contentText) return contentText;
|
|
2353
2465
|
const summaryText = Array.isArray(state.summaryLines)
|
|
2354
2466
|
? state.summaryLines.map((line) => String(line || '').trim()).filter(Boolean).join('\n')
|
|
2355
2467
|
: '';
|
|
2356
|
-
return summaryText || '(reasoning complete)';
|
|
2468
|
+
return summaryText || (complete ? '(reasoning complete)' : 'Waiting for reasoning summary...');
|
|
2357
2469
|
}
|
|
2358
2470
|
|
|
2359
2471
|
export function appendReasoningDelta(itemId, delta, isSummary = false, summaryIndex = null) {
|
|
2360
2472
|
const state = ensureReasoningState({ id: itemId });
|
|
2473
|
+
state.el?.classList.remove('cxp-reasoning-done');
|
|
2474
|
+
if (state.pillEl) state.pillEl.textContent = 'live';
|
|
2475
|
+
if (!state.userToggled && state.el && !state.el.open) {
|
|
2476
|
+
state.suppressToggleTracking = true;
|
|
2477
|
+
state.el.open = true;
|
|
2478
|
+
state.el.dataset.expanded = '1';
|
|
2479
|
+
setTimeout(() => { state.suppressToggleTracking = false; }, 0);
|
|
2480
|
+
}
|
|
2361
2481
|
if (isSummary) {
|
|
2362
2482
|
const idx = Number.isFinite(summaryIndex) ? Math.max(0, summaryIndex) : state.summaryLines.length;
|
|
2363
2483
|
state.summaryLines[idx] = (state.summaryLines[idx] || '') + (delta || '');
|
|
2364
|
-
if (state.summaryEl) state.summaryEl.textContent = state.summaryLines.join('').trim() || 'live';
|
|
2365
2484
|
} else {
|
|
2366
2485
|
state.contentLines.push(delta || '');
|
|
2367
2486
|
}
|
|
2487
|
+
updateReasoningChrome(state, { complete: false });
|
|
2368
2488
|
state.bodyEl.textContent = getReasoningBodyText(state);
|
|
2369
2489
|
_ctx.scrollEnd();
|
|
2370
2490
|
_ctx.scheduleThreadSnapshotSave(_ctx.boundTab);
|
|
@@ -2374,6 +2494,7 @@ export function appendReasoningSummaryPart(itemId, summaryIndex) {
|
|
|
2374
2494
|
const state = ensureReasoningState({ id: itemId });
|
|
2375
2495
|
const idx = Number.isFinite(summaryIndex) ? Math.max(0, summaryIndex) : state.summaryLines.length;
|
|
2376
2496
|
if (state.summaryLines[idx] == null) state.summaryLines[idx] = '';
|
|
2497
|
+
updateReasoningChrome(state, { complete: false });
|
|
2377
2498
|
state.bodyEl.textContent = getReasoningBodyText(state);
|
|
2378
2499
|
}
|
|
2379
2500
|
|
|
@@ -2452,9 +2573,15 @@ export function resolveHistoryRenderSource(thread, fallbackItems = null, storedS
|
|
|
2452
2573
|
const snapshotAtLeastAsComplete = !!snapshot
|
|
2453
2574
|
&& snapshot.itemCount > 0
|
|
2454
2575
|
&& snapshot.itemCount >= structuredItemCount;
|
|
2455
|
-
|
|
2576
|
+
// Trust the snapshot regardless of original source: SDK rebuild path was
|
|
2577
|
+
// observed to lose live render fidelity (streaming partials, MCP card state,
|
|
2578
|
+
// post-plan/post-compaction overlays). The snapshot is the most faithful
|
|
2579
|
+
// record of what the user saw, so prefer it when it's complete and fresh.
|
|
2580
|
+
const snapshotTrusted = !!snapshotSourceType;
|
|
2581
|
+
// Active threads still get the snapshot when no live SSE stream is reattaching
|
|
2582
|
+
// — covers the fresh-browser-load case where the thread was previously
|
|
2583
|
+
// running but the page reloaded before completion.
|
|
2456
2584
|
const canPreferSnapshot = !!snapshot
|
|
2457
|
-
&& thread?.status?.type !== 'active'
|
|
2458
2585
|
&& snapshotTrusted
|
|
2459
2586
|
&& snapshotFreshEnough
|
|
2460
2587
|
&& snapshotAtLeastAsComplete;
|
|
@@ -249,6 +249,10 @@ export function injectStyles() {
|
|
|
249
249
|
.cxp-effort-dots i.lit { opacity: 1; transform: scale(1.2); }
|
|
250
250
|
.cxp-toolbar-toggle[data-effort="off"] .cxp-effort-dots { display: none; }
|
|
251
251
|
|
|
252
|
+
#cxp-effort-toggle[data-effort="minimal"] { color: rgba(255,255,255,0.3); }
|
|
253
|
+
#cxp-effort-toggle[data-effort="minimal"]::after { transform: scaleX(0.25); background: rgba(255,255,255,0.16); }
|
|
254
|
+
#cxp-effort-toggle[data-effort="minimal"] .cxp-effort-dots i.lit { background: rgba(255,255,255,0.3); }
|
|
255
|
+
|
|
252
256
|
#cxp-effort-toggle[data-effort="low"] { color: rgba(255,255,255,0.35); }
|
|
253
257
|
#cxp-effort-toggle[data-effort="low"]::after { transform: scaleX(0.4); background: rgba(255,255,255,0.2); }
|
|
254
258
|
#cxp-effort-toggle[data-effort="low"] .cxp-effort-dots i.lit { background: rgba(255,255,255,0.35); }
|
|
@@ -261,6 +265,10 @@ export function injectStyles() {
|
|
|
261
265
|
#cxp-effort-toggle[data-effort="high"]::after { transform: scaleX(0.8); background: rgba(255,255,255,0.4); }
|
|
262
266
|
#cxp-effort-toggle[data-effort="high"] .cxp-effort-dots i.lit { background: rgba(255,255,255,0.5); }
|
|
263
267
|
|
|
268
|
+
#cxp-effort-toggle[data-effort="xhigh"] { color: rgba(255,255,255,0.7); }
|
|
269
|
+
#cxp-effort-toggle[data-effort="xhigh"]::after { transform: scaleX(1); background: rgba(255,255,255,0.5); }
|
|
270
|
+
#cxp-effort-toggle[data-effort="xhigh"] .cxp-effort-dots i.lit { background: rgba(255,255,255,0.65); }
|
|
271
|
+
|
|
264
272
|
/* ── Plan toggle active — blue underline ── */
|
|
265
273
|
#cxp-plan-toggle.active { color: rgba(130, 175, 255, 0.85); }
|
|
266
274
|
#cxp-plan-toggle.active::after { transform: scaleX(1); background: rgba(130, 175, 255, 0.6); }
|
|
@@ -976,6 +984,38 @@ export function injectStyles() {
|
|
|
976
984
|
.cxp-empty-logo svg { width: 32px; height: 32px; opacity: 0.25; }
|
|
977
985
|
.cxp-empty-name { font-size: 13px; font-weight: 500; color: rgba(255,255,255,0.35); letter-spacing: 0.02em; }
|
|
978
986
|
.cxp-empty-status { font-size: 11px; color: rgba(255,255,255,0.28); line-height: 1.5; min-height: 1em; }
|
|
987
|
+
.cxp-cli-missing {
|
|
988
|
+
display: flex; flex-direction: column; align-items: center; gap: 8px;
|
|
989
|
+
max-width: 320px; padding: 14px 16px; margin-top: 4px;
|
|
990
|
+
border: 1px solid rgba(255,180,80,0.35); border-radius: 8px;
|
|
991
|
+
background: rgba(255,180,80,0.06);
|
|
992
|
+
}
|
|
993
|
+
.cxp-cli-missing-title {
|
|
994
|
+
font-size: 12px; font-weight: 600; color: rgba(255,200,120,0.9);
|
|
995
|
+
letter-spacing: 0.02em;
|
|
996
|
+
}
|
|
997
|
+
.cxp-cli-missing-body {
|
|
998
|
+
font-size: 11px; color: rgba(255,255,255,0.55); text-align: center; line-height: 1.45;
|
|
999
|
+
}
|
|
1000
|
+
.cxp-cli-missing-body code {
|
|
1001
|
+
display: inline-block; padding: 1px 6px; margin-top: 4px;
|
|
1002
|
+
background: rgba(0,0,0,0.35); border-radius: 4px; font-size: 10.5px;
|
|
1003
|
+
color: rgba(255,255,255,0.75);
|
|
1004
|
+
}
|
|
1005
|
+
.cxp-cli-missing-actions { display: flex; gap: 8px; margin-top: 4px; }
|
|
1006
|
+
.cxp-cli-missing-link, .cxp-cli-missing-recheck {
|
|
1007
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
1008
|
+
padding: 5px 10px; font-size: 11px; font-weight: 500;
|
|
1009
|
+
border-radius: 5px; border: 1px solid rgba(255,255,255,0.15);
|
|
1010
|
+
background: rgba(255,255,255,0.04); color: rgba(255,255,255,0.85);
|
|
1011
|
+
text-decoration: none; cursor: pointer; user-select: none;
|
|
1012
|
+
}
|
|
1013
|
+
.cxp-cli-missing-link:hover, .cxp-cli-missing-recheck:hover {
|
|
1014
|
+
background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.3);
|
|
1015
|
+
}
|
|
1016
|
+
.cxp-cli-missing-recheck:disabled { opacity: 0.5; cursor: default; }
|
|
1017
|
+
.codex-panel.cxp-cli-blocked .cxp-send { opacity: 0.4 !important; cursor: not-allowed !important; }
|
|
1018
|
+
.codex-panel.cxp-cli-blocked .cxp-input { opacity: 0.7; }
|
|
979
1019
|
.cxp-system {
|
|
980
1020
|
align-self: center;
|
|
981
1021
|
max-width: 92%;
|
|
@@ -1079,15 +1119,8 @@ export function injectStyles() {
|
|
|
1079
1119
|
text-transform: uppercase;
|
|
1080
1120
|
letter-spacing: 0.05em;
|
|
1081
1121
|
}
|
|
1082
|
-
.cxp-msg-assistant[data-phase="commentary"] .cxp-msg-
|
|
1083
|
-
|
|
1084
|
-
border-radius: 14px;
|
|
1085
|
-
border: 1px solid rgba(255,255,255,0.05);
|
|
1086
|
-
background: linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0.015));
|
|
1087
|
-
}
|
|
1088
|
-
.cxp-msg-assistant[data-phase="commentary"] .cxp-msg-label,
|
|
1089
|
-
.cxp-msg-assistant[data-phase="commentary"] .cxp-msg-phase {
|
|
1090
|
-
color: rgba(255,255,255,0.58);
|
|
1122
|
+
.cxp-msg-assistant[data-phase="commentary"] .cxp-msg-head {
|
|
1123
|
+
display: none;
|
|
1091
1124
|
}
|
|
1092
1125
|
.cxp-msg-assistant[data-phase="final_answer"] .cxp-msg-phase {
|
|
1093
1126
|
color: rgba(115, 213, 167, 0.85);
|
|
@@ -1631,6 +1664,18 @@ export function injectStyles() {
|
|
|
1631
1664
|
}
|
|
1632
1665
|
.cxp-reasoning summary .cxp-card-titles {
|
|
1633
1666
|
flex: 1;
|
|
1667
|
+
min-width: 0;
|
|
1668
|
+
}
|
|
1669
|
+
.cxp-reasoning:not(.cxp-reasoning-done) {
|
|
1670
|
+
border-color: rgba(149, 209, 255, 0.11);
|
|
1671
|
+
background: rgba(149, 209, 255, 0.035);
|
|
1672
|
+
}
|
|
1673
|
+
.cxp-reasoning.cxp-reasoning-done {
|
|
1674
|
+
background: rgba(255,255,255,0.025);
|
|
1675
|
+
}
|
|
1676
|
+
.cxp-reasoning.cxp-reasoning-done .cxp-status-pill {
|
|
1677
|
+
color: rgba(255,255,255,0.45);
|
|
1678
|
+
background: rgba(255,255,255,0.035);
|
|
1634
1679
|
}
|
|
1635
1680
|
.cxp-reasoning-body {
|
|
1636
1681
|
padding: 0 11px 11px;
|
|
@@ -1639,7 +1684,7 @@ export function injectStyles() {
|
|
|
1639
1684
|
color: rgba(255,255,255,0.78);
|
|
1640
1685
|
font-size: 11.5px;
|
|
1641
1686
|
line-height: 1.6;
|
|
1642
|
-
max-height:
|
|
1687
|
+
max-height: min(360px, 42vh);
|
|
1643
1688
|
overflow-y: auto;
|
|
1644
1689
|
}
|
|
1645
1690
|
.cxp-ask {
|