@gotgenes/pi-permission-system 5.5.1 → 5.6.0
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/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/handlers/gates/bash-external-directory.ts +70 -65
- package/src/handlers/gates/descriptor.ts +115 -0
- package/src/handlers/gates/external-directory.ts +63 -122
- package/src/handlers/gates/index.ts +12 -4
- package/src/handlers/gates/runner.ts +144 -0
- package/src/handlers/gates/skill-read.ts +37 -54
- package/src/handlers/gates/tool.ts +35 -97
- package/src/handlers/gates/types.ts +0 -77
- package/src/handlers/tool-call.ts +89 -58
- package/tests/handlers/gates/bash-external-directory.test.ts +128 -126
- package/tests/handlers/gates/external-directory.test.ts +117 -188
- package/tests/handlers/gates/runner.test.ts +361 -0
- package/tests/handlers/gates/skill-read.test.ts +87 -123
- package/tests/handlers/gates/tool.test.ts +119 -112
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { PermissionPromptDecision } from "../../permission-dialog";
|
|
2
|
+
import { applyPermissionGate } from "../../permission-gate";
|
|
3
|
+
import type { PermissionCheckResult } from "../../types";
|
|
4
|
+
import type { GateDescriptor, GateRunnerDeps } from "./descriptor";
|
|
5
|
+
import { deriveResolution } from "./helpers";
|
|
6
|
+
import type { GateOutcome } from "./types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Execute the full check→log→emit→approve cycle for a gate descriptor.
|
|
10
|
+
*
|
|
11
|
+
* This is the single site for:
|
|
12
|
+
* - Permission checking (or using pre-resolved state)
|
|
13
|
+
* - Session-hit fast path
|
|
14
|
+
* - Interactive prompt orchestration
|
|
15
|
+
* - Decision event emission
|
|
16
|
+
* - Session-rule recording
|
|
17
|
+
*
|
|
18
|
+
* Gate functions produce descriptors; this runner executes them.
|
|
19
|
+
*/
|
|
20
|
+
export async function runGateCheck(
|
|
21
|
+
descriptor: GateDescriptor,
|
|
22
|
+
agentName: string | null,
|
|
23
|
+
toolCallId: string,
|
|
24
|
+
deps: GateRunnerDeps,
|
|
25
|
+
): Promise<GateOutcome> {
|
|
26
|
+
// 1. Resolve permission state — pre-check, pre-resolved, or via checkPermission
|
|
27
|
+
let check: PermissionCheckResult;
|
|
28
|
+
if (descriptor.preCheck) {
|
|
29
|
+
check = descriptor.preCheck;
|
|
30
|
+
} else if (descriptor.preResolved) {
|
|
31
|
+
check = {
|
|
32
|
+
state: descriptor.preResolved.state,
|
|
33
|
+
toolName: descriptor.surface,
|
|
34
|
+
source: "tool",
|
|
35
|
+
origin: "builtin",
|
|
36
|
+
};
|
|
37
|
+
} else {
|
|
38
|
+
check = deps.checkPermission(
|
|
39
|
+
descriptor.surface,
|
|
40
|
+
descriptor.input,
|
|
41
|
+
agentName ?? undefined,
|
|
42
|
+
deps.getSessionRuleset(),
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// 2. Session-hit fast path
|
|
47
|
+
if (check.source === "session") {
|
|
48
|
+
deps.writeReviewLog("permission_request.session_approved", {
|
|
49
|
+
...descriptor.logContext,
|
|
50
|
+
agentName,
|
|
51
|
+
resolution: "session_approved",
|
|
52
|
+
sessionApprovalPattern: check.matchedPattern,
|
|
53
|
+
});
|
|
54
|
+
deps.emitDecision({
|
|
55
|
+
surface: descriptor.decision.surface,
|
|
56
|
+
value: descriptor.decision.value,
|
|
57
|
+
result: "allow",
|
|
58
|
+
resolution: "session_approved",
|
|
59
|
+
origin: check.origin ?? null,
|
|
60
|
+
agentName: agentName ?? null,
|
|
61
|
+
matchedPattern: check.matchedPattern ?? null,
|
|
62
|
+
});
|
|
63
|
+
return { action: "allow" };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 3. Apply the deny/ask/allow gate
|
|
67
|
+
const canConfirm = deps.canConfirm();
|
|
68
|
+
|
|
69
|
+
// Resolve the first pattern for applyPermissionGate's sessionApproval param
|
|
70
|
+
const singleSessionApproval = descriptor.sessionApproval
|
|
71
|
+
? "pattern" in descriptor.sessionApproval
|
|
72
|
+
? {
|
|
73
|
+
surface: descriptor.sessionApproval.surface,
|
|
74
|
+
pattern: descriptor.sessionApproval.pattern,
|
|
75
|
+
}
|
|
76
|
+
: descriptor.sessionApproval.patterns.length > 0
|
|
77
|
+
? {
|
|
78
|
+
surface: descriptor.sessionApproval.surface,
|
|
79
|
+
pattern: descriptor.sessionApproval.patterns[0],
|
|
80
|
+
}
|
|
81
|
+
: undefined
|
|
82
|
+
: undefined;
|
|
83
|
+
|
|
84
|
+
let autoApproved = false;
|
|
85
|
+
const gateResult = await applyPermissionGate({
|
|
86
|
+
state: check.state,
|
|
87
|
+
canConfirm,
|
|
88
|
+
sessionApproval: singleSessionApproval,
|
|
89
|
+
promptForApproval: async () => {
|
|
90
|
+
const decision = await deps.promptPermission({
|
|
91
|
+
requestId: toolCallId,
|
|
92
|
+
...descriptor.promptDetails,
|
|
93
|
+
});
|
|
94
|
+
autoApproved = decision.autoApproved === true;
|
|
95
|
+
return decision;
|
|
96
|
+
},
|
|
97
|
+
writeLog: deps.writeReviewLog,
|
|
98
|
+
logContext: { ...descriptor.logContext, agentName },
|
|
99
|
+
messages: descriptor.messages,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// 4. Determine whether session approval was granted
|
|
103
|
+
const hasSessionApproval =
|
|
104
|
+
gateResult.action === "allow" && gateResult.sessionApproval !== undefined;
|
|
105
|
+
|
|
106
|
+
// 5. Emit decision event
|
|
107
|
+
deps.emitDecision({
|
|
108
|
+
surface: descriptor.decision.surface,
|
|
109
|
+
value: descriptor.decision.value,
|
|
110
|
+
result: gateResult.action === "allow" ? "allow" : "deny",
|
|
111
|
+
resolution: deriveResolution(
|
|
112
|
+
check.state,
|
|
113
|
+
gateResult.action,
|
|
114
|
+
hasSessionApproval,
|
|
115
|
+
canConfirm,
|
|
116
|
+
autoApproved,
|
|
117
|
+
),
|
|
118
|
+
origin: check.origin ?? null,
|
|
119
|
+
agentName: agentName ?? null,
|
|
120
|
+
matchedPattern: check.matchedPattern ?? null,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// 6. Record session approval(s)
|
|
124
|
+
if (gateResult.action === "allow" && hasSessionApproval) {
|
|
125
|
+
if (descriptor.sessionApproval) {
|
|
126
|
+
if ("patterns" in descriptor.sessionApproval) {
|
|
127
|
+
for (const pattern of descriptor.sessionApproval.patterns) {
|
|
128
|
+
deps.approveSessionRule(descriptor.sessionApproval.surface, pattern);
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
deps.approveSessionRule(
|
|
132
|
+
descriptor.sessionApproval.surface,
|
|
133
|
+
descriptor.sessionApproval.pattern,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (gateResult.action === "block") {
|
|
140
|
+
return { action: "block", reason: gateResult.reason };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return { action: "allow" };
|
|
144
|
+
}
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import { toRecord } from "../../common";
|
|
2
2
|
import { normalizePathForComparison } from "../../external-directory";
|
|
3
|
-
import { applyPermissionGate } from "../../permission-gate";
|
|
4
3
|
import {
|
|
5
4
|
formatSkillPathAskPrompt,
|
|
6
5
|
formatSkillPathDenyReason,
|
|
7
6
|
} from "../../permission-prompts";
|
|
7
|
+
import type { SkillPromptEntry } from "../../skill-prompt-sanitizer";
|
|
8
8
|
import { findSkillPathMatch } from "../../skill-prompt-sanitizer";
|
|
9
|
-
import {
|
|
10
|
-
import type {
|
|
9
|
+
import type { GateDescriptor } from "./descriptor";
|
|
10
|
+
import type { ToolCallContext } from "./types";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
*
|
|
13
|
+
* Build a pure descriptor for the skill-read permission gate.
|
|
14
14
|
*
|
|
15
15
|
* Returns `null` when the gate does not apply (tool is not `read`, no active
|
|
16
16
|
* skill entries, or the read path does not match any skill).
|
|
17
|
+
* Returns a GateDescriptor with preResolved state from the matched skill entry.
|
|
17
18
|
*/
|
|
18
|
-
export
|
|
19
|
+
export function describeSkillReadGate(
|
|
19
20
|
tcc: ToolCallContext,
|
|
20
|
-
|
|
21
|
-
):
|
|
22
|
-
const activeSkillEntries =
|
|
21
|
+
getActiveSkillEntries: () => SkillPromptEntry[],
|
|
22
|
+
): GateDescriptor | null {
|
|
23
|
+
const activeSkillEntries = getActiveSkillEntries();
|
|
23
24
|
|
|
24
|
-
// Only applies to read tool calls with active skill entries
|
|
25
25
|
if (tcc.toolName !== "read" || activeSkillEntries.length === 0) {
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
@@ -47,29 +47,10 @@ export async function evaluateSkillReadGate(
|
|
|
47
47
|
path,
|
|
48
48
|
tcc.agentName ?? undefined,
|
|
49
49
|
);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
promptForApproval: () =>
|
|
55
|
-
deps.promptPermission({
|
|
56
|
-
requestId: tcc.toolCallId,
|
|
57
|
-
source: "skill_read",
|
|
58
|
-
agentName: tcc.agentName,
|
|
59
|
-
message: skillReadMessage,
|
|
60
|
-
toolCallId: tcc.toolCallId,
|
|
61
|
-
toolName: tcc.toolName,
|
|
62
|
-
skillName: matchedSkill.name,
|
|
63
|
-
path,
|
|
64
|
-
}),
|
|
65
|
-
writeLog: deps.writeReviewLog,
|
|
66
|
-
logContext: {
|
|
67
|
-
source: "skill_read",
|
|
68
|
-
skillName: matchedSkill.name,
|
|
69
|
-
agentName: tcc.agentName,
|
|
70
|
-
path,
|
|
71
|
-
message: skillReadMessage,
|
|
72
|
-
},
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
surface: "skill",
|
|
53
|
+
input: { name: matchedSkill.name },
|
|
73
54
|
messages: {
|
|
74
55
|
denyReason: formatSkillPathDenyReason(
|
|
75
56
|
matchedSkill,
|
|
@@ -84,26 +65,28 @@ export async function evaluateSkillReadGate(
|
|
|
84
65
|
return `User denied access to skill '${matchedSkill.name}'.${denialReason}`;
|
|
85
66
|
},
|
|
86
67
|
},
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
68
|
+
promptDetails: {
|
|
69
|
+
source: "skill_read",
|
|
70
|
+
agentName: tcc.agentName,
|
|
71
|
+
message: skillReadMessage,
|
|
72
|
+
toolCallId: tcc.toolCallId,
|
|
73
|
+
toolName: tcc.toolName,
|
|
74
|
+
skillName: matchedSkill.name,
|
|
75
|
+
path,
|
|
76
|
+
},
|
|
77
|
+
logContext: {
|
|
78
|
+
source: "skill_read",
|
|
79
|
+
skillName: matchedSkill.name,
|
|
80
|
+
agentName: tcc.agentName,
|
|
81
|
+
path,
|
|
82
|
+
message: skillReadMessage,
|
|
83
|
+
},
|
|
84
|
+
decision: {
|
|
85
|
+
surface: "skill",
|
|
86
|
+
value: matchedSkill.name,
|
|
87
|
+
},
|
|
88
|
+
preResolved: {
|
|
89
|
+
state: matchedSkill.state,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
109
92
|
}
|
|
@@ -1,53 +1,26 @@
|
|
|
1
1
|
import { PATH_BEARING_TOOLS } from "../../external-directory";
|
|
2
2
|
import { suggestSessionPattern } from "../../pattern-suggest";
|
|
3
|
-
import { applyPermissionGate } from "../../permission-gate";
|
|
4
3
|
import {
|
|
5
4
|
formatAskPrompt,
|
|
6
5
|
formatDenyReason,
|
|
7
6
|
formatUserDeniedReason,
|
|
8
7
|
} from "../../permission-prompts";
|
|
9
8
|
import { getPermissionLogContext } from "../../tool-input-preview";
|
|
10
|
-
import {
|
|
11
|
-
import type {
|
|
9
|
+
import type { PermissionCheckResult } from "../../types";
|
|
10
|
+
import type { GateDescriptor } from "./descriptor";
|
|
11
|
+
import { deriveDecisionValue } from "./helpers";
|
|
12
|
+
import type { ToolCallContext } from "./types";
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
+
* Build a pure descriptor for the normal tool permission gate.
|
|
15
16
|
*
|
|
16
|
-
*
|
|
17
|
+
* Takes a pre-computed PermissionCheckResult (from checkPermission) and
|
|
18
|
+
* returns a GateDescriptor that the runner can execute. No side effects.
|
|
17
19
|
*/
|
|
18
|
-
export
|
|
20
|
+
export function describeToolGate(
|
|
19
21
|
tcc: ToolCallContext,
|
|
20
|
-
|
|
21
|
-
):
|
|
22
|
-
const check = deps.checkPermission(
|
|
23
|
-
tcc.toolName,
|
|
24
|
-
tcc.input,
|
|
25
|
-
tcc.agentName ?? undefined,
|
|
26
|
-
deps.getSessionRuleset(),
|
|
27
|
-
);
|
|
28
|
-
|
|
29
|
-
// Session-hit: already approved by a session rule — skip the gate entirely.
|
|
30
|
-
if (check.source === "session") {
|
|
31
|
-
deps.writeReviewLog("permission_request.session_approved", {
|
|
32
|
-
source: "tool_call",
|
|
33
|
-
toolCallId: tcc.toolCallId,
|
|
34
|
-
toolName: tcc.toolName,
|
|
35
|
-
agentName: tcc.agentName,
|
|
36
|
-
resolution: "session_approved",
|
|
37
|
-
sessionApprovalPattern: check.matchedPattern,
|
|
38
|
-
});
|
|
39
|
-
deps.emitDecision({
|
|
40
|
-
surface: tcc.toolName,
|
|
41
|
-
value: deriveDecisionValue(tcc.toolName, check),
|
|
42
|
-
result: "allow",
|
|
43
|
-
resolution: "session_approved",
|
|
44
|
-
origin: check.origin ?? null,
|
|
45
|
-
agentName: tcc.agentName ?? null,
|
|
46
|
-
matchedPattern: check.matchedPattern ?? null,
|
|
47
|
-
});
|
|
48
|
-
return { action: "allow" };
|
|
49
|
-
}
|
|
50
|
-
|
|
22
|
+
check: PermissionCheckResult,
|
|
23
|
+
): GateDescriptor {
|
|
51
24
|
const permissionLogContext = getPermissionLogContext(
|
|
52
25
|
check,
|
|
53
26
|
tcc.input,
|
|
@@ -69,85 +42,50 @@ export async function evaluateToolGate(
|
|
|
69
42
|
typeof (tcc.input as Record<string, unknown>)?.command === "string"
|
|
70
43
|
? ((tcc.input as Record<string, unknown>).command as string)
|
|
71
44
|
: null;
|
|
72
|
-
const
|
|
45
|
+
const unavailableReason = inputCommand
|
|
73
46
|
? `Running bash command '${inputCommand}' requires approval, but no interactive UI is available.`
|
|
74
47
|
: tcc.toolName === "mcp"
|
|
75
48
|
? "Using tool 'mcp' requires approval, but no interactive UI is available."
|
|
76
49
|
: `Using tool '${tcc.toolName}' requires approval, but no interactive UI is available.`;
|
|
77
50
|
|
|
78
|
-
const
|
|
51
|
+
const askMessage = formatAskPrompt(
|
|
79
52
|
check,
|
|
80
53
|
tcc.agentName ?? undefined,
|
|
81
54
|
tcc.input,
|
|
82
55
|
);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
surface: tcc.toolName,
|
|
59
|
+
input: tcc.input,
|
|
60
|
+
messages: {
|
|
61
|
+
denyReason: formatDenyReason(check, tcc.agentName ?? undefined),
|
|
62
|
+
unavailableReason,
|
|
63
|
+
userDeniedReason: (decision) =>
|
|
64
|
+
formatUserDeniedReason(check, decision.denialReason),
|
|
65
|
+
},
|
|
88
66
|
sessionApproval: {
|
|
89
67
|
surface: suggestion.surface,
|
|
90
68
|
pattern: suggestion.pattern,
|
|
91
69
|
},
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
sessionLabel: suggestion.label,
|
|
101
|
-
...permissionLogContext,
|
|
102
|
-
});
|
|
103
|
-
toolDecisionAutoApproved = decision.autoApproved === true;
|
|
104
|
-
return decision;
|
|
70
|
+
promptDetails: {
|
|
71
|
+
source: "tool_call",
|
|
72
|
+
agentName: tcc.agentName,
|
|
73
|
+
message: askMessage,
|
|
74
|
+
toolCallId: tcc.toolCallId,
|
|
75
|
+
toolName: tcc.toolName,
|
|
76
|
+
sessionLabel: suggestion.label,
|
|
77
|
+
...permissionLogContext,
|
|
105
78
|
},
|
|
106
|
-
writeLog: deps.writeReviewLog,
|
|
107
79
|
logContext: {
|
|
108
80
|
source: "tool_call",
|
|
109
81
|
toolCallId: tcc.toolCallId,
|
|
110
82
|
toolName: tcc.toolName,
|
|
111
|
-
|
|
112
|
-
message: toolAskMessage,
|
|
83
|
+
message: askMessage,
|
|
113
84
|
...permissionLogContext,
|
|
114
85
|
},
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
userDeniedReason: (decision) =>
|
|
119
|
-
formatUserDeniedReason(check, decision.denialReason),
|
|
86
|
+
decision: {
|
|
87
|
+
surface: tcc.toolName,
|
|
88
|
+
value: deriveDecisionValue(tcc.toolName, check),
|
|
120
89
|
},
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const toolGateHasSession =
|
|
124
|
-
toolGate.action === "allow" && toolGate.sessionApproval !== undefined;
|
|
125
|
-
deps.emitDecision({
|
|
126
|
-
surface: tcc.toolName,
|
|
127
|
-
value: deriveDecisionValue(tcc.toolName, check),
|
|
128
|
-
result: toolGate.action === "allow" ? "allow" : "deny",
|
|
129
|
-
resolution: deriveResolution(
|
|
130
|
-
check.state,
|
|
131
|
-
toolGate.action,
|
|
132
|
-
toolGateHasSession,
|
|
133
|
-
toolCanConfirm,
|
|
134
|
-
toolDecisionAutoApproved,
|
|
135
|
-
),
|
|
136
|
-
origin: check.origin ?? null,
|
|
137
|
-
agentName: tcc.agentName ?? null,
|
|
138
|
-
matchedPattern: check.matchedPattern ?? null,
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
if (toolGate.action === "block") {
|
|
142
|
-
return { action: "block", reason: toolGate.reason };
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
if (toolGate.sessionApproval) {
|
|
146
|
-
deps.approveSessionRule(
|
|
147
|
-
toolGate.sessionApproval.surface,
|
|
148
|
-
toolGate.sessionApproval.pattern,
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return { action: "allow" };
|
|
90
|
+
};
|
|
153
91
|
}
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
|
|
2
|
-
|
|
3
|
-
import type { PermissionPromptDecision } from "../../permission-dialog";
|
|
4
|
-
import type { PermissionDecisionEvent } from "../../permission-events";
|
|
5
|
-
import type { Rule } from "../../rule";
|
|
6
|
-
import type { SkillPromptEntry } from "../../skill-prompt-sanitizer";
|
|
7
|
-
import type { PermissionCheckResult } from "../../types";
|
|
8
|
-
import type { PromptPermissionDetails } from "../types";
|
|
9
|
-
|
|
10
1
|
/** Outcome of a single permission gate evaluation. */
|
|
11
2
|
export type GateOutcome =
|
|
12
3
|
| { action: "allow" }
|
|
@@ -20,71 +11,3 @@ export interface ToolCallContext {
|
|
|
20
11
|
toolCallId: string;
|
|
21
12
|
cwd: string | undefined;
|
|
22
13
|
}
|
|
23
|
-
|
|
24
|
-
// ── Per-gate narrow dependency interfaces ──────────────────────────────────
|
|
25
|
-
|
|
26
|
-
/** Narrow deps for evaluateToolGate — every field is a leaf method. */
|
|
27
|
-
export interface ToolGateDeps {
|
|
28
|
-
checkPermission(
|
|
29
|
-
surface: string,
|
|
30
|
-
input: unknown,
|
|
31
|
-
agentName?: string,
|
|
32
|
-
sessionRules?: Rule[],
|
|
33
|
-
): PermissionCheckResult;
|
|
34
|
-
getSessionRuleset(): Rule[];
|
|
35
|
-
approveSessionRule(surface: string, pattern: string): void;
|
|
36
|
-
writeReviewLog(event: string, details: Record<string, unknown>): void;
|
|
37
|
-
emitDecision(event: PermissionDecisionEvent): void;
|
|
38
|
-
canConfirm(): boolean;
|
|
39
|
-
promptPermission(
|
|
40
|
-
details: PromptPermissionDetails,
|
|
41
|
-
): Promise<PermissionPromptDecision>;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** Narrow deps for evaluateExternalDirectoryGate. */
|
|
45
|
-
export interface ExternalDirectoryGateDeps {
|
|
46
|
-
checkPermission(
|
|
47
|
-
surface: string,
|
|
48
|
-
input: unknown,
|
|
49
|
-
agentName?: string,
|
|
50
|
-
sessionRules?: Rule[],
|
|
51
|
-
): PermissionCheckResult;
|
|
52
|
-
getSessionRuleset(): Rule[];
|
|
53
|
-
approveSessionRule(surface: string, pattern: string): void;
|
|
54
|
-
writeReviewLog(event: string, details: Record<string, unknown>): void;
|
|
55
|
-
emitDecision(event: PermissionDecisionEvent): void;
|
|
56
|
-
canConfirm(): boolean;
|
|
57
|
-
promptPermission(
|
|
58
|
-
details: PromptPermissionDetails,
|
|
59
|
-
): Promise<PermissionPromptDecision>;
|
|
60
|
-
/** Resolved infrastructure dirs (static + config-based). */
|
|
61
|
-
getInfrastructureDirs(): string[];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Narrow deps for evaluateBashExternalDirectoryGate. */
|
|
65
|
-
export interface BashExternalDirectoryGateDeps {
|
|
66
|
-
checkPermission(
|
|
67
|
-
surface: string,
|
|
68
|
-
input: unknown,
|
|
69
|
-
agentName?: string,
|
|
70
|
-
sessionRules?: Rule[],
|
|
71
|
-
): PermissionCheckResult;
|
|
72
|
-
getSessionRuleset(): Rule[];
|
|
73
|
-
approveSessionRule(surface: string, pattern: string): void;
|
|
74
|
-
writeReviewLog(event: string, details: Record<string, unknown>): void;
|
|
75
|
-
canConfirm(): boolean;
|
|
76
|
-
promptPermission(
|
|
77
|
-
details: PromptPermissionDetails,
|
|
78
|
-
): Promise<PermissionPromptDecision>;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/** Narrow deps for evaluateSkillReadGate. */
|
|
82
|
-
export interface SkillReadGateDeps {
|
|
83
|
-
getActiveSkillEntries(): SkillPromptEntry[];
|
|
84
|
-
writeReviewLog(event: string, details: Record<string, unknown>): void;
|
|
85
|
-
emitDecision(event: PermissionDecisionEvent): void;
|
|
86
|
-
canConfirm(): boolean;
|
|
87
|
-
promptPermission(
|
|
88
|
-
details: PromptPermissionDetails,
|
|
89
|
-
): Promise<PermissionPromptDecision>;
|
|
90
|
-
}
|