@theihtisham/agent-shadow-brain 1.0.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 (71) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +166 -0
  3. package/dist/adapters/base-adapter.d.ts +18 -0
  4. package/dist/adapters/base-adapter.d.ts.map +1 -0
  5. package/dist/adapters/base-adapter.js +110 -0
  6. package/dist/adapters/base-adapter.js.map +1 -0
  7. package/dist/adapters/claude-code.d.ts +14 -0
  8. package/dist/adapters/claude-code.d.ts.map +1 -0
  9. package/dist/adapters/claude-code.js +125 -0
  10. package/dist/adapters/claude-code.js.map +1 -0
  11. package/dist/adapters/cline.d.ts +13 -0
  12. package/dist/adapters/cline.d.ts.map +1 -0
  13. package/dist/adapters/cline.js +119 -0
  14. package/dist/adapters/cline.js.map +1 -0
  15. package/dist/adapters/codex.d.ts +12 -0
  16. package/dist/adapters/codex.d.ts.map +1 -0
  17. package/dist/adapters/codex.js +65 -0
  18. package/dist/adapters/codex.js.map +1 -0
  19. package/dist/adapters/index.d.ts +11 -0
  20. package/dist/adapters/index.d.ts.map +1 -0
  21. package/dist/adapters/index.js +38 -0
  22. package/dist/adapters/index.js.map +1 -0
  23. package/dist/adapters/kilo-code.d.ts +12 -0
  24. package/dist/adapters/kilo-code.d.ts.map +1 -0
  25. package/dist/adapters/kilo-code.js +94 -0
  26. package/dist/adapters/kilo-code.js.map +1 -0
  27. package/dist/adapters/opencode.d.ts +12 -0
  28. package/dist/adapters/opencode.d.ts.map +1 -0
  29. package/dist/adapters/opencode.js +100 -0
  30. package/dist/adapters/opencode.js.map +1 -0
  31. package/dist/brain/analyzer.d.ts +23 -0
  32. package/dist/brain/analyzer.d.ts.map +1 -0
  33. package/dist/brain/analyzer.js +218 -0
  34. package/dist/brain/analyzer.js.map +1 -0
  35. package/dist/brain/llm-client.d.ts +30 -0
  36. package/dist/brain/llm-client.d.ts.map +1 -0
  37. package/dist/brain/llm-client.js +240 -0
  38. package/dist/brain/llm-client.js.map +1 -0
  39. package/dist/brain/orchestrator.d.ts +41 -0
  40. package/dist/brain/orchestrator.d.ts.map +1 -0
  41. package/dist/brain/orchestrator.js +289 -0
  42. package/dist/brain/orchestrator.js.map +1 -0
  43. package/dist/brain/project-context.d.ts +15 -0
  44. package/dist/brain/project-context.d.ts.map +1 -0
  45. package/dist/brain/project-context.js +225 -0
  46. package/dist/brain/project-context.js.map +1 -0
  47. package/dist/cli.d.ts +3 -0
  48. package/dist/cli.d.ts.map +1 -0
  49. package/dist/cli.js +254 -0
  50. package/dist/cli.js.map +1 -0
  51. package/dist/index.d.ts +16 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +18 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/types.d.ts +87 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +3 -0
  58. package/dist/types.js.map +1 -0
  59. package/dist/ui/dashboard.d.ts +3 -0
  60. package/dist/ui/dashboard.d.ts.map +1 -0
  61. package/dist/ui/dashboard.js +110 -0
  62. package/dist/ui/dashboard.js.map +1 -0
  63. package/dist/watchers/file-watcher.d.ts +18 -0
  64. package/dist/watchers/file-watcher.d.ts.map +1 -0
  65. package/dist/watchers/file-watcher.js +132 -0
  66. package/dist/watchers/file-watcher.js.map +1 -0
  67. package/dist/watchers/git-watcher.d.ts +31 -0
  68. package/dist/watchers/git-watcher.d.ts.map +1 -0
  69. package/dist/watchers/git-watcher.js +93 -0
  70. package/dist/watchers/git-watcher.js.map +1 -0
  71. package/package.json +77 -0
@@ -0,0 +1,65 @@
1
+ // src/adapters/codex.ts — Adapter for OpenAI Codex CLI
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import * as os from 'os';
5
+ import { execSync } from 'child_process';
6
+ import { BaseAdapter } from './base-adapter.js';
7
+ export class CodexAdapter extends BaseAdapter {
8
+ constructor() {
9
+ super(...arguments);
10
+ this.name = 'codex';
11
+ this.displayName = 'Codex CLI';
12
+ }
13
+ getGlobalDir() {
14
+ return path.join(os.homedir(), '.codex');
15
+ }
16
+ async detect() {
17
+ if (fs.existsSync(this.getGlobalDir()))
18
+ return true;
19
+ if (fs.existsSync(path.join(this.projectDir, 'AGENTS.md')))
20
+ return true;
21
+ try {
22
+ execSync('codex --version', { timeout: 3000, encoding: 'utf-8' });
23
+ return true;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ }
29
+ getConfigPaths() {
30
+ return {
31
+ memoryDir: path.join(this.projectDir, '.codex', 'memory'),
32
+ rulesDir: this.projectDir, // Codex reads AGENTS.md from project root
33
+ conversationDir: path.join(this.getGlobalDir(), 'sessions'),
34
+ configFile: path.join(this.getGlobalDir(), 'config.json'),
35
+ };
36
+ }
37
+ async readActivity() {
38
+ // Codex CLI is newer, may not have persistent session logs yet
39
+ return [];
40
+ }
41
+ async injectContext(insight) {
42
+ // Codex reads AGENTS.md from project root
43
+ const agentsFile = path.join(this.projectDir, 'AGENTS.md');
44
+ const brainSection = `
45
+ ## 🧠 Shadow Brain — ${insight.type.toUpperCase()}
46
+
47
+ **Priority:** ${insight.priority}
48
+ **Time:** ${insight.timestamp.toISOString()}
49
+
50
+ ${insight.content}
51
+ ${insight.files?.length ? `\nRelevant files: ${insight.files.map(f => `\`${f}\``).join(', ')}` : ''}
52
+ `;
53
+ const existing = this.readFile(agentsFile) || '# Agent Instructions\n';
54
+ // Replace or append brain section
55
+ if (existing.includes('## 🧠 Shadow Brain')) {
56
+ const before = existing.split('## 🧠 Shadow Brain')[0];
57
+ fs.writeFileSync(agentsFile, before + brainSection, 'utf-8');
58
+ }
59
+ else {
60
+ fs.writeFileSync(agentsFile, existing + '\n' + brainSection, 'utf-8');
61
+ }
62
+ return true;
63
+ }
64
+ }
65
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/adapters/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { AgentAdapter, AgentTool } from '../types.js';
2
+ import { ClaudeCodeAdapter } from './claude-code.js';
3
+ import { KiloCodeAdapter } from './kilo-code.js';
4
+ import { ClineAdapter } from './cline.js';
5
+ import { OpenCodeAdapter } from './opencode.js';
6
+ import { CodexAdapter } from './codex.js';
7
+ export declare const ALL_ADAPTERS: Record<AgentTool, () => AgentAdapter>;
8
+ export declare function createAdapter(tool: AgentTool): AgentAdapter;
9
+ export declare function detectRunningAgents(projectDir: string): Promise<AgentAdapter[]>;
10
+ export { ClaudeCodeAdapter, KiloCodeAdapter, ClineAdapter, OpenCodeAdapter, CodexAdapter };
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,YAAY,CAS9D,CAAC;AAEF,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,GAAG,YAAY,CAI3D;AAED,wBAAsB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAcrF;AAED,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,38 @@
1
+ // src/adapters/index.ts — Export all adapters + factory
2
+ import { ClaudeCodeAdapter } from './claude-code.js';
3
+ import { KiloCodeAdapter } from './kilo-code.js';
4
+ import { ClineAdapter } from './cline.js';
5
+ import { OpenCodeAdapter } from './opencode.js';
6
+ import { CodexAdapter } from './codex.js';
7
+ export const ALL_ADAPTERS = {
8
+ 'claude-code': () => new ClaudeCodeAdapter(),
9
+ 'kilo-code': () => new KiloCodeAdapter(),
10
+ 'cline': () => new ClineAdapter(),
11
+ 'opencode': () => new OpenCodeAdapter(),
12
+ 'codex': () => new CodexAdapter(),
13
+ 'roo-code': () => new KiloCodeAdapter(), // Roo Code is Kilo Code fork
14
+ 'aider': () => new OpenCodeAdapter(), // Similar CLI pattern
15
+ 'cursor': () => new ClineAdapter(), // Similar VS Code pattern
16
+ };
17
+ export function createAdapter(tool) {
18
+ const factory = ALL_ADAPTERS[tool];
19
+ if (!factory)
20
+ throw new Error(`Unknown agent tool: ${tool}`);
21
+ return factory();
22
+ }
23
+ export async function detectRunningAgents(projectDir) {
24
+ const detected = [];
25
+ for (const [tool, factory] of Object.entries(ALL_ADAPTERS)) {
26
+ const adapter = factory();
27
+ adapter.projectDir = projectDir;
28
+ try {
29
+ if (await adapter.detect()) {
30
+ detected.push(adapter);
31
+ }
32
+ }
33
+ catch { /* skip failures */ }
34
+ }
35
+ return detected;
36
+ }
37
+ export { ClaudeCodeAdapter, KiloCodeAdapter, ClineAdapter, OpenCodeAdapter, CodexAdapter };
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAGxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,CAAC,MAAM,YAAY,GAA0C;IACjE,aAAa,EAAE,GAAG,EAAE,CAAC,IAAI,iBAAiB,EAAE;IAC5C,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,eAAe,EAAE;IACxC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE;IACjC,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,eAAe,EAAE;IACvC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE;IACjC,UAAU,EAAE,GAAG,EAAE,CAAC,IAAI,eAAe,EAAE,EAAE,6BAA6B;IACtE,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,eAAe,EAAE,EAAK,sBAAsB;IAC/D,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,YAAY,EAAE,EAAO,0BAA0B;CACpE,CAAC;AAEF,MAAM,UAAU,aAAa,CAAC,IAAe;IAC3C,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,EAAE,CAAC,CAAC;IAC7D,OAAO,OAAO,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,UAAkB;IAC1D,MAAM,QAAQ,GAAmB,EAAE,CAAC;IAEpC,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QAC3D,MAAM,OAAO,GAAG,OAAO,EAAE,CAAC;QACzB,OAAe,CAAC,UAAU,GAAG,UAAU,CAAC;QACzC,IAAI,CAAC;YACH,IAAI,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC3B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,YAAY,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { BaseAdapter } from './base-adapter.js';
2
+ import { AgentTool, AgentPaths, AgentActivity, BrainInsight } from '../types.js';
3
+ export declare class KiloCodeAdapter extends BaseAdapter {
4
+ name: AgentTool;
5
+ displayName: string;
6
+ private getGlobalDir;
7
+ detect(): Promise<boolean>;
8
+ getConfigPaths(): AgentPaths;
9
+ readActivity(): Promise<AgentActivity[]>;
10
+ injectContext(insight: BrainInsight): Promise<boolean>;
11
+ }
12
+ //# sourceMappingURL=kilo-code.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kilo-code.d.ts","sourceRoot":"","sources":["../../src/adapters/kilo-code.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEjF,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,IAAI,EAAE,SAAS,CAAe;IAC9B,WAAW,SAAe;IAE1B,OAAO,CAAC,YAAY;IAWd,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAShC,cAAc,IAAI,UAAU;IAStB,YAAY,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IA2CxC,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;CAe7D"}
@@ -0,0 +1,94 @@
1
+ // src/adapters/kilo-code.ts — Adapter for Kilo Code (VS Code extension)
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import * as os from 'os';
5
+ import { BaseAdapter } from './base-adapter.js';
6
+ export class KiloCodeAdapter extends BaseAdapter {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.name = 'kilo-code';
10
+ this.displayName = 'Kilo Code';
11
+ }
12
+ getGlobalDir() {
13
+ // Kilo Code stores data in VS Code's extension data
14
+ const platform = os.platform();
15
+ if (platform === 'win32') {
16
+ return path.join(os.homedir(), 'AppData', 'Roaming', 'Code', 'User', 'globalStorage', 'kilocode.kilo-code');
17
+ }
18
+ else if (platform === 'darwin') {
19
+ return path.join(os.homedir(), 'Library', 'Application Support', 'Code', 'User', 'globalStorage', 'kilocode.kilo-code');
20
+ }
21
+ return path.join(os.homedir(), '.config', 'Code', 'User', 'globalStorage', 'kilocode.kilo-code');
22
+ }
23
+ async detect() {
24
+ // Check for Kilo Code extension data
25
+ const dir = this.getGlobalDir();
26
+ if (fs.existsSync(dir))
27
+ return true;
28
+ // Check for .kilocode in project
29
+ return fs.existsSync(path.join(this.projectDir, '.kilocode'));
30
+ }
31
+ getConfigPaths() {
32
+ return {
33
+ memoryDir: path.join(this.projectDir, '.kilocode', 'memory'),
34
+ rulesDir: path.join(this.projectDir, '.kilocode', 'rules'),
35
+ conversationDir: path.join(this.getGlobalDir(), 'tasks'),
36
+ configFile: path.join(this.projectDir, '.kilocode', 'settings.json'),
37
+ };
38
+ }
39
+ async readActivity() {
40
+ const activities = [];
41
+ const tasksDir = path.join(this.getGlobalDir(), 'tasks');
42
+ if (!fs.existsSync(tasksDir))
43
+ return activities;
44
+ try {
45
+ // Kilo Code stores tasks as directories with JSON files
46
+ const taskDirs = fs.readdirSync(tasksDir)
47
+ .map(d => path.join(tasksDir, d))
48
+ .filter(d => fs.statSync(d).isDirectory())
49
+ .sort((a, b) => fs.statSync(b).mtimeMs - fs.statSync(a).mtimeMs)
50
+ .slice(0, 5);
51
+ for (const taskDir of taskDirs) {
52
+ const apiFile = path.join(taskDir, 'api_conversation_history.json');
53
+ if (fs.existsSync(apiFile)) {
54
+ try {
55
+ const data = JSON.parse(fs.readFileSync(apiFile, 'utf-8'));
56
+ if (Array.isArray(data)) {
57
+ for (const msg of data.slice(-20)) {
58
+ if (msg.role === 'assistant' && Array.isArray(msg.content)) {
59
+ for (const block of msg.content) {
60
+ if (block.type === 'tool_use') {
61
+ activities.push({
62
+ timestamp: new Date(),
63
+ type: block.name?.includes('write') ? 'file_edit' : 'file_read',
64
+ detail: `${block.name}: ${JSON.stringify(block.input || {}).slice(0, 200)}`,
65
+ file: block.input?.path,
66
+ });
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ catch { /* malformed */ }
74
+ }
75
+ }
76
+ }
77
+ catch { /* permission issues */ }
78
+ return activities;
79
+ }
80
+ async injectContext(insight) {
81
+ // Inject into .kilocode/rules/ as custom instructions
82
+ const rulesDir = path.join(this.projectDir, '.kilocode', 'rules');
83
+ fs.mkdirSync(rulesDir, { recursive: true });
84
+ const brainFile = path.join(rulesDir, 'shadow-brain.md');
85
+ const existing = this.readFile(brainFile) || '';
86
+ const updated = this.appendToBrainFile(existing, insight);
87
+ fs.writeFileSync(brainFile, updated, 'utf-8');
88
+ // Also write to the memory dir
89
+ const memoryDir = path.join(this.projectDir, '.kilocode', 'memory');
90
+ fs.mkdirSync(memoryDir, { recursive: true });
91
+ return await super.injectContext(insight);
92
+ }
93
+ }
94
+ //# sourceMappingURL=kilo-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kilo-code.js","sourceRoot":"","sources":["../../src/adapters/kilo-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { BaseAdapter } from './base-adapter.js';
2
+ import { AgentTool, AgentPaths, AgentActivity, BrainInsight } from '../types.js';
3
+ export declare class OpenCodeAdapter extends BaseAdapter {
4
+ name: AgentTool;
5
+ displayName: string;
6
+ private getGlobalDir;
7
+ detect(): Promise<boolean>;
8
+ getConfigPaths(): AgentPaths;
9
+ readActivity(): Promise<AgentActivity[]>;
10
+ injectContext(insight: BrainInsight): Promise<boolean>;
11
+ }
12
+ //# sourceMappingURL=opencode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../src/adapters/opencode.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEjF,qBAAa,eAAgB,SAAQ,WAAW;IAC9C,IAAI,EAAE,SAAS,CAAc;IAC7B,WAAW,SAAc;IAEzB,OAAO,CAAC,YAAY;IAId,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC;IAkBhC,cAAc,IAAI,UAAU;IAStB,YAAY,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAuCxC,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;CAkB7D"}
@@ -0,0 +1,100 @@
1
+ // src/adapters/opencode.ts — Adapter for OpenCode CLI
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import * as os from 'os';
5
+ import { execSync } from 'child_process';
6
+ import { BaseAdapter } from './base-adapter.js';
7
+ export class OpenCodeAdapter extends BaseAdapter {
8
+ constructor() {
9
+ super(...arguments);
10
+ this.name = 'opencode';
11
+ this.displayName = 'OpenCode';
12
+ }
13
+ getGlobalDir() {
14
+ return path.join(os.homedir(), '.opencode');
15
+ }
16
+ async detect() {
17
+ // Check for opencode config
18
+ if (fs.existsSync(this.getGlobalDir()))
19
+ return true;
20
+ if (fs.existsSync(path.join(this.projectDir, '.opencode')))
21
+ return true;
22
+ if (fs.existsSync(path.join(this.projectDir, 'opencode.json')))
23
+ return true;
24
+ // Check for running process
25
+ try {
26
+ const result = execSync('tasklist /FI "IMAGENAME eq opencode*" /NH 2>NUL || pgrep -f opencode 2>/dev/null', {
27
+ encoding: 'utf-8',
28
+ timeout: 3000,
29
+ });
30
+ return result.trim().length > 0;
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ }
36
+ getConfigPaths() {
37
+ return {
38
+ memoryDir: path.join(this.projectDir, '.opencode', 'memory'),
39
+ rulesDir: path.join(this.projectDir, '.opencode', 'rules'),
40
+ conversationDir: path.join(this.getGlobalDir(), 'sessions'),
41
+ configFile: path.join(this.projectDir, 'opencode.json'),
42
+ };
43
+ }
44
+ async readActivity() {
45
+ const activities = [];
46
+ const sessionsDir = path.join(this.getGlobalDir(), 'sessions');
47
+ if (!fs.existsSync(sessionsDir))
48
+ return activities;
49
+ try {
50
+ const files = fs.readdirSync(sessionsDir)
51
+ .filter(f => f.endsWith('.json'))
52
+ .sort((a, b) => {
53
+ try {
54
+ return fs.statSync(path.join(sessionsDir, b)).mtimeMs - fs.statSync(path.join(sessionsDir, a)).mtimeMs;
55
+ }
56
+ catch {
57
+ return 0;
58
+ }
59
+ })
60
+ .slice(0, 3);
61
+ for (const file of files) {
62
+ try {
63
+ const data = JSON.parse(fs.readFileSync(path.join(sessionsDir, file), 'utf-8'));
64
+ if (data.messages) {
65
+ for (const msg of data.messages.slice(-20)) {
66
+ if (msg.tool_calls) {
67
+ for (const call of msg.tool_calls) {
68
+ activities.push({
69
+ timestamp: new Date(msg.timestamp || Date.now()),
70
+ type: call.function?.name?.includes('write') ? 'file_edit' : 'file_read',
71
+ detail: `${call.function?.name}: ${JSON.stringify(call.function?.arguments || {}).slice(0, 200)}`,
72
+ });
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ catch { /* skip */ }
79
+ }
80
+ }
81
+ catch { /* permission */ }
82
+ return activities;
83
+ }
84
+ async injectContext(insight) {
85
+ // OpenCode: inject into project .opencode/rules/
86
+ const rulesDir = path.join(this.projectDir, '.opencode', 'rules');
87
+ fs.mkdirSync(rulesDir, { recursive: true });
88
+ const brainFile = path.join(rulesDir, 'shadow-brain.md');
89
+ const existing = this.readFile(brainFile) || '';
90
+ const updated = this.appendToBrainFile(existing, insight);
91
+ fs.writeFileSync(brainFile, updated, 'utf-8');
92
+ // Also create AGENTS.md or .opencode.md for native pickup
93
+ const agentsMd = path.join(this.projectDir, 'AGENTS.md');
94
+ if (!fs.existsSync(agentsMd)) {
95
+ fs.writeFileSync(agentsMd, `# Agent Instructions\n\nSee .opencode/rules/shadow-brain.md for AI brain insights.\n`, 'utf-8');
96
+ }
97
+ return true;
98
+ }
99
+ }
100
+ //# sourceMappingURL=opencode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/adapters/opencode.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import { LLMClient } from './llm-client.js';
2
+ import { BrainPersonality, BrainInsight, FileChange, ProjectContext, AgentActivity, AgentMemory } from '../types.js';
3
+ type ReviewDepth = 'quick' | 'standard' | 'deep';
4
+ interface AnalysisParams {
5
+ changes: FileChange[];
6
+ context: ProjectContext;
7
+ activity: AgentActivity[];
8
+ agentMemory?: AgentMemory;
9
+ }
10
+ export declare class Analyzer {
11
+ private llmClient;
12
+ private personality;
13
+ private reviewDepth;
14
+ constructor(llmClient: LLMClient, personality: BrainPersonality, reviewDepth: ReviewDepth);
15
+ analyze(params: AnalysisParams): Promise<BrainInsight[]>;
16
+ private ruleBasedAnalysis;
17
+ }
18
+ export declare class PromptBuilder {
19
+ static buildSystemPrompt(personality: BrainPersonality): string;
20
+ static buildUserPrompt(params: AnalysisParams, depth: ReviewDepth): string;
21
+ }
22
+ export {};
23
+ //# sourceMappingURL=analyzer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../src/brain/analyzer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAWrH,KAAK,WAAW,GAAG,OAAO,GAAG,UAAU,GAAG,MAAM,CAAC;AAEjD,UAAU,cAAc;IACtB,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,qBAAa,QAAQ;IACnB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,WAAW,CAAmB;IACtC,OAAO,CAAC,WAAW,CAAc;gBAErB,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,gBAAgB,EAAE,WAAW,EAAE,WAAW;IAMnF,OAAO,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAqB9D,OAAO,CAAC,iBAAiB;CA8G1B;AAED,qBAAa,aAAa;IACxB,MAAM,CAAC,iBAAiB,CAAC,WAAW,EAAE,gBAAgB,GAAG,MAAM;IA4C/D,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,WAAW,GAAG,MAAM;CA6D3E"}
@@ -0,0 +1,218 @@
1
+ // src/brain/analyzer.ts — Core analysis engine with LLM + rule-based fallback
2
+ import { z } from 'zod';
3
+ const BrainInsightSchema = z.object({
4
+ type: z.enum(['review', 'suggestion', 'warning', 'context', 'pattern', 'instruction']),
5
+ priority: z.enum(['critical', 'high', 'medium', 'low']),
6
+ title: z.string().max(100),
7
+ content: z.string().max(2000),
8
+ files: z.array(z.string()).optional(),
9
+ });
10
+ const BrainInsightsSchema = z.array(BrainInsightSchema).min(1).max(5);
11
+ export class Analyzer {
12
+ constructor(llmClient, personality, reviewDepth) {
13
+ this.llmClient = llmClient;
14
+ this.personality = personality;
15
+ this.reviewDepth = reviewDepth;
16
+ }
17
+ async analyze(params) {
18
+ const systemPrompt = PromptBuilder.buildSystemPrompt(this.personality);
19
+ const userPrompt = PromptBuilder.buildUserPrompt(params, this.reviewDepth);
20
+ try {
21
+ const raw = await this.llmClient.completeWithSchema(userPrompt, BrainInsightsSchema, systemPrompt);
22
+ return raw.map(insight => ({
23
+ ...insight,
24
+ timestamp: new Date(),
25
+ }));
26
+ }
27
+ catch {
28
+ // Fallback to rule-based analysis when LLM is unavailable
29
+ return this.ruleBasedAnalysis(params.changes, params.context);
30
+ }
31
+ }
32
+ ruleBasedAnalysis(changes, context) {
33
+ const insights = [];
34
+ const now = new Date();
35
+ // Security: .env file changes
36
+ const envChanges = changes.filter(c => c.path.includes('.env') && !c.path.includes('.example'));
37
+ if (envChanges.length > 0) {
38
+ insights.push({
39
+ type: 'warning',
40
+ priority: 'critical',
41
+ title: 'Potential secrets in .env file',
42
+ content: 'Environment file was modified. Ensure no secrets, API keys, or credentials are committed to version control. Verify .gitignore includes .env files.',
43
+ files: envChanges.map(c => c.path),
44
+ timestamp: now,
45
+ });
46
+ }
47
+ // Dependency changes
48
+ const pkgChanges = changes.filter(c => c.path.endsWith('package.json') || c.path.endsWith('requirements.txt') || c.path.endsWith('Cargo.toml'));
49
+ if (pkgChanges.length > 0) {
50
+ insights.push({
51
+ type: 'suggestion',
52
+ priority: 'medium',
53
+ title: 'Dependencies updated — consider audit',
54
+ content: 'A dependency manifest was modified. Review the changes for: version pinning, known vulnerabilities, license compatibility, and unnecessary additions.',
55
+ files: pkgChanges.map(c => c.path),
56
+ timestamp: now,
57
+ });
58
+ }
59
+ // Large batch of changes
60
+ if (changes.length > 10) {
61
+ insights.push({
62
+ type: 'review',
63
+ priority: 'high',
64
+ title: 'Large batch of changes detected',
65
+ content: `${changes.length} files changed at once. Consider splitting into smaller, focused commits for easier review and rollback. Large batches increase the risk of introducing bugs.`,
66
+ files: changes.slice(0, 5).map(c => c.path),
67
+ timestamp: now,
68
+ });
69
+ }
70
+ // Deleted files
71
+ const deletedFiles = changes.filter(c => c.type === 'delete');
72
+ if (deletedFiles.length > 0) {
73
+ insights.push({
74
+ type: 'warning',
75
+ priority: 'high',
76
+ title: 'Files deleted',
77
+ content: `Files were deleted: ${deletedFiles.map(f => f.path).join(', ')}. Verify these deletions are intentional and no other code depends on them.`,
78
+ files: deletedFiles.map(c => c.path),
79
+ timestamp: now,
80
+ });
81
+ }
82
+ // New test files — positive note
83
+ const testFiles = changes.filter(c => c.type === 'add' && (c.path.includes('.test.') || c.path.includes('.spec.') || c.path.includes('_test.')));
84
+ if (testFiles.length > 0) {
85
+ insights.push({
86
+ type: 'context',
87
+ priority: 'low',
88
+ title: 'New test files added',
89
+ content: `Test files created: ${testFiles.map(f => f.path).join(', ')}. Good practice — ensure tests cover edge cases and failure modes.`,
90
+ files: testFiles.map(c => c.path),
91
+ timestamp: now,
92
+ });
93
+ }
94
+ // Missing .gitignore
95
+ if (!context.structure.some(f => f.includes('.gitignore'))) {
96
+ insights.push({
97
+ type: 'suggestion',
98
+ priority: 'medium',
99
+ title: 'No .gitignore found',
100
+ content: 'Project does not have a .gitignore file. Consider adding one to prevent committing build artifacts, dependencies, and secrets.',
101
+ files: [],
102
+ timestamp: now,
103
+ });
104
+ }
105
+ // Language/framework mismatch
106
+ if (context.framework === 'Express' && changes.some(c => c.path.includes('pages/'))) {
107
+ insights.push({
108
+ type: 'suggestion',
109
+ priority: 'medium',
110
+ title: 'Possible framework mismatch',
111
+ content: 'Pages directory detected in an Express project. If migrating to Next.js, ensure proper configuration. Otherwise, follow Express conventions.',
112
+ files: changes.filter(c => c.path.includes('pages/')).map(c => c.path),
113
+ timestamp: now,
114
+ });
115
+ }
116
+ // Ensure at least one insight
117
+ if (insights.length === 0) {
118
+ insights.push({
119
+ type: 'context',
120
+ priority: 'low',
121
+ title: 'Changes monitored',
122
+ content: `${changes.length} file change(s) detected in ${context.name}. No immediate concerns found. Project uses ${context.language.join(', ')}${context.framework ? ` with ${context.framework}` : ''}.`,
123
+ files: changes.map(c => c.path),
124
+ timestamp: now,
125
+ });
126
+ }
127
+ return insights;
128
+ }
129
+ }
130
+ export class PromptBuilder {
131
+ static buildSystemPrompt(personality) {
132
+ const base = `You are the Shadow Brain, an AI that watches agentic coding tools and provides real-time insights.
133
+ You review file changes, git activity, and agent behavior, then generate actionable insights.
134
+ You respond in JSON only — an array of 1-5 insight objects.
135
+ Each insight has: type (review|suggestion|warning|context|pattern|instruction), priority (critical|high|medium|low), title (max 100 chars), content (max 2000 chars), files (array of relevant file paths).`;
136
+ const personalities = {
137
+ mentor: `\nYour personality is MENTOR — you teach and guide.
138
+ - Explain WHY something might be a problem, not just that it is.
139
+ - Suggest better approaches with brief explanations.
140
+ - Acknowledge good patterns when you see them.
141
+ - Be encouraging but honest.
142
+ - Focus on: code quality, best practices, learning opportunities.`,
143
+ critic: `\nYour personality is CRITIC — you give thorough, no-nonsense code reviews.
144
+ - Be direct and specific about issues.
145
+ - Cite specific lines/patterns that concern you.
146
+ - Rate the overall quality of changes.
147
+ - Focus on: bugs, logic errors, missing edge cases, poor naming.`,
148
+ architect: `\nYour personality is ARCHITECT — you think about the big picture.
149
+ - Consider how changes affect the overall system design.
150
+ - Look for coupling, cohesion, and separation of concerns.
151
+ - Suggest structural improvements and patterns.
152
+ - Focus on: modularity, scalability, maintainability, design patterns.`,
153
+ security: `\nYour personality is SECURITY — you are paranoid about vulnerabilities.
154
+ - Flag anything that could be a security risk.
155
+ - Check for: SQL injection, XSS, CSRF, insecure deserialization, hardcoded secrets, weak crypto, missing input validation, exposed endpoints.
156
+ - Be explicit about attack vectors and mitigations.`,
157
+ performance: `\nYour personality is PERFORMANCE — you optimize everything.
158
+ - Look for: N+1 queries, unnecessary re-renders, memory leaks, blocking I/O, large bundle sizes, unoptimized loops, missing caching.
159
+ - Suggest specific optimizations with expected impact.`,
160
+ balanced: `\nYour personality is BALANCED — you combine all perspectives.
161
+ - Mix mentorship, critique, architecture, security, and performance insights.
162
+ - Prioritize by severity: security > bugs > architecture > performance > style.
163
+ - Provide 2-3 insights per analysis covering different aspects.`,
164
+ };
165
+ return base + personalities[personality];
166
+ }
167
+ static buildUserPrompt(params, depth) {
168
+ const { changes, context, activity, agentMemory } = params;
169
+ const sections = [];
170
+ // Project context
171
+ sections.push(`## Project Context
172
+ - Name: ${context.name}
173
+ - Languages: ${context.language.join(', ') || 'Unknown'}
174
+ - Framework: ${context.framework || 'Unknown'}
175
+ - Package Manager: ${context.packageManager || 'Unknown'}
176
+ - Branch: ${context.gitBranch || 'N/A'}
177
+ - Git Status: ${context.gitStatus || 'N/A'}`);
178
+ // File changes
179
+ if (changes.length > 0) {
180
+ sections.push(`## File Changes (${changes.length} files)`);
181
+ for (const change of changes) {
182
+ let entry = `### ${change.type.toUpperCase()}: ${change.path}`;
183
+ if (depth === 'standard' && change.diff) {
184
+ const lines = change.diff.split('\n');
185
+ entry += '\n' + lines.slice(0, 100).join('\n');
186
+ if (lines.length > 100)
187
+ entry += `\n... (${lines.length - 100} more lines)`;
188
+ }
189
+ else if (depth === 'deep' && change.diff) {
190
+ entry += '\n' + change.diff;
191
+ }
192
+ sections.push(entry);
193
+ }
194
+ }
195
+ // Agent activity
196
+ if (activity.length > 0) {
197
+ const activityLines = activity.slice(-20).map(a => `- [${a.type}] ${a.detail}${a.file ? ` (${a.file})` : ''}`);
198
+ sections.push(`## Agent Activity (${activity.length} events)\n${activityLines.join('\n')}`);
199
+ }
200
+ // Agent memory
201
+ if (agentMemory && agentMemory.rules.length > 0) {
202
+ const rulesText = agentMemory.rules.slice(0, 3).join('\n').slice(0, 2000);
203
+ sections.push(`## Current Agent Rules\n${rulesText}`);
204
+ }
205
+ // Token budget guidance
206
+ const tokenLimits = { quick: 4000, standard: 8000, deep: 16000 };
207
+ const budgetNote = `\n---\nToken budget: ~${tokenLimits[depth]} tokens. Be concise but insightful.`;
208
+ sections.push(budgetNote);
209
+ // Truncate if too long
210
+ let result = sections.join('\n\n');
211
+ const maxChars = tokenLimits[depth] * 4; // rough token → char conversion
212
+ if (result.length > maxChars) {
213
+ result = result.slice(0, maxChars) + '\n\n[Content truncated to fit token budget]';
214
+ }
215
+ return result;
216
+ }
217
+ }
218
+ //# sourceMappingURL=analyzer.js.map