@plumpslabs/kuma 2.4.8 → 2.4.10
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/index.js +3 -3
- package/package.json +1 -1
- package/packages/ide/studio/dist/index.js +27 -4
- package/packages/ide/studio/public/index.html +175 -25
- package/plugin.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5579,7 +5579,7 @@ async function addGotcha(entry) {
|
|
|
5579
5579
|
try {
|
|
5580
5580
|
const { addEdge: addEdge2 } = await Promise.resolve().then(() => (init_kumaGraph(), kumaGraph_exports));
|
|
5581
5581
|
const stmt = db.prepare(`
|
|
5582
|
-
SELECT id FROM nodes WHERE type
|
|
5582
|
+
SELECT id FROM nodes WHERE type IN ('arch_flow', 'feature_domain')
|
|
5583
5583
|
AND (metadata LIKE ? OR file_path = ?)
|
|
5584
5584
|
LIMIT 5
|
|
5585
5585
|
`);
|
|
@@ -6758,7 +6758,7 @@ async function getFlowFreshness(domain) {
|
|
|
6758
6758
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
6759
6759
|
const db = await getDb2();
|
|
6760
6760
|
const stmt = db.prepare(
|
|
6761
|
-
`SELECT metadata FROM nodes WHERE type
|
|
6761
|
+
`SELECT metadata FROM nodes WHERE type IN ('feature_domain', 'arch_flow') AND name = ? LIMIT 1`
|
|
6762
6762
|
);
|
|
6763
6763
|
stmt.bind([domain]);
|
|
6764
6764
|
const found = stmt.step();
|
|
@@ -6848,7 +6848,7 @@ async function getHopsForDomain(domain) {
|
|
|
6848
6848
|
try {
|
|
6849
6849
|
const { getDb: getDb2 } = await Promise.resolve().then(() => (init_kumaDb(), kumaDb_exports));
|
|
6850
6850
|
const db = await getDb2();
|
|
6851
|
-
const stmt = db.prepare(`SELECT metadata FROM nodes WHERE type
|
|
6851
|
+
const stmt = db.prepare(`SELECT metadata FROM nodes WHERE type IN ('feature_domain', 'arch_flow') AND name = ? LIMIT 1`);
|
|
6852
6852
|
stmt.bind([domain]);
|
|
6853
6853
|
if (stmt.step()) {
|
|
6854
6854
|
const meta = JSON.parse(stmt.getAsObject().metadata || "{}");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@plumpslabs/kuma",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.10",
|
|
4
4
|
"description": "Safety-first context & orchestration engine for AI coding agents. MCP server with mandatory research pipeline, knowledge graph, impact analysis, decision memory, and safety guard — works with any MCP client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -166,7 +166,7 @@ async function getDashboardData() {
|
|
|
166
166
|
`SELECT json_group_array(json_object('id',id,'file_path',file_path,'description',REPLACE(REPLACE(description,char(10),' '),char(13),''),'severity',severity,'workaround',REPLACE(REPLACE(COALESCE(workaround,''),char(10),' '),char(13),''),'added_by',COALESCE(added_by,'agent'),'status',COALESCE(status,'active'),'scope_package',COALESCE(scope_package,''),'verified_by',COALESCE(verified_by,''),'created_at',created_at,'updated_at',COALESCE(updated_at,created_at))) FROM (SELECT * FROM known_gotchas ORDER BY created_at DESC)`
|
|
167
167
|
);
|
|
168
168
|
const flows = jsonRows(
|
|
169
|
-
`SELECT json_group_array(json_object('id',id,'name',name,'file_path',COALESCE(file_path,''),'metadata',COALESCE(metadata,'{}'),'updated_at',updated_at)) FROM (SELECT * FROM nodes WHERE type
|
|
169
|
+
`SELECT json_group_array(json_object('id',id,'name',name,'file_path',COALESCE(file_path,''),'metadata',COALESCE(metadata,'{}'),'updated_at',updated_at)) FROM (SELECT * FROM nodes WHERE type IN ('arch_flow', 'feature_domain') ORDER BY updated_at DESC)`
|
|
170
170
|
);
|
|
171
171
|
const decisions = jsonRows(
|
|
172
172
|
`SELECT json_group_array(json_object('id',id,'name',name,'metadata',COALESCE(metadata,'{}'),'created_at',created_at)) FROM (SELECT * FROM nodes WHERE type = 'decision' ORDER BY created_at DESC)`
|
|
@@ -182,11 +182,31 @@ async function getDashboardData() {
|
|
|
182
182
|
const pkg = JSON.parse(fs.readFileSync(rootPkgPath, "utf-8"));
|
|
183
183
|
const pnpmWs = path.join(root, "pnpm-workspace.yaml");
|
|
184
184
|
const isWs = Boolean(pkg.workspaces || fs.existsSync(pnpmWs));
|
|
185
|
+
const packages = [];
|
|
186
|
+
if (isWs) {
|
|
187
|
+
for (const dirName of ["packages", "apps", "libs", "services", "crates"]) {
|
|
188
|
+
const dirPath = path.join(root, dirName);
|
|
189
|
+
if (fs.existsSync(dirPath) && fs.statSync(dirPath).isDirectory()) {
|
|
190
|
+
for (const sub of fs.readdirSync(dirPath)) {
|
|
191
|
+
const subPkg = path.join(dirPath, sub, "package.json");
|
|
192
|
+
if (fs.existsSync(subPkg)) {
|
|
193
|
+
try {
|
|
194
|
+
const sp = JSON.parse(fs.readFileSync(subPkg, "utf-8"));
|
|
195
|
+
packages.push({ name: sp.name || sub, path: `${dirName}/${sub}` });
|
|
196
|
+
} catch {
|
|
197
|
+
packages.push({ name: sub, path: `${dirName}/${sub}` });
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
185
204
|
workspace = {
|
|
186
205
|
isWorkspace: isWs,
|
|
187
206
|
name: pkg.name || path.basename(root),
|
|
188
207
|
version: pkg.version || "1.0.0",
|
|
189
|
-
type: isWs ? fs.existsSync(pnpmWs) ? "pnpm" : "npm/yarn" : "single-package"
|
|
208
|
+
type: isWs ? fs.existsSync(pnpmWs) ? "pnpm" : "npm/yarn" : "single-package",
|
|
209
|
+
packages
|
|
190
210
|
};
|
|
191
211
|
}
|
|
192
212
|
} catch {
|
|
@@ -440,10 +460,13 @@ try {
|
|
|
440
460
|
} catch {
|
|
441
461
|
}
|
|
442
462
|
app.get("/", (c) => {
|
|
443
|
-
|
|
463
|
+
try {
|
|
464
|
+
const html = readFileSync(htmlPath, "utf-8");
|
|
465
|
+
return c.html(html);
|
|
466
|
+
} catch {
|
|
467
|
+
if (htmlCache) return c.html(htmlCache);
|
|
444
468
|
return c.text("index.html not found. Run from packages/ide/studio/", 500);
|
|
445
469
|
}
|
|
446
|
-
return c.html(htmlCache);
|
|
447
470
|
});
|
|
448
471
|
serve({ fetch: app.fetch, port: PORT }, (info) => {
|
|
449
472
|
const dbPath = findKumaDb();
|
|
@@ -322,10 +322,47 @@ header {
|
|
|
322
322
|
color: var(--muted);
|
|
323
323
|
border-radius: 4px;
|
|
324
324
|
font-size: 10px;
|
|
325
|
-
padding:
|
|
325
|
+
padding: 3px 8px;
|
|
326
326
|
cursor: pointer;
|
|
327
|
+
display: inline-flex;
|
|
328
|
+
align-items: center;
|
|
329
|
+
gap: 4px;
|
|
330
|
+
transition: all 0.2s ease;
|
|
327
331
|
}
|
|
328
332
|
.btn-copy-workaround:hover { color: #fff; border-color: var(--amber); }
|
|
333
|
+
.btn-copy-workaround.copied {
|
|
334
|
+
background: rgba(16, 185, 129, 0.15);
|
|
335
|
+
border-color: var(--emerald);
|
|
336
|
+
color: #34d399;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
#kuma-toast {
|
|
340
|
+
position: fixed;
|
|
341
|
+
bottom: 24px;
|
|
342
|
+
right: 24px;
|
|
343
|
+
background: #1e293b;
|
|
344
|
+
color: #f8fafc;
|
|
345
|
+
border: 1px solid #334155;
|
|
346
|
+
border-left: 4px solid var(--emerald);
|
|
347
|
+
padding: 10px 16px;
|
|
348
|
+
border-radius: 6px;
|
|
349
|
+
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
|
|
350
|
+
display: flex;
|
|
351
|
+
align-items: center;
|
|
352
|
+
gap: 8px;
|
|
353
|
+
font-size: 12px;
|
|
354
|
+
font-weight: 500;
|
|
355
|
+
z-index: 9999;
|
|
356
|
+
opacity: 0;
|
|
357
|
+
transform: translateY(12px);
|
|
358
|
+
transition: opacity 0.25s ease, transform 0.25s ease;
|
|
359
|
+
pointer-events: none;
|
|
360
|
+
}
|
|
361
|
+
#kuma-toast.show {
|
|
362
|
+
opacity: 1;
|
|
363
|
+
transform: translateY(0);
|
|
364
|
+
pointer-events: auto;
|
|
365
|
+
}
|
|
329
366
|
|
|
330
367
|
.gotcha-footer {
|
|
331
368
|
font-size: 11px;
|
|
@@ -699,11 +736,14 @@ async function fetchDashboard() {
|
|
|
699
736
|
}
|
|
700
737
|
|
|
701
738
|
function renderAll(data) {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
739
|
+
if (!data) return;
|
|
740
|
+
try { renderGotchas(data.gotchas || []); } catch (e) { console.error("renderGotchas error:", e); }
|
|
741
|
+
try { renderFlows(data.flows || []); } catch (e) { console.error("renderFlows error:", e); }
|
|
742
|
+
try { renderWorkspace(data.workspace, data.nodes || []); } catch (e) { console.error("renderWorkspace error:", e); }
|
|
743
|
+
try { renderHealth(data); } catch (e) { console.error("renderHealth error:", e); }
|
|
744
|
+
if (window.lucide && window.lucide.createIcons) {
|
|
745
|
+
try { window.lucide.createIcons(); } catch {}
|
|
746
|
+
}
|
|
707
747
|
}
|
|
708
748
|
|
|
709
749
|
function setStatusFilter(status) {
|
|
@@ -756,8 +796,10 @@ function renderGotchaCards(list) {
|
|
|
756
796
|
${g.workaround ? `
|
|
757
797
|
<div class="gotcha-workaround">
|
|
758
798
|
<strong>Workaround:</strong>
|
|
759
|
-
|
|
760
|
-
<button class="btn-copy-workaround" onclick="
|
|
799
|
+
<div class="workaround-text" style="margin-top:4px">${escapeHtml(g.workaround)}</div>
|
|
800
|
+
<button class="btn-copy-workaround" onclick="copyWorkaround(this)" title="Copy workaround to clipboard">
|
|
801
|
+
<i data-lucide="copy" style="width:11px;height:11px"></i> Copy
|
|
802
|
+
</button>
|
|
761
803
|
</div>
|
|
762
804
|
` : ''}
|
|
763
805
|
<div class="gotcha-footer">
|
|
@@ -771,29 +813,51 @@ function renderGotchaCards(list) {
|
|
|
771
813
|
}
|
|
772
814
|
|
|
773
815
|
function renderFlows(flows) {
|
|
774
|
-
document.getElementById("badge-flow-count")
|
|
816
|
+
var countBadge = document.getElementById("badge-flow-count");
|
|
817
|
+
if (countBadge) countBadge.textContent = flows ? flows.length : 0;
|
|
775
818
|
var container = document.getElementById("flow-cards-container");
|
|
776
|
-
if (!
|
|
819
|
+
if (!container) return;
|
|
820
|
+
if (!flows || !flows.length) {
|
|
777
821
|
container.innerHTML = '<div class="empty-placeholder"><i data-lucide="git-branch"></i><div>No domain sequence flows recorded yet.</div></div>';
|
|
778
822
|
if (window.lucide && window.lucide.createIcons) window.lucide.createIcons();
|
|
779
823
|
return;
|
|
780
824
|
}
|
|
781
825
|
container.innerHTML = flows.map(function(f) {
|
|
782
826
|
var meta = {};
|
|
783
|
-
try { meta = typeof f.metadata === "string" ? JSON.parse(f.metadata) : f.metadata; } catch {}
|
|
784
|
-
var hops = meta.hops
|
|
827
|
+
try { meta = typeof f.metadata === "string" ? JSON.parse(f.metadata) : (f.metadata || {}); } catch {}
|
|
828
|
+
var hops = Array.isArray(meta.hops) ? meta.hops : [];
|
|
829
|
+
var hopsCount = hops.length || (typeof meta.hops === "number" ? meta.hops : (meta.hopsCount || 0));
|
|
830
|
+
var gotchas = Array.isArray(meta.gotchas) ? meta.gotchas : [];
|
|
831
|
+
|
|
832
|
+
var hopsChainHtml = '';
|
|
833
|
+
if (hops.length > 0) {
|
|
834
|
+
hopsChainHtml = `
|
|
835
|
+
<div class="flow-hops-chain">
|
|
836
|
+
${hops.map(function(h, idx) {
|
|
837
|
+
var toLabel = typeof h === "object" ? (h.to || "") : String(h);
|
|
838
|
+
var fromLabel = (typeof h === "object" && h.from) ? h.from : "";
|
|
839
|
+
var rel = (typeof h === "object" && h.relation) ? ` <span style="opacity:0.6;font-size:10px">(${escapeHtml(h.relation)})</span>` : '';
|
|
840
|
+
var firstHopPrefix = (idx === 0 && fromLabel && fromLabel !== toLabel)
|
|
841
|
+
? `<span class="hop-node">${escapeHtml(fromLabel)}</span><span class="hop-arrow">→</span>`
|
|
842
|
+
: '';
|
|
843
|
+
return `${firstHopPrefix}<span class="hop-node">${escapeHtml(toLabel)}${rel}</span>${idx < hops.length - 1 ? '<span class="hop-arrow">→</span>' : ''}`;
|
|
844
|
+
}).join("")}
|
|
845
|
+
</div>
|
|
846
|
+
`;
|
|
847
|
+
} else if (hopsCount > 0) {
|
|
848
|
+
hopsChainHtml = `<div style="font-size:12px;color:var(--muted);padding:4px 0">${hopsCount} sequence hop(s) recorded.</div>`;
|
|
849
|
+
} else {
|
|
850
|
+
hopsChainHtml = `<div style="font-size:12px;color:var(--muted);padding:4px 0">No hops recorded for this flow.</div>`;
|
|
851
|
+
}
|
|
852
|
+
|
|
785
853
|
return `
|
|
786
854
|
<div class="flow-card">
|
|
787
855
|
<div class="flow-card-header">
|
|
788
856
|
<div class="flow-anchor"><i data-lucide="anchor" style="width:16px;height:16px"></i> ${escapeHtml(f.name || "Flow")}</div>
|
|
789
|
-
<span style="font-size:11px;color:var(--muted)">${
|
|
857
|
+
<span style="font-size:11px;color:var(--muted)">${hopsCount} hop(s)</span>
|
|
790
858
|
</div>
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
return `<span class="hop-node">${escapeHtml(h.to || h)}</span>${idx < hops.length - 1 ? '<span class="hop-arrow">→</span>' : ''}`;
|
|
794
|
-
}).join("")}
|
|
795
|
-
</div>
|
|
796
|
-
${meta.gotchas && meta.gotchas.length ? `<div style="font-size:11px;color:var(--amber)">⚠️ Linked Gotchas: ${meta.gotchas.map(escapeHtml).join(", ")}</div>` : ''}
|
|
859
|
+
${hopsChainHtml}
|
|
860
|
+
${gotchas.length ? `<div style="font-size:11px;color:var(--amber);margin-top:6px">⚠️ Linked Gotchas: ${gotchas.map(escapeHtml).join(", ")}</div>` : ''}
|
|
797
861
|
</div>
|
|
798
862
|
`;
|
|
799
863
|
}).join("");
|
|
@@ -802,14 +866,29 @@ function renderFlows(flows) {
|
|
|
802
866
|
|
|
803
867
|
function renderWorkspace(ws, nodes) {
|
|
804
868
|
var container = document.getElementById("ws-topology-info");
|
|
869
|
+
if (!container) return;
|
|
805
870
|
if (!ws) {
|
|
806
871
|
container.innerHTML = "<div>Single package workspace.</div>";
|
|
807
872
|
return;
|
|
808
873
|
}
|
|
874
|
+
var nodesLen = (nodes && nodes.length) ? nodes.length : 0;
|
|
875
|
+
var pkgHtml = '';
|
|
876
|
+
if (ws.packages && Array.isArray(ws.packages) && ws.packages.length > 0) {
|
|
877
|
+
pkgHtml = `
|
|
878
|
+
<div style="margin-top:10px"><strong>Monorepo Packages (${ws.packages.length}):</strong></div>
|
|
879
|
+
<div style="margin-top:6px;display:flex;flex-wrap:wrap;gap:6px">
|
|
880
|
+
${ws.packages.map(function(p) {
|
|
881
|
+
var name = typeof p === 'string' ? p : (p.name || p.path || '');
|
|
882
|
+
return `<span class="badge-pkg" style="background:#1e293b;border:1px solid #334155;padding:2px 8px;border-radius:4px;font-size:11px">📦 ${escapeHtml(name)}</span>`;
|
|
883
|
+
}).join("")}
|
|
884
|
+
</div>
|
|
885
|
+
`;
|
|
886
|
+
}
|
|
809
887
|
container.innerHTML = `
|
|
810
888
|
<div style="margin-bottom:8px"><strong>Workspace Type:</strong> <span class="badge-project">${escapeHtml(ws.type || "standard")}</span></div>
|
|
811
889
|
<div style="margin-bottom:8px"><strong>Project Root:</strong> <code>${escapeHtml(ws.name || "root")}</code> (v${escapeHtml(ws.version || "1.0.0")})</div>
|
|
812
|
-
|
|
890
|
+
${pkgHtml}
|
|
891
|
+
<div style="margin-top:12px;color:var(--muted)">Total indexed knowledge entities: <strong>${nodesLen}</strong></div>
|
|
813
892
|
`;
|
|
814
893
|
}
|
|
815
894
|
|
|
@@ -859,13 +938,16 @@ function renderHealth(data) {
|
|
|
859
938
|
|
|
860
939
|
var tbody = document.querySelector("#sessions-table tbody");
|
|
861
940
|
var sessions = eff.recentSessions || [];
|
|
941
|
+
if (!tbody) return;
|
|
862
942
|
if (!sessions.length) {
|
|
863
943
|
tbody.innerHTML = '<tr><td colspan="6" style="text-align:center;color:var(--muted)">No session records logged yet.</td></tr>';
|
|
864
944
|
} else {
|
|
865
945
|
tbody.innerHTML = sessions.map(function(s) {
|
|
946
|
+
var dateObj = s.startedAt ? new Date(s.startedAt < 1e11 ? s.startedAt * 1000 : s.startedAt) : null;
|
|
947
|
+
var timeStr = dateObj && !isNaN(dateObj.getTime()) ? dateObj.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : "Recent";
|
|
866
948
|
return `
|
|
867
949
|
<tr>
|
|
868
|
-
<td>${
|
|
950
|
+
<td>${timeStr}</td>
|
|
869
951
|
<td>${escapeHtml(s.goal || "General development")}</td>
|
|
870
952
|
<td>${s.toolCalls}</td>
|
|
871
953
|
<td>${s.edits}</td>
|
|
@@ -877,6 +959,7 @@ function renderHealth(data) {
|
|
|
877
959
|
}
|
|
878
960
|
|
|
879
961
|
var staleBox = document.getElementById("staleness-container");
|
|
962
|
+
if (!staleBox) return;
|
|
880
963
|
if (data.staleness && data.staleness.missing && data.staleness.missing.length) {
|
|
881
964
|
staleBox.innerHTML = `
|
|
882
965
|
<div style="color:var(--rose);margin-bottom:8px">⚠️ Detected ${data.staleness.missing.length} reference(s) to deleted files:</div>
|
|
@@ -896,7 +979,8 @@ function initOrRefreshGraph() {
|
|
|
896
979
|
var color = "#64748b";
|
|
897
980
|
if (n.type === "file") color = "#06b6d4";
|
|
898
981
|
else if (n.type === "gotcha") color = "#f59e0b";
|
|
899
|
-
else if (n.type === "arch_flow") color = "#6366f1";
|
|
982
|
+
else if (n.type === "arch_flow" || n.type === "feature_domain") color = "#6366f1";
|
|
983
|
+
else if (n.type === "cross_service_link" || n.type === "workflow") color = "#818cf8";
|
|
900
984
|
else if (n.type === "decision") color = "#10b981";
|
|
901
985
|
return {
|
|
902
986
|
id: n.id,
|
|
@@ -954,10 +1038,76 @@ async function resetDb() {
|
|
|
954
1038
|
}
|
|
955
1039
|
}
|
|
956
1040
|
|
|
957
|
-
function
|
|
958
|
-
|
|
959
|
-
|
|
1041
|
+
function showToast(msg) {
|
|
1042
|
+
var toast = document.getElementById("kuma-toast");
|
|
1043
|
+
if (!toast) {
|
|
1044
|
+
toast = document.createElement("div");
|
|
1045
|
+
toast.id = "kuma-toast";
|
|
1046
|
+
document.body.appendChild(toast);
|
|
1047
|
+
}
|
|
1048
|
+
toast.innerHTML = `<span style="color:var(--emerald);font-size:14px">✓</span> <span>${escapeHtml(msg || "Copied to clipboard!")}</span>`;
|
|
1049
|
+
toast.classList.add("show");
|
|
1050
|
+
clearTimeout(window.__kumaToastTimer);
|
|
1051
|
+
window.__kumaToastTimer = setTimeout(function() {
|
|
1052
|
+
toast.classList.remove("show");
|
|
1053
|
+
}, 2500);
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
function fallbackCopy(text) {
|
|
1057
|
+
var textarea = document.createElement("textarea");
|
|
1058
|
+
textarea.value = text;
|
|
1059
|
+
textarea.style.position = "fixed";
|
|
1060
|
+
textarea.style.top = "-9999px";
|
|
1061
|
+
textarea.style.left = "-9999px";
|
|
1062
|
+
document.body.appendChild(textarea);
|
|
1063
|
+
textarea.focus();
|
|
1064
|
+
textarea.select();
|
|
1065
|
+
try {
|
|
1066
|
+
document.execCommand("copy");
|
|
1067
|
+
} catch (err) {
|
|
1068
|
+
console.error("execCommand copy error:", err);
|
|
1069
|
+
}
|
|
1070
|
+
document.body.removeChild(textarea);
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
async function copyText(str, btn, toastMsg) {
|
|
1074
|
+
if (!str) return;
|
|
1075
|
+
var success = false;
|
|
1076
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
1077
|
+
try {
|
|
1078
|
+
await navigator.clipboard.writeText(str);
|
|
1079
|
+
success = true;
|
|
1080
|
+
} catch {
|
|
1081
|
+
fallbackCopy(str);
|
|
1082
|
+
success = true;
|
|
1083
|
+
}
|
|
1084
|
+
} else {
|
|
1085
|
+
fallbackCopy(str);
|
|
1086
|
+
success = true;
|
|
960
1087
|
}
|
|
1088
|
+
|
|
1089
|
+
if (success) {
|
|
1090
|
+
showToast(toastMsg || "Copied to clipboard!");
|
|
1091
|
+
if (btn) {
|
|
1092
|
+
var origHtml = btn.innerHTML;
|
|
1093
|
+
btn.classList.add("copied");
|
|
1094
|
+
btn.innerHTML = '<span>Copied! ✓</span>';
|
|
1095
|
+
setTimeout(function() {
|
|
1096
|
+
btn.classList.remove("copied");
|
|
1097
|
+
btn.innerHTML = origHtml;
|
|
1098
|
+
}, 2000);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
function copyWorkaround(btn) {
|
|
1104
|
+
if (!btn) return;
|
|
1105
|
+
var parent = btn.closest(".gotcha-workaround");
|
|
1106
|
+
if (!parent) return;
|
|
1107
|
+
var textEl = parent.querySelector(".workaround-text");
|
|
1108
|
+
var text = textEl ? textEl.innerText.trim() : "";
|
|
1109
|
+
if (!text) return;
|
|
1110
|
+
copyText(text, btn, "Workaround copied to clipboard!");
|
|
961
1111
|
}
|
|
962
1112
|
|
|
963
1113
|
function escapeHtml(str) {
|
package/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://antigravity.google/schemas/v1/plugin.json",
|
|
3
3
|
"name": "kuma",
|
|
4
|
-
"version": "2.4.
|
|
4
|
+
"version": "2.4.10",
|
|
5
5
|
"description": "Safety-first context & orchestration engine for AI coding agents. Shadow memory, gotcha lifecycle, blast radius impact analysis, and test verification.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "plumpslabs",
|