jeo-code 0.8.27 → 0.8.30
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 +37 -0
- package/README.ja.md +3 -3
- package/README.ko.md +3 -3
- package/README.md +3 -3
- package/README.zh.md +3 -3
- package/package.json +2 -2
- package/src/commands/launch.ts +20 -0
- package/src/tui/components/autocomplete.ts +29 -0
- package/src/tui/components/welcome.ts +109 -26
- package/src/util/whats-new.ts +1 -0
- package/src/types/playwriter.d.ts +0 -15
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,43 @@ 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.8.30] - 2026-07-20
|
|
10
|
+
_`bun run build` (the host-only dev binary build) has been silently broken for every user who ran it — a drift between the plain `package.json` `build` script and the actual working release-binary build command (`scripts/ci-release-build-binaries.ts`), which had already documented and fixed the exact same crash._
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **`bun run build` no longer crashes with `Could not resolve: "chromium-bidi/lib/cjs/bidiMapper/BidiMapper"`** (`package.json`) — `playwright-core`'s bundled `coreBundle.js` has a lazy `require("chromium-bidi/...")` reachable only through its BiDi bridge, a code path jeo never takes (`browser-session.ts` launches Chromium over plain CDP only). `chromium-bidi` isn't a declared dependency of `playwright-core` (confirmed against the published npm metadata — real `playwright-core@1.61.0` ships zero `dependencies`, everything is bundled), so it's absent from `node_modules`; Bun's `--compile` bundler statically resolves every reachable `require()` — dead code path or not — and fails the whole build without an explicit `--external`. `scripts/ci-release-build-binaries.ts`'s `buildCommand()` already carried `--external chromium-bidi` (plus `--keep-names` and `--no-compile-autoload-dotenv`) with a comment explaining exactly this, but the separate, hand-written `package.json` `"build"` script was never updated to match and always failed for anyone running the plain host-only dev build. Brought into sync with the same three flags.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- **Regression coverage locking the two build commands together** (`test/release-binaries.test.ts`) — `buildCommand()`'s own test now also asserts `--external chromium-bidi` is present (it wasn't previously locked, despite existing in the source); a new test reads `package.json` at runtime and asserts every `--flag` `buildCommand()` emits (excluding target-specific `--target`/`--outfile`) is present in the plain `build` script, plus the `chromium-bidi` module name itself, so the two commands can never silently drift apart again.
|
|
17
|
+
|
|
18
|
+
### Verified
|
|
19
|
+
- `bun run build` — real compile succeeds (`bundle 257 modules` / `compile dist/jeo`), producing a genuine standalone Mach-O binary (86MB, arm64 host).
|
|
20
|
+
- Ran the compiled binary directly (not the interpreted `bun src/cli.ts` path): `./dist/jeo --version` → `jeo v0.8.30`, exit 0; `./dist/jeo --help` → full command listing, exit 0.
|
|
21
|
+
- `test/release-binaries.test.ts` — 9 pass (was 8; +1 new test, +2 new assertions in the existing `buildCommand` test).
|
|
22
|
+
- Full `bun test` — 3081 pass / 0 fail across 304 files.
|
|
23
|
+
- `bun run typecheck` — no errors.
|
|
24
|
+
|
|
25
|
+
## [0.8.29] - 2026-07-20
|
|
26
|
+
_gajae-code (gjc) v0.10.2→v0.11.4 gap analysis: most of that range is gjc-specific architecture jeo intentionally does not replicate (SDK broker/session-index recovery, Gajae Pet, coordinator-mcp, Telegram/Discord rich-delivery internals, browser tab workers, worktree-subcommand removal, RPC durable model selection) — one genuinely applicable TUI bug was found and closed; the CLI empty-non-TTY-stdin fix (gjc #2586) was investigated and found already-correct by construction (jeo's one-shot gate forces true whenever stdin isn't a TTY, regardless of args, so the hang gjc fixed cannot occur here)._
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
- **Backtick-span literals no longer pop the `/command`/`$skill` autocomplete palette** (`src/tui/components/autocomplete.ts`) — gjc v0.11.3 parity ("suppress autocomplete in backtick spans", #2629). A composer example like "use `` `/model` `` to switch" or plain prose containing a lone, not-yet-closed backtick followed later by a `/word` or `$word` previously matched `complete()`'s mid-line command/skill branches and popped the live dropdown (and rode along into `readlineCompleter`'s Tab dispatch), because completion only ever looked at the trailing whitespace-delimited token, never the line's backtick-span state. New `insideBacktickSpan()` walks the line up to the token's start offset with escape-parity (a `\`` never toggles the span), and the mid-line `$skill`/`/command` branches now check it before matching; `@path` mentions are unaffected (preserved live inside a span, matching gjc's split). Closed/paired spans before the token, and lines with no span at all, are unaffected — this only suppresses matching while genuinely inside an open span.
|
|
30
|
+
|
|
31
|
+
### Verified
|
|
32
|
+
- `test/autocomplete.test.ts` — 32 pass (new coverage: open span suppresses `/command`/`$skill`, closed span doesn't, escape-parity distinguishes an escaped backtick from a real toggle, `@path` stays live inside a span).
|
|
33
|
+
- Full `bun test` — 3080 pass / 0 fail across 304 files.
|
|
34
|
+
- `bun run typecheck` — no errors.
|
|
35
|
+
|
|
36
|
+
## [0.8.28] - 2026-07-16
|
|
37
|
+
_Improved the welcome UI's right-side table to display dynamic sections (What's New, Flow keys, Project pulse, and Session trail) matching gajae-code (gjc) >= 0.8.0 features._
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
- **Dynamic welcome UI right-side table** (`src/tui/components/welcome.ts`, `src/commands/launch.ts`) — replaced the static metadata table with dynamic sections: "What's New" (latest changelog items), "Flow keys" (keyboard shortcuts), "Project pulse" (TypeScript language service status), and "Session trail" (recent sessions with relative time ago formatting).
|
|
41
|
+
|
|
42
|
+
### Verified
|
|
43
|
+
- Full `bun test` — all tests pass.
|
|
44
|
+
- `bun run typecheck` — no errors.
|
|
45
|
+
|
|
9
46
|
## [0.8.27] - 2026-07-16
|
|
10
47
|
_Repeat-read recovery now survives both context-overflow and refusal-result elision without reopening mutating-call loops._
|
|
11
48
|
|
package/README.ja.md
CHANGED
|
@@ -283,11 +283,11 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
|
|
|
283
283
|
## 変更履歴 (Changelog)
|
|
284
284
|
|
|
285
285
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
286
|
+
- **[0.8.30]** (2026-07-20) — `bun run build` (the host-only dev binary build) has been silently broken for every user who ran it — a drift between the plain `package.json` `build` script and the actual working release-binary build command (`scripts/ci-release-build-binaries.ts`), which had already documented and fixed the exact same crash.
|
|
287
|
+
- **[0.8.29]** (2026-07-20) — gajae-code (gjc) v0.10.2→v0.11.4 gap analysis: most of that range is gjc-specific architecture jeo intentionally does not replicate (SDK broker/session-index recovery, Gajae Pet, coordinator-mcp, Telegram/Discord rich-delivery internals, browser tab workers, worktree-subcommand removal, RPC durable model selection) — one genuinely applicable TUI bug was found and closed; the CLI empty-non-TTY-stdin fix (gjc #2586) was investigated and found already-correct by construction (jeo's one-shot gate forces true whenever stdin isn't a TTY, regardless of args, so the hang gjc fixed cannot occur here).
|
|
288
|
+
- **[0.8.28]** (2026-07-16) — Improved the welcome UI's right-side table to display dynamic sections (What's New, Flow keys, Project pulse, and Session trail) matching gajae-code (gjc) >= 0.8.0 features.
|
|
286
289
|
- **[0.8.27]** (2026-07-16) — Repeat-read recovery now survives both context-overflow and refusal-result elision without reopening mutating-call loops.
|
|
287
290
|
- **[0.8.26]** (2026-07-14) — Model catalog cleanup (drop sub-4.6 Anthropic `claude-haiku-4-5` from the exposed catalog/aliases per user direction) plus a focused gap analysis against `gajae-code`'s (gjc) 0.8.0→0.10.1 release history (~200 PRs) — most of gjc's surface (RPC/ACP/coordinator-mcp/IRC-sidebar/psmux/Windows-team) doesn't exist in jeo's smaller architecture and was ruled out with direct evidence; a few genuinely applicable gaps were found and closed.
|
|
288
|
-
- **[0.8.25]** (2026-07-13) — Post-audit follow-up: 0.8.24's fixture-repair subagent flagged (but, correctly, did not itself fix — out of its assigned scope) a case-sensitivity bug in the new PlanSchema maker→verifier ordering rule. Fixed.
|
|
289
|
-
- **[0.8.24]** (2026-07-13) — Follow-up gap analysis against the same external "self-improving agent system" framework (Fable-5-style loops), continuing 0.8.23's audit into 4 more primitives: independent-verifier ENFORCEMENT (0.8.23 had the gate logic but nothing forced a plan to actually contain one), model-tier safety-boundary fallback (a false-positive safety refusal previously backed off forever on the SAME model instead of trying a genuinely different one — the pattern already shipped for rate limits), memory confidence that was self-assigned once instead of earned via a real verification event, and Dynamic Workflows (jeo had parallel fan-out but no sequential composition or real control flow across subagent calls). Closed all 4, the last one non-trivially: an in-process `AsyncFunction` (the same pattern `browser {run}` already ships) cannot be given a real wall-clock timeout — a synchronous bug in agent-authored code blocks jeo's own event loop forever, and `Promise.race` can never preempt it (verified empirically). Fixed by running Dynamic Workflows scripts in an isolated `Worker` (a genuinely separate OS thread `worker.terminate()` can preempt unconditionally, mirroring `bashTool`'s own SIGTERM/SIGKILL escalation on a spawned process) with `task()` bridged back to the main thread over a `postMessage` RPC — config/credentials never leave the main thread, and every dispatch (however the script shapes it) stays bounded by a real concurrency semaphore, not just a per-call count cap.
|
|
290
|
-
- **[0.8.23]** (2026-07-12) — Gap analysis against an external "self-improving agent system" framework (Fable-5-style loops: independent verifiers, memory compounding, model-tier cost discipline, and scheduled routines) found jeo-code already had strong equivalents for most primitives — but 3 real gaps and 1 deliberately-scoped-safe gap. Closed all 4: skills that were "hand-authored, read-mostly, zero learning" now compound from real session failures; screenshots that were captured but never judged now close a real vision-verify loop; the `/goal` verifier and bulk fan-out dispatch that silently rode the same full-price model as the work they graded/executed now default to a cheap tier; and "runs without your laptop" is now achievable via a generated GitHub Actions template wrapping jeo's existing headless mode — with zero new attack surface inside jeo-code itself (no code-exec sandbox, no in-process scheduler/webhook receiver, both deliberately rejected as out of scope). Also absorbs 3 fixes shipped after 0.8.22 but never changelogged: a rate-limit fast-fallback audit that closed 4 real gaps, plus the cross-file `mock.module()` test-isolation class this release's own test additions collided with and fixed at its root cause.
|
|
291
291
|
|
|
292
292
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
293
293
|
<!-- CHANGELOG:END -->
|
package/README.ko.md
CHANGED
|
@@ -284,11 +284,11 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
|
|
|
284
284
|
## 변경 이력 (Changelog)
|
|
285
285
|
|
|
286
286
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
287
|
+
- **[0.8.30]** (2026-07-20) — `bun run build` (the host-only dev binary build) has been silently broken for every user who ran it — a drift between the plain `package.json` `build` script and the actual working release-binary build command (`scripts/ci-release-build-binaries.ts`), which had already documented and fixed the exact same crash.
|
|
288
|
+
- **[0.8.29]** (2026-07-20) — gajae-code (gjc) v0.10.2→v0.11.4 gap analysis: most of that range is gjc-specific architecture jeo intentionally does not replicate (SDK broker/session-index recovery, Gajae Pet, coordinator-mcp, Telegram/Discord rich-delivery internals, browser tab workers, worktree-subcommand removal, RPC durable model selection) — one genuinely applicable TUI bug was found and closed; the CLI empty-non-TTY-stdin fix (gjc #2586) was investigated and found already-correct by construction (jeo's one-shot gate forces true whenever stdin isn't a TTY, regardless of args, so the hang gjc fixed cannot occur here).
|
|
289
|
+
- **[0.8.28]** (2026-07-16) — Improved the welcome UI's right-side table to display dynamic sections (What's New, Flow keys, Project pulse, and Session trail) matching gajae-code (gjc) >= 0.8.0 features.
|
|
287
290
|
- **[0.8.27]** (2026-07-16) — Repeat-read recovery now survives both context-overflow and refusal-result elision without reopening mutating-call loops.
|
|
288
291
|
- **[0.8.26]** (2026-07-14) — Model catalog cleanup (drop sub-4.6 Anthropic `claude-haiku-4-5` from the exposed catalog/aliases per user direction) plus a focused gap analysis against `gajae-code`'s (gjc) 0.8.0→0.10.1 release history (~200 PRs) — most of gjc's surface (RPC/ACP/coordinator-mcp/IRC-sidebar/psmux/Windows-team) doesn't exist in jeo's smaller architecture and was ruled out with direct evidence; a few genuinely applicable gaps were found and closed.
|
|
289
|
-
- **[0.8.25]** (2026-07-13) — Post-audit follow-up: 0.8.24's fixture-repair subagent flagged (but, correctly, did not itself fix — out of its assigned scope) a case-sensitivity bug in the new PlanSchema maker→verifier ordering rule. Fixed.
|
|
290
|
-
- **[0.8.24]** (2026-07-13) — Follow-up gap analysis against the same external "self-improving agent system" framework (Fable-5-style loops), continuing 0.8.23's audit into 4 more primitives: independent-verifier ENFORCEMENT (0.8.23 had the gate logic but nothing forced a plan to actually contain one), model-tier safety-boundary fallback (a false-positive safety refusal previously backed off forever on the SAME model instead of trying a genuinely different one — the pattern already shipped for rate limits), memory confidence that was self-assigned once instead of earned via a real verification event, and Dynamic Workflows (jeo had parallel fan-out but no sequential composition or real control flow across subagent calls). Closed all 4, the last one non-trivially: an in-process `AsyncFunction` (the same pattern `browser {run}` already ships) cannot be given a real wall-clock timeout — a synchronous bug in agent-authored code blocks jeo's own event loop forever, and `Promise.race` can never preempt it (verified empirically). Fixed by running Dynamic Workflows scripts in an isolated `Worker` (a genuinely separate OS thread `worker.terminate()` can preempt unconditionally, mirroring `bashTool`'s own SIGTERM/SIGKILL escalation on a spawned process) with `task()` bridged back to the main thread over a `postMessage` RPC — config/credentials never leave the main thread, and every dispatch (however the script shapes it) stays bounded by a real concurrency semaphore, not just a per-call count cap.
|
|
291
|
-
- **[0.8.23]** (2026-07-12) — Gap analysis against an external "self-improving agent system" framework (Fable-5-style loops: independent verifiers, memory compounding, model-tier cost discipline, and scheduled routines) found jeo-code already had strong equivalents for most primitives — but 3 real gaps and 1 deliberately-scoped-safe gap. Closed all 4: skills that were "hand-authored, read-mostly, zero learning" now compound from real session failures; screenshots that were captured but never judged now close a real vision-verify loop; the `/goal` verifier and bulk fan-out dispatch that silently rode the same full-price model as the work they graded/executed now default to a cheap tier; and "runs without your laptop" is now achievable via a generated GitHub Actions template wrapping jeo's existing headless mode — with zero new attack surface inside jeo-code itself (no code-exec sandbox, no in-process scheduler/webhook receiver, both deliberately rejected as out of scope). Also absorbs 3 fixes shipped after 0.8.22 but never changelogged: a rate-limit fast-fallback audit that closed 4 real gaps, plus the cross-file `mock.module()` test-isolation class this release's own test additions collided with and fixed at its root cause.
|
|
292
292
|
|
|
293
293
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
294
294
|
<!-- CHANGELOG:END -->
|
package/README.md
CHANGED
|
@@ -291,11 +291,11 @@ Huge thanks to [gajae-code](https://github.com/Yeachan-Heo/gajae-code) for the i
|
|
|
291
291
|
## Changelog
|
|
292
292
|
|
|
293
293
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
294
|
+
- **[0.8.30]** (2026-07-20) — `bun run build` (the host-only dev binary build) has been silently broken for every user who ran it — a drift between the plain `package.json` `build` script and the actual working release-binary build command (`scripts/ci-release-build-binaries.ts`), which had already documented and fixed the exact same crash.
|
|
295
|
+
- **[0.8.29]** (2026-07-20) — gajae-code (gjc) v0.10.2→v0.11.4 gap analysis: most of that range is gjc-specific architecture jeo intentionally does not replicate (SDK broker/session-index recovery, Gajae Pet, coordinator-mcp, Telegram/Discord rich-delivery internals, browser tab workers, worktree-subcommand removal, RPC durable model selection) — one genuinely applicable TUI bug was found and closed; the CLI empty-non-TTY-stdin fix (gjc #2586) was investigated and found already-correct by construction (jeo's one-shot gate forces true whenever stdin isn't a TTY, regardless of args, so the hang gjc fixed cannot occur here).
|
|
296
|
+
- **[0.8.28]** (2026-07-16) — Improved the welcome UI's right-side table to display dynamic sections (What's New, Flow keys, Project pulse, and Session trail) matching gajae-code (gjc) >= 0.8.0 features.
|
|
294
297
|
- **[0.8.27]** (2026-07-16) — Repeat-read recovery now survives both context-overflow and refusal-result elision without reopening mutating-call loops.
|
|
295
298
|
- **[0.8.26]** (2026-07-14) — Model catalog cleanup (drop sub-4.6 Anthropic `claude-haiku-4-5` from the exposed catalog/aliases per user direction) plus a focused gap analysis against `gajae-code`'s (gjc) 0.8.0→0.10.1 release history (~200 PRs) — most of gjc's surface (RPC/ACP/coordinator-mcp/IRC-sidebar/psmux/Windows-team) doesn't exist in jeo's smaller architecture and was ruled out with direct evidence; a few genuinely applicable gaps were found and closed.
|
|
296
|
-
- **[0.8.25]** (2026-07-13) — Post-audit follow-up: 0.8.24's fixture-repair subagent flagged (but, correctly, did not itself fix — out of its assigned scope) a case-sensitivity bug in the new PlanSchema maker→verifier ordering rule. Fixed.
|
|
297
|
-
- **[0.8.24]** (2026-07-13) — Follow-up gap analysis against the same external "self-improving agent system" framework (Fable-5-style loops), continuing 0.8.23's audit into 4 more primitives: independent-verifier ENFORCEMENT (0.8.23 had the gate logic but nothing forced a plan to actually contain one), model-tier safety-boundary fallback (a false-positive safety refusal previously backed off forever on the SAME model instead of trying a genuinely different one — the pattern already shipped for rate limits), memory confidence that was self-assigned once instead of earned via a real verification event, and Dynamic Workflows (jeo had parallel fan-out but no sequential composition or real control flow across subagent calls). Closed all 4, the last one non-trivially: an in-process `AsyncFunction` (the same pattern `browser {run}` already ships) cannot be given a real wall-clock timeout — a synchronous bug in agent-authored code blocks jeo's own event loop forever, and `Promise.race` can never preempt it (verified empirically). Fixed by running Dynamic Workflows scripts in an isolated `Worker` (a genuinely separate OS thread `worker.terminate()` can preempt unconditionally, mirroring `bashTool`'s own SIGTERM/SIGKILL escalation on a spawned process) with `task()` bridged back to the main thread over a `postMessage` RPC — config/credentials never leave the main thread, and every dispatch (however the script shapes it) stays bounded by a real concurrency semaphore, not just a per-call count cap.
|
|
298
|
-
- **[0.8.23]** (2026-07-12) — Gap analysis against an external "self-improving agent system" framework (Fable-5-style loops: independent verifiers, memory compounding, model-tier cost discipline, and scheduled routines) found jeo-code already had strong equivalents for most primitives — but 3 real gaps and 1 deliberately-scoped-safe gap. Closed all 4: skills that were "hand-authored, read-mostly, zero learning" now compound from real session failures; screenshots that were captured but never judged now close a real vision-verify loop; the `/goal` verifier and bulk fan-out dispatch that silently rode the same full-price model as the work they graded/executed now default to a cheap tier; and "runs without your laptop" is now achievable via a generated GitHub Actions template wrapping jeo's existing headless mode — with zero new attack surface inside jeo-code itself (no code-exec sandbox, no in-process scheduler/webhook receiver, both deliberately rejected as out of scope). Also absorbs 3 fixes shipped after 0.8.22 but never changelogged: a rate-limit fast-fallback audit that closed 4 real gaps, plus the cross-file `mock.module()` test-isolation class this release's own test additions collided with and fixed at its root cause.
|
|
299
299
|
|
|
300
300
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
301
301
|
<!-- CHANGELOG:END -->
|
package/README.zh.md
CHANGED
|
@@ -283,11 +283,11 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
|
|
|
283
283
|
## 更新日志 (Changelog)
|
|
284
284
|
|
|
285
285
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
286
|
+
- **[0.8.30]** (2026-07-20) — `bun run build` (the host-only dev binary build) has been silently broken for every user who ran it — a drift between the plain `package.json` `build` script and the actual working release-binary build command (`scripts/ci-release-build-binaries.ts`), which had already documented and fixed the exact same crash.
|
|
287
|
+
- **[0.8.29]** (2026-07-20) — gajae-code (gjc) v0.10.2→v0.11.4 gap analysis: most of that range is gjc-specific architecture jeo intentionally does not replicate (SDK broker/session-index recovery, Gajae Pet, coordinator-mcp, Telegram/Discord rich-delivery internals, browser tab workers, worktree-subcommand removal, RPC durable model selection) — one genuinely applicable TUI bug was found and closed; the CLI empty-non-TTY-stdin fix (gjc #2586) was investigated and found already-correct by construction (jeo's one-shot gate forces true whenever stdin isn't a TTY, regardless of args, so the hang gjc fixed cannot occur here).
|
|
288
|
+
- **[0.8.28]** (2026-07-16) — Improved the welcome UI's right-side table to display dynamic sections (What's New, Flow keys, Project pulse, and Session trail) matching gajae-code (gjc) >= 0.8.0 features.
|
|
286
289
|
- **[0.8.27]** (2026-07-16) — Repeat-read recovery now survives both context-overflow and refusal-result elision without reopening mutating-call loops.
|
|
287
290
|
- **[0.8.26]** (2026-07-14) — Model catalog cleanup (drop sub-4.6 Anthropic `claude-haiku-4-5` from the exposed catalog/aliases per user direction) plus a focused gap analysis against `gajae-code`'s (gjc) 0.8.0→0.10.1 release history (~200 PRs) — most of gjc's surface (RPC/ACP/coordinator-mcp/IRC-sidebar/psmux/Windows-team) doesn't exist in jeo's smaller architecture and was ruled out with direct evidence; a few genuinely applicable gaps were found and closed.
|
|
288
|
-
- **[0.8.25]** (2026-07-13) — Post-audit follow-up: 0.8.24's fixture-repair subagent flagged (but, correctly, did not itself fix — out of its assigned scope) a case-sensitivity bug in the new PlanSchema maker→verifier ordering rule. Fixed.
|
|
289
|
-
- **[0.8.24]** (2026-07-13) — Follow-up gap analysis against the same external "self-improving agent system" framework (Fable-5-style loops), continuing 0.8.23's audit into 4 more primitives: independent-verifier ENFORCEMENT (0.8.23 had the gate logic but nothing forced a plan to actually contain one), model-tier safety-boundary fallback (a false-positive safety refusal previously backed off forever on the SAME model instead of trying a genuinely different one — the pattern already shipped for rate limits), memory confidence that was self-assigned once instead of earned via a real verification event, and Dynamic Workflows (jeo had parallel fan-out but no sequential composition or real control flow across subagent calls). Closed all 4, the last one non-trivially: an in-process `AsyncFunction` (the same pattern `browser {run}` already ships) cannot be given a real wall-clock timeout — a synchronous bug in agent-authored code blocks jeo's own event loop forever, and `Promise.race` can never preempt it (verified empirically). Fixed by running Dynamic Workflows scripts in an isolated `Worker` (a genuinely separate OS thread `worker.terminate()` can preempt unconditionally, mirroring `bashTool`'s own SIGTERM/SIGKILL escalation on a spawned process) with `task()` bridged back to the main thread over a `postMessage` RPC — config/credentials never leave the main thread, and every dispatch (however the script shapes it) stays bounded by a real concurrency semaphore, not just a per-call count cap.
|
|
290
|
-
- **[0.8.23]** (2026-07-12) — Gap analysis against an external "self-improving agent system" framework (Fable-5-style loops: independent verifiers, memory compounding, model-tier cost discipline, and scheduled routines) found jeo-code already had strong equivalents for most primitives — but 3 real gaps and 1 deliberately-scoped-safe gap. Closed all 4: skills that were "hand-authored, read-mostly, zero learning" now compound from real session failures; screenshots that were captured but never judged now close a real vision-verify loop; the `/goal` verifier and bulk fan-out dispatch that silently rode the same full-price model as the work they graded/executed now default to a cheap tier; and "runs without your laptop" is now achievable via a generated GitHub Actions template wrapping jeo's existing headless mode — with zero new attack surface inside jeo-code itself (no code-exec sandbox, no in-process scheduler/webhook receiver, both deliberately rejected as out of scope). Also absorbs 3 fixes shipped after 0.8.22 but never changelogged: a rate-limit fast-fallback audit that closed 4 real gaps, plus the cross-file `mock.module()` test-isolation class this release's own test additions collided with and fixed at its root cause.
|
|
291
291
|
|
|
292
292
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
293
293
|
<!-- CHANGELOG:END -->
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jeo-code",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.30",
|
|
4
4
|
"description": "Clean, highly optimized AI coding agent using spec-first loop",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/cli.ts",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"scripts": {
|
|
46
46
|
"start": "bun src/cli.ts",
|
|
47
47
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
48
|
-
"build": "bun build src/cli.ts --compile --outfile dist/jeo",
|
|
48
|
+
"build": "bun build src/cli.ts --compile --keep-names --external chromium-bidi --no-compile-autoload-dotenv --outfile dist/jeo",
|
|
49
49
|
"build:binaries": "bun scripts/ci-release-build-binaries.ts",
|
|
50
50
|
"build:win": "bun scripts/ci-release-build-binaries.ts --targets win32-x64",
|
|
51
51
|
"pack:check": "npm pack --dry-run",
|
package/src/commands/launch.ts
CHANGED
|
@@ -2129,6 +2129,25 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
|
|
|
2129
2129
|
const activeStartModel = sessionModel || defaultModel;
|
|
2130
2130
|
const { provider: startProvider } = await describeModel(activeStartModel);
|
|
2131
2131
|
const welcomeTheme = resolveTheme(process.env);
|
|
2132
|
+
|
|
2133
|
+
const formatTimeAgo = (isoString?: string): string => {
|
|
2134
|
+
if (!isoString) return "unknown";
|
|
2135
|
+
const diffMs = Date.now() - new Date(isoString).getTime();
|
|
2136
|
+
const diffMins = Math.floor(diffMs / 60000);
|
|
2137
|
+
if (diffMins < 1) return "just now";
|
|
2138
|
+
if (diffMins < 60) return `${diffMins}m ago`;
|
|
2139
|
+
const diffHours = Math.floor(diffMins / 60);
|
|
2140
|
+
if (diffHours < 24) return `${diffHours}h ago`;
|
|
2141
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
2142
|
+
return `${diffDays}d ago`;
|
|
2143
|
+
};
|
|
2144
|
+
|
|
2145
|
+
const sessions = await listSessions(cwd || process.cwd());
|
|
2146
|
+
const recentSessions = sessions.map(s => ({
|
|
2147
|
+
name: s.title || s.preview || s.id,
|
|
2148
|
+
timeAgo: formatTimeAgo(s.timestamp),
|
|
2149
|
+
}));
|
|
2150
|
+
|
|
2132
2151
|
const welcomeData = {
|
|
2133
2152
|
version: pkg.version,
|
|
2134
2153
|
model: activeStartModel,
|
|
@@ -2137,6 +2156,7 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
|
|
|
2137
2156
|
thinking: sessionThinking ?? "medium",
|
|
2138
2157
|
sessionId,
|
|
2139
2158
|
contextFiles: contextFiles.map(f => f.path),
|
|
2159
|
+
recentSessions,
|
|
2140
2160
|
cols: terminalSize().cols,
|
|
2141
2161
|
unicode: supportsUnicode(),
|
|
2142
2162
|
color: welcomeTheme.color,
|
|
@@ -184,6 +184,25 @@ function rankedModelPool(ctx: CompletionContext): string[] {
|
|
|
184
184
|
* before; free-text input stays untouched except for `@path` mentions, which can
|
|
185
185
|
* surface local relative paths.
|
|
186
186
|
*/
|
|
187
|
+
/**
|
|
188
|
+
* True when `pos` sits inside an unterminated (or paired) single-backtick span
|
|
189
|
+
* opened earlier on the same line (gjc parity, #2619/#2629). A backslash
|
|
190
|
+
* ALWAYS escapes the next character — an escaped backtick (`\``) never toggles
|
|
191
|
+
* the span — so a composer example like "use `/model` to switch" or a literal
|
|
192
|
+
* "type \` then a command" both classify correctly. Only line-local state:
|
|
193
|
+
* spans never carry across lines (there is no multi-line buffer here).
|
|
194
|
+
*/
|
|
195
|
+
function insideBacktickSpan(line: string, pos: number): boolean {
|
|
196
|
+
let open = false;
|
|
197
|
+
let i = 0;
|
|
198
|
+
while (i < pos && i < line.length) {
|
|
199
|
+
const ch = line[i];
|
|
200
|
+
if (ch === "\\") { i += 2; continue; }
|
|
201
|
+
if (ch === "`") open = !open;
|
|
202
|
+
i++;
|
|
203
|
+
}
|
|
204
|
+
return open;
|
|
205
|
+
}
|
|
187
206
|
export function complete(line: string, ctx: CompletionContext): CompletionResult {
|
|
188
207
|
const { tokens, trailingSpace } = tokenize(line);
|
|
189
208
|
if (!line.startsWith("/")) {
|
|
@@ -196,6 +215,16 @@ export function complete(line: string, ctx: CompletionContext): CompletionResult
|
|
|
196
215
|
const pool = (ctx.mentionPaths?.(prefix) ?? []).map(p => (p.startsWith("@") ? p : `@${p}`));
|
|
197
216
|
return { completions: dedupeCap(pool), token, kind: "path" };
|
|
198
217
|
}
|
|
218
|
+
// Literal backtick spans (`` `/model` ``, `` `$skill` ``) are protected text,
|
|
219
|
+
// not live mentions — suppress command/skill matching (and the Tab/Enter
|
|
220
|
+
// dispatch riding on it) below so a typed example never pops the palette.
|
|
221
|
+
// `@path` mentions above stay live inside a span (gjc parity: path
|
|
222
|
+
// completion is preserved in literals; only command/skill matching is
|
|
223
|
+
// suppressed). The token's own start offset is `line.length - token.length`
|
|
224
|
+
// (or `line.length` when trailing-space, which never matches $/ below).
|
|
225
|
+
if (insideBacktickSpan(line, line.length - token.length)) {
|
|
226
|
+
return { completions: [], token: line, kind: "none" };
|
|
227
|
+
}
|
|
199
228
|
// `$skill` mention completion at ANY position in the line (mention-style;
|
|
200
229
|
// a leading `$name` is additionally the direct-invocation entrypoint).
|
|
201
230
|
if (token.startsWith("$")) {
|
|
@@ -4,7 +4,24 @@ import * as os from "node:os";
|
|
|
4
4
|
import { renderForgeMark, FORGE_MARK_ART_GRAND } from "./ascii-art";
|
|
5
5
|
import { truncate, isTTY } from "../terminal";
|
|
6
6
|
import { detectColorLevel, ColorLevel, visibleWidth } from "./color";
|
|
7
|
+
import { parseChangelogSections, changelogText } from "../../util/whats-new";
|
|
7
8
|
|
|
9
|
+
function getLatestChangelogItems(): { version: string; items: string[] } {
|
|
10
|
+
try {
|
|
11
|
+
const sections = parseChangelogSections(changelogText);
|
|
12
|
+
if (sections.length > 0) {
|
|
13
|
+
const latest = sections[0];
|
|
14
|
+
const items: string[] = [];
|
|
15
|
+
for (const g of latest.groups) {
|
|
16
|
+
for (const item of g.items) {
|
|
17
|
+
items.push(item);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return { version: latest.version, items };
|
|
21
|
+
}
|
|
22
|
+
} catch {}
|
|
23
|
+
return { version: "", items: [] };
|
|
24
|
+
}
|
|
8
25
|
export interface WelcomeData {
|
|
9
26
|
version: string;
|
|
10
27
|
model: string;
|
|
@@ -47,29 +64,99 @@ function shortenPath(p: string | undefined, maxWidth: number, unicode: boolean):
|
|
|
47
64
|
return truncate(`${ell}${s.slice(-Math.max(1, maxWidth - visibleWidth(ell)))}`, maxWidth);
|
|
48
65
|
}
|
|
49
66
|
|
|
50
|
-
function
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
function renderRightColumn(d: WelcomeData, width: number, unicode: boolean, useColor: boolean): string[] {
|
|
68
|
+
const accent = useColor ? (d.accent ?? chalk.cyan) : (s: string) => s;
|
|
69
|
+
const dim = useColor ? chalk.dim : (s: string) => s;
|
|
70
|
+
const gray = useColor ? chalk.gray : (s: string) => s;
|
|
71
|
+
const bold = useColor ? chalk.bold : (s: string) => s;
|
|
72
|
+
const bulletChar = unicode ? "•" : "-";
|
|
73
|
+
const hChar = unicode ? "─" : "-";
|
|
74
|
+
const sepLine = dim(hChar.repeat(width));
|
|
75
|
+
|
|
76
|
+
const lines: string[] = [];
|
|
77
|
+
|
|
78
|
+
// 1. What's New
|
|
79
|
+
lines.push(padLine(` ${bold(accent("What's New"))}`, width));
|
|
80
|
+
const changelog = getLatestChangelogItems();
|
|
81
|
+
if (changelog.items.length > 0) {
|
|
82
|
+
const prefix = ` ${bulletChar} `;
|
|
83
|
+
const textWidth = Math.max(1, width - visibleWidth(prefix));
|
|
84
|
+
const shown = changelog.items.slice(0, 3);
|
|
85
|
+
for (const item of shown) {
|
|
86
|
+
const text = visibleWidth(item) > textWidth ? truncate(item, textWidth) : item;
|
|
87
|
+
lines.push(padLine(`${dim(prefix)}${gray(text)}`, width));
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
lines.push(padLine(gray(" Ready for your next prompt"), width));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
lines.push(padLine(sepLine, width));
|
|
94
|
+
|
|
95
|
+
// 2. Flow keys
|
|
96
|
+
lines.push(padLine(` ${bold(accent("Flow keys"))}`, width));
|
|
97
|
+
const FLOW_KEY_ITEMS = [
|
|
98
|
+
{ key: "/", label: "commands" },
|
|
99
|
+
{ key: "tab", label: "complete" },
|
|
100
|
+
{ key: "ctrl+l", label: "model" },
|
|
101
|
+
{ key: "ctrl+c", label: "cancel" },
|
|
102
|
+
{ key: "alt+enter", label: "newline" },
|
|
103
|
+
];
|
|
104
|
+
const flowKeyItemText = (item: { key: string; label: string }) => {
|
|
105
|
+
const k = useColor ? chalk.dim(item.key) : item.key;
|
|
106
|
+
const l = useColor ? chalk.gray(item.label) : item.label;
|
|
107
|
+
return `${k} ${l}`;
|
|
59
108
|
};
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
109
|
+
const dot = unicode ? "·" : "*";
|
|
110
|
+
const flowSep = ` ${dim(dot)} `;
|
|
111
|
+
let currentFlowLine = "";
|
|
112
|
+
const flowLines: string[] = [];
|
|
113
|
+
for (const item of FLOW_KEY_ITEMS) {
|
|
114
|
+
const segment = flowKeyItemText(item);
|
|
115
|
+
const next = currentFlowLine ? `${currentFlowLine}${flowSep}${segment}` : segment;
|
|
116
|
+
if (currentFlowLine && visibleWidth(next) > width - 2) {
|
|
117
|
+
flowLines.push(` ${currentFlowLine}`);
|
|
118
|
+
currentFlowLine = segment;
|
|
119
|
+
} else {
|
|
120
|
+
currentFlowLine = next;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (currentFlowLine) flowLines.push(` ${currentFlowLine}`);
|
|
124
|
+
for (const line of flowLines.slice(0, 2)) {
|
|
125
|
+
lines.push(padLine(line, width));
|
|
71
126
|
}
|
|
72
|
-
|
|
127
|
+
|
|
128
|
+
lines.push(padLine(sepLine, width));
|
|
129
|
+
|
|
130
|
+
// 3. Project pulse
|
|
131
|
+
lines.push(padLine(` ${bold(accent("Project pulse"))}`, width));
|
|
132
|
+
const dotChar = unicode ? "●" : "*";
|
|
133
|
+
const lspStatus = useColor ? chalk.green(dotChar) : dotChar;
|
|
134
|
+
lines.push(padLine(` ${lspStatus} ${gray("TypeScript")} ${dim("ready")}`, width));
|
|
135
|
+
|
|
136
|
+
lines.push(padLine(sepLine, width));
|
|
137
|
+
|
|
138
|
+
// 4. Session trail
|
|
139
|
+
lines.push(padLine(` ${bold(accent("Session trail"))}`, width));
|
|
140
|
+
const recent = d.recentSessions ?? [];
|
|
141
|
+
if (recent.length > 0) {
|
|
142
|
+
const bulletPrefix = ` ${bulletChar} `;
|
|
143
|
+
const prefixWidth = visibleWidth(bulletPrefix);
|
|
144
|
+
for (const session of recent.slice(0, 3)) {
|
|
145
|
+
const timeSuffixRaw = ` (${session.timeAgo})`;
|
|
146
|
+
const timeWidth = visibleWidth(timeSuffixRaw);
|
|
147
|
+
const nameBudget = Math.max(1, width - prefixWidth - timeWidth);
|
|
148
|
+
const nameVis = visibleWidth(session.name);
|
|
149
|
+
const name = nameVis > nameBudget ? truncate(session.name, nameBudget) : session.name;
|
|
150
|
+
const bullet = useColor ? chalk.dim(bulletPrefix) : bulletPrefix;
|
|
151
|
+
const sName = useColor ? chalk.gray(name) : name;
|
|
152
|
+
const sTime = useColor ? chalk.dim(timeSuffixRaw) : timeSuffixRaw;
|
|
153
|
+
lines.push(padLine(`${bullet}${sName}${sTime}`, width));
|
|
154
|
+
}
|
|
155
|
+
} else {
|
|
156
|
+
lines.push(padLine(gray(" No saved sessions"), width));
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return lines;
|
|
73
160
|
}
|
|
74
161
|
|
|
75
162
|
function centerColumn(lines: string[], width: number): string[] {
|
|
@@ -173,13 +260,9 @@ export function renderWelcome(d: WelcomeData): string[] {
|
|
|
173
260
|
|
|
174
261
|
let content: string[];
|
|
175
262
|
if (wideMeta) {
|
|
176
|
-
const tableTitle = useColor ? chalk.bold("workspace") : "workspace";
|
|
177
263
|
const rightContent = [
|
|
178
264
|
"",
|
|
179
|
-
|
|
180
|
-
(useColor ? chalk.dim : (s: string) => s)(padLine("forge context", rightWidth, "center")),
|
|
181
|
-
"",
|
|
182
|
-
...metaRows(d, rightWidth, unicode, useColor),
|
|
265
|
+
...renderRightColumn(d, rightWidth, unicode, useColor),
|
|
183
266
|
"",
|
|
184
267
|
];
|
|
185
268
|
content = zipColumns(centerColumn(leftContent, leftWidth), rightContent, leftWidth, gap, rightWidth);
|
package/src/util/whats-new.ts
CHANGED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// src/types/playwriter.d.ts
|
|
2
|
-
// Declaration file to allow TypeScript to recognize the optional Playwriter CLI module.
|
|
3
|
-
// This is only needed for the example automation script in scripts/playwriter-apply.ts.
|
|
4
|
-
// The actual Playwriter package is expected to be installed globally or run via npx.
|
|
5
|
-
|
|
6
|
-
declare module "playwriter" {
|
|
7
|
-
export class Playwriter {
|
|
8
|
-
/** Connect to the running Chrome extension bridge */
|
|
9
|
-
connect(): Promise<void>;
|
|
10
|
-
/** Open a new page (tab) in the connected browser */
|
|
11
|
-
newPage(): Promise<any>;
|
|
12
|
-
/** Disconnect from the bridge */
|
|
13
|
-
disconnect(): Promise<void>;
|
|
14
|
-
}
|
|
15
|
-
}
|