jeo-code 0.5.14 → 0.5.16
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 +13 -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/cli/runner.ts +1 -1
- package/src/commands/launch.ts +23 -30
- package/src/commands/update.ts +20 -9
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
The README mirrors the latest 5 entries — regenerate with `bun run changelog:sync`.
|
|
8
8
|
|
|
9
|
+
## [0.5.16] - 2026-06-16
|
|
10
|
+
_`/resume` and Ctrl+O no longer corrupt the TUI — clean screen restore + scrollback expand._
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **`/resume` corrupted the screen on a TTY.** After picking a session the resumed transcript was dumped on top of whatever was on screen (picker remnants, the prior conversation, the live input frame), so replayed ANSI/forge boxes from the old session collided with the live layout. Resume now wipes the screen + scrollback and re-renders the welcome banner BEFORE replaying the transcript — the same proven path `/clear` uses — so the restored view is a single, intact screen (verified live: one input box, one status bar, no picker remnants).
|
|
14
|
+
- **Ctrl+O at the prompt crammed the last response into the ~10-row footer**, clipping long/CJK content with "… N more line(s)" and risking a garbled box. Ctrl+O now expands the full last assistant response into scrollback (clean `disarm → print → re-arm` path), so it is fully scrollable and the input box + typed draft restore without corruption. Removed the now-dead footer history-panel machinery (`promptHistoryLines`, `historyPreviewLines`).
|
|
15
|
+
|
|
16
|
+
## [0.5.15] - 2026-06-16
|
|
17
|
+
_`jeo update` now actually upgrades — bare command installs the latest release instead of just printing a manual command._
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
- `jeo update` (bare) now performs the upgrade itself: when a newer release exists it runs the install (`bun install -g jeo-code@<latest>`, pinned to the resolved latest version so a stale global cache can't win) instead of printing "Run 'bun install -g jeo-code' to upgrade" and leaving the user to do it. `--check` is the new check-only mode; `--json` stays check-only for programmatic status (add `--install` to install in JSON mode); `--install` still forces an install. The check-only hint now points at `jeo update` itself.
|
|
21
|
+
|
|
9
22
|
## [0.5.14] - 2026-06-16
|
|
10
23
|
_`jeo --tmux` live-verification harness — repeatable stability + behavior checks._
|
|
11
24
|
|
package/README.ja.md
CHANGED
|
@@ -150,11 +150,11 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
|
|
|
150
150
|
## 変更履歴 (Changelog)
|
|
151
151
|
|
|
152
152
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
153
|
+
- **[0.5.16]** (2026-06-16) — `/resume` and Ctrl+O no longer corrupt the TUI — clean screen restore + scrollback expand.
|
|
154
|
+
- **[0.5.15]** (2026-06-16) — `jeo update` now actually upgrades — bare command installs the latest release instead of just printing a manual command.
|
|
153
155
|
- **[0.5.14]** (2026-06-16) — `jeo --tmux` live-verification harness — repeatable stability + behavior checks.
|
|
154
156
|
- **[0.5.13]** (2026-06-15) — Workflow `/` commands actually run — `/deep-interview`, `/team`, `/ultragoal`, `/ralplan` dispatch by name.
|
|
155
157
|
- **[0.5.12]** (2026-06-15) — Yellow status animation while a process runs, and elapsed `(Nms)` on every completed tool card.
|
|
156
|
-
- **[0.5.11]** (2026-06-15) — Backspace on an empty prompt line no longer quits jeo.
|
|
157
|
-
- **[0.5.10]** (2026-06-15) — `/resume` transcript no longer dumps raw JSON for batched tool calls.
|
|
158
158
|
|
|
159
159
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
160
160
|
<!-- CHANGELOG:END -->
|
package/README.ko.md
CHANGED
|
@@ -150,11 +150,11 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
|
|
|
150
150
|
## 변경 이력 (Changelog)
|
|
151
151
|
|
|
152
152
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
153
|
+
- **[0.5.16]** (2026-06-16) — `/resume` and Ctrl+O no longer corrupt the TUI — clean screen restore + scrollback expand.
|
|
154
|
+
- **[0.5.15]** (2026-06-16) — `jeo update` now actually upgrades — bare command installs the latest release instead of just printing a manual command.
|
|
153
155
|
- **[0.5.14]** (2026-06-16) — `jeo --tmux` live-verification harness — repeatable stability + behavior checks.
|
|
154
156
|
- **[0.5.13]** (2026-06-15) — Workflow `/` commands actually run — `/deep-interview`, `/team`, `/ultragoal`, `/ralplan` dispatch by name.
|
|
155
157
|
- **[0.5.12]** (2026-06-15) — Yellow status animation while a process runs, and elapsed `(Nms)` on every completed tool card.
|
|
156
|
-
- **[0.5.11]** (2026-06-15) — Backspace on an empty prompt line no longer quits jeo.
|
|
157
|
-
- **[0.5.10]** (2026-06-15) — `/resume` transcript no longer dumps raw JSON for batched tool calls.
|
|
158
158
|
|
|
159
159
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
160
160
|
<!-- CHANGELOG:END -->
|
package/README.md
CHANGED
|
@@ -150,11 +150,11 @@ Required npm token permissions (repository secret `NPM_TOKEN`):
|
|
|
150
150
|
## Changelog
|
|
151
151
|
|
|
152
152
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
153
|
+
- **[0.5.16]** (2026-06-16) — `/resume` and Ctrl+O no longer corrupt the TUI — clean screen restore + scrollback expand.
|
|
154
|
+
- **[0.5.15]** (2026-06-16) — `jeo update` now actually upgrades — bare command installs the latest release instead of just printing a manual command.
|
|
153
155
|
- **[0.5.14]** (2026-06-16) — `jeo --tmux` live-verification harness — repeatable stability + behavior checks.
|
|
154
156
|
- **[0.5.13]** (2026-06-15) — Workflow `/` commands actually run — `/deep-interview`, `/team`, `/ultragoal`, `/ralplan` dispatch by name.
|
|
155
157
|
- **[0.5.12]** (2026-06-15) — Yellow status animation while a process runs, and elapsed `(Nms)` on every completed tool card.
|
|
156
|
-
- **[0.5.11]** (2026-06-15) — Backspace on an empty prompt line no longer quits jeo.
|
|
157
|
-
- **[0.5.10]** (2026-06-15) — `/resume` transcript no longer dumps raw JSON for batched tool calls.
|
|
158
158
|
|
|
159
159
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
160
160
|
<!-- CHANGELOG:END -->
|
package/README.zh.md
CHANGED
|
@@ -150,11 +150,11 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
|
|
|
150
150
|
## 更新日志 (Changelog)
|
|
151
151
|
|
|
152
152
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
153
|
+
- **[0.5.16]** (2026-06-16) — `/resume` and Ctrl+O no longer corrupt the TUI — clean screen restore + scrollback expand.
|
|
154
|
+
- **[0.5.15]** (2026-06-16) — `jeo update` now actually upgrades — bare command installs the latest release instead of just printing a manual command.
|
|
153
155
|
- **[0.5.14]** (2026-06-16) — `jeo --tmux` live-verification harness — repeatable stability + behavior checks.
|
|
154
156
|
- **[0.5.13]** (2026-06-15) — Workflow `/` commands actually run — `/deep-interview`, `/team`, `/ultragoal`, `/ralplan` dispatch by name.
|
|
155
157
|
- **[0.5.12]** (2026-06-15) — Yellow status animation while a process runs, and elapsed `(Nms)` on every completed tool card.
|
|
156
|
-
- **[0.5.11]** (2026-06-15) — Backspace on an empty prompt line no longer quits jeo.
|
|
157
|
-
- **[0.5.10]** (2026-06-15) — `/resume` transcript no longer dumps raw JSON for batched tool calls.
|
|
158
158
|
|
|
159
159
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
160
160
|
<!-- CHANGELOG:END -->
|
package/package.json
CHANGED
package/src/cli/runner.ts
CHANGED
|
@@ -165,7 +165,7 @@ export const COMMANDS: readonly CommandSpec[] = [
|
|
|
165
165
|
},
|
|
166
166
|
{
|
|
167
167
|
name: "update",
|
|
168
|
-
summary: "
|
|
168
|
+
summary: "Update jeo-code to the latest npm release (bare = install; --check only checks).",
|
|
169
169
|
usage: "update [--check|--install] [--json] [--strict]",
|
|
170
170
|
loader: async () => {
|
|
171
171
|
const m = await import("../commands/update");
|
package/src/commands/launch.ts
CHANGED
|
@@ -2274,7 +2274,6 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
|
|
|
2274
2274
|
}
|
|
2275
2275
|
};
|
|
2276
2276
|
let previewPending = false;
|
|
2277
|
-
let promptHistoryLines: string[] | null = null;
|
|
2278
2277
|
|
|
2279
2278
|
// Inline boxed-footer rendering with a FIXED reservation (the "@-mention typing
|
|
2280
2279
|
// pushes the box down" fix). The footer reserves its full `footerRows` height
|
|
@@ -2426,22 +2425,6 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
|
|
|
2426
2425
|
const preview = (slash.length ? slash : args).map(l => chalk.gray(truncateAnsi(l, cols)));
|
|
2427
2426
|
return [statusBarLine(cols), "", ...input, ...preview].slice(0, footerRows);
|
|
2428
2427
|
};
|
|
2429
|
-
const historyPreviewLines = (detail: string[]): string[] => {
|
|
2430
|
-
const cols = Math.max(24, (process.stdout.columns ?? 80) - 1);
|
|
2431
|
-
const title = `${uiAccent("history")} ${chalk.dim("· Ctrl+O closes")}`;
|
|
2432
|
-
const budget = Math.max(0, footerRows - 2);
|
|
2433
|
-
const physical = detail.flatMap(line => line.split("\n")).map(line => truncateAnsi(line, cols));
|
|
2434
|
-
let body = physical;
|
|
2435
|
-
if (physical.length > budget) {
|
|
2436
|
-
const keep = Math.max(0, budget - 1);
|
|
2437
|
-
body = physical.slice(0, keep);
|
|
2438
|
-
body.push(chalk.gray(`… ${physical.length - keep} more line(s)`));
|
|
2439
|
-
} else {
|
|
2440
|
-
body = physical.slice(0, budget);
|
|
2441
|
-
}
|
|
2442
|
-
footerCursor = { row: Math.min(1, footerRows - 1), col: 1 };
|
|
2443
|
-
return [statusBarLine(cols), title, ...body].slice(0, footerRows);
|
|
2444
|
-
};
|
|
2445
2428
|
const drawFooter = (lines: string[]) => {
|
|
2446
2429
|
if (!previewArmed || footerRendered === 0) return;
|
|
2447
2430
|
// ALWAYS paint exactly footerRendered rows so the reservation is fully covered
|
|
@@ -2888,23 +2871,24 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
|
|
|
2888
2871
|
return;
|
|
2889
2872
|
}
|
|
2890
2873
|
if (!previewArmed || pickerActive) return;
|
|
2891
|
-
// Ctrl+O:
|
|
2892
|
-
// uses LaunchTui.showDetail(); this
|
|
2893
|
-
//
|
|
2874
|
+
// Ctrl+O: expand the last assistant response into scrollback for a full,
|
|
2875
|
+
// scrollable read. The live-turn TUI path uses LaunchTui.showDetail(); this
|
|
2876
|
+
// idle-prompt path prints the same content above a cleanly re-armed footer.
|
|
2894
2877
|
// (Cmd+O is intercepted by macOS/terminal and never reaches the app.)
|
|
2895
2878
|
if (key?.ctrl && key.name === "o") {
|
|
2896
|
-
if (promptHistoryLines) {
|
|
2897
|
-
promptHistoryLines = null;
|
|
2898
|
-
drawFooter(previewLines(typedLine, navIdx));
|
|
2899
|
-
return;
|
|
2900
|
-
}
|
|
2901
2879
|
const detail = composeDetailLines();
|
|
2902
2880
|
if (detail.length === 0) return;
|
|
2903
|
-
|
|
2904
|
-
|
|
2881
|
+
// Expand the last response into scrollback CLEANLY instead of cramming it
|
|
2882
|
+
// into the ~10-row footer reservation (which clipped long/CJK content and
|
|
2883
|
+
// could garble the box). Disarm → print full detail → re-arm + repaint is
|
|
2884
|
+
// the same path the resize handler/main loop use, so the input box and the
|
|
2885
|
+
// typed draft restore without corruption.
|
|
2886
|
+
disarmPreview();
|
|
2887
|
+
logLines(detail);
|
|
2888
|
+
armPreview();
|
|
2889
|
+
drawFooter(previewLines(typedLine, navIdx));
|
|
2905
2890
|
return;
|
|
2906
2891
|
}
|
|
2907
|
-
if (promptHistoryLines) promptHistoryLines = null;
|
|
2908
2892
|
// Ctrl+V: attach a clipboard IMAGE to the next message. Terminal text paste
|
|
2909
2893
|
// never arrives as a ctrl+v keypress (it streams as plain stdin data), so this
|
|
2910
2894
|
// binding is image-only; when the clipboard holds no image it's a silent no-op.
|
|
@@ -2947,7 +2931,6 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
|
|
|
2947
2931
|
if (!previewArmed) return;
|
|
2948
2932
|
try {
|
|
2949
2933
|
if (key && (key.name === "return" || key.name === "enter")) {
|
|
2950
|
-
promptHistoryLines = null;
|
|
2951
2934
|
drawFooter([]);
|
|
2952
2935
|
return;
|
|
2953
2936
|
}
|
|
@@ -3008,7 +2991,7 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
|
|
|
3008
2991
|
try {
|
|
3009
2992
|
disarmPreview();
|
|
3010
2993
|
armPreview();
|
|
3011
|
-
drawFooter(
|
|
2994
|
+
drawFooter(previewLines(typedLine, navIdx));
|
|
3012
2995
|
} catch { /* ignore resize render races */ }
|
|
3013
2996
|
};
|
|
3014
2997
|
process.stdout.on("resize", idleResizeHandler);
|
|
@@ -3221,6 +3204,16 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
|
|
|
3221
3204
|
if (rli.history[0] !== p) rli.history.unshift(p);
|
|
3222
3205
|
}
|
|
3223
3206
|
}
|
|
3207
|
+
// Clean restore: wipe the screen + scrollback BEFORE replaying the
|
|
3208
|
+
// transcript so it can't collide with picker remnants, the prior
|
|
3209
|
+
// conversation, or the live input frame — the "/resume corrupts the
|
|
3210
|
+
// TUI" fix. Same proven path as /clear; re-render the welcome banner
|
|
3211
|
+
// so the resumed view reads like a fresh, intact screen.
|
|
3212
|
+
if (process.stdout.isTTY) {
|
|
3213
|
+
disarmPreview();
|
|
3214
|
+
process.stdout.write("\x1b[2J\x1b[3J\x1b[H");
|
|
3215
|
+
console.log(renderWelcome(welcomeData).join("\n"));
|
|
3216
|
+
}
|
|
3224
3217
|
const sep = "─".repeat(Math.min(48, Math.max(20, (process.stdout.columns ?? 80) - 1)));
|
|
3225
3218
|
logLines([
|
|
3226
3219
|
sep,
|
package/src/commands/update.ts
CHANGED
|
@@ -35,7 +35,7 @@ export function compareVersions(a: string, b: string): -1 | 0 | 1 {
|
|
|
35
35
|
export interface UpdateDeps {
|
|
36
36
|
fetchJson: (url: string, options?: { signal?: AbortSignal }) => Promise<any>;
|
|
37
37
|
localVersion: () => string;
|
|
38
|
-
install: () => Promise<{ success: boolean; stdout?: string; stderr?: string }>;
|
|
38
|
+
install: (version?: string) => Promise<{ success: boolean; stdout?: string; stderr?: string }>;
|
|
39
39
|
/** Display release notes after a successful self-update (best-effort, no-op in tests). */
|
|
40
40
|
showWhatsNew?: () => void;
|
|
41
41
|
}
|
|
@@ -58,8 +58,12 @@ export const defaultDeps: UpdateDeps = {
|
|
|
58
58
|
localVersion: () => {
|
|
59
59
|
return pkg.version;
|
|
60
60
|
},
|
|
61
|
-
install: async () => {
|
|
62
|
-
|
|
61
|
+
install: async (version?: string) => {
|
|
62
|
+
// Self-update the global install. jeo runs on Bun (see the `#!/usr/bin/env bun`
|
|
63
|
+
// shebang), so Bun is always present; `@<version>` (default `latest`) forces the
|
|
64
|
+
// newest publish even if a stale global is cached.
|
|
65
|
+
const target = `jeo-code@${version ?? "latest"}`;
|
|
66
|
+
const proc = Bun.spawnSync(["bun", "install", "-g", target], {
|
|
63
67
|
stdout: "inherit",
|
|
64
68
|
stderr: "inherit",
|
|
65
69
|
});
|
|
@@ -83,6 +87,7 @@ export async function runUpdateCommand(args: string[] = []): Promise<void> {
|
|
|
83
87
|
export async function runUpdateCommandWith(args: string[], deps: UpdateDeps): Promise<void> {
|
|
84
88
|
const isHelp = args.includes("--help") || args.includes("-h");
|
|
85
89
|
const hasInstall = args.includes("--install");
|
|
90
|
+
const hasCheck = args.includes("--check");
|
|
86
91
|
const hasJson = args.includes("--json");
|
|
87
92
|
const hasStrict = args.includes("--strict");
|
|
88
93
|
|
|
@@ -154,8 +159,13 @@ export async function runUpdateCommandWith(args: string[], deps: UpdateDeps): Pr
|
|
|
154
159
|
}
|
|
155
160
|
}
|
|
156
161
|
|
|
162
|
+
// Default action is INSTALL (bare `jeo update` upgrades). `--check` forces a
|
|
163
|
+
// check-only run; `--json` stays check-only too (programmatic status polling must
|
|
164
|
+
// not trigger an install) unless `--install` is given explicitly.
|
|
165
|
+
const shouldInstall = hasInstall || (!hasCheck && !hasJson);
|
|
166
|
+
|
|
157
167
|
// We got the version successfully
|
|
158
|
-
if (
|
|
168
|
+
if (shouldInstall) {
|
|
159
169
|
if (upToDate) {
|
|
160
170
|
if (hasJson) {
|
|
161
171
|
console.log(JSON.stringify({
|
|
@@ -165,14 +175,14 @@ export async function runUpdateCommandWith(args: string[], deps: UpdateDeps): Pr
|
|
|
165
175
|
installed: false
|
|
166
176
|
}));
|
|
167
177
|
} else {
|
|
168
|
-
console.log(`jeo-code is up-to-date (${current})
|
|
178
|
+
console.log(`jeo-code is already up-to-date (${current}).`);
|
|
169
179
|
}
|
|
170
180
|
} else {
|
|
171
181
|
if (!hasJson) {
|
|
172
182
|
console.log(`Installing update: ${current} -> ${latest}...`);
|
|
173
183
|
}
|
|
174
184
|
try {
|
|
175
|
-
const result = await deps.install();
|
|
185
|
+
const result = await deps.install(latest ?? undefined);
|
|
176
186
|
if (result.success) {
|
|
177
187
|
if (hasJson) {
|
|
178
188
|
console.log(JSON.stringify({
|
|
@@ -236,7 +246,7 @@ export async function runUpdateCommandWith(args: string[], deps: UpdateDeps): Pr
|
|
|
236
246
|
}));
|
|
237
247
|
} else {
|
|
238
248
|
console.log(`Newer version available: ${latest} (current: ${current}).`);
|
|
239
|
-
console.log("Run '
|
|
249
|
+
console.log("Run 'jeo update' to install it.");
|
|
240
250
|
}
|
|
241
251
|
}
|
|
242
252
|
}
|
|
@@ -248,8 +258,9 @@ function printUsage() {
|
|
|
248
258
|
console.log("Check for and install updates for jeo-code.");
|
|
249
259
|
console.log("");
|
|
250
260
|
console.log("Options:");
|
|
251
|
-
console.log("
|
|
252
|
-
console.log(" --
|
|
261
|
+
console.log(" (default) Check and install if a newer version is available");
|
|
262
|
+
console.log(" --check Only check; do not install");
|
|
263
|
+
console.log(" --install Force install if newer (also used with --json)");
|
|
253
264
|
console.log(" --json Output result in JSON format");
|
|
254
265
|
console.log(" --strict Exit with code 1 on network/registry errors");
|
|
255
266
|
console.log(" -h, --help Show this help message");
|