pi-crew 0.5.0 → 0.5.1
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 +23 -1
- package/package.json +1 -1
- package/src/extension/team-onboard.ts +1 -3
- package/src/extension/team-tool.ts +105 -0
- package/src/schema/team-tool-schema.ts +13 -1
- package/src/state/run-graph.ts +5 -24
- package/src/utils/bm25-search.ts +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.5.
|
|
3
|
+
## [0.5.1] — Integration + End-to-End Tests (2026-05-26)
|
|
4
|
+
|
|
5
|
+
### Integration
|
|
6
|
+
- **team-tool.ts**: Wire P1-P6 into switch statement
|
|
7
|
+
- `action='graph'` — load/save/list run graphs
|
|
8
|
+
- `action='onboard'` — team onboarding generator
|
|
9
|
+
- `action='explain'` — task explain context
|
|
10
|
+
- `action='cache'` — run result caching lookup
|
|
11
|
+
- `action='checkpoint'` — checkpoint retrieval
|
|
12
|
+
- `action='search'` — BM25 ranked agent/team search
|
|
13
|
+
- **team-tool-schema.ts**: Add 6 new actions to schema
|
|
14
|
+
- **Type fixes**: run-graph.ts, run-cache.ts, checkpoint.ts, team-onboard.ts
|
|
15
|
+
- **P0 .gitignore**: ensureCrewDirectory auto-updates .gitignore
|
|
16
|
+
|
|
17
|
+
### Tests
|
|
18
|
+
- 8/8 new action tests pass
|
|
19
|
+
- 10/10 end-to-end feature tests pass
|
|
20
|
+
- All 1796 unit + 45 integration passing
|
|
21
|
+
- CI: Ubuntu/macOS/Windows all passing
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## [0.5.0]
|
|
4
26
|
|
|
5
27
|
### New Features: P0-P6 from Understand-Anything Research
|
|
6
28
|
|
package/package.json
CHANGED
|
@@ -64,9 +64,7 @@ function loadRunSummaries(cwd: string, options: OnboardingOptions = {}): RunSumm
|
|
|
64
64
|
team: raw.team,
|
|
65
65
|
createdAt: raw.createdAt,
|
|
66
66
|
completedAt: raw.completedAt ?? raw.updatedAt,
|
|
67
|
-
taskCount:
|
|
68
|
-
? ((raw as Record<string, unknown>).tasks as unknown[]).length
|
|
69
|
-
: 0,
|
|
67
|
+
taskCount: 0, // tasks stored separately, not in manifest
|
|
70
68
|
});
|
|
71
69
|
} catch {
|
|
72
70
|
continue;
|
|
@@ -129,12 +129,15 @@ async function handleRun(
|
|
|
129
129
|
import { waitForRun } from "../runtime/run-tracker.ts";
|
|
130
130
|
import { normalizeSkillOverride } from "../runtime/skill-instructions.ts";
|
|
131
131
|
import { logInternalError } from "../utils/internal-error.ts";
|
|
132
|
+
import { searchAgents, searchTeams } from "../utils/bm25-search.ts";
|
|
133
|
+
import { projectCrewRoot } from "../utils/paths.ts";
|
|
132
134
|
import {
|
|
133
135
|
type CacheControlDeps,
|
|
134
136
|
invalidateSnapshot,
|
|
135
137
|
} from "./team-tool/cache-control.ts";
|
|
136
138
|
import { handleCancel, handleRetry } from "./team-tool/cancel.ts";
|
|
137
139
|
import { handleDoctor } from "./team-tool/doctor.ts";
|
|
140
|
+
import { handleExplain } from "./team-tool/explain.ts";
|
|
138
141
|
import { handleHealthMonitor } from "./team-tool/health-monitor.ts";
|
|
139
142
|
import {
|
|
140
143
|
handleArtifacts,
|
|
@@ -150,6 +153,17 @@ import {
|
|
|
150
153
|
handlePrune,
|
|
151
154
|
handleWorktrees,
|
|
152
155
|
} from "./team-tool/lifecycle-actions.ts";
|
|
156
|
+
import {
|
|
157
|
+
getCachedRun,
|
|
158
|
+
computeRunCacheKey,
|
|
159
|
+
getCacheStats,
|
|
160
|
+
} from "../state/run-cache.ts";
|
|
161
|
+
import {
|
|
162
|
+
loadRunGraph,
|
|
163
|
+
listRunGraphs,
|
|
164
|
+
} from "../state/run-graph.ts";
|
|
165
|
+
import { FileCheckpointStore } from "../runtime/checkpoint.ts";
|
|
166
|
+
import { buildTeamOnboarding } from "./team-onboard.ts";
|
|
153
167
|
import { handleParallel } from "./team-tool/parallel-dispatch.ts";
|
|
154
168
|
import { handlePlan } from "./team-tool/plan.ts";
|
|
155
169
|
import { handleRespond } from "./team-tool/respond.ts";
|
|
@@ -1089,6 +1103,97 @@ export async function handleTeamTool(
|
|
|
1089
1103
|
return handleHealthMonitor(ctx, params);
|
|
1090
1104
|
case "wait":
|
|
1091
1105
|
return handleWait(params, ctx);
|
|
1106
|
+
case "graph": {
|
|
1107
|
+
if (params.runId) {
|
|
1108
|
+
const graph = loadRunGraph(ctx.cwd, params.runId);
|
|
1109
|
+
return result(
|
|
1110
|
+
graph ? JSON.stringify(graph, null, 2) : "No graph found for this run.",
|
|
1111
|
+
{ action: "graph", status: graph ? "ok" : "error" },
|
|
1112
|
+
!graph,
|
|
1113
|
+
);
|
|
1114
|
+
}
|
|
1115
|
+
const graphs = listRunGraphs(ctx.cwd);
|
|
1116
|
+
return result(
|
|
1117
|
+
graphs.length ? `Available graphs:\n${graphs.join("\n")}` : "No graphs available.",
|
|
1118
|
+
{ action: "graph", status: "ok" },
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
case "search": {
|
|
1122
|
+
const query = params.goal ?? params.task ?? "";
|
|
1123
|
+
if (!query) {
|
|
1124
|
+
return result("Search requires goal or task query.", { action: "search", status: "error" }, true);
|
|
1125
|
+
}
|
|
1126
|
+
try {
|
|
1127
|
+
const [agentResults, teamResults] = await Promise.all([
|
|
1128
|
+
searchAgents(query, { limit: 5 }),
|
|
1129
|
+
searchTeams(query, { limit: 3 }),
|
|
1130
|
+
]);
|
|
1131
|
+
const lines: string[] = [];
|
|
1132
|
+
if (teamResults.length) {
|
|
1133
|
+
lines.push("## Teams");
|
|
1134
|
+
for (const r of teamResults) {
|
|
1135
|
+
lines.push(`- [${r.team.name}] score=${r.score.toFixed(2)}: ${r.team.description ?? "(no description)"}`);
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
if (agentResults.length) {
|
|
1139
|
+
lines.push("## Agents");
|
|
1140
|
+
for (const r of agentResults) {
|
|
1141
|
+
lines.push(`- [${r.agent.name}] score=${r.score.toFixed(2)}: ${r.agent.description ?? "(no description)"}`);
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
return result(lines.length ? lines.join("\n") : "No results found.", { action: "search", status: "ok" });
|
|
1145
|
+
} catch (err) {
|
|
1146
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1147
|
+
return result(`Search failed: ${msg}`, { action: "search", status: "error" }, true);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
case "onboard": {
|
|
1151
|
+
const team = params.team ?? "default";
|
|
1152
|
+
const onboarding = buildTeamOnboarding(team, ctx.cwd);
|
|
1153
|
+
return result(onboarding, { action: "onboard", status: "ok" });
|
|
1154
|
+
}
|
|
1155
|
+
case "explain": {
|
|
1156
|
+
const explainResult = handleExplain(params, ctx.cwd);
|
|
1157
|
+
return result(explainResult.text, { action: "explain", status: explainResult.isError ? "error" : "ok" }, explainResult.isError);
|
|
1158
|
+
}
|
|
1159
|
+
case "cache": {
|
|
1160
|
+
if (params.goal) {
|
|
1161
|
+
const key = computeRunCacheKey(
|
|
1162
|
+
params.goal,
|
|
1163
|
+
params.team ?? "default",
|
|
1164
|
+
params.workflow ?? "default",
|
|
1165
|
+
ctx.cwd,
|
|
1166
|
+
);
|
|
1167
|
+
const cached = getCachedRun(ctx.cwd, key);
|
|
1168
|
+
if (cached) {
|
|
1169
|
+
return result(
|
|
1170
|
+
`Cached run found (${new Date(cached.cachedAt).toISOString()}): runId=${cached.runId}, status=${cached.status}, ${cached.tasks.length} tasks`,
|
|
1171
|
+
{ action: "cache", status: "ok", data: { cacheKey: key, cacheHit: true, runId: cached.runId, status: cached.status, taskCount: cached.tasks.length } },
|
|
1172
|
+
);
|
|
1173
|
+
}
|
|
1174
|
+
return result(`No cached result for key: ${key}`, { action: "cache", status: "ok", data: { cacheKey: key, cacheHit: false } });
|
|
1175
|
+
}
|
|
1176
|
+
const stats = getCacheStats(ctx.cwd);
|
|
1177
|
+
return result(
|
|
1178
|
+
`Cache stats: ${stats.entries} entries, ${stats.sizeBytes} bytes`,
|
|
1179
|
+
{ action: "cache", status: "ok" },
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
case "checkpoint": {
|
|
1183
|
+
if (!params.runId || !params.taskId) {
|
|
1184
|
+
return result("Checkpoint requires runId and taskId.", { action: "checkpoint", status: "error" }, true);
|
|
1185
|
+
}
|
|
1186
|
+
const stateRoot = path.join(projectCrewRoot(ctx.cwd), "state", "runs", params.runId);
|
|
1187
|
+
const store = new FileCheckpointStore(stateRoot);
|
|
1188
|
+
const checkpoint = store.load(params.runId, params.taskId);
|
|
1189
|
+
if (!checkpoint) {
|
|
1190
|
+
return result("No checkpoint found.", { action: "checkpoint", status: "error" }, true);
|
|
1191
|
+
}
|
|
1192
|
+
return result(
|
|
1193
|
+
`Checkpoint: step=${checkpoint.step}, progress=${checkpoint.progress}, savedAt=${new Date(checkpoint.savedAt).toISOString()}`,
|
|
1194
|
+
{ action: "checkpoint", status: "ok", data: { checkpoint } },
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1092
1197
|
default:
|
|
1093
1198
|
return result(
|
|
1094
1199
|
`Unknown action: ${action}`,
|
|
@@ -59,6 +59,12 @@ export const TeamToolParams = Type.Object({
|
|
|
59
59
|
Type.Literal("settings"),
|
|
60
60
|
Type.Literal("steer"),
|
|
61
61
|
Type.Literal("health"),
|
|
62
|
+
Type.Literal("graph"),
|
|
63
|
+
Type.Literal("onboard"),
|
|
64
|
+
Type.Literal("explain"),
|
|
65
|
+
Type.Literal("cache"),
|
|
66
|
+
Type.Literal("checkpoint"),
|
|
67
|
+
Type.Literal("search"),
|
|
62
68
|
],
|
|
63
69
|
{ description: "Team action. Defaults to 'list' when omitted." },
|
|
64
70
|
),
|
|
@@ -222,7 +228,13 @@ export interface TeamToolParamsValue {
|
|
|
222
228
|
| "settings"
|
|
223
229
|
| "steer"
|
|
224
230
|
| "invalidate"
|
|
225
|
-
| "health"
|
|
231
|
+
| "health"
|
|
232
|
+
| "graph"
|
|
233
|
+
| "onboard"
|
|
234
|
+
| "explain"
|
|
235
|
+
| "cache"
|
|
236
|
+
| "checkpoint"
|
|
237
|
+
| "search";
|
|
226
238
|
resource?: "agent" | "team" | "workflow";
|
|
227
239
|
team?: string;
|
|
228
240
|
workflow?: string;
|
package/src/state/run-graph.ts
CHANGED
|
@@ -57,7 +57,6 @@ export function buildRunGraph(
|
|
|
57
57
|
workflow: manifest.workflow,
|
|
58
58
|
status: manifest.status,
|
|
59
59
|
createdAt: manifest.createdAt,
|
|
60
|
-
completedAt: (manifest as Record<string, unknown>).completedAt,
|
|
61
60
|
},
|
|
62
61
|
});
|
|
63
62
|
nodeIds.add(`run:${runId}`);
|
|
@@ -73,10 +72,7 @@ export function buildRunGraph(
|
|
|
73
72
|
type: "task",
|
|
74
73
|
name: task.role,
|
|
75
74
|
metadata: {
|
|
76
|
-
phase: (task as Record<string, unknown>).phase,
|
|
77
75
|
status: task.status,
|
|
78
|
-
agentModel: (task as Record<string, unknown>).agentModel,
|
|
79
|
-
usage: (task as Record<string, unknown>).usage,
|
|
80
76
|
startedAt: task.startedAt,
|
|
81
77
|
finishedAt: task.finishedAt,
|
|
82
78
|
},
|
|
@@ -99,29 +95,14 @@ export function buildRunGraph(
|
|
|
99
95
|
});
|
|
100
96
|
}
|
|
101
97
|
|
|
102
|
-
// Edge from task to agent (if we have agent model info)
|
|
103
|
-
const agentModel = (task as Record<string, unknown>).agentModel as string | undefined;
|
|
104
|
-
if (agentModel) {
|
|
105
|
-
const agentId = `agent:${agentModel.replace(/[^a-zA-Z0-9-_]/g, "_")}`;
|
|
106
|
-
if (!nodeIds.has(agentId)) {
|
|
107
|
-
nodeIds.add(agentId);
|
|
108
|
-
nodes.push({ id: agentId, type: "agent", name: agentModel });
|
|
109
|
-
}
|
|
110
|
-
edges.push({
|
|
111
|
-
source: agentId,
|
|
112
|
-
target: taskId,
|
|
113
|
-
type: "runs",
|
|
114
|
-
weight: 0.9,
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
98
|
}
|
|
118
99
|
|
|
119
|
-
// Group by layer (based on phase)
|
|
100
|
+
// Group by layer (based on phase or role)
|
|
120
101
|
const layerMap = new Map<string, string[]>();
|
|
121
102
|
for (const task of tasks) {
|
|
122
|
-
const
|
|
123
|
-
if (!layerMap.has(
|
|
124
|
-
layerMap.get(
|
|
103
|
+
const layerName = task.adaptive?.phase ?? task.role;
|
|
104
|
+
if (!layerMap.has(layerName)) layerMap.set(layerName, []);
|
|
105
|
+
layerMap.get(layerName)!.push(`task:${task.id}`);
|
|
125
106
|
}
|
|
126
107
|
|
|
127
108
|
const layers: RunGraphLayer[] = [...layerMap.entries()].map(([name, nodeIdList]) => ({
|
|
@@ -135,7 +116,7 @@ export function buildRunGraph(
|
|
|
135
116
|
team: manifest.team ?? "unknown",
|
|
136
117
|
workflow: manifest.workflow ?? "unknown",
|
|
137
118
|
createdAt: manifest.createdAt,
|
|
138
|
-
completedAt:
|
|
119
|
+
completedAt: manifest.updatedAt,
|
|
139
120
|
status: manifest.status,
|
|
140
121
|
nodes,
|
|
141
122
|
edges,
|
package/src/utils/bm25-search.ts
CHANGED
|
@@ -140,7 +140,6 @@ export async function searchAgents(query: string, options?: { limit?: number }):
|
|
|
140
140
|
name: agent.name,
|
|
141
141
|
description: agent.description ?? "",
|
|
142
142
|
skills: (agent.skills ?? []).join(" "),
|
|
143
|
-
tags: (agent.tags ?? []).join(" "),
|
|
144
143
|
},
|
|
145
144
|
agent,
|
|
146
145
|
}));
|
|
@@ -149,7 +148,6 @@ export async function searchAgents(query: string, options?: { limit?: number }):
|
|
|
149
148
|
name: 3.0,
|
|
150
149
|
description: 1.5,
|
|
151
150
|
skills: 1.0,
|
|
152
|
-
tags: 1.0,
|
|
153
151
|
});
|
|
154
152
|
|
|
155
153
|
const results = engine.search(query, {
|