strray-ai 1.19.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/.opencode/plugin/strray-codex-injection.js +172 -158
  2. package/.strray/skills/api-design/SKILL.md +37 -0
  3. package/.strray/skills/architect-tools/SKILL.md +37 -0
  4. package/.strray/skills/architecture-patterns/SKILL.md +37 -0
  5. package/.strray/skills/auto-format/SKILL.md +37 -0
  6. package/.strray/skills/backend-engineer/SKILL.md +49 -0
  7. package/.strray/skills/boot-orchestrator/SKILL.md +37 -0
  8. package/.strray/skills/bug-triage/SKILL.md +43 -0
  9. package/.strray/skills/code-analyzer/SKILL.md +45 -0
  10. package/.strray/skills/code-review/SKILL.md +52 -0
  11. package/.strray/skills/content-creator/SKILL.md +38 -0
  12. package/.strray/skills/database-engineer/SKILL.md +46 -0
  13. package/.strray/skills/devops-engineer/SKILL.md +49 -0
  14. package/.strray/skills/enforcer/SKILL.md +37 -0
  15. package/.strray/skills/framework-compliance-audit/SKILL.md +37 -0
  16. package/.strray/skills/frontend-engineer/SKILL.md +49 -0
  17. package/.strray/skills/frontend-ui-ux-engineer/SKILL.md +41 -0
  18. package/.strray/skills/git-workflow/SKILL.md +37 -0
  19. package/.strray/skills/growth-strategist/SKILL.md +48 -0
  20. package/.strray/skills/hermes-agent/SKILL.md +212 -0
  21. package/.strray/skills/inference-improve/SKILL.md +97 -0
  22. package/.strray/skills/lint/SKILL.md +37 -0
  23. package/.strray/skills/log-monitor/SKILL.md +44 -0
  24. package/.strray/skills/mobile-developer/SKILL.md +42 -0
  25. package/.strray/skills/model-health-check/SKILL.md +37 -0
  26. package/.strray/skills/multimodal-looker/SKILL.md +45 -0
  27. package/.strray/skills/orchestrator/SKILL.md +37 -0
  28. package/.strray/skills/performance-analysis/SKILL.md +37 -0
  29. package/.strray/skills/performance-engineer/SKILL.md +41 -0
  30. package/.strray/skills/performance-optimization/SKILL.md +37 -0
  31. package/.strray/skills/processor-pipeline/SKILL.md +37 -0
  32. package/.strray/skills/project-analysis/SKILL.md +42 -0
  33. package/.strray/skills/refactoring-strategies/SKILL.md +37 -0
  34. package/.strray/skills/researcher/SKILL.md +37 -0
  35. package/.strray/skills/security-audit/SKILL.md +47 -0
  36. package/.strray/skills/security-scan/SKILL.md +37 -0
  37. package/.strray/skills/seo-consultant/SKILL.md +43 -0
  38. package/.strray/skills/session-management/SKILL.md +36 -0
  39. package/.strray/skills/state-manager/SKILL.md +37 -0
  40. package/.strray/skills/storyteller/SKILL.md +130 -0
  41. package/.strray/skills/strategist/SKILL.md +32 -0
  42. package/.strray/skills/tech-writer/SKILL.md +37 -0
  43. package/.strray/skills/testing-best-practices/SKILL.md +37 -0
  44. package/.strray/skills/testing-strategy/SKILL.md +43 -0
  45. package/.strray/skills/ui-ux-design/SKILL.md +603 -0
  46. package/AGENTS.md +3 -35
  47. package/dist/AGENTS.md +3 -35
  48. package/dist/CHANGELOG.md +32 -0
  49. package/dist/cli/commands/plugin-commands.d.ts +20 -0
  50. package/dist/cli/commands/plugin-commands.d.ts.map +1 -0
  51. package/dist/cli/commands/plugin-commands.js +226 -0
  52. package/dist/cli/commands/plugin-commands.js.map +1 -0
  53. package/dist/cli/index.js +70 -0
  54. package/dist/cli/index.js.map +1 -1
  55. package/dist/core/boot-orchestrator.d.ts +6 -0
  56. package/dist/core/boot-orchestrator.d.ts.map +1 -1
  57. package/dist/core/boot-orchestrator.js +37 -0
  58. package/dist/core/boot-orchestrator.js.map +1 -1
  59. package/dist/enforcement/enforcer-tools.d.ts.map +1 -1
  60. package/dist/enforcement/enforcer-tools.js +80 -1
  61. package/dist/enforcement/enforcer-tools.js.map +1 -1
  62. package/dist/integrations/base/ExampleIntegration.d.ts +48 -0
  63. package/dist/integrations/base/ExampleIntegration.d.ts.map +1 -0
  64. package/dist/integrations/base/ExampleIntegration.js +182 -0
  65. package/dist/integrations/base/ExampleIntegration.js.map +1 -0
  66. package/dist/integrations/base/Integration.d.ts +268 -0
  67. package/dist/integrations/base/Integration.d.ts.map +1 -0
  68. package/dist/integrations/base/Integration.js +396 -0
  69. package/dist/integrations/base/Integration.js.map +1 -0
  70. package/dist/integrations/base/index.d.ts +13 -0
  71. package/dist/integrations/base/index.d.ts.map +1 -0
  72. package/dist/integrations/base/index.js +17 -0
  73. package/dist/integrations/base/index.js.map +1 -0
  74. package/dist/integrations/base/registry.d.ts +274 -0
  75. package/dist/integrations/base/registry.d.ts.map +1 -0
  76. package/dist/integrations/base/registry.js +607 -0
  77. package/dist/integrations/base/registry.js.map +1 -0
  78. package/dist/integrations/base/types.d.ts +169 -0
  79. package/dist/integrations/base/types.d.ts.map +1 -0
  80. package/dist/integrations/base/types.js +119 -0
  81. package/dist/integrations/base/types.js.map +1 -0
  82. package/dist/integrations/plugins/index.d.ts +11 -0
  83. package/dist/integrations/plugins/index.d.ts.map +1 -0
  84. package/dist/integrations/plugins/index.js +11 -0
  85. package/dist/integrations/plugins/index.js.map +1 -0
  86. package/dist/integrations/plugins/plugin-integration.d.ts +290 -0
  87. package/dist/integrations/plugins/plugin-integration.d.ts.map +1 -0
  88. package/dist/integrations/plugins/plugin-integration.js +607 -0
  89. package/dist/integrations/plugins/plugin-integration.js.map +1 -0
  90. package/dist/integrations/plugins/plugin-registry.d.ts +225 -0
  91. package/dist/integrations/plugins/plugin-registry.d.ts.map +1 -0
  92. package/dist/integrations/plugins/plugin-registry.js +581 -0
  93. package/dist/integrations/plugins/plugin-registry.js.map +1 -0
  94. package/dist/mcps/config/index.d.ts +2 -0
  95. package/dist/mcps/config/index.d.ts.map +1 -1
  96. package/dist/mcps/config/index.js +1 -0
  97. package/dist/mcps/config/index.js.map +1 -1
  98. package/dist/mcps/config/plugin-server-registry.d.ts +128 -0
  99. package/dist/mcps/config/plugin-server-registry.d.ts.map +1 -0
  100. package/dist/mcps/config/plugin-server-registry.js +224 -0
  101. package/dist/mcps/config/plugin-server-registry.js.map +1 -0
  102. package/dist/plugins/plugin-manager.d.ts +40 -0
  103. package/dist/plugins/plugin-manager.d.ts.map +1 -0
  104. package/dist/plugins/plugin-manager.js +323 -0
  105. package/dist/plugins/plugin-manager.js.map +1 -0
  106. package/dist/plugins/types/index.d.ts +5 -0
  107. package/dist/plugins/types/index.d.ts.map +1 -0
  108. package/dist/plugins/types/index.js +5 -0
  109. package/dist/plugins/types/index.js.map +1 -0
  110. package/dist/plugins/types/plugin.types.d.ts +120 -0
  111. package/dist/plugins/types/plugin.types.d.ts.map +1 -0
  112. package/dist/plugins/types/plugin.types.js +22 -0
  113. package/dist/plugins/types/plugin.types.js.map +1 -0
  114. package/package.json +1 -1
  115. package/scripts/node/auto-reflection-generator.mjs +62 -20
  116. package/scripts/node/basic-security-audit.cjs +32 -15
@@ -11,38 +11,8 @@
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
- }
44
14
  // Dynamic imports for config-paths and framework-logger
45
- // Uses candidate-based resolution to work from both dist/plugin/ and .opencode/plugins/
15
+ // Uses candidate-based resolution to work from both dist/plugin/ and .opencode/plugin/
46
16
  let _resolveCodexPath;
47
17
  let _resolveStateDir;
48
18
  let _frameworkLogger;
@@ -50,14 +20,13 @@ async function loadFrameworkLogger() {
50
20
  if (_frameworkLogger)
51
21
  return _frameworkLogger;
52
22
  const candidates = [
53
- "strray-ai/dist/core/framework-logger.js",
54
23
  "../core/framework-logger.js",
55
24
  "../../dist/core/framework-logger.js",
25
+ "../../node_modules/strray-ai/dist/core/framework-logger.js",
56
26
  ];
57
27
  for (const p of candidates) {
58
28
  try {
59
- const mod = await resolvePluginImport(p);
60
- if (!mod) throw new Error("not found");
29
+ const mod = await import(p);
61
30
  _frameworkLogger = mod.frameworkLogger;
62
31
  return _frameworkLogger;
63
32
  }
@@ -75,14 +44,13 @@ async function loadConfigPaths() {
75
44
  if (_resolveCodexPath && _resolveStateDir)
76
45
  return;
77
46
  const candidates = [
78
- "strray-ai/dist/core/config-paths.js",
79
47
  "../core/config-paths.js",
80
48
  "../../dist/core/config-paths.js",
49
+ "../../node_modules/strray-ai/dist/core/config-paths.js",
81
50
  ];
82
51
  for (const p of candidates) {
83
52
  try {
84
- const mod = await resolvePluginImport(p);
85
- if (!mod) throw new Error("not found");
53
+ const mod = await import(p);
86
54
  _resolveCodexPath = mod.resolveCodexPath;
87
55
  _resolveStateDir = mod.resolveStateDir;
88
56
  return;
@@ -108,14 +76,13 @@ let SystemPromptGenerator;
108
76
  async function importSystemPromptGenerator() {
109
77
  if (!SystemPromptGenerator) {
110
78
  const candidates = [
111
- "strray-ai/dist/core/system-prompt-generator.js",
112
79
  "../core/system-prompt-generator.js",
113
80
  "../../dist/core/system-prompt-generator.js",
81
+ "../../node_modules/strray-ai/dist/core/system-prompt-generator.js",
114
82
  ];
115
83
  for (const p of candidates) {
116
84
  try {
117
- const module = await resolvePluginImport(p);
118
- if (!module) throw new Error("not found");
85
+ const module = await import(p);
119
86
  SystemPromptGenerator = module.generateLeanSystemPrompt;
120
87
  return;
121
88
  }
@@ -135,25 +102,41 @@ async function loadStrRayComponents() {
135
102
  if (ProcessorManager && StrRayStateManager && featuresConfigLoader)
136
103
  return;
137
104
  const logger = await getOrCreateLogger(process.cwd());
138
- const distDir = findStrrayDistDir();
139
- if (!distDir) {
140
- logger.error("Failed to locate strray-ai dist directory from any known path");
141
- return;
142
- }
105
+ // Try local dist first (for development)
143
106
  try {
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);
107
+ logger.log(`🔄 Attempting to load from ../../dist/`);
108
+ const procModule = await import("../../dist/processors/processor-manager.js");
109
+ const stateModule = await import("../../dist/state/state-manager.js");
110
+ const featuresModule = await import("../../dist/core/features-config.js");
111
+ ProcessorManager = procModule.ProcessorManager;
112
+ StrRayStateManager = stateModule.StrRayStateManager;
113
+ featuresConfigLoader = featuresModule.featuresConfigLoader;
114
+ detectTaskType = featuresModule.detectTaskType;
115
+ logger.log(`✅ Loaded from ../../dist/`);
153
116
  return;
154
117
  }
155
118
  catch (e) {
156
- logger.error("❌ Failed to load from " + distDir + ": " + (e?.message || e));
119
+ logger.error(`❌ Failed to load from ../../dist/: ${e?.message || e}`);
120
+ }
121
+ // Try node_modules (for consumer installation)
122
+ const pluginPaths = ["strray-ai", "strray-framework"];
123
+ for (const pluginPath of pluginPaths) {
124
+ try {
125
+ logger.log(`🔄 Attempting to load from ../../node_modules/${pluginPath}/dist/`);
126
+ const pm = await import(`../../node_modules/${pluginPath}/dist/processors/processor-manager.js`);
127
+ const sm = await import(`../../node_modules/${pluginPath}/dist/state/state-manager.js`);
128
+ const fm = await import(`../../node_modules/${pluginPath}/dist/core/features-config.js`);
129
+ ProcessorManager = pm.ProcessorManager;
130
+ StrRayStateManager = sm.StrRayStateManager;
131
+ featuresConfigLoader = fm.featuresConfigLoader;
132
+ detectTaskType = fm.detectTaskType;
133
+ logger.log(`✅ Loaded from ../../node_modules/${pluginPath}/dist/`);
134
+ return;
135
+ }
136
+ catch (e) {
137
+ logger.error(`❌ Failed to load from ../../node_modules/${pluginPath}/dist/: ${e?.message || e}`);
138
+ continue;
139
+ }
157
140
  }
158
141
  }
159
142
  function spawnPromise(command, args, cwd) {
@@ -251,65 +234,108 @@ function getFrameworkIdentity() {
251
234
  📚 Codex: 5 Essential Terms (99.6% Error Prevention Target)
252
235
  🎯 Goal: Progressive, production-ready development workflow
253
236
 
254
- 📖 Documentation: .opencode/strray/ (codex, config, agents docs)
237
+ 📖 Documentation: config dir (codex, config, agents docs) — resolved via config-paths
255
238
  `;
256
239
  }
257
240
  /**
258
241
  * Run Enforcer quality gate check before operations
242
+ * Now delegates to RuleEnforcer for proper rule enforcement
259
243
  */
260
244
  async function runEnforcerQualityGate(input, logger) {
261
245
  const violations = [];
262
246
  const { tool, args } = input;
263
- // Rule 1: tests-required for new files
264
- if (tool === "write" && args?.filePath) {
265
- const filePath = args.filePath;
266
- // Check if this is a source file (not test, not config)
267
- if (filePath.endsWith(".ts") &&
268
- !filePath.includes(".test.") &&
269
- !filePath.includes(".spec.")) {
270
- // Check if test file exists
271
- const testPath = filePath.replace(".ts", ".test.ts");
272
- const specPath = filePath.replace(".ts", ".spec.ts");
273
- if (!fs.existsSync(testPath) && !fs.existsSync(specPath)) {
274
- violations.push(`tests-required: No test file found for ${filePath} (expected ${testPath} or ${specPath})`);
275
- logger.log(`⚠️ ENFORCER: tests-required violation detected for ${filePath}`);
247
+ try {
248
+ // Lazy load RuleEnforcer to avoid circular dependencies
249
+ const { RuleEnforcer } = await import("../enforcement/rule-enforcer.js");
250
+ const ruleEnforcer = new RuleEnforcer();
251
+ // Build validation context from the input
252
+ const context = {
253
+ operation: tool === "write" ? "write" : tool === "edit" ? "edit" : "read",
254
+ };
255
+ if (args?.filePath) {
256
+ context.files = [args.filePath];
257
+ }
258
+ if (args?.content) {
259
+ context.newCode = args.content;
260
+ }
261
+ // Use RuleEnforcer.validateOperation() instead of hardcoded rules
262
+ const report = await ruleEnforcer.validateOperation(tool, context);
263
+ // Collect blocking violations from errors and failed results
264
+ const blockingViolations = [];
265
+ const allViolations = [];
266
+ // Check errors (these are blocking by nature)
267
+ if (report.errors && report.errors.length > 0) {
268
+ for (const error of report.errors) {
269
+ allViolations.push(error);
270
+ blockingViolations.push(error); // All errors are blocking
276
271
  }
277
272
  }
278
- }
279
- // Rule 2: documentation-required for new features
280
- if (tool === "write" && args?.filePath?.includes("src/")) {
281
- const docsDir = path.join(process.cwd(), "docs");
282
- const readmePath = path.join(process.cwd(), "README.md");
283
- // Check if docs directory exists
284
- if (!fs.existsSync(docsDir) && !fs.existsSync(readmePath)) {
285
- violations.push(`documentation-required: No documentation found for new feature`);
286
- logger.log(`⚠️ ENFORCER: documentation-required violation detected`);
273
+ // Check failed results - only block on error severity, not warnings
274
+ if (report.results) {
275
+ for (const result of report.results) {
276
+ if (!result.passed) {
277
+ const isBlocking = result.severity === "error" || result.severity === "blocking" || result.severity === "high";
278
+ allViolations.push(result.message);
279
+ // Only block on error/blocking/high severity, allow warnings
280
+ if (isBlocking) {
281
+ blockingViolations.push(result.message);
282
+ }
283
+ }
284
+ }
287
285
  }
288
- }
289
- // Rule 3: resolve-all-errors - check if we're creating code with error patterns
290
- if (args?.content) {
291
- const errorPatterns = [
292
- /console\.log\s*\(/g,
293
- /TODO\s*:/gi,
294
- /FIXME\s*:/gi,
295
- /throw\s+new\s+Error\s*\(\s*['"]test['"]\s*\)/gi,
296
- ];
297
- for (const pattern of errorPatterns) {
298
- if (pattern.test(args.content)) {
299
- violations.push(`resolve-all-errors: Found debug/error pattern (${pattern.source}) in code`);
300
- logger.log(`⚠️ ENFORCER: resolve-all-errors violation detected`);
301
- break;
286
+ if (allViolations.length > 0) {
287
+ logger.log(`⚠️ ENFORCER: ${allViolations.length} rule violation(s) detected`);
288
+ for (const v of allViolations.slice(0, 5)) {
289
+ logger.log(` - ${v}`);
290
+ }
291
+ if (allViolations.length > 5) {
292
+ logger.log(` ... and ${allViolations.length - 5} more`);
302
293
  }
303
294
  }
295
+ const passed = blockingViolations.length === 0;
296
+ violations.push(...blockingViolations);
297
+ if (!passed) {
298
+ logger.error(`🚫 Quality Gate FAILED with ${blockingViolations.length} blocking violation(s)`);
299
+ }
300
+ else {
301
+ logger.log(`✅ Quality Gate PASSED (${allViolations.length} warning(s))`);
302
+ }
303
+ return { passed, violations };
304
304
  }
305
- const passed = violations.length === 0;
306
- if (!passed) {
307
- logger.error(`🚫 Quality Gate FAILED with ${violations.length} violations`);
308
- }
309
- else {
310
- logger.log(`✅ Quality Gate PASSED`);
305
+ catch (error) {
306
+ // If RuleEnforcer fails to load or run, fall back to minimal checks
307
+ logger.log(`Warning: RuleEnforcer unavailable, using fallback checks: ${error instanceof Error ? error.message : String(error)}`);
308
+ // Fallback: minimal hardcoded checks (the old logic, as safety net)
309
+ if (tool === "write" && args?.filePath) {
310
+ const filePath = args.filePath;
311
+ if (filePath.endsWith(".ts") &&
312
+ !filePath.includes(".test.") &&
313
+ !filePath.includes(".spec.")) {
314
+ const testPath = filePath.replace(".ts", ".test.ts");
315
+ const specPath = filePath.replace(".ts", ".spec.ts");
316
+ if (!fs.existsSync(testPath) && !fs.existsSync(specPath)) {
317
+ violations.push(`tests-required: No test file found for ${filePath}`);
318
+ }
319
+ }
320
+ }
321
+ if (args?.content) {
322
+ const errorPatterns = [/console\.log\s*\(/g, /TODO\s*:/gi, /FIXME\s*:/gi];
323
+ for (const pattern of errorPatterns) {
324
+ if (pattern.test(args.content)) {
325
+ violations.push(`resolve-all-errors: Found error pattern in code`);
326
+ break;
327
+ }
328
+ }
329
+ }
330
+ const passed = violations.length === 0;
331
+ if (!passed) {
332
+ logger.error(`🚫 Fallback Quality Gate FAILED with ${violations.length} violation(s)`);
333
+ }
334
+ else {
335
+ logger.log(`✅ Fallback Quality Gate PASSED`);
336
+ }
337
+ return { passed, violations };
311
338
  }
312
- return { passed, violations };
313
339
  }
314
340
  /**
315
341
  * Global codex context cache (loaded once)
@@ -323,7 +349,7 @@ async function getCodexFileLocations(directory) {
323
349
  const root = directory || process.cwd();
324
350
  const resolved = await resolveCodexPath(root);
325
351
  // Add OpenCode-specific fallbacks not in the standard chain
326
- resolved.push(path.join(root, ".opencode", "codex.codex"), path.join(root, ".strray", "agents_template.md"), path.join(root, "AGENTS.md"));
352
+ 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"));
327
353
  return resolved;
328
354
  }
329
355
  /**
@@ -356,7 +382,7 @@ function extractCodexMetadata(content) {
356
382
  // Not valid JSON, try markdown format
357
383
  }
358
384
  }
359
- // Markdown format (AGENTS.md, .strray/agents_template.md)
385
+ // Markdown format (AGENTS.md, agents_template.md via config-paths resolver)
360
386
  const versionMatch = content.match(/\*\*Version\*\*:\s*(\d+\.\d+\.\d+)/);
361
387
  const version = versionMatch && versionMatch[1] ? versionMatch[1] : "1.6.0";
362
388
  const termMatches = content.match(/####\s*\d+\.\s/g);
@@ -551,22 +577,17 @@ export default async function strrayCodexPlugin(input) {
551
577
  let stateManager;
552
578
  let processorManager;
553
579
  // Check if framework is already booted (global state exists)
554
- const sessionKey = "strRayStateManager_" + process.pid;
555
- const globalState = globalThis[sessionKey];
580
+ const globalState = globalThis.strRayStateManager;
556
581
  if (globalState) {
557
582
  logger.log("🔗 Connecting to booted StrRay framework");
558
583
  stateManager = globalState;
559
584
  }
560
585
  else {
561
586
  logger.log("🚀 StrRay framework not booted, initializing...");
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;
587
+ // Create new state manager (framework not booted yet)
588
+ stateManager = new StrRayStateManager(await resolveStateDir(directory));
589
+ // Store globally for future use
590
+ globalThis.strRayStateManager = stateManager;
570
591
  }
571
592
  // Get processor manager from state
572
593
  processorManager = stateManager.get("processor:manager");
@@ -619,11 +640,6 @@ export default async function strrayCodexPlugin(input) {
619
640
  }
620
641
  // PHASE 2: Execute pre-processors with detailed logging
621
642
  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 {
627
643
  logger.log(`▶️ Executing pre-processors for ${tool}...`);
628
644
  const result = await processorManager.executePreProcessors({
629
645
  tool,
@@ -650,22 +666,32 @@ export default async function strrayCodexPlugin(input) {
650
666
  catch (error) {
651
667
  logger.error(`💥 Pre-processor execution error`, error);
652
668
  }
653
- } // end pre-processor guard
654
669
  // PHASE 3: Execute post-processors after tool completion
655
670
  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 {
661
671
  logger.log(`▶️ Executing post-processors for ${tool}...`);
662
672
  logger.log(`📝 Post-processor args: ${JSON.stringify(args)}`);
663
- const postResults = await processorManager.executePostProcessors(tool, {
673
+ // Determine operation type and enrich context with metadata for processors
674
+ const isPublishOperation = tool === "publish" || tool === "release" || tool === "npm-publish" || tool === "strray-release";
675
+ // Get agent info from session state if available
676
+ const agentName = global.currentAgent?.agentType ||
677
+ global.currentAgent?.type ||
678
+ input.agentType ||
679
+ "orchestrator";
680
+ const postProcessorContext = {
664
681
  directory,
665
- operation: "tool_execution",
682
+ operation: tool,
666
683
  filePath: args?.filePath,
667
684
  success: true,
668
- }, []);
685
+ agentName,
686
+ metadata: {
687
+ isPublishing: isPublishOperation,
688
+ hook: "tool_execution",
689
+ toolName: tool,
690
+ timestamp: Date.now(),
691
+ agentType: agentName,
692
+ },
693
+ };
694
+ const postResults = await processorManager.executePostProcessors(tool, postProcessorContext, []);
669
695
  // postResults is an array of ProcessorResult
670
696
  const allSuccess = postResults.every((r) => r.success);
671
697
  logger.log(`📊 Post-processor result: ${allSuccess ? "SUCCESS" : "FAILED"} (${postResults.length} processors)`);
@@ -682,7 +708,6 @@ export default async function strrayCodexPlugin(input) {
682
708
  catch (error) {
683
709
  logger.error(`💥 Post-processor execution error`, error);
684
710
  }
685
- } // end post-processor guard
686
711
  }
687
712
  },
688
713
  // Execute POST-processors AFTER tool completes (this is the correct place!)
@@ -694,20 +719,7 @@ export default async function strrayCodexPlugin(input) {
694
719
  // This feeds the inference tuner with real tool usage data so it
695
720
  // can refine keyword mappings and improve predictive analytics.
696
721
  try {
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
- }
722
+ const { routingOutcomeTracker } = await import("../delegation/analytics/outcome-tracker.js");
711
723
  const mapping = TOOL_AGENT_MAP[tool];
712
724
  const taskType = classifyTaskType(tool, args);
713
725
  const rawDesc = args?.content
@@ -766,12 +778,21 @@ export default async function strrayCodexPlugin(input) {
766
778
  logger.log(`📝 Post-processor tool: ${tool}`);
767
779
  logger.log(`📝 Post-processor args: ${JSON.stringify(args)}`);
768
780
  logger.log(`📝 Post-processor directory: ${directory}`);
769
- const postResults = await processorManager.executePostProcessors(tool, {
781
+ // Determine operation type and enrich context with metadata for processors
782
+ const isPublishOperation = tool === "publish" || tool === "release" || tool === "npm-publish" || tool === "strray-release";
783
+ const postProcessorContext = {
770
784
  directory,
771
- operation: "tool_execution",
785
+ operation: tool,
772
786
  filePath: args?.filePath,
773
787
  success: result?.success !== false,
774
- }, []);
788
+ metadata: {
789
+ isPublishing: isPublishOperation,
790
+ hook: "tool_execution",
791
+ toolName: tool,
792
+ timestamp: Date.now(),
793
+ },
794
+ };
795
+ const postResults = await processorManager.executePostProcessors(tool, postProcessorContext, []);
775
796
  // postResults is an array of ProcessorResult
776
797
  const allSuccess = postResults.every((r) => r.success);
777
798
  logger.log(`📊 Post-processor result: ${allSuccess ? "SUCCESS" : "FAILED"} (${postResults.length} processors)`);
@@ -805,20 +826,7 @@ export default async function strrayCodexPlugin(input) {
805
826
  if (_openCodeToolCallCount - _lastTuneToolCallCount >= INFERENCE_TUNE_INTERVAL) {
806
827
  _lastTuneToolCallCount = _openCodeToolCallCount;
807
828
  try {
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
- }
829
+ const { inferenceTuner } = await import("../services/inference-tuner.js");
822
830
  inferenceTuner
823
831
  .runTuningCycle()
824
832
  .then(() => {
@@ -854,7 +862,13 @@ export default async function strrayCodexPlugin(input) {
854
862
  const logger = await getOrCreateLogger(directory);
855
863
  logger.log("🔧 Plugin config hook triggered - initializing StrRay integration");
856
864
  // Initialize StrRay framework
857
- const initScriptPath = path.join(directory, ".opencode", "init.sh");
865
+ // Primary: project .opencode/init.sh (copied by postinstall)
866
+ // Fallback: package .opencode/init.sh (works when postinstall skips for Hermes consumers)
867
+ let initScriptPath = path.join(directory, ".opencode", "init.sh");
868
+ const pkgInitPath = path.join(directory, "node_modules", "strray-ai", ".opencode", "init.sh");
869
+ if (!fs.existsSync(initScriptPath) && fs.existsSync(pkgInitPath)) {
870
+ initScriptPath = pkgInitPath;
871
+ }
858
872
  if (fs.existsSync(initScriptPath)) {
859
873
  try {
860
874
  const { stderr } = await spawnPromise("bash", [initScriptPath], directory);
@@ -0,0 +1,37 @@
1
+ ---
2
+ source: framework
3
+ name: api-design
4
+ description: RESTful API design and validation
5
+ author: StrRay Framework
6
+ version: 1.0.0
7
+ schema_version: "1.0"
8
+ tags: [design, api, design]
9
+ capabilities:
10
+ - design_rest_api
11
+ - validate_api_specs
12
+ - generate_api_docs
13
+ dependencies: []
14
+
15
+ mcp:
16
+ api-design:
17
+ command: node
18
+ args: [node_modules/strray-ai/dist/mcps/knowledge-skills/api-design.server.js]
19
+ ---
20
+
21
+ # Api Design Skill
22
+
23
+ RESTful API design and validation.
24
+
25
+ ## Tools Available
26
+
27
+ - **api_design**: API design
28
+ - **endpoint_validation**: Endpoint validation
29
+ - **api_documentation**: API documentation
30
+
31
+ ## Usage
32
+
33
+ This skill provides design capabilities for api design functionality.
34
+
35
+ ## Integration
36
+
37
+ Activated when design capabilities are requested through the skills system.
@@ -0,0 +1,37 @@
1
+ ---
2
+ source: framework
3
+ name: architect-tools
4
+ description: System design and technical architecture tools
5
+ author: StrRay Framework
6
+ version: 1.0.0
7
+ schema_version: "1.0"
8
+ tags: [design, architect, tools]
9
+ capabilities:
10
+ - design_system
11
+ - evaluate_architecture
12
+ - recommend_tools
13
+ dependencies: []
14
+
15
+ mcp:
16
+ architect-tools:
17
+ command: node
18
+ args: [node_modules/strray-ai/dist/mcps/architect-tools.server.js]
19
+ ---
20
+
21
+ # Architect Tools Skill
22
+
23
+ System design and technical architecture tools.
24
+
25
+ ## Tools Available
26
+
27
+ - **architecture_design**: Architecture design
28
+ - **system_planning**: System planning
29
+ - **technical_decisions**: Technical decisions
30
+
31
+ ## Usage
32
+
33
+ This skill provides design capabilities for architect tools functionality.
34
+
35
+ ## Integration
36
+
37
+ Activated when design capabilities are requested through the skills system.
@@ -0,0 +1,37 @@
1
+ ---
2
+ source: framework
3
+ name: architecture-patterns
4
+ description: Software architecture patterns and best practices
5
+ author: StrRay Framework
6
+ version: 1.0.0
7
+ schema_version: "1.0"
8
+ tags: [design, architecture, patterns]
9
+ capabilities:
10
+ - analyze_architecture
11
+ - recommend_patterns
12
+ - evaluate_design
13
+ dependencies: []
14
+
15
+ mcp:
16
+ architecture-patterns:
17
+ command: node
18
+ args: [node_modules/strray-ai/dist/mcps/knowledge-skills/architecture-patterns.server.js]
19
+ ---
20
+
21
+ # Architecture Patterns Skill
22
+
23
+ Software architecture patterns and best practices.
24
+
25
+ ## Tools Available
26
+
27
+ - **architecture_patterns**: Architecture patterns
28
+ - **design_patterns**: Design patterns
29
+ - **best_practices**: Best practices
30
+
31
+ ## Usage
32
+
33
+ This skill provides design capabilities for architecture patterns functionality.
34
+
35
+ ## Integration
36
+
37
+ Activated when design capabilities are requested through the skills system.
@@ -0,0 +1,37 @@
1
+ ---
2
+ source: framework
3
+ name: auto-format
4
+ description: Automated code formatting and style consistency
5
+ author: StrRay Framework
6
+ version: 1.0.0
7
+ schema_version: "1.0"
8
+ tags: [formatting, auto, format]
9
+ capabilities:
10
+ - format_code
11
+ - enforce_style
12
+ - fix_lint_errors
13
+ dependencies: []
14
+
15
+ mcp:
16
+ auto-format:
17
+ command: node
18
+ args: [node_modules/strray-ai/dist/mcps/auto-format.server.js]
19
+ ---
20
+
21
+ # Auto Format Skill
22
+
23
+ Automated code formatting and style consistency.
24
+
25
+ ## Tools Available
26
+
27
+ - **code_formatting**: Code formatting
28
+ - **style_consistency**: Style consistency
29
+ - **auto-formatting**: Auto-formatting
30
+
31
+ ## Usage
32
+
33
+ This skill provides formatting capabilities for auto format functionality.
34
+
35
+ ## Integration
36
+
37
+ Activated when formatting capabilities are requested through the skills system.