tink-harness 1.10.0 → 1.11.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tink",
3
3
  "description": "A small harness layer for Claude Code and Codex.",
4
- "version": "1.10.0",
4
+ "version": "1.11.0",
5
5
  "author": {
6
6
  "name": "dotori"
7
7
  }
package/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to Tink are tracked here.
4
4
 
5
+ ## [1.11.0] - 2026-06-12
6
+
7
+ - **Fixed: update wiped run history.** `.tink/maintenance/` record files (`ledger.jsonl`, `friction.jsonl`, `weave-queue.json`) were in the always-overwrite set, so every npx `update` replaced the user's approval ledger and weave/friction signals with empty seeds - silently resetting dashboard usage history. They are now seed-only: created when missing, never overwritten.
8
+ - Fixed: update resurrected harnesses the user removed via an approved `/tink:frog` operation. The updater now reads `ledger.jsonl` frog entries and skips re-creating those files and index entries (other missing defaults are still restored; `--force` restores everything).
9
+ - Fixed: `dashboard` reported "opened in browser" even when the opener failed (e.g. no `xdg-open`); it now detects failure and tells you to open the file manually. Also fixed the installer's harness count including the human catalog file, and a `/tink:list` example that contradicted its own category rules.
10
+ - New `dashboard` subcommand: `npx tink-harness dashboard` generates the harness health report (lifecycle summary + HTML) from local `.tink` records and opens it in the default browser - no more memorizing the two `node .tink/tools/...` commands. `--no-open` generates the file only. Falls back to the packaged tools when `.tink/tools/` is missing, and finds `.tink` in the current or home directory.
11
+
5
12
  ## [1.10.0] - 2026-06-12
6
13
 
7
14
  - update: previously the npx `update` reset install scope and git policy to defaults; it now reuses the choices stored at install time (`.tink/config.json` gains `git_policy`). Choosing "커밋 안 함" (commit no .tink files) now means `.gitignore` is never created or edited - by install or by update - and a legacy whole-directory `.tink/` ignore line is left untouched.
package/README.ko.md CHANGED
@@ -10,7 +10,7 @@ Tink는 사소하지 않은 모든 에이전트 작업을 눈에 보이는 파
10
10
 
11
11
  <sub>Claude Code와 Codex를 위한 작은 하네스 레이어</sub>
12
12
 
13
- **최신 패키지:** v1.10.0 — 기본 하네스가 기능 특화 세트로 바뀌었습니다. 일반 작업은 하네스 없이 기본 절차로 진행하고, update가 퇴역한 범용 하네스를 자동 정리하며 설치 때 선택(언어·범위·git 정책)을 재사용합니다. weave/frog에는 건강 요약 기반 정리와 임시초안 승격이 추가됐습니다. 전체 변경 이력은 [CHANGELOG](CHANGELOG.md)를 확인하세요.
13
+ **최신 패키지:** v1.11.0 — 대시보드: `npx tink-harness dashboard`로 하네스 건강 리포트를 만들고 브라우저로 바로 엽니다. update가 승인 이력·신호 기록을 지우던 심각한 버그와 frog 삭제한 하네스가 부활하던 문제도 고쳤습니다. 전체 변경 이력은 [CHANGELOG](CHANGELOG.md)를 확인하세요.
14
14
 
15
15
  [English](README.md) · **한국어** · [변경 이력](CHANGELOG.md)
16
16
 
@@ -101,14 +101,14 @@ $tink:cast 인증 모듈 리팩터링 # Codex
101
101
 
102
102
  ## 하네스 건강을 눈으로 확인
103
103
 
104
- 몇 번의 run이 쌓이면, 읽기 전용 helper 두 개가 기록을 로컬 대시보드로 바꿔 줍니다:
104
+ 몇 번의 run이 쌓이면, 명령 하나로 기록을 로컬 대시보드로 만들어 브라우저까지 열어 줍니다:
105
105
 
106
106
  ```bash
107
- node .tink/tools/generate-harness-lifecycle-summary.mjs
108
- node .tink/tools/render-harness-health-report.mjs
109
- # .tink/maintenance/harness-health-report.html 열기
107
+ npx tink-harness dashboard # 파일만 만들려면 --no-open 추가
110
108
  ```
111
109
 
110
+ 내부적으로는 읽기 전용 helper 두 개(`node .tink/tools/generate-harness-lifecycle-summary.mjs` → `node .tink/tools/render-harness-health-report.mjs`)를 실행한 뒤 `.tink/maintenance/harness-health-report.html`을 엽니다.
111
+
112
112
  ![Tink 대시보드 데모 — 건강 그룹 클릭, 하네스 카드 탐색, 3D 지도 조작](.github/assets/demo.gif)
113
113
 
114
114
  <sub>당신의 워크플로와 맞는다면, ⭐ 하나가 다른 개발자들이 찾는 데 도움이 됩니다.</sub>
@@ -147,7 +147,7 @@ Standalone / Codex:
147
147
  npx tink-harness@latest update
148
148
  ```
149
149
 
150
- 업데이트는 질문 하나 — 어떤 agent surface를 갱신할지 — 만 묻고 나머지는 자동으로 처리합니다. 언어·설치 범위·git 정책은 설치 때 선택한 값을 그대로 재사용하며, ".tink 커밋 안 함"을 선택했다면 업데이트가 `.gitignore`를 절대 건드리지 않습니다. Tink가 관리하는 파일(commands, skills, maintenance, 런타임 tools)은 항상 최신으로 덮어쓰고, 사용자가 수정한 하네스·메모리·설정은 보존합니다.
150
+ 업데이트는 질문 하나 — 어떤 agent surface를 갱신할지 — 만 묻고 나머지는 자동으로 처리합니다. 언어·설치 범위·git 정책은 설치 때 선택한 값을 그대로 재사용하며, ".tink 커밋 안 함"을 선택했다면 업데이트가 `.gitignore`를 절대 건드리지 않습니다. Tink가 관리하는 파일(commands, skills, 런타임 tools)은 항상 최신으로 덮어쓰고, 사용자가 수정한 하네스·메모리·설정과 `.tink/maintenance/`의 모든 기록(ledger 등)은 보존합니다.
151
151
 
152
152
  `CODEX_HOME`을 지정하지 않으면 Windows에서는 `%USERPROFILE%\.codex`, macOS/Linux에서는 `~/.codex`에 Codex skill이 설치됩니다.
153
153
 
package/README.md CHANGED
@@ -17,14 +17,14 @@
17
17
  <p><sub>A small harness layer for Claude Code and Codex</sub></p>
18
18
 
19
19
  <p>
20
- <a href="https://github.com/dotoricode/tink-harness/releases/tag/v1.10.0"><img src="https://img.shields.io/github/v/release/dotoricode/tink-harness?label=release&color=2ea44f" alt="GitHub release"></a>
20
+ <a href="https://github.com/dotoricode/tink-harness/releases/tag/v1.11.0"><img src="https://img.shields.io/github/v/release/dotoricode/tink-harness?label=release&color=2ea44f" alt="GitHub release"></a>
21
21
  <a href="https://www.npmjs.com/package/tink-harness"><img src="https://img.shields.io/npm/v/tink-harness?label=npm&color=cb3837" alt="npm version"></a>
22
22
  <a href="https://github.com/dotoricode/tink-harness/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/dotoricode/tink-harness/ci.yml?branch=main&label=ci" alt="CI"></a>
23
23
  <a href="https://github.com/dotoricode/tink-harness/blob/main/LICENSE"><img src="https://img.shields.io/github/license/dotoricode/tink-harness" alt="License"></a>
24
24
  <a href="https://github.com/dotoricode/tink-harness/stargazers"><img src="https://img.shields.io/github/stars/dotoricode/tink-harness?style=social" alt="GitHub stars"></a>
25
25
  </p>
26
26
 
27
- <p><strong>Latest package:</strong> v1.10.0 - The default harness set is now specialized-only: generic work runs as a base run (no harness), update cleans up retired generic harnesses automatically and reuses your install-time choices, and weave/frog gained health-summary-driven cleanup and draft promotion. See <a href="CHANGELOG.md">CHANGELOG</a> for release history.</p>
27
+ <p><strong>Latest package:</strong> v1.11.0 - One-line dashboard: <code>npx tink-harness dashboard</code> generates the harness health report and opens it in your browser. Also fixes a serious update bug that wiped approval-ledger and signal history, and stops update from resurrecting harnesses you removed via frog. See <a href="CHANGELOG.md">CHANGELOG</a> for release history.</p>
28
28
 
29
29
  **English** · [한국어](README.ko.md) · [Changelog](CHANGELOG.md)
30
30
 
@@ -115,14 +115,14 @@ $tink:cast refactor the auth module # Codex
115
115
 
116
116
  ## See your harness health
117
117
 
118
- After a few runs, two read-only helpers turn your records into a local dashboard:
118
+ After a few runs, one command turns your records into a local dashboard and opens it in your browser:
119
119
 
120
120
  ```bash
121
- node .tink/tools/generate-harness-lifecycle-summary.mjs
122
- node .tink/tools/render-harness-health-report.mjs
123
- # then open .tink/maintenance/harness-health-report.html
121
+ npx tink-harness dashboard # add --no-open to just generate the file
124
122
  ```
125
123
 
124
+ Under the hood it runs the two read-only helpers (`node .tink/tools/generate-harness-lifecycle-summary.mjs`, then `node .tink/tools/render-harness-health-report.mjs`) and opens `.tink/maintenance/harness-health-report.html`.
125
+
126
126
  ![Tink dashboard demo - clicking a health group, browsing harness cards, and inspecting the 3D map](.github/assets/demo.gif)
127
127
 
128
128
  <sub>If this matches your workflow, a ⭐ helps others find it.</sub>
@@ -187,7 +187,7 @@ To update an existing standalone install (Claude Code or Codex):
187
187
  npx tink-harness@latest update
188
188
  ```
189
189
 
190
- Update asks one question - which agent surface to refresh - and handles the rest automatically. Language, install scope, and git policy are reused from the choices you made at install time; if you chose not to commit `.tink`, update never touches your `.gitignore`. Tink-owned files (commands, skills, maintenance, runtime tools) are always brought to the latest version; your customized harnesses, memory, and config are preserved.
190
+ Update asks one question - which agent surface to refresh - and handles the rest automatically. Language, install scope, and git policy are reused from the choices you made at install time; if you chose not to commit `.tink`, update never touches your `.gitignore`. Tink-owned files (commands, skills, runtime tools) are always brought to the latest version; your customized harnesses, memory, config, and all `.tink/maintenance/` history records are preserved.
191
191
 
192
192
  If `CODEX_HOME` is not set, Codex skills default to `%USERPROFILE%\.codex` on Windows and `~/.codex` on macOS/Linux.
193
193
 
package/VERSIONING.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Versioning
2
2
 
3
- Current version: `1.10.0`
3
+ Current version: `1.11.0`
4
4
 
5
5
  Tink follows semver from `1.0.0` onward.
6
6
 
package/bin/install.js CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { spawnSync } from 'node:child_process';
2
3
  import crypto from 'node:crypto';
3
4
  import fs from 'node:fs';
4
5
  import os from 'node:os';
@@ -125,7 +126,70 @@ function argValue(name) {
125
126
  }
126
127
 
127
128
  function usage() {
128
- console.log(`Tink installer for Claude Code and Codex\n\nUsage:\n tink-harness [install] [--scope=repo|global] [--global] [--lang=en|ko|zh] [--yes] [--with-hook] [--clean-codex-picker] [--dry-run] [--force]\n tink-harness update [--scope=repo|global] [--global] [--lang=en|ko|zh] [--yes] [--clean-codex-picker] [--dry-run] [--force]\n\nIf the command is not installed yet, use:\n npx tink-harness@latest [install]\n npx tink-harness@latest update\n\nCommands:\n install Install Tink.\n update Update Tink to the latest templates. Asks only the agent surface; Tink-owned files always refresh, user-modified harness/memory/config files are kept.\n\nDefault interactive flow:\n 1. Select language\n 2. Show TINK wizard\n 3. Select Claude Code, Codex, or both\n 4. Select components\n 5. Select repo/global installation scope\n 6. Select Advanced options\n 7. Select git tracking policy for project state\n\nAdvanced options:\n --dry-run Preview only. Show what would be written or removed, but do not change files.\n --force Overwrite user-modified files. Use only when you want official templates to replace local edits.\n --clean-codex-picker Codex-only cleanup. Remove repo-local Claude Tink surfaces that show as Source Command Tink entries.\n\nEnvironment:\n TINK_INSTALL_SURFACES=claude|codex|all\n TINK_CLEAN_CODEX_PICKER=1\n\nScopes:\n repo Install shared .tink files into the current project.\n global Install shared .tink files into your home directory.\n`);
129
+ console.log(`Tink installer for Claude Code and Codex\n\nUsage:\n tink-harness [install] [--scope=repo|global] [--global] [--lang=en|ko|zh] [--yes] [--with-hook] [--clean-codex-picker] [--dry-run] [--force]\n tink-harness update [--scope=repo|global] [--global] [--lang=en|ko|zh] [--yes] [--clean-codex-picker] [--dry-run] [--force]\n tink-harness dashboard [--no-open]\n\nIf the command is not installed yet, use:\n npx tink-harness@latest [install]\n npx tink-harness@latest update\n\nCommands:\n install Install Tink.\n update Update Tink to the latest templates. Asks only the agent surface; Tink-owned files always refresh, user-modified harness/memory/config files are kept.\n dashboard Generate the harness health report from local .tink records and open it in your browser. Use --no-open to skip opening.\n\nDefault interactive flow:\n 1. Select language\n 2. Show TINK wizard\n 3. Select Claude Code, Codex, or both\n 4. Select components\n 5. Select repo/global installation scope\n 6. Select Advanced options\n 7. Select git tracking policy for project state\n\nAdvanced options:\n --dry-run Preview only. Show what would be written or removed, but do not change files.\n --force Overwrite user-modified files. Use only when you want official templates to replace local edits.\n --clean-codex-picker Codex-only cleanup. Remove repo-local Claude Tink surfaces that show as Source Command Tink entries.\n\nEnvironment:\n TINK_INSTALL_SURFACES=claude|codex|all\n TINK_CLEAN_CODEX_PICKER=1\n\nScopes:\n repo Install shared .tink files into the current project.\n global Install shared .tink files into your home directory.\n`);
130
+ }
131
+
132
+ function findTinkRoot() {
133
+ for (const dir of [process.cwd(), os.homedir()]) {
134
+ if (fs.existsSync(path.join(dir, '.tink'))) return dir;
135
+ }
136
+ return null;
137
+ }
138
+
139
+ function openInBrowser(file) {
140
+ let result;
141
+ if (process.platform === 'win32') {
142
+ result = spawnSync('cmd', ['/c', 'start', '', file], { stdio: 'ignore' });
143
+ } else if (process.platform === 'darwin') {
144
+ result = spawnSync('open', [file], { stdio: 'ignore' });
145
+ } else {
146
+ result = spawnSync('xdg-open', [file], { stdio: 'ignore' });
147
+ }
148
+ return !result.error && result.status === 0;
149
+ }
150
+
151
+ function runDashboard() {
152
+ const target = findTinkRoot();
153
+ const language = detectInstalledLanguage() || detectLanguage();
154
+ if (!target) {
155
+ console.error(language === 'ko'
156
+ ? '.tink 디렉토리를 찾을 수 없습니다(현재 디렉토리·홈 디렉토리 확인). 먼저 `npx tink-harness@latest install`을 실행하세요.'
157
+ : 'No .tink directory found in the current or home directory. Run `npx tink-harness@latest install` first.');
158
+ process.exit(1);
159
+ }
160
+ const toolFor = (name) => {
161
+ const installed = path.join(target, '.tink/tools', name);
162
+ return fs.existsSync(installed) ? installed : path.join(root, 'templates/tink/tools', name);
163
+ };
164
+ const steps = [
165
+ toolFor('generate-harness-lifecycle-summary.mjs'),
166
+ toolFor('render-harness-health-report.mjs')
167
+ ];
168
+ for (const tool of steps) {
169
+ const result = spawnSync(process.execPath, [tool], { cwd: target, stdio: 'inherit' });
170
+ if (result.status !== 0) {
171
+ console.error(language === 'ko'
172
+ ? `대시보드 생성 실패: ${path.basename(tool)}`
173
+ : `Dashboard step failed: ${path.basename(tool)}`);
174
+ process.exit(result.status || 1);
175
+ }
176
+ }
177
+ const reportPath = path.join(target, '.tink/maintenance/harness-health-report.html');
178
+ if (!fs.existsSync(reportPath)) {
179
+ console.error(language === 'ko'
180
+ ? `리포트 파일이 없습니다: ${reportPath}`
181
+ : `Report not found: ${reportPath}`);
182
+ process.exit(1);
183
+ }
184
+ console.log(language === 'ko' ? `대시보드: ${reportPath}` : `Dashboard: ${reportPath}`);
185
+ if (args.includes('--no-open')) return;
186
+ if (openInBrowser(reportPath)) {
187
+ console.log(language === 'ko' ? '기본 브라우저에서 열었습니다.' : 'Opened in your default browser.');
188
+ } else {
189
+ console.log(language === 'ko'
190
+ ? '브라우저 자동 열기에 실패했습니다. 위 경로의 파일을 직접 열어주세요.'
191
+ : 'Could not open a browser automatically. Open the file above manually.');
192
+ }
129
193
  }
130
194
 
131
195
  function normalizeSurfaces(surfaces) {
@@ -366,7 +430,8 @@ function handleCancel(value) {
366
430
 
367
431
  function readHarnessCount() {
368
432
  const dir = path.join(root, 'templates/tink/harnesses');
369
- return fs.readdirSync(dir).filter((name) => name.endsWith('.md')).length;
433
+ // HARNESS.md is the human catalog, not a harness
434
+ return fs.readdirSync(dir).filter((name) => name.endsWith('.md') && name !== 'HARNESS.md').length;
370
435
  }
371
436
 
372
437
  function displayPath(base, filePath) {
@@ -410,10 +475,17 @@ function isAlwaysUpdatePath(src) {
410
475
  return rel.startsWith('templates/claude/commands/') ||
411
476
  rel.startsWith('templates/claude/skills/') ||
412
477
  rel.startsWith('templates/codex/skills/') ||
413
- rel.startsWith('templates/tink/maintenance/') ||
414
478
  rel.startsWith('templates/tink/tools/');
415
479
  }
416
480
 
481
+ function isSeedOnlyPath(src) {
482
+ // Runtime record files (ledger, friction, weave queue): the template only
483
+ // seeds them. Once they exist they hold user history and must never be
484
+ // overwritten by install or update.
485
+ const rel = path.relative(root, src).replace(/\\/g, '/');
486
+ return rel.startsWith('templates/tink/maintenance/');
487
+ }
488
+
417
489
  // Generic task-type harnesses retired from the default set: generic work now
418
490
  // runs on the base run contract alone. Values are normalized (CR-stripped)
419
491
  // sha256 hashes of every version ever shipped, so update can tell shipped
@@ -445,6 +517,42 @@ function normalizedSha256(content) {
445
517
  return crypto.createHash('sha256').update(content.replace(/\r/g, '')).digest('hex');
446
518
  }
447
519
 
520
+ // Default harnesses the user explicitly removed via an approved /tink:frog
521
+ // operation. Update must not resurrect them.
522
+ const retiredByFrog = new Set();
523
+
524
+ function harnessNameFromDest(dest) {
525
+ const match = String(dest).replace(/\\/g, '/').match(/\.tink\/harnesses\/([^/]+)\.md$/);
526
+ return match ? match[1] : '';
527
+ }
528
+
529
+ function loadFroggedHarnessNames(target) {
530
+ retiredByFrog.clear();
531
+ const ledgerPath = path.join(target, '.tink/maintenance/ledger.jsonl');
532
+ if (!fs.existsSync(ledgerPath)) return;
533
+ let lines;
534
+ try {
535
+ lines = fs.readFileSync(ledgerPath, 'utf8').split('\n');
536
+ } catch {
537
+ return;
538
+ }
539
+ for (const line of lines) {
540
+ const text = line.replace(/^/, '').trim();
541
+ if (!text) continue;
542
+ try {
543
+ const entry = JSON.parse(text);
544
+ if (entry && entry.type === 'frog' && entry.result === 'applied' && Array.isArray(entry.files)) {
545
+ for (const file of entry.files) {
546
+ const name = harnessNameFromDest(file);
547
+ if (name && name !== 'index') retiredByFrog.add(name);
548
+ }
549
+ }
550
+ } catch {
551
+ // skip malformed ledger lines
552
+ }
553
+ }
554
+ }
555
+
448
556
  function removeRetiredHarnesses(templateRoot, target) {
449
557
  const harnessDir = path.join(target, '.tink/harnesses');
450
558
  if (!fs.existsSync(harnessDir)) return;
@@ -481,7 +589,8 @@ function syncHarnessIndex(templateRoot, target, cleared) {
481
589
  // append default entries the installed index does not know yet
482
590
  const kept = installed.filter((entry) => !(entry && cleared.includes(entry.name)));
483
591
  const knownNames = new Set(kept.map((entry) => entry && entry.name));
484
- const added = template.filter((entry) => entry && !knownNames.has(entry.name));
592
+ const added = template.filter((entry) =>
593
+ entry && !knownNames.has(entry.name) && !retiredByFrog.has(entry.name));
485
594
  const next = [...kept, ...added];
486
595
  if (next.length === installed.length && added.length === 0) return;
487
596
  log.message(`${dryRun ? 'would sync' : 'sync'} ${displayPath(target, indexPath)} (${installed.length - kept.length} retired removed, ${added.length} default added)`);
@@ -549,6 +658,13 @@ function isGeneratedLegacyRuleGraph(src, dest) {
549
658
 
550
659
  function writeFileFromTemplate(src, dest, base) {
551
660
  const exists = fs.existsSync(dest);
661
+ if (exists && !force && isSeedOnlyPath(src)) {
662
+ return;
663
+ }
664
+ if (isUpdate && !exists && retiredByFrog.has(harnessNameFromDest(dest))) {
665
+ log.message(`skip frog-removed ${displayPath(base, dest)}`);
666
+ return;
667
+ }
552
668
  if (exists && !force) {
553
669
  if (isUpdate) {
554
670
  const srcContent = fs.readFileSync(src);
@@ -783,6 +899,7 @@ function copySelected(scope, components, agent) {
783
899
  }
784
900
  }
785
901
  if (components.includes('harnesses')) {
902
+ if (isUpdate) loadFroggedHarnessNames(target);
786
903
  copyDir(path.join(templateRoot, 'tink/harnesses'), path.join(target, '.tink/harnesses'), target);
787
904
  copyDir(path.join(templateRoot, 'tink/rules'), path.join(target, '.tink/rules'), target);
788
905
  copyDir(path.join(templateRoot, 'tink/schemas'), path.join(target, '.tink/schemas'), target);
@@ -1099,6 +1216,11 @@ async function main() {
1099
1216
  process.exit(0);
1100
1217
  }
1101
1218
 
1219
+ if (command === 'dashboard') {
1220
+ runDashboard();
1221
+ return;
1222
+ }
1223
+
1102
1224
  if (command !== 'install' && command !== 'update') {
1103
1225
  console.error(`Unknown command: ${command}`);
1104
1226
  usage();
package/commands/list.md CHANGED
@@ -11,7 +11,7 @@ List available Tink harnesses without loading every harness body.
11
11
  2. Read only compact usage metadata from `.tink/runs/` (frontmatter `selected_harnesses` / `actually_loaded_harnesses` + dates), `.tink/maintenance/ledger.jsonl`, and `.tink/maintenance/weave-queue.json`. Do not load raw logs.
12
12
  3. Treat `.tink/current/` as weak evidence unless it is clearly from the same active conversation. If context is uncertain, label it `stale current candidate`, not proof of usage.
13
13
  4. Classify every harness into exactly one of three categories:
14
- - **working** — directly performs or gates tasks (e.g. `ship`, `pr-merge`, `requirements-interview`, `plan-consensus`, `goal-checkpoint`, `delegation-brief`). Generic work (code change, research, review, docs) runs on the base run without a harness, so it does not appear here.
14
+ - **working** — directly performs or gates tasks (e.g. `ship`, `requirements-interview`, `plan-consensus`, `goal-checkpoint`, `delegation-brief`). Generic work (code change, research, review, docs) runs on the base run without a harness, so it does not appear here.
15
15
  - **meta** — manages other harnesses or Tink itself. Treat these names as meta regardless of `kind`: `harness-synthesis`, `harness-curation`, `tink-feedback-apply`.
16
16
  - **custom (this repo)** — `kind: synthesized` in `index.json` (created in this repo, not part of the default set). If a synthesized harness also matches a meta name, prefer meta.
17
17
  5. Compute the signal per harness:
@@ -15,7 +15,8 @@ This command does not run the update itself. It detects how Tink was installed i
15
15
  - If the project root (or `cwd`) has `.claude-plugin/plugin.json` and a top-level `commands/` directory, Tink was installed via Claude Code plugin marketplace.
16
16
  - Otherwise, treat it as an `npx tink-harness install` (standalone) installation.
17
17
  3. Scan for files that have diverged from the latest installed templates (read-only inspection only):
18
- - **Always updated**: `.claude/commands/tink/`, `.claude/skills/tink/`, `.tink/maintenance/`, `.tink/tools/` — template changes always propagate here.
18
+ - **Always updated**: `.claude/commands/tink/`, `.claude/skills/tink/`, `.tink/tools/` — template changes always propagate here.
19
+ - **Never overwritten once they exist**: `.tink/maintenance/` record files (`ledger.jsonl`, `friction.jsonl`, `weave-queue.json`) hold user history; the template only seeds them when missing.
19
20
  - **Preserved if user-modified**: `.tink/harnesses/`, `.tink/hooks/`, `.tink/memory/`, `.tink/config.json` — respects `weave` customizations and local configuration.
20
21
  4. Show the appropriate update path and a short list of files in the "preserved" category that have diverged.
21
22
 
@@ -38,7 +39,8 @@ npx tink-harness@latest update
38
39
  ```
39
40
 
40
41
  The `update` subcommand asks only one question - which agent surface to refresh (Claude Code, Codex, or both). Everything else updates automatically:
41
- - **Always overwrites**: commands, skills, maintenance, and runtime tools (`.claude/commands/tink/`, `.claude/skills/tink/`, `.tink/maintenance/`, `.tink/tools/`) — so you get the latest harness runner, report tools, and command behavior automatically.
42
+ - **Always overwrites**: commands, skills, and runtime tools (`.claude/commands/tink/`, `.claude/skills/tink/`, `.tink/tools/`) — so you get the latest harness runner, report tools, and command behavior automatically.
43
+ - **Never overwrites records**: `.tink/maintenance/` ledger, friction, and weave-queue files are user history; they are only seeded when missing.
42
44
  - **Preserves if modified**: harnesses, hooks, memory, and config (`.tink/harnesses/`, `.tink/hooks/`, `.tink/memory/`, `.tink/config.json`) — respects your `weave` customizations and local settings.
43
45
  - **Reuses stored choices**: language, install scope, and git policy come from `.tink/config.json`. With `git_policy: "none"` (커밋 안 함) the updater never creates or edits `.gitignore`, and an existing whole-directory `.tink/` ignore line is left as-is.
44
46
 
@@ -62,7 +64,7 @@ If the source-repo guard triggers, print only this and stop — do not present p
62
64
 
63
65
  **설치 경로**: <plugin marketplace | npx standalone>
64
66
 
65
- **항상 업데이트됨**: commands, skills, maintenance, tools (최신 버전으로 자동 반영)
67
+ **항상 업데이트됨**: commands, skills, tools (최신 버전으로 자동 반영) · maintenance 기록 파일은 보존
66
68
 
67
69
  **사용자 수정 파일** (업데이트 시 보존):
68
70
  - <path1>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tink-harness",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "description": "Self-growing harnesses for Claude Code and Codex.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -11,7 +11,7 @@ List available Tink harnesses without loading every harness body.
11
11
  2. Read only compact usage metadata from `.tink/runs/` (frontmatter `selected_harnesses` / `actually_loaded_harnesses` + dates), `.tink/maintenance/ledger.jsonl`, and `.tink/maintenance/weave-queue.json`. Do not load raw logs.
12
12
  3. Treat `.tink/current/` as weak evidence unless it is clearly from the same active conversation. If context is uncertain, label it `stale current candidate`, not proof of usage.
13
13
  4. Classify every harness into exactly one of three categories:
14
- - **working** — directly performs or gates tasks (e.g. `ship`, `pr-merge`, `requirements-interview`, `plan-consensus`, `goal-checkpoint`, `delegation-brief`). Generic work (code change, research, review, docs) runs on the base run without a harness, so it does not appear here.
14
+ - **working** — directly performs or gates tasks (e.g. `ship`, `requirements-interview`, `plan-consensus`, `goal-checkpoint`, `delegation-brief`). Generic work (code change, research, review, docs) runs on the base run without a harness, so it does not appear here.
15
15
  - **meta** — manages other harnesses or Tink itself. Treat these names as meta regardless of `kind`: `harness-synthesis`, `harness-curation`, `tink-feedback-apply`.
16
16
  - **custom (this repo)** — `kind: synthesized` in `index.json` (created in this repo, not part of the default set). If a synthesized harness also matches a meta name, prefer meta.
17
17
  5. Compute the signal per harness:
@@ -15,7 +15,8 @@ This command does not run the update itself. It detects how Tink was installed i
15
15
  - If the project root (or `cwd`) has `.claude-plugin/plugin.json` and a top-level `commands/` directory, Tink was installed via Claude Code plugin marketplace.
16
16
  - Otherwise, treat it as an `npx tink-harness install` (standalone) installation.
17
17
  3. Scan for files that have diverged from the latest installed templates (read-only inspection only):
18
- - **Always updated**: `.claude/commands/tink/`, `.claude/skills/tink/`, `.tink/maintenance/`, `.tink/tools/` — template changes always propagate here.
18
+ - **Always updated**: `.claude/commands/tink/`, `.claude/skills/tink/`, `.tink/tools/` — template changes always propagate here.
19
+ - **Never overwritten once they exist**: `.tink/maintenance/` record files (`ledger.jsonl`, `friction.jsonl`, `weave-queue.json`) hold user history; the template only seeds them when missing.
19
20
  - **Preserved if user-modified**: `.tink/harnesses/`, `.tink/hooks/`, `.tink/memory/`, `.tink/config.json` — respects `weave` customizations and local configuration.
20
21
  4. Show the appropriate update path and a short list of files in the "preserved" category that have diverged.
21
22
 
@@ -38,7 +39,8 @@ npx tink-harness@latest update
38
39
  ```
39
40
 
40
41
  The `update` subcommand asks only one question - which agent surface to refresh (Claude Code, Codex, or both). Everything else updates automatically:
41
- - **Always overwrites**: commands, skills, maintenance, and runtime tools (`.claude/commands/tink/`, `.claude/skills/tink/`, `.tink/maintenance/`, `.tink/tools/`) — so you get the latest harness runner, report tools, and command behavior automatically.
42
+ - **Always overwrites**: commands, skills, and runtime tools (`.claude/commands/tink/`, `.claude/skills/tink/`, `.tink/tools/`) — so you get the latest harness runner, report tools, and command behavior automatically.
43
+ - **Never overwrites records**: `.tink/maintenance/` ledger, friction, and weave-queue files are user history; they are only seeded when missing.
42
44
  - **Preserves if modified**: harnesses, hooks, memory, and config (`.tink/harnesses/`, `.tink/hooks/`, `.tink/memory/`, `.tink/config.json`) — respects your `weave` customizations and local settings.
43
45
  - **Reuses stored choices**: language, install scope, and git policy come from `.tink/config.json`. With `git_policy: "none"` (커밋 안 함) the updater never creates or edits `.gitignore`, and an existing whole-directory `.tink/` ignore line is left as-is.
44
46
 
@@ -62,7 +64,7 @@ If the source-repo guard triggers, print only this and stop — do not present p
62
64
 
63
65
  **설치 경로**: <plugin marketplace | npx standalone>
64
66
 
65
- **항상 업데이트됨**: commands, skills, maintenance, tools (최신 버전으로 자동 반영)
67
+ **항상 업데이트됨**: commands, skills, tools (최신 버전으로 자동 반영) · maintenance 기록 파일은 보존
66
68
 
67
69
  **사용자 수정 파일** (업데이트 시 보존):
68
70
  - <path1>