tink-harness 1.9.10 → 1.9.11

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.9.10",
4
+ "version": "1.9.11",
5
5
  "author": {
6
6
  "name": "dotori"
7
7
  }
package/CHANGELOG.md CHANGED
@@ -6,6 +6,14 @@ All notable changes to Tink are tracked here.
6
6
 
7
7
  No unreleased changes yet.
8
8
 
9
+ ## [1.9.11] - 2026-06-11
10
+
11
+ ### Changed
12
+
13
+ - Home health-group selection no longer carries over into the harness map or cards - it only opens the inline list and next-action suggestion on Home.
14
+ - Removed the Move/Rotate toggle: left-drag always pans, right-drag always rotates, and the in-map hint reflects this fixed mapping.
15
+ - The selected-node panel now starts empty ("no harness selected") instead of showing an arbitrary first harness, and uses the same tone-chip format as click selections; next-action phrasing was neutralized to fit single harnesses as well as groups.
16
+
9
17
  ## [1.9.10] - 2026-06-11
10
18
 
11
19
  ### Changed
package/VERSIONING.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Versioning
2
2
 
3
- Current version: `1.9.10`
3
+ Current version: `1.9.11`
4
4
 
5
5
  Tink follows semver from `1.0.0` onward.
6
6
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tink-harness",
3
- "version": "1.9.10",
3
+ "version": "1.9.11",
4
4
  "description": "Self-growing harnesses for Claude Code and Codex.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -161,10 +161,10 @@ const COPY = {
161
161
  frog_candidate: ['Cleanup review', 'bad']
162
162
  },
163
163
  actions: {
164
- keep: { what: 'This group is healthy and proven by records.', next: 'No action needed - just keep using it.', command: '', expect: '' },
164
+ keep: { what: 'Healthy and proven by records.', next: 'No action needed - just keep using it.', command: '', expect: '' },
165
165
  observe: { what: 'Not enough records to judge yet.', next: 'Keep working normally with /tink:cast so records accumulate.', command: '/tink:cast', expect: 'What happens: it picks the right harness for your task, plans the run, and the work gets recorded - improving future judgments.' },
166
- weave: { what: 'Repeated friction was recorded here.', next: 'Run /tink:weave to prepare a small improvement proposal.', command: '/tink:weave', expect: 'What happens: it drafts an improvement (e.g. updated instructions) from the recorded friction and shows it to you. Nothing changes until you approve.' },
167
- merge_candidate: { what: 'These are often used together with another harness.', next: 'Run /tink:weave to check the overlap and decide whether to combine them.', command: '/tink:weave', expect: 'What happens: it inspects the overlap evidence and proposes whether to combine or keep separate. Nothing changes until you approve.' },
166
+ weave: { what: 'Repeated friction shows up in the records.', next: 'Run /tink:weave to prepare a small improvement proposal.', command: '/tink:weave', expect: 'What happens: it drafts an improvement (e.g. updated instructions) from the recorded friction and shows it to you. Nothing changes until you approve.' },
167
+ merge_candidate: { what: 'Often used together with another harness.', next: 'Run /tink:weave to check the overlap and decide whether to combine them.', command: '/tink:weave', expect: 'What happens: it inspects the overlap evidence and proposes whether to combine or keep separate. Nothing changes until you approve.' },
168
168
  frog_candidate: { what: 'Repeated trouble plus high cost - cleanup candidates.', next: 'Run /tink:frog to review archive/delete with approval.', command: '/tink:frog', expect: 'What happens: it lists cleanup candidates with their evidence. Archiving or deleting only happens after your explicit approval.' }
169
169
  },
170
170
  recPlain: {
@@ -299,10 +299,10 @@ COPY.ko = {
299
299
  frog_candidate: ['정리 검토', 'bad']
300
300
  },
301
301
  actions: {
302
- keep: { what: '기록으로 검증된 건강한 그룹이에요.', next: '별도 행동이 필요 없어요 — 계속 사용하면 됩니다.', command: '', expect: '' },
302
+ keep: { what: '기록으로 검증되어 있어요.', next: '별도 행동이 필요 없어요 — 계속 사용하면 됩니다.', command: '', expect: '' },
303
303
  observe: { what: '아직 판단할 기록이 부족해요.', next: '/tink:cast로 평소처럼 작업하면 기록이 쌓여 판단이 정확해져요.', command: '/tink:cast', expect: '실행하면: 작업에 맞는 하네스를 골라 계획을 세우고, 끝나면 이번 작업이 기록으로 남아 다음 판단이 정확해져요.' },
304
- weave: { what: '반복되는 마찰이 기록된 그룹이에요.', next: '/tink:weave를 실행해 작은 개선 제안을 준비하세요.', command: '/tink:weave', expect: '실행하면: 기록된 마찰을 바탕으로 개선안(지침 수정 등)을 만들어 보여줘요. 승인하기 전에는 아무것도 바뀌지 않아요.' },
305
- merge_candidate: { what: '다른 하네스와 자주 함께 쓰이는 그룹이에요.', next: '/tink:weave로 겹침을 확인하고 합칠지 검토하세요.', command: '/tink:weave', expect: '실행하면: 겹침 근거를 살펴보고 합칠지 따로 둘지 제안해 줘요. 승인 전에는 아무것도 바뀌지 않아요.' },
304
+ weave: { what: '반복되는 마찰이 기록되어 있어요.', next: '/tink:weave를 실행해 작은 개선 제안을 준비하세요.', command: '/tink:weave', expect: '실행하면: 기록된 마찰을 바탕으로 개선안(지침 수정 등)을 만들어 보여줘요. 승인하기 전에는 아무것도 바뀌지 않아요.' },
305
+ merge_candidate: { what: '다른 하네스와 자주 함께 쓰여요.', next: '/tink:weave로 겹침을 확인하고 합칠지 검토하세요.', command: '/tink:weave', expect: '실행하면: 겹침 근거를 살펴보고 합칠지 따로 둘지 제안해 줘요. 승인 전에는 아무것도 바뀌지 않아요.' },
306
306
  frog_candidate: { what: '반복 문제와 높은 비용이 기록됐어요 — 정리 후보예요.', next: '/tink:frog로 보관/삭제 검토를 승인 절차와 함께 진행하세요.', command: '/tink:frog', expect: '실행하면: 정리 후보와 근거를 정리해 보여줘요. 보관·삭제는 명시적으로 승인해야만 실제로 진행돼요.' }
307
307
  },
308
308
  recPlain: {
@@ -874,10 +874,6 @@ function renderGraphCanvas(summary, copy) {
874
874
  <button class="active" type="button" data-mode="full" aria-pressed="true">${escapeHtml(copy.full)}</button>
875
875
  <button type="button" data-mode="core" aria-pressed="false">${escapeHtml(copy.core)}</button>
876
876
  </div>
877
- <div class="map-controls" aria-label="drag mode">
878
- <button class="active" type="button" data-drag="pan" aria-pressed="true">${escapeHtml(copy.dragPan || 'Move')}</button>
879
- <button type="button" data-drag="rotate" aria-pressed="false">${escapeHtml(copy.dragRotate || 'Rotate')}</button>
880
- </div>
881
877
  <div class="map-controls" aria-label="zoom">
882
878
  <button type="button" data-zoom="in" aria-label="${escapeAttr(copy.zoomIn || 'Zoom in')}" title="${escapeAttr(copy.zoomIn || 'Zoom in')}">+</button>
883
879
  <button type="button" data-zoom="out" aria-label="${escapeAttr(copy.zoomOut || 'Zoom out')}" title="${escapeAttr(copy.zoomOut || 'Zoom out')}">−</button>
@@ -1069,24 +1065,7 @@ function renderImportantHarnesses(harnesses, copy) {
1069
1065
  }
1070
1066
 
1071
1067
  function renderSelectedPanel(harnesses, copy) {
1072
- const first = harnesses.find((item) => item.signals?.uses > 0) || harnesses[0];
1073
- if (!first) {
1074
- return `<section class="insight-card selected" id="selected-panel"><p class="eyebrow">${escapeHtml(copy.selected)}</p><h2>${escapeHtml(copy.noHarnessSelected)}</h2><p>${escapeHtml(copy.clickNode)}</p></section>`;
1075
- }
1076
- const plain = (copy.recPlain && copy.recPlain[first.recommendation]) || normalizeReason(first.reason, copy) || copy.clickNode;
1077
- const stateText = (copy.statePlain && copy.statePlain[first.lifecycle_state]) || renderCopyValue(first.lifecycle_state, copy);
1078
- return `
1079
- <section class="insight-card selected" id="selected-panel">
1080
- <p class="eyebrow">${escapeHtml(copy.selected)}</p>
1081
- <h2>${escapeHtml(first.id)}</h2>
1082
- <p>${escapeHtml(plain)}</p>
1083
- <div class="stat-chips">
1084
- <span class="stat-chip">${escapeHtml(copy.uses)} ${escapeHtml(first.signals?.uses || 0)}${escapeHtml(copy.timesSuffix || '')}</span>
1085
- <span class="stat-chip">${escapeHtml(copy.score)} ${escapeHtml(first.candidate_score?.total || 0)}</span>
1086
- <span class="stat-chip">${escapeHtml(stateText)}</span>
1087
- </div>
1088
- </section>
1089
- `;
1068
+ return `<section class="insight-card selected" id="selected-panel"><p class="eyebrow">${escapeHtml(copy.selected)}</p><h2>${escapeHtml(copy.noHarnessSelected)}</h2><p>${escapeHtml(copy.clickNode)}</p></section>`;
1090
1069
  }
1091
1070
 
1092
1071
  function renderHarness(item, copy) {
@@ -1629,10 +1608,6 @@ function renderScript(harnesses, copy) {
1629
1608
  item.setAttribute('aria-pressed', 'false');
1630
1609
  });
1631
1610
  if (alreadyActive) {
1632
- cards.forEach((card) => card.classList.remove('is-filtered-out'));
1633
- window.__tinkGraphState.filter = null;
1634
- if (window.__tinkGraph) window.__tinkGraph.setFilter(null);
1635
- setStatus(copy.showingAll);
1636
1611
  setFilterStatus(copy.showingAll);
1637
1612
  updateActionPanel(null, null);
1638
1613
  updateGroupDetail(null);
@@ -1640,11 +1615,7 @@ function renderScript(harnesses, copy) {
1640
1615
  }
1641
1616
  button.classList.add('active-filter');
1642
1617
  button.setAttribute('aria-pressed', 'true');
1643
- cards.forEach((card) => card.classList.toggle('is-filtered-out', card.dataset.recommendation !== value));
1644
- window.__tinkGraphState.filter = value;
1645
- if (window.__tinkGraph) window.__tinkGraph.setFilter(value);
1646
1618
  const label = recLabelByFilter[value] || value;
1647
- setStatus(copy.filteredTo + ': ' + label);
1648
1619
  setFilterStatus(copy.filteredTo + ': ' + label);
1649
1620
  updateActionPanel(value, null);
1650
1621
  updateGroupDetail(value);
@@ -1656,24 +1627,8 @@ function renderScript(harnesses, copy) {
1656
1627
  else window.__tinkGraph.zoom(button.dataset.zoom === 'in' ? 0.78 : 1.28);
1657
1628
  });
1658
1629
  });
1659
- document.querySelectorAll('[data-drag]').forEach((button) => {
1660
- button.addEventListener('click', () => {
1661
- const mode = button.dataset.drag;
1662
- document.querySelectorAll('[data-drag]').forEach((item) => {
1663
- const active = item.dataset.drag === mode;
1664
- item.classList.toggle('active', active);
1665
- item.setAttribute('aria-pressed', active ? 'true' : 'false');
1666
- });
1667
- window.__tinkGraphState.dragMode = mode;
1668
- if (window.__tinkGraph) window.__tinkGraph.setDragMode(mode);
1669
- updateGraphHint();
1670
- });
1671
- });
1672
1630
  const graphHint = document.getElementById('graph-hint');
1673
- function updateGraphHint() {
1674
- if (graphHint) graphHint.textContent = window.__tinkGraphState.dragMode === 'rotate' ? (copy.hintRotate || '') : (copy.hintPan || '');
1675
- }
1676
- updateGraphHint();
1631
+ if (graphHint) graphHint.textContent = copy.hintPan || '';
1677
1632
  const rail = document.querySelector('.right-rail');
1678
1633
  const railResizer = document.getElementById('rail-resizer');
1679
1634
  if (rail && railResizer) {
@@ -1812,19 +1767,15 @@ function renderGraph3DModule(copy) {
1812
1767
  controls.zoomSpeed = 1.1;
1813
1768
  controls.screenSpacePanning = true;
1814
1769
  controls.panSpeed = 1.1;
1815
- function applyDragMode(mode) {
1816
- const rotate = mode === 'rotate';
1817
- controls.mouseButtons = {
1818
- LEFT: rotate ? THREE.MOUSE.ROTATE : THREE.MOUSE.PAN,
1819
- MIDDLE: THREE.MOUSE.DOLLY,
1820
- RIGHT: rotate ? THREE.MOUSE.PAN : THREE.MOUSE.ROTATE
1821
- };
1822
- controls.touches = {
1823
- ONE: rotate ? THREE.TOUCH.ROTATE : THREE.TOUCH.PAN,
1824
- TWO: THREE.TOUCH.DOLLY_ROTATE
1825
- };
1826
- }
1827
- applyDragMode((window.__tinkGraphState && window.__tinkGraphState.dragMode) || 'pan');
1770
+ controls.mouseButtons = {
1771
+ LEFT: THREE.MOUSE.PAN,
1772
+ MIDDLE: THREE.MOUSE.DOLLY,
1773
+ RIGHT: THREE.MOUSE.ROTATE
1774
+ };
1775
+ controls.touches = {
1776
+ ONE: THREE.TOUCH.PAN,
1777
+ TWO: THREE.TOUCH.DOLLY_ROTATE
1778
+ };
1828
1779
  controls.autoRotate = false;
1829
1780
  controls.minDistance = 8;
1830
1781
  controls.maxDistance = 220;
@@ -2184,9 +2135,6 @@ function renderGraph3DModule(copy) {
2184
2135
  camera.position.copy(INITIAL_CAM);
2185
2136
  controls.target.copy(INITIAL_TARGET);
2186
2137
  controls.update();
2187
- },
2188
- setDragMode(mode) {
2189
- applyDragMode(mode);
2190
2138
  }
2191
2139
  };
2192
2140
  applyState();