@bastani/atomic 0.8.28 → 0.8.29-alpha.3

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 (145) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/builtin/cursor/CHANGELOG.md +27 -0
  3. package/dist/builtin/cursor/LICENSE +26 -0
  4. package/dist/builtin/cursor/README.md +22 -0
  5. package/dist/builtin/cursor/index.ts +9 -0
  6. package/dist/builtin/cursor/package.json +46 -0
  7. package/dist/builtin/cursor/src/auth.ts +352 -0
  8. package/dist/builtin/cursor/src/catalog-cache.ts +155 -0
  9. package/dist/builtin/cursor/src/config.ts +123 -0
  10. package/dist/builtin/cursor/src/conversation-state.ts +135 -0
  11. package/dist/builtin/cursor/src/cursor-models-raw.json +583 -0
  12. package/dist/builtin/cursor/src/model-mapper.ts +270 -0
  13. package/dist/builtin/cursor/src/models.ts +54 -0
  14. package/dist/builtin/cursor/src/native-loader.ts +71 -0
  15. package/dist/builtin/cursor/src/proto/README.md +34 -0
  16. package/dist/builtin/cursor/src/proto/agent_pb.ts +15294 -0
  17. package/dist/builtin/cursor/src/proto/protobuf-codec.ts +717 -0
  18. package/dist/builtin/cursor/src/provider.ts +301 -0
  19. package/dist/builtin/cursor/src/stream.ts +564 -0
  20. package/dist/builtin/cursor/src/transport.ts +791 -0
  21. package/dist/builtin/intercom/CHANGELOG.md +4 -0
  22. package/dist/builtin/intercom/package.json +2 -2
  23. package/dist/builtin/intercom/skills/intercom/SKILL.md +5 -5
  24. package/dist/builtin/mcp/CHANGELOG.md +4 -0
  25. package/dist/builtin/mcp/package.json +3 -3
  26. package/dist/builtin/subagents/CHANGELOG.md +13 -0
  27. package/dist/builtin/subagents/README.md +7 -3
  28. package/dist/builtin/subagents/agents/codebase-online-researcher.md +9 -24
  29. package/dist/builtin/subagents/agents/debugger.md +3 -5
  30. package/dist/builtin/subagents/package.json +4 -4
  31. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +2 -1
  32. package/dist/builtin/subagents/src/runs/foreground/execution.ts +2 -1
  33. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +1 -0
  34. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +19 -2
  35. package/dist/builtin/subagents/src/runs/shared/structured-output.ts +271 -10
  36. package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +12 -39
  37. package/dist/builtin/subagents/src/shared/types.ts +5 -3
  38. package/dist/builtin/subagents/src/shared/utils.ts +50 -10
  39. package/dist/builtin/subagents/src/slash/saved-chain-mapping.ts +77 -0
  40. package/dist/builtin/subagents/src/slash/slash-commands.ts +1 -55
  41. package/dist/builtin/web-access/CHANGELOG.md +5 -1
  42. package/dist/builtin/web-access/README.md +1 -1
  43. package/dist/builtin/web-access/github-extract.ts +1 -1
  44. package/dist/builtin/web-access/package.json +3 -3
  45. package/dist/builtin/workflows/CHANGELOG.md +26 -0
  46. package/dist/builtin/workflows/README.md +28 -8
  47. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +9 -49
  48. package/dist/builtin/workflows/builtin/goal.ts +63 -106
  49. package/dist/builtin/workflows/builtin/index.d.ts +2 -0
  50. package/dist/builtin/workflows/builtin/open-claude-design.ts +31 -76
  51. package/dist/builtin/workflows/builtin/ralph.d.ts +2 -0
  52. package/dist/builtin/workflows/builtin/ralph.ts +227 -518
  53. package/dist/builtin/workflows/builtin/shared-prompts.ts +7 -0
  54. package/dist/builtin/workflows/package.json +2 -2
  55. package/dist/builtin/workflows/skills/research-codebase/SKILL.md +17 -3
  56. package/dist/builtin/workflows/src/extension/wiring.ts +72 -9
  57. package/dist/builtin/workflows/src/extension/workflow-schema.ts +34 -0
  58. package/dist/builtin/workflows/src/runs/foreground/executor.ts +13 -2
  59. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +86 -14
  60. package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +11 -3
  61. package/dist/builtin/workflows/src/shared/types.ts +8 -4
  62. package/dist/builtin/workflows/src/tui/overlay-adapter.ts +64 -2
  63. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +8 -8
  64. package/dist/builtin/workflows/src/tui/workflow-status.ts +2 -0
  65. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  66. package/dist/core/atomic-guide-command.js +7 -7
  67. package/dist/core/atomic-guide-command.js.map +1 -1
  68. package/dist/core/builtin-packages.d.ts.map +1 -1
  69. package/dist/core/builtin-packages.js +6 -0
  70. package/dist/core/builtin-packages.js.map +1 -1
  71. package/dist/core/extensions/index.d.ts +1 -1
  72. package/dist/core/extensions/index.d.ts.map +1 -1
  73. package/dist/core/extensions/index.js.map +1 -1
  74. package/dist/core/extensions/types.d.ts +20 -0
  75. package/dist/core/extensions/types.d.ts.map +1 -1
  76. package/dist/core/extensions/types.js.map +1 -1
  77. package/dist/core/model-resolver.d.ts +1 -0
  78. package/dist/core/model-resolver.d.ts.map +1 -1
  79. package/dist/core/model-resolver.js +17 -8
  80. package/dist/core/model-resolver.js.map +1 -1
  81. package/dist/core/package-manager.d.ts +11 -9
  82. package/dist/core/package-manager.d.ts.map +1 -1
  83. package/dist/core/package-manager.js +55 -10
  84. package/dist/core/package-manager.js.map +1 -1
  85. package/dist/core/project-trust.d.ts +1 -0
  86. package/dist/core/project-trust.d.ts.map +1 -1
  87. package/dist/core/project-trust.js +3 -3
  88. package/dist/core/project-trust.js.map +1 -1
  89. package/dist/core/resource-loader.d.ts +11 -2
  90. package/dist/core/resource-loader.d.ts.map +1 -1
  91. package/dist/core/resource-loader.js +72 -9
  92. package/dist/core/resource-loader.js.map +1 -1
  93. package/dist/core/sdk.d.ts +3 -3
  94. package/dist/core/sdk.d.ts.map +1 -1
  95. package/dist/core/sdk.js +5 -5
  96. package/dist/core/sdk.js.map +1 -1
  97. package/dist/core/tools/index.d.ts +1 -0
  98. package/dist/core/tools/index.d.ts.map +1 -1
  99. package/dist/core/tools/index.js +1 -0
  100. package/dist/core/tools/index.js.map +1 -1
  101. package/dist/core/tools/structured-output.d.ts +39 -0
  102. package/dist/core/tools/structured-output.d.ts.map +1 -0
  103. package/dist/core/tools/structured-output.js +141 -0
  104. package/dist/core/tools/structured-output.js.map +1 -0
  105. package/dist/index.d.ts +1 -1
  106. package/dist/index.d.ts.map +1 -1
  107. package/dist/index.js +1 -1
  108. package/dist/index.js.map +1 -1
  109. package/dist/main.d.ts.map +1 -1
  110. package/dist/main.js +36 -14
  111. package/dist/main.js.map +1 -1
  112. package/dist/modes/interactive/components/login-dialog.d.ts +3 -0
  113. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  114. package/dist/modes/interactive/components/login-dialog.js +16 -0
  115. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  116. package/dist/modes/interactive/interactive-mode.d.ts +11 -0
  117. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  118. package/dist/modes/interactive/interactive-mode.js +158 -11
  119. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  120. package/dist/modes/print-mode.d.ts.map +1 -1
  121. package/dist/modes/print-mode.js +39 -0
  122. package/dist/modes/print-mode.js.map +1 -1
  123. package/docs/custom-provider.md +1 -0
  124. package/docs/extensions.md +2 -2
  125. package/docs/models.md +2 -0
  126. package/docs/packages.md +3 -1
  127. package/docs/providers.md +15 -0
  128. package/docs/quickstart.md +3 -3
  129. package/docs/sdk.md +61 -0
  130. package/docs/security.md +1 -1
  131. package/docs/subagents.md +21 -0
  132. package/docs/usage.md +2 -0
  133. package/docs/workflows.md +28 -21
  134. package/examples/extensions/README.md +1 -1
  135. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  136. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  137. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  138. package/examples/extensions/gondolin/package-lock.json +2 -2
  139. package/examples/extensions/gondolin/package.json +1 -1
  140. package/examples/extensions/sandbox/package-lock.json +2 -2
  141. package/examples/extensions/sandbox/package.json +1 -1
  142. package/examples/extensions/structured-output.ts +22 -53
  143. package/examples/extensions/with-deps/package-lock.json +2 -2
  144. package/examples/extensions/with-deps/package.json +1 -1
  145. package/package.json +12 -9
@@ -0,0 +1,301 @@
1
+ import { randomUUID as nodeRandomUUID } from "node:crypto";
2
+ import type {
3
+ Api,
4
+ AssistantMessageEventStream,
5
+ Context,
6
+ Model,
7
+ OAuthCredentials,
8
+ OAuthLoginCallbacks,
9
+ SimpleStreamOptions,
10
+ } from "@earendil-works/pi-ai";
11
+ import {
12
+ CURSOR_API,
13
+ CURSOR_API_BASE_URL,
14
+ CURSOR_LOGIN_NAME,
15
+ CURSOR_PROVIDER_ID,
16
+ CURSOR_PROVIDER_NAME,
17
+ } from "./config.js";
18
+ import { CursorAuthService } from "./auth.js";
19
+ import { FileCursorCatalogCache, type CursorCatalogCache } from "./catalog-cache.js";
20
+ import { CursorConversationStateStore } from "./conversation-state.js";
21
+ import { CursorModelDiscoveryService } from "./models.js";
22
+ import {
23
+ createEstimatedCursorCatalog,
24
+ mapCursorCatalogToProviderModels,
25
+ type CursorModelCatalog,
26
+ type CursorProviderModelDefinition,
27
+ } from "./model-mapper.js";
28
+ import { CursorStreamAdapter } from "./stream.js";
29
+ import { Http2CursorAgentTransport, type CursorAgentTransport } from "./transport.js";
30
+
31
+ const DEFAULT_CATALOG_DISCOVERY_DISPOSE_TIMEOUT_MS = 1_000;
32
+
33
+ export interface CursorProviderOAuthConfig {
34
+ readonly name: string;
35
+ login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials>;
36
+ refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials>;
37
+ getApiKey(credentials: OAuthCredentials): string;
38
+ }
39
+
40
+ export interface CursorProviderConfig {
41
+ readonly name: string;
42
+ readonly baseUrl: string;
43
+ readonly api: string;
44
+ readonly models: readonly CursorProviderModelDefinition[];
45
+ readonly oauth: CursorProviderOAuthConfig;
46
+ readonly streamSimple: (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => AssistantMessageEventStream;
47
+ }
48
+
49
+ export type CursorSessionLifecycleEvent = "session_before_switch" | "session_before_fork" | "session_before_tree" | "session_shutdown";
50
+ export type CursorProviderEvent = "session_start" | CursorSessionLifecycleEvent;
51
+
52
+ export interface CursorProviderContext {
53
+ readonly sessionManager?: {
54
+ getSessionId?(): string;
55
+ };
56
+ readonly modelRegistry?: {
57
+ getApiKeyForProvider?(provider: string): Promise<string | undefined> | string | undefined;
58
+ };
59
+ }
60
+
61
+ export interface CursorProviderHost {
62
+ registerProvider(name: string, config: CursorProviderConfig): void;
63
+ on(event: CursorProviderEvent, handler: (event?: unknown, context?: CursorProviderContext) => Promise<void> | void): void;
64
+ }
65
+
66
+ export interface CursorProviderRegistrationOptions {
67
+ readonly transport?: CursorAgentTransport;
68
+ readonly authService?: CursorAuthService;
69
+ readonly discoveryService?: CursorModelDiscoveryService;
70
+ readonly streamAdapter?: CursorStreamAdapter;
71
+ readonly catalogCache?: CursorCatalogCache;
72
+ readonly catalogDiscoveryDisposeTimeoutMs?: number;
73
+ readonly uuid?: () => string;
74
+ }
75
+
76
+ export interface CursorProviderRuntime {
77
+ readonly transport: CursorAgentTransport;
78
+ readonly authService: CursorAuthService;
79
+ readonly discoveryService: CursorModelDiscoveryService;
80
+ readonly streamAdapter: CursorStreamAdapter;
81
+ readonly catalogCache: CursorCatalogCache;
82
+ dispose(): Promise<void>;
83
+ }
84
+
85
+ function defaultCursorUuid(): string {
86
+ return nodeRandomUUID();
87
+ }
88
+
89
+ export function registerCursorProvider(pi: CursorProviderHost, options: CursorProviderRegistrationOptions = {}): CursorProviderRuntime {
90
+ const transport = options.transport ?? new Http2CursorAgentTransport();
91
+ const uuid = options.uuid ?? defaultCursorUuid;
92
+ const authService = options.authService ?? new CursorAuthService({ uuid });
93
+ const discoveryService = options.discoveryService ?? new CursorModelDiscoveryService({ transport });
94
+ const catalogCache = options.catalogCache ?? new FileCursorCatalogCache();
95
+ const catalogDiscoveryDisposeTimeoutMs = options.catalogDiscoveryDisposeTimeoutMs ?? DEFAULT_CATALOG_DISCOVERY_DISPOSE_TIMEOUT_MS;
96
+ const streamAdapter = options.streamAdapter ?? new CursorStreamAdapter({
97
+ transport,
98
+ conversationState: new CursorConversationStateStore(),
99
+ uuid,
100
+ });
101
+ const catalogDiscoveryTasks = new Set<Promise<boolean>>();
102
+ const catalogDiscoveryAbortControllers = new Set<AbortController>();
103
+ const catalogDiscoveryTokens = new Set<string>();
104
+ const catalogDiscoveryInFlightTokens = new Map<string, Promise<boolean>>();
105
+ let firstUseRediscoveryTask: Promise<boolean> | undefined;
106
+ let disposed = false;
107
+ let disposePromise: Promise<void> | undefined;
108
+
109
+ const loadCachedLiveCatalog = (): CursorModelCatalog | null => {
110
+ try {
111
+ return catalogCache.load();
112
+ } catch {
113
+ return null;
114
+ }
115
+ };
116
+
117
+ const saveLiveCatalog = (catalog: CursorModelCatalog): boolean => {
118
+ try {
119
+ catalogCache.save(catalog);
120
+ return true;
121
+ } catch {
122
+ // Cache writes are best-effort and must never make auth/model use fail.
123
+ return false;
124
+ }
125
+ };
126
+
127
+ const registerCatalog = (catalogModels: readonly CursorProviderModelDefinition[]): void => {
128
+ pi.registerProvider(CURSOR_PROVIDER_ID, {
129
+ name: CURSOR_PROVIDER_NAME,
130
+ baseUrl: CURSOR_API_BASE_URL,
131
+ api: CURSOR_API,
132
+ models: catalogModels,
133
+ oauth: {
134
+ name: CURSOR_LOGIN_NAME,
135
+ async login(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {
136
+ const credentials = await authService.login(callbacks);
137
+ await registerLiveCatalogBestEffort(credentials.access, uuid(), callbacks.signal);
138
+ return credentials;
139
+ },
140
+ async refreshToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {
141
+ const refreshed = await authService.refreshToken(credentials);
142
+ scheduleTrackedCatalogDiscovery(refreshed.access);
143
+ return refreshed;
144
+ },
145
+ getApiKey(credentials: OAuthCredentials): string {
146
+ return credentials.access;
147
+ },
148
+ },
149
+ streamSimple(model: Model<Api>, context: Context, streamOptions?: SimpleStreamOptions): AssistantMessageEventStream {
150
+ scheduleFirstUseRediscovery(streamOptions?.apiKey);
151
+ return streamAdapter.streamSimple(model, context, streamOptions);
152
+ },
153
+ });
154
+ };
155
+
156
+ const registerLiveCatalog = (catalog: CursorModelCatalog): boolean => {
157
+ if (disposed) return false;
158
+ if (!saveLiveCatalog(catalog)) return false;
159
+ registerCatalog(mapCursorCatalogToProviderModels(catalog));
160
+ return true;
161
+ };
162
+
163
+ const discoverAndRegisterLiveCatalog = async (accessToken: string, requestId: string, signal: AbortSignal | undefined): Promise<boolean> => {
164
+ const liveCatalog = await discoveryService.discover(accessToken, requestId, signal);
165
+ return registerLiveCatalog(liveCatalog);
166
+ };
167
+
168
+ const registerLiveCatalogBestEffort = async (accessToken: string, requestId: string, signal: AbortSignal | undefined): Promise<boolean> => {
169
+ try {
170
+ const registered = await discoverAndRegisterLiveCatalog(accessToken, requestId, signal);
171
+ if (!registered) return false;
172
+ catalogDiscoveryTokens.add(accessToken);
173
+ return true;
174
+ } catch {
175
+ // Login, refresh, startup, and first-use discovery are best-effort in the reference provider.
176
+ // Never leak tokens via discovery errors/logs and keep the current fallback/cached catalog.
177
+ return false;
178
+ }
179
+ };
180
+
181
+ const scheduleTrackedCatalogDiscovery = (accessToken: string): Promise<boolean> | undefined => {
182
+ if (disposed || accessToken.trim().length === 0 || catalogDiscoveryTokens.has(accessToken)) return undefined;
183
+ const existing = catalogDiscoveryInFlightTokens.get(accessToken);
184
+ if (existing) return existing;
185
+ let requestId: string;
186
+ try {
187
+ requestId = uuid();
188
+ } catch {
189
+ return undefined;
190
+ }
191
+ const controller = new AbortController();
192
+ catalogDiscoveryAbortControllers.add(controller);
193
+ const task = registerLiveCatalogBestEffort(accessToken, requestId, controller.signal);
194
+ catalogDiscoveryInFlightTokens.set(accessToken, task);
195
+ catalogDiscoveryTasks.add(task);
196
+ task.then(
197
+ () => {
198
+ catalogDiscoveryInFlightTokens.delete(accessToken);
199
+ catalogDiscoveryTasks.delete(task);
200
+ catalogDiscoveryAbortControllers.delete(controller);
201
+ },
202
+ () => {
203
+ catalogDiscoveryInFlightTokens.delete(accessToken);
204
+ catalogDiscoveryTasks.delete(task);
205
+ catalogDiscoveryAbortControllers.delete(controller);
206
+ },
207
+ );
208
+ return task;
209
+ };
210
+
211
+ const scheduleFirstUseRediscovery = (accessToken: string | undefined): void => {
212
+ if (!accessToken || firstUseRediscoveryTask || disposed) return;
213
+ const task = scheduleTrackedCatalogDiscovery(accessToken);
214
+ if (!task) return;
215
+ firstUseRediscoveryTask = task;
216
+ task.then(
217
+ (success) => {
218
+ if (!success && firstUseRediscoveryTask === task) firstUseRediscoveryTask = undefined;
219
+ },
220
+ () => {
221
+ if (firstUseRediscoveryTask === task) firstUseRediscoveryTask = undefined;
222
+ },
223
+ );
224
+ };
225
+
226
+ const discoverCatalogFromStoredCredentials = async (_event?: unknown, context?: CursorProviderContext): Promise<void> => {
227
+ if (disposed) return;
228
+ let accessToken: string | undefined;
229
+ try {
230
+ accessToken = await context?.modelRegistry?.getApiKeyForProvider?.(CURSOR_PROVIDER_ID);
231
+ } catch {
232
+ return;
233
+ }
234
+ if (!accessToken) return;
235
+ scheduleTrackedCatalogDiscovery(accessToken);
236
+ };
237
+
238
+ const cleanupCurrentSession = async (_event?: unknown, context?: CursorProviderContext): Promise<void> => {
239
+ const sessionId = context?.sessionManager?.getSessionId?.();
240
+ if (sessionId) await streamAdapter.cleanupSession(sessionId);
241
+ };
242
+
243
+ const disposeRuntime = async (): Promise<void> => {
244
+ if (disposePromise) return disposePromise;
245
+ disposePromise = (async () => {
246
+ await waitForCatalogDiscoveryTasks(catalogDiscoveryTasks, catalogDiscoveryDisposeTimeoutMs);
247
+ disposed = true;
248
+ for (const controller of catalogDiscoveryAbortControllers) {
249
+ controller.abort();
250
+ }
251
+ await streamAdapter.dispose();
252
+ })();
253
+ return disposePromise;
254
+ };
255
+
256
+ const startupCatalog = loadCachedLiveCatalog() ?? createEstimatedCursorCatalog();
257
+ registerCatalog(mapCursorCatalogToProviderModels(startupCatalog));
258
+
259
+ const cleanupCurrentSessionAndDispose = async (event?: unknown, context?: CursorProviderContext): Promise<void> => {
260
+ try {
261
+ await cleanupCurrentSession(event, context);
262
+ } finally {
263
+ await disposeRuntime();
264
+ }
265
+ };
266
+
267
+ pi.on("session_start", discoverCatalogFromStoredCredentials);
268
+ pi.on("session_before_switch", cleanupCurrentSession);
269
+ pi.on("session_before_fork", cleanupCurrentSession);
270
+ pi.on("session_before_tree", cleanupCurrentSession);
271
+ pi.on("session_shutdown", cleanupCurrentSessionAndDispose);
272
+
273
+ return {
274
+ transport,
275
+ authService,
276
+ discoveryService,
277
+ streamAdapter,
278
+ catalogCache,
279
+ dispose: disposeRuntime,
280
+ };
281
+ }
282
+
283
+ async function waitForCatalogDiscoveryTasks(tasks: ReadonlySet<Promise<boolean>>, timeoutMs: number): Promise<void> {
284
+ const pending = [...tasks];
285
+ if (pending.length === 0 || timeoutMs <= 0) return;
286
+ let timer: ReturnType<typeof setTimeout> | undefined;
287
+ try {
288
+ await Promise.race([
289
+ Promise.allSettled(pending).then(() => undefined),
290
+ new Promise<void>((resolve) => {
291
+ timer = setTimeout(resolve, timeoutMs);
292
+ }),
293
+ ]);
294
+ } finally {
295
+ if (timer) clearTimeout(timer);
296
+ }
297
+ }
298
+
299
+ export default function cursorProviderExtension(pi: CursorProviderHost): void {
300
+ registerCursorProvider(pi);
301
+ }