agent-termo 1.0.0 → 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 +30 -11
- 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 -164
- 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 +2 -2
- package/src/cli.ts +91 -12
- 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 +62 -2
|
@@ -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":"AAAA,gFAAgF;AAChF,uBAAuB;AACvB,gFAAgF;AAEhF,0EAA0E;AAC1E,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,8BAA8B;IAC9B,OAAO,EAAK,gBAAgB;IAC5B,SAAS,EAAI,eAAe;IAE5B,WAAW;IACX,OAAO,EAAK,eAAe,EAAI,YAAY;IAC3C,OAAO,EAAK,gBAAgB,EAAG,YAAY;IAC3C,KAAK,EAAO,gBAAgB,EAAG,UAAU;IACzC,IAAI,EAAQ,eAAe,EAAI,WAAW;IAE1C,sBAAsB;IACtB,UAAU,EAAE,eAAe,EAAG,YAAY;IAC1C,OAAO,EAAK,eAAe,EAAG,YAAY;IAC1C,QAAQ,EAAI,eAAe,EAAG,YAAY;IAC1C,MAAM,EAAM,gBAAgB,EAAG,UAAU;IACzC,WAAW,EAAC,gBAAgB,EAAE,UAAU;IAExC,OAAO;IACP,IAAI,EAAS,gBAAgB,EAAE,WAAW;IAC1C,aAAa,EAAC,gBAAgB,EAAC,YAAY;IAC3C,KAAK,EAAQ,gBAAgB,EAAE,YAAY;IAC3C,GAAG,EAAU,gBAAgB,EAAE,YAAY;IAE3C,qBAAqB;IACrB,OAAO,EAAI,gBAAgB,EAAG,SAAS;IACvC,SAAS,EAAE,eAAe,EAAI,OAAO;IACrC,MAAM,EAAK,eAAe,EAAI,QAAQ;IACtC,QAAQ,EAAG,gBAAgB,EAAG,QAAQ;IAEtC,cAAc;IACd,WAAW,EAAG,gBAAgB,EAAE,WAAW;IAC3C,UAAU,EAAI,gBAAgB,EAAE,YAAY;IAC5C,WAAW,EAAG,gBAAgB,EAAE,WAAW;IAC3C,YAAY,EAAE,eAAe,EAAG,WAAW;IAC3C,QAAQ,EAAM,gBAAgB,EAAE,cAAc;IAE9C,QAAQ;IACR,OAAO,EAAG,eAAe,EAAI,iBAAiB;IAC9C,KAAK,EAAK,gBAAgB,EAAG,gBAAgB;IAE7C,aAAa;IACb,MAAM,EAAI,eAAe,EAAG,cAAc;IAE1C,QAAQ;IACR,KAAK,EAAK,SAAS;IACnB,MAAM,EAAI,SAAS;IACnB,QAAQ,EAAE,SAAS;IACnB,MAAM,EAAI,SAAS;IACnB,SAAS,EAAC,SAAS;CACpB,CAAC;AAEF,MAAM,CAAC,MAAM,EAAE,GAAG;IAChB,OAAO,EAAI,eAAe;IAC1B,QAAQ,EAAG,eAAe;IAC1B,SAAS,EAAE,eAAe;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,IAAI,EAAE,SAAS;IACf,GAAG,EAAG,SAAS;IACf,GAAG,EAAG,SAAS;IACf,EAAE,EAAI,SAAS;IACf,KAAK,EAAE,SAAS;CACjB,CAAC;AAEF,iBAAiB;AACjB,MAAM,UAAU,KAAK,CAAC,SAAiB,EAAE,IAAY;IACnD,OAAO,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,EAAE,CAAC,SAAiB,EAAE,IAAY;IAChD,OAAO,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;AAC9C,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,IAAY;IAC/B,OAAO,GAAG,GAAG,CAAC,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,GAAG,CAAC,IAAY;IAC9B,OAAO,GAAG,GAAG,CAAC,GAAG,GAAG,IAAI,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC;AACzC,CAAC;AAED,kDAAkD;AAClD,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAC1E,IAAI,YAAY,GAAG,CAAC,CAAC;AAErB,MAAM,UAAU,YAAY;IAC1B,MAAM,KAAK,GAAG,cAAc,CAAC,YAAY,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACnE,YAAY,EAAE,CAAC;IACf,OAAO,KAAK,IAAI,GAAG,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,YAAY,GAAG,CAAC,CAAC;AACnB,CAAC;AAED,sBAAsB;AACtB,MAAM,UAAU,IAAI,CAAC,MAAc,EAAE,IAAI,GAAG,GAAG;IAC7C,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,KAAK,CAAC,IAAY,EAAE,SAAiB;IACnD,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;AAC9C,CAAC;AAED,eAAe;AACf,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,KAAK,GAAG,EAAE;IACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC7B,OAAO,IAAI,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC;AACvF,CAAC;AAED,oBAAoB;AACpB,MAAM,UAAU,UAAU,CAAC,SAAiB;IAC1C,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC;IACtC,IAAI,KAAK,CAAC,QAAQ,CAAC,iBAAiB,CAAC;QAAE,OAAO,MAAM,CAAC,OAAO,CAAC;IAC7D,IAAI,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC;QAAE,OAAO,MAAM,CAAC,SAAS,CAAC;IACvF,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IACnF,OAAO,MAAM,CAAC,MAAM,CAAC;AACvB,CAAC;AAED,oBAAoB;AACpB,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC;AACrC,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;AACrC,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC;AACnC,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC;AACtC,MAAM,CAAC,MAAM,UAAU,GAAG,WAAW,CAAC"}
|
|
@@ -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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-termo",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Terminal-based AI coding agent that replicates Claude Code experience",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -87,4 +87,4 @@
|
|
|
87
87
|
],
|
|
88
88
|
"outputPath": "dist"
|
|
89
89
|
}
|
|
90
|
-
}
|
|
90
|
+
}
|
package/src/cli.ts
CHANGED
|
@@ -5,25 +5,104 @@
|
|
|
5
5
|
|
|
6
6
|
import { Command } from 'commander';
|
|
7
7
|
import { runRepl } from './main.js';
|
|
8
|
+
import { saveNimApiKey } from './utils/config.js';
|
|
8
9
|
|
|
9
10
|
const program = new Command();
|
|
10
11
|
|
|
12
|
+
async function promptForApiKey(): Promise<string> {
|
|
13
|
+
const input = process.stdin;
|
|
14
|
+
const output = process.stdout;
|
|
15
|
+
|
|
16
|
+
if (!input.isTTY || typeof input.setRawMode !== 'function') {
|
|
17
|
+
throw new Error(
|
|
18
|
+
'NVIDIA NIM API key is missing. Run Agent-Termo in an interactive terminal or set NIM_API_KEY before starting.',
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
console.log('An NVIDIA NIM API key is required to start Agent-Termo.');
|
|
23
|
+
console.log('Get your key at https://build.nvidia.com/');
|
|
24
|
+
output.write('Enter your API key (input hidden): ');
|
|
25
|
+
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
let apiKey = '';
|
|
28
|
+
let previousWasCarriageReturn = false;
|
|
29
|
+
|
|
30
|
+
const restoreTerminal = () => {
|
|
31
|
+
input.off('data', onData);
|
|
32
|
+
input.setRawMode(false);
|
|
33
|
+
input.pause();
|
|
34
|
+
output.write('\n');
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const onData = (data: Buffer) => {
|
|
38
|
+
for (const char of data.toString('utf-8')) {
|
|
39
|
+
if (char === '\n' && previousWasCarriageReturn) {
|
|
40
|
+
previousWasCarriageReturn = false;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
previousWasCarriageReturn = char === '\r';
|
|
44
|
+
|
|
45
|
+
if (char === '\u0003' || char === '\u0004') {
|
|
46
|
+
restoreTerminal();
|
|
47
|
+
reject(new Error('API key setup cancelled.'));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (char === '\r' || char === '\n') {
|
|
52
|
+
if (!apiKey.trim()) {
|
|
53
|
+
output.write('\nAn API key is required. Enter your API key: ');
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
restoreTerminal();
|
|
58
|
+
resolve(apiKey.trim());
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (char === '\u007f' || char === '\b') {
|
|
63
|
+
apiKey = apiKey.slice(0, -1);
|
|
64
|
+
} else if (char >= ' ') {
|
|
65
|
+
apiKey += char;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
input.setRawMode(true);
|
|
71
|
+
input.resume();
|
|
72
|
+
input.on('data', onData);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function startAgent(
|
|
77
|
+
project: string,
|
|
78
|
+
options: { apiKey?: string; model?: string; debug?: boolean },
|
|
79
|
+
): Promise<void> {
|
|
80
|
+
// Apply CLI overrides to env before main initializes.
|
|
81
|
+
if (options.apiKey) process.env.NIM_API_KEY = options.apiKey;
|
|
82
|
+
if (options.model) process.env.NIM_MODEL = options.model;
|
|
83
|
+
if (options.debug) process.env.LOG_LEVEL = 'debug';
|
|
84
|
+
|
|
85
|
+
if (!process.env.NIM_API_KEY?.trim()) {
|
|
86
|
+
const apiKey = await promptForApiKey();
|
|
87
|
+
saveNimApiKey(apiKey);
|
|
88
|
+
process.env.NIM_API_KEY = apiKey;
|
|
89
|
+
console.log('API key saved. Agent-Termo will remember it for future sessions.');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(`Starting Agent-Termo in: ${project}`);
|
|
93
|
+
await runRepl(project);
|
|
94
|
+
}
|
|
95
|
+
|
|
11
96
|
program
|
|
12
97
|
.name('agent-termo')
|
|
13
98
|
.description('Terminal AI coding agent with Nvidia NIM APIs')
|
|
14
|
-
.version('1.0.
|
|
99
|
+
.version('1.0.2')
|
|
15
100
|
.argument('[project]', 'Project directory to operate in', process.cwd())
|
|
16
101
|
.option('-k, --api-key <key>', 'Nvidia NIM API key')
|
|
17
102
|
.option('-m, --model <model>', 'Model name to use')
|
|
18
103
|
.option('--debug', 'Enable debug logging')
|
|
19
104
|
.action(async (project: string, options: { apiKey?: string; model?: string; debug?: boolean }) => {
|
|
20
|
-
|
|
21
|
-
if (options.apiKey) process.env.NIM_API_KEY = options.apiKey;
|
|
22
|
-
if (options.model) process.env.NIM_MODEL = options.model;
|
|
23
|
-
if (options.debug) process.env.LOG_LEVEL = 'debug';
|
|
24
|
-
|
|
25
|
-
console.log(`Starting Agent-Termo in: ${project}`);
|
|
26
|
-
await runRepl(project);
|
|
105
|
+
await startAgent(project, options);
|
|
27
106
|
});
|
|
28
107
|
|
|
29
108
|
program
|
|
@@ -56,14 +135,14 @@ program
|
|
|
56
135
|
|
|
57
136
|
console.log(`\n✓ Initialized Agent-Termo in ${resolve(dir)}`);
|
|
58
137
|
console.log(' Created: docs/MEMORY.md, docs/TIMELINE.md');
|
|
59
|
-
console.log('
|
|
138
|
+
console.log(' Agent-Termo will ask for your NVIDIA NIM API key the first time you launch it.');
|
|
60
139
|
});
|
|
61
140
|
|
|
62
141
|
async function main() {
|
|
63
|
-
//
|
|
142
|
+
// Run REPL mode directly when no command or options are supplied.
|
|
64
143
|
const args = process.argv.slice(2);
|
|
65
144
|
if (args.length === 0) {
|
|
66
|
-
await
|
|
145
|
+
await startAgent(process.cwd(), {});
|
|
67
146
|
return;
|
|
68
147
|
}
|
|
69
148
|
|
|
@@ -73,4 +152,4 @@ async function main() {
|
|
|
73
152
|
main().catch((err) => {
|
|
74
153
|
console.error(`\nFatal error: ${err instanceof Error ? err.message : err}`);
|
|
75
154
|
process.exit(1);
|
|
76
|
-
});
|
|
155
|
+
});
|
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
|
+
}
|