opencodekit 0.6.3 → 0.6.5

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/dist/index.js CHANGED
@@ -750,7 +750,7 @@ var cac = (name = "") => new CAC(name);
750
750
  // package.json
751
751
  var package_default = {
752
752
  name: "opencodekit",
753
- version: "0.6.3",
753
+ version: "0.6.5",
754
754
  description: "CLI tool for bootstrapping and managing OpenCodeKit projects",
755
755
  type: "module",
756
756
  repository: {
@@ -136,11 +136,11 @@ Branch: [branch]
136
136
 
137
137
  Saved: .beads/artifacts/<bead-id>/handoffs/<timestamp>.md
138
138
 
139
- Resume: /resume <bead-id>
139
+ ━━━━━━━━━━━━━━━━━━━━━━━━
140
+ 🔄 Press Ctrl+K to compact session with handoff context
141
+ ━━━━━━━━━━━━━━━━━━━━━━━━
142
+
143
+ The handoff plugin will automatically inject this context into the new session.
140
144
 
141
- Next session will auto-load:
142
- - This handoff
143
- - Previous session context (read_session)
144
- - Git state
145
- - Bead artifacts
145
+ Alternatively, resume manually: /resume <bead-id>
146
146
  ```
@@ -1,8 +1,71 @@
1
- import { existsSync } from "node:fs";
2
- import { extname } from "node:path";
1
+ import { existsSync, readdirSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { extname, join } from "node:path";
3
4
  import { BUILTIN_SERVERS, EXT_TO_LANG } from "./constants";
4
5
  import type { LSPServerConfig } from "./types";
5
6
 
7
+ /**
8
+ * Known paths where OpenCode installs bundled LSP servers
9
+ * These are checked when the command isn't found in PATH
10
+ */
11
+ function getOpenCodeDataDir(): string {
12
+ const home = homedir();
13
+ switch (process.platform) {
14
+ case "darwin":
15
+ return join(home, ".local/share/opencode");
16
+ case "win32":
17
+ return join(
18
+ process.env.APPDATA ?? join(home, "AppData/Roaming"),
19
+ "opencode",
20
+ );
21
+ default: // linux
22
+ return join(
23
+ process.env.XDG_DATA_HOME ?? join(home, ".local/share"),
24
+ "opencode",
25
+ );
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Find OpenCode's bundled jdtls launcher jar
31
+ */
32
+ function findOpenCodeJdtls(): string[] | null {
33
+ const jdtlsDir = join(getOpenCodeDataDir(), "bin/jdtls");
34
+ const pluginsDir = join(jdtlsDir, "plugins");
35
+
36
+ if (!existsSync(pluginsDir)) return null;
37
+
38
+ try {
39
+ const files = readdirSync(pluginsDir);
40
+ const launcherJar = files.find(
41
+ (f) =>
42
+ f.startsWith("org.eclipse.equinox.launcher_") && f.endsWith(".jar"),
43
+ );
44
+ if (!launcherJar) return null;
45
+
46
+ const configDir = join(
47
+ jdtlsDir,
48
+ process.platform === "darwin"
49
+ ? "config_mac"
50
+ : process.platform === "win32"
51
+ ? "config_win"
52
+ : "config_linux",
53
+ );
54
+
55
+ if (!existsSync(configDir)) return null;
56
+
57
+ return [
58
+ "java",
59
+ "-jar",
60
+ join(pluginsDir, launcherJar),
61
+ "-configuration",
62
+ configDir,
63
+ ];
64
+ } catch {
65
+ return null;
66
+ }
67
+ }
68
+
6
69
  export interface ResolvedServer extends LSPServerConfig {
7
70
  id: string;
8
71
  }
@@ -58,6 +121,18 @@ export function resolveServer(filePath: string): ResolvedServer | null {
58
121
  }
59
122
  }
60
123
 
124
+ // Special case: Try OpenCode's bundled jdtls for Java files
125
+ if (ext === ".java") {
126
+ const jdtlsCommand = findOpenCodeJdtls();
127
+ if (jdtlsCommand && commandExists("java")) {
128
+ return {
129
+ id: "jdtls",
130
+ command: jdtlsCommand,
131
+ extensions: [".java"],
132
+ };
133
+ }
134
+ }
135
+
61
136
  return null;
62
137
  }
63
138
 
@@ -87,10 +162,17 @@ export function listAvailableServers(): Array<{
87
162
  for (const [id, config] of Object.entries(BUILTIN_SERVERS)) {
88
163
  if (configuredIds.has(id)) continue;
89
164
  const [cmd] = config.command;
165
+
166
+ // Special case: jdtls can use OpenCode's bundled version
167
+ let available = !!cmd && commandExists(cmd);
168
+ if (!available && id === "jdtls") {
169
+ available = !!(findOpenCodeJdtls() && commandExists("java"));
170
+ }
171
+
90
172
  results.push({
91
173
  id,
92
174
  extensions: config.extensions,
93
- available: !!cmd && commandExists(cmd),
175
+ available,
94
176
  });
95
177
  }
96
178
 
@@ -40,20 +40,45 @@ export const DEFAULT_MAX_REFERENCES = 200;
40
40
  export const DEFAULT_MAX_SYMBOLS = 200;
41
41
  export const DEFAULT_MAX_DIAGNOSTICS = 200;
42
42
 
43
- // Synced with OpenCode's server.ts
43
+ /**
44
+ * Built-in LSP servers synced with OpenCode's LSP configuration
45
+ * @see https://opencode.ai/docs/lsp/
46
+ *
47
+ * Servers are matched in order - first match wins.
48
+ * Some servers (jdtls, pyright, etc.) may use OpenCode's bundled installation.
49
+ */
44
50
  export const BUILTIN_SERVERS: Record<string, Omit<LSPServerConfig, "id">> = {
51
+ // TypeScript/JavaScript
45
52
  typescript: {
46
53
  command: ["typescript-language-server", "--stdio"],
47
54
  extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"],
48
55
  },
56
+ deno: {
57
+ command: ["deno", "lsp"],
58
+ extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs"],
59
+ },
60
+
61
+ // Frontend frameworks
49
62
  vue: {
50
63
  command: ["vue-language-server", "--stdio"],
51
64
  extensions: [".vue"],
52
65
  },
66
+ svelte: {
67
+ command: ["svelteserver", "--stdio"],
68
+ extensions: [".svelte"],
69
+ },
70
+ astro: {
71
+ command: ["astro-ls", "--stdio"],
72
+ extensions: [".astro"],
73
+ },
74
+
75
+ // Go
53
76
  gopls: {
54
77
  command: ["gopls"],
55
78
  extensions: [".go"],
56
79
  },
80
+
81
+ // Python
57
82
  basedpyright: {
58
83
  command: ["basedpyright-langserver", "--stdio"],
59
84
  extensions: [".py", ".pyi"],
@@ -62,10 +87,14 @@ export const BUILTIN_SERVERS: Record<string, Omit<LSPServerConfig, "id">> = {
62
87
  command: ["pyright-langserver", "--stdio"],
63
88
  extensions: [".py", ".pyi"],
64
89
  },
90
+
91
+ // Rust
65
92
  rust: {
66
93
  command: ["rust-analyzer"],
67
94
  extensions: [".rs"],
68
95
  },
96
+
97
+ // C/C++
69
98
  clangd: {
70
99
  command: ["clangd", "--background-index", "--clang-tidy"],
71
100
  extensions: [
@@ -81,26 +110,117 @@ export const BUILTIN_SERVERS: Record<string, Omit<LSPServerConfig, "id">> = {
81
110
  ".h++",
82
111
  ],
83
112
  },
84
- svelte: {
85
- command: ["svelteserver", "--stdio"],
86
- extensions: [".svelte"],
87
- },
88
- astro: {
89
- command: ["astro-ls", "--stdio"],
90
- extensions: [".astro"],
91
- },
113
+
114
+ // Java - OpenCode auto-installs jdtls, requires Java 21+
92
115
  jdtls: {
93
116
  command: ["jdtls"],
94
117
  extensions: [".java"],
95
118
  },
96
- lua: {
119
+
120
+ // C#/F#
121
+ csharp: {
122
+ command: ["OmniSharp", "-lsp"],
123
+ extensions: [".cs"],
124
+ },
125
+ fsharp: {
126
+ command: ["fsautocomplete", "--adaptive-lsp-server-enabled"],
127
+ extensions: [".fs", ".fsi", ".fsx", ".fsscript"],
128
+ },
129
+
130
+ // Ruby
131
+ "ruby-lsp": {
132
+ command: ["ruby-lsp"],
133
+ extensions: [".rb", ".rake", ".gemspec", ".ru"],
134
+ },
135
+
136
+ // PHP
137
+ intelephense: {
138
+ command: ["intelephense", "--stdio"],
139
+ extensions: [".php"],
140
+ },
141
+
142
+ // Lua
143
+ "lua-ls": {
97
144
  command: ["lua-language-server"],
98
145
  extensions: [".lua"],
99
146
  },
147
+
148
+ // Shell
149
+ bash: {
150
+ command: ["bash-language-server", "start"],
151
+ extensions: [".sh", ".bash", ".zsh", ".ksh"],
152
+ },
153
+
154
+ // Swift/Objective-C
155
+ "sourcekit-lsp": {
156
+ command: ["sourcekit-lsp"],
157
+ extensions: [".swift", ".objc", ".objcpp"],
158
+ },
159
+
160
+ // Dart
161
+ dart: {
162
+ command: ["dart", "language-server", "--protocol=lsp"],
163
+ extensions: [".dart"],
164
+ },
165
+
166
+ // Elixir
167
+ "elixir-ls": {
168
+ command: ["elixir-ls"],
169
+ extensions: [".ex", ".exs"],
170
+ },
171
+
172
+ // Gleam
173
+ gleam: {
174
+ command: ["gleam", "lsp"],
175
+ extensions: [".gleam"],
176
+ },
177
+
178
+ // Clojure
179
+ "clojure-lsp": {
180
+ command: ["clojure-lsp"],
181
+ extensions: [".clj", ".cljs", ".cljc", ".edn"],
182
+ },
183
+
184
+ // OCaml
185
+ "ocaml-lsp": {
186
+ command: ["ocamllsp"],
187
+ extensions: [".ml", ".mli"],
188
+ },
189
+
190
+ // Zig
191
+ zls: {
192
+ command: ["zls"],
193
+ extensions: [".zig", ".zon"],
194
+ },
195
+
196
+ // Nix
197
+ nixd: {
198
+ command: ["nixd"],
199
+ extensions: [".nix"],
200
+ },
201
+
202
+ // Terraform
203
+ terraform: {
204
+ command: ["terraform-ls", "serve"],
205
+ extensions: [".tf", ".tfvars"],
206
+ },
207
+
208
+ // Typst
209
+ tinymist: {
210
+ command: ["tinymist", "lsp"],
211
+ extensions: [".typ", ".typc"],
212
+ },
213
+
214
+ // YAML
215
+ "yaml-ls": {
216
+ command: ["yaml-language-server", "--stdio"],
217
+ extensions: [".yaml", ".yml"],
218
+ },
100
219
  };
101
220
 
102
- // Extension to language ID mapping
221
+ // Extension to language ID mapping (used for LSP textDocument/didOpen)
103
222
  export const EXT_TO_LANG: Record<string, string> = {
223
+ // TypeScript/JavaScript
104
224
  ".ts": "typescript",
105
225
  ".tsx": "typescriptreact",
106
226
  ".mts": "typescript",
@@ -111,28 +231,109 @@ export const EXT_TO_LANG: Record<string, string> = {
111
231
  ".cjs": "javascript",
112
232
  ".json": "json",
113
233
  ".jsonc": "jsonc",
234
+
235
+ // Python
114
236
  ".py": "python",
115
237
  ".pyi": "python",
238
+
239
+ // Go
116
240
  ".go": "go",
241
+
242
+ // Rust
117
243
  ".rs": "rust",
244
+
245
+ // C/C++
118
246
  ".c": "c",
119
247
  ".cpp": "cpp",
120
248
  ".cc": "cpp",
121
249
  ".cxx": "cpp",
250
+ ".c++": "cpp",
122
251
  ".h": "c",
123
252
  ".hpp": "cpp",
253
+ ".hh": "cpp",
254
+ ".hxx": "cpp",
255
+ ".h++": "cpp",
256
+
257
+ // Java
124
258
  ".java": "java",
259
+
260
+ // C#/F#
261
+ ".cs": "csharp",
262
+ ".fs": "fsharp",
263
+ ".fsi": "fsharp",
264
+ ".fsx": "fsharp",
265
+ ".fsscript": "fsharp",
266
+
267
+ // Ruby
268
+ ".rb": "ruby",
269
+ ".rake": "ruby",
270
+ ".gemspec": "ruby",
271
+ ".ru": "ruby",
272
+
273
+ // PHP
274
+ ".php": "php",
275
+
276
+ // Lua
125
277
  ".lua": "lua",
278
+
279
+ // Shell
280
+ ".sh": "shellscript",
281
+ ".bash": "shellscript",
282
+ ".zsh": "shellscript",
283
+ ".ksh": "shellscript",
284
+
285
+ // Swift/Objective-C
286
+ ".swift": "swift",
287
+ ".objc": "objective-c",
288
+ ".objcpp": "objective-cpp",
289
+
290
+ // Dart
291
+ ".dart": "dart",
292
+
293
+ // Elixir
294
+ ".ex": "elixir",
295
+ ".exs": "elixir",
296
+
297
+ // Gleam
298
+ ".gleam": "gleam",
299
+
300
+ // Clojure
301
+ ".clj": "clojure",
302
+ ".cljs": "clojurescript",
303
+ ".cljc": "clojure",
304
+ ".edn": "edn",
305
+
306
+ // OCaml
307
+ ".ml": "ocaml",
308
+ ".mli": "ocaml",
309
+
310
+ // Zig
311
+ ".zig": "zig",
312
+ ".zon": "zig",
313
+
314
+ // Nix
315
+ ".nix": "nix",
316
+
317
+ // Terraform
318
+ ".tf": "terraform",
319
+ ".tfvars": "terraform",
320
+
321
+ // Typst
322
+ ".typ": "typst",
323
+ ".typc": "typst",
324
+
325
+ // Frontend frameworks
126
326
  ".vue": "vue",
127
327
  ".svelte": "svelte",
128
328
  ".astro": "astro",
329
+
330
+ // Web
129
331
  ".html": "html",
130
332
  ".css": "css",
131
333
  ".scss": "scss",
132
- ".md": "markdown",
334
+
335
+ // Config/Data
133
336
  ".yaml": "yaml",
134
337
  ".yml": "yaml",
135
- ".sh": "shellscript",
136
- ".bash": "shellscript",
137
- ".zsh": "shellscript",
338
+ ".md": "markdown",
138
339
  };
@@ -0,0 +1,76 @@
1
+ # Handoff: test-handoff-plugin
2
+
3
+ **Created:** 2025-12-27T10:30:00Z
4
+ **Agent:** build
5
+
6
+ ## Provenance
7
+
8
+ | Key | Value |
9
+ | ------ | --------------------------------------------------- |
10
+ | Repo | git@github.com:opencodekit/opencodekit-template.git |
11
+ | Branch | main |
12
+ | Commit | ae38a95f899300419e9b17030268cedc60ebb44f |
13
+ | Clean | no |
14
+
15
+ ## Session Context
16
+
17
+ **Current Session:** testing handoff plugin
18
+ **Token Usage:** ~50k estimated
19
+
20
+ Next session can load context with:
21
+
22
+ ```
23
+ read_session("last", project="current")
24
+ ```
25
+
26
+ ## Progress
27
+
28
+ ### Completed
29
+
30
+ - [x] Released v0.6.4 (version bump, changelog, tag, GitHub release)
31
+ - [x] Reviewed Agent-Skills-for-Context-Engineering repo (verdict: mostly theory, not worth stealing)
32
+ - [x] Reviewed Karpathy's hn-time-capsule (verdict: useful patterns)
33
+ - [x] Created handoff plugin (`plugin/handoff.ts`)
34
+ - [x] Updated `/handoff` command to instruct Ctrl+K
35
+
36
+ ### In Progress
37
+
38
+ - [ ] Testing handoff plugin - verifying it injects context on compaction
39
+
40
+ ### Remaining
41
+
42
+ - [ ] Commit new handoff plugin and updated command
43
+ - [ ] Test full flow: handoff → Ctrl+K → new session with context
44
+
45
+ ## Context
46
+
47
+ ### Key Files
48
+
49
+ - `.opencode/plugin/handoff.ts` - New plugin that injects handoff on compaction
50
+ - `.opencode/command/handoff.md` - Updated to tell user to press Ctrl+K
51
+ - `.opencode/plugin/compactor.ts` - Reference for plugin structure
52
+
53
+ ### Decisions Made
54
+
55
+ - Use `experimental.session.compacting` hook to inject handoff context
56
+ - Only inject handoffs < 1 hour old to prevent stale context
57
+ - Search both `.opencode/memory/handoffs/` and `.beads/artifacts/` for handoffs
58
+
59
+ ### Blockers/Issues
60
+
61
+ - OpenCode lacks `session.start` hook (Issue #5409) - can't auto-navigate to new session
62
+ - Workaround: User must manually press Ctrl+K after /handoff
63
+
64
+ ## Resume Instructions
65
+
66
+ 1. Commit the new handoff plugin and updated command
67
+ 2. Test the full flow: run /handoff, press Ctrl+K, verify context injected
68
+ 3. If working, consider adding to v0.6.5 release
69
+
70
+ **Recommended:** Start next session with `/resume test-handoff-plugin` to auto-load this handoff + previous session context.
71
+
72
+ ## Artifacts
73
+
74
+ - spec.md: missing
75
+ - research.md: missing
76
+ - plan.md: missing