@soleri/core 9.2.0 → 9.3.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 +8 -9
- package/data/flows/deliver.flow.yaml +9 -10
- package/data/flows/design.flow.yaml +3 -4
- package/data/flows/enhance.flow.yaml +5 -6
- package/data/flows/explore.flow.yaml +3 -4
- package/data/flows/fix.flow.yaml +5 -6
- package/data/flows/plan.flow.yaml +4 -5
- package/data/flows/review.flow.yaml +3 -4
- package/dist/curator/curator.d.ts.map +1 -1
- package/dist/curator/curator.js +98 -22
- package/dist/curator/curator.js.map +1 -1
- package/dist/engine/bin/soleri-engine.js.map +1 -1
- package/dist/engine/module-manifest.d.ts.map +1 -1
- package/dist/engine/module-manifest.js +21 -1
- package/dist/engine/module-manifest.js.map +1 -1
- package/dist/engine/register-engine.d.ts.map +1 -1
- package/dist/engine/register-engine.js +25 -1
- package/dist/engine/register-engine.js.map +1 -1
- package/dist/flows/gate-evaluator.js.map +1 -1
- package/dist/operator/operator-profile.d.ts.map +1 -1
- package/dist/operator/operator-profile.js +11 -5
- package/dist/operator/operator-profile.js.map +1 -1
- package/dist/operator/operator-signals.d.ts.map +1 -1
- package/dist/operator/operator-signals.js.map +1 -1
- package/dist/planning/evidence-collector.js.map +1 -1
- package/dist/planning/gap-passes.d.ts.map +1 -1
- package/dist/planning/gap-passes.js +23 -6
- package/dist/planning/gap-passes.js.map +1 -1
- package/dist/planning/gap-patterns.d.ts.map +1 -1
- package/dist/planning/gap-patterns.js +57 -11
- package/dist/planning/gap-patterns.js.map +1 -1
- package/dist/planning/github-projection.d.ts.map +1 -1
- package/dist/planning/github-projection.js +39 -20
- package/dist/planning/github-projection.js.map +1 -1
- package/dist/planning/impact-analyzer.d.ts.map +1 -1
- package/dist/planning/impact-analyzer.js +20 -18
- package/dist/planning/impact-analyzer.js.map +1 -1
- package/dist/planning/plan-lifecycle.d.ts.map +1 -1
- package/dist/planning/plan-lifecycle.js +22 -9
- package/dist/planning/plan-lifecycle.js.map +1 -1
- package/dist/planning/planner.d.ts.map +1 -1
- package/dist/planning/planner.js +60 -17
- package/dist/planning/planner.js.map +1 -1
- package/dist/planning/rationalization-detector.d.ts.map +1 -1
- package/dist/planning/rationalization-detector.js.map +1 -1
- package/dist/planning/reconciliation-engine.d.ts.map +1 -1
- package/dist/planning/reconciliation-engine.js.map +1 -1
- package/dist/planning/task-verifier.d.ts.map +1 -1
- package/dist/planning/task-verifier.js +14 -6
- package/dist/planning/task-verifier.js.map +1 -1
- package/dist/runtime/admin-setup-ops.d.ts.map +1 -1
- package/dist/runtime/admin-setup-ops.js +2 -1
- package/dist/runtime/admin-setup-ops.js.map +1 -1
- package/dist/runtime/branching-ops.d.ts +12 -0
- package/dist/runtime/branching-ops.d.ts.map +1 -0
- package/dist/runtime/branching-ops.js +100 -0
- package/dist/runtime/branching-ops.js.map +1 -0
- package/dist/runtime/context-health.d.ts.map +1 -1
- package/dist/runtime/context-health.js.map +1 -1
- package/dist/runtime/facades/branching-facade.d.ts +7 -0
- package/dist/runtime/facades/branching-facade.d.ts.map +1 -0
- package/dist/runtime/facades/branching-facade.js +8 -0
- package/dist/runtime/facades/branching-facade.js.map +1 -0
- package/dist/runtime/facades/chat-service-ops.d.ts.map +1 -1
- package/dist/runtime/facades/chat-service-ops.js +3 -1
- package/dist/runtime/facades/chat-service-ops.js.map +1 -1
- package/dist/runtime/facades/chat-transport-ops.d.ts.map +1 -1
- package/dist/runtime/facades/chat-transport-ops.js.map +1 -1
- package/dist/runtime/facades/index.d.ts.map +1 -1
- package/dist/runtime/facades/index.js +42 -0
- package/dist/runtime/facades/index.js.map +1 -1
- package/dist/runtime/facades/intake-facade.d.ts +9 -0
- package/dist/runtime/facades/intake-facade.d.ts.map +1 -0
- package/dist/runtime/facades/intake-facade.js +11 -0
- package/dist/runtime/facades/intake-facade.js.map +1 -0
- package/dist/runtime/facades/links-facade.d.ts +9 -0
- package/dist/runtime/facades/links-facade.d.ts.map +1 -0
- package/dist/runtime/facades/links-facade.js +10 -0
- package/dist/runtime/facades/links-facade.js.map +1 -0
- package/dist/runtime/facades/operator-facade.d.ts.map +1 -1
- package/dist/runtime/facades/operator-facade.js.map +1 -1
- package/dist/runtime/facades/plan-facade.d.ts.map +1 -1
- package/dist/runtime/facades/plan-facade.js +4 -1
- package/dist/runtime/facades/plan-facade.js.map +1 -1
- package/dist/runtime/facades/tier-facade.d.ts +7 -0
- package/dist/runtime/facades/tier-facade.d.ts.map +1 -0
- package/dist/runtime/facades/tier-facade.js +8 -0
- package/dist/runtime/facades/tier-facade.js.map +1 -0
- package/dist/runtime/facades/vault-facade.d.ts +9 -1
- package/dist/runtime/facades/vault-facade.d.ts.map +1 -1
- package/dist/runtime/facades/vault-facade.js +44 -187
- package/dist/runtime/facades/vault-facade.js.map +1 -1
- package/dist/runtime/github-integration.d.ts.map +1 -1
- package/dist/runtime/github-integration.js +11 -4
- package/dist/runtime/github-integration.js.map +1 -1
- package/dist/runtime/orchestrate-ops.d.ts.map +1 -1
- package/dist/runtime/orchestrate-ops.js +32 -10
- package/dist/runtime/orchestrate-ops.js.map +1 -1
- package/dist/runtime/planning-extra-ops.d.ts.map +1 -1
- package/dist/runtime/planning-extra-ops.js.map +1 -1
- package/dist/runtime/runtime.d.ts.map +1 -1
- package/dist/runtime/runtime.js +3 -1
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/runtime/session-briefing.d.ts.map +1 -1
- package/dist/runtime/session-briefing.js +5 -1
- package/dist/runtime/session-briefing.js.map +1 -1
- package/dist/runtime/tier-ops.d.ts +13 -0
- package/dist/runtime/tier-ops.d.ts.map +1 -0
- package/dist/runtime/tier-ops.js +110 -0
- package/dist/runtime/tier-ops.js.map +1 -0
- package/dist/skills/sync-skills.d.ts.map +1 -1
- package/dist/skills/sync-skills.js +1 -1
- package/dist/skills/sync-skills.js.map +1 -1
- package/dist/vault/linking.d.ts.map +1 -1
- package/dist/vault/linking.js +41 -5
- package/dist/vault/linking.js.map +1 -1
- package/dist/vault/vault-entries.d.ts.map +1 -1
- package/dist/vault/vault-entries.js +68 -26
- package/dist/vault/vault-entries.js.map +1 -1
- package/dist/vault/vault-maintenance.d.ts.map +1 -1
- package/dist/vault/vault-maintenance.js +6 -2
- package/dist/vault/vault-maintenance.js.map +1 -1
- package/dist/vault/vault-markdown-sync.d.ts.map +1 -1
- package/dist/vault/vault-markdown-sync.js.map +1 -1
- package/dist/vault/vault-memories.d.ts.map +1 -1
- package/dist/vault/vault-memories.js +3 -1
- package/dist/vault/vault-memories.js.map +1 -1
- package/dist/vault/vault-schema.js +36 -10
- package/dist/vault/vault-schema.js.map +1 -1
- package/dist/vault/vault.d.ts.map +1 -1
- package/dist/vault/vault.js +5 -1
- package/dist/vault/vault.js.map +1 -1
- package/package.json +7 -7
- package/src/agency/agency-manager.test.ts +60 -40
- package/src/agency/default-rules.test.ts +17 -9
- package/src/capabilities/registry.test.ts +2 -12
- package/src/chat/agent-loop.test.ts +33 -43
- package/src/chat/mcp-bridge.test.ts +7 -2
- package/src/claudemd/inject.test.ts +2 -12
- package/src/context/context-engine.test.ts +96 -51
- package/src/control/intent-router.test.ts +3 -3
- package/src/curator/classifier.test.ts +14 -8
- package/src/curator/contradiction-detector.test.ts +30 -5
- package/src/curator/curator.ts +278 -56
- package/src/curator/duplicate-detector.test.ts +77 -15
- package/src/curator/quality-gate.test.ts +71 -31
- package/src/curator/tag-manager.test.ts +12 -4
- package/src/domain-packs/knowledge-installer.test.ts +2 -10
- package/src/domain-packs/token-resolver.test.ts +1 -3
- package/src/domain-packs/types.test.ts +16 -2
- package/src/enforcement/registry.test.ts +2 -8
- package/src/engine/bin/soleri-engine.ts +3 -1
- package/src/engine/module-manifest.test.ts +5 -4
- package/src/engine/module-manifest.ts +21 -1
- package/src/engine/register-engine.test.ts +6 -1
- package/src/engine/register-engine.ts +26 -3
- package/src/errors/classify.test.ts +6 -2
- package/src/errors/retry.test.ts +1 -4
- package/src/facades/facade-factory.test.ts +110 -64
- package/src/flows/epilogue.test.ts +16 -10
- package/src/flows/gate-evaluator.test.ts +12 -6
- package/src/flows/gate-evaluator.ts +1 -3
- package/src/governance/governance.test.ts +137 -21
- package/src/health/health-registry.test.ts +8 -1
- package/src/intake/content-classifier.test.ts +121 -51
- package/src/intake/dedup-gate.test.ts +38 -22
- package/src/intake/intake-pipeline.test.ts +5 -3
- package/src/intake/text-ingester.test.ts +26 -20
- package/src/llm/key-pool.test.ts +1 -3
- package/src/llm/llm-client.test.ts +1 -4
- package/src/llm/oauth-discovery.test.ts +16 -16
- package/src/llm/utils.test.ts +62 -18
- package/src/logging/logger.test.ts +4 -1
- package/src/loop/loop-manager.test.ts +2 -6
- package/src/migrations/migration-runner.edge-cases.test.ts +2 -7
- package/src/operator/operator-profile-extended.test.ts +15 -5
- package/src/operator/operator-profile.test.ts +26 -8
- package/src/operator/operator-profile.ts +38 -22
- package/src/operator/operator-signals-extended.test.ts +35 -23
- package/src/operator/operator-signals.test.ts +6 -10
- package/src/operator/operator-signals.ts +2 -1
- package/src/operator/prompts/hook-precompact-operator-dispatch.md +10 -6
- package/src/operator/prompts/subagent-soft-signal-extractor.md +5 -0
- package/src/operator/prompts/subagent-synthesis-cognition.md +19 -10
- package/src/operator/prompts/subagent-synthesis-communication.md +13 -7
- package/src/operator/prompts/subagent-synthesis-technical.md +19 -9
- package/src/operator/prompts/subagent-synthesis-trust.md +27 -21
- package/src/persona/defaults.test.ts +1 -5
- package/src/planning/evidence-collector.test.ts +147 -38
- package/src/planning/evidence-collector.ts +1 -4
- package/src/planning/gap-analysis-alternatives.test.ts +41 -11
- package/src/planning/gap-passes.test.ts +215 -33
- package/src/planning/gap-passes.ts +115 -46
- package/src/planning/gap-patterns.test.ts +87 -13
- package/src/planning/gap-patterns.ts +114 -31
- package/src/planning/github-projection.test.ts +6 -1
- package/src/planning/github-projection.ts +41 -20
- package/src/planning/impact-analyzer.test.ts +10 -23
- package/src/planning/impact-analyzer.ts +33 -46
- package/src/planning/plan-lifecycle.test.ts +103 -36
- package/src/planning/plan-lifecycle.ts +49 -18
- package/src/planning/planner.test.ts +12 -2
- package/src/planning/planner.ts +198 -58
- package/src/planning/rationalization-detector.test.ts +5 -20
- package/src/planning/rationalization-detector.ts +14 -16
- package/src/planning/reconciliation-engine.test.ts +20 -3
- package/src/planning/reconciliation-engine.ts +1 -2
- package/src/planning/task-verifier.test.ts +59 -27
- package/src/planning/task-verifier.ts +15 -9
- package/src/playbooks/playbook-executor.test.ts +1 -3
- package/src/plugins/plugin-loader.test.ts +19 -14
- package/src/plugins/plugin-registry.test.ts +45 -33
- package/src/project/project-registry.test.ts +23 -12
- package/src/prompts/template-manager.test.ts +4 -1
- package/src/queue/job-queue.test.ts +10 -14
- package/src/runtime/admin-extra-ops.test.ts +5 -19
- package/src/runtime/admin-ops.test.ts +1 -3
- package/src/runtime/admin-setup-ops.test.ts +3 -4
- package/src/runtime/admin-setup-ops.ts +9 -2
- package/src/runtime/archive-ops.test.ts +4 -1
- package/src/runtime/branching-ops.test.ts +144 -0
- package/src/runtime/branching-ops.ts +107 -0
- package/src/runtime/capture-ops.test.ts +7 -21
- package/src/runtime/chain-ops.test.ts +16 -6
- package/src/runtime/claude-md-helpers.test.ts +1 -3
- package/src/runtime/context-health.test.ts +1 -3
- package/src/runtime/context-health.ts +1 -3
- package/src/runtime/curator-extra-ops.test.ts +3 -1
- package/src/runtime/domain-ops.test.ts +46 -36
- package/src/runtime/facades/admin-facade.test.ts +1 -4
- package/src/runtime/facades/archive-facade.test.ts +21 -7
- package/src/runtime/facades/brain-facade.test.ts +176 -72
- package/src/runtime/facades/branching-facade.test.ts +43 -0
- package/src/runtime/facades/branching-facade.ts +11 -0
- package/src/runtime/facades/chat-facade.test.ts +81 -28
- package/src/runtime/facades/chat-service-ops.test.ts +178 -73
- package/src/runtime/facades/chat-service-ops.ts +3 -1
- package/src/runtime/facades/chat-session-ops.test.ts +25 -10
- package/src/runtime/facades/chat-transport-ops.test.ts +101 -34
- package/src/runtime/facades/chat-transport-ops.ts +0 -1
- package/src/runtime/facades/context-facade.test.ts +19 -4
- package/src/runtime/facades/control-facade.test.ts +3 -3
- package/src/runtime/facades/index.ts +42 -0
- package/src/runtime/facades/intake-facade.test.ts +215 -0
- package/src/runtime/facades/intake-facade.ts +14 -0
- package/src/runtime/facades/links-facade.test.ts +203 -0
- package/src/runtime/facades/links-facade.ts +13 -0
- package/src/runtime/facades/loop-facade.test.ts +22 -5
- package/src/runtime/facades/memory-facade.test.ts +19 -5
- package/src/runtime/facades/operator-facade.test.ts +17 -4
- package/src/runtime/facades/operator-facade.ts +11 -3
- package/src/runtime/facades/orchestrate-facade.test.ts +7 -1
- package/src/runtime/facades/plan-facade.test.ts +29 -12
- package/src/runtime/facades/plan-facade.ts +7 -2
- package/src/runtime/facades/tier-facade.test.ts +47 -0
- package/src/runtime/facades/tier-facade.ts +11 -0
- package/src/runtime/facades/vault-facade.test.ts +174 -242
- package/src/runtime/facades/vault-facade.ts +55 -199
- package/src/runtime/github-integration.ts +11 -8
- package/src/runtime/grading-ops.test.ts +39 -8
- package/src/runtime/intake-ops.test.ts +69 -16
- package/src/runtime/loop-ops.test.ts +16 -6
- package/src/runtime/memory-cross-project-ops.test.ts +25 -14
- package/src/runtime/orchestrate-ops.ts +54 -27
- package/src/runtime/pack-ops.test.ts +23 -6
- package/src/runtime/planning-extra-ops.test.ts +17 -7
- package/src/runtime/planning-extra-ops.ts +3 -1
- package/src/runtime/playbook-ops.test.ts +26 -3
- package/src/runtime/plugin-ops.test.ts +83 -25
- package/src/runtime/project-ops.test.ts +26 -6
- package/src/runtime/runtime.ts +3 -1
- package/src/runtime/session-briefing.test.ts +183 -54
- package/src/runtime/session-briefing.ts +8 -2
- package/src/runtime/sync-ops.test.ts +3 -12
- package/src/runtime/telemetry-ops.test.ts +31 -6
- package/src/runtime/tier-ops.test.ts +159 -0
- package/src/runtime/tier-ops.ts +119 -0
- package/src/runtime/vault-extra-ops.test.ts +32 -8
- package/src/runtime/vault-sharing-ops.test.ts +1 -4
- package/src/skills/sync-skills.ts +2 -12
- package/src/transport/ws-server.test.ts +7 -4
- package/src/vault/__tests__/vault-characterization.test.ts +492 -81
- package/src/vault/linking.test.ts +50 -17
- package/src/vault/linking.ts +48 -7
- package/src/vault/obsidian-sync.test.ts +6 -3
- package/src/vault/scope-detector.test.ts +1 -3
- package/src/vault/vault-branching.test.ts +9 -7
- package/src/vault/vault-entries.ts +209 -65
- package/src/vault/vault-maintenance.ts +7 -12
- package/src/vault/vault-manager.test.ts +10 -10
- package/src/vault/vault-markdown-sync.ts +4 -1
- package/src/vault/vault-memories.ts +7 -7
- package/src/vault/vault-schema.ts +72 -15
- package/src/vault/vault.ts +55 -9
- package/src/brain/strength-scorer.ts +0 -404
- package/src/engine/index.ts +0 -21
- package/src/persona/index.ts +0 -9
- package/src/vault/vault-interfaces.ts +0 -56
|
@@ -8,9 +8,7 @@ function makeMockRuntime(overrides: Record<string, unknown> = {}) {
|
|
|
8
8
|
vault: {
|
|
9
9
|
get: vi.fn().mockReturnValue({ id: 'e1', tags: ['pattern'] }),
|
|
10
10
|
update: vi.fn(),
|
|
11
|
-
searchMemories: vi.fn().mockReturnValue([
|
|
12
|
-
{ id: 'm1', content: 'memory 1' },
|
|
13
|
-
]),
|
|
11
|
+
searchMemories: vi.fn().mockReturnValue([{ id: 'm1', content: 'memory 1' }]),
|
|
14
12
|
search: vi.fn().mockReturnValue([
|
|
15
13
|
{ entry: { id: 'g1', tags: ['_global'] }, score: 0.9 },
|
|
16
14
|
{ entry: { id: 'g2', tags: ['other'] }, score: 0.8 },
|
|
@@ -25,9 +23,9 @@ function makeMockRuntime(overrides: Record<string, unknown> = {}) {
|
|
|
25
23
|
metadata: { memoryConfig: { crossProjectEnabled: true, extraPaths: ['/extra'] } },
|
|
26
24
|
}),
|
|
27
25
|
register: vi.fn(),
|
|
28
|
-
getLinkedProjects: vi
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
getLinkedProjects: vi
|
|
27
|
+
.fn()
|
|
28
|
+
.mockReturnValue([{ project: { path: '/linked', name: 'linked-project' } }]),
|
|
31
29
|
},
|
|
32
30
|
} as unknown as AgentRuntime;
|
|
33
31
|
}
|
|
@@ -60,7 +58,9 @@ describe('createMemoryCrossProjectOps', () => {
|
|
|
60
58
|
it('promotes entry by adding _global tag', async () => {
|
|
61
59
|
const runtime = makeMockRuntime();
|
|
62
60
|
ops = createMemoryCrossProjectOps(runtime);
|
|
63
|
-
const result = (await findOp('memory_promote_to_global').handler({
|
|
61
|
+
const result = (await findOp('memory_promote_to_global').handler({
|
|
62
|
+
entryId: 'e1',
|
|
63
|
+
})) as Record<string, unknown>;
|
|
64
64
|
expect(result.promoted).toBe(true);
|
|
65
65
|
expect(result.tags).toContain('_global');
|
|
66
66
|
expect(runtime.vault.update).toHaveBeenCalledWith('e1', { tags: ['pattern', '_global'] });
|
|
@@ -69,7 +69,9 @@ describe('createMemoryCrossProjectOps', () => {
|
|
|
69
69
|
it('returns error when entry not found', async () => {
|
|
70
70
|
const runtime = makeMockRuntime({ get: vi.fn().mockReturnValue(null) });
|
|
71
71
|
ops = createMemoryCrossProjectOps(runtime);
|
|
72
|
-
const result = (await findOp('memory_promote_to_global').handler({
|
|
72
|
+
const result = (await findOp('memory_promote_to_global').handler({
|
|
73
|
+
entryId: 'missing',
|
|
74
|
+
})) as Record<string, unknown>;
|
|
73
75
|
expect(result.promoted).toBe(false);
|
|
74
76
|
expect(result.error).toContain('Entry not found');
|
|
75
77
|
});
|
|
@@ -79,7 +81,9 @@ describe('createMemoryCrossProjectOps', () => {
|
|
|
79
81
|
get: vi.fn().mockReturnValue({ id: 'e1', tags: ['_global'] }),
|
|
80
82
|
});
|
|
81
83
|
ops = createMemoryCrossProjectOps(runtime);
|
|
82
|
-
const result = (await findOp('memory_promote_to_global').handler({
|
|
84
|
+
const result = (await findOp('memory_promote_to_global').handler({
|
|
85
|
+
entryId: 'e1',
|
|
86
|
+
})) as Record<string, unknown>;
|
|
83
87
|
expect(result.promoted).toBe(false);
|
|
84
88
|
expect(result.message).toContain('already promoted');
|
|
85
89
|
});
|
|
@@ -132,12 +136,15 @@ describe('createMemoryCrossProjectOps', () => {
|
|
|
132
136
|
const runtime = makeMockRuntime();
|
|
133
137
|
ops = createMemoryCrossProjectOps(runtime);
|
|
134
138
|
await findOp('memory_cross_project_search').handler({
|
|
135
|
-
query: 'test',
|
|
139
|
+
query: 'test',
|
|
140
|
+
projectPath: '/test',
|
|
136
141
|
});
|
|
137
142
|
|
|
138
143
|
// Should search current project, linked project, and extra path
|
|
139
144
|
const searchCalls = (runtime.vault.searchMemories as ReturnType<typeof vi.fn>).mock.calls;
|
|
140
|
-
const searchedPaths = searchCalls.map(
|
|
145
|
+
const searchedPaths = searchCalls.map(
|
|
146
|
+
(c: unknown[]) => (c[1] as Record<string, unknown>).projectPath,
|
|
147
|
+
);
|
|
141
148
|
expect(searchedPaths).toContain('/test');
|
|
142
149
|
expect(searchedPaths).toContain('/linked');
|
|
143
150
|
expect(searchedPaths).toContain('/extra');
|
|
@@ -151,7 +158,8 @@ describe('createMemoryCrossProjectOps', () => {
|
|
|
151
158
|
]);
|
|
152
159
|
ops = createMemoryCrossProjectOps(runtime);
|
|
153
160
|
const result = (await findOp('memory_cross_project_search').handler({
|
|
154
|
-
query: 'test',
|
|
161
|
+
query: 'test',
|
|
162
|
+
projectPath: '/test',
|
|
155
163
|
})) as Record<string, unknown>;
|
|
156
164
|
|
|
157
165
|
// linkedMemories should be empty because m1 was already in current results
|
|
@@ -162,12 +170,15 @@ describe('createMemoryCrossProjectOps', () => {
|
|
|
162
170
|
it('skips linked search when cross-project disabled', async () => {
|
|
163
171
|
const runtime = makeMockRuntime();
|
|
164
172
|
(runtime.projectRegistry.getByPath as ReturnType<typeof vi.fn>).mockReturnValue({
|
|
165
|
-
id: 'proj-1',
|
|
173
|
+
id: 'proj-1',
|
|
174
|
+
name: 'test',
|
|
175
|
+
path: '/test',
|
|
166
176
|
metadata: { memoryConfig: { crossProjectEnabled: false } },
|
|
167
177
|
});
|
|
168
178
|
ops = createMemoryCrossProjectOps(runtime);
|
|
169
179
|
const result = (await findOp('memory_cross_project_search').handler({
|
|
170
|
-
query: 'test',
|
|
180
|
+
query: 'test',
|
|
181
|
+
projectPath: '/test',
|
|
171
182
|
})) as Record<string, unknown>;
|
|
172
183
|
|
|
173
184
|
expect(runtime.projectRegistry.getLinkedProjects).not.toHaveBeenCalled();
|
|
@@ -182,10 +182,7 @@ function buildHealthWarning(
|
|
|
182
182
|
* Collect all acceptance criteria from a plan's tasks.
|
|
183
183
|
* Returns empty array if plan not found or has no criteria (graceful skip).
|
|
184
184
|
*/
|
|
185
|
-
function collectAcceptanceCriteria(
|
|
186
|
-
plannerRef: AgentRuntime['planner'],
|
|
187
|
-
planId: string,
|
|
188
|
-
): string[] {
|
|
185
|
+
function collectAcceptanceCriteria(plannerRef: AgentRuntime['planner'], planId: string): string[] {
|
|
189
186
|
const plan = plannerRef.get(planId);
|
|
190
187
|
if (!plan) return [];
|
|
191
188
|
const criteria: string[] = [];
|
|
@@ -210,7 +207,8 @@ function captureRationalizationAntiPattern(
|
|
|
210
207
|
vaultRef.add({
|
|
211
208
|
id: `antipattern-rationalization-${Date.now()}`,
|
|
212
209
|
title: 'Rationalization detected in completion claim',
|
|
213
|
-
description:
|
|
210
|
+
description:
|
|
211
|
+
`Detected rationalization patterns: ${patterns}. ` +
|
|
214
212
|
`Items: ${report.items.map((i) => `"${i.phrase}" (${i.pattern})`).join('; ')}.`,
|
|
215
213
|
type: 'anti-pattern',
|
|
216
214
|
domain: 'planning',
|
|
@@ -247,7 +245,10 @@ export function createOrchestrateOps(
|
|
|
247
245
|
'a pruned orchestration plan with gate-guarded steps.',
|
|
248
246
|
auth: 'write',
|
|
249
247
|
schema: z.object({
|
|
250
|
-
prompt: z
|
|
248
|
+
prompt: z
|
|
249
|
+
.string()
|
|
250
|
+
.optional()
|
|
251
|
+
.describe('Natural language description of what to do (or use objective)'),
|
|
251
252
|
projectPath: z.string().optional().default('.').describe('Project root path'),
|
|
252
253
|
// Legacy params — still accepted for backward compat
|
|
253
254
|
objective: z.string().optional().describe('(Legacy) Plan objective — use prompt instead'),
|
|
@@ -277,9 +278,10 @@ export function createOrchestrateOps(
|
|
|
277
278
|
recommendations = raw.map((r) => {
|
|
278
279
|
// Look up vault entry ID by title for feedback tracking
|
|
279
280
|
const entries = vault.search(r.pattern, { limit: 1 });
|
|
280
|
-
const entryId =
|
|
281
|
-
|
|
282
|
-
|
|
281
|
+
const entryId =
|
|
282
|
+
entries.length > 0 && entries[0].entry.title === r.pattern
|
|
283
|
+
? entries[0].entry.id
|
|
284
|
+
: undefined;
|
|
283
285
|
return { pattern: r.pattern, strength: r.strength, entryId };
|
|
284
286
|
});
|
|
285
287
|
} catch {
|
|
@@ -307,12 +309,10 @@ export function createOrchestrateOps(
|
|
|
307
309
|
planStore.set(plan.planId, { plan, createdAt: Date.now() });
|
|
308
310
|
|
|
309
311
|
// 5. Also create a planner plan for lifecycle tracking (backward compat)
|
|
310
|
-
const decisions = recommendations.map(
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
},
|
|
315
|
-
);
|
|
312
|
+
const decisions = recommendations.map((r) => {
|
|
313
|
+
const base = `Brain pattern: ${r.pattern} (strength: ${r.strength.toFixed(1)})`;
|
|
314
|
+
return r.entryId ? `${base} [entryId:${r.entryId}]` : base;
|
|
315
|
+
});
|
|
316
316
|
const tasks = (params.tasks as Array<{ title: string; description: string }>) ?? [];
|
|
317
317
|
|
|
318
318
|
// 5b. Extract GitHub issue context if prompt references #NNN
|
|
@@ -333,7 +333,8 @@ export function createOrchestrateOps(
|
|
|
333
333
|
}
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
-
const planObjective =
|
|
336
|
+
const planObjective =
|
|
337
|
+
((params as Record<string, unknown>)._enrichedObjective as string | undefined) ?? prompt;
|
|
337
338
|
|
|
338
339
|
let legacyPlan;
|
|
339
340
|
try {
|
|
@@ -478,11 +479,21 @@ export function createOrchestrateOps(
|
|
|
478
479
|
.optional()
|
|
479
480
|
.default('completed')
|
|
480
481
|
.describe('Plan outcome'),
|
|
481
|
-
summary: z
|
|
482
|
+
summary: z
|
|
483
|
+
.string()
|
|
484
|
+
.optional()
|
|
485
|
+
.describe('Completion summary — checked for rationalization language'),
|
|
482
486
|
toolsUsed: z.array(z.string()).optional().describe('Tools used during execution'),
|
|
483
487
|
filesModified: z.array(z.string()).optional().describe('Files modified during execution'),
|
|
484
|
-
projectPath: z
|
|
485
|
-
|
|
488
|
+
projectPath: z
|
|
489
|
+
.string()
|
|
490
|
+
.optional()
|
|
491
|
+
.default('.')
|
|
492
|
+
.describe('Project root path for impact analysis'),
|
|
493
|
+
overrideRationalization: z
|
|
494
|
+
.boolean()
|
|
495
|
+
.optional()
|
|
496
|
+
.default(false)
|
|
486
497
|
.describe('Set true to bypass rationalization gate and impact warnings after review'),
|
|
487
498
|
}),
|
|
488
499
|
handler: async (params) => {
|
|
@@ -517,9 +528,7 @@ export function createOrchestrateOps(
|
|
|
517
528
|
try {
|
|
518
529
|
const analyzer = new ImpactAnalyzer();
|
|
519
530
|
const planObj = planner.get(planId);
|
|
520
|
-
const scopeHints = planObj?.scope
|
|
521
|
-
? [planObj.scope]
|
|
522
|
-
: undefined;
|
|
531
|
+
const scopeHints = planObj?.scope ? [planObj.scope] : undefined;
|
|
523
532
|
impactReport = analyzer.analyzeImpact(
|
|
524
533
|
filesModified,
|
|
525
534
|
(params.projectPath as string) ?? '.',
|
|
@@ -710,11 +719,22 @@ export function createOrchestrateOps(
|
|
|
710
719
|
auth: 'write',
|
|
711
720
|
schema: z.object({
|
|
712
721
|
planId: z.string().describe('ID of the plan to project to GitHub'),
|
|
713
|
-
projectPath: z
|
|
722
|
+
projectPath: z
|
|
723
|
+
.string()
|
|
724
|
+
.optional()
|
|
725
|
+
.default('.')
|
|
726
|
+
.describe('Project root path for git detection'),
|
|
714
727
|
milestone: z.number().optional().describe('GitHub milestone number to assign issues to'),
|
|
715
728
|
labels: z.array(z.string()).optional().describe('Labels to apply to created issues'),
|
|
716
|
-
linkToIssue: z
|
|
717
|
-
|
|
729
|
+
linkToIssue: z
|
|
730
|
+
.number()
|
|
731
|
+
.optional()
|
|
732
|
+
.describe('Existing issue number to link plan to instead of creating new issues'),
|
|
733
|
+
dryRun: z
|
|
734
|
+
.boolean()
|
|
735
|
+
.optional()
|
|
736
|
+
.default(false)
|
|
737
|
+
.describe('Preview what would be created without actually creating issues'),
|
|
718
738
|
}),
|
|
719
739
|
handler: async (params) => {
|
|
720
740
|
const planId = params.planId as string;
|
|
@@ -729,7 +749,9 @@ export function createOrchestrateOps(
|
|
|
729
749
|
if (!plan) throw new Error(`Plan not found: ${planId}`);
|
|
730
750
|
|
|
731
751
|
if (plan.tasks.length === 0) {
|
|
732
|
-
throw new Error(
|
|
752
|
+
throw new Error(
|
|
753
|
+
'Plan has no tasks — run plan_split first to define tasks before projecting to GitHub',
|
|
754
|
+
);
|
|
733
755
|
}
|
|
734
756
|
|
|
735
757
|
// 2. Detect GitHub context
|
|
@@ -807,7 +829,12 @@ export function createOrchestrateOps(
|
|
|
807
829
|
|
|
808
830
|
// 6. Create issues per task (with duplicate detection)
|
|
809
831
|
const created: Array<{ taskId: string; issueNumber: number; title: string }> = [];
|
|
810
|
-
const skipped: Array<{
|
|
832
|
+
const skipped: Array<{
|
|
833
|
+
taskId: string;
|
|
834
|
+
title: string;
|
|
835
|
+
existingIssue: number;
|
|
836
|
+
reason: string;
|
|
837
|
+
}> = [];
|
|
811
838
|
const failed: Array<{ taskId: string; title: string; reason: string }> = [];
|
|
812
839
|
|
|
813
840
|
for (const task of plan.tasks) {
|
|
@@ -54,7 +54,10 @@ describe('createPackOps', () => {
|
|
|
54
54
|
runtime = makeMockRuntime();
|
|
55
55
|
ops = createPackOps(runtime);
|
|
56
56
|
expect(ops.map((o) => o.name)).toEqual([
|
|
57
|
-
'pack_validate',
|
|
57
|
+
'pack_validate',
|
|
58
|
+
'pack_install',
|
|
59
|
+
'pack_list',
|
|
60
|
+
'pack_uninstall',
|
|
58
61
|
]);
|
|
59
62
|
});
|
|
60
63
|
|
|
@@ -91,7 +94,10 @@ describe('createPackOps', () => {
|
|
|
91
94
|
const hotRegister = vi.fn();
|
|
92
95
|
setHotRegister(hotRegister);
|
|
93
96
|
ops = createPackOps(runtime);
|
|
94
|
-
const result = (await findOp('pack_install').handler({ packDir: '/packs/test' })) as Record<
|
|
97
|
+
const result = (await findOp('pack_install').handler({ packDir: '/packs/test' })) as Record<
|
|
98
|
+
string,
|
|
99
|
+
unknown
|
|
100
|
+
>;
|
|
95
101
|
expect(hotRegister).toHaveBeenCalledWith('test-agent_design', 'Design facade', []);
|
|
96
102
|
expect(result.hotReloaded).toBe(true);
|
|
97
103
|
});
|
|
@@ -99,14 +105,19 @@ describe('createPackOps', () => {
|
|
|
99
105
|
it('skips hot-register when no callback set', async () => {
|
|
100
106
|
runtime = makeMockRuntime();
|
|
101
107
|
ops = createPackOps(runtime);
|
|
102
|
-
const result = (await findOp('pack_install').handler({ packDir: '/packs/test' })) as Record<
|
|
108
|
+
const result = (await findOp('pack_install').handler({ packDir: '/packs/test' })) as Record<
|
|
109
|
+
string,
|
|
110
|
+
unknown
|
|
111
|
+
>;
|
|
103
112
|
expect(result.hotReloaded).toBeUndefined();
|
|
104
113
|
});
|
|
105
114
|
|
|
106
115
|
it('skips hot-register when no facades', async () => {
|
|
107
116
|
runtime = makeMockRuntime();
|
|
108
117
|
(runtime.packInstaller.install as ReturnType<typeof vi.fn>).mockResolvedValue({
|
|
109
|
-
installed: true,
|
|
118
|
+
installed: true,
|
|
119
|
+
id: 'pack-1',
|
|
120
|
+
facades: 0,
|
|
110
121
|
});
|
|
111
122
|
const hotRegister = vi.fn();
|
|
112
123
|
setHotRegister(hotRegister);
|
|
@@ -142,7 +153,10 @@ describe('createPackOps', () => {
|
|
|
142
153
|
it('uninstalls a pack', async () => {
|
|
143
154
|
runtime = makeMockRuntime();
|
|
144
155
|
ops = createPackOps(runtime);
|
|
145
|
-
const result = (await findOp('pack_uninstall').handler({ packId: 'pack-1' })) as Record<
|
|
156
|
+
const result = (await findOp('pack_uninstall').handler({ packId: 'pack-1' })) as Record<
|
|
157
|
+
string,
|
|
158
|
+
unknown
|
|
159
|
+
>;
|
|
146
160
|
expect(result.uninstalled).toBe(true);
|
|
147
161
|
expect(result.id).toBe('pack-1');
|
|
148
162
|
});
|
|
@@ -151,7 +165,10 @@ describe('createPackOps', () => {
|
|
|
151
165
|
runtime = makeMockRuntime();
|
|
152
166
|
(runtime.packInstaller.uninstall as ReturnType<typeof vi.fn>).mockReturnValue(false);
|
|
153
167
|
ops = createPackOps(runtime);
|
|
154
|
-
const result = (await findOp('pack_uninstall').handler({ packId: 'missing' })) as Record<
|
|
168
|
+
const result = (await findOp('pack_uninstall').handler({ packId: 'missing' })) as Record<
|
|
169
|
+
string,
|
|
170
|
+
unknown
|
|
171
|
+
>;
|
|
155
172
|
expect(result.error).toContain('Pack not found');
|
|
156
173
|
});
|
|
157
174
|
});
|
|
@@ -70,11 +70,17 @@ function createMockRuntime(): AgentRuntime {
|
|
|
70
70
|
return {
|
|
71
71
|
planner: {
|
|
72
72
|
iterate: vi.fn(() => plan),
|
|
73
|
-
splitTasks: vi.fn(() => ({
|
|
73
|
+
splitTasks: vi.fn(() => ({
|
|
74
|
+
...plan,
|
|
75
|
+
tasks: [plan.tasks[0], { id: 'task-2', title: 'Task 2' }],
|
|
76
|
+
})),
|
|
74
77
|
reconcile: vi.fn(() => ({
|
|
75
78
|
...plan,
|
|
76
79
|
status: 'reconciling',
|
|
77
|
-
reconciliation: {
|
|
80
|
+
reconciliation: {
|
|
81
|
+
accuracy: 85,
|
|
82
|
+
driftItems: [{ type: 'added', description: 'Extra test' }],
|
|
83
|
+
},
|
|
78
84
|
})),
|
|
79
85
|
get: vi.fn(() => plan),
|
|
80
86
|
getDispatch: vi.fn(() => ({ task: plan.tasks[0], ready: true, unmetDeps: [] })),
|
|
@@ -147,14 +153,20 @@ describe('createPlanningExtraOps', () => {
|
|
|
147
153
|
objective: 'New objective',
|
|
148
154
|
})) as Record<string, unknown>;
|
|
149
155
|
expect(result.iterated).toBe(true);
|
|
150
|
-
expect(runtime.planner.iterate).toHaveBeenCalledWith(
|
|
156
|
+
expect(runtime.planner.iterate).toHaveBeenCalledWith(
|
|
157
|
+
'plan-1',
|
|
158
|
+
expect.objectContaining({ objective: 'New objective' }),
|
|
159
|
+
);
|
|
151
160
|
});
|
|
152
161
|
|
|
153
162
|
it('returns error on failure', async () => {
|
|
154
163
|
vi.mocked(runtime.planner.iterate).mockImplementation(() => {
|
|
155
164
|
throw new Error('Not a draft');
|
|
156
165
|
});
|
|
157
|
-
const result = (await findOp(ops, 'plan_iterate').handler({ planId: 'x' })) as Record<
|
|
166
|
+
const result = (await findOp(ops, 'plan_iterate').handler({ planId: 'x' })) as Record<
|
|
167
|
+
string,
|
|
168
|
+
unknown
|
|
169
|
+
>;
|
|
158
170
|
expect(result.error).toBe('Not a draft');
|
|
159
171
|
});
|
|
160
172
|
});
|
|
@@ -569,9 +581,7 @@ describe('createPlanningExtraOps', () => {
|
|
|
569
581
|
});
|
|
570
582
|
|
|
571
583
|
it('purges specific plans by ID', async () => {
|
|
572
|
-
vi.mocked(runtime.planner.list).mockReturnValue([
|
|
573
|
-
makePlan({ id: 'plan-1' }),
|
|
574
|
-
] as unknown);
|
|
584
|
+
vi.mocked(runtime.planner.list).mockReturnValue([makePlan({ id: 'plan-1' })] as unknown);
|
|
575
585
|
const result = (await findOp(ops, 'plan_purge').handler({
|
|
576
586
|
mode: 'specific',
|
|
577
587
|
planIds: ['plan-1'],
|
|
@@ -46,7 +46,9 @@ export function createPlanningExtraOps(runtime: AgentRuntime): OpDefinition[] {
|
|
|
46
46
|
decisions: z
|
|
47
47
|
.array(z.union([z.string(), z.object({ decision: z.string(), rationale: z.string() })]))
|
|
48
48
|
.optional()
|
|
49
|
-
.describe(
|
|
49
|
+
.describe(
|
|
50
|
+
'New decisions list (replaces existing) — strings or {decision, rationale} objects',
|
|
51
|
+
),
|
|
50
52
|
addTasks: z
|
|
51
53
|
.array(z.object({ title: z.string(), description: z.string() }))
|
|
52
54
|
.optional()
|
|
@@ -9,7 +9,19 @@ import type { AgentRuntime } from './types.js';
|
|
|
9
9
|
|
|
10
10
|
/** Minimal vault stub that stores entries in memory. */
|
|
11
11
|
function makeVaultStub() {
|
|
12
|
-
const entries = new Map<
|
|
12
|
+
const entries = new Map<
|
|
13
|
+
string,
|
|
14
|
+
{
|
|
15
|
+
id: string;
|
|
16
|
+
type: string;
|
|
17
|
+
domain?: string;
|
|
18
|
+
title: string;
|
|
19
|
+
description: string;
|
|
20
|
+
context?: string;
|
|
21
|
+
tags?: string[];
|
|
22
|
+
severity?: string;
|
|
23
|
+
}
|
|
24
|
+
>();
|
|
13
25
|
return {
|
|
14
26
|
list: (opts: { type?: string; domain?: string; limit?: number }) => {
|
|
15
27
|
let arr = [...entries.values()];
|
|
@@ -18,7 +30,16 @@ function makeVaultStub() {
|
|
|
18
30
|
return arr.slice(0, opts.limit ?? 50);
|
|
19
31
|
},
|
|
20
32
|
get: (id: string) => entries.get(id) ?? null,
|
|
21
|
-
add: (entry: {
|
|
33
|
+
add: (entry: {
|
|
34
|
+
id: string;
|
|
35
|
+
type: string;
|
|
36
|
+
title: string;
|
|
37
|
+
description: string;
|
|
38
|
+
domain?: string;
|
|
39
|
+
context?: string;
|
|
40
|
+
tags?: string[];
|
|
41
|
+
severity?: string;
|
|
42
|
+
}) => {
|
|
22
43
|
entries.set(entry.id, entry);
|
|
23
44
|
},
|
|
24
45
|
_entries: entries,
|
|
@@ -77,7 +98,9 @@ describe('playbook-ops', () => {
|
|
|
77
98
|
domain: 'testing',
|
|
78
99
|
title: 'TDD Workflow',
|
|
79
100
|
description: 'Test-driven development playbook',
|
|
80
|
-
context: JSON.stringify({
|
|
101
|
+
context: JSON.stringify({
|
|
102
|
+
steps: [{ order: 1, title: 'Write test', description: 'Write failing test' }],
|
|
103
|
+
}),
|
|
81
104
|
tags: ['tdd'],
|
|
82
105
|
});
|
|
83
106
|
|
|
@@ -10,17 +10,28 @@ import type { OpDefinition } from '../facades/types.js';
|
|
|
10
10
|
|
|
11
11
|
/** Minimal plugin registry stub. */
|
|
12
12
|
function makePluginRegistryStub() {
|
|
13
|
-
const plugins = new Map<
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
const plugins = new Map<
|
|
14
|
+
string,
|
|
15
|
+
{
|
|
16
|
+
id: string;
|
|
17
|
+
manifest: {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
version: string;
|
|
21
|
+
domain: string;
|
|
22
|
+
description: string;
|
|
23
|
+
dependencies: string[];
|
|
24
|
+
intelligence: unknown[];
|
|
25
|
+
};
|
|
26
|
+
status: string;
|
|
27
|
+
provenance: string;
|
|
28
|
+
directory: string;
|
|
29
|
+
error?: string;
|
|
30
|
+
facades: Array<{ name: string; description: string; ops: OpDefinition[] }>;
|
|
31
|
+
registeredAt: number;
|
|
32
|
+
activatedAt?: number;
|
|
33
|
+
}
|
|
34
|
+
>();
|
|
24
35
|
|
|
25
36
|
return {
|
|
26
37
|
get: (id: string) => plugins.get(id) ?? null,
|
|
@@ -43,10 +54,24 @@ function makePluginRegistryStub() {
|
|
|
43
54
|
plugin.status = 'registered';
|
|
44
55
|
return true;
|
|
45
56
|
}),
|
|
46
|
-
_seed: (
|
|
57
|
+
_seed: (
|
|
58
|
+
id: string,
|
|
59
|
+
overrides?: Partial<{
|
|
60
|
+
status: string;
|
|
61
|
+
facades: Array<{ name: string; description: string; ops: OpDefinition[] }>;
|
|
62
|
+
}>,
|
|
63
|
+
) => {
|
|
47
64
|
plugins.set(id, {
|
|
48
65
|
id,
|
|
49
|
-
manifest: {
|
|
66
|
+
manifest: {
|
|
67
|
+
id,
|
|
68
|
+
name: `Plugin ${id}`,
|
|
69
|
+
version: '1.0.0',
|
|
70
|
+
domain: 'test',
|
|
71
|
+
description: 'Test plugin',
|
|
72
|
+
dependencies: [],
|
|
73
|
+
intelligence: [],
|
|
74
|
+
},
|
|
50
75
|
status: overrides?.status ?? 'registered',
|
|
51
76
|
provenance: 'local',
|
|
52
77
|
directory: `/plugins/${id}`,
|
|
@@ -63,10 +88,7 @@ describe('plugin-ops', () => {
|
|
|
63
88
|
const config = { agentId: 'test-agent' };
|
|
64
89
|
const opSink = opts?.opSink;
|
|
65
90
|
const ops = captureOps(
|
|
66
|
-
createPluginOps(
|
|
67
|
-
{ pluginRegistry, config } as unknown as AgentRuntime,
|
|
68
|
-
opSink,
|
|
69
|
-
),
|
|
91
|
+
createPluginOps({ pluginRegistry, config } as unknown as AgentRuntime, opSink),
|
|
70
92
|
);
|
|
71
93
|
return { pluginRegistry, ops, opSink };
|
|
72
94
|
}
|
|
@@ -83,11 +105,24 @@ describe('plugin-ops', () => {
|
|
|
83
105
|
|
|
84
106
|
it('lists registered plugins with status', async () => {
|
|
85
107
|
const { ops, pluginRegistry } = setup();
|
|
86
|
-
pluginRegistry._seed('plug-a', {
|
|
108
|
+
pluginRegistry._seed('plug-a', {
|
|
109
|
+
status: 'active',
|
|
110
|
+
facades: [
|
|
111
|
+
{
|
|
112
|
+
name: 'f1',
|
|
113
|
+
description: 'F1',
|
|
114
|
+
ops: [{ name: 'op1', handler: async () => ({}), auth: 'read', description: '' }],
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
});
|
|
87
118
|
pluginRegistry._seed('plug-b', { status: 'registered' });
|
|
88
119
|
|
|
89
120
|
const res = await executeOp(ops, 'plugin_list');
|
|
90
|
-
const data = res.data as {
|
|
121
|
+
const data = res.data as {
|
|
122
|
+
count: number;
|
|
123
|
+
active: number;
|
|
124
|
+
plugins: Array<{ id: string; status: string; facades: number; ops: number }>;
|
|
125
|
+
};
|
|
91
126
|
expect(data.count).toBe(2);
|
|
92
127
|
expect(data.active).toBe(1);
|
|
93
128
|
expect(data.plugins[0].facades).toBe(1);
|
|
@@ -108,7 +143,13 @@ describe('plugin-ops', () => {
|
|
|
108
143
|
pluginRegistry._seed('my-plug');
|
|
109
144
|
|
|
110
145
|
const res = await executeOp(ops, 'plugin_status', { pluginId: 'my-plug' });
|
|
111
|
-
const data = res.data as {
|
|
146
|
+
const data = res.data as {
|
|
147
|
+
id: string;
|
|
148
|
+
name: string;
|
|
149
|
+
version: string;
|
|
150
|
+
status: string;
|
|
151
|
+
directory: string;
|
|
152
|
+
};
|
|
112
153
|
expect(data.id).toBe('my-plug');
|
|
113
154
|
expect(data.version).toBe('1.0.0');
|
|
114
155
|
expect(data.directory).toBe('/plugins/my-plug');
|
|
@@ -140,7 +181,10 @@ describe('plugin-ops', () => {
|
|
|
140
181
|
pluginRegistry._seed('p2', { status: 'registered', facades: [] });
|
|
141
182
|
|
|
142
183
|
const res = await executeOp(ops, 'plugin_activate', {});
|
|
143
|
-
const data = res.data as {
|
|
184
|
+
const data = res.data as {
|
|
185
|
+
activated: number;
|
|
186
|
+
results: Array<{ id: string; status: string }>;
|
|
187
|
+
};
|
|
144
188
|
expect(data.activated).toBe(2);
|
|
145
189
|
expect(data.results).toHaveLength(2);
|
|
146
190
|
});
|
|
@@ -148,8 +192,15 @@ describe('plugin-ops', () => {
|
|
|
148
192
|
it('injects plugin ops into opSink on activation', async () => {
|
|
149
193
|
const opSink: OpDefinition[] = [];
|
|
150
194
|
const { ops, pluginRegistry } = setup({ opSink });
|
|
151
|
-
const testOp: OpDefinition = {
|
|
152
|
-
|
|
195
|
+
const testOp: OpDefinition = {
|
|
196
|
+
name: 'injected_op',
|
|
197
|
+
handler: async () => 'hi',
|
|
198
|
+
auth: 'read',
|
|
199
|
+
description: 'test',
|
|
200
|
+
};
|
|
201
|
+
pluginRegistry._seed('plug-inject', {
|
|
202
|
+
facades: [{ name: 'test-facade', description: 'TF', ops: [testOp] }],
|
|
203
|
+
});
|
|
153
204
|
|
|
154
205
|
await executeOp(ops, 'plugin_activate', { pluginId: 'plug-inject' });
|
|
155
206
|
expect(opSink.some((o) => o.name === 'injected_op')).toBe(true);
|
|
@@ -177,8 +228,15 @@ describe('plugin-ops', () => {
|
|
|
177
228
|
it('removes injected ops from opSink on deactivation', async () => {
|
|
178
229
|
const opSink: OpDefinition[] = [];
|
|
179
230
|
const { ops, pluginRegistry } = setup({ opSink });
|
|
180
|
-
const testOp: OpDefinition = {
|
|
181
|
-
|
|
231
|
+
const testOp: OpDefinition = {
|
|
232
|
+
name: 'to_remove',
|
|
233
|
+
handler: async () => 'hi',
|
|
234
|
+
auth: 'read',
|
|
235
|
+
description: 'test',
|
|
236
|
+
};
|
|
237
|
+
pluginRegistry._seed('plug-rm', {
|
|
238
|
+
facades: [{ name: 'f', description: 'F', ops: [testOp] }],
|
|
239
|
+
});
|
|
182
240
|
|
|
183
241
|
await executeOp(ops, 'plugin_activate', { pluginId: 'plug-rm' });
|
|
184
242
|
expect(opSink.some((o) => o.name === 'to_remove')).toBe(true);
|