jeo-code 0.9.8 → 0.9.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.
- package/CHANGELOG.md +21 -0
- package/README.ja.md +2 -2
- package/README.ko.md +2 -2
- package/README.md +2 -2
- package/README.zh.md +2 -2
- package/package.json +1 -1
- package/src/commands/launch/tmux.ts +11 -0
- package/src/commands/launch.ts +9 -7
- package/src/commands/update.ts +61 -32
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,27 @@ The README mirrors the latest 5 entries — regenerate with `bun run changelog:s
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.9.10] - 2026-07-27
|
|
12
|
+
_`jeo update` now verifies the binary you actually run, and recovers from bun's stale registry cache._
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
- **`jeo update` claimed success while the machine still ran the old build** (`src/commands/update.ts`) — a package manager's zero exit was treated as proof of an update. In practice bun can fail to resolve a just-published version (`No version matching "x.y.z" ... (but package exists)`) from a stale manifest, jeo then fell back to npm, npm installed into a prefix the user's PATH does not resolve, and the command printed `Successfully installed` while `jeo --version` still reported the previous release. The install now retries bun with `--force` (which re-resolves against the registry) before falling back to npm, stops only once the binary on PATH reports the requested version, and reports a stale active binary as a failure (exit 1, `installed: false` in `--json`) with the exact recovery commands.
|
|
16
|
+
|
|
17
|
+
### Verified
|
|
18
|
+
- Update suite: 33 pass / 0 fail, including the new stale-active-binary failure, its `--json` shape, and the bun `--force` retry ordering.
|
|
19
|
+
- Reproduced live: `bun install -g jeo-code@0.9.9` resolved nothing from cache while `--force` installed it correctly.
|
|
20
|
+
|
|
21
|
+
## [0.9.9] - 2026-07-27
|
|
22
|
+
_Root-causes the frozen `jeo --tmux` TUI: the window was pinned to its launch size, so resizing the terminal only cut the view._
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- **`jeo --tmux` no longer freezes the window at its launch geometry** (`src/commands/launch.ts`, `src/commands/launch/tmux.ts`) — the pre-attach `tmux resize-window` flipped the window's `window-size` option to `manual` as a documented side effect, permanently detaching it from the attached client. Resizing the terminal then left the tmux window frozen: the pane was shown cut/letterboxed and jeo never received SIGWINCH, so no amount of in-app reflow could help. The redundant `resize-window` is gone (`new-session -x/-y` already sizes the detached window), and every jeo-owned session now explicitly asserts `window-size latest`, which also protects users whose `tmux.conf` sets `manual` globally.
|
|
26
|
+
|
|
27
|
+
### Verified
|
|
28
|
+
- Live tmux 3.6a: attached client 100x30 → window 100x29, 140x40 → 140x39, 72x20 → 72x19, with the TUI reflowing at each step.
|
|
29
|
+
- Control run reproducing the old behaviour: with `window-size manual` the window stayed 80x24 under a 120x36 client (the reported truncation); restoring `latest` recovered instantly.
|
|
30
|
+
- tmux suite: 18 pass / 0 fail, including new assertions that the launch flow never issues `resize-window` and always sets `window-size latest`.
|
|
31
|
+
|
|
11
32
|
## [0.9.8] - 2026-07-27
|
|
12
33
|
_The provider model list now persists and rehydrates, so an account's live models survive across launches (gjc parity)._
|
|
13
34
|
|
package/README.ja.md
CHANGED
|
@@ -285,10 +285,10 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
|
|
|
285
285
|
|
|
286
286
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
287
287
|
- **[Unreleased]**
|
|
288
|
+
- **[0.9.10]** (2026-07-27) — `jeo update` now verifies the binary you actually run, and recovers from bun's stale registry cache.
|
|
289
|
+
- **[0.9.9]** (2026-07-27) — Root-causes the frozen `jeo --tmux` TUI: the window was pinned to its launch size, so resizing the terminal only cut the view.
|
|
288
290
|
- **[0.9.8]** (2026-07-27) — The provider model list now persists and rehydrates, so an account's live models survive across launches (gjc parity).
|
|
289
291
|
- **[0.9.7]** (2026-07-27) — Fixes the broken 0.9.3-0.9.6 npm releases: `jeo` and `jeo --tmux` crashed at startup right after `jeo update`.
|
|
290
|
-
- **[0.9.6]** (2026-07-27) — Resize-safe ledger flush and terminal clear handling after viewport shrink.
|
|
291
|
-
- **[0.9.5]** (2026-07-27) — Resize-safe live TUI rendering for terminal viewport shrink/grow transitions.
|
|
292
292
|
|
|
293
293
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
294
294
|
<!-- CHANGELOG:END -->
|
package/README.ko.md
CHANGED
|
@@ -286,10 +286,10 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
|
|
|
286
286
|
|
|
287
287
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
288
288
|
- **[Unreleased]**
|
|
289
|
+
- **[0.9.10]** (2026-07-27) — `jeo update` now verifies the binary you actually run, and recovers from bun's stale registry cache.
|
|
290
|
+
- **[0.9.9]** (2026-07-27) — Root-causes the frozen `jeo --tmux` TUI: the window was pinned to its launch size, so resizing the terminal only cut the view.
|
|
289
291
|
- **[0.9.8]** (2026-07-27) — The provider model list now persists and rehydrates, so an account's live models survive across launches (gjc parity).
|
|
290
292
|
- **[0.9.7]** (2026-07-27) — Fixes the broken 0.9.3-0.9.6 npm releases: `jeo` and `jeo --tmux` crashed at startup right after `jeo update`.
|
|
291
|
-
- **[0.9.6]** (2026-07-27) — Resize-safe ledger flush and terminal clear handling after viewport shrink.
|
|
292
|
-
- **[0.9.5]** (2026-07-27) — Resize-safe live TUI rendering for terminal viewport shrink/grow transitions.
|
|
293
293
|
|
|
294
294
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
295
295
|
<!-- CHANGELOG:END -->
|
package/README.md
CHANGED
|
@@ -293,10 +293,10 @@ Huge thanks to [gajae-code](https://github.com/Yeachan-Heo/gajae-code) for the i
|
|
|
293
293
|
|
|
294
294
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
295
295
|
- **[Unreleased]**
|
|
296
|
+
- **[0.9.10]** (2026-07-27) — `jeo update` now verifies the binary you actually run, and recovers from bun's stale registry cache.
|
|
297
|
+
- **[0.9.9]** (2026-07-27) — Root-causes the frozen `jeo --tmux` TUI: the window was pinned to its launch size, so resizing the terminal only cut the view.
|
|
296
298
|
- **[0.9.8]** (2026-07-27) — The provider model list now persists and rehydrates, so an account's live models survive across launches (gjc parity).
|
|
297
299
|
- **[0.9.7]** (2026-07-27) — Fixes the broken 0.9.3-0.9.6 npm releases: `jeo` and `jeo --tmux` crashed at startup right after `jeo update`.
|
|
298
|
-
- **[0.9.6]** (2026-07-27) — Resize-safe ledger flush and terminal clear handling after viewport shrink.
|
|
299
|
-
- **[0.9.5]** (2026-07-27) — Resize-safe live TUI rendering for terminal viewport shrink/grow transitions.
|
|
300
300
|
|
|
301
301
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
302
302
|
<!-- CHANGELOG:END -->
|
package/README.zh.md
CHANGED
|
@@ -285,10 +285,10 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
|
|
|
285
285
|
|
|
286
286
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
287
287
|
- **[Unreleased]**
|
|
288
|
+
- **[0.9.10]** (2026-07-27) — `jeo update` now verifies the binary you actually run, and recovers from bun's stale registry cache.
|
|
289
|
+
- **[0.9.9]** (2026-07-27) — Root-causes the frozen `jeo --tmux` TUI: the window was pinned to its launch size, so resizing the terminal only cut the view.
|
|
288
290
|
- **[0.9.8]** (2026-07-27) — The provider model list now persists and rehydrates, so an account's live models survive across launches (gjc parity).
|
|
289
291
|
- **[0.9.7]** (2026-07-27) — Fixes the broken 0.9.3-0.9.6 npm releases: `jeo` and `jeo --tmux` crashed at startup right after `jeo update`.
|
|
290
|
-
- **[0.9.6]** (2026-07-27) — Resize-safe ledger flush and terminal clear handling after viewport shrink.
|
|
291
|
-
- **[0.9.5]** (2026-07-27) — Resize-safe live TUI rendering for terminal viewport shrink/grow transitions.
|
|
292
292
|
|
|
293
293
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
294
294
|
<!-- CHANGELOG:END -->
|
package/package.json
CHANGED
|
@@ -193,6 +193,17 @@ export function tmuxProfileCommands(
|
|
|
193
193
|
): TmuxProfileCommand[] {
|
|
194
194
|
const t = `=${target}:`;
|
|
195
195
|
const commands: TmuxProfileCommand[] = [];
|
|
196
|
+
// Follow the attached client's geometry, always. tmux's default is already
|
|
197
|
+
// `latest`, but ANY `resize-window` (jeo's own, a user keybinding, a wrapper
|
|
198
|
+
// script) silently flips the window to `manual`, and a user's tmux.conf may set
|
|
199
|
+
// `manual` globally. A manual window never resizes with the terminal: jeo's pane
|
|
200
|
+
// stays frozen at its launch size, gets shown letterboxed/cut, and jeo never sees
|
|
201
|
+
// SIGWINCH so it cannot reflow either. Asserting `latest` per jeo session makes
|
|
202
|
+
// the live TUI track every terminal resize.
|
|
203
|
+
commands.push({
|
|
204
|
+
description: "track the attached client's size (never freeze the window)",
|
|
205
|
+
args: ["set-window-option", "-t", t, "window-size", "latest"],
|
|
206
|
+
});
|
|
196
207
|
if (env.JEO_TMUX_MOUSE !== "0") {
|
|
197
208
|
commands.push({
|
|
198
209
|
description: "enable tmux mouse scrolling (wheel-up → copy-mode over real history)",
|
package/src/commands/launch.ts
CHANGED
|
@@ -491,13 +491,15 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
|
|
|
491
491
|
: `Starting new independent tmux session: ${sessionName} (another live jeo session already owns ${sessionBase}; reattach later with: tmux attach -t ${sessionName})`,
|
|
492
492
|
);
|
|
493
493
|
|
|
494
|
-
//
|
|
495
|
-
//
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
494
|
+
// NOTE: never `tmux resize-window` here. tmux flips the window's `window-size`
|
|
495
|
+
// option to `manual` as a side effect of that command, which permanently
|
|
496
|
+
// detaches the window from the attached client's geometry — the terminal is
|
|
497
|
+
// resized, tmux keeps the window frozen at its old size, and the pane is shown
|
|
498
|
+
// letterboxed/cut with jeo never receiving SIGWINCH (the "TUI is stuck at the
|
|
499
|
+
// launch size and the screen is cut" report). `new-session -x/-y` already
|
|
500
|
+
// creates the detached window at the caller's size, and `window-size latest`
|
|
501
|
+
// (asserted in tmuxProfileCommands) makes the attach and every later terminal
|
|
502
|
+
// resize track the client automatically.
|
|
501
503
|
|
|
502
504
|
const attach = Bun.spawn([tmuxBin, "attach-session", "-t", `=${sessionName}`], {
|
|
503
505
|
stdin: "inherit",
|
package/src/commands/update.ts
CHANGED
|
@@ -43,6 +43,36 @@ export interface UpdateDeps {
|
|
|
43
43
|
activeVersion?: () => string | null;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Ordered install attempts for `target` (`jeo-code@<version>`).
|
|
48
|
+
*
|
|
49
|
+
* `bun install -g` alone is not enough in practice: right after a publish bun can
|
|
50
|
+
* still hold a stale registry manifest and fail with `No version matching "<v>"
|
|
51
|
+
* found ... (but package exists)`. `--force` re-resolves against the registry and
|
|
52
|
+
* is what actually recovers that state. npm remains the last resort for
|
|
53
|
+
* npm-installed globals. Pure so the policy is unit-testable without spawning.
|
|
54
|
+
*/
|
|
55
|
+
export function installCandidates(target: string): string[][] {
|
|
56
|
+
return [
|
|
57
|
+
["bun", "install", "-g", target],
|
|
58
|
+
// Cache-buster: bun's resolver held a stale manifest for a just-published version.
|
|
59
|
+
["bun", "install", "-g", target, "--force"],
|
|
60
|
+
["npm", "install", "-g", target],
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Version of the `jeo` binary PATH actually resolves, or null when unreadable. */
|
|
65
|
+
function readActiveVersion(): string | null {
|
|
66
|
+
try {
|
|
67
|
+
const proc = Bun.spawnSync(["jeo", "--version"], { stdout: "pipe", stderr: "pipe" });
|
|
68
|
+
if (!proc.success) return null;
|
|
69
|
+
const out = new TextDecoder().decode(proc.stdout);
|
|
70
|
+
const m = out.match(/(\d+\.\d+\.\d+(?:-[\w.]+)?)/);
|
|
71
|
+
return m ? m[1] : null;
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
46
76
|
export const defaultDeps: UpdateDeps = {
|
|
47
77
|
fetchJson: async (url: string, options?: { signal?: AbortSignal }) => {
|
|
48
78
|
const res = await fetch(url, options);
|
|
@@ -65,17 +95,20 @@ export const defaultDeps: UpdateDeps = {
|
|
|
65
95
|
// Self-update the global install via the SAME toolchain it was installed with. jeo
|
|
66
96
|
// ships as a `#!/usr/bin/env bun` script so bun is the common case, but npm-installed
|
|
67
97
|
// globals exist too — try bun first, fall back to npm (and tolerate either missing).
|
|
68
|
-
// `@<version>` (the resolved latest) forces the newest publish past a stale global cache.
|
|
69
98
|
const target = `jeo-code@${version ?? "latest"}`;
|
|
70
|
-
const managers: string[][] = [
|
|
71
|
-
["bun", "install", "-g", target],
|
|
72
|
-
["npm", "install", "-g", target],
|
|
73
|
-
];
|
|
74
99
|
let lastErr = "";
|
|
75
|
-
for (const cmd of
|
|
100
|
+
for (const cmd of installCandidates(target)) {
|
|
76
101
|
try {
|
|
77
102
|
const proc = Bun.spawnSync(cmd, { stdout: "inherit", stderr: "inherit" });
|
|
78
|
-
if (proc.success)
|
|
103
|
+
if (proc.success) {
|
|
104
|
+
// A zero exit is NOT proof the user's `jeo` moved: npm's global prefix is
|
|
105
|
+
// often a different directory than the bun prefix PATH actually resolves,
|
|
106
|
+
// so an npm fallback can "succeed" while the active binary is untouched.
|
|
107
|
+
// Only stop once the binary on PATH really reports the requested version.
|
|
108
|
+
if (!version || readActiveVersion() === version) return { success: true };
|
|
109
|
+
lastErr = `${cmd[0]} reported success but the active 'jeo' is still ${readActiveVersion() ?? "unknown"}`;
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
79
112
|
lastErr = `${cmd[0]} exited with code ${proc.exitCode}`;
|
|
80
113
|
} catch (err: any) {
|
|
81
114
|
lastErr = `${cmd[0]} unavailable: ${err?.message ?? String(err)}`;
|
|
@@ -84,20 +117,10 @@ export const defaultDeps: UpdateDeps = {
|
|
|
84
117
|
return { success: false, stderr: lastErr };
|
|
85
118
|
}
|
|
86
119
|
,
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
try {
|
|
92
|
-
const proc = Bun.spawnSync(["jeo", "--version"], { stdout: "pipe", stderr: "pipe" });
|
|
93
|
-
if (!proc.success) return null;
|
|
94
|
-
const out = new TextDecoder().decode(proc.stdout);
|
|
95
|
-
const m = out.match(/(\d+\.\d+\.\d+(?:-[\w.]+)?)/);
|
|
96
|
-
return m ? m[1] : null;
|
|
97
|
-
} catch {
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
120
|
+
// Version of the `jeo` actually on PATH — may differ from this process's bundled
|
|
121
|
+
// version after a self-update (e.g. npm installed into a prefix PATH does not
|
|
122
|
+
// resolve). Detects the silent "installed but PATH unchanged" no-op.
|
|
123
|
+
activeVersion: readActiveVersion
|
|
101
124
|
,
|
|
102
125
|
showWhatsNew: () => {
|
|
103
126
|
try {
|
|
@@ -279,25 +302,31 @@ export async function runUpdateCommandWith(args: string[], deps: UpdateDeps): Pr
|
|
|
279
302
|
try {
|
|
280
303
|
const result = await deps.install(latest ?? undefined);
|
|
281
304
|
if (result.success) {
|
|
305
|
+
// A package manager's zero exit does not prove the user's `jeo` moved: npm's
|
|
306
|
+
// global prefix is frequently a different directory than the one PATH resolves,
|
|
307
|
+
// so the install lands somewhere the user never runs. Verify the ACTIVE binary
|
|
308
|
+
// and treat a still-stale one as a failed update (exit 1) rather than printing
|
|
309
|
+
// a success line the machine contradicts.
|
|
310
|
+
const active = deps.activeVersion?.();
|
|
311
|
+
const stale = !!(active && latest && compareVersions(active, latest) < 0);
|
|
282
312
|
if (hasJson) {
|
|
283
313
|
console.log(JSON.stringify({
|
|
284
314
|
current,
|
|
285
315
|
latest,
|
|
286
316
|
upToDate: false,
|
|
287
|
-
installed:
|
|
317
|
+
installed: !stale,
|
|
318
|
+
...(stale ? { activeVersion: active, error: "active jeo still reports an older version" } : {}),
|
|
288
319
|
}));
|
|
320
|
+
if (stale) process.exitCode = 1;
|
|
321
|
+
} else if (stale) {
|
|
322
|
+
console.error(`[FAILED] Installed jeo-code@${latest}, but the active 'jeo' on PATH still reports ${active}.`);
|
|
323
|
+
console.error(`The install landed in a prefix your PATH does not use. Fix it with one of:`);
|
|
324
|
+
console.error(` bun install -g jeo-code@${latest} --force`);
|
|
325
|
+
console.error(` npm install -g jeo-code@${latest}`);
|
|
326
|
+
console.error(`Then confirm with: jeo --version`);
|
|
327
|
+
process.exitCode = 1;
|
|
289
328
|
} else {
|
|
290
329
|
console.log(`Successfully installed jeo-code@${latest}`);
|
|
291
|
-
// Verify the `jeo` on PATH actually picked up the new install — a bun-vs-npm or
|
|
292
|
-
// PATH mismatch can leave an older binary in front, which looks like "update did
|
|
293
|
-
// nothing". Surface that loudly with the manual fix instead of failing silently.
|
|
294
|
-
const active = deps.activeVersion?.();
|
|
295
|
-
if (active && latest && compareVersions(active, latest) < 0) {
|
|
296
|
-
console.warn(`Warning: installed ${latest}, but the active 'jeo' on PATH still reports ${active}.`);
|
|
297
|
-
console.warn(`Your PATH points at a different install. Fix it with one of:`);
|
|
298
|
-
console.warn(` npm install -g jeo-code@${latest}`);
|
|
299
|
-
console.warn(` bun install -g jeo-code@${latest}`);
|
|
300
|
-
}
|
|
301
330
|
deps.showWhatsNew?.();
|
|
302
331
|
}
|
|
303
332
|
} else {
|