opencode-autognosis 2.3.1 → 2.4.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.
@@ -55,6 +55,7 @@ export declare class CodeGraphDB {
55
55
  };
56
56
  findDependents(filePath: string): string[];
57
57
  searchSymbols(query: string): any[];
58
+ findAffectedTests(symbolName: string): string[];
58
59
  semanticSearch(query: string, limit?: number): Promise<any[]>;
59
60
  private cosineSimilarity;
60
61
  getStats(): {
package/dist/database.js CHANGED
@@ -524,6 +524,29 @@ ${card.content.slice(0, 2000)}`;
524
524
  `);
525
525
  return stmt.all(`%${query}%`);
526
526
  }
527
+ findAffectedTests(symbolName) {
528
+ // Find all files that call this symbol and look like test files
529
+ const query = this.db.prepare(`
530
+ WITH RECURSIVE impact_tree(caller_chunk_id) AS (
531
+ -- Base case: chunks calling the symbol directly
532
+ SELECT caller_chunk_id FROM calls WHERE callee_name = ?
533
+ UNION
534
+ -- Recursive step: chunks calling chunks in the impact tree
535
+ SELECT c.caller_chunk_id
536
+ FROM calls c
537
+ JOIN impact_tree it ON c.callee_name IN (
538
+ SELECT s.name FROM symbols s WHERE s.chunk_id = it.caller_chunk_id
539
+ )
540
+ )
541
+ SELECT DISTINCT f.path
542
+ FROM files f
543
+ JOIN chunks c ON f.id = c.file_id
544
+ JOIN impact_tree it ON c.id = it.caller_chunk_id
545
+ WHERE f.path LIKE '%.test.%' OR f.path LIKE '%Tests.%' OR f.path LIKE 'test_%'
546
+ `);
547
+ const results = query.all(symbolName);
548
+ return results.map(r => r.path);
549
+ }
527
550
  async semanticSearch(query, limit = 10) {
528
551
  if (!(await ollama.isRunning()))
529
552
  throw new Error("Ollama is not running.");
@@ -40,14 +40,14 @@ async function updateBridgePrompt(plugins) {
40
40
  if (!fsSync.existsSync(bridgePath))
41
41
  return "bridge.md not found at " + bridgePath;
42
42
  const toolsSection = `
43
- ## Current Consolidated Tools (Autognosis v2.3)
43
+ ## Current Consolidated Tools (Autognosis v2.4)
44
44
  - code_search: Universal search (semantic, symbol, filename, content).
45
45
  - code_analyze: Deep structural analysis and impact reports.
46
- - code_context: Working memory (ActiveSet) management, LRU eviction, and Symbol Graffiti.
47
- - code_read: Precise symbol jumping and file slicing with Mutex Lock checks.
48
- - code_propose: Planning, patch generation, PR promotion, and Intent indexing.
49
- - code_status: System health, background jobs, Multi-Agent Blackboard, and Resource Locks.
50
- - code_setup: Environment initialization, AI setup, and Architectural Boundaries.
46
+ - code_context: Working memory management and LRU eviction.
47
+ - code_read: Precise reading with Mutex Lock checks and Graffiti retrieval.
48
+ - code_propose: Planning, patching, validation, and PR promotion. Now features surgical test scoping.
49
+ - code_status: Dashboard, background jobs, blackboard, and resource locks.
50
+ - code_setup: Environment initialization and architectural boundaries.
51
51
 
52
52
  ## Other Detected Plugins
53
53
  ${plugins.filter(p => p !== "opencode-autognosis").map(p => `- ${p}`).join('\n')}
@@ -140,9 +140,7 @@ export function unifiedTools() {
140
140
  if (resourceId) {
141
141
  getDb().logAccess(resourceId, args.plan_id);
142
142
  const lock = getDb().isLocked(resourceId);
143
- // Smart History Housekeeping
144
- const graffiti = getDb().getGraffiti(resourceId, 3); // Limit to top 3 recent/pinned notes
145
- // Contextual Verification: Get current hash
143
+ const graffiti = getDb().getGraffiti(resourceId, 3);
146
144
  let currentHash = "";
147
145
  try {
148
146
  const { execSync } = await import("node:child_process");
@@ -176,10 +174,10 @@ export function unifiedTools() {
176
174
  }
177
175
  }),
178
176
  code_propose: tool({
179
- description: "Plan, propose, and promote changes. Automatically handles coordination pulse and lock checks.",
177
+ description: "Plan, propose, and promote changes. Includes patch generation, surgical test scoping, and PR promotion.",
180
178
  args: {
181
179
  action: tool.schema.enum(["plan", "patch", "validate", "finalize", "promote"]),
182
- symbol: tool.schema.string().optional(),
180
+ symbol: tool.schema.string().optional().describe("Locus symbol for plan"),
183
181
  intent: tool.schema.string().optional(),
184
182
  reasoning: tool.schema.string().optional(),
185
183
  message: tool.schema.string().optional(),
@@ -218,8 +216,26 @@ export function unifiedTools() {
218
216
  return res;
219
217
  }
220
218
  case "validate": {
221
- getDb().postToBlackboard(agentName, `Validating patch ${args.patch_path}`, "pulse");
222
- return internal.validate_patch.execute({ patch_path: args.patch_path, plan_id: args.plan_id });
219
+ // 1. Arch Check
220
+ const { stdout: diff } = await internal.runCmd("git diff --name-only");
221
+ const changedFiles = diff.split('\n').filter(Boolean);
222
+ for (const file of changedFiles) {
223
+ const deps = await internal.extractDependencies.execute({ content: "", ast: null, filePath: file });
224
+ const imports = JSON.parse(deps);
225
+ for (const imp of imports) {
226
+ const violation = getDb().checkArchViolation(file, imp);
227
+ if (violation)
228
+ return JSON.stringify({ status: "ARCH_VIOLATION", file, forbidden_import: imp, rule: violation }, null, 2);
229
+ }
230
+ }
231
+ // 2. Surgical Test Scoping
232
+ let focusTests = [];
233
+ if (args.symbol) {
234
+ focusTests = getDb().findAffectedTests(args.symbol);
235
+ }
236
+ getDb().postToBlackboard(agentName, `Validating patch ${args.patch_path}. Scoped tests: ${focusTests.length}`, "pulse");
237
+ // Call validation with scoped tests hint
238
+ return internal.validate_patch.execute({ patch_path: args.patch_path, plan_id: args.plan_id, tests: focusTests });
223
239
  }
224
240
  case "promote": {
225
241
  const branch = args.branch || `autognosis-fix-${Date.now()}`;
@@ -244,12 +260,12 @@ export function unifiedTools() {
244
260
  }
245
261
  }),
246
262
  code_status: tool({
247
- description: "Monitor system health, Multi-Agent Blackboard, and Resource Locks.",
263
+ description: "Monitor system health, background jobs, Multi-Agent Blackboard, and Resource Locks.",
248
264
  args: {
249
- mode: tool.schema.enum(["stats", "hot_files", "jobs", "plan", "doctor", "blackboard", "locks"]).optional().default("stats"),
265
+ mode: tool.schema.enum(["stats", "hot_files", "jobs", "plan", "doctor", "blackboard", "locks", "dashboard"]).optional().default("stats"),
250
266
  action: tool.schema.enum(["post", "read", "lock", "unlock", "archive", "pin"]).optional(),
251
267
  topic: tool.schema.string().optional().default("general"),
252
- target: tool.schema.string().optional().describe("Resource ID (file/symbol) or Note ID"),
268
+ target: tool.schema.string().optional().describe("Resource ID or Note ID"),
253
269
  pinned: tool.schema.boolean().optional().default(false),
254
270
  message: tool.schema.string().optional(),
255
271
  job_id: tool.schema.string().optional(),
@@ -258,6 +274,25 @@ export function unifiedTools() {
258
274
  },
259
275
  async execute(args) {
260
276
  switch (args.mode) {
277
+ case "dashboard": {
278
+ const stats = getDb().getStats();
279
+ const locks = getDb().listLocks();
280
+ const jobs = getDb().listJobs();
281
+ const compliance = args.plan_id ? getDb().getPlanMetrics(args.plan_id) : null;
282
+ let dashboard = `# Autognosis TUI Dashboard\n\n`;
283
+ dashboard += `## 📊 System Stats\n- Files: ${stats.files}\n- Chunks: ${stats.chunks}\n- Embedded: ${stats.embeddings.completed}/${stats.chunks}\n\n`;
284
+ dashboard += `## 🔒 Active Locks\n`;
285
+ if (locks.length > 0)
286
+ dashboard += locks.map((l) => `- ${l.resource_id} (${l.owner_agent})`).join('\n') + '\n\n';
287
+ else
288
+ dashboard += "_No active locks._\n\n";
289
+ dashboard += `## ⚙️ Recent Jobs\n`;
290
+ dashboard += jobs.map((j) => `- [${j.status.toUpperCase()}] ${j.type} (${j.progress}%)`).join('\n') + '\n\n';
291
+ if (compliance) {
292
+ dashboard += `## 📉 Plan Compliance (${args.plan_id})\n- Score: ${compliance.compliance}%\n- Total Calls: ${compliance.total}\n- Off-Plan: ${compliance.off_plan}\n`;
293
+ }
294
+ return dashboard;
295
+ }
261
296
  case "locks": {
262
297
  if (args.action === "lock") {
263
298
  getDb().acquireLock(args.target, agentName);
@@ -301,14 +336,14 @@ export function unifiedTools() {
301
336
  }
302
337
  }),
303
338
  code_setup: tool({
304
- description: "Setup and maintenance tasks (AI, Git Journal, Indexing, Prompt Scouting, Arch Boundaries).",
339
+ description: "Setup tasks (AI, Git Journal, Indexing, Prompt Scouting, Arch Boundaries).",
305
340
  args: {
306
341
  action: tool.schema.enum(["init", "ai", "index", "journal", "scout", "arch_rule"]),
307
342
  provider: tool.schema.enum(["ollama", "mlx"]).optional().default("ollama"),
308
343
  model: tool.schema.string().optional(),
309
344
  limit: tool.schema.number().optional(),
310
- source: tool.schema.string().optional().describe("Source target pattern"),
311
- target: tool.schema.string().optional().describe("Target target pattern (forbidden)")
345
+ source: tool.schema.string().optional(),
346
+ target: tool.schema.string().optional()
312
347
  },
313
348
  async execute(args) {
314
349
  switch (args.action) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-autognosis",
3
- "version": "2.3.1",
3
+ "version": "2.4.0",
4
4
  "description": "Advanced RAG-powered codebase awareness for OpenCode agents. Features Chunk Cards synthesis, hierarchical reasoning, ActiveSet working memory, and performance optimization for enterprise-scale repositories.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",