@selesai/code 0.8.4 → 0.8.6

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 (147) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +7 -1
  3. package/dist/core/slash-commands.js +1 -0
  4. package/dist/defaults/models.json +46 -55
  5. package/dist/defaults/settings.json +7 -8
  6. package/dist/extensions/agent-browser.test.ts +178 -2
  7. package/dist/extensions/agent-browser.ts +2 -0
  8. package/dist/extensions/copy-turn.test.ts +229 -0
  9. package/dist/extensions/copy-turn.ts +11 -0
  10. package/dist/extensions/grep-app/index.test.ts +356 -1
  11. package/dist/extensions/grep-app/index.ts +6 -1
  12. package/dist/extensions/handoff-new.test.ts +351 -161
  13. package/dist/extensions/handoff-new.ts +3 -0
  14. package/dist/extensions/inline-skills.test.ts +93 -0
  15. package/dist/extensions/inline-skills.ts +3 -0
  16. package/dist/extensions/pi-subagents/CHANGELOG.md +26 -3
  17. package/dist/extensions/pi-subagents/README.md +2 -0
  18. package/dist/extensions/pi-subagents/agents/builder.md +5 -2
  19. package/dist/extensions/pi-subagents/agents/commentator.md +1 -1
  20. package/dist/extensions/pi-subagents/docs/configuration.md +54 -2
  21. package/dist/extensions/pi-subagents/docs/observability.md +1 -1
  22. package/dist/extensions/pi-subagents/docs/tool-reference.md +1 -1
  23. package/dist/extensions/pi-subagents/docs/workflows.md +1 -1
  24. package/dist/extensions/pi-subagents/package-lock.json +2 -2
  25. package/dist/extensions/pi-subagents/package.json +1 -1
  26. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +1 -1
  27. package/dist/extensions/pi-subagents/src/agents/agents.ts +9 -3
  28. package/dist/extensions/pi-subagents/src/extension/config.ts +12 -0
  29. package/dist/extensions/pi-subagents/src/extension/doctor.ts +40 -0
  30. package/dist/extensions/pi-subagents/src/extension/index.ts +104 -14
  31. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +5 -0
  32. package/dist/extensions/pi-subagents/src/extension/rpc.ts +3 -9
  33. package/dist/extensions/pi-subagents/src/extension/schemas.ts +2 -2
  34. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +4 -1
  35. package/dist/extensions/pi-subagents/src/missions/lifecycle.ts +4 -7
  36. package/dist/extensions/pi-subagents/src/missions/store.ts +4 -4
  37. package/dist/extensions/pi-subagents/src/missions/workflow-state.ts +6 -2
  38. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +374 -0
  39. package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +9 -5
  40. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +117 -29
  41. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +12 -6
  42. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +7 -1
  43. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +14 -5
  44. package/dist/extensions/pi-subagents/src/runs/background/chain-append.ts +33 -15
  45. package/dist/extensions/pi-subagents/src/runs/background/notify.ts +5 -2
  46. package/dist/extensions/pi-subagents/src/runs/background/owned-process-tree.ts +104 -0
  47. package/dist/extensions/pi-subagents/src/runs/background/process-terminal.ts +17 -3
  48. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +19 -1
  49. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +2 -2
  50. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +5 -2
  51. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +12 -6
  52. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +3 -3
  53. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +84 -36
  54. package/dist/extensions/pi-subagents/src/runs/background/wait-subscriptions.ts +2 -1
  55. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +37 -2
  56. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +135 -22
  57. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-control.ts +12 -0
  58. package/dist/extensions/pi-subagents/src/runs/foreground/foreground-history.ts +7 -4
  59. package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +171 -0
  60. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +653 -196
  61. package/dist/extensions/pi-subagents/src/runs/shared/acceptance.ts +13 -4
  62. package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +286 -0
  63. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +23 -0
  64. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -0
  65. package/dist/extensions/pi-subagents/src/runs/shared/pi-args.ts +44 -1
  66. package/dist/extensions/pi-subagents/src/runs/shared/run-fanout-budget.ts +280 -0
  67. package/dist/extensions/pi-subagents/src/runs/shared/single-output.ts +4 -2
  68. package/dist/extensions/pi-subagents/src/runs/shared/task-intent.ts +19 -3
  69. package/dist/extensions/pi-subagents/src/runs/shared/worktree.ts +17 -5
  70. package/dist/extensions/pi-subagents/src/shared/session-lineage.ts +71 -0
  71. package/dist/extensions/pi-subagents/src/shared/types.ts +108 -0
  72. package/dist/extensions/pi-subagents/src/shared/utils.ts +3 -1
  73. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +7 -5
  74. package/dist/extensions/pi-subagents/src/tui/fleet.ts +226 -13
  75. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +22 -5
  76. package/dist/extensions/pi-subagents/src/workflows/workflow-auto-relaunch.ts +28 -0
  77. package/dist/extensions/pi-subagents/test/integration/acceptance-file-report.test.ts +87 -0
  78. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +96 -6
  79. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +28 -5
  80. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +8 -5
  81. package/dist/extensions/pi-subagents/test/integration/fork-context-execution.test.ts +83 -2
  82. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +211 -15
  83. package/dist/extensions/pi-subagents/test/integration/parallel-execution.test.ts +41 -3
  84. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +314 -10
  85. package/dist/extensions/pi-subagents/test/unit/acceptance.test.ts +31 -1
  86. package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +317 -0
  87. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +21 -2
  88. package/dist/extensions/pi-subagents/test/unit/async-recovery-descriptor.test.ts +16 -1
  89. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +6 -1
  90. package/dist/extensions/pi-subagents/test/unit/chain-append.test.ts +75 -4
  91. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +18 -0
  92. package/dist/extensions/pi-subagents/test/unit/doctor.test.ts +29 -1
  93. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +31 -5
  94. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +139 -1
  95. package/dist/extensions/pi-subagents/test/unit/foreground-control.test.ts +10 -0
  96. package/dist/extensions/pi-subagents/test/unit/handoff-adoption.test.ts +103 -0
  97. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +22 -0
  98. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +2 -1
  99. package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +171 -0
  100. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +30 -4
  101. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +14 -0
  102. package/dist/extensions/pi-subagents/test/unit/owned-process-tree.test.ts +69 -0
  103. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +83 -0
  104. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +2 -2
  105. package/dist/extensions/pi-subagents/test/unit/process-terminal.test.ts +55 -2
  106. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +12 -1
  107. package/dist/extensions/pi-subagents/test/unit/rpc.test.ts +7 -7
  108. package/dist/extensions/pi-subagents/test/unit/run-fanout-budget.test.ts +121 -0
  109. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +9 -0
  110. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +4 -3
  111. package/dist/extensions/pi-subagents/test/unit/session-lineage.test.ts +73 -0
  112. package/dist/extensions/pi-subagents/test/unit/single-output.test.ts +28 -0
  113. package/dist/extensions/pi-subagents/test/unit/steering-action.test.ts +10 -1
  114. package/dist/extensions/pi-subagents/test/unit/task-intent.test.ts +39 -0
  115. package/dist/extensions/pi-subagents/test/unit/timeout-defaults.test.ts +65 -0
  116. package/dist/extensions/pi-subagents/test/unit/workflow-auto-relaunch.test.ts +45 -0
  117. package/dist/extensions/pi-subagents/test/unit/worktree.test.ts +61 -0
  118. package/dist/extensions/ponytail/index.js +11 -0
  119. package/dist/extensions/ponytail/ponytail-config.cjs +2 -0
  120. package/dist/extensions/ponytail/ponytail-instructions.cjs +6 -0
  121. package/dist/extensions/ponytail/test/extension.test.js +274 -140
  122. package/dist/extensions/ponytail/test/helpers.test.js +280 -92
  123. package/dist/extensions/question/index.ts +18 -0
  124. package/dist/extensions/question/question-list.ts +22 -0
  125. package/dist/extensions/question/tests/batch.test.ts +103 -65
  126. package/dist/extensions/question/tests/helpers.test.ts +68 -35
  127. package/dist/extensions/question/tests/question-list.test.ts +506 -204
  128. package/dist/extensions/question/tests/row-layout.test.ts +180 -114
  129. package/dist/extensions/question/tests/schemas.test.ts +42 -19
  130. package/dist/extensions/question/tests/shortcuts.test.ts +106 -84
  131. package/dist/extensions/question/tests/wizard.test.ts +771 -50
  132. package/dist/extensions/rtk.test.ts +180 -1
  133. package/dist/extensions/tokenin-onboarding.ts +3 -0
  134. package/dist/extensions/undo.test.ts +720 -0
  135. package/dist/extensions/undo.ts +6 -0
  136. package/dist/extensions/web-agent-onboarding.test.ts +415 -0
  137. package/dist/extensions/workflow/extension.ts +3 -3
  138. package/dist/extensions/workflow/modes.ts +41 -19
  139. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  140. package/dist/modes/interactive/interactive-mode.js +48 -1
  141. package/dist/skills/pi-subagents/references/execution-controls.md +1 -1
  142. package/docs/plans/workflow-autoloop-reference.md +1 -2
  143. package/docs/plans/workflow-handoff-carryover.md +108 -0
  144. package/docs/quickstart.md +27 -43
  145. package/docs/settings.md +4 -0
  146. package/docs/usage.md +1 -0
  147. package/package.json +5 -1
@@ -328,6 +328,7 @@ export interface FileMutationEffect {
328
328
  expected: boolean;
329
329
  attempted: boolean;
330
330
  message?: string;
331
+ resolvedBy?: "llm-intent-arbiter";
331
332
  }
332
333
 
333
334
  export interface EffectsProjection {
@@ -343,6 +344,7 @@ export type ProcessTerminalReason =
343
344
  | "runner-candidate-missing"
344
345
  | "runner-instance-mismatch"
345
346
  | "writer-close-unverified"
347
+ | "process-tree-unverified"
346
348
  | "canonical-session-unavailable"
347
349
  | "canonical-session-lease-active"
348
350
  | "canonical-session-release-unverified"
@@ -357,6 +359,19 @@ export interface RunnerProcessInstanceExitV1 {
357
359
  signal: string | null;
358
360
  }
359
361
 
362
+ export type ProcessTreeTerminalV1 =
363
+ | {
364
+ state: "observed";
365
+ mechanism: "posix-process-group";
366
+ processGroupId: number;
367
+ verifiedAt: number;
368
+ }
369
+ | {
370
+ state: "unknown";
371
+ reason: "unsupported-platform" | "signal-failed" | "verification-failed";
372
+ diagnostic?: string;
373
+ };
374
+
360
375
  export interface PiWriterProcessInstanceExitV1 {
361
376
  processInstanceId: string;
362
377
  kind: "pi-writer";
@@ -364,6 +379,7 @@ export interface PiWriterProcessInstanceExitV1 {
364
379
  closeObservedAt: number;
365
380
  exitCode: number | null;
366
381
  signal: string | null;
382
+ processTree: ProcessTreeTerminalV1;
367
383
  }
368
384
 
369
385
  export type ProcessInstanceExitV1 = RunnerProcessInstanceExitV1 | PiWriterProcessInstanceExitV1;
@@ -462,9 +478,30 @@ export interface SteeringNotice {
462
478
  currentSessionId?: string;
463
479
  }
464
480
 
481
+ export interface RunFanoutBudgetDescriptor {
482
+ version: 1;
483
+ rootRunId: string;
484
+ directory: string;
485
+ limit: number;
486
+ parentPath?: string;
487
+ }
488
+
489
+ export interface RunFanoutBudgetSnapshot {
490
+ used: number;
491
+ limit: number;
492
+ remaining: number;
493
+ }
494
+
495
+ export interface RunFanoutRejection extends RunFanoutBudgetSnapshot {
496
+ code: "RUN_FANOUT_LIMIT";
497
+ path: string;
498
+ requested: number;
499
+ }
500
+
465
501
  export interface SteeringRecoveryDescriptor {
466
502
  version: 1;
467
503
  launchContractDigest?: string;
504
+ runFanoutBudget: RunFanoutBudgetDescriptor;
468
505
  sourceRunId: string;
469
506
  agentContract?: AgentContract;
470
507
  agent: string;
@@ -1024,6 +1061,9 @@ export interface Details {
1024
1061
  // Aggregated cost across all agents in the run
1025
1062
  totalCost?: CostSummary;
1026
1063
  spawnBudget?: SpawnBudgetSnapshot;
1064
+ runFanoutBudget?: RunFanoutBudgetSnapshot;
1065
+ runFanoutRejection?: RunFanoutRejection;
1066
+ activeAsyncCapacity?: ActiveAsyncCapacitySnapshot;
1027
1067
  capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
1028
1068
  capabilityAudit?: SubagentCapabilityAudit;
1029
1069
  parallelHandoff?: ParallelHandoffReference;
@@ -1321,8 +1361,12 @@ export interface AsyncStatus {
1321
1361
  pendingAppends?: number;
1322
1362
  parallelGroups?: AsyncParallelGroupStatus[];
1323
1363
  workflowGraph?: WorkflowGraphSnapshot;
1364
+ /** Auto-relaunch count when a workflow budget result triggered a fresh top-level run. */
1365
+ workflowRelaunchCount?: number;
1324
1366
  checkpoint?: ChainCheckpointState;
1325
1367
  processTerminal?: ProcessTerminalV1;
1368
+ runFanoutBudget?: RunFanoutBudgetSnapshot;
1369
+ runFanoutBudgetDescriptor?: RunFanoutBudgetDescriptor;
1326
1370
  launchContractDigest?: string;
1327
1371
  launchResolvedExtensions?: LaunchResolvedChildExtensionsV1;
1328
1372
  runtimeAcknowledgedExtensions?: RuntimeAcknowledgedChildExtensionsV1;
@@ -1342,6 +1386,10 @@ export interface AsyncStatus {
1342
1386
  phase?: string;
1343
1387
  label?: string;
1344
1388
  workflowKey?: string;
1389
+ /** Child run identity for workflow capacity reconciliation. */
1390
+ runId?: string;
1391
+ /** True only when this workflow child owns a detached async runner. */
1392
+ async?: boolean;
1345
1393
  parentWorkflowRunId?: string;
1346
1394
  outputName?: string;
1347
1395
  structured?: boolean;
@@ -1414,6 +1462,8 @@ export type AsyncJobStep = NonNullable<AsyncStatus["steps"]>[number] & {
1414
1462
  export interface AsyncJobState {
1415
1463
  asyncId: string;
1416
1464
  asyncDir: string;
1465
+ /** True when the job was adopted from a previous session via lineage carry-over. */
1466
+ adopted?: boolean;
1417
1467
  /** Parent-resolved launch directory retained for trusted live artifact lookup. */
1418
1468
  cwd?: string;
1419
1469
  status: "queued" | "running" | "complete" | "failed" | "paused" | "stopped" | "rejected";
@@ -1574,6 +1624,12 @@ export interface ForegroundRunControl {
1574
1624
  toolCount?: number;
1575
1625
  /** Independently tracked children for foreground parallel work and fleet inspection. */
1576
1626
  activeChildren?: Map<number, ForegroundChildControl>;
1627
+ /** Live Prompt Audit redo callback. It is current-session memory only. */
1628
+ promptAuditRedo?: (index: number, guidance: string) => Promise<{ text: string; isError?: boolean }>;
1629
+ /** Memory-only source run for Prompt Audit redo. */
1630
+ sourceRunId?: string;
1631
+ /** Memory-only replacement run started by Prompt Audit redo. */
1632
+ supersededByRunId?: string;
1577
1633
  /** Scheduling owners that may still launch another child. Removal is safe only at zero. */
1578
1634
  schedulingOwners?: number;
1579
1635
  nestedRoute?: NestedRouteInfo;
@@ -1593,9 +1649,21 @@ export interface WaitSubscriptionRecord {
1593
1649
  expiresAt: number;
1594
1650
  }
1595
1651
 
1652
+ export interface ActiveAsyncCapacitySnapshot {
1653
+ used: number;
1654
+ /** Zero means the opt-in cap is disabled. */
1655
+ limit: number;
1656
+ }
1657
+
1596
1658
  export interface SubagentState {
1597
1659
  baseCwd: string;
1598
1660
  currentSessionId: string | null;
1661
+ /** Ordered session identities (session file paths) whose workflow estate this session adopts, self first. */
1662
+ sessionLineage?: string[];
1663
+ /** Earliest result-file mtime eligible for adoption from lineage sessions (replay guard). */
1664
+ adoptedResultWindowStart?: number;
1665
+ /** Set when a session switch adopted live workflows; consumed on the first settled turn to inject a carry-over summary. */
1666
+ handoffResumePending?: boolean;
1599
1667
  /** Runtime-owned artifact resolution inputs used by Fleet transcript targeting. */
1600
1668
  artifactDirPreference?: ArtifactDirPreference;
1601
1669
  /** Runtime authority snapshot used by optional inspector controls. */
@@ -1613,6 +1681,8 @@ export interface SubagentState {
1613
1681
  granted?: number;
1614
1682
  grantHistory?: SpawnBudgetGrant[];
1615
1683
  };
1684
+ /** Current-session top-level async capacity projection. */
1685
+ activeAsyncCapacity?: ActiveAsyncCapacitySnapshot;
1616
1686
  asyncJobs: Map<string, AsyncJobState>;
1617
1687
  /** Current-session active and recent async runs for the native fleet inspector. */
1618
1688
  fleetJobs?: Map<string, AsyncJobState>;
@@ -1730,9 +1800,12 @@ export interface RunSyncOptions {
1730
1800
  /** Effective parent wait-tool setting propagated to the child runtime. */
1731
1801
  waitToolEnabled?: boolean;
1732
1802
  capabilityCeiling?: ResolvedSubagentCapabilityCeiling;
1803
+ runFanoutBudget?: RunFanoutBudgetDescriptor;
1733
1804
  nestedRoute?: NestedRouteInfo;
1734
1805
  /** Override the agent's default model (format: "provider/id" or just "id") */
1735
1806
  modelOverride?: string;
1807
+ /** LLM intent arbiter for the completion mutation guard (rescues read-only review runs). */
1808
+ llmIntentArbiter?: import("../runs/shared/llm-intent-arbiter.ts").TaskMutationArbiter;
1736
1809
  /** Override the agent's default thinking level for this run */
1737
1810
  thinkingOverride?: AgentConfig["thinking"];
1738
1811
  /** Registry models available for heuristic bare-model resolution */
@@ -1756,6 +1829,8 @@ export interface RunSyncOptions {
1756
1829
  dynamic?: boolean;
1757
1830
  dynamicGroup?: boolean;
1758
1831
  };
1832
+ /** Private live callback for the exact child prompt after runtime acceptance injection. */
1833
+ onEffectivePrompt?: (prompt: string) => void;
1759
1834
  }
1760
1835
 
1761
1836
  export type IntercomBridgeMode = "off" | "fork-only" | "always";
@@ -1840,8 +1915,28 @@ export interface ExtensionConfig {
1840
1915
  maxSubagentDepth?: number;
1841
1916
  /** Optional cumulative session cap. Unset or 0 means unlimited. */
1842
1917
  maxSubagentSpawnsPerSession?: number;
1918
+ /** Cumulative logical-child cap for one top-level run tree. Defaults to 64. */
1919
+ maxSubagentSpawnsPerRun?: number;
1920
+ /**
1921
+ * Max auto-relaunches when a scripted workflow ends with a fan-out budget
1922
+ * result before the goal is clean. Each relaunch is a fresh top-level run
1923
+ * with a new fan-out budget. Defaults to 12; 0 means unlimited.
1924
+ */
1925
+ maxWorkflowAutoRelaunches?: number;
1926
+ /** Optional active top-level async run cap per parent session. Unset or 0 means unlimited. */
1927
+ maxActiveAsyncRunsPerSession?: number;
1843
1928
  /** Global cap on simultaneously-running subagent tasks within a single run. Defaults to 20. */
1844
1929
  globalConcurrencyLimit?: number;
1930
+ /**
1931
+ * Global default runtime deadline in milliseconds. It replaces the built-in
1932
+ * 30-minute backstop for single, parallel, and chain launches (foreground, plus
1933
+ * plain single-agent async runs) when neither the call (`timeoutMs`/`maxRuntimeMs`)
1934
+ * nor the selected agent provides a timeout. Explicit call values and agent
1935
+ * frontmatter defaults still win. Composite async runs (chain/parallel/workflow)
1936
+ * stay unbounded at the top level by design — their children are bounded individually.
1937
+ * Must be a positive integer; invalid values are ignored.
1938
+ */
1939
+ timeoutMs?: number;
1845
1940
  control?: ControlConfig;
1846
1941
  completionBatch?: CompletionBatchConfig;
1847
1942
  turnBudget?: TurnBudgetConfig;
@@ -2057,6 +2152,19 @@ export function resolveMaxSubagentSpawnsPerSession(configMaxSpawns?: number): nu
2057
2152
  return configuredMaxSpawns === 0 ? undefined : configuredMaxSpawns;
2058
2153
  }
2059
2154
 
2155
+ export const DEFAULT_MAX_SUBAGENT_SPAWNS_PER_RUN = 64;
2156
+
2157
+ export function normalizeMaxSubagentSpawnsPerRun(value: unknown): number | undefined {
2158
+ const normalized = normalizeNonNegativeInteger(value);
2159
+ return normalized !== undefined && normalized > 0 ? normalized : undefined;
2160
+ }
2161
+
2162
+ export function resolveMaxSubagentSpawnsPerRun(configMaxSpawns?: number): number {
2163
+ return normalizeMaxSubagentSpawnsPerRun(process.env.SELESAI_SUBAGENT_MAX_SPAWNS_PER_RUN)
2164
+ ?? normalizeMaxSubagentSpawnsPerRun(configMaxSpawns)
2165
+ ?? DEFAULT_MAX_SUBAGENT_SPAWNS_PER_RUN;
2166
+ }
2167
+
2060
2168
  // ============================================================================
2061
2169
  // Utility Functions
2062
2170
  // ============================================================================
@@ -17,6 +17,7 @@ import type { AgentProgress, AsyncStatus, Details, DisplayItem, ErrorInfo, Neste
17
17
  const DEFAULT_CONFIG_DIR_NAME = ".selesai";
18
18
  const PI_CODING_AGENT_PACKAGE_NAME = "@selesai/code";
19
19
  export const SELESAI_CODING_AGENT_PACKAGE_ROOT_ENV = "SELESAI_SUBAGENTS_SELESAI_PACKAGE_ROOT";
20
+ export const PROMPT_REDACTED = "[prompt redacted]";
20
21
 
21
22
  export function resolveWatchPath(
22
23
  watchPath: string,
@@ -354,7 +355,7 @@ function compactCompletedProgress(progress: AgentProgress): AgentProgress {
354
355
  agent: progress.agent,
355
356
  status: progress.status,
356
357
  activityState: progress.activityState,
357
- task: progress.task,
358
+ task: "[prompt redacted]",
358
359
  skills: progress.skills,
359
360
  toolCount: progress.toolCount,
360
361
  tokens: progress.tokens,
@@ -428,6 +429,7 @@ export function compactForegroundResult(result: SingleResult): SingleResult {
428
429
  const toolCalls = result.toolCalls?.length ? result.toolCalls : extractToolCallSummaries(result.messages);
429
430
  return {
430
431
  ...result,
432
+ task: "[prompt redacted]",
431
433
  messages: undefined,
432
434
  progress: undefined,
433
435
  toolCalls: toolCalls.length ? toolCalls : undefined,
@@ -318,7 +318,7 @@ export class SubagentFleetStatus {
318
318
  this.clearWidget();
319
319
  return;
320
320
  }
321
- if (this.entries.length === 0) {
321
+ if (this.entries.length === 0 && !(this.state.activeAsyncCapacity?.used)) {
322
322
  this.active = false;
323
323
  this.selectedKey = "main";
324
324
  this.lastRenderKey = "";
@@ -413,10 +413,13 @@ export class SubagentFleetStatus {
413
413
  }
414
414
 
415
415
  render(width: number, theme: Theme): string[] {
416
- if (this.entries.length === 0) return [];
416
+ if (this.entries.length === 0 && !(this.state.activeAsyncCapacity?.used)) return [];
417
417
  if (!this.active) {
418
418
  const tokens = this.entries.reduce((total, entry) => total + entry.tokens, 0);
419
- const label = `${this.entries.length} active ${this.entries.length === 1 ? "agent" : "agents"}`;
419
+ const capacity = this.state.activeAsyncCapacity;
420
+ const asyncRuns = capacity ? `Async runs ${capacity.used}/${capacity.limit || "∞"}` : "";
421
+ const agents = this.entries.length > 0 ? `${this.entries.length} active ${this.entries.length === 1 ? "agent" : "agents"}` : "";
422
+ const label = [agents, asyncRuns].filter(Boolean).join(" · ");
420
423
  return [truncateToWidth(` ${theme.fg("muted", label)} · ${theme.fg("dim", `${formatFleetTokens(tokens)} · ↓/← to inspect`)}`, width)];
421
424
  }
422
425
  const roster = this.rosterKeys();
@@ -444,9 +447,8 @@ export class SubagentFleetStatus {
444
447
  }
445
448
 
446
449
  private renderEntry(rosterIndex: number, selectedIndex: number, entry: FleetStatusEntry, width: number, theme: Theme): string {
447
- const description = entry.description?.replace(/\s+/g, " ").trim();
448
450
  const agent = entry.modelThinking ? `${entry.agent} (${entry.modelThinking})` : entry.agent;
449
- const left = ` ${this.bullet(rosterIndex, selectedIndex, theme)} ${theme.fg("muted", agent)} · ${entry.state}${description ? ` ${description}` : ""}`;
451
+ const left = ` ${this.bullet(rosterIndex, selectedIndex, theme)} ${theme.fg("muted", agent)} · ${entry.state}`;
450
452
  const elapsed = Date.now() - entry.startedAt;
451
453
  const right = theme.fg("dim", `${formatFleetElapsed(elapsed)} · ${formatFleetTokens(entry.tokens)}`);
452
454
  return rightAlign(left, right, width);