@tekyzinc/gsd-t 2.73.22 → 2.73.24
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,22 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GSD-T are documented here. Updated with each release.
|
|
4
4
|
|
|
5
|
+
## [2.73.24] - 2026-04-09
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Remove element button** — hover over any component in the list to reveal a red × button. Clicking it excludes the element from review and auto-comments "EXCLUDED — not in Figma design". Excluded count shown in submit stats.
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
- **Comment validation removed** — all comments are now accepted (questions, exclusions, feedback). The "don't suggest specific changes" popup no longer blocks submission.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- **Submit stats** show removed count alongside changed/commented.
|
|
15
|
+
|
|
16
|
+
## [2.73.23] - 2026-04-09
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- **Container props auto-redirect to parent** — setting `gap`, `borderRadius`, or `overflow` on a bar segment (child) now auto-targets the parent flex/grid container. Previously only worked when the container itself was selected.
|
|
20
|
+
|
|
5
21
|
## [2.73.22] - 2026-04-09
|
|
6
22
|
|
|
7
23
|
### 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.24",
|
|
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",
|
|
@@ -712,8 +712,22 @@
|
|
|
712
712
|
const propagate = msg.propagate !== false; // default true
|
|
713
713
|
let propagatedCount = 0;
|
|
714
714
|
|
|
715
|
-
//
|
|
716
|
-
|
|
715
|
+
// Container-only props: if applied to a non-container child, redirect to parent
|
|
716
|
+
const containerOnlyProps = new Set(["gap", "row-gap", "column-gap", "border-radius"]);
|
|
717
|
+
let targetEl = lockedEl;
|
|
718
|
+
if (containerOnlyProps.has(cssName)) {
|
|
719
|
+
const elStyle = getComputedStyle(lockedEl);
|
|
720
|
+
const isContainer = elStyle.display === "flex" || elStyle.display === "inline-flex" || elStyle.display === "grid";
|
|
721
|
+
if (!isContainer && lockedEl.parentElement) {
|
|
722
|
+
const parentStyle = getComputedStyle(lockedEl.parentElement);
|
|
723
|
+
if (parentStyle.display === "flex" || parentStyle.display === "inline-flex" || parentStyle.display === "grid") {
|
|
724
|
+
targetEl = lockedEl.parentElement;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
// Apply to target element (may be parent for container-only props)
|
|
730
|
+
targetEl.style.setProperty(cssName, msg.value, "important");
|
|
717
731
|
|
|
718
732
|
// Typography props cascade to descendants
|
|
719
733
|
const inheritProps = new Set(["font-size", "font-weight", "font-family", "line-height",
|
|
@@ -792,22 +806,24 @@
|
|
|
792
806
|
} else if (tag === "div" && parent) {
|
|
793
807
|
const elStyle = getComputedStyle(lockedEl);
|
|
794
808
|
const parentStyle = getComputedStyle(parent);
|
|
795
|
-
const layoutProps = new Set(["gap", "row-gap", "column-gap"]);
|
|
796
809
|
|
|
797
810
|
// Props that propagate across sibling containers (all bar columns)
|
|
798
811
|
const containerProps = new Set(["gap", "row-gap", "column-gap", "border-radius", "overflow"]);
|
|
799
812
|
|
|
800
813
|
if (containerProps.has(cssName)) {
|
|
801
|
-
|
|
802
|
-
|
|
814
|
+
// Use targetEl (may be parent if redirected) for container propagation
|
|
815
|
+
const containerEl = targetEl;
|
|
816
|
+
const containerParent = containerEl.parentElement;
|
|
817
|
+
const containerDisplay = getComputedStyle(containerEl).display;
|
|
818
|
+
if (containerParent && (containerDisplay === "flex" || containerDisplay === "inline-flex" || containerDisplay === "grid")) {
|
|
803
819
|
// Auto-set overflow:hidden when border-radius is applied to a container
|
|
804
820
|
if (cssName === "border-radius" && msg.value && msg.value !== "0px" && msg.value !== "0") {
|
|
805
|
-
|
|
821
|
+
containerEl.style.setProperty("overflow", "hidden", "important");
|
|
806
822
|
}
|
|
807
|
-
for (const sib of
|
|
808
|
-
if (sib ===
|
|
823
|
+
for (const sib of containerParent.children) {
|
|
824
|
+
if (sib === containerEl || sib.tagName !== "DIV") continue;
|
|
809
825
|
const sibStyle = getComputedStyle(sib);
|
|
810
|
-
if (sibStyle.display ===
|
|
826
|
+
if (sibStyle.display === containerDisplay) {
|
|
811
827
|
sib.style.setProperty(cssName, msg.value, "important");
|
|
812
828
|
if (cssName === "border-radius" && msg.value && msg.value !== "0px" && msg.value !== "0") {
|
|
813
829
|
sib.style.setProperty("overflow", "hidden", "important");
|
|
@@ -195,6 +195,12 @@
|
|
|
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; color: #ef4444; font-size: 16px;
|
|
200
|
+
cursor: pointer; padding: 0 4px; line-height: 1; opacity: 0.6;
|
|
201
|
+
}
|
|
202
|
+
.remove-btn:hover { opacity: 1; }
|
|
203
|
+
.component-item:hover .remove-btn { display: block; }
|
|
198
204
|
|
|
199
205
|
/* ── Submit bar ─────────────────────────────────── */
|
|
200
206
|
.submit-bar {
|
|
@@ -801,6 +807,7 @@
|
|
|
801
807
|
let inspectActive = false;
|
|
802
808
|
const changes = new Map(); // componentId → [{path, property, oldValue, newValue}]
|
|
803
809
|
const comments = new Map(); // componentId → string
|
|
810
|
+
const excluded = new Set(); // componentIds removed from review
|
|
804
811
|
let currentElementPath = null;
|
|
805
812
|
let currentStyles = null;
|
|
806
813
|
|
|
@@ -952,14 +959,28 @@
|
|
|
952
959
|
statusClass = "rejected";
|
|
953
960
|
}
|
|
954
961
|
|
|
962
|
+
if (excluded.has(item.id)) return; // skip excluded elements
|
|
963
|
+
|
|
955
964
|
const div = document.createElement("div");
|
|
956
965
|
div.className = `component-item${idx === selectedIdx ? " selected" : ""}`;
|
|
957
966
|
div.innerHTML = `
|
|
958
967
|
<div class="component-status ${statusClass}"></div>
|
|
959
968
|
<div class="component-name">${item.name || item.id}</div>
|
|
960
969
|
<div class="component-type">${item.type || ""}</div>
|
|
970
|
+
<button class="remove-btn" title="Remove from review">×</button>
|
|
961
971
|
`;
|
|
962
|
-
div.addEventListener("click", () => selectComponent(idx));
|
|
972
|
+
div.querySelector(".component-name").addEventListener("click", () => selectComponent(idx));
|
|
973
|
+
div.querySelector(".component-status").addEventListener("click", () => selectComponent(idx));
|
|
974
|
+
div.querySelector(".remove-btn").addEventListener("click", (e) => {
|
|
975
|
+
e.stopPropagation();
|
|
976
|
+
excluded.add(item.id);
|
|
977
|
+
comments.set(item.id, "EXCLUDED — not in Figma design");
|
|
978
|
+
if (selectedIdx === idx) {
|
|
979
|
+
selectedIdx = Math.min(idx, filteredQueue.filter(q => !excluded.has(q.id)).length - 1);
|
|
980
|
+
}
|
|
981
|
+
renderComponentList();
|
|
982
|
+
updateSubmitStats();
|
|
983
|
+
});
|
|
963
984
|
componentList.appendChild(div);
|
|
964
985
|
});
|
|
965
986
|
}
|
|
@@ -2110,21 +2131,20 @@
|
|
|
2110
2131
|
// ── Submit ────────────────────────────────────────
|
|
2111
2132
|
function updateSubmitStats() {
|
|
2112
2133
|
const total = queue.length;
|
|
2134
|
+
const excludedCount = excluded.size;
|
|
2113
2135
|
const changed = Array.from(changes.keys()).filter(id => (changes.get(id) || []).length > 0).length;
|
|
2114
|
-
const commented = comments.
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
submitAll.textContent = changed > 0 || commented > 0
|
|
2127
|
-
? `Submit (${changed} changes, ${commented} comments)`
|
|
2136
|
+
const commented = Array.from(comments.keys()).filter(id => !excluded.has(id)).length;
|
|
2137
|
+
|
|
2138
|
+
const parts = [];
|
|
2139
|
+
if (changed > 0) parts.push(`<span><span class="component-status changed" style="display:inline-block"></span> ${changed} changed</span>`);
|
|
2140
|
+
if (commented > 0) parts.push(`<span><span class="component-status rejected" style="display:inline-block"></span> ${commented} commented</span>`);
|
|
2141
|
+
if (excludedCount > 0) parts.push(`<span style="color:#ef4444">${excludedCount} removed</span>`);
|
|
2142
|
+
parts.push(`<span style="color:var(--text-dim)">${total - excludedCount} of ${total}</span>`);
|
|
2143
|
+
submitStats.innerHTML = parts.join(" ");
|
|
2144
|
+
|
|
2145
|
+
const actionCount = changed + commented + excludedCount;
|
|
2146
|
+
submitAll.textContent = actionCount > 0
|
|
2147
|
+
? `Submit (${changed} changes, ${commented} comments, ${excludedCount} removed)`
|
|
2128
2148
|
: "Submit — Approve All";
|
|
2129
2149
|
}
|
|
2130
2150
|
|
|
@@ -2136,28 +2156,7 @@
|
|
|
2136
2156
|
else comments.delete(filteredQueue[selectedIdx].id);
|
|
2137
2157
|
}
|
|
2138
2158
|
|
|
2139
|
-
//
|
|
2140
|
-
const actionWords = /change|make|set|move|add|remove|reduce|increase|fix|use|switch|replace|adjust|align|center|should be|needs to|too |bigger|smaller|wider|narrower|thicker|thinner|lighter|darker|bolder|px|rem|%|#[0-9a-f]/i;
|
|
2141
|
-
const docComments = [];
|
|
2142
|
-
for (const [compId, comment] of comments) {
|
|
2143
|
-
if (!actionWords.test(comment)) {
|
|
2144
|
-
const item = queue.find(q => q.id === compId);
|
|
2145
|
-
docComments.push(item ? item.name : compId);
|
|
2146
|
-
}
|
|
2147
|
-
}
|
|
2148
|
-
if (docComments.length > 0) {
|
|
2149
|
-
const proceed = confirm(
|
|
2150
|
-
"These comments don't suggest specific changes:\n\n" +
|
|
2151
|
-
docComments.map(n => " \u2022 " + n).join("\n") +
|
|
2152
|
-
"\n\nComments should describe what to change, e.g.:\n" +
|
|
2153
|
-
' "make padding 8px"\n "use darker blue"\n "reduce gap between title and chart"\n\n' +
|
|
2154
|
-
"Non-actionable comments will be discarded.\n\nSubmit anyway?"
|
|
2155
|
-
);
|
|
2156
|
-
if (!proceed) return;
|
|
2157
|
-
for (const [compId, comment] of comments) {
|
|
2158
|
-
if (!actionWords.test(comment)) comments.delete(compId);
|
|
2159
|
-
}
|
|
2160
|
-
}
|
|
2159
|
+
// All comments are accepted — questions, exclusions, and change requests alike
|
|
2161
2160
|
|
|
2162
2161
|
// Build feedback: each element gets its changes and comments
|
|
2163
2162
|
const feedback = queue.map(item => ({
|