@xagent-ai/cli 1.3.0 → 1.3.1
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/.github/release.yml +76 -0
- package/.github/workflows/ci.yml +3 -0
- package/.github/workflows/release.yml +11 -17
- package/README.md +2 -2
- package/README_CN.md +2 -2
- package/dist/agents.d.ts.map +1 -1
- package/dist/agents.js +7 -3
- package/dist/agents.js.map +1 -1
- package/dist/ai-client/factory.d.ts +0 -12
- package/dist/ai-client/factory.d.ts.map +1 -1
- package/dist/ai-client/factory.js +0 -32
- package/dist/ai-client/factory.js.map +1 -1
- package/dist/ai-client/index.js +1 -1
- package/dist/ai-client/index.js.map +1 -1
- package/dist/ai-client/providers/anthropic.d.ts.map +1 -1
- package/dist/ai-client/providers/anthropic.js +10 -4
- package/dist/ai-client/providers/anthropic.js.map +1 -1
- package/dist/ai-client/providers/openai.d.ts.map +1 -1
- package/dist/ai-client/providers/openai.js +8 -4
- package/dist/ai-client/providers/openai.js.map +1 -1
- package/dist/ai-client/providers/remote.d.ts +0 -1
- package/dist/ai-client/providers/remote.d.ts.map +1 -1
- package/dist/ai-client/providers/remote.js +11 -10
- package/dist/ai-client/providers/remote.js.map +1 -1
- package/dist/ai-client/types.d.ts +14 -0
- package/dist/ai-client/types.d.ts.map +1 -1
- package/dist/ai-client/types.js +17 -0
- package/dist/ai-client/types.js.map +1 -1
- package/dist/ai-client-factory.d.ts.map +1 -1
- package/dist/ai-client-factory.js +4 -4
- package/dist/ai-client-factory.js.map +1 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +10 -12
- package/dist/auth.js.map +1 -1
- package/dist/cancellation.d.ts.map +1 -1
- package/dist/cancellation.js +3 -5
- package/dist/cancellation.js.map +1 -1
- package/dist/checkpoint.d.ts +1 -0
- package/dist/checkpoint.d.ts.map +1 -1
- package/dist/checkpoint.js +37 -4
- package/dist/checkpoint.js.map +1 -1
- package/dist/cli.js +132 -32
- package/dist/cli.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/context-compressor.d.ts +1 -2
- package/dist/context-compressor.d.ts.map +1 -1
- package/dist/context-compressor.js +23 -18
- package/dist/context-compressor.js.map +1 -1
- package/dist/conversation.d.ts +1 -1
- package/dist/conversation.d.ts.map +1 -1
- package/dist/conversation.js +8 -7
- package/dist/conversation.js.map +1 -1
- package/dist/gui-subagent/action-parser/actionParser.js +2 -2
- package/dist/gui-subagent/action-parser/actionParser.js.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.d.ts +10 -0
- package/dist/gui-subagent/agent/gui-agent.d.ts.map +1 -1
- package/dist/gui-subagent/agent/gui-agent.js +105 -32
- package/dist/gui-subagent/agent/gui-agent.js.map +1 -1
- package/dist/gui-subagent/index.d.ts +7 -0
- package/dist/gui-subagent/index.d.ts.map +1 -1
- package/dist/gui-subagent/index.js +2 -0
- package/dist/gui-subagent/index.js.map +1 -1
- package/dist/gui-subagent/operator/computer-operator.d.ts.map +1 -1
- package/dist/gui-subagent/operator/computer-operator.js +2 -0
- package/dist/gui-subagent/operator/computer-operator.js.map +1 -1
- package/dist/input-processor.js +2 -2
- package/dist/input-processor.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +1 -1
- package/dist/logger.js.map +1 -1
- package/dist/mcp.d.ts +2 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +83 -21
- package/dist/mcp.js.map +1 -1
- package/dist/memory.d.ts.map +1 -1
- package/dist/memory.js +3 -3
- package/dist/memory.js.map +1 -1
- package/dist/output-util.d.ts +27 -0
- package/dist/output-util.d.ts.map +1 -0
- package/dist/output-util.js +74 -0
- package/dist/output-util.js.map +1 -0
- package/dist/retry.js +1 -1
- package/dist/retry.js.map +1 -1
- package/dist/ripgrep.d.ts.map +1 -1
- package/dist/ripgrep.js +5 -3
- package/dist/ripgrep.js.map +1 -1
- package/dist/sdk-output-adapter.d.ts +265 -0
- package/dist/sdk-output-adapter.d.ts.map +1 -0
- package/dist/sdk-output-adapter.js +701 -0
- package/dist/sdk-output-adapter.js.map +1 -0
- package/dist/sdk-session.d.ts +13 -0
- package/dist/sdk-session.d.ts.map +1 -0
- package/dist/sdk-session.js +50 -0
- package/dist/sdk-session.js.map +1 -0
- package/dist/session-manager.js +3 -3
- package/dist/session-manager.js.map +1 -1
- package/dist/session.d.ts +96 -2
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +849 -262
- package/dist/session.js.map +1 -1
- package/dist/shell.d.ts.map +1 -1
- package/dist/shell.js +5 -4
- package/dist/shell.js.map +1 -1
- package/dist/skill-installer.js +3 -3
- package/dist/skill-installer.js.map +1 -1
- package/dist/skill-invoker.d.ts +1 -1
- package/dist/skill-invoker.d.ts.map +1 -1
- package/dist/skill-invoker.js +2 -2
- package/dist/skill-invoker.js.map +1 -1
- package/dist/skill-loader.js +6 -5
- package/dist/skill-loader.js.map +1 -1
- package/dist/skill-manager.d.ts.map +1 -1
- package/dist/skill-manager.js +3 -2
- package/dist/skill-manager.js.map +1 -1
- package/dist/slash-commands.d.ts +1 -1
- package/dist/slash-commands.d.ts.map +1 -1
- package/dist/slash-commands.js +24 -11
- package/dist/slash-commands.js.map +1 -1
- package/dist/smart-approval.d.ts +20 -1
- package/dist/smart-approval.d.ts.map +1 -1
- package/dist/smart-approval.js +58 -1
- package/dist/smart-approval.js.map +1 -1
- package/dist/system-prompt-generator.js +3 -3
- package/dist/system-prompt-generator.js.map +1 -1
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +8 -7
- package/dist/theme.js.map +1 -1
- package/dist/tools.d.ts +15 -0
- package/dist/tools.d.ts.map +1 -1
- package/dist/tools.js +487 -215
- package/dist/tools.js.map +1 -1
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +49 -0
- package/dist/types.js.map +1 -1
- package/dist/update.d.ts.map +1 -1
- package/dist/update.js +12 -9
- package/dist/update.js.map +1 -1
- package/dist/workflow.d.ts.map +1 -1
- package/dist/workflow.js +1 -2
- package/dist/workflow.js.map +1 -1
- package/docs/third-party-models.md +16 -15
- package/package.json +3 -1
- package/src/agents.ts +7 -3
- package/src/ai-client/factory.ts +1 -36
- package/src/ai-client/index.ts +1 -1
- package/src/ai-client/providers/anthropic.ts +12 -3
- package/src/ai-client/providers/openai.ts +10 -4
- package/src/ai-client/providers/remote.ts +13 -10
- package/src/ai-client/types.ts +19 -0
- package/src/ai-client-factory.ts +5 -5
- package/src/auth.ts +11 -13
- package/src/cancellation.ts +3 -6
- package/src/checkpoint.ts +40 -4
- package/src/cli.ts +154 -37
- package/src/config.ts +1 -1
- package/src/context-compressor.ts +28 -23
- package/src/conversation.ts +9 -7
- package/src/gui-subagent/action-parser/actionParser.ts +2 -2
- package/src/gui-subagent/agent/gui-agent.ts +117 -34
- package/src/gui-subagent/index.ts +8 -0
- package/src/gui-subagent/operator/computer-operator.ts +2 -1
- package/src/input-processor.ts +2 -2
- package/src/logger.ts +2 -4
- package/src/mcp.ts +86 -23
- package/src/memory.ts +3 -4
- package/src/output-util.ts +80 -0
- package/src/retry.ts +1 -1
- package/src/ripgrep.ts +5 -3
- package/src/sdk-output-adapter.ts +842 -0
- package/src/sdk-session.ts +62 -0
- package/src/session-manager.ts +3 -3
- package/src/session.ts +942 -302
- package/src/shell.ts +6 -5
- package/src/skill-installer.ts +3 -3
- package/src/skill-invoker.ts +3 -4
- package/src/skill-loader.ts +7 -7
- package/src/skill-manager.ts +4 -3
- package/src/slash-commands.ts +24 -16
- package/src/smart-approval.ts +76 -1
- package/src/system-prompt-generator.ts +3 -3
- package/src/theme.ts +9 -8
- package/src/tools.ts +563 -267
- package/src/types.ts +118 -0
- package/src/update.ts +12 -9
- package/src/workflow.ts +2 -4
- package/test/cli-launch.test.ts +279 -0
- package/vitest.config.ts +2 -0
- /package/{.eslintrc.js → .eslintrc.cjs} +0 -0
package/src/shell.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { existsSync } from 'fs';
|
|
2
2
|
import { spawn, spawnSync } from 'child_process';
|
|
3
|
+
import { output as logOutput } from './output-util.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Find bash executable on PATH (Windows).
|
|
6
7
|
*/
|
|
7
|
-
function
|
|
8
|
+
function _findBashOnPath(): string | null {
|
|
8
9
|
try {
|
|
9
10
|
const result = spawnSync('where', ['bash.exe'], { encoding: 'utf-8', timeout: 5000 });
|
|
10
11
|
if (result.status === 0 && result.stdout) {
|
|
@@ -115,19 +116,19 @@ export function killProcessTree(pid: number): void {
|
|
|
115
116
|
detached: true,
|
|
116
117
|
});
|
|
117
118
|
} catch (error) {
|
|
118
|
-
|
|
119
|
+
logOutput('warning', `[shell] Failed to kill process tree (PID ${pid})`, { error: error instanceof Error ? error.message : String(error) });
|
|
119
120
|
}
|
|
120
121
|
} else {
|
|
121
122
|
// Use SIGKILL on Unix/Linux/Mac
|
|
122
123
|
try {
|
|
123
124
|
process.kill(-pid, 'SIGKILL');
|
|
124
|
-
} catch
|
|
125
|
+
} catch {
|
|
125
126
|
// Fallback to killing just the child if process group kill fails
|
|
126
127
|
try {
|
|
127
128
|
process.kill(pid, 'SIGKILL');
|
|
128
129
|
} catch (fallbackError) {
|
|
129
|
-
|
|
130
|
+
logOutput('warning', `[shell] Failed to kill process (PID ${pid})`, { error: fallbackError instanceof Error ? fallbackError.message : String(fallbackError) });
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
}
|
|
133
|
-
}
|
|
134
|
+
}
|
package/src/skill-installer.ts
CHANGED
|
@@ -12,7 +12,7 @@ import simpleGit from 'simple-git';
|
|
|
12
12
|
import { getConfigManager } from './config.js';
|
|
13
13
|
import { getLogger } from './logger.js';
|
|
14
14
|
|
|
15
|
-
const
|
|
15
|
+
const _logger = getLogger();
|
|
16
16
|
const CLONE_TIMEOUT_MS = 60000; // 60 seconds
|
|
17
17
|
|
|
18
18
|
export interface RemoteSource {
|
|
@@ -317,8 +317,8 @@ async function installFromGitHub(source: RemoteSource): Promise<InstallResult> {
|
|
|
317
317
|
return { success: false, error: 'Invalid GitHub URL' };
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
const [,
|
|
321
|
-
const
|
|
320
|
+
const [, _owner, repo] = urlMatch;
|
|
321
|
+
const _cleanRepo = repo.replace(/\.git$/, '');
|
|
322
322
|
const ref = source.ref || 'main';
|
|
323
323
|
|
|
324
324
|
let tempDir: string | null = null;
|
package/src/skill-invoker.ts
CHANGED
|
@@ -2,8 +2,7 @@ import fs from 'fs/promises';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
import { getSkillLoader, SkillInfo, SkillLoader } from './skill-loader.js';
|
|
5
|
-
import {
|
|
6
|
-
import { ExecutionMode, Tool } from './types.js';
|
|
5
|
+
import { ExecutionMode } from './types.js';
|
|
7
6
|
import { getConfigManager } from './config.js';
|
|
8
7
|
|
|
9
8
|
// Re-export SkillInfo for other modules
|
|
@@ -579,7 +578,7 @@ export class SkillInvoker {
|
|
|
579
578
|
* NOTE: SKILL_TRIGGERS disabled. Let LLM decide based on system prompt.
|
|
580
579
|
* Returns null to indicate no explicit match - LLM should use its own judgment.
|
|
581
580
|
*/
|
|
582
|
-
async matchSkill(
|
|
581
|
+
async matchSkill(_userInput: string): Promise<SkillMatcherResult | null> {
|
|
583
582
|
// SKILL_TRIGGERS is disabled for experiment purposes.
|
|
584
583
|
// The LLM should decide which skill to use based on system prompt information.
|
|
585
584
|
return null;
|
|
@@ -684,7 +683,7 @@ export class SkillInvoker {
|
|
|
684
683
|
* Get executor for skill
|
|
685
684
|
* Unified dynamic approach - all skills use GenericSkillExecutor
|
|
686
685
|
*/
|
|
687
|
-
private getSkillExecutor(
|
|
686
|
+
private getSkillExecutor(_skillId: string): SkillExecutor {
|
|
688
687
|
return new GenericSkillExecutor();
|
|
689
688
|
}
|
|
690
689
|
|
package/src/skill-loader.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'fs/promises';
|
|
2
|
-
import
|
|
2
|
+
import _fsSync from 'fs';
|
|
3
3
|
import path from 'path';
|
|
4
|
-
import
|
|
4
|
+
import os from 'os';
|
|
5
5
|
import { WorkflowConfig } from './workflow.js';
|
|
6
6
|
import { getConfigManager } from './config.js';
|
|
7
7
|
|
|
@@ -59,7 +59,7 @@ export class SkillLoader {
|
|
|
59
59
|
} else {
|
|
60
60
|
const configManager = getConfigManager();
|
|
61
61
|
const userPath = configManager.getUserSkillsPath();
|
|
62
|
-
this.skillsRootPath = userPath || path.join(
|
|
62
|
+
this.skillsRootPath = userPath || path.join(os.homedir(), '.xagent', 'skills');
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
async loadAllSkills(): Promise<SkillInfo[]> {
|
|
@@ -356,19 +356,19 @@ export class SkillLoader {
|
|
|
356
356
|
// Try to extract frontmatter - support both formats:
|
|
357
357
|
// 1. Standard YAML: ---name: docx...--- 2. No opening ---: name: docx...
|
|
358
358
|
let frontmatter = '';
|
|
359
|
-
let
|
|
359
|
+
let _contentStart = 0;
|
|
360
360
|
|
|
361
|
-
const frontmatterMatch = normalizedContent.match(
|
|
361
|
+
const frontmatterMatch = normalizedContent.match(/^---([\s\S]*?)\n---/);
|
|
362
362
|
if (frontmatterMatch) {
|
|
363
363
|
// Standard format with --- at start and end
|
|
364
364
|
frontmatter = frontmatterMatch[1];
|
|
365
|
-
|
|
365
|
+
_contentStart = frontmatterMatch[0].length;
|
|
366
366
|
} else {
|
|
367
367
|
// Check for format without opening --- (just YAML at the start)
|
|
368
368
|
const yamlMatch = normalizedContent.match(/^([\s\S]*?)\n---/);
|
|
369
369
|
if (yamlMatch) {
|
|
370
370
|
frontmatter = yamlMatch[1];
|
|
371
|
-
|
|
371
|
+
_contentStart = yamlMatch[0].length;
|
|
372
372
|
}
|
|
373
373
|
}
|
|
374
374
|
|
package/src/skill-manager.ts
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* - Removes distinction between built-in and user skills
|
|
6
6
|
*/
|
|
7
7
|
import fs from 'fs/promises';
|
|
8
|
-
import
|
|
8
|
+
import os from 'os';
|
|
9
|
+
import _fsSync from 'fs';
|
|
9
10
|
import path from 'path';
|
|
10
11
|
import { fileURLToPath } from 'url';
|
|
11
12
|
import { getConfigManager } from './config.js';
|
|
@@ -50,7 +51,7 @@ export class SkillManager {
|
|
|
50
51
|
this.userSkillsRoot = config.userSkillsRoot;
|
|
51
52
|
} else {
|
|
52
53
|
this.userSkillsRoot = configManager.getUserSkillsPath() ||
|
|
53
|
-
path.join(
|
|
54
|
+
path.join(os.homedir(), '.xagent', 'skills');
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
|
|
@@ -184,7 +185,7 @@ export class SkillManager {
|
|
|
184
185
|
try {
|
|
185
186
|
const resolvedPath = path.resolve(sourcePath);
|
|
186
187
|
const skillName = path.basename(resolvedPath);
|
|
187
|
-
const
|
|
188
|
+
const _destPath = path.join(this.userSkillsRoot, skillName);
|
|
188
189
|
|
|
189
190
|
// Check if source exists
|
|
190
191
|
await fs.access(resolvedPath);
|
package/src/slash-commands.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import readline from 'readline';
|
|
2
1
|
import { select, confirm, text } from '@clack/prompts';
|
|
3
2
|
import chalk from 'chalk';
|
|
4
3
|
import ora from 'ora';
|
|
5
4
|
import fs from 'fs/promises';
|
|
6
5
|
import path from 'path';
|
|
7
|
-
import { ExecutionMode, ChatMessage, InputType,
|
|
8
|
-
import { Message, detectThinkingKeywords, getThinkingTokens } from './ai-client/types.js';
|
|
6
|
+
import { ExecutionMode, ChatMessage, InputType, Checkpoint, AgentConfig, CompressionConfig, AuthType } from './types.js';
|
|
9
7
|
import { fetchDefaultModels } from './ai-client/providers/remote.js';
|
|
10
8
|
import { getToolRegistry } from './tools.js';
|
|
11
9
|
import { getAgentManager } from './agents.js';
|
|
@@ -21,7 +19,6 @@ import {
|
|
|
21
19
|
} from './context-compressor.js';
|
|
22
20
|
import { getConversationManager, ConversationManager } from './conversation.js';
|
|
23
21
|
import { icons, colors } from './theme.js';
|
|
24
|
-
import { SystemPromptGenerator } from './system-prompt-generator.js';
|
|
25
22
|
import { ensureTtySane } from './terminal.js';
|
|
26
23
|
import { AuthService, selectAuthType, ThirdPartyProvider, THIRD_PARTY_PROVIDERS, VLM_PROVIDERS, VLMProviderInfo } from './auth.js';
|
|
27
24
|
|
|
@@ -626,7 +623,6 @@ export class SlashCommandHandler {
|
|
|
626
623
|
const success = await authService.authenticate();
|
|
627
624
|
|
|
628
625
|
if (success) {
|
|
629
|
-
const newConfig = this.configManager.getAuthConfig();
|
|
630
626
|
console.log(chalk.green('\n✅ Login successful!'));
|
|
631
627
|
console.log(chalk.cyan(` Token saved to: ~/.xagent/settings.json`));
|
|
632
628
|
console.log(chalk.gray(' You can now use xAgent CLI with remote AI services.\n'));
|
|
@@ -1216,7 +1212,7 @@ export class SlashCommandHandler {
|
|
|
1216
1212
|
}
|
|
1217
1213
|
|
|
1218
1214
|
private async addMcpServerInteractive(serverName?: string): Promise<void> {
|
|
1219
|
-
|
|
1215
|
+
const name = (await text({
|
|
1220
1216
|
message: 'Enter MCP server name:',
|
|
1221
1217
|
defaultValue: serverName,
|
|
1222
1218
|
validate: (value: string | undefined) => {
|
|
@@ -1345,10 +1341,8 @@ export class SlashCommandHandler {
|
|
|
1345
1341
|
|
|
1346
1342
|
this.mcpManager.registerServer(name, config);
|
|
1347
1343
|
|
|
1348
|
-
let connected = false;
|
|
1349
1344
|
try {
|
|
1350
1345
|
await this.mcpManager.connectServer(name);
|
|
1351
|
-
connected = true;
|
|
1352
1346
|
} catch (error: any) {
|
|
1353
1347
|
this.mcpManager.disconnectServer(name);
|
|
1354
1348
|
this.configManager.removeMcpServer(name);
|
|
@@ -1403,11 +1397,6 @@ export class SlashCommandHandler {
|
|
|
1403
1397
|
|
|
1404
1398
|
private async removeMcpServer(serverName: string): Promise<void> {
|
|
1405
1399
|
try {
|
|
1406
|
-
// Get server info before disconnecting to notify LLM
|
|
1407
|
-
const server = this.mcpManager.getServer(serverName);
|
|
1408
|
-
const removedTools = server ? server.getToolNames() : [];
|
|
1409
|
-
const removedToolNames = removedTools.map((t: string) => `${serverName}__${t}`).join(', ');
|
|
1410
|
-
|
|
1411
1400
|
// Disconnect
|
|
1412
1401
|
this.mcpManager.disconnectServer(serverName);
|
|
1413
1402
|
|
|
@@ -1909,7 +1898,6 @@ export class SlashCommandHandler {
|
|
|
1909
1898
|
private async handleSkill(args: string[]): Promise<void> {
|
|
1910
1899
|
const os = await import('os');
|
|
1911
1900
|
const path = await import('path');
|
|
1912
|
-
const { fileURLToPath } = await import('url');
|
|
1913
1901
|
const { promises: fs } = await import('fs');
|
|
1914
1902
|
|
|
1915
1903
|
const action = args[0] || 'list';
|
|
@@ -2146,10 +2134,11 @@ export class SlashCommandHandler {
|
|
|
2146
2134
|
}
|
|
2147
2135
|
}
|
|
2148
2136
|
|
|
2149
|
-
export function parseInput(input: string): InputType[] {
|
|
2137
|
+
export async function parseInput(input: string): Promise<InputType[]> {
|
|
2150
2138
|
const inputs: InputType[] = [];
|
|
2151
2139
|
let remaining = input;
|
|
2152
2140
|
|
|
2141
|
+
// Match @ followed by any non-whitespace sequence
|
|
2153
2142
|
const fileRefRegex = /@([^\s]+)/g;
|
|
2154
2143
|
let match;
|
|
2155
2144
|
while ((match = fileRefRegex.exec(remaining)) !== null) {
|
|
@@ -2161,7 +2150,14 @@ export function parseInput(input: string): InputType[] {
|
|
|
2161
2150
|
inputs.push({ type: 'text', content: beforeMatch.trim() });
|
|
2162
2151
|
}
|
|
2163
2152
|
|
|
2164
|
-
|
|
2153
|
+
// Only treat as file reference if the file actually exists
|
|
2154
|
+
const exists = await fileExists(filePath);
|
|
2155
|
+
if (exists) {
|
|
2156
|
+
inputs.push({ type: 'file', content: filePath });
|
|
2157
|
+
} else {
|
|
2158
|
+
// Not a file, treat as regular text (preserving the @ symbol)
|
|
2159
|
+
inputs.push({ type: 'text', content: '@' + filePath });
|
|
2160
|
+
}
|
|
2165
2161
|
remaining = afterMatch;
|
|
2166
2162
|
}
|
|
2167
2163
|
|
|
@@ -2176,6 +2172,18 @@ export function parseInput(input: string): InputType[] {
|
|
|
2176
2172
|
return inputs;
|
|
2177
2173
|
}
|
|
2178
2174
|
|
|
2175
|
+
// Helper function to check if a file path exists
|
|
2176
|
+
async function fileExists(filePath: string): Promise<boolean> {
|
|
2177
|
+
try {
|
|
2178
|
+
// Resolve to absolute path
|
|
2179
|
+
const absolutePath = path.resolve(filePath);
|
|
2180
|
+
await fs.access(absolutePath);
|
|
2181
|
+
return true;
|
|
2182
|
+
} catch {
|
|
2183
|
+
return false;
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2179
2187
|
export function detectImageInput(input: string): boolean {
|
|
2180
2188
|
return input.includes('[Pasted image') || input.includes('<image');
|
|
2181
2189
|
}
|
package/src/smart-approval.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { AuthType } from './types.js';
|
|
|
6
6
|
import { getLogger } from './logger.js';
|
|
7
7
|
import { colors, icons } from './theme.js';
|
|
8
8
|
import { getCancellationManager } from './cancellation.js';
|
|
9
|
+
import { SdkOutputAdapter } from './sdk-output-adapter.js';
|
|
9
10
|
|
|
10
11
|
const logger = getLogger();
|
|
11
12
|
|
|
@@ -494,6 +495,8 @@ export class SmartApprovalEngine {
|
|
|
494
495
|
private blacklistChecker: BlacklistChecker;
|
|
495
496
|
private aiChecker: AIApprovalChecker;
|
|
496
497
|
private debugMode: boolean;
|
|
498
|
+
private sdkAdapter: SdkOutputAdapter | null = null;
|
|
499
|
+
private isSdkMode: boolean = false;
|
|
497
500
|
|
|
498
501
|
constructor(debugMode: boolean = false) {
|
|
499
502
|
this.whitelistChecker = new WhitelistChecker();
|
|
@@ -502,6 +505,28 @@ export class SmartApprovalEngine {
|
|
|
502
505
|
this.debugMode = debugMode;
|
|
503
506
|
}
|
|
504
507
|
|
|
508
|
+
/**
|
|
509
|
+
* Set SDK mode and output adapter for SDK mode support
|
|
510
|
+
*/
|
|
511
|
+
setSdkMode(enabled: boolean, adapter: SdkOutputAdapter | null): void {
|
|
512
|
+
this.isSdkMode = enabled;
|
|
513
|
+
this.sdkAdapter = adapter;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Check if in SDK mode
|
|
518
|
+
*/
|
|
519
|
+
getIsSdkMode(): boolean {
|
|
520
|
+
return this.isSdkMode;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Get SDK adapter
|
|
525
|
+
*/
|
|
526
|
+
getSdkAdapter(): SdkOutputAdapter | null {
|
|
527
|
+
return this.sdkAdapter;
|
|
528
|
+
}
|
|
529
|
+
|
|
505
530
|
/**
|
|
506
531
|
* Evaluate tool call
|
|
507
532
|
*/
|
|
@@ -583,7 +608,17 @@ export class SmartApprovalEngine {
|
|
|
583
608
|
/**
|
|
584
609
|
* Request user confirmation
|
|
585
610
|
*/
|
|
586
|
-
async requestConfirmation(
|
|
611
|
+
async requestConfirmation(
|
|
612
|
+
result: ApprovalResult,
|
|
613
|
+
toolName?: string,
|
|
614
|
+
toolParams?: Record<string, unknown>
|
|
615
|
+
): Promise<boolean> {
|
|
616
|
+
// Check if in SDK mode with adapter
|
|
617
|
+
if (this.isSdkMode && this.sdkAdapter) {
|
|
618
|
+
return this.requestConfirmationSdk(result, toolName, toolParams);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
// Regular TUI mode
|
|
587
622
|
const separator = icons.separator.repeat(40);
|
|
588
623
|
console.log('');
|
|
589
624
|
console.log(
|
|
@@ -624,6 +659,46 @@ export class SmartApprovalEngine {
|
|
|
624
659
|
}
|
|
625
660
|
}
|
|
626
661
|
|
|
662
|
+
/**
|
|
663
|
+
* Request user confirmation in SDK mode
|
|
664
|
+
*/
|
|
665
|
+
private async requestConfirmationSdk(
|
|
666
|
+
result: ApprovalResult,
|
|
667
|
+
toolName?: string,
|
|
668
|
+
toolParams?: Record<string, unknown>
|
|
669
|
+
): Promise<boolean> {
|
|
670
|
+
const requestId = `approval_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
671
|
+
|
|
672
|
+
// Output approval request through SDK adapter
|
|
673
|
+
this.sdkAdapter!.outputApprovalRequest({
|
|
674
|
+
requestId,
|
|
675
|
+
toolName: toolName || 'unknown',
|
|
676
|
+
params: toolParams || {},
|
|
677
|
+
riskLevel: result.riskLevel,
|
|
678
|
+
description: result.description,
|
|
679
|
+
aiAnalysis: result.aiAnalysis
|
|
680
|
+
});
|
|
681
|
+
|
|
682
|
+
// Wait for SDK response using session
|
|
683
|
+
try {
|
|
684
|
+
const { getSingletonSession } = await import('./session.js');
|
|
685
|
+
const session = getSingletonSession();
|
|
686
|
+
if (!session) {
|
|
687
|
+
logger.error('SDK session not available');
|
|
688
|
+
return false;
|
|
689
|
+
}
|
|
690
|
+
const approved = await session.waitForApprovalResponse(requestId);
|
|
691
|
+
this.sdkAdapter!.outputApprovalResponse(requestId, approved);
|
|
692
|
+
return approved;
|
|
693
|
+
} catch (error) {
|
|
694
|
+
logger.error(
|
|
695
|
+
'Failed to get SDK approval response',
|
|
696
|
+
error instanceof Error ? error.message : String(error)
|
|
697
|
+
);
|
|
698
|
+
return false;
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
627
702
|
/**
|
|
628
703
|
* Get risk level display
|
|
629
704
|
*/
|
|
@@ -44,7 +44,7 @@ export class SystemPromptGenerator {
|
|
|
44
44
|
*/
|
|
45
45
|
private generateEnvironmentInfo(): string {
|
|
46
46
|
const platform = os.platform();
|
|
47
|
-
const
|
|
47
|
+
const _arch = os.arch();
|
|
48
48
|
const nodeVersion = process.version;
|
|
49
49
|
const cwd = process.cwd();
|
|
50
50
|
const homeDir = os.homedir();
|
|
@@ -104,7 +104,7 @@ export class SystemPromptGenerator {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
// Get available local tools (includes MCP wrapper tools registered via registerMCPTools)
|
|
107
|
-
|
|
107
|
+
const allAvailableTools = localTools;
|
|
108
108
|
|
|
109
109
|
let enhancedPrompt = baseSystemPrompt;
|
|
110
110
|
|
|
@@ -739,7 +739,7 @@ Remember: You are in a conversational mode, not a tool-execution mode. Just talk
|
|
|
739
739
|
return output;
|
|
740
740
|
}
|
|
741
741
|
|
|
742
|
-
private generateDecisionMakingGuide(availableTools: any[],
|
|
742
|
+
private generateDecisionMakingGuide(availableTools: any[], _skills: SkillInfo[] = []): string {
|
|
743
743
|
// Tool name to short description mapping
|
|
744
744
|
const toolDescriptions: Record<string, string> = {
|
|
745
745
|
'Read': 'When you need to understand existing code, configuration, or documentation',
|
package/src/theme.ts
CHANGED
|
@@ -8,7 +8,7 @@ function getTerminalBackground(): 'dark' | 'light' {
|
|
|
8
8
|
// Check common environment variables
|
|
9
9
|
const colorfgbg = process.env.COLORFGBG; // e.g., "15;0" (light fg, dark bg)
|
|
10
10
|
const termProgram = process.env.TERM_PROGRAM;
|
|
11
|
-
const
|
|
11
|
+
const _termProgramVersion = process.env.TERM_PROGRAM_VERSION;
|
|
12
12
|
|
|
13
13
|
// Try to parse COLORFGBG (format: "fg;bg" or "fg;color;bg")
|
|
14
14
|
if (colorfgbg) {
|
|
@@ -82,7 +82,7 @@ interface SubAgentBoxOptions {
|
|
|
82
82
|
accentColor?: ColorFunction;
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
interface
|
|
85
|
+
interface _BoxFunctions {
|
|
86
86
|
single: (content: string, options?: BoxOptions) => string;
|
|
87
87
|
double: (content: string, options?: BoxOptions) => string;
|
|
88
88
|
minimal: (content: string, options?: Omit<BoxOptions, 'title' | 'titleAlign'>) => string;
|
|
@@ -284,13 +284,13 @@ export const styleHelpers = {
|
|
|
284
284
|
const chars = styleHelpers.border.single;
|
|
285
285
|
const availableWidth = width - 4;
|
|
286
286
|
|
|
287
|
-
|
|
287
|
+
const lines: string[] = [];
|
|
288
288
|
|
|
289
289
|
if (title) {
|
|
290
290
|
const titleContent = ` ${title} `;
|
|
291
291
|
const paddingNeeded = availableWidth - titleContent.length;
|
|
292
|
-
|
|
293
|
-
|
|
292
|
+
const leftPad = titleAlign === 'center' ? Math.floor(paddingNeeded / 2) : (titleAlign === 'right' ? paddingNeeded : 0);
|
|
293
|
+
const rightPad = titleAlign === 'center' ? Math.ceil(paddingNeeded / 2) : (titleAlign === 'right' ? 0 : paddingNeeded);
|
|
294
294
|
|
|
295
295
|
lines.push(`${indent}${chars.topLeft}${' '.repeat(leftPad)}${titleContent}${' '.repeat(rightPad)}${chars.topRight}`);
|
|
296
296
|
} else {
|
|
@@ -314,13 +314,13 @@ export const styleHelpers = {
|
|
|
314
314
|
const chars = styleHelpers.border.double;
|
|
315
315
|
const availableWidth = width - 4;
|
|
316
316
|
|
|
317
|
-
|
|
317
|
+
const lines: string[] = [];
|
|
318
318
|
|
|
319
319
|
if (title) {
|
|
320
320
|
const titleContent = ` ${title} `;
|
|
321
321
|
const paddingNeeded = availableWidth - titleContent.length;
|
|
322
|
-
|
|
323
|
-
|
|
322
|
+
const leftPad = titleAlign === 'center' ? Math.floor(paddingNeeded / 2) : (titleAlign === 'right' ? paddingNeeded : 0);
|
|
323
|
+
const rightPad = titleAlign === 'center' ? Math.ceil(paddingNeeded / 2) : (titleAlign === 'right' ? 0 : paddingNeeded);
|
|
324
324
|
|
|
325
325
|
lines.push(`${indent}${chars.topLeft}${' '.repeat(leftPad)}${titleContent}${' '.repeat(rightPad)}${chars.topRight}`);
|
|
326
326
|
} else {
|
|
@@ -364,6 +364,7 @@ export const styleHelpers = {
|
|
|
364
364
|
const availableWidth = width - 2;
|
|
365
365
|
|
|
366
366
|
const headerContent = `${colors.primaryBright(agentName)}: ${description}`;
|
|
367
|
+
// eslint-disable-next-line no-control-regex
|
|
367
368
|
const headerContentLength = headerContent.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
368
369
|
const headerFillLength = Math.max(0, availableWidth - 3 - headerContentLength);
|
|
369
370
|
const headerLine = `${indent}${accentColor(chars.topLeft)}${accentColor('─── ')}${headerContent} ${accentColor('─'.repeat(headerFillLength))}${accentColor(chars.topRight)}`;
|