@llblab/pi-actors 0.45.0 → 0.45.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 +2 -0
- package/CHANGELOG.md +6 -0
- package/README.md +2 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +10 -110
- package/dist/lib/extension-runtime.d.ts +21 -0
- package/dist/lib/extension-runtime.js +116 -0
- package/dist/scripts/async-runner.mjs +0 -16
- package/dist/scripts/executable-block-style.d.mts +1 -0
- package/dist/scripts/executable-block-style.mjs +73 -0
- package/dist/scripts/locker.mjs +0 -21
- package/dist/scripts/recipe-utils.mjs +0 -1
- package/dist/scripts/release-gates.mjs +14 -11
- package/dist/scripts/validate-recipe.mjs +0 -1
- package/index.ts +17 -112
- package/lib/extension-runtime.ts +139 -0
- package/package.json +2 -2
- package/scripts/async-runner.mjs +0 -16
- package/scripts/executable-block-style.d.mts +1 -0
- package/scripts/executable-block-style.mjs +73 -0
- package/scripts/locker.mjs +0 -21
- package/scripts/recipe-utils.mjs +0 -1
- package/scripts/release-gates.mjs +14 -11
- package/scripts/validate-recipe.mjs +0 -1
package/AGENTS.md
CHANGED
|
@@ -44,6 +44,7 @@ Pi host
|
|
|
44
44
|
|
|
45
45
|
## Key Domains
|
|
46
46
|
|
|
47
|
+
- `extension-runtime.ts`: low-level Pi session lifecycle, tool adaptation, and runtime service composition behind the thin `index.ts` event-registration root.
|
|
47
48
|
- `command-templates.ts`: portable synchronous execution graph.
|
|
48
49
|
- `recipes-references.ts`, `recipes-discovery.ts`, `recipe-control.ts`: Recipe resolution, imports, shadowing, and Control declarations.
|
|
49
50
|
- `async-runs.ts`: lifecycle facade.
|
|
@@ -135,6 +136,7 @@ When a deferred Run result gates the next step, wait for its terminal follow-up.
|
|
|
135
136
|
## Documentation and Release Discipline
|
|
136
137
|
|
|
137
138
|
- Keep published text portable: use `~`, `<repo>`, or relative paths.
|
|
139
|
+
- Keep executable JavaScript and TypeScript blocks compact: no blank lines inside function bodies or control-flow blocks. Structural object, type, interface, class, and module bodies are exempt.
|
|
138
140
|
- Update `skills/actors/SKILL.md` when durable operating mechanics change.
|
|
139
141
|
- Keep `skills/swarm/SKILL.md` focused on multi-agent methodology rather than kernel internals.
|
|
140
142
|
- Recipe `description` is optional because discovery supplies stable fallback tool copy; packaged Recipe QA must report zero diagnostics and zero release-blocking warnings without component boilerplate.
|
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
|
+
## 0.45.1: Entrypoint and Release Policy
|
|
6
|
+
|
|
7
|
+
- `Architecture`: Keeps `index.ts` as a thin Pi event-registration and composition root while moving session lifecycle, runtime service composition, Skill discovery, and tool adaptation into the acyclic `extension-runtime.ts` domain.
|
|
8
|
+
- `Release Policy`: Raises the fixed shipped-source ceiling to 32,000 lines and rejects blank lines inside executable JavaScript/TypeScript blocks across the complete source and test tree while exempting structural declarations.
|
|
9
|
+
- `Package Metadata`: Moves the package image to the new raw-content endpoint to restore cross-origin loading.
|
|
10
|
+
|
|
5
11
|
## 0.45.0: Skill Recipe Standard Library
|
|
6
12
|
|
|
7
13
|
- `Recipe Values`: Makes inline argument defaults optional, applies caller > values > defaults > inline precedence across tools, Runs, imports, and delegation, and validates final typed/enum values plus duplicate, unknown-default, and conflicting-type declarations.
|
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* pi-actors — actor runtime and persistent local tool registry for pi.
|
|
3
3
|
* Zones: composition root, pi agent, actor runtime
|
|
4
|
-
*
|
|
5
|
-
* Wraps command templates as callable pi tools, stores durable user tools as recipe files, and exposes actor orchestration across reloads and sessions.
|
|
4
|
+
* Owns extension composition and Pi event registration, not domain behavior.
|
|
6
5
|
*/
|
|
7
6
|
import * as Pi from "./lib/pi.ts";
|
|
8
7
|
export default function toolRegistryExtension(pi: Pi.ExtensionAPI): void;
|
package/dist/index.js
CHANGED
|
@@ -1,117 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* pi-actors — actor runtime and persistent local tool registry for pi.
|
|
3
3
|
* Zones: composition root, pi agent, actor runtime
|
|
4
|
-
*
|
|
5
|
-
* Wraps command templates as callable pi tools, stores durable user tools as recipe files, and exposes actor orchestration across reloads and sessions.
|
|
4
|
+
* Owns extension composition and Pi event registration, not domain behavior.
|
|
6
5
|
*/
|
|
7
|
-
import * as
|
|
8
|
-
import * as CommandTemplates from "./lib/command-templates.js";
|
|
6
|
+
import * as ExtensionRuntime from "./lib/extension-runtime.js";
|
|
9
7
|
import * as InspectorCommand from "./lib/inspector-command.js";
|
|
10
|
-
import * as Paths from "./lib/paths.js";
|
|
11
|
-
import * as Pi from "./lib/pi.js";
|
|
12
|
-
import * as Prompts from "./lib/prompts.js";
|
|
13
|
-
import * as RecipesReferences from "./lib/recipes-references.js";
|
|
14
|
-
import * as RunUiRuntime from "./lib/run-ui-runtime.js";
|
|
15
|
-
import * as Runtime from "./lib/runtime.js";
|
|
16
|
-
import * as Temp from "./lib/temp.js";
|
|
17
|
-
import * as Tools from "./lib/tools.js";
|
|
18
|
-
import * as ToolsResponse from "./lib/tools-response.js";
|
|
19
8
|
export default function toolRegistryExtension(pi) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
getActiveContext: () => activeRunContext,
|
|
29
|
-
getRunOwnerId,
|
|
30
|
-
onRunEvent: automaticReview.schedule,
|
|
31
|
-
pi,
|
|
32
|
-
});
|
|
33
|
-
const actorToolDefinitions = new Map();
|
|
34
|
-
const withCurrentThinkingContext = (definition) => {
|
|
35
|
-
if (typeof definition.execute !== "function")
|
|
36
|
-
return definition;
|
|
37
|
-
const execute = definition.execute;
|
|
38
|
-
return {
|
|
39
|
-
...definition,
|
|
40
|
-
execute: async (...args) => {
|
|
41
|
-
const nextArgs = [...args];
|
|
42
|
-
const ctx = nextArgs[4];
|
|
43
|
-
if (ctx && typeof ctx === "object") {
|
|
44
|
-
nextArgs[4] = {
|
|
45
|
-
...ctx,
|
|
46
|
-
getThinkingLevel: () => pi.getThinkingLevel(),
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
return ToolsResponse.spaceToolResult(await execute(...nextArgs));
|
|
51
|
-
}
|
|
52
|
-
catch (error) {
|
|
53
|
-
throw ToolsResponse.spaceToolError(error);
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
const runtime = Runtime.createAutoToolsRuntime({
|
|
59
|
-
configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
|
|
60
|
-
exec: CommandTemplates.execCommandTemplate,
|
|
61
|
-
getActiveTools: () => pi.getActiveTools(),
|
|
62
|
-
registerTool: (definition) => {
|
|
63
|
-
const wrapped = withCurrentThinkingContext(definition);
|
|
64
|
-
actorToolDefinitions.set(wrapped.name, wrapped);
|
|
65
|
-
pi.registerTool(wrapped);
|
|
66
|
-
},
|
|
67
|
-
reservedToolNames: Tools.RESERVED_TOOL_NAMES,
|
|
68
|
-
setActiveTools: (toolNames) => pi.setActiveTools(toolNames),
|
|
69
|
-
});
|
|
70
|
-
const recipeReload = Runtime.createRecipeToolReloadWatcher(runtime);
|
|
71
|
-
pi.on("resources_discover", async () => {
|
|
72
|
-
const skillPaths = Paths.getExistingExtensionSkillPaths(import.meta.url);
|
|
73
|
-
if (skillPaths.length === 0)
|
|
74
|
-
return;
|
|
75
|
-
return { skillPaths };
|
|
76
|
-
});
|
|
77
|
-
pi.on("session_start", async (_event, ctx) => {
|
|
78
|
-
// Clear the pre-overlay widget after hot reloads from older pi-actors builds.
|
|
79
|
-
ctx.ui.setWidget("zz-pi-actors-comms", undefined);
|
|
80
|
-
activeRunContext = ctx;
|
|
81
|
-
runUiRuntime.close();
|
|
82
|
-
automaticReview.close();
|
|
83
|
-
recipeReload.close();
|
|
84
|
-
await Temp.prepareExtensionTempDir(Paths.EXTENSION_RUNTIME_PATHS.tempDir);
|
|
85
|
-
if (activeRunContext !== ctx)
|
|
86
|
-
return;
|
|
87
|
-
automaticReview.start(ctx);
|
|
88
|
-
runtime.loadTools(ctx);
|
|
89
|
-
runUiRuntime.start(ctx);
|
|
90
|
-
recipeReload.watch(ctx);
|
|
91
|
-
});
|
|
92
|
-
pi.on("agent_end", async (_event, ctx) => {
|
|
93
|
-
if (activeRunContext === ctx)
|
|
94
|
-
automaticReview.schedule();
|
|
95
|
-
});
|
|
96
|
-
pi.on("session_shutdown", async (event, ctx) => {
|
|
97
|
-
activeRunContext = undefined;
|
|
98
|
-
automaticReview.close();
|
|
99
|
-
recipeReload.close();
|
|
100
|
-
runUiRuntime.shutdown(event.reason, ctx);
|
|
101
|
-
});
|
|
102
|
-
InspectorCommand.registerActorInspectorCommand(pi, getRunOwnerId);
|
|
103
|
-
pi.on("before_agent_start", async (event) => {
|
|
104
|
-
RecipesReferences.setActiveSkillRecipeSources(event.systemPromptOptions.skills ?? []);
|
|
105
|
-
return {
|
|
106
|
-
systemPrompt: `${event.systemPrompt}\n\n${Prompts.ONBOARDING_SYSTEM_PROMPT}`,
|
|
107
|
-
};
|
|
108
|
-
});
|
|
109
|
-
Pi.registerToolDefinitions(pi, Tools.createCoreActorToolDefinitions({
|
|
110
|
-
configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
|
|
111
|
-
getActiveTools: () => pi.getActiveTools(),
|
|
112
|
-
getRuntimeTool: (name) => Tools.resolveActiveRuntimeTool(name, runtime.getTools(), (activeName) => actorToolDefinitions.get(activeName)),
|
|
113
|
-
handleRuntimeControl: automaticReview.handleControl,
|
|
114
|
-
registryRuntime: runtime,
|
|
115
|
-
setActiveTools: (toolNames) => pi.setActiveTools(toolNames),
|
|
116
|
-
}).map(withCurrentThinkingContext));
|
|
9
|
+
const runtime = ExtensionRuntime.createActorExtensionRuntime(pi);
|
|
10
|
+
pi.on("resources_discover", async () => runtime.discoverResources(import.meta.url));
|
|
11
|
+
pi.on("session_start", async (_event, ctx) => runtime.onSessionStart(ctx));
|
|
12
|
+
pi.on("agent_end", async (_event, ctx) => runtime.onAgentEnd(ctx));
|
|
13
|
+
pi.on("session_shutdown", async (event, ctx) => runtime.onSessionShutdown(event.reason, ctx));
|
|
14
|
+
pi.on("before_agent_start", async (event) => runtime.beforeAgentStart(event.systemPrompt, event.systemPromptOptions.skills ?? []));
|
|
15
|
+
InspectorCommand.registerActorInspectorCommand(pi, runtime.getRunOwnerId);
|
|
16
|
+
runtime.registerCoreTools();
|
|
117
17
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pi actor extension runtime coordinator.
|
|
3
|
+
* Zones: extension session lifecycle, host tool adaptation, runtime service composition
|
|
4
|
+
* Owns low-level Pi lifecycle effects and tool wrapping without owning event registration.
|
|
5
|
+
*/
|
|
6
|
+
import * as Pi from "./pi.ts";
|
|
7
|
+
import * as RecipesReferences from "./recipes-references.ts";
|
|
8
|
+
export interface ActorExtensionRuntime {
|
|
9
|
+
beforeAgentStart(systemPrompt: string, skills: RecipesReferences.ActiveSkillRecipeSource[]): {
|
|
10
|
+
systemPrompt: string;
|
|
11
|
+
};
|
|
12
|
+
discoverResources(metaUrl: string): {
|
|
13
|
+
skillPaths: string[];
|
|
14
|
+
} | undefined;
|
|
15
|
+
getRunOwnerId(ctx: Pi.ExtensionContext): string;
|
|
16
|
+
onAgentEnd(ctx: Pi.ExtensionContext): void;
|
|
17
|
+
onSessionShutdown(reason: string, ctx: Pi.ExtensionContext): void;
|
|
18
|
+
onSessionStart(ctx: Pi.ExtensionContext): Promise<void>;
|
|
19
|
+
registerCoreTools(): void;
|
|
20
|
+
}
|
|
21
|
+
export declare function createActorExtensionRuntime(pi: Pi.ExtensionAPI): ActorExtensionRuntime;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pi actor extension runtime coordinator.
|
|
3
|
+
* Zones: extension session lifecycle, host tool adaptation, runtime service composition
|
|
4
|
+
* Owns low-level Pi lifecycle effects and tool wrapping without owning event registration.
|
|
5
|
+
*/
|
|
6
|
+
import * as AutomaticReviewRuntime from "./automatic-review-runtime.js";
|
|
7
|
+
import * as CommandTemplates from "./command-templates.js";
|
|
8
|
+
import * as Paths from "./paths.js";
|
|
9
|
+
import * as Pi from "./pi.js";
|
|
10
|
+
import * as Prompts from "./prompts.js";
|
|
11
|
+
import * as RecipesReferences from "./recipes-references.js";
|
|
12
|
+
import * as RunUiRuntime from "./run-ui-runtime.js";
|
|
13
|
+
import * as Runtime from "./runtime.js";
|
|
14
|
+
import * as Temp from "./temp.js";
|
|
15
|
+
import * as Tools from "./tools.js";
|
|
16
|
+
import * as ToolsResponse from "./tools-response.js";
|
|
17
|
+
export function createActorExtensionRuntime(pi) {
|
|
18
|
+
let activeRunContext;
|
|
19
|
+
const getRunOwnerId = Pi.getSessionId;
|
|
20
|
+
const automaticReview = AutomaticReviewRuntime.createAutomaticReviewRuntime({
|
|
21
|
+
getActiveContext: () => activeRunContext,
|
|
22
|
+
getRunOwnerId,
|
|
23
|
+
getThinkingLevel: () => pi.getThinkingLevel(),
|
|
24
|
+
});
|
|
25
|
+
const runUiRuntime = RunUiRuntime.createRunUiRuntime({
|
|
26
|
+
getActiveContext: () => activeRunContext,
|
|
27
|
+
getRunOwnerId,
|
|
28
|
+
onRunEvent: automaticReview.schedule,
|
|
29
|
+
pi,
|
|
30
|
+
});
|
|
31
|
+
const actorToolDefinitions = new Map();
|
|
32
|
+
const withCurrentThinkingContext = (definition) => {
|
|
33
|
+
if (typeof definition.execute !== "function")
|
|
34
|
+
return definition;
|
|
35
|
+
const execute = definition.execute;
|
|
36
|
+
return {
|
|
37
|
+
...definition,
|
|
38
|
+
execute: async (...args) => {
|
|
39
|
+
const nextArgs = [...args];
|
|
40
|
+
const ctx = nextArgs[4];
|
|
41
|
+
if (ctx && typeof ctx === "object") {
|
|
42
|
+
nextArgs[4] = {
|
|
43
|
+
...ctx,
|
|
44
|
+
getThinkingLevel: () => pi.getThinkingLevel(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
return ToolsResponse.spaceToolResult(await execute(...nextArgs));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
throw ToolsResponse.spaceToolError(error);
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
const runtime = Runtime.createAutoToolsRuntime({
|
|
57
|
+
configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
|
|
58
|
+
exec: CommandTemplates.execCommandTemplate,
|
|
59
|
+
getActiveTools: () => pi.getActiveTools(),
|
|
60
|
+
registerTool: (definition) => {
|
|
61
|
+
const wrapped = withCurrentThinkingContext(definition);
|
|
62
|
+
actorToolDefinitions.set(wrapped.name, wrapped);
|
|
63
|
+
pi.registerTool(wrapped);
|
|
64
|
+
},
|
|
65
|
+
reservedToolNames: Tools.RESERVED_TOOL_NAMES,
|
|
66
|
+
setActiveTools: (toolNames) => pi.setActiveTools(toolNames),
|
|
67
|
+
});
|
|
68
|
+
const recipeReload = Runtime.createRecipeToolReloadWatcher(runtime);
|
|
69
|
+
return {
|
|
70
|
+
beforeAgentStart(systemPrompt, skills) {
|
|
71
|
+
RecipesReferences.setActiveSkillRecipeSources(skills);
|
|
72
|
+
return {
|
|
73
|
+
systemPrompt: `${systemPrompt}\n\n${Prompts.ONBOARDING_SYSTEM_PROMPT}`,
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
discoverResources(metaUrl) {
|
|
77
|
+
const skillPaths = Paths.getExistingExtensionSkillPaths(metaUrl);
|
|
78
|
+
return skillPaths.length > 0 ? { skillPaths } : undefined;
|
|
79
|
+
},
|
|
80
|
+
getRunOwnerId,
|
|
81
|
+
onAgentEnd(ctx) {
|
|
82
|
+
if (activeRunContext === ctx)
|
|
83
|
+
automaticReview.schedule();
|
|
84
|
+
},
|
|
85
|
+
onSessionShutdown(reason, ctx) {
|
|
86
|
+
activeRunContext = undefined;
|
|
87
|
+
automaticReview.close();
|
|
88
|
+
recipeReload.close();
|
|
89
|
+
runUiRuntime.shutdown(reason, ctx);
|
|
90
|
+
},
|
|
91
|
+
async onSessionStart(ctx) {
|
|
92
|
+
ctx.ui.setWidget("zz-pi-actors-comms", undefined);
|
|
93
|
+
activeRunContext = ctx;
|
|
94
|
+
runUiRuntime.close();
|
|
95
|
+
automaticReview.close();
|
|
96
|
+
recipeReload.close();
|
|
97
|
+
await Temp.prepareExtensionTempDir(Paths.EXTENSION_RUNTIME_PATHS.tempDir);
|
|
98
|
+
if (activeRunContext !== ctx)
|
|
99
|
+
return;
|
|
100
|
+
automaticReview.start(ctx);
|
|
101
|
+
runtime.loadTools(ctx);
|
|
102
|
+
runUiRuntime.start(ctx);
|
|
103
|
+
recipeReload.watch(ctx);
|
|
104
|
+
},
|
|
105
|
+
registerCoreTools() {
|
|
106
|
+
Pi.registerToolDefinitions(pi, Tools.createCoreActorToolDefinitions({
|
|
107
|
+
configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
|
|
108
|
+
getActiveTools: () => pi.getActiveTools(),
|
|
109
|
+
getRuntimeTool: (name) => Tools.resolveActiveRuntimeTool(name, runtime.getTools(), (activeName) => actorToolDefinitions.get(activeName)),
|
|
110
|
+
handleRuntimeControl: automaticReview.handleControl,
|
|
111
|
+
registryRuntime: runtime,
|
|
112
|
+
setActiveTools: (toolNames) => pi.setActiveTools(toolNames),
|
|
113
|
+
}).map(withCurrentThinkingContext));
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
@@ -74,7 +74,6 @@ function summarizeCommandDetail(commandDetail) {
|
|
|
74
74
|
|
|
75
75
|
export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
76
76
|
if (!stateDir) throw new Error("missing state dir");
|
|
77
|
-
|
|
78
77
|
const runPath = join(stateDir, "run.json");
|
|
79
78
|
const progressPath = join(stateDir, "progress.json");
|
|
80
79
|
const resultPath = join(stateDir, "result.json");
|
|
@@ -83,11 +82,9 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
83
82
|
const stderrPath = join(stateDir, "stderr.log");
|
|
84
83
|
const executionPath = join(stateDir, "execution.json");
|
|
85
84
|
const meta = JSON.parse(readFileSync(runPath, "utf8"));
|
|
86
|
-
|
|
87
85
|
function event(kind, data = {}) {
|
|
88
86
|
appendRunTraceEvent(stateDir, { kind, data });
|
|
89
87
|
}
|
|
90
|
-
|
|
91
88
|
function observation(kind, summary, data = {}, delivery = "log", level = "info") {
|
|
92
89
|
appendRunTraceEvent(stateDir, {
|
|
93
90
|
kind,
|
|
@@ -97,7 +94,6 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
97
94
|
...(level === "error" ? { level: "error" } : {}),
|
|
98
95
|
});
|
|
99
96
|
}
|
|
100
|
-
|
|
101
97
|
function progress(phase, extra = {}) {
|
|
102
98
|
writeJsonAtomic(progressPath, {
|
|
103
99
|
...(meta.model_policy ? { model_policy: meta.model_policy } : {}),
|
|
@@ -106,7 +102,6 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
106
102
|
...extra,
|
|
107
103
|
});
|
|
108
104
|
}
|
|
109
|
-
|
|
110
105
|
let activeSubagents = 0;
|
|
111
106
|
let completedSubagents = 0;
|
|
112
107
|
let promptCounter = 0;
|
|
@@ -115,7 +110,6 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
115
110
|
const evidenceRecords = [];
|
|
116
111
|
const stageOccurrences = new Map();
|
|
117
112
|
let reportEvidence;
|
|
118
|
-
|
|
119
113
|
function writeExecutionManifest(status) {
|
|
120
114
|
writeJsonAtomic(executionPath, {
|
|
121
115
|
version: 1,
|
|
@@ -129,7 +123,6 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
129
123
|
updated_at: new Date().toISOString(),
|
|
130
124
|
});
|
|
131
125
|
}
|
|
132
|
-
|
|
133
126
|
function commandSessionFiles(sessionDir) {
|
|
134
127
|
if (!sessionDir) return [];
|
|
135
128
|
try {
|
|
@@ -141,7 +134,6 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
141
134
|
return [];
|
|
142
135
|
}
|
|
143
136
|
}
|
|
144
|
-
|
|
145
137
|
function commandEvidenceStartRecord({
|
|
146
138
|
commandDetail,
|
|
147
139
|
commandId,
|
|
@@ -181,7 +173,6 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
181
173
|
: "not_required",
|
|
182
174
|
};
|
|
183
175
|
}
|
|
184
|
-
|
|
185
176
|
function commandEvidenceRecord({
|
|
186
177
|
captureDir,
|
|
187
178
|
commandDetail,
|
|
@@ -273,7 +264,6 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
273
264
|
: "rejected",
|
|
274
265
|
};
|
|
275
266
|
}
|
|
276
|
-
|
|
277
267
|
function auditReviewReport(text) {
|
|
278
268
|
const required = evidenceRecords
|
|
279
269
|
.filter((record) =>
|
|
@@ -294,11 +284,9 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
294
284
|
complete_allowed: missing.length === 0,
|
|
295
285
|
};
|
|
296
286
|
}
|
|
297
|
-
|
|
298
287
|
function getCommandDoneDelivery(result) {
|
|
299
288
|
return result.code !== 0 || activeSubagents > 0 ? "followup" : "log";
|
|
300
289
|
}
|
|
301
|
-
|
|
302
290
|
function progressRunning() {
|
|
303
291
|
progress("running", {
|
|
304
292
|
activeSubagents,
|
|
@@ -306,14 +294,12 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
306
294
|
failures: subagentFailures,
|
|
307
295
|
});
|
|
308
296
|
}
|
|
309
|
-
|
|
310
297
|
function promptFilePath() {
|
|
311
298
|
promptCounter += 1;
|
|
312
299
|
const dir = join(stateDir, "prompts");
|
|
313
300
|
mkdirSync(dir, { recursive: true });
|
|
314
301
|
return join(dir, `command-${String(promptCounter).padStart(3, "0")}.md`);
|
|
315
302
|
}
|
|
316
|
-
|
|
317
303
|
function readPromptText(promptFile) {
|
|
318
304
|
if (!promptFile) return undefined;
|
|
319
305
|
try {
|
|
@@ -322,7 +308,6 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
322
308
|
return undefined;
|
|
323
309
|
}
|
|
324
310
|
}
|
|
325
|
-
|
|
326
311
|
async function observedExec(command, args, options) {
|
|
327
312
|
captureCounter += 1;
|
|
328
313
|
const commandId = `command-${String(captureCounter).padStart(3, "0")}`;
|
|
@@ -485,7 +470,6 @@ export async function runAsyncRunner(stateDir = process.argv[2]) {
|
|
|
485
470
|
progressRunning();
|
|
486
471
|
return result;
|
|
487
472
|
}
|
|
488
|
-
|
|
489
473
|
try {
|
|
490
474
|
event("run.runner.start", { pid: process.pid });
|
|
491
475
|
progressRunning();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function executableBlockBlankLines(source: string): number[];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/** Detect blank lines inside executable JavaScript and TypeScript blocks. */
|
|
2
|
+
|
|
3
|
+
export function executableBlockBlankLines(source) {
|
|
4
|
+
const lines = source.split(/\r?\n/u);
|
|
5
|
+
const blanks = [];
|
|
6
|
+
const stack = [];
|
|
7
|
+
let blockComment = false;
|
|
8
|
+
let currentExecutableDepth = 0;
|
|
9
|
+
let previousCode = "";
|
|
10
|
+
let quote;
|
|
11
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex += 1) {
|
|
12
|
+
const line = lines[lineIndex];
|
|
13
|
+
if (
|
|
14
|
+
/^\s*$/u.test(line) &&
|
|
15
|
+
currentExecutableDepth > 0 &&
|
|
16
|
+
quote !== "`"
|
|
17
|
+
)
|
|
18
|
+
blanks.push(lineIndex + 1);
|
|
19
|
+
let code = "";
|
|
20
|
+
let regularExpression = false;
|
|
21
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
22
|
+
const char = line[index];
|
|
23
|
+
const next = line[index + 1];
|
|
24
|
+
if (blockComment) {
|
|
25
|
+
if (char === "*" && next === "/") {
|
|
26
|
+
blockComment = false;
|
|
27
|
+
index += 1;
|
|
28
|
+
}
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (quote) {
|
|
32
|
+
if (char === "\\") index += 1;
|
|
33
|
+
else if (char === quote) quote = undefined;
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (regularExpression) {
|
|
37
|
+
if (char === "\\") index += 1;
|
|
38
|
+
else if (char === "/") regularExpression = false;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (char === "/" && next === "*") {
|
|
42
|
+
blockComment = true;
|
|
43
|
+
index += 1;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (char === "/" && next === "/") break;
|
|
47
|
+
if (
|
|
48
|
+
char === "/" &&
|
|
49
|
+
/^(?:|.*(?:[=(,:;!&|?{}]|\b(?:return|case|throw)))\s*$/u.test(code)
|
|
50
|
+
) {
|
|
51
|
+
regularExpression = true;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
55
|
+
quote = char;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (char === "{") {
|
|
59
|
+
const prefix = code.trimEnd() || previousCode;
|
|
60
|
+
const executable =
|
|
61
|
+
/\)\s*$|=>\s*$|\b(?:else|try|finally|do)\s*$/u.test(prefix);
|
|
62
|
+
stack.push(executable);
|
|
63
|
+
if (executable) currentExecutableDepth += 1;
|
|
64
|
+
} else if (char === "}") {
|
|
65
|
+
if (stack.pop()) currentExecutableDepth -= 1;
|
|
66
|
+
}
|
|
67
|
+
code += char;
|
|
68
|
+
}
|
|
69
|
+
if (quote !== "`") quote = undefined;
|
|
70
|
+
if (code.trim()) previousCode = code.trim();
|
|
71
|
+
}
|
|
72
|
+
return blanks;
|
|
73
|
+
}
|
package/dist/scripts/locker.mjs
CHANGED
|
@@ -65,7 +65,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
65
65
|
const controlPath = join(stateDir, "control.fifo");
|
|
66
66
|
let runInstanceId;
|
|
67
67
|
mkdirSync(stateDir, { recursive: true });
|
|
68
|
-
|
|
69
68
|
function readJson(path, fallback) {
|
|
70
69
|
if (!existsSync(path)) return fallback;
|
|
71
70
|
try {
|
|
@@ -74,11 +73,9 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
74
73
|
return fallback;
|
|
75
74
|
}
|
|
76
75
|
}
|
|
77
|
-
|
|
78
76
|
function writeJson(path, value) {
|
|
79
77
|
writeJsonAtomic(path, value);
|
|
80
78
|
}
|
|
81
|
-
|
|
82
79
|
function getControlEndpoint() {
|
|
83
80
|
if (process.platform !== "win32") return { path: controlPath, type: "fifo" };
|
|
84
81
|
const hash = createHash("sha256")
|
|
@@ -87,7 +84,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
87
84
|
.slice(0, 20);
|
|
88
85
|
return { path: `\\\\.\\pipe\\pi-actors-locker-${hash}`, type: "named-pipe" };
|
|
89
86
|
}
|
|
90
|
-
|
|
91
87
|
function writeControlEndpoint(endpoint) {
|
|
92
88
|
if (!runInstanceId) throw new Error("Run generation unavailable for Control endpoint");
|
|
93
89
|
writeJson(join(stateDir, "control-endpoint.json"), {
|
|
@@ -96,7 +92,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
96
92
|
run_instance_id: runInstanceId,
|
|
97
93
|
});
|
|
98
94
|
}
|
|
99
|
-
|
|
100
95
|
function journal(event, data = {}) {
|
|
101
96
|
const release = acquireFileMutationLock(journalPath);
|
|
102
97
|
try {
|
|
@@ -111,11 +106,9 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
111
106
|
writeTextAtomic(journalPath, content);
|
|
112
107
|
} finally { release(); }
|
|
113
108
|
}
|
|
114
|
-
|
|
115
109
|
function encodeJournal(records) {
|
|
116
110
|
return records.length ? `${records.map((record) => JSON.stringify(record)).join("\n")}\n` : "";
|
|
117
111
|
}
|
|
118
|
-
|
|
119
112
|
function emitTrace(kind, summary, data = {}, level = "info") {
|
|
120
113
|
appendRunTraceEvent(stateDir, {
|
|
121
114
|
attention: "followup",
|
|
@@ -125,11 +118,9 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
125
118
|
summary,
|
|
126
119
|
});
|
|
127
120
|
}
|
|
128
|
-
|
|
129
121
|
function now() {
|
|
130
122
|
return Date.now();
|
|
131
123
|
}
|
|
132
|
-
|
|
133
124
|
function cleanExpiredLocks(locks) {
|
|
134
125
|
const current = now();
|
|
135
126
|
const kept = {};
|
|
@@ -139,7 +130,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
139
130
|
}
|
|
140
131
|
return kept;
|
|
141
132
|
}
|
|
142
|
-
|
|
143
133
|
function normalizeControl(line) {
|
|
144
134
|
const trimmed = line.trim();
|
|
145
135
|
if (!trimmed) return undefined;
|
|
@@ -160,8 +150,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
160
150
|
);
|
|
161
151
|
}
|
|
162
152
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
153
|
function tailJournal(count) {
|
|
166
154
|
if (!existsSync(journalPath)) return [];
|
|
167
155
|
return readFileSync(journalPath, "utf8")
|
|
@@ -177,7 +165,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
177
165
|
}
|
|
178
166
|
});
|
|
179
167
|
}
|
|
180
|
-
|
|
181
168
|
function printSnapshot() {
|
|
182
169
|
const locks = cleanExpiredLocks(readJson(locksPath, {}));
|
|
183
170
|
writeJson(locksPath, locks);
|
|
@@ -195,7 +182,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
195
182
|
),
|
|
196
183
|
);
|
|
197
184
|
}
|
|
198
|
-
|
|
199
185
|
function nextTask(queue, locks) {
|
|
200
186
|
const items = Array.isArray(queue.items) ? queue.items : [];
|
|
201
187
|
const index = items.findIndex((item) => {
|
|
@@ -205,7 +191,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
205
191
|
if (index < 0) return undefined;
|
|
206
192
|
return items.splice(index, 1)[0];
|
|
207
193
|
}
|
|
208
|
-
|
|
209
194
|
function handle(control) {
|
|
210
195
|
const action = control.action;
|
|
211
196
|
const body =
|
|
@@ -333,18 +318,15 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
333
318
|
journal("lock.unknown", { action, input: body });
|
|
334
319
|
emitTrace("lock.unknown", `Unknown Control ${action}`, { action, input: body }, "warning");
|
|
335
320
|
}
|
|
336
|
-
|
|
337
321
|
if (mode === "snapshot") {
|
|
338
322
|
printSnapshot();
|
|
339
323
|
process.exit(0);
|
|
340
324
|
}
|
|
341
|
-
|
|
342
325
|
const startupRun = readJson(join(stateDir, "run.json"), undefined);
|
|
343
326
|
if (!startupRun || typeof startupRun.run_instance_id !== "string") {
|
|
344
327
|
throw new Error("Run generation unavailable for Control service");
|
|
345
328
|
}
|
|
346
329
|
runInstanceId = startupRun.run_instance_id;
|
|
347
|
-
|
|
348
330
|
function handleLine(line) {
|
|
349
331
|
const control = normalizeControl(line);
|
|
350
332
|
if (!control) return false;
|
|
@@ -376,7 +358,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
376
358
|
return false;
|
|
377
359
|
}
|
|
378
360
|
}
|
|
379
|
-
|
|
380
361
|
async function serveFifo(endpoint) {
|
|
381
362
|
if (!existsSync(endpoint.path)) {
|
|
382
363
|
const result = spawnSync("mkfifo", [endpoint.path]);
|
|
@@ -403,7 +384,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
403
384
|
fs.closeSync(fd);
|
|
404
385
|
}
|
|
405
386
|
}
|
|
406
|
-
|
|
407
387
|
async function serveNamedPipe(endpoint) {
|
|
408
388
|
let resolveStopped;
|
|
409
389
|
const stopped = new Promise((resolve) => {
|
|
@@ -428,7 +408,6 @@ async function runLocker(argv = process.argv.slice(2)) {
|
|
|
428
408
|
});
|
|
429
409
|
await stopped;
|
|
430
410
|
}
|
|
431
|
-
|
|
432
411
|
const endpoint = getControlEndpoint();
|
|
433
412
|
writeJson(queuePath, readJson(queuePath, { items: [] }));
|
|
434
413
|
writeJson(locksPath, cleanExpiredLocks(readJson(locksPath, {})));
|