everything-gemini 1.8.0 → 2.0.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/CHANGELOG.md +47 -0
- package/CONTRIBUTING.md +5 -0
- package/README.md +28 -9
- package/agents/mlops-engineer.md +33 -0
- package/agents/platform-engineer.md +33 -0
- package/bin/everything-gemini +390 -18
- package/docs/LAUNCH_KIT_v2.0.0.md +187 -0
- package/docs/architecture/progressive-disclosure.md +3 -3
- package/docs/index.html +23 -7
- package/examples/python-sdk/README.md +8 -0
- package/examples/python-sdk/autonomous_mlops_rag_pipeline.py +254 -0
- package/examples/python-sdk/platform_provisioning_pipeline.py +193 -0
- package/mcp/README.md +2 -0
- package/mcp/mcp_config.example.json +11 -0
- package/package.json +1 -1
- package/scripts/validate.sh +1 -1
- package/skills/chromadb-vector-store/SKILL.md +188 -0
- package/skills/cloudflare-r2-object-storage/SKILL.md +143 -0
- package/skills/distributed-rate-limiting/SKILL.md +138 -0
- package/skills/keda-event-autoscaling/SKILL.md +218 -0
- package/skills/milvus-vector-clustering/SKILL.md +134 -0
- package/skills/opa-gatekeeper-policy/SKILL.md +200 -0
- package/skills/triton-inference-server/SKILL.md +221 -0
- package/skills/vault-secrets-management/SKILL.md +129 -0
- package/templates/full-power/mcp_config.json +11 -0
- package/tests/cli.test.js +118 -11
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: triton-inference-server
|
|
3
|
+
description: Deploys, configures, and tunes NVIDIA Triton Inference Server for high-throughput, low-latency multi-model serving with dynamic batching and GPU acceleration.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Triton Inference Server
|
|
7
|
+
|
|
8
|
+
Provides production architecture and configuration patterns for serving deep learning and LLM models at enterprise scale with NVIDIA Triton Inference Server.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Architecture & Execution Model
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
Client Application (gRPC / HTTP KServe v2)
|
|
16
|
+
│
|
|
17
|
+
▼
|
|
18
|
+
┌──────────────────────────────────────────────┐
|
|
19
|
+
│ NVIDIA Triton Inference Server │
|
|
20
|
+
│ │
|
|
21
|
+
│ ┌──────────────────┐ ┌──────────────────┐ │
|
|
22
|
+
│ │ Dynamic Batching │ │ Model Concurrency│ │
|
|
23
|
+
│ │ Scheduler │ │ & GPU Instances │ │
|
|
24
|
+
│ └─────────┬────────┘ └────────┬─────────┘ │
|
|
25
|
+
│ │ │ │
|
|
26
|
+
│ ▼ ▼ │
|
|
27
|
+
│ ┌────────────────────────────────────────┐ │
|
|
28
|
+
│ │ Backend Engines │ │
|
|
29
|
+
│ │ - TensorRT-LLM (High-speed generative)│ │
|
|
30
|
+
│ │ - vLLM Engine (PagedAttention serving)│ │
|
|
31
|
+
│ │ - ONNX Runtime (Embedding & classifier│ │
|
|
32
|
+
│ │ - Python Backend (Custom preprocessing│ │
|
|
33
|
+
│ └────────────────────────────────────────┘ │
|
|
34
|
+
└──────────────────────┬───────────────────────┘
|
|
35
|
+
│
|
|
36
|
+
▼
|
|
37
|
+
NVIDIA Tensor Core GPUs (H100/A100/L4)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## 2. Model Repository Layout
|
|
43
|
+
|
|
44
|
+
Triton requires a strict directory layout with versioned subdirectories and `config.pbtxt`:
|
|
45
|
+
|
|
46
|
+
```text
|
|
47
|
+
model_repository/
|
|
48
|
+
├── embedding_model/
|
|
49
|
+
│ ├── 1/
|
|
50
|
+
│ │ └── model.onnx
|
|
51
|
+
│ └── config.pbtxt
|
|
52
|
+
└── llm_generator/
|
|
53
|
+
├── 1/
|
|
54
|
+
│ └── model.py
|
|
55
|
+
└── config.pbtxt
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 3. High-Throughput `config.pbtxt` Configuration
|
|
61
|
+
|
|
62
|
+
Configures dynamic batching, GPU instance groups, and TensorRT acceleration:
|
|
63
|
+
|
|
64
|
+
```protobuf
|
|
65
|
+
name: "embedding_model"
|
|
66
|
+
platform: "onnxruntime_onnx"
|
|
67
|
+
max_batch_size: 128
|
|
68
|
+
|
|
69
|
+
input [
|
|
70
|
+
{
|
|
71
|
+
name: "input_ids"
|
|
72
|
+
data_type: TYPE_INT64
|
|
73
|
+
dims: [ -1 ]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "attention_mask"
|
|
77
|
+
data_type: TYPE_INT64
|
|
78
|
+
dims: [ -1 ]
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
output [
|
|
83
|
+
{
|
|
84
|
+
name: "sentence_embedding"
|
|
85
|
+
data_type: TYPE_FP32
|
|
86
|
+
dims: [ 768 ]
|
|
87
|
+
}
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
# Maximize GPU utilization via dynamic queue batching
|
|
91
|
+
dynamic_batching {
|
|
92
|
+
max_queue_delay_microseconds: 5000 # 5ms SLA window
|
|
93
|
+
preferred_batch_size: [ 16, 32, 64, 128 ]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Run 2 concurrent model instances on GPU 0
|
|
97
|
+
instance_group [
|
|
98
|
+
{
|
|
99
|
+
count: 2
|
|
100
|
+
kind: KIND_GPU
|
|
101
|
+
gpus: [ 0 ]
|
|
102
|
+
}
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
optimization {
|
|
106
|
+
execution_accelerators {
|
|
107
|
+
gpu_execution_accelerator : [ {
|
|
108
|
+
name : "tensorrt"
|
|
109
|
+
parameters { key: "precision_mode" value: "FP16" }
|
|
110
|
+
parameters { key: "max_workspace_size_bytes" value: "4294967296" }
|
|
111
|
+
}]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 4. High-Performance gRPC Client (Python)
|
|
119
|
+
|
|
120
|
+
Uses binary gRPC streaming with zero-copy serialization:
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
import numpy as np
|
|
124
|
+
import tritonclient.grpc as grpcclient
|
|
125
|
+
from tritonclient.grpc import InferInput, InferRequestedOutput
|
|
126
|
+
|
|
127
|
+
def query_triton_embeddings(
|
|
128
|
+
texts_token_ids: np.ndarray,
|
|
129
|
+
attention_masks: np.ndarray,
|
|
130
|
+
server_url: str = "localhost:8001"
|
|
131
|
+
) -> np.ndarray:
|
|
132
|
+
"""Queries Triton via low-latency gRPC channel."""
|
|
133
|
+
with grpcclient.InferenceServerClient(url=server_url) as client:
|
|
134
|
+
# Check server readiness
|
|
135
|
+
if not client.is_server_ready():
|
|
136
|
+
raise RuntimeError("Triton server is not healthy.")
|
|
137
|
+
|
|
138
|
+
inputs = [
|
|
139
|
+
InferInput("input_ids", texts_token_ids.shape, "INT64"),
|
|
140
|
+
InferInput("attention_mask", attention_masks.shape, "INT64")
|
|
141
|
+
]
|
|
142
|
+
inputs[0].set_data_from_numpy(texts_token_ids)
|
|
143
|
+
inputs[1].set_data_from_numpy(attention_masks)
|
|
144
|
+
|
|
145
|
+
outputs = [InferRequestedOutput("sentence_embedding")]
|
|
146
|
+
|
|
147
|
+
response = client.infer(
|
|
148
|
+
model_name="embedding_model",
|
|
149
|
+
inputs=inputs,
|
|
150
|
+
outputs=outputs,
|
|
151
|
+
timeout=10.0
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
return response.as_numpy("sentence_embedding")
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 5. Production Docker & Kubernetes Deployment
|
|
160
|
+
|
|
161
|
+
```yaml
|
|
162
|
+
apiVersion: apps/v1
|
|
163
|
+
kind: Deployment
|
|
164
|
+
metadata:
|
|
165
|
+
name: triton-inference-server
|
|
166
|
+
namespace: mlops
|
|
167
|
+
spec:
|
|
168
|
+
replicas: 2
|
|
169
|
+
selector:
|
|
170
|
+
matchLabels:
|
|
171
|
+
app: triton
|
|
172
|
+
template:
|
|
173
|
+
metadata:
|
|
174
|
+
labels:
|
|
175
|
+
app: triton
|
|
176
|
+
spec:
|
|
177
|
+
containers:
|
|
178
|
+
- name: triton
|
|
179
|
+
image: nvcr.io/nvidia/tritonserver:24.08-py3
|
|
180
|
+
args: ["tritonserver", "--model-repository=/models", "--strict-model-config=true"]
|
|
181
|
+
resources:
|
|
182
|
+
limits:
|
|
183
|
+
nvidia.com/gpu: 1
|
|
184
|
+
memory: 16Gi
|
|
185
|
+
cpu: "8"
|
|
186
|
+
ports:
|
|
187
|
+
- containerPort: 8000 # HTTP
|
|
188
|
+
- containerPort: 8001 # gRPC
|
|
189
|
+
- containerPort: 8002 # Metrics (Prometheus)
|
|
190
|
+
livenessProbe:
|
|
191
|
+
httpGet:
|
|
192
|
+
path: /v2/health/live
|
|
193
|
+
port: 8000
|
|
194
|
+
initialDelaySeconds: 30
|
|
195
|
+
readinessProbe:
|
|
196
|
+
httpGet:
|
|
197
|
+
path: /v2/health/ready
|
|
198
|
+
port: 8000
|
|
199
|
+
initialDelaySeconds: 15
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## 6. Performance Benchmarking & Profiling
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
# Verify health and loaded models via v2 API
|
|
208
|
+
curl -s http://localhost:8000/v2/health/ready
|
|
209
|
+
curl -s http://localhost:8000/v2/models/embedding_model/ready
|
|
210
|
+
|
|
211
|
+
# Profile throughput and P99 latency with Perf Analyzer
|
|
212
|
+
perf_analyzer -m embedding_model \
|
|
213
|
+
-u localhost:8001 -i gRPC \
|
|
214
|
+
--concurrency-range 1:16 \
|
|
215
|
+
--shape input_ids:128 \
|
|
216
|
+
--shape attention_mask:128 \
|
|
217
|
+
--percentile 99
|
|
218
|
+
|
|
219
|
+
# Query Prometheus metrics
|
|
220
|
+
curl -s http://localhost:8002/metrics | grep nv_inference_
|
|
221
|
+
```
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: vault-secrets-management
|
|
3
|
+
description: >-
|
|
4
|
+
Architects and automates HashiCorp Vault secrets management, AppRole machine authentication, dynamic ephemeral database credentials, and PKI mTLS certificate rotation.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# HashiCorp Vault Secrets Management & Ephemeral Credentials
|
|
8
|
+
|
|
9
|
+
This skill guides the design, automation, and operational patterns for HashiCorp Vault enterprise secrets orchestration, dynamic credential generation, and PKI certificate authority workflows.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## ⚡ Secret Engine Capabilities Matrix
|
|
14
|
+
|
|
15
|
+
| Secret Engine | Purpose | Lifecycle Behavior |
|
|
16
|
+
| :--- | :--- | :--- |
|
|
17
|
+
| **`kv-v2`** | Static credentials & API keys | Versioned key-value store with soft delete and rollback. |
|
|
18
|
+
| **`database`** | Ephemeral DB access (Postgres, MySQL) | Generates short-lived user credentials and revokes upon lease expiry. |
|
|
19
|
+
| **`pki`** | Internal mTLS & TLS certificates | Acts as CA/sub-CA; dynamically issues certificates in milliseconds. |
|
|
20
|
+
| **`transit`** | Cryptography as a service | Encrypts/decrypts data without exposing raw encryption keys. |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🔐 AppRole Machine Authentication Workflow
|
|
25
|
+
|
|
26
|
+
Applications authenticate using decoupled `role_id` and short-lived `secret_id`:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
# 1. Enable AppRole auth method
|
|
30
|
+
vault auth enable approle
|
|
31
|
+
|
|
32
|
+
# 2. Configure service role with strict CIDR and token policies
|
|
33
|
+
vault write auth/approle/role/api-service \
|
|
34
|
+
secret_id_ttl=60m \
|
|
35
|
+
token_ttl=30m \
|
|
36
|
+
token_max_ttl=4h \
|
|
37
|
+
secret_id_num_uses=10 \
|
|
38
|
+
token_policies="api-service-policy" \
|
|
39
|
+
bind_secret_id=true
|
|
40
|
+
|
|
41
|
+
# 3. Retrieve Role ID (stored in deployment manifest)
|
|
42
|
+
vault read auth/approle/role/api-service/role-id
|
|
43
|
+
|
|
44
|
+
# 4. Generate Secret ID (delivered securely via CI/CD or orchestrator)
|
|
45
|
+
vault write -f auth/approle/role/api-service/secret-id
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Node.js / Python authentication client:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import axios from 'axios';
|
|
52
|
+
|
|
53
|
+
export async function loginWithAppRole(vaultAddr: string, roleId: string, secretId: string) {
|
|
54
|
+
const response = await axios.post(`${vaultAddr}/v1/auth/approle/login`, {
|
|
55
|
+
role_id: roleId,
|
|
56
|
+
secret_id: secretId,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const clientToken = response.data.auth.client_token;
|
|
60
|
+
const leaseDuration = response.data.auth.lease_duration;
|
|
61
|
+
return { clientToken, leaseDuration };
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## ⏳ Dynamic Ephemeral Database Credentials
|
|
68
|
+
|
|
69
|
+
Configure Vault to create temporary, unique PostgreSQL roles for each application instance:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# 1. Mount database engine
|
|
73
|
+
vault secrets enable database
|
|
74
|
+
|
|
75
|
+
# 2. Configure connection to PostgreSQL
|
|
76
|
+
vault write database/config/production-postgres \
|
|
77
|
+
plugin_name=postgresql-database-plugin \
|
|
78
|
+
allowed_roles="readwrite-service" \
|
|
79
|
+
connection_url="postgresql://{{username}}:{{password}}@postgres:5432/production?sslmode=verify-full" \
|
|
80
|
+
username="vaultadmin" \
|
|
81
|
+
password="supersecretadminpassword"
|
|
82
|
+
|
|
83
|
+
# 3. Define role template with automated role creation SQL
|
|
84
|
+
vault write database/roles/readwrite-service \
|
|
85
|
+
db_name=production-postgres \
|
|
86
|
+
creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; \
|
|
87
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
|
|
88
|
+
default_ttl="1h" \
|
|
89
|
+
max_ttl="24h"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Application requests credentials on demand:
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
vault read database/creds/readwrite-service
|
|
96
|
+
# Returns: username: v-approle-readwrite-abc123, password: xyz..., lease_id: database/creds/readwrite-service/xyz...
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## 📜 PKI Dynamic mTLS Certificate Issuance
|
|
102
|
+
|
|
103
|
+
Automate TLS certificate issuance without manual CSR handling:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
# Mount PKI engine and configure Root/Intermediate CA
|
|
107
|
+
vault secrets enable pki
|
|
108
|
+
vault secrets tune -max-lease-ttl=87600h pki
|
|
109
|
+
|
|
110
|
+
# Configure role for cluster services
|
|
111
|
+
vault write pki/roles/internal-mesh \
|
|
112
|
+
allowed_domains="internal.cluster.local" \
|
|
113
|
+
allow_subdomains=true \
|
|
114
|
+
max_ttl="72h"
|
|
115
|
+
|
|
116
|
+
# Generate certificate on demand
|
|
117
|
+
vault write pki/issue/internal-mesh \
|
|
118
|
+
common_name="billing-service.internal.cluster.local" \
|
|
119
|
+
ttl="24h"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 📋 Architectural Rules & Best Practices
|
|
125
|
+
|
|
126
|
+
1. **Never Hardcode Secrets**: Eliminate long-lived static DB passwords; adopt dynamic ephemeral database roles with short TTLs (< 2 hours).
|
|
127
|
+
2. **Strict Secret ID Binding**: Bind AppRole `secret_id` to expected subnet CIDRs (`secret_id_bound_cidrs`) to stop credential theft across VPCs.
|
|
128
|
+
3. **Lease Renewal & Heartbeats**: Background workers must periodically renew active leases (`vault write sys/leases/renew lease_id=...`) before expiry.
|
|
129
|
+
4. **Audit Logging**: Enable Vault audit devices (`vault audit enable file file_path=/var/log/vault/audit.log`) with hashed payload sanitization.
|
|
@@ -53,6 +53,17 @@
|
|
|
53
53
|
"SLACK_BOT_TOKEN": "${SLACK_BOT_TOKEN}",
|
|
54
54
|
"SLACK_TEAM_ID": "${SLACK_TEAM_ID}"
|
|
55
55
|
}
|
|
56
|
+
},
|
|
57
|
+
"puppeteer": {
|
|
58
|
+
"command": "npx",
|
|
59
|
+
"args": ["-y", "@modelcontextprotocol/server-puppeteer"]
|
|
60
|
+
},
|
|
61
|
+
"brave-search": {
|
|
62
|
+
"command": "npx",
|
|
63
|
+
"args": ["-y", "@modelcontextprotocol/server-brave-search"],
|
|
64
|
+
"env": {
|
|
65
|
+
"BRAVE_API_KEY": "${BRAVE_API_KEY}"
|
|
66
|
+
}
|
|
56
67
|
}
|
|
57
68
|
}
|
|
58
69
|
}
|
package/tests/cli.test.js
CHANGED
|
@@ -90,9 +90,9 @@ it('should benchmark ecosystem components and output valid JSON with --json', ()
|
|
|
90
90
|
const res = runCli('benchmark --json');
|
|
91
91
|
assert.strictEqual(res.status, 0);
|
|
92
92
|
const data = JSON.parse(res.stdout);
|
|
93
|
-
assert.strictEqual(data.totalComponents,
|
|
94
|
-
assert.strictEqual(data.progressiveSkillsCount,
|
|
95
|
-
assert.strictEqual(data.scopedAgentsCount,
|
|
93
|
+
assert.strictEqual(data.totalComponents, 80);
|
|
94
|
+
assert.strictEqual(data.progressiveSkillsCount, 60);
|
|
95
|
+
assert.strictEqual(data.scopedAgentsCount, 13);
|
|
96
96
|
assert.strictEqual(data.lifecycleHooksCount, 7);
|
|
97
97
|
assert(data.totalRunbookTokens > 15000, 'Expected >15,000 runbook tokens');
|
|
98
98
|
assert(data.estimatedTokensSavedPerTurn > 8000, 'Expected significant token savings');
|
|
@@ -316,7 +316,7 @@ try {
|
|
|
316
316
|
const dryRes = runCli(`bundle --output "${bundleTarget}" --dry-run`);
|
|
317
317
|
assert.strictEqual(dryRes.status, 0);
|
|
318
318
|
assert.match(dryRes.stdout, /DRY RUN MODE ACTIVATED/);
|
|
319
|
-
assert.match(dryRes.stdout, /Skills to bundle:
|
|
319
|
+
assert.match(dryRes.stdout, /Skills to bundle: 60/);
|
|
320
320
|
assert.strictEqual(fs.existsSync(bundleTarget), false, 'Dry run should not create destination directory');
|
|
321
321
|
|
|
322
322
|
// JSON Dry-run mode
|
|
@@ -324,7 +324,7 @@ try {
|
|
|
324
324
|
assert.strictEqual(jsonRes.status, 0);
|
|
325
325
|
const dryData = JSON.parse(jsonRes.stdout);
|
|
326
326
|
assert.strictEqual(dryData.dryRun, true);
|
|
327
|
-
assert.strictEqual(dryData.manifest.components.totalCount,
|
|
327
|
+
assert.strictEqual(dryData.manifest.components.totalCount, 80);
|
|
328
328
|
|
|
329
329
|
// Live mode
|
|
330
330
|
const liveRes = runCli(`bundle --output "${bundleTarget}"`);
|
|
@@ -332,8 +332,49 @@ try {
|
|
|
332
332
|
assert.match(liveRes.stdout, /Offline Distribution Bundle Created/);
|
|
333
333
|
assert.strictEqual(fs.existsSync(path.join(bundleTarget, 'bundle-manifest.json')), true);
|
|
334
334
|
assert.strictEqual(fs.existsSync(path.join(bundleTarget, 'offline-install.sh')), true);
|
|
335
|
-
assert.strictEqual(fs.existsSync(path.join(bundleTarget, 'skills', '
|
|
336
|
-
assert.strictEqual(fs.existsSync(path.join(bundleTarget, 'agents', '
|
|
335
|
+
assert.strictEqual(fs.existsSync(path.join(bundleTarget, 'skills', 'milvus-vector-clustering')), true);
|
|
336
|
+
assert.strictEqual(fs.existsSync(path.join(bundleTarget, 'agents', 'platform-engineer.md')), true);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
// Scaffold Command
|
|
340
|
+
it('should scaffold skill, agent, and hook in dry-run and live modes', () => {
|
|
341
|
+
const scaffoldWorkspace = path.join(tempWorkspace, 'scaffold-ws');
|
|
342
|
+
|
|
343
|
+
// Skill Dry-run
|
|
344
|
+
const drySkill = runCli(`scaffold skill demo-test-skill --workspace "${scaffoldWorkspace}" --dry-run --json`);
|
|
345
|
+
assert.strictEqual(drySkill.status, 0);
|
|
346
|
+
const drySkillData = JSON.parse(drySkill.stdout);
|
|
347
|
+
assert.strictEqual(drySkillData.isDryRun, true);
|
|
348
|
+
assert.strictEqual(drySkillData.type, 'skill');
|
|
349
|
+
|
|
350
|
+
// Live Agent Scaffold
|
|
351
|
+
const liveAgent = runCli(`scaffold agent demo-qa-agent --workspace "${scaffoldWorkspace}"`);
|
|
352
|
+
assert.strictEqual(liveAgent.status, 0);
|
|
353
|
+
assert.match(liveAgent.stdout, /Created subagent profile/);
|
|
354
|
+
assert.strictEqual(fs.existsSync(path.join(scaffoldWorkspace, 'agents', 'demo-qa-agent.md')), true);
|
|
355
|
+
|
|
356
|
+
// Live Hook Scaffold
|
|
357
|
+
const liveHook = runCli(`scaffold hook demo-safety --workspace "${scaffoldWorkspace}"`);
|
|
358
|
+
assert.strictEqual(liveHook.status, 0);
|
|
359
|
+
assert.match(liveHook.stdout, /Created lifecycle hook/);
|
|
360
|
+
assert.strictEqual(fs.existsSync(path.join(scaffoldWorkspace, 'hooks', 'demo-safety', 'hooks.json')), true);
|
|
361
|
+
assert.strictEqual(fs.existsSync(path.join(scaffoldWorkspace, 'hooks', 'demo-safety', 'scripts', 'demo-safety-gate.sh')), true);
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
// Sync Command
|
|
365
|
+
it('should synchronize workspace with sync command in dry-run and live modes', () => {
|
|
366
|
+
// Dry-run
|
|
367
|
+
const drySync = runCli(`sync --workspace "${tempWorkspace}" --dry-run`);
|
|
368
|
+
assert.strictEqual(drySync.status, 0);
|
|
369
|
+
assert.match(drySync.stdout, /DRY RUN MODE ACTIVATED/);
|
|
370
|
+
assert.match(drySync.stdout, /Synchronizing Workspace with Catalog/);
|
|
371
|
+
|
|
372
|
+
// JSON Dry-run
|
|
373
|
+
const jsonSync = runCli(`sync --workspace "${tempWorkspace}" --dry-run --json`);
|
|
374
|
+
assert.strictEqual(jsonSync.status, 0);
|
|
375
|
+
const syncData = JSON.parse(jsonSync.stdout);
|
|
376
|
+
assert.strictEqual(syncData.isDryRun, true);
|
|
377
|
+
assert.strictEqual(syncData.success, true);
|
|
337
378
|
});
|
|
338
379
|
|
|
339
380
|
// Info for incident-responder and v1.8.0 skills
|
|
@@ -359,14 +400,80 @@ try {
|
|
|
359
400
|
assert.match(resLite.stdout, /LiteLLM/);
|
|
360
401
|
});
|
|
361
402
|
|
|
403
|
+
// Info for platform-engineer and v1.9.0 skills
|
|
404
|
+
it('should display info for platform-engineer subagent and v1.9.0 skills', () => {
|
|
405
|
+
const resPlat = runCli('info platform-engineer');
|
|
406
|
+
assert.strictEqual(resPlat.status, 0);
|
|
407
|
+
assert.match(resPlat.stdout, /Platform Engineer/);
|
|
408
|
+
|
|
409
|
+
const resMilvus = runCli('info milvus-vector-clustering');
|
|
410
|
+
assert.strictEqual(resMilvus.status, 0);
|
|
411
|
+
assert.match(resMilvus.stdout, /Milvus/);
|
|
412
|
+
|
|
413
|
+
const resR2 = runCli('info cloudflare-r2-object-storage');
|
|
414
|
+
assert.strictEqual(resR2.status, 0);
|
|
415
|
+
assert.match(resR2.stdout, /Cloudflare R2/);
|
|
416
|
+
|
|
417
|
+
const resVault = runCli('info vault-secrets-management');
|
|
418
|
+
assert.strictEqual(resVault.status, 0);
|
|
419
|
+
assert.match(resVault.stdout, /Vault/);
|
|
420
|
+
|
|
421
|
+
const resRate = runCli('info distributed-rate-limiting');
|
|
422
|
+
assert.strictEqual(resRate.status, 0);
|
|
423
|
+
assert.match(resRate.stdout, /Distributed Rate Limiting/);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
// Info for mlops-engineer and v2.0.0 skills
|
|
427
|
+
it('should display info for mlops-engineer subagent and v2.0.0 skills', () => {
|
|
428
|
+
const resMl = runCli('info mlops-engineer');
|
|
429
|
+
assert.strictEqual(resMl.status, 0);
|
|
430
|
+
assert.match(resMl.stdout, /MLOps Engineer/);
|
|
431
|
+
|
|
432
|
+
const resKeda = runCli('info keda-event-autoscaling');
|
|
433
|
+
assert.strictEqual(resKeda.status, 0);
|
|
434
|
+
assert.match(resKeda.stdout, /KEDA/);
|
|
435
|
+
|
|
436
|
+
const resChroma = runCli('info chromadb-vector-store');
|
|
437
|
+
assert.strictEqual(resChroma.status, 0);
|
|
438
|
+
assert.match(resChroma.stdout, /ChromaDB/);
|
|
439
|
+
|
|
440
|
+
const resOpa = runCli('info opa-gatekeeper-policy');
|
|
441
|
+
assert.strictEqual(resOpa.status, 0);
|
|
442
|
+
assert.match(resOpa.stdout, /Gatekeeper/);
|
|
443
|
+
|
|
444
|
+
const resTriton = runCli('info triton-inference-server');
|
|
445
|
+
assert.strictEqual(resTriton.status, 0);
|
|
446
|
+
assert.match(resTriton.stdout, /Triton/);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
// Graph command verification
|
|
450
|
+
it('should render interaction graph in terminal, mermaid, and JSON formats', () => {
|
|
451
|
+
const resTerm = runCli('graph');
|
|
452
|
+
assert.strictEqual(resTerm.status, 0);
|
|
453
|
+
assert.match(resTerm.stdout, /Multi-Agent Topology & Dependency Graph/);
|
|
454
|
+
assert.match(resTerm.stdout, /MLOPS-ENGINEER/);
|
|
455
|
+
|
|
456
|
+
const resMermaid = runCli('graph --mermaid');
|
|
457
|
+
assert.strictEqual(resMermaid.status, 0);
|
|
458
|
+
assert.match(resMermaid.stdout, /graph TD/);
|
|
459
|
+
assert.match(resMermaid.stdout, /A_mlops_engineer/);
|
|
460
|
+
|
|
461
|
+
const resJson = runCli('graph --json');
|
|
462
|
+
assert.strictEqual(resJson.status, 0);
|
|
463
|
+
const data = JSON.parse(resJson.stdout);
|
|
464
|
+
assert.ok(data.totalNodes > 50, 'Graph should contain > 50 nodes');
|
|
465
|
+
assert.ok(data.totalEdges > 50, 'Graph should contain > 50 edges');
|
|
466
|
+
assert.ok(data.nodes.find(n => n.id === 'agent:mlops-engineer'));
|
|
467
|
+
});
|
|
468
|
+
|
|
362
469
|
// Benchmark Components Verification
|
|
363
|
-
it('should report
|
|
470
|
+
it('should report 80 components, 60 skills, and 13 subagents in benchmark --json', () => {
|
|
364
471
|
const res = runCli('benchmark --json');
|
|
365
472
|
assert.strictEqual(res.status, 0);
|
|
366
473
|
const data = JSON.parse(res.stdout);
|
|
367
|
-
assert.strictEqual(data.totalComponents,
|
|
368
|
-
assert.strictEqual(data.progressiveSkillsCount,
|
|
369
|
-
assert.strictEqual(data.scopedAgentsCount,
|
|
474
|
+
assert.strictEqual(data.totalComponents, 80, 'Total components should be 80');
|
|
475
|
+
assert.strictEqual(data.progressiveSkillsCount, 60, 'Progressive skills should be 60');
|
|
476
|
+
assert.strictEqual(data.scopedAgentsCount, 13, 'Scoped agents should be 13');
|
|
370
477
|
assert.strictEqual(data.lifecycleHooksCount, 7, 'Lifecycle hooks should be 7');
|
|
371
478
|
});
|
|
372
479
|
|