Skip to content

Commit 3deb873

Browse files
committed
chore: Update mods/
1 parent 2301018 commit 3deb873

100 files changed

Lines changed: 3323 additions & 301 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.

‎mods/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ source, published as it is built into the binary.
77

88
| Mod | What it does | Seated |
99
| --- | --- | --- |
10-
| [`sec-default`](sec-default) | Keeps an organization's classic hooks, prompt content, managed settings, tool policy and deny rules out of reach of the plugins a person installs; adds no policy of its own. | Outermost, on a machine with managed settings or for a Team or Enterprise organization, unless managed `prependPlugins` says otherwise |
10+
| [`sec-default`](sec-default) | Keeps an organization's classic hooks, prompt content, managed settings, tool policy, permission rules and pinned environment out of reach of the plugins a person installs; adds no policy of its own. | Outermost, on a machine with managed settings or a managed-mcp.json, or for a Team or Enterprise organization, and from then on for the session, unless managed `prependPlugins` says otherwise |
1111
| [`diff`](diff) | `/diff`: the session's uncommitted changes in a pane beside the transcript, file by file with their hunks, refreshed as Claude edits files and runs commands. | Built in |
1212
| [`telemetry`](telemetry) | Hooks `$.telemetry`'s two events (`log`, `mark`), adding the noun in the `engine.create` fold where the engine has none, so a built-in plugin can record an event as a first-party analytics row, sent in batches; refuses installed plugins; sends nothing wherever Claude Code's analytics are off. | Built in |
1313
| [`agents-md`](agents-md) | `AGENTS.md` as project instructions, by one option: loaded where the project has no `CLAUDE.md` of its own (`claude-md-or-agents-md`, the default) or beside it (`claude-md-and-agents-md`), placed and framed exactly as the engine places `CLAUDE.md`, nested ones on a `Read`; or the project's and the person's instruction files dropped and the organization's kept (`managed-only`); or `CLAUDE.md` alone, as the engine reads it (`claude-md`). | Built in |

‎mods/sec-default/.claude-plugin/plugin.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "sec-default",
33
"version": "0.1.0",
4-
"description": "Security default for organizations: seated outermost, it keeps the organization's classic hooks, prompt content, settings and tool policy out of reach of the plugins a person installs, and adds no policy of its own; one managed option, allowManagedModsOnly, limits mods to the organization's.",
4+
"description": "Security default for organizations: seated outermost, it keeps the organization's classic hooks, prompt content, settings, tool policy and pinned environment out of reach of the plugins a person installs, and adds no policy of its own; one managed option, allowManagedModsOnly, limits mods to the organization's.",
55
"author": {
66
"name": "Anthropic"
77
}

‎mods/sec-default/README.md‎

Lines changed: 121 additions & 39 deletions
Large diffs are not rendered by default.

‎mods/sec-default/hooks/held-verdict/caught-answer.ts‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import Verdicts from './verdicts'
66
* What the `tool.check` hook's failure handler answers from the one run it
77
* can read, the failed hook's last: that run's verdict, or a refusal.
88
*
9-
* A deny stands, and so does a verdict no link that may hold a person's
10-
* plugin loosened. A loosened one, or none at all, met no deny rule.
9+
* A verdict stands that no link that may hold a person's plugin rewrote
10+
* without tightening. A rewritten one, or none at all, met no rule or hook.
1111
*
1212
* @param last what that run settled on; undefined when it rejected
1313
* @param trace that run's `next.trace`
@@ -18,8 +18,7 @@ export function caughtAnswer(
1818
trace: readonly TraceEntry<'tool.check'>[],
1919
) {
2020
const isVouched =
21-
last !== undefined &&
22-
(last.decision === 'deny' || Verdicts.loosenedByUsers(trace).length === 0)
21+
last !== undefined && Verdicts.rewrittenByUsers(trace).length === 0
2322

2423
return isVouched ? last : Verdicts.UNCHECKED_DENY
2524
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { EventResult } from 'claude-code'
2+
3+
/**
4+
* What kind of thing held over a person's plugin, as the notice calls it:
5+
* `deny rule`, `ask rule`, `<event> hook's ask`, `ask cap`, or `refusal`.
6+
*
7+
* A deny that names no rule is a refusal even when it names a hook: the hook
8+
* may only have asked, and something else refused. An ask that names neither
9+
* holds by the ceiling an organization set on the tool.
10+
*
11+
* @param held the verdict that holds
12+
* @returns the kind
13+
*/
14+
export function heldKind(held: EventResult<'tool.check'>): string {
15+
const isRuled = held.rule !== undefined
16+
const isRefused = held.decision === 'deny'
17+
const isHooked = held.hook !== undefined
18+
19+
return isRuled
20+
? `${held.decision} rule`
21+
: isRefused
22+
? 'refusal'
23+
: isHooked
24+
? `${held.hook} hook's ask`
25+
: 'ask cap'
26+
}
Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,34 @@
1+
import type { EventResult } from 'claude-code'
2+
3+
import { heldKind } from './held-kind.js'
4+
15
/**
2-
* What a person reads, once for each plugin in a session, when a plugin they
3-
* installed answered allow or ask over a deny rule in their settings.
6+
* What a person reads, once for each plugin and kind in a session, when a
7+
* plugin they installed rewrote a verdict that holds over it.
48
*
59
* It names the option an administrator sets to let such plugins override.
610
*
711
* @param plugin the plugin's name, or its batch's, as the trace names it
812
* @param tool the tool the call named
9-
* @param rule the deny rule that decided, as written
13+
* @param held the verdict that holds, naming the rule behind it if one is
14+
* @param attempt what the plugin did: answered looser, or the same reworded
1015
* @returns the line
1116
*/
12-
export const heldNotice = (plugin: string, tool: string, rule: string) =>
13-
`${plugin} tried to lift a deny rule in your settings from a ${tool} ` +
14-
`call (${rule}); the deny rule holds over the plugins you install ` +
15-
'(allowModsToOverrideDenyRules)'
17+
export function heldNotice(
18+
plugin: string,
19+
tool: string,
20+
held: EventResult<'tool.check'>,
21+
attempt: 'lift' | 'reword',
22+
): string {
23+
const kind = heldKind(held)
24+
const article = kind.startsWith('a') ? 'an' : 'a'
25+
const changed =
26+
held.rule === undefined
27+
? `${article} ${kind} from a ${tool} call`
28+
: `${article} ${kind} in your settings from a ${tool} call (${held.rule})`
29+
30+
return (
31+
`${plugin} tried to ${attempt} ${changed}; the ${kind} holds over the ` +
32+
'plugins you install (allowModsToOverrideDenyRules)'
33+
)
34+
}

‎mods/sec-default/hooks/held-verdict/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './caught-answer.js'
2+
export * from './held-kind.js'
23
export * from './held-notice.js'
34
export * from './verdicts'
45

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import type { EventResult } from 'claude-code'
2+
3+
import { isSameVerdict } from './is-same-verdict.js'
4+
import Ranking from './ranking'
5+
6+
/**
7+
* Whether the verdict reached past the user tier holds whole over the
8+
* chain's answer: a deny, or an ask a rule, a hook or a ceiling stands behind.
9+
*
10+
* It holds over a more permissive answer and over the same decision reworded
11+
* or stripped of its rule or hook; a stricter answer stands. Any rule or
12+
* classic hook counts, whoever configured it, and so does the ceiling an
13+
* organization set on the tool. The mode's own ask, with none, never holds.
14+
*
15+
* @param held what the run past the user tier settled on
16+
* @param answer what the whole chain settled on
17+
* @returns true when the held verdict is the one to return, as it is
18+
*/
19+
export const holdsOver = (
20+
held: EventResult<'tool.check'>,
21+
answer: EventResult<'tool.check'>,
22+
) =>
23+
!Ranking.isLooser(held, answer) &&
24+
!isSameVerdict(held, answer) &&
25+
(held.decision === 'deny' ||
26+
held.rule !== undefined ||
27+
held.hook !== undefined ||
28+
held.ceiling !== undefined)
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
export * from './is-rule-deny.js'
2-
export * from './loosened-by-users.js'
1+
export * from './holds-over.js'
2+
export * from './is-same-verdict.js'
33
export * from './ranking'
4-
export * from './types'
4+
export * from './rewritten-by-users.js'
55
export * from './unchecked-deny.js'
66

77
export * as default from '.'

‎mods/sec-default/hooks/held-verdict/verdicts/is-rule-deny.ts‎

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)