pi-crew 0.9.49 → 0.9.50

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +209 -0
  2. package/dist/build-meta.json +50 -32
  3. package/dist/index.mjs +75 -42
  4. package/dist/index.mjs.map +4 -4
  5. package/package.json +1 -2
  6. package/skills/distill-persona/SKILL.md +83 -145
  7. package/skills/distill-persona/references/cross-skill-differentiation.md +12 -0
  8. package/skills/distill-persona/references/description-discipline.md +6 -0
  9. package/skills/distill-persona/references/diagnostic-path.md +25 -0
  10. package/skills/distill-persona/references/fidelity-rubric.md +19 -0
  11. package/skills/distill-persona/references/field-models.md +20 -0
  12. package/skills/distill-persona/references/optional-body-sections.md +9 -0
  13. package/skills/distill-persona/references/registry-routing.md +11 -0
  14. package/skills/distill-persona/references/self-upgrade-directive.md +20 -0
  15. package/skills/distill-persona/references/taste-principles.md +8 -0
  16. package/skills/distill-persona/references/topic-variant.md +13 -0
  17. package/skills/distill-persona/references/update-mode.md +7 -0
  18. package/skills/distill-persona/scripts/validate-run.mjs +297 -0
  19. package/skills/distill-software/SKILL.md +151 -90
  20. package/skills/research/SKILL.md +1 -1
  21. package/src/extension/crew-cleanup.ts +18 -1
  22. package/src/extension/crew-vibes/index.ts +11 -2
  23. package/src/extension/register.ts +1 -1
  24. package/src/extension/registration/command-registration.ts +1 -0
  25. package/src/extension/registration/commands.ts +7 -3
  26. package/src/extension/registration/lifecycle-handlers.ts +1 -3
  27. package/src/extension/registration/ui.ts +4 -0
  28. package/src/extension/registration/viewers.ts +3 -0
  29. package/src/extension/team-tool/run.ts +7 -6
  30. package/src/runtime/chain-runner.ts +3 -2
  31. package/src/runtime/pipeline-runner.ts +8 -7
  32. package/src/ui/live-run-sidebar.ts +2 -0
  33. package/src/ui/mascot.ts +11 -9
  34. package/src/ui/render-coalescer.ts +9 -0
  35. package/src/ui/run-snapshot-cache.ts +10 -11
  36. package/src/ui/terminal-status.ts +5 -0
  37. package/src/ui/widget/index.ts +3 -5
  38. package/src/ui/widget/widget-types.ts +0 -1
  39. package/assets/runner-spritesheet.png +0 -0
package/dist/index.mjs CHANGED
@@ -6893,8 +6893,8 @@ function extractErrorMessage(event) {
6893
6893
  const obj = asRecord3(event);
6894
6894
  if (!obj) return void 0;
6895
6895
  const message = asRecord3(obj.message) ?? obj;
6896
- const errorMessage = message.errorMessage;
6897
- return typeof errorMessage === "string" && errorMessage.trim() ? errorMessage.trim() : void 0;
6896
+ const errorMessage2 = message.errorMessage;
6897
+ return typeof errorMessage2 === "string" && errorMessage2.trim() ? errorMessage2.trim() : void 0;
6898
6898
  }
6899
6899
  function extractPatch(event, patches) {
6900
6900
  const obj = asRecord3(event);
@@ -8078,7 +8078,8 @@ var init_child_pi = __esm({
8078
8078
  });
8079
8079
 
8080
8080
  // src/extension/crew-cleanup.ts
8081
- function registerCleanupHandler(pi) {
8081
+ function registerCleanupHandler(pi, opts) {
8082
+ terminalStatusDispose = opts?.disposeTerminalStatus;
8082
8083
  pi.on("session_shutdown", async () => {
8083
8084
  console.log("[pi-crew] Session shutdown - cleaning up resources");
8084
8085
  try {
@@ -8093,6 +8094,10 @@ function registerCleanupHandler(pi) {
8093
8094
  signalHandlersRegistered = true;
8094
8095
  const handleSignal = async (signal) => {
8095
8096
  console.log(`[pi-crew] Received ${signal} - starting cleanup`);
8097
+ try {
8098
+ terminalStatusDispose?.();
8099
+ } catch {
8100
+ }
8096
8101
  await cleanupChildProcesses();
8097
8102
  };
8098
8103
  process.on("SIGTERM", () => {
@@ -8140,7 +8145,7 @@ function registerChildProcess(pid, runId, agentId) {
8140
8145
  function unregisterChildProcess(pid) {
8141
8146
  childProcessRegistry.unregister(pid);
8142
8147
  }
8143
- var signalHandlersRegistered, ChildProcessRegistry, childProcessRegistry;
8148
+ var signalHandlersRegistered, ChildProcessRegistry, childProcessRegistry, terminalStatusDispose;
8144
8149
  var init_crew_cleanup = __esm({
8145
8150
  "src/extension/crew-cleanup.ts"() {
8146
8151
  "use strict";
@@ -40864,6 +40869,14 @@ var init_render_coalescer = __esm({
40864
40869
  this.#timerId = null;
40865
40870
  }
40866
40871
  this.#pending = false;
40872
+ const dropped = this.#dropped;
40873
+ this.#dropped = 0;
40874
+ if (dropped > 0) {
40875
+ try {
40876
+ this.#onDrop(dropped);
40877
+ } catch {
40878
+ }
40879
+ }
40867
40880
  this.#callback();
40868
40881
  }
40869
40882
  /** Check if a render is pending. */
@@ -44021,8 +44034,6 @@ function updateCrewWidget(ctx, state, config, manifestCache2, snapshotCache, pre
44021
44034
  requestRender(ctx);
44022
44035
  }
44023
44036
  function stopCrewWidget(ctx, state, config) {
44024
- if (state.interval) clearInterval(state.interval);
44025
- state.interval = void 0;
44026
44037
  if (ctx?.hasUI) {
44027
44038
  const placement = config?.widgetPlacement ?? DEFAULT_UI.widgetPlacement;
44028
44039
  ctx.ui.setStatus(STATUS_KEY, void 0);
@@ -44093,7 +44104,7 @@ var init_widget = __esm({
44093
44104
  ).join("|");
44094
44105
  const hasRunning = runs.some((entry) => entry.agents.some((a) => a.status === "running")) || [...listLiveAgents()].some((h) => h.status === "running");
44095
44106
  const animation = hasRunning ? `:spin=${spinnerBucket()}` : "";
44096
- return runs.map(
44107
+ const sig = runs.map(
44097
44108
  (entry) => entry.snapshot?.signature ?? `${entry.run.runId}:${entry.run.status}:${entry.run.updatedAt}:` + entry.agents.map((a) => {
44098
44109
  const recentOutput = a.progress?.recentOutput.at(-1) ?? "";
44099
44110
  const progress = [
@@ -44107,6 +44118,7 @@ var init_widget = __esm({
44107
44118
  return `${a.status}:${a.startedAt}:${a.completedAt ?? ""}:${a.toolUses ?? 0}:${progress}`;
44108
44119
  }).join(",")
44109
44120
  ).join("|") + `|live:${liveSig}${animation}`;
44121
+ return sig;
44110
44122
  }
44111
44123
  colorize(lines, width) {
44112
44124
  return renderLines(
@@ -54169,6 +54181,16 @@ var init_team_runner = __esm({
54169
54181
  }
54170
54182
  });
54171
54183
 
54184
+ // src/utils/guards.ts
54185
+ function errorMessage(err2) {
54186
+ return err2 instanceof Error ? err2.message : String(err2);
54187
+ }
54188
+ var init_guards = __esm({
54189
+ "src/utils/guards.ts"() {
54190
+ "use strict";
54191
+ }
54192
+ });
54193
+
54172
54194
  // src/state/run-metrics.ts
54173
54195
  function collectRunMetrics(cwd, runId) {
54174
54196
  assertSafePathId("runId", runId);
@@ -54809,6 +54831,7 @@ var ChainRunner;
54809
54831
  var init_chain_runner = __esm({
54810
54832
  "src/runtime/chain-runner.ts"() {
54811
54833
  "use strict";
54834
+ init_guards();
54812
54835
  init_chain_parser();
54813
54836
  ChainRunner = class _ChainRunner {
54814
54837
  /** Maximum number of chain history entries to prevent memory leaks */
@@ -54930,13 +54953,13 @@ var init_chain_runner = __esm({
54930
54953
  });
54931
54954
  }
54932
54955
  } catch (error) {
54933
- const errorMessage = error instanceof Error ? error.message : String(error);
54956
+ const errMsg = errorMessage(error);
54934
54957
  stepResults.push({
54935
54958
  step: i + 1,
54936
54959
  name: step.name,
54937
54960
  outcome: "failure",
54938
54961
  duration: Date.now() - stepStart,
54939
- error: errorMessage
54962
+ error: errMsg
54940
54963
  });
54941
54964
  if (!spec.continueOnError && !step.continueOnError) {
54942
54965
  break;
@@ -57345,7 +57368,7 @@ Use workspaceMode: 'single' or run from a git repository.`,
57345
57368
  try {
57346
57369
  await assertCleanLeaderAsync(gitRoot);
57347
57370
  } catch (err2) {
57348
- const msg = err2 instanceof Error ? err2.message : String(err2);
57371
+ const msg = errorMessage(err2);
57349
57372
  return result(
57350
57373
  `${msg}
57351
57374
  Commit or stash changes before using worktree mode, or use workspaceMode: 'single'.`,
@@ -57516,7 +57539,7 @@ Commit or stash changes before using worktree mode, or use workspaceMode: 'singl
57516
57539
  tokenBudget: params.tokenBudget ?? workflow.maxTokenBudget
57517
57540
  });
57518
57541
  } catch (runnerError) {
57519
- const failureReason = runnerError instanceof Error ? runnerError.message : String(runnerError);
57542
+ const failureReason = errorMessage(runnerError);
57520
57543
  const failedManifest = {
57521
57544
  ...dwfManifest,
57522
57545
  status: "failed",
@@ -57704,13 +57727,13 @@ ${dwfResult.manifest.summary ?? ""}`,
57704
57727
  workspaceId: ctx.sessionId ?? ctx.cwd
57705
57728
  });
57706
57729
  } catch (waitError) {
57707
- const errorMessage = waitError instanceof Error ? waitError.message : String(waitError);
57730
+ const waitErrMsg = errorMessage(waitError);
57708
57731
  return result(
57709
57732
  [
57710
57733
  `pi-crew run timed out or failed: ${updatedManifest.runId}`,
57711
57734
  `Team: ${team.name}`,
57712
57735
  `Workflow: ${workflow.name}`,
57713
- `Error: ${errorMessage}`,
57736
+ `Error: ${waitErrMsg}`,
57714
57737
  "",
57715
57738
  `Check status with: team status runId=${updatedManifest.runId}`,
57716
57739
  `State: ${updatedManifest.stateRoot}`,
@@ -57814,13 +57837,13 @@ ${dwfResult.manifest.summary ?? ""}`,
57814
57837
  workspaceId: ctx.sessionId ?? ctx.cwd
57815
57838
  });
57816
57839
  } catch (waitError) {
57817
- const errorMessage = waitError instanceof Error ? waitError.message : String(waitError);
57840
+ const waitErrMsg = errorMessage(waitError);
57818
57841
  return result(
57819
57842
  [
57820
57843
  `pi-crew run timed out or failed: ${updatedManifest.runId}`,
57821
57844
  `Team: ${team.name}`,
57822
57845
  `Workflow: ${workflow.name}`,
57823
- `Error: ${errorMessage}`,
57846
+ `Error: ${waitErrMsg}`,
57824
57847
  "",
57825
57848
  `Check status with: team status runId=${updatedManifest.runId}`,
57826
57849
  `State: ${updatedManifest.stateRoot}`
@@ -57890,6 +57913,7 @@ var init_run = __esm({
57890
57913
  init_discover_teams();
57891
57914
  init_discover_workflows();
57892
57915
  init_worktree_manager();
57916
+ init_guards();
57893
57917
  init_internal_error();
57894
57918
  init_safe_paths();
57895
57919
  init_runtime_resolver();
@@ -59994,6 +60018,9 @@ async function openLiveConversation(ctx, initialRunId, initialTaskId) {
59994
60018
  }
59995
60019
  },
59996
60020
  invalidate() {
60021
+ },
60022
+ dispose() {
60023
+ overlay.dispose();
59997
60024
  }
59998
60025
  };
59999
60026
  },
@@ -62168,7 +62195,7 @@ var init_mascot = __esm({
62168
62195
  tickTypewriter() {
62169
62196
  const state = this.effectState;
62170
62197
  if (state.pos === void 0) return true;
62171
- for (let i = 0; i < 6; i++) {
62198
+ for (let i = 0; i < 18; i++) {
62172
62199
  const row = Math.floor(state.pos / ARMIN_WIDTH);
62173
62200
  const x = state.pos % ARMIN_WIDTH;
62174
62201
  if (row >= ARMIN_DISPLAY_HEIGHT) return true;
@@ -62180,9 +62207,11 @@ var init_mascot = __esm({
62180
62207
  tickScanline() {
62181
62208
  const state = this.effectState;
62182
62209
  if (state.row === void 0) return true;
62183
- if (state.row >= ARMIN_DISPLAY_HEIGHT) return true;
62184
- for (let x = 0; x < ARMIN_WIDTH; x++) this.currentArminGrid[state.row][x] = this.finalArminGrid[state.row][x];
62185
- state.row++;
62210
+ for (let step = 0; step < 3; step++) {
62211
+ if (state.row >= ARMIN_DISPLAY_HEIGHT) return true;
62212
+ for (let x = 0; x < ARMIN_WIDTH; x++) this.currentArminGrid[state.row][x] = this.finalArminGrid[state.row][x];
62213
+ state.row++;
62214
+ }
62186
62215
  return false;
62187
62216
  }
62188
62217
  tickRain() {
@@ -62204,7 +62233,7 @@ var init_mascot = __esm({
62204
62233
  break;
62205
62234
  }
62206
62235
  }
62207
- drop.y++;
62236
+ drop.y += 3;
62208
62237
  if (drop.y >= 0 && drop.y < ARMIN_DISPLAY_HEIGHT) {
62209
62238
  if (targetRow >= 0 && drop.y >= targetRow) {
62210
62239
  drop.settled = ARMIN_DISPLAY_HEIGHT - targetRow;
@@ -62219,7 +62248,7 @@ var init_mascot = __esm({
62219
62248
  tickFade() {
62220
62249
  const state = this.effectState;
62221
62250
  if (!state.positions || state.idx === void 0) return true;
62222
- for (let i = 0; i < 18; i++) {
62251
+ for (let i = 0; i < 54; i++) {
62223
62252
  if (state.idx >= state.positions.length) return true;
62224
62253
  const [row, x] = state.positions[state.idx];
62225
62254
  this.currentArminGrid[row][x] = this.finalArminGrid[row][x];
@@ -62237,7 +62266,7 @@ var init_mascot = __esm({
62237
62266
  for (let row = Math.max(0, top); row <= Math.min(ARMIN_DISPLAY_HEIGHT - 1, bottom); row++) {
62238
62267
  for (let x = 0; x < ARMIN_WIDTH; x++) this.currentArminGrid[row][x] = this.finalArminGrid[row][x];
62239
62268
  }
62240
- state.expansion++;
62269
+ state.expansion += 3;
62241
62270
  return state.expansion > ARMIN_DISPLAY_HEIGHT;
62242
62271
  }
62243
62272
  tickGlitch() {
@@ -62258,7 +62287,7 @@ var init_mascot = __esm({
62258
62287
  }
62259
62288
  }
62260
62289
  }
62261
- state.phase++;
62290
+ state.phase += 3;
62262
62291
  return false;
62263
62292
  }
62264
62293
  for (let row = 0; row < ARMIN_DISPLAY_HEIGHT; row++) {
@@ -62271,7 +62300,7 @@ var init_mascot = __esm({
62271
62300
  tickDissolve() {
62272
62301
  const state = this.effectState;
62273
62302
  if (!state.positions || state.idx === void 0) return true;
62274
- for (let i = 0; i < 22; i++) {
62303
+ for (let i = 0; i < 66; i++) {
62275
62304
  if (state.idx >= state.positions.length) return true;
62276
62305
  const [row, x] = state.positions[state.idx];
62277
62306
  this.currentArminGrid[row][x] = this.finalArminGrid[row][x];
@@ -63519,6 +63548,7 @@ async function openTeamDashboard(ctx) {
63519
63548
  if (!ctx.hasUI) return;
63520
63549
  const deps = depsRef;
63521
63550
  if (!deps) return;
63551
+ if (deps.uiState) deps.uiState.dashboardOpen = true;
63522
63552
  const cmdCtx = ctx;
63523
63553
  for (; ; ) {
63524
63554
  const sessionId = cmdCtx.sessionManager?.getSessionId?.();
@@ -63552,7 +63582,7 @@ async function openTeamDashboard(ctx) {
63552
63582
  } : { width, maxHeight: "90%", anchor: "center", margin: 2 }
63553
63583
  }
63554
63584
  );
63555
- if (!selection) return;
63585
+ if (!selection) break;
63556
63586
  if (selection.action === "reload") continue;
63557
63587
  if (selection.action === "notifications-dismiss") {
63558
63588
  deps.dismissNotifications?.();
@@ -63646,8 +63676,9 @@ async function openTeamDashboard(ctx) {
63646
63676
  )
63647
63677
  );
63648
63678
  await notifyCommandResult(cmdCtx, commandText2(result4));
63649
- return;
63679
+ break;
63650
63680
  }
63681
+ if (deps.uiState) deps.uiState.dashboardOpen = false;
63651
63682
  }
63652
63683
  function registerTeamCommands(pi, deps) {
63653
63684
  depsRef = deps;
@@ -64025,7 +64056,7 @@ function registerTeamCommands(pi, deps) {
64025
64056
  const { AnimatedMascot: AnimatedMascot2 } = await ui();
64026
64057
  await ctx.ui.custom(
64027
64058
  (tui, theme, _keybindings, done) => new AnimatedMascot2(theme, () => done(void 0), {
64028
- frameIntervalMs: style === "armin" ? 33 : 180,
64059
+ frameIntervalMs: style === "armin" ? 100 : 180,
64029
64060
  autoCloseMs: 7e3,
64030
64061
  requestRender: () => requestRenderTarget(tui),
64031
64062
  style,
@@ -65038,10 +65069,12 @@ var init_live_run_sidebar = __esm({
65038
65069
  if (isTerminal && !hasActiveAgents && !this.hasAutoClosed) {
65039
65070
  const autoCloseMs = this.config?.autoCloseDashboardMs ?? 3e3;
65040
65071
  if (autoCloseMs > 0) {
65072
+ if (this.autoCloseTimeout) clearTimeout(this.autoCloseTimeout);
65041
65073
  this.autoCloseTimeout = setTimeout(() => {
65042
65074
  this.hasAutoClosed = true;
65043
65075
  this.done(void 0);
65044
65076
  }, autoCloseMs);
65077
+ this.autoCloseTimeout?.unref();
65045
65078
  lines.push(line3(`auto-close in ${Math.round(autoCloseMs / 1e3)}s\u2026`, w));
65046
65079
  }
65047
65080
  } else if (this.autoCloseTimeout) {
@@ -69178,7 +69211,9 @@ function registerCrewVibes(pi) {
69178
69211
  });
69179
69212
  }
69180
69213
  function refreshFooter(ctx) {
69181
- if (ctx?.hasUI) safeUiCall("refresh-footer", () => requestRender(ctx));
69214
+ safeUiCall("refresh-footer", () => {
69215
+ if (ctx?.hasUI) requestRender(ctx);
69216
+ });
69182
69217
  }
69183
69218
  function publishSpeedFooter(ctx, speed = footerAnimator.value()) {
69184
69219
  if (!config.enabled || !config.speed.enabled || !config.speed.footer) {
@@ -69527,6 +69562,7 @@ function registerPiCommands(pi, ctx) {
69527
69562
  getManifestCache: ctx.getManifestCache,
69528
69563
  getRunSnapshotCache: ctx.getRunSnapshotCache,
69529
69564
  getMetricRegistry: () => ctx.observabilityState.metricRegistry,
69565
+ uiState: ctx.uiState,
69530
69566
  dismissNotifications: () => {
69531
69567
  ctx.widgetState.notificationCount = 0;
69532
69568
  if (ctx.currentCtx) {
@@ -70839,16 +70875,15 @@ function createRunSnapshotCache(cwd, options = {}) {
70839
70875
  const scheduleRefresh = (runId) => {
70840
70876
  const existing = pendingRefreshes.get(runId);
70841
70877
  if (existing) clearTimeout(existing);
70842
- pendingRefreshes.set(
70843
- runId,
70844
- setTimeout(() => {
70845
- pendingRefreshes.delete(runId);
70846
- try {
70847
- localRefreshIfStale(runId);
70848
- } catch {
70849
- }
70850
- }, INVAL_COALESCE_MS)
70851
- );
70878
+ const timer = setTimeout(() => {
70879
+ pendingRefreshes.delete(runId);
70880
+ try {
70881
+ localRefreshIfStale(runId);
70882
+ } catch {
70883
+ }
70884
+ }, INVAL_COALESCE_MS);
70885
+ timer.unref();
70886
+ pendingRefreshes.set(runId, timer);
70852
70887
  };
70853
70888
  const unsubState = runEventBus.onChannel("run:state", (event) => {
70854
70889
  if (entries.has(event.runId)) scheduleRefresh(event.runId);
@@ -72921,8 +72956,6 @@ function installSessionStartHandler(pi, ctx) {
72921
72956
  ctx.crewAutocompleteRegistered = true;
72922
72957
  registerCrewAutocomplete(extensionCtx);
72923
72958
  }
72924
- if (ctx.widgetState.interval) clearInterval(ctx.widgetState.interval);
72925
- ctx.widgetState.interval = void 0;
72926
72959
  notifyActiveRuns(extensionCtx);
72927
72960
  const currentSessionId = extractBrokerSessionId(extensionCtx);
72928
72961
  ctx.brokerController?.setSessionId(currentSessionId);
@@ -73232,7 +73265,7 @@ function setupRenderLoop(pi, ctx, extensionCtx, loadedConfig) {
73232
73265
  const snapshotCache = lastFrameSnapshotCache ?? ctx.getRunSnapshotCache(ctx.currentCtx.cwd);
73233
73266
  const manifests = lastPreloadedManifests;
73234
73267
  if (!lastPreloadedConfig) backgroundPreload();
73235
- if (ctx.uiState.liveSidebarRunId) {
73268
+ if (ctx.uiState.liveSidebarRunId || ctx.uiState.dashboardOpen) {
73236
73269
  const placement = config?.widgetPlacement ?? DEFAULT_UI.widgetPlacement;
73237
73270
  if (ctx.widgetState.lastVisibility !== "hidden" || ctx.widgetState.lastPlacement !== placement) {
73238
73271
  setExtensionWidget(ctx.currentCtx, "pi-crew", void 0, { placement });
@@ -74652,7 +74685,7 @@ function registerPiTeams(pi) {
74652
74685
  installPiHooks(pi, ctx);
74653
74686
  installSessionLifecycleHandlers(pi, ctx);
74654
74687
  ctx.brokerController = installCrewBrokerLifecycleController(pi, ctx);
74655
- registerCleanupHandler(pi);
74688
+ registerCleanupHandler(pi, { disposeTerminalStatus: () => ctx.terminalStatus?.dispose?.() });
74656
74689
  registerCompactionGuard(pi, {
74657
74690
  foregroundControllers: ctx.foregroundControllers,
74658
74691
  foregroundTeamRunControllers: ctx.foregroundTeamRunControllers