@coworker-jp/aidr 0.1.293 → 0.1.294

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coworker-jp/aidr",
3
- "version": "0.1.293",
3
+ "version": "0.1.294",
4
4
  "description": "AIDR setup CLI - installs ai-scanner hooks for 19+ AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,11 +13,15 @@ const SCRIPT_FILES = [
13
13
  "scan_webfetch.sh", "scan_websearch.sh",
14
14
  "log_web_urls.sh",
15
15
  ];
16
+ // bin ディレクトリ直下に生まれる、バイナリ以外の生成物。
16
17
  // `.ai-scanner-unscanned` は hook が「無検査でツールコールが通った」ことを
17
- // 記録するファイル (#1774)。**消す対象に入れておくこと** —— 残ると bin
18
- // ディレクトリが空にならず `rmdirIfEmpty` が効かないので、アンインストール後に
19
- // ディレクトリと記録が居座る。7 エージェントすべて同じ表を持つ。
20
- const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned"];
18
+ // 記録するファイル (#1774)、`.ai-scanner-last-pull` は自己更新の間引きスタンプ
19
+ // (#1795。エージェントごとに 1 個で、以前は `~/.claude/` に 1 個だけだった)。
20
+ // **どちらも消す対象に入れておくこと** —— 残ると bin ディレクトリが空にならず
21
+ // `rmdirIfEmpty` が効かないので、アンインストール後にディレクトリと記録が居座る。
22
+ // 7 エージェントすべて同じ表を持ち、`tests/bin-dir-artifacts.test.mjs` が
23
+ // 「表 ⇔ テンプレートが実際に書く名前」を両方向で照合する。
24
+ const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned", ".ai-scanner-last-pull"];
21
25
 
22
26
  export const meta = {
23
27
  name: "claude",
@@ -27,11 +27,15 @@ const SCRIPT_FILES = [
27
27
  "pre_shell.sh",
28
28
  "post_shell.sh",
29
29
  ];
30
+ // bin ディレクトリ直下に生まれる、バイナリ以外の生成物。
30
31
  // `.ai-scanner-unscanned` は hook が「無検査でツールコールが通った」ことを
31
- // 記録するファイル (#1774)。**消す対象に入れておくこと** —— 残ると bin
32
- // ディレクトリが空にならず `rmdirIfEmpty` が効かないので、アンインストール後に
33
- // ディレクトリと記録が居座る。7 エージェントすべて同じ表を持つ。
34
- const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned"];
32
+ // 記録するファイル (#1774)、`.ai-scanner-last-pull` は自己更新の間引きスタンプ
33
+ // (#1795。エージェントごとに 1 個で、以前は `~/.claude/` に 1 個だけだった)。
34
+ // **どちらも消す対象に入れておくこと** —— 残ると bin ディレクトリが空にならず
35
+ // `rmdirIfEmpty` が効かないので、アンインストール後にディレクトリと記録が居座る。
36
+ // 7 エージェントすべて同じ表を持ち、`tests/bin-dir-artifacts.test.mjs` が
37
+ // 「表 ⇔ テンプレートが実際に書く名前」を両方向で照合する。
38
+ const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned", ".ai-scanner-last-pull"];
35
39
  const ROOT_FILES = ["AGENTS.md"];
36
40
 
37
41
  export const meta = {
@@ -28,11 +28,15 @@ const SCRIPT_FILES = [
28
28
  "post_read.sh",
29
29
  "post_write.sh",
30
30
  ];
31
+ // bin ディレクトリ直下に生まれる、バイナリ以外の生成物。
31
32
  // `.ai-scanner-unscanned` は hook が「無検査でツールコールが通った」ことを
32
- // 記録するファイル (#1774)。**消す対象に入れておくこと** —— 残ると bin
33
- // ディレクトリが空にならず `rmdirIfEmpty` が効かないので、アンインストール後に
34
- // ディレクトリと記録が居座る。7 エージェントすべて同じ表を持つ。
35
- const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned"];
33
+ // 記録するファイル (#1774)、`.ai-scanner-last-pull` は自己更新の間引きスタンプ
34
+ // (#1795。エージェントごとに 1 個で、以前は `~/.claude/` に 1 個だけだった)。
35
+ // **どちらも消す対象に入れておくこと** —— 残ると bin ディレクトリが空にならず
36
+ // `rmdirIfEmpty` が効かないので、アンインストール後にディレクトリと記録が居座る。
37
+ // 7 エージェントすべて同じ表を持ち、`tests/bin-dir-artifacts.test.mjs` が
38
+ // 「表 ⇔ テンプレートが実際に書く名前」を両方向で照合する。
39
+ const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned", ".ai-scanner-last-pull"];
36
40
 
37
41
  export const meta = {
38
42
  name: "cursor",
@@ -5,11 +5,15 @@ import * as T from "../templates.mjs";
5
5
  import { buildGeminiSettings, mergeGeminiSettings, unmergeGeminiSettings } from "../merge.mjs";
6
6
 
7
7
  const HOOK_FILES = ["aidr-pre.sh"];
8
+ // bin ディレクトリ直下に生まれる、バイナリ以外の生成物。
8
9
  // `.ai-scanner-unscanned` は hook が「無検査でツールコールが通った」ことを
9
- // 記録するファイル (#1774)。**消す対象に入れておくこと** —— 残ると bin
10
- // ディレクトリが空にならず `rmdirIfEmpty` が効かないので、アンインストール後に
11
- // ディレクトリと記録が居座る。7 エージェントすべて同じ表を持つ。
12
- const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned"];
10
+ // 記録するファイル (#1774)、`.ai-scanner-last-pull` は自己更新の間引きスタンプ
11
+ // (#1795。エージェントごとに 1 個で、以前は `~/.claude/` に 1 個だけだった)。
12
+ // **どちらも消す対象に入れておくこと** —— 残ると bin ディレクトリが空にならず
13
+ // `rmdirIfEmpty` が効かないので、アンインストール後にディレクトリと記録が居座る。
14
+ // 7 エージェントすべて同じ表を持ち、`tests/bin-dir-artifacts.test.mjs` が
15
+ // 「表 ⇔ テンプレートが実際に書く名前」を両方向で照合する。
16
+ const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned", ".ai-scanner-last-pull"];
13
17
 
14
18
  export const meta = {
15
19
  name: "gemini",
@@ -18,11 +18,15 @@ const SCRIPT_FILES = [
18
18
  "post_read.sh",
19
19
  "post_write.sh",
20
20
  ];
21
+ // bin ディレクトリ直下に生まれる、バイナリ以外の生成物。
21
22
  // `.ai-scanner-unscanned` は hook が「無検査でツールコールが通った」ことを
22
- // 記録するファイル (#1774)。**消す対象に入れておくこと** —— 残ると bin
23
- // ディレクトリが空にならず `rmdirIfEmpty` が効かないので、アンインストール後に
24
- // ディレクトリと記録が居座る。7 エージェントすべて同じ表を持つ。
25
- const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned"];
23
+ // 記録するファイル (#1774)、`.ai-scanner-last-pull` は自己更新の間引きスタンプ
24
+ // (#1795。エージェントごとに 1 個で、以前は `~/.claude/` に 1 個だけだった)。
25
+ // **どちらも消す対象に入れておくこと** —— 残ると bin ディレクトリが空にならず
26
+ // `rmdirIfEmpty` が効かないので、アンインストール後にディレクトリと記録が居座る。
27
+ // 7 エージェントすべて同じ表を持ち、`tests/bin-dir-artifacts.test.mjs` が
28
+ // 「表 ⇔ テンプレートが実際に書く名前」を両方向で照合する。
29
+ const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned", ".ai-scanner-last-pull"];
26
30
 
27
31
  export const meta = {
28
32
  name: "kiro",
@@ -2,11 +2,15 @@ import path from "node:path";
2
2
  import fsp from "node:fs/promises";
3
3
  import { pathExists, rmdirIfEmpty } from "../fs-utils.mjs";
4
4
 
5
+ // bin ディレクトリ直下に生まれる、バイナリ以外の生成物。
5
6
  // `.ai-scanner-unscanned` は hook が「無検査でツールコールが通った」ことを
6
- // 記録するファイル (#1774)。**消す対象に入れておくこと** —— 残ると bin
7
- // ディレクトリが空にならず `rmdirIfEmpty` が効かないので、アンインストール後に
8
- // ディレクトリと記録が居座る。7 エージェントすべて同じ表を持つ。
9
- const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned"];
7
+ // 記録するファイル (#1774)、`.ai-scanner-last-pull` は自己更新の間引きスタンプ
8
+ // (#1795。エージェントごとに 1 個で、以前は `~/.claude/` に 1 個だけだった)。
9
+ // **どちらも消す対象に入れておくこと** —— 残ると bin ディレクトリが空にならず
10
+ // `rmdirIfEmpty` が効かないので、アンインストール後にディレクトリと記録が居座る。
11
+ // 7 エージェントすべて同じ表を持ち、`tests/bin-dir-artifacts.test.mjs` が
12
+ // 「表 ⇔ テンプレートが実際に書く名前」を両方向で照合する。
13
+ const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned", ".ai-scanner-last-pull"];
10
14
 
11
15
  export const meta = {
12
16
  name: "standalone",
@@ -25,11 +25,15 @@ const SCRIPT_FILES = [
25
25
  "post_read.sh",
26
26
  "post_write.sh",
27
27
  ];
28
+ // bin ディレクトリ直下に生まれる、バイナリ以外の生成物。
28
29
  // `.ai-scanner-unscanned` は hook が「無検査でツールコールが通った」ことを
29
- // 記録するファイル (#1774)。**消す対象に入れておくこと** —— 残ると bin
30
- // ディレクトリが空にならず `rmdirIfEmpty` が効かないので、アンインストール後に
31
- // ディレクトリと記録が居座る。7 エージェントすべて同じ表を持つ。
32
- const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned"];
30
+ // 記録するファイル (#1774)、`.ai-scanner-last-pull` は自己更新の間引きスタンプ
31
+ // (#1795。エージェントごとに 1 個で、以前は `~/.claude/` に 1 個だけだった)。
32
+ // **どちらも消す対象に入れておくこと** —— 残ると bin ディレクトリが空にならず
33
+ // `rmdirIfEmpty` が効かないので、アンインストール後にディレクトリと記録が居座る。
34
+ // 7 エージェントすべて同じ表を持ち、`tests/bin-dir-artifacts.test.mjs` が
35
+ // 「表 ⇔ テンプレートが実際に書く名前」を両方向で照合する。
36
+ const BIN_FILES = ["ai-scanner", "opengrep", ".ai-scanner-unscanned", ".ai-scanner-last-pull"];
33
37
 
34
38
  export const meta = {
35
39
  name: "windsurf",
package/src/cli.mjs CHANGED
@@ -624,7 +624,16 @@ export async function readUnscannedRecord(binDir) {
624
624
  }
625
625
  const parts = raw.split(/\r?\n/)[0].trim().split(/\s+/);
626
626
  if (parts.length < 3) return null;
627
- const [first, last, count] = parts.map((n) => (/^\d+$/.test(n) ? Number(n) : null));
627
+ // 10 進の非負整数だけを受け、**`Number` が正確に持てる範囲を超えたら壊れている
628
+ // ものとして扱う**。超えた値をそのまま返すと `9007199254740993` が
629
+ // `9007199254740992` として表示され、しかも誰も気付けない。Rust 側
630
+ // (`docker/scanner/src/agent_hooks.rs::parse_unscanned_record`) が同じ上限を
631
+ // 持ち、`tests/fixtures/unscanned-record-cases.json` が両者の一致を固定する。
632
+ const [first, last, count] = parts.map((n) => {
633
+ if (!/^\d+$/.test(n)) return null;
634
+ const v = Number(n);
635
+ return Number.isSafeInteger(v) ? v : null;
636
+ });
628
637
  if (first === null || last === null || count === null || count === 0) return null;
629
638
  return { first: new Date(first * 1000), last: new Date(last * 1000), count };
630
639
  }
package/src/templates.mjs CHANGED
@@ -32,11 +32,26 @@ export function getStartScannerSh(downloadBase = "https://pytd2jd5p7.execute-api
32
32
  # - Fail-open: never block Claude Code startup
33
33
  BIN="\${AI_SCANNER_BIN:-$HOME/.claude/bin/ai-scanner}"
34
34
  BIN_DIR="$(dirname "$BIN")"
35
- PULL_STAMP="$HOME/.claude/.ai-scanner-last-pull"
35
+ # The self-update throttle belongs to the binary it throttles, so it is derived
36
+ # from \$BIN — the one source this script already trusts for "where is my copy"
37
+ # (\`.ai-scanner-unscanned\` is placed the same way). It used to be pinned to
38
+ # \`\$HOME/.claude/\`, which made ONE stamp for ALL agents: every agent installs
39
+ # its own copy under \`\$HOME/.<agent>/bin/\`, so a Claude Code session starting
40
+ # suppressed the update check of the Cursor copy for PULL_INTERVAL seconds and
41
+ # vice versa (#1795). docs/scanner/SCANNER.md already documented it as per-agent.
42
+ PULL_STAMP="$BIN_DIR/.ai-scanner-last-pull"
36
43
  PULL_INTERVAL=300
37
44
  DOWNLOAD_BASE="${downloadBase}"
38
45
 
39
- mkdir -p "$BIN_DIR" "$HOME/.claude/quarantine" "$HOME/.claude/ai-scanner"
46
+ # Only the directory this script itself writes into (the download lands here).
47
+ # The scanner's own state directories are created by the binary at startup
48
+ # (\`main()\` -> \`paths::process_paths().create_dirs()\`, docker/scanner/src/paths.rs),
49
+ # which is the single source of truth for that layout and honours
50
+ # AI_SCANNER_DATA_DIR / AI_SCANNER_QUARANTINE_DIR. Creating them here as well
51
+ # was a second, hardcoded copy of that layout that ignored both overrides, and
52
+ # on a machine where the binary never arrives it left empty \`~/.claude/\`
53
+ # directories behind for agents that are not Claude Code (#1795).
54
+ mkdir -p "$BIN_DIR"
40
55
 
41
56
  # macOS has no base \`timeout\` (it's in GNU coreutils). Shim it so hooks work
42
57
  # on fresh Macs without brew install coreutils.