claude-spotter 1.6.0 → 1.6.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,22 @@
|
|
|
3
3
|
各節はそのversion公開時点の変更記録であり、後続versionにより置換された仕様を含む。
|
|
4
4
|
現行runtime契約は[`docs/00_overview.md`](docs/00_overview.md)から辿る。
|
|
5
5
|
|
|
6
|
+
## 1.6.2 — 2026-08-29
|
|
7
|
+
|
|
8
|
+
- **Windowsの`spotter install -y`がMCP調査後に終了する。** 調査対象のprocess treeを
|
|
9
|
+
Windows共通経路で停止し、stdin / stdout / stderrのpipeを停止前後に破棄する。
|
|
10
|
+
カタログ生成後もstdin pipeがNodeのイベントループを保持し、工場セットアップが
|
|
11
|
+
完了しなかった問題を修正した。
|
|
12
|
+
- **隔離runtime error workerが指定期限内に呼び出し元へ戻る。** timeout時は結果を先に
|
|
13
|
+
確定し、子process treeのbest-effort掃除を並行して続ける。Windowsで掃除の待機時間が
|
|
14
|
+
絶対期限へ上乗せされていた問題を修正した。
|
|
15
|
+
- Cursor hookの安定Node path試験を、空白を含むWindows pathの正しい引用形式へ対応させた。
|
|
16
|
+
|
|
17
|
+
## 1.6.1 — 2026-08-24
|
|
18
|
+
|
|
19
|
+
- **Cursor hook が Homebrew Cellar の版付き Node を焼かない。** `spotter cursor-hook install` は
|
|
20
|
+
Codex hook と同じ安定 Node path を使い、版更新で sessionStart が消えるのを防ぐ。
|
|
21
|
+
|
|
6
22
|
## 1.6.0 — 2026-08-24
|
|
7
23
|
|
|
8
24
|
- **Cursor を tool-db host として足した。** `src/host/adapters.mjs` に
|
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@ import { homedir } from 'node:os';
|
|
|
4
4
|
import { dirname, join, resolve } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { spawnRefreshDetached } from '../hooks/spawn-daemon.mjs';
|
|
7
|
+
import { resolveCodexHookNodePath } from './codex-hook-cmd.mjs';
|
|
7
8
|
import {
|
|
8
9
|
die,
|
|
9
10
|
findSpotterMarker,
|
|
@@ -90,7 +91,7 @@ export function cursorCwd(input) {
|
|
|
90
91
|
|
|
91
92
|
export async function installCursorHooks({
|
|
92
93
|
cursorHome = defaultCursorHome(),
|
|
93
|
-
nodePath =
|
|
94
|
+
nodePath = resolveCodexHookNodePath(),
|
|
94
95
|
spotterBin = SPOTTER_BIN,
|
|
95
96
|
} = {}) {
|
|
96
97
|
const hooksPath = join(cursorHome, 'hooks.json');
|
|
@@ -270,10 +270,14 @@ function runRuntimeWorker(workerPath, args, timeoutMs, signal) {
|
|
|
270
270
|
signal?.removeEventListener('abort', abort);
|
|
271
271
|
resolve(result);
|
|
272
272
|
};
|
|
273
|
-
const stop = (kind) => {
|
|
273
|
+
const stop = (kind) => {
|
|
274
|
+
if (stopping || settled) return;
|
|
275
|
+
stopping = true;
|
|
276
|
+
finish({ kind });
|
|
277
|
+
void killWorkerTree(child);
|
|
278
|
+
};
|
|
274
279
|
const abort = () => stop('cancelled');
|
|
275
|
-
const
|
|
276
|
-
const timer = setTimeout(() => stop('timeout'), Math.max(1, timeoutMs - killGraceMs));
|
|
280
|
+
const timer = setTimeout(() => stop('timeout'), timeoutMs);
|
|
277
281
|
try {
|
|
278
282
|
child = spawn(process.execPath, [workerPath, ...args], {
|
|
279
283
|
stdio: 'ignore',
|
|
@@ -11,7 +11,11 @@
|
|
|
11
11
|
|
|
12
12
|
import { spawn } from 'node:child_process';
|
|
13
13
|
import { isWindowsAbsolutePath } from '../platform/paths.mjs';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
execFileWindowsSafe,
|
|
16
|
+
terminateProcessTree,
|
|
17
|
+
windowsCompatibleCommand,
|
|
18
|
+
} from '../platform/spawn.mjs';
|
|
15
19
|
import { listToolsHttp } from './investigate-mcp-http.mjs';
|
|
16
20
|
import { readMcpServers, describeServer } from './mcp-config.mjs';
|
|
17
21
|
import { version as SPOTTER_VERSION } from '../version.mjs';
|
|
@@ -253,6 +257,17 @@ export function buildStdioSpawn(command, args) {
|
|
|
253
257
|
return { cmd: invocation.command, cmdArgs: invocation.args };
|
|
254
258
|
}
|
|
255
259
|
|
|
260
|
+
export async function closeMcpTransport(child, { terminateChildFn = terminateProcessTree } = {}) {
|
|
261
|
+
const destroyStreams = () => {
|
|
262
|
+
for (const stream of [child.stdin, child.stdout, child.stderr]) {
|
|
263
|
+
try { stream.destroy(); } catch { /* ignore */ }
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
destroyStreams();
|
|
267
|
+
try { await terminateChildFn(child); } catch { /* direct kill fallback already ran */ }
|
|
268
|
+
destroyStreams();
|
|
269
|
+
}
|
|
270
|
+
|
|
256
271
|
async function spawnAndQuery({ command, args, env = {} }, serverName) {
|
|
257
272
|
return new Promise((resolve, reject) => {
|
|
258
273
|
const { cmd, cmdArgs } = buildStdioSpawn(command, args);
|
|
@@ -267,16 +282,14 @@ async function spawnAndQuery({ command, args, env = {} }, serverName) {
|
|
|
267
282
|
let settled = false;
|
|
268
283
|
let initializedSent = false;
|
|
269
284
|
|
|
270
|
-
const cleanup = () =>
|
|
271
|
-
try { child.stdin.end(); } catch { /* ignore */ }
|
|
272
|
-
try { child.kill(); } catch { /* ignore */ }
|
|
273
|
-
};
|
|
285
|
+
const cleanup = () => closeMcpTransport(child);
|
|
274
286
|
|
|
275
287
|
const timer = setTimeout(() => {
|
|
276
288
|
if (settled) return;
|
|
277
289
|
settled = true;
|
|
278
|
-
cleanup()
|
|
279
|
-
|
|
290
|
+
void cleanup().then(() => {
|
|
291
|
+
reject(new McpInvestigationError(`handshake/list timed out after ${HANDSHAKE_TIMEOUT_MS}ms`, serverName));
|
|
292
|
+
});
|
|
280
293
|
}, HANDSHAKE_TIMEOUT_MS);
|
|
281
294
|
|
|
282
295
|
const send = (msg) => {
|
|
@@ -347,13 +360,13 @@ async function spawnAndQuery({ command, args, env = {} }, serverName) {
|
|
|
347
360
|
if (settled) return;
|
|
348
361
|
settled = true;
|
|
349
362
|
clearTimeout(timer);
|
|
350
|
-
cleanup();
|
|
363
|
+
await cleanup();
|
|
351
364
|
resolve(tools);
|
|
352
365
|
} catch (err) {
|
|
353
366
|
if (settled) return;
|
|
354
367
|
settled = true;
|
|
355
368
|
clearTimeout(timer);
|
|
356
|
-
cleanup();
|
|
369
|
+
await cleanup();
|
|
357
370
|
reject(err);
|
|
358
371
|
}
|
|
359
372
|
})();
|