icopilot 2.2.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 (203) hide show
  1. package/CHANGELOG.md +250 -0
  2. package/LICENSE +21 -0
  3. package/README.md +214 -0
  4. package/bin/icopilot.js +6 -0
  5. package/dist/acp/router.js +123 -0
  6. package/dist/acp/schema.js +53 -0
  7. package/dist/agents/aggregator.js +187 -0
  8. package/dist/agents/custom-agents.js +97 -0
  9. package/dist/agents/goal-driven.js +411 -0
  10. package/dist/agents/multi-repo.js +350 -0
  11. package/dist/agents/parallel-runner.js +181 -0
  12. package/dist/agents/router.js +144 -0
  13. package/dist/agents/self-heal.js +481 -0
  14. package/dist/agents/tdd-agent.js +278 -0
  15. package/dist/api/github-models.js +158 -0
  16. package/dist/bridge/ide-bridge.js +479 -0
  17. package/dist/cloud/routine-executor.js +34 -0
  18. package/dist/cloud/routine-scheduler.js +67 -0
  19. package/dist/cloud/routine-storage.js +297 -0
  20. package/dist/commands/acp-cmd.js +143 -0
  21. package/dist/commands/actions-cmd.js +624 -0
  22. package/dist/commands/agent-cmd.js +144 -0
  23. package/dist/commands/alias-cmd.js +132 -0
  24. package/dist/commands/bookmark-cmd.js +77 -0
  25. package/dist/commands/changelog-cmd.js +99 -0
  26. package/dist/commands/changes-cmd.js +120 -0
  27. package/dist/commands/clipboard-cmd.js +217 -0
  28. package/dist/commands/cloud-routine-cmd.js +265 -0
  29. package/dist/commands/codegen-cmd.js +544 -0
  30. package/dist/commands/compare-cmd.js +116 -0
  31. package/dist/commands/context-cmd.js +247 -0
  32. package/dist/commands/context-viz-cmd.js +43 -0
  33. package/dist/commands/conventions-cmd.js +116 -0
  34. package/dist/commands/cost-cmd.js +51 -0
  35. package/dist/commands/deps-cmd.js +294 -0
  36. package/dist/commands/diagram-cmd.js +658 -0
  37. package/dist/commands/diff-review-cmd.js +92 -0
  38. package/dist/commands/doc-cmd.js +412 -0
  39. package/dist/commands/doctor-cmd.js +152 -0
  40. package/dist/commands/editor-cmd.js +49 -0
  41. package/dist/commands/env-cmd.js +86 -0
  42. package/dist/commands/explain-cmd.js +78 -0
  43. package/dist/commands/explain-shell-cmd.js +22 -0
  44. package/dist/commands/explore-cmd.js +231 -0
  45. package/dist/commands/feedback-cmd.js +98 -0
  46. package/dist/commands/fix-cmd.js +17 -0
  47. package/dist/commands/generate-cmd.js +38 -0
  48. package/dist/commands/git-extra.js +197 -0
  49. package/dist/commands/git-log-cmd.js +98 -0
  50. package/dist/commands/git-undo-cmd.js +137 -0
  51. package/dist/commands/git.js +155 -0
  52. package/dist/commands/history-cmd.js +122 -0
  53. package/dist/commands/index-cmd.js +65 -0
  54. package/dist/commands/init-cmd.js +73 -0
  55. package/dist/commands/lint-cmd.js +133 -0
  56. package/dist/commands/memory-cmd.js +98 -0
  57. package/dist/commands/metrics-cmd.js +97 -0
  58. package/dist/commands/mode-prefix.js +30 -0
  59. package/dist/commands/multi-cmd.js +44 -0
  60. package/dist/commands/notify-cmd.js +204 -0
  61. package/dist/commands/profile-cmd.js +101 -0
  62. package/dist/commands/prompts.js +17 -0
  63. package/dist/commands/rag-cmd.js +60 -0
  64. package/dist/commands/readme-cmd.js +564 -0
  65. package/dist/commands/reasoning-cmd.js +34 -0
  66. package/dist/commands/refactor-cmd.js +96 -0
  67. package/dist/commands/release-cmd.js +450 -0
  68. package/dist/commands/repo-cmd.js +195 -0
  69. package/dist/commands/route-cmd.js +21 -0
  70. package/dist/commands/schedule-cmd.js +109 -0
  71. package/dist/commands/search-cmd.js +47 -0
  72. package/dist/commands/security-cmd.js +156 -0
  73. package/dist/commands/settings-cmd.js +238 -0
  74. package/dist/commands/skill-cmd.js +338 -0
  75. package/dist/commands/slash.js +2721 -0
  76. package/dist/commands/snippets-cmd.js +83 -0
  77. package/dist/commands/space-cmd.js +92 -0
  78. package/dist/commands/stash-cmd.js +156 -0
  79. package/dist/commands/stats-cmd.js +36 -0
  80. package/dist/commands/style-cmd.js +85 -0
  81. package/dist/commands/suggest-cmd.js +40 -0
  82. package/dist/commands/summary-cmd.js +138 -0
  83. package/dist/commands/task-cmd.js +58 -0
  84. package/dist/commands/team-memory-cmd.js +97 -0
  85. package/dist/commands/template-cmd.js +475 -0
  86. package/dist/commands/test-cmd.js +146 -0
  87. package/dist/commands/todo-cmd.js +172 -0
  88. package/dist/commands/tokens-cmd.js +277 -0
  89. package/dist/commands/trigger-cmd.js +147 -0
  90. package/dist/commands/undo-cmd.js +18 -0
  91. package/dist/commands/voice-cmd.js +89 -0
  92. package/dist/commands/watch-cmd.js +110 -0
  93. package/dist/commands/web-cmd.js +183 -0
  94. package/dist/commands/worktree-cmd.js +119 -0
  95. package/dist/config-profile.js +66 -0
  96. package/dist/config.js +288 -0
  97. package/dist/context/compactor.js +53 -0
  98. package/dist/context/dep-context.js +329 -0
  99. package/dist/context/file-refs.js +54 -0
  100. package/dist/context/git-context.js +229 -0
  101. package/dist/context/image-input.js +66 -0
  102. package/dist/context/memory.js +55 -0
  103. package/dist/context/persistent-memory.js +104 -0
  104. package/dist/context/pinned.js +96 -0
  105. package/dist/context/priority.js +150 -0
  106. package/dist/context/read-only.js +48 -0
  107. package/dist/context/smart-files.js +286 -0
  108. package/dist/context/team-memory.js +156 -0
  109. package/dist/extensions/loader.js +149 -0
  110. package/dist/extensions/marketplace.js +49 -0
  111. package/dist/extensions/slack-provider.js +181 -0
  112. package/dist/extensions/team.js +56 -0
  113. package/dist/extensions/teams-provider.js +222 -0
  114. package/dist/extensions/voice.js +18 -0
  115. package/dist/hooks/lifecycle.js +215 -0
  116. package/dist/hooks/precommit.js +463 -0
  117. package/dist/index/embeddings.js +23 -0
  118. package/dist/index/indexer.js +86 -0
  119. package/dist/index/retrieve.js +20 -0
  120. package/dist/index/store.js +95 -0
  121. package/dist/index.js +286 -0
  122. package/dist/intelligence/dead-code.js +457 -0
  123. package/dist/intelligence/error-watch.js +263 -0
  124. package/dist/intelligence/navigation.js +141 -0
  125. package/dist/intelligence/stack-trace.js +210 -0
  126. package/dist/intelligence/symbol-index.js +410 -0
  127. package/dist/knowledge/auto-memory.js +412 -0
  128. package/dist/knowledge/conventions.js +475 -0
  129. package/dist/knowledge/corrections.js +213 -0
  130. package/dist/knowledge/rag.js +450 -0
  131. package/dist/knowledge/style-learner.js +324 -0
  132. package/dist/logger.js +35 -0
  133. package/dist/mcp/client.js +144 -0
  134. package/dist/mcp/config.js +24 -0
  135. package/dist/mcp/index.js +89 -0
  136. package/dist/modes/auto-compact.js +20 -0
  137. package/dist/modes/autopilot.js +157 -0
  138. package/dist/modes/background.js +82 -0
  139. package/dist/modes/interactive.js +187 -0
  140. package/dist/modes/oneshot.js +36 -0
  141. package/dist/modes/tui.js +265 -0
  142. package/dist/modes/turn.js +342 -0
  143. package/dist/notifications/manager.js +107 -0
  144. package/dist/plugins/marketplace.js +244 -0
  145. package/dist/providers/custom-provider.js +298 -0
  146. package/dist/providers/local-model.js +121 -0
  147. package/dist/routing/profiles.js +44 -0
  148. package/dist/routing/router.js +18 -0
  149. package/dist/sandbox/container.js +151 -0
  150. package/dist/security/audit.js +237 -0
  151. package/dist/security/content-filter.js +449 -0
  152. package/dist/security/proxy.js +301 -0
  153. package/dist/security/retention.js +281 -0
  154. package/dist/security/roles.js +252 -0
  155. package/dist/server/api-server.js +679 -0
  156. package/dist/session/bookmarks.js +72 -0
  157. package/dist/session/cloud-session.js +291 -0
  158. package/dist/session/handoff.js +405 -0
  159. package/dist/session/manager.js +35 -0
  160. package/dist/session/session.js +296 -0
  161. package/dist/session/share.js +313 -0
  162. package/dist/session/undo-journal.js +91 -0
  163. package/dist/snippets/store.js +60 -0
  164. package/dist/spaces/space-config.js +156 -0
  165. package/dist/spaces/space.js +220 -0
  166. package/dist/stats/store.js +101 -0
  167. package/dist/tools/apply-patch.js +134 -0
  168. package/dist/tools/auto-check.js +218 -0
  169. package/dist/tools/diff-edit.js +150 -0
  170. package/dist/tools/diff-prompt.js +36 -0
  171. package/dist/tools/edit-file.js +66 -0
  172. package/dist/tools/file-ops.js +205 -0
  173. package/dist/tools/glob.js +17 -0
  174. package/dist/tools/grep.js +56 -0
  175. package/dist/tools/image.js +194 -0
  176. package/dist/tools/list-directory.js +228 -0
  177. package/dist/tools/memory.js +17 -0
  178. package/dist/tools/multi-edit.js +299 -0
  179. package/dist/tools/policy.js +95 -0
  180. package/dist/tools/registry.js +484 -0
  181. package/dist/tools/retry.js +74 -0
  182. package/dist/tools/run-in-terminal.js +162 -0
  183. package/dist/tools/safety.js +64 -0
  184. package/dist/tools/sandbox.js +15 -0
  185. package/dist/tools/search-symbols.js +212 -0
  186. package/dist/tools/shell.js +118 -0
  187. package/dist/tools/web.js +167 -0
  188. package/dist/ui/prompt.js +37 -0
  189. package/dist/ui/render.js +96 -0
  190. package/dist/ui/screen.js +13 -0
  191. package/dist/ui/theme.js +56 -0
  192. package/dist/util/browser.js +34 -0
  193. package/dist/util/completion.js +350 -0
  194. package/dist/util/cost.js +28 -0
  195. package/dist/util/keybindings.js +113 -0
  196. package/dist/util/lazy.js +26 -0
  197. package/dist/util/perf.js +25 -0
  198. package/dist/util/token-worker.js +11 -0
  199. package/dist/util/tokens.js +50 -0
  200. package/dist/workflows/builtins.js +128 -0
  201. package/dist/workflows/engine.js +496 -0
  202. package/dist/workflows/file-trigger.js +197 -0
  203. package/package.json +79 -0
@@ -0,0 +1,350 @@
1
+ import { loadCustomAgents } from '../agents/custom-agents.js';
2
+ const defaultSlashCommands = [
3
+ 'help',
4
+ 'clear',
5
+ 'new',
6
+ 'goal',
7
+ 'model',
8
+ 'provider',
9
+ 'cwd',
10
+ 'diff',
11
+ 'changes',
12
+ 'diff-review',
13
+ 'git-log',
14
+ 'context',
15
+ 'usage',
16
+ 'pin',
17
+ 'unpin',
18
+ 'read-only',
19
+ 'ro',
20
+ 'every',
21
+ 'after',
22
+ 'schedule',
23
+ 'tokens',
24
+ 'editor',
25
+ 'reasoning',
26
+ 'think-tokens',
27
+ 'compact',
28
+ 'settings',
29
+ 'feedback',
30
+ 'sessions',
31
+ 'cloud',
32
+ 'export',
33
+ 'share',
34
+ 'paste',
35
+ 'copy',
36
+ 'copy-context',
37
+ 'handoff',
38
+ 'plan',
39
+ 'edit-format',
40
+ 'commit',
41
+ 'pr',
42
+ 'review',
43
+ 'issue',
44
+ 'branch',
45
+ 'index',
46
+ 'rag',
47
+ 'search',
48
+ 'goto',
49
+ 'refs',
50
+ 'route',
51
+ 'undo',
52
+ 'redo',
53
+ 'cost',
54
+ 'snippets',
55
+ 'profile',
56
+ 'role',
57
+ 'style',
58
+ 'conventions',
59
+ 'stats',
60
+ 'metrics',
61
+ 'audit',
62
+ 'explain',
63
+ 'explain-shell',
64
+ 'suggest',
65
+ 'generate',
66
+ 'actions',
67
+ 'codegen',
68
+ 'summary',
69
+ 'agent',
70
+ 'explore',
71
+ 'compare',
72
+ 'env',
73
+ 'trigger',
74
+ 'template',
75
+ 'readme',
76
+ 'changelog',
77
+ 'release',
78
+ 'fix',
79
+ 'heal',
80
+ 'lint',
81
+ 'test',
82
+ 'auto-lint',
83
+ 'auto-test',
84
+ 'auto-fix',
85
+ 'doctor',
86
+ 'tdd',
87
+ 'task',
88
+ 'tasks',
89
+ 'todo',
90
+ 'deps',
91
+ 'init',
92
+ 'security',
93
+ 'proxy',
94
+ 'filter',
95
+ 'retention',
96
+ 'dead-code',
97
+ 'refactor',
98
+ 'stacktrace',
99
+ 'history',
100
+ 'bookmark',
101
+ 'alias',
102
+ 'skill',
103
+ 'stash',
104
+ 'multi',
105
+ 'parallel',
106
+ 'watch',
107
+ 'web',
108
+ 'run',
109
+ 'bridge',
110
+ 'error-watch',
111
+ 'memory',
112
+ 'corrections',
113
+ 'repo',
114
+ 'hook',
115
+ 'team-memory',
116
+ 'space',
117
+ 'doc',
118
+ 'diagram',
119
+ 'extension',
120
+ 'serve',
121
+ 'worktree',
122
+ 'plugin',
123
+ 'workflow',
124
+ 'sandbox',
125
+ 'ask',
126
+ 'code',
127
+ 'architect',
128
+ 'exit',
129
+ 'quit',
130
+ ];
131
+ const defaultFlags = [
132
+ '-p',
133
+ '--prompt',
134
+ '--model',
135
+ '--provider',
136
+ '--base-url',
137
+ '--local',
138
+ '--provider',
139
+ '--cwd',
140
+ '--sandbox',
141
+ '--tui',
142
+ '--architect',
143
+ '--verbose',
144
+ '--serve',
145
+ '--browser',
146
+ '--help',
147
+ '--version',
148
+ ];
149
+ const defaultAgentNames = ['explore', 'task', 'review', 'plan'];
150
+ const undoArgs = ['--hard', 'file', 'status'];
151
+ const defaultSlashSubcommands = {
152
+ memory: ['list', 'add', 'remove', 'clear', 'search', 'auto'],
153
+ 'memory auto': ['list', 'clear', 'forget'],
154
+ };
155
+ export function defaultContext(projectRoot = process.cwd()) {
156
+ const customAgentNames = safeCustomAgentNames(projectRoot);
157
+ return {
158
+ slashCommands: [...defaultSlashCommands],
159
+ flags: [...defaultFlags],
160
+ agentNames: [...new Set([...defaultAgentNames, ...customAgentNames])],
161
+ slashSubcommands: structuredClone(defaultSlashSubcommands),
162
+ };
163
+ }
164
+ export function bashCompletion(ctx = defaultContext()) {
165
+ const commands = ctx.slashCommands
166
+ .map((command) => `/${command}`)
167
+ .map(bashWord)
168
+ .join(' ');
169
+ const flags = ctx.flags.map(bashWord).join(' ');
170
+ const agentNames = ctx.agentNames.map(bashWord).join(' ');
171
+ const undoOptions = undoArgs.map(bashWord).join(' ');
172
+ const memorySubcommands = (ctx.slashSubcommands.memory ?? []).map(bashWord).join(' ');
173
+ const memoryAutoSubcommands = (ctx.slashSubcommands['memory auto'] ?? []).map(bashWord).join(' ');
174
+ const bashCompWordCur = '${COMP_WORDS[COMP_CWORD]}';
175
+ const bashCompWordPrev = '${COMP_WORDS[COMP_CWORD-1]}';
176
+ const bashCompWordPrevPrev = '${COMP_WORDS[COMP_CWORD-2]}';
177
+ return `# bash completion for icopilot and icli
178
+ _icopilot() {
179
+ local cur prev
180
+ COMPREPLY=()
181
+
182
+ if type _init_completion >/dev/null 2>&1; then
183
+ _init_completion -n : || return
184
+ else
185
+ cur="${bashCompWordCur}"
186
+ prev="${bashCompWordPrev}"
187
+ fi
188
+
189
+ local slash_commands='${commands}'
190
+ local flags='${flags}'
191
+ local agent_names='${agentNames}'
192
+ local undo_args='${undoOptions}'
193
+ local memory_subcommands='${memorySubcommands}'
194
+ local memory_auto_subcommands='${memoryAutoSubcommands}'
195
+
196
+ if [[ "$prev" == "/agent" ]]; then
197
+ COMPREPLY=( $(compgen -W "$agent_names" -- "$cur") )
198
+ return
199
+ fi
200
+
201
+ if [[ "$prev" == "/undo" ]]; then
202
+ COMPREPLY=( $(compgen -W "$undo_args" -- "$cur") )
203
+ return
204
+ fi
205
+
206
+ if [[ "$prev" == "/memory" ]]; then
207
+ COMPREPLY=( $(compgen -W "$memory_subcommands" -- "$cur") )
208
+ return
209
+ fi
210
+
211
+ if [[ "$prev" == "auto" && "${bashCompWordPrevPrev}" == "/memory" ]]; then
212
+ COMPREPLY=( $(compgen -W "$memory_auto_subcommands" -- "$cur") )
213
+ return
214
+ fi
215
+
216
+ case "$cur" in
217
+ /*)
218
+ COMPREPLY=( $(compgen -W "$slash_commands" -- "$cur") )
219
+ return
220
+ ;;
221
+ -* )
222
+ COMPREPLY=( $(compgen -W "$flags" -- "$cur") )
223
+ return
224
+ ;;
225
+ esac
226
+
227
+ if declare -F _filedir >/dev/null 2>&1; then
228
+ _filedir
229
+ fi
230
+ }
231
+
232
+ complete -F _icopilot icopilot icli
233
+ `;
234
+ }
235
+ export function zshCompletion(ctx = defaultContext()) {
236
+ const commands = ctx.slashCommands
237
+ .map((command) => `/${command}`)
238
+ .map(zshSingleQuoted)
239
+ .join(' ');
240
+ const flagSpecs = ctx.flags
241
+ .map((flag) => ` ${zshSingleQuoted(`${flag}[icopilot option]`)} \\\n`)
242
+ .join('');
243
+ const agentNames = ctx.agentNames.map(zshSingleQuoted).join(' ');
244
+ const undoOptions = undoArgs.map(zshSingleQuoted).join(' ');
245
+ const memorySubcommands = (ctx.slashSubcommands.memory ?? []).map(zshSingleQuoted).join(' ');
246
+ const memoryAutoSubcommands = (ctx.slashSubcommands['memory auto'] ?? [])
247
+ .map(zshSingleQuoted)
248
+ .join(' ');
249
+ return `#compdef icopilot icli
250
+
251
+ _icopilot() {
252
+ local -a slash_commands
253
+ slash_commands=(${commands})
254
+ local -a agent_names
255
+ agent_names=(${agentNames})
256
+ local -a undo_args
257
+ undo_args=(${undoOptions})
258
+ local -a memory_subcommands
259
+ memory_subcommands=(${memorySubcommands})
260
+ local -a memory_auto_subcommands
261
+ memory_auto_subcommands=(${memoryAutoSubcommands})
262
+
263
+ _arguments \\
264
+ ${flagSpecs} '*::arg:->args'
265
+
266
+ case $state in
267
+ args)
268
+ if (( CURRENT >= 2 )) && [[ \${words[CURRENT-1]} == /agent ]]; then
269
+ compadd -- $agent_names
270
+ elif (( CURRENT >= 2 )) && [[ \${words[CURRENT-1]} == /undo ]]; then
271
+ compadd -- $undo_args
272
+ elif (( CURRENT >= 2 )) && [[ \${words[CURRENT-1]} == /memory ]]; then
273
+ compadd -- $memory_subcommands
274
+ elif (( CURRENT >= 3 )) && [[ \${words[CURRENT-2]} == /memory && \${words[CURRENT-1]} == auto ]]; then
275
+ compadd -- $memory_auto_subcommands
276
+ elif [[ $PREFIX == /* ]]; then
277
+ compadd -- $slash_commands
278
+ else
279
+ _files
280
+ fi
281
+ ;;
282
+ esac
283
+ }
284
+
285
+ _icopilot "$@"
286
+ `;
287
+ }
288
+ export function pwshCompletion(ctx = defaultContext()) {
289
+ const commands = ctx.slashCommands
290
+ .map((command) => `/${command}`)
291
+ .map(pwshSingleQuoted)
292
+ .join(', ');
293
+ const flags = ctx.flags.map(pwshSingleQuoted).join(', ');
294
+ const agentNames = ctx.agentNames.map(pwshSingleQuoted).join(', ');
295
+ const undoOptions = undoArgs.map(pwshSingleQuoted).join(', ');
296
+ const memorySubcommands = (ctx.slashSubcommands.memory ?? []).map(pwshSingleQuoted).join(', ');
297
+ const memoryAutoSubcommands = (ctx.slashSubcommands['memory auto'] ?? [])
298
+ .map(pwshSingleQuoted)
299
+ .join(', ');
300
+ return `# PowerShell completion for icopilot and icli
301
+ Register-ArgumentCompleter -Native -CommandName icopilot,icli -ScriptBlock {
302
+ param($wordToComplete, $commandAst, $cursorPosition)
303
+
304
+ $slashCommands = @(${commands})
305
+ $flags = @(${flags})
306
+ $agentNames = @(${agentNames})
307
+ $undoArgs = @(${undoOptions})
308
+ $memorySubcommands = @(${memorySubcommands})
309
+ $memoryAutoSubcommands = @(${memoryAutoSubcommands})
310
+ $elements = @($commandAst.CommandElements | ForEach-Object { $_.Extent.Text })
311
+
312
+ if ($elements.Count -ge 2 -and $elements[$elements.Count - 2] -eq '/agent') {
313
+ $candidates = $agentNames
314
+ } elseif ($elements.Count -ge 2 -and $elements[$elements.Count - 2] -eq '/undo') {
315
+ $candidates = $undoArgs
316
+ } elseif ($elements.Count -ge 2 -and $elements[$elements.Count - 2] -eq '/memory') {
317
+ $candidates = $memorySubcommands
318
+ } elseif ($elements.Count -ge 3 -and $elements[$elements.Count - 3] -eq '/memory' -and $elements[$elements.Count - 2] -eq 'auto') {
319
+ $candidates = $memoryAutoSubcommands
320
+ } elseif ($wordToComplete -like '/*') {
321
+ $candidates = $slashCommands
322
+ } elseif ($wordToComplete -like '-*') {
323
+ $candidates = $flags
324
+ } else {
325
+ $candidates = $slashCommands + $flags
326
+ }
327
+
328
+ $candidates |
329
+ Where-Object { $_ -like "$wordToComplete*" } |
330
+ ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) }
331
+ }
332
+ `;
333
+ }
334
+ function bashWord(value) {
335
+ return value.replace(/[\\'"$`\s]/g, '\\$&');
336
+ }
337
+ function zshSingleQuoted(value) {
338
+ return `'${value.replace(/'/g, `'\\''`)}'`;
339
+ }
340
+ function pwshSingleQuoted(value) {
341
+ return `'${value.replace(/'/g, `''`)}'`;
342
+ }
343
+ function safeCustomAgentNames(projectRoot) {
344
+ try {
345
+ return loadCustomAgents(projectRoot).map((agent) => agent.name);
346
+ }
347
+ catch {
348
+ return [];
349
+ }
350
+ }
@@ -0,0 +1,28 @@
1
+ export const RATES = {
2
+ 'gpt-4o': { input: 2.5, output: 10 },
3
+ 'gpt-4o-mini': { input: 0.15, output: 0.6 },
4
+ 'gpt-4.1': { input: 2, output: 8 },
5
+ 'gpt-4.1-mini': { input: 0.4, output: 1.6 },
6
+ o1: { input: 15, output: 60 },
7
+ 'o1-mini': { input: 1.1, output: 4.4 },
8
+ 'o3-mini': { input: 1.1, output: 4.4 },
9
+ };
10
+ export const DEFAULT_RATE = { input: 1, output: 3 };
11
+ export function getRate(model) {
12
+ const normalized = model.trim().toLowerCase();
13
+ const match = Object.entries(RATES)
14
+ .sort(([a], [b]) => b.length - a.length)
15
+ .find(([name]) => normalized.startsWith(name.toLowerCase()));
16
+ return match?.[1] ?? DEFAULT_RATE;
17
+ }
18
+ export function estimateCost(model, inputTokens, outputTokens) {
19
+ const rate = getRate(model);
20
+ return (inputTokens / 1000) * rate.input + (outputTokens / 1000) * rate.output;
21
+ }
22
+ export function formatUsd(n) {
23
+ if (n > 0 && n < 0.0001)
24
+ return '<$0.0001';
25
+ if (n < 1)
26
+ return `$${n.toFixed(4)}`;
27
+ return `$${n.toFixed(2)}`;
28
+ }
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Vi and Emacs keybinding support for readline-based REPL.
3
+ * Provides modal editing (vi) and extended key sequences (emacs).
4
+ */
5
+ import { config } from '../config.js';
6
+ const DEFAULT_KEYMAP = {
7
+ emacs: 'EMACS',
8
+ vi: 'VI',
9
+ default: 'DEFAULT',
10
+ };
11
+ /**
12
+ * Enhance readline interface with vi/emacs keybindings.
13
+ * Note: Node's readline has limited key handling. This provides
14
+ * basic support through key event listeners and buffer manipulation.
15
+ */
16
+ export function attachKeybindings(rl, mode = 'default') {
17
+ if (mode === 'default') {
18
+ return { mode: 'default', viMode: 'insert', buffer: '', cursor: 0 };
19
+ }
20
+ const state = {
21
+ mode,
22
+ viMode: 'insert',
23
+ buffer: '',
24
+ cursor: 0,
25
+ };
26
+ // Node.js readline doesn't expose raw key events in a portable way.
27
+ // Instead, we provide integration points that applications can use.
28
+ // For full vi/emacs support, users should use a readline alternative like ink or blessed.
29
+ // Store reference to readline for applications to integrate with.
30
+ rl.__keybindingMode = mode;
31
+ rl.__keybindingState = state;
32
+ return state;
33
+ }
34
+ /**
35
+ * Check if readline interface has keybindings attached.
36
+ */
37
+ export function hasKeybindings(rl) {
38
+ return !!rl.__keybindingMode && rl.__keybindingMode !== 'default';
39
+ }
40
+ /**
41
+ * Get current keybinding mode.
42
+ */
43
+ export function getKeybindingMode(rl) {
44
+ return rl.__keybindingMode ?? 'default';
45
+ }
46
+ /**
47
+ * Guide text for keybindings.
48
+ */
49
+ export function getKeybindingHelp(mode) {
50
+ if (mode === 'vi') {
51
+ return `
52
+ Vi keybindings enabled.
53
+ ESC enter normal mode
54
+ i insert mode
55
+ dd delete line
56
+ yy yank (copy) line
57
+ p paste
58
+ h/j/k/l navigation
59
+ 0/$ go to start/end of line
60
+ A/I append/insert at line end/start
61
+ u undo
62
+
63
+ Type '/help keybindings' for more info.
64
+ `;
65
+ }
66
+ else if (mode === 'emacs') {
67
+ return `
68
+ Emacs keybindings enabled.
69
+ C-a go to line start
70
+ C-e go to line end
71
+ C-k kill to line end
72
+ C-u kill from line start
73
+ C-w kill word
74
+ M-d delete word
75
+ C-y yank (paste)
76
+ C-r search history
77
+
78
+ Type '/help keybindings' for more info.
79
+ `;
80
+ }
81
+ return 'Default keybindings enabled. Type "/help keybindings" for more info.\n';
82
+ }
83
+ /**
84
+ * Get recommended readline options for keybinding mode.
85
+ * These work with native Node readline, but for full vi/emacs experience,
86
+ * use a library like ink, blessed, or rustyline (via wasm).
87
+ */
88
+ export function getReadlineOptionsForMode(mode) {
89
+ // Node.js readline has limited keybinding support.
90
+ // In native mode, only basic Ctrl sequences work.
91
+ // Full vi/emacs would require a wrapper library.
92
+ return {
93
+ terminal: true,
94
+ historySize: 500,
95
+ };
96
+ }
97
+ /**
98
+ * Apply keybinding configuration from .icopilotrc.
99
+ */
100
+ export function applyKeybindingConfig() {
101
+ const mode = config.keybindings?.mode ?? 'default';
102
+ if (mode !== 'vi' && mode !== 'emacs' && mode !== 'default') {
103
+ return 'default';
104
+ }
105
+ return mode;
106
+ }
107
+ /**
108
+ * Format keybinding info for display.
109
+ */
110
+ export function formatKeybindingInfo(mode) {
111
+ const modeLabel = mode === 'vi' ? '🔤 Vi' : mode === 'emacs' ? '🔤 Emacs' : '⌨️ Default';
112
+ return `${modeLabel} mode`;
113
+ }
@@ -0,0 +1,26 @@
1
+ export function lazy(loader) {
2
+ let promise = null;
3
+ let value;
4
+ let loaded = false;
5
+ return async () => {
6
+ if (loaded)
7
+ return value;
8
+ promise ??= loader().then((result) => {
9
+ value = result;
10
+ loaded = true;
11
+ return result;
12
+ });
13
+ return promise;
14
+ };
15
+ }
16
+ export function lazySync(loader) {
17
+ let loaded = false;
18
+ let value;
19
+ return () => {
20
+ if (!loaded) {
21
+ value = loader();
22
+ loaded = true;
23
+ }
24
+ return value;
25
+ };
26
+ }
@@ -0,0 +1,25 @@
1
+ const START = process.hrtime.bigint();
2
+ const MODULE_LOAD_MS = process.uptime() * 1_000;
3
+ let reported = false;
4
+ let tracingEnabled = Boolean(process.env.ICOPILOT_PERF_TRACE) || process.argv.includes('--perf-trace');
5
+ export function enablePerfTrace() {
6
+ tracingEnabled = true;
7
+ process.env.ICOPILOT_PERF_TRACE = '1';
8
+ }
9
+ export function elapsedMs() {
10
+ return Number(process.hrtime.bigint() - START) / 1_000_000;
11
+ }
12
+ export function reportColdStart(label = 'cold-start') {
13
+ if (!tracingEnabled)
14
+ return;
15
+ process.stderr.write(`[perf] process start → ${label}: ${process.uptime().toFixed(1)}ms\n`);
16
+ }
17
+ export function markFirstPrompt(label = 'first prompt ready') {
18
+ if (reported || !tracingEnabled)
19
+ return;
20
+ reported = true;
21
+ const firstPromptMs = process.uptime() * 1_000;
22
+ process.stderr.write(`[perf] process start → module load: ${MODULE_LOAD_MS.toFixed(1)}ms\n`);
23
+ process.stderr.write(`[perf] module load → ${label}: ${(firstPromptMs - MODULE_LOAD_MS).toFixed(1)}ms\n`);
24
+ process.stderr.write(`[perf] process start → ${label}: ${firstPromptMs.toFixed(1)}ms\n`);
25
+ }
@@ -0,0 +1,11 @@
1
+ import { parentPort } from 'node:worker_threads';
2
+ import { encode } from 'gpt-tokenizer';
3
+ parentPort?.on('message', (message) => {
4
+ try {
5
+ const text = typeof message.text === 'string' ? message.text : '';
6
+ parentPort?.postMessage({ count: encode(text).length });
7
+ }
8
+ catch (error) {
9
+ parentPort?.postMessage({ error: String(error?.message || error) });
10
+ }
11
+ });
@@ -0,0 +1,50 @@
1
+ import { Worker } from 'node:worker_threads';
2
+ import { lazy } from './lazy.js';
3
+ let _cachedEncode = null;
4
+ const loadTokenizer = lazy(async () => {
5
+ const encode = (await import('gpt-tokenizer')).encode;
6
+ _cachedEncode = encode;
7
+ return encode;
8
+ });
9
+ export async function countTokens(text) {
10
+ if (text.length > 200_000 && Worker) {
11
+ return countTokensInWorker(text);
12
+ }
13
+ const encode = await loadTokenizer();
14
+ return encode(text).length;
15
+ }
16
+ /**
17
+ * Count tokens when the caller cannot await dynamic tokenizer loading.
18
+ *
19
+ * If the async tokenizer cache has already been warmed, this returns the exact
20
+ * tokenizer count. Otherwise it returns the existing length/4 heuristic to keep
21
+ * synchronous call sites cold-start friendly.
22
+ */
23
+ export function countTokensSync(text) {
24
+ if (_cachedEncode)
25
+ return _cachedEncode(text).length;
26
+ return Math.ceil(text.length / 4);
27
+ }
28
+ export async function primeTokenizer() {
29
+ await loadTokenizer();
30
+ }
31
+ function countTokensInWorker(text) {
32
+ return new Promise((resolve, reject) => {
33
+ const worker = new Worker(new URL('./token-worker.js', import.meta.url));
34
+ worker.once('message', (message) => {
35
+ if (typeof message.count === 'number') {
36
+ resolve(message.count);
37
+ }
38
+ else {
39
+ reject(new Error(message.error || 'token worker failed'));
40
+ }
41
+ void worker.terminate();
42
+ });
43
+ worker.once('error', reject);
44
+ worker.once('exit', (code) => {
45
+ if (code !== 0)
46
+ reject(new Error(`token worker exited with code ${code}`));
47
+ });
48
+ worker.postMessage({ text });
49
+ });
50
+ }