Skip to content

Commit 0c37cc4

Browse files
refactor storage code to fix fundamental errors
1 parent ab1b1c4 commit 0c37cc4

File tree

2 files changed

+115
-89
lines changed

2 files changed

+115
-89
lines changed

dist/index.js

Lines changed: 33 additions & 33 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/storage.ts

Lines changed: 82 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,43 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
3-
import type { AnalysisResult } from "./analysis";
43

5-
// Best-effort write; failures are non-fatal and only logged to stderr.
6-
export function saveArtifact(issueNumber: number, name: string, contents = ''): void {
7-
try {
8-
const artifactsDir = path.join(process.cwd(), 'artifacts');
9-
const filePath = path.join(artifactsDir, `${issueNumber}-${name}`);
10-
fs.mkdirSync(artifactsDir, { recursive: true });
11-
fs.writeFileSync(filePath, contents, 'utf8');
12-
} catch (err) {
13-
const message = err instanceof Error ? err.message : String(err);
14-
console.error(`⚠️ Failed to save artifact ${name} for #${issueNumber}: ${message}`);
15-
}
4+
export interface TriageDbEntry {
5+
lastTriaged?: string; // ISO timestamp of when triage was completed
6+
thoughts?: string; // Raw model "thoughts" / chain-of-thought output
7+
summary?: string; // One-line summary from analysis
168
}
179

10+
export type TriageDb = Record<string, TriageDbEntry>;
11+
1812
export function loadDatabase(dbPath?: string): TriageDb {
1913
if (!dbPath) return {};
14+
2015
try {
2116
if (!fs.existsSync(dbPath)) return {};
17+
2218
const contents = fs.readFileSync(dbPath, 'utf8');
2319
const db = contents ? JSON.parse(contents) : {};
2420
console.info(`📊 Loaded ${dbPath} with ${Object.keys(db).length} entries`);
2521
return db;
2622
} catch (err) {
27-
const message = err instanceof Error ? err.message : String(err);
23+
const message = getErrorMessage(err);
2824
console.error(`⚠️ Failed to load ${dbPath}: ${message}. Starting with empty database.`);
2925
return {};
3026
}
3127
}
3228

3329
export function saveDatabase(db: TriageDb, dbPath?: string, enabled?: boolean): void {
3430
if (!dbPath || !enabled) return;
31+
3532
try {
3633
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
3734
fs.writeFileSync(dbPath, JSON.stringify(db, null, 2));
3835
} catch (err) {
39-
const message = err instanceof Error ? err.message : String(err);
36+
const message = getErrorMessage(err);
4037
console.error(`⚠️ Failed to save ${dbPath}: ${message}`);
4138
}
4239
}
4340

44-
export type TriageDb = Record<string, TriageDbEntry>;
45-
46-
export interface TriageDbEntry {
47-
lastTriaged?: string;
48-
thoughts?: string;
49-
summary?: string;
50-
}
51-
5241
export function getDbEntry(db: TriageDb, issueNumber: number): TriageDbEntry {
5342
return db[String(issueNumber)] || {};
5443
}
@@ -57,59 +46,96 @@ export function updateDbEntry(
5746
db: TriageDb,
5847
issueNumber: number,
5948
summary: string,
60-
thoughts: string,
49+
thoughts: string
6150
): void {
6251
const key = String(issueNumber);
63-
const existing: TriageDbEntry | undefined = db[key];
64-
const entry: TriageDbEntry = {
65-
...existing,
66-
summary,
67-
thoughts,
68-
lastTriaged: new Date().toISOString(),
69-
};
52+
const existing = db[key] || {};
53+
const entry: TriageDbEntry = { ...existing };
54+
55+
entry.summary = summary;
56+
entry.thoughts = thoughts;
57+
entry.lastTriaged = new Date().toISOString();
58+
7059
db[key] = entry;
7160
}
7261

73-
export type Config = {
74-
owner: string;
75-
repo: string;
76-
token: string;
77-
geminiApiKey: string;
78-
modelTemperature: number;
79-
enabled: boolean;
80-
thinkingBudget: number;
81-
issueNumber?: number;
82-
issueNumbers?: number[];
83-
promptPath: string;
84-
readmePath: string;
85-
dbPath?: string;
86-
modelFast: string;
87-
modelPro: string;
88-
maxTimelineEvents: number;
89-
maxTriages: number;
90-
};
62+
function getErrorMessage(error: unknown): string {
63+
return error instanceof Error ? error.message : String(error);
64+
}
65+
66+
export function saveArtifact(issueNumber: number, name: string, contents: string): void {
67+
try {
68+
const artifactsDir = path.join(process.cwd(), 'artifacts');
69+
const fileName = `${issueNumber}-${name}`;
70+
const filePath = path.join(artifactsDir, fileName);
71+
72+
fs.mkdirSync(artifactsDir, { recursive: true });
73+
fs.writeFileSync(filePath, contents, 'utf8');
74+
} catch (err) {
75+
const message = getErrorMessage(err);
76+
console.error(`⚠️ Failed to save artifact ${name} for #${issueNumber}: ${message}`);
77+
}
78+
}
9179

9280
export function loadReadme(readmePath?: string): string {
9381
if (!readmePath) return '';
82+
9483
try {
95-
const resolved = path.isAbsolute(readmePath) ? readmePath : path.join(process.cwd(), readmePath);
84+
const resolved = path.isAbsolute(readmePath)
85+
? readmePath
86+
: path.join(process.cwd(), readmePath);
87+
9688
if (!fs.existsSync(resolved)) return '';
9789
return fs.readFileSync(resolved, 'utf8');
9890
} catch (err) {
99-
const message = err instanceof Error ? err.message : String(err);
100-
console.warn(`Warning: failed to read README at '${readmePath}': ${message}`);
91+
const message = getErrorMessage(err);
92+
console.warn(`⚠️ Failed to read README at '${readmePath}': ${message}`);
10193
return '';
10294
}
10395
}
10496

10597
export function loadPrompt(promptPath: string): string {
98+
if (!promptPath) {
99+
throw new Error('Prompt path is required');
100+
}
101+
106102
try {
107-
// If a prompt path is provided, try to load it
108-
const resolvedPath = path.isAbsolute(promptPath) ? promptPath : path.join(process.cwd(), promptPath);
103+
// Try custom prompt path first
104+
const resolvedPath = path.isAbsolute(promptPath)
105+
? promptPath
106+
: path.join(process.cwd(), promptPath);
109107
return fs.readFileSync(resolvedPath, 'utf8');
110108
} catch (error) {
111-
// If custom prompt file doesn't exist, fall through to bundled default
112-
const bundledPath = path.join(__dirname, 'AutoTriage.prompt');
113-
return fs.readFileSync(bundledPath, 'utf8');
109+
// Fall back to bundled default prompt
110+
try {
111+
const bundledPath = path.join(__dirname, 'AutoTriage.prompt');
112+
return fs.readFileSync(bundledPath, 'utf8');
113+
} catch (bundledError) {
114+
const customMessage = getErrorMessage(error);
115+
const bundledMessage = getErrorMessage(bundledError);
116+
throw new Error(
117+
`Failed to load prompt. Custom path '${promptPath}': ${customMessage}. ` +
118+
`Bundled fallback: ${bundledMessage}`
119+
);
120+
}
114121
}
115122
}
123+
124+
export interface Config {
125+
owner: string;
126+
repo: string;
127+
token: string;
128+
geminiApiKey: string;
129+
modelTemperature: number;
130+
enabled: boolean;
131+
thinkingBudget: number;
132+
issueNumber?: number;
133+
issueNumbers?: number[];
134+
promptPath: string;
135+
readmePath: string;
136+
dbPath?: string;
137+
modelFast: string;
138+
modelPro: string;
139+
maxTimelineEvents: number;
140+
maxTriages: number;
141+
}

0 commit comments

Comments
 (0)