0xray 3.4.1 → 3.4.2
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/codex.json +598 -0
- package/.xray/config.json +25 -0
- package/.xray/features.json +146 -0
- package/.xray/features.schema.json +33 -0
- package/AGENTS-consumer.md +127 -10
- package/AGENTS.md +172 -56
- package/README.md +159 -82
- package/SKILLS.md +79 -53
- package/dist/AGENTS.md +172 -56
- package/dist/CHANGELOG.md +79 -52
- package/dist/README.md +159 -82
- package/dist/SKILLS.md +79 -53
- package/dist/core/features-config.js +5 -0
- package/dist/integrations/grok/hooks/grok-hook-activity.js +53 -0
- package/dist/integrations/grok/hooks/grok-hook-utils.js +261 -0
- package/dist/integrations/grok/hooks/pre-tool-use.js +85 -115
- package/dist/integrations/grok/hooks/session-start.js +52 -0
- package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +20 -3
- package/dist/mcps/config/server-config-registry.js +4 -3
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +33 -3
- package/dist/mcps/orchestrator/server.js +1 -1
- package/dist/mcps/researcher.server.js +3 -0
- package/dist/nucleus/autonomy-kernel.js +176 -0
- package/dist/nucleus/index.js +1 -0
- package/dist/skills/boot-orchestrator/SKILL.md +1 -5
- package/dist/skills/orchestrator/SKILL.md +35 -12
- package/dist/skills/researcher/SKILL.md +17 -4
- package/dist/skills/strategist/SKILL.md +12 -0
- package/dist/skills/testing-strategy/SKILL.md +13 -2
- package/package.json +23 -8
- package/scripts/node/consumer-install-smoke.mjs +163 -0
- package/scripts/node/install-bridges.cjs +19 -6
- package/scripts/node/pre-publish-guard.js +107 -168
- package/scripts/node/reconcile-version.mjs +147 -0
- package/scripts/node/release-gate.mjs +66 -0
- package/scripts/node/release.js +5 -147
- package/scripts/node/release.mjs +106 -181
- package/scripts/node/setup.cjs +12 -22
- package/scripts/node/sync-versions.mjs +12 -134
- package/scripts/node/universal-version-manager.js +4 -0
- package/scripts/node/validate-release-docs.mjs +299 -0
- package/scripts/node/version-manager.mjs +225 -49
- package/src/integrations/grok/plugin/0xray/hooks/hooks.json +20 -3
- package/src/mcps/config/__tests__/server-config-registry.test.ts +9 -0
- package/src/mcps/config/server-config-registry.ts +5 -3
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +54 -3
- package/src/mcps/orchestrator/server.ts +1 -1
- package/src/mcps/researcher.server.ts +4 -0
- package/src/skills/boot-orchestrator/SKILL.md +1 -5
- package/src/skills/orchestrator/SKILL.md +35 -12
- package/src/skills/researcher/SKILL.md +17 -4
- package/src/skills/strategist/SKILL.md +12 -0
- package/src/skills/testing-strategy/SKILL.md +13 -2
- package/xray/config.json +25 -0
- package/xray/features.json +146 -0
- package/xray/features.schema.json +33 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lead-dev plan builder — internal implementation for orchestrator + hooks.
|
|
3
|
+
* Config: features.json → multi_agent_orchestration (lead_dev_mode), NOT a separate surface.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { featuresConfigLoader } from '../core/features-config.js';
|
|
8
|
+
import { scoreComplexity } from './thin-dispatch.js';
|
|
9
|
+
export const LEAD_DEV_RULES = [
|
|
10
|
+
'Phased plan + detailed todos; assign best subagent; monitor output; iterate fully',
|
|
11
|
+
'Lead dev takes helm — loop test fix until complete; no permission pings',
|
|
12
|
+
'Per-suite test triage after major changes; full suite only when individuals pass',
|
|
13
|
+
'Lead stays main thread; subagents execute; update todos continuously',
|
|
14
|
+
'Read all console and test output; triage fix rerun',
|
|
15
|
+
'Never defer errors as pre-existing — add todo and resolve',
|
|
16
|
+
'Resolve all errors before phase completion',
|
|
17
|
+
];
|
|
18
|
+
export const MANDATORY_MAJOR_CONSULTS = [
|
|
19
|
+
'researcher',
|
|
20
|
+
'architect-tools',
|
|
21
|
+
'code-review',
|
|
22
|
+
];
|
|
23
|
+
const TASK_TYPE_ROUTES = {
|
|
24
|
+
plan: 'strategist',
|
|
25
|
+
architecture: 'architect-tools',
|
|
26
|
+
research: 'researcher',
|
|
27
|
+
implement: 'backend-engineer',
|
|
28
|
+
frontend: 'frontend-engineer',
|
|
29
|
+
test: 'bug-triage',
|
|
30
|
+
review: 'code-review',
|
|
31
|
+
security: 'security-audit',
|
|
32
|
+
governance: 'enforcer',
|
|
33
|
+
};
|
|
34
|
+
function orchestrationConfig() {
|
|
35
|
+
try {
|
|
36
|
+
return featuresConfigLoader.loadConfig().multi_agent_orchestration;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return { enabled: true };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export function isLeadDevModeActive() {
|
|
43
|
+
const cfg = orchestrationConfig();
|
|
44
|
+
return cfg.enabled && cfg.lead_dev_mode !== false;
|
|
45
|
+
}
|
|
46
|
+
export function routeSubagent(taskType) {
|
|
47
|
+
return TASK_TYPE_ROUTES[taskType.toLowerCase().trim()] ?? 'backend-engineer';
|
|
48
|
+
}
|
|
49
|
+
export function shouldFlagFullTestSuite(command) {
|
|
50
|
+
const cfg = orchestrationConfig();
|
|
51
|
+
if (!cfg.enabled || cfg.per_suite_test_triage === false)
|
|
52
|
+
return false;
|
|
53
|
+
const cmd = command.toLowerCase();
|
|
54
|
+
const isTest = /\b(npm\s+(run\s+)?test|vitest\s+run|pnpm\s+test|yarn\s+test)\b/.test(cmd);
|
|
55
|
+
const hasFocusedTarget = /--\s+\S+\.test/.test(cmd) ||
|
|
56
|
+
/vitest\s+run\s+\S+\.test/.test(cmd) ||
|
|
57
|
+
/\btest:\w+/.test(cmd);
|
|
58
|
+
return isTest && !hasFocusedTarget;
|
|
59
|
+
}
|
|
60
|
+
export function buildLeadDevPlan(description, taskTypes = ['implement']) {
|
|
61
|
+
if (!isLeadDevModeActive())
|
|
62
|
+
return null;
|
|
63
|
+
const cfg = orchestrationConfig();
|
|
64
|
+
const threshold = cfg.phased_plan_threshold ?? 25;
|
|
65
|
+
const score = scoreComplexity(description, { taskTypes });
|
|
66
|
+
const complexity = score.score;
|
|
67
|
+
const requiresPhasedPlan = complexity > threshold;
|
|
68
|
+
const mandatoryConsults = cfg.auto_consult_major_work !== false && requiresPhasedPlan
|
|
69
|
+
? [...MANDATORY_MAJOR_CONSULTS]
|
|
70
|
+
: [];
|
|
71
|
+
const phases = requiresPhasedPlan
|
|
72
|
+
? [
|
|
73
|
+
{
|
|
74
|
+
id: 'phase-1',
|
|
75
|
+
name: 'Research & architecture',
|
|
76
|
+
goal: 'Understand scope before edits',
|
|
77
|
+
definitionOfDone: 'researcher + architect-tools + code-review consulted',
|
|
78
|
+
todos: mandatoryConsults.map((subagent, i) => ({
|
|
79
|
+
id: `1.${i + 1}`,
|
|
80
|
+
task: `Consult ${subagent} on: ${description.slice(0, 120)}`,
|
|
81
|
+
subagent: subagent,
|
|
82
|
+
status: 'pending',
|
|
83
|
+
})),
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 'phase-2',
|
|
87
|
+
name: 'Implementation',
|
|
88
|
+
goal: 'Execute with best subagent per todo',
|
|
89
|
+
definitionOfDone: 'Affected per-suite tests green',
|
|
90
|
+
todos: taskTypes.map((type, i) => ({
|
|
91
|
+
id: `2.${i + 1}`,
|
|
92
|
+
task: description.slice(0, 200),
|
|
93
|
+
subagent: routeSubagent(type),
|
|
94
|
+
status: 'pending',
|
|
95
|
+
})),
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: 'phase-3',
|
|
99
|
+
name: 'Verification',
|
|
100
|
+
goal: 'Per-suite triage then full suite gate',
|
|
101
|
+
definitionOfDone: 'Full test suite green; zero open errors',
|
|
102
|
+
todos: [
|
|
103
|
+
{
|
|
104
|
+
id: '3.1',
|
|
105
|
+
task: 'Run affected test files individually; triage and fix',
|
|
106
|
+
subagent: 'bug-triage',
|
|
107
|
+
status: 'pending',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: '3.2',
|
|
111
|
+
task: 'Run full test suite gate',
|
|
112
|
+
subagent: 'bug-triage',
|
|
113
|
+
status: 'pending',
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
},
|
|
117
|
+
]
|
|
118
|
+
: [
|
|
119
|
+
{
|
|
120
|
+
id: 'phase-1',
|
|
121
|
+
name: 'Direct execution',
|
|
122
|
+
goal: description.slice(0, 120),
|
|
123
|
+
definitionOfDone: 'Task complete with tests green',
|
|
124
|
+
todos: [
|
|
125
|
+
{
|
|
126
|
+
id: '1.1',
|
|
127
|
+
task: description.slice(0, 200),
|
|
128
|
+
subagent: routeSubagent(taskTypes[0] ?? 'implement'),
|
|
129
|
+
status: 'pending',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
];
|
|
134
|
+
return {
|
|
135
|
+
active: true,
|
|
136
|
+
rules: LEAD_DEV_RULES,
|
|
137
|
+
codexTerms: [59, 67, 68, 69],
|
|
138
|
+
description,
|
|
139
|
+
complexity,
|
|
140
|
+
requiresPhasedPlan,
|
|
141
|
+
recommendedStrategy: score.recommendedStrategy,
|
|
142
|
+
mandatoryConsults,
|
|
143
|
+
phases,
|
|
144
|
+
testProtocol: {
|
|
145
|
+
perSuiteFirst: cfg.per_suite_test_triage !== false,
|
|
146
|
+
fullSuiteGate: true,
|
|
147
|
+
hint: 'After major changes: npm test -- path/to/file.test.ts → fix → repeat → full npm test last',
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
export function buildSessionBootContext() {
|
|
152
|
+
if (!isLeadDevModeActive()) {
|
|
153
|
+
return { lead_dev_mode: false, reason: 'multi_agent_orchestration.lead_dev_mode=false' };
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
lead_dev_mode: true,
|
|
157
|
+
codexTerms: [67, 68],
|
|
158
|
+
rules: LEAD_DEV_RULES,
|
|
159
|
+
mcpBoot: 'xray-orchestrator → analyze-complexity (includes lead-dev plan when active)',
|
|
160
|
+
message: '[0xRay] Lead dev mode ON — phased todos, subagent dispatch, loop until green.',
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/** Persist plan for PreToolUse spawn_subagent gate */
|
|
164
|
+
export function persistLeadDevPlan(plan, projectRoot = process.cwd()) {
|
|
165
|
+
const stateDir = path.join(projectRoot, '.xray', 'state');
|
|
166
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
167
|
+
const planPath = path.join(stateDir, 'lead-dev-plan.json');
|
|
168
|
+
const payload = { ...plan, persistedAt: new Date().toISOString() };
|
|
169
|
+
fs.writeFileSync(planPath, JSON.stringify(payload, null, 2));
|
|
170
|
+
return planPath;
|
|
171
|
+
}
|
|
172
|
+
/** @deprecated Use isLeadDevModeActive */
|
|
173
|
+
export const isAutonomyKernelActive = isLeadDevModeActive;
|
|
174
|
+
/** @deprecated Use buildLeadDevPlan */
|
|
175
|
+
export const buildAutonomyIntake = buildLeadDevPlan;
|
|
176
|
+
export const AUTONOMY_RULES = LEAD_DEV_RULES;
|
package/dist/nucleus/index.js
CHANGED
|
@@ -8,4 +8,5 @@ export { handleGovernRequest, governSingle, getGovernanceService, GovernHTTPAdap
|
|
|
8
8
|
export { pluginRegistry, } from './plugin-registry.js';
|
|
9
9
|
export { scoreComplexity, routeToAgent, scoreAndRoute } from './thin-dispatch.js';
|
|
10
10
|
export { NUCLEUS_THIN_DISPATCH_VERSION } from './thin-dispatch.js';
|
|
11
|
+
export { LEAD_DEV_RULES, isLeadDevModeActive, buildLeadDevPlan, buildSessionBootContext, shouldFlagFullTestSuite, } from './autonomy-kernel.js';
|
|
11
12
|
export { registerDefaultPlugins } from './default-plugins.js';
|
|
@@ -28,10 +28,6 @@ Framework initialization and boot orchestration.
|
|
|
28
28
|
- **initialization**: Initialization
|
|
29
29
|
- **framework_startup**: Framework startup
|
|
30
30
|
|
|
31
|
-
## Usage
|
|
32
|
-
|
|
33
|
-
This skill provides infrastructure capabilities for boot orchestrator functionality.
|
|
34
|
-
|
|
35
31
|
## Integration
|
|
36
32
|
|
|
37
|
-
|
|
33
|
+
Lead-dev boot is handled by SessionStart hook + `orchestrator` skill — see `multi_agent_orchestration.lead_dev_mode` in features.json.
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: framework
|
|
3
3
|
name: orchestrator
|
|
4
|
-
description: Multi-agent workflow coordination and task delegation
|
|
4
|
+
description: Multi-agent workflow coordination, lead-dev operating model (codex 67-68), and task delegation. Default when suit is worn — no keywords required.
|
|
5
5
|
author: Xray Framework
|
|
6
6
|
version: 1.0.0
|
|
7
7
|
schema_version: "1.0"
|
|
8
|
-
tags: [orchestration, orchestrator]
|
|
8
|
+
tags: [orchestration, orchestrator, lead-dev]
|
|
9
9
|
capabilities:
|
|
10
10
|
- coordinate_agents
|
|
11
11
|
- delegate_tasks
|
|
@@ -18,20 +18,43 @@ mcp:
|
|
|
18
18
|
args: [node_modules/0xray/dist/mcps/orchestrator.server.js]
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
# Orchestrator Skill
|
|
21
|
+
# Orchestrator Skill — includes lead-dev operating model
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
When `multi_agent_orchestration.lead_dev_mode` is true in `features.json` (default when suit is worn), this is the **default OS behavior** — not a separate skill or MCP.
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## Seven rules (codex 67–68)
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
27
|
+
1. Phased plan + detailed todos; assign best subagent; monitor output
|
|
28
|
+
2. Lead dev loops test→fix until green; no permission pings
|
|
29
|
+
3. Per-suite test triage after major changes; full suite last
|
|
30
|
+
4. Lead stays main thread; subagents execute; update todos
|
|
31
|
+
5. Read all console and test output; triage fix rerun
|
|
32
|
+
6. Never defer errors as "pre-existing" — add todo and resolve
|
|
33
|
+
7. Resolve all errors before phase completion
|
|
30
34
|
|
|
31
|
-
##
|
|
35
|
+
## MCP loop (one tool surface — no autonomy-intake)
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
| Step | MCP tool | Notes |
|
|
38
|
+
|------|----------|-------|
|
|
39
|
+
| **Intake + classify** | `analyze-complexity` | Pass `tasks` array; response includes **lead-dev plan JSON** when mode is on |
|
|
40
|
+
| Delegate | `orchestrate-task` | Include agent + sessionId (codex 67) |
|
|
41
|
+
| Monitor | `get-orchestration-status` | Lead updates todos |
|
|
42
|
+
| Major work | researcher + architect-tools + code-review | Auto-listed in plan when complexity > threshold |
|
|
34
43
|
|
|
35
|
-
##
|
|
44
|
+
## Subagent routing
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
| Task | Subagent |
|
|
47
|
+
|------|----------|
|
|
48
|
+
| Phasing | strategist |
|
|
49
|
+
| Architecture | architect-tools |
|
|
50
|
+
| Research | researcher |
|
|
51
|
+
| Implementation | backend-engineer / frontend-engineer |
|
|
52
|
+
| Test failures | bug-triage |
|
|
53
|
+
| Review | code-review |
|
|
54
|
+
|
|
55
|
+
## Hooks (rewired, not new MCPs)
|
|
56
|
+
|
|
57
|
+
- **SessionStart** → `session-start.js` boots lead_dev_mode
|
|
58
|
+
- **PreToolUse** → hints `per_suite_triage_required` on full `npm test`
|
|
59
|
+
|
|
60
|
+
Config: `features.json` → `multi_agent_orchestration.lead_dev_mode`
|
|
@@ -28,10 +28,23 @@ Multi-repo analysis, documentation lookup, and implementation examples.
|
|
|
28
28
|
- **find_implementations**: Find implementations
|
|
29
29
|
- **analyze_documentation**: Analyze documentation
|
|
30
30
|
|
|
31
|
-
##
|
|
31
|
+
## When to invoke (autonomy-command)
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Lead dev dispatches researcher **before** major planning, refactors, or cross-repo work — not only when user says "research."
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
| Trigger | Action |
|
|
36
|
+
|---------|--------|
|
|
37
|
+
| Major refactor / new phase | `search_codebase`, `get_documentation`, `find_implementation` |
|
|
38
|
+
| Prior art / patterns | Search sibling repos (xray, groover, repertoire) |
|
|
39
|
+
| Proposal analysis | `analyze_proposal` via xray-researcher MCP |
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
## MCP tools (xray-researcher)
|
|
42
|
+
|
|
43
|
+
- `get_documentation` — module/class docs (`target` required)
|
|
44
|
+
- `search_codebase` — text search in workspace
|
|
45
|
+
- `find_implementation` — locate implementations
|
|
46
|
+
- `analyze_proposal` — governance-aware proposal review
|
|
47
|
+
|
|
48
|
+
## Return shape for lead
|
|
49
|
+
|
|
50
|
+
Summarize: findings (3–5 bullets), file paths, recommended next todos. Do not defer work back to lead without concrete patches or todos.
|
|
@@ -30,3 +30,15 @@ Think deeply before recommending. Consider trade-offs and long-term implications
|
|
|
30
30
|
- Risk analysis and mitigation planning
|
|
31
31
|
- High-level system design and framework evolution
|
|
32
32
|
- Technical debt identification and prioritization
|
|
33
|
+
|
|
34
|
+
## When to invoke (autonomy-command)
|
|
35
|
+
|
|
36
|
+
Lead dev dispatches strategist when `analyze-complexity` score **>25** or work spans multiple repos/phases.
|
|
37
|
+
|
|
38
|
+
| Output required | Format |
|
|
39
|
+
|-----------------|--------|
|
|
40
|
+
| Phased plan | Phase N + goal + definition of done |
|
|
41
|
+
| Todo breakdown | ID, task, subagent assignment |
|
|
42
|
+
| Risks | Top 3 with mitigations |
|
|
43
|
+
|
|
44
|
+
Use `orchestrate-task` or Task subagent. Return actionable todos — not essays.
|
|
@@ -38,6 +38,17 @@ This skill helps design and optimize testing strategies for:
|
|
|
38
38
|
- Test coverage optimization
|
|
39
39
|
- Testing best practices implementation
|
|
40
40
|
|
|
41
|
-
##
|
|
41
|
+
## Per-suite triage (autonomy-command rule 3)
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
After major changes, **do not** run the full test suite first.
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
1. Identify affected test file(s) from the diff
|
|
47
|
+
2. Run ONE suite: npm test -- path/to/focused.test.ts
|
|
48
|
+
3. Read ALL failure output — triage root cause
|
|
49
|
+
4. Fix → rerun that suite until green
|
|
50
|
+
5. Repeat for each affected suite
|
|
51
|
+
6. Only then: npm test (full suite gate)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Lead dev owns every failure. No "pre-existing" deferrals.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "0xray",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.2",
|
|
4
4
|
"description": "Multi-agent orchestration and Codex governance for OpenCode, Hermes, Grok Build, and OpenClaw",
|
|
5
5
|
"readme": "README.md",
|
|
6
6
|
"license": "MIT",
|
|
@@ -55,12 +55,16 @@
|
|
|
55
55
|
"plugin": "./dist/plugin/xray-codex-injection.js",
|
|
56
56
|
"mcps": "./dist/mcps/"
|
|
57
57
|
},
|
|
58
|
+
"xray": {
|
|
59
|
+
"dist": "dist",
|
|
60
|
+
"mcpServersPath": "dist/mcps"
|
|
61
|
+
},
|
|
58
62
|
"scripts": {
|
|
59
|
-
"prepublishOnly": "npm run prepare-consumer && npm run build:all && find dist -name '*.d.ts' -o -name '*.d.ts.map' -o -name '*.js.map' | xargs rm -f",
|
|
63
|
+
"prepublishOnly": "node scripts/node/reconcile-version.mjs --check && npm run prepare-consumer && npm run build:all && find dist -name '*.d.ts' -o -name '*.d.ts.map' -o -name '*.js.map' | xargs rm -f",
|
|
60
64
|
"version:bump": "node scripts/node/version-manager.mjs",
|
|
61
65
|
"version": "node scripts/node/version-manager.mjs",
|
|
62
66
|
"prebuild": "rm -rf dist tsconfig.tsbuildinfo tsconfig.*.tsbuildinfo",
|
|
63
|
-
"build": "tsc && mkdir -p dist/public dist/scripts && cp -r public/* dist/public/ && cp scripts/hooks/pre-command dist/scripts/ && cp scripts/hooks/pre-command.mjs dist/scripts/ && cp README.md AGENTS.md SKILLS.md CHANGELOG.md LICENSE .gitignore.default dist/ && find src -name '*.mjs' ! -path '*/__tests__/*' | while read f; do tgt=\"dist/${f#src/}\"; mkdir -p \"$(dirname $tgt)\"; cp \"$f\" \"$tgt\"; done && for dir in skills integrations mcps; do find src/$dir -type f ! -name '*.ts' ! -path '*/.pytest_cache/*' | while read f; do tgt=\"dist/${f#src/}\"; mkdir -p \"$(dirname $tgt)\"; cp \"$f\" \"$tgt\"; done; done && mkdir -p dist/plugin && (find dist/plugin -name '*codex-injection*.js' -exec cp {} dist/plugin/xray-codex-injection.js \\; 2>/dev/null || true) && cp -r src/opencode/ .opencode/ && mkdir -p .xray &&
|
|
67
|
+
"build": "tsc && mkdir -p dist/public dist/scripts && cp -r public/* dist/public/ && cp scripts/hooks/pre-command dist/scripts/ && cp scripts/hooks/pre-command.mjs dist/scripts/ && cp README.md AGENTS.md SKILLS.md CHANGELOG.md LICENSE .gitignore.default dist/ && find src -name '*.mjs' ! -path '*/__tests__/*' | while read f; do tgt=\"dist/${f#src/}\"; mkdir -p \"$(dirname $tgt)\"; cp \"$f\" \"$tgt\"; done && for dir in skills integrations mcps; do find src/$dir -type f ! -name '*.ts' ! -path '*/.pytest_cache/*' | while read f; do tgt=\"dist/${f#src/}\"; mkdir -p \"$(dirname $tgt)\"; cp \"$f\" \"$tgt\"; done; done && mkdir -p dist/plugin && (find dist/plugin -name '*codex-injection*.js' -exec cp {} dist/plugin/xray-codex-injection.js \\; 2>/dev/null || true) && cp -r src/opencode/ .opencode/ && mkdir -p .xray && for f in codex.json features.json features.schema.json config.json; do cp xray/$f .xray/$f 2>/dev/null || true; done",
|
|
64
68
|
"build:all": "npm run build",
|
|
65
69
|
"ci-install": "npm ci",
|
|
66
70
|
"clean": "rm -rf dist tsconfig.tsbuildinfo tsconfig.*.tsbuildinfo",
|
|
@@ -94,6 +98,7 @@
|
|
|
94
98
|
"test:dependency-scan": "npm run security-audit",
|
|
95
99
|
"test:integration": "node scripts/mjs/test-consumer-readiness.mjs && node scripts/mjs/test-mcp-functionality.mjs",
|
|
96
100
|
"test:e2e": "node scripts/node/validate-mcp-connectivity.js && node scripts/node/validate-external-processes.js",
|
|
101
|
+
"live-feedback-session": "npx --yes tsx scripts/live-taskhandler-feedback-session.ts",
|
|
97
102
|
"validate": "echo \"[xray] Use 'npm test' or 'npm run test:comprehensive'.\"",
|
|
98
103
|
"validate:quick": "npm run validate",
|
|
99
104
|
"debug:inference:force": "XRAY_FORCE_MCP_GOVERNANCE=true XRAY_DEV_PATH=dist node dist/cli/index.js inference:run --force",
|
|
@@ -108,15 +113,18 @@
|
|
|
108
113
|
"build:clean": "node scripts/build/utils.js clean",
|
|
109
114
|
"build:verify": "node scripts/build/utils.js verify",
|
|
110
115
|
"enforce:versions": "bash scripts/node/enforce-version-compliance.sh",
|
|
111
|
-
"version:sync": "node scripts/node/
|
|
112
|
-
"
|
|
113
|
-
"release": "node scripts/node/release.js",
|
|
116
|
+
"version:sync": "node scripts/node/version-manager.mjs --artifacts-only",
|
|
117
|
+
"release": "node scripts/node/release.mjs patch",
|
|
114
118
|
"release:minor": "node scripts/node/release.mjs minor",
|
|
115
119
|
"release:major": "node scripts/node/release.mjs major",
|
|
116
|
-
"release:dry": "node scripts/node/release.
|
|
120
|
+
"release:dry": "node scripts/node/release.mjs patch --dry-run",
|
|
121
|
+
"version:reconcile": "node scripts/node/reconcile-version.mjs",
|
|
122
|
+
"consumer:smoke": "node scripts/node/consumer-install-smoke.mjs",
|
|
123
|
+
"release:gate": "node scripts/node/release-gate.mjs",
|
|
124
|
+
"release:docs-check": "node scripts/node/validate-release-docs.mjs",
|
|
117
125
|
"pre-publish-guard": "node scripts/node/pre-publish-guard.js",
|
|
118
126
|
"safe-publish": "npm run prepare-consumer && npm run build",
|
|
119
|
-
"publish": "npm run
|
|
127
|
+
"publish": "npm run release:gate && npm run safe-publish && npm publish --access public",
|
|
120
128
|
"release:patch": "node scripts/node/release.mjs patch"
|
|
121
129
|
},
|
|
122
130
|
"files": [
|
|
@@ -155,6 +163,13 @@
|
|
|
155
163
|
"SKILLS.md",
|
|
156
164
|
"xray/agents_template.md",
|
|
157
165
|
"xray/codex.json",
|
|
166
|
+
"xray/features.json",
|
|
167
|
+
"xray/features.schema.json",
|
|
168
|
+
"xray/config.json",
|
|
169
|
+
".xray/codex.json",
|
|
170
|
+
".xray/features.json",
|
|
171
|
+
".xray/features.schema.json",
|
|
172
|
+
".xray/config.json",
|
|
158
173
|
".gitignore.default",
|
|
159
174
|
"LICENSE"
|
|
160
175
|
],
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* consumer-install-smoke.mjs — Clean-room pack + install verification.
|
|
4
|
+
*
|
|
5
|
+
* Simulates what consumers receive from npm without publishing.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node scripts/node/consumer-install-smoke.mjs
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { execSync } from "child_process";
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import os from "os";
|
|
14
|
+
import path from "path";
|
|
15
|
+
import { fileURLToPath } from "url";
|
|
16
|
+
import { createRequire } from "module";
|
|
17
|
+
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const rootDir = path.resolve(__dirname, "../..");
|
|
21
|
+
|
|
22
|
+
const XRAY_MCP_NAMES = [
|
|
23
|
+
"xray-governance",
|
|
24
|
+
"xray-skills",
|
|
25
|
+
"xray-orchestrator",
|
|
26
|
+
"xray-enforcer",
|
|
27
|
+
"xray-researcher",
|
|
28
|
+
"xray-code-review",
|
|
29
|
+
"xray-architect-tools",
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
function run(cmd, cwd, { inherit = false } = {}) {
|
|
33
|
+
const result = execSync(cmd, {
|
|
34
|
+
cwd,
|
|
35
|
+
encoding: inherit ? undefined : "utf-8",
|
|
36
|
+
stdio: inherit ? "inherit" : "pipe",
|
|
37
|
+
});
|
|
38
|
+
return inherit ? "" : String(result).trim();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function main() {
|
|
42
|
+
console.log("\n=== Consumer Install Smoke ===\n");
|
|
43
|
+
|
|
44
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf-8"));
|
|
45
|
+
const version = pkg.version;
|
|
46
|
+
const tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), "0xray-smoke-"));
|
|
47
|
+
let tarball = null;
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
console.log("📦 npm pack...");
|
|
51
|
+
const packOut = run("npm pack --silent", rootDir);
|
|
52
|
+
tarball = packOut.split("\n").filter(Boolean).pop();
|
|
53
|
+
const tarballPath = path.join(rootDir, tarball);
|
|
54
|
+
if (!fs.existsSync(tarballPath)) {
|
|
55
|
+
throw new Error(`Tarball not found: ${tarballPath}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const consumerPkg = {
|
|
59
|
+
name: "0xray-smoke-consumer",
|
|
60
|
+
private: true,
|
|
61
|
+
version: "1.0.0",
|
|
62
|
+
dependencies: {
|
|
63
|
+
"0xray": `file:${tarballPath}`,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
fs.writeFileSync(
|
|
67
|
+
path.join(tmpRoot, "package.json"),
|
|
68
|
+
JSON.stringify(consumerPkg, null, 2) + "\n",
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
console.log("📥 npm install (runs postinstall)...");
|
|
72
|
+
run("npm install", tmpRoot, { inherit: true });
|
|
73
|
+
|
|
74
|
+
const nmRoot = path.join(tmpRoot, "node_modules", "0xray");
|
|
75
|
+
const requiredFiles = [
|
|
76
|
+
"scripts/node/install-bridges.cjs",
|
|
77
|
+
"scripts/node/postinstall.cjs",
|
|
78
|
+
"package.json",
|
|
79
|
+
"xray/features.json",
|
|
80
|
+
"xray/features.schema.json",
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
for (const rel of requiredFiles) {
|
|
84
|
+
const full = path.join(nmRoot, rel);
|
|
85
|
+
if (!fs.existsSync(full)) {
|
|
86
|
+
throw new Error(`Missing in tarball install: ${rel}`);
|
|
87
|
+
}
|
|
88
|
+
console.log(` ✅ ${rel}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const installedPkg = JSON.parse(fs.readFileSync(path.join(nmRoot, "package.json"), "utf-8"));
|
|
92
|
+
if (installedPkg.version !== version) {
|
|
93
|
+
throw new Error(`Installed version ${installedPkg.version} != packed ${version}`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const bridges = require(path.join(nmRoot, "scripts/node/install-bridges.cjs"));
|
|
97
|
+
for (const exp of ["installAllBridges", "resolveConsumerTargetDir", "isConsumerInstall"]) {
|
|
98
|
+
if (typeof bridges[exp] !== "function") {
|
|
99
|
+
throw new Error(`install-bridges missing export: ${exp}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
console.log(" ✅ install-bridges exports");
|
|
103
|
+
|
|
104
|
+
if (!bridges.isConsumerInstall(nmRoot, tmpRoot)) {
|
|
105
|
+
throw new Error("isConsumerInstall should be true for node_modules/0xray → project root");
|
|
106
|
+
}
|
|
107
|
+
console.log(" ✅ consumer target resolution");
|
|
108
|
+
|
|
109
|
+
// Postinstall should have run; verify .mcp.json merge
|
|
110
|
+
const mcpPath = path.join(tmpRoot, ".mcp.json");
|
|
111
|
+
if (!fs.existsSync(mcpPath)) {
|
|
112
|
+
throw new Error(".mcp.json not created by postinstall");
|
|
113
|
+
}
|
|
114
|
+
const mcp = JSON.parse(fs.readFileSync(mcpPath, "utf-8"));
|
|
115
|
+
const servers = Object.keys(mcp.mcpServers || {});
|
|
116
|
+
for (const name of XRAY_MCP_NAMES) {
|
|
117
|
+
if (!servers.includes(name)) {
|
|
118
|
+
throw new Error(`Missing MCP server in .mcp.json: ${name}`);
|
|
119
|
+
}
|
|
120
|
+
const entry = mcp.mcpServers[name];
|
|
121
|
+
if (entry.command !== "npx") {
|
|
122
|
+
throw new Error(`${name} should use npx, got ${entry.command}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
console.log(` ✅ .mcp.json has ${XRAY_MCP_NAMES.length} npx MCP servers`);
|
|
126
|
+
|
|
127
|
+
const consumerFeaturesPath = path.join(tmpRoot, ".xray", "features.json");
|
|
128
|
+
if (!fs.existsSync(consumerFeaturesPath)) {
|
|
129
|
+
throw new Error(".xray/features.json not deployed to consumer project by postinstall");
|
|
130
|
+
}
|
|
131
|
+
const features = JSON.parse(fs.readFileSync(consumerFeaturesPath, "utf-8"));
|
|
132
|
+
if (!features.memory_routing) {
|
|
133
|
+
throw new Error("Deployed features.json missing memory_routing block");
|
|
134
|
+
}
|
|
135
|
+
console.log(" ✅ .xray/features.json deployed with memory_routing");
|
|
136
|
+
|
|
137
|
+
const schemaInPackage = path.join(nmRoot, "xray", "features.schema.json");
|
|
138
|
+
if (!fs.existsSync(schemaInPackage)) {
|
|
139
|
+
throw new Error("xray/features.schema.json missing from installed package");
|
|
140
|
+
}
|
|
141
|
+
console.log(" ✅ xray/features.schema.json in package");
|
|
142
|
+
|
|
143
|
+
console.log("\n✅ Consumer install smoke passed\n");
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.error(`\n❌ Consumer smoke failed: ${err.message}\n`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
} finally {
|
|
148
|
+
if (tarball) {
|
|
149
|
+
try {
|
|
150
|
+
fs.unlinkSync(path.join(rootDir, tarball));
|
|
151
|
+
} catch {
|
|
152
|
+
/* best-effort */
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
try {
|
|
156
|
+
fs.rmSync(tmpRoot, { recursive: true, force: true });
|
|
157
|
+
} catch {
|
|
158
|
+
/* best-effort */
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
main();
|
|
@@ -397,18 +397,27 @@ function installOpenclawBridge(targetDir, packageRoot, log) {
|
|
|
397
397
|
if (copied > 0) log("openclaw-bridge", `skills synced (${copied})`, "info", { path: "~/.openclaw/skills/" });
|
|
398
398
|
}
|
|
399
399
|
|
|
400
|
+
const XRAY_CONFIG_FILES = ["codex.json", "features.json", "features.schema.json", "config.json"];
|
|
401
|
+
|
|
402
|
+
function resolveXrayConfigSource(packageRoot, file) {
|
|
403
|
+
const dotXray = path.join(packageRoot, ".xray", file);
|
|
404
|
+
if (fs.existsSync(dotXray)) return dotXray;
|
|
405
|
+
const xrayDir = path.join(packageRoot, "xray", file);
|
|
406
|
+
if (fs.existsSync(xrayDir)) return xrayDir;
|
|
407
|
+
return null;
|
|
408
|
+
}
|
|
409
|
+
|
|
400
410
|
function deployXrayConfig(targetDir, packageRoot, log) {
|
|
401
|
-
const xraySourceDir = path.join(packageRoot, ".xray");
|
|
402
411
|
const xrayTargetDir = path.join(targetDir, ".xray");
|
|
403
|
-
const
|
|
404
|
-
if (!
|
|
412
|
+
const hasAnySource = XRAY_CONFIG_FILES.some((file) => resolveXrayConfigSource(packageRoot, file));
|
|
413
|
+
if (!hasAnySource) return;
|
|
405
414
|
|
|
406
415
|
if (!fs.existsSync(xrayTargetDir)) fs.mkdirSync(xrayTargetDir, { recursive: true });
|
|
407
416
|
let copied = 0;
|
|
408
|
-
for (const file of
|
|
409
|
-
const src =
|
|
417
|
+
for (const file of XRAY_CONFIG_FILES) {
|
|
418
|
+
const src = resolveXrayConfigSource(packageRoot, file);
|
|
410
419
|
const dst = path.join(xrayTargetDir, file);
|
|
411
|
-
if (!
|
|
420
|
+
if (!src) continue;
|
|
412
421
|
const shouldCopy = !fs.existsSync(dst) || fs.statSync(src).mtime > fs.statSync(dst).mtime;
|
|
413
422
|
if (shouldCopy) {
|
|
414
423
|
fs.copyFileSync(src, dst);
|
|
@@ -416,6 +425,7 @@ function deployXrayConfig(targetDir, packageRoot, log) {
|
|
|
416
425
|
}
|
|
417
426
|
}
|
|
418
427
|
if (copied > 0) log("xray-config", `${copied} files deployed`, "info", { path: ".xray/" });
|
|
428
|
+
return copied;
|
|
419
429
|
}
|
|
420
430
|
|
|
421
431
|
function installGitHooks(packageRoot, log) {
|
|
@@ -463,4 +473,7 @@ module.exports = {
|
|
|
463
473
|
resolveConsumerTargetDir,
|
|
464
474
|
syncBuiltinSkills,
|
|
465
475
|
isConsumerInstall,
|
|
476
|
+
deployXrayConfig,
|
|
477
|
+
resolveXrayConfigSource,
|
|
478
|
+
XRAY_CONFIG_FILES,
|
|
466
479
|
};
|