codiedev 0.9.80 → 0.10.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. package/README.md +12 -5
  2. package/dist/backup/cache.js +1 -5
  3. package/dist/backup/match.js +0 -6
  4. package/dist/backup/run.js +3 -35
  5. package/dist/captureExclusions.js +0 -12
  6. package/dist/captureLog.js +0 -28
  7. package/dist/captureReadiness.js +0 -58
  8. package/dist/captureSignals.js +0 -11
  9. package/dist/cli.js +11 -33
  10. package/dist/cliSession.js +3 -60
  11. package/dist/codexHookTrust.js +0 -28
  12. package/dist/codexLimitScan.js +0 -107
  13. package/dist/codie.js +64 -57
  14. package/dist/codieBrandInstall.js +0 -18
  15. package/dist/codieLauncher.js +1 -72
  16. package/dist/codieRuntime.js +27 -32
  17. package/dist/codieRuntimeInstall.js +11 -43
  18. package/dist/codieUsage.js +0 -49
  19. package/dist/commands/agentTemplates.generated.js +136 -0
  20. package/dist/commands/agents.js +1088 -0
  21. package/dist/commands/agentsSdk.generated.js +7 -0
  22. package/dist/commands/ask.js +0 -3
  23. package/dist/commands/capture.js +0 -2
  24. package/dist/commands/createTicket.js +0 -10
  25. package/dist/commands/doctor.js +2 -72
  26. package/dist/commands/evals.js +3 -9
  27. package/dist/commands/inbox.js +0 -2
  28. package/dist/commands/library.js +0 -3
  29. package/dist/commands/pack.js +0 -29
  30. package/dist/commands/ping.js +0 -2
  31. package/dist/commands/pull.js +0 -9
  32. package/dist/commands/push.js +0 -12
  33. package/dist/commands/search.js +0 -4
  34. package/dist/commands/send.js +0 -5
  35. package/dist/commands/share.js +0 -4
  36. package/dist/commands/shared.js +0 -35
  37. package/dist/commands/traces.js +0 -13
  38. package/dist/commands/tracesLabel.js +0 -8
  39. package/dist/configDir.js +1 -18
  40. package/dist/connect.js +3 -75
  41. package/dist/connectFlow.js +0 -15
  42. package/dist/copilotHooks.js +0 -67
  43. package/dist/copilotInstallation.js +0 -1
  44. package/dist/cursorHooks.js +1 -11
  45. package/dist/cursorLifecycle.js +1 -7
  46. package/dist/detection.js +0 -30
  47. package/dist/harnessDirs.js +0 -19
  48. package/dist/hook.js +43 -293
  49. package/dist/inboxFormat.js +0 -24
  50. package/dist/launchContext.js +0 -50
  51. package/dist/launcher.js +0 -33
  52. package/dist/limitEvent.js +2 -34
  53. package/dist/managedPi.js +2 -50
  54. package/dist/mcp.js +0 -48
  55. package/dist/nativeSteering.js +1 -4
  56. package/dist/packs/codie.js +0 -15
  57. package/dist/packs/harnesses.js +1 -38
  58. package/dist/packs/hookGate.js +0 -33
  59. package/dist/packs/install.js +0 -20
  60. package/dist/packs/manifest.js +1 -15
  61. package/dist/packs/paths.js +0 -8
  62. package/dist/packs/shim.js +0 -8
  63. package/dist/packs/store.js +0 -12
  64. package/dist/packs/sync.js +0 -20
  65. package/dist/piHooks.js +4 -45
  66. package/dist/piRuntime.js +0 -18
  67. package/dist/repoResolver.js +0 -19
  68. package/dist/secret.js +0 -3
  69. package/dist/selfUpdate.js +2 -77
  70. package/dist/skillMarker.js +0 -14
  71. package/dist/subagents.js +0 -18
  72. package/dist/teamSkillContext.js +0 -1
  73. package/dist/transcriptModels.js +0 -8
  74. package/dist/upgradeNudge.js +1 -30
  75. package/dist/utils.js +165 -768
  76. package/dist/version.js +0 -10
  77. package/dist/versionCheck.js +0 -33
  78. package/package.json +13 -8
  79. package/dist/backup/cache.d.ts +0 -14
  80. package/dist/backup/match.d.ts +0 -2
  81. package/dist/backup/run.d.ts +0 -25
  82. package/dist/captureExclusions.d.ts +0 -30
  83. package/dist/captureLog.d.ts +0 -20
  84. package/dist/captureReadiness.d.ts +0 -65
  85. package/dist/captureSignals.d.ts +0 -47
  86. package/dist/cli.d.ts +0 -15
  87. package/dist/cliSession.d.ts +0 -108
  88. package/dist/codexHookTrust.d.ts +0 -49
  89. package/dist/codexLimitScan.d.ts +0 -64
  90. package/dist/codie.d.ts +0 -2
  91. package/dist/codieBrandInstall.d.ts +0 -11
  92. package/dist/codieLauncher.d.ts +0 -87
  93. package/dist/codieRuntime.d.ts +0 -35
  94. package/dist/codieRuntimeInstall.d.ts +0 -56
  95. package/dist/codieUsage.d.ts +0 -64
  96. package/dist/commands/ask.d.ts +0 -1
  97. package/dist/commands/capture.d.ts +0 -14
  98. package/dist/commands/createTicket.d.ts +0 -27
  99. package/dist/commands/delete.d.ts +0 -1
  100. package/dist/commands/doctor.d.ts +0 -9
  101. package/dist/commands/evals.d.ts +0 -3
  102. package/dist/commands/inbox.d.ts +0 -3
  103. package/dist/commands/library.d.ts +0 -2
  104. package/dist/commands/note.d.ts +0 -1
  105. package/dist/commands/pack.d.ts +0 -54
  106. package/dist/commands/ping.d.ts +0 -1
  107. package/dist/commands/pull.d.ts +0 -2
  108. package/dist/commands/push.d.ts +0 -33
  109. package/dist/commands/search.d.ts +0 -2
  110. package/dist/commands/send.d.ts +0 -2
  111. package/dist/commands/share.d.ts +0 -2
  112. package/dist/commands/shared.d.ts +0 -64
  113. package/dist/commands/traces.d.ts +0 -72
  114. package/dist/commands/tracesLabel.d.ts +0 -24
  115. package/dist/configDir.d.ts +0 -10
  116. package/dist/connect.d.ts +0 -1
  117. package/dist/connectFlow.d.ts +0 -34
  118. package/dist/copilotHooks.d.ts +0 -85
  119. package/dist/copilotInstallation.d.ts +0 -10
  120. package/dist/cursorHooks.d.ts +0 -13
  121. package/dist/cursorLifecycle.d.ts +0 -2
  122. package/dist/detection.d.ts +0 -30
  123. package/dist/harnessDirs.d.ts +0 -15
  124. package/dist/hook.d.ts +0 -6
  125. package/dist/inboxFormat.d.ts +0 -38
  126. package/dist/launchContext.d.ts +0 -46
  127. package/dist/launcher.d.ts +0 -25
  128. package/dist/limitEvent.d.ts +0 -15
  129. package/dist/limitEventReporter.d.ts +0 -21
  130. package/dist/managedPi.d.ts +0 -48
  131. package/dist/mcp.d.ts +0 -12
  132. package/dist/nativeSteering.d.ts +0 -5
  133. package/dist/packs/codie.d.ts +0 -45
  134. package/dist/packs/harnesses.d.ts +0 -74
  135. package/dist/packs/hookGate.d.ts +0 -53
  136. package/dist/packs/install.d.ts +0 -46
  137. package/dist/packs/manifest.d.ts +0 -52
  138. package/dist/packs/paths.d.ts +0 -17
  139. package/dist/packs/shim.d.ts +0 -26
  140. package/dist/packs/store.d.ts +0 -42
  141. package/dist/packs/sync.d.ts +0 -40
  142. package/dist/piHooks.d.ts +0 -22
  143. package/dist/piRuntime.d.ts +0 -26
  144. package/dist/repoResolver.d.ts +0 -17
  145. package/dist/secret.d.ts +0 -1
  146. package/dist/selfUpdate.d.ts +0 -64
  147. package/dist/skillMarker.d.ts +0 -6
  148. package/dist/subagents.d.ts +0 -36
  149. package/dist/teamSkillContext.d.ts +0 -9
  150. package/dist/transcriptModels.d.ts +0 -20
  151. package/dist/upgradeNudge.d.ts +0 -24
  152. package/dist/utils.d.ts +0 -396
  153. package/dist/version.d.ts +0 -1
  154. 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);
@@ -60,12 +50,7 @@ const codie_1 = require("./packs/codie");
60
50
  const paths_1 = require("./packs/paths");
61
51
  const managedPi_1 = require("./managedPi");
62
52
  const cliSession_1 = require("./cliSession");
63
- // The engine reads its gateway key once, at launch. With browser sign-in the
64
- // key is a 24h access token, so start every session with at least 12h left
65
- // (refreshing first if needed) instead of one that dies mid-task.
66
53
  const CODIE_MIN_TOKEN_VALIDITY_MS = 12 * 60 * 60_000;
67
- // How long to let the gateway finish booking the last request before asking
68
- // what the session cost.
69
54
  const USAGE_SETTLE_MS = 1200;
70
55
  function git(args) {
71
56
  const result = (0, child_process_1.spawnSync)("git", args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
@@ -95,9 +80,6 @@ function existingInlineConfig() {
95
80
  throw new Error("OPENCODE_CONFIG_CONTENT is not valid JSON");
96
81
  }
97
82
  }
98
- // The one credential. `codiedev connect` wrote it; the gateway validates the
99
- // same userApiTokens row (a browser sign-in reports through its own row), so
100
- // there is no second harness token to mint.
101
83
  function connectedCodiedevConfig() {
102
84
  try {
103
85
  return JSON.parse(fs.readFileSync(path.join((0, configDir_1.codiedevStateDir)(), "config.json"), "utf8"));
@@ -106,12 +88,8 @@ function connectedCodiedevConfig() {
106
88
  return {};
107
89
  }
108
90
  }
109
- // Starter packs (`codiedev pack install`) reach Codie here: skills, agents and
110
- // the hook shim are merged into the inline config at launch. Best-effort — a
111
- // broken pack must never stop the harness from starting.
112
91
  function withStarterPacks(existing, approved, catalog) {
113
92
  try {
114
- // Agent levels (opus/sonnet/haiku) resolve against this account's catalog.
115
93
  const packs = (0, codie_1.codiePackConfig)((0, paths_1.packsRoot)(), { approvedModels: approved, catalog });
116
94
  if (process.env.CODIEDEV_DEBUG) {
117
95
  for (const note of packs.notes)
@@ -125,13 +103,8 @@ function withStarterPacks(existing, approved, catalog) {
125
103
  }
126
104
  }
127
105
  function assetPath(name) {
128
- // dist/codie.js → ../assets/<name>; src/codie.ts → ../assets/<name>.
129
106
  return path.join(__dirname, "..", "assets", name);
130
107
  }
131
- // Remove the engine's boot/exit banner wordmark in place (see
132
- // patchBrandWordmark). Best-effort like the TUI plugin: any failure rolls the
133
- // bytes back and the stock banner keeps working. Runs once per install; an
134
- // already-suppressed binary has no known source region and is skipped.
135
108
  function installBrandWordmark(runtime) {
136
109
  try {
137
110
  installBrandWordmarkUnsafe(runtime);
@@ -145,10 +118,6 @@ function installBrandWordmarkUnsafe(runtime) {
145
118
  const { changed, offset, replacement } = (0, codieLauncher_1.patchBrandWordmark)(binary);
146
119
  if (!changed || !replacement)
147
120
  return;
148
- // In-place write (not copy+rename): opencode-ai/bin/opencode.exe and the
149
- // platform package's binary are hardlinks to one inode, and this keeps them
150
- // consistent. Restoring the original bytes is a true rollback — identical
151
- // content revalidates the existing macOS signature.
152
121
  const writeAt = (bytes) => {
153
122
  const fd = fs.openSync(runtime, "r+");
154
123
  try {
@@ -161,7 +130,6 @@ function installBrandWordmarkUnsafe(runtime) {
161
130
  const restore = () => writeAt(binary.subarray(offset, offset + replacement.length));
162
131
  writeAt(replacement);
163
132
  if (process.platform === "darwin") {
164
- // A modified Mach-O needs a fresh ad-hoc signature or the OS kills it.
165
133
  const signed = (0, child_process_1.spawnSync)("codesign", ["--force", "--sign", "-", runtime], { stdio: "ignore" });
166
134
  if (signed.status !== 0) {
167
135
  restore();
@@ -175,6 +143,49 @@ function installBrandWordmarkUnsafe(runtime) {
175
143
  (0, child_process_1.spawnSync)("codesign", ["--force", "--sign", "-", runtime], { stdio: "ignore" });
176
144
  }
177
145
  }
146
+ async function runNonInteractive(runtime, runtimeArgs, env) {
147
+ const detached = process.platform !== "win32";
148
+ const child = (0, child_process_1.spawn)(runtime, runtimeArgs, {
149
+ stdio: ["pipe", "pipe", "pipe"],
150
+ env,
151
+ detached,
152
+ });
153
+ if (child.stdin)
154
+ process.stdin.pipe(child.stdin);
155
+ const signalChild = (signal) => {
156
+ if (detached && child.pid) {
157
+ try {
158
+ process.kill(-child.pid, signal);
159
+ return;
160
+ }
161
+ catch {
162
+ }
163
+ }
164
+ child.kill(signal);
165
+ };
166
+ const forwardInterrupt = () => signalChild("SIGINT");
167
+ const forwardTermination = () => signalChild("SIGTERM");
168
+ process.once("SIGINT", forwardInterrupt);
169
+ process.once("SIGTERM", forwardTermination);
170
+ return await new Promise((resolve, reject) => {
171
+ child.stdout?.on("data", (chunk) => process.stdout.write(chunk));
172
+ child.stderr?.on("data", (chunk) => process.stderr.write(chunk));
173
+ child.once("error", (error) => {
174
+ if (child.stdin)
175
+ process.stdin.unpipe(child.stdin);
176
+ process.removeListener("SIGINT", forwardInterrupt);
177
+ process.removeListener("SIGTERM", forwardTermination);
178
+ reject(error);
179
+ });
180
+ child.once("close", (status) => {
181
+ if (child.stdin)
182
+ process.stdin.unpipe(child.stdin);
183
+ process.removeListener("SIGINT", forwardInterrupt);
184
+ process.removeListener("SIGTERM", forwardTermination);
185
+ resolve(status);
186
+ });
187
+ });
188
+ }
178
189
  async function main() {
179
190
  (0, codieRuntime_1.assertCodieNodeVersion)(process.versions.node);
180
191
  if (!process.env.CODIEDEV_GATEWAY_KEY && !process.env.CODIEDEV_TOKEN) {
@@ -184,9 +195,6 @@ async function main() {
184
195
  }
185
196
  }
186
197
  const connected = connectedCodiedevConfig();
187
- // Browser sign-in: let the engine's per-request hook keep the 24h key
188
- // fresh for sessions that run longer (assets/session-key.mjs). Not for an
189
- // explicit key from the environment, and not for pasted API tokens.
190
198
  if (!process.env.CODIEDEV_GATEWAY_KEY && !process.env.CODIEDEV_TOKEN && connected.auth) {
191
199
  process.env.CODIEDEV_SESSION_CONFIG = path.join((0, configDir_1.codiedevStateDir)(), "config.json");
192
200
  process.env.CODIEDEV_CLI_JS = path.join(__dirname, "cli.js");
@@ -198,9 +206,6 @@ async function main() {
198
206
  if (!key) {
199
207
  throw new Error("Connect your Codiedev account first with `codiedev connect`");
200
208
  }
201
- // Before anything paints: once the OpenCode engine owns stdio, a prompt is
202
- // unreadable. A successful in-place upgrade relaunches this command with the
203
- // new package, so the stale process must stop here.
204
209
  const update = await (0, upgradeNudge_1.maybeOfferUpgrade)();
205
210
  if (update.relaunched) {
206
211
  process.exitCode = update.status ?? 0;
@@ -208,8 +213,6 @@ async function main() {
208
213
  }
209
214
  const gatewayUrl = process.env.CODIEDEV_GATEWAY_URL || "https://gateway.codiedev.com/api/v1";
210
215
  const catalog = await (0, codieLauncher_1.fetchApprovedCatalog)({ baseUrl: gatewayUrl, key });
211
- // `codie --pi [args]`: pi instead of the OpenCode engine, on the same
212
- // approved catalog and gateway key (see managedPi.ts).
213
216
  if (process.argv[2] === "--pi") {
214
217
  let skillPaths = [];
215
218
  try {
@@ -222,8 +225,6 @@ async function main() {
222
225
  try {
223
226
  process.exitCode = (0, managedPi_1.runManagedPi)({
224
227
  args: process.argv.slice(3), key, gatewayUrl, catalog, stateDir: (0, configDir_1.codiedevStateDir)(), skillPaths,
225
- // This release line has no Agent Security hooks.
226
- agentSecurityEnabled: false,
227
228
  });
228
229
  }
229
230
  catch (error) {
@@ -240,11 +241,20 @@ async function main() {
240
241
  }
241
242
  (0, codieLauncher_1.validateCodieArgs)(parsed.args, catalog);
242
243
  const stateDir = (0, configDir_1.codiedevStateDir)();
243
- const runtime = (0, codieRuntimeInstall_1.ensureCodieRuntimeBinary)({
244
+ const runtime = await (0, codieRuntimeInstall_1.ensureCodieRuntimeBinary)({
244
245
  resolve: () => (0, codieRuntime_1.resolveCodieRuntime)({
245
246
  env: process.env,
246
247
  stateDir,
247
248
  existsSync: (candidate) => fs.existsSync(candidate),
249
+ readInstalledVersion: (candidate) => {
250
+ try {
251
+ const value = JSON.parse(fs.readFileSync(candidate, "utf8"));
252
+ return typeof value.version === "string" ? value.version : null;
253
+ }
254
+ catch {
255
+ return null;
256
+ }
257
+ },
248
258
  resolveBundled: () => {
249
259
  try {
250
260
  return require.resolve("opencode-ai/bin/opencode.exe");
@@ -257,18 +267,24 @@ async function main() {
257
267
  }),
258
268
  install: (missing) => (0, codieRuntimeInstall_1.installCodieRuntimeOnDisk)(missing, stateDir),
259
269
  repair: (unlinked) => {
260
- // npm 12 skips dependency install scripts; codie runs opencode-ai's own
261
- // link step instead (not when npm is explicitly set to ignore scripts).
262
270
  console.error("codie: finishing the engine setup npm skipped (opencode-ai's postinstall)…");
263
271
  const linked = (0, codieRuntimeInstall_1.linkEngineOnDisk)(unlinked.packageDir);
264
- // npm set to ignore scripts: a reinstall would hit the same wall, so stop
265
- // with the one clear step instead of downloading again every run.
266
272
  if (!linked.ok && linked.detail === codieRuntimeInstall_1.IGNORE_SCRIPTS)
267
273
  throw new Error((0, codieRuntimeInstall_1.linkFailure)(linked, unlinked.packageDir));
268
274
  if (!linked.ok)
269
275
  console.error(`codie: ${(0, codieRuntimeInstall_1.linkFailure)(linked, unlinked.packageDir)} Reinstalling the engine.`);
270
276
  return linked.ok;
271
277
  },
278
+ confirmUpdate: async (outdated) => {
279
+ console.error("");
280
+ console.error(`Codie harness ${outdated.expectedVersion} is available (you're on ${outdated.currentVersion}).`);
281
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
282
+ console.error("Restart `codie` in an interactive terminal to update the harness.");
283
+ console.error("");
284
+ return false;
285
+ }
286
+ return await (0, upgradeNudge_1.promptYesNo)(" Update the harness now? [y/N] ");
287
+ },
272
288
  });
273
289
  const metadataPlugin = (0, url_1.pathToFileURL)(assetPath("opencode-plugin.mjs")).href;
274
290
  const capturePlugin = (0, codieLauncher_1.resolveCapturePlugin)({ homeDir: os.homedir(), existsSync: fs.existsSync });
@@ -292,10 +308,6 @@ async function main() {
292
308
  const runtimeArgs = (0, codieLauncher_1.withCodieWorkingDirectory)(parsed.args, process.cwd());
293
309
  const nonInteractiveRun = runtimeArgs[0] === "run";
294
310
  if (nonInteractiveRun) {
295
- // The TUI paints its own live status line from the same endpoint. A
296
- // non-interactive run has no TUI, so the budget arrives as two printed
297
- // lines instead — and only for a human at a terminal, so a scripted run
298
- // is neither slowed nor polluted.
299
311
  const reportCost = Boolean(process.stderr.isTTY);
300
312
  const startedAt = Date.now();
301
313
  if (reportCost) {
@@ -303,13 +315,8 @@ async function main() {
303
315
  if (line)
304
316
  console.error(line);
305
317
  }
306
- const result = (0, child_process_1.spawnSync)(runtime, runtimeArgs, { stdio: "inherit", env });
307
- if (result.error)
308
- throw result.error;
309
- process.exitCode = result.status === null ? 1 : result.status;
318
+ process.exitCode = (await runNonInteractive(runtime, runtimeArgs, env)) ?? 1;
310
319
  if (reportCost) {
311
- // The gateway books a request's cost after it has answered, so a poll
312
- // fired the instant the run closes can miss the last one.
313
320
  await new Promise((resolve) => setTimeout(resolve, USAGE_SETTLE_MS));
314
321
  const cost = (0, codieUsage_1.formatSessionCostLine)(await (0, codieUsage_1.fetchCodieUsage)({ baseUrl: gatewayUrl, key, sinceMs: startedAt }));
315
322
  if (cost)
@@ -1,13 +1,4 @@
1
1
  "use strict";
2
- // Stages the Codiedev TUI plugin into the engine's config directory.
3
- //
4
- // TUI plugins load only from tui.json in the OpenCode config dir, so the
5
- // packaged template is copied there and referenced by a relative spec. The
6
- // copy also carries the status line, which needs an absolute path back into
7
- // this package — the plugin sits outside it and cannot reach it any other way.
8
- //
9
- // Every step is best-effort: a developer who cannot write this directory still
10
- // gets a working harness, just the stock logo and no status line.
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);
@@ -50,15 +41,8 @@ const os = __importStar(require("os"));
50
41
  const path = __importStar(require("path"));
51
42
  const codieLauncher_1 = require("./codieLauncher");
52
43
  function assetPath(name) {
53
- // dist/codieBrandInstall.js → ../assets/<name>; src/… → ../assets/<name>.
54
44
  return path.join(__dirname, "..", "assets", name);
55
45
  }
56
- /**
57
- * The usage module this install should load. The shipped package has the
58
- * compiled file; a source checkout (and the test run) has the TypeScript one.
59
- * Naming a path that does not exist would cost the status line silently, so a
60
- * miss raises instead and the caller falls back to the plain plugin.
61
- */
62
46
  function usageModulePath() {
63
47
  const candidates = [
64
48
  path.join(__dirname, "codieUsage.js"),
@@ -69,8 +53,6 @@ function usageModulePath() {
69
53
  throw new Error("this install has no Codiedev usage module");
70
54
  return found;
71
55
  }
72
- /** The engine resolves its config dir per the XDG spec, so a customized
73
- * XDG_CONFIG_HOME must be honored or tui.json lands where it never reads. */
74
56
  function openCodeConfigDir() {
75
57
  return path.join(process.env.XDG_CONFIG_HOME?.trim() || path.join(os.homedir(), ".config"), "opencode");
76
58
  }
@@ -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);
@@ -59,6 +50,7 @@ const path = __importStar(require("path"));
59
50
  const url_1 = require("url");
60
51
  const harnessDirs_1 = require("./harnessDirs");
61
52
  const DEFAULT_NAMES = {
53
+ "openai/gpt-5.6-luna": "GPT-5.6 Luna",
62
54
  "openai/gpt-5.3-codex": "GPT-5.3 Codex",
63
55
  "openai/gpt-5.2-codex": "GPT-5.2 Codex",
64
56
  "openai/gpt-5.1-codex-mini": "GPT-5.1 Codex Mini",
@@ -66,9 +58,6 @@ const DEFAULT_NAMES = {
66
58
  "z-ai/glm-5.2": "GLM 5.2 · Fireworks ZDR",
67
59
  "moonshotai/kimi-k2.7-code": "Kimi K2.7 Code · Fireworks ZDR",
68
60
  };
69
- /** A rate card is usable only when both sides are real, finite and not
70
- * negative. Half a card prices a session wrong in a way nobody can see, so a
71
- * partial one is dropped and the model stays unpriced. */
72
61
  function usableModelCost(value) {
73
62
  if (!value || typeof value !== "object")
74
63
  return undefined;
@@ -81,10 +70,6 @@ function usableModelCost(value) {
81
70
  return undefined;
82
71
  return { input, output };
83
72
  }
84
- /** A context/output window is usable only when both sides are real, finite and
85
- * positive. A partial window makes the engine's "% of context used" read wrong
86
- * in a way nobody can see, so a partial one is dropped and the model keeps the
87
- * engine's default. */
88
73
  function usableModelLimit(value) {
89
74
  if (!value || typeof value !== "object")
90
75
  return undefined;
@@ -97,12 +82,6 @@ function usableModelLimit(value) {
97
82
  return undefined;
98
83
  return { context, output };
99
84
  }
100
- /**
101
- * Pin non-interactive runs to the directory where `codie` was launched.
102
- * OpenCode can reuse a previously-known project instance; without an explicit
103
- * --dir, a real smoke run launched in a throwaway repo resumed the caller's
104
- * main checkout and executed there. TUI mode already owns its cwd directly.
105
- */
106
85
  function withCodieWorkingDirectory(args, cwd) {
107
86
  if (args[0] !== "run")
108
87
  return args;
@@ -124,8 +103,6 @@ function governedModel(value, approved, fallback, label) {
124
103
  return `codiedev/${model}`;
125
104
  }
126
105
  function economicalModel(catalog, primary) {
127
- // Catalog ids arrive already normalized through bareModel(), so the
128
- // gateway's `codiedev/fast` alias appears here as plain "fast".
129
106
  const preferred = ["openai/gpt-5.1-codex-mini", "fast", "z-ai/glm-5.2"];
130
107
  return preferred.find((id) => catalog.some((model) => model.id === id)) || primary;
131
108
  }
@@ -157,11 +134,6 @@ function buildCodieConfig({ existing = {}, catalog, env = {}, plugin, plugins =
157
134
  const existingPlugins = Array.isArray(existing.plugin) ? existing.plugin : [];
158
135
  const requiredPlugins = [...plugins, plugin].filter(Boolean);
159
136
  const models = Object.fromEntries(catalog.map((model) => {
160
- // The engine prices a session from this rate card. Without it every
161
- // model reads $0.00, which is how the harness came to show no spend at
162
- // all. The gateway publishes prompt and completion prices only, so
163
- // cached tokens are priced at zero here and the engine's session figure
164
- // stays an estimate — the budget line from /me/usage is the true spend.
165
137
  const cost = usableModelCost(model.cost);
166
138
  const limit = usableModelLimit(model.limit);
167
139
  return [
@@ -201,14 +173,6 @@ function buildCodieConfig({ existing = {}, catalog, env = {}, plugin, plugins =
201
173
  };
202
174
  }
203
175
  exports.USAGE_MODULE_PLACEHOLDER = "__CODIEDEV_USAGE_MODULE__";
204
- /**
205
- * Point the staged TUI plugin at this install's usage module.
206
- *
207
- * The plugin is copied into the engine's own config directory, so it cannot
208
- * reach the package by a relative path — the absolute path is baked in at
209
- * stage time. It goes in as a JSON literal so a Windows path keeps its
210
- * backslashes instead of turning into escape sequences.
211
- */
212
176
  function stageUsageModule(source, modulePath) {
213
177
  if (!source.includes(exports.USAGE_MODULE_PLACEHOLDER)) {
214
178
  throw new Error(`plugin template is missing the ${exports.USAGE_MODULE_PLACEHOLDER} placeholder`);
@@ -216,8 +180,6 @@ function stageUsageModule(source, modulePath) {
216
180
  return source.split(exports.USAGE_MODULE_PLACEHOLDER).join(JSON.stringify(modulePath));
217
181
  }
218
182
  exports.BRAND_PLUGIN_SPEC = "./plugins/codiedev-brand.tsx";
219
- // Pure merge for ~/.config/opencode/tui.json: TUI plugins load from tui.json,
220
- // not the opencode.json we inject via OPENCODE_CONFIG_CONTENT.
221
183
  function withBrandPlugin(existing) {
222
184
  const config = existing && typeof existing === "object" && !Array.isArray(existing) ? existing : {};
223
185
  const plugins = Array.isArray(config.plugin) ? config.plugin : [];
@@ -226,13 +188,6 @@ function withBrandPlugin(existing) {
226
188
  return { config, changed: false };
227
189
  return { config: { ...config, plugin: [...plugins, exports.BRAND_PLUGIN_SPEC] }, changed: true };
228
190
  }
229
- // ── Engine wordmark suppression ─────────────────────────────────────────
230
- // The OpenCode engine prints a block-letter "opencode" wordmark to terminal
231
- // scrollback around each session (the boot/exit banner). A four-row terminal
232
- // raster cannot reproduce the real Codiedev wordmark cleanly, so leave that
233
- // surface blank and keep the proper brand mark on the plugin-driven home
234
- // screen. The bundled JS table is replaced byte-for-byte so binary offsets do
235
- // not move.
236
191
  function escapeJsSource(row) {
237
192
  let out = "";
238
193
  for (const ch of row) {
@@ -245,7 +200,6 @@ function wordmarkRegion(left, right, { escapeUnicode = true } = {}) {
245
200
  const rows = (list) => list.map((row) => `"${escapeUnicode ? escapeJsSource(row) : row}"`).join(",");
246
201
  return `var vn={left:[${rows(left)}],right:[${rows(right)}]};`;
247
202
  }
248
- // o p e n | c o d e — must match the engine's bundle byte-for-byte.
249
203
  exports.STOCK_WORDMARK = wordmarkRegion([
250
204
  " ",
251
205
  "█▀▀█ █▀▀█ █▀▀█ █▀▀▄",
@@ -257,12 +211,6 @@ exports.STOCK_WORDMARK = wordmarkRegion([
257
211
  "█___ █__█ █__█ █^^^",
258
212
  "▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀",
259
213
  ]);
260
- // c o d i | e d e v, rasterized from public/codiedevlogo.svg at eight vertical
261
- // pixels and packed into four terminal rows with half-block characters. This
262
- // preserves the real mark's round lowercase bowls, linked c/o, ascenders, and
263
- // compact v instead of approximating the letters with OpenCode's square font.
264
- // The engine inserts one column between left and right, so the blank source
265
- // column at the codi/edev boundary is intentionally omitted.
266
214
  const CODIE_LEFT = [
267
215
  " ▄ ▄",
268
216
  " ▄▄█▄▄ ▄▄█▄▄ ▄████ █",
@@ -275,9 +223,6 @@ const CODIE_RIGHT = [
275
223
  "██▀▀█ █ █ ██▄▀█ ▀█▄█ ",
276
224
  "▀▀█▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀▀ ",
277
225
  ];
278
- // Migration source for the first hand-drawn banner shipped during development.
279
- // Recognizing it lets an existing install upgrade in place instead of keeping
280
- // the old square letterforms until OpenCode happens to reinstall its binary.
281
226
  const LEGACY_CODIE_LEFT = [
282
227
  " ▄ ▄ ",
283
228
  "█▀▀▀ █▀▀█ █▀▀█ █ ",
@@ -299,9 +244,6 @@ exports.LEGACY_CODIEDEV_WORDMARK = (() => {
299
244
  return wordmarkRegion(LEGACY_CODIE_LEFT, padded);
300
245
  })();
301
246
  exports.CODIEDEV_WORDMARK = (() => {
302
- // Raw Unicode is valid JavaScript and costs fewer source bytes than \uXXXX.
303
- // Put the remaining byte padding outside the strings so it cannot widen the
304
- // rendered banner or shift its centering.
305
247
  const unpadded = wordmarkRegion(CODIE_LEFT, CODIE_RIGHT, { escapeUnicode: false });
306
248
  const deficit = Buffer.byteLength(exports.STOCK_WORDMARK) - Buffer.byteLength(unpadded);
307
249
  if (deficit < 0)
@@ -323,9 +265,6 @@ exports.HIDDEN_WORDMARK = (() => {
323
265
  }
324
266
  return region;
325
267
  })();
326
- // Pure: locate the stock or an earlier Codiedev wordmark in an engine binary.
327
- // Refuses to touch the file unless exactly one known region appears; an
328
- // already-hidden or reshaped upstream bundle is left alone.
329
268
  function patchBrandWordmark(binary) {
330
269
  const stock = Buffer.from(exports.STOCK_WORDMARK);
331
270
  const candidates = [stock, Buffer.from(exports.LEGACY_CODIEDEV_WORDMARK), Buffer.from(exports.CODIEDEV_WORDMARK)];
@@ -349,15 +288,8 @@ function resolveCapturePlugin({ homeDir, existsSync, }) {
349
288
  }
350
289
  return (0, url_1.pathToFileURL)(capturePath).href;
351
290
  }
352
- // A definite answer from the gateway (harness off, token rejected): retrying
353
- // can't change it.
354
291
  class CatalogRejected extends Error {
355
292
  }
356
- /**
357
- * The account's approved models. Every `codie` session starts here, so one
358
- * dropped connection or slow gateway reply would end the session before it
359
- * began; anything but a definite rejection is retried once.
360
- */
361
293
  async function fetchApprovedCatalog({ baseUrl, key, fetchImpl = fetch, retryDelayMs = 1_000, }) {
362
294
  try {
363
295
  return await fetchCatalogOnce(baseUrl, key, fetchImpl);
@@ -377,9 +309,6 @@ async function fetchCatalogOnce(baseUrl, key, fetchImpl) {
377
309
  headers: { Authorization: `Bearer ${key}` },
378
310
  signal: controller.signal,
379
311
  });
380
- // The `codie` bin ships to every connected machine, including companies
381
- // whose gateway is still switched off. Those developers must get an
382
- // answer, not an HTTP status.
383
312
  if (response.status === 403) {
384
313
  throw new CatalogRejected("The Codie harness is not enabled for your company yet. Ask your Codiedev admin to turn it on — " +
385
314
  "your session capture keeps working in the meantime.");
@@ -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,19 +33,15 @@ var __importStar = (this && this.__importStar) || (function () {
43
33
  };
44
34
  })();
45
35
  Object.defineProperty(exports, "__esModule", { value: true });
46
- exports.ENGINE_MIN_BYTES = exports.CODIE_MIN_NODE_MAJOR = 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;
48
38
  exports.isEngineSize = isEngineSize;
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
- // The harness needs 20; capture does not. package.json `engines` stays >=18 so
57
- // `codiedev connect` still installs for Node 18 users — this floor is enforced
58
- // at `codie` launch instead.
44
+ exports.OPENCODE_RUNTIME_VERSION = exports.OPENCODE_RUNTIME_SPEC.slice(exports.OPENCODE_RUNTIME_SPEC.lastIndexOf("@") + 1);
59
45
  exports.CODIE_MIN_NODE_MAJOR = 20;
60
46
  function codieRuntimeDir(stateDir) {
61
47
  return path.join(stateDir, "runtime");
@@ -63,21 +49,14 @@ function codieRuntimeDir(stateDir) {
63
49
  function installedBinary(stateDir) {
64
50
  return path.join(codieRuntimeDir(stateDir), "node_modules", "opencode-ai", "bin", "opencode.exe");
65
51
  }
66
- /**
67
- * The real engine is a ~132MB native executable. opencode-ai ships
68
- * bin/opencode.exe as a ~500-byte shell script that only prints "postinstall
69
- * was not run" until its postinstall swaps the binary in; anything this small
70
- * is that placeholder, not an engine. Pure.
71
- */
72
52
  exports.ENGINE_MIN_BYTES = 1_000_000;
73
53
  function isEngineSize(bytes) {
74
54
  return bytes >= exports.ENGINE_MIN_BYTES;
75
55
  }
76
- function installedPackageDir(stateDir) {
77
- return path.join(codieRuntimeDir(stateDir), "node_modules", "opencode-ai");
56
+ function installedRuntimePackageJson(stateDir) {
57
+ return path.join(codieRuntimeDir(stateDir), "node_modules", "opencode-ai", "package.json");
78
58
  }
79
- function resolveCodieRuntime({ env, stateDir, existsSync, resolveBundled, isEngine = () => true, }) {
80
- // 1. Explicit override — the air-gapped / pre-provisioned escape hatch.
59
+ function resolveCodieRuntime({ env, stateDir, existsSync, readInstalledVersion, resolveBundled, isEngine = () => true, }) {
81
60
  const override = env.CODIEDEV_OPENCODE_BINARY?.trim();
82
61
  if (override) {
83
62
  if (!existsSync(override)) {
@@ -85,16 +64,32 @@ function resolveCodieRuntime({ env, stateDir, existsSync, resolveBundled, isEngi
85
64
  }
86
65
  return { kind: "ready", binary: override };
87
66
  }
88
- // 2. A bundled engine, if this package was installed with one (dev checkout,
89
- // or a future vendored distribution).
90
67
  const bundled = resolveBundled();
91
68
  if (bundled && isEngine(bundled))
92
69
  return { kind: "ready", binary: bundled };
93
- // 3. The lazily installed engine.
94
70
  const binary = installedBinary(stateDir);
95
71
  if (existsSync(binary)) {
96
- if (!isEngine(binary)) {
97
- return { kind: "unlinked", installDir: codieRuntimeDir(stateDir), binary, spec: exports.OPENCODE_RUNTIME_SPEC, packageDir: installedPackageDir(stateDir) };
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
+ }
82
+ if (currentVersion && currentVersion !== exports.OPENCODE_RUNTIME_VERSION) {
83
+ return {
84
+ kind: "outdated",
85
+ installDir: codieRuntimeDir(stateDir),
86
+ binary,
87
+ spec: exports.OPENCODE_RUNTIME_SPEC,
88
+ currentVersion,
89
+ expectedVersion: exports.OPENCODE_RUNTIME_VERSION,
90
+ linked: isEngine(binary),
91
+ packageDir: path.dirname(installedRuntimePackageJson(stateDir)),
92
+ };
98
93
  }
99
94
  return { kind: "ready", binary };
100
95
  }