@gajae-code/coding-agent 0.9.5 → 0.10.0

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.
Files changed (194) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/types/cli/classify-install-target.d.ts +0 -10
  3. package/dist/types/cli/daemon-cli.d.ts +2 -0
  4. package/dist/types/cli/initial-message.d.ts +1 -1
  5. package/dist/types/cli/malloc-env-guard.d.ts +65 -0
  6. package/dist/types/cli/malloc-env-guard.test.d.ts +1 -0
  7. package/dist/types/cli/notify-cli.d.ts +3 -1
  8. package/dist/types/cli/session-picker.d.ts +4 -3
  9. package/dist/types/cli/update-cli.d.ts +22 -3
  10. package/dist/types/cli.d.ts +4 -0
  11. package/dist/types/commands/daemon.d.ts +6 -2
  12. package/dist/types/commands/launch.d.ts +1 -0
  13. package/dist/types/commands/notify.d.ts +6 -0
  14. package/dist/types/commit/analysis/conventional.d.ts +1 -1
  15. package/dist/types/commit/analysis/summary.d.ts +1 -1
  16. package/dist/types/commit/changelog/generate.d.ts +1 -1
  17. package/dist/types/commit/changelog/index.d.ts +2 -2
  18. package/dist/types/commit/map-reduce/map-phase.d.ts +1 -1
  19. package/dist/types/commit/map-reduce/reduce-phase.d.ts +1 -1
  20. package/dist/types/config/keybindings.d.ts +5 -0
  21. package/dist/types/config/model-profile-activation.d.ts +1 -0
  22. package/dist/types/config/settings-schema.d.ts +47 -7
  23. package/dist/types/coordinator-mcp/model-preset.d.ts +45 -0
  24. package/dist/types/coordinator-mcp/server.d.ts +67 -6
  25. package/dist/types/daemon/control-types.d.ts +10 -0
  26. package/dist/types/daemon/operator-contract.d.ts +47 -0
  27. package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.d.ts +4 -0
  28. package/dist/types/discovery/helpers.d.ts +1 -1
  29. package/dist/types/discovery/substitute-plugin-root.d.ts +0 -4
  30. package/dist/types/gjc-runtime/launch-tmux.d.ts +26 -7
  31. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +34 -3
  32. package/dist/types/gjc-runtime/tmux-common.d.ts +6 -0
  33. package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +5 -0
  34. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +309 -0
  35. package/dist/types/gjc-runtime/tmux-sessions.d.ts +49 -17
  36. package/dist/types/internal-urls/local-protocol.d.ts +13 -9
  37. package/dist/types/main.d.ts +66 -2
  38. package/dist/types/modes/acp/acp-agent.d.ts +19 -2
  39. package/dist/types/modes/acp/acp-mode.d.ts +12 -0
  40. package/dist/types/modes/components/assistant-message.d.ts +1 -1
  41. package/dist/types/modes/components/custom-editor.d.ts +2 -0
  42. package/dist/types/modes/components/gajae-pet-widget.d.ts +59 -0
  43. package/dist/types/modes/components/hook-selector.d.ts +5 -0
  44. package/dist/types/modes/components/irc-sidebar.d.ts +32 -0
  45. package/dist/types/modes/components/pet-selector.d.ts +11 -0
  46. package/dist/types/modes/components/session-selector.d.ts +22 -9
  47. package/dist/types/modes/components/settings-selector.d.ts +2 -0
  48. package/dist/types/modes/components/tool-execution.d.ts +1 -0
  49. package/dist/types/modes/components/user-message.d.ts +2 -1
  50. package/dist/types/modes/controllers/event-controller.d.ts +4 -0
  51. package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
  52. package/dist/types/modes/interactive-mode.d.ts +24 -2
  53. package/dist/types/modes/irc-observation-ledger.d.ts +22 -0
  54. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +8 -0
  55. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +5 -0
  56. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +45 -0
  57. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +42 -2
  58. package/dist/types/modes/theme/defaults/index.d.ts +568 -568
  59. package/dist/types/modes/types.d.ts +28 -2
  60. package/dist/types/modes/utils/abort-message.d.ts +1 -1
  61. package/dist/types/modes/utils/irc-message.d.ts +38 -0
  62. package/dist/types/modes/utils/ui-helpers.d.ts +13 -4
  63. package/dist/types/notifications/config.d.ts +34 -0
  64. package/dist/types/notifications/daemon-paths.d.ts +7 -0
  65. package/dist/types/notifications/index.d.ts +27 -0
  66. package/dist/types/notifications/lifecycle-control-runtime.d.ts +12 -4
  67. package/dist/types/notifications/notification-service.d.ts +144 -0
  68. package/dist/types/notifications/rate-limit-pool.d.ts +27 -9
  69. package/dist/types/notifications/telegram-daemon-control.d.ts +6 -0
  70. package/dist/types/notifications/telegram-daemon.d.ts +130 -3
  71. package/dist/types/notifications/telegram-reference.d.ts +19 -2
  72. package/dist/types/notifications/topic-registry.d.ts +24 -4
  73. package/dist/types/registry/agent-registry.d.ts +2 -0
  74. package/dist/types/rlm/index.d.ts +1 -1
  75. package/dist/types/sdk.d.ts +2 -0
  76. package/dist/types/secrets/obfuscator.d.ts +1 -1
  77. package/dist/types/session/agent-session.d.ts +26 -2
  78. package/dist/types/session/cache-economics.d.ts +79 -0
  79. package/dist/types/session/provider-safety-stop.d.ts +5 -0
  80. package/dist/types/session/session-manager.d.ts +124 -4
  81. package/dist/types/session/session-storage.d.ts +155 -13
  82. package/dist/types/setup/credential-auto-import.d.ts +2 -2
  83. package/dist/types/task/executor.d.ts +3 -0
  84. package/dist/types/task/receipt.d.ts +3 -1
  85. package/dist/types/task/types.d.ts +8 -0
  86. package/dist/types/tools/ask-answer-registry.d.ts +5 -0
  87. package/dist/types/tools/ask.d.ts +25 -1
  88. package/dist/types/tools/bash.d.ts +1 -1
  89. package/dist/types/tools/browser/tab-supervisor.d.ts +6 -0
  90. package/dist/types/tools/index.d.ts +58 -6
  91. package/dist/types/tools/telegram-send.d.ts +7 -0
  92. package/dist/types/utils/external-editor.d.ts +2 -0
  93. package/package.json +9 -9
  94. package/scripts/compile-args.ts +8 -2
  95. package/scripts/g004-tmux-smoke.ts +196 -36
  96. package/src/cli/daemon-cli.ts +19 -29
  97. package/src/cli/malloc-env-guard.test.ts +104 -0
  98. package/src/cli/malloc-env-guard.ts +149 -0
  99. package/src/cli/notify-cli.ts +78 -14
  100. package/src/cli/session-picker.ts +23 -40
  101. package/src/cli/update-cli.ts +56 -37
  102. package/src/cli.ts +50 -10
  103. package/src/commands/daemon.ts +19 -5
  104. package/src/commands/harness.ts +515 -47
  105. package/src/commands/launch.ts +11 -3
  106. package/src/commands/notify.ts +5 -1
  107. package/src/commands/session.ts +6 -1
  108. package/src/config/keybindings.ts +5 -0
  109. package/src/config/model-profile-activation.ts +1 -1
  110. package/src/config/model-profiles.ts +23 -23
  111. package/src/config/settings-schema.ts +41 -1
  112. package/src/coordinator-mcp/model-preset.ts +100 -0
  113. package/src/coordinator-mcp/server.ts +2653 -425
  114. package/src/daemon/control-types.ts +11 -0
  115. package/src/daemon/operator-contract.ts +121 -0
  116. package/src/deep-interview/render-middleware.ts +67 -2
  117. package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +57 -17
  118. package/src/defaults/gjc/extensions/grok-cli-vendor/src/payload/sanitize.ts +15 -2
  119. package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +5 -1
  120. package/src/gjc-runtime/launch-tmux.ts +702 -135
  121. package/src/gjc-runtime/session-state-sidecar.ts +756 -135
  122. package/src/gjc-runtime/team-runtime.ts +6 -0
  123. package/src/gjc-runtime/tmux-common.ts +26 -7
  124. package/src/gjc-runtime/tmux-gc.ts +52 -9
  125. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +185 -0
  126. package/src/gjc-runtime/tmux-owner-isolation.ts +2060 -0
  127. package/src/gjc-runtime/tmux-sessions.ts +871 -68
  128. package/src/internal-urls/docs-index.generated.ts +9 -8
  129. package/src/internal-urls/local-protocol.ts +29 -10
  130. package/src/main.ts +298 -75
  131. package/src/modes/acp/acp-agent.ts +728 -98
  132. package/src/modes/acp/acp-mode.ts +29 -2
  133. package/src/modes/components/assistant-message.ts +32 -3
  134. package/src/modes/components/bash-execution.ts +43 -13
  135. package/src/modes/components/custom-editor.ts +5 -0
  136. package/src/modes/components/gajae-pet-widget.ts +360 -0
  137. package/src/modes/components/hook-selector.ts +12 -0
  138. package/src/modes/components/irc-sidebar.ts +206 -0
  139. package/src/modes/components/pet-selector.ts +55 -0
  140. package/src/modes/components/session-selector.ts +222 -221
  141. package/src/modes/components/settings-selector.ts +10 -0
  142. package/src/modes/components/tool-execution.ts +47 -6
  143. package/src/modes/components/user-message.ts +26 -9
  144. package/src/modes/controllers/command-controller.ts +28 -2
  145. package/src/modes/controllers/event-controller.ts +159 -36
  146. package/src/modes/controllers/extension-ui-controller.ts +36 -17
  147. package/src/modes/controllers/input-controller.ts +8 -2
  148. package/src/modes/controllers/selector-controller.ts +62 -15
  149. package/src/modes/interactive-mode.ts +183 -7
  150. package/src/modes/irc-observation-ledger.ts +127 -0
  151. package/src/modes/shared/agent-wire/deep-interview-gate.ts +45 -2
  152. package/src/modes/shared/agent-wire/unattended-session.ts +288 -1
  153. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +130 -20
  154. package/src/modes/types.ts +34 -2
  155. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  156. package/src/modes/utils/irc-message.ts +138 -0
  157. package/src/modes/utils/ui-helpers.ts +216 -50
  158. package/src/notifications/config.ts +44 -0
  159. package/src/notifications/daemon-paths.ts +8 -0
  160. package/src/notifications/index.ts +535 -75
  161. package/src/notifications/lifecycle-control-runtime.ts +930 -77
  162. package/src/notifications/notification-service.ts +710 -0
  163. package/src/notifications/rate-limit-pool.ts +46 -12
  164. package/src/notifications/telegram-daemon-cli.ts +2 -0
  165. package/src/notifications/telegram-daemon-control.ts +27 -2
  166. package/src/notifications/telegram-daemon.ts +635 -94
  167. package/src/notifications/telegram-reference.ts +73 -13
  168. package/src/notifications/topic-registry.ts +86 -9
  169. package/src/prompts/system/irc-peer-roster.md +1 -0
  170. package/src/prompts/system/subagent-system-prompt.md +1 -0
  171. package/src/prompts/system/system-prompt.md +1 -0
  172. package/src/prompts/tools/irc.md +1 -1
  173. package/src/registry/agent-registry.ts +3 -0
  174. package/src/sdk.ts +52 -1
  175. package/src/secrets/obfuscator.ts +4 -2
  176. package/src/session/agent-session.ts +396 -145
  177. package/src/session/cache-economics.ts +275 -0
  178. package/src/session/provider-safety-stop.ts +9 -0
  179. package/src/session/session-dump-format.ts +6 -0
  180. package/src/session/session-manager.ts +809 -39
  181. package/src/session/session-storage.ts +582 -38
  182. package/src/slash-commands/builtin-registry.ts +143 -9
  183. package/src/task/executor.ts +12 -3
  184. package/src/task/index.ts +8 -0
  185. package/src/task/receipt.ts +7 -2
  186. package/src/task/types.ts +26 -0
  187. package/src/tools/ask-answer-registry.ts +25 -0
  188. package/src/tools/ask.ts +355 -33
  189. package/src/tools/browser/tab-supervisor.ts +63 -6
  190. package/src/tools/browser.ts +8 -3
  191. package/src/tools/index.ts +81 -6
  192. package/src/tools/sqlite-reader.ts +8 -4
  193. package/src/tui/output-block.ts +18 -6
  194. package/src/utils/external-editor.ts +6 -1
@@ -13,19 +13,24 @@ import { prepareLaunchWorktree } from "../gjc-runtime/launch-worktree";
13
13
  import {
14
14
  GJC_COORDINATOR_SESSION_ID_ENV,
15
15
  GJC_COORDINATOR_SESSION_STATE_FILE_ENV,
16
+ GJC_TMUX_OWNER_GENERATION_ENV,
16
17
  } from "../gjc-runtime/session-state-sidecar";
17
18
  import { runRootCommand } from "../main";
18
19
  import { prepareAcpTerminalAuthArgs } from "../modes/acp/terminal-auth";
19
20
 
20
- async function persistCoordinatorLaunchFailure(error: unknown, cwd: string): Promise<void> {
21
- const stateFile = process.env[GJC_COORDINATOR_SESSION_STATE_FILE_ENV]?.trim();
21
+ export async function persistCoordinatorLaunchFailure(
22
+ error: unknown,
23
+ cwd: string,
24
+ env: NodeJS.ProcessEnv = process.env,
25
+ ): Promise<void> {
26
+ const stateFile = env[GJC_COORDINATOR_SESSION_STATE_FILE_ENV]?.trim();
22
27
  if (!stateFile) return;
23
28
  const message = error instanceof Error ? error.message : String(error);
24
29
  const code = message.split(":", 1)[0] || "launch_failed";
25
30
  const now = new Date().toISOString();
26
31
  const payload = {
27
32
  schema_version: 1,
28
- session_id: process.env[GJC_COORDINATOR_SESSION_ID_ENV]?.trim() || null,
33
+ session_id: env[GJC_COORDINATOR_SESSION_ID_ENV]?.trim() || null,
29
34
  state: "errored",
30
35
  ready_for_input: false,
31
36
  updated_at: now,
@@ -45,6 +50,9 @@ async function persistCoordinatorLaunchFailure(error: unknown, cwd: string): Pro
45
50
  truncated: false,
46
51
  },
47
52
  error: { code, message, recoverable: true },
53
+ ...(env[GJC_COORDINATOR_SESSION_ID_ENV]?.trim()
54
+ ? { owner_generation: env[GJC_TMUX_OWNER_GENERATION_ENV] ?? null }
55
+ : {}),
48
56
  };
49
57
  await fs.mkdir(path.dirname(stateFile), { recursive: true });
50
58
  await Bun.write(stateFile, `${JSON.stringify(payload, null, 2)}\n`);
@@ -5,7 +5,7 @@ import { Args, Command, Flags } from "@gajae-code/utils/cli";
5
5
  import { type NotifyAction, type NotifyCommandArgs, runNotifyCliCommand } from "../cli/notify-cli";
6
6
  import { initTheme } from "../modes/theme/theme";
7
7
 
8
- const ACTIONS: NotifyAction[] = ["setup", "status", "daemon-internal"];
8
+ const ACTIONS: NotifyAction[] = ["setup", "status", "health", "test", "recovery", "daemon-internal"];
9
9
 
10
10
  export default class Notify extends Command {
11
11
  static description = "Configure Telegram notifications";
@@ -28,6 +28,8 @@ export default class Notify extends Command {
28
28
  token: Flags.string({ description: "Telegram bot token (non-interactive setup)" }),
29
29
  "chat-id": Flags.string({ description: "Telegram chat id to pair (non-interactive setup)" }),
30
30
  redact: Flags.boolean({ description: "Enable redaction of remote notification content" }),
31
+ probe: Flags.boolean({ description: "notify health: probe Telegram reachability (getMe)" }),
32
+ message: Flags.string({ description: "notify test: custom message body" }),
31
33
  "owner-id": Flags.string({ description: "Internal: daemon owner id" }),
32
34
  "agent-dir": Flags.string({ description: "Internal: agent dir for the daemon" }),
33
35
  };
@@ -53,6 +55,8 @@ export default class Notify extends Command {
53
55
  token: flags.token as string | undefined,
54
56
  chatId: (flags as Record<string, unknown>)["chat-id"] as string | undefined,
55
57
  redact: Boolean(flags.redact),
58
+ probe: Boolean(flags.probe),
59
+ message: flags.message as string | undefined,
56
60
  };
57
61
 
58
62
  if (action !== "daemon-internal") await initTheme();
@@ -145,7 +145,12 @@ export default class Session extends Command {
145
145
  }
146
146
 
147
147
  if (action === "force-close" || action === "force-remove") {
148
- const closed = forceCloseGjcTmuxSession(sessionName, process.env, flags["session-id"], flags["state-file"]);
148
+ const closed = await forceCloseGjcTmuxSession(
149
+ sessionName,
150
+ process.env,
151
+ flags["session-id"],
152
+ flags["state-file"],
153
+ );
149
154
  if (json) {
150
155
  writeJson({ ok: true, session: sessionJson(closed) });
151
156
  return;
@@ -52,6 +52,7 @@ interface AppKeybindings {
52
52
  "app.plan.toggle": true;
53
53
  "app.history.search": true;
54
54
  "app.stt.toggle": true;
55
+ "app.irc.sidebar.toggle": true;
55
56
  }
56
57
 
57
58
  export type AppKeybinding = keyof AppKeybindings;
@@ -214,6 +215,10 @@ export const KEYBINDINGS = {
214
215
  defaultKeys: "alt+h",
215
216
  description: "Toggle speech-to-text",
216
217
  },
218
+ "app.irc.sidebar.toggle": {
219
+ defaultKeys: "alt+i",
220
+ description: "Toggle IRC sidebar",
221
+ },
217
222
  } as const satisfies KeybindingDefinitions;
218
223
 
219
224
  /**
@@ -181,7 +181,7 @@ export function formatModelProfileCredentialError(profileLabel: string, provider
181
181
  return `Model profile "${profileLabel}" requires credentials for: ${providers.join(", ")}. Run /login and configure the missing provider(s), then retry.`;
182
182
  }
183
183
 
184
- function resolveModelProfileName(profileName: string, profiles: ReadonlyMap<string, unknown>): string {
184
+ export function resolveModelProfileName(profileName: string, profiles: ReadonlyMap<string, unknown>): string {
185
185
  // A retired-name alias is fallback-only: never shadow a profile that actually
186
186
  // exists under the requested name (e.g. a user-defined `codex-standard`).
187
187
  if (profiles.has(profileName)) return profileName;
@@ -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.5:low",
74
- executor: "openai-codex/gpt-5.5:minimal",
75
- planner: "openai-codex/gpt-5.5:low",
76
- critic: "openai-codex/gpt-5.5:medium",
77
- architect: "openai-codex/gpt-5.5:high",
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",
78
78
  }),
79
79
  profile("codex-medium", ["openai-codex"], {
80
- default: "openai-codex/gpt-5.5:medium",
81
- executor: "openai-codex/gpt-5.5:low",
82
- planner: "openai-codex/gpt-5.5:medium",
83
- critic: "openai-codex/gpt-5.5:high",
84
- architect: "openai-codex/gpt-5.5:xhigh",
80
+ default: "openai-codex/gpt-5.6-sol:medium",
81
+ executor: "openai-codex/gpt-5.6-terra:xhigh",
82
+ planner: "openai-codex/gpt-5.6-terra:high",
83
+ critic: "openai-codex/gpt-5.6-terra:xhigh",
84
+ architect: "openai-codex/gpt-5.6-sol:high",
85
85
  }),
86
86
  profile("codex-pro", ["openai-codex"], {
87
- default: "openai-codex/gpt-5.5:xhigh",
88
- executor: "openai-codex/gpt-5.5:medium",
89
- planner: "openai-codex/gpt-5.5:high",
90
- critic: "openai-codex/gpt-5.5:xhigh",
91
- architect: "openai-codex/gpt-5.5:xhigh",
87
+ default: "openai-codex/gpt-5.6-sol:xhigh",
88
+ executor: "openai-codex/gpt-5.6-terra:xhigh",
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",
92
92
  }),
93
93
  profile("opencodego", ["opencode-go"], {
94
94
  default: "opencode-go/kimi-k2.6",
@@ -256,24 +256,24 @@ 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.5:low",
260
- planner: "openai-codex/gpt-5.5:medium",
261
- critic: "openai-codex/gpt-5.5:high",
262
- architect: "openai-codex/gpt-5.5: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",
263
263
  }),
264
264
  profile("codex-opencodego", ["openai-codex", "opencode-go"], {
265
- default: "openai-codex/gpt-5.5:medium",
265
+ default: "openai-codex/gpt-5.6-terra:xhigh",
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.5:xhigh",
269
+ architect: "openai-codex/gpt-5.6-sol:xhigh",
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.5:high",
273
+ executor: "openai-codex/gpt-5.6-terra:xhigh",
274
274
  planner: "anthropic/claude-opus-4-8:medium",
275
275
  critic: "anthropic/claude-opus-4-8:high",
276
- architect: "openai-codex/gpt-5.5:xhigh",
276
+ architect: "openai-codex/gpt-5.6-sol:xhigh",
277
277
  }),
278
278
  ];
279
279
 
@@ -1,4 +1,5 @@
1
1
  import type { Effort } from "@gajae-code/ai/model-thinking";
2
+ import { PET_MODE_IDS, PET_SKIN_IDS, PET_SKINS } from "@gajae-code/tui/components/gajae-pet";
2
3
  import { TASK_SIMPLE_MODES } from "../task/simple-mode";
3
4
  import { getThinkingLevelMetadata } from "../thinking-metadata";
4
5
  import { EDIT_MODES } from "../utils/edit-mode";
@@ -261,6 +262,7 @@ export const SETTINGS_SCHEMA = {
261
262
  "notifications.telegram.chatId": { type: "string", default: undefined },
262
263
  "notifications.telegram.rich.enabled": { type: "boolean", default: true },
263
264
  "notifications.telegram.richDraft.enabled": { type: "boolean", default: false },
265
+ "notifications.telegram.topics.nameTemplate": { type: "string", default: undefined },
264
266
  "notifications.discord.botToken": { type: "string", default: undefined },
265
267
  "notifications.discord.channelId": { type: "string", default: undefined },
266
268
  "notifications.slack.botToken": { type: "string", default: undefined },
@@ -271,6 +273,11 @@ export const SETTINGS_SCHEMA = {
271
273
  default: "lean",
272
274
  validate: (value: string) => value === "lean" || value === "verbose",
273
275
  },
276
+ "notifications.sessionScope": {
277
+ type: "string",
278
+ default: "all",
279
+ validate: (value: string) => value === "all" || value === "primary",
280
+ },
274
281
  "notifications.daemon.idleTimeoutMs": {
275
282
  type: "number",
276
283
  default: 60000,
@@ -510,6 +517,25 @@ export const SETTINGS_SCHEMA = {
510
517
  description: "Use the session name color for the editor border and status line gap",
511
518
  },
512
519
  },
520
+
521
+ "pet.mode": {
522
+ type: "enum",
523
+ values: PET_MODE_IDS,
524
+ default: "off",
525
+ ui: {
526
+ tab: "appearance",
527
+ label: "Gajae Pet",
528
+ description: "16x16 real-pixel gajae living beside the composer (sixel/kitty terminals)",
529
+ options: [
530
+ { value: "off", label: "Off", description: "No pet" },
531
+ ...PET_SKIN_IDS.map(id => ({
532
+ value: id,
533
+ label: PET_SKINS[id].label,
534
+ description: PET_SKINS[id].description,
535
+ })),
536
+ ],
537
+ },
538
+ },
513
539
  "statusLine.maxRows": {
514
540
  type: "number",
515
541
  default: 1,
@@ -1224,7 +1250,8 @@ export const SETTINGS_SCHEMA = {
1224
1250
  ui: {
1225
1251
  tab: "interaction",
1226
1252
  label: "Check for Updates",
1227
- description: "If false, skip update check",
1253
+ description:
1254
+ "At interactive startup, notify of newer versions; never install. Use `gjc update` only for recognized Bun global, Windows npm, or bundled-installer binaries; source, linked, and unrecognized installs use their original method.",
1228
1255
  },
1229
1256
  },
1230
1257
 
@@ -2164,6 +2191,16 @@ export const SETTINGS_SCHEMA = {
2164
2191
  },
2165
2192
  },
2166
2193
 
2194
+ "irc.sidebar.enabled": {
2195
+ type: "boolean",
2196
+ default: true,
2197
+ ui: {
2198
+ tab: "tools",
2199
+ label: "IRC Sidebar",
2200
+ description: "Enable the IRC message sidebar (opens with the toggle key; starts closed)",
2201
+ },
2202
+ },
2203
+
2167
2204
  // Optional tools
2168
2205
 
2169
2206
  "renderMermaid.enabled": {
@@ -3417,6 +3454,9 @@ export interface NotificationsSettings {
3417
3454
  richDraft: {
3418
3455
  enabled: boolean;
3419
3456
  };
3457
+ topics: {
3458
+ nameTemplate: string | undefined;
3459
+ };
3420
3460
  };
3421
3461
  discord: {
3422
3462
  botToken: string | undefined;
@@ -0,0 +1,100 @@
1
+ import * as path from "node:path";
2
+ import { getAgentDir } from "@gajae-code/utils";
3
+ import { resolveModelProfileName } from "../config/model-profile-activation";
4
+ import { type ModelProfileDefinition, mergeModelProfiles } from "../config/model-profiles";
5
+ import { ModelsConfigFile } from "../config/model-registry";
6
+
7
+ /**
8
+ * Loads the merged built-in + custom model-profile registry the way the `gjc`
9
+ * CLI resolves `--mpreset`, so coordinator MCP launches select the same
10
+ * authoritative profile the spawned child will activate. Custom profiles live
11
+ * in the shared models config, which the child inherits, so both sides agree.
12
+ */
13
+ export type CoordinatorModelProfileLoader = () =>
14
+ | Map<string, ModelProfileDefinition>
15
+ | Promise<Map<string, ModelProfileDefinition>>;
16
+
17
+ const MAX_ECHOED_MPRESET_LENGTH = 128;
18
+
19
+ /**
20
+ * Thrown by the default loader when `models.yml` exists but is invalid or
21
+ * unreadable. This lets the resolver fail closed with a distinct, stable reason
22
+ * instead of silently collapsing a broken registry to the built-ins-only set
23
+ * (which would misreport a caller's valid custom profile as unknown).
24
+ */
25
+ export class CoordinatorModelProfileRegistryError extends Error {
26
+ constructor(cause?: unknown) {
27
+ super("coordinator_model_profile_registry_error");
28
+ this.name = "CoordinatorModelProfileRegistryError";
29
+ if (cause !== undefined) (this as { cause?: unknown }).cause = cause;
30
+ }
31
+ }
32
+
33
+ export const loadCoordinatorModelProfiles: CoordinatorModelProfileLoader = () => {
34
+ const configFile = ModelsConfigFile.relocate(path.join(getAgentDir(), "models.yml"));
35
+ configFile.invalidate();
36
+ const loaded = configFile.tryLoad();
37
+ // A present-but-invalid config must fail closed; absence (`value` undefined
38
+ // with a non-error status) is fine and yields the built-in profiles only.
39
+ if (loaded.status === "error") throw new CoordinatorModelProfileRegistryError(loaded.error);
40
+ return mergeModelProfiles(loaded.value?.profiles);
41
+ };
42
+
43
+ function sortedProfileNames(profiles: ReadonlyMap<string, ModelProfileDefinition>): string[] {
44
+ return [...profiles.keys()].sort((left, right) => left.localeCompare(right));
45
+ }
46
+
47
+ export type CoordinatorMpresetResolution =
48
+ | { ok: true; mpreset: string | null }
49
+ | { ok: false; reason: "unknown_model_profile"; mpreset: string; available_profiles: string[] }
50
+ | { ok: false; reason: "model_profile_registry_error"; mpreset: string; available_profiles: string[] };
51
+
52
+ /**
53
+ * Resolve a coordinator `mpreset` argument against the merged profile registry.
54
+ *
55
+ * Only an absent (`undefined`/`null`) value is a no-op (`mpreset: null`); an
56
+ * explicit empty/whitespace string is a caller error and is rejected rather
57
+ * than silently launching at the default tier. Legacy aliases are canonicalized
58
+ * exactly like the CLI (e.g. `codex-standard` -> `codex-medium`) so coordinator
59
+ * selection stays in parity with `gjc --mpreset <profile>`; the resolved value
60
+ * is the canonical profile name. Unknown names are rejected with the
61
+ * available-profile listing and never reach a spawned child command, and a
62
+ * broken registry fails closed with `model_profile_registry_error`.
63
+ */
64
+ export async function resolveCoordinatorMpreset(
65
+ raw: unknown,
66
+ loadProfiles: CoordinatorModelProfileLoader,
67
+ ): Promise<CoordinatorMpresetResolution> {
68
+ if (raw === undefined || raw === null) return { ok: true, mpreset: null };
69
+ const requested = typeof raw === "string" ? raw.trim() : "";
70
+ const echoed = requested.slice(0, MAX_ECHOED_MPRESET_LENGTH);
71
+ let profiles: Map<string, ModelProfileDefinition>;
72
+ try {
73
+ profiles = await loadProfiles();
74
+ } catch (error) {
75
+ if (error instanceof CoordinatorModelProfileRegistryError) {
76
+ return { ok: false, reason: "model_profile_registry_error", mpreset: echoed, available_profiles: [] };
77
+ }
78
+ throw error;
79
+ }
80
+ // Non-string input and explicit blank/whitespace strings can never name a
81
+ // profile; only absent/null (handled above) means "no selection".
82
+ if (typeof raw !== "string" || requested.length === 0) {
83
+ return {
84
+ ok: false,
85
+ reason: "unknown_model_profile",
86
+ mpreset: echoed,
87
+ available_profiles: sortedProfileNames(profiles),
88
+ };
89
+ }
90
+ const canonical = resolveModelProfileName(requested, profiles);
91
+ if (!profiles.has(canonical)) {
92
+ return {
93
+ ok: false,
94
+ reason: "unknown_model_profile",
95
+ mpreset: echoed,
96
+ available_profiles: sortedProfileNames(profiles),
97
+ };
98
+ }
99
+ return { ok: true, mpreset: canonical };
100
+ }