@jamesmurdza/opencode-daytona 0.1.15 → 0.1.16

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 (135) hide show
  1. package/.opencode/plugin/daytona/core/logger.d.ts +15 -0
  2. package/.opencode/plugin/daytona/core/logger.d.ts.map +1 -0
  3. package/.opencode/plugin/daytona/core/logger.js +43 -0
  4. package/.opencode/plugin/daytona/core/logger.js.map +1 -0
  5. package/.opencode/plugin/daytona/core/project-data-storage.d.ts +38 -0
  6. package/.opencode/plugin/daytona/core/project-data-storage.d.ts.map +1 -0
  7. package/.opencode/plugin/daytona/core/project-data-storage.js +130 -0
  8. package/.opencode/plugin/daytona/core/project-data-storage.js.map +1 -0
  9. package/.opencode/plugin/daytona/core/session-manager.d.ts +42 -0
  10. package/.opencode/plugin/daytona/core/session-manager.d.ts.map +1 -0
  11. package/.opencode/plugin/daytona/core/session-manager.js +151 -0
  12. package/.opencode/plugin/daytona/core/session-manager.js.map +1 -0
  13. package/.opencode/plugin/daytona/core/types.d.ts +51 -0
  14. package/.opencode/plugin/daytona/core/types.d.ts.map +1 -0
  15. package/.opencode/plugin/daytona/core/types.js +11 -0
  16. package/.opencode/plugin/daytona/core/types.js.map +1 -0
  17. package/.opencode/plugin/daytona/git/host-git-manager.d.ts +13 -0
  18. package/.opencode/plugin/daytona/git/host-git-manager.d.ts.map +1 -0
  19. package/.opencode/plugin/daytona/git/host-git-manager.js +97 -0
  20. package/.opencode/plugin/daytona/git/host-git-manager.js.map +1 -0
  21. package/.opencode/plugin/daytona/git/index.d.ts +2 -0
  22. package/.opencode/plugin/daytona/git/index.d.ts.map +1 -0
  23. package/.opencode/plugin/daytona/git/index.js +2 -0
  24. package/.opencode/plugin/daytona/git/index.js.map +1 -0
  25. package/.opencode/plugin/daytona/git/sandbox-git-manager.d.ts +10 -0
  26. package/.opencode/plugin/daytona/git/sandbox-git-manager.d.ts.map +1 -0
  27. package/.opencode/plugin/daytona/git/sandbox-git-manager.js +49 -0
  28. package/.opencode/plugin/daytona/git/sandbox-git-manager.js.map +1 -0
  29. package/.opencode/plugin/daytona/git/session-git-manager.d.ts +25 -0
  30. package/.opencode/plugin/daytona/git/session-git-manager.d.ts.map +1 -0
  31. package/.opencode/plugin/daytona/git/session-git-manager.js +52 -0
  32. package/.opencode/plugin/daytona/git/session-git-manager.js.map +1 -0
  33. package/.opencode/plugin/daytona/index.d.ts +26 -0
  34. package/.opencode/plugin/daytona/index.d.ts.map +1 -0
  35. package/.opencode/plugin/daytona/index.js +37 -0
  36. package/.opencode/plugin/daytona/index.js.map +1 -0
  37. package/.opencode/plugin/daytona/plugins/custom-tools.d.ts +8 -0
  38. package/.opencode/plugin/daytona/plugins/custom-tools.d.ts.map +1 -0
  39. package/.opencode/plugin/daytona/plugins/custom-tools.js +17 -0
  40. package/.opencode/plugin/daytona/plugins/custom-tools.js.map +1 -0
  41. package/.opencode/plugin/daytona/plugins/index.d.ts +8 -0
  42. package/.opencode/plugin/daytona/plugins/index.d.ts.map +1 -0
  43. package/.opencode/plugin/daytona/plugins/{index.ts → index.js} +5 -5
  44. package/.opencode/plugin/daytona/plugins/index.js.map +1 -0
  45. package/.opencode/plugin/daytona/plugins/session-cleanup.d.ts +8 -0
  46. package/.opencode/plugin/daytona/plugins/session-cleanup.d.ts.map +1 -0
  47. package/.opencode/plugin/daytona/plugins/session-cleanup.js +19 -0
  48. package/.opencode/plugin/daytona/plugins/session-cleanup.js.map +1 -0
  49. package/.opencode/plugin/daytona/plugins/session-idle-auto-commit.d.ts +7 -0
  50. package/.opencode/plugin/daytona/plugins/session-idle-auto-commit.d.ts.map +1 -0
  51. package/.opencode/plugin/daytona/plugins/session-idle-auto-commit.js +28 -0
  52. package/.opencode/plugin/daytona/plugins/session-idle-auto-commit.js.map +1 -0
  53. package/.opencode/plugin/daytona/plugins/system-transform.d.ts +7 -0
  54. package/.opencode/plugin/daytona/plugins/system-transform.d.ts.map +1 -0
  55. package/.opencode/plugin/daytona/plugins/system-transform.js +20 -0
  56. package/.opencode/plugin/daytona/plugins/system-transform.js.map +1 -0
  57. package/.opencode/plugin/daytona/tools/bash.d.ts +15 -0
  58. package/.opencode/plugin/daytona/tools/bash.d.ts.map +1 -0
  59. package/.opencode/plugin/daytona/tools/bash.js +31 -0
  60. package/.opencode/plugin/daytona/tools/bash.js.map +1 -0
  61. package/.opencode/plugin/daytona/tools/edit.d.ts +17 -0
  62. package/.opencode/plugin/daytona/tools/edit.d.ts.map +1 -0
  63. package/.opencode/plugin/daytona/tools/edit.js +19 -0
  64. package/.opencode/plugin/daytona/tools/edit.js.map +1 -0
  65. package/.opencode/plugin/daytona/tools/get-preview-url.d.ts +13 -0
  66. package/.opencode/plugin/daytona/tools/get-preview-url.d.ts.map +1 -0
  67. package/.opencode/plugin/daytona/tools/get-preview-url.js +13 -0
  68. package/.opencode/plugin/daytona/tools/get-preview-url.js.map +1 -0
  69. package/.opencode/plugin/daytona/tools/glob.d.ts +13 -0
  70. package/.opencode/plugin/daytona/tools/glob.d.ts.map +1 -0
  71. package/.opencode/plugin/daytona/tools/glob.js +17 -0
  72. package/.opencode/plugin/daytona/tools/glob.js.map +1 -0
  73. package/.opencode/plugin/daytona/tools/grep.d.ts +13 -0
  74. package/.opencode/plugin/daytona/tools/grep.d.ts.map +1 -0
  75. package/.opencode/plugin/daytona/tools/grep.js +17 -0
  76. package/.opencode/plugin/daytona/tools/grep.js.map +1 -0
  77. package/.opencode/plugin/daytona/tools/ls.d.ts +13 -0
  78. package/.opencode/plugin/daytona/tools/ls.d.ts.map +1 -0
  79. package/.opencode/plugin/daytona/tools/ls.js +18 -0
  80. package/.opencode/plugin/daytona/tools/ls.js.map +1 -0
  81. package/.opencode/plugin/daytona/tools/lsp.d.ts +17 -0
  82. package/.opencode/plugin/daytona/tools/lsp.d.ts.map +1 -0
  83. package/.opencode/plugin/daytona/tools/lsp.js +13 -0
  84. package/.opencode/plugin/daytona/tools/lsp.js.map +1 -0
  85. package/.opencode/plugin/daytona/tools/multiedit.d.ts +21 -0
  86. package/.opencode/plugin/daytona/tools/multiedit.d.ts.map +1 -0
  87. package/.opencode/plugin/daytona/tools/multiedit.js +23 -0
  88. package/.opencode/plugin/daytona/tools/multiedit.js.map +1 -0
  89. package/.opencode/plugin/daytona/tools/patch.d.ts +17 -0
  90. package/.opencode/plugin/daytona/tools/patch.d.ts.map +1 -0
  91. package/.opencode/plugin/daytona/tools/patch.js +19 -0
  92. package/.opencode/plugin/daytona/tools/patch.js.map +1 -0
  93. package/.opencode/plugin/daytona/tools/read.d.ts +13 -0
  94. package/.opencode/plugin/daytona/tools/read.d.ts.map +1 -0
  95. package/.opencode/plugin/daytona/tools/read.js +14 -0
  96. package/.opencode/plugin/daytona/tools/read.js.map +1 -0
  97. package/.opencode/plugin/daytona/tools/write.d.ts +15 -0
  98. package/.opencode/plugin/daytona/tools/write.d.ts.map +1 -0
  99. package/.opencode/plugin/daytona/tools/write.js +14 -0
  100. package/.opencode/plugin/daytona/tools/write.js.map +1 -0
  101. package/.opencode/plugin/daytona/tools.d.ts +130 -0
  102. package/.opencode/plugin/daytona/tools.d.ts.map +1 -0
  103. package/.opencode/plugin/daytona/tools.js +30 -0
  104. package/.opencode/plugin/daytona/tools.js.map +1 -0
  105. package/.opencode/plugin/index.d.ts +6 -0
  106. package/.opencode/plugin/index.d.ts.map +1 -0
  107. package/.opencode/plugin/{index.ts → index.js} +2 -1
  108. package/.opencode/plugin/index.js.map +1 -0
  109. package/README.md +192 -0
  110. package/package.json +6 -1
  111. package/.opencode/plugin/daytona/core/logger.ts +0 -50
  112. package/.opencode/plugin/daytona/core/project-data-storage.ts +0 -154
  113. package/.opencode/plugin/daytona/core/session-manager.ts +0 -170
  114. package/.opencode/plugin/daytona/core/types.ts +0 -68
  115. package/.opencode/plugin/daytona/git/host-git-manager.ts +0 -94
  116. package/.opencode/plugin/daytona/git/index.ts +0 -1
  117. package/.opencode/plugin/daytona/git/sandbox-git-manager.ts +0 -51
  118. package/.opencode/plugin/daytona/git/session-git-manager.ts +0 -65
  119. package/.opencode/plugin/daytona/index.ts +0 -50
  120. package/.opencode/plugin/daytona/plugins/custom-tools.ts +0 -20
  121. package/.opencode/plugin/daytona/plugins/session-cleanup.ts +0 -22
  122. package/.opencode/plugin/daytona/plugins/session-idle-auto-commit.ts +0 -30
  123. package/.opencode/plugin/daytona/plugins/system-transform.ts +0 -28
  124. package/.opencode/plugin/daytona/tools/bash.ts +0 -32
  125. package/.opencode/plugin/daytona/tools/edit.ts +0 -21
  126. package/.opencode/plugin/daytona/tools/get-preview-url.ts +0 -15
  127. package/.opencode/plugin/daytona/tools/glob.ts +0 -16
  128. package/.opencode/plugin/daytona/tools/grep.ts +0 -16
  129. package/.opencode/plugin/daytona/tools/ls.ts +0 -18
  130. package/.opencode/plugin/daytona/tools/lsp.ts +0 -15
  131. package/.opencode/plugin/daytona/tools/multiedit.ts +0 -32
  132. package/.opencode/plugin/daytona/tools/patch.ts +0 -21
  133. package/.opencode/plugin/daytona/tools/read.ts +0 -16
  134. package/.opencode/plugin/daytona/tools/write.ts +0 -16
  135. package/.opencode/plugin/daytona/tools.ts +0 -33
@@ -1,94 +0,0 @@
1
- import { logger } from '../core/logger'
2
- import { exec, execSync } from 'child_process'
3
-
4
- function execSyncSilent(cmd: string, options: any = {}) {
5
- return execSync(cmd, { stdio: 'ignore', ...options })
6
- }
7
-
8
- export class HostGitManager {
9
- // No constructor needed; use global logger
10
-
11
- /**
12
- * Pushes local changes to the sandbox remote, following the same steps as the standalone function.
13
- * @param sshUrl The SSH URL of the sandbox remote.
14
- * @param branch The branch to push to.
15
- */
16
- pushLocalToSandboxRemote(sshUrl: string, branch: string): void {
17
- try {
18
- logger.info(`Init in current directory, pushing to ${sshUrl} on branch ${branch}`)
19
- try {
20
- execSyncSilent('git rev-parse --is-inside-work-tree')
21
- } catch {
22
- execSyncSilent('git init')
23
- }
24
- try {
25
- execSyncSilent('git remote get-url sandbox')
26
- execSyncSilent(`git remote set-url sandbox ${sshUrl}`)
27
- } catch (e) {
28
- execSyncSilent(`git remote add sandbox ${sshUrl}`)
29
- }
30
- execSyncSilent('git add .')
31
- execSyncSilent('git commit -m "Sync local changes before agent start" || echo "No changes to commit"', {
32
- shell: '/bin/bash',
33
- })
34
- execSyncSilent(`git push sandbox HEAD:${branch}`)
35
- logger.info('✓ Pushed local changes to sandbox')
36
- } catch (e) {
37
- logger.error(`Error pushing to sandbox: ${e}`)
38
- }
39
- }
40
-
41
- ensureRepo(): void {
42
- try {
43
- execSyncSilent('git rev-parse --is-inside-work-tree')
44
- logger.info('Git repo already exists in local worktree.')
45
- } catch {
46
- execSyncSilent('git init')
47
- logger.info('Initialized new git repo in local worktree.')
48
- }
49
- }
50
-
51
- setRemote(remoteName: string, sshUrl: string): void {
52
- try {
53
- // remove existing remote if it exists
54
- execSyncSilent(`git remote remove ${remoteName} || true`)
55
- execSyncSilent(`git remote add ${remoteName} ${sshUrl}`)
56
- } catch (e) {
57
- logger.warn(`Could not set sandbox remote: ${e}`)
58
- }
59
- }
60
-
61
- pull(remoteName: string, branch: string, localBranch?: string): void {
62
- let attempts = 0
63
- // The first pull attempt sometimes fails. I'm not sure what the cause is.
64
- while (attempts < 3) {
65
- try {
66
- if (localBranch) {
67
- // Fetch the remote branch into the specified local branch
68
- execSyncSilent(`git fetch ${remoteName} ${branch}:${localBranch}`)
69
- logger.info(`✓ Fetched latest changes from sandbox into ${localBranch}`)
70
- } else {
71
- execSyncSilent(`git pull ${remoteName} ${branch}`)
72
- logger.info('✓ Pulled latest changes from sandbox')
73
- }
74
- return
75
- } catch (e) {
76
- attempts++
77
- if (attempts >= 3) {
78
- logger.error(`Error pulling from sandbox after 3 attempts: ${e}`)
79
- } else {
80
- logger.warn(`Pull attempt ${attempts} failed, retrying...`)
81
- }
82
- }
83
- }
84
- }
85
-
86
- push(remoteName: string, branch: string): void {
87
- try {
88
- execSyncSilent(`git push ${remoteName} HEAD:${branch}`)
89
- logger.info('✓ Pushed changes to sandbox')
90
- } catch (e) {
91
- logger.error(`Error pushing to sandbox: ${e}`)
92
- }
93
- }
94
- }
@@ -1 +0,0 @@
1
- export { SessionGitManager } from './session-git-manager'
@@ -1,51 +0,0 @@
1
- import type { Sandbox } from '@daytonaio/sdk'
2
- import { logger } from '../core/logger'
3
-
4
- export class DaytonaSandboxGitManager {
5
- constructor(
6
- private readonly sandbox: Sandbox,
7
- private readonly repoPath: string,
8
- ) {}
9
-
10
- async ensureRepo(): Promise<void> {
11
- await this.sandbox.process.executeCommand(`mkdir -p ${this.repoPath}`)
12
- const isGit = await this.sandbox.process.executeCommand('git rev-parse --is-inside-work-tree', this.repoPath)
13
- if (!isGit || isGit.result.trim() !== 'true') {
14
- await this.sandbox.process.executeCommand('git init', this.repoPath)
15
- await this.sandbox.process.executeCommand('git config user.email "sandbox@example.com"', this.repoPath)
16
- await this.sandbox.process.executeCommand('git config user.name "Daytona Sandbox"', this.repoPath)
17
- logger.info(`Initialized git repo in sandbox at ${this.repoPath}`)
18
- }
19
- }
20
-
21
- async autoCommit(): Promise<void> {
22
- try {
23
- await this.sandbox.process.executeCommand('git add .', this.repoPath)
24
- await this.sandbox.process.executeCommand(
25
- 'git commit -am "Auto-commit from Daytona plugin" || true',
26
- this.repoPath,
27
- )
28
- logger.info(`Auto-committed changes in sandbox at ${this.repoPath}`)
29
- } catch (err) {
30
- logger.error(`Failed to auto-commit in sandbox at ${this.repoPath}: ${err}`)
31
- }
32
- }
33
-
34
- async resetToRemote(branch: string): Promise<void> {
35
- try {
36
- const result = await this.sandbox.process.executeCommand(`git checkout -B ${branch}`, this.repoPath)
37
- logger.info(`Checked out branch '${branch}': ${result.result}`)
38
- await this.sandbox.process.executeCommand('git reset --hard', this.repoPath)
39
- await this.sandbox.process.executeCommand('git clean -fd', this.repoPath)
40
- logger.info('Reset sandbox worktree to pushed state.')
41
- const statusResult = await this.sandbox.process.executeCommand('git status --porcelain', this.repoPath)
42
- if (statusResult.result.trim()) {
43
- logger.warn(`Sandbox has uncommitted changes after reset:\n${statusResult.result}`)
44
- } else {
45
- logger.info('No uncommitted changes in sandbox after reset.')
46
- }
47
- } catch (err) {
48
- logger.error(`Failed to reset sandbox worktree: ${err}`)
49
- }
50
- }
51
- }
@@ -1,65 +0,0 @@
1
- import type { Sandbox } from '@daytonaio/sdk'
2
- import { logger } from '../core/logger'
3
- import { DaytonaSandboxGitManager } from './sandbox-git-manager'
4
- import { HostGitManager } from './host-git-manager'
5
-
6
- /**
7
- * SessionGitManager: Combines DaytonaSandboxGitManager and HostGitManager for session lifecycle git operations.
8
- */
9
- export class SessionGitManager {
10
- private readonly sandboxGit: DaytonaSandboxGitManager
11
- private readonly hostGit: HostGitManager
12
- private readonly sandbox: Sandbox
13
- private readonly repoPath: string
14
- private readonly branch: string
15
- private readonly localBranch: string
16
- private readonly branchNumber: number
17
-
18
- constructor(sandbox: Sandbox, repoPath: string, branchNumber: number) {
19
- this.sandbox = sandbox
20
- this.repoPath = repoPath
21
- this.branch = 'opencode'
22
- this.branchNumber = branchNumber
23
- this.localBranch = `opencode/${branchNumber}`
24
- this.sandboxGit = new DaytonaSandboxGitManager(sandbox, repoPath)
25
- this.hostGit = new HostGitManager()
26
- }
27
-
28
- private async getSshUrl(): Promise<string> {
29
- const sshAccess = await this.sandbox.createSshAccess(10)
30
- logger.info(`Created SSH access token ${sshAccess.token}@ssh.app.daytona.io`)
31
- return `ssh://${sshAccess.token}@ssh.app.daytona.io${this.repoPath}`
32
- }
33
-
34
- /**
35
- * Initialize git in the sandbox and sync with host
36
- * Used when a new sandbox is created for a session
37
- */
38
- async initializeAndSync() {
39
- logger.info(
40
- `Using branch number ${this.branchNumber} (local ${this.localBranch}) for sandbox git init/sync`,
41
- )
42
- await this.sandboxGit.ensureRepo()
43
- this.hostGit.ensureRepo()
44
- const sshUrl = await this.getSshUrl()
45
- this.hostGit.setRemote('sandbox', sshUrl)
46
- this.hostGit.pushLocalToSandboxRemote(sshUrl, this.branch)
47
- await this.sandboxGit.resetToRemote(this.branch)
48
- }
49
-
50
- /**
51
- * Auto-commit in the sandbox and pull latest from host
52
- * Used on session idle
53
- */
54
- async autoCommitAndPull() {
55
- logger.info(
56
- `Using branch number ${this.branchNumber} (local ${this.localBranch}) for sandbox auto-commit/pull`,
57
- )
58
- await this.sandboxGit.ensureRepo()
59
- await this.sandboxGit.autoCommit()
60
- this.hostGit.ensureRepo()
61
- const sshUrl = await this.getSshUrl()
62
- this.hostGit.setRemote('sandbox', sshUrl)
63
- this.hostGit.pull('sandbox', this.branch, this.localBranch)
64
- }
65
- }
@@ -1,50 +0,0 @@
1
- /**
2
- * OpenCode Plugin: Daytona Sandbox Integration
3
- *
4
- * OpenCode plugins extend the AI coding assistant by adding custom tools, handling events,
5
- * and modifying behavior. Plugins are TypeScript/JavaScript modules that export functions
6
- * which return hooks for various lifecycle events.
7
- *
8
- * This plugin integrates Daytona sandboxes with OpenCode, providing isolated development
9
- * environments for each session. It adds custom tools for file operations, command execution,
10
- * and search within sandboxes, and automatically cleans up resources when sessions end.
11
- *
12
- * Learn more: https://opencode.ai/docs/plugins/
13
- *
14
- * Daytona Sandbox Integration Tools
15
- *
16
- * Requires:
17
- * - npm install @daytonaio/sdk
18
- * - Environment: DAYTONA_API_KEY
19
- */
20
-
21
- import { join } from 'path'
22
- import { xdgData } from 'xdg-basedir'
23
- import type { Plugin } from '@opencode-ai/plugin'
24
-
25
- // Import modules
26
- import { setLogFilePath } from './core/logger'
27
- import { DaytonaSessionManager } from './core/session-manager'
28
- import {
29
- createCustomToolsPlugin,
30
- createSessionCleanupPlugin,
31
- createSystemTransformPlugin,
32
- createSessionIdleAutoCommitPlugin,
33
- } from './plugins'
34
-
35
- // Export types for consumers
36
- export type { EventSessionDeleted, LogLevel, SandboxInfo, SessionInfo, ProjectSessionData } from './core/types'
37
-
38
- // Initialize logger and session manager using xdg-basedir (same as OpenCode)
39
- const LOG_FILE = join(xdgData!, '.daytona-plugin.log')
40
- const STORAGE_DIR = join(xdgData!, 'opencode', 'storage', 'daytona')
41
- const REPO_PATH = '/home/daytona/project'
42
-
43
- setLogFilePath(LOG_FILE)
44
- const sessionManager = new DaytonaSessionManager(process.env.DAYTONA_API_KEY || '', STORAGE_DIR, REPO_PATH)
45
-
46
- // Export plugin instances
47
- export const CustomToolsPlugin: Plugin = createCustomToolsPlugin(sessionManager)
48
- export const DaytonaSessionCleanupPlugin: Plugin = createSessionCleanupPlugin(sessionManager)
49
- export const SystemTransformPlugin: Plugin = createSystemTransformPlugin(REPO_PATH)
50
- export const DaytonaSessionIdleAutoCommitPlugin: Plugin = createSessionIdleAutoCommitPlugin(sessionManager, REPO_PATH)
@@ -1,20 +0,0 @@
1
- import type { Plugin, PluginInput } from '@opencode-ai/plugin'
2
- import { createDaytonaTools } from '../tools'
3
- import { logger } from '../core/logger'
4
- import type { DaytonaSessionManager } from '../core/session-manager'
5
-
6
- /**
7
- * Creates the custom tools plugin for Daytona sandbox integration
8
- * Provides tools for file operations, command execution, and search within sandboxes
9
- */
10
- export function createCustomToolsPlugin(sessionManager: DaytonaSessionManager): Plugin {
11
- return async (pluginCtx: PluginInput) => {
12
- logger.info('OpenCode started with Daytona plugin')
13
- const projectId = pluginCtx.project.id
14
- const worktree = pluginCtx.project.worktree
15
-
16
- return {
17
- tool: createDaytonaTools(sessionManager, projectId, worktree),
18
- }
19
- }
20
- }
@@ -1,22 +0,0 @@
1
- import type { Plugin, PluginInput } from '@opencode-ai/plugin'
2
- import type { DaytonaSessionManager } from '../core/session-manager'
3
- import { EVENT_TYPE_SESSION_DELETED } from '../core/types'
4
- import type { EventSessionDeleted } from '../core/types'
5
-
6
- /**
7
- * Creates the session cleanup plugin for Daytona
8
- * Automatically cleans up sandbox resources when sessions end
9
- */
10
- export function createSessionCleanupPlugin(sessionManager: DaytonaSessionManager): Plugin {
11
- return async (pluginCtx: PluginInput) => {
12
- const projectId = pluginCtx.project.id
13
- return {
14
- event: async ({ event }) => {
15
- if (event.type === EVENT_TYPE_SESSION_DELETED) {
16
- const sessionId = (event as EventSessionDeleted).properties.info.id
17
- await sessionManager.deleteSandbox(sessionId, projectId)
18
- }
19
- },
20
- }
21
- }
22
- }
@@ -1,30 +0,0 @@
1
- import type { Plugin, PluginInput } from '@opencode-ai/plugin'
2
- import type { DaytonaSessionManager } from '../core/session-manager'
3
- import { SessionGitManager } from '../git/session-git-manager'
4
- import { EVENT_TYPE_SESSION_IDLE } from '../core/types'
5
-
6
- /**
7
- * Creates a plugin to auto-commit in the sandbox on session idle
8
- */
9
- export function createSessionIdleAutoCommitPlugin(sessionManager: DaytonaSessionManager, repoPath: string): Plugin {
10
- return async (pluginCtx: PluginInput) => {
11
- const projectId = pluginCtx.project.id
12
- const worktree = pluginCtx.project.worktree
13
- return {
14
- event: async (args: any) => {
15
- const event = args.event
16
- if (event.type === EVENT_TYPE_SESSION_IDLE) {
17
- const sessionId = event.properties.sessionID
18
- // Use SessionGitManager abstraction for auto-commit and pull
19
- const sandbox = await sessionManager.getSandbox(sessionId, projectId, worktree)
20
- const branchNumber = sessionManager.getBranchNumberForSandbox(projectId, sandbox.id)
21
- if (!branchNumber) {
22
- throw new Error(`No branch number found for sandbox ${sandbox.id}`)
23
- }
24
- const sessionGit = new SessionGitManager(sandbox, repoPath, branchNumber)
25
- await sessionGit.autoCommitAndPull()
26
- }
27
- },
28
- }
29
- }
30
- }
@@ -1,28 +0,0 @@
1
- import type { Plugin, PluginInput } from '@opencode-ai/plugin'
2
- import type {
3
- ExperimentalChatSystemTransformInput,
4
- ExperimentalChatSystemTransformOutput,
5
- } from '../core/types'
6
-
7
- /**
8
- * Creates the system transform plugin for Daytona
9
- * Adds Daytona-specific instructions to the system prompt
10
- */
11
- export function createSystemTransformPlugin(repoPath: string): Plugin {
12
- return async (pluginCtx: PluginInput) => {
13
- return {
14
- 'experimental.chat.system.transform': async (
15
- input: ExperimentalChatSystemTransformInput,
16
- output: ExperimentalChatSystemTransformOutput,
17
- ) => {
18
- output.system.push(`
19
- ## Daytona Sandbox Integration
20
- This session is integrated with a Daytona sandbox.
21
- The main project repository is located at: ${repoPath}.
22
- Work in this directory. Do NOT try to use the current working directory of the host system.
23
- When executing long-running commands, use the 'background' option to run them asynchronously.
24
- `)
25
- },
26
- }
27
- }
28
- }
@@ -1,32 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
-
5
- export const bashTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
6
- description: 'Executes shell commands in a Daytona sandbox',
7
- args: {
8
- command: z.string(),
9
- background: z.boolean().optional(),
10
- },
11
- async execute(args: { command: string; background?: boolean }, ctx: ToolContext) {
12
- const sessionId = ctx.sessionID
13
- const sandbox = await sessionManager.getSandbox(sessionId, projectId, worktree)
14
-
15
- if (args.background) {
16
- const execSessionId = `exec-session-${sessionId}`
17
- try {
18
- await sandbox.process.getSession(execSessionId)
19
- } catch {
20
- await sandbox.process.createSession(execSessionId)
21
- }
22
- const result = await sandbox.process.executeSessionCommand(execSessionId, {
23
- command: args.command,
24
- runAsync: true,
25
- })
26
- return `Command started in background (cmdId: ${result.cmdId})`
27
- } else {
28
- const result = await sandbox.process.executeCommand(args.command)
29
- return `Exit code: ${result.exitCode}\n${result.result}`
30
- }
31
- },
32
- })
@@ -1,21 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
-
5
- export const editTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
6
- description: 'Replaces text in a file in Daytona sandbox',
7
- args: {
8
- filePath: z.string(),
9
- oldString: z.string(),
10
- newString: z.string(),
11
- },
12
- async execute(args: { filePath: string; oldString: string; newString: string }, ctx: ToolContext) {
13
- const sandbox = await sessionManager.getSandbox(ctx.sessionID, projectId, worktree)
14
- const buffer = await sandbox.fs.downloadFile(args.filePath)
15
- const decoder = new TextDecoder()
16
- const content = decoder.decode(buffer)
17
- const newContent = content.replace(args.oldString, args.newString)
18
- await sandbox.fs.uploadFile(Buffer.from(newContent), args.filePath)
19
- return `Edited ${args.filePath}`
20
- },
21
- })
@@ -1,15 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
-
5
- export const getPreviewURLTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
6
- description: 'Gets a preview URL for the Daytona sandbox',
7
- args: {
8
- port: z.number(),
9
- },
10
- async execute(args: { port: number }, ctx: ToolContext) {
11
- const sandbox = await sessionManager.getSandbox(ctx.sessionID, projectId, worktree)
12
- const previewLink = await sandbox.getPreviewLink(args.port)
13
- return `Sandbox Preview URL: ${previewLink.url}`
14
- },
15
- })
@@ -1,16 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
-
5
- export const globTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
6
- description: 'Searches for files matching a pattern in Daytona sandbox',
7
- args: {
8
- pattern: z.string(),
9
- },
10
- async execute(args: { pattern: string }, ctx: ToolContext) {
11
- const sandbox = await sessionManager.getSandbox(ctx.sessionID, projectId, worktree)
12
- const workDir = await sandbox.getWorkDir()
13
- const result = await sandbox.fs.searchFiles(workDir, args.pattern)
14
- return result.files.join('\n')
15
- },
16
- })
@@ -1,16 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
-
5
- export const grepTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
6
- description: 'Searches for text pattern in files in Daytona sandbox',
7
- args: {
8
- pattern: z.string(),
9
- },
10
- async execute(args: { pattern: string }, ctx: ToolContext) {
11
- const sandbox = await sessionManager.getSandbox(ctx.sessionID, projectId, worktree)
12
- const workDir = await sandbox.getWorkDir()
13
- const matches = await sandbox.fs.findFiles(workDir, args.pattern)
14
- return matches.map((m) => `${m.file}:${m.line}: ${m.content}`).join('\n')
15
- },
16
- })
@@ -1,18 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
- import type { FileInfo } from '@daytonaio/sdk'
5
-
6
- export const lsTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
7
- description: 'Lists files in a directory in Daytona sandbox',
8
- args: {
9
- dirPath: z.string().optional(),
10
- },
11
- async execute(args: { dirPath?: string }, ctx: ToolContext) {
12
- const sandbox = await sessionManager.getSandbox(ctx.sessionID, projectId, worktree)
13
- const workDir = await sandbox.getWorkDir()
14
- const path = args.dirPath || workDir
15
- const files = (await sandbox.fs.listFiles(path)) as FileInfo[]
16
- return files.map((f) => f.name).join('\n')
17
- },
18
- })
@@ -1,15 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
-
5
- export const lspTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
6
- description: 'LSP operation in Daytona sandbox (code intelligence)',
7
- args: {
8
- op: z.string(),
9
- filePath: z.string(),
10
- line: z.number(),
11
- },
12
- async execute(args: { op: string; filePath: string; line: number }, ctx: ToolContext) {
13
- return `LSP operations are not yet implemented in the Daytona plugin.`
14
- },
15
- })
@@ -1,32 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
-
5
- export const multieditTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
6
- description: 'Applies multiple edits to a file in Daytona sandbox atomically',
7
- args: {
8
- filePath: z.string(),
9
- edits: z.array(
10
- z.object({
11
- oldString: z.string(),
12
- newString: z.string(),
13
- }),
14
- ),
15
- },
16
- async execute(
17
- args: { filePath: string; edits: Array<{ oldString: string; newString: string }> },
18
- ctx: ToolContext,
19
- ) {
20
- const sandbox = await sessionManager.getSandbox(ctx.sessionID, projectId, worktree)
21
- const buffer = await sandbox.fs.downloadFile(args.filePath)
22
- const decoder = new TextDecoder()
23
- let content = decoder.decode(buffer)
24
-
25
- for (const edit of args.edits) {
26
- content = content.replace(edit.oldString, edit.newString)
27
- }
28
-
29
- await sandbox.fs.uploadFile(Buffer.from(content), args.filePath)
30
- return `Applied ${args.edits.length} edits to ${args.filePath}`
31
- },
32
- })
@@ -1,21 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
-
5
- export const patchTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
6
- description: 'Patches a file with a code snippet in Daytona sandbox',
7
- args: {
8
- filePath: z.string(),
9
- oldSnippet: z.string(),
10
- newSnippet: z.string(),
11
- },
12
- async execute(args: { filePath: string; oldSnippet: string; newSnippet: string }, ctx: ToolContext) {
13
- const sandbox = await sessionManager.getSandbox(ctx.sessionID, projectId, worktree)
14
- const buffer = await sandbox.fs.downloadFile(args.filePath)
15
- const decoder = new TextDecoder()
16
- const content = decoder.decode(buffer)
17
- const newContent = content.replace(args.oldSnippet, args.newSnippet)
18
- await sandbox.fs.uploadFile(Buffer.from(newContent), args.filePath)
19
- return `Patched ${args.filePath}`
20
- },
21
- })
@@ -1,16 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
-
5
- export const readTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
6
- description: 'Reads file from Daytona sandbox',
7
- args: {
8
- filePath: z.string(),
9
- },
10
- async execute(args: { filePath: string }, ctx: ToolContext) {
11
- const sandbox = await sessionManager.getSandbox(ctx.sessionID, projectId, worktree)
12
- const buffer = await sandbox.fs.downloadFile(args.filePath)
13
- const decoder = new TextDecoder()
14
- return decoder.decode(buffer)
15
- },
16
- })
@@ -1,16 +0,0 @@
1
- import { z } from 'zod'
2
- import type { ToolContext } from '@opencode-ai/plugin'
3
- import type { DaytonaSessionManager } from '../core/session-manager'
4
-
5
- export const writeTool = (sessionManager: DaytonaSessionManager, projectId: string, worktree: string) => ({
6
- description: 'Writes content to file in Daytona sandbox',
7
- args: {
8
- filePath: z.string(),
9
- content: z.string(),
10
- },
11
- async execute(args: { filePath: string; content: string }, ctx: ToolContext) {
12
- const sandbox = await sessionManager.getSandbox(ctx.sessionID, projectId, worktree)
13
- await sandbox.fs.uploadFile(Buffer.from(args.content), args.filePath)
14
- return `Written ${args.content.length} bytes to ${args.filePath}`
15
- },
16
- })
@@ -1,33 +0,0 @@
1
- /**
2
- * Tool implementations for Daytona sandbox integration
3
- */
4
-
5
- import { bashTool } from './tools/bash'
6
- import { readTool } from './tools/read'
7
- import { writeTool } from './tools/write'
8
- import { editTool } from './tools/edit'
9
- import { multieditTool } from './tools/multiedit'
10
- import { patchTool } from './tools/patch'
11
- import { lsTool } from './tools/ls'
12
- import { globTool } from './tools/glob'
13
- import { grepTool } from './tools/grep'
14
- import { lspTool } from './tools/lsp'
15
- import { getPreviewURLTool } from './tools/get-preview-url'
16
-
17
- import type { DaytonaSessionManager } from './core/session-manager'
18
-
19
- export function createDaytonaTools(sessionManager: DaytonaSessionManager, projectId: string, worktree: string) {
20
- return {
21
- bash: bashTool(sessionManager, projectId, worktree),
22
- read: readTool(sessionManager, projectId, worktree),
23
- write: writeTool(sessionManager, projectId, worktree),
24
- edit: editTool(sessionManager, projectId, worktree),
25
- multiedit: multieditTool(sessionManager, projectId, worktree),
26
- patch: patchTool(sessionManager, projectId, worktree),
27
- ls: lsTool(sessionManager, projectId, worktree),
28
- glob: globTool(sessionManager, projectId, worktree),
29
- grep: grepTool(sessionManager, projectId, worktree),
30
- lsp: lspTool(sessionManager, projectId, worktree),
31
- getPreviewURL: getPreviewURLTool(sessionManager, projectId, worktree),
32
- }
33
- }