pi-crew 0.9.56 → 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.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +29 -0
- package/README.md +53 -5
- package/dist/index.mjs +5350 -4350
- package/docs/README.md +54 -0
- package/package.json +12 -12
- package/skills/real-test-pi-crew/SKILL.md +93 -3
- package/src/agents/discover-agents.ts +68 -10
- package/src/benchmark/feedback-loop.ts +1 -1
- package/src/config/config.ts +2 -1
- package/src/config/types.ts +12 -0
- package/src/extension/action-suggestions.ts +16 -63
- package/src/extension/async-notifier.ts +3 -3
- package/src/extension/command-completions.ts +2 -2
- package/src/extension/crew-cleanup.ts +3 -3
- package/src/extension/crew-vibes/footer.ts +4 -2
- package/src/extension/cross-extension-rpc.ts +10 -5
- package/src/extension/knowledge-injection.ts +57 -10
- package/src/extension/register.ts +2 -2
- package/src/extension/registration/artifact-cleanup.ts +41 -3
- package/src/extension/registration/commands.ts +4 -4
- package/src/extension/registration/context-builder.ts +10 -10
- package/src/extension/registration/crash-recovery-cache.ts +3 -3
- package/src/extension/registration/foreground-run-controller.ts +1 -1
- package/src/extension/registration/lazy-configurers.ts +2 -2
- package/src/extension/registration/lifecycle-handlers.ts +12 -12
- package/src/extension/registration/lifecycle.ts +2 -2
- package/src/extension/registration/observability.ts +2 -2
- package/src/extension/registration/registration-types.ts +3 -3
- package/src/extension/registration/runtime-cleanup.ts +1 -1
- package/src/extension/registration/subagent-helpers.ts +2 -2
- package/src/extension/registration/subagent-manager-setup.ts +2 -2
- package/src/extension/registration/subagent-tools.ts +21 -16
- package/src/extension/registration/team-tool.ts +108 -17
- package/src/extension/registration/viewers.ts +3 -4
- package/src/extension/registration/wire-cross-extension.ts +7 -7
- package/src/extension/rpc-hmac.ts +3 -2
- package/src/extension/run-bundle-schema.ts +13 -4
- package/src/extension/run-export.ts +2 -2
- package/src/extension/run-index.ts +2 -3
- package/src/extension/run-maintenance.ts +57 -1
- package/src/extension/team-manager-command.ts +3 -1
- package/src/extension/team-tool/anchor.ts +8 -2
- package/src/extension/team-tool/api.ts +117 -39
- package/src/extension/team-tool/cancel.ts +23 -8
- package/src/extension/team-tool/chain-executor.ts +1 -1
- package/src/extension/team-tool/dispatch/automate.ts +17 -2
- package/src/extension/team-tool/dispatch/control.ts +17 -2
- package/src/extension/team-tool/dispatch/manage.ts +34 -2
- package/src/extension/team-tool/dispatch/run.ts +17 -2
- package/src/extension/team-tool/dispatch/status.ts +37 -5
- package/src/extension/team-tool/doctor.ts +2 -2
- package/src/extension/team-tool/explain.ts +1 -1
- package/src/extension/team-tool/goal-wrap.ts +5 -5
- package/src/extension/team-tool/goal.ts +30 -9
- package/src/extension/team-tool/handle-schedule.ts +37 -19
- package/src/extension/team-tool/inspect.ts +21 -5
- package/src/extension/team-tool/lifecycle-actions.ts +53 -10
- package/src/extension/team-tool/parallel-dispatch.ts +14 -5
- package/src/extension/team-tool/param-error.ts +24 -0
- package/src/extension/team-tool/respond.ts +20 -6
- package/src/extension/team-tool/run.ts +27 -17
- package/src/extension/team-tool/status.ts +11 -5
- package/src/extension/team-tool.ts +26 -19
- package/src/hooks/registry.ts +1 -1
- package/src/i18n.ts +22 -0
- package/src/observability/event-bus.ts +1 -1
- package/src/prompt/prompt-runtime.ts +2 -2
- package/src/runtime/README.md +35 -0
- package/src/runtime/agent-control.ts +1 -1
- package/src/runtime/anchor-manager.ts +0 -2
- package/src/runtime/async-runner.ts +1 -1
- package/src/runtime/attention-events.ts +1 -1
- package/src/runtime/auto-summarize.ts +0 -2
- package/src/runtime/background-runner.ts +103 -30
- package/src/runtime/{crew-broker-child.ts → broker/crew-broker-child.ts} +2 -2
- package/src/runtime/{crew-broker-client.ts → broker/crew-broker-client.ts} +4 -7
- package/src/runtime/{crew-broker.ts → broker/crew-broker.ts} +13 -21
- package/src/runtime/chain-runner.ts +50 -5
- package/src/runtime/{child-pi-constants.ts → child-pi/child-pi-constants.ts} +1 -1
- package/src/runtime/{child-pi-kill.ts → child-pi/child-pi-kill.ts} +3 -3
- package/src/runtime/{child-pi-spawn.ts → child-pi/child-pi-spawn.ts} +28 -12
- package/src/runtime/{child-pi-steering.ts → child-pi/child-pi-steering.ts} +1 -1
- package/src/runtime/{child-pi-streams.ts → child-pi/child-pi-streams.ts} +11 -4
- package/src/runtime/{child-pi-transcript.ts → child-pi/child-pi-transcript.ts} +6 -6
- package/src/runtime/{child-pi.ts → child-pi/child-pi.ts} +28 -72
- package/src/runtime/{compact-stages → compaction/compact-stages}/bounded-tail.ts +1 -1
- package/src/runtime/{compact-stages → compaction/compact-stages}/index.ts +2 -2
- package/src/runtime/{compaction-summary.ts → compaction/compaction-summary.ts} +3 -3
- package/src/runtime/{tool-output-pruner.ts → compaction/tool-output-pruner.ts} +1 -1
- package/src/runtime/custom-tools/irc-tool.ts +2 -2
- package/src/runtime/delivery-coordinator.ts +0 -3
- package/src/runtime/diagnostic-export.ts +3 -3
- package/src/runtime/foreground-control.ts +1 -1
- package/src/runtime/foreground-watchdog.ts +1 -1
- package/src/runtime/{adaptive-plan.ts → goal-workflow/adaptive-plan.ts} +8 -8
- package/src/runtime/{dynamic-workflow-context.ts → goal-workflow/dynamic-workflow-context.ts} +16 -16
- package/src/runtime/{dynamic-workflow-runner.ts → goal-workflow/dynamic-workflow-runner.ts} +10 -10
- package/src/runtime/{goal-achievement.ts → goal-workflow/goal-achievement.ts} +3 -3
- package/src/runtime/{goal-evaluator.ts → goal-workflow/goal-evaluator.ts} +8 -8
- package/src/runtime/{goal-loop-runner.ts → goal-workflow/goal-loop-runner.ts} +27 -25
- package/src/runtime/{goal-state-store.ts → goal-workflow/goal-state-store.ts} +8 -8
- package/src/runtime/{plan-templates.ts → goal-workflow/plan-templates.ts} +1 -1
- package/src/runtime/group-join.ts +3 -3
- package/src/runtime/handoff-manager.ts +0 -2
- package/src/runtime/{heartbeat-watcher.ts → heartbeat/heartbeat-watcher.ts} +7 -7
- package/src/runtime/iteration-hooks.ts +1 -1
- package/src/runtime/{live-agent-control.ts → live-session/live-agent-control.ts} +2 -2
- package/src/runtime/{live-agent-manager.ts → live-session/live-agent-manager.ts} +4 -4
- package/src/runtime/{live-session-runtime.ts → live-session/live-session-runtime.ts} +39 -41
- package/src/runtime/manifest-cache.ts +1 -1
- package/src/runtime/{model-fallback.ts → model/model-fallback.ts} +1 -1
- package/src/runtime/{pi-args.ts → model/pi-args.ts} +20 -5
- package/src/runtime/model/provider-extensions.ts +116 -0
- package/src/runtime/{runtime-policy.ts → model/runtime-policy.ts} +2 -2
- package/src/runtime/{runtime-resolver.ts → model/runtime-resolver.ts} +3 -3
- package/src/runtime/{runtime-warmup.ts → model/runtime-warmup.ts} +8 -8
- package/src/runtime/orphan-worker-registry.ts +1 -1
- package/src/runtime/{progress-tracker.ts → output/progress-tracker.ts} +1 -1
- package/src/runtime/{result-extractor.ts → output/result-extractor.ts} +4 -4
- package/src/runtime/{sidechain-output.ts → output/sidechain-output.ts} +2 -2
- package/src/runtime/{stream-preview.ts → output/stream-preview.ts} +1 -1
- package/src/runtime/{streaming-output.ts → output/streaming-output.ts} +2 -2
- package/src/runtime/{tool-progress.ts → output/tool-progress.ts} +1 -1
- package/src/runtime/parent-guard.ts +30 -10
- package/src/runtime/pipeline-runner.ts +2 -2
- package/src/runtime/policy-engine.ts +2 -2
- package/src/runtime/{cancellation.ts → process/cancellation.ts} +1 -1
- package/src/runtime/{post-exit-stdio-guard.ts → process/post-exit-stdio-guard.ts} +1 -1
- package/src/runtime/{process-lifecycle.ts → process/process-lifecycle.ts} +3 -3
- package/src/runtime/{checkpoint.ts → recovery/checkpoint.ts} +4 -4
- package/src/runtime/{crash-recovery.ts → recovery/crash-recovery.ts} +93 -21
- package/src/runtime/{overflow-recovery.ts → recovery/overflow-recovery.ts} +1 -1
- package/src/runtime/{recovery-recipes.ts → recovery/recovery-recipes.ts} +1 -1
- package/src/runtime/{retry-executor.ts → recovery/retry-executor.ts} +2 -2
- package/src/runtime/{retry-runner.ts → recovery/retry-runner.ts} +2 -8
- package/src/runtime/run-tracker.ts +1 -1
- package/src/runtime/run-worker.ts +3 -3
- package/src/runtime/{coalesce-tasks.ts → scheduling/coalesce-tasks.ts} +3 -3
- package/src/runtime/{concurrency.ts → scheduling/concurrency.ts} +1 -1
- package/src/runtime/{parallel-research.ts → scheduling/parallel-research.ts} +4 -2
- package/src/runtime/{run-coalesced-task-group.ts → scheduling/run-coalesced-task-group.ts} +95 -36
- package/src/runtime/{task-graph-scheduler.ts → scheduling/task-graph-scheduler.ts} +1 -1
- package/src/runtime/session-resources.ts +1 -1
- package/src/runtime/settings-store.ts +1 -1
- package/src/runtime/single-agent-compose.ts +1 -0
- package/src/runtime/stale-reconciler.ts +1 -1
- package/src/runtime/subagent-manager.ts +1 -1
- package/src/runtime/supervisor-contact.ts +1 -1
- package/src/runtime/task-output-context.ts +7 -5
- package/src/runtime/task-runner/child-executor.ts +62 -22
- package/src/runtime/task-runner/live-executor.ts +8 -8
- package/src/runtime/task-runner/post-execution.ts +12 -12
- package/src/runtime/task-runner/pre-execution.ts +6 -6
- package/src/runtime/task-runner/progress.ts +1 -1
- package/src/runtime/task-runner/run-projection.ts +1 -1
- package/src/runtime/task-runner/scaffold-executor.ts +1 -1
- package/src/runtime/task-runner/state-helpers.ts +2 -2
- package/src/runtime/task-runner.ts +4 -4
- package/src/runtime/team-runner.ts +380 -139
- package/src/runtime/{completion-guard.ts → verification/completion-guard.ts} +1 -1
- package/src/runtime/{green-contract.ts → verification/green-contract.ts} +1 -1
- package/src/runtime/{post-checks.ts → verification/post-checks.ts} +4 -4
- package/src/runtime/{verification-gates.ts → verification/verification-gates.ts} +5 -5
- package/src/runtime/{verification-integrity.ts → verification/verification-integrity.ts} +1 -1
- package/src/schema/config-schema.ts +1 -0
- package/src/schema/team-tool-schema.ts +133 -177
- package/src/state/README.md +44 -0
- package/src/state/atomic-write.ts +24 -3
- package/src/state/{locks.ts → coordination/locks.ts} +118 -38
- package/src/state/{mailbox.ts → coordination/mailbox.ts} +14 -8
- package/src/state/{schedule.ts → coordination/schedule.ts} +3 -3
- package/src/state/{task-claims.ts → coordination/task-claims.ts} +1 -1
- package/src/state/decision-ledger.ts +1 -1
- package/src/state/{event-log-rotation.ts → event-log/event-log-rotation.ts} +161 -31
- package/src/state/{event-log.ts → event-log/event-log.ts} +38 -26
- package/src/state/{jsonl-writer.ts → event-log/jsonl-writer.ts} +14 -6
- package/src/state/hook-instinct-bridge.ts +2 -2
- package/src/state/{active-run-registry.ts → stores/active-run-registry.ts} +7 -7
- package/src/state/{artifact-store.ts → stores/artifact-store.ts} +62 -4
- package/src/state/{blob-store.ts → stores/blob-store.ts} +3 -3
- package/src/state/{health-store.ts → stores/health-store.ts} +3 -3
- package/src/state/{instinct-store.ts → stores/instinct-store.ts} +3 -3
- package/src/state/{observation-store.ts → stores/observation-store.ts} +2 -2
- package/src/state/{run-cache.ts → stores/run-cache.ts} +4 -4
- package/src/state/{run-graph.ts → stores/run-graph.ts} +4 -4
- package/src/state/{run-metrics.ts → stores/run-metrics.ts} +3 -3
- package/src/state/{state-store.ts → stores/state-store.ts} +236 -17
- package/src/state/types.ts +27 -3
- package/src/ui/component.ts +55 -0
- package/src/ui/crew-select-list.ts +3 -1
- package/src/ui/dashboard-panes/agents-pane.ts +1 -1
- package/src/ui/dwf-phase-display.ts +1 -1
- package/src/ui/heartbeat-aggregator.ts +1 -1
- package/src/ui/keybinding-map.ts +179 -6
- package/src/ui/layout-primitives.ts +9 -5
- package/src/ui/live-conversation-overlay.ts +1 -1
- package/src/ui/live-run-sidebar.ts +1 -1
- package/src/ui/overlay-stack.ts +148 -0
- package/src/ui/overlays/agent-picker-overlay.ts +1 -1
- package/src/ui/overlays/mailbox-compose-overlay.ts +1 -1
- package/src/ui/overlays/mailbox-detail-overlay.ts +2 -2
- package/src/ui/powerbar-publisher.ts +1 -1
- package/src/ui/render-scheduler.ts +1 -1
- package/src/ui/run-action-dispatcher.ts +3 -3
- package/src/ui/run-dashboard.ts +5 -33
- package/src/ui/run-event-bus.ts +3 -3
- package/src/ui/run-snapshot-cache.ts +37 -18
- package/src/ui/settings-overlay.ts +13 -21
- package/src/ui/snapshot-types.ts +1 -1
- package/src/ui/status-colors.ts +0 -2
- package/src/ui/terminal-status.ts +1 -1
- package/src/ui/theme-adapter.ts +33 -13
- package/src/ui/tool-renderers/index.ts +8 -0
- package/src/ui/transcript-viewer.ts +37 -13
- package/src/ui/widget/index.ts +32 -9
- package/src/ui/widget/widget-formatters.ts +62 -4
- package/src/ui/widget/widget-model.ts +2 -2
- package/src/ui/widget/widget-renderer.ts +1 -1
- package/src/utils/conflict-detect.ts +58 -5
- package/src/utils/ndjson.ts +2 -2
- package/src/utils/socket-path.ts +1 -1
- package/src/workflows/workflow-config.ts +1 -1
- package/src/worktree/cleanup.ts +1 -1
- package/src/worktree/worktree-manager.ts +88 -39
- package/workflows/chain.workflow.md +2 -2
- package/index.bundle.ts +0 -25
- package/scripts/bench-check.mjs +0 -96
- package/scripts/bench-cold-start.mjs +0 -216
- package/scripts/build-bundle.mjs +0 -92
- package/scripts/check-all-skills.ts +0 -294
- package/scripts/check-bundle-size.mjs +0 -38
- package/scripts/check-bundle-staleness.mjs +0 -97
- package/scripts/check-conflict-markers.mjs +0 -91
- package/scripts/check-lazy-imports.mjs +0 -28
- package/scripts/dev-runner.mjs +0 -106
- package/scripts/profile-startup.mjs +0 -125
- package/scripts/release-smoke.mjs +0 -74
- package/scripts/run-bench.mjs +0 -47
- package/scripts/run-real-chain.ts +0 -41
- package/scripts/smoke-team-perf.ts +0 -43
- package/scripts/test-issue-29-crash.ts +0 -111
- package/scripts/test-issue-29-e2e.ts +0 -183
- package/scripts/test-issue-29-real-runtime.ts +0 -330
- package/scripts/test-issue-29-real-tasks.ts +0 -387
- package/scripts/test-issue-29-team-tool.ts +0 -105
- package/scripts/test-runner.mjs +0 -84
- package/scripts/verify-flicker-fix.ts +0 -109
- package/scripts/verify-skill.ts +0 -550
- package/scripts/watch-bundle.mjs +0 -259
- package/scripts/watchdog-harness.ts +0 -119
- package/src/adapters/claude-adapter.ts +0 -23
- package/src/adapters/codex-adapter.ts +0 -21
- package/src/adapters/cursor-adapter.ts +0 -17
- package/src/adapters/export-util.ts +0 -143
- package/src/adapters/index.ts +0 -15
- package/src/adapters/registry.ts +0 -18
- package/src/adapters/types.ts +0 -23
- package/src/runtime/code-summary.ts +0 -292
- package/src/runtime/cross-extension-rpc.ts +0 -143
- package/src/runtime/hidden-handoff.ts +0 -407
- package/src/runtime/prose-compressor.ts +0 -162
- package/src/subagents/async-entry.ts +0 -1
- package/src/subagents/index.ts +0 -3
- package/src/subagents/live/control.ts +0 -1
- package/src/subagents/live/manager.ts +0 -1
- package/src/subagents/live/realtime.ts +0 -1
- package/src/subagents/live/session-runtime.ts +0 -1
- package/src/subagents/manager.ts +0 -1
- package/src/subagents/spawn.ts +0 -1
- package/test-integration-check.ts +0 -118
- /package/src/runtime/{broker-issuer.ts → broker/broker-issuer.ts} +0 -0
- /package/src/runtime/{crew-broker-tokens.ts → broker/crew-broker-tokens.ts} +0 -0
- /package/src/runtime/{child-pi-pool.ts → child-pi/child-pi-pool.ts} +0 -0
- /package/src/runtime/{compact-pipeline.ts → compaction/compact-pipeline.ts} +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/ansi-strip-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/blank-collapse-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/deduplicate-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/head-snap-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/tail-capture-stage.ts +0 -0
- /package/src/runtime/{compact-stages → compaction/compact-stages}/truncation-stage.ts +0 -0
- /package/src/runtime/{important-line-classifier.ts → compaction/important-line-classifier.ts} +0 -0
- /package/src/runtime/{heartbeat-gradient.ts → heartbeat/heartbeat-gradient.ts} +0 -0
- /package/src/runtime/{worker-heartbeat.ts → heartbeat/worker-heartbeat.ts} +0 -0
- /package/src/runtime/{worker-startup.ts → heartbeat/worker-startup.ts} +0 -0
- /package/src/runtime/{intercom-bridge.ts → live-session/intercom-bridge.ts} +0 -0
- /package/src/runtime/{live-control-realtime.ts → live-session/live-control-realtime.ts} +0 -0
- /package/src/runtime/{live-extension-bridge.ts → live-session/live-extension-bridge.ts} +0 -0
- /package/src/runtime/{live-irc.ts → live-session/live-irc.ts} +0 -0
- /package/src/runtime/{live-session-health.ts → live-session/live-session-health.ts} +0 -0
- /package/src/runtime/{model-resolver.ts → model/model-resolver.ts} +0 -0
- /package/src/runtime/{model-scope.ts → model/model-scope.ts} +0 -0
- /package/src/runtime/{output-validator.ts → output/output-validator.ts} +0 -0
- /package/src/runtime/{pi-json-output.ts → output/pi-json-output.ts} +0 -0
- /package/src/runtime/{progress-event-coalescer.ts → output/progress-event-coalescer.ts} +0 -0
- /package/src/runtime/{cancellation-token.ts → process/cancellation-token.ts} +0 -0
- /package/src/runtime/{zombie-scanner.ts → process/zombie-scanner.ts} +0 -0
- /package/src/runtime/{crash-classification.ts → recovery/crash-classification.ts} +0 -0
- /package/src/runtime/{batch-barrier.ts → scheduling/batch-barrier.ts} +0 -0
- /package/src/runtime/{global-worker-cap.ts → scheduling/global-worker-cap.ts} +0 -0
- /package/src/runtime/{parallel-utils.ts → scheduling/parallel-utils.ts} +0 -0
- /package/src/runtime/{scheduler.ts → scheduling/scheduler.ts} +0 -0
- /package/src/runtime/{semaphore.ts → scheduling/semaphore.ts} +0 -0
- /package/src/runtime/{task-graph.ts → scheduling/task-graph.ts} +0 -0
- /package/src/runtime/{verification-worktree.ts → verification/verification-worktree.ts} +0 -0
- /package/src/state/{event-reconstructor.ts → event-log/event-reconstructor.ts} +0 -0
- /package/src/state/{worker-atomic-writer.ts → event-log/worker-atomic-writer.ts} +0 -0
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { listRecentRuns } from "../../extension/run-index.ts";
|
|
8
|
-
import { reconcileAllStaleRuns } from "../../runtime/crash-recovery.ts";
|
|
9
8
|
import { readCrewAgents } from "../../runtime/crew-agent-records.ts";
|
|
10
9
|
import type { CrewAgentRecord } from "../../runtime/crew-agent-runtime.ts";
|
|
11
|
-
import { evictStaleLiveAgentHandles } from "../../runtime/live-agent-manager.ts";
|
|
10
|
+
import { evictStaleLiveAgentHandles } from "../../runtime/live-session/live-agent-manager.ts";
|
|
12
11
|
import type { ManifestCache } from "../../runtime/manifest-cache.ts";
|
|
13
12
|
import { isDisplayActiveRun } from "../../runtime/process-status.ts";
|
|
13
|
+
import { reconcileAllStaleRuns } from "../../runtime/recovery/crash-recovery.ts";
|
|
14
14
|
import type { TeamRunManifest } from "../../state/types.ts";
|
|
15
15
|
import type { RunSnapshotCache } from "../snapshot-types.ts";
|
|
16
16
|
import type { WidgetRun } from "./widget-types.ts";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Extracted from crew-widget.ts.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { listLiveAgents } from "../../runtime/live-agent-manager.ts";
|
|
7
|
+
import { listLiveAgents } from "../../runtime/live-session/live-agent-manager.ts";
|
|
8
8
|
import { isFinishedRunStatus } from "../../runtime/process-status.ts";
|
|
9
9
|
import { truncate } from "../../utils/visual.ts";
|
|
10
10
|
import { Box, Text } from "../layout-primitives.ts";
|
|
@@ -341,11 +341,20 @@ export function parseConflictUri(raw: string): ParsedConflictUri | null {
|
|
|
341
341
|
* Works by locating the recorded marker block by content (anchored to
|
|
342
342
|
* `entry.startLine` as the preferred match), so out-of-band edits earlier
|
|
343
343
|
* in the file that shift line numbers don't break resolution.
|
|
344
|
+
*
|
|
345
|
+
* EOL preservation: lines are split keeping each line's original ending
|
|
346
|
+
* bytes (CRLF / LF / none). Only the conflicting region is rewritten; every
|
|
347
|
+
* other line is round-tripped byte-for-byte, so a mixed-EOL file produces a
|
|
348
|
+
* minimal git diff (previously every line ending was normalised, rewriting
|
|
349
|
+
* the whole file even when only a few lines conflicted).
|
|
344
350
|
*/
|
|
345
351
|
export function spliceConflict(originalText: string, entry: ConflictEntry, replacement: string): string {
|
|
346
|
-
//
|
|
347
|
-
|
|
348
|
-
const
|
|
352
|
+
// Split preserving each line's original EOL so non-conflicting lines are
|
|
353
|
+
// round-tripped byte-for-byte (minimal git diff on mixed-EOL files).
|
|
354
|
+
const segments = splitPreservingEol(originalText);
|
|
355
|
+
// Content-only view (CR stripped) — identical to the old `split(/\r?\n/)`,
|
|
356
|
+
// so conflict detection / region matching behaviour is unchanged.
|
|
357
|
+
const lines = segments.map((s) => s.content);
|
|
349
358
|
const expected = buildRecordedRegion(entry);
|
|
350
359
|
const match = locateRegion(lines, expected, entry.startLine - 1);
|
|
351
360
|
if (!match) {
|
|
@@ -356,8 +365,52 @@ export function spliceConflict(originalText: string, entry: ConflictEntry, repla
|
|
|
356
365
|
|
|
357
366
|
const trimmed = normalizeTrailingNewline(replacement);
|
|
358
367
|
const replacementLines = trimmed.split("\n");
|
|
359
|
-
|
|
360
|
-
|
|
368
|
+
// EOL for the inserted lines: prefer the EOL that originally terminated the
|
|
369
|
+
// conflict region (local style); fall back to the file's dominant EOL.
|
|
370
|
+
const regionEol = segments[match.endIdx]?.eol ?? "";
|
|
371
|
+
const interEol = regionEol || (originalText.includes("\r\n") ? "\r\n" : "\n");
|
|
372
|
+
|
|
373
|
+
const out: string[] = [];
|
|
374
|
+
// Lines before the conflict — verbatim (original content + original EOL).
|
|
375
|
+
for (let i = 0; i < match.startIdx; i++) out.push(segments[i].content, segments[i].eol);
|
|
376
|
+
// Replacement lines — intermediate ones use the local EOL; the final one
|
|
377
|
+
// reuses the boundary EOL that originally separated the region from the
|
|
378
|
+
// following line, preserving that line's leading boundary exactly.
|
|
379
|
+
for (let i = 0; i < replacementLines.length; i++) {
|
|
380
|
+
out.push(replacementLines[i]);
|
|
381
|
+
out.push(i < replacementLines.length - 1 ? interEol : regionEol);
|
|
382
|
+
}
|
|
383
|
+
// Lines after the conflict — verbatim.
|
|
384
|
+
for (let i = match.endIdx + 1; i < segments.length; i++) out.push(segments[i].content, segments[i].eol);
|
|
385
|
+
return out.join("");
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Split `text` into `{ content, eol }` segments keeping each line's exact
|
|
390
|
+
* ending bytes. The `content` view equals `text.split(/\r?\n/)`, but the
|
|
391
|
+
* original EOL (`"\r\n"`, `"\n"`, or `""` for the final line) is retained
|
|
392
|
+
* so callers can reconstruct the text byte-for-byte.
|
|
393
|
+
*/
|
|
394
|
+
function splitPreservingEol(text: string): { content: string; eol: string }[] {
|
|
395
|
+
const segments: { content: string; eol: string }[] = [];
|
|
396
|
+
const n = text.length;
|
|
397
|
+
let i = 0;
|
|
398
|
+
while (i <= n) {
|
|
399
|
+
const nl = text.indexOf("\n", i);
|
|
400
|
+
if (nl === -1) {
|
|
401
|
+
segments.push({ content: text.slice(i), eol: "" });
|
|
402
|
+
break;
|
|
403
|
+
}
|
|
404
|
+
let contentEnd = nl;
|
|
405
|
+
let eol = "\n";
|
|
406
|
+
if (nl > 0 && text.charCodeAt(nl - 1) === 13 /* \r */) {
|
|
407
|
+
contentEnd = nl - 1;
|
|
408
|
+
eol = "\r\n";
|
|
409
|
+
}
|
|
410
|
+
segments.push({ content: text.slice(i, contentEnd), eol });
|
|
411
|
+
i = nl + 1;
|
|
412
|
+
}
|
|
413
|
+
return segments;
|
|
361
414
|
}
|
|
362
415
|
|
|
363
416
|
/** Reconstruct the recorded marker block as it should appear in the file. */
|
package/src/utils/ndjson.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ndjson.ts — Canonical broker NDJSON framing primitives (encoder + decoder
|
|
3
3
|
* + typed errors). Newline-delimited JSON, one frame per `\\n`.
|
|
4
4
|
*
|
|
5
|
-
* Moved out of the parallel-work stub `src/runtime/crew-broker-deps.ts`.
|
|
5
|
+
* Moved out of the parallel-work stub `src/runtime/broker/crew-broker-deps.ts`.
|
|
6
6
|
* The public surface (MAX_BROKER_FRAME_BYTES, BrokerError, BrokerErrorCode,
|
|
7
7
|
* encodeBrokerFrame, NdjsonDecoder) is preserved verbatim so importers
|
|
8
8
|
* can be updated with a single import-path change.
|
|
@@ -112,4 +112,4 @@ export class NdjsonDecoder {
|
|
|
112
112
|
// External re-exports
|
|
113
113
|
// ============================================================================
|
|
114
114
|
// Re-exported here for callers that import all broker primitives from ndjson.ts.
|
|
115
|
-
export { newBrokerToken } from "../runtime/crew-broker-tokens.ts";
|
|
115
|
+
export { newBrokerToken } from "../runtime/broker/crew-broker-tokens.ts";
|
package/src/utils/socket-path.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* socket-path.ts — Canonical broker Unix-socket / named-pipe path utilities.
|
|
3
3
|
*
|
|
4
|
-
* Moved out of the parallel-work stub `src/runtime/crew-broker-deps.ts`.
|
|
4
|
+
* Moved out of the parallel-work stub `src/runtime/broker/crew-broker-deps.ts`.
|
|
5
5
|
* The public surface (hashSessionId, getBrokerSocketPath,
|
|
6
6
|
* prepareBrokerSocketDir, removeStaleBrokerSocket) is preserved verbatim
|
|
7
7
|
* so importers can be updated with a single import-path change.
|
|
@@ -63,7 +63,7 @@ export interface WorkflowConfig {
|
|
|
63
63
|
* multiple ready tasks sharing role + cwd are grouped into a single
|
|
64
64
|
* multi-task worker prompt to reduce per-task cold-start cost. Disabled
|
|
65
65
|
* in v0.9.17 unless the workflow author opts in. See
|
|
66
|
-
* src/runtime/coalesce-tasks.ts. */
|
|
66
|
+
* src/runtime/scheduling/coalesce-tasks.ts. */
|
|
67
67
|
coalesceMicroTasks?: boolean;
|
|
68
68
|
}
|
|
69
69
|
|
package/src/worktree/cleanup.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { execFileSync } from "node:child_process";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { DEFAULT_PATHS } from "../config/defaults.ts";
|
|
5
|
-
import { writeArtifact } from "../state/artifact-store.ts";
|
|
5
|
+
import { writeArtifact } from "../state/stores/artifact-store.ts";
|
|
6
6
|
import type { TeamRunManifest } from "../state/types.ts";
|
|
7
7
|
import { WINDOWS_ESSENTIAL_ENV_VARS } from "../utils/env-allowlist.ts";
|
|
8
8
|
import { sanitizeEnvSecrets } from "../utils/env-filter.ts";
|
|
@@ -5,7 +5,7 @@ import * as path from "node:path";
|
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
import { loadConfig } from "../config/config.ts";
|
|
7
7
|
import { DEFAULT_PATHS } from "../config/defaults.ts";
|
|
8
|
-
import { writeArtifact } from "../state/artifact-store.ts";
|
|
8
|
+
import { writeArtifact } from "../state/stores/artifact-store.ts";
|
|
9
9
|
import type { TeamRunManifest, TeamTaskState } from "../state/types.ts";
|
|
10
10
|
import { WINDOWS_ESSENTIAL_ENV_VARS } from "../utils/env-allowlist.ts";
|
|
11
11
|
import { sanitizeEnvSecrets } from "../utils/env-filter.ts";
|
|
@@ -583,7 +583,7 @@ export function overlaySeedPaths(repoRoot: string, worktreePath: string, seedPat
|
|
|
583
583
|
* recovered via `git apply` / manual restore. Best-effort: a snapshot failure
|
|
584
584
|
* only logs (it must not block the clean-slate reuse flow).
|
|
585
585
|
*/
|
|
586
|
-
function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskState, worktreePath: string, dirtyStatus: string): boolean {
|
|
586
|
+
export function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskState, worktreePath: string, dirtyStatus: string): boolean {
|
|
587
587
|
try {
|
|
588
588
|
const parts: string[] = [
|
|
589
589
|
`# Worktree recovery snapshot`,
|
|
@@ -591,15 +591,18 @@ function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskState, w
|
|
|
591
591
|
`capturedAt: ${new Date().toISOString()}`,
|
|
592
592
|
"",
|
|
593
593
|
];
|
|
594
|
+
// ST-1: use --binary so tracked binary modifications are recoverable via `git apply`.
|
|
594
595
|
let trackedDiff = "";
|
|
595
596
|
try {
|
|
596
|
-
trackedDiff = git(worktreePath, ["diff", "HEAD"]);
|
|
597
|
+
trackedDiff = git(worktreePath, ["diff", "HEAD", "--binary"]);
|
|
597
598
|
} catch {
|
|
598
599
|
trackedDiff = "";
|
|
599
600
|
}
|
|
600
601
|
if (trackedDiff.trim()) {
|
|
601
|
-
parts.push("## Tracked changes (`git diff HEAD`)", "```diff", trackedDiff, "```", "");
|
|
602
|
+
parts.push("## Tracked changes (`git diff HEAD --binary`)", "```diff", trackedDiff, "```", "");
|
|
602
603
|
}
|
|
604
|
+
// ST-1: per-file byte cap — skip/truncate larger files with a note to avoid OOM.
|
|
605
|
+
const MAX_FILE_BYTES = 256 * 1024;
|
|
603
606
|
for (const line of dirtyStatus.split("\n")) {
|
|
604
607
|
if (!line.startsWith("?? ")) continue;
|
|
605
608
|
// Strip the "?? " prefix and surrounding git quotes.
|
|
@@ -608,8 +611,27 @@ function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskState, w
|
|
|
608
611
|
try {
|
|
609
612
|
const abs = path.join(worktreePath, rel);
|
|
610
613
|
if (!fs.existsSync(abs) || fs.statSync(abs).isDirectory()) continue;
|
|
611
|
-
|
|
612
|
-
|
|
614
|
+
// ST-1: read raw bytes (not utf-8) so binary files are not corrupted.
|
|
615
|
+
const buf = fs.readFileSync(abs);
|
|
616
|
+
const originalSize = buf.byteLength;
|
|
617
|
+
let data: Buffer = buf;
|
|
618
|
+
let note = "";
|
|
619
|
+
if (originalSize > MAX_FILE_BYTES) {
|
|
620
|
+
data = buf.subarray(0, MAX_FILE_BYTES);
|
|
621
|
+
note = ` (truncated: ${originalSize} → ${MAX_FILE_BYTES} bytes)`;
|
|
622
|
+
}
|
|
623
|
+
// ST-1: detect non-UTF-8 via fatal TextDecoder; base64-encode binary files.
|
|
624
|
+
let isUtf8 = true;
|
|
625
|
+
try {
|
|
626
|
+
new TextDecoder("utf-8", { fatal: true }).decode(data);
|
|
627
|
+
} catch {
|
|
628
|
+
isUtf8 = false;
|
|
629
|
+
}
|
|
630
|
+
if (isUtf8) {
|
|
631
|
+
parts.push(`## Untracked file: ${rel}${note}`, "```", data.toString("utf-8"), "```", "");
|
|
632
|
+
} else {
|
|
633
|
+
parts.push(`## Untracked file: ${rel}${note} (base64-encoded binary)`, "```base64", data.toString("base64"), "```", "");
|
|
634
|
+
}
|
|
613
635
|
} catch {
|
|
614
636
|
/* skip unreadable/unstat-able entry */
|
|
615
637
|
}
|
|
@@ -744,8 +766,8 @@ export function prepareTaskWorkspace(manifest: TeamRunManifest, task: TeamTaskSt
|
|
|
744
766
|
if (currentBranch !== branch) {
|
|
745
767
|
throw new Error(`Existing worktree branch mismatch at ${worktreePath}: expected '${branch}', got '${currentBranch}'.`);
|
|
746
768
|
}
|
|
747
|
-
//
|
|
748
|
-
const dirtyStatus = git(worktreePath, ["status", "--porcelain"]);
|
|
769
|
+
// ST-1: use -uall so untracked directories are expanded to individual files.
|
|
770
|
+
const dirtyStatus = git(worktreePath, ["status", "--porcelain", "-uall"]);
|
|
749
771
|
if (dirtyStatus.trim()) {
|
|
750
772
|
// Snapshot uncommitted work to a recovery artifact BEFORE discarding, so the
|
|
751
773
|
// previous run's changes are never silently destroyed on reuse.
|
|
@@ -904,7 +926,8 @@ export async function prepareTaskWorkspaceAsync(
|
|
|
904
926
|
if (currentBranch !== branch) {
|
|
905
927
|
throw new Error(`Existing worktree branch mismatch at ${worktreePath}: expected '${branch}', got '${currentBranch}'.`);
|
|
906
928
|
}
|
|
907
|
-
|
|
929
|
+
// ST-1: use -uall so untracked directories are expanded to individual files.
|
|
930
|
+
const dirtyStatus = await gitAsync(worktreePath, ["status", "--porcelain", "-uall"]);
|
|
908
931
|
if (dirtyStatus.trim()) {
|
|
909
932
|
const snapshotOk = snapshotDirtyWorktree(manifest, task, worktreePath, dirtyStatus);
|
|
910
933
|
if (snapshotOk) {
|
|
@@ -1060,52 +1083,78 @@ export async function captureWorktreeDiffAsync(worktreePath: string): Promise<st
|
|
|
1060
1083
|
* assertCleanLeader, pruneStaleWorktrees, sanitizeBranchPart,
|
|
1061
1084
|
* linkNodeModulesIfPresent) but with a minimal, task-free signature.
|
|
1062
1085
|
*
|
|
1063
|
-
* Returns `undefined` when worktree
|
|
1064
|
-
*
|
|
1086
|
+
* Returns `undefined` when worktree isolation is genuinely unavailable (no git
|
|
1087
|
+
* repo, dirty leader) so the caller (`ctx.agent`) can fall back gracefully.
|
|
1088
|
+
* ST-15: when creation was attempted but failed (e.g. disk full), this THROWS
|
|
1089
|
+
* instead of returning undefined so the caller never silently runs in the
|
|
1090
|
+
* leader repo. The branch + path suffix is non-deterministic so a 2nd call for
|
|
1091
|
+
* the same agentId always produces a distinct worktree.
|
|
1065
1092
|
*/
|
|
1066
1093
|
export function prepareAgentWorktree(manifest: TeamRunManifest, agentId: string): PreparedTaskWorkspace | undefined {
|
|
1094
|
+
// ST-15: Split preconditions from worktree creation.
|
|
1095
|
+
// Precondition failures (no git repo, dirty leader) → return undefined so the
|
|
1096
|
+
// caller falls back gracefully (worktree isolation is genuinely unavailable).
|
|
1097
|
+
let repoRoot: string;
|
|
1098
|
+
let loadedConfig: ReturnType<typeof loadConfig>;
|
|
1067
1099
|
try {
|
|
1068
|
-
|
|
1069
|
-
|
|
1100
|
+
repoRoot = findGitRoot(manifest.cwd);
|
|
1101
|
+
loadedConfig = loadConfig(manifest.cwd);
|
|
1070
1102
|
if (loadedConfig.config.requireCleanWorktreeLeader !== false) assertCleanLeader(repoRoot);
|
|
1071
|
-
const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
|
|
1072
|
-
const worktreeRoot = path.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
|
|
1073
|
-
fs.mkdirSync(worktreeRoot, { recursive: true });
|
|
1074
|
-
const sanitizedAgentId = sanitizeBranchPart(agentId);
|
|
1075
|
-
const worktreePath = path.join(worktreeRoot, sanitizedAgentId);
|
|
1076
|
-
const branch = `pi-crew/${sanitizedRunId}/${sanitizedAgentId}`;
|
|
1077
|
-
pruneStaleWorktrees(repoRoot);
|
|
1078
|
-
git(repoRoot, ["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
|
|
1079
|
-
const nodeModulesLinked =
|
|
1080
|
-
loadedConfig.config.worktree?.linkNodeModules === true ? linkNodeModulesIfPresent(repoRoot, worktreePath) : false;
|
|
1081
|
-
return { cwd: worktreePath, worktreePath, branch, nodeModulesLinked };
|
|
1082
1103
|
} catch {
|
|
1083
|
-
// Graceful fallback: no git repo
|
|
1104
|
+
// Graceful fallback: no git repo or dirty leader → run normally in cwd.
|
|
1084
1105
|
return undefined;
|
|
1085
1106
|
}
|
|
1107
|
+
|
|
1108
|
+
// ST-15: NON-DETERMINISTIC branch + path suffix. The OLD deterministic name
|
|
1109
|
+
// (`pi-crew/<runId>/<agentId>`) made a 2nd call for the same agent collide
|
|
1110
|
+
// ("already exists") → catch → returned undefined → the run silently fell
|
|
1111
|
+
// back to the leader repo (isolation lost, no error). The timestamp +
|
|
1112
|
+
// short-uuid suffix makes every call produce a distinct worktree.
|
|
1113
|
+
// Creation failures here THROW (not undefined) so callers never silently lose
|
|
1114
|
+
// isolation when worktree creation was requested but failed.
|
|
1115
|
+
const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
|
|
1116
|
+
const worktreeRoot = path.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
|
|
1117
|
+
fs.mkdirSync(worktreeRoot, { recursive: true });
|
|
1118
|
+
const sanitizedAgentId = sanitizeBranchPart(agentId);
|
|
1119
|
+
const stamp = `${Date.now()}-${randomBytes(4).toString("hex")}`;
|
|
1120
|
+
const worktreePath = path.join(worktreeRoot, `${sanitizedAgentId}-${stamp}`);
|
|
1121
|
+
const branch = `pi-crew/${sanitizedRunId}/${sanitizedAgentId}-${stamp}`;
|
|
1122
|
+
pruneStaleWorktrees(repoRoot);
|
|
1123
|
+
git(repoRoot, ["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
|
|
1124
|
+
const nodeModulesLinked =
|
|
1125
|
+
loadedConfig.config.worktree?.linkNodeModules === true ? linkNodeModulesIfPresent(repoRoot, worktreePath) : false;
|
|
1126
|
+
return { cwd: worktreePath, worktreePath, branch, nodeModulesLinked };
|
|
1086
1127
|
}
|
|
1087
1128
|
|
|
1088
1129
|
/** Async version of prepareAgentWorktree — yields the event loop during git operations. */
|
|
1089
1130
|
export async function prepareAgentWorktreeAsync(manifest: TeamRunManifest, agentId: string): Promise<PreparedTaskWorkspace | undefined> {
|
|
1131
|
+
// ST-15: Split preconditions from worktree creation (see prepareAgentWorktree).
|
|
1132
|
+
let repoRoot: string;
|
|
1133
|
+
let loadedConfig: ReturnType<typeof loadConfig>;
|
|
1090
1134
|
try {
|
|
1091
|
-
|
|
1092
|
-
|
|
1135
|
+
repoRoot = await findGitRootAsync(manifest.cwd);
|
|
1136
|
+
loadedConfig = loadConfig(manifest.cwd);
|
|
1093
1137
|
if (loadedConfig.config.requireCleanWorktreeLeader !== false) await assertCleanLeaderAsync(repoRoot);
|
|
1094
|
-
const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
|
|
1095
|
-
const worktreeRoot = path.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
|
|
1096
|
-
fs.mkdirSync(worktreeRoot, { recursive: true });
|
|
1097
|
-
const sanitizedAgentId = sanitizeBranchPart(agentId);
|
|
1098
|
-
const worktreePath = path.join(worktreeRoot, sanitizedAgentId);
|
|
1099
|
-
const branch = `pi-crew/${sanitizedRunId}/${sanitizedAgentId}`;
|
|
1100
|
-
await pruneStaleWorktreesAsync(repoRoot);
|
|
1101
|
-
await gitAsync(repoRoot, ["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
|
|
1102
|
-
const nodeModulesLinked =
|
|
1103
|
-
loadedConfig.config.worktree?.linkNodeModules === true ? linkNodeModulesIfPresent(repoRoot, worktreePath) : false;
|
|
1104
|
-
return { cwd: worktreePath, worktreePath, branch, nodeModulesLinked };
|
|
1105
1138
|
} catch {
|
|
1106
|
-
// Graceful fallback: no git repo
|
|
1139
|
+
// Graceful fallback: no git repo or dirty leader → run normally in cwd.
|
|
1107
1140
|
return undefined;
|
|
1108
1141
|
}
|
|
1142
|
+
|
|
1143
|
+
// ST-15: NON-DETERMINISTIC branch + path suffix — a 2nd call for the same
|
|
1144
|
+
// agentId creates a DISTINCT worktree instead of colliding. Creation failures
|
|
1145
|
+
// here THROW so callers never silently fall back to the leader repo.
|
|
1146
|
+
const sanitizedRunId = manifest.runId.replace(/[^a-zA-Z0-9._-]/g, "-").replace(/^-+|-+$/g, "") || "run";
|
|
1147
|
+
const worktreeRoot = path.join(projectCrewRoot(manifest.cwd), DEFAULT_PATHS.state.worktreesSubdir, sanitizedRunId);
|
|
1148
|
+
fs.mkdirSync(worktreeRoot, { recursive: true });
|
|
1149
|
+
const sanitizedAgentId = sanitizeBranchPart(agentId);
|
|
1150
|
+
const stamp = `${Date.now()}-${randomBytes(4).toString("hex")}`;
|
|
1151
|
+
const worktreePath = path.join(worktreeRoot, `${sanitizedAgentId}-${stamp}`);
|
|
1152
|
+
const branch = `pi-crew/${sanitizedRunId}/${sanitizedAgentId}-${stamp}`;
|
|
1153
|
+
await pruneStaleWorktreesAsync(repoRoot);
|
|
1154
|
+
await gitAsync(repoRoot, ["worktree", "add", "-b", branch, worktreePath, "HEAD"]);
|
|
1155
|
+
const nodeModulesLinked =
|
|
1156
|
+
loadedConfig.config.worktree?.linkNodeModules === true ? linkNodeModulesIfPresent(repoRoot, worktreePath) : false;
|
|
1157
|
+
return { cwd: worktreePath, worktreePath, branch, nodeModulesLinked };
|
|
1109
1158
|
}
|
|
1110
1159
|
|
|
1111
1160
|
/**
|
|
@@ -6,7 +6,7 @@ topology: dynamic
|
|
|
6
6
|
|
|
7
7
|
# Chain Workflow - Sequential execution with context passing
|
|
8
8
|
|
|
9
|
-
**Source:**
|
|
9
|
+
**Source:** pi-boomerang integration plan
|
|
10
10
|
**Syntax:** `step1 -> step2 -> step3`
|
|
11
11
|
**Version:** 1.0.0
|
|
12
12
|
|
|
@@ -255,4 +255,4 @@ pi team run --chain "@step1 -> @step2" --continue-on-error
|
|
|
255
255
|
|
|
256
256
|
---
|
|
257
257
|
|
|
258
|
-
*Generated from pi-boomerang integration plan
|
|
258
|
+
*Generated from pi-boomerang integration plan.*
|
package/index.bundle.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bundle entry point — NO shell logic.
|
|
3
|
-
*
|
|
4
|
-
* Bundled by `scripts/build-bundle.mjs` into `dist/index.mjs`. Keep this
|
|
5
|
-
* file minimal — the bundle should NOT try to recursively load itself
|
|
6
|
-
* or do path resolution. The shell (load-with-fallback) lives in
|
|
7
|
-
* `index.ts`; this file just re-exports the inner extension API so the
|
|
8
|
-
* bundle is a single self-contained module the shell can `import()`.
|
|
9
|
-
*
|
|
10
|
-
* Why a separate file from `index.ts`:
|
|
11
|
-
* - `index.ts` runs at the package root and resolves `dist/index.mjs`
|
|
12
|
-
* relative to its own location.
|
|
13
|
-
* - If the bundle were built FROM `index.ts`, the bundled code would
|
|
14
|
-
* resolve `dist/index.mjs` relative to ITS OWN location (inside
|
|
15
|
-
* `dist/`), producing `dist/dist/index.mjs` and a recursion error.
|
|
16
|
-
* - Building from `index.bundle.ts` (which has no shell) sidesteps
|
|
17
|
-
* this chicken-and-egg entirely.
|
|
18
|
-
*/
|
|
19
|
-
import { registerPiTeams } from "./src/extension/register.ts";
|
|
20
|
-
import { waitForRun } from "./src/runtime/run-tracker.ts";
|
|
21
|
-
|
|
22
|
-
export { waitForRun, registerPiTeams };
|
|
23
|
-
export default function (pi: Parameters<typeof registerPiTeams>[0]): void {
|
|
24
|
-
registerPiTeams(pi);
|
|
25
|
-
}
|
package/scripts/bench-check.mjs
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Compare test/bench/results.json against test/bench/baseline.json.
|
|
4
|
-
*
|
|
5
|
-
* Fails if any p95 metric regresses by more than the allowed threshold.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* npm run bench:check # default 15% threshold
|
|
9
|
-
* THRESHOLD_PCT=10 npm run bench:check # tighter
|
|
10
|
-
* BASELINE=test/bench/baseline.json npm run bench:check
|
|
11
|
-
*/
|
|
12
|
-
import * as fs from "node:fs";
|
|
13
|
-
import * as path from "node:path";
|
|
14
|
-
|
|
15
|
-
const root = path.resolve(import.meta.dirname, "..");
|
|
16
|
-
const benchDir = path.join(root, "test", "bench");
|
|
17
|
-
const resultsPath = path.join(benchDir, "results.json");
|
|
18
|
-
const baselinePath = process.env.BASELINE ? path.resolve(process.env.BASELINE) : path.join(benchDir, "baseline.json");
|
|
19
|
-
const threshold = Number(process.env.THRESHOLD_PCT ?? 15) / 100;
|
|
20
|
-
|
|
21
|
-
if (!fs.existsSync(resultsPath)) {
|
|
22
|
-
console.error(`[bench:check] missing ${resultsPath}; run \`npm run bench\` first.`);
|
|
23
|
-
process.exit(2);
|
|
24
|
-
}
|
|
25
|
-
if (!fs.existsSync(baselinePath)) {
|
|
26
|
-
console.error(`[bench:check] missing baseline ${baselinePath}.`);
|
|
27
|
-
console.error(" Capture baseline with: npm run bench && cp test/bench/results.json test/bench/baseline.json");
|
|
28
|
-
process.exit(2);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const results = JSON.parse(fs.readFileSync(resultsPath, "utf-8"));
|
|
32
|
-
const baseline = JSON.parse(fs.readFileSync(baselinePath, "utf-8"));
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Walk each bench's nested numeric metrics and pair with baseline.
|
|
36
|
-
* Reports any p95 metric where current > baseline * (1 + threshold).
|
|
37
|
-
*/
|
|
38
|
-
const regressions = [];
|
|
39
|
-
const improvements = [];
|
|
40
|
-
for (const [benchName, current] of Object.entries(results.results)) {
|
|
41
|
-
const base = baseline.results?.[benchName];
|
|
42
|
-
if (!base) {
|
|
43
|
-
console.log(`[bench:check] no baseline for ${benchName} — skipping`);
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
for (const metric of metricKeys(current)) {
|
|
47
|
-
const cur = readPath(current, metric);
|
|
48
|
-
const ref = readPath(base, metric);
|
|
49
|
-
if (typeof cur !== "number" || typeof ref !== "number" || ref === 0) continue;
|
|
50
|
-
// Sub-ms metrics are dominated by GC / OS jitter — applying a strict
|
|
51
|
-
// percentage gate causes false positives. Use absolute delta cap instead.
|
|
52
|
-
if (ref < 1.0) {
|
|
53
|
-
const absDelta = cur - ref;
|
|
54
|
-
if (absDelta > 0.5) regressions.push({ bench: benchName, metric: metric.join("."), baseline: ref, current: cur, deltaPct: round(((cur - ref) / ref) * 100), reason: "abs > 0.5ms" });
|
|
55
|
-
else if (absDelta < -0.05) improvements.push({ bench: benchName, metric: metric.join("."), baseline: ref, current: cur, deltaPct: round(((cur - ref) / ref) * 100) });
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
const delta = (cur - ref) / ref;
|
|
59
|
-
if (delta > threshold) regressions.push({ bench: benchName, metric: metric.join("."), baseline: ref, current: cur, deltaPct: round(delta * 100) });
|
|
60
|
-
else if (delta < -0.05) improvements.push({ bench: benchName, metric: metric.join("."), baseline: ref, current: cur, deltaPct: round(delta * 100) });
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (improvements.length) {
|
|
65
|
-
console.log("[bench:check] improvements:");
|
|
66
|
-
for (const item of improvements) console.log(` ${item.bench}.${item.metric}: ${item.baseline} → ${item.current} (${item.deltaPct}%)`);
|
|
67
|
-
}
|
|
68
|
-
if (regressions.length) {
|
|
69
|
-
console.error(`[bench:check] regressions (>${(threshold * 100).toFixed(0)}%):`);
|
|
70
|
-
for (const item of regressions) console.error(` ${item.bench}.${item.metric}: ${item.baseline} → ${item.current} (+${item.deltaPct}%)`);
|
|
71
|
-
process.exit(1);
|
|
72
|
-
}
|
|
73
|
-
console.log(`[bench:check] all benches within ${(threshold * 100).toFixed(0)}% of baseline.`);
|
|
74
|
-
|
|
75
|
-
function metricKeys(obj, prefix = []) {
|
|
76
|
-
const skip = new Set(["name", "unit", "iters", "tasks", "events", "eventsPerIter"]);
|
|
77
|
-
const keys = [];
|
|
78
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
79
|
-
if (skip.has(k)) continue;
|
|
80
|
-
if (k === "p50" || k === "p95" || k === "p99" || k === "min" || k === "max") {
|
|
81
|
-
// We only gate on p95; min/max printed but not enforced.
|
|
82
|
-
if (k === "p95") keys.push([...prefix, k]);
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
if (v && typeof v === "object" && !Array.isArray(v)) keys.push(...metricKeys(v, [...prefix, k]));
|
|
86
|
-
}
|
|
87
|
-
return keys;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function readPath(obj, parts) {
|
|
91
|
-
let cur = obj;
|
|
92
|
-
for (const p of parts) cur = cur?.[p];
|
|
93
|
-
return cur;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function round(n) { return Math.round(n * 100) / 100; }
|