Skip to content

Commit 2c703d1

Browse files
committed
chore(sync): cascade fleet template@3c55c23
Auto-applied by socket-wheelhouse sync-scaffolding into vscode-socket-security. 189 file(s) touched: - .claude/hooks/_shared/README.md - .claude/hooks/_shared/hook-env.mts - .claude/hooks/_shared/markers.mts - .claude/hooks/_shared/payload.mts - .claude/hooks/_shared/transcript.mts - .claude/hooks/auth-rotation-reminder/README.md - .claude/hooks/auth-rotation-reminder/index.mts - .claude/hooks/auth-rotation-reminder/package.json - .claude/hooks/auth-rotation-reminder/test/auth-rotation-reminder.test.mts - .claude/hooks/auth-rotation-reminder/tsconfig.json - .claude/hooks/check-new-deps/README.md - .claude/hooks/check-new-deps/index.mts - .claude/hooks/check-new-deps/package.json - .claude/hooks/check-new-deps/types.mts - .claude/hooks/claude-md-section-size-guard/tsconfig.json - .claude/hooks/claude-md-size-guard/tsconfig.json - .claude/hooks/comment-tone-reminder/tsconfig.json - .claude/hooks/commit-author-guard/tsconfig.json - .claude/hooks/commit-pr-reminder/test/index.test.mts - .claude/hooks/commit-pr-reminder/tsconfig.json ... and 169 more
1 parent 34a51da commit 2c703d1

189 files changed

Lines changed: 8291 additions & 1014 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/hooks/_shared/README.md

Lines changed: 26 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.claude/hooks/_shared/hook-env.mts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* @fileoverview Hook-runtime helpers: disable-env check + prefixed
3+
* stderr writer.
4+
*
5+
* Two responsibilities every hook needs:
6+
*
7+
* 1. `isHookDisabled(slug)` — check the canonical
8+
* `SOCKET_<UPPER_SLUG>_DISABLED` env var so every hook gets a
9+
* uniform kill switch. The hook's name is the only input; the
10+
* env-var name is derived (kebab → upper-snake + `_DISABLED`
11+
* suffix). Today 15 of 47 hooks have a manually-named disable
12+
* env; this helper makes it free for every hook.
13+
*
14+
* 2. `hookLog(slug, ...lines)` — write `[<slug>] <line>` to stderr.
15+
* Hooks have long duplicated this prefix shape with
16+
* `process.stderr.write(\`[hook-name] ...\`)`; centralizing it
17+
* keeps the format consistent and lets us evolve it later
18+
* (color, level prefixes, etc.) in one file.
19+
*
20+
* No dependency on `@socketsecurity/lib-stable` — hooks load fast at PreTool-
21+
* Use time and the lib's logger ships a chunk of code (spinners, color
22+
* detection, header/footer) that's wasted on a single stderr.write.
23+
* Plain process.stderr is the right tool here.
24+
*/
25+
26+
import process from 'node:process'
27+
28+
/**
29+
* Convert a hook slug (kebab-case) to its canonical disable env-var
30+
* name. Pure string transform — exposed for tests + for hooks that
31+
* want to mention the env-var name in their disable hint.
32+
*
33+
* hookDisableEnvVar('no-revert-guard') → 'SOCKET_NO_REVERT_GUARD_DISABLED'
34+
* hookDisableEnvVar('comment-tone-reminder') → 'SOCKET_COMMENT_TONE_REMINDER_DISABLED'
35+
* hookDisableEnvVar('auth-rotation-reminder') → 'SOCKET_AUTH_ROTATION_REMINDER_DISABLED'
36+
*/
37+
export function hookDisableEnvVar(slug: string): string {
38+
const upper = slug.toUpperCase().replace(/-/g, '_')
39+
return `SOCKET_${upper}_DISABLED`
40+
}
41+
42+
/**
43+
* True when the canonical disable env is set to a truthy value. The
44+
* fleet treats any non-empty value as "disabled" — `=1`, `=true`,
45+
* `=yes`, all the same. An explicit `=0` or `=false` is also still
46+
* non-empty, so technically "disabled"; if a user wants to enable
47+
* after a session-wide disable, they should `unset` the var.
48+
*/
49+
export function isHookDisabled(slug: string): boolean {
50+
return Boolean(process.env[hookDisableEnvVar(slug)])
51+
}
52+
53+
/**
54+
* Write one or more lines to stderr, each prefixed with `[<slug>] `.
55+
* Trailing newlines are added automatically. Empty-string args are
56+
* written as bare newlines (useful for visual separation).
57+
*
58+
* hookLog('foo', 'first line', '', 'after blank')
59+
* → [foo] first line\n
60+
* \n
61+
* [foo] after blank\n
62+
*/
63+
export function hookLog(slug: string, ...lines: readonly string[]): void {
64+
const prefix = `[${slug}] `
65+
for (let i = 0, { length } = lines; i < length; i += 1) {
66+
const ln = lines[i]!
67+
if (ln === '') {
68+
process.stderr.write('\n')
69+
} else {
70+
process.stderr.write(`${prefix}${ln}\n`)
71+
}
72+
}
73+
}

.claude/hooks/_shared/markers.mts

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.claude/hooks/_shared/payload.mts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* @fileoverview Shared types for Claude Code PreToolUse hook payloads.
3+
*
4+
* Claude Code sends a JSON object on stdin to every PreToolUse hook:
5+
*
6+
* { "tool_name": "Edit" | "Write" | "Bash" | ..., "tool_input": {...} }
7+
*
8+
* The shape of `tool_input` varies by tool. The fleet's hooks need
9+
* three subsets:
10+
*
11+
* - Edit/Write hooks read `file_path` (always present) and either
12+
* `content` (Write) or `new_string` (Edit).
13+
* - Bash hooks read `command` (the shell line to run).
14+
* - A few hooks (cross-repo-guard, no-fleet-fork-guard) read
15+
* `file_path` to gate edits to specific paths.
16+
*
17+
* Each hook used to declare its own `tool_input` type inline — 7
18+
* distinct shapes existed across the fleet for the same data. This
19+
* file centralizes them so:
20+
*
21+
* 1. Future hooks copy-paste the right type instead of inventing one.
22+
* 2. A schema change (new tool, new field) is a one-file edit.
23+
* 3. The `unknown`-vs-`string` widening choice is consistent across
24+
* hooks (we widen to `unknown` and narrow at use; that's the
25+
* defensive shape for a payload we don't fully control).
26+
*
27+
* All fields are optional + `unknown` because:
28+
* - Hooks never know which tool they're inspecting until they read
29+
* `tool_name`. A Bash hook gets a Bash payload but the type is
30+
* the same union shape.
31+
* - The harness reserves the right to add fields; explicit `unknown`
32+
* forces callers to narrow at use, which prevents silent breakage
33+
* when an unexpected value lands in a known field.
34+
*/
35+
36+
/**
37+
* The full PreToolUse payload Claude Code sends on stdin. Every hook
38+
* imports this and narrows the `tool_input` fields it reads.
39+
*/
40+
export interface ToolCallPayload {
41+
readonly tool_name?: string | undefined
42+
readonly tool_input?: ToolInput | undefined
43+
}
44+
45+
/**
46+
* Union of the `tool_input` fields the fleet's hooks read. Tool-
47+
* specific fields are all optional and typed `unknown` — narrow at
48+
* the use site so a payload-shape surprise (number where a string
49+
* expected, etc.) doesn't crash the hook.
50+
*/
51+
export interface ToolInput {
52+
// Edit/Write
53+
readonly file_path?: unknown
54+
readonly content?: unknown
55+
readonly new_string?: unknown
56+
readonly old_string?: unknown
57+
// Bash
58+
readonly command?: unknown
59+
}
60+
61+
/**
62+
* Narrow `tool_input.command` to a string. Returns `undefined` when
63+
* the field is missing or non-string. Use as the canonical entry
64+
* point for Bash hooks so the narrowing logic is one line at every
65+
* call site:
66+
*
67+
* const cmd = readCommand(payload)
68+
* if (!cmd) return
69+
*/
70+
export function readCommand(payload: ToolCallPayload): string | undefined {
71+
const cmd = payload?.tool_input?.command
72+
return typeof cmd === 'string' ? cmd : undefined
73+
}
74+
75+
/**
76+
* Narrow `tool_input.file_path` to a string. Same shape as
77+
* `readCommand` — single entry point so callers don't repeat the
78+
* `typeof === 'string'` guard.
79+
*/
80+
export function readFilePath(payload: ToolCallPayload): string | undefined {
81+
const fp = payload?.tool_input?.file_path
82+
return typeof fp === 'string' ? fp : undefined
83+
}
84+
85+
/**
86+
* Narrow the write-content field. For Write tools the field is
87+
* `content`; for Edit it's `new_string`. Returns the first present
88+
* string field or `undefined`. Useful for hooks that want to scan
89+
* "what's about to land on disk" without caring whether it's a
90+
* Write or an Edit.
91+
*/
92+
export function readWriteContent(
93+
payload: ToolCallPayload,
94+
): string | undefined {
95+
const content = payload?.tool_input?.content
96+
if (typeof content === 'string') {
97+
return content
98+
}
99+
const newStr = payload?.tool_input?.new_string
100+
if (typeof newStr === 'string') {
101+
return newStr
102+
}
103+
return undefined
104+
}

.claude/hooks/_shared/transcript.mts

Lines changed: 121 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.claude/hooks/auth-rotation-reminder/README.md

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)