Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/coding-agent/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@
### Added
- Added a deterministic quick-lane task classifier (`classifyQuickLane`) exposed through a read-only `gjc quick-lane classify` command. It is an auditable classification surface that performs no routing and is NOT wired into runtime routing: it only prints whether a task request carries quick-lane eligibility signals (explicit file paths, issue/PR numbers, named symbols, explicit tests, numbered steps, acceptance criteria, error references, code blocks, or an explicit `force:`/`!` override) or deep-lane exclusions (vague, ambiguous, exploratory, risk-sensitive, or multi-file/cross-contract scope), and it never alters deep-path defaults. The classifier is deterministic and fail-closed: any exclusion forces the deep lane even when a concrete anchor is present. The #3984 routing decision remains open.

- Gajae Pet now renders in iTerm2 using inline PNG frames, with the same reserved composer-side layout and lifecycle cleanup used by Kitty and Sixel.

- `session.list` now supports bounded pages with opaque continuation cursors and stable snapshot sequences. Internal ACP, coordinator, CLI, and broker-restart consumers drain every page so existing session discovery remains complete.
- Bounded-memory cold-session disk offloading is rollout-ready behind the `sessionMemory` settings namespace. `sessionMemory.mode` (default `"shadow"`) selects `off`/`shadow`/`enabled`: shadow measures without changing observable session behavior, and canary/default-on remain release-channel decisions rather than user-facing enum values. Fixed implementation budgets preserve the ≤64 MiB steady-state guarantee; transcript v5 stays authoritative and derived `.spill.*` sidecars remain disposable. Context materialization uses the typed `SessionContextTooLargeError` preflight, while `sessionMemory.contextOverflowRecovery` independently controls the async compact-once recovery path.
- Enabled explicit-path and managed-session resumes validate descriptor-bound commit metadata, base/tail hashes, terminal proof, and hot-record digests before retaining only the authenticated post-compaction tail. Managed TUI and nested review-subagent sessions read authoritative transcript ranges through retained/no-follow descriptor checks while keeping disposable sidecars in a verified per-process resident cache outside the managed tree. Fresh-process gates cover 120k compaction cycles, direct/captured forks, and one-million-record first build plus exact lazy reopen.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ const KITTY_DROP_FRACTION = 0.45;
const petKittyDropPx = (cellHeightPx: number): number =>
Math.min(Math.max(0, cellHeightPx - 1), Math.floor(cellHeightPx * KITTY_DROP_FRACTION));
const PET_RAISE_ROWS = 1;
/** iTerm2 has no sub-cell placement parameter; use transparent padding in a row above. */
const ITERM2_RAISE_FRACTION = 0.25;
const allocatedPetKittyImageIds = new Set<number>();

function allocatePetKittyImageId(): number {
Expand Down Expand Up @@ -326,7 +328,7 @@ export class GajaePetWidget {
kittyImageId: protocol === "kitty" ? this.#kittyImageId : undefined,
// iTerm2 receives an explicit 1:1 pixel size; keep its raster inside the
// same two-row footprint reserved for Kitty and Sixel.
iterm2TopPaddingPx: 0,
iterm2TopPaddingPx: Math.round(cell.heightPx * (1 - ITERM2_RAISE_FRACTION)),
iterm2BottomPaddingPx: 0,
});
this.#framedEditor.setReserve(this.#pixel.columns + PET_SIDE_MARGIN);
Expand Down
10 changes: 5 additions & 5 deletions packages/coding-agent/test/gajae-pet-widget.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ describe("GajaePetWidget", () => {
const payload = getEmitter()?.();
expect(payload).toContain("\x1b[28;76H");
expect(payload).toContain("\x1b]1337;File=");
expect(payload).toContain("width=36px;height=36px;preserveAspectRatio=0");
expect(payload).toContain("width=36px;height=50px;preserveAspectRatio=0");
expect(payload).toEndWith("\x1b\\");
} finally {
widget.dispose();
Expand All @@ -198,22 +198,22 @@ describe("GajaePetWidget", () => {
written.length = 0;

vi.advanceTimersByTime(1200);
expect(written.some(chunk => chunk.includes("\x1b[28;76H\x1b[4X") && chunk.includes("\x1b]1337;File="))).toBe(
expect(written.some(chunk => chunk.includes("\x1b[28;76H") && chunk.includes("\x1b]1337;File="))).toBe(
true,
);

setCellDimensions({ widthPx: 12, heightPx: 24 });
vi.advanceTimersByTime(100);
expect(getEmitter()?.()).toContain("width=48px;height=48px");
expect(getEmitter()?.()).toContain("width=48px;height=66px");

setTerminalSize(12, 30);
expect(getEmitter()?.()).toContain("\x1b[28;76H\x1b[4X");
expect(getEmitter()?.()).toContain("\x1b[28;76H");
setTerminalSize(80, 30);
expect(getEmitter()?.()).toContain("\x1b]1337;File=");

written.length = 0;
widget.setMode("off");
expect(written.some(chunk => chunk.includes("\x1b[28;76H\x1b[4X"))).toBe(true);
expect(written.some(chunk => chunk.includes("\x1b[28;76H"))).toBe(true);
} finally {
setCellDimensions(original);
widget.dispose();
Expand Down
52 changes: 52 additions & 0 deletions run-gjc-pet.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/bin/sh
set -eu

SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
SOURCE_DIR="$SCRIPT_DIR"
ORIGINAL_PATH=${PATH-}

if [ ! -f "$SOURCE_DIR/packages/coding-agent/src/cli.ts" ]; then
printf '%s\n' "ERROR: Gajae-Code checkout not found: $SOURCE_DIR" >&2
exit 1
fi

if ! command -v bun >/dev/null 2>&1; then
printf '%s\n' 'ERROR: bun is not available on PATH.' >&2
exit 1
fi

RUST_BIN=''
if command -v rustup >/dev/null 2>&1; then
RUSTC_PATH=$(rustup which rustc 2>/dev/null || true)
if [ -n "$RUSTC_PATH" ]; then
RUST_BIN=$(dirname -- "$RUSTC_PATH")
fi
fi

RUN_PATH=$ORIGINAL_PATH
if [ -n "$RUST_BIN" ]; then
RUN_PATH="$RUST_BIN:$RUN_PATH"
fi

# This launcher is for iTerm2. GJC normally disables image overlays inside a
# multiplexer because raw graphics escapes are not portable there; the explicit
# protocol tells GJC that this launcher's output is intended for iTerm2.
IMAGE_PROTOCOL=${GJC_FORCE_IMAGE_PROTOCOL:-iterm2}

if [ ! -f "$SOURCE_DIR/packages/natives/native/pi_natives.darwin-arm64.node" ]; then
printf '%s\n' 'Native addon is missing; building it once...'
(
cd "$SOURCE_DIR"
PATH="$RUN_PATH" GJC_FORCE_IMAGE_PROTOCOL="$IMAGE_PROTOCOL" bun --cwd=packages/natives run build
)
fi

printf '%s\n' "Starting local Gajae-Code from: $SOURCE_DIR"
(
cd "$SOURCE_DIR"
PATH="$RUN_PATH" GJC_FORCE_IMAGE_PROTOCOL="$IMAGE_PROTOCOL" bun packages/coding-agent/src/cli.ts "$@"
)

# PATH is deliberately scoped to the subshell above and remains unchanged here.
PATH=$ORIGINAL_PATH
export PATH
Loading