@yancyyu/openhermit 1.6.18 → 1.6.20
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/bin/hermit.mjs +69 -52
- package/package.json +1 -1
package/bin/hermit.mjs
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import { spawn, execSync } from 'node:child_process';
|
|
18
|
-
import crypto from 'node:crypto';
|
|
19
18
|
import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
20
19
|
import { createRequire } from 'node:module';
|
|
21
20
|
import os from 'node:os';
|
|
@@ -96,7 +95,7 @@ const ccConnectConfigPath =
|
|
|
96
95
|
process.env.HERMIT_CC_CONNECT_CONFIG ||
|
|
97
96
|
process.env.CC_CONNECT_CONFIG ||
|
|
98
97
|
path.join(hermitHome, 'cc-connect', 'config.toml');
|
|
99
|
-
const
|
|
98
|
+
const starterProjectName = 'my-project';
|
|
100
99
|
|
|
101
100
|
// ---------------------------------------------------------------------------
|
|
102
101
|
// Update command
|
|
@@ -350,10 +349,6 @@ Please install dependencies first:
|
|
|
350
349
|
// cc-connect sidecar
|
|
351
350
|
// ---------------------------------------------------------------------------
|
|
352
351
|
|
|
353
|
-
function randomToken() {
|
|
354
|
-
return crypto.randomBytes(16).toString('hex');
|
|
355
|
-
}
|
|
356
|
-
|
|
357
352
|
function escapeTomlPath(value) {
|
|
358
353
|
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
359
354
|
}
|
|
@@ -384,63 +379,45 @@ function isManagedBootstrapBlock(block) {
|
|
|
384
379
|
);
|
|
385
380
|
}
|
|
386
381
|
|
|
387
|
-
function
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
382
|
+
function isStarterProjectConfig(raw) {
|
|
383
|
+
const block = findProjectBlock(raw, starterProjectName);
|
|
384
|
+
if (!block) return false;
|
|
385
|
+
const text = block.match[0];
|
|
386
|
+
return (
|
|
387
|
+
text.includes('name = "my-project"') &&
|
|
388
|
+
text.includes('type = "claudecode"') &&
|
|
389
|
+
text.includes('work_dir = "/path/to/your/project"') &&
|
|
390
|
+
text.includes('app_id = "your-feishu-app-id"') &&
|
|
391
|
+
text.includes('app_secret = "your-feishu-app-secret"')
|
|
392
|
+
);
|
|
396
393
|
}
|
|
397
394
|
|
|
398
|
-
function
|
|
395
|
+
function hasRunnableProjectEntries(raw) {
|
|
399
396
|
const projectPattern = /\[\[projects\]\]\nname\s*=\s*"([^"]+)"[\s\S]*?(?=\n\[\[projects\]\]|\s*$)/g;
|
|
400
397
|
for (const match of raw.matchAll(projectPattern)) {
|
|
401
|
-
|
|
402
|
-
if (!bootstrapProjectNames.has(name) || !isManagedBootstrapBlock(match[0])) {
|
|
398
|
+
if (!isStarterProjectConfig(match[0]) && !isManagedBootstrapBlock(match[0])) {
|
|
403
399
|
return true;
|
|
404
400
|
}
|
|
405
401
|
}
|
|
406
402
|
return false;
|
|
407
403
|
}
|
|
408
404
|
|
|
409
|
-
function
|
|
405
|
+
function readCcConnectConfigState() {
|
|
410
406
|
mkdirSync(path.dirname(ccConnectConfigPath), { recursive: true });
|
|
411
407
|
if (!existsSync(ccConnectConfigPath)) {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
host = "127.0.0.1"
|
|
420
|
-
port = 9820
|
|
421
|
-
token = "${managementToken}"
|
|
422
|
-
|
|
423
|
-
[bridge]
|
|
424
|
-
enabled = true
|
|
425
|
-
host = "127.0.0.1"
|
|
426
|
-
port = 9810
|
|
427
|
-
token = "${bridgeToken}"
|
|
428
|
-
path = "/bridge/ws"
|
|
429
|
-
|
|
430
|
-
[log]
|
|
431
|
-
level = "info"
|
|
432
|
-
`;
|
|
433
|
-
writeFileSync(ccConnectConfigPath, config, 'utf-8');
|
|
408
|
+
return {
|
|
409
|
+
configExists: false,
|
|
410
|
+
managementToken: process.env.CC_CONNECT_TOKEN || process.env.CC_CONNECT_MANAGEMENT_TOKEN || '',
|
|
411
|
+
bridgeToken: process.env.CC_CONNECT_BRIDGE_TOKEN || process.env.CC_CONNECT_TOKEN || '',
|
|
412
|
+
hasRunnableProjects: false,
|
|
413
|
+
isStarterConfig: false,
|
|
414
|
+
};
|
|
434
415
|
}
|
|
435
416
|
|
|
436
|
-
|
|
437
|
-
const migrated = stripManagedBootstrapProjects(raw);
|
|
438
|
-
if (migrated !== raw) {
|
|
439
|
-
raw = migrated;
|
|
440
|
-
writeFileSync(ccConnectConfigPath, raw, 'utf-8');
|
|
441
|
-
}
|
|
417
|
+
const raw = readFileSync(ccConnectConfigPath, 'utf-8');
|
|
442
418
|
|
|
443
419
|
return {
|
|
420
|
+
configExists: true,
|
|
444
421
|
managementToken:
|
|
445
422
|
process.env.CC_CONNECT_TOKEN ||
|
|
446
423
|
process.env.CC_CONNECT_MANAGEMENT_TOKEN ||
|
|
@@ -449,7 +426,8 @@ level = "info"
|
|
|
449
426
|
process.env.CC_CONNECT_BRIDGE_TOKEN ||
|
|
450
427
|
process.env.CC_CONNECT_TOKEN ||
|
|
451
428
|
parseTomlToken(raw, 'bridge'),
|
|
452
|
-
|
|
429
|
+
hasRunnableProjects: hasRunnableProjectEntries(raw),
|
|
430
|
+
isStarterConfig: isStarterProjectConfig(raw),
|
|
453
431
|
};
|
|
454
432
|
}
|
|
455
433
|
|
|
@@ -538,14 +516,53 @@ let ccTokens = {
|
|
|
538
516
|
};
|
|
539
517
|
|
|
540
518
|
if (!skipCcConnect) {
|
|
541
|
-
ccTokens =
|
|
519
|
+
ccTokens = readCcConnectConfigState();
|
|
542
520
|
const ccBaseUrl = process.env.CC_CONNECT_BASE_URL || 'http://127.0.0.1:9820';
|
|
543
521
|
const alreadyRunning = await waitForCcConnect(ccBaseUrl, ccTokens.managementToken, 1_000);
|
|
544
522
|
if (alreadyRunning) {
|
|
545
523
|
console.log(`[openHermit] Runtime service already running: ${ccBaseUrl}`);
|
|
546
|
-
} else if (!ccTokens.
|
|
547
|
-
console.log('[openHermit]
|
|
548
|
-
console.log(
|
|
524
|
+
} else if (!ccTokens.configExists) {
|
|
525
|
+
console.log('[openHermit] Initializing runtime config with bundled runtime service...');
|
|
526
|
+
console.log(`[openHermit] Runtime config: ${ccConnectConfigPath}`);
|
|
527
|
+
const initProcess = spawn(process.execPath, [resolveCcConnectRunner(), '-config', ccConnectConfigPath], {
|
|
528
|
+
cwd: repoRoot,
|
|
529
|
+
env: {
|
|
530
|
+
...process.env,
|
|
531
|
+
CC_CONNECT_TOKEN: ccTokens.managementToken,
|
|
532
|
+
CC_CONNECT_MANAGEMENT_TOKEN: ccTokens.managementToken,
|
|
533
|
+
CC_CONNECT_BRIDGE_TOKEN: ccTokens.bridgeToken,
|
|
534
|
+
},
|
|
535
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
536
|
+
});
|
|
537
|
+
initProcess.stdout?.on('data', (chunk) => {
|
|
538
|
+
process.stdout.write(chunk);
|
|
539
|
+
appendLog(runtimeLogPath, chunk);
|
|
540
|
+
});
|
|
541
|
+
initProcess.stderr?.on('data', (chunk) => {
|
|
542
|
+
process.stderr.write(chunk);
|
|
543
|
+
appendLog(runtimeLogPath, chunk);
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
const initCode = await new Promise((resolve) => {
|
|
547
|
+
initProcess.on('exit', (code) => resolve(code ?? 1));
|
|
548
|
+
initProcess.on('error', () => resolve(1));
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
ccTokens = readCcConnectConfigState();
|
|
552
|
+
if (initCode === 0 && ccTokens.configExists) {
|
|
553
|
+
console.log('[openHermit] Runtime starter config created.');
|
|
554
|
+
console.log('[openHermit] Open the panel to finish setup before starting the runtime service.');
|
|
555
|
+
} else {
|
|
556
|
+
console.error(`[openHermit] Runtime config initialization failed (code ${initCode}).`);
|
|
557
|
+
printLogTail('Runtime', runtimeLogPath);
|
|
558
|
+
process.exit(1);
|
|
559
|
+
}
|
|
560
|
+
} else if (!ccTokens.hasRunnableProjects) {
|
|
561
|
+
console.log('[openHermit] Runtime config is a starter template; starting control panel only.');
|
|
562
|
+
console.log(`[openHermit] Edit runtime config in the UI before starting the runtime service.`);
|
|
563
|
+
if (ccTokens.isStarterConfig) {
|
|
564
|
+
console.log(`[openHermit] Starter config: ${ccConnectConfigPath}`);
|
|
565
|
+
}
|
|
549
566
|
} else {
|
|
550
567
|
console.log('[openHermit] Starting bundled runtime service...');
|
|
551
568
|
console.log(`[openHermit] Runtime config: ${ccConnectConfigPath}`);
|