@chrisromp/copilot-bridge 0.6.0-dev.2
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/LICENSE +21 -0
- package/README.md +93 -0
- package/bin/copilot-bridge.js +61 -0
- package/config.sample.json +100 -0
- package/dist/channels/mattermost/adapter.d.ts +55 -0
- package/dist/channels/mattermost/adapter.d.ts.map +1 -0
- package/dist/channels/mattermost/adapter.js +524 -0
- package/dist/channels/mattermost/adapter.js.map +1 -0
- package/dist/channels/mattermost/streaming.d.ts +29 -0
- package/dist/channels/mattermost/streaming.d.ts.map +1 -0
- package/dist/channels/mattermost/streaming.js +151 -0
- package/dist/channels/mattermost/streaming.js.map +1 -0
- package/dist/config.d.ts +107 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +817 -0
- package/dist/config.js.map +1 -0
- package/dist/core/bridge.d.ts +73 -0
- package/dist/core/bridge.d.ts.map +1 -0
- package/dist/core/bridge.js +166 -0
- package/dist/core/bridge.js.map +1 -0
- package/dist/core/channel-idle.d.ts +40 -0
- package/dist/core/channel-idle.d.ts.map +1 -0
- package/dist/core/channel-idle.js +120 -0
- package/dist/core/channel-idle.js.map +1 -0
- package/dist/core/command-handler.d.ts +51 -0
- package/dist/core/command-handler.d.ts.map +1 -0
- package/dist/core/command-handler.js +393 -0
- package/dist/core/command-handler.js.map +1 -0
- package/dist/core/inter-agent.d.ts +52 -0
- package/dist/core/inter-agent.d.ts.map +1 -0
- package/dist/core/inter-agent.js +179 -0
- package/dist/core/inter-agent.js.map +1 -0
- package/dist/core/onboarding.d.ts +44 -0
- package/dist/core/onboarding.d.ts.map +1 -0
- package/dist/core/onboarding.js +205 -0
- package/dist/core/onboarding.js.map +1 -0
- package/dist/core/scheduler.d.ts +38 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +253 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/session-manager.d.ts +166 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +1732 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/stream-formatter.d.ts +14 -0
- package/dist/core/stream-formatter.d.ts.map +1 -0
- package/dist/core/stream-formatter.js +198 -0
- package/dist/core/stream-formatter.js.map +1 -0
- package/dist/core/thread-utils.d.ts +22 -0
- package/dist/core/thread-utils.d.ts.map +1 -0
- package/dist/core/thread-utils.js +44 -0
- package/dist/core/thread-utils.js.map +1 -0
- package/dist/core/workspace-manager.d.ts +38 -0
- package/dist/core/workspace-manager.d.ts.map +1 -0
- package/dist/core/workspace-manager.js +230 -0
- package/dist/core/workspace-manager.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1286 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +34 -0
- package/dist/logger.js.map +1 -0
- package/dist/state/store.d.ts +124 -0
- package/dist/state/store.d.ts.map +1 -0
- package/dist/state/store.js +523 -0
- package/dist/state/store.js.map +1 -0
- package/dist/types.d.ts +185 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -0
- package/scripts/check.ts +267 -0
- package/scripts/com.copilot-bridge.plist +41 -0
- package/scripts/copilot-bridge.service +30 -0
- package/scripts/init.ts +250 -0
- package/scripts/install-service.ts +123 -0
- package/scripts/lib/config-gen.ts +129 -0
- package/scripts/lib/mattermost.ts +109 -0
- package/scripts/lib/output.ts +69 -0
- package/scripts/lib/prerequisites.ts +86 -0
- package/scripts/lib/prompts.ts +65 -0
- package/scripts/lib/service.ts +191 -0
- package/scripts/uninstall-service.ts +90 -0
- package/templates/admin/AGENTS.md +325 -0
- package/templates/admin/MEMORY.md +4 -0
- package/templates/agents/AGENTS.md +97 -0
- package/templates/agents/MEMORY.md +4 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
import { setChannelPrefs, getChannelPrefs, getGlobalSetting, setGlobalSetting } from '../state/store.js';
|
|
2
|
+
const VALID_REASONING_EFFORTS = new Set(['low', 'medium', 'high', 'xhigh']);
|
|
3
|
+
const TRUTHY = new Set(['on', 'true', 'yes', '1', 'enable', 'enabled']);
|
|
4
|
+
const FALSY = new Set(['off', 'false', 'no', '0', 'disable', 'disabled']);
|
|
5
|
+
/** Parse a loose boolean string. Returns fallback if unrecognized. */
|
|
6
|
+
function parseBool(input, fallback) {
|
|
7
|
+
const v = input.toLowerCase().trim();
|
|
8
|
+
if (TRUTHY.has(v))
|
|
9
|
+
return true;
|
|
10
|
+
if (FALSY.has(v))
|
|
11
|
+
return false;
|
|
12
|
+
return fallback;
|
|
13
|
+
}
|
|
14
|
+
/** Check if a model should be hidden in streamer mode. */
|
|
15
|
+
function isHiddenModel(model) {
|
|
16
|
+
return /\((preview|internal\b)[^)]*\)/i.test(model.name);
|
|
17
|
+
}
|
|
18
|
+
/** Get the redacted display name for a hidden model. */
|
|
19
|
+
function redactedModelLabel(index) {
|
|
20
|
+
return `Hidden Model ${index}`;
|
|
21
|
+
}
|
|
22
|
+
/** Check if streamer mode is currently enabled. */
|
|
23
|
+
function isStreamerMode() {
|
|
24
|
+
return getGlobalSetting('streamer_mode') === '1';
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Fuzzy-match user input to a model from the available list.
|
|
28
|
+
* Always tries to pick the best match. Returns:
|
|
29
|
+
* - { model, alternatives } on success (alternatives may be empty)
|
|
30
|
+
* - { error } only when truly no match is found
|
|
31
|
+
*/
|
|
32
|
+
export function resolveModel(input, models) {
|
|
33
|
+
const lower = input.toLowerCase().trim();
|
|
34
|
+
if (!lower)
|
|
35
|
+
return { error: '⚠️ Please specify a model name.' };
|
|
36
|
+
// Exact match on id or name
|
|
37
|
+
const exact = models.find(m => m.id.toLowerCase() === lower || m.name.toLowerCase() === lower);
|
|
38
|
+
if (exact)
|
|
39
|
+
return { model: exact, alternatives: [] };
|
|
40
|
+
// Substring match: input appears in id or name
|
|
41
|
+
const substringMatches = models.filter(m => m.id.toLowerCase().includes(lower) || m.name.toLowerCase().includes(lower));
|
|
42
|
+
if (substringMatches.length === 1)
|
|
43
|
+
return { model: substringMatches[0], alternatives: [] };
|
|
44
|
+
// Token match: all words in input appear in id or name
|
|
45
|
+
const tokens = lower.split(/[\s\-_.]+/).filter(Boolean);
|
|
46
|
+
const tokenMatches = models.filter(m => {
|
|
47
|
+
const haystack = `${m.id} ${m.name}`.toLowerCase();
|
|
48
|
+
return tokens.every(t => haystack.includes(t));
|
|
49
|
+
});
|
|
50
|
+
if (tokenMatches.length === 1)
|
|
51
|
+
return { model: tokenMatches[0], alternatives: [] };
|
|
52
|
+
// Multiple matches — pick the best one
|
|
53
|
+
const candidates = (substringMatches.length > 0 ? substringMatches : tokenMatches).slice(0, 8);
|
|
54
|
+
if (candidates.length > 1) {
|
|
55
|
+
const best = pickBestMatch(lower, candidates);
|
|
56
|
+
const alternatives = candidates.filter(m => m.id !== best.id);
|
|
57
|
+
return { model: best, alternatives };
|
|
58
|
+
}
|
|
59
|
+
return { error: `⚠️ Unknown model "${input}". Use \`/model\` to see available models.` };
|
|
60
|
+
}
|
|
61
|
+
/** Pick the best model from ambiguous candidates. Prefers shorter IDs and closer matches. */
|
|
62
|
+
function pickBestMatch(input, candidates) {
|
|
63
|
+
return candidates.sort((a, b) => {
|
|
64
|
+
// Prefer exact id prefix match (e.g., "opus" matching "claude-opus-4.6" not "claude-opus-4.6-1m")
|
|
65
|
+
const aStartsId = a.id.toLowerCase().endsWith(input) ? 1 : 0;
|
|
66
|
+
const bStartsId = b.id.toLowerCase().endsWith(input) ? 1 : 0;
|
|
67
|
+
if (aStartsId !== bStartsId)
|
|
68
|
+
return bStartsId - aStartsId;
|
|
69
|
+
// Prefer shorter ID (base model vs specialized variant)
|
|
70
|
+
if (a.id.length !== b.id.length)
|
|
71
|
+
return a.id.length - b.id.length;
|
|
72
|
+
// Prefer shorter name
|
|
73
|
+
return a.name.length - b.name.length;
|
|
74
|
+
})[0];
|
|
75
|
+
}
|
|
76
|
+
/** Format a token count as a human-readable string (e.g., 109000 → "109k"). */
|
|
77
|
+
function formatTokens(n) {
|
|
78
|
+
if (n >= 1000)
|
|
79
|
+
return `${Math.round(n / 1000)}k`;
|
|
80
|
+
return String(n);
|
|
81
|
+
}
|
|
82
|
+
/** Format context usage as a one-line summary. */
|
|
83
|
+
function formatContextUsage(usage) {
|
|
84
|
+
if (usage.tokenLimit <= 0) {
|
|
85
|
+
return `${formatTokens(usage.currentTokens)}/? tokens`;
|
|
86
|
+
}
|
|
87
|
+
const pct = Math.round((usage.currentTokens / usage.tokenLimit) * 100);
|
|
88
|
+
return `${formatTokens(usage.currentTokens)}/${formatTokens(usage.tokenLimit)} tokens (${pct}%)`;
|
|
89
|
+
}
|
|
90
|
+
export function parseCommand(text) {
|
|
91
|
+
const trimmed = text.trim();
|
|
92
|
+
if (!trimmed.startsWith('/'))
|
|
93
|
+
return null;
|
|
94
|
+
const spaceIdx = trimmed.indexOf(' ');
|
|
95
|
+
if (spaceIdx === -1)
|
|
96
|
+
return { command: trimmed.slice(1).toLowerCase(), args: '' };
|
|
97
|
+
return {
|
|
98
|
+
command: trimmed.slice(1, spaceIdx).toLowerCase(),
|
|
99
|
+
args: trimmed.slice(spaceIdx + 1).trim(),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function handleCommand(channelId, text, sessionInfo, effectivePrefs, channelMeta, models, mcpInfo, contextUsage) {
|
|
103
|
+
const parsed = parseCommand(text);
|
|
104
|
+
if (!parsed)
|
|
105
|
+
return { handled: false };
|
|
106
|
+
// Resolve current model's info from models list
|
|
107
|
+
const currentModelInfo = models && sessionInfo
|
|
108
|
+
? models.find(m => m.id === sessionInfo.model) ?? null
|
|
109
|
+
: null;
|
|
110
|
+
switch (parsed.command) {
|
|
111
|
+
case 'new':
|
|
112
|
+
return { handled: true, action: 'new_session', response: '🔄 Creating new session...' };
|
|
113
|
+
case 'stop':
|
|
114
|
+
case 'cancel':
|
|
115
|
+
return { handled: true, action: 'stop_session', response: '🛑 Stopping current task...' };
|
|
116
|
+
case 'reload':
|
|
117
|
+
if (parsed.args?.trim().toLowerCase() === 'config') {
|
|
118
|
+
return { handled: true, action: 'reload_config', response: '🔄 Reloading config...' };
|
|
119
|
+
}
|
|
120
|
+
return { handled: true, action: 'reload_session', response: '🔄 Reloading session...' };
|
|
121
|
+
case 'resume': {
|
|
122
|
+
if (!parsed.args) {
|
|
123
|
+
// No args = list available sessions for this channel's working directory
|
|
124
|
+
return { handled: true, action: 'list_sessions', response: '📋 Fetching sessions...' };
|
|
125
|
+
}
|
|
126
|
+
return { handled: true, action: 'resume_session', payload: parsed.args.trim(), response: '🔄 Resuming session...' };
|
|
127
|
+
}
|
|
128
|
+
case 'model':
|
|
129
|
+
case 'models': {
|
|
130
|
+
if (!parsed.args) {
|
|
131
|
+
// No args: show model table
|
|
132
|
+
if (!models || models.length === 0) {
|
|
133
|
+
return { handled: true, response: '⚠️ Model list not available.' };
|
|
134
|
+
}
|
|
135
|
+
const streamer = isStreamerMode();
|
|
136
|
+
let hiddenIndex = 0;
|
|
137
|
+
const lines = [
|
|
138
|
+
'**Available Models**',
|
|
139
|
+
'',
|
|
140
|
+
'| Model | Billing | |',
|
|
141
|
+
'|:------|--------:|:--|',
|
|
142
|
+
];
|
|
143
|
+
for (const m of models) {
|
|
144
|
+
const current = sessionInfo?.model === m.id ? ' ← current' : '';
|
|
145
|
+
const reasoning = m.supportedReasoningEfforts?.length ? ' 🧠' : '';
|
|
146
|
+
const billing = m.billing ? `${m.billing.multiplier}x` : '—';
|
|
147
|
+
const hidden = streamer && isHiddenModel(m);
|
|
148
|
+
const displayName = hidden ? redactedModelLabel(++hiddenIndex) : `\`${m.id}\``;
|
|
149
|
+
lines.push(`| ${displayName} | ${billing} |${reasoning}${current} |`);
|
|
150
|
+
}
|
|
151
|
+
lines.push('', '🧠 = supports reasoning effort · Billing = premium request multiplier');
|
|
152
|
+
lines.push('↳ Use `/model <name>` to switch');
|
|
153
|
+
return { handled: true, response: lines.join('\n') };
|
|
154
|
+
}
|
|
155
|
+
if (!models || models.length === 0) {
|
|
156
|
+
return { handled: true, action: 'switch_model', payload: parsed.args, response: `🔄 Switching model to **${parsed.args}**...` };
|
|
157
|
+
}
|
|
158
|
+
const result = resolveModel(parsed.args, models);
|
|
159
|
+
if ('error' in result) {
|
|
160
|
+
return { handled: true, response: result.error };
|
|
161
|
+
}
|
|
162
|
+
const streamerSwitch = isStreamerMode();
|
|
163
|
+
const switchName = (streamerSwitch && isHiddenModel(result.model))
|
|
164
|
+
? 'a hidden model'
|
|
165
|
+
: `**${result.model.name}** (\`${result.model.id}\`)`;
|
|
166
|
+
let response = `✅ Switched to ${switchName}`;
|
|
167
|
+
if (result.alternatives.length > 0) {
|
|
168
|
+
const altList = result.alternatives
|
|
169
|
+
.filter(m => !(streamerSwitch && isHiddenModel(m)))
|
|
170
|
+
.map(m => `\`${m.id}\` (${m.name})`).join(', ');
|
|
171
|
+
if (altList)
|
|
172
|
+
response += `\n↳ Also matched: ${altList}`;
|
|
173
|
+
}
|
|
174
|
+
return { handled: true, action: 'switch_model', payload: result.model.id, response };
|
|
175
|
+
}
|
|
176
|
+
case 'agent': {
|
|
177
|
+
const agent = parsed.args || null;
|
|
178
|
+
return {
|
|
179
|
+
handled: true,
|
|
180
|
+
action: 'switch_agent',
|
|
181
|
+
payload: agent,
|
|
182
|
+
response: agent ? `✅ Switched to agent **${agent}**` : '✅ Agent deselected (using default Copilot)',
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
case 'verbose': {
|
|
186
|
+
const prefs = getChannelPrefs(channelId);
|
|
187
|
+
const current = effectivePrefs?.verbose ?? prefs?.verbose ?? false;
|
|
188
|
+
const newVerbose = parsed.args ? parseBool(parsed.args, !current) : !current;
|
|
189
|
+
setChannelPrefs(channelId, { verbose: newVerbose });
|
|
190
|
+
return {
|
|
191
|
+
handled: true,
|
|
192
|
+
action: 'toggle_verbose',
|
|
193
|
+
response: newVerbose ? '🔊 Verbose mode **enabled** — tool calls will be shown.' : '🔇 Verbose mode **disabled** — only final responses shown.',
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
case 'reasoning': {
|
|
197
|
+
const level = parsed.args.toLowerCase();
|
|
198
|
+
if (!level) {
|
|
199
|
+
const current = effectivePrefs?.reasoningEffort ?? 'default';
|
|
200
|
+
return { handled: true, response: `🧠 Current reasoning effort: **${current}**\nUsage: \`/reasoning <low|medium|high|xhigh>\`` };
|
|
201
|
+
}
|
|
202
|
+
if (!VALID_REASONING_EFFORTS.has(level)) {
|
|
203
|
+
return { handled: true, response: `⚠️ Invalid reasoning effort. Valid values: \`low\`, \`medium\`, \`high\`, \`xhigh\`` };
|
|
204
|
+
}
|
|
205
|
+
if (currentModelInfo && currentModelInfo.supportedReasoningEfforts && !currentModelInfo.supportedReasoningEfforts.includes(level)) {
|
|
206
|
+
const reasoningModelName = (isStreamerMode() && isHiddenModel(currentModelInfo))
|
|
207
|
+
? 'the current model'
|
|
208
|
+
: `**${sessionInfo?.model ?? 'unknown'}**`;
|
|
209
|
+
return { handled: true, response: `⚠️ Model ${reasoningModelName} does not support reasoning effort.\nSupported models include Opus and other reasoning-capable models.` };
|
|
210
|
+
}
|
|
211
|
+
setChannelPrefs(channelId, { reasoningEffort: level });
|
|
212
|
+
return {
|
|
213
|
+
handled: true,
|
|
214
|
+
action: 'set_reasoning',
|
|
215
|
+
payload: level,
|
|
216
|
+
response: `🧠 Reasoning effort set to **${level}**. Takes effect on next session (\`/new\`).`,
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
case 'status': {
|
|
220
|
+
if (!sessionInfo) {
|
|
221
|
+
return { handled: true, response: '📊 No active session for this channel.' };
|
|
222
|
+
}
|
|
223
|
+
const prefs = getChannelPrefs(channelId);
|
|
224
|
+
const streamerStatus = isStreamerMode();
|
|
225
|
+
const modelDisplay = (streamerStatus && currentModelInfo && isHiddenModel(currentModelInfo))
|
|
226
|
+
? 'Hidden Model'
|
|
227
|
+
: sessionInfo.model;
|
|
228
|
+
const lines = [
|
|
229
|
+
'📊 **Session Status**',
|
|
230
|
+
`• Session: \`${sessionInfo.sessionId.slice(0, 8)}...\``,
|
|
231
|
+
`• Model: **${modelDisplay}**`,
|
|
232
|
+
`• Agent: ${sessionInfo.agent ? `**${sessionInfo.agent}**` : 'Default (Copilot)'}`,
|
|
233
|
+
`• Workspace: \`${channelMeta?.workingDirectory ?? 'unknown'}\``,
|
|
234
|
+
`• Bot: ${channelMeta?.bot ? `@${channelMeta.bot}` : 'default'}`,
|
|
235
|
+
`• Verbose: ${(effectivePrefs?.verbose ?? prefs?.verbose) ? '🔊 On' : '🔇 Off'}`,
|
|
236
|
+
`• Permission mode: ${(effectivePrefs?.permissionMode ?? prefs?.permissionMode) === 'autopilot' ? '🤖 Autopilot' : '🛡️ Interactive'}`,
|
|
237
|
+
];
|
|
238
|
+
// Only show reasoning effort for models that support it
|
|
239
|
+
if (currentModelInfo?.supportedReasoningEfforts && currentModelInfo.supportedReasoningEfforts.length > 0) {
|
|
240
|
+
const current = effectivePrefs?.reasoningEffort ?? currentModelInfo.defaultReasoningEffort ?? 'default';
|
|
241
|
+
lines.push(`• Reasoning effort: 🧠 **${current}** (supports: ${currentModelInfo.supportedReasoningEfforts.join(', ')})`);
|
|
242
|
+
}
|
|
243
|
+
if (contextUsage) {
|
|
244
|
+
lines.push(`• Context: ${formatContextUsage(contextUsage)}`);
|
|
245
|
+
}
|
|
246
|
+
return { handled: true, response: lines.join('\n') };
|
|
247
|
+
}
|
|
248
|
+
case 'context': {
|
|
249
|
+
if (!contextUsage) {
|
|
250
|
+
return { handled: true, response: '📊 Context usage not available yet. Send a message first.' };
|
|
251
|
+
}
|
|
252
|
+
return { handled: true, response: `📊 **Context:** ${formatContextUsage(contextUsage)}` };
|
|
253
|
+
}
|
|
254
|
+
case 'approve':
|
|
255
|
+
return { handled: true, action: 'approve', response: '✅ Approved.' };
|
|
256
|
+
case 'deny':
|
|
257
|
+
return { handled: true, action: 'deny', response: '❌ Denied.' };
|
|
258
|
+
case 'autopilot':
|
|
259
|
+
case 'yolo': {
|
|
260
|
+
const prefs = getChannelPrefs(channelId);
|
|
261
|
+
const current = effectivePrefs?.permissionMode ?? prefs?.permissionMode ?? 'interactive';
|
|
262
|
+
const newMode = current === 'autopilot' ? 'interactive' : 'autopilot';
|
|
263
|
+
setChannelPrefs(channelId, { permissionMode: newMode });
|
|
264
|
+
return {
|
|
265
|
+
handled: true,
|
|
266
|
+
action: 'toggle_autopilot',
|
|
267
|
+
response: newMode === 'autopilot'
|
|
268
|
+
? '🤖 **Autopilot enabled** — all permissions auto-approved.'
|
|
269
|
+
: '🛡️ **Interactive mode** — permissions will require approval.',
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
case 'remember':
|
|
273
|
+
case 'rule':
|
|
274
|
+
case 'rules': {
|
|
275
|
+
const sub = parsed.args.trim().toLowerCase();
|
|
276
|
+
if (sub === 'list' || (parsed.command !== 'remember' && !sub)) {
|
|
277
|
+
return { handled: true, action: 'remember_list' };
|
|
278
|
+
}
|
|
279
|
+
if (sub === 'clear' || sub.startsWith('clear ')) {
|
|
280
|
+
const spec = parsed.args.trim().slice(5).trim(); // everything after "clear"
|
|
281
|
+
return { handled: true, action: 'remember_clear', payload: spec || undefined };
|
|
282
|
+
}
|
|
283
|
+
return { handled: true, action: 'remember' };
|
|
284
|
+
}
|
|
285
|
+
case 'mcp': {
|
|
286
|
+
if (!mcpInfo || mcpInfo.length === 0) {
|
|
287
|
+
return { handled: true, response: '🔌 No MCP servers configured.' };
|
|
288
|
+
}
|
|
289
|
+
const userServers = mcpInfo.filter(s => s.source === 'user');
|
|
290
|
+
const workspaceServers = mcpInfo.filter(s => s.source === 'workspace');
|
|
291
|
+
const overrideServers = mcpInfo.filter(s => s.source === 'workspace (override)');
|
|
292
|
+
const lines = ['🔌 **MCP Servers**', ''];
|
|
293
|
+
if (userServers.length > 0) {
|
|
294
|
+
lines.push('**User** (plugin + user config)');
|
|
295
|
+
for (const s of userServers)
|
|
296
|
+
lines.push(`• \`${s.name}\``);
|
|
297
|
+
lines.push('');
|
|
298
|
+
}
|
|
299
|
+
if (workspaceServers.length > 0) {
|
|
300
|
+
lines.push('**Workspace**');
|
|
301
|
+
for (const s of workspaceServers)
|
|
302
|
+
lines.push(`• \`${s.name}\``);
|
|
303
|
+
lines.push('');
|
|
304
|
+
}
|
|
305
|
+
if (overrideServers.length > 0) {
|
|
306
|
+
lines.push('**Workspace (overriding user)**');
|
|
307
|
+
for (const s of overrideServers)
|
|
308
|
+
lines.push(`• \`${s.name}\``);
|
|
309
|
+
lines.push('');
|
|
310
|
+
}
|
|
311
|
+
lines.push(`Total: ${mcpInfo.length} server(s)`);
|
|
312
|
+
return { handled: true, response: lines.join('\n') };
|
|
313
|
+
}
|
|
314
|
+
case 'streamer-mode':
|
|
315
|
+
case 'on-air': {
|
|
316
|
+
const current = isStreamerMode();
|
|
317
|
+
const newValue = parsed.args ? parseBool(parsed.args, !current) : !current;
|
|
318
|
+
setGlobalSetting('streamer_mode', newValue ? '1' : '0');
|
|
319
|
+
return {
|
|
320
|
+
handled: true,
|
|
321
|
+
response: newValue
|
|
322
|
+
? '📺 **Streamer mode enabled** — preview and internal models are hidden.'
|
|
323
|
+
: '📺 **Streamer mode disabled** — all models visible.',
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
case 'schedule':
|
|
327
|
+
case 'schedules':
|
|
328
|
+
case 'tasks':
|
|
329
|
+
return { handled: true, action: 'schedule', payload: parsed.args?.trim() };
|
|
330
|
+
case 'skills':
|
|
331
|
+
case 'tools':
|
|
332
|
+
return { handled: true, action: 'skills' };
|
|
333
|
+
case 'help': {
|
|
334
|
+
const showAll = parsed.args?.trim().toLowerCase() === 'all';
|
|
335
|
+
const common = [
|
|
336
|
+
'**Commands**',
|
|
337
|
+
'`/new` — Start a new session',
|
|
338
|
+
'`/stop` — Stop the current task',
|
|
339
|
+
'`/model [name]` — List or switch models',
|
|
340
|
+
'`/status` — Show session info',
|
|
341
|
+
'`/context` — Show context window usage',
|
|
342
|
+
'`/verbose` — Toggle tool call visibility',
|
|
343
|
+
'`/autopilot` — Toggle auto-approve mode',
|
|
344
|
+
'`/schedule list` — List scheduled tasks',
|
|
345
|
+
'`/skills` — Show available skills and MCP tools',
|
|
346
|
+
'`/help all` — Show all commands',
|
|
347
|
+
];
|
|
348
|
+
if (!showAll)
|
|
349
|
+
return { handled: true, response: common.join('\n') };
|
|
350
|
+
return {
|
|
351
|
+
handled: true,
|
|
352
|
+
response: [
|
|
353
|
+
'**All Commands**',
|
|
354
|
+
'',
|
|
355
|
+
'**Session**',
|
|
356
|
+
'`/new` — Start a new session',
|
|
357
|
+
'`/stop` — Stop the current task (alias: `/cancel`)',
|
|
358
|
+
'`/reload` — Reload session (re-reads AGENTS.md, workspace config)',
|
|
359
|
+
'`/reload config` — Hot-reload config.json',
|
|
360
|
+
'`/resume [id]` — Resume current session (or a past one by ID)',
|
|
361
|
+
'`/model [name]` — List models or switch model (fuzzy match)',
|
|
362
|
+
'`/agent <name>` — Switch custom agent (empty to deselect)',
|
|
363
|
+
'`/reasoning <level>` — Set reasoning effort (low/medium/high/xhigh)',
|
|
364
|
+
'`/context` — Show context window usage',
|
|
365
|
+
'`/verbose` — Toggle tool call visibility',
|
|
366
|
+
'`/status` — Show session info',
|
|
367
|
+
'',
|
|
368
|
+
'**Permissions**',
|
|
369
|
+
'`/approve` / `/deny` — Handle pending permission',
|
|
370
|
+
'`/remember` — Approve + save permission rule',
|
|
371
|
+
'`/rules` — Show all permission rules',
|
|
372
|
+
'`/rules clear [spec]` — Clear rules (all or specific)',
|
|
373
|
+
'`/autopilot` — Toggle auto-approve mode (alias: `/yolo`)',
|
|
374
|
+
'',
|
|
375
|
+
'**Scheduling**',
|
|
376
|
+
'`/schedule list` — List scheduled tasks (aliases: `/schedules`, `/tasks`)',
|
|
377
|
+
'`/schedule cancel <id>` — Cancel a scheduled task',
|
|
378
|
+
'`/schedule pause|resume <id>` — Pause or resume a task',
|
|
379
|
+
'`/schedule history [n]` — Show recent task execution history',
|
|
380
|
+
'',
|
|
381
|
+
'**Tools & Info**',
|
|
382
|
+
'`/skills` — Show available skills and MCP tools',
|
|
383
|
+
'`/mcp` — Show MCP servers and their source',
|
|
384
|
+
'`/streamer-mode [on|off]` — Toggle streamer mode',
|
|
385
|
+
'`/help` — Show common commands',
|
|
386
|
+
].join('\n'),
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
default:
|
|
390
|
+
return { handled: false };
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
//# sourceMappingURL=command-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-handler.js","sourceRoot":"","sources":["../../src/core/command-handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { InterAgentConfig } from '../types.js';
|
|
2
|
+
export interface InterAgentContext {
|
|
3
|
+
chainId: string;
|
|
4
|
+
visited: string[];
|
|
5
|
+
depth: number;
|
|
6
|
+
callerBot: string;
|
|
7
|
+
callerChannel: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BotWorkspaceEntry {
|
|
10
|
+
channelName: string;
|
|
11
|
+
channelId: string;
|
|
12
|
+
workingDirectory: string;
|
|
13
|
+
}
|
|
14
|
+
export interface AgentDefinition {
|
|
15
|
+
name: string;
|
|
16
|
+
content: string;
|
|
17
|
+
filePath: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Check whether callerBot is allowed to call targetBot given the current context.
|
|
21
|
+
* Returns null if allowed, or an error message if blocked.
|
|
22
|
+
*/
|
|
23
|
+
export declare function canCall(callerBot: string, targetBot: string, context: InterAgentContext, config?: InterAgentConfig): string | null;
|
|
24
|
+
/** Create a fresh InterAgentContext for a new call chain. */
|
|
25
|
+
export declare function createContext(callerBot: string, callerChannel: string): InterAgentContext;
|
|
26
|
+
/** Extend an existing context for the next hop in the chain. */
|
|
27
|
+
export declare function extendContext(context: InterAgentContext, nextBot: string): InterAgentContext;
|
|
28
|
+
/**
|
|
29
|
+
* Get all working directories for channels served by a given bot.
|
|
30
|
+
* Queries both static config and dynamic channels.
|
|
31
|
+
*/
|
|
32
|
+
export declare function getBotWorkspaceMap(botName: string): BotWorkspaceEntry[];
|
|
33
|
+
/**
|
|
34
|
+
* Build the system prompt context for workspace awareness.
|
|
35
|
+
* Lists all project workspaces the target bot has access to.
|
|
36
|
+
*/
|
|
37
|
+
export declare function buildWorkspacePrompt(workspaceMap: BotWorkspaceEntry[]): string;
|
|
38
|
+
/**
|
|
39
|
+
* Build the caller attribution section of the system prompt.
|
|
40
|
+
*/
|
|
41
|
+
export declare function buildCallerPrompt(context: InterAgentContext): string;
|
|
42
|
+
/**
|
|
43
|
+
* Discover *.agent.md files in a bot's workspace agents/ directory.
|
|
44
|
+
* Returns a map of agent name → definition.
|
|
45
|
+
*/
|
|
46
|
+
export declare function discoverAgentDefinitions(workspacePath: string): Map<string, AgentDefinition>;
|
|
47
|
+
/**
|
|
48
|
+
* Resolve which agent definition to use for an ephemeral session.
|
|
49
|
+
* Priority: explicit agent param → bot's default agent → none.
|
|
50
|
+
*/
|
|
51
|
+
export declare function resolveAgentDefinition(workspacePath: string, agentParam?: string, botDefaultAgent?: string | null): AgentDefinition | null;
|
|
52
|
+
//# sourceMappingURL=inter-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inter-agent.d.ts","sourceRoot":"","sources":["../../src/core/inter-agent.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAOpD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID;;;GAGG;AACH,wBAAgB,OAAO,CACrB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,iBAAiB,EAC1B,MAAM,CAAC,EAAE,gBAAgB,GACxB,MAAM,GAAG,IAAI,CAoCf;AAOD,6DAA6D;AAC7D,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,iBAAiB,CAQzF;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,OAAO,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAQ5F;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAgCvE;AAUD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,iBAAiB,EAAE,GAAG,MAAM,CAO9E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,MAAM,CAMpE;AAID;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,aAAa,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAwB5F;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,aAAa,EAAE,MAAM,EACrB,UAAU,CAAC,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,GAC9B,eAAe,GAAG,IAAI,CAWxB"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import crypto from 'node:crypto';
|
|
4
|
+
import { getConfig, getInterAgentConfig } from '../config.js';
|
|
5
|
+
import { getDynamicChannels } from '../state/store.js';
|
|
6
|
+
import { createLogger } from '../logger.js';
|
|
7
|
+
const log = createLogger('inter-agent');
|
|
8
|
+
// --- Loop Prevention ---
|
|
9
|
+
/**
|
|
10
|
+
* Check whether callerBot is allowed to call targetBot given the current context.
|
|
11
|
+
* Returns null if allowed, or an error message if blocked.
|
|
12
|
+
*/
|
|
13
|
+
export function canCall(callerBot, targetBot, context, config) {
|
|
14
|
+
const iaConfig = config ?? getInterAgentConfig();
|
|
15
|
+
// Gate: feature must be enabled
|
|
16
|
+
if (!iaConfig.enabled) {
|
|
17
|
+
return 'Inter-agent communication is disabled';
|
|
18
|
+
}
|
|
19
|
+
// Depth check
|
|
20
|
+
const maxDepth = iaConfig.maxDepth ?? 3;
|
|
21
|
+
if (context.depth >= maxDepth) {
|
|
22
|
+
return `Call chain depth limit reached (max ${maxDepth})`;
|
|
23
|
+
}
|
|
24
|
+
// Visited set: prevent cycles (A→B→A)
|
|
25
|
+
if (context.visited.includes(targetBot)) {
|
|
26
|
+
return `Cycle detected: ${targetBot} is already in the call chain [${context.visited.join(' → ')}]`;
|
|
27
|
+
}
|
|
28
|
+
// Allowlist: caller must have canCall permission for target
|
|
29
|
+
if (iaConfig.allow) {
|
|
30
|
+
const callerPerms = iaConfig.allow[callerBot];
|
|
31
|
+
if (!callerPerms?.canCall || !matchesAllowList(targetBot, callerPerms.canCall)) {
|
|
32
|
+
return `${callerBot} is not allowed to call ${targetBot}`;
|
|
33
|
+
}
|
|
34
|
+
const targetPerms = iaConfig.allow[targetBot];
|
|
35
|
+
if (!targetPerms?.canBeCalledBy || !matchesAllowList(callerBot, targetPerms.canBeCalledBy)) {
|
|
36
|
+
return `${targetBot} does not allow calls from ${callerBot}`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// No allowlist configured — block all cross-agent calls
|
|
41
|
+
return 'No inter-agent allowlist configured';
|
|
42
|
+
}
|
|
43
|
+
return null; // allowed
|
|
44
|
+
}
|
|
45
|
+
/** Check if a bot name matches an allowlist (supports "*" wildcard). */
|
|
46
|
+
function matchesAllowList(botName, allowList) {
|
|
47
|
+
return allowList.some(pattern => pattern === '*' || pattern === botName);
|
|
48
|
+
}
|
|
49
|
+
/** Create a fresh InterAgentContext for a new call chain. */
|
|
50
|
+
export function createContext(callerBot, callerChannel) {
|
|
51
|
+
return {
|
|
52
|
+
chainId: crypto.randomUUID(),
|
|
53
|
+
visited: [callerBot],
|
|
54
|
+
depth: 0,
|
|
55
|
+
callerBot,
|
|
56
|
+
callerChannel,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
/** Extend an existing context for the next hop in the chain. */
|
|
60
|
+
export function extendContext(context, nextBot) {
|
|
61
|
+
return {
|
|
62
|
+
chainId: context.chainId,
|
|
63
|
+
visited: [...context.visited, nextBot],
|
|
64
|
+
depth: context.depth + 1,
|
|
65
|
+
callerBot: context.visited[context.visited.length - 1],
|
|
66
|
+
callerChannel: context.callerChannel,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
// --- Workspace Awareness ---
|
|
70
|
+
/**
|
|
71
|
+
* Get all working directories for channels served by a given bot.
|
|
72
|
+
* Queries both static config and dynamic channels.
|
|
73
|
+
*/
|
|
74
|
+
export function getBotWorkspaceMap(botName) {
|
|
75
|
+
const config = getConfig();
|
|
76
|
+
const entries = [];
|
|
77
|
+
const seen = new Set(); // dedupe by channelId
|
|
78
|
+
// Static config channels
|
|
79
|
+
for (const ch of config.channels) {
|
|
80
|
+
const channelBot = ch.bot ?? getDefaultBotForPlatform(ch.platform);
|
|
81
|
+
if (channelBot === botName && !seen.has(ch.id)) {
|
|
82
|
+
seen.add(ch.id);
|
|
83
|
+
entries.push({
|
|
84
|
+
channelName: ch.name || ch.id,
|
|
85
|
+
channelId: ch.id,
|
|
86
|
+
workingDirectory: ch.workingDirectory,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Dynamic channels from SQLite
|
|
91
|
+
for (const dyn of getDynamicChannels()) {
|
|
92
|
+
const channelBot = dyn.bot ?? getDefaultBotForPlatform(dyn.platform);
|
|
93
|
+
if (channelBot === botName && !seen.has(dyn.channelId)) {
|
|
94
|
+
seen.add(dyn.channelId);
|
|
95
|
+
entries.push({
|
|
96
|
+
channelName: dyn.name || dyn.channelId,
|
|
97
|
+
channelId: dyn.channelId,
|
|
98
|
+
workingDirectory: dyn.workingDirectory,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return entries;
|
|
103
|
+
}
|
|
104
|
+
/** Get the default bot name for a platform (first bot in the bots map, or 'default'). */
|
|
105
|
+
function getDefaultBotForPlatform(platformName) {
|
|
106
|
+
const config = getConfig();
|
|
107
|
+
const platform = config.platforms[platformName];
|
|
108
|
+
if (platform?.bots)
|
|
109
|
+
return Object.keys(platform.bots)[0] ?? 'default';
|
|
110
|
+
return 'default';
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Build the system prompt context for workspace awareness.
|
|
114
|
+
* Lists all project workspaces the target bot has access to.
|
|
115
|
+
*/
|
|
116
|
+
export function buildWorkspacePrompt(workspaceMap) {
|
|
117
|
+
if (workspaceMap.length === 0)
|
|
118
|
+
return '';
|
|
119
|
+
const lines = workspaceMap.map(e => `- ${e.channelName}: ${e.workingDirectory}`);
|
|
120
|
+
return `You have access to the following project workspaces:\n${lines.join('\n')}`;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Build the caller attribution section of the system prompt.
|
|
124
|
+
*/
|
|
125
|
+
export function buildCallerPrompt(context) {
|
|
126
|
+
return [
|
|
127
|
+
`This request is from agent "${context.callerBot}". You are responding to an inter-agent query, not a direct user message.`,
|
|
128
|
+
`The originating channel is "${context.callerChannel}".`,
|
|
129
|
+
context.depth > 0 ? `Call chain depth: ${context.depth}. Chain: ${context.visited.join(' → ')}.` : '',
|
|
130
|
+
].filter(Boolean).join('\n');
|
|
131
|
+
}
|
|
132
|
+
// --- Agent Definition Discovery ---
|
|
133
|
+
/**
|
|
134
|
+
* Discover *.agent.md files in a bot's workspace agents/ directory.
|
|
135
|
+
* Returns a map of agent name → definition.
|
|
136
|
+
*/
|
|
137
|
+
export function discoverAgentDefinitions(workspacePath) {
|
|
138
|
+
const agentsDir = path.join(workspacePath, 'agents');
|
|
139
|
+
const definitions = new Map();
|
|
140
|
+
if (!fs.existsSync(agentsDir))
|
|
141
|
+
return definitions;
|
|
142
|
+
try {
|
|
143
|
+
for (const entry of fs.readdirSync(agentsDir, { withFileTypes: true })) {
|
|
144
|
+
if (!entry.isFile() || !entry.name.endsWith('.agent.md'))
|
|
145
|
+
continue;
|
|
146
|
+
const name = entry.name.replace(/\.agent\.md$/, '');
|
|
147
|
+
const filePath = path.join(agentsDir, entry.name);
|
|
148
|
+
try {
|
|
149
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
150
|
+
definitions.set(name, { name, content, filePath });
|
|
151
|
+
log.debug(`Discovered agent definition: ${name} at ${filePath}`);
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
log.warn(`Failed to read agent definition ${filePath}: ${err?.message}`);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
log.warn(`Failed to scan agents directory ${agentsDir}: ${err?.message}`);
|
|
160
|
+
}
|
|
161
|
+
return definitions;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Resolve which agent definition to use for an ephemeral session.
|
|
165
|
+
* Priority: explicit agent param → bot's default agent → none.
|
|
166
|
+
*/
|
|
167
|
+
export function resolveAgentDefinition(workspacePath, agentParam, botDefaultAgent) {
|
|
168
|
+
const agentName = agentParam ?? botDefaultAgent;
|
|
169
|
+
if (!agentName)
|
|
170
|
+
return null;
|
|
171
|
+
const definitions = discoverAgentDefinitions(workspacePath);
|
|
172
|
+
const def = definitions.get(agentName);
|
|
173
|
+
if (!def) {
|
|
174
|
+
log.warn(`Agent definition "${agentName}" not found in ${workspacePath}/agents/`);
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
return def;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=inter-agent.js.map
|