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,211 @@
1
+ /**
2
+ * Managed snapshot refresh — periodic re-probe with settings-change detection.
3
+ *
4
+ * Adapted from t3code's `makeManagedServerProvider.ts`. Uses plain
5
+ * TypeScript (setInterval, callbacks) instead of Effect (Fiber, PubSub, Ref).
6
+ *
7
+ * Provides periodic model refresh, settings-change detection, and an
8
+ * enrichment pipeline. All scoped — `dispose()` clears intervals and
9
+ * releases resources.
10
+ *
11
+ * @module shared/managed-refresh
12
+ */
13
+
14
+ import type { ProviderSnapshot, DiscoveredModel } from "./provider-driver.js";
15
+ import { fileLog } from "./file-logger.js";
16
+
17
+ const LOG_DOMAIN = "managed-refresh";
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Types
21
+ // ---------------------------------------------------------------------------
22
+
23
+ export interface ManagedSnapshotOptions<Settings = unknown> {
24
+ /** Build the initial snapshot from current settings. */
25
+ readonly initialSnapshot: (settings: Settings) => ProviderSnapshot;
26
+
27
+ /** Probe current status (binary version, availability, models). */
28
+ readonly checkProvider: () => Promise<ProviderSnapshot>;
29
+
30
+ /** Optional: enrich a snapshot (e.g. model catalog refresh). */
31
+ readonly enrichSnapshot?: (input: {
32
+ readonly settings: Settings;
33
+ readonly snapshot: ProviderSnapshot;
34
+ readonly getSnapshot: () => ProviderSnapshot;
35
+ readonly publishSnapshot: (snapshot: ProviderSnapshot) => void;
36
+ }) => Promise<void>;
37
+
38
+ /** Get current settings. */
39
+ readonly getSettings: () => Settings;
40
+
41
+ /** Detect meaningful settings changes. */
42
+ readonly haveSettingsChanged: (previous: Settings, next: Settings) => boolean;
43
+
44
+ /**
45
+ * Refresh interval in milliseconds.
46
+ * Default: 300_000 (5 minutes), matching t3code's SNAPSHOT_REFRESH_INTERVAL.
47
+ */
48
+ readonly refreshIntervalMs?: number;
49
+
50
+ /** Optional callback when snapshot changes. */
51
+ readonly onSnapshotChange?: (snapshot: ProviderSnapshot) => void;
52
+
53
+ /**
54
+ * Skip the fire-and-forget initial probe on create.
55
+ * Use when the caller already discovered models during create() and
56
+ * passed them via initialSnapshot — avoids duplicate discovery on startup.
57
+ */
58
+ readonly skipInitialRefresh?: boolean;
59
+ }
60
+
61
+ export interface ManagedSnapshotResult {
62
+ /** Get the current snapshot. */
63
+ readonly getSnapshot: () => ProviderSnapshot;
64
+ /** Force a refresh now. */
65
+ readonly refresh: () => Promise<ProviderSnapshot>;
66
+ /** Stop all refresh timers and release resources. */
67
+ readonly dispose: () => void;
68
+ }
69
+
70
+ // ---------------------------------------------------------------------------
71
+ // Implementation
72
+ // ---------------------------------------------------------------------------
73
+
74
+ const DEFAULT_REFRESH_INTERVAL_MS = 300_000; // 5 minutes
75
+
76
+ /**
77
+ * Create a managed snapshot with periodic refresh and settings-change detection.
78
+ *
79
+ * Adapted from t3code's `makeManagedServerProvider`:
80
+ * - Periodic refresh via `setInterval` (t3code uses `Effect.forever + Effect.sleep`)
81
+ * - Settings-change detection triggers re-probe (t3code uses `Stream.runForEach`)
82
+ * - Enrichment pipeline for model catalog refresh (t3code uses forked fibers)
83
+ * - Deterministic cleanup via `dispose()` (t3code uses `Scope`)
84
+ */
85
+ export function makeManagedSnapshot<Settings = unknown>(
86
+ opts: ManagedSnapshotOptions<Settings>,
87
+ ): ManagedSnapshotResult {
88
+ const refreshIntervalMs = opts.refreshIntervalMs ?? DEFAULT_REFRESH_INTERVAL_MS;
89
+
90
+ let currentSnapshot = opts.initialSnapshot(opts.getSettings());
91
+ let previousSettings = opts.getSettings();
92
+ let refreshing = false;
93
+ let disposed = false;
94
+ let enrichmentAbort: AbortController | null = null;
95
+
96
+ const publishSnapshot = (snapshot: ProviderSnapshot): void => {
97
+ if (disposed) return;
98
+ currentSnapshot = snapshot;
99
+ opts.onSnapshotChange?.(snapshot);
100
+ };
101
+
102
+ const doRefresh = async (forceRefresh = false): Promise<ProviderSnapshot> => {
103
+ if (disposed) return currentSnapshot;
104
+ if (refreshing) return currentSnapshot;
105
+ refreshing = true;
106
+
107
+ try {
108
+ const nextSettings = opts.getSettings();
109
+ const settingsChanged = opts.haveSettingsChanged(previousSettings, nextSettings);
110
+
111
+ if (!forceRefresh && !settingsChanged) {
112
+ previousSettings = nextSettings;
113
+ return currentSnapshot;
114
+ }
115
+
116
+ const nextSnapshot = await opts.checkProvider();
117
+ if (disposed) return currentSnapshot;
118
+
119
+ previousSettings = nextSettings;
120
+ publishSnapshot(nextSnapshot);
121
+
122
+ // Cancel any previous enrichment
123
+ if (enrichmentAbort) {
124
+ enrichmentAbort.abort();
125
+ enrichmentAbort = null;
126
+ }
127
+
128
+ // Run enrichment if provided
129
+ if (opts.enrichSnapshot) {
130
+ enrichmentAbort = new AbortController();
131
+ const capturedSnapshot = nextSnapshot;
132
+ // Fire-and-forget enrichment (t3code forks this as a scoped fiber)
133
+ opts.enrichSnapshot({
134
+ settings: nextSettings,
135
+ snapshot: capturedSnapshot,
136
+ getSnapshot: () => currentSnapshot,
137
+ publishSnapshot,
138
+ }).catch((err) => {
139
+ if (!disposed) {
140
+ fileLog(LOG_DOMAIN, "warn", LOG_DOMAIN,
141
+ `enrichment failed: ${err instanceof Error ? err.message : String(err)}`);
142
+ }
143
+ });
144
+ }
145
+
146
+ return nextSnapshot;
147
+ } catch (err) {
148
+ if (!disposed) {
149
+ fileLog(LOG_DOMAIN, "warn", LOG_DOMAIN,
150
+ `refresh failed: ${err instanceof Error ? err.message : String(err)}`);
151
+ }
152
+ return currentSnapshot;
153
+ } finally {
154
+ refreshing = false;
155
+ }
156
+ };
157
+
158
+ // Initial probe (fire-and-forget, matching t3code's forkScoped initial probe)
159
+ // Skip when the caller already discovered models during create() and passed
160
+ // them via initialSnapshot — avoids duplicate discovery on startup.
161
+ if (!opts.skipInitialRefresh) {
162
+ doRefresh(true).catch((err) => {
163
+ fileLog(LOG_DOMAIN, "warn", LOG_DOMAIN,
164
+ `initial refresh failed: ${err instanceof Error ? err.message : String(err)}`);
165
+ });
166
+ }
167
+
168
+ // Periodic refresh
169
+ const timer = setInterval(() => {
170
+ doRefresh(true).catch((err) => {
171
+ fileLog(LOG_DOMAIN, "warn", LOG_DOMAIN,
172
+ `periodic refresh failed: ${err instanceof Error ? err.message : String(err)}`);
173
+ });
174
+ }, refreshIntervalMs);
175
+
176
+ // Unref so it doesn't keep the process alive
177
+ if (timer.unref) timer.unref();
178
+
179
+ return {
180
+ getSnapshot: () => currentSnapshot,
181
+ refresh: () => doRefresh(true),
182
+ dispose: () => {
183
+ if (disposed) return;
184
+ disposed = true;
185
+ clearInterval(timer);
186
+ if (enrichmentAbort) {
187
+ enrichmentAbort.abort();
188
+ enrichmentAbort = null;
189
+ }
190
+ },
191
+ };
192
+ }
193
+
194
+ /**
195
+ * Build a simple initial snapshot from discovered models.
196
+ * Convenience for drivers that discover models during probe.
197
+ */
198
+ export function buildInitialSnapshot(
199
+ available: boolean,
200
+ models: readonly DiscoveredModel[],
201
+ version?: string,
202
+ message?: string,
203
+ ): ProviderSnapshot {
204
+ return {
205
+ available,
206
+ version,
207
+ models,
208
+ message,
209
+ checkedAt: new Date().toISOString(),
210
+ };
211
+ }
@@ -0,0 +1,295 @@
1
+ /**
2
+ * ProviderDriver / ProviderInstance — driver SPI as plain values.
3
+ *
4
+ * Adapted from t3code's `ProviderDriver.ts`. Uses plain TypeScript
5
+ * (no Effect dependency) — async functions replace Effect monads,
6
+ * try/finally replaces scoped lifecycle.
7
+ *
8
+ * `ProviderDriver` is a record, not a class. The thing it produces
9
+ * (`ProviderInstance`) is also a record — captured closures
10
+ * (`snapshot`, `adapter`), an id, and a driver kind. There are
11
+ * intentionally no singletons because we need many instances of the
12
+ * same driver.
13
+ *
14
+ * Driver factories are functions of `(typed config, env)` where:
15
+ * - `typed config` is validated once by the registry via `configSchema`,
16
+ * so drivers never deal with raw `unknown`.
17
+ * - Cleanup is deterministic: `dispose()` releases every resource the
18
+ * driver opened (child processes, intervals, pubsub channels).
19
+ *
20
+ * @module shared/provider-driver
21
+ */
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Stream Events (unified across CLI + ACPX)
25
+ // ---------------------------------------------------------------------------
26
+
27
+ /** Normalized event emitted by driver adapters during a turn. */
28
+ export type DriverStreamEvent =
29
+ | { readonly kind: "text_delta"; readonly text: string }
30
+ | { readonly kind: "thinking_delta"; readonly text: string }
31
+ | { readonly kind: "session"; readonly sessionId: string }
32
+ | { readonly kind: "turn_complete"; readonly stopReason?: string };
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // ProviderDriver Metadata
36
+ // ---------------------------------------------------------------------------
37
+
38
+ /**
39
+ * Static metadata advertised by a driver. Used for default presentation
40
+ * and (later) settings UI. Drivers are registered at startup — nothing
41
+ * here is dynamic.
42
+ */
43
+ export interface ProviderDriverMetadata {
44
+ /** Human-readable name for the driver itself (e.g. "Cursor CLI"). */
45
+ readonly displayName: string;
46
+ /**
47
+ * Whether the driver may be instantiated more than once concurrently.
48
+ * Defaults to `true`. Set to `false` for drivers that wrap a global
49
+ * resource (e.g. a single desktop app socket) — the registry then
50
+ * rejects multi-instance configurations with a clear error.
51
+ */
52
+ readonly supportsMultipleInstances?: boolean;
53
+ }
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Probe Result
57
+ // ---------------------------------------------------------------------------
58
+
59
+ /**
60
+ * Result of a driver's binary/runtime probe. Returned by `driver.probe()`.
61
+ * When `available` is false, the registry creates an "unavailable" shadow
62
+ * snapshot instead of calling `create()`.
63
+ */
64
+ export interface ProviderProbeResult {
65
+ readonly available: boolean;
66
+ readonly version?: string;
67
+ /** Human-readable reason when unavailable (e.g. "binary not on PATH"). */
68
+ readonly reason?: string;
69
+ }
70
+
71
+ // ---------------------------------------------------------------------------
72
+ // Provider Snapshot Shape
73
+ // ---------------------------------------------------------------------------
74
+
75
+ /** A point-in-time snapshot of a provider's status and models. */
76
+ export interface ProviderSnapshot {
77
+ readonly available: boolean;
78
+ readonly version?: string;
79
+ readonly models: readonly DiscoveredModel[];
80
+ /** Human-readable message (error detail, status, etc.). */
81
+ readonly message?: string;
82
+ readonly checkedAt: string;
83
+ }
84
+
85
+ /** Model discovered by a driver (used in snapshots). */
86
+ export interface DiscoveredModel {
87
+ readonly id: string;
88
+ readonly name: string;
89
+ }
90
+
91
+ /**
92
+ * Live snapshot accessor for a provider instance. The registry reads
93
+ * `getSnapshot()` for current state, calls `refresh()` to force a
94
+ * re-probe, and optionally subscribes to `onChange` for push updates.
95
+ */
96
+ export interface ProviderSnapshotShape {
97
+ readonly getSnapshot: () => ProviderSnapshot;
98
+ readonly refresh: () => Promise<ProviderSnapshot>;
99
+ /** Optional callback-based change notification. */
100
+ readonly onChange?: (listener: (snapshot: ProviderSnapshot) => void) => () => void;
101
+ /** Cleanup — stop refresh intervals, release resources. */
102
+ readonly dispose: () => void;
103
+ }
104
+
105
+ // ---------------------------------------------------------------------------
106
+ // Provider Adapter Shape (Session / Turn runtime)
107
+ // ---------------------------------------------------------------------------
108
+
109
+ /** Options for starting a session via the adapter. */
110
+ export interface SessionStartOptions {
111
+ readonly model?: string;
112
+ readonly systemPrompt?: string;
113
+ readonly cwd: string;
114
+ }
115
+
116
+ /** Opaque handle to an active adapter session. */
117
+ export interface SessionHandle {
118
+ readonly sessionId: string;
119
+ readonly model: string;
120
+ }
121
+
122
+ /** Options for sending a turn. */
123
+ export interface TurnOptions {
124
+ readonly signal?: AbortSignal;
125
+ /** Pi conversation context — used by drivers that seed history into fresh CLI sessions. */
126
+ readonly context?: { messages: Array<{ role: string; content: any }> };
127
+ readonly onEvent?: (event: DriverStreamEvent) => void;
128
+ }
129
+
130
+ /** Per-turn token usage and cost breakdown. */
131
+ export interface DriverUsage {
132
+ readonly inputTokens?: number;
133
+ readonly outputTokens?: number;
134
+ readonly cachedReadTokens?: number;
135
+ readonly cachedWriteTokens?: number;
136
+ readonly thoughtTokens?: number;
137
+ readonly totalTokens?: number;
138
+ /** USD cost when the provider reports it (Claude CLI, ACPX). */
139
+ readonly costUsd?: number;
140
+ }
141
+
142
+ /** Result of a completed turn. */
143
+ export interface TurnResult {
144
+ readonly text: string;
145
+ readonly thinking?: string;
146
+ readonly sessionId?: string;
147
+ readonly stopReason?: string;
148
+ readonly usage?: DriverUsage;
149
+ }
150
+
151
+ /**
152
+ * Provider-specific runtime adapter contract — session/turn operations.
153
+ *
154
+ * Adapted from t3code's `ProviderAdapterShape`. Simplified to async
155
+ * functions (no Effect monads). Drivers own session state; the registry
156
+ * owns instance lifecycle.
157
+ */
158
+ export interface ProviderAdapterShape {
159
+ /** Start a new session or resume an existing one. */
160
+ readonly startSession: (opts: SessionStartOptions) => Promise<SessionHandle>;
161
+
162
+ /** Send a turn (prompt) to an active session. */
163
+ readonly sendTurn: (
164
+ handle: SessionHandle,
165
+ prompt: string,
166
+ opts?: TurnOptions,
167
+ ) => Promise<TurnResult>;
168
+
169
+ /** Stop one session. */
170
+ readonly stopSession: (handle: SessionHandle) => Promise<void>;
171
+
172
+ /** Stop all sessions owned by this adapter. */
173
+ readonly stopAll: () => Promise<void>;
174
+
175
+ /** Check whether this adapter owns an active session id. */
176
+ readonly hasSession: (sessionId: string) => boolean;
177
+ }
178
+
179
+ // ---------------------------------------------------------------------------
180
+ // Provider Instance
181
+ // ---------------------------------------------------------------------------
182
+
183
+ /**
184
+ * One materialized provider instance. Held by the registry, looked up by
185
+ * `instanceId`, torn down by calling `dispose()`.
186
+ *
187
+ * The two "shape" fields are captured closures owned by this instance —
188
+ * stopping one instance cannot affect another, and starting a second
189
+ * instance of the same driver does not reach into the first instance's
190
+ * state.
191
+ */
192
+ export interface ProviderInstance {
193
+ readonly instanceId: string;
194
+ readonly driverKind: string;
195
+ readonly displayName?: string;
196
+ readonly enabled: boolean;
197
+ /** Status/models/health — refreshable. */
198
+ readonly snapshot: ProviderSnapshotShape;
199
+ /** Session/turn runtime. */
200
+ readonly adapter: ProviderAdapterShape;
201
+ /** Cleanup — called when instance is torn down. Releases all resources. */
202
+ readonly dispose: () => Promise<void>;
203
+ }
204
+
205
+ // ---------------------------------------------------------------------------
206
+ // Provider Driver Create Input
207
+ // ---------------------------------------------------------------------------
208
+
209
+ /**
210
+ * Inputs the registry passes to a driver's `create` function.
211
+ *
212
+ * `config` is the typed payload — already validated by the registry through
213
+ * `driver.configSchema`. Drivers never validate their own raw envelope.
214
+ */
215
+ export interface ProviderDriverCreateInput<Config> {
216
+ readonly instanceId: string;
217
+ readonly displayName?: string;
218
+ readonly enabled: boolean;
219
+ readonly config: Config;
220
+ readonly cwd: string;
221
+ }
222
+
223
+ // ---------------------------------------------------------------------------
224
+ // Config Schema (validation interface)
225
+ // ---------------------------------------------------------------------------
226
+
227
+ /**
228
+ * Minimal config validation interface. Drivers provide a `parse(unknown)`
229
+ * that either returns a typed config or throws. Works with zod schemas
230
+ * or any hand-rolled validator.
231
+ *
232
+ * ```ts
233
+ * const schema: ConfigSchema<MyConfig> = {
234
+ * parse: (raw) => { ... validate and return MyConfig ... },
235
+ * };
236
+ * ```
237
+ */
238
+ export interface ConfigSchema<Config> {
239
+ /** Decode unknown input into typed Config. Throws on validation failure. */
240
+ readonly parse: (raw: unknown) => Config;
241
+ }
242
+
243
+ // ---------------------------------------------------------------------------
244
+ // Provider Driver SPI
245
+ // ---------------------------------------------------------------------------
246
+
247
+ /**
248
+ * Driver SPI — registered as a plain value, not a class.
249
+ *
250
+ * `Config` is whatever the driver decoded from settings. `create` is
251
+ * responsible for *all* per-instance state — process handles, intervals,
252
+ * file watchers — and must release them when `dispose()` is called on the
253
+ * returned instance. Two calls to `create` with different `instanceId` /
254
+ * `config` MUST yield instances with no shared mutable state.
255
+ */
256
+ export interface ProviderDriver<Config> {
257
+ readonly driverKind: string;
258
+ readonly metadata: ProviderDriverMetadata;
259
+ /**
260
+ * Validator for the opaque config envelope. The registry runs this
261
+ * exactly once per (re)load of an instance; a validation failure is
262
+ * surfaced as `ProviderDriverError` and downgraded to an unavailable
263
+ * shadow snapshot.
264
+ */
265
+ readonly configSchema: ConfigSchema<Config>;
266
+ /**
267
+ * Default config payload used when settings are empty or when the driver
268
+ * is auto-bootstrapped without user configuration.
269
+ */
270
+ readonly defaultConfig: () => Config;
271
+ /**
272
+ * Probe binary/runtime availability + basic status. Called before
273
+ * `create()` — when `available` is false, the registry synthesizes an
274
+ * "unavailable" shadow snapshot.
275
+ */
276
+ readonly probe: (config: Config) => Promise<ProviderProbeResult>;
277
+ /**
278
+ * Materialize one instance. The returned instance owns all per-instance
279
+ * state. Failures throw `ProviderDriverError` — the registry catches
280
+ * them and downgrades to an unavailable shadow snapshot.
281
+ *
282
+ * Two calls to `create` with different `instanceId` / `config` MUST
283
+ * yield instances with no shared mutable state.
284
+ */
285
+ readonly create: (
286
+ input: ProviderDriverCreateInput<Config>,
287
+ ) => Promise<ProviderInstance>;
288
+ }
289
+
290
+ /**
291
+ * Heterogeneous-array convenience: the registry stores drivers as
292
+ * `AnyProviderDriver[]` where the per-driver Config is erased.
293
+ */
294
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
295
+ export type AnyProviderDriver = ProviderDriver<any>;