@leing2021/super-pi 0.22.1 → 0.23.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.
Files changed (117) hide show
  1. package/README.md +66 -293
  2. package/extensions/ce-core/index.ts +276 -48
  3. package/extensions/ce-core/tools/parallel-subagent.ts +3 -3
  4. package/extensions/ce-core/tools/subagent.ts +2 -2
  5. package/package.json +4 -20
  6. package/rules/common/naming.md +154 -0
  7. package/skills/01-brainstorm/SKILL.md +42 -79
  8. package/skills/01-brainstorm/references/ce-brainstorm-mode.md +47 -0
  9. package/skills/02-plan/SKILL.md +43 -61
  10. package/skills/02-plan/references/solution-search.md +46 -0
  11. package/skills/03-work/SKILL.md +34 -52
  12. package/skills/03-work/references/completion-report.md +51 -0
  13. package/skills/04-review/SKILL.md +44 -51
  14. package/skills/04-review/references/solution-search.md +46 -0
  15. package/skills/06-next/SKILL.md +35 -20
  16. package/skills/06-next/references/recommendation-logic.md +47 -2
  17. package/skills/07-worktree/SKILL.md +21 -20
  18. package/skills/08-help/SKILL.md +46 -0
  19. package/skills/08-help/references/workflow-sequence.md +135 -0
  20. package/skills/references/language-detection.md +44 -0
  21. package/LICENSE +0 -21
  22. package/THIRD-PARTY-NOTICES.md +0 -35
  23. package/extensions/subagent/__tests__/async-job-tracker.test.ts +0 -21
  24. package/extensions/subagent/__tests__/execution-activity.test.ts +0 -15
  25. package/extensions/subagent/__tests__/parallel-render-stress.test.ts +0 -82
  26. package/extensions/subagent/__tests__/render-dedup.test.ts +0 -98
  27. package/extensions/subagent/__tests__/render-widget.test.ts +0 -28
  28. package/extensions/subagent/__tests__/throttle.test.ts +0 -90
  29. package/extensions/subagent/agent-management.ts +0 -596
  30. package/extensions/subagent/agent-manager-chain-detail.ts +0 -163
  31. package/extensions/subagent/agent-manager-detail.ts +0 -232
  32. package/extensions/subagent/agent-manager-edit.ts +0 -391
  33. package/extensions/subagent/agent-manager-list.ts +0 -279
  34. package/extensions/subagent/agent-manager-parallel.ts +0 -305
  35. package/extensions/subagent/agent-manager.ts +0 -706
  36. package/extensions/subagent/agent-scope.ts +0 -9
  37. package/extensions/subagent/agent-selection.ts +0 -26
  38. package/extensions/subagent/agent-serializer.ts +0 -124
  39. package/extensions/subagent/agent-templates.ts +0 -63
  40. package/extensions/subagent/agents/context-builder.md +0 -37
  41. package/extensions/subagent/agents/delegate.md +0 -9
  42. package/extensions/subagent/agents/oracle.md +0 -73
  43. package/extensions/subagent/agents/planner.md +0 -52
  44. package/extensions/subagent/agents/researcher.md +0 -50
  45. package/extensions/subagent/agents/reviewer.md +0 -38
  46. package/extensions/subagent/agents/scout.md +0 -48
  47. package/extensions/subagent/agents/worker.md +0 -52
  48. package/extensions/subagent/agents.ts +0 -762
  49. package/extensions/subagent/artifacts.ts +0 -101
  50. package/extensions/subagent/async-execution.ts +0 -521
  51. package/extensions/subagent/async-job-tracker.ts +0 -240
  52. package/extensions/subagent/async-status.ts +0 -242
  53. package/extensions/subagent/chain-clarify.ts +0 -1365
  54. package/extensions/subagent/chain-execution.ts +0 -854
  55. package/extensions/subagent/chain-serializer.ts +0 -127
  56. package/extensions/subagent/completion-dedupe.ts +0 -66
  57. package/extensions/subagent/doctor.ts +0 -201
  58. package/extensions/subagent/execution.ts +0 -748
  59. package/extensions/subagent/file-coalescer.ts +0 -43
  60. package/extensions/subagent/fork-context.ts +0 -64
  61. package/extensions/subagent/formatters.ts +0 -123
  62. package/extensions/subagent/frontmatter.ts +0 -32
  63. package/extensions/subagent/index.ts +0 -586
  64. package/extensions/subagent/intercom-bridge.ts +0 -241
  65. package/extensions/subagent/jsonl-writer.ts +0 -84
  66. package/extensions/subagent/model-fallback.ts +0 -109
  67. package/extensions/subagent/notify.ts +0 -111
  68. package/extensions/subagent/parallel-utils.ts +0 -109
  69. package/extensions/subagent/pi-args.ts +0 -139
  70. package/extensions/subagent/pi-spawn.ts +0 -101
  71. package/extensions/subagent/post-exit-stdio-guard.ts +0 -88
  72. package/extensions/subagent/prompt-template-bridge.ts +0 -400
  73. package/extensions/subagent/prompts/gather-context-and-clarify.md +0 -13
  74. package/extensions/subagent/prompts/parallel-cleanup.md +0 -42
  75. package/extensions/subagent/prompts/parallel-research.md +0 -50
  76. package/extensions/subagent/prompts/parallel-review.md +0 -40
  77. package/extensions/subagent/render-helpers.ts +0 -83
  78. package/extensions/subagent/render.ts +0 -908
  79. package/extensions/subagent/result-intercom.ts +0 -238
  80. package/extensions/subagent/result-watcher.ts +0 -172
  81. package/extensions/subagent/run-history.ts +0 -58
  82. package/extensions/subagent/run-status.ts +0 -137
  83. package/extensions/subagent/schemas.ts +0 -165
  84. package/extensions/subagent/session-tokens.ts +0 -51
  85. package/extensions/subagent/settings.ts +0 -368
  86. package/extensions/subagent/single-output.ts +0 -98
  87. package/extensions/subagent/skills.ts +0 -627
  88. package/extensions/subagent/slash-bridge.ts +0 -177
  89. package/extensions/subagent/slash-commands.ts +0 -304
  90. package/extensions/subagent/slash-live-state.ts +0 -295
  91. package/extensions/subagent/subagent-control.ts +0 -151
  92. package/extensions/subagent/subagent-executor.ts +0 -1915
  93. package/extensions/subagent/subagent-prompt-runtime.ts +0 -76
  94. package/extensions/subagent/subagent-runner.ts +0 -1471
  95. package/extensions/subagent/subagents-status.ts +0 -473
  96. package/extensions/subagent/text-editor.ts +0 -273
  97. package/extensions/subagent/throttle.ts +0 -77
  98. package/extensions/subagent/top-level-async.ts +0 -16
  99. package/extensions/subagent/types.ts +0 -624
  100. package/extensions/subagent/utils.ts +0 -457
  101. package/extensions/subagent/worktree.ts +0 -580
  102. package/extensions/super-pi-extension/agents/ce-oracle.md +0 -109
  103. package/extensions/super-pi-extension/agents/ce-planner.md +0 -116
  104. package/extensions/super-pi-extension/agents/ce-reviewer.md +0 -99
  105. package/extensions/super-pi-extension/agents/ce-scout.md +0 -80
  106. package/extensions/super-pi-extension/agents/ce-worker.md +0 -78
  107. package/extensions/super-pi-extension/chains/ce-parallel-review.chain.md +0 -34
  108. package/extensions/super-pi-extension/chains/ce-review-only.chain.md +0 -12
  109. package/extensions/super-pi-extension/chains/ce-standard.chain.md +0 -28
  110. package/extensions/super-pi-extension/index.ts +0 -129
  111. package/extensions/super-pi-extension/model-sync.ts +0 -204
  112. package/skills/08-status/SKILL.md +0 -41
  113. package/skills/08-status/references/artifact-locations.md +0 -10
  114. package/skills/09-help/SKILL.md +0 -37
  115. package/skills/09-help/references/workflow-sequence.md +0 -9
  116. package/skills/10-rules/SKILL.md +0 -76
  117. package/skills/pi-subagents/SKILL.md +0 -566
@@ -1,624 +0,0 @@
1
- // SPDX-FileCopyrightText: 2025 Nico Bailon
2
- // SPDX-License-Identifier: MIT
3
- // Source: https://github.com/nicobailon/pi-subagents
4
- /**
5
- * Type definitions for the subagent extension
6
- */
7
-
8
- import * as os from "node:os";
9
- import * as path from "node:path";
10
- import type { Message } from "@mariozechner/pi-ai";
11
- import type { FSWatcher } from "node:fs";
12
- import type { ExtensionContext } from "@mariozechner/pi-coding-agent";
13
-
14
- // ============================================================================
15
- // Basic Types
16
- // ============================================================================
17
-
18
- export interface MaxOutputConfig {
19
- bytes?: number;
20
- lines?: number;
21
- }
22
-
23
- export interface TruncationResult {
24
- text: string;
25
- truncated: boolean;
26
- originalBytes?: number;
27
- originalLines?: number;
28
- artifactPath?: string;
29
- }
30
-
31
- export interface Usage {
32
- input: number;
33
- output: number;
34
- cacheRead: number;
35
- cacheWrite: number;
36
- cost: number;
37
- turns: number;
38
- }
39
-
40
- export interface TokenUsage {
41
- input: number;
42
- output: number;
43
- total: number;
44
- }
45
-
46
- export type ActivityState = "needs_attention";
47
- export type ControlEventType = "needs_attention";
48
- export type ControlNotificationChannel = "event" | "async" | "intercom";
49
-
50
- export interface ControlConfig {
51
- enabled?: boolean;
52
- needsAttentionAfterMs?: number;
53
- notifyOn?: ControlEventType[];
54
- notifyChannels?: ControlNotificationChannel[];
55
- }
56
-
57
- export interface ResolvedControlConfig {
58
- enabled: boolean;
59
- needsAttentionAfterMs: number;
60
- notifyOn: ControlEventType[];
61
- notifyChannels: ControlNotificationChannel[];
62
- }
63
-
64
- export interface ControlEvent {
65
- type: ControlEventType;
66
- from?: ActivityState;
67
- to: ActivityState;
68
- ts: number;
69
- agent: string;
70
- index?: number;
71
- runId: string;
72
- message: string;
73
- }
74
-
75
- export type SubagentResultStatus = "completed" | "failed" | "paused" | "detached";
76
-
77
- export interface SubagentResultIntercomChild {
78
- agent: string;
79
- status: SubagentResultStatus;
80
- summary: string;
81
- index?: number;
82
- artifactPath?: string;
83
- sessionPath?: string;
84
- intercomTarget?: string;
85
- }
86
-
87
- export interface SubagentResultIntercomPayload {
88
- to: string;
89
- message: string;
90
- requestId?: string;
91
- runId: string;
92
- mode: "single" | "parallel" | "chain";
93
- status: SubagentResultStatus;
94
- summary: string;
95
- source: "foreground" | "async";
96
- children: SubagentResultIntercomChild[];
97
- asyncId?: string;
98
- asyncDir?: string;
99
- chainSteps?: number;
100
- agent?: string;
101
- index?: number;
102
- artifactPath?: string;
103
- sessionPath?: string;
104
- }
105
-
106
- // ============================================================================
107
- // Progress Tracking
108
- // ============================================================================
109
-
110
- export interface AgentProgress {
111
- index: number;
112
- agent: string;
113
- status: "pending" | "running" | "completed" | "failed" | "detached";
114
- activityState?: ActivityState;
115
- task: string;
116
- skills?: string[];
117
- lastActivityAt?: number;
118
- currentTool?: string;
119
- currentToolArgs?: string;
120
- currentToolStartedAt?: number;
121
- recentTools: Array<{ tool: string; args: string; endMs: number }>;
122
- recentOutput: string[];
123
- toolCount: number;
124
- tokens: number;
125
- durationMs: number;
126
- error?: string;
127
- failedTool?: string;
128
- }
129
-
130
- export interface ToolCallSummary {
131
- text: string;
132
- expandedText: string;
133
- }
134
-
135
- export interface ProgressSummary {
136
- toolCount: number;
137
- tokens: number;
138
- durationMs: number;
139
- }
140
-
141
- // ============================================================================
142
- // Results
143
- // ============================================================================
144
-
145
- export interface ModelAttempt {
146
- model: string;
147
- success: boolean;
148
- exitCode?: number | null;
149
- error?: string;
150
- usage?: Usage;
151
- }
152
-
153
- export interface SingleResult {
154
- agent: string;
155
- task: string;
156
- exitCode: number;
157
- detached?: boolean;
158
- detachedReason?: string;
159
- interrupted?: boolean;
160
- messages?: Message[];
161
- usage: Usage;
162
- model?: string;
163
- attemptedModels?: string[];
164
- modelAttempts?: ModelAttempt[];
165
- controlEvents?: ControlEvent[];
166
- error?: string;
167
- sessionFile?: string;
168
- skills?: string[];
169
- skillsWarning?: string;
170
- progress?: AgentProgress;
171
- progressSummary?: ProgressSummary;
172
- toolCalls?: ToolCallSummary[];
173
- artifactPaths?: ArtifactPaths;
174
- truncation?: TruncationResult;
175
- finalOutput?: string;
176
- savedOutputPath?: string;
177
- outputSaveError?: string;
178
- }
179
-
180
- export interface Details {
181
- mode: "single" | "parallel" | "chain" | "management";
182
- context?: "fresh" | "fork";
183
- results: SingleResult[];
184
- controlEvents?: ControlEvent[];
185
- asyncId?: string;
186
- asyncDir?: string;
187
- progress?: AgentProgress[];
188
- progressSummary?: ProgressSummary;
189
- artifacts?: {
190
- dir: string;
191
- files: ArtifactPaths[];
192
- };
193
- truncation?: {
194
- truncated: boolean;
195
- originalBytes?: number;
196
- originalLines?: number;
197
- artifactPath?: string;
198
- };
199
- // Chain metadata for observability
200
- chainAgents?: string[]; // Agent names in order, e.g., ["scout", "planner"]
201
- totalSteps?: number; // Total steps in chain
202
- currentStepIndex?: number; // 0-indexed current step (for running chains)
203
- }
204
-
205
- // ============================================================================
206
- // Artifacts
207
- // ============================================================================
208
-
209
- export interface ArtifactPaths {
210
- inputPath: string;
211
- outputPath: string;
212
- jsonlPath: string;
213
- metadataPath: string;
214
- }
215
-
216
- export interface ArtifactConfig {
217
- enabled: boolean;
218
- includeInput: boolean;
219
- includeOutput: boolean;
220
- includeJsonl: boolean;
221
- includeMetadata: boolean;
222
- cleanupDays: number;
223
- }
224
-
225
- // ============================================================================
226
- // Async Execution
227
- // ============================================================================
228
-
229
- export interface AsyncStatus {
230
- runId: string;
231
- mode: "single" | "chain";
232
- state: "queued" | "running" | "complete" | "failed" | "paused";
233
- activityState?: ActivityState;
234
- lastActivityAt?: number;
235
- currentTool?: string;
236
- currentToolStartedAt?: number;
237
- startedAt: number;
238
- endedAt?: number;
239
- lastUpdate?: number;
240
- pid?: number;
241
- cwd?: string;
242
- currentStep?: number;
243
- steps?: Array<{
244
- agent: string;
245
- status: string;
246
- activityState?: ActivityState;
247
- lastActivityAt?: number;
248
- currentTool?: string;
249
- currentToolStartedAt?: number;
250
- startedAt?: number;
251
- endedAt?: number;
252
- durationMs?: number;
253
- tokens?: TokenUsage;
254
- skills?: string[];
255
- model?: string;
256
- attemptedModels?: string[];
257
- modelAttempts?: ModelAttempt[];
258
- error?: string;
259
- }>;
260
- sessionDir?: string;
261
- outputFile?: string;
262
- totalTokens?: TokenUsage;
263
- sessionFile?: string;
264
- }
265
-
266
- export interface AsyncJobState {
267
- asyncId: string;
268
- asyncDir: string;
269
- status: "queued" | "running" | "complete" | "failed" | "paused";
270
- activityState?: ActivityState;
271
- lastActivityAt?: number;
272
- currentTool?: string;
273
- currentToolStartedAt?: number;
274
- mode?: "single" | "chain";
275
- agents?: string[];
276
- currentStep?: number;
277
- stepsTotal?: number;
278
- startedAt?: number;
279
- updatedAt?: number;
280
- sessionDir?: string;
281
- outputFile?: string;
282
- totalTokens?: TokenUsage;
283
- sessionFile?: string;
284
- controlEventCursor?: number;
285
- }
286
-
287
- export interface SubagentState {
288
- baseCwd: string;
289
- currentSessionId: string | null;
290
- asyncJobs: Map<string, AsyncJobState>;
291
- foregroundControls: Map<string, {
292
- runId: string;
293
- mode: "single" | "parallel" | "chain";
294
- startedAt: number;
295
- updatedAt: number;
296
- currentAgent?: string;
297
- currentIndex?: number;
298
- currentActivityState?: ActivityState;
299
- lastActivityAt?: number;
300
- currentTool?: string;
301
- currentToolStartedAt?: number;
302
- interrupt?: () => boolean;
303
- }>;
304
- lastForegroundControlId: string | null;
305
- cleanupTimers: Map<string, ReturnType<typeof setTimeout>>;
306
- lastUiContext: ExtensionContext | null;
307
- poller: NodeJS.Timeout | null;
308
- completionSeen: Map<string, number>;
309
- watcher: FSWatcher | null;
310
- watcherRestartTimer: ReturnType<typeof setTimeout> | null;
311
- resultFileCoalescer: {
312
- schedule(file: string, delayMs?: number): boolean;
313
- clear(): void;
314
- };
315
- }
316
-
317
- // ============================================================================
318
- // Display
319
- // ============================================================================
320
-
321
- export type DisplayItem =
322
- | { type: "text"; text: string }
323
- | { type: "tool"; name: string; args: Record<string, unknown> };
324
-
325
- // ============================================================================
326
- // Error Handling
327
- // ============================================================================
328
-
329
- export interface ErrorInfo {
330
- hasError: boolean;
331
- exitCode?: number;
332
- errorType?: string;
333
- details?: string;
334
- }
335
-
336
- export interface IntercomEventBus {
337
- on(channel: string, handler: (data: unknown) => void): () => void;
338
- emit(channel: string, data: unknown): void;
339
- }
340
-
341
- export const INTERCOM_DETACH_REQUEST_EVENT = "pi-intercom:detach-request";
342
- export const INTERCOM_DETACH_RESPONSE_EVENT = "pi-intercom:detach-response";
343
- export const SUBAGENT_ASYNC_STARTED_EVENT = "subagent:async-started";
344
- export const SUBAGENT_ASYNC_COMPLETE_EVENT = "subagent:async-complete";
345
- export const SUBAGENT_CONTROL_EVENT = "subagent:control-event";
346
- export const SUBAGENT_CONTROL_INTERCOM_EVENT = "subagent:control-intercom";
347
- export const SUBAGENT_RESULT_INTERCOM_EVENT = "subagent:result-intercom";
348
- export const SUBAGENT_RESULT_INTERCOM_DELIVERY_EVENT = "subagent:result-intercom-delivery";
349
-
350
- // ============================================================================
351
- // Execution Options
352
- // ============================================================================
353
-
354
- export interface RunSyncOptions {
355
- cwd?: string;
356
- signal?: AbortSignal;
357
- interruptSignal?: AbortSignal;
358
- allowIntercomDetach?: boolean;
359
- intercomEvents?: IntercomEventBus;
360
- onUpdate?: (r: import("@mariozechner/pi-agent-core").AgentToolResult<Details>) => void;
361
- onControlEvent?: (event: ControlEvent) => void;
362
- controlConfig?: ResolvedControlConfig;
363
- intercomSessionName?: string;
364
- maxOutput?: MaxOutputConfig;
365
- artifactsDir?: string;
366
- artifactConfig?: ArtifactConfig;
367
- runId: string;
368
- index?: number;
369
- sessionDir?: string;
370
- sessionFile?: string;
371
- share?: boolean;
372
- outputPath?: string;
373
- maxSubagentDepth?: number;
374
- /** Override the agent's default model (format: "provider/id" or just "id") */
375
- modelOverride?: string;
376
- /** Registry models available for heuristic bare-model resolution */
377
- availableModels?: Array<{ provider: string; id: string; fullId: string }>;
378
- /** Current parent-session provider to prefer for ambiguous bare model ids */
379
- preferredModelProvider?: string;
380
- /** Skills to inject (overrides agent default if provided) */
381
- skills?: string[];
382
- }
383
-
384
- export type IntercomBridgeMode = "off" | "fork-only" | "always";
385
-
386
- export interface IntercomBridgeConfig {
387
- mode?: IntercomBridgeMode;
388
- instructionFile?: string;
389
- }
390
-
391
- export interface TopLevelParallelConfig {
392
- maxTasks?: number;
393
- concurrency?: number;
394
- }
395
-
396
- export interface ExtensionConfig {
397
- asyncByDefault?: boolean;
398
- forceTopLevelAsync?: boolean;
399
- defaultSessionDir?: string;
400
- maxSubagentDepth?: number;
401
- control?: ControlConfig;
402
- parallel?: TopLevelParallelConfig;
403
- worktreeSetupHook?: string;
404
- worktreeSetupHookTimeoutMs?: number;
405
- intercomBridge?: IntercomBridgeConfig;
406
- }
407
-
408
- // ============================================================================
409
- // Constants
410
- // ============================================================================
411
-
412
- export const DEFAULT_MAX_OUTPUT: Required<MaxOutputConfig> = {
413
- bytes: 200 * 1024,
414
- lines: 5000,
415
- };
416
-
417
- export const DEFAULT_ARTIFACT_CONFIG: ArtifactConfig = {
418
- enabled: true,
419
- includeInput: true,
420
- includeOutput: true,
421
- includeJsonl: false,
422
- includeMetadata: true,
423
- cleanupDays: 7,
424
- };
425
-
426
- function sanitizeTempScopeSegment(value: string): string {
427
- const sanitized = value
428
- .trim()
429
- .replace(/[^A-Za-z0-9._-]+/g, "-")
430
- .replace(/^-+|-+$/g, "");
431
- return sanitized || "unknown";
432
- }
433
-
434
- export function resolveTempScopeId(options?: {
435
- env?: NodeJS.ProcessEnv;
436
- getuid?: (() => number) | undefined;
437
- userInfo?: (() => { username?: string | null }) | undefined;
438
- homedir?: (() => string) | undefined;
439
- }): string {
440
- const env = options?.env ?? process.env;
441
- const getuid = options && Object.hasOwn(options, "getuid")
442
- ? options.getuid
443
- : process.getuid?.bind(process);
444
- if (typeof getuid === "function") {
445
- return `uid-${getuid()}`;
446
- }
447
-
448
- for (const key of ["USERNAME", "USER", "LOGNAME"] as const) {
449
- const value = env[key];
450
- if (value) return `user-${sanitizeTempScopeSegment(value)}`;
451
- }
452
-
453
- const userInfo = options && Object.hasOwn(options, "userInfo")
454
- ? options.userInfo
455
- : os.userInfo;
456
- try {
457
- const username = userInfo?.().username;
458
- if (username) return `user-${sanitizeTempScopeSegment(username)}`;
459
- } catch {
460
- // Fall through to home-directory-based scoping.
461
- }
462
-
463
- const homedir = env.USERPROFILE ?? env.HOME;
464
- if (homedir) return `home-${sanitizeTempScopeSegment(homedir)}`;
465
-
466
- const resolveHomedir = options && Object.hasOwn(options, "homedir")
467
- ? options.homedir
468
- : os.homedir;
469
- try {
470
- const fallbackHomedir = resolveHomedir?.();
471
- if (fallbackHomedir) return `home-${sanitizeTempScopeSegment(fallbackHomedir)}`;
472
- } catch {
473
- // Fall through to the last-resort shared scope.
474
- }
475
-
476
- return "shared";
477
- }
478
-
479
- export const MAX_PARALLEL = 8;
480
- export const MAX_CONCURRENCY = 4;
481
- export const TEMP_ROOT_DIR = path.join(os.tmpdir(), `pi-subagents-${resolveTempScopeId()}`);
482
- export const RESULTS_DIR = path.join(TEMP_ROOT_DIR, "async-subagent-results");
483
- export const ASYNC_DIR = path.join(TEMP_ROOT_DIR, "async-subagent-runs");
484
- export const CHAIN_RUNS_DIR = path.join(TEMP_ROOT_DIR, "chain-runs");
485
- export const TEMP_ARTIFACTS_DIR = path.join(TEMP_ROOT_DIR, "artifacts");
486
- export const WIDGET_KEY = "subagent-async";
487
- export const SLASH_RESULT_TYPE = "subagent-slash-result";
488
- export const SLASH_SUBAGENT_REQUEST_EVENT = "subagent:slash:request";
489
- export const SLASH_SUBAGENT_STARTED_EVENT = "subagent:slash:started";
490
- export const SLASH_SUBAGENT_RESPONSE_EVENT = "subagent:slash:response";
491
- export const SLASH_SUBAGENT_UPDATE_EVENT = "subagent:slash:update";
492
- export const SLASH_SUBAGENT_CANCEL_EVENT = "subagent:slash:cancel";
493
- export const POLL_INTERVAL_MS = 250;
494
- export const MAX_WIDGET_JOBS = 4;
495
- export const DEFAULT_SUBAGENT_MAX_DEPTH = 2;
496
-
497
- export const DEFAULT_FORK_PREAMBLE =
498
- "You are a delegated subagent running from a fork of the parent session. " +
499
- "Treat the inherited conversation as reference-only context, not a live thread to continue. " +
500
- "Do not continue or answer prior messages as if they are waiting for a reply. " +
501
- "Your sole job is to execute the task below and return a focused result for that task using your tools.";
502
-
503
- function normalizeTopLevelParallelValue(value: unknown): number | undefined {
504
- const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
505
- if (!Number.isInteger(parsed) || parsed < 1) return undefined;
506
- return parsed;
507
- }
508
-
509
- export function resolveTopLevelParallelMaxTasks(value: unknown): number {
510
- return normalizeTopLevelParallelValue(value) ?? MAX_PARALLEL;
511
- }
512
-
513
- export function resolveTopLevelParallelConcurrency(
514
- override: unknown,
515
- configValue: unknown,
516
- ): number {
517
- return normalizeTopLevelParallelValue(override)
518
- ?? normalizeTopLevelParallelValue(configValue)
519
- ?? MAX_CONCURRENCY;
520
- }
521
-
522
- export function getAsyncConfigPath(suffix: string): string {
523
- return path.join(TEMP_ROOT_DIR, `async-cfg-${suffix}.json`);
524
- }
525
-
526
- export function wrapForkTask(task: string, preamble?: string | false): string {
527
- if (preamble === false) return task;
528
- const effectivePreamble = preamble ?? DEFAULT_FORK_PREAMBLE;
529
- const wrappedPrefix = `${effectivePreamble}\n\nTask:\n`;
530
- if (task.startsWith(wrappedPrefix)) return task;
531
- return `${wrappedPrefix}${task}`;
532
- }
533
-
534
- // ============================================================================
535
- // Recursion Depth Guard
536
- // ============================================================================
537
-
538
- export function normalizeMaxSubagentDepth(value: unknown): number | undefined {
539
- const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
540
- if (!Number.isInteger(parsed) || parsed < 0) return undefined;
541
- return parsed;
542
- }
543
-
544
- export function resolveCurrentMaxSubagentDepth(configMaxDepth?: number): number {
545
- return normalizeMaxSubagentDepth(process.env.PI_SUBAGENT_MAX_DEPTH)
546
- ?? normalizeMaxSubagentDepth(configMaxDepth)
547
- ?? DEFAULT_SUBAGENT_MAX_DEPTH;
548
- }
549
-
550
- export function resolveChildMaxSubagentDepth(parentMaxDepth: number, agentMaxDepth?: number): number {
551
- const normalizedParent = normalizeMaxSubagentDepth(parentMaxDepth) ?? DEFAULT_SUBAGENT_MAX_DEPTH;
552
- const normalizedAgent = normalizeMaxSubagentDepth(agentMaxDepth);
553
- return normalizedAgent === undefined ? normalizedParent : Math.min(normalizedParent, normalizedAgent);
554
- }
555
-
556
- export function checkSubagentDepth(configMaxDepth?: number): { blocked: boolean; depth: number; maxDepth: number } {
557
- const depth = Number(process.env.PI_SUBAGENT_DEPTH ?? "0");
558
- const maxDepth = resolveCurrentMaxSubagentDepth(configMaxDepth);
559
- const blocked = Number.isFinite(depth) && depth >= maxDepth;
560
- return { blocked, depth, maxDepth };
561
- }
562
-
563
- export function getSubagentDepthEnv(maxDepth?: number): Record<string, string> {
564
- const parentDepth = Number(process.env.PI_SUBAGENT_DEPTH ?? "0");
565
- const nextDepth = Number.isFinite(parentDepth) ? parentDepth + 1 : 1;
566
- return {
567
- PI_SUBAGENT_DEPTH: String(nextDepth),
568
- PI_SUBAGENT_MAX_DEPTH: String(normalizeMaxSubagentDepth(maxDepth) ?? resolveCurrentMaxSubagentDepth()),
569
- };
570
- }
571
-
572
- // ============================================================================
573
- // Utility Functions
574
- // ============================================================================
575
-
576
- export function formatBytes(bytes: number): string {
577
- if (bytes < 1024) return `${bytes}B`;
578
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
579
- return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
580
- }
581
-
582
- export function truncateOutput(
583
- output: string,
584
- config: Required<MaxOutputConfig>,
585
- artifactPath?: string,
586
- ): TruncationResult {
587
- const lines = output.split("\n");
588
- const bytes = Buffer.byteLength(output, "utf-8");
589
-
590
- if (bytes <= config.bytes && lines.length <= config.lines) {
591
- return { text: output, truncated: false };
592
- }
593
-
594
- let truncatedLines = lines;
595
- if (lines.length > config.lines) {
596
- truncatedLines = lines.slice(0, config.lines);
597
- }
598
-
599
- let result = truncatedLines.join("\n");
600
- if (Buffer.byteLength(result, "utf-8") > config.bytes) {
601
- let low = 0;
602
- let high = result.length;
603
- while (low < high) {
604
- const mid = Math.floor((low + high + 1) / 2);
605
- if (Buffer.byteLength(result.slice(0, mid), "utf-8") <= config.bytes) {
606
- low = mid;
607
- } else {
608
- high = mid - 1;
609
- }
610
- }
611
- result = result.slice(0, low);
612
- }
613
-
614
- const keptLines = result.split("\n").length;
615
- const marker = `[TRUNCATED: showing first ${keptLines} of ${lines.length} lines, ${formatBytes(Buffer.byteLength(result))} of ${formatBytes(bytes)}${artifactPath ? ` - full output at ${artifactPath}` : ""}]\n`;
616
-
617
- return {
618
- text: marker + result,
619
- truncated: true,
620
- originalBytes: bytes,
621
- originalLines: lines.length,
622
- artifactPath,
623
- };
624
- }