import { runAppleScript } from 'run-applescript';
export interface Todo {
id: string;
name: string;
status: 'open' | 'completed' | 'canceled';
notes?: string;
}
async function runThingsScript(scriptBody: string): Promise<string> {
const fullScript = `
tell application "Things3"
${scriptBody}
end tell
`;
return runAppleScript(fullScript);
}
export async function getTodos(listName: string): Promise<Todo[]> {
const script = `
set output to ""
set delimiter to "|||"
set itemDelimiter to "&&&"
repeat with aTodo in to dos of list "${listName}"
set todoId to id of aTodo
set todoName to name of aTodo
set todoStatus to status of aTodo as text
set todoNotes to notes of aTodo
if todoNotes is missing value then
set todoNotes to ""
end if
set output to output & todoId & delimiter & todoName & delimiter & todoStatus & delimiter & todoNotes & itemDelimiter
end repeat
return output
`;
const rawOutput = await runThingsScript(script);
if (!rawOutput) return [];
const items = rawOutput.split('&&&');
const todos: Todo[] = [];
for (const item of items) {
if (!item.trim()) continue;
const [id, name, status, notes] = item.split('|||');
todos.push({
id,
name,
status: status as 'open' | 'completed' | 'canceled',
notes: notes === "" ? undefined : notes
});
}
return todos;
}
export async function createTodo(title: string, listName: string = "Inbox", notes?: string): Promise<string> {
const escape = (str: string) => str.replace(/"/g, '\\"');
const safeTitle = escape(title);
const safeNotes = notes ? escape(notes) : "";
let properties = `name:"${safeTitle}"`;
if (notes) {
properties += `, notes:"${safeNotes}"`;
}
const script = `
set newTodo to make new to do with properties {${properties}} at beginning of list "${listName}"
return id of newTodo
`;
return runThingsScript(script);
}