@gajae-code/coding-agent 0.6.1 → 0.6.4
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 +54 -0
- package/README.md +73 -1
- package/dist/types/cli/update-cli.d.ts +3 -0
- package/dist/types/config/model-registry.d.ts +3 -0
- package/dist/types/config/models-config-schema.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +27 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +2 -0
- package/dist/types/lsp/startup-events.d.ts +1 -0
- package/dist/types/modes/components/welcome.d.ts +3 -1
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -0
- package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +5 -0
- package/package.json +7 -7
- package/scripts/build-binary.ts +0 -7
- package/src/cli/setup-cli.ts +14 -1
- package/src/cli/update-cli.ts +53 -3
- package/src/commands/launch.ts +1 -1
- package/src/config/model-registry.ts +9 -2
- package/src/config/model-resolver.ts +13 -2
- package/src/config/models-config-schema.ts +1 -0
- package/src/config/settings-schema.ts +17 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +3 -1
- package/src/defaults/gjc/skills/ralplan/SKILL.md +2 -0
- package/src/exec/bash-executor.ts +3 -1
- package/src/gjc-runtime/launch-tmux.ts +62 -14
- package/src/gjc-runtime/state-runtime.ts +22 -14
- package/src/gjc-runtime/state-writer.ts +21 -1
- package/src/gjc-runtime/tmux-sessions.ts +36 -1
- package/src/internal-urls/docs-index.generated.ts +5 -6
- package/src/lsp/startup-events.ts +24 -0
- package/src/modes/components/welcome.ts +42 -9
- package/src/modes/controllers/input-controller.ts +21 -3
- package/src/modes/interactive-mode.ts +27 -19
- package/src/modes/prompt-action-autocomplete.ts +11 -1
- package/src/session/agent-session.ts +28 -20
- package/src/session/session-manager.ts +19 -2
- package/src/setup/hermes/templates/operator-instructions.v1.md +8 -0
- package/src/skill-state/active-state.ts +53 -30
- package/src/skill-state/deep-interview-mutation-guard.ts +238 -30
- package/src/slash-commands/builtin-registry.ts +8 -4
- package/src/system-prompt.ts +11 -9
- package/src/tools/ast-edit.ts +2 -2
- package/src/utils/edit-mode.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,11 +2,64 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.6.4] - 2026-06-20
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- Added `startup.welcomeBannerMode = "square"` for a square-corner Unicode welcome-logo fallback, and stopped treating Windows Terminal (`WT_SESSION`) as an automatic ASCII downgrade; `auto` now preserves the rounded Unicode logo while `unicode`, `square`, and `ascii` remain explicit overrides.
|
|
10
|
+
|
|
11
|
+
- Improved image input discoverability by adding an interactive `#paste-image` prompt action and clearer clipboard fallback guidance when no image is available.
|
|
12
|
+
|
|
13
|
+
- Improved skill migration guidance for users moving custom skills onto the current skill system (#899).
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Fixed native Windows tmux launch and hardened Windows tmux root launch, and resolved follow-up Windows tmux launch and input regressions (#884, #895, #906).
|
|
18
|
+
- Fixed `EXDEV` failures when moving session artifacts across filesystems (cross-device session artifact moves) (#886).
|
|
19
|
+
- Excluded user context files from the project prompt so file-level context filtering no longer leaks user-scoped files into project context (#885).
|
|
20
|
+
- Fixed a bash cancellation descendant-cleanup race so cancellation now waits for child-process cleanup within a bounded stall prompt (#893).
|
|
21
|
+
- Fixed the TUI dropping the first `/goal set <objective>` command from input history: the typed command is now recorded whenever args are supplied, regardless of prior goal-mode state (#910).
|
|
22
|
+
- Fixed Ctrl+Enter/Ctrl+Shift+Enter newline handling in the editor: idle Ctrl+Enter now falls through to newline insertion while keeping Ctrl+Enter as the busy-session follow-up shortcut, and Ctrl+Shift+Enter inserts a newline (#911).
|
|
23
|
+
- Fixed parsing of psmux modified-enter key sequences in the TUI (#918).
|
|
24
|
+
|
|
25
|
+
### Documentation
|
|
26
|
+
|
|
27
|
+
- Documented Windows Terminal welcome-logo troubleshooting with Cascadia Mono / Cascadia Mono Nerd Font and the profile `fontFace` setting.
|
|
28
|
+
- Documented CLI `@image` attachments and interactive TUI clipboard image paste fallbacks in the root README.
|
|
29
|
+
|
|
30
|
+
- Documented lifecycle notification hooks (#903).
|
|
31
|
+
- Added a routed GJC session guide for Clawhip/Hermes/OpenClaw visible routed sessions and linked it from the Hermes docs and operator instructions.
|
|
32
|
+
|
|
33
|
+
## [0.6.3] - 2026-06-19
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- Reverted the experimental minified npm-bundle distribution introduced in 0.6.2. The published `@gajae-code/coding-agent` shipped both `src/` and ~30MB of `dist/` bundles (`cli.js` plus stats/browser/eval worker bundles), which pushed the package past npm's registry payload limit (`E413 Payload Too Large`) and blocked publishing of `@gajae-code/coding-agent` and the `gajae-code` wrapper (so 0.6.2 only partially published the sibling libraries). The CLI `bin`/`./cli` export ships from `src/` again, matching the layout that published cleanly through 0.6.1; the embedded tiktoken/o200k tokenizer removal is unaffected. Local measurement showed the bundle gave no idle-RAM benefit over running from source.
|
|
38
|
+
- Fixed `edit-mode.ts` importing the full `@gajae-code/utils` barrel (which re-exports native-addon-backed `ptree`/`procmgr`); it now imports `$env` from the `@gajae-code/utils/env` subpath, so schema generation and other lightweight paths no longer eagerly load the native addon.
|
|
39
|
+
|
|
40
|
+
## [0.6.2] - 2026-06-19
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
|
|
44
|
+
- Reconciled the planning-phase mutation guard into one uniform policy across skill states (`deep-interview-mutation-guard.ts`). Previously only `deep-interview` blocked product-code mutation (and it blocked *all* `write`/`edit`/`ast_edit` targets, including neutral `/tmp` scratch), while `ralplan`/`ultragoal` planning enforced nothing beyond the always-on `.gjc/**` runtime-owned block, and `bash` got a free pass to mutate product code during the interview. Now: (1) the phase-boundary block is shared by every pre-approval planning phase — `deep-interview`, `ralplan`, and `ultragoal`'s `goal-planning` phase (`team` and executing `ultragoal` are unaffected); (2) `bash` reaches parity with `write`/`edit`/`ast_edit` so product-mutating shell commands are blocked too; and (3) neutral scratch writes to a system temp directory (`os.tmpdir()`/`$TMPDIR`, `/tmp`, `/var/tmp`) outside the project tree are always allowed, so an agent can stage a draft and persist it through the sanctioned CLI (`gjc deep-interview --write --spec <temp-path>`, `gjc ralplan --write --artifact <temp-path>`). The `.gjc/**` block is unchanged. Each planning skill now emits its own block message.
|
|
45
|
+
- Made the reconciled mutation guard skill-transition/return safe by keying the block off the single canonical *current* workflow skill (the resolved top-level `skill` the HUD and skill-tool chain guard already use) instead of independently scanning every skill. Phase semantics now match the manifest and the Stop hook's `STOP_RELEASING_PHASES`: `handoff` and ralplan's pre-approval `final` keep blocking for `deep-interview`/`ralplan` (until the skill is demoted or cleared), executor phases (`ultragoal` `pending`/`active`/`blocked`) release, and a missing/corrupt mode-state still fails open. As a result a handoff (e.g. ralplan → ultragoal) never lets a stale planning entry block the executor, and a return (e.g. re-entering ralplan/deep-interview after a goal completes) reliably re-blocks.
|
|
46
|
+
- Hardened the reconciled guard after architect + red-team review: the `gjc …` bash fast-path no longer skips scanning for compound/redirected/multiline commands (`gjc …; tee src/x`, `gjc … && echo x > .gjc/state/foo`, and newline-separated `gjc …\ntouch src/x` are now caught); the current-skill resolver prefers the most-recently-updated active entry so a stale planning row can never block a newer executor; neutral-temp classification canonicalizes paths (realpath of the nearest existing ancestor) so a `/tmp` symlink or macOS `/tmp`→`/private/tmp` alias pointing back into the project/`.gjc` is blocked; the deferred `ast_edit` apply path now mirrors the always-on `.gjc/**` block; and a heredoc delimiter (`<<EOF`) is no longer mis-read as a write target. Bash mutation detection remains best-effort defense-in-depth (the authoritative guard is the fully-pathed `write`/`edit`/`ast_edit` tools). Added generic guard exports (`getWorkflowMutationDecision`/`assertWorkflowMutationAllowed`/`assertWorkflowMutationRawPathsAllowed`) used by the session and `ast_edit` callers, with the `*DeepInterview*` names retained as compatibility aliases.
|
|
47
|
+
- The published `@gajae-code/coding-agent` npm package now ships a prebuilt **minified** `dist/cli.js` (built with `bun build --minify`, not `--compile`) as the CLI entrypoint; the native addon and the stats/browser/eval worker entrypoints are emitted as externals so the bundle loads them from `node_modules` at runtime, and release compiled binaries also gain `--minify`. Measured `gjc --help` RSS dropped from ~302MB (running from source) to ~120MB (#879, #881).
|
|
48
|
+
- Lazy-loaded the `eval` tool and its Python-kernel backend via dynamic import, so the kernel and its dependencies are no longer eagerly imported at startup and load only when the `eval` tool actually runs (#879).
|
|
49
|
+
- `rust-analyzer` is now treated as an optional LSP server: its startup failure no longer raises a startup warning (it is auto-installed lazily on demand), while non-optional LSP server startup failures still warn (#872).
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- Fixed planning-pipeline stage precedence so activating a downstream stage (`deep-interview → ralplan → ultragoal`) supersedes upstream stages by pipeline rank, preventing a stale upstream row from continuing to own the HUD, mutation gate, or primary active-state snapshot (#878).
|
|
54
|
+
- Made `gjc state doctor` resolve the session id like every other state command (explicit `--session-id`, then payload `session_id`, then the `GJC_SESSION_ID` env var set for agent-initiated invocations), so it inspects the caller's session-scoped state files instead of a default location (#880).
|
|
55
|
+
- Fixed a second workspace-relative import that the 0.6.0 #867 fix missed: `edit-mode.ts` now imports `$env` through the `@gajae-code/utils` package boundary instead of `../../../utils/src/env`, so global Bun installs no longer crash resolving edit mode, with package-boundary regression coverage (#868).
|
|
56
|
+
|
|
5
57
|
## [0.6.1] - 2026-06-18
|
|
6
58
|
|
|
7
59
|
### Fixed
|
|
8
60
|
|
|
9
61
|
- Fixed the `computer` tool (and any other `z.union`/discriminated-union tool) shipping a bare top-level `anyOf`/`oneOf`/`allOf` `input_schema` root that strict providers (Amazon Bedrock Converse incl. Kiro/CodeWhisperer relays, OpenAI strict mode, Gemini) reject. Tool schema roots are now flattened to a single `type: "object"` across all providers via the shared `flattenToolRootCombinators`. See `@gajae-code/ai` 0.6.1.
|
|
62
|
+
- `gjc update` now runs the freshly installed `gjc --smoke-test` after version verification and tells users to restart running sessions, surfacing stale or partial runtime updates such as native-addon release mismatches immediately.
|
|
10
63
|
|
|
11
64
|
## [0.6.0] - 2026-06-18
|
|
12
65
|
### Added
|
|
@@ -14,6 +67,7 @@
|
|
|
14
67
|
- Exposed the existing goal-pause capability through the `goal` tool as `goal({op:"pause"})`. The runtime `pauseGoal()` method and `paused` status already existed and were reachable via the `/goal pause` slash command and the goal menu, but the agent-facing `goal` tool only enumerated `create | get | complete | resume | drop` — so an agent could not park a goal whose remaining work was blocked on human input. It was forced to either `drop` (clearing the goal) or leave the goal `active`, which re-fired the hidden autonomous-continuation steer every turn with no exit condition. `pause` reuses the existing `paused` status and continuation gate (`buildContinuationPrompt` already returns `undefined` when `enabled=false`), parks the goal without dropping it, persists as `goal_paused`, and is resumable via the existing `resume` op. The active-goal and continuation prompts now instruct the agent to pause when every outstanding deliverable is genuinely human-blocked. `pauseGoal()` now rejects any goal whose status is not `active`, so a completed or dropped goal cannot be driven into a paused-mode lifecycle when paused through the tool.
|
|
15
68
|
|
|
16
69
|
### Fixed
|
|
70
|
+
- Fixed global Bun installs crashing during interactive startup when edit-mode resolution followed a workspace-relative `packages/utils/src` import that is absent from the published package layout; coding-agent now imports `$env` through the `@gajae-code/utils` package boundary and has regression coverage for sibling workspace source imports (#867).
|
|
17
71
|
|
|
18
72
|
- Restored steer-by-default while the agent is busy: `busyPromptMode` now defaults to `steer`, so Enter on a normal prompt interrupts the active turn. Queueing for the next turn is reserved for the explicit Ctrl+Enter follow-up keystroke (or `busyPromptMode: "queue"`); existing steer/cancel plus explicit queue/dequeue controls remain separate (#829).
|
|
19
73
|
- Fixed `gjc rlm "<question>"` consuming the seeded question as a one-shot autonomous run that exited immediately; a seeded prompt now lands in the interactive composer so the research session stays interactive.
|
package/README.md
CHANGED
|
@@ -11,9 +11,69 @@ Package-specific references:
|
|
|
11
11
|
- [DEVELOPMENT](./DEVELOPMENT.md)
|
|
12
12
|
- [RenderMermaid guide](../../docs/render-mermaid.md)
|
|
13
13
|
|
|
14
|
+
## External lifecycle notifications
|
|
15
|
+
|
|
16
|
+
GJC already exposes public lifecycle events through the extension/hook event contract. External notification integrations for Discord, Hermes, clawhip, or similar channels should be opt-in and subscribe to these events instead of scraping transcripts or logs:
|
|
17
|
+
|
|
18
|
+
- `turn_end` — a model/tool turn finished. The public payload is `{ type: "turn_end", turnIndex, message, toolResults }`.
|
|
19
|
+
- `agent_end` — the agent loop for a submitted prompt reached a terminal boundary. The public payload is `{ type: "agent_end", messages }`.
|
|
20
|
+
|
|
21
|
+
Recommended external mapping:
|
|
22
|
+
|
|
23
|
+
| Notification | Public event | Status guidance |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| Turn finished | `turn_end` | Use the handler's own sanitized status such as `"finished"`. |
|
|
26
|
+
| Agent stopped/finished | `agent_end` | Treat as terminal for the prompt. |
|
|
27
|
+
| Waiting/blocked/failed | `agent_end` plus a caller-supplied safe summary | Current lifecycle events do not expose a separate structured waiting/blocked reason; inspect only public-safe, integration-owned state. |
|
|
28
|
+
|
|
29
|
+
Forward only a minimal, caller-sanitized payload. Do not include raw prompts, assistant transcripts, hidden prompts, tool outputs, raw logs, host paths, private config, webhook URLs, channel IDs, tokens, or secrets. A safe notification payload should be built by the extension/hook itself, for example:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import type { ExtensionAPI } from "@gajae-code/coding-agent";
|
|
33
|
+
|
|
34
|
+
type PublicLifecycleNotification = {
|
|
35
|
+
type: "turn_end" | "agent_end";
|
|
36
|
+
status: "finished" | "stopped" | "failed" | "blocked" | "waiting";
|
|
37
|
+
turnIndex?: number;
|
|
38
|
+
timestamp: string;
|
|
39
|
+
summary: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export default function lifecycleNotifier(pi: ExtensionAPI) {
|
|
43
|
+
const enabled = process.env.GJC_LIFECYCLE_NOTIFY === "1";
|
|
44
|
+
if (!enabled) return;
|
|
45
|
+
|
|
46
|
+
const send = async (payload: PublicLifecycleNotification) => {
|
|
47
|
+
// POST to Discord/Hermes/clawhip here. Keep target URLs and channel IDs in
|
|
48
|
+
// private config or environment variables; never include them in payloads.
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
pi.on("turn_end", event =>
|
|
52
|
+
send({
|
|
53
|
+
type: "turn_end",
|
|
54
|
+
status: "finished",
|
|
55
|
+
turnIndex: event.turnIndex,
|
|
56
|
+
timestamp: new Date().toISOString(),
|
|
57
|
+
summary: "GJC turn finished",
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
pi.on("agent_end", () =>
|
|
62
|
+
send({
|
|
63
|
+
type: "agent_end",
|
|
64
|
+
status: "stopped",
|
|
65
|
+
timestamp: new Date().toISOString(),
|
|
66
|
+
summary: "GJC prompt reached a terminal lifecycle boundary",
|
|
67
|
+
}),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
This is the supported repo-native lifecycle notification path. It is not Claude Code hook compatibility, and it remains disabled unless the user configures an extension/hook handler and private delivery target.
|
|
73
|
+
|
|
14
74
|
## Memory backends
|
|
15
75
|
|
|
16
|
-
The agent supports three mutually-exclusive memory backends, selected via the `memory.backend` setting (Settings → Memory tab, or `~/.gjc/config.yml`):
|
|
76
|
+
The agent supports three mutually-exclusive memory backends, selected via the `memory.backend` setting (Settings → Memory tab, or `~/.gjc/agent/config.yml`):
|
|
17
77
|
|
|
18
78
|
- `off` (default) — no memory subsystem runs.
|
|
19
79
|
- `local` — existing rollout-summarisation pipeline; writes `memory_summary.md` and consolidated artifacts under the agent dir.
|
|
@@ -35,3 +95,15 @@ Switching backends mid-session is honoured on the next system-prompt rebuild and
|
|
|
35
95
|
## Red-claw TUI theme
|
|
36
96
|
|
|
37
97
|
The interactive TUI defaults to the bundled `red-claw` crustacean theme for dark terminals and the bundled `blue-crab` theme for light-appearance terminals, with matching welcome/icon assets. Three additional bundled migration themes — `claude-code`, `codex`, and `opencode` — mirror the look of those tools for easy eye-migration and are selectable from Settings or `/theme`. Explicit user theme settings still win; set `theme.dark: red-claw` and `theme.light: blue-crab` in `~/.gjc/agent/config.yml` to pin them.
|
|
98
|
+
|
|
99
|
+
### Welcome banner fonts on Windows Terminal
|
|
100
|
+
|
|
101
|
+
The startup logo defaults to rounded Unicode box drawing. Windows Terminal can render it correctly when the selected profile font has the needed box-drawing glyphs; recommended choices are `Cascadia Mono` or `Cascadia Mono Nerd Font`. In Windows Terminal Settings, set the profile font face to one of those fonts, or add it to the profile JSON:
|
|
102
|
+
|
|
103
|
+
```json
|
|
104
|
+
"font": {
|
|
105
|
+
"face": "Cascadia Mono"
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
For terminals or fonts with broken rounded corners, set `startup.welcomeBannerMode` in `~/.gjc/agent/config.yml` to one of `unicode`, `square`, or `ascii`. `square` keeps a Unicode-looking logo using square corners (`┌ ┐ └ ┘`) while `ascii` uses only `+`, `-`, and `|`.
|
|
@@ -3,6 +3,8 @@ export interface InstalledVersionVerification {
|
|
|
3
3
|
ok: boolean;
|
|
4
4
|
actual?: string;
|
|
5
5
|
path?: string;
|
|
6
|
+
smokeTestFailed?: boolean;
|
|
7
|
+
smokeTestOutput?: string;
|
|
6
8
|
}
|
|
7
9
|
/** Paths and verifier used while replacing a downloaded binary update. */
|
|
8
10
|
export interface BinaryReplacementOptions {
|
|
@@ -24,6 +26,7 @@ export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: s
|
|
|
24
26
|
export declare function formatBinaryDownloadFailureMessageForTest(binaryName: string, url: string, status: string | number, platform?: NodeJS.Platform): string;
|
|
25
27
|
export declare function buildReleaseBinaryUrlForTest(version: string, platform?: NodeJS.Platform, arch?: string): string;
|
|
26
28
|
export declare function formatManualUpdateInstructionsForTest(platform?: NodeJS.Platform): string;
|
|
29
|
+
export declare function formatVerificationFailureForTest(result: InstalledVersionVerification, expectedVersion: string): string;
|
|
27
30
|
/**
|
|
28
31
|
* Atomically replace the installed binary and roll back if version verification fails.
|
|
29
32
|
*/
|
|
@@ -51,6 +51,7 @@ export declare const ModelsConfigFile: ConfigFile<{
|
|
|
51
51
|
compat?: {
|
|
52
52
|
supportsStore?: boolean | undefined;
|
|
53
53
|
supportsDeveloperRole?: boolean | undefined;
|
|
54
|
+
sendSessionHeaders?: boolean | undefined;
|
|
54
55
|
supportsMultipleSystemMessages?: boolean | undefined;
|
|
55
56
|
supportsReasoningEffort?: boolean | undefined;
|
|
56
57
|
reasoningEffortMap?: {
|
|
@@ -129,6 +130,7 @@ export declare const ModelsConfigFile: ConfigFile<{
|
|
|
129
130
|
compat?: {
|
|
130
131
|
supportsStore?: boolean | undefined;
|
|
131
132
|
supportsDeveloperRole?: boolean | undefined;
|
|
133
|
+
sendSessionHeaders?: boolean | undefined;
|
|
132
134
|
supportsMultipleSystemMessages?: boolean | undefined;
|
|
133
135
|
supportsReasoningEffort?: boolean | undefined;
|
|
134
136
|
reasoningEffortMap?: {
|
|
@@ -202,6 +204,7 @@ export declare const ModelsConfigFile: ConfigFile<{
|
|
|
202
204
|
compat?: {
|
|
203
205
|
supportsStore?: boolean | undefined;
|
|
204
206
|
supportsDeveloperRole?: boolean | undefined;
|
|
207
|
+
sendSessionHeaders?: boolean | undefined;
|
|
205
208
|
supportsMultipleSystemMessages?: boolean | undefined;
|
|
206
209
|
supportsReasoningEffort?: boolean | undefined;
|
|
207
210
|
reasoningEffortMap?: {
|
|
@@ -2,6 +2,7 @@ import * as z from "zod/v4";
|
|
|
2
2
|
export declare const OpenAICompatSchema: z.ZodObject<{
|
|
3
3
|
supportsStore: z.ZodOptional<z.ZodBoolean>;
|
|
4
4
|
supportsDeveloperRole: z.ZodOptional<z.ZodBoolean>;
|
|
5
|
+
sendSessionHeaders: z.ZodOptional<z.ZodBoolean>;
|
|
5
6
|
supportsMultipleSystemMessages: z.ZodOptional<z.ZodBoolean>;
|
|
6
7
|
supportsReasoningEffort: z.ZodOptional<z.ZodBoolean>;
|
|
7
8
|
reasoningEffortMap: z.ZodOptional<z.ZodObject<{
|
|
@@ -163,6 +164,7 @@ export declare const ModelOverrideSchema: z.ZodObject<{
|
|
|
163
164
|
compat: z.ZodOptional<z.ZodObject<{
|
|
164
165
|
supportsStore: z.ZodOptional<z.ZodBoolean>;
|
|
165
166
|
supportsDeveloperRole: z.ZodOptional<z.ZodBoolean>;
|
|
167
|
+
sendSessionHeaders: z.ZodOptional<z.ZodBoolean>;
|
|
166
168
|
supportsMultipleSystemMessages: z.ZodOptional<z.ZodBoolean>;
|
|
167
169
|
supportsReasoningEffort: z.ZodOptional<z.ZodBoolean>;
|
|
168
170
|
reasoningEffortMap: z.ZodOptional<z.ZodObject<{
|
|
@@ -276,6 +278,7 @@ export declare const ModelsConfigSchema: z.ZodObject<{
|
|
|
276
278
|
compat: z.ZodOptional<z.ZodObject<{
|
|
277
279
|
supportsStore: z.ZodOptional<z.ZodBoolean>;
|
|
278
280
|
supportsDeveloperRole: z.ZodOptional<z.ZodBoolean>;
|
|
281
|
+
sendSessionHeaders: z.ZodOptional<z.ZodBoolean>;
|
|
279
282
|
supportsMultipleSystemMessages: z.ZodOptional<z.ZodBoolean>;
|
|
280
283
|
supportsReasoningEffort: z.ZodOptional<z.ZodBoolean>;
|
|
281
284
|
reasoningEffortMap: z.ZodOptional<z.ZodObject<{
|
|
@@ -442,6 +445,7 @@ export declare const ModelsConfigSchema: z.ZodObject<{
|
|
|
442
445
|
compat: z.ZodOptional<z.ZodObject<{
|
|
443
446
|
supportsStore: z.ZodOptional<z.ZodBoolean>;
|
|
444
447
|
supportsDeveloperRole: z.ZodOptional<z.ZodBoolean>;
|
|
448
|
+
sendSessionHeaders: z.ZodOptional<z.ZodBoolean>;
|
|
445
449
|
supportsMultipleSystemMessages: z.ZodOptional<z.ZodBoolean>;
|
|
446
450
|
supportsReasoningEffort: z.ZodOptional<z.ZodBoolean>;
|
|
447
451
|
reasoningEffortMap: z.ZodOptional<z.ZodObject<{
|
|
@@ -582,6 +586,7 @@ export declare const ModelsConfigSchema: z.ZodObject<{
|
|
|
582
586
|
compat: z.ZodOptional<z.ZodObject<{
|
|
583
587
|
supportsStore: z.ZodOptional<z.ZodBoolean>;
|
|
584
588
|
supportsDeveloperRole: z.ZodOptional<z.ZodBoolean>;
|
|
589
|
+
sendSessionHeaders: z.ZodOptional<z.ZodBoolean>;
|
|
585
590
|
supportsMultipleSystemMessages: z.ZodOptional<z.ZodBoolean>;
|
|
586
591
|
supportsReasoningEffort: z.ZodOptional<z.ZodBoolean>;
|
|
587
592
|
reasoningEffortMap: z.ZodOptional<z.ZodObject<{
|
|
@@ -1195,6 +1195,33 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
1195
1195
|
readonly description: "Skip welcome screen and startup status messages";
|
|
1196
1196
|
};
|
|
1197
1197
|
};
|
|
1198
|
+
readonly "startup.welcomeBannerMode": {
|
|
1199
|
+
readonly type: "enum";
|
|
1200
|
+
readonly values: readonly ["auto", "unicode", "square", "ascii"];
|
|
1201
|
+
readonly default: "auto";
|
|
1202
|
+
readonly ui: {
|
|
1203
|
+
readonly tab: "interaction";
|
|
1204
|
+
readonly label: "Welcome Banner Mode";
|
|
1205
|
+
readonly description: "Logo style for the startup welcome screen";
|
|
1206
|
+
readonly options: readonly [{
|
|
1207
|
+
readonly value: "auto";
|
|
1208
|
+
readonly label: "Auto";
|
|
1209
|
+
readonly description: "Use the rounded Unicode logo";
|
|
1210
|
+
}, {
|
|
1211
|
+
readonly value: "unicode";
|
|
1212
|
+
readonly label: "Unicode";
|
|
1213
|
+
readonly description: "Force the rounded Unicode logo";
|
|
1214
|
+
}, {
|
|
1215
|
+
readonly value: "square";
|
|
1216
|
+
readonly label: "Square Unicode";
|
|
1217
|
+
readonly description: "Force the square-corner Unicode fallback";
|
|
1218
|
+
}, {
|
|
1219
|
+
readonly value: "ascii";
|
|
1220
|
+
readonly label: "ASCII";
|
|
1221
|
+
readonly description: "Force the ASCII-safe logo";
|
|
1222
|
+
}];
|
|
1223
|
+
};
|
|
1224
|
+
};
|
|
1198
1225
|
readonly "startup.checkUpdate": {
|
|
1199
1226
|
readonly type: "boolean";
|
|
1200
1227
|
readonly default: true;
|
|
@@ -32,6 +32,8 @@ export declare function listGjcTmuxSessions(env?: NodeJS.ProcessEnv): GjcTmuxSes
|
|
|
32
32
|
/** @internal */
|
|
33
33
|
export declare function listTmuxSessionsForGc(env?: NodeJS.ProcessEnv): GjcTmuxSessionsForGc;
|
|
34
34
|
export declare function findGjcTmuxSessionByBranch(branch: string, env?: NodeJS.ProcessEnv, project?: string | null): GjcTmuxSessionStatus | undefined;
|
|
35
|
+
export declare function findGjcTmuxSessionByName(sessionName: string, env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus | undefined;
|
|
36
|
+
export declare function findGjcTmuxSessionByScope(project: string, branch: string | null | undefined, env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus | undefined;
|
|
35
37
|
export declare function statusGjcTmuxSession(sessionName: string, env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus;
|
|
36
38
|
export declare function createGjcTmuxSession(env?: NodeJS.ProcessEnv): GjcTmuxSessionStatus;
|
|
37
39
|
/** @internal */
|
|
@@ -8,6 +8,7 @@ export interface LspServerInfo {
|
|
|
8
8
|
status: "ready" | "error" | "connecting";
|
|
9
9
|
fileTypes: string[];
|
|
10
10
|
}
|
|
11
|
+
export type WelcomeLogoMode = "unicode" | "square" | "ascii";
|
|
11
12
|
/**
|
|
12
13
|
* GJC-native launch surface with compact command affordances, project
|
|
13
14
|
* signals, and a claw/talon mark without copying another agent shell.
|
|
@@ -19,7 +20,8 @@ export declare class WelcomeComponent implements Component {
|
|
|
19
20
|
private providerName;
|
|
20
21
|
private recentSessions;
|
|
21
22
|
private lspServers;
|
|
22
|
-
|
|
23
|
+
private readonly logoMode;
|
|
24
|
+
constructor(version: string, modelName: string, providerName: string, recentSessions?: RecentSession[], lspServers?: LspServerInfo[], logoMode?: WelcomeLogoMode);
|
|
23
25
|
invalidate(): void;
|
|
24
26
|
/**
|
|
25
27
|
* Play a one-shot intro that sweeps the gradient through every phase
|
|
@@ -23,9 +23,12 @@ import type { HookInputComponent } from "./components/hook-input";
|
|
|
23
23
|
import type { HookSelectorComponent } from "./components/hook-selector";
|
|
24
24
|
import { StatusLineComponent } from "./components/status-line";
|
|
25
25
|
import type { ToolExecutionHandle } from "./components/tool-execution";
|
|
26
|
+
import { type WelcomeLogoMode } from "./components/welcome";
|
|
26
27
|
import { OAuthManualInputManager } from "./oauth-manual-input";
|
|
27
28
|
import type { Theme } from "./theme/theme";
|
|
28
29
|
import type { CompactionQueuedMessage, InteractiveModeContext, SubmittedUserInput, TodoItem, TodoPhase } from "./types";
|
|
30
|
+
export type WelcomeBannerSettingMode = "auto" | "unicode" | "square" | "ascii";
|
|
31
|
+
export declare function resolveWelcomeLogoMode(mode: WelcomeBannerSettingMode, env?: Record<string, string | undefined>, platform?: NodeJS.Platform): WelcomeLogoMode;
|
|
29
32
|
/** Options for creating an InteractiveMode instance (for future API use) */
|
|
30
33
|
export interface InteractiveModeOptions {
|
|
31
34
|
/** Providers that were migrated during startup */
|
|
@@ -13,6 +13,7 @@ interface PromptActionAutocompleteOptions {
|
|
|
13
13
|
keybindings: KeybindingsManager;
|
|
14
14
|
copyCurrentLine: () => void;
|
|
15
15
|
copyPrompt: () => void;
|
|
16
|
+
pasteImage: () => void;
|
|
16
17
|
undo: (prefix: string) => void;
|
|
17
18
|
moveCursorToMessageEnd: () => void;
|
|
18
19
|
moveCursorToMessageStart: () => void;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { AgentTool } from "@gajae-code/agent-core";
|
|
2
2
|
export declare const DEEP_INTERVIEW_MUTATION_BLOCK_MESSAGE = "Deep-interview phase boundary: continue gathering context/questions/risks and emit a handoff/spec before code edits. Mutation tools and patch execution are blocked while deep-interview is active; finalize specs through `gjc deep-interview --write --stage final` or hand off to an execution phase.";
|
|
3
3
|
export declare const WORKFLOW_STATE_MUTATION_BLOCK_MESSAGE = ".gjc workflow state and artifacts are runtime-owned. Agent mutation tools cannot edit `.gjc/**`; use the sanctioned `gjc` CLI instead.";
|
|
4
|
+
export declare const RALPLAN_MUTATION_BLOCK_MESSAGE = "Ralplan planning phase boundary: keep refining the consensus plan and persist plan artifacts through `gjc ralplan --write` (stage scratch files under a temp dir if needed). Product-code mutation tools and patch execution are blocked while ralplan is active; mutate only after the plan is approved and execution begins.";
|
|
5
|
+
export declare const ULTRAGOAL_GOAL_PLANNING_MUTATION_BLOCK_MESSAGE = "Ultragoal goal-planning phase boundary: finish goal planning and record goals through `gjc ultragoal` before editing code. Product-code mutation tools and patch execution are blocked until goal planning completes and execution begins.";
|
|
4
6
|
type ToolWithEditMode = AgentTool & {
|
|
5
7
|
mode?: unknown;
|
|
6
8
|
customWireName?: unknown;
|
|
@@ -30,4 +32,7 @@ export declare function assertDeepInterviewMutationRawPathsAllowed(input: {
|
|
|
30
32
|
}): Promise<void>;
|
|
31
33
|
export declare function getDeepInterviewMutationDecision(input: DeepInterviewMutationGuardInput): Promise<DeepInterviewMutationDecision>;
|
|
32
34
|
export declare function assertDeepInterviewMutationAllowed(input: DeepInterviewMutationGuardInput): Promise<void>;
|
|
35
|
+
export declare const getWorkflowMutationDecision: typeof getDeepInterviewMutationDecision;
|
|
36
|
+
export declare const assertWorkflowMutationAllowed: typeof assertDeepInterviewMutationAllowed;
|
|
37
|
+
export declare const assertWorkflowMutationRawPathsAllowed: typeof assertDeepInterviewMutationRawPathsAllowed;
|
|
33
38
|
export {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.6.
|
|
4
|
+
"version": "0.6.4",
|
|
5
5
|
"description": "Gajae Code CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://gaebal-gajae.dev",
|
|
7
7
|
"author": "Yeachan-Heo",
|
|
@@ -51,12 +51,12 @@
|
|
|
51
51
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
52
52
|
"@babel/parser": "^7.29.3",
|
|
53
53
|
"@mozilla/readability": "^0.6.0",
|
|
54
|
-
"@gajae-code/stats": "0.6.
|
|
55
|
-
"@gajae-code/agent-core": "0.6.
|
|
56
|
-
"@gajae-code/ai": "0.6.
|
|
57
|
-
"@gajae-code/natives": "0.6.
|
|
58
|
-
"@gajae-code/tui": "0.6.
|
|
59
|
-
"@gajae-code/utils": "0.6.
|
|
54
|
+
"@gajae-code/stats": "0.6.4",
|
|
55
|
+
"@gajae-code/agent-core": "0.6.4",
|
|
56
|
+
"@gajae-code/ai": "0.6.4",
|
|
57
|
+
"@gajae-code/natives": "0.6.4",
|
|
58
|
+
"@gajae-code/tui": "0.6.4",
|
|
59
|
+
"@gajae-code/utils": "0.6.4",
|
|
60
60
|
"@puppeteer/browsers": "^2.13.0",
|
|
61
61
|
"@types/turndown": "5.0.6",
|
|
62
62
|
"@xterm/headless": "^6.0.0",
|
package/scripts/build-binary.ts
CHANGED
|
@@ -5,12 +5,6 @@ import * as path from "node:path";
|
|
|
5
5
|
const packageDir = path.join(import.meta.dir, "..");
|
|
6
6
|
const outputPath = path.join(packageDir, "dist", "gjc");
|
|
7
7
|
const nativeDir = path.join(packageDir, "..", "natives", "native");
|
|
8
|
-
// Lazy native tokenizer entrypoint. `agent-core/compaction` loads this from
|
|
9
|
-
// the explicit native entrypoint instead of a package-name dynamic require of
|
|
10
|
-
// `@gajae-code/natives`, because those fail inside Bun standalone `$bunfs`.
|
|
11
|
-
// Listing the module here makes the absolute target path exist in the compiled
|
|
12
|
-
// bunfs.
|
|
13
|
-
const nativeTokenizerEntrypoint = "../natives/native/index.js";
|
|
14
8
|
|
|
15
9
|
function shouldAdhocSignDarwinBinary(): boolean {
|
|
16
10
|
return process.platform === "darwin";
|
|
@@ -72,7 +66,6 @@ async function main(): Promise<void> {
|
|
|
72
66
|
"../stats/src/sync-worker.ts",
|
|
73
67
|
"./src/tools/browser/tab-worker-entry.ts",
|
|
74
68
|
"./src/eval/js/worker-entry.ts",
|
|
75
|
-
nativeTokenizerEntrypoint,
|
|
76
69
|
"--outfile",
|
|
77
70
|
"dist/gjc",
|
|
78
71
|
],
|
package/src/cli/setup-cli.ts
CHANGED
|
@@ -374,6 +374,7 @@ async function handleHooksSetup(flags: { json?: boolean; check?: boolean }): Pro
|
|
|
374
374
|
async function handleDefaultsSetup(flags: { json?: boolean; check?: boolean; force?: boolean }): Promise<void> {
|
|
375
375
|
const result = await installDefaultGjcDefinitions({ check: flags.check, force: flags.force });
|
|
376
376
|
const hasCheckFailure = result.missing > 0 || result.different > 0;
|
|
377
|
+
const inspectGuidance = `Inspect bundled skills with: ${APP_NAME} skills list; read one with: ${APP_NAME} skills read ralplan`;
|
|
377
378
|
|
|
378
379
|
if (flags.json) {
|
|
379
380
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -388,18 +389,30 @@ async function handleDefaultsSetup(flags: { json?: boolean; check?: boolean; for
|
|
|
388
389
|
console.error(
|
|
389
390
|
chalk.dim(`Missing: ${result.missing}; different: ${result.different}; matching: ${result.matching}`),
|
|
390
391
|
);
|
|
392
|
+
console.error(chalk.dim(inspectGuidance));
|
|
393
|
+
console.error(
|
|
394
|
+
chalk.dim(
|
|
395
|
+
`Compare embedded defaults before overwriting local files with: ${APP_NAME} setup defaults --force`,
|
|
396
|
+
),
|
|
397
|
+
);
|
|
391
398
|
process.exit(1);
|
|
392
399
|
}
|
|
393
400
|
console.log(chalk.green(`${theme.status.success} Default GJC workflow skills are installed`));
|
|
394
401
|
console.log(chalk.dim(`Target: ${result.targetRoot}`));
|
|
402
|
+
console.log(chalk.dim(inspectGuidance));
|
|
395
403
|
return;
|
|
396
404
|
}
|
|
397
405
|
|
|
398
406
|
console.log(chalk.green(`${theme.status.success} Default GJC workflow skills installed`));
|
|
399
407
|
console.log(chalk.dim(`Target: ${result.targetRoot}`));
|
|
400
408
|
console.log(chalk.dim(`Written: ${result.written}; skipped: ${result.skipped}`));
|
|
409
|
+
console.log(chalk.dim(inspectGuidance));
|
|
401
410
|
if (result.skipped > 0 && !flags.force) {
|
|
402
|
-
console.log(
|
|
411
|
+
console.log(
|
|
412
|
+
chalk.dim(
|
|
413
|
+
`Existing local default workflow skill files were preserved. Use ${APP_NAME} setup defaults --force to overwrite them intentionally.`,
|
|
414
|
+
),
|
|
415
|
+
);
|
|
403
416
|
}
|
|
404
417
|
}
|
|
405
418
|
|
package/src/cli/update-cli.ts
CHANGED
|
@@ -25,6 +25,8 @@ export interface InstalledVersionVerification {
|
|
|
25
25
|
ok: boolean;
|
|
26
26
|
actual?: string;
|
|
27
27
|
path?: string;
|
|
28
|
+
smokeTestFailed?: boolean;
|
|
29
|
+
smokeTestOutput?: string;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
/** Paths and verifier used while replacing a downloaded binary update. */
|
|
@@ -226,6 +228,36 @@ async function verifyInstalledVersion(expectedVersion: string): Promise<Installe
|
|
|
226
228
|
}
|
|
227
229
|
}
|
|
228
230
|
|
|
231
|
+
async function verifyInstalledRuntime(expectedVersion: string): Promise<InstalledVersionVerification> {
|
|
232
|
+
const versionResult = await verifyInstalledVersion(expectedVersion);
|
|
233
|
+
if (!versionResult.ok || !versionResult.path) {
|
|
234
|
+
return versionResult;
|
|
235
|
+
}
|
|
236
|
+
try {
|
|
237
|
+
const smokeResult = await $`${versionResult.path} --smoke-test`.quiet().nothrow();
|
|
238
|
+
if (smokeResult.exitCode === 0) {
|
|
239
|
+
return versionResult;
|
|
240
|
+
}
|
|
241
|
+
return {
|
|
242
|
+
...versionResult,
|
|
243
|
+
ok: false,
|
|
244
|
+
smokeTestFailed: true,
|
|
245
|
+
smokeTestOutput: smokeResult.text().trim(),
|
|
246
|
+
};
|
|
247
|
+
} catch (error) {
|
|
248
|
+
return {
|
|
249
|
+
...versionResult,
|
|
250
|
+
ok: false,
|
|
251
|
+
smokeTestFailed: true,
|
|
252
|
+
smokeTestOutput: error instanceof Error ? error.message : String(error),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function printRestartGuidance(): void {
|
|
258
|
+
console.log(chalk.dim(`Restart ${APP_NAME} to use the new version`));
|
|
259
|
+
}
|
|
260
|
+
|
|
229
261
|
function printVerifiedVersion(expectedVersion: string): void {
|
|
230
262
|
console.log(chalk.green(`\n${theme.status.success} Updated to ${expectedVersion}`));
|
|
231
263
|
}
|
|
@@ -289,20 +321,38 @@ export function formatManualUpdateInstructionsForTest(platform: NodeJS.Platform
|
|
|
289
321
|
return formatManualUpdateInstructions(platform);
|
|
290
322
|
}
|
|
291
323
|
|
|
324
|
+
function normalizeVerificationOutput(output: string | undefined): string {
|
|
325
|
+
return output?.replace(/\s+/g, " ").trim() ?? "";
|
|
326
|
+
}
|
|
327
|
+
|
|
292
328
|
function formatVerificationFailure(result: InstalledVersionVerification, expectedVersion: string): string {
|
|
329
|
+
if (result.smokeTestFailed) {
|
|
330
|
+
const output = normalizeVerificationOutput(result.smokeTestOutput);
|
|
331
|
+
const outputSuffix = output ? `: ${output}` : "";
|
|
332
|
+
const pathSuffix = result.path ? ` at ${result.path}` : "";
|
|
333
|
+
return `${APP_NAME}${pathSuffix} reports ${result.actual ?? expectedVersion}, but --smoke-test failed${outputSuffix}. Close running ${APP_NAME} sessions and reinstall to repair a stale or partial update.`;
|
|
334
|
+
}
|
|
293
335
|
if (result.actual) {
|
|
294
336
|
return `${APP_NAME} at ${result.path} still reports ${result.actual} (expected ${expectedVersion})`;
|
|
295
337
|
}
|
|
296
338
|
return `could not verify updated version${result.path ? ` at ${result.path}` : ""}`;
|
|
297
339
|
}
|
|
298
340
|
|
|
341
|
+
export function formatVerificationFailureForTest(
|
|
342
|
+
result: InstalledVersionVerification,
|
|
343
|
+
expectedVersion: string,
|
|
344
|
+
): string {
|
|
345
|
+
return formatVerificationFailure(result, expectedVersion);
|
|
346
|
+
}
|
|
347
|
+
|
|
299
348
|
/**
|
|
300
349
|
* Print post-update verification result.
|
|
301
350
|
*/
|
|
302
351
|
async function printVerification(expectedVersion: string): Promise<void> {
|
|
303
|
-
const result = await
|
|
352
|
+
const result = await verifyInstalledRuntime(expectedVersion);
|
|
304
353
|
if (result.ok) {
|
|
305
354
|
printVerifiedVersion(expectedVersion);
|
|
355
|
+
printRestartGuidance();
|
|
306
356
|
return;
|
|
307
357
|
}
|
|
308
358
|
console.log(chalk.yellow(`\nWarning: ${formatVerificationFailure(result, expectedVersion)}`));
|
|
@@ -385,10 +435,10 @@ async function updateViaBinaryAt(targetPath: string, expectedVersion: string): P
|
|
|
385
435
|
tempPath,
|
|
386
436
|
backupPath,
|
|
387
437
|
expectedVersion,
|
|
388
|
-
verifyInstalledVersion,
|
|
438
|
+
verifyInstalledVersion: verifyInstalledRuntime,
|
|
389
439
|
});
|
|
390
440
|
printVerifiedVersion(expectedVersion);
|
|
391
|
-
|
|
441
|
+
printRestartGuidance();
|
|
392
442
|
}
|
|
393
443
|
|
|
394
444
|
/**
|
package/src/commands/launch.ts
CHANGED
|
@@ -169,7 +169,7 @@ export default class Index extends Command {
|
|
|
169
169
|
rawArgs: launch.args,
|
|
170
170
|
cwd: launch.cwd,
|
|
171
171
|
worktreeBranch: launch.worktree.enabled && !launch.worktree.detached ? launch.worktree.branchName : null,
|
|
172
|
-
project: launch.
|
|
172
|
+
project: launch.cwd,
|
|
173
173
|
})
|
|
174
174
|
)
|
|
175
175
|
return;
|
|
@@ -872,7 +872,13 @@ const customReferenceMap = buildCustomReferenceMap();
|
|
|
872
872
|
|
|
873
873
|
function getCustomReferenceCandidateIds(modelId: string): string[] {
|
|
874
874
|
const candidates = new Set<string>();
|
|
875
|
-
const
|
|
875
|
+
const minimaxM = /^minimax-m(\d+(?:\.\d+)*)$/i.exec(modelId.trim());
|
|
876
|
+
const queue = minimaxM ? [`MiniMax-M${minimaxM[1]}`, modelId] : [modelId];
|
|
877
|
+
if (minimaxM) {
|
|
878
|
+
// MiniMax catalogs include lowercase wire ids plus display-cased aliases.
|
|
879
|
+
// Custom providers should keep the lowercase wire id while inheriting the
|
|
880
|
+
// canonical display casing when the alias exists.
|
|
881
|
+
}
|
|
876
882
|
for (let index = 0; index < queue.length; index += 1) {
|
|
877
883
|
const candidate = queue[index]?.trim();
|
|
878
884
|
if (!candidate || candidates.has(candidate)) continue;
|
|
@@ -1212,13 +1218,14 @@ export class ModelRegistry {
|
|
|
1212
1218
|
const existingIndex = indexByKey.get(key);
|
|
1213
1219
|
if (existingIndex !== undefined) {
|
|
1214
1220
|
const existingModel = merged[existingIndex];
|
|
1221
|
+
const referenceModel = resolveCustomModelReference(customModel.id);
|
|
1215
1222
|
merged[existingIndex] = enrichModelThinking({
|
|
1216
1223
|
...existingModel,
|
|
1217
1224
|
id: customModel.id,
|
|
1218
1225
|
provider: customModel.provider,
|
|
1219
1226
|
api: customModel.api,
|
|
1220
1227
|
baseUrl: customModel.baseUrl,
|
|
1221
|
-
name: customModel.name ?? existingModel.name,
|
|
1228
|
+
name: customModel.name ?? referenceModel?.name ?? existingModel.name,
|
|
1222
1229
|
reasoning: customModel.reasoning ?? existingModel.reasoning,
|
|
1223
1230
|
thinking: customModel.thinking ?? existingModel.thinking,
|
|
1224
1231
|
input: customModel.input ?? existingModel.input,
|
|
@@ -147,12 +147,23 @@ export function resolveProviderModelReference(
|
|
|
147
147
|
modelId: string,
|
|
148
148
|
availableModels: readonly Model<Api>[],
|
|
149
149
|
): Model<Api> | undefined {
|
|
150
|
-
const
|
|
151
|
-
const
|
|
150
|
+
const trimmedProvider = provider.trim();
|
|
151
|
+
const trimmedModelId = modelId.trim();
|
|
152
|
+
const normalizedProvider = trimmedProvider.toLowerCase();
|
|
153
|
+
const normalizedModelId = trimmedModelId.toLowerCase();
|
|
152
154
|
if (!normalizedProvider || !normalizedModelId) {
|
|
153
155
|
return undefined;
|
|
154
156
|
}
|
|
155
157
|
|
|
158
|
+
// Prefer an exact provider/model id match before falling back to the
|
|
159
|
+
// case-insensitive index. Some provider catalogs intentionally carry both a
|
|
160
|
+
// machine-id form (for example `minimax-m3`) and a display-cased alias
|
|
161
|
+
// (`MiniMax-M3`). The lowercase index correctly treats those aliases as
|
|
162
|
+
// ambiguous for fuzzy/case-insensitive lookup, but an exact selector should
|
|
163
|
+
// still resolve deterministically.
|
|
164
|
+
const caseExact = availableModels.find(m => m.provider === trimmedProvider && m.id === trimmedModelId);
|
|
165
|
+
if (caseExact) return caseExact;
|
|
166
|
+
|
|
156
167
|
const index = getProviderModelIndex(availableModels);
|
|
157
168
|
const exact = index.get(`${normalizedProvider}\u0000${normalizedModelId}`);
|
|
158
169
|
if (exact === null) {
|
|
@@ -22,6 +22,7 @@ const ReasoningEffortMapSchema = z.object({
|
|
|
22
22
|
export const OpenAICompatSchema = z.object({
|
|
23
23
|
supportsStore: z.boolean().optional(),
|
|
24
24
|
supportsDeveloperRole: z.boolean().optional(),
|
|
25
|
+
sendSessionHeaders: z.boolean().optional(),
|
|
25
26
|
supportsMultipleSystemMessages: z.boolean().optional(),
|
|
26
27
|
supportsReasoningEffort: z.boolean().optional(),
|
|
27
28
|
reasoningEffortMap: ReasoningEffortMapSchema.optional(),
|