claude-spotter 1.4.25 → 1.4.26

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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.4.26 — 2026-07-20
4
+
5
+ - **SessionEnd cleanupを冪等化。** daemonが未起動または既に停止済みの`E_UNREACHABLE`は
6
+ `already-stopped`として記録し、正常な終了状態をstderr warningへ誤分類しない。他のcleanup
7
+ failureは従来どおりwarningと構造eventを残す。
8
+ - **Windows native Codex hookをPowerShell実行可能に修正。** quoted Node commandの先頭へ
9
+ Windowsだけcall operator `&`を付ける。installerのownership判定は新旧両形式を認識し、
10
+ 再installで旧形式をcanonicalへ更新、uninstallでも除去できる。
11
+ - **Windows runtime error storeのACL処理を安定化。** 混雑したWindows runnerでも
12
+ PowerShellによるprivate ACL設定が誤ってtimeoutしないよう、上限を15秒へ拡張した。
13
+
3
14
  ## 1.4.25 — 2026-07-14
4
15
 
5
16
  - **Windows Codex CLI実行経路を修正。** `spotter install`、`spotter doctor`、Codex hook /
@@ -12,7 +23,9 @@
12
23
  POSIXと実体`.exe`の直接spawn、stdin prompt、非0終了時のfail-loud診断は維持する。
13
24
  - **検証。** 530 tests(528 pass / 2 platform skip)、68-file pack、FOX Windows nativeの
14
25
  tarball仮導入、install、warning 0のdoctor、Codex hooks / catalog、実Codex CLI auditor、
15
- codex-sidecar auditor diagnostics、dotagents `verify-install`を通過した。
26
+ codex-sidecar auditor diagnostics、dotagents `verify-install`を通過した。公開commit
27
+ `65bccf8`をnpm `latest`、`v1.4.25` tag、GitHub Releaseへ同期し、Mac、main-server、
28
+ FOX WSL2、FOX Windows nativeのregistry版global installとwarning 0のdoctorを確認した。
16
29
 
17
30
  ## 1.4.24 — 2026-07-14
18
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-spotter",
3
- "version": "1.4.25",
3
+ "version": "1.4.26",
4
4
  "description": "Audit agent running alongside Claude Code that catches missed tool calls — 気づく役と実行する役の分離",
5
5
  "type": "module",
6
6
  "bin": {
@@ -464,11 +464,11 @@ export async function runCodexHookDiagnosticsCommand({
464
464
  writeOutput(JSON.stringify(result, null, 2) + '\n');
465
465
  }
466
466
 
467
- export async function installCodexHooks({ codexHome = defaultCodexHome(), nodePath = resolveCodexHookNodePath(), spotterBin = SPOTTER_BIN } = {}) {
467
+ export async function installCodexHooks({ codexHome = defaultCodexHome(), nodePath = resolveCodexHookNodePath(), spotterBin = SPOTTER_BIN, platform = process.platform } = {}) {
468
468
  const hooksPath = join(codexHome, 'hooks.json');
469
469
  const configPath = join(codexHome, 'config.toml');
470
470
  const current = await loadJson(hooksPath);
471
- const next = mergeCodexHooks(current, { nodePath, spotterBin });
471
+ const next = mergeCodexHooks(current, { nodePath, spotterBin, platform });
472
472
  const hooksChanged = JSON.stringify(current) !== JSON.stringify(next);
473
473
  if (hooksChanged) {
474
474
  await mkdir(dirname(hooksPath), { recursive: true });
@@ -879,14 +879,15 @@ async function loadJson(path) {
879
879
  }
880
880
  }
881
881
 
882
- function mergeCodexHooks(current, { nodePath, spotterBin }) {
882
+ function mergeCodexHooks(current, { nodePath, spotterBin, platform = process.platform }) {
883
883
  const next = structuredClone(current ?? {});
884
884
  next.hooks = next.hooks ?? {};
885
- addCodexHook(next, 'SessionStart', `${quoteArg(nodePath)} ${quoteArg(spotterBin)} codex-hook session-start`, {
885
+ const prefix = platform === 'win32' ? '& ' : '';
886
+ addCodexHook(next, 'SessionStart', `${prefix}${quoteArg(nodePath)} ${quoteArg(spotterBin)} codex-hook session-start`, {
886
887
  timeout: 5,
887
888
  });
888
- addCodexHook(next, 'UserPromptSubmit', `${quoteArg(nodePath)} ${quoteArg(spotterBin)} codex-hook user-prompt-submit`);
889
- addCodexHook(next, 'Stop', `${quoteArg(nodePath)} ${quoteArg(spotterBin)} codex-hook stop`);
889
+ addCodexHook(next, 'UserPromptSubmit', `${prefix}${quoteArg(nodePath)} ${quoteArg(spotterBin)} codex-hook user-prompt-submit`);
890
+ addCodexHook(next, 'Stop', `${prefix}${quoteArg(nodePath)} ${quoteArg(spotterBin)} codex-hook stop`);
890
891
  return next;
891
892
  }
892
893
 
@@ -943,7 +944,7 @@ function isSpotterCodexHook(hook) {
943
944
  }
944
945
 
945
946
  function isSpotterCodexCommand(command, event = null) {
946
- const match = command.match(/^(?:"((?:\\.|[^"\\])*)"|(\S+))\s+(?:"((?:\\.|[^"\\])*)"|(\S+))\s+codex-hook\s+(session-start|user-prompt-submit|stop)\s*$/);
947
+ const match = command.match(/^(?:&\s+)?(?:"((?:\\.|[^"\\])*)"|(\S+))\s+(?:"((?:\\.|[^"\\])*)"|(\S+))\s+codex-hook\s+(session-start|user-prompt-submit|stop)\s*$/);
947
948
  if (!match) return false;
948
949
  const nodePath = unescapeQuotedCommandToken(match[1] ?? match[2]);
949
950
  const spotterPath = unescapeQuotedCommandToken(match[3] ?? match[4]);
@@ -635,7 +635,7 @@ async function runWindowsAcl(path, { directory }, options) {
635
635
  const executable = options.powerShellPath ?? 'powershell.exe';
636
636
  const script = buildWindowsAclPowerShell({ directory });
637
637
  await spawnForExit(executable, ['-NoProfile', '-NonInteractive', '-Command', script], {
638
- timeoutMs: options.aclTimeoutMs ?? 3_000,
638
+ timeoutMs: options.aclTimeoutMs ?? 15_000,
639
639
  env: { ...process.env, SPOTTER_ACL_PATH: path },
640
640
  });
641
641
  }
@@ -20,6 +20,7 @@ export async function runSessionEnd({
20
20
  readInput = readStdinJson,
21
21
  sendRequestFn = sendRequest,
22
22
  recordHookEventFn = recordClaudeHookEvent,
23
+ writeError = (text) => process.stderr.write(text),
23
24
  } = {}) {
24
25
  if (isChildCall()) return;
25
26
  const input = await readInput();
@@ -41,6 +42,13 @@ export async function runSessionEnd({
41
42
  event: { hook: 'SessionEnd', status: 'shutdown', durationMs: Date.now() - startedAt },
42
43
  });
43
44
  } catch (err) {
45
+ if (err?.code === 'E_UNREACHABLE') {
46
+ await recordHookEventFn({
47
+ projectRoot,
48
+ event: { hook: 'SessionEnd', status: 'already-stopped', durationMs: Date.now() - startedAt },
49
+ });
50
+ return;
51
+ }
44
52
  await recordHookEventFn({
45
53
  projectRoot,
46
54
  event: {
@@ -51,8 +59,7 @@ export async function runSessionEnd({
51
59
  },
52
60
  });
53
61
  // §14.1 exception — don't fail the Claude Code session just because cleanup failed.
54
- process.stderr.write(`spotter-hook: session-end shutdown warning: ${err.code ?? '?'}: ${err.message}\n`);
55
- process.exit(0);
62
+ writeError(`spotter-hook: session-end shutdown warning: ${err.code ?? '?'}: ${err.message}\n`);
56
63
  }
57
64
  }
58
65