@gajae-code/coding-agent 0.2.1 → 0.2.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 +31 -1
- package/dist/types/commands/contribution-prep.d.ts +18 -0
- package/dist/types/commands/session.d.ts +24 -0
- package/dist/types/config/model-registry.d.ts +2 -2
- package/dist/types/config/models-config-schema.d.ts +17 -9
- package/dist/types/config/settings-schema.d.ts +1 -24
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +15 -0
- package/dist/types/gjc-runtime/goal-mode-request.d.ts +1 -1
- package/dist/types/gjc-runtime/launch-tmux.d.ts +12 -11
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +25 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +13 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +37 -5
- package/dist/types/gjc-runtime/tmux-common.d.ts +41 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +17 -0
- package/dist/types/goals/runtime.d.ts +3 -9
- package/dist/types/goals/state.d.ts +3 -6
- package/dist/types/goals/tools/goal-tool.d.ts +1 -69
- package/dist/types/modes/components/status-line/types.d.ts +0 -3
- package/dist/types/modes/components/status-line.d.ts +0 -3
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -12
- package/dist/types/modes/theme/defaults/index.d.ts +0 -2
- package/dist/types/modes/theme/theme.d.ts +1 -2
- package/dist/types/modes/types.d.ts +1 -7
- package/dist/types/session/agent-session.d.ts +2 -0
- package/dist/types/session/contribution-prep.d.ts +47 -0
- package/dist/types/skill-state/active-state.d.ts +4 -0
- package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +6 -1
- package/dist/types/skill-state/workflow-hud.d.ts +9 -4
- package/dist/types/skill-state/workflow-state-contract.d.ts +34 -0
- package/package.json +7 -7
- package/src/cli/args.ts +3 -2
- package/src/cli.ts +6 -1
- package/src/commands/contribution-prep.ts +41 -0
- package/src/commands/deep-interview.ts +6 -22
- package/src/commands/launch.ts +10 -1
- package/src/commands/ralplan.ts +10 -22
- package/src/commands/session.ts +150 -0
- package/src/commands/state.ts +14 -4
- package/src/commands/team.ts +23 -3
- package/src/config/model-registry.ts +10 -2
- package/src/config/models-config-schema.ts +120 -102
- package/src/config/settings-schema.ts +1 -25
- package/src/config.ts +1 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +14 -13
- package/src/defaults/gjc/skills/ralplan/SKILL.md +14 -2
- package/src/defaults/gjc/skills/team/SKILL.md +29 -7
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +23 -25
- package/src/eval/py/prelude.py +1 -1
- package/src/gjc-runtime/deep-interview-runtime.ts +279 -0
- package/src/gjc-runtime/goal-mode-request.ts +2 -19
- package/src/gjc-runtime/launch-tmux.ts +83 -43
- package/src/gjc-runtime/ralplan-runtime.ts +460 -0
- package/src/gjc-runtime/state-runtime.ts +562 -0
- package/src/gjc-runtime/team-runtime.ts +708 -52
- package/src/gjc-runtime/tmux-common.ts +119 -0
- package/src/gjc-runtime/tmux-sessions.ts +165 -0
- package/src/gjc-runtime/ultragoal-guard.ts +6 -3
- package/src/gjc-runtime/ultragoal-runtime.ts +5 -4
- package/src/goals/runtime.ts +38 -144
- package/src/goals/state.ts +36 -7
- package/src/goals/tools/goal-tool.ts +15 -172
- package/src/hooks/skill-state.ts +31 -12
- package/src/internal-urls/docs-index.generated.ts +4 -3
- package/src/modes/components/skill-hud/render.ts +4 -0
- package/src/modes/components/status-line/segments.ts +5 -16
- package/src/modes/components/status-line/types.ts +0 -3
- package/src/modes/components/status-line.ts +0 -6
- package/src/modes/controllers/command-controller.ts +25 -1
- package/src/modes/controllers/input-controller.ts +0 -15
- package/src/modes/interactive-mode.ts +18 -219
- package/src/modes/theme/defaults/dark-poimandres.json +0 -1
- package/src/modes/theme/defaults/light-poimandres.json +0 -1
- package/src/modes/theme/theme.ts +0 -6
- package/src/modes/types.ts +1 -7
- package/src/prompts/goals/goal-continuation.md +1 -4
- package/src/prompts/goals/goal-mode-active.md +3 -5
- package/src/prompts/system/system-prompt.md +5 -7
- package/src/prompts/tools/goal.md +4 -4
- package/src/sdk.ts +1 -1
- package/src/session/agent-session.ts +18 -0
- package/src/session/contribution-prep.ts +320 -0
- package/src/skill-state/active-state.ts +38 -0
- package/src/skill-state/deep-interview-mutation-guard.ts +88 -24
- package/src/skill-state/workflow-hud.ts +23 -5
- package/src/skill-state/workflow-state-contract.ts +121 -0
- package/src/slash-commands/builtin-registry.ts +24 -12
- package/src/task/commands.ts +1 -5
- package/src/tools/gh.ts +212 -2
- package/src/tools/index.ts +2 -5
- package/dist/types/commands/gjc-runtime-bridge.d.ts +0 -30
- package/dist/types/commands/question.d.ts +0 -7
- package/dist/types/modes/loop-limit.d.ts +0 -22
- package/src/commands/gjc-runtime-bridge.ts +0 -227
- package/src/commands/question.ts +0 -12
- package/src/modes/loop-limit.ts +0 -140
- package/src/prompts/commands/orchestrate.md +0 -49
- package/src/prompts/goals/goal-budget-limit.md +0 -16
- package/src/prompts/tools/create-goal.md +0 -3
- package/src/prompts/tools/get-goal.md +0 -3
- package/src/prompts/tools/update-goal.md +0 -3
package/src/commands/ralplan.ts
CHANGED
|
@@ -1,31 +1,19 @@
|
|
|
1
1
|
import { Command } from "@gajae-code/utils/cli";
|
|
2
|
-
import {
|
|
3
|
-
import { runGjcRuntimeBridgeWithHudSidecar } from "./gjc-runtime-bridge";
|
|
2
|
+
import { runNativeRalplanCommand } from "../gjc-runtime/ralplan-runtime";
|
|
4
3
|
|
|
5
4
|
export default class Ralplan extends Command {
|
|
6
|
-
static description = "Run
|
|
5
|
+
static description = "Run native GJC RALPLAN consensus planning workflow";
|
|
7
6
|
static strict = false;
|
|
8
|
-
static examples = [
|
|
7
|
+
static examples = [
|
|
8
|
+
'$ gjc ralplan "<task description>"',
|
|
9
|
+
'$ gjc ralplan --interactive --deliberate "<task description>"',
|
|
10
|
+
'$ gjc ralplan --write --stage planner --stage_n 1 --artifact "<markdown or path>"',
|
|
11
|
+
];
|
|
9
12
|
|
|
10
13
|
async run(): Promise<void> {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
sidecarSkill: "ralplan",
|
|
15
|
-
onHudPayload: payload =>
|
|
16
|
-
syncSkillActiveState({
|
|
17
|
-
cwd,
|
|
18
|
-
skill: "ralplan",
|
|
19
|
-
active: payload.active ?? true,
|
|
20
|
-
phase: payload.phase,
|
|
21
|
-
sessionId: payload.session_id,
|
|
22
|
-
threadId: payload.thread_id,
|
|
23
|
-
turnId: payload.turn_id,
|
|
24
|
-
hud: payload.hud,
|
|
25
|
-
source: "gjc-runtime-bridge",
|
|
26
|
-
}),
|
|
27
|
-
});
|
|
28
|
-
if (result.error) process.stderr.write(`${result.error}\n`);
|
|
14
|
+
const result = await runNativeRalplanCommand(this.argv, process.cwd());
|
|
15
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
16
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
29
17
|
process.exitCode = result.status;
|
|
30
18
|
}
|
|
31
19
|
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { Args, Command, Flags } from "@gajae-code/utils/cli";
|
|
2
|
+
import {
|
|
3
|
+
attachGjcTmuxSession,
|
|
4
|
+
createGjcTmuxSession,
|
|
5
|
+
listGjcTmuxSessions,
|
|
6
|
+
removeGjcTmuxSession,
|
|
7
|
+
statusGjcTmuxSession,
|
|
8
|
+
} from "../gjc-runtime/tmux-sessions";
|
|
9
|
+
|
|
10
|
+
function writeJson(value: unknown): void {
|
|
11
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function writeText(lines: string[]): void {
|
|
15
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function writeJsonFailure(error: unknown): void {
|
|
19
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
20
|
+
const [reason = "session_error"] = message.split(":");
|
|
21
|
+
writeJson({ ok: false, reason });
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface SessionJsonDto {
|
|
25
|
+
name: string;
|
|
26
|
+
attached: boolean;
|
|
27
|
+
windows: number;
|
|
28
|
+
panes: number;
|
|
29
|
+
bindings: string;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function sessionJson(session: SessionJsonDto): SessionJsonDto {
|
|
34
|
+
return {
|
|
35
|
+
name: session.name,
|
|
36
|
+
attached: session.attached,
|
|
37
|
+
windows: session.windows,
|
|
38
|
+
panes: session.panes,
|
|
39
|
+
bindings: session.bindings,
|
|
40
|
+
createdAt: session.createdAt,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default class Session extends Command {
|
|
45
|
+
static description = "List, inspect, attach, and remove tagged GJC-managed tmux sessions";
|
|
46
|
+
static strict = false;
|
|
47
|
+
|
|
48
|
+
static args = {
|
|
49
|
+
action: Args.string({
|
|
50
|
+
description: "list (default), status, create, attach, or remove",
|
|
51
|
+
required: false,
|
|
52
|
+
}),
|
|
53
|
+
session: Args.string({
|
|
54
|
+
description: "Session name for status, attach, or remove",
|
|
55
|
+
required: false,
|
|
56
|
+
}),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
static flags = {
|
|
60
|
+
json: Flags.boolean({ char: "j", description: "Emit machine-readable JSON", default: false }),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
static examples = [
|
|
64
|
+
"gjc session list",
|
|
65
|
+
"gjc session create",
|
|
66
|
+
"gjc session status <session>",
|
|
67
|
+
"gjc session attach <session>",
|
|
68
|
+
"gjc session remove <session>",
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
async run(): Promise<void> {
|
|
72
|
+
const { args, flags } = await this.parse(Session);
|
|
73
|
+
const action = args.action ?? "list";
|
|
74
|
+
const sessionName = args.session;
|
|
75
|
+
const json = flags.json ?? false;
|
|
76
|
+
try {
|
|
77
|
+
if (action === "list") {
|
|
78
|
+
const sessions = listGjcTmuxSessions();
|
|
79
|
+
if (json) {
|
|
80
|
+
writeJson({ ok: true, sessions: sessions.map(sessionJson) });
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
writeText(
|
|
84
|
+
sessions.map(session =>
|
|
85
|
+
[
|
|
86
|
+
session.name,
|
|
87
|
+
`windows=${session.windows}`,
|
|
88
|
+
`attached=${session.attached}`,
|
|
89
|
+
`createdAt=${session.createdAt}`,
|
|
90
|
+
`panes=${session.panes}`,
|
|
91
|
+
`bindings=${session.bindings || "none"}`,
|
|
92
|
+
].join("\t"),
|
|
93
|
+
),
|
|
94
|
+
);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (action === "create") {
|
|
99
|
+
const session = createGjcTmuxSession();
|
|
100
|
+
if (json) {
|
|
101
|
+
writeJson({ ok: true, session: sessionJson(session) });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
writeText([`created: ${session.name}`]);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (!sessionName) throw new Error("missing_session_name");
|
|
109
|
+
|
|
110
|
+
if (action === "status") {
|
|
111
|
+
const session = statusGjcTmuxSession(sessionName);
|
|
112
|
+
if (json) {
|
|
113
|
+
writeJson({ ok: true, session: sessionJson(session) });
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
writeText([
|
|
117
|
+
`session: ${session.name}`,
|
|
118
|
+
`windows: ${session.windows}`,
|
|
119
|
+
`attached: ${session.attached}`,
|
|
120
|
+
`createdAt: ${session.createdAt}`,
|
|
121
|
+
`panes: ${session.panes}`,
|
|
122
|
+
`bindings: ${session.bindings || "none"}`,
|
|
123
|
+
]);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (action === "remove" || action === "rm" || action === "delete") {
|
|
128
|
+
const removed = removeGjcTmuxSession(sessionName);
|
|
129
|
+
if (json) {
|
|
130
|
+
writeJson({ ok: true, session: sessionJson(removed) });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
writeText([`removed: ${removed.name}`]);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (action === "attach") {
|
|
138
|
+
attachGjcTmuxSession(sessionName);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
throw new Error(`unknown_session_action:${action}`);
|
|
142
|
+
} catch (error) {
|
|
143
|
+
if (json) {
|
|
144
|
+
writeJsonFailure(error);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
package/src/commands/state.ts
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { Command } from "@gajae-code/utils/cli";
|
|
2
|
-
import {
|
|
2
|
+
import { runNativeStateCommand } from "../gjc-runtime/state-runtime";
|
|
3
3
|
|
|
4
4
|
export default class State extends Command {
|
|
5
|
-
static description = "Read or update
|
|
5
|
+
static description = "Read or update GJC workflow state receipts under .gjc/state";
|
|
6
6
|
static strict = false;
|
|
7
|
-
static examples = [
|
|
7
|
+
static examples = [
|
|
8
|
+
'$ gjc state read --input \'{"mode":"deep-interview"}\' --json',
|
|
9
|
+
'$ gjc state write --input \'{"state":{"interview_id":"abc"}}\' --mode deep-interview --json',
|
|
10
|
+
"$ gjc state clear --mode deep-interview",
|
|
11
|
+
"$ gjc state deep-interview read --json",
|
|
12
|
+
'$ gjc state ralplan write --input \'{"phase":"approval","active":true}\' --json',
|
|
13
|
+
"$ gjc state team contract",
|
|
14
|
+
];
|
|
8
15
|
|
|
9
16
|
async run(): Promise<void> {
|
|
10
|
-
await
|
|
17
|
+
const result = await runNativeStateCommand(this.argv);
|
|
18
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
19
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
20
|
+
process.exitCode = result.status;
|
|
11
21
|
}
|
|
12
22
|
}
|
package/src/commands/team.ts
CHANGED
|
@@ -42,6 +42,18 @@ function formatTaskCounts(counts: Record<string, number>): string {
|
|
|
42
42
|
.join(" ");
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
function formatNotificationSummary(snapshot: GjcTeamSnapshot): string {
|
|
46
|
+
const summary = snapshot.notification_summary;
|
|
47
|
+
return `notifications: total=${summary.total} replay_eligible=${summary.replay_eligible} pending=${summary.by_state.pending} queued=${summary.by_state.queued} deferred=${summary.by_state.deferred} failed=${summary.by_state.failed}`;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function formatAwaitingIntegrationNextStep(snapshot: GjcTeamSnapshot): string[] {
|
|
51
|
+
if (snapshot.phase !== "awaiting_integration") return [];
|
|
52
|
+
return [
|
|
53
|
+
"next: worker tasks are completed, but integration still needs leader attention before the team is complete",
|
|
54
|
+
];
|
|
55
|
+
}
|
|
56
|
+
|
|
45
57
|
function formatIntegrationSummary(snapshot: {
|
|
46
58
|
integration_by_worker?: Record<string, { status?: string; conflict_files?: string[] }>;
|
|
47
59
|
}): string[] {
|
|
@@ -64,7 +76,7 @@ function parseInputFlag(argv: string[]): Record<string, unknown> {
|
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
export default class Team extends Command {
|
|
67
|
-
static description = "Run native GJC tmux team orchestration
|
|
79
|
+
static description = "Run native GJC tmux team orchestration; --dry-run writes ephemeral .gjc/state/team state only";
|
|
68
80
|
static strict = false;
|
|
69
81
|
|
|
70
82
|
static args = {
|
|
@@ -76,13 +88,18 @@ export default class Team extends Command {
|
|
|
76
88
|
|
|
77
89
|
static flags = {
|
|
78
90
|
json: Flags.boolean({ char: "j", description: "Emit machine-readable JSON", default: false }),
|
|
79
|
-
"dry-run": Flags.boolean({
|
|
91
|
+
"dry-run": Flags.boolean({
|
|
92
|
+
description:
|
|
93
|
+
"Create ephemeral .gjc/state/team state without starting tmux panes; do not commit generated state",
|
|
94
|
+
default: false,
|
|
95
|
+
}),
|
|
80
96
|
};
|
|
81
97
|
|
|
82
98
|
static examples = [
|
|
83
99
|
'gjc team 3:executor "Implement the approved plan"',
|
|
84
100
|
"gjc team status <team-name> --json",
|
|
85
101
|
'gjc team api claim-task --input \'{"team_name":"demo","worker_id":"worker-1"}\' --json',
|
|
102
|
+
'gjc team 2:executor --dry-run --json "Preview state only"',
|
|
86
103
|
"gjc team shutdown <team-name>",
|
|
87
104
|
];
|
|
88
105
|
|
|
@@ -118,6 +135,8 @@ export default class Team extends Command {
|
|
|
118
135
|
`state: ${snapshot.state_dir}`,
|
|
119
136
|
`tasks: ${snapshot.task_total} (${formatTaskCounts(snapshot.task_counts)})`,
|
|
120
137
|
`workers: ${snapshot.workers.map(worker => `${worker.id}:${worker.status}`).join(" ")}`,
|
|
138
|
+
formatNotificationSummary(snapshot),
|
|
139
|
+
...formatAwaitingIntegrationNextStep(snapshot),
|
|
121
140
|
...formatIntegrationSummary(snapshot),
|
|
122
141
|
]);
|
|
123
142
|
return;
|
|
@@ -141,7 +160,7 @@ export default class Team extends Command {
|
|
|
141
160
|
if (!operation || operation === "--help" || operation === "help") {
|
|
142
161
|
writeText([
|
|
143
162
|
"Supported operations:",
|
|
144
|
-
"send-message broadcast mailbox-list mailbox-mark-delivered mailbox-mark-notified",
|
|
163
|
+
"send-message broadcast mailbox-list mailbox-mark-delivered mailbox-mark-notified notification-list notification-read notification-replay notification-mark-pane-attempt worker-startup-ack",
|
|
145
164
|
"create-task read-task list-tasks update-task claim-task transition-task-status release-task-claim",
|
|
146
165
|
"read-config read-manifest read-worker-status read-worker-heartbeat update-worker-heartbeat write-worker-inbox write-worker-identity",
|
|
147
166
|
"append-event read-events await-event write-shutdown-request read-shutdown-ack read-monitor-snapshot write-monitor-snapshot read-task-approval write-task-approval",
|
|
@@ -176,6 +195,7 @@ export default class Team extends Command {
|
|
|
176
195
|
`tmux: ${snapshot.tmux_session}`,
|
|
177
196
|
`state: ${snapshot.state_dir}`,
|
|
178
197
|
`workers: ${snapshot.workers.length}`,
|
|
198
|
+
...(dryRun ? ["dry-run: wrote ephemeral .gjc/state/team state only; do not commit generated .gjc state"] : []),
|
|
179
199
|
]);
|
|
180
200
|
}
|
|
181
201
|
}
|
|
@@ -243,6 +243,10 @@ interface ProviderValidationConfig {
|
|
|
243
243
|
models: ProviderValidationModel[];
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
+
function usesAwsCredentialChain(api: Api | undefined): boolean {
|
|
247
|
+
return api === "bedrock-converse-stream";
|
|
248
|
+
}
|
|
249
|
+
|
|
246
250
|
function validateProviderConfiguration(
|
|
247
251
|
providerName: string,
|
|
248
252
|
config: ProviderValidationConfig,
|
|
@@ -274,10 +278,14 @@ function validateProviderConfiguration(
|
|
|
274
278
|
if (!config.baseUrl) {
|
|
275
279
|
throw new Error(`Provider ${providerName}: "baseUrl" is required when defining custom models.`);
|
|
276
280
|
}
|
|
281
|
+
const usesProviderCredentialChain = usesAwsCredentialChain(config.api);
|
|
277
282
|
const requiresAuth =
|
|
278
283
|
mode === "runtime-register"
|
|
279
|
-
? !config.apiKey && !config.oauthConfigured
|
|
280
|
-
: !
|
|
284
|
+
? !usesProviderCredentialChain && !config.apiKey && !config.oauthConfigured
|
|
285
|
+
: !usesProviderCredentialChain &&
|
|
286
|
+
!config.apiKey &&
|
|
287
|
+
!config.apiKeyEnv &&
|
|
288
|
+
(config.auth ?? "apiKey") !== "none";
|
|
281
289
|
if (requiresAuth) {
|
|
282
290
|
throw new Error(
|
|
283
291
|
mode === "runtime-register"
|
|
@@ -63,76 +63,86 @@ const ModelThinkingSchema = z.object({
|
|
|
63
63
|
levels: z.array(EffortSchema).optional(),
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
const RequestTransformSchema = z
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
const RequestTransformSchema = z
|
|
67
|
+
.object({
|
|
68
|
+
profile: z.enum(["openai-proxy"]).optional(),
|
|
69
|
+
stripHeaders: z.array(z.string().min(1)).optional(),
|
|
70
|
+
setHeaders: z.record(z.string(), z.string().nullable()).optional(),
|
|
71
|
+
extraBody: z.record(z.string(), z.unknown()).optional(),
|
|
72
|
+
})
|
|
73
|
+
.strict();
|
|
72
74
|
|
|
73
75
|
const ModelBindingsSchema = z.object({
|
|
74
76
|
modelRoles: z.record(z.string(), z.string().min(1)).optional(),
|
|
75
77
|
agentModelOverrides: z.record(z.string(), z.string().min(1)).optional(),
|
|
76
78
|
});
|
|
77
79
|
|
|
78
|
-
const ModelDefinitionSchema = z
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
80
|
+
const ModelDefinitionSchema = z
|
|
81
|
+
.object({
|
|
82
|
+
id: z.string().min(1),
|
|
83
|
+
name: z.string().min(1).optional(),
|
|
84
|
+
api: z
|
|
85
|
+
.enum([
|
|
86
|
+
"openai-completions",
|
|
87
|
+
"openai-responses",
|
|
88
|
+
"openai-codex-responses",
|
|
89
|
+
"azure-openai-responses",
|
|
90
|
+
"anthropic-messages",
|
|
91
|
+
"bedrock-converse-stream",
|
|
92
|
+
"google-generative-ai",
|
|
93
|
+
"google-vertex",
|
|
94
|
+
"google-gemini-cli",
|
|
95
|
+
"ollama-chat",
|
|
96
|
+
"cursor-agent",
|
|
97
|
+
])
|
|
98
|
+
.optional(),
|
|
99
|
+
baseUrl: z.string().min(1).optional(),
|
|
100
|
+
reasoning: z.boolean().optional(),
|
|
101
|
+
thinking: ModelThinkingSchema.optional(),
|
|
102
|
+
input: z.array(z.enum(["text", "image"])).optional(),
|
|
103
|
+
cost: z
|
|
104
|
+
.object({
|
|
105
|
+
input: z.number(),
|
|
106
|
+
output: z.number(),
|
|
107
|
+
cacheRead: z.number(),
|
|
108
|
+
cacheWrite: z.number(),
|
|
109
|
+
})
|
|
110
|
+
.optional(),
|
|
111
|
+
premiumMultiplier: z.number().optional(),
|
|
112
|
+
contextWindow: z.number().optional(),
|
|
113
|
+
maxTokens: z.number().optional(),
|
|
114
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
115
|
+
compat: OpenAICompatSchema.optional(),
|
|
116
|
+
contextPromotionTarget: z.string().min(1).optional(),
|
|
117
|
+
wireModelId: z.string().min(1).optional(),
|
|
118
|
+
requestTransform: RequestTransformSchema.optional(),
|
|
119
|
+
})
|
|
120
|
+
.strict();
|
|
121
|
+
|
|
122
|
+
export const ModelOverrideSchema = z
|
|
123
|
+
.object({
|
|
124
|
+
name: z.string().min(1).optional(),
|
|
125
|
+
reasoning: z.boolean().optional(),
|
|
126
|
+
thinking: ModelThinkingSchema.optional(),
|
|
127
|
+
input: z.array(z.enum(["text", "image"])).optional(),
|
|
128
|
+
cost: z
|
|
129
|
+
.object({
|
|
130
|
+
input: z.number().optional(),
|
|
131
|
+
output: z.number().optional(),
|
|
132
|
+
cacheRead: z.number().optional(),
|
|
133
|
+
cacheWrite: z.number().optional(),
|
|
134
|
+
})
|
|
135
|
+
.optional(),
|
|
136
|
+
premiumMultiplier: z.number().optional(),
|
|
137
|
+
contextWindow: z.number().optional(),
|
|
138
|
+
maxTokens: z.number().optional(),
|
|
139
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
140
|
+
compat: OpenAICompatSchema.optional(),
|
|
141
|
+
contextPromotionTarget: z.string().min(1).optional(),
|
|
142
|
+
wireModelId: z.string().min(1).optional(),
|
|
143
|
+
requestTransform: RequestTransformSchema.optional(),
|
|
144
|
+
})
|
|
145
|
+
.strict();
|
|
136
146
|
|
|
137
147
|
export type ModelOverride = z.infer<typeof ModelOverrideSchema>;
|
|
138
148
|
|
|
@@ -145,49 +155,57 @@ export const ProviderAuthSchema = z.enum(["apiKey", "none", "oauth"]);
|
|
|
145
155
|
export type ProviderAuthMode = z.infer<typeof ProviderAuthSchema>;
|
|
146
156
|
export type ProviderDiscovery = z.infer<typeof ProviderDiscoverySchema>;
|
|
147
157
|
|
|
148
|
-
const ProviderConfigSchema = z
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
158
|
+
const ProviderConfigSchema = z
|
|
159
|
+
.object({
|
|
160
|
+
baseUrl: z.string().min(1).optional(),
|
|
161
|
+
apiKey: z.string().min(1).optional(),
|
|
162
|
+
apiKeyEnv: z.string().min(1).optional(),
|
|
163
|
+
api: z
|
|
164
|
+
.enum([
|
|
165
|
+
"openai-completions",
|
|
166
|
+
"openai-responses",
|
|
167
|
+
"openai-codex-responses",
|
|
168
|
+
"azure-openai-responses",
|
|
169
|
+
"anthropic-messages",
|
|
170
|
+
"bedrock-converse-stream",
|
|
171
|
+
"google-generative-ai",
|
|
172
|
+
"google-vertex",
|
|
173
|
+
"google-gemini-cli",
|
|
174
|
+
"ollama-chat",
|
|
175
|
+
"cursor-agent",
|
|
176
|
+
])
|
|
177
|
+
.optional(),
|
|
178
|
+
headers: z.record(z.string(), z.string()).optional(),
|
|
179
|
+
compat: OpenAICompatSchema.optional(),
|
|
180
|
+
authHeader: z.boolean().optional(),
|
|
181
|
+
auth: ProviderAuthSchema.optional(),
|
|
182
|
+
discovery: ProviderDiscoverySchema.optional(),
|
|
183
|
+
requestTransform: RequestTransformSchema.optional(),
|
|
184
|
+
models: z.array(ModelDefinitionSchema).optional(),
|
|
185
|
+
modelOverrides: z.record(z.string(), ModelOverrideSchema).optional(),
|
|
186
|
+
disableStrictTools: z.boolean().optional(),
|
|
187
|
+
/**
|
|
188
|
+
* Streaming transport override. When set to `"pi-native"`, gjc dispatches
|
|
189
|
+
* every model under this provider via the auth-gateway's
|
|
190
|
+
* `POST /v1/pi/stream` endpoint instead of the per-provider SDK. The
|
|
191
|
+
* provider's `baseUrl` must point at a compatible `gjc auth-gateway`
|
|
192
|
+
* and `apiKey` must carry the gateway bearer.
|
|
193
|
+
*/
|
|
194
|
+
transport: z.literal("pi-native").optional(),
|
|
195
|
+
})
|
|
196
|
+
.strict();
|
|
181
197
|
|
|
182
198
|
const EquivalenceConfigSchema = z.object({
|
|
183
199
|
overrides: z.record(z.string(), z.string().min(1)).optional(),
|
|
184
200
|
exclude: z.array(z.string().min(1)).optional(),
|
|
185
201
|
});
|
|
186
202
|
|
|
187
|
-
export const ModelsConfigSchema = z
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
203
|
+
export const ModelsConfigSchema = z
|
|
204
|
+
.object({
|
|
205
|
+
providers: z.record(z.string(), ProviderConfigSchema).optional(),
|
|
206
|
+
modelBindings: ModelBindingsSchema.optional(),
|
|
207
|
+
equivalence: EquivalenceConfigSchema.optional(),
|
|
208
|
+
})
|
|
209
|
+
.strict();
|
|
192
210
|
|
|
193
211
|
export type ModelsConfig = z.infer<typeof ModelsConfigSchema>;
|
|
@@ -901,30 +901,6 @@ export const SETTINGS_SCHEMA = {
|
|
|
901
901
|
},
|
|
902
902
|
},
|
|
903
903
|
|
|
904
|
-
"loop.mode": {
|
|
905
|
-
type: "enum",
|
|
906
|
-
values: ["prompt", "compact", "reset"] as const,
|
|
907
|
-
default: "prompt",
|
|
908
|
-
ui: {
|
|
909
|
-
tab: "interaction",
|
|
910
|
-
label: "Loop Mode",
|
|
911
|
-
description: "What happens between /loop iterations before re-submitting the prompt",
|
|
912
|
-
options: [
|
|
913
|
-
{
|
|
914
|
-
value: "prompt",
|
|
915
|
-
label: "Prompt",
|
|
916
|
-
description: "Re-submit the prompt as a follow-up message (current behavior)",
|
|
917
|
-
},
|
|
918
|
-
{
|
|
919
|
-
value: "compact",
|
|
920
|
-
label: "Compact",
|
|
921
|
-
description: "Compact the session context, then re-submit the prompt",
|
|
922
|
-
},
|
|
923
|
-
{ value: "reset", label: "Reset", description: "Start a new session, then re-submit the prompt" },
|
|
924
|
-
],
|
|
925
|
-
},
|
|
926
|
-
},
|
|
927
|
-
|
|
928
904
|
// Input and startup
|
|
929
905
|
doubleEscapeAction: {
|
|
930
906
|
type: "enum",
|
|
@@ -2207,7 +2183,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
2207
2183
|
ui: {
|
|
2208
2184
|
tab: "tasks",
|
|
2209
2185
|
label: "Goal Status In Footer",
|
|
2210
|
-
description: "Show
|
|
2186
|
+
description: "Show goal usage alongside the goal indicator in the status line",
|
|
2211
2187
|
},
|
|
2212
2188
|
},
|
|
2213
2189
|
|
package/src/config.ts
CHANGED
|
@@ -20,7 +20,7 @@ const PROJECT_CONFIG_PRIORITY = [{ dir: CONFIG_DIR_NAME }, { dir: ".gemini" }];
|
|
|
20
20
|
*/
|
|
21
21
|
export function getPackageDir(): string {
|
|
22
22
|
// Allow override via environment variable (useful for Nix/Guix where store paths tokenize poorly)
|
|
23
|
-
const envDir = process.env.PI_PACKAGE_DIR;
|
|
23
|
+
const envDir = process.env.GJC_PACKAGE_DIR ?? process.env.PI_PACKAGE_DIR;
|
|
24
24
|
if (envDir) {
|
|
25
25
|
return expandTilde(envDir);
|
|
26
26
|
}
|