@raymondchins/agentmap 0.2.1 → 0.2.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/README.md CHANGED
@@ -339,7 +339,7 @@ $ node agentmap.mjs --print | jq '.hubs[0]'
339
339
  | `--help` / `-h` | Print a usage block listing every flag and exit 0. |
340
340
  | `--version` / `-v` | Print the version from `package.json` and exit 0. |
341
341
  | `--json` | **Global modifier.** When present, every command prints exactly one JSON object to stdout (no prose). Shapes vary per command: `--json --hubs` → `{command,fileCount,sha,hubs:[string]}`, `--json --find X` → `{command,query,matches:[{file,name,kind}]}`, `--json --relates X` → `{command,file,pagerank,exports,imports,dependents,related}`, `--json --any X` → `{command,query,kind,…payload}`, etc. Bare `--json` (no query flag) → `{command:"build",fileCount,features,topHub}`. |
342
- | `--install-hooks` | Copy `hooks/post-commit` into `.git/hooks/` (chmod 0755), ensure `.claude/agentmap.json` is in `.gitignore`, and print the Claude Code `settings.json` `PreToolUse` snippet. Exit 0 on success, stderr + exit 1 on failure. |
342
+ | `--install-hooks` | Copy `hooks/post-commit` into `.git/hooks/` (chmod 0755), ensure `.claude/agentmap.json` is in `.gitignore`, and auto-wire the Claude Code `PreToolUse(Grep)` nudge into `.claude/settings.json` (merge-safe + idempotent). Exit 0 on success, stderr + exit 1 on failure. |
343
343
  | `--mcp` | Start agentmap as a **stdio MCP server** so non-Claude-Code agents (Cursor, Cline, any MCP client) can call every flag as a first-class tool. |
344
344
 
345
345
  **Exit-code contract:** `0` = success / match / help / version; `1` = query returned zero results (`--any`, `--find`, `--relates`, `--feature` with no match); `2` = usage error (missing required arg, unknown flag). Any token starting with `-` that matches no known flag prints an error to stderr and exits 2.
@@ -365,8 +365,9 @@ npx @raymondchins/agentmap --install-hooks
365
365
  ```
366
366
 
367
367
  This copies `hooks/post-commit` into `.git/hooks/`, sets it executable, ensures
368
- `.claude/agentmap.json` is in `.gitignore`, and prints the `.claude/settings.json`
369
- snippet for the `PreToolUse` nudge hook (below). Manual alternative:
368
+ `.claude/agentmap.json` is in `.gitignore`, and **auto-wires the `PreToolUse` nudge
369
+ hook into `.claude/settings.json`** (merge-safe + idempotent) so map enforcement is
370
+ on by default — no manual paste. Manual alternative for just the post-commit hook:
370
371
 
371
372
  ```bash
372
373
  # from your repo root
@@ -385,7 +386,9 @@ reuse search, it injects a reminder steering the agent to `agentmap --any` first
385
386
  denies the grep, and stays silent for raw-string / Tailwind-class / lowercase-HTML-tag
386
387
  sweeps — so it's high-signal, not nagging.
387
388
 
388
- Wire it up in `.claude/settings.json`:
389
+ `--install-hooks` writes this into `.claude/settings.json` for you (merge-safe — it
390
+ preserves existing settings and won't duplicate on re-run). For reference, or to wire
391
+ it by hand:
389
392
 
390
393
  ```json
391
394
  {
package/agentmap.mjs CHANGED
@@ -13,11 +13,18 @@
13
13
  // Near-zero deps (ts-morph only). Runs in the target repo's cwd.
14
14
  // Algorithm credit: Aider's repo map (Apache-2.0) — github.com/Aider-AI/aider
15
15
  // ============================================================================
16
- import { Project, SyntaxKind } from "ts-morph";
17
- const CallExpression = SyntaxKind.CallExpression;
18
16
  import { writeFileSync, readFileSync, existsSync, mkdirSync, renameSync, readdirSync, statSync, chmodSync } from "node:fs";
19
17
  import { execSync, execFileSync } from "node:child_process";
20
18
  import { createHash } from "node:crypto";
19
+ import { createRequire } from "node:module";
20
+
21
+ // Lazy ts-morph: its ~105ms module init only fires on a COLD rebuild. Warm cache
22
+ // queries (the common case) never construct a Project, so they skip the load
23
+ // entirely (~2x faster warm). createRequire keeps it synchronous — no async to
24
+ // thread through build()/makeProject().
25
+ const _require = createRequire(import.meta.url);
26
+ let _tsm = null;
27
+ const tsMorph = () => (_tsm ??= _require("ts-morph"));
21
28
 
22
29
  const MAP = ".claude/agentmap.json";
23
30
  const SCHEMA_VERSION = 2;
@@ -177,6 +184,7 @@ function identMul(ident, defineCount, mentioned) {
177
184
  // else (missing / malformed / solution-style references that index 0 files) fall
178
185
  // back to broad source globs so the tool degrades gracefully instead of crashing.
179
186
  function makeProject() {
187
+ const { Project } = tsMorph();
180
188
  // skipFileDependencyResolution: ~40% faster build, verified identical edge
181
189
  // set (we resolve module specifiers explicitly below, never via the implicit
182
190
  // dependency graph). allowJs so .js/.jsx are parsed.
@@ -248,6 +256,8 @@ function makeProject() {
248
256
  function build() {
249
257
  const t0 = Date.now();
250
258
  const project = makeProject();
259
+ const { SyntaxKind } = tsMorph();
260
+ const CallExpression = SyntaxKind.CallExpression;
251
261
  const cwd = process.cwd().replace(/\\/g, "/");
252
262
  const rel = (p) => p.replace(cwd + "/", "");
253
263
  const files = {}, dependents = {}, features = {};
@@ -534,14 +544,13 @@ function fileBlock(key, f) {
534
544
 
535
545
  // ---------------------------------------------------------------------------
536
546
  // --install-hooks: copy the package post-commit hook into .git/hooks, ensure
537
- // .claude/agentmap.json is gitignored, and print the Claude Code PreToolUse
538
- // snippet (mirrors hooks/INSTALL.md). Throws on any failure so the caller can
539
- // stderr+exit 1. Resolves the package hooks/ dir relative to THIS script so it
540
- // works whether agentmap is run locally, via npx, or globally installed.
547
+ // .claude/agentmap.json is gitignored, and auto-wire the Claude Code
548
+ // PreToolUse(Grep) nudge into the project's .claude/settings.json so map
549
+ // enforcement is ON by default (no manual copy-paste). Merge-safe + idempotent.
550
+ // Throws on any failure so the caller can stderr+exit 1.
541
551
  // ---------------------------------------------------------------------------
542
552
  function installHooks() {
543
553
  const src = new URL("./hooks/post-commit", import.meta.url);
544
- const nudge = new URL("./hooks/agentmap-nudge.mjs", import.meta.url);
545
554
  // The package hooks/ dir must ship alongside agentmap.mjs.
546
555
  if (!existsSync(src)) throw new Error(`packaged hook not found at ${src.pathname} (is the hooks/ dir present?)`);
547
556
 
@@ -565,14 +574,36 @@ function installHooks() {
565
574
  writeFileSync(".gitignore", IGNORE_LINE + "\n");
566
575
  }
567
576
 
568
- // Success report + the ready-to-paste PreToolUse snippet (points node at the
569
- // installed nudge use its absolute path so it resolves from any cwd).
577
+ // Auto-wire the PreToolUse(Grep) enforcement nudge into the PROJECT settings
578
+ // (.claude/settings.json) so "the agent is forced to use the map" is ON by
579
+ // default — not a manual paste. Merge-safe + idempotent: preserves any
580
+ // existing settings/hooks, never duplicates our entry. Uses a project-relative
581
+ // command so a committed settings.json stays portable across machines.
582
+ const NUDGE_CMD = "node node_modules/@raymondchins/agentmap/hooks/agentmap-nudge.mjs";
583
+ const settingsPath = ".claude/settings.json";
584
+ let settings = {};
585
+ if (existsSync(settingsPath)) {
586
+ try { settings = JSON.parse(readFileSync(settingsPath, "utf8")) || {}; }
587
+ catch { throw new Error(`${settingsPath} is not valid JSON — fix or remove it, then re-run --install-hooks`); }
588
+ }
589
+ settings.hooks ??= {};
590
+ settings.hooks.PreToolUse ??= [];
591
+ const alreadyWired = settings.hooks.PreToolUse.some(
592
+ (e) => Array.isArray(e?.hooks) && e.hooks.some((h) => typeof h?.command === "string" && h.command.includes("agentmap-nudge")),
593
+ );
594
+ if (!alreadyWired) {
595
+ settings.hooks.PreToolUse.push({ matcher: "Grep", hooks: [{ type: "command", command: NUDGE_CMD }] });
596
+ mkdirSync(".claude", { recursive: true });
597
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
598
+ }
599
+
600
+ // Success report.
570
601
  console.log(`installed post-commit hook → ${dest}`);
571
602
  console.log(ignoredAlready ? `.gitignore already has ${IGNORE_LINE}` : `added ${IGNORE_LINE} to .gitignore`);
572
- console.log("\nAdd this to your .claude/settings.json to enable the PreToolUse(Grep) nudge:\n");
573
- console.log(JSON.stringify({
574
- hooks: { PreToolUse: [{ matcher: "Grep", hooks: [{ type: "command", command: `node ${nudge.pathname}` }] }] },
575
- }, null, 2));
603
+ console.log(alreadyWired
604
+ ? `${settingsPath} already wires the PreToolUse(Grep) → agentmap nudge — left as-is`
605
+ : `wired PreToolUse(Grep) agentmap nudge into ${settingsPath} (map enforcement on by default)`);
606
+ console.log("\nDone — the map auto-refreshes on commit, and greps are nudged to agentmap first.");
576
607
  }
577
608
 
578
609
  // ---------------------------------------------------------------------------
package/hooks/INSTALL.md CHANGED
@@ -121,8 +121,10 @@ agentmap --install-hooks
121
121
  ```
122
122
 
123
123
  This copies `hooks/post-commit` to `.git/hooks/post-commit`, chmods it, ensures
124
- `.claude/agentmap.json` is in `.gitignore`, and prints the Claude Code
125
- `settings.json` PreToolUse snippet all in one step.
124
+ `.claude/agentmap.json` is in `.gitignore`, and auto-wires the Claude Code
125
+ `PreToolUse(Grep)` nudge into `.claude/settings.json` (merge-safepreserves
126
+ existing settings, idempotent on re-run) — enforcement on by default, all in one
127
+ step. No manual paste needed.
126
128
 
127
129
  **Manual alternative:**
128
130
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raymondchins/agentmap",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },