toga-ai 1.0.4 → 1.0.5

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/package.json +1 -1
  2. package/scripts/install.js +27 -29
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",
@@ -462,17 +462,17 @@ function main() {
462
462
  console.log('toga-ai — TOGA Technology Claude harness');
463
463
  console.log('═════════════════════════════════════════════');
464
464
 
465
- // Step 1: npm bundle is always the baseline source
466
- let sourceDir = PACKAGE_ROOT;
467
- let sourceLabel = 'npm bundle v' + bundleVersion;
465
+ // Harness components (skills/agents/rules/hooks) ALWAYS come from the npm bundle.
466
+ // The git repo is ONLY used to pull newer knowledge docs on top — it never
467
+ // replaces harness components, so a stale local clone can't break the install.
468
+ const harnessDir = PACKAGE_ROOT;
469
+ let knowledgeDir = PACKAGE_ROOT; // overridden below if git repo found
468
470
  let gitUpdateLine = null;
469
471
 
470
- // Step 2: find or try to clone git repo for updates
471
472
  if (repoFlag) {
472
473
  const resolved = path.resolve(repoFlag);
473
474
  if (isValidClone(resolved)) {
474
- sourceDir = resolved;
475
- sourceLabel = 'git repo (--repo flag)';
475
+ knowledgeDir = resolved;
476
476
  } else {
477
477
  console.error(' ERROR: --repo path is not a valid clone: ' + resolved);
478
478
  process.exit(1);
@@ -481,40 +481,37 @@ function main() {
481
481
  let repoDir = findExistingClone();
482
482
 
483
483
  if (!repoDir && !isPostInstall) {
484
- // Try to clone silently — no error if it fails
485
484
  repoDir = tryCloneRepo(path.join(os.homedir(), 'toga-tech'));
486
485
  }
487
486
 
488
487
  if (repoDir) {
489
- // Pull latest — silent on failure, just use bundle
490
488
  const pullResult = tryGitPull(repoDir);
491
489
  saveRepoPathCache(repoDir);
492
490
 
493
491
  if (pullResult.pulled) {
494
- sourceDir = repoDir;
495
- sourceLabel = 'npm bundle v' + bundleVersion;
492
+ knowledgeDir = repoDir;
496
493
  if (pullResult.newDocs > 0) {
497
494
  gitUpdateLine = 'git update: pulled ' + pullResult.newDocs + ' new knowledge doc' + (pullResult.newDocs !== 1 ? 's' : '') + ' from TOGATechnology/claude';
498
- } else {
495
+ } else if (pullResult.message !== 'already up to date') {
499
496
  gitUpdateLine = 'git update: ' + pullResult.message;
500
497
  }
501
498
  } else if (isValidClone(repoDir)) {
502
- // Pull failed but repo exists — still use it as source
503
- sourceDir = repoDir;
504
- sourceLabel = 'git repo (offline, using cached)';
499
+ // Pull failed but repo exists — use cached knowledge only
500
+ knowledgeDir = repoDir;
505
501
  }
506
- // else: pull failed and can't use repo — silently stick with bundle
507
502
  }
508
- // No git access at all — silently use bundle
509
503
  }
510
504
 
511
- console.log(' Source: ' + sourceLabel);
512
- if (gitUpdateLine) {
505
+ console.log(' Harness: npm bundle v' + bundleVersion);
506
+ if (knowledgeDir !== PACKAGE_ROOT) {
507
+ console.log(' Knowledge: git repo' + (gitUpdateLine ? ' (' + gitUpdateLine.replace('git update: ', '') + ')' : ' (cached)'));
508
+ }
509
+ if (gitUpdateLine && knowledgeDir === PACKAGE_ROOT) {
513
510
  console.log(' ↳ ' + gitUpdateLine);
514
511
  }
515
512
  console.log('');
516
513
 
517
- if (isPostInstall && sourceDir === PACKAGE_ROOT && !repoFlag) {
514
+ if (isPostInstall && !repoFlag) {
518
515
  console.log(' First-time setup: run `toga-ai` from your project to');
519
516
  console.log(' install the harness into your .claude/ directory.');
520
517
  console.log('');
@@ -535,7 +532,7 @@ function main() {
535
532
  const errors = [];
536
533
 
537
534
  // Skills
538
- const skillsSrc = path.join(sourceDir, 'skills');
535
+ const skillsSrc = path.join(harnessDir, 'skills');
539
536
  const skillsDest = path.join(claudeDir, 'skills');
540
537
  fs.mkdirSync(skillsDest, { recursive: true });
541
538
  const skillNames = fs.existsSync(skillsSrc)
@@ -552,7 +549,7 @@ function main() {
552
549
  console.log(' ✓ Skills (' + skillNames.length + '): ' + fmtStats(skillStats));
553
550
 
554
551
  // Rules — update if content changed (team standards should always be current)
555
- const rulesSrc = path.join(sourceDir, 'rules');
552
+ const rulesSrc = path.join(harnessDir, 'rules');
556
553
  const rulesDest = path.join(claudeDir, 'rules', 'toga');
557
554
  let rulesStats = { added: 0, updated: 0, unchanged: 0 };
558
555
  if (fs.existsSync(rulesSrc)) {
@@ -562,7 +559,7 @@ function main() {
562
559
  console.log(' ✓ Rules (' + countMd(rulesDest) + '): ' + fmtStats(rulesStats));
563
560
 
564
561
  // Agents — update if content changed
565
- const agentsSrc = path.join(sourceDir, 'agents');
562
+ const agentsSrc = path.join(harnessDir, 'agents');
566
563
  const agentsDest = path.join(claudeDir, 'agents', 'toga');
567
564
  let agentsStats = { added: 0, updated: 0, unchanged: 0 };
568
565
  if (fs.existsSync(agentsSrc)) {
@@ -573,7 +570,7 @@ function main() {
573
570
  console.log(' ✓ Agents (' + agentsCount + '): ' + fmtStats(agentsStats));
574
571
 
575
572
  // Hook scripts — always overwrite so paths stay up to date
576
- const hooksSrc = path.join(sourceDir, 'scripts', 'hooks');
573
+ const hooksSrc = path.join(harnessDir, 'scripts', 'hooks');
577
574
  const hooksDest = path.join(claudeDir, 'hooks', 'toga');
578
575
  let hooksCount = 0;
579
576
  if (fs.existsSync(hooksSrc)) {
@@ -584,18 +581,18 @@ function main() {
584
581
  }
585
582
 
586
583
  // knowledge.js CLI — always overwrite so it stays current
587
- const knowledgeJsSrc = path.join(sourceDir, 'knowledge.js');
584
+ const knowledgeJsSrc = path.join(harnessDir, 'knowledge.js');
588
585
  if (fs.existsSync(knowledgeJsSrc)) {
589
586
  try { fs.copyFileSync(knowledgeJsSrc, path.join(claudeDir, 'knowledge.js')); }
590
587
  catch (e) { errors.push('knowledge.js: ' + e.message); }
591
588
  }
592
589
 
593
590
  // Settings — merge (additive only, never removes existing hooks or permissions)
594
- const ok = mergeSettings(claudeDir, sourceDir);
591
+ const ok = mergeSettings(claudeDir, harnessDir);
595
592
  console.log(' ' + (ok ? '✓' : '✗') + ' Hooks (' + hooksCount + ' scripts in .claude/hooks/toga/, settings.json merged)');
596
593
 
597
594
  // MCP example — skip if already present
598
- const mcpSrc = path.join(sourceDir, 'mcp-configs', 'mcp-servers.json');
595
+ const mcpSrc = path.join(harnessDir, 'mcp-configs', 'mcp-servers.json');
599
596
  const mcpDest = path.join(claudeDir, 'mcp-servers.example.json');
600
597
  if (fs.existsSync(mcpSrc) && !fs.existsSync(mcpDest)) {
601
598
  try { fs.copyFileSync(mcpSrc, mcpDest); }
@@ -603,8 +600,9 @@ function main() {
603
600
  console.log(' ✓ MCP (.claude/mcp-servers.example.json — merge into .mcp.json to enable)');
604
601
  }
605
602
 
606
- // Knowledge — skipExisting: user-grown docs are never overwritten by the bundle
607
- const knowledgeSrc = path.join(sourceDir, 'knowledge');
603
+ // Knowledge — git repo if available (has team-captured docs), else npm bundle
604
+ // skipExisting: user-grown docs are never overwritten
605
+ const knowledgeSrc = path.join(knowledgeDir, 'knowledge');
608
606
  const knowledgeDest = path.join(claudeDir, 'knowledge');
609
607
  let knowledgeStats = { added: 0, updated: 0, unchanged: 0 };
610
608
  if (fs.existsSync(knowledgeSrc)) {
@@ -614,7 +612,7 @@ function main() {
614
612
  console.log(' ✓ Knowledge (' + countMd(knowledgeDest) + ' docs): ' + fmtStats(knowledgeStats));
615
613
 
616
614
  // CLAUDE.md
617
- const action = updateClaudeMd(projectRoot, skillNames, sourceDir, sourceLabel);
615
+ const action = updateClaudeMd(projectRoot, skillNames, harnessDir, 'npm bundle v' + bundleVersion);
618
616
  console.log(' ✓ CLAUDE.md ' + action);
619
617
 
620
618
  // ECC global integration — detect and report