centaurus-cli 3.1.2 → 3.1.4
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/dist/cli-adapter.js +689 -155
- package/dist/cli-adapter.js.map +1 -1
- package/dist/config/defaultConfig.js +1 -4
- package/dist/config/defaultConfig.js.map +1 -1
- package/dist/config/models.js +6 -0
- package/dist/config/models.js.map +1 -1
- package/dist/config/slash-commands.js +66 -2
- package/dist/config/slash-commands.js.map +1 -1
- package/dist/config/types.js +4 -4
- package/dist/config/types.js.map +1 -1
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -1
- package/dist/services/ai-context-injector.js +109 -0
- package/dist/services/ai-context-injector.js.map +1 -1
- package/dist/services/ai-service-client.js +3 -2
- package/dist/services/ai-service-client.js.map +1 -1
- package/dist/services/api-client.js.map +1 -1
- package/dist/services/background-task-manager.js +59 -0
- package/dist/services/background-task-manager.js.map +1 -1
- package/dist/services/local-chat-storage.js +2 -0
- package/dist/services/local-chat-storage.js.map +1 -1
- package/dist/services/skill-storage.js +141 -0
- package/dist/services/skill-storage.js.map +1 -0
- package/dist/services/sub-agent-manager.js +49 -8
- package/dist/services/sub-agent-manager.js.map +1 -1
- package/dist/services/warpify-detector.js +17 -5
- package/dist/services/warpify-detector.js.map +1 -1
- package/dist/tools/background-command.js +5 -2
- package/dist/tools/background-command.js.map +1 -1
- package/dist/tools/command.js +367 -109
- package/dist/tools/command.js.map +1 -1
- package/dist/tools/file-ops.js +23 -6
- package/dist/tools/file-ops.js.map +1 -1
- package/dist/tools/plan-mode.js +184 -336
- package/dist/tools/plan-mode.js.map +1 -1
- package/dist/tools/sub-agent.js +24 -5
- package/dist/tools/sub-agent.js.map +1 -1
- package/dist/tools/todo-list.js +157 -0
- package/dist/tools/todo-list.js.map +1 -0
- package/dist/types/skill.js +30 -0
- package/dist/types/skill.js.map +1 -0
- package/dist/ui/components/App.js +956 -162
- package/dist/ui/components/App.js.map +1 -1
- package/dist/ui/components/AuthScreen.js +3 -1
- package/dist/ui/components/AuthScreen.js.map +1 -1
- package/dist/ui/components/AuthWelcomeScreen.js +3 -1
- package/dist/ui/components/AuthWelcomeScreen.js.map +1 -1
- package/dist/ui/components/CodeBlock.js +3 -1
- package/dist/ui/components/CodeBlock.js.map +1 -1
- package/dist/ui/components/CompactShellPreview.js +44 -0
- package/dist/ui/components/CompactShellPreview.js.map +1 -0
- package/dist/ui/components/ConfigViewer.js +3 -1
- package/dist/ui/components/ConfigViewer.js.map +1 -1
- package/dist/ui/components/ConfirmPrompt.js +3 -1
- package/dist/ui/components/ConfirmPrompt.js.map +1 -1
- package/dist/ui/components/ConnectionStatusMessage.js +3 -1
- package/dist/ui/components/ConnectionStatusMessage.js.map +1 -1
- package/dist/ui/components/DetailedPlanReviewScreen.js +84 -74
- package/dist/ui/components/DetailedPlanReviewScreen.js.map +1 -1
- package/dist/ui/components/DiffViewer.js +6 -3
- package/dist/ui/components/DiffViewer.js.map +1 -1
- package/dist/ui/components/FileCreationPreview.js.map +1 -1
- package/dist/ui/components/FileTagAutocomplete.js +4 -2
- package/dist/ui/components/FileTagAutocomplete.js.map +1 -1
- package/dist/ui/components/InputBox.js +243 -40
- package/dist/ui/components/InputBox.js.map +1 -1
- package/dist/ui/components/InteractiveShell.js +5 -3
- package/dist/ui/components/InteractiveShell.js.map +1 -1
- package/dist/ui/components/KeyboardHelp.js +4 -1
- package/dist/ui/components/KeyboardHelp.js.map +1 -1
- package/dist/ui/components/LoadingIndicator.js +3 -1
- package/dist/ui/components/LoadingIndicator.js.map +1 -1
- package/dist/ui/components/MCPAddScreen.js +63 -13
- package/dist/ui/components/MCPAddScreen.js.map +1 -1
- package/dist/ui/components/MarkdownRenderer.js +3 -1
- package/dist/ui/components/MarkdownRenderer.js.map +1 -1
- package/dist/ui/components/MessageDisplay.js +9 -7
- package/dist/ui/components/MessageDisplay.js.map +1 -1
- package/dist/ui/components/ModelPicker.js +170 -0
- package/dist/ui/components/ModelPicker.js.map +1 -0
- package/dist/ui/components/MonitorModeAIPanel.js +3 -1
- package/dist/ui/components/MonitorModeAIPanel.js.map +1 -1
- package/dist/ui/components/PlanAcceptedMessage.js +12 -6
- package/dist/ui/components/PlanAcceptedMessage.js.map +1 -1
- package/dist/ui/components/PlanQuestionMessage.js +37 -0
- package/dist/ui/components/PlanQuestionMessage.js.map +1 -0
- package/dist/ui/components/PlanQuestionScreen.js +138 -0
- package/dist/ui/components/PlanQuestionScreen.js.map +1 -0
- package/dist/ui/components/PlanReviewScreen.js +7 -9
- package/dist/ui/components/PlanReviewScreen.js.map +1 -1
- package/dist/ui/components/RulesEditorScreen.js +65 -28
- package/dist/ui/components/RulesEditorScreen.js.map +1 -1
- package/dist/ui/components/SelectPrompt.js +3 -1
- package/dist/ui/components/SelectPrompt.js.map +1 -1
- package/dist/ui/components/SkillCreatorScreen.js +217 -0
- package/dist/ui/components/SkillCreatorScreen.js.map +1 -0
- package/dist/ui/components/SlashCommandAutocomplete.js +4 -2
- package/dist/ui/components/SlashCommandAutocomplete.js.map +1 -1
- package/dist/ui/components/StatusBar.js +4 -2
- package/dist/ui/components/StatusBar.js.map +1 -1
- package/dist/ui/components/StreamingMessageDisplay.js +5 -3
- package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
- package/dist/ui/components/SubAgentListScreen.js +65 -0
- package/dist/ui/components/SubAgentListScreen.js.map +1 -0
- package/dist/ui/components/SubAgentViewScreen.js +123 -0
- package/dist/ui/components/SubAgentViewScreen.js.map +1 -0
- package/dist/ui/components/TaskCompletedMessage.js +40 -8
- package/dist/ui/components/TaskCompletedMessage.js.map +1 -1
- package/dist/ui/components/TaskProgressIndicator.js +6 -4
- package/dist/ui/components/TaskProgressIndicator.js.map +1 -1
- package/dist/ui/components/TextEditor.js +297 -0
- package/dist/ui/components/TextEditor.js.map +1 -0
- package/dist/ui/components/TodoListMessage.js +59 -0
- package/dist/ui/components/TodoListMessage.js.map +1 -0
- package/dist/ui/components/ToolExecutionMessage.js +134 -84
- package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
- package/dist/ui/components/ToolExecutionStatus.js +3 -1
- package/dist/ui/components/ToolExecutionStatus.js.map +1 -1
- package/dist/ui/components/WelcomeBanner.js +33 -33
- package/dist/ui/components/WelcomeBanner.js.map +1 -1
- package/dist/ui/components/WorkflowCreatorScreen.js +5 -3
- package/dist/ui/components/WorkflowCreatorScreen.js.map +1 -1
- package/dist/ui/theme.js +97 -0
- package/dist/ui/theme.js.map +1 -0
- package/dist/ui/utils/chat-history-limit.js +247 -0
- package/dist/ui/utils/chat-history-limit.js.map +1 -0
- package/dist/utils/chat-formatter.js +22 -9
- package/dist/utils/chat-formatter.js.map +1 -1
- package/dist/utils/git-stats.js +7 -5
- package/dist/utils/git-stats.js.map +1 -1
- package/dist/utils/input-classifier.js +11 -1
- package/dist/utils/input-classifier.js.map +1 -1
- package/dist/utils/output-truncation.js +175 -0
- package/dist/utils/output-truncation.js.map +1 -0
- package/dist/utils/rule-reference-resolver.js +3 -3
- package/dist/utils/rule-reference-resolver.js.map +1 -1
- package/dist/utils/tunnel-commands-manager.js +134 -0
- package/dist/utils/tunnel-commands-manager.js.map +1 -0
- package/package.json +91 -90
- package/postinstall.js +4 -11
- package/dist/ui/components/MultiLineInput.js +0 -255
- package/dist/ui/components/MultiLineInput.js.map +0 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import * as fs from "fs/promises";
|
|
2
|
+
import * as fsSync from "fs";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as os from "os";
|
|
5
|
+
function normalizeTunnelCommand(command) {
|
|
6
|
+
return command.trim().replace(/\s+/g, " ").toLowerCase();
|
|
7
|
+
}
|
|
8
|
+
function matchTunnelableCommand(command, registeredCommands) {
|
|
9
|
+
const normalizedInput = normalizeTunnelCommand(command);
|
|
10
|
+
if (!normalizedInput) {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
const normalizedRegistered = [...new Set(
|
|
14
|
+
registeredCommands.map(normalizeTunnelCommand).filter(Boolean)
|
|
15
|
+
)].sort((a, b) => b.length - a.length);
|
|
16
|
+
for (const registeredCommand of normalizedRegistered) {
|
|
17
|
+
if (normalizedInput === registeredCommand || normalizedInput.startsWith(`${registeredCommand} `)) {
|
|
18
|
+
return registeredCommand;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
class TunnelCommandsManager {
|
|
24
|
+
static instance;
|
|
25
|
+
configPath;
|
|
26
|
+
data;
|
|
27
|
+
loaded = false;
|
|
28
|
+
constructor() {
|
|
29
|
+
const configDir = path.join(os.homedir(), ".centaurus");
|
|
30
|
+
this.configPath = path.join(configDir, "tunnel-commands.json");
|
|
31
|
+
this.data = { commands: [], version: 1 };
|
|
32
|
+
}
|
|
33
|
+
static getInstance() {
|
|
34
|
+
if (!TunnelCommandsManager.instance) {
|
|
35
|
+
TunnelCommandsManager.instance = new TunnelCommandsManager();
|
|
36
|
+
}
|
|
37
|
+
return TunnelCommandsManager.instance;
|
|
38
|
+
}
|
|
39
|
+
async initialize() {
|
|
40
|
+
if (this.loaded) return;
|
|
41
|
+
await this.load();
|
|
42
|
+
}
|
|
43
|
+
loadSync() {
|
|
44
|
+
if (this.loaded) return;
|
|
45
|
+
try {
|
|
46
|
+
if (fsSync.existsSync(this.configPath)) {
|
|
47
|
+
const content = fsSync.readFileSync(this.configPath, "utf-8");
|
|
48
|
+
const parsed = JSON.parse(content);
|
|
49
|
+
if (parsed.commands && Array.isArray(parsed.commands)) {
|
|
50
|
+
this.data = {
|
|
51
|
+
commands: parsed.commands.map(normalizeTunnelCommand).filter(Boolean),
|
|
52
|
+
version: parsed.version || 1
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
this.data = { commands: [], version: 1 };
|
|
58
|
+
}
|
|
59
|
+
this.loaded = true;
|
|
60
|
+
}
|
|
61
|
+
async ensureConfigDir() {
|
|
62
|
+
const configDir = path.dirname(this.configPath);
|
|
63
|
+
try {
|
|
64
|
+
await fs.access(configDir);
|
|
65
|
+
} catch {
|
|
66
|
+
await fs.mkdir(configDir, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async load() {
|
|
70
|
+
try {
|
|
71
|
+
const content = await fs.readFile(this.configPath, "utf-8");
|
|
72
|
+
const parsed = JSON.parse(content);
|
|
73
|
+
if (parsed.commands && Array.isArray(parsed.commands)) {
|
|
74
|
+
this.data = {
|
|
75
|
+
commands: parsed.commands.map(normalizeTunnelCommand).filter(Boolean),
|
|
76
|
+
version: parsed.version || 1
|
|
77
|
+
};
|
|
78
|
+
} else {
|
|
79
|
+
this.data = { commands: [], version: 1 };
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
this.data = { commands: [], version: 1 };
|
|
83
|
+
}
|
|
84
|
+
this.loaded = true;
|
|
85
|
+
}
|
|
86
|
+
async save() {
|
|
87
|
+
await this.ensureConfigDir();
|
|
88
|
+
await fs.writeFile(
|
|
89
|
+
this.configPath,
|
|
90
|
+
JSON.stringify(this.data, null, 2),
|
|
91
|
+
"utf-8"
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
async addCommand(command) {
|
|
95
|
+
const normalized = normalizeTunnelCommand(command);
|
|
96
|
+
if (!normalized) {
|
|
97
|
+
return { success: false, message: "Tunnel command cannot be empty" };
|
|
98
|
+
}
|
|
99
|
+
if (this.data.commands.includes(normalized)) {
|
|
100
|
+
return { success: false, message: `Tunnel command "${normalized}" already exists` };
|
|
101
|
+
}
|
|
102
|
+
this.data.commands.push(normalized);
|
|
103
|
+
this.data.commands.sort();
|
|
104
|
+
await this.save();
|
|
105
|
+
return { success: true, message: `Added "${normalized}" to tunnel commands` };
|
|
106
|
+
}
|
|
107
|
+
async deleteCommand(command) {
|
|
108
|
+
const normalized = normalizeTunnelCommand(command);
|
|
109
|
+
const index = this.data.commands.indexOf(normalized);
|
|
110
|
+
if (index === -1) {
|
|
111
|
+
return { success: false, message: `Tunnel command "${normalized}" not found` };
|
|
112
|
+
}
|
|
113
|
+
this.data.commands.splice(index, 1);
|
|
114
|
+
await this.save();
|
|
115
|
+
return { success: true, message: `Deleted "${normalized}" from tunnel commands` };
|
|
116
|
+
}
|
|
117
|
+
listCommands() {
|
|
118
|
+
return [...this.data.commands];
|
|
119
|
+
}
|
|
120
|
+
matchCommand(command) {
|
|
121
|
+
return matchTunnelableCommand(command, this.data.commands);
|
|
122
|
+
}
|
|
123
|
+
getCount() {
|
|
124
|
+
return this.data.commands.length;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
var tunnel_commands_manager_default = TunnelCommandsManager;
|
|
128
|
+
export {
|
|
129
|
+
TunnelCommandsManager,
|
|
130
|
+
tunnel_commands_manager_default as default,
|
|
131
|
+
matchTunnelableCommand,
|
|
132
|
+
normalizeTunnelCommand
|
|
133
|
+
};
|
|
134
|
+
//# sourceMappingURL=tunnel-commands-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/tunnel-commands-manager.ts"],"sourcesContent":["import * as fs from 'fs/promises';\r\nimport * as fsSync from 'fs';\r\nimport * as path from 'path';\r\nimport * as os from 'os';\r\n\r\ninterface TunnelCommandsData {\r\n commands: string[];\r\n version: number;\r\n}\r\n\r\nexport function normalizeTunnelCommand(command: string): string {\r\n return command.trim().replace(/\\s+/g, ' ').toLowerCase();\r\n}\r\n\r\nexport function matchTunnelableCommand(command: string, registeredCommands: string[]): string | null {\r\n const normalizedInput = normalizeTunnelCommand(command);\r\n if (!normalizedInput) {\r\n return null;\r\n }\r\n\r\n const normalizedRegistered = [...new Set(\r\n registeredCommands\r\n .map(normalizeTunnelCommand)\r\n .filter(Boolean)\r\n )].sort((a, b) => b.length - a.length);\r\n\r\n for (const registeredCommand of normalizedRegistered) {\r\n if (\r\n normalizedInput === registeredCommand ||\r\n normalizedInput.startsWith(`${registeredCommand} `)\r\n ) {\r\n return registeredCommand;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport class TunnelCommandsManager {\r\n private static instance: TunnelCommandsManager;\r\n private configPath: string;\r\n private data: TunnelCommandsData;\r\n private loaded: boolean = false;\r\n\r\n private constructor() {\r\n const configDir = path.join(os.homedir(), '.centaurus');\r\n this.configPath = path.join(configDir, 'tunnel-commands.json');\r\n this.data = { commands: [], version: 1 };\r\n }\r\n\r\n static getInstance(): TunnelCommandsManager {\r\n if (!TunnelCommandsManager.instance) {\r\n TunnelCommandsManager.instance = new TunnelCommandsManager();\r\n }\r\n return TunnelCommandsManager.instance;\r\n }\r\n\r\n async initialize(): Promise<void> {\r\n if (this.loaded) return;\r\n await this.load();\r\n }\r\n\r\n loadSync(): void {\r\n if (this.loaded) return;\r\n\r\n try {\r\n if (fsSync.existsSync(this.configPath)) {\r\n const content = fsSync.readFileSync(this.configPath, 'utf-8');\r\n const parsed = JSON.parse(content);\r\n if (parsed.commands && Array.isArray(parsed.commands)) {\r\n this.data = {\r\n commands: parsed.commands.map(normalizeTunnelCommand).filter(Boolean),\r\n version: parsed.version || 1,\r\n };\r\n }\r\n }\r\n } catch {\r\n this.data = { commands: [], version: 1 };\r\n }\r\n\r\n this.loaded = true;\r\n }\r\n\r\n private async ensureConfigDir(): Promise<void> {\r\n const configDir = path.dirname(this.configPath);\r\n try {\r\n await fs.access(configDir);\r\n } catch {\r\n await fs.mkdir(configDir, { recursive: true });\r\n }\r\n }\r\n\r\n private async load(): Promise<void> {\r\n try {\r\n const content = await fs.readFile(this.configPath, 'utf-8');\r\n const parsed = JSON.parse(content);\r\n if (parsed.commands && Array.isArray(parsed.commands)) {\r\n this.data = {\r\n commands: parsed.commands.map(normalizeTunnelCommand).filter(Boolean),\r\n version: parsed.version || 1,\r\n };\r\n } else {\r\n this.data = { commands: [], version: 1 };\r\n }\r\n } catch {\r\n this.data = { commands: [], version: 1 };\r\n }\r\n\r\n this.loaded = true;\r\n }\r\n\r\n private async save(): Promise<void> {\r\n await this.ensureConfigDir();\r\n await fs.writeFile(\r\n this.configPath,\r\n JSON.stringify(this.data, null, 2),\r\n 'utf-8'\r\n );\r\n }\r\n\r\n async addCommand(command: string): Promise<{ success: boolean; message: string }> {\r\n const normalized = normalizeTunnelCommand(command);\r\n\r\n if (!normalized) {\r\n return { success: false, message: 'Tunnel command cannot be empty' };\r\n }\r\n\r\n if (this.data.commands.includes(normalized)) {\r\n return { success: false, message: `Tunnel command \"${normalized}\" already exists` };\r\n }\r\n\r\n this.data.commands.push(normalized);\r\n this.data.commands.sort();\r\n await this.save();\r\n\r\n return { success: true, message: `Added \"${normalized}\" to tunnel commands` };\r\n }\r\n\r\n async deleteCommand(command: string): Promise<{ success: boolean; message: string }> {\r\n const normalized = normalizeTunnelCommand(command);\r\n const index = this.data.commands.indexOf(normalized);\r\n\r\n if (index === -1) {\r\n return { success: false, message: `Tunnel command \"${normalized}\" not found` };\r\n }\r\n\r\n this.data.commands.splice(index, 1);\r\n await this.save();\r\n\r\n return { success: true, message: `Deleted \"${normalized}\" from tunnel commands` };\r\n }\r\n\r\n listCommands(): string[] {\r\n return [...this.data.commands];\r\n }\r\n\r\n matchCommand(command: string): string | null {\r\n return matchTunnelableCommand(command, this.data.commands);\r\n }\r\n\r\n getCount(): number {\r\n return this.data.commands.length;\r\n }\r\n}\r\n\r\nexport default TunnelCommandsManager;\r\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,92 +1,93 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name":
|
|
3
|
-
"version":
|
|
4
|
-
"description":
|
|
5
|
-
"type":
|
|
6
|
-
"main":
|
|
7
|
-
"bin":
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"scripts":
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
2
|
+
"name": "centaurus-cli",
|
|
3
|
+
"version": "3.1.4",
|
|
4
|
+
"description": "A powerful command-line AI coding assistant with Google Gemini support",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"centaurus": "dist/index.js",
|
|
9
|
+
"centaurus-cli": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc --noEmit && tsup",
|
|
13
|
+
"build:release": "node scripts/build-release-bundle.mjs",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"dev": "tsup --watch",
|
|
16
|
+
"start": "node --max-old-space-size=6144 dist/index.js",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"postinstall": "node postinstall.js || true",
|
|
19
|
+
"test": "node --experimental-vm-modules node_modules/.bin/jest --config jest.config.cjs",
|
|
20
|
+
"test:ci": "node --experimental-vm-modules node_modules/.bin/jest --config jest.config.cjs --ci --forceExit"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"ai",
|
|
24
|
+
"cli",
|
|
25
|
+
"coding-assistant",
|
|
26
|
+
"gemini",
|
|
27
|
+
"agentic",
|
|
28
|
+
"code-editor",
|
|
29
|
+
"ai-assistant",
|
|
30
|
+
"terminal",
|
|
31
|
+
"developer-tools",
|
|
32
|
+
"llm",
|
|
33
|
+
"artificial-intelligence"
|
|
34
|
+
],
|
|
35
|
+
"author": "Rohan Abhilash S",
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18.0.0"
|
|
39
|
+
},
|
|
40
|
+
"files": [
|
|
41
|
+
"dist",
|
|
42
|
+
"prompts",
|
|
43
|
+
"postinstall.js",
|
|
44
|
+
"models-config.json",
|
|
45
|
+
"README.md",
|
|
46
|
+
"LICENSE",
|
|
47
|
+
"CONFIG_GUIDE.md",
|
|
48
|
+
"AUTH_FLOW.md"
|
|
49
|
+
],
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"@anthropic-ai/sdk": "^0.74.0",
|
|
52
|
+
"@crosscopy/clipboard": "^0.2.8",
|
|
53
|
+
"@homebridge/node-pty-prebuilt-multiarch": "^0.13.1",
|
|
54
|
+
"@huggingface/transformers": "^3.8.1",
|
|
55
|
+
"@modelcontextprotocol/sdk": "^1.24.2",
|
|
56
|
+
"@types/sharp": "^0.31.1",
|
|
57
|
+
"axios": "^1.12.2",
|
|
58
|
+
"boxen": "^8.0.1",
|
|
59
|
+
"chalk": "^5.6.2",
|
|
60
|
+
"cheerio": "^1.1.2",
|
|
61
|
+
"cli-highlight": "^2.1.11",
|
|
62
|
+
"clipboard-files": "^3.0.0",
|
|
63
|
+
"commander": "^14.0.1",
|
|
64
|
+
"cross-spawn": "^7.0.6",
|
|
65
|
+
"diff": "^8.0.2",
|
|
66
|
+
"fast-glob": "^3.3.3",
|
|
67
|
+
"ink": "^4.4.1",
|
|
68
|
+
"ink-select-input": "^5.0.0",
|
|
69
|
+
"ink-spinner": "^5.0.0",
|
|
70
|
+
"ink-text-input": "^5.0.1",
|
|
71
|
+
"js-tiktoken": "^1.0.21",
|
|
72
|
+
"open": "^10.1.0",
|
|
73
|
+
"react": "^18.3.1",
|
|
74
|
+
"sharp": "^0.34.5",
|
|
75
|
+
"ssh2": "^1.15.0",
|
|
76
|
+
"string-width": "^8.1.0",
|
|
77
|
+
"strip-ansi": "^7.1.0",
|
|
78
|
+
"typescript": "^5.9.3",
|
|
79
|
+
"wrap-ansi": "^9.0.2"
|
|
80
|
+
},
|
|
81
|
+
"devDependencies": {
|
|
82
|
+
"@types/inquirer": "^9.0.9",
|
|
83
|
+
"@types/jest": "^30.0.0",
|
|
84
|
+
"@types/node": "^24.7.2",
|
|
85
|
+
"@types/react": "^18.3.26",
|
|
86
|
+
"@types/ssh2": "^1.15.0",
|
|
87
|
+
"jest": "^30.2.0",
|
|
88
|
+
"prettier": "^3.6.2",
|
|
89
|
+
"ts-jest": "^29.4.6",
|
|
90
|
+
"ts-node": "^10.9.2",
|
|
91
|
+
"tsup": "^8.5.1"
|
|
92
|
+
}
|
|
92
93
|
}
|
package/postinstall.js
CHANGED
|
@@ -16,22 +16,15 @@ ${chalk.bold('Quick Start:')}
|
|
|
16
16
|
1. Run Centaurus in any directory:
|
|
17
17
|
${chalk.cyan('$ centaurus')}
|
|
18
18
|
|
|
19
|
-
2.
|
|
20
|
-
${chalk.cyan('/config set googleApiKey YOUR_KEY')}
|
|
21
|
-
|
|
22
|
-
3. Start chatting with AI!
|
|
23
|
-
|
|
24
|
-
${chalk.bold('Get API Keys:')}
|
|
25
|
-
• Google AI: ${chalk.blue('https://makersuite.google.com/app/apikey')}
|
|
26
|
-
• OpenRouter: ${chalk.blue('https://openrouter.ai/keys')}
|
|
19
|
+
2. Sign in when prompted and start chatting with AI.
|
|
27
20
|
|
|
28
21
|
${chalk.bold('Documentation:')}
|
|
29
|
-
•
|
|
30
|
-
•
|
|
22
|
+
• Run ${chalk.cyan('centaurus')} and type ${chalk.cyan('/help')}
|
|
23
|
+
• Open the web docs from the app when needed
|
|
31
24
|
|
|
32
25
|
${chalk.bold('Need Help?')}
|
|
33
26
|
• Type ${chalk.cyan('/help')} in the CLI
|
|
34
|
-
•
|
|
27
|
+
• Use the in-app docs and support links
|
|
35
28
|
|
|
36
29
|
${chalk.dim('Made with ❤️ by developers, for developers')}
|
|
37
30
|
`;
|
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef } from "react";
|
|
2
|
-
import { Box, Text, useInput } from "ink";
|
|
3
|
-
const isWordBoundary = (char) => /[\s\n]/.test(char);
|
|
4
|
-
const getVisualLines = (text, width) => {
|
|
5
|
-
const logicalLines = text.split("\n");
|
|
6
|
-
const visualLines = [];
|
|
7
|
-
let currentOffset = 0;
|
|
8
|
-
logicalLines.forEach((line, i) => {
|
|
9
|
-
if (line.length === 0) {
|
|
10
|
-
visualLines.push({ start: currentOffset, end: currentOffset, isHardEnd: true });
|
|
11
|
-
currentOffset += 1;
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
let remaining = line;
|
|
15
|
-
let lineStartOffset = currentOffset;
|
|
16
|
-
while (remaining.length > 0) {
|
|
17
|
-
let splitIndex = remaining.length;
|
|
18
|
-
let isHardEnd = false;
|
|
19
|
-
if (remaining.length > width) {
|
|
20
|
-
splitIndex = width;
|
|
21
|
-
const lastSpace = remaining.lastIndexOf(" ", width);
|
|
22
|
-
if (lastSpace > 0) {
|
|
23
|
-
splitIndex = lastSpace + 1;
|
|
24
|
-
}
|
|
25
|
-
} else {
|
|
26
|
-
isHardEnd = true;
|
|
27
|
-
}
|
|
28
|
-
visualLines.push({
|
|
29
|
-
start: lineStartOffset,
|
|
30
|
-
end: lineStartOffset + splitIndex,
|
|
31
|
-
isHardEnd
|
|
32
|
-
});
|
|
33
|
-
lineStartOffset += splitIndex;
|
|
34
|
-
remaining = remaining.slice(splitIndex);
|
|
35
|
-
}
|
|
36
|
-
currentOffset += line.length + (i < logicalLines.length - 1 ? 1 : 0);
|
|
37
|
-
});
|
|
38
|
-
return visualLines;
|
|
39
|
-
};
|
|
40
|
-
const MultiLineInput = ({
|
|
41
|
-
value = "",
|
|
42
|
-
onChange,
|
|
43
|
-
onSubmit,
|
|
44
|
-
placeholder = "",
|
|
45
|
-
isActive = true,
|
|
46
|
-
minHeight = 3,
|
|
47
|
-
maxHeight = 10,
|
|
48
|
-
submitOnEnter = true
|
|
49
|
-
}) => {
|
|
50
|
-
const [cursorOffset, setCursorOffset] = useState(0);
|
|
51
|
-
const valueRef = useRef(value);
|
|
52
|
-
const cursorOffsetRef = useRef(cursorOffset);
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
valueRef.current = value;
|
|
55
|
-
}, [value]);
|
|
56
|
-
useEffect(() => {
|
|
57
|
-
cursorOffsetRef.current = cursorOffset;
|
|
58
|
-
}, [cursorOffset]);
|
|
59
|
-
useEffect(() => {
|
|
60
|
-
if (cursorOffset > value.length) {
|
|
61
|
-
setCursorOffset(value.length);
|
|
62
|
-
}
|
|
63
|
-
}, [value, cursorOffset]);
|
|
64
|
-
useInput((input, key) => {
|
|
65
|
-
if (!isActive) return;
|
|
66
|
-
const currentValue = valueRef.current;
|
|
67
|
-
const currentCursorOffset = cursorOffsetRef.current;
|
|
68
|
-
const normalizedInput = input ? input.toLowerCase() : "";
|
|
69
|
-
const isTerminalShiftEnterSequence = input === "\x1B\r" || input === "\x1B\n" || normalizedInput === "\x1B[13;2u" || normalizedInput === "\x1B[13;2~" || normalizedInput === "\x1B[27;2;13~";
|
|
70
|
-
const isEnterEvent = key.return || isTerminalShiftEnterSequence;
|
|
71
|
-
if (key.backspace || key.delete) {
|
|
72
|
-
if (currentCursorOffset > 0) {
|
|
73
|
-
const newValue = currentValue.slice(0, currentCursorOffset - 1) + currentValue.slice(currentCursorOffset);
|
|
74
|
-
onChange(newValue);
|
|
75
|
-
setCursorOffset(currentCursorOffset - 1);
|
|
76
|
-
}
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
if (isEnterEvent && (input.length <= 1 || isTerminalShiftEnterSequence)) {
|
|
80
|
-
const isBackslashEnterFallback = !key.shift && !key.ctrl && !key.meta && !isTerminalShiftEnterSequence && currentCursorOffset > 0 && currentValue[currentCursorOffset - 1] === "\\";
|
|
81
|
-
const shouldInsertNewline = !submitOnEnter || key.shift || key.ctrl || key.meta || input === "\n" || isTerminalShiftEnterSequence || isBackslashEnterFallback;
|
|
82
|
-
if (shouldInsertNewline) {
|
|
83
|
-
const newValue = isBackslashEnterFallback ? currentValue.slice(0, currentCursorOffset - 1) + "\n" + currentValue.slice(currentCursorOffset) : currentValue.slice(0, currentCursorOffset) + "\n" + currentValue.slice(currentCursorOffset);
|
|
84
|
-
const newOffset = isBackslashEnterFallback ? currentCursorOffset : currentCursorOffset + 1;
|
|
85
|
-
onChange(newValue);
|
|
86
|
-
setCursorOffset(newOffset);
|
|
87
|
-
} else {
|
|
88
|
-
onSubmit(currentValue);
|
|
89
|
-
}
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
if (key.upArrow) {
|
|
93
|
-
const width = (process.stdout.columns || 80) - 4;
|
|
94
|
-
const visualLines2 = getVisualLines(currentValue, width);
|
|
95
|
-
let currentLineIdx = visualLines2.findIndex(
|
|
96
|
-
(line) => currentCursorOffset >= line.start && currentCursorOffset < line.end || currentCursorOffset === line.end && line.isHardEnd
|
|
97
|
-
);
|
|
98
|
-
if (currentLineIdx === -1 && currentCursorOffset === currentValue.length) {
|
|
99
|
-
currentLineIdx = visualLines2.length - 1;
|
|
100
|
-
}
|
|
101
|
-
if (currentLineIdx > 0) {
|
|
102
|
-
const currentLine = visualLines2[currentLineIdx];
|
|
103
|
-
const targetLine = visualLines2[currentLineIdx - 1];
|
|
104
|
-
const offsetInLine = currentCursorOffset - currentLine.start;
|
|
105
|
-
const newOffset = targetLine.start + Math.min(offsetInLine, targetLine.end - targetLine.start);
|
|
106
|
-
setCursorOffset(newOffset);
|
|
107
|
-
} else {
|
|
108
|
-
setCursorOffset(0);
|
|
109
|
-
}
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
if (key.downArrow) {
|
|
113
|
-
const width = (process.stdout.columns || 80) - 4;
|
|
114
|
-
const visualLines2 = getVisualLines(currentValue, width);
|
|
115
|
-
let currentLineIdx = visualLines2.findIndex(
|
|
116
|
-
(line) => currentCursorOffset >= line.start && currentCursorOffset < line.end || currentCursorOffset === line.end && line.isHardEnd
|
|
117
|
-
);
|
|
118
|
-
if (currentLineIdx === -1 && currentCursorOffset === currentValue.length) {
|
|
119
|
-
currentLineIdx = visualLines2.length - 1;
|
|
120
|
-
}
|
|
121
|
-
if (currentLineIdx < visualLines2.length - 1) {
|
|
122
|
-
const currentLine = visualLines2[currentLineIdx];
|
|
123
|
-
const targetLine = visualLines2[currentLineIdx + 1];
|
|
124
|
-
const offsetInLine = currentCursorOffset - currentLine.start;
|
|
125
|
-
const newOffset = targetLine.start + Math.min(offsetInLine, targetLine.end - targetLine.start);
|
|
126
|
-
setCursorOffset(newOffset);
|
|
127
|
-
} else {
|
|
128
|
-
setCursorOffset(currentValue.length);
|
|
129
|
-
}
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
if (key.leftArrow) {
|
|
133
|
-
if (currentCursorOffset > 0) {
|
|
134
|
-
let newOffset = currentCursorOffset;
|
|
135
|
-
if (key.ctrl || key.meta) {
|
|
136
|
-
while (newOffset > 0 && isWordBoundary(currentValue[newOffset - 1])) {
|
|
137
|
-
newOffset--;
|
|
138
|
-
}
|
|
139
|
-
while (newOffset > 0 && !isWordBoundary(currentValue[newOffset - 1])) {
|
|
140
|
-
newOffset--;
|
|
141
|
-
}
|
|
142
|
-
} else {
|
|
143
|
-
newOffset--;
|
|
144
|
-
}
|
|
145
|
-
setCursorOffset(newOffset);
|
|
146
|
-
}
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
if (key.rightArrow) {
|
|
150
|
-
if (currentCursorOffset < currentValue.length) {
|
|
151
|
-
let newOffset = currentCursorOffset;
|
|
152
|
-
if (key.ctrl || key.meta) {
|
|
153
|
-
while (newOffset < currentValue.length && !isWordBoundary(currentValue[newOffset])) {
|
|
154
|
-
newOffset++;
|
|
155
|
-
}
|
|
156
|
-
while (newOffset < currentValue.length && isWordBoundary(currentValue[newOffset])) {
|
|
157
|
-
newOffset++;
|
|
158
|
-
}
|
|
159
|
-
} else {
|
|
160
|
-
newOffset++;
|
|
161
|
-
}
|
|
162
|
-
setCursorOffset(newOffset);
|
|
163
|
-
}
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (key.home) {
|
|
167
|
-
const width = (process.stdout.columns || 80) - 4;
|
|
168
|
-
const visualLines2 = getVisualLines(currentValue, width);
|
|
169
|
-
const currentLine = visualLines2.find(
|
|
170
|
-
(line) => currentCursorOffset >= line.start && currentCursorOffset < line.end || currentCursorOffset === line.end && line.isHardEnd
|
|
171
|
-
);
|
|
172
|
-
if (currentLine) {
|
|
173
|
-
setCursorOffset(currentLine.start);
|
|
174
|
-
} else {
|
|
175
|
-
setCursorOffset(0);
|
|
176
|
-
}
|
|
177
|
-
return;
|
|
178
|
-
}
|
|
179
|
-
if (key.end) {
|
|
180
|
-
const width = (process.stdout.columns || 80) - 4;
|
|
181
|
-
const visualLines2 = getVisualLines(currentValue, width);
|
|
182
|
-
const currentLine = visualLines2.find(
|
|
183
|
-
(line) => currentCursorOffset >= line.start && currentCursorOffset < line.end || currentCursorOffset === line.end && line.isHardEnd
|
|
184
|
-
);
|
|
185
|
-
if (currentLine) {
|
|
186
|
-
setCursorOffset(currentLine.end);
|
|
187
|
-
} else {
|
|
188
|
-
setCursorOffset(currentValue.length);
|
|
189
|
-
}
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
if (input) {
|
|
193
|
-
const cleanedInput = input.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
194
|
-
const newValue = currentValue.slice(0, currentCursorOffset) + cleanedInput + currentValue.slice(currentCursorOffset);
|
|
195
|
-
onChange(newValue);
|
|
196
|
-
setCursorOffset(currentCursorOffset + cleanedInput.length);
|
|
197
|
-
}
|
|
198
|
-
});
|
|
199
|
-
const termWidth = (process.stdout.columns || 80) - 4;
|
|
200
|
-
const visualLines = getVisualLines(value, termWidth);
|
|
201
|
-
let cursorVisualLine = 0;
|
|
202
|
-
for (let i = 0; i < visualLines.length; i++) {
|
|
203
|
-
if (cursorOffset >= visualLines[i].start && cursorOffset <= visualLines[i].end) {
|
|
204
|
-
cursorVisualLine = i;
|
|
205
|
-
break;
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
if (cursorOffset === value.length && visualLines.length > 0) {
|
|
209
|
-
cursorVisualLine = visualLines.length - 1;
|
|
210
|
-
}
|
|
211
|
-
const totalLines = visualLines.length;
|
|
212
|
-
const height = Math.min(Math.max(totalLines, minHeight), maxHeight);
|
|
213
|
-
let startLine = 0;
|
|
214
|
-
if (totalLines > height) {
|
|
215
|
-
if (cursorVisualLine < height) {
|
|
216
|
-
startLine = 0;
|
|
217
|
-
} else {
|
|
218
|
-
startLine = cursorVisualLine - height + 1;
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
const endLine = Math.min(startLine + height, totalLines);
|
|
222
|
-
const visibleLines = visualLines.slice(startLine, endLine);
|
|
223
|
-
const topIndicatorCount = startLine > 0 ? 1 : 0;
|
|
224
|
-
const bottomIndicatorCount = endLine < totalLines ? 1 : 0;
|
|
225
|
-
const fillerLineCount = Math.max(0, height - visibleLines.length - topIndicatorCount - bottomIndicatorCount);
|
|
226
|
-
if (value.length === 0 && placeholder) {
|
|
227
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: "100%", minHeight: height }, /* @__PURE__ */ React.createElement(Text, { color: "gray" }, placeholder), Array.from({ length: Math.max(0, height - 1) }, (_, idx) => /* @__PURE__ */ React.createElement(Text, { key: `placeholder-pad-${idx}` }, " ")));
|
|
228
|
-
}
|
|
229
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", width: "100%", minHeight: height }, startLine > 0 && /* @__PURE__ */ React.createElement(Text, { color: "gray" }, "\u2191"), visibleLines.map((vLine, idx) => {
|
|
230
|
-
const lineContent = value.slice(vLine.start, vLine.end);
|
|
231
|
-
const isCursorLine = cursorOffset >= vLine.start && cursorOffset <= vLine.end;
|
|
232
|
-
const cursorCol = isCursorLine ? cursorOffset - vLine.start : -1;
|
|
233
|
-
if (!isActive) {
|
|
234
|
-
return /* @__PURE__ */ React.createElement(Text, { key: idx }, lineContent);
|
|
235
|
-
}
|
|
236
|
-
const chars = lineContent.split("");
|
|
237
|
-
const renderedChars = chars.map((char, charIdx) => {
|
|
238
|
-
if (isCursorLine && charIdx === cursorCol) {
|
|
239
|
-
return /* @__PURE__ */ React.createElement(Text, { key: charIdx, inverse: true }, char);
|
|
240
|
-
}
|
|
241
|
-
return /* @__PURE__ */ React.createElement(Text, { key: charIdx }, char);
|
|
242
|
-
});
|
|
243
|
-
if (isCursorLine && cursorCol === lineContent.length) {
|
|
244
|
-
renderedChars.push(/* @__PURE__ */ React.createElement(Text, { key: "cursor", inverse: true }, " "));
|
|
245
|
-
}
|
|
246
|
-
if (renderedChars.length === 0) {
|
|
247
|
-
return /* @__PURE__ */ React.createElement(Text, { key: idx }, " ");
|
|
248
|
-
}
|
|
249
|
-
return /* @__PURE__ */ React.createElement(Text, { key: idx }, renderedChars);
|
|
250
|
-
}), endLine < totalLines && /* @__PURE__ */ React.createElement(Text, { color: "gray" }, "\u2193"), Array.from({ length: fillerLineCount }, (_, idx) => /* @__PURE__ */ React.createElement(Text, { key: `pad-${idx}` }, " ")));
|
|
251
|
-
};
|
|
252
|
-
export {
|
|
253
|
-
MultiLineInput
|
|
254
|
-
};
|
|
255
|
-
//# sourceMappingURL=MultiLineInput.js.map
|