From 6bf18b53a6503d4824fc2ef462d288e2bb8595e2 Mon Sep 17 00:00:00 2001 From: htafolla Date: Sun, 29 Mar 2026 22:25:46 -0500 Subject: [PATCH 1/9] fix: resolve stale version display and add missing report CLI flags - init.sh: use FRAMEWORK_ROOT/package.json for version (was prioritizing stale node_modules/strray-ai/package.json in dev mode, showing 1.15.19 instead of actual source version) - cli report: add --daily, --performance, --compliance, --session, --ci convenience flags matching AGENTS.md documentation - cli report: fix --output to actually write to file instead of just logging the path --- .opencode/init.sh | 19 +++------------- src/cli/index.ts | 58 +++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 54 insertions(+), 23 deletions(-) diff --git a/.opencode/init.sh b/.opencode/init.sh index c72bef62c..b2b077914 100755 --- a/.opencode/init.sh +++ b/.opencode/init.sh @@ -19,22 +19,9 @@ else FRAMEWORK_ROOT="$PROJECT_ROOT" fi -# StringRay Framework Version - read dynamically from package.json -# Priority: node_modules (installed) > source (development) -get_version() { - # 1. Try node_modules/strray-ai/package.json (installed consumer - THIS IS THE DEPLOYED VERSION) - if [ -f "$PROJECT_ROOT/node_modules/strray-ai/package.json" ]; then - node -e "console.log(require('$PROJECT_ROOT/node_modules/strray-ai/package.json').version)" 2>/dev/null && return - fi - # 2. Try .opencode parent package.json (if running from source) - if [ -f "$SCRIPT_DIR/../package.json" ]; then - node -e "console.log(require('$SCRIPT_DIR/../package.json').version)" 2>/dev/null && return - fi - # Fallback - should never reach here - echo "unknown" -} - -STRRAY_VERSION=$(get_version) +# StringRay Framework Version - read from FRAMEWORK_ROOT (already resolved above) +# FRAMEWORK_ROOT correctly picks source in dev mode, node_modules in consumer mode +STRRAY_VERSION=$(node -e "console.log(require('$FRAMEWORK_ROOT/package.json').version)" 2>/dev/null || echo "unknown") # Dedup guard — prevent duplicate runs during startup # Uses a TTL lockfile (10s window) since OpenCode may trigger config hook diff --git a/src/cli/index.ts b/src/cli/index.ts index be83d653d..e53739044 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -378,27 +378,71 @@ program .description("Generate framework activity and health reports") .option( "-t, --type ", - "Report type (full-analysis, agent-usage, performance)", + "Report type (full-analysis, agent-usage, performance, orchestration, context-awareness)", "full-analysis", ) .option("-o, --output ", "Output file path") + .option("--daily", "Daily report (full-analysis for last 24 hours)") + .option("--performance", "Performance report") + .option("--compliance", "Compliance report (codex violations)") + .option("--session", "Current session report") + .option("--ci", "CI-friendly JSON output for pipelines") .action(async (options) => { - console.log(`šŸ“Š StringRay Framework Report: ${options.type}`); + // Resolve convenience flags to report type + const typeMap: Record = { + daily: "full-analysis", + performance: "performance", + compliance: "full-analysis", + session: "full-analysis", + ci: "full-analysis", + }; + + let reportType = options.type; + let outputFormat: "json" | "markdown" = "json"; + + // Convenience flags override --type + for (const [flag, mappedType] of Object.entries(typeMap)) { + if (options[flag]) { + reportType = mappedType; + break; + } + } + + // CI mode always outputs JSON + if (options.ci) { + outputFormat = "json"; + } + + const label = options.ci + ? "ci" + : options.daily + ? "daily" + : options.performance + ? "performance" + : options.compliance + ? "compliance" + : options.session + ? "session" + : reportType; + + console.log(`šŸ“Š StringRay Framework Report: ${label}`); console.log("=========================================="); console.log(""); try { // Import and run the reporting system directly const { FrameworkReportingSystem } = await import("../reporting/framework-reporting-system.js"); - + const reportingSystem = new FrameworkReportingSystem(); - + const report = await reportingSystem.generateReport({ - type: options.type as any, - outputFormat: "json" + type: reportType as any, + outputFormat, }); - + if (options.output) { + const fs = await import("fs"); + fs.writeFileSync(options.output, report); console.log(`āœ… Report saved to: ${options.output}`); } else { console.log(report); From 7ec26177d048cf0359055a72db46a7ec3acd2bff Mon Sep 17 00:00:00 2001 From: htafolla Date: Mon, 30 Mar 2026 05:19:47 -0500 Subject: [PATCH 2/9] feat: postinstaller installs all 4 git hooks (pre-commit, post-commit, pre-push, post-push) Previously only pre-commit was ever installed (manually). The postinstaller now installs all hooks with smart handling: - Detects existing StringRay hooks and updates if source is newer - Backs up non-StringRay hooks before overwriting - Only installs if .git directory and hook runner exist - Sets executable permissions (755) --- scripts/node/postinstall.cjs | 86 ++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/scripts/node/postinstall.cjs b/scripts/node/postinstall.cjs index 05e56df84..9f6762b68 100755 --- a/scripts/node/postinstall.cjs +++ b/scripts/node/postinstall.cjs @@ -535,6 +535,92 @@ if (fs.existsSync(hermesPluginSource)) { } } +// Install git hooks (pre-commit, post-commit, pre-push, post-push) +const hookNames = ['pre-commit', 'post-commit', 'pre-push', 'post-push']; +const hooksSourceDir = path.join(packageRoot, 'hooks'); +const scriptsHooksDir = path.join(packageRoot, 'scripts', 'hooks'); + +function installGitHooks() { + // Determine git hooks directory + const gitDir = path.join(targetDir, '.git'); + if (!fs.existsSync(gitDir) || !fs.statSync(gitDir).isDirectory()) { + console.log('ā„¹ļø No .git directory found, skipping git hooks installation'); + return; + } + + const gitHooksDir = path.join(gitDir, 'hooks'); + if (!fs.existsSync(gitHooksDir)) { + fs.mkdirSync(gitHooksDir, { recursive: true }); + } + + // Check if the hook runner exists + const hookRunner = path.join(scriptsHooksDir, 'run-hook.js'); + const hookRunnerDist = path.join(packageRoot, 'dist', 'scripts', 'hooks', 'run-hook.js'); + const hasHookRunner = fs.existsSync(hookRunner) || fs.existsSync(hookRunnerDist); + + if (!hasHookRunner) { + console.warn('āš ļø Hook runner not found (scripts/hooks/run-hook.js), skipping git hooks'); + return; + } + + let installed = 0; + let skipped = 0; + + for (const hookName of hookNames) { + const hookSource = path.join(hooksSourceDir, hookName); + const hookDest = path.join(gitHooksDir, hookName); + + if (!fs.existsSync(hookSource)) { + console.warn(`āš ļø Hook script not found: ${hookName}`); + continue; + } + + if (fs.existsSync(hookDest)) { + // Check if it's already a StringRay hook or a symlink to one + try { + const destContent = fs.readFileSync(hookDest, 'utf8'); + if (destContent.includes('StringRay') || destContent.includes('strray')) { + // Already a StringRay hook — update if source is newer + if (fs.statSync(hookSource).mtime > fs.statSync(hookDest).mtime) { + fs.copyFileSync(hookSource, hookDest); + fs.chmodSync(hookDest, 0o755); + installed++; + } else { + skipped++; + } + continue; + } + } catch (e) { + // Can't read — overwrite + } + + // Non-StringRay hook exists — back it up + const backupDest = hookDest + '.strray-backup'; + if (!fs.existsSync(backupDest)) { + fs.copyFileSync(hookDest, backupDest); + console.log(`šŸ“ Backed up existing ${hookName} → ${hookName}.strray-backup`); + } + } + + fs.copyFileSync(hookSource, hookDest); + fs.chmodSync(hookDest, 0o755); + installed++; + } + + if (installed > 0) { + console.log(`āœ… Installed ${installed} git hook(s) (${hookNames.join(', ')})`); + } + if (skipped > 0) { + console.log(`ā„¹ļø ${skipped} git hook(s) already up to date`); + } +} + +try { + installGitHooks(); +} catch (error) { + console.warn('āš ļø Could not install git hooks:', error.message); +} + console.log("šŸ“‹ Next steps:"); console.log("1. Restart OpenCode to load the plugin"); console.log("2. Run 'opencode agent list' to see StrRay agents"); From dda25b90eb3dd7828f57ba04c4b710ae6295892a Mon Sep 17 00:00:00 2001 From: htafolla Date: Mon, 30 Mar 2026 05:32:19 -0500 Subject: [PATCH 3/9] fix: agents_template.md not found in consumer installs + add missing routing-mappings.json - strray-codex-injection.ts: added .opencode/strray/agents_template.md as a codex file location (was only checking .strray/ which may not exist in consumer installs where .opencode/strray/ is the active config dir) - Added routing-mappings.json to .opencode/strray/ in source so the postinstaller copies it to consumers (was only in .strray/ which relies on a symlink that may break) --- .opencode/strray/routing-mappings.json | 752 +++++++++++++++++++++++++ src/plugin/strray-codex-injection.ts | 1 + 2 files changed, 753 insertions(+) create mode 100644 .opencode/strray/routing-mappings.json diff --git a/.opencode/strray/routing-mappings.json b/.opencode/strray/routing-mappings.json new file mode 100644 index 000000000..ba656cd80 --- /dev/null +++ b/.opencode/strray/routing-mappings.json @@ -0,0 +1,752 @@ +[ + { + "keywords": [ + "design", + "architect", + "plan", + "system", + "model", + "pattern", + "scalability", + "dependency", + "structure", + "architecture", + "system-integration", + "delegation", + "complexity-analysis", + "solid", + "clean-architecture" + ], + "skill": "architecture-patterns", + "agent": "architect", + "confidence": 0.95 + }, + { + "keywords": [ + "ux", + "ui", + "interface", + "mockup", + "prototype", + "figma", + "wireframe", + "css", + "html", + "component" + ], + "skill": "ui-ux-design", + "agent": "frontend-ui-ux-engineer", + "confidence": 0.95 + }, + { + "keywords": [ + "frontend", + "react", + "vue", + "angular" + ], + "skill": "frontend-development", + "agent": "frontend-engineer", + "confidence": 0.95 + }, + { + "keywords": [ + "backend", + "api", + "server", + "microservice", + "endpoint" + ], + "skill": "backend-development", + "agent": "backend-engineer", + "confidence": 0.95 + }, + { + "keywords": [ + "fix", + "debug", + "triage", + "broken", + "error", + "crash", + "bug", + "issue", + "resolve", + "root cause", + "debugging", + "error-analysis", + "fix-validation", + "surgical-fix", + "stack-trace", + "error-investigation", + "triage", + "surgical-fix", + "root-cause", + "debugging", + "crash", + "exception", + "fix-validation" + ], + "skill": "bug-triage", + "agent": "bug-triage-specialist", + "confidence": 0.92 + }, + { + "keywords": [ + "security", + "vulnerability", + "threat", + "scan", + "risk", + "exploit", + "secure", + "pentest", + "encrypt", + "vulnerability-detection", + "compliance-monitoring", + "threat-analysis", + "security-validation", + "audit-trail", + "owasp", + "vulnerability", + "threat", + "secrets", + "hardcoded", + "outdated", + "permissions", + "env-exposure", + "ssl", + "tls", + "https", + "dependency-audit", + "owasp" + ], + "skill": "security-audit", + "agent": "security-auditor", + "confidence": 0.95 + }, + { + "keywords": [ + "review", + "audit", + "assess", + "evaluate", + "check", + "inspect", + "quality", + "validate", + "code-review", + "quality-assurance", + "monitoring", + "analytics", + "compliance-validation", + "pull-request", + "pr-review", + "linting", + "quality-metrics", + "improvement" + ], + "skill": "code-review", + "agent": "code-reviewer", + "confidence": 0.9 + }, + { + "keywords": [ + "test", + "testing", + "jest", + "coverage", + "unit", + "e2e", + "cypress", + "qa", + "spec", + "verify", + "validate", + "test-auto-creation", + "test-strategy-design", + "coverage-optimization", + "behavioral-testing", + "performance-validation", + "qa", + "quality-assurance", + "test-automation", + "unit-test", + "integration-test", + "e2e-test", + "test-coverage", + "coverage-analysis" + ], + "skill": "testing-best-practices", + "agent": "testing-lead", + "confidence": 0.95 + }, + { + "keywords": [ + "refactor", + "cleanup", + "improve", + "restructure", + "modernize", + "debt", + "dry", + "consolidate", + "technical-debt-elimination", + "code-consolidation", + "surgical-refactoring", + "maintainability-enhancement", + "code-quality", + "maintainability", + "restructure", + "consolidation", + "debt", + "authentication", + "auth system", + "oauth", + "jwt", + "session management" + ], + "skill": "refactoring-strategies", + "agent": "refactorer", + "confidence": 0.92 + }, + { + "keywords": [ + "performance", + "optimize", + "bottleneck", + "benchmark", + "profile", + "speed", + "latency", + "performance-profiling", + "resource-optimization", + "load-testing", + "bottleneck-analysis", + "caching-optimization", + "memory-optimization", + "core-web-vitals", + "lcp", + "inp", + "cls", + "metrics", + "build-time", + "memory-usage", + "load-time", + "bundle-size", + "optimization", + "bottleneck", + "profiling", + "monitoring", + "perf" + ], + "skill": "performance-optimization", + "agent": "performance-engineer", + "confidence": 0.93 + }, + { + "keywords": [ + "deploy", + "ci/cd", + "pipeline", + "docker", + "kubernetes", + "infrastructure", + "aws", + "cloud" + ], + "skill": "devops-deployment", + "agent": "devops-engineer", + "confidence": 0.94 + }, + { + "keywords": [ + "database", + "db", + "sql", + "schema", + "migration", + "query", + "postgres", + "mysql", + "mongodb" + ], + "skill": "database-design", + "agent": "database-engineer", + "confidence": 0.95 + }, + { + "keywords": [ + "docs", + "documentation", + "readme", + "wiki", + "guide", + "manual", + "document", + "write" + ], + "skill": "documentation-generation", + "agent": "tech-writer", + "confidence": 0.9 + }, + { + "keywords": [ + "codebase", + "codebase-exploration", + "context-building", + "discover", + "documentation-retrieval", + "explore", + "implementation", + "lookup", + "pattern-recognition", + "research", + "search" + ], + "skill": "git-workflow", + "agent": "researcher", + "confidence": 0.88 + }, + { + "keywords": [ + "story", + "narrative", + "journey", + "saga", + "reflection", + "write a", + "deep-reflection", + "technical-story" + ], + "skill": "storytelling", + "agent": "storyteller", + "confidence": 0.95 + }, + { + "keywords": [ + "seo", + "search", + "ranking", + "google", + "meta", + "sitemap", + "optimize" + ], + "skill": "seo-consultant", + "agent": "seo-consultant", + "confidence": 0.96 + }, + { + "keywords": [ + "marketing", + "growth", + "content", + "blog", + "campaign", + "metric", + "acquisition" + ], + "skill": "growth-strategist", + "agent": "growth-strategist", + "confidence": 0.92 + }, + { + "keywords": [ + "mobile", + "ios", + "android", + "react-native", + "flutter", + "swift", + "kotlin" + ], + "skill": "mobile-development", + "agent": "mobile-developer", + "confidence": 0.95 + }, + { + "keywords": [ + "log", + "monitor", + "anomaly", + "alert", + "observability", + "watch", + "trace" + ], + "skill": "log-monitor", + "agent": "log-monitor", + "confidence": 0.93 + }, + { + "keywords": [ + "image", + "diagram", + "visual", + "screenshot", + "photo", + "look at" + ], + "skill": "multimodal-looker", + "agent": "multimodal-looker", + "confidence": 0.94 + }, + { + "keywords": [ + "complexity", + "metrics", + "static analysis", + "measure", + "assess", + "code-analysis", + "system-analysis", + "dependency-analysis", + "performance-analysis", + "security-analysis", + "architecture-analysis", + "technical-debt-assessment", + "integration-analysis", + "comprehensive-reporting", + "examine", + "static-analysis", + "complexity", + "metrics", + "code-quality", + "anti-pattern", + "lint", + "eslint", + "prettier", + "format", + "performance" + ], + "skill": "code-analyzer", + "agent": "code-analyzer", + "confidence": 0.9 + }, + { + "keywords": [ + "branch", + "codebase", + "commit", + "conflict", + "discover", + "explore", + "git", + "merge", + "repository", + "version" + ], + "skill": "git-workflow", + "agent": "researcher", + "confidence": 0.88 + }, + { + "keywords": [ + "enforce", + "compliance", + "rule", + "standard", + "codex", + "block", + "prevent", + "error-prevention", + "systematic-validation", + "codex-enforcement", + "security-policy", + "compliance", + "threshold", + "audit", + "lint", + "pre-commit", + "introspection", + "bundle-size", + "test-coverage", + "duplication", + "jscpd", + "syntax-error", + "error-handling", + "convention", + "framework-compliance" + ], + "skill": "enforcer", + "agent": "enforcer", + "confidence": 0.95 + }, + { + "keywords": [ + "orchestrate", + "coordinate", + "delegate", + "workflow", + "manage", + "multi-step", + "multi-agent-orchestration", + "workflow-management", + "task-delegation", + "conflict-resolution", + "session-management" + ], + "skill": "orchestrator", + "agent": "orchestrator", + "confidence": 0.94 + }, + { + "keywords": [ + "plan", + "strategy", + "roadmap", + "vision", + "goal", + "objective", + "prioritize", + "decide" + ], + "skill": "strategist", + "agent": "strategist", + "confidence": 0.9 + }, + { + "keywords": [ + "format", + "formatting", + "prettier", + "lint:fix", + "auto-format", + "code-style" + ], + "skill": "auto-format", + "agent": "enforcer", + "confidence": 0.9 + }, + { + "keywords": [ + "session", + "state", + "persistence", + "recovery", + "backup" + ], + "skill": "session-management", + "agent": "orchestrator", + "confidence": 0.85 + }, + { + "keywords": [ + "api", + "endpoint", + "rest", + "graphql", + "request", + "response", + "openapi" + ], + "skill": "api-design", + "agent": "backend-engineer", + "confidence": 0.92 + }, + { + "keywords": [ + "stress-test-0" + ], + "agent": "bug-triage-specialist", + "skill": "bug-triage", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T21:42:16.150Z" + }, + { + "keywords": [ + "stress-test-1" + ], + "agent": "code-reviewer", + "skill": "code-review", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T21:42:16.150Z" + }, + { + "keywords": [ + "stress-test-2", + "perf" + ], + "agent": "performance-engineer", + "skill": "performance-optimization", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T21:42:16.150Z" + }, + { + "keywords": [ + "stress-test-3" + ], + "agent": "testing-lead", + "skill": "testing-best-practices", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T21:42:16.150Z" + }, + { + "keywords": [ + "stress-test-4" + ], + "agent": "security-auditor", + "skill": "security-audit", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T21:42:16.150Z" + }, + { + "keywords": [ + "e2e-1" + ], + "agent": "code-reviewer", + "skill": "code-review", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T22:33:49.731Z" + }, + { + "keywords": [ + "e2e-2", + "perf" + ], + "agent": "performance-engineer", + "skill": "performance-optimization", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T22:33:49.732Z" + }, + { + "keywords": [ + "e2e-3" + ], + "agent": "testing-lead", + "skill": "testing-best-practices", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T22:33:49.732Z" + }, + { + "keywords": [ + "e2e-4" + ], + "agent": "security-auditor", + "skill": "security-audit", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T22:33:49.732Z" + }, + { + "keywords": [ + "e2e-5" + ], + "agent": "refactorer", + "skill": "refactoring-strategies", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T22:33:49.733Z" + }, + { + "keywords": [ + "test-0.5529761171611898" + ], + "agent": "bug-triage-specialist", + "skill": "bug-triage", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T22:39:21.456Z" + }, + { + "keywords": [ + "test-0.16742614828927516" + ], + "agent": "code-reviewer", + "skill": "code-review", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T22:39:21.456Z" + }, + { + "keywords": [ + "test-0.48963983958092205", + "perf" + ], + "agent": "performance-engineer", + "skill": "performance-optimization", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T22:39:21.456Z" + }, + { + "keywords": [ + "test-0.8717365494490283" + ], + "agent": "security-auditor", + "skill": "security-audit", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T22:39:21.456Z" + }, + { + "keywords": [ + "test-0.3362740549961909" + ], + "agent": "refactorer", + "skill": "refactoring-strategies", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T22:39:21.457Z" + }, + { + "keywords": [ + "pipeline-0" + ], + "agent": "bug-triage-specialist", + "skill": "bug-triage", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T23:46:49.805Z" + }, + { + "keywords": [ + "pipeline-1" + ], + "agent": "code-reviewer", + "skill": "code-review", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T23:46:49.806Z" + }, + { + "keywords": [ + "pipeline-2", + "perf" + ], + "agent": "performance-engineer", + "skill": "performance-optimization", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T23:46:49.807Z" + }, + { + "keywords": [ + "pipeline-3" + ], + "agent": "testing-lead", + "skill": "testing-best-practices", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T23:46:49.807Z" + }, + { + "keywords": [ + "pipeline-4" + ], + "agent": "security-auditor", + "skill": "security-audit", + "confidence": 0.9, + "autoGenerated": true, + "autoGeneratedAt": "2026-03-20T23:46:49.807Z" + } +] \ No newline at end of file diff --git a/src/plugin/strray-codex-injection.ts b/src/plugin/strray-codex-injection.ts index 03858df44..cf20d67dc 100644 --- a/src/plugin/strray-codex-injection.ts +++ b/src/plugin/strray-codex-injection.ts @@ -382,6 +382,7 @@ async function getCodexFileLocations(directory?: string): Promise { resolved.push( path.join(root, ".opencode", "codex.codex"), path.join(root, ".strray", "agents_template.md"), + path.join(root, ".opencode", "strray", "agents_template.md"), path.join(root, "AGENTS.md"), ); return resolved; From 40121d2d73e6e6840eff78dd126d16961c3510dc Mon Sep 17 00:00:00 2001 From: htafolla Date: Mon, 30 Mar 2026 05:38:30 -0500 Subject: [PATCH 4/9] =?UTF-8?q?fix:=20eliminate=20hardcoded=20config=20pat?= =?UTF-8?q?hs=20=E2=80=94=20use=20config-paths=20resolver=20throughout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Files that hardcoded .opencode/strray/ or .strray/ and missed the alternate path in consumer installs: - codex-loader.ts: was hardcoded to .opencode/strray/codex.json, now uses resolveCodexPath() which checks both .strray/ and .opencode/strray/ - PostProcessor.ts: was hardcoded to .opencode/strray/features.json, now uses resolveConfigPath() with fallback - agent-delegator.ts: routing-mappings candidates now includes .strray/ - inference-tuner.ts: routing-mappings candidates now includes .strray/ - validate-codex.mjs: now also checks .opencode/strray/ for codex.json --- scripts/node/validate-codex.mjs | 12 ++++++++++++ src/delegation/agent-delegator.ts | 1 + src/enforcement/loaders/codex-loader.ts | 8 +++++++- src/postprocessor/PostProcessor.ts | 3 ++- src/services/inference-tuner.ts | 1 + 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/scripts/node/validate-codex.mjs b/scripts/node/validate-codex.mjs index 276307158..9b6de8a35 100644 --- a/scripts/node/validate-codex.mjs +++ b/scripts/node/validate-codex.mjs @@ -129,6 +129,18 @@ if (isDevelopment) { } else { console.warn(".strray directory not found"); } + + // Check .opencode/strray directory + if (fs.existsSync(".opencode/strray")) { + console.log(".opencode/strray directory exists"); + if (fs.existsSync(".opencode/strray/codex.json")) { + console.log("codex.json exists"); + } else { + console.warn("codex.json not found in .opencode/strray"); + } + } else { + console.warn(".opencode/strray directory not found"); + } } console.log("All validation checks passed"); diff --git a/src/delegation/agent-delegator.ts b/src/delegation/agent-delegator.ts index ac3eddea8..f3784c0cf 100644 --- a/src/delegation/agent-delegator.ts +++ b/src/delegation/agent-delegator.ts @@ -118,6 +118,7 @@ export class AgentDelegator { */ private loadRoutingMappings(): RoutingMapping[] { const candidates = [ + path.resolve(process.cwd(), ".strray/routing-mappings.json"), path.resolve(process.cwd(), "strray/routing-mappings.json"), path.resolve(process.cwd(), ".opencode/strray/routing-mappings.json"), path.resolve(process.cwd(), "routing-mappings.json"), diff --git a/src/enforcement/loaders/codex-loader.ts b/src/enforcement/loaders/codex-loader.ts index e204d9d7f..dcfceeee7 100644 --- a/src/enforcement/loaders/codex-loader.ts +++ b/src/enforcement/loaders/codex-loader.ts @@ -11,6 +11,8 @@ */ import { frameworkLogger } from "../../core/framework-logger.js"; +import { resolveCodexPath } from "../../core/config-paths.js"; +import { existsSync } from "fs"; import { BaseLoader, } from "./base-loader.js"; @@ -40,9 +42,13 @@ export class CodexLoader extends BaseLoader { /** * Path to the codex.json file. + * Uses the standard config-paths resolver which checks .strray/, .opencode/strray/, etc. */ private get codexPath(): string { - return this.resolvePath(".opencode/strray/codex.json"); + const candidates = resolveCodexPath(); + const found = candidates.find((p) => existsSync(p)); + // Fallback to primary path even if not found yet + return found ?? candidates[0] ?? this.resolvePath(".opencode/strray/codex.json"); } /** diff --git a/src/postprocessor/PostProcessor.ts b/src/postprocessor/PostProcessor.ts index a27739848..dfbed1f79 100644 --- a/src/postprocessor/PostProcessor.ts +++ b/src/postprocessor/PostProcessor.ts @@ -10,6 +10,7 @@ import * as path from "path"; import { frameworkLogger } from "../core/framework-logger.js"; +import { resolveConfigPath } from "../core/config-paths.js"; import { StringRayStateManager } from "../state/state-manager.js"; import { SessionMonitor } from "../session/session-monitor.js"; import { GitHookTrigger } from "./triggers/GitHookTrigger.js"; @@ -340,7 +341,7 @@ export class PostProcessor { const path = await import("path"); try { - const configPath = path.join(process.cwd(), ".opencode/strray/features.json"); + const configPath = resolveConfigPath("features.json") ?? path.join(process.cwd(), ".opencode", "strray", "features.json"); if (fs.existsSync(configPath)) { const config = JSON.parse(fs.readFileSync(configPath, "utf-8")); return config.processors || {}; diff --git a/src/services/inference-tuner.ts b/src/services/inference-tuner.ts index bbbc782d3..c91fe4bb4 100644 --- a/src/services/inference-tuner.ts +++ b/src/services/inference-tuner.ts @@ -288,6 +288,7 @@ export class InferenceTuner { */ private resolveMappingsPath(): string | null { const candidates = [ + path.resolve(process.cwd(), ".strray/routing-mappings.json"), path.resolve(process.cwd(), "strray/routing-mappings.json"), path.resolve(process.cwd(), ".opencode/strray/routing-mappings.json"), path.resolve(process.cwd(), "routing-mappings.json"), From 715541d80b43aa73537614b0da9ea3da9a2cee6b Mon Sep 17 00:00:00 2001 From: htafolla Date: Mon, 30 Mar 2026 05:59:46 -0500 Subject: [PATCH 5/9] =?UTF-8?q?fix:=20eliminate=20all=20hardcoded=20config?= =?UTF-8?q?=20paths=20=E2=80=94=20centralize=20on=20config-paths=20resolve?= =?UTF-8?q?r?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every config file reference now goes through the canonical resolver which checks STRRAY_CONFIG_DIR > .strray/ > .opencode/strray/ in priority order. Source files (use config-paths.ts directly): - config-loader.ts, features-config.ts, consent-manager.ts: fallback now uses getConfigDir() instead of hardcoded .strray/ - universal-registry-bridge.ts: cache dir uses getConfigDir() instead of hardcoded .opencode/strray/ relative to __dirname - universal-librarian-consultation.ts: codex version tracking uses resolveConfigPath() instead of hardcoded .opencode/strray/codex.json - autonomous-report-generator.ts, system-prompt-generator.ts, strray-codex-injection.ts: user-facing strings updated - cli/index.ts: status command shows actual config dir path - profiling-demo.ts: uses resolveProfilesDir() Scripts (use new shared helpers): - Added scripts/helpers/resolve-config-path.mjs and .cjs — mirrors src/core/config-paths.ts logic for non-TS scripts - boot-check.mjs, pre-publish-guard.js, validate-codex.mjs, universal-version-manager.js, generate-autonomous-report.cjs, test-mcp-registration.mjs, validate-postinstall-config.mjs: all now use the shared resolver instead of hardcoded paths This ensures StringRay works correctly in all three environments: - Hermes Agent (uses STRRAY_CONFIG_DIR or .strray/) - OpenCode (uses .opencode/strray/) - OpenClaw (uses STRRAY_CONFIG_DIR) --- scripts/helpers/resolve-config-path.cjs | 59 +++++++++++++++ scripts/helpers/resolve-config-path.mjs | 75 +++++++++++++++++++ scripts/mjs/test-mcp-registration.mjs | 3 +- scripts/mjs/test-postinstall-files.mjs | 4 +- scripts/mjs/validate-postinstall-config.mjs | 6 +- scripts/node/boot-check.mjs | 4 +- scripts/node/generate-autonomous-report.cjs | 21 ++++-- scripts/node/pre-publish-guard.js | 3 +- scripts/node/profiling-demo.js | 2 +- scripts/node/universal-version-manager.js | 12 ++- scripts/node/validate-codex.mjs | 3 +- src/analytics/consent-manager.ts | 4 +- src/cli/index.ts | 4 +- src/core/config-loader.ts | 6 +- src/core/features-config.ts | 4 +- src/core/system-prompt-generator.ts | 6 +- src/enforcement/loaders/codex-loader.ts | 2 +- .../universal-librarian-consultation.ts | 4 +- src/orchestrator/universal-registry-bridge.ts | 3 +- src/plugin/strray-codex-injection.ts | 4 +- src/reporting/autonomous-report-generator.ts | 4 +- src/scripts/profiling-demo.ts | 3 +- 22 files changed, 197 insertions(+), 39 deletions(-) create mode 100644 scripts/helpers/resolve-config-path.cjs create mode 100644 scripts/helpers/resolve-config-path.mjs diff --git a/scripts/helpers/resolve-config-path.cjs b/scripts/helpers/resolve-config-path.cjs new file mode 100644 index 000000000..79d9c3b81 --- /dev/null +++ b/scripts/helpers/resolve-config-path.cjs @@ -0,0 +1,59 @@ +/** + * Shared config path resolver for StringRay scripts (CJS version). + * Mirrors src/core/config-paths.ts logic. + */ + +"use strict"; +const { existsSync } = require("fs"); +const { join, resolve } = require("path"); + +const STRRAY_CONFIG_DIR_ENV = "STRRAY_CONFIG_DIR"; + +const _cache = new Map(); + +function getConfigDir(projectRoot) { + const root = projectRoot || process.cwd(); + const cached = _cache.get(root); + if (cached) return cached; + + const envDir = process.env[STRRAY_CONFIG_DIR_ENV]; + const candidates = []; + + if (envDir) { + candidates.push(resolve(root, envDir)); + } + candidates.push(join(root, ".strray")); + candidates.push(join(root, ".opencode", "strray")); + + for (const dir of candidates) { + if (existsSync(dir)) { + _cache.set(root, dir); + return dir; + } + } + + _cache.set(root, candidates[0]); + return candidates[0]; +} + +function resolveConfigPath(relativePath, projectRoot) { + const root = projectRoot || process.cwd(); + const envDir = process.env[STRRAY_CONFIG_DIR_ENV]; + + const candidates = []; + if (envDir) { + candidates.push(resolve(root, envDir, relativePath)); + } + candidates.push(join(root, ".strray", relativePath)); + candidates.push(join(root, ".opencode", "strray", relativePath)); + + for (const candidate of candidates) { + if (existsSync(candidate)) { + return candidate; + } + } + + return candidates[0] || null; +} + +module.exports = { getConfigDir, resolveConfigPath, STRRAY_CONFIG_DIR_ENV }; diff --git a/scripts/helpers/resolve-config-path.mjs b/scripts/helpers/resolve-config-path.mjs new file mode 100644 index 000000000..0702fff47 --- /dev/null +++ b/scripts/helpers/resolve-config-path.mjs @@ -0,0 +1,75 @@ +#!/usr/bin/env node + +/** + * Shared config path resolver for StringRay scripts (.mjs/.cjs/.js). + * + * Mirrors the logic in src/core/config-paths.ts so scripts don't need to + * import compiled TypeScript. Supports STRRAY_CONFIG_DIR env var. + * + * Usage: + * import { getConfigDir, resolveConfigPath } from "../helpers/resolve-config-path.mjs"; + * // or for CJS: + * const { getConfigDir, resolveConfigPath } = require("../helpers/resolve-config-path.cjs"); + */ + +import { existsSync } from "fs"; +import { join, resolve } from "path"; + +const STRRAY_CONFIG_DIR_ENV = "STRRAY_CONFIG_DIR"; + +/** Cache of resolved config dirs per project root */ +const _cache = new Map(); + +/** + * Detect the best available config directory. + * Priority: STRRAY_CONFIG_DIR > .strray > .opencode/strray + */ +export function getConfigDir(projectRoot) { + const root = projectRoot || process.cwd(); + const cached = _cache.get(root); + if (cached) return cached; + + const envDir = process.env[STRRAY_CONFIG_DIR_ENV]; + const candidates = []; + + if (envDir) { + candidates.push(resolve(root, envDir)); + } + candidates.push(join(root, ".strray")); + candidates.push(join(root, ".opencode", "strray")); + + for (const dir of candidates) { + if (existsSync(dir)) { + _cache.set(root, dir); + return dir; + } + } + + // Default: highest priority (env > .strray > .opencode/strray) + _cache.set(root, candidates[0]); + return candidates[0]; +} + +/** + * Resolve a specific config file using the standard priority chain. + * Returns the first existing candidate, or the highest-priority default. + */ +export function resolveConfigPath(relativePath, projectRoot) { + const root = projectRoot || process.cwd(); + const envDir = process.env[STRRAY_CONFIG_DIR_ENV]; + + const candidates = []; + if (envDir) { + candidates.push(resolve(root, envDir, relativePath)); + } + candidates.push(join(root, ".strray", relativePath)); + candidates.push(join(root, ".opencode", "strray", relativePath)); + + for (const candidate of candidates) { + if (existsSync(candidate)) { + return candidate; + } + } + + return candidates[0] || null; +} diff --git a/scripts/mjs/test-mcp-registration.mjs b/scripts/mjs/test-mcp-registration.mjs index 12e847e0d..949101890 100644 --- a/scripts/mjs/test-mcp-registration.mjs +++ b/scripts/mjs/test-mcp-registration.mjs @@ -62,7 +62,8 @@ function test(name, fn) { // Load features.json function loadFeatures() { - const featuresPath = path.join(rootDir, '.opencode/strray/features.json'); + const { resolveConfigPath } = await import('../helpers/resolve-config-path.mjs'); + const featuresPath = resolveConfigPath('features.json', rootDir); if (!fs.existsSync(featuresPath)) { throw new Error('features.json not found'); } diff --git a/scripts/mjs/test-postinstall-files.mjs b/scripts/mjs/test-postinstall-files.mjs index b519af37a..f9e8e4d67 100644 --- a/scripts/mjs/test-postinstall-files.mjs +++ b/scripts/mjs/test-postinstall-files.mjs @@ -158,7 +158,7 @@ class PostinstallFileValidator { try { // NOTE: .opencode/OpenCode.json is NOT required and can cause OpenCode boot issues - // The framework uses .opencode/strray/config.json for configuration instead + // The framework uses the config-paths resolver (checks .strray/, .opencode/strray/, STRRAY_CONFIG_DIR) for configuration instead const ohMyOpencodePath = path.join( process.cwd(), ".opencode", @@ -170,7 +170,7 @@ class PostinstallFileValidator { console.log(" ā„¹ļø .opencode/OpenCode.json not found (optional - using strray/config.json instead)"); this.results.passed.push({ test: "OpenCode Config File", - details: "Optional - using .opencode/strray/config.json instead" + details: "Optional - using config-paths resolver for config.json" }); return; } diff --git a/scripts/mjs/validate-postinstall-config.mjs b/scripts/mjs/validate-postinstall-config.mjs index 533e577ae..644ca6179 100644 --- a/scripts/mjs/validate-postinstall-config.mjs +++ b/scripts/mjs/validate-postinstall-config.mjs @@ -56,8 +56,10 @@ check('.opencode/hooks/post-commit', 'Post-commit hook'); check('.opencode/hooks/post-push', 'Post-push hook'); // Check strray config -check('.opencode/strray/config.json', 'StrRay config'); -check('.opencode/strray/features.json', 'StrRay features'); +const { getConfigDir } = await import('../helpers/resolve-config-path.mjs'); +const _cd = getConfigDir(); +check(_cd + '/config.json', 'StrRay config'); +check(_cd + '/features.json', 'StrRay features'); console.log('\n══════════════════════════════════════════════════'); diff --git a/scripts/node/boot-check.mjs b/scripts/node/boot-check.mjs index aa814526d..dbaf69dfa 100644 --- a/scripts/node/boot-check.mjs +++ b/scripts/node/boot-check.mjs @@ -136,7 +136,9 @@ class BootChecker { async checkLogging() { const projectRoot = path.join(__dirname, "..", ".."); - const logDir = path.join(projectRoot, ".strray/logs"); + const { getConfigDir } = await import("../helpers/resolve-config-path.mjs"); + const configDir = getConfigDir(projectRoot); + const logDir = path.join(configDir, "logs"); if (!fs.existsSync(logDir)) { return { logFiles: 0, loggingDisabled: true }; } diff --git a/scripts/node/generate-autonomous-report.cjs b/scripts/node/generate-autonomous-report.cjs index 262ae8458..91acfabc5 100644 --- a/scripts/node/generate-autonomous-report.cjs +++ b/scripts/node/generate-autonomous-report.cjs @@ -17,7 +17,9 @@ class MinimalAutonomousReportGenerator { try { const path = require('path'); const fs = require('fs'); - const configPath = path.join(__dirname, '..', '.strray', 'config.json'); + const { getConfigDir } = require('../helpers/resolve-config-path.cjs'); + const configDir = getConfigDir(); + const configPath = path.join(configDir, 'config.json'); if (fs.existsSync(configPath)) { const configContent = fs.readFileSync(configPath, 'utf8'); const config = JSON.parse(configContent); @@ -61,7 +63,8 @@ class MinimalAutonomousReportGenerator { checkIfEnabled() { if (!this.config.enabled) { console.log('āŒ Autonomous reporting is disabled in configuration.'); - console.log(' To enable, set autonomous_reporting.enabled: true in .strray/config.json'); + const { getConfigDir: _gcd } = require('../helpers/resolve-config-path.cjs'); + console.log(` To enable, set autonomous_reporting.enabled: true in ${_gcd()}/config.json`); console.log(''); console.log('Example configuration:'); console.log(JSON.stringify({ @@ -308,11 +311,13 @@ Session Summary: ${report.summary.recommendation} if (this.config._setup_instructions) { console.log('1. Create the configuration directory:'); - console.log(' mkdir -p .strray'); + console.log(' mkdir -p ' + _cd2); console.log(''); - console.log('2. Create .strray/config.json with:'); + const { getConfigDir: _gcd2 } = require('../helpers/resolve-config-path.cjs'); + const _cd2 = _gcd2(); + console.log('2. Create ' + _cd2 + '/config.json with:'); } else { - console.log('1. Update .strray/config.json to include:'); + console.log('1. Update ' + _cd2 + '/config.json to include:'); } console.log(' {'); @@ -358,9 +363,11 @@ async function main() { const config = generator.getConfig(); if (config._setup_instructions) { console.log('šŸ“‹ Configuration Status: Not configured'); - console.log(' No .strray/config.json file found.'); + const { getConfigDir: _gcd3 } = require('../helpers/resolve-config-path.cjs'); + const _cd3 = _gcd3(); + console.log(' No ' + _cd3 + '/config.json file found.'); console.log(''); - console.log('šŸ“‹ To enable autonomous reporting, create .strray/config.json with:'); + console.log('šŸ“‹ To enable autonomous reporting, create ' + _cd3 + '/config.json with:'); console.log(' {'); console.log(' "autonomous_reporting": {'); console.log(' "enabled": true,'); diff --git a/scripts/node/pre-publish-guard.js b/scripts/node/pre-publish-guard.js index 0fc5746cd..bbdbf0f38 100644 --- a/scripts/node/pre-publish-guard.js +++ b/scripts/node/pre-publish-guard.js @@ -159,7 +159,8 @@ function checkVersionManagerRan() { const vmContent = fs.readFileSync(vmPath, 'utf-8'); // Check that files have been updated (look for recent timestamps or version) - const featuresPath = path.join(rootDir, '.opencode/strray/features.json'); + const { resolveConfigPath } = require('../helpers/resolve-config-path.cjs'); + const featuresPath = resolveConfigPath('features.json', rootDir); const features = JSON.parse(fs.readFileSync(featuresPath, 'utf-8')); // Version manager should have updated strray_version diff --git a/scripts/node/profiling-demo.js b/scripts/node/profiling-demo.js index 5a52b47f1..910fa7e03 100644 --- a/scripts/node/profiling-demo.js +++ b/scripts/node/profiling-demo.js @@ -98,7 +98,7 @@ async function simulateAgentOperations() { await new Promise((resolve) => setTimeout(resolve, 65000)); // Wait for report generation console.log("\nšŸŽ‰ Profiling demo completed successfully!"); console.log( - "šŸ“Š Check the .opencode/strray/profiles/ directory for performance reports", + "šŸ“Š Check the profiles directory for performance reports", ); // Cleanup enterpriseMonitoringSystem.stop(); diff --git a/scripts/node/universal-version-manager.js b/scripts/node/universal-version-manager.js index 24a128586..56eb1b4ff 100644 --- a/scripts/node/universal-version-manager.js +++ b/scripts/node/universal-version-manager.js @@ -356,7 +356,8 @@ const UPDATE_PATTERNS = [ let warnings = []; // 1. Check codex.json has exactly 60 terms - const codexJsonPath = ".opencode/strray/codex.json"; + const { resolveConfigPath } = require("../helpers/resolve-config-path.cjs"); + const codexJsonPath = resolveConfigPath("codex.json") || ".opencode/strray/codex.json"; if (fs.existsSync(codexJsonPath)) { try { const codexContent = JSON.parse(fs.readFileSync(codexJsonPath, "utf8")); @@ -520,11 +521,14 @@ const UPDATE_PATTERNS = [ // Phase 1: Explicitly update critical .opencode config files console.log("\nšŸ“ Phase 1: Updating .opencode configuration files..."); + const { resolveConfigPath: rcp } = require("../helpers/resolve-config-path.cjs"); + const codexPath = rcp("codex.json") || ".opencode/strray/codex.json"; + const featuresPath = rcp("features.json") || ".opencode/strray/features.json"; const criticalConfigFiles = [ - ".opencode/strray/codex.json", // Legacy codex config + codexPath, // Codex config ".opencode/codex.codex", // Main codex (17 terms) ".opencode/package.json", // OpenCode package.json - ".opencode/strray/features.json", // Feature flags + featuresPath, // Feature flags ]; let configFilesUpdated = 0; @@ -567,7 +571,7 @@ const UPDATE_PATTERNS = [ const documentationFiles = [ "AGENTS.md", ".opencode/AGENTS-consumer.md", - ".opencode/strray/agents_template.md", + rcp("agents_template.md") || ".opencode/strray/agents_template.md", "docs/reference/templates/agents_template.md", "docs/reference/templates/master-agent-template.md", "docs/reference/templates/agent-template-dev.md", diff --git a/scripts/node/validate-codex.mjs b/scripts/node/validate-codex.mjs index 9b6de8a35..bf54c2d1c 100644 --- a/scripts/node/validate-codex.mjs +++ b/scripts/node/validate-codex.mjs @@ -63,9 +63,10 @@ if (isDeployed) { // Development environment checks if (isDevelopment) { // Check if codex files exist + const { resolveConfigPath: _rcp } = await import("../helpers/resolve-config-path.mjs"); const codexFiles = [ "docs/framework/agents_template.md", - ".opencode/strray/agents_template.md", + _rcp("agents_template.md") || ".opencode/strray/agents_template.md", ]; let codexFound = false; diff --git a/src/analytics/consent-manager.ts b/src/analytics/consent-manager.ts index 2b5556a12..d3f6520de 100644 --- a/src/analytics/consent-manager.ts +++ b/src/analytics/consent-manager.ts @@ -11,7 +11,7 @@ import * as fs from "fs/promises"; import * as path from "path"; import { frameworkLogger } from "../core/framework-logger.js"; -import { resolveConfigPath } from "../core/config-paths.js"; +import { getConfigDir, resolveConfigPath } from "../core/config-paths.js"; export interface ConsentConfiguration { analyticsEnabled: boolean; @@ -39,7 +39,7 @@ export class ConsentManager { private submissionQueue: any[] = []; constructor(configPath: string | undefined = undefined) { - this.configPath = configPath || resolveConfigPath("consent.json") || ".strray/consent.json"; +this.configPath = configPath || resolveConfigPath("consent.json") || path.join(getConfigDir(), "consent.json"); } /** diff --git a/src/cli/index.ts b/src/cli/index.ts index e53739044..f82451c9b 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -626,9 +626,9 @@ program if (opencodeExists) { console.log("āœ… opencode configuration found"); } else if (strrayDirExists) { - console.log("āœ… .strray/ configuration directory found"); + console.log(`āœ… Configuration directory found: ${strrayDir}`); } else { - console.log("ā„¹ļø No opencode.json or .strray/ directory found (run: npx strray-ai fix to create)"); + console.log("ā„¹ļø No opencode.json or config directory found (run: npx strray-ai fix to create)"); } // Check for common issues diff --git a/src/core/config-loader.ts b/src/core/config-loader.ts index eb53e8362..d89503ad8 100644 --- a/src/core/config-loader.ts +++ b/src/core/config-loader.ts @@ -10,7 +10,7 @@ import * as fs from "fs"; import * as path from "path"; import { frameworkLogger } from "./framework-logger.js"; -import { resolveConfigPath } from "./config-paths.js"; +import { getConfigDir, resolveConfigPath } from "./config-paths.js"; export interface MultiAgentOrchestrationConfig { enabled: boolean; @@ -51,11 +51,11 @@ export class StringRayConfigLoader { private lastLoadTime: number = 0; constructor(configPath?: string) { - this.configPath = configPath || resolveConfigPath("config.json") || ".strray/config.json"; + this.configPath = configPath || resolveConfigPath("config.json") || path.join(getConfigDir(), "config.json"); } /** - * Load StringRay configuration from .opencode/strray/config.json + * Load StringRay configuration from the resolved config directory */ public loadConfig(): StringRayConfig { const now = Date.now(); diff --git a/src/core/features-config.ts b/src/core/features-config.ts index b7e7acd0d..86133ca70 100644 --- a/src/core/features-config.ts +++ b/src/core/features-config.ts @@ -10,7 +10,7 @@ import * as fs from "fs"; import * as path from "path"; -import { resolveConfigPath } from "./config-paths.js"; +import { getConfigDir, resolveConfigPath } from "./config-paths.js"; // ============================================================================ // Type Definitions @@ -285,7 +285,7 @@ export class FeaturesConfigLoader { private lastLoadTime: number = 0; constructor(featuresPath?: string) { - this.featuresPath = featuresPath || resolveConfigPath("features.json") || ".strray/features.json"; +this.featuresPath = featuresPath || resolveConfigPath("features.json") || path.join(getConfigDir(), "features.json"); } /** diff --git a/src/core/system-prompt-generator.ts b/src/core/system-prompt-generator.ts index 661994c8d..3a1dcdc47 100644 --- a/src/core/system-prompt-generator.ts +++ b/src/core/system-prompt-generator.ts @@ -135,7 +135,7 @@ function formatEssentialTerms(): string { parts.push(`\n**${termNum}. ${term.title}** ${zeroTolBadge}\n${term.description}`); } - parts.push("\nšŸ”— Key: .opencode/strray/ (codex, config, agents docs)"); + parts.push("\nšŸ”— Key: config dir (codex, config, agents docs) — resolved via config-paths"); return parts.join(""); } @@ -211,7 +211,7 @@ export async function generateLeanSystemPrompt( // 5. Essential links if space permits if (showEssentialLinks && safePrompt.length < 1500) { - safePrompt += "\nšŸ“– Documentation: .opencode/strray/ | AGENTS.md\n"; + safePrompt += "\nšŸ“– Documentation: config dir | AGENTS.md\n"; } // Final validation and fallback @@ -247,7 +247,7 @@ function generateCodexSummary(context: any, maxTokens: number): string { function generateMinimalFallbackPrompt(): string { return `StringRay Framework v${getFrameworkVersion()} Essential: Production-ready code, zero-tolerance errors, type safety -šŸ“–: .opencode/strray/ | AGENTS.md +šŸ“–: config dir (resolved via config-paths) | AGENTS.md `; } diff --git a/src/enforcement/loaders/codex-loader.ts b/src/enforcement/loaders/codex-loader.ts index dcfceeee7..0acd9b715 100644 --- a/src/enforcement/loaders/codex-loader.ts +++ b/src/enforcement/loaders/codex-loader.ts @@ -1,7 +1,7 @@ /** * Codex Rule Loader * - * Loads codex terms from .opencode/strray/codex.json and converts them + * Loads codex terms from the resolved codex path and converts them * to RuleDefinition objects for the rule enforcement system. * * Phase 4 refactoring: Extracted from RuleEnforcer.loadCodexRules() diff --git a/src/orchestrator/universal-librarian-consultation.ts b/src/orchestrator/universal-librarian-consultation.ts index fd1d0505c..338df6938 100644 --- a/src/orchestrator/universal-librarian-consultation.ts +++ b/src/orchestrator/universal-librarian-consultation.ts @@ -5,6 +5,7 @@ import { frameworkLogger } from "../core/framework-logger.js"; import { RuleEnforcer } from "../enforcement/rule-enforcer.js"; +import { resolveConfigPath } from "../core/config-paths.js"; export interface SystemAction { type: @@ -196,8 +197,9 @@ export class UniversalLibrarianConsultation { const updates: VersionUpdate[] = []; if (action.type === "rule-modification" || action.scope === "framework") { + const codexPath = resolveConfigPath("codex.json") || "codex.json"; updates.push({ - file: ".opencode/strray/codex.json", + file: codexPath, field: "version", oldVersion: "1.1.1", newVersion: "1.1.2", diff --git a/src/orchestrator/universal-registry-bridge.ts b/src/orchestrator/universal-registry-bridge.ts index f3bdcc49d..1a4a7510b 100644 --- a/src/orchestrator/universal-registry-bridge.ts +++ b/src/orchestrator/universal-registry-bridge.ts @@ -13,6 +13,7 @@ import { existsSync } from "fs"; import { resolve, dirname, join } from "path"; import { fileURLToPath } from "url"; import { frameworkLogger } from "../core/framework-logger.js"; +import { getConfigDir } from "../core/config-paths.js"; import type { AgentConfig } from "../agents/types.js"; const __filename = fileURLToPath(import.meta.url); @@ -48,7 +49,7 @@ export class UniversalRegistryBridge { constructor(options: BridgeOptions) { this.registries = options.registries || []; this.cacheDir = - options.cacheDir || join(__dirname, "../../.opencode/strray/registry-cache"); + options.cacheDir || join(getConfigDir(), "registry-cache"); this.autoRefresh = options.autoRefresh ?? true; } diff --git a/src/plugin/strray-codex-injection.ts b/src/plugin/strray-codex-injection.ts index cf20d67dc..75b2eac99 100644 --- a/src/plugin/strray-codex-injection.ts +++ b/src/plugin/strray-codex-injection.ts @@ -271,7 +271,7 @@ function getFrameworkIdentity(): string { šŸ“š Codex: 5 Essential Terms (99.6% Error Prevention Target) šŸŽÆ Goal: Progressive, production-ready development workflow -šŸ“– Documentation: .opencode/strray/ (codex, config, agents docs) +šŸ“– Documentation: config dir (codex, config, agents docs) — resolved via config-paths `; } @@ -421,7 +421,7 @@ function extractCodexMetadata(content: string): { } } - // Markdown format (AGENTS.md, .strray/agents_template.md) + // Markdown format (AGENTS.md, agents_template.md via config-paths resolver) const versionMatch = content.match(/\*\*Version\*\*:\s*(\d+\.\d+\.\d+)/); const version = versionMatch && versionMatch[1] ? versionMatch[1] : "1.6.0"; diff --git a/src/reporting/autonomous-report-generator.ts b/src/reporting/autonomous-report-generator.ts index 266fc2e0a..f6e435a7a 100644 --- a/src/reporting/autonomous-report-generator.ts +++ b/src/reporting/autonomous-report-generator.ts @@ -11,6 +11,7 @@ import { frameworkLogger, generateJobId } from "../core/framework-logger.js"; import { strRayConfigLoader } from "../core/config-loader.js"; +import { resolveConfigPath } from "../core/config-paths.js"; export interface DiagnosticReport { reportId: string; @@ -146,9 +147,10 @@ export class AutonomousReportGenerator { // Check if autonomous reporting is enabled in configuration const config = strRayConfigLoader.loadConfig(); if (!config.autonomous_reporting.enabled) { + const _cfgPath = resolveConfigPath("config.json") || "config.json"; throw new Error( "Autonomous reporting is disabled in configuration. " + - "Enable it in .opencode/strray/config.json by setting autonomous_reporting.enabled to true.", + "Enable it in " + _cfgPath + " by setting autonomous_reporting.enabled to true.", ); } diff --git a/src/scripts/profiling-demo.ts b/src/scripts/profiling-demo.ts index cd714ea3c..9e14e359f 100644 --- a/src/scripts/profiling-demo.ts +++ b/src/scripts/profiling-demo.ts @@ -1,5 +1,6 @@ import { advancedProfiler } from '../monitoring/advanced-profiler'; import { enterpriseMonitoringSystem } from '../monitoring/enterprise-monitoring-system'; +import { resolveProfilesDir } from '../core/config-paths.js'; // Simulate agent operations with profiling async function simulateAgentOperations() { @@ -83,7 +84,7 @@ async function simulateAgentOperations() { await new Promise(resolve => setTimeout(resolve, 65000)); // Wait for report generation console.log('\nšŸŽ‰ Profiling demo completed successfully!'); - console.log('šŸ“Š Check the .opencode/strray/profiles/ directory for performance reports'); + console.log('šŸ“Š Check the ' + resolveProfilesDir() + ' directory for performance reports'); // Cleanup enterpriseMonitoringSystem.stop(); From 16111ec54891f03b089cb87e76a2d2b7ab1aba84 Mon Sep 17 00:00:00 2001 From: htafolla Date: Mon, 30 Mar 2026 06:11:57 -0500 Subject: [PATCH 6/9] chore: remove all references to deleted .opencode/OpenCode.json The file was removed long ago but 29 scripts still referenced it: Deleted (orphaned test scripts built entirely around OpenCode.json): - scripts/hook-consolidation-tests.sh (193 lines) - scripts/config-integration-tests.sh (159 lines) - scripts/bash/validate-multi-agent-orchestration.backup.sh (195 lines) Fixed functional references: - model-validator.sh: CONFIG_FILE now points to opencode.json - config-loader.sh: CONFIG_FILE now points to opencode.json - setup.cjs: removed dead OpenCode.json fallback lookup - framework-compliance-audit.sh: removed from audit file list - extract-framework.sh: removed dead framework customization block (25 lines) Cleaned up stale comments across 15+ scripts: - Removed all "(.opencode/OpenCode.json deprecated)" parentheticals - Replaced with simple "use opencode.json at root" where needed --- .../bash/check-agent-orchestration-health.sh | 2 +- scripts/bash/ci-npm-orchestration-test.sh | 2 +- scripts/bash/extract-framework.sh | 25 +-- scripts/bash/framework-compliance-audit.sh | 1 - scripts/bash/strray-triage.sh | 2 +- scripts/bash/test-deployment.sh | 10 +- scripts/bash/test-multi-agent-trigger.sh | 2 +- scripts/bash/test-npm-install.sh | 2 +- ...lidate-multi-agent-orchestration.backup.sh | 195 ------------------ .../validate-multi-agent-orchestration.sh | 2 +- scripts/config-integration-tests.sh | 159 -------------- scripts/config-loader.sh | 2 +- scripts/hook-consolidation-tests.sh | 193 ----------------- scripts/mjs/test-consumer-readiness.mjs | 4 +- scripts/mjs/test-consumer-validation.mjs | 6 +- .../mjs/test-final-consumer-validation.mjs | 4 +- scripts/mjs/test-postinstall-files.mjs | 12 +- scripts/mjs/verify-plugin-paths.mjs | 8 +- scripts/model-validator.sh | 4 +- scripts/node/enforce-agents-md.mjs | 2 +- scripts/node/prepare-consumer.cjs | 2 +- scripts/node/setup-ci-paths.cjs | 2 +- scripts/node/setup-dev.cjs | 2 +- scripts/node/setup.cjs | 10 - scripts/node/test-plugin-comprehensive.js | 2 +- .../validate-oh-my-opencode-integration.cjs | 2 +- scripts/node/validate-postinstall-config.mjs | 5 +- scripts/simple-validation.sh | 1 - scripts/test/test-consumer-readiness.cjs | 2 +- 29 files changed, 40 insertions(+), 625 deletions(-) delete mode 100755 scripts/bash/validate-multi-agent-orchestration.backup.sh delete mode 100644 scripts/config-integration-tests.sh delete mode 100644 scripts/hook-consolidation-tests.sh diff --git a/scripts/bash/check-agent-orchestration-health.sh b/scripts/bash/check-agent-orchestration-health.sh index 8148d43ce..dbcc33221 100755 --- a/scripts/bash/check-agent-orchestration-health.sh +++ b/scripts/bash/check-agent-orchestration-health.sh @@ -57,7 +57,7 @@ echo "" echo "2ļøāƒ£ Testing Multi-Agent Orchestration Configuration..." echo "" -# Use opencode.json at root (.opencode/OpenCode.json deprecated) +# Use opencode.json at root if [ ! -f "opencode.json" ]; then echo "āŒ OpenCode configuration not found" exit 1 diff --git a/scripts/bash/ci-npm-orchestration-test.sh b/scripts/bash/ci-npm-orchestration-test.sh index d5c0138e1..8b62da0c4 100755 --- a/scripts/bash/ci-npm-orchestration-test.sh +++ b/scripts/bash/ci-npm-orchestration-test.sh @@ -205,7 +205,7 @@ fi # Additional manual checks log_info "Checking configuration files..." -# Check opencode.json at root (.opencode/OpenCode.json deprecated) +# Check opencode.json at root if [[ -f "opencode.json" ]]; then if grep -q "node_modules/strray-ai" opencode.json; then log_success "opencode.json has correct paths" diff --git a/scripts/bash/extract-framework.sh b/scripts/bash/extract-framework.sh index d05d8322e..4b6f5adc0 100755 --- a/scripts/bash/extract-framework.sh +++ b/scripts/bash/extract-framework.sh @@ -150,30 +150,7 @@ create_configuration() { rm -f "$target_dir/.opencode/enforcer-config.json.bak" fi - # Customize OpenCode.json for project type - if [ -f "$target_dir/.opencode/OpenCode.json" ]; then - case $PROJECT_FRAMEWORK in - "react") - sed -i.bak 's/"framework": "[^"]*"/"framework": "React + TypeScript"/g' "$target_dir/.opencode/OpenCode.json" - ;; - "vue") - sed -i.bak 's/"framework": "[^"]*"/"framework": "Vue.js"/g' "$target_dir/.opencode/OpenCode.json" - ;; - "angular") - sed -i.bak 's/"framework": "[^"]*"/"framework": "Angular"/g' "$target_dir/.opencode/OpenCode.json" - ;; - "python") - sed -i.bak 's/"framework": "[^"]*"/"framework": "Python"/g' "$target_dir/.opencode/OpenCode.json" - ;; - "rust") - sed -i.bak 's/"framework": "[^"]*"/"framework": "Rust"/g' "$target_dir/.opencode/OpenCode.json" - ;; - "go") - sed -i.bak 's/"framework": "[^"]*"/"framework": "Go"/g' "$target_dir/.opencode/OpenCode.json" - ;; - esac - rm -f "$target_dir/.opencode/OpenCode.json.bak" - fi + } # Setup automation hooks diff --git a/scripts/bash/framework-compliance-audit.sh b/scripts/bash/framework-compliance-audit.sh index b4f14112f..8d98d5bf4 100755 --- a/scripts/bash/framework-compliance-audit.sh +++ b/scripts/bash/framework-compliance-audit.sh @@ -12,7 +12,6 @@ REQUIRED_FILES=( "package.json" "tsconfig.json" "opencode.json" - ".opencode/OpenCode.json" "dist/plugin/strray-codex-injection.js" ) diff --git a/scripts/bash/strray-triage.sh b/scripts/bash/strray-triage.sh index ef41923ab..989d30291 100755 --- a/scripts/bash/strray-triage.sh +++ b/scripts/bash/strray-triage.sh @@ -233,7 +233,7 @@ check_configuration() { log_warning "Global OpenCode config missing: ~/.config/opencode/opencode.json" fi - # Check project config - .opencode/OpenCode.json is NOT required (causes boot issues) + # Check project config in opencode.json # The framework uses .opencode/strray/config.json instead if [[ -f "$PROJECT_ROOT/.opencode/strray/config.json" ]]; then log_success "Project StrRay config exists: .opencode/strray/config.json" diff --git a/scripts/bash/test-deployment.sh b/scripts/bash/test-deployment.sh index fe4044200..304ec6d43 100755 --- a/scripts/bash/test-deployment.sh +++ b/scripts/bash/test-deployment.sh @@ -161,7 +161,7 @@ PACK_FILE=$(ls *.tgz | head -1) cd test-config npm install "../$PACK_FILE" > /dev/null 2>&1 -# Check if config was created - use opencode.json at root (.opencode/OpenCode.json deprecated) +# Check if config was created - use opencode.json at root if [ -f "opencode.json" ]; then echo "āœ… opencode.json created" echo "Configuration content (first 10 lines):" @@ -195,7 +195,7 @@ PACK_FILE=$(ls *.tgz | head -1) cd test-registration npm install "../$PACK_FILE" > /dev/null 2>&1 -# Use opencode.json at root (.opencode/OpenCode.json deprecated) +# Use opencode.json at root if grep -q "strray" opencode.json; then echo "āœ… Plugin registered in configuration" else @@ -245,7 +245,7 @@ try { echo "" echo "3.2 Agent Configuration Validation" -echo "Testing agent configuration in OpenCode.json" +echo "Testing agent configuration in opencode.json" mkdir -p test-agents cd test-agents @@ -267,10 +267,10 @@ npm install "../$PACK_FILE" > /dev/null 2>&1 AGENTS=("orchestrator" "enforcer" "architect" "testing-lead" "bug-triage-specialist" "code-reviewer" "security-auditor" "refactorer" "researcher" "strategist") MISSING_AGENTS=() -# Check agents in the main project opencode.json at root (.opencode/OpenCode.json deprecated) +# Check agents in the main project opencode.json at root OPENCODE_PATH="opencode.json" -# Agents that are actually configured in OpenCode.json +# Agents configured in opencode.json CONFIGURED_AGENTS=("orchestrator" "enforcer" "architect") for agent in "${AGENTS[@]}"; do diff --git a/scripts/bash/test-multi-agent-trigger.sh b/scripts/bash/test-multi-agent-trigger.sh index 501925e89..698889327 100755 --- a/scripts/bash/test-multi-agent-trigger.sh +++ b/scripts/bash/test-multi-agent-trigger.sh @@ -28,7 +28,7 @@ test_config() { echo "" log "Testing multi-agent orchestration configuration..." - # Use opencode.json at root (.opencode/OpenCode.json deprecated) + # Use opencode.json at root if grep -q '"enabled": true' opencode.json && grep -q '"multi_agent_orchestration"' opencode.json; then success "Multi-agent orchestration is enabled in configuration" else diff --git a/scripts/bash/test-npm-install.sh b/scripts/bash/test-npm-install.sh index 0ada117d9..9f9d2804d 100755 --- a/scripts/bash/test-npm-install.sh +++ b/scripts/bash/test-npm-install.sh @@ -73,7 +73,7 @@ if ! run_with_timeout 120 npx $PACKAGE_NAME install; then exit 1 fi -# Verify files were created - .opencode/OpenCode.json is deprecated +# Verify files were created expected_files=(".mcp.json" "opencode.json") for file in "${expected_files[@]}"; do if [ ! -f "$file" ]; then diff --git a/scripts/bash/validate-multi-agent-orchestration.backup.sh b/scripts/bash/validate-multi-agent-orchestration.backup.sh deleted file mode 100755 index 061873c77..000000000 --- a/scripts/bash/validate-multi-agent-orchestration.backup.sh +++ /dev/null @@ -1,195 +0,0 @@ -#!/bin/bash - -# Multi-Agent Orchestration Validator -echo "šŸ” Multi-Agent Orchestration System Validator" -echo "==============================================" - -# Test 1: Agent Configuration Validation -echo "" -echo "1ļøāƒ£ Testing Agent Configurations..." -# Check all agents with complete configurations -AGENTS=("enforcer" "architect" "testing-lead" "bug-triage-specialist" "code-reviewer" "security-auditor" "refactorer" "researcher" "code-analyzer" "strategist" "multimodal-looker" "frontend-ui-ux-engineer" "tech-writer") -MISSING_AGENTS=() -INVALID_AGENTS=() - -for agent in "${AGENTS[@]}"; do - # Detect if we're in .opencode directory or parent directory - if [ -f "agents/${agent}.md" ]; then - AGENT_MD_PATH="agents/${agent}.md" - elif [ -f ".opencode/agents/${agent}.md" ]; then - AGENT_MD_PATH=".opencode/agents/${agent}.md" - else - MISSING_AGENTS+=("$agent") - continue - fi - - if [ -f "agents/${agent}.yml" ]; then - AGENT_YML_PATH="agents/${agent}.yml" - elif [ -f ".opencode/agents/${agent}.yml" ]; then - AGENT_YML_PATH=".opencode/agents/${agent}.yml" - else - MISSING_AGENTS+=("${agent}.yml") - continue - fi - - # Check if YAML has required fields - if [ -f "$AGENT_YML_PATH" ]; then - if ! grep -q "capabilities:" "$AGENT_YML_PATH"; then - INVALID_AGENTS+=("$agent.yml (missing capabilities)") - fi - if ! grep -q "model:" "$AGENT_YML_PATH"; then - INVALID_AGENTS+=("$agent.yml (missing model)") - fi - fi -done - -if [ ${#MISSING_AGENTS[@]} -eq 0 ]; then - echo "āœ… All agent configuration files present" -else - echo "āŒ Missing agent configurations: ${MISSING_AGENTS[*]}" -fi - -if [ ${#INVALID_AGENTS[@]} -eq 0 ]; then - echo "āœ… All agent configurations are valid" -else - echo "āŒ Invalid agent configurations: ${INVALID_AGENTS[*]}" -fi - -# Test 2: Multi-Agent Configuration -echo "" -echo "2ļøāƒ£ Testing Multi-Agent Orchestration Configuration..." - -# Detect if we're in .opencode directory or parent directory -if [ -f "OpenCode.json" ]; then - CONFIG_FILE="OpenCode.json" -elif [ -f ".opencode/OpenCode.json" ]; then - CONFIG_FILE=".opencode/OpenCode.json" -else - echo "āŒ OpenCode.json not found" - return 1 -fi - -if grep -q '"enabled": true' "$CONFIG_FILE" && grep -q '"multi_agent_orchestration"' "$CONFIG_FILE"; then - echo "āœ… Multi-agent orchestration is enabled" -else - echo "āŒ Multi-agent orchestration is not enabled" -fi - -if grep -q '"max_concurrent_agents": 5' "$CONFIG_FILE"; then - echo "āœ… Max concurrent agents set correctly (5)" -else - echo "āŒ Max concurrent agents not set correctly" -fi - -# Test 3: Agent Delegation System -echo "" -echo "3ļøāƒ£ Testing Agent Delegation System..." -node -e " -(async () => { - try { - const { createAgentDelegator } = await import('./dist/delegation/agent-delegator.js'); - const { StrRayStateManager } = await import('./dist/state/state-manager.js'); - - const stateManager = new StrRayStateManager(); - const delegator = createAgentDelegator(stateManager); - - // Test delegation analysis - const result = await delegator.analyzeDelegation({ - operation: 'test-strategy', - description: 'Test delegation analysis', - context: { test: true }, - priority: 'medium' - }); - - console.log('āœ… Agent delegation system operational'); - console.log(' Strategy:', result.strategy); - console.log(' Agents selected:', result.agents.length); - - // Test agent capabilities - const capabilities = delegator.getDelegationMetrics(); - console.log('āœ… Agent capabilities loaded'); - console.log(' Total delegations tracked:', capabilities.totalDelegations); - - } catch (error) { - console.log('āŒ Agent delegation system error:', error.message); - } -})(); -" 2>/dev/null - -# Test 4: Agent Event Handling -echo "" -echo "4ļøāƒ£ Testing Agent Event Handling..." -node -e " -(async () => { - try { - const { createAgentDelegator } = await import('./dist/delegation/agent-delegator.js'); - const { StrRayStateManager } = await import('./dist/state/state-manager.js'); - - const stateManager = new StrRayStateManager(); - const delegator = createAgentDelegator(stateManager); - - // Test file creation handling - await delegator.handleFileCreation('test-file.ts', 'console.log(\"test\");'); - - console.log('āœ… File creation event handling operational'); - console.log(' Test architect should have been consulted for .ts file'); - - } catch (error) { - console.log('āŒ File creation event handling error:', error.message); - } -})(); -" 2>/dev/null - -# Test 5: Memory Integration -echo "" -echo "5ļøāƒ£ Testing Memory System Integration..." -node -e " -(async () => { - try { - const { memoryMonitor } = await import('./dist/monitoring/memory-monitor.js'); - - const stats = memoryMonitor.getCurrentStats(); - const summary = memoryMonitor.getSummary(); - - console.log('āœ… Memory monitoring integrated'); - console.log(' Current heap usage:', stats.heapUsed.toFixed(2), 'MB'); - console.log(' Memory trend:', summary.trend); - - } catch (error) { - console.log('āŒ Memory system integration error:', error.message); - } -})(); -" 2>/dev/null - -# Test 6: Framework Boot Integration -echo "" -echo "6ļøāƒ£ Testing Framework Boot Integration..." -if [ -f "logs/framework/activity.log" ]; then - if grep -q "agent-delegator" logs/framework/activity.log; then - echo "āœ… Agent delegator integrated with framework boot" - else - echo "āŒ Agent delegator not found in framework logs" - fi - - if grep -q "multi-agent" logs/framework/activity.log; then - echo "āœ… Multi-agent orchestration active in framework" - else - echo "āŒ Multi-agent orchestration not active" - fi -else - echo "āŒ Framework activity log not found" -fi - -echo "" -echo "šŸŽÆ Multi-Agent Orchestration Validation Complete" -echo "==================================================" -echo "" -echo "Summary:" -echo "- Agent configurations: $([ ${#MISSING_AGENTS[@]} -eq 0 ] && echo "āœ… Valid" || echo "āŒ Issues found")" -echo "- Multi-agent config: $(grep -q '"enabled": true' .opencode/OpenCode.json && echo "āœ… Enabled" || echo "āŒ Disabled")" -echo "- Delegation system: $(node -e "(async()=>{try{const{d}=await import('./dist/delegation/agent-delegator.js');const s=new(await import('./dist/state/state-manager.js')).StrRayStateManager();const d2=d.createAgentDelegator(s);await d2.analyzeDelegation({operation:'test',description:'test',context:{}});console.log('āœ… Working')}catch(e){console.log('āŒ Error')}})();" 2>/dev/null)" -echo "" -echo "Next steps:" -echo "- Run 'npm run framework:init' to test full system integration" -echo "- Monitor .opencode/logs/ for agent delegation activity" -echo "- Use 'npm run memory:dashboard' to verify memory monitoring" \ No newline at end of file diff --git a/scripts/bash/validate-multi-agent-orchestration.sh b/scripts/bash/validate-multi-agent-orchestration.sh index 384f906c4..3d6df934c 100755 --- a/scripts/bash/validate-multi-agent-orchestration.sh +++ b/scripts/bash/validate-multi-agent-orchestration.sh @@ -52,7 +52,7 @@ echo "" # Test 2: Multi-Agent Orchestration Configuration echo "2ļøāƒ£ Testing Multi-Agent Orchestration Configuration..." -# Use opencode.json at root (.opencode/OpenCode.json deprecated) +# Use opencode.json at root if [ ! -f "opencode.json" ]; then echo "āŒ OpenCode configuration not found" exit 1 diff --git a/scripts/config-integration-tests.sh b/scripts/config-integration-tests.sh deleted file mode 100644 index 225424fb0..000000000 --- a/scripts/config-integration-tests.sh +++ /dev/null @@ -1,159 +0,0 @@ -#!/bin/bash -# StrRay Framework - Configuration Integration Tests -# Tests config system functionality, validation, and integration - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# Test counters -TOTAL_TESTS=0 -PASSED_TESTS=0 -FAILED_TESTS=0 - -log_test() { - local test_name="$1" - local status="$2" - local message="$3" - - echo -e "${status} ${test_name}: ${message}${NC}" -} - -run_test() { - local test_name="$1" - local command="$2" - - ((TOTAL_TESTS++)) - echo -n "Running ${test_name}... " - - if eval "$command" >/dev/null 2>&1; then - log_test "$test_name" "${GREEN}āœ“ PASS" "" - ((PASSED_TESTS++)) - else - log_test "$test_name" "${RED}āœ— FAIL" "" - ((FAILED_TESTS++)) - fi -} - -# Configuration file validation tests -echo "šŸ”§ Running Configuration Integration Tests" -echo "===========================================" - -# Test 1: Configuration file existence -run_test "Config file exists" "test -f \"${PROJECT_ROOT}/.opencode/OpenCode.json\"" - -# Test 2: Configuration JSON validity -run_test "Config JSON syntax" "python3 -c \"import json; json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json'))\"" - -# Test 3: Required configuration properties -run_test "Required properties present" "python3 -c \" -import json -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) -required = ['strray_agents', 'dynamic_models', 'ai_logging', 'python_backend'] -missing = [k for k in required if k not in config] -if not missing: - exit(0) -else: - print(f'Missing: {missing}') - exit(1) -\"" - -# Test 4: Agent configuration structure -run_test "Agent config structure" "python3 -c \" -import json -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) -agents = config.get('strray_agents', {}) -if 'enabled' in agents and 'disabled' in agents: - if isinstance(agents['enabled'], list) and isinstance(agents['disabled'], list): - exit(0) -exit(1) -\"" - -# Test 5: Model configuration validation -run_test "Model config validation" "python3 -c \" -import json -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) -models = config.get('dynamic_models', {}) -if 'enabled' in models and 'fallback_models' in models: - if isinstance(models['fallback_models'], list): - exit(0) -exit(1) -\"" - -# Test 6: Python backend configuration -run_test "Python backend config" "python3 -c \" -import json -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) -backend = config.get('python_backend', {}) -if 'enabled' in backend and 'path' in backend and 'entry_point' in backend: - exit(0) -exit(1) -\"" - -# Test 7: MCP server configurations -run_test "MCP server configs" "python3 -c \" -import json -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) -mcps = config.get('mcps', {}) -if isinstance(mcps, dict) and len(mcps) > 0: - # Check that each MCP has server and config - for name, mcp_config in mcps.items(): - if not ('server' in mcp_config and 'config' in mcp_config): - exit(1) - exit(0) -exit(1) -\"" - -# Test 8: Schema compliance check -run_test "Schema compliance" "python3 -c \" -import json -import requests -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) -schema_url = config.get('\$schema') -if schema_url: - try: - response = requests.get(schema_url, timeout=10) - if response.status_code == 200: - exit(0) - except: - pass -exit(1) -\"" - -# Test 9: Agent count validation -run_test "Agent count validation" "python3 -c \" -import json -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) -agents = config.get('strray_agents', {}).get('enabled', []) -expected_agents = ['enforcer', 'architect', 'orchestrator', 'bug-triage-specialist', 'code-reviewer', 'security-auditor', 'refactorer', 'testing-lead'] -if set(agents) == set(expected_agents): - exit(0) -exit(1) -\"" - -# Test 10: File permission checks -run_test "Config file permissions" "test -r \"${PROJECT_ROOT}/.opencode/OpenCode.json\" && test -w \"${PROJECT_ROOT}/.opencode/OpenCode.json\"" - -# Test Results Summary -echo "" -echo "===========================================" -echo "Configuration Integration Test Results" -echo "===========================================" -echo "Total Tests: $TOTAL_TESTS" -echo -e "Passed: ${GREEN}$PASSED_TESTS${NC}" -echo -e "Failed: ${RED}$FAILED_TESTS${NC}" - -if [ "$FAILED_TESTS" -eq 0 ]; then - echo -e "${GREEN}āœ“ All configuration integration tests passed!${NC}" - exit 0 -else - echo -e "${RED}āœ— $FAILED_TESTS configuration tests failed${NC}" - exit 1 -fi \ No newline at end of file diff --git a/scripts/config-loader.sh b/scripts/config-loader.sh index d02a8322d..66fea751c 100644 --- a/scripts/config-loader.sh +++ b/scripts/config-loader.sh @@ -13,7 +13,7 @@ GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color -CONFIG_FILE="${PROJECT_ROOT}/.opencode/OpenCode.json" +CONFIG_FILE="${PROJECT_ROOT}/opencode.json" echo "šŸ”§ StrRay Configuration Loader" echo "==============================" diff --git a/scripts/hook-consolidation-tests.sh b/scripts/hook-consolidation-tests.sh deleted file mode 100644 index 0ce48b271..000000000 --- a/scripts/hook-consolidation-tests.sh +++ /dev/null @@ -1,193 +0,0 @@ -#!/bin/bash -# StrRay Framework - Hook Consolidation Tests -# Tests hook system consolidation and backward compatibility - -set -e - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' # No Color - -# Test counters -TOTAL_TESTS=0 -PASSED_TESTS=0 -FAILED_TESTS=0 - -log_test() { - local test_name="$1" - local status="$2" - local message="$3" - - echo -e "${status} ${test_name}: ${message}${NC}" -} - -run_test() { - local test_name="$1" - local command="$2" - - ((TOTAL_TESTS++)) - echo -n "Running ${test_name}... " - - if eval "$command" >/dev/null 2>&1; then - log_test "$test_name" "${GREEN}āœ“ PASS" "" - ((PASSED_TESTS++)) - else - log_test "$test_name" "${RED}āœ— FAIL" "" - ((FAILED_TESTS++)) - fi -} - -# Hook consolidation tests -echo "šŸ”— Running Hook Consolidation Tests" -echo "====================================" - -# Test 1: Hook directory structure -run_test "Hook directory exists" "test -d \"${PROJECT_ROOT}/.opencode/hooks\"" - -# Test 2: Hook dispatcher script exists -run_test "Hook dispatcher exists" "test -f \"${PROJECT_ROOT}/.opencode/scripts/hook-dispatcher.sh\"" - -# Test 3: Hook configuration in OpenCode.json -run_test "Hook config in OpenCode" "python3 -c \" -import json -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) -disabled = config.get('disabled_hooks', []) -if isinstance(disabled, list): - exit(0) -exit(1) -\"" - -# Test 4: Legacy hook type mapping -run_test "Legacy hook mapping" "python3 -c \" -# Test that old hook types map to new consolidated hooks -legacy_types = ['pre-commit', 'post-commit', 'pre-build', 'post-build', 'pre-deploy', 'post-deploy'] -consolidated_types = ['commit', 'build', 'deploy'] - -# Check if legacy types can be mapped -for legacy in legacy_types: - if any(consolidated in legacy for consolidated in consolidated_types): - continue - else: - exit(1) -exit(0) -\"" - -# Test 5: Hook execution dispatcher -run_test "Hook dispatcher executable" "test -x \"${PROJECT_ROOT}/.opencode/scripts/hook-dispatcher.sh\"" - -# Test 6: Hook consolidation configuration -run_test "Hook consolidation config" "python3 -c \" -import json -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) - -# Check for consolidated hook settings -experimental = config.get('experimental', {}) -if 'consolidated_hooks' in experimental: - exit(0) - -# Check for legacy hook settings that should be migrated -legacy_hooks = ['pre_commit_hooks', 'post_commit_hooks', 'build_hooks', 'deploy_hooks'] -for hook_type in legacy_hooks: - if hook_type in config: - exit(1) # Should be migrated - -exit(0) -\"" - -# Test 7: Backward compatibility preservation -run_test "Backward compatibility" "python3 -c \" -# Test that old hook configurations still work -import json -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) - -# Check for any legacy hook configurations -legacy_indicators = [ - 'pre_commit_enabled', 'post_commit_enabled', - 'build_hooks_enabled', 'deploy_hooks_enabled' -] - -for indicator in legacy_indicators: - if indicator in config: - # If legacy config exists, it should still be supported - exit(0) - -# No legacy configs found - that's also fine -exit(0) -\"" - -# Test 8: Hook performance impact -run_test "Hook performance impact" "python3 -c \" -# Test that hook consolidation doesn't significantly impact performance -import time -import json - -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) -disabled_hooks = config.get('disabled_hooks', []) - -# Performance should not be significantly impacted by disabled hooks -if len(disabled_hooks) <= 10: # Reasonable limit - exit(0) -exit(1) -\"" - -# Test 9: Hook consolidation integrity -run_test "Hook consolidation integrity" "python3 -c \" -import json -config = json.load(open('${PROJECT_ROOT}/.opencode/OpenCode.json')) - -# Check that hook consolidation didn't break existing functionality -required_sections = ['disabled_hooks', 'disabled_commands', 'disabled_skills'] -for section in required_sections: - if section not in config: - exit(1) - -# Check that disabled items are arrays -for section in required_sections: - items = config.get(section, []) - if not isinstance(items, list): - exit(1) - -exit(0) -\"" - -# Test 10: Hook system initialization -run_test "Hook system initialization" "python3 -c \" -# Test that the hook system can be initialized without errors -import sys -import os -sys.path.insert(0, '${PROJECT_ROOT}/.opencode/src') - -try: - # Try to import and initialize hook-related components - from strray.core.config import ConfigManager - config_manager = ConfigManager() - config = config_manager.get_config() - - # Check that hook-related configurations are accessible - if 'disabled_hooks' in config: - exit(0) -except Exception as e: - exit(1) -\"" - -# Test Results Summary -echo "" -echo "========================================" -echo "Hook Consolidation Test Results" -echo "========================================" -echo "Total Tests: $TOTAL_TESTS" -echo -e "Passed: ${GREEN}$PASSED_TESTS${NC}" -echo -e "Failed: ${RED}$FAILED_TESTS${NC}" - -if [ "$FAILED_TESTS" -eq 0 ]; then - echo -e "${GREEN}āœ“ All hook consolidation tests passed!${NC}" - exit 0 -else - echo -e "${RED}āœ— $FAILED_TESTS hook consolidation tests failed${NC}" - exit 1 -fi \ No newline at end of file diff --git a/scripts/mjs/test-consumer-readiness.mjs b/scripts/mjs/test-consumer-readiness.mjs index c8e4ed75c..74e571c94 100644 --- a/scripts/mjs/test-consumer-readiness.mjs +++ b/scripts/mjs/test-consumer-readiness.mjs @@ -109,12 +109,12 @@ class ConsumerReadinessCheck { checkPluginRegistration() { try { - // Use opencode.json at project root (.opencode/OpenCode.json is deprecated) + // Use opencode.json at project root let config = null; if (fs.existsSync("opencode.json")) { config = JSON.parse(fs.readFileSync("opencode.json", "utf8")); } - // NOTE: .opencode/OpenCode.json is deprecated - removed fallback + // Config is in opencode.json at project root if (!config) { const isCIEnvironment = process.env.CI || process.env.GITHUB_ACTIONS; diff --git a/scripts/mjs/test-consumer-validation.mjs b/scripts/mjs/test-consumer-validation.mjs index 827ab4584..a07c063e9 100644 --- a/scripts/mjs/test-consumer-validation.mjs +++ b/scripts/mjs/test-consumer-validation.mjs @@ -303,7 +303,7 @@ class ConsumerValidator { // Refactored architecture: MCP config is in opencode.json under 'mcp' key const requiredFiles = [ { path: "opencode.json", description: "OpenCode base configuration" }, - // .opencode/OpenCode.json is deprecated - removed + // OpenCode.json removed { path: "node_modules/strray-ai/dist/plugin/strray-codex-injection.js", description: "Main plugin file", @@ -419,7 +419,7 @@ class ConsumerValidator { const checks = [ // File existence checks () => fs.existsSync("opencode.json"), - // .opencode/OpenCode.json is deprecated - removed + // OpenCode.json removed () => fs.existsSync( "node_modules/strray-ai/dist/plugin/strray-codex-injection.js", @@ -435,7 +435,7 @@ class ConsumerValidator { return false; } }, - // .opencode/OpenCode.json deprecated - removed check + // Config is in opencode.json at project root // MCP server count check (in opencode.json under 'mcp' key) // Only external/global MCPs should be listed here - StringRay internal MCPs are NOT in opencode.json diff --git a/scripts/mjs/test-final-consumer-validation.mjs b/scripts/mjs/test-final-consumer-validation.mjs index 67acb77c3..4b43bbeb5 100644 --- a/scripts/mjs/test-final-consumer-validation.mjs +++ b/scripts/mjs/test-final-consumer-validation.mjs @@ -58,7 +58,7 @@ class FinalConsumerValidation { // Refactored: MCP config is in opencode.json, not .mcp.json const requiredFiles = [ { path: "opencode.json", description: "OpenCode base configuration (includes MCP)" }, - // .opencode/OpenCode.json is deprecated - removed + // OpenCode.json removed ]; // Add package files for validation @@ -167,7 +167,7 @@ class FinalConsumerValidation { console.log("\nšŸ”Œ PLUGIN INTEGRATION VALIDATION"); try { - // Use opencode.json at root (.opencode/OpenCode.json deprecated) + // Use opencode.json at root const configPath = path.resolve(this.consumerRoot, "opencode.json"); const ohMyOpencodeConfig = JSON.parse( fs.readFileSync(configPath, "utf8"), diff --git a/scripts/mjs/test-postinstall-files.mjs b/scripts/mjs/test-postinstall-files.mjs index f9e8e4d67..6caeaf9a6 100644 --- a/scripts/mjs/test-postinstall-files.mjs +++ b/scripts/mjs/test-postinstall-files.mjs @@ -157,17 +157,15 @@ class PostinstallFileValidator { console.log("\nšŸ”Œ Validating OpenCode Configuration..."); try { - // NOTE: .opencode/OpenCode.json is NOT required and can cause OpenCode boot issues + // NOTE: .opencode/OpenCode.json was removed // The framework uses the config-paths resolver (checks .strray/, .opencode/strray/, STRRAY_CONFIG_DIR) for configuration instead const ohMyOpencodePath = path.join( process.cwd(), ".opencode", - "OpenCode.json", ); if (!fs.existsSync(ohMyOpencodePath)) { - // OpenCode.json is optional - don't fail the test - console.log(" ā„¹ļø .opencode/OpenCode.json not found (optional - using strray/config.json instead)"); + console.log(" ā„¹ļø OpenCode.json removed — using opencode.json at project root"); this.results.passed.push({ test: "OpenCode Config File", details: "Optional - using config-paths resolver for config.json" @@ -209,14 +207,14 @@ class PostinstallFileValidator { const isCIEnvironment = process.env.CI || process.env.GITHUB_ACTIONS || !this.isConsumerEnvironment; if (hasStringRayPlugin) { - console.log(` āœ… StringRay plugin registered in OpenCode.json (${this.environment})`); + console.log(` āœ… StringRay plugin registered in opencode.json (${this.environment})`); this.results.passed.push("OpenCode Plugin Registration"); } else if (isCIEnvironment) { // Don't fail CI for missing plugin registration - console.log(` ā„¹ļø StringRay plugin not found in OpenCode.json (${this.environment}) - Optional in CI`); + console.log(` ā„¹ļø StringRay plugin not found in opencode.json (${this.environment}) - Optional in CI`); this.results.passed.push("OpenCode Plugin Registration (Optional in CI)"); } else { - console.log(` āŒ StringRay plugin not found in OpenCode.json (${this.environment})`); + console.log(` āŒ StringRay plugin not found in opencode.json (${this.environment})`); this.results.failed.push({ test: "OpenCode Plugin Registration", error: "Plugin not registered", diff --git a/scripts/mjs/verify-plugin-paths.mjs b/scripts/mjs/verify-plugin-paths.mjs index 216bd360b..f9b993c39 100755 --- a/scripts/mjs/verify-plugin-paths.mjs +++ b/scripts/mjs/verify-plugin-paths.mjs @@ -50,7 +50,7 @@ class PathVerifier { const cwd = process.cwd(); console.log(`Working directory: ${cwd}\n`); - // Check 1: Verify OpenCode.json exists and has correct paths + // Check 1: Verify opencode.json exists and has correct paths await this.verifyOhMyOpencodeConfig(); // Check 2: Verify opencode.json has correct paths @@ -79,12 +79,12 @@ class PathVerifier { } async verifyOhMyOpencodeConfig() { - this.check('OpenCode.json paths'); + this.check('opencode.json paths'); // Detect development mode const isDevMode = fs.existsSync('src/plugin/strray-codex-injection.ts'); - // Use opencode.json at root (.opencode/OpenCode.json is deprecated) + // Use opencode.json at root const configPath = 'opencode.json'; if (!fs.existsSync(configPath)) { this.error(`${configPath} not found`); @@ -238,7 +238,7 @@ class PathVerifier { async verifyNoOldPaths() { this.check('No old development paths remaining'); - // Only check opencode.json at root (.opencode/OpenCode.json deprecated) + // Only check opencode.json at root const filesToCheck = [ 'opencode.json', ]; diff --git a/scripts/model-validator.sh b/scripts/model-validator.sh index 1ec8a195b..5bf5cbf74 100644 --- a/scripts/model-validator.sh +++ b/scripts/model-validator.sh @@ -14,7 +14,7 @@ YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color -CONFIG_FILE="${PROJECT_ROOT}/.opencode/OpenCode.json" +CONFIG_FILE="${PROJECT_ROOT}/opencode.json" echo "šŸ¤– StrRay Model Validator" echo "========================" @@ -158,7 +158,7 @@ sys.path.append('${PROJECT_ROOT}/.opencode/src') from strray.model_router import ModelRouter try: - router = ModelRouter('${PROJECT_ROOT}/.opencode/OpenCode.json') + router = ModelRouter('${PROJECT_ROOT}/opencode.json') test_model = router.get_validated_model('architect') print(f'āœ“ ModelRouter functional - returned: {test_model}') except Exception as e: diff --git a/scripts/node/enforce-agents-md.mjs b/scripts/node/enforce-agents-md.mjs index 9d695801c..b4b9c3955 100644 --- a/scripts/node/enforce-agents-md.mjs +++ b/scripts/node/enforce-agents-md.mjs @@ -348,7 +348,7 @@ class AgentsMdEnforcer { */ async discoverAgents() { const agents = []; - // Use opencode.json at project root (not .opencode/OpenCode.json - deprecated) + // Use opencode.json at project root const configPath = path.join(this.projectRoot, 'opencode.json'); if (fs.existsSync(configPath)) { diff --git a/scripts/node/prepare-consumer.cjs b/scripts/node/prepare-consumer.cjs index fc75b7011..8a803fd45 100755 --- a/scripts/node/prepare-consumer.cjs +++ b/scripts/node/prepare-consumer.cjs @@ -122,7 +122,7 @@ function updatePathsInFile(filePath) { } // Files to update for consumer preparation -// Note: .opencode/OpenCode.json was removed - plugin loads from opencode.json in root +// Config loaded from opencode.json in project root const filesToUpdate = [ "opencode.json" ]; diff --git a/scripts/node/setup-ci-paths.cjs b/scripts/node/setup-ci-paths.cjs index 7f195bcba..2701e82d3 100755 --- a/scripts/node/setup-ci-paths.cjs +++ b/scripts/node/setup-ci-paths.cjs @@ -14,7 +14,7 @@ const path = require("path"); console.log('šŸ”§ CI Path Setup: Converting to development paths...'); // Files that need path conversion for CI -// Note: .opencode/OpenCode.json was removed - plugin loads from opencode.json in root +// Config loaded from opencode.json in project root const filesToUpdate = [ '.mcp.json' ]; diff --git a/scripts/node/setup-dev.cjs b/scripts/node/setup-dev.cjs index b38f7e080..f2a7c2a72 100755 --- a/scripts/node/setup-dev.cjs +++ b/scripts/node/setup-dev.cjs @@ -63,7 +63,7 @@ function updatePathsInFile(filePath) { } // Files to update for development -// Note: .opencode/OpenCode.json was removed - plugin loads from opencode.json in root +// Config loaded from opencode.json in project root const filesToUpdate = [ ".mcp.json", "opencode.json" diff --git a/scripts/node/setup.cjs b/scripts/node/setup.cjs index 5125bbf70..858301b86 100644 --- a/scripts/node/setup.cjs +++ b/scripts/node/setup.cjs @@ -12,16 +12,6 @@ const path = require("path"); const os = require("os"); function getOhMyOpenCodeConfigPath() { - // Try to find OpenCode config in current project - const projectConfig = path.join( - process.cwd(), - ".opencode", - "OpenCode.json", - ); - if (fs.existsSync(projectConfig)) { - return projectConfig; - } - // Try to find global OpenCode config const homeDir = os.homedir(); const globalConfig = path.join( diff --git a/scripts/node/test-plugin-comprehensive.js b/scripts/node/test-plugin-comprehensive.js index 6c514041a..773a18411 100644 --- a/scripts/node/test-plugin-comprehensive.js +++ b/scripts/node/test-plugin-comprehensive.js @@ -95,7 +95,7 @@ async function runComprehensiveTests() { // 2. Test configuration files console.log('\nāš™ļø 2. Testing configuration files...'); - // Use opencode.json at root (.opencode/OpenCode.json is deprecated) + // Use opencode.json at root const configPaths = [ './opencode.json' ]; diff --git a/scripts/node/validate-oh-my-opencode-integration.cjs b/scripts/node/validate-oh-my-opencode-integration.cjs index f98bdc637..e3fdfcff1 100644 --- a/scripts/node/validate-oh-my-opencode-integration.cjs +++ b/scripts/node/validate-oh-my-opencode-integration.cjs @@ -49,7 +49,7 @@ class OhMyOpenCodeIntegrationValidator { console.log("\nšŸ”Œ Testing Plugin Registration..."); try { - // Use opencode.json at root (.opencode/OpenCode.json is deprecated) + // Use opencode.json at root const configPath = path.join(this.packageRoot, "opencode.json"); const ohMyOpencodeConfig = JSON.parse( fs.readFileSync(configPath, "utf8"), diff --git a/scripts/node/validate-postinstall-config.mjs b/scripts/node/validate-postinstall-config.mjs index 4e55c650a..46c82650e 100644 --- a/scripts/node/validate-postinstall-config.mjs +++ b/scripts/node/validate-postinstall-config.mjs @@ -49,7 +49,6 @@ class PostinstallConfigValidator { // Optional files (not required for CI/test environments) const optionalFiles = [ { - path: ".opencode/OpenCode.json", description: "OpenCode main config (optional - can cause boot issues)", }, { path: ".mcp.json", description: "MCP server configuration (lazy loaded)" }, @@ -99,9 +98,9 @@ class PostinstallConfigValidator { async validateOpencodeConfig() { console.log("\nšŸ› ļø Testing OpenCode Configuration..."); - // .opencode/OpenCode.json is NOT required - skip this check entirely + // OpenCode.json was removed - config is in opencode.json at project root // Framework uses opencode.json (root) instead - console.log(" ā„¹ļø Skipping .opencode/OpenCode.json check (not required - uses opencode.json at root)"); + console.log(" ā„¹ļø OpenCode.json removed — config is in opencode.json at project root"); this.results.passed.push({ test: "OpenCode Configuration", details: "Skipped - uses opencode.json at root" diff --git a/scripts/simple-validation.sh b/scripts/simple-validation.sh index d2543153d..4788be786 100755 --- a/scripts/simple-validation.sh +++ b/scripts/simple-validation.sh @@ -63,7 +63,6 @@ check_dir "dist" "Compiled code" echo "" echo "šŸ“„ Configuration Files:" -check_json ".opencode/OpenCode.json" "OpenCode config" check_json ".mcp.json" "MCP server registry" check_json "$HOME/.config/opencode/opencode.json" "Global OpenCode config" diff --git a/scripts/test/test-consumer-readiness.cjs b/scripts/test/test-consumer-readiness.cjs index 54a3c1b47..de9a431f4 100644 --- a/scripts/test/test-consumer-readiness.cjs +++ b/scripts/test/test-consumer-readiness.cjs @@ -210,7 +210,7 @@ class ConsumerReadinessTest { const integrationPoints = [ { name: 'OpenCode Configuration', check: () => { const fs = require('fs'); - // Plugin config is in opencode.json (root), not .opencode/OpenCode.json + // Plugin config is in opencode.json at project root return fs.existsSync(path.join(__dirname, '..', '..', 'opencode.json')); }}, { name: 'Postinstall Script', check: () => { From c88bce9738f81bedd2477963f6a848c038af9974 Mon Sep 17 00:00:00 2001 From: htafolla Date: Mon, 30 Mar 2026 06:19:34 -0500 Subject: [PATCH 7/9] fix: add 14 missing agents to opencode.json Agents that had src/agents/*.ts + .opencode/agents/*.yml but were not registered in opencode.json as subagents: - strategist, backend-engineer, frontend-engineer - frontend-ui-ux-engineer, database-engineer, devops-engineer - mobile-developer, performance-engineer, content-creator - growth-strategist, seo-consultant, tech-writer - librarian-agents-updater, multimodal-looker All added with mode=subagent and descriptions from their .yml definitions. Active agent count: 11 -> 26. Disabled/legacy agents unchanged (48). --- opencode.json | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/opencode.json b/opencode.json index 167b17260..fce283514 100644 --- a/opencode.json +++ b/opencode.json @@ -67,6 +67,76 @@ "temperature": 1.0, "mode": "subagent" }, + "strategist": { + "description": "Expert in system design, architecture decisions, and technical roadmaps", + "temperature": 1.0, + "mode": "subagent" + }, + "backend-engineer": { + "description": "Expert in REST/GraphQL APIs, microservices, authentication, server architecture, and backend performance", + "temperature": 1.0, + "mode": "subagent" + }, + "frontend-engineer": { + "description": "Expert in React, Vue, Angular, responsive design, and frontend performance", + "temperature": 1.0, + "mode": "subagent" + }, + "frontend-ui-ux-engineer": { + "description": "Expert in visual design, CSS systems, accessibility, and user experience", + "temperature": 1.0, + "mode": "subagent" + }, + "database-engineer": { + "description": "Expert in SQL/NoSQL databases, query optimization, data modeling, and database performance", + "temperature": 1.0, + "mode": "subagent" + }, + "devops-engineer": { + "description": "Expert in CI/CD pipelines, infrastructure as code, containerization, and deployment automation", + "temperature": 1.0, + "mode": "subagent" + }, + "mobile-developer": { + "description": "Expert in iOS, Android, React Native, and Flutter development", + "temperature": 1.0, + "mode": "subagent" + }, + "performance-engineer": { + "description": "Expert in profiling, benchmarking, load testing, and optimization", + "temperature": 1.0, + "mode": "subagent" + }, + "content-creator": { + "description": "Expert in creating marketing copy, technical documentation, blog posts, and social media content", + "temperature": 1.0, + "mode": "subagent" + }, + "growth-strategist": { + "description": "Expert in growth hacking, user acquisition, conversion optimization, and analytics", + "temperature": 1.0, + "mode": "subagent" + }, + "seo-consultant": { + "description": "Expert in search engine optimization, keyword research, and organic traffic growth", + "temperature": 1.0, + "mode": "subagent" + }, + "tech-writer": { + "description": "Expert in API documentation, README files, guides, and developer experience", + "temperature": 1.0, + "mode": "subagent" + }, + "librarian-agents-updater": { + "description": "Agent for updating and synchronizing agent definitions", + "temperature": 1.0, + "mode": "subagent" + }, + "multimodal-looker": { + "description": "Media file analysis and interpretation specialist for images, diagrams, PDFs, and visual content", + "temperature": 1.0, + "mode": "subagent" + }, "code-analyzer": { "description": "Code analyzer for metrics", "temperature": 1.0, From 8c1751bcf4d6e22d23f91639b22561c2f4653ebb Mon Sep 17 00:00:00 2001 From: htafolla Date: Mon, 30 Mar 2026 06:54:21 -0500 Subject: [PATCH 8/9] =?UTF-8?q?fix:=20Hermes=20consumer=20cleanup=20?= =?UTF-8?q?=E2=80=94=20skip=20.opencode/,=20fix=20bridge=20state=20dir?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - postinstall: detect Hermes via ~/.hermes, skip all .opencode/ setup (.opencode dir copy, skills, plugin, opencode.json, MCP path conversion) Hermes reads .strray/ directly — .opencode/ was dead weight that goes stale - bridge.mjs: state dir .opencode/state → .strray/state (active bug — hardcoded .opencode path meant Hermes processors never found state) - opencode.json removed from configFiles — Hermes never reads it --- scripts/node/postinstall.cjs | 39 ++++++++++++++++-------- src/integrations/hermes-agent/bridge.mjs | 2 +- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/scripts/node/postinstall.cjs b/scripts/node/postinstall.cjs index 9f6762b68..bf969b1b2 100755 --- a/scripts/node/postinstall.cjs +++ b/scripts/node/postinstall.cjs @@ -33,10 +33,9 @@ console.log("šŸ”§ StrRay Postinstall: Package root:", packageRoot); console.log("šŸ”§ StrRay Postinstall: Consumer directory:", targetDir); console.log("šŸ”§ StrRay Postinstall: Current working dir:", process.cwd()); -// Configuration files to copy during installation +// Configuration files to copy during installation (OpenCode consumers only) const configFiles = [ - // ".mcp.json", // Refactored out - MCP config now in opencode.json - "opencode.json", + // opencode.json NOT included — Hermes consumers don't need it "AGENTS-consumer.md:AGENTS.md" // Minimal version for consumers ]; @@ -46,6 +45,14 @@ const MERGE_FILES = [ 'enforcer-config.json' ]; +// Detect Hermes Agent installation (skip .opencode/ for Hermes consumers) +const homeDir = process.env.HOME || process.env.USERPROFILE || require('os').homedir(); +const isHermes = fs.existsSync(path.join(homeDir, '.hermes')); + +if (isHermes) { + console.log('šŸ” Hermes Agent detected — skipping .opencode/ setup (uses .strray/ directly)'); +} + // Directories to skip entirely const SKIP_DIRS = [ 'node_modules', @@ -60,7 +67,8 @@ const SKIP_FILES = [ 'package-lock.json' ]; -// Copy core skills from src/skills/ to .opencode/skills/ (if not already there or outdated) +// Copy core skills from src/skills/ to .opencode/skills/ (OpenCode consumers only) +if (!isHermes) { const skillsSource = path.join(packageRoot, 'src', 'skills'); const skillsDest = path.join(targetDir, '.opencode', 'skills'); @@ -106,9 +114,11 @@ if (fs.existsSync(skillsSource)) { } catch (error) { console.warn(`āš ļø Could not copy skills:`, error.message); } -} +} // end existsSync(skillsSource) +} // end isHermes guard for skills -// Copy .opencode directory recursively with smart merging +// Copy .opencode directory recursively with smart merging (OpenCode consumers only) +if (!isHermes) { const opencodeSource = path.join(packageRoot, '.opencode'); const opencodeDest = path.join(targetDir, '.opencode'); @@ -216,9 +226,11 @@ if (fs.existsSync(opencodeSource)) { } catch (error) { console.warn(`āš ļø Could not copy directory .opencode:`, error.message); } -} +} // end existsSync(opencodeSource) +} // end isHermes guard for .opencode dir -// Copy plugin from dist/plugin/ to .opencode/plugins/ (if not already there or if outdated) +// Copy plugin from dist/plugin/ to .opencode/plugins/ (OpenCode consumers only) +if (!isHermes) { const pluginSource = path.join(packageRoot, 'dist', 'plugin', 'strray-codex-injection.js'); const pluginDest = path.join(targetDir, '.opencode', 'plugins', 'strray-codex-injection.js'); @@ -243,12 +255,14 @@ if (fs.existsSync(pluginSource)) { } else { console.warn(`āš ļø Plugin source not found: ${pluginSource}`); } +} // end isHermes guard for plugin +// Copy individual files (OpenCode consumers only — Hermes uses .strray/ directly) +if (!isHermes) { console.log("šŸ”§ StrRay Postinstall: Copying configuration files..."); console.log("šŸ“ Package root:", packageRoot); console.log("šŸ“ Target directory:", targetDir); -// Copy individual files configFiles.forEach(fileMapping => { // Handle "source:destination" format for renames const [sourceFile, destFile] = fileMapping.split(':'); @@ -273,6 +287,7 @@ configFiles.forEach(fileMapping => { console.warn(`āš ļø Could not copy ${fileMapping}:`, error.message); } }); +} // end isHermes guard for config files // Create symlink to scripts directory for post-processor monitoring const scriptsSource = path.join(packageRoot, 'scripts'); @@ -305,8 +320,8 @@ const isConsumerEnvironment = fs.existsSync( path.join(cwd, 'node_modules', 'strray-ai', 'package.json') ); -// Convert paths for consumer environment -if (isConsumerEnvironment) { +// Convert paths for consumer environment (OpenCode consumers only) +if (!isHermes && isConsumerEnvironment) { console.log("šŸ”§ StrRay Postinstall: Converting paths for consumer environment..."); // Note: .mcp.json was refactored out - no longer need to update MCP paths @@ -460,7 +475,6 @@ const hermesSkillSource = path.join(packageRoot, 'src', 'skills', 'hermes-agent' if (fs.existsSync(hermesSkillSource)) { try { - const homeDir = process.env.HOME || process.env.USERPROFILE || require('os').homedir(); const targetHermesSkills = path.join(homeDir, '.hermes', 'skills', 'hermes-agent'); if (fs.existsSync(path.join(homeDir, '.hermes'))) { @@ -487,7 +501,6 @@ const hermesPluginSource = path.join(packageRoot, 'src', 'integrations', 'hermes if (fs.existsSync(hermesPluginSource)) { try { - const homeDir = process.env.HOME || process.env.USERPROFILE || require('os').homedir(); const hermesDir = path.join(homeDir, '.hermes'); if (fs.existsSync(hermesDir)) { diff --git a/src/integrations/hermes-agent/bridge.mjs b/src/integrations/hermes-agent/bridge.mjs index 891595869..cabda2137 100644 --- a/src/integrations/hermes-agent/bridge.mjs +++ b/src/integrations/hermes-agent/bridge.mjs @@ -235,7 +235,7 @@ async function runProcessors(tool, args, phase, projectRoot, logDir) { const logger = new BridgeLogger(logDir); try { - const stateDir = join(projectRoot, ".opencode", "state"); + const stateDir = join(projectRoot, ".strray", "state"); const stateManager = new StrRayStateManager(stateDir); const processorManager = new ProcessorManager(stateManager); From a2519e8895eedc742344bb3b39cd7864310a3036 Mon Sep 17 00:00:00 2001 From: htafolla Date: Mon, 30 Mar 2026 07:02:17 -0500 Subject: [PATCH 9/9] =?UTF-8?q?docs:=20fix=20stale=20.opencode/state=20pat?= =?UTF-8?q?h=20in=20README=20=E2=80=94=20.strray/state/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c6a883ae..20db79b9f 100644 --- a/README.md +++ b/README.md @@ -234,7 +234,7 @@ Once connected, Hermes can use the tools directly in conversation: - Use absolute paths in `args` if Hermes runs from a different working directory than your project - Increase `timeout` for orchestrator and researcher (60s) — they do heavier analysis -- The state-manager persists to `.opencode/state/mcp-state.json` — survives Hermes restarts +- The state-manager persists to `.strray/state/mcp-state.json` — survives Hermes restarts - Auto-format and lint need Prettier/ESLint installed in your project to do real work (otherwise they report what's missing) ## šŸ“– Documentation