@jaguilar87/gaia-ops 1.3.3 β†’ 1.3.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.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,56 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [1.3.5] - 2025-11-10
11
+
12
+ ### Added
13
+ - **Smart Installer Flow:** Project context repo now asked FIRST, with auto-population of all config
14
+ - **Input Sanitization:** Handles "git clone <url>" pastes automatically (extracts just URL)
15
+ - **Auto-Configuration:** Parses project-context.json and pre-fills all wizard questions
16
+ - **Better Error Messages:** Clear troubleshooting tips for git clone failures (SSH keys, access, URL)
17
+
18
+ ### Changed
19
+ - **Wizard Question Order:** Project context moved from last to first question
20
+ - **User Experience:** Reduced manual input when project context exists
21
+ - **Clone Strategy:** Validates project context early, then sets up in final location
22
+ - **Error Handling:** Installation continues even if project context clone fails
23
+
24
+ ### Improved
25
+ - Eliminates typos and configuration errors by pre-filling from existing context
26
+ - Saves time for users with existing project-context repos
27
+ - Better guidance when git operations fail
28
+
29
+ ---
30
+
31
+ ## [1.3.4] - 2025-11-10
32
+
33
+ ### Fixed
34
+ - **Installer:** Removed incorrect AGENTS.md symlink creation in project root during installation
35
+ - **Documentation:** AGENTS.md now only accessible via `.claude/config/AGENTS.md` as intended
36
+ - **Package Quality:** Excluded Python cache files (`__pycache__/`) from published package
37
+
38
+ ### Changed
39
+ - **README.md:** Updated project structure documentation to reflect correct AGENTS.md location
40
+ - **README.en.md:** Updated project structure and corrected package references
41
+ - **Package Size:** Reduced from 911.7 kB (93 files) to 660.7 kB (77 files) - 27% reduction
42
+
43
+ ### Added
44
+ - **Package Metadata:** Added `homepage` and `bugs` fields to package.json for better npm discovery
45
+ - **Badges:** Added npm version, license, and Node.js version badges to README files
46
+ - **CI/CD:** Created GitHub Actions workflow for automated npm publishing
47
+ - **.npmignore:** Added file to exclude development artifacts from package
48
+ - **Cleanup Script:** Added `npm run clean` to remove Python cache files automatically
49
+ - **Pre-publish Hook:** Added `prepublishOnly` script for automatic cleanup before publishing
50
+
51
+ ### Package Quality Improvements
52
+ - Better npm package metadata for discoverability
53
+ - Professional badges in documentation
54
+ - Automated publishing workflow
55
+ - Cleaner package distribution (no cache files)
56
+ - Improved documentation consistency
57
+
58
+ ---
59
+
10
60
  ## [2.1.0] - 2025-11-07
11
61
 
12
62
  ### Changed
package/README.en.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @jaguilar87/gaia-ops
2
2
 
3
+ [![npm version](https://badge.fury.io/js/@jaguilar87%2Fgaia-ops.svg)](https://www.npmjs.com/package/@jaguilar87/gaia-ops)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js Version](https://img.shields.io/node/v/@jaguilar87/gaia-ops.svg)](https://nodejs.org)
6
+
3
7
  **[πŸ‡ͺπŸ‡Έ VersiΓ³n en espaΓ±ol](README.md)**
4
8
 
5
9
  Multi-agent orchestration system for Claude Code - DevOps automation toolkit.
@@ -127,26 +131,24 @@ After installation:
127
131
 
128
132
  ```
129
133
  your-project/
130
- β”œβ”€β”€ .claude/ # Symlinked to node_modules/@aaxis/claude-agents/
131
- β”‚ β”œβ”€β”€ agents/ β†’ node_modules/@aaxis/claude-agents/agents/
132
- β”‚ β”œβ”€β”€ tools/ β†’ node_modules/@aaxis/claude-agents/tools/
133
- β”‚ β”œβ”€β”€ hooks/ β†’ node_modules/@aaxis/claude-agents/hooks/
134
- β”‚ β”œβ”€β”€ commands/ β†’ node_modules/@aaxis/claude-agents/commands/
135
- β”‚ β”œβ”€β”€ docs/ β†’ node_modules/@aaxis/claude-agents/docs/
136
- β”‚ β”œβ”€β”€ templates/ β†’ node_modules/@aaxis/claude-agents/templates/
137
- β”‚ β”œβ”€β”€ config/ β†’ node_modules/@aaxis/claude-agents/config/
138
- β”‚ β”œβ”€β”€ CHANGELOG.md β†’ node_modules/@aaxis/claude-agents/CHANGELOG.md
134
+ β”œβ”€β”€ .claude/ # Symlinked to node_modules/@jaguilar87/gaia-ops/
135
+ β”‚ β”œβ”€β”€ agents/ β†’ node_modules/@jaguilar87/gaia-ops/agents/
136
+ β”‚ β”œβ”€β”€ tools/ β†’ node_modules/@jaguilar87/gaia-ops/tools/
137
+ β”‚ β”œβ”€β”€ hooks/ β†’ node_modules/@jaguilar87/gaia-ops/hooks/
138
+ β”‚ β”œβ”€β”€ commands/ β†’ node_modules/@jaguilar87/gaia-ops/commands/
139
+ β”‚ β”œβ”€β”€ config/ β†’ node_modules/@jaguilar87/gaia-ops/config/
140
+ β”‚ β”œβ”€β”€ templates/ β†’ node_modules/@jaguilar87/gaia-ops/templates/
141
+ β”‚ β”œβ”€β”€ CHANGELOG.md β†’ node_modules/@jaguilar87/gaia-ops/CHANGELOG.md
139
142
  β”‚ β”œβ”€β”€ logs/ # Project-specific (NOT symlinked)
140
143
  β”‚ β”œβ”€β”€ tests/ # Project-specific (NOT symlinked)
141
144
  β”‚ └── project-context.json # Project-specific (NOT symlinked)
142
145
  β”œβ”€β”€ CLAUDE.md # Generated from template
143
- β”œβ”€β”€ AGENTS.md β†’ node_modules/@aaxis/claude-agents/AGENTS.md
144
146
  β”œβ”€β”€ gitops/ # Your GitOps manifests
145
147
  β”œβ”€β”€ terraform/ # Your Terraform code
146
148
  β”œβ”€β”€ app-services/ # Your application code
147
149
  β”œβ”€β”€ node_modules/
148
- β”‚ └── @aaxis/
149
- β”‚ └── claude-agents/ # This package
150
+ β”‚ └── @jaguilar87/
151
+ β”‚ └── gaia-ops/ # This package
150
152
  └── package.json
151
153
  ```
152
154
 
package/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @jaguilar87/gaia-ops
2
2
 
3
+ [![npm version](https://badge.fury.io/js/@jaguilar87%2Fgaia-ops.svg)](https://www.npmjs.com/package/@jaguilar87/gaia-ops)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+ [![Node.js Version](https://img.shields.io/node/v/@jaguilar87/gaia-ops.svg)](https://nodejs.org)
6
+
3
7
  **[πŸ‡ΊπŸ‡Έ English version](README.en.md)**
4
8
 
5
9
  Sistema de orquestaciΓ³n multi-agente para Claude Code - Toolkit de automatizaciΓ³n DevOps.
@@ -139,7 +143,6 @@ tu-proyecto/
139
143
  β”‚ β”œβ”€β”€ tests/ # EspecΓ­fico del proyecto (NO symlink)
140
144
  β”‚ └── project-context.json # EspecΓ­fico del proyecto (NO symlink)
141
145
  β”œβ”€β”€ CLAUDE.md # Generado desde template
142
- β”œβ”€β”€ AGENTS.md β†’ node_modules/@jaguilar87/gaia-ops/AGENTS.md
143
146
  β”œβ”€β”€ gitops/ # Tus manifiestos GitOps
144
147
  β”œβ”€β”€ terraform/ # Tu cΓ³digo Terraform
145
148
  β”œβ”€β”€ app-services/ # Tu cΓ³digo de aplicaciΓ³n
package/bin/gaia-init.js CHANGED
@@ -254,6 +254,81 @@ function validateConfiguration(config, nonInteractive) {
254
254
  // Interactive prompts
255
255
  // ============================================================================
256
256
 
257
+ /**
258
+ * Sanitize git repo URL input
259
+ * Handles cases where user pastes "git clone <url>" instead of just "<url>"
260
+ */
261
+ function sanitizeGitUrl(input) {
262
+ if (!input || typeof input !== 'string') return '';
263
+
264
+ // Trim whitespace
265
+ let sanitized = input.trim();
266
+
267
+ // Remove "git clone" prefix if present
268
+ if (sanitized.toLowerCase().startsWith('git clone ')) {
269
+ sanitized = sanitized.substring('git clone '.length).trim();
270
+ }
271
+
272
+ // Remove quotes if present
273
+ sanitized = sanitized.replace(/^["']|["']$/g, '');
274
+
275
+ return sanitized;
276
+ }
277
+
278
+ /**
279
+ * Try to clone project context repo early and parse config
280
+ * Returns parsed config or null if clone fails
281
+ */
282
+ async function tryCloneProjectContext(repoUrl) {
283
+ if (!repoUrl || repoUrl.trim() === '') {
284
+ return null;
285
+ }
286
+
287
+ const sanitizedUrl = sanitizeGitUrl(repoUrl);
288
+
289
+ const spinner = ora('Cloning project context repository...').start();
290
+
291
+ try {
292
+ const tempDir = join(CWD, '.claude-temp-context');
293
+
294
+ // Remove temp dir if exists
295
+ if (existsSync(tempDir)) {
296
+ await fs.rm(tempDir, { recursive: true, force: true });
297
+ }
298
+
299
+ // Clone to temp directory
300
+ await execAsync(`git clone ${sanitizedUrl} ${tempDir}`, { timeout: 30000 });
301
+
302
+ // Try to read project-context.json
303
+ const contextPath = join(tempDir, 'project-context.json');
304
+
305
+ if (existsSync(contextPath)) {
306
+ const contextData = JSON.parse(await fs.readFile(contextPath, 'utf-8'));
307
+
308
+ // Clean up temp dir
309
+ await fs.rm(tempDir, { recursive: true, force: true });
310
+
311
+ spinner.succeed('Project context loaded successfully');
312
+ console.log(chalk.green(' βœ“ Auto-populated configuration from project context\n'));
313
+
314
+ return {
315
+ contextData,
316
+ repoUrl: sanitizedUrl
317
+ };
318
+ } else {
319
+ // No project-context.json found
320
+ await fs.rm(tempDir, { recursive: true, force: true });
321
+ spinner.warn('Repository cloned but no project-context.json found');
322
+ return null;
323
+ }
324
+ } catch (error) {
325
+ spinner.fail('Failed to clone project context repository');
326
+ console.log(chalk.yellow(`\n⚠️ Error: ${error.message}`));
327
+ console.log(chalk.gray(' Continuing with manual configuration...\n'));
328
+ return null;
329
+ }
330
+ }
331
+
257
332
  /**
258
333
  * Present interactive wizard to user
259
334
  */
@@ -276,32 +351,79 @@ async function runInteractiveWizard(detected) {
276
351
 
277
352
  console.log(chalk.gray('This wizard will set up the Gaia-Ops agent system for your project.\n'));
278
353
 
279
- console.log(chalk.yellow('πŸ“ Directory Configuration'));
280
- console.log(chalk.gray('Gaia-Ops agents need to know where your code lives:\n'));
281
- console.log(chalk.gray(' β€’ GitOps: Kubernetes manifests that agents will monitor and deploy'));
282
- console.log(chalk.gray(' β€’ Terraform: Infrastructure code that agents will plan and apply'));
283
- console.log(chalk.gray(' β€’ App Services: Application code that agents will build and test\n'));
354
+ // =========================================================================
355
+ // STEP 1: Ask for project context repo first (if available)
356
+ // =========================================================================
357
+ console.log(chalk.yellow('πŸ”— Project Context (Optional but Recommended)'));
358
+ console.log(chalk.gray('If you have a project context repo, we can auto-populate your configuration.\n'));
359
+
360
+ const contextQuestion = await prompts({
361
+ type: 'text',
362
+ name: 'projectContextRepo',
363
+ message: 'πŸ“¦ Project context Git repo (e.g., git@bitbucket.org:org/context.git):',
364
+ initial: ''
365
+ }, {
366
+ onCancel: () => {
367
+ console.log(chalk.yellow('\n⚠️ Installation cancelled by user\n'));
368
+ process.exit(0);
369
+ }
370
+ });
371
+
372
+ // Try to clone and parse project context
373
+ let projectContext = null;
374
+ if (contextQuestion.projectContextRepo) {
375
+ projectContext = await tryCloneProjectContext(contextQuestion.projectContextRepo);
376
+ }
377
+
378
+ // Extract defaults from project context if available
379
+ const defaults = projectContext ? {
380
+ gitops: projectContext.contextData.paths?.gitops || detected.gitops || './gitops',
381
+ terraform: projectContext.contextData.paths?.terraform || detected.terraform || './terraform',
382
+ appServices: projectContext.contextData.paths?.app_services || detected.appServices || './app-services',
383
+ cloudProvider: projectContext.contextData.sections?.project_details?.cloud_provider || 'gcp',
384
+ gcpProjectId: projectContext.contextData.sections?.project_details?.project_id || projectContext.contextData.metadata?.project_id || '',
385
+ awsAccountId: projectContext.contextData.sections?.project_details?.aws_account || projectContext.contextData.metadata?.aws_account || '',
386
+ region: projectContext.contextData.sections?.project_details?.region || projectContext.contextData.metadata?.primary_region || 'us-central1',
387
+ clusterName: projectContext.contextData.sections?.project_details?.cluster_name || '',
388
+ repoUrl: projectContext?.repoUrl || contextQuestion.projectContextRepo
389
+ } : {
390
+ gitops: detected.gitops || './gitops',
391
+ terraform: detected.terraform || './terraform',
392
+ appServices: detected.appServices || './app-services',
393
+ cloudProvider: 'gcp',
394
+ gcpProjectId: '',
395
+ awsAccountId: '',
396
+ region: 'us-central1',
397
+ clusterName: '',
398
+ repoUrl: contextQuestion.projectContextRepo
399
+ };
400
+
401
+ // =========================================================================
402
+ // STEP 2: Ask remaining questions (with smart defaults from context)
403
+ // =========================================================================
404
+ console.log(chalk.yellow('\nπŸ“ Directory Configuration'));
405
+ console.log(chalk.gray('Verify or adjust the following paths:\n'));
284
406
 
285
407
  const questions = [
286
408
  {
287
409
  type: 'text',
288
410
  name: 'gitops',
289
411
  message: 'πŸ“¦ GitOps directory:',
290
- initial: detected.gitops || './gitops',
412
+ initial: defaults.gitops,
291
413
  validate: value => value.trim().length > 0
292
414
  },
293
415
  {
294
416
  type: 'text',
295
417
  name: 'terraform',
296
418
  message: 'πŸ”§ Terraform directory:',
297
- initial: detected.terraform || './terraform',
419
+ initial: defaults.terraform,
298
420
  validate: value => value.trim().length > 0
299
421
  },
300
422
  {
301
423
  type: 'text',
302
424
  name: 'appServices',
303
425
  message: 'πŸš€ App Services directory:',
304
- initial: detected.appServices || './app-services',
426
+ initial: defaults.appServices,
305
427
  validate: value => value.trim().length > 0
306
428
  },
307
429
  {
@@ -313,31 +435,34 @@ async function runInteractiveWizard(detected) {
313
435
  { title: 'AWS (Amazon Web Services)', value: 'aws' },
314
436
  { title: 'Multi-cloud (AWS + GCP)', value: 'multi-cloud' }
315
437
  ],
316
- initial: 0
438
+ initial: defaults.cloudProvider === 'gcp' ? 0 : defaults.cloudProvider === 'aws' ? 1 : 2
317
439
  },
318
440
  {
319
441
  type: (prev, values) => ['gcp', 'multi-cloud'].includes(values.cloudProvider) ? 'text' : null,
320
442
  name: 'gcpProjectId',
321
443
  message: '🌐 GCP Project ID (e.g., aaxis-rnd-non-prod):',
444
+ initial: defaults.gcpProjectId,
322
445
  validate: value => value.trim().length > 0
323
446
  },
324
447
  {
325
448
  type: (prev, values) => ['aws', 'multi-cloud'].includes(values.cloudProvider) ? 'text' : null,
326
449
  name: 'awsAccountId',
327
450
  message: '🌐 AWS Account ID (e.g., 929914624686):',
451
+ initial: defaults.awsAccountId,
328
452
  validate: value => value.trim().length > 0
329
453
  },
330
454
  {
331
455
  type: 'text',
332
456
  name: 'region',
333
457
  message: '🌍 Primary Region (e.g., us-central1 for GCP, us-east-1 for AWS):',
334
- initial: 'us-central1',
458
+ initial: defaults.region,
335
459
  validate: value => value.trim().length > 0
336
460
  },
337
461
  {
338
462
  type: 'text',
339
463
  name: 'clusterName',
340
464
  message: '☸️ Cluster Name (e.g., rnd-gke-nonprod or digital-eks-prod):',
465
+ initial: defaults.clusterName,
341
466
  validate: value => value.trim().length > 0
342
467
  },
343
468
  {
@@ -345,12 +470,6 @@ async function runInteractiveWizard(detected) {
345
470
  name: 'installClaudeCode',
346
471
  message: 'πŸ“₯ Install Claude Code if not present?',
347
472
  initial: true
348
- },
349
- {
350
- type: 'text',
351
- name: 'projectContextRepo',
352
- message: 'πŸ”— Project context Git repo (optional, e.g., git@bitbucket.org:org/context.git):',
353
- initial: ''
354
473
  }
355
474
  ];
356
475
 
@@ -367,6 +486,10 @@ async function runInteractiveWizard(detected) {
367
486
  process.exit(0);
368
487
  }
369
488
 
489
+ // Add project context info to responses
490
+ responses.projectContextRepo = defaults.repoUrl;
491
+ responses.projectContextAlreadyCloned = !!projectContext;
492
+
370
493
  return responses;
371
494
  }
372
495
 
@@ -496,27 +619,13 @@ async function generateClaudeMd(config) {
496
619
 
497
620
  /**
498
621
  * Generate AGENTS.md symlink
622
+ * NOTE: AGENTS.md is already available at .claude/config/AGENTS.md via the config/ symlink
623
+ * No need to create a separate symlink in the project root
499
624
  */
500
625
  async function generateAgentsMd() {
501
- const spinner = ora('Creating AGENTS.md symlink...').start();
502
-
503
- try {
504
- const agentsMdLink = join(CWD, 'AGENTS.md');
505
- const packagePath = join(CWD, 'node_modules', '@jaguilar87', 'gaia-ops', 'config', 'AGENTS.md');
506
- const relativePath = relative(CWD, packagePath);
507
-
508
- // Remove existing if present
509
- if (existsSync(agentsMdLink)) {
510
- await fs.unlink(agentsMdLink);
511
- }
512
-
513
- await fs.symlink(relativePath, agentsMdLink);
514
-
515
- spinner.succeed('AGENTS.md symlink created');
516
- } catch (error) {
517
- spinner.fail('Failed to create AGENTS.md symlink');
518
- throw error;
519
- }
626
+ // AGENTS.md is accessible via .claude/config/AGENTS.md (symlinked directory)
627
+ // No action needed - keeping function for backward compatibility
628
+ return Promise.resolve();
520
629
  }
521
630
 
522
631
  /**
@@ -712,13 +821,58 @@ async function installClaudeAgentsPackage() {
712
821
 
713
822
  /**
714
823
  * Clone project context repository (optional)
824
+ * If already cloned during wizard, skip clone and just set it up in final location
715
825
  */
716
- async function cloneProjectContextRepo(repoUrl) {
826
+ async function cloneProjectContextRepo(repoUrl, alreadyCloned = false) {
717
827
  if (!repoUrl || repoUrl.trim() === '') {
718
828
  console.log(chalk.gray('\nβœ“ Skipping project context repo clone (not provided)\n'));
719
829
  return;
720
830
  }
721
831
 
832
+ const sanitizedUrl = sanitizeGitUrl(repoUrl);
833
+
834
+ if (alreadyCloned) {
835
+ // Context was already cloned during wizard, just re-clone to final location
836
+ const spinner = ora('Setting up project context...').start();
837
+
838
+ try {
839
+ const projectContextDir = join(CWD, '.claude', 'project-context');
840
+
841
+ // Remove the generated project-context.json as it will be replaced by the cloned repo
842
+ const generatedFile = join(projectContextDir, 'project-context.json');
843
+ if (existsSync(generatedFile)) {
844
+ await fs.unlink(generatedFile);
845
+ }
846
+
847
+ // Clone fresh to final location (we already validated it works)
848
+ const tempDir = `${projectContextDir}-temp`;
849
+ await execAsync(`git clone ${sanitizedUrl} ${tempDir}`, { timeout: 30000 });
850
+
851
+ // Move contents from temp to project-context
852
+ const files = await fs.readdir(tempDir);
853
+ for (const file of files) {
854
+ const src = join(tempDir, file);
855
+ const dest = join(projectContextDir, file);
856
+ await fs.rename(src, dest);
857
+ }
858
+
859
+ // Remove temp directory
860
+ await fs.rm(tempDir, { recursive: true, force: true });
861
+
862
+ spinner.succeed('Project context repository configured');
863
+ console.log(chalk.green(` β†’ Location: .claude/project-context/\n`));
864
+ } catch (error) {
865
+ spinner.fail('Failed to setup project context repository');
866
+ console.log(chalk.yellow(`\n⚠️ You can clone it manually with:`));
867
+ console.log(chalk.gray(` cd .claude`));
868
+ console.log(chalk.gray(` rm -rf project-context`));
869
+ console.log(chalk.gray(` git clone ${sanitizedUrl} project-context\n`));
870
+ // Don't throw - allow installation to continue
871
+ }
872
+ return;
873
+ }
874
+
875
+ // Not cloned yet during wizard, try to clone now
722
876
  const spinner = ora('Cloning project context repository...').start();
723
877
 
724
878
  try {
@@ -730,11 +884,11 @@ async function cloneProjectContextRepo(repoUrl) {
730
884
  await fs.unlink(generatedFile);
731
885
  }
732
886
 
733
- // Clone repo directly into project-context directory
734
- await execAsync(`git clone ${repoUrl} ${projectContextDir}-temp`);
887
+ // Clone repo
888
+ const tempDir = `${projectContextDir}-temp`;
889
+ await execAsync(`git clone ${sanitizedUrl} ${tempDir}`, { timeout: 30000 });
735
890
 
736
891
  // Move contents from temp to project-context
737
- const tempDir = `${projectContextDir}-temp`;
738
892
  const files = await fs.readdir(tempDir);
739
893
  for (const file of files) {
740
894
  const src = join(tempDir, file);
@@ -743,17 +897,22 @@ async function cloneProjectContextRepo(repoUrl) {
743
897
  }
744
898
 
745
899
  // Remove temp directory
746
- await fs.rmdir(tempDir);
900
+ await fs.rm(tempDir, { recursive: true, force: true });
747
901
 
748
902
  spinner.succeed('Project context repository cloned');
749
- console.log(chalk.green(` β†’ Cloned from: ${repoUrl}`));
903
+ console.log(chalk.green(` β†’ Cloned from: ${sanitizedUrl}`));
750
904
  console.log(chalk.gray(` β†’ Location: .claude/project-context/\n`));
751
905
  } catch (error) {
752
906
  spinner.fail('Failed to clone project context repository');
753
- console.log(chalk.yellow(`\n⚠️ You can clone it manually later with:`));
754
- console.log(chalk.gray(` cd .claude`));
755
- console.log(chalk.gray(` rm -rf project-context`));
756
- console.log(chalk.gray(` git clone ${repoUrl} project-context\n`));
907
+ console.log(chalk.yellow(`\n⚠️ Error: ${error.message}`));
908
+ console.log(chalk.gray('\n Common issues:'));
909
+ console.log(chalk.gray(' β€’ Check SSH keys are configured: ssh -T git@bitbucket.org'));
910
+ console.log(chalk.gray(' β€’ Verify repository URL is correct'));
911
+ console.log(chalk.gray(' β€’ Ensure you have access to the repository\n'));
912
+ console.log(chalk.yellow(` You can clone it manually later with:`));
913
+ console.log(chalk.gray(` cd .claude`));
914
+ console.log(chalk.gray(` rm -rf project-context`));
915
+ console.log(chalk.gray(` git clone ${sanitizedUrl} project-context\n`));
757
916
  // Don't throw - allow installation to continue
758
917
  }
759
918
  }
@@ -828,7 +987,7 @@ async function main() {
828
987
 
829
988
  // Step 10: Clone project context repository (optional)
830
989
  if (config.projectContextRepo) {
831
- await cloneProjectContextRepo(config.projectContextRepo);
990
+ await cloneProjectContextRepo(config.projectContextRepo, config.projectContextAlreadyCloned);
832
991
  }
833
992
 
834
993
  // Success message
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaguilar87/gaia-ops",
3
- "version": "1.3.3",
3
+ "version": "1.3.5",
4
4
  "description": "Multi-agent orchestration system for Claude Code - DevOps automation toolkit",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -25,6 +25,11 @@
25
25
  "type": "git",
26
26
  "url": "git+https://github.com/metraton/gaia-ops.git"
27
27
  },
28
+ "homepage": "https://github.com/metraton/gaia-ops#readme",
29
+ "bugs": {
30
+ "url": "https://github.com/metraton/gaia-ops/issues",
31
+ "email": "jaguilar1897@gmail.com"
32
+ },
28
33
  "files": [
29
34
  "bin/",
30
35
  "agents/",
@@ -42,7 +47,9 @@
42
47
  "scripts": {
43
48
  "test": "pytest tests/ -v",
44
49
  "validate": "python3 tools/commit_validator.py",
45
- "lint": "eslint ."
50
+ "lint": "eslint .",
51
+ "clean": "find . -type d -name '__pycache__' -exec rm -rf {} + 2>/dev/null || true",
52
+ "prepublishOnly": "npm run clean"
46
53
  },
47
54
  "dependencies": {
48
55
  "prompts": "^2.4.2",