@yancyyu/openhermit 1.6.17 → 1.6.19
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 +65 -61
- package/package.json +1 -1
package/bin/hermit.mjs
CHANGED
|
@@ -96,8 +96,7 @@ const ccConnectConfigPath =
|
|
|
96
96
|
process.env.HERMIT_CC_CONNECT_CONFIG ||
|
|
97
97
|
process.env.CC_CONNECT_CONFIG ||
|
|
98
98
|
path.join(hermitHome, 'cc-connect', 'config.toml');
|
|
99
|
-
const
|
|
100
|
-
const legacyBootstrapProjectName = '__openhermit_bootstrap__';
|
|
99
|
+
const starterProjectName = 'my-project';
|
|
101
100
|
|
|
102
101
|
// ---------------------------------------------------------------------------
|
|
103
102
|
// Update command
|
|
@@ -364,36 +363,6 @@ function parseTomlToken(raw, section) {
|
|
|
364
363
|
return match?.[1] || '';
|
|
365
364
|
}
|
|
366
365
|
|
|
367
|
-
function hasProjectEntries(raw) {
|
|
368
|
-
return /^\s*\[\[projects\]\]/m.test(raw);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
function buildBootstrapProjectToml() {
|
|
372
|
-
return `
|
|
373
|
-
# Internal bootstrap project used only so cc-connect can start with an otherwise empty config.
|
|
374
|
-
# It is safe to keep this project; users can replace or delete it after creating real teams.
|
|
375
|
-
[[projects]]
|
|
376
|
-
name = "${bootstrapProjectName}"
|
|
377
|
-
disabled_commands = ["*"]
|
|
378
|
-
|
|
379
|
-
[projects.agent]
|
|
380
|
-
type = "claudecode"
|
|
381
|
-
|
|
382
|
-
[projects.agent.options]
|
|
383
|
-
work_dir = "${escapeTomlPath(hermitHome)}"
|
|
384
|
-
mode = "default"
|
|
385
|
-
|
|
386
|
-
[[projects.platforms]]
|
|
387
|
-
type = "line"
|
|
388
|
-
|
|
389
|
-
[projects.platforms.options]
|
|
390
|
-
channel_secret = "openhermit-bootstrap"
|
|
391
|
-
channel_token = "openhermit-bootstrap"
|
|
392
|
-
port = "0"
|
|
393
|
-
callback_path = "/openhermit-bootstrap"
|
|
394
|
-
`;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
366
|
function escapeRegExp(value) {
|
|
398
367
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
399
368
|
}
|
|
@@ -415,24 +384,11 @@ function isManagedBootstrapBlock(block) {
|
|
|
415
384
|
);
|
|
416
385
|
}
|
|
417
386
|
|
|
418
|
-
function
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const withoutLegacy = raw.replace(legacyBlock.pattern, '').replace(/\n{3,}/g, '\n\n').trimEnd();
|
|
423
|
-
if (findProjectBlock(withoutLegacy, bootstrapProjectName)) {
|
|
424
|
-
return `${withoutLegacy}\n`;
|
|
425
|
-
}
|
|
387
|
+
function buildStarterConfigToml(managementToken, bridgeToken) {
|
|
388
|
+
return `# cc-connect configuration
|
|
389
|
+
# Docs: https://github.com/chenhg5/cc-connect
|
|
426
390
|
|
|
427
|
-
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
function ensureCcConnectConfig() {
|
|
431
|
-
mkdirSync(path.dirname(ccConnectConfigPath), { recursive: true });
|
|
432
|
-
if (!existsSync(ccConnectConfigPath)) {
|
|
433
|
-
const managementToken = randomToken();
|
|
434
|
-
const bridgeToken = randomToken();
|
|
435
|
-
const config = `data_dir = "${escapeTomlPath(path.join(hermitHome, 'cc-connect', 'data'))}"
|
|
391
|
+
data_dir = "${escapeTomlPath(path.join(hermitHome, 'cc-connect', 'data'))}"
|
|
436
392
|
language = "zh"
|
|
437
393
|
|
|
438
394
|
[management]
|
|
@@ -450,21 +406,61 @@ path = "/bridge/ws"
|
|
|
450
406
|
|
|
451
407
|
[log]
|
|
452
408
|
level = "info"
|
|
453
|
-
${buildBootstrapProjectToml()}`;
|
|
454
|
-
writeFileSync(ccConnectConfigPath, config, 'utf-8');
|
|
455
|
-
}
|
|
456
409
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
410
|
+
[[projects]]
|
|
411
|
+
name = "my-project"
|
|
412
|
+
|
|
413
|
+
[projects.agent]
|
|
414
|
+
type = "claudecode" # "claudecode", "codex", "cursor", "gemini", "qoder", "opencode", or "iflow"
|
|
415
|
+
|
|
416
|
+
[projects.agent.options]
|
|
417
|
+
work_dir = "/path/to/your/project"
|
|
418
|
+
mode = "default"
|
|
419
|
+
# model = "claude-sonnet-4-20250514"
|
|
420
|
+
|
|
421
|
+
# --- Choose at least one platform below ---
|
|
422
|
+
|
|
423
|
+
[[projects.platforms]]
|
|
424
|
+
type = "feishu"
|
|
425
|
+
|
|
426
|
+
[projects.platforms.options]
|
|
427
|
+
app_id = "your-feishu-app-id"
|
|
428
|
+
app_secret = "your-feishu-app-secret"
|
|
429
|
+
`;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function isStarterProjectConfig(raw) {
|
|
433
|
+
const block = findProjectBlock(raw, starterProjectName);
|
|
434
|
+
if (!block) return false;
|
|
435
|
+
const text = block.match[0];
|
|
436
|
+
return (
|
|
437
|
+
text.includes('name = "my-project"') &&
|
|
438
|
+
text.includes('type = "claudecode"') &&
|
|
439
|
+
text.includes('work_dir = "/path/to/your/project"') &&
|
|
440
|
+
text.includes('app_id = "your-feishu-app-id"') &&
|
|
441
|
+
text.includes('app_secret = "your-feishu-app-secret"')
|
|
442
|
+
);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function hasRunnableProjectEntries(raw) {
|
|
446
|
+
const projectPattern = /\[\[projects\]\]\nname\s*=\s*"([^"]+)"[\s\S]*?(?=\n\[\[projects\]\]|\s*$)/g;
|
|
447
|
+
for (const match of raw.matchAll(projectPattern)) {
|
|
448
|
+
if (!isStarterProjectConfig(match[0]) && !isManagedBootstrapBlock(match[0])) {
|
|
449
|
+
return true;
|
|
466
450
|
}
|
|
467
451
|
}
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function ensureCcConnectConfig() {
|
|
456
|
+
mkdirSync(path.dirname(ccConnectConfigPath), { recursive: true });
|
|
457
|
+
if (!existsSync(ccConnectConfigPath)) {
|
|
458
|
+
const managementToken = randomToken();
|
|
459
|
+
const bridgeToken = randomToken();
|
|
460
|
+
writeFileSync(ccConnectConfigPath, buildStarterConfigToml(managementToken, bridgeToken), 'utf-8');
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const raw = readFileSync(ccConnectConfigPath, 'utf-8');
|
|
468
464
|
|
|
469
465
|
return {
|
|
470
466
|
managementToken:
|
|
@@ -475,6 +471,8 @@ ${buildBootstrapProjectToml()}`;
|
|
|
475
471
|
process.env.CC_CONNECT_BRIDGE_TOKEN ||
|
|
476
472
|
process.env.CC_CONNECT_TOKEN ||
|
|
477
473
|
parseTomlToken(raw, 'bridge'),
|
|
474
|
+
hasRunnableProjects: hasRunnableProjectEntries(raw),
|
|
475
|
+
isStarterConfig: isStarterProjectConfig(raw),
|
|
478
476
|
};
|
|
479
477
|
}
|
|
480
478
|
|
|
@@ -568,6 +566,12 @@ if (!skipCcConnect) {
|
|
|
568
566
|
const alreadyRunning = await waitForCcConnect(ccBaseUrl, ccTokens.managementToken, 1_000);
|
|
569
567
|
if (alreadyRunning) {
|
|
570
568
|
console.log(`[openHermit] Runtime service already running: ${ccBaseUrl}`);
|
|
569
|
+
} else if (!ccTokens.hasRunnableProjects) {
|
|
570
|
+
console.log('[openHermit] Runtime config is a starter template; starting control panel only.');
|
|
571
|
+
console.log(`[openHermit] Edit runtime config in the UI before starting the runtime service.`);
|
|
572
|
+
if (ccTokens.isStarterConfig) {
|
|
573
|
+
console.log(`[openHermit] Starter config: ${ccConnectConfigPath}`);
|
|
574
|
+
}
|
|
571
575
|
} else {
|
|
572
576
|
console.log('[openHermit] Starting bundled runtime service...');
|
|
573
577
|
console.log(`[openHermit] Runtime config: ${ccConnectConfigPath}`);
|