pi-crew 0.9.55 → 0.9.57

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 (309) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +58 -0
  3. package/README.md +53 -5
  4. package/dist/index.mjs +5666 -4370
  5. package/docs/README.md +54 -0
  6. package/package.json +12 -13
  7. package/skills/real-test-pi-crew/SKILL.md +93 -3
  8. package/src/agents/discover-agents.ts +68 -10
  9. package/src/benchmark/feedback-loop.ts +1 -1
  10. package/src/config/config.ts +2 -1
  11. package/src/config/types.ts +12 -0
  12. package/src/extension/action-suggestions.ts +16 -63
  13. package/src/extension/async-notifier.ts +3 -3
  14. package/src/extension/command-completions.ts +2 -2
  15. package/src/extension/crew-cleanup.ts +3 -3
  16. package/src/extension/crew-vibes/footer.ts +4 -2
  17. package/src/extension/cross-extension-rpc.ts +10 -5
  18. package/src/extension/knowledge-injection.ts +57 -10
  19. package/src/extension/register.ts +2 -2
  20. package/src/extension/registration/artifact-cleanup.ts +41 -3
  21. package/src/extension/registration/commands.ts +4 -4
  22. package/src/extension/registration/context-builder.ts +10 -10
  23. package/src/extension/registration/crash-recovery-cache.ts +3 -3
  24. package/src/extension/registration/foreground-run-controller.ts +1 -1
  25. package/src/extension/registration/lazy-configurers.ts +2 -2
  26. package/src/extension/registration/lifecycle-handlers.ts +12 -12
  27. package/src/extension/registration/lifecycle.ts +2 -2
  28. package/src/extension/registration/observability.ts +2 -2
  29. package/src/extension/registration/registration-types.ts +3 -3
  30. package/src/extension/registration/runtime-cleanup.ts +1 -1
  31. package/src/extension/registration/subagent-helpers.ts +2 -2
  32. package/src/extension/registration/subagent-manager-setup.ts +2 -2
  33. package/src/extension/registration/subagent-tools.ts +21 -16
  34. package/src/extension/registration/team-tool.ts +109 -17
  35. package/src/extension/registration/viewers.ts +3 -4
  36. package/src/extension/registration/wire-cross-extension.ts +7 -7
  37. package/src/extension/rpc-hmac.ts +3 -2
  38. package/src/extension/run-bundle-schema.ts +13 -4
  39. package/src/extension/run-export.ts +2 -2
  40. package/src/extension/run-index.ts +2 -3
  41. package/src/extension/run-maintenance.ts +57 -1
  42. package/src/extension/team-manager-command.ts +3 -1
  43. package/src/extension/team-tool/anchor.ts +8 -2
  44. package/src/extension/team-tool/api.ts +117 -39
  45. package/src/extension/team-tool/cancel.ts +23 -8
  46. package/src/extension/team-tool/chain-executor.ts +1 -1
  47. package/src/extension/team-tool/dispatch/automate.ts +17 -2
  48. package/src/extension/team-tool/dispatch/control.ts +17 -2
  49. package/src/extension/team-tool/dispatch/manage.ts +34 -2
  50. package/src/extension/team-tool/dispatch/run.ts +17 -2
  51. package/src/extension/team-tool/dispatch/status.ts +37 -5
  52. package/src/extension/team-tool/doctor.ts +2 -2
  53. package/src/extension/team-tool/explain.ts +1 -1
  54. package/src/extension/team-tool/goal-wrap.ts +5 -5
  55. package/src/extension/team-tool/goal.ts +30 -9
  56. package/src/extension/team-tool/handle-schedule.ts +37 -19
  57. package/src/extension/team-tool/inspect.ts +21 -5
  58. package/src/extension/team-tool/lifecycle-actions.ts +53 -10
  59. package/src/extension/team-tool/parallel-dispatch.ts +14 -5
  60. package/src/extension/team-tool/param-error.ts +138 -0
  61. package/src/extension/team-tool/respond.ts +20 -6
  62. package/src/extension/team-tool/run.ts +27 -17
  63. package/src/extension/team-tool/status.ts +17 -6
  64. package/src/extension/team-tool.ts +26 -19
  65. package/src/hooks/registry.ts +1 -1
  66. package/src/i18n.ts +22 -0
  67. package/src/observability/event-bus.ts +1 -1
  68. package/src/prompt/prompt-runtime.ts +2 -2
  69. package/src/runtime/README.md +35 -0
  70. package/src/runtime/agent-control.ts +1 -1
  71. package/src/runtime/anchor-manager.ts +0 -2
  72. package/src/runtime/async-runner.ts +1 -1
  73. package/src/runtime/attention-events.ts +3 -2
  74. package/src/runtime/auto-summarize.ts +0 -2
  75. package/src/runtime/background-runner.ts +103 -30
  76. package/src/runtime/{crew-broker-child.ts → broker/crew-broker-child.ts} +2 -2
  77. package/src/runtime/{crew-broker-client.ts → broker/crew-broker-client.ts} +4 -7
  78. package/src/runtime/{crew-broker.ts → broker/crew-broker.ts} +13 -21
  79. package/src/runtime/chain-runner.ts +50 -5
  80. package/src/runtime/{child-pi-constants.ts → child-pi/child-pi-constants.ts} +1 -1
  81. package/src/runtime/{child-pi-kill.ts → child-pi/child-pi-kill.ts} +3 -3
  82. package/src/runtime/{child-pi-spawn.ts → child-pi/child-pi-spawn.ts} +28 -12
  83. package/src/runtime/{child-pi-steering.ts → child-pi/child-pi-steering.ts} +1 -1
  84. package/src/runtime/{child-pi-streams.ts → child-pi/child-pi-streams.ts} +23 -4
  85. package/src/runtime/{child-pi-transcript.ts → child-pi/child-pi-transcript.ts} +6 -6
  86. package/src/runtime/{child-pi.ts → child-pi/child-pi.ts} +47 -78
  87. package/src/runtime/compaction/compact-stages/bounded-tail.ts +84 -0
  88. package/src/runtime/{compact-stages → compaction/compact-stages}/index.ts +2 -2
  89. package/src/runtime/{compaction-summary.ts → compaction/compaction-summary.ts} +3 -3
  90. package/src/runtime/{tool-output-pruner.ts → compaction/tool-output-pruner.ts} +1 -1
  91. package/src/runtime/crew-agent-records.ts +48 -2
  92. package/src/runtime/custom-tools/irc-tool.ts +2 -2
  93. package/src/runtime/delivery-coordinator.ts +0 -3
  94. package/src/runtime/diagnostic-export.ts +5 -4
  95. package/src/runtime/foreground-control.ts +1 -1
  96. package/src/runtime/foreground-watchdog.ts +1 -1
  97. package/src/runtime/{adaptive-plan.ts → goal-workflow/adaptive-plan.ts} +8 -8
  98. package/src/runtime/{dynamic-workflow-context.ts → goal-workflow/dynamic-workflow-context.ts} +16 -16
  99. package/src/runtime/{dynamic-workflow-runner.ts → goal-workflow/dynamic-workflow-runner.ts} +10 -10
  100. package/src/runtime/{goal-achievement.ts → goal-workflow/goal-achievement.ts} +3 -3
  101. package/src/runtime/{goal-evaluator.ts → goal-workflow/goal-evaluator.ts} +8 -8
  102. package/src/runtime/{goal-loop-runner.ts → goal-workflow/goal-loop-runner.ts} +27 -25
  103. package/src/runtime/{goal-state-store.ts → goal-workflow/goal-state-store.ts} +8 -8
  104. package/src/runtime/{plan-templates.ts → goal-workflow/plan-templates.ts} +1 -1
  105. package/src/runtime/group-join.ts +3 -3
  106. package/src/runtime/handoff-manager.ts +0 -2
  107. package/src/runtime/{heartbeat-watcher.ts → heartbeat/heartbeat-watcher.ts} +7 -7
  108. package/src/runtime/iteration-hooks.ts +1 -1
  109. package/src/runtime/{live-agent-control.ts → live-session/live-agent-control.ts} +2 -2
  110. package/src/runtime/{live-agent-manager.ts → live-session/live-agent-manager.ts} +4 -4
  111. package/src/runtime/{live-session-runtime.ts → live-session/live-session-runtime.ts} +39 -41
  112. package/src/runtime/manifest-cache.ts +6 -2
  113. package/src/runtime/{model-fallback.ts → model/model-fallback.ts} +1 -1
  114. package/src/runtime/{pi-args.ts → model/pi-args.ts} +20 -5
  115. package/src/runtime/model/provider-extensions.ts +116 -0
  116. package/src/runtime/{runtime-policy.ts → model/runtime-policy.ts} +2 -2
  117. package/src/runtime/{runtime-resolver.ts → model/runtime-resolver.ts} +3 -3
  118. package/src/runtime/{runtime-warmup.ts → model/runtime-warmup.ts} +8 -8
  119. package/src/runtime/orphan-worker-registry.ts +1 -1
  120. package/src/runtime/{progress-tracker.ts → output/progress-tracker.ts} +1 -1
  121. package/src/runtime/{result-extractor.ts → output/result-extractor.ts} +4 -4
  122. package/src/runtime/{sidechain-output.ts → output/sidechain-output.ts} +2 -2
  123. package/src/runtime/{stream-preview.ts → output/stream-preview.ts} +1 -1
  124. package/src/runtime/{streaming-output.ts → output/streaming-output.ts} +2 -2
  125. package/src/runtime/{tool-progress.ts → output/tool-progress.ts} +1 -1
  126. package/src/runtime/parent-guard.ts +30 -10
  127. package/src/runtime/pipeline-runner.ts +2 -2
  128. package/src/runtime/policy-engine.ts +2 -2
  129. package/src/runtime/{cancellation.ts → process/cancellation.ts} +1 -1
  130. package/src/runtime/{post-exit-stdio-guard.ts → process/post-exit-stdio-guard.ts} +1 -1
  131. package/src/runtime/{process-lifecycle.ts → process/process-lifecycle.ts} +3 -3
  132. package/src/runtime/{checkpoint.ts → recovery/checkpoint.ts} +4 -4
  133. package/src/runtime/{crash-recovery.ts → recovery/crash-recovery.ts} +93 -21
  134. package/src/runtime/{overflow-recovery.ts → recovery/overflow-recovery.ts} +1 -1
  135. package/src/runtime/{recovery-recipes.ts → recovery/recovery-recipes.ts} +1 -1
  136. package/src/runtime/{retry-executor.ts → recovery/retry-executor.ts} +2 -2
  137. package/src/runtime/{retry-runner.ts → recovery/retry-runner.ts} +2 -8
  138. package/src/runtime/run-tracker.ts +1 -1
  139. package/src/runtime/run-worker.ts +3 -3
  140. package/src/runtime/{coalesce-tasks.ts → scheduling/coalesce-tasks.ts} +3 -3
  141. package/src/runtime/{concurrency.ts → scheduling/concurrency.ts} +9 -3
  142. package/src/runtime/{parallel-research.ts → scheduling/parallel-research.ts} +4 -2
  143. package/src/runtime/{run-coalesced-task-group.ts → scheduling/run-coalesced-task-group.ts} +95 -36
  144. package/src/runtime/{semaphore.ts → scheduling/semaphore.ts} +4 -1
  145. package/src/runtime/{task-graph-scheduler.ts → scheduling/task-graph-scheduler.ts} +1 -1
  146. package/src/runtime/session-resources.ts +1 -1
  147. package/src/runtime/settings-store.ts +1 -1
  148. package/src/runtime/single-agent-compose.ts +1 -0
  149. package/src/runtime/stale-reconciler.ts +1 -1
  150. package/src/runtime/subagent-manager.ts +1 -1
  151. package/src/runtime/supervisor-contact.ts +28 -13
  152. package/src/runtime/task-output-context.ts +7 -5
  153. package/src/runtime/task-runner/child-executor.ts +67 -31
  154. package/src/runtime/task-runner/live-executor.ts +8 -8
  155. package/src/runtime/task-runner/post-execution.ts +12 -12
  156. package/src/runtime/task-runner/pre-execution.ts +6 -6
  157. package/src/runtime/task-runner/progress.ts +1 -1
  158. package/src/runtime/task-runner/run-projection.ts +1 -1
  159. package/src/runtime/task-runner/scaffold-executor.ts +1 -1
  160. package/src/runtime/task-runner/state-helpers.ts +2 -2
  161. package/src/runtime/task-runner.ts +4 -4
  162. package/src/runtime/team-runner.ts +441 -175
  163. package/src/runtime/{completion-guard.ts → verification/completion-guard.ts} +1 -1
  164. package/src/runtime/{green-contract.ts → verification/green-contract.ts} +1 -1
  165. package/src/runtime/{post-checks.ts → verification/post-checks.ts} +4 -4
  166. package/src/runtime/{verification-gates.ts → verification/verification-gates.ts} +5 -5
  167. package/src/runtime/{verification-integrity.ts → verification/verification-integrity.ts} +1 -1
  168. package/src/schema/config-schema.ts +1 -0
  169. package/src/schema/team-tool-schema.ts +149 -185
  170. package/src/state/README.md +44 -0
  171. package/src/state/atomic-write.ts +24 -3
  172. package/src/state/{locks.ts → coordination/locks.ts} +118 -38
  173. package/src/state/{mailbox.ts → coordination/mailbox.ts} +14 -8
  174. package/src/state/{schedule.ts → coordination/schedule.ts} +3 -3
  175. package/src/state/{task-claims.ts → coordination/task-claims.ts} +1 -1
  176. package/src/state/decision-ledger.ts +1 -1
  177. package/src/state/{event-log-rotation.ts → event-log/event-log-rotation.ts} +189 -31
  178. package/src/state/{event-log.ts → event-log/event-log.ts} +77 -39
  179. package/src/state/{jsonl-writer.ts → event-log/jsonl-writer.ts} +14 -6
  180. package/src/state/hook-instinct-bridge.ts +2 -2
  181. package/src/state/{active-run-registry.ts → stores/active-run-registry.ts} +7 -7
  182. package/src/state/{artifact-store.ts → stores/artifact-store.ts} +62 -4
  183. package/src/state/{blob-store.ts → stores/blob-store.ts} +3 -3
  184. package/src/state/{health-store.ts → stores/health-store.ts} +3 -3
  185. package/src/state/{instinct-store.ts → stores/instinct-store.ts} +3 -3
  186. package/src/state/{observation-store.ts → stores/observation-store.ts} +2 -2
  187. package/src/state/{run-cache.ts → stores/run-cache.ts} +4 -4
  188. package/src/state/{run-graph.ts → stores/run-graph.ts} +4 -4
  189. package/src/state/{run-metrics.ts → stores/run-metrics.ts} +3 -3
  190. package/src/state/{state-store.ts → stores/state-store.ts} +254 -21
  191. package/src/state/types.ts +27 -3
  192. package/src/ui/component.ts +55 -0
  193. package/src/ui/crew-select-list.ts +3 -1
  194. package/src/ui/dashboard-panes/agents-pane.ts +1 -1
  195. package/src/ui/dwf-phase-display.ts +1 -1
  196. package/src/ui/heartbeat-aggregator.ts +1 -1
  197. package/src/ui/keybinding-map.ts +179 -6
  198. package/src/ui/layout-primitives.ts +9 -5
  199. package/src/ui/live-conversation-overlay.ts +1 -1
  200. package/src/ui/live-run-sidebar.ts +1 -1
  201. package/src/ui/overlay-stack.ts +148 -0
  202. package/src/ui/overlays/agent-picker-overlay.ts +1 -1
  203. package/src/ui/overlays/mailbox-compose-overlay.ts +1 -1
  204. package/src/ui/overlays/mailbox-detail-overlay.ts +2 -2
  205. package/src/ui/powerbar-publisher.ts +1 -1
  206. package/src/ui/render-scheduler.ts +1 -1
  207. package/src/ui/run-action-dispatcher.ts +3 -3
  208. package/src/ui/run-dashboard.ts +5 -33
  209. package/src/ui/run-event-bus.ts +3 -3
  210. package/src/ui/run-snapshot-cache.ts +37 -18
  211. package/src/ui/settings-overlay.ts +13 -21
  212. package/src/ui/snapshot-types.ts +1 -1
  213. package/src/ui/status-colors.ts +0 -2
  214. package/src/ui/terminal-status.ts +1 -1
  215. package/src/ui/theme-adapter.ts +33 -13
  216. package/src/ui/tool-renderers/index.ts +8 -0
  217. package/src/ui/transcript-viewer.ts +37 -13
  218. package/src/ui/widget/index.ts +32 -9
  219. package/src/ui/widget/widget-formatters.ts +62 -4
  220. package/src/ui/widget/widget-model.ts +2 -2
  221. package/src/ui/widget/widget-renderer.ts +1 -1
  222. package/src/utils/conflict-detect.ts +58 -5
  223. package/src/utils/ndjson.ts +2 -2
  224. package/src/utils/redaction.ts +39 -0
  225. package/src/utils/socket-path.ts +1 -1
  226. package/src/workflows/workflow-config.ts +1 -1
  227. package/src/worktree/cleanup.ts +1 -1
  228. package/src/worktree/worktree-manager.ts +111 -47
  229. package/workflows/chain.workflow.md +2 -2
  230. package/dist/build-meta.json +0 -16807
  231. package/index.bundle.ts +0 -25
  232. package/scripts/bench-check.mjs +0 -96
  233. package/scripts/bench-cold-start.mjs +0 -216
  234. package/scripts/build-bundle.mjs +0 -92
  235. package/scripts/check-all-skills.ts +0 -294
  236. package/scripts/check-bundle-size.mjs +0 -38
  237. package/scripts/check-bundle-staleness.mjs +0 -97
  238. package/scripts/check-conflict-markers.mjs +0 -91
  239. package/scripts/check-lazy-imports.mjs +0 -28
  240. package/scripts/dev-runner.mjs +0 -106
  241. package/scripts/profile-startup.mjs +0 -125
  242. package/scripts/release-smoke.mjs +0 -74
  243. package/scripts/run-bench.mjs +0 -47
  244. package/scripts/run-real-chain.ts +0 -41
  245. package/scripts/test-issue-29-crash.ts +0 -111
  246. package/scripts/test-issue-29-e2e.ts +0 -183
  247. package/scripts/test-issue-29-real-runtime.ts +0 -330
  248. package/scripts/test-issue-29-real-tasks.ts +0 -387
  249. package/scripts/test-issue-29-team-tool.ts +0 -105
  250. package/scripts/test-runner.mjs +0 -84
  251. package/scripts/verify-flicker-fix.ts +0 -109
  252. package/scripts/verify-skill.ts +0 -550
  253. package/scripts/watch-bundle.mjs +0 -259
  254. package/scripts/watchdog-harness.ts +0 -119
  255. package/src/adapters/claude-adapter.ts +0 -23
  256. package/src/adapters/codex-adapter.ts +0 -21
  257. package/src/adapters/cursor-adapter.ts +0 -17
  258. package/src/adapters/export-util.ts +0 -143
  259. package/src/adapters/index.ts +0 -15
  260. package/src/adapters/registry.ts +0 -18
  261. package/src/adapters/types.ts +0 -23
  262. package/src/runtime/code-summary.ts +0 -292
  263. package/src/runtime/cross-extension-rpc.ts +0 -143
  264. package/src/runtime/hidden-handoff.ts +0 -407
  265. package/src/runtime/prose-compressor.ts +0 -162
  266. package/src/subagents/async-entry.ts +0 -1
  267. package/src/subagents/index.ts +0 -3
  268. package/src/subagents/live/control.ts +0 -1
  269. package/src/subagents/live/manager.ts +0 -1
  270. package/src/subagents/live/realtime.ts +0 -1
  271. package/src/subagents/live/session-runtime.ts +0 -1
  272. package/src/subagents/manager.ts +0 -1
  273. package/src/subagents/spawn.ts +0 -1
  274. package/test-integration-check.ts +0 -118
  275. /package/src/runtime/{broker-issuer.ts → broker/broker-issuer.ts} +0 -0
  276. /package/src/runtime/{crew-broker-tokens.ts → broker/crew-broker-tokens.ts} +0 -0
  277. /package/src/runtime/{child-pi-pool.ts → child-pi/child-pi-pool.ts} +0 -0
  278. /package/src/runtime/{compact-pipeline.ts → compaction/compact-pipeline.ts} +0 -0
  279. /package/src/runtime/{compact-stages → compaction/compact-stages}/ansi-strip-stage.ts +0 -0
  280. /package/src/runtime/{compact-stages → compaction/compact-stages}/blank-collapse-stage.ts +0 -0
  281. /package/src/runtime/{compact-stages → compaction/compact-stages}/deduplicate-stage.ts +0 -0
  282. /package/src/runtime/{compact-stages → compaction/compact-stages}/head-snap-stage.ts +0 -0
  283. /package/src/runtime/{compact-stages → compaction/compact-stages}/tail-capture-stage.ts +0 -0
  284. /package/src/runtime/{compact-stages → compaction/compact-stages}/truncation-stage.ts +0 -0
  285. /package/src/runtime/{important-line-classifier.ts → compaction/important-line-classifier.ts} +0 -0
  286. /package/src/runtime/{heartbeat-gradient.ts → heartbeat/heartbeat-gradient.ts} +0 -0
  287. /package/src/runtime/{worker-heartbeat.ts → heartbeat/worker-heartbeat.ts} +0 -0
  288. /package/src/runtime/{worker-startup.ts → heartbeat/worker-startup.ts} +0 -0
  289. /package/src/runtime/{intercom-bridge.ts → live-session/intercom-bridge.ts} +0 -0
  290. /package/src/runtime/{live-control-realtime.ts → live-session/live-control-realtime.ts} +0 -0
  291. /package/src/runtime/{live-extension-bridge.ts → live-session/live-extension-bridge.ts} +0 -0
  292. /package/src/runtime/{live-irc.ts → live-session/live-irc.ts} +0 -0
  293. /package/src/runtime/{live-session-health.ts → live-session/live-session-health.ts} +0 -0
  294. /package/src/runtime/{model-resolver.ts → model/model-resolver.ts} +0 -0
  295. /package/src/runtime/{model-scope.ts → model/model-scope.ts} +0 -0
  296. /package/src/runtime/{output-validator.ts → output/output-validator.ts} +0 -0
  297. /package/src/runtime/{pi-json-output.ts → output/pi-json-output.ts} +0 -0
  298. /package/src/runtime/{progress-event-coalescer.ts → output/progress-event-coalescer.ts} +0 -0
  299. /package/src/runtime/{cancellation-token.ts → process/cancellation-token.ts} +0 -0
  300. /package/src/runtime/{zombie-scanner.ts → process/zombie-scanner.ts} +0 -0
  301. /package/src/runtime/{crash-classification.ts → recovery/crash-classification.ts} +0 -0
  302. /package/src/runtime/{batch-barrier.ts → scheduling/batch-barrier.ts} +0 -0
  303. /package/src/runtime/{global-worker-cap.ts → scheduling/global-worker-cap.ts} +0 -0
  304. /package/src/runtime/{parallel-utils.ts → scheduling/parallel-utils.ts} +0 -0
  305. /package/src/runtime/{scheduler.ts → scheduling/scheduler.ts} +0 -0
  306. /package/src/runtime/{task-graph.ts → scheduling/task-graph.ts} +0 -0
  307. /package/src/runtime/{verification-worktree.ts → verification/verification-worktree.ts} +0 -0
  308. /package/src/state/{event-reconstructor.ts → event-log/event-reconstructor.ts} +0 -0
  309. /package/src/state/{worker-atomic-writer.ts → event-log/worker-atomic-writer.ts} +0 -0
@@ -1,7 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import { redactSecrets } from "../utils/redaction.ts";
4
- import { isSafePathId } from "../utils/safe-paths.ts";
3
+ import { redactSecrets } from "../../utils/redaction.ts";
4
+ import { isSafePathId } from "../../utils/safe-paths.ts";
5
5
 
6
6
  export interface SidechainEntry {
7
7
  isSidechain: true;
@@ -2,7 +2,7 @@
2
2
  // Captures incremental worker output during task execution for live preview.
3
3
  // Used by the UI layer to show partial results before task completion.
4
4
 
5
- import { TAIL_CAPTURE_STREAM_STAGE } from "./compact-stages/index.ts";
5
+ import { TAIL_CAPTURE_STREAM_STAGE } from "../compaction/compact-stages/index.ts";
6
6
  import type { ParsedPiUsage } from "./pi-json-output.ts";
7
7
 
8
8
  export interface ToolCallPreview {
@@ -1,7 +1,7 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import type { TeamRunManifest } from "../state/types.ts";
4
- import { isSafePathId } from "../utils/safe-paths.ts";
3
+ import type { TeamRunManifest } from "../../state/types.ts";
4
+ import { isSafePathId } from "../../utils/safe-paths.ts";
5
5
 
6
6
  export interface StreamingOutputHandle {
7
7
  write(text: string): void;
@@ -10,7 +10,7 @@
10
10
  * 4. This module provides structured types and utilities for the event system
11
11
  */
12
12
 
13
- import type { CrewAgentProgress } from "../state/types.ts";
13
+ import type { CrewAgentProgress } from "../../state/types.ts";
14
14
 
15
15
  // ── Event Types ─────────────────────────────────────────────────────────
16
16
 
@@ -1,16 +1,32 @@
1
1
  /**
2
- * Parent liveness guard for pi-crew worker processes.
2
+ * Parent liveness guard for pi-crew background-runner process.
3
3
  *
4
- * Workers call `startParentGuard(parentPid)` at startup. A lightweight
5
- * interval checks if the parent PID is still alive. When the parent dies
6
- * (SIGKILL, crash, power loss, terminal close), the worker self-terminates
7
- * immediately — no sentinel process needed.
4
+ * REALITY (verified by grep, RT-19/RT-2): `startParentGuard` is called in
5
+ * exactly ONE production location — `background-runner.ts:508`. The
6
+ * background-runner watches the main pi session that spawned it. If that
7
+ * parent dies, the runner self-terminates so it does not leak.
8
+ *
9
+ * Child pi workers do NOT call `startParentGuard`. They are the external
10
+ * `pi` binary (`@earendil-works/pi-coding-agent`) — pi-crew does not control
11
+ * its entry point. Although `PI_CREW_PARENT_PID` is set in the child's env
12
+ * (`child-pi-spawn.ts:134`), it has ZERO consumers: grep of the Pi binary
13
+ * dist for `PI_CREW_PARENT_PID` / `startParentGuard` / `parent-guard` = 0
14
+ * matches. This means child workers are NOT protected by this guard.
15
+ *
16
+ * The deeper fix (wiring `startParentGuard` into the pi worker entry point) is
17
+ * DEFERRED because workers are an external binary pi-crew doesn't control.
18
+ *
19
+ * Orphan-mitigation for this gap relies on:
20
+ * 1. The RT-2 SIGINT fix in `background-runner.ts` (abort + exitCode pattern
21
+ * lets the finally/runCleanup block terminate child-pi processes).
22
+ * 2. The reactive `zombie-scanner.ts` sweep (finds workers whose
23
+ * `PI_CREW_PARENT_PID` points at a dead PID and reports them).
8
24
  *
9
25
  * Note: `process.kill(pid, 0)` works on both Unix and Windows in Node.js
10
26
  * for checking process existence. On Windows, it may throw for processes
11
27
  * owned by other users (permission error), but correctly detects dead PIDs.
12
28
  *
13
- * Usage in worker entry points:
29
+ * Usage in background-runner.ts (the ONLY consumer):
14
30
  * ```ts
15
31
  * const parentPid = Number(process.env.PI_CREW_PARENT_PID);
16
32
  * if (parentPid > 0) startParentGuard(parentPid);
@@ -81,12 +97,16 @@ function selfTerminate(parentPid: number): never {
81
97
 
82
98
  /**
83
99
  * Start a lightweight poll that checks if the parent process is still alive.
84
- * If the parent dies, this worker exits immediately with code 124.
100
+ * If the parent dies, the calling process exits immediately with code 124.
101
+ *
102
+ * CURRENT REALITY: the only production caller is `background-runner.ts`, which
103
+ * uses this to self-terminate when the main pi session dies. Child pi workers
104
+ * do NOT call this (see module header for the DEFERRED deeper fix).
85
105
  *
86
106
  * FIX: Removed unref() — the guard interval MUST keep the event loop alive
87
- * to prevent premature worker exit when the parent is still alive but the
88
- * worker has no other pending work (LLM calls, timers, I/O). Without this,
89
- * a worker in pure CPU wait could exit even though its parent is alive.
107
+ * to prevent premature runner exit when the parent is still alive but the
108
+ * runner has no other pending work (LLM calls, timers, I/O). Without this,
109
+ * a runner in pure CPU wait could exit even though its parent is alive.
90
110
  */
91
111
  export function startParentGuard(parentPid: number): void {
92
112
  if (!parentPid || !Number.isFinite(parentPid) || parentPid <= 0) return;
@@ -1,8 +1,8 @@
1
1
  import { errors } from "../errors.ts";
2
- import { appendEventAsync, flushEventLogBuffer } from "../state/event-log.ts";
2
+ import { appendEventAsync, flushEventLogBuffer } from "../state/event-log/event-log.ts";
3
3
  import { errorMessage } from "../utils/guards.ts";
4
4
  import type { WorkflowConfig } from "../workflows/workflow-config.ts";
5
- import { mapConcurrent } from "./parallel-utils.ts";
5
+ import { mapConcurrent } from "./scheduling/parallel-utils.ts";
6
6
 
7
7
  /**
8
8
  * Pipeline stage configuration.
@@ -1,7 +1,7 @@
1
1
  import type { CrewLimitsConfig } from "../config/config.ts";
2
2
  import type { PolicyDecision, PolicyDecisionAction, PolicyDecisionReason, TeamRunManifest, TeamTaskState } from "../state/types.ts";
3
- import { evaluateGreenContract } from "./green-contract.ts";
4
- import { isWorkerHeartbeatStale } from "./worker-heartbeat.ts";
3
+ import { isWorkerHeartbeatStale } from "./heartbeat/worker-heartbeat.ts";
4
+ import { evaluateGreenContract } from "./verification/green-contract.ts";
5
5
 
6
6
  export interface PolicyEngineInput {
7
7
  manifest: TeamRunManifest;
@@ -1,4 +1,4 @@
1
- import type { OperationTerminalEvidence } from "../state/types.ts";
1
+ import type { OperationTerminalEvidence } from "../../state/types.ts";
2
2
 
3
3
  export type CancellationReasonCode =
4
4
  | "caller_cancelled"
@@ -1,5 +1,5 @@
1
1
  import type { ChildProcess } from "node:child_process";
2
- import { logInternalError } from "../utils/internal-error.ts";
2
+ import { logInternalError } from "../../utils/internal-error.ts";
3
3
 
4
4
  interface PostExitStdioGuardOptions {
5
5
  idleMs: number;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Owned-process lifecycle abstraction (P0 item #3).
3
3
  *
4
- * Distilled and adapted from gajae-code's `runtime/process-lifecycle.ts`.
4
+ * Distilled and adapted from gajae-code's `runtime/process/process-lifecycle.ts`.
5
5
  *
6
6
  * Two complementary primitives:
7
7
  *
@@ -30,7 +30,7 @@
30
30
  * See `.crew/knowledge.md` gotchas: BSD/Windows signal handling differs.
31
31
  */
32
32
  import { type ChildProcess, type SpawnOptions, spawn } from "node:child_process";
33
- import { logInternalError } from "../utils/internal-error.ts";
33
+ import { logInternalError } from "../../utils/internal-error.ts";
34
34
 
35
35
  // ── tunables ──────────────────────────────────────────────────────────────────
36
36
 
@@ -197,7 +197,7 @@ export class OwnedProcess {
197
197
  }
198
198
  }
199
199
 
200
- private deregisterFn: () => void = () => {};
200
+ private deregisterFn: () => void = () => undefined;
201
201
 
202
202
  /** `true` once `dispose()` has started. */
203
203
  get isDisposed(): boolean {
@@ -1,9 +1,9 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import { atomicWriteFile } from "../state/atomic-write.ts";
4
- import { logInternalError } from "../utils/internal-error.ts";
5
- import { projectCrewRoot } from "../utils/paths.ts";
6
- import { assertSafePathId } from "../utils/safe-paths.ts";
3
+ import { atomicWriteFile } from "../../state/atomic-write.ts";
4
+ import { logInternalError } from "../../utils/internal-error.ts";
5
+ import { projectCrewRoot } from "../../utils/paths.ts";
6
+ import { assertSafePathId } from "../../utils/safe-paths.ts";
7
7
 
8
8
  export interface Checkpoint {
9
9
  runId: string;
@@ -1,22 +1,23 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
3
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
4
- import { appendHookEvent, executeHook } from "../hooks/registry.ts";
5
- import type { MetricRegistry } from "../observability/metric-registry.ts";
6
- import { readActiveRunRegistry, unregisterActiveRun } from "../state/active-run-registry.ts";
7
- import { appendEvent, scanSequence } from "../state/event-log.ts";
8
- import { withRunLockSync } from "../state/locks.ts";
9
- import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../state/state-store.ts";
10
- import type { TeamTaskState } from "../state/types.ts";
11
- import { logInternalError } from "../utils/internal-error.ts";
12
- import { projectCrewRoot, userCrewRoot } from "../utils/paths.ts";
13
- import { resolveRealContainedPath } from "../utils/safe-paths.ts";
14
- import { recordFromTask, upsertCrewAgent } from "./crew-agent-records.ts";
15
- import { terminateLiveAgentsForRun } from "./live-agent-manager.ts";
16
- import type { ManifestCache } from "./manifest-cache.ts";
17
- import { checkProcessLiveness } from "./process-status.ts";
18
- import { isPlanApprovalPending, type ReconcileResult, reconcileStaleRun } from "./stale-reconciler.ts";
19
- import { isWorkerHeartbeatStale } from "./worker-heartbeat.ts";
4
+ import { appendHookEvent, executeHook } from "../../hooks/registry.ts";
5
+ import type { MetricRegistry } from "../../observability/metric-registry.ts";
6
+ import { withRunLockSync } from "../../state/coordination/locks.ts";
7
+ import { appendEvent, scanSequence } from "../../state/event-log/event-log.ts";
8
+ import { readActiveRunRegistry, unregisterActiveRun } from "../../state/stores/active-run-registry.ts";
9
+ import { loadRunManifestById, saveRunTasks, updateRunStatus } from "../../state/stores/state-store.ts";
10
+ import type { TeamTaskState } from "../../state/types.ts";
11
+ import { logInternalError } from "../../utils/internal-error.ts";
12
+ import { projectCrewRoot, userCrewRoot } from "../../utils/paths.ts";
13
+ import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
14
+ import { sleepSync } from "../../utils/sleep.ts";
15
+ import { recordFromTask, upsertCrewAgent } from "../crew-agent-records.ts";
16
+ import { isWorkerHeartbeatStale } from "../heartbeat/worker-heartbeat.ts";
17
+ import { terminateLiveAgentsForRun } from "../live-session/live-agent-manager.ts";
18
+ import type { ManifestCache } from "../manifest-cache.ts";
19
+ import { checkProcessLiveness } from "../process-status.ts";
20
+ import { isPlanApprovalPending, type ReconcileResult, reconcileStaleRun } from "../stale-reconciler.ts";
20
21
 
21
22
  export interface RecoveryPlan {
22
23
  runId: string;
@@ -35,6 +36,68 @@ function isTerminalTask(task: TeamTaskState): boolean {
35
36
  );
36
37
  }
37
38
 
39
+ /**
40
+ * Errno codes that represent transient filesystem conditions (e.g. Windows AV
41
+ * scan temporarily locking the file, or a brief permission window). On these
42
+ * errors the manifest is NOT corrupt — retrying the read after a short backoff
43
+ * will succeed.
44
+ */
45
+ const TRANSIENT_READ_ERRNO_CODES = new Set(["EBUSY", "EACCES", "EAGAIN", "EPERM", "ENFILE", "EMFILE"]);
46
+
47
+ /**
48
+ * Raw file-read function used by readManifestWithTransientRetry. Separated as
49
+ * a module-level binding so tests can inject transient-error mocks without
50
+ * needing to mutate the frozen ESM `fs` namespace.
51
+ */
52
+ let _readManifestFileSync: (filePath: string) => string = (p) => fs.readFileSync(p, "utf-8");
53
+
54
+ /**
55
+ * @internal — test seam for readManifestWithTransientRetry. Pass `null` to reset.
56
+ */
57
+ export function _setReadManifestFileSyncForTest(fn: ((filePath: string) => string) | null): void {
58
+ _readManifestFileSync = fn ?? ((p) => fs.readFileSync(p, "utf-8"));
59
+ }
60
+
61
+ /**
62
+ * Read and JSON-parse a manifest file, retrying transient read errors
63
+ * (EBUSY/EACCES/EAGAIN — common on Windows when AV software briefly locks the
64
+ * file) with exponential backoff.
65
+ *
66
+ * ST-6: Previously, a single `catch` quarantined the manifest on ALL errors,
67
+ * including transient I/O failures that left a perfectly healthy manifest
68
+ * unparseable for a few milliseconds. This renamed the valid file to
69
+ * `.corrupt-*`, making the run permanently unloadable.
70
+ *
71
+ * Behavior:
72
+ * - Success → returns parsed object
73
+ * - SyntaxError (genuinely corrupt JSON) → rethrown immediately (caller quarantines)
74
+ * - Transient ErrnoException → retried up to `maxRetries` times; if still
75
+ * failing, rethrown so the caller can skip WITHOUT quarantining
76
+ * - Other ErrnoException (ENOENT, etc.) → rethrown immediately
77
+ */
78
+ export function readManifestWithTransientRetry(manifestPath: string, maxRetries = 3, baseDelayMs = 100): Record<string, unknown> {
79
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
80
+ try {
81
+ return JSON.parse(_readManifestFileSync(manifestPath)) as Record<string, unknown>;
82
+ } catch (err) {
83
+ // SyntaxError = genuinely corrupt JSON → rethrow immediately
84
+ if (err instanceof SyntaxError) throw err;
85
+ const code = (err as NodeJS.ErrnoException).code;
86
+ // Transient read error → retry with exponential backoff
87
+ if (code !== undefined && TRANSIENT_READ_ERRNO_CODES.has(code)) {
88
+ if (attempt < maxRetries) {
89
+ sleepSync(baseDelayMs * 2 ** attempt);
90
+ continue;
91
+ }
92
+ }
93
+ // Non-transient error, or retries exhausted → rethrow
94
+ throw err;
95
+ }
96
+ }
97
+ // Unreachable: the loop either returns or throws on every iteration.
98
+ throw new Error(`unreachable: readManifestWithTransientRetry exhausted for ${manifestPath}`);
99
+ }
100
+
38
101
  function shouldRecoverTask(task: TeamTaskState, deadMs: number): boolean {
39
102
  if (task.status !== "running") return false;
40
103
  if (!task.heartbeat) return true;
@@ -375,11 +438,20 @@ export function purgeStaleActiveRunIndex(staleThresholdMs = 300_000, now = Date.
375
438
  }
376
439
  | undefined;
377
440
  try {
378
- manifest = JSON.parse(fs.readFileSync(entry.manifestPath, "utf-8"));
379
- } catch {
380
- // R-01: Quarantine the corrupt manifest instead of deleting all run state.
381
- // A single corrupted byte must NOT cause total data loss — events.jsonl,
382
- // task data, and artifacts are preserved for manual recovery.
441
+ manifest = readManifestWithTransientRetry(entry.manifestPath) as typeof manifest;
442
+ } catch (err) {
443
+ // ST-6: Transient read errors (EBUSY/EACCES/EAGAIN from Windows AV
444
+ // scans) must NOT quarantine a healthy manifest — the file is fine,
445
+ // just temporarily locked. Skip this entry and try again next cycle.
446
+ const code = (err as NodeJS.ErrnoException).code;
447
+ const isTransient = code !== undefined && TRANSIENT_READ_ERRNO_CODES.has(code);
448
+ if (isTransient) continue;
449
+
450
+ // R-01: Quarantine the corrupt manifest instead of deleting all run
451
+ // state. A single corrupted byte must NOT cause total data loss —
452
+ // events.jsonl, task data, and artifacts are preserved for manual
453
+ // recovery. SyntaxError (genuinely corrupt JSON) and unexpected
454
+ // non-transient errors fall through to here.
383
455
  try {
384
456
  // Include pid for uniqueness across concurrent quarantines in the same ms.
385
457
  fs.renameSync(entry.manifestPath, entry.manifestPath + ".corrupt-" + Date.now() + "-" + process.pid);
@@ -1,4 +1,4 @@
1
- import { logInternalError } from "../utils/internal-error.ts";
1
+ import { logInternalError } from "../../utils/internal-error.ts";
2
2
 
3
3
  export type OverflowPhase = "none" | "compaction" | "retrying" | "recovered" | "failed";
4
4
 
@@ -1,4 +1,4 @@
1
- import type { PolicyDecision, PolicyDecisionReason } from "../state/types.ts";
1
+ import type { PolicyDecision, PolicyDecisionReason } from "../../state/types.ts";
2
2
 
3
3
  export type FailureScenario =
4
4
  | "trust_prompt_unresolved"
@@ -1,5 +1,5 @@
1
- import { sleep } from "../utils/sleep.ts";
2
- import { throwIfCancelled } from "./cancellation.ts";
1
+ import { sleep } from "../../utils/sleep.ts";
2
+ import { throwIfCancelled } from "../process/cancellation.ts";
3
3
 
4
4
  export interface RetryPolicy {
5
5
  maxAttempts: number;
@@ -7,11 +7,9 @@
7
7
  * - Accumulates context from previous attempts
8
8
  * - Supports exponential backoff
9
9
  * - Limits handoff accumulation to prevent memory leaks
10
- *
11
- * @see docs/pi-boomerang-integration-plan.md
12
10
  */
13
11
 
14
- import type { HandoffManager, HandoffSummary, TaskPacket, TaskResult } from "./handoff-manager.ts";
12
+ import type { HandoffManager, HandoffSummary, TaskPacket, TaskResult } from "../handoff-manager.ts";
15
13
 
16
14
  /**
17
15
  * Retry configuration.
@@ -73,7 +71,6 @@ export class RetryRunner {
73
71
 
74
72
  private taskRunner: TaskRunnerLike;
75
73
  private handoffManager: HandoffManager;
76
- private _handoffs: HandoffSummary[] = [];
77
74
 
78
75
  constructor(taskRunner: TaskRunnerLike, handoffManager: HandoffManager) {
79
76
  this.taskRunner = taskRunner;
@@ -100,7 +97,7 @@ export class RetryRunner {
100
97
  * Useful when you want to reset state without disposing.
101
98
  */
102
99
  clearHandoffs(): void {
103
- this._handoffs = [];
100
+ /* no-op: _handoffs field removed (was never read) */
104
101
  }
105
102
 
106
103
  /**
@@ -139,9 +136,6 @@ export class RetryRunner {
139
136
  const startTime = Date.now();
140
137
  const maxHandoffs = this.getMaxHandoffs(config);
141
138
 
142
- // Clear previous handoffs at start of each retry run
143
- this._handoffs = [];
144
-
145
139
  for (let attempt = 1; attempt <= config.maxAttempts; attempt++) {
146
140
  if (this._disposed) {
147
141
  throw new Error("RetryRunner was disposed during retry");
@@ -1,6 +1,6 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import { loadRunManifestById } from "../state/state-store.ts";
3
+ import { loadRunManifestById } from "../state/stores/state-store.ts";
4
4
  import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
5
5
  import { projectCrewRoot } from "../utils/paths.ts";
6
6
  import { isFinishedRunStatus } from "./process-status.ts";
@@ -26,9 +26,9 @@
26
26
  * caller-owned (they need task/manifest state that runWorker does not see).
27
27
  */
28
28
 
29
- import type { ChildPiRunInput, ChildPiRunResult } from "./child-pi.ts";
30
- import { runChildPi } from "./child-pi.ts";
31
- import { withWorkerSlot } from "./global-worker-cap.ts";
29
+ import type { ChildPiRunInput, ChildPiRunResult } from "./child-pi/child-pi.ts";
30
+ import { runChildPi } from "./child-pi/child-pi.ts";
31
+ import { withWorkerSlot } from "./scheduling/global-worker-cap.ts";
32
32
 
33
33
  /**
34
34
  * Input for {@link runWorker}. Extends {@link ChildPiRunInput} with the `cap`
@@ -27,9 +27,9 @@
27
27
  * grouping many micro-tasks into one worker prompt.
28
28
  */
29
29
 
30
- import type { TeamTaskState } from "../state/types.ts";
31
- import type { WorkflowConfig, WorkflowStep } from "../workflows/workflow-config.ts";
32
- import { permissionForRole } from "./role-permission.ts";
30
+ import type { TeamTaskState } from "../../state/types.ts";
31
+ import type { WorkflowConfig, WorkflowStep } from "../../workflows/workflow-config.ts";
32
+ import { permissionForRole } from "../role-permission.ts";
33
33
 
34
34
  /** Default cap on group size to prevent context-budget overflow. */
35
35
  export const DEFAULT_MAX_GROUP_SIZE = 5;
@@ -1,4 +1,5 @@
1
- import { DEFAULT_CONCURRENCY } from "../config/defaults.ts";
1
+ import { DEFAULT_CONCURRENCY } from "../../config/defaults.ts";
2
+ import { getWorkerCapCapacity } from "./global-worker-cap.ts";
2
3
 
3
4
  export interface ResolveBatchConcurrencyInput {
4
5
  workflowName: string;
@@ -7,6 +8,8 @@ export interface ResolveBatchConcurrencyInput {
7
8
  limitMaxConcurrentWorkers?: number;
8
9
  allowUnboundedConcurrency?: boolean;
9
10
  hardCap?: number;
11
+ /** Optional override for the global worker cap (test determinism). Defaults to getWorkerCapCapacity(). */
12
+ workerCap?: number;
10
13
  readyCount: number;
11
14
  workspaceMode?: "single" | "worktree";
12
15
  readyRoles?: string[];
@@ -45,9 +48,12 @@ export function resolveBatchConcurrency(input: ResolveBatchConcurrencyInput): Ba
45
48
  else if (teamMax !== undefined) source = "team";
46
49
  else source = "workflow";
47
50
  const hardCap = positiveInteger(input.hardCap) ?? DEFAULT_CONCURRENCY.hardCap;
48
- const maxConcurrent = input.allowUnboundedConcurrency ? requested : Math.min(requested, hardCap);
51
+ // P1-7: consult the global worker cap so the scheduler doesn't over-dispatch
52
+ // (e.g. dispatch 4 while the global semaphore holds 2 on a 4-core machine).
53
+ const workerCap = positiveInteger(input.workerCap) ?? getWorkerCapCapacity();
54
+ const maxConcurrent = input.allowUnboundedConcurrency ? requested : Math.min(requested, hardCap, workerCap);
49
55
  const readyCount = Math.max(0, Math.trunc(Number.isFinite(input.readyCount) ? input.readyCount : 0));
50
- const cappedReason = maxConcurrent < requested ? `;capped:${hardCap}` : "";
56
+ const cappedReason = maxConcurrent < requested ? `;capped:hard=${hardCap},worker=${workerCap}` : "";
51
57
  const unboundedReason = input.allowUnboundedConcurrency && requested > hardCap ? `;unbounded:${hardCap}` : "";
52
58
  return {
53
59
  maxConcurrent,
@@ -1,6 +1,6 @@
1
1
  import * as fs from "node:fs";
2
2
  import * as path from "node:path";
3
- import type { WorkflowConfig, WorkflowStep } from "../workflows/workflow-config.ts";
3
+ import type { WorkflowConfig, WorkflowStep } from "../../workflows/workflow-config.ts";
4
4
 
5
5
  export function sourcePiProjects(cwd: string): string[] {
6
6
  const sourceDir = path.join(cwd, "Source");
@@ -17,7 +17,9 @@ export function sourcePiProjects(cwd: string): string[] {
17
17
 
18
18
  export function chunkProjects(projects: string[], target = 6): string[][] {
19
19
  const chunks = Array.from({ length: Math.min(Math.max(1, target), Math.max(1, projects.length)) }, () => [] as string[]);
20
- projects.forEach((project, index) => chunks[index % chunks.length]!.push(project));
20
+ projects.forEach((project, index) => {
21
+ chunks[index % chunks.length]!.push(project);
22
+ });
21
23
  return chunks.filter((chunk) => chunk.length > 0);
22
24
  }
23
25