@gajae-code/coding-agent 0.7.10 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +2 -2
  3. package/dist/types/capability/mcp.d.ts +2 -0
  4. package/dist/types/config/keybindings.d.ts +11 -5
  5. package/dist/types/config/settings-schema.d.ts +25 -2
  6. package/dist/types/defaults/gjc-defaults.d.ts +7 -0
  7. package/dist/types/discovery/cursor.d.ts +4 -1
  8. package/dist/types/discovery/index.d.ts +0 -1
  9. package/dist/types/discovery/windsurf.d.ts +3 -1
  10. package/dist/types/gjc-runtime/launch-tmux.d.ts +3 -0
  11. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +3 -2
  12. package/dist/types/gjc-runtime/restricted-role-agent-bash.d.ts +1 -0
  13. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +5 -0
  14. package/dist/types/gjc-runtime/state-writer.d.ts +1 -0
  15. package/dist/types/modes/components/custom-editor.d.ts +6 -1
  16. package/dist/types/modes/components/settings-selector.d.ts +1 -0
  17. package/dist/types/modes/components/skill-message.d.ts +1 -0
  18. package/dist/types/modes/components/status-line.d.ts +8 -0
  19. package/dist/types/modes/components/two-column-body.d.ts +9 -0
  20. package/dist/types/modes/components/welcome.d.ts +9 -1
  21. package/dist/types/modes/controllers/command-controller.d.ts +1 -0
  22. package/dist/types/modes/controllers/input-controller.d.ts +5 -1
  23. package/dist/types/modes/controllers/selector-controller.d.ts +8 -0
  24. package/dist/types/modes/interactive-mode.d.ts +2 -0
  25. package/dist/types/modes/prompt-action-autocomplete.d.ts +2 -0
  26. package/dist/types/modes/rpc/rpc-types.d.ts +1 -0
  27. package/dist/types/modes/slash-command-visibility.d.ts +1 -0
  28. package/dist/types/modes/types.d.ts +2 -0
  29. package/dist/types/runtime-mcp/config-writer.d.ts +9 -0
  30. package/dist/types/runtime-mcp/config.d.ts +2 -0
  31. package/dist/types/runtime-mcp/loader.d.ts +2 -0
  32. package/dist/types/runtime-mcp/manager.d.ts +2 -0
  33. package/dist/types/runtime-mcp/types.d.ts +6 -0
  34. package/dist/types/sdk.d.ts +1 -1
  35. package/dist/types/session/agent-session.d.ts +8 -5
  36. package/dist/types/slash-commands/types.d.ts +2 -0
  37. package/dist/types/system-prompt.d.ts +7 -0
  38. package/dist/types/utils/cmux-workspace.d.ts +30 -1
  39. package/dist/types/web/search/index.d.ts +3 -1
  40. package/dist/types/web/search/provider.d.ts +9 -0
  41. package/dist/types/web/search/providers/utils.d.ts +42 -13
  42. package/dist/types/workflow/workflow-intent-diff.d.ts +19 -0
  43. package/package.json +10 -10
  44. package/src/capability/mcp.ts +2 -0
  45. package/src/cli/update-cli.ts +24 -0
  46. package/src/cli/web-search-cli.ts +2 -5
  47. package/src/cli.ts +1 -1
  48. package/src/commands/launch.ts +1 -1
  49. package/src/commands/ralplan.ts +1 -0
  50. package/src/config/keybindings.ts +14 -5
  51. package/src/config/mcp-schema.json +5 -1
  52. package/src/config/model-profiles.ts +16 -0
  53. package/src/config/settings-schema.ts +18 -2
  54. package/src/coordinator-mcp/server.ts +15 -3
  55. package/src/defaults/gjc/skills/ralplan/SKILL.md +16 -14
  56. package/src/defaults/gjc-defaults.ts +16 -0
  57. package/src/discovery/builtin.ts +12 -0
  58. package/src/discovery/cursor.ts +5 -84
  59. package/src/discovery/gemini.ts +3 -89
  60. package/src/discovery/index.ts +4 -1
  61. package/src/discovery/mcp-json.ts +11 -0
  62. package/src/discovery/opencode.ts +5 -122
  63. package/src/discovery/windsurf.ts +4 -82
  64. package/src/edit/read-file.ts +9 -1
  65. package/src/extensibility/extensions/runner.ts +2 -1
  66. package/src/gjc-runtime/launch-tmux.ts +164 -42
  67. package/src/gjc-runtime/ralplan-runtime.ts +22 -6
  68. package/src/gjc-runtime/restricted-role-agent-bash.ts +1 -0
  69. package/src/gjc-runtime/session-state-sidecar.ts +167 -24
  70. package/src/gjc-runtime/state-runtime.ts +8 -5
  71. package/src/gjc-runtime/state-writer.ts +5 -5
  72. package/src/gjc-runtime/team-runtime.ts +56 -51
  73. package/src/internal-urls/docs-index.generated.ts +8 -7
  74. package/src/main.ts +2 -2
  75. package/src/migrate/executor.ts +23 -6
  76. package/src/modes/components/agent-dashboard.ts +1 -34
  77. package/src/modes/components/custom-editor.ts +26 -0
  78. package/src/modes/components/extensions/extension-dashboard.ts +2 -48
  79. package/src/modes/components/model-selector.ts +64 -4
  80. package/src/modes/components/session-selector.ts +19 -9
  81. package/src/modes/components/settings-selector.ts +13 -2
  82. package/src/modes/components/skill-message.ts +18 -10
  83. package/src/modes/components/status-line.ts +215 -86
  84. package/src/modes/components/tree-selector.ts +28 -8
  85. package/src/modes/components/two-column-body.ts +36 -0
  86. package/src/modes/components/welcome.ts +171 -35
  87. package/src/modes/controllers/command-controller.ts +23 -0
  88. package/src/modes/controllers/event-controller.ts +4 -0
  89. package/src/modes/controllers/input-controller.ts +192 -39
  90. package/src/modes/controllers/selector-controller.ts +25 -28
  91. package/src/modes/interactive-mode.ts +36 -30
  92. package/src/modes/prompt-action-autocomplete.ts +23 -1
  93. package/src/modes/rpc/rpc-types.ts +1 -0
  94. package/src/modes/shared/agent-wire/deep-interview-gate.ts +9 -3
  95. package/src/modes/shared/agent-wire/workflow-gate-schema.ts +20 -0
  96. package/src/modes/slash-command-visibility.ts +9 -0
  97. package/src/modes/types.ts +2 -0
  98. package/src/modes/utils/hotkeys-markdown.ts +5 -2
  99. package/src/modes/utils/ui-helpers.ts +76 -3
  100. package/src/notifications/index.ts +20 -1
  101. package/src/notifications/lifecycle-control-runtime.ts +12 -3
  102. package/src/notifications/telegram-daemon.ts +4 -4
  103. package/src/prompts/agents/architect.md +7 -4
  104. package/src/prompts/agents/critic.md +15 -6
  105. package/src/prompts/agents/planner.md +8 -3
  106. package/src/prompts/system/system-prompt.md +15 -1
  107. package/src/prompts/tools/bash.md +1 -1
  108. package/src/runtime-mcp/config-writer.ts +28 -0
  109. package/src/runtime-mcp/config.ts +7 -0
  110. package/src/runtime-mcp/loader.ts +3 -0
  111. package/src/runtime-mcp/manager.ts +3 -0
  112. package/src/runtime-mcp/types.ts +6 -0
  113. package/src/sdk.ts +7 -6
  114. package/src/session/agent-session.ts +81 -18
  115. package/src/session/session-manager.ts +58 -18
  116. package/src/slash-commands/builtin-registry.ts +30 -10
  117. package/src/slash-commands/types.ts +2 -0
  118. package/src/system-prompt.ts +8 -0
  119. package/src/task/executor.ts +5 -0
  120. package/src/tools/ast-grep.ts +10 -7
  121. package/src/tools/bash.ts +39 -14
  122. package/src/tools/index.ts +8 -1
  123. package/src/utils/cmux-workspace.ts +134 -7
  124. package/src/utils/title-generator.ts +1 -1
  125. package/src/web/kagi.ts +1 -1
  126. package/src/web/parallel.ts +2 -2
  127. package/src/web/search/index.ts +118 -45
  128. package/src/web/search/provider.ts +65 -0
  129. package/src/web/search/providers/anthropic.ts +1 -1
  130. package/src/web/search/providers/brave.ts +1 -1
  131. package/src/web/search/providers/codex.ts +1 -1
  132. package/src/web/search/providers/duckduckgo.ts +1 -1
  133. package/src/web/search/providers/exa.ts +1 -1
  134. package/src/web/search/providers/gemini.ts +7 -3
  135. package/src/web/search/providers/jina.ts +1 -1
  136. package/src/web/search/providers/kimi.ts +6 -1
  137. package/src/web/search/providers/openai-compatible.ts +1 -1
  138. package/src/web/search/providers/parallel.ts +1 -1
  139. package/src/web/search/providers/perplexity.ts +2 -2
  140. package/src/web/search/providers/searxng.ts +1 -1
  141. package/src/web/search/providers/synthetic.ts +1 -1
  142. package/src/web/search/providers/tavily.ts +1 -1
  143. package/src/web/search/providers/utils.ts +67 -17
  144. package/src/web/search/providers/xai.ts +1 -1
  145. package/src/web/search/providers/zai.ts +1 -1
  146. package/src/workflow/workflow-intent-diff.ts +199 -0
  147. package/dist/types/discovery/vscode.d.ts +0 -1
  148. package/src/discovery/vscode.ts +0 -105
@@ -159,7 +159,7 @@ export interface AgentSessionConfig {
159
159
  agent: Agent;
160
160
  sessionManager: SessionManager;
161
161
  settings: Settings;
162
- /** Models to cycle through with Ctrl+P (from --models flag) */
162
+ /** Models to cycle through with Alt+N (from --models flag) */
163
163
  scopedModels?: ScopedModelSelection[];
164
164
  /** Initial session thinking selector. */
165
165
  thinkingLevel?: ThinkingLevel;
@@ -671,7 +671,7 @@ export declare class AgentSession {
671
671
  followUp: readonly string[];
672
672
  };
673
673
  /**
674
- * Pop the last queued message (steering first, then follow-up).
674
+ * Pop the newest queued message across steering and follow-up queues.
675
675
  * Used by dequeue keybinding to restore messages to editor one at a time.
676
676
  * Returns the popped entry's `.text`; the tag (if any) dies with the
677
677
  * record — no orphan state can outlive the queue entry.
@@ -905,9 +905,12 @@ export declare class AgentSession {
905
905
  */
906
906
  setAutoRetryEnabled(enabled: boolean): void;
907
907
  /**
908
- * Manually retry the last failed assistant turn.
909
- * Removes the error message from agent state and re-attempts with a fresh retry budget.
910
- * @returns true if retry was initiated, false if no failed turn to retry or agent is busy
908
+ * Manually retry the last failed assistant turn, or resume an interrupted tail
909
+ * left by a non-graceful process exit after the user/custom/tool-result message
910
+ * was persisted but before the agent emitted a terminal assistant response.
911
+ * Removes failed/aborted/unresolved tool-use assistant tails before
912
+ * re-attempting with a fresh retry budget.
913
+ * @returns true if retry/resume was initiated, false if no retryable tail exists or agent is busy
911
914
  */
912
915
  retry(): Promise<boolean>;
913
916
  /**
@@ -17,6 +17,8 @@ export interface BuiltinSlashCommand {
17
17
  subcommands?: SubcommandDef[];
18
18
  /** Static inline hint when command takes a simple argument (no subcommands). */
19
19
  inlineHint?: string;
20
+ /** Higher values sort earlier in TUI slash-command autocomplete. */
21
+ priority?: number;
20
22
  }
21
23
  /** Parsed slash-command text after stripping the leading "/". */
22
24
  export interface ParsedSlashCommand {
@@ -76,6 +76,13 @@ export interface BuildSystemPromptOptions {
76
76
  mcpDiscoveryMode?: boolean;
77
77
  /** Discoverable MCP server summaries to advertise when discovery mode is active. */
78
78
  mcpDiscoveryServerSummaries?: string[];
79
+ /** Whether built-in tool discovery ("all" mode) is active; enables the tool-discovery prompt block. */
80
+ toolDiscoveryActive?: boolean;
81
+ /** Hidden discoverable tools to advertise (name + one-line summary) when tool discovery is active. */
82
+ discoverableTools?: Array<{
83
+ name: string;
84
+ summary: string;
85
+ }>;
79
86
  /** Encourage the agent to delegate via tasks unless changes are trivial. */
80
87
  eagerTasks?: boolean;
81
88
  /** Rules with alwaysApply=true — their full content is injected into the prompt. */
@@ -2,6 +2,13 @@ export interface CmuxWorkspaceRenameCommand {
2
2
  command: string;
3
3
  args: string[];
4
4
  }
5
+ /** Current ownership state of a cmux workspace, read back from `cmux workspace list`. */
6
+ export interface CmuxWorkspaceOwnership {
7
+ /** cmux marks a workspace `has_custom_title` once an explicit title is set (by the user or by GJC). */
8
+ hasCustomTitle: boolean;
9
+ /** The workspace's current display title. */
10
+ title: string;
11
+ }
5
12
  export interface CmuxWorkspaceRenameProcess {
6
13
  exited: Promise<number>;
7
14
  kill(): void;
@@ -17,7 +24,29 @@ export interface CmuxWorkspaceTitleSyncOptions {
17
24
  stdout: "ignore";
18
25
  stderr: "ignore";
19
26
  }) => CmuxWorkspaceRenameProcess;
27
+ /** Reads the current ownership state of `workspaceId`. Injectable for tests. */
28
+ readOwnership?: (cmuxCommand: string, workspaceId: string, env: NodeJS.ProcessEnv) => Promise<CmuxWorkspaceOwnership | null>;
20
29
  }
21
30
  export declare function sanitizeCmuxWorkspaceTitle(title: string | undefined): string | undefined;
31
+ export declare function formatCmuxWorkspaceTitle(title: string | undefined): string | undefined;
22
32
  export declare function buildCmuxWorkspaceRenameCommand(sessionName: string | undefined, env?: NodeJS.ProcessEnv): CmuxWorkspaceRenameCommand | null;
23
- export declare function syncCmuxWorkspaceTitle(sessionName: string | undefined, options?: CmuxWorkspaceTitleSyncOptions): void;
33
+ /** Parse `cmux workspace list --json --id-format both` output and return the
34
+ * ownership state of the workspace matching `workspaceId` (by UUID `id` or `ref`). */
35
+ export declare function parseCmuxWorkspaceOwnership(jsonText: string, workspaceId: string): CmuxWorkspaceOwnership | null;
36
+ /** Only rename when GJC owns the name:
37
+ * - unknown ownership (read failed) → skip (fail safe, never clobber)
38
+ * - already the desired title → skip (no-op)
39
+ * - workspace still on its default title → rename
40
+ * - any custom title (user- or peer-set) → skip
41
+ * This makes GJC name a fresh workspace once and then leave it alone, so it
42
+ * never overwrites a user-pinned name and multiple sessions sharing one
43
+ * CMUX_WORKSPACE_ID do not thrash the workspace title. */
44
+ export declare function shouldRenameCmuxWorkspace(ownership: CmuxWorkspaceOwnership | null, desiredTitle: string): boolean;
45
+ /**
46
+ * Best-effort sync of the containing cmux workspace title to the current GJC
47
+ * session name. Ownership-guarded: GJC reads the current workspace title and
48
+ * only renames a workspace that still has its default title, so it never
49
+ * overwrites a name the user pinned or a name a peer session (sharing the same
50
+ * CMUX_WORKSPACE_ID) set. Opt out with GJC_NO_CMUX_RENAME.
51
+ */
52
+ export declare function syncCmuxWorkspaceTitle(sessionName: string | undefined, options?: CmuxWorkspaceTitleSyncOptions): Promise<void>;
@@ -44,6 +44,8 @@ export type SearchToolParams = z.infer<typeof webSearchSchema>;
44
44
  export interface SearchQueryParams extends SearchToolParams {
45
45
  provider?: SearchProviderId | "auto";
46
46
  }
47
+ /** Override the hedge delay (tests). Non-finite/non-positive resets to default. */
48
+ export declare function setDdgHedgeDelayMs(ms: number | undefined): void;
47
49
  /**
48
50
  * Execute a web search query for CLI/testing workflows.
49
51
  *
@@ -111,6 +113,6 @@ export declare class WebSearchTool implements AgentTool<typeof webSearchSchema,
111
113
  export declare const webSearchCustomTool: CustomTool<typeof webSearchSchema, SearchRenderDetails>;
112
114
  export declare function getSearchTools(): CustomTool<any, any>[];
113
115
  export { getConfiguredSearchProviderPreference, getSearchProvider, setPreferredSearchProvider, setSearchFallbackProviders, } from "./provider";
114
- export { setSearchHardTimeoutMs } from "./providers/utils";
116
+ export { applyConfiguredSearchTimeout, setSearchHardTimeoutMs } from "./providers/utils";
115
117
  export type { SearchProviderId as SearchProvider, SearchResponse } from "./types";
116
118
  export { isConfigurableSearchProviderId, isSearchProviderPreference } from "./types";
@@ -6,8 +6,17 @@ export { SearchProvider } from "./providers/base";
6
6
  export declare function getSearchProviderLabel(id: SearchProviderId): string;
7
7
  export declare function getSearchProvider(id: SearchProviderId): Promise<SearchProvider>;
8
8
  export declare const SEARCH_PROVIDER_ORDER: SearchProviderId[];
9
+ /** Drop every cached resolved chain (settings changed, tests). */
10
+ export declare function clearResolvedChainCache(): void;
9
11
  export declare function setPreferredSearchProvider(provider: SearchProviderId | "auto"): void;
10
12
  export declare function setSearchFallbackProviders(ids: readonly string[]): void;
13
+ /**
14
+ * Fire-and-forget warm-up: resolve the provider chain once so the provider
15
+ * modules are imported and the chain cache is primed before the first
16
+ * user-visible search. Errors are intentionally swallowed — prewarming must
17
+ * never surface a failure the real search path would handle itself.
18
+ */
19
+ export declare function prewarmSearchProviders(options: ResolveProviderChainOptions): void;
11
20
  export interface SearchProviderPreferenceSource {
12
21
  get(path: "providers.webSearch" | "web_search.provider"): SearchProviderId | "auto";
13
22
  has(path: "providers.webSearch" | "web_search.provider"): boolean;
@@ -15,27 +15,53 @@ import { SearchProviderError, type SearchProviderId, type SearchSource } from ".
15
15
  */
16
16
  export declare function findCredential(storage: AgentStorage | null | undefined, envKey: string | null | undefined, ...storageProviders: string[]): string | null;
17
17
  /**
18
- * Default hard ceiling for a single web-search round-trip. 300s tolerates
19
- * legitimate slow LLM-mediated responses (anthropic web_search_20250305,
20
- * perplexity, gemini, OpenAI code backend) while still guaranteeing the session unfreezes
21
- * if Bun's `AbortSignal` fails to propagate on Windows.
22
- *
23
- * Pure search APIs (brave, exa, jina, tavily, searxng, synthetic, zai)
24
- * settle far faster in practice; reusing the same ceiling keeps the wiring
25
- * uniform without compromising correctness.
18
+ * Legacy hard ceiling for a single web-search round-trip, retained as the
19
+ * fallback for call sites that do not declare a timeout class. 300s tolerates
20
+ * pathological cases while still guaranteeing the session unfreezes if Bun's
21
+ * `AbortSignal` fails to propagate on Windows.
26
22
  */
27
23
  export declare const SEARCH_HARD_TIMEOUT_MS = 300000;
24
+ /**
25
+ * Hard ceiling for pure search APIs (brave, exa, jina, tavily, kagi,
26
+ * parallel, searxng, synthetic, zai, duckduckgo). These settle in ~1-3s in
27
+ * practice; a hung TCP/TLS connection should fall through to the next
28
+ * provider in seconds, not minutes. Kimi is the exception: it declares an
29
+ * explicit ceiling aligned with its upstream 30s request budget.
30
+ */
31
+ export declare const SEARCH_API_TIMEOUT_MS = 15000;
32
+ /**
33
+ * Hard ceiling for LLM-mediated search providers (anthropic, codex, gemini,
34
+ * perplexity, xai, openai-compatible). These legitimately take tens of
35
+ * seconds because a model performs the search and synthesizes an answer.
36
+ */
37
+ export declare const SEARCH_LLM_TIMEOUT_MS = 120000;
38
+ /** Timeout class a provider declares for its outbound round-trips. */
39
+ export type SearchTimeoutClass = "api" | "llm";
28
40
  /**
29
41
  * Override the hard timeout applied to every web-search round-trip.
30
42
  *
31
43
  * @param ms - Hard timeout in milliseconds. Non-finite or non-positive
32
- * values reset the timeout to {@link SEARCH_HARD_TIMEOUT_MS}.
44
+ * values clear the override so per-class defaults apply.
33
45
  */
34
46
  export declare function setSearchHardTimeoutMs(ms: number | undefined): void;
47
+ /** Structural settings source for {@link applyConfiguredSearchTimeout}. */
48
+ export interface SearchTimeoutSettingSource {
49
+ get(path: "web_search.timeout"): unknown;
50
+ has(path: "web_search.timeout"): boolean;
51
+ }
52
+ /**
53
+ * Install the `web_search.timeout` override from settings — but only when the
54
+ * user explicitly configured it. The settings schema ships a default value
55
+ * (300), and consuming that default via `get()` alone would reinstall a
56
+ * uniform 300s ceiling on every session, silently disabling the per-class
57
+ * timeout defaults. `has()` distinguishes loaded/overridden settings from
58
+ * schema defaults; unset clears any previous override so class defaults apply.
59
+ */
60
+ export declare function applyConfiguredSearchTimeout(settings: SearchTimeoutSettingSource): void;
35
61
  /**
36
62
  * Compose a caller-supplied {@link AbortSignal} with a hard timeout so an
37
- * outbound `fetch()` is guaranteed to settle within `ms` even when the
38
- * runtime fails to propagate cancellation to the underlying transport.
63
+ * outbound `fetch()` is guaranteed to settle even when the runtime fails to
64
+ * propagate cancellation to the underlying transport.
39
65
  *
40
66
  * Bun's WinHTTP backend on Windows is known to ignore `AbortSignal` once a
41
67
  * TCP/TLS connection stalls (oven-sh/bun#15275, oven-sh/bun#18536); without
@@ -43,9 +69,12 @@ export declare function setSearchHardTimeoutMs(ms: number | undefined): void;
43
69
  * because the user's Esc is never delivered to the native layer.
44
70
  *
45
71
  * @param signal - Caller cancellation signal, if any.
46
- * @param ms - Hard timeout in milliseconds. Defaults to the configured value.
72
+ * @param msOrClass - Explicit timeout in milliseconds, or a
73
+ * {@link SearchTimeoutClass} resolved to its class default. Omitted falls
74
+ * back to the legacy {@link SEARCH_HARD_TIMEOUT_MS} ceiling. A user-set
75
+ * `web_search.timeout` overrides class defaults (but not explicit ms).
47
76
  */
48
- export declare function withHardTimeout(signal: AbortSignal | undefined, ms?: number): AbortSignal;
77
+ export declare function withHardTimeout(signal: AbortSignal | undefined, msOrClass?: number | SearchTimeoutClass): AbortSignal;
49
78
  /**
50
79
  * Map a provider's raw source list to the unified SearchSource shape,
51
80
  * clamped to the requested result count and annotated with ageSeconds.
@@ -0,0 +1,19 @@
1
+ export declare const WORKFLOW_INTENT_DIFF_CUSTOM_TYPE = "workflow-intent-diff";
2
+ export type WorkflowIntentRoute = "direct" | "deep-interview" | "ralplan" | "ultragoal" | "team";
3
+ export type DirectTrackingMode = "custom-entry-only" | "not-direct";
4
+ export type RootCausePhaseStatus = "active" | "inactive";
5
+ export interface WorkflowIntentDiff {
6
+ readonly version: 1;
7
+ readonly route: WorkflowIntentRoute;
8
+ readonly reason: string;
9
+ readonly directTracking: DirectTrackingMode;
10
+ readonly recommendedSkill?: Exclude<WorkflowIntentRoute, "direct">;
11
+ readonly recommendedInvocation?: string;
12
+ readonly triggers: readonly string[];
13
+ readonly rootCausePhase: {
14
+ readonly status: RootCausePhaseStatus;
15
+ readonly triggers: readonly string[];
16
+ };
17
+ readonly promptPreview: string;
18
+ }
19
+ export declare function buildWorkflowIntentDiff(text: string): WorkflowIntentDiff | null;
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.7.10",
4
+ "version": "0.8.0",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
- "homepage": "https://gaebal-gajae.dev",
6
+ "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo",
8
8
  "contributors": [
9
9
  "Mario Zechner"
@@ -11,11 +11,11 @@
11
11
  "license": "MIT",
12
12
  "repository": {
13
13
  "type": "git",
14
- "url": "git+https://github.com/gajae-ai/gajae-code.git",
14
+ "url": "git+https://github.com/Yeachan-Heo/gajae-code.git",
15
15
  "directory": "packages/coding-agent"
16
16
  },
17
17
  "bugs": {
18
- "url": "https://github.com/gajae-ai/gajae-code/issues"
18
+ "url": "https://github.com/Yeachan-Heo/gajae-code/issues"
19
19
  },
20
20
  "keywords": [
21
21
  "coding-agent",
@@ -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.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",
55
+ "@gajae-code/stats": "0.8.0",
56
+ "@gajae-code/agent-core": "0.8.0",
57
+ "@gajae-code/ai": "0.8.0",
58
+ "@gajae-code/natives": "0.8.0",
59
+ "@gajae-code/tui": "0.8.0",
60
+ "@gajae-code/utils": "0.8.0",
61
61
  "@puppeteer/browsers": "^2.13.0",
62
62
  "@types/turndown": "5.0.6",
63
63
  "@xterm/headless": "^6.0.0",
@@ -15,6 +15,8 @@ export interface MCPServer {
15
15
  name: string;
16
16
  /** Whether this server is enabled (default: true) */
17
17
  enabled?: boolean;
18
+ /** Whether to connect automatically at session startup (default: true) */
19
+ autoload?: boolean;
18
20
  /** Connection timeout in milliseconds */
19
21
  timeout?: number;
20
22
  /** Command to run (for stdio transport) */
@@ -10,6 +10,7 @@ import { pipeline } from "node:stream/promises";
10
10
  import { $which, APP_NAME, isEnoent, VERSION } from "@gajae-code/utils";
11
11
  import { $ } from "bun";
12
12
  import chalk from "chalk";
13
+ import { installDefaultGjcDefinitions } from "../defaults/gjc-defaults";
13
14
  import { theme } from "../modes/theme/theme";
14
15
 
15
16
  const RELEASE_REPO = "Yeachan-Heo/gajae-code";
@@ -628,6 +629,29 @@ export async function runUpdateCommand(opts: { force: boolean; check: boolean })
628
629
  console.error(chalk.red(`Update failed: ${err}`));
629
630
  process.exit(1);
630
631
  }
632
+
633
+ await refreshInstalledDefaultSkills();
634
+ }
635
+
636
+ /**
637
+ * Refresh opted-in on-disk default workflow skill copies after a successful
638
+ * update. The four default skills ship embedded in the binary, so most users
639
+ * need nothing here. But users who ran `gjc setup defaults` have on-disk copies
640
+ * under the agent dir that shadow the embedded defaults; those would otherwise
641
+ * go stale after an update. Only rewrite files that already exist and differ —
642
+ * never materialize new copies for users who never opted in.
643
+ */
644
+ async function refreshInstalledDefaultSkills(): Promise<void> {
645
+ try {
646
+ const result = await installDefaultGjcDefinitions({ refreshOnly: true });
647
+ if (result.written > 0) {
648
+ console.log(
649
+ chalk.dim(`Refreshed ${result.written} local default workflow skill file(s) at ${result.targetRoot}`),
650
+ );
651
+ }
652
+ } catch (err) {
653
+ console.error(chalk.yellow(`Warning: failed to refresh local default workflow skills: ${err}`));
654
+ }
631
655
  }
632
656
 
633
657
  /**
@@ -16,7 +16,7 @@ import {
16
16
  type SearchQueryParams,
17
17
  } from "../web/search/index";
18
18
  import { SEARCH_PROVIDER_ORDER, setPreferredSearchProvider, setSearchFallbackProviders } from "../web/search/provider";
19
- import { setSearchHardTimeoutMs } from "../web/search/providers/utils";
19
+ import { applyConfiguredSearchTimeout } from "../web/search/providers/utils";
20
20
  import { renderSearchResult } from "../web/search/render";
21
21
  import type { SearchProviderId } from "../web/search/types";
22
22
 
@@ -181,10 +181,7 @@ export async function runSearchCommand(cmd: SearchCommandArgs): Promise<void> {
181
181
  configuredFallback.filter(value => typeof value === "string" && isConfigurableSearchProviderId(value)),
182
182
  );
183
183
  }
184
- const configuredTimeout = settings.get("web_search.timeout");
185
- if (typeof configuredTimeout === "number" && Number.isFinite(configuredTimeout) && configuredTimeout > 0) {
186
- setSearchHardTimeoutMs(configuredTimeout * 1000);
187
- }
184
+ applyConfiguredSearchTimeout(settings);
188
185
 
189
186
  const params: SearchQueryParams = {
190
187
  query: cmd.query,
package/src/cli.ts CHANGED
@@ -141,7 +141,7 @@ class RootHelpCommand extends Command {
141
141
  resume: Flags.string({ char: "r", description: "Resume a session (by ID prefix, path, or picker if omitted)" }),
142
142
  "session-dir": Flags.string({ description: "Directory for session storage and lookup" }),
143
143
  "no-session": Flags.boolean({ description: "Don't save session (ephemeral)" }),
144
- models: Flags.string({ description: "Comma-separated model patterns for Ctrl+P cycling" }),
144
+ models: Flags.string({ description: "Comma-separated model patterns for Alt+N cycling" }),
145
145
  "no-tools": Flags.boolean({ description: "Disable all built-in tools" }),
146
146
  "no-lsp": Flags.boolean({ description: "Disable LSP tools, formatting, and diagnostics" }),
147
147
  "no-pty": Flags.boolean({ description: "Disable PTY-based interactive bash execution" }),
@@ -119,7 +119,7 @@ export default class Index extends Command {
119
119
  description: "Don't save session (ephemeral)",
120
120
  }),
121
121
  models: Flags.string({
122
- description: "Comma-separated model patterns for Ctrl+P cycling",
122
+ description: "Comma-separated model patterns for Alt+N cycling",
123
123
  }),
124
124
  "no-tools": Flags.boolean({
125
125
  description: "Disable all built-in tools",
@@ -8,6 +8,7 @@ export default class Ralplan extends Command {
8
8
  '$ gjc ralplan "<task description>"',
9
9
  '$ gjc ralplan --interactive --deliberate "<task description>"',
10
10
  '$ gjc ralplan --write --stage planner --stage_n 1 --artifact "<markdown or path>"',
11
+ "$ gjc ralplan --write --stage critic --stage_n 1 --artifact-env GJC_RALPLAN_ARTIFACT",
11
12
  ];
12
13
 
13
14
  async run(): Promise<void> {
@@ -22,6 +22,7 @@ interface AppKeybindings {
22
22
  "app.suspend": true;
23
23
  "app.thinking.cycle": true;
24
24
  "app.thinking.toggle": true;
25
+ "app.commandPalette.open": true;
25
26
  "app.model.cycleForward": true;
26
27
  "app.model.cycleBackward": true;
27
28
  "app.model.select": true;
@@ -59,6 +60,10 @@ declare module "@gajae-code/tui" {
59
60
  interface Keybindings extends AppKeybindings {}
60
61
  }
61
62
 
63
+ export function defaultMessageQueueKeysForPlatform(platform: NodeJS.Platform = process.platform): KeyId {
64
+ return platform === "win32" ? "alt+q" : "alt+enter";
65
+ }
66
+
62
67
  /**
63
68
  * All keybindings definitions: TUI + app-specific.
64
69
  */
@@ -88,12 +93,16 @@ export const KEYBINDINGS = {
88
93
  defaultKeys: "ctrl+t",
89
94
  description: "Toggle thinking mode",
90
95
  },
91
- "app.model.cycleForward": {
96
+ "app.commandPalette.open": {
92
97
  defaultKeys: "ctrl+p",
98
+ description: "Open command palette",
99
+ },
100
+ "app.model.cycleForward": {
101
+ defaultKeys: "alt+n",
93
102
  description: "Cycle to next model",
94
103
  },
95
104
  "app.model.cycleBackward": {
96
- defaultKeys: "shift+ctrl+p",
105
+ defaultKeys: "alt+shift+n",
97
106
  description: "Cycle to previous model",
98
107
  },
99
108
  "app.model.select": {
@@ -121,7 +130,7 @@ export const KEYBINDINGS = {
121
130
  description: "Send follow-up message (no default; Ctrl+Enter submits)",
122
131
  },
123
132
  "app.message.queue": {
124
- defaultKeys: "alt+enter",
133
+ defaultKeys: defaultMessageQueueKeysForPlatform(),
125
134
  description: "Queue message for next turn",
126
135
  },
127
136
  "app.message.dequeue": {
@@ -141,8 +150,8 @@ export const KEYBINDINGS = {
141
150
  description: "Copy prompt",
142
151
  },
143
152
  "app.session.new": {
144
- defaultKeys: [],
145
- description: "Create new session",
153
+ defaultKeys: "ctrl+n",
154
+ description: "Start a new session",
146
155
  },
147
156
  "app.session.tree": {
148
157
  defaultKeys: [],
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://raw.githubusercontent.com/can1357/gajae-code/main/packages/coding-agent/src/config/mcp-schema.json",
3
+ "$id": "https://raw.githubusercontent.com/Yeachan-Heo/gajae-code/main/packages/coding-agent/src/config/mcp-schema.json",
4
4
  "title": "GJC MCP configuration",
5
5
  "description": "Schema for mcp.json, .mcp.json, .gjc/mcp.json, and ~/.gjc/agent/mcp.json used by the GJC coding agent.",
6
6
  "type": "object",
@@ -96,6 +96,10 @@
96
96
  "type": "boolean",
97
97
  "description": "Whether GJC should try to connect this server."
98
98
  },
99
+ "autoload": {
100
+ "type": "boolean",
101
+ "description": "Whether to connect this server automatically at session startup (default: true). When false the server stays configured until connected explicitly (e.g. /mcp connect <name>)."
102
+ },
99
103
  "timeout": {
100
104
  "type": "number",
101
105
  "exclusiveMinimum": 0,
@@ -104,6 +104,13 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
104
104
  critic: "anthropic/claude-opus-4-8:high",
105
105
  architect: "anthropic/claude-opus-4-8:xhigh",
106
106
  }),
107
+ profile("claude-fable", ["anthropic"], {
108
+ default: "anthropic/claude-fable-5:xhigh",
109
+ executor: "anthropic/claude-sonnet-5",
110
+ planner: "anthropic/claude-fable-5:low",
111
+ critic: "anthropic/claude-fable-5:high",
112
+ architect: "anthropic/claude-fable-5:xhigh",
113
+ }),
107
114
  profile("glm-eco", ["zai"], {
108
115
  default: "zai/glm-5.2:low",
109
116
  executor: "zai/glm-5.2:minimal",
@@ -261,6 +268,13 @@ export const BUILTIN_MODEL_PROFILES: readonly ModelProfileDefinition[] = [
261
268
  critic: "opencode-go/mimo-v2.5-pro",
262
269
  architect: "openai-codex/gpt-5.5:xhigh",
263
270
  }),
271
+ profile("fable-opus-codex", ["anthropic", "openai-codex"], {
272
+ default: "anthropic/claude-fable-5:high",
273
+ executor: "openai-codex/gpt-5.5:high",
274
+ planner: "anthropic/claude-opus-4-8:medium",
275
+ critic: "anthropic/claude-opus-4-8:high",
276
+ architect: "openai-codex/gpt-5.5:xhigh",
277
+ }),
264
278
  ];
265
279
 
266
280
  export interface ModelProfilePresentation {
@@ -278,6 +292,7 @@ const PROFILE_PRESENTATION: Record<string, ModelProfilePresentation> = {
278
292
  "codex-pro": { displayName: "Codex Pro", providerGroup: "CODEX" },
279
293
  opencodego: { displayName: "OpenCodeGo", providerGroup: "OPENCODEGO" },
280
294
  "claude-opus": { displayName: "Claude Opus", providerGroup: "CLAUDE" },
295
+ "claude-fable": { displayName: "Claude Fable", providerGroup: "CLAUDE" },
281
296
  "glm-eco": { displayName: "GLM Eco", providerGroup: "GLM" },
282
297
  "glm-medium": { displayName: "GLM Medium", providerGroup: "GLM" },
283
298
  "glm-pro": { displayName: "GLM Pro", providerGroup: "GLM" },
@@ -299,6 +314,7 @@ const PROFILE_PRESENTATION: Record<string, ModelProfilePresentation> = {
299
314
  "minimax-pro": { displayName: "MiniMax Pro", providerGroup: "MINIMAX" },
300
315
  "opus-codex": { displayName: "Opus + Codex", providerGroup: "COMBOS" },
301
316
  "codex-opencodego": { displayName: "Codex + OpenCodeGo", providerGroup: "COMBOS" },
317
+ "fable-opus-codex": { displayName: "Fable + Opus + Codex", providerGroup: "COMBOS" },
302
318
  };
303
319
 
304
320
  const PROFILE_GROUP_ORDER = [
@@ -507,6 +507,21 @@ export const SETTINGS_SCHEMA = {
507
507
  description: "Use the session name color for the editor border and status line gap",
508
508
  },
509
509
  },
510
+ "statusLine.maxRows": {
511
+ type: "number",
512
+ default: 1,
513
+ ui: {
514
+ tab: "appearance",
515
+ label: "Status Line Rows",
516
+ description:
517
+ "Maximum rows for the status line. When greater than 1, overflowing segments wrap onto additional rows instead of being dropped.",
518
+ options: [
519
+ { value: "1", label: "1 row", description: "Single line; overflow is truncated (default)" },
520
+ { value: "2", label: "2 rows", description: "Wrap overflow onto a second row" },
521
+ { value: "3", label: "3 rows", description: "Wrap overflow across up to three rows" },
522
+ ],
523
+ },
524
+ },
510
525
  "tools.artifactSpillThreshold": {
511
526
  type: "number",
512
527
  default: 50,
@@ -2478,7 +2493,7 @@ export const SETTINGS_SCHEMA = {
2478
2493
  "tools.discoveryMode": {
2479
2494
  type: "enum",
2480
2495
  values: ["off", "all"] as const,
2481
- default: "off",
2496
+ default: "all",
2482
2497
  ui: {
2483
2498
  tab: "tools",
2484
2499
  label: "Tool Discovery",
@@ -2493,7 +2508,7 @@ export const SETTINGS_SCHEMA = {
2493
2508
  tab: "tools",
2494
2509
  label: "Essential Tools Override",
2495
2510
  description:
2496
- "Override the always-loaded built-in tools (default: read, bash, edit). Leave empty to use defaults.",
2511
+ "Override the always-loaded built-in tools (default: read, bash, edit, write, search, find). Leave empty to use defaults.",
2497
2512
  },
2498
2513
  },
2499
2514
 
@@ -3280,6 +3295,7 @@ export interface ExaSettings {
3280
3295
  export interface StatusLineSettings {
3281
3296
  preset: StatusLinePreset;
3282
3297
  separator: StatusLineSeparatorStyle;
3298
+ maxRows: number;
3283
3299
  showHookStatus: boolean;
3284
3300
  showSkillHud: boolean;
3285
3301
  leftSegments: StatusLineSegmentId[];
@@ -1273,9 +1273,21 @@ async function sendTmuxPromptKeys(
1273
1273
  prompt: string,
1274
1274
  runner: CommandRunner = runCommand,
1275
1275
  ): Promise<boolean> {
1276
- const typed = await runner(["tmux", "send-keys", "-t", target, "-l", prompt]);
1277
- if (typed.exitCode !== 0) return false;
1278
- const submitted = await runner(["tmux", "send-keys", "-t", target, "C-m"]);
1276
+ const bufferName = `gjc-coordinator-prompt-${randomUUID()}`;
1277
+ const buffered = await runner(["tmux", "set-buffer", "-b", bufferName, "--", prompt]);
1278
+ if (buffered.exitCode !== 0) return false;
1279
+ const pasted = await runner(["tmux", "paste-buffer", "-d", "-b", bufferName, "-t", target]);
1280
+ if (pasted.exitCode !== 0) {
1281
+ await runner(["tmux", "delete-buffer", "-b", bufferName]);
1282
+ return false;
1283
+ }
1284
+
1285
+ // Multiline slash-command prompts can leave the editor autocomplete menu focused
1286
+ // after paste. Escape clears that UI-only state so Enter submits the buffered
1287
+ // prompt instead of selecting the highlighted completion.
1288
+ const dismissedAutocomplete = await runner(["tmux", "send-keys", "-t", target, "Escape"]);
1289
+ if (dismissedAutocomplete.exitCode !== 0) return false;
1290
+ const submitted = await runner(["tmux", "send-keys", "-t", target, "Enter"]);
1279
1291
  return submitted.exitCode === 0;
1280
1292
  }
1281
1293