0xray 3.5.4 → 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 +32 -6
- package/.xray/features.schema.json +87 -0
- package/AGENTS-consumer.md +16 -6
- package/AGENTS.md +21 -3
- package/README.md +13 -10
- package/SKILLS.md +1 -1
- package/dist/AGENTS.md +21 -3
- package/dist/CHANGELOG.md +98 -0
- package/dist/README.md +13 -10
- package/dist/SKILLS.md +1 -1
- package/dist/cli/commands/hermes-install.js +6 -1
- package/dist/cli/commands/openclaw-install.js +14 -0
- package/dist/cli/index.js +0 -0
- package/dist/core/features-config.d.ts +30 -2
- package/dist/governance/governance-service.d.ts +1 -0
- package/dist/governance/governance-service.js +81 -6
- package/dist/infrastructure/schemas/cloud-schemas.d.ts +1 -1
- package/dist/integrations/enforcement-gate.js +15 -5
- package/dist/integrations/grok/grok-cli.d.ts +3 -0
- package/dist/integrations/grok/grok-cli.js +92 -13
- package/dist/integrations/grok/hooks/grok-hook-utils.js +99 -9
- package/dist/integrations/grok/hooks/post-tool-use.js +68 -25
- package/dist/integrations/grok/hooks/pre-tool-use.js +17 -14
- package/dist/integrations/grok/hooks/session-start.js +114 -4
- package/dist/integrations/grok/plugin/0xray/hooks/hooks.json +31 -24
- 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 +92 -11
- package/dist/integrations/hooks/confer-hook-runtime.mjs +49 -0
- package/dist/integrations/hooks/delegation-gate-runtime.mjs +32 -3
- package/dist/integrations/hooks/pipeline-hook-runtime.mjs +211 -0
- package/dist/integrations/hooks/plan-hook-runtime.mjs +68 -0
- 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/hooks/user-aside-hook-runtime.mjs +49 -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/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 +107 -8
- 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/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 +74 -4
- package/dist/memory-routing/provider-registry.js +3 -2
- package/dist/nucleus/aside-worktree.d.ts +41 -0
- package/dist/nucleus/aside-worktree.js +164 -0
- package/dist/nucleus/autonomy-kernel.d.ts +2 -2
- package/dist/nucleus/autonomy-kernel.js +17 -6
- package/dist/nucleus/confer.d.ts +57 -0
- package/dist/nucleus/confer.js +322 -0
- package/dist/nucleus/delegation-gate.d.ts +18 -8
- package/dist/nucleus/delegation-gate.js +234 -20
- 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/suit-temperament.d.ts +40 -0
- package/dist/nucleus/suit-temperament.js +157 -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/plugin/xray-codex-injection.js +14 -3
- package/dist/postprocessor/PostProcessor.d.ts +1 -0
- package/dist/postprocessor/PostProcessor.js +11 -0
- package/dist/postprocessor/triggers/GitHookTrigger.js +11 -5
- package/dist/processors/implementations/session-summary-processor.d.ts +1 -1
- package/dist/processors/implementations/session-summary-processor.js +9 -6
- package/opencode.json +88 -0
- package/package.json +25 -6
- package/scripts/hooks/install-hooks.cjs +21 -6
- package/scripts/hooks/run-hook.js +237 -88
- package/scripts/mjs/run-repertoire-mcp.mjs +39 -0
- package/scripts/mjs/verify-confer-core.mjs +103 -0
- package/scripts/mjs/verify-delegation-gate-core.mjs +76 -3
- package/scripts/mjs/verify-four-floor-compact.mjs +524 -0
- package/scripts/mjs/verify-hermes-session-start.mjs +137 -0
- package/scripts/mjs/verify-pipeline-facets.mjs +215 -0
- package/scripts/mjs/verify-pre-push-diff-core.mjs +87 -0
- package/scripts/mjs/verify-temperament-live.mjs +261 -0
- package/scripts/mjs/verify-user-aside-core.mjs +137 -0
- package/scripts/node/bridge-mcp-wiring.cjs +287 -29
- package/scripts/node/install-bridges.cjs +198 -44
- package/scripts/node/load-reflection-config.mjs +2 -2
- package/scripts/node/postinstall.cjs +50 -27
- package/scripts/node/release-gate.mjs +8 -4
- 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/architect-tools.server.ts +6 -1
- package/src/mcps/orchestrator/handlers/complexity-handler.ts +180 -21
- package/src/mcps/orchestrator/handlers/task-handler.ts +99 -0
- package/src/mcps/orchestrator/server.ts +56 -5
- 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 +32 -6
- package/xray/features.schema.json +87 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User aside — parallel work tracks (worktree-like) declared by the user.
|
|
3
|
+
* SSOT: `.xray/state/asides/{id}.json` + `_active.json`.
|
|
4
|
+
* Todo ids: `{asideId}.a.{phase}.{todo}` — globally unique per aside.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import * as path from 'path';
|
|
8
|
+
import { buildLeadDevPlan, isLeadDevModeActive, } from './autonomy-kernel.js';
|
|
9
|
+
import { allPlanTodos, getNextRequiredTodo, getOutstandingTodos, } from './lead-dev-plan-persistence.js';
|
|
10
|
+
export const USER_ASIDE_ID_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/;
|
|
11
|
+
/** Namespaced aside todo: `suit-nft.a.1.1` */
|
|
12
|
+
export const USER_ASIDE_TODO_PATTERN = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}\.a\.\d+\.\d+$/;
|
|
13
|
+
export const USER_ASIDE_STATE_VERSION = 1;
|
|
14
|
+
export class UserAsideValidationError extends Error {
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
this.name = 'UserAsideValidationError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function assertSafeAsideId(asideId) {
|
|
21
|
+
const trimmed = asideId.trim();
|
|
22
|
+
if (!trimmed || !USER_ASIDE_ID_PATTERN.test(trimmed)) {
|
|
23
|
+
throw new UserAsideValidationError(`Invalid aside id "${asideId}" — use [a-zA-Z0-9][a-zA-Z0-9._-]{0,63}`);
|
|
24
|
+
}
|
|
25
|
+
if (trimmed.includes('..') || trimmed.includes('/') || trimmed.includes('\\')) {
|
|
26
|
+
throw new UserAsideValidationError(`Invalid aside id "${asideId}" — path characters forbidden`);
|
|
27
|
+
}
|
|
28
|
+
return trimmed;
|
|
29
|
+
}
|
|
30
|
+
export function asideTodoId(asideId, phaseIndex, todoIndex) {
|
|
31
|
+
return `${assertSafeAsideId(asideId)}.a.${phaseIndex + 1}.${todoIndex + 1}`;
|
|
32
|
+
}
|
|
33
|
+
export function isUserAsideTodoId(todoId) {
|
|
34
|
+
return USER_ASIDE_TODO_PATTERN.test(todoId);
|
|
35
|
+
}
|
|
36
|
+
export function parseAsideIdFromTodoId(todoId) {
|
|
37
|
+
if (!isUserAsideTodoId(todoId))
|
|
38
|
+
return null;
|
|
39
|
+
const dotA = todoId.indexOf('.a.');
|
|
40
|
+
if (dotA <= 0)
|
|
41
|
+
return null;
|
|
42
|
+
const asideId = todoId.slice(0, dotA);
|
|
43
|
+
try {
|
|
44
|
+
return assertSafeAsideId(asideId);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function userAsidesDir(projectRoot = process.cwd()) {
|
|
51
|
+
return path.join(projectRoot, '.xray', 'state', 'asides');
|
|
52
|
+
}
|
|
53
|
+
export function userAsidePath(asideId, projectRoot = process.cwd()) {
|
|
54
|
+
const safe = assertSafeAsideId(asideId);
|
|
55
|
+
const resolved = path.resolve(userAsidesDir(projectRoot), `${safe}.json`);
|
|
56
|
+
const base = path.resolve(userAsidesDir(projectRoot));
|
|
57
|
+
if (!resolved.startsWith(base + path.sep) && resolved !== base) {
|
|
58
|
+
throw new UserAsideValidationError(`Aside path escapes asides directory: ${asideId}`);
|
|
59
|
+
}
|
|
60
|
+
return resolved;
|
|
61
|
+
}
|
|
62
|
+
export function activeAsidePointerPath(projectRoot = process.cwd()) {
|
|
63
|
+
return path.join(userAsidesDir(projectRoot), '_active.json');
|
|
64
|
+
}
|
|
65
|
+
export function isUserAsidesEnabled(projectRoot = process.cwd()) {
|
|
66
|
+
const featuresPath = path.join(projectRoot, '.xray', 'features.json');
|
|
67
|
+
if (!fs.existsSync(featuresPath))
|
|
68
|
+
return isLeadDevModeActive();
|
|
69
|
+
try {
|
|
70
|
+
const data = JSON.parse(fs.readFileSync(featuresPath, 'utf8'));
|
|
71
|
+
const raw = data.multi_agent_orchestration?.user_asides;
|
|
72
|
+
if (raw?.enabled === false)
|
|
73
|
+
return false;
|
|
74
|
+
return isLeadDevModeActive();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return isLeadDevModeActive();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function validateLoadedAside(parsed, expectedId) {
|
|
81
|
+
if (!parsed || typeof parsed !== 'object')
|
|
82
|
+
return null;
|
|
83
|
+
const row = parsed;
|
|
84
|
+
if (row.version !== USER_ASIDE_STATE_VERSION)
|
|
85
|
+
return null;
|
|
86
|
+
if (!row.id || !row.title || !row.description || !row.plan)
|
|
87
|
+
return null;
|
|
88
|
+
if (!Array.isArray(row.plan.phases))
|
|
89
|
+
return null;
|
|
90
|
+
try {
|
|
91
|
+
assertSafeAsideId(row.id);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
if (expectedId && row.id !== expectedId)
|
|
97
|
+
return null;
|
|
98
|
+
for (const phase of row.plan.phases) {
|
|
99
|
+
if (!phase?.todos || !Array.isArray(phase.todos))
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
return row;
|
|
103
|
+
}
|
|
104
|
+
function remapPhasesToAsidePrefix(asideId, phases) {
|
|
105
|
+
const safeId = assertSafeAsideId(asideId);
|
|
106
|
+
return phases.map((phase, phaseIndex) => ({
|
|
107
|
+
...phase,
|
|
108
|
+
id: phase.id.startsWith('phase-') ? `aside-phase-${phaseIndex + 1}` : phase.id,
|
|
109
|
+
todos: phase.todos.map((todo, todoIndex) => ({
|
|
110
|
+
...todo,
|
|
111
|
+
id: asideTodoId(safeId, phaseIndex, todoIndex),
|
|
112
|
+
status: todo.status ?? 'pending',
|
|
113
|
+
})),
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
/** Build a phased aside plan from task intake (mirrors lead-dev plan, namespaced todo ids). */
|
|
117
|
+
export function buildUserAsidePlan(asideId, title, description, taskInputs = [], mcpOverallComplexity, projectRoot = process.cwd()) {
|
|
118
|
+
if (!isUserAsidesEnabled(projectRoot))
|
|
119
|
+
return null;
|
|
120
|
+
const safeId = assertSafeAsideId(asideId);
|
|
121
|
+
const taskTypes = taskInputs.map((t) => t.type ?? 'implement');
|
|
122
|
+
const basePlan = buildLeadDevPlan(description, taskTypes, taskInputs, mcpOverallComplexity, projectRoot);
|
|
123
|
+
if (!basePlan)
|
|
124
|
+
return null;
|
|
125
|
+
return {
|
|
126
|
+
version: USER_ASIDE_STATE_VERSION,
|
|
127
|
+
id: safeId,
|
|
128
|
+
title,
|
|
129
|
+
status: 'active',
|
|
130
|
+
description,
|
|
131
|
+
persistedAt: new Date().toISOString(),
|
|
132
|
+
plan: {
|
|
133
|
+
...basePlan,
|
|
134
|
+
description: `[Aside ${safeId}] ${description}`,
|
|
135
|
+
phases: remapPhasesToAsidePrefix(safeId, basePlan.phases),
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
/** Merge new task intake into an existing aside (re-intake). */
|
|
140
|
+
export function mergeUserAsideIntake(existing, description, taskInputs, mcpOverallComplexity, projectRoot = process.cwd()) {
|
|
141
|
+
const fresh = buildUserAsidePlan(existing.id, existing.title, description || existing.description, taskInputs.length > 0 ? taskInputs : [{ description: existing.description, type: 'implement' }], mcpOverallComplexity, projectRoot);
|
|
142
|
+
if (!fresh)
|
|
143
|
+
return existing;
|
|
144
|
+
const mergedPhases = [...existing.plan.phases];
|
|
145
|
+
for (const phase of fresh.plan.phases) {
|
|
146
|
+
const match = mergedPhases.find((p) => p.id === phase.id);
|
|
147
|
+
if (match) {
|
|
148
|
+
const existingIds = new Set(match.todos.map((t) => t.id));
|
|
149
|
+
for (const todo of phase.todos) {
|
|
150
|
+
if (!existingIds.has(todo.id))
|
|
151
|
+
match.todos.push(todo);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
mergedPhases.push(phase);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
...existing,
|
|
160
|
+
description: description || existing.description,
|
|
161
|
+
status: existing.status === 'completed' ? 'active' : existing.status,
|
|
162
|
+
plan: { ...existing.plan, phases: mergedPhases },
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
export function loadUserAside(asideId, projectRoot = process.cwd()) {
|
|
166
|
+
try {
|
|
167
|
+
const filePath = userAsidePath(asideId, projectRoot);
|
|
168
|
+
if (!fs.existsSync(filePath))
|
|
169
|
+
return null;
|
|
170
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
171
|
+
return validateLoadedAside(parsed, assertSafeAsideId(asideId));
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
export function saveUserAside(aside, projectRoot = process.cwd()) {
|
|
178
|
+
assertSafeAsideId(aside.id);
|
|
179
|
+
const dir = userAsidesDir(projectRoot);
|
|
180
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
181
|
+
const filePath = userAsidePath(aside.id, projectRoot);
|
|
182
|
+
const payload = {
|
|
183
|
+
...aside,
|
|
184
|
+
version: USER_ASIDE_STATE_VERSION,
|
|
185
|
+
persistedAt: new Date().toISOString(),
|
|
186
|
+
};
|
|
187
|
+
fs.writeFileSync(filePath, JSON.stringify(payload, null, 2));
|
|
188
|
+
return filePath;
|
|
189
|
+
}
|
|
190
|
+
export function listUserAsideIds(projectRoot = process.cwd()) {
|
|
191
|
+
const dir = userAsidesDir(projectRoot);
|
|
192
|
+
if (!fs.existsSync(dir))
|
|
193
|
+
return [];
|
|
194
|
+
return fs
|
|
195
|
+
.readdirSync(dir)
|
|
196
|
+
.filter((f) => f.endsWith('.json') && f !== '_active.json')
|
|
197
|
+
.map((f) => f.replace(/\.json$/, ''))
|
|
198
|
+
.filter((id) => USER_ASIDE_ID_PATTERN.test(id));
|
|
199
|
+
}
|
|
200
|
+
export function loadActiveAsidePointer(projectRoot = process.cwd()) {
|
|
201
|
+
const pointerPath = activeAsidePointerPath(projectRoot);
|
|
202
|
+
if (!fs.existsSync(pointerPath))
|
|
203
|
+
return null;
|
|
204
|
+
try {
|
|
205
|
+
const parsed = JSON.parse(fs.readFileSync(pointerPath, 'utf8'));
|
|
206
|
+
if (!parsed?.asideId)
|
|
207
|
+
return null;
|
|
208
|
+
assertSafeAsideId(parsed.asideId);
|
|
209
|
+
return parsed;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
export function getActiveAsideId(projectRoot = process.cwd(), sessionId) {
|
|
216
|
+
if (!isUserAsidesEnabled(projectRoot))
|
|
217
|
+
return null;
|
|
218
|
+
const pointer = loadActiveAsidePointer(projectRoot);
|
|
219
|
+
if (!pointer)
|
|
220
|
+
return null;
|
|
221
|
+
if (pointer.sessionId) {
|
|
222
|
+
if (!sessionId || pointer.sessionId !== sessionId)
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const aside = loadUserAside(pointer.asideId, projectRoot);
|
|
226
|
+
if (!aside || aside.status !== 'active')
|
|
227
|
+
return null;
|
|
228
|
+
return pointer.asideId;
|
|
229
|
+
}
|
|
230
|
+
export function setActiveAsideId(asideId, projectRoot = process.cwd(), sessionId) {
|
|
231
|
+
const safeId = assertSafeAsideId(asideId);
|
|
232
|
+
const aside = loadUserAside(safeId, projectRoot);
|
|
233
|
+
if (!aside) {
|
|
234
|
+
throw new UserAsideValidationError(`Cannot activate aside "${safeId}" — file not found at .xray/state/asides/${safeId}.json`);
|
|
235
|
+
}
|
|
236
|
+
if (aside.status !== 'active' && aside.status !== 'paused') {
|
|
237
|
+
throw new UserAsideValidationError(`Cannot activate aside "${safeId}" — status is ${aside.status}`);
|
|
238
|
+
}
|
|
239
|
+
if (aside.status === 'paused') {
|
|
240
|
+
aside.status = 'active';
|
|
241
|
+
saveUserAside(aside, projectRoot);
|
|
242
|
+
}
|
|
243
|
+
const dir = userAsidesDir(projectRoot);
|
|
244
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
245
|
+
const pointer = {
|
|
246
|
+
asideId: safeId,
|
|
247
|
+
activatedAt: new Date().toISOString(),
|
|
248
|
+
...(sessionId ? { sessionId } : {}),
|
|
249
|
+
};
|
|
250
|
+
fs.writeFileSync(activeAsidePointerPath(projectRoot), JSON.stringify(pointer, null, 2));
|
|
251
|
+
return pointer;
|
|
252
|
+
}
|
|
253
|
+
export function clearActiveAside(projectRoot = process.cwd()) {
|
|
254
|
+
const pointerPath = activeAsidePointerPath(projectRoot);
|
|
255
|
+
if (!fs.existsSync(pointerPath))
|
|
256
|
+
return false;
|
|
257
|
+
fs.unlinkSync(pointerPath);
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
export function loadActiveUserAside(projectRoot = process.cwd(), sessionId) {
|
|
261
|
+
const id = getActiveAsideId(projectRoot, sessionId);
|
|
262
|
+
if (!id) {
|
|
263
|
+
const pointer = loadActiveAsidePointer(projectRoot);
|
|
264
|
+
if (pointer) {
|
|
265
|
+
const aside = loadUserAside(pointer.asideId, projectRoot);
|
|
266
|
+
if (aside && aside.status !== 'active')
|
|
267
|
+
clearActiveAside(projectRoot);
|
|
268
|
+
}
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
const aside = loadUserAside(id, projectRoot);
|
|
272
|
+
if (!aside || aside.status !== 'active') {
|
|
273
|
+
clearActiveAside(projectRoot);
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
return aside;
|
|
277
|
+
}
|
|
278
|
+
/** PersistedLeadDevPlan view of an aside for spawn-gate reuse. */
|
|
279
|
+
export function asideToSpawnPlan(aside) {
|
|
280
|
+
const plan = { ...aside.plan };
|
|
281
|
+
if (aside.persistedAt)
|
|
282
|
+
plan.persistedAt = aside.persistedAt;
|
|
283
|
+
if (aside.sessionId)
|
|
284
|
+
plan.sessionId = aside.sessionId;
|
|
285
|
+
return plan;
|
|
286
|
+
}
|
|
287
|
+
/** Aside routable when active for session, or pointer is unscoped (accepted exception). */
|
|
288
|
+
export function isAsideActiveForSession(asideId, projectRoot = process.cwd(), sessionId) {
|
|
289
|
+
const activeId = getActiveAsideId(projectRoot, sessionId);
|
|
290
|
+
if (activeId === asideId)
|
|
291
|
+
return true;
|
|
292
|
+
const pointer = loadActiveAsidePointer(projectRoot);
|
|
293
|
+
if (!pointer || pointer.asideId !== asideId)
|
|
294
|
+
return false;
|
|
295
|
+
if (!pointer.sessionId)
|
|
296
|
+
return true;
|
|
297
|
+
return Boolean(sessionId && pointer.sessionId === sessionId);
|
|
298
|
+
}
|
|
299
|
+
export function findAsideContainingTodo(todoId, projectRoot = process.cwd(), preferredAsideId) {
|
|
300
|
+
if (!isUserAsideTodoId(todoId))
|
|
301
|
+
return null;
|
|
302
|
+
if (preferredAsideId) {
|
|
303
|
+
const direct = loadUserAside(preferredAsideId, projectRoot);
|
|
304
|
+
if (direct) {
|
|
305
|
+
const hit = allPlanTodos(asideToSpawnPlan(direct)).some((t) => t.id === todoId);
|
|
306
|
+
if (hit)
|
|
307
|
+
return direct;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
const parsedId = parseAsideIdFromTodoId(todoId);
|
|
311
|
+
if (parsedId) {
|
|
312
|
+
const aside = loadUserAside(parsedId, projectRoot);
|
|
313
|
+
if (aside) {
|
|
314
|
+
const hit = allPlanTodos(asideToSpawnPlan(aside)).some((t) => t.id === todoId);
|
|
315
|
+
if (hit)
|
|
316
|
+
return aside;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
export function updateUserAsideTodoStatus(todoId, status, projectRoot = process.cwd(), sessionId) {
|
|
322
|
+
const parsedId = parseAsideIdFromTodoId(todoId);
|
|
323
|
+
let aside = parsedId
|
|
324
|
+
? findAsideContainingTodo(todoId, projectRoot, parsedId)
|
|
325
|
+
: null;
|
|
326
|
+
if (aside && parsedId && !isAsideActiveForSession(parsedId, projectRoot, sessionId)) {
|
|
327
|
+
aside = null;
|
|
328
|
+
}
|
|
329
|
+
if (!aside)
|
|
330
|
+
aside = loadActiveUserAside(projectRoot, sessionId);
|
|
331
|
+
if (!aside)
|
|
332
|
+
return false;
|
|
333
|
+
let updated = false;
|
|
334
|
+
for (const phase of aside.plan.phases) {
|
|
335
|
+
for (const todo of phase.todos) {
|
|
336
|
+
if (todo.id === todoId) {
|
|
337
|
+
todo.status = status;
|
|
338
|
+
updated = true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
if (!updated)
|
|
343
|
+
return false;
|
|
344
|
+
const outstanding = getOutstandingTodos(asideToSpawnPlan(aside));
|
|
345
|
+
if (outstanding.length === 0) {
|
|
346
|
+
aside.status = 'completed';
|
|
347
|
+
clearActiveAside(projectRoot);
|
|
348
|
+
}
|
|
349
|
+
saveUserAside(aside, projectRoot);
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
export function getNextAsideTodo(aside) {
|
|
353
|
+
return getNextRequiredTodo(asideToSpawnPlan(aside));
|
|
354
|
+
}
|
|
355
|
+
export function formatUserAsideSummary(aside) {
|
|
356
|
+
const todos = allPlanTodos(asideToSpawnPlan(aside));
|
|
357
|
+
const done = todos.filter((t) => t.status === 'completed').length;
|
|
358
|
+
const lines = [
|
|
359
|
+
`**Aside \`${aside.id}\`** — ${aside.title}`,
|
|
360
|
+
`Status: ${aside.status} | Todos: ${done}/${todos.length}`,
|
|
361
|
+
aside.worktree ? `Worktree: \`${aside.worktree}\`` : null,
|
|
362
|
+
aside.branch ? `Branch: \`${aside.branch}\`` : null,
|
|
363
|
+
'',
|
|
364
|
+
...todos.map((t) => `- [${t.status === 'completed' ? 'x' : ' '}] ${t.id} (${t.subagent}): ${t.task}`),
|
|
365
|
+
].filter(Boolean);
|
|
366
|
+
return lines.join('\n');
|
|
367
|
+
}
|
|
368
|
+
export function getUserAsideBootHints(projectRoot = process.cwd(), sessionId) {
|
|
369
|
+
if (!isUserAsidesEnabled(projectRoot))
|
|
370
|
+
return null;
|
|
371
|
+
const aside = loadActiveUserAside(projectRoot, sessionId);
|
|
372
|
+
if (!aside)
|
|
373
|
+
return null;
|
|
374
|
+
const hints = {
|
|
375
|
+
activeAside: aside.id,
|
|
376
|
+
asideTitle: aside.title,
|
|
377
|
+
asideStatus: aside.status,
|
|
378
|
+
asideTodoPrefix: `${aside.id}.a.*`,
|
|
379
|
+
asideHint: 'Spawns route to active aside todos; orchestrate-task clearActiveAside to resume main',
|
|
380
|
+
};
|
|
381
|
+
if (aside.worktree)
|
|
382
|
+
hints.asideWorktree = aside.worktree;
|
|
383
|
+
if (aside.branch)
|
|
384
|
+
hints.asideBranch = aside.branch;
|
|
385
|
+
if (aside.governance?.trapSignals?.length) {
|
|
386
|
+
hints.asideTrapSignals = aside.governance.trapSignals;
|
|
387
|
+
}
|
|
388
|
+
if (aside.governance?.conferOnPhaseStart) {
|
|
389
|
+
hints.asideConferRecommended = true;
|
|
390
|
+
hints.asideConferTrigger = 'orchestrate-task { confer: true } or synthesis analyze-complexity';
|
|
391
|
+
}
|
|
392
|
+
return hints;
|
|
393
|
+
}
|
|
@@ -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"));
|
|
@@ -23,6 +23,7 @@ export declare class PostProcessor {
|
|
|
23
23
|
private escalationEngine;
|
|
24
24
|
private successHandler;
|
|
25
25
|
private triggers;
|
|
26
|
+
private metamorphosisEngines;
|
|
26
27
|
constructor(stateManager: XrayStateManager, sessionMonitor?: SessionMonitor | null, config?: Partial<PostProcessorConfig>);
|
|
27
28
|
/**
|
|
28
29
|
* Generate automated framework report if conditions are met
|
|
@@ -25,6 +25,7 @@ import { defaultConfig } from "./config.js";
|
|
|
25
25
|
import { frameworkReportingSystem } from "../reporting/framework-reporting-system.js";
|
|
26
26
|
import { ReportContentValidator } from "../validation/report-content-validator.js";
|
|
27
27
|
import { RegressionAnalysisService } from "./services/RegressionAnalysisService.js";
|
|
28
|
+
import { SelfProposalEngine } from "./metamorphosis/SelfProposalEngine.js";
|
|
28
29
|
export class PostProcessor {
|
|
29
30
|
stateManager;
|
|
30
31
|
sessionMonitor;
|
|
@@ -39,6 +40,7 @@ export class PostProcessor {
|
|
|
39
40
|
escalationEngine;
|
|
40
41
|
successHandler;
|
|
41
42
|
triggers;
|
|
43
|
+
metamorphosisEngines;
|
|
42
44
|
constructor(stateManager, sessionMonitor = null, config = {}) {
|
|
43
45
|
this.stateManager = stateManager;
|
|
44
46
|
this.sessionMonitor = sessionMonitor;
|
|
@@ -56,6 +58,7 @@ export class PostProcessor {
|
|
|
56
58
|
// Initialize escalation and success handlers
|
|
57
59
|
this.escalationEngine = new EscalationEngine(this.config.escalation);
|
|
58
60
|
this.successHandler = new SuccessHandler(this.config.success);
|
|
61
|
+
this.metamorphosisEngines = [new SelfProposalEngine({ projectRoot: process.cwd() })];
|
|
59
62
|
// Initialize trigger mechanisms
|
|
60
63
|
this.triggers = {
|
|
61
64
|
gitHook: new GitHookTrigger(this),
|
|
@@ -736,6 +739,14 @@ All path violations will be automatically detected and blocked.
|
|
|
736
739
|
};
|
|
737
740
|
// Handle successful completion
|
|
738
741
|
await this.successHandler.handleSuccess(context, result, monitoringResults);
|
|
742
|
+
for (const engine of this.metamorphosisEngines) {
|
|
743
|
+
try {
|
|
744
|
+
await engine.onPhase('post-process-complete', { context, result, monitoringResults });
|
|
745
|
+
}
|
|
746
|
+
catch (metaErr) {
|
|
747
|
+
await frameworkLogger.log('-post-processor', 'self-proposal-phase-error', 'warning', { error: String(metaErr) });
|
|
748
|
+
}
|
|
749
|
+
}
|
|
739
750
|
// AGENTS.md auto-update with smart triggers
|
|
740
751
|
// Only updates when agent-related files have changed
|
|
741
752
|
const agentChangePatterns = [
|
|
@@ -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: [
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Session Summary Post-Processor
|
|
3
3
|
*
|
|
4
4
|
* Generates emoji-formatted session summaries after tool execution.
|
|
5
|
-
* Uses features.json ->
|
|
5
|
+
* Uses features.json -> autonomous_reporting config for control.
|
|
6
6
|
*
|
|
7
7
|
* @since 2026-04-04
|
|
8
8
|
*/
|
|
@@ -29,12 +29,15 @@ export class SessionSummaryProcessor extends PostProcessor {
|
|
|
29
29
|
loadConfig() {
|
|
30
30
|
try {
|
|
31
31
|
const configData = featuresConfigLoader.loadConfig();
|
|
32
|
-
const autoReporting = configData.auto_reporting;
|
|
32
|
+
const autoReporting = configData.autonomous_reporting ?? configData.auto_reporting;
|
|
33
33
|
if (autoReporting) {
|
|
34
|
-
this.config.enabled = autoReporting.
|
|
35
|
-
this.config.include_emojis =
|
|
36
|
-
|
|
37
|
-
this.config.
|
|
34
|
+
this.config.enabled = autoReporting.enabled !== false;
|
|
35
|
+
this.config.include_emojis =
|
|
36
|
+
autoReporting.include_agent_activities !== false;
|
|
37
|
+
this.config.include_recommendations =
|
|
38
|
+
autoReporting.include_recommendations !== false;
|
|
39
|
+
this.config.include_agent_activities =
|
|
40
|
+
autoReporting.include_agent_activities !== false;
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
43
|
catch (error) {
|
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": {
|