centient 2.20.0 → 2.25.0
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/CHANGELOG.md +106 -0
- package/README.md +134 -21
- package/dist/cli.d.ts +38 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +816 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +18 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +341 -0
- package/dist/commands.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +86 -18
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +192 -88
- package/dist/server.js.map +1 -1
- package/dist/telemetry/tracer.d.ts.map +1 -1
- package/dist/telemetry/tracer.js +15 -1
- package/dist/telemetry/tracer.js.map +1 -1
- package/dist/tools/knowledge/promoteDecision.d.ts.map +1 -1
- package/dist/tools/knowledge/promoteDecision.js +7 -1
- package/dist/tools/knowledge/promoteDecision.js.map +1 -1
- package/dist/tools/knowledge/promoteLearning.d.ts.map +1 -1
- package/dist/tools/knowledge/promoteLearning.js +7 -1
- package/dist/tools/knowledge/promoteLearning.js.map +1 -1
- package/dist/tools/memory-bank/pushToMemoryBank.d.ts +9 -0
- package/dist/tools/memory-bank/pushToMemoryBank.d.ts.map +1 -0
- package/dist/tools/memory-bank/pushToMemoryBank.js +195 -0
- package/dist/tools/memory-bank/pushToMemoryBank.js.map +1 -0
- package/dist/tools/patterns/executeSkill.js +0 -41
- package/dist/tools/patterns/executeSkill.js.map +1 -1
- package/dist/tools/patterns/loadSkill.js +0 -17
- package/dist/tools/patterns/loadSkill.js.map +1 -1
- package/dist/tools/patterns/searchPatterns.js +0 -15
- package/dist/tools/patterns/searchPatterns.js.map +1 -1
- package/dist/tools/patterns/signPattern.js +0 -20
- package/dist/tools/patterns/signPattern.js.map +1 -1
- package/dist/tools/trails/executeTrailScript.d.ts +19 -0
- package/dist/tools/trails/executeTrailScript.d.ts.map +1 -0
- package/dist/tools/trails/executeTrailScript.js +65 -0
- package/dist/tools/trails/executeTrailScript.js.map +1 -0
- package/dist/tools/trails/index.d.ts +9 -0
- package/dist/tools/trails/index.d.ts.map +1 -0
- package/dist/tools/trails/index.js +9 -0
- package/dist/tools/trails/index.js.map +1 -0
- package/dist/tools/trails/trailDiscoverAuto.d.ts +9 -0
- package/dist/tools/trails/trailDiscoverAuto.d.ts.map +1 -0
- package/dist/tools/trails/trailDiscoverAuto.js +76 -0
- package/dist/tools/trails/trailDiscoverAuto.js.map +1 -0
- package/dist/tools/trails/trailDiscoverConvergence.d.ts +9 -0
- package/dist/tools/trails/trailDiscoverConvergence.d.ts.map +1 -0
- package/dist/tools/trails/trailDiscoverConvergence.js +66 -0
- package/dist/tools/trails/trailDiscoverConvergence.js.map +1 -0
- package/dist/tools/trails/trailDiscoverInfluence.d.ts +9 -0
- package/dist/tools/trails/trailDiscoverInfluence.d.ts.map +1 -0
- package/dist/tools/trails/trailDiscoverInfluence.js +79 -0
- package/dist/tools/trails/trailDiscoverInfluence.js.map +1 -0
- package/dist/tools/trails/trailList.d.ts +9 -0
- package/dist/tools/trails/trailList.d.ts.map +1 -0
- package/dist/tools/trails/trailList.js +74 -0
- package/dist/tools/trails/trailList.js.map +1 -0
- package/dist/tools/trails/trailQueryByTopic.d.ts +9 -0
- package/dist/tools/trails/trailQueryByTopic.d.ts.map +1 -0
- package/dist/tools/trails/trailQueryByTopic.js +40 -0
- package/dist/tools/trails/trailQueryByTopic.js.map +1 -0
- package/dist/tools/trails/trailQueryIntersect.d.ts +9 -0
- package/dist/tools/trails/trailQueryIntersect.d.ts.map +1 -0
- package/dist/tools/trails/trailQueryIntersect.js +54 -0
- package/dist/tools/trails/trailQueryIntersect.js.map +1 -0
- package/dist/tools/trails/trailQueryTopics.d.ts +9 -0
- package/dist/tools/trails/trailQueryTopics.d.ts.map +1 -0
- package/dist/tools/trails/trailQueryTopics.js +44 -0
- package/dist/tools/trails/trailQueryTopics.js.map +1 -0
- package/dist/tools/trails/trailView.d.ts +9 -0
- package/dist/tools/trails/trailView.d.ts.map +1 -0
- package/dist/tools/trails/trailView.js +94 -0
- package/dist/tools/trails/trailView.js.map +1 -0
- package/dist/utils/AuditLogger.d.ts +25 -18
- package/dist/utils/AuditLogger.d.ts.map +1 -1
- package/dist/utils/AuditLogger.js +261 -150
- package/dist/utils/AuditLogger.js.map +1 -1
- package/dist/utils/GeminiEmbeddingService.d.ts +25 -0
- package/dist/utils/GeminiEmbeddingService.d.ts.map +1 -0
- package/dist/utils/GeminiEmbeddingService.js +115 -0
- package/dist/utils/GeminiEmbeddingService.js.map +1 -0
- package/dist/utils/InstanceRegistry.d.ts +47 -0
- package/dist/utils/InstanceRegistry.d.ts.map +1 -0
- package/dist/utils/InstanceRegistry.js +195 -0
- package/dist/utils/InstanceRegistry.js.map +1 -0
- package/dist/utils/MetaKnowledgeEncryption.d.ts +21 -0
- package/dist/utils/MetaKnowledgeEncryption.d.ts.map +1 -0
- package/dist/utils/MetaKnowledgeEncryption.js +125 -0
- package/dist/utils/MetaKnowledgeEncryption.js.map +1 -0
- package/dist/utils/MetaKnowledgeManager.d.ts +18 -0
- package/dist/utils/MetaKnowledgeManager.d.ts.map +1 -1
- package/dist/utils/MetaKnowledgeManager.js +110 -6
- package/dist/utils/MetaKnowledgeManager.js.map +1 -1
- package/dist/utils/PatternIndexer.d.ts +1 -2
- package/dist/utils/PatternIndexer.d.ts.map +1 -1
- package/dist/utils/PatternIndexer.js +40 -72
- package/dist/utils/PatternIndexer.js.map +1 -1
- package/dist/utils/SessionCoordinator.d.ts +0 -1
- package/dist/utils/SessionCoordinator.d.ts.map +1 -1
- package/dist/utils/SessionCoordinator.js +3 -61
- package/dist/utils/SessionCoordinator.js.map +1 -1
- package/dist/utils/VertexSync.d.ts +12 -0
- package/dist/utils/VertexSync.d.ts.map +1 -0
- package/dist/utils/VertexSync.js +173 -0
- package/dist/utils/VertexSync.js.map +1 -0
- package/dist/utils/config.d.ts +60 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +246 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/rlvr/RewardHistoryStore.d.ts +0 -2
- package/dist/utils/rlvr/RewardHistoryStore.d.ts.map +1 -1
- package/dist/utils/rlvr/RewardHistoryStore.js +5 -18
- package/dist/utils/rlvr/RewardHistoryStore.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
ADDED
|
@@ -0,0 +1,816 @@
|
|
|
1
|
+
import { readFileSync, existsSync, watch, statSync } from "fs";
|
|
2
|
+
import { join, dirname } from "path";
|
|
3
|
+
import { fileURLToPath } from "url";
|
|
4
|
+
import { homedir } from "os";
|
|
5
|
+
import { createReadStream } from "fs";
|
|
6
|
+
import { createInterface } from "readline";
|
|
7
|
+
import { listInstances, getAggregatedStats, formatUptime, isHeartbeatStale, } from "./utils/InstanceRegistry.js";
|
|
8
|
+
import { getAuditLogPath as getConfigAuditLogPath, getMetaKnowledgeConfig } from "./utils/config.js";
|
|
9
|
+
import { getSharedPatternsPath } from "./utils/filesystem.js";
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
function getVersion() {
|
|
12
|
+
try {
|
|
13
|
+
const packagePath = join(__dirname, "..", "package.json");
|
|
14
|
+
const pkg = JSON.parse(readFileSync(packagePath, "utf-8"));
|
|
15
|
+
return pkg.version || "unknown";
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return "unknown";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export function printVersion() {
|
|
22
|
+
console.log(`centient ${getVersion()}`);
|
|
23
|
+
}
|
|
24
|
+
export function printHelp() {
|
|
25
|
+
const version = getVersion();
|
|
26
|
+
console.log(`centient v${version} - MCP server for context engineering
|
|
27
|
+
|
|
28
|
+
Usage: centient [command] [options]
|
|
29
|
+
|
|
30
|
+
Commands:
|
|
31
|
+
init Initialize .claude/ directory with commands
|
|
32
|
+
check-commands Show missing/outdated commands
|
|
33
|
+
update-commands Update outdated commands
|
|
34
|
+
|
|
35
|
+
Options:
|
|
36
|
+
-V, --version Show version number
|
|
37
|
+
-h, --help Show this help message
|
|
38
|
+
-l, --list-tools List all available MCP tools
|
|
39
|
+
--health Run health check and exit
|
|
40
|
+
--config Show current configuration
|
|
41
|
+
--stats Show usage statistics and exit
|
|
42
|
+
--force Force overwrite (for init/update-commands)
|
|
43
|
+
--dry-run Show what would be updated without making changes
|
|
44
|
+
|
|
45
|
+
Instance Monitoring (like ps):
|
|
46
|
+
--monitor List all running centient instances
|
|
47
|
+
-p, --project <name> Filter instances by project name
|
|
48
|
+
-f, --follow Watch for activity in real-time
|
|
49
|
+
-j, --json Output in JSON format
|
|
50
|
+
-q, --quiet Output just PIDs (for scripting)
|
|
51
|
+
-s, --summary Show aggregate statistics only
|
|
52
|
+
|
|
53
|
+
Audit Log (per-project):
|
|
54
|
+
--log Tail local audit log
|
|
55
|
+
--last <n> Show last n events (default: 20)
|
|
56
|
+
-f, --follow Continuous tailing mode
|
|
57
|
+
|
|
58
|
+
Running without arguments starts the MCP server (stdio transport).
|
|
59
|
+
|
|
60
|
+
Examples:
|
|
61
|
+
centient init # Initialize project with commands
|
|
62
|
+
centient init --force # Overwrite existing commands
|
|
63
|
+
centient check-commands # Check command status
|
|
64
|
+
centient update-commands # Update outdated commands
|
|
65
|
+
centient update-commands --dry-run # Preview what would be updated
|
|
66
|
+
centient --monitor # Show all running instances
|
|
67
|
+
centient --monitor -f # Watch activity across all instances
|
|
68
|
+
centient --log --last 50 # Show last 50 audit log events
|
|
69
|
+
|
|
70
|
+
Documentation: https://github.com/Szermer/centient
|
|
71
|
+
`);
|
|
72
|
+
}
|
|
73
|
+
export function printTools(tools) {
|
|
74
|
+
const version = getVersion();
|
|
75
|
+
console.log(`centient v${version} - Available MCP Tools (${tools.length} total)\n`);
|
|
76
|
+
const modules = {};
|
|
77
|
+
for (const tool of tools) {
|
|
78
|
+
let module = "other";
|
|
79
|
+
const name = tool.name;
|
|
80
|
+
if (name.includes("Pattern") || name.includes("Skill") || name === "findPatterns") {
|
|
81
|
+
module = "patterns";
|
|
82
|
+
}
|
|
83
|
+
else if (name.includes("Artifact") || (name.includes("Session") && name.includes("load"))) {
|
|
84
|
+
module = "artifacts";
|
|
85
|
+
}
|
|
86
|
+
else if (name.includes("Note") || name === "getDecisions" || name === "getHypotheses") {
|
|
87
|
+
module = "memory";
|
|
88
|
+
}
|
|
89
|
+
else if (name.includes("Compression") || name.includes("Reuse") || name.includes("Cost") || name.includes("Analytics") || name.includes("Audit")) {
|
|
90
|
+
module = "metrics";
|
|
91
|
+
}
|
|
92
|
+
else if (name.includes("semantic") || (name.includes("index") && name.includes("Session")) || name.includes("SearchStats")) {
|
|
93
|
+
module = "search";
|
|
94
|
+
}
|
|
95
|
+
else if (name.includes("session") || name.includes("Session") || name.includes("Constraint") || name.includes("Claim") || name.includes("Citation") || name.includes("Verification") || name.includes("Feasibility") || name.includes("Duplicate") || name.includes("Approval")) {
|
|
96
|
+
module = "session";
|
|
97
|
+
}
|
|
98
|
+
else if (name.includes("Stuck") || name.includes("Recovery")) {
|
|
99
|
+
module = "stuck";
|
|
100
|
+
}
|
|
101
|
+
else if (name.includes("Health") || name.includes("Circuit") || name.includes("RateLimit") || name.includes("Qdrant")) {
|
|
102
|
+
module = "health";
|
|
103
|
+
}
|
|
104
|
+
else if (name.includes("Research") || name.includes("Model")) {
|
|
105
|
+
module = "research";
|
|
106
|
+
}
|
|
107
|
+
else if (name.includes("memory_bank")) {
|
|
108
|
+
module = "memory-bank";
|
|
109
|
+
}
|
|
110
|
+
else if (name.includes("Relationship") || name.includes("Graph") || name.includes("link")) {
|
|
111
|
+
module = "graph";
|
|
112
|
+
}
|
|
113
|
+
else if (name.includes("consult") || name.includes("Consultation") || name.includes("Consensus") || name.includes("Review") || (name.includes("Decision") && name.includes("validate"))) {
|
|
114
|
+
module = "consultation";
|
|
115
|
+
}
|
|
116
|
+
else if (name.includes("Branch") || name.includes("branch") || (name.includes("Decision") && name.includes("Point"))) {
|
|
117
|
+
module = "branching";
|
|
118
|
+
}
|
|
119
|
+
else if (name.includes("rlvr")) {
|
|
120
|
+
module = "rlvr";
|
|
121
|
+
}
|
|
122
|
+
else if (name.includes("Learning") || name.includes("Knowledge") || name.includes("promote")) {
|
|
123
|
+
module = "knowledge";
|
|
124
|
+
}
|
|
125
|
+
else if (name.includes("trail")) {
|
|
126
|
+
module = "trails";
|
|
127
|
+
}
|
|
128
|
+
(modules[module] ??= []).push(tool);
|
|
129
|
+
}
|
|
130
|
+
const moduleOrder = [
|
|
131
|
+
"patterns",
|
|
132
|
+
"artifacts",
|
|
133
|
+
"memory",
|
|
134
|
+
"metrics",
|
|
135
|
+
"search",
|
|
136
|
+
"session",
|
|
137
|
+
"stuck",
|
|
138
|
+
"health",
|
|
139
|
+
"research",
|
|
140
|
+
"memory-bank",
|
|
141
|
+
"graph",
|
|
142
|
+
"consultation",
|
|
143
|
+
"branching",
|
|
144
|
+
"rlvr",
|
|
145
|
+
"knowledge",
|
|
146
|
+
"trails",
|
|
147
|
+
"other",
|
|
148
|
+
];
|
|
149
|
+
for (const moduleName of moduleOrder) {
|
|
150
|
+
const moduleTools = modules[moduleName];
|
|
151
|
+
if (!moduleTools || moduleTools.length === 0)
|
|
152
|
+
continue;
|
|
153
|
+
console.log(`${moduleName.toUpperCase()} (${moduleTools.length} tools)`);
|
|
154
|
+
console.log("─".repeat(60));
|
|
155
|
+
for (const tool of moduleTools) {
|
|
156
|
+
const desc = tool.description?.split("\n")[0] || "";
|
|
157
|
+
const truncatedDesc = desc.length > 50 ? desc.slice(0, 47) + "..." : desc;
|
|
158
|
+
console.log(` ${tool.name.padEnd(35)} ${truncatedDesc}`);
|
|
159
|
+
}
|
|
160
|
+
console.log("");
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
export async function printHealth() {
|
|
164
|
+
const version = getVersion();
|
|
165
|
+
console.log(`centient v${version} health check\n`);
|
|
166
|
+
const envVars = {
|
|
167
|
+
QDRANT_URL: process.env.QDRANT_URL,
|
|
168
|
+
QDRANT_API_KEY: process.env.QDRANT_API_KEY,
|
|
169
|
+
GEMINI_API_KEY: process.env.GEMINI_API_KEY,
|
|
170
|
+
OPENROUTER_API_KEY: process.env.OPENROUTER_API_KEY,
|
|
171
|
+
};
|
|
172
|
+
console.log("Environment:");
|
|
173
|
+
for (const [key, value] of Object.entries(envVars)) {
|
|
174
|
+
const status = value ? "\x1b[32m✓\x1b[0m configured" : "\x1b[31m✗\x1b[0m not set";
|
|
175
|
+
console.log(` ${key.padEnd(20)} ${status}`);
|
|
176
|
+
}
|
|
177
|
+
console.log("\nServices:");
|
|
178
|
+
if (envVars.QDRANT_URL && envVars.QDRANT_API_KEY) {
|
|
179
|
+
try {
|
|
180
|
+
const response = await fetch(`${envVars.QDRANT_URL}/collections`, {
|
|
181
|
+
headers: {
|
|
182
|
+
"api-key": envVars.QDRANT_API_KEY,
|
|
183
|
+
},
|
|
184
|
+
signal: AbortSignal.timeout(5000),
|
|
185
|
+
});
|
|
186
|
+
if (response.ok) {
|
|
187
|
+
console.log(" Qdrant Cloud \x1b[32m✓\x1b[0m connected");
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
console.log(` Qdrant Cloud \x1b[31m✗\x1b[0m error (${response.status})`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
const msg = error instanceof Error ? error.message : "unknown error";
|
|
195
|
+
console.log(` Qdrant Cloud \x1b[31m✗\x1b[0m ${msg}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
console.log(" Qdrant Cloud \x1b[33m-\x1b[0m not configured");
|
|
200
|
+
}
|
|
201
|
+
if (envVars.GEMINI_API_KEY) {
|
|
202
|
+
try {
|
|
203
|
+
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models?key=${envVars.GEMINI_API_KEY}`, { signal: AbortSignal.timeout(5000) });
|
|
204
|
+
if (response.ok) {
|
|
205
|
+
console.log(" Gemini API \x1b[32m✓\x1b[0m connected");
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
console.log(` Gemini API \x1b[31m✗\x1b[0m error (${response.status})`);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
const msg = error instanceof Error ? error.message : "unknown error";
|
|
213
|
+
console.log(` Gemini API \x1b[31m✗\x1b[0m ${msg}`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
console.log(" Gemini API \x1b[33m-\x1b[0m not configured");
|
|
218
|
+
}
|
|
219
|
+
if (envVars.OPENROUTER_API_KEY) {
|
|
220
|
+
try {
|
|
221
|
+
const response = await fetch("https://openrouter.ai/api/v1/models", {
|
|
222
|
+
headers: {
|
|
223
|
+
Authorization: `Bearer ${envVars.OPENROUTER_API_KEY}`,
|
|
224
|
+
},
|
|
225
|
+
signal: AbortSignal.timeout(5000),
|
|
226
|
+
});
|
|
227
|
+
if (response.ok) {
|
|
228
|
+
console.log(" OpenRouter API \x1b[32m✓\x1b[0m connected");
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
console.log(` OpenRouter API \x1b[31m✗\x1b[0m error (${response.status})`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
const msg = error instanceof Error ? error.message : "unknown error";
|
|
236
|
+
console.log(` OpenRouter API \x1b[31m✗\x1b[0m ${msg}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
console.log(" OpenRouter API \x1b[33m-\x1b[0m not configured");
|
|
241
|
+
}
|
|
242
|
+
console.log("");
|
|
243
|
+
}
|
|
244
|
+
export function printConfig() {
|
|
245
|
+
const version = getVersion();
|
|
246
|
+
console.log(`centient v${version} configuration\n`);
|
|
247
|
+
function redact(value) {
|
|
248
|
+
if (!value)
|
|
249
|
+
return "(not set)";
|
|
250
|
+
if (value.length <= 8)
|
|
251
|
+
return "***";
|
|
252
|
+
return value.slice(0, 4) + "..." + value.slice(-4);
|
|
253
|
+
}
|
|
254
|
+
console.log("Environment Variables:");
|
|
255
|
+
console.log(` QDRANT_URL ${process.env.QDRANT_URL || "(not set)"}`);
|
|
256
|
+
console.log(` QDRANT_API_KEY ${redact(process.env.QDRANT_API_KEY)}`);
|
|
257
|
+
console.log(` GEMINI_API_KEY ${redact(process.env.GEMINI_API_KEY)}`);
|
|
258
|
+
console.log(` OPENROUTER_API_KEY ${redact(process.env.OPENROUTER_API_KEY)}`);
|
|
259
|
+
console.log("\nPaths:");
|
|
260
|
+
console.log(` Shared Patterns ${getSharedPatternsPath()}`);
|
|
261
|
+
console.log(` MCP Context ${join(homedir(), ".mcp-context")}`);
|
|
262
|
+
console.log(` Audit Log ${getConfigAuditLogPath()}`);
|
|
263
|
+
const metaConfig = getMetaKnowledgeConfig();
|
|
264
|
+
console.log("\nMeta-Knowledge (Tier 3):");
|
|
265
|
+
console.log(` Path ${metaConfig.path}`);
|
|
266
|
+
console.log(` Encryption ${metaConfig.encryption.enabled ? `✓ enabled (${metaConfig.encryption.keySource})` : "✗ disabled"}`);
|
|
267
|
+
console.log(` Vertex Sync ${metaConfig.vertex.enabled ? `✓ enabled (${metaConfig.vertex.projectId || "no project"})` : "✗ disabled"}`);
|
|
268
|
+
console.log(` Retention ${metaConfig.retention.days > 0 ? `${metaConfig.retention.days} days` : "∞ forever"}`);
|
|
269
|
+
if (metaConfig.retention.days > 0) {
|
|
270
|
+
console.log(` Archive Path ${metaConfig.retention.archivePath}`);
|
|
271
|
+
}
|
|
272
|
+
console.log("\nRuntime:");
|
|
273
|
+
console.log(` Node.js ${process.version}`);
|
|
274
|
+
console.log(` Platform ${process.platform} ${process.arch}`);
|
|
275
|
+
console.log(` Working Directory ${process.cwd()}`);
|
|
276
|
+
console.log("");
|
|
277
|
+
}
|
|
278
|
+
const isTTY = process.stdout.isTTY ?? false;
|
|
279
|
+
const colors = isTTY ? {
|
|
280
|
+
reset: "\x1b[0m",
|
|
281
|
+
bright: "\x1b[1m",
|
|
282
|
+
dim: "\x1b[2m",
|
|
283
|
+
red: "\x1b[31m",
|
|
284
|
+
green: "\x1b[32m",
|
|
285
|
+
yellow: "\x1b[33m",
|
|
286
|
+
blue: "\x1b[34m",
|
|
287
|
+
magenta: "\x1b[35m",
|
|
288
|
+
cyan: "\x1b[36m",
|
|
289
|
+
white: "\x1b[37m",
|
|
290
|
+
gray: "\x1b[90m",
|
|
291
|
+
} : {
|
|
292
|
+
reset: "",
|
|
293
|
+
bright: "",
|
|
294
|
+
dim: "",
|
|
295
|
+
red: "",
|
|
296
|
+
green: "",
|
|
297
|
+
yellow: "",
|
|
298
|
+
blue: "",
|
|
299
|
+
magenta: "",
|
|
300
|
+
cyan: "",
|
|
301
|
+
white: "",
|
|
302
|
+
gray: "",
|
|
303
|
+
};
|
|
304
|
+
function formatLogEntry(entry) {
|
|
305
|
+
const time = new Date(entry.timestamp).toLocaleTimeString();
|
|
306
|
+
const outcomeColor = entry.outcome === "success" ? colors.green : colors.red;
|
|
307
|
+
const outcomeSymbol = entry.outcome === "success" ? "✓" : "✗";
|
|
308
|
+
const duration = `${entry.duration}ms`.padStart(6);
|
|
309
|
+
let summary = "";
|
|
310
|
+
if (entry.output) {
|
|
311
|
+
if ("resultCount" in entry.output) {
|
|
312
|
+
summary = `${entry.output.resultCount} results`;
|
|
313
|
+
}
|
|
314
|
+
else if ("errorMessage" in entry.output) {
|
|
315
|
+
const msg = String(entry.output.errorMessage);
|
|
316
|
+
summary = msg.length > 30 ? msg.slice(0, 27) + "..." : msg;
|
|
317
|
+
}
|
|
318
|
+
else if ("tokensUsed" in entry.output) {
|
|
319
|
+
summary = `${entry.output.tokensUsed} tokens`;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return `${colors.gray}${time}${colors.reset} │ ${colors.cyan}${entry.tool.padEnd(28)}${colors.reset} │ ${outcomeColor}${outcomeSymbol} ${duration}${colors.reset} │ ${summary}`;
|
|
323
|
+
}
|
|
324
|
+
function getAuditLogPath() {
|
|
325
|
+
return getConfigAuditLogPath();
|
|
326
|
+
}
|
|
327
|
+
async function readLastLines(filePath, n) {
|
|
328
|
+
if (!existsSync(filePath)) {
|
|
329
|
+
return [];
|
|
330
|
+
}
|
|
331
|
+
const entries = [];
|
|
332
|
+
const fileStream = createReadStream(filePath);
|
|
333
|
+
const rl = createInterface({ input: fileStream, crlfDelay: Infinity });
|
|
334
|
+
for await (const line of rl) {
|
|
335
|
+
if (line.trim()) {
|
|
336
|
+
try {
|
|
337
|
+
entries.push(JSON.parse(line));
|
|
338
|
+
}
|
|
339
|
+
catch {
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return entries.slice(-n);
|
|
344
|
+
}
|
|
345
|
+
export async function printStats() {
|
|
346
|
+
const version = getVersion();
|
|
347
|
+
console.log(`centient v${version} statistics\n`);
|
|
348
|
+
const logPath = getAuditLogPath();
|
|
349
|
+
if (!existsSync(logPath)) {
|
|
350
|
+
console.log(`${colors.yellow}No audit log found at ${logPath}${colors.reset}`);
|
|
351
|
+
console.log("Statistics will be available after centient processes some requests.\n");
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const stats = {
|
|
355
|
+
totalEvents: 0,
|
|
356
|
+
successCount: 0,
|
|
357
|
+
failureCount: 0,
|
|
358
|
+
totalDuration: 0,
|
|
359
|
+
toolCounts: {},
|
|
360
|
+
toolTotalDurations: {},
|
|
361
|
+
toolDurationCounts: {},
|
|
362
|
+
eventTypeCounts: {},
|
|
363
|
+
firstTimestamp: null,
|
|
364
|
+
lastTimestamp: null,
|
|
365
|
+
};
|
|
366
|
+
const fileStream = createReadStream(logPath);
|
|
367
|
+
const rl = createInterface({ input: fileStream, crlfDelay: Infinity });
|
|
368
|
+
for await (const line of rl) {
|
|
369
|
+
if (!line.trim())
|
|
370
|
+
continue;
|
|
371
|
+
let entry;
|
|
372
|
+
try {
|
|
373
|
+
entry = JSON.parse(line);
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
stats.totalEvents++;
|
|
379
|
+
if (!stats.firstTimestamp) {
|
|
380
|
+
stats.firstTimestamp = entry.timestamp;
|
|
381
|
+
}
|
|
382
|
+
stats.lastTimestamp = entry.timestamp;
|
|
383
|
+
stats.toolCounts[entry.tool] = (stats.toolCounts[entry.tool] || 0) + 1;
|
|
384
|
+
stats.toolTotalDurations[entry.tool] = (stats.toolTotalDurations[entry.tool] || 0) + entry.duration;
|
|
385
|
+
stats.toolDurationCounts[entry.tool] = (stats.toolDurationCounts[entry.tool] || 0) + 1;
|
|
386
|
+
stats.eventTypeCounts[entry.eventType] = (stats.eventTypeCounts[entry.eventType] || 0) + 1;
|
|
387
|
+
if (entry.outcome === "success") {
|
|
388
|
+
stats.successCount++;
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
stats.failureCount++;
|
|
392
|
+
}
|
|
393
|
+
stats.totalDuration += entry.duration;
|
|
394
|
+
}
|
|
395
|
+
if (stats.totalEvents === 0) {
|
|
396
|
+
console.log(`${colors.yellow}Audit log is empty${colors.reset}\n`);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
console.log(`${colors.bright}Summary${colors.reset}`);
|
|
400
|
+
console.log("─".repeat(50));
|
|
401
|
+
console.log(` Total events: ${stats.totalEvents}`);
|
|
402
|
+
console.log(` Success rate: ${colors.green}${((stats.successCount / stats.totalEvents) * 100).toFixed(1)}%${colors.reset} (${stats.successCount}/${stats.totalEvents})`);
|
|
403
|
+
console.log(` Total duration: ${(stats.totalDuration / 1000).toFixed(2)}s`);
|
|
404
|
+
console.log(` Avg duration: ${(stats.totalDuration / stats.totalEvents).toFixed(0)}ms`);
|
|
405
|
+
console.log("");
|
|
406
|
+
const sortedTools = Object.entries(stats.toolCounts)
|
|
407
|
+
.sort((a, b) => b[1] - a[1])
|
|
408
|
+
.slice(0, 10);
|
|
409
|
+
console.log(`${colors.bright}Top Tools${colors.reset}`);
|
|
410
|
+
console.log("─".repeat(50));
|
|
411
|
+
for (const [tool, count] of sortedTools) {
|
|
412
|
+
const totalDuration = stats.toolTotalDurations[tool] || 0;
|
|
413
|
+
const durationCount = stats.toolDurationCounts[tool] || 1;
|
|
414
|
+
const avgDuration = totalDuration / durationCount;
|
|
415
|
+
console.log(` ${tool.padEnd(30)} ${String(count).padStart(5)} calls ${avgDuration.toFixed(0).padStart(5)}ms avg`);
|
|
416
|
+
}
|
|
417
|
+
console.log("");
|
|
418
|
+
console.log(`${colors.bright}Event Types${colors.reset}`);
|
|
419
|
+
console.log("─".repeat(50));
|
|
420
|
+
for (const [eventType, count] of Object.entries(stats.eventTypeCounts).sort((a, b) => b[1] - a[1])) {
|
|
421
|
+
console.log(` ${eventType.padEnd(30)} ${String(count).padStart(5)}`);
|
|
422
|
+
}
|
|
423
|
+
console.log("");
|
|
424
|
+
if (stats.firstTimestamp && stats.lastTimestamp) {
|
|
425
|
+
console.log(`${colors.bright}Time Range${colors.reset}`);
|
|
426
|
+
console.log("─".repeat(50));
|
|
427
|
+
console.log(` From: ${new Date(stats.firstTimestamp).toLocaleString()}`);
|
|
428
|
+
console.log(` To: ${new Date(stats.lastTimestamp).toLocaleString()}`);
|
|
429
|
+
}
|
|
430
|
+
console.log("");
|
|
431
|
+
}
|
|
432
|
+
export async function log(options) {
|
|
433
|
+
const version = getVersion();
|
|
434
|
+
const logPath = getAuditLogPath();
|
|
435
|
+
console.log(`${colors.bright}AUDIT LOG${colors.reset} v${version}`);
|
|
436
|
+
console.log("─".repeat(80));
|
|
437
|
+
console.log(`${colors.gray}Time${colors.reset} │ ${colors.gray}Tool${colors.reset} │ ${colors.gray}Status${colors.reset} │ ${colors.gray}Details${colors.reset}`);
|
|
438
|
+
console.log("─".repeat(80));
|
|
439
|
+
if (!existsSync(logPath)) {
|
|
440
|
+
console.log(`\n${colors.yellow}Waiting for audit log to be created...${colors.reset}`);
|
|
441
|
+
console.log(`Expected at: ${logPath}\n`);
|
|
442
|
+
if (!options.follow) {
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
const dir = dirname(logPath);
|
|
446
|
+
if (existsSync(dir)) {
|
|
447
|
+
await new Promise((resolve) => {
|
|
448
|
+
const watcher = watch(dir, (_eventType, filename) => {
|
|
449
|
+
if (filename === ".audit-log.jsonl" && existsSync(logPath)) {
|
|
450
|
+
watcher.close();
|
|
451
|
+
resolve();
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
const entries = await readLastLines(logPath, options.last);
|
|
458
|
+
for (const entry of entries) {
|
|
459
|
+
console.log(formatLogEntry(entry));
|
|
460
|
+
}
|
|
461
|
+
if (!options.follow) {
|
|
462
|
+
console.log("─".repeat(80));
|
|
463
|
+
console.log(`${colors.gray}Showing last ${entries.length} events. Use --follow to watch in real-time.${colors.reset}`);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
console.log("─".repeat(80));
|
|
467
|
+
console.log(`${colors.gray}Watching for new events... (Ctrl+C to exit)${colors.reset}`);
|
|
468
|
+
console.log("─".repeat(80));
|
|
469
|
+
let lastSize = statSync(logPath).size;
|
|
470
|
+
const logWatcher = watch(logPath, async () => {
|
|
471
|
+
try {
|
|
472
|
+
if (!existsSync(logPath)) {
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
const currentSize = statSync(logPath).size;
|
|
476
|
+
if (currentSize > lastSize) {
|
|
477
|
+
const stream = createReadStream(logPath, { start: lastSize });
|
|
478
|
+
const rl = createInterface({ input: stream, crlfDelay: Infinity });
|
|
479
|
+
for await (const line of rl) {
|
|
480
|
+
if (line.trim()) {
|
|
481
|
+
try {
|
|
482
|
+
const entry = JSON.parse(line);
|
|
483
|
+
console.log(formatLogEntry(entry));
|
|
484
|
+
}
|
|
485
|
+
catch {
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
lastSize = currentSize;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
catch (error) {
|
|
493
|
+
if (error.code !== "ENOENT") {
|
|
494
|
+
console.error(`${colors.red}Error reading log:${colors.reset}`, error);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
const cleanup = () => {
|
|
499
|
+
logWatcher.close();
|
|
500
|
+
console.log(`\n${colors.gray}Monitor stopped.${colors.reset}`);
|
|
501
|
+
process.exit(0);
|
|
502
|
+
};
|
|
503
|
+
process.on("SIGINT", cleanup);
|
|
504
|
+
process.on("SIGTERM", cleanup);
|
|
505
|
+
await new Promise(() => {
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
function calculateReqPerMin(instance) {
|
|
509
|
+
if (instance.uptime === 0 || instance.requestCount === 0)
|
|
510
|
+
return 0;
|
|
511
|
+
const minutes = instance.uptime / 60;
|
|
512
|
+
if (minutes < 1)
|
|
513
|
+
return instance.requestCount;
|
|
514
|
+
return Math.round(instance.requestCount / minutes);
|
|
515
|
+
}
|
|
516
|
+
function getStatusIndicator(instance) {
|
|
517
|
+
if (isHeartbeatStale(instance)) {
|
|
518
|
+
return `${colors.yellow}?${colors.reset}`;
|
|
519
|
+
}
|
|
520
|
+
switch (instance.status) {
|
|
521
|
+
case "active":
|
|
522
|
+
return `${colors.green}●${colors.reset}`;
|
|
523
|
+
case "idle":
|
|
524
|
+
return `${colors.gray}○${colors.reset}`;
|
|
525
|
+
case "stopping":
|
|
526
|
+
return `${colors.red}-${colors.reset}`;
|
|
527
|
+
default:
|
|
528
|
+
return `${colors.blue}◐${colors.reset}`;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
function formatInstanceRow(instance) {
|
|
532
|
+
const pid = String(instance.pid).padStart(5);
|
|
533
|
+
const project = instance.projectName.padEnd(24).slice(0, 24);
|
|
534
|
+
const tools = String(instance.toolCount).padStart(5);
|
|
535
|
+
const reqPerMin = String(calculateReqPerMin(instance)).padStart(5);
|
|
536
|
+
const mem = `${instance.memoryUsageMB}MB`.padStart(6);
|
|
537
|
+
const uptime = formatUptime(instance.uptime).padStart(7);
|
|
538
|
+
const status = getStatusIndicator(instance);
|
|
539
|
+
const statusText = instance.status.padEnd(7);
|
|
540
|
+
return ` ${pid} ${project} ${tools} ${reqPerMin} ${mem} ${uptime} ${status} ${statusText}`;
|
|
541
|
+
}
|
|
542
|
+
function printInstanceTableHeader(version, instanceCount) {
|
|
543
|
+
const countText = instanceCount === 1 ? "1 instance" : `${instanceCount} instances`;
|
|
544
|
+
console.log(`${colors.bright}centient-monitor${colors.reset} v${version} ${countText}`);
|
|
545
|
+
console.log("─".repeat(80));
|
|
546
|
+
console.log(`${colors.gray} PID PROJECT TOOLS REQ/M MEM UPTIME STATUS${colors.reset}`);
|
|
547
|
+
console.log("─".repeat(80));
|
|
548
|
+
}
|
|
549
|
+
function printInstancesJson(instances) {
|
|
550
|
+
const stats = getAggregatedStats();
|
|
551
|
+
const output = {
|
|
552
|
+
timestamp: new Date().toISOString(),
|
|
553
|
+
instances: instances.map(i => ({
|
|
554
|
+
...i,
|
|
555
|
+
reqPerMin: calculateReqPerMin(i),
|
|
556
|
+
stale: isHeartbeatStale(i),
|
|
557
|
+
})),
|
|
558
|
+
summary: stats,
|
|
559
|
+
};
|
|
560
|
+
console.log(JSON.stringify(output, null, 2));
|
|
561
|
+
}
|
|
562
|
+
function printInstancesQuiet(instances) {
|
|
563
|
+
for (const instance of instances) {
|
|
564
|
+
console.log(instance.pid);
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
function printInstancesSummary(version) {
|
|
568
|
+
const stats = getAggregatedStats();
|
|
569
|
+
const instances = listInstances();
|
|
570
|
+
console.log(`${colors.bright}centient-monitor${colors.reset} v${version}\n`);
|
|
571
|
+
const activeText = stats.activeInstances > 0
|
|
572
|
+
? `${colors.green}${stats.activeInstances} active${colors.reset}`
|
|
573
|
+
: "0 active";
|
|
574
|
+
const idleText = stats.idleInstances > 0
|
|
575
|
+
? `${colors.gray}${stats.idleInstances} idle${colors.reset}`
|
|
576
|
+
: "0 idle";
|
|
577
|
+
console.log(`Instances: ${stats.totalInstances} total (${activeText}, ${idleText})`);
|
|
578
|
+
console.log(`Memory: ${stats.totalMemoryMB} MB total`);
|
|
579
|
+
console.log(`Requests: ${stats.totalRequests} total`);
|
|
580
|
+
if (instances.length > 0) {
|
|
581
|
+
const oldest = instances.reduce((a, b) => a.uptime > b.uptime ? a : b);
|
|
582
|
+
console.log(`Oldest: ${formatUptime(oldest.uptime)} (${oldest.projectName})`);
|
|
583
|
+
}
|
|
584
|
+
console.log("");
|
|
585
|
+
}
|
|
586
|
+
function formatActivityEntry(projectName, entry) {
|
|
587
|
+
const time = new Date(entry.timestamp).toLocaleTimeString();
|
|
588
|
+
const outcomeColor = entry.outcome === "success" ? colors.green : colors.red;
|
|
589
|
+
const outcomeSymbol = entry.outcome === "success" ? "✓" : "✗";
|
|
590
|
+
const duration = `${entry.duration}ms`.padStart(6);
|
|
591
|
+
return ` ${colors.gray}${time}${colors.reset} │ ${colors.cyan}${projectName.padEnd(16).slice(0, 16)}${colors.reset} │ ${entry.tool.padEnd(24).slice(0, 24)} │ ${outcomeColor}${outcomeSymbol}${colors.reset} ${duration}`;
|
|
592
|
+
}
|
|
593
|
+
async function watchAllInstanceLogs(instances, onActivity) {
|
|
594
|
+
const watchers = [];
|
|
595
|
+
const fileSizes = new Map();
|
|
596
|
+
for (const instance of instances) {
|
|
597
|
+
const logPath = join(instance.projectPath, ".audit-log.jsonl");
|
|
598
|
+
if (!existsSync(logPath))
|
|
599
|
+
continue;
|
|
600
|
+
try {
|
|
601
|
+
fileSizes.set(logPath, statSync(logPath).size);
|
|
602
|
+
const watcher = watch(logPath, async () => {
|
|
603
|
+
try {
|
|
604
|
+
if (!existsSync(logPath))
|
|
605
|
+
return;
|
|
606
|
+
const currentSize = statSync(logPath).size;
|
|
607
|
+
const lastSize = fileSizes.get(logPath) || 0;
|
|
608
|
+
if (currentSize > lastSize) {
|
|
609
|
+
const stream = createReadStream(logPath, { start: lastSize });
|
|
610
|
+
const rl = createInterface({ input: stream, crlfDelay: Infinity });
|
|
611
|
+
for await (const line of rl) {
|
|
612
|
+
if (line.trim()) {
|
|
613
|
+
try {
|
|
614
|
+
const entry = JSON.parse(line);
|
|
615
|
+
onActivity(instance.projectName, entry);
|
|
616
|
+
}
|
|
617
|
+
catch {
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
fileSizes.set(logPath, currentSize);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
catch {
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
watchers.push(watcher);
|
|
628
|
+
}
|
|
629
|
+
catch {
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return () => {
|
|
633
|
+
for (const watcher of watchers) {
|
|
634
|
+
watcher.close();
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
export async function monitor(options) {
|
|
639
|
+
const version = getVersion();
|
|
640
|
+
let instances = listInstances();
|
|
641
|
+
if (options.project) {
|
|
642
|
+
instances = instances.filter(i => i.projectName.toLowerCase().includes(options.project.toLowerCase()));
|
|
643
|
+
}
|
|
644
|
+
if (options.quiet) {
|
|
645
|
+
printInstancesQuiet(instances);
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
if (options.json && !options.follow) {
|
|
649
|
+
printInstancesJson(instances);
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
if (options.summary) {
|
|
653
|
+
printInstancesSummary(version);
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
printInstanceTableHeader(version, instances.length);
|
|
657
|
+
if (instances.length === 0) {
|
|
658
|
+
console.log(`\n${colors.yellow}No running centient instances found.${colors.reset}`);
|
|
659
|
+
console.log(`${colors.gray}Start a centient MCP server to see it here.${colors.reset}\n`);
|
|
660
|
+
return;
|
|
661
|
+
}
|
|
662
|
+
for (const instance of instances) {
|
|
663
|
+
console.log(formatInstanceRow(instance));
|
|
664
|
+
}
|
|
665
|
+
console.log("─".repeat(80));
|
|
666
|
+
if (!options.follow) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
console.log(`\n${colors.bright}Recent Activity${colors.reset}`);
|
|
670
|
+
console.log("─".repeat(80));
|
|
671
|
+
console.log(`${colors.gray}Watching for new events... (Ctrl+C to exit)${colors.reset}\n`);
|
|
672
|
+
const cleanup = await watchAllInstanceLogs(instances, (projectName, entry) => {
|
|
673
|
+
if (options.json) {
|
|
674
|
+
console.log(JSON.stringify({
|
|
675
|
+
type: "activity",
|
|
676
|
+
timestamp: entry.timestamp,
|
|
677
|
+
project: projectName,
|
|
678
|
+
tool: entry.tool,
|
|
679
|
+
duration: entry.duration,
|
|
680
|
+
outcome: entry.outcome,
|
|
681
|
+
}));
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
console.log(formatActivityEntry(projectName, entry));
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
const shutdownHandler = () => {
|
|
688
|
+
cleanup();
|
|
689
|
+
console.log(`\n${colors.gray}Monitor stopped.${colors.reset}`);
|
|
690
|
+
process.exit(0);
|
|
691
|
+
};
|
|
692
|
+
process.on("SIGINT", shutdownHandler);
|
|
693
|
+
process.on("SIGTERM", shutdownHandler);
|
|
694
|
+
await new Promise(() => {
|
|
695
|
+
});
|
|
696
|
+
}
|
|
697
|
+
export function parseArgs(args) {
|
|
698
|
+
let logLast = 20;
|
|
699
|
+
let logFollow = false;
|
|
700
|
+
let monitorFollow = false;
|
|
701
|
+
let monitorProject;
|
|
702
|
+
let monitorJson = false;
|
|
703
|
+
let monitorQuiet = false;
|
|
704
|
+
let monitorSummary = false;
|
|
705
|
+
let initForce = false;
|
|
706
|
+
let updateDryRun = false;
|
|
707
|
+
let hasMonitor = false;
|
|
708
|
+
let hasLog = false;
|
|
709
|
+
let hasInit = false;
|
|
710
|
+
let hasCheckCommands = false;
|
|
711
|
+
let hasUpdateCommands = false;
|
|
712
|
+
for (let i = 0; i < args.length; i++) {
|
|
713
|
+
const arg = args[i];
|
|
714
|
+
switch (arg) {
|
|
715
|
+
case "-V":
|
|
716
|
+
case "--version":
|
|
717
|
+
return { action: "version" };
|
|
718
|
+
case "-h":
|
|
719
|
+
case "--help":
|
|
720
|
+
return { action: "help" };
|
|
721
|
+
case "-l":
|
|
722
|
+
case "--list-tools":
|
|
723
|
+
return { action: "list-tools" };
|
|
724
|
+
case "--health":
|
|
725
|
+
return { action: "health" };
|
|
726
|
+
case "--config":
|
|
727
|
+
return { action: "config" };
|
|
728
|
+
case "--stats":
|
|
729
|
+
return { action: "stats" };
|
|
730
|
+
case "init":
|
|
731
|
+
hasInit = true;
|
|
732
|
+
break;
|
|
733
|
+
case "check-commands":
|
|
734
|
+
hasCheckCommands = true;
|
|
735
|
+
break;
|
|
736
|
+
case "update-commands":
|
|
737
|
+
hasUpdateCommands = true;
|
|
738
|
+
break;
|
|
739
|
+
case "--monitor":
|
|
740
|
+
hasMonitor = true;
|
|
741
|
+
break;
|
|
742
|
+
case "--log":
|
|
743
|
+
hasLog = true;
|
|
744
|
+
break;
|
|
745
|
+
case "-f":
|
|
746
|
+
case "--follow":
|
|
747
|
+
monitorFollow = true;
|
|
748
|
+
logFollow = true;
|
|
749
|
+
break;
|
|
750
|
+
case "-j":
|
|
751
|
+
case "--json":
|
|
752
|
+
monitorJson = true;
|
|
753
|
+
break;
|
|
754
|
+
case "-q":
|
|
755
|
+
case "--quiet":
|
|
756
|
+
monitorQuiet = true;
|
|
757
|
+
break;
|
|
758
|
+
case "-s":
|
|
759
|
+
case "--summary":
|
|
760
|
+
monitorSummary = true;
|
|
761
|
+
break;
|
|
762
|
+
case "--force":
|
|
763
|
+
initForce = true;
|
|
764
|
+
break;
|
|
765
|
+
case "--dry-run":
|
|
766
|
+
updateDryRun = true;
|
|
767
|
+
break;
|
|
768
|
+
case "-p":
|
|
769
|
+
case "--project":
|
|
770
|
+
const projectArg = args[i + 1];
|
|
771
|
+
if (projectArg && !projectArg.startsWith("-")) {
|
|
772
|
+
monitorProject = projectArg;
|
|
773
|
+
i++;
|
|
774
|
+
}
|
|
775
|
+
break;
|
|
776
|
+
case "--last":
|
|
777
|
+
const lastArg = args[i + 1];
|
|
778
|
+
if (lastArg && !lastArg.startsWith("-")) {
|
|
779
|
+
logLast = parseInt(lastArg, 10) || 20;
|
|
780
|
+
i++;
|
|
781
|
+
}
|
|
782
|
+
break;
|
|
783
|
+
default:
|
|
784
|
+
if (arg && arg.startsWith("-")) {
|
|
785
|
+
console.error(`Warning: Unknown option '${arg}'`);
|
|
786
|
+
}
|
|
787
|
+
break;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
if (hasLog) {
|
|
791
|
+
return { action: "log", logOptions: { last: logLast, follow: logFollow } };
|
|
792
|
+
}
|
|
793
|
+
if (hasMonitor) {
|
|
794
|
+
return {
|
|
795
|
+
action: "monitor",
|
|
796
|
+
monitorOptions: {
|
|
797
|
+
follow: monitorFollow,
|
|
798
|
+
project: monitorProject,
|
|
799
|
+
json: monitorJson,
|
|
800
|
+
quiet: monitorQuiet,
|
|
801
|
+
summary: monitorSummary,
|
|
802
|
+
},
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
if (hasInit) {
|
|
806
|
+
return { action: "init", initOptions: { force: initForce } };
|
|
807
|
+
}
|
|
808
|
+
if (hasCheckCommands) {
|
|
809
|
+
return { action: "check-commands" };
|
|
810
|
+
}
|
|
811
|
+
if (hasUpdateCommands) {
|
|
812
|
+
return { action: "update-commands", updateOptions: { force: initForce, dryRun: updateDryRun } };
|
|
813
|
+
}
|
|
814
|
+
return { action: "server" };
|
|
815
|
+
}
|
|
816
|
+
//# sourceMappingURL=cli.js.map
|