-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathai-code-opencode.el
More file actions
131 lines (112 loc) · 4.39 KB
/
ai-code-opencode.el
File metadata and controls
131 lines (112 loc) · 4.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
;;; ai-code-opencode.el --- Thin wrapper for Opencode -*- lexical-binding: t; -*-
;; Author: Kang Tu <tninja@gmail.com>
;; SPDX-License-Identifier: Apache-2.0
;;; Commentary:
;;
;; Thin wrapper that reuses `ai-code-backends-infra' to run Opencode.
;; Provides interactive commands and aliases for the AI Code suite.
;;
;; Opencode is an open-source alternative to Claude Code that provides
;; HTTP server APIs and customization features (LSP, custom LLM providers, etc.)
;; See: https://opencode.ai/
;;
;;; Code:
(require 'ai-code-backends)
(require 'ai-code-backends-infra)
(defgroup ai-code-opencode nil
"Opencode integration via `ai-code-backends-infra.el'."
:group 'tools
:prefix "ai-code-opencode-")
(defcustom ai-code-opencode-program "opencode"
"Path to the Opencode executable."
:type 'string
:group 'ai-code-opencode)
(defcustom ai-code-opencode-program-switches nil
"Command line switches to pass to Opencode on startup."
:type '(repeat string)
:group 'ai-code-opencode)
(defcustom ai-code-opencode-extra-env-vars
'("OTUI_USE_ALTERNATE_SCREEN=main-screen")
"Extra environment variables passed to the Opencode terminal session.
`OTUI_USE_ALTERNATE_SCREEN=main-screen' avoids the alternate screen
buffer so that terminal scrollback is partially preserved."
:type '(repeat string)
:group 'ai-code-opencode)
(defconst ai-code-opencode--session-prefix "opencode"
"Session prefix used in Opencode buffer names.")
(defvar ai-code-opencode--processes (make-hash-table :test 'equal)
"Hash table mapping Opencode session keys to processes.")
;;;###autoload
(defun ai-code-opencode (&optional arg)
"Start Opencode (uses `ai-code-backends-infra' logic).
With prefix ARG, prompt for CLI args using
`ai-code-opencode-program-switches' as the default input."
(interactive "P")
(let* ((working-dir (ai-code-backends-infra--session-working-directory))
(resolved (ai-code-backends-infra--resolve-start-command
ai-code-opencode-program
ai-code-opencode-program-switches
arg
"Opencode"))
(command (plist-get resolved :command)))
(ai-code-backends-infra--toggle-or-create-session
working-dir
nil
ai-code-opencode--processes
command
nil
nil
nil
ai-code-opencode--session-prefix
nil
ai-code-opencode-extra-env-vars)))
;;;###autoload
(defun ai-code-opencode-switch-to-buffer (&optional force-prompt)
"Switch to the Opencode buffer.
When FORCE-PROMPT is non-nil, prompt to select a session."
(interactive "P")
(let ((working-dir (ai-code-backends-infra--session-working-directory)))
(ai-code-backends-infra--switch-to-session-buffer
nil
"No Opencode session for this project"
ai-code-opencode--session-prefix
working-dir
force-prompt)))
;;;###autoload
(defun ai-code-opencode-send-command (line)
"Send LINE to Opencode.
When called interactively, prompts for the command."
(interactive "sOpencode> ")
(let ((working-dir (ai-code-backends-infra--session-working-directory)))
(ai-code-backends-infra--send-line-to-session
nil
"No Opencode session for this project"
line
ai-code-opencode--session-prefix
working-dir)))
;;;###autoload
(defun ai-code-opencode-resume (&optional arg)
"Resume a previous Opencode session.
This command starts Opencode with the --resume flag to resume
a specific past session. The CLI will present an interactive list of past
sessions to choose from.
If current buffer belongs to a project, start in the project's root
directory. Otherwise start in the directory of the current buffer file,
or the current value of `default-directory' if no project and no buffer file.
With double prefix ARG (\\[universal-argument] \\[universal-argument]),
prompt for the project directory."
(interactive "P")
(let ((ai-code-opencode-program-switches
(append ai-code-opencode-program-switches '("--continue"))))
(ai-code-opencode arg)
(let* ((working-dir (ai-code-backends-infra--session-working-directory))
(buffer (ai-code-backends-infra--select-session-buffer
ai-code-opencode--session-prefix
working-dir)))
(when buffer
(with-current-buffer buffer
(sit-for 0.5)
(ai-code-backends-infra--terminal-send-string "")
(goto-char (point-min)))))))
(provide 'ai-code-opencode)
;;; ai-code-opencode.el ends here