opencode-autognosis 2.0.5 → 2.3.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/dist/activeset.d.ts +28 -0
- package/dist/activeset.js +2 -2
- package/dist/chunk-cards.d.ts +4 -0
- package/dist/chunk-cards.js +40 -0
- package/dist/database.d.ts +24 -8
- package/dist/database.js +292 -119
- package/dist/index.d.ts +6 -1
- package/dist/index.js +32 -1
- package/dist/performance-optimization.d.ts +1 -0
- package/dist/performance-optimization.js +7 -2
- package/dist/services/mlx.d.ts +8 -0
- package/dist/services/mlx.js +53 -0
- package/dist/services/policy.d.ts +12 -0
- package/dist/services/policy.js +59 -0
- package/dist/services/tui.d.ts +8 -0
- package/dist/services/tui.js +43 -0
- package/dist/services/watcher.d.ts +8 -0
- package/dist/services/watcher.js +50 -0
- package/dist/system-tools.js +6 -0
- package/dist/unified-api.js +159 -55
- package/package.json +4 -2
|
@@ -8,6 +8,7 @@ import * as crypto from "node:crypto";
|
|
|
8
8
|
import { getDb } from "./database.js";
|
|
9
9
|
import { CHUNK_DIR, ensureChunkDir, calculateHash, calculateComplexity, parseFileAST, generateSummaryChunk, generateApiChunk, generateInvariantChunk, extractDependencies, extractSymbolsFromAST, extractSymbols } from "./chunk-cards.js";
|
|
10
10
|
import { Logger } from "./services/logger.js";
|
|
11
|
+
import { tui } from "./services/tui.js";
|
|
11
12
|
const execAsync = promisify(exec);
|
|
12
13
|
const PROJECT_ROOT = process.cwd();
|
|
13
14
|
const OPENCODE_DIR = path.join(PROJECT_ROOT, ".opencode");
|
|
@@ -606,7 +607,7 @@ async function getAllSourceFiles() {
|
|
|
606
607
|
await scanDirectory(PROJECT_ROOT);
|
|
607
608
|
return sourceFiles;
|
|
608
609
|
}
|
|
609
|
-
async function indexFile(filePath) {
|
|
610
|
+
export async function indexFile(filePath) {
|
|
610
611
|
try {
|
|
611
612
|
const content = await fs.readFile(filePath, 'utf-8');
|
|
612
613
|
await ensureChunkDir();
|
|
@@ -711,8 +712,11 @@ async function runBackgroundIndexing(taskId, indexingState) {
|
|
|
711
712
|
processed++;
|
|
712
713
|
// Update progress periodically
|
|
713
714
|
if (processed % 5 === 0 || processed === total) {
|
|
714
|
-
|
|
715
|
+
const progress = Math.round((processed / total) * 100);
|
|
716
|
+
task.progress = progress;
|
|
715
717
|
await fs.writeFile(taskPath, JSON.stringify(task, null, 2));
|
|
718
|
+
// Stream to TUI
|
|
719
|
+
await tui.showProgress("Codebase Indexing", progress, `Processing: ${file}`);
|
|
716
720
|
}
|
|
717
721
|
}
|
|
718
722
|
// Complete task
|
|
@@ -720,6 +724,7 @@ async function runBackgroundIndexing(taskId, indexingState) {
|
|
|
720
724
|
task.completed_at = new Date().toISOString();
|
|
721
725
|
task.progress = 100;
|
|
722
726
|
await fs.writeFile(taskPath, JSON.stringify(task, null, 2));
|
|
727
|
+
await tui.showSuccess("Indexing Complete", `Processed ${total} files.`);
|
|
723
728
|
}
|
|
724
729
|
catch (error) {
|
|
725
730
|
// Update task with error
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const DEFAULT_MLX_MODEL = "sentence-transformers/all-MiniLM-L6-v2";
|
|
2
|
+
export declare class MLXService {
|
|
3
|
+
private isAvailable;
|
|
4
|
+
checkAvailability(): Promise<boolean>;
|
|
5
|
+
setup(): Promise<string>;
|
|
6
|
+
getEmbedding(text: string, model?: string): Promise<number[]>;
|
|
7
|
+
}
|
|
8
|
+
export declare const mlxService: MLXService;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { exec } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import * as fs from "node:fs";
|
|
4
|
+
import * as path from "node:path";
|
|
5
|
+
import { Logger } from "./logger.js";
|
|
6
|
+
const execAsync = promisify(exec);
|
|
7
|
+
export const DEFAULT_MLX_MODEL = "sentence-transformers/all-MiniLM-L6-v2";
|
|
8
|
+
export class MLXService {
|
|
9
|
+
isAvailable = null;
|
|
10
|
+
async checkAvailability() {
|
|
11
|
+
if (this.isAvailable !== null)
|
|
12
|
+
return this.isAvailable;
|
|
13
|
+
try {
|
|
14
|
+
await execAsync('python3 -c "import mlx.core; import sentence_transformers"');
|
|
15
|
+
this.isAvailable = true;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
this.isAvailable = false;
|
|
19
|
+
}
|
|
20
|
+
return this.isAvailable;
|
|
21
|
+
}
|
|
22
|
+
async setup() {
|
|
23
|
+
try {
|
|
24
|
+
Logger.log("MLX", "Setting up MLX dependencies...");
|
|
25
|
+
await execAsync("pip3 install mlx sentence-transformers huggingface_hub");
|
|
26
|
+
this.isAvailable = true;
|
|
27
|
+
return "MLX and sentence-transformers installed successfully.";
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new Error(`MLX setup failed: ${error.message}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async getEmbedding(text, model = DEFAULT_MLX_MODEL) {
|
|
34
|
+
if (!text || !text.trim())
|
|
35
|
+
return [];
|
|
36
|
+
// Escape text for python string
|
|
37
|
+
const escapedText = text.replace(/"/g, '\\"').replace(/\n/g, ' ');
|
|
38
|
+
// MLX optimized sentence-transformers execution
|
|
39
|
+
const pyScript = "\nimport mlx.core as mx\nfrom sentence_transformers import SentenceTransformer\nimport json\nimport sys\n\ntry:\n model = SentenceTransformer(\"${model}\")\n # Move to GPU if available (MLX default)\n embeddings = model.encode([\"${escapedText}\"])\n print(json.dumps(embeddings[0].tolist()))\nexcept Exception as e:\n print(json.dumps({\"error\": str(e)}))\n sys.exit(1)\n";
|
|
40
|
+
try {
|
|
41
|
+
const { stdout } = await execAsync(`python3 -c '${pyScript}'`);
|
|
42
|
+
const result = JSON.parse(stdout);
|
|
43
|
+
if (result.error)
|
|
44
|
+
throw new Error(result.error);
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
Logger.log("MLX", "Embedding failed", error);
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export const mlxService = new MLXService();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface PolicyViolation {
|
|
2
|
+
file: string;
|
|
3
|
+
line: number;
|
|
4
|
+
message: string;
|
|
5
|
+
severity: "error" | "warning";
|
|
6
|
+
}
|
|
7
|
+
export declare class PolicyEngine {
|
|
8
|
+
private rules;
|
|
9
|
+
checkContent(file: string, content: string): PolicyViolation[];
|
|
10
|
+
checkDiff(diff: string): PolicyViolation[];
|
|
11
|
+
}
|
|
12
|
+
export declare const policyEngine: PolicyEngine;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import * as fsSync from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { Logger } from "./logger.js";
|
|
4
|
+
export class PolicyEngine {
|
|
5
|
+
rules = [
|
|
6
|
+
{
|
|
7
|
+
name: "No Debug Logs",
|
|
8
|
+
pattern: /console\.(log|debug|info)\(/,
|
|
9
|
+
message: "Direct console logging is forbidden in production code.",
|
|
10
|
+
severity: "error"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: "No TODO Debt",
|
|
14
|
+
pattern: /\/\/\s*TODO/,
|
|
15
|
+
message: "New TODOs must be linked to a ticket ID.",
|
|
16
|
+
severity: "warning"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: "Forbidden Eval",
|
|
20
|
+
pattern: /eval\(/,
|
|
21
|
+
message: "Use of 'eval' is strictly forbidden for security reasons.",
|
|
22
|
+
severity: "error"
|
|
23
|
+
}
|
|
24
|
+
];
|
|
25
|
+
checkContent(file, content) {
|
|
26
|
+
const violations = [];
|
|
27
|
+
const lines = content.split('\n');
|
|
28
|
+
for (const rule of this.rules) {
|
|
29
|
+
lines.forEach((line, index) => {
|
|
30
|
+
if (rule.pattern.test(line)) {
|
|
31
|
+
violations.push({
|
|
32
|
+
file,
|
|
33
|
+
line: index + 1,
|
|
34
|
+
message: rule.message,
|
|
35
|
+
severity: rule.severity
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return violations;
|
|
41
|
+
}
|
|
42
|
+
checkDiff(diff) {
|
|
43
|
+
// Check only added lines in diffs
|
|
44
|
+
const addedLines = diff.split('\n').filter(l => l.startsWith('+') && !l.startsWith('+++'));
|
|
45
|
+
const violations = [];
|
|
46
|
+
for (const rule of this.rules) {
|
|
47
|
+
if (rule.pattern.test(addedLines.join('\n'))) {
|
|
48
|
+
violations.push({
|
|
49
|
+
file: "diff",
|
|
50
|
+
line: 0,
|
|
51
|
+
message: `[Policy: ${rule.name}] ${rule.message}`,
|
|
52
|
+
severity: rule.severity
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return violations;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export const policyEngine = new PolicyEngine();
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare class TUIService {
|
|
2
|
+
private client;
|
|
3
|
+
setClient(client: any): void;
|
|
4
|
+
showProgress(title: string, progress: number, message: string): Promise<void>;
|
|
5
|
+
showSuccess(title: string, message: string): Promise<void>;
|
|
6
|
+
showError(title: string, message: string): Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare const tui: TUIService;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export class TUIService {
|
|
2
|
+
client;
|
|
3
|
+
setClient(client) {
|
|
4
|
+
this.client = client;
|
|
5
|
+
}
|
|
6
|
+
async showProgress(title, progress, message) {
|
|
7
|
+
if (!this.client)
|
|
8
|
+
return;
|
|
9
|
+
try {
|
|
10
|
+
await this.client.tui.showToast({
|
|
11
|
+
body: {
|
|
12
|
+
title: `[${progress}%] ${title}`,
|
|
13
|
+
message,
|
|
14
|
+
variant: "info"
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
// Ignore if TUI not available
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
async showSuccess(title, message) {
|
|
23
|
+
if (!this.client)
|
|
24
|
+
return;
|
|
25
|
+
try {
|
|
26
|
+
await this.client.tui.showToast({
|
|
27
|
+
body: { title, message, variant: "success" }
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
catch (e) { }
|
|
31
|
+
}
|
|
32
|
+
async showError(title, message) {
|
|
33
|
+
if (!this.client)
|
|
34
|
+
return;
|
|
35
|
+
try {
|
|
36
|
+
await this.client.tui.showToast({
|
|
37
|
+
body: { title, message, variant: "error" }
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
catch (e) { }
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export const tui = new TUIService();
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import chokidar, { FSWatcher } from "chokidar";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { indexFile } from "../performance-optimization.js";
|
|
4
|
+
import { Logger } from "./logger.js";
|
|
5
|
+
const PROJECT_ROOT = process.cwd();
|
|
6
|
+
export class CodeWatcher {
|
|
7
|
+
watcher = null;
|
|
8
|
+
start() {
|
|
9
|
+
if (this.watcher)
|
|
10
|
+
return;
|
|
11
|
+
Logger.log("Watcher", "Starting live codebase watcher...");
|
|
12
|
+
this.watcher = chokidar.watch(PROJECT_ROOT, {
|
|
13
|
+
ignored: [
|
|
14
|
+
"**/node_modules/**",
|
|
15
|
+
"**/dist/**",
|
|
16
|
+
"**/build/**",
|
|
17
|
+
"**/.opencode/**"
|
|
18
|
+
],
|
|
19
|
+
persistent: true,
|
|
20
|
+
ignoreInitial: true
|
|
21
|
+
});
|
|
22
|
+
this.watcher
|
|
23
|
+
.on("add", (filePath) => this.handleFileChange("added", filePath))
|
|
24
|
+
.on("change", (filePath) => this.handleFileChange("changed", filePath))
|
|
25
|
+
.on("unlink", (filePath) => this.handleFileDelete(filePath));
|
|
26
|
+
}
|
|
27
|
+
stop() {
|
|
28
|
+
if (this.watcher) {
|
|
29
|
+
this.watcher.close();
|
|
30
|
+
this.watcher = null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async handleFileChange(event, filePath) {
|
|
34
|
+
const ext = path.extname(filePath);
|
|
35
|
+
const supportedExts = [".ts", ".js", ".tsx", ".jsx", ".cpp", ".c", ".h", ".hpp", ".swift", ".py", ".go", ".rs"];
|
|
36
|
+
if (supportedExts.includes(ext)) {
|
|
37
|
+
Logger.log("Watcher", `File ${event}: ${filePath}`);
|
|
38
|
+
try {
|
|
39
|
+
await indexFile(filePath);
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
Logger.log("Watcher", `Failed to index ${filePath}`, e);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
handleFileDelete(filePath) {
|
|
47
|
+
Logger.log("Watcher", `File deleted: ${filePath}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export const codeWatcher = new CodeWatcher();
|
package/dist/system-tools.js
CHANGED
|
@@ -7,6 +7,7 @@ import { promisify } from "node:util";
|
|
|
7
7
|
import * as crypto from "node:crypto";
|
|
8
8
|
import { Logger } from "./services/logger.js";
|
|
9
9
|
import { getDb } from "./database.js";
|
|
10
|
+
import { tui } from "./services/tui.js";
|
|
10
11
|
const execAsync = promisify(exec);
|
|
11
12
|
const PROJECT_ROOT = process.cwd();
|
|
12
13
|
const OPENCODE_DIR = path.join(PROJECT_ROOT, ".opencode");
|
|
@@ -305,10 +306,12 @@ export function systemTools() {
|
|
|
305
306
|
// Spawn background worker
|
|
306
307
|
(async () => {
|
|
307
308
|
getDb().updateJob(jobId, { status: "running", progress: 10 });
|
|
309
|
+
await tui.showProgress("Patch Validation", 10, "Creating temporary worktree...");
|
|
308
310
|
const tempWorktree = path.join(PROJECT_ROOT, ".opencode", "temp-" + jobId);
|
|
309
311
|
try {
|
|
310
312
|
await runCmd(`git worktree add -d "${tempWorktree}"`);
|
|
311
313
|
getDb().updateJob(jobId, { progress: 30 });
|
|
314
|
+
await tui.showProgress("Patch Validation", 30, "Applying diff...");
|
|
312
315
|
const content = await fs.readFile(patch_path, "utf-8");
|
|
313
316
|
const parts = content.split('\n\n');
|
|
314
317
|
const diffOnly = parts.length > 1 ? parts.slice(1).join('\n\n') : content;
|
|
@@ -318,6 +321,7 @@ export function systemTools() {
|
|
|
318
321
|
if (applyError)
|
|
319
322
|
throw new Error(`Apply failed: ${applyError.message}`);
|
|
320
323
|
getDb().updateJob(jobId, { progress: 60 });
|
|
324
|
+
await tui.showProgress("Patch Validation", 60, "Running build verification...");
|
|
321
325
|
let buildStatus = "SKIPPED";
|
|
322
326
|
if (fsSync.existsSync(path.join(tempWorktree, "package.json"))) {
|
|
323
327
|
const { error: buildError } = await runCmd("npm run build", tempWorktree);
|
|
@@ -332,9 +336,11 @@ export function systemTools() {
|
|
|
332
336
|
progress: 100,
|
|
333
337
|
result: JSON.stringify({ apply: "OK", build: buildStatus })
|
|
334
338
|
});
|
|
339
|
+
await tui.showSuccess("Validation Complete", `Apply: OK, Build: ${buildStatus}`);
|
|
335
340
|
}
|
|
336
341
|
catch (error) {
|
|
337
342
|
getDb().updateJob(jobId, { status: "failed", error: error.message });
|
|
343
|
+
await tui.showError("Validation Failed", error.message);
|
|
338
344
|
}
|
|
339
345
|
finally {
|
|
340
346
|
try {
|