@gotgenes/pi-permission-system 18.1.0 → 18.1.2
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 +23 -0
- package/docs/assets/logo.png +0 -0
- package/docs/assets/logo.svg +213 -0
- package/docs/configuration.md +700 -0
- package/docs/cross-extension-api.md +525 -0
- package/docs/guides/permission-frontmatter-for-subagent-extensions.md +201 -0
- package/docs/guides/upstream-issue-template.md +113 -0
- package/docs/migration/legacy-to-flat.md +365 -0
- package/docs/opencode-compatibility.md +213 -0
- package/docs/session-approvals.md +68 -0
- package/docs/subagent-integration.md +102 -0
- package/docs/troubleshooting.md +53 -0
- package/package.json +5 -2
- package/src/access-intent/access-path.ts +29 -4
- package/src/access-intent/bash/bash-path-resolver.ts +39 -18
- package/src/access-intent/bash/msys-bash-tokens.ts +64 -0
- package/src/path-normalizer.ts +105 -2
- package/test/access-intent/access-path.test.ts +0 -277
- package/test/access-intent/bash/node-text.test.ts +0 -148
- package/test/access-intent/bash/parser.test.ts +0 -19
- package/test/access-intent/bash/program.test.ts +0 -673
- package/test/access-intent/bash/token-classification.test.ts +0 -363
- package/test/access-intent/bash/token-collection.test.ts +0 -300
- package/test/active-agent.test.ts +0 -155
- package/test/async-cache.test.ts +0 -48
- package/test/bash-arity.test.ts +0 -144
- package/test/bash-external-directory.test.ts +0 -1022
- package/test/builtin-tool-input-formatters.test.ts +0 -109
- package/test/canonicalize-path.test.ts +0 -119
- package/test/composition-root.test.ts +0 -698
- package/test/config-loader.test.ts +0 -740
- package/test/config-modal.test.ts +0 -320
- package/test/config-paths.test.ts +0 -83
- package/test/config-pipeline.test.ts +0 -90
- package/test/config-reporter.test.ts +0 -147
- package/test/config-store.test.ts +0 -466
- package/test/decision-audit.test.ts +0 -72
- package/test/decision-reporter.test.ts +0 -112
- package/test/denial-messages.test.ts +0 -714
- package/test/detect-permissive-bash-fallback.test.ts +0 -56
- package/test/expand-home.test.ts +0 -93
- package/test/extension-config.test.ts +0 -129
- package/test/extension-paths.test.ts +0 -108
- package/test/forwarded-permissions/io.test.ts +0 -251
- package/test/forwarding-manager.test.ts +0 -200
- package/test/handlers/before-agent-start.test.ts +0 -314
- package/test/handlers/external-directory-integration.test.ts +0 -515
- package/test/handlers/external-directory-session-dedup.test.ts +0 -175
- package/test/handlers/external-directory-symlink-acceptance.test.ts +0 -167
- package/test/handlers/gates/bash-command-metamorphic.test.ts +0 -88
- package/test/handlers/gates/bash-command.test.ts +0 -257
- package/test/handlers/gates/bash-external-directory.test.ts +0 -268
- package/test/handlers/gates/bash-path.test.ts +0 -346
- package/test/handlers/gates/candidate-check.test.ts +0 -52
- package/test/handlers/gates/external-directory-messages.test.ts +0 -85
- package/test/handlers/gates/external-directory-policy.test.ts +0 -134
- package/test/handlers/gates/external-directory.test.ts +0 -267
- package/test/handlers/gates/helpers.test.ts +0 -165
- package/test/handlers/gates/path.test.ts +0 -369
- package/test/handlers/gates/runner.test.ts +0 -408
- package/test/handlers/gates/skill-input-gate-pipeline.test.ts +0 -176
- package/test/handlers/gates/skill-input.test.ts +0 -128
- package/test/handlers/gates/skill-read.test.ts +0 -161
- package/test/handlers/gates/tool-call-gate-pipeline.test.ts +0 -356
- package/test/handlers/gates/tool.test.ts +0 -244
- package/test/handlers/input-events.test.ts +0 -168
- package/test/handlers/input.test.ts +0 -199
- package/test/handlers/lifecycle.test.ts +0 -221
- package/test/handlers/tool-call-boundary.test.ts +0 -145
- package/test/handlers/tool-call-events.test.ts +0 -277
- package/test/handlers/tool-call.test.ts +0 -395
- package/test/handlers/validate-requested-tool.test.ts +0 -92
- package/test/helpers/external-directory-fixtures.ts +0 -269
- package/test/helpers/gate-fixtures.ts +0 -316
- package/test/helpers/handler-fixtures.ts +0 -335
- package/test/helpers/make-fake-pi.ts +0 -100
- package/test/helpers/manager-harness.ts +0 -112
- package/test/helpers/session-fixtures.ts +0 -199
- package/test/input-normalizer.test.ts +0 -325
- package/test/logging.test.ts +0 -51
- package/test/mcp-targets.test.ts +0 -233
- package/test/node-modules-discovery.test.ts +0 -97
- package/test/normalize.test.ts +0 -247
- package/test/path-containment.test.ts +0 -161
- package/test/path-normalization.test.ts +0 -233
- package/test/path-normalizer.test.ts +0 -196
- package/test/path-surfaces.test.ts +0 -55
- package/test/pattern-suggest.test.ts +0 -248
- package/test/permission-dialog.test.ts +0 -205
- package/test/permission-event-rpc.test.ts +0 -560
- package/test/permission-events.test.ts +0 -400
- package/test/permission-forwarder.test.ts +0 -370
- package/test/permission-forwarding.test.ts +0 -315
- package/test/permission-gate.test.ts +0 -269
- package/test/permission-manager-unified.test.ts +0 -3714
- package/test/permission-merge.test.ts +0 -61
- package/test/permission-prompter.test.ts +0 -518
- package/test/permission-prompts.test.ts +0 -363
- package/test/permission-resolver.test.ts +0 -277
- package/test/permission-session.test.ts +0 -404
- package/test/permission-ui-prompt.test.ts +0 -146
- package/test/permissions-service.test.ts +0 -192
- package/test/pi-infrastructure-read.test.ts +0 -432
- package/test/policy-loader.test.ts +0 -561
- package/test/prompting-gateway.test.ts +0 -231
- package/test/rule.test.ts +0 -650
- package/test/safe-system-paths.test.ts +0 -46
- package/test/scope-merge.test.ts +0 -116
- package/test/service-lifecycle.test.ts +0 -163
- package/test/service.test.ts +0 -261
- package/test/session-approval.test.ts +0 -75
- package/test/session-logger.test.ts +0 -200
- package/test/session-rules.test.ts +0 -321
- package/test/session-start.test.ts +0 -112
- package/test/skill-prompt-sanitizer.test.ts +0 -418
- package/test/status.test.ts +0 -10
- package/test/subagent-context.test.ts +0 -372
- package/test/subagent-lifecycle-events.test.ts +0 -132
- package/test/subagent-registry.test.ts +0 -145
- package/test/synthesize.test.ts +0 -302
- package/test/system-prompt-sanitizer.test.ts +0 -382
- package/test/tool-access-extractor-registry.test.ts +0 -77
- package/test/tool-input-formatter-registry.test.ts +0 -75
- package/test/tool-input-path.test.ts +0 -84
- package/test/tool-input-preview.test.ts +0 -129
- package/test/tool-input-prompt-formatters.test.ts +0 -115
- package/test/tool-preview-formatter.test.ts +0 -458
- package/test/tool-registry.test.ts +0 -197
- package/test/value-guards.test.ts +0 -193
- package/test/wildcard-matcher.test.ts +0 -424
- package/test/yaml-frontmatter.test.ts +0 -91
- package/test/yolo-mode.test.ts +0 -188
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { extractFrontmatter, parseSimpleYamlMap } from "#src/yaml-frontmatter";
|
|
4
|
-
|
|
5
|
-
describe("extractFrontmatter", () => {
|
|
6
|
-
test("returns empty string when no frontmatter delimiter", () => {
|
|
7
|
-
expect(extractFrontmatter("# Hello\nSome content")).toBe("");
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
test("returns empty string when only opening delimiter with no closing", () => {
|
|
11
|
-
expect(extractFrontmatter("---\nkey: value")).toBe("");
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test("returns frontmatter body between delimiters", () => {
|
|
15
|
-
const markdown = "---\nissue: 1\ntitle: Test\n---\n# Content";
|
|
16
|
-
expect(extractFrontmatter(markdown)).toBe("issue: 1\ntitle: Test");
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test("returns empty string when file does not start with ---", () => {
|
|
20
|
-
expect(extractFrontmatter("content\n---\nkey: val\n---")).toBe("");
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
test("handles CRLF line endings", () => {
|
|
24
|
-
const markdown = "---\r\nissue: 5\r\n---\r\n# Content";
|
|
25
|
-
expect(extractFrontmatter(markdown)).toBe("issue: 5");
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test("returns empty string for empty string input", () => {
|
|
29
|
-
expect(extractFrontmatter("")).toBe("");
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("returns empty frontmatter for --- \\n--- with nothing between", () => {
|
|
33
|
-
const markdown = "---\n---\n# Content";
|
|
34
|
-
expect(extractFrontmatter(markdown)).toBe("");
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
describe("parseSimpleYamlMap", () => {
|
|
39
|
-
test("returns empty object for empty string", () => {
|
|
40
|
-
expect(parseSimpleYamlMap("")).toEqual({});
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test("parses simple key-value pairs", () => {
|
|
44
|
-
const yaml = "issue: 21\ntitle: Test";
|
|
45
|
-
expect(parseSimpleYamlMap(yaml)).toEqual({ issue: "21", title: "Test" });
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test("strips surrounding quotes from values", () => {
|
|
49
|
-
const yaml = 'title: "My Title"';
|
|
50
|
-
expect(parseSimpleYamlMap(yaml)).toEqual({ title: "My Title" });
|
|
51
|
-
|
|
52
|
-
const yaml2 = "title: 'My Title'";
|
|
53
|
-
expect(parseSimpleYamlMap(yaml2)).toEqual({ title: "My Title" });
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test("skips lines without colon or with colon at position 0", () => {
|
|
57
|
-
const yaml = "no separator here\n:starts-with-colon: val\nkey: val";
|
|
58
|
-
const result = parseSimpleYamlMap(yaml);
|
|
59
|
-
expect(result.key).toBe("val");
|
|
60
|
-
expect(result["no separator here"]).toBeUndefined();
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("skips comment lines", () => {
|
|
64
|
-
const yaml = "# This is a comment\nkey: value";
|
|
65
|
-
expect(parseSimpleYamlMap(yaml)).toEqual({ key: "value" });
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("skips blank lines", () => {
|
|
69
|
-
const yaml = "\n\nkey: value\n\n";
|
|
70
|
-
expect(parseSimpleYamlMap(yaml)).toEqual({ key: "value" });
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test("parses nested map (child indented under parent)", () => {
|
|
74
|
-
const yaml = "parent:\n child: nested_value";
|
|
75
|
-
const result = parseSimpleYamlMap(yaml);
|
|
76
|
-
expect(result.parent).toEqual({ child: "nested_value" });
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test("handles multi-line values correctly (second line is new key)", () => {
|
|
80
|
-
const yaml = "key1: val1\nkey2: val2";
|
|
81
|
-
const result = parseSimpleYamlMap(yaml);
|
|
82
|
-
expect(result.key1).toBe("val1");
|
|
83
|
-
expect(result.key2).toBe("val2");
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
test("strips quotes from keys", () => {
|
|
87
|
-
const yaml = '"quoted-key": value';
|
|
88
|
-
const result = parseSimpleYamlMap(yaml);
|
|
89
|
-
expect(result["quoted-key"]).toBe("value");
|
|
90
|
-
});
|
|
91
|
-
});
|
package/test/yolo-mode.test.ts
DELETED
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, test, vi } from "vitest";
|
|
2
|
-
import type { PermissionSystemExtensionConfig } from "#src/extension-config";
|
|
3
|
-
import { DEFAULT_EXTENSION_CONFIG } from "#src/extension-config";
|
|
4
|
-
import { resolvePermissionForwardingTargetSessionId } from "#src/permission-forwarding";
|
|
5
|
-
import {
|
|
6
|
-
canResolveAskPermissionRequest,
|
|
7
|
-
shouldAutoApprovePermissionState,
|
|
8
|
-
} from "#src/yolo-mode";
|
|
9
|
-
|
|
10
|
-
afterEach(() => {
|
|
11
|
-
vi.restoreAllMocks();
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
function makeConfig(
|
|
15
|
-
yoloMode: boolean | undefined,
|
|
16
|
-
): PermissionSystemExtensionConfig {
|
|
17
|
-
return { yoloMode } as PermissionSystemExtensionConfig;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
describe("shouldAutoApprovePermissionState", () => {
|
|
21
|
-
test("returns true for 'ask' when yolo mode is on", () => {
|
|
22
|
-
expect(shouldAutoApprovePermissionState("ask", makeConfig(true))).toBe(
|
|
23
|
-
true,
|
|
24
|
-
);
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test("returns false for 'ask' when yolo mode is off", () => {
|
|
28
|
-
expect(shouldAutoApprovePermissionState("ask", makeConfig(false))).toBe(
|
|
29
|
-
false,
|
|
30
|
-
);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test("returns false for 'ask' when yolo mode is undefined", () => {
|
|
34
|
-
expect(shouldAutoApprovePermissionState("ask", makeConfig(undefined))).toBe(
|
|
35
|
-
false,
|
|
36
|
-
);
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test("returns false for 'allow' even when yolo mode is on", () => {
|
|
40
|
-
expect(shouldAutoApprovePermissionState("allow", makeConfig(true))).toBe(
|
|
41
|
-
false,
|
|
42
|
-
);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
test("returns false for 'deny' even when yolo mode is on", () => {
|
|
46
|
-
expect(shouldAutoApprovePermissionState("deny", makeConfig(true))).toBe(
|
|
47
|
-
false,
|
|
48
|
-
);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe("canResolveAskPermissionRequest", () => {
|
|
53
|
-
test("returns true when hasUI is true regardless of other flags", () => {
|
|
54
|
-
expect(
|
|
55
|
-
canResolveAskPermissionRequest({
|
|
56
|
-
config: makeConfig(false),
|
|
57
|
-
hasUI: true,
|
|
58
|
-
isSubagent: false,
|
|
59
|
-
}),
|
|
60
|
-
).toBe(true);
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
test("returns true when isSubagent is true regardless of other flags", () => {
|
|
64
|
-
expect(
|
|
65
|
-
canResolveAskPermissionRequest({
|
|
66
|
-
config: makeConfig(false),
|
|
67
|
-
hasUI: false,
|
|
68
|
-
isSubagent: true,
|
|
69
|
-
}),
|
|
70
|
-
).toBe(true);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test("returns true when yolo mode is on regardless of UI/subagent flags", () => {
|
|
74
|
-
expect(
|
|
75
|
-
canResolveAskPermissionRequest({
|
|
76
|
-
config: makeConfig(true),
|
|
77
|
-
hasUI: false,
|
|
78
|
-
isSubagent: false,
|
|
79
|
-
}),
|
|
80
|
-
).toBe(true);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test("returns false when no UI, not a subagent, and yolo mode is off", () => {
|
|
84
|
-
expect(
|
|
85
|
-
canResolveAskPermissionRequest({
|
|
86
|
-
config: makeConfig(false),
|
|
87
|
-
hasUI: false,
|
|
88
|
-
isSubagent: false,
|
|
89
|
-
}),
|
|
90
|
-
).toBe(false);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test("returns false when no UI, not a subagent, and yolo mode is undefined", () => {
|
|
94
|
-
expect(
|
|
95
|
-
canResolveAskPermissionRequest({
|
|
96
|
-
config: makeConfig(undefined),
|
|
97
|
-
hasUI: false,
|
|
98
|
-
isSubagent: false,
|
|
99
|
-
}),
|
|
100
|
-
).toBe(false);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test("returns true when all three conditions are true", () => {
|
|
104
|
-
expect(
|
|
105
|
-
canResolveAskPermissionRequest({
|
|
106
|
-
config: makeConfig(true),
|
|
107
|
-
hasUI: true,
|
|
108
|
-
isSubagent: true,
|
|
109
|
-
}),
|
|
110
|
-
).toBe(true);
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// ---------------------------------------------------------------------------
|
|
115
|
-
// Moved from permission-system.test.ts catch-all (#342)
|
|
116
|
-
// ---------------------------------------------------------------------------
|
|
117
|
-
|
|
118
|
-
test("Yolo mode only auto-approves ask-state permissions", () => {
|
|
119
|
-
expect(
|
|
120
|
-
shouldAutoApprovePermissionState("ask", DEFAULT_EXTENSION_CONFIG),
|
|
121
|
-
).toBe(false);
|
|
122
|
-
expect(
|
|
123
|
-
shouldAutoApprovePermissionState("ask", {
|
|
124
|
-
...DEFAULT_EXTENSION_CONFIG,
|
|
125
|
-
yoloMode: true,
|
|
126
|
-
}),
|
|
127
|
-
).toBe(true);
|
|
128
|
-
expect(
|
|
129
|
-
shouldAutoApprovePermissionState("deny", {
|
|
130
|
-
...DEFAULT_EXTENSION_CONFIG,
|
|
131
|
-
yoloMode: true,
|
|
132
|
-
}),
|
|
133
|
-
).toBe(false);
|
|
134
|
-
expect(
|
|
135
|
-
shouldAutoApprovePermissionState("allow", {
|
|
136
|
-
...DEFAULT_EXTENSION_CONFIG,
|
|
137
|
-
yoloMode: true,
|
|
138
|
-
}),
|
|
139
|
-
).toBe(false);
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
test("Yolo mode resolves ask permissions without UI or delegation forwarding", () => {
|
|
143
|
-
expect(
|
|
144
|
-
canResolveAskPermissionRequest({
|
|
145
|
-
config: DEFAULT_EXTENSION_CONFIG,
|
|
146
|
-
hasUI: false,
|
|
147
|
-
isSubagent: false,
|
|
148
|
-
}),
|
|
149
|
-
).toBe(false);
|
|
150
|
-
expect(
|
|
151
|
-
canResolveAskPermissionRequest({
|
|
152
|
-
config: { ...DEFAULT_EXTENSION_CONFIG, yoloMode: true },
|
|
153
|
-
hasUI: false,
|
|
154
|
-
isSubagent: false,
|
|
155
|
-
}),
|
|
156
|
-
).toBe(true);
|
|
157
|
-
expect(
|
|
158
|
-
canResolveAskPermissionRequest({
|
|
159
|
-
config: DEFAULT_EXTENSION_CONFIG,
|
|
160
|
-
hasUI: false,
|
|
161
|
-
isSubagent: true,
|
|
162
|
-
}),
|
|
163
|
-
).toBe(true);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
test("Yolo mode bypasses delegated ask routing when no parent forwarding target is available", () => {
|
|
167
|
-
const targetSessionId = resolvePermissionForwardingTargetSessionId({
|
|
168
|
-
hasUI: false,
|
|
169
|
-
isSubagent: true,
|
|
170
|
-
currentSessionId: "child-session",
|
|
171
|
-
env: {},
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
expect(targetSessionId).toBe(null);
|
|
175
|
-
expect(
|
|
176
|
-
canResolveAskPermissionRequest({
|
|
177
|
-
config: { ...DEFAULT_EXTENSION_CONFIG, yoloMode: true },
|
|
178
|
-
hasUI: false,
|
|
179
|
-
isSubagent: true,
|
|
180
|
-
}),
|
|
181
|
-
).toBe(true);
|
|
182
|
-
expect(
|
|
183
|
-
shouldAutoApprovePermissionState("ask", {
|
|
184
|
-
...DEFAULT_EXTENSION_CONFIG,
|
|
185
|
-
yoloMode: true,
|
|
186
|
-
}),
|
|
187
|
-
).toBe(true);
|
|
188
|
-
});
|