gaslamp 2.1.0 → 2.1.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gaslamp",
3
- "version": "2.1.0",
3
+ "version": "2.1.2",
4
4
  "description": "Let Claude Code and Codex consult each other from the shell.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/consult.mjs CHANGED
@@ -33,7 +33,7 @@
33
33
  // (one-hop) refusal · 4 network-disabled sandbox · 5 session busy
34
34
 
35
35
  import { spawn } from "node:child_process";
36
- import { createWriteStream, existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
36
+ import { createWriteStream, existsSync, mkdirSync, readFileSync, realpathSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
37
37
  import { homedir } from "node:os";
38
38
  import { join } from "node:path";
39
39
  import { which } from "./which.mjs";
@@ -87,8 +87,16 @@ function resolveBin(backend) {
87
87
  if (existsSync(c)) return c;
88
88
  return which("claude") || "claude";
89
89
  }
90
- if (process.env.CODEX_BIN && existsSync(process.env.CODEX_BIN)) return process.env.CODEX_BIN;
91
- return which("codex") || "codex";
90
+ // codex looks for its helper binaries (codex-code-mode-host) as SIBLINGS of
91
+ // the path it was invoked as, without resolving symlinks. The standalone
92
+ // package's ~/.local/bin/codex is a bare symlink, so spawning it kills the
93
+ // consulted agent's whole execution bridge ("failed to spawn code-mode
94
+ // host…"): it can neither read nor write. Spawn the real binary instead.
95
+ const found = process.env.CODEX_BIN && existsSync(process.env.CODEX_BIN)
96
+ ? process.env.CODEX_BIN
97
+ : which("codex");
98
+ if (!found) return "codex";
99
+ try { return realpathSync(found); } catch { return found; }
92
100
  }
93
101
 
94
102
  function parseArgs(argv) {
@@ -378,7 +386,11 @@ export function runConsult(backend, argv) {
378
386
  costUsd: j.total_cost_usd ?? null,
379
387
  };
380
388
  } else if (backend === "codex" && j.type === "turn.completed" && j.usage) {
381
- usageAcc.input += (j.usage.input_tokens ?? 0) + (j.usage.cached_input_tokens ?? 0);
389
+ // OpenAI semantics differ from Anthropic's: input_tokens already
390
+ // INCLUDES the cached portion (cached_input_tokens is a subset, and
391
+ // codex's own total_tokens = input + output), so adding it again
392
+ // double-counts cache hits.
393
+ usageAcc.input += j.usage.input_tokens ?? 0;
382
394
  usageAcc.output += j.usage.output_tokens ?? 0;
383
395
  meta.usage = { inputTokens: usageAcc.input, outputTokens: usageAcc.output, costUsd: null };
384
396
  } else if (backend === "codex" && j.type === "item.completed") {
package/src/setup.mjs CHANGED
@@ -89,6 +89,32 @@ The \`--json\` envelope then carries \`data\` (the parsed object). A reply that
89
89
 
90
90
  Fleets default to \`--sandbox read-only\` (N writers in one cwd race) — pass \`--sandbox\` to opt into writes. Duplicate resume/thread targets are refused up front.
91
91
 
92
+ ## Picking a model
93
+
94
+ Both ladders, strongest first: fable ≈ astra > opus ≈ sol > terra > sonnet ≈ luna > haiku.
95
+
96
+ ${other === "codex"
97
+ ? `Codex tiers — pass the full id to \`--model\` (bare tier names are rejected):
98
+
99
+ | tier | \`--model\` | ≈ claude | reach for it when |
100
+ |------|-----------|----------|-------------------|
101
+ | astra | \`gpt-6-astra\` | fable | the hardest reasoning: adversarial verification, design spars, proofs |
102
+ | sol | \`gpt-5.6-sol\` | opus | substantial work: reviews, diagnosis, real implementation |
103
+ | terra | \`gpt-5.6-terra\` | (between opus and sonnet) | everyday work: routine reviews, well-scoped changes |
104
+ | luna | \`gpt-5.6-luna\` | sonnet | quick checks, mechanical transforms, high-N fleets |`
105
+ : `Claude tiers — \`--model\` takes the bare alias:
106
+
107
+ | \`--model\` | ≈ codex | reach for it when |
108
+ |-----------|---------|-------------------|
109
+ | \`fable\` | astra | the hardest reasoning: adversarial verification, design spars, proofs |
110
+ | \`opus\` | sol | substantial work: reviews, diagnosis, real implementation |
111
+ | \`sonnet\` | luna | quick checks, mechanical transforms, high-N fleets |
112
+ | \`haiku\` | (below luna) | pings, one-word sanity checks, the cheapest fan-outs |`}
113
+
114
+ Omit \`--model\` to use ${Other}'s own configured default. Match the tier to the stakes: verification you'll rely on deserves the top tier; a fleet vote usually doesn't.
115
+
116
+ \`--effort\` takes \`low\` / \`medium\` / \`high\` / \`xhigh\` / \`max\`${other === "codex" ? "; astra, sol and terra also take `ultra` (max reasoning plus automatic task delegation). Omitted = Codex's configured `model_reasoning_effort`, else the model's own default — sol's is `low`, so pass it explicitly when the consult matters." : ". Omitted = Claude's own default."}
117
+
92
118
  ## Reading the records
93
119
 
94
120
  gaslamp jobs [--json] # recent consults: status, label, thread, tokens