@gajae-code/coding-agent 0.7.8 → 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.
Files changed (92) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +8 -0
  3. package/dist/types/config/keybindings.d.ts +1 -1
  4. package/dist/types/config/model-profile-activation.d.ts +19 -2
  5. package/dist/types/config/model-profiles.d.ts +1 -0
  6. package/dist/types/config/model-registry.d.ts +4 -0
  7. package/dist/types/config/settings-schema.d.ts +12 -3
  8. package/dist/types/extensibility/extensions/types.d.ts +11 -0
  9. package/dist/types/gjc-runtime/launch-tmux.d.ts +19 -3
  10. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +7 -1
  11. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +0 -4
  12. package/dist/types/modes/components/hook-input.d.ts +1 -0
  13. package/dist/types/modes/components/hook-selector.d.ts +5 -0
  14. package/dist/types/modes/components/model-selector.d.ts +9 -0
  15. package/dist/types/modes/components/status-line.d.ts +3 -0
  16. package/dist/types/modes/controllers/extension-ui-controller.d.ts +3 -1
  17. package/dist/types/modes/interactive-mode.d.ts +3 -1
  18. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +41 -7
  19. package/dist/types/modes/types.d.ts +3 -1
  20. package/dist/types/notifications/daemon-paths.d.ts +9 -0
  21. package/dist/types/notifications/html-format.d.ts +2 -0
  22. package/dist/types/notifications/recent-activity.d.ts +5 -1
  23. package/dist/types/notifications/telegram-daemon-cli.d.ts +8 -2
  24. package/dist/types/notifications/telegram-daemon-control.d.ts +8 -0
  25. package/dist/types/notifications/telegram-daemon.d.ts +1 -10
  26. package/dist/types/notifications/telegram-reference.d.ts +4 -0
  27. package/dist/types/notifications/threaded-render.d.ts +1 -0
  28. package/dist/types/tools/ask.d.ts +26 -0
  29. package/dist/types/tools/ultragoal-ask-guard.d.ts +9 -2
  30. package/dist/types/utils/cmux-workspace.d.ts +23 -0
  31. package/dist/types/web/search/index.d.ts +1 -1
  32. package/dist/types/web/search/provider.d.ts +5 -0
  33. package/dist/types/web/search/render.d.ts +1 -0
  34. package/package.json +7 -7
  35. package/src/cli/notify-cli.ts +1 -1
  36. package/src/cli/web-search-cli.ts +3 -2
  37. package/src/cli.ts +1 -0
  38. package/src/config/keybindings.ts +1 -1
  39. package/src/config/model-profile-activation.ts +92 -11
  40. package/src/config/model-profiles.ts +15 -2
  41. package/src/config/model-registry.ts +81 -5
  42. package/src/config/settings-schema.ts +14 -3
  43. package/src/coordinator-mcp/server.ts +4 -2
  44. package/src/deep-interview/render-middleware.ts +1 -0
  45. package/src/defaults/gjc/skills/deep-interview/SKILL.md +40 -8
  46. package/src/defaults/gjc/skills/ralplan/SKILL.md +14 -7
  47. package/src/defaults/gjc/skills/ultragoal/SKILL.md +37 -112
  48. package/src/extensibility/extensions/types.ts +11 -0
  49. package/src/gjc-runtime/deep-interview-runtime.ts +1 -1
  50. package/src/gjc-runtime/launch-tmux.ts +366 -48
  51. package/src/gjc-runtime/team-runtime.ts +69 -4
  52. package/src/gjc-runtime/ultragoal-guard.ts +150 -24
  53. package/src/gjc-runtime/ultragoal-runtime.ts +16 -124
  54. package/src/gjc-runtime/workflow-manifest.generated.json +0 -8
  55. package/src/gjc-runtime/workflow-manifest.ts +0 -1
  56. package/src/hooks/skill-state.ts +33 -73
  57. package/src/internal-urls/docs-index.generated.ts +8 -7
  58. package/src/modes/components/custom-model-preset-wizard.ts +2 -4
  59. package/src/modes/components/hook-editor.ts +7 -4
  60. package/src/modes/components/hook-input.ts +4 -0
  61. package/src/modes/components/hook-selector.ts +21 -3
  62. package/src/modes/components/model-selector.ts +84 -13
  63. package/src/modes/components/settings-selector.ts +83 -24
  64. package/src/modes/components/status-line/presets.ts +11 -0
  65. package/src/modes/components/status-line/segments.ts +10 -2
  66. package/src/modes/components/status-line.ts +1 -0
  67. package/src/modes/controllers/extension-ui-controller.ts +20 -2
  68. package/src/modes/controllers/selector-controller.ts +130 -7
  69. package/src/modes/interactive-mode.ts +7 -2
  70. package/src/modes/shared/agent-wire/deep-interview-gate.ts +64 -13
  71. package/src/modes/types.ts +6 -1
  72. package/src/notifications/daemon-paths.ts +22 -0
  73. package/src/notifications/html-format.ts +75 -1
  74. package/src/notifications/index.ts +12 -1
  75. package/src/notifications/recent-activity.ts +32 -8
  76. package/src/notifications/telegram-daemon-cli.ts +13 -4
  77. package/src/notifications/telegram-daemon-control.ts +9 -0
  78. package/src/notifications/telegram-daemon.ts +69 -45
  79. package/src/notifications/telegram-reference.ts +36 -14
  80. package/src/notifications/threaded-render.ts +14 -6
  81. package/src/prompts/system/system-prompt.md +10 -1
  82. package/src/sdk.ts +13 -6
  83. package/src/session/agent-session.ts +10 -1
  84. package/src/tools/ask.ts +147 -17
  85. package/src/tools/eval.ts +2 -2
  86. package/src/tools/render-utils.ts +2 -0
  87. package/src/tools/ultragoal-ask-guard.ts +39 -5
  88. package/src/utils/cmux-workspace.ts +106 -0
  89. package/src/utils/title-generator.ts +2 -0
  90. package/src/web/search/index.ts +22 -10
  91. package/src/web/search/provider.ts +15 -0
  92. package/src/web/search/render.ts +3 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,41 @@
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
+
27
+ ## [0.7.9] - 2026-07-01
28
+ ### Added
29
+
30
+ - Added an optional Tavily web search provider selectable through `providers.webSearch`, using `TAVILY_API_KEY` only when Tavily is selected (#1323).
31
+
32
+ ### Fixed
33
+
34
+ - Deep Interview now treats English `implementation` and Korean `구현` wording as eventual-target language, not permission to edit code or launch implementation before post-interview approval (#1320).
35
+ - Restored default Enter = submit in the main chat composer. #1326 rerouted plain Enter in the prompt to insert a newline (making Ctrl+Enter the submit chord); this reverts that so Enter submits again and Shift+Enter inserts a newline.
36
+ - Registered the optional `gjc acp` subcommand so Zed/custom ACP clients can launch the ACP stdio server through the documented command entrypoint, and documented the Zed `agent_servers` custom-agent shape (#1327).
37
+ - Compiled binaries can now include the hidden Telegram daemon CLI entrypoint without hanging root startup, and release builds preserve that entry so `gjc notify daemon-internal --smoke` is available in standalone binaries (#1288).
38
+ - Documented Windows Terminal BEL limitations for terminal bell notifications and added a PowerShell `completion.notifyCommand` beep workaround example (#1318).
39
+
5
40
  ## [0.7.8] - 2026-06-30
6
41
  ### Added
7
42
 
@@ -11,10 +46,15 @@
11
46
 
12
47
  ### Fixed
13
48
 
49
+ - Fixed a class of TUI renderer crashes (`TypeError: undefined is not an object (evaluating 'x.trim'/'x.split')`) where render helpers typed `(x: string)` ran a string op on an optional/possibly-undefined tool-detail field. The deep-interview/ralplan `ask` renderer crashed on a result with a missing `question`; caught during streaming but fatal on render/teardown paths such as `/background` detach. Hardened `normalizeText`, `getPreviewLines`, `shortenPath`, and the eval git_log status-event renderer (#1290).
50
+
14
51
  - `gjc update` now verifies the installed runtime after package-manager failures and treats a nonzero Bun/npm exit as recoverable when the requested version and smoke test actually landed, avoiding false failures from Bun tarball extraction errors (#1280).
52
+ - Deep Interview now prefers the native hook's pre-resolved ambiguity threshold state and avoids surfacing missing optional settings files as failed `Read` calls during Phase 0.
53
+ - Scoped Ultragoal ask-guard checks for `deep-interview` and `ralplan` asks to the current session, so stale or ambiguous Ultragoal state from other sessions no longer suppresses the choice UI while same-session active Ultragoal blockers still apply.
15
54
  - Submitted user prompts now use the live terminal viewport width in wide Windows Terminal/PowerShell sessions, keeping Korean/CJK prompt wrapping responsive without changing narrow layouts (#1239).
16
55
  - Coordinator MCP now fails tmux-delivered turns that never receive a runtime prompt acknowledgement/`turn_start`, surfacing an explicit unacknowledged delivery reason instead of leaving Hermes/Oren waiting on a normal active/running state (#1237).
17
56
  - Telegram now advertises `/session_create`, `/session_recent`, `/session_close`, and `/session_resume` in the bot command menu so lifecycle control commands are discoverable from `/` autocomplete.
57
+ - `gjc --tmux` now prefixes the root terminal title (`GJC: tmp`) and managed tmux window names (`GJC-tmp`) with a GJC workspace label so terminal multiplexers and workspace switchers do not fall back to noisy launch paths.
18
58
 
19
59
  ## [0.7.7] - 2026-06-28
20
60
  ### Added
package/README.md CHANGED
@@ -24,6 +24,14 @@ 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
+
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:
30
+
31
+ ```powershell
32
+ gjc config set completion.notifyCommand 'powershell.exe -NoProfile -Command "[Console]::Beep(880, 300)"'
33
+ ```
34
+
27
35
  `cmux notify` returning successfully means GJC handed the completion event to cmux. cmux may still suppress the native desktop banner when the app/window is focused, the emitting workspace is active, or the notification panel is open. In those cases, check cmux's notification panel or unread workspace state instead of treating the missing banner as a GJC delivery failure.
28
36
 
29
37
  Recommended external mapping:
@@ -231,7 +231,7 @@ export declare const KEYBINDINGS: {
231
231
  };
232
232
  readonly "app.message.followUp": {
233
233
  readonly defaultKeys: [];
234
- readonly description: "Send follow-up message (no default; Ctrl+Enter inserts a newline)";
234
+ readonly description: "Send follow-up message (no default; Ctrl+Enter submits)";
235
235
  };
236
236
  readonly "app.message.queue": {
237
237
  readonly defaultKeys: "alt+enter";
@@ -21,7 +21,7 @@ export interface PreparedModelProfileActivation {
21
21
  session: ModelProfileActivationSession & {
22
22
  setModelTemporary: AgentSession["setModelTemporary"];
23
23
  };
24
- settings: Pick<Settings, "get" | "override" | "set" | "flush">;
24
+ settings: Pick<Settings, "clearOverride" | "get" | "getGlobal" | "override" | "set" | "flush">;
25
25
  previousModel: Model<Api> | undefined;
26
26
  previousThinkingLevel: ThinkingLevel | undefined;
27
27
  previousAgentModelOverrides: Record<string, string>;
@@ -47,11 +47,28 @@ export interface MaterializeModelProfileAssignmentOptions {
47
47
  selector: string;
48
48
  }
49
49
  export declare function materializeActiveModelProfileAssignment(options: MaterializeModelProfileAssignmentOptions): boolean;
50
- export declare function formatModelProfileCredentialError(profileName: string, providers: readonly string[]): string;
50
+ export declare function formatModelProfileCredentialError(profileLabel: string, providers: readonly string[]): string;
51
51
  export declare function prepareModelProfileActivation(options: PrepareModelProfileActivationOptions): Promise<PreparedModelProfileActivation>;
52
52
  export declare function applyPreparedModelProfileActivation(prepared: PreparedModelProfileActivation, options?: {
53
53
  persistDefault?: boolean;
54
54
  }): Promise<void>;
55
+ export interface MaterializeModelProfileForDeletionResult {
56
+ modelRoles: Record<string, string>;
57
+ agentModelOverrides: Record<string, string>;
58
+ previousModelRoles: Record<string, string>;
59
+ previousAgentModelOverrides: Record<string, string>;
60
+ previousDefaultProfile: string | undefined;
61
+ previousPersistedDefaultProfile: string | undefined;
62
+ previousActiveModelProfile: string | undefined;
63
+ }
64
+ export declare function materializeModelProfileForDeletion(options: PrepareModelProfileActivationOptions & {
65
+ settings: Pick<Settings, "clearOverride" | "flush" | "get" | "getGlobal" | "override" | "set">;
66
+ }): Promise<MaterializeModelProfileForDeletionResult>;
67
+ export declare function restoreMaterializedModelProfileForDeletion(options: {
68
+ settings: Pick<Settings, "flush" | "override" | "set">;
69
+ session: Pick<ModelProfileActivationSession, "setActiveModelProfile">;
70
+ snapshot: MaterializeModelProfileForDeletionResult;
71
+ }): Promise<void>;
55
72
  export declare function activateModelProfile(options: PrepareModelProfileActivationOptions, applyOptions?: {
56
73
  persistDefault?: boolean;
57
74
  }): Promise<void>;
@@ -31,6 +31,7 @@ export interface ModelProfilePresentation {
31
31
  providerGroup: string;
32
32
  }
33
33
  export declare function getModelProfilePresentation(profile: string | Pick<ModelProfileDefinition, "name" | "displayName">): ModelProfilePresentation;
34
+ export declare function formatModelProfileDisplayLabel(profile: Pick<ModelProfileDefinition, "name" | "displayName">): string;
34
35
  export declare function groupModelProfilesForPresetLanding(profiles: ReadonlyMap<string, ModelProfileDefinition>): Map<string, ModelProfileDefinition[]>;
35
36
  export declare function recommendModelProfileForProvider(providerId: string, profiles: ReadonlyMap<string, ModelProfileDefinition>): ModelProfileDefinition | undefined;
36
37
  export declare function mergeModelProfiles(userProfiles?: ModelsConfig["profiles"]): Map<string, ModelProfileDefinition>;
@@ -19,6 +19,8 @@ export interface ModelRoleInfo {
19
19
  }
20
20
  export declare const MODEL_ROLES: Record<ModelRole, ModelRoleInfo>;
21
21
  export declare const MODEL_ROLE_IDS: ModelRole[];
22
+ export declare const MODEL_PROFILE_NAME_PATTERN: RegExp;
23
+ export declare const MODEL_PROFILE_NAME_PATTERN_DESCRIPTION = "lowercase letters, numbers, dots, underscores, or hyphens";
22
24
  export type GjcModelAssignmentTargetId = "default" | "executor" | "architect" | "planner" | "critic";
23
25
  export interface GjcModelAssignmentTargetInfo extends ModelRoleInfo {
24
26
  id: GjcModelAssignmentTargetId;
@@ -342,6 +344,8 @@ export declare class ModelRegistry {
342
344
  getModelProfile(name: string): ModelProfileDefinition | undefined;
343
345
  getAvailableModelProfileNames(): string[];
344
346
  saveCustomModelProfile(name: string, definition: ModelProfileConfig): Promise<ModelProfileDefinition>;
347
+ renameCustomModelProfile(name: string, displayName: string): Promise<ModelProfileDefinition>;
348
+ deleteCustomModelProfile(name: string): Promise<ModelProfileConfig>;
345
349
  applyConfiguredModelBindings(targetSettings: Settings): void;
346
350
  /**
347
351
  * Get all models (built-in + custom).
@@ -166,7 +166,7 @@ export declare const SETTINGS_SCHEMA: {
166
166
  readonly ui: {
167
167
  readonly tab: "interaction";
168
168
  readonly label: "Terminal Bell";
169
- readonly description: "Emit a BEL character for local terminal notifications";
169
+ readonly description: "Emit a BEL character for local terminal notifications. Windows Terminal may keep BEL silent depending on profile/system sound settings; use completion.notifyCommand for a PowerShell Console.Beep workaround.";
170
170
  };
171
171
  };
172
172
  readonly "notifications.bellOnComplete": {
@@ -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";
@@ -1343,7 +1347,7 @@ export declare const SETTINGS_SCHEMA: {
1343
1347
  readonly ui: {
1344
1348
  readonly tab: "interaction";
1345
1349
  readonly label: "Completion Notification Command";
1346
- readonly description: "Optional user-level shell command to run when an agent turn completes; receives GJC_NOTIFICATION_* environment variables.";
1350
+ readonly description: "Optional user-level shell command to run when an agent turn completes; receives GJC_NOTIFICATION_* environment variables. On Windows, this can call PowerShell [Console]::Beep when terminal BEL is silent.";
1347
1351
  };
1348
1352
  };
1349
1353
  readonly "ask.timeout": {
@@ -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,13 +33,26 @@ 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;
37
43
  env: NodeJS.ProcessEnv;
38
- stdin: "inherit";
39
- stdout: "inherit";
40
- stderr: "inherit";
44
+ stdin: "inherit" | "pipe";
45
+ stdout: "inherit" | "pipe";
46
+ stderr: "inherit" | "pipe";
47
+ /**
48
+ * When true, the spawn captures stderr into a buffer and forwards it to
49
+ * the parent stderr so the user still sees the live output. The captured
50
+ * text is also returned in TmuxSpawnResult.stderr for diagnostic
51
+ * surfacing in "attach failed" / "profile tagging failed" messages.
52
+ * Defaults to false to preserve the previous PTY-binding behavior for
53
+ * attach-session and other interactive commands.
54
+ */
55
+ captureStderr?: boolean;
41
56
  }
42
57
  export interface TmuxLaunchPlan {
43
58
  tmuxCommand: string;
@@ -45,6 +60,7 @@ export interface TmuxLaunchPlan {
45
60
  cwd: string;
46
61
  innerCommand: string;
47
62
  newSessionArgs: string[];
63
+ initialSize?: TmuxTerminalSize;
48
64
  branch?: string | null;
49
65
  attachSessionName?: string;
50
66
  project?: string | null;
@@ -29,7 +29,13 @@ export declare function readUltragoalVerificationState(input: {
29
29
  currentGoal?: CurrentGoalLike | null;
30
30
  sessionId?: string | null;
31
31
  }): Promise<UltragoalGuardDiagnostic>;
32
- export declare function isUltragoalAskBlocked(cwd: string): Promise<UltragoalAskBlockDiagnostic>;
32
+ export declare function verifyUltragoalDurableCompletionState(input: {
33
+ cwd: string;
34
+ sessionId?: string | null;
35
+ }): Promise<UltragoalGuardDiagnostic>;
36
+ export declare function isUltragoalAskBlocked(cwd: string, options?: {
37
+ sessionId?: string | null;
38
+ }): Promise<UltragoalAskBlockDiagnostic>;
33
39
  /**
34
40
  * Escalating per-attempt refusal text. Deliberately avoids every
35
41
  * `isUltragoalBypassPrompt` trigger: no `update_goal(`, no "skip/weaken verification",
@@ -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
  /**
@@ -3,6 +3,7 @@
3
3
  */
4
4
  import { Container, type TUI } from "@gajae-code/tui";
5
5
  export interface HookInputOptions {
6
+ initialValue?: string;
6
7
  tui?: TUI;
7
8
  timeout?: number;
8
9
  onTimeout?: () => void;
@@ -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 `/`
@@ -19,6 +19,12 @@ export type ModelSelectorSelection = {
19
19
  } | {
20
20
  kind: "createProfile";
21
21
  profile: ModelProfileConfig;
22
+ } | {
23
+ kind: "renameProfile";
24
+ profileName: string;
25
+ } | {
26
+ kind: "deleteProfile";
27
+ profileName: string;
22
28
  };
23
29
  type RoleSelectCallback = (selection: ModelSelectorSelection) => void | Promise<void>;
24
30
  /**
@@ -47,7 +53,10 @@ export declare class ModelSelectorComponent extends Container {
47
53
  activeModelProfile?: string;
48
54
  }): void;
49
55
  handleInput(keyData: string): void;
56
+ refreshPresetProfiles(profileName?: string): void;
50
57
  getSearchInput(): Input;
51
58
  __testSelectProfile(profileName: string, setDefault: boolean): Promise<void>;
59
+ __testSelectPresetAction(profileName: string, action: "rename" | "delete"): Promise<void>;
60
+ __testSelectedPresetRowIdentity(): string | undefined;
52
61
  }
53
62
  export {};
@@ -22,6 +22,9 @@ export interface StatusLineSegmentOptions {
22
22
  format?: "12h" | "24h";
23
23
  showSeconds?: boolean;
24
24
  };
25
+ usage?: {
26
+ mode?: "used" | "remaining";
27
+ };
25
28
  }
26
29
  export interface StatusLineSettings {
27
30
  preset?: StatusLinePreset;
@@ -41,7 +41,9 @@ export declare class ExtensionUiController {
41
41
  /**
42
42
  * Show a text input for hooks.
43
43
  */
44
- showHookInput(title: string, placeholder?: string, dialogOptions?: ExtensionUIDialogOptions): Promise<string | undefined>;
44
+ showHookInput(title: string, placeholder?: string, dialogOptions?: ExtensionUIDialogOptions, inputOptions?: {
45
+ readonly initialValue?: string;
46
+ }): Promise<string | undefined>;
45
47
  /**
46
48
  * Hide the hook input.
47
49
  */
@@ -250,7 +250,9 @@ export declare class InteractiveMode implements InteractiveModeContext {
250
250
  setHookStatus(key: string, text: string | undefined): void;
251
251
  showHookSelector(title: string, options: string[], dialogOptions?: ExtensionUIDialogOptions): Promise<string | undefined>;
252
252
  hideHookSelector(): void;
253
- showHookInput(title: string, placeholder?: string): Promise<string | undefined>;
253
+ showHookInput(title: string, placeholder?: string, dialogOptions?: ExtensionUIDialogOptions, inputOptions?: {
254
+ readonly initialValue?: string;
255
+ }): Promise<string | undefined>;
254
256
  hideHookInput(): void;
255
257
  showHookEditor(title: string, prefill?: string, dialogOptions?: ExtensionUIDialogOptions, editorOptions?: {
256
258
  promptStyle?: boolean;
@@ -1,3 +1,17 @@
1
+ /**
2
+ * Deep-interview gate mapping (#316).
3
+ *
4
+ * Converts deep-interview `ask`-tool questions into machine-addressable
5
+ * `workflow_gate` { kind: "question" } events (option set + free-text shape
6
+ * encoded in `schema`/`options`) and decodes a `workflow_gate_response` answer
7
+ * back into the exact QuestionResult shape the human path produces, so ambiguity
8
+ * scoring/state updates proceed identically whether a human or an agent answers.
9
+ *
10
+ * This is the pure mapping primitive. Routing the ask tool through it (instead of
11
+ * the interactive select/editor UI) when an unattended controller + gate broker
12
+ * are attached is wired with the transport in #321 and exercised by #323.
13
+ */
14
+ import type { RpcWorkflowGateKind, RpcWorkflowStage } from "../../rpc/rpc-types";
1
15
  import type { OpenGateInput } from "./workflow-gate-broker";
2
16
  /** "Other (type your own)" sentinel, mirroring the interactive ask tool. */
3
17
  export declare const GATE_OTHER_OPTION = "Other (type your own)";
@@ -9,6 +23,10 @@ export interface AskGateDeepInterviewState {
9
23
  dimension: string;
10
24
  ambiguity: number;
11
25
  }
26
+ export interface AskGateWorkflowGateMeta {
27
+ stage: RpcWorkflowStage;
28
+ kind: RpcWorkflowGateKind;
29
+ }
12
30
  export interface AskGateQuestion {
13
31
  id: string;
14
32
  question: string;
@@ -22,6 +40,8 @@ export interface AskGateQuestion {
22
40
  * `stage_state`; when absent, the question text is regex-parsed as a fallback.
23
41
  */
24
42
  deepInterview?: AskGateDeepInterviewState;
43
+ /** Override the emitted workflow gate address for non-deep-interview ask prompts. */
44
+ workflowGate?: AskGateWorkflowGateMeta;
25
45
  }
26
46
  export interface AskGateResult {
27
47
  id: string;
@@ -30,6 +50,7 @@ export interface AskGateResult {
30
50
  multi: boolean;
31
51
  selectedOptions: string[];
32
52
  customInput?: string;
53
+ clarificationQuestion?: string;
33
54
  }
34
55
  /**
35
56
  * The answer shape an agent returns for a deep-interview question gate.
@@ -37,17 +58,30 @@ export interface AskGateResult {
37
58
  * `selected` are picked option labels; free text is conveyed by `other: true`
38
59
  * plus `custom`, encoded separately from `selected` so a real option whose label
39
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.
40
65
  */
41
- export interface DeepInterviewGateAnswer {
66
+ export type DeepInterviewGateAnswer = {
42
67
  selected: string[];
43
- other?: boolean;
44
- custom?: string;
45
- }
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
+ };
46
80
  export declare class DeepInterviewGateError extends Error {
47
- readonly code: "invalid_answer_shape" | "unknown_option" | "multi_not_allowed" | "missing_custom" | "empty_selection" | "duplicate_selection";
48
- 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);
49
83
  }
50
- /** Build the `workflow_gate` open-input for one deep-interview question. */
84
+ /** Build the `workflow_gate` open-input for one ask question. */
51
85
  export declare function questionToGate(question: AskGateQuestion): OpenGateInput;
52
86
  /**
53
87
  * Decode a gate answer into the QuestionResult the interactive path produces.
@@ -260,7 +260,9 @@ export interface InteractiveModeContext {
260
260
  setHookStatus(key: string, text: string | undefined): void;
261
261
  showHookSelector(title: string, options: string[], dialogOptions?: ExtensionUIDialogOptions): Promise<string | undefined>;
262
262
  hideHookSelector(): void;
263
- showHookInput(title: string, placeholder?: string): Promise<string | undefined>;
263
+ showHookInput(title: string, placeholder?: string, dialogOptions?: ExtensionUIDialogOptions, inputOptions?: {
264
+ readonly initialValue?: string;
265
+ }): Promise<string | undefined>;
264
266
  hideHookInput(): void;
265
267
  showHookEditor(title: string, prefill?: string, dialogOptions?: ExtensionUIDialogOptions, editorOptions?: {
266
268
  promptStyle?: boolean;
@@ -0,0 +1,9 @@
1
+ export interface DaemonPaths {
2
+ dir: string;
3
+ lock: string;
4
+ state: string;
5
+ roots: string;
6
+ steal: string;
7
+ aliases: string;
8
+ }
9
+ export declare function daemonPaths(agentDir: string): DaemonPaths;
@@ -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
- readFirstLine?: (file: string) => string | undefined;
30
+ readInitialLines?: (file: string, maxLines: number) => string[];
27
31
  }
28
32
  /**
29
33
  * List recent sessions ranked by history-file mtime (newest first).
@@ -1,12 +1,17 @@
1
1
  import type { Settings } from "../config/settings";
2
- import { TelegramNotificationDaemon } from "./telegram-daemon";
2
+ import type { TelegramDaemonOptions } from "./telegram-daemon";
3
+ type TelegramDaemonRunner = {
4
+ run(): Promise<void>;
5
+ requestStop(reason?: "reload" | "signal" | "stop"): void;
6
+ };
7
+ type TelegramDaemonConstructor = new (opts: TelegramDaemonOptions) => TelegramDaemonRunner;
3
8
  export interface RunDaemonInternalDeps {
4
9
  SettingsImpl?: {
5
10
  init: (options?: {
6
11
  agentDir?: string;
7
12
  }) => Promise<Pick<Settings, "get" | "getAgentDir">>;
8
13
  };
9
- DaemonImpl?: typeof TelegramNotificationDaemon;
14
+ DaemonImpl?: TelegramDaemonConstructor;
10
15
  processPid?: number;
11
16
  pidAlive?: (pid: number) => boolean;
12
17
  }
@@ -20,3 +25,4 @@ export declare function runDaemonSmoke(opts?: {
20
25
  agentDir?: string;
21
26
  }): Promise<void>;
22
27
  export declare function runDaemonInternal(argv: string[], deps?: RunDaemonInternalDeps): Promise<void>;
28
+ export {};
@@ -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;
@@ -16,14 +16,6 @@ export interface DaemonState {
16
16
  version: 1;
17
17
  stoppedAt?: number;
18
18
  }
19
- export interface DaemonPaths {
20
- dir: string;
21
- lock: string;
22
- state: string;
23
- roots: string;
24
- steal: string;
25
- aliases: string;
26
- }
27
19
  export interface TelegramDaemonFs {
28
20
  mkdir(path: string, opts?: fs.MakeDirectoryOptions): Promise<void>;
29
21
  readFile(path: string, encoding: BufferEncoding): Promise<string>;
@@ -59,7 +51,7 @@ export declare const DAEMON_VERSION = 1;
59
51
  export declare const CLIENT_PING_PONG_CAPABILITY = "client_ping_pong";
60
52
  /** Protocol version the daemon advertises in its ClientHello. */
61
53
  export declare const NOTIFICATION_PROTOCOL_VERSION = 2;
62
- export declare function daemonPaths(agentDir: string): DaemonPaths;
54
+ export { type DaemonPaths, daemonPaths } from "./daemon-paths";
63
55
  /**
64
56
  * Attach session-lifecycle control (create/close/resume) to the running daemon.
65
57
  *
@@ -390,4 +382,3 @@ export declare class TelegramNotificationDaemon {
390
382
  run(): Promise<void>;
391
383
  private controlStopRequested;
392
384
  }
393
- export {};
@@ -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 {};
@@ -42,6 +42,7 @@ interface ThreadedFrame {
42
42
  tokenUsage?: unknown;
43
43
  model?: unknown;
44
44
  diff?: unknown;
45
+ cwd?: unknown;
45
46
  phase?: unknown;
46
47
  text?: unknown;
47
48
  messageRef?: unknown;