feat(console): skill editor onto the xl shelf — create/edit merge, lock in the head

The last legacy modal pair (create-template + edit-template, ~430 lines
per mode) collapses into one pane-scoped 920px shelf: a hidden skl-id
decides POST vs PUT, the duplicated ctm-/etm- field sets merge into one
skl-/sklc- set, and the skill-spec two-column grid transplants whole into
the scrolling body (content-area rule re-scoped under .sh-body so the
shelf's font:inherit/min-height cadence doesn't flatten it; the mobile
breakpoint becomes a pane container query to match the shelf's own
bottom-sheet degradation).

Everything judgment-bearing carries over: paste-to-parse (now cancelled
via the shelf's onClose so Escape/scrim dismissals abort the inflight
parse too), live {{variable}} detection (re-dressed as match-strip chips
under the textarea, count mirrored into the foot meta when provenance
isn't occupying it), pending-resource rows in create, server-backed
resources + security scan + re-scan in edit, and the runtime-config
field set that stays editable on readonly skills (must keep matching
SKILL_RUNTIME_CONFIG_FIELDS). The readonly lock affordance moves into
the head strip left of the designation plate as a ghost icon button;
origin/locked provenance renders in the foot meta lane (installed/
customized chip + source URL + 'locked — unlock to edit'); the unlock
confirm stacks above the shelf via the native top layer and the
post-unlock re-render mutates the open shelf in place. Progressive
disclosure keeps its <details> semantics on rawhatch chrome, with the
shared-DOM state leaks (disabled spec fields, expanded details) re-armed
on every create open.

Mode-exclusive blocks keep their ctm-/etm- ids (pending vs server
resources, scan) — only true duplicates merged. Inline onclick wiring
moves to a one-shot _skillShelfWire; submits go busy via the shelf LED
lock. The legacy overlay markup and the .skill-lock-btn / .skill-vars-*
rules are deleted; trap machinery teardown follows separately.

Livepass-verified (stubbed authFetch, headless Chrome): create, edit
populated, locked view (disabled spec + editable runtime + scan +
readonly resources), unlock confirm stacked over the shelf, paste
auto-fill, variable chips, pending-resource add/remove.
This commit is contained in:
Patrick Buckley
2026-06-10 00:12:09 -07:00
parent 14f159ccdf
commit ecef600c0b
3 changed files with 948 additions and 1289 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+19 -89
View File
@@ -1566,10 +1566,10 @@ h3.skill-spec-heading {
flex-direction: column;
}
/* Chained `textarea.` so the rule beats `.admin-modal textarea` (0,1,1) on
source order — without that bump, min-height: 220px loses to the modal's
default min-height: 40px and the spec content textarea renders short. */
textarea.skill-content-area {
/* Scoped under `.sh-body` so the rule beats hatch.css's `.sh-body textarea`
(0,1,1, later in source) — without that bump, the shelf's `font: inherit`
+ min-height: 64px would flatten the mono face and the 220px floor. */
.sh-body textarea.skill-content-area {
flex: 1;
min-height: 220px;
font-family: var(--font-mono);
@@ -1577,29 +1577,6 @@ textarea.skill-content-area {
line-height: 1.65;
}
.skill-vars-row {
display: flex;
align-items: center;
gap: 8px;
margin-top: 8px;
min-height: 18px;
}
.skill-vars-label {
font-family: var(--font-ui);
font-size: 10px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--fg-dim);
white-space: nowrap;
flex-shrink: 0;
}
.skill-vars-display {
font-size: 11px;
}
.skill-config-grid {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
@@ -1610,7 +1587,8 @@ textarea.skill-content-area {
min-width: 0;
}
/* Origin badge — shown for remotely installed (readonly) skills */
/* Origin badge — provenance chip in the skill shelf's foot meta lane
(installed/customized skills). Sized to the 11px foot strip. */
.skill-origin-badge {
display: inline-flex;
align-items: center;
@@ -1624,8 +1602,7 @@ textarea.skill-content-area {
background: rgba(103, 232, 249, 0.07);
border: 1px solid rgba(103, 232, 249, 0.18);
border-radius: var(--radius-sm);
padding: 5px 10px;
margin-bottom: 14px;
padding: 2px 7px;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
@@ -1637,7 +1614,17 @@ textarea.skill-content-area {
flex-shrink: 0;
}
@media (max-width: 700px) {
/* Head lock affordance on the skill shelf — the sh-x ghost recipe minus its
right-edge margin compensation (the lock sits mid-strip, left of the
designation plate). Text-variant keeps the glyph monochrome. */
#skill-shelf .skl-lock {
margin: -4px 0;
font-variant-emoji: text;
}
/* Narrow pane (mobile OR a tight split): single column, matching the
shelf's own bottom-sheet container breakpoint in hatch.css. */
@container pane (max-width: 700px) {
.skill-spec-body {
grid-template-columns: 1fr;
}
@@ -1654,16 +1641,6 @@ textarea.skill-content-area {
.skill-config-grid {
grid-template-columns: 1fr 1fr;
}
/* Touch target: 44×44 minimum on mobile (WCAG 2.5.5 / Apple HIG). */
.skill-lock-btn {
width: 44px;
height: 44px;
top: 8px;
right: 8px;
}
.admin-modal-skill > h2 {
padding-right: 56px;
}
}
.modal-buttons {
@@ -1726,52 +1703,6 @@ textarea.skill-content-area {
cursor: not-allowed;
filter: none;
}
/* Lock-icon affordance in the top-right of an installed (readonly) skill's
edit modal — clicking detaches the skill from upstream so spec fields
become editable. Reserved for the modal it lives in; not a generic
button class. */
.skill-lock-btn {
position: absolute;
/* top: 18px (not 14px) so the button drops below the modal's accent-line
decoration's visual zone instead of competing with it horizontally. */
top: 18px;
right: 14px;
width: 32px;
height: 32px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
background: transparent;
color: var(--fg);
border: 1px solid var(--border-strong);
border-radius: var(--radius-sm);
font-size: 14px;
/* Render the lock glyph as text where supported (keeps the monochrome
instrument-panel aesthetic instead of a coloured emoji). Browsers
that don't support font-variant-emoji fall back gracefully. */
font-variant-emoji: text;
cursor: pointer;
transition:
background 0.15s,
border-color 0.15s;
z-index: 2;
}
.skill-lock-btn:hover {
background: var(--bg-highlight);
border-color: var(--accent);
color: var(--accent);
}
.skill-lock-btn:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
.skill-lock-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
pointer-events: none;
}
#create-template-overlay,
#edit-template-overlay {
position: fixed;
@@ -3776,8 +3707,7 @@ textarea.skill-content-area {
}
.admin-action-btn,
.modal-cancel,
.modal-submit,
.skill-lock-btn {
.modal-submit {
transition: none;
}
.admin-modal input,