claude-spotter 1.9.1 → 1.9.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/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  各節はそのversion公開時点の変更記録であり、後続versionにより置換された仕様を含む。
4
4
  現行runtime契約は[`docs/00_overview.md`](https://github.com/kitepon/Spotter/blob/main/docs/00_overview.md)から辿る。
5
5
 
6
+ ## 1.9.2 — 2026-10-06
7
+
8
+ - daemonが起動直後にsessionのcwdを離れ、`~/.spotter`へ移る。hostが`SessionEnd`を実行せずに終わると、
9
+ daemonはheartbeat timeout(最後のhook eventから30分)まで残る。Windowsではその間、daemonがcwdとして
10
+ 持つsessionの作業directoryを削除できなかった。heartbeatとhook、監査の動作は変えていない。
11
+
6
12
  ## 1.9.1 — 2026-10-03
7
13
 
8
14
  - runtime-error定期送信のlaunchd/systemd雛形を、NodeとCLI本体を絶対pathで起動する形へ修正。launchdの既定PATHにNodeが無く
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-spotter",
3
- "version": "1.9.1",
3
+ "version": "1.9.2",
4
4
  "description": "Audit agent running alongside Claude Code that catches missed tool calls — 気づく役と実行する役の分離",
5
5
  "type": "module",
6
6
  "bin": {
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { startDaemon, DaemonAlreadyRunningError } from '../daemon/daemon.mjs';
4
4
  import { homedir } from 'node:os';
5
- import { join } from 'node:path';
5
+ import { join, resolve } from 'node:path';
6
6
  import { open } from 'node:fs/promises';
7
7
  import { writeFileSync } from 'node:fs';
8
8
  import { observeRuntimeErrorIsolatedSafe } from '../core/runtime-error-store.mjs';
@@ -21,16 +21,33 @@ function parseArgs(argv) {
21
21
  return out;
22
22
  }
23
23
 
24
+ // The hook spawns the daemon detached, so it starts in the session's cwd. Windows
25
+ // refuses to delete a directory while any process has it as cwd, and after an
26
+ // unclean host exit the daemon lives on until the heartbeat timeout. The daemon
27
+ // passes an explicit cwd to every child and never reads its own, so it moves to
28
+ // Spotter's state directory. A failed move is logged and does not stop the daemon.
29
+ export function leaveSessionCwd({ target, chdir = process.chdir, log }) {
30
+ try {
31
+ chdir(target);
32
+ } catch (err) {
33
+ log(`cwd release failed (target=${target}): ${err.message}`);
34
+ return false;
35
+ }
36
+ return true;
37
+ }
38
+
24
39
  export async function runDaemonStart({ argv }) {
25
- const { sessionId, projectRoot } = parseArgs(argv);
40
+ const { sessionId, projectRoot: projectRootArg } = parseArgs(argv);
26
41
  if (!sessionId) {
27
42
  process.stderr.write('spotter daemon start: --session-id is required\n');
28
43
  process.exit(2);
29
44
  }
30
- if (!projectRoot) {
45
+ if (!projectRootArg) {
31
46
  process.stderr.write('spotter daemon start: --project-root is required (the path containing .spotter/marker.json)\n');
32
47
  process.exit(2);
33
48
  }
49
+ // Resolved before the cwd changes below, so a relative argument keeps its meaning.
50
+ const projectRoot = resolve(projectRootArg);
34
51
 
35
52
  const logFilePath = join(homedir(), '.spotter', 'logs', `daemon-${sessionId}.log`);
36
53
 
@@ -63,6 +80,8 @@ export async function runDaemonStart({ argv }) {
63
80
  logFile.write(line).catch(() => {});
64
81
  };
65
82
 
83
+ leaveSessionCwd({ target: join(homedir(), '.spotter'), log });
84
+
66
85
  let running;
67
86
  try {
68
87
  // v0.5.0: no warmup. Session-scoped Haiku (--resume on follow-ups) pays cold-start