apple-voice-memos-mcp 2.0.0 → 2.0.2
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/bin/cli.js +1 -1
- package/package.json +1 -1
- package/src/dist/services/config-service.js +47 -8
package/bin/cli.js
CHANGED
|
@@ -63,7 +63,7 @@ const NODE = ${JSON.stringify(process.execPath)};
|
|
|
63
63
|
const PORT = ${TCP_PORT};
|
|
64
64
|
|
|
65
65
|
const server = net.createServer((socket) => {
|
|
66
|
-
const child = spawn(NODE, [SERVER_JS], { stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env } });
|
|
66
|
+
const child = spawn(NODE, [SERVER_JS], { stdio: ['pipe', 'pipe', 'pipe'], env: { ...process.env }, cwd: ${JSON.stringify(join(__dirname, '..'))} });
|
|
67
67
|
socket.pipe(child.stdin);
|
|
68
68
|
child.stdout.pipe(socket);
|
|
69
69
|
child.stderr.on('data', () => {});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apple-voice-memos-mcp",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.2",
|
|
4
4
|
"description": "MCP server for Apple Voice Memos on macOS \u2014 AssemblyAI diarization, whisper.cpp fallback, auto-saved transcripts, bundled app + one-command setup",
|
|
5
5
|
"bin": {
|
|
6
6
|
"apple-voice-memos-mcp": "bin/cli.js"
|
|
@@ -57,28 +57,65 @@ export function ensureTranscriptsDir(dir) {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
/** Save a transcript in the configured folder; returns the written file path */
|
|
60
|
+
const TIMESTAMP_RE = /^\d{4}-\d{2}-\d{2}T/;
|
|
61
|
+
|
|
62
|
+
/** Nome della memo così come appare nell'app Memo Vocali del Mac */
|
|
63
|
+
function memoDisplayName(memo) {
|
|
64
|
+
const candidates = [memo.originalTitle, memo.customLabel, memo.title];
|
|
65
|
+
for (const c of candidates) {
|
|
66
|
+
if (c && !TIMESTAMP_RE.test(c)) return c; // preferisce il nome reale a un timestamp ISO
|
|
67
|
+
}
|
|
68
|
+
return candidates.find(Boolean) || `memo-${memo.id}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Data+ora leggibile: "sabato 29 agosto 2026 alle 12:45" (locale Mac) */
|
|
72
|
+
function formatDateTime(iso) {
|
|
73
|
+
if (!iso) return "n/d";
|
|
74
|
+
try {
|
|
75
|
+
const d = new Date(iso);
|
|
76
|
+
return d.toLocaleString("it-IT", {
|
|
77
|
+
weekday: "long", year: "numeric", month: "long",
|
|
78
|
+
day: "numeric", hour: "2-digit", minute: "2-digit",
|
|
79
|
+
});
|
|
80
|
+
} catch (e) {
|
|
81
|
+
return iso;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Durata "1:08:14" */
|
|
86
|
+
function formatDuration(seconds) {
|
|
87
|
+
const s = Math.round(seconds || 0);
|
|
88
|
+
const h = Math.floor(s / 3600);
|
|
89
|
+
const m = Math.floor((s % 3600) / 60);
|
|
90
|
+
const sec = s % 60;
|
|
91
|
+
const mm = String(m).padStart(2, "0");
|
|
92
|
+
const ss = String(sec).padStart(2, "0");
|
|
93
|
+
return h > 0 ? `${h}:${mm}:${ss}` : `${m}:${ss.padStart(2, "0")}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
60
96
|
export function saveTranscript({ memo, result, transcriptsDir }) {
|
|
61
97
|
const dir = ensureTranscriptsDir(transcriptsDir);
|
|
98
|
+
const displayName = memoDisplayName(memo);
|
|
62
99
|
const date = memo.date ? memo.date.slice(0, 10) : "unknown-date";
|
|
63
|
-
const safeTitle = String(
|
|
100
|
+
const safeTitle = String(displayName)
|
|
64
101
|
.replace(/[\\/:*?"<>|]/g, "-")
|
|
65
102
|
.replace(/\s+/g, " ")
|
|
66
103
|
.trim()
|
|
67
104
|
.slice(0, 80);
|
|
68
|
-
const base = `${
|
|
105
|
+
const base = `${safeTitle} - ${date} (id-${memo.id})`;
|
|
69
106
|
|
|
70
107
|
const files = [];
|
|
71
108
|
// markdown completo con diarization
|
|
72
109
|
const mdPath = join(dir, `${base}.md`);
|
|
73
110
|
const provider = result.provider || "unknown";
|
|
74
111
|
const md = [
|
|
75
|
-
`# Trascrizione — ${
|
|
112
|
+
`# Trascrizione memo vocale — ${displayName}`,
|
|
76
113
|
"",
|
|
114
|
+
`- **Memo vocale:** ${displayName}`,
|
|
115
|
+
`- **Data e ora:** ${formatDateTime(memo.date)}`,
|
|
116
|
+
`- **Durata:** ${formatDuration(memo.duration)}`,
|
|
77
117
|
`- **Memo ID:** ${memo.id}`,
|
|
78
|
-
`- **
|
|
79
|
-
`- **Data:** ${memo.date || "n/d"}`,
|
|
80
|
-
`- **Durata:** ${memo.durationFormatted || Math.round(memo.duration) + "s"}`,
|
|
81
|
-
`- **Provider:** ${provider}`,
|
|
118
|
+
`- **Provider trascrizione:** ${provider}`,
|
|
82
119
|
result.speakers ? `- **Speaker rilevati:** ${result.speakers}` : "",
|
|
83
120
|
result.languageCode ? `- **Lingua:** ${result.languageCode}` : "",
|
|
84
121
|
"",
|
|
@@ -94,9 +131,11 @@ export function saveTranscript({ memo, result, transcriptsDir }) {
|
|
|
94
131
|
const jsonPath = join(dir, `${base}.json`);
|
|
95
132
|
writeFileSyncSafe(jsonPath, JSON.stringify({
|
|
96
133
|
memoId: memo.id,
|
|
97
|
-
|
|
134
|
+
memoName: displayName,
|
|
98
135
|
originalTitle: memo.originalTitle || null,
|
|
99
136
|
date: memo.date,
|
|
137
|
+
dateTimeReadable: formatDateTime(memo.date),
|
|
138
|
+
durationFormatted: formatDuration(memo.duration),
|
|
100
139
|
durationSeconds: memo.duration,
|
|
101
140
|
provider,
|
|
102
141
|
speakers: result.speakers ?? null,
|