agent-termo 1.0.1 → 1.0.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/README.md +27 -2
- package/dist/agents/index.d.ts +5 -0
- package/dist/agents/index.d.ts.map +1 -0
- package/dist/agents/index.js +86 -0
- package/dist/agents/index.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +97 -168
- package/dist/cli.js.map +4 -4
- package/dist/diff/index.d.ts +9 -0
- package/dist/diff/index.d.ts.map +1 -0
- package/dist/diff/index.js +213 -0
- package/dist/diff/index.js.map +1 -0
- package/dist/llm/client.d.ts +39 -0
- package/dist/llm/client.d.ts.map +1 -0
- package/dist/llm/client.js +188 -0
- package/dist/llm/client.js.map +1 -0
- package/dist/llm/models.d.ts +19 -0
- package/dist/llm/models.d.ts.map +1 -0
- package/dist/llm/models.js +45 -0
- package/dist/llm/models.js.map +1 -0
- package/dist/llm/tools.d.ts +3 -0
- package/dist/llm/tools.d.ts.map +1 -0
- package/dist/llm/tools.js +204 -0
- package/dist/llm/tools.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +91 -140
- package/dist/main.js.map +4 -4
- package/dist/memory/index.d.ts +10 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +117 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +334 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types/index.d.ts +119 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/index.d.ts +47 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +321 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/screen.d.ts +59 -0
- package/dist/ui/screen.d.ts.map +1 -0
- package/dist/ui/screen.js +629 -0
- package/dist/ui/screen.js.map +1 -0
- package/dist/utils/ansi.d.ts +62 -0
- package/dist/utils/ansi.d.ts.map +1 -0
- package/dist/utils/ansi.js +116 -0
- package/dist/utils/ansi.js.map +1 -0
- package/dist/utils/config.d.ts +9 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +120 -0
- package/dist/utils/config.js.map +1 -0
- package/package.json +1 -1
- package/src/cli.ts +1 -1
- package/src/llm/client.ts +24 -0
- package/src/llm/models.ts +55 -0
- package/src/main.ts +201 -75
- package/src/ui/index.ts +256 -389
- package/src/ui/screen.ts +698 -0
- package/src/utils/config.ts +37 -20
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export declare const COLORS: {
|
|
2
|
+
primary: string;
|
|
3
|
+
primaryBg: string;
|
|
4
|
+
success: string;
|
|
5
|
+
warning: string;
|
|
6
|
+
error: string;
|
|
7
|
+
info: string;
|
|
8
|
+
background: string;
|
|
9
|
+
surface: string;
|
|
10
|
+
elevated: string;
|
|
11
|
+
border: string;
|
|
12
|
+
borderLight: string;
|
|
13
|
+
text: string;
|
|
14
|
+
textSecondary: string;
|
|
15
|
+
muted: string;
|
|
16
|
+
dim: string;
|
|
17
|
+
manager: string;
|
|
18
|
+
architect: string;
|
|
19
|
+
expert: string;
|
|
20
|
+
security: string;
|
|
21
|
+
codeKeyword: string;
|
|
22
|
+
codeString: string;
|
|
23
|
+
codeComment: string;
|
|
24
|
+
codeFunction: string;
|
|
25
|
+
codeType: string;
|
|
26
|
+
userMsg: string;
|
|
27
|
+
aiMsg: string;
|
|
28
|
+
accent: string;
|
|
29
|
+
reset: string;
|
|
30
|
+
bright: string;
|
|
31
|
+
dim_text: string;
|
|
32
|
+
italic: string;
|
|
33
|
+
underline: string;
|
|
34
|
+
};
|
|
35
|
+
export declare const BG: {
|
|
36
|
+
surface: string;
|
|
37
|
+
elevated: string;
|
|
38
|
+
primaryBg: string;
|
|
39
|
+
};
|
|
40
|
+
export declare const FMT: {
|
|
41
|
+
bold: string;
|
|
42
|
+
dim: string;
|
|
43
|
+
ita: string;
|
|
44
|
+
ul: string;
|
|
45
|
+
reset: string;
|
|
46
|
+
};
|
|
47
|
+
export declare function color(colorCode: string, text: string): string;
|
|
48
|
+
export declare function bg(colorCode: string, text: string): string;
|
|
49
|
+
export declare function bold(text: string): string;
|
|
50
|
+
export declare function dim(text: string): string;
|
|
51
|
+
export declare function spinnerFrame(): string;
|
|
52
|
+
export declare function resetSpinner(): void;
|
|
53
|
+
export declare function hbar(length: number, char?: string): string;
|
|
54
|
+
export declare function clamp(text: string, maxLength: number): string;
|
|
55
|
+
export declare function progressBar(percent: number, width?: number): string;
|
|
56
|
+
export declare function agentColor(agentName: string): string;
|
|
57
|
+
export declare const clearLine = "\u001B[2K\r";
|
|
58
|
+
export declare const clearScreen = "\u001B[2J";
|
|
59
|
+
export declare const cursorHome = "\u001B[H";
|
|
60
|
+
export declare const hideCursor = "\u001B[?25l";
|
|
61
|
+
export declare const showCursor = "\u001B[?25h";
|
|
62
|
+
//# sourceMappingURL=ansi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ansi.d.ts","sourceRoot":"","sources":["../../src/utils/ansi.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkDlB,CAAC;AAEF,eAAO,MAAM,EAAE;;;;CAId,CAAC;AAEF,eAAO,MAAM,GAAG;;;;;;CAMf,CAAC;AAGF,wBAAgB,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE7D;AAED,wBAAgB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzC;AAED,wBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExC;AAMD,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AAED,wBAAgB,YAAY,IAAI,IAAI,CAEnC;AAGD,wBAAgB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,SAAM,GAAG,MAAM,CAEvD;AAED,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAG7D;AAGD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,CAI/D;AAGD,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAMpD;AAGD,eAAO,MAAM,SAAS,gBAAc,CAAC;AACrC,eAAO,MAAM,WAAW,cAAY,CAAC;AACrC,eAAO,MAAM,UAAU,aAAW,CAAC;AACnC,eAAO,MAAM,UAAU,gBAAc,CAAC;AACtC,eAAO,MAAM,UAAU,gBAAc,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// ANSI Color Utilities
|
|
3
|
+
// =============================================================================
|
|
4
|
+
// Design System colors (ANSI 256-color codes for cross-platform terminal)
|
|
5
|
+
export const COLORS = {
|
|
6
|
+
// Primary: #A855F7 → ANSI 135
|
|
7
|
+
primary: '\x1b[38;5;135m',
|
|
8
|
+
primaryBg: '\x1b[48;5;57m',
|
|
9
|
+
// Semantic
|
|
10
|
+
success: '\x1b[38;5;82m', // green-500
|
|
11
|
+
warning: '\x1b[38;5;214m', // amber-500
|
|
12
|
+
error: '\x1b[38;5;203m', // red-500
|
|
13
|
+
info: '\x1b[38;5;75m', // blue-500
|
|
14
|
+
// Dark theme neutrals
|
|
15
|
+
background: '\x1b[48;5;17m', // slate-900
|
|
16
|
+
surface: '\x1b[48;5;30m', // slate-800
|
|
17
|
+
elevated: '\x1b[48;5;31m', // slate-700
|
|
18
|
+
border: '\x1b[38;5;240m', // #646B7B
|
|
19
|
+
borderLight: '\x1b[38;5;241m', // #7C8796
|
|
20
|
+
// Text
|
|
21
|
+
text: '\x1b[38;5;255m', // slate-50
|
|
22
|
+
textSecondary: '\x1b[38;5;188m', // slate-300
|
|
23
|
+
muted: '\x1b[38;5;250m', // slate-400
|
|
24
|
+
dim: '\x1b[38;5;244m', // slate-400
|
|
25
|
+
// Agent badge colors
|
|
26
|
+
manager: '\x1b[38;5;135m', // purple
|
|
27
|
+
architect: '\x1b[38;5;75m', // blue
|
|
28
|
+
expert: '\x1b[38;5;82m', // green
|
|
29
|
+
security: '\x1b[38;5;214m', // amber
|
|
30
|
+
// Code syntax
|
|
31
|
+
codeKeyword: '\x1b[38;5;219m', // pink-400
|
|
32
|
+
codeString: '\x1b[38;5;114m', // green-400
|
|
33
|
+
codeComment: '\x1b[38;5;245m', // gray-400
|
|
34
|
+
codeFunction: '\x1b[38;5;75m', // blue-400
|
|
35
|
+
codeType: '\x1b[38;5;171m', // emerald-400
|
|
36
|
+
// Roles
|
|
37
|
+
userMsg: '\x1b[38;5;82m', // green for user
|
|
38
|
+
aiMsg: '\x1b[38;5;135m', // purple for AI
|
|
39
|
+
// Decorators
|
|
40
|
+
accent: '\x1b[38;5;75m', // blue accent
|
|
41
|
+
// Reset
|
|
42
|
+
reset: '\x1b[0m',
|
|
43
|
+
bright: '\x1b[1m',
|
|
44
|
+
dim_text: '\x1b[2m',
|
|
45
|
+
italic: '\x1b[3m',
|
|
46
|
+
underline: '\x1b[4m',
|
|
47
|
+
};
|
|
48
|
+
export const BG = {
|
|
49
|
+
surface: '\x1b[48;5;30m',
|
|
50
|
+
elevated: '\x1b[48;5;31m',
|
|
51
|
+
primaryBg: '\x1b[48;5;57m',
|
|
52
|
+
};
|
|
53
|
+
export const FMT = {
|
|
54
|
+
bold: '\x1b[1m',
|
|
55
|
+
dim: '\x1b[2m',
|
|
56
|
+
ita: '\x1b[3m',
|
|
57
|
+
ul: '\x1b[4m',
|
|
58
|
+
reset: '\x1b[0m',
|
|
59
|
+
};
|
|
60
|
+
// Escape helpers
|
|
61
|
+
export function color(colorCode, text) {
|
|
62
|
+
return `${colorCode}${text}${COLORS.reset}`;
|
|
63
|
+
}
|
|
64
|
+
export function bg(colorCode, text) {
|
|
65
|
+
return `${colorCode}${text}${COLORS.reset}`;
|
|
66
|
+
}
|
|
67
|
+
export function bold(text) {
|
|
68
|
+
return `${FMT.bold}${text}${FMT.reset}`;
|
|
69
|
+
}
|
|
70
|
+
export function dim(text) {
|
|
71
|
+
return `${FMT.dim}${text}${FMT.reset}`;
|
|
72
|
+
}
|
|
73
|
+
// Spinner frames (80ms per frame, 12 chars cycle)
|
|
74
|
+
const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
75
|
+
let spinnerIndex = 0;
|
|
76
|
+
export function spinnerFrame() {
|
|
77
|
+
const frame = SPINNER_FRAMES[spinnerIndex % SPINNER_FRAMES.length];
|
|
78
|
+
spinnerIndex++;
|
|
79
|
+
return frame ?? ' ';
|
|
80
|
+
}
|
|
81
|
+
export function resetSpinner() {
|
|
82
|
+
spinnerIndex = 0;
|
|
83
|
+
}
|
|
84
|
+
// Box drawing helpers
|
|
85
|
+
export function hbar(length, char = '─') {
|
|
86
|
+
return char.repeat(length);
|
|
87
|
+
}
|
|
88
|
+
export function clamp(text, maxLength) {
|
|
89
|
+
if (text.length <= maxLength)
|
|
90
|
+
return text;
|
|
91
|
+
return text.slice(0, maxLength - 3) + '...';
|
|
92
|
+
}
|
|
93
|
+
// Progress bar
|
|
94
|
+
export function progressBar(percent, width = 30) {
|
|
95
|
+
const filled = Math.round((percent / 100) * width);
|
|
96
|
+
const empty = width - filled;
|
|
97
|
+
return `[${COLORS.success}${'█'.repeat(filled)}${'░'.repeat(empty)}${COLORS.reset}]`;
|
|
98
|
+
}
|
|
99
|
+
// Agent badge color
|
|
100
|
+
export function agentColor(agentName) {
|
|
101
|
+
const lower = agentName.toLowerCase();
|
|
102
|
+
if (lower.includes('project-manager'))
|
|
103
|
+
return COLORS.manager;
|
|
104
|
+
if (lower.includes('architecture') || lower.includes('stack'))
|
|
105
|
+
return COLORS.architect;
|
|
106
|
+
if (lower.includes('security') || lower.includes('deploy'))
|
|
107
|
+
return COLORS.security;
|
|
108
|
+
return COLORS.expert;
|
|
109
|
+
}
|
|
110
|
+
// Clear line (ANSI)
|
|
111
|
+
export const clearLine = '\x1b[2K\r';
|
|
112
|
+
export const clearScreen = '\x1b[2J';
|
|
113
|
+
export const cursorHome = '\x1b[H';
|
|
114
|
+
export const hideCursor = '\x1b[?25l';
|
|
115
|
+
export const showCursor = '\x1b[?25h';
|
|
116
|
+
//# sourceMappingURL=ansi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ansi.js","sourceRoot":"","sources":["../../src/utils/ansi.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { AppConfig } from '../types/index.js';
|
|
2
|
+
declare const PROJECT_ROOT: string;
|
|
3
|
+
export { PROJECT_ROOT };
|
|
4
|
+
export declare function getAgentTermoDir(): string;
|
|
5
|
+
export declare function saveNimApiKey(apiKey: string): void;
|
|
6
|
+
export declare function saveNimModel(model: string): void;
|
|
7
|
+
export declare function getConfig(projectRoot: string): AppConfig;
|
|
8
|
+
export declare function resolveProjectRoot(cwd?: string): string;
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAiCnD,QAAA,MAAM,YAAY,QAAmB,CAAC;AAItC,OAAO,EAAE,YAAY,EAAE,CAAC;AAExB,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAmDD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAElD;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEhD;AAKD,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,CAgBxD;AAED,wBAAgB,kBAAkB,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEvD"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// Config Management
|
|
3
|
+
// =============================================================================
|
|
4
|
+
import { chmodSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { resolve, dirname } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
// Find project root reliably (works even when cwd != project dir)
|
|
8
|
+
function getProjectRoot() {
|
|
9
|
+
// Try import.meta.url first (ESM)
|
|
10
|
+
try {
|
|
11
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
12
|
+
return dirname(dirname(thisFile)); // src/utils/ → src/ → project root
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Fall back to process.cwd()
|
|
16
|
+
return process.cwd();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
// Load .env files at startup
|
|
20
|
+
function loadEnvFile(envPath) {
|
|
21
|
+
try {
|
|
22
|
+
const content = readFileSync(envPath, 'utf-8');
|
|
23
|
+
for (const line of content.split('\n')) {
|
|
24
|
+
const trimmed = line.trim();
|
|
25
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
26
|
+
continue;
|
|
27
|
+
const eqIdx = trimmed.indexOf('=');
|
|
28
|
+
if (eqIdx === -1 || eqIdx === trimmed.length - 1)
|
|
29
|
+
continue;
|
|
30
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
31
|
+
const value = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, '');
|
|
32
|
+
if (!process.env[key])
|
|
33
|
+
process.env[key] = value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// file not found — continue silently
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Load .env from project root and current directory
|
|
41
|
+
const PROJECT_ROOT = getProjectRoot();
|
|
42
|
+
loadEnvFile(resolve(PROJECT_ROOT, '.env'));
|
|
43
|
+
loadEnvFile(resolve('.env')); // also try cwd
|
|
44
|
+
export { PROJECT_ROOT };
|
|
45
|
+
export function getAgentTermoDir() {
|
|
46
|
+
const envDir = process.env.AGENT_TERMO_DIR;
|
|
47
|
+
if (envDir) {
|
|
48
|
+
return resolve(process.env.HOME || process.env.USERPROFILE || '.', envDir);
|
|
49
|
+
}
|
|
50
|
+
return resolve(process.env.HOME || process.env.USERPROFILE || '.', '.agent-termo');
|
|
51
|
+
}
|
|
52
|
+
function readStoredConfig() {
|
|
53
|
+
try {
|
|
54
|
+
const existing = JSON.parse(readFileSync(resolve(getAgentTermoDir(), 'config.json'), 'utf-8'));
|
|
55
|
+
if (existing && typeof existing === 'object' && !Array.isArray(existing)) {
|
|
56
|
+
return existing;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// No saved user configuration yet.
|
|
61
|
+
}
|
|
62
|
+
return {};
|
|
63
|
+
}
|
|
64
|
+
function updateStoredConfig(patch) {
|
|
65
|
+
const configDir = getAgentTermoDir();
|
|
66
|
+
const configPath = resolve(configDir, 'config.json');
|
|
67
|
+
const storedConfig = { ...readStoredConfig(), ...patch };
|
|
68
|
+
mkdirSync(configDir, { recursive: true, mode: 0o700 });
|
|
69
|
+
writeFileSync(configPath, `${JSON.stringify(storedConfig, null, 2)}\n`, {
|
|
70
|
+
encoding: 'utf-8',
|
|
71
|
+
mode: 0o600,
|
|
72
|
+
});
|
|
73
|
+
// Restrict permissions even when updating an existing file on Unix.
|
|
74
|
+
if (process.platform !== 'win32')
|
|
75
|
+
chmodSync(configPath, 0o600);
|
|
76
|
+
}
|
|
77
|
+
function loadStoredNimApiKey() {
|
|
78
|
+
if (process.env.NIM_API_KEY)
|
|
79
|
+
return;
|
|
80
|
+
const { nimApiKey } = readStoredConfig();
|
|
81
|
+
if (typeof nimApiKey === 'string' && nimApiKey.trim()) {
|
|
82
|
+
process.env.NIM_API_KEY = nimApiKey;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A model picked with /model is saved and wins over NIM_MODEL from .env, so
|
|
87
|
+
* the choice survives restarts. The --model CLI flag still overrides it.
|
|
88
|
+
*/
|
|
89
|
+
function loadStoredNimModel() {
|
|
90
|
+
const { nimModel } = readStoredConfig();
|
|
91
|
+
if (typeof nimModel === 'string' && nimModel.trim()) {
|
|
92
|
+
process.env.NIM_MODEL = nimModel;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
export function saveNimApiKey(apiKey) {
|
|
96
|
+
updateStoredConfig({ nimApiKey: apiKey });
|
|
97
|
+
}
|
|
98
|
+
export function saveNimModel(model) {
|
|
99
|
+
updateStoredConfig({ nimModel: model });
|
|
100
|
+
}
|
|
101
|
+
loadStoredNimApiKey();
|
|
102
|
+
loadStoredNimModel();
|
|
103
|
+
export function getConfig(projectRoot) {
|
|
104
|
+
loadEnvFile(resolve(projectRoot, '.env'));
|
|
105
|
+
return {
|
|
106
|
+
nimApiKey: process.env.NIM_API_KEY ?? '',
|
|
107
|
+
nimBaseUrl: process.env.NIM_BASE_URL ?? 'https://integrate.api.nvidia.com/v1',
|
|
108
|
+
nimModel: process.env.NIM_MODEL ?? 'stepfun-ai/step-3.7-flash',
|
|
109
|
+
agentTermoDir: process.env.AGENT_TERMO_DIR ?? '.claude',
|
|
110
|
+
logLevel: process.env.LOG_LEVEL || 'info',
|
|
111
|
+
confirmDestructive: process.env.CONFIRM_DESTRUCTIVE !== 'false',
|
|
112
|
+
allowedCommands: (process.env.ALLOWED_COMMANDS ?? 'git,npm,node,pnpm,yarn,tsx,tsc,npx').split(','),
|
|
113
|
+
llmTimeout: parseInt(process.env.LLM_TIMEOUT ?? '120000', 10),
|
|
114
|
+
bashTimeout: parseInt(process.env.BASH_TIMEOUT ?? '300000', 10),
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export function resolveProjectRoot(cwd) {
|
|
118
|
+
return cwd || PROJECT_ROOT;
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -96,7 +96,7 @@ async function startAgent(
|
|
|
96
96
|
program
|
|
97
97
|
.name('agent-termo')
|
|
98
98
|
.description('Terminal AI coding agent with Nvidia NIM APIs')
|
|
99
|
-
.version('1.0.
|
|
99
|
+
.version('1.0.2')
|
|
100
100
|
.argument('[project]', 'Project directory to operate in', process.cwd())
|
|
101
101
|
.option('-k, --api-key <key>', 'Nvidia NIM API key')
|
|
102
102
|
.option('-m, --model <model>', 'Model name to use')
|
package/src/llm/client.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import OpenAI from 'openai';
|
|
6
6
|
import type { ToolCall, ConversationMessage, ToolDef } from '../types/index.js';
|
|
7
|
+
import { mergeModels, type ModelInfo } from './models.js';
|
|
7
8
|
|
|
8
9
|
type NIMTool = OpenAI.Chat.ChatCompletionTool;
|
|
9
10
|
|
|
@@ -40,6 +41,29 @@ export class NimClient {
|
|
|
40
41
|
return this.model;
|
|
41
42
|
}
|
|
42
43
|
|
|
44
|
+
setModel(model: string): void {
|
|
45
|
+
this.model = model;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Fetch the models this API key can use. Never throws: on failure the curated
|
|
50
|
+
* list is returned with `live: false` and the reason in `error`.
|
|
51
|
+
*/
|
|
52
|
+
async listModels(): Promise<{ models: ModelInfo[]; live: boolean; error?: string }> {
|
|
53
|
+
try {
|
|
54
|
+
const page = await this.client.models.list({ timeout: 10_000 });
|
|
55
|
+
const ids = page.data.map((m) => m.id);
|
|
56
|
+
if (ids.length === 0) throw new Error('empty model list');
|
|
57
|
+
return { models: mergeModels(ids), live: true };
|
|
58
|
+
} catch (err) {
|
|
59
|
+
return {
|
|
60
|
+
models: mergeModels(null),
|
|
61
|
+
live: false,
|
|
62
|
+
error: err instanceof Error ? err.message : String(err),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
43
67
|
/**
|
|
44
68
|
* Streaming chat completion.
|
|
45
69
|
* Handles Stepfun's quirks: filters "null" reasoning chunks, strips reasoning field.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// NVIDIA NIM model catalogue — curated suggestions + live /v1/models merge
|
|
3
|
+
// =============================================================================
|
|
4
|
+
|
|
5
|
+
export interface ModelInfo {
|
|
6
|
+
id: string;
|
|
7
|
+
note?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Hand-picked chat/coding models worth surfacing first. This list is only a
|
|
12
|
+
* starting point: when the live catalogue is reachable, entries NIM no longer
|
|
13
|
+
* serves are dropped, and everything else NIM returns is still selectable.
|
|
14
|
+
*/
|
|
15
|
+
export const CURATED_MODELS: ModelInfo[] = [
|
|
16
|
+
{ id: 'stepfun-ai/step-3.7-flash', note: 'default' },
|
|
17
|
+
{ id: 'meta/llama-3.1-8b-instruct', note: 'fast, low cost' },
|
|
18
|
+
{ id: 'meta/llama-3.1-70b-instruct', note: 'balanced' },
|
|
19
|
+
{ id: 'meta/llama-3.3-70b-instruct', note: 'balanced' },
|
|
20
|
+
{ id: 'meta/llama-3.1-405b-instruct', note: 'highest quality Llama' },
|
|
21
|
+
{ id: 'nvidia/llama-3.1-nemotron-70b-instruct', note: 'NVIDIA tuned' },
|
|
22
|
+
{ id: 'qwen/qwen2.5-coder-32b-instruct', note: 'coding' },
|
|
23
|
+
{ id: 'deepseek-ai/deepseek-r1', note: 'reasoning' },
|
|
24
|
+
{ id: 'moonshotai/kimi-k2-instruct', note: 'agentic / tool use' },
|
|
25
|
+
{ id: 'openai/gpt-oss-120b', note: 'open-weight GPT' },
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
// NIM serves embedding, vision, speech and other non-chat models from the same
|
|
29
|
+
// endpoint. Hide the obvious ones so the picker stays about chat models.
|
|
30
|
+
const NON_CHAT =
|
|
31
|
+
/embed|rerank|retriev|reward|guard|safety|parse|clip|vila|neva|fuyu|kosmos|paligemma|deplot|riva|asr|tts|whisper|diffusion|sdxl|flux|cosmos|segment|bge-|e5-|gliner|pii|streampetr|ocdrnet|bevformer/i;
|
|
32
|
+
|
|
33
|
+
export function isChatModel(id: string): boolean {
|
|
34
|
+
return !NON_CHAT.test(id);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Build the picker list.
|
|
39
|
+
* - live === null: the catalogue could not be fetched, so offer the curated list.
|
|
40
|
+
* - otherwise: curated entries that NIM serves first, then the rest of the live
|
|
41
|
+
* chat models alphabetically.
|
|
42
|
+
*/
|
|
43
|
+
export function mergeModels(live: string[] | null): ModelInfo[] {
|
|
44
|
+
if (!live) return [...CURATED_MODELS];
|
|
45
|
+
|
|
46
|
+
const liveSet = new Set(live);
|
|
47
|
+
const curated = CURATED_MODELS.filter((m) => liveSet.has(m.id));
|
|
48
|
+
const curatedIds = new Set(curated.map((m) => m.id));
|
|
49
|
+
const rest = live
|
|
50
|
+
.filter((id) => !curatedIds.has(id) && isChatModel(id))
|
|
51
|
+
.sort((a, b) => a.localeCompare(b))
|
|
52
|
+
.map((id): ModelInfo => ({ id }));
|
|
53
|
+
|
|
54
|
+
return [...curated, ...rest];
|
|
55
|
+
}
|