@gajae-code/coding-agent 0.7.9 → 0.7.10
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 +22 -0
- package/README.md +2 -0
- package/dist/types/config/settings-schema.d.ts +10 -1
- package/dist/types/extensibility/extensions/types.d.ts +11 -0
- package/dist/types/gjc-runtime/launch-tmux.d.ts +7 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +0 -4
- package/dist/types/modes/components/hook-selector.d.ts +5 -0
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +20 -6
- package/dist/types/notifications/html-format.d.ts +2 -0
- package/dist/types/notifications/recent-activity.d.ts +5 -1
- package/dist/types/notifications/telegram-daemon-control.d.ts +8 -0
- package/dist/types/notifications/telegram-reference.d.ts +4 -0
- package/dist/types/notifications/threaded-render.d.ts +1 -0
- package/dist/types/tools/ask.d.ts +2 -0
- package/dist/types/utils/cmux-workspace.d.ts +23 -0
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/provider.d.ts +5 -0
- package/dist/types/web/search/render.d.ts +1 -0
- package/package.json +7 -7
- package/src/cli/web-search-cli.ts +3 -2
- package/src/config/settings-schema.ts +11 -1
- package/src/coordinator-mcp/server.ts +1 -1
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +26 -2
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +37 -112
- package/src/extensibility/extensions/types.ts +11 -0
- package/src/gjc-runtime/launch-tmux.ts +63 -2
- package/src/gjc-runtime/ultragoal-guard.ts +139 -19
- package/src/gjc-runtime/ultragoal-runtime.ts +16 -124
- package/src/gjc-runtime/workflow-manifest.generated.json +0 -8
- package/src/gjc-runtime/workflow-manifest.ts +0 -1
- package/src/hooks/skill-state.ts +33 -73
- package/src/internal-urls/docs-index.generated.ts +2 -1
- package/src/modes/components/hook-selector.ts +21 -3
- package/src/modes/components/settings-selector.ts +47 -3
- package/src/modes/components/status-line/presets.ts +11 -0
- package/src/modes/controllers/extension-ui-controller.ts +18 -2
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +53 -9
- package/src/notifications/html-format.ts +75 -1
- package/src/notifications/index.ts +12 -1
- package/src/notifications/recent-activity.ts +32 -8
- package/src/notifications/telegram-daemon-control.ts +9 -0
- package/src/notifications/telegram-daemon.ts +67 -24
- package/src/notifications/telegram-reference.ts +36 -14
- package/src/notifications/threaded-render.ts +14 -6
- package/src/prompts/system/system-prompt.md +5 -1
- package/src/sdk.ts +3 -5
- package/src/tools/ask.ts +136 -16
- package/src/utils/cmux-workspace.ts +106 -0
- package/src/utils/title-generator.ts +2 -0
- package/src/web/search/index.ts +22 -10
- package/src/web/search/provider.ts +15 -0
- package/src/web/search/render.ts +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.7.10] - 2026-07-02
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- GJC now best-effort renames the containing cmux workspace to the current GJC session name when running inside a cmux terminal.
|
|
9
|
+
- Added a status line default usage preset (#1305).
|
|
10
|
+
- Telegram threaded updates now include verbose session identity (session id and cwd) metadata.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Deep Interview option-clarification prompts now stay out of the interview transcript and ambiguity recorder, so asking about displayed choices no longer persists as the round answer before the user selects an actual option.
|
|
15
|
+
- `gjc daemon reload telegram` now spawns the replacement daemon with a stable owner pid so the new daemon does not exit immediately after the short-lived reload CLI process ends.
|
|
16
|
+
- Managed `gjc --tmux` launches now size the initial window correctly (#1376).
|
|
17
|
+
- Coordinator tmux-delivered turns now submit correctly on Enter (#1372).
|
|
18
|
+
- Generic long `retry-after` rate limits are now kept retryable instead of being treated as fatal (#1370).
|
|
19
|
+
- Anthropic hard 429 responses are now surfaced before the stream watchdog fires (#1369).
|
|
20
|
+
- Internal sessions are now hidden from the Telegram recent-session list (#1367).
|
|
21
|
+
- Telegram messages exceeding the length limit are now chunked correctly.
|
|
22
|
+
- Web search now falls back correctly when the preferred provider is unavailable (#1348).
|
|
23
|
+
- Restored the Ultragoal team checkpoint snapshot wording (#1349).
|
|
24
|
+
- Deep Interview now exits early for simple tasks instead of running unnecessary rounds (#1311).
|
|
25
|
+
- Ultragoal goal identity and state now resolve solely from the canonical session-scoped `goals.json`, eliminating goal-identity drift from transcript-replayed snapshots (#1344).
|
|
26
|
+
|
|
5
27
|
## [0.7.9] - 2026-07-01
|
|
6
28
|
### Added
|
|
7
29
|
|
package/README.md
CHANGED
|
@@ -24,6 +24,8 @@ For simple local side effects that do not need a full extension, set the user-le
|
|
|
24
24
|
gjc config set completion.notifyCommand 'cmux notify --title "$GJC_NOTIFICATION_TITLE" --body "$GJC_NOTIFICATION_BODY"'
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
When GJC is running inside a cmux terminal (`CMUX_WORKSPACE_ID` is set), GJC also best-effort renames that cmux workspace to the current GJC session name whenever the session title is set or restored.
|
|
28
|
+
|
|
27
29
|
Windows Terminal may keep BEL (`[Console]::Write([char]7)`) silent depending on profile and system sound settings even when `notifications.terminalBell` is enabled. For an audible Windows completion beep, configure a user-level PowerShell command hook instead:
|
|
28
30
|
|
|
29
31
|
```powershell
|
|
@@ -351,7 +351,7 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
351
351
|
};
|
|
352
352
|
readonly "statusLine.preset": {
|
|
353
353
|
readonly type: "enum";
|
|
354
|
-
readonly values: readonly ["default", "minimal", "compact", "full", "nerd", "ascii", "custom"];
|
|
354
|
+
readonly values: readonly ["default", "default-usage", "minimal", "compact", "full", "nerd", "ascii", "custom"];
|
|
355
355
|
readonly default: "default";
|
|
356
356
|
readonly ui: {
|
|
357
357
|
readonly tab: "appearance";
|
|
@@ -361,6 +361,10 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
361
361
|
readonly value: "default";
|
|
362
362
|
readonly label: "Default";
|
|
363
363
|
readonly description: "Model, path, git, context, tokens, cost";
|
|
364
|
+
}, {
|
|
365
|
+
readonly value: "default-usage";
|
|
366
|
+
readonly label: "Default + Usage";
|
|
367
|
+
readonly description: "Default layout with provider usage quota";
|
|
364
368
|
}, {
|
|
365
369
|
readonly value: "minimal";
|
|
366
370
|
readonly label: "Minimal";
|
|
@@ -2575,6 +2579,11 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
2575
2579
|
readonly description: "Enable the web_search tool for web searching";
|
|
2576
2580
|
};
|
|
2577
2581
|
};
|
|
2582
|
+
readonly "web_search.provider": {
|
|
2583
|
+
readonly type: "enum";
|
|
2584
|
+
readonly values: readonly ["auto", "duckduckgo", "insane", "exa", "brave", "jina", "kimi", "zai", "anthropic", "perplexity", "gemini", "codex", "xai", "tavily", "parallel", "kagi", "synthetic", "searxng"];
|
|
2585
|
+
readonly default: "auto";
|
|
2586
|
+
};
|
|
2578
2587
|
readonly "web_search.fallback": {
|
|
2579
2588
|
readonly type: "array";
|
|
2580
2589
|
readonly default: string[];
|
|
@@ -76,6 +76,17 @@ export interface ExtensionUIDialogOptions {
|
|
|
76
76
|
optionLabel: string;
|
|
77
77
|
onSubmit: (text: string) => void;
|
|
78
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* Inline free-text input for a non-answer clarification action. It is
|
|
81
|
+
* separate from `customInput` so callers can distinguish "ask about these
|
|
82
|
+
* choices" from "provide my own answer". Empty/whitespace-only submissions
|
|
83
|
+
* may be rejected by the selector when `allowEmpty` is false.
|
|
84
|
+
*/
|
|
85
|
+
clarificationInput?: {
|
|
86
|
+
optionLabel: string;
|
|
87
|
+
onSubmit: (text: string) => void;
|
|
88
|
+
allowEmpty?: boolean;
|
|
89
|
+
};
|
|
79
90
|
}
|
|
80
91
|
/** Raw terminal input listener for extensions. */
|
|
81
92
|
export type TerminalInputHandler = (data: string) => {
|
|
@@ -8,6 +8,8 @@ export declare const GJC_PSMUX_PROFILE_FORCE_ENV = "GJC_PSMUX_PROFILE_FORCE";
|
|
|
8
8
|
interface TtyState {
|
|
9
9
|
stdin: boolean;
|
|
10
10
|
stdout: boolean;
|
|
11
|
+
columns?: number;
|
|
12
|
+
rows?: number;
|
|
11
13
|
}
|
|
12
14
|
export interface TmuxLaunchContext {
|
|
13
15
|
parsed: Args;
|
|
@@ -31,6 +33,10 @@ export interface TmuxSpawnResult {
|
|
|
31
33
|
signalCode?: string | null;
|
|
32
34
|
stderr?: string;
|
|
33
35
|
}
|
|
36
|
+
export interface TmuxTerminalSize {
|
|
37
|
+
columns: number;
|
|
38
|
+
rows: number;
|
|
39
|
+
}
|
|
34
40
|
export type TmuxSpawnSync = (command: string, args: string[], options: TmuxSpawnOptions) => TmuxSpawnResult;
|
|
35
41
|
export interface TmuxSpawnOptions {
|
|
36
42
|
cwd: string;
|
|
@@ -54,6 +60,7 @@ export interface TmuxLaunchPlan {
|
|
|
54
60
|
cwd: string;
|
|
55
61
|
innerCommand: string;
|
|
56
62
|
newSessionArgs: string[];
|
|
63
|
+
initialSize?: TmuxTerminalSize;
|
|
57
64
|
branch?: string | null;
|
|
58
65
|
attachSessionName?: string;
|
|
59
66
|
project?: string | null;
|
|
@@ -29,6 +29,10 @@ export declare function readUltragoalVerificationState(input: {
|
|
|
29
29
|
currentGoal?: CurrentGoalLike | null;
|
|
30
30
|
sessionId?: string | null;
|
|
31
31
|
}): Promise<UltragoalGuardDiagnostic>;
|
|
32
|
+
export declare function verifyUltragoalDurableCompletionState(input: {
|
|
33
|
+
cwd: string;
|
|
34
|
+
sessionId?: string | null;
|
|
35
|
+
}): Promise<UltragoalGuardDiagnostic>;
|
|
32
36
|
export declare function isUltragoalAskBlocked(cwd: string, options?: {
|
|
33
37
|
sessionId?: string | null;
|
|
34
38
|
}): Promise<UltragoalAskBlockDiagnostic>;
|
|
@@ -36,7 +36,6 @@ export interface UltragoalCompletionVerification {
|
|
|
36
36
|
gjcGoalMode: UltragoalGjcGoalMode;
|
|
37
37
|
gjcObjective: string;
|
|
38
38
|
qualityGateHash: string;
|
|
39
|
-
gjcGoalSnapshotHash: string;
|
|
40
39
|
planGeneration: string;
|
|
41
40
|
basis: {
|
|
42
41
|
planHashBeforeCheckpoint: string;
|
|
@@ -237,7 +236,6 @@ export declare function checkpointUltragoalGoal(input: {
|
|
|
237
236
|
goalId: string;
|
|
238
237
|
status: UltragoalGoalStatus;
|
|
239
238
|
evidence: string;
|
|
240
|
-
gjcGoalJson?: string;
|
|
241
239
|
qualityGateJson?: string;
|
|
242
240
|
}): Promise<UltragoalPlan>;
|
|
243
241
|
export interface UltragoalCheckpointContinuation {
|
|
@@ -253,7 +251,6 @@ export declare function checkpointAndContinueUltragoalGoal(input: {
|
|
|
253
251
|
goalId: string;
|
|
254
252
|
status: UltragoalGoalStatus;
|
|
255
253
|
evidence: string;
|
|
256
|
-
gjcGoalJson?: string;
|
|
257
254
|
qualityGateJson?: string;
|
|
258
255
|
advanceNext?: boolean;
|
|
259
256
|
retryFailed?: boolean;
|
|
@@ -271,7 +268,6 @@ export declare function recordUltragoalReviewBlockers(input: {
|
|
|
271
268
|
title: string;
|
|
272
269
|
objective: string;
|
|
273
270
|
evidence: string;
|
|
274
|
-
gjcGoalJson?: string;
|
|
275
271
|
}): Promise<UltragoalPlan>;
|
|
276
272
|
export type UltragoalBlockerClassification = "human_blocked" | "resolvable";
|
|
277
273
|
/**
|
|
@@ -33,6 +33,11 @@ export interface HookSelectorOptions {
|
|
|
33
33
|
optionLabel: string;
|
|
34
34
|
onSubmit: (text: string) => void;
|
|
35
35
|
};
|
|
36
|
+
clarificationInput?: {
|
|
37
|
+
optionLabel: string;
|
|
38
|
+
onSubmit: (text: string) => void;
|
|
39
|
+
allowEmpty?: boolean;
|
|
40
|
+
};
|
|
36
41
|
/**
|
|
37
42
|
* Autocomplete provider for the inline custom-input editor. When present,
|
|
38
43
|
* the "Other (type your own)" editor gains the same `@` file-link and `/`
|
|
@@ -50,6 +50,7 @@ export interface AskGateResult {
|
|
|
50
50
|
multi: boolean;
|
|
51
51
|
selectedOptions: string[];
|
|
52
52
|
customInput?: string;
|
|
53
|
+
clarificationQuestion?: string;
|
|
53
54
|
}
|
|
54
55
|
/**
|
|
55
56
|
* The answer shape an agent returns for a deep-interview question gate.
|
|
@@ -57,15 +58,28 @@ export interface AskGateResult {
|
|
|
57
58
|
* `selected` are picked option labels; free text is conveyed by `other: true`
|
|
58
59
|
* plus `custom`, encoded separately from `selected` so a real option whose label
|
|
59
60
|
* happens to equal the display sentinel can never collide with the free-text path.
|
|
61
|
+
*
|
|
62
|
+
* `action: "clarify"` is a non-answer. It lets a Deep Interview user ask about
|
|
63
|
+
* the presented choices without advancing the round, scoring ambiguity, or
|
|
64
|
+
* recording selection state.
|
|
60
65
|
*/
|
|
61
|
-
export
|
|
66
|
+
export type DeepInterviewGateAnswer = {
|
|
62
67
|
selected: string[];
|
|
63
|
-
other?:
|
|
64
|
-
custom?:
|
|
65
|
-
|
|
68
|
+
other?: false;
|
|
69
|
+
custom?: undefined;
|
|
70
|
+
action?: "answer";
|
|
71
|
+
} | {
|
|
72
|
+
selected: string[];
|
|
73
|
+
other: true;
|
|
74
|
+
custom: string;
|
|
75
|
+
action?: "answer";
|
|
76
|
+
} | {
|
|
77
|
+
action: "clarify";
|
|
78
|
+
question: string;
|
|
79
|
+
};
|
|
66
80
|
export declare class DeepInterviewGateError extends Error {
|
|
67
|
-
readonly code: "invalid_answer_shape" | "unknown_option" | "multi_not_allowed" | "missing_custom" | "empty_selection" | "duplicate_selection";
|
|
68
|
-
constructor(code: "invalid_answer_shape" | "unknown_option" | "multi_not_allowed" | "missing_custom" | "empty_selection" | "duplicate_selection", message: string);
|
|
81
|
+
readonly code: "invalid_answer_shape" | "unknown_option" | "multi_not_allowed" | "missing_custom" | "missing_clarification" | "empty_selection" | "duplicate_selection";
|
|
82
|
+
constructor(code: "invalid_answer_shape" | "unknown_option" | "multi_not_allowed" | "missing_custom" | "missing_clarification" | "empty_selection" | "duplicate_selection", message: string);
|
|
69
83
|
}
|
|
70
84
|
/** Build the `workflow_gate` open-input for one ask question. */
|
|
71
85
|
export declare function questionToGate(question: AskGateQuestion): OpenGateInput;
|
|
@@ -38,6 +38,8 @@ export declare function markdownToTelegramHtml(markdown: string): string;
|
|
|
38
38
|
* `marker`. The final string is guaranteed to be <= `max`.
|
|
39
39
|
*/
|
|
40
40
|
export declare function truncateTelegramHtml(message: string, max?: number, marker?: string): string;
|
|
41
|
+
/** Split a finished Telegram HTML message into ordered chunks without splitting tags or entities. */
|
|
42
|
+
export declare function splitTelegramHtml(message: string, max?: number): string[];
|
|
41
43
|
/** Finalize an optional message: undefined passthrough, else safe-truncate. */
|
|
42
44
|
export declare function finalizeTelegramHtml(message?: string): string | undefined;
|
|
43
45
|
/**
|
|
@@ -14,6 +14,8 @@ export interface RecentSessionEntry {
|
|
|
14
14
|
mtimeMs: number;
|
|
15
15
|
/** True when a terminal breadcrumb points at this session file. */
|
|
16
16
|
currentTerminal?: boolean;
|
|
17
|
+
/** True when this history is an internal helper/sub-agent session. */
|
|
18
|
+
internal?: boolean;
|
|
17
19
|
}
|
|
18
20
|
export interface RecentActivityDeps {
|
|
19
21
|
/** Root holding `<encoded-cwd>/<sessionId>.jsonl` history files. */
|
|
@@ -22,8 +24,10 @@ export interface RecentActivityDeps {
|
|
|
22
24
|
breadcrumbPaths?: string[];
|
|
23
25
|
/** Max entries to return (default 20). */
|
|
24
26
|
limit?: number;
|
|
27
|
+
/** Include internal helper/sub-agent sessions (default true). */
|
|
28
|
+
includeInternal?: boolean;
|
|
25
29
|
/** Injection seam for tests. */
|
|
26
|
-
|
|
30
|
+
readInitialLines?: (file: string, maxLines: number) => string[];
|
|
27
31
|
}
|
|
28
32
|
/**
|
|
29
33
|
* List recent sessions ranked by history-file mtime (newest first).
|
|
@@ -29,6 +29,14 @@ export interface TelegramDaemonControlDeps {
|
|
|
29
29
|
sendSignal?: (pid: number, signal: NodeJS.Signals) => void;
|
|
30
30
|
spawn?: TelegramDaemonDeps["spawn"];
|
|
31
31
|
execPath?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Stable process id encoded into freshly-spawned daemon owner ids.
|
|
34
|
+
*
|
|
35
|
+
* The daemon-internal entrypoint rejects numeric owner ids whose process is
|
|
36
|
+
* already gone. `gjc daemon reload` is a short-lived CLI process, so using its
|
|
37
|
+
* own pid can race the child startup and make the replacement exit immediately.
|
|
38
|
+
*/
|
|
39
|
+
ownerPid?: number;
|
|
32
40
|
randomId?: () => string;
|
|
33
41
|
sleep?: (ms: number) => Promise<void>;
|
|
34
42
|
waitStepMs?: number;
|
|
@@ -23,6 +23,7 @@ export interface RenderedMessage {
|
|
|
23
23
|
text: string;
|
|
24
24
|
inline_keyboard?: InlineButton[][];
|
|
25
25
|
}
|
|
26
|
+
type TelegramSend = (method: string, body: unknown) => Promise<Response>;
|
|
26
27
|
/** Encode `actionId` + option `index` into Telegram callback_data (<=64 bytes). */
|
|
27
28
|
export declare function encodeCallbackData(actionId: string, index: number): string;
|
|
28
29
|
/** Decode callback_data produced by {@link encodeCallbackData}. */
|
|
@@ -58,6 +59,8 @@ export declare function buildActionMessage(action: {
|
|
|
58
59
|
options?: string[];
|
|
59
60
|
summary?: string;
|
|
60
61
|
}): RenderedMessage;
|
|
62
|
+
/** Send Telegram HTML text chunks sequentially so long messages preserve order. */
|
|
63
|
+
export declare function sendTelegramHtmlChunks(send: TelegramSend, chatId: string, text: string, inlineKeyboard?: InlineButton[][]): Promise<void>;
|
|
61
64
|
/** A protocol `reply` frame the client should send to the server. */
|
|
62
65
|
export interface ReplyFrame {
|
|
63
66
|
type: "reply";
|
|
@@ -111,3 +114,4 @@ export interface TelegramReferenceOptions {
|
|
|
111
114
|
* production clients add reconnection, multi-chat routing, and persistence.
|
|
112
115
|
*/
|
|
113
116
|
export declare function runTelegramReferenceClient(opts: TelegramReferenceOptions): Promise<void>;
|
|
117
|
+
export {};
|
|
@@ -59,6 +59,7 @@ export interface QuestionResult {
|
|
|
59
59
|
multi: boolean;
|
|
60
60
|
selectedOptions: string[];
|
|
61
61
|
customInput?: string;
|
|
62
|
+
clarificationQuestion?: string;
|
|
62
63
|
}
|
|
63
64
|
export interface AskToolDetails {
|
|
64
65
|
question?: string;
|
|
@@ -66,6 +67,7 @@ export interface AskToolDetails {
|
|
|
66
67
|
multi?: boolean;
|
|
67
68
|
selectedOptions?: string[];
|
|
68
69
|
customInput?: string;
|
|
70
|
+
clarificationQuestion?: string;
|
|
69
71
|
/** Multi-part question mode */
|
|
70
72
|
results?: QuestionResult[];
|
|
71
73
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface CmuxWorkspaceRenameCommand {
|
|
2
|
+
command: string;
|
|
3
|
+
args: string[];
|
|
4
|
+
}
|
|
5
|
+
export interface CmuxWorkspaceRenameProcess {
|
|
6
|
+
exited: Promise<number>;
|
|
7
|
+
kill(): void;
|
|
8
|
+
unref(): void;
|
|
9
|
+
}
|
|
10
|
+
export interface CmuxWorkspaceTitleSyncOptions {
|
|
11
|
+
env?: NodeJS.ProcessEnv;
|
|
12
|
+
isTty?: boolean;
|
|
13
|
+
which?: (command: string) => string | null;
|
|
14
|
+
spawn?: (command: string[], options: {
|
|
15
|
+
env: NodeJS.ProcessEnv;
|
|
16
|
+
stdin: "ignore";
|
|
17
|
+
stdout: "ignore";
|
|
18
|
+
stderr: "ignore";
|
|
19
|
+
}) => CmuxWorkspaceRenameProcess;
|
|
20
|
+
}
|
|
21
|
+
export declare function sanitizeCmuxWorkspaceTitle(title: string | undefined): string | undefined;
|
|
22
|
+
export declare function buildCmuxWorkspaceRenameCommand(sessionName: string | undefined, env?: NodeJS.ProcessEnv): CmuxWorkspaceRenameCommand | null;
|
|
23
|
+
export declare function syncCmuxWorkspaceTitle(sessionName: string | undefined, options?: CmuxWorkspaceTitleSyncOptions): void;
|
|
@@ -110,7 +110,7 @@ export declare class WebSearchTool implements AgentTool<typeof webSearchSchema,
|
|
|
110
110
|
/** Web search tool as CustomTool (for TUI rendering support) */
|
|
111
111
|
export declare const webSearchCustomTool: CustomTool<typeof webSearchSchema, SearchRenderDetails>;
|
|
112
112
|
export declare function getSearchTools(): CustomTool<any, any>[];
|
|
113
|
-
export { getSearchProvider, setPreferredSearchProvider, setSearchFallbackProviders } from "./provider";
|
|
113
|
+
export { getConfiguredSearchProviderPreference, getSearchProvider, setPreferredSearchProvider, setSearchFallbackProviders, } from "./provider";
|
|
114
114
|
export { setSearchHardTimeoutMs } from "./providers/utils";
|
|
115
115
|
export type { SearchProviderId as SearchProvider, SearchResponse } from "./types";
|
|
116
116
|
export { isConfigurableSearchProviderId, isSearchProviderPreference } from "./types";
|
|
@@ -8,6 +8,11 @@ export declare function getSearchProvider(id: SearchProviderId): Promise<SearchP
|
|
|
8
8
|
export declare const SEARCH_PROVIDER_ORDER: SearchProviderId[];
|
|
9
9
|
export declare function setPreferredSearchProvider(provider: SearchProviderId | "auto"): void;
|
|
10
10
|
export declare function setSearchFallbackProviders(ids: readonly string[]): void;
|
|
11
|
+
export interface SearchProviderPreferenceSource {
|
|
12
|
+
get(path: "providers.webSearch" | "web_search.provider"): SearchProviderId | "auto";
|
|
13
|
+
has(path: "providers.webSearch" | "web_search.provider"): boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function getConfiguredSearchProviderPreference(settings: SearchProviderPreferenceSource): SearchProviderId | "auto";
|
|
11
16
|
export interface ResolveProviderChainOptions {
|
|
12
17
|
authStorage: AuthStorage;
|
|
13
18
|
sessionId?: string;
|
|
@@ -10,6 +10,7 @@ import type { SearchResponse } from "./types";
|
|
|
10
10
|
export interface SearchRenderDetails {
|
|
11
11
|
response: SearchResponse;
|
|
12
12
|
error?: string;
|
|
13
|
+
warning?: string;
|
|
13
14
|
}
|
|
14
15
|
/** Render web search result with tree-based layout */
|
|
15
16
|
export declare function renderSearchResult(result: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@gajae-code/coding-agent",
|
|
4
|
-
"version": "0.7.
|
|
4
|
+
"version": "0.7.10",
|
|
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",
|
|
@@ -52,12 +52,12 @@
|
|
|
52
52
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
53
53
|
"@babel/parser": "^7.29.3",
|
|
54
54
|
"@mozilla/readability": "^0.6.0",
|
|
55
|
-
"@gajae-code/stats": "0.7.
|
|
56
|
-
"@gajae-code/agent-core": "0.7.
|
|
57
|
-
"@gajae-code/ai": "0.7.
|
|
58
|
-
"@gajae-code/natives": "0.7.
|
|
59
|
-
"@gajae-code/tui": "0.7.
|
|
60
|
-
"@gajae-code/utils": "0.7.
|
|
55
|
+
"@gajae-code/stats": "0.7.10",
|
|
56
|
+
"@gajae-code/agent-core": "0.7.10",
|
|
57
|
+
"@gajae-code/ai": "0.7.10",
|
|
58
|
+
"@gajae-code/natives": "0.7.10",
|
|
59
|
+
"@gajae-code/tui": "0.7.10",
|
|
60
|
+
"@gajae-code/utils": "0.7.10",
|
|
61
61
|
"@puppeteer/browsers": "^2.13.0",
|
|
62
62
|
"@types/turndown": "5.0.6",
|
|
63
63
|
"@xterm/headless": "^6.0.0",
|
|
@@ -9,6 +9,7 @@ import chalk from "chalk";
|
|
|
9
9
|
import { Settings } from "../config/settings";
|
|
10
10
|
import { initTheme, theme } from "../modes/theme/theme";
|
|
11
11
|
import {
|
|
12
|
+
getConfiguredSearchProviderPreference,
|
|
12
13
|
isConfigurableSearchProviderId,
|
|
13
14
|
isSearchProviderPreference,
|
|
14
15
|
runSearchQuery,
|
|
@@ -170,8 +171,8 @@ export async function runSearchCommand(cmd: SearchCommandArgs): Promise<void> {
|
|
|
170
171
|
|
|
171
172
|
await initTheme();
|
|
172
173
|
const settings = await Settings.init();
|
|
173
|
-
const configuredProvider = settings
|
|
174
|
-
if (
|
|
174
|
+
const configuredProvider = getConfiguredSearchProviderPreference(settings);
|
|
175
|
+
if (isSearchProviderPreference(configuredProvider)) {
|
|
175
176
|
setPreferredSearchProvider(configuredProvider);
|
|
176
177
|
}
|
|
177
178
|
const configuredFallback = settings.get("web_search.fallback");
|
|
@@ -455,7 +455,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
455
455
|
// Status line
|
|
456
456
|
"statusLine.preset": {
|
|
457
457
|
type: "enum",
|
|
458
|
-
values: ["default", "minimal", "compact", "full", "nerd", "ascii", "custom"] as const,
|
|
458
|
+
values: ["default", "default-usage", "minimal", "compact", "full", "nerd", "ascii", "custom"] as const,
|
|
459
459
|
default: "default",
|
|
460
460
|
ui: {
|
|
461
461
|
tab: "appearance",
|
|
@@ -463,6 +463,11 @@ export const SETTINGS_SCHEMA = {
|
|
|
463
463
|
description: "Pre-built status line configurations",
|
|
464
464
|
options: [
|
|
465
465
|
{ value: "default", label: "Default", description: "Model, path, git, context, tokens, cost" },
|
|
466
|
+
{
|
|
467
|
+
value: "default-usage",
|
|
468
|
+
label: "Default + Usage",
|
|
469
|
+
description: "Default layout with provider usage quota",
|
|
470
|
+
},
|
|
466
471
|
{ value: "minimal", label: "Minimal", description: "Path and git only" },
|
|
467
472
|
{ value: "compact", label: "Compact", description: "Model, git, cost, context" },
|
|
468
473
|
{ value: "full", label: "Full", description: "All segments including time" },
|
|
@@ -2205,6 +2210,11 @@ export const SETTINGS_SCHEMA = {
|
|
|
2205
2210
|
ui: { tab: "tools", label: "Web Search", description: "Enable the web_search tool for web searching" },
|
|
2206
2211
|
},
|
|
2207
2212
|
|
|
2213
|
+
"web_search.provider": {
|
|
2214
|
+
type: "enum",
|
|
2215
|
+
values: ["auto", ...CONFIGURABLE_SEARCH_PROVIDER_IDS] as const,
|
|
2216
|
+
default: "auto",
|
|
2217
|
+
},
|
|
2208
2218
|
"web_search.fallback": {
|
|
2209
2219
|
type: "array",
|
|
2210
2220
|
default: EMPTY_STRING_ARRAY,
|
|
@@ -1275,7 +1275,7 @@ async function sendTmuxPromptKeys(
|
|
|
1275
1275
|
): Promise<boolean> {
|
|
1276
1276
|
const typed = await runner(["tmux", "send-keys", "-t", target, "-l", prompt]);
|
|
1277
1277
|
if (typed.exitCode !== 0) return false;
|
|
1278
|
-
const submitted = await runner(["tmux", "send-keys", "-t", target, "-
|
|
1278
|
+
const submitted = await runner(["tmux", "send-keys", "-t", target, "C-m"]);
|
|
1279
1279
|
return submitted.exitCode === 0;
|
|
1280
1280
|
}
|
|
1281
1281
|
|
|
@@ -21,13 +21,14 @@ Deep Interview implements Ouroboros-inspired Socratic questioning with mathemati
|
|
|
21
21
|
- User wants to avoid "that's not what I meant" outcomes from autonomous execution
|
|
22
22
|
- Task is complex enough that jumping to code would waste cycles on scope discovery
|
|
23
23
|
- User wants mathematically-validated clarity before committing to execution
|
|
24
|
+
- User explicitly requests deep-interview even after being told the request is already clear, bounded, and low-risk
|
|
24
25
|
</Use_When>
|
|
25
26
|
|
|
26
27
|
<Do_Not_Use_When>
|
|
27
28
|
- User has a detailed, specific request with file paths, function names, or acceptance criteria -- execute directly
|
|
28
29
|
- User wants to explore options or brainstorm -- use `ralplan` skill instead
|
|
29
|
-
- User wants a quick fix or single change --
|
|
30
|
-
- User says "just do it" or "skip the questions" without an explicit execution path -- respect their intent by
|
|
30
|
+
- User wants a quick fix or single change -- use direct execution, not deep-interview or role-agent delegation
|
|
31
|
+
- User says "just do it" or "skip the questions" without an explicit execution path -- respect their intent by exiting deep-interview, not by writing a `pending approval` spec
|
|
31
32
|
- User already has a PRD or plan file and explicitly asks to execute it -- use the requested execution skill with that plan
|
|
32
33
|
</Do_Not_Use_When>
|
|
33
34
|
|
|
@@ -111,6 +112,27 @@ Deep Interview threshold: <resolvedThresholdPercent> (source: <resolvedThreshold
|
|
|
111
112
|
- Include both threshold and source in the final spec metadata.
|
|
112
113
|
- Read any `language` object from active deep-interview state and carry `language.instruction` forward mechanically. If absent, default to English unless `{{ARGUMENTS}}` makes another user/session language obvious or the user explicitly requests another language. Do not add language-specific special cases.
|
|
113
114
|
|
|
115
|
+
## Phase 0.5: Suitability Gate
|
|
116
|
+
|
|
117
|
+
Run this gate after the Phase 0 threshold marker and before Phase 1, brownfield exploration, `gjc state write`, Round 0, ambiguity scoring, or spec writing.
|
|
118
|
+
|
|
119
|
+
If `{{ARGUMENTS}}` is already clear, bounded, low-risk, and asks for a quick fix, single change, known file/symbol edit, explicit command, or direct answer:
|
|
120
|
+
|
|
121
|
+
1. **Stop deep-interview immediately**:
|
|
122
|
+
- First inspect current-session state with `gjc state read --mode deep-interview --json` (include `--session-id <current-session-id>` when available).
|
|
123
|
+
- Clear through `gjc state clear --force --mode deep-interview --json` only when the state is a newly seeded empty interview: no recorded `rounds`, no `spec_path`, no `handoff_from`, no final/pending spec, and no user-confirmed topology.
|
|
124
|
+
- If state already contains rounds, a spec path, handoff metadata, pending approval, or confirmed topology, do not clear it. Preserve the active interview and ask the user whether to continue, cancel, or explicitly clear the workflow.
|
|
125
|
+
- Do not initialize deep-interview state.
|
|
126
|
+
- Do not run Round 0.
|
|
127
|
+
- Do not write a pending-approval spec.
|
|
128
|
+
- Do not hand off to `ralplan`, `ultragoal`, `team`, or a role agent.
|
|
129
|
+
2. **Return the request to direct implementation**:
|
|
130
|
+
- Say briefly that deep-interview is unnecessary because the request is already clear and small.
|
|
131
|
+
- State the direct implementation path the normal coding agent should take.
|
|
132
|
+
- If the user explicitly insists on deep-interview anyway, continue to Phase 1.
|
|
133
|
+
|
|
134
|
+
This gate exists to prevent deep-interview from making easy problems harder. A small verification need does not make a request interview-worthy.
|
|
135
|
+
|
|
114
136
|
## Phase 1: Initialize
|
|
115
137
|
|
|
116
138
|
1. **Parse the user's idea** from `{{ARGUMENTS}}`
|
|
@@ -314,6 +336,8 @@ After applying `language.instruction` to the visible question, options, and gene
|
|
|
314
336
|
|
|
315
337
|
When calling `ask`, SHOULD include optional structured metadata so the runtime can record the round without manual state writes: `deepInterview.round_id?`, `deepInterview.round`, `deepInterview.component`, `deepInterview.dimension`, and `deepInterview.ambiguity`. Keep this metadata aligned with the visible Round/Component/Targeting/Ambiguity line; if metadata cannot be supplied, the legacy formatted question text remains the fallback.
|
|
316
338
|
|
|
339
|
+
If the `ask` tool returns `clarificationQuestion`, treat it as a non-answer about the displayed choices. Answer the clarification briefly from the current interview context, then call `ask` again with the exact original question, options, and `deepInterview.*` metadata. A clarification bypasses Step 2b′ auto-answer, Step 2b″ free-text refine, Step 2c ambiguity scoring, Step 2d progress reporting, and Step 2e state updates; it must not be recorded as a round answer. This does not violate the one-question-per-round rule because the round remains unresolved until the user submits a real listed option or `Other` answer.
|
|
340
|
+
|
|
317
341
|
### Step 2b′: Auto-Answer Opted-Out Questions
|
|
318
342
|
|
|
319
343
|
After the `ask` tool resolves and before ambiguity scoring, if the user opts out of answering the current question or explicitly asks the agent to decide, load `auto-answer-uncertain.md` as an internal `kind: "skill-fragment"` prompt for a fork-context architect. Pass the opted-out question, prompt-safe transcript summary, locked topology, current scores/gaps, and any auto-research candidates used for the round. The architect must return exactly one decisive answer with rationale, confidence, and explicit uncertainty. Validate the response shape before using it; if valid, record it as the tentative answer for scoring, append the round number to `auto_answered_rounds`, and mark the transcript answer as architect-assisted.
|