claude-spotter 1.4.26 → 1.4.28

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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.4.28 — 2026-07-21
4
+
5
+ - **Windows Codex SessionStartの誤timeoutを修正。** detached refreshを起動するSpotter所有hookの
6
+ host側上限を5秒から30秒へ変更し、Windows nativeのNode起動・project discoveryが5秒を超えても
7
+ SessionStart失敗として切られないようにした。再installは旧5秒設定をcanonical 30秒へ正規化する。
8
+
9
+ ## 1.4.27 — 2026-07-21
10
+
11
+ - **Windows PowerShell 5.1向け診断JSONをASCII安全化。** `spotter diagnostics logs --json`は
12
+ 非ASCII文字をJSONのUnicode escapeとして出力する。履歴上のtool名に全角括弧などが含まれても、
13
+ Windows PowerShell 5.1のnative stdout誤復号でJSON構造が壊れず、`ConvertFrom-Json`で読める。
14
+
3
15
  ## 1.4.26 — 2026-07-20
4
16
 
5
17
  - **SessionEnd cleanupを冪等化。** daemonが未起動または既に停止済みの`E_UNREACHABLE`は
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-spotter",
3
- "version": "1.4.26",
3
+ "version": "1.4.28",
4
4
  "description": "Audit agent running alongside Claude Code that catches missed tool calls — 気づく役と実行する役の分離",
5
5
  "type": "module",
6
6
  "bin": {
@@ -39,6 +39,7 @@ const HERE = dirname(fileURLToPath(import.meta.url));
39
39
  const PACKAGE_ROOT = resolve(HERE, '..', '..');
40
40
  const SPOTTER_BIN = join(PACKAGE_ROOT, 'bin', 'spotter.mjs');
41
41
  const CODEX_HOOK_TIMEOUT_SEC = 60;
42
+ const CODEX_SESSION_START_TIMEOUT_SEC = 30;
42
43
  const DEFAULT_CODEX_HOOK_AUDITOR_TIMEOUT_MS = 20_000;
43
44
  const DEFAULT_CODEX_STOP_SHORT_FINAL_MAX_CHARS = 120;
44
45
  const CODEX_HOOK_FEATURE_NAMES = ['hooks', 'codex_hooks'];
@@ -623,6 +624,7 @@ function validateSpotterCodexHookEvent(settings, event) {
623
624
  const candidates = allEntries.filter((hook) => isSpotterCodexCommand(String(hook?.command ?? '')));
624
625
  const expectedCandidates = candidates.filter((hook) => isSpotterCodexCommand(String(hook.command ?? ''), event));
625
626
  const expected = expectedCandidates.filter((hook) => hook?.type === 'command');
627
+ const expectedTimeout = event === 'SessionStart' ? CODEX_SESSION_START_TIMEOUT_SEC : CODEX_HOOK_TIMEOUT_SEC;
626
628
  const issues = [];
627
629
  if (expectedCandidates.length === 0) issues.push('missing');
628
630
  if (expectedCandidates.length > 1) issues.push('duplicate');
@@ -632,6 +634,7 @@ function validateSpotterCodexHookEvent(settings, event) {
632
634
  if (hook.async === true) issues.push('async:true');
633
635
  if (!Object.hasOwn(hook, 'timeout')) issues.push('timeout:missing');
634
636
  else if (!Number.isFinite(hook.timeout) || hook.timeout <= 0) issues.push('timeout-invalid');
637
+ else if (hook.timeout !== expectedTimeout) issues.push(`timeout!=${expectedTimeout}`);
635
638
  if (Object.hasOwn(hook, 'timeoutSec')) issues.push('timeoutSec');
636
639
  if (hook.async === false) issues.push('async:false');
637
640
  if (hook.statusMessage === null) issues.push('statusMessage:null');
@@ -658,6 +661,8 @@ function isIncompatibleSpotterHookIssue(issue) {
658
661
  'type!=command',
659
662
  'async:true',
660
663
  'timeout-invalid',
664
+ 'timeout!=30',
665
+ 'timeout!=60',
661
666
  'timeoutSec',
662
667
  'commandWindows-invalid',
663
668
  ].includes(issue);
@@ -884,7 +889,7 @@ function mergeCodexHooks(current, { nodePath, spotterBin, platform = process.pla
884
889
  next.hooks = next.hooks ?? {};
885
890
  const prefix = platform === 'win32' ? '& ' : '';
886
891
  addCodexHook(next, 'SessionStart', `${prefix}${quoteArg(nodePath)} ${quoteArg(spotterBin)} codex-hook session-start`, {
887
- timeout: 5,
892
+ timeout: CODEX_SESSION_START_TIMEOUT_SEC,
888
893
  });
889
894
  addCodexHook(next, 'UserPromptSubmit', `${prefix}${quoteArg(nodePath)} ${quoteArg(spotterBin)} codex-hook user-prompt-submit`);
890
895
  addCodexHook(next, 'Stop', `${prefix}${quoteArg(nodePath)} ${quoteArg(spotterBin)} codex-hook stop`);
@@ -53,12 +53,18 @@ export async function runDiagnosticsLogsCommand({
53
53
  const runtimeErrors = await readRuntimeErrorStoreStatusFn();
54
54
  const merged = { ...summary, hookEvents, runtimeErrors };
55
55
  if (opts.json) {
56
- writeOutput(JSON.stringify(merged, null, 2) + '\n');
56
+ writeOutput(stringifyAsciiJson(merged) + '\n');
57
57
  return;
58
58
  }
59
59
  writeOutput(formatDaemonLogSummary(merged));
60
60
  }
61
61
 
62
+ function stringifyAsciiJson(value) {
63
+ return JSON.stringify(value, null, 2).replace(/[\u007f-\uffff]/g, (character) =>
64
+ `\\u${character.charCodeAt(0).toString(16).padStart(4, '0')}`
65
+ );
66
+ }
67
+
62
68
  export function formatDaemonLogSummary(summary) {
63
69
  const lines = [
64
70
  'spotter diagnostics logs',