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 import(p);
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 import(p);
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 import(p);
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
- // Try local dist first (for development)
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(`🔄 Attempting to load from ../../dist/`);
105
- const procModule = await import("../../dist/processors/processor-manager.js");
106
- const stateModule = await import("../../dist/state/state-manager.js");
107
- const featuresModule = await import("../../dist/core/features-config.js");
108
- ProcessorManager = procModule.ProcessorManager;
109
- StrRayStateManager = stateModule.StrRayStateManager;
110
- featuresConfigLoader = featuresModule.featuresConfigLoader;
111
- detectTaskType = featuresModule.detectTaskType;
112
- logger.log(`✅ Loaded from ../../dist/`);
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(`❌ Failed to load from ../../dist/: ${e?.message || e}`);
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 globalState = globalThis.strRayStateManager;
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
- // Create new state manager (framework not booted yet)
542
- stateManager = new StrRayStateManager(await resolveStateDir(directory));
543
- // Store globally for future use
544
- globalThis.strRayStateManager = stateManager;
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
- const { routingOutcomeTracker } = await import("../delegation/analytics/outcome-tracker.js");
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
- const { inferenceTuner } = await import("../services/inference-tuner.js");
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
- // Primary: project .opencode/init.sh (copied by postinstall)
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.36",
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.36",
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)