oxe-cc 1.0.0 → 1.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/.cursor/commands/oxe-ask.md +3 -3
- package/.cursor/commands/oxe-capabilities.md +3 -3
- package/.cursor/commands/oxe-checkpoint.md +3 -3
- package/.cursor/commands/oxe-compact.md +3 -3
- package/.cursor/commands/oxe-dashboard.md +3 -3
- package/.cursor/commands/oxe-debug.md +3 -3
- package/.cursor/commands/oxe-discuss.md +3 -3
- package/.cursor/commands/oxe-execute.md +7 -4
- package/.cursor/commands/oxe-forensics.md +3 -3
- package/.cursor/commands/oxe-help.md +3 -3
- package/.cursor/commands/oxe-loop.md +3 -3
- package/.cursor/commands/oxe-milestone.md +3 -3
- package/.cursor/commands/oxe-next.md +3 -3
- package/.cursor/commands/oxe-obs.md +3 -3
- package/.cursor/commands/oxe-plan-agent.md +3 -3
- package/.cursor/commands/oxe-plan.md +3 -3
- package/.cursor/commands/oxe-project.md +3 -3
- package/.cursor/commands/oxe-quick.md +3 -3
- package/.cursor/commands/oxe-research.md +3 -3
- package/.cursor/commands/oxe-retro.md +3 -3
- package/.cursor/commands/oxe-review-pr.md +3 -3
- package/.cursor/commands/oxe-route.md +3 -3
- package/.cursor/commands/oxe-scan.md +3 -3
- package/.cursor/commands/oxe-security.md +3 -3
- package/.cursor/commands/oxe-session.md +4 -4
- package/.cursor/commands/oxe-ship.md +45 -0
- package/.cursor/commands/oxe-skill.md +3 -3
- package/.cursor/commands/oxe-spec.md +3 -3
- package/.cursor/commands/oxe-ui-review.md +3 -3
- package/.cursor/commands/oxe-ui-spec.md +3 -3
- package/.cursor/commands/oxe-update.md +3 -3
- package/.cursor/commands/oxe-validate-gaps.md +3 -3
- package/.cursor/commands/oxe-verify.md +6 -3
- package/.cursor/commands/oxe-workstream.md +3 -3
- package/.cursor/commands/oxe.md +6 -6
- package/.github/copilot-instructions.md +94 -4
- package/.github/prompts/oxe-ask.prompt.md +3 -3
- package/.github/prompts/oxe-capabilities.prompt.md +3 -3
- package/.github/prompts/oxe-checkpoint.prompt.md +3 -3
- package/.github/prompts/oxe-compact.prompt.md +3 -3
- package/.github/prompts/oxe-dashboard.prompt.md +3 -3
- package/.github/prompts/oxe-debug.prompt.md +3 -3
- package/.github/prompts/oxe-discuss.prompt.md +3 -3
- package/.github/prompts/oxe-execute.prompt.md +7 -4
- package/.github/prompts/oxe-forensics.prompt.md +3 -3
- package/.github/prompts/oxe-help.prompt.md +3 -3
- package/.github/prompts/oxe-loop.prompt.md +3 -3
- package/.github/prompts/oxe-milestone.prompt.md +3 -3
- package/.github/prompts/oxe-next.prompt.md +3 -3
- package/.github/prompts/oxe-obs.prompt.md +3 -3
- package/.github/prompts/oxe-plan-agent.prompt.md +3 -3
- package/.github/prompts/oxe-plan.prompt.md +3 -3
- package/.github/prompts/oxe-project.prompt.md +3 -3
- package/.github/prompts/oxe-quick.prompt.md +3 -3
- package/.github/prompts/oxe-research.prompt.md +3 -3
- package/.github/prompts/oxe-retro.prompt.md +3 -3
- package/.github/prompts/oxe-review-pr.prompt.md +3 -3
- package/.github/prompts/oxe-route.prompt.md +3 -3
- package/.github/prompts/oxe-scan.prompt.md +3 -3
- package/.github/prompts/oxe-security.prompt.md +3 -3
- package/.github/prompts/oxe-session.prompt.md +4 -4
- package/.github/prompts/oxe-ship.prompt.md +45 -0
- package/.github/prompts/oxe-skill.prompt.md +3 -3
- package/.github/prompts/oxe-spec.prompt.md +3 -3
- package/.github/prompts/oxe-ui-review.prompt.md +3 -3
- package/.github/prompts/oxe-ui-spec.prompt.md +3 -3
- package/.github/prompts/oxe-update.prompt.md +3 -3
- package/.github/prompts/oxe-validate-gaps.prompt.md +3 -3
- package/.github/prompts/oxe-verify.prompt.md +6 -3
- package/.github/prompts/oxe-workstream.prompt.md +3 -3
- package/.github/prompts/oxe.prompt.md +5 -5
- package/AGENTS.md +43 -28
- package/CHANGELOG.md +193 -0
- package/README.md +610 -529
- package/bin/banner.txt +1 -1
- package/bin/lib/oxe-agent-install.cjs +69 -69
- package/bin/lib/oxe-azure.cjs +1445 -1445
- package/bin/lib/oxe-context-engine.cjs +867 -867
- package/bin/lib/oxe-dashboard.cjs +76 -28
- package/bin/lib/oxe-operational.cjs +2144 -1340
- package/bin/lib/oxe-project-health.cjs +483 -1
- package/bin/lib/oxe-runtime-semantics.cjs +12 -0
- package/bin/oxe-cc.js +554 -152
- package/commands/oxe/ask.md +7 -3
- package/commands/oxe/capabilities.md +2 -2
- package/commands/oxe/checkpoint.md +3 -3
- package/commands/oxe/compact.md +3 -3
- package/commands/oxe/dashboard.md +2 -2
- package/commands/oxe/debug.md +3 -3
- package/commands/oxe/discuss.md +2 -2
- package/commands/oxe/execute.md +7 -4
- package/commands/oxe/forensics.md +3 -3
- package/commands/oxe/help.md +2 -2
- package/commands/oxe/loop.md +3 -3
- package/commands/oxe/milestone.md +3 -3
- package/commands/oxe/next.md +3 -3
- package/commands/oxe/obs.md +3 -3
- package/commands/oxe/oxe.md +5 -5
- package/commands/oxe/plan-agent.md +2 -2
- package/commands/oxe/plan.md +2 -2
- package/commands/oxe/project.md +3 -3
- package/commands/oxe/quick.md +2 -2
- package/commands/oxe/research.md +3 -3
- package/commands/oxe/retro.md +3 -3
- package/commands/oxe/review-pr.md +3 -3
- package/commands/oxe/route.md +3 -3
- package/commands/oxe/scan.md +3 -3
- package/commands/oxe/security.md +3 -3
- package/commands/oxe/session.md +4 -4
- package/commands/oxe/ship.md +49 -0
- package/commands/oxe/skill.md +2 -2
- package/commands/oxe/spec.md +4 -4
- package/commands/oxe/ui-review.md +3 -3
- package/commands/oxe/ui-spec.md +3 -3
- package/commands/oxe/update.md +2 -2
- package/commands/oxe/validate-gaps.md +3 -3
- package/commands/oxe/verify.md +7 -4
- package/commands/oxe/workstream.md +3 -3
- package/lib/runtime/audit/audit-trail.d.ts +71 -0
- package/lib/runtime/audit/audit-trail.js +154 -0
- package/lib/runtime/audit/index.d.ts +2 -0
- package/lib/runtime/audit/index.js +18 -0
- package/lib/runtime/audit/policy-pack.d.ts +15 -0
- package/lib/runtime/audit/policy-pack.js +57 -0
- package/lib/runtime/context/context-pack-builder.d.ts +15 -0
- package/lib/runtime/context/context-pack-builder.js +42 -0
- package/lib/runtime/context/context-pack-store.d.ts +38 -0
- package/lib/runtime/context/context-pack-store.js +142 -0
- package/lib/runtime/context/context-profiles.d.ts +11 -0
- package/lib/runtime/context/context-profiles.js +51 -0
- package/lib/runtime/context/index.d.ts +2 -0
- package/lib/runtime/context/index.js +2 -0
- package/lib/runtime/decision/decision-engine.d.ts +43 -0
- package/lib/runtime/decision/decision-engine.js +127 -0
- package/lib/runtime/decision/decision-memo.d.ts +53 -0
- package/lib/runtime/decision/decision-memo.js +173 -0
- package/lib/runtime/decision/index.d.ts +2 -0
- package/lib/runtime/decision/index.js +18 -0
- package/lib/runtime/delivery/branch-manager.d.ts +1 -0
- package/lib/runtime/delivery/branch-manager.js +7 -0
- package/lib/runtime/delivery/ci-checks.js +34 -1
- package/lib/runtime/delivery/delivery-records.d.ts +34 -0
- package/lib/runtime/delivery/delivery-records.js +48 -0
- package/lib/runtime/delivery/index.d.ts +2 -0
- package/lib/runtime/delivery/index.js +2 -0
- package/lib/runtime/delivery/promotion-pipeline.d.ts +63 -0
- package/lib/runtime/delivery/promotion-pipeline.js +224 -0
- package/lib/runtime/gate/gate-manager.d.ts +41 -0
- package/lib/runtime/gate/gate-manager.js +108 -1
- package/lib/runtime/index.d.ts +5 -2
- package/lib/runtime/index.js +7 -1
- package/lib/runtime/models/gate-decision.d.ts +4 -1
- package/lib/runtime/models/workspace.d.ts +3 -0
- package/lib/runtime/plugins/capability-adapter.d.ts +12 -0
- package/lib/runtime/plugins/capability-adapter.js +204 -0
- package/lib/runtime/plugins/capability-matrix.d.ts +25 -0
- package/lib/runtime/plugins/capability-matrix.js +90 -0
- package/lib/runtime/plugins/index.d.ts +3 -0
- package/lib/runtime/plugins/index.js +3 -0
- package/lib/runtime/plugins/plugin-abi.d.ts +2 -0
- package/lib/runtime/plugins/plugin-manifest.d.ts +22 -0
- package/lib/runtime/plugins/plugin-manifest.js +95 -0
- package/lib/runtime/plugins/plugin-registry.d.ts +46 -0
- package/lib/runtime/plugins/plugin-registry.js +84 -2
- package/lib/runtime/policy/policy-engine.d.ts +47 -1
- package/lib/runtime/policy/policy-engine.js +172 -9
- package/lib/runtime/projection/projection-engine.d.ts +9 -1
- package/lib/runtime/projection/projection-engine.js +73 -3
- package/lib/runtime/reducers/run-state-reducer.d.ts +26 -0
- package/lib/runtime/reducers/run-state-reducer.js +117 -1
- package/lib/runtime/scheduler/agent-registry.d.ts +44 -0
- package/lib/runtime/scheduler/agent-registry.js +96 -0
- package/lib/runtime/scheduler/agent-roles.d.ts +54 -0
- package/lib/runtime/scheduler/agent-roles.js +62 -0
- package/lib/runtime/scheduler/index.d.ts +3 -0
- package/lib/runtime/scheduler/index.js +3 -0
- package/lib/runtime/scheduler/multi-agent-coordinator.d.ts +45 -1
- package/lib/runtime/scheduler/multi-agent-coordinator.js +234 -35
- package/lib/runtime/scheduler/run-journal.d.ts +18 -0
- package/lib/runtime/scheduler/run-journal.js +54 -0
- package/lib/runtime/scheduler/scheduler.d.ts +29 -1
- package/lib/runtime/scheduler/scheduler.js +387 -14
- package/lib/runtime/verification/index.d.ts +1 -0
- package/lib/runtime/verification/index.js +1 -0
- package/lib/runtime/verification/verification-compiler.d.ts +43 -0
- package/lib/runtime/verification/verification-compiler.js +137 -0
- package/lib/runtime/verification/verification-manifest.d.ts +67 -0
- package/lib/runtime/verification/verification-manifest.js +179 -0
- package/lib/runtime/workspace/strategies/ephemeral-container.d.ts +1 -0
- package/lib/runtime/workspace/strategies/ephemeral-container.js +4 -0
- package/lib/runtime/workspace/strategies/git-worktree.d.ts +1 -0
- package/lib/runtime/workspace/strategies/git-worktree.js +2 -0
- package/lib/runtime/workspace/strategies/inplace.d.ts +1 -0
- package/lib/runtime/workspace/strategies/inplace.js +2 -0
- package/lib/runtime/workspace/workspace-manager.d.ts +2 -1
- package/lib/sdk/README.md +9 -9
- package/lib/sdk/index.cjs +33 -24
- package/lib/sdk/index.d.ts +149 -14
- package/oxe/templates/ACTIVE-RUN.template.json +32 -32
- package/oxe/templates/CAPABILITIES.template.md +7 -7
- package/oxe/templates/CAPABILITY.template.md +45 -45
- package/oxe/templates/CHECKPOINTS.template.md +7 -7
- package/oxe/templates/EXECUTION-RUNTIME.template.md +68 -68
- package/oxe/templates/HYPOTHESES.template.md +33 -33
- package/oxe/templates/LESSONS-METRICS.template.json +13 -13
- package/oxe/templates/NOTES.template.md +16 -16
- package/oxe/templates/PLAN-REVIEW.template.md +31 -31
- package/oxe/templates/SESSION.template.md +34 -34
- package/oxe/templates/SKILL.template.md +26 -26
- package/oxe/templates/STATE.md +55 -55
- package/oxe/templates/WORKFLOW_AUTHORING.md +18 -18
- package/oxe/workflows/ask.md +96 -92
- package/oxe/workflows/capabilities.md +25 -25
- package/oxe/workflows/checkpoint.md +14 -10
- package/oxe/workflows/dashboard.md +33 -33
- package/oxe/workflows/debug.md +19 -15
- package/oxe/workflows/discuss.md +12 -12
- package/oxe/workflows/execute.md +44 -2
- package/oxe/workflows/forensics.md +13 -9
- package/oxe/workflows/help.md +352 -304
- package/oxe/workflows/loop.md +17 -13
- package/oxe/workflows/next.md +22 -22
- package/oxe/workflows/obs.md +4 -0
- package/oxe/workflows/oxe.md +64 -31
- package/oxe/workflows/plan-agent.md +9 -9
- package/oxe/workflows/project.md +6 -1
- package/oxe/workflows/quick.md +10 -10
- package/oxe/workflows/references/reasoning-discovery.md +28 -28
- package/oxe/workflows/references/reasoning-execution.md +29 -29
- package/oxe/workflows/references/reasoning-planning.md +32 -32
- package/oxe/workflows/references/reasoning-review.md +29 -29
- package/oxe/workflows/references/reasoning-status.md +24 -24
- package/oxe/workflows/references/robustness-elevation.md +295 -295
- package/oxe/workflows/references/workflow-runtime-contracts.json +952 -907
- package/oxe/workflows/research.md +32 -28
- package/oxe/workflows/retro.md +4 -0
- package/oxe/workflows/review-pr.md +15 -11
- package/oxe/workflows/route.md +16 -16
- package/oxe/workflows/scan.md +4 -0
- package/oxe/workflows/security.md +14 -10
- package/oxe/workflows/session.md +213 -197
- package/oxe/workflows/ship.md +142 -0
- package/oxe/workflows/skill.md +44 -44
- package/oxe/workflows/spec.md +15 -0
- package/oxe/workflows/ui-review.md +20 -16
- package/oxe/workflows/ui-spec.md +7 -3
- package/oxe/workflows/validate-gaps.md +13 -9
- package/oxe/workflows/verify-audit.md +73 -73
- package/oxe/workflows/verify.md +52 -3
- package/package.json +92 -92
- package/packages/runtime/package.json +17 -17
- package/packages/runtime/src/audit/audit-trail.ts +243 -0
- package/packages/runtime/src/audit/index.ts +2 -0
- package/packages/runtime/src/audit/policy-pack.ts +62 -0
- package/packages/runtime/src/compiler/graph-compiler.ts +245 -245
- package/packages/runtime/src/compiler/index.ts +1 -1
- package/packages/runtime/src/context/context-pack-builder.ts +259 -193
- package/packages/runtime/src/context/context-pack-store.ts +197 -0
- package/packages/runtime/src/context/context-profiles.ts +60 -0
- package/packages/runtime/src/context/index.ts +3 -1
- package/packages/runtime/src/decision/decision-engine.ts +174 -0
- package/packages/runtime/src/decision/decision-memo.ts +211 -0
- package/packages/runtime/src/decision/index.ts +2 -0
- package/packages/runtime/src/delivery/branch-manager.ts +91 -84
- package/packages/runtime/src/delivery/ci-checks.ts +285 -252
- package/packages/runtime/src/delivery/delivery-records.ts +75 -0
- package/packages/runtime/src/delivery/index.ts +5 -3
- package/packages/runtime/src/delivery/pr-manager.ts +112 -112
- package/packages/runtime/src/delivery/promotion-pipeline.ts +334 -0
- package/packages/runtime/src/events/bus.ts +92 -92
- package/packages/runtime/src/events/catalog.ts +29 -29
- package/packages/runtime/src/events/envelope.ts +14 -14
- package/packages/runtime/src/events/index.ts +3 -3
- package/packages/runtime/src/evidence/evidence-store.ts +130 -130
- package/packages/runtime/src/evidence/index.ts +1 -1
- package/packages/runtime/src/gate/gate-manager.ts +289 -137
- package/packages/runtime/src/gate/index.ts +1 -1
- package/packages/runtime/src/index.ts +41 -32
- package/packages/runtime/src/models/attempt.ts +19 -19
- package/packages/runtime/src/models/evidence.ts +21 -21
- package/packages/runtime/src/models/gate-decision.ts +25 -21
- package/packages/runtime/src/models/index.ts +8 -8
- package/packages/runtime/src/models/run.ts +24 -24
- package/packages/runtime/src/models/session.ts +11 -11
- package/packages/runtime/src/models/verification-result.ts +10 -10
- package/packages/runtime/src/models/work-item.ts +25 -25
- package/packages/runtime/src/models/workspace.ts +31 -28
- package/packages/runtime/src/plugins/capability-adapter.ts +206 -0
- package/packages/runtime/src/plugins/capability-matrix.ts +126 -0
- package/packages/runtime/src/plugins/index.ts +5 -2
- package/packages/runtime/src/plugins/plugin-abi.ts +97 -95
- package/packages/runtime/src/plugins/plugin-manifest.ts +118 -0
- package/packages/runtime/src/plugins/plugin-registry.ts +232 -119
- package/packages/runtime/src/policy/index.ts +1 -1
- package/packages/runtime/src/policy/policy-engine.ts +330 -113
- package/packages/runtime/src/projection/index.ts +1 -1
- package/packages/runtime/src/projection/projection-engine.ts +328 -249
- package/packages/runtime/src/reducers/debug-reducer.ts +36 -36
- package/packages/runtime/src/reducers/index.ts +2 -2
- package/packages/runtime/src/reducers/run-state-reducer.ts +269 -127
- package/packages/runtime/src/scheduler/agent-registry.ts +132 -0
- package/packages/runtime/src/scheduler/agent-roles.ts +109 -0
- package/packages/runtime/src/scheduler/index.ts +4 -1
- package/packages/runtime/src/scheduler/multi-agent-coordinator.ts +521 -231
- package/packages/runtime/src/scheduler/run-journal.ts +62 -0
- package/packages/runtime/src/scheduler/scheduler.ts +722 -281
- package/packages/runtime/src/verification/index.ts +2 -1
- package/packages/runtime/src/verification/verification-compiler.ts +436 -225
- package/packages/runtime/src/verification/verification-manifest.ts +252 -0
- package/packages/runtime/src/workspace/index.ts +5 -5
- package/packages/runtime/src/workspace/strategies/ephemeral-container.ts +126 -121
- package/packages/runtime/src/workspace/strategies/git-worktree.ts +79 -77
- package/packages/runtime/src/workspace/strategies/inplace.ts +38 -35
- package/packages/runtime/src/workspace/workspace-manager.ts +16 -15
- package/packages/runtime/tsconfig.json +17 -17
- package/vscode-extension/.vscodeignore +7 -7
- package/vscode-extension/oxe-agents-1.0.0.vsix +0 -0
- package/vscode-extension/package.json +185 -185
- package/vscode-extension/src/extension.js +310 -310
- package/vscode-extension/src/shared/contextLoader.js +137 -137
- package/vscode-extension/src/shared/contractBuilder.js +159 -159
- package/vscode-extension/src/shared/stateReader.js +101 -101
|
@@ -24,6 +24,7 @@ export interface ToolProvider {
|
|
|
24
24
|
}
|
|
25
25
|
export interface WorkspaceProvider extends WorkspaceManager {
|
|
26
26
|
readonly name: string;
|
|
27
|
+
readonly isolation_level: 'shared' | 'isolated';
|
|
27
28
|
supportsStrategy(strategy: string): boolean;
|
|
28
29
|
}
|
|
29
30
|
export interface VerificationInput {
|
|
@@ -67,6 +68,7 @@ export interface ContextProvider {
|
|
|
67
68
|
export interface OxePlugin {
|
|
68
69
|
readonly name: string;
|
|
69
70
|
readonly version?: string;
|
|
71
|
+
readonly abi_version?: string;
|
|
70
72
|
toolProviders?: ToolProvider[];
|
|
71
73
|
workspaceProviders?: WorkspaceProvider[];
|
|
72
74
|
verifierProviders?: VerifierProvider[];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { OxePlugin } from './plugin-abi';
|
|
2
|
+
export declare const CURRENT_ABI_VERSION = "1";
|
|
3
|
+
export interface PluginManifest {
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
abi_version: string;
|
|
7
|
+
capabilities: Array<'tool' | 'workspace' | 'verifier' | 'context' | 'hooks'>;
|
|
8
|
+
tool_action_types?: string[];
|
|
9
|
+
workspace_strategies?: string[];
|
|
10
|
+
verifier_check_types?: string[];
|
|
11
|
+
context_provider_names?: string[];
|
|
12
|
+
hook_names?: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface PluginValidationResult {
|
|
15
|
+
valid: boolean;
|
|
16
|
+
errors: string[];
|
|
17
|
+
warnings: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function extractManifest(plugin: OxePlugin): PluginManifest;
|
|
20
|
+
export declare function validatePlugin(plugin: OxePlugin): PluginValidationResult;
|
|
21
|
+
export declare function isAbiCompatible(pluginAbiVersion: string): boolean;
|
|
22
|
+
export declare function sandboxInvoke<T>(fn: () => Promise<T>, timeoutMs?: number): Promise<T>;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CURRENT_ABI_VERSION = void 0;
|
|
4
|
+
exports.extractManifest = extractManifest;
|
|
5
|
+
exports.validatePlugin = validatePlugin;
|
|
6
|
+
exports.isAbiCompatible = isAbiCompatible;
|
|
7
|
+
exports.sandboxInvoke = sandboxInvoke;
|
|
8
|
+
exports.CURRENT_ABI_VERSION = '1';
|
|
9
|
+
function extractManifest(plugin) {
|
|
10
|
+
const capabilities = [];
|
|
11
|
+
if (plugin.toolProviders?.length)
|
|
12
|
+
capabilities.push('tool');
|
|
13
|
+
if (plugin.workspaceProviders?.length)
|
|
14
|
+
capabilities.push('workspace');
|
|
15
|
+
if (plugin.verifierProviders?.length)
|
|
16
|
+
capabilities.push('verifier');
|
|
17
|
+
if (plugin.contextProviders?.length)
|
|
18
|
+
capabilities.push('context');
|
|
19
|
+
if (plugin.hooks && Object.keys(plugin.hooks).length > 0)
|
|
20
|
+
capabilities.push('hooks');
|
|
21
|
+
return {
|
|
22
|
+
name: plugin.name,
|
|
23
|
+
version: plugin.version ?? '0.0.0',
|
|
24
|
+
abi_version: plugin.abi_version ?? exports.CURRENT_ABI_VERSION,
|
|
25
|
+
capabilities,
|
|
26
|
+
tool_action_types: plugin.toolProviders?.flatMap((p) => ['read_code', 'generate_patch', 'run_tests', 'collect_evidence', 'custom'].filter((t) => p.supports(t))) ?? [],
|
|
27
|
+
workspace_strategies: plugin.workspaceProviders?.map((p) => p.name) ?? [],
|
|
28
|
+
verifier_check_types: plugin.verifierProviders?.flatMap((p) => ['unit', 'integration', 'smoke', 'policy', 'security', 'custom'].filter((t) => p.supports(t))) ?? [],
|
|
29
|
+
context_provider_names: plugin.contextProviders?.map((p) => p.name) ?? [],
|
|
30
|
+
hook_names: plugin.hooks ? Object.keys(plugin.hooks) : [],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
function validatePlugin(plugin) {
|
|
34
|
+
const errors = [];
|
|
35
|
+
const warnings = [];
|
|
36
|
+
if (!plugin.name || typeof plugin.name !== 'string') {
|
|
37
|
+
errors.push('Plugin must have a non-empty string name');
|
|
38
|
+
}
|
|
39
|
+
if (plugin.version && !/^\d+\.\d+\.\d+/.test(plugin.version)) {
|
|
40
|
+
warnings.push(`Plugin version "${plugin.version}" does not follow semver`);
|
|
41
|
+
}
|
|
42
|
+
const abiVersion = plugin.abi_version ?? exports.CURRENT_ABI_VERSION;
|
|
43
|
+
if (!isAbiCompatible(abiVersion)) {
|
|
44
|
+
errors.push(`Plugin ABI "${abiVersion}" is incompatible with runtime ABI "${exports.CURRENT_ABI_VERSION}"`);
|
|
45
|
+
}
|
|
46
|
+
if (!plugin.toolProviders?.length &&
|
|
47
|
+
!plugin.workspaceProviders?.length &&
|
|
48
|
+
!plugin.verifierProviders?.length &&
|
|
49
|
+
!plugin.contextProviders?.length &&
|
|
50
|
+
!plugin.hooks) {
|
|
51
|
+
warnings.push('Plugin declares no providers or hooks — it has no effect');
|
|
52
|
+
}
|
|
53
|
+
// Validate each tool provider
|
|
54
|
+
for (const tp of plugin.toolProviders ?? []) {
|
|
55
|
+
if (!tp.name)
|
|
56
|
+
errors.push('ToolProvider missing name');
|
|
57
|
+
if (typeof tp.supports !== 'function')
|
|
58
|
+
errors.push(`ToolProvider "${tp.name}" missing supports() method`);
|
|
59
|
+
if (typeof tp.invoke !== 'function')
|
|
60
|
+
errors.push(`ToolProvider "${tp.name}" missing invoke() method`);
|
|
61
|
+
}
|
|
62
|
+
// Validate each workspace provider
|
|
63
|
+
for (const wp of plugin.workspaceProviders ?? []) {
|
|
64
|
+
if (!wp.name)
|
|
65
|
+
errors.push('WorkspaceProvider missing name');
|
|
66
|
+
if (typeof wp.supportsStrategy !== 'function')
|
|
67
|
+
errors.push(`WorkspaceProvider "${wp.name}" missing supportsStrategy()`);
|
|
68
|
+
if (typeof wp.allocate !== 'function')
|
|
69
|
+
errors.push(`WorkspaceProvider "${wp.name}" missing allocate()`);
|
|
70
|
+
}
|
|
71
|
+
// Validate each verifier provider
|
|
72
|
+
for (const vp of plugin.verifierProviders ?? []) {
|
|
73
|
+
if (!vp.name)
|
|
74
|
+
errors.push('VerifierProvider missing name');
|
|
75
|
+
if (typeof vp.supports !== 'function')
|
|
76
|
+
errors.push(`VerifierProvider "${vp.name}" missing supports()`);
|
|
77
|
+
if (typeof vp.execute !== 'function')
|
|
78
|
+
errors.push(`VerifierProvider "${vp.name}" missing execute()`);
|
|
79
|
+
}
|
|
80
|
+
return { valid: errors.length === 0, errors, warnings };
|
|
81
|
+
}
|
|
82
|
+
function isAbiCompatible(pluginAbiVersion) {
|
|
83
|
+
// Major version must match; minor/patch are backwards-compatible
|
|
84
|
+
const [currMajor] = exports.CURRENT_ABI_VERSION.split('.').map(Number);
|
|
85
|
+
const [plugMajor] = pluginAbiVersion.split('.').map(Number);
|
|
86
|
+
return currMajor === plugMajor;
|
|
87
|
+
}
|
|
88
|
+
function sandboxInvoke(fn, timeoutMs = 10000) {
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
const timer = setTimeout(() => {
|
|
91
|
+
reject(new Error(`Plugin invocation timed out after ${timeoutMs}ms`));
|
|
92
|
+
}, timeoutMs);
|
|
93
|
+
fn().then((result) => { clearTimeout(timer); resolve(result); }, (err) => { clearTimeout(timer); reject(err instanceof Error ? err : new Error(String(err))); });
|
|
94
|
+
});
|
|
95
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { OxePlugin, ToolProvider, WorkspaceProvider, VerifierProvider, ContextProvider } from './plugin-abi';
|
|
2
|
+
import { type CapabilityMatrix } from './capability-matrix';
|
|
2
3
|
export declare class PluginRegistry {
|
|
3
4
|
private plugins;
|
|
5
|
+
private loadErrors;
|
|
4
6
|
register(plugin: OxePlugin): void;
|
|
5
7
|
unregister(name: string): void;
|
|
6
8
|
loadFromDirectory(dir: string): string[];
|
|
@@ -16,6 +18,50 @@ export declare class PluginRegistry {
|
|
|
16
18
|
version?: string;
|
|
17
19
|
providers: string[];
|
|
18
20
|
}>;
|
|
21
|
+
registerProjectCapabilities(projectRoot: string): string[];
|
|
22
|
+
loadErrorsSnapshot(): string[];
|
|
23
|
+
clearLoadErrors(): void;
|
|
24
|
+
snapshot(): Array<{
|
|
25
|
+
name: string;
|
|
26
|
+
version?: string;
|
|
27
|
+
abi_version?: string;
|
|
28
|
+
toolProviders: Array<{
|
|
29
|
+
name: string;
|
|
30
|
+
kind: string;
|
|
31
|
+
idempotent: boolean;
|
|
32
|
+
}>;
|
|
33
|
+
workspaceProviders: Array<{
|
|
34
|
+
name: string;
|
|
35
|
+
}>;
|
|
36
|
+
verifierProviders: Array<{
|
|
37
|
+
name: string;
|
|
38
|
+
}>;
|
|
39
|
+
contextProviders: Array<{
|
|
40
|
+
name: string;
|
|
41
|
+
}>;
|
|
42
|
+
}>;
|
|
43
|
+
summary(): {
|
|
44
|
+
total_plugins: number;
|
|
45
|
+
tool_providers: number;
|
|
46
|
+
workspace_providers: number;
|
|
47
|
+
verifier_providers: number;
|
|
48
|
+
context_providers: number;
|
|
49
|
+
load_errors: number;
|
|
50
|
+
pluginsCount: number;
|
|
51
|
+
toolProviders: number;
|
|
52
|
+
workspaceProviders: number;
|
|
53
|
+
verifierProviders: number;
|
|
54
|
+
contextProviders: number;
|
|
55
|
+
loadErrors: number;
|
|
56
|
+
plugins: Array<{
|
|
57
|
+
name: string;
|
|
58
|
+
version?: string;
|
|
59
|
+
providers: string[];
|
|
60
|
+
}>;
|
|
61
|
+
};
|
|
62
|
+
capabilityMatrix(): CapabilityMatrix;
|
|
19
63
|
}
|
|
20
64
|
export declare function globalRegistry(): PluginRegistry;
|
|
21
65
|
export declare function resetGlobalRegistry(): void;
|
|
66
|
+
export declare function registrySummary(registry: PluginRegistry): ReturnType<PluginRegistry['summary']>;
|
|
67
|
+
export declare function resolveCapabilityMatrix(registry: PluginRegistry): CapabilityMatrix;
|
|
@@ -6,16 +6,26 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.PluginRegistry = void 0;
|
|
7
7
|
exports.globalRegistry = globalRegistry;
|
|
8
8
|
exports.resetGlobalRegistry = resetGlobalRegistry;
|
|
9
|
+
exports.registrySummary = registrySummary;
|
|
10
|
+
exports.resolveCapabilityMatrix = resolveCapabilityMatrix;
|
|
9
11
|
const fs_1 = __importDefault(require("fs"));
|
|
10
12
|
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const plugin_manifest_1 = require("./plugin-manifest");
|
|
14
|
+
const capability_matrix_1 = require("./capability-matrix");
|
|
15
|
+
const capability_adapter_1 = require("./capability-adapter");
|
|
11
16
|
class PluginRegistry {
|
|
12
17
|
constructor() {
|
|
13
18
|
this.plugins = [];
|
|
19
|
+
this.loadErrors = [];
|
|
14
20
|
}
|
|
15
21
|
register(plugin) {
|
|
16
22
|
if (this.plugins.some((p) => p.name === plugin.name)) {
|
|
17
23
|
throw new Error(`Plugin "${plugin.name}" is already registered`);
|
|
18
24
|
}
|
|
25
|
+
const validation = (0, plugin_manifest_1.validatePlugin)(plugin);
|
|
26
|
+
if (!validation.valid && validation.errors.length > 0) {
|
|
27
|
+
throw new Error(`Plugin "${plugin.name}" failed validation: ${validation.errors.join('; ')}`);
|
|
28
|
+
}
|
|
19
29
|
this.plugins.push(plugin);
|
|
20
30
|
}
|
|
21
31
|
unregister(name) {
|
|
@@ -38,8 +48,8 @@ class PluginRegistry {
|
|
|
38
48
|
loaded.push(plugin.name);
|
|
39
49
|
}
|
|
40
50
|
}
|
|
41
|
-
catch {
|
|
42
|
-
|
|
51
|
+
catch (error) {
|
|
52
|
+
this.loadErrors.push(`Plugin ${fullPath} falhou ao carregar: ${error instanceof Error ? error.message : String(error)}`);
|
|
43
53
|
}
|
|
44
54
|
}
|
|
45
55
|
return loaded;
|
|
@@ -101,6 +111,72 @@ class PluginRegistry {
|
|
|
101
111
|
],
|
|
102
112
|
}));
|
|
103
113
|
}
|
|
114
|
+
registerProjectCapabilities(projectRoot) {
|
|
115
|
+
const loaded = [];
|
|
116
|
+
for (const plugin of (0, capability_adapter_1.loadCapabilityPlugins)(projectRoot)) {
|
|
117
|
+
try {
|
|
118
|
+
this.register(plugin);
|
|
119
|
+
loaded.push(plugin.name);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
this.loadErrors.push(`Capability plugin ${plugin.name} falhou ao registrar: ${error instanceof Error ? error.message : String(error)}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return loaded;
|
|
126
|
+
}
|
|
127
|
+
loadErrorsSnapshot() {
|
|
128
|
+
return [...this.loadErrors];
|
|
129
|
+
}
|
|
130
|
+
clearLoadErrors() {
|
|
131
|
+
this.loadErrors = [];
|
|
132
|
+
}
|
|
133
|
+
snapshot() {
|
|
134
|
+
return this.plugins.map((plugin) => ({
|
|
135
|
+
name: plugin.name,
|
|
136
|
+
version: plugin.version,
|
|
137
|
+
abi_version: plugin.abi_version,
|
|
138
|
+
toolProviders: (plugin.toolProviders ?? []).map((provider) => ({
|
|
139
|
+
name: provider.name,
|
|
140
|
+
kind: provider.kind,
|
|
141
|
+
idempotent: provider.idempotent,
|
|
142
|
+
})),
|
|
143
|
+
workspaceProviders: (plugin.workspaceProviders ?? []).map((provider) => ({
|
|
144
|
+
name: provider.name,
|
|
145
|
+
})),
|
|
146
|
+
verifierProviders: (plugin.verifierProviders ?? []).map((provider) => ({
|
|
147
|
+
name: provider.name,
|
|
148
|
+
})),
|
|
149
|
+
contextProviders: (plugin.contextProviders ?? []).map((provider) => ({
|
|
150
|
+
name: provider.name,
|
|
151
|
+
})),
|
|
152
|
+
}));
|
|
153
|
+
}
|
|
154
|
+
summary() {
|
|
155
|
+
const plugins = this.list();
|
|
156
|
+
const toolProviders = plugins.reduce((sum, plugin) => sum + plugin.providers.filter((provider) => provider.startsWith('tool:')).length, 0);
|
|
157
|
+
const workspaceProviders = plugins.reduce((sum, plugin) => sum + plugin.providers.filter((provider) => provider.startsWith('workspace:')).length, 0);
|
|
158
|
+
const verifierProviders = plugins.reduce((sum, plugin) => sum + plugin.providers.filter((provider) => provider.startsWith('verifier:')).length, 0);
|
|
159
|
+
const contextProviders = plugins.reduce((sum, plugin) => sum + plugin.providers.filter((provider) => provider.startsWith('context:')).length, 0);
|
|
160
|
+
const loadErrors = this.loadErrors.length;
|
|
161
|
+
return {
|
|
162
|
+
total_plugins: plugins.length,
|
|
163
|
+
tool_providers: toolProviders,
|
|
164
|
+
workspace_providers: workspaceProviders,
|
|
165
|
+
verifier_providers: verifierProviders,
|
|
166
|
+
context_providers: contextProviders,
|
|
167
|
+
load_errors: loadErrors,
|
|
168
|
+
pluginsCount: plugins.length,
|
|
169
|
+
toolProviders,
|
|
170
|
+
workspaceProviders,
|
|
171
|
+
verifierProviders,
|
|
172
|
+
contextProviders,
|
|
173
|
+
loadErrors,
|
|
174
|
+
plugins,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
capabilityMatrix() {
|
|
178
|
+
return (0, capability_matrix_1.buildMatrix)(this);
|
|
179
|
+
}
|
|
104
180
|
}
|
|
105
181
|
exports.PluginRegistry = PluginRegistry;
|
|
106
182
|
let _globalRegistry = null;
|
|
@@ -112,3 +188,9 @@ function globalRegistry() {
|
|
|
112
188
|
function resetGlobalRegistry() {
|
|
113
189
|
_globalRegistry = null;
|
|
114
190
|
}
|
|
191
|
+
function registrySummary(registry) {
|
|
192
|
+
return registry.summary();
|
|
193
|
+
}
|
|
194
|
+
function resolveCapabilityMatrix(registry) {
|
|
195
|
+
return registry.capabilityMatrix();
|
|
196
|
+
}
|
|
@@ -1,12 +1,27 @@
|
|
|
1
1
|
export type PolicyAction = 'allow' | 'deny' | 'require_human_gate';
|
|
2
|
+
export type SideEffectClass = 'read_fs' | 'write_fs' | 'spawn_process' | 'network_call' | 'git_mutation' | 'db_change' | 'secret_access' | 'infra_operation';
|
|
3
|
+
export type AutonomyTier = 'L0' | 'L1' | 'L2' | 'L3';
|
|
2
4
|
export interface PolicyWhenClause {
|
|
3
5
|
tool?: string;
|
|
4
6
|
env?: string;
|
|
5
7
|
kind?: string;
|
|
8
|
+
side_effect_class?: SideEffectClass;
|
|
9
|
+
autonomy_tier?: AutonomyTier;
|
|
6
10
|
}
|
|
7
11
|
export interface PolicyAssertClause {
|
|
8
12
|
diff_within_scope?: boolean;
|
|
9
13
|
}
|
|
14
|
+
export interface NodePolicyConfig {
|
|
15
|
+
max_retries: number;
|
|
16
|
+
mutation_budget?: number;
|
|
17
|
+
autonomy_tier?: AutonomyTier;
|
|
18
|
+
allowed_side_effects?: SideEffectClass[];
|
|
19
|
+
}
|
|
20
|
+
export interface EnvironmentGuardrail {
|
|
21
|
+
protected_paths: string[];
|
|
22
|
+
protected_branches: string[];
|
|
23
|
+
require_human_gate_on: SideEffectClass[];
|
|
24
|
+
}
|
|
10
25
|
export interface PolicyRule {
|
|
11
26
|
id: string;
|
|
12
27
|
when: PolicyWhenClause;
|
|
@@ -19,22 +34,53 @@ export interface PolicyContext {
|
|
|
19
34
|
kind?: string;
|
|
20
35
|
mutation_scope?: string[];
|
|
21
36
|
affected_paths?: string[];
|
|
37
|
+
side_effect_class?: SideEffectClass;
|
|
38
|
+
autonomy_tier?: AutonomyTier;
|
|
39
|
+
mutation_count?: number;
|
|
40
|
+
node_policy?: NodePolicyConfig;
|
|
22
41
|
}
|
|
23
42
|
export interface PolicyDecision {
|
|
43
|
+
decision_id: string;
|
|
24
44
|
allowed: boolean;
|
|
25
45
|
gate_required: boolean;
|
|
26
46
|
reason: string;
|
|
27
47
|
rule_id: string | null;
|
|
48
|
+
timestamp: string;
|
|
49
|
+
}
|
|
50
|
+
export interface PersistedPolicyDecision extends PolicyDecision {
|
|
51
|
+
run_id: string;
|
|
52
|
+
work_item_id: string | null;
|
|
53
|
+
action: string;
|
|
54
|
+
actor: string;
|
|
55
|
+
override: boolean;
|
|
56
|
+
rationale: string | null;
|
|
57
|
+
context: PolicyContext;
|
|
28
58
|
}
|
|
29
59
|
export declare class PolicyEngine {
|
|
30
60
|
private readonly rules;
|
|
31
|
-
|
|
61
|
+
private readonly guardrail;
|
|
62
|
+
constructor(rules?: PolicyRule[], guardrail?: EnvironmentGuardrail);
|
|
32
63
|
evaluate(ctx: PolicyContext): PolicyDecision;
|
|
64
|
+
private checkGuardrails;
|
|
65
|
+
private checkAutonomyTier;
|
|
66
|
+
private checkMutationBudget;
|
|
33
67
|
private matches;
|
|
34
68
|
private checkAssert;
|
|
35
69
|
withRule(rule: PolicyRule): PolicyEngine;
|
|
70
|
+
withGuardrail(guardrail: EnvironmentGuardrail): PolicyEngine;
|
|
71
|
+
getGuardrail(): EnvironmentGuardrail;
|
|
36
72
|
static fromConfig(config: {
|
|
37
73
|
policies?: PolicyRule[];
|
|
74
|
+
guardrail?: EnvironmentGuardrail;
|
|
38
75
|
}): PolicyEngine;
|
|
39
76
|
static fromConfigFile(configPath: string): PolicyEngine;
|
|
77
|
+
static defaultGuardrail(): EnvironmentGuardrail;
|
|
40
78
|
}
|
|
79
|
+
export declare function savePolicyDecision(projectRoot: string, decision: PersistedPolicyDecision): PersistedPolicyDecision;
|
|
80
|
+
export declare function loadPolicyDecisions(projectRoot: string, runId: string): PersistedPolicyDecision[];
|
|
81
|
+
export declare function summarizePolicyDecisions(decisions: PersistedPolicyDecision[]): {
|
|
82
|
+
total: number;
|
|
83
|
+
denied: number;
|
|
84
|
+
gated: number;
|
|
85
|
+
overridesWithoutRationale: number;
|
|
86
|
+
};
|
|
@@ -1,17 +1,53 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.PolicyEngine = void 0;
|
|
7
|
+
exports.savePolicyDecision = savePolicyDecision;
|
|
8
|
+
exports.loadPolicyDecisions = loadPolicyDecisions;
|
|
9
|
+
exports.summarizePolicyDecisions = summarizePolicyDecisions;
|
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
4
12
|
const ALLOW_ALL = {
|
|
13
|
+
decision_id: '__default_allow',
|
|
5
14
|
allowed: true,
|
|
6
15
|
gate_required: false,
|
|
7
16
|
reason: 'no matching policy — default allow',
|
|
8
17
|
rule_id: null,
|
|
18
|
+
timestamp: new Date().toISOString(),
|
|
19
|
+
};
|
|
20
|
+
const DEFAULT_GUARDRAIL = {
|
|
21
|
+
protected_paths: ['.oxe/config.json', '.env', 'package.json'],
|
|
22
|
+
protected_branches: ['main', 'master', 'production', 'release'],
|
|
23
|
+
require_human_gate_on: ['infra_operation', 'db_change', 'secret_access'],
|
|
24
|
+
};
|
|
25
|
+
// Autonomy tier → max side effect class allowed without a gate
|
|
26
|
+
const TIER_SIDE_EFFECT_MAP = {
|
|
27
|
+
L0: ['read_fs'],
|
|
28
|
+
L1: ['read_fs', 'write_fs', 'spawn_process'],
|
|
29
|
+
L2: ['read_fs', 'write_fs', 'spawn_process', 'network_call', 'git_mutation'],
|
|
30
|
+
L3: ['read_fs', 'write_fs', 'spawn_process', 'network_call', 'git_mutation', 'db_change', 'secret_access', 'infra_operation'],
|
|
9
31
|
};
|
|
10
32
|
class PolicyEngine {
|
|
11
|
-
constructor(rules = []) {
|
|
33
|
+
constructor(rules = [], guardrail = DEFAULT_GUARDRAIL) {
|
|
12
34
|
this.rules = rules;
|
|
35
|
+
this.guardrail = guardrail;
|
|
13
36
|
}
|
|
14
37
|
evaluate(ctx) {
|
|
38
|
+
// Check autonomy tier first — a denial takes priority over guardrail gates
|
|
39
|
+
const tierDecision = this.checkAutonomyTier(ctx);
|
|
40
|
+
if (tierDecision)
|
|
41
|
+
return tierDecision;
|
|
42
|
+
// Check environment guardrails (may require gate even when tier permits)
|
|
43
|
+
const guardrailDecision = this.checkGuardrails(ctx);
|
|
44
|
+
if (guardrailDecision)
|
|
45
|
+
return guardrailDecision;
|
|
46
|
+
// Check mutation budget
|
|
47
|
+
const budgetDecision = this.checkMutationBudget(ctx);
|
|
48
|
+
if (budgetDecision)
|
|
49
|
+
return budgetDecision;
|
|
50
|
+
// Evaluate rules (first match wins)
|
|
15
51
|
for (const rule of this.rules) {
|
|
16
52
|
if (!this.matches(rule.when, ctx))
|
|
17
53
|
continue;
|
|
@@ -19,23 +55,107 @@ class PolicyEngine {
|
|
|
19
55
|
const assertFailed = this.checkAssert(rule.assert, ctx);
|
|
20
56
|
if (assertFailed) {
|
|
21
57
|
return {
|
|
58
|
+
decision_id: rule.id,
|
|
22
59
|
allowed: false,
|
|
23
60
|
gate_required: false,
|
|
24
61
|
reason: `Assert failed for rule ${rule.id}: ${assertFailed}`,
|
|
25
62
|
rule_id: rule.id,
|
|
63
|
+
timestamp: new Date().toISOString(),
|
|
26
64
|
};
|
|
27
65
|
}
|
|
28
66
|
}
|
|
29
67
|
switch (rule.action) {
|
|
30
68
|
case 'allow':
|
|
31
|
-
return {
|
|
69
|
+
return {
|
|
70
|
+
decision_id: rule.id,
|
|
71
|
+
allowed: true,
|
|
72
|
+
gate_required: false,
|
|
73
|
+
reason: `Allowed by rule ${rule.id}`,
|
|
74
|
+
rule_id: rule.id,
|
|
75
|
+
timestamp: new Date().toISOString(),
|
|
76
|
+
};
|
|
32
77
|
case 'deny':
|
|
33
|
-
return {
|
|
78
|
+
return {
|
|
79
|
+
decision_id: rule.id,
|
|
80
|
+
allowed: false,
|
|
81
|
+
gate_required: false,
|
|
82
|
+
reason: `Denied by rule ${rule.id}`,
|
|
83
|
+
rule_id: rule.id,
|
|
84
|
+
timestamp: new Date().toISOString(),
|
|
85
|
+
};
|
|
34
86
|
case 'require_human_gate':
|
|
35
|
-
return {
|
|
87
|
+
return {
|
|
88
|
+
decision_id: rule.id,
|
|
89
|
+
allowed: true,
|
|
90
|
+
gate_required: true,
|
|
91
|
+
reason: `Gate required by rule ${rule.id}`,
|
|
92
|
+
rule_id: rule.id,
|
|
93
|
+
timestamp: new Date().toISOString(),
|
|
94
|
+
};
|
|
36
95
|
}
|
|
37
96
|
}
|
|
38
|
-
return ALLOW_ALL;
|
|
97
|
+
return { ...ALLOW_ALL, timestamp: new Date().toISOString() };
|
|
98
|
+
}
|
|
99
|
+
checkGuardrails(ctx) {
|
|
100
|
+
// Protected path check
|
|
101
|
+
const affected = ctx.affected_paths ?? [];
|
|
102
|
+
for (const p of affected) {
|
|
103
|
+
if (this.guardrail.protected_paths.some((pp) => p === pp || p.startsWith(pp + '/'))) {
|
|
104
|
+
return {
|
|
105
|
+
decision_id: '__guardrail_path',
|
|
106
|
+
allowed: true,
|
|
107
|
+
gate_required: true,
|
|
108
|
+
reason: `Protected path affected: ${p}`,
|
|
109
|
+
rule_id: '__guardrail_path',
|
|
110
|
+
timestamp: new Date().toISOString(),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Side effect class requiring gate
|
|
115
|
+
if (ctx.side_effect_class && this.guardrail.require_human_gate_on.includes(ctx.side_effect_class)) {
|
|
116
|
+
return {
|
|
117
|
+
decision_id: '__guardrail_side_effect',
|
|
118
|
+
allowed: true,
|
|
119
|
+
gate_required: true,
|
|
120
|
+
reason: `Side effect class '${ctx.side_effect_class}' requires human gate`,
|
|
121
|
+
rule_id: '__guardrail_side_effect',
|
|
122
|
+
timestamp: new Date().toISOString(),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
checkAutonomyTier(ctx) {
|
|
128
|
+
if (!ctx.autonomy_tier || !ctx.side_effect_class)
|
|
129
|
+
return null;
|
|
130
|
+
const allowed = TIER_SIDE_EFFECT_MAP[ctx.autonomy_tier] ?? [];
|
|
131
|
+
if (!allowed.includes(ctx.side_effect_class)) {
|
|
132
|
+
return {
|
|
133
|
+
decision_id: '__autonomy_tier',
|
|
134
|
+
allowed: false,
|
|
135
|
+
gate_required: false,
|
|
136
|
+
reason: `Autonomy tier ${ctx.autonomy_tier} does not permit side effect '${ctx.side_effect_class}'`,
|
|
137
|
+
rule_id: '__autonomy_tier',
|
|
138
|
+
timestamp: new Date().toISOString(),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
checkMutationBudget(ctx) {
|
|
144
|
+
const budget = ctx.node_policy?.mutation_budget;
|
|
145
|
+
if (budget === undefined || budget === null)
|
|
146
|
+
return null;
|
|
147
|
+
const count = ctx.mutation_count ?? 0;
|
|
148
|
+
if (count >= budget) {
|
|
149
|
+
return {
|
|
150
|
+
decision_id: '__mutation_budget',
|
|
151
|
+
allowed: false,
|
|
152
|
+
gate_required: false,
|
|
153
|
+
reason: `Mutation budget exhausted: ${count}/${budget}`,
|
|
154
|
+
rule_id: '__mutation_budget',
|
|
155
|
+
timestamp: new Date().toISOString(),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
39
159
|
}
|
|
40
160
|
matches(when, ctx) {
|
|
41
161
|
if (when.tool && when.tool !== ctx.tool)
|
|
@@ -44,6 +164,10 @@ class PolicyEngine {
|
|
|
44
164
|
return false;
|
|
45
165
|
if (when.kind && when.kind !== ctx.kind)
|
|
46
166
|
return false;
|
|
167
|
+
if (when.side_effect_class && when.side_effect_class !== ctx.side_effect_class)
|
|
168
|
+
return false;
|
|
169
|
+
if (when.autonomy_tier && when.autonomy_tier !== ctx.autonomy_tier)
|
|
170
|
+
return false;
|
|
47
171
|
return true;
|
|
48
172
|
}
|
|
49
173
|
checkAssert(assert, ctx) {
|
|
@@ -51,7 +175,7 @@ class PolicyEngine {
|
|
|
51
175
|
const scope = ctx.mutation_scope ?? [];
|
|
52
176
|
const affected = ctx.affected_paths ?? [];
|
|
53
177
|
if (scope.length === 0)
|
|
54
|
-
return null;
|
|
178
|
+
return null;
|
|
55
179
|
const outsideScope = affected.filter((p) => !scope.some((s) => p.startsWith(s) || s.startsWith(p)));
|
|
56
180
|
if (outsideScope.length > 0) {
|
|
57
181
|
return `paths outside mutation scope: ${outsideScope.join(', ')}`;
|
|
@@ -60,14 +184,19 @@ class PolicyEngine {
|
|
|
60
184
|
return null;
|
|
61
185
|
}
|
|
62
186
|
withRule(rule) {
|
|
63
|
-
return new PolicyEngine([...this.rules, rule]);
|
|
187
|
+
return new PolicyEngine([...this.rules, rule], this.guardrail);
|
|
188
|
+
}
|
|
189
|
+
withGuardrail(guardrail) {
|
|
190
|
+
return new PolicyEngine(this.rules, guardrail);
|
|
191
|
+
}
|
|
192
|
+
getGuardrail() {
|
|
193
|
+
return this.guardrail;
|
|
64
194
|
}
|
|
65
195
|
static fromConfig(config) {
|
|
66
|
-
return new PolicyEngine(config.policies ?? []);
|
|
196
|
+
return new PolicyEngine(config.policies ?? [], config.guardrail ?? DEFAULT_GUARDRAIL);
|
|
67
197
|
}
|
|
68
198
|
static fromConfigFile(configPath) {
|
|
69
199
|
try {
|
|
70
|
-
// Dynamic require to avoid bundling issues
|
|
71
200
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
72
201
|
const cfg = require(configPath);
|
|
73
202
|
return PolicyEngine.fromConfig(cfg);
|
|
@@ -76,5 +205,39 @@ class PolicyEngine {
|
|
|
76
205
|
return new PolicyEngine();
|
|
77
206
|
}
|
|
78
207
|
}
|
|
208
|
+
static defaultGuardrail() {
|
|
209
|
+
return { ...DEFAULT_GUARDRAIL };
|
|
210
|
+
}
|
|
79
211
|
}
|
|
80
212
|
exports.PolicyEngine = PolicyEngine;
|
|
213
|
+
function policyDecisionPath(projectRoot, runId) {
|
|
214
|
+
return path_1.default.join(projectRoot, '.oxe', 'runs', runId, 'policy-decisions.json');
|
|
215
|
+
}
|
|
216
|
+
function savePolicyDecision(projectRoot, decision) {
|
|
217
|
+
const target = policyDecisionPath(projectRoot, decision.run_id);
|
|
218
|
+
fs_1.default.mkdirSync(path_1.default.dirname(target), { recursive: true });
|
|
219
|
+
const existing = loadPolicyDecisions(projectRoot, decision.run_id);
|
|
220
|
+
const next = [...existing.filter((item) => item.decision_id !== decision.decision_id), decision];
|
|
221
|
+
fs_1.default.writeFileSync(target, JSON.stringify(next, null, 2), 'utf8');
|
|
222
|
+
return decision;
|
|
223
|
+
}
|
|
224
|
+
function loadPolicyDecisions(projectRoot, runId) {
|
|
225
|
+
const target = policyDecisionPath(projectRoot, runId);
|
|
226
|
+
if (!fs_1.default.existsSync(target))
|
|
227
|
+
return [];
|
|
228
|
+
try {
|
|
229
|
+
const raw = JSON.parse(fs_1.default.readFileSync(target, 'utf8'));
|
|
230
|
+
return Array.isArray(raw) ? raw : [];
|
|
231
|
+
}
|
|
232
|
+
catch {
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
function summarizePolicyDecisions(decisions) {
|
|
237
|
+
return {
|
|
238
|
+
total: decisions.length,
|
|
239
|
+
denied: decisions.filter((decision) => !decision.allowed).length,
|
|
240
|
+
gated: decisions.filter((decision) => decision.gate_required).length,
|
|
241
|
+
overridesWithoutRationale: decisions.filter((decision) => decision.override && !decision.rationale).length,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
@@ -2,10 +2,18 @@ import type { RunState } from '../reducers/run-state-reducer';
|
|
|
2
2
|
import type { ExecutionGraph } from '../compiler/graph-compiler';
|
|
3
3
|
import type { VerificationResult } from '../models/verification-result';
|
|
4
4
|
import type { CheckResult } from '../verification/verification-compiler';
|
|
5
|
+
import type { VerificationManifest, ResidualRiskLedger } from '../verification/verification-manifest';
|
|
5
6
|
export declare class ProjectionEngine {
|
|
6
7
|
projectPlan(state: RunState, graph: ExecutionGraph): string;
|
|
7
|
-
projectVerify(state: RunState, results: VerificationResult[], checkResults?: CheckResult[]
|
|
8
|
+
projectVerify(state: RunState, results: VerificationResult[], checkResults?: CheckResult[], manifest?: VerificationManifest | null, riskLedger?: ResidualRiskLedger | null, evidenceCoverage?: {
|
|
9
|
+
total_checks: number;
|
|
10
|
+
checks_with_evidence: number;
|
|
11
|
+
total_evidence_refs: number;
|
|
12
|
+
coverage_percent: number;
|
|
13
|
+
} | null): string;
|
|
8
14
|
projectState(state: RunState): string;
|
|
9
15
|
projectRunSummary(state: RunState): string;
|
|
10
16
|
projectPRSummary(state: RunState, graph: ExecutionGraph): string;
|
|
17
|
+
projectCommitSummary(state: RunState, graph: ExecutionGraph): string;
|
|
18
|
+
projectPromotionSummary(state: RunState, graph: ExecutionGraph): string;
|
|
11
19
|
}
|