0xray 3.5.4 → 3.5.5
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/.xray/features.json +5 -1
- package/.xray/features.schema.json +56 -0
- package/AGENTS-consumer.md +1 -1
- package/AGENTS.md +11 -1
- package/README.md +1 -1
- package/SKILLS.md +1 -1
- package/dist/AGENTS.md +11 -1
- package/dist/CHANGELOG.md +44 -0
- package/dist/README.md +1 -1
- package/dist/SKILLS.md +1 -1
- package/dist/cli/commands/hermes-install.js +3 -1
- package/dist/cli/index.js +0 -0
- package/dist/core/features-config.d.ts +15 -0
- package/dist/governance/governance-service.d.ts +1 -0
- package/dist/governance/governance-service.js +81 -6
- package/dist/integrations/enforcement-gate.js +15 -5
- package/dist/integrations/grok/grok-cli.js +1 -10
- package/dist/integrations/grok/hooks/grok-hook-utils.js +46 -2
- package/dist/integrations/grok/hooks/post-tool-use.js +21 -0
- package/dist/integrations/grok/hooks/pre-tool-use.js +20 -0
- package/dist/integrations/grok/hooks/session-start.js +28 -0
- package/dist/integrations/hermes-agent/__init__.py +11 -1
- package/dist/integrations/hermes-agent/__pycache__/__init__.cpython-313.pyc +0 -0
- package/dist/integrations/hermes-agent/__pycache__/schemas.cpython-313.pyc +0 -0
- package/dist/integrations/hermes-agent/__pycache__/tools.cpython-313.pyc +0 -0
- package/dist/integrations/hermes-agent/bridge.mjs +73 -10
- package/dist/integrations/hooks/confer-hook-runtime.mjs +49 -0
- package/dist/integrations/hooks/pipeline-hook-runtime.mjs +211 -0
- package/dist/integrations/hooks/plan-hook-runtime.mjs +68 -0
- package/dist/integrations/hooks/user-aside-hook-runtime.mjs +49 -0
- package/dist/mcps/architect-tools.server.js +6 -1
- package/dist/mcps/orchestrator/handlers/complexity-handler.d.ts +7 -0
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +106 -7
- package/dist/mcps/orchestrator/handlers/task-handler.d.ts +6 -0
- package/dist/mcps/orchestrator/handlers/task-handler.js +75 -0
- package/dist/mcps/orchestrator/server.js +54 -5
- package/dist/memory-routing/provider-loader.js +30 -2
- package/dist/nucleus/aside-worktree.d.ts +41 -0
- package/dist/nucleus/aside-worktree.js +164 -0
- package/dist/nucleus/confer.d.ts +57 -0
- package/dist/nucleus/confer.js +308 -0
- package/dist/nucleus/delegation-gate.d.ts +4 -0
- package/dist/nucleus/delegation-gate.js +90 -11
- package/dist/nucleus/lead-dev-plan-persistence.d.ts +27 -3
- package/dist/nucleus/lead-dev-plan-persistence.js +201 -19
- package/dist/nucleus/spawn-plan-resolution.d.ts +20 -0
- package/dist/nucleus/spawn-plan-resolution.js +42 -0
- package/dist/nucleus/synthesis-consult-receipt.js +18 -2
- package/dist/nucleus/synthesis-context.js +1 -1
- package/dist/nucleus/user-aside.d.ts +70 -0
- package/dist/nucleus/user-aside.js +393 -0
- package/dist/postprocessor/PostProcessor.d.ts +1 -0
- package/dist/postprocessor/PostProcessor.js +11 -0
- package/dist/processors/implementations/session-summary-processor.d.ts +1 -1
- package/dist/processors/implementations/session-summary-processor.js +9 -6
- package/package.json +14 -5
- package/scripts/hooks/install-hooks.cjs +3 -3
- package/scripts/hooks/run-hook.js +171 -86
- package/scripts/mjs/verify-confer-core.mjs +103 -0
- package/scripts/mjs/verify-delegation-gate-core.mjs +48 -2
- package/scripts/mjs/verify-hermes-session-start.mjs +137 -0
- package/scripts/mjs/verify-pre-push-diff-core.mjs +87 -0
- package/scripts/mjs/verify-user-aside-core.mjs +137 -0
- package/scripts/node/bridge-mcp-wiring.cjs +10 -0
- package/scripts/node/install-bridges.cjs +3 -11
- package/scripts/node/load-reflection-config.mjs +2 -2
- package/scripts/node/release-gate.mjs +8 -4
- package/src/mcps/architect-tools.server.ts +6 -1
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +178 -20
- package/src/mcps/orchestrator/handlers/task-handler.ts +99 -0
- package/src/mcps/orchestrator/server.ts +56 -5
- package/xray/features.json +5 -1
- package/xray/features.schema.json +56 -0
package/.xray/features.json
CHANGED
|
@@ -36,7 +36,11 @@
|
|
|
36
36
|
"phased_plan_threshold": 25,
|
|
37
37
|
"auto_consult_major_work": true,
|
|
38
38
|
"no_new_surface": true,
|
|
39
|
-
"auto_chain_delegations": true
|
|
39
|
+
"auto_chain_delegations": true,
|
|
40
|
+
"user_asides": {
|
|
41
|
+
"enabled": true,
|
|
42
|
+
"auto_provision_worktree": false
|
|
43
|
+
}
|
|
40
44
|
},
|
|
41
45
|
"autonomous_reporting": {
|
|
42
46
|
"enabled": true,
|
|
@@ -28,6 +28,62 @@
|
|
|
28
28
|
"required": ["module_path"]
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
|
+
"multi_agent_orchestration": {
|
|
32
|
+
"type": "object",
|
|
33
|
+
"properties": {
|
|
34
|
+
"enabled": { "type": "boolean" },
|
|
35
|
+
"lead_dev_mode": { "type": "boolean" },
|
|
36
|
+
"plan_stale_hours": {
|
|
37
|
+
"type": "number",
|
|
38
|
+
"minimum": 1,
|
|
39
|
+
"description": "Archive lead-dev-plan when all todos still pending after N hours"
|
|
40
|
+
},
|
|
41
|
+
"plan_archive_marker_hours": {
|
|
42
|
+
"type": "number",
|
|
43
|
+
"minimum": 1,
|
|
44
|
+
"description": "How long spawn-plan-stale persists after a stale plan was archived (hours)"
|
|
45
|
+
},
|
|
46
|
+
"confer_on_synthesis": {
|
|
47
|
+
"type": "boolean",
|
|
48
|
+
"description": "Auto-run 3-agent confer quorum at synthesis checkpoint (default true)"
|
|
49
|
+
},
|
|
50
|
+
"confer": {
|
|
51
|
+
"type": "object",
|
|
52
|
+
"properties": {
|
|
53
|
+
"enabled": { "type": "boolean" },
|
|
54
|
+
"on_synthesis": { "type": "boolean" }
|
|
55
|
+
},
|
|
56
|
+
"description": "Mandatory researcher/architect-tools/code-review quorum"
|
|
57
|
+
},
|
|
58
|
+
"sibling_repos": {
|
|
59
|
+
"type": "array",
|
|
60
|
+
"items": {
|
|
61
|
+
"oneOf": [
|
|
62
|
+
{ "type": "string" },
|
|
63
|
+
{
|
|
64
|
+
"type": "object",
|
|
65
|
+
"properties": {
|
|
66
|
+
"path": { "type": "string" },
|
|
67
|
+
"label": { "type": "string" }
|
|
68
|
+
},
|
|
69
|
+
"required": ["path"]
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"description": "Sibling workspace roots (e.g. UI repo when MCP host is cwd)"
|
|
74
|
+
},
|
|
75
|
+
"user_asides": {
|
|
76
|
+
"type": "object",
|
|
77
|
+
"properties": {
|
|
78
|
+
"enabled": { "type": "boolean" },
|
|
79
|
+
"auto_provision_worktree": {
|
|
80
|
+
"type": "boolean",
|
|
81
|
+
"description": "Run guarded git worktree add on analyze-complexity aside intake when worktree+branch set"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
31
87
|
"synthesis": {
|
|
32
88
|
"type": "object",
|
|
33
89
|
"properties": {
|
package/AGENTS-consumer.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Quick reference for the 0xRay AI orchestration framework (shipped to your project on `npm install 0xray`).
|
|
6
6
|
|
|
7
|
-
**v3.5.
|
|
7
|
+
**v3.5.5** — 7 MCP servers · 45 skills · 68 codex terms · 4 platform bridges
|
|
8
8
|
|
|
9
9
|
## Postinstall (automatic)
|
|
10
10
|
|
package/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# xray Agents
|
|
2
2
|
|
|
3
|
-
Quick reference for the xray AI orchestration framework (**v3.5.
|
|
3
|
+
Quick reference for the xray AI orchestration framework (**v3.5.5**).
|
|
4
4
|
|
|
5
5
|
**42 agents** · **45 skills** · **7 consumer MCP servers** · **68 codex terms** · **3,226 tests**
|
|
6
6
|
|
|
@@ -77,6 +77,16 @@ Governance deliberation: **code-review**, **security-audit**, **researcher** wit
|
|
|
77
77
|
- Observation extractors: governance, orchestration, complexity
|
|
78
78
|
- Repertoire context flows via `ExecutionPlan.memoryContext`
|
|
79
79
|
|
|
80
|
+
## User asides (parallel work tracks)
|
|
81
|
+
|
|
82
|
+
**Not** AsideContext — user-declared parallel tracks (worktree-like):
|
|
83
|
+
|
|
84
|
+
- SSOT: `.xray/state/asides/{id}.json` + `_active.json`; todos use `{asideId}.a.*` (namespaced)
|
|
85
|
+
- Intake: `analyze-complexity` with `userAsideId` (+ optional `worktree`, `branch`)
|
|
86
|
+
- Activate / resume main: `orchestrate-task` with `userAsideId` or `clearActiveAside: true`
|
|
87
|
+
- Spawn gate routes to active aside plan; session-boot exposes `activeAside`
|
|
88
|
+
- Config: `features.json` → `multi_agent_orchestration.user_asides.enabled`
|
|
89
|
+
|
|
80
90
|
## Confidence gate (v3.3.1)
|
|
81
91
|
|
|
82
92
|
`ExecutionPlanner.calculateTaskComplexity()` + `getTaskConfidence()` — complexity boost and ontological-trap routing.
|
package/README.md
CHANGED
package/SKILLS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 0xray Skills
|
|
2
2
|
|
|
3
|
-
**v3.5.
|
|
3
|
+
**v3.5.5** — **45 skills** · invoked via `xray-skills` MCP · synced on postinstall
|
|
4
4
|
|
|
5
5
|
xray ships 45 knowledge skills (`src/skills/<name>/SKILL.md`) across the full software lifecycle. Lead-dev operating model lives in **`orchestrator`** skill + `multi_agent_orchestration.lead_dev_mode` in features.json. Skills load on demand via the **xray-skills** MCP server (`npx -y 0xray mcp skills`), agent `@mentions`, or platform skill directories after postinstall.
|
|
6
6
|
|
package/dist/AGENTS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# xray Agents
|
|
2
2
|
|
|
3
|
-
Quick reference for the xray AI orchestration framework (**v3.5.
|
|
3
|
+
Quick reference for the xray AI orchestration framework (**v3.5.5**).
|
|
4
4
|
|
|
5
5
|
**42 agents** · **45 skills** · **7 consumer MCP servers** · **68 codex terms** · **3,226 tests**
|
|
6
6
|
|
|
@@ -77,6 +77,16 @@ Governance deliberation: **code-review**, **security-audit**, **researcher** wit
|
|
|
77
77
|
- Observation extractors: governance, orchestration, complexity
|
|
78
78
|
- Repertoire context flows via `ExecutionPlan.memoryContext`
|
|
79
79
|
|
|
80
|
+
## User asides (parallel work tracks)
|
|
81
|
+
|
|
82
|
+
**Not** AsideContext — user-declared parallel tracks (worktree-like):
|
|
83
|
+
|
|
84
|
+
- SSOT: `.xray/state/asides/{id}.json` + `_active.json`; todos use `{asideId}.a.*` (namespaced)
|
|
85
|
+
- Intake: `analyze-complexity` with `userAsideId` (+ optional `worktree`, `branch`)
|
|
86
|
+
- Activate / resume main: `orchestrate-task` with `userAsideId` or `clearActiveAside: true`
|
|
87
|
+
- Spawn gate routes to active aside plan; session-boot exposes `activeAside`
|
|
88
|
+
- Config: `features.json` → `multi_agent_orchestration.user_asides.enabled`
|
|
89
|
+
|
|
80
90
|
## Confidence gate (v3.3.1)
|
|
81
91
|
|
|
82
92
|
`ExecutionPlanner.calculateTaskComplexity()` + `getTaskConfidence()` — complexity boost and ontological-trap routing.
|
package/dist/CHANGELOG.md
CHANGED
|
@@ -4,13 +4,57 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Conventional Commits](https://www.conventionalcommits.org/).
|
|
6
6
|
|
|
7
|
+
## [3.5.5] - 2026-06-20
|
|
8
|
+
|
|
9
|
+
### ✨ Features
|
|
10
|
+
- **User-asides P0** — PreToolUse **denies** aside spawns without `cwd` / `working_directory` matching `aside.worktree`; `aside-worktree.ts` SSOT; synthesis-gate parity
|
|
11
|
+
- **Worktree auto-provision** — `analyze-complexity` runs guarded `git worktree add` when `user_asides.auto_provision_worktree: true`
|
|
12
|
+
- **Pipeline P3** — `verify:pipeline-facets` script; consumer `confirm:suit:full --pipeline-audit` wiring
|
|
13
|
+
|
|
14
|
+
### 🐛 Fixes
|
|
15
|
+
- **Worktree cwd enforce** — `auto_chain_delegations: false` no longer bypasses aside worktree cwd check; synthesis-gate parity retained
|
|
16
|
+
- **`isAutoProvisionWorktreeEnabled`** — requires `user_asides.enabled` before honoring `auto_provision_worktree`
|
|
17
|
+
- **`provisionGitWorktree`** — macOS `/var` vs `/private/var` path resolution for idempotent worktree detection
|
|
18
|
+
|
|
19
|
+
### 🔄 Changes
|
|
20
|
+
- **`verify:pipeline-facets --package-only`** — release-gate probes shipped artifacts without consumer feature matrix
|
|
21
|
+
- **`release-gate.mjs`** — wires pipeline facet verify (package-only mode)
|
|
22
|
+
|
|
23
|
+
### ✅ Tests
|
|
24
|
+
- `aside-worktree.test.ts`; delegation-gate cwd deny/allow; auto_chain-off + synthesis worktree deny; `provisionGitWorktree` guards; `verify-user-aside-core` 10/10
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
7
28
|
## [3.5.4] - 2026-06-19
|
|
8
29
|
|
|
9
30
|
### ✨ Features
|
|
10
31
|
- **Synthesis consult receipt gate** — s.1–s.3 todos require `.xray/state/synthesis-consult-{id}.json` before completion; `evaluatePostToolSpawn` records receipts from subagent output; Grok post-tool hook wired
|
|
32
|
+
- **User asides** — parallel work tracks (worktree-like) via `.xray/state/asides/{id}.json`; namespaced `{asideId}.a.*` todo routing; `analyze-complexity` + `orchestrate-task` rewire (no new MCP); session-boot hints; synthesis/pending bypass for aside spawns; `verify:user-aside` 9/9; docs `guides/user-asides.md`
|
|
33
|
+
- **Confer quorum** — `confer.ts` SSOT; auto-runs at synthesis `analyze-complexity` (researcher → architect-tools → code-review); `verify:confer` 7/7; config `confer_on_synthesis` (default true); session-boot `conferPending` hint; emoji agent panel in quorum report
|
|
34
|
+
- **Pipeline integration (P0–P2)** — enforcement-gate `{ proposals: [...] }` shape; `applyDecisionMatrix` + `calculateMetamorphosisScore` in `GovernanceService`; Grok `pipeline-hook-runtime.mjs` (reflection stubs, routing outcomes, reporting, inference-improvement light); `SelfProposalEngine` wired in PostProcessor; aside worktree cwd warn in delegation-gate; `autonomous_reporting` config key fix in SessionSummaryProcessor
|
|
35
|
+
- **Stale lead-dev plan** — archive after `plan_stale_hours`; `spawn-plan-stale` persists after archival via recent archive marker; synthesis realignment (s.1–s.3) exempt until consult todos complete
|
|
36
|
+
- **Hermes session-start parity** — `bridge.mjs` `session-start` command archives stale plans; lazy `plan-hook-runtime.mjs`; `verify-hermes-session-start.mjs` (4/4)
|
|
37
|
+
- **Pre-commit / pre-push codex** — diff-hunk and commit-range scope verifiers (`verify:pre-commit-diff`, `verify:pre-push-diff`)
|
|
38
|
+
- **Reflection noise** — minimal defaults 50 commits / `autoGenerate: false`; shell fallbacks synced
|
|
39
|
+
- **Multi-repo boot** — `sibling_repos` in `session-boot.json`
|
|
40
|
+
|
|
41
|
+
### 🔄 Changes
|
|
42
|
+
- **autonomy-command.md** — SSOT is `analyze-complexity` + `multi_agent_orchestration`; removed stale `autonomy-intake` / `autonomy_kernel` references
|
|
11
43
|
|
|
12
44
|
### ✅ Tests
|
|
13
45
|
- `synthesis-consult-receipt.test.ts`; E2E/outcome verifiers write fixture receipts
|
|
46
|
+
- `governance-service-metamorphosis.test.ts`; `confer.test.ts` emoji panel
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## [Unreleased]
|
|
51
|
+
|
|
52
|
+
### Planned (iterate before next release)
|
|
53
|
+
- **Configurable archive marker** — `plan_archive_marker_hours` controls `spawn-plan-stale` persistence after archival
|
|
54
|
+
- **Verifier coverage** — `spawn-plan-stale` in `verify-delegation-gate-core` (5/5); wired into `release-gate`
|
|
55
|
+
- **Post-commit log maintenance** — consumer path fix (`node_modules/0xray/dist`)
|
|
56
|
+
- **grok_postprocessor_light** — opt-in marker + activity.log on Grok write tools (full PP subset deferred)
|
|
57
|
+
- **P2 session capture** — git post-commit → `captureSessionInference` when threshold met
|
|
14
58
|
|
|
15
59
|
---
|
|
16
60
|
|
package/dist/README.md
CHANGED
package/dist/SKILLS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 0xray Skills
|
|
2
2
|
|
|
3
|
-
**v3.5.
|
|
3
|
+
**v3.5.5** — **45 skills** · invoked via `xray-skills` MCP · synced on postinstall
|
|
4
4
|
|
|
5
5
|
xray ships 45 knowledge skills (`src/skills/<name>/SKILL.md`) across the full software lifecycle. Lead-dev operating model lives in **`orchestrator`** skill + `multi_agent_orchestration.lead_dev_mode` in features.json. Skills load on demand via the **xray-skills** MCP server (`npx -y 0xray mcp skills`), agent `@mentions`, or platform skill directories after postinstall.
|
|
6
6
|
|
|
@@ -6,7 +6,8 @@ import { frameworkLogger } from '../../core/framework-logger.js';
|
|
|
6
6
|
import { syncBuiltinSkills } from './skill-install.js';
|
|
7
7
|
const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
|
8
8
|
const require = createRequire(import.meta.url);
|
|
9
|
-
const
|
|
9
|
+
const packageRoot = path.join(__dirname, '..', '..', '..');
|
|
10
|
+
const wiring = require(path.join(packageRoot, 'scripts', 'node', 'bridge-mcp-wiring.cjs'));
|
|
10
11
|
export function registerHermesCommands(hermesCmd) {
|
|
11
12
|
hermesCmd
|
|
12
13
|
.command('install')
|
|
@@ -62,6 +63,7 @@ async function installForHermes(options = {}) {
|
|
|
62
63
|
}
|
|
63
64
|
frameworkLogger.log('hermes-integration', 'skills-synced', 'info', { count: skillsCopied });
|
|
64
65
|
}
|
|
66
|
+
wiring.copyHermesFindProjectRootHelper(packageRoot, targetPluginDir);
|
|
65
67
|
const wired = wiring.wireHermesBridge(targetDir);
|
|
66
68
|
console.log(`\x1b[32m✓ Wired Hermes mcp_servers (${wired.count} servers)\x1b[0m`);
|
|
67
69
|
console.log(`\x1b[32m✓ Consumer root → ${targetDir}\x1b[0m`);
|
package/dist/cli/index.js
CHANGED
|
File without changes
|
|
@@ -65,6 +65,21 @@ export interface MultiAgentOrchestrationConfig {
|
|
|
65
65
|
no_new_surface?: boolean;
|
|
66
66
|
/** 3.5.0 — PreToolUse gate after delegate-deferred (default true when lead_dev_mode) */
|
|
67
67
|
auto_chain_delegations?: boolean;
|
|
68
|
+
/** Hours before unstarted lead-dev plan is archived (default 8) */
|
|
69
|
+
plan_stale_hours?: number;
|
|
70
|
+
/** Hours spawn-plan-stale persists after archival (default 24) */
|
|
71
|
+
plan_archive_marker_hours?: number;
|
|
72
|
+
/** Sibling workspace roots for multi-repo session boot metadata */
|
|
73
|
+
sibling_repos?: Array<string | {
|
|
74
|
+
path: string;
|
|
75
|
+
label?: string;
|
|
76
|
+
}>;
|
|
77
|
+
/** Auto-run 3-agent confer at synthesis checkpoint */
|
|
78
|
+
confer_on_synthesis?: boolean;
|
|
79
|
+
confer?: {
|
|
80
|
+
enabled?: boolean;
|
|
81
|
+
on_synthesis?: boolean;
|
|
82
|
+
};
|
|
68
83
|
}
|
|
69
84
|
/** Reflection triggers merged from legacy auto_reflection when synthesis is configured */
|
|
70
85
|
export interface SynthesisReflectionConfig {
|
|
@@ -29,6 +29,7 @@ export declare class GovernanceService {
|
|
|
29
29
|
* Dynamo Solar SSOT is treated as a hard requirement by default.
|
|
30
30
|
*/
|
|
31
31
|
govern(request: GovernanceRequest): Promise<GovernanceResponse>;
|
|
32
|
+
private resolveRequireExternalDynamo;
|
|
32
33
|
private runGovernanceWithTimeout;
|
|
33
34
|
private callSkillServer;
|
|
34
35
|
private callExternalDynamo;
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
import { mcpClientManager } from '../mcps/mcp-client.js';
|
|
19
19
|
import { callInProcessSkill } from '../mcps/in-process-skill-registry.js';
|
|
20
20
|
import { getGovernanceIntegration, } from '../integrations/governance/index.js';
|
|
21
|
-
import { mergeVotes } from './governance-core.js';
|
|
21
|
+
import { applyDecisionMatrix, calculateMetamorphosisScore, mergeVotes, } from './governance-core.js';
|
|
22
22
|
import { frameworkLogger } from '../core/framework-logger.js';
|
|
23
|
+
import { featuresConfigLoader } from '../core/features-config.js';
|
|
23
24
|
export class GovernanceService {
|
|
24
25
|
constructor() {
|
|
25
26
|
// We deliberately do *not* cache the integration here.
|
|
@@ -39,7 +40,7 @@ export class GovernanceService {
|
|
|
39
40
|
*/
|
|
40
41
|
async govern(request) {
|
|
41
42
|
const { proposals, context, options } = request;
|
|
42
|
-
const requireExternal = options?.requireExternalDynamo
|
|
43
|
+
const requireExternal = this.resolveRequireExternalDynamo(options?.requireExternalDynamo);
|
|
43
44
|
const timeoutMs = options?.timeoutMs ?? 90000;
|
|
44
45
|
const maxAbstentionThreshold = options?.maxAbstentionThreshold ?? 1.0;
|
|
45
46
|
frameworkLogger.log('governance-service', 'govern-start', 'info', {
|
|
@@ -59,7 +60,7 @@ export class GovernanceService {
|
|
|
59
60
|
}
|
|
60
61
|
}
|
|
61
62
|
// Run governance with end-to-end timeout
|
|
62
|
-
const result = await this.runGovernanceWithTimeout(proposals, context, requireExternal, timeoutMs);
|
|
63
|
+
const result = await this.runGovernanceWithTimeout(proposals, context, requireExternal, timeoutMs, options?.metamorphosisThreshold);
|
|
63
64
|
// Check abstention threshold
|
|
64
65
|
if (result.results.length > 0 && maxAbstentionThreshold < 1.0) {
|
|
65
66
|
const totalVotes = result.results.reduce((sum, r) => sum + r.votes.length, 0);
|
|
@@ -91,7 +92,26 @@ export class GovernanceService {
|
|
|
91
92
|
},
|
|
92
93
|
};
|
|
93
94
|
}
|
|
94
|
-
|
|
95
|
+
resolveRequireExternalDynamo(explicit) {
|
|
96
|
+
if (explicit !== undefined)
|
|
97
|
+
return explicit;
|
|
98
|
+
if (process.env.XRAY_LOCAL_MODE === '1' || process.env.XRAY_LOCAL_MODE === 'true') {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const config = featuresConfigLoader.loadConfig();
|
|
103
|
+
const ig = config.inference_governance;
|
|
104
|
+
if (ig?.require_external_dynamo === false)
|
|
105
|
+
return false;
|
|
106
|
+
if (ig?.local_mode === true)
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
/* default strict */
|
|
111
|
+
}
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
async runGovernanceWithTimeout(proposals, context, requireExternal, timeoutMs, metamorphosisThreshold = 0.7) {
|
|
95
115
|
const controller = new AbortController();
|
|
96
116
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
|
97
117
|
try {
|
|
@@ -112,12 +132,67 @@ export class GovernanceService {
|
|
|
112
132
|
...(externalVotes[index] || []),
|
|
113
133
|
];
|
|
114
134
|
const merged = mergeVotes(votes);
|
|
135
|
+
const externalVote = votes.find((v) => v.server === 'external-dynamo');
|
|
136
|
+
let finalDecision = merged.finalDecision;
|
|
137
|
+
let averageConfidence = merged.averageConfidence;
|
|
138
|
+
let moralOverride = 'none';
|
|
139
|
+
if (externalVote?.moralTension ||
|
|
140
|
+
externalVote?.moralScore != null ||
|
|
141
|
+
externalVote?.moralFusion != null) {
|
|
142
|
+
const matrixInput = {
|
|
143
|
+
resonance: averageConfidence,
|
|
144
|
+
isotopicRatio: externalVote.moralFusion ?? 0.5,
|
|
145
|
+
};
|
|
146
|
+
if (externalVote.moralTension != null) {
|
|
147
|
+
matrixInput.moralTension = externalVote.moralTension;
|
|
148
|
+
}
|
|
149
|
+
if (externalVote.moralScore != null) {
|
|
150
|
+
matrixInput.moralScore = externalVote.moralScore;
|
|
151
|
+
}
|
|
152
|
+
if (externalVote.moralFusion != null) {
|
|
153
|
+
matrixInput.moralFusion = externalVote.moralFusion;
|
|
154
|
+
}
|
|
155
|
+
const matrix = applyDecisionMatrix(matrixInput);
|
|
156
|
+
moralOverride = matrix.moralOverride ?? 'none';
|
|
157
|
+
if (matrix.recommendation === 'REJECT') {
|
|
158
|
+
finalDecision = 'reject';
|
|
159
|
+
}
|
|
160
|
+
else if (matrix.recommendation === 'NEEDS_REVISION' && finalDecision === 'approve') {
|
|
161
|
+
finalDecision = 'needs_revision';
|
|
162
|
+
}
|
|
163
|
+
else if (matrix.recommendation === 'PASS' && finalDecision !== 'reject') {
|
|
164
|
+
finalDecision = 'approve';
|
|
165
|
+
}
|
|
166
|
+
averageConfidence = matrix.confidence;
|
|
167
|
+
}
|
|
168
|
+
let metamorphosisScore;
|
|
169
|
+
if (proposal.type === 'metamorphosis' || proposal.source === 'metamorphosis') {
|
|
170
|
+
const proposalType = proposal.type === 'compliance'
|
|
171
|
+
? 'compliance'
|
|
172
|
+
: proposal.type === 'automate' || proposal.type === 'codify'
|
|
173
|
+
? proposal.type
|
|
174
|
+
: 'fix';
|
|
175
|
+
const metamorphosisInput = {
|
|
176
|
+
averageConfidence,
|
|
177
|
+
proposalType,
|
|
178
|
+
resonanceScore: averageConfidence,
|
|
179
|
+
};
|
|
180
|
+
if (externalVote?.moralFusion != null) {
|
|
181
|
+
metamorphosisInput.historicalCoherence = externalVote.moralFusion;
|
|
182
|
+
}
|
|
183
|
+
metamorphosisScore = calculateMetamorphosisScore(metamorphosisInput);
|
|
184
|
+
if (metamorphosisScore < metamorphosisThreshold) {
|
|
185
|
+
finalDecision = 'needs_revision';
|
|
186
|
+
}
|
|
187
|
+
}
|
|
115
188
|
return {
|
|
116
189
|
proposalId: proposal.id,
|
|
117
|
-
finalDecision
|
|
118
|
-
averageConfidence
|
|
190
|
+
finalDecision,
|
|
191
|
+
averageConfidence,
|
|
119
192
|
votes,
|
|
120
193
|
reasoningSummary: merged.reasoningSummary,
|
|
194
|
+
moralOverride,
|
|
195
|
+
...(metamorphosisScore != null ? { metamorphosisScore } : {}),
|
|
121
196
|
};
|
|
122
197
|
});
|
|
123
198
|
return { results };
|
|
@@ -252,12 +252,22 @@ export async function afterToolHook(tool, args, _result, _error, _context) {
|
|
|
252
252
|
const result = _result;
|
|
253
253
|
if (result && typeof result === "object" && "title" in result && "description" in result) {
|
|
254
254
|
const { handleGovernRequest } = await import("../nucleus/index.js");
|
|
255
|
+
const localMode = process.env.XRAY_LOCAL_MODE === "1" || process.env.XRAY_LOCAL_MODE === "true";
|
|
255
256
|
const governanceResult = await handleGovernRequest({
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
257
|
+
proposals: [
|
|
258
|
+
{
|
|
259
|
+
id: `gate-${Date.now()}`,
|
|
260
|
+
type: String(result.type || "fix"),
|
|
261
|
+
title: String(result.title || ""),
|
|
262
|
+
description: String(result.description || ""),
|
|
263
|
+
evidence: [],
|
|
264
|
+
source: "manual",
|
|
265
|
+
metadata: result,
|
|
266
|
+
},
|
|
267
|
+
],
|
|
268
|
+
options: {
|
|
269
|
+
requireExternalDynamo: localMode ? false : undefined,
|
|
270
|
+
},
|
|
261
271
|
});
|
|
262
272
|
governanceTriggered = governanceResult?.overallDecision === 'approve';
|
|
263
273
|
if (governanceTriggered) {
|
|
@@ -25,16 +25,7 @@ const __dirname = path.dirname(new URL(import.meta.url).pathname);
|
|
|
25
25
|
const packageRoot = path.resolve(__dirname, '..', '..', '..');
|
|
26
26
|
const requireCjs = createRequire(import.meta.url);
|
|
27
27
|
const { resolveConsumerTargetDir } = requireCjs(path.join(packageRoot, 'scripts/node/install-bridges.cjs'));
|
|
28
|
-
|
|
29
|
-
const XRAY_MCP_SERVERS = [
|
|
30
|
-
{ name: 'xray-governance', mcpCmd: 'governance', env: { XRAY_FORCE_MCP_GOVERNANCE: 'true' } },
|
|
31
|
-
{ name: 'xray-skills', mcpCmd: 'skills', env: {} },
|
|
32
|
-
{ name: 'xray-orchestrator', mcpCmd: 'orchestrator', env: {} },
|
|
33
|
-
{ name: 'xray-enforcer', mcpCmd: 'enforcer', env: {} },
|
|
34
|
-
{ name: 'xray-researcher', mcpCmd: 'researcher', env: {} },
|
|
35
|
-
{ name: 'xray-code-review', mcpCmd: 'code-review', env: {} },
|
|
36
|
-
{ name: 'xray-architect-tools', mcpCmd: 'architect-tools', env: {} },
|
|
37
|
-
];
|
|
28
|
+
const { XRAY_MCP_SERVERS } = requireCjs(path.join(packageRoot, 'scripts/node/bridge-mcp-wiring.cjs'));
|
|
38
29
|
function registerGrokMcpServers(targetDir) {
|
|
39
30
|
try {
|
|
40
31
|
execSync('which grok', { stdio: 'ignore' });
|
|
@@ -18,6 +18,8 @@ import {
|
|
|
18
18
|
validateSpawnMatchesTodo,
|
|
19
19
|
updatePlanTodoStatusInPlace,
|
|
20
20
|
} from '../../hooks/delegation-gate-runtime.mjs';
|
|
21
|
+
import { isConferPendingForSession } from '../../hooks/confer-hook-runtime.mjs';
|
|
22
|
+
import { getActiveUserAsideBoot } from '../../hooks/user-aside-hook-runtime.mjs';
|
|
21
23
|
|
|
22
24
|
export {
|
|
23
25
|
checkPendingDelegationGate,
|
|
@@ -105,6 +107,30 @@ export function resolveCodexPath(root = workspaceRoot()) {
|
|
|
105
107
|
return null;
|
|
106
108
|
}
|
|
107
109
|
|
|
110
|
+
export function resolveSiblingWorkspaceRoots(root = workspaceRoot()) {
|
|
111
|
+
const featuresPath = resolveFeaturesPath(root);
|
|
112
|
+
if (!featuresPath) return [];
|
|
113
|
+
try {
|
|
114
|
+
const data = JSON.parse(fs.readFileSync(featuresPath, 'utf8'));
|
|
115
|
+
const siblings = data.multi_agent_orchestration?.sibling_repos ?? [];
|
|
116
|
+
if (!Array.isArray(siblings)) return [];
|
|
117
|
+
const resolved = [];
|
|
118
|
+
for (const entry of siblings) {
|
|
119
|
+
const rel = typeof entry === 'string' ? entry : entry?.path;
|
|
120
|
+
if (!rel || typeof rel !== 'string') continue;
|
|
121
|
+
const abs = path.isAbsolute(rel) ? rel : path.resolve(root, rel);
|
|
122
|
+
if (!fs.existsSync(abs)) continue;
|
|
123
|
+
resolved.push({
|
|
124
|
+
path: abs,
|
|
125
|
+
label: typeof entry === 'object' && entry.label ? entry.label : path.basename(abs),
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
return resolved;
|
|
129
|
+
} catch {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
108
134
|
export function loadFeatures(root = workspaceRoot()) {
|
|
109
135
|
const featuresPath = resolveFeaturesPath(root);
|
|
110
136
|
if (!featuresPath) return { lead_dev_mode: true, no_new_surface: true, per_suite_triage: true };
|
|
@@ -116,6 +142,7 @@ export function loadFeatures(root = workspaceRoot()) {
|
|
|
116
142
|
no_new_surface: orch.no_new_surface !== false,
|
|
117
143
|
per_suite_test_triage: orch.per_suite_test_triage !== false,
|
|
118
144
|
auto_chain_delegations: orch.auto_chain_delegations !== false,
|
|
145
|
+
sibling_repos: resolveSiblingWorkspaceRoots(root),
|
|
119
146
|
};
|
|
120
147
|
} catch {
|
|
121
148
|
return {
|
|
@@ -123,6 +150,7 @@ export function loadFeatures(root = workspaceRoot()) {
|
|
|
123
150
|
no_new_surface: true,
|
|
124
151
|
per_suite_triage: true,
|
|
125
152
|
auto_chain_delegations: true,
|
|
153
|
+
sibling_repos: [],
|
|
126
154
|
};
|
|
127
155
|
}
|
|
128
156
|
}
|
|
@@ -215,9 +243,22 @@ export function sessionBootPath(root = workspaceRoot()) {
|
|
|
215
243
|
return path.join(root, '.xray', 'state', 'session-boot.json');
|
|
216
244
|
}
|
|
217
245
|
|
|
246
|
+
export function loadConferPending(root = workspaceRoot(), sessionId = null) {
|
|
247
|
+
try {
|
|
248
|
+
return isConferPendingForSession(root, sessionId);
|
|
249
|
+
} catch {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
218
254
|
export function buildSessionBootPayload(root, source = '0xray/grok-session-start', extra = {}) {
|
|
219
|
-
const features = loadFeatures();
|
|
255
|
+
const features = loadFeatures(root);
|
|
220
256
|
const blockingTerms = loadBlockingCodexTerms();
|
|
257
|
+
const siblingRoots = features.sibling_repos ?? resolveSiblingWorkspaceRoots(root);
|
|
258
|
+
const sessionId =
|
|
259
|
+
extra.sessionId || process.env.GROK_SESSION_ID || process.env.GROK_SESSION || null;
|
|
260
|
+
const conferPending = loadConferPending(root, sessionId);
|
|
261
|
+
const userAsideBoot = getActiveUserAsideBoot(root, sessionId);
|
|
221
262
|
return {
|
|
222
263
|
hook: source,
|
|
223
264
|
lead_dev_mode: features.lead_dev_mode,
|
|
@@ -228,7 +269,10 @@ export function buildSessionBootPayload(root, source = '0xray/grok-session-start
|
|
|
228
269
|
mcpIntake: 'xray-orchestrator → analyze-complexity (required before spawn_subagent)',
|
|
229
270
|
enforcement: 'PreToolUse hook — codex patterns + surface area + spawn gate',
|
|
230
271
|
workspaceRoot: root,
|
|
231
|
-
|
|
272
|
+
...(siblingRoots.length > 0 ? { siblingWorkspaceRoots: siblingRoots } : {}),
|
|
273
|
+
...(conferPending ? { conferPending: true, conferTrigger: 'analyze-complexity at synthesis checkpoint' } : {}),
|
|
274
|
+
...(userAsideBoot ?? {}),
|
|
275
|
+
sessionId,
|
|
232
276
|
timestamp: new Date().toISOString(),
|
|
233
277
|
source,
|
|
234
278
|
...extra,
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
evaluatePostToolSpawn,
|
|
18
18
|
isOrchestrateToolEvent as gateIsOrchestrateToolEvent,
|
|
19
19
|
} from '../../hooks/delegation-gate-runtime.mjs';
|
|
20
|
+
import { recordRoutingOutcome } from '../../hooks/pipeline-hook-runtime.mjs';
|
|
20
21
|
|
|
21
22
|
function extractToolOutput(event) {
|
|
22
23
|
return (
|
|
@@ -43,6 +44,16 @@ async function main() {
|
|
|
43
44
|
sessionId,
|
|
44
45
|
note: 'orchestrate-task completed — pending-delegations.json written by task-handler',
|
|
45
46
|
});
|
|
47
|
+
try {
|
|
48
|
+
recordRoutingOutcome(eventRoot, {
|
|
49
|
+
tool: toolName,
|
|
50
|
+
agent: toolInput?.subagent_type ?? toolInput?.agent ?? 'orchestrate-task',
|
|
51
|
+
planTodoId: toolInput?.planTodoId ?? null,
|
|
52
|
+
sessionId,
|
|
53
|
+
});
|
|
54
|
+
} catch {
|
|
55
|
+
/* non-blocking */
|
|
56
|
+
}
|
|
46
57
|
}
|
|
47
58
|
|
|
48
59
|
if (isSubagentTool(toolName)) {
|
|
@@ -61,6 +72,16 @@ async function main() {
|
|
|
61
72
|
todoCompleted: spawnResult.todoCompleted ?? false,
|
|
62
73
|
});
|
|
63
74
|
}
|
|
75
|
+
try {
|
|
76
|
+
recordRoutingOutcome(eventRoot, {
|
|
77
|
+
tool: toolName,
|
|
78
|
+
agent: toolInput?.subagent_type ?? toolInput?.agent ?? 'subagent',
|
|
79
|
+
planTodoId: toolInput?.planTodoId ?? spawnResult.expectedTodoId ?? null,
|
|
80
|
+
sessionId,
|
|
81
|
+
});
|
|
82
|
+
} catch {
|
|
83
|
+
/* non-blocking */
|
|
84
|
+
}
|
|
64
85
|
}
|
|
65
86
|
|
|
66
87
|
process.exit(0);
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
workspaceRoot,
|
|
22
22
|
} from './grok-hook-utils.js';
|
|
23
23
|
import { appendHookActivity } from './grok-hook-activity.js';
|
|
24
|
+
import { runGrokPostprocessorLight } from '../../hooks/pipeline-hook-runtime.mjs';
|
|
24
25
|
|
|
25
26
|
function finish(root, decision, reason, hint, toolName, extra = {}) {
|
|
26
27
|
const out = { decision, ...extra };
|
|
@@ -69,6 +70,17 @@ async function main() {
|
|
|
69
70
|
);
|
|
70
71
|
}
|
|
71
72
|
|
|
73
|
+
if (gateBlock.reason) {
|
|
74
|
+
finish(
|
|
75
|
+
eventRoot,
|
|
76
|
+
'allow',
|
|
77
|
+
gateBlock.reason,
|
|
78
|
+
gateBlock.hint,
|
|
79
|
+
toolName,
|
|
80
|
+
{ gate: gateBlock.gate, warn: true },
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
72
84
|
if (features.no_new_surface && isWriteTool(toolName) && paths.length) {
|
|
73
85
|
const surfaceBlock = checkSurfaceArea(paths, eventRoot);
|
|
74
86
|
if (surfaceBlock) finish(eventRoot, 'deny', surfaceBlock, null, toolName);
|
|
@@ -88,6 +100,14 @@ async function main() {
|
|
|
88
100
|
if (testHint) finish(eventRoot, 'allow', null, testHint, toolName);
|
|
89
101
|
}
|
|
90
102
|
|
|
103
|
+
if (features.grok_postprocessor_light === true && isWriteTool(toolName)) {
|
|
104
|
+
try {
|
|
105
|
+
runGrokPostprocessorLight(eventRoot, { tool: toolName, paths });
|
|
106
|
+
} catch {
|
|
107
|
+
/* non-blocking */
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
91
111
|
finish(eventRoot, 'allow', null, null, toolName);
|
|
92
112
|
} catch (err) {
|
|
93
113
|
appendHookActivity(root, 'grok-pre-tool-use', 'hook-error', 'error', {
|