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,66 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
const NAME_RE = /^[a-z0-9][a-z0-9_-]{0,32}$/i;
|
|
5
|
+
export function profilesPath() {
|
|
6
|
+
return (process.env.ICOPILOT_PROFILES_PATH || path.join(os.homedir(), '.icopilot', 'profiles.json'));
|
|
7
|
+
}
|
|
8
|
+
export function loadProfiles() {
|
|
9
|
+
const file = profilesPath();
|
|
10
|
+
if (!fs.existsSync(file))
|
|
11
|
+
return { active: null, profiles: {} };
|
|
12
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
13
|
+
const profiles = parsed.profiles && typeof parsed.profiles === 'object' && !Array.isArray(parsed.profiles)
|
|
14
|
+
? parsed.profiles
|
|
15
|
+
: {};
|
|
16
|
+
return {
|
|
17
|
+
active: typeof parsed.active === 'string' ? parsed.active : null,
|
|
18
|
+
profiles,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function saveProfiles(data) {
|
|
22
|
+
const file = profilesPath();
|
|
23
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
24
|
+
fs.writeFileSync(file, JSON.stringify(data, null, 2) + '\n', 'utf8');
|
|
25
|
+
}
|
|
26
|
+
export function listProfiles() {
|
|
27
|
+
const data = loadProfiles();
|
|
28
|
+
return {
|
|
29
|
+
active: data.active,
|
|
30
|
+
names: Object.keys(data.profiles).sort((a, b) => a.localeCompare(b)),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function getProfile(name) {
|
|
34
|
+
return loadProfiles().profiles[name] ?? null;
|
|
35
|
+
}
|
|
36
|
+
export function setProfile(profile) {
|
|
37
|
+
if (!NAME_RE.test(profile.name)) {
|
|
38
|
+
throw new Error('profile name must match /^[a-z0-9][a-z0-9_-]{0,32}$/i');
|
|
39
|
+
}
|
|
40
|
+
const data = loadProfiles();
|
|
41
|
+
data.profiles[profile.name] = { ...profile };
|
|
42
|
+
saveProfiles(data);
|
|
43
|
+
}
|
|
44
|
+
export function deleteProfile(name) {
|
|
45
|
+
const data = loadProfiles();
|
|
46
|
+
if (!data.profiles[name])
|
|
47
|
+
return false;
|
|
48
|
+
delete data.profiles[name];
|
|
49
|
+
if (data.active === name)
|
|
50
|
+
data.active = null;
|
|
51
|
+
saveProfiles(data);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
export function useProfile(name) {
|
|
55
|
+
const data = loadProfiles();
|
|
56
|
+
const profile = data.profiles[name] ?? null;
|
|
57
|
+
if (!profile)
|
|
58
|
+
return null;
|
|
59
|
+
data.active = name;
|
|
60
|
+
saveProfiles(data);
|
|
61
|
+
return profile;
|
|
62
|
+
}
|
|
63
|
+
export function activeProfile() {
|
|
64
|
+
const data = loadProfiles();
|
|
65
|
+
return data.active ? (data.profiles[data.active] ?? null) : null;
|
|
66
|
+
}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { providerRegistry, resolveProviderApiKey } from './providers/custom-provider.js';
|
|
6
|
+
const HOME = os.homedir();
|
|
7
|
+
const DEFAULT_CONFIG = {
|
|
8
|
+
provider: 'github',
|
|
9
|
+
endpoint: 'https://models.inference.ai.azure.com',
|
|
10
|
+
token: undefined,
|
|
11
|
+
defaultModel: 'gpt-4o-mini',
|
|
12
|
+
editFormat: 'diff',
|
|
13
|
+
autoLint: false,
|
|
14
|
+
autoTest: false,
|
|
15
|
+
sessionDir: path.join(HOME, '.terminal-copilot', 'sessions'),
|
|
16
|
+
contextWindow: 120_000,
|
|
17
|
+
contextWarn: 0.75,
|
|
18
|
+
autoCompact: true,
|
|
19
|
+
autoCompactThreshold: 0.95,
|
|
20
|
+
cwd: process.cwd(),
|
|
21
|
+
verbose: false,
|
|
22
|
+
logLevel: 'info',
|
|
23
|
+
sandbox: false,
|
|
24
|
+
policyPath: undefined,
|
|
25
|
+
theme: 'auto',
|
|
26
|
+
jsonOutput: false,
|
|
27
|
+
quiet: false,
|
|
28
|
+
autoApprove: false,
|
|
29
|
+
autoFix: true,
|
|
30
|
+
lintCmd: '',
|
|
31
|
+
testCmd: '',
|
|
32
|
+
reasoningEffort: undefined,
|
|
33
|
+
thinkTokens: undefined,
|
|
34
|
+
keybindings: { mode: 'default' },
|
|
35
|
+
acp: { enabled: false, port: 5173 },
|
|
36
|
+
cloudRoutines: { enabled: false },
|
|
37
|
+
};
|
|
38
|
+
function parseBool(value) {
|
|
39
|
+
if (value === undefined)
|
|
40
|
+
return undefined;
|
|
41
|
+
if (/^(1|true|yes|on)$/i.test(value))
|
|
42
|
+
return true;
|
|
43
|
+
if (/^(0|false|no|off)$/i.test(value))
|
|
44
|
+
return false;
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
function parseLogLevel(value) {
|
|
48
|
+
return value === 'debug' || value === 'info' || value === 'warn' || value === 'error'
|
|
49
|
+
? value
|
|
50
|
+
: undefined;
|
|
51
|
+
}
|
|
52
|
+
function parseTheme(value) {
|
|
53
|
+
return value === 'auto' || value === 'light' || value === 'dark' || value === 'none'
|
|
54
|
+
? value
|
|
55
|
+
: undefined;
|
|
56
|
+
}
|
|
57
|
+
function parseEditFormat(value) {
|
|
58
|
+
return value === 'whole' || value === 'diff' ? value : undefined;
|
|
59
|
+
}
|
|
60
|
+
function parseReasoningEffort(value) {
|
|
61
|
+
return value === 'low' || value === 'medium' || value === 'high' || value === 'max'
|
|
62
|
+
? value
|
|
63
|
+
: undefined;
|
|
64
|
+
}
|
|
65
|
+
function parseThinkTokens(value) {
|
|
66
|
+
if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {
|
|
67
|
+
return Math.floor(value);
|
|
68
|
+
}
|
|
69
|
+
if (typeof value !== 'string')
|
|
70
|
+
return undefined;
|
|
71
|
+
const trimmed = value.trim();
|
|
72
|
+
if (!trimmed)
|
|
73
|
+
return undefined;
|
|
74
|
+
const match = trimmed.match(/^(\d+(?:\.\d+)?)([kKmM]?)$/);
|
|
75
|
+
if (!match)
|
|
76
|
+
return undefined;
|
|
77
|
+
const amount = Number(match[1]);
|
|
78
|
+
if (!Number.isFinite(amount) || amount < 0)
|
|
79
|
+
return undefined;
|
|
80
|
+
const suffix = match[2].toLowerCase();
|
|
81
|
+
const multiplier = suffix === 'k' ? 1024 : suffix === 'm' ? 1024 * 1024 : 1;
|
|
82
|
+
return Math.round(amount * multiplier);
|
|
83
|
+
}
|
|
84
|
+
function normalizeConfig(raw) {
|
|
85
|
+
const out = {};
|
|
86
|
+
if (typeof raw.provider === 'string')
|
|
87
|
+
out.provider = raw.provider;
|
|
88
|
+
if (typeof raw.endpoint === 'string')
|
|
89
|
+
out.endpoint = raw.endpoint;
|
|
90
|
+
if (typeof raw.token === 'string')
|
|
91
|
+
out.token = raw.token;
|
|
92
|
+
if (typeof raw.defaultModel === 'string')
|
|
93
|
+
out.defaultModel = raw.defaultModel;
|
|
94
|
+
if (typeof raw.model === 'string')
|
|
95
|
+
out.defaultModel = raw.model;
|
|
96
|
+
const editFormat = parseEditFormat(raw.editFormat);
|
|
97
|
+
if (editFormat)
|
|
98
|
+
out.editFormat = editFormat;
|
|
99
|
+
if (typeof raw.autoLint === 'boolean')
|
|
100
|
+
out.autoLint = raw.autoLint;
|
|
101
|
+
if (typeof raw.autoTest === 'boolean')
|
|
102
|
+
out.autoTest = raw.autoTest;
|
|
103
|
+
if (typeof raw.sessionDir === 'string')
|
|
104
|
+
out.sessionDir = raw.sessionDir;
|
|
105
|
+
if (typeof raw.contextWindow === 'number')
|
|
106
|
+
out.contextWindow = raw.contextWindow;
|
|
107
|
+
if (typeof raw.contextWarn === 'number')
|
|
108
|
+
out.contextWarn = raw.contextWarn;
|
|
109
|
+
if (typeof raw.autoCompact === 'boolean')
|
|
110
|
+
out.autoCompact = raw.autoCompact;
|
|
111
|
+
if (typeof raw.autoCompactThreshold === 'number')
|
|
112
|
+
out.autoCompactThreshold = raw.autoCompactThreshold;
|
|
113
|
+
if (typeof raw.cwd === 'string')
|
|
114
|
+
out.cwd = raw.cwd;
|
|
115
|
+
if (typeof raw.verbose === 'boolean')
|
|
116
|
+
out.verbose = raw.verbose;
|
|
117
|
+
if (typeof raw.sandbox === 'boolean')
|
|
118
|
+
out.sandbox = raw.sandbox;
|
|
119
|
+
if (typeof raw.policyPath === 'string')
|
|
120
|
+
out.policyPath = raw.policyPath;
|
|
121
|
+
if (typeof raw.jsonOutput === 'boolean')
|
|
122
|
+
out.jsonOutput = raw.jsonOutput;
|
|
123
|
+
if (typeof raw.quiet === 'boolean')
|
|
124
|
+
out.quiet = raw.quiet;
|
|
125
|
+
if (typeof raw.autoApprove === 'boolean')
|
|
126
|
+
out.autoApprove = raw.autoApprove;
|
|
127
|
+
if (typeof raw.autoFix === 'boolean')
|
|
128
|
+
out.autoFix = raw.autoFix;
|
|
129
|
+
if (typeof raw.lintCmd === 'string')
|
|
130
|
+
out.lintCmd = raw.lintCmd;
|
|
131
|
+
if (typeof raw.testCmd === 'string')
|
|
132
|
+
out.testCmd = raw.testCmd;
|
|
133
|
+
const logLevel = parseLogLevel(raw.logLevel);
|
|
134
|
+
if (logLevel)
|
|
135
|
+
out.logLevel = logLevel;
|
|
136
|
+
const theme = parseTheme(raw.theme);
|
|
137
|
+
if (theme)
|
|
138
|
+
out.theme = theme;
|
|
139
|
+
const reasoningEffort = parseReasoningEffort(raw.reasoningEffort);
|
|
140
|
+
if (reasoningEffort)
|
|
141
|
+
out.reasoningEffort = reasoningEffort;
|
|
142
|
+
const thinkTokens = parseThinkTokens(raw.thinkTokens);
|
|
143
|
+
if (thinkTokens !== undefined)
|
|
144
|
+
out.thinkTokens = thinkTokens;
|
|
145
|
+
return out;
|
|
146
|
+
}
|
|
147
|
+
export function rcFilePath() {
|
|
148
|
+
const configured = process.env.ICOPILOT_RC_PATH || path.join(HOME, '.icopilotrc.json');
|
|
149
|
+
if (configured === '~')
|
|
150
|
+
return os.homedir();
|
|
151
|
+
if (/^~[\\/]/.test(configured))
|
|
152
|
+
return path.join(os.homedir(), configured.slice(2));
|
|
153
|
+
return path.resolve(configured);
|
|
154
|
+
}
|
|
155
|
+
export function getDefaultConfig() {
|
|
156
|
+
return { ...DEFAULT_CONFIG };
|
|
157
|
+
}
|
|
158
|
+
export function loadRcFile() {
|
|
159
|
+
const rcPath = rcFilePath();
|
|
160
|
+
try {
|
|
161
|
+
if (!fs.existsSync(rcPath))
|
|
162
|
+
return {};
|
|
163
|
+
const parsed = JSON.parse(fs.readFileSync(rcPath, 'utf8'));
|
|
164
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed))
|
|
165
|
+
return {};
|
|
166
|
+
return normalizeConfig(parsed);
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
if (process.env.ICOPILOT_LOG_LEVEL === 'debug' || parseBool(process.env.ICOPILOT_VERBOSE)) {
|
|
170
|
+
process.stderr.write(`debug: failed to load ${rcPath}: ${err?.message || err}\n`);
|
|
171
|
+
}
|
|
172
|
+
return {};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function envConfig() {
|
|
176
|
+
const out = {};
|
|
177
|
+
if (process.env.ICOPILOT_PROVIDER)
|
|
178
|
+
out.provider = process.env.ICOPILOT_PROVIDER;
|
|
179
|
+
if (process.env.ICOPILOT_ENDPOINT)
|
|
180
|
+
out.endpoint = process.env.ICOPILOT_ENDPOINT;
|
|
181
|
+
if (process.env.ICOPILOT_TOKEN)
|
|
182
|
+
out.token = process.env.ICOPILOT_TOKEN;
|
|
183
|
+
if (process.env.ICOPILOT_MODEL)
|
|
184
|
+
out.defaultModel = process.env.ICOPILOT_MODEL;
|
|
185
|
+
const editFormat = parseEditFormat(process.env.ICOPILOT_EDIT_FORMAT);
|
|
186
|
+
if (editFormat)
|
|
187
|
+
out.editFormat = editFormat;
|
|
188
|
+
const autoLint = parseBool(process.env.ICOPILOT_AUTO_LINT);
|
|
189
|
+
if (autoLint !== undefined)
|
|
190
|
+
out.autoLint = autoLint;
|
|
191
|
+
const autoTest = parseBool(process.env.ICOPILOT_AUTO_TEST);
|
|
192
|
+
if (autoTest !== undefined)
|
|
193
|
+
out.autoTest = autoTest;
|
|
194
|
+
if (process.env.ICOPILOT_SESSION_DIR)
|
|
195
|
+
out.sessionDir = process.env.ICOPILOT_SESSION_DIR;
|
|
196
|
+
if (process.env.ICOPILOT_CTX_WINDOW)
|
|
197
|
+
out.contextWindow = Number(process.env.ICOPILOT_CTX_WINDOW);
|
|
198
|
+
const autoCompact = parseBool(process.env.ICOPILOT_AUTO_COMPACT);
|
|
199
|
+
if (autoCompact !== undefined)
|
|
200
|
+
out.autoCompact = autoCompact;
|
|
201
|
+
if (process.env.ICOPILOT_AUTO_COMPACT_THRESHOLD) {
|
|
202
|
+
out.autoCompactThreshold = Number(process.env.ICOPILOT_AUTO_COMPACT_THRESHOLD);
|
|
203
|
+
}
|
|
204
|
+
const verbose = parseBool(process.env.ICOPILOT_VERBOSE);
|
|
205
|
+
if (verbose !== undefined)
|
|
206
|
+
out.verbose = verbose;
|
|
207
|
+
const logLevel = parseLogLevel(process.env.ICOPILOT_LOG_LEVEL);
|
|
208
|
+
if (logLevel)
|
|
209
|
+
out.logLevel = logLevel;
|
|
210
|
+
const sandbox = parseBool(process.env.ICOPILOT_SANDBOX);
|
|
211
|
+
if (sandbox !== undefined)
|
|
212
|
+
out.sandbox = sandbox;
|
|
213
|
+
if (process.env.ICOPILOT_POLICY)
|
|
214
|
+
out.policyPath = process.env.ICOPILOT_POLICY;
|
|
215
|
+
const theme = parseTheme(process.env.ICOPILOT_THEME);
|
|
216
|
+
if (theme)
|
|
217
|
+
out.theme = theme;
|
|
218
|
+
const jsonOutput = parseBool(process.env.ICOPILOT_JSON);
|
|
219
|
+
if (jsonOutput !== undefined)
|
|
220
|
+
out.jsonOutput = jsonOutput;
|
|
221
|
+
const quiet = parseBool(process.env.ICOPILOT_QUIET);
|
|
222
|
+
if (quiet !== undefined)
|
|
223
|
+
out.quiet = quiet;
|
|
224
|
+
const autoApprove = parseBool(process.env.ICOPILOT_AUTO_APPROVE);
|
|
225
|
+
if (autoApprove !== undefined)
|
|
226
|
+
out.autoApprove = autoApprove;
|
|
227
|
+
const autoFix = parseBool(process.env.ICOPILOT_AUTO_FIX);
|
|
228
|
+
if (autoFix !== undefined)
|
|
229
|
+
out.autoFix = autoFix;
|
|
230
|
+
if (process.env.ICOPILOT_LINT_CMD)
|
|
231
|
+
out.lintCmd = process.env.ICOPILOT_LINT_CMD;
|
|
232
|
+
if (process.env.ICOPILOT_TEST_CMD)
|
|
233
|
+
out.testCmd = process.env.ICOPILOT_TEST_CMD;
|
|
234
|
+
const reasoningEffort = parseReasoningEffort(process.env.ICOPILOT_REASONING_EFFORT);
|
|
235
|
+
if (reasoningEffort)
|
|
236
|
+
out.reasoningEffort = reasoningEffort;
|
|
237
|
+
const thinkTokens = parseThinkTokens(process.env.ICOPILOT_THINK_TOKENS);
|
|
238
|
+
if (thinkTokens !== undefined)
|
|
239
|
+
out.thinkTokens = thinkTokens;
|
|
240
|
+
return out;
|
|
241
|
+
}
|
|
242
|
+
function finalizeConfig(raw) {
|
|
243
|
+
const activeProvider = providerRegistry.getActive();
|
|
244
|
+
const requestedProvider = typeof raw.provider === 'string' && raw.provider.trim() ? raw.provider.trim() : undefined;
|
|
245
|
+
const provider = (requestedProvider &&
|
|
246
|
+
(requestedProvider !== DEFAULT_CONFIG.provider ||
|
|
247
|
+
activeProvider.name === DEFAULT_CONFIG.provider)
|
|
248
|
+
? providerRegistry.get(requestedProvider)
|
|
249
|
+
: undefined) ||
|
|
250
|
+
activeProvider ||
|
|
251
|
+
providerRegistry.get('github');
|
|
252
|
+
if (!provider)
|
|
253
|
+
return raw;
|
|
254
|
+
const useProviderEndpoint = !raw.endpoint ||
|
|
255
|
+
(raw.endpoint === DEFAULT_CONFIG.endpoint && provider.baseUrl !== DEFAULT_CONFIG.endpoint);
|
|
256
|
+
const useProviderModel = !raw.defaultModel ||
|
|
257
|
+
(raw.defaultModel === DEFAULT_CONFIG.defaultModel &&
|
|
258
|
+
(provider.defaultModel || provider.models[0] || DEFAULT_CONFIG.defaultModel) !==
|
|
259
|
+
DEFAULT_CONFIG.defaultModel);
|
|
260
|
+
return {
|
|
261
|
+
...raw,
|
|
262
|
+
provider: provider.name,
|
|
263
|
+
endpoint: useProviderEndpoint ? provider.baseUrl : raw.endpoint,
|
|
264
|
+
token: raw.token || resolveProviderApiKey(provider),
|
|
265
|
+
defaultModel: useProviderModel
|
|
266
|
+
? provider.defaultModel || provider.models[0] || DEFAULT_CONFIG.defaultModel
|
|
267
|
+
: raw.defaultModel,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
export const config = finalizeConfig({
|
|
271
|
+
...DEFAULT_CONFIG,
|
|
272
|
+
...loadRcFile(),
|
|
273
|
+
...envConfig(),
|
|
274
|
+
});
|
|
275
|
+
export function setProvider(name, options = {}) {
|
|
276
|
+
const provider = options.persist === false ? providerRegistry.get(name) : providerRegistry.setActive(name);
|
|
277
|
+
if (!provider) {
|
|
278
|
+
throw new Error(`unknown provider: ${name}`);
|
|
279
|
+
}
|
|
280
|
+
config.provider = provider.name;
|
|
281
|
+
config.endpoint = provider.baseUrl;
|
|
282
|
+
config.token = resolveProviderApiKey(provider) || config.token;
|
|
283
|
+
if (provider.defaultModel)
|
|
284
|
+
config.defaultModel = provider.defaultModel;
|
|
285
|
+
}
|
|
286
|
+
export function requireToken() {
|
|
287
|
+
return config.token || 'not-needed';
|
|
288
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { streamChat } from '../api/github-models.js';
|
|
2
|
+
import { hookManager } from '../hooks/lifecycle.js';
|
|
3
|
+
import { theme } from '../ui/theme.js';
|
|
4
|
+
const SUMMARY_PROMPT = `You are summarizing a developer/AI assistant conversation to preserve essential context while drastically reducing token usage.
|
|
5
|
+
Produce a structured summary with these sections (omit empty ones):
|
|
6
|
+
- **Goals**: what the user is trying to achieve
|
|
7
|
+
- **Decisions**: key choices made
|
|
8
|
+
- **Files touched**: paths + 1-line purpose
|
|
9
|
+
- **Open questions**: unresolved items
|
|
10
|
+
- **Next steps**: what to do next
|
|
11
|
+
Keep it under 400 words.`;
|
|
12
|
+
export async function compactSession(session, signal) {
|
|
13
|
+
await hookManager.emit('preCompact', {
|
|
14
|
+
sessionId: session.state.id,
|
|
15
|
+
cwd: session.state.cwd,
|
|
16
|
+
messageCount: session.state.messages.length,
|
|
17
|
+
});
|
|
18
|
+
const history = session.state.messages
|
|
19
|
+
.map((m) => {
|
|
20
|
+
const c = typeof m.content === 'string' ? m.content : JSON.stringify(m.content ?? '');
|
|
21
|
+
return `### ${m.role}\n${c}`;
|
|
22
|
+
})
|
|
23
|
+
.join('\n\n');
|
|
24
|
+
const messages = [
|
|
25
|
+
{ role: 'system', content: SUMMARY_PROMPT },
|
|
26
|
+
{ role: 'user', content: history || '(empty conversation)' },
|
|
27
|
+
];
|
|
28
|
+
process.stdout.write(theme.dim('Compacting history…\n'));
|
|
29
|
+
let acc = '';
|
|
30
|
+
const res = await streamChat({
|
|
31
|
+
model: session.state.model,
|
|
32
|
+
messages,
|
|
33
|
+
temperature: 0,
|
|
34
|
+
signal,
|
|
35
|
+
onToken: (t) => {
|
|
36
|
+
acc += t;
|
|
37
|
+
process.stdout.write(theme.dim(t));
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
process.stdout.write('\n');
|
|
41
|
+
const summary = res.content || acc;
|
|
42
|
+
const hookResult = await hookManager.emit('postCompact', {
|
|
43
|
+
sessionId: session.state.id,
|
|
44
|
+
cwd: session.state.cwd,
|
|
45
|
+
messageCount: session.state.messages.length,
|
|
46
|
+
summary,
|
|
47
|
+
});
|
|
48
|
+
if (hookResult.action === 'modify' &&
|
|
49
|
+
typeof hookResult.modifications?.summary === 'string') {
|
|
50
|
+
return String(hookResult.modifications.summary);
|
|
51
|
+
}
|
|
52
|
+
return summary;
|
|
53
|
+
}
|