pi-crew 0.1.36 → 0.1.37

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-crew",
3
- "version": "0.1.36",
3
+ "version": "0.1.37",
4
4
  "description": "Pi extension for coordinated AI teams, workflows, worktrees, and async task orchestration",
5
5
  "author": "baphuongna",
6
6
  "license": "MIT",
@@ -46,7 +46,7 @@ export class HeartbeatWatcher {
46
46
  const loaded = loadRunManifestById(this.opts.cwd, run.runId);
47
47
  if (!loaded) continue;
48
48
  for (const task of loaded.tasks) {
49
- if (task.status !== "running" && task.status !== "queued") continue;
49
+ if (task.status !== "running") continue;
50
50
  const key = `${run.runId}:${task.id}`;
51
51
  const elapsed = heartbeatAgeMs(task.heartbeat, now);
52
52
  const level = classifyHeartbeat(task.heartbeat, thresholds, now);
@@ -106,8 +106,16 @@ export async function runTeamTask(input: TaskRunnerInput): Promise<{ manifest: T
106
106
  const transcriptPath = `${manifest.artifactsRoot}/transcripts/${task.id}.jsonl`;
107
107
  let finalCheckpointWritten = false;
108
108
  let lastAgentRecordPersistedAt = 0;
109
+ let lastHeartbeatPersistedAt = 0;
109
110
  let lastRunProgressPersistedAt = 0;
110
111
  let lastRunProgressSummary: ProgressEventSummary | undefined;
112
+ const persistHeartbeat = (force = false): void => {
113
+ const now = Date.now();
114
+ if (!force && now - lastHeartbeatPersistedAt < 1000) return;
115
+ lastHeartbeatPersistedAt = now;
116
+ task = { ...task, heartbeat: touchWorkerHeartbeat(task.heartbeat ?? createWorkerHeartbeat(task.id)) };
117
+ tasks = persistSingleTaskUpdate(manifest, tasks, task);
118
+ };
111
119
  const persistChildProgress = (event: unknown, force = false): void => {
112
120
  const now = Date.now();
113
121
  if (force || shouldFlushProgressEvent(event) || now - lastAgentRecordPersistedAt >= 500) {
@@ -140,9 +148,13 @@ export async function runTeamTask(input: TaskRunnerInput): Promise<{ manifest: T
140
148
  onSpawn: (pid) => {
141
149
  ({ task, tasks } = checkpointTask(manifest, tasks, task, "child-spawned", pid));
142
150
  },
143
- onStdoutLine: (line) => appendCrewAgentOutput(manifest, task.id, line),
151
+ onStdoutLine: (line) => {
152
+ appendCrewAgentOutput(manifest, task.id, line);
153
+ persistHeartbeat();
154
+ },
144
155
  onJsonEvent: (event) => {
145
156
  appendCrewAgentEvent(manifest, task.id, event);
157
+ persistHeartbeat();
146
158
  task = { ...task, agentProgress: applyAgentProgressEvent(task.agentProgress ?? emptyCrewAgentProgress(), event, task.startedAt) };
147
159
  tasks = updateTask(tasks, task);
148
160
  if (!finalCheckpointWritten && isFinalChildEvent(event)) {
@@ -158,6 +170,7 @@ export async function runTeamTask(input: TaskRunnerInput): Promise<{ manifest: T
158
170
  finalStderr = childResult.stderr;
159
171
  parsedOutput = parsePiJsonOutput(fs.existsSync(transcriptPath) ? fs.readFileSync(transcriptPath, "utf-8") : childResult.stdout);
160
172
  error = childResult.error || (childResult.exitCode && childResult.exitCode !== 0 ? childResult.stderr || `Child Pi exited with ${childResult.exitCode}` : undefined);
173
+ persistHeartbeat(true);
161
174
  persistChildProgress({ type: "attempt_finished" }, true);
162
175
  const attempt: ModelAttemptSummary = { model: model ?? "default", success: !error, exitCode, error };
163
176
  modelAttempts.push(attempt);
@@ -28,7 +28,7 @@ function nowMs(now: number | Date | undefined): number {
28
28
  }
29
29
 
30
30
  function isActiveTask(task: TeamTaskState): boolean {
31
- return task.status === "running" || task.status === "queued";
31
+ return task.status === "running";
32
32
  }
33
33
 
34
34
  export function summarizeHeartbeats(snapshot: RunUiSnapshot, opts: HeartbeatSummaryOptions = {}): HeartbeatSummary {