@jamesmurdza/opencode-daytona 0.1.22 → 0.1.23
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/.opencode/plugin/daytona/core/logger.d.ts +2 -2
- package/.opencode/plugin/daytona/core/logger.js +28 -15
- package/.opencode/plugin/daytona/core/logger.js.map +1 -1
- package/.opencode/plugin/daytona/core/project-data-storage.d.ts +11 -7
- package/.opencode/plugin/daytona/core/project-data-storage.js +84 -43
- package/.opencode/plugin/daytona/core/project-data-storage.js.map +1 -1
- package/.opencode/plugin/daytona/core/session-manager.d.ts +4 -1
- package/.opencode/plugin/daytona/core/session-manager.js +92 -33
- package/.opencode/plugin/daytona/core/session-manager.js.map +1 -1
- package/.opencode/plugin/daytona/core/toast.d.ts +4 -1
- package/.opencode/plugin/daytona/core/toast.js +6 -3
- package/.opencode/plugin/daytona/core/toast.js.map +1 -1
- package/.opencode/plugin/daytona/core/types.d.ts +10 -8
- package/.opencode/plugin/daytona/core/types.js +10 -6
- package/.opencode/plugin/daytona/core/types.js.map +1 -1
- package/.opencode/plugin/daytona/git/host-git-manager.d.ts +25 -5
- package/.opencode/plugin/daytona/git/host-git-manager.js +191 -44
- package/.opencode/plugin/daytona/git/host-git-manager.js.map +1 -1
- package/.opencode/plugin/daytona/git/index.d.ts +4 -1
- package/.opencode/plugin/daytona/git/index.js +9 -1
- package/.opencode/plugin/daytona/git/index.js.map +1 -1
- package/.opencode/plugin/daytona/git/sandbox-git-manager.d.ts +4 -1
- package/.opencode/plugin/daytona/git/sandbox-git-manager.js +19 -11
- package/.opencode/plugin/daytona/git/sandbox-git-manager.js.map +1 -1
- package/.opencode/plugin/daytona/git/session-git-manager.d.ts +11 -2
- package/.opencode/plugin/daytona/git/session-git-manager.js +39 -22
- package/.opencode/plugin/daytona/git/session-git-manager.js.map +1 -1
- package/.opencode/plugin/daytona/index.d.ts +131 -23
- package/.opencode/plugin/daytona/index.js +27 -16
- package/.opencode/plugin/daytona/index.js.map +1 -1
- package/.opencode/plugin/daytona/plugins/custom-tools.d.ts +129 -5
- package/.opencode/plugin/daytona/plugins/custom-tools.js +15 -15
- package/.opencode/plugin/daytona/plugins/custom-tools.js.map +1 -1
- package/.opencode/plugin/daytona/plugins/session-events.d.ts +10 -0
- package/.opencode/plugin/daytona/plugins/session-events.js +51 -0
- package/.opencode/plugin/daytona/plugins/session-events.js.map +1 -0
- package/.opencode/plugin/daytona/plugins/system-transform.d.ts +8 -5
- package/.opencode/plugin/daytona/plugins/system-transform.js +19 -16
- package/.opencode/plugin/daytona/plugins/system-transform.js.map +1 -1
- package/.opencode/plugin/daytona/tools/bash.d.ts +6 -2
- package/.opencode/plugin/daytona/tools/bash.js +12 -4
- package/.opencode/plugin/daytona/tools/bash.js.map +1 -1
- package/.opencode/plugin/daytona/tools/edit.d.ts +6 -2
- package/.opencode/plugin/daytona/tools/edit.js +13 -5
- package/.opencode/plugin/daytona/tools/edit.js.map +1 -1
- package/.opencode/plugin/daytona/tools/get-preview-url.d.ts +6 -2
- package/.opencode/plugin/daytona/tools/get-preview-url.js +11 -3
- package/.opencode/plugin/daytona/tools/get-preview-url.js.map +1 -1
- package/.opencode/plugin/daytona/tools/glob.d.ts +6 -2
- package/.opencode/plugin/daytona/tools/glob.js +11 -3
- package/.opencode/plugin/daytona/tools/glob.js.map +1 -1
- package/.opencode/plugin/daytona/tools/grep.d.ts +6 -2
- package/.opencode/plugin/daytona/tools/grep.js +11 -3
- package/.opencode/plugin/daytona/tools/grep.js.map +1 -1
- package/.opencode/plugin/daytona/tools/ls.d.ts +6 -2
- package/.opencode/plugin/daytona/tools/ls.js +11 -3
- package/.opencode/plugin/daytona/tools/ls.js.map +1 -1
- package/.opencode/plugin/daytona/tools/lsp.d.ts +6 -2
- package/.opencode/plugin/daytona/tools/lsp.js +13 -5
- package/.opencode/plugin/daytona/tools/lsp.js.map +1 -1
- package/.opencode/plugin/daytona/tools/multiedit.d.ts +6 -2
- package/.opencode/plugin/daytona/tools/multiedit.js +14 -6
- package/.opencode/plugin/daytona/tools/multiedit.js.map +1 -1
- package/.opencode/plugin/daytona/tools/patch.d.ts +7 -5
- package/.opencode/plugin/daytona/tools/patch.js +13 -13
- package/.opencode/plugin/daytona/tools/patch.js.map +1 -1
- package/.opencode/plugin/daytona/tools/read.d.ts +6 -2
- package/.opencode/plugin/daytona/tools/read.js +11 -3
- package/.opencode/plugin/daytona/tools/read.js.map +1 -1
- package/.opencode/plugin/daytona/tools/write.d.ts +6 -2
- package/.opencode/plugin/daytona/tools/write.js +12 -4
- package/.opencode/plugin/daytona/tools/write.js.map +1 -1
- package/.opencode/plugin/daytona/tools.d.ts +14 -16
- package/.opencode/plugin/daytona/tools.js +30 -23
- package/.opencode/plugin/daytona/tools.js.map +1 -1
- package/.opencode/plugin/index.d.ts +7 -4
- package/.opencode/plugin/index.js +12 -3
- package/.opencode/plugin/index.js.map +1 -1
- package/README.md +58 -26
- package/package.json +34 -17
- package/.opencode/plugin/daytona/core/logger.d.ts.map +0 -1
- package/.opencode/plugin/daytona/core/project-data-storage.d.ts.map +0 -1
- package/.opencode/plugin/daytona/core/session-manager.d.ts.map +0 -1
- package/.opencode/plugin/daytona/core/toast.d.ts.map +0 -1
- package/.opencode/plugin/daytona/core/types.d.ts.map +0 -1
- package/.opencode/plugin/daytona/git/host-git-manager.d.ts.map +0 -1
- package/.opencode/plugin/daytona/git/index.d.ts.map +0 -1
- package/.opencode/plugin/daytona/git/sandbox-git-manager.d.ts.map +0 -1
- package/.opencode/plugin/daytona/git/session-git-manager.d.ts.map +0 -1
- package/.opencode/plugin/daytona/index.d.ts.map +0 -1
- package/.opencode/plugin/daytona/plugins/custom-tools.d.ts.map +0 -1
- package/.opencode/plugin/daytona/plugins/index.d.ts +0 -8
- package/.opencode/plugin/daytona/plugins/index.d.ts.map +0 -1
- package/.opencode/plugin/daytona/plugins/index.js +0 -8
- package/.opencode/plugin/daytona/plugins/index.js.map +0 -1
- package/.opencode/plugin/daytona/plugins/session-cleanup.d.ts +0 -8
- package/.opencode/plugin/daytona/plugins/session-cleanup.d.ts.map +0 -1
- package/.opencode/plugin/daytona/plugins/session-cleanup.js +0 -36
- package/.opencode/plugin/daytona/plugins/session-cleanup.js.map +0 -1
- package/.opencode/plugin/daytona/plugins/session-idle-auto-commit.d.ts +0 -7
- package/.opencode/plugin/daytona/plugins/session-idle-auto-commit.d.ts.map +0 -1
- package/.opencode/plugin/daytona/plugins/session-idle-auto-commit.js +0 -44
- package/.opencode/plugin/daytona/plugins/session-idle-auto-commit.js.map +0 -1
- package/.opencode/plugin/daytona/plugins/system-transform.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/bash.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/edit.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/get-preview-url.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/glob.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/grep.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/ls.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/lsp.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/multiedit.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/patch.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/read.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools/write.d.ts.map +0 -1
- package/.opencode/plugin/daytona/tools.d.ts.map +0 -1
- package/.opencode/plugin/index.d.ts.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Copyright 2025 Daytona Platforms Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
3
4
|
*/
|
|
4
5
|
import type { LogLevel } from './types';
|
|
5
6
|
export declare function setLogFilePath(path: string): void;
|
|
@@ -12,4 +13,3 @@ declare class Logger {
|
|
|
12
13
|
}
|
|
13
14
|
export declare const logger: Logger;
|
|
14
15
|
export {};
|
|
15
|
-
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2025 Daytona Platforms Inc.
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.logger = void 0;
|
|
8
|
+
exports.setLogFilePath = setLogFilePath;
|
|
1
9
|
/**
|
|
2
10
|
* Logger class for handling plugin logging
|
|
3
11
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
12
|
+
const fs_1 = require("fs");
|
|
13
|
+
const path_1 = require("path");
|
|
14
|
+
const types_1 = require("./types");
|
|
7
15
|
let logFilePath;
|
|
8
|
-
|
|
16
|
+
function setLogFilePath(path) {
|
|
9
17
|
logFilePath = path;
|
|
10
18
|
}
|
|
11
19
|
class Logger {
|
|
@@ -14,20 +22,25 @@ class Logger {
|
|
|
14
22
|
throw new Error('Logger file path not set. Call setLogFilePath(path) before use.');
|
|
15
23
|
return logFilePath;
|
|
16
24
|
}
|
|
17
|
-
log(message, level = LOG_LEVEL_INFO) {
|
|
25
|
+
log(message, level = types_1.LOG_LEVEL_INFO) {
|
|
18
26
|
// Ensure log directory exists
|
|
19
27
|
try {
|
|
20
|
-
mkdirSync(dirname(this.logFile), { recursive: true });
|
|
28
|
+
(0, fs_1.mkdirSync)((0, path_1.dirname)(this.logFile), { recursive: true });
|
|
21
29
|
}
|
|
22
30
|
catch (err) {
|
|
23
31
|
// Directory may already exist, ignore
|
|
24
32
|
}
|
|
25
|
-
//
|
|
33
|
+
// Trim log file if it exceeds 3MB (keep last 1MB)
|
|
26
34
|
try {
|
|
27
|
-
const stats = statSync(this.logFile);
|
|
28
|
-
const maxSize =
|
|
35
|
+
const stats = (0, fs_1.statSync)(this.logFile);
|
|
36
|
+
const maxSize = 3 * 1024 * 1024;
|
|
37
|
+
const keepSize = 1024 * 1024;
|
|
29
38
|
if (stats.size > maxSize) {
|
|
30
|
-
|
|
39
|
+
const content = (0, fs_1.readFileSync)(this.logFile, 'utf8');
|
|
40
|
+
const trimmed = content.slice(-keepSize);
|
|
41
|
+
// Drop partial first line so we don't start mid-log
|
|
42
|
+
const firstNewline = trimmed.indexOf('\n');
|
|
43
|
+
(0, fs_1.writeFileSync)(this.logFile, firstNewline >= 0 ? trimmed.slice(firstNewline + 1) : trimmed);
|
|
31
44
|
}
|
|
32
45
|
}
|
|
33
46
|
catch (err) {
|
|
@@ -35,17 +48,17 @@ class Logger {
|
|
|
35
48
|
}
|
|
36
49
|
const timestamp = new Date().toISOString();
|
|
37
50
|
const logEntry = `[${timestamp}] [${level}] ${message}\n`;
|
|
38
|
-
appendFileSync(this.logFile, logEntry);
|
|
51
|
+
(0, fs_1.appendFileSync)(this.logFile, logEntry);
|
|
39
52
|
}
|
|
40
53
|
info(message) {
|
|
41
|
-
this.log(message, LOG_LEVEL_INFO);
|
|
54
|
+
this.log(message, types_1.LOG_LEVEL_INFO);
|
|
42
55
|
}
|
|
43
56
|
error(message) {
|
|
44
|
-
this.log(message, LOG_LEVEL_ERROR);
|
|
57
|
+
this.log(message, types_1.LOG_LEVEL_ERROR);
|
|
45
58
|
}
|
|
46
59
|
warn(message) {
|
|
47
|
-
this.log(message, LOG_LEVEL_WARN);
|
|
60
|
+
this.log(message, types_1.LOG_LEVEL_WARN);
|
|
48
61
|
}
|
|
49
62
|
}
|
|
50
|
-
|
|
63
|
+
exports.logger = new Logger();
|
|
51
64
|
//# sourceMappingURL=logger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../../../../../libs/opencode-plugin/.opencode/plugin/daytona/core/logger.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAaH,wCAEC;AAbD;;GAEG;AAEH,2BAAqF;AACrF,+BAA8B;AAE9B,mCAAyE;AAEzE,IAAI,WAA+B,CAAA;AAEnC,SAAgB,cAAc,CAAC,IAAY;IACzC,WAAW,GAAG,IAAI,CAAA;AACpB,CAAC;AAED,MAAM,MAAM;IACV,IAAY,OAAO;QACjB,IAAI,CAAC,WAAW;YAAE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAA;QACpG,OAAO,WAAW,CAAA;IACpB,CAAC;IAED,GAAG,CAAC,OAAe,EAAE,QAAkB,sBAAc;QACnD,8BAA8B;QAC9B,IAAI,CAAC;YACH,IAAA,cAAS,EAAC,IAAA,cAAO,EAAC,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QACvD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,sCAAsC;QACxC,CAAC;QACD,kDAAkD;QAClD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAA,aAAQ,EAAC,IAAI,CAAC,OAAO,CAAC,CAAA;YACpC,MAAM,OAAO,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAA;YAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAA;YAC5B,IAAI,KAAK,CAAC,IAAI,GAAG,OAAO,EAAE,CAAC;gBACzB,MAAM,OAAO,GAAG,IAAA,iBAAY,EAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;gBAClD,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAA;gBACxC,oDAAoD;gBACpD,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;gBAC1C,IAAA,kBAAa,EAAC,IAAI,CAAC,OAAO,EAAE,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAA;YAC5F,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,iCAAiC;QACnC,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;QAC1C,MAAM,QAAQ,GAAG,IAAI,SAAS,MAAM,KAAK,KAAK,OAAO,IAAI,CAAA;QACzD,IAAA,mBAAc,EAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IACxC,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,sBAAc,CAAC,CAAA;IACnC,CAAC;IAED,KAAK,CAAC,OAAe;QACnB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,uBAAe,CAAC,CAAA;IACpC,CAAC;IAED,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,sBAAc,CAAC,CAAA;IACnC,CAAC;CACF;AAEY,QAAA,MAAM,GAAG,IAAI,MAAM,EAAE,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Copyright 2025 Daytona Platforms Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import type { ProjectSessionData, SessionInfo } from './types';
|
|
6
6
|
export declare class ProjectDataStorage {
|
|
@@ -10,18 +10,23 @@ export declare class ProjectDataStorage {
|
|
|
10
10
|
* Get the file path for a project's session data
|
|
11
11
|
*/
|
|
12
12
|
private getProjectFilePath;
|
|
13
|
+
/**
|
|
14
|
+
* List known project IDs from storage.
|
|
15
|
+
*/
|
|
16
|
+
private listProjectIds;
|
|
13
17
|
/**
|
|
14
18
|
* Load project session data from disk
|
|
15
19
|
*/
|
|
16
20
|
load(projectId: string): ProjectSessionData | null;
|
|
17
21
|
/**
|
|
18
|
-
*
|
|
22
|
+
* Get a session for a project. If not found in the requested project, search all other
|
|
23
|
+
* projects on disk and, if found, migrate it into the requested project.
|
|
19
24
|
*/
|
|
20
|
-
|
|
25
|
+
getSession(projectId: string, worktree: string, sessionId: string): SessionInfo | undefined;
|
|
21
26
|
/**
|
|
22
|
-
*
|
|
27
|
+
* Save project session data to disk
|
|
23
28
|
*/
|
|
24
|
-
|
|
29
|
+
save(projectId: string, worktree: string, sessions: Record<string, SessionInfo>): void;
|
|
25
30
|
/**
|
|
26
31
|
* Get branch number for a sandbox
|
|
27
32
|
*/
|
|
@@ -35,4 +40,3 @@ export declare class ProjectDataStorage {
|
|
|
35
40
|
*/
|
|
36
41
|
removeSession(projectId: string, worktree: string, sessionId: string): void;
|
|
37
42
|
}
|
|
38
|
-
//# sourceMappingURL=project-data-storage.d.ts.map
|
|
@@ -1,24 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2025 Daytona Platforms Inc.
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ProjectDataStorage = void 0;
|
|
1
8
|
/**
|
|
2
9
|
* Handles file storage operations for project session data
|
|
3
10
|
* Stores data per-project in ~/.local/share/opencode/storage/daytona/{projectId}.json
|
|
4
11
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
12
|
+
const fs_1 = require("fs");
|
|
13
|
+
const path_1 = require("path");
|
|
14
|
+
const logger_1 = require("./logger");
|
|
15
|
+
class ProjectDataStorage {
|
|
9
16
|
storageDir;
|
|
10
17
|
constructor(storageDir) {
|
|
11
18
|
this.storageDir = storageDir;
|
|
12
19
|
// Ensure storage directory exists
|
|
13
|
-
if (!existsSync(this.storageDir)) {
|
|
14
|
-
mkdirSync(this.storageDir, { recursive: true });
|
|
20
|
+
if (!(0, fs_1.existsSync)(this.storageDir)) {
|
|
21
|
+
(0, fs_1.mkdirSync)(this.storageDir, { recursive: true });
|
|
15
22
|
}
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
18
25
|
* Get the file path for a project's session data
|
|
19
26
|
*/
|
|
20
27
|
getProjectFilePath(projectId) {
|
|
21
|
-
return join(this.storageDir, `${projectId}.json`);
|
|
28
|
+
return (0, path_1.join)(this.storageDir, `${projectId}.json`);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* List known project IDs from storage.
|
|
32
|
+
*/
|
|
33
|
+
listProjectIds() {
|
|
34
|
+
try {
|
|
35
|
+
return (0, fs_1.readdirSync)(this.storageDir)
|
|
36
|
+
.filter((name) => name.endsWith('.json'))
|
|
37
|
+
.map((name) => name.slice(0, -'.json'.length));
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
logger_1.logger.error(`Failed to list project data files: ${err}`);
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
22
43
|
}
|
|
23
44
|
/**
|
|
24
45
|
* Load project session data from disk
|
|
@@ -26,49 +47,73 @@ export class ProjectDataStorage {
|
|
|
26
47
|
load(projectId) {
|
|
27
48
|
const filePath = this.getProjectFilePath(projectId);
|
|
28
49
|
try {
|
|
29
|
-
if (existsSync(filePath)) {
|
|
30
|
-
return JSON.parse(readFileSync(filePath, 'utf-8'));
|
|
50
|
+
if ((0, fs_1.existsSync)(filePath)) {
|
|
51
|
+
return JSON.parse((0, fs_1.readFileSync)(filePath, 'utf-8'));
|
|
31
52
|
}
|
|
32
53
|
}
|
|
33
54
|
catch (err) {
|
|
34
|
-
logger.error(`Failed to load project data for ${projectId}: ${err}`);
|
|
55
|
+
logger_1.logger.error(`Failed to load project data for ${projectId}: ${err}`);
|
|
35
56
|
}
|
|
36
57
|
return null;
|
|
37
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Get a session for a project. If not found in the requested project, search all other
|
|
61
|
+
* projects on disk and, if found, migrate it into the requested project.
|
|
62
|
+
*/
|
|
63
|
+
getSession(projectId, worktree, sessionId) {
|
|
64
|
+
const current = this.load(projectId);
|
|
65
|
+
const currentSession = current?.sessions?.[sessionId];
|
|
66
|
+
if (currentSession) {
|
|
67
|
+
return currentSession;
|
|
68
|
+
}
|
|
69
|
+
// Look in other projects and migrate if found.
|
|
70
|
+
for (const otherProjectId of this.listProjectIds()) {
|
|
71
|
+
if (otherProjectId === projectId)
|
|
72
|
+
continue;
|
|
73
|
+
const otherData = this.load(otherProjectId);
|
|
74
|
+
const found = otherData?.sessions?.[sessionId];
|
|
75
|
+
if (!found)
|
|
76
|
+
continue;
|
|
77
|
+
const destination = current ?? {
|
|
78
|
+
projectId,
|
|
79
|
+
worktree,
|
|
80
|
+
sessions: {},
|
|
81
|
+
};
|
|
82
|
+
// Remove from source first (best effort).
|
|
83
|
+
try {
|
|
84
|
+
delete otherData.sessions[sessionId];
|
|
85
|
+
this.save(otherProjectId, otherData.worktree, otherData.sessions);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
logger_1.logger.warn(`Failed to remove session ${sessionId} from project ${otherProjectId}: ${err}`);
|
|
89
|
+
}
|
|
90
|
+
// Add to destination and persist.
|
|
91
|
+
destination.sessions[sessionId] = found;
|
|
92
|
+
// Prefer the worktree for the project we're actually operating on.
|
|
93
|
+
destination.worktree = worktree;
|
|
94
|
+
this.save(projectId, destination.worktree, destination.sessions);
|
|
95
|
+
logger_1.logger.info(`Migrated session ${sessionId} from project ${otherProjectId} to project ${projectId}`);
|
|
96
|
+
return found;
|
|
97
|
+
}
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
38
100
|
/**
|
|
39
101
|
* Save project session data to disk
|
|
40
102
|
*/
|
|
41
|
-
save(projectId, worktree, sessions
|
|
103
|
+
save(projectId, worktree, sessions) {
|
|
42
104
|
const filePath = this.getProjectFilePath(projectId);
|
|
43
105
|
const projectData = {
|
|
44
106
|
projectId,
|
|
45
107
|
worktree,
|
|
46
|
-
lastBranchNumber,
|
|
47
108
|
sessions,
|
|
48
109
|
};
|
|
49
110
|
try {
|
|
50
|
-
writeFileSync(filePath, JSON.stringify(projectData, null, 2));
|
|
51
|
-
logger.info(`Saved project data for ${projectId}`);
|
|
111
|
+
(0, fs_1.writeFileSync)(filePath, JSON.stringify(projectData, null, 2));
|
|
112
|
+
logger_1.logger.info(`Saved project data for ${projectId}`);
|
|
52
113
|
}
|
|
53
114
|
catch (err) {
|
|
54
|
-
logger.error(`Failed to save project data for ${projectId}: ${err}`);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Get the next available branch number for a project
|
|
59
|
-
*/
|
|
60
|
-
getNextBranchNumber(projectId) {
|
|
61
|
-
const projectData = this.load(projectId);
|
|
62
|
-
if (!projectData) {
|
|
63
|
-
return 1;
|
|
115
|
+
logger_1.logger.error(`Failed to save project data for ${projectId}: ${err}`);
|
|
64
116
|
}
|
|
65
|
-
const branchNumbers = Object.values(projectData.sessions)
|
|
66
|
-
.map(s => s.branchNumber)
|
|
67
|
-
.filter((n) => n !== undefined);
|
|
68
|
-
// Use a persisted monotonic pointer so we never reuse deleted numbers.
|
|
69
|
-
const pointer = projectData.lastBranchNumber ?? 0;
|
|
70
|
-
const maxInSessions = branchNumbers.length > 0 ? Math.max(...branchNumbers) : 0;
|
|
71
|
-
return Math.max(pointer, maxInSessions) + 1;
|
|
72
117
|
}
|
|
73
118
|
/**
|
|
74
119
|
* Get branch number for a sandbox
|
|
@@ -78,7 +123,7 @@ export class ProjectDataStorage {
|
|
|
78
123
|
if (!projectData) {
|
|
79
124
|
return undefined;
|
|
80
125
|
}
|
|
81
|
-
const session = Object.values(projectData.sessions).find(s => s.sandboxId === sandboxId);
|
|
126
|
+
const session = Object.values(projectData.sessions).find((s) => s.sandboxId === sandboxId);
|
|
82
127
|
return session?.branchNumber;
|
|
83
128
|
}
|
|
84
129
|
/**
|
|
@@ -88,32 +133,28 @@ export class ProjectDataStorage {
|
|
|
88
133
|
const projectData = this.load(projectId) || {
|
|
89
134
|
projectId,
|
|
90
135
|
worktree,
|
|
91
|
-
lastBranchNumber: 0,
|
|
92
136
|
sessions: {},
|
|
93
137
|
};
|
|
94
138
|
const now = Date.now();
|
|
95
139
|
if (!projectData.sessions[sessionId]) {
|
|
96
|
-
// Assign branch number if not provided
|
|
97
|
-
const assignedBranchNumber = branchNumber ?? this.getNextBranchNumber(projectId);
|
|
98
140
|
projectData.sessions[sessionId] = {
|
|
99
141
|
sandboxId,
|
|
100
|
-
branchNumber:
|
|
142
|
+
...(branchNumber !== undefined ? { branchNumber } : {}),
|
|
101
143
|
created: now,
|
|
102
144
|
lastAccessed: now,
|
|
103
145
|
};
|
|
104
|
-
projectData.lastBranchNumber = Math.max(projectData.lastBranchNumber ?? 0, assignedBranchNumber);
|
|
105
146
|
}
|
|
106
147
|
else {
|
|
107
148
|
projectData.sessions[sessionId].sandboxId = sandboxId;
|
|
108
149
|
projectData.sessions[sessionId].lastAccessed = now;
|
|
109
150
|
// Only update branch number if it wasn't set before
|
|
110
151
|
if (projectData.sessions[sessionId].branchNumber === undefined) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
152
|
+
if (branchNumber !== undefined) {
|
|
153
|
+
projectData.sessions[sessionId].branchNumber = branchNumber;
|
|
154
|
+
}
|
|
114
155
|
}
|
|
115
156
|
}
|
|
116
|
-
this.save(projectId, worktree, projectData.sessions
|
|
157
|
+
this.save(projectId, worktree, projectData.sessions);
|
|
117
158
|
}
|
|
118
159
|
/**
|
|
119
160
|
* Remove a session from the project file
|
|
@@ -122,9 +163,9 @@ export class ProjectDataStorage {
|
|
|
122
163
|
const projectData = this.load(projectId);
|
|
123
164
|
if (projectData && projectData.sessions[sessionId]) {
|
|
124
165
|
delete projectData.sessions[sessionId];
|
|
125
|
-
|
|
126
|
-
this.save(projectId, worktree, projectData.sessions, projectData.lastBranchNumber);
|
|
166
|
+
this.save(projectId, worktree, projectData.sessions);
|
|
127
167
|
}
|
|
128
168
|
}
|
|
129
169
|
}
|
|
170
|
+
exports.ProjectDataStorage = ProjectDataStorage;
|
|
130
171
|
//# sourceMappingURL=project-data-storage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-data-storage.js","sourceRoot":"","sources":["
|
|
1
|
+
{"version":3,"file":"project-data-storage.js","sourceRoot":"","sources":["../../../../../../../libs/opencode-plugin/.opencode/plugin/daytona/core/project-data-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2025 Daytona Platforms Inc.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
1
5
|
/**
|
|
2
6
|
* Manages Daytona sandbox sessions and persists session-sandbox mappings
|
|
3
7
|
* Stores data per-project in ~/.local/share/opencode/storage/daytona/{projectId}.json
|
|
@@ -40,4 +44,3 @@ export declare class DaytonaSessionManager {
|
|
|
40
44
|
*/
|
|
41
45
|
deleteSandbox(sessionId: string, projectId: string): Promise<void>;
|
|
42
46
|
}
|
|
43
|
-
//# sourceMappingURL=session-manager.d.ts.map
|
|
@@ -1,13 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright 2025 Daytona Platforms Inc.
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.DaytonaSessionManager = void 0;
|
|
1
8
|
/**
|
|
2
9
|
* Manages Daytona sandbox sessions and persists session-sandbox mappings
|
|
3
10
|
* Stores data per-project in ~/.local/share/opencode/storage/daytona/{projectId}.json
|
|
4
11
|
*/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
12
|
+
const sdk_1 = require("@daytonaio/sdk");
|
|
13
|
+
const logger_1 = require("./logger");
|
|
14
|
+
const session_git_manager_1 = require("../git/session-git-manager");
|
|
15
|
+
const sandbox_git_manager_1 = require("../git/sandbox-git-manager");
|
|
16
|
+
const project_data_storage_1 = require("./project-data-storage");
|
|
17
|
+
const toast_1 = require("./toast");
|
|
18
|
+
class DaytonaSessionManager {
|
|
11
19
|
apiKey;
|
|
12
20
|
dataStorage;
|
|
13
21
|
sessionSandboxes;
|
|
@@ -15,7 +23,7 @@ export class DaytonaSessionManager {
|
|
|
15
23
|
repoPath;
|
|
16
24
|
constructor(apiKey, storageDir, repoPath) {
|
|
17
25
|
this.apiKey = apiKey;
|
|
18
|
-
this.dataStorage = new ProjectDataStorage(storageDir);
|
|
26
|
+
this.dataStorage = new project_data_storage_1.ProjectDataStorage(storageDir);
|
|
19
27
|
this.repoPath = repoPath;
|
|
20
28
|
this.sessionSandboxes = new Map();
|
|
21
29
|
}
|
|
@@ -40,7 +48,7 @@ export class DaytonaSessionManager {
|
|
|
40
48
|
for (const [sessionId, sessionInfo] of Object.entries(projectData.sessions)) {
|
|
41
49
|
this.sessionSandboxes.set(sessionId, { id: sessionInfo.sandboxId });
|
|
42
50
|
}
|
|
43
|
-
logger.info(`Loaded ${Object.keys(projectData.sessions).length} sessions for project ${projectId}`);
|
|
51
|
+
logger_1.logger.info(`Loaded ${Object.keys(projectData.sessions).length} sessions for project ${projectId}`);
|
|
44
52
|
}
|
|
45
53
|
}
|
|
46
54
|
/**
|
|
@@ -49,6 +57,7 @@ export class DaytonaSessionManager {
|
|
|
49
57
|
setProjectContext(projectId) {
|
|
50
58
|
if (this.currentProjectId !== projectId) {
|
|
51
59
|
this.currentProjectId = projectId;
|
|
60
|
+
this.sessionSandboxes.clear();
|
|
52
61
|
this.loadProjectSessions(projectId);
|
|
53
62
|
}
|
|
54
63
|
}
|
|
@@ -63,11 +72,11 @@ export class DaytonaSessionManager {
|
|
|
63
72
|
*/
|
|
64
73
|
async getSandbox(sessionId, projectId, worktree, pluginCtx) {
|
|
65
74
|
if (pluginCtx?.client?.tui) {
|
|
66
|
-
toast.initialize(pluginCtx.client.tui);
|
|
75
|
+
toast_1.toast.initialize(pluginCtx.client.tui);
|
|
67
76
|
}
|
|
68
77
|
if (!this.apiKey) {
|
|
69
|
-
logger.error('DAYTONA_API_KEY is not set. Cannot create or retrieve sandbox.');
|
|
70
|
-
toast.show({
|
|
78
|
+
logger_1.logger.error('DAYTONA_API_KEY is not set. Cannot create or retrieve sandbox.');
|
|
79
|
+
toast_1.toast.show({
|
|
71
80
|
title: 'Sandbox error',
|
|
72
81
|
message: 'DAYTONA_API_KEY is not set. Please set the environment variable to use Daytona sandboxes.',
|
|
73
82
|
variant: 'error',
|
|
@@ -82,7 +91,7 @@ export class DaytonaSessionManager {
|
|
|
82
91
|
// Refresh sandbox state and ensure it's running
|
|
83
92
|
await existing.refreshData();
|
|
84
93
|
if (existing.state !== 'started') {
|
|
85
|
-
logger.info(`Starting sandbox ${existing.id} (current state: ${existing.state})`);
|
|
94
|
+
logger_1.logger.info(`Starting sandbox ${existing.id} (current state: ${existing.state})`);
|
|
86
95
|
await existing.start();
|
|
87
96
|
}
|
|
88
97
|
this.dataStorage.updateSession(projectId, worktree, sessionId, existing.id);
|
|
@@ -90,50 +99,99 @@ export class DaytonaSessionManager {
|
|
|
90
99
|
}
|
|
91
100
|
// If we have a sandboxId but not a full sandbox object, reconnect to it
|
|
92
101
|
if (this.isPartiallyInitialized(existing)) {
|
|
93
|
-
logger.info(`Reconnecting to existing sandbox: ${existing.id}`);
|
|
94
|
-
const daytona = new Daytona({ apiKey: this.apiKey });
|
|
102
|
+
logger_1.logger.info(`Reconnecting to existing sandbox: ${existing.id}`);
|
|
103
|
+
const daytona = new sdk_1.Daytona({ apiKey: this.apiKey });
|
|
104
|
+
const reconnectStart = Date.now();
|
|
105
|
+
logger_1.logger.info(`Daytona get begin sandboxId=${existing.id}`);
|
|
95
106
|
const sandbox = await daytona.get(existing.id);
|
|
107
|
+
logger_1.logger.info(`Daytona get done sandboxId=${existing.id} in ${Date.now() - reconnectStart}ms`);
|
|
108
|
+
logger_1.logger.info(`Starting sandbox begin sandboxId=${sandbox.id}`);
|
|
96
109
|
await sandbox.start();
|
|
110
|
+
logger_1.logger.info(`Starting sandbox done sandboxId=${sandbox.id} in ${Date.now() - reconnectStart}ms`);
|
|
97
111
|
this.sessionSandboxes.set(sessionId, sandbox);
|
|
98
112
|
// Preserve branch number if it exists for this sandbox
|
|
99
113
|
let branchNumber = this.dataStorage.getBranchNumberForSandbox(projectId, sandbox.id);
|
|
100
114
|
if (!branchNumber) {
|
|
101
|
-
|
|
115
|
+
try {
|
|
116
|
+
branchNumber = session_git_manager_1.SessionGitManager.allocateAndReserveBranchNumber(worktree);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// No local git repo (or git unavailable) shouldn't block sandbox usage.
|
|
120
|
+
branchNumber = undefined;
|
|
121
|
+
}
|
|
102
122
|
}
|
|
103
123
|
this.dataStorage.updateSession(projectId, worktree, sessionId, sandbox.id, branchNumber);
|
|
104
|
-
toast.show({
|
|
124
|
+
toast_1.toast.show({
|
|
105
125
|
title: 'Sandbox connected',
|
|
106
126
|
message: `Connected to existing sandbox.`,
|
|
107
127
|
variant: 'info',
|
|
108
128
|
});
|
|
129
|
+
// Even if git syncing is disabled, ensure the project directory exists in the sandbox.
|
|
130
|
+
if (!branchNumber) {
|
|
131
|
+
try {
|
|
132
|
+
await new sandbox_git_manager_1.DaytonaSandboxGitManager(sandbox, this.repoPath).ensureDirectory();
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
logger_1.logger.warn(`Failed to ensure sandbox project directory exists: ${err}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
109
138
|
return sandbox;
|
|
110
139
|
}
|
|
140
|
+
// If not in cache/storage for this project, try to recover from other projects and migrate.
|
|
141
|
+
if (!existing) {
|
|
142
|
+
const migrated = this.dataStorage.getSession(projectId, worktree, sessionId);
|
|
143
|
+
if (migrated?.sandboxId) {
|
|
144
|
+
logger_1.logger.info(`Recovered session ${sessionId} for project ${projectId} (migrated from another project)`);
|
|
145
|
+
this.sessionSandboxes.set(sessionId, { id: migrated.sandboxId });
|
|
146
|
+
// Re-run getSandbox to go through the normal reconnect path.
|
|
147
|
+
return this.getSandbox(sessionId, projectId, worktree, pluginCtx);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
111
150
|
// Otherwise, create a new sandbox
|
|
112
|
-
logger.info(`Creating new sandbox for session: ${sessionId} in project: ${projectId}`);
|
|
113
|
-
const daytona = new Daytona({ apiKey: this.apiKey });
|
|
114
|
-
const
|
|
151
|
+
logger_1.logger.info(`Creating new sandbox for session: ${sessionId} in project: ${projectId}`);
|
|
152
|
+
const daytona = new sdk_1.Daytona({ apiKey: this.apiKey });
|
|
153
|
+
const createStart = Date.now();
|
|
154
|
+
logger_1.logger.info(`Daytona create begin sessionId=${sessionId}`);
|
|
155
|
+
const waitingLog = setTimeout(() => {
|
|
156
|
+
logger_1.logger.warn(`Daytona create still waiting after ${Date.now() - createStart}ms (sessionId=${sessionId})`);
|
|
157
|
+
}, 15_000);
|
|
158
|
+
const sandbox = await daytona.create().finally(() => clearTimeout(waitingLog));
|
|
159
|
+
logger_1.logger.info(`Daytona create done sessionId=${sessionId} sandboxId=${sandbox.id} in ${Date.now() - createStart}ms`);
|
|
115
160
|
this.sessionSandboxes.set(sessionId, sandbox);
|
|
116
161
|
// Get or assign branch number for this sandbox
|
|
117
162
|
let branchNumber = this.dataStorage.getBranchNumberForSandbox(projectId, sandbox.id);
|
|
118
163
|
if (!branchNumber) {
|
|
119
|
-
|
|
164
|
+
try {
|
|
165
|
+
branchNumber = session_git_manager_1.SessionGitManager.allocateAndReserveBranchNumber(worktree);
|
|
166
|
+
}
|
|
167
|
+
catch (err) {
|
|
168
|
+
logger_1.logger.warn(`allocateAndReserveBranchNumber failed sessionId=${sessionId}: ${err}`);
|
|
169
|
+
// No local git repo (or git unavailable) shouldn't block sandbox usage.
|
|
170
|
+
branchNumber = undefined;
|
|
171
|
+
}
|
|
120
172
|
}
|
|
121
173
|
this.dataStorage.updateSession(projectId, worktree, sessionId, sandbox.id, branchNumber);
|
|
122
|
-
logger.info(`Sandbox created successfully: ${sandbox.id} with branch number ${branchNumber}`);
|
|
174
|
+
logger_1.logger.info(`Sandbox created successfully: ${sandbox.id}${branchNumber ? ` with branch number ${branchNumber}` : ''}`);
|
|
123
175
|
// Initialize git repo in the sandbox and sync with host
|
|
124
176
|
try {
|
|
125
|
-
|
|
126
|
-
|
|
177
|
+
if (branchNumber) {
|
|
178
|
+
const sessionGit = new session_git_manager_1.SessionGitManager(sandbox, this.repoPath, worktree, branchNumber);
|
|
179
|
+
await sessionGit.initializeAndSync(pluginCtx);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
// Git disabled; still ensure the directory exists so tools can operate.
|
|
183
|
+
await new sandbox_git_manager_1.DaytonaSandboxGitManager(sandbox, this.repoPath).ensureDirectory();
|
|
184
|
+
}
|
|
127
185
|
}
|
|
128
186
|
catch (err) {
|
|
129
|
-
logger.error(`Failed to initialize git repo or push local changes in sandbox: ${err}`);
|
|
130
|
-
toast.show({
|
|
187
|
+
logger_1.logger.error(`Failed to initialize git repo or push local changes in sandbox: ${err}`);
|
|
188
|
+
toast_1.toast.show({
|
|
131
189
|
title: 'Git error',
|
|
132
190
|
message: err?.message || 'Failed to initialize git repo in sandbox.',
|
|
133
191
|
variant: 'error',
|
|
134
192
|
});
|
|
135
193
|
}
|
|
136
|
-
toast.show({
|
|
194
|
+
toast_1.toast.show({
|
|
137
195
|
title: 'Sandbox created',
|
|
138
196
|
message: `Created new sandbox for session.`,
|
|
139
197
|
variant: 'success',
|
|
@@ -147,22 +205,22 @@ export class DaytonaSessionManager {
|
|
|
147
205
|
let sandbox = this.sessionSandboxes.get(sessionId);
|
|
148
206
|
// If not in cache, try to load from storage and reconnect
|
|
149
207
|
if (!sandbox || this.isPartiallyInitialized(sandbox)) {
|
|
150
|
-
const
|
|
151
|
-
const sessionInfo =
|
|
208
|
+
const storedWorktree = this.dataStorage.load(projectId)?.worktree ?? '';
|
|
209
|
+
const sessionInfo = this.dataStorage.getSession(projectId, storedWorktree, sessionId);
|
|
152
210
|
if (sessionInfo?.sandboxId) {
|
|
153
|
-
const daytona = new Daytona({ apiKey: this.apiKey });
|
|
211
|
+
const daytona = new sdk_1.Daytona({ apiKey: this.apiKey });
|
|
154
212
|
try {
|
|
155
213
|
sandbox = await daytona.get(sessionInfo.sandboxId);
|
|
156
214
|
this.sessionSandboxes.set(sessionId, sandbox);
|
|
157
215
|
}
|
|
158
216
|
catch (err) {
|
|
159
|
-
logger.error(`Failed to reconnect to sandbox ${sessionInfo.sandboxId}: ${err}`);
|
|
217
|
+
logger_1.logger.error(`Failed to reconnect to sandbox ${sessionInfo.sandboxId}: ${err}`);
|
|
160
218
|
}
|
|
161
219
|
}
|
|
162
220
|
}
|
|
163
221
|
// Delete the sandbox if we have a fully initialized one
|
|
164
222
|
if (this.isFullyInitialized(sandbox)) {
|
|
165
|
-
logger.info(`Removing sandbox for session: ${sessionId}`);
|
|
223
|
+
logger_1.logger.info(`Removing sandbox for session: ${sessionId}`);
|
|
166
224
|
await sandbox.delete();
|
|
167
225
|
this.sessionSandboxes.delete(sessionId);
|
|
168
226
|
// Remove from storage
|
|
@@ -170,11 +228,12 @@ export class DaytonaSessionManager {
|
|
|
170
228
|
if (projectData) {
|
|
171
229
|
this.dataStorage.removeSession(projectId, projectData.worktree, sessionId);
|
|
172
230
|
}
|
|
173
|
-
logger.info(`Sandbox deleted successfully.`);
|
|
231
|
+
logger_1.logger.info(`Sandbox deleted successfully.`);
|
|
174
232
|
}
|
|
175
233
|
else {
|
|
176
|
-
logger.warn(`No sandbox found for session: ${sessionId}`);
|
|
234
|
+
logger_1.logger.warn(`No sandbox found for session: ${sessionId}`);
|
|
177
235
|
}
|
|
178
236
|
}
|
|
179
237
|
}
|
|
238
|
+
exports.DaytonaSessionManager = DaytonaSessionManager;
|
|
180
239
|
//# sourceMappingURL=session-manager.js.map
|