@veris-ai/daytona-opencode 0.1.0

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 (106) hide show
  1. package/.opencode/plugin/daytona/core/logger.d.ts +15 -0
  2. package/.opencode/plugin/daytona/core/logger.js +65 -0
  3. package/.opencode/plugin/daytona/core/logger.js.map +1 -0
  4. package/.opencode/plugin/daytona/core/logger.ts +71 -0
  5. package/.opencode/plugin/daytona/core/project-data-storage.d.ts +63 -0
  6. package/.opencode/plugin/daytona/core/project-data-storage.js +213 -0
  7. package/.opencode/plugin/daytona/core/project-data-storage.js.map +1 -0
  8. package/.opencode/plugin/daytona/core/project-data-storage.ts +234 -0
  9. package/.opencode/plugin/daytona/core/session-manager.d.ts +74 -0
  10. package/.opencode/plugin/daytona/core/session-manager.js +441 -0
  11. package/.opencode/plugin/daytona/core/session-manager.js.map +1 -0
  12. package/.opencode/plugin/daytona/core/session-manager.ts +471 -0
  13. package/.opencode/plugin/daytona/core/toast.d.ts +47 -0
  14. package/.opencode/plugin/daytona/core/toast.js +70 -0
  15. package/.opencode/plugin/daytona/core/toast.js.map +1 -0
  16. package/.opencode/plugin/daytona/core/toast.ts +96 -0
  17. package/.opencode/plugin/daytona/core/types.d.ts +53 -0
  18. package/.opencode/plugin/daytona/core/types.js +12 -0
  19. package/.opencode/plugin/daytona/core/types.js.map +1 -0
  20. package/.opencode/plugin/daytona/core/types.ts +72 -0
  21. package/.opencode/plugin/daytona/git/host-git-manager.d.ts +58 -0
  22. package/.opencode/plugin/daytona/git/host-git-manager.js +342 -0
  23. package/.opencode/plugin/daytona/git/host-git-manager.js.map +1 -0
  24. package/.opencode/plugin/daytona/git/host-git-manager.ts +372 -0
  25. package/.opencode/plugin/daytona/git/index.d.ts +5 -0
  26. package/.opencode/plugin/daytona/git/index.js +6 -0
  27. package/.opencode/plugin/daytona/git/index.js.map +1 -0
  28. package/.opencode/plugin/daytona/git/index.ts +6 -0
  29. package/.opencode/plugin/daytona/git/sandbox-git-manager.d.ts +22 -0
  30. package/.opencode/plugin/daytona/git/sandbox-git-manager.js +80 -0
  31. package/.opencode/plugin/daytona/git/sandbox-git-manager.js.map +1 -0
  32. package/.opencode/plugin/daytona/git/sandbox-git-manager.ts +92 -0
  33. package/.opencode/plugin/daytona/git/session-git-manager.d.ts +54 -0
  34. package/.opencode/plugin/daytona/git/session-git-manager.js +184 -0
  35. package/.opencode/plugin/daytona/git/session-git-manager.js.map +1 -0
  36. package/.opencode/plugin/daytona/git/session-git-manager.ts +203 -0
  37. package/.opencode/plugin/daytona/index.d.ts +125 -0
  38. package/.opencode/plugin/daytona/index.js +60 -0
  39. package/.opencode/plugin/daytona/index.js.map +1 -0
  40. package/.opencode/plugin/daytona/index.ts +73 -0
  41. package/.opencode/plugin/daytona/plugins/custom-tools.d.ts +122 -0
  42. package/.opencode/plugin/daytona/plugins/custom-tools.js +18 -0
  43. package/.opencode/plugin/daytona/plugins/custom-tools.js.map +1 -0
  44. package/.opencode/plugin/daytona/plugins/custom-tools.ts +21 -0
  45. package/.opencode/plugin/daytona/plugins/session-events.d.ts +10 -0
  46. package/.opencode/plugin/daytona/plugins/session-events.js +63 -0
  47. package/.opencode/plugin/daytona/plugins/session-events.js.map +1 -0
  48. package/.opencode/plugin/daytona/plugins/session-events.ts +61 -0
  49. package/.opencode/plugin/daytona/plugins/system-transform.d.ts +10 -0
  50. package/.opencode/plugin/daytona/plugins/system-transform.js +38 -0
  51. package/.opencode/plugin/daytona/plugins/system-transform.js.map +1 -0
  52. package/.opencode/plugin/daytona/plugins/system-transform.ts +43 -0
  53. package/.opencode/plugin/daytona/tools/bash.d.ts +19 -0
  54. package/.opencode/plugin/daytona/tools/bash.js +42 -0
  55. package/.opencode/plugin/daytona/tools/bash.js.map +1 -0
  56. package/.opencode/plugin/daytona/tools/bash.ts +51 -0
  57. package/.opencode/plugin/daytona/tools/edit.d.ts +21 -0
  58. package/.opencode/plugin/daytona/tools/edit.js +33 -0
  59. package/.opencode/plugin/daytona/tools/edit.js.map +1 -0
  60. package/.opencode/plugin/daytona/tools/edit.ts +44 -0
  61. package/.opencode/plugin/daytona/tools/get-preview-url.d.ts +17 -0
  62. package/.opencode/plugin/daytona/tools/get-preview-url.js +17 -0
  63. package/.opencode/plugin/daytona/tools/get-preview-url.js.map +1 -0
  64. package/.opencode/plugin/daytona/tools/get-preview-url.ts +26 -0
  65. package/.opencode/plugin/daytona/tools/git-sync.d.ts +12 -0
  66. package/.opencode/plugin/daytona/tools/git-sync.js +26 -0
  67. package/.opencode/plugin/daytona/tools/git-sync.js.map +1 -0
  68. package/.opencode/plugin/daytona/tools/git-sync.ts +36 -0
  69. package/.opencode/plugin/daytona/tools/glob.d.ts +17 -0
  70. package/.opencode/plugin/daytona/tools/glob.js +21 -0
  71. package/.opencode/plugin/daytona/tools/glob.js.map +1 -0
  72. package/.opencode/plugin/daytona/tools/glob.ts +30 -0
  73. package/.opencode/plugin/daytona/tools/grep.d.ts +17 -0
  74. package/.opencode/plugin/daytona/tools/grep.js +29 -0
  75. package/.opencode/plugin/daytona/tools/grep.js.map +1 -0
  76. package/.opencode/plugin/daytona/tools/grep.ts +39 -0
  77. package/.opencode/plugin/daytona/tools/ls.d.ts +17 -0
  78. package/.opencode/plugin/daytona/tools/ls.js +22 -0
  79. package/.opencode/plugin/daytona/tools/ls.js.map +1 -0
  80. package/.opencode/plugin/daytona/tools/ls.ts +32 -0
  81. package/.opencode/plugin/daytona/tools/multiedit.d.ts +25 -0
  82. package/.opencode/plugin/daytona/tools/multiedit.js +37 -0
  83. package/.opencode/plugin/daytona/tools/multiedit.js.map +1 -0
  84. package/.opencode/plugin/daytona/tools/multiedit.ts +54 -0
  85. package/.opencode/plugin/daytona/tools/read.d.ts +17 -0
  86. package/.opencode/plugin/daytona/tools/read.js +18 -0
  87. package/.opencode/plugin/daytona/tools/read.js.map +1 -0
  88. package/.opencode/plugin/daytona/tools/read.ts +27 -0
  89. package/.opencode/plugin/daytona/tools/veris-receipt.d.ts +26 -0
  90. package/.opencode/plugin/daytona/tools/veris-receipt.js +76 -0
  91. package/.opencode/plugin/daytona/tools/veris-receipt.js.map +1 -0
  92. package/.opencode/plugin/daytona/tools/veris-receipt.ts +103 -0
  93. package/.opencode/plugin/daytona/tools/write.d.ts +19 -0
  94. package/.opencode/plugin/daytona/tools/write.js +18 -0
  95. package/.opencode/plugin/daytona/tools/write.js.map +1 -0
  96. package/.opencode/plugin/daytona/tools/write.ts +27 -0
  97. package/.opencode/plugin/daytona/tools.d.ts +119 -0
  98. package/.opencode/plugin/daytona/tools.js +35 -0
  99. package/.opencode/plugin/daytona/tools.js.map +1 -0
  100. package/.opencode/plugin/daytona/tools.ts +45 -0
  101. package/.opencode/plugin/index.d.ts +9 -0
  102. package/.opencode/plugin/index.js +10 -0
  103. package/.opencode/plugin/index.js.map +1 -0
  104. package/.opencode/plugin/index.ts +11 -0
  105. package/README.md +87 -0
  106. package/package.json +52 -0
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Copyright Daytona Platforms Inc.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ /**
6
+ * Manages Daytona sandbox sessions and persists session-sandbox mappings
7
+ * Stores data per-project in ~/.local/share/opencode/storage/daytona/{projectId}.json
8
+ */
9
+ import { type Sandbox } from '@veris-ai/daytona';
10
+ import type { PluginInput } from '@opencode-ai/plugin';
11
+ export declare class DaytonaSessionManager {
12
+ private readonly apiKey;
13
+ private readonly dataStorage;
14
+ private sessionSandboxes;
15
+ private readonly deletingSessions;
16
+ private readonly deletionPromises;
17
+ private currentProjectId?;
18
+ readonly repoPath: string;
19
+ /** Snapshot new sandboxes are created from; undefined uses Daytona's default snapshot. */
20
+ readonly snapshot?: string;
21
+ constructor(apiKey: string, storageDir: string, repoPath: string, snapshot?: string);
22
+ /**
23
+ * Check if a sandbox is fully initialized (has process property)
24
+ */
25
+ private isFullyInitialized;
26
+ /**
27
+ * Check if a sandbox is partially initialized (has id but not process)
28
+ */
29
+ private isPartiallyInitialized;
30
+ /**
31
+ * Load sessions for a specific project into memory
32
+ */
33
+ private loadProjectSessions;
34
+ /**
35
+ * Set the current project context
36
+ */
37
+ setProjectContext(projectId: string): void;
38
+ /**
39
+ * Get branch number for a sandbox
40
+ */
41
+ getBranchNumberForSandbox(projectId: string, sandboxId: string): number | undefined;
42
+ /**
43
+ * Get or create a sandbox for the given session ID
44
+ */
45
+ getSandbox(sessionId: string, projectId: string, worktree: string, pluginCtx?: PluginInput): Promise<Sandbox>;
46
+ /**
47
+ * Delete the sandbox associated with the given session ID
48
+ */
49
+ deleteSandbox(sessionId: string, projectId: string): Promise<boolean>;
50
+ private deleteSandboxInner;
51
+ /**
52
+ * Pull not-yet-synced sandbox changes into the local repo before the sandbox is
53
+ * destroyed. Throws — aborting deletion so the sandbox is preserved — when unsynced
54
+ * changes cannot be pulled, including when the local repository itself is no longer
55
+ * accessible (a silent skip there would destroy the only copy of the work). A sandbox
56
+ * that is not running is deleted without being started: anything in it was either
57
+ * synced while it ran or is abandoned by the explicit delete.
58
+ *
59
+ * Runs inside the session's sync queue; it must NOT enqueue (that would deadlock).
60
+ */
61
+ private syncBeforeDelete;
62
+ /**
63
+ * Read-only check for a session→sandbox mapping (memory or storage); never creates,
64
+ * migrates, or connects.
65
+ */
66
+ hasSandbox(sessionId: string, projectId: string): boolean;
67
+ isSessionDeleting(sessionId: string): boolean;
68
+ /**
69
+ * Guard for registration points that follow an await: deletion may have started (and
70
+ * finished) while a sandbox was being refreshed or reconnected, and persisting the
71
+ * mapping afterwards would resurrect state for a session that no longer exists.
72
+ */
73
+ private ensureNotDeleted;
74
+ }
@@ -0,0 +1,441 @@
1
+ /**
2
+ * Copyright Daytona Platforms Inc.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ /**
6
+ * Manages Daytona sandbox sessions and persists session-sandbox mappings
7
+ * Stores data per-project in ~/.local/share/opencode/storage/daytona/{projectId}.json
8
+ */
9
+ // The Veris fork's entire diff to this file is the module named below.
10
+ //
11
+ // @veris-ai/daytona re-exports all of @daytona/sdk and overrides only
12
+ // `Daytona`, so every `new Daytona({ apiKey })` in this file now returns a
13
+ // client whose create() also registers the Veris snapshot, provisions a twin,
14
+ // sets the domain allowlist, and waits for veris-proxy to bind — and whose
15
+ // get() rehydrates that surface on reconnect. The sandboxes handed back carry
16
+ // `.veris` for receipts, and their delete() removes the twin as well.
17
+ //
18
+ // DaytonaNotFoundError and DaytonaValidationError below are the SAME class
19
+ // objects @daytona/sdk exports (it is a peer dependency of @veris-ai/daytona),
20
+ // so the `instanceof` checks further down keep working — including against
21
+ // errors raised in tools/bash.ts, which still imports from '@daytona/sdk'.
22
+ import { Daytona, DaytonaNotFoundError, DaytonaValidationError, } from '@veris-ai/daytona';
23
+ import { logger } from './logger';
24
+ import { SessionGitManager } from '../git/session-git-manager';
25
+ import { DaytonaSandboxGitManager } from '../git/sandbox-git-manager';
26
+ import { ProjectDataStorage } from './project-data-storage';
27
+ import { toast } from './toast';
28
+ export class DaytonaSessionManager {
29
+ apiKey;
30
+ dataStorage;
31
+ sessionSandboxes;
32
+ // Sessions whose sandbox teardown has begun. getSandbox creates sandboxes on demand,
33
+ // so without this tombstone a sync queued behind a deletion would resurrect a fresh
34
+ // sandbox for a session that no longer exists (invisible, billed, never cleaned up).
35
+ deletingSessions = new Set();
36
+ deletionPromises = new Map();
37
+ currentProjectId;
38
+ repoPath;
39
+ /** Snapshot new sandboxes are created from; undefined uses Daytona's default snapshot. */
40
+ snapshot;
41
+ constructor(apiKey, storageDir, repoPath, snapshot) {
42
+ this.apiKey = apiKey;
43
+ this.dataStorage = new ProjectDataStorage(storageDir);
44
+ this.repoPath = repoPath;
45
+ this.snapshot = snapshot?.trim() || undefined;
46
+ this.sessionSandboxes = new Map();
47
+ }
48
+ /**
49
+ * Check if a sandbox is fully initialized (has process property)
50
+ */
51
+ isFullyInitialized(sandbox) {
52
+ return sandbox !== undefined && 'process' in sandbox;
53
+ }
54
+ /**
55
+ * Check if a sandbox is partially initialized (has id but not process)
56
+ */
57
+ isPartiallyInitialized(sandbox) {
58
+ return sandbox !== undefined && 'id' in sandbox && !('process' in sandbox);
59
+ }
60
+ /**
61
+ * Load sessions for a specific project into memory
62
+ */
63
+ loadProjectSessions(projectId) {
64
+ const projectData = this.dataStorage.load(projectId);
65
+ if (projectData) {
66
+ for (const [sessionId, sessionInfo] of Object.entries(projectData.sessions)) {
67
+ this.sessionSandboxes.set(sessionId, { id: sessionInfo.sandboxId });
68
+ }
69
+ logger.info(`Loaded ${Object.keys(projectData.sessions).length} sessions for project ${projectId}`);
70
+ }
71
+ }
72
+ /**
73
+ * Set the current project context
74
+ */
75
+ setProjectContext(projectId) {
76
+ if (this.currentProjectId !== projectId) {
77
+ this.currentProjectId = projectId;
78
+ this.sessionSandboxes.clear();
79
+ this.loadProjectSessions(projectId);
80
+ }
81
+ }
82
+ /**
83
+ * Get branch number for a sandbox
84
+ */
85
+ getBranchNumberForSandbox(projectId, sandboxId) {
86
+ return this.dataStorage.getBranchNumberForSandbox(projectId, sandboxId);
87
+ }
88
+ /**
89
+ * Get or create a sandbox for the given session ID
90
+ */
91
+ async getSandbox(sessionId, projectId, worktree, pluginCtx) {
92
+ if (pluginCtx?.client?.tui) {
93
+ toast.initialize(pluginCtx.client.tui);
94
+ }
95
+ if (this.deletingSessions.has(sessionId)) {
96
+ throw new Error(`Session ${sessionId} is deleted; not creating a new sandbox for it.`);
97
+ }
98
+ if (!this.apiKey) {
99
+ logger.error('DAYTONA_API_KEY is not set. Cannot create or retrieve sandbox.');
100
+ toast.show({
101
+ title: 'Sandbox error',
102
+ message: 'DAYTONA_API_KEY is not set. Please set the environment variable to use Daytona sandboxes.',
103
+ variant: 'error',
104
+ });
105
+ throw new Error('DAYTONA_API_KEY is not set. Please set the environment variable to use Daytona sandboxes.');
106
+ }
107
+ // Veris coordinates get the same treatment as the Daytona key, and for the
108
+ // same reason: this is the first tool call of a session, and a legible
109
+ // message here is the difference between "set one env var" and a stack
110
+ // trace out of sandbox creation.
111
+ //
112
+ // Deliberately fatal rather than degrading to a plain Daytona sandbox. A
113
+ // sandbox without a twin reaches the REAL vendor, and an agent cannot tell
114
+ // the difference — so an unset key has to stop the session, not quietly
115
+ // change what it is doing.
116
+ for (const [name, hint] of [
117
+ ['VERIS_API_KEY', 'Get one at https://studio.veris.ai'],
118
+ ['VERIS_ENVIRONMENT_ID', 'A Veris environment decides which vendor services your twin gets'],
119
+ ]) {
120
+ if (process.env[name])
121
+ continue;
122
+ const message = `${name} is not set, so this sandbox would reach real vendor APIs. ${hint}.`;
123
+ logger.error(message);
124
+ toast.show({ title: 'Veris not configured', message, variant: 'error' });
125
+ throw new Error(message);
126
+ }
127
+ // Load project sessions if needed
128
+ this.setProjectContext(projectId);
129
+ const existing = this.sessionSandboxes.get(sessionId);
130
+ // If we have a fully initialized sandbox, reuse it
131
+ if (this.isFullyInitialized(existing)) {
132
+ // Refresh sandbox state and ensure it's running
133
+ await existing.refreshData();
134
+ if (existing.state !== 'started') {
135
+ logger.info(`Starting sandbox ${existing.id} (current state: ${existing.state})`);
136
+ await existing.start();
137
+ }
138
+ this.ensureNotDeleted(sessionId);
139
+ this.dataStorage.updateSession(projectId, worktree, sessionId, existing.id);
140
+ return existing;
141
+ }
142
+ // If we have a sandboxId but not a full sandbox object, reconnect to it
143
+ if (this.isPartiallyInitialized(existing)) {
144
+ try {
145
+ logger.info(`Reconnecting to existing sandbox: ${existing.id}`);
146
+ const daytona = new Daytona({ apiKey: this.apiKey });
147
+ const reconnectStart = Date.now();
148
+ logger.info(`Daytona get begin sandboxId=${existing.id}`);
149
+ const sandbox = await daytona.get(existing.id);
150
+ logger.info(`Daytona get done sandboxId=${existing.id} in ${Date.now() - reconnectStart}ms`);
151
+ logger.info(`Starting sandbox begin sandboxId=${sandbox.id}`);
152
+ await sandbox.start();
153
+ logger.info(`Starting sandbox done sandboxId=${sandbox.id} in ${Date.now() - reconnectStart}ms`);
154
+ this.ensureNotDeleted(sessionId);
155
+ this.sessionSandboxes.set(sessionId, sandbox);
156
+ // Preserve branch number if it exists for this sandbox
157
+ let branchNumber = this.dataStorage.getBranchNumberForSandbox(projectId, sandbox.id);
158
+ if (!branchNumber) {
159
+ try {
160
+ branchNumber = SessionGitManager.allocateAndReserveBranchNumber(worktree);
161
+ }
162
+ catch {
163
+ // No local git repo (or git unavailable) shouldn't block sandbox usage.
164
+ branchNumber = undefined;
165
+ }
166
+ }
167
+ this.dataStorage.updateSession(projectId, worktree, sessionId, sandbox.id, branchNumber);
168
+ toast.show({
169
+ title: 'Sandbox connected',
170
+ message: `Connected to existing sandbox.`,
171
+ variant: 'info',
172
+ });
173
+ // Even if git syncing is disabled, ensure the project directory exists in the sandbox.
174
+ if (!branchNumber) {
175
+ try {
176
+ await new DaytonaSandboxGitManager(sandbox, this.repoPath).ensureDirectory();
177
+ }
178
+ catch (err) {
179
+ logger.warn(`Failed to ensure sandbox project directory exists: ${err}`);
180
+ }
181
+ }
182
+ return sandbox;
183
+ }
184
+ catch (err) {
185
+ // Only treat 404 as "sandbox is confirmed gone" — clear the mapping and fall through
186
+ // to create a replacement. For transient errors (network, auth, timeout, provisioning),
187
+ // preserve the mapping and propagate so the caller can retry later without losing the
188
+ // session→sandbox binding and its branchNumber.
189
+ if (err instanceof DaytonaNotFoundError) {
190
+ logger.error(`Sandbox ${existing.id} no longer exists; creating a replacement.`);
191
+ this.sessionSandboxes.delete(sessionId);
192
+ this.dataStorage.removeSession(projectId, worktree, sessionId);
193
+ }
194
+ else {
195
+ logger.error(`Failed to reconnect to sandbox ${existing.id}: ${err}`);
196
+ throw err;
197
+ }
198
+ }
199
+ }
200
+ // If not in cache/storage for this project, try to recover from other projects and migrate.
201
+ if (!existing) {
202
+ const migrated = this.dataStorage.getSession(projectId, worktree, sessionId);
203
+ if (migrated?.sandboxId) {
204
+ logger.info(`Recovered session ${sessionId} for project ${projectId} (migrated from another project)`);
205
+ this.sessionSandboxes.set(sessionId, { id: migrated.sandboxId });
206
+ // Re-run getSandbox to go through the normal reconnect path.
207
+ return this.getSandbox(sessionId, projectId, worktree, pluginCtx);
208
+ }
209
+ }
210
+ // Otherwise, create a new sandbox
211
+ logger.info(`Creating new sandbox for session: ${sessionId} in project: ${projectId}`);
212
+ const daytona = new Daytona({ apiKey: this.apiKey });
213
+ // Omit the key entirely when unset so Daytona applies its default snapshot.
214
+ const createParams = this.snapshot ? { snapshot: this.snapshot } : {};
215
+ const createStart = Date.now();
216
+ logger.info(`Daytona create begin sessionId=${sessionId} snapshot=${this.snapshot ?? '(default)'}`);
217
+ const waitingLog = setTimeout(() => {
218
+ logger.warn(`Daytona create still waiting after ${Date.now() - createStart}ms (sessionId=${sessionId})`);
219
+ }, 15_000);
220
+ const sandbox = await daytona
221
+ .create(createParams)
222
+ .catch((err) => {
223
+ // Only blame the snapshot when the request itself was rejected. The create
224
+ // params contain nothing but the snapshot name, so a validation error means
225
+ // Daytona refused that name (empirically: "Snapshot <name> not found" is a
226
+ // DaytonaValidationError). Auth, network, quota, and timeout failures are
227
+ // unrelated to DAYTONA_SNAPSHOT and propagate unattributed, as before.
228
+ if (this.snapshot && err instanceof DaytonaValidationError) {
229
+ logger.error(`Failed to create sandbox from snapshot '${this.snapshot}': ${err}`);
230
+ toast.show({
231
+ title: 'Sandbox error',
232
+ message: `Verify DAYTONA_SNAPSHOT names an available snapshot: ${err.message}`,
233
+ variant: 'error',
234
+ });
235
+ }
236
+ throw err;
237
+ })
238
+ .finally(() => clearTimeout(waitingLog));
239
+ logger.info(`Daytona create done sessionId=${sessionId} sandboxId=${sandbox.id} in ${Date.now() - createStart}ms`);
240
+ if (this.deletingSessions.has(sessionId)) {
241
+ // The session was deleted while creation was in flight. The fresh sandbox is not
242
+ // registered anywhere, so nothing else will ever clean it up - discard it here.
243
+ logger.warn(`Session ${sessionId} was deleted during sandbox creation; discarding sandbox ${sandbox.id}`);
244
+ try {
245
+ await sandbox.delete();
246
+ }
247
+ catch (err) {
248
+ logger.error(`Failed to discard sandbox ${sandbox.id} for deleted session ${sessionId}: ${err}`);
249
+ throw new Error(`Session ${sessionId} is deleted and discarding newly created sandbox ${sandbox.id} failed; if it still exists, delete it from the Daytona dashboard.`);
250
+ }
251
+ throw new Error(`Session ${sessionId} is deleted; the newly created sandbox was discarded.`);
252
+ }
253
+ this.sessionSandboxes.set(sessionId, sandbox);
254
+ // Get or assign branch number for this sandbox
255
+ let branchNumber = this.dataStorage.getBranchNumberForSandbox(projectId, sandbox.id);
256
+ if (!branchNumber) {
257
+ try {
258
+ branchNumber = SessionGitManager.allocateAndReserveBranchNumber(worktree);
259
+ }
260
+ catch (err) {
261
+ logger.warn(`allocateAndReserveBranchNumber failed sessionId=${sessionId}: ${err}`);
262
+ // No local git repo (or git unavailable) shouldn't block sandbox usage.
263
+ branchNumber = undefined;
264
+ }
265
+ }
266
+ this.dataStorage.updateSession(projectId, worktree, sessionId, sandbox.id, branchNumber);
267
+ logger.info(`Sandbox created successfully: ${sandbox.id}${branchNumber ? ` with branch number ${branchNumber}` : ''}`);
268
+ // Initialize git repo in the sandbox and sync with host
269
+ try {
270
+ if (branchNumber) {
271
+ const sessionGit = new SessionGitManager(sandbox, this.repoPath, worktree, branchNumber);
272
+ await sessionGit.initializeAndSync(pluginCtx);
273
+ }
274
+ else {
275
+ // Git disabled; still ensure the directory exists so tools can operate.
276
+ await new DaytonaSandboxGitManager(sandbox, this.repoPath).ensureDirectory();
277
+ }
278
+ }
279
+ catch (err) {
280
+ logger.error(`Failed to initialize git repo or push local changes in sandbox: ${err}`);
281
+ toast.show({
282
+ title: 'Git error',
283
+ message: err?.message || 'Failed to initialize git repo in sandbox.',
284
+ variant: 'error',
285
+ });
286
+ }
287
+ // Deletion may have raced the initialization awaits above; the mapping was already
288
+ // registered, so the delete flow owns (and removes) the sandbox itself - returning
289
+ // it would hand callers a destroyed sandbox that fails confusingly on first use.
290
+ this.ensureNotDeleted(sessionId);
291
+ toast.show({
292
+ title: 'Sandbox created',
293
+ message: `Created new sandbox for session.`,
294
+ variant: 'success',
295
+ });
296
+ return sandbox;
297
+ }
298
+ /**
299
+ * Delete the sandbox associated with the given session ID
300
+ */
301
+ async deleteSandbox(sessionId, projectId) {
302
+ // Concurrent deletes share one promise: a second teardown racing the first would
303
+ // observe the already-deleted sandbox, throw, and wrongly clear the tombstone.
304
+ const inFlight = this.deletionPromises.get(sessionId);
305
+ if (inFlight)
306
+ return inFlight;
307
+ // Tombstone first, removed again on failure: while set, no code path may create or
308
+ // reconnect a sandbox for this session. Kept after success on purpose - the session
309
+ // is gone, and any late event for it must no-op instead of resurrecting a sandbox.
310
+ this.deletingSessions.add(sessionId);
311
+ const run = (async () => {
312
+ try {
313
+ return await this.deleteSandboxInner(sessionId, projectId);
314
+ }
315
+ catch (err) {
316
+ this.deletingSessions.delete(sessionId);
317
+ throw err;
318
+ }
319
+ finally {
320
+ this.deletionPromises.delete(sessionId);
321
+ }
322
+ })();
323
+ this.deletionPromises.set(sessionId, run);
324
+ return run;
325
+ }
326
+ async deleteSandboxInner(sessionId, projectId) {
327
+ await SessionGitManager.waitForPendingSync(sessionId);
328
+ let sandbox = this.sessionSandboxes.get(sessionId);
329
+ // Read-only lookup so deleting never migrates sessions or rewrites project metadata.
330
+ const stored = this.dataStorage.findSession(sessionId);
331
+ let sandboxGone = false;
332
+ // If not in cache, try to load from storage and reconnect
333
+ if (!sandbox || this.isPartiallyInitialized(sandbox)) {
334
+ if (stored?.session.sandboxId) {
335
+ const daytona = new Daytona({ apiKey: this.apiKey });
336
+ try {
337
+ sandbox = await daytona.get(stored.session.sandboxId);
338
+ this.sessionSandboxes.set(sessionId, sandbox);
339
+ }
340
+ catch (err) {
341
+ if (err instanceof DaytonaNotFoundError) {
342
+ sandboxGone = true;
343
+ logger.warn(`Sandbox ${stored.session.sandboxId} no longer exists; clearing stale mapping.`);
344
+ }
345
+ else {
346
+ // Non-404: we cannot confirm the sandbox is gone. Surface the error so the
347
+ // event handler shows a "Delete failed" toast instead of silently reporting
348
+ // success while leaving a running sandbox on the Daytona account.
349
+ logger.error(`Failed to reconnect to sandbox ${stored.session.sandboxId}: ${err}`);
350
+ throw err;
351
+ }
352
+ }
353
+ }
354
+ else {
355
+ sandboxGone = true;
356
+ }
357
+ }
358
+ // Delete the sandbox if we have a fully initialized one
359
+ let deleted = false;
360
+ if (this.isFullyInitialized(sandbox)) {
361
+ // Final sync and deletion run as ONE queue entry, so a sync enqueued between the
362
+ // wait above and this point is drained first, and nothing can slot in between
363
+ // pulling the last changes and destroying the sandbox.
364
+ const target = sandbox;
365
+ await SessionGitManager.enqueueSessionSync(sessionId, async () => {
366
+ await this.syncBeforeDelete(target, stored);
367
+ logger.info(`Removing sandbox for session: ${sessionId}`);
368
+ await target.delete();
369
+ });
370
+ deleted = true;
371
+ sandboxGone = true;
372
+ logger.info(`Sandbox deleted successfully.`);
373
+ }
374
+ else {
375
+ logger.warn(`No sandbox found for session: ${sessionId}`);
376
+ }
377
+ // Clear the local mapping when the sandbox is gone (deleted or already absent) so a
378
+ // stale entry can't cause repeated reconnect failures. Preserve it on transient errors.
379
+ if (sandboxGone) {
380
+ this.sessionSandboxes.delete(sessionId);
381
+ const cleanupProjectId = stored?.projectId ?? projectId;
382
+ const cleanupWorktree = stored?.worktree ?? this.dataStorage.load(projectId)?.worktree ?? '';
383
+ this.dataStorage.removeSession(cleanupProjectId, cleanupWorktree, sessionId);
384
+ }
385
+ return deleted;
386
+ }
387
+ /**
388
+ * Pull not-yet-synced sandbox changes into the local repo before the sandbox is
389
+ * destroyed. Throws — aborting deletion so the sandbox is preserved — when unsynced
390
+ * changes cannot be pulled, including when the local repository itself is no longer
391
+ * accessible (a silent skip there would destroy the only copy of the work). A sandbox
392
+ * that is not running is deleted without being started: anything in it was either
393
+ * synced while it ran or is abandoned by the explicit delete.
394
+ *
395
+ * Runs inside the session's sync queue; it must NOT enqueue (that would deadlock).
396
+ */
397
+ async syncBeforeDelete(sandbox, stored) {
398
+ const branchNumber = stored?.session.branchNumber;
399
+ if (!branchNumber || !stored?.worktree)
400
+ return;
401
+ await sandbox.refreshData();
402
+ if (sandbox.state !== 'started')
403
+ return;
404
+ const sessionGit = new SessionGitManager(sandbox, this.repoPath, stored.worktree, branchNumber);
405
+ if (!sessionGit.hasLocalRepo()) {
406
+ throw new Error(`Local repository at ${stored.worktree} is not accessible, so unsynced sandbox changes cannot be pulled; the sandbox was not deleted. Restore the repository or delete the sandbox from the Daytona dashboard.`);
407
+ }
408
+ try {
409
+ await sessionGit.autoCommitAndPull();
410
+ }
411
+ catch (err) {
412
+ throw new Error(`Sandbox has changes that could not be synced to the local repository; the sandbox was not deleted. ${err?.message ?? err}`);
413
+ }
414
+ }
415
+ /**
416
+ * Read-only check for a session→sandbox mapping (memory or storage); never creates,
417
+ * migrates, or connects.
418
+ */
419
+ hasSandbox(sessionId, projectId) {
420
+ if (this.deletingSessions.has(sessionId))
421
+ return false;
422
+ this.setProjectContext(projectId);
423
+ if (this.sessionSandboxes.has(sessionId))
424
+ return true;
425
+ return this.dataStorage.findSession(sessionId) !== undefined;
426
+ }
427
+ isSessionDeleting(sessionId) {
428
+ return this.deletingSessions.has(sessionId);
429
+ }
430
+ /**
431
+ * Guard for registration points that follow an await: deletion may have started (and
432
+ * finished) while a sandbox was being refreshed or reconnected, and persisting the
433
+ * mapping afterwards would resurrect state for a session that no longer exists.
434
+ */
435
+ ensureNotDeleted(sessionId) {
436
+ if (this.deletingSessions.has(sessionId)) {
437
+ throw new Error(`Session ${sessionId} was deleted while its sandbox was being prepared.`);
438
+ }
439
+ }
440
+ }
441
+ //# sourceMappingURL=session-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-manager.js","sourceRoot":"","sources":["session-manager.ts"],"names":[],"mappings":"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"}