@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 +221 -54
- package/package.json +1 -1
- package/templates/CLAUDE.template.md +1 -6
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
|
-
|
|
262
|
-
console.log(chalk.
|
|
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
|
|
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
|
|
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
|
|
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: '
|
|
288
|
-
name: '
|
|
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.,
|
|
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(/{{
|
|
406
|
-
template = template.replace(/{{
|
|
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
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
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
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
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
|
-
|
|
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
|
@@ -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
|
-
|
|
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}}
|