@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.
Files changed (2) hide show
  1. package/bin/hermit.mjs +69 -52
  2. 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 bootstrapProjectNames = new Set(['default', '__openhermit_bootstrap__']);
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 stripManagedBootstrapProjects(raw) {
388
- let next = raw;
389
- for (const name of bootstrapProjectNames) {
390
- const block = findProjectBlock(next, name);
391
- if (block && isManagedBootstrapBlock(block.match[0])) {
392
- next = next.replace(block.pattern, '').replace(/\n{3,}/g, '\n\n').trimEnd() + '\n';
393
- }
394
- }
395
- return next;
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 hasRealProjectEntries(raw) {
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
- const name = match[1];
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 ensureCcConnectConfig() {
405
+ function readCcConnectConfigState() {
410
406
  mkdirSync(path.dirname(ccConnectConfigPath), { recursive: true });
411
407
  if (!existsSync(ccConnectConfigPath)) {
412
- const managementToken = randomToken();
413
- const bridgeToken = randomToken();
414
- const config = `data_dir = "${escapeTomlPath(path.join(hermitHome, 'cc-connect', 'data'))}"
415
- language = "zh"
416
-
417
- [management]
418
- enabled = true
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
- let raw = readFileSync(ccConnectConfigPath, 'utf-8');
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
- hasRealProjects: hasRealProjectEntries(raw),
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 = ensureCcConnectConfig();
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.hasRealProjects) {
547
- console.log('[openHermit] No runtime projects configured; starting control panel only.');
548
- console.log('[openHermit] Create a team in the UI to install/configure a runtime.');
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}`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@yancyyu/openhermit",
3
3
  "type": "module",
4
- "version": "1.6.18",
4
+ "version": "1.6.20",
5
5
  "description": "openHermit: team-oriented agent management workbench atop cc-connect.",
6
6
  "license": "AGPL-3.0",
7
7
  "author": {