@gajae-code/coding-agent 0.11.6 → 0.11.8

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 (259) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/dist/types/capability/index.d.ts +10 -20
  3. package/dist/types/capability/types.d.ts +3 -0
  4. package/dist/types/cli/args.d.ts +0 -2
  5. package/dist/types/commands/daemon.d.ts +2 -2
  6. package/dist/types/commands/sdk.d.ts +20 -2
  7. package/dist/types/config/keybindings.d.ts +34 -4
  8. package/dist/types/config/model-profile-activation.d.ts +4 -3
  9. package/dist/types/config/model-profile-contract.d.ts +38 -0
  10. package/dist/types/config/settings-schema.d.ts +70 -7
  11. package/dist/types/edit/modes/patch.d.ts +13 -0
  12. package/dist/types/edit/path-mutation-lock.d.ts +15 -0
  13. package/dist/types/eval/py/executor.d.ts +1 -1
  14. package/dist/types/eval/py/runner-artifact.d.ts +8 -0
  15. package/dist/types/eval/py/tool-bridge.d.ts +1 -2
  16. package/dist/types/gjc-runtime/repository-binding.d.ts +63 -0
  17. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +6 -5
  18. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +20 -0
  19. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +43 -5
  20. package/dist/types/main.d.ts +32 -1
  21. package/dist/types/modes/components/btw-panel.d.ts +1 -0
  22. package/dist/types/modes/components/model-selector.d.ts +2 -0
  23. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
  24. package/dist/types/modes/components/tool-status-header.d.ts +4 -2
  25. package/dist/types/modes/components/welcome.d.ts +2 -0
  26. package/dist/types/modes/controllers/btw-controller.d.ts +5 -0
  27. package/dist/types/modes/controllers/command-controller.d.ts +2 -0
  28. package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
  29. package/dist/types/modes/interactive-mode.d.ts +7 -2
  30. package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
  31. package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
  32. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
  33. package/dist/types/modes/types.d.ts +4 -0
  34. package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
  35. package/dist/types/runtime-mcp/content-limits.d.ts +7 -0
  36. package/dist/types/runtime-mcp/manager.d.ts +1 -1
  37. package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
  38. package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
  39. package/dist/types/sdk/broker/broker.d.ts +2 -0
  40. package/dist/types/sdk/broker/lifecycle.d.ts +6 -0
  41. package/dist/types/sdk/bus/chat-daemon-control.d.ts +6 -1
  42. package/dist/types/sdk/bus/config-commands.d.ts +2 -2
  43. package/dist/types/sdk/bus/config.d.ts +2 -0
  44. package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
  45. package/dist/types/sdk/bus/index.d.ts +26 -1
  46. package/dist/types/sdk/bus/lifecycle-commands.d.ts +5 -4
  47. package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
  48. package/dist/types/sdk/bus/notification-service.d.ts +34 -0
  49. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +105 -0
  50. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +18 -3
  51. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
  52. package/dist/types/sdk/bus/telegram-daemon.d.ts +189 -4
  53. package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
  54. package/dist/types/sdk/bus/topic-registry.d.ts +88 -2
  55. package/dist/types/sdk/client/discovery.d.ts +2 -0
  56. package/dist/types/sdk/client/liveness.d.ts +7 -0
  57. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  58. package/dist/types/sdk/host/host.d.ts +1 -1
  59. package/dist/types/sdk/host/query/handlers.d.ts +9 -0
  60. package/dist/types/sdk/index.d.ts +2 -0
  61. package/dist/types/sdk/prompt-status.d.ts +88 -0
  62. package/dist/types/sdk/session-directory.d.ts +1 -1
  63. package/dist/types/sdk/startup-capability.d.ts +3 -0
  64. package/dist/types/sdk/transport/auth-preface.d.ts +9 -0
  65. package/dist/types/sdk/transport/index.d.ts +12 -0
  66. package/dist/types/sdk/transport/relay.d.ts +43 -0
  67. package/dist/types/sdk/transport/serve-cli.d.ts +4 -0
  68. package/dist/types/sdk/transport/socket.d.ts +7 -0
  69. package/dist/types/sdk/transport/stdio.d.ts +3 -0
  70. package/dist/types/session/agent-session.d.ts +30 -5
  71. package/dist/types/session/btw-contract.d.ts +16 -0
  72. package/dist/types/session/internal/managed-session-scope.d.ts +32 -9
  73. package/dist/types/session/internal/managed-session-storage.d.ts +27 -10
  74. package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
  75. package/dist/types/session/session-manager.d.ts +25 -4
  76. package/dist/types/session/session-storage.d.ts +18 -0
  77. package/dist/types/setup/credential-import.d.ts +5 -1
  78. package/dist/types/setup/provider-onboarding.d.ts +2 -0
  79. package/dist/types/ssh/utils.d.ts +1 -0
  80. package/dist/types/task/discovery.d.ts +3 -1
  81. package/dist/types/task/index.d.ts +3 -1
  82. package/dist/types/task/receipt.d.ts +2 -0
  83. package/dist/types/task/types.d.ts +94 -0
  84. package/dist/types/tools/ask.d.ts +454 -174
  85. package/dist/types/tools/fetch.d.ts +5 -8
  86. package/dist/types/tools/image-gen.d.ts +63 -1
  87. package/dist/types/tools/index.d.ts +4 -0
  88. package/dist/types/tools/skill-discovery.d.ts +7 -0
  89. package/dist/types/tools/sqlite-reader.d.ts +7 -0
  90. package/dist/types/utils/prompt-suggestion.d.ts +33 -0
  91. package/dist/types/utils/shell-snapshot.d.ts +12 -0
  92. package/dist/types/web/insane/bridge.d.ts +1 -0
  93. package/dist/types/web/insane/url-guard.d.ts +17 -0
  94. package/package.json +8 -8
  95. package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
  96. package/scripts/dogfood-repository-binding.ts +209 -0
  97. package/scripts/generate-sdk-operation-inventory.ts +4 -0
  98. package/scripts/run-test-manifest.ts +4 -4
  99. package/src/capability/index.ts +50 -42
  100. package/src/capability/types.ts +3 -0
  101. package/src/cli/args.ts +2 -92
  102. package/src/cli/notify-cli.ts +5 -38
  103. package/src/cli/setup-cli.ts +10 -4
  104. package/src/cli.ts +52 -9
  105. package/src/commands/daemon.ts +22 -5
  106. package/src/commands/sdk.ts +44 -11
  107. package/src/config/keybindings.ts +158 -25
  108. package/src/config/model-profile-activation.ts +7 -18
  109. package/src/config/model-profile-contract.ts +161 -0
  110. package/src/config/model-profiles.ts +18 -0
  111. package/src/config/model-registry.ts +11 -1
  112. package/src/config/settings-schema.ts +73 -7
  113. package/src/coordinator-mcp/model-preset.ts +21 -74
  114. package/src/defaults/gjc/skills/deep-interview/SKILL.md +2 -2
  115. package/src/defaults/gjc/skills/ralplan/SKILL.md +3 -1
  116. package/src/defaults/gjc/skills/ultragoal/SKILL.md +42 -1
  117. package/src/discovery/ssh.ts +12 -1
  118. package/src/edit/index.ts +3 -6
  119. package/src/edit/modes/patch.ts +38 -1
  120. package/src/edit/modes/replace.ts +42 -0
  121. package/src/edit/path-mutation-lock.ts +112 -0
  122. package/src/eval/py/executor.ts +30 -11
  123. package/src/eval/py/kernel.ts +1 -21
  124. package/src/eval/py/prelude.py +2 -2
  125. package/src/eval/py/runner-artifact.ts +84 -0
  126. package/src/eval/py/tool-bridge.ts +34 -18
  127. package/src/extensibility/gjc-plugins/runtime-adapters.ts +2 -1
  128. package/src/extensibility/plugins/marketplace/fetcher.ts +191 -7
  129. package/src/gjc-runtime/launch-tmux.ts +1 -1
  130. package/src/gjc-runtime/managed-owner-supervisor.ts +83 -4
  131. package/src/gjc-runtime/ralplan-runtime.ts +75 -3
  132. package/src/gjc-runtime/repository-binding.ts +267 -0
  133. package/src/gjc-runtime/session-state-sidecar.ts +25 -9
  134. package/src/gjc-runtime/tmux-owner-isolation.ts +2 -1
  135. package/src/gjc-runtime/tmux-sessions.ts +45 -6
  136. package/src/gjc-runtime/ultragoal-guard.ts +93 -15
  137. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +103 -0
  138. package/src/gjc-runtime/ultragoal-runtime.ts +456 -31
  139. package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
  140. package/src/gjc-runtime/workflow-manifest.ts +23 -0
  141. package/src/internal-urls/docs-index.generated.ts +12 -10
  142. package/src/internal-urls/local-protocol.ts +64 -21
  143. package/src/internal-urls/mcp-protocol.ts +73 -11
  144. package/src/main.ts +111 -37
  145. package/src/modes/DESIGN.md +5 -0
  146. package/src/modes/acp/acp-agent.ts +50 -16
  147. package/src/modes/action-registry.ts +1 -1
  148. package/src/modes/components/btw-panel.ts +82 -16
  149. package/src/modes/components/model-selector.ts +73 -11
  150. package/src/modes/components/plan-preview-overlay.ts +1 -1
  151. package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
  152. package/src/modes/components/tool-status-header.ts +25 -4
  153. package/src/modes/components/welcome.ts +22 -18
  154. package/src/modes/controllers/btw-controller.ts +119 -36
  155. package/src/modes/controllers/command-controller.ts +97 -54
  156. package/src/modes/controllers/event-controller.ts +10 -0
  157. package/src/modes/controllers/input-controller.ts +38 -2
  158. package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
  159. package/src/modes/controllers/selector-controller.ts +149 -63
  160. package/src/modes/interactive-mode.ts +57 -34
  161. package/src/modes/prompt-action-autocomplete.ts +32 -13
  162. package/src/modes/prompt-suggestion-controller.ts +96 -0
  163. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
  164. package/src/modes/types.ts +4 -0
  165. package/src/modes/utils/hotkeys-markdown.ts +64 -36
  166. package/src/modes/utils/ui-helpers.ts +5 -3
  167. package/src/prompts/agents/architect.md +0 -1
  168. package/src/prompts/agents/critic.md +0 -1
  169. package/src/prompts/system/btw-user.md +3 -8
  170. package/src/prompts/system/prompt-suggestion-system.md +32 -0
  171. package/src/prompts/system/system-prompt.md +6 -4
  172. package/src/prompts/tools/cron.md +3 -1
  173. package/src/prompts/tools/skill-discovery.md +1 -0
  174. package/src/runtime-mcp/client.ts +41 -55
  175. package/src/runtime-mcp/content-limits.ts +71 -0
  176. package/src/runtime-mcp/json-rpc.ts +23 -9
  177. package/src/runtime-mcp/manager.ts +51 -53
  178. package/src/runtime-mcp/oauth-flow.ts +0 -72
  179. package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
  180. package/src/runtime-mcp/transports/http.ts +63 -22
  181. package/src/sdk/broker/broker.ts +34 -20
  182. package/src/sdk/broker/lifecycle.ts +185 -36
  183. package/src/sdk/bus/chat-daemon-control.ts +19 -5
  184. package/src/sdk/bus/config-commands.ts +2 -2
  185. package/src/sdk/bus/config.ts +9 -1
  186. package/src/sdk/bus/conversation-store.ts +40 -6
  187. package/src/sdk/bus/index.ts +244 -70
  188. package/src/sdk/bus/lifecycle-commands.ts +63 -10
  189. package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
  190. package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
  191. package/src/sdk/bus/notification-orchestration.ts +12 -0
  192. package/src/sdk/bus/notification-service.ts +68 -20
  193. package/src/sdk/bus/prompt-reconciliation.ts +239 -0
  194. package/src/sdk/bus/recent-activity.ts +90 -26
  195. package/src/sdk/bus/telegram-daemon-contract.ts +18 -3
  196. package/src/sdk/bus/telegram-daemon-control.ts +147 -35
  197. package/src/sdk/bus/telegram-daemon.ts +2463 -450
  198. package/src/sdk/bus/telegram-reference.ts +20 -2
  199. package/src/sdk/bus/topic-registry.ts +451 -12
  200. package/src/sdk/cli/session-cli.ts +15 -2
  201. package/src/sdk/client/discovery.ts +19 -3
  202. package/src/sdk/client/liveness.ts +49 -0
  203. package/src/sdk/host/control/dispatch.ts +1 -1
  204. package/src/sdk/host/control/operations.ts +1 -1
  205. package/src/sdk/host/host.ts +2 -6
  206. package/src/sdk/host/query/handlers.ts +70 -5
  207. package/src/sdk/index.ts +12 -0
  208. package/src/sdk/prompt-status.ts +97 -0
  209. package/src/sdk/protocol/operation-inventory.generated.json +58 -0
  210. package/src/sdk/protocol/operation-registry.ts +18 -4
  211. package/src/sdk/session-directory.ts +5 -1
  212. package/src/sdk/session.ts +31 -5
  213. package/src/sdk/startup-capability.ts +9 -1
  214. package/src/sdk/transport/auth-preface.ts +82 -0
  215. package/src/sdk/transport/index.ts +18 -0
  216. package/src/sdk/transport/relay.ts +252 -0
  217. package/src/sdk/transport/serve-cli.ts +105 -0
  218. package/src/sdk/transport/socket.ts +197 -0
  219. package/src/sdk/transport/stdio.ts +17 -0
  220. package/src/session/agent-session.ts +292 -154
  221. package/src/session/blob-store.ts +25 -7
  222. package/src/session/btw-contract.ts +59 -0
  223. package/src/session/internal/managed-session-scope.ts +1163 -137
  224. package/src/session/internal/managed-session-storage.ts +397 -234
  225. package/src/session/internal/native-publish-outcome.ts +266 -0
  226. package/src/session/session-manager.ts +620 -403
  227. package/src/session/session-storage.ts +128 -11
  228. package/src/setup/credential-import.ts +28 -3
  229. package/src/setup/provider-onboarding.ts +30 -1
  230. package/src/setup/provider-presets.json +2 -1
  231. package/src/slash-commands/builtin-registry.ts +1 -1
  232. package/src/ssh/utils.ts +14 -0
  233. package/src/task/discovery.ts +8 -2
  234. package/src/task/gjc-command.ts +2 -2
  235. package/src/task/index.ts +121 -15
  236. package/src/task/receipt.ts +3 -0
  237. package/src/task/types.ts +34 -3
  238. package/src/tools/ask.ts +199 -89
  239. package/src/tools/ast-edit.ts +2 -2
  240. package/src/tools/bash-pty-selection.ts +2 -2
  241. package/src/tools/browser/screenshot-format.ts +6 -1
  242. package/src/tools/cron.ts +1 -1
  243. package/src/tools/fetch.ts +13 -131
  244. package/src/tools/image-gen.ts +476 -23
  245. package/src/tools/index.ts +4 -0
  246. package/src/tools/read.ts +2 -0
  247. package/src/tools/render-utils.ts +7 -1
  248. package/src/tools/skill-discovery.ts +39 -3
  249. package/src/tools/sqlite-reader.ts +63 -5
  250. package/src/utils/edit-mode.ts +2 -2
  251. package/src/utils/pasted-image-path.ts +15 -6
  252. package/src/utils/prompt-suggestion.ts +265 -0
  253. package/src/utils/shell-snapshot.ts +173 -63
  254. package/src/utils/sixel.ts +3 -3
  255. package/src/web/insane/bridge.ts +5 -1
  256. package/src/web/insane/url-guard.ts +140 -27
  257. package/src/web/scrapers/docs-rs.ts +30 -5
  258. package/src/web/scrapers/types.ts +19 -49
  259. package/src/web/scrapers/utils.ts +12 -26
@@ -2,7 +2,7 @@ import { type Model } from "@gajae-code/ai";
2
2
  import * as z from "zod/v4";
3
3
  import { type ModelRegistry } from "../config/model-registry";
4
4
  import type { CustomTool } from "../extensibility/custom-tools/types";
5
- type ImageProvider = "antigravity" | "gemini" | "openai" | "openai-codex" | "openrouter";
5
+ type ImageProvider = "alibaba" | "antigravity" | "gemini" | "openai" | "openai-codex" | "openrouter";
6
6
  declare const responseModalitySchema: z.ZodEnum<{
7
7
  IMAGE: "IMAGE";
8
8
  TEXT: "TEXT";
@@ -55,6 +55,52 @@ interface OpenAIResponsesUsage {
55
55
  total_tokens?: number;
56
56
  }
57
57
  type ImageUsageMetadata = GeminiUsageMetadata | OpenAIResponsesUsage;
58
+ interface AlibabaImageContentPart {
59
+ type?: string;
60
+ text?: string;
61
+ image?: string;
62
+ }
63
+ interface AlibabaImageResponse {
64
+ code?: string;
65
+ message?: string;
66
+ output?: {
67
+ choices?: Array<{
68
+ message?: {
69
+ content?: AlibabaImageContentPart[];
70
+ };
71
+ }>;
72
+ };
73
+ }
74
+ /** Map the tool's image_size values onto wan2.7's 1K/2K size classes. */
75
+ export declare function resolveAlibabaImageSize(imageSize: string | undefined): string | undefined;
76
+ /**
77
+ * Build the Bailian multimodal-generation request body for wan2.7 image
78
+ * generation/editing. Input images ride along as data URLs; generation-only
79
+ * calls send just the prompt text. The sync endpoint returns OSS URLs inline.
80
+ */
81
+ export declare function buildAlibabaImageRequest(model: string, promptText: string, inputImages: InlineImageData[], imageSize: string | undefined): {
82
+ model: string;
83
+ input: {
84
+ messages: Array<{
85
+ role: "user";
86
+ content: Array<{
87
+ text: string;
88
+ } | {
89
+ image: string;
90
+ }>;
91
+ }>;
92
+ };
93
+ parameters: {
94
+ n: number;
95
+ watermark: boolean;
96
+ size?: string;
97
+ };
98
+ };
99
+ /** Collect OSS image URLs and any text parts from a Bailian image response. */
100
+ export declare function collectAlibabaImageResult(response: AlibabaImageResponse): {
101
+ imageUrls: string[];
102
+ responseText?: string;
103
+ };
58
104
  interface ImageGenToolDetails {
59
105
  provider: ImageProvider;
60
106
  model: string;
@@ -72,6 +118,22 @@ interface InlineImageData {
72
118
  }
73
119
  /** Set the preferred image provider from settings */
74
120
  export declare function setPreferredImageProvider(provider: ImageProvider | "auto"): void;
121
+ /** Provider → default image model mapping for auto-binding */
122
+ export declare const IMAGE_PROVIDER_DEFAULTS: Record<string, string>;
123
+ /** Resolved image generation configuration from settings */
124
+ export interface ImageProviderConfig {
125
+ provider: ImageProvider | "auto" | "custom";
126
+ model: string | null;
127
+ customUrl?: string;
128
+ customKey?: string;
129
+ customKeyEnv?: string;
130
+ }
131
+ /** Set the configured image provider + model from settings */
132
+ export declare function setConfiguredImageModel(config: ImageProviderConfig | null): void;
133
+ /** Get the current configured image model (for UI display) */
134
+ export declare function getConfiguredImageModel(): ImageProviderConfig | null;
135
+ /** Resolve the effective image model for a configured provider */
136
+ export declare function resolveImageModel(provider: string, modelOverride: string | null): string;
75
137
  export declare function isOpenAIHostedImageModel(model: Model | undefined): model is Model;
76
138
  export declare const imageGenTool: CustomTool<typeof imageGenSchema, ImageGenToolDetails>;
77
139
  export declare function getImageGenTools(modelRegistry?: ModelRegistry, activeModel?: Model): Promise<Array<CustomTool<typeof imageGenSchema, ImageGenToolDetails>>>;
@@ -82,6 +82,8 @@ export interface AskAnswerRequest {
82
82
  options: string[];
83
83
  interaction: "selector" | "custom_editor" | "clarification_editor";
84
84
  controls: readonly AskRemoteControl[];
85
+ /** Optional zero-based recommendation into the authoritative raw options. */
86
+ recommendedIndex?: number;
85
87
  }
86
88
  export type AskRemoteInteraction = {
87
89
  kind: "value";
@@ -155,6 +157,8 @@ export interface ToolSession {
155
157
  * its terminal-phase chain guard. Returns the raw phase string or undefined
156
158
  * when no active skill (or accessor) is available. */
157
159
  getActiveSkillPhase?: () => string | undefined;
160
+ /** Restrict provider-facing deep-interview ask metadata to the active workflow stage. */
161
+ getDeepInterviewAskStage?: () => "topology" | "post-topology" | undefined;
158
162
  /** Pre-loaded prompt templates */
159
163
  promptTemplates?: PromptTemplate[];
160
164
  /** Whether LSP integrations are enabled */
@@ -15,6 +15,13 @@ export type SkillDiscoveryToolInput = z.infer<typeof skillDiscoverySchema>;
15
15
  export interface SkillDiscoveryToolDetails {
16
16
  candidates: RuntimeSkillDiscoveryCandidate[];
17
17
  count: number;
18
+ /**
19
+ * Present only when zero candidates were returned AND discovery config gates
20
+ * (`skills.enabled` / `skills.enablePiProject` / `skills.enablePiUser`)
21
+ * prevented some or all of the requested scope from being searched. Without
22
+ * this, a disabled config is indistinguishable from "no skills exist".
23
+ */
24
+ notice?: string;
18
25
  }
19
26
  export declare class SkillDiscoveryTool implements AgentTool<typeof skillDiscoverySchema, SkillDiscoveryToolDetails> {
20
27
  #private;
@@ -32,6 +32,13 @@ export type SqliteRowLookup = {
32
32
  } | {
33
33
  kind: "rowid";
34
34
  };
35
+ /**
36
+ * Keep raw reads deliberately narrower than SQLite's full grammar. Comments are
37
+ * rejected, and a statement terminator is accepted only as the final
38
+ * non-whitespace character. Quoted semicolons remain ordinary query data.
39
+ */
40
+ export declare function validateSqliteReadQuery(sql: string): string;
41
+ export declare function enforceSqliteQueryOnly(db: Database): void;
35
42
  export declare function parseSqlitePathCandidates(filePath: string): SqlitePathCandidate[];
36
43
  export declare function isSqliteFile(absolutePath: string): Promise<boolean>;
37
44
  export declare function parseSqliteSelector(subPath: string, queryString: string): SqliteSelector;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Predict the user's likely next prompt after an agent turn using a smol,
3
+ * fast model. Native GJC port of the ghost-text prompt-suggestion behavior
4
+ * from Claude Code: the prediction renders as dim ghost text in the empty
5
+ * composer and Tab accepts it.
6
+ */
7
+ import type { AgentMessage } from "@gajae-code/agent-core";
8
+ import { type Api, type Model } from "@gajae-code/ai";
9
+ import type { ModelRegistry } from "../config/model-registry";
10
+ import type { Settings } from "../config/settings";
11
+ export declare const PROMPT_SUGGESTION_MAX_WORDS = 12;
12
+ export declare const PROMPT_SUGGESTION_MAX_CHARS = 100;
13
+ /**
14
+ * Strip wrapper tags and label prefixes a model sometimes adds despite being
15
+ * told to reply with only the suggestion.
16
+ */
17
+ export declare function sanitizePromptSuggestion(raw: string): string;
18
+ /**
19
+ * Heuristic gate rejecting model output that would make a bad ghost-text
20
+ * suggestion. Returns the rejection reason, or null when the text is usable.
21
+ */
22
+ export declare function suppressPromptSuggestionReason(text: string): string | null;
23
+ /**
24
+ * Build a compact recent-conversation transcript for the prediction request.
25
+ * Returns null when there is no user message to predict from.
26
+ */
27
+ export declare function buildPromptSuggestionContext(messages: AgentMessage[]): string | null;
28
+ /**
29
+ * Generate a predicted next user prompt from the recent conversation.
30
+ * Returns null when no usable suggestion is produced (silence is the
31
+ * expected steady state).
32
+ */
33
+ export declare function generatePromptSuggestion(messages: AgentMessage[], registry: ModelRegistry, settings: Settings, sessionId?: string, currentModel?: Model<Api>, metadataResolver?: (provider: string) => Record<string, unknown> | undefined): Promise<string | null>;
@@ -1,5 +1,17 @@
1
+ interface ShellSnapshotCacheOptions {
2
+ tempRoot: string;
3
+ home: string | (() => string);
4
+ platform: NodeJS.Platform;
5
+ }
6
+ declare function createShellSnapshotCache(options: ShellSnapshotCacheOptions): {
7
+ getOrCreateSnapshot(shell: string, env: Record<string, string | undefined>): Promise<string | null>;
8
+ cleanup(): Promise<void>;
9
+ };
10
+ /** @internal Test-only factory for isolated filesystem and platform assertions. */
11
+ export declare const createShellSnapshotCacheForTesting: typeof createShellSnapshotCache;
1
12
  /**
2
13
  * Create a shell snapshot, caching the result.
3
14
  * Returns the path to the snapshot file, or null if creation failed.
4
15
  */
5
16
  export declare function getOrCreateSnapshot(shell: string, env: Record<string, string | undefined>): Promise<string | null>;
17
+ export {};
@@ -16,6 +16,7 @@ import { spawn as nodeSpawn } from "node:child_process";
16
16
  export declare const INSANE_VENDOR_DIR: string;
17
17
  /** Stable note prefixes — tests assert on these without depending on full stderr. */
18
18
  export declare const INSANE_NOTES: {
19
+ readonly securityDisabled: `insane fallback disabled: remote renderer cannot preserve validated network routing`;
19
20
  readonly guardBlocked: (reason: string) => string;
20
21
  readonly vendorMissing: `insane fallback unavailable: vendor engine missing at packages/coding-agent/vendor/insane-search`;
21
22
  readonly noPython: `insane fallback unavailable: python3 not found; install python3 and curl_cffi, then retry with web.insaneFallback=true`;
@@ -10,6 +10,18 @@ export interface PublicUrlRejected {
10
10
  export type PublicUrlResult = PublicUrlAccepted | PublicUrlRejected;
11
11
  /** Resolver seam so tests can inject DNS results without real lookups. */
12
12
  export type AddressResolver = (hostname: string) => Promise<string[]>;
13
+ type ProxyEnvironment = Record<string, string | undefined>;
14
+ export type GuardedPublicFetchResult = {
15
+ ok: true;
16
+ response: Response;
17
+ logicalUrl: URL;
18
+ wireUrl: URL;
19
+ } | {
20
+ ok: false;
21
+ reason: string;
22
+ logicalUrl: string;
23
+ };
24
+ export declare function hasConfiguredProxy(env: ProxyEnvironment): boolean;
13
25
  /** True for any address that is not a routable public unicast address. */
14
26
  export declare function isPrivateOrSpecialAddress(address: string): boolean;
15
27
  /**
@@ -19,7 +31,12 @@ export declare function isPrivateOrSpecialAddress(address: string): boolean;
19
31
  */
20
32
  export declare function validatePublicHttpUrl(rawUrl: string, options?: {
21
33
  resolver?: AddressResolver;
34
+ signal?: AbortSignal;
22
35
  }): Promise<PublicUrlResult>;
36
+ export declare function guardedPublicFetch(rawUrl: string, init?: BunFetchRequestInit, options?: {
37
+ resolver?: AddressResolver;
38
+ }): Promise<GuardedPublicFetchResult>;
23
39
  export declare function validatePublicHttpUrlForInsane(rawUrl: string, options?: {
24
40
  resolver?: AddressResolver;
25
41
  }): Promise<PublicUrlResult>;
42
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.11.6",
4
+ "version": "0.11.8",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -53,13 +53,13 @@
53
53
  "@agentclientprotocol/sdk": "1.2.1",
54
54
  "@babel/parser": "^7.29.3",
55
55
  "@mozilla/readability": "^0.6.0",
56
- "@gajae-code/stats": "0.11.6",
57
- "@gajae-code/agent-core": "0.11.6",
58
- "@gajae-code/ai": "0.11.6",
59
- "@gajae-code/bridge-client": "0.11.6",
60
- "@gajae-code/natives": "0.11.6",
61
- "@gajae-code/tui": "0.11.6",
62
- "@gajae-code/utils": "0.11.6",
56
+ "@gajae-code/stats": "0.11.8",
57
+ "@gajae-code/agent-core": "0.11.8",
58
+ "@gajae-code/ai": "0.11.8",
59
+ "@gajae-code/bridge-client": "0.11.8",
60
+ "@gajae-code/natives": "0.11.8",
61
+ "@gajae-code/tui": "0.11.8",
62
+ "@gajae-code/utils": "0.11.8",
63
63
  "@puppeteer/browsers": "^2.13.0",
64
64
  "@types/turndown": "5.0.6",
65
65
  "@xterm/headless": "^6.0.0",
@@ -0,0 +1,342 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import {
4
+ PLATFORM_SHORTCUT_LABELS_SHOWCASE_ENTRIES,
5
+ PLATFORM_SHORTCUT_LABELS_SHOWCASE_EXPECTED_ENTRY_COUNT,
6
+ type PlatformShortcutLabelsShowcaseEntry,
7
+ renderPlatformShortcutLabelsShowcase,
8
+ } from "../test/fixtures/tui/platform-shortcut-labels-showcase";
9
+
10
+ const CANONICAL_COMMAND =
11
+ "bun packages/coding-agent/scripts/capture-platform-shortcut-labels-showcase.ts --output .gjc/qa/platform-shortcut-labels";
12
+ const CAPTURE_TOOL_VERSION = "platform-shortcut-labels-fixture-injected-platform-v1";
13
+ const EXPECTED_KEYS = [
14
+ "darwin/composer-idle/80x24/unicode-color",
15
+ "darwin/composer-idle/120x36/unicode-color",
16
+ "darwin/composer-idle/160x48/unicode-color",
17
+ "darwin/composer-busy-effective-queue-remap/80x24/unicode-color",
18
+ "darwin/composer-busy-effective-queue-remap/120x36/unicode-color",
19
+ "darwin/composer-busy-effective-queue-remap/160x48/unicode-color",
20
+ "darwin/status-effective-remap-unbound/80x24/unicode-color",
21
+ "darwin/status-effective-remap-unbound/120x36/unicode-color",
22
+ "darwin/status-effective-remap-unbound/160x48/unicode-color",
23
+ "darwin/welcome-flow/80x24/unicode-color",
24
+ "darwin/welcome-flow/120x36/unicode-color",
25
+ "darwin/welcome-flow/160x48/unicode-color",
26
+ "win32/composer-idle/80x24/unicode-color",
27
+ "win32/composer-idle/120x36/unicode-color",
28
+ "win32/composer-busy-effective-queue-remap/80x24/unicode-color",
29
+ "win32/composer-busy-effective-queue-remap/120x36/unicode-color",
30
+ "win32/status-effective-remap-unbound/80x24/unicode-color",
31
+ "win32/status-effective-remap-unbound/120x36/unicode-color",
32
+ "win32/welcome-flow/80x24/unicode-color",
33
+ "win32/welcome-flow/120x36/unicode-color",
34
+ "linux/composer-idle/80x24/unicode-color",
35
+ "linux/composer-idle/120x36/unicode-color",
36
+ "linux/composer-busy-effective-queue-remap/80x24/unicode-color",
37
+ "linux/composer-busy-effective-queue-remap/120x36/unicode-color",
38
+ "linux/status-effective-remap-unbound/80x24/unicode-color",
39
+ "linux/status-effective-remap-unbound/120x36/unicode-color",
40
+ "linux/welcome-flow/80x24/unicode-color",
41
+ "linux/welcome-flow/120x36/unicode-color",
42
+ "darwin/composer-idle/80x24/ascii-no-color",
43
+ "darwin/composer-busy-effective-queue-remap/80x24/ascii-no-color",
44
+ "darwin/status-effective-remap-unbound/80x24/ascii-no-color",
45
+ "darwin/welcome-flow/80x24/ascii-no-color",
46
+ "darwin/status-effective-remap-unbound/48x36/unicode-color",
47
+ "darwin/welcome-flow/48x36/unicode-color",
48
+ ] as const;
49
+
50
+ type ArtifactFile = { path: string; sha256: string; byte_length: number };
51
+ type ManifestEntry = {
52
+ key: string;
53
+ platform: string;
54
+ surface: string;
55
+ viewport: { id: string; columns: number; rows: number };
56
+ render_mode: string;
57
+ capture_mode: "fixture-injected-platform";
58
+ files: ArtifactFile[];
59
+ };
60
+
61
+ function usage(): never {
62
+ throw new Error(`Usage: ${CANONICAL_COMMAND}`);
63
+ }
64
+ function outputPath(args: string[]): string {
65
+ if (args.length !== 2 || args[0] !== "--output" || !args[1]) usage();
66
+ return args[1];
67
+ }
68
+ function json(value: unknown): string {
69
+ return `${JSON.stringify(value, null, 2)}\n`;
70
+ }
71
+ function sha256(value: string): string {
72
+ return new Bun.CryptoHasher("sha256").update(value).digest("hex");
73
+ }
74
+ function escapeHtml(value: string): string {
75
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
76
+ }
77
+
78
+ type AnsiStyle = {
79
+ foreground?: string;
80
+ background?: string;
81
+ bold?: boolean;
82
+ dim?: boolean;
83
+ italic?: boolean;
84
+ underline?: boolean;
85
+ inverse?: boolean;
86
+ };
87
+
88
+ const ANSI_COLORS: Record<number, string> = {
89
+ 30: "#000000",
90
+ 31: "#cc0000",
91
+ 32: "#4e9a06",
92
+ 33: "#c4a000",
93
+ 34: "#3465a4",
94
+ 35: "#75507b",
95
+ 36: "#06989a",
96
+ 37: "#d3d7cf",
97
+ 90: "#555753",
98
+ 91: "#ef2929",
99
+ 92: "#8ae234",
100
+ 93: "#fce94f",
101
+ 94: "#729fcf",
102
+ 95: "#ad7fa8",
103
+ 96: "#34e2e2",
104
+ 97: "#eeeeec",
105
+ };
106
+
107
+ function ansi256Color(index: number): string {
108
+ if (index < 16) return ANSI_COLORS[index < 8 ? index + 30 : index + 82] ?? "#ffffff";
109
+ if (index >= 232) {
110
+ const value = (index - 232) * 10 + 8;
111
+ return `rgb(${value},${value},${value})`;
112
+ }
113
+ const value = index - 16;
114
+ const red = Math.floor(value / 36);
115
+ const green = Math.floor((value % 36) / 6);
116
+ const blue = value % 6;
117
+ const channel = (component: number) => (component === 0 ? 0 : component * 40 + 55);
118
+ return `rgb(${channel(red)},${channel(green)},${channel(blue)})`;
119
+ }
120
+
121
+ function styleAttribute(style: AnsiStyle): string {
122
+ const declarations: string[] = [];
123
+ if (style.foreground) declarations.push(`color:${style.foreground}`);
124
+ if (style.background) declarations.push(`background-color:${style.background}`);
125
+ if (style.bold) declarations.push("font-weight:700");
126
+ if (style.dim) declarations.push("opacity:.65");
127
+ if (style.italic) declarations.push("font-style:italic");
128
+ if (style.underline) declarations.push("text-decoration:underline");
129
+ if (style.inverse) declarations.push("filter:invert(1)");
130
+ return declarations.join(";");
131
+ }
132
+
133
+ const NON_VISUAL_TERMINAL_CONTROL = /\x1b_[^\x1b\x07]*(?:\x07|\x1b\\)/g;
134
+
135
+ /** Render emitted SGR styles as safe inline CSS without retaining terminal control codes. */
136
+ function ansiToHtml(value: string): string {
137
+ const visibleText = value.replace(NON_VISUAL_TERMINAL_CONTROL, "");
138
+ const sgr = /\x1b\[([0-9;]*)m/g;
139
+ let body = "";
140
+ let offset = 0;
141
+ let spanOpen = false;
142
+ let style: AnsiStyle = {};
143
+ const close = () => {
144
+ if (!spanOpen) return;
145
+ body += "</span>";
146
+ spanOpen = false;
147
+ };
148
+ const open = () => {
149
+ const attribute = styleAttribute(style);
150
+ if (!attribute) return;
151
+ body += `<span style="${attribute}">`;
152
+ spanOpen = true;
153
+ };
154
+
155
+ for (const match of visibleText.matchAll(sgr)) {
156
+ body += escapeHtml(visibleText.slice(offset, match.index));
157
+ offset = (match.index ?? 0) + match[0].length;
158
+ close();
159
+ const codes = (match[1] || "0").split(";").map(Number);
160
+ for (let index = 0; index < codes.length; index += 1) {
161
+ const code = codes[index];
162
+ if (code === 0) style = {};
163
+ else if (code === 1) style.bold = true;
164
+ else if (code === 2) style.dim = true;
165
+ else if (code === 3) style.italic = true;
166
+ else if (code === 4) style.underline = true;
167
+ else if (code === 7) style.inverse = true;
168
+ else if (code === 22) {
169
+ style.bold = false;
170
+ style.dim = false;
171
+ } else if (code === 23) style.italic = false;
172
+ else if (code === 24) style.underline = false;
173
+ else if (code === 27) style.inverse = false;
174
+ else if (code === 39) style.foreground = undefined;
175
+ else if (code === 49) style.background = undefined;
176
+ else if (code in ANSI_COLORS) style.foreground = ANSI_COLORS[code];
177
+ else if (code >= 40 && code <= 47) style.background = ANSI_COLORS[code - 10];
178
+ else if (code >= 100 && code <= 107) style.background = ANSI_COLORS[code - 10];
179
+ else if (code === 38 || code === 48) {
180
+ const colorMode = codes[index + 1];
181
+ if (colorMode === 2) {
182
+ const red = codes[index + 2];
183
+ const green = codes[index + 3];
184
+ const blue = codes[index + 4];
185
+ if ([red, green, blue].every(Number.isInteger)) {
186
+ if (code === 38) style.foreground = `rgb(${red},${green},${blue})`;
187
+ else style.background = `rgb(${red},${green},${blue})`;
188
+ }
189
+ index += 4;
190
+ } else if (colorMode === 5 && Number.isInteger(codes[index + 2])) {
191
+ if (code === 38) style.foreground = ansi256Color(codes[index + 2]!);
192
+ else style.background = ansi256Color(codes[index + 2]!);
193
+ index += 2;
194
+ }
195
+ }
196
+ }
197
+ open();
198
+ }
199
+ body += escapeHtml(visibleText.slice(offset));
200
+ close();
201
+ return `<!doctype html>\n<html lang="en"><head><meta charset="utf-8"><meta name="color-scheme" content="dark"><title>Platform shortcut labels showcase</title><style>body{margin:0;background:#110b0b;color:#ffe7dc;overflow:auto}pre{margin:0;padding:1em;white-space:pre;font-family:ui-monospace,monospace;line-height:1.2}</style></head><body><pre>${body}</pre></body></html>\n`;
202
+ }
203
+ function validateMatrix(entries: readonly PlatformShortcutLabelsShowcaseEntry[]): void {
204
+ if (PLATFORM_SHORTCUT_LABELS_SHOWCASE_EXPECTED_ENTRY_COUNT !== 34)
205
+ throw new Error("Expected showcase entry count must remain 34");
206
+ if (entries.length !== PLATFORM_SHORTCUT_LABELS_SHOWCASE_EXPECTED_ENTRY_COUNT)
207
+ throw new Error(`Showcase matrix changed: expected 34 entries, received ${entries.length}`);
208
+ const actual = entries.map(entry => entry.key);
209
+ if (new Set(actual).size !== actual.length) throw new Error("Showcase matrix contains duplicate entry keys");
210
+ const expected = new Set<string>(EXPECTED_KEYS);
211
+ const missing = EXPECTED_KEYS.filter(key => !actual.includes(key));
212
+ const surplus = actual.filter(key => !expected.has(key));
213
+ if (missing.length || surplus.length || actual.some((key, index) => key !== EXPECTED_KEYS[index]))
214
+ throw new Error(
215
+ `Showcase matrix keys differ; missing=${missing.join(",") || "none"}; surplus=${surplus.join(",") || "none"}`,
216
+ );
217
+ }
218
+ async function writeArtifact(filePath: string, content: string, outputRoot: string): Promise<ArtifactFile> {
219
+ await Bun.write(filePath, content);
220
+ return {
221
+ path: path.relative(outputRoot, filePath).split(path.sep).join("/"),
222
+ sha256: sha256(content),
223
+ byte_length: Buffer.byteLength(content, "utf8"),
224
+ };
225
+ }
226
+ async function captureEntry(
227
+ entry: PlatformShortcutLabelsShowcaseEntry,
228
+ outputRoot: string,
229
+ capturedAt: string,
230
+ ): Promise<ManifestEntry> {
231
+ const rendered = await renderPlatformShortcutLabelsShowcase(entry);
232
+ const directory = path.join(outputRoot, entry.platform, entry.surface, entry.viewport.id, entry.renderMode);
233
+ await fs.mkdir(directory, { recursive: true });
234
+ const html = ansiToHtml(rendered.terminalAnsiText);
235
+ const metadata = json({
236
+ schema_version: 1,
237
+ entry_key: entry.key,
238
+ platform: entry.platform,
239
+ viewport: entry.viewport,
240
+ render_mode: entry.renderMode,
241
+ capture_mode: rendered.captureMode,
242
+ platform_provenance: rendered.platformProvenance,
243
+ key_display_context: rendered.keyDisplayContext,
244
+ components: rendered.components,
245
+ capture_timestamp: capturedAt,
246
+ command_or_replay_source: CANONICAL_COMMAND,
247
+ fixture_source: "packages/coding-agent/test/fixtures/tui/platform-shortcut-labels-showcase.ts",
248
+ tool_version: CAPTURE_TOOL_VERSION,
249
+ terminal: {
250
+ columns: entry.viewport.columns,
251
+ rows: entry.viewport.rows,
252
+ font_rendering_assumptions:
253
+ "Embedded red-claw truecolor theme; HTML uses a monospace terminal fallback stack.",
254
+ wrapping_policy:
255
+ "Real components render at the recorded terminal-cell width; CJK content is retained for width review.",
256
+ ansi_control_semantics:
257
+ "terminal-ansi.txt preserves emitted SGR sequences; terminal.txt strips them; ascii-no-color strips styling only.",
258
+ },
259
+ provenance: {
260
+ platform: "fixture-injected-platform",
261
+ live_capture: false,
262
+ native_platform_claim: entry.platform === "darwin" ? "none (fixture only)" : "none",
263
+ },
264
+ fixed_clock_timestamp: rendered.fixedClockTimestamp,
265
+ });
266
+ const files = await Promise.all([
267
+ writeArtifact(path.join(directory, "terminal.txt"), rendered.terminalText, outputRoot),
268
+ writeArtifact(path.join(directory, "terminal-ansi.txt"), rendered.terminalAnsiText, outputRoot),
269
+ writeArtifact(path.join(directory, "terminal.html"), html, outputRoot),
270
+ writeArtifact(path.join(directory, "metadata.json"), metadata, outputRoot),
271
+ ]);
272
+ return {
273
+ key: entry.key,
274
+ platform: entry.platform,
275
+ surface: entry.surface,
276
+ viewport: entry.viewport,
277
+ render_mode: entry.renderMode,
278
+ capture_mode: rendered.captureMode,
279
+ files,
280
+ };
281
+ }
282
+ async function main(): Promise<void> {
283
+ const root = path.resolve(outputPath(process.argv.slice(2)));
284
+ const capturedAt = new Date().toISOString();
285
+ validateMatrix(PLATFORM_SHORTCUT_LABELS_SHOWCASE_ENTRIES);
286
+ await fs.mkdir(root, { recursive: true });
287
+ const entries: ManifestEntry[] = [];
288
+ for (const entry of PLATFORM_SHORTCUT_LABELS_SHOWCASE_ENTRIES)
289
+ entries.push(await captureEntry(entry, root, capturedAt));
290
+ const manifest = json({
291
+ schema_version: 1,
292
+ capture_tool: CAPTURE_TOOL_VERSION,
293
+ capture_mode: "fixture-injected-platform",
294
+ command: CANONICAL_COMMAND,
295
+ capture_timestamp: capturedAt,
296
+ expected_entry_count: 34,
297
+ entry_count: entries.length,
298
+ ordered_keys: EXPECTED_KEYS,
299
+ provenance: "fixture-injected-platform",
300
+ review_input_file: "visual-review-input.json",
301
+ entries,
302
+ });
303
+ const manifestSha256 = sha256(manifest);
304
+ await Bun.write(path.join(root, "manifest.json"), manifest);
305
+ await Bun.write(
306
+ path.join(root, "visual-review-input.json"),
307
+ json({
308
+ schema_version: 1,
309
+ manifest_sha256: manifestSha256,
310
+ expected_manifest_entries: 34,
311
+ ordered_keys: EXPECTED_KEYS,
312
+ evidence_scope: {
313
+ component_surface: "Real CustomEditor, StatusLineComponent, and WelcomeComponent rendering.",
314
+ operations_boundary: "Fixed clock, in-memory settings, and explicit injected KeyDisplayContext platform.",
315
+ external_effects: "No network, filesystem settings, daemon, or live native platform capture is invoked.",
316
+ },
317
+ review_requirements: [
318
+ "Inspect every recorded key.",
319
+ "Confirm Darwin glyphs and ASCII/no-color variants retain the same labels.",
320
+ "Confirm CJK and terminal-cell width evidence in both 48x36 entries.",
321
+ "Confirm all platform provenance is fixture-injected-platform.",
322
+ ],
323
+ required_feature_cases: [
324
+ {
325
+ id: "darwin-composer",
326
+ entry_key: "darwin/composer-idle/80x24/unicode-color",
327
+ focus: "Darwin modifier and Enter glyph labels.",
328
+ },
329
+ {
330
+ id: "effective-remap",
331
+ entry_key: "darwin/status-effective-remap-unbound/80x24/unicode-color",
332
+ focus: "Effective remap and unbound action labels.",
333
+ },
334
+ { id: "cjk-width", entry_key: "darwin/welcome-flow/48x36/unicode-color", focus: "CJK width and wrapping." },
335
+ ],
336
+ }),
337
+ );
338
+ process.stdout.write(
339
+ `Captured ${entries.length} deterministic platform shortcut showcase entries to ${root}\nmanifest.json sha256: ${manifestSha256}\n`,
340
+ );
341
+ }
342
+ await main();