ccjk 10.3.0 → 11.1.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/dist/chunks/auto-init.mjs +7585 -0
- package/dist/chunks/evolution.mjs +383 -0
- package/dist/chunks/package.mjs +1 -1
- package/dist/chunks/quick-provider.mjs +1 -0
- package/dist/chunks/remote.mjs +166 -0
- package/dist/cli.mjs +86 -0
- package/dist/i18n/locales/en/evolution.json +54 -0
- package/dist/i18n/locales/en/remote.json +39 -0
- package/dist/i18n/locales/zh-CN/evolution.json +54 -0
- package/dist/i18n/locales/zh-CN/remote.json +39 -0
- package/dist/index.mjs +2 -73
- package/dist/shared/ccjk.Cu_R2MbQ.mjs +75 -0
- package/package.json +7 -1
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
import ansis from 'ansis';
|
|
2
|
+
import { i18n } from './index2.mjs';
|
|
3
|
+
import 'node:fs';
|
|
4
|
+
import 'node:process';
|
|
5
|
+
import 'node:url';
|
|
6
|
+
import 'i18next';
|
|
7
|
+
import 'i18next-fs-backend';
|
|
8
|
+
import 'pathe';
|
|
9
|
+
|
|
10
|
+
class A2AClient {
|
|
11
|
+
baseUrl;
|
|
12
|
+
token = null;
|
|
13
|
+
agentId = null;
|
|
14
|
+
constructor(baseUrl = "http://localhost:3005") {
|
|
15
|
+
this.baseUrl = baseUrl;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Register agent (hello)
|
|
19
|
+
*/
|
|
20
|
+
async hello(agent) {
|
|
21
|
+
const response = await this.request("/a2a/hello", {
|
|
22
|
+
method: "POST",
|
|
23
|
+
body: { type: "hello", agent }
|
|
24
|
+
});
|
|
25
|
+
this.token = response.token;
|
|
26
|
+
this.agentId = response.agentId;
|
|
27
|
+
return response;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Publish a gene
|
|
31
|
+
*/
|
|
32
|
+
async publish(gene, proof) {
|
|
33
|
+
this.ensureAuthenticated();
|
|
34
|
+
return this.request("/a2a/publish", {
|
|
35
|
+
method: "POST",
|
|
36
|
+
body: { type: "publish", gene, proof },
|
|
37
|
+
auth: true
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Fetch genes
|
|
42
|
+
*/
|
|
43
|
+
async fetch(query, limit) {
|
|
44
|
+
this.ensureAuthenticated();
|
|
45
|
+
const response = await this.request("/a2a/fetch", {
|
|
46
|
+
method: "POST",
|
|
47
|
+
body: { type: "fetch", query, limit },
|
|
48
|
+
auth: true
|
|
49
|
+
});
|
|
50
|
+
return response.genes;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Report usage result
|
|
54
|
+
*/
|
|
55
|
+
async report(geneId, result) {
|
|
56
|
+
this.ensureAuthenticated();
|
|
57
|
+
return this.request("/a2a/report", {
|
|
58
|
+
method: "POST",
|
|
59
|
+
body: { type: "report", geneId, result },
|
|
60
|
+
auth: true
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Request decision
|
|
65
|
+
*/
|
|
66
|
+
async decision(problem, options, context) {
|
|
67
|
+
this.ensureAuthenticated();
|
|
68
|
+
return this.request("/a2a/decision", {
|
|
69
|
+
method: "POST",
|
|
70
|
+
body: { type: "decision", problem, options, context },
|
|
71
|
+
auth: true
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Revoke a gene
|
|
76
|
+
*/
|
|
77
|
+
async revoke(geneId, reason) {
|
|
78
|
+
this.ensureAuthenticated();
|
|
79
|
+
await this.request(`/a2a/genes/${geneId}`, {
|
|
80
|
+
method: "DELETE",
|
|
81
|
+
body: { reason },
|
|
82
|
+
auth: true
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get agent ID
|
|
87
|
+
*/
|
|
88
|
+
getAgentId() {
|
|
89
|
+
return this.agentId;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Check if authenticated
|
|
93
|
+
*/
|
|
94
|
+
isAuthenticated() {
|
|
95
|
+
return this.token !== null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Internal request wrapper
|
|
99
|
+
*/
|
|
100
|
+
async request(path, options) {
|
|
101
|
+
const url = `${this.baseUrl}${path}`;
|
|
102
|
+
const headers = {
|
|
103
|
+
"Content-Type": "application/json"
|
|
104
|
+
};
|
|
105
|
+
if (options.auth && this.token) {
|
|
106
|
+
headers["Authorization"] = `Bearer ${this.token}`;
|
|
107
|
+
}
|
|
108
|
+
const response = await globalThis.fetch(url, {
|
|
109
|
+
method: options.method,
|
|
110
|
+
headers,
|
|
111
|
+
body: options.body ? JSON.stringify(options.body) : void 0
|
|
112
|
+
});
|
|
113
|
+
if (!response.ok) {
|
|
114
|
+
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
115
|
+
throw new Error(error.error || `Request failed: ${response.statusText}`);
|
|
116
|
+
}
|
|
117
|
+
return response.json();
|
|
118
|
+
}
|
|
119
|
+
ensureAuthenticated() {
|
|
120
|
+
if (!this.token) {
|
|
121
|
+
throw new Error("Not authenticated. Call hello() first.");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const PROTOCOL_CACHE_TTL_MS = 10 * 60 * 1e3;
|
|
127
|
+
const HEALTH_PATH = "/health";
|
|
128
|
+
const API_CANDIDATES = [
|
|
129
|
+
"https://remote-api.claudehome.cn",
|
|
130
|
+
"http://remote-api.claudehome.cn"
|
|
131
|
+
];
|
|
132
|
+
let protocolCache = null;
|
|
133
|
+
async function resolveRemoteApiBaseUrl(timeoutMs = 5e3) {
|
|
134
|
+
const now = Date.now();
|
|
135
|
+
if (protocolCache && protocolCache.expiresAt > now) {
|
|
136
|
+
return protocolCache.baseUrl;
|
|
137
|
+
}
|
|
138
|
+
for (const baseUrl of API_CANDIDATES) {
|
|
139
|
+
const ok = await probeHealth(baseUrl, timeoutMs);
|
|
140
|
+
if (ok) {
|
|
141
|
+
protocolCache = {
|
|
142
|
+
baseUrl,
|
|
143
|
+
expiresAt: now + PROTOCOL_CACHE_TTL_MS
|
|
144
|
+
};
|
|
145
|
+
return baseUrl;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
throw new Error("Remote API unavailable");
|
|
149
|
+
}
|
|
150
|
+
async function probeHealth(baseUrl, timeoutMs) {
|
|
151
|
+
const controller = new AbortController();
|
|
152
|
+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
153
|
+
try {
|
|
154
|
+
const response = await fetch(`${baseUrl}${HEALTH_PATH}`, {
|
|
155
|
+
method: "GET",
|
|
156
|
+
signal: controller.signal
|
|
157
|
+
});
|
|
158
|
+
if (!response.ok) {
|
|
159
|
+
return false;
|
|
160
|
+
}
|
|
161
|
+
const data = await response.json().catch(() => null);
|
|
162
|
+
return data?.status === "ok";
|
|
163
|
+
} catch {
|
|
164
|
+
return false;
|
|
165
|
+
} finally {
|
|
166
|
+
clearTimeout(timeoutId);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function handleEvolutionCommand(action, args, options) {
|
|
171
|
+
try {
|
|
172
|
+
const resolvedBaseUrl = await resolveRemoteApiBaseUrl();
|
|
173
|
+
const client = new A2AClient(resolvedBaseUrl);
|
|
174
|
+
switch (action) {
|
|
175
|
+
case "top":
|
|
176
|
+
await showTopCapabilities(client, options);
|
|
177
|
+
break;
|
|
178
|
+
case "search":
|
|
179
|
+
await searchSolutions(client, args[0], options);
|
|
180
|
+
break;
|
|
181
|
+
case "show":
|
|
182
|
+
await showGeneDetails(client, args[0]);
|
|
183
|
+
break;
|
|
184
|
+
case "stats":
|
|
185
|
+
await showStats(client);
|
|
186
|
+
break;
|
|
187
|
+
default:
|
|
188
|
+
await showTopCapabilities(client, { limit: "30", minGdi: "70" });
|
|
189
|
+
}
|
|
190
|
+
} catch (error) {
|
|
191
|
+
const failedMsg = i18n.t("evolution:failed", "Failed");
|
|
192
|
+
console.error(ansis.red("\u274C " + failedMsg + ":"), error.message);
|
|
193
|
+
process.exit(1);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async function showTopCapabilities(client, options) {
|
|
197
|
+
const connectingMsg = i18n.t("evolution:connecting", "Connecting to Evolution Layer...");
|
|
198
|
+
console.log(ansis.blue("\u{1F517} " + connectingMsg));
|
|
199
|
+
await client.hello({
|
|
200
|
+
id: "claude-code-cli",
|
|
201
|
+
name: "claude-code",
|
|
202
|
+
version: "1.0.0",
|
|
203
|
+
capabilities: ["fetch", "report"]
|
|
204
|
+
});
|
|
205
|
+
const fetchingMsg = i18n.t("evolution:fetching", "Fetching top capabilities...");
|
|
206
|
+
console.log(ansis.blue("\u{1F4CA} " + fetchingMsg));
|
|
207
|
+
const genes = await client.fetch(
|
|
208
|
+
{
|
|
209
|
+
signature: "*",
|
|
210
|
+
context: [],
|
|
211
|
+
minGDI: Number.parseInt(options.minGdi || "70")
|
|
212
|
+
},
|
|
213
|
+
Number.parseInt(options.limit || "30")
|
|
214
|
+
);
|
|
215
|
+
const foundMsg = i18n.t("evolution:found", "Found {{count}} capabilities", { count: genes.length });
|
|
216
|
+
console.log(ansis.green("\n\u2705 " + foundMsg + "\n"));
|
|
217
|
+
if (genes.length === 0) {
|
|
218
|
+
const noResultsMsg = i18n.t("evolution:noResults", "No capabilities found");
|
|
219
|
+
console.log(ansis.yellow(noResultsMsg));
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
genes.forEach((gene, index) => {
|
|
223
|
+
console.log(ansis.bold(`${index + 1}. ${gene.id.substring(0, 8)}`));
|
|
224
|
+
const problemLabel = ansis.cyan(i18n.t("evolution:problem", "Problem"));
|
|
225
|
+
console.log(" " + problemLabel + ": " + gene.problem.signature);
|
|
226
|
+
const solutionLabel = ansis.yellow(i18n.t("evolution:solution", "Solution"));
|
|
227
|
+
console.log(" " + solutionLabel + ": " + gene.solution.strategy);
|
|
228
|
+
console.log(" " + ansis.green("GDI") + ": " + gene.quality.gdi.toFixed(1));
|
|
229
|
+
const usedLabel = ansis.gray(i18n.t("evolution:used", "Used"));
|
|
230
|
+
const timesLabel = i18n.t("evolution:times", "times");
|
|
231
|
+
console.log(" " + usedLabel + ": " + gene.quality.usageCount + " " + timesLabel);
|
|
232
|
+
const successLabel = ansis.gray(i18n.t("evolution:success", "Success"));
|
|
233
|
+
const successRate = (gene.quality.successRate * 100).toFixed(1);
|
|
234
|
+
console.log(" " + successLabel + ": " + successRate + "%");
|
|
235
|
+
console.log();
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
async function searchSolutions(client, query, options) {
|
|
239
|
+
const searchingMsg = i18n.t("evolution:searching", "Searching for: {{query}}", { query });
|
|
240
|
+
console.log(ansis.blue("\u{1F50D} " + searchingMsg));
|
|
241
|
+
await client.hello({
|
|
242
|
+
id: "claude-code-cli",
|
|
243
|
+
name: "claude-code",
|
|
244
|
+
version: "1.0.0",
|
|
245
|
+
capabilities: ["fetch", "report"]
|
|
246
|
+
});
|
|
247
|
+
const genes = await client.fetch(
|
|
248
|
+
{
|
|
249
|
+
signature: query,
|
|
250
|
+
context: [],
|
|
251
|
+
minGDI: Number.parseInt(options.minGdi || "60")
|
|
252
|
+
},
|
|
253
|
+
Number.parseInt(options.limit || "10")
|
|
254
|
+
);
|
|
255
|
+
if (genes.length === 0) {
|
|
256
|
+
const noSolutionsMsg = i18n.t("evolution:noSolutions", "No solutions found");
|
|
257
|
+
console.log(ansis.yellow("\n" + noSolutionsMsg));
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const foundMsg = i18n.t("evolution:foundSolutions", "Found {{count}} solutions", { count: genes.length });
|
|
261
|
+
console.log(ansis.green("\n\u2705 " + foundMsg + "\n"));
|
|
262
|
+
genes.forEach((gene, index) => {
|
|
263
|
+
console.log(ansis.bold(`${index + 1}. ${gene.problem.signature}`));
|
|
264
|
+
console.log(" " + gene.solution.strategy);
|
|
265
|
+
const usedLabel = i18n.t("evolution:used", "Used");
|
|
266
|
+
console.log(" GDI: " + gene.quality.gdi.toFixed(1) + " | " + usedLabel + ": " + gene.quality.usageCount + "x");
|
|
267
|
+
if (gene.problem.context.length > 0) {
|
|
268
|
+
const contextLabel = ansis.gray(i18n.t("evolution:context", "Context"));
|
|
269
|
+
console.log(" " + contextLabel + ": " + gene.problem.context.join(", "));
|
|
270
|
+
}
|
|
271
|
+
console.log();
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
async function showGeneDetails(client, geneId) {
|
|
275
|
+
await client.hello({
|
|
276
|
+
id: "claude-code-cli",
|
|
277
|
+
name: "claude-code",
|
|
278
|
+
version: "1.0.0",
|
|
279
|
+
capabilities: ["fetch", "report"]
|
|
280
|
+
});
|
|
281
|
+
const genes = await client.fetch({ signature: "*", context: [] });
|
|
282
|
+
const gene = genes.find((g) => g.id.startsWith(geneId));
|
|
283
|
+
if (!gene) {
|
|
284
|
+
const notFoundMsg = i18n.t("evolution:geneNotFound", "Gene not found");
|
|
285
|
+
console.log(ansis.red(notFoundMsg));
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
displayGene(gene);
|
|
289
|
+
}
|
|
290
|
+
async function showStats(client) {
|
|
291
|
+
const fetchingMsg = i18n.t("evolution:fetchingStats", "Fetching statistics...");
|
|
292
|
+
console.log(ansis.blue("\u{1F4CA} " + fetchingMsg));
|
|
293
|
+
await client.hello({
|
|
294
|
+
id: "claude-code-cli",
|
|
295
|
+
name: "claude-code",
|
|
296
|
+
version: "1.0.0",
|
|
297
|
+
capabilities: ["fetch", "report"]
|
|
298
|
+
});
|
|
299
|
+
const allGenes = await client.fetch({ signature: "*", context: [] }, 1e3);
|
|
300
|
+
const totalGenes = allGenes.length;
|
|
301
|
+
const avgGDI = allGenes.reduce((sum, g) => sum + g.quality.gdi, 0) / totalGenes;
|
|
302
|
+
const totalUsage = allGenes.reduce((sum, g) => sum + g.quality.usageCount, 0);
|
|
303
|
+
const avgSuccessRate = allGenes.reduce((sum, g) => sum + g.quality.successRate, 0) / totalGenes;
|
|
304
|
+
const typeCount = allGenes.reduce((acc, g) => {
|
|
305
|
+
acc[g.type] = (acc[g.type] || 0) + 1;
|
|
306
|
+
return acc;
|
|
307
|
+
}, {});
|
|
308
|
+
console.log(ansis.bold("\n\u{1F4C8} Evolution Layer Statistics\n"));
|
|
309
|
+
const totalLabel = ansis.cyan(i18n.t("evolution:totalGenes", "Total Genes"));
|
|
310
|
+
console.log(totalLabel + ": " + totalGenes);
|
|
311
|
+
const avgGdiLabel = ansis.cyan(i18n.t("evolution:avgGDI", "Average GDI"));
|
|
312
|
+
console.log(avgGdiLabel + ": " + avgGDI.toFixed(1));
|
|
313
|
+
const totalUsageLabel = ansis.cyan(i18n.t("evolution:totalUsage", "Total Usage"));
|
|
314
|
+
console.log(totalUsageLabel + ": " + totalUsage);
|
|
315
|
+
const avgSuccessLabel = ansis.cyan(i18n.t("evolution:avgSuccess", "Average Success Rate"));
|
|
316
|
+
console.log(avgSuccessLabel + ": " + (avgSuccessRate * 100).toFixed(1) + "%");
|
|
317
|
+
console.log();
|
|
318
|
+
const byTypeLabel = i18n.t("evolution:byType", "By Type");
|
|
319
|
+
console.log(ansis.bold(byTypeLabel + ":"));
|
|
320
|
+
Object.entries(typeCount).forEach(([type, count]) => {
|
|
321
|
+
console.log(" " + type + ": " + count);
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
function displayGene(gene) {
|
|
325
|
+
const detailsLabel = i18n.t("evolution:geneDetails", "Gene Details");
|
|
326
|
+
console.log(ansis.bold("\n\u{1F4E6} " + detailsLabel + "\n"));
|
|
327
|
+
console.log(ansis.cyan("ID") + ": " + gene.id);
|
|
328
|
+
const typeLabel = i18n.t("evolution:type", "Type");
|
|
329
|
+
console.log(ansis.cyan(typeLabel) + ": " + gene.type);
|
|
330
|
+
console.log(ansis.cyan("SHA256") + ": " + gene.sha256);
|
|
331
|
+
console.log();
|
|
332
|
+
const problemLabel = i18n.t("evolution:problem", "Problem");
|
|
333
|
+
console.log(ansis.bold(problemLabel + ":"));
|
|
334
|
+
const sigLabel = i18n.t("evolution:signature", "Signature");
|
|
335
|
+
console.log(" " + sigLabel + ": " + gene.problem.signature);
|
|
336
|
+
if (gene.problem.context.length > 0) {
|
|
337
|
+
const contextLabel = i18n.t("evolution:context", "Context");
|
|
338
|
+
console.log(" " + contextLabel + ": " + gene.problem.context.join(", "));
|
|
339
|
+
}
|
|
340
|
+
console.log();
|
|
341
|
+
const solutionLabel = i18n.t("evolution:solution", "Solution");
|
|
342
|
+
console.log(ansis.bold(solutionLabel + ":"));
|
|
343
|
+
const strategyLabel = i18n.t("evolution:strategy", "Strategy");
|
|
344
|
+
console.log(" " + strategyLabel + ": " + gene.solution.strategy);
|
|
345
|
+
if (gene.solution.code) {
|
|
346
|
+
const codeLabel = i18n.t("evolution:code", "Code");
|
|
347
|
+
console.log(" " + codeLabel + ":");
|
|
348
|
+
const codeLines = gene.solution.code.split("\n").map((line) => " " + line).join("\n");
|
|
349
|
+
console.log(ansis.gray(codeLines));
|
|
350
|
+
}
|
|
351
|
+
if (gene.solution.steps.length > 0) {
|
|
352
|
+
const stepsLabel = i18n.t("evolution:steps", "Steps");
|
|
353
|
+
console.log(" " + stepsLabel + ":");
|
|
354
|
+
gene.solution.steps.forEach((step, i) => {
|
|
355
|
+
console.log(" " + (i + 1) + ". " + step);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
console.log();
|
|
359
|
+
const qualityLabel = i18n.t("evolution:quality", "Quality");
|
|
360
|
+
console.log(ansis.bold(qualityLabel + ":"));
|
|
361
|
+
console.log(" GDI: " + gene.quality.gdi.toFixed(1));
|
|
362
|
+
const successRateLabel = i18n.t("evolution:successRate", "Success Rate");
|
|
363
|
+
console.log(" " + successRateLabel + ": " + (gene.quality.successRate * 100).toFixed(1) + "%");
|
|
364
|
+
const usageCountLabel = i18n.t("evolution:usageCount", "Usage Count");
|
|
365
|
+
console.log(" " + usageCountLabel + ": " + gene.quality.usageCount);
|
|
366
|
+
const avgTimeLabel = i18n.t("evolution:avgTime", "Average Time");
|
|
367
|
+
console.log(" " + avgTimeLabel + ": " + gene.quality.avgTime + "s");
|
|
368
|
+
if (gene.metadata) {
|
|
369
|
+
console.log();
|
|
370
|
+
const metadataLabel = i18n.t("evolution:metadata", "Metadata");
|
|
371
|
+
console.log(ansis.bold(metadataLabel + ":"));
|
|
372
|
+
const authorLabel = i18n.t("evolution:author", "Author");
|
|
373
|
+
console.log(" " + authorLabel + ": " + (gene.metadata.author || "-"));
|
|
374
|
+
const createdLabel = i18n.t("evolution:createdAt", "Created At");
|
|
375
|
+
console.log(" " + createdLabel + ": " + (gene.metadata.createdAt || "-"));
|
|
376
|
+
if (gene.metadata.tags && gene.metadata.tags.length > 0) {
|
|
377
|
+
const tagsLabel = i18n.t("evolution:tags", "Tags");
|
|
378
|
+
console.log(" " + tagsLabel + ": " + gene.metadata.tags.join(", "));
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
export { handleEvolutionCommand };
|
package/dist/chunks/package.mjs
CHANGED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { l as logger } from '../shared/ccjk.Cu_R2MbQ.mjs';
|
|
2
|
+
import { i18n } from './index2.mjs';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
import { spawn } from 'child_process';
|
|
5
|
+
import { homedir } from 'os';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync } from 'fs';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import 'ansis';
|
|
10
|
+
import 'node:fs';
|
|
11
|
+
import 'node:process';
|
|
12
|
+
import 'node:url';
|
|
13
|
+
import 'i18next';
|
|
14
|
+
import 'i18next-fs-backend';
|
|
15
|
+
import 'pathe';
|
|
16
|
+
|
|
17
|
+
const DAEMON_CONFIG_PATH = join(homedir(), ".ccjk", "daemon.json");
|
|
18
|
+
async function enableRemote() {
|
|
19
|
+
console.log(i18n.t("remote:enable.title"));
|
|
20
|
+
const config = loadDaemonConfig();
|
|
21
|
+
if (config.enabled) {
|
|
22
|
+
console.log(i18n.t("remote:enable.already_enabled"));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const { serverUrl } = await inquirer.prompt([
|
|
26
|
+
{
|
|
27
|
+
type: "input",
|
|
28
|
+
name: "serverUrl",
|
|
29
|
+
message: i18n.t("remote:enable.server_url"),
|
|
30
|
+
default: "https://ccjk-server.example.com"
|
|
31
|
+
}
|
|
32
|
+
]);
|
|
33
|
+
const machineId = `machine-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
34
|
+
const newConfig = {
|
|
35
|
+
enabled: true,
|
|
36
|
+
serverUrl,
|
|
37
|
+
machineId
|
|
38
|
+
};
|
|
39
|
+
saveDaemonConfig(newConfig);
|
|
40
|
+
console.log(i18n.t("remote:enable.success"));
|
|
41
|
+
console.log(i18n.t("remote:enable.next_steps"));
|
|
42
|
+
}
|
|
43
|
+
async function disableRemote() {
|
|
44
|
+
console.log(i18n.t("remote:disable.title"));
|
|
45
|
+
const config = loadDaemonConfig();
|
|
46
|
+
if (!config.enabled) {
|
|
47
|
+
console.log(i18n.t("remote:disable.already_disabled"));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
await stopDaemon();
|
|
51
|
+
config.enabled = false;
|
|
52
|
+
saveDaemonConfig(config);
|
|
53
|
+
console.log(i18n.t("remote:disable.success"));
|
|
54
|
+
}
|
|
55
|
+
async function remoteStatus() {
|
|
56
|
+
const config = loadDaemonConfig();
|
|
57
|
+
console.log(i18n.t("remote:status.title"));
|
|
58
|
+
console.log(` ${i18n.t("remote:status.enabled")}: ${config.enabled ? "\u2705" : "\u274C"}`);
|
|
59
|
+
if (config.enabled) {
|
|
60
|
+
console.log(` ${i18n.t("remote:status.server")}: ${config.serverUrl}`);
|
|
61
|
+
console.log(` ${i18n.t("remote:status.machine_id")}: ${config.machineId}`);
|
|
62
|
+
const daemonRunning = await isDaemonRunning();
|
|
63
|
+
console.log(` ${i18n.t("remote:status.daemon")}: ${daemonRunning ? "\u{1F7E2} Running" : "\u{1F534} Stopped"}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function showQRCode() {
|
|
67
|
+
const config = loadDaemonConfig();
|
|
68
|
+
if (!config.enabled) {
|
|
69
|
+
console.log(i18n.t("remote:qr.not_enabled"));
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const pairingData = {
|
|
73
|
+
serverUrl: config.serverUrl,
|
|
74
|
+
machineId: config.machineId,
|
|
75
|
+
timestamp: Date.now()
|
|
76
|
+
};
|
|
77
|
+
const pairingUrl = `ccjk://pair?data=${encodeURIComponent(JSON.stringify(pairingData))}`;
|
|
78
|
+
console.log(i18n.t("remote:qr.title"));
|
|
79
|
+
console.log(i18n.t("remote:qr.instructions"));
|
|
80
|
+
console.log();
|
|
81
|
+
console.log(` ${pairingUrl}`);
|
|
82
|
+
console.log();
|
|
83
|
+
console.log(i18n.t("remote:qr.manual_entry"));
|
|
84
|
+
console.log(` Server: ${config.serverUrl}`);
|
|
85
|
+
console.log(` Machine ID: ${config.machineId}`);
|
|
86
|
+
}
|
|
87
|
+
async function startDaemon() {
|
|
88
|
+
const spinner = ora(i18n.t("remote:daemon.starting")).start();
|
|
89
|
+
try {
|
|
90
|
+
if (await isDaemonRunning()) {
|
|
91
|
+
spinner.warn(i18n.t("remote:daemon.already_running"));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
const daemon = spawn("ccjk-daemon", ["start"], {
|
|
95
|
+
detached: true,
|
|
96
|
+
stdio: "ignore"
|
|
97
|
+
});
|
|
98
|
+
daemon.unref();
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
100
|
+
if (await isDaemonRunning()) {
|
|
101
|
+
spinner.succeed(i18n.t("remote:daemon.started"));
|
|
102
|
+
} else {
|
|
103
|
+
spinner.fail(i18n.t("remote:daemon.start_failed"));
|
|
104
|
+
}
|
|
105
|
+
} catch (error) {
|
|
106
|
+
spinner.fail(i18n.t("remote:daemon.start_error"));
|
|
107
|
+
logger.error("Failed to start daemon:", error);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
async function stopDaemon() {
|
|
111
|
+
const spinner = ora(i18n.t("remote:daemon.stopping")).start();
|
|
112
|
+
try {
|
|
113
|
+
if (!await isDaemonRunning()) {
|
|
114
|
+
spinner.warn(i18n.t("remote:daemon.not_running"));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const response = await fetch("http://127.0.0.1:37821/stop", {
|
|
118
|
+
method: "POST"
|
|
119
|
+
});
|
|
120
|
+
if (response.ok) {
|
|
121
|
+
spinner.succeed(i18n.t("remote:daemon.stopped"));
|
|
122
|
+
} else {
|
|
123
|
+
spinner.fail(i18n.t("remote:daemon.stop_failed"));
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
spinner.fail(i18n.t("remote:daemon.stop_error"));
|
|
127
|
+
logger.error("Failed to stop daemon:", error);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function isDaemonRunning() {
|
|
131
|
+
try {
|
|
132
|
+
const response = await fetch("http://127.0.0.1:37821/health", {
|
|
133
|
+
signal: AbortSignal.timeout(1e3)
|
|
134
|
+
});
|
|
135
|
+
return response.ok;
|
|
136
|
+
} catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function loadDaemonConfig() {
|
|
141
|
+
try {
|
|
142
|
+
if (existsSync(DAEMON_CONFIG_PATH)) {
|
|
143
|
+
return JSON.parse(readFileSync(DAEMON_CONFIG_PATH, "utf-8"));
|
|
144
|
+
}
|
|
145
|
+
} catch (error) {
|
|
146
|
+
logger.error("Failed to load daemon config:", error);
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
enabled: false,
|
|
150
|
+
serverUrl: ""
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function saveDaemonConfig(config) {
|
|
154
|
+
try {
|
|
155
|
+
const dir = join(homedir(), ".ccjk");
|
|
156
|
+
if (!existsSync(dir)) {
|
|
157
|
+
require("fs").mkdirSync(dir, { recursive: true });
|
|
158
|
+
}
|
|
159
|
+
writeFileSync(DAEMON_CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
160
|
+
} catch (error) {
|
|
161
|
+
logger.error("Failed to save daemon config:", error);
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export { disableRemote, enableRemote, remoteStatus, showQRCode, startDaemon, stopDaemon };
|
package/dist/cli.mjs
CHANGED
|
@@ -1456,6 +1456,87 @@ ${ansis.yellow("By Status:")}`);
|
|
|
1456
1456
|
};
|
|
1457
1457
|
}
|
|
1458
1458
|
},
|
|
1459
|
+
{
|
|
1460
|
+
name: "remote",
|
|
1461
|
+
description: "Remote control management",
|
|
1462
|
+
tier: "core",
|
|
1463
|
+
options: [
|
|
1464
|
+
{ flags: "enable", description: "Enable remote control" },
|
|
1465
|
+
{ flags: "disable", description: "Disable remote control" },
|
|
1466
|
+
{ flags: "status", description: "Show remote status" },
|
|
1467
|
+
{ flags: "qr", description: "Show pairing QR code" }
|
|
1468
|
+
],
|
|
1469
|
+
loader: async () => {
|
|
1470
|
+
const { enableRemote, disableRemote, remoteStatus, showQRCode } = await import('./chunks/remote.mjs');
|
|
1471
|
+
return async (options, ...args) => {
|
|
1472
|
+
const action = args[0];
|
|
1473
|
+
switch (action) {
|
|
1474
|
+
case "enable":
|
|
1475
|
+
await enableRemote();
|
|
1476
|
+
break;
|
|
1477
|
+
case "disable":
|
|
1478
|
+
await disableRemote();
|
|
1479
|
+
break;
|
|
1480
|
+
case "status":
|
|
1481
|
+
await remoteStatus();
|
|
1482
|
+
break;
|
|
1483
|
+
case "qr":
|
|
1484
|
+
await showQRCode();
|
|
1485
|
+
break;
|
|
1486
|
+
default:
|
|
1487
|
+
await remoteStatus();
|
|
1488
|
+
}
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
},
|
|
1492
|
+
{
|
|
1493
|
+
name: "evolution",
|
|
1494
|
+
description: "Evolution Layer - AI knowledge sharing",
|
|
1495
|
+
tier: "core",
|
|
1496
|
+
options: [
|
|
1497
|
+
{ flags: "top", description: "Show top capabilities" },
|
|
1498
|
+
{ flags: "search <query>", description: "Search for solutions" },
|
|
1499
|
+
{ flags: "show <geneId>", description: "Show gene details" },
|
|
1500
|
+
{ flags: "stats", description: "Show statistics" }
|
|
1501
|
+
],
|
|
1502
|
+
loader: async () => {
|
|
1503
|
+
const { handleEvolutionCommand } = await import('./chunks/evolution.mjs');
|
|
1504
|
+
return async (options, ...args) => {
|
|
1505
|
+
const action = args[0];
|
|
1506
|
+
const restArgs = args.slice(1);
|
|
1507
|
+
await handleEvolutionCommand(action, restArgs, options);
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
name: "daemon",
|
|
1513
|
+
description: "Daemon management",
|
|
1514
|
+
tier: "core",
|
|
1515
|
+
options: [
|
|
1516
|
+
{ flags: "start", description: "Start daemon" },
|
|
1517
|
+
{ flags: "stop", description: "Stop daemon" },
|
|
1518
|
+
{ flags: "status", description: "Daemon status" }
|
|
1519
|
+
],
|
|
1520
|
+
loader: async () => {
|
|
1521
|
+
const { startDaemon, stopDaemon, remoteStatus } = await import('./chunks/remote.mjs');
|
|
1522
|
+
return async (options, ...args) => {
|
|
1523
|
+
const action = args[0];
|
|
1524
|
+
switch (action) {
|
|
1525
|
+
case "start":
|
|
1526
|
+
await startDaemon();
|
|
1527
|
+
break;
|
|
1528
|
+
case "stop":
|
|
1529
|
+
await stopDaemon();
|
|
1530
|
+
break;
|
|
1531
|
+
case "status":
|
|
1532
|
+
await remoteStatus();
|
|
1533
|
+
break;
|
|
1534
|
+
default:
|
|
1535
|
+
await remoteStatus();
|
|
1536
|
+
}
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
},
|
|
1459
1540
|
{
|
|
1460
1541
|
name: "morning",
|
|
1461
1542
|
description: "Morning health check + stats summary",
|
|
@@ -1918,6 +1999,11 @@ async function runLazyCli() {
|
|
|
1918
1999
|
} catch {
|
|
1919
2000
|
}
|
|
1920
2001
|
bootstrapCloudServices();
|
|
2002
|
+
try {
|
|
2003
|
+
const { autoInitBrainHooks } = await import('./chunks/auto-init.mjs');
|
|
2004
|
+
await autoInitBrainHooks();
|
|
2005
|
+
} catch {
|
|
2006
|
+
}
|
|
1921
2007
|
const handled = await tryQuickProviderLaunch();
|
|
1922
2008
|
if (handled) {
|
|
1923
2009
|
spinner?.stop();
|