@zigrivers/scaffold 3.30.0 → 3.31.1
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/content/guides/AUTHORING.md +8 -5
- package/content/guides/cli/index.html +367 -14
- package/content/guides/concepts/index.html +367 -14
- package/content/guides/dashboard/index.html +367 -14
- package/content/guides/index.html +368 -15
- package/content/guides/install/index.html +373 -20
- package/content/guides/install/index.md +6 -6
- package/content/guides/knowledge/index.html +367 -14
- package/content/guides/knowledge-freshness/index.html +369 -16
- package/content/guides/knowledge-freshness/index.md +2 -2
- package/content/guides/mmr/index.html +373 -20
- package/content/guides/multi-agent/index.html +369 -16
- package/content/guides/multi-agent/index.md +2 -2
- package/content/guides/observability/index.html +367 -14
- package/content/guides/pipeline/index.html +378 -37
- package/content/guides/pipeline/index.md +8 -8
- package/content/guides/review-workflow/index.html +367 -14
- package/dist/cli/commands/info.test.js +3 -0
- package/dist/cli/commands/info.test.js.map +1 -1
- package/dist/cli/commands/list.test.js +6 -0
- package/dist/cli/commands/list.test.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +38 -4
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/commands/status.test.js +66 -2
- package/dist/cli/commands/status.test.js.map +1 -1
- package/dist/e2e/commands.test.js +3 -0
- package/dist/e2e/commands.test.js.map +1 -1
- package/dist/e2e/knowledge.test.js +5 -0
- package/dist/e2e/knowledge.test.js.map +1 -1
- package/dist/guides/build.d.ts +1 -1
- package/dist/guides/build.d.ts.map +1 -1
- package/dist/guides/build.js +14 -7
- package/dist/guides/build.js.map +1 -1
- package/dist/guides/build.test.js +39 -0
- package/dist/guides/build.test.js.map +1 -1
- package/dist/guides/chrome.d.ts.map +1 -1
- package/dist/guides/chrome.js +83 -12
- package/dist/guides/chrome.js.map +1 -1
- package/dist/guides/cli-guides.test.js +3 -0
- package/dist/guides/cli-guides.test.js.map +1 -1
- package/dist/guides/dashboard-theme.css +8 -0
- package/dist/guides/directives-tabs.test.js +47 -0
- package/dist/guides/directives-tabs.test.js.map +1 -1
- package/dist/guides/directives.d.ts.map +1 -1
- package/dist/guides/directives.js +14 -0
- package/dist/guides/directives.js.map +1 -1
- package/dist/guides/guides.css +268 -0
- package/dist/guides/index-page.d.ts.map +1 -1
- package/dist/guides/index-page.js +41 -8
- package/dist/guides/index-page.js.map +1 -1
- package/dist/guides/sanitize.d.ts.map +1 -1
- package/dist/guides/sanitize.js +4 -0
- package/dist/guides/sanitize.js.map +1 -1
- package/dist/guides/template.d.ts.map +1 -1
- package/dist/guides/template.js +7 -2
- package/dist/guides/template.js.map +1 -1
- package/dist/state/ensure-v3-migration.d.ts.map +1 -1
- package/dist/state/ensure-v3-migration.js +4 -2
- package/dist/state/ensure-v3-migration.js.map +1 -1
- package/dist/utils/fs.d.ts +6 -30
- package/dist/utils/fs.d.ts.map +1 -1
- package/dist/utils/fs.js +66 -58
- package/dist/utils/fs.js.map +1 -1
- package/dist/utils/fs.test.js +53 -6
- package/dist/utils/fs.test.js.map +1 -1
- package/dist/validation/index.test.js +3 -0
- package/dist/validation/index.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -48,9 +48,13 @@
|
|
|
48
48
|
--yellow: #d97706;
|
|
49
49
|
--yellow-bg: #fffbeb;
|
|
50
50
|
--yellow-border:#fde68a;
|
|
51
|
+
--red: #dc2626;
|
|
52
|
+
--red-bg: #fef2f2;
|
|
53
|
+
--red-border: #fecaca;
|
|
51
54
|
--gray: #9ca3af;
|
|
52
55
|
--gray-bg: #f3f4f6;
|
|
53
56
|
--gray-border: #e5e7eb;
|
|
57
|
+
--scrim: rgba(15, 17, 23, 0.45);
|
|
54
58
|
|
|
55
59
|
/* Semantic: Next Banner */
|
|
56
60
|
--next-bg: #eef2ff;
|
|
@@ -133,9 +137,13 @@
|
|
|
133
137
|
--yellow: #fbbf24;
|
|
134
138
|
--yellow-bg: rgba(120, 53, 15, 0.25);
|
|
135
139
|
--yellow-border:rgba(251, 191, 36, 0.20);
|
|
140
|
+
--red: #f87171;
|
|
141
|
+
--red-bg: rgba(127, 29, 29, 0.25);
|
|
142
|
+
--red-border: rgba(248, 113, 113, 0.22);
|
|
136
143
|
--gray: #6b7294;
|
|
137
144
|
--gray-bg: #252940;
|
|
138
145
|
--gray-border: #363c58;
|
|
146
|
+
--scrim: rgba(0, 0, 0, 0.6);
|
|
139
147
|
|
|
140
148
|
/* Semantic: Next Banner */
|
|
141
149
|
--next-bg: rgba(30, 27, 75, 0.50);
|
|
@@ -1078,17 +1086,290 @@ figure.mermaid svg .marker {
|
|
|
1078
1086
|
}
|
|
1079
1087
|
figure.mermaid svg .edgeLabel,
|
|
1080
1088
|
figure.mermaid svg .edgeLabel text { fill: var(--text-muted); color: var(--text-muted); }
|
|
1089
|
+
|
|
1090
|
+
/* ============================================================================
|
|
1091
|
+
* guides.css — component + layout styles for `scaffold guides` reference pages.
|
|
1092
|
+
*
|
|
1093
|
+
* Pairs with lib/dashboard-theme.css (the token source) and src/guides/chrome.ts
|
|
1094
|
+
* (the behavior). Styles the guide CHROME (.topbar, .layout, .rail, nav.toc,
|
|
1095
|
+
* .content) and the markdown DIRECTIVES (callouts, sev chips, filter-tables,
|
|
1096
|
+
* charts, tabs, citations) plus base prose typography.
|
|
1097
|
+
*
|
|
1098
|
+
* DESIGN SYSTEM: all COLORS come from dashboard-theme.css tokens, and spacing
|
|
1099
|
+
* uses the --sp-* scale wherever it maps. The few structural layout constants
|
|
1100
|
+
* (topbar height, rail/drawer width, chart label column, card min) are declared
|
|
1101
|
+
* as local custom properties below; a handful of sub-scale UI values (chip/bar
|
|
1102
|
+
* sizing, em-based inline-code padding) and the responsive breakpoint are
|
|
1103
|
+
* literal because no token expresses them. Both themes are covered because every
|
|
1104
|
+
* color is a token.
|
|
1105
|
+
* ==========================================================================*/
|
|
1106
|
+
|
|
1107
|
+
:root {
|
|
1108
|
+
--topbar-h: 52px; /* sticky topbar height; rail sticky offset keys off it */
|
|
1109
|
+
--rail-w: 260px; /* desktop TOC sidebar column */
|
|
1110
|
+
--drawer-w: 280px; /* mobile off-canvas TOC drawer */
|
|
1111
|
+
--card-min: 260px; /* index card min track width */
|
|
1112
|
+
--chart-label-w: 90px; /* chart row label column min */
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
/* ── Base / reset on top of the token base in dashboard-theme.css ─────────── */
|
|
1116
|
+
.content a { color: var(--accent); text-decoration: none; }
|
|
1117
|
+
.content a:hover { text-decoration: underline; }
|
|
1118
|
+
.content strong { font-weight: var(--fw-semi); }
|
|
1119
|
+
.content hr { border: 0; border-top: 1px solid var(--border-light); margin: var(--sp-6) 0; }
|
|
1120
|
+
|
|
1121
|
+
/* Consistent keyboard focus for every interactive control (a11y). */
|
|
1122
|
+
.topbar button:focus-visible,
|
|
1123
|
+
.copy-btn:focus-visible,
|
|
1124
|
+
.tab-btn:focus-visible,
|
|
1125
|
+
.filter-input:focus-visible,
|
|
1126
|
+
nav.toc a:focus-visible,
|
|
1127
|
+
.guide-card:focus-visible,
|
|
1128
|
+
.content a:focus-visible {
|
|
1129
|
+
outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-sm);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
/* ── Topbar ────────────────────────────────────────────────────────────────*/
|
|
1133
|
+
.topbar {
|
|
1134
|
+
position: sticky; top: 0; z-index: 60; height: var(--topbar-h);
|
|
1135
|
+
display: flex; align-items: center; gap: var(--sp-3);
|
|
1136
|
+
padding: 0 var(--page-pad);
|
|
1137
|
+
background: var(--bg-card); border-bottom: 1px solid var(--border);
|
|
1138
|
+
}
|
|
1139
|
+
.topbar h1 {
|
|
1140
|
+
flex: 1; min-width: 0; margin: 0;
|
|
1141
|
+
font-size: var(--text-lg); font-weight: var(--fw-bold);
|
|
1142
|
+
letter-spacing: var(--ls-tight);
|
|
1143
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
1144
|
+
}
|
|
1145
|
+
.topbar button {
|
|
1146
|
+
background: var(--bg-card); border: 1px solid var(--border); color: var(--text);
|
|
1147
|
+
border-radius: var(--radius-sm); padding: var(--sp-1) var(--sp-3); font-size: var(--text-base);
|
|
1148
|
+
line-height: 1; cursor: pointer; font-family: inherit;
|
|
1149
|
+
}
|
|
1150
|
+
.topbar button:hover { background: var(--bg-hover); border-color: var(--accent); }
|
|
1151
|
+
.nav-toggle { display: none; }
|
|
1152
|
+
|
|
1153
|
+
/* ── Layout: sticky sidebar TOC + reading-width content ──────────────────── */
|
|
1154
|
+
.layout {
|
|
1155
|
+
max-width: var(--max-w); margin: 0 auto;
|
|
1156
|
+
display: grid; grid-template-columns: var(--rail-w) minmax(0, 1fr);
|
|
1157
|
+
gap: var(--sp-8); padding: 0 var(--page-pad);
|
|
1158
|
+
}
|
|
1159
|
+
.rail {
|
|
1160
|
+
position: sticky; top: var(--topbar-h); align-self: start;
|
|
1161
|
+
height: calc(100vh - var(--topbar-h)); overflow-y: auto;
|
|
1162
|
+
padding: var(--sp-5) 0; border-right: 1px solid var(--border-light);
|
|
1163
|
+
}
|
|
1164
|
+
.content { min-width: 0; padding: var(--sp-6) 0 var(--sp-10); }
|
|
1165
|
+
|
|
1166
|
+
/* Backdrop behind the mobile drawer (toggled with the rail via chrome.ts). */
|
|
1167
|
+
.rail-backdrop { display: none; }
|
|
1168
|
+
/* In-drawer close button — hidden on desktop (the rail is a static sidebar). */
|
|
1169
|
+
.rail-close { display: none; }
|
|
1170
|
+
|
|
1171
|
+
/* ── Table of contents (scrollspy marks a.active) ────────────────────────── */
|
|
1172
|
+
nav.toc ul { list-style: none; margin: 0; padding: 0; }
|
|
1173
|
+
nav.toc li { margin: 0; }
|
|
1174
|
+
nav.toc a {
|
|
1175
|
+
display: block; padding: var(--sp-1) var(--sp-3); line-height: 1.35;
|
|
1176
|
+
color: var(--text-muted); font-size: var(--text-sm);
|
|
1177
|
+
text-decoration: none; border-left: 2px solid transparent;
|
|
1178
|
+
border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
|
|
1179
|
+
}
|
|
1180
|
+
nav.toc a:hover { color: var(--text); background: var(--bg-hover); }
|
|
1181
|
+
nav.toc a.active {
|
|
1182
|
+
color: var(--accent); border-left-color: var(--accent);
|
|
1183
|
+
background: var(--accent-glow); font-weight: var(--fw-medium);
|
|
1184
|
+
}
|
|
1185
|
+
nav.toc li.toc-3 a { padding-left: var(--sp-6); font-size: var(--text-xs); }
|
|
1186
|
+
|
|
1187
|
+
/* ── Prose typography ──────────────────────────────────────────────────────*/
|
|
1188
|
+
.content h2 {
|
|
1189
|
+
font-size: var(--text-xl); letter-spacing: var(--ls-tight);
|
|
1190
|
+
margin: var(--sp-8) 0 var(--sp-3); padding-bottom: var(--sp-2);
|
|
1191
|
+
border-bottom: 1px solid var(--border-light); scroll-margin-top: calc(var(--topbar-h) + var(--sp-3));
|
|
1192
|
+
}
|
|
1193
|
+
.content h3 {
|
|
1194
|
+
font-size: var(--text-lg); margin: var(--sp-5) 0 var(--sp-2);
|
|
1195
|
+
scroll-margin-top: calc(var(--topbar-h) + var(--sp-3));
|
|
1196
|
+
}
|
|
1197
|
+
.content p { margin: var(--sp-3) 0; line-height: var(--lh-relaxed); }
|
|
1198
|
+
.content ul, .content ol { margin: var(--sp-3) 0; padding-left: var(--sp-6); }
|
|
1199
|
+
.content li { margin: var(--sp-1) 0; line-height: var(--lh-relaxed); }
|
|
1200
|
+
.content blockquote {
|
|
1201
|
+
margin: var(--sp-3) 0; padding: var(--sp-1) var(--sp-4);
|
|
1202
|
+
border-left: 3px solid var(--border); color: var(--text-muted);
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
/* ── Inline code + code blocks (chrome.ts wraps <pre> in .code + .copy-btn) ──*/
|
|
1206
|
+
.content code {
|
|
1207
|
+
font-family: var(--font-mono); font-size: 0.85em;
|
|
1208
|
+
background: var(--bg-inset); padding: 0.12em 0.4em; border-radius: var(--radius-sm);
|
|
1209
|
+
}
|
|
1210
|
+
.content .code { position: relative; margin: var(--sp-3) 0; }
|
|
1211
|
+
.content .code pre {
|
|
1212
|
+
margin: 0; padding: var(--sp-3) var(--sp-4); overflow-x: auto;
|
|
1213
|
+
background: var(--bg-inset); border: 1px solid var(--border-light);
|
|
1214
|
+
border-radius: var(--radius-sm); font-family: var(--font-mono);
|
|
1215
|
+
font-size: var(--text-sm); line-height: var(--lh-relaxed);
|
|
1216
|
+
}
|
|
1217
|
+
.content .code pre code { background: none; padding: 0; font-size: inherit; }
|
|
1218
|
+
.copy-btn {
|
|
1219
|
+
position: absolute; top: var(--sp-1); right: var(--sp-1);
|
|
1220
|
+
background: var(--bg-card); border: 1px solid var(--border); color: var(--text-muted);
|
|
1221
|
+
border-radius: var(--radius-sm); font-size: var(--text-xs); padding: var(--sp-1) var(--sp-2);
|
|
1222
|
+
cursor: pointer; opacity: 0.85; font-family: inherit;
|
|
1223
|
+
}
|
|
1224
|
+
.copy-btn:hover { color: var(--accent); border-color: var(--accent); opacity: 1; }
|
|
1225
|
+
|
|
1226
|
+
/* ── Callouts ─ (border-color BEFORE border-left-color so the accent wins) ── */
|
|
1227
|
+
.callout {
|
|
1228
|
+
margin: var(--sp-4) 0; padding: var(--sp-3) var(--sp-4);
|
|
1229
|
+
border: 1px solid var(--border); border-left-width: 3px;
|
|
1230
|
+
border-radius: var(--radius-sm); background: var(--bg-card);
|
|
1231
|
+
}
|
|
1232
|
+
.callout > :first-child { margin-top: 0; }
|
|
1233
|
+
.callout > :last-child { margin-bottom: 0; }
|
|
1234
|
+
.callout-note, .callout-info { background: var(--blue-bg); border-color: var(--blue-border); border-left-color: var(--blue); }
|
|
1235
|
+
.callout-tip { background: var(--green-bg); border-color: var(--green-border); border-left-color: var(--green); }
|
|
1236
|
+
.callout-warning { background: var(--yellow-bg); border-color: var(--yellow-border); border-left-color: var(--yellow); }
|
|
1237
|
+
.callout-danger { background: var(--red-bg); border-color: var(--red-border); border-left-color: var(--red); }
|
|
1238
|
+
|
|
1239
|
+
/* ── Severity chips (:sev) — tight pill, sub-scale vertical padding ───────── */
|
|
1240
|
+
.sev {
|
|
1241
|
+
display: inline-block; font-size: var(--text-xs); font-weight: var(--fw-semi);
|
|
1242
|
+
padding: 1px var(--sp-2); border-radius: 999px; line-height: 1.5;
|
|
1243
|
+
border: 1px solid var(--border); background: var(--bg-inset); color: var(--text-muted);
|
|
1244
|
+
white-space: nowrap;
|
|
1245
|
+
}
|
|
1246
|
+
.sev-p0 { color: var(--sev-p0); border-color: var(--sev-p0); }
|
|
1247
|
+
.sev-p1 { color: var(--sev-p1); border-color: var(--sev-p1); }
|
|
1248
|
+
.sev-p2 { color: var(--sev-p2); border-color: var(--sev-p2); }
|
|
1249
|
+
.sev-p3 { color: var(--sev-p3); border-color: var(--sev-p3); }
|
|
1250
|
+
.sev-pass { color: var(--sev-pass); border-color: var(--sev-pass); }
|
|
1251
|
+
|
|
1252
|
+
/* ── Citations (:cite) — inline provenance refs ──────────────────────────── */
|
|
1253
|
+
.fp, .cite-advisory {
|
|
1254
|
+
font-family: var(--font-mono); font-size: 0.82em;
|
|
1255
|
+
padding: 0.05em 0.35em; border-radius: var(--radius-sm);
|
|
1256
|
+
background: var(--bg-inset); border: 1px solid var(--border-light);
|
|
1257
|
+
}
|
|
1258
|
+
.fp { color: var(--accent); }
|
|
1259
|
+
.cite-advisory { color: var(--text-faint); border-style: dashed; }
|
|
1260
|
+
|
|
1261
|
+
/* ── Tables + filter-tables ──────────────────────────────────────────────── */
|
|
1262
|
+
.content table { width: 100%; border-collapse: collapse; margin: var(--sp-3) 0; font-size: var(--text-sm); }
|
|
1263
|
+
.content th, .content td { text-align: left; padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border-light); vertical-align: top; }
|
|
1264
|
+
.content th {
|
|
1265
|
+
color: var(--text-muted); font-weight: var(--fw-semi); font-size: var(--text-xs);
|
|
1266
|
+
text-transform: uppercase; letter-spacing: var(--ls-wide); border-bottom-color: var(--border);
|
|
1267
|
+
}
|
|
1268
|
+
.content tbody tr:hover { background: var(--bg-hover); }
|
|
1269
|
+
.content td code { white-space: nowrap; }
|
|
1270
|
+
.filter-table { margin: var(--sp-4) 0; }
|
|
1271
|
+
.filter-input {
|
|
1272
|
+
width: 100%; max-width: 320px; margin-bottom: var(--sp-2);
|
|
1273
|
+
padding: var(--sp-2) var(--sp-3); font-family: inherit; font-size: var(--text-sm);
|
|
1274
|
+
color: var(--text); background: var(--bg-card);
|
|
1275
|
+
border: 1px solid var(--border); border-radius: var(--radius-sm);
|
|
1276
|
+
}
|
|
1277
|
+
.filter-input:focus { border-color: var(--accent); }
|
|
1278
|
+
|
|
1279
|
+
/* ── Charts (:::chart) — label + proportional bar (fill carries inline width%) */
|
|
1280
|
+
.chart-block { margin: var(--sp-4) 0; }
|
|
1281
|
+
.chart-row {
|
|
1282
|
+
display: grid; grid-template-columns: minmax(var(--chart-label-w), 24%) 1fr;
|
|
1283
|
+
align-items: center; gap: var(--sp-3); margin: var(--sp-1) 0;
|
|
1284
|
+
}
|
|
1285
|
+
.chart-label {
|
|
1286
|
+
font-size: var(--text-sm); color: var(--text-muted); text-align: right;
|
|
1287
|
+
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
|
|
1288
|
+
}
|
|
1289
|
+
.chart-row .chart-bar {
|
|
1290
|
+
height: 0.9em; min-width: 2px; background: var(--accent);
|
|
1291
|
+
border-radius: var(--radius-sm);
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
/* ── Tabs (::::tabs / :::tab) ─────────────────────────────────────────────── */
|
|
1295
|
+
.tabs { margin: var(--sp-4) 0; }
|
|
1296
|
+
.tablist { display: flex; flex-wrap: wrap; gap: var(--sp-1); border-bottom: 1px solid var(--border); margin-bottom: var(--sp-3); }
|
|
1297
|
+
.tab-btn {
|
|
1298
|
+
background: none; border: none; border-bottom: 2px solid transparent; margin-bottom: -1px;
|
|
1299
|
+
padding: var(--sp-2) var(--sp-3); color: var(--text-muted);
|
|
1300
|
+
font-family: inherit; font-size: var(--text-sm); font-weight: var(--fw-medium); cursor: pointer;
|
|
1301
|
+
}
|
|
1302
|
+
.tab-btn:hover { color: var(--text); }
|
|
1303
|
+
.tab-btn.active { color: var(--accent); border-bottom-color: var(--accent); }
|
|
1304
|
+
.tabpane { display: none; }
|
|
1305
|
+
.tabpane.active { display: block; }
|
|
1306
|
+
|
|
1307
|
+
/* ── Mermaid diagrams ────────────────────────────────────────────────────── */
|
|
1308
|
+
.content figure { margin: var(--sp-4) 0; text-align: center; }
|
|
1309
|
+
.content figure svg, .content > svg, .content .mermaid svg { max-width: 100%; height: auto; }
|
|
1310
|
+
|
|
1311
|
+
/* ── Index page: category card grid ──────────────────────────────────────── */
|
|
1312
|
+
.content .lead { color: var(--text-muted); font-size: var(--text-base); max-width: 60ch; margin-top: var(--sp-2); }
|
|
1313
|
+
.guide-cards {
|
|
1314
|
+
display: grid; grid-template-columns: repeat(auto-fill, minmax(min(var(--card-min), 100%), 1fr));
|
|
1315
|
+
gap: var(--sp-4); margin: var(--sp-4) 0 var(--sp-6);
|
|
1316
|
+
}
|
|
1317
|
+
.guide-card {
|
|
1318
|
+
display: flex; flex-direction: column; gap: var(--sp-2);
|
|
1319
|
+
padding: var(--sp-4); background: var(--bg-card);
|
|
1320
|
+
border: 1px solid var(--border); border-radius: var(--radius);
|
|
1321
|
+
color: inherit; text-decoration: none;
|
|
1322
|
+
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
|
1323
|
+
}
|
|
1324
|
+
.guide-card:hover { border-color: var(--accent); box-shadow: var(--shadow-md); text-decoration: none; }
|
|
1325
|
+
.guide-card-title { font-weight: var(--fw-semi); color: var(--accent); font-size: var(--text-base); }
|
|
1326
|
+
.guide-card-desc { color: var(--text-muted); font-size: var(--text-sm); line-height: var(--lh-normal); }
|
|
1327
|
+
|
|
1328
|
+
/* ── Responsive: TOC becomes an off-canvas drawer (chrome.ts toggles .open) ──*/
|
|
1329
|
+
/* 860px is literal — media queries cannot read custom properties. Revisit it if
|
|
1330
|
+
--topbar-h / --rail-w / --drawer-w change (the drawer sticky offsets key off them). */
|
|
1331
|
+
@media (max-width: 860px) {
|
|
1332
|
+
.nav-toggle { display: inline-flex; align-items: center; }
|
|
1333
|
+
.layout { grid-template-columns: 1fr; gap: 0; }
|
|
1334
|
+
.rail {
|
|
1335
|
+
position: fixed; top: var(--topbar-h); left: 0; bottom: 0; width: var(--drawer-w); z-index: 50;
|
|
1336
|
+
height: auto; background: var(--bg-card); border-right: 1px solid var(--border);
|
|
1337
|
+
padding: var(--sp-4); box-shadow: var(--shadow-lg);
|
|
1338
|
+
transform: translateX(-100%); transition: transform 0.2s ease, visibility 0.2s ease;
|
|
1339
|
+
/* Closed drawer is off-screen AND removed from tab order / pointer events. */
|
|
1340
|
+
visibility: hidden; pointer-events: none;
|
|
1341
|
+
}
|
|
1342
|
+
.rail.open { transform: translateX(0); visibility: visible; pointer-events: auto; }
|
|
1343
|
+
.rail-close {
|
|
1344
|
+
display: block; margin-left: auto; margin-bottom: var(--sp-2);
|
|
1345
|
+
background: var(--bg-card); border: 1px solid var(--border); color: var(--text);
|
|
1346
|
+
border-radius: var(--radius-sm); padding: var(--sp-1) var(--sp-3); font-size: var(--text-base);
|
|
1347
|
+
line-height: 1; cursor: pointer; font-family: inherit;
|
|
1348
|
+
}
|
|
1349
|
+
.rail-close:hover { background: var(--bg-hover); border-color: var(--accent); }
|
|
1350
|
+
.rail-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
|
|
1351
|
+
.rail-backdrop {
|
|
1352
|
+
display: block; position: fixed; inset: var(--topbar-h) 0 0 0;
|
|
1353
|
+
background: var(--scrim); z-index: 49;
|
|
1354
|
+
opacity: 0; pointer-events: none; transition: opacity 0.2s ease;
|
|
1355
|
+
}
|
|
1356
|
+
.rail.open ~ .rail-backdrop { opacity: 1; pointer-events: auto; }
|
|
1357
|
+
}
|
|
1081
1358
|
</style>
|
|
1082
1359
|
<script>(function(){try{var t=localStorage.getItem('guide-theme');if(!t&&window.matchMedia&&matchMedia('(prefers-color-scheme: dark)').matches)t='dark';if(t)document.documentElement.setAttribute('data-theme',t);}catch(e){}})();</script>
|
|
1083
1360
|
</head>
|
|
1084
1361
|
<body>
|
|
1085
1362
|
<header class="topbar">
|
|
1086
|
-
<button data-action="nav" class="nav-toggle" aria-label="Toggle navigation"
|
|
1363
|
+
<button data-action="nav" class="nav-toggle" aria-label="Toggle navigation"
|
|
1364
|
+
aria-expanded="false" aria-controls="guide-toc">☰</button>
|
|
1087
1365
|
<h1>Knowledge Freshness</h1>
|
|
1088
1366
|
<button data-action="theme" class="theme-toggle" aria-label="Toggle theme">◐</button>
|
|
1089
1367
|
</header>
|
|
1090
1368
|
<div class="layout">
|
|
1091
|
-
<aside class="rail"
|
|
1369
|
+
<aside class="rail" id="guide-toc">
|
|
1370
|
+
<button class="rail-close" data-action="nav" aria-label="Close navigation">✕</button>
|
|
1371
|
+
<nav class="toc" aria-label="Table of contents"><ul><li class="toc-2"><a href="#what-this-system-does">What this system does</a></li><li class="toc-3"><a href="#how-a-gap-closes">How a gap closes</a></li><li class="toc-2"><a href="#system-map">System map</a></li><li class="toc-2"><a href="#frontmatter-signals-and-resolution">Frontmatter, signals, and resolution</a></li><li class="toc-3"><a href="#frontmatter-schema">Frontmatter schema</a></li><li class="toc-3"><a href="#cadence-model">Cadence model</a></li><li class="toc-3"><a href="#adding-a-new-entry-to-the-kb">Adding a new entry to the KB</a></li><li class="toc-3"><a href="#gap-signal-payload">Gap-signal payload</a></li><li class="toc-3"><a href="#knowledgerootresolution-shape">KnowledgeRootResolution shape</a></li><li class="toc-2"><a href="#from-candidate-to-merged-pr">From candidate to merged PR</a></li><li class="toc-3"><a href="#prefilter">Prefilter</a></li><li class="toc-3"><a href="#audit-verdicts">Audit verdicts</a></li><li class="toc-3"><a href="#pr-generation">PR generation</a></li><li class="toc-3"><a href="#mmr-corroboration-manual">MMR corroboration (manual)</a></li><li class="toc-2"><a href="#the-five-pr-gates">The five PR gates</a></li><li class="toc-2"><a href="#lens-i-gap-detection-suppression">Lens I — gap detection + suppression</a></li><li class="toc-3"><a href="#threshold-matrix">Threshold matrix</a></li><li class="toc-3"><a href="#topic-normalization">Topic normalization</a></li><li class="toc-3"><a href="#what-the-lessonsmd-scanner-sees">What the lessons.md scanner sees</a></li><li class="toc-3"><a href="#3-tier---knowledge-root-resolution">3-tier --knowledge-root resolution</a></li><li class="toc-3"><a href="#warning-policy">Warning policy</a></li><li class="toc-3"><a href="#what-a-lens-i-finding-looks-like">What a Lens I finding looks like</a></li><li class="toc-2"><a href="#the-allowlist">The allowlist</a></li><li class="toc-3"><a href="#most-cited-hosts">Most-cited hosts</a></li><li class="toc-3"><a href="#the-full-allowlist">The full allowlist</a></li><li class="toc-3"><a href="#kb-inventory">KB inventory</a></li><li class="toc-3"><a href="#how-to-expand-the-allowlist">How to expand the allowlist</a></li><li class="toc-2"><a href="#anthropic-vs-deepseek-cron-uses-deepseek">Anthropic vs DeepSeek (cron uses DeepSeek)</a></li><li class="toc-2"><a href="#every-command-that-touches-the-system">Every command that touches the system</a></li><li class="toc-3"><a href="#refresh-arm-commands">Refresh-arm commands</a></li><li class="toc-3"><a href="#gap-arm-commands">Gap-arm commands</a></li><li class="toc-3"><a href="#gate-side-subcommands-also-runnable-locally-for-triage">Gate-side subcommands (also runnable locally for triage)</a></li><li class="toc-2"><a href="#operations-cheat-sheet">Operations cheat sheet</a></li><li class="toc-3"><a href="#an-entrys-audit-failed-in-the-cron">An entry's audit failed in the cron</a></li><li class="toc-3"><a href="#lens-i-keeps-surfacing-a-topic-the-kb-already-covers">Lens I keeps surfacing a topic the KB already covers</a></li><li class="toc-3"><a href="#downstream-auto-detect-cant-find-the-kb">Downstream auto-detect can't find the KB</a></li><li class="toc-3"><a href="#yaml-knowledge-root-stops-working-after-an-upgrade">Yaml knowledge_root stops working after an upgrade</a></li><li class="toc-3"><a href="#a-source-url-fetches-in-curl-but-the-cron-rejects-it">A source URL fetches in curl but the cron rejects it</a></li><li class="toc-3"><a href="#--knowledge-root-resolves-to-a-path-you-didnt-expect">--knowledge-root resolves to a path you didn't expect</a></li><li class="toc-2"><a href="#config-reference">Config reference</a></li><li class="toc-2"><a href="#roadmap-and-known-divergences">Roadmap and known divergences</a></li><li class="toc-3"><a href="#phase-5-planned">Phase 5 (planned)</a></li><li class="toc-3"><a href="#known-divergences">Known divergences</a></li></ul></nav>
|
|
1372
|
+
</aside>
|
|
1092
1373
|
<main class="content"><h2 id="what-this-system-does">What this system does</h2>
|
|
1093
1374
|
<p>Knowledge entries under <code>content/knowledge/</code> declare a <code>volatility</code> tier and a
|
|
1094
1375
|
list of <code>sources</code>. A daily cron prefilters at most ten entries that are <em>due</em> —
|
|
@@ -2111,13 +2392,13 @@ resolved by <code>resolveProvider</code> (<span class="fp" data-path="src/knowle
|
|
|
2111
2392
|
<li>No env, <code>claude</code> on PATH → anthropic (subprocess uses keychain)</li>
|
|
2112
2393
|
<li>Nothing → error (no provider configured)</li>
|
|
2113
2394
|
</ol>
|
|
2114
|
-
<div class="tabs"><div class="tablist" role="tablist"><button class="tab-btn active" role="tab" data-tab="0">Anthropic</button><button class="tab-btn" role="tab" data-tab="1">DeepSeek</button></div><div class="tabpane active" data-tab="0"><p>Subprocess: <code>claude -p --tools ""</code> (empty-tools disables WebFetch so the model
|
|
2395
|
+
<div class="tabs"><div class="tablist" role="tablist"><button id="tab-0-0" class="tab-btn active" role="tab" data-tab="0" aria-controls="tabpane-0-0" aria-selected="true" tabindex="0">Anthropic</button><button id="tab-0-1" class="tab-btn" role="tab" data-tab="1" aria-controls="tabpane-0-1" aria-selected="false" tabindex="-1">DeepSeek</button></div><div id="tabpane-0-0" class="tabpane active" role="tabpanel" data-tab="0" aria-labelledby="tab-0-0" tabindex="0"><p>Subprocess: <code>claude -p --tools ""</code> (empty-tools disables WebFetch so the model
|
|
2115
2396
|
can only read the prefetched bodies). <strong>Requires the <code>claude</code> CLI on PATH
|
|
2116
2397
|
regardless of how the provider was chosen</strong> — the resolver throws
|
|
2117
2398
|
(<span class="fp" data-path="src/knowledge-freshness/providers/index.ts:44-56">src/knowledge-freshness/providers/index.ts:44-56</span>) if anthropic is
|
|
2118
2399
|
picked via flag, env, or API-key inference and <code>claude</code> isn't installed.
|
|
2119
2400
|
<code>ANTHROPIC_API_KEY</code> alone is <em>not</em> sufficient. Source:
|
|
2120
|
-
<code>src/knowledge-freshness/providers/anthropic.ts</code>.</p></div><div class="tabpane" data-tab="1"><p>HTTP. No subprocess; works in CI without the Claude CLI.</p><ul>
|
|
2401
|
+
<code>src/knowledge-freshness/providers/anthropic.ts</code>.</p></div><div id="tabpane-0-1" class="tabpane" role="tabpanel" data-tab="1" aria-labelledby="tab-0-1" tabindex="0"><p>HTTP. No subprocess; works in CI without the Claude CLI.</p><ul>
|
|
2121
2402
|
<li><strong>Auth:</strong> requires <code>DEEPSEEK_API_KEY</code>.</li>
|
|
2122
2403
|
<li><strong>Default model:</strong> <code>deepseek-v4-flash</code>.</li>
|
|
2123
2404
|
<li><strong>Override:</strong> set <code>KNOWLEDGE_FRESHNESS_DEEPSEEK_MODEL</code> to <code>deepseek-v4-pro</code>.
|
|
@@ -2344,6 +2625,7 @@ describes suppression in future tense; both have shipped.</li>
|
|
|
2344
2625
|
<li><strong><code>www.</code> prefix inconsistency</strong> (P3) — mixed <code>www.</code> use in the allowlist; bare
|
|
2345
2626
|
entries already auto-match subdomains, so the prefix is redundant.</li>
|
|
2346
2627
|
</ul></main>
|
|
2628
|
+
<div class="rail-backdrop" data-action="nav" aria-hidden="true"></div>
|
|
2347
2629
|
</div>
|
|
2348
2630
|
<script>(function(){
|
|
2349
2631
|
var LS_KEY = 'guide-theme';
|
|
@@ -2362,12 +2644,69 @@ entries already auto-match subdomains, so the prefix is redundant.</li>
|
|
|
2362
2644
|
});
|
|
2363
2645
|
});
|
|
2364
2646
|
|
|
2365
|
-
// ─── Mobile nav
|
|
2647
|
+
// ─── Mobile nav (drawer + backdrop; aria-expanded + Escape-to-close) ──────
|
|
2648
|
+
function setNav(open) {
|
|
2649
|
+
var rail = document.querySelector('.rail');
|
|
2650
|
+
if (rail) rail.classList.toggle('open', open);
|
|
2651
|
+
var toggle = document.querySelector('.nav-toggle');
|
|
2652
|
+
if (toggle) toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
|
|
2653
|
+
// Modal-drawer focus containment: while open, make the page content inert
|
|
2654
|
+
// (out of tab order + a11y tree) and move focus into the drawer; on close,
|
|
2655
|
+
// restore content and return focus to the toggle.
|
|
2656
|
+
var main = document.querySelector('.content');
|
|
2657
|
+
if (main) main.inert = open;
|
|
2658
|
+
if (open) {
|
|
2659
|
+
var first = rail && rail.querySelector('a, button, [tabindex]:not([tabindex="-1"])');
|
|
2660
|
+
if (first) first.focus();
|
|
2661
|
+
else if (rail) { rail.setAttribute('tabindex', '-1'); rail.focus(); }
|
|
2662
|
+
} else if (toggle) {
|
|
2663
|
+
toggle.focus();
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
// If the viewport grows past the mobile breakpoint while the drawer is open,
|
|
2667
|
+
// the rail becomes the desktop sidebar and the toggle hides — clear the open
|
|
2668
|
+
// state so .content doesn't stay inert with no way to close it.
|
|
2669
|
+
if (window.matchMedia) {
|
|
2670
|
+
var mq = window.matchMedia('(max-width: 860px)');
|
|
2671
|
+
var onMq = function() {
|
|
2672
|
+
if (mq.matches) return;
|
|
2673
|
+
var rail = document.querySelector('.rail');
|
|
2674
|
+
if (rail) rail.classList.remove('open');
|
|
2675
|
+
var toggle = document.querySelector('.nav-toggle');
|
|
2676
|
+
if (toggle) toggle.setAttribute('aria-expanded', 'false');
|
|
2677
|
+
var main = document.querySelector('.content');
|
|
2678
|
+
if (main) main.inert = false;
|
|
2679
|
+
};
|
|
2680
|
+
if (mq.addEventListener) mq.addEventListener('change', onMq);
|
|
2681
|
+
else if (mq.addListener) mq.addListener(onMq);
|
|
2682
|
+
}
|
|
2366
2683
|
document.querySelectorAll('[data-action="nav"]').forEach(function(btn) {
|
|
2367
2684
|
btn.addEventListener('click', function() {
|
|
2368
2685
|
var rail = document.querySelector('.rail');
|
|
2369
|
-
|
|
2686
|
+
setNav(!(rail && rail.classList.contains('open')));
|
|
2687
|
+
});
|
|
2688
|
+
});
|
|
2689
|
+
// Selecting a TOC link closes the drawer (so the now-active content isn't
|
|
2690
|
+
// left inert behind the panel) before the anchor navigation scrolls.
|
|
2691
|
+
var drawerRail = document.querySelector('.rail');
|
|
2692
|
+
if (drawerRail) {
|
|
2693
|
+
drawerRail.querySelectorAll('a').forEach(function(a) {
|
|
2694
|
+
a.addEventListener('click', function() {
|
|
2695
|
+
if (drawerRail.classList.contains('open')) setNav(false);
|
|
2696
|
+
});
|
|
2370
2697
|
});
|
|
2698
|
+
}
|
|
2699
|
+
document.addEventListener('keydown', function(e) {
|
|
2700
|
+
var rail = document.querySelector('.rail');
|
|
2701
|
+
if (!rail || !rail.classList.contains('open')) return;
|
|
2702
|
+
if (e.key === 'Escape') { setNav(false); return; } // setNav restores focus to the toggle
|
|
2703
|
+
// Trap Tab within the open drawer (modal pattern).
|
|
2704
|
+
if (e.key !== 'Tab') return;
|
|
2705
|
+
var f = rail.querySelectorAll('a[href], button, [tabindex]:not([tabindex="-1"])');
|
|
2706
|
+
if (!f.length) return;
|
|
2707
|
+
var first = f[0], last = f[f.length - 1];
|
|
2708
|
+
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
|
|
2709
|
+
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
|
|
2371
2710
|
});
|
|
2372
2711
|
|
|
2373
2712
|
// ─── Copy buttons ─────────────────────────────────────────────────────────
|
|
@@ -2394,17 +2733,31 @@ entries already auto-match subdomains, so the prefix is redundant.</li>
|
|
|
2394
2733
|
wrapper.insertBefore(btn, pre);
|
|
2395
2734
|
});
|
|
2396
2735
|
|
|
2397
|
-
// ─── Tabs
|
|
2736
|
+
// ─── Tabs (ARIA pattern: aria-selected + roving tabindex + arrow keys) ────
|
|
2737
|
+
function activateTab(group, btn, focus) {
|
|
2738
|
+
var idx = btn.getAttribute('data-tab');
|
|
2739
|
+
group.querySelectorAll('.tab-btn').forEach(function(b) {
|
|
2740
|
+
var on = b === btn;
|
|
2741
|
+
b.classList.toggle('active', on);
|
|
2742
|
+
b.setAttribute('aria-selected', on ? 'true' : 'false');
|
|
2743
|
+
b.setAttribute('tabindex', on ? '0' : '-1');
|
|
2744
|
+
});
|
|
2745
|
+
group.querySelectorAll('.tabpane').forEach(function(pane) {
|
|
2746
|
+
pane.classList.toggle('active', pane.getAttribute('data-tab') === idx);
|
|
2747
|
+
});
|
|
2748
|
+
if (focus) btn.focus();
|
|
2749
|
+
}
|
|
2398
2750
|
document.querySelectorAll('.tabs').forEach(function(group) {
|
|
2399
|
-
group.querySelectorAll('.tab-btn')
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2751
|
+
var btns = [].slice.call(group.querySelectorAll('.tab-btn'));
|
|
2752
|
+
btns.forEach(function(btn, i) {
|
|
2753
|
+
btn.addEventListener('click', function() { activateTab(group, btn, false); });
|
|
2754
|
+
btn.addEventListener('keydown', function(e) {
|
|
2755
|
+
var ni = -1;
|
|
2756
|
+
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') ni = (i + 1) % btns.length;
|
|
2757
|
+
else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') ni = (i - 1 + btns.length) % btns.length;
|
|
2758
|
+
else if (e.key === 'Home') ni = 0;
|
|
2759
|
+
else if (e.key === 'End') ni = btns.length - 1;
|
|
2760
|
+
if (ni >= 0) { e.preventDefault(); activateTab(group, btns[ni], true); }
|
|
2408
2761
|
});
|
|
2409
2762
|
});
|
|
2410
2763
|
});
|
|
@@ -665,7 +665,7 @@ resolved by `resolveProvider` (:cite[src/knowledge-freshness/providers/index.ts:
|
|
|
665
665
|
6. Nothing → error (no provider configured)
|
|
666
666
|
|
|
667
667
|
::::tabs
|
|
668
|
-
:::tab{title=Anthropic}
|
|
668
|
+
:::tab{title="Anthropic"}
|
|
669
669
|
Subprocess: `claude -p --tools ""` (empty-tools disables WebFetch so the model
|
|
670
670
|
can only read the prefetched bodies). **Requires the `claude` CLI on PATH
|
|
671
671
|
regardless of how the provider was chosen** — the resolver throws
|
|
@@ -674,7 +674,7 @@ picked via flag, env, or API-key inference and `claude` isn't installed.
|
|
|
674
674
|
`ANTHROPIC_API_KEY` alone is *not* sufficient. Source:
|
|
675
675
|
`src/knowledge-freshness/providers/anthropic.ts`.
|
|
676
676
|
:::
|
|
677
|
-
:::tab{title=DeepSeek}
|
|
677
|
+
:::tab{title="DeepSeek"}
|
|
678
678
|
HTTP. No subprocess; works in CI without the Claude CLI.
|
|
679
679
|
|
|
680
680
|
- **Auth:** requires `DEEPSEEK_API_KEY`.
|