@hasna/recordings 0.1.6 → 0.1.7
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/cli/index.js +47 -25
- package/dist/db/database.d.ts.map +1 -1
- package/dist/db/recordings.d.ts.map +1 -1
- package/dist/index.js +30 -10
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/mcp/index.js +19 -8
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/config.test.ts +1 -1
- package/src/cli/index.ts +11 -8
- package/src/lib/config.ts +22 -5
- package/src/native/Recordings/Recordings/RecordingEngine.swift +1 -1
- package/src/native/Recordings/Recordings/VoiceShortcuts.swift +1 -1
- package/src/native/Recordings/build.sh +2 -2
- package/src/native/RecordingsHelper.swift +9 -2
package/dist/cli/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { Command } from "commander";
|
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
|
|
9
9
|
// src/lib/config.ts
|
|
10
|
-
import { existsSync, readFileSync } from "fs";
|
|
10
|
+
import { existsSync, readFileSync, mkdirSync, cpSync } from "fs";
|
|
11
11
|
import { join } from "path";
|
|
12
12
|
import { homedir } from "os";
|
|
13
13
|
var DEFAULT_CONFIG = {
|
|
@@ -65,7 +65,9 @@ function loadConfig(configPath) {
|
|
|
65
65
|
if (process.env.RECORDINGS_LANGUAGE) {
|
|
66
66
|
config.language = process.env.RECORDINGS_LANGUAGE;
|
|
67
67
|
}
|
|
68
|
-
if (process.env.
|
|
68
|
+
if (process.env.HASNA_RECORDINGS_DB_PATH) {
|
|
69
|
+
config.db_path = process.env.HASNA_RECORDINGS_DB_PATH;
|
|
70
|
+
} else if (process.env.RECORDINGS_DB_PATH) {
|
|
69
71
|
config.db_path = process.env.RECORDINGS_DB_PATH;
|
|
70
72
|
}
|
|
71
73
|
if (process.env.RECORDINGS_AUDIO_DIR) {
|
|
@@ -114,7 +116,16 @@ function getDataDir() {
|
|
|
114
116
|
break;
|
|
115
117
|
dir = parent;
|
|
116
118
|
}
|
|
117
|
-
|
|
119
|
+
const home = homedir();
|
|
120
|
+
const newDir = join(home, ".hasna", "recordings");
|
|
121
|
+
const oldDir = join(home, ".recordings");
|
|
122
|
+
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
123
|
+
try {
|
|
124
|
+
mkdirSync(join(home, ".hasna"), { recursive: true });
|
|
125
|
+
cpSync(oldDir, newDir, { recursive: true });
|
|
126
|
+
} catch {}
|
|
127
|
+
}
|
|
128
|
+
return newDir;
|
|
118
129
|
}
|
|
119
130
|
function loadSecretKey(keyName) {
|
|
120
131
|
const secretsPath = join(homedir(), ".secrets");
|
|
@@ -135,16 +146,16 @@ function loadSecretKey(keyName) {
|
|
|
135
146
|
return "";
|
|
136
147
|
}
|
|
137
148
|
function ensureDataDir(config) {
|
|
138
|
-
const { mkdirSync } = __require("fs");
|
|
139
|
-
|
|
149
|
+
const { mkdirSync: mkdirSync2 } = __require("fs");
|
|
150
|
+
mkdirSync2(config.audio_dir, { recursive: true });
|
|
140
151
|
const dbDir = config.db_path.substring(0, config.db_path.lastIndexOf("/"));
|
|
141
152
|
if (dbDir)
|
|
142
|
-
|
|
153
|
+
mkdirSync2(dbDir, { recursive: true });
|
|
143
154
|
}
|
|
144
155
|
|
|
145
156
|
// src/db/database.ts
|
|
146
157
|
import { Database } from "bun:sqlite";
|
|
147
|
-
import { mkdirSync } from "fs";
|
|
158
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
148
159
|
import { dirname } from "path";
|
|
149
160
|
var _db = null;
|
|
150
161
|
var MIGRATIONS = [
|
|
@@ -203,6 +214,12 @@ var MIGRATIONS = [
|
|
|
203
214
|
CREATE INDEX IF NOT EXISTS idx_recordings_created ON recordings(created_at);
|
|
204
215
|
CREATE INDEX IF NOT EXISTS idx_recordings_mode ON recordings(processing_mode);
|
|
205
216
|
CREATE INDEX IF NOT EXISTS idx_recording_tags_tag ON recording_tags(tag);
|
|
217
|
+
`,
|
|
218
|
+
`
|
|
219
|
+
ALTER TABLE recordings ADD COLUMN goal TEXT;
|
|
220
|
+
ALTER TABLE recordings ADD COLUMN role TEXT;
|
|
221
|
+
ALTER TABLE recordings ADD COLUMN task_list_id TEXT;
|
|
222
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (2);
|
|
206
223
|
`
|
|
207
224
|
];
|
|
208
225
|
function getDatabase(dbPath) {
|
|
@@ -210,7 +227,7 @@ function getDatabase(dbPath) {
|
|
|
210
227
|
return _db;
|
|
211
228
|
const path = dbPath || loadConfig().db_path;
|
|
212
229
|
const dir = dirname(path);
|
|
213
|
-
|
|
230
|
+
mkdirSync2(dir, { recursive: true });
|
|
214
231
|
_db = new Database(path, { create: true });
|
|
215
232
|
_db.run("PRAGMA journal_mode = WAL");
|
|
216
233
|
_db.run("PRAGMA busy_timeout = 5000");
|
|
@@ -249,6 +266,9 @@ function parseRow(row) {
|
|
|
249
266
|
agent_id: row["agent_id"] || null,
|
|
250
267
|
project_id: row["project_id"] || null,
|
|
251
268
|
session_id: row["session_id"] || null,
|
|
269
|
+
goal: row["goal"] || null,
|
|
270
|
+
role: row["role"] || null,
|
|
271
|
+
task_list_id: row["task_list_id"] || null,
|
|
252
272
|
metadata: JSON.parse(row["metadata"] || "{}"),
|
|
253
273
|
created_at: row["created_at"]
|
|
254
274
|
};
|
|
@@ -258,8 +278,8 @@ function createRecording(input, db) {
|
|
|
258
278
|
const id = crypto.randomUUID();
|
|
259
279
|
const tagsJson = JSON.stringify(input.tags || []);
|
|
260
280
|
const metadataJson = JSON.stringify(input.metadata || {});
|
|
261
|
-
d.query(`INSERT INTO recordings (id, audio_path, raw_text, processed_text, processing_mode, model_used, enhancement_model, duration_ms, language, tags, agent_id, project_id, session_id, metadata)
|
|
262
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.audio_path || null, input.raw_text, input.processed_text || null, input.processing_mode || "raw", input.model_used || "gpt-4o-mini-transcribe", input.enhancement_model || null, input.duration_ms || 0, input.language || null, tagsJson, input.agent_id || null, input.project_id || null, input.session_id || null, metadataJson);
|
|
281
|
+
d.query(`INSERT INTO recordings (id, audio_path, raw_text, processed_text, processing_mode, model_used, enhancement_model, duration_ms, language, tags, agent_id, project_id, session_id, goal, role, task_list_id, metadata)
|
|
282
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.audio_path || null, input.raw_text, input.processed_text || null, input.processing_mode || "raw", input.model_used || "gpt-4o-mini-transcribe", input.enhancement_model || null, input.duration_ms || 0, input.language || null, tagsJson, input.agent_id || null, input.project_id || null, input.session_id || null, input.goal || null, input.role || null, input.task_list_id || null, metadataJson);
|
|
263
283
|
if (input.tags && input.tags.length > 0) {
|
|
264
284
|
const insertTag = d.query("INSERT OR IGNORE INTO recording_tags (recording_id, tag) VALUES (?, ?)");
|
|
265
285
|
for (const tag of input.tags) {
|
|
@@ -925,12 +945,12 @@ program.command("projects").description("List registered projects").action(() =>
|
|
|
925
945
|
}
|
|
926
946
|
});
|
|
927
947
|
program.command("init").description("Initialize .recordings/ in current directory").action(() => {
|
|
928
|
-
const { mkdirSync:
|
|
948
|
+
const { mkdirSync: mkdirSync3, writeFileSync, existsSync: existsSync3 } = __require("fs");
|
|
929
949
|
const { join: join3 } = __require("path");
|
|
930
950
|
const dir = join3(process.cwd(), ".recordings");
|
|
931
951
|
const audioDir = join3(dir, "audio");
|
|
932
952
|
const configFile = join3(dir, "config.json");
|
|
933
|
-
|
|
953
|
+
mkdirSync3(audioDir, { recursive: true });
|
|
934
954
|
if (!existsSync3(configFile)) {
|
|
935
955
|
const defaultConf = {
|
|
936
956
|
transcription_model: "gpt-4o-mini-transcribe",
|
|
@@ -971,19 +991,21 @@ program.command("start").description("Launch the menu bar helper app (F5 to togg
|
|
|
971
991
|
const { homedir: getHome } = __require("os");
|
|
972
992
|
const { existsSync: fileExists } = __require("fs");
|
|
973
993
|
const home = getHome();
|
|
974
|
-
const appPath = pathJoin(home, ".recordings", "RecordingsHelper.app");
|
|
975
|
-
|
|
994
|
+
const appPath = pathJoin(home, ".hasna", "recordings", "RecordingsHelper.app");
|
|
995
|
+
const oldAppPath = pathJoin(home, ".recordings", "RecordingsHelper.app");
|
|
996
|
+
if (!fileExists(appPath) && !fileExists(oldAppPath)) {
|
|
976
997
|
console.error(chalk.red("RecordingsHelper.app not found. Run: recordings shortcut --install"));
|
|
977
998
|
process.exit(1);
|
|
978
999
|
}
|
|
1000
|
+
const resolvedAppPath = fileExists(appPath) ? appPath : oldAppPath;
|
|
979
1001
|
try {
|
|
980
1002
|
execSync("pkill -f RecordingsHelper", { stdio: "pipe" });
|
|
981
1003
|
} catch {}
|
|
982
|
-
execSync(`open "${
|
|
1004
|
+
execSync(`open "${resolvedAppPath}"`, { stdio: "pipe" });
|
|
983
1005
|
console.log(chalk.green("Recordings helper launched \u2014 press F5 to record"));
|
|
984
1006
|
if (opts.login) {
|
|
985
1007
|
try {
|
|
986
|
-
execSync(`osascript -e 'tell application "System Events" to make login item at end with properties {path:"${
|
|
1008
|
+
execSync(`osascript -e 'tell application "System Events" to make login item at end with properties {path:"${resolvedAppPath}", hidden:true}'`, { stdio: "pipe" });
|
|
987
1009
|
console.log(chalk.green("Added to Login Items \u2014 will start on boot"));
|
|
988
1010
|
} catch {
|
|
989
1011
|
console.log(chalk.yellow("Could not add to Login Items \u2014 add manually in System Settings > General > Login Items"));
|
|
@@ -1108,12 +1130,12 @@ Bye.`));
|
|
|
1108
1130
|
});
|
|
1109
1131
|
});
|
|
1110
1132
|
program.command("shortcut").description("Set up a global keyboard shortcut for recording (macOS)").option("--raycast", "Generate Raycast script command").option("--install", "Set up F5 global shortcut via macOS Services (no extra installs)").option("--karabiner", "Set up Fn key via Karabiner-Elements").option("--skhd", "Generate skhd hotkey config").option("--hammerspoon", "Generate Hammerspoon config").option("--script", "Just output the shell script path").action((opts) => {
|
|
1111
|
-
const { writeFileSync, mkdirSync:
|
|
1133
|
+
const { writeFileSync, mkdirSync: mkdirSync3, chmodSync, existsSync: fileExists } = __require("fs");
|
|
1112
1134
|
const { join: pathJoin } = __require("path");
|
|
1113
1135
|
const { homedir: getHome } = __require("os");
|
|
1114
1136
|
const home = getHome();
|
|
1115
|
-
const scriptDir = pathJoin(home, ".recordings");
|
|
1116
|
-
|
|
1137
|
+
const scriptDir = pathJoin(home, ".hasna", "recordings");
|
|
1138
|
+
mkdirSync3(scriptDir, { recursive: true });
|
|
1117
1139
|
const scriptPath = pathJoin(scriptDir, "record-toggle.sh");
|
|
1118
1140
|
const pidFile = pathJoin(scriptDir, ".recording.pid");
|
|
1119
1141
|
const recordingsBin = pathJoin(home, ".bun", "bin", "recordings");
|
|
@@ -1165,16 +1187,16 @@ fi
|
|
|
1165
1187
|
chmodSync(scriptPath, 493);
|
|
1166
1188
|
if (opts.install) {
|
|
1167
1189
|
const { execSync: exec } = __require("child_process");
|
|
1168
|
-
const appPath = pathJoin(home, ".recordings", "RecordingsHelper.app");
|
|
1190
|
+
const appPath = pathJoin(home, ".hasna", "recordings", "RecordingsHelper.app");
|
|
1169
1191
|
const srcSwift = pathJoin(__dirname, "..", "native", "RecordingsHelper.swift");
|
|
1170
1192
|
const distApp = pathJoin(__dirname, "..", "RecordingsHelper.app");
|
|
1171
1193
|
if (fileExists(pathJoin(distApp, "Contents", "MacOS", "RecordingsHelper"))) {
|
|
1172
1194
|
exec(`rm -rf "${appPath}" && cp -R "${distApp}" "${appPath}"`, { stdio: "pipe", shell: "/bin/bash" });
|
|
1173
1195
|
} else if (fileExists(srcSwift)) {
|
|
1174
1196
|
console.log(chalk.blue("Compiling native helper app..."));
|
|
1175
|
-
const appDir = pathJoin(home, ".recordings", "RecordingsHelper.app", "Contents", "MacOS");
|
|
1176
|
-
|
|
1177
|
-
const plistDir = pathJoin(home, ".recordings", "RecordingsHelper.app", "Contents");
|
|
1197
|
+
const appDir = pathJoin(home, ".hasna", "recordings", "RecordingsHelper.app", "Contents", "MacOS");
|
|
1198
|
+
mkdirSync3(appDir, { recursive: true });
|
|
1199
|
+
const plistDir = pathJoin(home, ".hasna", "recordings", "RecordingsHelper.app", "Contents");
|
|
1178
1200
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
1179
1201
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
1180
1202
|
<plist version="1.0"><dict>
|
|
@@ -1213,7 +1235,7 @@ Recordings helper installed and running!
|
|
|
1213
1235
|
}
|
|
1214
1236
|
if (opts.karabiner) {
|
|
1215
1237
|
const karabinerDir = pathJoin(home, ".config", "karabiner", "assets", "complex_modifications");
|
|
1216
|
-
|
|
1238
|
+
mkdirSync3(karabinerDir, { recursive: true });
|
|
1217
1239
|
const rule = {
|
|
1218
1240
|
title: "Recordings \u2014 Fn key to toggle recording",
|
|
1219
1241
|
rules: [
|
|
@@ -1253,7 +1275,7 @@ Recordings helper installed and running!
|
|
|
1253
1275
|
}
|
|
1254
1276
|
if (opts.raycast) {
|
|
1255
1277
|
const raycastDir = pathJoin(home, ".config", "raycast", "script-commands");
|
|
1256
|
-
|
|
1278
|
+
mkdirSync3(raycastDir, { recursive: true });
|
|
1257
1279
|
const raycastScript = `#!/bin/bash
|
|
1258
1280
|
|
|
1259
1281
|
# Required parameters:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AA2EtC,wBAAgB,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAkBrD;AAuBD,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC;AAED,wBAAgB,SAAS,IAAI,MAAM,CAElC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recordings.d.ts","sourceRoot":"","sources":["../../src/db/recordings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,KAAK,EACV,SAAS,EACT,oBAAoB,EACpB,eAAe,EAChB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"recordings.d.ts","sourceRoot":"","sources":["../../src/db/recordings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,OAAO,KAAK,EACV,SAAS,EACT,oBAAoB,EACpB,eAAe,EAChB,MAAM,mBAAmB,CAAC;AA0B3B,wBAAgB,eAAe,CAC7B,KAAK,EAAE,oBAAoB,EAC3B,EAAE,CAAC,EAAE,QAAQ,GACZ,SAAS,CAwCX;AAED,wBAAgB,YAAY,CAC1B,EAAE,EAAE,MAAM,EACV,EAAE,CAAC,EAAE,QAAQ,GACZ,SAAS,GAAG,IAAI,CAgBlB;AAED,wBAAgB,cAAc,CAC5B,MAAM,CAAC,EAAE,eAAe,EACxB,EAAE,CAAC,EAAE,QAAQ,GACZ,SAAS,EAAE,CAuDb;AAED,wBAAgB,eAAe,CAC7B,EAAE,EAAE,MAAM,EACV,EAAE,CAAC,EAAE,QAAQ,GACZ,OAAO,CAIT;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,eAAe,EACxB,EAAE,CAAC,EAAE,QAAQ,GACZ,SAAS,EAAE,CAEb;AAED,wBAAgB,iBAAiB,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,CA2CA"}
|
package/dist/index.js
CHANGED
|
@@ -31,11 +31,11 @@ class EnhancementError extends Error {
|
|
|
31
31
|
}
|
|
32
32
|
// src/db/database.ts
|
|
33
33
|
import { Database } from "bun:sqlite";
|
|
34
|
-
import { mkdirSync } from "fs";
|
|
34
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
35
35
|
import { dirname } from "path";
|
|
36
36
|
|
|
37
37
|
// src/lib/config.ts
|
|
38
|
-
import { existsSync, readFileSync } from "fs";
|
|
38
|
+
import { existsSync, readFileSync, mkdirSync, cpSync } from "fs";
|
|
39
39
|
import { join } from "path";
|
|
40
40
|
import { homedir } from "os";
|
|
41
41
|
var DEFAULT_CONFIG = {
|
|
@@ -93,7 +93,9 @@ function loadConfig(configPath) {
|
|
|
93
93
|
if (process.env.RECORDINGS_LANGUAGE) {
|
|
94
94
|
config.language = process.env.RECORDINGS_LANGUAGE;
|
|
95
95
|
}
|
|
96
|
-
if (process.env.
|
|
96
|
+
if (process.env.HASNA_RECORDINGS_DB_PATH) {
|
|
97
|
+
config.db_path = process.env.HASNA_RECORDINGS_DB_PATH;
|
|
98
|
+
} else if (process.env.RECORDINGS_DB_PATH) {
|
|
97
99
|
config.db_path = process.env.RECORDINGS_DB_PATH;
|
|
98
100
|
}
|
|
99
101
|
if (process.env.RECORDINGS_AUDIO_DIR) {
|
|
@@ -142,7 +144,16 @@ function getDataDir() {
|
|
|
142
144
|
break;
|
|
143
145
|
dir = parent;
|
|
144
146
|
}
|
|
145
|
-
|
|
147
|
+
const home = homedir();
|
|
148
|
+
const newDir = join(home, ".hasna", "recordings");
|
|
149
|
+
const oldDir = join(home, ".recordings");
|
|
150
|
+
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
151
|
+
try {
|
|
152
|
+
mkdirSync(join(home, ".hasna"), { recursive: true });
|
|
153
|
+
cpSync(oldDir, newDir, { recursive: true });
|
|
154
|
+
} catch {}
|
|
155
|
+
}
|
|
156
|
+
return newDir;
|
|
146
157
|
}
|
|
147
158
|
function loadSecretKey(keyName) {
|
|
148
159
|
const secretsPath = join(homedir(), ".secrets");
|
|
@@ -163,11 +174,11 @@ function loadSecretKey(keyName) {
|
|
|
163
174
|
return "";
|
|
164
175
|
}
|
|
165
176
|
function ensureDataDir(config) {
|
|
166
|
-
const { mkdirSync } = __require("fs");
|
|
167
|
-
|
|
177
|
+
const { mkdirSync: mkdirSync2 } = __require("fs");
|
|
178
|
+
mkdirSync2(config.audio_dir, { recursive: true });
|
|
168
179
|
const dbDir = config.db_path.substring(0, config.db_path.lastIndexOf("/"));
|
|
169
180
|
if (dbDir)
|
|
170
|
-
|
|
181
|
+
mkdirSync2(dbDir, { recursive: true });
|
|
171
182
|
}
|
|
172
183
|
|
|
173
184
|
// src/db/database.ts
|
|
@@ -228,6 +239,12 @@ var MIGRATIONS = [
|
|
|
228
239
|
CREATE INDEX IF NOT EXISTS idx_recordings_created ON recordings(created_at);
|
|
229
240
|
CREATE INDEX IF NOT EXISTS idx_recordings_mode ON recordings(processing_mode);
|
|
230
241
|
CREATE INDEX IF NOT EXISTS idx_recording_tags_tag ON recording_tags(tag);
|
|
242
|
+
`,
|
|
243
|
+
`
|
|
244
|
+
ALTER TABLE recordings ADD COLUMN goal TEXT;
|
|
245
|
+
ALTER TABLE recordings ADD COLUMN role TEXT;
|
|
246
|
+
ALTER TABLE recordings ADD COLUMN task_list_id TEXT;
|
|
247
|
+
INSERT OR IGNORE INTO _migrations (id) VALUES (2);
|
|
231
248
|
`
|
|
232
249
|
];
|
|
233
250
|
function getDatabase(dbPath) {
|
|
@@ -235,7 +252,7 @@ function getDatabase(dbPath) {
|
|
|
235
252
|
return _db;
|
|
236
253
|
const path = dbPath || loadConfig().db_path;
|
|
237
254
|
const dir = dirname(path);
|
|
238
|
-
|
|
255
|
+
mkdirSync2(dir, { recursive: true });
|
|
239
256
|
_db = new Database(path, { create: true });
|
|
240
257
|
_db.run("PRAGMA journal_mode = WAL");
|
|
241
258
|
_db.run("PRAGMA busy_timeout = 5000");
|
|
@@ -288,6 +305,9 @@ function parseRow(row) {
|
|
|
288
305
|
agent_id: row["agent_id"] || null,
|
|
289
306
|
project_id: row["project_id"] || null,
|
|
290
307
|
session_id: row["session_id"] || null,
|
|
308
|
+
goal: row["goal"] || null,
|
|
309
|
+
role: row["role"] || null,
|
|
310
|
+
task_list_id: row["task_list_id"] || null,
|
|
291
311
|
metadata: JSON.parse(row["metadata"] || "{}"),
|
|
292
312
|
created_at: row["created_at"]
|
|
293
313
|
};
|
|
@@ -297,8 +317,8 @@ function createRecording(input, db) {
|
|
|
297
317
|
const id = crypto.randomUUID();
|
|
298
318
|
const tagsJson = JSON.stringify(input.tags || []);
|
|
299
319
|
const metadataJson = JSON.stringify(input.metadata || {});
|
|
300
|
-
d.query(`INSERT INTO recordings (id, audio_path, raw_text, processed_text, processing_mode, model_used, enhancement_model, duration_ms, language, tags, agent_id, project_id, session_id, metadata)
|
|
301
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.audio_path || null, input.raw_text, input.processed_text || null, input.processing_mode || "raw", input.model_used || "gpt-4o-mini-transcribe", input.enhancement_model || null, input.duration_ms || 0, input.language || null, tagsJson, input.agent_id || null, input.project_id || null, input.session_id || null, metadataJson);
|
|
320
|
+
d.query(`INSERT INTO recordings (id, audio_path, raw_text, processed_text, processing_mode, model_used, enhancement_model, duration_ms, language, tags, agent_id, project_id, session_id, goal, role, task_list_id, metadata)
|
|
321
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.audio_path || null, input.raw_text, input.processed_text || null, input.processing_mode || "raw", input.model_used || "gpt-4o-mini-transcribe", input.enhancement_model || null, input.duration_ms || 0, input.language || null, tagsJson, input.agent_id || null, input.project_id || null, input.session_id || null, input.goal || null, input.role || null, input.task_list_id || null, metadataJson);
|
|
302
322
|
if (input.tags && input.tags.length > 0) {
|
|
303
323
|
const insertTag = d.query("INSERT OR IGNORE INTO recording_tags (recording_id, tag) VALUES (?, ?)");
|
|
304
324
|
for (const tag of input.tags) {
|
package/dist/lib/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,eAAO,MAAM,cAAc,EAAE,gBA0B5B,CAAC;AAEF,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,gBAAgB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D,eAAO,MAAM,cAAc,EAAE,gBA0B5B,CAAC;AAEF,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAqEhE;AAgBD,wBAAgB,UAAU,IAAI,MAAM,CA4BnC;AA0BD,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAU5D"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -3994,7 +3994,7 @@ var coerce = {
|
|
|
3994
3994
|
};
|
|
3995
3995
|
var NEVER = INVALID;
|
|
3996
3996
|
// src/lib/config.ts
|
|
3997
|
-
import { existsSync, readFileSync } from "fs";
|
|
3997
|
+
import { existsSync, readFileSync, mkdirSync, cpSync } from "fs";
|
|
3998
3998
|
import { join } from "path";
|
|
3999
3999
|
import { homedir } from "os";
|
|
4000
4000
|
var DEFAULT_CONFIG = {
|
|
@@ -4052,7 +4052,9 @@ function loadConfig(configPath) {
|
|
|
4052
4052
|
if (process.env.RECORDINGS_LANGUAGE) {
|
|
4053
4053
|
config.language = process.env.RECORDINGS_LANGUAGE;
|
|
4054
4054
|
}
|
|
4055
|
-
if (process.env.
|
|
4055
|
+
if (process.env.HASNA_RECORDINGS_DB_PATH) {
|
|
4056
|
+
config.db_path = process.env.HASNA_RECORDINGS_DB_PATH;
|
|
4057
|
+
} else if (process.env.RECORDINGS_DB_PATH) {
|
|
4056
4058
|
config.db_path = process.env.RECORDINGS_DB_PATH;
|
|
4057
4059
|
}
|
|
4058
4060
|
if (process.env.RECORDINGS_AUDIO_DIR) {
|
|
@@ -4101,7 +4103,16 @@ function getDataDir() {
|
|
|
4101
4103
|
break;
|
|
4102
4104
|
dir = parent;
|
|
4103
4105
|
}
|
|
4104
|
-
|
|
4106
|
+
const home = homedir();
|
|
4107
|
+
const newDir = join(home, ".hasna", "recordings");
|
|
4108
|
+
const oldDir = join(home, ".recordings");
|
|
4109
|
+
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
4110
|
+
try {
|
|
4111
|
+
mkdirSync(join(home, ".hasna"), { recursive: true });
|
|
4112
|
+
cpSync(oldDir, newDir, { recursive: true });
|
|
4113
|
+
} catch {}
|
|
4114
|
+
}
|
|
4115
|
+
return newDir;
|
|
4105
4116
|
}
|
|
4106
4117
|
function loadSecretKey(keyName) {
|
|
4107
4118
|
const secretsPath = join(homedir(), ".secrets");
|
|
@@ -4122,16 +4133,16 @@ function loadSecretKey(keyName) {
|
|
|
4122
4133
|
return "";
|
|
4123
4134
|
}
|
|
4124
4135
|
function ensureDataDir(config) {
|
|
4125
|
-
const { mkdirSync } = __require("fs");
|
|
4126
|
-
|
|
4136
|
+
const { mkdirSync: mkdirSync2 } = __require("fs");
|
|
4137
|
+
mkdirSync2(config.audio_dir, { recursive: true });
|
|
4127
4138
|
const dbDir = config.db_path.substring(0, config.db_path.lastIndexOf("/"));
|
|
4128
4139
|
if (dbDir)
|
|
4129
|
-
|
|
4140
|
+
mkdirSync2(dbDir, { recursive: true });
|
|
4130
4141
|
}
|
|
4131
4142
|
|
|
4132
4143
|
// src/db/database.ts
|
|
4133
4144
|
import { Database } from "bun:sqlite";
|
|
4134
|
-
import { mkdirSync } from "fs";
|
|
4145
|
+
import { mkdirSync as mkdirSync2 } from "fs";
|
|
4135
4146
|
import { dirname } from "path";
|
|
4136
4147
|
var _db = null;
|
|
4137
4148
|
var MIGRATIONS = [
|
|
@@ -4203,7 +4214,7 @@ function getDatabase(dbPath) {
|
|
|
4203
4214
|
return _db;
|
|
4204
4215
|
const path = dbPath || loadConfig().db_path;
|
|
4205
4216
|
const dir = dirname(path);
|
|
4206
|
-
|
|
4217
|
+
mkdirSync2(dir, { recursive: true });
|
|
4207
4218
|
_db = new Database(path, { create: true });
|
|
4208
4219
|
_db.run("PRAGMA journal_mode = WAL");
|
|
4209
4220
|
_db.run("PRAGMA busy_timeout = 5000");
|
package/dist/types/index.d.ts
CHANGED
|
@@ -12,6 +12,9 @@ export interface Recording {
|
|
|
12
12
|
agent_id: string | null;
|
|
13
13
|
project_id: string | null;
|
|
14
14
|
session_id: string | null;
|
|
15
|
+
goal: string | null;
|
|
16
|
+
role: string | null;
|
|
17
|
+
task_list_id: string | null;
|
|
15
18
|
metadata: Record<string, unknown>;
|
|
16
19
|
created_at: string;
|
|
17
20
|
}
|
|
@@ -29,6 +32,9 @@ export interface CreateRecordingInput {
|
|
|
29
32
|
agent_id?: string;
|
|
30
33
|
project_id?: string;
|
|
31
34
|
session_id?: string;
|
|
35
|
+
goal?: string;
|
|
36
|
+
role?: string;
|
|
37
|
+
task_list_id?: string;
|
|
32
38
|
metadata?: Record<string, unknown>;
|
|
33
39
|
}
|
|
34
40
|
export interface RecordingFilter {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/cli/index.ts
CHANGED
|
@@ -485,24 +485,27 @@ program
|
|
|
485
485
|
const { existsSync: fileExists } = require("node:fs") as typeof import("node:fs");
|
|
486
486
|
const home = getHome();
|
|
487
487
|
|
|
488
|
-
const appPath = pathJoin(home, ".recordings", "RecordingsHelper.app");
|
|
488
|
+
const appPath = pathJoin(home, ".hasna", "recordings", "RecordingsHelper.app");
|
|
489
|
+
const oldAppPath = pathJoin(home, ".recordings", "RecordingsHelper.app");
|
|
489
490
|
|
|
490
|
-
if (!fileExists(appPath)) {
|
|
491
|
+
if (!fileExists(appPath) && !fileExists(oldAppPath)) {
|
|
491
492
|
console.error(chalk.red("RecordingsHelper.app not found. Run: recordings shortcut --install"));
|
|
492
493
|
process.exit(1);
|
|
493
494
|
}
|
|
494
495
|
|
|
496
|
+
const resolvedAppPath = fileExists(appPath) ? appPath : oldAppPath;
|
|
497
|
+
|
|
495
498
|
// Kill existing instance
|
|
496
499
|
try { execSync("pkill -f RecordingsHelper", { stdio: "pipe" }); } catch { /* not running */ }
|
|
497
500
|
|
|
498
501
|
// Launch
|
|
499
|
-
execSync(`open "${
|
|
502
|
+
execSync(`open "${resolvedAppPath}"`, { stdio: "pipe" });
|
|
500
503
|
console.log(chalk.green("Recordings helper launched — press F5 to record"));
|
|
501
504
|
|
|
502
505
|
if (opts.login) {
|
|
503
506
|
try {
|
|
504
507
|
execSync(
|
|
505
|
-
`osascript -e 'tell application "System Events" to make login item at end with properties {path:"${
|
|
508
|
+
`osascript -e 'tell application "System Events" to make login item at end with properties {path:"${resolvedAppPath}", hidden:true}'`,
|
|
506
509
|
{ stdio: "pipe" }
|
|
507
510
|
);
|
|
508
511
|
console.log(chalk.green("Added to Login Items — will start on boot"));
|
|
@@ -688,7 +691,7 @@ program
|
|
|
688
691
|
const { homedir: getHome } = require("node:os") as typeof import("node:os");
|
|
689
692
|
const home = getHome();
|
|
690
693
|
|
|
691
|
-
const scriptDir = pathJoin(home, ".recordings");
|
|
694
|
+
const scriptDir = pathJoin(home, ".hasna", "recordings");
|
|
692
695
|
mkdirSync(scriptDir, { recursive: true });
|
|
693
696
|
|
|
694
697
|
const scriptPath = pathJoin(scriptDir, "record-toggle.sh");
|
|
@@ -747,7 +750,7 @@ fi
|
|
|
747
750
|
// Install the native menu bar app — no config needed, just works with F5
|
|
748
751
|
const { execSync: exec } = require("node:child_process") as typeof import("node:child_process");
|
|
749
752
|
|
|
750
|
-
const appPath = pathJoin(home, ".recordings", "RecordingsHelper.app");
|
|
753
|
+
const appPath = pathJoin(home, ".hasna", "recordings", "RecordingsHelper.app");
|
|
751
754
|
const srcSwift = pathJoin(__dirname, "..", "native", "RecordingsHelper.swift");
|
|
752
755
|
const distApp = pathJoin(__dirname, "..", "RecordingsHelper.app");
|
|
753
756
|
|
|
@@ -757,10 +760,10 @@ fi
|
|
|
757
760
|
} else if (fileExists(srcSwift)) {
|
|
758
761
|
// Compile from source
|
|
759
762
|
console.log(chalk.blue("Compiling native helper app..."));
|
|
760
|
-
const appDir = pathJoin(home, ".recordings", "RecordingsHelper.app", "Contents", "MacOS");
|
|
763
|
+
const appDir = pathJoin(home, ".hasna", "recordings", "RecordingsHelper.app", "Contents", "MacOS");
|
|
761
764
|
mkdirSync(appDir, { recursive: true });
|
|
762
765
|
|
|
763
|
-
const plistDir = pathJoin(home, ".recordings", "RecordingsHelper.app", "Contents");
|
|
766
|
+
const plistDir = pathJoin(home, ".hasna", "recordings", "RecordingsHelper.app", "Contents");
|
|
764
767
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
765
768
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
766
769
|
<plist version="1.0"><dict>
|
package/src/lib/config.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "fs";
|
|
1
|
+
import { existsSync, readFileSync, mkdirSync, cpSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
import { homedir } from "os";
|
|
4
4
|
import type { RecordingsConfig } from "../types/index.js";
|
|
@@ -67,7 +67,9 @@ export function loadConfig(configPath?: string): RecordingsConfig {
|
|
|
67
67
|
if (process.env.RECORDINGS_LANGUAGE) {
|
|
68
68
|
config.language = process.env.RECORDINGS_LANGUAGE;
|
|
69
69
|
}
|
|
70
|
-
if (process.env.
|
|
70
|
+
if (process.env.HASNA_RECORDINGS_DB_PATH) {
|
|
71
|
+
config.db_path = process.env.HASNA_RECORDINGS_DB_PATH;
|
|
72
|
+
} else if (process.env.RECORDINGS_DB_PATH) {
|
|
71
73
|
config.db_path = process.env.RECORDINGS_DB_PATH;
|
|
72
74
|
}
|
|
73
75
|
if (process.env.RECORDINGS_AUDIO_DIR) {
|
|
@@ -115,7 +117,7 @@ function findConfigFile(): string | null {
|
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
export function getDataDir(): string {
|
|
118
|
-
// Check for .recordings in cwd hierarchy
|
|
120
|
+
// Check for .recordings in cwd hierarchy (project-local)
|
|
119
121
|
let dir = process.cwd();
|
|
120
122
|
const root = "/";
|
|
121
123
|
while (dir !== root) {
|
|
@@ -125,8 +127,23 @@ export function getDataDir(): string {
|
|
|
125
127
|
if (parent === dir) break;
|
|
126
128
|
dir = parent;
|
|
127
129
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
+
|
|
131
|
+
// Global: ~/.hasna/recordings (with backward compat from ~/.recordings)
|
|
132
|
+
const home = homedir();
|
|
133
|
+
const newDir = join(home, ".hasna", "recordings");
|
|
134
|
+
const oldDir = join(home, ".recordings");
|
|
135
|
+
|
|
136
|
+
// Auto-migrate from old location if new dir doesn't exist yet
|
|
137
|
+
if (!existsSync(newDir) && existsSync(oldDir)) {
|
|
138
|
+
try {
|
|
139
|
+
mkdirSync(join(home, ".hasna"), { recursive: true });
|
|
140
|
+
cpSync(oldDir, newDir, { recursive: true });
|
|
141
|
+
} catch {
|
|
142
|
+
// Fall through to use new dir
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return newDir;
|
|
130
147
|
}
|
|
131
148
|
|
|
132
149
|
function loadSecretKey(keyName: string): string {
|
|
@@ -69,7 +69,7 @@ final class RecordingEngine: ObservableObject {
|
|
|
69
69
|
private let fnMonitor = FnKeyMonitor()
|
|
70
70
|
|
|
71
71
|
let home = FileManager.default.homeDirectoryForCurrentUser.path
|
|
72
|
-
private var audioDir: String { "\(home)/.recordings/audio" }
|
|
72
|
+
private var audioDir: String { "\(home)/.hasna/recordings/audio" }
|
|
73
73
|
|
|
74
74
|
init() {
|
|
75
75
|
try? FileManager.default.createDirectory(atPath: audioDir, withIntermediateDirectories: true)
|
|
@@ -22,7 +22,7 @@ final class VoiceShortcuts: ObservableObject {
|
|
|
22
22
|
|
|
23
23
|
private let storageURL: URL = {
|
|
24
24
|
let home = FileManager.default.homeDirectoryForCurrentUser
|
|
25
|
-
return home.appendingPathComponent(".recordings/voice-shortcuts.json")
|
|
25
|
+
return home.appendingPathComponent(".hasna/recordings/voice-shortcuts.json")
|
|
26
26
|
}()
|
|
27
27
|
|
|
28
28
|
init() {
|
|
@@ -33,8 +33,8 @@ fi
|
|
|
33
33
|
|
|
34
34
|
echo "✓ Built $APP_DIR"
|
|
35
35
|
echo ""
|
|
36
|
-
echo "To install to ~/.recordings/:"
|
|
37
|
-
echo " cp -r $APP_DIR ~/.recordings/Recordings.app"
|
|
36
|
+
echo "To install to ~/.hasna/recordings/:"
|
|
37
|
+
echo " cp -r $APP_DIR ~/.hasna/recordings/Recordings.app"
|
|
38
38
|
echo ""
|
|
39
39
|
echo "To run:"
|
|
40
40
|
echo " open $APP_DIR"
|
|
@@ -18,12 +18,19 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
|
|
18
18
|
|
|
19
19
|
let recordingsDir: String = {
|
|
20
20
|
let home = FileManager.default.homeDirectoryForCurrentUser.path
|
|
21
|
-
|
|
21
|
+
let newDir = "\(home)/.hasna/recordings"
|
|
22
|
+
let oldDir = "\(home)/.recordings"
|
|
23
|
+
// Auto-migrate from old location
|
|
24
|
+
if !FileManager.default.fileExists(atPath: newDir) && FileManager.default.fileExists(atPath: oldDir) {
|
|
25
|
+
try? FileManager.default.createDirectory(atPath: "\(home)/.hasna", withIntermediateDirectories: true)
|
|
26
|
+
try? FileManager.default.copyItem(atPath: oldDir, toPath: newDir)
|
|
27
|
+
}
|
|
28
|
+
return newDir
|
|
22
29
|
}()
|
|
23
30
|
|
|
24
31
|
let audioDir: String = {
|
|
25
32
|
let home = FileManager.default.homeDirectoryForCurrentUser.path
|
|
26
|
-
return "\(home)/.recordings/audio"
|
|
33
|
+
return "\(home)/.hasna/recordings/audio"
|
|
27
34
|
}()
|
|
28
35
|
|
|
29
36
|
let recordingsBin: String = {
|