alchemylab-opencode 1.0.1 → 1.0.4

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 (45) hide show
  1. package/build.mjs +153 -0
  2. package/dist/chunk-7JG6KCBC.js +78 -0
  3. package/dist/chunk-7JG6KCBC.js.map +7 -0
  4. package/dist/chunk-CMAI7CAJ.js +2270 -0
  5. package/dist/chunk-CMAI7CAJ.js.map +7 -0
  6. package/dist/chunk-FPPWDLO7.js +117 -0
  7. package/dist/chunk-FPPWDLO7.js.map +7 -0
  8. package/dist/chunk-K4ME3WTI.js +6525 -0
  9. package/dist/chunk-K4ME3WTI.js.map +7 -0
  10. package/dist/chunk-KMHCMDYS.js +309 -0
  11. package/dist/chunk-KMHCMDYS.js.map +7 -0
  12. package/dist/chunk-NBI23JB4.js +23721 -0
  13. package/dist/chunk-NBI23JB4.js.map +7 -0
  14. package/dist/chunk-P44FI4UK.js +21 -0
  15. package/dist/chunk-P44FI4UK.js.map +7 -0
  16. package/dist/chunk-SM4I7RU4.js +718 -0
  17. package/dist/chunk-SM4I7RU4.js.map +7 -0
  18. package/dist/chunk-WCK3PNT7.js +5015 -0
  19. package/dist/chunk-WCK3PNT7.js.map +7 -0
  20. package/dist/mcp-6ID7DRNS.js +12 -0
  21. package/dist/mcp-6ID7DRNS.js.map +7 -0
  22. package/dist/pty.node-IR7ZMJYY.js +30 -0
  23. package/dist/pty.node-IR7ZMJYY.js.map +7 -0
  24. package/dist/registry-O4THPVFS.js +13 -0
  25. package/dist/registry-O4THPVFS.js.map +7 -0
  26. package/dist/run-HRWKT4NL.js +4781 -0
  27. package/dist/run-HRWKT4NL.js.map +7 -0
  28. package/dist/run-service-23VXHTA6.js +12 -0
  29. package/dist/run-service-23VXHTA6.js.map +7 -0
  30. package/dist/run.js +12 -0
  31. package/dist/run.js.map +7 -0
  32. package/dist/schema-YARWYUAH.js +14 -0
  33. package/dist/schema-YARWYUAH.js.map +7 -0
  34. package/dist/serve.js +31 -0
  35. package/dist/serve.js.map +7 -0
  36. package/dist/server-MHSLBRNZ.js +16 -0
  37. package/dist/server-MHSLBRNZ.js.map +7 -0
  38. package/dist/session-3UEFY5NC.js +13 -0
  39. package/dist/session-3UEFY5NC.js.map +7 -0
  40. package/dist/share-next-Q5WQ2ELY.js +14 -0
  41. package/dist/share-next-Q5WQ2ELY.js.map +7 -0
  42. package/dist/worktree-E5I74P2A.js +53 -0
  43. package/dist/worktree-E5I74P2A.js.map +7 -0
  44. package/package.json +11 -4
  45. package/packages/opencode/package.json +1 -1
@@ -0,0 +1,2270 @@
1
+ // Built by esbuild from opencode-server source
2
+ import {
3
+ withStatics
4
+ } from "./chunk-P44FI4UK.js";
5
+ import {
6
+ __export,
7
+ __reExport
8
+ } from "./chunk-7JG6KCBC.js";
9
+
10
+ // packages/opencode/src/effect/run-service.ts
11
+ import { Effect as Effect5, Layer as Layer4, ManagedRuntime } from "effect";
12
+
13
+ // packages/opencode/src/bus/global.ts
14
+ import { EventEmitter } from "events";
15
+ var GlobalBus = new EventEmitter();
16
+
17
+ // packages/opencode/src/effect/instance-registry.ts
18
+ var disposers = /* @__PURE__ */ new Set();
19
+ function registerDisposer(disposer) {
20
+ disposers.add(disposer);
21
+ return () => {
22
+ disposers.delete(disposer);
23
+ };
24
+ }
25
+ async function disposeInstance(directory) {
26
+ await Promise.allSettled([...disposers].map((disposer) => disposer(directory)));
27
+ }
28
+
29
+ // packages/opencode/src/util/filesystem.ts
30
+ import { chmod, mkdir, readFile, stat as statFile, writeFile } from "fs/promises";
31
+ import { createWriteStream, existsSync, statSync } from "fs";
32
+ import { lookup } from "mime-types";
33
+ import { realpathSync } from "fs";
34
+ import { dirname, join, relative, resolve as pathResolve, win32 } from "path";
35
+ import { Readable } from "stream";
36
+ import { pipeline } from "stream/promises";
37
+
38
+ // packages/opencode/src/util/glob.ts
39
+ import { glob, globSync } from "glob";
40
+ import { minimatch } from "minimatch";
41
+ var Glob;
42
+ ((Glob2) => {
43
+ function toGlobOptions(options) {
44
+ return {
45
+ cwd: options.cwd,
46
+ absolute: options.absolute,
47
+ dot: options.dot,
48
+ follow: options.symlink ?? false,
49
+ nodir: options.include !== "all"
50
+ };
51
+ }
52
+ async function scan(pattern, options = {}) {
53
+ return glob(pattern, toGlobOptions(options));
54
+ }
55
+ Glob2.scan = scan;
56
+ function scanSync(pattern, options = {}) {
57
+ return globSync(pattern, toGlobOptions(options));
58
+ }
59
+ Glob2.scanSync = scanSync;
60
+ function match(pattern, filepath) {
61
+ return minimatch(filepath, pattern, { dot: true });
62
+ }
63
+ Glob2.match = match;
64
+ })(Glob || (Glob = {}));
65
+
66
+ // packages/opencode/src/util/filesystem.ts
67
+ var Filesystem;
68
+ ((Filesystem2) => {
69
+ async function exists(p) {
70
+ return existsSync(p);
71
+ }
72
+ Filesystem2.exists = exists;
73
+ async function isDir(p) {
74
+ try {
75
+ return statSync(p).isDirectory();
76
+ } catch {
77
+ return false;
78
+ }
79
+ }
80
+ Filesystem2.isDir = isDir;
81
+ function stat(p) {
82
+ return statSync(p, { throwIfNoEntry: false }) ?? void 0;
83
+ }
84
+ Filesystem2.stat = stat;
85
+ async function statAsync(p) {
86
+ return statFile(p).catch((e) => {
87
+ if (isEnoent(e)) return void 0;
88
+ throw e;
89
+ });
90
+ }
91
+ Filesystem2.statAsync = statAsync;
92
+ async function size(p) {
93
+ const s = stat(p)?.size ?? 0;
94
+ return typeof s === "bigint" ? Number(s) : s;
95
+ }
96
+ Filesystem2.size = size;
97
+ async function readText(p) {
98
+ return readFile(p, "utf-8");
99
+ }
100
+ Filesystem2.readText = readText;
101
+ async function readJson(p) {
102
+ return JSON.parse(await readFile(p, "utf-8"));
103
+ }
104
+ Filesystem2.readJson = readJson;
105
+ async function readBytes(p) {
106
+ return readFile(p);
107
+ }
108
+ Filesystem2.readBytes = readBytes;
109
+ async function readArrayBuffer(p) {
110
+ const buf = await readFile(p);
111
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
112
+ }
113
+ Filesystem2.readArrayBuffer = readArrayBuffer;
114
+ function isEnoent(e) {
115
+ return typeof e === "object" && e !== null && "code" in e && e.code === "ENOENT";
116
+ }
117
+ async function write(p, content, mode) {
118
+ try {
119
+ if (mode) {
120
+ await writeFile(p, content, { mode });
121
+ } else {
122
+ await writeFile(p, content);
123
+ }
124
+ } catch (e) {
125
+ if (isEnoent(e)) {
126
+ await mkdir(dirname(p), { recursive: true });
127
+ if (mode) {
128
+ await writeFile(p, content, { mode });
129
+ } else {
130
+ await writeFile(p, content);
131
+ }
132
+ return;
133
+ }
134
+ throw e;
135
+ }
136
+ }
137
+ Filesystem2.write = write;
138
+ async function writeJson(p, data2, mode) {
139
+ return write(p, JSON.stringify(data2, null, 2), mode);
140
+ }
141
+ Filesystem2.writeJson = writeJson;
142
+ async function writeStream(p, stream, mode) {
143
+ const dir = dirname(p);
144
+ if (!existsSync(dir)) {
145
+ await mkdir(dir, { recursive: true });
146
+ }
147
+ const nodeStream = stream instanceof ReadableStream ? Readable.fromWeb(stream) : stream;
148
+ const writeStream2 = createWriteStream(p);
149
+ await pipeline(nodeStream, writeStream2);
150
+ if (mode) {
151
+ await chmod(p, mode);
152
+ }
153
+ }
154
+ Filesystem2.writeStream = writeStream;
155
+ function mimeType(p) {
156
+ return lookup(p) || "application/octet-stream";
157
+ }
158
+ Filesystem2.mimeType = mimeType;
159
+ function normalizePath(p) {
160
+ if (process.platform !== "win32") return p;
161
+ const resolved = win32.normalize(win32.resolve(windowsPath(p)));
162
+ try {
163
+ return realpathSync.native(resolved);
164
+ } catch {
165
+ return resolved;
166
+ }
167
+ }
168
+ Filesystem2.normalizePath = normalizePath;
169
+ function normalizePathPattern(p) {
170
+ if (process.platform !== "win32") return p;
171
+ if (p === "*") return p;
172
+ const match = p.match(/^(.*)[\\/]\*$/);
173
+ if (!match) return normalizePath(p);
174
+ const dir = /^[A-Za-z]:$/.test(match[1]) ? match[1] + "\\" : match[1];
175
+ return join(normalizePath(dir), "*");
176
+ }
177
+ Filesystem2.normalizePathPattern = normalizePathPattern;
178
+ function resolve(p) {
179
+ const resolved = pathResolve(windowsPath(p));
180
+ try {
181
+ return normalizePath(realpathSync(resolved));
182
+ } catch (e) {
183
+ if (isEnoent(e)) return normalizePath(resolved);
184
+ throw e;
185
+ }
186
+ }
187
+ Filesystem2.resolve = resolve;
188
+ function windowsPath(p) {
189
+ if (process.platform !== "win32") return p;
190
+ return p.replace(/^\/([a-zA-Z]):(?:[\\/]|$)/, (_, drive) => `${drive.toUpperCase()}:/`).replace(/^\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`).replace(/^\/cygdrive\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`).replace(/^\/mnt\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`);
191
+ }
192
+ Filesystem2.windowsPath = windowsPath;
193
+ function overlaps(a, b) {
194
+ const relA = relative(a, b);
195
+ const relB = relative(b, a);
196
+ return !relA || !relA.startsWith("..") || !relB || !relB.startsWith("..");
197
+ }
198
+ Filesystem2.overlaps = overlaps;
199
+ function contains(parent, child) {
200
+ return !relative(parent, child).startsWith("..");
201
+ }
202
+ Filesystem2.contains = contains;
203
+ async function findUp(target, start, stop, options) {
204
+ const dirs = [start];
205
+ let current = start;
206
+ while (true) {
207
+ if (stop === current) break;
208
+ const parent = dirname(current);
209
+ if (parent === current) break;
210
+ dirs.push(parent);
211
+ current = parent;
212
+ }
213
+ const targets = Array.isArray(target) ? target : [target];
214
+ const result = [];
215
+ for (const dir of options?.rootFirst ? dirs.toReversed() : dirs) {
216
+ for (const item of targets) {
217
+ const search = join(dir, item);
218
+ if (await exists(search)) result.push(search);
219
+ }
220
+ }
221
+ return result;
222
+ }
223
+ Filesystem2.findUp = findUp;
224
+ async function* up(options) {
225
+ const { targets, start, stop } = options;
226
+ let current = start;
227
+ while (true) {
228
+ for (const target of targets) {
229
+ const search = join(current, target);
230
+ if (await exists(search)) yield search;
231
+ }
232
+ if (stop === current) break;
233
+ const parent = dirname(current);
234
+ if (parent === current) break;
235
+ current = parent;
236
+ }
237
+ }
238
+ Filesystem2.up = up;
239
+ async function globUp(pattern, start, stop) {
240
+ let current = start;
241
+ const result = [];
242
+ while (true) {
243
+ try {
244
+ const matches = await Glob.scan(pattern, {
245
+ cwd: current,
246
+ absolute: true,
247
+ include: "file",
248
+ dot: true
249
+ });
250
+ result.push(...matches);
251
+ } catch {
252
+ }
253
+ if (stop === current) break;
254
+ const parent = dirname(current);
255
+ if (parent === current) break;
256
+ current = parent;
257
+ }
258
+ return result;
259
+ }
260
+ Filesystem2.globUp = globUp;
261
+ })(Filesystem || (Filesystem = {}));
262
+
263
+ // packages/opencode/src/util/iife.ts
264
+ function iife(fn) {
265
+ return fn();
266
+ }
267
+
268
+ // packages/opencode/src/util/log.ts
269
+ import path2 from "path";
270
+ import fs2 from "fs/promises";
271
+ import { createWriteStream as createWriteStream2 } from "fs";
272
+
273
+ // packages/opencode/src/global/index.ts
274
+ import fs from "fs/promises";
275
+ import { xdgData, xdgCache, xdgConfig, xdgState } from "xdg-basedir";
276
+ import path from "path";
277
+ import os from "os";
278
+ var app = "opencode";
279
+ var customDataDir = process.env["OPENCODE_DATA_DIR"];
280
+ var data = customDataDir || path.join(xdgData, app);
281
+ var cache = path.join(xdgCache, app);
282
+ var config = customDataDir ? path.join(customDataDir, "config") : path.join(xdgConfig, app);
283
+ var state = customDataDir ? path.join(customDataDir, "state") : path.join(xdgState, app);
284
+ var Global;
285
+ ((Global2) => {
286
+ Global2.Path = {
287
+ // Allow override via OPENCODE_TEST_HOME for test isolation
288
+ get home() {
289
+ return process.env.OPENCODE_TEST_HOME || os.homedir();
290
+ },
291
+ data,
292
+ bin: path.join(cache, "bin"),
293
+ log: path.join(data, "log"),
294
+ cache,
295
+ config,
296
+ state
297
+ };
298
+ })(Global || (Global = {}));
299
+ await Promise.all([
300
+ fs.mkdir(Global.Path.data, { recursive: true }),
301
+ fs.mkdir(Global.Path.config, { recursive: true }),
302
+ fs.mkdir(Global.Path.state, { recursive: true }),
303
+ fs.mkdir(Global.Path.log, { recursive: true }),
304
+ fs.mkdir(Global.Path.bin, { recursive: true })
305
+ ]);
306
+ var CACHE_VERSION = "21";
307
+ var version = await Filesystem.readText(path.join(Global.Path.cache, "version")).catch(() => "0");
308
+ if (version !== CACHE_VERSION) {
309
+ try {
310
+ const contents = await fs.readdir(Global.Path.cache);
311
+ await Promise.all(
312
+ contents.map(
313
+ (item) => fs.rm(path.join(Global.Path.cache, item), {
314
+ recursive: true,
315
+ force: true
316
+ })
317
+ )
318
+ );
319
+ } catch (e) {
320
+ }
321
+ await Filesystem.write(path.join(Global.Path.cache, "version"), CACHE_VERSION);
322
+ }
323
+
324
+ // packages/opencode/src/util/log.ts
325
+ import z from "zod";
326
+ var Log;
327
+ ((Log2) => {
328
+ Log2.Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).meta({ ref: "LogLevel", description: "Log level" });
329
+ const levelPriority = {
330
+ DEBUG: 0,
331
+ INFO: 1,
332
+ WARN: 2,
333
+ ERROR: 3
334
+ };
335
+ let level = "INFO";
336
+ function shouldLog(input) {
337
+ return levelPriority[input] >= levelPriority[level];
338
+ }
339
+ const loggers = /* @__PURE__ */ new Map();
340
+ Log2.Default = create({ service: "default" });
341
+ let logpath = "";
342
+ function file() {
343
+ return logpath;
344
+ }
345
+ Log2.file = file;
346
+ let write = (msg) => {
347
+ process.stderr.write(msg);
348
+ return msg.length;
349
+ };
350
+ async function init2(options) {
351
+ if (options.level) level = options.level;
352
+ cleanup(Global.Path.log);
353
+ if (options.print) return;
354
+ logpath = path2.join(
355
+ Global.Path.log,
356
+ options.dev ? "dev.log" : (/* @__PURE__ */ new Date()).toISOString().split(".")[0].replace(/:/g, "") + ".log"
357
+ );
358
+ await fs2.truncate(logpath).catch(() => {
359
+ });
360
+ const stream = createWriteStream2(logpath, { flags: "a" });
361
+ write = async (msg) => {
362
+ return new Promise((resolve, reject) => {
363
+ stream.write(msg, (err) => {
364
+ if (err) reject(err);
365
+ else resolve(msg.length);
366
+ });
367
+ });
368
+ };
369
+ }
370
+ Log2.init = init2;
371
+ async function cleanup(dir) {
372
+ const files = await Glob.scan("????-??-??T??????.log", {
373
+ cwd: dir,
374
+ absolute: true,
375
+ include: "file"
376
+ });
377
+ if (files.length <= 5) return;
378
+ const filesToDelete = files.slice(0, -10);
379
+ await Promise.all(filesToDelete.map((file2) => fs2.unlink(file2).catch(() => {
380
+ })));
381
+ }
382
+ function formatError(error, depth = 0) {
383
+ const result = error.message;
384
+ return error.cause instanceof Error && depth < 10 ? result + " Caused by: " + formatError(error.cause, depth + 1) : result;
385
+ }
386
+ let last = Date.now();
387
+ function create(tags) {
388
+ tags = tags || {};
389
+ const service = tags["service"];
390
+ if (service && typeof service === "string") {
391
+ const cached = loggers.get(service);
392
+ if (cached) {
393
+ return cached;
394
+ }
395
+ }
396
+ function build(message, extra) {
397
+ const prefix = Object.entries({
398
+ ...tags,
399
+ ...extra
400
+ }).filter(([_, value]) => value !== void 0 && value !== null).map(([key, value]) => {
401
+ const prefix2 = `${key}=`;
402
+ if (value instanceof Error) return prefix2 + formatError(value);
403
+ if (typeof value === "object") return prefix2 + JSON.stringify(value);
404
+ return prefix2 + value;
405
+ }).join(" ");
406
+ const next = /* @__PURE__ */ new Date();
407
+ const diff = next.getTime() - last;
408
+ last = next.getTime();
409
+ return [next.toISOString().split(".")[0], "+" + diff + "ms", prefix, message].filter(Boolean).join(" ") + "\n";
410
+ }
411
+ const result = {
412
+ debug(message, extra) {
413
+ if (shouldLog("DEBUG")) {
414
+ write("DEBUG " + build(message, extra));
415
+ }
416
+ },
417
+ info(message, extra) {
418
+ if (shouldLog("INFO")) {
419
+ write("INFO " + build(message, extra));
420
+ }
421
+ },
422
+ error(message, extra) {
423
+ if (shouldLog("ERROR")) {
424
+ write("ERROR " + build(message, extra));
425
+ }
426
+ },
427
+ warn(message, extra) {
428
+ if (shouldLog("WARN")) {
429
+ write("WARN " + build(message, extra));
430
+ }
431
+ },
432
+ tag(key, value) {
433
+ if (tags) tags[key] = value;
434
+ return result;
435
+ },
436
+ clone() {
437
+ return Log2.create({ ...tags });
438
+ },
439
+ time(message, extra) {
440
+ const now = Date.now();
441
+ result.info(message, { status: "started", ...extra });
442
+ function stop() {
443
+ result.info(message, {
444
+ status: "completed",
445
+ duration: Date.now() - now,
446
+ ...extra
447
+ });
448
+ }
449
+ return {
450
+ stop,
451
+ [Symbol.dispose]() {
452
+ stop();
453
+ }
454
+ };
455
+ }
456
+ };
457
+ if (service && typeof service === "string") {
458
+ loggers.set(service, result);
459
+ }
460
+ return result;
461
+ }
462
+ Log2.create = create;
463
+ })(Log || (Log = {}));
464
+
465
+ // packages/opencode/src/util/context.ts
466
+ import { AsyncLocalStorage } from "async_hooks";
467
+ var Context;
468
+ ((Context2) => {
469
+ class NotFound extends Error {
470
+ constructor(name) {
471
+ super(`No context found for ${name}`);
472
+ this.name = name;
473
+ }
474
+ name;
475
+ }
476
+ Context2.NotFound = NotFound;
477
+ function create(name) {
478
+ const storage = new AsyncLocalStorage();
479
+ return {
480
+ use() {
481
+ const result = storage.getStore();
482
+ if (!result) {
483
+ throw new NotFound(name);
484
+ }
485
+ return result;
486
+ },
487
+ provide(value, fn) {
488
+ return storage.run(value, fn);
489
+ }
490
+ };
491
+ }
492
+ Context2.create = create;
493
+ })(Context || (Context = {}));
494
+
495
+ // packages/opencode/src/project/project.ts
496
+ import z6 from "zod";
497
+
498
+ // packages/opencode/src/storage/db.ts
499
+ var db_exports = {};
500
+ __export(db_exports, {
501
+ Database: () => Database,
502
+ NotFoundError: () => NotFoundError
503
+ });
504
+ __reExport(db_exports, drizzle_orm_star);
505
+ import { migrate } from "drizzle-orm/node-sqlite/migrator";
506
+ import * as drizzle_orm_star from "drizzle-orm";
507
+
508
+ // packages/opencode/src/util/lazy.ts
509
+ function lazy(fn) {
510
+ let value;
511
+ let loaded = false;
512
+ const result = () => {
513
+ if (loaded) return value;
514
+ try {
515
+ value = fn();
516
+ loaded = true;
517
+ return value;
518
+ } catch (e) {
519
+ throw e;
520
+ }
521
+ };
522
+ result.reset = () => {
523
+ loaded = false;
524
+ value = void 0;
525
+ };
526
+ return result;
527
+ }
528
+
529
+ // packages/util/src/error.ts
530
+ import z2 from "zod";
531
+ var NamedError = class _NamedError extends Error {
532
+ static create(name, data2) {
533
+ const schema = z2.object({
534
+ name: z2.literal(name),
535
+ data: data2
536
+ }).meta({
537
+ ref: name
538
+ });
539
+ const result = class extends _NamedError {
540
+ constructor(data3, options) {
541
+ super(name, options);
542
+ this.data = data3;
543
+ this.name = name;
544
+ }
545
+ data;
546
+ static Schema = schema;
547
+ name = name;
548
+ static isInstance(input) {
549
+ return typeof input === "object" && "name" in input && input.name === name;
550
+ }
551
+ schema() {
552
+ return schema;
553
+ }
554
+ toObject() {
555
+ return {
556
+ name,
557
+ data: this.data
558
+ };
559
+ }
560
+ };
561
+ Object.defineProperty(result, "name", { value: name });
562
+ return result;
563
+ }
564
+ static Unknown = _NamedError.create(
565
+ "UnknownError",
566
+ z2.object({
567
+ message: z2.string()
568
+ })
569
+ );
570
+ };
571
+
572
+ // packages/opencode/src/storage/db.ts
573
+ import z3 from "zod";
574
+ import path3 from "path";
575
+ import { readFileSync, readdirSync, existsSync as existsSync2 } from "fs";
576
+
577
+ // packages/opencode/src/flag/flag.ts
578
+ import { Config } from "effect";
579
+ function truthy(key) {
580
+ const value = process.env[key]?.toLowerCase();
581
+ return value === "true" || value === "1";
582
+ }
583
+ function falsy(key) {
584
+ const value = process.env[key]?.toLowerCase();
585
+ return value === "false" || value === "0";
586
+ }
587
+ var Flag;
588
+ ((Flag2) => {
589
+ Flag2.OPENCODE_AUTO_SHARE = truthy("OPENCODE_AUTO_SHARE");
590
+ Flag2.OPENCODE_AUTO_HEAP_SNAPSHOT = truthy("OPENCODE_AUTO_HEAP_SNAPSHOT");
591
+ Flag2.OPENCODE_GIT_BASH_PATH = process.env["OPENCODE_GIT_BASH_PATH"];
592
+ Flag2.OPENCODE_CONFIG = process.env["OPENCODE_CONFIG"];
593
+ Flag2.OPENCODE_CONFIG_CONTENT = process.env["OPENCODE_CONFIG_CONTENT"];
594
+ Flag2.OPENCODE_DISABLE_AUTOUPDATE = truthy("OPENCODE_DISABLE_AUTOUPDATE");
595
+ Flag2.OPENCODE_ALWAYS_NOTIFY_UPDATE = truthy("OPENCODE_ALWAYS_NOTIFY_UPDATE");
596
+ Flag2.OPENCODE_DISABLE_PRUNE = truthy("OPENCODE_DISABLE_PRUNE");
597
+ Flag2.OPENCODE_DISABLE_TERMINAL_TITLE = truthy("OPENCODE_DISABLE_TERMINAL_TITLE");
598
+ Flag2.OPENCODE_SHOW_TTFD = truthy("OPENCODE_SHOW_TTFD");
599
+ Flag2.OPENCODE_PERMISSION = process.env["OPENCODE_PERMISSION"];
600
+ Flag2.OPENCODE_DISABLE_DEFAULT_PLUGINS = truthy("OPENCODE_DISABLE_DEFAULT_PLUGINS");
601
+ Flag2.OPENCODE_DISABLE_LSP_DOWNLOAD = truthy("OPENCODE_DISABLE_LSP_DOWNLOAD");
602
+ Flag2.OPENCODE_ENABLE_EXPERIMENTAL_MODELS = truthy("OPENCODE_ENABLE_EXPERIMENTAL_MODELS");
603
+ Flag2.OPENCODE_DISABLE_AUTOCOMPACT = truthy("OPENCODE_DISABLE_AUTOCOMPACT");
604
+ Flag2.OPENCODE_DISABLE_MODELS_FETCH = truthy("OPENCODE_DISABLE_MODELS_FETCH");
605
+ Flag2.OPENCODE_DISABLE_MOUSE = truthy("OPENCODE_DISABLE_MOUSE");
606
+ Flag2.OPENCODE_DISABLE_CLAUDE_CODE = truthy("OPENCODE_DISABLE_CLAUDE_CODE");
607
+ Flag2.OPENCODE_DISABLE_CLAUDE_CODE_PROMPT = Flag2.OPENCODE_DISABLE_CLAUDE_CODE || truthy("OPENCODE_DISABLE_CLAUDE_CODE_PROMPT");
608
+ Flag2.OPENCODE_DISABLE_CLAUDE_CODE_SKILLS = Flag2.OPENCODE_DISABLE_CLAUDE_CODE || truthy("OPENCODE_DISABLE_CLAUDE_CODE_SKILLS");
609
+ Flag2.OPENCODE_DISABLE_EXTERNAL_SKILLS = Flag2.OPENCODE_DISABLE_CLAUDE_CODE_SKILLS || truthy("OPENCODE_DISABLE_EXTERNAL_SKILLS");
610
+ Flag2.OPENCODE_FAKE_VCS = process.env["OPENCODE_FAKE_VCS"];
611
+ Flag2.OPENCODE_SERVER_PASSWORD = process.env["OPENCODE_SERVER_PASSWORD"];
612
+ Flag2.OPENCODE_SERVER_USERNAME = process.env["OPENCODE_SERVER_USERNAME"];
613
+ Flag2.OPENCODE_ENABLE_QUESTION_TOOL = truthy("OPENCODE_ENABLE_QUESTION_TOOL");
614
+ Flag2.OPENCODE_EXPERIMENTAL = truthy("OPENCODE_EXPERIMENTAL");
615
+ Flag2.OPENCODE_EXPERIMENTAL_FILEWATCHER = Config.boolean("OPENCODE_EXPERIMENTAL_FILEWATCHER").pipe(
616
+ Config.withDefault(false)
617
+ );
618
+ Flag2.OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER = Config.boolean(
619
+ "OPENCODE_EXPERIMENTAL_DISABLE_FILEWATCHER"
620
+ ).pipe(Config.withDefault(false));
621
+ Flag2.OPENCODE_EXPERIMENTAL_ICON_DISCOVERY = Flag2.OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_ICON_DISCOVERY");
622
+ const copy = process.env["OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT"];
623
+ Flag2.OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT = copy === void 0 ? process.platform === "win32" : truthy("OPENCODE_EXPERIMENTAL_DISABLE_COPY_ON_SELECT");
624
+ Flag2.OPENCODE_ENABLE_EXA = truthy("OPENCODE_ENABLE_EXA") || Flag2.OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_EXA");
625
+ Flag2.OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS = number("OPENCODE_EXPERIMENTAL_BASH_DEFAULT_TIMEOUT_MS");
626
+ Flag2.OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX = number("OPENCODE_EXPERIMENTAL_OUTPUT_TOKEN_MAX");
627
+ Flag2.OPENCODE_EXPERIMENTAL_OXFMT = Flag2.OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_OXFMT");
628
+ Flag2.OPENCODE_EXPERIMENTAL_LSP_TY = truthy("OPENCODE_EXPERIMENTAL_LSP_TY");
629
+ Flag2.OPENCODE_EXPERIMENTAL_LSP_TOOL = Flag2.OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_LSP_TOOL");
630
+ Flag2.OPENCODE_DISABLE_FILETIME_CHECK = Config.boolean("OPENCODE_DISABLE_FILETIME_CHECK").pipe(
631
+ Config.withDefault(false)
632
+ );
633
+ Flag2.OPENCODE_EXPERIMENTAL_PLAN_MODE = Flag2.OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_PLAN_MODE");
634
+ Flag2.OPENCODE_EXPERIMENTAL_WORKSPACES = Flag2.OPENCODE_EXPERIMENTAL || truthy("OPENCODE_EXPERIMENTAL_WORKSPACES");
635
+ Flag2.OPENCODE_EXPERIMENTAL_MARKDOWN = !falsy("OPENCODE_EXPERIMENTAL_MARKDOWN");
636
+ Flag2.OPENCODE_MODELS_URL = process.env["OPENCODE_MODELS_URL"];
637
+ Flag2.OPENCODE_MODELS_PATH = process.env["OPENCODE_MODELS_PATH"];
638
+ Flag2.OPENCODE_DISABLE_EMBEDDED_WEB_UI = truthy("OPENCODE_DISABLE_EMBEDDED_WEB_UI");
639
+ Flag2.OPENCODE_DB = process.env["OPENCODE_DB"];
640
+ Flag2.OPENCODE_DISABLE_CHANNEL_DB = truthy("OPENCODE_DISABLE_CHANNEL_DB");
641
+ Flag2.OPENCODE_SKIP_MIGRATIONS = truthy("OPENCODE_SKIP_MIGRATIONS");
642
+ Flag2.OPENCODE_STRICT_CONFIG_DEPS = truthy("OPENCODE_STRICT_CONFIG_DEPS");
643
+ function number(key) {
644
+ const value = process.env[key];
645
+ if (!value) return void 0;
646
+ const parsed = Number(value);
647
+ return Number.isInteger(parsed) && parsed > 0 ? parsed : void 0;
648
+ }
649
+ })(Flag || (Flag = {}));
650
+ Object.defineProperty(Flag, "OPENCODE_DISABLE_PROJECT_CONFIG", {
651
+ get() {
652
+ return truthy("OPENCODE_DISABLE_PROJECT_CONFIG");
653
+ },
654
+ enumerable: true,
655
+ configurable: false
656
+ });
657
+ Object.defineProperty(Flag, "OPENCODE_TUI_CONFIG", {
658
+ get() {
659
+ return process.env["OPENCODE_TUI_CONFIG"];
660
+ },
661
+ enumerable: true,
662
+ configurable: false
663
+ });
664
+ Object.defineProperty(Flag, "OPENCODE_CONFIG_DIR", {
665
+ get() {
666
+ return process.env["OPENCODE_CONFIG_DIR"];
667
+ },
668
+ enumerable: true,
669
+ configurable: false
670
+ });
671
+ Object.defineProperty(Flag, "OPENCODE_PURE", {
672
+ get() {
673
+ return truthy("OPENCODE_PURE");
674
+ },
675
+ enumerable: true,
676
+ configurable: false
677
+ });
678
+ Object.defineProperty(Flag, "OPENCODE_PLUGIN_META_FILE", {
679
+ get() {
680
+ return process.env["OPENCODE_PLUGIN_META_FILE"];
681
+ },
682
+ enumerable: true,
683
+ configurable: false
684
+ });
685
+ Object.defineProperty(Flag, "OPENCODE_CLIENT", {
686
+ get() {
687
+ return process.env["OPENCODE_CLIENT"] ?? "cli";
688
+ },
689
+ enumerable: true,
690
+ configurable: false
691
+ });
692
+
693
+ // packages/opencode/src/installation/meta.ts
694
+ var VERSION = typeof OPENCODE_VERSION === "string" ? OPENCODE_VERSION : "local";
695
+ var CHANNEL = typeof OPENCODE_CHANNEL === "string" ? OPENCODE_CHANNEL : "local";
696
+
697
+ // packages/opencode/src/effect/instance-state.ts
698
+ import { Effect, Fiber, ScopedCache, ServiceMap as ServiceMap2 } from "effect";
699
+
700
+ // packages/opencode/src/effect/instance-ref.ts
701
+ import { ServiceMap } from "effect";
702
+ var InstanceRef = ServiceMap.Reference("~opencode/InstanceRef", {
703
+ defaultValue: () => void 0
704
+ });
705
+
706
+ // packages/opencode/src/effect/instance-state.ts
707
+ var TypeId = "~opencode/InstanceState";
708
+ var InstanceState;
709
+ ((InstanceState2) => {
710
+ InstanceState2.bind = (fn) => {
711
+ try {
712
+ return Instance.bind(fn);
713
+ } catch (err) {
714
+ if (!(err instanceof Context.NotFound)) throw err;
715
+ }
716
+ const fiber = Fiber.getCurrent();
717
+ const ctx = fiber ? ServiceMap2.getReferenceUnsafe(fiber.services, InstanceRef) : void 0;
718
+ if (!ctx) return fn;
719
+ return ((...args) => Instance.restore(ctx, () => fn(...args)));
720
+ };
721
+ InstanceState2.context = Effect.gen(function* () {
722
+ return (yield* InstanceRef) ?? Instance.current;
723
+ });
724
+ InstanceState2.directory = Effect.map(InstanceState2.context, (ctx) => ctx.directory);
725
+ InstanceState2.make = (init2) => Effect.gen(function* () {
726
+ const cache3 = yield* ScopedCache.make({
727
+ capacity: Number.POSITIVE_INFINITY,
728
+ lookup: () => Effect.gen(function* () {
729
+ return yield* init2(yield* InstanceState2.context);
730
+ })
731
+ });
732
+ const off = registerDisposer((directory2) => Effect.runPromise(ScopedCache.invalidate(cache3, directory2)));
733
+ yield* Effect.addFinalizer(() => Effect.sync(off));
734
+ return {
735
+ [TypeId]: TypeId,
736
+ cache: cache3
737
+ };
738
+ });
739
+ InstanceState2.get = (self) => Effect.gen(function* () {
740
+ return yield* ScopedCache.get(self.cache, yield* InstanceState2.directory);
741
+ });
742
+ InstanceState2.use = (self, select) => Effect.map((0, InstanceState2.get)(self), select);
743
+ InstanceState2.useEffect = (self, select) => Effect.flatMap((0, InstanceState2.get)(self), select);
744
+ InstanceState2.has = (self) => Effect.gen(function* () {
745
+ return yield* ScopedCache.has(self.cache, yield* InstanceState2.directory);
746
+ });
747
+ InstanceState2.invalidate = (self) => Effect.gen(function* () {
748
+ return yield* ScopedCache.invalidate(self.cache, yield* InstanceState2.directory);
749
+ });
750
+ InstanceState2.withALS = (fn) => Effect.map(InstanceState2.context, (ctx) => Instance.restore(ctx, fn));
751
+ })(InstanceState || (InstanceState = {}));
752
+
753
+ // packages/opencode/src/storage/db.node.ts
754
+ import { DatabaseSync } from "node:sqlite";
755
+ import { drizzle } from "drizzle-orm/node-sqlite";
756
+ function init(path5) {
757
+ const sqlite = new DatabaseSync(path5);
758
+ const db = drizzle({ client: sqlite });
759
+ return db;
760
+ }
761
+
762
+ // packages/opencode/src/storage/db.ts
763
+ var NotFoundError = NamedError.create(
764
+ "NotFoundError",
765
+ z3.object({
766
+ message: z3.string()
767
+ })
768
+ );
769
+ var log = Log.create({ service: "db" });
770
+ var Database;
771
+ ((Database2) => {
772
+ function getChannelPath() {
773
+ if (["latest", "beta"].includes(CHANNEL) || Flag.OPENCODE_DISABLE_CHANNEL_DB)
774
+ return path3.join(Global.Path.data, "opencode.db");
775
+ const safe = CHANNEL.replace(/[^a-zA-Z0-9._-]/g, "-");
776
+ return path3.join(Global.Path.data, `opencode-${safe}.db`);
777
+ }
778
+ Database2.getChannelPath = getChannelPath;
779
+ Database2.Path = iife(() => {
780
+ if (Flag.OPENCODE_DB) {
781
+ if (Flag.OPENCODE_DB === ":memory:" || path3.isAbsolute(Flag.OPENCODE_DB)) return Flag.OPENCODE_DB;
782
+ return path3.join(Global.Path.data, Flag.OPENCODE_DB);
783
+ }
784
+ return getChannelPath();
785
+ });
786
+ function time(tag) {
787
+ const match = /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/.exec(tag);
788
+ if (!match) return 0;
789
+ return Date.UTC(
790
+ Number(match[1]),
791
+ Number(match[2]) - 1,
792
+ Number(match[3]),
793
+ Number(match[4]),
794
+ Number(match[5]),
795
+ Number(match[6])
796
+ );
797
+ }
798
+ function migrations(dir) {
799
+ const dirs = readdirSync(dir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
800
+ const sql = dirs.map((name) => {
801
+ const file = path3.join(dir, name, "migration.sql");
802
+ if (!existsSync2(file)) return;
803
+ return {
804
+ sql: readFileSync(file, "utf-8"),
805
+ timestamp: time(name),
806
+ name
807
+ };
808
+ }).filter(Boolean);
809
+ return sql.sort((a, b) => a.timestamp - b.timestamp);
810
+ }
811
+ Database2.Client = lazy(() => {
812
+ log.info("opening database", { path: Database2.Path });
813
+ const db = init(Database2.Path);
814
+ db.run("PRAGMA journal_mode = WAL");
815
+ db.run("PRAGMA synchronous = NORMAL");
816
+ db.run("PRAGMA busy_timeout = 5000");
817
+ db.run("PRAGMA cache_size = -64000");
818
+ db.run("PRAGMA foreign_keys = ON");
819
+ db.run("PRAGMA wal_checkpoint(PASSIVE)");
820
+ const migrationsDir = path3.join(import.meta.dirname, "../packages/opencode/migration");
821
+ if (typeof OPENCODE_MIGRATIONS !== "undefined") {
822
+ const entries = OPENCODE_MIGRATIONS;
823
+ if (entries.length > 0) {
824
+ log.info("applying migrations", { count: entries.length, mode: "bundled" });
825
+ if (Flag.OPENCODE_SKIP_MIGRATIONS) {
826
+ for (const item of entries) item.sql = "select 1;";
827
+ }
828
+ migrate(db, entries);
829
+ }
830
+ } else {
831
+ const entries = migrations(migrationsDir);
832
+ log.info("applying migrations", { count: entries.length, mode: "dev" });
833
+ if (!Flag.OPENCODE_SKIP_MIGRATIONS && entries.length > 0) {
834
+ migrate(db, { migrationsFolder: migrationsDir });
835
+ }
836
+ }
837
+ return db;
838
+ });
839
+ function close() {
840
+ (0, Database2.Client)().$client.close();
841
+ Database2.Client.reset();
842
+ }
843
+ Database2.close = close;
844
+ const ctx = Context.create("database");
845
+ function use(callback2) {
846
+ try {
847
+ return callback2(ctx.use().tx);
848
+ } catch (err) {
849
+ if (err instanceof Context.NotFound) {
850
+ const effects = [];
851
+ const result = ctx.provide({ effects, tx: (0, Database2.Client)() }, () => callback2((0, Database2.Client)()));
852
+ for (const effect3 of effects) effect3();
853
+ return result;
854
+ }
855
+ throw err;
856
+ }
857
+ }
858
+ Database2.use = use;
859
+ function effect2(fn) {
860
+ const bound = InstanceState.bind(fn);
861
+ try {
862
+ ctx.use().effects.push(bound);
863
+ } catch {
864
+ bound();
865
+ }
866
+ }
867
+ Database2.effect = effect2;
868
+ function transaction(callback2, options) {
869
+ try {
870
+ return callback2(ctx.use().tx);
871
+ } catch (err) {
872
+ if (err instanceof Context.NotFound) {
873
+ const effects = [];
874
+ const txCallback = InstanceState.bind((tx) => ctx.provide({ tx, effects }, () => callback2(tx)));
875
+ const result = (0, Database2.Client)().transaction(txCallback, { behavior: options?.behavior });
876
+ for (const effect3 of effects) effect3();
877
+ return result;
878
+ }
879
+ throw err;
880
+ }
881
+ }
882
+ Database2.transaction = transaction;
883
+ })(Database || (Database = {}));
884
+
885
+ // packages/opencode/src/project/project.sql.ts
886
+ import { sqliteTable, text, integer as integer2 } from "drizzle-orm/sqlite-core";
887
+
888
+ // packages/opencode/src/storage/schema.sql.ts
889
+ import { integer } from "drizzle-orm/sqlite-core";
890
+ var Timestamps = {
891
+ time_created: integer().notNull().$default(() => Date.now()),
892
+ time_updated: integer().notNull().$onUpdate(() => Date.now())
893
+ };
894
+
895
+ // packages/opencode/src/project/project.sql.ts
896
+ var ProjectTable = sqliteTable("project", {
897
+ id: text().$type().primaryKey(),
898
+ worktree: text().notNull(),
899
+ vcs: text(),
900
+ name: text(),
901
+ icon_url: text(),
902
+ icon_color: text(),
903
+ ...Timestamps,
904
+ time_initialized: integer2(),
905
+ sandboxes: text({ mode: "json" }).notNull().$type(),
906
+ commands: text({ mode: "json" }).$type()
907
+ });
908
+
909
+ // packages/opencode/src/session/session.sql.ts
910
+ import { sqliteTable as sqliteTable2, text as text2, integer as integer3, index, primaryKey } from "drizzle-orm/sqlite-core";
911
+ var SessionTable = sqliteTable2(
912
+ "session",
913
+ {
914
+ id: text2().$type().primaryKey(),
915
+ project_id: text2().$type().notNull().references(() => ProjectTable.id, { onDelete: "cascade" }),
916
+ workspace_id: text2().$type(),
917
+ parent_id: text2().$type(),
918
+ slug: text2().notNull(),
919
+ directory: text2().notNull(),
920
+ title: text2().notNull(),
921
+ version: text2().notNull(),
922
+ share_url: text2(),
923
+ summary_additions: integer3(),
924
+ summary_deletions: integer3(),
925
+ summary_files: integer3(),
926
+ summary_diffs: text2({ mode: "json" }).$type(),
927
+ revert: text2({ mode: "json" }).$type(),
928
+ permission: text2({ mode: "json" }).$type(),
929
+ ...Timestamps,
930
+ time_compacting: integer3(),
931
+ time_archived: integer3()
932
+ },
933
+ (table) => [
934
+ index("session_project_idx").on(table.project_id),
935
+ index("session_workspace_idx").on(table.workspace_id),
936
+ index("session_parent_idx").on(table.parent_id)
937
+ ]
938
+ );
939
+ var MessageTable = sqliteTable2(
940
+ "message",
941
+ {
942
+ id: text2().$type().primaryKey(),
943
+ session_id: text2().$type().notNull().references(() => SessionTable.id, { onDelete: "cascade" }),
944
+ ...Timestamps,
945
+ data: text2({ mode: "json" }).notNull().$type()
946
+ },
947
+ (table) => [index("message_session_time_created_id_idx").on(table.session_id, table.time_created, table.id)]
948
+ );
949
+ var PartTable = sqliteTable2(
950
+ "part",
951
+ {
952
+ id: text2().$type().primaryKey(),
953
+ message_id: text2().$type().notNull().references(() => MessageTable.id, { onDelete: "cascade" }),
954
+ session_id: text2().$type().notNull(),
955
+ ...Timestamps,
956
+ data: text2({ mode: "json" }).notNull().$type()
957
+ },
958
+ (table) => [
959
+ index("part_message_id_id_idx").on(table.message_id, table.id),
960
+ index("part_session_idx").on(table.session_id)
961
+ ]
962
+ );
963
+ var TodoTable = sqliteTable2(
964
+ "todo",
965
+ {
966
+ session_id: text2().$type().notNull().references(() => SessionTable.id, { onDelete: "cascade" }),
967
+ content: text2().notNull(),
968
+ status: text2().notNull(),
969
+ priority: text2().notNull(),
970
+ position: integer3().notNull(),
971
+ ...Timestamps
972
+ },
973
+ (table) => [
974
+ primaryKey({ columns: [table.session_id, table.position] }),
975
+ index("todo_session_idx").on(table.session_id)
976
+ ]
977
+ );
978
+ var PermissionTable = sqliteTable2("permission", {
979
+ project_id: text2().primaryKey().references(() => ProjectTable.id, { onDelete: "cascade" }),
980
+ ...Timestamps,
981
+ data: text2({ mode: "json" }).notNull().$type()
982
+ });
983
+
984
+ // packages/opencode/src/bus/bus-event.ts
985
+ import z4 from "zod";
986
+ var BusEvent;
987
+ ((BusEvent2) => {
988
+ const registry = /* @__PURE__ */ new Map();
989
+ function define(type, properties) {
990
+ const result = {
991
+ type,
992
+ properties
993
+ };
994
+ registry.set(type, result);
995
+ return result;
996
+ }
997
+ BusEvent2.define = define;
998
+ function payloads() {
999
+ return z4.discriminatedUnion(
1000
+ "type",
1001
+ registry.entries().map(([type, def]) => {
1002
+ return z4.object({
1003
+ type: z4.literal(type),
1004
+ properties: def.properties
1005
+ }).meta({
1006
+ ref: "Event." + def.type
1007
+ });
1008
+ }).toArray()
1009
+ ).meta({
1010
+ ref: "Event"
1011
+ });
1012
+ }
1013
+ BusEvent2.payloads = payloads;
1014
+ })(BusEvent || (BusEvent = {}));
1015
+
1016
+ // packages/opencode/src/util/which.ts
1017
+ import whichPkg from "which";
1018
+ import path4 from "path";
1019
+ function which(cmd, env) {
1020
+ const base = env?.PATH ?? env?.Path ?? process.env.PATH ?? process.env.Path ?? "";
1021
+ const full = base ? base + path4.delimiter + Global.Path.bin : Global.Path.bin;
1022
+ const result = whichPkg.sync(cmd, {
1023
+ nothrow: true,
1024
+ path: full,
1025
+ pathExt: env?.PATHEXT ?? env?.PathExt ?? process.env.PATHEXT ?? process.env.PathExt
1026
+ });
1027
+ return typeof result === "string" ? result : null;
1028
+ }
1029
+
1030
+ // packages/opencode/src/project/schema.ts
1031
+ import { Schema } from "effect";
1032
+ import z5 from "zod";
1033
+ var projectIdSchema = Schema.String.pipe(Schema.brand("ProjectID"));
1034
+ var ProjectID = projectIdSchema.pipe(
1035
+ withStatics((schema) => ({
1036
+ global: schema.makeUnsafe("global"),
1037
+ make: (id) => schema.makeUnsafe(id),
1038
+ zod: z5.string().pipe(z5.custom())
1039
+ }))
1040
+ );
1041
+
1042
+ // packages/opencode/src/project/project.ts
1043
+ import { Effect as Effect4, Layer as Layer3, Path as Path3, Scope as Scope2, ServiceMap as ServiceMap4, Stream as Stream2 } from "effect";
1044
+ import { ChildProcess as ChildProcess2, ChildProcessSpawner as ChildProcessSpawner2 } from "effect/unstable/process";
1045
+ import { NodePath as NodePath2 } from "@effect/platform-node";
1046
+
1047
+ // packages/opencode/src/filesystem/index.ts
1048
+ import { NodeFileSystem } from "@effect/platform-node";
1049
+ import { dirname as dirname2, join as join2, relative as relative2, resolve as pathResolve2 } from "path";
1050
+ import { realpathSync as realpathSync2 } from "fs";
1051
+ import * as NFS from "fs/promises";
1052
+ import { lookup as lookup2 } from "mime-types";
1053
+ import { Effect as Effect2, FileSystem, Layer, Schema as Schema2, ServiceMap as ServiceMap3 } from "effect";
1054
+ var AppFileSystem;
1055
+ ((AppFileSystem2) => {
1056
+ class FileSystemError extends Schema2.TaggedErrorClass()("FileSystemError", {
1057
+ method: Schema2.String,
1058
+ cause: Schema2.optional(Schema2.Defect)
1059
+ }) {
1060
+ }
1061
+ AppFileSystem2.FileSystemError = FileSystemError;
1062
+ class Service extends ServiceMap3.Service()("@opencode/FileSystem") {
1063
+ }
1064
+ AppFileSystem2.Service = Service;
1065
+ AppFileSystem2.layer = Layer.effect(
1066
+ Service,
1067
+ Effect2.gen(function* () {
1068
+ const fs3 = yield* FileSystem.FileSystem;
1069
+ const existsSafe = Effect2.fn("FileSystem.existsSafe")(function* (path5) {
1070
+ return yield* fs3.exists(path5).pipe(Effect2.orElseSucceed(() => false));
1071
+ });
1072
+ const isDir = Effect2.fn("FileSystem.isDir")(function* (path5) {
1073
+ const info = yield* fs3.stat(path5).pipe(Effect2.catch(() => Effect2.void));
1074
+ return info?.type === "Directory";
1075
+ });
1076
+ const isFile = Effect2.fn("FileSystem.isFile")(function* (path5) {
1077
+ const info = yield* fs3.stat(path5).pipe(Effect2.catch(() => Effect2.void));
1078
+ return info?.type === "File";
1079
+ });
1080
+ const readDirectoryEntries = Effect2.fn("FileSystem.readDirectoryEntries")(function* (dirPath) {
1081
+ return yield* Effect2.tryPromise({
1082
+ try: async () => {
1083
+ const entries = await NFS.readdir(dirPath, { withFileTypes: true });
1084
+ return entries.map(
1085
+ (e) => ({
1086
+ name: e.name,
1087
+ type: e.isDirectory() ? "directory" : e.isSymbolicLink() ? "symlink" : e.isFile() ? "file" : "other"
1088
+ })
1089
+ );
1090
+ },
1091
+ catch: (cause) => new FileSystemError({ method: "readDirectoryEntries", cause })
1092
+ });
1093
+ });
1094
+ const readJson = Effect2.fn("FileSystem.readJson")(function* (path5) {
1095
+ const text3 = yield* fs3.readFileString(path5);
1096
+ return JSON.parse(text3);
1097
+ });
1098
+ const writeJson = Effect2.fn("FileSystem.writeJson")(function* (path5, data2, mode) {
1099
+ const content = JSON.stringify(data2, null, 2);
1100
+ yield* fs3.writeFileString(path5, content);
1101
+ if (mode) yield* fs3.chmod(path5, mode);
1102
+ });
1103
+ const ensureDir = Effect2.fn("FileSystem.ensureDir")(function* (path5) {
1104
+ yield* fs3.makeDirectory(path5, { recursive: true });
1105
+ });
1106
+ const writeWithDirs = Effect2.fn("FileSystem.writeWithDirs")(function* (path5, content, mode) {
1107
+ const write = typeof content === "string" ? fs3.writeFileString(path5, content) : fs3.writeFile(path5, content);
1108
+ yield* write.pipe(
1109
+ Effect2.catchIf(
1110
+ (e) => e.reason._tag === "NotFound",
1111
+ () => Effect2.gen(function* () {
1112
+ yield* fs3.makeDirectory(dirname2(path5), { recursive: true });
1113
+ yield* write;
1114
+ })
1115
+ )
1116
+ );
1117
+ if (mode) yield* fs3.chmod(path5, mode);
1118
+ });
1119
+ const glob2 = Effect2.fn("FileSystem.glob")(function* (pattern, options) {
1120
+ return yield* Effect2.tryPromise({
1121
+ try: () => Glob.scan(pattern, options),
1122
+ catch: (cause) => new FileSystemError({ method: "glob", cause })
1123
+ });
1124
+ });
1125
+ const findUp = Effect2.fn("FileSystem.findUp")(function* (target, start, stop) {
1126
+ const result = [];
1127
+ let current = start;
1128
+ while (true) {
1129
+ const search = join2(current, target);
1130
+ if (yield* fs3.exists(search)) result.push(search);
1131
+ if (stop === current) break;
1132
+ const parent = dirname2(current);
1133
+ if (parent === current) break;
1134
+ current = parent;
1135
+ }
1136
+ return result;
1137
+ });
1138
+ const up = Effect2.fn("FileSystem.up")(function* (options) {
1139
+ const result = [];
1140
+ let current = options.start;
1141
+ while (true) {
1142
+ for (const target of options.targets) {
1143
+ const search = join2(current, target);
1144
+ if (yield* fs3.exists(search)) result.push(search);
1145
+ }
1146
+ if (options.stop === current) break;
1147
+ const parent = dirname2(current);
1148
+ if (parent === current) break;
1149
+ current = parent;
1150
+ }
1151
+ return result;
1152
+ });
1153
+ const globUp = Effect2.fn("FileSystem.globUp")(function* (pattern, start, stop) {
1154
+ const result = [];
1155
+ let current = start;
1156
+ while (true) {
1157
+ const matches = yield* glob2(pattern, { cwd: current, absolute: true, include: "file", dot: true }).pipe(
1158
+ Effect2.catch(() => Effect2.succeed([]))
1159
+ );
1160
+ result.push(...matches);
1161
+ if (stop === current) break;
1162
+ const parent = dirname2(current);
1163
+ if (parent === current) break;
1164
+ current = parent;
1165
+ }
1166
+ return result;
1167
+ });
1168
+ return Service.of({
1169
+ ...fs3,
1170
+ existsSafe,
1171
+ isDir,
1172
+ isFile,
1173
+ readDirectoryEntries,
1174
+ readJson,
1175
+ writeJson,
1176
+ ensureDir,
1177
+ writeWithDirs,
1178
+ findUp,
1179
+ up,
1180
+ globUp,
1181
+ glob: glob2,
1182
+ globMatch: Glob.match
1183
+ });
1184
+ })
1185
+ );
1186
+ AppFileSystem2.defaultLayer = AppFileSystem2.layer.pipe(Layer.provide(NodeFileSystem.layer));
1187
+ function mimeType(p) {
1188
+ return lookup2(p) || "application/octet-stream";
1189
+ }
1190
+ AppFileSystem2.mimeType = mimeType;
1191
+ function normalizePath(p) {
1192
+ if (process.platform !== "win32") return p;
1193
+ const resolved = pathResolve2(windowsPath(p));
1194
+ try {
1195
+ return realpathSync2.native(resolved);
1196
+ } catch {
1197
+ return resolved;
1198
+ }
1199
+ }
1200
+ AppFileSystem2.normalizePath = normalizePath;
1201
+ function normalizePathPattern(p) {
1202
+ if (process.platform !== "win32") return p;
1203
+ if (p === "*") return p;
1204
+ const match = p.match(/^(.*)[\\/]\*$/);
1205
+ if (!match) return normalizePath(p);
1206
+ const dir = /^[A-Za-z]:$/.test(match[1]) ? match[1] + "\\" : match[1];
1207
+ return join2(normalizePath(dir), "*");
1208
+ }
1209
+ AppFileSystem2.normalizePathPattern = normalizePathPattern;
1210
+ function resolve(p) {
1211
+ const resolved = pathResolve2(windowsPath(p));
1212
+ try {
1213
+ return normalizePath(realpathSync2(resolved));
1214
+ } catch (e) {
1215
+ if (e?.code === "ENOENT") return normalizePath(resolved);
1216
+ throw e;
1217
+ }
1218
+ }
1219
+ AppFileSystem2.resolve = resolve;
1220
+ function windowsPath(p) {
1221
+ if (process.platform !== "win32") return p;
1222
+ return p.replace(/^\/([a-zA-Z]):(?:[\\/]|$)/, (_, drive) => `${drive.toUpperCase()}:/`).replace(/^\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`).replace(/^\/cygdrive\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`).replace(/^\/mnt\/([a-zA-Z])(?:\/|$)/, (_, drive) => `${drive.toUpperCase()}:/`);
1223
+ }
1224
+ AppFileSystem2.windowsPath = windowsPath;
1225
+ function overlaps(a, b) {
1226
+ const relA = relative2(a, b);
1227
+ const relB = relative2(b, a);
1228
+ return !relA || !relA.startsWith("..") || !relB || !relB.startsWith("..");
1229
+ }
1230
+ AppFileSystem2.overlaps = overlaps;
1231
+ function contains(parent, child) {
1232
+ return !relative2(parent, child).startsWith("..");
1233
+ }
1234
+ AppFileSystem2.contains = contains;
1235
+ })(AppFileSystem || (AppFileSystem = {}));
1236
+
1237
+ // packages/opencode/src/effect/cross-spawn-spawner.ts
1238
+ import { NodeFileSystem as NodeFileSystem2, NodeSink, NodeStream } from "@effect/platform-node";
1239
+ import * as NodePath from "@effect/platform-node/NodePath";
1240
+ import * as Deferred from "effect/Deferred";
1241
+ import * as Effect3 from "effect/Effect";
1242
+ import * as Exit from "effect/Exit";
1243
+ import * as FileSystem2 from "effect/FileSystem";
1244
+ import * as Layer2 from "effect/Layer";
1245
+ import * as Path from "effect/Path";
1246
+ import * as PlatformError from "effect/PlatformError";
1247
+ import * as Predicate from "effect/Predicate";
1248
+ import * as Sink from "effect/Sink";
1249
+ import * as Stream from "effect/Stream";
1250
+ import * as ChildProcess from "effect/unstable/process/ChildProcess";
1251
+ import {
1252
+ ChildProcessSpawner,
1253
+ ExitCode,
1254
+ make as makeSpawner,
1255
+ makeHandle,
1256
+ ProcessId
1257
+ } from "effect/unstable/process/ChildProcessSpawner";
1258
+ import * as NodeChildProcess from "node:child_process";
1259
+ import { PassThrough } from "node:stream";
1260
+ import launch from "cross-spawn";
1261
+ var toError = (err) => err instanceof globalThis.Error ? err : new globalThis.Error(String(err));
1262
+ var toTag = (err) => {
1263
+ switch (err.code) {
1264
+ case "ENOENT":
1265
+ return "NotFound";
1266
+ case "EACCES":
1267
+ return "PermissionDenied";
1268
+ case "EEXIST":
1269
+ return "AlreadyExists";
1270
+ case "EISDIR":
1271
+ return "BadResource";
1272
+ case "ENOTDIR":
1273
+ return "BadResource";
1274
+ case "EBUSY":
1275
+ return "Busy";
1276
+ case "ELOOP":
1277
+ return "BadResource";
1278
+ default:
1279
+ return "Unknown";
1280
+ }
1281
+ };
1282
+ var flatten = (command) => {
1283
+ const commands = [];
1284
+ const opts = [];
1285
+ const walk = (cmd) => {
1286
+ switch (cmd._tag) {
1287
+ case "StandardCommand":
1288
+ commands.push(cmd);
1289
+ return;
1290
+ case "PipedCommand":
1291
+ walk(cmd.left);
1292
+ opts.push(cmd.options);
1293
+ walk(cmd.right);
1294
+ return;
1295
+ }
1296
+ };
1297
+ walk(command);
1298
+ if (commands.length === 0) throw new Error("flatten produced empty commands array");
1299
+ const [head, ...tail] = commands;
1300
+ return {
1301
+ commands: [head, ...tail],
1302
+ opts
1303
+ };
1304
+ };
1305
+ var toPlatformError = (method, err, command) => {
1306
+ const cmd = flatten(command).commands.map((x) => `${x.command} ${x.args.join(" ")}`).join(" | ");
1307
+ return PlatformError.systemError({
1308
+ _tag: toTag(err),
1309
+ module: "ChildProcess",
1310
+ method,
1311
+ pathOrDescriptor: cmd,
1312
+ syscall: err.syscall,
1313
+ cause: err
1314
+ });
1315
+ };
1316
+ var make2 = Effect3.gen(function* () {
1317
+ const fs3 = yield* FileSystem2.FileSystem;
1318
+ const path5 = yield* Path.Path;
1319
+ const cwd = Effect3.fnUntraced(function* (opts) {
1320
+ if (Predicate.isUndefined(opts.cwd)) return void 0;
1321
+ yield* fs3.access(opts.cwd);
1322
+ return path5.resolve(opts.cwd);
1323
+ });
1324
+ const env = (opts) => opts.extendEnv ? { ...globalThis.process.env, ...opts.env } : opts.env;
1325
+ const input = (x) => Stream.isStream(x) ? "pipe" : x;
1326
+ const output = (x) => Sink.isSink(x) ? "pipe" : x;
1327
+ const stdin = (opts) => {
1328
+ const cfg = { stream: "pipe", encoding: "utf-8", endOnDone: true };
1329
+ if (Predicate.isUndefined(opts.stdin)) return cfg;
1330
+ if (typeof opts.stdin === "string") return { ...cfg, stream: opts.stdin };
1331
+ if (Stream.isStream(opts.stdin)) return { ...cfg, stream: opts.stdin };
1332
+ return {
1333
+ stream: opts.stdin.stream,
1334
+ encoding: opts.stdin.encoding ?? cfg.encoding,
1335
+ endOnDone: opts.stdin.endOnDone ?? cfg.endOnDone
1336
+ };
1337
+ };
1338
+ const stdio = (opts, key) => {
1339
+ const cfg = opts[key];
1340
+ if (Predicate.isUndefined(cfg)) return { stream: "pipe" };
1341
+ if (typeof cfg === "string") return { stream: cfg };
1342
+ if (Sink.isSink(cfg)) return { stream: cfg };
1343
+ return { stream: cfg.stream };
1344
+ };
1345
+ const fds = (opts) => {
1346
+ if (Predicate.isUndefined(opts.additionalFds)) return [];
1347
+ return Object.entries(opts.additionalFds).flatMap(([name, config2]) => {
1348
+ const fd = ChildProcess.parseFdName(name);
1349
+ return Predicate.isUndefined(fd) ? [] : [{ fd, config: config2 }];
1350
+ }).toSorted((a, b) => a.fd - b.fd);
1351
+ };
1352
+ const stdios = (sin, sout, serr, extra) => {
1353
+ const pipe = (x) => process.platform === "win32" && x === "pipe" ? "overlapped" : x;
1354
+ const arr = [
1355
+ pipe(input(sin.stream)),
1356
+ pipe(output(sout.stream)),
1357
+ pipe(output(serr.stream))
1358
+ ];
1359
+ if (extra.length === 0) return arr;
1360
+ const max = extra.reduce((acc, x) => Math.max(acc, x.fd), 2);
1361
+ for (let i = 3; i <= max; i++) arr[i] = "ignore";
1362
+ for (const x of extra) arr[x.fd] = pipe("pipe");
1363
+ return arr;
1364
+ };
1365
+ const setupFds = Effect3.fnUntraced(function* (command, proc, extra) {
1366
+ if (extra.length === 0) {
1367
+ return {
1368
+ getInputFd: () => Sink.drain,
1369
+ getOutputFd: () => Stream.empty
1370
+ };
1371
+ }
1372
+ const ins = /* @__PURE__ */ new Map();
1373
+ const outs = /* @__PURE__ */ new Map();
1374
+ for (const x of extra) {
1375
+ const node = proc.stdio[x.fd];
1376
+ switch (x.config.type) {
1377
+ case "input": {
1378
+ let sink = Sink.drain;
1379
+ if (node && "write" in node) {
1380
+ sink = NodeSink.fromWritable({
1381
+ evaluate: () => node,
1382
+ onError: (err) => toPlatformError(`fromWritable(fd${x.fd})`, toError(err), command),
1383
+ endOnDone: true
1384
+ });
1385
+ }
1386
+ if (x.config.stream) yield* Effect3.forkScoped(Stream.run(x.config.stream, sink));
1387
+ ins.set(x.fd, sink);
1388
+ break;
1389
+ }
1390
+ case "output": {
1391
+ let stream = Stream.empty;
1392
+ if (node && "read" in node) {
1393
+ const tap = new PassThrough();
1394
+ node.on("error", (err) => tap.destroy(toError(err)));
1395
+ node.pipe(tap);
1396
+ stream = NodeStream.fromReadable({
1397
+ evaluate: () => tap,
1398
+ onError: (err) => toPlatformError(`fromReadable(fd${x.fd})`, toError(err), command)
1399
+ });
1400
+ }
1401
+ if (x.config.sink) stream = Stream.transduce(stream, x.config.sink);
1402
+ outs.set(x.fd, stream);
1403
+ break;
1404
+ }
1405
+ }
1406
+ }
1407
+ return {
1408
+ getInputFd: (fd) => ins.get(fd) ?? Sink.drain,
1409
+ getOutputFd: (fd) => outs.get(fd) ?? Stream.empty
1410
+ };
1411
+ });
1412
+ const setupStdin = (command, proc, cfg) => Effect3.suspend(() => {
1413
+ let sink = Sink.drain;
1414
+ if (Predicate.isNotNull(proc.stdin)) {
1415
+ sink = NodeSink.fromWritable({
1416
+ evaluate: () => proc.stdin,
1417
+ onError: (err) => toPlatformError("fromWritable(stdin)", toError(err), command),
1418
+ endOnDone: cfg.endOnDone,
1419
+ encoding: cfg.encoding
1420
+ });
1421
+ }
1422
+ if (Stream.isStream(cfg.stream)) return Effect3.as(Effect3.forkScoped(Stream.run(cfg.stream, sink)), sink);
1423
+ return Effect3.succeed(sink);
1424
+ });
1425
+ const setupOutput = (command, proc, out, err) => {
1426
+ let stdout = proc.stdout ? NodeStream.fromReadable({
1427
+ evaluate: () => proc.stdout,
1428
+ onError: (cause) => toPlatformError("fromReadable(stdout)", toError(cause), command)
1429
+ }) : Stream.empty;
1430
+ let stderr = proc.stderr ? NodeStream.fromReadable({
1431
+ evaluate: () => proc.stderr,
1432
+ onError: (cause) => toPlatformError("fromReadable(stderr)", toError(cause), command)
1433
+ }) : Stream.empty;
1434
+ if (Sink.isSink(out.stream)) stdout = Stream.transduce(stdout, out.stream);
1435
+ if (Sink.isSink(err.stream)) stderr = Stream.transduce(stderr, err.stream);
1436
+ return { stdout, stderr, all: Stream.merge(stdout, stderr) };
1437
+ };
1438
+ const spawn = (command, opts) => Effect3.callback((resume) => {
1439
+ const signal = Deferred.makeUnsafe();
1440
+ const proc = launch(command.command, command.args, opts);
1441
+ let end = false;
1442
+ let exit;
1443
+ proc.on("error", (err) => {
1444
+ resume(Effect3.fail(toPlatformError("spawn", err, command)));
1445
+ });
1446
+ proc.on("exit", (...args) => {
1447
+ exit = args;
1448
+ });
1449
+ proc.on("close", (...args) => {
1450
+ if (end) return;
1451
+ end = true;
1452
+ Deferred.doneUnsafe(signal, Exit.succeed(exit ?? args));
1453
+ });
1454
+ proc.on("spawn", () => {
1455
+ resume(Effect3.succeed([proc, signal]));
1456
+ });
1457
+ return Effect3.sync(() => {
1458
+ proc.kill("SIGTERM");
1459
+ });
1460
+ });
1461
+ const killGroup = (command, proc, signal) => {
1462
+ if (globalThis.process.platform === "win32") {
1463
+ return Effect3.callback((resume) => {
1464
+ NodeChildProcess.exec(`taskkill /pid ${proc.pid} /T /F`, { windowsHide: true }, (err) => {
1465
+ if (err) return resume(Effect3.fail(toPlatformError("kill", toError(err), command)));
1466
+ resume(Effect3.void);
1467
+ });
1468
+ });
1469
+ }
1470
+ return Effect3.try({
1471
+ try: () => {
1472
+ globalThis.process.kill(-proc.pid, signal);
1473
+ },
1474
+ catch: (err) => toPlatformError("kill", toError(err), command)
1475
+ });
1476
+ };
1477
+ const killOne = (command, proc, signal) => Effect3.suspend(() => {
1478
+ if (proc.kill(signal)) return Effect3.void;
1479
+ return Effect3.fail(toPlatformError("kill", new Error("Failed to kill child process"), command));
1480
+ });
1481
+ const timeout = (proc, command, opts) => (f) => {
1482
+ const signal = opts?.killSignal ?? "SIGTERM";
1483
+ if (Predicate.isUndefined(opts?.forceKillAfter)) return f(command, proc, signal);
1484
+ return Effect3.timeoutOrElse(f(command, proc, signal), {
1485
+ duration: opts.forceKillAfter,
1486
+ orElse: () => f(command, proc, "SIGKILL")
1487
+ });
1488
+ };
1489
+ const source = (handle, from) => {
1490
+ const opt = from ?? "stdout";
1491
+ switch (opt) {
1492
+ case "stdout":
1493
+ return handle.stdout;
1494
+ case "stderr":
1495
+ return handle.stderr;
1496
+ case "all":
1497
+ return handle.all;
1498
+ default: {
1499
+ const fd = ChildProcess.parseFdName(opt);
1500
+ return Predicate.isNotUndefined(fd) ? handle.getOutputFd(fd) : handle.stdout;
1501
+ }
1502
+ }
1503
+ };
1504
+ const spawnCommand = Effect3.fnUntraced(
1505
+ function* (command) {
1506
+ switch (command._tag) {
1507
+ case "StandardCommand": {
1508
+ const sin = stdin(command.options);
1509
+ const sout = stdio(command.options, "stdout");
1510
+ const serr = stdio(command.options, "stderr");
1511
+ const extra = fds(command.options);
1512
+ const dir = yield* cwd(command.options);
1513
+ const [proc, signal] = yield* Effect3.acquireRelease(
1514
+ spawn(command, {
1515
+ cwd: dir,
1516
+ env: env(command.options),
1517
+ stdio: stdios(sin, sout, serr, extra),
1518
+ detached: command.options.detached ?? process.platform !== "win32",
1519
+ shell: command.options.shell,
1520
+ windowsHide: process.platform === "win32"
1521
+ }),
1522
+ Effect3.fnUntraced(function* ([proc2, signal2]) {
1523
+ const done = yield* Deferred.isDone(signal2);
1524
+ const kill = timeout(proc2, command, command.options);
1525
+ if (done) {
1526
+ const [code] = yield* Deferred.await(signal2);
1527
+ if (process.platform === "win32") return yield* Effect3.void;
1528
+ if (code !== 0 && Predicate.isNotNull(code)) return yield* Effect3.ignore(kill(killGroup));
1529
+ return yield* Effect3.void;
1530
+ }
1531
+ const send = (s) => Effect3.catch(killGroup(command, proc2, s), () => killOne(command, proc2, s));
1532
+ const sig = command.options.killSignal ?? "SIGTERM";
1533
+ const attempt = send(sig).pipe(Effect3.andThen(Deferred.await(signal2)), Effect3.asVoid);
1534
+ const escalated = command.options.forceKillAfter ? Effect3.timeoutOrElse(attempt, {
1535
+ duration: command.options.forceKillAfter,
1536
+ orElse: () => send("SIGKILL").pipe(Effect3.andThen(Deferred.await(signal2)), Effect3.asVoid)
1537
+ }) : attempt;
1538
+ return yield* Effect3.ignore(escalated);
1539
+ })
1540
+ );
1541
+ const fd = yield* setupFds(command, proc, extra);
1542
+ const out = setupOutput(command, proc, sout, serr);
1543
+ return makeHandle({
1544
+ pid: ProcessId(proc.pid),
1545
+ stdin: yield* setupStdin(command, proc, sin),
1546
+ stdout: out.stdout,
1547
+ stderr: out.stderr,
1548
+ all: out.all,
1549
+ getInputFd: fd.getInputFd,
1550
+ getOutputFd: fd.getOutputFd,
1551
+ isRunning: Effect3.map(Deferred.isDone(signal), (done) => !done),
1552
+ exitCode: Effect3.flatMap(Deferred.await(signal), ([code, signal2]) => {
1553
+ if (Predicate.isNotNull(code)) return Effect3.succeed(ExitCode(code));
1554
+ return Effect3.fail(
1555
+ toPlatformError(
1556
+ "exitCode",
1557
+ new Error(`Process interrupted due to receipt of signal: '${signal2}'`),
1558
+ command
1559
+ )
1560
+ );
1561
+ }),
1562
+ kill: (opts) => {
1563
+ const sig = opts?.killSignal ?? "SIGTERM";
1564
+ const send = (s) => Effect3.catch(killGroup(command, proc, s), () => killOne(command, proc, s));
1565
+ const attempt = send(sig).pipe(Effect3.andThen(Deferred.await(signal)), Effect3.asVoid);
1566
+ if (!opts?.forceKillAfter) return attempt;
1567
+ return Effect3.timeoutOrElse(attempt, {
1568
+ duration: opts.forceKillAfter,
1569
+ orElse: () => send("SIGKILL").pipe(Effect3.andThen(Deferred.await(signal)), Effect3.asVoid)
1570
+ });
1571
+ }
1572
+ });
1573
+ }
1574
+ case "PipedCommand": {
1575
+ const flat = flatten(command);
1576
+ const [head, ...tail] = flat.commands;
1577
+ let handle = spawnCommand(head);
1578
+ for (let i = 0; i < tail.length; i++) {
1579
+ const next = tail[i];
1580
+ const opts = flat.opts[i] ?? {};
1581
+ const sin = stdin(next.options);
1582
+ const stream = Stream.unwrap(Effect3.map(handle, (x) => source(x, opts.from)));
1583
+ const to = opts.to ?? "stdin";
1584
+ if (to === "stdin") {
1585
+ handle = spawnCommand(
1586
+ ChildProcess.make(next.command, next.args, {
1587
+ ...next.options,
1588
+ stdin: { ...sin, stream }
1589
+ })
1590
+ );
1591
+ continue;
1592
+ }
1593
+ const fd = ChildProcess.parseFdName(to);
1594
+ if (Predicate.isUndefined(fd)) {
1595
+ handle = spawnCommand(
1596
+ ChildProcess.make(next.command, next.args, {
1597
+ ...next.options,
1598
+ stdin: { ...sin, stream }
1599
+ })
1600
+ );
1601
+ continue;
1602
+ }
1603
+ handle = spawnCommand(
1604
+ ChildProcess.make(next.command, next.args, {
1605
+ ...next.options,
1606
+ additionalFds: {
1607
+ ...next.options.additionalFds,
1608
+ [ChildProcess.fdName(fd)]: { type: "input", stream }
1609
+ }
1610
+ })
1611
+ );
1612
+ }
1613
+ return yield* handle;
1614
+ }
1615
+ }
1616
+ }
1617
+ );
1618
+ return makeSpawner(spawnCommand);
1619
+ });
1620
+ var layer2 = Layer2.effect(
1621
+ ChildProcessSpawner,
1622
+ make2
1623
+ );
1624
+ var defaultLayer = layer2.pipe(Layer2.provide(NodeFileSystem2.layer), Layer2.provide(NodePath.layer));
1625
+ var rt = lazy(async () => {
1626
+ const { makeRuntime: makeRuntime2 } = await import("./run-service-23VXHTA6.js");
1627
+ return makeRuntime2(ChildProcessSpawner, defaultLayer);
1628
+ });
1629
+ var runPromiseExit = async (...args) => (await rt()).runPromiseExit(...args);
1630
+
1631
+ // packages/opencode/src/project/project.ts
1632
+ var Project;
1633
+ ((Project2) => {
1634
+ const log2 = Log.create({ service: "project" });
1635
+ Project2.Info = z6.object({
1636
+ id: ProjectID.zod,
1637
+ worktree: z6.string(),
1638
+ vcs: z6.literal("git").optional(),
1639
+ name: z6.string().optional(),
1640
+ icon: z6.object({
1641
+ url: z6.string().optional(),
1642
+ override: z6.string().optional(),
1643
+ color: z6.string().optional()
1644
+ }).optional(),
1645
+ commands: z6.object({
1646
+ start: z6.string().optional().describe("Startup script to run when creating a new workspace (worktree)")
1647
+ }).optional(),
1648
+ time: z6.object({
1649
+ created: z6.number(),
1650
+ updated: z6.number(),
1651
+ initialized: z6.number().optional()
1652
+ }),
1653
+ sandboxes: z6.array(z6.string())
1654
+ }).meta({
1655
+ ref: "Project"
1656
+ });
1657
+ Project2.Event = {
1658
+ Updated: BusEvent.define("project.updated", Project2.Info)
1659
+ };
1660
+ function fromRow(row) {
1661
+ const icon = row.icon_url || row.icon_color ? { url: row.icon_url ?? void 0, color: row.icon_color ?? void 0 } : void 0;
1662
+ return {
1663
+ id: row.id,
1664
+ worktree: row.worktree,
1665
+ vcs: row.vcs ? Project2.Info.shape.vcs.parse(row.vcs) : void 0,
1666
+ name: row.name ?? void 0,
1667
+ icon,
1668
+ time: {
1669
+ created: row.time_created,
1670
+ updated: row.time_updated,
1671
+ initialized: row.time_initialized ?? void 0
1672
+ },
1673
+ sandboxes: row.sandboxes,
1674
+ commands: row.commands ?? void 0
1675
+ };
1676
+ }
1677
+ Project2.fromRow = fromRow;
1678
+ Project2.UpdateInput = z6.object({
1679
+ projectID: ProjectID.zod,
1680
+ name: z6.string().optional(),
1681
+ icon: Project2.Info.shape.icon.optional(),
1682
+ commands: Project2.Info.shape.commands.optional()
1683
+ });
1684
+ class Service extends ServiceMap4.Service()("@opencode/Project") {
1685
+ }
1686
+ Project2.Service = Service;
1687
+ Project2.layer = Layer3.effect(
1688
+ Service,
1689
+ Effect4.gen(function* () {
1690
+ const fs3 = yield* AppFileSystem.Service;
1691
+ const pathSvc = yield* Path3.Path;
1692
+ const spawner = yield* ChildProcessSpawner2.ChildProcessSpawner;
1693
+ const git = Effect4.fnUntraced(
1694
+ function* (args, opts) {
1695
+ const handle = yield* spawner.spawn(
1696
+ ChildProcess2.make("git", args, { cwd: opts?.cwd, extendEnv: true, stdin: "ignore" })
1697
+ );
1698
+ const [text3, stderr] = yield* Effect4.all(
1699
+ [Stream2.mkString(Stream2.decodeText(handle.stdout)), Stream2.mkString(Stream2.decodeText(handle.stderr))],
1700
+ { concurrency: 2 }
1701
+ );
1702
+ const code = yield* handle.exitCode;
1703
+ return { code, text: text3, stderr };
1704
+ },
1705
+ Effect4.scoped,
1706
+ Effect4.catch(() => Effect4.succeed({ code: 1, text: "", stderr: "" }))
1707
+ );
1708
+ const db = (fn) => Effect4.sync(() => Database.use(fn));
1709
+ const emitUpdated = (data2) => Effect4.sync(
1710
+ () => GlobalBus.emit("event", {
1711
+ payload: { type: Project2.Event.Updated.type, properties: data2 }
1712
+ })
1713
+ );
1714
+ const fakeVcs = Project2.Info.shape.vcs.parse(Flag.OPENCODE_FAKE_VCS);
1715
+ const resolveGitPath = (cwd, name) => {
1716
+ if (!name) return cwd;
1717
+ name = name.replace(/[\r\n]+$/, "");
1718
+ if (!name) return cwd;
1719
+ name = AppFileSystem.windowsPath(name);
1720
+ if (pathSvc.isAbsolute(name)) return pathSvc.normalize(name);
1721
+ return pathSvc.resolve(cwd, name);
1722
+ };
1723
+ const scope = yield* Scope2.Scope;
1724
+ const readCachedProjectId = Effect4.fnUntraced(function* (dir) {
1725
+ return yield* fs3.readFileString(pathSvc.join(dir, "opencode")).pipe(
1726
+ Effect4.map((x) => x.trim()),
1727
+ Effect4.map(ProjectID.make),
1728
+ Effect4.catch(() => Effect4.succeed(void 0))
1729
+ );
1730
+ });
1731
+ const fromDirectory2 = Effect4.fn("Project.fromDirectory")(function* (directory) {
1732
+ log2.info("fromDirectory", { directory });
1733
+ const data2 = yield* Effect4.gen(function* () {
1734
+ const dotgitMatches = yield* fs3.up({ targets: [".git"], start: directory }).pipe(Effect4.orDie);
1735
+ const dotgit = dotgitMatches[0];
1736
+ if (!dotgit) {
1737
+ return {
1738
+ id: ProjectID.global,
1739
+ worktree: "/",
1740
+ sandbox: "/",
1741
+ vcs: fakeVcs
1742
+ };
1743
+ }
1744
+ let sandbox = pathSvc.dirname(dotgit);
1745
+ const gitBinary = yield* Effect4.sync(() => which("git"));
1746
+ let id = yield* readCachedProjectId(dotgit);
1747
+ if (!gitBinary) {
1748
+ return {
1749
+ id: id ?? ProjectID.global,
1750
+ worktree: sandbox,
1751
+ sandbox,
1752
+ vcs: fakeVcs
1753
+ };
1754
+ }
1755
+ const commonDir = yield* git(["rev-parse", "--git-common-dir"], { cwd: sandbox });
1756
+ if (commonDir.code !== 0) {
1757
+ return {
1758
+ id: id ?? ProjectID.global,
1759
+ worktree: sandbox,
1760
+ sandbox,
1761
+ vcs: fakeVcs
1762
+ };
1763
+ }
1764
+ const worktree = (() => {
1765
+ const common = resolveGitPath(sandbox, commonDir.text.trim());
1766
+ return common === sandbox ? sandbox : pathSvc.dirname(common);
1767
+ })();
1768
+ if (id == null) {
1769
+ id = yield* readCachedProjectId(pathSvc.join(worktree, ".git"));
1770
+ }
1771
+ if (!id) {
1772
+ const revList = yield* git(["rev-list", "--max-parents=0", "HEAD"], { cwd: sandbox });
1773
+ const roots = revList.text.split("\n").filter(Boolean).map((x) => x.trim()).toSorted();
1774
+ id = roots[0] ? ProjectID.make(roots[0]) : void 0;
1775
+ if (id) {
1776
+ yield* fs3.writeFileString(pathSvc.join(worktree, ".git", "opencode"), id).pipe(Effect4.ignore);
1777
+ }
1778
+ }
1779
+ if (!id) {
1780
+ return { id: ProjectID.global, worktree: sandbox, sandbox, vcs: "git" };
1781
+ }
1782
+ const topLevel = yield* git(["rev-parse", "--show-toplevel"], { cwd: sandbox });
1783
+ if (topLevel.code !== 0) {
1784
+ return {
1785
+ id,
1786
+ worktree: sandbox,
1787
+ sandbox,
1788
+ vcs: fakeVcs
1789
+ };
1790
+ }
1791
+ sandbox = resolveGitPath(sandbox, topLevel.text.trim());
1792
+ return { id, sandbox, worktree, vcs: "git" };
1793
+ });
1794
+ const row = yield* db((d) => d.select().from(ProjectTable).where((0, db_exports.eq)(ProjectTable.id, data2.id)).get());
1795
+ const existing = row ? fromRow(row) : {
1796
+ id: data2.id,
1797
+ worktree: data2.worktree,
1798
+ vcs: data2.vcs,
1799
+ sandboxes: [],
1800
+ time: { created: Date.now(), updated: Date.now() }
1801
+ };
1802
+ if (Flag.OPENCODE_EXPERIMENTAL_ICON_DISCOVERY)
1803
+ yield* discover2(existing).pipe(Effect4.ignore, Effect4.forkIn(scope));
1804
+ const result = {
1805
+ ...existing,
1806
+ worktree: data2.worktree,
1807
+ vcs: data2.vcs,
1808
+ time: { ...existing.time, updated: Date.now() }
1809
+ };
1810
+ if (data2.sandbox !== result.worktree && !result.sandboxes.includes(data2.sandbox))
1811
+ result.sandboxes.push(data2.sandbox);
1812
+ result.sandboxes = yield* Effect4.forEach(
1813
+ result.sandboxes,
1814
+ (s) => fs3.exists(s).pipe(
1815
+ Effect4.orDie,
1816
+ Effect4.map((exists) => exists ? s : void 0)
1817
+ ),
1818
+ { concurrency: "unbounded" }
1819
+ ).pipe(Effect4.map((arr) => arr.filter((x) => x !== void 0)));
1820
+ yield* db(
1821
+ (d) => d.insert(ProjectTable).values({
1822
+ id: result.id,
1823
+ worktree: result.worktree,
1824
+ vcs: result.vcs ?? null,
1825
+ name: result.name,
1826
+ icon_url: result.icon?.url,
1827
+ icon_color: result.icon?.color,
1828
+ time_created: result.time.created,
1829
+ time_updated: result.time.updated,
1830
+ time_initialized: result.time.initialized,
1831
+ sandboxes: result.sandboxes,
1832
+ commands: result.commands
1833
+ }).onConflictDoUpdate({
1834
+ target: ProjectTable.id,
1835
+ set: {
1836
+ worktree: result.worktree,
1837
+ vcs: result.vcs ?? null,
1838
+ name: result.name,
1839
+ icon_url: result.icon?.url,
1840
+ icon_color: result.icon?.color,
1841
+ time_updated: result.time.updated,
1842
+ time_initialized: result.time.initialized,
1843
+ sandboxes: result.sandboxes,
1844
+ commands: result.commands
1845
+ }
1846
+ }).run()
1847
+ );
1848
+ if (data2.id !== ProjectID.global) {
1849
+ yield* db(
1850
+ (d) => d.update(SessionTable).set({ project_id: data2.id }).where((0, db_exports.and)((0, db_exports.eq)(SessionTable.project_id, ProjectID.global), (0, db_exports.eq)(SessionTable.directory, data2.worktree))).run()
1851
+ );
1852
+ }
1853
+ yield* emitUpdated(result);
1854
+ return { project: result, sandbox: data2.sandbox };
1855
+ });
1856
+ const discover2 = Effect4.fn("Project.discover")(function* (input) {
1857
+ if (input.vcs !== "git") return;
1858
+ if (input.icon?.override) return;
1859
+ if (input.icon?.url) return;
1860
+ const matches = yield* fs3.glob("**/favicon.{ico,png,svg,jpg,jpeg,webp}", {
1861
+ cwd: input.worktree,
1862
+ absolute: true,
1863
+ include: "file"
1864
+ }).pipe(Effect4.orDie);
1865
+ const shortest = matches.sort((a, b) => a.length - b.length)[0];
1866
+ if (!shortest) return;
1867
+ const buffer = yield* fs3.readFile(shortest).pipe(Effect4.orDie);
1868
+ const base64 = Buffer.from(buffer).toString("base64");
1869
+ const mime = AppFileSystem.mimeType(shortest);
1870
+ const url = `data:${mime};base64,${base64}`;
1871
+ yield* update2({ projectID: input.id, icon: { url } });
1872
+ });
1873
+ const list2 = Effect4.fn("Project.list")(function* () {
1874
+ return yield* db((d) => d.select().from(ProjectTable).all().map(fromRow));
1875
+ });
1876
+ const get2 = Effect4.fn("Project.get")(function* (id) {
1877
+ const row = yield* db((d) => d.select().from(ProjectTable).where((0, db_exports.eq)(ProjectTable.id, id)).get());
1878
+ return row ? fromRow(row) : void 0;
1879
+ });
1880
+ const update2 = Effect4.fn("Project.update")(function* (input) {
1881
+ const result = yield* db(
1882
+ (d) => d.update(ProjectTable).set({
1883
+ name: input.name,
1884
+ icon_url: input.icon?.url,
1885
+ icon_color: input.icon?.color,
1886
+ commands: input.commands,
1887
+ time_updated: Date.now()
1888
+ }).where((0, db_exports.eq)(ProjectTable.id, input.projectID)).returning().get()
1889
+ );
1890
+ if (!result) throw new Error(`Project not found: ${input.projectID}`);
1891
+ const data2 = fromRow(result);
1892
+ yield* emitUpdated(data2);
1893
+ return data2;
1894
+ });
1895
+ const initGit2 = Effect4.fn("Project.initGit")(function* (input) {
1896
+ if (input.project.vcs === "git") return input.project;
1897
+ if (!(yield* Effect4.sync(() => which("git")))) throw new Error("Git is not installed");
1898
+ const result = yield* git(["init", "--quiet"], { cwd: input.directory });
1899
+ if (result.code !== 0) {
1900
+ throw new Error(result.stderr.trim() || result.text.trim() || "Failed to initialize git repository");
1901
+ }
1902
+ const { project } = yield* fromDirectory2(input.directory);
1903
+ return project;
1904
+ });
1905
+ const setInitialized2 = Effect4.fn("Project.setInitialized")(function* (id) {
1906
+ yield* db(
1907
+ (d) => d.update(ProjectTable).set({ time_initialized: Date.now() }).where((0, db_exports.eq)(ProjectTable.id, id)).run()
1908
+ );
1909
+ });
1910
+ const sandboxes2 = Effect4.fn("Project.sandboxes")(function* (id) {
1911
+ const row = yield* db((d) => d.select().from(ProjectTable).where((0, db_exports.eq)(ProjectTable.id, id)).get());
1912
+ if (!row) return [];
1913
+ const data2 = fromRow(row);
1914
+ return yield* Effect4.forEach(
1915
+ data2.sandboxes,
1916
+ (dir) => fs3.isDir(dir).pipe(
1917
+ Effect4.orDie,
1918
+ Effect4.map((ok) => ok ? dir : void 0)
1919
+ ),
1920
+ { concurrency: "unbounded" }
1921
+ ).pipe(Effect4.map((arr) => arr.filter((x) => x !== void 0)));
1922
+ });
1923
+ const addSandbox2 = Effect4.fn("Project.addSandbox")(function* (id, directory) {
1924
+ const row = yield* db((d) => d.select().from(ProjectTable).where((0, db_exports.eq)(ProjectTable.id, id)).get());
1925
+ if (!row) throw new Error(`Project not found: ${id}`);
1926
+ const sboxes = [...row.sandboxes];
1927
+ if (!sboxes.includes(directory)) sboxes.push(directory);
1928
+ const result = yield* db(
1929
+ (d) => d.update(ProjectTable).set({ sandboxes: sboxes, time_updated: Date.now() }).where((0, db_exports.eq)(ProjectTable.id, id)).returning().get()
1930
+ );
1931
+ if (!result) throw new Error(`Project not found: ${id}`);
1932
+ yield* emitUpdated(fromRow(result));
1933
+ });
1934
+ const removeSandbox2 = Effect4.fn("Project.removeSandbox")(function* (id, directory) {
1935
+ const row = yield* db((d) => d.select().from(ProjectTable).where((0, db_exports.eq)(ProjectTable.id, id)).get());
1936
+ if (!row) throw new Error(`Project not found: ${id}`);
1937
+ const sboxes = row.sandboxes.filter((s) => s !== directory);
1938
+ const result = yield* db(
1939
+ (d) => d.update(ProjectTable).set({ sandboxes: sboxes, time_updated: Date.now() }).where((0, db_exports.eq)(ProjectTable.id, id)).returning().get()
1940
+ );
1941
+ if (!result) throw new Error(`Project not found: ${id}`);
1942
+ yield* emitUpdated(fromRow(result));
1943
+ });
1944
+ return Service.of({
1945
+ fromDirectory: fromDirectory2,
1946
+ discover: discover2,
1947
+ list: list2,
1948
+ get: get2,
1949
+ update: update2,
1950
+ initGit: initGit2,
1951
+ setInitialized: setInitialized2,
1952
+ sandboxes: sandboxes2,
1953
+ addSandbox: addSandbox2,
1954
+ removeSandbox: removeSandbox2
1955
+ });
1956
+ })
1957
+ );
1958
+ Project2.defaultLayer = Project2.layer.pipe(
1959
+ Layer3.provide(defaultLayer),
1960
+ Layer3.provide(AppFileSystem.defaultLayer),
1961
+ Layer3.provide(NodePath2.layer)
1962
+ );
1963
+ const { runPromise } = makeRuntime(Service, Project2.defaultLayer);
1964
+ function fromDirectory(directory) {
1965
+ return runPromise((svc) => svc.fromDirectory(directory));
1966
+ }
1967
+ Project2.fromDirectory = fromDirectory;
1968
+ function discover(input) {
1969
+ return runPromise((svc) => svc.discover(input));
1970
+ }
1971
+ Project2.discover = discover;
1972
+ function list() {
1973
+ return Database.use(
1974
+ (db) => db.select().from(ProjectTable).all().map((row) => fromRow(row))
1975
+ );
1976
+ }
1977
+ Project2.list = list;
1978
+ function get(id) {
1979
+ const row = Database.use((db) => db.select().from(ProjectTable).where((0, db_exports.eq)(ProjectTable.id, id)).get());
1980
+ if (!row) return void 0;
1981
+ return fromRow(row);
1982
+ }
1983
+ Project2.get = get;
1984
+ function setInitialized(id) {
1985
+ Database.use(
1986
+ (db) => db.update(ProjectTable).set({ time_initialized: Date.now() }).where((0, db_exports.eq)(ProjectTable.id, id)).run()
1987
+ );
1988
+ }
1989
+ Project2.setInitialized = setInitialized;
1990
+ function initGit(input) {
1991
+ return runPromise((svc) => svc.initGit(input));
1992
+ }
1993
+ Project2.initGit = initGit;
1994
+ function update(input) {
1995
+ return runPromise((svc) => svc.update(input));
1996
+ }
1997
+ Project2.update = update;
1998
+ function sandboxes(id) {
1999
+ return runPromise((svc) => svc.sandboxes(id));
2000
+ }
2001
+ Project2.sandboxes = sandboxes;
2002
+ function addSandbox(id, directory) {
2003
+ return runPromise((svc) => svc.addSandbox(id, directory));
2004
+ }
2005
+ Project2.addSandbox = addSandbox;
2006
+ function removeSandbox(id, directory) {
2007
+ return runPromise((svc) => svc.removeSandbox(id, directory));
2008
+ }
2009
+ Project2.removeSandbox = removeSandbox;
2010
+ })(Project || (Project = {}));
2011
+
2012
+ // packages/opencode/src/project/state.ts
2013
+ var State;
2014
+ ((State2) => {
2015
+ const log2 = Log.create({ service: "state" });
2016
+ const recordsByKey = /* @__PURE__ */ new Map();
2017
+ function create(root, init2, dispose2) {
2018
+ return () => {
2019
+ const key = root();
2020
+ let entries = recordsByKey.get(key);
2021
+ if (!entries) {
2022
+ entries = /* @__PURE__ */ new Map();
2023
+ recordsByKey.set(key, entries);
2024
+ }
2025
+ const exists = entries.get(init2);
2026
+ if (exists) return exists.state;
2027
+ const state2 = init2();
2028
+ entries.set(init2, {
2029
+ state: state2,
2030
+ dispose: dispose2
2031
+ });
2032
+ return state2;
2033
+ };
2034
+ }
2035
+ State2.create = create;
2036
+ async function dispose(key) {
2037
+ const entries = recordsByKey.get(key);
2038
+ if (!entries) return;
2039
+ log2.info("waiting for state disposal to complete", { key });
2040
+ let disposalFinished = false;
2041
+ setTimeout(() => {
2042
+ if (!disposalFinished) {
2043
+ log2.warn(
2044
+ "state disposal is taking an unusually long time - if it does not complete in a reasonable time, please report this as a bug",
2045
+ { key }
2046
+ );
2047
+ }
2048
+ }, 1e4).unref();
2049
+ const tasks = [];
2050
+ for (const [init2, entry] of entries) {
2051
+ if (!entry.dispose) continue;
2052
+ const label = typeof init2 === "function" ? init2.name : String(init2);
2053
+ const task = Promise.resolve(entry.state).then((state2) => entry.dispose(state2)).catch((error) => {
2054
+ log2.error("Error while disposing state:", { error, key, init: label });
2055
+ });
2056
+ tasks.push(task);
2057
+ }
2058
+ await Promise.all(tasks);
2059
+ entries.clear();
2060
+ recordsByKey.delete(key);
2061
+ disposalFinished = true;
2062
+ log2.info("state disposal completed", { key });
2063
+ }
2064
+ State2.dispose = dispose;
2065
+ })(State || (State = {}));
2066
+
2067
+ // packages/opencode/src/project/instance.ts
2068
+ var context = Context.create("instance");
2069
+ var cache2 = /* @__PURE__ */ new Map();
2070
+ var disposal = {
2071
+ all: void 0
2072
+ };
2073
+ function emit(directory) {
2074
+ GlobalBus.emit("event", {
2075
+ directory,
2076
+ payload: {
2077
+ type: "server.instance.disposed",
2078
+ properties: {
2079
+ directory
2080
+ }
2081
+ }
2082
+ });
2083
+ }
2084
+ function boot(input) {
2085
+ return iife(async () => {
2086
+ const ctx = input.project && input.worktree ? {
2087
+ directory: input.directory,
2088
+ worktree: input.worktree,
2089
+ project: input.project
2090
+ } : await Project.fromDirectory(input.directory).then(({ project, sandbox }) => ({
2091
+ directory: input.directory,
2092
+ worktree: sandbox,
2093
+ project
2094
+ }));
2095
+ await context.provide(ctx, async () => {
2096
+ await input.init?.();
2097
+ });
2098
+ return ctx;
2099
+ });
2100
+ }
2101
+ function track(directory, next) {
2102
+ const task = next.catch((error) => {
2103
+ if (cache2.get(directory) === task) cache2.delete(directory);
2104
+ throw error;
2105
+ });
2106
+ cache2.set(directory, task);
2107
+ return task;
2108
+ }
2109
+ var Instance = {
2110
+ async provide(input) {
2111
+ const directory = Filesystem.resolve(input.directory);
2112
+ let existing = cache2.get(directory);
2113
+ if (!existing) {
2114
+ Log.Default.info("creating instance", { directory });
2115
+ existing = track(
2116
+ directory,
2117
+ boot({
2118
+ directory,
2119
+ init: input.init
2120
+ })
2121
+ );
2122
+ }
2123
+ const ctx = await existing;
2124
+ return context.provide(ctx, async () => {
2125
+ return input.fn();
2126
+ });
2127
+ },
2128
+ get current() {
2129
+ return context.use();
2130
+ },
2131
+ get directory() {
2132
+ return context.use().directory;
2133
+ },
2134
+ get worktree() {
2135
+ return context.use().worktree;
2136
+ },
2137
+ get project() {
2138
+ return context.use().project;
2139
+ },
2140
+ /**
2141
+ * Check if a path is within the project boundary.
2142
+ * Returns true if path is inside Instance.directory OR Instance.worktree.
2143
+ * Paths within the worktree but outside the working directory should not trigger external_directory permission.
2144
+ */
2145
+ containsPath(filepath) {
2146
+ if (Filesystem.contains(Instance.directory, filepath)) return true;
2147
+ if (Instance.worktree === "/") return false;
2148
+ return Filesystem.contains(Instance.worktree, filepath);
2149
+ },
2150
+ /**
2151
+ * Captures the current instance ALS context and returns a wrapper that
2152
+ * restores it when called. Use this for callbacks that fire outside the
2153
+ * instance async context (native addons, event emitters, timers, etc.).
2154
+ */
2155
+ bind(fn) {
2156
+ const ctx = context.use();
2157
+ return ((...args) => context.provide(ctx, () => fn(...args)));
2158
+ },
2159
+ /**
2160
+ * Run a synchronous function within the given instance context ALS.
2161
+ * Use this to bridge from Effect (where InstanceRef carries context)
2162
+ * back to sync code that reads Instance.directory from ALS.
2163
+ */
2164
+ restore(ctx, fn) {
2165
+ return context.provide(ctx, fn);
2166
+ },
2167
+ state(init2, dispose) {
2168
+ return State.create(() => Instance.directory, init2, dispose);
2169
+ },
2170
+ async reload(input) {
2171
+ const directory = Filesystem.resolve(input.directory);
2172
+ Log.Default.info("reloading instance", { directory });
2173
+ await Promise.all([State.dispose(directory), disposeInstance(directory)]);
2174
+ cache2.delete(directory);
2175
+ const next = track(directory, boot({ ...input, directory }));
2176
+ emit(directory);
2177
+ return await next;
2178
+ },
2179
+ async dispose() {
2180
+ const directory = Instance.directory;
2181
+ Log.Default.info("disposing instance", { directory });
2182
+ await Promise.all([State.dispose(directory), disposeInstance(directory)]);
2183
+ cache2.delete(directory);
2184
+ emit(directory);
2185
+ },
2186
+ async disposeAll() {
2187
+ if (disposal.all) return disposal.all;
2188
+ disposal.all = iife(async () => {
2189
+ Log.Default.info("disposing all instances");
2190
+ const entries = [...cache2.entries()];
2191
+ for (const [key, value] of entries) {
2192
+ if (cache2.get(key) !== value) continue;
2193
+ const ctx = await value.catch((error) => {
2194
+ Log.Default.warn("instance dispose failed", { key, error });
2195
+ return void 0;
2196
+ });
2197
+ if (!ctx) {
2198
+ if (cache2.get(key) === value) cache2.delete(key);
2199
+ continue;
2200
+ }
2201
+ if (cache2.get(key) !== value) continue;
2202
+ await context.provide(ctx, async () => {
2203
+ await Instance.dispose();
2204
+ });
2205
+ }
2206
+ }).finally(() => {
2207
+ disposal.all = void 0;
2208
+ });
2209
+ return disposal.all;
2210
+ }
2211
+ };
2212
+
2213
+ // packages/opencode/src/effect/run-service.ts
2214
+ var memoMap = Layer4.makeMemoMapUnsafe();
2215
+ function attach(effect2) {
2216
+ try {
2217
+ const ctx = Instance.current;
2218
+ return Effect5.provideService(effect2, InstanceRef, ctx);
2219
+ } catch (err) {
2220
+ if (!(err instanceof Context.NotFound)) throw err;
2221
+ }
2222
+ return effect2;
2223
+ }
2224
+ function makeRuntime(service, layer3) {
2225
+ let rt2;
2226
+ const getRuntime = () => rt2 ??= ManagedRuntime.make(layer3, { memoMap });
2227
+ return {
2228
+ runSync: (fn) => getRuntime().runSync(attach(service.use(fn))),
2229
+ runPromiseExit: (fn, options) => getRuntime().runPromiseExit(attach(service.use(fn)), options),
2230
+ runPromise: (fn, options) => getRuntime().runPromise(attach(service.use(fn)), options),
2231
+ runFork: (fn) => getRuntime().runFork(attach(service.use(fn))),
2232
+ runCallback: (fn) => getRuntime().runCallback(attach(service.use(fn)))
2233
+ };
2234
+ }
2235
+
2236
+ export {
2237
+ Glob,
2238
+ Filesystem,
2239
+ Global,
2240
+ Log,
2241
+ GlobalBus,
2242
+ iife,
2243
+ lazy,
2244
+ NamedError,
2245
+ Flag,
2246
+ VERSION,
2247
+ CHANNEL,
2248
+ InstanceState,
2249
+ NotFoundError,
2250
+ Database,
2251
+ db_exports,
2252
+ Timestamps,
2253
+ ProjectTable,
2254
+ SessionTable,
2255
+ MessageTable,
2256
+ PartTable,
2257
+ TodoTable,
2258
+ PermissionTable,
2259
+ BusEvent,
2260
+ which,
2261
+ ProjectID,
2262
+ AppFileSystem,
2263
+ defaultLayer,
2264
+ runPromiseExit,
2265
+ Project,
2266
+ Instance,
2267
+ memoMap,
2268
+ makeRuntime
2269
+ };
2270
+ //# sourceMappingURL=chunk-CMAI7CAJ.js.map