@jaguilar87/gaia-ops 1.1.0 β†’ 1.3.0

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/gaia-init.js CHANGED
@@ -258,48 +258,87 @@ function validateConfiguration(config, nonInteractive) {
258
258
  * Present interactive wizard to user
259
259
  */
260
260
  async function runInteractiveWizard(detected) {
261
- console.log(chalk.cyan.bold('\nπŸ€– Claude Code Agent System Installer\n'));
262
- console.log(chalk.gray('This wizard will set up the Claude Code agent system for your project.\n'));
261
+ // ASCII Art banner
262
+ console.log(chalk.cyan(`
263
+ ╔═══════════════════════════════════════════════════════════════╗
264
+ β•‘ β•‘
265
+ β•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β•‘
266
+ β•‘ β–ˆβ–ˆβ•”β•β•β•β•β• β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β• β•‘
267
+ β•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β•‘
268
+ β•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β•β• β•šβ•β•β•β•β–ˆβ–ˆβ•‘ β•‘
269
+ β•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘ β•‘
270
+ β•‘ β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•šβ•β•β•šβ•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•β•β•β•β• β•‘
271
+ β•‘ β•‘
272
+ β•‘ Multi-Agent DevOps Orchestration System β•‘
273
+ β•‘ Powered by Claude Code β•‘
274
+ β•‘ β•‘
275
+ β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
276
+ `));
277
+
278
+ console.log(chalk.gray('This wizard will set up the Gaia-Ops agent system for your project.\n'));
279
+
280
+ console.log(chalk.yellow('πŸ“ Directory Configuration'));
281
+ console.log(chalk.gray('Gaia-Ops agents need to know where your code lives:\n'));
282
+ console.log(chalk.gray(' β€’ GitOps: Kubernetes manifests that agents will monitor and deploy'));
283
+ console.log(chalk.gray(' β€’ Terraform: Infrastructure code that agents will plan and apply'));
284
+ console.log(chalk.gray(' β€’ App Services: Application code that agents will build and test\n'));
263
285
 
264
286
  const questions = [
265
287
  {
266
288
  type: 'text',
267
289
  name: 'gitops',
268
- message: 'πŸ“¦ GitOps directory (Flux/Kubernetes manifests):',
290
+ message: 'πŸ“¦ GitOps directory:',
269
291
  initial: detected.gitops || './gitops',
270
292
  validate: value => value.trim().length > 0
271
293
  },
272
294
  {
273
295
  type: 'text',
274
296
  name: 'terraform',
275
- message: 'πŸ”§ Terraform directory (infrastructure as code):',
297
+ message: 'πŸ”§ Terraform directory:',
276
298
  initial: detected.terraform || './terraform',
277
299
  validate: value => value.trim().length > 0
278
300
  },
279
301
  {
280
302
  type: 'text',
281
303
  name: 'appServices',
282
- message: 'πŸš€ App Services directory (application code):',
304
+ message: 'πŸš€ App Services directory:',
283
305
  initial: detected.appServices || './app-services',
284
306
  validate: value => value.trim().length > 0
285
307
  },
286
308
  {
287
- type: 'text',
288
- name: 'projectId',
309
+ type: 'select',
310
+ name: 'cloudProvider',
311
+ message: '☁️ Cloud provider:',
312
+ choices: [
313
+ { title: 'GCP (Google Cloud Platform)', value: 'gcp' },
314
+ { title: 'AWS (Amazon Web Services)', value: 'aws' },
315
+ { title: 'Multi-cloud (AWS + GCP)', value: 'multi-cloud' }
316
+ ],
317
+ initial: 0
318
+ },
319
+ {
320
+ type: (prev, values) => ['gcp', 'multi-cloud'].includes(values.cloudProvider) ? 'text' : null,
321
+ name: 'gcpProjectId',
289
322
  message: '🌐 GCP Project ID (e.g., aaxis-rnd-non-prod):',
290
323
  validate: value => value.trim().length > 0
291
324
  },
325
+ {
326
+ type: (prev, values) => ['aws', 'multi-cloud'].includes(values.cloudProvider) ? 'text' : null,
327
+ name: 'awsAccountId',
328
+ message: '🌐 AWS Account ID (e.g., 929914624686):',
329
+ validate: value => value.trim().length > 0
330
+ },
292
331
  {
293
332
  type: 'text',
294
333
  name: 'region',
295
- message: '🌍 Primary Region (e.g., us-central1):',
334
+ message: '🌍 Primary Region (e.g., us-central1 for GCP, us-east-1 for AWS):',
296
335
  initial: 'us-central1',
297
336
  validate: value => value.trim().length > 0
298
337
  },
299
338
  {
300
339
  type: 'text',
301
340
  name: 'clusterName',
302
- message: '☸️ Cluster Name (e.g., non-prod-rnd-gke):',
341
+ message: '☸️ Cluster Name (e.g., rnd-gke-nonprod or digital-eks-prod):',
303
342
  validate: value => value.trim().length > 0
304
343
  },
305
344
  {
@@ -307,6 +346,12 @@ async function runInteractiveWizard(detected) {
307
346
  name: 'installClaudeCode',
308
347
  message: 'πŸ“₯ Install Claude Code if not present?',
309
348
  initial: true
349
+ },
350
+ {
351
+ type: 'text',
352
+ name: 'projectContextRepo',
353
+ message: 'πŸ”— Project context Git repo (optional, e.g., git@bitbucket.org:org/context.git):',
354
+ initial: ''
310
355
  }
311
356
  ];
312
357
 
@@ -382,6 +427,7 @@ async function createClaudeDirectory() {
382
427
  // Create project-specific directories (NOT symlinked)
383
428
  await fs.mkdir(join(claudeDir, 'logs'), { recursive: true });
384
429
  await fs.mkdir(join(claudeDir, 'tests'), { recursive: true });
430
+ await fs.mkdir(join(claudeDir, 'project-context'), { recursive: true });
385
431
 
386
432
  spinner.succeed('.claude/ directory created with symlinks');
387
433
  } catch (error) {
@@ -401,10 +447,34 @@ async function generateClaudeMd(config) {
401
447
  const templatePath = getTemplatePath('CLAUDE.template.md');
402
448
  let template = await fs.readFile(templatePath, 'utf-8');
403
449
 
450
+ // Build project configuration section based on cloud provider
451
+ let projectConfig = '';
452
+
453
+ if (config.cloudProvider === 'gcp') {
454
+ projectConfig = `- **Cloud Provider:** GCP
455
+ - **GCP Project ID:** ${config.gcpProjectId}
456
+ - **Region:** ${config.region}
457
+ - **Cluster:** ${config.clusterName}`;
458
+ } else if (config.cloudProvider === 'aws') {
459
+ projectConfig = `- **Cloud Provider:** AWS
460
+ - **AWS Account ID:** ${config.awsAccountId}
461
+ - **Region:** ${config.region}
462
+ - **Cluster:** ${config.clusterName}`;
463
+ } else if (config.cloudProvider === 'multi-cloud') {
464
+ projectConfig = `- **Cloud Provider:** Multi-cloud (AWS + GCP)`;
465
+ if (config.gcpProjectId) {
466
+ projectConfig += `\n- **GCP Project ID:** ${config.gcpProjectId}`;
467
+ }
468
+ if (config.awsAccountId) {
469
+ projectConfig += `\n- **AWS Account ID:** ${config.awsAccountId}`;
470
+ }
471
+ projectConfig += `\n- **Primary Region:** ${config.region}
472
+ - **Cluster:** ${config.clusterName}`;
473
+ }
474
+
404
475
  // Replace placeholders
405
- template = template.replace(/{{PROJECT_ID}}/g, config.projectId);
406
- template = template.replace(/{{REGION}}/g, config.region);
407
- template = template.replace(/{{CLUSTER_NAME}}/g, config.clusterName);
476
+ template = template.replace(/{{TIMESTAMP}}/g, new Date().toISOString().split('T')[0]);
477
+ template = template.replace(/{{PROJECT_CONFIG}}/g, projectConfig);
408
478
  template = template.replace(/{{GITOPS_PATH}}/g, config.gitops);
409
479
  template = template.replace(/{{TERRAFORM_PATH}}/g, config.terraform);
410
480
  template = template.replace(/{{APP_SERVICES_PATH}}/g, config.appServices);
@@ -504,62 +574,100 @@ async function generateProjectContext(config) {
504
574
  const spinner = ora('Generating project-context.json...').start();
505
575
 
506
576
  try {
577
+ // Build metadata section based on cloud provider
578
+ const metadata = {
579
+ version: '1.0',
580
+ last_updated: new Date().toISOString(),
581
+ project_root: '.', // Reference point: where CLAUDE.md is located
582
+ created_by: 'gaia-init',
583
+ cloud_provider: config.cloudProvider,
584
+ environment: 'non-prod',
585
+ primary_region: config.region
586
+ };
587
+
588
+ // Add cloud-specific metadata
589
+ if (config.cloudProvider === 'gcp') {
590
+ metadata.project_id = config.gcpProjectId;
591
+ } else if (config.cloudProvider === 'aws') {
592
+ metadata.aws_account = config.awsAccountId;
593
+ } else if (config.cloudProvider === 'multi-cloud') {
594
+ if (config.gcpProjectId) metadata.project_id = config.gcpProjectId;
595
+ if (config.awsAccountId) metadata.aws_account = config.awsAccountId;
596
+ }
597
+
598
+ // Build project_details section
599
+ const projectDetails = {
600
+ region: config.region,
601
+ environment: 'non-prod',
602
+ cluster_name: config.clusterName,
603
+ cloud_provider: config.cloudProvider
604
+ };
605
+
606
+ if (config.gcpProjectId) {
607
+ projectDetails.project_id = config.gcpProjectId;
608
+ }
609
+ if (config.awsAccountId) {
610
+ projectDetails.aws_account = config.awsAccountId;
611
+ }
612
+
613
+ // Build provider_credentials section
614
+ const providerCredentials = {};
615
+ if (config.gcpProjectId) {
616
+ providerCredentials.gcp = {
617
+ project: config.gcpProjectId,
618
+ region: config.region
619
+ };
620
+ }
621
+ if (config.awsAccountId) {
622
+ providerCredentials.aws = {
623
+ account_id: config.awsAccountId,
624
+ region: config.region
625
+ };
626
+ }
627
+
507
628
  const projectContext = {
508
- metadata: {
509
- version: '1.0',
510
- last_updated: new Date().toISOString(),
511
- project_root: '.', // Reference point: where CLAUDE.md is located
512
- created_by: 'gaia-init'
513
- },
629
+ metadata,
514
630
  paths: {
515
631
  gitops: config.gitops,
516
632
  terraform: config.terraform,
517
633
  app_services: config.appServices
518
634
  },
519
- project_details: {
520
- id: config.projectId,
521
- region: config.region,
522
- environment: 'non-prod',
523
- cluster_name: config.clusterName
524
- },
525
- terraform_infrastructure: {
526
- layout: {
527
- base_path: config.terraform,
528
- module_structure: 'terragrunt'
635
+ sections: {
636
+ project_details: projectDetails,
637
+ terraform_infrastructure: {
638
+ layout: {
639
+ base_path: config.terraform,
640
+ module_structure: 'terragrunt'
641
+ },
642
+ provider_credentials: providerCredentials
529
643
  },
530
- provider_credentials: {
531
- gcp: {
532
- project: config.projectId,
533
- region: config.region
644
+ gitops_configuration: {
645
+ repository: {
646
+ path: config.gitops,
647
+ platform: 'flux'
648
+ },
649
+ flux_details: {
650
+ namespaces: []
534
651
  }
535
- }
536
- },
537
- gitops_configuration: {
538
- repository: {
539
- path: config.gitops,
540
- platform: 'flux'
541
652
  },
542
- flux_details: {
543
- namespaces: []
544
- }
545
- },
546
- application_services: {
547
- base_path: config.appServices,
548
- services: []
549
- },
550
- operational_guidelines: {
551
- commit_standards: {
552
- format: 'conventional_commits',
553
- validation_required: true,
554
- config_path: '.claude/config/git_standards.json'
653
+ application_services: {
654
+ base_path: config.appServices,
655
+ services: []
656
+ },
657
+ operational_guidelines: {
658
+ commit_standards: {
659
+ format: 'conventional_commits',
660
+ validation_required: true,
661
+ config_path: '.claude/config/git_standards.json'
662
+ }
555
663
  }
556
664
  }
557
665
  };
558
666
 
559
- const projectContextPath = join(CWD, '.claude', 'project-context.json');
667
+ const projectContextPath = join(CWD, '.claude', 'project-context', 'project-context.json');
560
668
  await fs.writeFile(projectContextPath, JSON.stringify(projectContext, null, 2), 'utf-8');
561
669
 
562
- spinner.succeed('project-context.json generated');
670
+ spinner.succeed('project-context/project-context.json generated');
563
671
  } catch (error) {
564
672
  spinner.fail('Failed to generate project-context.json');
565
673
  throw error;
@@ -598,6 +706,54 @@ async function installClaudeAgentsPackage() {
598
706
  }
599
707
  }
600
708
 
709
+ /**
710
+ * Clone project context repository (optional)
711
+ */
712
+ async function cloneProjectContextRepo(repoUrl) {
713
+ if (!repoUrl || repoUrl.trim() === '') {
714
+ console.log(chalk.gray('\nβœ“ Skipping project context repo clone (not provided)\n'));
715
+ return;
716
+ }
717
+
718
+ const spinner = ora('Cloning project context repository...').start();
719
+
720
+ try {
721
+ const projectContextDir = join(CWD, '.claude', 'project-context');
722
+
723
+ // Remove the generated project-context.json as it will be replaced by the cloned repo
724
+ const generatedFile = join(projectContextDir, 'project-context.json');
725
+ if (existsSync(generatedFile)) {
726
+ await fs.unlink(generatedFile);
727
+ }
728
+
729
+ // Clone repo directly into project-context directory
730
+ await execAsync(`git clone ${repoUrl} ${projectContextDir}-temp`);
731
+
732
+ // Move contents from temp to project-context
733
+ const tempDir = `${projectContextDir}-temp`;
734
+ const files = await fs.readdir(tempDir);
735
+ for (const file of files) {
736
+ const src = join(tempDir, file);
737
+ const dest = join(projectContextDir, file);
738
+ await fs.rename(src, dest);
739
+ }
740
+
741
+ // Remove temp directory
742
+ await fs.rmdir(tempDir);
743
+
744
+ spinner.succeed('Project context repository cloned');
745
+ console.log(chalk.green(` β†’ Cloned from: ${repoUrl}`));
746
+ console.log(chalk.gray(` β†’ Location: .claude/project-context/\n`));
747
+ } catch (error) {
748
+ spinner.fail('Failed to clone project context repository');
749
+ console.log(chalk.yellow(`\n⚠️ You can clone it manually later with:`));
750
+ console.log(chalk.gray(` cd .claude`));
751
+ console.log(chalk.gray(` rm -rf project-context`));
752
+ console.log(chalk.gray(` git clone ${repoUrl} project-context\n`));
753
+ // Don't throw - allow installation to continue
754
+ }
755
+ }
756
+
601
757
  // ============================================================================
602
758
  // Main installer flow
603
759
  // ============================================================================
@@ -666,11 +822,22 @@ async function main() {
666
822
  // Step 9: Generate project-context.json
667
823
  await generateProjectContext(config);
668
824
 
825
+ // Step 10: Clone project context repository (optional)
826
+ if (config.projectContextRepo) {
827
+ await cloneProjectContextRepo(config.projectContextRepo);
828
+ }
829
+
669
830
  // Success message
670
831
  console.log(chalk.green.bold('\nβœ… Installation complete!\n'));
671
832
  console.log(chalk.gray('Next steps:'));
672
833
  console.log(chalk.gray(' 1. Review CLAUDE.md and adjust paths if needed'));
673
- console.log(chalk.gray(' 2. Update .claude/project-context.json with your services'));
834
+ if (!config.projectContextRepo) {
835
+ console.log(chalk.gray(' 2. Update .claude/project-context/project-context.json with your services'));
836
+ console.log(chalk.gray(' OR clone your project context repo:'));
837
+ console.log(chalk.gray(' cd .claude && git clone <your-repo> project-context'));
838
+ } else {
839
+ console.log(chalk.gray(' 2. Your project context has been cloned to .claude/project-context/'));
840
+ }
674
841
  console.log(chalk.gray(' 3. Start Claude Code: claude-code\n'));
675
842
  console.log(chalk.cyan('πŸ“š Documentation: .claude/config/\n'));
676
843
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaguilar87/gaia-ops",
3
- "version": "1.1.0",
3
+ "version": "1.3.0",
4
4
  "description": "Multi-agent orchestration system for Claude Code - DevOps automation toolkit",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -4,9 +4,6 @@ last_updated: {{TIMESTAMP}}
4
4
  description: Orchestrator instructions for Claude Code agent system
5
5
  maintainer: jaguilar@aaxis.com
6
6
  changelog: .claude/CHANGELOG.md
7
- project_id: {{PROJECT_ID}}
8
- region: {{REGION}}
9
- cluster: {{CLUSTER_NAME}}
10
7
  ---
11
8
 
12
9
  # CLAUDE.md
@@ -142,9 +139,7 @@ Guidance for Claude Code orchestrator working in this repository.
142
139
  ## Project Configuration
143
140
 
144
141
  **This project:**
145
- - **GCP Project ID:** {{PROJECT_ID}}
146
- - **Region:** {{REGION}}
147
- - **Cluster:** {{CLUSTER_NAME}}
142
+ {{PROJECT_CONFIG}}
148
143
  - **GitOps Path:** {{GITOPS_PATH}}
149
144
  - **Terraform Path:** {{TERRAFORM_PATH}}
150
145
  - **App Services Path:** {{APP_SERVICES_PATH}}