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