0xray 3.5.5 → 4.0.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/.mcp.json +51 -7
- package/.opencode/skills/api-design/SKILL.md +1 -1
- package/.opencode/skills/architect-tools/SKILL.md +1 -1
- package/.opencode/skills/architecture-patterns/SKILL.md +1 -1
- package/.opencode/skills/auto-format/SKILL.md +1 -1
- package/.opencode/skills/boot-orchestrator/SKILL.md +2 -6
- package/.opencode/skills/bug-triage/SKILL.md +1 -1
- package/.opencode/skills/code-analyzer/SKILL.md +1 -1
- package/.opencode/skills/code-review/SKILL.md +1 -1
- package/.opencode/skills/enforcer/SKILL.md +1 -1
- package/.opencode/skills/framework-compliance-audit/SKILL.md +1 -1
- package/.opencode/skills/git-workflow/SKILL.md +1 -1
- package/.opencode/skills/hermes-agent/SKILL.md +36 -36
- package/.opencode/skills/inference-improve/SKILL.md +1 -1
- package/.opencode/skills/lint/SKILL.md +1 -1
- package/.opencode/skills/log-monitor/SKILL.md +1 -1
- package/.opencode/skills/model-health-check/SKILL.md +1 -1
- package/.opencode/skills/multimodal-looker/SKILL.md +1 -1
- package/.opencode/skills/orchestrator/SKILL.md +38 -14
- package/.opencode/skills/performance-analysis/SKILL.md +1 -1
- package/.opencode/skills/performance-optimization/SKILL.md +1 -1
- package/.opencode/skills/processor-pipeline/SKILL.md +1 -1
- package/.opencode/skills/project-analysis/SKILL.md +1 -1
- package/.opencode/skills/refactoring-strategies/SKILL.md +1 -1
- package/.opencode/skills/registry.json +65 -0
- package/.opencode/skills/researcher/SKILL.md +18 -5
- package/.opencode/skills/security-audit/SKILL.md +1 -1
- package/.opencode/skills/security-scan/SKILL.md +1 -1
- package/.opencode/skills/session-management/SKILL.md +1 -1
- package/.opencode/skills/state-manager/SKILL.md +1 -1
- package/.opencode/skills/storyteller/SKILL.md +1 -1
- package/.opencode/skills/strategist/SKILL.md +12 -0
- package/.opencode/skills/testing-best-practices/SKILL.md +37 -0
- package/.opencode/skills/testing-strategy/SKILL.md +14 -3
- package/.opencode/skills/ui-ux-design/SKILL.md +1 -1
- package/.opencode/skills/xray-orchestrator/index.ts +267 -0
- package/.xray/codex.json +12 -3
- package/.xray/features.json +27 -5
- package/.xray/features.schema.json +31 -0
- package/AGENTS-consumer.md +16 -6
- package/AGENTS.md +11 -3
- package/README.md +13 -10
- package/SKILLS.md +1 -1
- package/dist/AGENTS.md +11 -3
- package/dist/CHANGELOG.md +65 -11
- package/dist/README.md +13 -10
- package/dist/SKILLS.md +1 -1
- package/dist/cli/commands/hermes-install.js +3 -0
- package/dist/cli/commands/openclaw-install.js +14 -0
- package/dist/core/features-config.d.ts +15 -2
- package/dist/infrastructure/schemas/cloud-schemas.d.ts +1 -1
- package/dist/integrations/grok/grok-cli.d.ts +3 -0
- package/dist/integrations/grok/grok-cli.js +92 -4
- package/dist/integrations/grok/hooks/grok-hook-utils.js +53 -7
- package/dist/integrations/grok/hooks/post-tool-use.js +68 -46
- package/dist/integrations/grok/hooks/pre-tool-use.js +14 -31
- package/dist/integrations/grok/hooks/session-start.js +86 -4
- package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
- package/dist/integrations/hermes-agent/bridge.mjs +19 -1
- package/dist/integrations/hooks/delegation-gate-runtime.mjs +32 -3
- package/dist/integrations/hooks/pipeline-hook-runtime.mjs +1 -1
- package/dist/integrations/hooks/station-hook-runtime.cjs +421 -0
- package/dist/integrations/hooks/station-hook-runtime.mjs +24 -0
- package/dist/integrations/hooks/station-memory-ingest.mjs +45 -0
- package/dist/integrations/hooks/station-memory-match.mjs +47 -0
- package/dist/integrations/openclaw/client.d.ts +5 -1
- package/dist/integrations/openclaw/client.js +17 -9
- package/dist/integrations/openclaw/config.js +0 -1
- package/dist/integrations/openclaw/hooks/pre-tool-gate-runtime.mjs +102 -0
- package/dist/integrations/openclaw/index.js +17 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
- package/dist/integrations/openclaw/plugin/xray-pre-tool/package.json +10 -0
- package/dist/integrations/openclaw/pre-tool-gate.d.ts +19 -0
- package/dist/integrations/openclaw/pre-tool-gate.js +39 -0
- package/dist/mcps/orchestrator/handlers/complexity-handler.js +2 -2
- package/dist/memory-routing/index.d.ts +1 -1
- package/dist/memory-routing/index.js +1 -1
- package/dist/memory-routing/provider-loader.d.ts +4 -0
- package/dist/memory-routing/provider-loader.js +44 -2
- package/dist/memory-routing/provider-registry.js +3 -2
- package/dist/nucleus/autonomy-kernel.d.ts +2 -2
- package/dist/nucleus/autonomy-kernel.js +17 -6
- package/dist/nucleus/confer.js +17 -3
- package/dist/nucleus/delegation-gate.d.ts +14 -8
- package/dist/nucleus/delegation-gate.js +151 -16
- package/dist/nucleus/suit-temperament.d.ts +40 -0
- package/dist/nucleus/suit-temperament.js +157 -0
- package/dist/nucleus/user-aside.js +1 -1
- package/dist/plugin/xray-codex-injection.js +14 -3
- package/dist/postprocessor/triggers/GitHookTrigger.js +11 -5
- package/opencode.json +88 -0
- package/package.json +14 -4
- package/scripts/hooks/install-hooks.cjs +18 -3
- package/scripts/hooks/run-hook.js +67 -3
- package/scripts/mjs/run-repertoire-mcp.mjs +39 -0
- package/scripts/mjs/verify-confer-core.mjs +1 -1
- package/scripts/mjs/verify-delegation-gate-core.mjs +29 -2
- package/scripts/mjs/verify-four-floor-compact.mjs +524 -0
- package/scripts/mjs/verify-pipeline-facets.mjs +215 -0
- package/scripts/mjs/verify-temperament-live.mjs +261 -0
- package/scripts/node/bridge-mcp-wiring.cjs +277 -29
- package/scripts/node/install-bridges.cjs +195 -33
- package/scripts/node/postinstall.cjs +50 -27
- package/scripts/node/release-gate.mjs +1 -1
- package/scripts/node/release.mjs +2 -2
- package/scripts/node/validate-release-docs.mjs +20 -33
- package/scripts/node/version-manager.mjs +25 -10
- package/src/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
- package/src/integrations/openclaw/README.md +134 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/index.js +75 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/openclaw.plugin.json +10 -0
- package/src/integrations/openclaw/plugin/xray-pre-tool/package.json +10 -0
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +2 -1
- package/vendor/@0xray/repertoire/AGENTS.md +163 -0
- package/vendor/@0xray/repertoire/LICENSE +21 -0
- package/vendor/@0xray/repertoire/README.md +120 -0
- package/vendor/@0xray/repertoire/data/curated_signals.json +208 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts +78 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.js +153 -0
- package/vendor/@0xray/repertoire/dist/RepertoireService.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts +39 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js +60 -0
- package/vendor/@0xray/repertoire/dist/governance/ontological-trap-enforcer.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/index.d.ts +14 -0
- package/vendor/@0xray/repertoire/dist/index.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/index.js +14 -0
- package/vendor/@0xray/repertoire/dist/index.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts +26 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js +109 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-ingester.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts +18 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js +94 -0
- package/vendor/@0xray/repertoire/dist/ingestion/groover-log-parser.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts +7 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js +18 -0
- package/vendor/@0xray/repertoire/dist/ingestion/orchestrator-feedback-ingester.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts +31 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js +83 -0
- package/vendor/@0xray/repertoire/dist/ingestion/xray-session-ingester.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.d.ts +6 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.js +173 -0
- package/vendor/@0xray/repertoire/dist/mcp/server.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts +27 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js +107 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/RepertoireOrchestratorBridge.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts +11 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js +32 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/capability-enhancer.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts +9 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js +72 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/confidence-gate.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts +5 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js +18 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-agent-affinity.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts +31 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js +218 -0
- package/vendor/@0xray/repertoire/dist/orchestrator-bridge/signal-injector.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/paths.d.ts +24 -0
- package/vendor/@0xray/repertoire/dist/paths.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/paths.js +74 -0
- package/vendor/@0xray/repertoire/dist/paths.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts +141 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js +210 -0
- package/vendor/@0xray/repertoire/dist/provider/memory-routing-provider.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts +48 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js +221 -0
- package/vendor/@0xray/repertoire/dist/registry/CuratedSignalsManager.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts +11 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js +43 -0
- package/vendor/@0xray/repertoire/dist/registry/InferenceStateManager.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts +15 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.js +35 -0
- package/vendor/@0xray/repertoire/dist/registry/signal-prune.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts +3 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js +24 -0
- package/vendor/@0xray/repertoire/dist/synthesis/concrete-sections.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts +24 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js +148 -0
- package/vendor/@0xray/repertoire/dist/synthesis/meta-inference-engine.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts +4 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js +44 -0
- package/vendor/@0xray/repertoire/dist/synthesis/primitive-confidence-aggregator.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts +22 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js +66 -0
- package/vendor/@0xray/repertoire/dist/synthesis/synthesis-prompt-builder.js.map +1 -0
- package/vendor/@0xray/repertoire/dist/types.d.ts +210 -0
- package/vendor/@0xray/repertoire/dist/types.d.ts.map +1 -0
- package/vendor/@0xray/repertoire/dist/types.js +2 -0
- package/vendor/@0xray/repertoire/dist/types.js.map +1 -0
- package/vendor/@0xray/repertoire/docs/MEMORY-ROUTING-PROVIDER.md +54 -0
- package/vendor/@0xray/repertoire/hermes-mcp.example.json +20 -0
- package/vendor/@0xray/repertoire/mcp-config.example.json +11 -0
- package/vendor/@0xray/repertoire/package.json +124 -0
- package/vendor/@0xray/repertoire/schemas/curated-signal.schema.json +68 -0
- package/vendor/@0xray/repertoire/schemas/inference-log.schema.json +82 -0
- package/vendor/@0xray/repertoire/scripts/confirm-suit-all.mjs +253 -0
- package/vendor/@0xray/repertoire/scripts/confirm-suit-harness.mjs +220 -0
- package/vendor/@0xray/repertoire/scripts/run-live-synthesis-checkpoint.mjs +215 -0
- package/vendor/@0xray/repertoire/scripts/suit-bridge-shared.mjs +139 -0
- package/vendor/@0xray/repertoire/scripts/verify-grok-suit.mjs +304 -0
- package/vendor/@0xray/repertoire/scripts/verify-hermes-suit.mjs +163 -0
- package/vendor/@0xray/repertoire/scripts/verify-openclaw-suit.mjs +125 -0
- package/vendor/@0xray/repertoire/scripts/verify-opencode-suit.mjs +127 -0
- package/vendor/@0xray/repertoire/scripts/verify-synthesis-dogfood.mjs +207 -0
- package/vendor/@0xray/repertoire/skills/repertoire-trap-handling/SKILL.md +206 -0
- package/xray/codex.json +12 -3
- package/xray/features.json +27 -5
- package/xray/features.schema.json +31 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Multi-host delegation gate SSOT — pending-delegations + spawn todo enforcement.
|
|
3
3
|
* Grok / Hermes / OpenCode adapters call evaluatePreToolGate via delegation-gate-runtime.
|
|
4
|
-
*
|
|
4
|
+
* Constitution (11/29/69 + destructive shell) lives here. Grok may still extra-block Codex 2/7.
|
|
5
5
|
*/
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
@@ -13,6 +13,8 @@ import { isSynthesisConsultTodoId, tryRecordSynthesisConsultReceipt, } from './s
|
|
|
13
13
|
import { resolveSpawnPlan, hasValidSpawnPlanContext } from './spawn-plan-resolution.js';
|
|
14
14
|
import { isUserAsidesEnabled, isUserAsideTodoId, loadActiveAsidePointer, loadActiveUserAside, } from './user-aside.js';
|
|
15
15
|
import { validateAsideWorktreeCwd, } from './aside-worktree.js';
|
|
16
|
+
import { ceremonyForProfile, resolveSuitProfile, spawnPlanModeForProfile, writeSuitSessionBoot, maybeHeatHostStation, } from './suit-temperament.js';
|
|
17
|
+
export { writeSuitSessionBoot, maybeHeatHostStation };
|
|
16
18
|
export { extractSpawnCwd, validateAsideWorktreeCwd, provisionGitWorktree } from './aside-worktree.js';
|
|
17
19
|
function denyAsideWorktreeCwd(cwdCheck) {
|
|
18
20
|
const base = {
|
|
@@ -30,7 +32,7 @@ function asideWorktreeCwdDenyIfNeeded(activeAside, toolInput, projectRoot) {
|
|
|
30
32
|
return denyAsideWorktreeCwd(cwdCheck);
|
|
31
33
|
return undefined;
|
|
32
34
|
}
|
|
33
|
-
export { validateSpawnMatchesTodo, updatePlanTodoStatus, savePersistedLeadDevPlan, } from './lead-dev-plan-persistence.js';
|
|
35
|
+
export { validateSpawnMatchesTodo, updatePlanTodoStatus, savePersistedLeadDevPlan, archiveStaleLeadDevPlan, findRecentStalePlanArchive, } from './lead-dev-plan-persistence.js';
|
|
34
36
|
export { buildReceiptFromConsultOutput, hasValidSynthesisConsultReceipt, isSynthesisConsultTodoId, loadSynthesisConsultReceipt, parseConsultVerdictFromText, tryRecordSynthesisConsultReceipt, writeSynthesisConsultReceipt, } from './synthesis-consult-receipt.js';
|
|
35
37
|
export const updatePlanTodoStatusInPlace = updatePlanTodoStatus;
|
|
36
38
|
const READ_TOOLS = new Set([
|
|
@@ -69,21 +71,34 @@ const SYNTHESIS_ALLOWED_CONSULT_TOOLS = new Set([
|
|
|
69
71
|
]);
|
|
70
72
|
const HERMES_WRITE_TOOLS = new Set(['write_file', 'patch', 'write', 'edit']);
|
|
71
73
|
const OPENCODE_WRITE_TOOLS = new Set(['write', 'edit', 'multiedit']);
|
|
72
|
-
export function loadDelegationGateFeatures(projectRoot = process.cwd()) {
|
|
74
|
+
export function loadDelegationGateFeatures(projectRoot = process.cwd(), host = 'generic') {
|
|
75
|
+
const fallback = (profile) => ({
|
|
76
|
+
lead_dev_mode: true,
|
|
77
|
+
auto_chain_delegations: true,
|
|
78
|
+
spawn_plan_mode: spawnPlanModeForProfile(profile),
|
|
79
|
+
ceremony: ceremonyForProfile(profile),
|
|
80
|
+
suit_profile: profile,
|
|
81
|
+
no_new_surface: true,
|
|
82
|
+
});
|
|
73
83
|
const featuresPath = path.join(projectRoot, '.xray', 'features.json');
|
|
74
84
|
if (!fs.existsSync(featuresPath)) {
|
|
75
|
-
return
|
|
85
|
+
return fallback(resolveSuitProfile(undefined, host));
|
|
76
86
|
}
|
|
77
87
|
try {
|
|
78
88
|
const data = JSON.parse(fs.readFileSync(featuresPath, 'utf8'));
|
|
79
89
|
const orch = data.multi_agent_orchestration ?? {};
|
|
90
|
+
const profile = resolveSuitProfile(data.suit_temperament, host);
|
|
80
91
|
return {
|
|
81
92
|
lead_dev_mode: orch.enabled !== false && orch.lead_dev_mode !== false,
|
|
82
93
|
auto_chain_delegations: orch.auto_chain_delegations !== false,
|
|
94
|
+
spawn_plan_mode: spawnPlanModeForProfile(profile),
|
|
95
|
+
ceremony: ceremonyForProfile(profile),
|
|
96
|
+
suit_profile: profile,
|
|
97
|
+
no_new_surface: profile === 'strict' ? true : orch.no_new_surface !== false,
|
|
83
98
|
};
|
|
84
99
|
}
|
|
85
100
|
catch {
|
|
86
|
-
return
|
|
101
|
+
return fallback(resolveSuitProfile(undefined, host));
|
|
87
102
|
}
|
|
88
103
|
}
|
|
89
104
|
export function normalizeHostToolInput(toolInput) {
|
|
@@ -197,40 +212,53 @@ function denyFromPending(primary, pendingCount) {
|
|
|
197
212
|
delegationId: primary.id,
|
|
198
213
|
};
|
|
199
214
|
}
|
|
215
|
+
function spawnPlanSoftAllow(gate, reason) {
|
|
216
|
+
return { allow: true, reason, gate };
|
|
217
|
+
}
|
|
200
218
|
/** Spawn plan missing — applies before auto_chain opt-out for subagent tools. */
|
|
201
219
|
export function evaluateSpawnPlanGate(toolName, toolInput, ctx) {
|
|
202
220
|
if (!ctx.features.lead_dev_mode || !isSubagentTool(toolName)) {
|
|
203
221
|
return { allow: true };
|
|
204
222
|
}
|
|
223
|
+
const spawnMode = ctx.features.spawn_plan_mode ?? 'deny';
|
|
224
|
+
if (spawnMode === 'off') {
|
|
225
|
+
return { allow: true };
|
|
226
|
+
}
|
|
205
227
|
const activeAside = isUserAsidesEnabled(ctx.projectRoot)
|
|
206
228
|
? loadActiveUserAside(ctx.projectRoot, ctx.sessionId)
|
|
207
229
|
: null;
|
|
208
230
|
const plan = loadPersistedLeadDevPlan(ctx.projectRoot);
|
|
209
231
|
if (!activeAside && plan && isLeadDevPlanStale(plan, ctx.projectRoot)) {
|
|
210
|
-
|
|
211
|
-
allow: false,
|
|
232
|
+
const stale = {
|
|
212
233
|
reason: 'Lead-dev plan is stale (unstarted todos exceeded TTL) — ' +
|
|
213
234
|
're-run xray-orchestrator analyze-complexity to refresh the plan',
|
|
214
235
|
gate: 'spawn-plan-stale',
|
|
215
236
|
hint: { tool: 'analyze-complexity', mcp: 'xray-orchestrator' },
|
|
216
237
|
};
|
|
238
|
+
if (spawnMode === 'warn')
|
|
239
|
+
return spawnPlanSoftAllow(stale.gate, stale.reason);
|
|
240
|
+
return { allow: false, ...stale };
|
|
217
241
|
}
|
|
218
242
|
if (!hasValidSpawnPlanContext(ctx.projectRoot, ctx.sessionId)) {
|
|
219
243
|
if (findRecentStalePlanArchive(ctx.projectRoot)) {
|
|
220
|
-
|
|
221
|
-
allow: false,
|
|
244
|
+
const archived = {
|
|
222
245
|
reason: 'Lead-dev plan was stale and archived — ' +
|
|
223
246
|
're-run xray-orchestrator analyze-complexity to refresh the plan',
|
|
224
247
|
gate: 'spawn-plan-stale',
|
|
225
248
|
hint: { tool: 'analyze-complexity', mcp: 'xray-orchestrator' },
|
|
226
249
|
};
|
|
250
|
+
if (spawnMode === 'warn')
|
|
251
|
+
return spawnPlanSoftAllow(archived.gate, archived.reason);
|
|
252
|
+
return { allow: false, ...archived };
|
|
227
253
|
}
|
|
228
|
-
|
|
229
|
-
allow: false,
|
|
254
|
+
const missing = {
|
|
230
255
|
reason: 'Codex 59/67: call xray-orchestrator analyze-complexity first — ' +
|
|
231
256
|
'writes .xray/state/lead-dev-plan.json required before spawn_subagent',
|
|
232
257
|
gate: 'spawn-plan-missing',
|
|
233
258
|
};
|
|
259
|
+
if (spawnMode === 'warn')
|
|
260
|
+
return spawnPlanSoftAllow(missing.gate, missing.reason);
|
|
261
|
+
return { allow: false, ...missing };
|
|
234
262
|
}
|
|
235
263
|
if (ctx.features.auto_chain_delegations === false) {
|
|
236
264
|
const cwdDeny = asideWorktreeCwdDenyIfNeeded(activeAside, toolInput, ctx.projectRoot);
|
|
@@ -246,13 +274,16 @@ export function evaluateSpawnPlanGate(toolName, toolInput, ctx) {
|
|
|
246
274
|
const expectedTodo = pending[0]?.planTodoId && resolved.plan
|
|
247
275
|
? allPlanTodos(resolved.plan).find((t) => t.id === pending[0].planTodoId) ?? null
|
|
248
276
|
: null;
|
|
277
|
+
const cwdDeny = asideWorktreeCwdDenyIfNeeded(activeAside, toolInput, ctx.projectRoot);
|
|
278
|
+
if (cwdDeny)
|
|
279
|
+
return cwdDeny;
|
|
249
280
|
const validation = validateSpawnMatchesTodo(normalized, ctx.projectRoot, expectedTodo, ctx.sessionId);
|
|
250
281
|
if (!validation.valid) {
|
|
282
|
+
if (spawnMode === 'warn') {
|
|
283
|
+
return spawnPlanSoftAllow(validation.gate ?? 'spawn-todo-persistence', validation.reason ?? 'Spawn did not match lead-dev plan todo (frontier: warn, not deny)');
|
|
284
|
+
}
|
|
251
285
|
return denyFromSpawnValidation(validation);
|
|
252
286
|
}
|
|
253
|
-
const cwdDeny = asideWorktreeCwdDenyIfNeeded(activeAside, toolInput, ctx.projectRoot);
|
|
254
|
-
if (cwdDeny)
|
|
255
|
-
return cwdDeny;
|
|
256
287
|
return { allow: true };
|
|
257
288
|
}
|
|
258
289
|
/** Block writes / spawns / shell while synthesis checkpoint is due. */
|
|
@@ -346,8 +377,110 @@ export function evaluatePendingDelegationGate(toolName, toolInput, ctx) {
|
|
|
346
377
|
* Full pre-tool evaluation — synthesis gate first, slice recording, then
|
|
347
378
|
* pending gate, then spawn todo gate for subagent tools.
|
|
348
379
|
*/
|
|
380
|
+
const CONSTITUTION_ANY = /:\s*any\b|as\s+any\b/;
|
|
381
|
+
const CONSTITUTION_TS_IGNORE = /@ts-ignore|@ts-expect-error/;
|
|
382
|
+
const CONSTITUTION_EVAL = /\beval\s*\(/;
|
|
383
|
+
const CONSTITUTION_DESTRUCTIVE = /\brm\s+-rf\s+\/(?:\s|$)|\bmkfs\b|\bdd\s+if=|:()\s*\{\s*:\|&\s*\}\s*;:/i;
|
|
384
|
+
const SURFACE_DENY = [
|
|
385
|
+
/(?:^|\/)src\/mcps\/[^/]+\.server\.(ts|js)$/i,
|
|
386
|
+
/(?:^|\/)src\/skills\/[^/]+\/SKILL\.md$/i,
|
|
387
|
+
/(?:^|\/)src\/mcps\/orchestrator\/handlers\/[^/]+-handler\.(ts|js)$/i,
|
|
388
|
+
/(?:^|\/)src\/nucleus\/autonomy-kernel\.(ts|js)$/i,
|
|
389
|
+
/(?:^|\/)src\/mcps\/[^/]+\/handlers\/autonomy-handler\.(ts|js)$/i,
|
|
390
|
+
];
|
|
391
|
+
function collectWriteContent(toolInput) {
|
|
392
|
+
return [
|
|
393
|
+
toolInput.new_string,
|
|
394
|
+
toolInput.contents,
|
|
395
|
+
toolInput.content,
|
|
396
|
+
toolInput.command,
|
|
397
|
+
toolInput.prompt,
|
|
398
|
+
]
|
|
399
|
+
.filter((v) => v != null)
|
|
400
|
+
.map(String)
|
|
401
|
+
.join('\n');
|
|
402
|
+
}
|
|
403
|
+
function collectWritePaths(toolInput) {
|
|
404
|
+
const paths = [];
|
|
405
|
+
for (const key of ['path', 'file_path', 'filePath', 'target_notebook']) {
|
|
406
|
+
const v = toolInput[key];
|
|
407
|
+
if (typeof v === 'string' && v)
|
|
408
|
+
paths.push(v);
|
|
409
|
+
}
|
|
410
|
+
const extra = toolInput.paths;
|
|
411
|
+
if (Array.isArray(extra)) {
|
|
412
|
+
for (const p of extra) {
|
|
413
|
+
if (typeof p === 'string' && p)
|
|
414
|
+
paths.push(p);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
return paths;
|
|
418
|
+
}
|
|
419
|
+
/** Codex 11 / 29 / 69 + destructive shell — always on, all hosts that call this SSOT. */
|
|
420
|
+
export function evaluateConstitutionGate(toolName, toolInput, ctx) {
|
|
421
|
+
const content = collectWriteContent(toolInput);
|
|
422
|
+
const paths = collectWritePaths(toolInput);
|
|
423
|
+
const writing = isWriteTool(toolName, ctx.host ?? 'generic');
|
|
424
|
+
if (writing && ctx.features.no_new_surface !== false) {
|
|
425
|
+
for (const p of paths) {
|
|
426
|
+
const normalized = p.replace(/\\/g, '/');
|
|
427
|
+
const abs = path.isAbsolute(p) ? p : path.join(ctx.projectRoot, p);
|
|
428
|
+
if (fs.existsSync(abs))
|
|
429
|
+
continue;
|
|
430
|
+
if (SURFACE_DENY.some((re) => re.test(normalized))) {
|
|
431
|
+
return {
|
|
432
|
+
allow: false,
|
|
433
|
+
reason: 'Codex 69: new MCP/skill/handler surface — rewire existing',
|
|
434
|
+
gate: 'no-new-surface',
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (writing && content) {
|
|
440
|
+
if (CONSTITUTION_ANY.test(content) || CONSTITUTION_TS_IGNORE.test(content)) {
|
|
441
|
+
return {
|
|
442
|
+
allow: false,
|
|
443
|
+
reason: 'Codex 11 Type Safety: no `any` / @ts-ignore / @ts-expect-error',
|
|
444
|
+
gate: 'codex-11',
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
if (CONSTITUTION_EVAL.test(content)) {
|
|
448
|
+
return {
|
|
449
|
+
allow: false,
|
|
450
|
+
reason: 'Codex 29 Security: eval() prohibited',
|
|
451
|
+
gate: 'codex-29',
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (isShellTool(toolName) && CONSTITUTION_DESTRUCTIVE.test(String(toolInput.command ?? ''))) {
|
|
456
|
+
return {
|
|
457
|
+
allow: false,
|
|
458
|
+
reason: 'Blocked destructive shell command',
|
|
459
|
+
gate: 'destructive-shell',
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
return { allow: true };
|
|
463
|
+
}
|
|
349
464
|
export function evaluatePreToolGate(toolName, toolInput, ctx) {
|
|
350
|
-
|
|
465
|
+
if (ctx.host === 'openclaw') {
|
|
466
|
+
try {
|
|
467
|
+
maybeHeatHostStation(ctx.projectRoot, 'openclaw', {
|
|
468
|
+
source: '0xray/openclaw-pre-tool',
|
|
469
|
+
sessionId: ctx.sessionId || 'openclaw',
|
|
470
|
+
hookEvent: ctx.hookEvent || 'session_start',
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
catch {
|
|
474
|
+
/* station heat is best-effort — constitution still runs */
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
const constitution = evaluateConstitutionGate(toolName, toolInput, ctx);
|
|
478
|
+
if (!constitution.allow)
|
|
479
|
+
return constitution;
|
|
480
|
+
const lite = ctx.features.ceremony === 'lite';
|
|
481
|
+
const synthesisBlock = lite
|
|
482
|
+
? { allow: true }
|
|
483
|
+
: evaluateSynthesisGate(toolName, toolInput, ctx);
|
|
351
484
|
if (!synthesisBlock.allow)
|
|
352
485
|
return synthesisBlock;
|
|
353
486
|
if (!isSynthesisCheckpointDue(ctx.projectRoot, ctx.sessionId)) {
|
|
@@ -356,7 +489,9 @@ export function evaluatePreToolGate(toolName, toolInput, ctx) {
|
|
|
356
489
|
sessionId: ctx.sessionId,
|
|
357
490
|
});
|
|
358
491
|
}
|
|
359
|
-
const pendingBlock =
|
|
492
|
+
const pendingBlock = lite
|
|
493
|
+
? { allow: true }
|
|
494
|
+
: evaluatePendingDelegationGate(toolName, toolInput, ctx);
|
|
360
495
|
if (!pendingBlock.allow)
|
|
361
496
|
return pendingBlock;
|
|
362
497
|
const spawnBlock = evaluateSpawnPlanGate(toolName, toolInput, ctx);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0xRay 4.0 suit temperament — how loudly the Autonomous Engine insists.
|
|
3
|
+
*
|
|
4
|
+
* v2 three-subsystem OS stays: Inference · External Governance · Autonomous Engine.
|
|
5
|
+
* This module does not replace thinDispatch or Codex. It only scales *ceremony*
|
|
6
|
+
* (spawn-plan deny, synthesis, confer) by host strength.
|
|
7
|
+
*
|
|
8
|
+
* Frontier (Grok 4.6 / Grok Build): engine available, spawn warns if no plan.
|
|
9
|
+
* Guided (OpenCode / Hermes / OpenClaw, including free models): full v2 ceremony.
|
|
10
|
+
* Missing config → guided (existing consumers unchanged).
|
|
11
|
+
*/
|
|
12
|
+
export type SuitHost = 'grok' | 'hermes' | 'opencode' | 'openclaw' | 'generic';
|
|
13
|
+
export type SuitProfile = 'frontier' | 'guided' | 'strict';
|
|
14
|
+
export type SuitProfileOrAuto = 'auto' | SuitProfile;
|
|
15
|
+
export type CeremonyLevel = 'full' | 'lite';
|
|
16
|
+
export type SpawnPlanMode = 'deny' | 'warn' | 'off';
|
|
17
|
+
export interface SuitTemperamentConfig {
|
|
18
|
+
/** auto = pick from host_defaults */
|
|
19
|
+
profile?: SuitProfileOrAuto;
|
|
20
|
+
host_defaults?: Partial<Record<SuitHost, SuitProfile>>;
|
|
21
|
+
}
|
|
22
|
+
export declare const DEFAULT_HOST_PROFILES: Record<SuitHost, SuitProfile>;
|
|
23
|
+
export declare function loadSuitTemperamentRaw(projectRoot: string): SuitTemperamentConfig | undefined;
|
|
24
|
+
export declare function resolveSuitProfile(raw: SuitTemperamentConfig | undefined, host: SuitHost): SuitProfile;
|
|
25
|
+
/**
|
|
26
|
+
* Host-aware when known. Kernel/MCP (`generic`) uses last session-boot profile.
|
|
27
|
+
* A Hermes/OpenCode host ignores a leftover Grok boot (and vice versa).
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveRuntimeSuitProfile(projectRoot: string, host?: SuitHost): SuitProfile;
|
|
30
|
+
/**
|
|
31
|
+
* Write station heat when this host/session has no live card yet.
|
|
32
|
+
* OpenClaw has no SessionStart — PreToolUse is the session boundary.
|
|
33
|
+
* Install/init cards without a session id are not a live session.
|
|
34
|
+
*/
|
|
35
|
+
export declare function maybeHeatHostStation(projectRoot: string, host: SuitHost, extra?: Record<string, unknown>): string | null;
|
|
36
|
+
/** Merge temperament fields into session-boot.json for the host that just started. */
|
|
37
|
+
export declare function writeSuitSessionBoot(projectRoot: string, host: SuitHost, extra?: Record<string, unknown>): string;
|
|
38
|
+
export declare function ceremonyForProfile(profile: SuitProfile): CeremonyLevel;
|
|
39
|
+
export declare function spawnPlanModeForProfile(profile: SuitProfile): SpawnPlanMode;
|
|
40
|
+
export declare function conferDefaultForProfile(profile: SuitProfile): boolean;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0xRay 4.0 suit temperament — how loudly the Autonomous Engine insists.
|
|
3
|
+
*
|
|
4
|
+
* v2 three-subsystem OS stays: Inference · External Governance · Autonomous Engine.
|
|
5
|
+
* This module does not replace thinDispatch or Codex. It only scales *ceremony*
|
|
6
|
+
* (spawn-plan deny, synthesis, confer) by host strength.
|
|
7
|
+
*
|
|
8
|
+
* Frontier (Grok 4.6 / Grok Build): engine available, spawn warns if no plan.
|
|
9
|
+
* Guided (OpenCode / Hermes / OpenClaw, including free models): full v2 ceremony.
|
|
10
|
+
* Missing config → guided (existing consumers unchanged).
|
|
11
|
+
*/
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import * as path from 'path';
|
|
14
|
+
import { createRequire } from 'node:module';
|
|
15
|
+
const requireCjs = createRequire(import.meta.url);
|
|
16
|
+
const stationHeat = requireCjs('../integrations/hooks/station-hook-runtime.cjs');
|
|
17
|
+
export const DEFAULT_HOST_PROFILES = {
|
|
18
|
+
grok: 'frontier',
|
|
19
|
+
hermes: 'guided',
|
|
20
|
+
opencode: 'guided',
|
|
21
|
+
openclaw: 'guided',
|
|
22
|
+
generic: 'guided',
|
|
23
|
+
};
|
|
24
|
+
function isSuitProfile(value) {
|
|
25
|
+
return value === 'frontier' || value === 'guided' || value === 'strict';
|
|
26
|
+
}
|
|
27
|
+
export function loadSuitTemperamentRaw(projectRoot) {
|
|
28
|
+
const featuresPath = path.join(projectRoot, '.xray', 'features.json');
|
|
29
|
+
if (!fs.existsSync(featuresPath))
|
|
30
|
+
return undefined;
|
|
31
|
+
try {
|
|
32
|
+
const data = JSON.parse(fs.readFileSync(featuresPath, 'utf8'));
|
|
33
|
+
return data.suit_temperament;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function isSuitHost(value) {
|
|
40
|
+
return (value === 'grok' ||
|
|
41
|
+
value === 'hermes' ||
|
|
42
|
+
value === 'opencode' ||
|
|
43
|
+
value === 'openclaw' ||
|
|
44
|
+
value === 'generic');
|
|
45
|
+
}
|
|
46
|
+
function readSessionBoot(projectRoot) {
|
|
47
|
+
try {
|
|
48
|
+
const bootPath = path.join(projectRoot, '.xray', 'state', 'session-boot.json');
|
|
49
|
+
if (!fs.existsSync(bootPath))
|
|
50
|
+
return null;
|
|
51
|
+
const boot = JSON.parse(fs.readFileSync(bootPath, 'utf8'));
|
|
52
|
+
return {
|
|
53
|
+
host: isSuitHost(boot.host) ? boot.host : null,
|
|
54
|
+
suit_profile: isSuitProfile(boot.suit_profile) ? boot.suit_profile : null,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function resolveSuitProfile(raw, host) {
|
|
62
|
+
// No key / empty object without profile → guided (existing consumers).
|
|
63
|
+
if (!raw || !raw.profile)
|
|
64
|
+
return 'guided';
|
|
65
|
+
if (raw.profile !== 'auto') {
|
|
66
|
+
return raw.profile;
|
|
67
|
+
}
|
|
68
|
+
const defaults = {
|
|
69
|
+
...DEFAULT_HOST_PROFILES,
|
|
70
|
+
...(raw.host_defaults ?? {}),
|
|
71
|
+
};
|
|
72
|
+
return defaults[host] ?? 'guided';
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Host-aware when known. Kernel/MCP (`generic`) uses last session-boot profile.
|
|
76
|
+
* A Hermes/OpenCode host ignores a leftover Grok boot (and vice versa).
|
|
77
|
+
*/
|
|
78
|
+
export function resolveRuntimeSuitProfile(projectRoot, host = 'generic') {
|
|
79
|
+
const raw = loadSuitTemperamentRaw(projectRoot);
|
|
80
|
+
const boot = readSessionBoot(projectRoot);
|
|
81
|
+
if (raw?.profile === 'auto' && boot?.suit_profile) {
|
|
82
|
+
if (host === 'generic' || boot.host == null || boot.host === host) {
|
|
83
|
+
return boot.suit_profile;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return resolveSuitProfile(raw, host);
|
|
87
|
+
}
|
|
88
|
+
function concreteSessionId(value) {
|
|
89
|
+
return typeof value === 'string' && value.length > 0 ? value : null;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Write station heat when this host/session has no live card yet.
|
|
93
|
+
* OpenClaw has no SessionStart — PreToolUse is the session boundary.
|
|
94
|
+
* Install/init cards without a session id are not a live session.
|
|
95
|
+
*/
|
|
96
|
+
export function maybeHeatHostStation(projectRoot, host, extra = {}) {
|
|
97
|
+
const bootPath = path.join(projectRoot, '.xray', 'state', 'session-boot.json');
|
|
98
|
+
const cardPath = path.join(projectRoot, '.xray', 'state', 'STATION.md');
|
|
99
|
+
let existing = {};
|
|
100
|
+
if (fs.existsSync(bootPath)) {
|
|
101
|
+
try {
|
|
102
|
+
existing = JSON.parse(fs.readFileSync(bootPath, 'utf8'));
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
existing = {};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const sessionId = concreteSessionId(extra.sessionId);
|
|
109
|
+
const existingSessionId = concreteSessionId(existing.sessionId);
|
|
110
|
+
const sameHost = existing.host === host;
|
|
111
|
+
const sameSession = existingSessionId !== null && sessionId !== null && existingSessionId === sessionId;
|
|
112
|
+
if (sameHost && sameSession && fs.existsSync(cardPath)) {
|
|
113
|
+
return bootPath;
|
|
114
|
+
}
|
|
115
|
+
return writeSuitSessionBoot(projectRoot, host, extra);
|
|
116
|
+
}
|
|
117
|
+
/** Merge temperament fields into session-boot.json for the host that just started. */
|
|
118
|
+
export function writeSuitSessionBoot(projectRoot, host, extra = {}) {
|
|
119
|
+
const profile = resolveSuitProfile(loadSuitTemperamentRaw(projectRoot), host);
|
|
120
|
+
const stateDir = path.join(projectRoot, '.xray', 'state');
|
|
121
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
122
|
+
const bootPath = path.join(stateDir, 'session-boot.json');
|
|
123
|
+
let existing = {};
|
|
124
|
+
if (fs.existsSync(bootPath)) {
|
|
125
|
+
try {
|
|
126
|
+
existing = JSON.parse(fs.readFileSync(bootPath, 'utf8'));
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
existing = {};
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const heat = stationHeat.applyStationHeat(projectRoot, host, extra, existing);
|
|
133
|
+
const payload = {
|
|
134
|
+
...existing,
|
|
135
|
+
...extra,
|
|
136
|
+
...heat,
|
|
137
|
+
host,
|
|
138
|
+
suit_profile: profile,
|
|
139
|
+
ceremony: ceremonyForProfile(profile),
|
|
140
|
+
spawn_plan_mode: spawnPlanModeForProfile(profile),
|
|
141
|
+
timestamp: new Date().toISOString(),
|
|
142
|
+
};
|
|
143
|
+
fs.writeFileSync(bootPath, JSON.stringify(payload, null, 2));
|
|
144
|
+
stationHeat.writeStationMarkdown(projectRoot, payload);
|
|
145
|
+
return bootPath;
|
|
146
|
+
}
|
|
147
|
+
export function ceremonyForProfile(profile) {
|
|
148
|
+
return profile === 'frontier' ? 'lite' : 'full';
|
|
149
|
+
}
|
|
150
|
+
export function spawnPlanModeForProfile(profile) {
|
|
151
|
+
if (profile === 'frontier')
|
|
152
|
+
return 'warn';
|
|
153
|
+
return 'deny';
|
|
154
|
+
}
|
|
155
|
+
export function conferDefaultForProfile(profile) {
|
|
156
|
+
return profile !== 'frontier';
|
|
157
|
+
}
|
|
@@ -119,7 +119,7 @@ export function buildUserAsidePlan(asideId, title, description, taskInputs = [],
|
|
|
119
119
|
return null;
|
|
120
120
|
const safeId = assertSafeAsideId(asideId);
|
|
121
121
|
const taskTypes = taskInputs.map((t) => t.type ?? 'implement');
|
|
122
|
-
const basePlan = buildLeadDevPlan(description, taskTypes, taskInputs, mcpOverallComplexity);
|
|
122
|
+
const basePlan = buildLeadDevPlan(description, taskTypes, taskInputs, mcpOverallComplexity, projectRoot);
|
|
123
123
|
if (!basePlan)
|
|
124
124
|
return null;
|
|
125
125
|
return {
|
|
@@ -7,7 +7,7 @@ import { getOrCreateLogger } from "./plugin-logger.js";
|
|
|
7
7
|
import { resolveStateDir, importSystemPromptGenerator, loadXrayComponents, getProcessorManager, getXrayStateManager, getFeaturesConfigLoader, getDetectTaskType, getSystemPromptGenerator, } from "./plugin-modules.js";
|
|
8
8
|
import { getFrameworkIdentity, classifyTaskType, isWriteEditOperation, isPublishOperation, resolveAgentName, registerAllProcessors, registerAfterPostProcessors, logPreProcessorResults, logPostProcessorResults, logTestAutoCreationResult, spawnPromise, } from "./plugin-helpers.js";
|
|
9
9
|
import { runEnforcerQualityGate } from "./plugin-quality-gate.js";
|
|
10
|
-
import { evaluatePostToolSpawn, evaluatePreToolGate, isSubagentTool, loadDelegationGateFeatures, } from "../nucleus/delegation-gate.js";
|
|
10
|
+
import { evaluatePostToolSpawn, evaluatePreToolGate, isSubagentTool, loadDelegationGateFeatures, writeSuitSessionBoot, } from "../nucleus/delegation-gate.js";
|
|
11
11
|
import { readFileSync } from "fs";
|
|
12
12
|
import { join } from "path";
|
|
13
13
|
// Re-export all public API for test compatibility
|
|
@@ -23,6 +23,15 @@ let _lastTuneToolCallCount = 0;
|
|
|
23
23
|
export default async function xrayCodexPlugin(input) {
|
|
24
24
|
const { directory: inputDirectory } = input;
|
|
25
25
|
const directory = inputDirectory || process.cwd();
|
|
26
|
+
try {
|
|
27
|
+
writeSuitSessionBoot(directory, "opencode", {
|
|
28
|
+
source: "0xray/opencode-plugin",
|
|
29
|
+
hookEvent: process.env.XRAY_HOOK_EVENT || "session_start",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
/* session-boot is best-effort */
|
|
34
|
+
}
|
|
26
35
|
return {
|
|
27
36
|
"experimental.chat.system.transform": async (_input, output) => {
|
|
28
37
|
try {
|
|
@@ -40,7 +49,9 @@ export default async function xrayCodexPlugin(input) {
|
|
|
40
49
|
});
|
|
41
50
|
}
|
|
42
51
|
if (output.system && Array.isArray(output.system)) {
|
|
43
|
-
|
|
52
|
+
const cardPath = path.join(directory, ".xray", "state", "STATION.md");
|
|
53
|
+
const card = fs.existsSync(cardPath) ? fs.readFileSync(cardPath, "utf8").trim() : "";
|
|
54
|
+
output.system = card ? [leanPrompt, card] : [leanPrompt];
|
|
44
55
|
}
|
|
45
56
|
}
|
|
46
57
|
catch (error) {
|
|
@@ -84,7 +95,7 @@ export default async function xrayCodexPlugin(input) {
|
|
|
84
95
|
throw new Error(`ENFORCER BLOCKED: ${qualityGateResult.violations.join("; ")}`);
|
|
85
96
|
}
|
|
86
97
|
logger.log(`✅ Quality gate passed for ${tool}`);
|
|
87
|
-
const features = loadDelegationGateFeatures(directory);
|
|
98
|
+
const features = loadDelegationGateFeatures(directory, "opencode");
|
|
88
99
|
let sessionId = process.env.GROK_SESSION_ID ?? null;
|
|
89
100
|
try {
|
|
90
101
|
const boot = JSON.parse(readFileSync(join(directory, ".xray", "state", "session-boot.json"), "utf8"));
|
|
@@ -397,10 +397,16 @@ fi
|
|
|
397
397
|
(async () => {
|
|
398
398
|
try {
|
|
399
399
|
// Use dynamic import that works in both dev and consumer
|
|
400
|
-
const
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
const
|
|
400
|
+
const { pathToFileURL } = await import('url');
|
|
401
|
+
const { existsSync } = await import('fs');
|
|
402
|
+
const { join } = await import('path');
|
|
403
|
+
const candidates = [
|
|
404
|
+
join(process.cwd(), 'node_modules/0xray/dist/postprocessor/triggers/GitHookTrigger.js'),
|
|
405
|
+
join(process.cwd(), 'dist/postprocessor/triggers/GitHookTrigger.js'),
|
|
406
|
+
];
|
|
407
|
+
const triggerPath = candidates.find((p) => existsSync(p));
|
|
408
|
+
if (!triggerPath) return;
|
|
409
|
+
const { archiveLogFiles } = await import(pathToFileURL(triggerPath).href);
|
|
404
410
|
const archiveResult = await archiveLogFiles({
|
|
405
411
|
archiveDirectory: 'logs/framework',
|
|
406
412
|
maxFileSizeMB: 10, // Archive if > 10MB
|
|
@@ -415,7 +421,7 @@ fi
|
|
|
415
421
|
}
|
|
416
422
|
|
|
417
423
|
// Then cleanup old files
|
|
418
|
-
const { cleanupLogFiles } = await import(
|
|
424
|
+
const { cleanupLogFiles } = await import(pathToFileURL(triggerPath).href);
|
|
419
425
|
const result = await cleanupLogFiles({
|
|
420
426
|
maxAgeHours: 24,
|
|
421
427
|
excludePatterns: [
|
package/opencode.json
CHANGED
|
@@ -16,6 +16,94 @@
|
|
|
16
16
|
},
|
|
17
17
|
"global-git": {
|
|
18
18
|
"enabled": false
|
|
19
|
+
},
|
|
20
|
+
"xray-governance": {
|
|
21
|
+
"type": "local",
|
|
22
|
+
"command": [
|
|
23
|
+
"npx",
|
|
24
|
+
"-y",
|
|
25
|
+
"0xray",
|
|
26
|
+
"mcp",
|
|
27
|
+
"governance"
|
|
28
|
+
],
|
|
29
|
+
"enabled": true,
|
|
30
|
+
"environment": {
|
|
31
|
+
"XRAY_FORCE_MCP_GOVERNANCE": "true"
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
"xray-skills": {
|
|
35
|
+
"type": "local",
|
|
36
|
+
"command": [
|
|
37
|
+
"npx",
|
|
38
|
+
"-y",
|
|
39
|
+
"0xray",
|
|
40
|
+
"mcp",
|
|
41
|
+
"skills"
|
|
42
|
+
],
|
|
43
|
+
"enabled": true
|
|
44
|
+
},
|
|
45
|
+
"xray-orchestrator": {
|
|
46
|
+
"type": "local",
|
|
47
|
+
"command": [
|
|
48
|
+
"npx",
|
|
49
|
+
"-y",
|
|
50
|
+
"0xray",
|
|
51
|
+
"mcp",
|
|
52
|
+
"orchestrator"
|
|
53
|
+
],
|
|
54
|
+
"enabled": true
|
|
55
|
+
},
|
|
56
|
+
"xray-enforcer": {
|
|
57
|
+
"type": "local",
|
|
58
|
+
"command": [
|
|
59
|
+
"npx",
|
|
60
|
+
"-y",
|
|
61
|
+
"0xray",
|
|
62
|
+
"mcp",
|
|
63
|
+
"enforcer"
|
|
64
|
+
],
|
|
65
|
+
"enabled": true
|
|
66
|
+
},
|
|
67
|
+
"xray-researcher": {
|
|
68
|
+
"type": "local",
|
|
69
|
+
"command": [
|
|
70
|
+
"npx",
|
|
71
|
+
"-y",
|
|
72
|
+
"0xray",
|
|
73
|
+
"mcp",
|
|
74
|
+
"researcher"
|
|
75
|
+
],
|
|
76
|
+
"enabled": true
|
|
77
|
+
},
|
|
78
|
+
"xray-code-review": {
|
|
79
|
+
"type": "local",
|
|
80
|
+
"command": [
|
|
81
|
+
"npx",
|
|
82
|
+
"-y",
|
|
83
|
+
"0xray",
|
|
84
|
+
"mcp",
|
|
85
|
+
"code-review"
|
|
86
|
+
],
|
|
87
|
+
"enabled": true
|
|
88
|
+
},
|
|
89
|
+
"xray-architect-tools": {
|
|
90
|
+
"type": "local",
|
|
91
|
+
"command": [
|
|
92
|
+
"npx",
|
|
93
|
+
"-y",
|
|
94
|
+
"0xray",
|
|
95
|
+
"mcp",
|
|
96
|
+
"architect-tools"
|
|
97
|
+
],
|
|
98
|
+
"enabled": true
|
|
99
|
+
},
|
|
100
|
+
"repertoire": {
|
|
101
|
+
"type": "local",
|
|
102
|
+
"command": [
|
|
103
|
+
"node",
|
|
104
|
+
"/tmp/xray-v4-validate/node_modules/@0xray/repertoire/dist/mcp/server.js"
|
|
105
|
+
],
|
|
106
|
+
"enabled": true
|
|
19
107
|
}
|
|
20
108
|
},
|
|
21
109
|
"agent": {
|