@soleri/core 9.3.1 → 9.5.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/dist/brain/intelligence.d.ts +5 -0
- package/dist/brain/intelligence.d.ts.map +1 -1
- package/dist/brain/intelligence.js +115 -26
- package/dist/brain/intelligence.js.map +1 -1
- package/dist/brain/learning-radar.d.ts +3 -3
- package/dist/brain/learning-radar.d.ts.map +1 -1
- package/dist/brain/learning-radar.js +8 -4
- package/dist/brain/learning-radar.js.map +1 -1
- package/dist/control/intent-router.d.ts +2 -2
- package/dist/control/intent-router.d.ts.map +1 -1
- package/dist/control/intent-router.js +35 -1
- package/dist/control/intent-router.js.map +1 -1
- package/dist/control/types.d.ts +10 -2
- package/dist/control/types.d.ts.map +1 -1
- package/dist/curator/curator.d.ts +4 -0
- package/dist/curator/curator.d.ts.map +1 -1
- package/dist/curator/curator.js +23 -1
- package/dist/curator/curator.js.map +1 -1
- package/dist/curator/schema.d.ts +1 -1
- package/dist/curator/schema.d.ts.map +1 -1
- package/dist/curator/schema.js +8 -0
- package/dist/curator/schema.js.map +1 -1
- package/dist/domain-packs/types.d.ts +6 -0
- package/dist/domain-packs/types.d.ts.map +1 -1
- package/dist/domain-packs/types.js +1 -0
- package/dist/domain-packs/types.js.map +1 -1
- package/dist/engine/module-manifest.js +3 -3
- package/dist/engine/module-manifest.js.map +1 -1
- package/dist/engine/register-engine.d.ts +9 -0
- package/dist/engine/register-engine.d.ts.map +1 -1
- package/dist/engine/register-engine.js +59 -1
- package/dist/engine/register-engine.js.map +1 -1
- package/dist/facades/types.d.ts +5 -1
- package/dist/facades/types.d.ts.map +1 -1
- package/dist/facades/types.js.map +1 -1
- package/dist/hooks/candidate-scorer.d.ts +28 -0
- package/dist/hooks/candidate-scorer.d.ts.map +1 -0
- package/dist/hooks/candidate-scorer.js +20 -0
- package/dist/hooks/candidate-scorer.js.map +1 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/operator/operator-context-store.d.ts +54 -0
- package/dist/operator/operator-context-store.d.ts.map +1 -0
- package/dist/operator/operator-context-store.js +434 -0
- package/dist/operator/operator-context-store.js.map +1 -0
- package/dist/operator/operator-context-types.d.ts +101 -0
- package/dist/operator/operator-context-types.d.ts.map +1 -0
- package/dist/operator/operator-context-types.js +27 -0
- package/dist/operator/operator-context-types.js.map +1 -0
- package/dist/packs/index.d.ts +2 -2
- package/dist/packs/index.d.ts.map +1 -1
- package/dist/packs/index.js +1 -1
- package/dist/packs/index.js.map +1 -1
- package/dist/packs/lockfile.d.ts +3 -0
- package/dist/packs/lockfile.d.ts.map +1 -1
- package/dist/packs/lockfile.js.map +1 -1
- package/dist/packs/types.d.ts +8 -2
- package/dist/packs/types.d.ts.map +1 -1
- package/dist/packs/types.js +6 -0
- package/dist/packs/types.js.map +1 -1
- package/dist/planning/plan-lifecycle.d.ts +12 -1
- package/dist/planning/plan-lifecycle.d.ts.map +1 -1
- package/dist/planning/plan-lifecycle.js +54 -16
- package/dist/planning/plan-lifecycle.js.map +1 -1
- package/dist/planning/planner-types.d.ts +6 -0
- package/dist/planning/planner-types.d.ts.map +1 -1
- package/dist/planning/planner.d.ts +21 -1
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +62 -3
- package/dist/planning/planner.js.map +1 -1
- package/dist/planning/task-complexity-assessor.d.ts.map +1 -1
- package/dist/planning/task-complexity-assessor.js.map +1 -1
- package/dist/plugins/types.d.ts +18 -18
- package/dist/runtime/admin-ops.d.ts +1 -1
- package/dist/runtime/admin-ops.d.ts.map +1 -1
- package/dist/runtime/admin-ops.js +100 -3
- package/dist/runtime/admin-ops.js.map +1 -1
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
- package/dist/runtime/admin-setup-ops.js +19 -9
- package/dist/runtime/admin-setup-ops.js.map +1 -1
- package/dist/runtime/capture-ops.d.ts.map +1 -1
- package/dist/runtime/capture-ops.js +35 -7
- package/dist/runtime/capture-ops.js.map +1 -1
- package/dist/runtime/facades/brain-facade.d.ts.map +1 -1
- package/dist/runtime/facades/brain-facade.js +4 -2
- package/dist/runtime/facades/brain-facade.js.map +1 -1
- package/dist/runtime/facades/control-facade.d.ts.map +1 -1
- package/dist/runtime/facades/control-facade.js +8 -2
- package/dist/runtime/facades/control-facade.js.map +1 -1
- package/dist/runtime/facades/curator-facade.d.ts.map +1 -1
- package/dist/runtime/facades/curator-facade.js +13 -0
- package/dist/runtime/facades/curator-facade.js.map +1 -1
- package/dist/runtime/facades/memory-facade.d.ts.map +1 -1
- package/dist/runtime/facades/memory-facade.js +10 -12
- package/dist/runtime/facades/memory-facade.js.map +1 -1
- package/dist/runtime/facades/orchestrate-facade.d.ts.map +1 -1
- package/dist/runtime/facades/orchestrate-facade.js +36 -1
- package/dist/runtime/facades/orchestrate-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +20 -4
- package/dist/runtime/facades/plan-facade.js.map +1 -1
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
- package/dist/runtime/orchestrate-ops.js +71 -4
- package/dist/runtime/orchestrate-ops.js.map +1 -1
- package/dist/runtime/plan-feedback-helper.d.ts +21 -0
- package/dist/runtime/plan-feedback-helper.d.ts.map +1 -0
- package/dist/runtime/plan-feedback-helper.js +52 -0
- package/dist/runtime/plan-feedback-helper.js.map +1 -0
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
- package/dist/runtime/planning-extra-ops.js +73 -34
- package/dist/runtime/planning-extra-ops.js.map +1 -1
- package/dist/runtime/session-briefing.d.ts.map +1 -1
- package/dist/runtime/session-briefing.js +9 -1
- package/dist/runtime/session-briefing.js.map +1 -1
- package/dist/runtime/types.d.ts +3 -0
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/skills/sync-skills.d.ts.map +1 -1
- package/dist/skills/sync-skills.js +13 -7
- package/dist/skills/sync-skills.js.map +1 -1
- package/package.json +1 -1
- package/src/brain/brain-intelligence.test.ts +30 -0
- package/src/brain/brain.ts +120 -46
- package/src/brain/extraction-quality.test.ts +323 -0
- package/src/brain/intelligence.ts +175 -64
- package/src/brain/learning-radar.ts +8 -5
- package/src/brain/second-brain-features.test.ts +1 -1
- package/src/chat/agent-loop.ts +1 -1
- package/src/chat/notifications.ts +4 -0
- package/src/control/intent-router.test.ts +73 -3
- package/src/control/intent-router.ts +48 -9
- package/src/control/types.ts +13 -2
- package/src/curator/curator.test.ts +92 -0
- package/src/curator/curator.ts +162 -18
- package/src/curator/schema.ts +8 -0
- package/src/domain-packs/types.ts +8 -0
- package/src/engine/module-manifest.test.ts +8 -2
- package/src/engine/module-manifest.ts +3 -3
- package/src/engine/register-engine.test.ts +73 -1
- package/src/engine/register-engine.ts +61 -1
- package/src/facades/types.ts +5 -0
- package/src/hooks/candidate-scorer.test.ts +76 -0
- package/src/hooks/candidate-scorer.ts +39 -0
- package/src/hooks/index.ts +6 -0
- package/src/index.ts +24 -0
- package/src/llm/llm-client.ts +1 -0
- package/src/operator/operator-context-store.test.ts +698 -0
- package/src/operator/operator-context-store.ts +569 -0
- package/src/operator/operator-context-types.ts +139 -0
- package/src/packs/index.ts +3 -1
- package/src/packs/lockfile.ts +3 -0
- package/src/packs/types.ts +9 -0
- package/src/persistence/sqlite-provider.ts +1 -0
- package/src/planning/github-projection.ts +48 -44
- package/src/planning/plan-lifecycle.ts +93 -22
- package/src/planning/planner-types.ts +6 -0
- package/src/planning/planner.ts +74 -4
- package/src/planning/task-complexity-assessor.test.ts +6 -2
- package/src/planning/task-complexity-assessor.ts +1 -4
- package/src/queue/pipeline-runner.ts +4 -0
- package/src/runtime/admin-ops.test.ts +139 -6
- package/src/runtime/admin-ops.ts +104 -3
- package/src/runtime/admin-setup-ops.ts +30 -10
- package/src/runtime/capture-ops.test.ts +84 -0
- package/src/runtime/capture-ops.ts +35 -7
- package/src/runtime/curator-extra-ops.test.ts +7 -0
- package/src/runtime/curator-extra-ops.ts +10 -1
- package/src/runtime/facades/admin-facade.test.ts +1 -1
- package/src/runtime/facades/brain-facade.ts +6 -3
- package/src/runtime/facades/control-facade.ts +10 -2
- package/src/runtime/facades/curator-facade.test.ts +7 -0
- package/src/runtime/facades/curator-facade.ts +18 -0
- package/src/runtime/facades/memory-facade.test.ts +14 -12
- package/src/runtime/facades/memory-facade.ts +197 -12
- package/src/runtime/facades/orchestrate-facade.ts +33 -1
- package/src/runtime/facades/plan-facade.test.ts +213 -0
- package/src/runtime/facades/plan-facade.ts +23 -4
- package/src/runtime/orchestrate-ops.test.ts +202 -2
- package/src/runtime/orchestrate-ops.ts +88 -7
- package/src/runtime/plan-feedback-helper.test.ts +173 -0
- package/src/runtime/plan-feedback-helper.ts +63 -0
- package/src/runtime/planning-extra-ops.test.ts +43 -1
- package/src/runtime/planning-extra-ops.ts +96 -33
- package/src/runtime/runtime.test.ts +50 -2
- package/src/runtime/runtime.ts +117 -89
- package/src/runtime/session-briefing.test.ts +1 -0
- package/src/runtime/session-briefing.ts +10 -1
- package/src/runtime/shutdown-registry.test.ts +151 -0
- package/src/runtime/shutdown-registry.ts +85 -0
- package/src/runtime/types.ts +7 -1
- package/src/skills/sync-skills.ts +14 -7
- package/src/transport/http-server.ts +50 -3
- package/src/transport/ws-server.ts +8 -0
- package/src/vault/linking.test.ts +12 -0
- package/src/vault/linking.ts +90 -44
- package/src/vault/vault-maintenance.ts +11 -18
- package/src/vault/vault-memories.ts +21 -13
- package/src/vault/vault-schema.ts +21 -0
- package/src/vault/vault.ts +8 -3
- package/vitest.config.ts +1 -0
|
@@ -35,6 +35,9 @@ function mockRuntime(): AgentRuntime {
|
|
|
35
35
|
curator: {
|
|
36
36
|
getStatus: vi.fn().mockReturnValue({ initialized: true }),
|
|
37
37
|
},
|
|
38
|
+
packInstaller: {
|
|
39
|
+
list: vi.fn().mockReturnValue([]),
|
|
40
|
+
},
|
|
38
41
|
contextHealth: {
|
|
39
42
|
check: vi.fn().mockReturnValue({
|
|
40
43
|
level: 'green',
|
|
@@ -67,8 +70,8 @@ describe('createAdminOps', () => {
|
|
|
67
70
|
ops = createAdminOps(rt);
|
|
68
71
|
});
|
|
69
72
|
|
|
70
|
-
it('returns
|
|
71
|
-
expect(ops.length).toBe(
|
|
73
|
+
it('returns 11 ops', () => {
|
|
74
|
+
expect(ops.length).toBe(11);
|
|
72
75
|
});
|
|
73
76
|
|
|
74
77
|
// ─── admin_health ─────────────────────────────────────────────
|
|
@@ -98,6 +101,50 @@ describe('createAdminOps', () => {
|
|
|
98
101
|
expect(llm.openai).toBe(true);
|
|
99
102
|
expect(llm.anthropic).toBe(false);
|
|
100
103
|
});
|
|
104
|
+
|
|
105
|
+
it('reports skills status', async () => {
|
|
106
|
+
const op = findOp(ops, 'admin_health');
|
|
107
|
+
const result = (await op.handler({})) as Record<string, unknown>;
|
|
108
|
+
const skills = result.skills as Record<string, unknown>;
|
|
109
|
+
expect(skills).toBeDefined();
|
|
110
|
+
expect(skills.count).toBe(0);
|
|
111
|
+
expect(skills.agent).toEqual([]);
|
|
112
|
+
expect(skills.packs).toEqual([]);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('reports hooks status', async () => {
|
|
116
|
+
const op = findOp(ops, 'admin_health');
|
|
117
|
+
const result = (await op.handler({})) as Record<string, unknown>;
|
|
118
|
+
const hooks = result.hooks as Record<string, unknown>;
|
|
119
|
+
expect(hooks).toBeDefined();
|
|
120
|
+
expect(hooks.count).toBe(0);
|
|
121
|
+
expect(hooks.packs).toEqual([]);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('includes pack skills and hooks when packs are installed', async () => {
|
|
125
|
+
vi.mocked(rt.packInstaller.list).mockReturnValue([
|
|
126
|
+
{
|
|
127
|
+
id: 'test-pack',
|
|
128
|
+
manifest: {} as never,
|
|
129
|
+
directory: '/tmp/pack',
|
|
130
|
+
status: 'installed',
|
|
131
|
+
vaultEntries: 5,
|
|
132
|
+
skills: ['my-skill', 'another-skill'],
|
|
133
|
+
hooks: ['my-hook'],
|
|
134
|
+
facadesRegistered: false,
|
|
135
|
+
installedAt: Date.now(),
|
|
136
|
+
},
|
|
137
|
+
]);
|
|
138
|
+
const updatedOps = createAdminOps(rt);
|
|
139
|
+
const op = findOp(updatedOps, 'admin_health');
|
|
140
|
+
const result = (await op.handler({})) as Record<string, unknown>;
|
|
141
|
+
const skills = result.skills as Record<string, unknown>;
|
|
142
|
+
expect(skills.count).toBe(2);
|
|
143
|
+
expect(skills.packs).toEqual(['my-skill', 'another-skill']);
|
|
144
|
+
const hooks = result.hooks as Record<string, unknown>;
|
|
145
|
+
expect(hooks.count).toBe(1);
|
|
146
|
+
expect(hooks.packs).toEqual(['my-hook']);
|
|
147
|
+
});
|
|
101
148
|
});
|
|
102
149
|
|
|
103
150
|
// ─── context_health ───────────────────────────────────────────
|
|
@@ -135,9 +182,7 @@ describe('createAdminOps', () => {
|
|
|
135
182
|
|
|
136
183
|
it('returns routing hints in grouped mode', async () => {
|
|
137
184
|
const op = findOp(ops, 'admin_tool_list');
|
|
138
|
-
const allOps = [
|
|
139
|
-
{ name: 'admin_health', description: 'Health check', auth: 'read' },
|
|
140
|
-
];
|
|
185
|
+
const allOps = [{ name: 'admin_health', description: 'Health check', auth: 'read' }];
|
|
141
186
|
const result = (await op.handler({ _allOps: allOps })) as Record<string, unknown>;
|
|
142
187
|
const routing = result.routing as Record<string, string>;
|
|
143
188
|
expect(routing).toBeDefined();
|
|
@@ -229,6 +274,94 @@ describe('createAdminOps', () => {
|
|
|
229
274
|
});
|
|
230
275
|
});
|
|
231
276
|
|
|
277
|
+
// ─── operator_context_inspect ────────────────────────────────
|
|
278
|
+
|
|
279
|
+
describe('operator_context_inspect', () => {
|
|
280
|
+
it('returns full profile when store is available', async () => {
|
|
281
|
+
const mockContext = {
|
|
282
|
+
expertise: [
|
|
283
|
+
{
|
|
284
|
+
topic: 'TypeScript',
|
|
285
|
+
level: 'expert',
|
|
286
|
+
confidence: 0.9,
|
|
287
|
+
sessionCount: 5,
|
|
288
|
+
lastObserved: Date.now(),
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
corrections: [],
|
|
292
|
+
interests: [
|
|
293
|
+
{ tag: 'testing', confidence: 0.7, mentionCount: 3, lastMentioned: Date.now() },
|
|
294
|
+
],
|
|
295
|
+
patterns: [],
|
|
296
|
+
sessionCount: 5,
|
|
297
|
+
lastUpdated: Date.now(),
|
|
298
|
+
};
|
|
299
|
+
(rt as Record<string, unknown>).operatorContextStore = {
|
|
300
|
+
inspect: vi.fn().mockReturnValue(mockContext),
|
|
301
|
+
deleteItem: vi.fn(),
|
|
302
|
+
};
|
|
303
|
+
const updatedOps = createAdminOps(rt);
|
|
304
|
+
const op = findOp(updatedOps, 'operator_context_inspect');
|
|
305
|
+
const result = (await op.handler({})) as Record<string, unknown>;
|
|
306
|
+
expect(result.available).toBe(true);
|
|
307
|
+
expect(result.expertise).toEqual(mockContext.expertise);
|
|
308
|
+
expect(result.interests).toEqual(mockContext.interests);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
it('returns not-available when store is missing', async () => {
|
|
312
|
+
// Default mock runtime has no operatorContextStore
|
|
313
|
+
const op = findOp(ops, 'operator_context_inspect');
|
|
314
|
+
const result = (await op.handler({})) as Record<string, unknown>;
|
|
315
|
+
expect(result.available).toBe(false);
|
|
316
|
+
expect(result.message).toBe('Operator context not configured');
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// ─── operator_context_delete ───────────────────────────────────
|
|
321
|
+
|
|
322
|
+
describe('operator_context_delete', () => {
|
|
323
|
+
it('removes an item successfully', async () => {
|
|
324
|
+
(rt as Record<string, unknown>).operatorContextStore = {
|
|
325
|
+
inspect: vi.fn(),
|
|
326
|
+
deleteItem: vi.fn().mockReturnValue(true),
|
|
327
|
+
};
|
|
328
|
+
const updatedOps = createAdminOps(rt);
|
|
329
|
+
const op = findOp(updatedOps, 'operator_context_delete');
|
|
330
|
+
const result = (await op.handler({ type: 'expertise', id: 'abc-123' })) as Record<
|
|
331
|
+
string,
|
|
332
|
+
unknown
|
|
333
|
+
>;
|
|
334
|
+
expect(result.deleted).toBe(true);
|
|
335
|
+
expect(result.type).toBe('expertise');
|
|
336
|
+
expect(result.id).toBe('abc-123');
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('returns false for missing item', async () => {
|
|
340
|
+
(rt as Record<string, unknown>).operatorContextStore = {
|
|
341
|
+
inspect: vi.fn(),
|
|
342
|
+
deleteItem: vi.fn().mockReturnValue(false),
|
|
343
|
+
};
|
|
344
|
+
const updatedOps = createAdminOps(rt);
|
|
345
|
+
const op = findOp(updatedOps, 'operator_context_delete');
|
|
346
|
+
const result = (await op.handler({ type: 'pattern', id: 'nonexistent' })) as Record<
|
|
347
|
+
string,
|
|
348
|
+
unknown
|
|
349
|
+
>;
|
|
350
|
+
expect(result.deleted).toBe(false);
|
|
351
|
+
expect(result.message).toBe('Item not found');
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it('returns not-available when store is missing', async () => {
|
|
355
|
+
const op = findOp(ops, 'operator_context_delete');
|
|
356
|
+
const result = (await op.handler({ type: 'expertise', id: 'abc' })) as Record<
|
|
357
|
+
string,
|
|
358
|
+
unknown
|
|
359
|
+
>;
|
|
360
|
+
expect(result.deleted).toBe(false);
|
|
361
|
+
expect(result.message).toBe('Operator context not configured');
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
|
|
232
365
|
// ─── admin_diagnostic ─────────────────────────────────────────
|
|
233
366
|
|
|
234
367
|
describe('admin_diagnostic', () => {
|
|
@@ -241,7 +374,7 @@ describe('createAdminOps', () => {
|
|
|
241
374
|
expect(result).toHaveProperty('checks');
|
|
242
375
|
expect(result).toHaveProperty('summary');
|
|
243
376
|
const checks = result.checks as Array<Record<string, string>>;
|
|
244
|
-
expect(checks.length).toBeGreaterThanOrEqual(
|
|
377
|
+
expect(checks.length).toBeGreaterThanOrEqual(8);
|
|
245
378
|
});
|
|
246
379
|
|
|
247
380
|
it('reports degraded when LLM unavailable', async () => {
|
package/src/runtime/admin-ops.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Admin / infrastructure operations —
|
|
2
|
+
* Admin / infrastructure operations — 11 ops for agent self-management.
|
|
3
3
|
*
|
|
4
4
|
* These ops let agents introspect their own health, configuration, and
|
|
5
5
|
* runtime state. No new modules needed — uses existing runtime parts.
|
|
@@ -11,6 +11,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
11
11
|
import type { OpDefinition } from '../facades/types.js';
|
|
12
12
|
import type { AgentRuntime } from './types.js';
|
|
13
13
|
import { ENGINE_MODULE_MANIFEST } from '../engine/module-manifest.js';
|
|
14
|
+
import { discoverSkills } from '../skills/sync-skills.js';
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Resolve the @soleri/core package.json version.
|
|
@@ -42,13 +43,13 @@ function getCoreVersion(): string {
|
|
|
42
43
|
* Groups: health (1–2), introspection (4), diagnostics (2), mutation (1).
|
|
43
44
|
*/
|
|
44
45
|
export function createAdminOps(runtime: AgentRuntime): OpDefinition[] {
|
|
45
|
-
const { vault, brain, brainIntelligence, llmClient, curator } = runtime;
|
|
46
|
+
const { vault, brain, brainIntelligence, llmClient, curator, packInstaller } = runtime;
|
|
46
47
|
|
|
47
48
|
return [
|
|
48
49
|
// ─── Health ──────────────────────────────────────────────────────
|
|
49
50
|
{
|
|
50
51
|
name: 'admin_health',
|
|
51
|
-
description: 'Comprehensive agent health check — vault, LLM, brain status.',
|
|
52
|
+
description: 'Comprehensive agent health check — vault, LLM, brain, skills, hooks status.',
|
|
52
53
|
auth: 'read',
|
|
53
54
|
handler: async () => {
|
|
54
55
|
const vaultStats = vault.stats();
|
|
@@ -56,6 +57,24 @@ export function createAdminOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
56
57
|
const brainStats = brain.getStats();
|
|
57
58
|
const curatorStatus = curator.getStatus();
|
|
58
59
|
|
|
60
|
+
// Skills: agent-level + pack-level
|
|
61
|
+
const agentDir = runtime.config.agentDir;
|
|
62
|
+
const agentSkillsDirs = agentDir ? [join(agentDir, 'skills')] : [];
|
|
63
|
+
const agentSkills = discoverSkills(agentSkillsDirs);
|
|
64
|
+
const packs = packInstaller.list();
|
|
65
|
+
const packSkills = packs.flatMap((p) => p.skills);
|
|
66
|
+
const allSkillNames = [...agentSkills.map((s) => s.name), ...packSkills];
|
|
67
|
+
|
|
68
|
+
// Hooks: pack-level
|
|
69
|
+
const packHooks = packs.flatMap((p) => p.hooks);
|
|
70
|
+
|
|
71
|
+
// Tier breakdown
|
|
72
|
+
const tierCounts = { default: 0, community: 0, premium: 0 };
|
|
73
|
+
for (const pk of packs) {
|
|
74
|
+
const t = (pk.manifest as { tier?: string })?.tier ?? 'community';
|
|
75
|
+
if (t in tierCounts) tierCounts[t as keyof typeof tierCounts]++;
|
|
76
|
+
}
|
|
77
|
+
|
|
59
78
|
return {
|
|
60
79
|
status: 'ok',
|
|
61
80
|
vault: { entries: vaultStats.totalEntries, domains: Object.keys(vaultStats.byDomain) },
|
|
@@ -65,6 +84,16 @@ export function createAdminOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
65
84
|
feedbackCount: brainStats.feedbackCount,
|
|
66
85
|
},
|
|
67
86
|
curator: { initialized: curatorStatus.initialized },
|
|
87
|
+
skills: {
|
|
88
|
+
count: allSkillNames.length,
|
|
89
|
+
agent: agentSkills.map((s) => s.name),
|
|
90
|
+
packs: packSkills,
|
|
91
|
+
},
|
|
92
|
+
hooks: {
|
|
93
|
+
count: packHooks.length,
|
|
94
|
+
packs: packHooks,
|
|
95
|
+
},
|
|
96
|
+
packTiers: tierCounts,
|
|
68
97
|
};
|
|
69
98
|
},
|
|
70
99
|
},
|
|
@@ -215,6 +244,39 @@ export function createAdminOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
215
244
|
},
|
|
216
245
|
},
|
|
217
246
|
|
|
247
|
+
// ─── Operator Context ───────────────────────────────────────────
|
|
248
|
+
{
|
|
249
|
+
name: 'operator_context_inspect',
|
|
250
|
+
description:
|
|
251
|
+
'Inspect the full operator context profile — expertise, corrections, interests, patterns.',
|
|
252
|
+
auth: 'read',
|
|
253
|
+
handler: async () => {
|
|
254
|
+
const store = runtime.operatorContextStore;
|
|
255
|
+
if (!store) {
|
|
256
|
+
return { available: false, message: 'Operator context not configured' };
|
|
257
|
+
}
|
|
258
|
+
return { available: true, ...store.inspect() };
|
|
259
|
+
},
|
|
260
|
+
},
|
|
261
|
+
{
|
|
262
|
+
name: 'operator_context_delete',
|
|
263
|
+
description: 'Delete a specific item from the operator context profile.',
|
|
264
|
+
auth: 'write',
|
|
265
|
+
handler: async (params) => {
|
|
266
|
+
const store = runtime.operatorContextStore;
|
|
267
|
+
if (!store) {
|
|
268
|
+
return { deleted: false, message: 'Operator context not configured' };
|
|
269
|
+
}
|
|
270
|
+
const type = params.type as string;
|
|
271
|
+
const id = params.id as string;
|
|
272
|
+
const deleted = store.deleteItem(type as Parameters<typeof store.deleteItem>[0], id);
|
|
273
|
+
if (deleted) {
|
|
274
|
+
return { deleted: true, type, id };
|
|
275
|
+
}
|
|
276
|
+
return { deleted: false, message: 'Item not found' };
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
|
|
218
280
|
// ─── Diagnostics ─────────────────────────────────────────────────
|
|
219
281
|
{
|
|
220
282
|
name: 'admin_diagnostic',
|
|
@@ -301,6 +363,45 @@ export function createAdminOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
301
363
|
});
|
|
302
364
|
}
|
|
303
365
|
|
|
366
|
+
// 7. Skills
|
|
367
|
+
try {
|
|
368
|
+
const agentDir = runtime.config.agentDir;
|
|
369
|
+
const skillsDirs = agentDir ? [join(agentDir, 'skills')] : [];
|
|
370
|
+
const agentSkills = discoverSkills(skillsDirs);
|
|
371
|
+
const installedPacks = packInstaller.list();
|
|
372
|
+
const packSkillCount = installedPacks.reduce((sum, p) => sum + p.skills.length, 0);
|
|
373
|
+
const totalSkills = agentSkills.length + packSkillCount;
|
|
374
|
+
const skillStatus = totalSkills > 0 ? 'ok' : agentDir ? 'warn' : 'ok';
|
|
375
|
+
checks.push({
|
|
376
|
+
name: 'skills',
|
|
377
|
+
status: skillStatus,
|
|
378
|
+
detail: `${totalSkills} skills (${agentSkills.length} agent, ${packSkillCount} pack)`,
|
|
379
|
+
});
|
|
380
|
+
} catch (err) {
|
|
381
|
+
checks.push({
|
|
382
|
+
name: 'skills',
|
|
383
|
+
status: 'error',
|
|
384
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// 8. Hooks
|
|
389
|
+
try {
|
|
390
|
+
const installedPacks = packInstaller.list();
|
|
391
|
+
const packHookCount = installedPacks.reduce((sum, p) => sum + p.hooks.length, 0);
|
|
392
|
+
checks.push({
|
|
393
|
+
name: 'hooks',
|
|
394
|
+
status: 'ok',
|
|
395
|
+
detail: `${packHookCount} hooks from ${installedPacks.length} packs`,
|
|
396
|
+
});
|
|
397
|
+
} catch (err) {
|
|
398
|
+
checks.push({
|
|
399
|
+
name: 'hooks',
|
|
400
|
+
status: 'error',
|
|
401
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
304
405
|
const errorCount = checks.filter((c) => c.status === 'error').length;
|
|
305
406
|
const warnCount = checks.filter((c) => c.status === 'warn').length;
|
|
306
407
|
const overall = errorCount > 0 ? 'unhealthy' : warnCount > 0 ? 'degraded' : 'healthy';
|
|
@@ -99,7 +99,7 @@ function discoverHookifyFiles(dir: string): Array<{ name: string; path: string }
|
|
|
99
99
|
// ─── Settings.json Hook Merging ───────────────────────────────────────
|
|
100
100
|
|
|
101
101
|
interface SettingsHook {
|
|
102
|
-
type: 'prompt' | 'agent';
|
|
102
|
+
type: 'prompt' | 'agent' | 'command';
|
|
103
103
|
prompt?: string;
|
|
104
104
|
command?: string;
|
|
105
105
|
timeout?: number;
|
|
@@ -110,6 +110,17 @@ interface SettingsHookGroup {
|
|
|
110
110
|
hooks: SettingsHook[];
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Build a shell command that checks if the agent's MCP server is configured
|
|
115
|
+
* in the current project's .mcp.json before emitting an instruction.
|
|
116
|
+
* This ensures hooks are globally safe — they no-op in projects without the agent.
|
|
117
|
+
*/
|
|
118
|
+
function buildConditionalHookCommand(agentId: string, instruction: string): string {
|
|
119
|
+
// Escape single quotes in instruction for safe shell embedding
|
|
120
|
+
const escaped = instruction.replace(/'/g, "'\\''");
|
|
121
|
+
return `root=$(git rev-parse --show-toplevel 2>/dev/null || echo "."); if grep -q '"${agentId}"' "$root/.mcp.json" 2>/dev/null; then echo '${escaped}'; fi`;
|
|
122
|
+
}
|
|
123
|
+
|
|
113
124
|
/** Default lifecycle hooks for any Soleri agent */
|
|
114
125
|
function getDefaultLifecycleHooks(agentId: string): Record<string, SettingsHookGroup[]> {
|
|
115
126
|
const marker = `mcp__${agentId}__${agentId}_`;
|
|
@@ -120,9 +131,12 @@ function getDefaultLifecycleHooks(agentId: string): Record<string, SettingsHookG
|
|
|
120
131
|
matcher: '',
|
|
121
132
|
hooks: [
|
|
122
133
|
{
|
|
123
|
-
type: '
|
|
124
|
-
|
|
125
|
-
|
|
134
|
+
type: 'command',
|
|
135
|
+
command: buildConditionalHookCommand(
|
|
136
|
+
agentId,
|
|
137
|
+
`Call ${marker}admin op:admin_health to verify agent is ready. Do not show the result unless there are errors.`,
|
|
138
|
+
),
|
|
139
|
+
timeout: 5000,
|
|
126
140
|
},
|
|
127
141
|
],
|
|
128
142
|
},
|
|
@@ -132,9 +146,12 @@ function getDefaultLifecycleHooks(agentId: string): Record<string, SettingsHookG
|
|
|
132
146
|
matcher: '',
|
|
133
147
|
hooks: [
|
|
134
148
|
{
|
|
135
|
-
type: '
|
|
136
|
-
|
|
137
|
-
|
|
149
|
+
type: 'command',
|
|
150
|
+
command: buildConditionalHookCommand(
|
|
151
|
+
agentId,
|
|
152
|
+
`First, call ${marker}plan op:plan_close_stale params:{ olderThanMs: 0 } to auto-close any plans still in non-terminal states. Then call ${marker}memory op:session_capture with a brief summary of the current session before context is compacted. Include any auto-closed plan IDs in the summary.`,
|
|
153
|
+
),
|
|
154
|
+
timeout: 10000,
|
|
138
155
|
},
|
|
139
156
|
],
|
|
140
157
|
},
|
|
@@ -144,9 +161,12 @@ function getDefaultLifecycleHooks(agentId: string): Record<string, SettingsHookG
|
|
|
144
161
|
matcher: '',
|
|
145
162
|
hooks: [
|
|
146
163
|
{
|
|
147
|
-
type: '
|
|
148
|
-
|
|
149
|
-
|
|
164
|
+
type: 'command',
|
|
165
|
+
command: buildConditionalHookCommand(
|
|
166
|
+
agentId,
|
|
167
|
+
`First, call ${marker}plan op:plan_close_stale params:{ olderThanMs: 0 } to auto-close any plans still in non-terminal states. Then call ${marker}memory op:session_capture with a structured summary of what was accomplished, including any auto-closed plan IDs. Finally check ${marker}loop op:loop_status — if a loop is active, remind the user.`,
|
|
168
|
+
),
|
|
169
|
+
timeout: 10000,
|
|
150
170
|
},
|
|
151
171
|
],
|
|
152
172
|
},
|
|
@@ -37,6 +37,19 @@ function createMockRuntime(): AgentRuntime {
|
|
|
37
37
|
entry: { id: 'captured-1' },
|
|
38
38
|
})),
|
|
39
39
|
intelligentSearch: vi.fn(async () => [{ id: 'r1', title: 'Result 1', score: 0.8 }]),
|
|
40
|
+
scanSearch: vi.fn(async () => [
|
|
41
|
+
{
|
|
42
|
+
id: 'r1',
|
|
43
|
+
title: 'Result 1',
|
|
44
|
+
score: 0.8,
|
|
45
|
+
snippet: 'Short desc...',
|
|
46
|
+
tokenEstimate: 50,
|
|
47
|
+
type: 'pattern',
|
|
48
|
+
domain: 'test',
|
|
49
|
+
severity: 'suggestion',
|
|
50
|
+
tags: ['test'],
|
|
51
|
+
},
|
|
52
|
+
]),
|
|
40
53
|
recordFeedback: vi.fn(),
|
|
41
54
|
},
|
|
42
55
|
governance: {
|
|
@@ -365,6 +378,77 @@ describe('createCaptureOps', () => {
|
|
|
365
378
|
})) as Array<Record<string, unknown>>;
|
|
366
379
|
expect((result[0].score as number) >= (result[1].score as number)).toBe(true);
|
|
367
380
|
});
|
|
381
|
+
|
|
382
|
+
it('scan mode calls brain.scanSearch instead of intelligentSearch', async () => {
|
|
383
|
+
const result = (await findOp(ops, 'search_intelligent').handler({
|
|
384
|
+
query: 'test patterns',
|
|
385
|
+
mode: 'scan',
|
|
386
|
+
})) as Array<Record<string, unknown>>;
|
|
387
|
+
expect(runtime.brain.scanSearch).toHaveBeenCalledWith(
|
|
388
|
+
'test patterns',
|
|
389
|
+
expect.objectContaining({ limit: 10 }),
|
|
390
|
+
);
|
|
391
|
+
expect(runtime.brain.intelligentSearch).not.toHaveBeenCalled();
|
|
392
|
+
expect(Array.isArray(result)).toBe(true);
|
|
393
|
+
expect(result[0].source).toBe('vault');
|
|
394
|
+
expect(result[0].snippet).toBeDefined();
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it('scan mode defaults limit to 10', async () => {
|
|
398
|
+
await findOp(ops, 'search_intelligent').handler({
|
|
399
|
+
query: 'test',
|
|
400
|
+
mode: 'scan',
|
|
401
|
+
});
|
|
402
|
+
expect(runtime.brain.scanSearch).toHaveBeenCalledWith(
|
|
403
|
+
'test',
|
|
404
|
+
expect.objectContaining({ limit: 10 }),
|
|
405
|
+
);
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
it('full mode (default) still uses intelligentSearch with limit 20', async () => {
|
|
409
|
+
await findOp(ops, 'search_intelligent').handler({
|
|
410
|
+
query: 'test',
|
|
411
|
+
});
|
|
412
|
+
expect(runtime.brain.intelligentSearch).toHaveBeenCalledWith(
|
|
413
|
+
'test',
|
|
414
|
+
expect.objectContaining({ limit: 20 }),
|
|
415
|
+
);
|
|
416
|
+
expect(runtime.brain.scanSearch).not.toHaveBeenCalled();
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
it('scan mode with includeMemories returns lightweight memory results', async () => {
|
|
420
|
+
vi.mocked(runtime.vault.searchMemories).mockReturnValue([
|
|
421
|
+
{
|
|
422
|
+
id: 'm1',
|
|
423
|
+
summary:
|
|
424
|
+
'A long memory summary that should be truncated to 120 chars for scan mode lightweight results test',
|
|
425
|
+
context: 'Auth context',
|
|
426
|
+
},
|
|
427
|
+
] as unknown);
|
|
428
|
+
const result = (await findOp(ops, 'search_intelligent').handler({
|
|
429
|
+
query: 'auth',
|
|
430
|
+
mode: 'scan',
|
|
431
|
+
includeMemories: true,
|
|
432
|
+
})) as Array<Record<string, unknown>>;
|
|
433
|
+
const memResult = result.find((r) => r.source === 'memory');
|
|
434
|
+
expect(memResult).toBeDefined();
|
|
435
|
+
expect(memResult!.id).toBe('m1');
|
|
436
|
+
expect(memResult!.snippet).toBeDefined();
|
|
437
|
+
expect(typeof memResult!.snippet).toBe('string');
|
|
438
|
+
// Should NOT have full memory fields
|
|
439
|
+
expect(memResult!.filesModified).toBeUndefined();
|
|
440
|
+
expect(memResult!.toolsUsed).toBeUndefined();
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
it('scan mode handles search failure gracefully', async () => {
|
|
444
|
+
vi.mocked(runtime.brain.scanSearch).mockRejectedValue(new Error('Scan failed'));
|
|
445
|
+
const result = (await findOp(ops, 'search_intelligent').handler({
|
|
446
|
+
query: 'anything',
|
|
447
|
+
mode: 'scan',
|
|
448
|
+
})) as Array<Record<string, unknown>>;
|
|
449
|
+
expect(Array.isArray(result)).toBe(true);
|
|
450
|
+
expect(result).toHaveLength(0);
|
|
451
|
+
});
|
|
368
452
|
});
|
|
369
453
|
|
|
370
454
|
describe('search_feedback', () => {
|
|
@@ -484,28 +484,42 @@ export function createCaptureOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
484
484
|
{
|
|
485
485
|
name: 'search_intelligent',
|
|
486
486
|
description:
|
|
487
|
-
'Project-scoped intelligent search combining vault FTS, brain TF-IDF ranking, and optional memory search.',
|
|
487
|
+
'Project-scoped intelligent search combining vault FTS, brain TF-IDF ranking, and optional memory search. mode:"scan" returns lightweight results (titles + scores + snippets) for two-pass retrieval. mode:"full" (default) returns complete entries.',
|
|
488
488
|
auth: 'read',
|
|
489
489
|
schema: z.object({
|
|
490
490
|
query: z.string(),
|
|
491
491
|
projectPath: z.string().optional(),
|
|
492
492
|
domain: z.string().optional(),
|
|
493
493
|
type: z.string().optional(),
|
|
494
|
-
limit: z.number().optional()
|
|
494
|
+
limit: z.number().optional(),
|
|
495
495
|
includeMemories: z.boolean().optional().default(false),
|
|
496
|
+
mode: z
|
|
497
|
+
.enum(['full', 'scan'])
|
|
498
|
+
.optional()
|
|
499
|
+
.default('full')
|
|
500
|
+
.describe(
|
|
501
|
+
'full = complete entries with scoring breakdowns, scan = lightweight titles + scores for two-pass retrieval',
|
|
502
|
+
),
|
|
496
503
|
}),
|
|
497
504
|
handler: async (params) => {
|
|
498
505
|
const query = params.query as string;
|
|
499
506
|
const domain = params.domain as string | undefined;
|
|
500
507
|
const type = params.type as string | undefined;
|
|
501
|
-
const
|
|
508
|
+
const mode = (params.mode as string | undefined) ?? 'full';
|
|
509
|
+
const isScan = mode === 'scan';
|
|
510
|
+
const limit = (params.limit as number | undefined) ?? (isScan ? 10 : 20);
|
|
502
511
|
const includeMemories = (params.includeMemories as boolean | undefined) ?? false;
|
|
503
512
|
|
|
504
|
-
// Search vault
|
|
513
|
+
// Search vault — scan mode returns lightweight results, full returns complete entries
|
|
505
514
|
let vaultResults: Array<{ source: string; [key: string]: unknown }> = [];
|
|
506
515
|
try {
|
|
507
|
-
|
|
508
|
-
|
|
516
|
+
if (isScan) {
|
|
517
|
+
const scanned = await brain.scanSearch(query, { domain, type, limit });
|
|
518
|
+
vaultResults = scanned.map((r) => ({ ...r, source: 'vault' }));
|
|
519
|
+
} else {
|
|
520
|
+
const ranked = await brain.intelligentSearch(query, { domain, type, limit });
|
|
521
|
+
vaultResults = ranked.map((r) => ({ ...r, source: 'vault' }));
|
|
522
|
+
}
|
|
509
523
|
} catch {
|
|
510
524
|
// Graceful degradation — return empty vault results
|
|
511
525
|
}
|
|
@@ -515,7 +529,21 @@ export function createCaptureOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
515
529
|
if (includeMemories) {
|
|
516
530
|
try {
|
|
517
531
|
const memories = vault.searchMemories(query, { limit });
|
|
518
|
-
|
|
532
|
+
if (isScan) {
|
|
533
|
+
// Lightweight memory results for scan mode
|
|
534
|
+
memoryResults = memories.map((m) => {
|
|
535
|
+
const desc = m.summary ?? '';
|
|
536
|
+
return {
|
|
537
|
+
id: m.id,
|
|
538
|
+
title: m.context ?? '',
|
|
539
|
+
snippet: desc.slice(0, 120) + (desc.length > 120 ? '...' : ''),
|
|
540
|
+
score: 0.5,
|
|
541
|
+
source: 'memory',
|
|
542
|
+
};
|
|
543
|
+
});
|
|
544
|
+
} else {
|
|
545
|
+
memoryResults = memories.map((m) => ({ ...m, source: 'memory', score: 0.5 }));
|
|
546
|
+
}
|
|
519
547
|
} catch {
|
|
520
548
|
// Graceful degradation — return empty memory results
|
|
521
549
|
}
|
|
@@ -10,9 +10,18 @@ import type { OpDefinition } from '../facades/types.js';
|
|
|
10
10
|
import type { AgentRuntime } from './types.js';
|
|
11
11
|
|
|
12
12
|
export function createCuratorExtraOps(runtime: AgentRuntime): OpDefinition[] {
|
|
13
|
-
const { curator, jobQueue, pipelineRunner } = runtime;
|
|
13
|
+
const { curator, jobQueue, pipelineRunner, shutdownRegistry } = runtime;
|
|
14
14
|
let consolidationInterval: ReturnType<typeof setInterval> | null = null;
|
|
15
15
|
|
|
16
|
+
// Register cleanup for any consolidation interval started during this session
|
|
17
|
+
shutdownRegistry.register('curatorConsolidation', () => {
|
|
18
|
+
if (consolidationInterval) {
|
|
19
|
+
clearInterval(consolidationInterval);
|
|
20
|
+
consolidationInterval = null;
|
|
21
|
+
}
|
|
22
|
+
pipelineRunner.stop();
|
|
23
|
+
});
|
|
24
|
+
|
|
16
25
|
return [
|
|
17
26
|
// ─── Entry History ──────────────────────────────────────────────
|
|
18
27
|
{
|
|
@@ -466,13 +466,16 @@ export function createBrainFacadeOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
466
466
|
},
|
|
467
467
|
{
|
|
468
468
|
name: 'radar_dismiss',
|
|
469
|
-
description:
|
|
469
|
+
description:
|
|
470
|
+
'Dismiss one or more pending radar candidates — marks them as not worth capturing. Accepts a single ID or an array.',
|
|
470
471
|
auth: 'write',
|
|
471
472
|
schema: z.object({
|
|
472
|
-
candidateId: z
|
|
473
|
+
candidateId: z
|
|
474
|
+
.union([z.number(), z.array(z.number())])
|
|
475
|
+
.describe('Radar candidate ID(s) to dismiss — single number or array'),
|
|
473
476
|
}),
|
|
474
477
|
handler: async (params) => {
|
|
475
|
-
return learningRadar.dismiss(params.candidateId as number);
|
|
478
|
+
return learningRadar.dismiss(params.candidateId as number | number[]);
|
|
476
479
|
},
|
|
477
480
|
},
|
|
478
481
|
{
|
|
@@ -118,11 +118,19 @@ export function createControlFacadeOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
118
118
|
mode: z
|
|
119
119
|
.string()
|
|
120
120
|
.describe(
|
|
121
|
-
'The operational mode to switch to. Valid modes: BUILD-MODE, FIX-MODE, VALIDATE-MODE, DESIGN-MODE, IMPROVE-MODE, DELIVER-MODE, EXPLORE-MODE, PLAN-MODE, REVIEW-MODE, GENERAL-MODE. Use "reset" to return to GENERAL-MODE.',
|
|
121
|
+
'The operational mode to switch to. Valid modes: BUILD-MODE, FIX-MODE, VALIDATE-MODE, DESIGN-MODE, IMPROVE-MODE, DELIVER-MODE, EXPLORE-MODE, PLAN-MODE, REVIEW-MODE, GENERAL-MODE, YOLO-MODE. Use "reset" to return to GENERAL-MODE.',
|
|
122
|
+
),
|
|
123
|
+
hookPackInstalled: z
|
|
124
|
+
.boolean()
|
|
125
|
+
.optional()
|
|
126
|
+
.describe(
|
|
127
|
+
'Whether the yolo-safety hook pack is installed. Required for YOLO-MODE activation. The CLI layer should check for the hook pack before calling morph.',
|
|
122
128
|
),
|
|
123
129
|
}),
|
|
124
130
|
handler: async (params) => {
|
|
125
|
-
return intentRouter.morph(params.mode as OperationalMode
|
|
131
|
+
return intentRouter.morph(params.mode as OperationalMode, {
|
|
132
|
+
hookPackInstalled: params.hookPackInstalled as boolean | undefined,
|
|
133
|
+
});
|
|
126
134
|
},
|
|
127
135
|
},
|
|
128
136
|
{
|