pi-crew 0.11.0 → 0.11.2
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/CHANGELOG.md +155 -9
- package/README.md +161 -1037
- package/agents/verifier.md +18 -7
- package/dist/index.mjs +744 -90644
- package/docs/README.md +57 -46
- package/docs/architecture.md +87 -33
- package/docs/commands-reference.md +9 -5
- package/docs/troubleshooting.md +3 -2
- package/package.json +1 -3
- package/schema.json +39 -0
- package/skills/real-test-pi-crew/REPORT-TEMPLATE.md +2 -0
- package/skills/real-test-pi-crew/SKILL.md +371 -34
- package/src/agents/agent-config.ts +1 -1
- package/src/agents/discover-agents.ts +1 -1
- package/src/config/config-validation.ts +15 -2
- package/src/config/config.ts +47 -13
- package/src/config/defaults.ts +0 -1
- package/src/config/env-vars.ts +35 -0
- package/src/config/types.ts +19 -5
- package/src/errors.ts +2 -2
- package/src/extension/async-notifier.ts +23 -0
- package/src/extension/crew-vibes/config.ts +0 -21
- package/src/extension/crew-vibes/index.ts +0 -2
- package/src/extension/crew-vibes/render.ts +1 -50
- package/src/extension/help.ts +21 -12
- package/src/extension/knowledge-injection.ts +2 -1
- package/src/extension/management.ts +8 -3
- package/src/extension/notification-sink.ts +17 -0
- package/src/extension/register.ts +7 -2
- package/src/extension/registration/command-utils.ts +28 -2
- package/src/extension/registration/commands/dashboard.ts +11 -1
- package/src/extension/registration/commands/manage.ts +36 -19
- package/src/extension/registration/commands/run.ts +24 -2
- package/src/extension/registration/commands/shared.ts +23 -1
- package/src/extension/registration/commands/status.ts +25 -2
- package/src/extension/registration/context-builder.ts +8 -2
- package/src/extension/registration/health-notify-policy.ts +100 -0
- package/src/extension/registration/lazy-configurers.ts +35 -0
- package/src/extension/registration/lifecycle-handlers.ts +91 -30
- package/src/extension/registration/lifecycle.ts +75 -10
- package/src/extension/registration/observability.ts +98 -35
- package/src/extension/registration/registration-types.ts +7 -5
- package/src/extension/registration/runtime-cleanup.ts +9 -3
- package/src/extension/registration/subagent-helpers.ts +38 -0
- package/src/extension/registration/subagent-tools.ts +16 -6
- package/src/extension/registration/team-tool.ts +10 -3
- package/src/extension/registration/terminal-status-wiring.ts +172 -0
- package/src/extension/registration/viewers.ts +6 -0
- package/src/extension/registration/wire-cross-extension.ts +28 -0
- package/src/extension/run-compare.ts +220 -0
- package/src/extension/run-export.ts +37 -5
- package/src/extension/run-maintenance.ts +155 -5
- package/src/extension/team-tool/dispatch/index.ts +3 -2
- package/src/extension/team-tool/dispatch/manage.ts +5 -2
- package/src/extension/team-tool/goal.ts +4 -1
- package/src/extension/team-tool/handle-settings.ts +33 -4
- package/src/extension/team-tool/health-monitor.ts +21 -7
- package/src/extension/team-tool/lifecycle-actions.ts +49 -1
- package/src/extension/team-tool/plan.ts +10 -0
- package/src/extension/team-tool/routing-hint.ts +63 -0
- package/src/extension/team-tool/status.ts +4 -0
- package/src/extension/team-tool.ts +52 -6
- package/src/extension/webhook-notify.ts +382 -0
- package/src/observability/metric-sink.ts +12 -2
- package/src/prompt/prompt-runtime.ts +82 -31
- package/src/prompt/worker-events-channel.ts +12 -0
- package/src/runtime/README.md +1 -1
- package/src/runtime/async-runner.ts +87 -1
- package/src/runtime/background-runner.ts +313 -234
- package/src/runtime/broker/crew-broker.ts +17 -11
- package/src/runtime/broker/delegate/shadow-lifecycle.ts +92 -0
- package/src/runtime/broker/wait-status-cache.ts +1 -1
- package/src/runtime/child-pi/child-pi-timers.ts +1 -1
- package/src/runtime/child-pi/mock-fixtures.ts +48 -0
- package/src/runtime/crew-agent-records.ts +337 -45
- package/src/runtime/deadletter.ts +43 -1
- package/src/runtime/delegate-spawn.ts +5 -1
- package/src/runtime/dispatch-batch.ts +72 -5
- package/src/runtime/goal-workflow/goal-loop-runner.ts +73 -4
- package/src/runtime/heartbeat/heartbeat-watcher.ts +7 -0
- package/src/runtime/model/model-fallback.ts +21 -1
- package/src/runtime/model/pi-args.ts +8 -10
- package/src/runtime/recovery/crash-recovery.ts +25 -1
- package/src/runtime/run-worker.ts +12 -1
- package/src/runtime/scheduling/global-worker-cap.ts +13 -6
- package/src/runtime/scheduling/run-coalesced-task-group.ts +27 -1
- package/src/runtime/scheduling/scheduler.ts +49 -13
- package/src/runtime/scheduling/semaphore.ts +148 -20
- package/src/runtime/scratchpad/README.md +1 -1
- package/src/runtime/scratchpad/protocol.ts +1 -1
- package/src/runtime/settings-store.ts +1 -1
- package/src/runtime/skill-instructions.ts +22 -0
- package/src/runtime/stale-reconciler.ts +85 -13
- package/src/runtime/task-display.ts +1 -1
- package/src/runtime/task-runner/pre-execution.ts +26 -2
- package/src/runtime/task-runner/prompt-builder.ts +142 -45
- package/src/runtime/task-runner.ts +21 -1
- package/src/runtime/team-runner.ts +38 -1
- package/src/runtime/workspace-lock.ts +4 -1
- package/src/schema/config-schema.ts +18 -0
- package/src/schema/team-tool-schema.ts +17 -0
- package/src/state/atomic-write.ts +53 -0
- package/src/state/contracts.ts +109 -0
- package/src/state/coordination/locks.ts +191 -33
- package/src/state/coordination/mailbox.ts +140 -15
- package/src/state/crew-init.ts +87 -12
- package/src/state/event-log/cursor.ts +37 -1
- package/src/state/event-log/event-log-rotation.ts +72 -7
- package/src/state/stores/active-run-registry.ts +13 -1
- package/src/state/stores/state-store.ts +112 -22
- package/src/state/types.ts +4 -0
- package/src/ui/adaptive-card.ts +65 -0
- package/src/ui/agents-jobs-browser.ts +70 -64
- package/src/ui/card-colors.ts +36 -7
- package/src/ui/dashboard-panes/agents-pane.ts +55 -14
- package/src/ui/dashboard-panes/cancellation-pane.ts +0 -42
- package/src/ui/dashboard-panes/health-pane.ts +7 -5
- package/src/ui/dashboard-panes/mailbox-pane.ts +22 -6
- package/src/ui/dashboard-panes/metrics-pane.ts +15 -7
- package/src/ui/dashboard-panes/pane-theme.ts +21 -0
- package/src/ui/dashboard-panes/plan-pane.ts +63 -30
- package/src/ui/dashboard-panes/progress-pane.ts +3 -2
- package/src/ui/dashboard-panes/schedules-pane.ts +44 -21
- package/src/ui/dashboard-panes/transcript-pane.ts +11 -5
- package/src/ui/dwf-phase-display.ts +3 -20
- package/src/ui/format-helpers.ts +22 -0
- package/src/ui/heartbeat-aggregator.ts +34 -0
- package/src/ui/inline-panel/crew-editor.ts +13 -3
- package/src/ui/inline-panel/index.ts +60 -4
- package/src/ui/keybinding-map.ts +251 -35
- package/src/ui/live-conversation-overlay.ts +180 -47
- package/src/ui/live-run-sidebar.ts +134 -55
- package/src/ui/mascot.ts +32 -16
- package/src/ui/overlays/agent-picker-overlay.ts +81 -26
- package/src/ui/overlays/confirm-overlay.ts +55 -29
- package/src/ui/overlays/help-overlay.ts +108 -53
- package/src/ui/overlays/mailbox-compose-overlay.ts +89 -50
- package/src/ui/overlays/mailbox-detail-overlay.ts +137 -57
- package/src/ui/powerbar-publisher.ts +0 -1
- package/src/ui/rail.ts +333 -0
- package/src/ui/run-dashboard.ts +193 -79
- package/src/ui/run-snapshot-cache.ts +18 -1
- package/src/ui/settings-overlay.ts +81 -39
- package/src/ui/spinner.ts +26 -2
- package/src/ui/terminal-status.ts +7 -1
- package/src/ui/theme-adapter.ts +0 -45
- package/src/ui/theme-discovery.ts +12 -6
- package/src/ui/tool-progress-formatter.ts +128 -9
- package/src/ui/tool-renderers/brief-mode.ts +10 -67
- package/src/ui/tool-renderers/index.ts +374 -523
- package/src/ui/transcript-viewer.ts +30 -12
- package/src/ui/widget/index.ts +32 -52
- package/src/ui/widget/task-list.ts +64 -32
- package/src/ui/widget/widget-formatters.ts +3 -402
- package/src/ui/widget/widget-model.ts +28 -7
- package/src/ui/widget/widget-renderer.ts +201 -128
- package/src/ui/widget/widget-types.ts +0 -2
- package/src/utils/incremental-reader.ts +11 -3
- package/src/utils/paths.ts +94 -12
- package/src/utils/project-markers.ts +40 -0
- package/src/utils/visual.ts +0 -4
- package/src/worktree/worktree-manager.ts +206 -26
- package/workflows/distill.workflow.md +3 -3
- package/workflows/fast-fix.workflow.md +1 -1
- package/workflows/plan-execute.workflow.md +1 -1
- package/workflows/review.workflow.md +1 -1
- package/workflows/strict-fast-fix.workflow.md +1 -1
- package/docs/migration-v0.4-v0.5.md +0 -208
- package/docs/runtime-flow.md +0 -148
- package/src/extension/crew-vibes/figures.ts +0 -22
- package/src/extension/crew-vibes/font-detect.ts +0 -71
- package/src/ui/dynamic-border.ts +0 -35
- package/src/ui/loaders.ts +0 -6
- package/src/ui/overlay-stack.ts +0 -148
|
@@ -21,6 +21,19 @@ export interface PreparedTaskWorkspace {
|
|
|
21
21
|
syntheticPaths?: string[];
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Options for prepareTaskWorkspace / prepareTaskWorkspaceAsync (RR-010).
|
|
26
|
+
*/
|
|
27
|
+
export interface PrepareTaskWorkspaceOptions {
|
|
28
|
+
/**
|
|
29
|
+
* RR-010 / AGENTS.md rule 40: allow discarding a dirty reused worktree EVEN
|
|
30
|
+
* WHEN the recovery snapshot is incomplete (truncated/skipped entries, failed
|
|
31
|
+
* tracked diff). Explicit per-call escape hatch — deliberately NOT a global
|
|
32
|
+
* config flag, so approval cannot silently become permanent.
|
|
33
|
+
*/
|
|
34
|
+
force?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
24
37
|
const execFileAsync = promisify(execFile);
|
|
25
38
|
|
|
26
39
|
export interface WorktreeDiffStat {
|
|
@@ -657,14 +670,140 @@ export function overlaySeedPaths(repoRoot: string, worktreePath: string, seedPat
|
|
|
657
670
|
}
|
|
658
671
|
}
|
|
659
672
|
|
|
673
|
+
/**
|
|
674
|
+
* Per-file byte cap for the recovery-snapshot PREVIEW (ST-1, kept at 256 KiB so
|
|
675
|
+
* the artifact stays readable). RR-010 (F01): the cap now ALSO bounds how many
|
|
676
|
+
* bytes are read (allocation bound) and marks over-cap entries as an
|
|
677
|
+
* INCOMPLETE backup — completeness, not preview size, gates the destructive
|
|
678
|
+
* reuse cleanup (AGENTS.md rule 40).
|
|
679
|
+
*/
|
|
680
|
+
export const SNAPSHOT_MAX_FILE_BYTES = 256 * 1024;
|
|
681
|
+
|
|
682
|
+
/** Entry whose backup was cut at SNAPSHOT_MAX_FILE_BYTES (partial capture). */
|
|
683
|
+
export interface WorktreeSnapshotTruncatedEntry {
|
|
684
|
+
/** Repo-relative path of the entry. */
|
|
685
|
+
path: string;
|
|
686
|
+
/** On-disk size in bytes BEFORE truncation (not the truncated size). */
|
|
687
|
+
originalSize: number;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/** Entry that could not be backed up at all — absent from the artifact content. */
|
|
691
|
+
export interface WorktreeSnapshotSkippedEntry {
|
|
692
|
+
/** Repo-relative path of the entry. */
|
|
693
|
+
path: string;
|
|
694
|
+
/** Why the entry was skipped (unreadable, unstat-able, missing, directory...). */
|
|
695
|
+
reason: string;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
/**
|
|
699
|
+
* Structured result of a dirty-worktree recovery snapshot (RR-010 / F01).
|
|
700
|
+
*
|
|
701
|
+
* A bare boolean could not distinguish "artifact written" from "backup
|
|
702
|
+
* complete": truncation at the cap, unreadable entries and a failed tracked
|
|
703
|
+
* diff all used to return `true`, so the reuse path ran `git checkout -- .` +
|
|
704
|
+
* `git clean -fd` and destroyed data the artifact never contained. `complete`
|
|
705
|
+
* is the invariant `truncated/skipped empty && no diff/write error` — callers
|
|
706
|
+
* must gate the destructive cleanup on it via shouldDiscardDirtyWorktree.
|
|
707
|
+
*/
|
|
708
|
+
export interface WorktreeSnapshotResult {
|
|
709
|
+
/** True ONLY when every dirty entry was fully backed up and the tracked diff (if any) was captured. */
|
|
710
|
+
complete: boolean;
|
|
711
|
+
/** Entries backed up only partially (cut at the preview cap). */
|
|
712
|
+
truncated: WorktreeSnapshotTruncatedEntry[];
|
|
713
|
+
/** Entries that could not be backed up at all. */
|
|
714
|
+
skipped: WorktreeSnapshotSkippedEntry[];
|
|
715
|
+
/** Set when `git diff HEAD --binary` failed — tracked changes may be lost. */
|
|
716
|
+
trackedDiffError?: string;
|
|
717
|
+
/** Set when writing the recovery artifact itself failed (the old `false`). */
|
|
718
|
+
writeError?: string;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
/**
|
|
722
|
+
* Pure, git-free gate for the destructive reuse cleanup (RR-010 AC4): discard
|
|
723
|
+
* dirty worktree content ONLY when the snapshot is complete, or when the caller
|
|
724
|
+
* explicitly set `force` (AGENTS.md rule 40). Fail CLOSED — when in doubt,
|
|
725
|
+
* preserve the worktree.
|
|
726
|
+
*/
|
|
727
|
+
export function shouldDiscardDirtyWorktree(result: WorktreeSnapshotResult, force: boolean): boolean {
|
|
728
|
+
return force || result.complete;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Allocation-bounded file read for the recovery snapshot (RR-010 AC5).
|
|
733
|
+
* Opens the file and reads at most `cap` bytes — `readFileSync` would allocate
|
|
734
|
+
* the WHOLE file in memory just to truncate it afterwards, so a multi-GiB
|
|
735
|
+
* untracked file could OOM the snapshot path. A short read (file shrank
|
|
736
|
+
* mid-read) is reported as truncated so it can never count as a complete
|
|
737
|
+
* backup (fail closed).
|
|
738
|
+
*/
|
|
739
|
+
export function readFileCappedForSnapshot(abs: string, cap: number): { data: Buffer; originalSize: number; truncated: boolean } {
|
|
740
|
+
const fd = fs.openSync(abs, "r");
|
|
741
|
+
try {
|
|
742
|
+
const originalSize = fs.fstatSync(fd).size;
|
|
743
|
+
const want = Math.min(originalSize, cap);
|
|
744
|
+
const data = Buffer.alloc(want);
|
|
745
|
+
let read = 0;
|
|
746
|
+
while (read < want) {
|
|
747
|
+
const n = fs.readSync(fd, data, read, want - read, read);
|
|
748
|
+
if (n <= 0) break;
|
|
749
|
+
read += n;
|
|
750
|
+
}
|
|
751
|
+
return {
|
|
752
|
+
data: read === want ? data : data.subarray(0, read),
|
|
753
|
+
originalSize,
|
|
754
|
+
truncated: read < want || originalSize > cap,
|
|
755
|
+
};
|
|
756
|
+
} finally {
|
|
757
|
+
fs.closeSync(fd);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
/** Human-readable incompleteness summary for the dirtyPreserved log (RR-010). */
|
|
762
|
+
function describeIncompleteSnapshot(result: WorktreeSnapshotResult): string {
|
|
763
|
+
const reasons: string[] = [];
|
|
764
|
+
if (result.writeError !== undefined) reasons.push(`snapshot write failed: ${result.writeError}`);
|
|
765
|
+
if (result.trackedDiffError !== undefined) reasons.push(`tracked diff capture failed: ${result.trackedDiffError}`);
|
|
766
|
+
if (result.truncated.length > 0)
|
|
767
|
+
reasons.push(
|
|
768
|
+
`${result.truncated.length} file(s) exceeded the ${SNAPSHOT_MAX_FILE_BYTES}-byte cap: ${result.truncated
|
|
769
|
+
.map((e) => `${e.path} (${e.originalSize} bytes)`)
|
|
770
|
+
.join(", ")}`,
|
|
771
|
+
);
|
|
772
|
+
if (result.skipped.length > 0)
|
|
773
|
+
reasons.push(
|
|
774
|
+
`${result.skipped.length} unreadable/unstat-able entries: ${result.skipped.map((e) => `${e.path} (${e.reason})`).join(", ")}`,
|
|
775
|
+
);
|
|
776
|
+
return reasons.length > 0 ? ` — ${reasons.join("; ")}` : "";
|
|
777
|
+
}
|
|
778
|
+
|
|
660
779
|
/**
|
|
661
780
|
* Snapshot uncommitted work in a reused worktree to a recovery artifact BEFORE
|
|
662
781
|
* discarding it, so the data is never silently lost. Captures tracked changes
|
|
663
782
|
* (git diff HEAD) and inlines untracked file contents so the work can be
|
|
664
|
-
* recovered via `git apply` / manual restore.
|
|
665
|
-
*
|
|
783
|
+
* recovered via `git apply` / manual restore.
|
|
784
|
+
*
|
|
785
|
+
* RR-010 (F01) — returns a structured WorktreeSnapshotResult. An artifact that
|
|
786
|
+
* was written is NOT proof the backup is complete: truncated (over-cap /
|
|
787
|
+
* short-read) entries, unreadable entries and a failed tracked diff all surface
|
|
788
|
+
* in the result so callers can refuse the destructive cleanup
|
|
789
|
+
* (shouldDiscardDirtyWorktree). Design choice (RR-010 design.md §3–§4):
|
|
790
|
+
* structured result + pure predicate over raising the cap (moves the boundary,
|
|
791
|
+
* does not remove it), louder warnings (violates AGENTS.md rule 40), full
|
|
792
|
+
* base64 (artifact size explodes), dropping cleanup entirely (breaks
|
|
793
|
+
* clean-slate reuse; `force` stays as the escape hatch) and `git stash` (also a
|
|
794
|
+
* destructive git op with no artifact trail). The 256 KiB PREVIEW cap is kept
|
|
795
|
+
* on purpose — backup completeness, not preview size, gates cleanup.
|
|
666
796
|
*/
|
|
667
|
-
export function snapshotDirtyWorktree(
|
|
797
|
+
export function snapshotDirtyWorktree(
|
|
798
|
+
manifest: TeamRunManifest,
|
|
799
|
+
task: TeamTaskState,
|
|
800
|
+
worktreePath: string,
|
|
801
|
+
dirtyStatus: string,
|
|
802
|
+
): WorktreeSnapshotResult {
|
|
803
|
+
const truncated: WorktreeSnapshotTruncatedEntry[] = [];
|
|
804
|
+
const skipped: WorktreeSnapshotSkippedEntry[] = [];
|
|
805
|
+
let trackedDiffError: string | undefined;
|
|
806
|
+
let writeError: string | undefined;
|
|
668
807
|
try {
|
|
669
808
|
const parts: string[] = [
|
|
670
809
|
`# Worktree recovery snapshot`,
|
|
@@ -676,14 +815,16 @@ export function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskS
|
|
|
676
815
|
let trackedDiff = "";
|
|
677
816
|
try {
|
|
678
817
|
trackedDiff = git(worktreePath, ["diff", "HEAD", "--binary"]);
|
|
679
|
-
} catch {
|
|
818
|
+
} catch (err) {
|
|
819
|
+
// RR-010: "" stays reserved for the legitimate "no tracked changes" outcome —
|
|
820
|
+
// a FAILED diff is an incomplete backup (tracked edits would be destroyed by
|
|
821
|
+
// `git checkout -- .` with no copy anywhere).
|
|
680
822
|
trackedDiff = "";
|
|
823
|
+
trackedDiffError = err instanceof Error ? err.message : String(err);
|
|
681
824
|
}
|
|
682
825
|
if (trackedDiff.trim()) {
|
|
683
826
|
parts.push("## Tracked changes (`git diff HEAD --binary`)", "```diff", trackedDiff, "```", "");
|
|
684
827
|
}
|
|
685
|
-
// ST-1: per-file byte cap — skip/truncate larger files with a note to avoid OOM.
|
|
686
|
-
const MAX_FILE_BYTES = 256 * 1024;
|
|
687
828
|
for (const line of dirtyStatus.split("\n")) {
|
|
688
829
|
if (!line.startsWith("?? ")) continue;
|
|
689
830
|
// Strip the "?? " prefix and surrounding git quotes.
|
|
@@ -691,15 +832,24 @@ export function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskS
|
|
|
691
832
|
if (!rel) continue;
|
|
692
833
|
try {
|
|
693
834
|
const abs = path.join(worktreePath, rel);
|
|
694
|
-
if (!fs.existsSync(abs)
|
|
835
|
+
if (!fs.existsSync(abs)) {
|
|
836
|
+
// RR-010: record instead of silently `continue` — a vanished entry is
|
|
837
|
+
// unexplained and must fail CLOSED (preserve, do not clean).
|
|
838
|
+
skipped.push({ path: rel, reason: "not found (deleted between status and snapshot?)" });
|
|
839
|
+
continue;
|
|
840
|
+
}
|
|
841
|
+
if (fs.statSync(abs).isDirectory()) {
|
|
842
|
+
skipped.push({ path: rel, reason: "directory entry — individual files must be captured instead" });
|
|
843
|
+
continue;
|
|
844
|
+
}
|
|
695
845
|
// ST-1: read raw bytes (not utf-8) so binary files are not corrupted.
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
846
|
+
// RR-010: bounded read — never allocate more than the cap for a file that
|
|
847
|
+
// is only going to be truncated anyway (AC5).
|
|
848
|
+
const { data, originalSize, truncated: overCap } = readFileCappedForSnapshot(abs, SNAPSHOT_MAX_FILE_BYTES);
|
|
699
849
|
let note = "";
|
|
700
|
-
if (
|
|
701
|
-
|
|
702
|
-
note = ` (truncated: ${originalSize} → ${
|
|
850
|
+
if (overCap) {
|
|
851
|
+
truncated.push({ path: rel, originalSize });
|
|
852
|
+
note = ` (truncated: ${originalSize} → ${data.byteLength} bytes)`;
|
|
703
853
|
}
|
|
704
854
|
// ST-1: detect non-UTF-8 via fatal TextDecoder; base64-encode binary files.
|
|
705
855
|
let isUtf8 = true;
|
|
@@ -713,10 +863,22 @@ export function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskS
|
|
|
713
863
|
} else {
|
|
714
864
|
parts.push(`## Untracked file: ${rel}${note} (base64-encoded binary)`, "```base64", data.toString("base64"), "```", "");
|
|
715
865
|
}
|
|
716
|
-
} catch {
|
|
717
|
-
|
|
866
|
+
} catch (err) {
|
|
867
|
+
// RR-010: unreadable/unstat-able entries are recorded (and named in the
|
|
868
|
+
// artifact below) instead of being silently dropped — they used to be
|
|
869
|
+
// destroyed by `git clean -fd` with ZERO recovery.
|
|
870
|
+
skipped.push({ path: rel, reason: err instanceof Error ? err.message : String(err) });
|
|
718
871
|
}
|
|
719
872
|
}
|
|
873
|
+
// RR-010 (AC3): skipped entries MUST be named in the artifact so operators
|
|
874
|
+
// can see exactly which files were NOT backed up before deciding to force a
|
|
875
|
+
// cleanup — an artifact silent about them is false evidence.
|
|
876
|
+
if (skipped.length > 0) {
|
|
877
|
+
parts.push("## Skipped entries (NOT backed up)", ...skipped.map((s) => `- ${s.path} — ${s.reason}`), "");
|
|
878
|
+
}
|
|
879
|
+
if (trackedDiffError !== undefined) {
|
|
880
|
+
parts.push("## Tracked diff capture FAILED — tracked modifications are NOT backed up", "```", trackedDiffError, "```", "");
|
|
881
|
+
}
|
|
720
882
|
writeArtifact(manifest.artifactsRoot, {
|
|
721
883
|
kind: "diff",
|
|
722
884
|
relativePath: `worktree-recovery/${task.id}-${Date.now()}.md`,
|
|
@@ -724,15 +886,16 @@ export function snapshotDirtyWorktree(manifest: TeamRunManifest, task: TeamTaskS
|
|
|
724
886
|
producer: "worktree-manager.snapshotDirtyWorktree",
|
|
725
887
|
retention: "run",
|
|
726
888
|
});
|
|
727
|
-
return true;
|
|
728
889
|
} catch (err) {
|
|
729
890
|
logInternalError(
|
|
730
891
|
"worktree.recovery.snapshotFailed",
|
|
731
892
|
err instanceof Error ? err : new Error(String(err)),
|
|
732
893
|
`runId=${manifest.runId}, taskId=${task.id}`,
|
|
733
894
|
);
|
|
734
|
-
|
|
895
|
+
writeError = err instanceof Error ? err.message : String(err);
|
|
735
896
|
}
|
|
897
|
+
const complete = truncated.length === 0 && skipped.length === 0 && trackedDiffError === undefined && writeError === undefined;
|
|
898
|
+
return { complete, truncated, skipped, trackedDiffError, writeError };
|
|
736
899
|
}
|
|
737
900
|
|
|
738
901
|
/**
|
|
@@ -775,7 +938,12 @@ async function cleanupCreatedWorktreeAsync(repoRoot: string, worktreePath: strin
|
|
|
775
938
|
}
|
|
776
939
|
}
|
|
777
940
|
|
|
778
|
-
export function prepareTaskWorkspace(
|
|
941
|
+
export function prepareTaskWorkspace(
|
|
942
|
+
manifest: TeamRunManifest,
|
|
943
|
+
task: TeamTaskState,
|
|
944
|
+
stepSeedPaths?: string[],
|
|
945
|
+
options?: PrepareTaskWorkspaceOptions,
|
|
946
|
+
): PreparedTaskWorkspace {
|
|
779
947
|
if (manifest.workspaceMode !== "worktree") return { cwd: task.cwd };
|
|
780
948
|
const repoRoot = findGitRoot(manifest.cwd);
|
|
781
949
|
const loadedConfig = loadConfig(manifest.cwd);
|
|
@@ -852,11 +1020,17 @@ export function prepareTaskWorkspace(manifest: TeamRunManifest, task: TeamTaskSt
|
|
|
852
1020
|
if (dirtyStatus.trim()) {
|
|
853
1021
|
// Snapshot uncommitted work to a recovery artifact BEFORE discarding, so the
|
|
854
1022
|
// previous run's changes are never silently destroyed on reuse.
|
|
855
|
-
|
|
856
|
-
|
|
1023
|
+
// RR-010 (F01): discard only when the snapshot is COMPLETE (or the caller
|
|
1024
|
+
// explicitly forced it) — AGENTS.md rule 40. An artifact that was written
|
|
1025
|
+
// is not proof the backup is complete; fail CLOSED and preserve.
|
|
1026
|
+
const snapshotResult = snapshotDirtyWorktree(manifest, task, worktreePath, dirtyStatus);
|
|
1027
|
+
if (shouldDiscardDirtyWorktree(snapshotResult, options?.force === true)) {
|
|
857
1028
|
logInternalError(
|
|
858
1029
|
"worktree.reused.dirty",
|
|
859
|
-
new Error(
|
|
1030
|
+
new Error(
|
|
1031
|
+
`Discarding uncommitted changes in reused worktree at ${worktreePath} (snapshot saved to artifacts)` +
|
|
1032
|
+
(snapshotResult.complete ? "" : " — SNAPSHOT INCOMPLETE, discarded because caller set force=true"),
|
|
1033
|
+
),
|
|
860
1034
|
`runId=${manifest.runId}, taskId=${task.id}, dirtyStatus=${dirtyStatus.trim()}`,
|
|
861
1035
|
);
|
|
862
1036
|
git(worktreePath, ["checkout", "--", "."]);
|
|
@@ -865,7 +1039,7 @@ export function prepareTaskWorkspace(manifest: TeamRunManifest, task: TeamTaskSt
|
|
|
865
1039
|
logInternalError(
|
|
866
1040
|
"worktree.reused.dirtyPreserved",
|
|
867
1041
|
new Error(
|
|
868
|
-
`Snapshot
|
|
1042
|
+
`Snapshot incomplete — preserving dirty worktree at ${worktreePath} (skipping git checkout/clean to prevent data loss)${describeIncompleteSnapshot(snapshotResult)}`,
|
|
869
1043
|
),
|
|
870
1044
|
`runId=${manifest.runId}, taskId=${task.id}, dirtyStatus=${dirtyStatus.trim()}`,
|
|
871
1045
|
);
|
|
@@ -948,6 +1122,7 @@ export async function prepareTaskWorkspaceAsync(
|
|
|
948
1122
|
manifest: TeamRunManifest,
|
|
949
1123
|
task: TeamTaskState,
|
|
950
1124
|
stepSeedPaths?: string[],
|
|
1125
|
+
options?: PrepareTaskWorkspaceOptions,
|
|
951
1126
|
): Promise<PreparedTaskWorkspace> {
|
|
952
1127
|
if (manifest.workspaceMode !== "worktree") return { cwd: task.cwd };
|
|
953
1128
|
const repoRoot = await findGitRootAsync(manifest.cwd);
|
|
@@ -1012,11 +1187,16 @@ export async function prepareTaskWorkspaceAsync(
|
|
|
1012
1187
|
// ST-1: use -uall so untracked directories are expanded to individual files.
|
|
1013
1188
|
const dirtyStatus = await gitAsync(worktreePath, ["-c", "core.quotePath=false", "status", "--porcelain", "-uall"]);
|
|
1014
1189
|
if (dirtyStatus.trim()) {
|
|
1015
|
-
|
|
1016
|
-
|
|
1190
|
+
// RR-010 (F01): mirror of the sync gate — discard only when the snapshot is
|
|
1191
|
+
// COMPLETE (or explicitly forced). AGENTS.md rule 40. Fail CLOSED.
|
|
1192
|
+
const snapshotResult = snapshotDirtyWorktree(manifest, task, worktreePath, dirtyStatus);
|
|
1193
|
+
if (shouldDiscardDirtyWorktree(snapshotResult, options?.force === true)) {
|
|
1017
1194
|
logInternalError(
|
|
1018
1195
|
"worktree.reused.dirty",
|
|
1019
|
-
new Error(
|
|
1196
|
+
new Error(
|
|
1197
|
+
`Discarding uncommitted changes in reused worktree at ${worktreePath} (snapshot saved to artifacts)` +
|
|
1198
|
+
(snapshotResult.complete ? "" : " — SNAPSHOT INCOMPLETE, discarded because caller set force=true"),
|
|
1199
|
+
),
|
|
1020
1200
|
`runId=${manifest.runId}, taskId=${task.id}, dirtyStatus=${dirtyStatus.trim()}`,
|
|
1021
1201
|
);
|
|
1022
1202
|
await gitAsync(worktreePath, ["checkout", "--", "."]);
|
|
@@ -1025,7 +1205,7 @@ export async function prepareTaskWorkspaceAsync(
|
|
|
1025
1205
|
logInternalError(
|
|
1026
1206
|
"worktree.reused.dirtyPreserved",
|
|
1027
1207
|
new Error(
|
|
1028
|
-
`Snapshot
|
|
1208
|
+
`Snapshot incomplete — preserving dirty worktree at ${worktreePath} (skipping git checkout/clean to prevent data loss)${describeIncompleteSnapshot(snapshotResult)}`,
|
|
1029
1209
|
),
|
|
1030
1210
|
`runId=${manifest.runId}, taskId=${task.id}, dirtyStatus=${dirtyStatus.trim()}`,
|
|
1031
1211
|
);
|
|
@@ -144,7 +144,7 @@ output: apply-plan.md
|
|
|
144
144
|
- **HOW to apply**: AGENTS.md edit, lint rule add, src/ pattern adopt, CONTRIBUTING.md update, scripts/ operational script, or skill in target's skills/ dir
|
|
145
145
|
- **Exact file:line target** in the target project
|
|
146
146
|
- **Tier priority**: Tier 1 (high V3, low V4 cost) → Tier 2 (high V3, medium V4 cost) → Tier 3 (high V3, high V4 cost — pilot first)
|
|
147
|
-
- **Verification gate per item**: `npm run test:critical` + `npm run typecheck` + `npm run build:bundle` must pass after each apply; bundle MD5 must match or be updated; if tests fail → rollback
|
|
147
|
+
- **Verification gate per item**: `npm run test:critical` + `npm run typecheck` + `npm run build:bundle` must pass after each apply; bundle MD5 must match or be updated; if tests fail → rollback. (If the TARGET project is not this repo or lacks these scripts, use its fastest documented check gate instead — never run a full suite per item.)
|
|
148
148
|
|
|
149
149
|
Write to `references/apply-plan.md`. This is the input for the executor in Phase 4.
|
|
150
150
|
|
|
@@ -157,7 +157,7 @@ output: applied-changes.md
|
|
|
157
157
|
|
|
158
158
|
Per-item protocol:
|
|
159
159
|
1. Edit the target file(s) as specified in apply-plan.md
|
|
160
|
-
2. Run verification gate: `npm run test:critical` (or
|
|
160
|
+
2. Run verification gate: `npm run test:critical` (or the target's fastest documented check) + `npm run typecheck` + `npm run build:bundle`
|
|
161
161
|
3. Capture before/after diff + bundle MD5 (before/after)
|
|
162
162
|
4. If any gate fails → rollback the change (git checkout the file), log REJECTED in APPLY-LOG, continue with next item
|
|
163
163
|
5. If passes → log APPLIED in APPLY-LOG with file:line
|
|
@@ -173,7 +173,7 @@ verify: true
|
|
|
173
173
|
|
|
174
174
|
**Phase 5 (new — Darwin ratchet).** The output of a distillation is NOT "has skill" — it's "target improved." Read `applied-changes.md` + the target project's git diff. For each APPLIED item, re-verify:
|
|
175
175
|
- Does the change actually improve the target? (concrete, measurable — e.g. "new helper reduces 18 sites to 1 import"; not vibes)
|
|
176
|
-
- Do the tests still pass? (`npm run test:critical`)
|
|
176
|
+
- Do the tests still pass? (`npm run test:critical` — or the target's fastest documented check; never the full suite per item)
|
|
177
177
|
- Did the bundle MD5 change as expected? (intentional change OK; unexpected change → flag)
|
|
178
178
|
- Is the change consistent with target's existing style/conventions? (no foreign code injected)
|
|
179
179
|
|
|
@@ -21,4 +21,4 @@ dependsOn: execute
|
|
|
21
21
|
verify: true
|
|
22
22
|
|
|
23
23
|
Verify the fix with available evidence.
|
|
24
|
-
Run FAST checks ONCE
|
|
24
|
+
Run FAST checks ONCE and cache output WITH provenance to `.crew/cache/` (per `agents/verifier.md`: unique per-attempt filename, `set -o pipefail` so the recorded exit code is the command's — not `tee`'s — and a sibling `.meta` recording command, git revision, tree fingerprint): `npm run test:critical && npx tsc --noEmit` (completes in <60s; if this repo lacks these scripts, use its fastest documented check instead). Do NOT run `npm run test:unit` or `npm test` — too slow (642 files, >4 min). Cross-reference cached output with the fix — reuse a cached log only when its provenance matches. Do NOT re-run tests. Give PASS or FAIL with specific test evidence.
|
|
@@ -27,4 +27,4 @@ dependsOn: execute
|
|
|
27
27
|
verify: true
|
|
28
28
|
|
|
29
29
|
Verify completion for: {goal}
|
|
30
|
-
Run FAST checks ONCE
|
|
30
|
+
Run FAST checks ONCE and cache output WITH provenance to `.crew/cache/` (per `agents/verifier.md`: unique per-attempt filename, `set -o pipefail` so the recorded exit code is the command's — not `tee`'s — and a sibling `.meta` recording command, git revision, tree fingerprint): `npm run test:critical && npx tsc --noEmit` (completes in <60s; if this repo lacks these scripts, use its fastest documented check instead). Do NOT run `npm run test:unit` or `npm test` — too slow (642 files, >4 min). Cross-reference cached output with the changes — reuse a cached log only when its provenance matches. Do NOT re-run tests. Give PASS or FAIL with specific test evidence.
|
|
@@ -28,4 +28,4 @@ role: verifier
|
|
|
28
28
|
dependsOn: code-review, security-review
|
|
29
29
|
verify: true
|
|
30
30
|
|
|
31
|
-
Run FAST checks ONCE
|
|
31
|
+
Run FAST checks ONCE and cache output WITH provenance to `.crew/cache/` (per `agents/verifier.md`: unique per-attempt filename, `set -o pipefail` so the recorded exit code is the command's — not `tee`'s — and a sibling `.meta` recording command, git revision, tree fingerprint): `npm run test:critical && npx tsc --noEmit` (completes in <60s; if this repo lacks these scripts, use its fastest documented check instead). Do NOT run `npm run test:unit` or `npm test` — too slow (642 files, >4 min). Cross-reference cached output with reviewer and security-reviewer findings — reuse a cached log only when its provenance matches. Confirm each finding against real test output. Give PASS if findings match evidence, FAIL if critical findings are false positives or tests reveal new issues.
|
|
@@ -23,4 +23,4 @@ dependsOn: execute
|
|
|
23
23
|
verify: true
|
|
24
24
|
|
|
25
25
|
Verify the fix with available evidence, AND cross-reference the SPEC-EVIDENCE footer from explore+execute against the spec's requirements (machine-check the citations vs the spec id set).
|
|
26
|
-
Run FAST checks ONCE
|
|
26
|
+
Run FAST checks ONCE and cache output WITH provenance to `.crew/cache/` (per `agents/verifier.md`: unique per-attempt filename, `set -o pipefail` so the recorded exit code is the command's — not `tee`'s — and a sibling `.meta` recording command, git revision, tree fingerprint): `npm run test:critical && npx tsc --noEmit` (completes in <60s; if this repo lacks these scripts, use its fastest documented check instead). Do NOT run `npm run test:unit` or `npm test` — too slow (642 files, >4 min). Cross-reference cached output with the fix — reuse a cached log only when its provenance matches. Do NOT re-run tests. Give PASS or FAIL with specific test evidence + spec gate verdict.
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
# pi-crew Migration Guide: v0.4 → v0.5
|
|
2
|
-
|
|
3
|
-
**Author:** pi-crew team
|
|
4
|
-
**Date:** 2026-06-01
|
|
5
|
-
**Version:** 0.5.5 *(covers v0.4→v0.5 migration; later v0.5.x versions are drop-in replacements)*
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Overview
|
|
10
|
-
|
|
11
|
-
This guide covers breaking changes and new features introduced in v0.5.x.
|
|
12
|
-
|
|
13
|
-
---
|
|
14
|
-
|
|
15
|
-
## v0.5.5 Highlights (June 2026)
|
|
16
|
-
|
|
17
|
-
v0.5.5 closes 13 rounds of code review. The user-facing changes are:
|
|
18
|
-
|
|
19
|
-
- **Linear-time secret redaction** at all event/mailbox/artifact boundaries.
|
|
20
|
-
- **v8.deserialize hardened** with `BINARY_MAGIC` headers — old binaries are auto-discarded.
|
|
21
|
-
- **Adaptive implementation workflow** now has a single `assess` step; the planner picks the smallest effective crew.
|
|
22
|
-
- **Async-notifier debounce** of 30 s — completion notifications can be delayed by up to 30 s.
|
|
23
|
-
- **Mailbox delivery state capped at 10000 messages** — older entries are pruned FIFO.
|
|
24
|
-
- **Anchors cap at 50 with 100 handoffs each** — older handoffs are pruned FIFO.
|
|
25
|
-
|
|
26
|
-
No new public API is required for any of these changes. If you pinned a `BINARY_MAGIC`-guarded binary from a previous session, delete `~/.pi/agent/pi-crew/.cache/active-run-index.bin` once.
|
|
27
|
-
|
|
28
|
-
## v0.5.4 → v0.5.5 Migration
|
|
29
|
-
|
|
30
|
-
No breaking changes. Drop-in replacement.
|
|
31
|
-
|
|
32
|
-
## Breaking Changes
|
|
33
|
-
|
|
34
|
-
### 1. Environment Variable Allowlist (Security)
|
|
35
|
-
|
|
36
|
-
**Before (v0.4):**
|
|
37
|
-
```typescript
|
|
38
|
-
// Child Pi workers received ALL matching secrets
|
|
39
|
-
"*_API_KEY",
|
|
40
|
-
"*_TOKEN",
|
|
41
|
-
"*_SECRET",
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
**After (v0.5):**
|
|
45
|
-
```typescript
|
|
46
|
-
// Only explicit provider keys
|
|
47
|
-
"ANTHROPIC_API_KEY",
|
|
48
|
-
"OPENAI_API_KEY",
|
|
49
|
-
"GOOGLE_API_KEY",
|
|
50
|
-
// ...
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
**Action Required:** If your workflows rely on custom environment variables with `*_API_KEY` patterns, you must now explicitly list them:
|
|
54
|
-
```json
|
|
55
|
-
{
|
|
56
|
-
"piCrew": {
|
|
57
|
-
"runtime": {
|
|
58
|
-
"envAllowlist": ["MY_CUSTOM_API_KEY", "MY_OTHER_KEY"]
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
### 2. Mock Mode Requires Dual Environment Variables
|
|
67
|
-
|
|
68
|
-
**Before (v0.4):**
|
|
69
|
-
```bash
|
|
70
|
-
PI_TEAMS_MOCK_CHILD_PI=success # Works silently
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
**After (v0.5):**
|
|
74
|
-
```bash
|
|
75
|
-
PI_TEAMS_MOCK_CHILD_PI=success
|
|
76
|
-
PI_CREW_ALLOW_MOCK=1 # Required for security
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
**Action Required:** Update CI/CD and test scripts that use mock mode.
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
### 3. Skill Frontmatter Format
|
|
84
|
-
|
|
85
|
-
**Before (v0.4):**
|
|
86
|
-
```yaml
|
|
87
|
-
---
|
|
88
|
-
name: my-skill
|
|
89
|
-
description: "My skill description"
|
|
90
|
-
---
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
**After (v0.5):**
|
|
94
|
-
```yaml
|
|
95
|
-
---
|
|
96
|
-
name: my-skill
|
|
97
|
-
description: "My skill description"
|
|
98
|
-
triggers:
|
|
99
|
-
- "trigger phrase 1"
|
|
100
|
-
- "trigger phrase 2"
|
|
101
|
-
---
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
**Action Required:** Run `node scripts/check-all-skills.ts` to identify skills needing `triggers` field.
|
|
105
|
-
|
|
106
|
-
---
|
|
107
|
-
|
|
108
|
-
## New Features in v0.5
|
|
109
|
-
|
|
110
|
-
### 1. Enhanced Security
|
|
111
|
-
|
|
112
|
-
- **Secure env allowlist**: Only explicit API keys passed to child processes
|
|
113
|
-
- **Mock mode protection**: Requires `PI_CREW_ALLOW_MOCK=1` alongside `PI_TEAMS_MOCK_CHILD_PI`
|
|
114
|
-
- **Worktree hook hardening**: Safer execution on Windows
|
|
115
|
-
|
|
116
|
-
### 2. Improved Reliability
|
|
117
|
-
|
|
118
|
-
- **Terminal event durability**: Critical events (task.completed, task.failed) now bypass event buffering
|
|
119
|
-
- **Race condition fixes**: Foreground interrupt requests are now properly serialized
|
|
120
|
-
- **File descriptor cleanup**: Background runner properly closes log file descriptors
|
|
121
|
-
|
|
122
|
-
### 3. Better Observability
|
|
123
|
-
|
|
124
|
-
- **Reduced cache TTL**: Manifest cache now expires in 30s instead of 5min for faster state updates
|
|
125
|
-
- **Decision ledger integrity**: Ledger entries are preserved during promote/decay operations
|
|
126
|
-
|
|
127
|
-
### 4. Skill System
|
|
128
|
-
|
|
129
|
-
- **Standardized triggers**: All 35 built-in skills now have explicit trigger phrases
|
|
130
|
-
- **Enforcement gates**: Skills include checklist-based enforcement sections
|
|
131
|
-
- **Anti-patterns**: Most skills include anti-pattern documentation
|
|
132
|
-
|
|
133
|
-
---
|
|
134
|
-
|
|
135
|
-
## Configuration Changes
|
|
136
|
-
|
|
137
|
-
### New Config Keys
|
|
138
|
-
|
|
139
|
-
| Key | Type | Default | Description |
|
|
140
|
-
|-----|------|---------|-------------|
|
|
141
|
-
| `limits.heartbeatStaleMs` | number | 30000 | Stale heartbeat threshold |
|
|
142
|
-
| `runtime.effectivenessGuard` | string | "off" | Effectiveness guard level |
|
|
143
|
-
| `runtime.completionMutationGuard` | string | "off" | Mutation guard level |
|
|
144
|
-
|
|
145
|
-
### Deprecated Config Keys
|
|
146
|
-
|
|
147
|
-
None in v0.5.
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
## Workflow Migration
|
|
152
|
-
|
|
153
|
-
### Updating Custom Agents
|
|
154
|
-
|
|
155
|
-
1. Ensure agent files have `triggers` in frontmatter:
|
|
156
|
-
```yaml
|
|
157
|
-
---
|
|
158
|
-
name: my-agent
|
|
159
|
-
triggers:
|
|
160
|
-
- "my trigger"
|
|
161
|
-
---
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
2. Verify agent is discovered:
|
|
165
|
-
```bash
|
|
166
|
-
team action=list agent=my-agent
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### Updating Custom Teams
|
|
170
|
-
|
|
171
|
-
1. Validate team config:
|
|
172
|
-
```bash
|
|
173
|
-
team action=validate resource=team name=my-team
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
2. Check for breaking changes in role/task definitions.
|
|
177
|
-
|
|
178
|
-
---
|
|
179
|
-
|
|
180
|
-
## Testing Checklist
|
|
181
|
-
|
|
182
|
-
After upgrading to v0.5:
|
|
183
|
-
|
|
184
|
-
- [ ] Run `team action=doctor` to verify configuration
|
|
185
|
-
- [ ] Run `node scripts/check-all-skills.ts` to verify skills
|
|
186
|
-
- [ ] Test mock mode with both env vars set
|
|
187
|
-
- [ ] Verify environment variables are properly filtered in child processes
|
|
188
|
-
- [ ] Test foreground interrupt (cancel) behavior
|
|
189
|
-
- [ ] Verify terminal events are properly logged
|
|
190
|
-
|
|
191
|
-
---
|
|
192
|
-
|
|
193
|
-
## Rollback
|
|
194
|
-
|
|
195
|
-
If issues occur after upgrade:
|
|
196
|
-
|
|
197
|
-
```bash
|
|
198
|
-
# Revert to v0.4.x
|
|
199
|
-
pi install npm:pi-crew@0.4.x
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
---
|
|
203
|
-
|
|
204
|
-
## Support
|
|
205
|
-
|
|
206
|
-
- **Issues**: https://github.com/baphuongna/pi-crew/issues
|
|
207
|
-
- **Documentation**: [docs/](docs/)
|
|
208
|
-
- **Changelog**: [CHANGELOG.md](CHANGELOG.md)
|