clementine-agent 1.3.0 → 1.3.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/dist/cli/dashboard.js +81 -24
- package/package.json +1 -1
package/dist/cli/dashboard.js
CHANGED
|
@@ -11333,7 +11333,7 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
11333
11333
|
<span id="builder-agent-label" style="padding:0;font-size:13px;color:var(--text-secondary);font-weight:500"></span>
|
|
11334
11334
|
<input type="hidden" id="builder-agent" value="">
|
|
11335
11335
|
<span style="flex:1"></span>
|
|
11336
|
-
<button class="btn-sm" onclick="
|
|
11336
|
+
<button class="btn-sm btn-primary" onclick="newFromBuildHeader()" title="Create a new artifact for this tab" style="padding:4px 14px;border-radius:6px;cursor:pointer;font-size:12px">New</button>
|
|
11337
11337
|
<button class="btn-sm" id="builder-test-btn" onclick="testBuilderSkill()" style="background:var(--bg-tertiary);border:1px solid var(--border);color:var(--text-secondary);padding:4px 12px;border-radius:6px;cursor:pointer;font-size:12px;display:none">Test</button>
|
|
11338
11338
|
<button class="btn-sm btn-primary" id="builder-save-btn" onclick="saveBuilderArtifact()" style="padding:4px 16px;font-size:12px;display:none">Save</button>
|
|
11339
11339
|
</div>
|
|
@@ -11402,7 +11402,15 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
11402
11402
|
<div onclick="_builderAddNodeOfKind('loop')" class="builder-palette-item" data-kind="loop">loop</div>
|
|
11403
11403
|
</div>
|
|
11404
11404
|
<!-- Slide-out config panel -->
|
|
11405
|
-
<div id="builder-config-panel" style="display:none;position:absolute;right:0;top:0;bottom:0;width:340px;background:var(--bg-secondary);border-left:1px solid var(--border);box-shadow:-4px 0 16px rgba(0,0,0,0.15);z-index:12;
|
|
11405
|
+
<div id="builder-config-panel" style="display:none;position:absolute;right:0;top:0;bottom:0;width:340px;background:var(--bg-secondary);border-left:1px solid var(--border);box-shadow:-4px 0 16px rgba(0,0,0,0.15);z-index:12;flex-direction:column"></div>
|
|
11406
|
+
<!-- Empty-state CTA — visible when no workflow is open on the canvas -->
|
|
11407
|
+
<div id="builder-canvas-empty" style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:14px;color:var(--text-muted);text-align:center;padding:32px;pointer-events:none">
|
|
11408
|
+
<div style="font-size:38px;opacity:0.4">🔗</div>
|
|
11409
|
+
<div style="font-size:14px;font-weight:500;color:var(--text-secondary)">No workflow open</div>
|
|
11410
|
+
<div style="font-size:12px;line-height:1.5;max-width:280px">
|
|
11411
|
+
Pick one from the dropdown above — or click <strong>New</strong> in the header to create one from scratch, or open the <strong>Templates</strong> tab for starter patterns.
|
|
11412
|
+
</div>
|
|
11413
|
+
</div>
|
|
11406
11414
|
<div id="builder-canvas-footer" style="padding:6px 14px;border-top:1px solid var(--border);font-size:11px;color:var(--text-muted);display:flex;gap:14px;align-items:center">
|
|
11407
11415
|
<span id="builder-canvas-status"></span>
|
|
11408
11416
|
<span style="flex:1"></span>
|
|
@@ -14005,6 +14013,9 @@ function switchBuildTab(tab) {
|
|
|
14005
14013
|
var workPane = document.getElementById('build-tab-workflows');
|
|
14006
14014
|
var tplPane = document.getElementById('build-tab-templates');
|
|
14007
14015
|
var headerStrip = document.getElementById('build-header-strip');
|
|
14016
|
+
// Always close any open workflow when changing tabs — switching context
|
|
14017
|
+
// is a clean slate, not a stale node hanging on the canvas.
|
|
14018
|
+
if (typeof closeBuilderCanvas === 'function') closeBuilderCanvas();
|
|
14008
14019
|
if (tab === 'templates') {
|
|
14009
14020
|
if (workPane) workPane.style.display = 'none';
|
|
14010
14021
|
if (tplPane) tplPane.style.display = '';
|
|
@@ -14025,6 +14036,11 @@ function switchBuildTab(tab) {
|
|
|
14025
14036
|
updateBuilderMode();
|
|
14026
14037
|
}
|
|
14027
14038
|
}
|
|
14039
|
+
// Preload Drawflow eagerly so the canvas is responsive when the
|
|
14040
|
+
// user picks a workflow (rather than waiting for the lazy load).
|
|
14041
|
+
if (typeof _ensureDrawflowLoaded === 'function') {
|
|
14042
|
+
_ensureDrawflowLoaded().catch(function() { /* */ });
|
|
14043
|
+
}
|
|
14028
14044
|
// Focus chat input
|
|
14029
14045
|
setTimeout(function() {
|
|
14030
14046
|
var bi = document.getElementById('builder-input');
|
|
@@ -14033,6 +14049,38 @@ function switchBuildTab(tab) {
|
|
|
14033
14049
|
}
|
|
14034
14050
|
}
|
|
14035
14051
|
|
|
14052
|
+
// "New" button in the Build header strip — context-aware: prompts for a
|
|
14053
|
+
// name and creates the right artifact for the active tab. Workflows + Crons
|
|
14054
|
+
// route through the workflow_create surface; Skills falls back to the
|
|
14055
|
+
// existing chat-based Skill Studio reset.
|
|
14056
|
+
async function newFromBuildHeader() {
|
|
14057
|
+
var activeTab = document.querySelector('#build-tabs button.active')?.getAttribute('data-build-tab') || 'workflows';
|
|
14058
|
+
if (activeTab === 'skills') {
|
|
14059
|
+
if (typeof resetBuilder === 'function') resetBuilder();
|
|
14060
|
+
var bi = document.getElementById('builder-input');
|
|
14061
|
+
if (bi) bi.focus();
|
|
14062
|
+
return;
|
|
14063
|
+
}
|
|
14064
|
+
if (activeTab === 'templates') {
|
|
14065
|
+
toast('Pick a template to fork from the cards.', 'info');
|
|
14066
|
+
return;
|
|
14067
|
+
}
|
|
14068
|
+
var noun = activeTab === 'crons' ? 'cron' : 'workflow';
|
|
14069
|
+
var name = prompt('Name your new ' + noun + ':');
|
|
14070
|
+
if (!name || !name.trim()) return;
|
|
14071
|
+
try {
|
|
14072
|
+
var body = { name: name.trim() };
|
|
14073
|
+
if (activeTab === 'crons') body.schedule = '0 9 * * *'; // sensible default; user edits in canvas
|
|
14074
|
+
var r = await apiJson('POST', '/api/builder/workflows', body);
|
|
14075
|
+
if (r && r.error) { toast('Create failed: ' + r.error, 'error'); return; }
|
|
14076
|
+
if (r && r.id) {
|
|
14077
|
+
await refreshBuilderCanvasPicker(activeTab === 'crons' ? 'cron' : 'workflow');
|
|
14078
|
+
await openBuilderWorkflow(r.id);
|
|
14079
|
+
toast('Created ' + noun + ': ' + name, 'success');
|
|
14080
|
+
}
|
|
14081
|
+
} catch (err) { toast('Create error: ' + err, 'error'); }
|
|
14082
|
+
}
|
|
14083
|
+
|
|
14036
14084
|
// ── Build templates: fork a starter pattern into a new workflow ─────
|
|
14037
14085
|
async function forkBuildTemplate(templateId) {
|
|
14038
14086
|
var templates = {
|
|
@@ -18287,6 +18335,9 @@ async function openBuilderWorkflow(id) {
|
|
|
18287
18335
|
function _renderBuilderCanvas(drawflowData) {
|
|
18288
18336
|
var host = document.getElementById('builder-canvas');
|
|
18289
18337
|
if (!host) return;
|
|
18338
|
+
// Hide empty-state CTA — there's a workflow open now.
|
|
18339
|
+
var empty = document.getElementById('builder-canvas-empty');
|
|
18340
|
+
if (empty) empty.style.display = 'none';
|
|
18290
18341
|
// Tear down previous editor
|
|
18291
18342
|
if (_builderCanvasEditor) {
|
|
18292
18343
|
try { _builderCanvasEditor.clear(); } catch (e) { /* ignore */ }
|
|
@@ -18296,13 +18347,16 @@ function _renderBuilderCanvas(drawflowData) {
|
|
|
18296
18347
|
editor.reroute = true;
|
|
18297
18348
|
editor.editor_mode = 'edit';
|
|
18298
18349
|
editor.start();
|
|
18350
|
+
// Assign global BEFORE decoration runs — decoration reads node data via
|
|
18351
|
+
// editor.export() to recover stepIds (Drawflow doesn't preserve our
|
|
18352
|
+
// df-* attrs without a template).
|
|
18353
|
+
_builderCanvasEditor = editor;
|
|
18299
18354
|
try {
|
|
18300
18355
|
editor.import(drawflowData || { drawflow: { Home: { data: {} } } });
|
|
18301
18356
|
_decorateBuilderNodes(host, _builderCanvasLastWorkflow);
|
|
18302
18357
|
} catch (err) {
|
|
18303
18358
|
host.innerHTML = '<div style="padding:24px;color:var(--red)">Failed to render canvas: ' + esc(String(err)) + '</div>';
|
|
18304
18359
|
}
|
|
18305
|
-
_builderCanvasEditor = editor;
|
|
18306
18360
|
_bindBuilderCanvasEvents(editor);
|
|
18307
18361
|
}
|
|
18308
18362
|
|
|
@@ -18394,35 +18448,30 @@ function _updateBuilderBannerFromValidation(v) {
|
|
|
18394
18448
|
}
|
|
18395
18449
|
|
|
18396
18450
|
function _decorateBuilderNodes(host, wf) {
|
|
18397
|
-
if (!wf) return;
|
|
18451
|
+
if (!wf || !_builderCanvasEditor) return;
|
|
18452
|
+
// Pull each Drawflow node's data via the editor (which preserves the
|
|
18453
|
+
// stepId we set in stepToNodeData on the server side). Earlier code tried
|
|
18454
|
+
// to recover stepId from a df-stepId input, which Drawflow doesn't emit
|
|
18455
|
+
// unless you use templates — so every node decorated with the same step.
|
|
18456
|
+
// Now we look the step up by stepId directly.
|
|
18398
18457
|
var byStepId = {};
|
|
18399
18458
|
for (var i = 0; i < wf.steps.length; i++) byStepId[wf.steps[i].id] = wf.steps[i];
|
|
18400
|
-
|
|
18459
|
+
var allData = _builderCanvasEditor.export();
|
|
18460
|
+
var nodeData = (allData && allData.drawflow && allData.drawflow.Home && allData.drawflow.Home.data) || {};
|
|
18401
18461
|
var nodes = host.querySelectorAll('.drawflow-node');
|
|
18402
18462
|
nodes.forEach(function(nodeEl) {
|
|
18403
18463
|
var contentEl = nodeEl.querySelector('.drawflow_content_node');
|
|
18404
18464
|
if (!contentEl || contentEl.dataset._decorated) return;
|
|
18405
18465
|
contentEl.dataset._decorated = '1';
|
|
18406
|
-
var
|
|
18407
|
-
var
|
|
18408
|
-
|
|
18409
|
-
var
|
|
18410
|
-
var kind =
|
|
18411
|
-
var title = '';
|
|
18412
|
-
var body =
|
|
18413
|
-
var matchedStep = null;
|
|
18414
|
-
for (var j = 0; j < wf.steps.length; j++) {
|
|
18415
|
-
var s = wf.steps[j];
|
|
18416
|
-
if ((s.kind || 'prompt') === kind) { matchedStep = s; break; }
|
|
18417
|
-
}
|
|
18418
|
-
if (!matchedStep) {
|
|
18419
|
-
// Best-effort: use first step
|
|
18420
|
-
matchedStep = wf.steps[0];
|
|
18421
|
-
}
|
|
18422
|
-
title = (matchedStep ? matchedStep.id : '?');
|
|
18423
|
-
body = _summarizeStep(matchedStep, kind);
|
|
18466
|
+
var numericId = (nodeEl.id || '').replace(/^node-/, '');
|
|
18467
|
+
var data = (nodeData[numericId] && nodeData[numericId].data) || {};
|
|
18468
|
+
var stepId = data.stepId || null;
|
|
18469
|
+
var step = stepId ? byStepId[stepId] : null;
|
|
18470
|
+
var kind = (data.kind || (step && step.kind) || 'prompt');
|
|
18471
|
+
var title = step ? step.id : (stepId || '?');
|
|
18472
|
+
var body = _summarizeStep(step || data, kind);
|
|
18424
18473
|
contentEl.innerHTML =
|
|
18425
|
-
'<div style="font-weight:600;font-size:12px;margin-bottom:4px;color:#fff;text-transform:lowercase">' + esc(kind) + '
|
|
18474
|
+
'<div style="font-weight:600;font-size:12px;margin-bottom:4px;color:#fff;text-transform:lowercase">' + esc(kind) + ' · ' + esc(title) + '</div>' +
|
|
18426
18475
|
'<div style="font-size:11px;color:rgba(255,255,255,0.85);line-height:1.35;max-height:80px;overflow:hidden">' + esc(body) + '</div>';
|
|
18427
18476
|
});
|
|
18428
18477
|
}
|
|
@@ -18450,6 +18499,14 @@ function closeBuilderCanvas() {
|
|
|
18450
18499
|
if (idEl) idEl.textContent = '';
|
|
18451
18500
|
var banner = document.getElementById('builder-canvas-banner');
|
|
18452
18501
|
if (banner) banner.style.display = 'none';
|
|
18502
|
+
// Reset picker if it has a stale selection
|
|
18503
|
+
var picker = document.getElementById('builder-canvas-picker');
|
|
18504
|
+
if (picker && picker.value) picker.value = '';
|
|
18505
|
+
// Close config panel if it was open
|
|
18506
|
+
if (typeof _closeNodeConfigPanel === 'function') _closeNodeConfigPanel();
|
|
18507
|
+
// Show empty-state CTA
|
|
18508
|
+
var empty = document.getElementById('builder-canvas-empty');
|
|
18509
|
+
if (empty) empty.style.display = 'flex';
|
|
18453
18510
|
}
|
|
18454
18511
|
|
|
18455
18512
|
async function validateBuilderCanvas() {
|