pi-orchestrator-config 4.1.5

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 (175) hide show
  1. package/README.md +808 -0
  2. package/agents/api-documenter.md +32 -0
  3. package/agents/bash-expert.md +53 -0
  4. package/agents/code-reviewer-docs.md +145 -0
  5. package/agents/code-reviewer-guidelines.md +97 -0
  6. package/agents/code-reviewer-quality.md +142 -0
  7. package/agents/code-reviewer-security.md +107 -0
  8. package/agents/code-reviewer-spec.md +164 -0
  9. package/agents/debugger.md +63 -0
  10. package/agents/docker-expert.md +40 -0
  11. package/agents/docs-fetcher.md +48 -0
  12. package/agents/git-expert.md +63 -0
  13. package/agents/github-expert.md +83 -0
  14. package/agents/go-expert.md +62 -0
  15. package/agents/issue-reviewer-feasibility.md +60 -0
  16. package/agents/issue-reviewer-scope.md +63 -0
  17. package/agents/issue-reviewer-spec.md +77 -0
  18. package/agents/java-expert.md +31 -0
  19. package/agents/jenkins-expert.md +38 -0
  20. package/agents/kubernetes-expert.md +40 -0
  21. package/agents/planner.md +42 -0
  22. package/agents/python-expert.md +61 -0
  23. package/agents/reviewer.md +26 -0
  24. package/agents/scout.md +40 -0
  25. package/agents/security-auditor.md +254 -0
  26. package/agents/technical-documentation-writer.md +37 -0
  27. package/agents/test-automator.md +55 -0
  28. package/agents/test-runner.md +47 -0
  29. package/agents/ts-expert.md +23 -0
  30. package/agents/worker.md +30 -0
  31. package/extensions/acpx-provider/index.ts +104 -0
  32. package/extensions/acpx-provider/load-runtime.ts +99 -0
  33. package/extensions/acpx-provider/runtime-models.ts +40 -0
  34. package/extensions/cli-provider/agents/claude.ts +128 -0
  35. package/extensions/cli-provider/agents/cursor.ts +84 -0
  36. package/extensions/cli-provider/agents/gemini.ts +100 -0
  37. package/extensions/cli-provider/discover.ts +77 -0
  38. package/extensions/cli-provider/index.ts +57 -0
  39. package/extensions/cli-provider/parsers.ts +304 -0
  40. package/extensions/cli-provider/providers.ts +58 -0
  41. package/extensions/cli-provider/runner.ts +225 -0
  42. package/extensions/cli-provider/runtime-models.ts +32 -0
  43. package/extensions/cli-provider/session-reaper.ts +122 -0
  44. package/extensions/cli-provider/sessions.ts +533 -0
  45. package/extensions/cli-provider/shared/discover-cache.ts +235 -0
  46. package/extensions/cli-provider/types.ts +48 -0
  47. package/extensions/coms/coms-net-server.ts +1642 -0
  48. package/extensions/coms/coms-net-wrapper.ts +521 -0
  49. package/extensions/coms/coms-net.ts +1589 -0
  50. package/extensions/coms/coms-p2p.ts +1879 -0
  51. package/extensions/coms/coms-shared.ts +510 -0
  52. package/extensions/coms/coms-wrapper.ts +138 -0
  53. package/extensions/coms/index.ts +20 -0
  54. package/extensions/coms/themeMap.ts +147 -0
  55. package/extensions/image-gen/image-gen.ts +332 -0
  56. package/extensions/image-gen/index.ts +14 -0
  57. package/extensions/orchestrator/agents.ts +134 -0
  58. package/extensions/orchestrator/ask-user.ts +293 -0
  59. package/extensions/orchestrator/async-agents.ts +1037 -0
  60. package/extensions/orchestrator/async-capability.ts +129 -0
  61. package/extensions/orchestrator/async-runner.ts +324 -0
  62. package/extensions/orchestrator/async-status-parse.ts +31 -0
  63. package/extensions/orchestrator/async-status-ui.ts +201 -0
  64. package/extensions/orchestrator/async-wait.ts +36 -0
  65. package/extensions/orchestrator/btw.ts +210 -0
  66. package/extensions/orchestrator/cron-status-format.ts +126 -0
  67. package/extensions/orchestrator/cron-status-ui.ts +132 -0
  68. package/extensions/orchestrator/cron.ts +730 -0
  69. package/extensions/orchestrator/dreaming.ts +355 -0
  70. package/extensions/orchestrator/enforcement-helpers.ts +530 -0
  71. package/extensions/orchestrator/enforcement-rules.ts +329 -0
  72. package/extensions/orchestrator/enforcement.ts +828 -0
  73. package/extensions/orchestrator/extended-autocomplete.ts +593 -0
  74. package/extensions/orchestrator/git-helpers.ts +420 -0
  75. package/extensions/orchestrator/github-autocomplete.ts +250 -0
  76. package/extensions/orchestrator/icons.ts +17 -0
  77. package/extensions/orchestrator/index.ts +100 -0
  78. package/extensions/orchestrator/memory-embeddings.ts +281 -0
  79. package/extensions/orchestrator/memory-promotion.ts +449 -0
  80. package/extensions/orchestrator/memory-provenance.ts +80 -0
  81. package/extensions/orchestrator/memory-query-class.ts +90 -0
  82. package/extensions/orchestrator/memory-scoring.ts +434 -0
  83. package/extensions/orchestrator/memory-tools.ts +883 -0
  84. package/extensions/orchestrator/memory-tree.ts +212 -0
  85. package/extensions/orchestrator/nvim.ts +169 -0
  86. package/extensions/orchestrator/overlay-dashboard-utils.ts +25 -0
  87. package/extensions/orchestrator/overlay-dashboard.ts +512 -0
  88. package/extensions/orchestrator/pi-config-review-state.ts +303 -0
  89. package/extensions/orchestrator/preference-extractor.ts +106 -0
  90. package/extensions/orchestrator/project-settings.ts +468 -0
  91. package/extensions/orchestrator/promotion-queue.ts +311 -0
  92. package/extensions/orchestrator/resolve-agent-model.ts +32 -0
  93. package/extensions/orchestrator/review-ui.ts +204 -0
  94. package/extensions/orchestrator/rule-placeholders.ts +12 -0
  95. package/extensions/orchestrator/rules.ts +481 -0
  96. package/extensions/orchestrator/session-search.ts +243 -0
  97. package/extensions/orchestrator/session-validation.ts +374 -0
  98. package/extensions/orchestrator/situation-report.ts +370 -0
  99. package/extensions/orchestrator/status-bar.ts +31 -0
  100. package/extensions/orchestrator/status-line.ts +192 -0
  101. package/extensions/orchestrator/status.ts +110 -0
  102. package/extensions/orchestrator/subagent-tool.ts +1748 -0
  103. package/extensions/orchestrator/task-lifecycle.ts +88 -0
  104. package/extensions/orchestrator/utils.ts +227 -0
  105. package/extensions/pidash/index.ts +15 -0
  106. package/extensions/pidash/pidash.ts +941 -0
  107. package/extensions/pidiff/index.ts +13 -0
  108. package/extensions/pidiff/pidiff.ts +369 -0
  109. package/extensions/providers/acpx-driver.ts +479 -0
  110. package/extensions/providers/built-in-drivers.ts +52 -0
  111. package/extensions/providers/claude-driver.ts +319 -0
  112. package/extensions/providers/cursor-acpx-driver.ts +398 -0
  113. package/extensions/providers/cursor-cli-driver.ts +484 -0
  114. package/extensions/providers/gemini-driver.ts +302 -0
  115. package/extensions/providers/index.ts +513 -0
  116. package/extensions/shared/build-system-prompt.ts +57 -0
  117. package/extensions/shared/create-runtime-provider.ts +190 -0
  118. package/extensions/shared/daemon-manager.ts +248 -0
  119. package/extensions/shared/file-logger.ts +115 -0
  120. package/extensions/shared/managed-refresh.ts +211 -0
  121. package/extensions/shared/provider-driver.ts +295 -0
  122. package/extensions/shared/provider-errors.ts +305 -0
  123. package/extensions/shared/provider-registry.ts +388 -0
  124. package/extensions/shared/stream-builder.ts +275 -0
  125. package/extensions/shared/types.ts +20 -0
  126. package/extensions/shared/ui/README.md +10 -0
  127. package/extensions/shared/ui/badge.tsx +52 -0
  128. package/extensions/shared/ui/button.tsx +58 -0
  129. package/extensions/shared/ui/collapsible.tsx +21 -0
  130. package/extensions/shared/ui/dropdown-menu.tsx +266 -0
  131. package/extensions/shared/ui/input.tsx +20 -0
  132. package/extensions/shared/ui/popover.tsx +114 -0
  133. package/extensions/shared/ui/resizable.tsx +48 -0
  134. package/extensions/shared/ui/scroll-area.tsx +53 -0
  135. package/extensions/shared/ui/select.tsx +201 -0
  136. package/extensions/shared/ui/separator.tsx +25 -0
  137. package/extensions/shared/ui/tooltip.tsx +64 -0
  138. package/extensions/shared/ws-client.ts +74 -0
  139. package/package.json +59 -0
  140. package/prompts/coderabbit-rate-limit.md +95 -0
  141. package/prompts/create-coms-feature-manager.md +186 -0
  142. package/prompts/create-skill.md +128 -0
  143. package/prompts/domain-model.md +109 -0
  144. package/prompts/external-ai.md +665 -0
  145. package/prompts/implement-and-review.md +25 -0
  146. package/prompts/implement.md +26 -0
  147. package/prompts/issue-review.md +256 -0
  148. package/prompts/pr-review.md +753 -0
  149. package/prompts/query-db.md +154 -0
  150. package/prompts/refine-review.md +208 -0
  151. package/prompts/release.md +235 -0
  152. package/prompts/remember.md +33 -0
  153. package/prompts/review-handler-status.md +27 -0
  154. package/prompts/review-handler.md +677 -0
  155. package/prompts/review-local.md +159 -0
  156. package/prompts/scout-and-plan.md +21 -0
  157. package/rules/00-orchestrator-core.md +42 -0
  158. package/rules/05-issue-first-workflow.md +119 -0
  159. package/rules/10-agent-routing.md +58 -0
  160. package/rules/15-mcp-launchpad.md +46 -0
  161. package/rules/20-code-review-loop.md +234 -0
  162. package/rules/25-documentation-updates.md +15 -0
  163. package/rules/30-prompt-templates.md +19 -0
  164. package/rules/35-memory.md +240 -0
  165. package/rules/40-critical-rules.md +124 -0
  166. package/rules/45-file-preview.md +29 -0
  167. package/rules/50-agent-bug-reporting.md +90 -0
  168. package/rules/55-coms-protocol.md +63 -0
  169. package/rules/60-task-tracking.md +66 -0
  170. package/skills/conflict-resolver/SKILL.md +213 -0
  171. package/skills/skill-creator/SKILL.md +85 -0
  172. package/skills/systematic-debugging/SKILL.md +353 -0
  173. package/skills/test-driven-development/SKILL.md +335 -0
  174. package/skills/update-agents-md/SKILL.md +282 -0
  175. package/templates/coms-feature-manager-prompt.md +313 -0
@@ -0,0 +1,225 @@
1
+ /**
2
+ * Spawn CLI agent processes — buffered or live stream-json.
3
+ */
4
+
5
+ import { spawn } from "node:child_process";
6
+ import type { CliAgentName } from "./providers.js";
7
+ import { buildCliCommand } from "./providers.js";
8
+ import {
9
+ parseCliOutput,
10
+ StreamJsonAccumulator,
11
+ type CliParseResult,
12
+ type CliStreamEvent,
13
+ } from "./parsers.js";
14
+
15
+ export interface CliRunOptions {
16
+ agent: CliAgentName;
17
+ model: string;
18
+ cwd: string;
19
+ prompt: string;
20
+ sessionId?: string | null;
21
+ continueSession?: boolean;
22
+ signal?: AbortSignal;
23
+ /** Override the default agent binary (from driver config). */
24
+ binary?: string;
25
+ /** Optional only — no default. Omit for unlimited turn duration. */
26
+ timeoutMs?: number;
27
+ /** When set, stream NDJSON events as they arrive (stream-json agents). */
28
+ onEvent?: (event: CliStreamEvent) => void;
29
+ }
30
+
31
+ export interface CliRunResult extends CliParseResult {
32
+ exitCode: number | null;
33
+ stderr: string;
34
+ }
35
+
36
+ /**
37
+ * Resolve turn timeout for CLI agents.
38
+ *
39
+ * Intentional product policy (issue #647): **no default wall-clock timeout**.
40
+ * Long turns (e.g. autoqodo) must not be SIGKILL'd after N minutes.
41
+ * Cancellation: pass `AbortSignal`, or an explicit positive `timeoutMs`.
42
+ */
43
+ export function resolveCliTimeoutMs(
44
+ timeoutMs: number | undefined,
45
+ ): number | undefined {
46
+ return typeof timeoutMs === "number" && timeoutMs > 0 ? timeoutMs : undefined;
47
+ }
48
+
49
+ /** Env keys that cause nested-session / ACP re-entry in some CLIs. */
50
+ const STRIP_ENV = [
51
+ "CLAUDECODE",
52
+ "CLAUDE_CODE_ENTRYPOINT",
53
+ "CURSOR_AGENT",
54
+ "CURSOR_TRACE_ID",
55
+ ];
56
+
57
+ function childEnv(): NodeJS.ProcessEnv {
58
+ const env = { ...process.env };
59
+ for (const k of STRIP_ENV) delete env[k];
60
+ return env;
61
+ }
62
+
63
+ export function runCliAgent(opts: CliRunOptions): Promise<CliRunResult> {
64
+ const { binary, args, promptOnStdin } = buildCliCommand({
65
+ agent: opts.agent,
66
+ model: opts.model,
67
+ cwd: opts.cwd,
68
+ sessionId: opts.sessionId,
69
+ continueSession: opts.continueSession,
70
+ binary: opts.binary,
71
+ });
72
+
73
+ const argv = promptOnStdin ? args : [...args, opts.prompt];
74
+ const timeoutMs = resolveCliTimeoutMs(opts.timeoutMs);
75
+ const stream = typeof opts.onEvent === "function";
76
+
77
+ return new Promise((resolve, reject) => {
78
+ if (opts.signal?.aborted) {
79
+ reject(new Error("CLI call aborted"));
80
+ return;
81
+ }
82
+
83
+ const child = spawn(binary, argv, {
84
+ cwd: opts.cwd,
85
+ env: childEnv(),
86
+ stdio: ["pipe", "pipe", "pipe"],
87
+ windowsHide: true,
88
+ });
89
+
90
+ let stdout = "";
91
+ let stderr = "";
92
+ let settled = false;
93
+ const acc = new StreamJsonAccumulator();
94
+ const lineBuf = { value: "" };
95
+
96
+ let timer: ReturnType<typeof setTimeout> | undefined;
97
+ if (timeoutMs !== undefined) {
98
+ timer = setTimeout(() => {
99
+ try {
100
+ child.kill("SIGTERM");
101
+ setTimeout(() => {
102
+ try {
103
+ child.kill("SIGKILL");
104
+ } catch {
105
+ /* ignore */
106
+ }
107
+ }, 2000).unref?.();
108
+ } catch {
109
+ /* ignore */
110
+ }
111
+ if (!settled) {
112
+ settled = true;
113
+ reject(new Error(`CLI ${binary} timed out after ${timeoutMs}ms`));
114
+ }
115
+ }, timeoutMs);
116
+ timer.unref?.();
117
+ }
118
+ const onAbort = () => {
119
+ try {
120
+ child.kill("SIGTERM");
121
+ } catch {
122
+ /* ignore */
123
+ }
124
+ };
125
+ opts.signal?.addEventListener("abort", onAbort, { once: true });
126
+
127
+ child.stdout?.setEncoding("utf-8");
128
+ child.stderr?.setEncoding("utf-8");
129
+ child.stdout?.on("data", (d: string) => {
130
+ if (stream) {
131
+ for (const ev of acc.feedChunk(d, lineBuf)) {
132
+ opts.onEvent!(ev);
133
+ }
134
+ } else {
135
+ stdout += d;
136
+ }
137
+ });
138
+ child.stderr?.on("data", (d) => {
139
+ stderr += d;
140
+ });
141
+
142
+ // Attach before any write/end — child may exit immediately (EPIPE).
143
+ child.stdin?.on("error", () => {
144
+ /* ignore broken pipe */
145
+ });
146
+
147
+ if (promptOnStdin) {
148
+ try {
149
+ child.stdin?.write(opts.prompt);
150
+ child.stdin?.end();
151
+ } catch {
152
+ /* EPIPE if child exits before stdin write */
153
+ }
154
+ } else {
155
+ try {
156
+ child.stdin?.end();
157
+ } catch {
158
+ /* ignore */
159
+ }
160
+ }
161
+
162
+ child.on("error", (err) => {
163
+ if (timer) clearTimeout(timer);
164
+ opts.signal?.removeEventListener("abort", onAbort);
165
+ if (!settled) {
166
+ settled = true;
167
+ reject(err);
168
+ }
169
+ });
170
+
171
+ child.on("close", (code) => {
172
+ if (timer) clearTimeout(timer);
173
+ opts.signal?.removeEventListener("abort", onAbort);
174
+ if (settled) return;
175
+ settled = true;
176
+
177
+ if (stream) {
178
+ for (const ev of acc.flush(lineBuf)) {
179
+ opts.onEvent!(ev);
180
+ }
181
+ if (code !== 0 && !acc.text.trim()) {
182
+ reject(
183
+ new Error(
184
+ `CLI ${binary} exited ${code}: ${stderr.trim().slice(0, 500) || "no output"}`,
185
+ ),
186
+ );
187
+ return;
188
+ }
189
+ resolve({
190
+ text: acc.text,
191
+ sessionId: acc.sessionId,
192
+ thinking: acc.thinking || undefined,
193
+ usage: acc.usage,
194
+ exitCode: code,
195
+ stderr,
196
+ });
197
+ return;
198
+ }
199
+
200
+ if (code !== 0 && !stdout.trim()) {
201
+ reject(
202
+ new Error(
203
+ `CLI ${binary} exited ${code}: ${stderr.trim().slice(0, 500) || "no output"}`,
204
+ ),
205
+ );
206
+ return;
207
+ }
208
+ try {
209
+ const parsed = parseCliOutput(opts.agent, stdout);
210
+ resolve({
211
+ ...parsed,
212
+ exitCode: code,
213
+ stderr,
214
+ });
215
+ } catch (e: any) {
216
+ reject(
217
+ new Error(
218
+ `Failed to parse ${opts.agent} CLI output: ${e?.message || e}\n` +
219
+ `stdout head: ${stdout.slice(0, 200)}`,
220
+ ),
221
+ );
222
+ }
223
+ });
224
+ });
225
+ }
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Map CLI discovery results → full createProvider Model[].
3
+ * Kept separate from index.ts so unit tests do not load stream/session code.
4
+ */
5
+
6
+ import { buildRuntimeModel } from "../shared/create-runtime-provider.js";
7
+ import type { DiscoveredCliModel } from "./discover.js";
8
+
9
+ export function mapCliDiscoveredModels(
10
+ agent: string,
11
+ discovered: readonly DiscoveredCliModel[],
12
+ ): ReturnType<typeof buildRuntimeModel>[] {
13
+ const provider = `cli-${agent}`;
14
+ if (discovered.length === 0) {
15
+ return [
16
+ buildRuntimeModel({
17
+ id: `${agent}:default`,
18
+ name: `${agent} (default)`,
19
+ api: "cli",
20
+ provider,
21
+ }),
22
+ ];
23
+ }
24
+ return discovered.map((m) =>
25
+ buildRuntimeModel({
26
+ id: `${agent}:${m.id}`,
27
+ name: `${m.name} (${agent})`,
28
+ api: "cli",
29
+ provider,
30
+ }),
31
+ );
32
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Reap stale CLI session markers (t3 ProviderSessionReaper pattern).
3
+ * Deletes idle *stopped* bindings only — never status=running, so concurrent
4
+ * pi sessions in the same cwd keep CLI --resume continuity.
5
+ */
6
+
7
+ import { unlinkSync } from "node:fs";
8
+ import { cliProviderLog } from "../shared/file-logger.js";
9
+ import { listCliSessions } from "./sessions.js";
10
+
11
+ export const DEFAULT_INACTIVITY_THRESHOLD_MS = 30 * 60 * 1000;
12
+ export const DEFAULT_SWEEP_INTERVAL_MS = 5 * 60 * 1000;
13
+
14
+ export interface ReapOptions {
15
+ inactivityThresholdMs?: number;
16
+ /** Only reap sessions matching this cwd (optional). */
17
+ cwd?: string;
18
+ /**
19
+ * Current pi session UUID (informational / future scoping).
20
+ * Running markers are never reaped regardless of this value — concurrent
21
+ * sessions in the same cwd must keep --resume (issue #661).
22
+ */
23
+ activePiSessionId?: string | null;
24
+ }
25
+
26
+ /**
27
+ * Remove idle *stopped* session files only.
28
+ * Never deletes status=running (own or other piSessionId) so two pi processes
29
+ * on the same project both keep CLI --resume after idle timeouts.
30
+ */
31
+ export function reapStaleCliSessions(options?: ReapOptions): number {
32
+ const threshold = Math.max(
33
+ 1,
34
+ options?.inactivityThresholdMs ?? DEFAULT_INACTIVITY_THRESHOLD_MS,
35
+ );
36
+ const now = Date.now();
37
+ let reaped = 0;
38
+
39
+ for (const { path, record } of listCliSessions()) {
40
+ if (options?.cwd && record.cwd !== options.cwd) continue;
41
+
42
+ // Concurrent pi sessions share ~/.pi/cli-sessions for the same cwd.
43
+ // Deleting another session's running marker breaks its --resume.
44
+ if (record.status === "running") continue;
45
+
46
+ const lastSeenMs = Date.parse(record.lastSeenAt);
47
+ const idle =
48
+ Number.isNaN(lastSeenMs) || now - lastSeenMs >= threshold;
49
+ if (!idle) continue;
50
+
51
+ try {
52
+ unlinkSync(path);
53
+ reaped += 1;
54
+ cliProviderLog(
55
+ "info",
56
+ `reaped session ${record.agent}/${record.model} ` +
57
+ `(status=${record.status}, piSessionId=${record.piSessionId}, ` +
58
+ `lastSeen=${record.lastSeenAt})`,
59
+ );
60
+ } catch (err) {
61
+ cliProviderLog(
62
+ "error",
63
+ `failed to reap session ${record.agent}/${record.model} at ${path}`,
64
+ err,
65
+ );
66
+ }
67
+ }
68
+
69
+ return reaped;
70
+ }
71
+
72
+ let reaperTimer: ReturnType<typeof setInterval> | null = null;
73
+
74
+ /** Prefer getter over env when resolving which pi session the reaper protects. */
75
+ export function resolveReaperActivePiSessionId(
76
+ getActivePiSessionId?: () => string | null,
77
+ envPiSessionId: string | null | undefined = process.env.PI_SESSION_ID,
78
+ ): string | null {
79
+ // Getter provided (even if temporarily null) → do not fall back to env.
80
+ // Startup window before session_start must stay "unknown" so all running
81
+ // markers stay protected (/reload continuity).
82
+ if (typeof getActivePiSessionId === "function") {
83
+ const fromGetter = getActivePiSessionId();
84
+ return fromGetter != null && fromGetter !== "" ? fromGetter : null;
85
+ }
86
+ return envPiSessionId != null && envPiSessionId !== ""
87
+ ? envPiSessionId
88
+ : null;
89
+ }
90
+
91
+ export function startCliSessionReaper(opts?: {
92
+ sweepIntervalMs?: number;
93
+ inactivityThresholdMs?: number;
94
+ cwd?: string;
95
+ getActivePiSessionId?: () => string | null;
96
+ }): void {
97
+ stopCliSessionReaper();
98
+ const interval = Math.max(
99
+ 1,
100
+ opts?.sweepIntervalMs ?? DEFAULT_SWEEP_INTERVAL_MS,
101
+ );
102
+ const sweep = () => {
103
+ reapStaleCliSessions({
104
+ inactivityThresholdMs: opts?.inactivityThresholdMs,
105
+ cwd: opts?.cwd,
106
+ activePiSessionId: resolveReaperActivePiSessionId(
107
+ opts?.getActivePiSessionId,
108
+ ),
109
+ });
110
+ };
111
+ // Do not sweep immediately — activePiSessionId is usually still unset at
112
+ // extension load; waiting one interval avoids racing session_start.
113
+ reaperTimer = setInterval(sweep, interval);
114
+ if (reaperTimer.unref) reaperTimer.unref();
115
+ }
116
+
117
+ export function stopCliSessionReaper(): void {
118
+ if (reaperTimer) {
119
+ clearInterval(reaperTimer);
120
+ reaperTimer = null;
121
+ }
122
+ }