@luanpdd/kit-mcp 1.12.1 → 1.14.0
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/README.md +10 -10
- package/kit/agents/codebase-mapper.md +0 -6
- package/kit/agents/debugger.md +0 -6
- package/kit/agents/executor.md +0 -6
- package/kit/agents/phase-researcher.md +0 -6
- package/kit/agents/planner.md +0 -6
- package/kit/agents/project-researcher.md +0 -6
- package/kit/agents/research-synthesizer.md +0 -6
- package/kit/agents/roadmapper.md +0 -6
- package/kit/agents/ui-auditor.md +0 -6
- package/kit/agents/ui-researcher.md +0 -6
- package/kit/agents/verifier.md +0 -6
- package/kit/file-manifest.json +154 -48
- package/kit/hooks/check-update.js +4 -0
- package/kit/hooks/context-monitor.js +9 -2
- package/kit/hooks/post-apply-migration.js +10 -2
- package/kit/hooks/prompt-guard.js +9 -2
- package/kit/hooks/sidecar-tool-publisher.js +36 -14
- package/kit/hooks/statusline.js +6 -0
- package/kit/hooks/workflow-guard.js +9 -2
- package/package.json +1 -2
- package/src/cli/index.js +17 -5
- package/src/core/error-redaction.js +76 -0
- package/src/core/gate-runner.js +16 -4
- package/src/core/manifest-verify.js +103 -0
- package/src/core/path-safety.js +111 -0
- package/src/core/reflect.js +6 -1
- package/src/core/replays.js +59 -4
- package/src/core/sync.js +17 -2
- package/src/mcp-server/index.js +69 -18
- package/src/ui/auto-spawn.js +6 -1
- package/src/ui/client.js +34 -19
- package/src/ui/lockfile.js +5 -1
- package/src/ui/server.js +113 -20
- package/src/ui/static/index.html +66 -14
- package/CHANGELOG.md +0 -883
package/src/ui/static/index.html
CHANGED
|
@@ -1175,11 +1175,51 @@ button { font: inherit; color: inherit; background: none; border: 0; cursor: poi
|
|
|
1175
1175
|
|
|
1176
1176
|
<script>
|
|
1177
1177
|
/* ──────────────────────────────────────────────────────────
|
|
1178
|
-
kit-mcp sidecar —
|
|
1179
|
-
|
|
1180
|
-
|
|
1178
|
+
kit-mcp sidecar — production client
|
|
1179
|
+
SEC-14-01 (Phase 82): All event-derived content rendered via escapeHtml()
|
|
1180
|
+
before insertion into innerHTML. CSP without 'unsafe-inline' in script-src
|
|
1181
|
+
is primary defense; escapeHtml() is defense-in-depth.
|
|
1182
|
+
When adding new innerHTML sites, always escape dynamic fields.
|
|
1181
1183
|
────────────────────────────────────────────────────────── */
|
|
1182
1184
|
|
|
1185
|
+
/* ──────────────────────────────────────────────────────────
|
|
1186
|
+
SEC-14-02 (Phase 82 / Plan 02): auth token from URL query param.
|
|
1187
|
+
Server (Plan 01) requires Bearer token on /publish, /shutdown, /state
|
|
1188
|
+
and ?t= on /events. This block extracts ?t= once at boot, scrubs it
|
|
1189
|
+
from the address bar (so it doesn't leak via screen-share / browser
|
|
1190
|
+
history copy-paste), and exposes helpers for fetch + EventSource.
|
|
1191
|
+
Variable scoped to closure (not sessionStorage) — reload re-handshakes.
|
|
1192
|
+
────────────────────────────────────────────────────────── */
|
|
1193
|
+
const __sidecarToken = (() => {
|
|
1194
|
+
try {
|
|
1195
|
+
const params = new URLSearchParams(window.location.search);
|
|
1196
|
+
const t = params.get("t");
|
|
1197
|
+
if (t && /^[0-9a-f]{64}$/.test(t)) {
|
|
1198
|
+
// Scrub from URL so re-share / screenshot doesn't leak it.
|
|
1199
|
+
params.delete("t");
|
|
1200
|
+
const newSearch = params.toString();
|
|
1201
|
+
const newUrl = window.location.pathname + (newSearch ? "?" + newSearch : "") + window.location.hash;
|
|
1202
|
+
window.history.replaceState(null, "", newUrl);
|
|
1203
|
+
return t;
|
|
1204
|
+
}
|
|
1205
|
+
} catch (_) { /* fall through */ }
|
|
1206
|
+
return null;
|
|
1207
|
+
})();
|
|
1208
|
+
|
|
1209
|
+
function authedFetch(input, init = {}) {
|
|
1210
|
+
const opts = { ...init, headers: { ...(init.headers || {}) } };
|
|
1211
|
+
if (__sidecarToken) {
|
|
1212
|
+
opts.headers["Authorization"] = "Bearer " + __sidecarToken;
|
|
1213
|
+
}
|
|
1214
|
+
return fetch(input, opts);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
function authedEventSourceUrl(path) {
|
|
1218
|
+
if (!__sidecarToken) return path;
|
|
1219
|
+
const sep = path.includes("?") ? "&" : "?";
|
|
1220
|
+
return path + sep + "t=" + encodeURIComponent(__sidecarToken);
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1183
1223
|
/* ---------- humanize helpers (preserved API) ---------- */
|
|
1184
1224
|
const TYPE_LABELS = {
|
|
1185
1225
|
"run.start": "INICIADO",
|
|
@@ -1433,16 +1473,21 @@ function historyRowHtml(h) {
|
|
|
1433
1473
|
return `<div class="hist-detail-row"><span class="pct">${escapeHtml(pct)}</span><span class="lbl">${escapeHtml(lbl)}</span>${tk ? `<span class="tok">${tk}t</span>` : ""}</div>`;
|
|
1434
1474
|
})
|
|
1435
1475
|
.join("");
|
|
1476
|
+
// SEC-14-01: every dynamic field escaped before injection into the
|
|
1477
|
+
// history-row template. status/statusGlyph/dur/when/tokens are computed
|
|
1478
|
+
// locally (string enum or pre-built HTML literal) so are safe by construction;
|
|
1479
|
+
// h.runId and h.eventsCount cross the publisher boundary and MUST be escaped
|
|
1480
|
+
// even though they should normally be benign — defense in depth.
|
|
1436
1481
|
return `
|
|
1437
|
-
<div class="hist-row" data-status="${status}" data-runid="${h.runId}">
|
|
1482
|
+
<div class="hist-row" data-status="${escapeHtml(status)}" data-runid="${escapeHtml(h.runId)}">
|
|
1438
1483
|
<div class="hist-status">${statusGlyph}</div>
|
|
1439
1484
|
<div class="hist-title">${escapeHtml(title)}</div>
|
|
1440
1485
|
<div class="hist-when">${when}</div>
|
|
1441
1486
|
<div class="hist-meta-row">
|
|
1442
1487
|
<span><span class="num">${dur}</span> dur</span>
|
|
1443
1488
|
<span>${tokens}</span>
|
|
1444
|
-
<span><span class="num">${h.eventsCount || 0}</span> eventos</span>
|
|
1445
|
-
<span class="num">id ${h.runId.slice(0,8)}</span>
|
|
1489
|
+
<span><span class="num">${escapeHtml(String(h.eventsCount || 0))}</span> eventos</span>
|
|
1490
|
+
<span class="num">id ${escapeHtml(String(h.runId).slice(0,8))}</span>
|
|
1446
1491
|
</div>
|
|
1447
1492
|
<div class="hist-detail">${detailRows || '<div class="hist-detail-row"><span class="lbl">(sem progresso registrado)</span></div>'}</div>
|
|
1448
1493
|
</div>
|
|
@@ -1534,10 +1579,14 @@ function activeCardHtml(run) {
|
|
|
1534
1579
|
const longRunning = elapsed > 30_000;
|
|
1535
1580
|
const stepCount = run.total ? `${run.current}/${run.total}` : "";
|
|
1536
1581
|
const showTokens = run.tokens > 0;
|
|
1582
|
+
// SEC-14-01: family/iconHref/title/stepLabel/stepCount/percent are computed
|
|
1583
|
+
// locally; runId crosses the publisher boundary and is escaped before any
|
|
1584
|
+
// injection (data-attribute or text). Defense in depth: even string enums
|
|
1585
|
+
// (family) get escaped to ensure regression resistance.
|
|
1537
1586
|
return `
|
|
1538
|
-
<article class="run-card" data-runid="${run.runId}">
|
|
1587
|
+
<article class="run-card" data-runid="${escapeHtml(run.runId)}">
|
|
1539
1588
|
<div class="rc-head">
|
|
1540
|
-
<div class="rc-icon" data-tool="${family}"><svg><use href="${iconHref}"/></svg></div>
|
|
1589
|
+
<div class="rc-icon" data-tool="${escapeHtml(family)}"><svg><use href="${escapeHtml(iconHref)}"/></svg></div>
|
|
1541
1590
|
<div class="rc-title-block">
|
|
1542
1591
|
<div class="rc-tool">${escapeHtml(safeStr(run.tool) || "processo")}</div>
|
|
1543
1592
|
<div class="rc-title">${escapeHtml(title)}</div>
|
|
@@ -1556,7 +1605,7 @@ function activeCardHtml(run) {
|
|
|
1556
1605
|
<div class="rc-step">
|
|
1557
1606
|
<span class="glyph"><svg><use href="#i-spin"/></svg></span>
|
|
1558
1607
|
<span class="rc-step-text">${escapeHtml(stepLabel)}</span>
|
|
1559
|
-
${stepCount ? `<span class="rc-step-count">${stepCount}</span>` : ""}
|
|
1608
|
+
${stepCount ? `<span class="rc-step-count">${escapeHtml(stepCount)}</span>` : ""}
|
|
1560
1609
|
</div>
|
|
1561
1610
|
|
|
1562
1611
|
<div class="rc-tokens" ${showTokens ? "" : "style=\"display:none\""}>
|
|
@@ -1565,7 +1614,7 @@ function activeCardHtml(run) {
|
|
|
1565
1614
|
</div>
|
|
1566
1615
|
|
|
1567
1616
|
<div class="rc-foot">
|
|
1568
|
-
<span class="rc-runid">id ${run.runId.slice(0, 8)}</span>
|
|
1617
|
+
<span class="rc-runid">id ${escapeHtml(String(run.runId).slice(0, 8))}</span>
|
|
1569
1618
|
<span class="sep">·</span>
|
|
1570
1619
|
<span>${escapeHtml(safeStr(run.tool) || "")}</span>
|
|
1571
1620
|
</div>
|
|
@@ -1708,8 +1757,11 @@ function rowHtml(evt, idx, prev) {
|
|
|
1708
1757
|
msg = `<span class="ident">${escapeHtml(badge.toLowerCase())}</span>`;
|
|
1709
1758
|
}
|
|
1710
1759
|
const sourcePill = renderSourcePill(evt.payload?.source);
|
|
1760
|
+
// SEC-14-01: evt.type and evt.runId cross publisher boundary → escape.
|
|
1761
|
+
// msg/tokenChip/sourcePill are pre-built HTML literals where each interpolation
|
|
1762
|
+
// already used escapeHtml() — safe by construction.
|
|
1711
1763
|
return `
|
|
1712
|
-
<div class="tl-row" data-type="${evt.type}" data-ok="${ok}" data-grouped="${grouped}">
|
|
1764
|
+
<div class="tl-row" data-type="${escapeHtml(evt.type)}" data-ok="${ok}" data-grouped="${grouped}">
|
|
1713
1765
|
<div class="tl-time" title="${time}">${rel}</div>
|
|
1714
1766
|
<div class="tl-rail"><div class="tl-node"></div></div>
|
|
1715
1767
|
<div class="tl-content">
|
|
@@ -1717,7 +1769,7 @@ function rowHtml(evt, idx, prev) {
|
|
|
1717
1769
|
<span class="tl-msg">${msg}</span>
|
|
1718
1770
|
${tokenChip}
|
|
1719
1771
|
${sourcePill}
|
|
1720
|
-
${evt.runId ? `<span class="tl-runid">${evt.runId.slice(0,6)}</span>` : ""}
|
|
1772
|
+
${evt.runId ? `<span class="tl-runid">${escapeHtml(String(evt.runId).slice(0,6))}</span>` : ""}
|
|
1721
1773
|
</div>
|
|
1722
1774
|
</div>
|
|
1723
1775
|
`;
|
|
@@ -1917,7 +1969,7 @@ function applyConnState(s) {
|
|
|
1917
1969
|
|
|
1918
1970
|
async function hydrateFromState() {
|
|
1919
1971
|
try {
|
|
1920
|
-
const res = await
|
|
1972
|
+
const res = await authedFetch("/state", { credentials: "omit" });
|
|
1921
1973
|
if (!res.ok) return;
|
|
1922
1974
|
const j = await res.json();
|
|
1923
1975
|
if (j.port && document.querySelector(".brand-sub")) {
|
|
@@ -1938,7 +1990,7 @@ function connectRealSource() {
|
|
|
1938
1990
|
applyConnState("connecting");
|
|
1939
1991
|
if (evtSource) try { evtSource.close(); } catch (_) {}
|
|
1940
1992
|
|
|
1941
|
-
evtSource = new EventSource("/events");
|
|
1993
|
+
evtSource = new EventSource(authedEventSourceUrl("/events"));
|
|
1942
1994
|
|
|
1943
1995
|
evtSource.addEventListener("open", () => {
|
|
1944
1996
|
lastConnectedAt = Date.now();
|