recall-player 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.
- package/README.md +238 -0
- package/backend/dist/db/connection.d.ts +47 -0
- package/backend/dist/db/connection.d.ts.map +1 -0
- package/backend/dist/db/connection.js +88 -0
- package/backend/dist/db/connection.js.map +1 -0
- package/backend/dist/db/queries.d.ts +172 -0
- package/backend/dist/db/queries.d.ts.map +1 -0
- package/backend/dist/db/queries.js +436 -0
- package/backend/dist/db/queries.js.map +1 -0
- package/backend/dist/db/schema.d.ts +100 -0
- package/backend/dist/db/schema.d.ts.map +1 -0
- package/backend/dist/db/schema.js +6 -0
- package/backend/dist/db/schema.js.map +1 -0
- package/backend/dist/db/transcript-connection.d.ts +57 -0
- package/backend/dist/db/transcript-connection.d.ts.map +1 -0
- package/backend/dist/db/transcript-connection.js +112 -0
- package/backend/dist/db/transcript-connection.js.map +1 -0
- package/backend/dist/db/transcript-queries.d.ts +152 -0
- package/backend/dist/db/transcript-queries.d.ts.map +1 -0
- package/backend/dist/db/transcript-queries.js +706 -0
- package/backend/dist/db/transcript-queries.js.map +1 -0
- package/backend/dist/db/transcript-schema.d.ts +143 -0
- package/backend/dist/db/transcript-schema.d.ts.map +1 -0
- package/backend/dist/db/transcript-schema.js +10 -0
- package/backend/dist/db/transcript-schema.js.map +1 -0
- package/backend/dist/index.d.ts +2 -0
- package/backend/dist/index.d.ts.map +1 -0
- package/backend/dist/index.js +96 -0
- package/backend/dist/index.js.map +1 -0
- package/backend/dist/parser/agent-detector.d.ts +76 -0
- package/backend/dist/parser/agent-detector.d.ts.map +1 -0
- package/backend/dist/parser/agent-detector.js +281 -0
- package/backend/dist/parser/agent-detector.js.map +1 -0
- package/backend/dist/parser/base-parser.d.ts +123 -0
- package/backend/dist/parser/base-parser.d.ts.map +1 -0
- package/backend/dist/parser/base-parser.js +364 -0
- package/backend/dist/parser/base-parser.js.map +1 -0
- package/backend/dist/parser/claude-parser.d.ts +78 -0
- package/backend/dist/parser/claude-parser.d.ts.map +1 -0
- package/backend/dist/parser/claude-parser.js +247 -0
- package/backend/dist/parser/claude-parser.js.map +1 -0
- package/backend/dist/parser/codex-parser.d.ts +128 -0
- package/backend/dist/parser/codex-parser.d.ts.map +1 -0
- package/backend/dist/parser/codex-parser.js +371 -0
- package/backend/dist/parser/codex-parser.js.map +1 -0
- package/backend/dist/parser/gemini-parser.d.ts +107 -0
- package/backend/dist/parser/gemini-parser.d.ts.map +1 -0
- package/backend/dist/parser/gemini-parser.js +360 -0
- package/backend/dist/parser/gemini-parser.js.map +1 -0
- package/backend/dist/parser/parser-factory.d.ts +83 -0
- package/backend/dist/parser/parser-factory.d.ts.map +1 -0
- package/backend/dist/parser/parser-factory.js +163 -0
- package/backend/dist/parser/parser-factory.js.map +1 -0
- package/backend/dist/parser/session-indexer.d.ts +79 -0
- package/backend/dist/parser/session-indexer.d.ts.map +1 -0
- package/backend/dist/parser/session-indexer.js +558 -0
- package/backend/dist/parser/session-indexer.js.map +1 -0
- package/backend/dist/parser/timeline-builder.d.ts +7 -0
- package/backend/dist/parser/timeline-builder.d.ts.map +1 -0
- package/backend/dist/parser/timeline-builder.js +334 -0
- package/backend/dist/parser/timeline-builder.js.map +1 -0
- package/backend/dist/parser/transcript-parser.d.ts +25 -0
- package/backend/dist/parser/transcript-parser.d.ts.map +1 -0
- package/backend/dist/parser/transcript-parser.js +137 -0
- package/backend/dist/parser/transcript-parser.js.map +1 -0
- package/backend/dist/routes/commentary.d.ts +33 -0
- package/backend/dist/routes/commentary.d.ts.map +1 -0
- package/backend/dist/routes/commentary.js +153 -0
- package/backend/dist/routes/commentary.js.map +1 -0
- package/backend/dist/routes/import.d.ts +3 -0
- package/backend/dist/routes/import.d.ts.map +1 -0
- package/backend/dist/routes/import.js +220 -0
- package/backend/dist/routes/import.js.map +1 -0
- package/backend/dist/routes/sessions.d.ts +3 -0
- package/backend/dist/routes/sessions.d.ts.map +1 -0
- package/backend/dist/routes/sessions.js +393 -0
- package/backend/dist/routes/sessions.js.map +1 -0
- package/backend/dist/server.d.ts +25 -0
- package/backend/dist/server.d.ts.map +1 -0
- package/backend/dist/server.js +110 -0
- package/backend/dist/server.js.map +1 -0
- package/backend/dist/services/example-import.d.ts +20 -0
- package/backend/dist/services/example-import.d.ts.map +1 -0
- package/backend/dist/services/example-import.js +93 -0
- package/backend/dist/services/example-import.js.map +1 -0
- package/backend/dist/services/file-watcher.d.ts +22 -0
- package/backend/dist/services/file-watcher.d.ts.map +1 -0
- package/backend/dist/services/file-watcher.js +141 -0
- package/backend/dist/services/file-watcher.js.map +1 -0
- package/backend/dist/services/import-cli.d.ts +11 -0
- package/backend/dist/services/import-cli.d.ts.map +1 -0
- package/backend/dist/services/import-cli.js +171 -0
- package/backend/dist/services/import-cli.js.map +1 -0
- package/backend/dist/services/transcript-importer.d.ts +98 -0
- package/backend/dist/services/transcript-importer.d.ts.map +1 -0
- package/backend/dist/services/transcript-importer.js +342 -0
- package/backend/dist/services/transcript-importer.js.map +1 -0
- package/backend/dist/types/transcript.d.ts +174 -0
- package/backend/dist/types/transcript.d.ts.map +1 -0
- package/backend/dist/types/transcript.js +8 -0
- package/backend/dist/types/transcript.js.map +1 -0
- package/backend/package.json +40 -0
- package/backend/public/.gitkeep +0 -0
- package/backend/public/assets/index-D8IP1zNL.css +1 -0
- package/backend/public/assets/index-GtkMiMqE.js +69 -0
- package/backend/public/index.html +14 -0
- package/bin/recall.js +43 -0
- package/package.json +54 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.queryClaudeMemDirect = queryClaudeMemDirect;
|
|
4
|
+
const express_1 = require("express");
|
|
5
|
+
const child_process_1 = require("child_process");
|
|
6
|
+
const util_1 = require("util");
|
|
7
|
+
const router = (0, express_1.Router)();
|
|
8
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
9
|
+
/**
|
|
10
|
+
* GET /api/sessions/:id/commentary
|
|
11
|
+
* Get claude-mem observations for a session mapped to timeline
|
|
12
|
+
*
|
|
13
|
+
* URL Parameters:
|
|
14
|
+
* - id: Session UUID
|
|
15
|
+
*
|
|
16
|
+
* Response:
|
|
17
|
+
* - commentary: Array of CommentaryBubble objects
|
|
18
|
+
* - total: Total number of observations
|
|
19
|
+
* - sessionId: The session ID
|
|
20
|
+
*
|
|
21
|
+
* Status Codes:
|
|
22
|
+
* - 200: Success
|
|
23
|
+
* - 500: Internal error
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* GET /api/sessions/4b198fdf-b80d-4bbc-806f-2900282cdc56/commentary
|
|
27
|
+
*/
|
|
28
|
+
router.get('/:id/commentary', async (req, res) => {
|
|
29
|
+
try {
|
|
30
|
+
const sessionId = req.params.id;
|
|
31
|
+
if (!sessionId) {
|
|
32
|
+
res.status(400).json({ error: 'Session ID is required' });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Query claude-mem for observations matching this session ID
|
|
36
|
+
const observations = await queryClaudeMemObservations(sessionId);
|
|
37
|
+
// Map observations to commentary bubbles
|
|
38
|
+
const commentary = observations.map((obs) => ({
|
|
39
|
+
id: obs.id,
|
|
40
|
+
timestamp: obs.timestamp,
|
|
41
|
+
type: obs.type,
|
|
42
|
+
title: obs.title,
|
|
43
|
+
content: obs.content,
|
|
44
|
+
metadata: obs.metadata,
|
|
45
|
+
}));
|
|
46
|
+
res.json({
|
|
47
|
+
commentary,
|
|
48
|
+
total: commentary.length,
|
|
49
|
+
sessionId,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
console.error('Error fetching commentary:', error);
|
|
54
|
+
res.status(500).json({
|
|
55
|
+
error: 'Failed to fetch commentary',
|
|
56
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
/**
|
|
61
|
+
* Query claude-mem MCP server for observations
|
|
62
|
+
* Uses the claude CLI with MCP integration
|
|
63
|
+
*/
|
|
64
|
+
async function queryClaudeMemObservations(sessionId) {
|
|
65
|
+
try {
|
|
66
|
+
// Use the claude-mem MCP search to find observations for this session
|
|
67
|
+
// The search command queries the claude-mem sqlite database
|
|
68
|
+
const query = JSON.stringify({
|
|
69
|
+
session_id: sessionId,
|
|
70
|
+
limit: 100,
|
|
71
|
+
});
|
|
72
|
+
// Execute search via MCP server
|
|
73
|
+
// Note: This assumes claude-mem MCP server is running and configured
|
|
74
|
+
const command = `claude mcp call claude-mem search '${query}'`;
|
|
75
|
+
const { stdout, stderr } = await execAsync(command);
|
|
76
|
+
if (stderr) {
|
|
77
|
+
console.warn('claude-mem search warning:', stderr);
|
|
78
|
+
}
|
|
79
|
+
// Parse the MCP response
|
|
80
|
+
const response = JSON.parse(stdout);
|
|
81
|
+
// Extract observations from the response
|
|
82
|
+
// The exact format depends on claude-mem's response structure
|
|
83
|
+
const observations = [];
|
|
84
|
+
if (response && response.results) {
|
|
85
|
+
for (const result of response.results) {
|
|
86
|
+
observations.push({
|
|
87
|
+
id: result.id,
|
|
88
|
+
timestamp: result.timestamp || Date.now(),
|
|
89
|
+
session_id: sessionId,
|
|
90
|
+
type: result.type || 'observation',
|
|
91
|
+
title: result.title || result.summary || 'Observation',
|
|
92
|
+
content: result.content || result.text || '',
|
|
93
|
+
metadata: result.metadata,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return observations;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
console.error('Error querying claude-mem:', error);
|
|
101
|
+
// Return empty array if claude-mem is not available
|
|
102
|
+
// This allows the app to work without claude-mem installed
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Alternative implementation using direct sqlite access
|
|
108
|
+
* This is a fallback if MCP server is not available
|
|
109
|
+
* Exported for potential future use or testing
|
|
110
|
+
*/
|
|
111
|
+
async function queryClaudeMemDirect(sessionId) {
|
|
112
|
+
try {
|
|
113
|
+
// Import better-sqlite3
|
|
114
|
+
const Database = require('better-sqlite3');
|
|
115
|
+
const os = require('os');
|
|
116
|
+
const path = require('path');
|
|
117
|
+
// claude-mem stores data in ~/.claude-mem/memory.db
|
|
118
|
+
const dbPath = path.join(os.homedir(), '.claude-mem', 'memory.db');
|
|
119
|
+
const db = new Database(dbPath, { readonly: true });
|
|
120
|
+
// Query observations for this session
|
|
121
|
+
const stmt = db.prepare(`
|
|
122
|
+
SELECT
|
|
123
|
+
id,
|
|
124
|
+
timestamp,
|
|
125
|
+
session_id,
|
|
126
|
+
type,
|
|
127
|
+
title,
|
|
128
|
+
content,
|
|
129
|
+
metadata
|
|
130
|
+
FROM observations
|
|
131
|
+
WHERE session_id = ?
|
|
132
|
+
ORDER BY timestamp ASC
|
|
133
|
+
`);
|
|
134
|
+
const rows = stmt.all(sessionId);
|
|
135
|
+
db.close();
|
|
136
|
+
// Map to MemObservation format
|
|
137
|
+
return rows.map((row) => ({
|
|
138
|
+
id: row.id,
|
|
139
|
+
timestamp: row.timestamp,
|
|
140
|
+
session_id: row.session_id,
|
|
141
|
+
type: row.type || 'observation',
|
|
142
|
+
title: row.title || 'Observation',
|
|
143
|
+
content: row.content || '',
|
|
144
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
|
|
145
|
+
}));
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
console.error('Error querying claude-mem database directly:', error);
|
|
149
|
+
return [];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
exports.default = router;
|
|
153
|
+
//# sourceMappingURL=commentary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commentary.js","sourceRoot":"","sources":["../../src/routes/commentary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import.d.ts","sourceRoot":"","sources":["../../src/routes/import.ts"],"names":[],"mappings":"AASA,QAAA,MAAM,MAAM,4CAAW,CAAC;AA6OxB,eAAe,MAAM,CAAC"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const express_1 = require("express");
|
|
4
|
+
const transcript_importer_1 = require("../services/transcript-importer");
|
|
5
|
+
const transcript_queries_1 = require("../db/transcript-queries");
|
|
6
|
+
const agent_detector_1 = require("../parser/agent-detector");
|
|
7
|
+
const router = (0, express_1.Router)();
|
|
8
|
+
/**
|
|
9
|
+
* Track current import job state
|
|
10
|
+
*/
|
|
11
|
+
let currentImportJob = {
|
|
12
|
+
status: 'idle',
|
|
13
|
+
totalSessions: 0,
|
|
14
|
+
completedSessions: 0,
|
|
15
|
+
failedSessions: 0,
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* POST /api/import/start
|
|
19
|
+
* Start a bulk import of transcript files
|
|
20
|
+
*
|
|
21
|
+
* Request Body:
|
|
22
|
+
* - sourcePath (string, optional): Path to scan for .jsonl files (default: ~/.claude/projects/)
|
|
23
|
+
* - parallel (number, optional): Number of parallel workers (default: 10)
|
|
24
|
+
* - skipExisting (boolean, optional): Skip already imported sessions (default: true)
|
|
25
|
+
*
|
|
26
|
+
* Response:
|
|
27
|
+
* - success: boolean
|
|
28
|
+
* - message: string
|
|
29
|
+
* - jobId: string (for tracking)
|
|
30
|
+
*
|
|
31
|
+
* Status Codes:
|
|
32
|
+
* - 202: Import job started
|
|
33
|
+
* - 400: Invalid request
|
|
34
|
+
* - 409: Import already in progress
|
|
35
|
+
* - 500: Internal error
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* POST /api/import/start
|
|
39
|
+
* {
|
|
40
|
+
* "parallel": 10,
|
|
41
|
+
* "skipExisting": true
|
|
42
|
+
* }
|
|
43
|
+
*/
|
|
44
|
+
router.post('/start', async (req, res) => {
|
|
45
|
+
try {
|
|
46
|
+
// Check if import is already running
|
|
47
|
+
if (currentImportJob.status === 'importing') {
|
|
48
|
+
res.status(409).json({
|
|
49
|
+
success: false,
|
|
50
|
+
error: 'Import already in progress',
|
|
51
|
+
currentJob: currentImportJob,
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
// Get config from request body
|
|
56
|
+
const { sourcePath, parallel = 10, skipExisting = true, } = req.body || {};
|
|
57
|
+
// Reset job state
|
|
58
|
+
currentImportJob = {
|
|
59
|
+
status: 'importing',
|
|
60
|
+
totalSessions: 0,
|
|
61
|
+
completedSessions: 0,
|
|
62
|
+
failedSessions: 0,
|
|
63
|
+
startedAt: new Date().toISOString(),
|
|
64
|
+
};
|
|
65
|
+
// Start import in background (don't await)
|
|
66
|
+
(0, transcript_importer_1.bulkImportTranscripts)({
|
|
67
|
+
sourcePath,
|
|
68
|
+
parallel,
|
|
69
|
+
skipExisting,
|
|
70
|
+
onProgress: (completed, total) => {
|
|
71
|
+
currentImportJob.totalSessions = total;
|
|
72
|
+
currentImportJob.completedSessions = completed;
|
|
73
|
+
},
|
|
74
|
+
})
|
|
75
|
+
.then((summary) => {
|
|
76
|
+
currentImportJob.status = 'completed';
|
|
77
|
+
currentImportJob.completedAt = new Date().toISOString();
|
|
78
|
+
currentImportJob.totalSessions = summary.totalFiles;
|
|
79
|
+
currentImportJob.completedSessions = summary.successful;
|
|
80
|
+
currentImportJob.failedSessions = summary.failed;
|
|
81
|
+
console.log(`[Import] Completed: ${summary.successful}/${summary.totalFiles} sessions`);
|
|
82
|
+
})
|
|
83
|
+
.catch((error) => {
|
|
84
|
+
currentImportJob.status = 'failed';
|
|
85
|
+
currentImportJob.completedAt = new Date().toISOString();
|
|
86
|
+
currentImportJob.errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
87
|
+
console.error('[Import] Failed:', error);
|
|
88
|
+
});
|
|
89
|
+
// Return immediately
|
|
90
|
+
res.status(202).json({
|
|
91
|
+
success: true,
|
|
92
|
+
message: 'Import job started',
|
|
93
|
+
job: currentImportJob,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
catch (error) {
|
|
97
|
+
console.error('Error starting import:', error);
|
|
98
|
+
res.status(500).json({
|
|
99
|
+
success: false,
|
|
100
|
+
error: 'Failed to start import',
|
|
101
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
/**
|
|
106
|
+
* GET /api/import/status
|
|
107
|
+
* Get current import job status
|
|
108
|
+
*
|
|
109
|
+
* Response:
|
|
110
|
+
* - status: 'idle' | 'importing' | 'completed' | 'failed'
|
|
111
|
+
* - totalSessions: number
|
|
112
|
+
* - completedSessions: number
|
|
113
|
+
* - failedSessions: number
|
|
114
|
+
* - currentSession?: string
|
|
115
|
+
* - startedAt?: string
|
|
116
|
+
* - completedAt?: string
|
|
117
|
+
* - errorMessage?: string
|
|
118
|
+
*
|
|
119
|
+
* Status Codes:
|
|
120
|
+
* - 200: Success
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* GET /api/import/status
|
|
124
|
+
*/
|
|
125
|
+
router.get('/status', (_req, res) => {
|
|
126
|
+
res.json(currentImportJob);
|
|
127
|
+
});
|
|
128
|
+
/**
|
|
129
|
+
* GET /api/import/stats
|
|
130
|
+
* Get database import statistics
|
|
131
|
+
*
|
|
132
|
+
* Response:
|
|
133
|
+
* - total: Total sessions in parsing_status table
|
|
134
|
+
* - pending: Number of pending imports
|
|
135
|
+
* - completed: Number of completed imports
|
|
136
|
+
* - failed: Number of failed imports
|
|
137
|
+
*
|
|
138
|
+
* Status Codes:
|
|
139
|
+
* - 200: Success
|
|
140
|
+
* - 500: Internal error
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* GET /api/import/stats
|
|
144
|
+
*/
|
|
145
|
+
router.get('/stats', (_req, res) => {
|
|
146
|
+
try {
|
|
147
|
+
const stats = (0, transcript_queries_1.getImportStats)();
|
|
148
|
+
res.json(stats);
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
console.error('Error fetching import stats:', error);
|
|
152
|
+
res.status(500).json({
|
|
153
|
+
error: 'Failed to fetch import stats',
|
|
154
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
/**
|
|
159
|
+
* POST /api/import/single
|
|
160
|
+
* Import a single transcript file
|
|
161
|
+
*
|
|
162
|
+
* Request Body:
|
|
163
|
+
* - filePath (string, required): Path to .jsonl file
|
|
164
|
+
* - agent (string, optional): Agent type ('claude', 'codex', 'gemini', 'unknown')
|
|
165
|
+
* If not specified, auto-detected from file path
|
|
166
|
+
*
|
|
167
|
+
* Response:
|
|
168
|
+
* - success: boolean
|
|
169
|
+
* - message: string
|
|
170
|
+
* - agent: string (detected or specified agent type)
|
|
171
|
+
*
|
|
172
|
+
* Status Codes:
|
|
173
|
+
* - 200: Import successful
|
|
174
|
+
* - 400: Invalid request
|
|
175
|
+
* - 500: Import failed
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* POST /api/import/single
|
|
179
|
+
* {
|
|
180
|
+
* "filePath": "/Users/fpirzada/.claude/projects/my-project/session.jsonl"
|
|
181
|
+
* }
|
|
182
|
+
*
|
|
183
|
+
* @example
|
|
184
|
+
* POST /api/import/single
|
|
185
|
+
* {
|
|
186
|
+
* "filePath": "/custom/path/session.jsonl",
|
|
187
|
+
* "agent": "codex"
|
|
188
|
+
* }
|
|
189
|
+
*/
|
|
190
|
+
router.post('/single', async (req, res) => {
|
|
191
|
+
try {
|
|
192
|
+
const { filePath, agent: specifiedAgent } = req.body || {};
|
|
193
|
+
if (!filePath || typeof filePath !== 'string') {
|
|
194
|
+
res.status(400).json({
|
|
195
|
+
success: false,
|
|
196
|
+
error: 'Missing required field: filePath',
|
|
197
|
+
});
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
// Determine agent type: use specified agent or auto-detect from path
|
|
201
|
+
const agent = specifiedAgent || (0, agent_detector_1.detectAgentFromPath)(filePath);
|
|
202
|
+
// Import the file
|
|
203
|
+
await (0, transcript_importer_1.importTranscript)(filePath, agent);
|
|
204
|
+
res.json({
|
|
205
|
+
success: true,
|
|
206
|
+
message: 'Transcript imported successfully',
|
|
207
|
+
agent,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
console.error('Error importing transcript:', error);
|
|
212
|
+
res.status(500).json({
|
|
213
|
+
success: false,
|
|
214
|
+
error: 'Failed to import transcript',
|
|
215
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
exports.default = router;
|
|
220
|
+
//# sourceMappingURL=import.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"import.js","sourceRoot":"","sources":["../../src/routes/import.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAUA,QAAA,MAAM,MAAM,4CAAW,CAAC;AAwaxB,eAAe,MAAM,CAAC"}
|