wayfind 2.0.78 → 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.
@@ -2908,12 +2908,21 @@ function ensureStateWritePermissions() {
2908
2908
  if (!HOME) return [];
2909
2909
  const settingsPath = path.join(HOME, '.claude', 'settings.json');
2910
2910
 
2911
+ // Each path is listed twice: once as absolute (for tools that resolve paths)
2912
+ // and once as the literal form Claude Code may pass (tilde or relative).
2913
+ // Permission matching is against the literal file_path argument, not the
2914
+ // resolved path, so both forms are needed.
2911
2915
  const required = [
2912
2916
  `Write(${HOME}/.claude/memory/**)`,
2917
+ `Write(~/.claude/memory/**)`,
2913
2918
  `Write(${HOME}/.claude/global-state.md)`,
2919
+ `Write(~/.claude/global-state.md)`,
2914
2920
  `Write(${HOME}/.claude/state.md)`,
2921
+ `Write(~/.claude/state.md)`,
2915
2922
  `Write(${HOME}/**/.claude/team-state.md)`,
2923
+ `Write(.claude/team-state.md)`,
2916
2924
  `Write(${HOME}/**/.claude/personal-state.md)`,
2925
+ `Write(.claude/personal-state.md)`,
2917
2926
  ];
2918
2927
 
2919
2928
  let settings = {};
@@ -2933,6 +2942,40 @@ function ensureStateWritePermissions() {
2933
2942
  return added;
2934
2943
  }
2935
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
+
2936
2979
  /**
2937
2980
  * Re-sync hooks and commands from the installed Wayfind package to ~/.claude/.
2938
2981
  * Copies hook scripts and slash-command files, overwriting stale copies.
@@ -3017,6 +3060,15 @@ function runUpdate() {
3017
3060
  for (const p of addedPerms) console.log(` ✓ Allowlisted: ${p}`);
3018
3061
  console.log(' (Prevents plan-mode prompts on journal and state-file writes)');
3019
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
+ }
3020
3072
  }
3021
3073
 
3022
3074
  // ── Migrate to plugin ───────────────────────────────────────────────────────
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wayfind",
3
- "version": "2.0.78",
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.78",
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,25 +146,69 @@ 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
- Ensure the following entries are present in `permissions.allow`. Add any that are missing — do NOT remove existing entries:
153
+ ### Part A: Write allowlist
154
+
155
+ Ensure the following entries are present in `permissions.allow`. Add any that are missing — do NOT remove existing entries.
156
+
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.
154
158
 
155
159
  ```
156
160
  Write(<HOME>/.claude/memory/**)
161
+ Write(~/.claude/memory/**)
157
162
  Write(<HOME>/.claude/global-state.md)
163
+ Write(~/.claude/global-state.md)
158
164
  Write(<HOME>/.claude/state.md)
165
+ Write(~/.claude/state.md)
159
166
  Write(<HOME>/**/.claude/team-state.md)
167
+ Write(.claude/team-state.md)
160
168
  Write(<HOME>/**/.claude/personal-state.md)
169
+ Write(.claude/personal-state.md)
161
170
  ```
162
171
 
163
172
  Where `<HOME>` is the user's actual home directory (e.g. `/home/greg` or `/Users/greg`).
164
173
 
165
- **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.
166
210
 
167
- 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).
168
212
 
169
213
  ## Step 5: Register State Files in Global Index
170
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