@soleri/core 2.12.0 → 7.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/data/flows/build.flow.yaml +128 -0
- package/data/flows/deliver.flow.yaml +110 -0
- package/data/flows/design.flow.yaml +108 -0
- package/data/flows/enhance.flow.yaml +90 -0
- package/data/flows/explore.flow.yaml +84 -0
- package/data/flows/fix.flow.yaml +90 -0
- package/data/flows/plan.flow.yaml +87 -0
- package/data/flows/review.flow.yaml +90 -0
- package/dist/brain/intelligence.d.ts.map +1 -1
- package/dist/brain/intelligence.js +16 -2
- package/dist/brain/intelligence.js.map +1 -1
- package/dist/capabilities/chain-mapping.d.ts +21 -0
- package/dist/capabilities/chain-mapping.d.ts.map +1 -0
- package/dist/capabilities/chain-mapping.js +86 -0
- package/dist/capabilities/chain-mapping.js.map +1 -0
- package/dist/capabilities/index.d.ts +10 -0
- package/dist/capabilities/index.d.ts.map +1 -0
- package/dist/capabilities/index.js +8 -0
- package/dist/capabilities/index.js.map +1 -0
- package/dist/capabilities/registry.d.ts +95 -0
- package/dist/capabilities/registry.d.ts.map +1 -0
- package/dist/capabilities/registry.js +227 -0
- package/dist/capabilities/registry.js.map +1 -0
- package/dist/capabilities/types.d.ts +106 -0
- package/dist/capabilities/types.d.ts.map +1 -0
- package/dist/capabilities/types.js +12 -0
- package/dist/capabilities/types.js.map +1 -0
- package/dist/control/intent-router.d.ts.map +1 -1
- package/dist/control/intent-router.js +58 -2
- package/dist/control/intent-router.js.map +1 -1
- package/dist/domain-packs/index.d.ts +8 -0
- package/dist/domain-packs/index.d.ts.map +1 -0
- package/dist/domain-packs/index.js +8 -0
- package/dist/domain-packs/index.js.map +1 -0
- package/dist/domain-packs/inject-rules.d.ts +24 -0
- package/dist/domain-packs/inject-rules.d.ts.map +1 -0
- package/dist/domain-packs/inject-rules.js +65 -0
- package/dist/domain-packs/inject-rules.js.map +1 -0
- package/dist/domain-packs/knowledge-installer.d.ts +27 -0
- package/dist/domain-packs/knowledge-installer.d.ts.map +1 -0
- package/dist/domain-packs/knowledge-installer.js +89 -0
- package/dist/domain-packs/knowledge-installer.js.map +1 -0
- package/dist/domain-packs/loader.d.ts +28 -0
- package/dist/domain-packs/loader.d.ts.map +1 -0
- package/dist/domain-packs/loader.js +105 -0
- package/dist/domain-packs/loader.js.map +1 -0
- package/dist/domain-packs/pack-runtime.d.ts +80 -0
- package/dist/domain-packs/pack-runtime.d.ts.map +1 -0
- package/dist/domain-packs/pack-runtime.js +36 -0
- package/dist/domain-packs/pack-runtime.js.map +1 -0
- package/dist/domain-packs/skills-installer.d.ts +21 -0
- package/dist/domain-packs/skills-installer.d.ts.map +1 -0
- package/dist/domain-packs/skills-installer.js +38 -0
- package/dist/domain-packs/skills-installer.js.map +1 -0
- package/dist/domain-packs/token-resolver.d.ts +37 -0
- package/dist/domain-packs/token-resolver.d.ts.map +1 -0
- package/dist/domain-packs/token-resolver.js +109 -0
- package/dist/domain-packs/token-resolver.js.map +1 -0
- package/dist/domain-packs/types.d.ts +91 -0
- package/dist/domain-packs/types.d.ts.map +1 -0
- package/dist/domain-packs/types.js +122 -0
- package/dist/domain-packs/types.js.map +1 -0
- package/dist/engine/bin/soleri-engine.d.ts +12 -0
- package/dist/engine/bin/soleri-engine.d.ts.map +1 -0
- package/dist/engine/bin/soleri-engine.js +183 -0
- package/dist/engine/bin/soleri-engine.js.map +1 -0
- package/dist/engine/core-ops.d.ts +27 -0
- package/dist/engine/core-ops.d.ts.map +1 -0
- package/dist/engine/core-ops.js +159 -0
- package/dist/engine/core-ops.js.map +1 -0
- package/dist/engine/index.d.ts +19 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +17 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/register-engine.d.ts +54 -0
- package/dist/engine/register-engine.d.ts.map +1 -0
- package/dist/engine/register-engine.js +270 -0
- package/dist/engine/register-engine.js.map +1 -0
- package/dist/engine/test-helpers.d.ts +30 -0
- package/dist/engine/test-helpers.d.ts.map +1 -0
- package/dist/engine/test-helpers.js +59 -0
- package/dist/engine/test-helpers.js.map +1 -0
- package/dist/flows/context-router.d.ts +39 -0
- package/dist/flows/context-router.d.ts.map +1 -0
- package/dist/flows/context-router.js +206 -0
- package/dist/flows/context-router.js.map +1 -0
- package/dist/flows/dispatch-registry.d.ts +24 -0
- package/dist/flows/dispatch-registry.d.ts.map +1 -0
- package/dist/flows/dispatch-registry.js +70 -0
- package/dist/flows/dispatch-registry.js.map +1 -0
- package/dist/flows/epilogue.d.ts +24 -0
- package/dist/flows/epilogue.d.ts.map +1 -0
- package/dist/flows/epilogue.js +52 -0
- package/dist/flows/epilogue.js.map +1 -0
- package/dist/flows/executor.d.ts +25 -0
- package/dist/flows/executor.d.ts.map +1 -0
- package/dist/flows/executor.js +153 -0
- package/dist/flows/executor.js.map +1 -0
- package/dist/flows/gate-evaluator.d.ts +26 -0
- package/dist/flows/gate-evaluator.d.ts.map +1 -0
- package/dist/flows/gate-evaluator.js +162 -0
- package/dist/flows/gate-evaluator.js.map +1 -0
- package/dist/flows/index.d.ts +14 -0
- package/dist/flows/index.d.ts.map +1 -0
- package/dist/flows/index.js +20 -0
- package/dist/flows/index.js.map +1 -0
- package/dist/flows/loader.d.ts +17 -0
- package/dist/flows/loader.d.ts.map +1 -0
- package/dist/flows/loader.js +61 -0
- package/dist/flows/loader.js.map +1 -0
- package/dist/flows/plan-builder.d.ts +40 -0
- package/dist/flows/plan-builder.d.ts.map +1 -0
- package/dist/flows/plan-builder.js +213 -0
- package/dist/flows/plan-builder.js.map +1 -0
- package/dist/flows/probes.d.ts +11 -0
- package/dist/flows/probes.d.ts.map +1 -0
- package/dist/flows/probes.js +62 -0
- package/dist/flows/probes.js.map +1 -0
- package/dist/flows/types.d.ts +950 -0
- package/dist/flows/types.d.ts.map +1 -0
- package/dist/flows/types.js +105 -0
- package/dist/flows/types.js.map +1 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/intelligence/loader.d.ts +19 -0
- package/dist/intelligence/loader.d.ts.map +1 -1
- package/dist/intelligence/loader.js +35 -0
- package/dist/intelligence/loader.js.map +1 -1
- package/dist/intelligence/types.d.ts +1 -0
- package/dist/intelligence/types.d.ts.map +1 -1
- package/dist/packs/types.d.ts +58 -19
- package/dist/packs/types.d.ts.map +1 -1
- package/dist/packs/types.js +14 -0
- package/dist/packs/types.js.map +1 -1
- package/dist/playbooks/generic/onboarding.d.ts +9 -0
- package/dist/playbooks/generic/onboarding.d.ts.map +1 -0
- package/dist/playbooks/generic/onboarding.js +74 -0
- package/dist/playbooks/generic/onboarding.js.map +1 -0
- package/dist/playbooks/playbook-registry.d.ts.map +1 -1
- package/dist/playbooks/playbook-registry.js +2 -0
- package/dist/playbooks/playbook-registry.js.map +1 -1
- package/dist/runtime/admin-extra-ops.d.ts.map +1 -1
- package/dist/runtime/admin-extra-ops.js +15 -9
- package/dist/runtime/admin-extra-ops.js.map +1 -1
- package/dist/runtime/admin-ops.js +4 -4
- package/dist/runtime/admin-ops.js.map +1 -1
- package/dist/runtime/capture-ops.d.ts.map +1 -1
- package/dist/runtime/capture-ops.js +33 -1
- package/dist/runtime/capture-ops.js.map +1 -1
- package/dist/runtime/domain-ops.d.ts +21 -5
- package/dist/runtime/domain-ops.d.ts.map +1 -1
- package/dist/runtime/domain-ops.js +64 -6
- package/dist/runtime/domain-ops.js.map +1 -1
- package/dist/runtime/facades/cognee-facade.d.ts.map +1 -1
- package/dist/runtime/facades/cognee-facade.js +3 -1
- package/dist/runtime/facades/cognee-facade.js.map +1 -1
- package/dist/runtime/facades/index.d.ts.map +1 -1
- package/dist/runtime/facades/index.js +10 -6
- package/dist/runtime/facades/index.js.map +1 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +2 -0
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/orchestrate-ops.d.ts +8 -7
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
- package/dist/runtime/orchestrate-ops.js +217 -61
- package/dist/runtime/orchestrate-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +23 -17
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/types.d.ts +6 -2
- package/dist/runtime/types.d.ts.map +1 -1
- package/dist/runtime/vault-linking-ops.d.ts +13 -0
- package/dist/runtime/vault-linking-ops.d.ts.map +1 -0
- package/dist/runtime/vault-linking-ops.js +367 -0
- package/dist/runtime/vault-linking-ops.js.map +1 -0
- package/dist/vault/linking.d.ts +46 -0
- package/dist/vault/linking.d.ts.map +1 -0
- package/dist/vault/linking.js +275 -0
- package/dist/vault/linking.js.map +1 -0
- package/dist/vault/vault-types.d.ts +37 -0
- package/dist/vault/vault-types.d.ts.map +1 -1
- package/dist/vault/vault.d.ts +12 -0
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +85 -6
- package/dist/vault/vault.js.map +1 -1
- package/package.json +4 -1
- package/src/__tests__/admin-extra-ops.test.ts +1 -1
- package/src/__tests__/admin-ops.test.ts +2 -1
- package/src/__tests__/cognee-client-gaps.test.ts +470 -0
- package/src/__tests__/cognee-hybrid-search.test.ts +478 -0
- package/src/__tests__/cognee-sync-manager-deep.test.ts +630 -0
- package/src/__tests__/cognee-sync-manager.test.ts +1 -0
- package/src/__tests__/core-ops.test.ts +9 -61
- package/src/__tests__/domain-packs.test.ts +421 -0
- package/src/__tests__/flows.test.ts +604 -0
- package/src/__tests__/playbook-registry.test.ts +2 -2
- package/src/__tests__/playbook-seeder.test.ts +8 -8
- package/src/__tests__/playbook.test.ts +5 -5
- package/src/__tests__/token-resolver.test.ts +79 -0
- package/src/brain/intelligence.ts +21 -2
- package/src/capabilities/chain-mapping.ts +93 -0
- package/src/capabilities/index.ts +21 -0
- package/src/capabilities/registry.ts +290 -0
- package/src/capabilities/types.ts +143 -0
- package/src/control/intent-router.ts +46 -2
- package/src/domain-packs/index.ts +27 -0
- package/src/domain-packs/inject-rules.ts +74 -0
- package/src/domain-packs/knowledge-installer.ts +116 -0
- package/src/domain-packs/loader.ts +124 -0
- package/src/domain-packs/pack-runtime.ts +99 -0
- package/src/domain-packs/skills-installer.ts +56 -0
- package/src/domain-packs/token-resolver.ts +126 -0
- package/src/domain-packs/types.ts +229 -0
- package/src/engine/__tests__/register-engine.test.ts +104 -0
- package/src/engine/bin/soleri-engine.ts +217 -0
- package/src/engine/core-ops.ts +178 -0
- package/src/engine/index.ts +19 -0
- package/src/engine/register-engine.ts +385 -0
- package/src/engine/test-helpers.ts +83 -0
- package/src/flows/context-router.ts +257 -0
- package/src/flows/dispatch-registry.ts +80 -0
- package/src/flows/epilogue.ts +65 -0
- package/src/flows/executor.ts +182 -0
- package/src/flows/gate-evaluator.ts +171 -0
- package/src/flows/index.ts +52 -0
- package/src/flows/loader.ts +63 -0
- package/src/flows/plan-builder.ts +250 -0
- package/src/flows/probes.ts +70 -0
- package/src/flows/types.ts +217 -0
- package/src/index.ts +68 -1
- package/src/intelligence/loader.ts +38 -0
- package/src/intelligence/types.ts +1 -0
- package/src/packs/types.ts +19 -0
- package/src/playbooks/generic/onboarding.ts +79 -0
- package/src/playbooks/playbook-registry.ts +2 -0
- package/src/runtime/admin-extra-ops.ts +14 -8
- package/src/runtime/admin-ops.ts +4 -4
- package/src/runtime/capture-ops.ts +40 -1
- package/src/runtime/domain-ops.ts +71 -5
- package/src/runtime/facades/cognee-facade.ts +3 -1
- package/src/runtime/facades/index.ts +12 -6
- package/src/runtime/facades/vault-facade.ts +2 -0
- package/src/runtime/orchestrate-ops.ts +261 -65
- package/src/runtime/runtime.ts +27 -18
- package/src/runtime/types.ts +6 -2
- package/src/runtime/vault-linking-ops.ts +454 -0
- package/src/vault/linking.ts +333 -0
- package/src/vault/vault-types.ts +46 -0
- package/src/vault/vault.ts +94 -7
|
@@ -34,8 +34,9 @@ describe('createSemanticFacades', () => {
|
|
|
34
34
|
return op;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
it('should return
|
|
38
|
-
|
|
37
|
+
it('should return ops from all semantic facades (without cognee)', () => {
|
|
38
|
+
// Op count varies as new ops are added. Just verify a reasonable minimum.
|
|
39
|
+
expect(ops.length).toBeGreaterThan(250);
|
|
39
40
|
});
|
|
40
41
|
|
|
41
42
|
it('should have all expected op names', () => {
|
|
@@ -103,12 +104,8 @@ describe('createSemanticFacades', () => {
|
|
|
103
104
|
expect(names).toContain('route_intent');
|
|
104
105
|
expect(names).toContain('morph');
|
|
105
106
|
expect(names).toContain('get_behavior_rules');
|
|
106
|
-
// Cognee
|
|
107
|
-
|
|
108
|
-
expect(names).toContain('cognee_search');
|
|
109
|
-
expect(names).toContain('cognee_add');
|
|
110
|
-
expect(names).toContain('cognee_cognify');
|
|
111
|
-
expect(names).toContain('cognee_config');
|
|
107
|
+
// Cognee — only present when cognee is enabled in runtime
|
|
108
|
+
// (this test creates runtime without cognee: true)
|
|
112
109
|
// Context Engine (#172)
|
|
113
110
|
expect(names).toContain('context_extract_entities');
|
|
114
111
|
expect(names).toContain('context_retrieve_knowledge');
|
|
@@ -324,10 +321,7 @@ describe('createSemanticFacades', () => {
|
|
|
324
321
|
// Prompt templates
|
|
325
322
|
expect(names).toContain('render_prompt');
|
|
326
323
|
expect(names).toContain('list_templates');
|
|
327
|
-
// Cognee Sync ops
|
|
328
|
-
expect(names).toContain('cognee_sync_status');
|
|
329
|
-
expect(names).toContain('cognee_sync_drain');
|
|
330
|
-
expect(names).toContain('cognee_sync_reconcile');
|
|
324
|
+
// Cognee Sync ops — only present when cognee is enabled
|
|
331
325
|
// Intake ops
|
|
332
326
|
expect(names).toContain('intake_ingest_book');
|
|
333
327
|
expect(names).toContain('intake_process');
|
|
@@ -515,55 +509,9 @@ describe('createSemanticFacades', () => {
|
|
|
515
509
|
expect(result.totalEntries).toBe(1);
|
|
516
510
|
});
|
|
517
511
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
available: boolean;
|
|
522
|
-
url: string;
|
|
523
|
-
};
|
|
524
|
-
expect(typeof result.available).toBe('boolean');
|
|
525
|
-
expect(typeof result.url).toBe('string');
|
|
526
|
-
});
|
|
527
|
-
|
|
528
|
-
it('cognee_search should return empty when unavailable', async () => {
|
|
529
|
-
const results = (await findOp('cognee_search').handler({
|
|
530
|
-
query: 'test pattern',
|
|
531
|
-
})) as unknown[];
|
|
532
|
-
expect(results).toEqual([]);
|
|
533
|
-
});
|
|
534
|
-
|
|
535
|
-
it('cognee_add should return 0 when unavailable', async () => {
|
|
536
|
-
runtime.vault.seed([
|
|
537
|
-
{
|
|
538
|
-
id: 'cog-1',
|
|
539
|
-
type: 'pattern',
|
|
540
|
-
domain: 'testing',
|
|
541
|
-
title: 'Cognee test',
|
|
542
|
-
severity: 'warning',
|
|
543
|
-
description: 'Test.',
|
|
544
|
-
tags: ['test'],
|
|
545
|
-
},
|
|
546
|
-
]);
|
|
547
|
-
const result = (await findOp('cognee_add').handler({
|
|
548
|
-
entryIds: ['cog-1'],
|
|
549
|
-
})) as { added: number };
|
|
550
|
-
expect(result.added).toBe(0);
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
it('cognee_cognify should return unavailable when Cognee is down', async () => {
|
|
554
|
-
const result = (await findOp('cognee_cognify').handler({})) as { status: string };
|
|
555
|
-
expect(result.status).toBe('unavailable');
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
it('cognee_config should return config and null status', async () => {
|
|
559
|
-
const result = (await findOp('cognee_config').handler({})) as {
|
|
560
|
-
config: { baseUrl: string; dataset: string };
|
|
561
|
-
cachedStatus: null;
|
|
562
|
-
};
|
|
563
|
-
expect(result.config.baseUrl).toBe('http://localhost:8000');
|
|
564
|
-
expect(result.config.dataset).toBe('test-core-ops');
|
|
565
|
-
expect(result.cachedStatus).toBeNull();
|
|
566
|
-
});
|
|
512
|
+
// Cognee ops are only registered when runtime has cognee enabled.
|
|
513
|
+
// This test creates runtime without cognee: true, so these ops are not present.
|
|
514
|
+
// See e2e/full-pipeline.test.ts for cognee facade tests with cognee enabled.
|
|
567
515
|
|
|
568
516
|
it('llm_rotate should return rotation status', async () => {
|
|
569
517
|
const result = (await findOp('llm_rotate').handler({ provider: 'openai' })) as {
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain Packs — failing tests for the DomainPack primitive.
|
|
3
|
+
*
|
|
4
|
+
* These tests define the contract for domain packs:
|
|
5
|
+
* - DomainPack types and validation
|
|
6
|
+
* - Pack loading and dependency resolution
|
|
7
|
+
* - Extended createDomainFacades() with pack support
|
|
8
|
+
* - OCP: standard domains unchanged when packs are absent
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
12
|
+
import { createAgentRuntime } from '../runtime/runtime.js';
|
|
13
|
+
import { createDomainFacade, createDomainFacades } from '../runtime/domain-ops.js';
|
|
14
|
+
import type { AgentRuntime } from '../runtime/types.js';
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
|
|
17
|
+
import type { DomainPack } from '../domain-packs/types.js';
|
|
18
|
+
import { validateDomainPack, SEMANTIC_FACADE_NAMES } from '../domain-packs/types.js';
|
|
19
|
+
import { resolveDependencies } from '../domain-packs/loader.js';
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Helpers: mock domain packs for testing
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
function createMockPack(overrides: Partial<DomainPack> = {}): DomainPack {
|
|
26
|
+
return {
|
|
27
|
+
name: 'test-design',
|
|
28
|
+
version: '1.0.0',
|
|
29
|
+
domains: ['design'],
|
|
30
|
+
ops: [
|
|
31
|
+
{
|
|
32
|
+
name: 'check_contrast',
|
|
33
|
+
description: 'Check WCAG contrast ratio between two colors.',
|
|
34
|
+
auth: 'read' as const,
|
|
35
|
+
schema: z.object({
|
|
36
|
+
foreground: z.string(),
|
|
37
|
+
background: z.string(),
|
|
38
|
+
}),
|
|
39
|
+
handler: async (_params) => {
|
|
40
|
+
return { ratio: 4.5, passes: true, level: 'AA' };
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'validate_token',
|
|
45
|
+
description: 'Validate a design token name against the token schema.',
|
|
46
|
+
auth: 'read' as const,
|
|
47
|
+
schema: z.object({ token: z.string() }),
|
|
48
|
+
handler: async (params) => {
|
|
49
|
+
return { valid: true, token: params.token };
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'get_color_pairs',
|
|
54
|
+
description: 'Get accessible color pair suggestions.',
|
|
55
|
+
auth: 'read' as const,
|
|
56
|
+
schema: z.object({ background: z.string() }),
|
|
57
|
+
handler: async (params) => {
|
|
58
|
+
return { pairs: [{ fg: '#000', bg: params.background, ratio: 21 }] };
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
...overrides,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function createMockPackWithFacades(): DomainPack {
|
|
67
|
+
return {
|
|
68
|
+
name: 'test-design-full',
|
|
69
|
+
version: '1.0.0',
|
|
70
|
+
domains: ['design'],
|
|
71
|
+
ops: [
|
|
72
|
+
{
|
|
73
|
+
name: 'check_contrast',
|
|
74
|
+
description: 'Check contrast.',
|
|
75
|
+
auth: 'read' as const,
|
|
76
|
+
handler: async () => ({ ratio: 4.5 }),
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
facades: [
|
|
80
|
+
{
|
|
81
|
+
name: 'design_rules',
|
|
82
|
+
description: 'Design rules and guidelines.',
|
|
83
|
+
ops: [
|
|
84
|
+
{
|
|
85
|
+
name: 'get_clean_code_rules',
|
|
86
|
+
description: 'Get clean code rules for design.',
|
|
87
|
+
auth: 'read' as const,
|
|
88
|
+
handler: async () => ({ rules: ['no-hex-colors', 'semantic-tokens-only'] }),
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'get_architecture_patterns',
|
|
92
|
+
description: 'Get architecture patterns.',
|
|
93
|
+
auth: 'read' as const,
|
|
94
|
+
handler: async () => ({ patterns: ['component-composition'] }),
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// 1. DomainPack Types & Validation
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
describe('DomainPack types and validation', () => {
|
|
107
|
+
it('should validate a well-formed domain pack', () => {
|
|
108
|
+
const pack = createMockPack();
|
|
109
|
+
const result = validateDomainPack(pack);
|
|
110
|
+
expect(result.success).toBe(true);
|
|
111
|
+
if (result.success) {
|
|
112
|
+
expect(result.data.name).toBe('test-design');
|
|
113
|
+
expect(result.data.ops.length).toBe(3);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should reject pack with missing required fields', () => {
|
|
118
|
+
const result = validateDomainPack({ name: 'incomplete' });
|
|
119
|
+
expect(result.success).toBe(false);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should reject pack with duplicate op names', () => {
|
|
123
|
+
const pack = createMockPack({
|
|
124
|
+
ops: [
|
|
125
|
+
{
|
|
126
|
+
name: 'duplicate_op',
|
|
127
|
+
description: 'First.',
|
|
128
|
+
auth: 'read',
|
|
129
|
+
handler: async () => ({}),
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
name: 'duplicate_op',
|
|
133
|
+
description: 'Second.',
|
|
134
|
+
auth: 'read',
|
|
135
|
+
handler: async () => ({}),
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
});
|
|
139
|
+
const result = validateDomainPack(pack);
|
|
140
|
+
expect(result.success).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should reject pack with facade name colliding with semantic facades', () => {
|
|
144
|
+
const pack = createMockPack({
|
|
145
|
+
facades: [
|
|
146
|
+
{
|
|
147
|
+
name: 'vault', // collides with semantic facade
|
|
148
|
+
description: 'Bad facade.',
|
|
149
|
+
ops: [],
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
});
|
|
153
|
+
const result = validateDomainPack(pack);
|
|
154
|
+
expect(result.success).toBe(false);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('should export SEMANTIC_FACADE_NAMES containing core facade names', () => {
|
|
158
|
+
expect(SEMANTIC_FACADE_NAMES).toContain('vault');
|
|
159
|
+
expect(SEMANTIC_FACADE_NAMES).toContain('plan');
|
|
160
|
+
expect(SEMANTIC_FACADE_NAMES).toContain('brain');
|
|
161
|
+
expect(SEMANTIC_FACADE_NAMES).toContain('memory');
|
|
162
|
+
expect(SEMANTIC_FACADE_NAMES).toContain('admin');
|
|
163
|
+
expect(SEMANTIC_FACADE_NAMES).toContain('curator');
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should accept pack with valid KnowledgeManifest tiers', () => {
|
|
167
|
+
const pack = createMockPack({
|
|
168
|
+
knowledge: {
|
|
169
|
+
canonical: './knowledge/canonical',
|
|
170
|
+
curated: './knowledge/curated',
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
const result = validateDomainPack(pack);
|
|
174
|
+
expect(result.success).toBe(true);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// 2. Pack Dependency Resolution
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
describe('Pack dependency resolution', () => {
|
|
183
|
+
it('should resolve packs with no dependencies', () => {
|
|
184
|
+
const packA = createMockPack({ name: 'pack-a' });
|
|
185
|
+
const packB = createMockPack({ name: 'pack-b', domains: ['testing'] });
|
|
186
|
+
const sorted = resolveDependencies([packA, packB]);
|
|
187
|
+
expect(sorted.length).toBe(2);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('should sort packs by dependency order', () => {
|
|
191
|
+
const packA = createMockPack({ name: 'pack-a', requires: ['pack-b'] });
|
|
192
|
+
const packB = createMockPack({ name: 'pack-b', domains: ['testing'] });
|
|
193
|
+
const sorted = resolveDependencies([packA, packB]);
|
|
194
|
+
const names = sorted.map((p) => p.name);
|
|
195
|
+
expect(names.indexOf('pack-b')).toBeLessThan(names.indexOf('pack-a'));
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('should detect circular dependencies', () => {
|
|
199
|
+
const packA = createMockPack({ name: 'pack-a', requires: ['pack-b'] });
|
|
200
|
+
const packB = createMockPack({ name: 'pack-b', domains: ['testing'], requires: ['pack-a'] });
|
|
201
|
+
expect(() => resolveDependencies([packA, packB])).toThrow(/circular/i);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should throw on missing dependency', () => {
|
|
205
|
+
const packA = createMockPack({ name: 'pack-a', requires: ['pack-nonexistent'] });
|
|
206
|
+
expect(() => resolveDependencies([packA])).toThrow(/not found/i);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
// 3. Extended createDomainFacades() with pack support
|
|
212
|
+
// ---------------------------------------------------------------------------
|
|
213
|
+
|
|
214
|
+
describe('createDomainFacades with packs', () => {
|
|
215
|
+
let runtime: AgentRuntime;
|
|
216
|
+
|
|
217
|
+
beforeEach(() => {
|
|
218
|
+
runtime = createAgentRuntime({
|
|
219
|
+
agentId: 'test-packs',
|
|
220
|
+
vaultPath: ':memory:',
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
afterEach(() => {
|
|
225
|
+
runtime.close();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// --- OCP: no packs = identical behavior ---
|
|
229
|
+
|
|
230
|
+
it('should work identically without packs parameter', () => {
|
|
231
|
+
const withoutPacks = createDomainFacades(runtime, 'test-packs', ['security']);
|
|
232
|
+
expect(withoutPacks.length).toBe(1);
|
|
233
|
+
expect(withoutPacks[0].ops.length).toBe(5);
|
|
234
|
+
expect(withoutPacks[0].name).toBe('test-packs_security');
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('should work identically with empty packs array', () => {
|
|
238
|
+
const withEmpty = createDomainFacades(runtime, 'test-packs', ['security'], []);
|
|
239
|
+
expect(withEmpty.length).toBe(1);
|
|
240
|
+
expect(withEmpty[0].ops.length).toBe(5);
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// --- Pack ops override standard ops ---
|
|
244
|
+
|
|
245
|
+
it('should use pack ops for claimed domain', () => {
|
|
246
|
+
const pack = createMockPack(); // claims 'design'
|
|
247
|
+
const facades = createDomainFacades(runtime, 'test-packs', ['design'], [pack]);
|
|
248
|
+
const designFacade = facades.find((f) => f.name.includes('design'));
|
|
249
|
+
expect(designFacade).toBeDefined();
|
|
250
|
+
|
|
251
|
+
// Should have pack's 3 custom ops + standard fallbacks for unclaimed names
|
|
252
|
+
const opNames = designFacade!.ops.map((o) => o.name);
|
|
253
|
+
expect(opNames).toContain('check_contrast');
|
|
254
|
+
expect(opNames).toContain('validate_token');
|
|
255
|
+
expect(opNames).toContain('get_color_pairs');
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it('should keep standard ops as fallbacks for names not in pack', () => {
|
|
259
|
+
const pack = createMockPack(); // has check_contrast, validate_token, get_color_pairs
|
|
260
|
+
const facades = createDomainFacades(runtime, 'test-packs', ['design'], [pack]);
|
|
261
|
+
const designFacade = facades.find((f) => f.name.includes('design'));
|
|
262
|
+
const opNames = designFacade!.ops.map((o) => o.name);
|
|
263
|
+
|
|
264
|
+
// Standard ops not overridden by pack should still exist as fallbacks
|
|
265
|
+
expect(opNames).toContain('get_patterns');
|
|
266
|
+
expect(opNames).toContain('search');
|
|
267
|
+
expect(opNames).toContain('get_entry');
|
|
268
|
+
expect(opNames).toContain('capture');
|
|
269
|
+
expect(opNames).toContain('remove');
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it('should use pack handler when pack overrides a standard op name', () => {
|
|
273
|
+
const customSearchHandler = async () => ({ custom: true, source: 'pack' });
|
|
274
|
+
const pack = createMockPack({
|
|
275
|
+
ops: [
|
|
276
|
+
{
|
|
277
|
+
name: 'search', // overrides standard search
|
|
278
|
+
description: 'Custom domain search with specialized ranking.',
|
|
279
|
+
auth: 'read' as const,
|
|
280
|
+
handler: customSearchHandler,
|
|
281
|
+
},
|
|
282
|
+
],
|
|
283
|
+
});
|
|
284
|
+
const facades = createDomainFacades(runtime, 'test-packs', ['design'], [pack]);
|
|
285
|
+
const designFacade = facades.find((f) => f.name.includes('design'));
|
|
286
|
+
const searchOp = designFacade!.ops.find((o) => o.name === 'search');
|
|
287
|
+
expect(searchOp!.handler).toBe(customSearchHandler);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// --- Unclaimed domains get standard 5 ops ---
|
|
291
|
+
|
|
292
|
+
it('should give unclaimed domains standard 5 ops', () => {
|
|
293
|
+
const pack = createMockPack(); // claims 'design' only
|
|
294
|
+
const facades = createDomainFacades(runtime, 'test-packs', ['design', 'security'], [pack]);
|
|
295
|
+
const securityFacade = facades.find((f) => f.name.includes('security'));
|
|
296
|
+
expect(securityFacade).toBeDefined();
|
|
297
|
+
expect(securityFacade!.ops.length).toBe(5);
|
|
298
|
+
expect(securityFacade!.ops.map((o) => o.name)).not.toContain('check_contrast');
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
// --- Pack standalone facades ---
|
|
302
|
+
|
|
303
|
+
it('should register pack standalone facades as additional facades', () => {
|
|
304
|
+
const pack = createMockPackWithFacades();
|
|
305
|
+
const facades = createDomainFacades(runtime, 'test-packs', ['design'], [pack]);
|
|
306
|
+
|
|
307
|
+
// Should have domain facade + standalone design_rules facade
|
|
308
|
+
const facadeNames = facades.map((f) => f.name);
|
|
309
|
+
expect(facadeNames.some((n) => n.includes('design_rules'))).toBe(true);
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
it('should prefix standalone facade names with agentId', () => {
|
|
313
|
+
const pack = createMockPackWithFacades();
|
|
314
|
+
const facades = createDomainFacades(runtime, 'test-packs', ['design'], [pack]);
|
|
315
|
+
const rulesFacade = facades.find((f) => f.name.includes('design_rules'));
|
|
316
|
+
expect(rulesFacade!.name).toBe('test-packs_design_rules');
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
it('standalone facade ops should be callable', async () => {
|
|
320
|
+
const pack = createMockPackWithFacades();
|
|
321
|
+
const facades = createDomainFacades(runtime, 'test-packs', ['design'], [pack]);
|
|
322
|
+
const rulesFacade = facades.find((f) => f.name.includes('design_rules'));
|
|
323
|
+
const cleanCodeOp = rulesFacade!.ops.find((o) => o.name === 'get_clean_code_rules');
|
|
324
|
+
const result = (await cleanCodeOp!.handler({})) as { rules: string[] };
|
|
325
|
+
expect(result.rules).toContain('no-hex-colors');
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// --- Custom ops are callable ---
|
|
329
|
+
|
|
330
|
+
it('custom pack ops should execute and return results', async () => {
|
|
331
|
+
const pack = createMockPack();
|
|
332
|
+
const facades = createDomainFacades(runtime, 'test-packs', ['design'], [pack]);
|
|
333
|
+
const designFacade = facades.find((f) => f.name.includes('design'));
|
|
334
|
+
const contrastOp = designFacade!.ops.find((o) => o.name === 'check_contrast');
|
|
335
|
+
const result = (await contrastOp!.handler({
|
|
336
|
+
foreground: '#000000',
|
|
337
|
+
background: '#ffffff',
|
|
338
|
+
})) as { ratio: number; passes: boolean };
|
|
339
|
+
expect(result.ratio).toBe(4.5);
|
|
340
|
+
expect(result.passes).toBe(true);
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
// --- Multiple packs ---
|
|
344
|
+
|
|
345
|
+
it('should support multiple packs claiming different domains', () => {
|
|
346
|
+
const designPack = createMockPack({ name: 'design-pack', domains: ['design'] });
|
|
347
|
+
const securityPack = createMockPack({
|
|
348
|
+
name: 'security-pack',
|
|
349
|
+
domains: ['security'],
|
|
350
|
+
ops: [
|
|
351
|
+
{
|
|
352
|
+
name: 'scan_vulnerabilities',
|
|
353
|
+
description: 'Scan for security vulnerabilities.',
|
|
354
|
+
auth: 'read' as const,
|
|
355
|
+
handler: async () => ({ vulnerabilities: [] }),
|
|
356
|
+
},
|
|
357
|
+
],
|
|
358
|
+
});
|
|
359
|
+
const facades = createDomainFacades(
|
|
360
|
+
runtime,
|
|
361
|
+
'test-packs',
|
|
362
|
+
['design', 'security'],
|
|
363
|
+
[designPack, securityPack],
|
|
364
|
+
);
|
|
365
|
+
expect(facades.length).toBeGreaterThanOrEqual(2);
|
|
366
|
+
|
|
367
|
+
const designOps = facades.find((f) => f.name.includes('design'))!.ops.map((o) => o.name);
|
|
368
|
+
const securityOps = facades.find((f) => f.name.includes('security'))!.ops.map((o) => o.name);
|
|
369
|
+
|
|
370
|
+
expect(designOps).toContain('check_contrast');
|
|
371
|
+
expect(securityOps).toContain('scan_vulnerabilities');
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
// ---------------------------------------------------------------------------
|
|
376
|
+
// 4. OCP Regression — existing behavior preserved
|
|
377
|
+
// ---------------------------------------------------------------------------
|
|
378
|
+
|
|
379
|
+
describe('OCP regression: existing domain-ops behavior', () => {
|
|
380
|
+
let runtime: AgentRuntime;
|
|
381
|
+
|
|
382
|
+
beforeEach(() => {
|
|
383
|
+
runtime = createAgentRuntime({
|
|
384
|
+
agentId: 'test-ocp',
|
|
385
|
+
vaultPath: ':memory:',
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
afterEach(() => {
|
|
390
|
+
runtime.close();
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
it('createDomainFacade (singular) still works unchanged', () => {
|
|
394
|
+
const facade = createDomainFacade(runtime, 'test-ocp', 'security');
|
|
395
|
+
expect(facade.ops.length).toBe(5);
|
|
396
|
+
expect(facade.name).toBe('test-ocp_security');
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it('createDomainFacades without 4th arg still returns standard facades', () => {
|
|
400
|
+
const facades = createDomainFacades(runtime, 'test-ocp', ['security', 'api-design']);
|
|
401
|
+
expect(facades.length).toBe(2);
|
|
402
|
+
facades.forEach((f) => {
|
|
403
|
+
expect(f.ops.length).toBe(5);
|
|
404
|
+
});
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it('standard domain capture still integrates with governance', async () => {
|
|
408
|
+
const facade = createDomainFacade(runtime, 'test-ocp', 'security');
|
|
409
|
+
const captureOp = facade.ops.find((o) => o.name === 'capture')!;
|
|
410
|
+
const result = (await captureOp.handler({
|
|
411
|
+
id: 'ocp-test-1',
|
|
412
|
+
type: 'pattern',
|
|
413
|
+
title: 'OCP Test',
|
|
414
|
+
severity: 'warning',
|
|
415
|
+
description: 'Should still work.',
|
|
416
|
+
tags: ['ocp'],
|
|
417
|
+
})) as { captured: boolean; governance: { action: string } };
|
|
418
|
+
expect(result.captured).toBe(true);
|
|
419
|
+
expect(result.governance.action).toBe('capture');
|
|
420
|
+
});
|
|
421
|
+
});
|