@llblab/pi-actors 0.41.1 → 0.42.0

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.
Files changed (147) hide show
  1. package/AGENTS.md +11 -6
  2. package/BACKLOG.md +2 -62
  3. package/CHANGELOG.md +15 -0
  4. package/README.md +22 -4
  5. package/dist/index.js +25 -121
  6. package/dist/lib/async-runs.d.ts +25 -5
  7. package/dist/lib/async-runs.js +136 -47
  8. package/dist/lib/automatic-review-runtime.d.ts +18 -0
  9. package/dist/lib/automatic-review-runtime.js +96 -0
  10. package/dist/lib/draft-consolidation-transaction.d.ts +65 -0
  11. package/dist/lib/draft-consolidation-transaction.js +610 -0
  12. package/dist/lib/draft-consolidation.d.ts +35 -0
  13. package/dist/lib/draft-consolidation.js +126 -0
  14. package/dist/lib/draft-review.d.ts +56 -0
  15. package/dist/lib/draft-review.js +254 -0
  16. package/dist/lib/draft-sleep.d.ts +65 -0
  17. package/dist/lib/draft-sleep.js +468 -0
  18. package/dist/lib/file-state.d.ts +8 -1
  19. package/dist/lib/file-state.js +115 -18
  20. package/dist/lib/inspector-actions.d.ts +16 -0
  21. package/dist/lib/inspector-actions.js +57 -0
  22. package/dist/lib/inspector-command.d.ts +7 -0
  23. package/dist/lib/inspector-command.js +37 -0
  24. package/dist/lib/inspector-overlay.d.ts +20 -3
  25. package/dist/lib/inspector-overlay.js +275 -74
  26. package/dist/lib/inspector.d.ts +9 -0
  27. package/dist/lib/inspector.js +48 -0
  28. package/dist/lib/observability.d.ts +1 -0
  29. package/dist/lib/observability.js +11 -1
  30. package/dist/lib/paths.d.ts +7 -0
  31. package/dist/lib/paths.js +28 -0
  32. package/dist/lib/recipes-discovery.js +32 -24
  33. package/dist/lib/recipes-usage.d.ts +18 -6
  34. package/dist/lib/recipes-usage.js +445 -34
  35. package/dist/lib/review-control.d.ts +14 -0
  36. package/dist/lib/review-control.js +111 -0
  37. package/dist/lib/review-diagnostics.d.ts +11 -0
  38. package/dist/lib/review-diagnostics.js +148 -0
  39. package/dist/lib/review-projection.d.ts +14 -0
  40. package/dist/lib/review-projection.js +170 -0
  41. package/dist/lib/run-ui-runtime.d.ts +18 -0
  42. package/dist/lib/run-ui-runtime.js +123 -0
  43. package/dist/lib/runs-artifacts.d.ts +1 -1
  44. package/dist/lib/runs-artifacts.js +1 -1
  45. package/dist/lib/runs-control.d.ts +8 -2
  46. package/dist/lib/runs-control.js +23 -6
  47. package/dist/lib/runs-identity.d.ts +1 -1
  48. package/dist/lib/runs-identity.js +1 -1
  49. package/dist/lib/runs-index.d.ts +11 -2
  50. package/dist/lib/runs-index.js +46 -23
  51. package/dist/lib/runs-mailbox.d.ts +1 -1
  52. package/dist/lib/runs-mailbox.js +1 -1
  53. package/dist/lib/runs-messages.d.ts +1 -1
  54. package/dist/lib/runs-messages.js +1 -1
  55. package/dist/lib/runs-outbox.d.ts +1 -1
  56. package/dist/lib/runs-outbox.js +1 -1
  57. package/dist/lib/runs-ownership.d.ts +1 -1
  58. package/dist/lib/runs-ownership.js +1 -1
  59. package/dist/lib/runs-parent-teardown.d.ts +51 -0
  60. package/dist/lib/runs-parent-teardown.js +172 -0
  61. package/dist/lib/runs-process.d.ts +1 -1
  62. package/dist/lib/runs-process.js +1 -1
  63. package/dist/lib/runs-retention.d.ts +1 -1
  64. package/dist/lib/runs-retention.js +1 -1
  65. package/dist/lib/runs-start.d.ts +5 -3
  66. package/dist/lib/runs-start.js +6 -48
  67. package/dist/lib/runs-status.d.ts +5 -3
  68. package/dist/lib/runs-status.js +4 -6
  69. package/dist/lib/runtime.d.ts +7 -1
  70. package/dist/lib/runtime.js +32 -18
  71. package/dist/lib/tool-review-lineage-transaction.d.ts +27 -0
  72. package/dist/lib/tool-review-lineage-transaction.js +597 -0
  73. package/dist/lib/tool-review-lineage.d.ts +24 -0
  74. package/dist/lib/tool-review-lineage.js +98 -0
  75. package/dist/lib/tool-review-scheduler.d.ts +80 -0
  76. package/dist/lib/tool-review-scheduler.js +494 -0
  77. package/dist/lib/tool-review-transaction.d.ts +50 -0
  78. package/dist/lib/tool-review-transaction.js +362 -0
  79. package/dist/lib/tool-review.d.ts +56 -0
  80. package/dist/lib/tool-review.js +197 -0
  81. package/dist/lib/tools-inspect.js +26 -3
  82. package/dist/lib/tools-local.js +4 -2
  83. package/dist/lib/tools-message.d.ts +1 -0
  84. package/dist/lib/tools-message.js +29 -17
  85. package/dist/lib/tools-spawn.js +4 -1
  86. package/dist/lib/tools.d.ts +1 -0
  87. package/dist/lib/tools.js +1 -0
  88. package/dist/recipes/draft-review.json +24 -0
  89. package/dist/recipes/tool-review.json +24 -0
  90. package/dist/scripts/release-gates.mjs +165 -0
  91. package/dist/skills/actors/SKILL.md +9 -8
  92. package/dist/skills/swarm/SKILL.md +1 -1
  93. package/docs/actor-inspector.md +20 -11
  94. package/docs/async-runs.md +9 -1
  95. package/docs/recipe-library.md +7 -3
  96. package/docs/template-recipes.md +4 -11
  97. package/docs/tool-registry.md +11 -4
  98. package/index.ts +27 -142
  99. package/lib/async-runs.ts +218 -62
  100. package/lib/automatic-review-runtime.ts +135 -0
  101. package/lib/draft-consolidation-transaction.ts +821 -0
  102. package/lib/draft-consolidation.ts +181 -0
  103. package/lib/draft-review.ts +325 -0
  104. package/lib/draft-sleep.ts +576 -0
  105. package/lib/file-state.ts +143 -19
  106. package/lib/inspector-actions.ts +79 -0
  107. package/lib/inspector-command.ts +54 -0
  108. package/lib/inspector-overlay.ts +325 -91
  109. package/lib/inspector.ts +72 -0
  110. package/lib/observability.ts +14 -1
  111. package/lib/paths.ts +43 -0
  112. package/lib/recipes-discovery.ts +34 -26
  113. package/lib/recipes-usage.ts +569 -40
  114. package/lib/review-control.ts +137 -0
  115. package/lib/review-diagnostics.ts +164 -0
  116. package/lib/review-projection.ts +200 -0
  117. package/lib/run-ui-runtime.ts +153 -0
  118. package/lib/runs-artifacts.ts +1 -1
  119. package/lib/runs-control.ts +49 -5
  120. package/lib/runs-identity.ts +1 -1
  121. package/lib/runs-index.ts +57 -21
  122. package/lib/runs-mailbox.ts +1 -1
  123. package/lib/runs-messages.ts +1 -1
  124. package/lib/runs-outbox.ts +1 -1
  125. package/lib/runs-ownership.ts +1 -1
  126. package/lib/runs-parent-teardown.ts +257 -0
  127. package/lib/runs-process.ts +1 -1
  128. package/lib/runs-retention.ts +1 -1
  129. package/lib/runs-start.ts +12 -68
  130. package/lib/runs-status.ts +12 -8
  131. package/lib/runtime.ts +34 -17
  132. package/lib/tool-review-lineage-transaction.ts +881 -0
  133. package/lib/tool-review-lineage.ts +145 -0
  134. package/lib/tool-review-scheduler.ts +635 -0
  135. package/lib/tool-review-transaction.ts +563 -0
  136. package/lib/tool-review.ts +270 -0
  137. package/lib/tools-inspect.ts +33 -3
  138. package/lib/tools-local.ts +8 -2
  139. package/lib/tools-message.ts +45 -30
  140. package/lib/tools-spawn.ts +8 -1
  141. package/lib/tools.ts +5 -0
  142. package/package.json +3 -2
  143. package/recipes/draft-review.json +24 -0
  144. package/recipes/tool-review.json +24 -0
  145. package/scripts/release-gates.mjs +165 -0
  146. package/skills/actors/SKILL.md +9 -8
  147. package/skills/swarm/SKILL.md +1 -1
@@ -311,6 +311,9 @@ function observeRun(stateDir) {
311
311
  !Array.isArray(status.model_policy)
312
312
  ? { modelPolicy: status.model_policy }
313
313
  : {}),
314
+ ...(status.notification_policy === "silent"
315
+ ? { notificationPolicy: "silent" }
316
+ : {}),
314
317
  ...(typeof status.recipe_file === "string"
315
318
  ? { recipeFile: status.recipe_file }
316
319
  : {}),
@@ -615,7 +618,9 @@ export function detectRunTransitions(previous, summary) {
615
618
  for (const run of summary.runs) {
616
619
  const key = runObservationKey(run);
617
620
  const old = previous.get(key);
618
- if (!run.terminalHandled && TERMINAL.has(run.status)) {
621
+ if (run.notificationPolicy !== "silent" &&
622
+ !run.terminalHandled &&
623
+ TERMINAL.has(run.status)) {
619
624
  transitions.push({
620
625
  from: old ?? "running",
621
626
  run: run.run,
@@ -707,6 +712,11 @@ export function detectRunOutboxEvents(previousLineCounts, summary, seenEventIds
707
712
  const key = run.stateDir ?? run.run;
708
713
  const records = readOutboxRecords(run);
709
714
  const previousCount = previousLineCounts.get(key) ?? 0;
715
+ if (run.notificationPolicy === "silent") {
716
+ previousLineCounts.set(key, records.length);
717
+ seenEventIds.set(key, seenEventIds.get(key) ?? new Set());
718
+ continue;
719
+ }
710
720
  const start = Math.min(previousCount, records.length);
711
721
  const seen = seenEventIds.get(key) ?? new Set();
712
722
  for (let index = start; index < records.length; index += 1) {
@@ -4,6 +4,7 @@
4
4
  * Owns agent directory, tools config, recipe root, and actor run state root resolution
5
5
  */
6
6
  export declare function getAgentDir(env?: Record<string, string | undefined>): string;
7
+ export declare function isAutomaticRecipeReviewEnabled(env?: Record<string, string | undefined>): boolean;
7
8
  export interface ExtensionRuntimePaths {
8
9
  configPath: string;
9
10
  runStateRoot: string;
@@ -12,6 +13,12 @@ export interface ExtensionRuntimePaths {
12
13
  export declare function getConfigPath(agentDir?: string): string;
13
14
  export declare function getExtensionTmpDir(agentDir?: string, extensionName?: string): string;
14
15
  export declare function getRunStateRoot(agentDir?: string): string;
16
+ export declare function getDraftSleepRoot(agentDir?: string): string;
17
+ export declare function getDraftSleepStatePath(agentDir?: string): string;
18
+ export declare function getDraftSleepBatchDir(batchId: string, agentDir?: string): string;
19
+ export declare function getToolReviewRoot(agentDir?: string): string;
20
+ export declare function getToolReviewStatePath(agentDir?: string): string;
21
+ export declare function getToolReviewBatchDir(reviewId: string, agentDir?: string): string;
15
22
  export declare function getExtensionRuntimePaths(agentDir?: string): ExtensionRuntimePaths;
16
23
  export declare const EXTENSION_RUNTIME_PATHS: ExtensionRuntimePaths;
17
24
  export declare function getExtensionSkillsDir(extensionUrl: string): string;
package/dist/lib/paths.js CHANGED
@@ -12,6 +12,10 @@ export function getAgentDir(env = process.env) {
12
12
  ? resolve(env.PI_CODING_AGENT_DIR)
13
13
  : join(homedir(), ".pi", "agent");
14
14
  }
15
+ export function isAutomaticRecipeReviewEnabled(env = process.env) {
16
+ const value = env.PI_ACTORS_AUTOMATIC_REVIEW?.trim().toLowerCase();
17
+ return value === undefined || !["0", "false", "off"].includes(value);
18
+ }
15
19
  export function getConfigPath(agentDir = getAgentDir()) {
16
20
  return join(agentDir, "tool-registry.json");
17
21
  }
@@ -21,6 +25,30 @@ export function getExtensionTmpDir(agentDir = getAgentDir(), extensionName = "pi
21
25
  export function getRunStateRoot(agentDir = getAgentDir()) {
22
26
  return join(getExtensionTmpDir(agentDir), "runs");
23
27
  }
28
+ export function getDraftSleepRoot(agentDir = getAgentDir()) {
29
+ return join(getExtensionTmpDir(agentDir), "draft-sleep");
30
+ }
31
+ export function getDraftSleepStatePath(agentDir = getAgentDir()) {
32
+ return join(getDraftSleepRoot(agentDir), "state.json");
33
+ }
34
+ export function getDraftSleepBatchDir(batchId, agentDir = getAgentDir()) {
35
+ if (!/^[a-f0-9-]{36}$/u.test(batchId)) {
36
+ throw new Error("Invalid draft sleep batch id.");
37
+ }
38
+ return join(getDraftSleepRoot(agentDir), "batches", batchId);
39
+ }
40
+ export function getToolReviewRoot(agentDir = getAgentDir()) {
41
+ return join(getExtensionTmpDir(agentDir), "tool-review");
42
+ }
43
+ export function getToolReviewStatePath(agentDir = getAgentDir()) {
44
+ return join(getToolReviewRoot(agentDir), "state.json");
45
+ }
46
+ export function getToolReviewBatchDir(reviewId, agentDir = getAgentDir()) {
47
+ if (!/^[a-f0-9-]{36}$/u.test(reviewId)) {
48
+ throw new Error("Invalid tool review id.");
49
+ }
50
+ return join(getToolReviewRoot(agentDir), "batches", reviewId);
51
+ }
24
52
  export function getExtensionRuntimePaths(agentDir = getAgentDir()) {
25
53
  return {
26
54
  configPath: getConfigPath(agentDir),
@@ -528,30 +528,38 @@ function templatePreview(value) {
528
528
  }
529
529
  export function listDraftRecipes(root) {
530
530
  return listRecipeFiles(root).map((path) => {
531
- const id = RecipesReferences.getRecipeIdFromPath(path);
532
- const bytes = readFileSync(path);
533
- const stat = statSync(path);
534
- const config = RecipesReferences.readRawRecipeConfig(path);
535
- const resolved = RecipesReferences.readResolvedRecipeConfig(path);
536
- const diagnostics = getRecipeConfigDiagnostics(path, resolved);
537
- const sourceRun = String(config?.description ?? "").match(/spawn run ([^\s]+)/)?.[1];
538
- const preview = templatePreview(config?.template);
539
- const riskLabels = getRecipeRiskLabels(resolved);
540
- return {
541
- id,
542
- path,
543
- sha256: createHash("sha256").update(bytes).digest("hex"),
544
- size: bytes.byteLength,
545
- created_at: stat.birthtime.toISOString(),
546
- modified_at: stat.mtime.toISOString(),
547
- valid: Boolean(resolved),
548
- diagnostics,
549
- ...(riskLabels.length ? { risk_labels: riskLabels } : {}),
550
- ...(config?.description ? { description: config.description } : {}),
551
- ...(sourceRun ? { source_run: sourceRun } : {}),
552
- ...(config?.async !== undefined ? { async: config.async } : {}),
553
- ...(preview ? { template_preview: preview } : {}),
554
- };
531
+ for (let attempt = 0; attempt < 3; attempt += 1) {
532
+ const id = RecipesReferences.getRecipeIdFromPath(path);
533
+ const bytes = readFileSync(path);
534
+ const fingerprint = createHash("sha256").update(bytes).digest("hex");
535
+ const stat = statSync(path);
536
+ const config = RecipesReferences.readRawRecipeConfig(path);
537
+ const resolved = RecipesReferences.readResolvedRecipeConfig(path);
538
+ const diagnostics = getRecipeConfigDiagnostics(path, resolved);
539
+ const after = readFileSync(path);
540
+ if (createHash("sha256").update(after).digest("hex") !== fingerprint) {
541
+ continue;
542
+ }
543
+ const sourceRun = String(config?.description ?? "").match(/spawn run ([^\s]+)/)?.[1];
544
+ const preview = templatePreview(config?.template);
545
+ const riskLabels = getRecipeRiskLabels(resolved);
546
+ return {
547
+ id,
548
+ path,
549
+ sha256: fingerprint,
550
+ size: bytes.byteLength,
551
+ created_at: stat.birthtime.toISOString(),
552
+ modified_at: stat.mtime.toISOString(),
553
+ valid: Boolean(resolved),
554
+ diagnostics,
555
+ ...(riskLabels.length ? { risk_labels: riskLabels } : {}),
556
+ ...(config?.description ? { description: config.description } : {}),
557
+ ...(sourceRun ? { source_run: sourceRun } : {}),
558
+ ...(config?.async !== undefined ? { async: config.async } : {}),
559
+ ...(preview ? { template_preview: preview } : {}),
560
+ };
561
+ }
562
+ throw new Error(`Draft changed repeatedly during inventory: ${path}`);
555
563
  });
556
564
  }
557
565
  export function summarizeDiscovery(result) {
@@ -1,9 +1,21 @@
1
1
  /**
2
- * Recipe usage metadata helpers
3
- * Zones: recipe telemetry, muscle-memory cleanup evidence
4
- * Owns lightweight launch counters for user-owned recipe files
2
+ * Recipe usage and name-based lineage metadata.
3
+ * Zones: recipe lineage, launch telemetry, revision history, migration
4
+ * Owns priority-compatible recipe names and lifetime/revision counters for user recipes.
5
5
  */
6
6
  export type RecipeLaunchKind = "direct" | "spawn" | "tool";
7
- export declare function getRecipeUsagePath(path: string): string;
8
- export declare function readRecipeUsage(path: string): Record<string, unknown> | undefined;
9
- export declare function recordRecipeLaunch(path: string, now?: Date, kind?: RecipeLaunchKind): boolean;
7
+ export declare function getRecipeUsageIndexPath(recipeRoot: string): string;
8
+ export declare function getRecipeUsageLedgerPath(lineageName: string, recipeRoot: string): string;
9
+ export declare const RECIPE_REVISION_SNAPSHOT_LIMIT = 32;
10
+ export declare function getRecipeRevisionSnapshotPath(lineageName: string, revision: number, recipeRoot: string): string;
11
+ export declare function readRecipeUsage(path: string, recipeRoot?: string): Record<string, unknown> | undefined;
12
+ export declare function ensureRecipeLineage(path: string, now?: Date, recipeRoot?: string): boolean;
13
+ export declare function isCurrentRecipeRevisionReviewed(path: string, recipeRoot?: string): boolean;
14
+ export interface RecipeLaunchRecordOptions {
15
+ onMutationLockContention?(): void;
16
+ }
17
+ export declare function recordRecipeLaunch(path: string, now?: Date, kind?: RecipeLaunchKind, recipeRoot?: string, options?: RecipeLaunchRecordOptions): boolean;
18
+ export declare function recordRecipeReview(path: string, reviewEpoch: string, now?: Date, recipeRoot?: string): boolean;
19
+ export declare function recordRecipeRollback(path: string, rollbackRevision: number, now?: Date, recipeRoot?: string): boolean;
20
+ export declare function retireRecipeUsage(path: string, recipeRoot?: string): boolean;
21
+ export declare function moveRecipeUsage(fromPath: string, toPath: string, recipeRoot?: string): boolean;