strray-ai 1.19.0 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.opencode/plugin/strray-codex-injection.js +172 -158
- package/.strray/skills/api-design/SKILL.md +37 -0
- package/.strray/skills/architect-tools/SKILL.md +37 -0
- package/.strray/skills/architecture-patterns/SKILL.md +37 -0
- package/.strray/skills/auto-format/SKILL.md +37 -0
- package/.strray/skills/backend-engineer/SKILL.md +49 -0
- package/.strray/skills/boot-orchestrator/SKILL.md +37 -0
- package/.strray/skills/bug-triage/SKILL.md +43 -0
- package/.strray/skills/code-analyzer/SKILL.md +45 -0
- package/.strray/skills/code-review/SKILL.md +52 -0
- package/.strray/skills/content-creator/SKILL.md +38 -0
- package/.strray/skills/database-engineer/SKILL.md +46 -0
- package/.strray/skills/devops-engineer/SKILL.md +49 -0
- package/.strray/skills/enforcer/SKILL.md +37 -0
- package/.strray/skills/framework-compliance-audit/SKILL.md +37 -0
- package/.strray/skills/frontend-engineer/SKILL.md +49 -0
- package/.strray/skills/frontend-ui-ux-engineer/SKILL.md +41 -0
- package/.strray/skills/git-workflow/SKILL.md +37 -0
- package/.strray/skills/growth-strategist/SKILL.md +48 -0
- package/.strray/skills/hermes-agent/SKILL.md +212 -0
- package/.strray/skills/inference-improve/SKILL.md +97 -0
- package/.strray/skills/lint/SKILL.md +37 -0
- package/.strray/skills/log-monitor/SKILL.md +44 -0
- package/.strray/skills/mobile-developer/SKILL.md +42 -0
- package/.strray/skills/model-health-check/SKILL.md +37 -0
- package/.strray/skills/multimodal-looker/SKILL.md +45 -0
- package/.strray/skills/orchestrator/SKILL.md +37 -0
- package/.strray/skills/performance-analysis/SKILL.md +37 -0
- package/.strray/skills/performance-engineer/SKILL.md +41 -0
- package/.strray/skills/performance-optimization/SKILL.md +37 -0
- package/.strray/skills/processor-pipeline/SKILL.md +37 -0
- package/.strray/skills/project-analysis/SKILL.md +42 -0
- package/.strray/skills/refactoring-strategies/SKILL.md +37 -0
- package/.strray/skills/researcher/SKILL.md +37 -0
- package/.strray/skills/security-audit/SKILL.md +47 -0
- package/.strray/skills/security-scan/SKILL.md +37 -0
- package/.strray/skills/seo-consultant/SKILL.md +43 -0
- package/.strray/skills/session-management/SKILL.md +36 -0
- package/.strray/skills/state-manager/SKILL.md +37 -0
- package/.strray/skills/storyteller/SKILL.md +130 -0
- package/.strray/skills/strategist/SKILL.md +32 -0
- package/.strray/skills/tech-writer/SKILL.md +37 -0
- package/.strray/skills/testing-best-practices/SKILL.md +37 -0
- package/.strray/skills/testing-strategy/SKILL.md +43 -0
- package/.strray/skills/ui-ux-design/SKILL.md +603 -0
- package/AGENTS.md +3 -35
- package/dist/AGENTS.md +3 -35
- package/dist/CHANGELOG.md +24 -0
- package/dist/cli/commands/plugin-commands.d.ts +20 -0
- package/dist/cli/commands/plugin-commands.d.ts.map +1 -0
- package/dist/cli/commands/plugin-commands.js +226 -0
- package/dist/cli/commands/plugin-commands.js.map +1 -0
- package/dist/cli/index.js +70 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/core/boot-orchestrator.d.ts +6 -0
- package/dist/core/boot-orchestrator.d.ts.map +1 -1
- package/dist/core/boot-orchestrator.js +37 -0
- package/dist/core/boot-orchestrator.js.map +1 -1
- package/dist/enforcement/enforcer-tools.d.ts.map +1 -1
- package/dist/enforcement/enforcer-tools.js +80 -1
- package/dist/enforcement/enforcer-tools.js.map +1 -1
- package/dist/integrations/base/ExampleIntegration.d.ts +48 -0
- package/dist/integrations/base/ExampleIntegration.d.ts.map +1 -0
- package/dist/integrations/base/ExampleIntegration.js +182 -0
- package/dist/integrations/base/ExampleIntegration.js.map +1 -0
- package/dist/integrations/base/Integration.d.ts +268 -0
- package/dist/integrations/base/Integration.d.ts.map +1 -0
- package/dist/integrations/base/Integration.js +396 -0
- package/dist/integrations/base/Integration.js.map +1 -0
- package/dist/integrations/base/index.d.ts +13 -0
- package/dist/integrations/base/index.d.ts.map +1 -0
- package/dist/integrations/base/index.js +17 -0
- package/dist/integrations/base/index.js.map +1 -0
- package/dist/integrations/base/registry.d.ts +274 -0
- package/dist/integrations/base/registry.d.ts.map +1 -0
- package/dist/integrations/base/registry.js +607 -0
- package/dist/integrations/base/registry.js.map +1 -0
- package/dist/integrations/base/types.d.ts +169 -0
- package/dist/integrations/base/types.d.ts.map +1 -0
- package/dist/integrations/base/types.js +119 -0
- package/dist/integrations/base/types.js.map +1 -0
- package/dist/integrations/plugins/index.d.ts +11 -0
- package/dist/integrations/plugins/index.d.ts.map +1 -0
- package/dist/integrations/plugins/index.js +11 -0
- package/dist/integrations/plugins/index.js.map +1 -0
- package/dist/integrations/plugins/plugin-integration.d.ts +290 -0
- package/dist/integrations/plugins/plugin-integration.d.ts.map +1 -0
- package/dist/integrations/plugins/plugin-integration.js +607 -0
- package/dist/integrations/plugins/plugin-integration.js.map +1 -0
- package/dist/integrations/plugins/plugin-registry.d.ts +225 -0
- package/dist/integrations/plugins/plugin-registry.d.ts.map +1 -0
- package/dist/integrations/plugins/plugin-registry.js +581 -0
- package/dist/integrations/plugins/plugin-registry.js.map +1 -0
- package/dist/mcps/config/index.d.ts +2 -0
- package/dist/mcps/config/index.d.ts.map +1 -1
- package/dist/mcps/config/index.js +1 -0
- package/dist/mcps/config/index.js.map +1 -1
- package/dist/mcps/config/plugin-server-registry.d.ts +128 -0
- package/dist/mcps/config/plugin-server-registry.d.ts.map +1 -0
- package/dist/mcps/config/plugin-server-registry.js +224 -0
- package/dist/mcps/config/plugin-server-registry.js.map +1 -0
- package/dist/plugins/plugin-manager.d.ts +40 -0
- package/dist/plugins/plugin-manager.d.ts.map +1 -0
- package/dist/plugins/plugin-manager.js +323 -0
- package/dist/plugins/plugin-manager.js.map +1 -0
- package/dist/plugins/types/index.d.ts +5 -0
- package/dist/plugins/types/index.d.ts.map +1 -0
- package/dist/plugins/types/index.js +5 -0
- package/dist/plugins/types/index.js.map +1 -0
- package/dist/plugins/types/plugin.types.d.ts +120 -0
- package/dist/plugins/types/plugin.types.d.ts.map +1 -0
- package/dist/plugins/types/plugin.types.js +22 -0
- package/dist/plugins/types/plugin.types.js.map +1 -0
- package/package.json +1 -1
- package/scripts/node/auto-reflection-generator.mjs +62 -20
- 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/
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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(
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
const
|
|
148
|
-
ProcessorManager =
|
|
149
|
-
StrRayStateManager =
|
|
150
|
-
featuresConfigLoader =
|
|
151
|
-
detectTaskType =
|
|
152
|
-
logger.log(
|
|
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(
|
|
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:
|
|
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
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
-
|
|
306
|
-
|
|
307
|
-
logger.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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,
|
|
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
|
|
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
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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.
|