@tekyzinc/gsd-t 2.73.24 → 2.73.25
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
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GSD-T are documented here. Updated with each release.
|
|
4
4
|
|
|
5
|
+
## [2.73.25] - 2026-04-09
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Undo remove** — excluded elements show as struck-through with a green ↩ restore button instead of disappearing. Click to undo before submitting.
|
|
9
|
+
- **Contract deletion on submit** — when excluded elements are submitted, their contract files and source files are deleted from the project. The `/review/api/exclude` endpoint handles cleanup.
|
|
10
|
+
|
|
5
11
|
## [2.73.24] - 2026-04-09
|
|
6
12
|
|
|
7
13
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tekyzinc/gsd-t",
|
|
3
|
-
"version": "2.73.
|
|
3
|
+
"version": "2.73.25",
|
|
4
4
|
"description": "GSD-T: Contract-Driven Development for Claude Code — 56 slash commands with headless CI/CD mode, graph-powered code analysis, real-time agent dashboard, execution intelligence, task telemetry, doc-ripple enforcement, backlog management, impact analysis, test sync, milestone archival, and PRD generation",
|
|
5
5
|
"author": "Tekyz, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -620,6 +620,48 @@ const server = http.createServer((req, res) => {
|
|
|
620
620
|
return;
|
|
621
621
|
}
|
|
622
622
|
|
|
623
|
+
if (pathname === "/review/api/exclude" && req.method === "POST") {
|
|
624
|
+
// Remove excluded elements: delete contract files and remove from queue
|
|
625
|
+
let body = "";
|
|
626
|
+
req.on("data", (chunk) => { body += chunk; });
|
|
627
|
+
req.on("end", () => {
|
|
628
|
+
try {
|
|
629
|
+
const { excludedIds } = JSON.parse(body);
|
|
630
|
+
const removed = [];
|
|
631
|
+
for (const id of excludedIds) {
|
|
632
|
+
const item = reviewQueue.find(q => q.id === id);
|
|
633
|
+
if (!item || !item.sourcePath) continue;
|
|
634
|
+
const match = item.sourcePath.match(/src\/components\/(\w+)\/(\w+)\.vue$/);
|
|
635
|
+
if (!match) continue;
|
|
636
|
+
const [, tier, name] = match;
|
|
637
|
+
const kebab = name.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
638
|
+
const contractPath = path.join(PROJECT_DIR, ".gsd-t", "contracts", "design", tier, `${kebab}.contract.md`);
|
|
639
|
+
if (fs.existsSync(contractPath)) {
|
|
640
|
+
fs.unlinkSync(contractPath);
|
|
641
|
+
removed.push({ id, contract: contractPath });
|
|
642
|
+
}
|
|
643
|
+
// Remove source file too
|
|
644
|
+
const srcPath = path.join(PROJECT_DIR, item.sourcePath);
|
|
645
|
+
if (fs.existsSync(srcPath)) {
|
|
646
|
+
fs.unlinkSync(srcPath);
|
|
647
|
+
removed.push({ id, source: srcPath });
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
// Remove from queue
|
|
651
|
+
for (let i = reviewQueue.length - 1; i >= 0; i--) {
|
|
652
|
+
if (excludedIds.includes(reviewQueue[i].id)) reviewQueue.splice(i, 1);
|
|
653
|
+
}
|
|
654
|
+
broadcast("queue-update", reviewQueue);
|
|
655
|
+
res.writeHead(200, { "Content-Type": "application/json", "Access-Control-Allow-Origin": "*" });
|
|
656
|
+
res.end(JSON.stringify({ ok: true, removed }));
|
|
657
|
+
} catch (err) {
|
|
658
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
659
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
|
|
623
665
|
if (pathname === "/review/api/write-source" && req.method === "POST") {
|
|
624
666
|
// Apply CSS property changes back to source files
|
|
625
667
|
let body = "";
|
|
@@ -195,11 +195,13 @@
|
|
|
195
195
|
|
|
196
196
|
.component-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
197
197
|
.component-type { font-size: 10px; color: #94a3b8; }
|
|
198
|
-
.remove-btn {
|
|
199
|
-
display: none; background: none; border: none;
|
|
198
|
+
.remove-btn, .undo-remove-btn {
|
|
199
|
+
display: none; background: none; border: none; font-size: 14px;
|
|
200
200
|
cursor: pointer; padding: 0 4px; line-height: 1; opacity: 0.6;
|
|
201
201
|
}
|
|
202
|
-
.remove-btn
|
|
202
|
+
.remove-btn { color: #ef4444; }
|
|
203
|
+
.undo-remove-btn { color: #22c55e; display: block; }
|
|
204
|
+
.remove-btn:hover, .undo-remove-btn:hover { opacity: 1; }
|
|
203
205
|
.component-item:hover .remove-btn { display: block; }
|
|
204
206
|
|
|
205
207
|
/* ── Submit bar ─────────────────────────────────── */
|
|
@@ -959,28 +961,45 @@
|
|
|
959
961
|
statusClass = "rejected";
|
|
960
962
|
}
|
|
961
963
|
|
|
962
|
-
|
|
964
|
+
const isExcluded = excluded.has(item.id);
|
|
963
965
|
|
|
964
966
|
const div = document.createElement("div");
|
|
965
|
-
div.className = `component-item${idx === selectedIdx ? " selected" : ""}`;
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
967
|
+
div.className = `component-item${idx === selectedIdx ? " selected" : ""}${isExcluded ? " excluded" : ""}`;
|
|
968
|
+
|
|
969
|
+
if (isExcluded) {
|
|
970
|
+
div.innerHTML = `
|
|
971
|
+
<div class="component-status" style="background:#ef4444"></div>
|
|
972
|
+
<div class="component-name" style="text-decoration:line-through;opacity:0.5">${item.name || item.id}</div>
|
|
973
|
+
<button class="undo-remove-btn" title="Restore element">↩</button>
|
|
974
|
+
`;
|
|
975
|
+
div.querySelector(".undo-remove-btn").addEventListener("click", (e) => {
|
|
976
|
+
e.stopPropagation();
|
|
977
|
+
excluded.delete(item.id);
|
|
978
|
+
comments.delete(item.id);
|
|
979
|
+
renderComponentList();
|
|
980
|
+
updateSubmitStats();
|
|
981
|
+
});
|
|
982
|
+
} else {
|
|
983
|
+
div.innerHTML = `
|
|
984
|
+
<div class="component-status ${statusClass}"></div>
|
|
985
|
+
<div class="component-name">${item.name || item.id}</div>
|
|
986
|
+
<div class="component-type">${item.type || ""}</div>
|
|
987
|
+
<button class="remove-btn" title="Remove from review">×</button>
|
|
988
|
+
`;
|
|
989
|
+
div.querySelector(".component-name").addEventListener("click", () => selectComponent(idx));
|
|
990
|
+
div.querySelector(".component-status").addEventListener("click", () => selectComponent(idx));
|
|
991
|
+
div.querySelector(".remove-btn").addEventListener("click", (e) => {
|
|
992
|
+
e.stopPropagation();
|
|
993
|
+
excluded.add(item.id);
|
|
994
|
+
comments.set(item.id, "EXCLUDED — not in Figma design");
|
|
995
|
+
if (selectedIdx === idx) {
|
|
996
|
+
const remaining = filteredQueue.filter(q => !excluded.has(q.id));
|
|
997
|
+
selectedIdx = remaining.length > 0 ? filteredQueue.indexOf(remaining[0]) : -1;
|
|
998
|
+
}
|
|
999
|
+
renderComponentList();
|
|
1000
|
+
updateSubmitStats();
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
984
1003
|
componentList.appendChild(div);
|
|
985
1004
|
});
|
|
986
1005
|
}
|
|
@@ -2192,6 +2211,15 @@
|
|
|
2192
2211
|
body: JSON.stringify({ changes: allChanges }),
|
|
2193
2212
|
});
|
|
2194
2213
|
}
|
|
2214
|
+
|
|
2215
|
+
// Delete contracts and source files for excluded elements
|
|
2216
|
+
if (excluded.size > 0) {
|
|
2217
|
+
await fetch("/review/api/exclude", {
|
|
2218
|
+
method: "POST",
|
|
2219
|
+
headers: { "Content-Type": "application/json" },
|
|
2220
|
+
body: JSON.stringify({ excludedIds: Array.from(excluded) }),
|
|
2221
|
+
});
|
|
2222
|
+
}
|
|
2195
2223
|
}
|
|
2196
2224
|
} catch (err) {
|
|
2197
2225
|
submitAll.textContent = "Error — retry";
|