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
|
@@ -229,27 +229,6 @@ function linkifyFilePaths(container) {
|
|
|
229
229
|
attachFileLinkHandlers(container);
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
-
// ── Throttle helper for streaming ──
|
|
233
|
-
function throttle(fn, ms) {
|
|
234
|
-
let last = 0;
|
|
235
|
-
let timer = null;
|
|
236
|
-
return function (...args) {
|
|
237
|
-
const now = Date.now();
|
|
238
|
-
const remaining = ms - (now - last);
|
|
239
|
-
if (remaining <= 0) {
|
|
240
|
-
if (timer) { clearTimeout(timer); timer = null; }
|
|
241
|
-
last = now;
|
|
242
|
-
fn.apply(this, args);
|
|
243
|
-
} else if (!timer) {
|
|
244
|
-
timer = setTimeout(() => {
|
|
245
|
-
last = Date.now();
|
|
246
|
-
timer = null;
|
|
247
|
-
fn.apply(this, args);
|
|
248
|
-
}, remaining);
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
|
|
253
232
|
function thinkBlockHtml(content, partial) {
|
|
254
233
|
const label = partial ? 'Thinking…' : 'Thought';
|
|
255
234
|
return `<details class="ocp-think-block"${partial ? ' open' : ''}><summary><span class="ocp-think-icon">${THINK_ICON_SVG}</span><span class="ocp-think-label">${label}</span><span class="ocp-think-chevron">›</span></summary><div class="ocp-think-content">${esc(content)}</div></details>`;
|
|
@@ -842,19 +821,46 @@ export function getOrCreateStreamingEl(container) {
|
|
|
842
821
|
return el;
|
|
843
822
|
}
|
|
844
823
|
|
|
824
|
+
function renderStreamingElement(container, el, { partialThinking = true } = {}) {
|
|
825
|
+
if (!el) return;
|
|
826
|
+
let html = '';
|
|
827
|
+
let hasContent = false;
|
|
828
|
+
if (el.dataset.thinkText) {
|
|
829
|
+
html += thinkBlockHtml(el.dataset.thinkText, partialThinking);
|
|
830
|
+
hasContent = true;
|
|
831
|
+
}
|
|
832
|
+
if (el.dataset.rawText) {
|
|
833
|
+
const rendered = renderAssistantMarkdown(el.dataset.rawText);
|
|
834
|
+
if (rendered.hasContent) {
|
|
835
|
+
html += rendered.html;
|
|
836
|
+
hasContent = true;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
el.innerHTML = html;
|
|
840
|
+
clearThinkingTimer(el);
|
|
841
|
+
el.classList.toggle('ocp-msg-empty', !hasContent);
|
|
842
|
+
postProcessRenderedHtml(el);
|
|
843
|
+
scrollToBottom(container);
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
function scheduleStreamingRender(container, el) {
|
|
847
|
+
if (el._ocpStreamRaf) return;
|
|
848
|
+
const schedule = typeof requestAnimationFrame === 'function'
|
|
849
|
+
? requestAnimationFrame
|
|
850
|
+
: (fn) => setTimeout(fn, 16);
|
|
851
|
+
el._ocpStreamRaf = schedule(() => {
|
|
852
|
+
el._ocpStreamRaf = null;
|
|
853
|
+
renderStreamingElement(container, el, { partialThinking: true });
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
|
|
845
857
|
/** Append a text chunk to the streaming element. */
|
|
846
858
|
export function appendStreamChunk(container, text) {
|
|
847
859
|
const chunk = normalizeTextContent(text, { stringifyObjects: false });
|
|
848
860
|
if (!chunk) return getOrCreateStreamingEl(container);
|
|
849
861
|
const el = getOrCreateStreamingEl(container);
|
|
850
862
|
el.dataset.rawText = (el.dataset.rawText || '') + chunk;
|
|
851
|
-
|
|
852
|
-
if (el.dataset.rawText != null) {
|
|
853
|
-
setAssistantHtml(el, el.dataset.rawText);
|
|
854
|
-
scrollToBottom(container);
|
|
855
|
-
}
|
|
856
|
-
}, 32);
|
|
857
|
-
doRender();
|
|
863
|
+
scheduleStreamingRender(container, el);
|
|
858
864
|
return el;
|
|
859
865
|
}
|
|
860
866
|
|
|
@@ -864,12 +870,7 @@ export function appendThinkChunk(container, text) {
|
|
|
864
870
|
if (!chunk) return getOrCreateStreamingEl(container);
|
|
865
871
|
const el = getOrCreateStreamingEl(container);
|
|
866
872
|
el.dataset.thinkText = (el.dataset.thinkText || '') + chunk;
|
|
867
|
-
|
|
868
|
-
const thinkHtml = thinkBlockHtml(el.dataset.thinkText, true);
|
|
869
|
-
const responseHtml = el.dataset.rawText ? renderAssistantMarkdown(el.dataset.rawText).html : '';
|
|
870
|
-
el.innerHTML = thinkHtml + responseHtml;
|
|
871
|
-
clearThinkingTimer(el);
|
|
872
|
-
scrollToBottom(container);
|
|
873
|
+
scheduleStreamingRender(container, el);
|
|
873
874
|
return el;
|
|
874
875
|
}
|
|
875
876
|
|
|
@@ -878,10 +879,9 @@ export function finalizeStreamingMessage(container) {
|
|
|
878
879
|
const el = container.querySelector('.ocp-msg-assistant.streaming');
|
|
879
880
|
if (el) {
|
|
880
881
|
el.classList.remove('streaming');
|
|
881
|
-
|
|
882
|
-
setAssistantHtml(el, el.dataset.rawText);
|
|
883
|
-
}
|
|
882
|
+
renderStreamingElement(container, el, { partialThinking: false });
|
|
884
883
|
delete el.dataset.rawText;
|
|
884
|
+
delete el.dataset.thinkText;
|
|
885
885
|
}
|
|
886
886
|
const pending = container.querySelector('.ocp-msg-assistant.pending');
|
|
887
887
|
if (pending) {
|
|
@@ -985,9 +985,10 @@ export function renderEmptyState(container) {
|
|
|
985
985
|
<div class="ocp-empty">
|
|
986
986
|
<svg viewBox="0 0 240 300"><path fill-rule="evenodd" d="M0 0h240v300H0V0zm30 30v240h180V30H30z" fill="currentColor"/><rect x="30" y="150" width="180" height="120" opacity=".45" fill="currentColor"/></svg>
|
|
987
987
|
<span>OpenCode</span>
|
|
988
|
-
<span style="font-size:10px;opacity:0.5">Send a message to start</span>
|
|
988
|
+
<span class="ocp-empty-hint" style="font-size:10px;opacity:0.5">Send a message to start</span>
|
|
989
989
|
</div>
|
|
990
990
|
`;
|
|
991
|
+
document.dispatchEvent(new CustomEvent('ocp-empty-rebuilt'));
|
|
991
992
|
}
|
|
992
993
|
|
|
993
994
|
// ── Render full history from messages:list response ──
|
|
@@ -1137,6 +1138,7 @@ function extractAllQuestions(input) {
|
|
|
1137
1138
|
: (input.question || input.text || input.options) ? [input]
|
|
1138
1139
|
: [input];
|
|
1139
1140
|
return questions.map(q => ({
|
|
1141
|
+
id: q.id || q.key || q.name || '',
|
|
1140
1142
|
question: q.question || q.text || q.message || '',
|
|
1141
1143
|
header: q.header || '',
|
|
1142
1144
|
options: normalizeOptions(q.options || q.choices),
|
|
@@ -1192,7 +1194,7 @@ export function renderQuestionCard(container, toolName, toolInput, toolId, { onA
|
|
|
1192
1194
|
// Render each question block
|
|
1193
1195
|
for (let qi = 0; qi < questions.length; qi++) {
|
|
1194
1196
|
const q = questions[qi];
|
|
1195
|
-
const questionKey = q.question || q.header || `question_${qi}`;
|
|
1197
|
+
const questionKey = q.id || q.question || q.header || `question_${qi}`;
|
|
1196
1198
|
const block = document.createElement('div');
|
|
1197
1199
|
block.className = 'ocp-question-block';
|
|
1198
1200
|
|
|
@@ -1255,6 +1257,7 @@ export function renderQuestionCard(container, toolName, toolInput, toolId, { onA
|
|
|
1255
1257
|
const isOther = opt.value === '__other__' || /^other$/i.test(opt.label);
|
|
1256
1258
|
const btn = document.createElement('button');
|
|
1257
1259
|
btn.className = `ocp-question-option${q.multiSelect ? ' multi' : ''}`;
|
|
1260
|
+
btn.dataset.value = opt.value;
|
|
1258
1261
|
btn.innerHTML = `
|
|
1259
1262
|
<span class="ocp-question-option-radio"></span>
|
|
1260
1263
|
<span>
|
|
@@ -1268,9 +1271,9 @@ export function renderQuestionCard(container, toolName, toolInput, toolId, { onA
|
|
|
1268
1271
|
const selected = [];
|
|
1269
1272
|
optsEl.querySelectorAll('.ocp-question-option.selected').forEach(b => {
|
|
1270
1273
|
const lbl = b.querySelector('.ocp-question-option-label');
|
|
1271
|
-
if (lbl && !/^other$/i.test(lbl.textContent)) selected.push(lbl.textContent);
|
|
1274
|
+
if (lbl && !/^other$/i.test(lbl.textContent)) selected.push(b.dataset.value || lbl.textContent);
|
|
1272
1275
|
});
|
|
1273
|
-
if (selected.length > 0) pendingAnswers[questionKey] = selected
|
|
1276
|
+
if (selected.length > 0) pendingAnswers[questionKey] = selected;
|
|
1274
1277
|
else delete pendingAnswers[questionKey];
|
|
1275
1278
|
} else {
|
|
1276
1279
|
optsEl.querySelectorAll('.ocp-question-option').forEach(b => b.classList.remove('selected'));
|
|
@@ -1283,7 +1286,7 @@ export function renderQuestionCard(container, toolName, toolInput, toolId, { onA
|
|
|
1283
1286
|
queueMicrotask(() => otherInput.focus());
|
|
1284
1287
|
} else {
|
|
1285
1288
|
otherWrap.hidden = true;
|
|
1286
|
-
pendingAnswers[questionKey] = opt.
|
|
1289
|
+
pendingAnswers[questionKey] = opt.value;
|
|
1287
1290
|
}
|
|
1288
1291
|
}
|
|
1289
1292
|
updateSubmitState();
|
|
@@ -1339,7 +1342,7 @@ export function lockQuestionCard(container, toolId) {
|
|
|
1339
1342
|
|
|
1340
1343
|
// ── Post-plan action card ──
|
|
1341
1344
|
|
|
1342
|
-
export function renderPostPlanCard(container, { onContinue, onCompact, onEditPlan } = {}) {
|
|
1345
|
+
export function renderPostPlanCard(container, { headerText = 'PLAN COMPLETE', onContinue, onCompact, onEditPlan, onContinuePlanning } = {}) {
|
|
1343
1346
|
const card = document.createElement('div');
|
|
1344
1347
|
card.className = 'ocp-post-plan-card';
|
|
1345
1348
|
card.innerHTML = `
|
|
@@ -1347,11 +1350,12 @@ export function renderPostPlanCard(container, { onContinue, onCompact, onEditPla
|
|
|
1347
1350
|
<svg class="ocp-post-plan-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
1348
1351
|
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/>
|
|
1349
1352
|
</svg>
|
|
1350
|
-
PLAN COMPLETE
|
|
1353
|
+
${esc(headerText || 'PLAN COMPLETE')}
|
|
1351
1354
|
</div>
|
|
1352
1355
|
<div class="ocp-post-plan-note">Review the plan above, then choose how to proceed.</div>
|
|
1353
1356
|
<div class="ocp-post-plan-actions">
|
|
1354
1357
|
<button class="ocp-post-plan-btn primary" data-action="continue">Continue with implementation</button>
|
|
1358
|
+
<button class="ocp-post-plan-btn" data-action="continue-planning">Continue planning</button>
|
|
1355
1359
|
<button class="ocp-post-plan-btn" data-action="compact">Compact context</button>
|
|
1356
1360
|
<button class="ocp-post-plan-btn" data-action="edit">Edit plan</button>
|
|
1357
1361
|
</div>
|
|
@@ -1367,6 +1371,10 @@ export function renderPostPlanCard(container, { onContinue, onCompact, onEditPla
|
|
|
1367
1371
|
card.querySelector('[data-action="edit"]').addEventListener('click', () => {
|
|
1368
1372
|
if (typeof onEditPlan === 'function') onEditPlan();
|
|
1369
1373
|
});
|
|
1374
|
+
card.querySelector('[data-action="continue-planning"]').addEventListener('click', () => {
|
|
1375
|
+
card.remove();
|
|
1376
|
+
if (typeof onContinuePlanning === 'function') onContinuePlanning();
|
|
1377
|
+
});
|
|
1370
1378
|
|
|
1371
1379
|
container.appendChild(card);
|
|
1372
1380
|
scrollToBottom(container);
|
|
@@ -1521,6 +1521,39 @@ export function injectStyles() {
|
|
|
1521
1521
|
stroke: currentColor; fill: none;
|
|
1522
1522
|
stroke-width: 1; opacity: 0.3;
|
|
1523
1523
|
}
|
|
1524
|
+
.ocp-cli-missing {
|
|
1525
|
+
display: flex; flex-direction: column; align-items: center; gap: 8px;
|
|
1526
|
+
max-width: 320px; padding: 14px 16px; margin-top: 4px;
|
|
1527
|
+
border: 1px solid rgba(255,180,80,0.35); border-radius: 8px;
|
|
1528
|
+
background: rgba(255,180,80,0.06);
|
|
1529
|
+
color: rgba(255,255,255,0.6);
|
|
1530
|
+
}
|
|
1531
|
+
.ocp-cli-missing-title {
|
|
1532
|
+
font-size: 12px; font-weight: 600; color: rgba(255,200,120,0.9);
|
|
1533
|
+
letter-spacing: 0.02em;
|
|
1534
|
+
}
|
|
1535
|
+
.ocp-cli-missing-body {
|
|
1536
|
+
font-size: 11px; color: rgba(255,255,255,0.55); text-align: center; line-height: 1.45;
|
|
1537
|
+
}
|
|
1538
|
+
.ocp-cli-missing-body code {
|
|
1539
|
+
display: inline-block; padding: 1px 6px; margin-top: 4px;
|
|
1540
|
+
background: rgba(0,0,0,0.35); border-radius: 4px; font-size: 10.5px;
|
|
1541
|
+
color: rgba(255,255,255,0.75);
|
|
1542
|
+
}
|
|
1543
|
+
.ocp-cli-missing-actions { display: flex; gap: 8px; margin-top: 4px; }
|
|
1544
|
+
.ocp-cli-missing-link, .ocp-cli-missing-recheck {
|
|
1545
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
1546
|
+
padding: 5px 10px; font-size: 11px; font-weight: 500;
|
|
1547
|
+
border-radius: 5px; border: 1px solid rgba(255,255,255,0.15);
|
|
1548
|
+
background: rgba(255,255,255,0.04); color: rgba(255,255,255,0.85);
|
|
1549
|
+
text-decoration: none; cursor: pointer; user-select: none;
|
|
1550
|
+
font-family: inherit;
|
|
1551
|
+
}
|
|
1552
|
+
.ocp-cli-missing-link:hover, .ocp-cli-missing-recheck:hover {
|
|
1553
|
+
background: rgba(255,255,255,0.1); border-color: rgba(255,255,255,0.3);
|
|
1554
|
+
}
|
|
1555
|
+
.ocp-cli-missing-recheck:disabled { opacity: 0.5; cursor: default; }
|
|
1556
|
+
.ocp-panel.ocp-cli-blocked .ocp-input { opacity: 0.7; }
|
|
1524
1557
|
|
|
1525
1558
|
/* ── Thinking indicator ── */
|
|
1526
1559
|
.ocp-thinking {
|