@llblab/pi-actors 0.53.0 → 0.53.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/AGENTS.md CHANGED
@@ -44,6 +44,8 @@ Pi host
44
44
 
45
45
  `index.ts` wires Pi ports and must not own domain behavior. Keep the local TypeScript import graph acyclic. For architecture-affecting work, load and follow `.agents/skills/domain-dag/SKILL.md`; its validator is local agent tooling, not an npm, CI, or release gate.
46
46
 
47
+ The committed `dist/` tree is required for npm and git package installs. `npm run build` compiles into a temporary candidate and atomically replaces the distributive; `npm run build:check` must reject source/artifact drift without rewriting the working tree.
48
+
47
49
  ## Key Domains
48
50
 
49
51
  - `extension-runtime.ts`: low-level Pi session lifecycle, tool adaptation, and runtime service composition behind the thin `index.ts` event-registration root.
@@ -150,4 +152,5 @@ When deferred Run results gate the next step, wait for their completion batch. I
150
152
  - Before release run the normal product validation and dependency audit. Use the project-local Domain DAG Skill during architecture-affecting development, not as publication automation.
151
153
  - `.github/workflows/release.yml` owns the immutable sequence reusable validation → npm Trusted Publisher publication/verification → GitHub Release convergence; follow [docs/releasing.md](docs/releasing.md).
152
154
  - Keep npm publication tokenless: use the exact npm Trusted Publisher binding and job-scoped OIDC permission, never a long-lived npm token or token fallback.
155
+ - Manifest-loaded packages expose bundled Skills only through `pi.skills`, preserving package resource filters and package-owned provenance. Only a checkout auto-discovered directly below a user or project Pi `extensions/` root may contribute its source Skill root through `resources_discover`; compiled-vs-source filename shape does not determine ownership.
153
156
  - Until a stable version beyond `1.x`, prefer clean breaking simplification over compatibility aliases or renamed legacy abstractions.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  > Each release keeps at most 8 outcome records of at most 512 characters.
4
4
 
5
+ ## Unreleased
6
+
7
+ ## 0.53.1: Filterable Skills and drift-safe Git installs
8
+
9
+ - `Filterable Packaged Skills`: Manifest-loaded runtime leaves all six bundled Skills to `pi.skills`, preserving filters and provenance. Auto-discovered checkouts contribute source Skills even when Pi selects compiled code; resolver regressions cover both modes. Unsupported source manifest aliases are removed, and the committed distributive supports git installs with drift-checking atomic builds.
10
+
5
11
  ## 0.53.0: Tree-Compressed Completion Delivery
6
12
 
7
13
  - `Quiet Draft Reloads`: Keeps automatic Recipe reload active for draft-directory changes while showing “Recipe tools refreshed” only for active non-draft Recipe changes or registry-root replacement, so ordinary spawn draft capture no longer produces misleading tool-refresh noise.
package/README.md CHANGED
@@ -31,7 +31,7 @@ For local development:
31
31
  pi install /path/to/pi-actors
32
32
  ```
33
33
 
34
- The package contributes the extension and six capability-owning Skills for actors, artifacts, music playback, project work, Recipe memory, and swarm orchestration.
34
+ The package contributes the extension and six capability-owning Skills for actors, artifacts, music playback, project work, Recipe memory, and swarm orchestration. Manifest-loaded packages expose those Skills through the package manifest so Pi resource filters and package provenance remain authoritative; a checkout auto-discovered directly under Pi's user or project extensions directory contributes its source Skills even when Pi selects the checkout's compiled entrypoint.
35
35
 
36
36
  ## Public Tools
37
37
 
@@ -238,7 +238,7 @@ npm run validate
238
238
  npm run test:preservation
239
239
  ```
240
240
 
241
- The build produces the JavaScript runtime used by detached Actor processes in npm installations. Pi can load a TypeScript extension entrypoint, but standalone Node processes cannot type-strip modules under `node_modules`; keeping compiled Run modules preserves process isolation without a runtime TypeScript loader.
241
+ The atomic build produces the committed JavaScript runtime used by npm and git installs; `npm run build:check` verifies that `dist/` matches source without rewriting it. Pi can load a TypeScript extension entrypoint, but standalone Node processes cannot type-strip modules under `node_modules`; keeping compiled Run modules preserves process isolation without a runtime TypeScript loader.
242
242
 
243
243
  See the [documentation index](./docs/README.md), [Run lifecycle](./docs/async-runs.md), and [Recipe library](./docs/recipe-library.md).
244
244
 
package/dist/index.js CHANGED
@@ -5,9 +5,12 @@
5
5
  */
6
6
  import * as ExtensionRuntime from "./lib/extension-runtime.js";
7
7
  import * as InspectorCommand from "./lib/inspector-command.js";
8
+ import * as Paths from "./lib/paths.js";
8
9
  export default function toolRegistryExtension(pi) {
9
10
  const runtime = ExtensionRuntime.createActorExtensionRuntime(pi);
10
- pi.on("resources_discover", async () => runtime.discoverResources(import.meta.url));
11
+ if (Paths.isRawExtensionCheckout(import.meta.url)) {
12
+ pi.on("resources_discover", async () => runtime.discoverResources(import.meta.url));
13
+ }
11
14
  pi.on("session_start", async (_event, ctx) => runtime.onSessionStart(ctx));
12
15
  pi.on("agent_settled", async (_event, ctx) => runtime.onAgentSettled(ctx));
13
16
  pi.on("context", async (event, ctx) => ({
@@ -21,6 +21,12 @@ export declare function getToolReviewStatePath(agentDir?: string): string;
21
21
  export declare function getToolReviewBatchDir(reviewId: string, agentDir?: string): string;
22
22
  export declare function getExtensionRuntimePaths(agentDir?: string): ExtensionRuntimePaths;
23
23
  export declare const EXTENSION_RUNTIME_PATHS: ExtensionRuntimePaths;
24
+ export declare function getExtensionPackageRoot(extensionUrl: string): string;
25
+ export interface RawExtensionCheckoutOptions {
26
+ agentDir?: string;
27
+ cwd?: string;
28
+ }
29
+ export declare function isRawExtensionCheckout(extensionUrl: string, options?: RawExtensionCheckoutOptions): boolean;
24
30
  export declare function getExtensionSkillsDir(extensionUrl: string): string;
25
31
  export declare function getExistingExtensionSkillPaths(extensionUrl: string): string[];
26
32
  export declare function getRecipeRoot(agentDir?: string): string;
package/dist/lib/paths.js CHANGED
@@ -57,8 +57,26 @@ export function getExtensionRuntimePaths(agentDir = getAgentDir()) {
57
57
  };
58
58
  }
59
59
  export const EXTENSION_RUNTIME_PATHS = getExtensionRuntimePaths();
60
+ export function getExtensionPackageRoot(extensionUrl) {
61
+ let current = dirname(fileURLToPath(extensionUrl));
62
+ while (true) {
63
+ if (existsSync(join(current, "package.json")))
64
+ return current;
65
+ const parent = dirname(current);
66
+ if (parent === current)
67
+ return dirname(fileURLToPath(extensionUrl));
68
+ current = parent;
69
+ }
70
+ }
71
+ export function isRawExtensionCheckout(extensionUrl, options = {}) {
72
+ const packageRoot = resolve(getExtensionPackageRoot(extensionUrl));
73
+ const agentDir = resolve(options.agentDir ?? getAgentDir());
74
+ const cwd = resolve(options.cwd ?? process.cwd());
75
+ return dirname(packageRoot) === join(agentDir, "extensions") ||
76
+ dirname(packageRoot) === join(cwd, ".pi", "extensions");
77
+ }
60
78
  export function getExtensionSkillsDir(extensionUrl) {
61
- return join(dirname(fileURLToPath(extensionUrl)), "skills");
79
+ return join(getExtensionPackageRoot(extensionUrl), "skills");
62
80
  }
63
81
  export function getExistingExtensionSkillPaths(extensionUrl) {
64
82
  const skillsDir = getExtensionSkillsDir(extensionUrl);
@@ -1,47 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Build the JavaScript-only distributive tree.
5
- *
6
- * This is intentionally standalone: it is package/build glue, not reusable
7
- * actor-domain behavior. It cleans dist, compiles TypeScript, mirrors runtime
8
- * assets, and syntax-checks packaged scripts.
4
+ * Builds or verifies the JavaScript-only distributive tree without exposing a
5
+ * partial tree to Pi or destroying the previous distributive on failure.
9
6
  */
10
7
 
11
8
  import { spawnSync } from "node:child_process";
12
9
  import {
13
10
  cpSync,
11
+ existsSync,
14
12
  mkdirSync,
13
+ mkdtempSync,
14
+ readFileSync,
15
15
  readdirSync,
16
+ renameSync,
16
17
  rmSync,
17
18
  writeFileSync,
18
19
  } from "node:fs";
19
- import { join } from "node:path";
20
+ import { join, relative } from "node:path";
21
+
22
+ const DIST_DIR = "dist";
23
+ const checkOnly = process.argv.includes("--check");
20
24
 
21
25
  function run(command, args) {
22
26
  const result = spawnSync(command, args, { stdio: "inherit" });
23
27
  if (result.error) throw result.error;
24
- if (result.status !== 0) process.exit(result.status ?? 1);
28
+ if (result.status !== 0) {
29
+ throw new Error(`${command} exited with status ${result.status ?? "unknown"}.`);
30
+ }
25
31
  }
26
32
 
27
- rmSync("dist", { recursive: true, force: true });
28
- mkdirSync("dist", { recursive: true });
29
-
30
- run(process.execPath, [
31
- join("node_modules", "typescript", "bin", "tsc"),
32
- "-p",
33
- "tsconfig.build.json",
34
- ]);
35
-
36
- mkdirSync(join("dist", "pi-actors"), { recursive: true });
37
- writeFileSync(
38
- join("dist", "pi-actors", "index.js"),
39
- 'export { default } from "../index.js";\n',
40
- "utf8",
41
- );
42
-
43
- for (const dir of ["scripts", "fixtures", "skills"]) {
44
- cpSync(dir, join("dist", dir), { recursive: true });
33
+ function listFiles(root, current = root) {
34
+ return readdirSync(current, { withFileTypes: true }).flatMap((entry) => {
35
+ const path = join(current, entry.name);
36
+ return entry.isDirectory() ? listFiles(root, path) : [relative(root, path)];
37
+ }).sort();
45
38
  }
46
39
 
47
40
  function listModuleScripts(root) {
@@ -52,9 +45,80 @@ function listModuleScripts(root) {
52
45
  });
53
46
  }
54
47
 
55
- const builtScripts = [
56
- ...listModuleScripts(join("dist", "scripts")),
57
- ...listModuleScripts(join("dist", "skills")),
58
- ];
48
+ function normalizeTextFiles(root) {
49
+ const textSuffixes = [".js", ".ts", ".mjs", ".json", ".md"];
50
+ for (const path of listFiles(root)) {
51
+ if (!textSuffixes.some((suffix) => path.endsWith(suffix))) continue;
52
+ const absolutePath = join(root, path);
53
+ const source = readFileSync(absolutePath, "utf8");
54
+ const normalized = source.replace(/\r\n?/g, "\n");
55
+ if (normalized !== source) writeFileSync(absolutePath, normalized, "utf8");
56
+ }
57
+ }
58
+
59
+ function assertTreesEqual(expectedRoot, actualRoot) {
60
+ if (!existsSync(expectedRoot)) {
61
+ throw new Error(`${expectedRoot} is missing; run npm run build.`);
62
+ }
63
+ const expectedFiles = listFiles(expectedRoot);
64
+ const actualFiles = listFiles(actualRoot);
65
+ if (JSON.stringify(expectedFiles) !== JSON.stringify(actualFiles)) {
66
+ throw new Error("dist file inventory is stale; run npm run build.");
67
+ }
68
+ for (const path of expectedFiles) {
69
+ if (!readFileSync(join(expectedRoot, path)).equals(readFileSync(join(actualRoot, path)))) {
70
+ throw new Error(`dist/${path} is stale; run npm run build.`);
71
+ }
72
+ }
73
+ }
74
+
75
+ function replaceDist(candidate) {
76
+ const backup = `.dist-backup-${process.pid}-${Date.now()}`;
77
+ const hadDist = existsSync(DIST_DIR);
78
+ if (hadDist) renameSync(DIST_DIR, backup);
79
+ try {
80
+ renameSync(candidate, DIST_DIR);
81
+ if (hadDist) rmSync(backup, { recursive: true, force: true });
82
+ } catch (error) {
83
+ if (hadDist && existsSync(backup) && !existsSync(DIST_DIR)) {
84
+ renameSync(backup, DIST_DIR);
85
+ }
86
+ throw error;
87
+ }
88
+ }
59
89
 
60
- run(process.execPath, ["--check", ...builtScripts]);
90
+ const candidate = mkdtempSync(join(process.cwd(), ".dist-build-"));
91
+ try {
92
+ run(process.execPath, [
93
+ join("node_modules", "typescript", "bin", "tsc"),
94
+ "-p",
95
+ "tsconfig.build.json",
96
+ "--outDir",
97
+ candidate,
98
+ ]);
99
+
100
+ mkdirSync(join(candidate, "pi-actors"), { recursive: true });
101
+ writeFileSync(
102
+ join(candidate, "pi-actors", "index.js"),
103
+ 'export { default } from "../index.js";\n',
104
+ "utf8",
105
+ );
106
+ normalizeTextFiles(candidate);
107
+ for (const dir of ["scripts", "fixtures", "skills"]) {
108
+ cpSync(dir, join(candidate, dir), { recursive: true });
109
+ }
110
+ const builtScripts = [
111
+ ...listModuleScripts(join(candidate, "scripts")),
112
+ ...listModuleScripts(join(candidate, "skills")),
113
+ ];
114
+ run(process.execPath, ["--check", ...builtScripts]);
115
+
116
+ if (checkOnly) {
117
+ assertTreesEqual(DIST_DIR, candidate);
118
+ console.log("pi-actors: dist is current");
119
+ } else {
120
+ replaceDist(candidate);
121
+ }
122
+ } finally {
123
+ rmSync(candidate, { recursive: true, force: true });
124
+ }
package/index.ts CHANGED
@@ -6,13 +6,16 @@
6
6
 
7
7
  import * as ExtensionRuntime from "./lib/extension-runtime.ts";
8
8
  import * as InspectorCommand from "./lib/inspector-command.ts";
9
+ import * as Paths from "./lib/paths.ts";
9
10
  import * as Pi from "./lib/pi.ts";
10
11
 
11
12
  export default function toolRegistryExtension(pi: Pi.ExtensionAPI) {
12
13
  const runtime = ExtensionRuntime.createActorExtensionRuntime(pi);
13
- pi.on("resources_discover", async () =>
14
- runtime.discoverResources(import.meta.url),
15
- );
14
+ if (Paths.isRawExtensionCheckout(import.meta.url)) {
15
+ pi.on("resources_discover", async () =>
16
+ runtime.discoverResources(import.meta.url),
17
+ );
18
+ }
16
19
  pi.on("session_start", async (_event, ctx) => runtime.onSessionStart(ctx));
17
20
  pi.on("agent_settled", async (_event, ctx) => runtime.onAgentSettled(ctx));
18
21
  pi.on("context", async (event, ctx) => ({
package/lib/paths.ts CHANGED
@@ -93,8 +93,34 @@ export function getExtensionRuntimePaths(
93
93
 
94
94
  export const EXTENSION_RUNTIME_PATHS = getExtensionRuntimePaths();
95
95
 
96
+ export function getExtensionPackageRoot(extensionUrl: string): string {
97
+ let current = dirname(fileURLToPath(extensionUrl));
98
+ while (true) {
99
+ if (existsSync(join(current, "package.json"))) return current;
100
+ const parent = dirname(current);
101
+ if (parent === current) return dirname(fileURLToPath(extensionUrl));
102
+ current = parent;
103
+ }
104
+ }
105
+
106
+ export interface RawExtensionCheckoutOptions {
107
+ agentDir?: string;
108
+ cwd?: string;
109
+ }
110
+
111
+ export function isRawExtensionCheckout(
112
+ extensionUrl: string,
113
+ options: RawExtensionCheckoutOptions = {},
114
+ ): boolean {
115
+ const packageRoot = resolve(getExtensionPackageRoot(extensionUrl));
116
+ const agentDir = resolve(options.agentDir ?? getAgentDir());
117
+ const cwd = resolve(options.cwd ?? process.cwd());
118
+ return dirname(packageRoot) === join(agentDir, "extensions") ||
119
+ dirname(packageRoot) === join(cwd, ".pi", "extensions");
120
+ }
121
+
96
122
  export function getExtensionSkillsDir(extensionUrl: string): string {
97
- return join(dirname(fileURLToPath(extensionUrl)), "skills");
123
+ return join(getExtensionPackageRoot(extensionUrl), "skills");
98
124
  }
99
125
 
100
126
  export function getExistingExtensionSkillPaths(extensionUrl: string): string[] {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-actors",
3
- "version": "0.53.0",
3
+ "version": "0.53.1",
4
4
  "private": false,
5
5
  "description": "Local Actor Kernel for Pi",
6
6
  "keywords": [
@@ -31,9 +31,10 @@
31
31
  "test:preservation": "node --experimental-strip-types --test --test-concurrency=1 tests/async-runs.test.ts tests/observability.test.ts tests/session-evidence.test.ts tests/inspector-security.test.ts tests/inspector-overlay.test.ts tests/review-control.test.ts",
32
32
  "pack:dry": "npm pack --dry-run",
33
33
  "recipes:qa": "node skills/actors/scripts/validate-recipe.mjs skills --skills --qa --summary",
34
- "validate": "npx tsc --noEmit && npm run recipes:qa && npm run build && npm run check && npm test && npm run conformance && npm run pack:dry",
34
+ "validate": "npx tsc --noEmit && npm run recipes:qa && npm run build:check && npm run check && npm test && npm run conformance && npm run pack:dry",
35
35
  "audit:dependencies": "npm audit --audit-level=high --omit=peer",
36
36
  "build": "node scripts/build-dist.mjs",
37
+ "build:check": "node scripts/build-dist.mjs --check",
37
38
  "prepack": "npm run build"
38
39
  },
39
40
  "files": [
@@ -54,15 +55,9 @@
54
55
  "extensions": [
55
56
  "./dist/pi-actors/index.js"
56
57
  ],
57
- "sourceExtensions": [
58
- "./index.ts"
59
- ],
60
58
  "skills": [
61
59
  "./dist/skills"
62
60
  ],
63
- "sourceSkills": [
64
- "./skills"
65
- ],
66
61
  "image": "https://raw.githubusercontent.com/llblab/pi-actors/main/banner.jpg"
67
62
  },
68
63
  "peerDependencies": {
@@ -1,47 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  /**
4
- * Build the JavaScript-only distributive tree.
5
- *
6
- * This is intentionally standalone: it is package/build glue, not reusable
7
- * actor-domain behavior. It cleans dist, compiles TypeScript, mirrors runtime
8
- * assets, and syntax-checks packaged scripts.
4
+ * Builds or verifies the JavaScript-only distributive tree without exposing a
5
+ * partial tree to Pi or destroying the previous distributive on failure.
9
6
  */
10
7
 
11
8
  import { spawnSync } from "node:child_process";
12
9
  import {
13
10
  cpSync,
11
+ existsSync,
14
12
  mkdirSync,
13
+ mkdtempSync,
14
+ readFileSync,
15
15
  readdirSync,
16
+ renameSync,
16
17
  rmSync,
17
18
  writeFileSync,
18
19
  } from "node:fs";
19
- import { join } from "node:path";
20
+ import { join, relative } from "node:path";
21
+
22
+ const DIST_DIR = "dist";
23
+ const checkOnly = process.argv.includes("--check");
20
24
 
21
25
  function run(command, args) {
22
26
  const result = spawnSync(command, args, { stdio: "inherit" });
23
27
  if (result.error) throw result.error;
24
- if (result.status !== 0) process.exit(result.status ?? 1);
28
+ if (result.status !== 0) {
29
+ throw new Error(`${command} exited with status ${result.status ?? "unknown"}.`);
30
+ }
25
31
  }
26
32
 
27
- rmSync("dist", { recursive: true, force: true });
28
- mkdirSync("dist", { recursive: true });
29
-
30
- run(process.execPath, [
31
- join("node_modules", "typescript", "bin", "tsc"),
32
- "-p",
33
- "tsconfig.build.json",
34
- ]);
35
-
36
- mkdirSync(join("dist", "pi-actors"), { recursive: true });
37
- writeFileSync(
38
- join("dist", "pi-actors", "index.js"),
39
- 'export { default } from "../index.js";\n',
40
- "utf8",
41
- );
42
-
43
- for (const dir of ["scripts", "fixtures", "skills"]) {
44
- cpSync(dir, join("dist", dir), { recursive: true });
33
+ function listFiles(root, current = root) {
34
+ return readdirSync(current, { withFileTypes: true }).flatMap((entry) => {
35
+ const path = join(current, entry.name);
36
+ return entry.isDirectory() ? listFiles(root, path) : [relative(root, path)];
37
+ }).sort();
45
38
  }
46
39
 
47
40
  function listModuleScripts(root) {
@@ -52,9 +45,80 @@ function listModuleScripts(root) {
52
45
  });
53
46
  }
54
47
 
55
- const builtScripts = [
56
- ...listModuleScripts(join("dist", "scripts")),
57
- ...listModuleScripts(join("dist", "skills")),
58
- ];
48
+ function normalizeTextFiles(root) {
49
+ const textSuffixes = [".js", ".ts", ".mjs", ".json", ".md"];
50
+ for (const path of listFiles(root)) {
51
+ if (!textSuffixes.some((suffix) => path.endsWith(suffix))) continue;
52
+ const absolutePath = join(root, path);
53
+ const source = readFileSync(absolutePath, "utf8");
54
+ const normalized = source.replace(/\r\n?/g, "\n");
55
+ if (normalized !== source) writeFileSync(absolutePath, normalized, "utf8");
56
+ }
57
+ }
58
+
59
+ function assertTreesEqual(expectedRoot, actualRoot) {
60
+ if (!existsSync(expectedRoot)) {
61
+ throw new Error(`${expectedRoot} is missing; run npm run build.`);
62
+ }
63
+ const expectedFiles = listFiles(expectedRoot);
64
+ const actualFiles = listFiles(actualRoot);
65
+ if (JSON.stringify(expectedFiles) !== JSON.stringify(actualFiles)) {
66
+ throw new Error("dist file inventory is stale; run npm run build.");
67
+ }
68
+ for (const path of expectedFiles) {
69
+ if (!readFileSync(join(expectedRoot, path)).equals(readFileSync(join(actualRoot, path)))) {
70
+ throw new Error(`dist/${path} is stale; run npm run build.`);
71
+ }
72
+ }
73
+ }
74
+
75
+ function replaceDist(candidate) {
76
+ const backup = `.dist-backup-${process.pid}-${Date.now()}`;
77
+ const hadDist = existsSync(DIST_DIR);
78
+ if (hadDist) renameSync(DIST_DIR, backup);
79
+ try {
80
+ renameSync(candidate, DIST_DIR);
81
+ if (hadDist) rmSync(backup, { recursive: true, force: true });
82
+ } catch (error) {
83
+ if (hadDist && existsSync(backup) && !existsSync(DIST_DIR)) {
84
+ renameSync(backup, DIST_DIR);
85
+ }
86
+ throw error;
87
+ }
88
+ }
59
89
 
60
- run(process.execPath, ["--check", ...builtScripts]);
90
+ const candidate = mkdtempSync(join(process.cwd(), ".dist-build-"));
91
+ try {
92
+ run(process.execPath, [
93
+ join("node_modules", "typescript", "bin", "tsc"),
94
+ "-p",
95
+ "tsconfig.build.json",
96
+ "--outDir",
97
+ candidate,
98
+ ]);
99
+
100
+ mkdirSync(join(candidate, "pi-actors"), { recursive: true });
101
+ writeFileSync(
102
+ join(candidate, "pi-actors", "index.js"),
103
+ 'export { default } from "../index.js";\n',
104
+ "utf8",
105
+ );
106
+ normalizeTextFiles(candidate);
107
+ for (const dir of ["scripts", "fixtures", "skills"]) {
108
+ cpSync(dir, join(candidate, dir), { recursive: true });
109
+ }
110
+ const builtScripts = [
111
+ ...listModuleScripts(join(candidate, "scripts")),
112
+ ...listModuleScripts(join(candidate, "skills")),
113
+ ];
114
+ run(process.execPath, ["--check", ...builtScripts]);
115
+
116
+ if (checkOnly) {
117
+ assertTreesEqual(DIST_DIR, candidate);
118
+ console.log("pi-actors: dist is current");
119
+ } else {
120
+ replaceDist(candidate);
121
+ }
122
+ } finally {
123
+ rmSync(candidate, { recursive: true, force: true });
124
+ }