indusagi-coding-agent 0.1.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 (240) hide show
  1. package/CHANGELOG.md +2249 -0
  2. package/README.md +546 -0
  3. package/dist/cli/args.js +282 -0
  4. package/dist/cli/config-selector.js +30 -0
  5. package/dist/cli/file-processor.js +78 -0
  6. package/dist/cli/list-models.js +91 -0
  7. package/dist/cli/session-picker.js +31 -0
  8. package/dist/cli.js +10 -0
  9. package/dist/config.js +158 -0
  10. package/dist/core/agent-session.js +2097 -0
  11. package/dist/core/auth-storage.js +278 -0
  12. package/dist/core/bash-executor.js +211 -0
  13. package/dist/core/compaction/branch-summarization.js +241 -0
  14. package/dist/core/compaction/compaction.js +606 -0
  15. package/dist/core/compaction/index.js +6 -0
  16. package/dist/core/compaction/utils.js +137 -0
  17. package/dist/core/diagnostics.js +1 -0
  18. package/dist/core/event-bus.js +24 -0
  19. package/dist/core/exec.js +70 -0
  20. package/dist/core/export-html/ansi-to-html.js +248 -0
  21. package/dist/core/export-html/index.js +221 -0
  22. package/dist/core/export-html/template.css +905 -0
  23. package/dist/core/export-html/template.html +54 -0
  24. package/dist/core/export-html/template.js +1549 -0
  25. package/dist/core/export-html/tool-renderer.js +56 -0
  26. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  27. package/dist/core/export-html/vendor/marked.min.js +6 -0
  28. package/dist/core/extensions/index.js +8 -0
  29. package/dist/core/extensions/loader.js +395 -0
  30. package/dist/core/extensions/runner.js +499 -0
  31. package/dist/core/extensions/types.js +31 -0
  32. package/dist/core/extensions/wrapper.js +101 -0
  33. package/dist/core/footer-data-provider.js +133 -0
  34. package/dist/core/index.js +8 -0
  35. package/dist/core/keybindings.js +140 -0
  36. package/dist/core/messages.js +122 -0
  37. package/dist/core/model-registry.js +454 -0
  38. package/dist/core/model-resolver.js +309 -0
  39. package/dist/core/package-manager.js +1142 -0
  40. package/dist/core/prompt-templates.js +250 -0
  41. package/dist/core/resource-loader.js +569 -0
  42. package/dist/core/sdk.js +225 -0
  43. package/dist/core/session-manager.js +1078 -0
  44. package/dist/core/settings-manager.js +430 -0
  45. package/dist/core/skills.js +339 -0
  46. package/dist/core/system-prompt.js +136 -0
  47. package/dist/core/timings.js +24 -0
  48. package/dist/core/tools/bash.js +226 -0
  49. package/dist/core/tools/edit-diff.js +242 -0
  50. package/dist/core/tools/edit.js +145 -0
  51. package/dist/core/tools/find.js +205 -0
  52. package/dist/core/tools/grep.js +238 -0
  53. package/dist/core/tools/index.js +60 -0
  54. package/dist/core/tools/ls.js +117 -0
  55. package/dist/core/tools/path-utils.js +52 -0
  56. package/dist/core/tools/read.js +165 -0
  57. package/dist/core/tools/truncate.js +204 -0
  58. package/dist/core/tools/write.js +77 -0
  59. package/dist/index.js +41 -0
  60. package/dist/main.js +565 -0
  61. package/dist/migrations.js +260 -0
  62. package/dist/modes/index.js +7 -0
  63. package/dist/modes/interactive/components/armin.js +328 -0
  64. package/dist/modes/interactive/components/assistant-message.js +86 -0
  65. package/dist/modes/interactive/components/bash-execution.js +155 -0
  66. package/dist/modes/interactive/components/bordered-loader.js +47 -0
  67. package/dist/modes/interactive/components/branch-summary-message.js +41 -0
  68. package/dist/modes/interactive/components/compaction-summary-message.js +42 -0
  69. package/dist/modes/interactive/components/config-selector.js +458 -0
  70. package/dist/modes/interactive/components/countdown-timer.js +27 -0
  71. package/dist/modes/interactive/components/custom-editor.js +61 -0
  72. package/dist/modes/interactive/components/custom-message.js +80 -0
  73. package/dist/modes/interactive/components/diff.js +132 -0
  74. package/dist/modes/interactive/components/dynamic-border.js +19 -0
  75. package/dist/modes/interactive/components/extension-editor.js +96 -0
  76. package/dist/modes/interactive/components/extension-input.js +54 -0
  77. package/dist/modes/interactive/components/extension-selector.js +70 -0
  78. package/dist/modes/interactive/components/footer.js +213 -0
  79. package/dist/modes/interactive/components/index.js +31 -0
  80. package/dist/modes/interactive/components/keybinding-hints.js +60 -0
  81. package/dist/modes/interactive/components/login-dialog.js +138 -0
  82. package/dist/modes/interactive/components/model-selector.js +253 -0
  83. package/dist/modes/interactive/components/oauth-selector.js +91 -0
  84. package/dist/modes/interactive/components/scoped-models-selector.js +262 -0
  85. package/dist/modes/interactive/components/session-selector-search.js +145 -0
  86. package/dist/modes/interactive/components/session-selector.js +698 -0
  87. package/dist/modes/interactive/components/settings-selector.js +250 -0
  88. package/dist/modes/interactive/components/show-images-selector.js +33 -0
  89. package/dist/modes/interactive/components/skill-invocation-message.js +44 -0
  90. package/dist/modes/interactive/components/theme-selector.js +43 -0
  91. package/dist/modes/interactive/components/thinking-selector.js +45 -0
  92. package/dist/modes/interactive/components/tool-execution.js +608 -0
  93. package/dist/modes/interactive/components/tree-selector.js +892 -0
  94. package/dist/modes/interactive/components/user-message-selector.js +109 -0
  95. package/dist/modes/interactive/components/user-message.js +15 -0
  96. package/dist/modes/interactive/components/visual-truncate.js +32 -0
  97. package/dist/modes/interactive/interactive-mode.js +3576 -0
  98. package/dist/modes/interactive/theme/dark.json +85 -0
  99. package/dist/modes/interactive/theme/light.json +84 -0
  100. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  101. package/dist/modes/interactive/theme/theme.js +938 -0
  102. package/dist/modes/print-mode.js +96 -0
  103. package/dist/modes/rpc/rpc-client.js +390 -0
  104. package/dist/modes/rpc/rpc-mode.js +448 -0
  105. package/dist/modes/rpc/rpc-types.js +7 -0
  106. package/dist/utils/changelog.js +86 -0
  107. package/dist/utils/clipboard-image.js +116 -0
  108. package/dist/utils/clipboard.js +58 -0
  109. package/dist/utils/frontmatter.js +25 -0
  110. package/dist/utils/git.js +5 -0
  111. package/dist/utils/image-convert.js +34 -0
  112. package/dist/utils/image-resize.js +180 -0
  113. package/dist/utils/mime.js +25 -0
  114. package/dist/utils/photon.js +120 -0
  115. package/dist/utils/shell.js +164 -0
  116. package/dist/utils/sleep.js +16 -0
  117. package/dist/utils/tools-manager.js +186 -0
  118. package/docs/compaction.md +390 -0
  119. package/docs/custom-provider.md +538 -0
  120. package/docs/development.md +69 -0
  121. package/docs/extensions.md +1733 -0
  122. package/docs/images/doom-extension.png +0 -0
  123. package/docs/images/interactive-mode.png +0 -0
  124. package/docs/images/tree-view.png +0 -0
  125. package/docs/json.md +79 -0
  126. package/docs/keybindings.md +162 -0
  127. package/docs/models.md +193 -0
  128. package/docs/packages.md +163 -0
  129. package/docs/prompt-templates.md +67 -0
  130. package/docs/providers.md +147 -0
  131. package/docs/rpc.md +1048 -0
  132. package/docs/sdk.md +957 -0
  133. package/docs/session.md +412 -0
  134. package/docs/settings.md +216 -0
  135. package/docs/shell-aliases.md +13 -0
  136. package/docs/skills.md +226 -0
  137. package/docs/terminal-setup.md +65 -0
  138. package/docs/themes.md +295 -0
  139. package/docs/tree.md +219 -0
  140. package/docs/tui.md +887 -0
  141. package/docs/windows.md +17 -0
  142. package/examples/README.md +25 -0
  143. package/examples/extensions/README.md +192 -0
  144. package/examples/extensions/antigravity-image-gen.ts +414 -0
  145. package/examples/extensions/auto-commit-on-exit.ts +49 -0
  146. package/examples/extensions/bookmark.ts +50 -0
  147. package/examples/extensions/claude-rules.ts +86 -0
  148. package/examples/extensions/confirm-destructive.ts +59 -0
  149. package/examples/extensions/custom-compaction.ts +115 -0
  150. package/examples/extensions/custom-footer.ts +65 -0
  151. package/examples/extensions/custom-header.ts +73 -0
  152. package/examples/extensions/custom-provider-anthropic/index.ts +605 -0
  153. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  154. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  155. package/examples/extensions/custom-provider-gitlab-duo/index.ts +350 -0
  156. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  157. package/examples/extensions/custom-provider-gitlab-duo/test.ts +83 -0
  158. package/examples/extensions/dirty-repo-guard.ts +56 -0
  159. package/examples/extensions/doom-overlay/README.md +46 -0
  160. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  161. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  162. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  163. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  164. package/examples/extensions/doom-overlay/doom-component.ts +133 -0
  165. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  166. package/examples/extensions/doom-overlay/doom-keys.ts +105 -0
  167. package/examples/extensions/doom-overlay/index.ts +74 -0
  168. package/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  169. package/examples/extensions/event-bus.ts +43 -0
  170. package/examples/extensions/file-trigger.ts +41 -0
  171. package/examples/extensions/git-checkpoint.ts +53 -0
  172. package/examples/extensions/handoff.ts +151 -0
  173. package/examples/extensions/hello.ts +25 -0
  174. package/examples/extensions/inline-bash.ts +94 -0
  175. package/examples/extensions/input-transform.ts +43 -0
  176. package/examples/extensions/interactive-shell.ts +196 -0
  177. package/examples/extensions/mac-system-theme.ts +47 -0
  178. package/examples/extensions/message-renderer.ts +60 -0
  179. package/examples/extensions/modal-editor.ts +86 -0
  180. package/examples/extensions/model-status.ts +31 -0
  181. package/examples/extensions/notify.ts +25 -0
  182. package/examples/extensions/overlay-qa-tests.ts +882 -0
  183. package/examples/extensions/overlay-test.ts +151 -0
  184. package/examples/extensions/permission-gate.ts +34 -0
  185. package/examples/extensions/pirate.ts +47 -0
  186. package/examples/extensions/plan-mode/README.md +65 -0
  187. package/examples/extensions/plan-mode/index.ts +341 -0
  188. package/examples/extensions/plan-mode/utils.ts +168 -0
  189. package/examples/extensions/preset.ts +399 -0
  190. package/examples/extensions/protected-paths.ts +30 -0
  191. package/examples/extensions/qna.ts +120 -0
  192. package/examples/extensions/question.ts +265 -0
  193. package/examples/extensions/questionnaire.ts +428 -0
  194. package/examples/extensions/rainbow-editor.ts +88 -0
  195. package/examples/extensions/sandbox/index.ts +318 -0
  196. package/examples/extensions/sandbox/package-lock.json +92 -0
  197. package/examples/extensions/sandbox/package.json +19 -0
  198. package/examples/extensions/send-user-message.ts +97 -0
  199. package/examples/extensions/session-name.ts +27 -0
  200. package/examples/extensions/shutdown-command.ts +63 -0
  201. package/examples/extensions/snake.ts +344 -0
  202. package/examples/extensions/space-invaders.ts +561 -0
  203. package/examples/extensions/ssh.ts +220 -0
  204. package/examples/extensions/status-line.ts +40 -0
  205. package/examples/extensions/subagent/README.md +172 -0
  206. package/examples/extensions/subagent/agents/planner.md +37 -0
  207. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  208. package/examples/extensions/subagent/agents/scout.md +50 -0
  209. package/examples/extensions/subagent/agents/worker.md +24 -0
  210. package/examples/extensions/subagent/agents.ts +127 -0
  211. package/examples/extensions/subagent/index.ts +964 -0
  212. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  213. package/examples/extensions/subagent/prompts/implement.md +10 -0
  214. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  215. package/examples/extensions/summarize.ts +196 -0
  216. package/examples/extensions/timed-confirm.ts +70 -0
  217. package/examples/extensions/todo.ts +300 -0
  218. package/examples/extensions/tool-override.ts +144 -0
  219. package/examples/extensions/tools.ts +147 -0
  220. package/examples/extensions/trigger-compact.ts +40 -0
  221. package/examples/extensions/truncated-tool.ts +193 -0
  222. package/examples/extensions/widget-placement.ts +17 -0
  223. package/examples/extensions/with-deps/index.ts +36 -0
  224. package/examples/extensions/with-deps/package-lock.json +31 -0
  225. package/examples/extensions/with-deps/package.json +22 -0
  226. package/examples/sdk/01-minimal.ts +22 -0
  227. package/examples/sdk/02-custom-model.ts +50 -0
  228. package/examples/sdk/03-custom-prompt.ts +55 -0
  229. package/examples/sdk/04-skills.ts +46 -0
  230. package/examples/sdk/05-tools.ts +56 -0
  231. package/examples/sdk/06-extensions.ts +88 -0
  232. package/examples/sdk/07-context-files.ts +40 -0
  233. package/examples/sdk/08-prompt-templates.ts +47 -0
  234. package/examples/sdk/09-api-keys-and-oauth.ts +48 -0
  235. package/examples/sdk/10-settings.ts +38 -0
  236. package/examples/sdk/11-sessions.ts +48 -0
  237. package/examples/sdk/12-full-control.ts +82 -0
  238. package/examples/sdk/13-codex-oauth.ts +37 -0
  239. package/examples/sdk/README.md +144 -0
  240. package/package.json +85 -0
@@ -0,0 +1,133 @@
1
+ import { existsSync, readFileSync, statSync, watch } from "fs";
2
+ import { dirname, join, resolve } from "path";
3
+ /**
4
+ * Find the git HEAD path by walking up from cwd.
5
+ * Handles both regular git repos (.git is a directory) and worktrees (.git is a file).
6
+ */
7
+ function findGitHeadPath() {
8
+ let dir = process.cwd();
9
+ while (true) {
10
+ const gitPath = join(dir, ".git");
11
+ if (existsSync(gitPath)) {
12
+ try {
13
+ const stat = statSync(gitPath);
14
+ if (stat.isFile()) {
15
+ const content = readFileSync(gitPath, "utf8").trim();
16
+ if (content.startsWith("gitdir: ")) {
17
+ const gitDir = content.slice(8);
18
+ const headPath = resolve(dir, gitDir, "HEAD");
19
+ if (existsSync(headPath))
20
+ return headPath;
21
+ }
22
+ }
23
+ else if (stat.isDirectory()) {
24
+ const headPath = join(gitPath, "HEAD");
25
+ if (existsSync(headPath))
26
+ return headPath;
27
+ }
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ const parent = dirname(dir);
34
+ if (parent === dir)
35
+ return null;
36
+ dir = parent;
37
+ }
38
+ }
39
+ /**
40
+ * Provides git branch and extension statuses - data not otherwise accessible to extensions.
41
+ * Token stats, model info available via ctx.sessionManager and ctx.model.
42
+ */
43
+ export class FooterDataProvider {
44
+ constructor() {
45
+ this.extensionStatuses = new Map();
46
+ this.cachedBranch = undefined;
47
+ this.gitWatcher = null;
48
+ this.branchChangeCallbacks = new Set();
49
+ this.availableProviderCount = 0;
50
+ this.setupGitWatcher();
51
+ }
52
+ /** Current git branch, null if not in repo, "detached" if detached HEAD */
53
+ getGitBranch() {
54
+ if (this.cachedBranch !== undefined)
55
+ return this.cachedBranch;
56
+ try {
57
+ const gitHeadPath = findGitHeadPath();
58
+ if (!gitHeadPath) {
59
+ this.cachedBranch = null;
60
+ return null;
61
+ }
62
+ const content = readFileSync(gitHeadPath, "utf8").trim();
63
+ this.cachedBranch = content.startsWith("ref: refs/heads/") ? content.slice(16) : "detached";
64
+ }
65
+ catch {
66
+ this.cachedBranch = null;
67
+ }
68
+ return this.cachedBranch;
69
+ }
70
+ /** Extension status texts set via ctx.ui.setStatus() */
71
+ getExtensionStatuses() {
72
+ return this.extensionStatuses;
73
+ }
74
+ /** Subscribe to git branch changes. Returns unsubscribe function. */
75
+ onBranchChange(callback) {
76
+ this.branchChangeCallbacks.add(callback);
77
+ return () => this.branchChangeCallbacks.delete(callback);
78
+ }
79
+ /** Internal: set extension status */
80
+ setExtensionStatus(key, text) {
81
+ if (text === undefined) {
82
+ this.extensionStatuses.delete(key);
83
+ }
84
+ else {
85
+ this.extensionStatuses.set(key, text);
86
+ }
87
+ }
88
+ /** Internal: clear extension statuses */
89
+ clearExtensionStatuses() {
90
+ this.extensionStatuses.clear();
91
+ }
92
+ /** Number of unique providers with available models (for footer display) */
93
+ getAvailableProviderCount() {
94
+ return this.availableProviderCount;
95
+ }
96
+ /** Internal: update available provider count */
97
+ setAvailableProviderCount(count) {
98
+ this.availableProviderCount = count;
99
+ }
100
+ /** Internal: cleanup */
101
+ dispose() {
102
+ if (this.gitWatcher) {
103
+ this.gitWatcher.close();
104
+ this.gitWatcher = null;
105
+ }
106
+ this.branchChangeCallbacks.clear();
107
+ }
108
+ setupGitWatcher() {
109
+ if (this.gitWatcher) {
110
+ this.gitWatcher.close();
111
+ this.gitWatcher = null;
112
+ }
113
+ const gitHeadPath = findGitHeadPath();
114
+ if (!gitHeadPath)
115
+ return;
116
+ // Watch the directory containing HEAD, not HEAD itself.
117
+ // Git uses atomic writes (write temp, rename over HEAD), which changes the inode.
118
+ // fs.watch on a file stops working after the inode changes.
119
+ const gitDir = dirname(gitHeadPath);
120
+ try {
121
+ this.gitWatcher = watch(gitDir, (_eventType, filename) => {
122
+ if (filename === "HEAD") {
123
+ this.cachedBranch = undefined;
124
+ for (const cb of this.branchChangeCallbacks)
125
+ cb();
126
+ }
127
+ });
128
+ }
129
+ catch {
130
+ // Silently fail if we can't watch
131
+ }
132
+ }
133
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Core modules shared between all run modes.
3
+ */
4
+ export { AgentSession, } from "./agent-session.js";
5
+ export { executeBash, executeBashWithOperations } from "./bash-executor.js";
6
+ export { createEventBus } from "./event-bus.js";
7
+ // Extensions system
8
+ export { discoverAndLoadExtensions, ExtensionRunner, wrapToolsWithExtensions, } from "./extensions/index.js";
@@ -0,0 +1,140 @@
1
+ import { DEFAULT_EDITOR_KEYBINDINGS, EditorKeybindingsManager, matchesKey, setEditorKeybindings, } from "indusagi/tui";
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { join } from "path";
4
+ import { getAgentDir } from "../config.js";
5
+ /**
6
+ * Default application keybindings.
7
+ */
8
+ export const DEFAULT_APP_KEYBINDINGS = {
9
+ interrupt: "escape",
10
+ clear: "ctrl+c",
11
+ exit: "ctrl+d",
12
+ suspend: "ctrl+z",
13
+ cycleThinkingLevel: "shift+tab",
14
+ cycleModelForward: "ctrl+p",
15
+ cycleModelBackward: "shift+ctrl+p",
16
+ selectModel: "ctrl+l",
17
+ expandTools: "ctrl+o",
18
+ toggleThinking: "ctrl+t",
19
+ externalEditor: "ctrl+g",
20
+ followUp: "alt+enter",
21
+ dequeue: "alt+up",
22
+ pasteImage: "ctrl+v",
23
+ };
24
+ /**
25
+ * All default keybindings (app + editor).
26
+ */
27
+ export const DEFAULT_KEYBINDINGS = {
28
+ ...DEFAULT_EDITOR_KEYBINDINGS,
29
+ ...DEFAULT_APP_KEYBINDINGS,
30
+ };
31
+ // App actions list for type checking
32
+ const APP_ACTIONS = [
33
+ "interrupt",
34
+ "clear",
35
+ "exit",
36
+ "suspend",
37
+ "cycleThinkingLevel",
38
+ "cycleModelForward",
39
+ "cycleModelBackward",
40
+ "selectModel",
41
+ "expandTools",
42
+ "toggleThinking",
43
+ "externalEditor",
44
+ "followUp",
45
+ "dequeue",
46
+ "pasteImage",
47
+ ];
48
+ function isAppAction(action) {
49
+ return APP_ACTIONS.includes(action);
50
+ }
51
+ /**
52
+ * Manages all keybindings (app + editor).
53
+ */
54
+ export class KeybindingsManager {
55
+ constructor(config) {
56
+ this.config = config;
57
+ this.appActionToKeys = new Map();
58
+ this.buildMaps();
59
+ }
60
+ /**
61
+ * Create from config file and set up editor keybindings.
62
+ */
63
+ static create(agentDir = getAgentDir()) {
64
+ const configPath = join(agentDir, "keybindings.json");
65
+ const config = KeybindingsManager.loadFromFile(configPath);
66
+ const manager = new KeybindingsManager(config);
67
+ // Set up editor keybindings globally
68
+ // Include both editor actions and expandTools (shared between app and editor)
69
+ const editorConfig = {};
70
+ for (const [action, keys] of Object.entries(config)) {
71
+ if (!isAppAction(action) || action === "expandTools") {
72
+ editorConfig[action] = keys;
73
+ }
74
+ }
75
+ setEditorKeybindings(new EditorKeybindingsManager(editorConfig));
76
+ return manager;
77
+ }
78
+ /**
79
+ * Create in-memory.
80
+ */
81
+ static inMemory(config = {}) {
82
+ return new KeybindingsManager(config);
83
+ }
84
+ static loadFromFile(path) {
85
+ if (!existsSync(path))
86
+ return {};
87
+ try {
88
+ return JSON.parse(readFileSync(path, "utf-8"));
89
+ }
90
+ catch {
91
+ return {};
92
+ }
93
+ }
94
+ buildMaps() {
95
+ this.appActionToKeys.clear();
96
+ // Set defaults for app actions
97
+ for (const [action, keys] of Object.entries(DEFAULT_APP_KEYBINDINGS)) {
98
+ const keyArray = Array.isArray(keys) ? keys : [keys];
99
+ this.appActionToKeys.set(action, [...keyArray]);
100
+ }
101
+ // Override with user config (app actions only)
102
+ for (const [action, keys] of Object.entries(this.config)) {
103
+ if (keys === undefined || !isAppAction(action))
104
+ continue;
105
+ const keyArray = Array.isArray(keys) ? keys : [keys];
106
+ this.appActionToKeys.set(action, keyArray);
107
+ }
108
+ }
109
+ /**
110
+ * Check if input matches an app action.
111
+ */
112
+ matches(data, action) {
113
+ const keys = this.appActionToKeys.get(action);
114
+ if (!keys)
115
+ return false;
116
+ for (const key of keys) {
117
+ if (matchesKey(data, key))
118
+ return true;
119
+ }
120
+ return false;
121
+ }
122
+ /**
123
+ * Get keys bound to an app action.
124
+ */
125
+ getKeys(action) {
126
+ return this.appActionToKeys.get(action) ?? [];
127
+ }
128
+ /**
129
+ * Get the full effective config.
130
+ */
131
+ getEffectiveConfig() {
132
+ const result = { ...DEFAULT_KEYBINDINGS };
133
+ for (const [action, keys] of Object.entries(this.config)) {
134
+ if (keys !== undefined) {
135
+ result[action] = keys;
136
+ }
137
+ }
138
+ return result;
139
+ }
140
+ }
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Custom message types and transformers for the coding agent.
3
+ *
4
+ * Extends the base AgentMessage type with coding-agent specific message types,
5
+ * and provides a transformer to convert them to LLM-compatible messages.
6
+ */
7
+ export const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:
8
+
9
+ <summary>
10
+ `;
11
+ export const COMPACTION_SUMMARY_SUFFIX = `
12
+ </summary>`;
13
+ export const BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:
14
+
15
+ <summary>
16
+ `;
17
+ export const BRANCH_SUMMARY_SUFFIX = `</summary>`;
18
+ /**
19
+ * Convert a BashExecutionMessage to user message text for LLM context.
20
+ */
21
+ export function bashExecutionToText(msg) {
22
+ let text = `Ran \`${msg.command}\`\n`;
23
+ if (msg.output) {
24
+ text += `\`\`\`\n${msg.output}\n\`\`\``;
25
+ }
26
+ else {
27
+ text += "(no output)";
28
+ }
29
+ if (msg.cancelled) {
30
+ text += "\n\n(command cancelled)";
31
+ }
32
+ else if (msg.exitCode !== null && msg.exitCode !== undefined && msg.exitCode !== 0) {
33
+ text += `\n\nCommand exited with code ${msg.exitCode}`;
34
+ }
35
+ if (msg.truncated && msg.fullOutputPath) {
36
+ text += `\n\n[Output truncated. Full output: ${msg.fullOutputPath}]`;
37
+ }
38
+ return text;
39
+ }
40
+ export function createBranchSummaryMessage(summary, fromId, timestamp) {
41
+ return {
42
+ role: "branchSummary",
43
+ summary,
44
+ fromId,
45
+ timestamp: new Date(timestamp).getTime(),
46
+ };
47
+ }
48
+ export function createCompactionSummaryMessage(summary, tokensBefore, timestamp) {
49
+ return {
50
+ role: "compactionSummary",
51
+ summary: summary,
52
+ tokensBefore,
53
+ timestamp: new Date(timestamp).getTime(),
54
+ };
55
+ }
56
+ /** Convert CustomMessageEntry to AgentMessage format */
57
+ export function createCustomMessage(customType, content, display, details, timestamp) {
58
+ return {
59
+ role: "custom",
60
+ customType,
61
+ content,
62
+ display,
63
+ details,
64
+ timestamp: new Date(timestamp).getTime(),
65
+ };
66
+ }
67
+ /**
68
+ * Transform AgentMessages (including custom types) to LLM-compatible Messages.
69
+ *
70
+ * This is used by:
71
+ * - Agent's transormToLlm option (for prompt calls and queued messages)
72
+ * - Compaction's generateSummary (for summarization)
73
+ * - Custom extensions and tools
74
+ */
75
+ export function convertToLlm(messages) {
76
+ return messages
77
+ .map((m) => {
78
+ switch (m.role) {
79
+ case "bashExecution":
80
+ // Skip messages excluded from context (!! prefix)
81
+ if (m.excludeFromContext) {
82
+ return undefined;
83
+ }
84
+ return {
85
+ role: "user",
86
+ content: [{ type: "text", text: bashExecutionToText(m) }],
87
+ timestamp: m.timestamp,
88
+ };
89
+ case "custom": {
90
+ const content = typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content;
91
+ return {
92
+ role: "user",
93
+ content,
94
+ timestamp: m.timestamp,
95
+ };
96
+ }
97
+ case "branchSummary":
98
+ return {
99
+ role: "user",
100
+ content: [{ type: "text", text: BRANCH_SUMMARY_PREFIX + m.summary + BRANCH_SUMMARY_SUFFIX }],
101
+ timestamp: m.timestamp,
102
+ };
103
+ case "compactionSummary":
104
+ return {
105
+ role: "user",
106
+ content: [
107
+ { type: "text", text: COMPACTION_SUMMARY_PREFIX + m.summary + COMPACTION_SUMMARY_SUFFIX },
108
+ ],
109
+ timestamp: m.timestamp,
110
+ };
111
+ case "user":
112
+ case "assistant":
113
+ case "toolResult":
114
+ return m;
115
+ default:
116
+ // biome-ignore lint/correctness/noSwitchDeclarations: fine
117
+ const _exhaustiveCheck = m;
118
+ return undefined;
119
+ }
120
+ })
121
+ .filter((m) => m !== undefined);
122
+ }