heyiam 0.1.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/app/dist/assets/index-BGQkmy7q.css +1 -0
- package/app/dist/assets/index-CbLHxerW.js +14 -0
- package/app/dist/favicon.svg +1 -0
- package/app/dist/icons.svg +24 -0
- package/app/dist/index.html +20 -0
- package/dist/analyzer.d.ts +96 -0
- package/dist/analyzer.js +249 -0
- package/dist/analyzer.js.map +1 -0
- package/dist/auth.d.ts +34 -0
- package/dist/auth.js +99 -0
- package/dist/auth.js.map +1 -0
- package/dist/bridge.d.ts +32 -0
- package/dist/bridge.js +211 -0
- package/dist/bridge.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +5 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +129 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/anthropic-provider.d.ts +11 -0
- package/dist/llm/anthropic-provider.js +16 -0
- package/dist/llm/anthropic-provider.js.map +1 -0
- package/dist/llm/index.d.ts +16 -0
- package/dist/llm/index.js +25 -0
- package/dist/llm/index.js.map +1 -0
- package/dist/llm/project-enhance.d.ts +71 -0
- package/dist/llm/project-enhance.js +236 -0
- package/dist/llm/project-enhance.js.map +1 -0
- package/dist/llm/proxy-provider.d.ts +16 -0
- package/dist/llm/proxy-provider.js +60 -0
- package/dist/llm/proxy-provider.js.map +1 -0
- package/dist/llm/triage.d.ts +66 -0
- package/dist/llm/triage.js +283 -0
- package/dist/llm/triage.js.map +1 -0
- package/dist/llm/types.d.ts +19 -0
- package/dist/llm/types.js +2 -0
- package/dist/llm/types.js.map +1 -0
- package/dist/machine-key.d.ts +10 -0
- package/dist/machine-key.js +51 -0
- package/dist/machine-key.js.map +1 -0
- package/dist/parsers/claude.d.ts +18 -0
- package/dist/parsers/claude.js +265 -0
- package/dist/parsers/claude.js.map +1 -0
- package/dist/parsers/index.d.ts +28 -0
- package/dist/parsers/index.js +124 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/types.d.ts +81 -0
- package/dist/parsers/types.js +2 -0
- package/dist/parsers/types.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +857 -0
- package/dist/server.js.map +1 -0
- package/dist/settings.d.ts +92 -0
- package/dist/settings.js +160 -0
- package/dist/settings.js.map +1 -0
- package/dist/summarize.d.ts +72 -0
- package/dist/summarize.js +312 -0
- package/dist/summarize.js.map +1 -0
- package/package.json +47 -0
package/dist/bridge.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// Bridge — converts parser output (SessionAnalysis from parsers/types.ts)
|
|
2
|
+
// into the analyzer's input format (SessionAnalysis from analyzer.ts)
|
|
3
|
+
import { analyzeSession } from "./analyzer.js";
|
|
4
|
+
import { parseSession } from "./parsers/index.js";
|
|
5
|
+
export function bridgeToAnalyzer(parsed, opts) {
|
|
6
|
+
const turns = entriesToTurns(parsed.raw_entries);
|
|
7
|
+
const filesChanged = computePerFileChanges(parsed.tool_calls);
|
|
8
|
+
const title = extractTitle(parsed.raw_entries);
|
|
9
|
+
const rawLog = extractRawLog(parsed.raw_entries);
|
|
10
|
+
const wallClockMinutes = parsed.wall_clock_ms > 0
|
|
11
|
+
? Math.max(1, Math.round(parsed.wall_clock_ms / 60_000))
|
|
12
|
+
: undefined;
|
|
13
|
+
return {
|
|
14
|
+
id: opts.sessionId,
|
|
15
|
+
title,
|
|
16
|
+
date: parsed.start_time ?? new Date().toISOString(),
|
|
17
|
+
...(parsed.end_time ? { endTime: parsed.end_time } : {}),
|
|
18
|
+
durationMinutes: parsed.duration_ms > 0
|
|
19
|
+
? Math.max(1, Math.round(parsed.duration_ms / 60_000))
|
|
20
|
+
: 0,
|
|
21
|
+
...(wallClockMinutes != null ? { wallClockMinutes } : {}),
|
|
22
|
+
projectName: opts.projectName,
|
|
23
|
+
turns,
|
|
24
|
+
filesChanged,
|
|
25
|
+
rawLog,
|
|
26
|
+
...(parsed.cwd ? { cwd: parsed.cwd } : {}),
|
|
27
|
+
...(opts.agentRole ? { agentRole: opts.agentRole } : {}),
|
|
28
|
+
...(opts.parentSessionId ? { parentSessionId: opts.parentSessionId } : {}),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function isToolUseBlock(block) {
|
|
32
|
+
return block.type === "tool_use";
|
|
33
|
+
}
|
|
34
|
+
function getContentBlocks(entry) {
|
|
35
|
+
const content = entry.message?.content;
|
|
36
|
+
if (!content || typeof content === "string")
|
|
37
|
+
return [];
|
|
38
|
+
return content;
|
|
39
|
+
}
|
|
40
|
+
function entriesToTurns(entries) {
|
|
41
|
+
const turns = [];
|
|
42
|
+
for (const entry of entries) {
|
|
43
|
+
if (entry.type === "user") {
|
|
44
|
+
const content = entry.message?.content;
|
|
45
|
+
if (typeof content === "string") {
|
|
46
|
+
turns.push({
|
|
47
|
+
timestamp: entry.timestamp,
|
|
48
|
+
type: "prompt",
|
|
49
|
+
content,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
// tool_result user entries are skipped — they're plumbing, not meaningful turns
|
|
53
|
+
}
|
|
54
|
+
else if (entry.type === "assistant") {
|
|
55
|
+
const blocks = getContentBlocks(entry);
|
|
56
|
+
for (const block of blocks) {
|
|
57
|
+
if (block.type === "text") {
|
|
58
|
+
turns.push({
|
|
59
|
+
timestamp: entry.timestamp,
|
|
60
|
+
type: "response",
|
|
61
|
+
content: block.text,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
else if (isToolUseBlock(block)) {
|
|
65
|
+
const toolInput = extractToolInput(block);
|
|
66
|
+
turns.push({
|
|
67
|
+
timestamp: entry.timestamp,
|
|
68
|
+
type: "tool",
|
|
69
|
+
content: `${block.name} ${toolInput ?? ""}`.trim(),
|
|
70
|
+
toolName: block.name,
|
|
71
|
+
toolInput,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return turns;
|
|
78
|
+
}
|
|
79
|
+
function extractToolInput(block) {
|
|
80
|
+
const input = block.input;
|
|
81
|
+
if (typeof input.file_path === "string")
|
|
82
|
+
return input.file_path;
|
|
83
|
+
if (typeof input.command === "string")
|
|
84
|
+
return input.command;
|
|
85
|
+
if (typeof input.pattern === "string")
|
|
86
|
+
return input.pattern;
|
|
87
|
+
if (typeof input.path === "string")
|
|
88
|
+
return input.path;
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
function computePerFileChanges(toolCalls) {
|
|
92
|
+
const files = new Map();
|
|
93
|
+
// Track writes for dedup (last write wins)
|
|
94
|
+
const writeLineCounts = new Map();
|
|
95
|
+
for (const call of toolCalls) {
|
|
96
|
+
if (call.name === "Write") {
|
|
97
|
+
const filePath = call.input.file_path;
|
|
98
|
+
const content = call.input.content;
|
|
99
|
+
if (typeof filePath !== "string" || typeof content !== "string")
|
|
100
|
+
continue;
|
|
101
|
+
const lines = content.split("\n").length;
|
|
102
|
+
const prev = writeLineCounts.get(filePath) ?? 0;
|
|
103
|
+
const existing = files.get(filePath) ?? { additions: 0, deletions: 0 };
|
|
104
|
+
if (writeLineCounts.has(filePath)) {
|
|
105
|
+
existing.additions = existing.additions - prev + lines;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
existing.additions += lines;
|
|
109
|
+
}
|
|
110
|
+
writeLineCounts.set(filePath, lines);
|
|
111
|
+
files.set(filePath, existing);
|
|
112
|
+
}
|
|
113
|
+
else if (call.name === "Edit") {
|
|
114
|
+
const filePath = call.input.file_path;
|
|
115
|
+
const oldStr = call.input.old_string;
|
|
116
|
+
const newStr = call.input.new_string;
|
|
117
|
+
if (typeof filePath !== "string")
|
|
118
|
+
continue;
|
|
119
|
+
const existing = files.get(filePath) ?? { additions: 0, deletions: 0 };
|
|
120
|
+
existing.additions += typeof newStr === "string" ? newStr.split("\n").length : 0;
|
|
121
|
+
existing.deletions += typeof oldStr === "string" ? oldStr.split("\n").length : 0;
|
|
122
|
+
files.set(filePath, existing);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return [...files.entries()]
|
|
126
|
+
.map(([path, stats]) => ({ path, ...stats }))
|
|
127
|
+
.sort((a, b) => a.path.localeCompare(b.path));
|
|
128
|
+
}
|
|
129
|
+
function extractTitle(entries) {
|
|
130
|
+
// Use the first user prompt as the title
|
|
131
|
+
for (const entry of entries) {
|
|
132
|
+
if (entry.type === "user") {
|
|
133
|
+
const content = entry.message?.content;
|
|
134
|
+
if (typeof content === "string" && content.trim().length > 0) {
|
|
135
|
+
const title = content.trim();
|
|
136
|
+
return title.length > 120 ? title.slice(0, 117) + "..." : title;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return "Untitled session";
|
|
141
|
+
}
|
|
142
|
+
function extractRawLog(entries) {
|
|
143
|
+
const log = [];
|
|
144
|
+
for (const entry of entries) {
|
|
145
|
+
if (entry.type === "user") {
|
|
146
|
+
const content = entry.message?.content;
|
|
147
|
+
if (typeof content === "string") {
|
|
148
|
+
log.push(`> ${content}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else if (entry.type === "assistant") {
|
|
152
|
+
const blocks = getContentBlocks(entry);
|
|
153
|
+
for (const block of blocks) {
|
|
154
|
+
if (block.type === "text") {
|
|
155
|
+
log.push(block.text);
|
|
156
|
+
}
|
|
157
|
+
else if (isToolUseBlock(block)) {
|
|
158
|
+
log.push(`[${block.name}] ${extractToolInput(block) ?? ""}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return log;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Deduplicate worktree clones: agents with same role and start time within
|
|
167
|
+
* 30 seconds are considered duplicates. Keep the one with more turns.
|
|
168
|
+
*/
|
|
169
|
+
export function deduplicateChildren(children) {
|
|
170
|
+
const seen = new Map();
|
|
171
|
+
for (const child of children) {
|
|
172
|
+
const startBucket = Math.floor(new Date(child.date).getTime() / 30_000);
|
|
173
|
+
const key = `${child.agentRole ?? 'agent'}::${startBucket}`;
|
|
174
|
+
const existing = seen.get(key);
|
|
175
|
+
if (!existing || child.turns > existing.turns) {
|
|
176
|
+
seen.set(key, child);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
return [...seen.values()];
|
|
180
|
+
}
|
|
181
|
+
/** Parse, bridge, and analyze each child session. Attaches results to parent. */
|
|
182
|
+
export async function bridgeChildSessions(parentMeta, projectName) {
|
|
183
|
+
if (!parentMeta.children || parentMeta.children.length === 0)
|
|
184
|
+
return [];
|
|
185
|
+
const results = [];
|
|
186
|
+
for (const child of parentMeta.children) {
|
|
187
|
+
try {
|
|
188
|
+
const parsed = await parseSession(child.path);
|
|
189
|
+
const input = bridgeToAnalyzer(parsed, {
|
|
190
|
+
sessionId: child.sessionId,
|
|
191
|
+
projectName,
|
|
192
|
+
agentRole: parsed.agent_role ?? child.agentRole,
|
|
193
|
+
parentSessionId: parentMeta.sessionId,
|
|
194
|
+
});
|
|
195
|
+
results.push(analyzeSession(input));
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// Skip children that fail to parse
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return deduplicateChildren(results);
|
|
202
|
+
}
|
|
203
|
+
/** Compute aggregated stats from fully-parsed child sessions. */
|
|
204
|
+
export function aggregateChildStats(children) {
|
|
205
|
+
return {
|
|
206
|
+
totalLoc: children.reduce((sum, c) => sum + c.linesOfCode, 0),
|
|
207
|
+
totalDurationMinutes: children.reduce((sum, c) => sum + c.durationMinutes, 0),
|
|
208
|
+
agentCount: children.length,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Base URL for the heyi.am Phoenix API. Set HEYIAM_API_URL in env for dev. */
|
|
2
|
+
export const API_URL = process.env.HEYIAM_API_URL ?? 'https://heyi.am';
|
|
3
|
+
/** Current enhancement mode: 'local' if ANTHROPIC_API_KEY is set, 'proxy' otherwise. */
|
|
4
|
+
export const ENHANCE_MODE = process.env.ANTHROPIC_API_KEY ? 'local' : 'proxy';
|
|
5
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,iBAAiB,CAAC;AAEvE,wFAAwF;AACxF,MAAM,CAAC,MAAM,YAAY,GAAsB,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { startServer } from './server.js';
|
|
4
|
+
import open from 'open';
|
|
5
|
+
import { checkAuthStatus, deviceAuthFlow, getAuthToken, deleteAuthToken, buildPublishPayload } from './auth.js';
|
|
6
|
+
import { loadOrCreateKeyPair, signPayload, getFingerprint } from './machine-key.js';
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name('heyiam')
|
|
10
|
+
.description('Turn AI coding sessions into portfolio case studies')
|
|
11
|
+
.version('0.1.0');
|
|
12
|
+
program
|
|
13
|
+
.command('open')
|
|
14
|
+
.description('Start the local server and open the browser')
|
|
15
|
+
.option('-p, --port <number>', 'Port to run on', '17845')
|
|
16
|
+
.option('--no-open', 'Start server without opening browser')
|
|
17
|
+
.action(async (opts) => {
|
|
18
|
+
const port = parseInt(opts.port, 10);
|
|
19
|
+
const server = await startServer(port);
|
|
20
|
+
const url = `http://localhost:${port}`;
|
|
21
|
+
console.log(`\nheyiam running at ${url}`);
|
|
22
|
+
console.log('Press Ctrl+C to stop\n');
|
|
23
|
+
if (opts.open) {
|
|
24
|
+
await open(url);
|
|
25
|
+
}
|
|
26
|
+
// Keep the process alive until Ctrl+C
|
|
27
|
+
const shutdown = () => {
|
|
28
|
+
console.log('\nShutting down...');
|
|
29
|
+
server.close(() => process.exit(0));
|
|
30
|
+
// Force exit after 3s if connections hang
|
|
31
|
+
setTimeout(() => process.exit(0), 3000);
|
|
32
|
+
};
|
|
33
|
+
process.on('SIGINT', shutdown);
|
|
34
|
+
process.on('SIGTERM', shutdown);
|
|
35
|
+
// Block forever — the event loop stays alive because the server is listening
|
|
36
|
+
await new Promise(() => { });
|
|
37
|
+
});
|
|
38
|
+
import { API_URL } from './config.js';
|
|
39
|
+
const API_BASE = API_URL;
|
|
40
|
+
program
|
|
41
|
+
.command('login')
|
|
42
|
+
.description('Authenticate with heyi.am')
|
|
43
|
+
.option('--api-url <url>', 'API base URL', API_BASE)
|
|
44
|
+
.action(async (opts) => {
|
|
45
|
+
const status = await checkAuthStatus(opts.apiUrl);
|
|
46
|
+
if (status.authenticated) {
|
|
47
|
+
console.log(`Already logged in as ${status.username}`);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
console.log('Starting device authorization...');
|
|
51
|
+
try {
|
|
52
|
+
const auth = await deviceAuthFlow(opts.apiUrl, undefined, {
|
|
53
|
+
openBrowser: (url) => open(url).then(() => { }),
|
|
54
|
+
onUserCode: (code, uri) => {
|
|
55
|
+
console.log(`\nOpen ${uri} and enter code: ${code}\n`);
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
console.log(`Logged in as ${auth.username}`);
|
|
59
|
+
}
|
|
60
|
+
catch (err) {
|
|
61
|
+
console.error(`Login failed: ${err.message}`);
|
|
62
|
+
process.exitCode = 1;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
program
|
|
66
|
+
.command('logout')
|
|
67
|
+
.description('Remove saved authentication credentials')
|
|
68
|
+
.action(() => {
|
|
69
|
+
deleteAuthToken();
|
|
70
|
+
console.log('Logged out. Run `heyiam login` to re-authenticate.');
|
|
71
|
+
});
|
|
72
|
+
program
|
|
73
|
+
.command('publish')
|
|
74
|
+
.description('Publish a session to heyi.am')
|
|
75
|
+
.option('--api-url <url>', 'API base URL', API_BASE)
|
|
76
|
+
.action(async (opts) => {
|
|
77
|
+
const auth = getAuthToken();
|
|
78
|
+
if (!auth) {
|
|
79
|
+
console.error('Not logged in. Run `heyiam login` first.');
|
|
80
|
+
process.exitCode = 1;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const keyPair = loadOrCreateKeyPair();
|
|
84
|
+
const fingerprint = getFingerprint(keyPair.publicKey);
|
|
85
|
+
console.log(`Using machine key: ${fingerprint}`);
|
|
86
|
+
// TODO: session data will come from the parser pipeline once Task 8.3+ are complete
|
|
87
|
+
const sessionData = { placeholder: true };
|
|
88
|
+
const payloadStr = JSON.stringify(sessionData);
|
|
89
|
+
const signature = signPayload(payloadStr, keyPair.privateKey);
|
|
90
|
+
const body = buildPublishPayload(sessionData, signature, keyPair.publicKey);
|
|
91
|
+
try {
|
|
92
|
+
const res = await fetch(`${opts.apiUrl}/api/shares`, {
|
|
93
|
+
method: 'POST',
|
|
94
|
+
headers: {
|
|
95
|
+
'Content-Type': 'application/json',
|
|
96
|
+
Authorization: `Bearer ${auth.token}`,
|
|
97
|
+
},
|
|
98
|
+
body: JSON.stringify(body),
|
|
99
|
+
});
|
|
100
|
+
if (!res.ok) {
|
|
101
|
+
const err = await res.text();
|
|
102
|
+
console.error(`Publish failed (${res.status}): ${err}`);
|
|
103
|
+
process.exitCode = 1;
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const result = (await res.json());
|
|
107
|
+
console.log(`Published! ${result.url ?? ''}`);
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
console.error(`Publish failed: ${err.message}`);
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
// Default to 'open' when no command is given
|
|
115
|
+
program.action(async () => {
|
|
116
|
+
await program.parseAsync(['', '', 'open']);
|
|
117
|
+
});
|
|
118
|
+
export { program };
|
|
119
|
+
// Only run if this is the entry point (not imported for testing).
|
|
120
|
+
// When installed via npm link, process.argv[1] is the symlink path
|
|
121
|
+
// (e.g., ~/.nvm/.../bin/heyiam), so we resolve it to check the real path.
|
|
122
|
+
import { realpathSync } from 'node:fs';
|
|
123
|
+
const resolvedArgv = process.argv[1] ? realpathSync(process.argv[1]) : '';
|
|
124
|
+
const isDirectRun = resolvedArgv.endsWith('/dist/index.js') ||
|
|
125
|
+
resolvedArgv.endsWith('/src/index.ts');
|
|
126
|
+
if (isDirectRun) {
|
|
127
|
+
program.parseAsync(process.argv);
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Session } from '../analyzer.js';
|
|
2
|
+
import type { EnhancementResult } from '../summarize.js';
|
|
3
|
+
import type { LLMProvider } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* BYOK provider — calls Anthropic SDK directly using the user's local API key.
|
|
6
|
+
* Reads from env var first, then falls back to ~/.config/heyiam/settings.json.
|
|
7
|
+
*/
|
|
8
|
+
export declare class AnthropicProvider implements LLMProvider {
|
|
9
|
+
name: "local";
|
|
10
|
+
enhance(session: Session): Promise<EnhancementResult>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import { summarizeSession } from '../summarize.js';
|
|
3
|
+
import { getAnthropicApiKey } from '../settings.js';
|
|
4
|
+
/**
|
|
5
|
+
* BYOK provider — calls Anthropic SDK directly using the user's local API key.
|
|
6
|
+
* Reads from env var first, then falls back to ~/.config/heyiam/settings.json.
|
|
7
|
+
*/
|
|
8
|
+
export class AnthropicProvider {
|
|
9
|
+
name = 'local';
|
|
10
|
+
async enhance(session) {
|
|
11
|
+
const apiKey = getAnthropicApiKey();
|
|
12
|
+
const client = apiKey ? new Anthropic({ apiKey }) : new Anthropic();
|
|
13
|
+
return summarizeSession(session, { client });
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=anthropic-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"anthropic-provider.js","sourceRoot":"","sources":["../../src/llm/anthropic-provider.ts"],"names":[],"mappings":"AAAA,OAAO,SAAS,MAAM,mBAAmB,CAAC;AAG1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEpD;;;GAGG;AACH,MAAM,OAAO,iBAAiB;IAC5B,IAAI,GAAG,OAAgB,CAAC;IAExB,KAAK,CAAC,OAAO,CAAC,OAAgB;QAC5B,MAAM,MAAM,GAAG,kBAAkB,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,SAAS,EAAE,CAAC;QACpE,OAAO,gBAAgB,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/C,CAAC;CACF"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { LLMProvider } from './types.js';
|
|
2
|
+
export type { LLMProvider } from './types.js';
|
|
3
|
+
export { ProxyError } from './proxy-provider.js';
|
|
4
|
+
/**
|
|
5
|
+
* Returns the appropriate LLM provider based on environment.
|
|
6
|
+
*
|
|
7
|
+
* Resolution priority:
|
|
8
|
+
* 1. If ANTHROPIC_API_KEY env var is set → AnthropicProvider (BYOK)
|
|
9
|
+
* 2. If API key saved in ~/.config/heyiam/settings.json → AnthropicProvider (BYOK)
|
|
10
|
+
* 3. Otherwise → ProxyProvider (server-side, requires auth)
|
|
11
|
+
*/
|
|
12
|
+
export declare function getProvider(): LLMProvider;
|
|
13
|
+
/**
|
|
14
|
+
* Returns the current enhancement mode for display purposes.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getEnhanceMode(): 'local' | 'proxy';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AnthropicProvider } from './anthropic-provider.js';
|
|
2
|
+
import { ProxyProvider } from './proxy-provider.js';
|
|
3
|
+
import { getAnthropicApiKey } from '../settings.js';
|
|
4
|
+
export { ProxyError } from './proxy-provider.js';
|
|
5
|
+
/**
|
|
6
|
+
* Returns the appropriate LLM provider based on environment.
|
|
7
|
+
*
|
|
8
|
+
* Resolution priority:
|
|
9
|
+
* 1. If ANTHROPIC_API_KEY env var is set → AnthropicProvider (BYOK)
|
|
10
|
+
* 2. If API key saved in ~/.config/heyiam/settings.json → AnthropicProvider (BYOK)
|
|
11
|
+
* 3. Otherwise → ProxyProvider (server-side, requires auth)
|
|
12
|
+
*/
|
|
13
|
+
export function getProvider() {
|
|
14
|
+
if (getAnthropicApiKey()) {
|
|
15
|
+
return new AnthropicProvider();
|
|
16
|
+
}
|
|
17
|
+
return new ProxyProvider();
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Returns the current enhancement mode for display purposes.
|
|
21
|
+
*/
|
|
22
|
+
export function getEnhanceMode() {
|
|
23
|
+
return getAnthropicApiKey() ? 'local' : 'proxy';
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/llm/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAGpD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW;IACzB,IAAI,kBAAkB,EAAE,EAAE,CAAC;QACzB,OAAO,IAAI,iBAAiB,EAAE,CAAC;IACjC,CAAC;IACD,OAAO,IAAI,aAAa,EAAE,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc;IAC5B,OAAO,kBAAkB,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
export interface SessionSummary {
|
|
2
|
+
sessionId: string;
|
|
3
|
+
title: string;
|
|
4
|
+
developerTake?: string;
|
|
5
|
+
skills: string[];
|
|
6
|
+
executionSteps: Array<{
|
|
7
|
+
title: string;
|
|
8
|
+
body: string;
|
|
9
|
+
}>;
|
|
10
|
+
keyDecisions?: string[];
|
|
11
|
+
duration: number;
|
|
12
|
+
loc: number;
|
|
13
|
+
turns: number;
|
|
14
|
+
files: number;
|
|
15
|
+
date: string;
|
|
16
|
+
correctionCount?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface SkippedSessionMeta {
|
|
19
|
+
title: string;
|
|
20
|
+
duration: number;
|
|
21
|
+
loc: number;
|
|
22
|
+
}
|
|
23
|
+
export interface ProjectQuestion {
|
|
24
|
+
id: string;
|
|
25
|
+
category: 'pattern' | 'architecture' | 'evolution';
|
|
26
|
+
question: string;
|
|
27
|
+
context: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ProjectEnhanceResult {
|
|
30
|
+
narrative: string;
|
|
31
|
+
arc: Array<{
|
|
32
|
+
phase: number;
|
|
33
|
+
title: string;
|
|
34
|
+
description: string;
|
|
35
|
+
}>;
|
|
36
|
+
skills: string[];
|
|
37
|
+
timeline: Array<{
|
|
38
|
+
period: string;
|
|
39
|
+
label: string;
|
|
40
|
+
sessions: Array<{
|
|
41
|
+
sessionId: string;
|
|
42
|
+
title: string;
|
|
43
|
+
featured: boolean;
|
|
44
|
+
tag?: string;
|
|
45
|
+
}>;
|
|
46
|
+
}>;
|
|
47
|
+
questions: ProjectQuestion[];
|
|
48
|
+
}
|
|
49
|
+
export interface RefinedNarrative {
|
|
50
|
+
narrative: string;
|
|
51
|
+
timeline: ProjectEnhanceResult['timeline'];
|
|
52
|
+
}
|
|
53
|
+
export type EnhanceProjectProgress = {
|
|
54
|
+
type: 'narrative_chunk';
|
|
55
|
+
text: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Generate a project narrative, arc, timeline, and context-aware questions
|
|
59
|
+
* from enhanced session summaries. Streams narrative chunks via onProgress
|
|
60
|
+
* as the LLM generates the response.
|
|
61
|
+
*/
|
|
62
|
+
export declare function enhanceProject(sessions: SessionSummary[], skippedSessions: SkippedSessionMeta[], onProgress?: (event: EnhanceProjectProgress) => void): Promise<ProjectEnhanceResult>;
|
|
63
|
+
/**
|
|
64
|
+
* Refine a project narrative by weaving in the developer's answers
|
|
65
|
+
* to context-aware questions.
|
|
66
|
+
*/
|
|
67
|
+
export declare function refineNarrative(draftNarrative: string, draftTimeline: ProjectEnhanceResult['timeline'], answers: Array<{
|
|
68
|
+
questionId: string;
|
|
69
|
+
question: string;
|
|
70
|
+
answer: string;
|
|
71
|
+
}>): Promise<RefinedNarrative>;
|