strray-ai 1.15.36 → 1.15.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -11,6 +11,36 @@
|
|
|
11
11
|
import * as fs from "fs";
|
|
12
12
|
import * as path from "path";
|
|
13
13
|
import { spawn } from "child_process";
|
|
14
|
+
import { fileURLToPath } from "url";
|
|
15
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
16
|
+
const __dirname = path.dirname(__filename);
|
|
17
|
+
|
|
18
|
+
async function resolvePluginImport(relativePath) {
|
|
19
|
+
const fromPlugin = path.resolve(__dirname, relativePath);
|
|
20
|
+
try { return await import("file://" + fromPlugin); } catch (_) {}
|
|
21
|
+
const fromNM = path.resolve(__dirname, "..", "..", "node_modules", relativePath);
|
|
22
|
+
try { return await import("file://" + fromNM); } catch (_) {}
|
|
23
|
+
const fallbacks = [
|
|
24
|
+
path.resolve("/app/backend/node_modules", relativePath),
|
|
25
|
+
path.resolve("/app/node_modules", relativePath),
|
|
26
|
+
path.resolve(__dirname, "..", "..", "backend", "node_modules", relativePath),
|
|
27
|
+
];
|
|
28
|
+
for (const fb of fallbacks) {
|
|
29
|
+
try { return await import("file://" + fb); } catch (_) {}
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function findStrrayDistDir() {
|
|
35
|
+
const candidates = [
|
|
36
|
+
path.resolve(__dirname, "..", "..", "node_modules", "strray-ai", "dist"),
|
|
37
|
+
path.resolve("/app/node_modules/strray-ai/dist"),
|
|
38
|
+
path.resolve("/app/backend/node_modules/strray-ai/dist"),
|
|
39
|
+
path.resolve(__dirname, "..", "..", "backend", "node_modules", "strray-ai", "dist"),
|
|
40
|
+
];
|
|
41
|
+
for (const d of candidates) { if (fs.existsSync(d)) return d; }
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
14
44
|
// Dynamic imports for config-paths and framework-logger
|
|
15
45
|
// Uses candidate-based resolution to work from both dist/plugin/ and .opencode/plugins/
|
|
16
46
|
let _resolveCodexPath;
|
|
@@ -20,12 +50,14 @@ async function loadFrameworkLogger() {
|
|
|
20
50
|
if (_frameworkLogger)
|
|
21
51
|
return _frameworkLogger;
|
|
22
52
|
const candidates = [
|
|
53
|
+
"strray-ai/dist/core/framework-logger.js",
|
|
23
54
|
"../core/framework-logger.js",
|
|
24
55
|
"../../dist/core/framework-logger.js",
|
|
25
56
|
];
|
|
26
57
|
for (const p of candidates) {
|
|
27
58
|
try {
|
|
28
|
-
const mod = await
|
|
59
|
+
const mod = await resolvePluginImport(p);
|
|
60
|
+
if (!mod) throw new Error("not found");
|
|
29
61
|
_frameworkLogger = mod.frameworkLogger;
|
|
30
62
|
return _frameworkLogger;
|
|
31
63
|
}
|
|
@@ -43,12 +75,14 @@ async function loadConfigPaths() {
|
|
|
43
75
|
if (_resolveCodexPath && _resolveStateDir)
|
|
44
76
|
return;
|
|
45
77
|
const candidates = [
|
|
78
|
+
"strray-ai/dist/core/config-paths.js",
|
|
46
79
|
"../core/config-paths.js",
|
|
47
80
|
"../../dist/core/config-paths.js",
|
|
48
81
|
];
|
|
49
82
|
for (const p of candidates) {
|
|
50
83
|
try {
|
|
51
|
-
const mod = await
|
|
84
|
+
const mod = await resolvePluginImport(p);
|
|
85
|
+
if (!mod) throw new Error("not found");
|
|
52
86
|
_resolveCodexPath = mod.resolveCodexPath;
|
|
53
87
|
_resolveStateDir = mod.resolveStateDir;
|
|
54
88
|
return;
|
|
@@ -74,12 +108,14 @@ let SystemPromptGenerator;
|
|
|
74
108
|
async function importSystemPromptGenerator() {
|
|
75
109
|
if (!SystemPromptGenerator) {
|
|
76
110
|
const candidates = [
|
|
111
|
+
"strray-ai/dist/core/system-prompt-generator.js",
|
|
77
112
|
"../core/system-prompt-generator.js",
|
|
78
113
|
"../../dist/core/system-prompt-generator.js",
|
|
79
114
|
];
|
|
80
115
|
for (const p of candidates) {
|
|
81
116
|
try {
|
|
82
|
-
const module = await
|
|
117
|
+
const module = await resolvePluginImport(p);
|
|
118
|
+
if (!module) throw new Error("not found");
|
|
83
119
|
SystemPromptGenerator = module.generateLeanSystemPrompt;
|
|
84
120
|
return;
|
|
85
121
|
}
|
|
@@ -99,41 +135,25 @@ async function loadStrRayComponents() {
|
|
|
99
135
|
if (ProcessorManager && StrRayStateManager && featuresConfigLoader)
|
|
100
136
|
return;
|
|
101
137
|
const logger = await getOrCreateLogger(process.cwd());
|
|
102
|
-
|
|
138
|
+
const distDir = findStrrayDistDir();
|
|
139
|
+
if (!distDir) {
|
|
140
|
+
logger.error("Failed to locate strray-ai dist directory from any known path");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
103
143
|
try {
|
|
104
|
-
logger.log(
|
|
105
|
-
const
|
|
106
|
-
const
|
|
107
|
-
const
|
|
108
|
-
ProcessorManager =
|
|
109
|
-
StrRayStateManager =
|
|
110
|
-
featuresConfigLoader =
|
|
111
|
-
detectTaskType =
|
|
112
|
-
logger.log(
|
|
144
|
+
logger.log("🔄 Loading from " + distDir);
|
|
145
|
+
const pm = await import("file://" + path.join(distDir, "processors", "processor-manager.js"));
|
|
146
|
+
const sm = await import("file://" + path.join(distDir, "state", "state-manager.js"));
|
|
147
|
+
const fm = await import("file://" + path.join(distDir, "core", "features-config.js"));
|
|
148
|
+
ProcessorManager = pm.ProcessorManager;
|
|
149
|
+
StrRayStateManager = sm.StrRayStateManager;
|
|
150
|
+
featuresConfigLoader = fm.featuresConfigLoader;
|
|
151
|
+
detectTaskType = fm.detectTaskType;
|
|
152
|
+
logger.log("✅ Loaded from " + distDir);
|
|
113
153
|
return;
|
|
114
154
|
}
|
|
115
155
|
catch (e) {
|
|
116
|
-
logger.error(
|
|
117
|
-
}
|
|
118
|
-
// Try node_modules (for consumer installation)
|
|
119
|
-
const pluginPaths = ["strray-ai", "strray-framework"];
|
|
120
|
-
for (const pluginPath of pluginPaths) {
|
|
121
|
-
try {
|
|
122
|
-
logger.log(`🔄 Attempting to load from ../../node_modules/${pluginPath}/dist/`);
|
|
123
|
-
const pm = await import(`../../node_modules/${pluginPath}/dist/processors/processor-manager.js`);
|
|
124
|
-
const sm = await import(`../../node_modules/${pluginPath}/dist/state/state-manager.js`);
|
|
125
|
-
const fm = await import(`../../node_modules/${pluginPath}/dist/core/features-config.js`);
|
|
126
|
-
ProcessorManager = pm.ProcessorManager;
|
|
127
|
-
StrRayStateManager = sm.StrRayStateManager;
|
|
128
|
-
featuresConfigLoader = fm.featuresConfigLoader;
|
|
129
|
-
detectTaskType = fm.detectTaskType;
|
|
130
|
-
logger.log(`✅ Loaded from ../../node_modules/${pluginPath}/dist/`);
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
catch (e) {
|
|
134
|
-
logger.error(`❌ Failed to load from ../../node_modules/${pluginPath}/dist/: ${e?.message || e}`);
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
156
|
+
logger.error("❌ Failed to load from " + distDir + ": " + (e?.message || e));
|
|
137
157
|
}
|
|
138
158
|
}
|
|
139
159
|
function spawnPromise(command, args, cwd) {
|
|
@@ -531,17 +551,22 @@ export default async function strrayCodexPlugin(input) {
|
|
|
531
551
|
let stateManager;
|
|
532
552
|
let processorManager;
|
|
533
553
|
// Check if framework is already booted (global state exists)
|
|
534
|
-
const
|
|
554
|
+
const sessionKey = "strRayStateManager_" + process.pid;
|
|
555
|
+
const globalState = globalThis[sessionKey];
|
|
535
556
|
if (globalState) {
|
|
536
557
|
logger.log("🔗 Connecting to booted StrRay framework");
|
|
537
558
|
stateManager = globalState;
|
|
538
559
|
}
|
|
539
560
|
else {
|
|
540
561
|
logger.log("🚀 StrRay framework not booted, initializing...");
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
562
|
+
try {
|
|
563
|
+
const stateDir = await resolveStateDir(directory);
|
|
564
|
+
stateManager = new StrRayStateManager(stateDir);
|
|
565
|
+
} catch (stateErr) {
|
|
566
|
+
logger.log("⚠️ resolveStateDir failed, using directory: " + (stateErr?.message || stateErr));
|
|
567
|
+
stateManager = new StrRayStateManager(directory);
|
|
568
|
+
}
|
|
569
|
+
globalThis[sessionKey] = stateManager;
|
|
545
570
|
}
|
|
546
571
|
// Get processor manager from state
|
|
547
572
|
processorManager = stateManager.get("processor:manager");
|
|
@@ -594,6 +619,11 @@ export default async function strrayCodexPlugin(input) {
|
|
|
594
619
|
}
|
|
595
620
|
// PHASE 2: Execute pre-processors with detailed logging
|
|
596
621
|
try {
|
|
622
|
+
if (typeof processorManager.executePreProcessors !== "function") {
|
|
623
|
+
logger.error("executePreProcessors is not a function — clearing stale cache");
|
|
624
|
+
stateManager.set("processor:manager", null);
|
|
625
|
+
globalThis[sessionKey] = null;
|
|
626
|
+
} else {
|
|
597
627
|
logger.log(`▶️ Executing pre-processors for ${tool}...`);
|
|
598
628
|
const result = await processorManager.executePreProcessors({
|
|
599
629
|
tool,
|
|
@@ -620,8 +650,14 @@ export default async function strrayCodexPlugin(input) {
|
|
|
620
650
|
catch (error) {
|
|
621
651
|
logger.error(`💥 Pre-processor execution error`, error);
|
|
622
652
|
}
|
|
653
|
+
} // end pre-processor guard
|
|
623
654
|
// PHASE 3: Execute post-processors after tool completion
|
|
624
655
|
try {
|
|
656
|
+
if (typeof processorManager.executePostProcessors !== "function") {
|
|
657
|
+
logger.error("executePostProcessors is not a function — clearing stale cache");
|
|
658
|
+
stateManager.set("processor:manager", null);
|
|
659
|
+
globalThis[sessionKey] = null;
|
|
660
|
+
} else {
|
|
625
661
|
logger.log(`▶️ Executing post-processors for ${tool}...`);
|
|
626
662
|
logger.log(`📝 Post-processor args: ${JSON.stringify(args)}`);
|
|
627
663
|
const postResults = await processorManager.executePostProcessors(tool, {
|
|
@@ -646,6 +682,7 @@ export default async function strrayCodexPlugin(input) {
|
|
|
646
682
|
catch (error) {
|
|
647
683
|
logger.error(`💥 Post-processor execution error`, error);
|
|
648
684
|
}
|
|
685
|
+
} // end post-processor guard
|
|
649
686
|
}
|
|
650
687
|
},
|
|
651
688
|
// Execute POST-processors AFTER tool completes (this is the correct place!)
|
|
@@ -657,7 +694,20 @@ export default async function strrayCodexPlugin(input) {
|
|
|
657
694
|
// This feeds the inference tuner with real tool usage data so it
|
|
658
695
|
// can refine keyword mappings and improve predictive analytics.
|
|
659
696
|
try {
|
|
660
|
-
|
|
697
|
+
let routingOutcomeTracker = null;
|
|
698
|
+
const distDir = findStrrayDistDir();
|
|
699
|
+
if (distDir) {
|
|
700
|
+
try {
|
|
701
|
+
const mod = await import("file://" + path.join(distDir, "delegation", "analytics", "outcome-tracker.js"));
|
|
702
|
+
routingOutcomeTracker = mod.routingOutcomeTracker;
|
|
703
|
+
} catch (_) {}
|
|
704
|
+
}
|
|
705
|
+
if (!routingOutcomeTracker) {
|
|
706
|
+
try {
|
|
707
|
+
const mod = await resolvePluginImport("strray-ai/dist/delegation/analytics/outcome-tracker.js");
|
|
708
|
+
if (mod) routingOutcomeTracker = mod.routingOutcomeTracker;
|
|
709
|
+
} catch (_) {}
|
|
710
|
+
}
|
|
661
711
|
const mapping = TOOL_AGENT_MAP[tool];
|
|
662
712
|
const taskType = classifyTaskType(tool, args);
|
|
663
713
|
const rawDesc = args?.content
|
|
@@ -755,7 +805,20 @@ export default async function strrayCodexPlugin(input) {
|
|
|
755
805
|
if (_openCodeToolCallCount - _lastTuneToolCallCount >= INFERENCE_TUNE_INTERVAL) {
|
|
756
806
|
_lastTuneToolCallCount = _openCodeToolCallCount;
|
|
757
807
|
try {
|
|
758
|
-
|
|
808
|
+
let inferenceTuner = null;
|
|
809
|
+
const tDir = findStrrayDistDir();
|
|
810
|
+
if (tDir) {
|
|
811
|
+
try {
|
|
812
|
+
const mod = await import("file://" + path.join(tDir, "services", "inference-tuner.js"));
|
|
813
|
+
inferenceTuner = mod.inferenceTuner;
|
|
814
|
+
} catch (_) {}
|
|
815
|
+
}
|
|
816
|
+
if (!inferenceTuner) {
|
|
817
|
+
try {
|
|
818
|
+
const mod = await resolvePluginImport("strray-ai/dist/services/inference-tuner.js");
|
|
819
|
+
if (mod) inferenceTuner = mod.inferenceTuner;
|
|
820
|
+
} catch (_) {}
|
|
821
|
+
}
|
|
759
822
|
inferenceTuner
|
|
760
823
|
.runTuningCycle()
|
|
761
824
|
.then(() => {
|
|
@@ -791,13 +854,7 @@ export default async function strrayCodexPlugin(input) {
|
|
|
791
854
|
const logger = await getOrCreateLogger(directory);
|
|
792
855
|
logger.log("🔧 Plugin config hook triggered - initializing StrRay integration");
|
|
793
856
|
// Initialize StrRay framework
|
|
794
|
-
|
|
795
|
-
// Fallback: package .opencode/init.sh (works when postinstall skips for Hermes consumers)
|
|
796
|
-
let initScriptPath = path.join(directory, ".opencode", "init.sh");
|
|
797
|
-
const pkgInitPath = path.join(directory, "node_modules", "strray-ai", ".opencode", "init.sh");
|
|
798
|
-
if (!fs.existsSync(initScriptPath) && fs.existsSync(pkgInitPath)) {
|
|
799
|
-
initScriptPath = pkgInitPath;
|
|
800
|
-
}
|
|
857
|
+
const initScriptPath = path.join(directory, ".opencode", "init.sh");
|
|
801
858
|
if (fs.existsSync(initScriptPath)) {
|
|
802
859
|
try {
|
|
803
860
|
const { stderr } = await spawnPromise("bash", [initScriptPath], directory);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strray-ai",
|
|
3
|
-
"version": "1.15.
|
|
3
|
+
"version": "1.15.37",
|
|
4
4
|
"description": "⚡ StringRay ⚡: Bulletproof AI orchestration with systematic error prevention. Zero dead ends. Ship clean, tested, optimized code — every time.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -78,7 +78,7 @@ const CALCULATED_COUNTS = calculateCounts();
|
|
|
78
78
|
const OFFICIAL_VERSIONS = {
|
|
79
79
|
// Framework version
|
|
80
80
|
framework: {
|
|
81
|
-
version: "1.15.
|
|
81
|
+
version: "1.15.38",
|
|
82
82
|
displayName: "StringRay AI v1.15.36",
|
|
83
83
|
lastUpdated: "2026-03-30",
|
|
84
84
|
// Counts (auto-calculated, but can be overridden)
|