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,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User-aside worktree path resolution, spawn cwd validation, optional git provision.
|
|
3
|
+
*/
|
|
4
|
+
import { execFileSync } from 'child_process';
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { isUserAsidesEnabled } from './user-aside.js';
|
|
8
|
+
export function normalizeWorktreePath(worktree, projectRoot) {
|
|
9
|
+
const trimmed = worktree.trim().replace(/\/$/, '');
|
|
10
|
+
const resolved = path.isAbsolute(trimmed) ? trimmed : path.resolve(projectRoot, trimmed);
|
|
11
|
+
return resolved.replace(/\/$/, '');
|
|
12
|
+
}
|
|
13
|
+
export function isAutoProvisionWorktreeEnabled(projectRoot = process.cwd()) {
|
|
14
|
+
if (!isUserAsidesEnabled(projectRoot))
|
|
15
|
+
return false;
|
|
16
|
+
const featuresPath = path.join(projectRoot, '.xray', 'features.json');
|
|
17
|
+
if (!fs.existsSync(featuresPath))
|
|
18
|
+
return false;
|
|
19
|
+
try {
|
|
20
|
+
const data = JSON.parse(fs.readFileSync(featuresPath, 'utf8'));
|
|
21
|
+
const raw = data.multi_agent_orchestration?.user_asides;
|
|
22
|
+
if (raw?.enabled === false)
|
|
23
|
+
return false;
|
|
24
|
+
return raw?.auto_provision_worktree === true;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Extract spawn cwd from host Task / spawn_subagent tool input. */
|
|
31
|
+
export function extractSpawnCwd(toolInput, projectRoot) {
|
|
32
|
+
const isolation = toolInput.isolation ?? toolInput.isolation_mode;
|
|
33
|
+
if (isolation === 'worktree' || isolation === 'git_worktree') {
|
|
34
|
+
const wt = toolInput.worktree_path ??
|
|
35
|
+
toolInput.worktreePath ??
|
|
36
|
+
toolInput.worktree ??
|
|
37
|
+
toolInput.cwd ??
|
|
38
|
+
toolInput.working_directory ??
|
|
39
|
+
toolInput.workingDirectory;
|
|
40
|
+
if (wt != null && String(wt).trim() !== '') {
|
|
41
|
+
return normalizeWorktreePath(String(wt), projectRoot);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const raw = toolInput.cwd ??
|
|
45
|
+
toolInput.working_directory ??
|
|
46
|
+
toolInput.workingDirectory;
|
|
47
|
+
if (raw == null || String(raw).trim() === '')
|
|
48
|
+
return null;
|
|
49
|
+
return normalizeWorktreePath(String(raw), projectRoot);
|
|
50
|
+
}
|
|
51
|
+
export function validateAsideWorktreeCwd(worktree, toolInput, projectRoot) {
|
|
52
|
+
if (!worktree?.trim())
|
|
53
|
+
return { valid: true };
|
|
54
|
+
const expected = normalizeWorktreePath(worktree, projectRoot);
|
|
55
|
+
const projectNorm = path.resolve(projectRoot).replace(/\/$/, '');
|
|
56
|
+
if (projectNorm === expected || projectNorm.startsWith(`${expected}/`)) {
|
|
57
|
+
return { valid: true };
|
|
58
|
+
}
|
|
59
|
+
const spawnCwd = extractSpawnCwd(toolInput, projectRoot);
|
|
60
|
+
if (!spawnCwd) {
|
|
61
|
+
return {
|
|
62
|
+
valid: false,
|
|
63
|
+
gate: 'aside-worktree-cwd-missing',
|
|
64
|
+
reason: `Aside worktree is ${expected} but project root is ${projectNorm} â ` +
|
|
65
|
+
'spawn must set cwd / working_directory / isolation:worktree to the aside worktree',
|
|
66
|
+
hint: {
|
|
67
|
+
worktree: expected,
|
|
68
|
+
projectRoot: projectNorm,
|
|
69
|
+
required: ['cwd', 'working_directory', 'isolation:worktree'],
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
if (spawnCwd !== expected && !spawnCwd.startsWith(`${expected}/`)) {
|
|
74
|
+
return {
|
|
75
|
+
valid: false,
|
|
76
|
+
gate: 'aside-worktree-cwd-mismatch',
|
|
77
|
+
reason: `Spawn cwd ${spawnCwd} does not match aside worktree ${expected}`,
|
|
78
|
+
hint: { worktree: expected, spawnCwd, projectRoot: projectNorm },
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
return { valid: true };
|
|
82
|
+
}
|
|
83
|
+
function gitBranchExists(projectRoot, branch) {
|
|
84
|
+
try {
|
|
85
|
+
execFileSync('git', ['rev-parse', '--verify', branch], {
|
|
86
|
+
cwd: projectRoot,
|
|
87
|
+
stdio: 'pipe',
|
|
88
|
+
});
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function resolvePathForCompare(p) {
|
|
96
|
+
try {
|
|
97
|
+
return fs.realpathSync.native(p).replace(/\/$/, '');
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return path.resolve(p).replace(/\/$/, '');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function isGitWorktreePath(wtPath, projectRoot) {
|
|
104
|
+
try {
|
|
105
|
+
const out = execFileSync('git', ['worktree', 'list', '--porcelain'], {
|
|
106
|
+
cwd: projectRoot,
|
|
107
|
+
encoding: 'utf8',
|
|
108
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
109
|
+
});
|
|
110
|
+
const normalized = resolvePathForCompare(wtPath);
|
|
111
|
+
return out.split('\n').some((line) => {
|
|
112
|
+
if (!line.startsWith('worktree '))
|
|
113
|
+
return false;
|
|
114
|
+
const listed = line.slice('worktree '.length).trim();
|
|
115
|
+
return resolvePathForCompare(listed) === normalized;
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Guarded `git worktree add` when auto_provision_worktree is enabled.
|
|
124
|
+
* Creates branch with -b when it does not exist locally.
|
|
125
|
+
*/
|
|
126
|
+
export function provisionGitWorktree(opts) {
|
|
127
|
+
const wtPath = normalizeWorktreePath(opts.worktree, opts.projectRoot);
|
|
128
|
+
const branch = opts.branch.trim();
|
|
129
|
+
if (!branch) {
|
|
130
|
+
return { ok: false, path: wtPath, created: false, message: 'branch is required' };
|
|
131
|
+
}
|
|
132
|
+
if (fs.existsSync(wtPath)) {
|
|
133
|
+
if (isGitWorktreePath(wtPath, opts.projectRoot)) {
|
|
134
|
+
return { ok: true, path: wtPath, created: false, message: 'worktree already exists' };
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
ok: false,
|
|
138
|
+
path: wtPath,
|
|
139
|
+
created: false,
|
|
140
|
+
message: `path exists but is not a git worktree: ${wtPath}`,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const gitDir = path.join(opts.projectRoot, '.git');
|
|
144
|
+
if (!fs.existsSync(gitDir)) {
|
|
145
|
+
return {
|
|
146
|
+
ok: false,
|
|
147
|
+
path: wtPath,
|
|
148
|
+
created: false,
|
|
149
|
+
message: `not a git repository: ${opts.projectRoot}`,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
const branchExists = gitBranchExists(opts.projectRoot, branch);
|
|
153
|
+
const args = branchExists
|
|
154
|
+
? ['worktree', 'add', wtPath, branch]
|
|
155
|
+
: ['worktree', 'add', '-b', branch, wtPath];
|
|
156
|
+
try {
|
|
157
|
+
execFileSync('git', args, { cwd: opts.projectRoot, stdio: 'pipe' });
|
|
158
|
+
return { ok: true, path: wtPath, created: true, message: 'worktree provisioned' };
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
162
|
+
return { ok: false, path: wtPath, created: false, message };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -43,8 +43,8 @@ export declare function isLeadDevModeActive(): boolean;
|
|
|
43
43
|
export declare function routeSubagent(taskType: string): SubagentRoute;
|
|
44
44
|
export declare function shouldFlagFullTestSuite(command: string): boolean;
|
|
45
45
|
/** Mandatory-consult plan for synthesis checkpoint realignment (no implementation phase). */
|
|
46
|
-
export declare function buildSynthesisCheckpointPlan(dueReason: string | null): LeadDevPlan | null;
|
|
47
|
-
export declare function buildLeadDevPlan(description: string, taskTypes?: string[], taskInputs?: LeadDevPlanTaskInput[], mcpOverallComplexity?: number): LeadDevPlan | null;
|
|
46
|
+
export declare function buildSynthesisCheckpointPlan(dueReason: string | null, projectRoot?: string): LeadDevPlan | null;
|
|
47
|
+
export declare function buildLeadDevPlan(description: string, taskTypes?: string[], taskInputs?: LeadDevPlanTaskInput[], mcpOverallComplexity?: number, projectRoot?: string): LeadDevPlan | null;
|
|
48
48
|
export declare function buildSessionBootContext(): Record<string, unknown>;
|
|
49
49
|
/** Persist plan for PreToolUse spawn_subagent gate */
|
|
50
50
|
export declare function persistLeadDevPlan(plan: LeadDevPlan, projectRoot?: string): string;
|
|
@@ -6,6 +6,7 @@ import * as fs from 'fs';
|
|
|
6
6
|
import * as path from 'path';
|
|
7
7
|
import { featuresConfigLoader } from '../core/features-config.js';
|
|
8
8
|
import { scoreComplexity } from './thin-dispatch.js';
|
|
9
|
+
import { conferDefaultForProfile, resolveRuntimeSuitProfile } from './suit-temperament.js';
|
|
9
10
|
export const LEAD_DEV_RULES = [
|
|
10
11
|
'Phased plan + detailed todos; assign best subagent; monitor output; iterate fully',
|
|
11
12
|
'Lead dev takes helm â loop test fix until complete; no permission pings',
|
|
@@ -75,11 +76,17 @@ function buildImplementationTodos(description, taskTypes, taskInputs, idPrefix)
|
|
|
75
76
|
}));
|
|
76
77
|
}
|
|
77
78
|
/** Mandatory-consult plan for synthesis checkpoint realignment (no implementation phase). */
|
|
78
|
-
export function buildSynthesisCheckpointPlan(dueReason) {
|
|
79
|
+
export function buildSynthesisCheckpointPlan(dueReason, projectRoot = process.cwd()) {
|
|
79
80
|
if (!isLeadDevModeActive())
|
|
80
81
|
return null;
|
|
81
82
|
const cfg = orchestrationConfig();
|
|
82
|
-
const
|
|
83
|
+
const profile = resolveRuntimeSuitProfile(projectRoot);
|
|
84
|
+
const autoConsult = profile === 'frontier'
|
|
85
|
+
? cfg.confer?.enabled === true || cfg.confer_on_synthesis === true
|
|
86
|
+
: profile === 'strict'
|
|
87
|
+
? true
|
|
88
|
+
: cfg.auto_consult_major_work !== false;
|
|
89
|
+
const mandatoryConsults = autoConsult ? [...MANDATORY_MAJOR_CONSULTS] : [];
|
|
83
90
|
if (mandatoryConsults.length === 0)
|
|
84
91
|
return null;
|
|
85
92
|
const reasonSuffix = dueReason ? ` (${dueReason})` : '';
|
|
@@ -113,10 +120,11 @@ export function buildSynthesisCheckpointPlan(dueReason) {
|
|
|
113
120
|
},
|
|
114
121
|
};
|
|
115
122
|
}
|
|
116
|
-
export function buildLeadDevPlan(description, taskTypes = ['implement'], taskInputs = [], mcpOverallComplexity) {
|
|
123
|
+
export function buildLeadDevPlan(description, taskTypes = ['implement'], taskInputs = [], mcpOverallComplexity, projectRoot = process.cwd()) {
|
|
117
124
|
if (!isLeadDevModeActive())
|
|
118
125
|
return null;
|
|
119
126
|
const cfg = orchestrationConfig();
|
|
127
|
+
const profile = resolveRuntimeSuitProfile(projectRoot);
|
|
120
128
|
const threshold = cfg.phased_plan_threshold ?? 25;
|
|
121
129
|
const score = scoreComplexity(description, { taskTypes });
|
|
122
130
|
const mcpScore = mcpOverallComplexity !== undefined && Number.isFinite(mcpOverallComplexity)
|
|
@@ -124,9 +132,12 @@ export function buildLeadDevPlan(description, taskTypes = ['implement'], taskInp
|
|
|
124
132
|
: 0;
|
|
125
133
|
const complexity = Math.max(score.score, mcpScore);
|
|
126
134
|
const requiresPhasedPlan = complexity > threshold || taskInputs.length > 1;
|
|
127
|
-
const
|
|
128
|
-
?
|
|
129
|
-
:
|
|
135
|
+
const autoConsult = profile === 'frontier'
|
|
136
|
+
? cfg.confer?.enabled === true || cfg.confer_on_synthesis === true
|
|
137
|
+
: profile === 'strict' || conferDefaultForProfile(profile)
|
|
138
|
+
? cfg.auto_consult_major_work !== false
|
|
139
|
+
: false;
|
|
140
|
+
const mandatoryConsults = autoConsult && requiresPhasedPlan ? [...MANDATORY_MAJOR_CONSULTS] : [];
|
|
130
141
|
const phases = requiresPhasedPlan
|
|
131
142
|
? [
|
|
132
143
|
{
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confer â mandatory 3-agent quorum SSOT (researcher / architect-tools / code-review).
|
|
3
|
+
* Triggered automatically at synthesis checkpoint; records consult receipts + plan todos.
|
|
4
|
+
*/
|
|
5
|
+
import { type SynthesisConsultReceipt } from './synthesis-consult-receipt.js';
|
|
6
|
+
export declare const CONFER_AGENTS: readonly ["researcher", "architect-tools", "code-review"];
|
|
7
|
+
export interface ConferConfig {
|
|
8
|
+
enabled: boolean;
|
|
9
|
+
on_synthesis: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ConferCheckpointState {
|
|
12
|
+
version: 1;
|
|
13
|
+
sessionId: string;
|
|
14
|
+
triggeredAt: string;
|
|
15
|
+
dueReason: string | null;
|
|
16
|
+
status: 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
17
|
+
completedAgents: string[];
|
|
18
|
+
lastError?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ConferAgentResult {
|
|
21
|
+
todoId: string;
|
|
22
|
+
subagent: string;
|
|
23
|
+
outputText: string;
|
|
24
|
+
receiptRecorded: boolean;
|
|
25
|
+
todoCompleted: boolean;
|
|
26
|
+
verdict: SynthesisConsultReceipt['verdict'] | null;
|
|
27
|
+
error?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ConferQuorumResult {
|
|
30
|
+
status: 'completed' | 'partial' | 'skipped' | 'failed';
|
|
31
|
+
agents: ConferAgentResult[];
|
|
32
|
+
message: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function conferCheckpointPath(projectRoot?: string): string;
|
|
35
|
+
export declare function defaultConferConfig(): ConferConfig;
|
|
36
|
+
export declare function loadConferConfig(projectRoot?: string): ConferConfig;
|
|
37
|
+
export declare function isConferEnabled(projectRoot?: string): boolean;
|
|
38
|
+
export declare function loadConferCheckpoint(projectRoot?: string): ConferCheckpointState | null;
|
|
39
|
+
export declare function saveConferCheckpoint(state: ConferCheckpointState, projectRoot?: string): string;
|
|
40
|
+
export declare function triggerConferCheckpoint(sessionId: string, dueReason: string | null, projectRoot?: string): ConferCheckpointState;
|
|
41
|
+
export declare function isConferPending(projectRoot?: string, sessionId?: string | null): boolean;
|
|
42
|
+
export declare function buildConferPrompt(subagent: string, todoTask: string, collocatedText: string, dueReason: string | null): string;
|
|
43
|
+
/** Map confer subagent â MCP server + tool. */
|
|
44
|
+
export declare function conferAgentMcpTarget(subagent: string): {
|
|
45
|
+
server: string;
|
|
46
|
+
tool: string;
|
|
47
|
+
args: (prompt: string, projectRoot: string) => Record<string, unknown>;
|
|
48
|
+
};
|
|
49
|
+
export declare function invokeConferAgent(subagent: string, prompt: string, projectRoot?: string): Promise<string>;
|
|
50
|
+
export declare function applyConferConsultResult(todoId: string, subagent: string, sessionId: string, outputText: string, projectRoot?: string): ConferAgentResult;
|
|
51
|
+
export declare function writeFixtureConferReceipt(todoId: string, subagent: string, sessionId: string, projectRoot?: string): ConferAgentResult;
|
|
52
|
+
export declare function runConferQuorum(projectRoot: string | undefined, sessionId: string, options?: {
|
|
53
|
+
collocatedText?: string;
|
|
54
|
+
dueReason?: string | null;
|
|
55
|
+
fixture?: boolean;
|
|
56
|
+
}): Promise<ConferQuorumResult>;
|
|
57
|
+
export declare function formatConferQuorumReport(result: ConferQuorumResult): string;
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confer â mandatory 3-agent quorum SSOT (researcher / architect-tools / code-review).
|
|
3
|
+
* Triggered automatically at synthesis checkpoint; records consult receipts + plan todos.
|
|
4
|
+
*/
|
|
5
|
+
import * as fs from 'fs';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { MANDATORY_MAJOR_CONSULTS } from './autonomy-kernel.js';
|
|
8
|
+
import { areSynthesisConsultTodosComplete, getNextRequiredTodo, getSynthesisConsultTodos, isSynthesisRealignmentPlan, loadPersistedLeadDevPlan, updatePlanTodoStatus, } from './lead-dev-plan-persistence.js';
|
|
9
|
+
import { buildReceiptFromConsultOutput, tryRecordSynthesisConsultReceipt, parseConsultVerdictFromText, } from './synthesis-consult-receipt.js';
|
|
10
|
+
import { isSynthesisCheckpointDue } from './synthesis.js';
|
|
11
|
+
import { conferDefaultForProfile, resolveRuntimeSuitProfile } from './suit-temperament.js';
|
|
12
|
+
export const CONFER_AGENTS = [...MANDATORY_MAJOR_CONSULTS];
|
|
13
|
+
const STATE_VERSION = 1;
|
|
14
|
+
export function conferCheckpointPath(projectRoot = process.cwd()) {
|
|
15
|
+
return path.join(projectRoot, '.xray', 'state', 'confer-checkpoint.json');
|
|
16
|
+
}
|
|
17
|
+
export function defaultConferConfig() {
|
|
18
|
+
return { enabled: true, on_synthesis: true };
|
|
19
|
+
}
|
|
20
|
+
export function loadConferConfig(projectRoot = process.cwd()) {
|
|
21
|
+
const featuresPath = path.join(projectRoot, '.xray', 'features.json');
|
|
22
|
+
const profile = resolveRuntimeSuitProfile(projectRoot);
|
|
23
|
+
if (profile === 'strict') {
|
|
24
|
+
return { enabled: true, on_synthesis: true };
|
|
25
|
+
}
|
|
26
|
+
if (!fs.existsSync(featuresPath)) {
|
|
27
|
+
return conferDefaultForProfile(profile)
|
|
28
|
+
? defaultConferConfig()
|
|
29
|
+
: { enabled: false, on_synthesis: false };
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
const data = JSON.parse(fs.readFileSync(featuresPath, 'utf8'));
|
|
33
|
+
const orch = data.multi_agent_orchestration ?? {};
|
|
34
|
+
const raw = orch.confer ?? {};
|
|
35
|
+
if (profile === 'frontier') {
|
|
36
|
+
const optedIn = raw.enabled === true || orch.confer_on_synthesis === true;
|
|
37
|
+
return { enabled: optedIn, on_synthesis: optedIn };
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
enabled: raw.enabled !== false && orch.confer_on_synthesis !== false,
|
|
41
|
+
on_synthesis: raw.on_synthesis !== false && orch.confer_on_synthesis !== false,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return conferDefaultForProfile(profile)
|
|
46
|
+
? defaultConferConfig()
|
|
47
|
+
: { enabled: false, on_synthesis: false };
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export function isConferEnabled(projectRoot = process.cwd()) {
|
|
51
|
+
return loadConferConfig(projectRoot).enabled;
|
|
52
|
+
}
|
|
53
|
+
export function loadConferCheckpoint(projectRoot = process.cwd()) {
|
|
54
|
+
const statePath = conferCheckpointPath(projectRoot);
|
|
55
|
+
if (!fs.existsSync(statePath))
|
|
56
|
+
return null;
|
|
57
|
+
try {
|
|
58
|
+
return JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function saveConferCheckpoint(state, projectRoot = process.cwd()) {
|
|
65
|
+
const statePath = conferCheckpointPath(projectRoot);
|
|
66
|
+
fs.mkdirSync(path.dirname(statePath), { recursive: true });
|
|
67
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
68
|
+
return statePath;
|
|
69
|
+
}
|
|
70
|
+
export function triggerConferCheckpoint(sessionId, dueReason, projectRoot = process.cwd()) {
|
|
71
|
+
const state = {
|
|
72
|
+
version: STATE_VERSION,
|
|
73
|
+
sessionId,
|
|
74
|
+
triggeredAt: new Date().toISOString(),
|
|
75
|
+
dueReason,
|
|
76
|
+
status: 'pending',
|
|
77
|
+
completedAgents: [],
|
|
78
|
+
};
|
|
79
|
+
saveConferCheckpoint(state, projectRoot);
|
|
80
|
+
return state;
|
|
81
|
+
}
|
|
82
|
+
export function isConferPending(projectRoot = process.cwd(), sessionId) {
|
|
83
|
+
const plan = loadPersistedLeadDevPlan(projectRoot);
|
|
84
|
+
if (!plan || !isSynthesisRealignmentPlan(plan))
|
|
85
|
+
return false;
|
|
86
|
+
if (areSynthesisConsultTodosComplete(plan))
|
|
87
|
+
return false;
|
|
88
|
+
if (sessionId && isSynthesisCheckpointDue(projectRoot, sessionId))
|
|
89
|
+
return true;
|
|
90
|
+
const state = loadConferCheckpoint(projectRoot);
|
|
91
|
+
if (!state || state.status === 'completed')
|
|
92
|
+
return false;
|
|
93
|
+
if (sessionId && state.sessionId !== sessionId)
|
|
94
|
+
return false;
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
export function buildConferPrompt(subagent, todoTask, collocatedText, dueReason) {
|
|
98
|
+
const reasonLine = dueReason ? `Due: ${dueReason}\n\n` : '';
|
|
99
|
+
return `${reasonLine}## Confer quorum â ${subagent}
|
|
100
|
+
|
|
101
|
+
${todoTask}
|
|
102
|
+
|
|
103
|
+
Review the collocated synthesis context and return a structured verdict.
|
|
104
|
+
|
|
105
|
+
**Required in your response:**
|
|
106
|
+
- Verdict: PASS | CONDITIONAL | FAIL
|
|
107
|
+
- Top risks (bulleted)
|
|
108
|
+
- Hardening note / recommendations
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
${collocatedText}`;
|
|
113
|
+
}
|
|
114
|
+
/** Map confer subagent â MCP server + tool. */
|
|
115
|
+
export function conferAgentMcpTarget(subagent) {
|
|
116
|
+
switch (subagent) {
|
|
117
|
+
case 'architect-tools':
|
|
118
|
+
return {
|
|
119
|
+
server: 'architect-tools',
|
|
120
|
+
tool: 'architecture-assessment',
|
|
121
|
+
args: (prompt, projectRoot) => ({
|
|
122
|
+
projectRoot,
|
|
123
|
+
assessmentType: 'comprehensive',
|
|
124
|
+
focusMetrics: ['complexity', 'coupling', 'cohesion', 'testability', 'scalability'],
|
|
125
|
+
conferPrompt: prompt,
|
|
126
|
+
}),
|
|
127
|
+
};
|
|
128
|
+
case 'researcher':
|
|
129
|
+
return {
|
|
130
|
+
server: 'researcher',
|
|
131
|
+
tool: 'analyze_proposal',
|
|
132
|
+
args: (prompt) => ({
|
|
133
|
+
proposalTitle: 'Synthesis confer â researcher',
|
|
134
|
+
proposalDescription: prompt,
|
|
135
|
+
proposalType: 'synthesis-confer',
|
|
136
|
+
evidence: [],
|
|
137
|
+
}),
|
|
138
|
+
};
|
|
139
|
+
case 'code-review':
|
|
140
|
+
default:
|
|
141
|
+
return {
|
|
142
|
+
server: 'code-review',
|
|
143
|
+
tool: 'analyze_proposal',
|
|
144
|
+
args: (prompt) => ({
|
|
145
|
+
proposalTitle: 'Synthesis confer â code-review',
|
|
146
|
+
proposalDescription: prompt,
|
|
147
|
+
proposalType: 'synthesis-confer',
|
|
148
|
+
evidence: [],
|
|
149
|
+
}),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function extractMcpText(result) {
|
|
154
|
+
const content = result?.content;
|
|
155
|
+
if (Array.isArray(content)) {
|
|
156
|
+
return content.map((c) => c.text ?? '').join('\n');
|
|
157
|
+
}
|
|
158
|
+
if (typeof result === 'string')
|
|
159
|
+
return result;
|
|
160
|
+
try {
|
|
161
|
+
return JSON.stringify(result);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return String(result);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
export async function invokeConferAgent(subagent, prompt, projectRoot = process.cwd()) {
|
|
168
|
+
const { mcpClientManager } = await import('../mcps/mcp-client.js');
|
|
169
|
+
const target = conferAgentMcpTarget(subagent);
|
|
170
|
+
const args = target.args(prompt, projectRoot);
|
|
171
|
+
const result = await mcpClientManager.callServerTool(target.server, target.tool, args);
|
|
172
|
+
const text = extractMcpText(result);
|
|
173
|
+
if (!text.trim()) {
|
|
174
|
+
throw new Error(`Empty confer response from ${subagent}`);
|
|
175
|
+
}
|
|
176
|
+
if (!parseConsultVerdictFromText(text)) {
|
|
177
|
+
throw new Error(`Confer response from ${subagent} missing parseable verdict (expected Verdict: PASS|CONDITIONAL|FAIL or DECISION: approve|reject|abstain)`);
|
|
178
|
+
}
|
|
179
|
+
return text;
|
|
180
|
+
}
|
|
181
|
+
export function applyConferConsultResult(todoId, subagent, sessionId, outputText, projectRoot = process.cwd()) {
|
|
182
|
+
const receipt = tryRecordSynthesisConsultReceipt(todoId, subagent, sessionId, outputText, projectRoot);
|
|
183
|
+
let todoCompleted = false;
|
|
184
|
+
if (receipt && receipt.verdict !== 'FAIL') {
|
|
185
|
+
todoCompleted = updatePlanTodoStatus(todoId, 'completed', projectRoot);
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
todoId,
|
|
189
|
+
subagent,
|
|
190
|
+
outputText,
|
|
191
|
+
receiptRecorded: receipt != null,
|
|
192
|
+
todoCompleted,
|
|
193
|
+
verdict: receipt?.verdict ?? buildReceiptFromConsultOutput(todoId, subagent, sessionId, outputText)?.verdict ?? null,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
export function writeFixtureConferReceipt(todoId, subagent, sessionId, projectRoot = process.cwd()) {
|
|
197
|
+
const output = `Verdict: PASS\nTop risks: none\nHardening: confer fixture quorum for ${subagent}`;
|
|
198
|
+
return applyConferConsultResult(todoId, subagent, sessionId, output, projectRoot);
|
|
199
|
+
}
|
|
200
|
+
export async function runConferQuorum(projectRoot = process.cwd(), sessionId, options = {}) {
|
|
201
|
+
const cfg = loadConferConfig(projectRoot);
|
|
202
|
+
if (!cfg.enabled || !cfg.on_synthesis) {
|
|
203
|
+
return {
|
|
204
|
+
status: 'skipped',
|
|
205
|
+
agents: [],
|
|
206
|
+
message: 'Confer disabled in features.json',
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
const plan = loadPersistedLeadDevPlan(projectRoot);
|
|
210
|
+
if (!plan || !isSynthesisRealignmentPlan(plan)) {
|
|
211
|
+
return {
|
|
212
|
+
status: 'skipped',
|
|
213
|
+
agents: [],
|
|
214
|
+
message: 'No synthesis realignment plan â confer not applicable',
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
if (areSynthesisConsultTodosComplete(plan)) {
|
|
218
|
+
return {
|
|
219
|
+
status: 'completed',
|
|
220
|
+
agents: [],
|
|
221
|
+
message: 'Confer already complete â all consult todos finished',
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
const state = triggerConferCheckpoint(sessionId, options.dueReason ?? null, projectRoot);
|
|
225
|
+
state.status = 'in_progress';
|
|
226
|
+
saveConferCheckpoint(state, projectRoot);
|
|
227
|
+
const collocated = options.collocatedText?.trim() ||
|
|
228
|
+
'# Synthesis confer\n\nReview checkpoint context and realign plan.';
|
|
229
|
+
const agents = [];
|
|
230
|
+
for (const todo of getSynthesisConsultTodos(plan)) {
|
|
231
|
+
if (todo.status === 'completed')
|
|
232
|
+
continue;
|
|
233
|
+
try {
|
|
234
|
+
let agentResult;
|
|
235
|
+
if (options.fixture) {
|
|
236
|
+
agentResult = writeFixtureConferReceipt(todo.id, todo.subagent, sessionId, projectRoot);
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
const prompt = buildConferPrompt(todo.subagent, todo.task, collocated, options.dueReason ?? null);
|
|
240
|
+
const outputText = await invokeConferAgent(todo.subagent, prompt, projectRoot);
|
|
241
|
+
agentResult = applyConferConsultResult(todo.id, todo.subagent, sessionId, outputText, projectRoot);
|
|
242
|
+
}
|
|
243
|
+
agents.push(agentResult);
|
|
244
|
+
if (agentResult.receiptRecorded && agentResult.todoCompleted) {
|
|
245
|
+
state.completedAgents.push(todo.subagent);
|
|
246
|
+
saveConferCheckpoint(state, projectRoot);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
state.status = 'failed';
|
|
250
|
+
state.lastError = `Receipt or todo completion failed for ${todo.id}`;
|
|
251
|
+
saveConferCheckpoint(state, projectRoot);
|
|
252
|
+
return {
|
|
253
|
+
status: 'partial',
|
|
254
|
+
agents,
|
|
255
|
+
message: state.lastError,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
261
|
+
state.status = 'failed';
|
|
262
|
+
state.lastError = message;
|
|
263
|
+
saveConferCheckpoint(state, projectRoot);
|
|
264
|
+
agents.push({
|
|
265
|
+
todoId: todo.id,
|
|
266
|
+
subagent: todo.subagent,
|
|
267
|
+
outputText: '',
|
|
268
|
+
receiptRecorded: false,
|
|
269
|
+
todoCompleted: false,
|
|
270
|
+
verdict: null,
|
|
271
|
+
error: message,
|
|
272
|
+
});
|
|
273
|
+
return { status: 'failed', agents, message };
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const refreshed = loadPersistedLeadDevPlan(projectRoot);
|
|
277
|
+
const done = refreshed &&
|
|
278
|
+
isSynthesisRealignmentPlan(refreshed) &&
|
|
279
|
+
areSynthesisConsultTodosComplete(refreshed);
|
|
280
|
+
state.status = done ? 'completed' : 'failed';
|
|
281
|
+
if (!done)
|
|
282
|
+
state.lastError = 'Consult todos remain after confer loop';
|
|
283
|
+
saveConferCheckpoint(state, projectRoot);
|
|
284
|
+
return {
|
|
285
|
+
status: done ? 'completed' : 'partial',
|
|
286
|
+
agents,
|
|
287
|
+
message: done
|
|
288
|
+
? 'Confer quorum complete â researcher, architect-tools, code-review consulted'
|
|
289
|
+
: (state.lastError ?? 'Confer incomplete'),
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
const CONFER_AGENT_EMOJI = {
|
|
293
|
+
researcher: 'đ',
|
|
294
|
+
'architect-tools': 'đī¸',
|
|
295
|
+
'code-review': 'â
',
|
|
296
|
+
'code-reviewer': 'â
',
|
|
297
|
+
architect: 'đī¸',
|
|
298
|
+
strategist: 'đ¯',
|
|
299
|
+
};
|
|
300
|
+
function conferAgentEmoji(subagent) {
|
|
301
|
+
return CONFER_AGENT_EMOJI[subagent] ?? 'đ¤';
|
|
302
|
+
}
|
|
303
|
+
export function formatConferQuorumReport(result) {
|
|
304
|
+
if (result.status === 'skipped') {
|
|
305
|
+
return `âšī¸ Confer skipped: ${result.message}`;
|
|
306
|
+
}
|
|
307
|
+
const lines = [
|
|
308
|
+
`## Confer quorum â ${result.status.toUpperCase()}`,
|
|
309
|
+
result.message,
|
|
310
|
+
'',
|
|
311
|
+
];
|
|
312
|
+
for (const agent of result.agents) {
|
|
313
|
+
const emoji = conferAgentEmoji(agent.subagent);
|
|
314
|
+
lines.push(`- ${emoji} **${agent.todoId}** (${agent.subagent}): verdict=${agent.verdict ?? 'n/a'} receipt=${agent.receiptRecorded} todo=${agent.todoCompleted}${agent.error ? ` error=${agent.error}` : ''}`);
|
|
315
|
+
}
|
|
316
|
+
const plan = loadPersistedLeadDevPlan();
|
|
317
|
+
const next = plan ? getNextRequiredTodo(plan) : null;
|
|
318
|
+
if (next) {
|
|
319
|
+
lines.push('', `**Next todo:** ${next.id} (${next.subagent})`);
|
|
320
|
+
}
|
|
321
|
+
return lines.join('\n');
|
|
322
|
+
}
|
|
@@ -1,18 +1,26 @@
|
|
|
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 { type PendingDelegation } from './pending-delegations.js';
|
|
7
7
|
export { getActivePendingDelegations } from './pending-delegations.js';
|
|
8
8
|
import { updatePlanTodoStatus, type SpawnToolInput } from './lead-dev-plan-persistence.js';
|
|
9
|
-
|
|
9
|
+
import { writeSuitSessionBoot, maybeHeatHostStation, type CeremonyLevel, type SpawnPlanMode, type SuitHost, type SuitProfile } from './suit-temperament.js';
|
|
10
|
+
export { writeSuitSessionBoot, maybeHeatHostStation };
|
|
11
|
+
export { extractSpawnCwd, validateAsideWorktreeCwd, provisionGitWorktree } from './aside-worktree.js';
|
|
12
|
+
export { validateSpawnMatchesTodo, updatePlanTodoStatus, savePersistedLeadDevPlan, archiveStaleLeadDevPlan, findRecentStalePlanArchive, } from './lead-dev-plan-persistence.js';
|
|
10
13
|
export { buildReceiptFromConsultOutput, hasValidSynthesisConsultReceipt, isSynthesisConsultTodoId, loadSynthesisConsultReceipt, parseConsultVerdictFromText, tryRecordSynthesisConsultReceipt, writeSynthesisConsultReceipt, type SynthesisConsultReceipt, type SynthesisConsultVerdict, } from './synthesis-consult-receipt.js';
|
|
11
14
|
export declare const updatePlanTodoStatusInPlace: typeof updatePlanTodoStatus;
|
|
12
|
-
export type DelegationGateHost =
|
|
15
|
+
export type DelegationGateHost = SuitHost;
|
|
13
16
|
export interface DelegationGateFeatures {
|
|
14
17
|
lead_dev_mode: boolean;
|
|
15
18
|
auto_chain_delegations: boolean;
|
|
19
|
+
/** v3 â deny (guided/strict), warn (frontier), off */
|
|
20
|
+
spawn_plan_mode?: SpawnPlanMode;
|
|
21
|
+
ceremony?: CeremonyLevel;
|
|
22
|
+
suit_profile?: SuitProfile;
|
|
23
|
+
no_new_surface?: boolean;
|
|
16
24
|
}
|
|
17
25
|
export interface ToolGateInput {
|
|
18
26
|
prompt?: string;
|
|
@@ -41,6 +49,7 @@ export interface PreToolGateContext {
|
|
|
41
49
|
sessionId: string | null;
|
|
42
50
|
features: DelegationGateFeatures;
|
|
43
51
|
host?: DelegationGateHost;
|
|
52
|
+
hookEvent?: string;
|
|
44
53
|
}
|
|
45
54
|
export interface PreToolGateDeny {
|
|
46
55
|
allow: false;
|
|
@@ -52,6 +61,9 @@ export interface PreToolGateDeny {
|
|
|
52
61
|
}
|
|
53
62
|
export interface PreToolGateAllow {
|
|
54
63
|
allow: true;
|
|
64
|
+
reason?: string;
|
|
65
|
+
gate?: string;
|
|
66
|
+
hint?: Record<string, unknown>;
|
|
55
67
|
}
|
|
56
68
|
export type PreToolGateResult = PreToolGateAllow | PreToolGateDeny;
|
|
57
69
|
export interface PostToolSpawnResult {
|
|
@@ -65,7 +77,7 @@ export interface PostToolSpawnOptions {
|
|
|
65
77
|
toolOutput?: unknown;
|
|
66
78
|
sessionId?: string | null;
|
|
67
79
|
}
|
|
68
|
-
export declare function loadDelegationGateFeatures(projectRoot?: string): DelegationGateFeatures;
|
|
80
|
+
export declare function loadDelegationGateFeatures(projectRoot?: string, host?: DelegationGateHost): DelegationGateFeatures;
|
|
69
81
|
export declare function normalizeHostToolInput(toolInput: ToolGateInput): SpawnToolInput & {
|
|
70
82
|
command?: string;
|
|
71
83
|
};
|
|
@@ -79,10 +91,8 @@ export declare function evaluateSpawnPlanGate(toolName: string, toolInput: ToolG
|
|
|
79
91
|
export declare function evaluateSynthesisGate(toolName: string, toolInput: ToolGateInput, ctx: PreToolGateContext): PreToolGateResult;
|
|
80
92
|
/** Block writes / unrelated work while pending delegations exist. */
|
|
81
93
|
export declare function evaluatePendingDelegationGate(toolName: string, toolInput: ToolGateInput, ctx: PreToolGateContext): PreToolGateResult;
|
|
82
|
-
/**
|
|
83
|
-
|
|
84
|
-
* pending gate, then spawn todo gate for subagent tools.
|
|
85
|
-
*/
|
|
94
|
+
/** Codex 11 / 29 / 69 + destructive shell â always on, all hosts that call this SSOT. */
|
|
95
|
+
export declare function evaluateConstitutionGate(toolName: string, toolInput: ToolGateInput, ctx: PreToolGateContext): PreToolGateResult;
|
|
86
96
|
export declare function evaluatePreToolGate(toolName: string, toolInput: ToolGateInput, ctx: PreToolGateContext): PreToolGateResult;
|
|
87
97
|
export declare function evaluatePostToolSpawn(toolName: string, toolInput: ToolGateInput, projectRoot: string, options?: PostToolSpawnOptions): PostToolSpawnResult;
|
|
88
98
|
export declare function isOrchestrateToolEvent(toolName: string, toolInput?: ToolGateInput): boolean;
|