@rosetears/aili-pi 0.1.5 → 0.1.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/README.md +14 -8
- package/THIRD_PARTY_NOTICES.md +13 -13
- package/extensions/matrix/index.ts +13 -3
- package/extensions/zentui/config.ts +9 -2
- package/extensions/zentui/extension-status.ts +25 -1
- package/extensions/zentui/gradient.ts +6 -6
- package/licenses/pi-permission-modes-MIT.txt +21 -0
- package/manifests/adapter-evidence.json +10 -9
- package/manifests/live-verification.json +19 -11
- package/manifests/provenance.json +17 -17
- package/manifests/sbom.json +6 -6
- package/manifests/skill-compatibility.json +12 -12
- package/manifests/subagent-provenance.json +13 -3
- package/notices/pi-sakura-cyberdeck-NOTICE.txt +3 -2
- package/package.json +5 -3
- package/scripts/generate-provenance.ts +1 -1
- package/scripts/sync-permission-modes.ts +135 -0
- package/src/runtime/native-integrations.ts +5 -5
- package/src/runtime/package-resolution.ts +8 -0
- package/src/runtime/registry.ts +138 -9
- package/src/runtime/subagents.ts +163 -11
- package/src/vendor/pi-permission-modes/index.ts +692 -0
- package/src/vendor/pi-permission-modes/resolve.ts +142 -0
- package/upstream/pi-permission-modes.lock.json +47 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated AILI adaptation of pi-permission-modes@2.2.0.
|
|
3
|
+
* Source revision: 23d65d10a53b67043cae42322acf9044d6edb196.
|
|
4
|
+
* Regenerate with scripts/sync-permission-modes.ts; do not edit manually.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Resolution engine — turns a (mode, surface, target) into an allow/ask/deny.
|
|
8
|
+
*
|
|
9
|
+
* Two composition rules, mirroring the opencode model:
|
|
10
|
+
* - within a surface's pattern-map: LAST matching pattern wins (so a leading
|
|
11
|
+
* `"*"` sets the default and later specific patterns override it);
|
|
12
|
+
* - across layers (path gate · external_directory · the named surface):
|
|
13
|
+
* MOST-RESTRICTIVE wins (deny > ask > allow).
|
|
14
|
+
*
|
|
15
|
+
* Pure and SDK-free (only `os.homedir()` for `~`/`$HOME` expansion) so the whole
|
|
16
|
+
* matrix is unit-testable. Out-of-project determination is passed in by the
|
|
17
|
+
* caller (computed via paths.isOutside) to keep this module free of fs/symlink
|
|
18
|
+
* concerns.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import os from "node:os";
|
|
22
|
+
import { FILE_SURFACES, type Action, type ModeDef, type Surface, type SurfaceValue } from "pi-permission-modes/src/schema.ts";
|
|
23
|
+
|
|
24
|
+
const RANK: Record<Action, number> = { allow: 0, ask: 1, deny: 2 };
|
|
25
|
+
|
|
26
|
+
/** Expand a leading `~` or `$HOME` to the user's home directory. */
|
|
27
|
+
export function expandHome(s: string): string {
|
|
28
|
+
const home = os.homedir();
|
|
29
|
+
if (s === "~" || s === "$HOME") return home;
|
|
30
|
+
if (s.startsWith("~/")) return home + s.slice(1);
|
|
31
|
+
if (s.startsWith("$HOME/")) return home + s.slice(5);
|
|
32
|
+
return s;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Glob match: `*` matches any run of characters INCLUDING `/` (so `*` is a true
|
|
37
|
+
* universal fallback and `*.md` matches nested paths); `?` matches exactly one
|
|
38
|
+
* character. `~`/`$HOME` are expanded on both pattern and target before matching.
|
|
39
|
+
*/
|
|
40
|
+
export function matchPattern(pattern: string, target: string): boolean {
|
|
41
|
+
const p = expandHome(pattern);
|
|
42
|
+
const t = expandHome(target);
|
|
43
|
+
let re = "^";
|
|
44
|
+
for (const ch of p) {
|
|
45
|
+
if (ch === "*") re += ".*";
|
|
46
|
+
else if (ch === "?") re += ".";
|
|
47
|
+
else re += ch.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
48
|
+
}
|
|
49
|
+
re += "$";
|
|
50
|
+
return new RegExp(re, "s").test(t);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Resolve one surface value against a target. String shorthand returns directly;
|
|
55
|
+
* a pattern-map returns the action of the LAST matching pattern (definition
|
|
56
|
+
* order, via Object.entries — keep pattern keys non-numeric to preserve order).
|
|
57
|
+
* Returns undefined when the surface is absent or nothing matches.
|
|
58
|
+
*/
|
|
59
|
+
export function resolveSurface(value: SurfaceValue | undefined, target: string): Action | undefined {
|
|
60
|
+
if (value === undefined) return undefined;
|
|
61
|
+
if (typeof value === "string") return value;
|
|
62
|
+
let result: Action | undefined;
|
|
63
|
+
for (const [pattern, action] of Object.entries(value)) {
|
|
64
|
+
if (matchPattern(pattern, target)) result = action;
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Most-restrictive of the given actions (deny > ask > allow); undefined ignored. */
|
|
70
|
+
export function mostRestrictive(...actions: (Action | undefined)[]): Action | undefined {
|
|
71
|
+
let best: Action | undefined;
|
|
72
|
+
let bestRank = -1;
|
|
73
|
+
for (const a of actions) {
|
|
74
|
+
if (a === undefined) continue;
|
|
75
|
+
if (RANK[a] > bestRank) {
|
|
76
|
+
best = a;
|
|
77
|
+
bestRank = RANK[a];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return best;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const isFileSurface = (s: Surface): boolean => FILE_SURFACES.includes(s);
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Decide the action for a (surface, target) under a mode. Folds the cross-cutting
|
|
87
|
+
* `path` gate (file surfaces only) and the `external_directory` gate (when the
|
|
88
|
+
* target is outside the project) into the named surface via most-restrictive.
|
|
89
|
+
*
|
|
90
|
+
* `opts.isOutside` — whether `target` resolves outside the project (caller
|
|
91
|
+
* computes via paths.isOutside). `opts.fallback` — the action when no layer
|
|
92
|
+
* matches at all (default "ask", least-privilege; built-in modes always specify
|
|
93
|
+
* a `"*"` so this only affects sparse user-authored modes).
|
|
94
|
+
*/
|
|
95
|
+
export function decide(
|
|
96
|
+
mode: ModeDef,
|
|
97
|
+
surface: Surface,
|
|
98
|
+
target: string,
|
|
99
|
+
opts: { isOutside?: boolean; fallback?: Action } = {},
|
|
100
|
+
): Action {
|
|
101
|
+
const layers: (Action | undefined)[] = [];
|
|
102
|
+
|
|
103
|
+
// The base policy and the project tighten-only overlay are independent sources;
|
|
104
|
+
// composing both with most-restrictive means the overlay can only tighten.
|
|
105
|
+
const sources = mode.projectOverlay ? [mode.permission, mode.projectOverlay] : [mode.permission];
|
|
106
|
+
for (const perm of sources) {
|
|
107
|
+
if (isFileSurface(surface)) layers.push(resolveSurface(perm.path, target));
|
|
108
|
+
if (opts.isOutside) layers.push(resolveSurface(perm.external_directory, target));
|
|
109
|
+
layers.push(resolveSurface(perm[surface], target));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return mostRestrictive(...layers) ?? opts.fallback ?? "ask";
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Decide the action for ONE extracted bash command (the tree-sitter path, where
|
|
117
|
+
* each command in a chain is judged separately). Per source (base policy +
|
|
118
|
+
* project tighten-only overlay), most-restrictive of:
|
|
119
|
+
* - the `bash` surface matched against the joined "name args…" string;
|
|
120
|
+
* - the cross-cutting `path` gate matched against that same joined string
|
|
121
|
+
* (parity with the heuristic fallback, where `decide` folds `path` over the
|
|
122
|
+
* whole command line);
|
|
123
|
+
* - the `path` gate matched against each individual token (name and each
|
|
124
|
+
* arg), so path globs like `*.env` bind bash arguments regardless of where
|
|
125
|
+
* they sit in the command.
|
|
126
|
+
*
|
|
127
|
+
* Returns undefined when no layer matches at all; the caller picks the default
|
|
128
|
+
* (the dispatcher treats a fully-unmatched command as "allow" within a chain,
|
|
129
|
+
* matching resolveSurface semantics for absent surfaces).
|
|
130
|
+
*/
|
|
131
|
+
export function decideBashCommand(mode: ModeDef, name: string, args: string[]): Action | undefined {
|
|
132
|
+
const tokens = [name, ...args];
|
|
133
|
+
const joined = tokens.join(" ").trim();
|
|
134
|
+
const layers: (Action | undefined)[] = [];
|
|
135
|
+
const sources = mode.projectOverlay ? [mode.permission, mode.projectOverlay] : [mode.permission];
|
|
136
|
+
for (const perm of sources) {
|
|
137
|
+
layers.push(resolveSurface(perm.bash, joined));
|
|
138
|
+
layers.push(resolveSurface(perm.path, joined));
|
|
139
|
+
for (const tok of tokens) layers.push(resolveSurface(perm.path, tok));
|
|
140
|
+
}
|
|
141
|
+
return mostRestrictive(...layers);
|
|
142
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"package": {
|
|
4
|
+
"name": "pi-permission-modes",
|
|
5
|
+
"version": "2.2.0",
|
|
6
|
+
"revision": "23d65d10a53b67043cae42322acf9044d6edb196",
|
|
7
|
+
"license": "MIT"
|
|
8
|
+
},
|
|
9
|
+
"upstreamFiles": [
|
|
10
|
+
{
|
|
11
|
+
"path": "src/index.ts",
|
|
12
|
+
"sha256": "fd4462a3b7ba986af734c2e17ba8ea7178df56c933e87ed444ba90ba24c2fd5b"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"path": "src/resolve.ts",
|
|
16
|
+
"sha256": "13f52a4a9c08d7a55f5f9d03f97302d864768838fb3e9fca2051cb7d94a0ae82"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "LICENSE",
|
|
20
|
+
"sha256": "d87cb99b43f6bf8771e57be83485db11b977b9dfa21b6bd201b8d3d370bdce43"
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"adaptedFiles": [
|
|
24
|
+
{
|
|
25
|
+
"path": "src/vendor/pi-permission-modes/index.ts",
|
|
26
|
+
"sha256": "8bfa0364967a2b76e9900cc72b8f434ea1cfa6520899c7827488220f2e288ee8"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"path": "src/vendor/pi-permission-modes/resolve.ts",
|
|
30
|
+
"sha256": "f71688f847495da5122724f75c5ebe3b41066b3d3cac74cbe99f66b9906404f6"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"path": "licenses/pi-permission-modes-MIT.txt",
|
|
34
|
+
"sha256": "d87cb99b43f6bf8771e57be83485db11b977b9dfa21b6bd201b8d3d370bdce43"
|
|
35
|
+
}
|
|
36
|
+
],
|
|
37
|
+
"localChanges": [
|
|
38
|
+
"Package-owned adapted entry redirects all unchanged sibling modules to the exact pi-permission-modes dependency while owning resolve.ts locally.",
|
|
39
|
+
"matchPattern compiles its anchored glob RegExp with dotAll so * and ? include ECMAScript line terminators."
|
|
40
|
+
],
|
|
41
|
+
"generatedBy": "scripts/sync-permission-modes.ts",
|
|
42
|
+
"verification": [
|
|
43
|
+
"npm run verify:permission-modes",
|
|
44
|
+
"tests/unit/permission-patterns.test.ts",
|
|
45
|
+
"tests/integration/permission-modes.test.ts"
|
|
46
|
+
]
|
|
47
|
+
}
|