@searls/turbocommit 0.13.1 → 0.13.2

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/lib/doctor.js CHANGED
@@ -53,7 +53,10 @@ function doctorLegacy (settingsPath, cwd) {
53
53
  const missing = Object.keys(HOOK_DEFS).filter(event =>
54
54
  !hasTurbocommit((settings.hooks && settings.hooks[event]) || [])
55
55
  )
56
- checks.push({ name: 'Hooks installed', status: 'error', message: `Missing hooks: ${missing.join(', ')}. Run: turbocommit uninstall && turbocommit install` })
56
+ const message = missing.length > 0
57
+ ? `Missing hooks: ${missing.join(', ')}. Run: turbocommit uninstall && turbocommit install`
58
+ : 'Outdated hooks (missing the --harness flag); Claude sessions may be misparsed. Run: turbocommit install'
59
+ checks.push({ name: 'Hooks installed', status: 'error', message })
57
60
  return { ok: false, checks }
58
61
  }
59
62
  checks.push({ name: 'Hooks installed', status: 'ok', message: `All ${Object.keys(HOOK_DEFS).length} hooks installed` })
package/lib/harness.js CHANGED
@@ -48,8 +48,14 @@ function selectedHarnesses (harness, { create = false } = {}) {
48
48
  }
49
49
 
50
50
  function inferHarness (hookInput, forcedHarness) {
51
+ // The installed hooks pass an explicit --harness flag, which is the source of
52
+ // truth. Inference is only a fallback for legacy flagless installs.
53
+ //
54
+ // We deliberately do NOT sniff `hook_event_name`: current Claude Code hook
55
+ // payloads include it too, so treating its presence as a Codex signal
56
+ // misroutes every Claude session into the Codex transcript parser (which
57
+ // yields zero pairs and a "(no transcript)" commit body). Default to Claude.
51
58
  if (forcedHarness) return forcedHarness
52
- if (hookInput && hookInput.hook_event_name) return 'codex'
53
59
  return 'claude'
54
60
  }
55
61
 
package/lib/install.js CHANGED
@@ -8,34 +8,34 @@ const { selectedHarnesses, claudeHome, codexHome } = require('./harness')
8
8
  const HOOK_DEFS = {
9
9
  PreToolUse: {
10
10
  matcher: 'Write|Edit|MultiEdit|NotebookEdit|Bash|mcp__.*',
11
- hooks: [{ type: 'command', command: 'turbocommit hook pre-tool-use' }]
11
+ hooks: [{ type: 'command', command: 'turbocommit hook pre-tool-use --harness claude' }]
12
12
  },
13
13
  SessionStart: {
14
- hooks: [{ type: 'command', command: 'turbocommit hook session-start' }]
14
+ hooks: [{ type: 'command', command: 'turbocommit hook session-start --harness claude' }]
15
15
  },
16
16
  SessionEnd: {
17
- hooks: [{ type: 'command', command: 'turbocommit hook session-end' }]
17
+ hooks: [{ type: 'command', command: 'turbocommit hook session-end --harness claude' }]
18
18
  },
19
19
  Stop: {
20
- hooks: [{ type: 'command', command: 'turbocommit hook stop' }]
20
+ hooks: [{ type: 'command', command: 'turbocommit hook stop --harness claude' }]
21
21
  }
22
22
  }
23
23
 
24
24
  const CODEX_HOOK_DEFS = {
25
25
  PreToolUse: {
26
26
  matcher: 'Write|Edit|MultiEdit|NotebookEdit|Bash|mcp__.*',
27
- hooks: [{ type: 'command', command: 'turbocommit hook pre-tool-use' }]
27
+ hooks: [{ type: 'command', command: 'turbocommit hook pre-tool-use --harness codex' }]
28
28
  },
29
29
  SessionStart: {
30
30
  matcher: 'resume|clear',
31
- hooks: [{ type: 'command', command: 'turbocommit hook session-start' }]
31
+ hooks: [{ type: 'command', command: 'turbocommit hook session-start --harness codex' }]
32
32
  },
33
33
  PreCompact: {
34
34
  matcher: 'manual|auto',
35
- hooks: [{ type: 'command', command: 'turbocommit hook pre-compact' }]
35
+ hooks: [{ type: 'command', command: 'turbocommit hook pre-compact --harness codex' }]
36
36
  },
37
37
  Stop: {
38
- hooks: [{ type: 'command', command: 'turbocommit hook stop' }]
38
+ hooks: [{ type: 'command', command: 'turbocommit hook stop --harness codex' }]
39
39
  }
40
40
  }
41
41
 
@@ -55,20 +55,37 @@ function hasTurbocommit (groups) {
55
55
  })
56
56
  }
57
57
 
58
+ /**
59
+ * Check whether the exact expected command is already installed for an event.
60
+ * Requiring an exact match (not just any turbocommit hook) means legacy
61
+ * flagless installs are treated as out-of-date and get rewritten with the
62
+ * explicit --harness flag on the next install.
63
+ */
64
+ function hasExactHooks (groups, def) {
65
+ if (!Array.isArray(groups)) return false
66
+ const expected = def.hooks.map(h => h.command)
67
+ return expected.every(cmd =>
68
+ groups.some(g => {
69
+ const hooks = g && g.hooks ? g.hooks : []
70
+ return hooks.some(h => h.command === cmd)
71
+ })
72
+ )
73
+ }
74
+
58
75
  /**
59
76
  * Check if turbocommit hooks are installed across all expected events.
60
77
  */
61
78
  function isFullyInstalled (settings) {
62
79
  if (!settings || !settings.hooks) return false
63
- return Object.keys(HOOK_DEFS).every(event =>
64
- hasTurbocommit(settings.hooks[event])
80
+ return Object.entries(HOOK_DEFS).every(([event, def]) =>
81
+ hasExactHooks(settings.hooks[event], def)
65
82
  )
66
83
  }
67
84
 
68
85
  function isCodexFullyInstalled (hooksConfig) {
69
86
  if (!hooksConfig || !hooksConfig.hooks) return false
70
- return Object.keys(CODEX_HOOK_DEFS).every(event =>
71
- hasTurbocommit(hooksConfig.hooks[event])
87
+ return Object.entries(CODEX_HOOK_DEFS).every(([event, def]) =>
88
+ hasExactHooks(hooksConfig.hooks[event], def)
72
89
  )
73
90
  }
74
91
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@searls/turbocommit",
3
- "version": "0.13.1",
3
+ "version": "0.13.2",
4
4
  "description": "Auto-commit after every AI coding agent turn",
5
5
  "bin": {
6
6
  "turbocommit": "./cli.js"