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.
- package/CHANGELOG.md +250 -0
- package/LICENSE +21 -0
- package/README.md +214 -0
- package/bin/icopilot.js +6 -0
- package/dist/acp/router.js +123 -0
- package/dist/acp/schema.js +53 -0
- package/dist/agents/aggregator.js +187 -0
- package/dist/agents/custom-agents.js +97 -0
- package/dist/agents/goal-driven.js +411 -0
- package/dist/agents/multi-repo.js +350 -0
- package/dist/agents/parallel-runner.js +181 -0
- package/dist/agents/router.js +144 -0
- package/dist/agents/self-heal.js +481 -0
- package/dist/agents/tdd-agent.js +278 -0
- package/dist/api/github-models.js +158 -0
- package/dist/bridge/ide-bridge.js +479 -0
- package/dist/cloud/routine-executor.js +34 -0
- package/dist/cloud/routine-scheduler.js +67 -0
- package/dist/cloud/routine-storage.js +297 -0
- package/dist/commands/acp-cmd.js +143 -0
- package/dist/commands/actions-cmd.js +624 -0
- package/dist/commands/agent-cmd.js +144 -0
- package/dist/commands/alias-cmd.js +132 -0
- package/dist/commands/bookmark-cmd.js +77 -0
- package/dist/commands/changelog-cmd.js +99 -0
- package/dist/commands/changes-cmd.js +120 -0
- package/dist/commands/clipboard-cmd.js +217 -0
- package/dist/commands/cloud-routine-cmd.js +265 -0
- package/dist/commands/codegen-cmd.js +544 -0
- package/dist/commands/compare-cmd.js +116 -0
- package/dist/commands/context-cmd.js +247 -0
- package/dist/commands/context-viz-cmd.js +43 -0
- package/dist/commands/conventions-cmd.js +116 -0
- package/dist/commands/cost-cmd.js +51 -0
- package/dist/commands/deps-cmd.js +294 -0
- package/dist/commands/diagram-cmd.js +658 -0
- package/dist/commands/diff-review-cmd.js +92 -0
- package/dist/commands/doc-cmd.js +412 -0
- package/dist/commands/doctor-cmd.js +152 -0
- package/dist/commands/editor-cmd.js +49 -0
- package/dist/commands/env-cmd.js +86 -0
- package/dist/commands/explain-cmd.js +78 -0
- package/dist/commands/explain-shell-cmd.js +22 -0
- package/dist/commands/explore-cmd.js +231 -0
- package/dist/commands/feedback-cmd.js +98 -0
- package/dist/commands/fix-cmd.js +17 -0
- package/dist/commands/generate-cmd.js +38 -0
- package/dist/commands/git-extra.js +197 -0
- package/dist/commands/git-log-cmd.js +98 -0
- package/dist/commands/git-undo-cmd.js +137 -0
- package/dist/commands/git.js +155 -0
- package/dist/commands/history-cmd.js +122 -0
- package/dist/commands/index-cmd.js +65 -0
- package/dist/commands/init-cmd.js +73 -0
- package/dist/commands/lint-cmd.js +133 -0
- package/dist/commands/memory-cmd.js +98 -0
- package/dist/commands/metrics-cmd.js +97 -0
- package/dist/commands/mode-prefix.js +30 -0
- package/dist/commands/multi-cmd.js +44 -0
- package/dist/commands/notify-cmd.js +204 -0
- package/dist/commands/profile-cmd.js +101 -0
- package/dist/commands/prompts.js +17 -0
- package/dist/commands/rag-cmd.js +60 -0
- package/dist/commands/readme-cmd.js +564 -0
- package/dist/commands/reasoning-cmd.js +34 -0
- package/dist/commands/refactor-cmd.js +96 -0
- package/dist/commands/release-cmd.js +450 -0
- package/dist/commands/repo-cmd.js +195 -0
- package/dist/commands/route-cmd.js +21 -0
- package/dist/commands/schedule-cmd.js +109 -0
- package/dist/commands/search-cmd.js +47 -0
- package/dist/commands/security-cmd.js +156 -0
- package/dist/commands/settings-cmd.js +238 -0
- package/dist/commands/skill-cmd.js +338 -0
- package/dist/commands/slash.js +2721 -0
- package/dist/commands/snippets-cmd.js +83 -0
- package/dist/commands/space-cmd.js +92 -0
- package/dist/commands/stash-cmd.js +156 -0
- package/dist/commands/stats-cmd.js +36 -0
- package/dist/commands/style-cmd.js +85 -0
- package/dist/commands/suggest-cmd.js +40 -0
- package/dist/commands/summary-cmd.js +138 -0
- package/dist/commands/task-cmd.js +58 -0
- package/dist/commands/team-memory-cmd.js +97 -0
- package/dist/commands/template-cmd.js +475 -0
- package/dist/commands/test-cmd.js +146 -0
- package/dist/commands/todo-cmd.js +172 -0
- package/dist/commands/tokens-cmd.js +277 -0
- package/dist/commands/trigger-cmd.js +147 -0
- package/dist/commands/undo-cmd.js +18 -0
- package/dist/commands/voice-cmd.js +89 -0
- package/dist/commands/watch-cmd.js +110 -0
- package/dist/commands/web-cmd.js +183 -0
- package/dist/commands/worktree-cmd.js +119 -0
- package/dist/config-profile.js +66 -0
- package/dist/config.js +288 -0
- package/dist/context/compactor.js +53 -0
- package/dist/context/dep-context.js +329 -0
- package/dist/context/file-refs.js +54 -0
- package/dist/context/git-context.js +229 -0
- package/dist/context/image-input.js +66 -0
- package/dist/context/memory.js +55 -0
- package/dist/context/persistent-memory.js +104 -0
- package/dist/context/pinned.js +96 -0
- package/dist/context/priority.js +150 -0
- package/dist/context/read-only.js +48 -0
- package/dist/context/smart-files.js +286 -0
- package/dist/context/team-memory.js +156 -0
- package/dist/extensions/loader.js +149 -0
- package/dist/extensions/marketplace.js +49 -0
- package/dist/extensions/slack-provider.js +181 -0
- package/dist/extensions/team.js +56 -0
- package/dist/extensions/teams-provider.js +222 -0
- package/dist/extensions/voice.js +18 -0
- package/dist/hooks/lifecycle.js +215 -0
- package/dist/hooks/precommit.js +463 -0
- package/dist/index/embeddings.js +23 -0
- package/dist/index/indexer.js +86 -0
- package/dist/index/retrieve.js +20 -0
- package/dist/index/store.js +95 -0
- package/dist/index.js +286 -0
- package/dist/intelligence/dead-code.js +457 -0
- package/dist/intelligence/error-watch.js +263 -0
- package/dist/intelligence/navigation.js +141 -0
- package/dist/intelligence/stack-trace.js +210 -0
- package/dist/intelligence/symbol-index.js +410 -0
- package/dist/knowledge/auto-memory.js +412 -0
- package/dist/knowledge/conventions.js +475 -0
- package/dist/knowledge/corrections.js +213 -0
- package/dist/knowledge/rag.js +450 -0
- package/dist/knowledge/style-learner.js +324 -0
- package/dist/logger.js +35 -0
- package/dist/mcp/client.js +144 -0
- package/dist/mcp/config.js +24 -0
- package/dist/mcp/index.js +89 -0
- package/dist/modes/auto-compact.js +20 -0
- package/dist/modes/autopilot.js +157 -0
- package/dist/modes/background.js +82 -0
- package/dist/modes/interactive.js +187 -0
- package/dist/modes/oneshot.js +36 -0
- package/dist/modes/tui.js +265 -0
- package/dist/modes/turn.js +342 -0
- package/dist/notifications/manager.js +107 -0
- package/dist/plugins/marketplace.js +244 -0
- package/dist/providers/custom-provider.js +298 -0
- package/dist/providers/local-model.js +121 -0
- package/dist/routing/profiles.js +44 -0
- package/dist/routing/router.js +18 -0
- package/dist/sandbox/container.js +151 -0
- package/dist/security/audit.js +237 -0
- package/dist/security/content-filter.js +449 -0
- package/dist/security/proxy.js +301 -0
- package/dist/security/retention.js +281 -0
- package/dist/security/roles.js +252 -0
- package/dist/server/api-server.js +679 -0
- package/dist/session/bookmarks.js +72 -0
- package/dist/session/cloud-session.js +291 -0
- package/dist/session/handoff.js +405 -0
- package/dist/session/manager.js +35 -0
- package/dist/session/session.js +296 -0
- package/dist/session/share.js +313 -0
- package/dist/session/undo-journal.js +91 -0
- package/dist/snippets/store.js +60 -0
- package/dist/spaces/space-config.js +156 -0
- package/dist/spaces/space.js +220 -0
- package/dist/stats/store.js +101 -0
- package/dist/tools/apply-patch.js +134 -0
- package/dist/tools/auto-check.js +218 -0
- package/dist/tools/diff-edit.js +150 -0
- package/dist/tools/diff-prompt.js +36 -0
- package/dist/tools/edit-file.js +66 -0
- package/dist/tools/file-ops.js +205 -0
- package/dist/tools/glob.js +17 -0
- package/dist/tools/grep.js +56 -0
- package/dist/tools/image.js +194 -0
- package/dist/tools/list-directory.js +228 -0
- package/dist/tools/memory.js +17 -0
- package/dist/tools/multi-edit.js +299 -0
- package/dist/tools/policy.js +95 -0
- package/dist/tools/registry.js +484 -0
- package/dist/tools/retry.js +74 -0
- package/dist/tools/run-in-terminal.js +162 -0
- package/dist/tools/safety.js +64 -0
- package/dist/tools/sandbox.js +15 -0
- package/dist/tools/search-symbols.js +212 -0
- package/dist/tools/shell.js +118 -0
- package/dist/tools/web.js +167 -0
- package/dist/ui/prompt.js +37 -0
- package/dist/ui/render.js +96 -0
- package/dist/ui/screen.js +13 -0
- package/dist/ui/theme.js +56 -0
- package/dist/util/browser.js +34 -0
- package/dist/util/completion.js +350 -0
- package/dist/util/cost.js +28 -0
- package/dist/util/keybindings.js +113 -0
- package/dist/util/lazy.js +26 -0
- package/dist/util/perf.js +25 -0
- package/dist/util/token-worker.js +11 -0
- package/dist/util/tokens.js +50 -0
- package/dist/workflows/builtins.js +128 -0
- package/dist/workflows/engine.js +496 -0
- package/dist/workflows/file-trigger.js +197 -0
- 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
|
+
}
|