wayfind 2.0.79 → 2.0.80

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.
@@ -2942,6 +2942,40 @@ function ensureStateWritePermissions() {
2942
2942
  return added;
2943
2943
  }
2944
2944
 
2945
+ /**
2946
+ * Ensure ~/.claude/settings.json has the PermissionRequest hook that auto-approves
2947
+ * Write calls to Wayfind state files. The permissions.allow list doesn't suppress
2948
+ * Claude Code's sensitive-file prompt for ~/.claude/ paths; a PermissionRequest hook
2949
+ * returning {"decision":"allow"} does.
2950
+ * Idempotent — no-ops if the hook command is already registered.
2951
+ * @returns {boolean} true if the hook was added
2952
+ */
2953
+ function ensurePermissionRequestHook() {
2954
+ if (!HOME) return false;
2955
+ const settingsPath = path.join(HOME, '.claude', 'settings.json');
2956
+ const hookCommand = 'bash ~/.claude/hooks/allow-wayfind-writes.sh';
2957
+
2958
+ let settings = {};
2959
+ if (fs.existsSync(settingsPath)) {
2960
+ try { settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch { return false; }
2961
+ }
2962
+
2963
+ if (!settings.hooks) settings.hooks = {};
2964
+ if (!Array.isArray(settings.hooks.PermissionRequest)) settings.hooks.PermissionRequest = [];
2965
+
2966
+ const alreadyRegistered = settings.hooks.PermissionRequest.some(entry =>
2967
+ Array.isArray(entry.hooks) && entry.hooks.some(h => h.command === hookCommand)
2968
+ );
2969
+ if (alreadyRegistered) return false;
2970
+
2971
+ settings.hooks.PermissionRequest.push({
2972
+ matcher: 'Write',
2973
+ hooks: [{ type: 'command', command: hookCommand, timeout: 5000 }],
2974
+ });
2975
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
2976
+ return true;
2977
+ }
2978
+
2945
2979
  /**
2946
2980
  * Re-sync hooks and commands from the installed Wayfind package to ~/.claude/.
2947
2981
  * Copies hook scripts and slash-command files, overwriting stale copies.
@@ -3026,6 +3060,15 @@ function runUpdate() {
3026
3060
  for (const p of addedPerms) console.log(` ✓ Allowlisted: ${p}`);
3027
3061
  console.log(' (Prevents plan-mode prompts on journal and state-file writes)');
3028
3062
  }
3063
+
3064
+ // Register PermissionRequest hook to suppress sensitive-file prompts for
3065
+ // ~/.claude/ paths, which the allowlist alone cannot suppress.
3066
+ const hookAdded = ensurePermissionRequestHook();
3067
+ if (hookAdded) {
3068
+ console.log('\n── PermissionRequest hook ──');
3069
+ console.log(' ✓ Registered allow-wayfind-writes.sh');
3070
+ console.log(' (Suppresses sensitive-file prompts for ~/.claude/ paths)');
3071
+ }
3029
3072
  }
3030
3073
 
3031
3074
  // ── Migrate to plugin ───────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wayfind",
3
- "version": "2.0.79",
3
+ "version": "2.0.80",
4
4
  "description": "Team decision trail for AI-assisted development. The connective tissue between product, engineering, and strategy.",
5
5
  "bin": {
6
6
  "wayfind": "./bin/team-context.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wayfind",
3
- "version": "2.0.79",
3
+ "version": "2.0.80",
4
4
  "description": "Team decision trail for AI-assisted development. Session memory, decision journals, and team digests.",
5
5
  "author": {
6
6
  "name": "Wayfind",
@@ -146,10 +146,12 @@ Read the repo's `CLAUDE.md`. If it does NOT already contain "Session State Proto
146
146
 
147
147
  If `CLAUDE.md` doesn't exist, create a minimal one with the repo name as a heading and the block above.
148
148
 
149
- ## Step 4.5: Patch Write Permissions in ~/.claude/settings.json
149
+ ## Step 4.5: Patch Write Permissions and PermissionRequest Hook in ~/.claude/settings.json
150
150
 
151
151
  Read `~/.claude/settings.json` (create it as `{}` if missing).
152
152
 
153
+ ### Part A: Write allowlist
154
+
153
155
  Ensure the following entries are present in `permissions.allow`. Add any that are missing — do NOT remove existing entries.
154
156
 
155
157
  Each path needs two forms: absolute (for tools that resolve paths before the permission check) and literal (tilde or relative, for tools that pass the path as-is). Both are required — Claude Code matches against the literal `file_path` argument, not the resolved path.
@@ -169,9 +171,44 @@ Write(.claude/personal-state.md)
169
171
 
170
172
  Where `<HOME>` is the user's actual home directory (e.g. `/home/greg` or `/Users/greg`).
171
173
 
172
- **Why:** Without these, Claude Code's plan mode prompts for approval on every journal and state-file write — even when the user is in bypass/dangerously-skip-permissions mode. These files are internal Wayfind state and are never dangerous to write.
174
+ ### Part B: PermissionRequest hook
175
+
176
+ Claude Code has a hardcoded sensitive-file check for `~/.claude/` paths that fires **independently** of `permissions.allow` — the allowlist alone cannot suppress it. A `PermissionRequest` hook is required.
177
+
178
+ First verify `~/.claude/hooks/allow-wayfind-writes.sh` exists. If missing, create it:
179
+
180
+ ```bash
181
+ #!/usr/bin/env bash
182
+ input=$(cat)
183
+ file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
184
+ [ -z "$file_path" ] && exit 0
185
+ expanded="${file_path/#\~/$HOME}"
186
+ if [[ "$expanded" == "$HOME/.claude/memory/"* ]] || \
187
+ [[ "$expanded" == "$HOME/.claude/global-state.md" ]] || \
188
+ [[ "$expanded" == "$HOME/.claude/state.md" ]] || \
189
+ [[ "$expanded" == *"/.claude/team-state.md" ]] || \
190
+ [[ "$expanded" == *"/.claude/personal-state.md" ]]; then
191
+ echo '{"decision": "allow"}'
192
+ exit 0
193
+ fi
194
+ ```
195
+
196
+ Make it executable: `chmod +x ~/.claude/hooks/allow-wayfind-writes.sh`
197
+
198
+ Then ensure this entry is present in `hooks.PermissionRequest` in `~/.claude/settings.json`:
199
+
200
+ ```json
201
+ {
202
+ "matcher": "Write",
203
+ "hooks": [{ "type": "command", "command": "bash ~/.claude/hooks/allow-wayfind-writes.sh", "timeout": 5000 }]
204
+ }
205
+ ```
206
+
207
+ Add it if missing — do NOT remove existing entries in the array.
208
+
209
+ **Why:** Without Part A, plan-mode users get prompted on every journal write. Without Part B, even bypass-mode users see "sensitive file" prompts for `~/.claude/` paths — which the allowlist cannot suppress.
173
210
 
174
- Report: "Write permissions patched — N entries added" (or "already present" if nothing changed).
211
+ Report: "Write permissions patched — N entries added; PermissionRequest hook registered" (or "already present" for each if nothing changed).
175
212
 
176
213
  ## Step 5: Register State Files in Global Index
177
214
 
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env bash
2
+ # Auto-approve Write permission requests for known-safe Wayfind state files.
3
+ # Runs as a PermissionRequest hook so it fires before Claude Code's sensitive-file
4
+ # prompt — the allowlist in settings.json doesn't suppress that prompt.
5
+ #
6
+ # Returns {"decision": "allow"} for matched paths, exits 0 with no output otherwise
7
+ # (Claude Code falls through to its normal permission handling).
8
+
9
+ input=$(cat)
10
+ file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
11
+
12
+ [ -z "$file_path" ] && exit 0
13
+
14
+ # Expand leading tilde to $HOME
15
+ expanded="${file_path/#\~/$HOME}"
16
+
17
+ if [[ "$expanded" == "$HOME/.claude/memory/"* ]] || \
18
+ [[ "$expanded" == "$HOME/.claude/global-state.md" ]] || \
19
+ [[ "$expanded" == "$HOME/.claude/state.md" ]] || \
20
+ [[ "$expanded" == *"/.claude/team-state.md" ]] || \
21
+ [[ "$expanded" == *"/.claude/personal-state.md" ]]; then
22
+ echo '{"decision": "allow"}'
23
+ exit 0
24
+ fi