@gajae-code/coding-agent 0.10.1 → 0.10.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/CHANGELOG.md CHANGED
@@ -2,6 +2,23 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.10.2] - 2026-07-14
6
+
7
+ ### Added
8
+
9
+ - Gajae Pet selection is now terminal-capability aware: unsupported terminals show an actionable warning (with multiplexer-specific guidance for tmux/screen/zellij, including the `PI_FORCE_IMAGE_PROTOCOL=sixel` expert opt-in), `/pet` and Settings disable the unavailable `RedGajae`/`BlueGajae` choices while `off` stays selectable, a saved-but-unavailable choice is identified as `(saved)`, and the public command names are consistent across execution, completion, and inline hints (`/pet RedGajae`, `/pet BlueGajae`, `/pet off`, case-insensitive).
10
+
11
+ ### Changed
12
+
13
+ - Documented the current GPT-5.6 Codex and combo profile mappings as product judgments, including the durable `opus-codex` `anthropic/claude-sonnet-5` planner override and `fable-opus-codex` `anthropic/claude-opus-4-8:medium` planner.
14
+ - RPC clients can now durably select the machine-global default model and effective thinking level for subsequent messages, while project policy and resumed session history retain precedence; a late live-apply failure now restores the prior runtime model and thinking level without masking the original error.
15
+
16
+ ### Fixed
17
+
18
+ - Gajae Pet overlays no longer leak images or stale pixels across lifecycle changes: each widget owns a randomized Kitty image ID (deleted on disable, replace, switch, and dispose), the previous Sixel footprint is tracked and erased on movement, resize, and narrow-terminal fallback, replaced pet widgets are disposed before their successors install, and a saved pet preference survives editor replacement while graphics are still unavailable (so a delayed Sixel capability probe can still activate it). Teardown is exception-safe and idempotent: a failed or unavailable terminal write never aborts logical disposal or steals a successor widget's overlay slot, and Sixel/Kitty cleanup authority is retained until the erase is actually delivered so a later mode switch or dispose retries it.
19
+ - Gajae Pet cleanup that fails during final widget disposal is now retained by the TUI for retry, and Kitty image IDs remain reserved until their exact-ID delete is delivered.
20
+ - Fixed `gjc --tmux` startup from GNOME and other VTE terminals by recognizing `vte-spawn-*.scope` only when cgroup metadata proves matching user-manager ancestry (#2159).
21
+
5
22
  ## [0.10.1] - 2026-07-13
6
23
 
7
24
  ### Added
@@ -12,8 +29,11 @@
12
29
  ### Fixed
13
30
 
14
31
  - IRC deliveries now accept their exchange batch in the recipient's volatile current-session queue before recipient/main UI observations or sender success. Awaited deliveries generate the reply first, then accept the ordered incoming + auto-reply pair and commit the IRC roster claim before observation; provider failures and sender aborts before acceptance leave no ghost exchange, while observer failures after acceptance are isolated. This is not a durability guarantee: durable history injection remains a later flush and no fsync, recovery, persistent IDs, or deduplication was added.
32
+ - `/model` role-agent assignments now replace active model-profile overrides immediately, so changing architect, critic, planner, or executor models and reasoning levels takes effect in the current session and remains persisted afterward.
15
33
  - Print mode now records terminal text-mode errors as exit status 1 (or 78 for context overflow) without bypassing output quiescence or session disposal. It retains JSON event delivery through disposal and suppresses `EPIPE` from its owned stdout; `ERR_STREAM_DESTROYED` is suppressed only after that `EPIPE` has latched, while other output failures remain errors.
16
34
  - Extension contexts now receive a defensive copy from `getSystemPrompt()` instead of the live mutable system-prompt array, so an in-place mutation by an in-process extension can no longer bypass context-revision tracking and serve stale display-only context-usage estimates.
35
+ - Preserved clipboard image attachments when the interactive editor clears the composer before dispatching the submit callback, so Alt+V image placeholders still send their image blocks instead of placeholder-only text (#2126).
36
+ - Completed bracketed-paste input now returns a manually paged transcript to live output before the paste is dispatched, including asynchronous consumed and unconsumed paste paths.
17
37
 
18
38
  ## [0.10.0] - 2026-07-12
19
39
 
@@ -53,6 +53,7 @@ export declare class GajaePetWidget {
53
53
  * eye-roll it fires the signature burst once (RedGajae flex, BlueGajae para-para
54
54
  * then sob) so the selector demos the animation instead of waiting the random gap. */
55
55
  previewMode(mode: PetMode): void;
56
+ commitPreviewMode(mode: PetMode): void;
56
57
  dispose(): void;
57
58
  /** Re-mount the composer editor (framed when a skin is active) after an overlay. */
58
59
  remountComposer(): void;
@@ -0,0 +1,37 @@
1
+ import { type SelectItem } from "@gajae-code/tui";
2
+ export type PetPixelProtocol = "sixel" | "kitty";
3
+ export declare const PET_UNAVAILABLE_DESCRIPTION = "Unavailable: requires compatible Kitty or Sixel overlay rendering";
4
+ export declare const PET_SAVED_UNAVAILABLE_DESCRIPTION = "Saved, unavailable \u2014 requires compatible Kitty or Sixel overlay rendering";
5
+ export declare const PET_UNAVAILABLE_WARNING = "\u26A0 Pets aren\u2019t available in this terminal. Its image support isn\u2019t compatible with Gajae Pet\u2019s overlay rendering yet. Try Kitty, Ghostty, WezTerm, or a terminal with compatible Sixel support.";
6
+ export declare function getPetUnavailableWarning(env?: NodeJS.ProcessEnv): string;
7
+ export declare function getPetPixelProtocol(): PetPixelProtocol | null;
8
+ export declare function isPetAvailable(): boolean;
9
+ export declare function createPetSelectItems(options: ReadonlyArray<SelectItem>, currentValue: string, available: boolean): SelectItem[];
10
+ /**
11
+ * Grace period before declaring the terminal pet-incapable at startup. The
12
+ * asynchronous Sixel capability probe starts inside `TUI.start()` and answers
13
+ * within its own 250 ms deadline; this margin covers probe scheduling so a
14
+ * supported terminal is never told it is incompatible while the probe is
15
+ * still in flight.
16
+ */
17
+ export declare const PET_CAPABILITY_SETTLE_MS = 1000;
18
+ /**
19
+ * Whether the asynchronous startup Sixel capability probe may still enable
20
+ * graphics for this session, meaning current unavailability is not final.
21
+ */
22
+ export declare function isPetCapabilityProbePending(env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform): boolean;
23
+ /**
24
+ * Deliver the pet-unavailable startup warning only once the capability
25
+ * question is settled. With no probe pending, unavailability is final and
26
+ * `onUnavailable` fires immediately. While a probe may still enable
27
+ * graphics, the warning is deferred: a protocol-change event cancels it (the
28
+ * saved pet re-applies through the existing subscription), and only the
29
+ * settle deadline passing with the terminal still unavailable emits it.
30
+ * Returns a disposer that cancels the pending decision.
31
+ */
32
+ export declare function warnWhenPetCapabilitySettled(options: {
33
+ probePending: boolean;
34
+ isAvailable?: () => boolean;
35
+ onUnavailable: () => void;
36
+ settleMs?: number;
37
+ }): () => void;
@@ -6,6 +6,6 @@ import type { PetMode } from "./gajae-pet-widget";
6
6
  */
7
7
  export declare class PetSelectorComponent extends Container {
8
8
  #private;
9
- constructor(current: PetMode, onSelect: (mode: PetMode) => void, onCancel: () => void, onPreview: (mode: PetMode) => void);
9
+ constructor(current: PetMode, onSelect: (mode: PetMode) => void, onCancel: () => void, onPreview: (mode: PetMode) => void, available: boolean);
10
10
  getSelectList(): SelectList;
11
11
  }
@@ -20,6 +20,8 @@ export interface SettingsRuntimeContext {
20
20
  availableModelProfiles: string[];
21
21
  /** Working directory for plugins tab */
22
22
  cwd: string;
23
+ /** Whether this terminal can render the pet overlay. */
24
+ petAvailable?: boolean;
23
25
  }
24
26
  /** Status line settings subset for preview */
25
27
  export interface StatusLinePreviewSettings {
@@ -41,6 +43,13 @@ export interface SettingsCallbacks {
41
43
  onThemePreviewCancel?: (theme: string) => void | Promise<void>;
42
44
  /** Called to live-preview the gajae pet skin while browsing the pet setting. */
43
45
  onPetPreview?: (mode: string) => void;
46
+ /**
47
+ * Commit a pet mode through the shared result-returning policy. The policy
48
+ * rechecks capability immediately before mutation and owns persistence, so
49
+ * the settings surface never persists `pet.mode` ahead of acceptance.
50
+ * Returns whether the commit was accepted.
51
+ */
52
+ onPetCommit?: (mode: string) => boolean;
44
53
  /** Called for status line preview while configuring */
45
54
  onStatusLinePreview?: (settings: StatusLinePreviewSettings) => void;
46
55
  /** Get current rendered status line for inline preview */
@@ -139,8 +139,9 @@ export declare class InteractiveMode implements InteractiveModeContext {
139
139
  updateEditorChrome(): void;
140
140
  updateEditorBorderColor(): void;
141
141
  updateEditorTopBorder(): void;
142
- setPetMode(mode: PetMode): void;
142
+ setPetMode(mode: PetMode): boolean;
143
143
  previewPetMode(mode: PetMode): void;
144
+ commitPetPreviewMode(mode: PetMode): boolean;
144
145
  restoreComposer(): void;
145
146
  rebuildChatFromMessages(policy: TranscriptRebuildPolicy): void;
146
147
  /** Apply any deferred model switch after the current stream ends. */
@@ -153,9 +153,19 @@ export interface InteractiveModeContext {
153
153
  setWorkingMessage(message?: string): void;
154
154
  applyPendingWorkingMessage(): void;
155
155
  ensureLoadingAnimation(): void;
156
- setPetMode(mode: PetMode): void;
156
+ /**
157
+ * Commit a pet mode through the shared result-returning policy: capability
158
+ * is rechecked immediately before mutation and the preference persists only
159
+ * on acceptance. Returns whether the commit was accepted.
160
+ */
161
+ setPetMode(mode: PetMode): boolean;
157
162
  /** Live-preview a pet skin during a selector without persisting. */
158
163
  previewPetMode(mode: PetMode): void;
164
+ /**
165
+ * Commit a settings-overlay pet change without re-mounting the composer.
166
+ * Same shared commit policy and result semantics as `setPetMode`.
167
+ */
168
+ commitPetPreviewMode(mode: PetMode): boolean;
159
169
  /** Re-mount the composer (pet-aware) after an overlay/selector closes. */
160
170
  restoreComposer(): void;
161
171
  startPendingSubmission(input: {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.10.1",
4
+ "version": "0.10.2",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -49,12 +49,12 @@
49
49
  "@agentclientprotocol/sdk": "1.2.1",
50
50
  "@babel/parser": "^7.29.3",
51
51
  "@mozilla/readability": "^0.6.0",
52
- "@gajae-code/stats": "0.10.1",
53
- "@gajae-code/agent-core": "0.10.1",
54
- "@gajae-code/ai": "0.10.1",
55
- "@gajae-code/natives": "0.10.1",
56
- "@gajae-code/tui": "0.10.1",
57
- "@gajae-code/utils": "0.10.1",
52
+ "@gajae-code/stats": "0.10.2",
53
+ "@gajae-code/agent-core": "0.10.2",
54
+ "@gajae-code/ai": "0.10.2",
55
+ "@gajae-code/natives": "0.10.2",
56
+ "@gajae-code/tui": "0.10.2",
57
+ "@gajae-code/utils": "0.10.2",
58
58
  "@puppeteer/browsers": "^2.13.0",
59
59
  "@types/turndown": "5.0.6",
60
60
  "@xterm/headless": "^6.0.0",
@@ -70,25 +70,25 @@ const profile = (
70
70
 
71
71
  export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
72
72
  profile("codex-eco", ["openai-codex"], {
73
- default: "openai-codex/gpt-5.6-terra:high",
74
- executor: "openai-codex/gpt-5.6-luna:high",
75
- planner: "openai-codex/gpt-5.6-terra:medium",
76
- critic: "openai-codex/gpt-5.6-terra:high",
77
- architect: "openai-codex/gpt-5.6-sol:medium",
73
+ default: "openai-codex/gpt-5.6-terra:low",
74
+ executor: "openai-codex/gpt-5.6-luna:low",
75
+ planner: "openai-codex/gpt-5.6-luna:high",
76
+ critic: "openai-codex/gpt-5.6-terra:xhigh",
77
+ architect: "openai-codex/gpt-5.6-terra:high",
78
78
  }),
79
79
  profile("codex-medium", ["openai-codex"], {
80
- default: "openai-codex/gpt-5.6-sol:medium",
81
- executor: "openai-codex/gpt-5.6-terra:xhigh",
80
+ default: "openai-codex/gpt-5.6-sol:low",
81
+ executor: "openai-codex/gpt-5.6-terra:low",
82
82
  planner: "openai-codex/gpt-5.6-terra:high",
83
- critic: "openai-codex/gpt-5.6-terra:xhigh",
83
+ critic: "openai-codex/gpt-5.6-sol:xhigh",
84
84
  architect: "openai-codex/gpt-5.6-sol:high",
85
85
  }),
86
86
  profile("codex-pro", ["openai-codex"], {
87
- default: "openai-codex/gpt-5.6-sol:xhigh",
88
- executor: "openai-codex/gpt-5.6-terra:xhigh",
87
+ default: "openai-codex/gpt-5.6-sol:medium",
88
+ executor: "openai-codex/gpt-5.6-terra:medium",
89
89
  planner: "openai-codex/gpt-5.6-sol:high",
90
- critic: "openai-codex/gpt-5.6-sol:xhigh",
91
- architect: "openai-codex/gpt-5.6-sol:max",
90
+ critic: "openai-codex/gpt-5.6-sol:max",
91
+ architect: "openai-codex/gpt-5.6-sol:xhigh",
92
92
  }),
93
93
  profile("opencodego", ["opencode-go"], {
94
94
  default: "opencode-go/kimi-k2.6",
@@ -256,21 +256,21 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
256
256
  }),
257
257
  profile("opus-codex", ["anthropic", "openai-codex"], {
258
258
  default: "anthropic/claude-opus-4-8:xhigh",
259
- executor: "openai-codex/gpt-5.6-terra:xhigh",
260
- planner: "openai-codex/gpt-5.6-terra:high",
261
- critic: "openai-codex/gpt-5.6-terra:xhigh",
262
- architect: "openai-codex/gpt-5.6-sol:xhigh",
259
+ executor: "openai-codex/gpt-5.6-terra:low",
260
+ planner: "anthropic/claude-sonnet-5",
261
+ critic: "openai-codex/gpt-5.6-sol:xhigh",
262
+ architect: "openai-codex/gpt-5.6-sol:high",
263
263
  }),
264
264
  profile("codex-opencodego", ["openai-codex", "opencode-go"], {
265
- default: "openai-codex/gpt-5.6-terra:xhigh",
265
+ default: "openai-codex/gpt-5.6-sol:low",
266
266
  executor: "opencode-go/deepseek-v4-pro",
267
267
  planner: "opencode-go/kimi-k2.6",
268
268
  critic: "opencode-go/mimo-v2.5-pro",
269
- architect: "openai-codex/gpt-5.6-sol:xhigh",
269
+ architect: "openai-codex/gpt-5.6-sol:high",
270
270
  }),
271
271
  profile("fable-opus-codex", ["anthropic", "openai-codex"], {
272
272
  default: "anthropic/claude-fable-5:high",
273
- executor: "openai-codex/gpt-5.6-terra:xhigh",
273
+ executor: "openai-codex/gpt-5.6-terra:medium",
274
274
  planner: "anthropic/claude-opus-4-8:medium",
275
275
  critic: "anthropic/claude-opus-4-8:high",
276
276
  architect: "openai-codex/gpt-5.6-sol:xhigh",
@@ -35,7 +35,7 @@ function buildArgumentCompletions(subcommands: SubcommandDef[]): (prefix: string
35
35
  if (argumentPrefix.includes(" ")) return null; // past the subcommand
36
36
  const lower = argumentPrefix.toLowerCase();
37
37
  const matches = subcommands
38
- .filter(s => s.name.startsWith(lower))
38
+ .filter(s => s.name.toLowerCase().startsWith(lower))
39
39
  .map(s => ({
40
40
  value: `${s.name} `,
41
41
  label: s.name,
@@ -59,7 +59,7 @@ function buildSubcommandInlineHint(subcommands: SubcommandDef[]): (argumentText:
59
59
  // Still typing subcommand name — show remaining chars + usage
60
60
  const prefix = trimmed.toLowerCase();
61
61
  if (prefix.length === 0) return null;
62
- const match = subcommands.find(s => s.name.startsWith(prefix));
62
+ const match = subcommands.find(s => s.name.toLowerCase().startsWith(prefix));
63
63
  if (!match) return null;
64
64
  const remaining = match.name.slice(prefix.length);
65
65
  return remaining + (match.usage ? ` ${match.usage}` : "");
@@ -68,7 +68,7 @@ function buildSubcommandInlineHint(subcommands: SubcommandDef[]): (argumentText:
68
68
  // Subcommand typed — show remaining usage params
69
69
  const subName = trimmed.slice(0, spaceIndex).toLowerCase();
70
70
  const afterSub = trimmed.slice(spaceIndex + 1);
71
- const sub = subcommands.find(s => s.name === subName);
71
+ const sub = subcommands.find(s => s.name.toLowerCase() === subName);
72
72
  if (!sub?.usage) return null;
73
73
 
74
74
  if (afterSub.length > 0) {
@@ -86,7 +86,10 @@ export function classifyCgroup(input: { platform: NodeJS.Platform; cgroupText?:
86
86
  diagnostic: "service_cgroup_inheritance",
87
87
  };
88
88
  const scope = paths.find(value => /(?:^|\/)(?:user|session|app|init|gjc)[^/]*\.scope(?:\/|$)/.test(value));
89
- if (scope) return { classification: "safe", scope };
89
+ const vteScope = paths.find(value =>
90
+ /^\/user\.slice\/user-(\d+)\.slice\/user@\1\.service(?:\/[^/]+)*\/vte-spawn-[A-Za-z0-9_.-]+\.scope$/.test(value),
91
+ );
92
+ if (scope || vteScope) return { classification: "safe", scope: scope ?? vteScope };
90
93
  if (paths.every(value => value === "/")) return { classification: "safe", scope: "/" };
91
94
  return {
92
95
  classification: "unverifiable",