dsh-tacit 0.5.0 → 0.6.0

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.
Files changed (2) hide show
  1. package/client/client.js +333 -201
  2. package/package.json +1 -1
package/client/client.js CHANGED
@@ -108,12 +108,15 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
108
108
  'steer.receiptEvaluated': '评定于',
109
109
  'steer.receiptVersion': '版本',
110
110
  'steer.receiptTrial': '试用窗口',
111
- 'steer.receiptTrialValue': '{turns} 轮,始于 {started} · 基线:杂乱 {messy}、纠正 {corrected}',
111
+ 'steer.receiptTurns': '{n} ',
112
+ 'steer.receiptTrialNote': '始于 {started} · 基线:杂乱 {messy}、纠正 {corrected}',
113
+ 'steer.receiptCalls': '{n} 次调用',
114
+ 'steer.enabled': '启用',
115
+ 'steer.options': '选项',
112
116
  'steer.receiptTriggers': '触发类别',
113
117
  'steer.receiptEvidence': '证据',
114
118
  'steer.receiptEvidenceValue': '{turns} 轮,来自 {conversations} 个会话',
115
119
  'steer.receiptCost': '提炼花费',
116
- 'steer.receiptCostValue': '{usd} · {calls} 次调用',
117
120
  'steer.moveTo': '移到工作区',
118
121
  'steer.notSeen': '自 {date} 起未见',
119
122
  'settings.auto': '自动分析混乱轮次',
@@ -394,12 +397,15 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
394
397
  'steer.receiptEvaluated': 'Evaluated',
395
398
  'steer.receiptVersion': 'Version',
396
399
  'steer.receiptTrial': 'Trial window',
397
- 'steer.receiptTrialValue': '{turns} turns from {started} · baseline messy {messy}, corrections {corrected}',
400
+ 'steer.receiptTurns': '{n} turns',
401
+ 'steer.receiptTrialNote': 'from {started} · baseline messy {messy}, corrections {corrected}',
402
+ 'steer.receiptCalls': '{n} calls',
403
+ 'steer.enabled': 'Enabled',
404
+ 'steer.options': 'Options',
398
405
  'steer.receiptTriggers': 'Trigger categories',
399
406
  'steer.receiptEvidence': 'Evidence',
400
407
  'steer.receiptEvidenceValue': '{turns} turns across {conversations} conversations',
401
408
  'steer.receiptCost': 'Distillation cost',
402
- 'steer.receiptCostValue': '{usd} · {calls} calls',
403
409
  'steer.moveTo': 'Move to workspace',
404
410
  'steer.notSeen': 'not seen since {date}',
405
411
  'settings.auto': 'Auto-analyze messy turns',
@@ -1878,7 +1884,13 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1878
1884
  return h('div', { className: 'tacit-progress' },
1879
1885
  h('div', { className: 'tacit-progress-head' },
1880
1886
  h('span', { className: 'tacit-progress-title' }, t('status.learned', { count: String(analyzed) })),
1881
- h('span', { className: 'tacit-progress-count' }, autoOn ? t('status.autoOn', { today: String(today), budget: String(budget) }) : '')),
1887
+ // The same badge idiom the directive cards use: a dot plus a label,
1888
+ // tinted by state. Off is said in the line below, not twice.
1889
+ autoOn
1890
+ ? h('span', { className: 'tacit-badge tacit-badge-active' },
1891
+ h('span', { className: 'tacit-badge-dot', 'aria-hidden': 'true' }),
1892
+ t('status.autoOn', { today: String(today), budget: String(budget) }))
1893
+ : null),
1882
1894
  h('div', { className: 'tacit-progress-text' }, autoOn ? t('status.autoHint') : t('status.autoOff')),
1883
1895
  hasTrend
1884
1896
  ? h('div', { className: 'tacit-trend', title: t('status.trendDocs') },
@@ -1977,8 +1989,10 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1977
1989
  const status = turn.finished === true
1978
1990
  ? null
1979
1991
  : (isNewest === true
1980
- ? h('span', { className: 'tacit-row-live' }, t('turn.running'))
1981
- : h('span', { className: 'tacit-chip tacit-chip-muted' }, t('turn.interrupted')))
1992
+ ? h('span', { className: 'tacit-badge tacit-badge-active' },
1993
+ h('span', { className: 'tacit-badge-dot', 'aria-hidden': 'true' }),
1994
+ t('turn.running'))
1995
+ : h('span', { className: 'tacit-badge tacit-badge-muted' }, t('turn.interrupted')))
1982
1996
 
1983
1997
  return h('div', { className: 'tacit-row' + (report !== null ? ' tacit-row-analyzed' : '') },
1984
1998
  h('div', { className: 'tacit-row-head' },
@@ -1996,35 +2010,47 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1996
2010
  h('span', { className: 'tacit-row-time' }, fmtTime(turn.startedAt)),
1997
2011
  report !== null ? h('span', { className: 'tacit-chip tacit-chip-trigger' }, t('trigger.' + report.trigger)) : null,
1998
2012
  status),
1999
- h('div', { className: 'tacit-row-chips' },
2000
- h('span', { className: 'tacit-chip' }, t('turn.tools', { n: String(tools) })),
2001
- h('span', { className: 'tacit-chip' }, t('turn.steps', { n: String(typeof turn.steps === 'number' ? turn.steps : 0) })),
2002
- h('span', { className: 'tacit-chip' }, t('turn.tokens', { n: fmt(tokens) })),
2003
- typeof turn.retries === 'number' && turn.retries > 0
2004
- ? h('span', { className: 'tacit-chip tacit-chip-warn' }, t('turn.retries', { n: String(turn.retries) }))
2005
- : null,
2013
+ // Two controls only, and the row's own action is the solid one:
2014
+ // opening the report is a disclosure, so it stays quiet.
2015
+ h('div', { className: 'tacit-row-actions' },
2006
2016
  report !== null
2007
- ? h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: () => toggleReport(store, turn.turn) },
2008
- t('turn.report') + (reportOpen ? ' ▾' : ''))
2017
+ ? h('button', {
2018
+ type: 'button',
2019
+ className: 'tacit-btn tacit-btn-sm tacit-btn-quiet',
2020
+ 'aria-expanded': reportOpen,
2021
+ onClick: () => toggleReport(store, turn.turn),
2022
+ }, t('turn.report'),
2023
+ h('span', { className: 'tacit-chevron' + (reportOpen ? ' tacit-chevron-open' : ''), 'aria-hidden': 'true' }, '›'))
2009
2024
  : null,
2010
2025
  h('button', {
2011
2026
  type: 'button',
2012
- className: 'tacit-btn tacit-btn-sm tacit-btn-quiet',
2027
+ className: 'tacit-btn tacit-btn-sm',
2013
2028
  disabled: analyzing,
2014
2029
  onClick: () => analyzeTurn(store, turn.turn),
2015
2030
  }, analyzing ? t('turn.analyzing') : (report !== null ? t('turn.reanalyze') : t('turn.analyze'))))),
2016
2031
  prompt.length > 0
2017
2032
  ? h('div', { className: 'tacit-row-prompt' },
2018
- h('button', {
2019
- type: 'button',
2020
- className: 'tacit-row-prompt-text',
2021
- onClick: () => setExpanded((open) => !open),
2022
- }, expanded ? prompt : promptPreview),
2033
+ // A long prompt is one control: the text itself toggles, and the
2034
+ // trailing word says so. A short one is plain text.
2023
2035
  prompt.length > 120
2024
- ? h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: () => setExpanded((open) => !open) },
2025
- expanded ? t('turn.collapse') : t('turn.expand'))
2026
- : null)
2036
+ ? h('button', {
2037
+ type: 'button',
2038
+ className: 'tacit-row-prompt-text',
2039
+ 'aria-expanded': expanded,
2040
+ onClick: () => setExpanded((open) => !open),
2041
+ }, expanded ? prompt : promptPreview,
2042
+ h('span', { className: 'tacit-row-more' }, expanded ? t('turn.collapse') : t('turn.expand')))
2043
+ : h('div', { className: 'tacit-row-prompt-text tacit-row-prompt-static' }, prompt))
2027
2044
  : null,
2045
+ // The measurements are context, not headline: one quiet dot-separated
2046
+ // line under the prompt rather than four bordered chips in the header.
2047
+ h('div', { className: 'tacit-row-meta' },
2048
+ h('span', null, t('turn.tools', { n: String(tools) })),
2049
+ h('span', null, t('turn.steps', { n: String(typeof turn.steps === 'number' ? turn.steps : 0) })),
2050
+ h('span', null, t('turn.tokens', { n: fmt(tokens) })),
2051
+ typeof turn.retries === 'number' && turn.retries > 0
2052
+ ? h('span', { className: 'tacit-row-meta-warn' }, t('turn.retries', { n: String(turn.retries) }))
2053
+ : null),
2028
2054
  typeof turn.enrichment === 'string' && turn.enrichment.length > 0
2029
2055
  ? h('div', { className: 'tacit-row-enrichment' },
2030
2056
  h('span', { className: 'tacit-report-title' }, t('turn.enrichment')),
@@ -2088,35 +2114,33 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2088
2114
 
2089
2115
  return h('div', { className: 'tacit-settings' },
2090
2116
  h('div', { className: 'tacit-settings-title' }, t('settings.title')),
2091
- h('div', { className: 'tacit-settings-row' },
2092
- h('label', { className: 'tacit-settings-label' }, t('settings.model')),
2093
- h('select', {
2094
- className: 'tacit-select',
2095
- value: model,
2096
- onChange: (event) => applyModel(event.target.value),
2097
- },
2098
- h('option', { value: 'deepseek-v4-flash' }, 'deepseek-v4-flash'),
2099
- h('option', { value: 'deepseek-v4-pro' }, 'deepseek-v4-pro'))),
2100
- h('div', { className: 'tacit-settings-row' },
2101
- h('label', { className: 'tacit-settings-label' }, t('settings.auto')),
2102
- h('input', { type: 'checkbox', checked: auto, onChange: toggleAuto })),
2103
- h('div', { className: 'tacit-settings-row' },
2104
- h('label', { className: 'tacit-settings-label' }, t('settings.learnGood')),
2105
- h('input', { type: 'checkbox', checked: learnGood, onChange: toggleLearnGood })),
2106
- h('div', { className: 'tacit-settings-row' },
2107
- h('label', { className: 'tacit-settings-label' }, t('settings.budget')),
2117
+ FieldRow(t('settings.model'), h('select', {
2118
+ id: 'tacit-tab-model',
2119
+ className: 'tacit-select',
2120
+ value: model,
2121
+ onChange: (event) => applyModel(event.target.value),
2122
+ },
2123
+ h('option', { value: 'deepseek-v4-flash' }, 'deepseek-v4-flash'),
2124
+ h('option', { value: 'deepseek-v4-pro' }, 'deepseek-v4-pro')), 'tacit-tab-model'),
2125
+ FieldRow(t('settings.budget'), [
2108
2126
  h('input', {
2127
+ key: 'input',
2128
+ id: 'tacit-tab-budget',
2109
2129
  className: 'tacit-input',
2110
2130
  type: 'number',
2111
2131
  min: 0,
2112
2132
  value: budgetText,
2113
2133
  onChange: (event) => setBudgetText(event.target.value),
2114
2134
  }),
2115
- h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: applyBudget }, t('settings.apply'))),
2116
- h('div', { className: 'tacit-settings-row' },
2117
- h('label', { className: 'tacit-settings-label' }, t('settings.live')),
2118
- h('input', { type: 'checkbox', checked: live, onChange: toggleLive })),
2119
- h('div', { className: 'tacit-settings-row' },
2135
+ h('button', { key: 'apply', type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: applyBudget }, t('settings.apply')),
2136
+ ], 'tacit-tab-budget'),
2137
+ // The three switches read as one group of clickable sentences, the way
2138
+ // the Agent guidance options do.
2139
+ h('div', { className: 'tacit-options' },
2140
+ OptionRow(t('settings.auto'), auto, toggleAuto),
2141
+ OptionRow(t('settings.learnGood'), learnGood, toggleLearnGood),
2142
+ OptionRow(t('settings.live'), live, toggleLive)),
2143
+ h('div', { className: 'tacit-inline' },
2120
2144
  h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: onClear }, t('settings.clear')),
2121
2145
  notice !== null ? h('span', { className: 'tacit-settings-notice' }, notice) : null))
2122
2146
  }
@@ -2148,7 +2172,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2148
2172
  h('div', { className: 'tacit-head-title' }, t('tab')),
2149
2173
  h('button', {
2150
2174
  type: 'button',
2151
- className: 'tacit-btn',
2175
+ className: 'tacit-btn tacit-btn-sm tacit-btn-quiet',
2152
2176
  onClick: () => setSettingsOpen((open) => !open),
2153
2177
  }, settingsOpen ? t('settings.close') : t('settings'))),
2154
2178
  StatusCard(kit, { config, profile, auto: store.auto }),
@@ -2168,11 +2192,10 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2168
2192
  ? h('div', { className: 'tacit-empty' }, t('empty'))
2169
2193
  : h('div', null,
2170
2194
  h('div', { className: 'tacit-toolbar' },
2171
- h('span', { className: 'tacit-panel-hint tacit-toolbar-hint' }, t('manual.hint')),
2172
2195
  BootstrapButton(kit, { bootstrap: store.bootstrap, onClick: () => bootstrapSession(store) }),
2173
2196
  h('button', {
2174
2197
  type: 'button',
2175
- className: 'tacit-btn tacit-btn-sm',
2198
+ className: 'tacit-btn tacit-btn-sm' + (store.selecting ? '' : ' tacit-btn-quiet'),
2176
2199
  onClick: () => toggleSelecting(store),
2177
2200
  }, store.selecting ? t('coach.selectDone') : t('coach.select')),
2178
2201
  store.selecting
@@ -2183,6 +2206,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2183
2206
  onClick: () => coachSelected(store),
2184
2207
  }, store.batchRunning ? t('coach.batchRunning') : t('coach.selected', { n: String(selectedCount) }))
2185
2208
  : null),
2209
+ h('div', { className: 'tacit-toolbar-note' }, t('manual.hint')),
2186
2210
  turns.map((turn, index) => h(TurnRow, { key: String(turn.turn), kit, store, turn, isNewest: index === 0 }))))
2187
2211
  }
2188
2212
  }
@@ -2242,21 +2266,23 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2242
2266
  : preview.error !== null
2243
2267
  ? h('div', { className: 'tacit-error' },
2244
2268
  t('err.' + String(preview.error.code), { detail: String(preview.error.detail || '') }))
2245
- : h('div', null,
2269
+ // What changed is the one sentence that decides Apply, so it
2270
+ // reads before the two columns rather than under them.
2271
+ : h('div', { className: 'tacit-modal-body' },
2272
+ preview.data !== null && typeof preview.data === 'object' && typeof preview.data.rationale === 'string' && preview.data.rationale.length > 0
2273
+ ? h('div', { className: 'tacit-modal-rationale' },
2274
+ h('div', { className: 'tacit-modal-col-title' }, t('preview.rationale')),
2275
+ h('div', { className: 'tacit-modal-rationale-text' }, preview.data.rationale))
2276
+ : null,
2246
2277
  unchanged
2247
2278
  ? h('div', { className: 'tacit-modal-unchanged' }, t('preview.unchanged'))
2248
2279
  : h('div', { className: 'tacit-modal-cols' },
2249
2280
  h('div', { className: 'tacit-modal-col' },
2250
2281
  h('div', { className: 'tacit-modal-col-title' }, t('preview.original')),
2251
2282
  h('pre', { className: 'tacit-pre' }, preview.original)),
2252
- h('div', { className: 'tacit-modal-col' },
2283
+ h('div', { className: 'tacit-modal-col tacit-modal-col-improved' },
2253
2284
  h('div', { className: 'tacit-modal-col-title' }, t('preview.improved')),
2254
2285
  h('pre', { className: 'tacit-pre' }, improvedText))),
2255
- preview.data !== null && typeof preview.data === 'object' && typeof preview.data.rationale === 'string' && preview.data.rationale.length > 0
2256
- ? h('div', { className: 'tacit-modal-rationale' },
2257
- h('div', { className: 'tacit-modal-col-title' }, t('preview.rationale')),
2258
- h('div', { className: 'tacit-modal-rationale-text' }, preview.data.rationale))
2259
- : null,
2260
2286
  h('div', { className: 'tacit-modal-actions' },
2261
2287
  unchanged
2262
2288
  ? null
@@ -2337,6 +2363,37 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2337
2363
 
2338
2364
  // ── Collapsible section card (Settings → Tacit) ────────────────────────
2339
2365
 
2366
+ /**
2367
+ * One settings row: a label that takes the slack and wraps, and its
2368
+ * control(s) right-aligned. `htmlFor` names the control when it has an id;
2369
+ * checkbox settings use `OptionRow` instead, which is a label all through.
2370
+ */
2371
+ function FieldRow(label, control, htmlFor) {
2372
+ const controls = Array.isArray(control) ? control : [control]
2373
+ return h('div', { className: 'tacit-field' },
2374
+ h('label', {
2375
+ className: 'tacit-field-label',
2376
+ ...(typeof htmlFor === 'string' && htmlFor.length > 0 ? { htmlFor } : {}),
2377
+ }, label),
2378
+ h('div', { className: 'tacit-field-control' }, ...controls))
2379
+ }
2380
+
2381
+ /**
2382
+ * One checkbox setting as a clickable `<label>`, so the hit target is the
2383
+ * whole sentence rather than a 14px box.
2384
+ */
2385
+ function OptionRow(label, checked, onChange, extra) {
2386
+ return h('label', { className: 'tacit-option' },
2387
+ h('input', {
2388
+ type: 'checkbox',
2389
+ className: 'tacit-check',
2390
+ checked,
2391
+ onChange,
2392
+ ...(extra !== null && typeof extra === 'object' ? extra : {}),
2393
+ }),
2394
+ h('span', null, label))
2395
+ }
2396
+
2340
2397
  /**
2341
2398
  * One accessible collapsible card.
2342
2399
  *
@@ -2366,10 +2423,15 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2366
2423
  typeof summary === 'string' && summary.length > 0
2367
2424
  ? h('span', { className: 'tacit-card-summary' }, summary)
2368
2425
  : null,
2369
- count !== undefined && count !== null
2426
+ // A zero count is silence, not a figure worth a chip.
2427
+ typeof count === 'number' && count > 0
2370
2428
  ? h('span', { className: 'tacit-card-count' }, String(count))
2371
2429
  : null,
2372
- h('span', { className: 'tacit-card-chevron', 'aria-label': label, title: label }, isOpen ? '▾' : '▸')),
2430
+ h('span', {
2431
+ className: 'tacit-chevron tacit-card-chevron' + (isOpen ? ' tacit-chevron-open' : ''),
2432
+ 'aria-label': label,
2433
+ title: label,
2434
+ }, '›')),
2373
2435
  h('div', { className: 'tacit-card-body', id: bodyId, hidden: !isOpen }, ...kids))
2374
2436
  }
2375
2437
 
@@ -2444,7 +2506,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2444
2506
  },
2445
2507
  },
2446
2508
  h('div', {
2447
- className: 'tacit-modal-card',
2509
+ className: 'tacit-modal-card tacit-modal-card-sm',
2448
2510
  role: 'dialog',
2449
2511
  'aria-modal': 'true',
2450
2512
  'aria-labelledby': 'tacit-confirm-title',
@@ -2476,31 +2538,54 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2476
2538
  if (typeof navigator === 'undefined' || navigator === null || !navigator.clipboard || typeof navigator.clipboard.writeText !== 'function') return
2477
2539
  navigator.clipboard.writeText(JSON.stringify(receipt, null, 2)).catch(() => {})
2478
2540
  }
2479
- const receiptRow = (label, value) => [h('dt', { key: label + '-t' }, label), h('dd', { key: label + '-d' }, value)]
2480
- /** What the receipt route returned for this directive, as definition rows; never any prompt text. */
2541
+ const metaRow = (label, value) => [h('dt', { key: label + '-t' }, label), h('dd', { key: label + '-d' }, value)]
2542
+ /** A null `note` marks an absent value ("never", "no ledger run"), shown quiet rather than as a headline figure. */
2543
+ const tile = (key, label, value, note) => h('div', { key, className: 'tacit-tile tacit-receipt-tile' },
2544
+ h('span', { className: 'tacit-tile-label' }, label),
2545
+ h('span', { className: 'tacit-tile-value' + (note === null ? ' tacit-tile-muted' : '') }, value),
2546
+ note === null ? null : h('span', { className: 'tacit-receipt-tile-note' }, note))
2547
+ const step = (key, label, ms) => h('li', { key, className: 'tacit-timeline-step' + (Number(ms) > 0 ? '' : ' tacit-timeline-never') },
2548
+ h('span', { className: 'tacit-timeline-label' }, label),
2549
+ h('span', { className: 'tacit-timeline-value' }, fmtDay(ms)))
2550
+ /**
2551
+ * What the receipt route returned for this directive, layered: three
2552
+ * tiles, a lifecycle timeline, the trigger chips, then the identity grid;
2553
+ * never any prompt text.
2554
+ */
2481
2555
  function Receipt(receipt) {
2482
2556
  if (receipt === null || typeof receipt === 'object' === false) return h('div', { className: 'tacit-panel-hint' }, t('steer.receiptLoading'))
2483
2557
  const triggers = Object.entries(receipt.triggers !== null && typeof receipt.triggers === 'object' ? receipt.triggers : {})
2484
- .map(([name, count]) => triggerName(name) + ' ' + String(count)).join(' · ')
2485
2558
  const evidence = receipt.evidence !== null && typeof receipt.evidence === 'object' ? receipt.evidence : { turns: 0, conversations: 0 }
2486
2559
  const cost = receipt.cost !== null && typeof receipt.cost === 'object' ? receipt.cost : { usd: null, calls: 0 }
2487
2560
  const trial = receipt.trial !== null && typeof receipt.trial === 'object' ? receipt.trial : null
2488
- return h('div', null,
2489
- h('dl', { className: 'tacit-receipt' },
2490
- ...receiptRow(t('steer.receiptId'), String(receipt.id)),
2491
- ...receiptRow(t('steer.receiptScope'), typeof receipt.scope === 'string' && receipt.scope.length > 0 ? receipt.scope : t('steer.everywhere')),
2492
- ...receiptRow(t('steer.receiptStatus'), String(receipt.status)),
2493
- ...receiptRow(t('steer.receiptSource'), receipt.source === 'user' ? t('steer.user') : t('steer.distilled')),
2494
- ...receiptRow(t('steer.receiptCreated'), fmtDay(receipt.createdAt)),
2495
- ...receiptRow(t('steer.receiptUpdated'), fmtDay(receipt.updatedAt)),
2496
- ...receiptRow(t('steer.receiptEvaluated'), fmtDay(receipt.evaluatedAt)),
2497
- ...receiptRow(t('steer.receiptVersion'), String(receipt.version)),
2498
- ...receiptRow(t('steer.receiptTrial'), trial === null ? t('steer.receiptNever') : t('steer.receiptTrialValue', {
2499
- turns: String(trial.turns), started: fmtDay(trial.startedAt), messy: pct(trial.baselineMessyRate), corrected: pct(trial.baselineCorrectionRate) })),
2500
- ...receiptRow(t('steer.receiptTriggers'), triggers.length > 0 ? triggers : t('steer.receiptNever')),
2501
- ...receiptRow(t('steer.receiptEvidence'), t('steer.receiptEvidenceValue', { turns: String(evidence.turns), conversations: String(evidence.conversations) })),
2502
- ...receiptRow(t('steer.receiptCost'), cost.usd === null ? t('steer.receiptNoRun') : t('steer.receiptCostValue', { usd: fmtUsd(cost.usd), calls: String(cost.calls) }))),
2503
- h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: () => copyReceipt(receipt) }, t('steer.receiptCopy')))
2561
+ return h('div', { className: 'tacit-receipt' },
2562
+ h('div', { className: 'tacit-tiles tacit-receipt-tiles' },
2563
+ tile('evidence', t('steer.receiptEvidence'), String(evidence.turns),
2564
+ t('steer.receiptEvidenceValue', { turns: String(evidence.turns), conversations: String(evidence.conversations) })),
2565
+ tile('trial', t('steer.receiptTrial'),
2566
+ trial === null ? t('steer.receiptNever') : t('steer.receiptTurns', { n: String(trial.turns) }),
2567
+ trial === null ? null : t('steer.receiptTrialNote', {
2568
+ started: fmtDay(trial.startedAt), messy: pct(trial.baselineMessyRate), corrected: pct(trial.baselineCorrectionRate) })),
2569
+ tile('cost', t('steer.receiptCost'),
2570
+ cost.usd === null ? t('steer.receiptNoRun') : fmtUsd(cost.usd),
2571
+ cost.usd === null ? null : t('steer.receiptCalls', { n: String(cost.calls) }))),
2572
+ h('ol', { className: 'tacit-timeline' },
2573
+ step('created', t('steer.receiptCreated'), receipt.createdAt),
2574
+ step('updated', t('steer.receiptUpdated'), receipt.updatedAt),
2575
+ step('evaluated', t('steer.receiptEvaluated'), receipt.evaluatedAt)),
2576
+ h('div', { className: 'tacit-receipt-row' },
2577
+ h('span', { className: 'tacit-receipt-label' }, t('steer.receiptTriggers')),
2578
+ triggers.length === 0
2579
+ ? h('span', { className: 'tacit-chip tacit-chip-muted' }, t('steer.receiptNever'))
2580
+ : triggers.map(([name, count]) => h('span', { key: name, className: 'tacit-chip' }, triggerName(name) + ' ' + String(count)))),
2581
+ h('dl', { className: 'tacit-receipt-meta' },
2582
+ ...metaRow(t('steer.receiptId'), String(receipt.id)),
2583
+ ...metaRow(t('steer.receiptVersion'), String(receipt.version)),
2584
+ ...metaRow(t('steer.receiptScope'), typeof receipt.scope === 'string' && receipt.scope.length > 0 ? receipt.scope : t('steer.everywhere')),
2585
+ ...metaRow(t('steer.receiptSource'), receipt.source === 'user' ? t('steer.user') : t('steer.distilled')),
2586
+ ...metaRow(t('steer.receiptStatus'), String(receipt.status))),
2587
+ h('div', { className: 'tacit-receipt-actions' },
2588
+ h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: () => copyReceipt(receipt) }, t('steer.receiptCopy'))))
2504
2589
  }
2505
2590
  return function DirectivesEditorView(props) {
2506
2591
  const { config, steering } = props
@@ -2553,23 +2638,42 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2553
2638
  setDraft('')
2554
2639
  editDirectives({ action: 'add', text: text.slice(0, 300), ...(scope.length > 0 ? { workspace: scope } : {}) })
2555
2640
  }
2556
- return h('div', { className: 'tacit-panel-section', 'data-testid': 'tacit-steering' },
2557
- h('div', { className: 'tacit-report-title' }, t('steer.title')),
2558
- h('div', { className: 'tacit-panel-hint' }, t('steer.desc')),
2559
- h('div', { className: 'tacit-settings-row' },
2560
- h('label', { className: 'tacit-settings-label' }, t('steer.toggle')),
2561
- h('input', { type: 'checkbox', checked: steerOn, onChange: toggleSteer })),
2562
- h('div', { className: 'tacit-settings-row' },
2563
- h('label', { className: 'tacit-settings-label' }, t('steer.enrich')),
2564
- h('input', { type: 'checkbox', checked: enrichOn, onChange: toggleEnrich })),
2565
- h('div', { className: 'tacit-settings-row' },
2566
- h('label', { className: 'tacit-settings-label' }, t('steer.review')),
2567
- h('input', { type: 'checkbox', checked: reviewOn, onChange: toggleReview })),
2568
- directives.length === 0
2569
- ? h('div', { className: 'tacit-empty' }, t('steer.empty'))
2570
- : h('div', { className: 'tacit-rules-list' },
2571
- directives.map((entry) => h('div', { key: entry.id, className: 'tacit-directive-block' },
2572
- h('div', { className: 'tacit-rule tacit-directive' + (entry.enabled === false ? ' tacit-directive-off' : '') },
2641
+ /** The lifecycle badge: one colour per status, the label the chips used to carry. */
2642
+ const statusOf = (entry) => {
2643
+ if (entry.status === 'queued') return { kind: 'queued', label: t('steer.queued') }
2644
+ if (entry.status === 'candidate') {
2645
+ return {
2646
+ kind: 'trial',
2647
+ label: t('steer.trial', {
2648
+ n: String(entry.trial !== null && typeof entry.trial === 'object' && typeof entry.trial.turns === 'number' ? entry.trial.turns : 0),
2649
+ total: String(config !== null && typeof config.directiveTrialTurns === 'number' ? config.directiveTrialTurns : 10),
2650
+ }),
2651
+ }
2652
+ }
2653
+ if (entry.status === 'retired') return { kind: 'retired', label: t('steer.retired', { reason: String(entry.retiredReason || '') }) }
2654
+ return { kind: 'active', label: t('steer.active') }
2655
+ }
2656
+ const directiveCard = (entry) => {
2657
+ const status = statusOf(entry)
2658
+ const scoped = typeof entry.workspace === 'string' && entry.workspace.length > 0
2659
+ return h('div', { key: entry.id, className: 'tacit-dir tacit-dir-' + status.kind + (entry.enabled === false ? ' tacit-dir-off' : '') },
2660
+ h('div', { className: 'tacit-dir-head' },
2661
+ h('span', { className: 'tacit-badge tacit-badge-' + status.kind },
2662
+ h('span', { className: 'tacit-badge-dot', 'aria-hidden': 'true' }),
2663
+ status.label),
2664
+ h('span', { className: 'tacit-chip' }, entry.source === 'user' ? t('steer.user') : t('steer.distilled')),
2665
+ scoped
2666
+ ? h('span', { className: 'tacit-chip tacit-chip-scope', title: entry.workspace }, t('steer.workspace', { name: labelOf(entry.workspace) }))
2667
+ : null,
2668
+ scoped && !liveScope(entry.workspace)
2669
+ ? h('span', { className: 'tacit-chip tacit-chip-muted', title: entry.workspace }, t('steer.notSeen', { date: notSeenSince(entry) }))
2670
+ : null,
2671
+ reviewOn && entry.status === 'queued' && !(entry.approvedAt > 0)
2672
+ ? h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm tacit-btn-primary tacit-dir-start', onClick: () => editDirectives({ action: 'start-trial', id: entry.id }) }, t('steer.startTrial'))
2673
+ : null),
2674
+ h('div', { className: 'tacit-dir-text' }, String(entry.text)),
2675
+ h('div', { className: 'tacit-dir-actions' },
2676
+ h('label', { className: 'tacit-dir-enabled' },
2573
2677
  h('input', {
2574
2678
  type: 'checkbox',
2575
2679
  className: 'tacit-check',
@@ -2577,46 +2681,33 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2577
2681
  checked: entry.enabled !== false,
2578
2682
  onChange: () => editDirectives({ action: 'toggle', id: entry.id, enabled: entry.enabled === false }),
2579
2683
  }),
2580
- h('span', { className: 'tacit-directive-text' }, String(entry.text)),
2581
- h('span', { className: 'tacit-chip' }, entry.source === 'user' ? t('steer.user') : t('steer.distilled')),
2582
- typeof entry.workspace === 'string' && entry.workspace.length > 0
2583
- ? h('span', { className: 'tacit-chip tacit-chip-scope', title: entry.workspace }, t('steer.workspace', { name: labelOf(entry.workspace) }))
2584
- : null,
2585
- typeof entry.workspace === 'string' && entry.workspace.length > 0 && !liveScope(entry.workspace)
2586
- ? h('span', { className: 'tacit-chip tacit-chip-muted', title: entry.workspace }, t('steer.notSeen', { date: notSeenSince(entry) }))
2587
- : null,
2588
- entry.status === 'queued'
2589
- ? h('span', { className: 'tacit-chip tacit-chip-muted' }, t('steer.queued'))
2590
- : entry.status === 'candidate'
2591
- ? h('span', { className: 'tacit-chip tacit-chip-trial' }, t('steer.trial', {
2592
- n: String(entry.trial !== null && typeof entry.trial === 'object' && typeof entry.trial.turns === 'number' ? entry.trial.turns : 0),
2593
- total: String(config !== null && typeof config.directiveTrialTurns === 'number' ? config.directiveTrialTurns : 10),
2594
- }))
2595
- : entry.status === 'retired'
2596
- ? h('span', { className: 'tacit-chip tacit-chip-warn' }, t('steer.retired', { reason: String(entry.retiredReason || '') }))
2597
- : h('span', { className: 'tacit-chip tacit-chip-ok' }, t('steer.active')),
2598
- reviewOn && entry.status === 'queued' && !(entry.approvedAt > 0)
2599
- ? h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: () => editDirectives({ action: 'start-trial', id: entry.id }) }, t('steer.startTrial'))
2600
- : null,
2601
- h('select', {
2602
- className: 'tacit-input tacit-select tacit-select-sm',
2603
- 'aria-label': t('steer.moveTo'),
2604
- onChange: (event) => {
2605
- if (event.target.value !== '-') editDirectives({ action: 'rescope', id: entry.id, workspace: event.target.value })
2606
- },
2607
- }, ...scopeOptions(typeof entry.workspace === 'string' ? entry.workspace : '')),
2608
- h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: () => editDirectives({ action: 'remove', id: entry.id }) }, t('steer.remove'))),
2609
- h('details', {
2610
- className: 'tacit-preview',
2611
- 'data-testid': 'tacit-receipt',
2612
- 'data-directive-id': entry.id,
2613
- onToggle: (event) => {
2614
- if (event.target.open) fetchReceipt(entry.id)
2615
- },
2684
+ t('steer.enabled')),
2685
+ h('select', {
2686
+ className: 'tacit-input tacit-select tacit-select-sm',
2687
+ 'aria-label': t('steer.moveTo'),
2688
+ onChange: (event) => {
2689
+ if (event.target.value !== '-') editDirectives({ action: 'rescope', id: entry.id, workspace: event.target.value })
2616
2690
  },
2617
- h('summary', null, t('steer.receipt')),
2618
- Receipt(receipts[entry.id] ?? null))))),
2619
- h('div', { className: 'tacit-settings-row' },
2691
+ }, ...scopeOptions(typeof entry.workspace === 'string' ? entry.workspace : '')),
2692
+ h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm tacit-btn-quiet tacit-dir-remove', onClick: () => editDirectives({ action: 'remove', id: entry.id }) }, t('steer.remove'))),
2693
+ h('details', {
2694
+ className: 'tacit-dir-receipt',
2695
+ 'data-testid': 'tacit-receipt',
2696
+ 'data-directive-id': entry.id,
2697
+ onToggle: (event) => {
2698
+ if (event.target.open) fetchReceipt(entry.id)
2699
+ },
2700
+ },
2701
+ h('summary', null, t('steer.receipt')),
2702
+ Receipt(receipts[entry.id] ?? null)))
2703
+ }
2704
+ return h('div', { className: 'tacit-panel-section', 'data-testid': 'tacit-steering' },
2705
+ h('div', { className: 'tacit-report-title' }, t('steer.title')),
2706
+ h('div', { className: 'tacit-panel-hint' }, t('steer.desc')),
2707
+ directives.length === 0
2708
+ ? h('div', { className: 'tacit-empty' }, t('steer.empty'))
2709
+ : h('div', { className: 'tacit-dir-list' }, directives.map(directiveCard)),
2710
+ h('div', { className: 'tacit-dir-add' },
2620
2711
  h('input', {
2621
2712
  className: 'tacit-input tacit-directive-input',
2622
2713
  type: 'text',
@@ -2639,7 +2730,12 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2639
2730
  h('option', { value: '' }, t('steer.everywhere')),
2640
2731
  ...workspaces.map((entry) => h('option', { key: entry.cwd, value: entry.cwd }, entry.label)))
2641
2732
  : null,
2642
- h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', disabled: draft.trim().length === 0, onClick: onAdd }, t('steer.add'))),
2733
+ h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm tacit-btn-primary', disabled: draft.trim().length === 0, onClick: onAdd }, t('steer.add'))),
2734
+ h('div', { className: 'tacit-options' },
2735
+ h('div', { className: 'tacit-report-title' }, t('steer.options')),
2736
+ OptionRow(t('steer.toggle'), steerOn, toggleSteer),
2737
+ OptionRow(t('steer.enrich'), enrichOn, toggleEnrich),
2738
+ OptionRow(t('steer.review'), reviewOn, toggleReview)),
2643
2739
  steering !== null && typeof steering === 'object' && typeof steering.text === 'string' && steering.text.length > 0
2644
2740
  ? h('details', { className: 'tacit-preview' },
2645
2741
  h('summary', null, t('steer.preview')),
@@ -2789,19 +2885,15 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2789
2885
  h('div', { className: 'tacit-settings-notice', role: 'status' }, notice === null ? '' : notice.text),
2790
2886
  card('overview', [
2791
2887
  StatusCard(kit, { config, profile, auto: rootStore.auto, trend: rootStore.trend }),
2792
- config !== null && typeof config.model === 'string' && config.model.length > 0
2793
- ? h('div', { className: 'tacit-settings-row' },
2794
- h('span', { className: 'tacit-chip' }, t('overview.model', { model: config.model })))
2795
- : null,
2796
- h('div', { className: 'tacit-settings-row' },
2888
+ h('div', { className: 'tacit-inline' },
2797
2889
  BootstrapButton(kit, {
2798
2890
  bootstrap: rootStore.bootstrap,
2799
2891
  // Only a loaded preview may disable the button: before one
2800
2892
  // lands, "0 eligible" is an absence of data, not a fact.
2801
2893
  disabled: preview !== null && preview.eligible === 0,
2802
2894
  onClick: () => bootstrapAll(t),
2803
- }),
2804
- h('span', { className: 'tacit-panel-hint' }, t('bootstrap.hint'))),
2895
+ })),
2896
+ h('p', { className: 'tacit-panel-hint' }, t('bootstrap.hint')),
2805
2897
  // What the run would actually cost, priced from the ledger once it
2806
2898
  // holds enough analyses; until the preview lands, the documented
2807
2899
  // figure stands in.
@@ -2840,41 +2932,40 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2840
2932
  }),
2841
2933
  ], { summary: pricingSummary(kit, usagePricing) }),
2842
2934
  card('learning', [
2843
- h('div', { className: 'tacit-settings-row' },
2844
- h('label', { className: 'tacit-settings-label' }, t('settings.model')),
2845
- h('select', {
2846
- className: 'tacit-select',
2847
- value: model,
2848
- onChange: (event) => applyModel(event.target.value),
2849
- },
2850
- h('option', { value: 'deepseek-v4-flash' }, 'deepseek-v4-flash'),
2851
- h('option', { value: 'deepseek-v4-pro' }, 'deepseek-v4-pro'))),
2852
- h('div', { className: 'tacit-settings-row' },
2853
- h('label', { className: 'tacit-settings-label' }, t('settings.auto')),
2854
- h('input', { type: 'checkbox', checked: auto, onChange: toggleAuto })),
2855
- h('div', { className: 'tacit-settings-row' },
2856
- h('label', { className: 'tacit-settings-label' }, t('settings.learnGood')),
2857
- h('input', { type: 'checkbox', checked: learnGood, onChange: toggleLearnGood })),
2858
- h('div', { className: 'tacit-settings-row' },
2859
- h('label', { className: 'tacit-settings-label' }, t('settings.budget')),
2935
+ FieldRow(t('settings.model'), h('select', {
2936
+ id: 'tacit-learning-model',
2937
+ className: 'tacit-select',
2938
+ value: model,
2939
+ onChange: (event) => applyModel(event.target.value),
2940
+ },
2941
+ h('option', { value: 'deepseek-v4-flash' }, 'deepseek-v4-flash'),
2942
+ h('option', { value: 'deepseek-v4-pro' }, 'deepseek-v4-pro')), 'tacit-learning-model'),
2943
+ FieldRow(t('settings.budget'), [
2860
2944
  h('input', {
2945
+ key: 'input',
2946
+ id: 'tacit-learning-budget',
2861
2947
  className: 'tacit-input',
2862
2948
  type: 'number',
2863
2949
  min: 0,
2864
2950
  value: budgetText,
2865
2951
  onChange: (event) => setBudgetText(event.target.value),
2866
2952
  }),
2867
- h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: applyBudget }, t('settings.apply'))),
2868
- ]),
2953
+ h('button', { key: 'apply', type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: applyBudget }, t('settings.apply')),
2954
+ ], 'tacit-learning-budget'),
2955
+ h('div', { className: 'tacit-options' },
2956
+ OptionRow(t('settings.auto'), auto, toggleAuto),
2957
+ OptionRow(t('settings.learnGood'), learnGood, toggleLearnGood)),
2958
+ // The model in force reads from the collapsed head, where it is set.
2959
+ ], config !== null && typeof config.model === 'string' && config.model.length > 0
2960
+ ? { summary: t('overview.model', { model: config.model }) }
2961
+ : undefined),
2869
2962
  card('guidance', [
2870
2963
  h(DirectivesEditorView, {
2871
2964
  workspaces: rootStore.workspaces, config, directives, steering: rootStore.steering,
2872
2965
  seenAt: rootStore.profile !== null && typeof rootStore.profile === 'object' ? rootStore.profile.workspaceSeenAt : null }),
2873
- ]),
2966
+ ], { count: directives.filter((entry) => entry.status !== 'removed').length }),
2874
2967
  card('improve', [
2875
- h('div', { className: 'tacit-settings-row' },
2876
- h('label', { className: 'tacit-settings-label' }, t('settings.live')),
2877
- h('input', { type: 'checkbox', checked: live, onChange: toggleLive })),
2968
+ OptionRow(t('settings.live'), live, toggleLive),
2878
2969
  h('div', { className: 'tacit-panel-section' },
2879
2970
  h('div', { className: 'tacit-report-title' }, t('panel.styleRules')),
2880
2971
  styleRules.length === 0
@@ -2904,18 +2995,16 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2904
2995
  ], { count: coached.length }),
2905
2996
  card('privacy', [
2906
2997
  h('p', { className: 'tacit-panel-hint' }, t('privacy.stored')),
2907
- h('div', { className: 'tacit-settings-row' },
2908
- h('label', { className: 'tacit-settings-label', htmlFor: 'tacit-retention' }, t('privacy.retention')),
2909
- h('select', {
2910
- id: 'tacit-retention',
2911
- className: 'tacit-select',
2912
- value: String(retention),
2913
- onChange: (event) => updateRootConfig({ costHistoryDays: Number(event.target.value) }),
2914
- },
2915
- ...retentionDays.map((days) => h('option', { key: days, value: String(days) }, String(days))))),
2916
- h('div', { className: 'tacit-settings-row' },
2917
- h('label', { className: 'tacit-settings-label', htmlFor: 'tacit-warn-daily' }, t('privacy.warnDaily')),
2998
+ FieldRow(t('privacy.retention'), h('select', {
2999
+ id: 'tacit-retention',
3000
+ className: 'tacit-select',
3001
+ value: String(retention),
3002
+ onChange: (event) => updateRootConfig({ costHistoryDays: Number(event.target.value) }),
3003
+ },
3004
+ ...retentionDays.map((days) => h('option', { key: days, value: String(days) }, String(days)))), 'tacit-retention'),
3005
+ FieldRow(t('privacy.warnDaily'), [
2918
3006
  h('input', {
3007
+ key: 'input',
2919
3008
  id: 'tacit-warn-daily',
2920
3009
  className: 'tacit-input',
2921
3010
  type: 'number',
@@ -2925,16 +3014,18 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2925
3014
  onChange: (event) => setDailyText(event.target.value),
2926
3015
  }),
2927
3016
  h('button', {
3017
+ key: 'apply',
2928
3018
  type: 'button',
2929
3019
  className: 'tacit-btn tacit-btn-sm',
2930
3020
  // Two identically labelled buttons in one card: the accessible
2931
3021
  // name has to say which threshold each one applies.
2932
3022
  'aria-label': t('privacy.applyTo', { action: t('privacy.apply'), field: t('privacy.warnDaily') }),
2933
3023
  onClick: () => applyWarn('costWarnDailyUsd', dailyText, setDailyText),
2934
- }, t('privacy.apply'))),
2935
- h('div', { className: 'tacit-settings-row' },
2936
- h('label', { className: 'tacit-settings-label', htmlFor: 'tacit-warn-monthly' }, t('privacy.warnMonthly')),
3024
+ }, t('privacy.apply')),
3025
+ ], 'tacit-warn-daily'),
3026
+ FieldRow(t('privacy.warnMonthly'), [
2937
3027
  h('input', {
3028
+ key: 'input',
2938
3029
  id: 'tacit-warn-monthly',
2939
3030
  className: 'tacit-input',
2940
3031
  type: 'number',
@@ -2944,18 +3035,20 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
2944
3035
  onChange: (event) => setMonthlyText(event.target.value),
2945
3036
  }),
2946
3037
  h('button', {
3038
+ key: 'apply',
2947
3039
  type: 'button',
2948
3040
  className: 'tacit-btn tacit-btn-sm',
2949
3041
  // Two identically labelled buttons in one card: the accessible
2950
3042
  // name has to say which threshold each one applies.
2951
3043
  'aria-label': t('privacy.applyTo', { action: t('privacy.apply'), field: t('privacy.warnMonthly') }),
2952
3044
  onClick: () => applyWarn('costWarnMonthlyUsd', monthlyText, setMonthlyText),
2953
- }, t('privacy.apply'))),
3045
+ }, t('privacy.apply')),
3046
+ ], 'tacit-warn-monthly'),
2954
3047
  h('p', { className: 'tacit-panel-hint' }, t('privacy.warnHint')),
2955
3048
  // Both clears are irreversible, so both go through the dialog.
2956
- h('div', { className: 'tacit-settings-row' },
2957
- h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: () => openConfirm('reports') }, t('settings.clear')),
2958
- h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', onClick: () => openConfirm('usage') }, t('privacy.clearUsage'))),
3049
+ h('div', { className: 'tacit-inline' },
3050
+ h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm tacit-btn-quiet', onClick: () => openConfirm('reports') }, t('settings.clear')),
3051
+ h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm tacit-btn-quiet', onClick: () => openConfirm('usage') }, t('privacy.clearUsage'))),
2959
3052
  ]),
2960
3053
  // Always rendered (null while closed) so its one effect keeps this
2961
3054
  // component's hook count stable.
@@ -3476,17 +3569,19 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
3476
3569
 
3477
3570
  const css = '.tacit-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}'
3478
3571
  + '.tacit-head{display:flex;align-items:baseline;gap:8px;margin-bottom:10px}.tacit-head-title{font-size:14px;font-weight:600;margin-right:auto}'
3479
- + '.tacit-progress{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:8px 12px;margin-bottom:12px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}.tacit-progress-title{font-weight:600;color:var(--dsw-alias-label-primary)}'
3480
- + '.tacit-empty{color:var(--dsw-alias-label-secondary);text-align:center;padding:24px 8px;line-height:1.6}'
3572
+ + '.tacit-progress{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:8px 12px;margin-bottom:12px;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.5}.tacit-progress-title{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);margin-right:auto}'
3573
+ + '.tacit-empty{color:var(--dsw-alias-label-secondary);text-align:center;font-size:12px;line-height:1.6;max-width:46ch;margin-inline:auto;padding:18px 12px;border:1px dashed var(--dsw-alias-border-l1);border-radius:8px;background:color-mix(in srgb, var(--dsw-alias-bg-layer-2) 50%, transparent)}'
3481
3574
  + '.tacit-error{color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:8px 12px;margin-bottom:12px;overflow-wrap:anywhere;font-size:12px}'
3482
3575
  + '.tacit-btn{font:inherit;font-size:12px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;cursor:pointer;padding:4px 10px}.tacit-btn:hover{border-color:var(--dsw-alias-label-primary)}.tacit-btn:disabled{opacity:.55;cursor:default}'
3483
3576
  + '.tacit-btn-primary{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:transparent}.tacit-btn-primary:hover{border-color:transparent;filter:brightness(1.1)}'
3484
3577
  + '.tacit-btn-sm{padding:2px 8px;font-size:11px}'
3485
3578
  + '.tacit-btn-danger{color:var(--dsw-alias-state-error-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent)}.tacit-btn-danger:hover{border-color:var(--dsw-alias-state-error-primary);background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}'
3486
3579
  + '.tacit-row{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:10px 12px;margin-bottom:10px}'
3487
- + '.tacit-row-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 12px}.tacit-row-heading{display:flex;align-items:baseline;gap:8px;font-weight:600}.tacit-row-turn{font-size:13px}.tacit-row-time{color:var(--dsw-alias-label-secondary);font-size:11px;font-weight:400}.tacit-row-live{color:var(--dsw-alias-state-success-primary);font-size:11px;font-weight:600}'
3488
- + '.tacit-row-chips{display:flex;flex-wrap:wrap;gap:4px;margin-left:auto}.tacit-chip{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:1px 7px;font-size:11px}.tacit-chip-warn{color:var(--dsw-alias-state-warn-primary)}'
3489
- + '.tacit-row-prompt{display:flex;align-items:flex-start;gap:8px;margin-top:8px}.tacit-row-prompt-text{font:inherit;font-size:12px;color:var(--dsw-alias-label-primary);background:none;border:0;cursor:pointer;text-align:left;padding:0;white-space:pre-wrap;word-break:break-word;flex:1;line-height:1.55}'
3580
+ + '.tacit-row-head{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px}.tacit-row-heading{display:flex;flex-wrap:wrap;align-items:center;gap:4px 8px;font-weight:600;min-width:0}.tacit-row-turn{font-size:13px;font-variant-numeric:tabular-nums}.tacit-row-time{color:var(--dsw-alias-label-secondary);font-size:11px;font-weight:400}.tacit-row-actions{display:flex;align-items:center;gap:6px;margin-left:auto}'
3581
+ + '.tacit-chip{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:1px 7px;font-size:11px}.tacit-chip-warn{color:var(--dsw-alias-state-warn-primary)}'
3582
+ // Turn facts read as one dot-separated line, not four bordered chips.
3583
+ + '.tacit-row-meta{display:flex;flex-wrap:wrap;align-items:center;margin-top:8px;font-size:11px;line-height:1.5;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}.tacit-row-meta>span+span::before{content:"·";margin:0 7px;opacity:.6}.tacit-row-meta-warn{color:var(--dsw-alias-state-warn-primary)}'
3584
+ + '.tacit-row-prompt{display:flex;align-items:flex-start;gap:8px;margin-top:8px}.tacit-row-prompt-text{font:inherit;font-size:12px;color:var(--dsw-alias-label-primary);background:none;border:0;cursor:pointer;text-align:left;padding:0;white-space:pre-wrap;word-break:break-word;flex:1;line-height:1.55}.tacit-row-prompt-static{cursor:auto}.tacit-row-more{margin-left:8px;font-size:11px;color:var(--dsw-alias-brand-primary);white-space:nowrap}'
3490
3585
  + '.tacit-report{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:10px;padding-top:10px;display:flex;flex-direction:column;gap:6px}'
3491
3586
  + '.tacit-report-title{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary)}'
3492
3587
  + '.tacit-report-note{color:var(--dsw-alias-label-secondary);font-size:12px}'
@@ -3502,7 +3597,11 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
3502
3597
  + '.tacit-problem-what{font-size:12px;color:var(--dsw-alias-label-primary);line-height:1.5}.tacit-problem-why{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.5}'
3503
3598
  + '.tacit-pre{margin:0;white-space:pre-wrap;word-break:break-word;font-family:inherit;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-primary)}'
3504
3599
  + '.tacit-settings{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;padding:10px 12px;margin-bottom:12px;display:flex;flex-direction:column;gap:8px}'
3505
- + '.tacit-settings-title{font-size:12px;font-weight:600}.tacit-settings-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.tacit-settings-label{font-size:12px;color:var(--dsw-alias-label-secondary);min-width:150px}'
3600
+ + '.tacit-settings-title{font-size:12px;font-weight:600}'
3601
+ // One settings row everywhere: the label takes the slack and wraps, the
3602
+ // control stays right-aligned, and nothing needs a 150px minimum.
3603
+ + '.tacit-field{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px}.tacit-field-label{flex:1 1 150px;min-width:0;font-size:12px;line-height:1.45;color:var(--dsw-alias-label-secondary)}.tacit-field-control{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-left:auto}'
3604
+ + '.tacit-inline,.tacit-settings-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px}'
3506
3605
  + '.tacit-settings-notice{font-size:11px;color:var(--dsw-alias-state-success-primary)}'
3507
3606
  // The idle live region has to stay mounted to announce, but as an empty
3508
3607
  // flex item it still claims one of the panel's 10px gaps; -5px a side
@@ -3511,22 +3610,22 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
3511
3610
  + '.tacit-select,.tacit-input{font:inherit;font-size:12px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;padding:3px 8px}.tacit-input{width:90px}'
3512
3611
  + '.tacit-improve-btn{font:inherit;font-size:13px;font-weight:500;line-height:20px;color:var(--dsw-alias-label-secondary);background:transparent;border:0;border-radius:24px;cursor:pointer;height:28px;padding:0 8px;white-space:nowrap;display:inline-flex;align-items:center;gap:4px}.tacit-improve-btn:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}'
3513
3612
  + '.tacit-check{width:14px;height:14px;accent-color:var(--dsw-alias-brand-primary);flex:none;margin:2px 4px 0 0}'
3514
- + '.tacit-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:10px;flex-wrap:wrap}.tacit-toolbar-hint{flex:1;min-width:200px}.tacit-btn-quiet{color:var(--dsw-alias-label-secondary);background:transparent}.tacit-chip-muted{opacity:.7}.tacit-row-analyzed{border-left:3px solid var(--dsw-alias-brand-primary)}'
3515
- + '.tacit-progress-head{display:flex;align-items:baseline;gap:8px;margin-bottom:6px}.tacit-progress-count{font-variant-numeric:tabular-nums;font-weight:600;color:var(--dsw-alias-label-primary)}'
3613
+ + '.tacit-toolbar{display:flex;align-items:center;gap:8px;margin-bottom:6px;flex-wrap:wrap}.tacit-toolbar-note{font-size:11px;line-height:1.5;color:var(--dsw-alias-label-secondary);margin-bottom:10px}.tacit-btn-quiet{color:var(--dsw-alias-label-secondary);background:transparent;border-color:transparent}.tacit-btn-quiet:hover{color:var(--dsw-alias-label-primary);border-color:transparent;background:var(--dsw-alias-interactive-bg-hover)}.tacit-chip-muted{opacity:.7}.tacit-row-analyzed{border-left:3px solid var(--dsw-alias-brand-primary)}'
3614
+ + '.tacit-progress-head{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;margin-bottom:6px}'
3516
3615
  + '.tacit-progress-text{font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.5}'
3517
- + '.tacit-panel{display:flex;flex-direction:column;gap:10px}.tacit-panel-section{display:flex;flex-direction:column;gap:6px}.tacit-panel-hint{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.5}'
3616
+ + '.tacit-panel{display:flex;flex-direction:column;gap:10px}.tacit-panel-section{display:flex;flex-direction:column;gap:6px}.tacit-panel-hint{margin:0;font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.5}'
3518
3617
  + '.tacit-coached-list{display:flex;flex-direction:column;gap:6px}.tacit-coached-row{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:6px 10px;display:flex;flex-direction:column;gap:3px}'
3519
3618
  + '.tacit-coached-meta{display:flex;align-items:baseline;gap:8px}.tacit-coached-turn{font-weight:600;font-size:12px}.tacit-coached-time{color:var(--dsw-alias-label-secondary);font-size:11px}'
3520
3619
  + '.tacit-coached-excerpt{font-size:12px;color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;line-height:1.5}.tacit-coached-improved{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.5;white-space:pre-wrap;word-break:break-word}'
3521
3620
  + ''
3522
3621
  + '.tacit-modal-backdrop{z-index:200;background:#00000073;display:flex;justify-content:center;align-items:center;position:fixed;inset:0}'
3523
- + '.tacit-modal-card{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);width:min(760px,100vw - 48px);max-height:min(84vh,800px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);color:var(--dsw-alias-label-primary);border-radius:12px;padding:16px 18px 18px;font-size:13px;display:flex;flex-direction:column;gap:10px;overflow-y:auto}'
3622
+ + '.tacit-modal-card{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);width:min(760px,100vw - 48px);max-height:min(84vh,800px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);color:var(--dsw-alias-label-primary);border-radius:12px;padding:16px 18px 18px;font-size:13px;display:flex;flex-direction:column;gap:10px;overflow-y:auto}.tacit-modal-card-sm{width:min(440px,100vw - 48px)}'
3524
3623
  + '.tacit-modal-head{display:flex;align-items:baseline;gap:8px}.tacit-modal-title{font-size:14px;font-weight:600;margin:0 auto 0 0}.tacit-modal-close{color:var(--dsw-alias-label-secondary);cursor:pointer;background:none;border:0;border-radius:6px;padding:2px 8px;font-family:inherit;font-size:18px;line-height:1}.tacit-modal-close:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}'
3525
3624
  + '.tacit-modal-pending{color:var(--dsw-alias-label-secondary);padding:16px 0;text-align:center}'
3526
3625
  + '.tacit-modal-unchanged{color:var(--dsw-alias-label-primary);padding:16px 0;text-align:center}'
3527
- + '.tacit-modal-cols{display:grid;grid-template-columns:1fr 1fr;gap:10px}.tacit-modal-col{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-2);padding:8px 10px;min-width:0;max-height:300px;overflow-y:auto}'
3626
+ + '.tacit-modal-body{display:flex;flex-direction:column;gap:10px}.tacit-modal-cols{display:grid;grid-template-columns:1fr 1fr;gap:10px}.tacit-modal-col{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-2);padding:8px 10px;min-width:0;max-height:300px;overflow-y:auto}'
3528
3627
  + '.tacit-modal-col-title{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);margin-bottom:6px}'
3529
- + '.tacit-modal-rationale-text{font-size:12px;color:var(--dsw-alias-label-primary);line-height:1.6}.tacit-modal-savings{color:var(--dsw-alias-state-success-primary);font-size:12px;font-weight:600}'
3628
+ + '.tacit-modal-col-improved{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary) 40%, transparent)}.tacit-modal-rationale{display:flex;flex-direction:column;gap:4px}.tacit-modal-rationale-text{font-size:12px;color:var(--dsw-alias-label-primary);line-height:1.6}.tacit-modal-savings{color:var(--dsw-alias-state-success-primary);font-size:12px;font-weight:600}'
3530
3629
  + '.tacit-modal-actions{display:flex;gap:8px;justify-content:flex-end}'
3531
3630
  + '.tacit-confirm-body{margin:0;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-primary)}'
3532
3631
  + '.tacit-confirm-actions{display:flex;gap:8px;justify-content:flex-end;margin-top:4px}'
@@ -3537,15 +3636,16 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
3537
3636
  + '.tacit-feedback-noted{color:var(--dsw-alias-state-success-primary);font-weight:600}'
3538
3637
  + '.tacit-trend{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-top:6px}.tacit-chip-trigger,.tacit-coached-trigger{text-transform:uppercase;letter-spacing:.04em;font-size:10px}.tacit-coached-trigger{margin-left:auto}.tacit-row-enrichment{margin-top:8px;border-left:3px solid var(--dsw-alias-brand-primary);padding:4px 10px;background:var(--dsw-alias-bg-layer-2);border-radius:6px}'
3539
3638
  + '.tacit-chip-trial{color:var(--dsw-alias-brand-primary)}.tacit-chip-ok{color:var(--dsw-alias-state-success-primary)}.tacit-chip-scope{color:var(--dsw-alias-brand-primary)}.tacit-select{max-width:11rem}'
3540
- + '.tacit-directive{display:flex;align-items:center;gap:8px}.tacit-directive-text{flex:1;min-width:0}.tacit-directive-off .tacit-directive-text{opacity:.5;text-decoration:line-through}.tacit-directive-input{width:min(420px,100%);flex:1}.tacit-preview summary{cursor:pointer;font-size:11px;color:var(--dsw-alias-label-secondary)}.tacit-preview pre{margin-top:6px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;padding:8px 10px}'
3639
+ + '.tacit-directive-input{width:min(420px,100%);flex:1}.tacit-preview summary{cursor:pointer;font-size:11px;color:var(--dsw-alias-label-secondary)}.tacit-preview pre{margin-top:6px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:6px;padding:8px 10px}'
3541
3640
  + '.tacit-rules-list{display:flex;flex-direction:column;gap:6px}.tacit-rule{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-left:3px solid var(--dsw-alias-brand-primary);border-radius:6px;padding:6px 10px;font-size:12px;line-height:1.55;color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word}'
3542
3641
  + '.tacit-card{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-1)}'
3543
- + '.tacit-card-head{width:100%;display:flex;align-items:center;gap:8px;text-align:left;padding:10px 12px;background:none;border:0;cursor:pointer;font:inherit;color:inherit}'
3642
+ + '.tacit-card-head{width:100%;display:flex;align-items:center;gap:8px;text-align:left;padding:10px 12px;background:none;border:0;border-radius:7px;cursor:pointer;font:inherit;color:inherit}.tacit-card-head:hover{background:var(--dsw-alias-interactive-bg-hover)}'
3544
3643
  + '.tacit-card-head:focus-visible{outline:2px solid var(--dsw-alias-brand-primary)}'
3545
3644
  + '.tacit-card-title{font-size:13px;font-weight:600}.tacit-card-summary{font-size:11px;color:var(--dsw-alias-label-secondary);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}'
3546
3645
  + '.tacit-card-count{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-secondary);border-radius:4px;padding:1px 7px;font-size:11px;font-variant-numeric:tabular-nums}'
3547
- + '.tacit-card-chevron{margin-left:auto;color:var(--dsw-alias-label-secondary);font-size:11px}'
3548
- + '.tacit-card-body{padding:0 12px 12px}'
3646
+ // One disclosure glyph everywhere: a › that rotates down when open.
3647
+ + '.tacit-chevron{display:inline-block;font-size:12px;line-height:1;color:inherit;transition:transform .15s ease}.tacit-chevron-open{transform:rotate(90deg)}.tacit-card-chevron{margin-left:auto;color:var(--dsw-alias-label-secondary)}'
3648
+ + '.tacit-card-body{display:flex;flex-direction:column;gap:10px;padding:10px 12px 12px;border-top:1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 60%, transparent)}.tacit-card-body[hidden]{display:none}'
3549
3649
  + '.tacit-usage{display:flex;flex-direction:column;gap:10px}'
3550
3650
  + '.tacit-tiles{display:flex;flex-wrap:wrap;gap:8px}'
3551
3651
  + '.tacit-tile{flex:1 1 140px;display:flex;flex-direction:column;gap:2px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:8px 10px;min-width:0}'
@@ -3580,7 +3680,39 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
3580
3680
  + '.tacit-pricing-table>.tacit-pricing-row:first-child{border-top:0}.tacit-pricing-head{color:var(--dsw-alias-label-secondary);font-weight:600;background:var(--dsw-alias-bg-layer-2)}'
3581
3681
  + '.tacit-pricing-cell{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tacit-pricing-model{font-weight:600}'
3582
3682
  + '.tacit-pricing-error{font-size:11px;color:var(--dsw-alias-state-warn-primary);line-height:1.5}'
3583
- + '@media (max-width:640px){.tacit-settings-label{min-width:0;flex-basis:100%}.tacit-modal-cols{grid-template-columns:1fr}.tacit-usage-row{display:flex;flex-direction:column}.tacit-usage-cell{white-space:normal}.tacit-pricing-row{display:flex;flex-direction:column}.tacit-pricing-cell{white-space:normal}.tacit-tile{flex-basis:45%}.tacit-breakdown-row{grid-template-columns:minmax(0,1fr) 4rem 5rem}}'
3683
+ // Directive cards: a status-coloured rail and pill badge, the text on
3684
+ // its own line, and a wrapping actions row, so nothing fights for width.
3685
+ + '.tacit-dir-list{display:flex;flex-direction:column;gap:8px}'
3686
+ + '.tacit-dir{--tacit-status:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-left:3px solid var(--tacit-status);border-radius:8px;padding:8px 10px 8px 12px;display:flex;flex-direction:column;gap:6px;min-width:0}'
3687
+ + '.tacit-dir-active{--tacit-status:var(--dsw-alias-state-success-primary)}.tacit-dir-trial{--tacit-status:var(--dsw-alias-brand-primary)}.tacit-dir-retired{--tacit-status:var(--dsw-alias-state-warn-primary)}'
3688
+ + '.tacit-dir-head{display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px}.tacit-dir-start{margin-left:auto}'
3689
+ + '.tacit-badge{--tacit-badge:var(--tacit-status, var(--dsw-alias-label-secondary));display:inline-flex;align-items:center;gap:5px;border-radius:999px;padding:1px 8px 1px 6px;font-size:11px;font-weight:600;line-height:1.5;color:var(--tacit-badge);background:color-mix(in srgb, var(--tacit-badge) 14%, transparent)}'
3690
+ + '.tacit-badge-active{--tacit-status:var(--dsw-alias-state-success-primary)}.tacit-badge-trial{--tacit-status:var(--dsw-alias-brand-primary)}.tacit-badge-retired{--tacit-status:var(--dsw-alias-state-warn-primary)}.tacit-badge-muted{--tacit-status:var(--dsw-alias-label-secondary)}'
3691
+ + '.tacit-badge-dot{width:6px;height:6px;border-radius:50%;background:var(--tacit-badge);flex:none}'
3692
+ + '.tacit-dir-text{font-size:13px;line-height:1.55;color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word}.tacit-dir-off .tacit-dir-text{opacity:.5;text-decoration:line-through}'
3693
+ + '.tacit-dir-actions{display:flex;flex-wrap:wrap;align-items:center;gap:6px 10px;font-size:11px;color:var(--dsw-alias-label-secondary)}'
3694
+ + '.tacit-dir-enabled{display:inline-flex;align-items:center;gap:5px;cursor:pointer}.tacit-dir-enabled .tacit-check{margin:0}.tacit-dir-remove{margin-left:auto}'
3695
+ + '.tacit-select-sm{font-size:11px;padding:2px 6px;width:auto}'
3696
+ + '.tacit-dir-receipt summary{cursor:pointer;font-size:11px;color:var(--dsw-alias-label-secondary)}.tacit-dir-receipt summary:hover{color:var(--dsw-alias-label-primary)}'
3697
+ + '.tacit-dir-add{display:flex;flex-wrap:wrap;align-items:center;gap:6px}'
3698
+ + '.tacit-options{display:flex;flex-direction:column;gap:6px;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:8px 10px}'
3699
+ + '.tacit-option{display:flex;align-items:flex-start;gap:8px;font-size:12px;line-height:1.5;cursor:pointer}.tacit-option .tacit-check{margin-top:2px}'
3700
+ // Hairlines between rows keep the group one soft box, not a list of boxes.
3701
+ + '.tacit-options>*+*{border-top:1px solid color-mix(in srgb, var(--dsw-alias-border-l1) 60%, transparent);padding-top:6px}.tacit-options .tacit-select,.tacit-options .tacit-input{background:var(--dsw-alias-bg-layer-1)}'
3702
+ // The receipt: tiles, a lifecycle timeline, trigger chips, then the
3703
+ // identity grid.
3704
+ + '.tacit-receipt{margin-top:8px;padding-top:10px;border-top:1px dashed var(--dsw-alias-border-l1);display:flex;flex-direction:column;gap:10px}'
3705
+ + '.tacit-receipt-tiles .tacit-tile{flex-basis:120px;background:var(--dsw-alias-bg-layer-1)}.tacit-receipt-tile-note{font-size:10px;color:var(--dsw-alias-label-secondary);line-height:1.4}.tacit-tile-muted{font-size:12px;font-weight:500;color:var(--dsw-alias-label-secondary)}'
3706
+ + '.tacit-timeline{list-style:none;margin:0;padding:0;display:flex}'
3707
+ + '.tacit-timeline-step{flex:1;position:relative;min-width:0;padding:14px 6px 0 0;font-size:11px}'
3708
+ + '.tacit-timeline-step::before{content:"";position:absolute;left:0;top:0;width:9px;height:9px;border-radius:50%;box-sizing:border-box;background:var(--dsw-alias-brand-primary)}'
3709
+ + '.tacit-timeline-step::after{content:"";position:absolute;left:12px;right:2px;top:4px;height:1px;background:var(--dsw-alias-border-l1)}.tacit-timeline-step:last-child::after{display:none}'
3710
+ + '.tacit-timeline-never::before{background:var(--dsw-alias-bg-layer-2);border:1.5px solid var(--dsw-alias-border-l1)}.tacit-timeline-never .tacit-timeline-value{color:var(--dsw-alias-label-secondary);font-weight:400}'
3711
+ + '.tacit-timeline-label{display:block;color:var(--dsw-alias-label-secondary)}.tacit-timeline-value{display:block;font-weight:600;font-variant-numeric:tabular-nums}'
3712
+ + '.tacit-receipt-row{display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px}.tacit-receipt-label{font-size:11px;color:var(--dsw-alias-label-secondary);margin-right:2px}'
3713
+ + '.tacit-receipt-meta{margin:0;display:grid;grid-template-columns:max-content minmax(0,1fr);gap:3px 12px;font-size:11px}.tacit-receipt-meta dt{color:var(--dsw-alias-label-secondary)}.tacit-receipt-meta dd{margin:0;overflow-wrap:anywhere;font-variant-numeric:tabular-nums}'
3714
+ + '.tacit-receipt-actions{display:flex;justify-content:flex-end}'
3715
+ + '@media (max-width:640px){.tacit-field-label{flex-basis:100%}.tacit-field-control{margin-left:0}.tacit-modal-cols{grid-template-columns:1fr}.tacit-usage-row{display:flex;flex-direction:column}.tacit-usage-cell{white-space:normal}.tacit-pricing-row{display:flex;flex-direction:column}.tacit-pricing-cell{white-space:normal}.tacit-tile{flex-basis:45%}.tacit-breakdown-row{grid-template-columns:minmax(0,1fr) 4rem 5rem}}'
3584
3716
 
3585
3717
  function injectCss() {
3586
3718
  const tagId = 'dsh-tacit/styles.css'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-tacit",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Tacit learns what you leave unsaid in your prompts — from messy turns and your own corrections, with zero clicks — and tells the agent how to compensate, on every turn, via a system-prompt section you can read and edit.",
5
5
  "author": "hackernotfound",
6
6
  "license": "MIT",