tink-harness 1.9.3 → 1.9.4
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
|
@@ -6,6 +6,17 @@ All notable changes to Tink are tracked here.
|
|
|
6
6
|
|
|
7
7
|
No unreleased changes yet.
|
|
8
8
|
|
|
9
|
+
## [1.9.4] - 2026-06-10
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Harness cards now sort by usage and open with a smooth expand animation showing richer details: last used, success/failure counts, context cost, co-used harness chips, score factors, safe next action, and evidence handles.
|
|
14
|
+
- Added an evaluation & maintenance history section to the Harnesses tab, fed by `.tink/maintenance/ledger.jsonl` (new `maintenance_events` field in the lifecycle summary).
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- The lifecycle generator now strips a UTF-8 BOM before parsing JSONL files, so the first ledger entry is no longer dropped.
|
|
19
|
+
|
|
9
20
|
## [1.9.3] - 2026-06-10
|
|
10
21
|
|
|
11
22
|
### Added
|
package/VERSIONING.md
CHANGED
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@ function readJson(filePath, fallback) {
|
|
|
15
15
|
|
|
16
16
|
function readLines(filePath) {
|
|
17
17
|
if (!fs.existsSync(filePath)) return [];
|
|
18
|
-
return fs.readFileSync(filePath, 'utf8').split(/\r?\n/).filter(Boolean);
|
|
18
|
+
return fs.readFileSync(filePath, 'utf8').replace(/^/, '').split(/\r?\n/).filter(Boolean);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
function listFiles(dirPath, suffix) {
|
|
@@ -517,6 +517,28 @@ function summarize(root) {
|
|
|
517
517
|
item.candidate_score = scoreCandidate(item);
|
|
518
518
|
}
|
|
519
519
|
const harnessSummaries = [...summaries.values()].sort((a, b) => a.id.localeCompare(b.id));
|
|
520
|
+
|
|
521
|
+
const ledgerPath = path.join(root, '.tink/maintenance/ledger.jsonl');
|
|
522
|
+
const knownHarnessIds = [...summaries.keys()];
|
|
523
|
+
const maintenanceEvents = parseJsonl(ledgerPath)
|
|
524
|
+
.map((entry) => {
|
|
525
|
+
const refs = [...(Array.isArray(entry.files) ? entry.files : []), ...(Array.isArray(entry.evidence) ? entry.evidence : []), String(entry.op_id || '')];
|
|
526
|
+
const related = knownHarnessIds.filter((id) =>
|
|
527
|
+
refs.some((ref) => String(ref).includes(`${id}.md`) || String(ref).includes(`harness:${id}`) || String(ref).includes(`-${id}-`))
|
|
528
|
+
).sort();
|
|
529
|
+
return {
|
|
530
|
+
timestamp: entry.timestamp || '',
|
|
531
|
+
op_id: entry.op_id || '',
|
|
532
|
+
type: entry.type || 'unknown',
|
|
533
|
+
files: (Array.isArray(entry.files) ? entry.files : []).slice(0, 8),
|
|
534
|
+
result: entry.result || 'unknown',
|
|
535
|
+
approval: entry.approval || '',
|
|
536
|
+
harnesses: related
|
|
537
|
+
};
|
|
538
|
+
})
|
|
539
|
+
.sort((a, b) => String(b.timestamp).localeCompare(String(a.timestamp)))
|
|
540
|
+
.slice(0, 60);
|
|
541
|
+
|
|
520
542
|
return {
|
|
521
543
|
generated_at: new Date().toISOString(),
|
|
522
544
|
run_window: {
|
|
@@ -530,11 +552,13 @@ function summarize(root) {
|
|
|
530
552
|
'.tink/memory/*.md',
|
|
531
553
|
'.tink/runs/*.md',
|
|
532
554
|
'.tink/maintenance/weave-queue.json',
|
|
533
|
-
'.tink/maintenance/friction.jsonl'
|
|
555
|
+
'.tink/maintenance/friction.jsonl',
|
|
556
|
+
'.tink/maintenance/ledger.jsonl'
|
|
534
557
|
],
|
|
535
558
|
harnesses: harnessSummaries,
|
|
536
559
|
graph: buildGraph(harnessSummaries),
|
|
537
|
-
timeline: buildTimeline(runs, root)
|
|
560
|
+
timeline: buildTimeline(runs, root),
|
|
561
|
+
maintenance_events: maintenanceEvents
|
|
538
562
|
};
|
|
539
563
|
}
|
|
540
564
|
|
|
@@ -130,6 +130,19 @@ const COPY = {
|
|
|
130
130
|
viewAll: 'View all',
|
|
131
131
|
confidenceShort: 'Confidence',
|
|
132
132
|
routingHelp: 'When cast routes a task to a visible-thinking overlay harness.',
|
|
133
|
+
lastUsed: 'Last used',
|
|
134
|
+
successes: 'Successes',
|
|
135
|
+
failures: 'Failures',
|
|
136
|
+
contextCost: 'Context cost',
|
|
137
|
+
coUsedWith: 'Often used with',
|
|
138
|
+
safeNextAction: 'Safe next action',
|
|
139
|
+
scoreFactors: 'Score factors',
|
|
140
|
+
viewInGraph: 'View in graph',
|
|
141
|
+
historyEyebrow: 'HISTORY',
|
|
142
|
+
historyTitle: 'Evaluation & maintenance history',
|
|
143
|
+
historyHelp: 'Approved reusable-state changes from the maintenance ledger, newest first.',
|
|
144
|
+
historyEmpty: 'No ledger history yet.',
|
|
145
|
+
sortNote: 'Sorted by usage',
|
|
133
146
|
groups: [
|
|
134
147
|
['keep', 'Healthy harnesses', 'Ready to keep using'],
|
|
135
148
|
['weave', 'Weave candidates', 'Worth improving next'],
|
|
@@ -174,6 +187,19 @@ COPY.ko = {
|
|
|
174
187
|
viewAll: '전체 보기',
|
|
175
188
|
confidenceShort: '신뢰도',
|
|
176
189
|
routingHelp: 'cast가 생각 보조 overlay 하네스로 라우팅하는 기준입니다.',
|
|
190
|
+
lastUsed: '마지막 사용',
|
|
191
|
+
successes: '성공',
|
|
192
|
+
failures: '실패',
|
|
193
|
+
contextCost: '컨텍스트 비용',
|
|
194
|
+
coUsedWith: '함께 쓰인 하네스',
|
|
195
|
+
safeNextAction: '다음 안전 행동',
|
|
196
|
+
scoreFactors: '점수 요인',
|
|
197
|
+
viewInGraph: '그래프에서 보기',
|
|
198
|
+
historyEyebrow: '히스토리',
|
|
199
|
+
historyTitle: '평가·생성 히스토리',
|
|
200
|
+
historyHelp: '유지보수 장부에 기록된 승인 변경 이력을 최신순으로 보여줍니다.',
|
|
201
|
+
historyEmpty: '아직 장부 기록이 없습니다.',
|
|
202
|
+
sortNote: '사용량 순 정렬',
|
|
177
203
|
navLabel: '탐색',
|
|
178
204
|
operator: '작업자',
|
|
179
205
|
online: 'Tink 온라인',
|
|
@@ -860,26 +886,81 @@ function renderSelectedPanel(harnesses, copy) {
|
|
|
860
886
|
function renderHarness(item, copy) {
|
|
861
887
|
const signals = item.signals || {};
|
|
862
888
|
const score = Number(item.candidate_score?.total || 0);
|
|
889
|
+
const factors = (item.candidate_score?.factors || []).slice(0, 5);
|
|
890
|
+
const coUsed = (signals.co_used_with || []).slice(0, 5);
|
|
891
|
+
const reason = normalizeReason(item.reason, copy);
|
|
863
892
|
return `
|
|
864
|
-
<article class="harness-card ${recommendationClass(item.recommendation)}" data-harness-id="${escapeAttr(item.id)}" data-recommendation="${escapeAttr(item.recommendation || 'unknown')}"
|
|
865
|
-
<
|
|
866
|
-
<
|
|
867
|
-
|
|
893
|
+
<article class="harness-card ${recommendationClass(item.recommendation)}" data-harness-id="${escapeAttr(item.id)}" data-recommendation="${escapeAttr(item.recommendation || 'unknown')}">
|
|
894
|
+
<button class="harness-summary" type="button" aria-expanded="false">
|
|
895
|
+
<div>
|
|
896
|
+
<p class="eyebrow">${escapeHtml(renderCopyValue(item.recommendation, copy))}</p>
|
|
897
|
+
<h3>${escapeHtml(item.id)}</h3>
|
|
898
|
+
</div>
|
|
899
|
+
<div class="harness-mini">
|
|
900
|
+
<span>${escapeHtml(copy.uses)} ${escapeHtml(signals.uses ?? 0)}</span>
|
|
901
|
+
<strong>${escapeHtml(score)}</strong>
|
|
902
|
+
</div>
|
|
903
|
+
<span class="chevron" aria-hidden="true"></span>
|
|
904
|
+
</button>
|
|
905
|
+
<div class="harness-detail">
|
|
906
|
+
<div class="harness-detail-inner">
|
|
907
|
+
${reason ? `<p class="harness-reason">${escapeHtml(reason)}</p>` : ''}
|
|
908
|
+
<dl>
|
|
909
|
+
<div><dt>${escapeHtml(copy.lifecycleState)}</dt><dd>${escapeHtml(renderCopyValue(item.lifecycle_state, copy))}</dd></div>
|
|
910
|
+
<div><dt>${escapeHtml(copy.lastUsed || 'Last used')}</dt><dd>${escapeHtml(signals.last_used ? shortDate(signals.last_used) : renderCopyValue('', copy))}</dd></div>
|
|
911
|
+
<div><dt>${escapeHtml(copy.successes || 'Successes')}</dt><dd>${escapeHtml(signals.successes ?? 0)}</dd></div>
|
|
912
|
+
<div><dt>${escapeHtml(copy.failures || 'Failures')}</dt><dd>${escapeHtml(signals.failures ?? 0)}</dd></div>
|
|
913
|
+
<div><dt>${escapeHtml(copy.blocked)}</dt><dd>${escapeHtml(signals.blocked ?? 0)}</dd></div>
|
|
914
|
+
<div><dt>${escapeHtml(copy.contextCost || 'Context cost')}</dt><dd>${escapeHtml(renderCopyValue(signals.context_cost, copy))}</dd></div>
|
|
915
|
+
</dl>
|
|
916
|
+
${coUsed.length ? `
|
|
917
|
+
<p class="detail-label">${escapeHtml(copy.coUsedWith || 'Often used with')}</p>
|
|
918
|
+
<div class="co-used-chips">${coUsed.map((related) => `<span class="co-chip">${escapeHtml(related.id)} ×${escapeHtml(related.count)}</span>`).join('')}</div>
|
|
919
|
+
` : ''}
|
|
920
|
+
${factors.length ? `
|
|
921
|
+
<p class="detail-label">${escapeHtml(copy.scoreFactors || 'Score factors')}</p>
|
|
922
|
+
<ul class="factor-list">${factors.map((factor) => `<li><span>${escapeHtml(factor.name)}</span><strong>${escapeHtml(factor.points ?? factor.value ?? '')}</strong></li>`).join('')}</ul>
|
|
923
|
+
` : ''}
|
|
924
|
+
${item.safe_next_action ? `
|
|
925
|
+
<p class="detail-label">${escapeHtml(copy.safeNextAction || 'Safe next action')}</p>
|
|
926
|
+
<p class="harness-next">${escapeHtml(item.safe_next_action)}</p>
|
|
927
|
+
` : ''}
|
|
928
|
+
<p class="detail-label">${escapeHtml(copy.evidenceHandles)} (${escapeHtml(String((item.evidence_handles || []).length))})</p>
|
|
929
|
+
<ul class="evidence-list">${renderEvidence(item.evidence_handles, copy)}</ul>
|
|
930
|
+
<button class="link-button" type="button" data-select-harness="${escapeAttr(item.id)}">${escapeHtml(copy.viewInGraph || 'View in graph')} →</button>
|
|
931
|
+
</div>
|
|
868
932
|
</div>
|
|
869
|
-
<strong>${escapeHtml(score)}</strong>
|
|
870
|
-
<dl>
|
|
871
|
-
<div><dt>${escapeHtml(copy.lifecycleState)}</dt><dd>${escapeHtml(renderCopyValue(item.lifecycle_state, copy))}</dd></div>
|
|
872
|
-
<div><dt>${escapeHtml(copy.uses)}</dt><dd>${escapeHtml(signals.uses ?? 0)}</dd></div>
|
|
873
|
-
<div><dt>${escapeHtml(copy.blocked)}</dt><dd>${escapeHtml(signals.blocked ?? 0)}</dd></div>
|
|
874
|
-
</dl>
|
|
875
|
-
<details>
|
|
876
|
-
<summary>${escapeHtml(copy.evidenceHandles)} (${escapeHtml(String((item.evidence_handles || []).length))})</summary>
|
|
877
|
-
<ul>${renderEvidence(item.evidence_handles, copy)}</ul>
|
|
878
|
-
</details>
|
|
879
933
|
</article>
|
|
880
934
|
`;
|
|
881
935
|
}
|
|
882
936
|
|
|
937
|
+
function renderHistorySection(events = [], copy) {
|
|
938
|
+
const items = Array.isArray(events) ? events.slice(0, 30) : [];
|
|
939
|
+
return `
|
|
940
|
+
<section class="history-section">
|
|
941
|
+
<div class="panel-title">
|
|
942
|
+
<p class="eyebrow">${escapeHtml(copy.historyEyebrow || 'HISTORY')}</p>
|
|
943
|
+
<h2>${escapeHtml(copy.historyTitle || 'Evaluation & maintenance history')}</h2>
|
|
944
|
+
<p>${escapeHtml(copy.historyHelp || '')}</p>
|
|
945
|
+
</div>
|
|
946
|
+
${items.length ? `
|
|
947
|
+
<ol class="history-feed">
|
|
948
|
+
${items.map((event) => `
|
|
949
|
+
<li>
|
|
950
|
+
<span class="history-type ${escapeAttr(String(event.type || 'unknown').replace(/[^a-z0-9_-]/gi, '-'))}">${escapeHtml(event.type || 'unknown')}</span>
|
|
951
|
+
<div>
|
|
952
|
+
<strong>${escapeHtml(shortDate(event.timestamp))} · ${escapeHtml(event.result || '')}</strong>
|
|
953
|
+
${event.harnesses?.length ? `<p class="history-harnesses">${event.harnesses.map((id) => escapeHtml(id)).join(', ')}</p>` : ''}
|
|
954
|
+
${event.files?.length ? `<p class="history-files">${event.files.slice(0, 4).map((file) => `<code>${escapeHtml(normalizePath(file).replace(/^.*[\\/]/, ''))}</code>`).join(' ')}</p>` : ''}
|
|
955
|
+
</div>
|
|
956
|
+
</li>
|
|
957
|
+
`).join('')}
|
|
958
|
+
</ol>
|
|
959
|
+
` : `<p class="empty-note">${escapeHtml(copy.historyEmpty || 'No ledger history yet.')}</p>`}
|
|
960
|
+
</section>
|
|
961
|
+
`;
|
|
962
|
+
}
|
|
963
|
+
|
|
883
964
|
function renderGraphOverview(graph = {}, copy) {
|
|
884
965
|
const stats = graphStats(graph);
|
|
885
966
|
const nodeCounts = new Map(stats.nodeCounts);
|
|
@@ -1267,13 +1348,11 @@ function renderScript(harnesses, copy) {
|
|
|
1267
1348
|
selectHarness(button.dataset.selectHarness);
|
|
1268
1349
|
});
|
|
1269
1350
|
});
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
selectHarness(card.dataset.harnessId);
|
|
1276
|
-
}
|
|
1351
|
+
document.querySelectorAll('.harness-summary').forEach((button) => {
|
|
1352
|
+
button.addEventListener('click', () => {
|
|
1353
|
+
const card = button.closest('.harness-card');
|
|
1354
|
+
const expanded = card.classList.toggle('is-expanded');
|
|
1355
|
+
button.setAttribute('aria-expanded', expanded ? 'true' : 'false');
|
|
1277
1356
|
});
|
|
1278
1357
|
});
|
|
1279
1358
|
document.querySelectorAll('[data-filter-rec]').forEach((button) => {
|
|
@@ -1999,24 +2078,26 @@ function renderStyles() {
|
|
|
1999
2078
|
|
|
2000
2079
|
.harness-grid {
|
|
2001
2080
|
display: grid;
|
|
2002
|
-
grid-template-columns: repeat(
|
|
2003
|
-
gap: var(--space-
|
|
2081
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
2082
|
+
gap: var(--space-2);
|
|
2083
|
+
align-items: start;
|
|
2004
2084
|
}
|
|
2005
2085
|
|
|
2006
2086
|
.harness-card {
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
gap: var(--space-2);
|
|
2087
|
+
transition: opacity 160ms ease, border-color 160ms ease;
|
|
2088
|
+
padding: 0;
|
|
2089
|
+
overflow: hidden;
|
|
2011
2090
|
}
|
|
2012
2091
|
|
|
2013
2092
|
.harness-card:hover,
|
|
2014
|
-
.harness-card
|
|
2015
|
-
.harness-card.is-
|
|
2093
|
+
.harness-card.is-selected,
|
|
2094
|
+
.harness-card.is-expanded {
|
|
2016
2095
|
border-color: var(--border-hover);
|
|
2017
2096
|
outline: none;
|
|
2018
2097
|
}
|
|
2019
2098
|
|
|
2099
|
+
.harness-card.is-expanded { border-color: var(--border-strong); }
|
|
2100
|
+
|
|
2020
2101
|
.harness-card.is-filtered-out { display: none; }
|
|
2021
2102
|
|
|
2022
2103
|
.harness-card.keep { border-top: 2px solid var(--success); }
|
|
@@ -2025,32 +2106,206 @@ function renderStyles() {
|
|
|
2025
2106
|
.harness-card.merge_candidate { border-top: 2px solid var(--accent); }
|
|
2026
2107
|
.harness-card.observe { border-top: 2px solid var(--text-secondary); }
|
|
2027
2108
|
|
|
2028
|
-
.harness-
|
|
2109
|
+
.harness-summary {
|
|
2110
|
+
width: 100%;
|
|
2111
|
+
display: grid;
|
|
2112
|
+
grid-template-columns: 1fr auto 14px;
|
|
2113
|
+
align-items: center;
|
|
2114
|
+
gap: var(--space-2);
|
|
2115
|
+
padding: var(--space-3);
|
|
2116
|
+
border: 0;
|
|
2117
|
+
background: transparent;
|
|
2118
|
+
color: var(--text-primary);
|
|
2119
|
+
font-family: var(--font-ui);
|
|
2120
|
+
text-align: left;
|
|
2121
|
+
cursor: pointer;
|
|
2122
|
+
}
|
|
2123
|
+
|
|
2124
|
+
.harness-summary:hover { background: var(--bg-hover); }
|
|
2125
|
+
|
|
2126
|
+
.harness-summary .eyebrow { margin: 0 0 2px; font-size: 10px; }
|
|
2029
2127
|
|
|
2030
|
-
.harness-
|
|
2128
|
+
.harness-summary h3 {
|
|
2031
2129
|
margin: 0;
|
|
2032
|
-
font-size:
|
|
2130
|
+
font-size: 14px;
|
|
2033
2131
|
line-height: 1.25;
|
|
2034
2132
|
font-weight: 600;
|
|
2133
|
+
overflow-wrap: anywhere;
|
|
2035
2134
|
}
|
|
2036
2135
|
|
|
2037
|
-
.harness-
|
|
2038
|
-
|
|
2039
|
-
|
|
2136
|
+
.harness-mini {
|
|
2137
|
+
display: grid;
|
|
2138
|
+
gap: 2px;
|
|
2139
|
+
justify-items: end;
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
.harness-mini span {
|
|
2143
|
+
color: var(--text-secondary);
|
|
2144
|
+
font-size: 11px;
|
|
2145
|
+
white-space: nowrap;
|
|
2146
|
+
}
|
|
2147
|
+
|
|
2148
|
+
.harness-mini strong {
|
|
2149
|
+
font-size: 18px;
|
|
2040
2150
|
line-height: 1;
|
|
2041
2151
|
font-family: var(--font-mono);
|
|
2042
2152
|
font-weight: 600;
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
.chevron {
|
|
2156
|
+
width: 7px;
|
|
2157
|
+
height: 7px;
|
|
2158
|
+
border-right: 1.5px solid var(--text-secondary);
|
|
2159
|
+
border-bottom: 1.5px solid var(--text-secondary);
|
|
2160
|
+
transform: rotate(45deg);
|
|
2161
|
+
transition: transform 240ms ease;
|
|
2162
|
+
justify-self: center;
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
.harness-card.is-expanded .chevron { transform: rotate(225deg); }
|
|
2166
|
+
|
|
2167
|
+
.harness-detail {
|
|
2168
|
+
display: grid;
|
|
2169
|
+
grid-template-rows: 0fr;
|
|
2170
|
+
transition: grid-template-rows 320ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
.harness-card.is-expanded .harness-detail { grid-template-rows: 1fr; }
|
|
2174
|
+
|
|
2175
|
+
.harness-detail-inner {
|
|
2176
|
+
overflow: hidden;
|
|
2177
|
+
min-height: 0;
|
|
2178
|
+
padding: 0 var(--space-3);
|
|
2179
|
+
display: grid;
|
|
2180
|
+
gap: var(--space-2);
|
|
2181
|
+
opacity: 0;
|
|
2182
|
+
transition: opacity 240ms ease 60ms, padding 320ms ease;
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
.harness-card.is-expanded .harness-detail-inner {
|
|
2186
|
+
opacity: 1;
|
|
2187
|
+
padding: var(--space-1) var(--space-3) var(--space-3);
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
.harness-reason {
|
|
2191
|
+
margin: 0;
|
|
2192
|
+
color: var(--text-secondary);
|
|
2193
|
+
font-size: 12px;
|
|
2194
|
+
line-height: 1.5;
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
.detail-label {
|
|
2198
|
+
margin: var(--space-1) 0 0;
|
|
2199
|
+
color: var(--text-secondary);
|
|
2200
|
+
font-size: 10px;
|
|
2201
|
+
text-transform: uppercase;
|
|
2202
|
+
letter-spacing: 0.06em;
|
|
2203
|
+
}
|
|
2204
|
+
|
|
2205
|
+
.co-used-chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
2206
|
+
|
|
2207
|
+
.co-chip {
|
|
2208
|
+
border: 1px solid var(--border-default);
|
|
2209
|
+
background: var(--bg-hover);
|
|
2210
|
+
border-radius: var(--radius-sm);
|
|
2211
|
+
padding: 2px 6px;
|
|
2212
|
+
font-size: 11px;
|
|
2213
|
+
font-family: var(--font-mono);
|
|
2214
|
+
color: var(--text-secondary);
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
.factor-list {
|
|
2218
|
+
margin: 0;
|
|
2219
|
+
padding: 0;
|
|
2220
|
+
list-style: none;
|
|
2221
|
+
display: grid;
|
|
2222
|
+
gap: 4px;
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
.factor-list li {
|
|
2226
|
+
display: flex;
|
|
2227
|
+
justify-content: space-between;
|
|
2228
|
+
gap: var(--space-2);
|
|
2229
|
+
font-size: 12px;
|
|
2230
|
+
color: var(--text-secondary);
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
.factor-list strong { font-family: var(--font-mono); color: var(--text-primary); font-weight: 500; }
|
|
2234
|
+
|
|
2235
|
+
.harness-next {
|
|
2236
|
+
margin: 0;
|
|
2043
2237
|
color: var(--text-primary);
|
|
2044
|
-
|
|
2238
|
+
font-size: 12px;
|
|
2239
|
+
line-height: 1.5;
|
|
2045
2240
|
}
|
|
2046
2241
|
|
|
2047
|
-
.
|
|
2242
|
+
.evidence-list {
|
|
2048
2243
|
margin: 0;
|
|
2244
|
+
padding-left: 16px;
|
|
2049
2245
|
color: var(--text-secondary);
|
|
2050
|
-
font-size:
|
|
2051
|
-
|
|
2246
|
+
font-size: 11px;
|
|
2247
|
+
display: grid;
|
|
2248
|
+
gap: 3px;
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
.harness-card .link-button { margin-top: var(--space-1); justify-self: start; }
|
|
2252
|
+
|
|
2253
|
+
.history-section {
|
|
2254
|
+
margin-top: var(--space-6);
|
|
2255
|
+
border-top: 1px solid var(--border-default);
|
|
2256
|
+
padding-top: var(--space-4);
|
|
2257
|
+
}
|
|
2258
|
+
|
|
2259
|
+
.history-feed {
|
|
2260
|
+
margin: var(--space-3) 0 0;
|
|
2261
|
+
padding: 0;
|
|
2262
|
+
list-style: none;
|
|
2263
|
+
display: grid;
|
|
2264
|
+
gap: var(--space-2);
|
|
2265
|
+
}
|
|
2266
|
+
|
|
2267
|
+
.history-feed li {
|
|
2268
|
+
display: grid;
|
|
2269
|
+
grid-template-columns: 110px 1fr;
|
|
2270
|
+
gap: var(--space-3);
|
|
2271
|
+
align-items: start;
|
|
2272
|
+
border: 1px solid var(--border-default);
|
|
2273
|
+
border-radius: var(--radius-md);
|
|
2274
|
+
background: var(--bg-card);
|
|
2275
|
+
padding: var(--space-2) var(--space-3);
|
|
2052
2276
|
}
|
|
2053
2277
|
|
|
2278
|
+
.history-type {
|
|
2279
|
+
display: inline-block;
|
|
2280
|
+
font-family: var(--font-mono);
|
|
2281
|
+
font-size: 10px;
|
|
2282
|
+
text-transform: uppercase;
|
|
2283
|
+
letter-spacing: 0.05em;
|
|
2284
|
+
color: var(--text-secondary);
|
|
2285
|
+
border: 1px solid var(--border-default);
|
|
2286
|
+
border-radius: var(--radius-sm);
|
|
2287
|
+
padding: 3px 6px;
|
|
2288
|
+
margin-top: 2px;
|
|
2289
|
+
text-align: center;
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
.history-type.memory { color: var(--accent-text); border-color: var(--accent-dim); }
|
|
2293
|
+
.history-type.weave { color: var(--warning); border-color: var(--warning-dim); }
|
|
2294
|
+
.history-type.frog { color: var(--danger); border-color: var(--danger-dim); }
|
|
2295
|
+
.history-type.harness-create,
|
|
2296
|
+
.history-type.harness-edit { color: var(--success); border-color: var(--success-dim); }
|
|
2297
|
+
|
|
2298
|
+
.history-feed strong { font-size: 12px; font-weight: 500; }
|
|
2299
|
+
|
|
2300
|
+
.history-harnesses {
|
|
2301
|
+
margin: 2px 0 0;
|
|
2302
|
+
color: var(--text-secondary);
|
|
2303
|
+
font-size: 11px;
|
|
2304
|
+
font-family: var(--font-mono);
|
|
2305
|
+
}
|
|
2306
|
+
|
|
2307
|
+
.history-files { margin: 4px 0 0; display: flex; flex-wrap: wrap; gap: 4px; }
|
|
2308
|
+
|
|
2054
2309
|
.harness-card dl,
|
|
2055
2310
|
.selected dl,
|
|
2056
2311
|
.graph-overview dl {
|
|
@@ -2359,7 +2614,7 @@ function renderStyles() {
|
|
|
2359
2614
|
}
|
|
2360
2615
|
.hero-sidebar { width: 100%; }
|
|
2361
2616
|
.project-strip-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
2362
|
-
.harness-grid,
|
|
2617
|
+
.harness-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
2363
2618
|
.stats-grid { grid-template-columns: 1fr; }
|
|
2364
2619
|
.home-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
|
2365
2620
|
.home-columns { grid-template-columns: 1fr; }
|
|
@@ -2439,13 +2694,19 @@ function renderReport(summary) {
|
|
|
2439
2694
|
<section class="page-head">
|
|
2440
2695
|
<p class="eyebrow">${escapeHtml(copy.harnessesEyebrow || 'HARNESSES')}</p>
|
|
2441
2696
|
<h1>${escapeHtml(copy.harnessCards)}</h1>
|
|
2442
|
-
<p>${escapeHtml(copy.harnessesHelp || '')}</p>
|
|
2697
|
+
<p>${escapeHtml(copy.harnessesHelp || '')} · ${escapeHtml(copy.sortNote || 'Sorted by usage')}</p>
|
|
2443
2698
|
</section>
|
|
2444
2699
|
<section class="harness-section">
|
|
2445
2700
|
<div class="harness-grid">
|
|
2446
|
-
${harnesses
|
|
2701
|
+
${[...harnesses]
|
|
2702
|
+
.sort((a, b) =>
|
|
2703
|
+
Number(b.signals?.uses || 0) - Number(a.signals?.uses || 0) ||
|
|
2704
|
+
Number(b.candidate_score?.total || 0) - Number(a.candidate_score?.total || 0) ||
|
|
2705
|
+
a.id.localeCompare(b.id))
|
|
2706
|
+
.map((item) => renderHarness(item, copy)).join('\n')}
|
|
2447
2707
|
</div>
|
|
2448
2708
|
</section>
|
|
2709
|
+
${renderHistorySection(summary.maintenance_events, copy)}
|
|
2449
2710
|
</section>
|
|
2450
2711
|
<section class="page" data-page="memory">
|
|
2451
2712
|
${renderMemoryPage(summary, copy)}
|