agentic-orchestrator 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +6 -1
- package/README.md +81 -54
- package/agentic/orchestrator/defaults/policy.defaults.yaml +212 -0
- package/agentic/orchestrator/schemas/adapters.schema.json +17 -4
- package/agentic/orchestrator/schemas/agents.schema.json +58 -13
- package/agentic/orchestrator/schemas/gates.schema.json +88 -17
- package/agentic/orchestrator/schemas/index.schema.json +172 -37
- package/agentic/orchestrator/schemas/multi-project.schema.json +85 -17
- package/agentic/orchestrator/schemas/plan.schema.json +135 -30
- package/agentic/orchestrator/schemas/policy.schema.json +198 -69
- package/agentic/orchestrator/schemas/policy.user.schema.json +165 -0
- package/agentic/orchestrator/schemas/qa_test_index.schema.json +71 -14
- package/agentic/orchestrator/schemas/state.schema.json +196 -39
- package/apps/control-plane/scripts/validate-architecture-rules.mjs +5 -3
- package/apps/control-plane/scripts/validate-docker-mcp-contract.mjs +0 -3
- package/apps/control-plane/scripts/validate-mcp-contracts.ts +2 -6
- package/apps/control-plane/src/application/services/policy-loader-service.ts +115 -0
- package/apps/control-plane/src/cli/aop.ts +35 -1
- package/apps/control-plane/src/cli/cli-argument-parser.ts +4 -0
- package/apps/control-plane/src/cli/help-command-handler.ts +2 -1
- package/apps/control-plane/src/cli/init-command-handler.ts +136 -27
- package/apps/control-plane/src/cli/retry-command-handler.ts +3 -6
- package/apps/control-plane/src/cli/types.ts +1 -0
- package/apps/control-plane/src/core/git.ts +1 -3
- package/apps/control-plane/src/core/kernel.ts +3 -6
- package/apps/control-plane/src/core/schemas.ts +36 -1
- package/apps/control-plane/src/interfaces/cli/bootstrap.ts +1 -1
- package/apps/control-plane/src/mcp/tool-registry-loader.ts +37 -1
- package/apps/control-plane/src/supervisor/qa-wave-executor.ts +1 -1
- package/apps/control-plane/test/aop.spec.ts +37 -0
- package/apps/control-plane/test/batch-operations.spec.ts +5 -3
- package/apps/control-plane/test/bootstrap-attach.spec.ts +28 -18
- package/apps/control-plane/test/bootstrap-edge-cases.spec.ts +25 -15
- package/apps/control-plane/test/bootstrap.spec.ts +30 -22
- package/apps/control-plane/test/cli.unit.spec.ts +55 -10
- package/apps/control-plane/test/core-utils.spec.ts +12 -3
- package/apps/control-plane/test/feature-deletion-service.spec.ts +2 -1
- package/apps/control-plane/test/feature-lifecycle.spec.ts +1 -1
- package/apps/control-plane/test/helpers.ts +22 -2
- package/apps/control-plane/test/init-wizard.spec.ts +160 -7
- package/apps/control-plane/test/issue-tracker.spec.ts +3 -3
- package/apps/control-plane/test/kernel.spec.ts +62 -0
- package/apps/control-plane/test/lock-service.spec.ts +4 -4
- package/apps/control-plane/test/policy-loader-service.spec.ts +346 -0
- package/apps/control-plane/test/reactions.spec.ts +8 -6
- package/apps/control-plane/test/resume-command.spec.ts +31 -15
- package/apps/control-plane/test/supervisor.unit.spec.ts +2 -2
- package/apps/control-plane/test/tool-registry-loader.spec.ts +12 -0
- package/apps/control-plane/vitest.config.ts +1 -1
- package/dist/apps/control-plane/application/services/policy-loader-service.d.ts +24 -0
- package/dist/apps/control-plane/application/services/policy-loader-service.js +90 -0
- package/dist/apps/control-plane/application/services/policy-loader-service.js.map +1 -0
- package/dist/apps/control-plane/application/tools/tool-metadata.js +1 -0
- package/dist/apps/control-plane/application/tools/tool-metadata.js.map +1 -1
- package/dist/apps/control-plane/cli/aop.js +33 -1
- package/dist/apps/control-plane/cli/aop.js.map +1 -1
- package/dist/apps/control-plane/cli/cli-argument-parser.js +4 -0
- package/dist/apps/control-plane/cli/cli-argument-parser.js.map +1 -1
- package/dist/apps/control-plane/cli/dashboard-command-handler.js +11 -5
- package/dist/apps/control-plane/cli/dashboard-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/help-command-handler.js +5 -4
- package/dist/apps/control-plane/cli/help-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/init-command-handler.d.ts +1 -0
- package/dist/apps/control-plane/cli/init-command-handler.js +110 -26
- package/dist/apps/control-plane/cli/init-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/retry-command-handler.js +3 -6
- package/dist/apps/control-plane/cli/retry-command-handler.js.map +1 -1
- package/dist/apps/control-plane/cli/types.d.ts +1 -0
- package/dist/apps/control-plane/core/git.js +1 -3
- package/dist/apps/control-plane/core/git.js.map +1 -1
- package/dist/apps/control-plane/core/kernel.js +3 -5
- package/dist/apps/control-plane/core/kernel.js.map +1 -1
- package/dist/apps/control-plane/core/schemas.d.ts +2 -0
- package/dist/apps/control-plane/core/schemas.js +31 -1
- package/dist/apps/control-plane/core/schemas.js.map +1 -1
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js +1 -1
- package/dist/apps/control-plane/interfaces/cli/bootstrap.js.map +1 -1
- package/dist/apps/control-plane/mcp/tool-registry-loader.d.ts +2 -0
- package/dist/apps/control-plane/mcp/tool-registry-loader.js +31 -1
- package/dist/apps/control-plane/mcp/tool-registry-loader.js.map +1 -1
- package/dist/apps/control-plane/supervisor/build-wave-executor.js +1 -1
- package/dist/apps/control-plane/supervisor/build-wave-executor.js.map +1 -1
- package/dist/apps/control-plane/supervisor/qa-wave-executor.js +1 -1
- package/dist/apps/control-plane/supervisor/qa-wave-executor.js.map +1 -1
- package/package.json +18 -17
- package/packages/web-dashboard/package.json +1 -1
- package/packages/web-dashboard/src/app/api/actions/route.ts +2 -2
- package/packages/web-dashboard/src/app/api/events/route.ts +1 -1
- package/packages/web-dashboard/src/app/api/features/[id]/checkout/route.ts +1 -1
- package/packages/web-dashboard/src/app/api/features/[id]/diff/route.ts +1 -1
- package/packages/web-dashboard/src/app/api/features/[id]/evidence/[artifact]/route.ts +1 -1
- package/packages/web-dashboard/src/app/api/features/[id]/review/route.ts +2 -2
- package/packages/web-dashboard/src/app/api/features/[id]/route.ts +1 -1
- package/packages/web-dashboard/src/app/api/projects/route.ts +2 -2
- package/packages/web-dashboard/src/app/api/status/route.ts +1 -1
- package/packages/web-dashboard/src/app/page.tsx +1 -1
- package/packages/web-dashboard/src/lib/aop-client.ts +1 -1
- package/packages/web-dashboard/src/lib/orchestrator-tools.ts +1 -1
- package/packages/web-dashboard/tsconfig.json +1 -0
- package/spec-files/completed/agentic_orchestrator_init_policy_ux_simplification_spec.md +481 -0
- package/spec-files/outstanding/agentic_orchestrator_artifact_database_publishing_spec.md +500 -0
- package/spec-files/outstanding/agentic_orchestrator_observability_integrity_diagnostics_spec.md +500 -195
- package/spec-files/outstanding/agentic_orchestrator_performance_improvements_spec.md +471 -162
- package/spec-files/outstanding/agentic_orchestrator_planning_review_quality_spec.md +532 -268
- package/spec-files/outstanding/agentic_orchestrator_productization_commercial_spec.md +645 -0
- package/spec-files/progress.md +99 -2
- package/tsconfig.base.json +4 -0
- /package/spec-files/{outstanding → completed}/agentic_orchestrator_validator_hardening_spec.md +0 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
5
|
+
|
|
6
|
+
import { mergePolicy, loadComposedPolicy } from '../src/application/services/policy-loader-service.js';
|
|
7
|
+
import { SchemaRegistry } from '../src/core/schemas.js';
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Unit tests for mergePolicy
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
|
|
13
|
+
describe('mergePolicy', () => {
|
|
14
|
+
it('GIVEN_scalar_user_value_WHEN_merged_THEN_replaces_default_scalar', () => {
|
|
15
|
+
const defaults = { version: 1, timeout: 600 };
|
|
16
|
+
const user = { timeout: 300 };
|
|
17
|
+
const result = mergePolicy(defaults, user);
|
|
18
|
+
expect(result).toEqual({ version: 1, timeout: 300 });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('GIVEN_object_user_value_WHEN_merged_THEN_recursive_merge_preserves_defaults', () => {
|
|
22
|
+
const defaults = { worktree: { base_branch: 'main', normalize: true } };
|
|
23
|
+
const user = { worktree: { base_branch: 'develop' } };
|
|
24
|
+
const result = mergePolicy(defaults, user);
|
|
25
|
+
expect(result).toEqual({ worktree: { base_branch: 'develop', normalize: true } });
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('GIVEN_array_override_WHEN_composed_THEN_array_replaces_default_array', () => {
|
|
29
|
+
const defaults = { required_modes: ['fast', 'full'] };
|
|
30
|
+
const user = { required_modes: ['fast'] };
|
|
31
|
+
const result = mergePolicy(defaults, user) as Record<string, unknown>;
|
|
32
|
+
expect(result['required_modes']).toEqual(['fast']);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('GIVEN_absent_user_keys_WHEN_merged_THEN_defaults_inherited', () => {
|
|
36
|
+
const defaults = { version: 1, locks: { lease_ttl_seconds: 300 } };
|
|
37
|
+
const user = { version: 1 };
|
|
38
|
+
const result = mergePolicy(defaults, user) as Record<string, unknown>;
|
|
39
|
+
expect(result['locks']).toEqual({ lease_ttl_seconds: 300 });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('GIVEN_undefined_user_field_WHEN_merged_THEN_field_is_ignored', () => {
|
|
43
|
+
const defaults = { version: 1, port: 3000 };
|
|
44
|
+
const user = { version: 1, port: undefined };
|
|
45
|
+
const result = mergePolicy(defaults, user) as Record<string, unknown>;
|
|
46
|
+
// undefined user fields inherit the default
|
|
47
|
+
expect(result['port']).toBe(3000);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('GIVEN_empty_user_object_WHEN_merged_THEN_returns_defaults_clone', () => {
|
|
51
|
+
const defaults = { version: 1, commit_policy: { allow_commit: false } };
|
|
52
|
+
const user = {};
|
|
53
|
+
const result = mergePolicy(defaults, user);
|
|
54
|
+
expect(result).toEqual(defaults);
|
|
55
|
+
// must be a deep clone, not same reference
|
|
56
|
+
expect(result).not.toBe(defaults);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('GIVEN_merge_determinism_WHEN_key_order_differs_THEN_same_output', () => {
|
|
60
|
+
const defaults = { a: 1, b: 2, c: { x: 10, y: 20 } };
|
|
61
|
+
const user1 = { b: 99, c: { y: 99 } };
|
|
62
|
+
const user2 = { c: { y: 99 }, b: 99 };
|
|
63
|
+
const result1 = mergePolicy(defaults, user1);
|
|
64
|
+
const result2 = mergePolicy(defaults, user2);
|
|
65
|
+
expect(result1).toEqual(result2);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('GIVEN_deeply_nested_user_value_WHEN_merged_THEN_only_overridden_leaf_changes', () => {
|
|
69
|
+
const defaults = {
|
|
70
|
+
execution: {
|
|
71
|
+
retry_policy: { transient_max_retries: 1, transient_error_codes: [124] }
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const user = {
|
|
75
|
+
execution: {
|
|
76
|
+
retry_policy: { transient_max_retries: 3 }
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
const result = mergePolicy(defaults, user) as {
|
|
80
|
+
execution: { retry_policy: { transient_max_retries: number; transient_error_codes: number[] } };
|
|
81
|
+
};
|
|
82
|
+
expect(result.execution.retry_policy.transient_max_retries).toBe(3);
|
|
83
|
+
expect(result.execution.retry_policy.transient_error_codes).toEqual([124]);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('GIVEN_array_in_protected_areas_WHEN_user_overrides_THEN_array_is_replaced_wholesale', () => {
|
|
87
|
+
const defaults = { protected_areas: ['agentic/orchestrator/policy.yaml'] };
|
|
88
|
+
const user = { protected_areas: ['agentic/orchestrator/policy.yaml', 'libs/core'] };
|
|
89
|
+
const result = mergePolicy(defaults, user) as Record<string, unknown>;
|
|
90
|
+
expect(result['protected_areas']).toEqual(['agentic/orchestrator/policy.yaml', 'libs/core']);
|
|
91
|
+
expect((result['protected_areas'] as unknown[]).length).toBe(2);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// Integration tests for loadComposedPolicy
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
describe('loadComposedPolicy', () => {
|
|
100
|
+
let tmpDir: string;
|
|
101
|
+
let schemaRegistry: SchemaRegistry;
|
|
102
|
+
|
|
103
|
+
beforeEach(async () => {
|
|
104
|
+
tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'aop-policy-loader-'));
|
|
105
|
+
// Use the real schema registry pointing at the AOP repo schemas (bundled)
|
|
106
|
+
schemaRegistry = new SchemaRegistry(tmpDir);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
afterEach(async () => {
|
|
110
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
111
|
+
vi.restoreAllMocks();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
async function writePolicyFile(content: string): Promise<string> {
|
|
115
|
+
const policyPath = path.join(tmpDir, 'policy.yaml');
|
|
116
|
+
await fs.writeFile(policyPath, content, 'utf8');
|
|
117
|
+
return policyPath;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
it('GIVEN_defaults_and_lean_user_policy_WHEN_composed_THEN_merged_policy_is_valid', async () => {
|
|
121
|
+
const leanPolicy = `version: 1
|
|
122
|
+
worktree:
|
|
123
|
+
base_branch: develop
|
|
124
|
+
supervisor:
|
|
125
|
+
max_parallel_gate_runs: 4
|
|
126
|
+
dashboard:
|
|
127
|
+
enabled: true
|
|
128
|
+
port: 4000
|
|
129
|
+
merge_policy:
|
|
130
|
+
require_user_approval: true
|
|
131
|
+
notifications:
|
|
132
|
+
enabled: false
|
|
133
|
+
channels:
|
|
134
|
+
desktop:
|
|
135
|
+
enabled: false
|
|
136
|
+
slack:
|
|
137
|
+
enabled: false
|
|
138
|
+
webhook: ""
|
|
139
|
+
channel: "#aop-alerts"
|
|
140
|
+
webhook:
|
|
141
|
+
enabled: false
|
|
142
|
+
url: ""
|
|
143
|
+
`;
|
|
144
|
+
const policyPath = await writePolicyFile(leanPolicy);
|
|
145
|
+
const result = await loadComposedPolicy(tmpDir, policyPath, schemaRegistry);
|
|
146
|
+
|
|
147
|
+
// User values are preserved in merged result
|
|
148
|
+
expect((result.mergedPolicy['worktree'] as Record<string, unknown>)['base_branch']).toBe('develop');
|
|
149
|
+
expect((result.mergedPolicy['supervisor'] as Record<string, unknown>)['max_parallel_gate_runs']).toBe(4);
|
|
150
|
+
|
|
151
|
+
// Defaults fill in required fields not in lean policy
|
|
152
|
+
expect(result.mergedPolicy['implementation']).toBeDefined();
|
|
153
|
+
expect((result.mergedPolicy['implementation'] as Record<string, unknown>)['workspace']).toBe('nx');
|
|
154
|
+
expect(result.mergedPolicy['rbac']).toBeDefined();
|
|
155
|
+
expect(result.mergedPolicy['locks']).toBeDefined();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('GIVEN_full_user_policy_WHEN_composed_THEN_user_values_override_defaults', async () => {
|
|
159
|
+
const fullPolicy = `version: 1
|
|
160
|
+
commit_policy:
|
|
161
|
+
allow_commit: true
|
|
162
|
+
allow_merge: true
|
|
163
|
+
patch_policy:
|
|
164
|
+
enforce_plan: false
|
|
165
|
+
enforce_allowed_areas: false
|
|
166
|
+
locks:
|
|
167
|
+
resources:
|
|
168
|
+
- openapi
|
|
169
|
+
contract_to_resource:
|
|
170
|
+
openapi: openapi
|
|
171
|
+
events: events
|
|
172
|
+
db: db_migrations
|
|
173
|
+
lease_ttl_seconds: 120
|
|
174
|
+
acquire_behavior: wait
|
|
175
|
+
default_wait_timeout_seconds: 120
|
|
176
|
+
acquire_backoff:
|
|
177
|
+
initial_ms: 100
|
|
178
|
+
max_ms: 2000
|
|
179
|
+
multiplier: 2
|
|
180
|
+
jitter_ms: 50
|
|
181
|
+
protected_areas:
|
|
182
|
+
- agentic/orchestrator/policy.yaml
|
|
183
|
+
required_modes:
|
|
184
|
+
- fast
|
|
185
|
+
required_merge_mode: merge
|
|
186
|
+
collision_policy: reject
|
|
187
|
+
config_precedence:
|
|
188
|
+
policy_hard_constraints:
|
|
189
|
+
- execution.default_step_timeout_seconds
|
|
190
|
+
gates_profile_defaults:
|
|
191
|
+
- profiles
|
|
192
|
+
plan_verification_overrides:
|
|
193
|
+
- verification_overrides
|
|
194
|
+
path_rules:
|
|
195
|
+
matching: repo_prefix
|
|
196
|
+
normalize_paths: true
|
|
197
|
+
allow_symlink_traversal: false
|
|
198
|
+
execution:
|
|
199
|
+
default_step_timeout_seconds: 300
|
|
200
|
+
retry_policy:
|
|
201
|
+
transient_max_retries: 2
|
|
202
|
+
transient_error_codes:
|
|
203
|
+
- 124
|
|
204
|
+
non_retryable_error_codes:
|
|
205
|
+
- 2
|
|
206
|
+
env_allowlist:
|
|
207
|
+
- PATH
|
|
208
|
+
implementation:
|
|
209
|
+
workspace: nx
|
|
210
|
+
testing:
|
|
211
|
+
framework: vitest
|
|
212
|
+
coverage:
|
|
213
|
+
minimums:
|
|
214
|
+
line: 0.8
|
|
215
|
+
branch: 0.8
|
|
216
|
+
targets:
|
|
217
|
+
line: 1.0
|
|
218
|
+
branch: 1.0
|
|
219
|
+
merge_policy:
|
|
220
|
+
require_user_approval: false
|
|
221
|
+
allowed_strategies:
|
|
222
|
+
- squash
|
|
223
|
+
worktree:
|
|
224
|
+
base_branch: main
|
|
225
|
+
rbac:
|
|
226
|
+
orchestrator:
|
|
227
|
+
- feature.get_context
|
|
228
|
+
system:
|
|
229
|
+
- "*"
|
|
230
|
+
`;
|
|
231
|
+
const policyPath = await writePolicyFile(fullPolicy);
|
|
232
|
+
const result = await loadComposedPolicy(tmpDir, policyPath, schemaRegistry);
|
|
233
|
+
|
|
234
|
+
// User values dominate
|
|
235
|
+
expect((result.mergedPolicy['commit_policy'] as Record<string, unknown>)['allow_commit']).toBe(true);
|
|
236
|
+
expect((result.mergedPolicy['execution'] as Record<string, unknown>)['default_step_timeout_seconds']).toBe(300);
|
|
237
|
+
expect((result.mergedPolicy['merge_policy'] as Record<string, unknown>)['require_user_approval']).toBe(false);
|
|
238
|
+
const strategies = (result.mergedPolicy['merge_policy'] as Record<string, unknown>)['allowed_strategies'];
|
|
239
|
+
expect(strategies).toEqual(['squash']);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('GIVEN_array_override_for_required_modes_WHEN_composed_THEN_array_replaces_default_array', async () => {
|
|
243
|
+
const policy = `version: 1
|
|
244
|
+
required_modes:
|
|
245
|
+
- fast
|
|
246
|
+
`;
|
|
247
|
+
const policyPath = await writePolicyFile(policy);
|
|
248
|
+
const result = await loadComposedPolicy(tmpDir, policyPath, schemaRegistry);
|
|
249
|
+
|
|
250
|
+
// User's array replaces the defaults array wholesale
|
|
251
|
+
expect(result.mergedPolicy['required_modes']).toEqual(['fast']);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('GIVEN_empty_user_policy_WHEN_loaded_THEN_merged_policy_is_defaults_only', async () => {
|
|
255
|
+
const policyPath = await writePolicyFile('');
|
|
256
|
+
const result = await loadComposedPolicy(tmpDir, policyPath, schemaRegistry);
|
|
257
|
+
|
|
258
|
+
// All required fields come from defaults
|
|
259
|
+
expect(result.userPolicy).toEqual({});
|
|
260
|
+
expect(result.mergedPolicy['version']).toBe(1);
|
|
261
|
+
expect(result.mergedPolicy['commit_policy']).toBeDefined();
|
|
262
|
+
expect(result.mergedPolicy['implementation']).toBeDefined();
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('GIVEN_invalid_user_policy_WHEN_loaded_THEN_validation_error_is_actionable', async () => {
|
|
266
|
+
// Provide a policy that overrides a required field with wrong type
|
|
267
|
+
const badPolicy = `version: 1
|
|
268
|
+
commit_policy:
|
|
269
|
+
allow_commit: "yes"
|
|
270
|
+
allow_merge: false
|
|
271
|
+
patch_policy:
|
|
272
|
+
enforce_plan: true
|
|
273
|
+
enforce_allowed_areas: true
|
|
274
|
+
locks:
|
|
275
|
+
resources: []
|
|
276
|
+
contract_to_resource:
|
|
277
|
+
openapi: openapi
|
|
278
|
+
events: events
|
|
279
|
+
db: db_migrations
|
|
280
|
+
lease_ttl_seconds: 300
|
|
281
|
+
acquire_behavior: wait
|
|
282
|
+
default_wait_timeout_seconds: 300
|
|
283
|
+
acquire_backoff:
|
|
284
|
+
initial_ms: 200
|
|
285
|
+
max_ms: 5000
|
|
286
|
+
multiplier: 2
|
|
287
|
+
jitter_ms: 150
|
|
288
|
+
protected_areas:
|
|
289
|
+
- agentic/orchestrator/policy.yaml
|
|
290
|
+
required_modes:
|
|
291
|
+
- fast
|
|
292
|
+
required_merge_mode: merge
|
|
293
|
+
collision_policy: reject
|
|
294
|
+
config_precedence: {}
|
|
295
|
+
path_rules:
|
|
296
|
+
matching: repo_prefix
|
|
297
|
+
normalize_paths: true
|
|
298
|
+
allow_symlink_traversal: false
|
|
299
|
+
execution:
|
|
300
|
+
default_step_timeout_seconds: 600
|
|
301
|
+
retry_policy:
|
|
302
|
+
transient_max_retries: 1
|
|
303
|
+
transient_error_codes: []
|
|
304
|
+
non_retryable_error_codes: []
|
|
305
|
+
env_allowlist: []
|
|
306
|
+
implementation:
|
|
307
|
+
workspace: nx
|
|
308
|
+
testing:
|
|
309
|
+
framework: vitest
|
|
310
|
+
coverage:
|
|
311
|
+
minimums:
|
|
312
|
+
line: 0.7
|
|
313
|
+
branch: 0.7
|
|
314
|
+
targets:
|
|
315
|
+
line: 1.0
|
|
316
|
+
branch: 1.0
|
|
317
|
+
merge_policy:
|
|
318
|
+
require_user_approval: true
|
|
319
|
+
allowed_strategies:
|
|
320
|
+
- merge_commit
|
|
321
|
+
worktree:
|
|
322
|
+
base_branch: main
|
|
323
|
+
rbac:
|
|
324
|
+
system:
|
|
325
|
+
- "*"
|
|
326
|
+
`;
|
|
327
|
+
const policyPath = await writePolicyFile(badPolicy);
|
|
328
|
+
await expect(loadComposedPolicy(tmpDir, policyPath, schemaRegistry)).rejects.toThrow(
|
|
329
|
+
/invalid_policy_yaml/
|
|
330
|
+
);
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it('GIVEN_missing_policy_file_WHEN_loaded_THEN_throws_read_error', async () => {
|
|
334
|
+
const missingPath = path.join(tmpDir, 'missing.yaml');
|
|
335
|
+
await expect(loadComposedPolicy(tmpDir, missingPath, schemaRegistry)).rejects.toThrow();
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
it('GIVEN_defaults_not_found_WHEN_loaded_THEN_throws_descriptive_error', async () => {
|
|
339
|
+
const policyPath = await writePolicyFile('version: 1\n');
|
|
340
|
+
// Temporarily override the bundled defaults path via mocking the fs.readFile call
|
|
341
|
+
// to simulate defaults artifact missing by mocking module internals
|
|
342
|
+
vi.spyOn(fs, 'readFile').mockRejectedValueOnce(new Error('ENOENT: no such file'));
|
|
343
|
+
|
|
344
|
+
await expect(loadComposedPolicy(tmpDir, policyPath, schemaRegistry)).rejects.toThrow();
|
|
345
|
+
});
|
|
346
|
+
});
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from 'vitest';
|
|
2
2
|
import { ReactionsService } from '../src/application/services/reactions-service.js';
|
|
3
3
|
import type { GateRepairContext, ReactionsPolicy } from '../src/application/services/reactions-service.js';
|
|
4
|
+
import type { ToolCaller } from '../src/core/tool-caller.js';
|
|
4
5
|
import { TOOLS } from '../src/core/constants.js';
|
|
5
6
|
|
|
6
|
-
function makeToolCaller(statePatchFn?: () => Promise<Record<string, unknown>>) {
|
|
7
|
+
function makeToolCaller(statePatchFn?: () => Promise<Record<string, unknown>>): ToolCaller {
|
|
7
8
|
return {
|
|
8
9
|
callTool: vi.fn(async (_role: string, toolName: string, _args?: Record<string, unknown>) => {
|
|
9
10
|
if (toolName === TOOLS.FEATURE_STATE_GET) {
|
|
@@ -16,7 +17,7 @@ function makeToolCaller(statePatchFn?: () => Promise<Record<string, unknown>>) {
|
|
|
16
17
|
return { ok: true, data: { updated: true } };
|
|
17
18
|
}
|
|
18
19
|
return { ok: true, data: {} };
|
|
19
|
-
})
|
|
20
|
+
}) as unknown as ToolCaller['callTool']
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -126,7 +127,7 @@ describe('ReactionsService', () => {
|
|
|
126
127
|
await service.recordRetry('feature_d', 1);
|
|
127
128
|
|
|
128
129
|
expect(patchCallCount).toBe(1);
|
|
129
|
-
const patchCall = toolCaller.callTool.mock.calls.find(([, tool]) => tool === TOOLS.FEATURE_STATE_PATCH);
|
|
130
|
+
const patchCall = vi.mocked(toolCaller.callTool).mock.calls.find(([, tool]) => tool === TOOLS.FEATURE_STATE_PATCH);
|
|
130
131
|
expect(patchCall).toBeDefined();
|
|
131
132
|
const patchArgs = patchCall?.[2] ?? {};
|
|
132
133
|
const patch = (patchArgs['patch'] ?? {}) as Record<string, unknown>;
|
|
@@ -144,7 +145,7 @@ describe('ReactionsService', () => {
|
|
|
144
145
|
// Simulate force reset by calling recordRetry with 0
|
|
145
146
|
await service.recordRetry('feature_e', 0);
|
|
146
147
|
|
|
147
|
-
const patchCall = toolCaller.callTool.mock.calls.find(([, tool]) => tool === TOOLS.FEATURE_STATE_PATCH);
|
|
148
|
+
const patchCall = vi.mocked(toolCaller.callTool).mock.calls.find(([, tool]) => tool === TOOLS.FEATURE_STATE_PATCH);
|
|
148
149
|
expect(patchCall).toBeDefined();
|
|
149
150
|
const patchArgs = patchCall?.[2] ?? {};
|
|
150
151
|
const patch = (patchArgs['patch'] ?? {}) as Record<string, unknown>;
|
|
@@ -321,6 +322,7 @@ describe('ReactionsService branch coverage', () => {
|
|
|
321
322
|
policy: makeEnabledPolicy()
|
|
322
323
|
});
|
|
323
324
|
const ctx: GateRepairContext = {
|
|
325
|
+
featureId: 'feature_history_none',
|
|
324
326
|
gateName: 'unit-tests',
|
|
325
327
|
exitCode: 1,
|
|
326
328
|
logs: 'test output',
|
|
@@ -336,7 +338,7 @@ describe('ReactionsService additional coverage', () => {
|
|
|
336
338
|
it('GIVEN_policy_with_valid_max_retries_number_WHEN_maxRetries_called_THEN_returns_floor_of_value', () => {
|
|
337
339
|
const service = new ReactionsService({
|
|
338
340
|
toolCaller: makeToolCaller(),
|
|
339
|
-
policy: { gate_failed: { enabled: true, action: 'retry_with_agent_repair', max_retries: 3.7, retry_delay_ms: 0 } }
|
|
341
|
+
policy: { gate_failed: { enabled: true, action: 'retry_with_agent_repair', max_retries: 3.7, escalate_after: 2, retry_delay_ms: 0 } }
|
|
340
342
|
});
|
|
341
343
|
expect(service.maxRetries()).toBe(3);
|
|
342
344
|
});
|
|
@@ -344,7 +346,7 @@ describe('ReactionsService additional coverage', () => {
|
|
|
344
346
|
it('GIVEN_non_finite_max_retries_WHEN_maxRetries_called_THEN_returns_default', () => {
|
|
345
347
|
const service = new ReactionsService({
|
|
346
348
|
toolCaller: makeToolCaller(),
|
|
347
|
-
policy: { gate_failed: { enabled: true, action: 'retry_with_agent_repair', max_retries: Infinity, retry_delay_ms: 0 } }
|
|
349
|
+
policy: { gate_failed: { enabled: true, action: 'retry_with_agent_repair', max_retries: Infinity, escalate_after: 2, retry_delay_ms: 0 } }
|
|
348
350
|
});
|
|
349
351
|
expect(service.maxRetries()).toBeGreaterThanOrEqual(0);
|
|
350
352
|
});
|
|
@@ -2,27 +2,43 @@ import { describe, it, expect, vi } from 'vitest';
|
|
|
2
2
|
|
|
3
3
|
vi.mock('../src/providers/providers.js', () => ({
|
|
4
4
|
resolveProviderSelection: vi.fn(() => ({ provider: 'null', model: 'none', provider_config_ref: null })),
|
|
5
|
-
NullWorkerProvider:
|
|
6
|
-
selection:
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
NullWorkerProvider: class NullWorkerProvider {
|
|
6
|
+
selection: unknown;
|
|
7
|
+
|
|
8
|
+
constructor(selection: unknown) {
|
|
9
|
+
this.selection = selection;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async createSession() {
|
|
13
|
+
return { session_id: 'mock-session' };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async reattachSession() {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async closeSession() {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
11
24
|
}));
|
|
12
25
|
|
|
13
26
|
vi.mock('../src/supervisor/runtime.js', () => ({
|
|
14
|
-
SupervisorRuntime:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
SupervisorRuntime: class SupervisorRuntime {
|
|
28
|
+
async start(features: unknown[]) {
|
|
29
|
+
return {
|
|
30
|
+
queue_depth: features.length,
|
|
31
|
+
status: 'running',
|
|
32
|
+
run_metadata: {},
|
|
33
|
+
dashboard: null
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
22
37
|
}));
|
|
23
38
|
|
|
24
39
|
import { ResumeCommandHandler } from '../src/cli/resume-command-handler.js';
|
|
25
40
|
import { STATUS } from '../src/core/constants.js';
|
|
41
|
+
import type { ToolTransport } from '../src/cli/types.js';
|
|
26
42
|
|
|
27
43
|
function makeKernel(overrides: Record<string, unknown> = {}) {
|
|
28
44
|
return {
|
|
@@ -50,7 +66,7 @@ function makeContext(kernel: ReturnType<typeof makeKernel>, toolClientOverride?:
|
|
|
50
66
|
repoRoot: '/tmp/repo',
|
|
51
67
|
env: process.env,
|
|
52
68
|
runId: 'fallback-run-id',
|
|
53
|
-
transport: 'stdio' as
|
|
69
|
+
transport: 'stdio' as unknown as ToolTransport,
|
|
54
70
|
options: {} as any,
|
|
55
71
|
kernel: kernel as any,
|
|
56
72
|
toolClient: (toolClientOverride ?? { call: vi.fn(async () => ({ ok: true, data: {} })) }) as any
|
|
@@ -716,7 +716,7 @@ describe('SupervisorRuntime delegation methods', () => {
|
|
|
716
716
|
orchestrator_epoch: 0,
|
|
717
717
|
feature_sessions: {}
|
|
718
718
|
});
|
|
719
|
-
provider.createSession.mockResolvedValue({ session_id: 'new-orch-session', role: 'orchestrator', feature_id: 'global', system_prompt_loaded: false });
|
|
719
|
+
provider.createSession.mockResolvedValue({ session_id: 'new-orch-session', role: 'orchestrator', feature_id: 'global', system_prompt_loaded: false } as any);
|
|
720
720
|
|
|
721
721
|
await runtime.ensureGlobalOrchestratorSession();
|
|
722
722
|
expect(provider.createSession).toHaveBeenCalled();
|
|
@@ -751,7 +751,7 @@ describe('SupervisorRuntime delegation methods', () => {
|
|
|
751
751
|
} as never);
|
|
752
752
|
|
|
753
753
|
const bundle = await runtime.loadRolePrompts();
|
|
754
|
-
expect(bundle.planner.system).toBe('p');
|
|
754
|
+
expect((bundle.planner as any).system).toBe('p');
|
|
755
755
|
});
|
|
756
756
|
|
|
757
757
|
it('GIVEN_runtime_WHEN_sessionsByFeature_set_THEN_roundtrips_value', () => {
|
|
@@ -146,6 +146,18 @@ describe('ToolRegistryLoader', () => {
|
|
|
146
146
|
expect(errorsSchema).toMatchObject({ type: 'object' });
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
+
it('GIVEN_repo_without_local_registry_WHEN_loading_THEN_falls_back_to_bundled_tools_registry', async () => {
|
|
150
|
+
const repoRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'aop-registry-fallback-'));
|
|
151
|
+
createdRoots.push(repoRoot);
|
|
152
|
+
const loader = new ToolRegistryLoader(repoRoot);
|
|
153
|
+
|
|
154
|
+
const loaded = await loader.load();
|
|
155
|
+
|
|
156
|
+
expect(loaded.catalog.tools.length).toBeGreaterThan(0);
|
|
157
|
+
expect(loader.catalogPath).not.toBe(path.join(repoRoot, 'agentic', 'orchestrator', 'tools', 'catalog.json'));
|
|
158
|
+
await expect(fs.stat(loader.catalogPath)).resolves.toBeDefined();
|
|
159
|
+
});
|
|
160
|
+
|
|
149
161
|
it('GIVEN_catalog_with_duplicate_tool_name_WHEN_loading_THEN_throws_duplicate_name_error', async () => {
|
|
150
162
|
const duplicateName: ToolCatalogEntry = { ...BASE_TOOL, handler_id: 'feature.other_handler' };
|
|
151
163
|
const repoRoot = await makeRegistryRepo({ tools: [BASE_TOOL, duplicateName] });
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { SchemaValidator } from '../../core/schemas.js';
|
|
2
|
+
export interface LoadPolicyResult {
|
|
3
|
+
userPolicy: Record<string, unknown>;
|
|
4
|
+
mergedPolicy: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Deep-merges `user` over `defaults` according to ADP-3 semantics:
|
|
8
|
+
* - scalar in user → replaces default scalar
|
|
9
|
+
* - object in both → recursive merge
|
|
10
|
+
* - array in user → replaces default array wholesale
|
|
11
|
+
* - undefined user fields → inherit from defaults
|
|
12
|
+
*/
|
|
13
|
+
export declare function mergePolicy(defaults: unknown, user: unknown): unknown;
|
|
14
|
+
/**
|
|
15
|
+
* Loads and composes a canonical policy by:
|
|
16
|
+
* 1. Reading bundled `policy.defaults.yaml`
|
|
17
|
+
* 2. Reading the user's `policy.yaml` at `policyPath`
|
|
18
|
+
* 3. Deep-merging user overrides over defaults (ADP-3 semantics)
|
|
19
|
+
* 4. Validating the merged result against `policy.schema.json`
|
|
20
|
+
*
|
|
21
|
+
* Throws with a descriptive error if defaults cannot be located, if either
|
|
22
|
+
* file cannot be read, or if the merged result fails schema validation.
|
|
23
|
+
*/
|
|
24
|
+
export declare function loadComposedPolicy(_repoRoot: string, policyPath: string, schemaRegistry: SchemaValidator): Promise<LoadPolicyResult>;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import fsSync from 'node:fs';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import YAML from 'yaml';
|
|
6
|
+
const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
function resolveBundledDefaultsPath(startDir) {
|
|
8
|
+
let current = path.resolve(startDir);
|
|
9
|
+
while (true) {
|
|
10
|
+
const candidate = path.join(current, 'agentic', 'orchestrator', 'defaults', 'policy.defaults.yaml');
|
|
11
|
+
if (fsSync.existsSync(candidate)) {
|
|
12
|
+
return candidate;
|
|
13
|
+
}
|
|
14
|
+
const parent = path.dirname(current);
|
|
15
|
+
if (parent === current) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
current = parent;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const BUNDLED_DEFAULTS_PATH = resolveBundledDefaultsPath(MODULE_DIR);
|
|
22
|
+
function isObject(value) {
|
|
23
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
24
|
+
}
|
|
25
|
+
function clone(value) {
|
|
26
|
+
if (Array.isArray(value)) {
|
|
27
|
+
return value.map(clone);
|
|
28
|
+
}
|
|
29
|
+
if (isObject(value)) {
|
|
30
|
+
const out = {};
|
|
31
|
+
for (const key of Object.keys(value)) {
|
|
32
|
+
out[key] = clone(value[key]);
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Deep-merges `user` over `defaults` according to ADP-3 semantics:
|
|
40
|
+
* - scalar in user → replaces default scalar
|
|
41
|
+
* - object in both → recursive merge
|
|
42
|
+
* - array in user → replaces default array wholesale
|
|
43
|
+
* - undefined user fields → inherit from defaults
|
|
44
|
+
*/
|
|
45
|
+
export function mergePolicy(defaults, user) {
|
|
46
|
+
if (Array.isArray(user)) {
|
|
47
|
+
return user.map(clone);
|
|
48
|
+
}
|
|
49
|
+
if (isObject(defaults) && isObject(user)) {
|
|
50
|
+
const out = clone(defaults);
|
|
51
|
+
for (const key of Object.keys(user)) {
|
|
52
|
+
const userVal = user[key];
|
|
53
|
+
if (userVal === undefined) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
out[key] = key in out ? mergePolicy(out[key], userVal) : clone(userVal);
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
return clone(user);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Loads and composes a canonical policy by:
|
|
64
|
+
* 1. Reading bundled `policy.defaults.yaml`
|
|
65
|
+
* 2. Reading the user's `policy.yaml` at `policyPath`
|
|
66
|
+
* 3. Deep-merging user overrides over defaults (ADP-3 semantics)
|
|
67
|
+
* 4. Validating the merged result against `policy.schema.json`
|
|
68
|
+
*
|
|
69
|
+
* Throws with a descriptive error if defaults cannot be located, if either
|
|
70
|
+
* file cannot be read, or if the merged result fails schema validation.
|
|
71
|
+
*/
|
|
72
|
+
export async function loadComposedPolicy(_repoRoot, policyPath, schemaRegistry) {
|
|
73
|
+
if (!BUNDLED_DEFAULTS_PATH) {
|
|
74
|
+
throw new Error('policy_defaults_not_found: bundled defaults artifact could not be located; ' +
|
|
75
|
+
'ensure agentic/orchestrator/defaults/policy.defaults.yaml exists in the AOP installation');
|
|
76
|
+
}
|
|
77
|
+
const defaultsText = await fs.readFile(BUNDLED_DEFAULTS_PATH, 'utf8');
|
|
78
|
+
const defaults = YAML.parse(defaultsText);
|
|
79
|
+
const userText = await fs.readFile(policyPath, 'utf8');
|
|
80
|
+
const userPolicy = YAML.parse(userText) ?? {};
|
|
81
|
+
const mergedPolicy = mergePolicy(defaults, userPolicy);
|
|
82
|
+
const validation = await schemaRegistry.validate('policy.schema.json', mergedPolicy);
|
|
83
|
+
if (!validation.valid) {
|
|
84
|
+
const messages = validation.errors.map((e) => e.message ?? String(e)).join('; ');
|
|
85
|
+
throw new Error(`invalid_policy_yaml: ${messages} ` +
|
|
86
|
+
`(merged from ${policyPath} over bundled defaults; check policy.yaml for invalid overrides)`);
|
|
87
|
+
}
|
|
88
|
+
return { userPolicy, mergedPolicy };
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=policy-loader-service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-loader-service.js","sourceRoot":"","sources":["../../../../../apps/control-plane/src/application/services/policy-loader-service.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,7 @@ const MUTATING_TOOLS = [
|
|
|
14
14
|
TOOLS.FEATURE_READY_TO_MERGE,
|
|
15
15
|
TOOLS.FEATURE_DELETE,
|
|
16
16
|
TOOLS.FEATURE_SEND_MESSAGE,
|
|
17
|
+
TOOLS.COST_RECORD,
|
|
17
18
|
TOOLS.PERFORMANCE_RECORD_OUTCOME
|
|
18
19
|
];
|
|
19
20
|
export const TOOL_BEHAVIOR_METADATA = Object.freeze(Object.fromEntries(MUTATING_TOOLS.map((name) => [name, { mutating: true, requires_operation_id: true }])));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-metadata.js","sourceRoot":"","sources":["../../../../../apps/control-plane/src/application/tools/tool-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAOhD,MAAM,cAAc,GAAG;IACrB,KAAK,CAAC,YAAY;IAClB,KAAK,CAAC,mBAAmB;IACzB,KAAK,CAAC,kBAAkB;IACxB,KAAK,CAAC,WAAW;IACjB,KAAK,CAAC,WAAW;IACjB,KAAK,CAAC,oBAAoB;IAC1B,KAAK,CAAC,gBAAgB;IACtB,KAAK,CAAC,SAAS;IACf,KAAK,CAAC,oBAAoB;IAC1B,KAAK,CAAC,aAAa;IACnB,KAAK,CAAC,aAAa;IACnB,KAAK,CAAC,sBAAsB;IAC5B,KAAK,CAAC,cAAc;IACpB,KAAK,CAAC,oBAAoB;IAC1B,KAAK,CAAC,0BAA0B;CACxB,CAAC;AAEX,MAAM,CAAC,MAAM,sBAAsB,GAAmD,MAAM,CAAC,MAAM,CACjG,MAAM,CAAC,WAAW,CAChB,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC,CAAC,CACtF,CACF,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,OAAO,sBAAsB,CAAC,QAAQ,CAAC,EAAE,QAAQ,IAAI,KAAK,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,OAAO,sBAAsB,CAAC,QAAQ,CAAC,EAAE,qBAAqB,IAAI,KAAK,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,QAAgB,EAChB,IAA6B,EAC7B,iBAAmE;IAEnE,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;IACrB,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IACpF,OAAO;QACL,GAAG,IAAI;QACP,YAAY,EAAE,iBAAiB,CAAC,QAAQ,EAAE,SAAS,CAAC;KACrD,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"tool-metadata.js","sourceRoot":"","sources":["../../../../../apps/control-plane/src/application/tools/tool-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAOhD,MAAM,cAAc,GAAG;IACrB,KAAK,CAAC,YAAY;IAClB,KAAK,CAAC,mBAAmB;IACzB,KAAK,CAAC,kBAAkB;IACxB,KAAK,CAAC,WAAW;IACjB,KAAK,CAAC,WAAW;IACjB,KAAK,CAAC,oBAAoB;IAC1B,KAAK,CAAC,gBAAgB;IACtB,KAAK,CAAC,SAAS;IACf,KAAK,CAAC,oBAAoB;IAC1B,KAAK,CAAC,aAAa;IACnB,KAAK,CAAC,aAAa;IACnB,KAAK,CAAC,sBAAsB;IAC5B,KAAK,CAAC,cAAc;IACpB,KAAK,CAAC,oBAAoB;IAC1B,KAAK,CAAC,WAAW;IACjB,KAAK,CAAC,0BAA0B;CACxB,CAAC;AAEX,MAAM,CAAC,MAAM,sBAAsB,GAAmD,MAAM,CAAC,MAAM,CACjG,MAAM,CAAC,WAAW,CAChB,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,CAAC,CAAC,CACtF,CACF,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,OAAO,sBAAsB,CAAC,QAAQ,CAAC,EAAE,QAAQ,IAAI,KAAK,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,QAAgB;IACtD,OAAO,sBAAsB,CAAC,QAAQ,CAAC,EAAE,qBAAqB,IAAI,KAAK,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,yBAAyB,CACvC,QAAgB,EAChB,IAA6B,EAC7B,iBAAmE;IAEnE,IAAI,CAAC,uBAAuB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACvC,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;IACrB,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IACpF,OAAO;QACL,GAAG,IAAI;QACP,YAAY,EAAE,iBAAiB,CAAC,QAAQ,EAAE,SAAS,CAAC;KACrD,CAAC;AACJ,CAAC"}
|