@llblab/pi-actors 0.38.0 → 0.38.1
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 +5 -0
- package/dist/lib/recipes-discovery.d.ts +1 -0
- package/dist/lib/recipes-discovery.js +48 -7
- package/dist/skills/actors/SKILL.md +1 -1
- package/dist/skills/swarm/SKILL.md +1 -1
- package/lib/recipes-discovery.ts +61 -11
- package/package.json +1 -1
- package/skills/actors/SKILL.md +1 -1
- package/skills/swarm/SKILL.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.38.1: Windows Recipe ACL Hotfix
|
|
6
|
+
|
|
7
|
+
- `[Registry]` Replaced POSIX mode-bit recipe-root writability checks on Windows with ACL-aware diagnostics, avoiding false `world-writable` and `group-writable` startup warnings from Node's NTFS mode emulation while still flagging broad Windows write grants.
|
|
8
|
+
- `[Tests]` Added portable coverage for broad Windows ACL parsing and skipped the POSIX chmod diagnostic regression on Windows.
|
|
9
|
+
|
|
5
10
|
## 0.38.0: Review Swarm Pipeline Hardening
|
|
6
11
|
|
|
7
12
|
- `[Recipes]` Added current model/thinking inheritance for packaged review/lens-swarm recipes through `{current_model}` and `{current_thinking}`, so normal subagent review swarms use the selected Pi session policy by default while explicit args still override it.
|
|
@@ -45,6 +45,7 @@ export interface RecipesDiscoverySource {
|
|
|
45
45
|
defaultTool?: boolean;
|
|
46
46
|
mutableUsage?: boolean;
|
|
47
47
|
}
|
|
48
|
+
export declare function hasBroadWindowsWriteAcl(icaclsOutput: string): boolean;
|
|
48
49
|
export declare function discoverRecipeSources(sources: RecipesDiscoverySource[]): RecipesDiscoveryResult;
|
|
49
50
|
export declare function discoverRecipes(roots: string[]): RecipesDiscoveryResult;
|
|
50
51
|
export declare function createRecipeIntegrityManifest(result: RecipesDiscoveryResult): RecipeIntegrityManifestEntry[];
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* Zones: recipe discovery, tool exposure, registry diagnostics
|
|
4
4
|
* Owns filename identity discovery across prioritized recipe roots
|
|
5
5
|
*/
|
|
6
|
+
import { execFileSync } from "node:child_process";
|
|
6
7
|
import { createHash } from "node:crypto";
|
|
7
8
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
8
9
|
import { join } from "node:path";
|
|
@@ -140,6 +141,50 @@ function filesForSource(source) {
|
|
|
140
141
|
}))
|
|
141
142
|
: [];
|
|
142
143
|
}
|
|
144
|
+
const WINDOWS_BROAD_WRITE_PRINCIPALS = [
|
|
145
|
+
"Everyone",
|
|
146
|
+
"BUILTIN\\Users",
|
|
147
|
+
"Authenticated Users",
|
|
148
|
+
"S-1-1-0",
|
|
149
|
+
"S-1-5-11",
|
|
150
|
+
"S-1-5-32-545",
|
|
151
|
+
];
|
|
152
|
+
const WINDOWS_WRITE_ACL_PATTERN = /\((?:[^)]*,)?(?:F|M|W|WD|AD|DC|GA|GW)(?:,[^)]*)?\)/i;
|
|
153
|
+
export function hasBroadWindowsWriteAcl(icaclsOutput) {
|
|
154
|
+
return icaclsOutput
|
|
155
|
+
.split(/\r?\n/)
|
|
156
|
+
.some((line) => WINDOWS_BROAD_WRITE_PRINCIPALS.some((principal) => line.includes(principal)) && WINDOWS_WRITE_ACL_PATTERN.test(line));
|
|
157
|
+
}
|
|
158
|
+
function getWindowsRecipeRootDiagnostics(root) {
|
|
159
|
+
try {
|
|
160
|
+
const output = execFileSync("icacls", [root], {
|
|
161
|
+
encoding: "utf8",
|
|
162
|
+
windowsHide: true,
|
|
163
|
+
timeout: 5000,
|
|
164
|
+
});
|
|
165
|
+
if (!hasBroadWindowsWriteAcl(output))
|
|
166
|
+
return [];
|
|
167
|
+
return [
|
|
168
|
+
`Recipe root grants write access to broad Windows principals; review ACLs: ${root}`,
|
|
169
|
+
];
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
return [
|
|
173
|
+
`Failed to inspect Windows ACL for recipe root ${root}: ${error instanceof Error ? error.message : String(error)}`,
|
|
174
|
+
];
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
function getPosixRecipeRootDiagnostics(root) {
|
|
178
|
+
const diagnostics = [];
|
|
179
|
+
const stat = statSync(root);
|
|
180
|
+
if ((stat.mode & 0o002) !== 0) {
|
|
181
|
+
diagnostics.push(`Recipe root is world-writable; review permissions: ${root}`);
|
|
182
|
+
}
|
|
183
|
+
if ((stat.mode & 0o020) !== 0) {
|
|
184
|
+
diagnostics.push(`Recipe root is group-writable; review ownership and permissions: ${root}`);
|
|
185
|
+
}
|
|
186
|
+
return diagnostics;
|
|
187
|
+
}
|
|
143
188
|
function getRecipeRootDiagnostics(sources) {
|
|
144
189
|
const diagnostics = [];
|
|
145
190
|
const roots = new Set(sources
|
|
@@ -149,13 +194,9 @@ function getRecipeRootDiagnostics(sources) {
|
|
|
149
194
|
try {
|
|
150
195
|
if (!existsSync(root))
|
|
151
196
|
continue;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
if ((stat.mode & 0o020) !== 0) {
|
|
157
|
-
diagnostics.push(`Recipe root is group-writable; review ownership and permissions: ${root}`);
|
|
158
|
-
}
|
|
197
|
+
diagnostics.push(...(process.platform === "win32"
|
|
198
|
+
? getWindowsRecipeRootDiagnostics(root)
|
|
199
|
+
: getPosixRecipeRootDiagnostics(root)));
|
|
159
200
|
}
|
|
160
201
|
catch (error) {
|
|
161
202
|
diagnostics.push(`Failed to inspect recipe root ${root}: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: actors
|
|
3
3
|
description: Required practical guide for non-trivial pi-actors use. Read before using or changing spawn, message, inspect, actor runs, tools, recipes, command templates, async lifecycle, mailboxes, artifacts, and local orchestration mechanics.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.38.
|
|
5
|
+
version: 0.38.1
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Actors (pi-actors)
|
package/lib/recipes-discovery.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Owns filename identity discovery across prioritized recipe roots
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { execFileSync } from "node:child_process";
|
|
7
8
|
import { createHash } from "node:crypto";
|
|
8
9
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
9
10
|
import { join } from "node:path";
|
|
@@ -234,6 +235,61 @@ function filesForSource(source: RecipesDiscoverySource): Array<{
|
|
|
234
235
|
: [];
|
|
235
236
|
}
|
|
236
237
|
|
|
238
|
+
const WINDOWS_BROAD_WRITE_PRINCIPALS = [
|
|
239
|
+
"Everyone",
|
|
240
|
+
"BUILTIN\\Users",
|
|
241
|
+
"Authenticated Users",
|
|
242
|
+
"S-1-1-0",
|
|
243
|
+
"S-1-5-11",
|
|
244
|
+
"S-1-5-32-545",
|
|
245
|
+
];
|
|
246
|
+
|
|
247
|
+
const WINDOWS_WRITE_ACL_PATTERN = /\((?:[^)]*,)?(?:F|M|W|WD|AD|DC|GA|GW)(?:,[^)]*)?\)/i;
|
|
248
|
+
|
|
249
|
+
export function hasBroadWindowsWriteAcl(icaclsOutput: string): boolean {
|
|
250
|
+
return icaclsOutput
|
|
251
|
+
.split(/\r?\n/)
|
|
252
|
+
.some((line) =>
|
|
253
|
+
WINDOWS_BROAD_WRITE_PRINCIPALS.some((principal) =>
|
|
254
|
+
line.includes(principal),
|
|
255
|
+
) && WINDOWS_WRITE_ACL_PATTERN.test(line),
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function getWindowsRecipeRootDiagnostics(root: string): string[] {
|
|
260
|
+
try {
|
|
261
|
+
const output = execFileSync("icacls", [root], {
|
|
262
|
+
encoding: "utf8",
|
|
263
|
+
windowsHide: true,
|
|
264
|
+
timeout: 5000,
|
|
265
|
+
});
|
|
266
|
+
if (!hasBroadWindowsWriteAcl(output)) return [];
|
|
267
|
+
return [
|
|
268
|
+
`Recipe root grants write access to broad Windows principals; review ACLs: ${root}`,
|
|
269
|
+
];
|
|
270
|
+
} catch (error) {
|
|
271
|
+
return [
|
|
272
|
+
`Failed to inspect Windows ACL for recipe root ${root}: ${error instanceof Error ? error.message : String(error)}`,
|
|
273
|
+
];
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function getPosixRecipeRootDiagnostics(root: string): string[] {
|
|
278
|
+
const diagnostics: string[] = [];
|
|
279
|
+
const stat = statSync(root);
|
|
280
|
+
if ((stat.mode & 0o002) !== 0) {
|
|
281
|
+
diagnostics.push(
|
|
282
|
+
`Recipe root is world-writable; review permissions: ${root}`,
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
if ((stat.mode & 0o020) !== 0) {
|
|
286
|
+
diagnostics.push(
|
|
287
|
+
`Recipe root is group-writable; review ownership and permissions: ${root}`,
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
return diagnostics;
|
|
291
|
+
}
|
|
292
|
+
|
|
237
293
|
function getRecipeRootDiagnostics(sources: RecipesDiscoverySource[]): string[] {
|
|
238
294
|
const diagnostics: string[] = [];
|
|
239
295
|
const roots = new Set(
|
|
@@ -244,17 +300,11 @@ function getRecipeRootDiagnostics(sources: RecipesDiscoverySource[]): string[] {
|
|
|
244
300
|
for (const root of roots) {
|
|
245
301
|
try {
|
|
246
302
|
if (!existsSync(root)) continue;
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
}
|
|
253
|
-
if ((stat.mode & 0o020) !== 0) {
|
|
254
|
-
diagnostics.push(
|
|
255
|
-
`Recipe root is group-writable; review ownership and permissions: ${root}`,
|
|
256
|
-
);
|
|
257
|
-
}
|
|
303
|
+
diagnostics.push(
|
|
304
|
+
...(process.platform === "win32"
|
|
305
|
+
? getWindowsRecipeRootDiagnostics(root)
|
|
306
|
+
: getPosixRecipeRootDiagnostics(root)),
|
|
307
|
+
);
|
|
258
308
|
} catch (error) {
|
|
259
309
|
diagnostics.push(
|
|
260
310
|
`Failed to inspect recipe root ${root}: ${error instanceof Error ? error.message : String(error)}`,
|
package/package.json
CHANGED
package/skills/actors/SKILL.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: actors
|
|
3
3
|
description: Required practical guide for non-trivial pi-actors use. Read before using or changing spawn, message, inspect, actor runs, tools, recipes, command templates, async lifecycle, mailboxes, artifacts, and local orchestration mechanics.
|
|
4
4
|
metadata:
|
|
5
|
-
version: 0.38.
|
|
5
|
+
version: 0.38.1
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Actors (pi-actors)
|
package/skills/swarm/SKILL.md
CHANGED