pi-crew 0.1.49 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +74 -1
- package/README.md +176 -781
- package/agents/analyst.md +11 -11
- package/agents/critic.md +11 -11
- package/agents/executor.md +11 -11
- package/agents/explorer.md +11 -11
- package/agents/planner.md +11 -11
- package/agents/reviewer.md +11 -11
- package/agents/security-reviewer.md +11 -11
- package/agents/test-engineer.md +11 -11
- package/agents/verifier.md +70 -11
- package/agents/writer.md +11 -11
- package/docs/actions-reference.md +595 -0
- package/docs/commands-reference.md +347 -0
- package/docs/runtime-flow.md +148 -148
- package/index.ts +6 -6
- package/package.json +99 -99
- package/skills/async-worker-recovery/SKILL.md +42 -42
- package/skills/context-artifact-hygiene/SKILL.md +52 -52
- package/skills/delegation-patterns/SKILL.md +54 -54
- package/skills/mailbox-interactive/SKILL.md +40 -40
- package/skills/model-routing-context/SKILL.md +39 -39
- package/skills/multi-perspective-review/SKILL.md +58 -58
- package/skills/observability-reliability/SKILL.md +41 -41
- package/skills/orchestration/SKILL.md +157 -157
- package/skills/ownership-session-security/SKILL.md +41 -41
- package/skills/pi-extension-lifecycle/SKILL.md +39 -39
- package/skills/requirements-to-task-packet/SKILL.md +63 -63
- package/skills/resource-discovery-config/SKILL.md +41 -41
- package/skills/runtime-state-reader/SKILL.md +44 -44
- package/skills/secure-agent-orchestration-review/SKILL.md +45 -45
- package/skills/state-mutation-locking/SKILL.md +42 -42
- package/skills/systematic-debugging/SKILL.md +67 -67
- package/skills/ui-render-performance/SKILL.md +39 -39
- package/skills/verification-before-done/SKILL.md +57 -57
- package/skills/worktree-isolation/SKILL.md +39 -39
- package/src/adapters/claude-adapter.ts +25 -0
- package/src/adapters/codex-adapter.ts +21 -0
- package/src/adapters/cursor-adapter.ts +17 -0
- package/src/adapters/export-util.ts +137 -0
- package/src/adapters/index.ts +15 -0
- package/src/adapters/registry.ts +18 -0
- package/src/adapters/types.ts +23 -0
- package/src/agents/agent-config.ts +2 -0
- package/src/agents/agent-search.ts +98 -98
- package/src/agents/discover-agents.ts +2 -1
- package/src/config/config.ts +14 -1
- package/src/config/defaults.ts +5 -5
- package/src/config/drift-detector.ts +211 -0
- package/src/config/markers.ts +327 -0
- package/src/config/resilient-parser.ts +108 -0
- package/src/config/suggestions.ts +74 -0
- package/src/extension/cross-extension-rpc.ts +103 -82
- package/src/extension/project-init.ts +36 -4
- package/src/extension/register.ts +67 -22
- package/src/extension/registration/commands.ts +77 -8
- package/src/extension/registration/subagent-tools.ts +10 -1
- package/src/extension/registration/team-tool.ts +10 -1
- package/src/extension/registration/viewers.ts +48 -34
- package/src/extension/run-bundle-schema.ts +89 -89
- package/src/extension/run-export.ts +26 -12
- package/src/extension/run-import.ts +25 -1
- package/src/extension/run-index.ts +5 -1
- package/src/extension/run-maintenance.ts +142 -68
- package/src/extension/team-manager-command.ts +10 -1
- package/src/extension/team-tool/context.ts +1 -1
- package/src/extension/team-tool/doctor.ts +28 -3
- package/src/extension/team-tool/handle-settings.ts +195 -188
- package/src/extension/team-tool/inspect.ts +41 -41
- package/src/extension/team-tool/intent-policy.ts +42 -42
- package/src/extension/team-tool/lifecycle-actions.ts +27 -8
- package/src/extension/team-tool/plan.ts +19 -19
- package/src/extension/team-tool/run.ts +12 -1
- package/src/extension/team-tool.ts +14 -3
- package/src/i18n.ts +184 -184
- package/src/observability/exporters/otlp-exporter.ts +92 -77
- package/src/prompt/prompt-runtime.ts +72 -72
- package/src/runtime/agent-memory.ts +72 -72
- package/src/runtime/agent-observability.ts +114 -114
- package/src/runtime/async-marker.ts +26 -26
- package/src/runtime/attention-events.ts +28 -28
- package/src/runtime/auto-resume.ts +100 -0
- package/src/runtime/background-runner.ts +11 -1
- package/src/runtime/cancellation-token.ts +89 -89
- package/src/runtime/cancellation.ts +61 -61
- package/src/runtime/capability-inventory.ts +116 -116
- package/src/runtime/child-pi.ts +7 -2
- package/src/runtime/compaction-summary.ts +271 -0
- package/src/runtime/completion-guard.ts +190 -190
- package/src/runtime/concurrency.ts +3 -1
- package/src/runtime/crash-recovery.ts +33 -0
- package/src/runtime/delta-conflict.ts +360 -0
- package/src/runtime/diagnostic-export.ts +3 -1
- package/src/runtime/direct-run.ts +35 -35
- package/src/runtime/event-stream-bridge.ts +3 -1
- package/src/runtime/foreground-control.ts +82 -82
- package/src/runtime/green-contract.ts +46 -46
- package/src/runtime/group-join.ts +106 -106
- package/src/runtime/heartbeat-gradient.ts +28 -28
- package/src/runtime/heartbeat-watcher.ts +124 -124
- package/src/runtime/iteration-hooks.ts +262 -0
- package/src/runtime/live-agent-control.ts +88 -88
- package/src/runtime/live-control-realtime.ts +36 -36
- package/src/runtime/live-extension-bridge.ts +150 -150
- package/src/runtime/live-irc.ts +92 -92
- package/src/runtime/live-session-health.ts +100 -100
- package/src/runtime/loop-gates.ts +129 -0
- package/src/runtime/metric-parser.ts +40 -0
- package/src/runtime/notebook-helpers.ts +90 -90
- package/src/runtime/orphan-sentinel.ts +7 -7
- package/src/runtime/parallel-research.ts +44 -44
- package/src/runtime/phase-progress.ts +217 -0
- package/src/runtime/pi-args.ts +38 -2
- package/src/runtime/pi-json-output.ts +111 -111
- package/src/runtime/pi-spawn.ts +74 -6
- package/src/runtime/policy-engine.ts +79 -79
- package/src/runtime/post-checks.ts +122 -0
- package/src/runtime/process-status.ts +14 -1
- package/src/runtime/progress-event-coalescer.ts +43 -43
- package/src/runtime/prose-compressor.ts +164 -164
- package/src/runtime/recovery-recipes.ts +74 -74
- package/src/runtime/result-extractor.ts +121 -121
- package/src/runtime/role-permission.ts +39 -39
- package/src/runtime/sensitive-paths.ts +3 -3
- package/src/runtime/session-resources.ts +25 -25
- package/src/runtime/session-snapshot.ts +59 -59
- package/src/runtime/session-usage.ts +79 -79
- package/src/runtime/sidechain-output.ts +29 -29
- package/src/runtime/stream-preview.ts +177 -177
- package/src/runtime/supervisor-contact.ts +59 -59
- package/src/runtime/task-display.ts +38 -38
- package/src/runtime/task-graph.ts +207 -0
- package/src/runtime/task-quality.ts +207 -0
- package/src/runtime/task-runner/capabilities.ts +78 -78
- package/src/runtime/task-runner/live-executor.ts +7 -1
- package/src/runtime/task-runner/progress.ts +119 -119
- package/src/runtime/task-runner/prompt-builder.ts +1 -1
- package/src/runtime/task-runner/prompt-pipeline.ts +64 -64
- package/src/runtime/task-runner/result-utils.ts +14 -14
- package/src/runtime/task-runner/run-projection.ts +103 -103
- package/src/runtime/task-runner/state-helpers.ts +22 -22
- package/src/runtime/team-runner.ts +126 -7
- package/src/runtime/worker-heartbeat.ts +21 -21
- package/src/runtime/worker-startup.ts +57 -57
- package/src/runtime/workflow-state.ts +187 -0
- package/src/runtime/workspace-tree.ts +298 -298
- package/src/schema/config-schema.ts +12 -0
- package/src/schema/validation-types.ts +148 -0
- package/src/skills/skill-templates.ts +374 -0
- package/src/state/active-run-registry.ts +35 -11
- package/src/state/atomic-write.ts +33 -26
- package/src/state/contracts.ts +1 -0
- package/src/state/event-reconstructor.ts +217 -0
- package/src/state/locks.ts +2 -11
- package/src/state/mailbox.ts +4 -3
- package/src/state/state-store.ts +32 -14
- package/src/state/task-claims.ts +44 -44
- package/src/state/types.ts +9 -0
- package/src/state/usage.ts +29 -29
- package/src/subagents/async-entry.ts +1 -1
- package/src/subagents/index.ts +3 -3
- package/src/subagents/live/control.ts +1 -1
- package/src/subagents/live/manager.ts +1 -1
- package/src/subagents/live/realtime.ts +1 -1
- package/src/subagents/live/session-runtime.ts +1 -1
- package/src/subagents/manager.ts +1 -1
- package/src/subagents/spawn.ts +1 -1
- package/src/teams/team-serializer.ts +38 -38
- package/src/types/diff.d.ts +18 -18
- package/src/ui/crew-footer.ts +101 -101
- package/src/ui/crew-select-list.ts +111 -111
- package/src/ui/crew-widget.ts +9 -4
- package/src/ui/dashboard-panes/cancellation-pane.ts +42 -42
- package/src/ui/dashboard-panes/capability-pane.ts +59 -59
- package/src/ui/dashboard-panes/mailbox-pane.ts +35 -35
- package/src/ui/dashboard-panes/metrics-pane.ts +34 -34
- package/src/ui/dashboard-panes/progress-pane.ts +11 -0
- package/src/ui/dynamic-border.ts +25 -25
- package/src/ui/layout-primitives.ts +106 -106
- package/src/ui/loaders.ts +158 -158
- package/src/ui/powerbar-publisher.ts +6 -0
- package/src/ui/render-coalescer.ts +51 -51
- package/src/ui/render-diff.ts +119 -119
- package/src/ui/render-scheduler.ts +143 -143
- package/src/ui/run-action-dispatcher.ts +10 -1
- package/src/ui/spinner.ts +17 -17
- package/src/ui/status-colors.ts +58 -58
- package/src/ui/syntax-highlight.ts +116 -116
- package/src/ui/transcript-entries.ts +258 -258
- package/src/utils/completion-dedupe.ts +63 -63
- package/src/utils/frontmatter.ts +68 -68
- package/src/utils/git.ts +262 -262
- package/src/utils/ids.ts +17 -17
- package/src/utils/incremental-reader.ts +104 -104
- package/src/utils/names.ts +27 -27
- package/src/utils/redaction.ts +44 -44
- package/src/utils/safe-paths.ts +47 -47
- package/src/utils/scan-cache.ts +136 -136
- package/src/utils/sleep.ts +40 -26
- package/src/utils/task-name-generator.ts +337 -337
- package/src/workflows/validate-workflow.ts +40 -40
- package/src/worktree/branch-freshness.ts +45 -45
- package/src/worktree/worktree-manager.ts +11 -3
- package/teams/default.team.md +12 -12
- package/teams/fast-fix.team.md +11 -11
- package/teams/implementation.team.md +18 -18
- package/teams/parallel-research.team.md +14 -14
- package/teams/research.team.md +11 -11
- package/teams/review.team.md +12 -12
- package/workflows/default.workflow.md +30 -29
- package/workflows/fast-fix.workflow.md +23 -22
- package/workflows/implementation.workflow.md +43 -38
- package/workflows/parallel-research.workflow.md +46 -46
- package/workflows/research.workflow.md +22 -22
- package/workflows/review.workflow.md +30 -30
- package/docs/refactor-tasks-phase3.md +0 -394
- package/docs/refactor-tasks-phase4.md +0 -564
- package/docs/refactor-tasks-phase5.md +0 -402
- package/docs/refactor-tasks-phase6.md +0 -662
- package/docs/refactor-tasks.md +0 -1484
- package/docs/research/AGENT-EXECUTION-ARCHITECTURE.md +0 -261
- package/docs/research/AGENT-LIFECYCLE-COMPARISON.md +0 -111
- package/docs/research/AUDIT_OH_MY_PI.md +0 -261
- package/docs/research/AUDIT_PI_CREW.md +0 -457
- package/docs/research/CAVEMAN-DEEP-RESEARCH.md +0 -281
- package/docs/research/COMPARISON_OH_MY_PI_VS_PI_CREW.md +0 -264
- package/docs/research/DEEP-RESEARCH-PI-POWERBAR.md +0 -343
- package/docs/research/DEEP_RESEARCH_SUBAGENT_ARCHITECTURE.md +0 -480
- package/docs/research/GAP_CLOSURE_IMPLEMENTATION_PLAN.md +0 -354
- package/docs/research/IMPLEMENTATION_PLAN.md +0 -385
- package/docs/research/LIVE-SESSION-PRODUCTION-READY-PLAN.md +0 -502
- package/docs/research/OH-MY-PI-DEEP-RESEARCH-v14.7.6.md +0 -266
- package/docs/research/REMAINING-GAPS-PLAN.md +0 -363
- package/docs/research/SESSION-SUMMARY-2026-05-08.md +0 -146
- package/docs/research/UI-RESPONSIVENESS-AUDIT.md +0 -173
- package/docs/research-awesome-agent-skills-distillation.md +0 -100
- package/docs/research-extension-examples.md +0 -297
- package/docs/research-extension-system.md +0 -324
- package/docs/research-oh-my-pi-distillation.md +0 -369
- package/docs/research-optimization-plan.md +0 -548
- package/docs/research-phase10-distillation.md +0 -199
- package/docs/research-phase11-distillation.md +0 -201
- package/docs/research-phase8-operator-experience-plan.md +0 -819
- package/docs/research-phase9-observability-reliability-plan.md +0 -1190
- package/docs/research-pi-coding-agent.md +0 -357
- package/docs/research-source-pi-crew-reference.md +0 -174
- package/docs/research-ui-optimization-plan.md +0 -480
- package/docs/source-runtime-refactor-map.md +0 -107
- package/src/utils/atomic-write.ts +0 -33
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
import type { PiTeamsConfig } from "../../config/config.ts";
|
|
2
|
-
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
3
|
-
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
4
|
-
import { configRecord, result } from "./context.ts";
|
|
5
|
-
|
|
6
|
-
export type DestructiveIntentAction = "cancel" | "cleanup" | "delete" | "forget" | "prune";
|
|
7
|
-
|
|
8
|
-
const DESTRUCTIVE_ACTION_LABELS: Record<DestructiveIntentAction, string> = {
|
|
9
|
-
cancel: "cancel",
|
|
10
|
-
cleanup: "forced cleanup",
|
|
11
|
-
delete: "delete",
|
|
12
|
-
forget: "forget",
|
|
13
|
-
prune: "prune",
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export function intentFromConfig(config: unknown): string | undefined {
|
|
17
|
-
const cfg = configRecord(config);
|
|
18
|
-
const rawIntent = cfg.intent ?? cfg._intent;
|
|
19
|
-
if (typeof rawIntent !== "string") return undefined;
|
|
20
|
-
const intent = rawIntent.replace(/\s+/g, " ").trim();
|
|
21
|
-
return intent ? intent.slice(0, 500) : undefined;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function shouldRequireIntent(config: PiTeamsConfig | undefined): boolean {
|
|
25
|
-
return config?.policy?.requireIntentForDestructiveActions === true;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function enforceDestructiveIntent(
|
|
29
|
-
action: DestructiveIntentAction,
|
|
30
|
-
params: TeamToolParamsValue,
|
|
31
|
-
config: PiTeamsConfig | undefined,
|
|
32
|
-
): PiTeamsToolResult | undefined {
|
|
33
|
-
if (!shouldRequireIntent(config)) return undefined;
|
|
34
|
-
if (action === "cleanup" && params.force !== true) return undefined;
|
|
35
|
-
if (intentFromConfig(params.config)) return undefined;
|
|
36
|
-
const label = DESTRUCTIVE_ACTION_LABELS[action];
|
|
37
|
-
return result(
|
|
38
|
-
`Destructive action '${label}' requires config.intent when policy.requireIntentForDestructiveActions is enabled.`,
|
|
39
|
-
{ action: action === "delete" ? "management" : action, status: "error" },
|
|
40
|
-
true,
|
|
41
|
-
);
|
|
42
|
-
}
|
|
1
|
+
import type { PiTeamsConfig } from "../../config/config.ts";
|
|
2
|
+
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
3
|
+
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
4
|
+
import { configRecord, result } from "./context.ts";
|
|
5
|
+
|
|
6
|
+
export type DestructiveIntentAction = "cancel" | "cleanup" | "delete" | "forget" | "prune";
|
|
7
|
+
|
|
8
|
+
const DESTRUCTIVE_ACTION_LABELS: Record<DestructiveIntentAction, string> = {
|
|
9
|
+
cancel: "cancel",
|
|
10
|
+
cleanup: "forced cleanup",
|
|
11
|
+
delete: "delete",
|
|
12
|
+
forget: "forget",
|
|
13
|
+
prune: "prune",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function intentFromConfig(config: unknown): string | undefined {
|
|
17
|
+
const cfg = configRecord(config);
|
|
18
|
+
const rawIntent = cfg.intent ?? cfg._intent;
|
|
19
|
+
if (typeof rawIntent !== "string") return undefined;
|
|
20
|
+
const intent = rawIntent.replace(/\s+/g, " ").trim();
|
|
21
|
+
return intent ? intent.slice(0, 500) : undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function shouldRequireIntent(config: PiTeamsConfig | undefined): boolean {
|
|
25
|
+
return config?.policy?.requireIntentForDestructiveActions === true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function enforceDestructiveIntent(
|
|
29
|
+
action: DestructiveIntentAction,
|
|
30
|
+
params: TeamToolParamsValue,
|
|
31
|
+
config: PiTeamsConfig | undefined,
|
|
32
|
+
): PiTeamsToolResult | undefined {
|
|
33
|
+
if (!shouldRequireIntent(config)) return undefined;
|
|
34
|
+
if (action === "cleanup" && params.force !== true) return undefined;
|
|
35
|
+
if (intentFromConfig(params.config)) return undefined;
|
|
36
|
+
const label = DESTRUCTIVE_ACTION_LABELS[action];
|
|
37
|
+
return result(
|
|
38
|
+
`Destructive action '${label}' requires config.intent when policy.requireIntentForDestructiveActions is enabled.`,
|
|
39
|
+
{ action: action === "delete" ? "management" : action, status: "error" },
|
|
40
|
+
true,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
@@ -11,6 +11,9 @@ import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
|
11
11
|
import { configRecord, result, type TeamContext } from "./context.ts";
|
|
12
12
|
import { enforceDestructiveIntent, intentFromConfig } from "./intent-policy.ts";
|
|
13
13
|
import { executeHook, appendHookEvent } from "../../hooks/registry.ts";
|
|
14
|
+
import { resolveRealContainedPath } from "../../utils/safe-paths.ts";
|
|
15
|
+
import { projectCrewRoot, userCrewRoot } from "../../utils/paths.ts";
|
|
16
|
+
import * as path from "node:path";
|
|
14
17
|
|
|
15
18
|
export function handleWorktrees(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
16
19
|
if (!params.runId) return result("Worktrees requires runId.", { action: "worktrees", status: "error" }, true);
|
|
@@ -42,6 +45,7 @@ export function handleImport(params: TeamToolParamsValue, ctx: TeamContext): PiT
|
|
|
42
45
|
}
|
|
43
46
|
|
|
44
47
|
export async function handleExport(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
|
|
48
|
+
// Note: no ownership check — export is intentionally cross-session (read-only, for sharing)
|
|
45
49
|
if (!params.runId) return result("Export requires runId.", { action: "export", status: "error" }, true);
|
|
46
50
|
const loaded = loadRunManifestById(ctx.cwd, params.runId);
|
|
47
51
|
if (!loaded) return result(`Run '${params.runId}' not found.`, { action: "export", status: "error" }, true);
|
|
@@ -57,6 +61,9 @@ export async function handleExport(params: TeamToolParamsValue, ctx: TeamContext
|
|
|
57
61
|
return result([`Exported run ${loaded.manifest.runId}.`, `JSON: ${exported.jsonPath}`, `Markdown: ${exported.markdownPath}`].join("\n"), { action: "export", status: "ok", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot });
|
|
58
62
|
}
|
|
59
63
|
|
|
64
|
+
// Note: handlePrune has no ownership check — intentionally cross-session.
|
|
65
|
+
// Prune is a maintenance-level operation that removes ALL finished runs
|
|
66
|
+
// regardless of which session created them. Requires confirm: true.
|
|
60
67
|
export async function handlePrune(params: TeamToolParamsValue, ctx: TeamContext): Promise<PiTeamsToolResult> {
|
|
61
68
|
const intentError = enforceDestructiveIntent("prune", params, ctx.config);
|
|
62
69
|
if (intentError) return intentError;
|
|
@@ -65,12 +72,12 @@ export async function handlePrune(params: TeamToolParamsValue, ctx: TeamContext)
|
|
|
65
72
|
if (keep < 0 || !Number.isInteger(keep)) return result("keep must be an integer >= 0.", { action: "prune", status: "error" }, true);
|
|
66
73
|
const intent = intentFromConfig(params.config);
|
|
67
74
|
const pruned = pruneFinishedRuns(ctx.cwd, keep, { intent, signal: ctx.signal });
|
|
68
|
-
|
|
69
|
-
if (
|
|
70
|
-
const
|
|
71
|
-
if (
|
|
72
|
-
const hookReport = await executeHook("before_cleanup", { runId:
|
|
73
|
-
appendHookEvent(
|
|
75
|
+
// Fire hook once with all removed run IDs for batch visibility
|
|
76
|
+
if (pruned.removed.length > 0) {
|
|
77
|
+
const sampleManifest = loadRunManifestById(ctx.cwd, pruned.removed[0])?.manifest;
|
|
78
|
+
if (sampleManifest) {
|
|
79
|
+
const hookReport = await executeHook("before_cleanup", { runId: sampleManifest.runId, cwd: ctx.cwd, data: { removedRunIds: pruned.removed, keptCount: pruned.kept.length } });
|
|
80
|
+
appendHookEvent(sampleManifest, hookReport);
|
|
74
81
|
}
|
|
75
82
|
}
|
|
76
83
|
return result([`Pruned finished pi-crew runs.`, `Kept: ${pruned.kept.length}`, `Removed: ${pruned.removed.length}`, ...(pruned.auditPath ? [`Audit: ${pruned.auditPath}`] : []), ...(pruned.removed.length ? ["Removed runs:", ...pruned.removed.map((runId) => `- ${runId}`)] : [])].join("\n"), { action: "prune", status: "ok", intent });
|
|
@@ -84,6 +91,10 @@ export async function handleForget(params: TeamToolParamsValue, ctx: TeamContext
|
|
|
84
91
|
const loaded = loadRunManifestById(ctx.cwd, params.runId);
|
|
85
92
|
if (!loaded) return result(`Run '${params.runId}' not found.`, { action: "forget", status: "error" }, true);
|
|
86
93
|
|
|
94
|
+
// Ownership check — prevent cross-session deletion
|
|
95
|
+
const foreignRun = typeof loaded.manifest.ownerSessionId === "string" && loaded.manifest.ownerSessionId !== ctx.sessionId;
|
|
96
|
+
if (foreignRun) return result(`Run ${params.runId} belongs to another session; not forgotten.`, { action: "forget", status: "error", runId: loaded.manifest.runId }, true);
|
|
97
|
+
|
|
87
98
|
const hookReport = await executeHook("before_forget", { runId: loaded.manifest.runId, cwd: ctx.cwd });
|
|
88
99
|
appendHookEvent(loaded.manifest, hookReport);
|
|
89
100
|
if (hookReport.outcome === "block") {
|
|
@@ -94,8 +105,12 @@ export async function handleForget(params: TeamToolParamsValue, ctx: TeamContext
|
|
|
94
105
|
if (cleanup.preserved.length > 0 && !params.force) return result([`Run '${params.runId}' has preserved worktrees. Use force: true to forget anyway.`, ...cleanup.preserved.map((item) => `- ${item.path}: ${item.reason}`)].join("\n"), { action: "forget", status: "error", runId: loaded.manifest.runId, artifactsRoot: loaded.manifest.artifactsRoot }, true);
|
|
95
106
|
const intent = intentFromConfig(params.config);
|
|
96
107
|
appendEvent(loaded.manifest.eventsPath, { type: "run.forget_requested", runId: loaded.manifest.runId, message: "Run state and artifacts are being forgotten.", data: { force: params.force === true, removedWorktrees: cleanup.removed, preservedWorktrees: cleanup.preserved, intent } });
|
|
97
|
-
|
|
98
|
-
|
|
108
|
+
// Determine scope from manifest paths (project vs user-level runs)
|
|
109
|
+
const crewRoot = loaded.manifest.stateRoot.startsWith(userCrewRoot() + path.sep) ? userCrewRoot() : projectCrewRoot(loaded.manifest.cwd);
|
|
110
|
+
const resolvedStateRoot = resolveRealContainedPath(crewRoot, loaded.manifest.stateRoot);
|
|
111
|
+
const resolvedArtifactsRoot = resolveRealContainedPath(crewRoot, loaded.manifest.artifactsRoot);
|
|
112
|
+
fs.rmSync(resolvedStateRoot, { recursive: true, force: true });
|
|
113
|
+
fs.rmSync(resolvedArtifactsRoot, { recursive: true, force: true });
|
|
99
114
|
return result([`Forgot run ${loaded.manifest.runId}.`, `Removed state: ${loaded.manifest.stateRoot}`, `Removed artifacts: ${loaded.manifest.artifactsRoot}`, ...(cleanup.removed.length ? ["Removed worktrees:", ...cleanup.removed.map((item) => `- ${item}`)] : [])].join("\n"), { action: "forget", status: "ok", runId: loaded.manifest.runId, intent });
|
|
100
115
|
}
|
|
101
116
|
|
|
@@ -106,6 +121,10 @@ export async function handleCleanup(params: TeamToolParamsValue, ctx: TeamContex
|
|
|
106
121
|
const loaded = loadRunManifestById(ctx.cwd, params.runId);
|
|
107
122
|
if (!loaded) return result(`Run '${params.runId}' not found.`, { action: "cleanup", status: "error" }, true);
|
|
108
123
|
|
|
124
|
+
// Ownership check — prevent cross-session worktree cleanup
|
|
125
|
+
const foreignRun = typeof loaded.manifest.ownerSessionId === "string" && loaded.manifest.ownerSessionId !== ctx.sessionId;
|
|
126
|
+
if (foreignRun) return result(`Run ${params.runId} belongs to another session; not cleaned up.`, { action: "cleanup", status: "error", runId: loaded.manifest.runId }, true);
|
|
127
|
+
|
|
109
128
|
const hookReport = await executeHook("before_cleanup", { runId: loaded.manifest.runId, cwd: ctx.cwd });
|
|
110
129
|
appendHookEvent(loaded.manifest, hookReport);
|
|
111
130
|
if (hookReport.outcome === "block") {
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import { allTeams, discoverTeams } from "../../teams/discover-teams.ts";
|
|
2
|
-
import { allWorkflows, discoverWorkflows } from "../../workflows/discover-workflows.ts";
|
|
3
|
-
import { validateWorkflowForTeam } from "../../workflows/validate-workflow.ts";
|
|
4
|
-
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
5
|
-
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
6
|
-
import { result, type TeamContext } from "./context.ts";
|
|
7
|
-
|
|
8
|
-
export function handlePlan(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
9
|
-
const teamName = params.team ?? "default";
|
|
10
|
-
const team = allTeams(discoverTeams(ctx.cwd)).find((item) => item.name === teamName);
|
|
11
|
-
if (!team) return result(`Team '${teamName}' not found.`, { action: "plan", status: "error" }, true);
|
|
12
|
-
const workflowName = params.workflow ?? team.defaultWorkflow ?? "default";
|
|
13
|
-
const workflow = allWorkflows(discoverWorkflows(ctx.cwd)).find((item) => item.name === workflowName);
|
|
14
|
-
if (!workflow) return result(`Workflow '${workflowName}' not found.`, { action: "plan", status: "error" }, true);
|
|
15
|
-
const errors = validateWorkflowForTeam(workflow, team);
|
|
16
|
-
if (errors.length > 0) return result([`Workflow '${workflow.name}' is not valid for team '${team.name}':`, ...errors.map((error) => `- ${error}`)].join("\n"), { action: "plan", status: "error" }, true);
|
|
17
|
-
const lines = [`Team plan: ${team.name}`, `Workflow: ${workflow.name}`, `Goal: ${params.goal ?? params.task ?? "(not provided)"}`, "", "Steps:", ...workflow.steps.map((step, index) => `${index + 1}. ${step.id} [${step.role}]${step.dependsOn?.length ? ` after ${step.dependsOn.join(", ")}` : ""}`)];
|
|
18
|
-
return result(lines.join("\n"), { action: "plan", status: "ok" });
|
|
19
|
-
}
|
|
1
|
+
import { allTeams, discoverTeams } from "../../teams/discover-teams.ts";
|
|
2
|
+
import { allWorkflows, discoverWorkflows } from "../../workflows/discover-workflows.ts";
|
|
3
|
+
import { validateWorkflowForTeam } from "../../workflows/validate-workflow.ts";
|
|
4
|
+
import type { TeamToolParamsValue } from "../../schema/team-tool-schema.ts";
|
|
5
|
+
import type { PiTeamsToolResult } from "../tool-result.ts";
|
|
6
|
+
import { result, type TeamContext } from "./context.ts";
|
|
7
|
+
|
|
8
|
+
export function handlePlan(params: TeamToolParamsValue, ctx: TeamContext): PiTeamsToolResult {
|
|
9
|
+
const teamName = params.team ?? "default";
|
|
10
|
+
const team = allTeams(discoverTeams(ctx.cwd)).find((item) => item.name === teamName);
|
|
11
|
+
if (!team) return result(`Team '${teamName}' not found.`, { action: "plan", status: "error" }, true);
|
|
12
|
+
const workflowName = params.workflow ?? team.defaultWorkflow ?? "default";
|
|
13
|
+
const workflow = allWorkflows(discoverWorkflows(ctx.cwd)).find((item) => item.name === workflowName);
|
|
14
|
+
if (!workflow) return result(`Workflow '${workflowName}' not found.`, { action: "plan", status: "error" }, true);
|
|
15
|
+
const errors = validateWorkflowForTeam(workflow, team);
|
|
16
|
+
if (errors.length > 0) return result([`Workflow '${workflow.name}' is not valid for team '${team.name}':`, ...errors.map((error) => `- ${error}`)].join("\n"), { action: "plan", status: "error" }, true);
|
|
17
|
+
const lines = [`Team plan: ${team.name}`, `Workflow: ${workflow.name}`, `Goal: ${params.goal ?? params.task ?? "(not provided)"}`, "", "Steps:", ...workflow.steps.map((step, index) => `${index + 1}. ${step.id} [${step.role}]${step.dependsOn?.length ? ` after ${step.dependsOn.join(", ")}` : ""}`)];
|
|
18
|
+
return result(lines.join("\n"), { action: "plan", status: "ok" });
|
|
19
|
+
}
|
|
@@ -8,7 +8,18 @@ import { registerActiveRun, unregisterActiveRun } from "../../state/active-run-r
|
|
|
8
8
|
import { createRunManifest, loadRunManifestById, updateRunStatus } from "../../state/state-store.ts";
|
|
9
9
|
import { atomicWriteJson } from "../../state/atomic-write.ts";
|
|
10
10
|
import { validateWorkflowForTeam } from "../../workflows/validate-workflow.ts";
|
|
11
|
-
|
|
11
|
+
// Heavy runtime — lazy-loaded to avoid 1.4s import cost at extension registration.
|
|
12
|
+
import type { executeTeamRun as ExecuteTeamRunFn } from "../../runtime/team-runner.ts";
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- type-only import for TS inference
|
|
14
|
+
const _typeCheck: typeof ExecuteTeamRunFn = null as never as typeof ExecuteTeamRunFn;
|
|
15
|
+
let _cachedExecuteTeamRun: typeof ExecuteTeamRunFn | undefined;
|
|
16
|
+
async function executeTeamRun(...args: Parameters<typeof ExecuteTeamRunFn>): Promise<Awaited<ReturnType<typeof ExecuteTeamRunFn>>> {
|
|
17
|
+
if (!_cachedExecuteTeamRun) {
|
|
18
|
+
const mod = await import("../../runtime/team-runner.ts");
|
|
19
|
+
_cachedExecuteTeamRun = mod.executeTeamRun;
|
|
20
|
+
}
|
|
21
|
+
return _cachedExecuteTeamRun(...args);
|
|
22
|
+
}
|
|
12
23
|
import { spawnBackgroundTeamRun } from "../../subagents/async-entry.ts";
|
|
13
24
|
import { appendEvent, readEvents } from "../../state/event-log.ts";
|
|
14
25
|
import { resolveCrewRuntime, runtimeResolutionState } from "../../runtime/runtime-resolver.ts";
|
|
@@ -26,7 +26,17 @@ import { formatValidationReport, validateResources } from "./validate-resources.
|
|
|
26
26
|
import { formatRecommendation, recommendTeam } from "./team-recommendation.ts";
|
|
27
27
|
import type { PiTeamsToolResult } from "./tool-result.ts";
|
|
28
28
|
import type { ArtifactDescriptor, TeamRunManifest, TeamTaskState } from "../state/types.ts";
|
|
29
|
-
|
|
29
|
+
// Heavy runtime — lazy-loaded to avoid 1.4s import cost at extension registration.
|
|
30
|
+
// executeTeamRun is only called when a team run actually executes.
|
|
31
|
+
import type { executeTeamRun as ExecuteTeamRunFn } from "../runtime/team-runner.ts";
|
|
32
|
+
let _cachedExecuteTeamRun: typeof ExecuteTeamRunFn | undefined;
|
|
33
|
+
async function executeTeamRun(...args: Parameters<typeof ExecuteTeamRunFn>): Promise<Awaited<ReturnType<typeof ExecuteTeamRunFn>>> {
|
|
34
|
+
if (!_cachedExecuteTeamRun) {
|
|
35
|
+
const mod = await import("../runtime/team-runner.ts");
|
|
36
|
+
_cachedExecuteTeamRun = mod.executeTeamRun;
|
|
37
|
+
}
|
|
38
|
+
return _cachedExecuteTeamRun(...args);
|
|
39
|
+
}
|
|
30
40
|
import { checkProcessLiveness, isActiveRunStatus } from "../runtime/process-status.ts";
|
|
31
41
|
import { saveCrewAgents, readCrewAgents, recordFromTask } from "../runtime/crew-agent-records.ts";
|
|
32
42
|
import { resolveCrewRuntime, runtimeResolutionState } from "../runtime/runtime-resolver.ts";
|
|
@@ -227,7 +237,8 @@ export async function handleTeamTool(params: TeamToolParamsValue, ctx: TeamConte
|
|
|
227
237
|
case "get": return handleGet(params, ctx);
|
|
228
238
|
case "init": {
|
|
229
239
|
const cfg = configRecord(params.config);
|
|
230
|
-
const
|
|
240
|
+
const ignoreMethod = typeof cfg.ignoreMethod === "string" && (cfg.ignoreMethod === "gitignore" || cfg.ignoreMethod === "exclude") ? cfg.ignoreMethod : undefined;
|
|
241
|
+
const initialized = initializeProject(ctx.cwd, { copyBuiltins: cfg.copyBuiltins === true, overwrite: cfg.overwrite === true, configScope: cfg.configScope === "project" || cfg.scope === "project" ? "project" : cfg.configScope === "none" || cfg.scope === "none" ? "none" : "global", ignoreMethod });
|
|
231
242
|
return result([
|
|
232
243
|
"Initialized pi-crew project layout.",
|
|
233
244
|
"Directories:",
|
|
@@ -236,7 +247,7 @@ export async function handleTeamTool(params: TeamToolParamsValue, ctx: TeamConte
|
|
|
236
247
|
...(initialized.copiedFiles.length ? initialized.copiedFiles.map((file) => `- ${file}`) : ["- (none)"]),
|
|
237
248
|
...(initialized.skippedFiles.length ? ["Skipped existing files:", ...initialized.skippedFiles.map((file) => `- ${file}`)] : []),
|
|
238
249
|
`Config: ${initialized.configPath || "(none)"} (${initialized.configScope}${initialized.configCreated ? "; created" : initialized.configSkipped ? "; already existed" : "; unchanged"})`,
|
|
239
|
-
`
|
|
250
|
+
`Ignore: ${initialized.gitignorePath} (${initialized.gitignoreUpdated ? "updated" : "already configured"})`,
|
|
240
251
|
].join("\n"), { action: "init", status: "ok" });
|
|
241
252
|
}
|
|
242
253
|
case "help": return result(piTeamsHelp(), { action: "help", status: "ok" });
|