feat: file-read gate allows Edit, add legacy-peer-deps for grammar install
- Change file-read gate from deny to allow with limit:1, injecting the observation timeline as additionalContext. Edit now works on gated files since the file registers as "read" with near-zero token cost. - Add updatedInput to HookResult type for PreToolUse hooks. - Add .npmrc with legacy-peer-deps=true for tree-sitter peer dep conflicts. - Add --legacy-peer-deps to npm fallback paths in smart-install.js so end users without bun can install the 24 grammar packages. - Rebuild plugin artifacts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -138,11 +138,11 @@ function formatFileTimeline(observations: ObservationRow[], filePath: string): s
|
||||
|
||||
const lines: string[] = [
|
||||
`Current: ${currentDate} ${currentTime} ${currentTimezone}`,
|
||||
`Read blocked: This file has prior observations. Choose the cheapest path:`,
|
||||
`This file has prior observations. Only line 1 was read to save tokens.`,
|
||||
`- **Already know enough?** The timeline below may be all you need (semantic priming).`,
|
||||
`- **Need details?** get_observations([IDs]) — ~300 tokens each.`,
|
||||
`- **Need current code?** smart_outline("${safePath}") for structure (~1-2k tokens), smart_unfold("${safePath}", "<symbol>") for a specific function (~400-2k tokens).`,
|
||||
`- **Need to edit?** Use smart tools for line numbers, then sed via Bash (Edit requires Read, but you already have the context).`,
|
||||
`- **Need full file?** Read again with offset/limit for the section you need.`,
|
||||
`- **Need to edit?** Edit works — the file is registered as read. Use smart_outline("${safePath}") for line numbers.`,
|
||||
];
|
||||
|
||||
for (const [day, dayObservations] of sortedDays) {
|
||||
@@ -233,15 +233,19 @@ export const fileContextHandler: EventHandler = {
|
||||
return { continue: true, suppressOutput: true };
|
||||
}
|
||||
|
||||
// Deny the read with the timeline as the reason — Claude sees the timeline
|
||||
// and decides: work from semantic priming, use get_observations(), or ask user to allow read
|
||||
// Allow the read with limit: 1 line — just enough for Edit's "file must be read"
|
||||
// check to pass, while keeping token cost near zero. The observation timeline
|
||||
// gives Claude full context about prior work on this file.
|
||||
const timeline = formatFileTimeline(dedupedObservations, filePath);
|
||||
return {
|
||||
hookSpecificOutput: {
|
||||
hookEventName: 'PreToolUse',
|
||||
additionalContext: '',
|
||||
permissionDecision: 'deny',
|
||||
permissionDecisionReason: timeline,
|
||||
additionalContext: timeline,
|
||||
permissionDecision: 'allow',
|
||||
updatedInput: {
|
||||
file_path: filePath,
|
||||
limit: 1,
|
||||
},
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
|
||||
@@ -22,6 +22,7 @@ export interface HookResult {
|
||||
additionalContext: string;
|
||||
permissionDecision?: 'allow' | 'deny';
|
||||
permissionDecisionReason?: string;
|
||||
updatedInput?: Record<string, unknown>;
|
||||
};
|
||||
systemMessage?: string;
|
||||
exitCode?: number;
|
||||
|
||||
Reference in New Issue
Block a user