kimi-plugin-cc 2.0.7
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.
- package/.agents/plugins/marketplace.json +20 -0
- package/.claude-plugin/marketplace.json +16 -0
- package/.claude-plugin/plugin.json +32 -0
- package/CHANGELOG.md +1096 -0
- package/LICENSE +201 -0
- package/README.md +772 -0
- package/agents/kimi-ask.md +82 -0
- package/agents/kimi-challenge.md +82 -0
- package/agents/kimi-pursue.md +91 -0
- package/agents/kimi-rescue.md +85 -0
- package/agents/kimi-review.md +82 -0
- package/agents/kimi-swarm-write.md +92 -0
- package/agents/kimi-swarm.md +83 -0
- package/commands/README.md +16 -0
- package/commands/ask.md +32 -0
- package/commands/cancel.md +17 -0
- package/commands/challenge.md +29 -0
- package/commands/pursue.md +37 -0
- package/commands/replay.md +13 -0
- package/commands/rescue.md +32 -0
- package/commands/result.md +13 -0
- package/commands/review.md +29 -0
- package/commands/setup.md +23 -0
- package/commands/status.md +13 -0
- package/commands/swarm.md +38 -0
- package/dist/background-spawn.js +224 -0
- package/dist/cli-cancellation.js +43 -0
- package/dist/cli-client.js +845 -0
- package/dist/commands/ask.js +327 -0
- package/dist/commands/cancel.js +178 -0
- package/dist/commands/cli-helpers.js +112 -0
- package/dist/commands/models.js +140 -0
- package/dist/commands/not-implemented.js +4 -0
- package/dist/commands/pursue.js +311 -0
- package/dist/commands/registry.js +87 -0
- package/dist/commands/repair-sessions.js +159 -0
- package/dist/commands/replay.js +123 -0
- package/dist/commands/rescue.js +333 -0
- package/dist/commands/result.js +58 -0
- package/dist/commands/review-gate.js +393 -0
- package/dist/commands/review.js +218 -0
- package/dist/commands/setup.js +1132 -0
- package/dist/commands/status.js +27 -0
- package/dist/commands/swarm.js +576 -0
- package/dist/commands/worker.js +31 -0
- package/dist/companion.js +114 -0
- package/dist/config.js +22 -0
- package/dist/errors.js +40 -0
- package/dist/git.js +215 -0
- package/dist/hooks/approval-hook.js +112 -0
- package/dist/hooks/approval-policy.js +254 -0
- package/dist/hooks/config-safety.js +637 -0
- package/dist/hooks/install-paths.js +504 -0
- package/dist/hooks/install.js +281 -0
- package/dist/hooks/managed-block.js +745 -0
- package/dist/hooks/review-gate-stop.js +19 -0
- package/dist/job-store.js +559 -0
- package/dist/jobs.js +202 -0
- package/dist/kimi-command.js +72 -0
- package/dist/kimi-engine.js +624 -0
- package/dist/kimi-errors.js +220 -0
- package/dist/kimi-home.js +9 -0
- package/dist/kimi-timeouts.js +68 -0
- package/dist/kimi-version-probe.js +1410 -0
- package/dist/logging.js +22 -0
- package/dist/native-v2-preflight.js +417 -0
- package/dist/package.json +1 -0
- package/dist/parsing.js +553 -0
- package/dist/paths.js +27 -0
- package/dist/plugin-data.js +98 -0
- package/dist/process-tree.js +448 -0
- package/dist/render.js +159 -0
- package/dist/rescue-approval.js +951 -0
- package/dist/schemas/review-gate-output.js +43 -0
- package/dist/session-title.js +293 -0
- package/dist/stream-json.js +498 -0
- package/dist/types.js +1 -0
- package/dist/vendor/shell-quote/LICENSE +24 -0
- package/dist/vendor/shell-quote/index.js +1 -0
- package/dist/vendor/shell-quote/parse.js +229 -0
- package/dist/vendor/smol-toml/LICENSE +24 -0
- package/dist/vendor/smol-toml/date.js +127 -0
- package/dist/vendor/smol-toml/error.js +63 -0
- package/dist/vendor/smol-toml/extract.js +100 -0
- package/dist/vendor/smol-toml/parse.js +148 -0
- package/dist/vendor/smol-toml/primitive.js +179 -0
- package/dist/vendor/smol-toml/struct.js +184 -0
- package/dist/vendor/smol-toml/util.js +113 -0
- package/dist/version.js +7 -0
- package/docs/migration.md +215 -0
- package/docs/models.md +82 -0
- package/docs/registry-releases.md +70 -0
- package/docs/safety.md +318 -0
- package/docs/session-visibility.md +32 -0
- package/hooks/README.md +9 -0
- package/hooks/hooks.json +16 -0
- package/package.json +67 -0
- package/plugins/kimi-codex/.codex-plugin/plugin.json +39 -0
- package/plugins/kimi-codex/dist/background-spawn.js +224 -0
- package/plugins/kimi-codex/dist/cli-cancellation.js +43 -0
- package/plugins/kimi-codex/dist/cli-client.js +845 -0
- package/plugins/kimi-codex/dist/commands/ask.js +327 -0
- package/plugins/kimi-codex/dist/commands/cancel.js +178 -0
- package/plugins/kimi-codex/dist/commands/cli-helpers.js +112 -0
- package/plugins/kimi-codex/dist/commands/models.js +140 -0
- package/plugins/kimi-codex/dist/commands/not-implemented.js +4 -0
- package/plugins/kimi-codex/dist/commands/pursue.js +311 -0
- package/plugins/kimi-codex/dist/commands/registry.js +87 -0
- package/plugins/kimi-codex/dist/commands/repair-sessions.js +159 -0
- package/plugins/kimi-codex/dist/commands/replay.js +123 -0
- package/plugins/kimi-codex/dist/commands/rescue.js +333 -0
- package/plugins/kimi-codex/dist/commands/result.js +58 -0
- package/plugins/kimi-codex/dist/commands/review-gate.js +393 -0
- package/plugins/kimi-codex/dist/commands/review.js +218 -0
- package/plugins/kimi-codex/dist/commands/setup.js +1132 -0
- package/plugins/kimi-codex/dist/commands/status.js +27 -0
- package/plugins/kimi-codex/dist/commands/swarm.js +576 -0
- package/plugins/kimi-codex/dist/commands/worker.js +31 -0
- package/plugins/kimi-codex/dist/companion.js +114 -0
- package/plugins/kimi-codex/dist/config.js +22 -0
- package/plugins/kimi-codex/dist/errors.js +40 -0
- package/plugins/kimi-codex/dist/git.js +215 -0
- package/plugins/kimi-codex/dist/hooks/approval-hook.js +112 -0
- package/plugins/kimi-codex/dist/hooks/approval-policy.js +254 -0
- package/plugins/kimi-codex/dist/hooks/config-safety.js +637 -0
- package/plugins/kimi-codex/dist/hooks/install-paths.js +504 -0
- package/plugins/kimi-codex/dist/hooks/install.js +281 -0
- package/plugins/kimi-codex/dist/hooks/managed-block.js +745 -0
- package/plugins/kimi-codex/dist/hooks/review-gate-stop.js +19 -0
- package/plugins/kimi-codex/dist/job-store.js +559 -0
- package/plugins/kimi-codex/dist/jobs.js +202 -0
- package/plugins/kimi-codex/dist/kimi-command.js +72 -0
- package/plugins/kimi-codex/dist/kimi-engine.js +624 -0
- package/plugins/kimi-codex/dist/kimi-errors.js +220 -0
- package/plugins/kimi-codex/dist/kimi-home.js +9 -0
- package/plugins/kimi-codex/dist/kimi-timeouts.js +68 -0
- package/plugins/kimi-codex/dist/kimi-version-probe.js +1410 -0
- package/plugins/kimi-codex/dist/logging.js +22 -0
- package/plugins/kimi-codex/dist/native-v2-preflight.js +417 -0
- package/plugins/kimi-codex/dist/package.json +1 -0
- package/plugins/kimi-codex/dist/parsing.js +553 -0
- package/plugins/kimi-codex/dist/paths.js +27 -0
- package/plugins/kimi-codex/dist/plugin-data.js +98 -0
- package/plugins/kimi-codex/dist/process-tree.js +448 -0
- package/plugins/kimi-codex/dist/render.js +159 -0
- package/plugins/kimi-codex/dist/rescue-approval.js +951 -0
- package/plugins/kimi-codex/dist/schemas/review-gate-output.js +43 -0
- package/plugins/kimi-codex/dist/session-title.js +293 -0
- package/plugins/kimi-codex/dist/stream-json.js +498 -0
- package/plugins/kimi-codex/dist/types.js +1 -0
- package/plugins/kimi-codex/dist/vendor/shell-quote/LICENSE +24 -0
- package/plugins/kimi-codex/dist/vendor/shell-quote/index.js +1 -0
- package/plugins/kimi-codex/dist/vendor/shell-quote/parse.js +229 -0
- package/plugins/kimi-codex/dist/vendor/smol-toml/LICENSE +24 -0
- package/plugins/kimi-codex/dist/vendor/smol-toml/date.js +127 -0
- package/plugins/kimi-codex/dist/vendor/smol-toml/error.js +63 -0
- package/plugins/kimi-codex/dist/vendor/smol-toml/extract.js +100 -0
- package/plugins/kimi-codex/dist/vendor/smol-toml/parse.js +148 -0
- package/plugins/kimi-codex/dist/vendor/smol-toml/primitive.js +179 -0
- package/plugins/kimi-codex/dist/vendor/smol-toml/struct.js +184 -0
- package/plugins/kimi-codex/dist/vendor/smol-toml/util.js +113 -0
- package/plugins/kimi-codex/dist/version.js +7 -0
- package/plugins/kimi-codex/scripts/companion.sh +37 -0
- package/plugins/kimi-codex/scripts/review-gate-hook.sh +32 -0
- package/plugins/kimi-codex/skills/kimi-ask/SKILL.md +31 -0
- package/plugins/kimi-codex/skills/kimi-ask/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-cancel/SKILL.md +25 -0
- package/plugins/kimi-codex/skills/kimi-cancel/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-challenge/SKILL.md +31 -0
- package/plugins/kimi-codex/skills/kimi-challenge/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-pursue/SKILL.md +30 -0
- package/plugins/kimi-codex/skills/kimi-pursue/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-replay/SKILL.md +25 -0
- package/plugins/kimi-codex/skills/kimi-replay/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-rescue/SKILL.md +30 -0
- package/plugins/kimi-codex/skills/kimi-rescue/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-result/SKILL.md +25 -0
- package/plugins/kimi-codex/skills/kimi-result/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-review/SKILL.md +31 -0
- package/plugins/kimi-codex/skills/kimi-review/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-setup/SKILL.md +32 -0
- package/plugins/kimi-codex/skills/kimi-setup/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-status/SKILL.md +25 -0
- package/plugins/kimi-codex/skills/kimi-status/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-swarm/SKILL.md +31 -0
- package/plugins/kimi-codex/skills/kimi-swarm/agents/openai.yaml +6 -0
- package/plugins/kimi-codex/skills/kimi-swarm-write/SKILL.md +32 -0
- package/plugins/kimi-codex/skills/kimi-swarm-write/agents/openai.yaml +6 -0
- package/scripts/companion.sh +37 -0
- package/scripts/review-gate-hook.sh +32 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
// Pure decision logic for the kimi-code PreToolUse hook.
|
|
2
|
+
//
|
|
3
|
+
// Why this module exists separately from the entry script:
|
|
4
|
+
//
|
|
5
|
+
// The hook script (approval-hook.ts) handles stdin / stdout / exit
|
|
6
|
+
// semantics. This module is a pure function — easy to unit-test, easy
|
|
7
|
+
// to import from the entry script and from PR 3's rescue dispatcher
|
|
8
|
+
// without forcing those callers to mock stdin.
|
|
9
|
+
//
|
|
10
|
+
// Why the hook is load-bearing for safety:
|
|
11
|
+
//
|
|
12
|
+
// kimi-code's `kimi -p` mode hard-codes `permission: 'auto'` and
|
|
13
|
+
// registers an auto-approve handler that allows every tool. The
|
|
14
|
+
// PreToolUse hook fires BEFORE permission rules (verified in
|
|
15
|
+
// agent-core/src/agent/turn/index.ts:436-458). For read-only commands
|
|
16
|
+
// (review/challenge/review_gate/ask), the hook is the only mechanism
|
|
17
|
+
// that overrides -p's auto-approve and enforces the safety contract
|
|
18
|
+
// advertised by /kimi:review, /kimi:challenge, etc.
|
|
19
|
+
//
|
|
20
|
+
// Fail-closed posture:
|
|
21
|
+
//
|
|
22
|
+
// Unknown command labels deny anything but Read/Grep/Glob. A
|
|
23
|
+
// KIMI_PLUGIN_CC_CMD env var someone forgot to set is the "out of
|
|
24
|
+
// plugin context" case (treated as allow); a label we don't recognize
|
|
25
|
+
// is the "stale config / misconfigured caller" case (treated as deny
|
|
26
|
+
// by default).
|
|
27
|
+
/**
|
|
28
|
+
* Tools considered read-only across review/challenge/review_gate/rescue.
|
|
29
|
+
*
|
|
30
|
+
* Includes kimi-code's own local-read defaults (`Read`, `Grep`, `Glob`)
|
|
31
|
+
* plus a few additional read-safe tools the runtime auto-allows
|
|
32
|
+
* (`ReadMediaFile`, `TaskList`, `TaskOutput`). Excludes network
|
|
33
|
+
* operations (`WebSearch`, `FetchURL`) since review-style commands
|
|
34
|
+
* should stay on the local repo — adding them would silently broaden
|
|
35
|
+
* the safety contract for what is documented as a local-only review.
|
|
36
|
+
*/
|
|
37
|
+
export const READ_ONLY_TOOLS = new Set([
|
|
38
|
+
"Read",
|
|
39
|
+
"Grep",
|
|
40
|
+
"Glob",
|
|
41
|
+
"ReadMediaFile",
|
|
42
|
+
"TaskList",
|
|
43
|
+
"TaskOutput",
|
|
44
|
+
]);
|
|
45
|
+
/**
|
|
46
|
+
* kimi-code's parallel fan-out tool (PR #424, 0.12.0). Its exact tool_name
|
|
47
|
+
* string is `AgentSwarm` (verified against
|
|
48
|
+
* packages/agent-core/src/tools/builtin/collaboration/agent-swarm.ts:87,
|
|
49
|
+
* `readonly name = 'AgentSwarm' as const`). The `/kimi:swarm` (read-only)
|
|
50
|
+
* label allowlists THIS tool so the parent agent can launch the swarm; every
|
|
51
|
+
* spawned subagent inherits the same KIMI_PLUGIN_CC_CMD label and fires THIS
|
|
52
|
+
* hook at permission policy index 0 (kimi-code
|
|
53
|
+
* createPermissionDecisionPolicies puts PreToolCallHookPermissionPolicy at
|
|
54
|
+
* index 0 for ALL agents — no sub-vs-main branch — so a subagent's write is
|
|
55
|
+
* denied exactly like a single-turn review's). The singular `Agent` tool is
|
|
56
|
+
* deliberately NOT allowlisted: swarm is specifically the fan-out surface.
|
|
57
|
+
*/
|
|
58
|
+
const AGENT_SWARM_TOOL = "AgentSwarm";
|
|
59
|
+
/**
|
|
60
|
+
* agent-core-v2's ONLY chain-breaking final allow is the plan-file guard, and
|
|
61
|
+
* it fires only while plan mode is ACTIVE. Native v2 is therefore certified on
|
|
62
|
+
* the invariant that plan mode is never armed in a plugin-managed session:
|
|
63
|
+
* `default_plan_mode` is refused pre-spawn (runtime/native-v2-preflight.ts),
|
|
64
|
+
* plan-tainted sessions are never resumed, and the model-reachable entry tool
|
|
65
|
+
* is denied HERE for every label. ExitPlanMode is denied too so the deny set
|
|
66
|
+
* is explicit rather than a side effect of the read-only allowlists.
|
|
67
|
+
*/
|
|
68
|
+
const PLAN_MODE_TOOLS = new Set(["EnterPlanMode", "ExitPlanMode"]);
|
|
69
|
+
/**
|
|
70
|
+
* Recognized command labels. Sole source of truth; keep in sync with
|
|
71
|
+
* the strings emitted by `runCliPrompt` callers in
|
|
72
|
+
* `runtime/commands/*.ts`.
|
|
73
|
+
*/
|
|
74
|
+
const KNOWN_LABELS = new Set([
|
|
75
|
+
"ask",
|
|
76
|
+
"review",
|
|
77
|
+
"challenge",
|
|
78
|
+
"review_gate",
|
|
79
|
+
"rescue",
|
|
80
|
+
"swarm",
|
|
81
|
+
"swarm-write",
|
|
82
|
+
]);
|
|
83
|
+
export async function decideHookOutcome(input, ctx) {
|
|
84
|
+
const label = typeof ctx.commandLabel === "string" ? ctx.commandLabel : undefined;
|
|
85
|
+
// Out-of-plugin context: any kimi process spawned without our env var
|
|
86
|
+
// is direct user usage. The hook MUST NOT restrict it.
|
|
87
|
+
if (label === undefined || label.length === 0) {
|
|
88
|
+
return { decision: "allow" };
|
|
89
|
+
}
|
|
90
|
+
const toolName = typeof input.tool_name === "string" ? input.tool_name : "";
|
|
91
|
+
if (PLAN_MODE_TOOLS.has(toolName)) {
|
|
92
|
+
return {
|
|
93
|
+
decision: "deny",
|
|
94
|
+
reason: `kimi-plugin-cc safety hook: tool "${toolName}" is denied for plugin-managed sessions because agent-core-v2 plan-file writes can bypass later external hooks; native plan mode is never armed in plugin-managed sessions.`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
if (["GetGoal", "UpdateGoal", "CreateGoal", "SetGoalBudget"].includes(toolName)) {
|
|
98
|
+
// Pursue keeps the rescue write boundary, but must be able to inspect and
|
|
99
|
+
// terminally settle its existing goal. Never allow creating/reactivating a
|
|
100
|
+
// goal or changing its budget through this metadata-only exception.
|
|
101
|
+
const args = input.tool_input;
|
|
102
|
+
const objectArgs = typeof args === "object" && args !== null && !Array.isArray(args) &&
|
|
103
|
+
(Object.getPrototypeOf(args) === Object.prototype || Object.getPrototypeOf(args) === null);
|
|
104
|
+
const keys = objectArgs ? Reflect.ownKeys(args) : [];
|
|
105
|
+
const validArgs = objectArgs && ((toolName === "GetGoal" && keys.length === 0) ||
|
|
106
|
+
(toolName === "UpdateGoal" && keys.length === 1 && keys[0] === "status" &&
|
|
107
|
+
(args.status === "complete" || args.status === "blocked")));
|
|
108
|
+
if (label === "rescue" && ctx.operationKind === "pursue" &&
|
|
109
|
+
typeof ctx.trustedWorkspaceRoot === "string" && ctx.trustedWorkspaceRoot.trim().length > 0 && validArgs) {
|
|
110
|
+
return { decision: "allow" };
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
decision: "deny",
|
|
114
|
+
reason: `kimi-plugin-cc safety hook: tool "${toolName}" requires a pursue run with a trusted workspace root and exact terminal goal metadata arguments; goal creation, reactivation, and budget changes are denied.`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
switch (label) {
|
|
118
|
+
case "ask":
|
|
119
|
+
case "review":
|
|
120
|
+
case "challenge":
|
|
121
|
+
case "review_gate":
|
|
122
|
+
// /kimi:ask is documented and dispatched as a read-only narrative
|
|
123
|
+
// surface (see agents/kimi-ask.md: "do not implement anything Kimi
|
|
124
|
+
// describes"). PR 2 initially trusted kimi-code's `permission:auto`
|
|
125
|
+
// for ask on the assumption the user was watching every tool call,
|
|
126
|
+
// but `/kimi:ask` runs as a non-interactive subprocess via
|
|
127
|
+
// companion.sh — the user never sees individual tool prompts. PR 4
|
|
128
|
+
// reviewers flagged this contradiction; ask now shares the
|
|
129
|
+
// read-only allowlist with review/challenge/review_gate.
|
|
130
|
+
if (READ_ONLY_TOOLS.has(toolName)) {
|
|
131
|
+
return { decision: "allow" };
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
decision: "deny",
|
|
135
|
+
reason: denyReadOnlyMessage(label, toolName),
|
|
136
|
+
};
|
|
137
|
+
case "swarm":
|
|
138
|
+
// /kimi:swarm — read-only PARALLEL fan-out. The parent agent must be
|
|
139
|
+
// allowed to call AgentSwarm (else the swarm never launches and the
|
|
140
|
+
// hook silently breaks the feature). Every spawned subagent inherits
|
|
141
|
+
// THIS "swarm" label and fires THIS hook at policy index 0, so a
|
|
142
|
+
// subagent's Write/Edit/Bash is denied exactly like a single-turn
|
|
143
|
+
// review's — read-only swarm opens ZERO new write surface. Allow only
|
|
144
|
+
// the read-only set plus AgentSwarm; deny everything else (including the
|
|
145
|
+
// singular `Agent` tool — swarm is the fan-out surface, not arbitrary
|
|
146
|
+
// delegation). Nested AgentSwarm calls from a subagent are allowed and
|
|
147
|
+
// bounded by the command's wall-clock budget (the only new risk is
|
|
148
|
+
// cost, not writes).
|
|
149
|
+
if (READ_ONLY_TOOLS.has(toolName) || toolName === AGENT_SWARM_TOOL) {
|
|
150
|
+
return { decision: "allow" };
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
decision: "deny",
|
|
154
|
+
reason: denySwarmMessage(toolName),
|
|
155
|
+
};
|
|
156
|
+
case "swarm-write": {
|
|
157
|
+
// /kimi:swarm --write — WRITE-capable parallel fan-out (v1.4). The
|
|
158
|
+
// coordinator and `coder` subagents run in an EPHEMERAL THROWAWAY WORKTREE
|
|
159
|
+
// (off the user's HEAD). Allow AgentSwarm (else the swarm never launches)
|
|
160
|
+
// plus the read-only set; deny the singular Agent. Every write/edit/shell
|
|
161
|
+
// goes through the rescue allowlist — but scoped to the TRUSTED env-provided
|
|
162
|
+
// worktree root (ctx.trustedWorkspaceRoot), NOT the hook payload `cwd`.
|
|
163
|
+
// Rationale: the worktree path is exported as KIMI_PLUGIN_CC_WORKSPACE_ROOT
|
|
164
|
+
// by the same trusted plugin spawn that sets KIMI_PLUGIN_CC_CMD, so the
|
|
165
|
+
// model running inside kimi cannot forge it, and confinement does not
|
|
166
|
+
// depend on how upstream derives the payload cwd for an in-process
|
|
167
|
+
// subagent. Missing root ⇒ fail-closed (deny writes).
|
|
168
|
+
if (READ_ONLY_TOOLS.has(toolName) || toolName === AGENT_SWARM_TOOL) {
|
|
169
|
+
return { decision: "allow" };
|
|
170
|
+
}
|
|
171
|
+
const workspaceRoot = typeof ctx.trustedWorkspaceRoot === "string" ? ctx.trustedWorkspaceRoot : "";
|
|
172
|
+
if (workspaceRoot.length === 0) {
|
|
173
|
+
return {
|
|
174
|
+
decision: "deny",
|
|
175
|
+
reason: `kimi-plugin-cc safety hook: swarm-write received no trusted workspace root; tool "${toolName}" denied. ` +
|
|
176
|
+
"This is a plugin misconfiguration — writes are refused rather than risk the user's working tree.",
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
if (ctx.rescueEvaluator !== undefined) {
|
|
180
|
+
return await ctx.rescueEvaluator(workspaceRoot, toolName, input.tool_input);
|
|
181
|
+
}
|
|
182
|
+
// Stub for callers that didn't inject the evaluator (tests of the policy
|
|
183
|
+
// function alone). The production entry script always injects it.
|
|
184
|
+
if (READ_ONLY_TOOLS.has(toolName)) {
|
|
185
|
+
return { decision: "allow" };
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
decision: "deny",
|
|
189
|
+
reason: `kimi-plugin-cc safety hook: swarm-write evaluator not configured; tool "${toolName}" denied as a safety default.`,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
case "rescue": {
|
|
193
|
+
const workspaceRoot = typeof ctx.trustedWorkspaceRoot === "string" ? ctx.trustedWorkspaceRoot : "";
|
|
194
|
+
if (workspaceRoot.length === 0) {
|
|
195
|
+
if (READ_ONLY_TOOLS.has(toolName))
|
|
196
|
+
return { decision: "allow" };
|
|
197
|
+
return {
|
|
198
|
+
decision: "deny",
|
|
199
|
+
reason: `kimi-plugin-cc safety hook: rescue received no trusted workspace root; tool "${toolName}" denied. ` +
|
|
200
|
+
"This is a plugin misconfiguration — writes are refused rather than trusting hook payload cwd.",
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
if (ctx.rescueEvaluator !== undefined) {
|
|
204
|
+
return await ctx.rescueEvaluator(workspaceRoot, toolName, input.tool_input);
|
|
205
|
+
}
|
|
206
|
+
// Stub for callers that didn't inject the evaluator (e.g.,
|
|
207
|
+
// tests that exercise only the policy function). Allow
|
|
208
|
+
// Read/Grep/Glob and friends; deny everything else. The
|
|
209
|
+
// production entry script wires the real evaluator from
|
|
210
|
+
// runtime/rescue-approval.ts.
|
|
211
|
+
if (READ_ONLY_TOOLS.has(toolName)) {
|
|
212
|
+
return { decision: "allow" };
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
decision: "deny",
|
|
216
|
+
reason: `kimi-plugin-cc safety hook: rescue evaluator not configured; tool "${toolName}" denied as a safety default.`,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
default:
|
|
220
|
+
if (KNOWN_LABELS.has(label)) {
|
|
221
|
+
// Should be unreachable — every entry in KNOWN_LABELS has its
|
|
222
|
+
// own branch above. If you see this, add the case.
|
|
223
|
+
return {
|
|
224
|
+
decision: "deny",
|
|
225
|
+
reason: `kimi-plugin-cc safety hook: command label "${label}" has no policy branch.`,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
// Unknown label. Be conservative; only allow Read/Grep/Glob.
|
|
229
|
+
if (READ_ONLY_TOOLS.has(toolName)) {
|
|
230
|
+
return { decision: "allow" };
|
|
231
|
+
}
|
|
232
|
+
return {
|
|
233
|
+
decision: "deny",
|
|
234
|
+
reason: `kimi-plugin-cc safety hook: unrecognized command label "${label}"; tool "${toolName}" denied as a safety default.`,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function denyReadOnlyMessage(label, toolName) {
|
|
239
|
+
const tool = toolName.length > 0 ? toolName : "<unspecified>";
|
|
240
|
+
return [
|
|
241
|
+
`kimi-plugin-cc safety hook: ${label} is read-only.`,
|
|
242
|
+
`Tool "${tool}" is denied — use Read, Grep, or Glob to inspect the workspace instead.`,
|
|
243
|
+
"If you need to mutate state, the user must invoke /kimi:rescue (write-capable) rather than this command.",
|
|
244
|
+
].join(" ");
|
|
245
|
+
}
|
|
246
|
+
function denySwarmMessage(toolName) {
|
|
247
|
+
const tool = toolName.length > 0 ? toolName : "<unspecified>";
|
|
248
|
+
return [
|
|
249
|
+
"kimi-plugin-cc safety hook: swarm is a read-only parallel review.",
|
|
250
|
+
`Tool "${tool}" is denied — every subagent may use Read, Grep, or Glob to inspect the workspace,`,
|
|
251
|
+
"and the coordinator may use AgentSwarm to fan out, but no write, edit, or shell operations are permitted.",
|
|
252
|
+
"Consolidate the subagents' findings into a markdown report instead.",
|
|
253
|
+
].join(" ");
|
|
254
|
+
}
|