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.
- package/README.md +808 -0
- package/agents/api-documenter.md +32 -0
- package/agents/bash-expert.md +53 -0
- package/agents/code-reviewer-docs.md +145 -0
- package/agents/code-reviewer-guidelines.md +97 -0
- package/agents/code-reviewer-quality.md +142 -0
- package/agents/code-reviewer-security.md +107 -0
- package/agents/code-reviewer-spec.md +164 -0
- package/agents/debugger.md +63 -0
- package/agents/docker-expert.md +40 -0
- package/agents/docs-fetcher.md +48 -0
- package/agents/git-expert.md +63 -0
- package/agents/github-expert.md +83 -0
- package/agents/go-expert.md +62 -0
- package/agents/issue-reviewer-feasibility.md +60 -0
- package/agents/issue-reviewer-scope.md +63 -0
- package/agents/issue-reviewer-spec.md +77 -0
- package/agents/java-expert.md +31 -0
- package/agents/jenkins-expert.md +38 -0
- package/agents/kubernetes-expert.md +40 -0
- package/agents/planner.md +42 -0
- package/agents/python-expert.md +61 -0
- package/agents/reviewer.md +26 -0
- package/agents/scout.md +40 -0
- package/agents/security-auditor.md +254 -0
- package/agents/technical-documentation-writer.md +37 -0
- package/agents/test-automator.md +55 -0
- package/agents/test-runner.md +47 -0
- package/agents/ts-expert.md +23 -0
- package/agents/worker.md +30 -0
- package/extensions/acpx-provider/index.ts +104 -0
- package/extensions/acpx-provider/load-runtime.ts +99 -0
- package/extensions/acpx-provider/runtime-models.ts +40 -0
- package/extensions/cli-provider/agents/claude.ts +128 -0
- package/extensions/cli-provider/agents/cursor.ts +84 -0
- package/extensions/cli-provider/agents/gemini.ts +100 -0
- package/extensions/cli-provider/discover.ts +77 -0
- package/extensions/cli-provider/index.ts +57 -0
- package/extensions/cli-provider/parsers.ts +304 -0
- package/extensions/cli-provider/providers.ts +58 -0
- package/extensions/cli-provider/runner.ts +225 -0
- package/extensions/cli-provider/runtime-models.ts +32 -0
- package/extensions/cli-provider/session-reaper.ts +122 -0
- package/extensions/cli-provider/sessions.ts +533 -0
- package/extensions/cli-provider/shared/discover-cache.ts +235 -0
- package/extensions/cli-provider/types.ts +48 -0
- package/extensions/coms/coms-net-server.ts +1642 -0
- package/extensions/coms/coms-net-wrapper.ts +521 -0
- package/extensions/coms/coms-net.ts +1589 -0
- package/extensions/coms/coms-p2p.ts +1879 -0
- package/extensions/coms/coms-shared.ts +510 -0
- package/extensions/coms/coms-wrapper.ts +138 -0
- package/extensions/coms/index.ts +20 -0
- package/extensions/coms/themeMap.ts +147 -0
- package/extensions/image-gen/image-gen.ts +332 -0
- package/extensions/image-gen/index.ts +14 -0
- package/extensions/orchestrator/agents.ts +134 -0
- package/extensions/orchestrator/ask-user.ts +293 -0
- package/extensions/orchestrator/async-agents.ts +1037 -0
- package/extensions/orchestrator/async-capability.ts +129 -0
- package/extensions/orchestrator/async-runner.ts +324 -0
- package/extensions/orchestrator/async-status-parse.ts +31 -0
- package/extensions/orchestrator/async-status-ui.ts +201 -0
- package/extensions/orchestrator/async-wait.ts +36 -0
- package/extensions/orchestrator/btw.ts +210 -0
- package/extensions/orchestrator/cron-status-format.ts +126 -0
- package/extensions/orchestrator/cron-status-ui.ts +132 -0
- package/extensions/orchestrator/cron.ts +730 -0
- package/extensions/orchestrator/dreaming.ts +355 -0
- package/extensions/orchestrator/enforcement-helpers.ts +530 -0
- package/extensions/orchestrator/enforcement-rules.ts +329 -0
- package/extensions/orchestrator/enforcement.ts +828 -0
- package/extensions/orchestrator/extended-autocomplete.ts +593 -0
- package/extensions/orchestrator/git-helpers.ts +420 -0
- package/extensions/orchestrator/github-autocomplete.ts +250 -0
- package/extensions/orchestrator/icons.ts +17 -0
- package/extensions/orchestrator/index.ts +100 -0
- package/extensions/orchestrator/memory-embeddings.ts +281 -0
- package/extensions/orchestrator/memory-promotion.ts +449 -0
- package/extensions/orchestrator/memory-provenance.ts +80 -0
- package/extensions/orchestrator/memory-query-class.ts +90 -0
- package/extensions/orchestrator/memory-scoring.ts +434 -0
- package/extensions/orchestrator/memory-tools.ts +883 -0
- package/extensions/orchestrator/memory-tree.ts +212 -0
- package/extensions/orchestrator/nvim.ts +169 -0
- package/extensions/orchestrator/overlay-dashboard-utils.ts +25 -0
- package/extensions/orchestrator/overlay-dashboard.ts +512 -0
- package/extensions/orchestrator/pi-config-review-state.ts +303 -0
- package/extensions/orchestrator/preference-extractor.ts +106 -0
- package/extensions/orchestrator/project-settings.ts +468 -0
- package/extensions/orchestrator/promotion-queue.ts +311 -0
- package/extensions/orchestrator/resolve-agent-model.ts +32 -0
- package/extensions/orchestrator/review-ui.ts +204 -0
- package/extensions/orchestrator/rule-placeholders.ts +12 -0
- package/extensions/orchestrator/rules.ts +481 -0
- package/extensions/orchestrator/session-search.ts +243 -0
- package/extensions/orchestrator/session-validation.ts +374 -0
- package/extensions/orchestrator/situation-report.ts +370 -0
- package/extensions/orchestrator/status-bar.ts +31 -0
- package/extensions/orchestrator/status-line.ts +192 -0
- package/extensions/orchestrator/status.ts +110 -0
- package/extensions/orchestrator/subagent-tool.ts +1748 -0
- package/extensions/orchestrator/task-lifecycle.ts +88 -0
- package/extensions/orchestrator/utils.ts +227 -0
- package/extensions/pidash/index.ts +15 -0
- package/extensions/pidash/pidash.ts +941 -0
- package/extensions/pidiff/index.ts +13 -0
- package/extensions/pidiff/pidiff.ts +369 -0
- package/extensions/providers/acpx-driver.ts +479 -0
- package/extensions/providers/built-in-drivers.ts +52 -0
- package/extensions/providers/claude-driver.ts +319 -0
- package/extensions/providers/cursor-acpx-driver.ts +398 -0
- package/extensions/providers/cursor-cli-driver.ts +484 -0
- package/extensions/providers/gemini-driver.ts +302 -0
- package/extensions/providers/index.ts +513 -0
- package/extensions/shared/build-system-prompt.ts +57 -0
- package/extensions/shared/create-runtime-provider.ts +190 -0
- package/extensions/shared/daemon-manager.ts +248 -0
- package/extensions/shared/file-logger.ts +115 -0
- package/extensions/shared/managed-refresh.ts +211 -0
- package/extensions/shared/provider-driver.ts +295 -0
- package/extensions/shared/provider-errors.ts +305 -0
- package/extensions/shared/provider-registry.ts +388 -0
- package/extensions/shared/stream-builder.ts +275 -0
- package/extensions/shared/types.ts +20 -0
- package/extensions/shared/ui/README.md +10 -0
- package/extensions/shared/ui/badge.tsx +52 -0
- package/extensions/shared/ui/button.tsx +58 -0
- package/extensions/shared/ui/collapsible.tsx +21 -0
- package/extensions/shared/ui/dropdown-menu.tsx +266 -0
- package/extensions/shared/ui/input.tsx +20 -0
- package/extensions/shared/ui/popover.tsx +114 -0
- package/extensions/shared/ui/resizable.tsx +48 -0
- package/extensions/shared/ui/scroll-area.tsx +53 -0
- package/extensions/shared/ui/select.tsx +201 -0
- package/extensions/shared/ui/separator.tsx +25 -0
- package/extensions/shared/ui/tooltip.tsx +64 -0
- package/extensions/shared/ws-client.ts +74 -0
- package/package.json +59 -0
- package/prompts/coderabbit-rate-limit.md +95 -0
- package/prompts/create-coms-feature-manager.md +186 -0
- package/prompts/create-skill.md +128 -0
- package/prompts/domain-model.md +109 -0
- package/prompts/external-ai.md +665 -0
- package/prompts/implement-and-review.md +25 -0
- package/prompts/implement.md +26 -0
- package/prompts/issue-review.md +256 -0
- package/prompts/pr-review.md +753 -0
- package/prompts/query-db.md +154 -0
- package/prompts/refine-review.md +208 -0
- package/prompts/release.md +235 -0
- package/prompts/remember.md +33 -0
- package/prompts/review-handler-status.md +27 -0
- package/prompts/review-handler.md +677 -0
- package/prompts/review-local.md +159 -0
- package/prompts/scout-and-plan.md +21 -0
- package/rules/00-orchestrator-core.md +42 -0
- package/rules/05-issue-first-workflow.md +119 -0
- package/rules/10-agent-routing.md +58 -0
- package/rules/15-mcp-launchpad.md +46 -0
- package/rules/20-code-review-loop.md +234 -0
- package/rules/25-documentation-updates.md +15 -0
- package/rules/30-prompt-templates.md +19 -0
- package/rules/35-memory.md +240 -0
- package/rules/40-critical-rules.md +124 -0
- package/rules/45-file-preview.md +29 -0
- package/rules/50-agent-bug-reporting.md +90 -0
- package/rules/55-coms-protocol.md +63 -0
- package/rules/60-task-tracking.md +66 -0
- package/skills/conflict-resolver/SKILL.md +213 -0
- package/skills/skill-creator/SKILL.md +85 -0
- package/skills/systematic-debugging/SKILL.md +353 -0
- package/skills/test-driven-development/SKILL.md +335 -0
- package/skills/update-agents-md/SKILL.md +282 -0
- package/templates/coms-feature-manager-prompt.md +313 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CursorAcpxDriver — ProviderDriver for the Cursor Agent via ACP runtime.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the acpx runtime for ACP-based session management. Owns
|
|
5
|
+
* ensureHandle, model discovery via runtime.getStatus, and event
|
|
6
|
+
* stream from turn.events.
|
|
7
|
+
*
|
|
8
|
+
* Reuses existing modules:
|
|
9
|
+
* - acpx-provider/load-runtime.ts — dynamic acpx import
|
|
10
|
+
* - shared/build-system-prompt.ts — system prompt injection
|
|
11
|
+
*
|
|
12
|
+
* @module providers/cursor-acpx-driver
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
16
|
+
import path from "node:path";
|
|
17
|
+
import os from "node:os";
|
|
18
|
+
import { rm } from "node:fs/promises";
|
|
19
|
+
import type {
|
|
20
|
+
ConfigSchema,
|
|
21
|
+
DiscoveredModel,
|
|
22
|
+
ProviderAdapterShape,
|
|
23
|
+
ProviderDriver,
|
|
24
|
+
ProviderDriverCreateInput,
|
|
25
|
+
ProviderInstance,
|
|
26
|
+
ProviderProbeResult,
|
|
27
|
+
SessionHandle,
|
|
28
|
+
SessionStartOptions,
|
|
29
|
+
TurnOptions,
|
|
30
|
+
TurnResult,
|
|
31
|
+
} from "../shared/provider-driver.js";
|
|
32
|
+
import { ProviderDriverError } from "../shared/provider-errors.js";
|
|
33
|
+
import { makeManagedSnapshot, buildInitialSnapshot } from "../shared/managed-refresh.js";
|
|
34
|
+
import { loadAcpxRuntime, type AcpxRuntimeModule } from "../acpx-provider/load-runtime.js";
|
|
35
|
+
import { modelIdToDisplayName } from "../acpx-provider/runtime-models.js";
|
|
36
|
+
import { buildExternalSystemPrompt } from "../shared/build-system-prompt.js";
|
|
37
|
+
import { fileLog } from "../shared/file-logger.js";
|
|
38
|
+
|
|
39
|
+
const LOG_DOMAIN = "cursor-acpx-driver";
|
|
40
|
+
const DRIVER_KIND = "cursor-acpx";
|
|
41
|
+
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
// Config
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
|
|
46
|
+
export interface CursorAcpxConfig {
|
|
47
|
+
readonly agent: string;
|
|
48
|
+
readonly enabled: boolean;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const cursorAcpxConfigSchema: ConfigSchema<CursorAcpxConfig> = {
|
|
52
|
+
parse: (raw: unknown): CursorAcpxConfig => {
|
|
53
|
+
if (!raw || typeof raw !== "object") {
|
|
54
|
+
return { agent: "cursor", enabled: true };
|
|
55
|
+
}
|
|
56
|
+
const obj = raw as Record<string, unknown>;
|
|
57
|
+
return {
|
|
58
|
+
agent: typeof obj.agent === "string" ? obj.agent : "cursor",
|
|
59
|
+
enabled: typeof obj.enabled === "boolean" ? obj.enabled : true,
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Runtime types
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
|
|
68
|
+
type AcpxRuntime = ReturnType<AcpxRuntimeModule["createAcpRuntime"]>;
|
|
69
|
+
type AcpRuntimeHandle = Awaited<ReturnType<AcpxRuntime["ensureSession"]>>;
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Adapter
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
function createCursorAcpxAdapter(
|
|
76
|
+
config: CursorAcpxConfig,
|
|
77
|
+
cwd: string,
|
|
78
|
+
runtime: AcpxRuntime,
|
|
79
|
+
cwdSlug: string,
|
|
80
|
+
): ProviderAdapterShape {
|
|
81
|
+
const handles = new Map<string, AcpRuntimeHandle>();
|
|
82
|
+
const pendingHandles = new Map<string, Promise<AcpRuntimeHandle>>();
|
|
83
|
+
const systemPromptSent = new Set<string>();
|
|
84
|
+
|
|
85
|
+
function sessionKey(modelId?: string): string {
|
|
86
|
+
const model = modelId && modelId !== "default"
|
|
87
|
+
? `-${modelId.replace(/[^a-zA-Z0-9.-]/g, "_")}`
|
|
88
|
+
: "";
|
|
89
|
+
return `pi-${config.agent}${model}-${cwdSlug}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function ensureHandle(
|
|
93
|
+
acpxModelId: string | undefined,
|
|
94
|
+
systemPrompt?: string,
|
|
95
|
+
): Promise<AcpRuntimeHandle> {
|
|
96
|
+
const key = acpxModelId || "default";
|
|
97
|
+
|
|
98
|
+
const existing = handles.get(key);
|
|
99
|
+
if (existing) return existing;
|
|
100
|
+
|
|
101
|
+
const pending = pendingHandles.get(key);
|
|
102
|
+
if (pending) return pending;
|
|
103
|
+
|
|
104
|
+
const promise = (async () => {
|
|
105
|
+
try {
|
|
106
|
+
const sessionOpts: { model?: string; systemPrompt?: string } = {};
|
|
107
|
+
if (acpxModelId && acpxModelId !== "default") {
|
|
108
|
+
sessionOpts.model = acpxModelId;
|
|
109
|
+
}
|
|
110
|
+
if (systemPrompt) {
|
|
111
|
+
sessionOpts.systemPrompt = systemPrompt;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const handle = await runtime.ensureSession({
|
|
115
|
+
sessionKey: sessionKey(acpxModelId),
|
|
116
|
+
agent: config.agent,
|
|
117
|
+
mode: "persistent",
|
|
118
|
+
cwd,
|
|
119
|
+
...(Object.keys(sessionOpts).length > 0
|
|
120
|
+
? { sessionOptions: sessionOpts }
|
|
121
|
+
: {}),
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
handles.set(key, handle);
|
|
125
|
+
return handle;
|
|
126
|
+
} finally {
|
|
127
|
+
pendingHandles.delete(key);
|
|
128
|
+
}
|
|
129
|
+
})();
|
|
130
|
+
|
|
131
|
+
pendingHandles.set(key, promise);
|
|
132
|
+
return promise;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
startSession: async (opts: SessionStartOptions): Promise<SessionHandle> => {
|
|
137
|
+
const model = opts.model || "default";
|
|
138
|
+
const systemPrompt = opts.systemPrompt
|
|
139
|
+
? opts.systemPrompt
|
|
140
|
+
: buildExternalSystemPrompt({ systemPrompt: undefined }, cwd);
|
|
141
|
+
const handle = await ensureHandle(model, systemPrompt);
|
|
142
|
+
return {
|
|
143
|
+
sessionId: sessionKey(model),
|
|
144
|
+
model,
|
|
145
|
+
};
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
sendTurn: async (
|
|
149
|
+
handle: SessionHandle,
|
|
150
|
+
prompt: string,
|
|
151
|
+
opts?: TurnOptions,
|
|
152
|
+
): Promise<TurnResult> => {
|
|
153
|
+
const handleKey = handle.model || "default";
|
|
154
|
+
const needsSystemPrompt = !systemPromptSent.has(handleKey);
|
|
155
|
+
const systemPrompt = needsSystemPrompt
|
|
156
|
+
? buildExternalSystemPrompt({ systemPrompt: undefined }, cwd)
|
|
157
|
+
: undefined;
|
|
158
|
+
|
|
159
|
+
const acpxHandle = await ensureHandle(handle.model, systemPrompt);
|
|
160
|
+
if (needsSystemPrompt) {
|
|
161
|
+
systemPromptSent.add(handleKey);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const abortController = new AbortController();
|
|
165
|
+
if (opts?.signal) {
|
|
166
|
+
if (opts.signal.aborted) {
|
|
167
|
+
abortController.abort();
|
|
168
|
+
} else {
|
|
169
|
+
opts.signal.addEventListener("abort", () => abortController.abort(), { once: true });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const turn = runtime.startTurn({
|
|
174
|
+
handle: acpxHandle,
|
|
175
|
+
text: prompt,
|
|
176
|
+
mode: "prompt",
|
|
177
|
+
requestId: `pi-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
178
|
+
signal: abortController.signal,
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
let text = "";
|
|
182
|
+
let thinking = "";
|
|
183
|
+
|
|
184
|
+
for await (const event of turn.events) {
|
|
185
|
+
if (abortController.signal.aborted) break;
|
|
186
|
+
|
|
187
|
+
if (event.type === "text_delta" && event.text) {
|
|
188
|
+
if (event.stream === "thought") {
|
|
189
|
+
thinking += event.text;
|
|
190
|
+
opts?.onEvent?.({ kind: "thinking_delta", text: event.text });
|
|
191
|
+
} else {
|
|
192
|
+
text += event.text;
|
|
193
|
+
opts?.onEvent?.({ kind: "text_delta", text: event.text });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const result = await turn.result;
|
|
199
|
+
let stopReason = "stop";
|
|
200
|
+
if (result.status === "completed") {
|
|
201
|
+
stopReason = result.stopReason === "end_turn" ? "stop" : (result.stopReason || "stop");
|
|
202
|
+
} else if (result.status === "failed") {
|
|
203
|
+
throw new Error(`acpx turn failed: ${result.error.message}`);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return { text, thinking: thinking || undefined, stopReason };
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
stopSession: async (handle: SessionHandle): Promise<void> => {
|
|
210
|
+
const key = handle.model || "default";
|
|
211
|
+
const acpxHandle = handles.get(key);
|
|
212
|
+
if (acpxHandle) {
|
|
213
|
+
await runtime.close({ handle: acpxHandle, reason: "session stop" }).catch((err: unknown) => {
|
|
214
|
+
fileLog(LOG_DOMAIN, "warn", LOG_DOMAIN,
|
|
215
|
+
`session close failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
216
|
+
});
|
|
217
|
+
handles.delete(key);
|
|
218
|
+
}
|
|
219
|
+
systemPromptSent.delete(key);
|
|
220
|
+
},
|
|
221
|
+
|
|
222
|
+
stopAll: async (): Promise<void> => {
|
|
223
|
+
const closePromises: Promise<void>[] = [];
|
|
224
|
+
for (const [key, acpxHandle] of handles) {
|
|
225
|
+
closePromises.push(
|
|
226
|
+
runtime.close({ handle: acpxHandle, reason: "stop all" }).catch((err: unknown) => {
|
|
227
|
+
fileLog(LOG_DOMAIN, "warn", LOG_DOMAIN,
|
|
228
|
+
`session close failed for ${key}: ${err instanceof Error ? err.message : String(err)}`);
|
|
229
|
+
}),
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
await Promise.allSettled(closePromises);
|
|
233
|
+
handles.clear();
|
|
234
|
+
pendingHandles.clear();
|
|
235
|
+
systemPromptSent.clear();
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
hasSession: (sessionId: string): boolean => {
|
|
239
|
+
for (const key of handles.keys()) {
|
|
240
|
+
if (sessionKey(key === "default" ? undefined : key) === sessionId) {
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return false;
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ---------------------------------------------------------------------------
|
|
250
|
+
// Discovery helper
|
|
251
|
+
// ---------------------------------------------------------------------------
|
|
252
|
+
|
|
253
|
+
async function discoverAcpxModelsInternal(
|
|
254
|
+
agent: string,
|
|
255
|
+
cwd: string,
|
|
256
|
+
): Promise<string[]> {
|
|
257
|
+
const { createAcpRuntime, createFileSessionStore, createAgentRegistry } =
|
|
258
|
+
await loadAcpxRuntime();
|
|
259
|
+
|
|
260
|
+
const uid = randomUUID().slice(0, 8);
|
|
261
|
+
const stateDir = path.join(os.homedir(), ".acpx", `discover-${process.pid}-${uid}`);
|
|
262
|
+
const runtime = createAcpRuntime({
|
|
263
|
+
cwd,
|
|
264
|
+
sessionStore: createFileSessionStore({ stateDir }),
|
|
265
|
+
agentRegistry: createAgentRegistry(),
|
|
266
|
+
permissionMode: "deny-all",
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
let handle: AcpRuntimeHandle | undefined;
|
|
270
|
+
try {
|
|
271
|
+
handle = await runtime.ensureSession({
|
|
272
|
+
sessionKey: `discover-${agent}-${uid}`,
|
|
273
|
+
agent,
|
|
274
|
+
mode: "oneshot",
|
|
275
|
+
cwd,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const status = await runtime.getStatus({ handle });
|
|
279
|
+
return status.models?.availableModelIds || [];
|
|
280
|
+
} catch (err) {
|
|
281
|
+
fileLog(LOG_DOMAIN, "warn", LOG_DOMAIN,
|
|
282
|
+
`model discovery failed for ${agent}: ${err instanceof Error ? err.message : String(err)}`);
|
|
283
|
+
return [];
|
|
284
|
+
} finally {
|
|
285
|
+
if (handle) {
|
|
286
|
+
await runtime.close({ handle, reason: "discovery complete" }).catch(() => {});
|
|
287
|
+
}
|
|
288
|
+
await rm(stateDir, { recursive: true, force: true }).catch(() => {});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// ---------------------------------------------------------------------------
|
|
293
|
+
// Driver
|
|
294
|
+
// ---------------------------------------------------------------------------
|
|
295
|
+
|
|
296
|
+
export const CursorAcpxDriver: ProviderDriver<CursorAcpxConfig> = {
|
|
297
|
+
driverKind: DRIVER_KIND,
|
|
298
|
+
metadata: {
|
|
299
|
+
displayName: "Cursor ACPX",
|
|
300
|
+
supportsMultipleInstances: false,
|
|
301
|
+
},
|
|
302
|
+
configSchema: cursorAcpxConfigSchema,
|
|
303
|
+
defaultConfig: () => ({ agent: "cursor", enabled: true }),
|
|
304
|
+
|
|
305
|
+
probe: async (_config: CursorAcpxConfig): Promise<ProviderProbeResult> => {
|
|
306
|
+
try {
|
|
307
|
+
await loadAcpxRuntime();
|
|
308
|
+
return { available: true };
|
|
309
|
+
} catch (err) {
|
|
310
|
+
return {
|
|
311
|
+
available: false,
|
|
312
|
+
reason: `acpx runtime not available: ${err instanceof Error ? err.message : String(err)}`,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
create: async (
|
|
318
|
+
input: ProviderDriverCreateInput<CursorAcpxConfig>,
|
|
319
|
+
): Promise<ProviderInstance> => {
|
|
320
|
+
const { instanceId, config, cwd } = input;
|
|
321
|
+
const cwdSlug = createHash("sha256").update(cwd).digest("hex").slice(0, 12);
|
|
322
|
+
|
|
323
|
+
// Load runtime
|
|
324
|
+
const { createAcpRuntime, createFileSessionStore, createAgentRegistry } =
|
|
325
|
+
await loadAcpxRuntime();
|
|
326
|
+
|
|
327
|
+
const stateDir = path.join(os.homedir(), ".acpx", `pi-${cwdSlug}`);
|
|
328
|
+
const runtime = createAcpRuntime({
|
|
329
|
+
cwd,
|
|
330
|
+
sessionStore: createFileSessionStore({ stateDir }),
|
|
331
|
+
agentRegistry: createAgentRegistry(),
|
|
332
|
+
permissionMode: "approve-all",
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
// Discover models
|
|
336
|
+
let discoveredModelIds: string[] = [];
|
|
337
|
+
try {
|
|
338
|
+
// Use the runtime's own status to discover models
|
|
339
|
+
const tmpHandle = await runtime.ensureSession({
|
|
340
|
+
sessionKey: `discover-${config.agent}-init`,
|
|
341
|
+
agent: config.agent,
|
|
342
|
+
mode: "oneshot",
|
|
343
|
+
cwd,
|
|
344
|
+
});
|
|
345
|
+
const status = await runtime.getStatus({ handle: tmpHandle });
|
|
346
|
+
discoveredModelIds = status.models?.availableModelIds || [];
|
|
347
|
+
await runtime.close({ handle: tmpHandle, reason: "initial discovery" }).catch(() => {});
|
|
348
|
+
} catch (err) {
|
|
349
|
+
fileLog(LOG_DOMAIN, "warn", LOG_DOMAIN,
|
|
350
|
+
`initial model discovery failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const discoveredModels: DiscoveredModel[] = discoveredModelIds.map((id) => ({
|
|
354
|
+
id,
|
|
355
|
+
name: modelIdToDisplayName(id),
|
|
356
|
+
}));
|
|
357
|
+
|
|
358
|
+
// Managed snapshot with periodic refresh
|
|
359
|
+
const managed = makeManagedSnapshot({
|
|
360
|
+
initialSnapshot: () => buildInitialSnapshot(true, discoveredModels),
|
|
361
|
+
checkProvider: async () => {
|
|
362
|
+
try {
|
|
363
|
+
const modelIds = await discoverAcpxModelsInternal(config.agent, cwd);
|
|
364
|
+
const models = modelIds.map((id) => ({
|
|
365
|
+
id,
|
|
366
|
+
name: modelIdToDisplayName(id),
|
|
367
|
+
}));
|
|
368
|
+
return buildInitialSnapshot(true, models);
|
|
369
|
+
} catch {
|
|
370
|
+
return buildInitialSnapshot(true, discoveredModels);
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
getSettings: () => config,
|
|
374
|
+
haveSettingsChanged: (prev, next) =>
|
|
375
|
+
prev.agent !== next.agent || prev.enabled !== next.enabled,
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// Create adapter
|
|
379
|
+
const adapter = createCursorAcpxAdapter(config, cwd, runtime, cwdSlug);
|
|
380
|
+
|
|
381
|
+
return {
|
|
382
|
+
instanceId,
|
|
383
|
+
driverKind: DRIVER_KIND,
|
|
384
|
+
displayName: input.displayName || `ACPX ${config.agent}`,
|
|
385
|
+
enabled: input.enabled,
|
|
386
|
+
snapshot: {
|
|
387
|
+
getSnapshot: managed.getSnapshot,
|
|
388
|
+
refresh: managed.refresh,
|
|
389
|
+
dispose: managed.dispose,
|
|
390
|
+
},
|
|
391
|
+
adapter,
|
|
392
|
+
dispose: async () => {
|
|
393
|
+
managed.dispose();
|
|
394
|
+
await adapter.stopAll();
|
|
395
|
+
},
|
|
396
|
+
};
|
|
397
|
+
},
|
|
398
|
+
};
|