codiedev 0.10.0-beta.3 → 0.10.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/assets/tui-brand-plugin.tsx +73 -0
- package/dist/backup/cache.js +1 -5
- package/dist/backup/match.js +0 -6
- package/dist/backup/run.js +3 -35
- package/dist/captureExclusions.js +0 -12
- package/dist/captureLog.js +0 -28
- package/dist/captureReadiness.js +0 -58
- package/dist/captureSignals.js +66 -3
- package/dist/cli.js +41 -18
- package/dist/codexHookTrust.js +61 -5
- package/dist/codexLimitScan.js +2 -109
- package/dist/codie.js +41 -56
- package/dist/codieBrandInstall.js +80 -0
- package/dist/codieLauncher.js +59 -59
- package/dist/codieRuntime.js +19 -23
- package/dist/codieRuntimeInstall.js +108 -23
- package/dist/codieStartup.js +0 -3
- package/dist/codieUsage.js +181 -0
- package/dist/commands/ask.js +0 -3
- package/dist/commands/capture.js +0 -2
- package/dist/commands/createTicket.js +0 -10
- package/dist/commands/doctor.js +41 -82
- package/dist/commands/inbox.js +0 -2
- package/dist/commands/library.js +0 -3
- package/dist/commands/pack.js +573 -0
- package/dist/commands/ping.js +0 -2
- package/dist/commands/pull.js +6 -10
- package/dist/commands/push.js +2 -12
- package/dist/commands/react.js +0 -2
- package/dist/commands/reverseTicket.js +0 -33
- package/dist/commands/search.js +0 -4
- package/dist/commands/send.js +0 -5
- package/dist/commands/share.js +0 -4
- package/dist/commands/shared.js +0 -35
- package/dist/commands/traces.js +280 -0
- package/dist/configDir.js +0 -10
- package/dist/connect.js +21 -77
- package/dist/connectFlow.js +0 -9
- package/dist/copilotHooks.js +395 -0
- package/dist/copilotInstallation.js +64 -0
- package/dist/cursorHooks.js +40 -17
- package/dist/cursorLifecycle.js +109 -0
- package/dist/detection.js +0 -30
- package/dist/harnessDirs.js +73 -0
- package/dist/hook.js +193 -316
- package/dist/inboxFormat.js +0 -24
- package/dist/launchContext.js +150 -0
- package/dist/launcher.js +140 -0
- package/dist/limitEvent.js +41 -35
- package/dist/limitEventReporter.js +1 -1
- package/dist/mcp.js +3 -77
- package/dist/nativeSteering.js +24 -0
- package/dist/packs/codie.js +182 -0
- package/dist/packs/harnesses.js +374 -0
- package/dist/packs/hookGate.js +256 -0
- package/dist/packs/install.js +285 -0
- package/dist/packs/manifest.js +126 -0
- package/dist/packs/paths.js +81 -0
- package/dist/packs/shim.js +214 -0
- package/dist/packs/store.js +155 -0
- package/dist/packs/sync.js +170 -0
- package/dist/prUrl.js +0 -5
- package/dist/repoResolver.js +0 -19
- package/dist/secret.js +0 -3
- package/dist/security.js +0 -20
- package/dist/securityDeepScan.js +1 -14
- package/dist/securityDoctor.js +0 -2
- package/dist/securityFeature.js +0 -1
- package/dist/securityInstall.js +6 -13
- package/dist/securityInventory.js +23 -13
- package/dist/securityPilot.js +0 -2
- package/dist/securityPolicy.js +0 -7
- package/dist/selfUpdate.js +331 -0
- package/dist/skillMarker.js +23 -0
- package/dist/subagents.js +135 -0
- package/dist/teamSkillContext.js +10 -0
- package/dist/transcriptModels.js +6 -8
- package/dist/upgradeNudge.js +0 -30
- package/dist/utils.js +286 -733
- package/dist/version.js +0 -10
- package/dist/versionCheck.js +0 -33
- package/package.json +8 -7
- package/dist/backup/cache.d.ts +0 -14
- package/dist/backup/match.d.ts +0 -2
- package/dist/backup/run.d.ts +0 -25
- package/dist/captureExclusions.d.ts +0 -30
- package/dist/captureLog.d.ts +0 -20
- package/dist/captureReadiness.d.ts +0 -65
- package/dist/captureSignals.d.ts +0 -19
- package/dist/cli.d.ts +0 -16
- package/dist/codexHookTrust.d.ts +0 -34
- package/dist/codexLimitScan.d.ts +0 -64
- package/dist/codie.d.ts +0 -2
- package/dist/codieLauncher.d.ts +0 -53
- package/dist/codieRuntime.d.ts +0 -29
- package/dist/codieRuntimeInstall.d.ts +0 -28
- package/dist/codieStartup.d.ts +0 -26
- package/dist/commands/ask.d.ts +0 -1
- package/dist/commands/capture.d.ts +0 -14
- package/dist/commands/createTicket.d.ts +0 -27
- package/dist/commands/delete.d.ts +0 -1
- package/dist/commands/doctor.d.ts +0 -1
- package/dist/commands/inbox.d.ts +0 -3
- package/dist/commands/library.d.ts +0 -2
- package/dist/commands/note.d.ts +0 -1
- package/dist/commands/ping.d.ts +0 -1
- package/dist/commands/promote.d.ts +0 -1
- package/dist/commands/pull.d.ts +0 -2
- package/dist/commands/push.d.ts +0 -33
- package/dist/commands/react.d.ts +0 -2
- package/dist/commands/reverseTicket.d.ts +0 -2
- package/dist/commands/search.d.ts +0 -2
- package/dist/commands/security.d.ts +0 -1
- package/dist/commands/send.d.ts +0 -2
- package/dist/commands/share.d.ts +0 -2
- package/dist/commands/shared.d.ts +0 -64
- package/dist/configDir.d.ts +0 -1
- package/dist/connect.d.ts +0 -1
- package/dist/connectFlow.d.ts +0 -13
- package/dist/cursorHooks.d.ts +0 -23
- package/dist/detection.d.ts +0 -30
- package/dist/hook.d.ts +0 -6
- package/dist/inboxFormat.d.ts +0 -38
- package/dist/limitEvent.d.ts +0 -16
- package/dist/limitEventReporter.d.ts +0 -21
- package/dist/mcp.d.ts +0 -12
- package/dist/prUrl.d.ts +0 -9
- package/dist/repoResolver.d.ts +0 -17
- package/dist/secret.d.ts +0 -1
- package/dist/security.d.ts +0 -102
- package/dist/securityDeepScan.d.ts +0 -41
- package/dist/securityDoctor.d.ts +0 -32
- package/dist/securityFeature.d.ts +0 -5
- package/dist/securityInstall.d.ts +0 -63
- package/dist/securityInventory.d.ts +0 -54
- package/dist/securityPilot.d.ts +0 -19
- package/dist/securityPolicy.d.ts +0 -33
- package/dist/securitySession.d.ts +0 -6
- package/dist/transcriptModels.d.ts +0 -18
- package/dist/upgradeNudge.d.ts +0 -25
- package/dist/utils.d.ts +0 -346
- package/dist/version.d.ts +0 -1
- package/dist/versionCheck.d.ts +0 -68
package/dist/codie.js
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
-
// `codie` — Codiedev's governed coding harness.
|
|
4
|
-
//
|
|
5
|
-
// Ships from the same package as `codiedev` so a developer runs one install and
|
|
6
|
-
// then picks their surface: Claude Code, Codex, and Cursor get session capture
|
|
7
|
-
// via `codiedev connect`; `codie` launches the governed harness against the
|
|
8
|
-
// same token. OpenCode is the embedded engine; all user-facing identity,
|
|
9
|
-
// credentials, models, policy, and capture belong to Codiedev.
|
|
10
|
-
//
|
|
11
|
-
// The engine is downloaded on first run (see codieRuntime.ts) so capture-only
|
|
12
|
-
// users never pay for it.
|
|
13
3
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
4
|
if (k2 === undefined) k2 = k;
|
|
15
5
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -51,10 +41,15 @@ const child_process_1 = require("child_process");
|
|
|
51
41
|
const url_1 = require("url");
|
|
52
42
|
const configDir_1 = require("./configDir");
|
|
53
43
|
const codieLauncher_1 = require("./codieLauncher");
|
|
44
|
+
const codieBrandInstall_1 = require("./codieBrandInstall");
|
|
45
|
+
const codieUsage_1 = require("./codieUsage");
|
|
54
46
|
const codieRuntime_1 = require("./codieRuntime");
|
|
55
47
|
const codieRuntimeInstall_1 = require("./codieRuntimeInstall");
|
|
56
48
|
const codieStartup_1 = require("./codieStartup");
|
|
57
49
|
const upgradeNudge_1 = require("./upgradeNudge");
|
|
50
|
+
const codie_1 = require("./packs/codie");
|
|
51
|
+
const paths_1 = require("./packs/paths");
|
|
52
|
+
const USAGE_SETTLE_MS = 1200;
|
|
58
53
|
function git(args) {
|
|
59
54
|
const result = (0, child_process_1.spawnSync)("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
|
|
60
55
|
return result.status === 0 ? result.stdout.trim() : "";
|
|
@@ -83,8 +78,6 @@ function existingInlineConfig() {
|
|
|
83
78
|
throw new Error("OPENCODE_CONFIG_CONTENT is not valid JSON");
|
|
84
79
|
}
|
|
85
80
|
}
|
|
86
|
-
// The one credential. `codiedev connect` wrote it; the gateway validates the
|
|
87
|
-
// same userApiTokens row, so there is no second harness token to mint.
|
|
88
81
|
function connectedCodiedevConfig() {
|
|
89
82
|
try {
|
|
90
83
|
return JSON.parse(fs.readFileSync(path.join((0, configDir_1.codiedevStateDir)(), "config.json"), "utf8"));
|
|
@@ -93,40 +86,23 @@ function connectedCodiedevConfig() {
|
|
|
93
86
|
return {};
|
|
94
87
|
}
|
|
95
88
|
}
|
|
96
|
-
function
|
|
97
|
-
// dist/codie.js → ../assets/<name>; src/codie.ts → ../assets/<name>.
|
|
98
|
-
return path.join(__dirname, "..", "assets", name);
|
|
99
|
-
}
|
|
100
|
-
// Stage the home-screen branding plugin. TUI plugins only load from tui.json
|
|
101
|
-
// in the OpenCode config dir, so the packaged file is copied next to the
|
|
102
|
-
// capture plugin and referenced with a relative spec. Best-effort: any
|
|
103
|
-
// failure (e.g. a hand-edited tui.json with comments) leaves the stock logo.
|
|
104
|
-
function installBrandPlugin() {
|
|
89
|
+
function withStarterPacks(existing, approved, catalog) {
|
|
105
90
|
try {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
fs.mkdirSync(pluginDir, { recursive: true });
|
|
111
|
-
const source = fs.readFileSync(assetPath("tui-brand-plugin.tsx"), "utf8");
|
|
112
|
-
const destination = path.join(pluginDir, "codiedev-brand.tsx");
|
|
113
|
-
if (!fs.existsSync(destination) || fs.readFileSync(destination, "utf8") !== source) {
|
|
114
|
-
fs.writeFileSync(destination, source);
|
|
91
|
+
const packs = (0, codie_1.codiePackConfig)((0, paths_1.packsRoot)(), { approvedModels: approved, catalog });
|
|
92
|
+
if (process.env.CODIEDEV_DEBUG) {
|
|
93
|
+
for (const note of packs.notes)
|
|
94
|
+
console.error(`codie: starter pack ${note}`);
|
|
115
95
|
}
|
|
116
|
-
|
|
117
|
-
const existing = fs.existsSync(tuiConfigPath) ? JSON.parse(fs.readFileSync(tuiConfigPath, "utf8")) : {};
|
|
118
|
-
const { config, changed } = (0, codieLauncher_1.withBrandPlugin)(existing);
|
|
119
|
-
if (changed)
|
|
120
|
-
fs.writeFileSync(tuiConfigPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
96
|
+
return (0, codie_1.mergeCodiePackConfig)(existing, packs);
|
|
121
97
|
}
|
|
122
98
|
catch (error) {
|
|
123
|
-
console.error(`codie:
|
|
99
|
+
console.error(`codie: skipping starter packs (${error instanceof Error ? error.message : error})`);
|
|
100
|
+
return existing;
|
|
124
101
|
}
|
|
125
102
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// already-suppressed binary has no known source region and is skipped.
|
|
103
|
+
function assetPath(name) {
|
|
104
|
+
return path.join(__dirname, "..", "assets", name);
|
|
105
|
+
}
|
|
130
106
|
function installBrandWordmark(runtime) {
|
|
131
107
|
try {
|
|
132
108
|
installBrandWordmarkUnsafe(runtime);
|
|
@@ -140,10 +116,6 @@ function installBrandWordmarkUnsafe(runtime) {
|
|
|
140
116
|
const { changed, offset, replacement } = (0, codieLauncher_1.patchBrandWordmark)(binary);
|
|
141
117
|
if (!changed || !replacement)
|
|
142
118
|
return;
|
|
143
|
-
// In-place write (not copy+rename): opencode-ai/bin/opencode.exe and the
|
|
144
|
-
// platform package's binary are hardlinks to one inode, and this keeps them
|
|
145
|
-
// consistent. Restoring the original bytes is a true rollback — identical
|
|
146
|
-
// content revalidates the existing macOS signature.
|
|
147
119
|
const writeAt = (bytes) => {
|
|
148
120
|
const fd = fs.openSync(runtime, "r+");
|
|
149
121
|
try {
|
|
@@ -156,7 +128,6 @@ function installBrandWordmarkUnsafe(runtime) {
|
|
|
156
128
|
const restore = () => writeAt(binary.subarray(offset, offset + replacement.length));
|
|
157
129
|
writeAt(replacement);
|
|
158
130
|
if (process.platform === "darwin") {
|
|
159
|
-
// A modified Mach-O needs a fresh ad-hoc signature or the OS kills it.
|
|
160
131
|
const signed = (0, child_process_1.spawnSync)("codesign", ["--force", "--sign", "-", runtime], { stdio: "ignore" });
|
|
161
132
|
if (signed.status !== 0) {
|
|
162
133
|
restore();
|
|
@@ -186,7 +157,6 @@ async function runNonInteractive(runtime, runtimeArgs, env) {
|
|
|
186
157
|
return;
|
|
187
158
|
}
|
|
188
159
|
catch {
|
|
189
|
-
// Fall back to the direct child if its process group already exited.
|
|
190
160
|
}
|
|
191
161
|
}
|
|
192
162
|
child.kill(signal);
|
|
@@ -199,11 +169,6 @@ async function runNonInteractive(runtime, runtimeArgs, env) {
|
|
|
199
169
|
let blockReason;
|
|
200
170
|
const errorPrefixes = [Buffer.from("\x1b[91m\x1b[1mError:"), Buffer.from("Error: {")];
|
|
201
171
|
const retainedPrefixBytes = Math.max(...errorPrefixes.map((prefix) => prefix.length)) - 1;
|
|
202
|
-
// OpenCode's generic UnknownError and the adapter's private reason can be
|
|
203
|
-
// delivered in either order — and the generic block can arrive on stdout
|
|
204
|
-
// or stderr. Gate both streams by content, retaining only a possible final
|
|
205
|
-
// error block. Ordinary output stays streaming apart from the few bytes
|
|
206
|
-
// needed to recognize a split prefix.
|
|
207
172
|
const createOutputGate = (write) => {
|
|
208
173
|
let tail = Buffer.alloc(0);
|
|
209
174
|
let possibleError;
|
|
@@ -293,9 +258,6 @@ async function main() {
|
|
|
293
258
|
if (!key) {
|
|
294
259
|
throw new Error("Connect your Codiedev account first with `codiedev connect`");
|
|
295
260
|
}
|
|
296
|
-
// Before anything paints: once the OpenCode engine owns stdio, a prompt is
|
|
297
|
-
// unreadable. A successful in-place upgrade relaunches this command with the
|
|
298
|
-
// new package, so the stale process must stop here.
|
|
299
261
|
const update = await (0, upgradeNudge_1.maybeOfferUpgrade)();
|
|
300
262
|
if (update.relaunched) {
|
|
301
263
|
process.exitCode = update.status ?? 0;
|
|
@@ -337,8 +299,18 @@ async function main() {
|
|
|
337
299
|
return null;
|
|
338
300
|
}
|
|
339
301
|
},
|
|
302
|
+
isEngine: codieRuntimeInstall_1.isEngineOnDisk,
|
|
340
303
|
}),
|
|
341
304
|
install: (missing) => (0, codieRuntimeInstall_1.installCodieRuntimeOnDisk)(missing, stateDir),
|
|
305
|
+
repair: (unlinked) => {
|
|
306
|
+
console.error("codie: finishing the engine setup npm skipped (opencode-ai's postinstall)…");
|
|
307
|
+
const linked = (0, codieRuntimeInstall_1.linkEngineOnDisk)(unlinked.packageDir);
|
|
308
|
+
if (!linked.ok && linked.detail === codieRuntimeInstall_1.IGNORE_SCRIPTS)
|
|
309
|
+
throw new Error((0, codieRuntimeInstall_1.linkFailure)(linked, unlinked.packageDir));
|
|
310
|
+
if (!linked.ok)
|
|
311
|
+
console.error(`codie: ${(0, codieRuntimeInstall_1.linkFailure)(linked, unlinked.packageDir)} Reinstalling the engine.`);
|
|
312
|
+
return linked.ok;
|
|
313
|
+
},
|
|
342
314
|
confirmUpdate: async (outdated) => {
|
|
343
315
|
console.error("");
|
|
344
316
|
console.error(`Codie harness ${outdated.expectedVersion} is available (you're on ${outdated.currentVersion}).`);
|
|
@@ -352,10 +324,10 @@ async function main() {
|
|
|
352
324
|
});
|
|
353
325
|
const metadataPlugin = (0, url_1.pathToFileURL)(assetPath("opencode-plugin.mjs")).href;
|
|
354
326
|
const capturePlugin = (0, codieLauncher_1.resolveCapturePlugin)({ homeDir: os.homedir(), existsSync: fs.existsSync });
|
|
355
|
-
|
|
327
|
+
(0, codieBrandInstall_1.installTuiPlugin)();
|
|
356
328
|
installBrandWordmark(runtime);
|
|
357
329
|
const config = (0, codieLauncher_1.buildCodieConfig)({
|
|
358
|
-
existing: existingInlineConfig(),
|
|
330
|
+
existing: withStarterPacks(existingInlineConfig(), new Set(catalog.map((model) => (0, codieLauncher_1.bareModel)(model.id)).filter(Boolean)), catalog),
|
|
359
331
|
catalog,
|
|
360
332
|
env: { ...process.env, ...parsed.overrides, CODIEDEV_GATEWAY_URL: gatewayUrl },
|
|
361
333
|
plugins: [capturePlugin, metadataPlugin],
|
|
@@ -374,7 +346,20 @@ async function main() {
|
|
|
374
346
|
if (nonInteractiveRun)
|
|
375
347
|
env.CODIEDEV_SECURITY_BLOCK_OUTPUT = "marker";
|
|
376
348
|
if (nonInteractiveRun) {
|
|
349
|
+
const reportCost = Boolean(process.stderr.isTTY);
|
|
350
|
+
const startedAt = Date.now();
|
|
351
|
+
if (reportCost) {
|
|
352
|
+
const line = (0, codieUsage_1.formatUsageLine)(await (0, codieUsage_1.fetchCodieUsage)({ baseUrl: gatewayUrl, key }));
|
|
353
|
+
if (line)
|
|
354
|
+
console.error(line);
|
|
355
|
+
}
|
|
377
356
|
process.exitCode = (await runNonInteractive(runtime, runtimeArgs, env)) ?? 1;
|
|
357
|
+
if (reportCost) {
|
|
358
|
+
await new Promise((resolve) => setTimeout(resolve, USAGE_SETTLE_MS));
|
|
359
|
+
const cost = (0, codieUsage_1.formatSessionCostLine)(await (0, codieUsage_1.fetchCodieUsage)({ baseUrl: gatewayUrl, key, sinceMs: startedAt }));
|
|
360
|
+
if (cost)
|
|
361
|
+
console.error(cost);
|
|
362
|
+
}
|
|
378
363
|
return;
|
|
379
364
|
}
|
|
380
365
|
const result = (0, child_process_1.spawnSync)(runtime, runtimeArgs, { stdio: "inherit", env });
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.usageModulePath = usageModulePath;
|
|
37
|
+
exports.openCodeConfigDir = openCodeConfigDir;
|
|
38
|
+
exports.installTuiPlugin = installTuiPlugin;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const os = __importStar(require("os"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const codieLauncher_1 = require("./codieLauncher");
|
|
43
|
+
function assetPath(name) {
|
|
44
|
+
return path.join(__dirname, "..", "assets", name);
|
|
45
|
+
}
|
|
46
|
+
function usageModulePath() {
|
|
47
|
+
const candidates = [
|
|
48
|
+
path.join(__dirname, "codieUsage.js"),
|
|
49
|
+
path.join(__dirname, "codieUsage.ts"),
|
|
50
|
+
];
|
|
51
|
+
const found = candidates.find((candidate) => fs.existsSync(candidate));
|
|
52
|
+
if (!found)
|
|
53
|
+
throw new Error("this install has no Codiedev usage module");
|
|
54
|
+
return found;
|
|
55
|
+
}
|
|
56
|
+
function openCodeConfigDir() {
|
|
57
|
+
return path.join(process.env.XDG_CONFIG_HOME?.trim() || path.join(os.homedir(), ".config"), "opencode");
|
|
58
|
+
}
|
|
59
|
+
function installTuiPlugin() {
|
|
60
|
+
try {
|
|
61
|
+
const configDir = openCodeConfigDir();
|
|
62
|
+
const pluginDir = path.join(configDir, "plugins");
|
|
63
|
+
fs.mkdirSync(pluginDir, { recursive: true });
|
|
64
|
+
const source = (0, codieLauncher_1.stageUsageModule)(fs.readFileSync(assetPath("tui-brand-plugin.tsx"), "utf8"), usageModulePath());
|
|
65
|
+
const destination = path.join(pluginDir, path.basename(codieLauncher_1.BRAND_PLUGIN_SPEC));
|
|
66
|
+
if (!fs.existsSync(destination) || fs.readFileSync(destination, "utf8") !== source) {
|
|
67
|
+
fs.writeFileSync(destination, source);
|
|
68
|
+
}
|
|
69
|
+
const tuiConfigPath = path.join(configDir, "tui.json");
|
|
70
|
+
const existing = fs.existsSync(tuiConfigPath)
|
|
71
|
+
? JSON.parse(fs.readFileSync(tuiConfigPath, "utf8"))
|
|
72
|
+
: {};
|
|
73
|
+
const { config, changed } = (0, codieLauncher_1.withBrandPlugin)(existing);
|
|
74
|
+
if (changed)
|
|
75
|
+
fs.writeFileSync(tuiConfigPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
console.error(`codie: continuing without Codiedev branding (${error instanceof Error ? error.message : error})`);
|
|
79
|
+
}
|
|
80
|
+
}
|
package/dist/codieLauncher.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Pure launcher logic for the Codie harness.
|
|
3
|
-
//
|
|
4
|
-
// Ported from codiedev-gateway-cli/npm/lib/launcher.js when the harness folded
|
|
5
|
-
// into this package so `npm i -g codiedev` is the only install a developer
|
|
6
|
-
// needs — Claude Code, Codex, Cursor, and Codie all come from one package and
|
|
7
|
-
// share the one token `codiedev connect` stored.
|
|
8
|
-
//
|
|
9
|
-
// Everything here is pure (no fs/network side effects beyond an injected
|
|
10
|
-
// fetch) so the governance rules can be tested without a live gateway.
|
|
11
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
3
|
if (k2 === undefined) k2 = k;
|
|
13
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -42,11 +33,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
42
33
|
};
|
|
43
34
|
})();
|
|
44
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
-
exports.HIDDEN_WORDMARK = exports.CODIEDEV_WORDMARK = exports.LEGACY_CODIEDEV_WORDMARK = exports.STOCK_WORDMARK = exports.BRAND_PLUGIN_SPEC = exports.CODIE_SECURITY_BLOCK_MARKER = void 0;
|
|
36
|
+
exports.HIDDEN_WORDMARK = exports.CODIEDEV_WORDMARK = exports.LEGACY_CODIEDEV_WORDMARK = exports.STOCK_WORDMARK = exports.BRAND_PLUGIN_SPEC = exports.USAGE_MODULE_PLACEHOLDER = exports.CODIE_SECURITY_BLOCK_MARKER = void 0;
|
|
37
|
+
exports.usableModelCost = usableModelCost;
|
|
38
|
+
exports.usableModelLimit = usableModelLimit;
|
|
46
39
|
exports.extractCodieSecurityBlock = extractCodieSecurityBlock;
|
|
47
40
|
exports.withCodieWorkingDirectory = withCodieWorkingDirectory;
|
|
48
41
|
exports.bareModel = bareModel;
|
|
49
42
|
exports.buildCodieConfig = buildCodieConfig;
|
|
43
|
+
exports.stageUsageModule = stageUsageModule;
|
|
50
44
|
exports.withBrandPlugin = withBrandPlugin;
|
|
51
45
|
exports.patchBrandWordmark = patchBrandWordmark;
|
|
52
46
|
exports.resolveCapturePlugin = resolveCapturePlugin;
|
|
@@ -55,6 +49,7 @@ exports.parseCodieArgs = parseCodieArgs;
|
|
|
55
49
|
exports.validateCodieArgs = validateCodieArgs;
|
|
56
50
|
const path = __importStar(require("path"));
|
|
57
51
|
const url_1 = require("url");
|
|
52
|
+
const harnessDirs_1 = require("./harnessDirs");
|
|
58
53
|
const DEFAULT_NAMES = {
|
|
59
54
|
"openai/gpt-5.6-luna": "GPT-5.6 Luna",
|
|
60
55
|
"openai/gpt-5.3-codex": "GPT-5.3 Codex",
|
|
@@ -64,10 +59,31 @@ const DEFAULT_NAMES = {
|
|
|
64
59
|
"z-ai/glm-5.2": "GLM 5.2 · Fireworks ZDR",
|
|
65
60
|
"moonshotai/kimi-k2.7-code": "Kimi K2.7 Code · Fireworks ZDR",
|
|
66
61
|
};
|
|
62
|
+
function usableModelCost(value) {
|
|
63
|
+
if (!value || typeof value !== "object")
|
|
64
|
+
return undefined;
|
|
65
|
+
const { input, output } = value;
|
|
66
|
+
if (typeof input !== "number" || typeof output !== "number")
|
|
67
|
+
return undefined;
|
|
68
|
+
if (!Number.isFinite(input) || !Number.isFinite(output))
|
|
69
|
+
return undefined;
|
|
70
|
+
if (input < 0 || output < 0)
|
|
71
|
+
return undefined;
|
|
72
|
+
return { input, output };
|
|
73
|
+
}
|
|
74
|
+
function usableModelLimit(value) {
|
|
75
|
+
if (!value || typeof value !== "object")
|
|
76
|
+
return undefined;
|
|
77
|
+
const { context, output } = value;
|
|
78
|
+
if (typeof context !== "number" || typeof output !== "number")
|
|
79
|
+
return undefined;
|
|
80
|
+
if (!Number.isFinite(context) || !Number.isFinite(output))
|
|
81
|
+
return undefined;
|
|
82
|
+
if (context <= 0 || output <= 0)
|
|
83
|
+
return undefined;
|
|
84
|
+
return { context, output };
|
|
85
|
+
}
|
|
67
86
|
exports.CODIE_SECURITY_BLOCK_MARKER = "__CODIEDEV_SECURITY_BLOCK__";
|
|
68
|
-
/** Extract the private adapter marker used to carry a local block reason
|
|
69
|
-
* across OpenCode's generic 500 boundary. The marker never contains prompt or
|
|
70
|
-
* tool input — only the deterministic policy reason. */
|
|
71
87
|
function extractCodieSecurityBlock(stderr) {
|
|
72
88
|
for (const line of stderr.split(/\r?\n/)) {
|
|
73
89
|
const markerIndex = line.indexOf(exports.CODIE_SECURITY_BLOCK_MARKER);
|
|
@@ -79,17 +95,10 @@ function extractCodieSecurityBlock(stderr) {
|
|
|
79
95
|
return parsed.reason.trim();
|
|
80
96
|
}
|
|
81
97
|
catch {
|
|
82
|
-
// Ignore malformed or foreign stderr and preserve the original runtime error.
|
|
83
98
|
}
|
|
84
99
|
}
|
|
85
100
|
return undefined;
|
|
86
101
|
}
|
|
87
|
-
/**
|
|
88
|
-
* Pin non-interactive runs to the directory where `codie` was launched.
|
|
89
|
-
* OpenCode can reuse a previously-known project instance; without an explicit
|
|
90
|
-
* --dir, a real smoke run launched in a throwaway repo resumed the caller's
|
|
91
|
-
* main checkout and executed there. TUI mode already owns its cwd directly.
|
|
92
|
-
*/
|
|
93
102
|
function withCodieWorkingDirectory(args, cwd) {
|
|
94
103
|
if (args[0] !== "run")
|
|
95
104
|
return args;
|
|
@@ -111,8 +120,6 @@ function governedModel(value, approved, fallback, label) {
|
|
|
111
120
|
return `codiedev/${model}`;
|
|
112
121
|
}
|
|
113
122
|
function economicalModel(catalog, primary) {
|
|
114
|
-
// Catalog ids arrive already normalized through bareModel(), so the
|
|
115
|
-
// gateway's `codiedev/fast` alias appears here as plain "fast".
|
|
116
123
|
const preferred = ["openai/gpt-5.1-codex-mini", "fast", "z-ai/glm-5.2"];
|
|
117
124
|
return preferred.find((id) => catalog.some((model) => model.id === id)) || primary;
|
|
118
125
|
}
|
|
@@ -143,10 +150,18 @@ function buildCodieConfig({ existing = {}, catalog, env = {}, plugin, plugins =
|
|
|
143
150
|
const planModel = governedModel(requestedPlan, approved, fast, "Plan agent");
|
|
144
151
|
const existingPlugins = Array.isArray(existing.plugin) ? existing.plugin : [];
|
|
145
152
|
const requiredPlugins = [...plugins, plugin].filter(Boolean);
|
|
146
|
-
const models = Object.fromEntries(catalog.map((model) =>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
153
|
+
const models = Object.fromEntries(catalog.map((model) => {
|
|
154
|
+
const cost = usableModelCost(model.cost);
|
|
155
|
+
const limit = usableModelLimit(model.limit);
|
|
156
|
+
return [
|
|
157
|
+
bareModel(model.id),
|
|
158
|
+
{
|
|
159
|
+
name: model.name || DEFAULT_NAMES[bareModel(model.id)] || bareModel(model.id),
|
|
160
|
+
...(cost ? { cost: { ...cost, cache: { read: 0, write: 0 } } } : {}),
|
|
161
|
+
...(limit ? { limit } : {}),
|
|
162
|
+
},
|
|
163
|
+
];
|
|
164
|
+
}));
|
|
150
165
|
return {
|
|
151
166
|
...existing,
|
|
152
167
|
model: governedModel(primary, approved, first, "Primary agent"),
|
|
@@ -174,9 +189,14 @@ function buildCodieConfig({ existing = {}, catalog, env = {}, plugin, plugins =
|
|
|
174
189
|
plugin: [...existingPlugins.filter((item) => !requiredPlugins.includes(item)), ...requiredPlugins],
|
|
175
190
|
};
|
|
176
191
|
}
|
|
192
|
+
exports.USAGE_MODULE_PLACEHOLDER = "__CODIEDEV_USAGE_MODULE__";
|
|
193
|
+
function stageUsageModule(source, modulePath) {
|
|
194
|
+
if (!source.includes(exports.USAGE_MODULE_PLACEHOLDER)) {
|
|
195
|
+
throw new Error(`plugin template is missing the ${exports.USAGE_MODULE_PLACEHOLDER} placeholder`);
|
|
196
|
+
}
|
|
197
|
+
return source.split(exports.USAGE_MODULE_PLACEHOLDER).join(JSON.stringify(modulePath));
|
|
198
|
+
}
|
|
177
199
|
exports.BRAND_PLUGIN_SPEC = "./plugins/codiedev-brand.tsx";
|
|
178
|
-
// Pure merge for ~/.config/opencode/tui.json: TUI plugins load from tui.json,
|
|
179
|
-
// not the opencode.json we inject via OPENCODE_CONFIG_CONTENT.
|
|
180
200
|
function withBrandPlugin(existing) {
|
|
181
201
|
const config = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
|
|
182
202
|
const plugins = Array.isArray(config.plugin) ? config.plugin : [];
|
|
@@ -185,13 +205,6 @@ function withBrandPlugin(existing) {
|
|
|
185
205
|
return { config, changed: false };
|
|
186
206
|
return { config: { ...config, plugin: [...plugins, exports.BRAND_PLUGIN_SPEC] }, changed: true };
|
|
187
207
|
}
|
|
188
|
-
// ── Engine wordmark suppression ─────────────────────────────────────────
|
|
189
|
-
// The OpenCode engine prints a block-letter "opencode" wordmark to terminal
|
|
190
|
-
// scrollback around each session (the boot/exit banner). A four-row terminal
|
|
191
|
-
// raster cannot reproduce the real Codiedev wordmark cleanly, so leave that
|
|
192
|
-
// surface blank and keep the proper brand mark on the plugin-driven home
|
|
193
|
-
// screen. The bundled JS table is replaced byte-for-byte so binary offsets do
|
|
194
|
-
// not move.
|
|
195
208
|
function escapeJsSource(row) {
|
|
196
209
|
let out = "";
|
|
197
210
|
for (const ch of row) {
|
|
@@ -204,7 +217,6 @@ function wordmarkRegion(left, right, { escapeUnicode = true } = {}) {
|
|
|
204
217
|
const rows = (list) => list.map((row) => `"${escapeUnicode ? escapeJsSource(row) : row}"`).join(",");
|
|
205
218
|
return `var vn={left:[${rows(left)}],right:[${rows(right)}]};`;
|
|
206
219
|
}
|
|
207
|
-
// o p e n | c o d e — must match the engine's bundle byte-for-byte.
|
|
208
220
|
exports.STOCK_WORDMARK = wordmarkRegion([
|
|
209
221
|
" ",
|
|
210
222
|
"█▀▀█ █▀▀█ █▀▀█ █▀▀▄",
|
|
@@ -216,12 +228,6 @@ exports.STOCK_WORDMARK = wordmarkRegion([
|
|
|
216
228
|
"█___ █__█ █__█ █^^^",
|
|
217
229
|
"▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀",
|
|
218
230
|
]);
|
|
219
|
-
// c o d i | e d e v, rasterized from public/codiedevlogo.svg at eight vertical
|
|
220
|
-
// pixels and packed into four terminal rows with half-block characters. This
|
|
221
|
-
// preserves the real mark's round lowercase bowls, linked c/o, ascenders, and
|
|
222
|
-
// compact v instead of approximating the letters with OpenCode's square font.
|
|
223
|
-
// The engine inserts one column between left and right, so the blank source
|
|
224
|
-
// column at the codi/edev boundary is intentionally omitted.
|
|
225
231
|
const CODIE_LEFT = [
|
|
226
232
|
" ▄ ▄",
|
|
227
233
|
" ▄▄█▄▄ ▄▄█▄▄ ▄████ █",
|
|
@@ -234,9 +240,6 @@ const CODIE_RIGHT = [
|
|
|
234
240
|
"██▀▀█ █ █ ██▄▀█ ▀█▄█ ",
|
|
235
241
|
"▀▀█▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀▀ ",
|
|
236
242
|
];
|
|
237
|
-
// Migration source for the first hand-drawn banner shipped during development.
|
|
238
|
-
// Recognizing it lets an existing install upgrade in place instead of keeping
|
|
239
|
-
// the old square letterforms until OpenCode happens to reinstall its binary.
|
|
240
243
|
const LEGACY_CODIE_LEFT = [
|
|
241
244
|
" ▄ ▄ ",
|
|
242
245
|
"█▀▀▀ █▀▀█ █▀▀█ █ ",
|
|
@@ -258,9 +261,6 @@ exports.LEGACY_CODIEDEV_WORDMARK = (() => {
|
|
|
258
261
|
return wordmarkRegion(LEGACY_CODIE_LEFT, padded);
|
|
259
262
|
})();
|
|
260
263
|
exports.CODIEDEV_WORDMARK = (() => {
|
|
261
|
-
// Raw Unicode is valid JavaScript and costs fewer source bytes than \uXXXX.
|
|
262
|
-
// Put the remaining byte padding outside the strings so it cannot widen the
|
|
263
|
-
// rendered banner or shift its centering.
|
|
264
264
|
const unpadded = wordmarkRegion(CODIE_LEFT, CODIE_RIGHT, { escapeUnicode: false });
|
|
265
265
|
const deficit = Buffer.byteLength(exports.STOCK_WORDMARK) - Buffer.byteLength(unpadded);
|
|
266
266
|
if (deficit < 0)
|
|
@@ -282,9 +282,6 @@ exports.HIDDEN_WORDMARK = (() => {
|
|
|
282
282
|
}
|
|
283
283
|
return region;
|
|
284
284
|
})();
|
|
285
|
-
// Pure: locate the stock or an earlier Codiedev wordmark in an engine binary.
|
|
286
|
-
// Refuses to touch the file unless exactly one known region appears; an
|
|
287
|
-
// already-hidden or reshaped upstream bundle is left alone.
|
|
288
285
|
function patchBrandWordmark(binary) {
|
|
289
286
|
const stock = Buffer.from(exports.STOCK_WORDMARK);
|
|
290
287
|
const candidates = [stock, Buffer.from(exports.LEGACY_CODIEDEV_WORDMARK), Buffer.from(exports.CODIEDEV_WORDMARK)];
|
|
@@ -302,7 +299,7 @@ function patchBrandWordmark(binary) {
|
|
|
302
299
|
return { changed: true, offset: matches[0], stock, replacement: Buffer.from(exports.HIDDEN_WORDMARK) };
|
|
303
300
|
}
|
|
304
301
|
function resolveCapturePlugin({ homeDir, existsSync, }) {
|
|
305
|
-
const capturePath = path.join(
|
|
302
|
+
const capturePath = path.join((0, harnessDirs_1.openCodeConfigDir)(process.env, homeDir), "plugins", "codiedev.js");
|
|
306
303
|
if (!existsSync(capturePath)) {
|
|
307
304
|
throw new Error("Codiedev session capture is not installed. Run `codiedev connect` first");
|
|
308
305
|
}
|
|
@@ -316,9 +313,6 @@ async function fetchApprovedCatalog({ baseUrl, key, fetchImpl = fetch, }) {
|
|
|
316
313
|
headers: { Authorization: `Bearer ${key}` },
|
|
317
314
|
signal: controller.signal,
|
|
318
315
|
});
|
|
319
|
-
// The `codie` bin ships to every connected machine, including companies
|
|
320
|
-
// whose gateway is still switched off. Those developers must get an
|
|
321
|
-
// answer, not an HTTP status.
|
|
322
316
|
if (response.status === 403) {
|
|
323
317
|
throw new Error("The Codie harness is not enabled for your company yet. Ask your Codiedev admin to turn it on — " +
|
|
324
318
|
"your session capture keeps working in the meantime.");
|
|
@@ -332,10 +326,16 @@ async function fetchApprovedCatalog({ baseUrl, key, fetchImpl = fetch, }) {
|
|
|
332
326
|
if (!Array.isArray(payload?.data) || payload.data.length === 0) {
|
|
333
327
|
throw new Error("model catalog is empty");
|
|
334
328
|
}
|
|
335
|
-
return payload.data.map((model) =>
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
329
|
+
return payload.data.map((model) => {
|
|
330
|
+
const cost = usableModelCost(model.cost);
|
|
331
|
+
const limit = usableModelLimit(model.limit);
|
|
332
|
+
return {
|
|
333
|
+
id: bareModel(model.id),
|
|
334
|
+
name: typeof model.name === "string" && model.name ? model.name : DEFAULT_NAMES[bareModel(model.id)],
|
|
335
|
+
...(cost ? { cost } : {}),
|
|
336
|
+
...(limit ? { limit } : {}),
|
|
337
|
+
};
|
|
338
|
+
});
|
|
339
339
|
}
|
|
340
340
|
finally {
|
|
341
341
|
clearTimeout(timeout);
|
package/dist/codieRuntime.js
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// Where the Codie harness gets its engine.
|
|
3
|
-
//
|
|
4
|
-
// The engine (`opencode-ai`) is a ~132MB platform binary. It is deliberately
|
|
5
|
-
// NOT a dependency of this package: the overwhelming majority of installs are
|
|
6
|
-
// capture-only (Claude Code, Codex, Cursor) and must not pay for a harness
|
|
7
|
-
// they never launch. So `npm i -g codiedev` stays small, and the first `codie`
|
|
8
|
-
// run downloads the engine into the Codiedev state dir.
|
|
9
|
-
//
|
|
10
|
-
// Resolution is pure and injectable so the precedence can be tested without
|
|
11
|
-
// touching the network or a real 132MB install.
|
|
12
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
3
|
if (k2 === undefined) k2 = k;
|
|
14
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -43,20 +33,15 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
43
33
|
};
|
|
44
34
|
})();
|
|
45
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
-
exports.CODIE_MIN_NODE_MAJOR = exports.OPENCODE_RUNTIME_VERSION = exports.OPENCODE_RUNTIME_SPEC = void 0;
|
|
36
|
+
exports.ENGINE_MIN_BYTES = exports.CODIE_MIN_NODE_MAJOR = exports.OPENCODE_RUNTIME_VERSION = exports.OPENCODE_RUNTIME_SPEC = void 0;
|
|
47
37
|
exports.codieRuntimeDir = codieRuntimeDir;
|
|
38
|
+
exports.isEngineSize = isEngineSize;
|
|
48
39
|
exports.installedRuntimePackageJson = installedRuntimePackageJson;
|
|
49
40
|
exports.resolveCodieRuntime = resolveCodieRuntime;
|
|
50
41
|
exports.assertCodieNodeVersion = assertCodieNodeVersion;
|
|
51
42
|
const path = __importStar(require("path"));
|
|
52
|
-
// Pinned exactly, not a range. patchBrandWordmark() only rewrites bundles it
|
|
53
|
-
// recognizes byte-for-byte, so a floating version would silently regress the
|
|
54
|
-
// terminal branding whenever OpenCode ships a new build.
|
|
55
43
|
exports.OPENCODE_RUNTIME_SPEC = "opencode-ai@1.18.4";
|
|
56
44
|
exports.OPENCODE_RUNTIME_VERSION = exports.OPENCODE_RUNTIME_SPEC.slice(exports.OPENCODE_RUNTIME_SPEC.lastIndexOf("@") + 1);
|
|
57
|
-
// The harness needs 20; capture does not. package.json `engines` stays >=18 so
|
|
58
|
-
// `codiedev connect` still installs for Node 18 users — this floor is enforced
|
|
59
|
-
// at `codie` launch instead.
|
|
60
45
|
exports.CODIE_MIN_NODE_MAJOR = 20;
|
|
61
46
|
function codieRuntimeDir(stateDir) {
|
|
62
47
|
return path.join(stateDir, "runtime");
|
|
@@ -64,11 +49,14 @@ function codieRuntimeDir(stateDir) {
|
|
|
64
49
|
function installedBinary(stateDir) {
|
|
65
50
|
return path.join(codieRuntimeDir(stateDir), "node_modules", "opencode-ai", "bin", "opencode.exe");
|
|
66
51
|
}
|
|
52
|
+
exports.ENGINE_MIN_BYTES = 1_000_000;
|
|
53
|
+
function isEngineSize(bytes) {
|
|
54
|
+
return bytes >= exports.ENGINE_MIN_BYTES;
|
|
55
|
+
}
|
|
67
56
|
function installedRuntimePackageJson(stateDir) {
|
|
68
57
|
return path.join(codieRuntimeDir(stateDir), "node_modules", "opencode-ai", "package.json");
|
|
69
58
|
}
|
|
70
|
-
function resolveCodieRuntime({ env, stateDir, existsSync, readInstalledVersion, resolveBundled, }) {
|
|
71
|
-
// 1. Explicit override — the air-gapped / pre-provisioned escape hatch.
|
|
59
|
+
function resolveCodieRuntime({ env, stateDir, existsSync, readInstalledVersion, resolveBundled, isEngine = () => true, }) {
|
|
72
60
|
const override = env.CODIEDEV_OPENCODE_BINARY?.trim();
|
|
73
61
|
if (override) {
|
|
74
62
|
if (!existsSync(override)) {
|
|
@@ -76,15 +64,21 @@ function resolveCodieRuntime({ env, stateDir, existsSync, readInstalledVersion,
|
|
|
76
64
|
}
|
|
77
65
|
return { kind: "ready", binary: override };
|
|
78
66
|
}
|
|
79
|
-
// 2. A bundled engine, if this package was installed with one (dev checkout,
|
|
80
|
-
// or a future vendored distribution).
|
|
81
67
|
const bundled = resolveBundled();
|
|
82
|
-
if (bundled)
|
|
68
|
+
if (bundled && isEngine(bundled))
|
|
83
69
|
return { kind: "ready", binary: bundled };
|
|
84
|
-
// 3. The lazily installed engine.
|
|
85
70
|
const binary = installedBinary(stateDir);
|
|
86
71
|
if (existsSync(binary)) {
|
|
87
72
|
const currentVersion = readInstalledVersion?.(installedRuntimePackageJson(stateDir)) ?? null;
|
|
73
|
+
if (!isEngine(binary) && (!currentVersion || currentVersion === exports.OPENCODE_RUNTIME_VERSION)) {
|
|
74
|
+
return {
|
|
75
|
+
kind: "unlinked",
|
|
76
|
+
installDir: codieRuntimeDir(stateDir),
|
|
77
|
+
binary,
|
|
78
|
+
spec: exports.OPENCODE_RUNTIME_SPEC,
|
|
79
|
+
packageDir: path.dirname(installedRuntimePackageJson(stateDir)),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
88
82
|
if (currentVersion && currentVersion !== exports.OPENCODE_RUNTIME_VERSION) {
|
|
89
83
|
return {
|
|
90
84
|
kind: "outdated",
|
|
@@ -93,6 +87,8 @@ function resolveCodieRuntime({ env, stateDir, existsSync, readInstalledVersion,
|
|
|
93
87
|
spec: exports.OPENCODE_RUNTIME_SPEC,
|
|
94
88
|
currentVersion,
|
|
95
89
|
expectedVersion: exports.OPENCODE_RUNTIME_VERSION,
|
|
90
|
+
linked: isEngine(binary),
|
|
91
|
+
packageDir: path.dirname(installedRuntimePackageJson(stateDir)),
|
|
96
92
|
};
|
|
97
93
|
}
|
|
98
94
|
return { kind: "ready", binary };
|