dsh-tacit 0.2.2 → 0.2.3

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/README.md CHANGED
@@ -85,6 +85,27 @@ reports. Dollar figures are estimates at list price; a cost plugin such as
85
85
  the honest list of limitations:
86
86
  [Privacy, cost & limitations](https://github.com/hackernotfound/dsh-tacit/blob/main/docs/privacy-and-cost.md).
87
87
 
88
+ ## Help shape Tacit
89
+
90
+ Tacit works and I use it every day — but so far it has learned from one
91
+ person's prompts. It gets better with more of them.
92
+
93
+ - **Try it and say what feels wrong.** A directive that misfires, a cost that
94
+ surprised you, a label that reads oddly:
95
+ [open an issue](https://github.com/hackernotfound/dsh-tacit/issues/new/choose).
96
+ Two minutes of your time beats a week of my guessing.
97
+ - **Pick up a task.** Issues tagged
98
+ [`good first issue`](https://github.com/hackernotfound/dsh-tacit/labels/good%20first%20issue)
99
+ are small and come with acceptance criteria;
100
+ [`help wanted`](https://github.com/hackernotfound/dsh-tacit/labels/help%20wanted)
101
+ ones are bigger and I will pair on the design.
102
+ - **Ask anything** in
103
+ [Discussions](https://github.com/hackernotfound/dsh-tacit/discussions).
104
+
105
+ PRs are welcome — the fork → branch → PR walkthrough is in
106
+ [CONTRIBUTING.md](https://github.com/hackernotfound/dsh-tacit/blob/main/CONTRIBUTING.md).
107
+ No API key is needed to run the tests.
108
+
88
109
  ## Documentation
89
110
 
90
111
  | | |
package/client/client.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  // Copyright (c) 2026 hackernotfound — https://github.com/hackernotfound/dsh-tacit
3
+ // GENERATED by scripts/build-client.mjs from client/src/ — edit the sources, not this file.
3
4
  /**
4
5
  * dsh-tacit — Client half (installed package bundle entry, zero-build).
5
6
  *
@@ -57,6 +58,10 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
57
58
  'trigger.correction': '纠正',
58
59
  'trigger.manual': '手动',
59
60
  'trigger.bootstrap': '引导',
61
+ 'trigger.good': '做对了',
62
+ 'report.strengths': '这次做对了什么',
63
+ 'report.lesson': '经验',
64
+ 'settings.learnGood': '也从混乱之后的顺利提示词中学习',
60
65
  'bootstrap.btn': '从我最近 20 轮中学习',
61
66
  'bootstrap.running': '学习中… {done}/{total}',
62
67
  'bootstrap.hint': '约 $0.02–0.05,一次性。已顺利完成的提示词会被跳过。',
@@ -74,6 +79,9 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
74
79
  'steer.active': '已生效',
75
80
  'steer.retired': '已淘汰 · {reason}',
76
81
  'steer.user': '你添加的',
82
+ 'steer.workspace': '仅 {name}',
83
+ 'steer.scope': '适用范围',
84
+ 'steer.everywhere': '所有工作区',
77
85
  'settings.auto': '自动分析混乱轮次',
78
86
  'settings.budget': '每日自动分析上限',
79
87
  settings: '设置',
@@ -164,6 +172,10 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
164
172
  'trigger.correction': 'correction',
165
173
  'trigger.manual': 'manual',
166
174
  'trigger.bootstrap': 'bootstrap',
175
+ 'trigger.good': 'what worked',
176
+ 'report.strengths': 'What this prompt got right',
177
+ 'report.lesson': 'Lesson',
178
+ 'settings.learnGood': 'Also learn from a clean prompt right after a messy turn',
167
179
  'bootstrap.btn': 'Learn from my last 20 turns',
168
180
  'bootstrap.running': 'Learning… {done}/{total}',
169
181
  'bootstrap.hint': '≈ $0.02–0.05, one time. Skips prompts that already went fine on their own.',
@@ -181,6 +193,9 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
181
193
  'steer.active': 'active',
182
194
  'steer.retired': 'retired · {reason}',
183
195
  'steer.user': 'yours',
196
+ 'steer.workspace': 'only {name}',
197
+ 'steer.scope': 'Applies to',
198
+ 'steer.everywhere': 'Everywhere',
184
199
  'settings.auto': 'Auto-analyze messy turns',
185
200
  'settings.budget': 'Daily cap on automatic analyses',
186
201
  settings: 'Settings',
@@ -346,13 +361,14 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
346
361
  return version
347
362
  }
348
363
 
349
- // ── Root store (sidebar action + settings section + frame overlay) ─────
364
+ // ── Root store (settings section + bootstrap + directives editor) ──────
350
365
 
351
366
  const rootStore = {
352
367
  config: null,
353
368
  profile: null,
354
369
  auto: null,
355
370
  steering: null, // {enabled, text}
371
+ workspaces: [], // [{cwd, label}] from /state
356
372
  trend: null, // measured early-vs-recent trend
357
373
  bootstrap: null, // {running, done, total}
358
374
  coached: [], // cross-session coached-prompt entries
@@ -388,6 +404,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
388
404
  rootStore.profile = state.profile !== null && typeof state.profile === 'object' ? state.profile : null
389
405
  rootStore.auto = state.auto !== null && typeof state.auto === 'object' ? state.auto : null
390
406
  rootStore.steering = state.steering !== null && typeof state.steering === 'object' ? state.steering : null
407
+ rootStore.workspaces = Array.isArray(state.workspaces) ? state.workspaces : []
391
408
  rootStore.bootstrap = state.bootstrap !== null && typeof state.bootstrap === 'object' ? state.bootstrap : null
392
409
  }
393
410
  const coached = await api('/history', { limit: 50 })
@@ -415,6 +432,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
415
432
  rootStore.profile = state.profile !== null && typeof state.profile === 'object' ? state.profile : null
416
433
  rootStore.auto = state.auto !== null && typeof state.auto === 'object' ? state.auto : null
417
434
  rootStore.steering = state.steering !== null && typeof state.steering === 'object' ? state.steering : null
435
+ rootStore.workspaces = Array.isArray(state.workspaces) ? state.workspaces : []
418
436
  rootStore.bootstrap = state.bootstrap !== null && typeof state.bootstrap === 'object' ? state.bootstrap : null
419
437
  }
420
438
  } catch {
@@ -944,14 +962,21 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
944
962
  }
945
963
  return h('div', { className: 'tacit-report' },
946
964
  h('div', { className: 'tacit-report-title' },
947
- t('report.problems'),
965
+ report.trigger === 'good' ? t('report.strengths') : t('report.problems'),
948
966
  ' ',
949
- h('span', { className: 'tacit-chip tacit-chip-trigger' }, t('trigger.' + report.trigger))),
950
- report.problems.length === 0
951
- ? h('div', { className: 'tacit-report-note' }, '—')
952
- : report.problems.map((problem, index) => ProblemRow(kit, problem, index)),
953
- h('div', { className: 'tacit-report-title' }, t('report.improved')),
954
- improved.length > 0
967
+ h('span', { className: 'tacit-chip tacit-chip-trigger' + (report.trigger === 'good' ? ' tacit-chip-ok' : '') }, t('trigger.' + report.trigger))),
968
+ report.trigger === 'good'
969
+ ? (Array.isArray(report.strengths) && report.strengths.length > 0
970
+ ? report.strengths.map((strength, index) => h('div', { key: index, className: 'tacit-problem' },
971
+ h('span', { className: 'tacit-chip tacit-chip-ok' }, String(strength.kind)),
972
+ ' ',
973
+ h('span', { className: 'tacit-problem-what' }, String(strength.what))))
974
+ : h('div', { className: 'tacit-report-note' }, '—'))
975
+ : report.problems.length === 0
976
+ ? h('div', { className: 'tacit-report-note' }, '—')
977
+ : report.problems.map((problem, index) => ProblemRow(kit, problem, index)),
978
+ report.trigger === 'good' ? null : h('div', { className: 'tacit-report-title' }, t('report.improved')),
979
+ report.trigger === 'good' ? null : improved.length > 0
955
980
  ? h('div', { className: 'tacit-report-improved' },
956
981
  h('div', { className: 'tacit-report-actions' },
957
982
  h('button', {
@@ -966,7 +991,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
966
991
  : h('div', { className: 'tacit-report-note' }, t('report.emptyImproved')),
967
992
  typeof report.explanation === 'string' && report.explanation.length > 0
968
993
  ? h('div', null,
969
- h('div', { className: 'tacit-report-title' }, t('report.explanation')),
994
+ h('div', { className: 'tacit-report-title' }, report.trigger === 'good' ? t('report.lesson') : t('report.explanation')),
970
995
  h('div', { className: 'tacit-report-body' },
971
996
  MarkdownText !== null
972
997
  ? h(MarkdownText, { text: report.explanation })
@@ -1063,6 +1088,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1063
1088
  const [model, setModel] = useState(config !== null && typeof config.model === 'string' ? config.model : 'deepseek-v4-flash')
1064
1089
  const [budgetText, setBudgetText] = useState(config !== null && typeof config.autoDailyBudget === 'number' ? String(config.autoDailyBudget) : '30')
1065
1090
  const [auto, setAuto] = useState(config !== null && config.autoAnalyze !== false)
1091
+ const [learnGood, setLearnGood] = useState(config !== null && config.learnFromGood !== false)
1066
1092
  const [live, setLive] = useState(config !== null && config.liveSuggestions !== false)
1067
1093
  const [notice, setNotice] = useState(null)
1068
1094
 
@@ -1071,6 +1097,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1071
1097
  if (typeof config.model === 'string') setModel(config.model)
1072
1098
  if (typeof config.autoDailyBudget === 'number') setBudgetText(String(config.autoDailyBudget))
1073
1099
  if (typeof config.autoAnalyze === 'boolean') setAuto(config.autoAnalyze)
1100
+ if (typeof config.learnFromGood === 'boolean') setLearnGood(config.learnFromGood)
1074
1101
  if (typeof config.liveSuggestions === 'boolean') setLive(config.liveSuggestions)
1075
1102
  }
1076
1103
  }, [config])
@@ -1084,6 +1111,11 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1084
1111
  setBudgetText(String(number))
1085
1112
  updateConfig(store, { autoDailyBudget: number })
1086
1113
  }
1114
+ const toggleLearnGood = () => {
1115
+ const next = !learnGood
1116
+ setLearnGood(next)
1117
+ updateConfig(store, { learnFromGood: next })
1118
+ }
1087
1119
  const toggleAuto = () => {
1088
1120
  const next = !auto
1089
1121
  setAuto(next)
@@ -1116,6 +1148,9 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1116
1148
  h('div', { className: 'tacit-settings-row' },
1117
1149
  h('label', { className: 'tacit-settings-label' }, t('settings.auto')),
1118
1150
  h('input', { type: 'checkbox', checked: auto, onChange: toggleAuto })),
1151
+ h('div', { className: 'tacit-settings-row' },
1152
+ h('label', { className: 'tacit-settings-label' }, t('settings.learnGood')),
1153
+ h('input', { type: 'checkbox', checked: learnGood, onChange: toggleLearnGood })),
1119
1154
  h('div', { className: 'tacit-settings-row' },
1120
1155
  h('label', { className: 'tacit-settings-label' }, t('settings.budget')),
1121
1156
  h('input', {
@@ -1259,7 +1294,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1259
1294
  }
1260
1295
  }
1261
1296
 
1262
- // ── Feedback strip (under the composer, Improve enabled only) ───────────
1297
+ // ── Feedback strip (above the composer, Improve enabled only) ───────────
1263
1298
 
1264
1299
  function FeedbackStrip(kit) {
1265
1300
  const { t } = kit
@@ -1329,13 +1364,19 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1329
1364
  }
1330
1365
  }
1331
1366
 
1332
- // ── Global panel (settings section, sidebar action, frame overlay) ─────
1367
+ // ── Global panel (Settings Tacit section) ────────────────────────────
1333
1368
 
1334
1369
  function DirectivesEditor(kit) {
1335
1370
  const { t } = kit
1336
1371
  return function DirectivesEditorView(props) {
1337
1372
  const { config, directives, steering } = props
1373
+ const workspaces = Array.isArray(props.workspaces) ? props.workspaces : []
1338
1374
  const [draft, setDraft] = useState('')
1375
+ const [scope, setScope] = useState('')
1376
+ const labelOf = (cwd) => {
1377
+ const parts = String(cwd).split(/[\\/]+/).filter((part) => part.length > 0)
1378
+ return parts.length > 0 ? parts[parts.length - 1] : String(cwd)
1379
+ }
1339
1380
  const [steerOn, setSteerOn] = useState(config !== null && config.steerAgent !== false)
1340
1381
  const [enrichOn, setEnrichOn] = useState(config !== null && config.enrichPrompts === true)
1341
1382
  useEffect(() => {
@@ -1356,7 +1397,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1356
1397
  const text = draft.trim()
1357
1398
  if (text.length === 0) return
1358
1399
  setDraft('')
1359
- editDirectives({ action: 'add', text: text.slice(0, 300) })
1400
+ editDirectives({ action: 'add', text: text.slice(0, 300), ...(scope.length > 0 ? { workspace: scope } : {}) })
1360
1401
  }
1361
1402
  return h('div', { className: 'tacit-panel-section', 'data-testid': 'tacit-steering' },
1362
1403
  h('div', { className: 'tacit-report-title' }, t('steer.title')),
@@ -1380,6 +1421,9 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1380
1421
  }),
1381
1422
  h('span', { className: 'tacit-directive-text' }, String(entry.text)),
1382
1423
  h('span', { className: 'tacit-chip' }, entry.source === 'user' ? t('steer.user') : t('steer.distilled')),
1424
+ typeof entry.workspace === 'string' && entry.workspace.length > 0
1425
+ ? h('span', { className: 'tacit-chip tacit-chip-scope', title: entry.workspace }, t('steer.workspace', { name: labelOf(entry.workspace) }))
1426
+ : null,
1383
1427
  entry.status === 'candidate'
1384
1428
  ? h('span', { className: 'tacit-chip tacit-chip-trial' }, t('steer.trial', {
1385
1429
  n: String(entry.trial !== null && typeof entry.trial === 'object' && typeof entry.trial.turns === 'number' ? entry.trial.turns : 0),
@@ -1402,6 +1446,16 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1402
1446
  if (event.key === 'Enter') onAdd()
1403
1447
  },
1404
1448
  }),
1449
+ workspaces.length > 0
1450
+ ? h('select', {
1451
+ className: 'tacit-input tacit-select',
1452
+ 'aria-label': t('steer.scope'),
1453
+ value: scope,
1454
+ onChange: (event) => setScope(event.target.value),
1455
+ },
1456
+ h('option', { value: '' }, t('steer.everywhere')),
1457
+ ...workspaces.map((entry) => h('option', { key: entry.cwd, value: entry.cwd }, entry.label)))
1458
+ : null,
1405
1459
  h('button', { type: 'button', className: 'tacit-btn tacit-btn-sm', disabled: draft.trim().length === 0, onClick: onAdd }, t('steer.add'))),
1406
1460
  steering !== null && typeof steering === 'object' && typeof steering.text === 'string' && steering.text.length > 0
1407
1461
  ? h('details', { className: 'tacit-preview' },
@@ -1425,6 +1479,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1425
1479
  const [model, setModel] = useState(config !== null && typeof config.model === 'string' ? config.model : 'deepseek-v4-flash')
1426
1480
  const [budgetText, setBudgetText] = useState(config !== null && typeof config.autoDailyBudget === 'number' ? String(config.autoDailyBudget) : '30')
1427
1481
  const [auto, setAuto] = useState(config !== null && config.autoAnalyze !== false)
1482
+ const [learnGood, setLearnGood] = useState(config !== null && config.learnFromGood !== false)
1428
1483
  const [live, setLive] = useState(config !== null && config.liveSuggestions !== false)
1429
1484
 
1430
1485
  useEffect(() => {
@@ -1432,6 +1487,7 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1432
1487
  if (typeof config.model === 'string') setModel(config.model)
1433
1488
  if (typeof config.autoDailyBudget === 'number') setBudgetText(String(config.autoDailyBudget))
1434
1489
  if (typeof config.autoAnalyze === 'boolean') setAuto(config.autoAnalyze)
1490
+ if (typeof config.learnFromGood === 'boolean') setLearnGood(config.learnFromGood)
1435
1491
  if (typeof config.liveSuggestions === 'boolean') setLive(config.liveSuggestions)
1436
1492
  }
1437
1493
  }, [config])
@@ -1445,6 +1501,11 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1445
1501
  setBudgetText(String(number))
1446
1502
  updateRootConfig({ autoDailyBudget: number })
1447
1503
  }
1504
+ const toggleLearnGood = () => {
1505
+ const next = !learnGood
1506
+ setLearnGood(next)
1507
+ updateRootConfig({ learnFromGood: next })
1508
+ }
1448
1509
  const toggleAuto = () => {
1449
1510
  const next = !auto
1450
1511
  setAuto(next)
@@ -1484,6 +1545,9 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1484
1545
  h('div', { className: 'tacit-settings-row' },
1485
1546
  h('label', { className: 'tacit-settings-label' }, t('settings.auto')),
1486
1547
  h('input', { type: 'checkbox', checked: auto, onChange: toggleAuto })),
1548
+ h('div', { className: 'tacit-settings-row' },
1549
+ h('label', { className: 'tacit-settings-label' }, t('settings.learnGood')),
1550
+ h('input', { type: 'checkbox', checked: learnGood, onChange: toggleLearnGood })),
1487
1551
  h('div', { className: 'tacit-settings-row' },
1488
1552
  h('label', { className: 'tacit-settings-label' }, t('settings.budget')),
1489
1553
  h('input', {
@@ -1502,7 +1566,8 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1502
1566
  error !== null && typeof error === 'object'
1503
1567
  ? h('div', { className: 'tacit-error' }, t('err.' + String(error.code), { detail: String(error.detail || '') }))
1504
1568
  : null,
1505
- h(DirectivesEditorView, { config, directives, steering: rootStore.steering }),
1569
+ h(DirectivesEditorView, {
1570
+ workspaces: rootStore.workspaces, config, directives, steering: rootStore.steering }),
1506
1571
  h('div', { className: 'tacit-panel-section' },
1507
1572
  h('div', { className: 'tacit-report-title' }, t('panel.styleRules')),
1508
1573
  styleRules.length === 0
@@ -1594,13 +1659,13 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1594
1659
  + '.tacit-modal-col-title{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);margin-bottom:6px}'
1595
1660
  + '.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}'
1596
1661
  + '.tacit-modal-actions{display:flex;gap:8px;justify-content:flex-end}'
1597
- + '.tacit-feedback{display:flex;justify-content:center;align-items:center;margin:8px 2px 0;font-size:12px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:6px 10px;gap:8px;transition:opacity .35s ease}.tacit-feedback-fading{opacity:0}'
1662
+ + '.tacit-feedback{display:flex;justify-content:center;align-items:center;margin:0 2px 8px;font-size:12px;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);border-radius:8px;padding:6px 10px;gap:8px;transition:opacity .35s ease}.tacit-feedback-fading{opacity:0}'
1598
1663
  + '.tacit-feedback-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.tacit-feedback-title{color:var(--dsw-alias-label-secondary)}'
1599
1664
  + '.tacit-feedback-vote{font:inherit;font-size:14px;line-height:1;cursor:pointer;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);border-radius:999px;padding:3px 8px}.tacit-feedback-vote:hover{border-color:var(--dsw-alias-brand-primary)}.tacit-feedback-vote-active{border-color:var(--dsw-alias-state-warn-primary);background:color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent)}'
1600
1665
  + '.tacit-feedback-reason{display:flex;align-items:center;gap:6px;flex-wrap:wrap}.tacit-feedback-input{width:260px;max-width:60vw}'
1601
1666
  + '.tacit-feedback-noted{color:var(--dsw-alias-state-success-primary);font-weight:600}'
1602
1667
  + '.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}'
1603
- + '.tacit-chip-trial{color:var(--dsw-alias-brand-primary)}.tacit-chip-ok{color:var(--dsw-alias-state-success-primary)}'
1668
+ + '.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}'
1604
1669
  + '.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}'
1605
1670
  + '.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}'
1606
1671
 
@@ -1650,11 +1715,12 @@ if (typeof window === 'undefined' || window.__ModuleLoader__ === undefined || ty
1650
1715
  inject: (sessionId) => ({ tacitStore: storeFor(sessionId) }),
1651
1716
  }, (props) => h(PreviewOverlayView, props)))
1652
1717
 
1653
- // The post-apply 👍/👎 strip lives in the band UNDER the composer card
1654
- // (composer.dock), only while the Improve button is enabled.
1718
+ // The post-apply 👍/👎 strip lives in the full-width row ABOVE the composer
1719
+ // card (input.dock). Not composer.dock: the harness hides that one until a
1720
+ // conversation has content, which is exactly when a first draft is improved.
1655
1721
  const FeedbackStripView = FeedbackStrip(kit)
1656
- ctx.slots.inject('conversation.composer.dock', () => ctx.slots.register({
1657
- name: 'conversation.composer.dock',
1722
+ ctx.slots.inject('conversation.input.dock', () => ctx.slots.register({
1723
+ name: 'conversation.input.dock',
1658
1724
  id: 'tacit-feedback',
1659
1725
  order: 10,
1660
1726
  locale: NS,
package/docs/README.md CHANGED
@@ -9,13 +9,13 @@ Pick the question you have:
9
9
 
10
10
  | I want to… | Read |
11
11
  | --- | --- |
12
- | Install it and see it working in five minutes | [Getting started](getting-started.md) |
12
+ | Install it and see it working in five minutes | [Getting started](getting-started.md) ([中文](getting-started.zh.md)) |
13
13
  | Understand what it does, step by step, and what the words mean | [How it works](how-it-works.md) |
14
14
  | Know what leaves my machine, what it costs, and what it can't do yet | [Privacy, cost & limitations](privacy-and-cost.md) |
15
15
  | Change a setting | [Configuration](configuration.md) |
16
- | Read or change the code | [Architecture](architecture.md) · [Contributing](../CONTRIBUTING.md) |
16
+ | Read or change the code | [Architecture](architecture.md) · [Contributing](../CONTRIBUTING.md) ([中文](CONTRIBUTING.zh.md)) |
17
17
  | See what changed between versions | [Changelog](../CHANGELOG.md) |
18
18
 
19
19
  Reading order for a newcomer: Getting started → How it works → Privacy & cost.
20
20
 
21
- 中文:[README.zh.md](README.zh.md)(仅 README 有中文版)。
21
+ 中文:[README.zh.md](README.zh.md) · [快速开始](getting-started.zh.md) · [贡献指南](CONTRIBUTING.zh.md)(其余文档为英文)。
package/docs/README.zh.md CHANGED
@@ -68,15 +68,16 @@ Tacit 从不接触你的 API Key(所有调用都经过 harness 自己的模型
68
68
  完整的数据流与成本表、以及坦白的限制清单(英文):
69
69
  [Privacy, cost & limitations](https://github.com/hackernotfound/dsh-tacit/blob/main/docs/privacy-and-cost.md)。
70
70
 
71
- ## 文档(均为英文)
71
+ ## 文档(除标注外均为英文)
72
72
 
73
73
  | | |
74
74
  | --- | --- |
75
- | [Getting started](https://github.com/hackernotfound/dsh-tacit/blob/main/docs/getting-started.md) | 安装、确认已启用、快速起步、界面各处在哪、排障 |
75
+ | [快速开始](https://github.com/hackernotfound/dsh-tacit/blob/main/docs/getting-started.zh.md)([English](https://github.com/hackernotfound/dsh-tacit/blob/main/docs/getting-started.md) | 安装、确认已启用、快速起步、界面各处在哪、排障 |
76
76
  | [How it works](https://github.com/hackernotfound/dsh-tacit/blob/main/docs/how-it-works.md) | 逐步流程,带图和术语表 |
77
77
  | [Privacy, cost & limitations](https://github.com/hackernotfound/dsh-tacit/blob/main/docs/privacy-and-cost.md) | 什么留在本地、什么会发出去、每次调用的花费、目前做不到的事 |
78
78
  | [Configuration](https://github.com/hackernotfound/dsh-tacit/blob/main/docs/configuration.md) | 所有设置项、默认值和取值范围 |
79
79
  | [Architecture](https://github.com/hackernotfound/dsh-tacit/blob/main/docs/architecture.md) | 面向贡献者:模块、钩子、路由、存储 |
80
- | [Contributing](https://github.com/hackernotfound/dsh-tacit/blob/main/CONTRIBUTING.md) · [Changelog](https://github.com/hackernotfound/dsh-tacit/blob/main/CHANGELOG.md) | |
80
+ | [贡献指南](https://github.com/hackernotfound/dsh-tacit/blob/main/docs/CONTRIBUTING.zh.md)[English](https://github.com/hackernotfound/dsh-tacit/blob/main/CONTRIBUTING.md) | fork → 分支 → PR 的流程、测试、基本规则;欢迎提 issue 和 PR |
81
+ | [Changelog](https://github.com/hackernotfound/dsh-tacit/blob/main/CHANGELOG.md) | 各版本的变更 |
81
82
 
82
83
  MIT © hackernotfound