@jaguilar87/gaia-ops 3.10.0 → 3.10.2

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.
File without changes
File without changes
File without changes
@@ -66,6 +66,92 @@ PROJECT_AGENTS = [
66
66
  ]
67
67
 
68
68
 
69
+ def _load_agent_skills(subagent_type: str) -> str:
70
+ """
71
+ Load skill content for a project agent by reading its frontmatter.
72
+
73
+ Reads the agent definition to find 'skills:' list, then loads each
74
+ SKILL.md file and returns concatenated content.
75
+
76
+ Args:
77
+ subagent_type: Agent name (e.g. 'cloud-troubleshooter')
78
+
79
+ Returns:
80
+ Concatenated skill content or empty string
81
+ """
82
+ # Find agent definition
83
+ agent_paths = [
84
+ Path(f".claude/agents/{subagent_type}.md"),
85
+ Path(__file__).parent.parent / "agents" / f"{subagent_type}.md",
86
+ ]
87
+
88
+ agent_file = None
89
+ for p in agent_paths:
90
+ if p.exists():
91
+ agent_file = p
92
+ break
93
+
94
+ if not agent_file:
95
+ return ""
96
+
97
+ # Parse frontmatter to extract skills list
98
+ try:
99
+ text = agent_file.read_text()
100
+ if not text.startswith("---"):
101
+ return ""
102
+ end = text.index("---", 3)
103
+ frontmatter = text[3:end]
104
+
105
+ skills = []
106
+ in_skills = False
107
+ for line in frontmatter.splitlines():
108
+ stripped = line.strip()
109
+ if stripped.startswith("skills:"):
110
+ in_skills = True
111
+ continue
112
+ if in_skills:
113
+ if stripped.startswith("- "):
114
+ skills.append(stripped[2:].strip())
115
+ else:
116
+ break
117
+ except Exception:
118
+ return ""
119
+
120
+ if not skills:
121
+ return ""
122
+
123
+ # Load each skill file
124
+ skills_dir_paths = [
125
+ Path(".claude/skills"),
126
+ Path(__file__).parent.parent / "skills",
127
+ ]
128
+
129
+ skills_dir = None
130
+ for p in skills_dir_paths:
131
+ if p.is_dir():
132
+ skills_dir = p
133
+ break
134
+
135
+ if not skills_dir:
136
+ return ""
137
+
138
+ parts = []
139
+ for skill_name in skills:
140
+ skill_file = skills_dir / skill_name / "SKILL.md"
141
+ if skill_file.exists():
142
+ content = skill_file.read_text().strip()
143
+ # Strip frontmatter from skill content
144
+ if content.startswith("---"):
145
+ try:
146
+ end_idx = content.index("---", 3)
147
+ content = content[end_idx + 3:].strip()
148
+ except ValueError:
149
+ pass
150
+ parts.append(content)
151
+
152
+ return "\n\n---\n\n".join(parts) if parts else ""
153
+
154
+
69
155
 
70
156
 
71
157
  def _should_inject_on_resume(parameters: dict) -> bool:
@@ -249,12 +335,16 @@ def _inject_project_context(parameters: dict) -> dict:
249
335
  # Check pending update count (non-blocking, fast path)
250
336
  pending_warning = _check_pending_updates_threshold()
251
337
 
252
- # Inject context into prompt (skills now loaded natively via agent frontmatter)
338
+ # Load skills content for this agent
339
+ skills_content = _load_agent_skills(subagent_type)
340
+ skills_section = f"\n\n---\n\n# Agent Skills (Auto-Injected)\n\n{skills_content}" if skills_content else ""
341
+
342
+ # Inject context and skills into prompt
253
343
  enriched_prompt = f"""# Project Context (Auto-Injected)
254
344
 
255
345
  {json.dumps(context_payload, indent=2)}
256
346
 
257
- {pending_warning}---
347
+ {pending_warning}---{skills_section}
258
348
 
259
349
  # User Task
260
350
 
@@ -271,8 +361,9 @@ def _inject_project_context(parameters: dict) -> dict:
271
361
  context_level = context_payload.get("metadata", {}).get("context_level", "unknown")
272
362
  standards_count = context_payload.get("metadata", {}).get("standards_count", 0)
273
363
 
364
+ skills_loaded = bool(skills_content)
274
365
  logger.info(
275
- f"✅ Context injected for {subagent_type} "
366
+ f"✅ Context{'+ skills' if skills_loaded else ''} injected for {subagent_type} "
276
367
  f"(level={context_level}, standards={standards_count})"
277
368
  )
278
369
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jaguilar87/gaia-ops",
3
- "version": "3.10.0",
3
+ "version": "3.10.2",
4
4
  "description": "Multi-agent orchestration system for Claude Code - DevOps automation toolkit",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -92,9 +92,19 @@ If PLAN_STATUS is:
92
92
 
93
93
  ## When to Delegate vs. Answer Directly
94
94
 
95
- **Answer Directly:** Response <200 tokens, no code execution, simple status query.
96
-
97
- **MUST Delegate:** Infrastructure ops, multi-file changes, T3 ops, code execution, credential-dependent tasks, complex troubleshooting.
95
+ ### Answer Directly:
96
+ - Response <200 tokens
97
+ - No code execution needed
98
+ - Simple status query answerable from project-context.json
99
+
100
+ ### MUST Delegate:
101
+ - Infrastructure operations (terraform, kubectl, gcloud, aws, helm, flux)
102
+ - Cloud diagnostics (cluster status, namespaces, pods, logs, resources)
103
+ - Multi-file operations (>2 files)
104
+ - T3 operations (apply, deploy, create, delete)
105
+ - Code execution (npm, docker, build, test)
106
+ - Anything requiring credentials (GCP, AWS, K8s)
107
+ - Complex troubleshooting
98
108
 
99
109
  ## System Paths
100
110