@textcortex/zenocode 0.1.14 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -1
- package/package.json +1 -1
- package/scripts/build-branded-opencode.mjs +292 -215
- package/scripts/build-branded-opencode.test.mjs +85 -59
- package/scripts/opencode-version.mjs +5 -3
- package/scripts/run-zenocode.mjs +600 -763
- package/scripts/run-zenocode.test.mjs +625 -430
- package/scripts/source-branding.mjs +721 -0
- package/scripts/source-branding.test.mjs +106 -0
- package/scripts/branding-patch.mjs +0 -193
- package/scripts/branding-patch.test.mjs +0 -89
|
@@ -0,0 +1,721 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export const zenocodeLogo = {
|
|
5
|
+
left: [
|
|
6
|
+
' ',
|
|
7
|
+
' \\u2580\\u2580\\u2588 \\u2588\\u2580\\u2580 \\u2588\\u2584 \\u2588 \\u2588\\u2580\\u2588',
|
|
8
|
+
' \\u2588\\u2584\\u2584 \\u2588\\u2588\\u2584 \\u2588 \\u2580\\u2588 \\u2588\\u2584\\u2588',
|
|
9
|
+
' ',
|
|
10
|
+
],
|
|
11
|
+
right: [
|
|
12
|
+
' ',
|
|
13
|
+
' \\u2588\\u2580\\u2580 \\u2588\\u2580\\u2588 \\u2588\\u2580\\u2584 \\u2588\\u2580\\u2580',
|
|
14
|
+
' \\u2588\\u2584\\u2584 \\u2588\\u2584\\u2588 \\u2588\\u2584\\u2580 \\u2588\\u2588\\u2584',
|
|
15
|
+
' ',
|
|
16
|
+
],
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const openCodeLogo = {
|
|
20
|
+
left: [
|
|
21
|
+
' ',
|
|
22
|
+
'█▀▀█ █▀▀█ █▀▀█ █▀▀▄',
|
|
23
|
+
'█__█ █__█ █^^^ █__█',
|
|
24
|
+
'▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀~~▀',
|
|
25
|
+
],
|
|
26
|
+
right: [
|
|
27
|
+
' ▄ ',
|
|
28
|
+
'█▀▀▀ █▀▀█ █▀▀█ █▀▀█',
|
|
29
|
+
'█___ █__█ █__█ █^^^',
|
|
30
|
+
'▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀',
|
|
31
|
+
],
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const zenocodeSourceLogo = {
|
|
35
|
+
left: zenocodeLogo.left.map(decodeLogoLine),
|
|
36
|
+
right: zenocodeLogo.right.map(decodeLogoLine),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const openCodeWordmark = [
|
|
40
|
+
'⠀ ▄ ',
|
|
41
|
+
'█▀▀█ █▀▀█ █▀▀█ █▀▀▄ █▀▀▀ █▀▀█ █▀▀█ █▀▀█',
|
|
42
|
+
'█ █ █ █ █▀▀▀ █ █ █ █ █ █ █ █▀▀▀',
|
|
43
|
+
'▀▀▀▀ █▀▀▀ ▀▀▀▀ ▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀',
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
const zenocodeWordmark = [
|
|
47
|
+
'⠀ ▄ ',
|
|
48
|
+
'▀▀▀█ █▀▀█ █▀▀▄ █▀▀█ █▀▀▀ █▀▀█ █▀▀█ █▀▀█',
|
|
49
|
+
' ▄▀ █▀▀▀ █ █ █ █ █ █ █ █ █ █▀▀▀',
|
|
50
|
+
'▀▀▀▀ ▀▀▀▀ ▀ ▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀',
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
const openCodeUpgradeSource = `import { Config } from "@/config/config"
|
|
54
|
+
import { AppRuntime } from "@/effect/app-runtime"
|
|
55
|
+
import { Flag } from "@opencode-ai/core/flag/flag"
|
|
56
|
+
import { Installation } from "@/installation"
|
|
57
|
+
import { InstallationVersion } from "@opencode-ai/core/installation/version"
|
|
58
|
+
import { GlobalBus } from "@/bus/global"
|
|
59
|
+
|
|
60
|
+
export async function upgrade() {
|
|
61
|
+
const config = await AppRuntime.runPromise(Config.Service.use((cfg) => cfg.getGlobal()))
|
|
62
|
+
if (config.autoupdate === false || Flag.OPENCODE_DISABLE_AUTOUPDATE) return
|
|
63
|
+
const method = await Installation.method()
|
|
64
|
+
const latest = await Installation.latest(method).catch(() => {})
|
|
65
|
+
if (!latest) return
|
|
66
|
+
|
|
67
|
+
if (Flag.OPENCODE_ALWAYS_NOTIFY_UPDATE) {
|
|
68
|
+
GlobalBus.emit("event", {
|
|
69
|
+
directory: "global",
|
|
70
|
+
payload: {
|
|
71
|
+
type: Installation.Event.UpdateAvailable.type,
|
|
72
|
+
properties: { version: latest },
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (InstallationVersion === latest) return
|
|
79
|
+
|
|
80
|
+
const kind = Installation.getReleaseType(InstallationVersion, latest)
|
|
81
|
+
|
|
82
|
+
if (config.autoupdate === "notify" || kind !== "patch") {
|
|
83
|
+
GlobalBus.emit("event", {
|
|
84
|
+
directory: "global",
|
|
85
|
+
payload: {
|
|
86
|
+
type: Installation.Event.UpdateAvailable.type,
|
|
87
|
+
properties: { version: latest },
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (method === "unknown") return
|
|
94
|
+
await Installation.upgrade(method, latest)
|
|
95
|
+
.then(() =>
|
|
96
|
+
GlobalBus.emit("event", {
|
|
97
|
+
directory: "global",
|
|
98
|
+
payload: {
|
|
99
|
+
type: Installation.Event.Updated.type,
|
|
100
|
+
properties: { version: latest },
|
|
101
|
+
},
|
|
102
|
+
}),
|
|
103
|
+
)
|
|
104
|
+
.catch(() => {})
|
|
105
|
+
}
|
|
106
|
+
`;
|
|
107
|
+
|
|
108
|
+
const zenocodeUpgradeSource = `/**
|
|
109
|
+
* Zenocode runtimes are released together with the @textcortex/zenocode
|
|
110
|
+
* launcher. Never query or install upstream OpenCode releases from the TUI.
|
|
111
|
+
*/
|
|
112
|
+
export async function upgrade() {}
|
|
113
|
+
`;
|
|
114
|
+
|
|
115
|
+
/** Pinned upstream TUI handler that offers an in-app runtime upgrade. */
|
|
116
|
+
export const openCodeUpdatePromptSource = ` event.on("installation.update-available", async (evt) => {
|
|
117
|
+
console.log("installation.update-available", evt)
|
|
118
|
+
const version = evt.properties.version
|
|
119
|
+
|
|
120
|
+
const skipped = kv.get("skipped_version")
|
|
121
|
+
if (skipped && !isVersionGreater(version, skipped)) return
|
|
122
|
+
|
|
123
|
+
const choice = await DialogConfirm.show(
|
|
124
|
+
dialog,
|
|
125
|
+
\`Update Available\`,
|
|
126
|
+
\`A new release v\${version} is available. Would you like to update now?\`,
|
|
127
|
+
"skip",
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
if (choice === false) {
|
|
131
|
+
kv.set("skipped_version", version)
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (choice !== true) return
|
|
136
|
+
|
|
137
|
+
toast.show({
|
|
138
|
+
variant: "info",
|
|
139
|
+
message: \`Updating to v\${version}...\`,
|
|
140
|
+
duration: 30000,
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
const result = await sdk.client.global.upgrade({ target: version })
|
|
144
|
+
|
|
145
|
+
if (result.error || !result.data?.success) {
|
|
146
|
+
toast.show({
|
|
147
|
+
variant: "error",
|
|
148
|
+
title: "Update Failed",
|
|
149
|
+
message: "Update failed",
|
|
150
|
+
duration: 10000,
|
|
151
|
+
})
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
await DialogAlert.show(
|
|
156
|
+
dialog,
|
|
157
|
+
"Update Complete",
|
|
158
|
+
\`Successfully updated to OpenCode v\${result.data.version}. Please restart the application.\`,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
void exit()
|
|
162
|
+
})
|
|
163
|
+
`;
|
|
164
|
+
|
|
165
|
+
// Zenocode pins its runtime package, so an in-app upgrade can never take effect
|
|
166
|
+
// and the "restart to finish updating" prompt would loop on every launch.
|
|
167
|
+
const zenocodeUpdatePromptSource = ` // Zenocode owns runtime updates; see apps/zenocode/scripts/source-branding.mjs.
|
|
168
|
+
event.on("installation.update-available", () => {})
|
|
169
|
+
`;
|
|
170
|
+
|
|
171
|
+
/** Pinned upstream server handler behind POST /global/upgrade. */
|
|
172
|
+
export const openCodeServerUpgradeSource = ` const upgrade = Effect.fn("GlobalHttpApi.upgrade")(function* (ctx: { payload: typeof GlobalUpgradeInput.Type }) {
|
|
173
|
+
const method = yield* installation.method()
|
|
174
|
+
if (method === "unknown") {
|
|
175
|
+
return {
|
|
176
|
+
status: 400,
|
|
177
|
+
body: { success: false as const, error: "Unknown installation method" },
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
const target = ctx.payload.target || (yield* installation.latest(method))
|
|
181
|
+
const result = yield* installation.upgrade(method, target).pipe(
|
|
182
|
+
Effect.as({ status: 200, body: { success: true as const, version: target } }),
|
|
183
|
+
Effect.catch((err) =>
|
|
184
|
+
Effect.succeed({
|
|
185
|
+
status: 500,
|
|
186
|
+
body: {
|
|
187
|
+
success: false as const,
|
|
188
|
+
error: err instanceof Error ? err.message : String(err),
|
|
189
|
+
},
|
|
190
|
+
}),
|
|
191
|
+
),
|
|
192
|
+
)
|
|
193
|
+
if (!result.body.success) return result
|
|
194
|
+
GlobalBus.emit("event", {
|
|
195
|
+
directory: "global",
|
|
196
|
+
payload: {
|
|
197
|
+
type: Installation.Event.Updated.type,
|
|
198
|
+
properties: { version: target },
|
|
199
|
+
},
|
|
200
|
+
})
|
|
201
|
+
return result
|
|
202
|
+
})
|
|
203
|
+
`;
|
|
204
|
+
|
|
205
|
+
const zenocodeServerUpgradeSource = ` const upgrade = Effect.fn("GlobalHttpApi.upgrade")(function* (_ctx: {
|
|
206
|
+
payload: typeof GlobalUpgradeInput.Type
|
|
207
|
+
}) {
|
|
208
|
+
return {
|
|
209
|
+
status: 400,
|
|
210
|
+
body: {
|
|
211
|
+
success: false as const,
|
|
212
|
+
error: "Zenocode manages runtime updates. Reinstall Zenocode to update.",
|
|
213
|
+
},
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
`;
|
|
217
|
+
|
|
218
|
+
function decodeLogoLine(line) {
|
|
219
|
+
return line.replace(/\\u([0-9a-fA-F]{4})/g, (_, codePoint) =>
|
|
220
|
+
String.fromCharCode(Number.parseInt(codePoint, 16))
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function sourceArray(values) {
|
|
225
|
+
return `[${values.map((value) => JSON.stringify(value)).join(', ')}]`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const openCodeLogoLeft = `left: ${sourceArray(openCodeLogo.left)}`;
|
|
229
|
+
const openCodeLogoRight = `right: ${sourceArray(openCodeLogo.right)}`;
|
|
230
|
+
const zenocodeLogoLeft = `left: ${sourceArray(zenocodeSourceLogo.left)}`;
|
|
231
|
+
const zenocodeLogoRight = `right: ${sourceArray(zenocodeSourceLogo.right)}`;
|
|
232
|
+
|
|
233
|
+
const sourceBrandingRules = new Map([
|
|
234
|
+
[
|
|
235
|
+
'packages/opencode/src/cli/upgrade.ts',
|
|
236
|
+
[{ from: openCodeUpgradeSource, to: zenocodeUpgradeSource, count: 1 }],
|
|
237
|
+
],
|
|
238
|
+
[
|
|
239
|
+
'packages/tui/src/logo.ts',
|
|
240
|
+
[
|
|
241
|
+
{ from: openCodeLogoLeft, to: zenocodeLogoLeft, count: 1 },
|
|
242
|
+
{ from: openCodeLogoRight, to: zenocodeLogoRight, count: 1 },
|
|
243
|
+
],
|
|
244
|
+
],
|
|
245
|
+
[
|
|
246
|
+
'packages/tui/src/util/presentation.ts',
|
|
247
|
+
[
|
|
248
|
+
{ from: openCodeLogoLeft, to: zenocodeLogoLeft, count: 1 },
|
|
249
|
+
{ from: openCodeLogoRight, to: zenocodeLogoRight, count: 1 },
|
|
250
|
+
{
|
|
251
|
+
from: 'opencode -s ${input.sessionID}',
|
|
252
|
+
to: 'zenocode -s ${input.sessionID}',
|
|
253
|
+
count: 1,
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
],
|
|
257
|
+
[
|
|
258
|
+
'packages/opencode/src/cli/ui.ts',
|
|
259
|
+
openCodeWordmark.map((line, index) => ({
|
|
260
|
+
from: `\`${line}\``,
|
|
261
|
+
to: `\`${zenocodeWordmark[index]}\``,
|
|
262
|
+
count: 1,
|
|
263
|
+
})),
|
|
264
|
+
],
|
|
265
|
+
[
|
|
266
|
+
'packages/opencode/src/index.ts',
|
|
267
|
+
[
|
|
268
|
+
{
|
|
269
|
+
from: 'import { UpgradeCommand } from "./cli/cmd/upgrade"\n',
|
|
270
|
+
to: '',
|
|
271
|
+
count: 1,
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
from: 'import { UninstallCommand } from "./cli/cmd/uninstall"\n',
|
|
275
|
+
to: '',
|
|
276
|
+
count: 1,
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
from: 'text.startsWith("opencode ")',
|
|
280
|
+
to: 'text.startsWith("zenocode ")',
|
|
281
|
+
count: 1,
|
|
282
|
+
},
|
|
283
|
+
{
|
|
284
|
+
from: '.scriptName("opencode")',
|
|
285
|
+
to: '.scriptName("zenocode")',
|
|
286
|
+
count: 1,
|
|
287
|
+
},
|
|
288
|
+
{ from: ' .command(UpgradeCommand)\n', to: '', count: 1 },
|
|
289
|
+
{ from: ' .command(UninstallCommand)\n', to: '', count: 1 },
|
|
290
|
+
],
|
|
291
|
+
],
|
|
292
|
+
[
|
|
293
|
+
'packages/tui/src/app.tsx',
|
|
294
|
+
[
|
|
295
|
+
{
|
|
296
|
+
from: 'renderer.setTerminalTitle("OpenCode")',
|
|
297
|
+
to: 'renderer.setTerminalTitle("Zenocode")',
|
|
298
|
+
count: 2,
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
from: 'renderer.setTerminalTitle(`OC | ${title}`)',
|
|
302
|
+
to: 'renderer.setTerminalTitle(`ZC | ${title}`)',
|
|
303
|
+
count: 1,
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
from: 'renderer.setTerminalTitle(`OC | ${route.data.id}`)',
|
|
307
|
+
to: 'renderer.setTerminalTitle(`ZC | ${route.data.id}`)',
|
|
308
|
+
count: 1,
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
from: openCodeUpdatePromptSource,
|
|
312
|
+
to: zenocodeUpdatePromptSource,
|
|
313
|
+
count: 1,
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
],
|
|
317
|
+
[
|
|
318
|
+
'packages/opencode/src/server/routes/instance/httpapi/handlers/global.ts',
|
|
319
|
+
[
|
|
320
|
+
{
|
|
321
|
+
from: openCodeServerUpgradeSource,
|
|
322
|
+
to: zenocodeServerUpgradeSource,
|
|
323
|
+
count: 1,
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
],
|
|
327
|
+
[
|
|
328
|
+
'packages/tui/src/routes/session/sidebar.tsx',
|
|
329
|
+
[
|
|
330
|
+
{ from: '<b>Open</b>', to: '<b>Zeno</b>', count: 1 },
|
|
331
|
+
{ from: '<b>Code</b>', to: '<b>code</b>', count: 1 },
|
|
332
|
+
],
|
|
333
|
+
],
|
|
334
|
+
[
|
|
335
|
+
'packages/tui/src/feature-plugins/sidebar/footer.tsx',
|
|
336
|
+
[
|
|
337
|
+
{ from: '<b>Open</b>', to: '<b>Zeno</b>', count: 1 },
|
|
338
|
+
{ from: '<b>Code</b>', to: '<b>code</b>', count: 1 },
|
|
339
|
+
{
|
|
340
|
+
from: 'OpenCode includes free models',
|
|
341
|
+
to: 'Zenocode includes free models',
|
|
342
|
+
count: 1,
|
|
343
|
+
},
|
|
344
|
+
],
|
|
345
|
+
],
|
|
346
|
+
[
|
|
347
|
+
'packages/tui/src/routes/session/permission.tsx',
|
|
348
|
+
[
|
|
349
|
+
{
|
|
350
|
+
from: 'until OpenCode is restarted',
|
|
351
|
+
to: 'until Zenocode is restarted',
|
|
352
|
+
count: 2,
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
from: 'Tell OpenCode what to do differently',
|
|
356
|
+
to: 'Tell Zenocode what to do differently',
|
|
357
|
+
count: 1,
|
|
358
|
+
},
|
|
359
|
+
],
|
|
360
|
+
],
|
|
361
|
+
[
|
|
362
|
+
'packages/opencode/src/cli/cmd/run/footer.permission.tsx',
|
|
363
|
+
[
|
|
364
|
+
{
|
|
365
|
+
from: 'Tell OpenCode what to do differently',
|
|
366
|
+
to: 'Tell Zenocode what to do differently',
|
|
367
|
+
count: 2,
|
|
368
|
+
},
|
|
369
|
+
],
|
|
370
|
+
],
|
|
371
|
+
[
|
|
372
|
+
'packages/tui/src/attention.ts',
|
|
373
|
+
[
|
|
374
|
+
{
|
|
375
|
+
from: 'const DEFAULT_TITLE = "opencode"',
|
|
376
|
+
to: 'const DEFAULT_TITLE = "zenocode"',
|
|
377
|
+
count: 1,
|
|
378
|
+
},
|
|
379
|
+
{
|
|
380
|
+
from: 'name: "OpenCode Default"',
|
|
381
|
+
to: 'name: "Zenocode Default"',
|
|
382
|
+
count: 1,
|
|
383
|
+
},
|
|
384
|
+
],
|
|
385
|
+
],
|
|
386
|
+
[
|
|
387
|
+
'packages/tui/src/component/error-component.tsx',
|
|
388
|
+
[
|
|
389
|
+
{ from: 'opencode crashed', to: 'zenocode crashed', count: 1 },
|
|
390
|
+
{
|
|
391
|
+
from: 'opencode {InstallationVersion}',
|
|
392
|
+
to: 'zenocode {InstallationVersion}',
|
|
393
|
+
count: 1,
|
|
394
|
+
},
|
|
395
|
+
{
|
|
396
|
+
from: 'the opencode crash screen',
|
|
397
|
+
to: 'the Zenocode crash screen',
|
|
398
|
+
count: 1,
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
from: 'The opencode TUI crashed',
|
|
402
|
+
to: 'The Zenocode TUI crashed',
|
|
403
|
+
count: 1,
|
|
404
|
+
},
|
|
405
|
+
],
|
|
406
|
+
],
|
|
407
|
+
[
|
|
408
|
+
'packages/tui/src/util/error.ts',
|
|
409
|
+
[
|
|
410
|
+
{ from: '`opencode models`', to: '`zenocode models`', count: 1 },
|
|
411
|
+
{
|
|
412
|
+
from: 'opencode does not support MCP',
|
|
413
|
+
to: 'Zenocode does not support MCP',
|
|
414
|
+
count: 1,
|
|
415
|
+
},
|
|
416
|
+
],
|
|
417
|
+
],
|
|
418
|
+
[
|
|
419
|
+
'packages/opencode/src/cli/error.ts',
|
|
420
|
+
[
|
|
421
|
+
{
|
|
422
|
+
from: 'opencode does not support MCP',
|
|
423
|
+
to: 'Zenocode does not support MCP',
|
|
424
|
+
count: 1,
|
|
425
|
+
},
|
|
426
|
+
{ from: '\\`opencode models\\`', to: '\\`zenocode models\\`', count: 1 },
|
|
427
|
+
{
|
|
428
|
+
from: '\\`opencode auth login ${url}\\`',
|
|
429
|
+
to: '\\`zenocode auth login ${url}\\`',
|
|
430
|
+
count: 1,
|
|
431
|
+
},
|
|
432
|
+
],
|
|
433
|
+
],
|
|
434
|
+
[
|
|
435
|
+
'packages/opencode/src/cli/cmd/debug/index.ts',
|
|
436
|
+
[{ from: 'opencode version:', to: 'zenocode version:', count: 1 }],
|
|
437
|
+
],
|
|
438
|
+
[
|
|
439
|
+
'packages/tui/src/feature-plugins/home/tips-view.tsx',
|
|
440
|
+
[
|
|
441
|
+
{
|
|
442
|
+
from: 'Create a plugin to prevent OpenCode from reading sensitive files',
|
|
443
|
+
to: 'Create a plugin to prevent Zenocode from reading sensitive files',
|
|
444
|
+
count: 1,
|
|
445
|
+
},
|
|
446
|
+
{
|
|
447
|
+
from: 'Use {highlight}opencode run{/highlight}',
|
|
448
|
+
to: 'Use {highlight}zenocode run{/highlight}',
|
|
449
|
+
count: 1,
|
|
450
|
+
},
|
|
451
|
+
{
|
|
452
|
+
from: 'Use {highlight}opencode --continue{/highlight}',
|
|
453
|
+
to: 'Use {highlight}zenocode --continue{/highlight}',
|
|
454
|
+
count: 1,
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
from: 'Use {highlight}opencode run -f file.ts{/highlight}',
|
|
458
|
+
to: 'Use {highlight}zenocode run -f file.ts{/highlight}',
|
|
459
|
+
count: 1,
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
from: 'Run {highlight}opencode serve{/highlight} for headless API access to OpenCode',
|
|
463
|
+
to: 'Run {highlight}zenocode serve{/highlight} for headless API access to Zenocode',
|
|
464
|
+
count: 1,
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
from: 'Use {highlight}opencode run --attach{/highlight}',
|
|
468
|
+
to: 'Use {highlight}zenocode run --attach{/highlight}',
|
|
469
|
+
count: 1,
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
from: 'Run {highlight}opencode upgrade{/highlight} to update to the latest version',
|
|
473
|
+
to: 'Run {highlight}zenocode upgrade{/highlight} for the managed update command',
|
|
474
|
+
count: 1,
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
from: 'Run {highlight}opencode auth list{/highlight}',
|
|
478
|
+
to: 'Run {highlight}zenocode auth list{/highlight}',
|
|
479
|
+
count: 1,
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
from: 'Run {highlight}opencode agent create{/highlight}',
|
|
483
|
+
to: 'Run {highlight}zenocode agent create{/highlight}',
|
|
484
|
+
count: 1,
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
from: 'Run {highlight}opencode github install{/highlight}',
|
|
488
|
+
to: 'Run {highlight}zenocode github install{/highlight}',
|
|
489
|
+
count: 1,
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
from: 'Run {highlight}opencode debug config{/highlight}',
|
|
493
|
+
to: 'Run {highlight}zenocode debug config{/highlight}',
|
|
494
|
+
count: 1,
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
from: 'Use {highlight}/connect{/highlight} with OpenCode Zen for curated, tested models',
|
|
498
|
+
to: 'Use {highlight}/connect{/highlight} with Zenocode for curated, tested models',
|
|
499
|
+
count: 1,
|
|
500
|
+
},
|
|
501
|
+
],
|
|
502
|
+
],
|
|
503
|
+
[
|
|
504
|
+
'packages/tui/src/component/dialog-status.tsx',
|
|
505
|
+
[
|
|
506
|
+
{
|
|
507
|
+
from: 'run: opencode mcp auth',
|
|
508
|
+
to: 'run: zenocode mcp auth',
|
|
509
|
+
count: 1,
|
|
510
|
+
},
|
|
511
|
+
],
|
|
512
|
+
],
|
|
513
|
+
[
|
|
514
|
+
'packages/opencode/src/cli/cmd/tui.ts',
|
|
515
|
+
[
|
|
516
|
+
{
|
|
517
|
+
from: 'describe: "start opencode tui"',
|
|
518
|
+
to: 'describe: "start Zenocode TUI"',
|
|
519
|
+
count: 1,
|
|
520
|
+
},
|
|
521
|
+
{
|
|
522
|
+
from: 'describe: "path to start opencode in"',
|
|
523
|
+
to: 'describe: "path to start Zenocode in"',
|
|
524
|
+
count: 1,
|
|
525
|
+
},
|
|
526
|
+
],
|
|
527
|
+
],
|
|
528
|
+
[
|
|
529
|
+
'packages/opencode/src/cli/network.ts',
|
|
530
|
+
[
|
|
531
|
+
{
|
|
532
|
+
from: 'custom domain name for mDNS service (default: opencode.local)',
|
|
533
|
+
to: 'custom domain name for mDNS service (default: zenocode.local)',
|
|
534
|
+
count: 1,
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
from: 'default: "opencode.local"',
|
|
538
|
+
to: 'default: "zenocode.local"',
|
|
539
|
+
count: 1,
|
|
540
|
+
},
|
|
541
|
+
],
|
|
542
|
+
],
|
|
543
|
+
[
|
|
544
|
+
'packages/opencode/src/cli/cmd/mcp.ts',
|
|
545
|
+
[
|
|
546
|
+
{
|
|
547
|
+
from: 'Add servers with: opencode mcp add',
|
|
548
|
+
to: 'Add servers with: zenocode mcp add',
|
|
549
|
+
count: 1,
|
|
550
|
+
},
|
|
551
|
+
{
|
|
552
|
+
from: 'e.g., opencode x @modelcontextprotocol/server-filesystem',
|
|
553
|
+
to: 'e.g., zenocode x @modelcontextprotocol/server-filesystem',
|
|
554
|
+
count: 1,
|
|
555
|
+
},
|
|
556
|
+
],
|
|
557
|
+
],
|
|
558
|
+
[
|
|
559
|
+
'packages/opencode/src/cli/cmd/run.ts',
|
|
560
|
+
[
|
|
561
|
+
{
|
|
562
|
+
from: 'describe: "run opencode with a message"',
|
|
563
|
+
to: 'describe: "run Zenocode with a message"',
|
|
564
|
+
count: 1,
|
|
565
|
+
},
|
|
566
|
+
{
|
|
567
|
+
from: 'attach to a running opencode server',
|
|
568
|
+
to: 'attach to a running Zenocode server',
|
|
569
|
+
count: 1,
|
|
570
|
+
},
|
|
571
|
+
{ from: '$0: "opencode"', to: '$0: "zenocode"', count: 1 },
|
|
572
|
+
],
|
|
573
|
+
],
|
|
574
|
+
[
|
|
575
|
+
'packages/opencode/src/cli/cmd/web.ts',
|
|
576
|
+
[
|
|
577
|
+
{
|
|
578
|
+
from: 'start opencode server and open web interface',
|
|
579
|
+
to: 'start Zenocode server and open web interface',
|
|
580
|
+
count: 1,
|
|
581
|
+
},
|
|
582
|
+
],
|
|
583
|
+
],
|
|
584
|
+
[
|
|
585
|
+
'packages/opencode/src/cli/cmd/pr.ts',
|
|
586
|
+
[
|
|
587
|
+
{ from: 'then run opencode', to: 'then run Zenocode', count: 1 },
|
|
588
|
+
{
|
|
589
|
+
from: 'Found opencode session:',
|
|
590
|
+
to: 'Found Zenocode session:',
|
|
591
|
+
count: 1,
|
|
592
|
+
},
|
|
593
|
+
{
|
|
594
|
+
from: '["opencode", "import", sessionUrl]',
|
|
595
|
+
to: '["zenocode", "import", sessionUrl]',
|
|
596
|
+
count: 1,
|
|
597
|
+
},
|
|
598
|
+
{ from: 'Starting opencode...', to: 'Starting Zenocode...', count: 1 },
|
|
599
|
+
{
|
|
600
|
+
from: 'Process.spawn(["opencode", ...opencodeArgs]',
|
|
601
|
+
to: 'Process.spawn(["zenocode", ...opencodeArgs]',
|
|
602
|
+
count: 1,
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
from: 'opencode exited with code',
|
|
606
|
+
to: 'Zenocode exited with code',
|
|
607
|
+
count: 1,
|
|
608
|
+
},
|
|
609
|
+
],
|
|
610
|
+
],
|
|
611
|
+
[
|
|
612
|
+
'packages/opencode/src/cli/cmd/attach.ts',
|
|
613
|
+
[
|
|
614
|
+
{
|
|
615
|
+
from: 'attach to a running opencode server',
|
|
616
|
+
to: 'attach to a running Zenocode server',
|
|
617
|
+
count: 1,
|
|
618
|
+
},
|
|
619
|
+
],
|
|
620
|
+
],
|
|
621
|
+
[
|
|
622
|
+
'packages/opencode/src/cli/cmd/serve.ts',
|
|
623
|
+
[
|
|
624
|
+
{
|
|
625
|
+
from: 'starts a headless opencode server',
|
|
626
|
+
to: 'starts a headless Zenocode server',
|
|
627
|
+
count: 1,
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
from: 'opencode server listening on',
|
|
631
|
+
to: 'Zenocode server listening on',
|
|
632
|
+
count: 1,
|
|
633
|
+
},
|
|
634
|
+
],
|
|
635
|
+
],
|
|
636
|
+
[
|
|
637
|
+
'packages/opencode/src/cli/cmd/run/splash.ts',
|
|
638
|
+
[
|
|
639
|
+
{
|
|
640
|
+
from: 'top, "OpenCode", right',
|
|
641
|
+
to: 'top, "Zenocode", right',
|
|
642
|
+
count: 1,
|
|
643
|
+
},
|
|
644
|
+
],
|
|
645
|
+
],
|
|
646
|
+
[
|
|
647
|
+
'packages/opencode/src/cli/cmd/run/footer.prompt.tsx',
|
|
648
|
+
[
|
|
649
|
+
{
|
|
650
|
+
from: 'description: "close OpenCode"',
|
|
651
|
+
to: 'description: "close Zenocode"',
|
|
652
|
+
count: 1,
|
|
653
|
+
},
|
|
654
|
+
],
|
|
655
|
+
],
|
|
656
|
+
[
|
|
657
|
+
'packages/opencode/src/cli/cmd/run/permission.shared.ts',
|
|
658
|
+
[
|
|
659
|
+
{
|
|
660
|
+
from: 'until OpenCode is restarted',
|
|
661
|
+
to: 'until Zenocode is restarted',
|
|
662
|
+
count: 2,
|
|
663
|
+
},
|
|
664
|
+
],
|
|
665
|
+
],
|
|
666
|
+
[
|
|
667
|
+
'packages/opencode/src/server/mdns.ts',
|
|
668
|
+
[
|
|
669
|
+
{
|
|
670
|
+
from: 'const host = domain ?? "opencode.local"',
|
|
671
|
+
to: 'const host = domain ?? "zenocode.local"',
|
|
672
|
+
count: 1,
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
from: 'const name = `opencode-${port}`',
|
|
676
|
+
to: 'const name = `zenocode-${port}`',
|
|
677
|
+
count: 1,
|
|
678
|
+
},
|
|
679
|
+
],
|
|
680
|
+
],
|
|
681
|
+
[
|
|
682
|
+
'packages/opencode/src/acp/service.ts',
|
|
683
|
+
[{ from: 'name: "OpenCode"', to: 'name: "Zenocode"', count: 1 }],
|
|
684
|
+
],
|
|
685
|
+
]);
|
|
686
|
+
|
|
687
|
+
export const sourceBrandingFiles = [...sourceBrandingRules.keys()];
|
|
688
|
+
|
|
689
|
+
function occurrenceCount(text, search) {
|
|
690
|
+
return text.split(search).length - 1;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/** Apply the pinned source transformations for one upstream OpenCode file. */
|
|
694
|
+
export function brandOpenCodeSourceFile(relativePath, source) {
|
|
695
|
+
const rules = sourceBrandingRules.get(relativePath);
|
|
696
|
+
if (!rules) {
|
|
697
|
+
throw new Error(`No Zenocode source-branding rules for ${relativePath}`);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
let branded = source;
|
|
701
|
+
for (const rule of rules) {
|
|
702
|
+
const actualCount = occurrenceCount(branded, rule.from);
|
|
703
|
+
if (actualCount !== rule.count) {
|
|
704
|
+
throw new Error(
|
|
705
|
+
`Upstream branding surface drifted in ${relativePath}: expected ${rule.count} occurrence(s), found ${actualCount}.`
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
branded = branded.replaceAll(rule.from, rule.to);
|
|
709
|
+
}
|
|
710
|
+
return branded;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
/** Brand the checked-out, pinned OpenCode source tree before it is compiled. */
|
|
714
|
+
export async function applyZenocodeSourceBranding(checkoutDir) {
|
|
715
|
+
for (const relativePath of sourceBrandingFiles) {
|
|
716
|
+
const filePath = path.join(checkoutDir, relativePath);
|
|
717
|
+
const source = await fs.readFile(filePath, 'utf-8');
|
|
718
|
+
const branded = brandOpenCodeSourceFile(relativePath, source);
|
|
719
|
+
await fs.writeFile(filePath, branded, 'utf-8');
|
|
720
|
+
}
|
|
721
|
+
}
|