@hazeljs/cli 2.0.5 → 2.0.6
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/README.md +46 -15
- package/cli-manifest.json +7 -1
- package/dist/commands/agent-templates.js +255 -1
- package/dist/commands/agent.test.js +4 -0
- package/dist/utils/packages-registry.js +47 -0
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @hazeljs/cli
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Scaffold Agent OS apps and HazelJS backends.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
DNA / Store / Skillgate / HITL live in [Meridian](https://github.com/hazel-js/hazeljs-meridian-ops) and `hazel agent new`. HTTP + HCEL templates (`--template=ai-native`) are a secondary framework path — not the Agent OS flagship.
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/@hazeljs/cli)
|
|
8
8
|
[](https://www.npmjs.com/package/@hazeljs/cli)
|
|
@@ -10,13 +10,13 @@ Generate controllers, services, modules, AI agents, RAG systems — or create a
|
|
|
10
10
|
|
|
11
11
|
## Features
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
13
|
+
- 🧬 **Agent OS** — `hazel agent new` (bare / agent-os / skillgate), Store, DNA install, runs, apply
|
|
14
|
+
- 🚪 **Skillgate / Gatekeeper** — `hazel skillgate from-openapi`, `hazel gatekeeper validate|simulate|explain`
|
|
15
|
+
- 🧪 **Eval / benchmark** — `hazel eval`, `hazel benchmark`
|
|
16
|
+
- 🚀 **App scaffolding** — `hazel new`, `hazel g app` (HTTP skeleton or `--template=ai-native`)
|
|
17
|
+
- 🎨 **Code generation** — controllers, services, agents, RAG, 20+ component types
|
|
18
|
+
- 📦 **Package management** — `hazel add` with optional setup files
|
|
19
|
+
- Generated apps do **not** list or import `reflect-metadata` — `@hazeljs/core` loads it
|
|
20
20
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
@@ -34,25 +34,45 @@ npm install --save-dev @hazeljs/cli
|
|
|
34
34
|
|
|
35
35
|
## Commands
|
|
36
36
|
|
|
37
|
-
###
|
|
37
|
+
### Agent OS (start here)
|
|
38
38
|
|
|
39
|
-
**
|
|
39
|
+
**Flagship teaching path** — clone [Meridian](https://github.com/hazel-js/hazeljs-meridian-ops) (`store:sync` → `platform:sync` → `dev`). The CLI is not a substitute for that app.
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Smaller Agent OS / DNA scaffold (not Meridian)
|
|
43
|
+
hazel agent new my-desk --template=agent-os
|
|
44
|
+
# templates: bare | agent-os | skillgate
|
|
45
|
+
# agent-os includes: DNA + real @Tool app + ops stack (self-healing + predictive-scaling) + K8s manifests
|
|
46
|
+
cd my-desk && npm install && npm run dev
|
|
47
|
+
|
|
48
|
+
hazel agent install ./packages/support.dna.json
|
|
49
|
+
hazel agent runs list
|
|
50
|
+
hazel store publish | install | list
|
|
51
|
+
hazel skillgate from-openapi ./openapi.yaml
|
|
52
|
+
hazel gatekeeper validate
|
|
53
|
+
hazel benchmark
|
|
54
|
+
hazel eval
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`hazel agent run` is a DNA smoke with stubs. Real tools and HITL = your app’s `runtime.execute` / Meridian `/api/chat`. `hazel agent apply` declares desired state — it does not restart Node.
|
|
58
|
+
|
|
59
|
+
### Create a framework application (secondary)
|
|
60
|
+
|
|
61
|
+
HTTP + HCEL / RAG scaffold — **not** the Agent OS flagship:
|
|
40
62
|
|
|
41
63
|
```bash
|
|
42
64
|
hazel g app my-ai-app --template=ai-native
|
|
43
65
|
cd my-ai-app && npm install && cp .env.example .env && docker-compose up -d && npm run dev
|
|
44
66
|
```
|
|
45
67
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
**Skeleton app (quick start):**
|
|
68
|
+
Skeleton API:
|
|
49
69
|
|
|
50
70
|
```bash
|
|
51
71
|
hazel g app my-app
|
|
52
72
|
cd my-app && npm install && npm run dev
|
|
53
73
|
```
|
|
54
74
|
|
|
55
|
-
|
|
75
|
+
Interactive package selection:
|
|
56
76
|
|
|
57
77
|
```bash
|
|
58
78
|
hazel new my-app -i
|
|
@@ -218,6 +238,17 @@ hazel g serverless handler --platform lambda
|
|
|
218
238
|
## Quick Reference
|
|
219
239
|
|
|
220
240
|
```bash
|
|
241
|
+
# Agent OS
|
|
242
|
+
hazel agent new <name> [--template agent-os|bare|skillgate]
|
|
243
|
+
hazel agent install <dna>
|
|
244
|
+
hazel agent run | doctor | logs
|
|
245
|
+
hazel agent runs list | inspect | cancel | resume | approve
|
|
246
|
+
hazel store publish | install | list
|
|
247
|
+
hazel skillgate from-openapi <spec>
|
|
248
|
+
hazel gatekeeper validate | simulate | explain
|
|
249
|
+
hazel benchmark
|
|
250
|
+
hazel eval
|
|
251
|
+
|
|
221
252
|
# Project Management
|
|
222
253
|
hazel new <name> [-i] # Create new project
|
|
223
254
|
hazel info # Show project info
|
package/cli-manifest.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "Machine-readable manifest of all CLI commands and options for LLM agent tool-use",
|
|
5
5
|
"cli": {
|
|
6
6
|
"name": "hazel",
|
|
7
|
-
"version": "2.0.
|
|
7
|
+
"version": "2.0.6",
|
|
8
8
|
"description": "CLI for generating HazelJS components and applications"
|
|
9
9
|
},
|
|
10
10
|
"commands": [
|
|
@@ -746,6 +746,12 @@
|
|
|
746
746
|
"label": "Configuration (@hazeljs/config)",
|
|
747
747
|
"description": "Environment-based configuration management"
|
|
748
748
|
},
|
|
749
|
+
{
|
|
750
|
+
"shortName": "config-server",
|
|
751
|
+
"npm": "@hazeljs/config-server",
|
|
752
|
+
"label": "Git config server (@hazeljs/config-server)",
|
|
753
|
+
"description": "Git-backed distributed configuration (Spring Cloud Config style)"
|
|
754
|
+
},
|
|
749
755
|
{
|
|
750
756
|
"shortName": "cron",
|
|
751
757
|
"npm": "@hazeljs/cron",
|
|
@@ -54,7 +54,7 @@ exports.AGENT_TEMPLATES = [
|
|
|
54
54
|
{
|
|
55
55
|
id: 'agent-os',
|
|
56
56
|
label: 'Agent OS mini-app',
|
|
57
|
-
description: 'DNA + real @Agent/@Tool
|
|
57
|
+
description: 'DNA + real @Agent/@Tool app + ops stack (self-healing + predictive scaling) + K8s manifests',
|
|
58
58
|
},
|
|
59
59
|
{
|
|
60
60
|
id: 'skillgate',
|
|
@@ -156,6 +156,235 @@ Wire real \`@Tool\` / Skillgate handlers in your Hazel app for production behavi
|
|
|
156
156
|
`,
|
|
157
157
|
};
|
|
158
158
|
}
|
|
159
|
+
function agentOsOpsFiles(npm, projectName) {
|
|
160
|
+
const deployment = npm;
|
|
161
|
+
const hpaName = `${npm}-hpa`;
|
|
162
|
+
return {
|
|
163
|
+
'.env.example': `# Agent runtime
|
|
164
|
+
HITL=0
|
|
165
|
+
|
|
166
|
+
# Ops stack (proactive scaling + reactive self-healing)
|
|
167
|
+
ENABLE_OPS_STACK=0
|
|
168
|
+
K8S_DEPLOYMENT=${deployment}
|
|
169
|
+
K8S_NAMESPACE=default
|
|
170
|
+
K8S_HPA_NAME=${hpaName}
|
|
171
|
+
PROMETHEUS_URL=http://prometheus.monitoring.svc:9090
|
|
172
|
+
SLACK_BOT_TOKEN=
|
|
173
|
+
PAGERDUTY_ROUTING_KEY=
|
|
174
|
+
`,
|
|
175
|
+
'src/ops/stack.ts': `import { createOperationsStack } from '@hazeljs/predictive-scaling';
|
|
176
|
+
import {
|
|
177
|
+
FetchKubernetesRestartClient,
|
|
178
|
+
FetchKubernetesScalingClient,
|
|
179
|
+
createSlackHealingNotifier,
|
|
180
|
+
createHealingNotifierChain,
|
|
181
|
+
InMemoryKubernetesRestartClient,
|
|
182
|
+
InMemoryKubernetesScalingClient,
|
|
183
|
+
} from '@hazeljs/self-healing';
|
|
184
|
+
|
|
185
|
+
export function createAgentOpsStack(appName: string) {
|
|
186
|
+
const deployment = process.env.K8S_DEPLOYMENT ?? appName;
|
|
187
|
+
const namespace = process.env.K8S_NAMESPACE ?? 'default';
|
|
188
|
+
const hpaName = process.env.K8S_HPA_NAME ?? \`\${deployment}-hpa\`;
|
|
189
|
+
const inCluster = Boolean(process.env.KUBERNETES_SERVICE_HOST);
|
|
190
|
+
|
|
191
|
+
const scalingClient = inCluster
|
|
192
|
+
? new FetchKubernetesScalingClient()
|
|
193
|
+
: new InMemoryKubernetesScalingClient();
|
|
194
|
+
const restartClient = inCluster
|
|
195
|
+
? new FetchKubernetesRestartClient()
|
|
196
|
+
: new InMemoryKubernetesRestartClient();
|
|
197
|
+
|
|
198
|
+
const notifications = [];
|
|
199
|
+
if (process.env.SLACK_BOT_TOKEN) {
|
|
200
|
+
notifications.push(
|
|
201
|
+
createSlackHealingNotifier({
|
|
202
|
+
token: process.env.SLACK_BOT_TOKEN,
|
|
203
|
+
channel: process.env.SLACK_ALERT_CHANNEL ?? '#ops-alerts',
|
|
204
|
+
})
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
return createOperationsStack({
|
|
209
|
+
healing: {
|
|
210
|
+
strategies: ['config-rollback', 'hpa-boost', 'pod-restart', 'safe-mode'],
|
|
211
|
+
aiDiagnostics: true,
|
|
212
|
+
drain: { timeoutMs: 30_000 },
|
|
213
|
+
notifyOn: ['critical-healing', 'healing-failed', 'hpa-boost', 'pod-restart'],
|
|
214
|
+
notifications: notifications.length ? createHealingNotifierChain(notifications) : undefined,
|
|
215
|
+
kubernetes: {
|
|
216
|
+
deployment,
|
|
217
|
+
namespace,
|
|
218
|
+
client: restartClient,
|
|
219
|
+
drainBeforeRestart: true,
|
|
220
|
+
hpa: {
|
|
221
|
+
name: hpaName,
|
|
222
|
+
namespace,
|
|
223
|
+
client: scalingClient,
|
|
224
|
+
boostMinReplicas: Number(process.env.HPA_BOOST_MIN ?? 4),
|
|
225
|
+
restoreAfterMs: Number(process.env.HPA_RESTORE_MS ?? 300_000),
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
performance: {
|
|
229
|
+
enabled: true,
|
|
230
|
+
autoScaleOnDegradation: true,
|
|
231
|
+
thresholds: { criticalLatencyMs: 2000, sampleSize: 20 },
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
scaling: {
|
|
235
|
+
model: 'time-series-forecast',
|
|
236
|
+
metrics: ['requests', 'latency', 'cpu'],
|
|
237
|
+
horizon: '30m',
|
|
238
|
+
confidence: 0.85,
|
|
239
|
+
capacityPerReplica: Number(process.env.CAPACITY_PER_REPLICA ?? 120),
|
|
240
|
+
hpa: {
|
|
241
|
+
name: hpaName,
|
|
242
|
+
namespace,
|
|
243
|
+
client: scalingClient,
|
|
244
|
+
maxReplicas: Number(process.env.HPA_MAX_REPLICAS ?? 50),
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
prometheus: process.env.PROMETHEUS_URL
|
|
248
|
+
? {
|
|
249
|
+
baseUrl: process.env.PROMETHEUS_URL,
|
|
250
|
+
pollIntervalMs: 60_000,
|
|
251
|
+
queries: {
|
|
252
|
+
requests: \`sum(rate(http_requests_total{service="${deployment}"}[5m]))\`,
|
|
253
|
+
latency:
|
|
254
|
+
\`histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{service="${deployment}"}[5m])) by (le))\`,
|
|
255
|
+
cpu: \`avg(rate(container_cpu_usage_seconds_total{pod=~"${deployment}-.*"}[5m]))\`,
|
|
256
|
+
},
|
|
257
|
+
}
|
|
258
|
+
: undefined,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let opsStack: ReturnType<typeof createAgentOpsStack> | null = null;
|
|
263
|
+
|
|
264
|
+
export function startAgentOpsStack(appName: string) {
|
|
265
|
+
if (opsStack) return opsStack;
|
|
266
|
+
opsStack = createAgentOpsStack(appName);
|
|
267
|
+
opsStack.start();
|
|
268
|
+
return opsStack;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
export function stopAgentOpsStack() {
|
|
272
|
+
opsStack?.stop();
|
|
273
|
+
opsStack = null;
|
|
274
|
+
}
|
|
275
|
+
`,
|
|
276
|
+
'deploy/kubernetes/deployment.yaml': `apiVersion: apps/v1
|
|
277
|
+
kind: Deployment
|
|
278
|
+
metadata:
|
|
279
|
+
name: ${deployment}
|
|
280
|
+
labels:
|
|
281
|
+
app: ${deployment}
|
|
282
|
+
spec:
|
|
283
|
+
replicas: 2
|
|
284
|
+
selector:
|
|
285
|
+
matchLabels:
|
|
286
|
+
app: ${deployment}
|
|
287
|
+
template:
|
|
288
|
+
metadata:
|
|
289
|
+
labels:
|
|
290
|
+
app: ${deployment}
|
|
291
|
+
spec:
|
|
292
|
+
serviceAccountName: ${deployment}
|
|
293
|
+
containers:
|
|
294
|
+
- name: agent
|
|
295
|
+
image: ${deployment}:latest
|
|
296
|
+
env:
|
|
297
|
+
- name: ENABLE_OPS_STACK
|
|
298
|
+
value: "1"
|
|
299
|
+
- name: K8S_DEPLOYMENT
|
|
300
|
+
value: ${deployment}
|
|
301
|
+
- name: K8S_HPA_NAME
|
|
302
|
+
value: ${hpaName}
|
|
303
|
+
- name: PROMETHEUS_URL
|
|
304
|
+
value: http://prometheus.monitoring.svc:9090
|
|
305
|
+
resources:
|
|
306
|
+
requests:
|
|
307
|
+
cpu: 250m
|
|
308
|
+
memory: 512Mi
|
|
309
|
+
limits:
|
|
310
|
+
cpu: "1"
|
|
311
|
+
memory: 1Gi
|
|
312
|
+
`,
|
|
313
|
+
'deploy/kubernetes/hpa.yaml': `apiVersion: autoscaling/v2
|
|
314
|
+
kind: HorizontalPodAutoscaler
|
|
315
|
+
metadata:
|
|
316
|
+
name: ${hpaName}
|
|
317
|
+
spec:
|
|
318
|
+
scaleTargetRef:
|
|
319
|
+
apiVersion: apps/v1
|
|
320
|
+
kind: Deployment
|
|
321
|
+
name: ${deployment}
|
|
322
|
+
minReplicas: 2
|
|
323
|
+
maxReplicas: 50
|
|
324
|
+
metrics:
|
|
325
|
+
- type: Resource
|
|
326
|
+
resource:
|
|
327
|
+
name: cpu
|
|
328
|
+
target:
|
|
329
|
+
type: Utilization
|
|
330
|
+
averageUtilization: 70
|
|
331
|
+
- type: Resource
|
|
332
|
+
resource:
|
|
333
|
+
name: memory
|
|
334
|
+
target:
|
|
335
|
+
type: Utilization
|
|
336
|
+
averageUtilization: 80
|
|
337
|
+
`,
|
|
338
|
+
'deploy/kubernetes/service.yaml': `apiVersion: v1
|
|
339
|
+
kind: Service
|
|
340
|
+
metadata:
|
|
341
|
+
name: ${deployment}
|
|
342
|
+
spec:
|
|
343
|
+
selector:
|
|
344
|
+
app: ${deployment}
|
|
345
|
+
ports:
|
|
346
|
+
- port: 80
|
|
347
|
+
targetPort: 3000
|
|
348
|
+
`,
|
|
349
|
+
'deploy/kubernetes/serviceaccount.yaml': `apiVersion: v1
|
|
350
|
+
kind: ServiceAccount
|
|
351
|
+
metadata:
|
|
352
|
+
name: ${deployment}
|
|
353
|
+
---
|
|
354
|
+
apiVersion: rbac.authorization.k8s.io/v1
|
|
355
|
+
kind: Role
|
|
356
|
+
metadata:
|
|
357
|
+
name: ${deployment}-ops
|
|
358
|
+
rules:
|
|
359
|
+
- apiGroups: ["autoscaling"]
|
|
360
|
+
resources: ["horizontalpodautoscalers"]
|
|
361
|
+
verbs: ["get", "patch", "update"]
|
|
362
|
+
- apiGroups: ["apps"]
|
|
363
|
+
resources: ["deployments"]
|
|
364
|
+
verbs: ["get", "patch", "update"]
|
|
365
|
+
---
|
|
366
|
+
apiVersion: rbac.authorization.k8s.io/v1
|
|
367
|
+
kind: RoleBinding
|
|
368
|
+
metadata:
|
|
369
|
+
name: ${deployment}-ops
|
|
370
|
+
subjects:
|
|
371
|
+
- kind: ServiceAccount
|
|
372
|
+
name: ${deployment}
|
|
373
|
+
roleRef:
|
|
374
|
+
apiGroup: rbac.authorization.k8s.io
|
|
375
|
+
kind: Role
|
|
376
|
+
name: ${deployment}-ops
|
|
377
|
+
`,
|
|
378
|
+
'deploy/kubernetes/kustomization.yaml': `apiVersion: kustomize.config.k8s.io/v1beta1
|
|
379
|
+
kind: Kustomization
|
|
380
|
+
resources:
|
|
381
|
+
- serviceaccount.yaml
|
|
382
|
+
- deployment.yaml
|
|
383
|
+
- service.yaml
|
|
384
|
+
- hpa.yaml
|
|
385
|
+
`,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
159
388
|
function agentOsFiles(projectName) {
|
|
160
389
|
const dnaName = agentDnaName(projectName);
|
|
161
390
|
const npm = sanitizeNpmName(projectName);
|
|
@@ -197,6 +426,8 @@ Use lookupOrder for facts. Call processRefund only after lookup. Be concise.`,
|
|
|
197
426
|
},
|
|
198
427
|
dependencies: {
|
|
199
428
|
'@hazeljs/agent': '^1.0.6',
|
|
429
|
+
'@hazeljs/self-healing': '^2.0.5',
|
|
430
|
+
'@hazeljs/predictive-scaling': '^2.0.5',
|
|
200
431
|
},
|
|
201
432
|
devDependencies: {
|
|
202
433
|
'@types/node': '^20.19.39',
|
|
@@ -279,9 +510,16 @@ import {
|
|
|
279
510
|
type AgentEvent,
|
|
280
511
|
} from '@hazeljs/agent';
|
|
281
512
|
import { SupportAgent } from './support.agent';
|
|
513
|
+
import { startAgentOpsStack, stopAgentOpsStack } from './ops/stack';
|
|
282
514
|
|
|
283
515
|
async function main() {
|
|
284
516
|
const input = process.argv.slice(2).join(' ') || 'Where is ORD-1001?';
|
|
517
|
+
|
|
518
|
+
if (process.env.ENABLE_OPS_STACK === '1') {
|
|
519
|
+
startAgentOpsStack('${npm}');
|
|
520
|
+
process.on('SIGINT', () => stopAgentOpsStack());
|
|
521
|
+
process.on('SIGTERM', () => stopAgentOpsStack());
|
|
522
|
+
}
|
|
285
523
|
// Demo uses mock LLM. Wire OpenAI (or another provider) in production apps.
|
|
286
524
|
const llm = createMockLlmProvider(
|
|
287
525
|
'Used real @Tool handlers on AgentRuntime. (Replace createMockLlmProvider with your LLM.)'
|
|
@@ -326,6 +564,8 @@ main().catch((e) => {
|
|
|
326
564
|
| \`dna/agent.marketplace.json\` | DNA / marketplace package (OpenAPI-for-agents) |
|
|
327
565
|
| \`src/support.agent.ts\` | Real tool handlers |
|
|
328
566
|
| \`src/main.ts\` | AgentRuntime bootstrap + optional DNA overlay |
|
|
567
|
+
| \`src/ops/stack.ts\` | Predictive scaling + self-healing ops stack |
|
|
568
|
+
| \`deploy/kubernetes/\` | K8s Deployment, HPA, RBAC for in-cluster ops |
|
|
329
569
|
|
|
330
570
|
## Quick start
|
|
331
571
|
|
|
@@ -343,7 +583,21 @@ npm run store:install
|
|
|
343
583
|
\`\`\`
|
|
344
584
|
|
|
345
585
|
Set \`HITL=1\` to pause on \`processRefund\` approvals.
|
|
586
|
+
|
|
587
|
+
## Production ops (predictive + self-healing)
|
|
588
|
+
|
|
589
|
+
\`\`\`bash
|
|
590
|
+
cp .env.example .env
|
|
591
|
+
ENABLE_OPS_STACK=1 npm run dev
|
|
592
|
+
|
|
593
|
+
# Deploy to Kubernetes (requires kubectl + kustomize)
|
|
594
|
+
kubectl apply -k deploy/kubernetes
|
|
595
|
+
\`\`\`
|
|
596
|
+
|
|
597
|
+
- **Proactive:** \`@hazeljs/predictive-scaling\` forecasts traffic and adjusts HPA min replicas
|
|
598
|
+
- **Reactive:** \`@hazeljs/self-healing\` heals failures, drains pods, opens Slack/Jira alerts
|
|
346
599
|
`,
|
|
600
|
+
...agentOsOpsFiles(npm, projectName),
|
|
347
601
|
};
|
|
348
602
|
}
|
|
349
603
|
function skillgateFiles(projectName) {
|
|
@@ -88,8 +88,12 @@ describe('agent templates scaffold', () => {
|
|
|
88
88
|
(0, agent_templates_1.scaffoldAgentProject)({ name: 'os-demo', destDir: dest, template: 'agent-os' });
|
|
89
89
|
expect(fs.existsSync(path.join(dest, 'src/support.agent.ts'))).toBe(true);
|
|
90
90
|
expect(fs.existsSync(path.join(dest, 'src/main.ts'))).toBe(true);
|
|
91
|
+
expect(fs.existsSync(path.join(dest, 'src/ops/stack.ts'))).toBe(true);
|
|
92
|
+
expect(fs.existsSync(path.join(dest, 'deploy/kubernetes/hpa.yaml'))).toBe(true);
|
|
91
93
|
expect(fs.existsSync(path.join(dest, 'dna/agent.marketplace.json'))).toBe(true);
|
|
92
94
|
const pkg = JSON.parse(fs.readFileSync(path.join(dest, 'package.json'), 'utf8'));
|
|
95
|
+
expect(pkg.dependencies['@hazeljs/self-healing']).toBe('^2.0.5');
|
|
96
|
+
expect(pkg.dependencies['@hazeljs/predictive-scaling']).toBe('^2.0.5');
|
|
93
97
|
expect(pkg.dependencies['reflect-metadata']).toBeUndefined();
|
|
94
98
|
const main = fs.readFileSync(path.join(dest, 'src/main.ts'), 'utf8');
|
|
95
99
|
const agent = fs.readFileSync(path.join(dest, 'src/support.agent.ts'), 'utf8');
|
|
@@ -91,6 +91,22 @@ export const oauthImports = [
|
|
|
91
91
|
moduleExpression: "ConfigModule.forRoot({ envFilePath: '.env' })",
|
|
92
92
|
setupTemplate: null,
|
|
93
93
|
},
|
|
94
|
+
{
|
|
95
|
+
shortName: 'config-server',
|
|
96
|
+
npm: '@hazeljs/config-server',
|
|
97
|
+
label: 'Git config server (@hazeljs/config-server)',
|
|
98
|
+
hint: 'import { ConfigServer } from "@hazeljs/config-server";\n // await new ConfigServer({ git: { uri: process.env.CONFIG_GIT_URI! }, port: 8888 }).start()',
|
|
99
|
+
moduleImport: "import { ConfigServerModule } from '@hazeljs/config-server';",
|
|
100
|
+
moduleExpression: "ConfigServerModule.forRoot({ git: { uri: process.env.CONFIG_GIT_URI || '' }, port: 8888 })",
|
|
101
|
+
setupTemplate: `import { ConfigServerModule } from '@hazeljs/config-server';
|
|
102
|
+
|
|
103
|
+
// Add ConfigServerModule.forRoot(...) to your HazelModule imports, then start:
|
|
104
|
+
// await new ConfigServer({ git: { uri: process.env.CONFIG_GIT_URI! }, port: 8888 }).start();
|
|
105
|
+
export const configServerImports = [
|
|
106
|
+
ConfigServerModule.forRoot({ git: { uri: process.env.CONFIG_GIT_URI || '' }, port: 8888 }),
|
|
107
|
+
];
|
|
108
|
+
`,
|
|
109
|
+
},
|
|
94
110
|
{
|
|
95
111
|
shortName: 'cron',
|
|
96
112
|
npm: '@hazeljs/cron',
|
|
@@ -363,6 +379,37 @@ export class ExampleResilienceService {
|
|
|
363
379
|
return 'ok';
|
|
364
380
|
}
|
|
365
381
|
}
|
|
382
|
+
`,
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
shortName: 'self-healing',
|
|
386
|
+
npm: '@hazeljs/self-healing',
|
|
387
|
+
label: 'Self-Healing Microservices (@hazeljs/self-healing)',
|
|
388
|
+
hint: 'import { SelfHealing, SelfHeal, createHealingCoordinator } from "@hazeljs/self-healing";',
|
|
389
|
+
moduleImport: null,
|
|
390
|
+
moduleExpression: null,
|
|
391
|
+
setupTemplate: `import { createHealingCoordinator } from '@hazeljs/self-healing';
|
|
392
|
+
|
|
393
|
+
export const healing = createHealingCoordinator({
|
|
394
|
+
strategies: ['config-rollback', 'hpa-boost', 'pod-restart'],
|
|
395
|
+
});
|
|
396
|
+
`,
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
shortName: 'predictive-scaling',
|
|
400
|
+
npm: '@hazeljs/predictive-scaling',
|
|
401
|
+
label: 'Predictive Auto-Scaling (@hazeljs/predictive-scaling)',
|
|
402
|
+
hint: 'import { PredictiveScaling, createPredictiveScaler } from "@hazeljs/predictive-scaling";',
|
|
403
|
+
moduleImport: null,
|
|
404
|
+
moduleExpression: null,
|
|
405
|
+
setupTemplate: `import { createPredictiveScaler } from '@hazeljs/predictive-scaling';
|
|
406
|
+
|
|
407
|
+
// Wire hpa.client to your Kubernetes scaling client
|
|
408
|
+
export const scaler = createPredictiveScaler({
|
|
409
|
+
horizon: '30m',
|
|
410
|
+
metrics: ['requests', 'latency'],
|
|
411
|
+
hpa: { name: 'api-hpa', client: scalingClient },
|
|
412
|
+
});
|
|
366
413
|
`,
|
|
367
414
|
},
|
|
368
415
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hazeljs/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.6",
|
|
4
4
|
"description": "Command-line interface for scaffolding and generating HazelJS applications and components",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -31,11 +31,11 @@
|
|
|
31
31
|
"mustache": "^4.2.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependencies": {
|
|
34
|
-
"@hazeljs/eval": "^2.0.
|
|
35
|
-
"@hazeljs/benchmark": "^2.0.
|
|
36
|
-
"@hazeljs/agent": "^2.0.
|
|
37
|
-
"@hazeljs/skillgate": "^2.0.
|
|
38
|
-
"@hazeljs/agent-gatekeeper": "^2.0.
|
|
34
|
+
"@hazeljs/eval": "^2.0.6",
|
|
35
|
+
"@hazeljs/benchmark": "^2.0.6",
|
|
36
|
+
"@hazeljs/agent": "^2.0.6",
|
|
37
|
+
"@hazeljs/skillgate": "^2.0.6",
|
|
38
|
+
"@hazeljs/agent-gatekeeper": "^2.0.6"
|
|
39
39
|
},
|
|
40
40
|
"peerDependenciesMeta": {
|
|
41
41
|
"@hazeljs/eval": {
|
|
@@ -55,11 +55,11 @@
|
|
|
55
55
|
}
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@hazeljs/eval": "^2.0.
|
|
59
|
-
"@hazeljs/benchmark": "^2.0.
|
|
60
|
-
"@hazeljs/agent": "^2.0.
|
|
61
|
-
"@hazeljs/skillgate": "^2.0.
|
|
62
|
-
"@hazeljs/agent-gatekeeper": "^2.0.
|
|
58
|
+
"@hazeljs/eval": "^2.0.6",
|
|
59
|
+
"@hazeljs/benchmark": "^2.0.6",
|
|
60
|
+
"@hazeljs/agent": "^2.0.6",
|
|
61
|
+
"@hazeljs/skillgate": "^2.0.6",
|
|
62
|
+
"@hazeljs/agent-gatekeeper": "^2.0.6",
|
|
63
63
|
"@types/inquirer": "^8.2.10",
|
|
64
64
|
"@types/mustache": "^4.2.5",
|
|
65
65
|
"typescript": "^6.0.3"
|