codiedev 0.10.0-beta.4 → 0.10.0-beta.6
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 +11 -5
- package/assets/tui-brand-plugin.tsx +14 -2
- 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 +68 -3
- package/dist/cli.js +75 -64
- package/dist/codexHookTrust.js +125 -6
- package/dist/codexLimitScan.js +2 -109
- package/dist/codie.js +50 -114
- package/dist/codieBrandInstall.js +0 -18
- package/dist/codieLauncher.js +20 -92
- package/dist/codieRuntime.js +19 -23
- package/dist/codieRuntimeInstall.js +108 -23
- package/dist/codieUsage.js +38 -41
- package/dist/commands/agentTemplates.generated.js +136 -0
- package/dist/commands/agents.js +1066 -0
- package/dist/commands/agentsSdk.generated.js +7 -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 +53 -120
- package/dist/commands/evals.js +187 -0
- 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/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 +344 -0
- package/dist/commands/tracesLabel.js +348 -0
- package/dist/configDir.js +0 -10
- package/dist/connect.js +19 -116
- package/dist/connectFlow.js +0 -9
- package/dist/copilotHooks.js +391 -0
- package/dist/copilotInstallation.js +64 -0
- package/dist/cursorHooks.js +38 -30
- package/dist/cursorLifecycle.js +109 -0
- package/dist/detection.js +0 -30
- package/dist/harnessDirs.js +77 -0
- package/dist/hook.js +182 -469
- 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/managedPi.js +240 -0
- package/dist/mcp.js +3 -384
- package/dist/nativeSteering.js +24 -0
- package/dist/packs/codie.js +182 -0
- package/dist/packs/harnesses.js +411 -0
- package/dist/packs/hookGate.js +256 -0
- package/dist/packs/install.js +286 -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/piHooks.js +216 -0
- package/dist/piRuntime.js +120 -0
- package/dist/repoResolver.js +0 -19
- package/dist/secret.js +0 -3
- package/dist/selfUpdate.js +376 -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 +494 -824
- package/dist/version.js +0 -10
- package/dist/versionCheck.js +0 -33
- package/package.json +8 -9
- 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/codieBrandInstall.d.ts +0 -11
- package/dist/codieLauncher.d.ts +0 -86
- package/dist/codieRuntime.d.ts +0 -29
- package/dist/codieRuntimeInstall.d.ts +0 -28
- package/dist/codieStartup.d.ts +0 -26
- package/dist/codieStartup.js +0 -30
- package/dist/codieUsage.d.ts +0 -57
- 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/promote.js +0 -53
- 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/react.js +0 -40
- package/dist/commands/reverseTicket.d.ts +0 -2
- package/dist/commands/reverseTicket.js +0 -477
- package/dist/commands/search.d.ts +0 -2
- package/dist/commands/security.d.ts +0 -1
- package/dist/commands/security.js +0 -156
- 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/prUrl.js +0 -33
- package/dist/repoResolver.d.ts +0 -17
- package/dist/secret.d.ts +0 -1
- package/dist/security.d.ts +0 -102
- package/dist/security.js +0 -437
- package/dist/securityDeepScan.d.ts +0 -41
- package/dist/securityDeepScan.js +0 -248
- package/dist/securityDoctor.d.ts +0 -32
- package/dist/securityDoctor.js +0 -63
- package/dist/securityFeature.d.ts +0 -5
- package/dist/securityFeature.js +0 -7
- package/dist/securityInstall.d.ts +0 -63
- package/dist/securityInstall.js +0 -239
- package/dist/securityInventory.d.ts +0 -54
- package/dist/securityInventory.js +0 -556
- package/dist/securityPilot.d.ts +0 -19
- package/dist/securityPilot.js +0 -61
- package/dist/securityPolicy.d.ts +0 -33
- package/dist/securityPolicy.js +0 -188
- package/dist/securitySession.d.ts +0 -6
- package/dist/securitySession.js +0 -72
- 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/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,10 +33,9 @@ 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.USAGE_MODULE_PLACEHOLDER =
|
|
36
|
+
exports.HIDDEN_WORDMARK = exports.CODIEDEV_WORDMARK = exports.LEGACY_CODIEDEV_WORDMARK = exports.STOCK_WORDMARK = exports.BRAND_PLUGIN_SPEC = exports.USAGE_MODULE_PLACEHOLDER = void 0;
|
|
46
37
|
exports.usableModelCost = usableModelCost;
|
|
47
38
|
exports.usableModelLimit = usableModelLimit;
|
|
48
|
-
exports.extractCodieSecurityBlock = extractCodieSecurityBlock;
|
|
49
39
|
exports.withCodieWorkingDirectory = withCodieWorkingDirectory;
|
|
50
40
|
exports.bareModel = bareModel;
|
|
51
41
|
exports.buildCodieConfig = buildCodieConfig;
|
|
@@ -58,6 +48,7 @@ exports.parseCodieArgs = parseCodieArgs;
|
|
|
58
48
|
exports.validateCodieArgs = validateCodieArgs;
|
|
59
49
|
const path = __importStar(require("path"));
|
|
60
50
|
const url_1 = require("url");
|
|
51
|
+
const harnessDirs_1 = require("./harnessDirs");
|
|
61
52
|
const DEFAULT_NAMES = {
|
|
62
53
|
"openai/gpt-5.6-luna": "GPT-5.6 Luna",
|
|
63
54
|
"openai/gpt-5.3-codex": "GPT-5.3 Codex",
|
|
@@ -67,9 +58,6 @@ const DEFAULT_NAMES = {
|
|
|
67
58
|
"z-ai/glm-5.2": "GLM 5.2 · Fireworks ZDR",
|
|
68
59
|
"moonshotai/kimi-k2.7-code": "Kimi K2.7 Code · Fireworks ZDR",
|
|
69
60
|
};
|
|
70
|
-
/** A rate card is usable only when both sides are real, finite and not
|
|
71
|
-
* negative. Half a card prices a session wrong in a way nobody can see, so a
|
|
72
|
-
* partial one is dropped and the model stays unpriced. */
|
|
73
61
|
function usableModelCost(value) {
|
|
74
62
|
if (!value || typeof value !== "object")
|
|
75
63
|
return undefined;
|
|
@@ -82,10 +70,6 @@ function usableModelCost(value) {
|
|
|
82
70
|
return undefined;
|
|
83
71
|
return { input, output };
|
|
84
72
|
}
|
|
85
|
-
/** A context/output window is usable only when both sides are real, finite and
|
|
86
|
-
* positive. A partial window makes the engine's "% of context used" read wrong
|
|
87
|
-
* in a way nobody can see, so a partial one is dropped and the model keeps the
|
|
88
|
-
* engine's default. */
|
|
89
73
|
function usableModelLimit(value) {
|
|
90
74
|
if (!value || typeof value !== "object")
|
|
91
75
|
return undefined;
|
|
@@ -98,32 +82,6 @@ function usableModelLimit(value) {
|
|
|
98
82
|
return undefined;
|
|
99
83
|
return { context, output };
|
|
100
84
|
}
|
|
101
|
-
exports.CODIE_SECURITY_BLOCK_MARKER = "__CODIEDEV_SECURITY_BLOCK__";
|
|
102
|
-
/** Extract the private adapter marker used to carry a local block reason
|
|
103
|
-
* across OpenCode's generic 500 boundary. The marker never contains prompt or
|
|
104
|
-
* tool input — only the deterministic policy reason. */
|
|
105
|
-
function extractCodieSecurityBlock(stderr) {
|
|
106
|
-
for (const line of stderr.split(/\r?\n/)) {
|
|
107
|
-
const markerIndex = line.indexOf(exports.CODIE_SECURITY_BLOCK_MARKER);
|
|
108
|
-
if (markerIndex < 0)
|
|
109
|
-
continue;
|
|
110
|
-
try {
|
|
111
|
-
const parsed = JSON.parse(line.slice(markerIndex + exports.CODIE_SECURITY_BLOCK_MARKER.length));
|
|
112
|
-
if (typeof parsed?.reason === "string" && parsed.reason.trim())
|
|
113
|
-
return parsed.reason.trim();
|
|
114
|
-
}
|
|
115
|
-
catch {
|
|
116
|
-
// Ignore malformed or foreign stderr and preserve the original runtime error.
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return undefined;
|
|
120
|
-
}
|
|
121
|
-
/**
|
|
122
|
-
* Pin non-interactive runs to the directory where `codie` was launched.
|
|
123
|
-
* OpenCode can reuse a previously-known project instance; without an explicit
|
|
124
|
-
* --dir, a real smoke run launched in a throwaway repo resumed the caller's
|
|
125
|
-
* main checkout and executed there. TUI mode already owns its cwd directly.
|
|
126
|
-
*/
|
|
127
85
|
function withCodieWorkingDirectory(args, cwd) {
|
|
128
86
|
if (args[0] !== "run")
|
|
129
87
|
return args;
|
|
@@ -145,8 +103,6 @@ function governedModel(value, approved, fallback, label) {
|
|
|
145
103
|
return `codiedev/${model}`;
|
|
146
104
|
}
|
|
147
105
|
function economicalModel(catalog, primary) {
|
|
148
|
-
// Catalog ids arrive already normalized through bareModel(), so the
|
|
149
|
-
// gateway's `codiedev/fast` alias appears here as plain "fast".
|
|
150
106
|
const preferred = ["openai/gpt-5.1-codex-mini", "fast", "z-ai/glm-5.2"];
|
|
151
107
|
return preferred.find((id) => catalog.some((model) => model.id === id)) || primary;
|
|
152
108
|
}
|
|
@@ -178,11 +134,6 @@ function buildCodieConfig({ existing = {}, catalog, env = {}, plugin, plugins =
|
|
|
178
134
|
const existingPlugins = Array.isArray(existing.plugin) ? existing.plugin : [];
|
|
179
135
|
const requiredPlugins = [...plugins, plugin].filter(Boolean);
|
|
180
136
|
const models = Object.fromEntries(catalog.map((model) => {
|
|
181
|
-
// The engine prices a session from this rate card. Without it every
|
|
182
|
-
// model reads $0.00, which is how the harness came to show no spend at
|
|
183
|
-
// all. The gateway publishes prompt and completion prices only, so
|
|
184
|
-
// cached tokens are priced at zero here and the engine's session figure
|
|
185
|
-
// stays an estimate — the budget line from /me/usage is the true spend.
|
|
186
137
|
const cost = usableModelCost(model.cost);
|
|
187
138
|
const limit = usableModelLimit(model.limit);
|
|
188
139
|
return [
|
|
@@ -222,14 +173,6 @@ function buildCodieConfig({ existing = {}, catalog, env = {}, plugin, plugins =
|
|
|
222
173
|
};
|
|
223
174
|
}
|
|
224
175
|
exports.USAGE_MODULE_PLACEHOLDER = "__CODIEDEV_USAGE_MODULE__";
|
|
225
|
-
/**
|
|
226
|
-
* Point the staged TUI plugin at this install's usage module.
|
|
227
|
-
*
|
|
228
|
-
* The plugin is copied into the engine's own config directory, so it cannot
|
|
229
|
-
* reach the package by a relative path — the absolute path is baked in at
|
|
230
|
-
* stage time. It goes in as a JSON literal so a Windows path keeps its
|
|
231
|
-
* backslashes instead of turning into escape sequences.
|
|
232
|
-
*/
|
|
233
176
|
function stageUsageModule(source, modulePath) {
|
|
234
177
|
if (!source.includes(exports.USAGE_MODULE_PLACEHOLDER)) {
|
|
235
178
|
throw new Error(`plugin template is missing the ${exports.USAGE_MODULE_PLACEHOLDER} placeholder`);
|
|
@@ -237,8 +180,6 @@ function stageUsageModule(source, modulePath) {
|
|
|
237
180
|
return source.split(exports.USAGE_MODULE_PLACEHOLDER).join(JSON.stringify(modulePath));
|
|
238
181
|
}
|
|
239
182
|
exports.BRAND_PLUGIN_SPEC = "./plugins/codiedev-brand.tsx";
|
|
240
|
-
// Pure merge for ~/.config/opencode/tui.json: TUI plugins load from tui.json,
|
|
241
|
-
// not the opencode.json we inject via OPENCODE_CONFIG_CONTENT.
|
|
242
183
|
function withBrandPlugin(existing) {
|
|
243
184
|
const config = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
|
|
244
185
|
const plugins = Array.isArray(config.plugin) ? config.plugin : [];
|
|
@@ -247,13 +188,6 @@ function withBrandPlugin(existing) {
|
|
|
247
188
|
return { config, changed: false };
|
|
248
189
|
return { config: { ...config, plugin: [...plugins, exports.BRAND_PLUGIN_SPEC] }, changed: true };
|
|
249
190
|
}
|
|
250
|
-
// ── Engine wordmark suppression ─────────────────────────────────────────
|
|
251
|
-
// The OpenCode engine prints a block-letter "opencode" wordmark to terminal
|
|
252
|
-
// scrollback around each session (the boot/exit banner). A four-row terminal
|
|
253
|
-
// raster cannot reproduce the real Codiedev wordmark cleanly, so leave that
|
|
254
|
-
// surface blank and keep the proper brand mark on the plugin-driven home
|
|
255
|
-
// screen. The bundled JS table is replaced byte-for-byte so binary offsets do
|
|
256
|
-
// not move.
|
|
257
191
|
function escapeJsSource(row) {
|
|
258
192
|
let out = "";
|
|
259
193
|
for (const ch of row) {
|
|
@@ -266,7 +200,6 @@ function wordmarkRegion(left, right, { escapeUnicode = true } = {}) {
|
|
|
266
200
|
const rows = (list) => list.map((row) => `"${escapeUnicode ? escapeJsSource(row) : row}"`).join(",");
|
|
267
201
|
return `var vn={left:[${rows(left)}],right:[${rows(right)}]};`;
|
|
268
202
|
}
|
|
269
|
-
// o p e n | c o d e — must match the engine's bundle byte-for-byte.
|
|
270
203
|
exports.STOCK_WORDMARK = wordmarkRegion([
|
|
271
204
|
" ",
|
|
272
205
|
"█▀▀█ █▀▀█ █▀▀█ █▀▀▄",
|
|
@@ -278,12 +211,6 @@ exports.STOCK_WORDMARK = wordmarkRegion([
|
|
|
278
211
|
"█___ █__█ █__█ █^^^",
|
|
279
212
|
"▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀",
|
|
280
213
|
]);
|
|
281
|
-
// c o d i | e d e v, rasterized from public/codiedevlogo.svg at eight vertical
|
|
282
|
-
// pixels and packed into four terminal rows with half-block characters. This
|
|
283
|
-
// preserves the real mark's round lowercase bowls, linked c/o, ascenders, and
|
|
284
|
-
// compact v instead of approximating the letters with OpenCode's square font.
|
|
285
|
-
// The engine inserts one column between left and right, so the blank source
|
|
286
|
-
// column at the codi/edev boundary is intentionally omitted.
|
|
287
214
|
const CODIE_LEFT = [
|
|
288
215
|
" ▄ ▄",
|
|
289
216
|
" ▄▄█▄▄ ▄▄█▄▄ ▄████ █",
|
|
@@ -296,9 +223,6 @@ const CODIE_RIGHT = [
|
|
|
296
223
|
"██▀▀█ █ █ ██▄▀█ ▀█▄█ ",
|
|
297
224
|
"▀▀█▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀▀ ",
|
|
298
225
|
];
|
|
299
|
-
// Migration source for the first hand-drawn banner shipped during development.
|
|
300
|
-
// Recognizing it lets an existing install upgrade in place instead of keeping
|
|
301
|
-
// the old square letterforms until OpenCode happens to reinstall its binary.
|
|
302
226
|
const LEGACY_CODIE_LEFT = [
|
|
303
227
|
" ▄ ▄ ",
|
|
304
228
|
"█▀▀▀ █▀▀█ █▀▀█ █ ",
|
|
@@ -320,9 +244,6 @@ exports.LEGACY_CODIEDEV_WORDMARK = (() => {
|
|
|
320
244
|
return wordmarkRegion(LEGACY_CODIE_LEFT, padded);
|
|
321
245
|
})();
|
|
322
246
|
exports.CODIEDEV_WORDMARK = (() => {
|
|
323
|
-
// Raw Unicode is valid JavaScript and costs fewer source bytes than \uXXXX.
|
|
324
|
-
// Put the remaining byte padding outside the strings so it cannot widen the
|
|
325
|
-
// rendered banner or shift its centering.
|
|
326
247
|
const unpadded = wordmarkRegion(CODIE_LEFT, CODIE_RIGHT, { escapeUnicode: false });
|
|
327
248
|
const deficit = Buffer.byteLength(exports.STOCK_WORDMARK) - Buffer.byteLength(unpadded);
|
|
328
249
|
if (deficit < 0)
|
|
@@ -344,9 +265,6 @@ exports.HIDDEN_WORDMARK = (() => {
|
|
|
344
265
|
}
|
|
345
266
|
return region;
|
|
346
267
|
})();
|
|
347
|
-
// Pure: locate the stock or an earlier Codiedev wordmark in an engine binary.
|
|
348
|
-
// Refuses to touch the file unless exactly one known region appears; an
|
|
349
|
-
// already-hidden or reshaped upstream bundle is left alone.
|
|
350
268
|
function patchBrandWordmark(binary) {
|
|
351
269
|
const stock = Buffer.from(exports.STOCK_WORDMARK);
|
|
352
270
|
const candidates = [stock, Buffer.from(exports.LEGACY_CODIEDEV_WORDMARK), Buffer.from(exports.CODIEDEV_WORDMARK)];
|
|
@@ -364,29 +282,39 @@ function patchBrandWordmark(binary) {
|
|
|
364
282
|
return { changed: true, offset: matches[0], stock, replacement: Buffer.from(exports.HIDDEN_WORDMARK) };
|
|
365
283
|
}
|
|
366
284
|
function resolveCapturePlugin({ homeDir, existsSync, }) {
|
|
367
|
-
const capturePath = path.join(
|
|
285
|
+
const capturePath = path.join((0, harnessDirs_1.openCodeConfigDir)(process.env, homeDir), "plugins", "codiedev.js");
|
|
368
286
|
if (!existsSync(capturePath)) {
|
|
369
287
|
throw new Error("Codiedev session capture is not installed. Run `codiedev connect` first");
|
|
370
288
|
}
|
|
371
289
|
return (0, url_1.pathToFileURL)(capturePath).href;
|
|
372
290
|
}
|
|
373
|
-
|
|
291
|
+
class CatalogRejected extends Error {
|
|
292
|
+
}
|
|
293
|
+
async function fetchApprovedCatalog({ baseUrl, key, fetchImpl = fetch, retryDelayMs = 1_000, }) {
|
|
294
|
+
try {
|
|
295
|
+
return await fetchCatalogOnce(baseUrl, key, fetchImpl);
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
if (error instanceof CatalogRejected)
|
|
299
|
+
throw error;
|
|
300
|
+
await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
|
|
301
|
+
return fetchCatalogOnce(baseUrl, key, fetchImpl);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
async function fetchCatalogOnce(baseUrl, key, fetchImpl) {
|
|
374
305
|
const controller = new AbortController();
|
|
375
|
-
const timeout = setTimeout(() => controller.abort(),
|
|
306
|
+
const timeout = setTimeout(() => controller.abort(), 10_000);
|
|
376
307
|
try {
|
|
377
308
|
const response = await fetchImpl(`${cleanBaseUrl(baseUrl)}/models`, {
|
|
378
309
|
headers: { Authorization: `Bearer ${key}` },
|
|
379
310
|
signal: controller.signal,
|
|
380
311
|
});
|
|
381
|
-
// The `codie` bin ships to every connected machine, including companies
|
|
382
|
-
// whose gateway is still switched off. Those developers must get an
|
|
383
|
-
// answer, not an HTTP status.
|
|
384
312
|
if (response.status === 403) {
|
|
385
|
-
throw new
|
|
313
|
+
throw new CatalogRejected("The Codie harness is not enabled for your company yet. Ask your Codiedev admin to turn it on — " +
|
|
386
314
|
"your session capture keeps working in the meantime.");
|
|
387
315
|
}
|
|
388
316
|
if (response.status === 401) {
|
|
389
|
-
throw new
|
|
317
|
+
throw new CatalogRejected("Your Codiedev token was rejected. Run `codiedev connect` to relink this machine.");
|
|
390
318
|
}
|
|
391
319
|
if (!response.ok)
|
|
392
320
|
throw new Error(`model catalog returned ${response.status}`);
|
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 };
|
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
// First-run install of the OpenCode engine for the Codie harness.
|
|
3
|
-
//
|
|
4
|
-
// Staged then renamed: npm writes into a sibling staging directory and only an
|
|
5
|
-
// install that actually produced the engine binary gets promoted to the real
|
|
6
|
-
// runtime path. An interrupted or half-finished download therefore never
|
|
7
|
-
// leaves a directory that resolveCodieRuntime() would report as "ready".
|
|
8
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
3
|
if (k2 === undefined) k2 = k;
|
|
10
4
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -39,9 +33,15 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
39
33
|
};
|
|
40
34
|
})();
|
|
41
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.IGNORE_SCRIPTS = void 0;
|
|
42
37
|
exports.buildRuntimeInstallArgs = buildRuntimeInstallArgs;
|
|
43
38
|
exports.installCodieRuntime = installCodieRuntime;
|
|
44
39
|
exports.ensureCodieRuntimeBinary = ensureCodieRuntimeBinary;
|
|
40
|
+
exports.linkFailure = linkFailure;
|
|
41
|
+
exports.windowsCommand = windowsCommand;
|
|
42
|
+
exports.isEngineOnDisk = isEngineOnDisk;
|
|
43
|
+
exports.npmIgnoresScripts = npmIgnoresScripts;
|
|
44
|
+
exports.linkEngineOnDisk = linkEngineOnDisk;
|
|
45
45
|
exports.installCodieRuntimeOnDisk = installCodieRuntimeOnDisk;
|
|
46
46
|
exports.defaultStagingRoot = defaultStagingRoot;
|
|
47
47
|
const fs = __importStar(require("fs"));
|
|
@@ -50,8 +50,6 @@ const path = __importStar(require("path"));
|
|
|
50
50
|
const child_process_1 = require("child_process");
|
|
51
51
|
const codieRuntime_1 = require("./codieRuntime");
|
|
52
52
|
function buildRuntimeInstallArgs(stagingDir, spec) {
|
|
53
|
-
// No --registry / --proxy: inherit whatever npm config the developer's
|
|
54
|
-
// machine already has so an internal mirror keeps working.
|
|
55
53
|
return [
|
|
56
54
|
"install",
|
|
57
55
|
"--prefix",
|
|
@@ -64,7 +62,7 @@ function buildRuntimeInstallArgs(stagingDir, spec) {
|
|
|
64
62
|
];
|
|
65
63
|
}
|
|
66
64
|
function installCodieRuntime(deps) {
|
|
67
|
-
const { runtime, makeStagingDir, run, exists, rename, remove, log } = deps;
|
|
65
|
+
const { runtime, makeStagingDir, run, exists, rename, remove, log, isEngine = () => true, linkEngine } = deps;
|
|
68
66
|
const staging = makeStagingDir();
|
|
69
67
|
log(`Installing the Codie engine (${runtime.spec}). This runs once, and only for \`codie\`.`);
|
|
70
68
|
let result;
|
|
@@ -79,56 +77,141 @@ function installCodieRuntime(deps) {
|
|
|
79
77
|
remove(staging);
|
|
80
78
|
throw installFailure(result.stderr?.trim() || `npm exited with ${result.status}`);
|
|
81
79
|
}
|
|
82
|
-
// Trust the artifact, not the exit code — a misconfigured mirror can succeed
|
|
83
|
-
// with nothing useful in the tarball.
|
|
84
80
|
const stagedBinary = path.join(staging, "node_modules", "opencode-ai", "bin", "opencode.exe");
|
|
85
81
|
if (!exists(stagedBinary)) {
|
|
86
82
|
remove(staging);
|
|
87
83
|
throw new Error(`The Codie engine install did not produce a runtime binary. ` +
|
|
88
84
|
`Check that ${runtime.spec} is available from your npm registry.`);
|
|
89
85
|
}
|
|
86
|
+
if (!isEngine(stagedBinary)) {
|
|
87
|
+
let linked = { ok: false };
|
|
88
|
+
try {
|
|
89
|
+
linked = linkEngine?.(path.dirname(path.dirname(stagedBinary))) ?? { ok: false };
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
linked = { ok: false, detail: error instanceof Error ? error.message : String(error) };
|
|
93
|
+
}
|
|
94
|
+
if (!linked.ok || !isEngine(stagedBinary)) {
|
|
95
|
+
if (linked.detail === exports.IGNORE_SCRIPTS) {
|
|
96
|
+
try {
|
|
97
|
+
rename(staging, runtime.installDir);
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
remove(staging);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
remove(staging);
|
|
105
|
+
}
|
|
106
|
+
throw new Error(linkFailure(linked, path.join(runtime.installDir, "node_modules", "opencode-ai")));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
90
109
|
try {
|
|
91
110
|
rename(staging, runtime.installDir);
|
|
92
111
|
}
|
|
93
112
|
finally {
|
|
94
|
-
// No-op after a successful promote (rmSync is force: true); after a failed
|
|
95
|
-
// one it keeps a ~132MB staging dir from being orphaned — mkdtemp mints a
|
|
96
|
-
// fresh sibling every attempt, so leaks would accumulate.
|
|
97
113
|
remove(staging);
|
|
98
114
|
}
|
|
99
115
|
}
|
|
100
|
-
|
|
101
|
-
async function ensureCodieRuntimeBinary({ resolve, install, confirmUpdate = async () => false, }) {
|
|
116
|
+
async function ensureCodieRuntimeBinary({ resolve, install, confirmUpdate = async () => false, repair, }) {
|
|
102
117
|
const runtime = resolve();
|
|
103
118
|
if (runtime.kind === "ready")
|
|
104
119
|
return runtime.binary;
|
|
105
|
-
if (runtime.kind === "outdated" && !(await confirmUpdate(runtime)))
|
|
120
|
+
if (runtime.kind === "outdated" && !(await confirmUpdate(runtime))) {
|
|
121
|
+
if (runtime.linked !== false || !repair || !runtime.packageDir)
|
|
122
|
+
return runtime.binary;
|
|
123
|
+
if (repair({ kind: "unlinked", installDir: runtime.installDir, binary: runtime.binary, spec: runtime.spec, packageDir: runtime.packageDir })) {
|
|
124
|
+
return runtime.binary;
|
|
125
|
+
}
|
|
126
|
+
install(runtime);
|
|
106
127
|
return runtime.binary;
|
|
128
|
+
}
|
|
129
|
+
if (runtime.kind === "unlinked" && repair?.(runtime)) {
|
|
130
|
+
const after = resolve();
|
|
131
|
+
if (after.kind === "ready")
|
|
132
|
+
return after.binary;
|
|
133
|
+
}
|
|
107
134
|
install(runtime);
|
|
108
135
|
return runtime.binary;
|
|
109
136
|
}
|
|
137
|
+
function linkFailure(linked, packageDir) {
|
|
138
|
+
if (linked.detail === exports.IGNORE_SCRIPTS) {
|
|
139
|
+
const script = packageDir ? `"${path.join(packageDir, "postinstall.mjs")}"` : "postinstall.mjs in the opencode-ai package";
|
|
140
|
+
return (`The Codie engine installed, but npm is set to ignore install scripts (ignore-scripts=true), ` +
|
|
141
|
+
`so codie won't run opencode-ai's setup step. Run \`node ${script}\` yourself, ` +
|
|
142
|
+
`or set CODIEDEV_OPENCODE_BINARY to an opencode binary.`);
|
|
143
|
+
}
|
|
144
|
+
return (`The Codie engine installed, but its setup step (opencode-ai's postinstall) failed, so there is no runnable engine` +
|
|
145
|
+
(linked.detail ? `: ${linked.detail}` : ".") +
|
|
146
|
+
` Set CODIEDEV_OPENCODE_BINARY to an opencode binary to use a pre-provisioned engine.`);
|
|
147
|
+
}
|
|
148
|
+
exports.IGNORE_SCRIPTS = "ignore-scripts";
|
|
110
149
|
function installFailure(detail) {
|
|
111
150
|
return new Error(`Could not download the Codie engine: ${detail}\n` +
|
|
112
151
|
`If you are behind a proxy or an internal registry, make sure npm can reach it. ` +
|
|
113
152
|
`To use a pre-provisioned engine instead, set CODIEDEV_OPENCODE_BINARY to its path.`);
|
|
114
153
|
}
|
|
115
|
-
|
|
116
|
-
|
|
154
|
+
function windowsCommand(command, args) {
|
|
155
|
+
const quote = (a) => (/[\s"&|<>^()%!]/.test(a) ? `"${a.replace(/"/g, '""')}"` : a);
|
|
156
|
+
return [command, ...args.map(quote)].join(" ");
|
|
157
|
+
}
|
|
158
|
+
function isEngineOnDisk(candidate) {
|
|
159
|
+
try {
|
|
160
|
+
return (0, codieRuntime_1.isEngineSize)(fs.statSync(candidate).size);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
function npmIgnoresScripts(env = process.env) {
|
|
167
|
+
const fromEnv = env.npm_config_ignore_scripts ?? env.NPM_CONFIG_IGNORE_SCRIPTS;
|
|
168
|
+
if (fromEnv !== undefined)
|
|
169
|
+
return !["", "false", "0", "null", "no"].includes(fromEnv.trim().toLowerCase());
|
|
170
|
+
const opts = { encoding: "utf8", timeout: 10_000, windowsHide: true };
|
|
171
|
+
const result = process.platform === "win32"
|
|
172
|
+
? (0, child_process_1.spawnSync)("npm.cmd config get ignore-scripts", { ...opts, shell: true })
|
|
173
|
+
: (0, child_process_1.spawnSync)("npm", ["config", "get", "ignore-scripts"], opts);
|
|
174
|
+
return result.status === 0 && (result.stdout || "").trim() === "true";
|
|
175
|
+
}
|
|
176
|
+
const LINK_TIMEOUT_MS = 120_000;
|
|
177
|
+
function linkEngineOnDisk(packageDir, { ignoreScripts = npmIgnoresScripts } = {}) {
|
|
178
|
+
const script = path.join(packageDir, "postinstall.mjs");
|
|
179
|
+
if (!fs.existsSync(script))
|
|
180
|
+
return { ok: false, detail: "opencode-ai has no postinstall.mjs" };
|
|
181
|
+
if (ignoreScripts())
|
|
182
|
+
return { ok: false, detail: exports.IGNORE_SCRIPTS };
|
|
183
|
+
const result = (0, child_process_1.spawnSync)(process.execPath, [script], {
|
|
184
|
+
cwd: packageDir,
|
|
185
|
+
encoding: "utf8",
|
|
186
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
187
|
+
timeout: LINK_TIMEOUT_MS,
|
|
188
|
+
windowsHide: true,
|
|
189
|
+
});
|
|
190
|
+
if (result.error || result.signal) {
|
|
191
|
+
return { ok: false, detail: result.error ? result.error.message : `timed out after ${LINK_TIMEOUT_MS / 1000}s` };
|
|
192
|
+
}
|
|
193
|
+
if (result.status !== 0)
|
|
194
|
+
return { ok: false, detail: (result.stderr || "").trim().split("\n").slice(-3).join(" ") || `exit ${result.status}` };
|
|
195
|
+
return isEngineOnDisk(path.join(packageDir, "bin", "opencode.exe"))
|
|
196
|
+
? { ok: true }
|
|
197
|
+
: { ok: false, detail: "postinstall ran but left no engine" };
|
|
198
|
+
}
|
|
117
199
|
function installCodieRuntimeOnDisk(runtime, stateDir) {
|
|
118
200
|
installCodieRuntime({
|
|
119
201
|
runtime,
|
|
120
202
|
makeStagingDir: () => {
|
|
121
|
-
// Sibling of the final dir so the promote is a same-filesystem rename.
|
|
122
203
|
fs.mkdirSync(path.dirname((0, codieRuntime_1.codieRuntimeDir)(stateDir)), { recursive: true });
|
|
123
204
|
return fs.mkdtempSync(path.join(path.dirname((0, codieRuntime_1.codieRuntimeDir)(stateDir)), ".runtime-staging-"));
|
|
124
205
|
},
|
|
125
206
|
run: (args) => {
|
|
126
|
-
const
|
|
127
|
-
const result = (0, child_process_1.spawnSync)(npm, args, {
|
|
207
|
+
const opts = {
|
|
128
208
|
encoding: "utf8",
|
|
129
209
|
stdio: ["ignore", "inherit", "pipe"],
|
|
130
210
|
env: { ...process.env, npm_config_yes: "true" },
|
|
131
|
-
}
|
|
211
|
+
};
|
|
212
|
+
const result = process.platform === "win32"
|
|
213
|
+
? (0, child_process_1.spawnSync)(windowsCommand("npm.cmd", args), { ...opts, shell: true, windowsHide: true })
|
|
214
|
+
: (0, child_process_1.spawnSync)("npm", args, opts);
|
|
132
215
|
if (result.error)
|
|
133
216
|
throw result.error;
|
|
134
217
|
return { status: result.status, stderr: result.stderr || "" };
|
|
@@ -140,6 +223,8 @@ function installCodieRuntimeOnDisk(runtime, stateDir) {
|
|
|
140
223
|
},
|
|
141
224
|
remove: (target) => fs.rmSync(target, { recursive: true, force: true }),
|
|
142
225
|
log: (message) => console.error(message),
|
|
226
|
+
isEngine: isEngineOnDisk,
|
|
227
|
+
linkEngine: linkEngineOnDisk,
|
|
143
228
|
});
|
|
144
229
|
}
|
|
145
230
|
function defaultStagingRoot() {
|