pi-crew 0.9.14 → 0.9.16
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 +126 -0
- package/README.md +66 -0
- package/package.json +1 -1
- package/src/config/types.ts +5 -0
- package/src/extension/registration/team-tool.ts +145 -35
- package/src/extension/team-tool/run.ts +646 -150
- package/src/runtime/crew-agent-records.ts +55 -0
- package/src/runtime/subagent-manager.ts +42 -0
- package/src/runtime/team-runner.ts +1445 -318
- package/src/workflows/discover-workflows.ts +144 -29
- package/src/workflows/preflight-validator.ts +195 -0
- package/src/workflows/topology-analyzer.ts +219 -0
- package/src/workflows/workflow-config.ts +11 -0
- package/workflows/chain.workflow.md +6 -0
- package/workflows/default.workflow.md +1 -0
- package/workflows/fast-fix.workflow.md +1 -0
- package/workflows/implementation.workflow.md +1 -0
- package/workflows/parallel-research.workflow.md +1 -0
- package/workflows/pipeline.workflow.md +1 -0
- package/workflows/research.workflow.md +1 -0
- package/workflows/review.workflow.md +1 -0
|
@@ -206,9 +206,64 @@ export function saveCrewAgents(manifest: TeamRunManifest, records: CrewAgentReco
|
|
|
206
206
|
|
|
207
207
|
const TERMINAL_AGENT_STATUSES = new Set(["completed", "failed", "cancelled", "blocked"]);
|
|
208
208
|
|
|
209
|
+
/**
|
|
210
|
+
* User policy (v0.9.16): cancelled / stopped crew-agent records leave NO trace.
|
|
211
|
+
* `failed` records keep their audit trail (different from cancel — agent errored).
|
|
212
|
+
*/
|
|
213
|
+
export function shouldDeleteCrewAgentOnTerminalStatus(
|
|
214
|
+
record: Pick<CrewAgentRecord, "status">,
|
|
215
|
+
): boolean {
|
|
216
|
+
const s = record.status;
|
|
217
|
+
return s === "cancelled" || s === "stopped";
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Remove a single crew-agent record from both `agents.json` (the index file)
|
|
222
|
+
* and the per-task `status.json`. Called on cancellation to wipe the trace.
|
|
223
|
+
* Safe-fail: missing files are treated as success (already removed).
|
|
224
|
+
*/
|
|
225
|
+
export function removeCrewAgent(
|
|
226
|
+
manifest: TeamRunManifest,
|
|
227
|
+
taskId: string,
|
|
228
|
+
): { removedIndex: boolean; removedStatus: boolean } {
|
|
229
|
+
let removedIndex = false;
|
|
230
|
+
let removedStatus = false;
|
|
231
|
+
// 1. Remove from agents.json index
|
|
232
|
+
try {
|
|
233
|
+
const existing = readCrewAgents(manifest);
|
|
234
|
+
const filtered = existing.filter((r) => r.taskId !== taskId);
|
|
235
|
+
if (filtered.length !== existing.length) {
|
|
236
|
+
saveCrewAgents(manifest, filtered);
|
|
237
|
+
removedIndex = true;
|
|
238
|
+
}
|
|
239
|
+
} catch {
|
|
240
|
+
// best-effort
|
|
241
|
+
}
|
|
242
|
+
// 2. Remove per-task status.json
|
|
243
|
+
try {
|
|
244
|
+
const statusPath = agentStatusPath(manifest, taskId);
|
|
245
|
+
if (fs.existsSync(statusPath)) {
|
|
246
|
+
fs.unlinkSync(statusPath);
|
|
247
|
+
removedStatus = true;
|
|
248
|
+
}
|
|
249
|
+
} catch {
|
|
250
|
+
// best-effort
|
|
251
|
+
}
|
|
252
|
+
return { removedIndex, removedStatus };
|
|
253
|
+
}
|
|
254
|
+
|
|
209
255
|
export function upsertCrewAgent(manifest: TeamRunManifest, record: CrewAgentRecord): void {
|
|
210
256
|
// Guard: skip if run state has been deleted (prune/forget/cleanup)
|
|
211
257
|
try { fs.statSync(manifest.stateRoot); } catch { return; }
|
|
258
|
+
// User policy (v0.9.16): cancelled / stopped crew agents leave NO trace.
|
|
259
|
+
// We delete BOTH the index entry (agents.json) and the per-task status.json
|
|
260
|
+
// immediately so the UI dashboard/widget never see the cancelled agent again.
|
|
261
|
+
if (shouldDeleteCrewAgentOnTerminalStatus(record)) {
|
|
262
|
+
removeCrewAgent(manifest, record.taskId);
|
|
263
|
+
// Invalidate the per-task reader cache so a subsequent read sees fresh state.
|
|
264
|
+
asyncAgentReaderCache.delete(agentsPath(manifest));
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
212
267
|
// Read current state
|
|
213
268
|
const existing = readCrewAgents(manifest);
|
|
214
269
|
// Deduplicate by id: keep newer record when same id appears
|
|
@@ -114,6 +114,36 @@ export function savePersistedSubagentRecord(
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Delete the persisted subagent record from disk.
|
|
119
|
+
* Used when a subagent is cancelled or terminated — the user wants no trace.
|
|
120
|
+
* Safe-fail: if the file does not exist (already deleted), this is a no-op.
|
|
121
|
+
* Any other I/O error is logged but not propagated.
|
|
122
|
+
*/
|
|
123
|
+
export function removePersistedSubagentRecord(cwd: string, id: string): boolean {
|
|
124
|
+
try {
|
|
125
|
+
const filePath = persistedSubagentPath(cwd, id);
|
|
126
|
+
fs.unlinkSync(filePath);
|
|
127
|
+
return true;
|
|
128
|
+
} catch (error) {
|
|
129
|
+
const code = (error as NodeJS.ErrnoException)?.code;
|
|
130
|
+
if (code === "ENOENT") return false;
|
|
131
|
+
logInternalError("subagent-manager.remove", error, `id=${id}`);
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Predicate: should this record's persisted file be deleted on terminal status?
|
|
138
|
+
* Only abnormal terminations (cancelled / stopped / terminated-flag) are wiped.
|
|
139
|
+
* Successful runs (`completed`) and agent errors (`failed`, `error`) keep their audit trail.
|
|
140
|
+
*/
|
|
141
|
+
export function shouldDeleteOnTerminalStatus(record: SubagentRecord): boolean {
|
|
142
|
+
if (record.terminated === true) return true;
|
|
143
|
+
const s = record.status;
|
|
144
|
+
return s === "cancelled" || s === "stopped";
|
|
145
|
+
}
|
|
146
|
+
|
|
117
147
|
const ALLOWED_RECORD_FIELDS = new Set([
|
|
118
148
|
"id",
|
|
119
149
|
"agentId",
|
|
@@ -427,6 +457,12 @@ export class SubagentManager {
|
|
|
427
457
|
? Math.max(0, record.completedAt - record.startedAt)
|
|
428
458
|
: undefined;
|
|
429
459
|
savePersistedSubagentRecord(options.cwd, record);
|
|
460
|
+
// User policy (v0.9.16): cancelled / stopped subagents leave NO trace.
|
|
461
|
+
// Successful runs (`completed`) and agent errors (`failed`, `error`)
|
|
462
|
+
// keep their audit trail. See shouldDeleteOnTerminalStatus().
|
|
463
|
+
if (shouldDeleteOnTerminalStatus(record)) {
|
|
464
|
+
removePersistedSubagentRecord(options.cwd, record.id);
|
|
465
|
+
}
|
|
430
466
|
this.onComplete?.(record);
|
|
431
467
|
}
|
|
432
468
|
this.drainQueue();
|
|
@@ -451,10 +487,16 @@ export class SubagentManager {
|
|
|
451
487
|
|
|
452
488
|
private markStopped(record: SubagentRecord, reason?: string): void {
|
|
453
489
|
record.status = "stopped";
|
|
490
|
+
record.terminated = true;
|
|
454
491
|
record.completedAt = Date.now();
|
|
455
492
|
if (reason && !record.error) record.error = reason;
|
|
456
493
|
const cwd = this.cwdByRecord.get(record.id);
|
|
494
|
+
// User policy (v0.9.16): stopped subagents leave NO trace on disk.
|
|
495
|
+
// Save first (so any concurrent reader sees the final status), then
|
|
496
|
+
// unlink. The race window is microseconds and the file is gone before
|
|
497
|
+
// the next widget/dashboard tick.
|
|
457
498
|
if (cwd) savePersistedSubagentRecord(cwd, record);
|
|
499
|
+
if (cwd) removePersistedSubagentRecord(cwd, record.id);
|
|
458
500
|
}
|
|
459
501
|
|
|
460
502
|
private createRunSignal(id: string, signal?: AbortSignal): AbortSignal {
|