@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.
@@ -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, {})));
@@ -369,7 +369,6 @@ if (!command) {
369
369
  usage();
370
370
  process.exit(1);
371
371
  }
372
-
373
372
  if (command === "run-summary")
374
373
  runSummary(args[0] ?? "~/.pi/agent/tmp/pi-actors/runs");
375
374
  else if (command === "run-ops-snapshot")
@@ -7,6 +7,8 @@ import { dirname, extname, join, normalize, relative, resolve } from "node:path"
7
7
  import { spawnSync } from "node:child_process";
8
8
  import { fileURLToPath } from "node:url";
9
9
 
10
+ import { executableBlockBlankLines } from "./executable-block-style.mjs";
11
+
10
12
  const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
11
13
  const temp = mkdtempSync(join(tmpdir(), "pi-actors-release-index-"));
12
14
  const indexPath = join(temp, "index");
@@ -71,7 +73,6 @@ try {
71
73
  .filter(Boolean);
72
74
  const fileSet = new Set(files);
73
75
  console.log(`[release] exact temporary index: ${files.length} files`);
74
-
75
76
  const secretPatterns = [
76
77
  [/-----BEGIN(?: [A-Z0-9]+)? PRIVATE KEY-----[\s\S]{80,}?-----END(?: [A-Z0-9]+)? PRIVATE KEY-----/u, "private-key block"],
77
78
  [/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/u, "AWS access key"],
@@ -92,7 +93,17 @@ try {
92
93
  }
93
94
  }
94
95
  console.log("[release] bounded secret and public-path hygiene checked");
95
-
96
+ const executableSources = files.filter((path) =>
97
+ /\.(?:[cm]?js|ts)$/u.test(path) && !path.startsWith("dist/"),
98
+ );
99
+ for (const path of executableSources) {
100
+ const blankLines = executableBlockBlankLines(stagedText(path) ?? "");
101
+ check(
102
+ blankLines.length === 0,
103
+ `blank lines inside executable blocks: ${path}:${blankLines.join(",")}`,
104
+ );
105
+ }
106
+ console.log("[release] executable blocks contain no blank lines");
96
107
  const removedPaths = [
97
108
  "lib/messages.ts",
98
109
  "lib/rooms.ts",
@@ -113,7 +124,6 @@ try {
113
124
  "lib/run-inspector-overlay.ts",
114
125
  ];
115
126
  for (const path of removedPaths) check(!fileSet.has(path), `removed surface returned: ${path}`);
116
-
117
127
  const currentSurface = /^(?:lib\/|scripts\/|recipes\/|fixtures\/|skills\/|docs\/|README\.md|AGENTS\.md)/u;
118
128
  const forbiddenPatterns = [
119
129
  [/room:</u, "room address"],
@@ -144,7 +154,6 @@ try {
144
154
  }
145
155
  }
146
156
  console.log("[release] removed-surface and legacy-fallback allowlists checked");
147
-
148
157
  const directTraceWrite = /(?:appendFileSync|writeFileSync|writeText(?:Atomic)?)\s*\(\s*[A-Za-z0-9_.]*?(?:trace|event)(?:Path|File)/iu;
149
158
  for (const path of files.filter((candidate) =>
150
159
  (candidate.startsWith("lib/") && candidate.endsWith(".ts")) ||
@@ -172,7 +181,6 @@ try {
172
181
  );
173
182
  }
174
183
  console.log("[release] canonical Trace and Control writer residue checked");
175
-
176
184
  // owner | class | lock | record bound | byte bound | recovery
177
185
  const appendOnlyOwners = new Set([
178
186
  "lib/runs-trace.ts", // canonical Run evidence | token lock | 2048 | 4 MiB | compact valid suffix
@@ -189,7 +197,6 @@ try {
189
197
  check(appendOnlyOwners.has(path), `unregistered shipped append-only writer: ${path}`);
190
198
  for (const path of appendOnlyOwners) check(fileSet.has(path), `stale append-only owner inventory: ${path}`);
191
199
  console.log(`[release] append-only owner inventory checked: ${appendOnlyOwners.size} source owners`);
192
-
193
200
  check(
194
201
  (stagedText("scripts/validate-recipe.mjs") ?? "").includes(
195
202
  "qaReport.diagnostics.length === 0 && qaReport.warnings.length === 0",
@@ -197,15 +204,13 @@ try {
197
204
  "Recipe QA warnings are not release-blocking",
198
205
  );
199
206
  console.log("[release] zero-warning Recipe QA gate checked");
200
-
201
- const maximumShippedLines = 29_767;
207
+ const maximumShippedLines = 32_000;
202
208
  const shippedPath = /^(?:lib\/|scripts\/|recipes\/|docs\/|skills\/)/u;
203
209
  const shippedLines = files
204
210
  .filter((path) => shippedPath.test(path))
205
211
  .reduce((total, path) => total + (((stagedText(path) ?? "").match(/\n/gu) ?? []).length + 1), 0);
206
212
  check(shippedLines <= maximumShippedLines, `shipped lines ${shippedLines} exceed release maximum ${maximumShippedLines}`);
207
213
  console.log(`[release] shipped lines ${shippedLines} <= release maximum ${maximumShippedLines}`);
208
-
209
214
  const sources = files.filter((path) => path === "index.ts" || (path.startsWith("lib/") && path.endsWith(".ts")));
210
215
  const sourceSet = new Set(sources);
211
216
  const graph = new Map();
@@ -240,7 +245,6 @@ try {
240
245
  }
241
246
  for (const path of sources) visit(path);
242
247
  console.log(`[release] strict Domain DAG: ${sources.length} sources, acyclic`);
243
-
244
248
  for (const path of ["README.md", "AGENTS.md", "BACKLOG.md", "CHANGELOG.md", "docs/README.md"]) {
245
249
  check(fileSet.has(path), `missing ABCd root/context file: ${path}`);
246
250
  }
@@ -263,7 +267,6 @@ try {
263
267
  check(docsIndex.includes(relative("docs", path).replaceAll("\\", "/")), `docs/README.md omits ${path}`);
264
268
  }
265
269
  console.log("[release] ABCd context roots, routing, and Markdown links checked");
266
-
267
270
  if (failures.length > 0) {
268
271
  for (const failure of failures) console.error(`[FAIL] ${failure}`);
269
272
  process.exitCode = 1;
@@ -187,7 +187,6 @@ export function validateRecipes(argv) {
187
187
  if (!targetArg || argv.includes("--help") || argv.includes("-h")) {
188
188
  return { help: true, ok: Boolean(targetArg), usage: validateRecipeUsage() };
189
189
  }
190
-
191
190
  const files = recipeFiles(expandPath(targetArg), all);
192
191
  const results = files.map((file) => validateFile(file, qa));
193
192
  const failed = results.filter((result) => !result.ok).length;