Sync from Mac mini main: preserve full-app-path fix (/System/Applications/), reminders assignment hints, deco_ha_bridge for clients, plus image tools, plus system speech API check

Mac mini is on macOS 26.5.2 Mac16,10 M4 - SpeechAnalyzer available
- Calendar/Contacts/Notes/Reminders use full /System/Applications/*.app path (more reliable)
- Reminders now returns assignment {assignee, source, available} with fallback to (Name) in title
- deco.js uses deco_ha_bridge.py for clients action (more reliable than old bridge)
- Added deco_ha_bridge.py (13KB RSA/AES Deco HA client)
- Added system_get_info + system_speech_api_status (verifies SpeechAnalyzer on macOS 26+)
- Preserved codex-image, gemini-image, gemini-chrome-prompt tools
- Updated README with all 23 tools + macOS 26 note + benchmark ref
This commit is contained in:
aeroreyna
2026-07-13 16:18:40 -04:00
parent 4bed6145b9
commit 2345627eb8
7 changed files with 544 additions and 24 deletions
+96 -6
View File
@@ -2,18 +2,105 @@ import { dateFromInput, runJxa } from "../apple-events.js";
const LISTS_SCRIPT = String.raw`
function run() {
const app = Application("Reminders");
const app = Application("/System/Applications/Reminders.app");
function stringValue(value) {
try {
return value === null || value === undefined ? null : String(value);
} catch (_) {
return null;
}
}
function accountName(list) {
try {
const container = list.container();
return stringValue(container.name ? container.name() : container);
} catch (_) {
return null;
}
}
return JSON.stringify(app.lists().map(function (list) {
return { id: String(list.id()), name: String(list.name()) };
return {
id: String(list.id()),
name: String(list.name()),
account: accountName(list),
shared: null,
assignmentMetadata: {
available: null,
note: "Apple Reminders automation does not expose shared-list participant metadata directly."
}
};
}));
}`;
const REMINDERS_LIST_SCRIPT = String.raw`
function run(argv) {
const input = JSON.parse(argv[0]);
const app = Application("Reminders");
const app = Application("/System/Applications/Reminders.app");
const lists = app.lists();
const found = [];
function stringValue(value) {
try {
return value === null || value === undefined ? null : String(value);
} catch (_) {
return null;
}
}
function compact(value) {
if (!value) return null;
const text = String(value).trim();
return text ? text : null;
}
function propertyValue(object, names) {
for (let i = 0; i < names.length; i++) {
try {
const getter = object[names[i]];
if (typeof getter !== "function") continue;
const value = getter.call(object);
const text = compact(stringValue(value));
if (text && !text.startsWith("[object ")) return text;
if (value && typeof value.name === "function") {
const name = compact(stringValue(value.name()));
if (name) return name;
}
} catch (_) {}
}
return null;
}
function assignmentHint(title, notes) {
const titleMatch = title.match(/\(([^()\n]{2,80})\)\s*$/);
if (titleMatch) return { assignee: titleMatch[1].trim(), source: "title" };
const explicit = notes.match(/\b(?:assigned to|assignee)\s*:\s*([^.;,\n]{2,80})/i);
if (explicit) return { assignee: explicit[1].trim(), source: "notes" };
const captured = notes.match(/\bCaptured\s+\d{4}-\d{2}-\d{2},\s*([^.;,\n]{2,80})\s*[.;]/i);
if (captured) return { assignee: captured[1].trim(), source: "notes" };
return { assignee: null, source: null };
}
function assignmentFor(reminder, title, notes) {
const nativeAssignee = propertyValue(reminder, [
"assignedTo",
"assignee",
"assignment",
"responsiblePerson",
"principal"
]);
if (nativeAssignee) {
return {
assignee: nativeAssignee,
source: "remindersAutomation",
available: true
};
}
const hint = assignmentHint(title, notes);
return {
assignee: hint.assignee,
source: hint.source,
available: hint.assignee !== null
};
}
for (let l = 0; l < lists.length && found.length < input.limit; l++) {
const list = lists[l];
const name = String(list.name());
@@ -28,13 +115,16 @@ function run(argv) {
const value = reminder.dueDate();
due = value ? value.toISOString() : null;
} catch (_) {}
const title = String(reminder.name());
const notes = String(reminder.body() || "");
found.push({
id: String(reminder.id()),
list: name,
title: String(reminder.name()),
title: title,
completed: completed,
due: due,
notes: String(reminder.body() || "")
notes: notes,
assignment: assignmentFor(reminder, title, notes)
});
}
}
@@ -44,7 +134,7 @@ function run(argv) {
const REMINDER_CREATE_SCRIPT = String.raw`
function run(argv) {
const input = JSON.parse(argv[0]);
const app = Application("Reminders");
const app = Application("/System/Applications/Reminders.app");
const lists = app.lists();
let destination = null;
for (let l = 0; l < lists.length; l++) {