@yancyyu/openhermit 1.6.17 → 1.6.18

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 +27 -49
  2. 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 bootstrapProjectName = 'default';
100
- const legacyBootstrapProjectName = '__openhermit_bootstrap__';
99
+ const bootstrapProjectNames = new Set(['default', '__openhermit_bootstrap__']);
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,16 +384,26 @@ function isManagedBootstrapBlock(block) {
415
384
  );
416
385
  }
417
386
 
418
- function migrateManagedBootstrapProject(raw) {
419
- const legacyBlock = findProjectBlock(raw, legacyBootstrapProjectName);
420
- if (!legacyBlock || !isManagedBootstrapBlock(legacyBlock.match[0])) return raw;
421
-
422
- const withoutLegacy = raw.replace(legacyBlock.pattern, '').replace(/\n{3,}/g, '\n\n').trimEnd();
423
- if (findProjectBlock(withoutLegacy, bootstrapProjectName)) {
424
- return `${withoutLegacy}\n`;
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
+ }
425
394
  }
395
+ return next;
396
+ }
426
397
 
427
- return `${withoutLegacy}\n${buildBootstrapProjectToml()}`;
398
+ function hasRealProjectEntries(raw) {
399
+ const projectPattern = /\[\[projects\]\]\nname\s*=\s*"([^"]+)"[\s\S]*?(?=\n\[\[projects\]\]|\s*$)/g;
400
+ for (const match of raw.matchAll(projectPattern)) {
401
+ const name = match[1];
402
+ if (!bootstrapProjectNames.has(name) || !isManagedBootstrapBlock(match[0])) {
403
+ return true;
404
+ }
405
+ }
406
+ return false;
428
407
  }
429
408
 
430
409
  function ensureCcConnectConfig() {
@@ -450,20 +429,15 @@ path = "/bridge/ws"
450
429
 
451
430
  [log]
452
431
  level = "info"
453
- ${buildBootstrapProjectToml()}`;
432
+ `;
454
433
  writeFileSync(ccConnectConfigPath, config, 'utf-8');
455
434
  }
456
435
 
457
436
  let raw = readFileSync(ccConnectConfigPath, 'utf-8');
458
- if (!hasProjectEntries(raw)) {
459
- raw = `${raw.trimEnd()}\n${buildBootstrapProjectToml()}`;
437
+ const migrated = stripManagedBootstrapProjects(raw);
438
+ if (migrated !== raw) {
439
+ raw = migrated;
460
440
  writeFileSync(ccConnectConfigPath, raw, 'utf-8');
461
- } else {
462
- const migrated = migrateManagedBootstrapProject(raw);
463
- if (migrated !== raw) {
464
- raw = migrated;
465
- writeFileSync(ccConnectConfigPath, raw, 'utf-8');
466
- }
467
441
  }
468
442
 
469
443
  return {
@@ -475,6 +449,7 @@ ${buildBootstrapProjectToml()}`;
475
449
  process.env.CC_CONNECT_BRIDGE_TOKEN ||
476
450
  process.env.CC_CONNECT_TOKEN ||
477
451
  parseTomlToken(raw, 'bridge'),
452
+ hasRealProjects: hasRealProjectEntries(raw),
478
453
  };
479
454
  }
480
455
 
@@ -568,6 +543,9 @@ if (!skipCcConnect) {
568
543
  const alreadyRunning = await waitForCcConnect(ccBaseUrl, ccTokens.managementToken, 1_000);
569
544
  if (alreadyRunning) {
570
545
  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.');
571
549
  } else {
572
550
  console.log('[openHermit] Starting bundled runtime service...');
573
551
  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.17",
4
+ "version": "1.6.18",
5
5
  "description": "openHermit: team-oriented agent management workbench atop cc-connect.",
6
6
  "license": "AGPL-3.0",
7
7
  "author": {