omega restructuring + a bunch of changes i have made over the last weeks
This commit is contained in:
431
marts/src/c2vi/deno.ts
Normal file
431
marts/src/c2vi/deno.ts
Normal file
@@ -0,0 +1,431 @@
|
||||
import { createClient } from "@libsql/client";
|
||||
import { drizzle } from "drizzle-orm/libsql";
|
||||
import { sqliteTable, text, integer } from "drizzle-orm/sqlite-core";
|
||||
import { eq } from "drizzle-orm";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import os from "node:os";
|
||||
import { spawnSync } from "node:child_process";
|
||||
|
||||
export async function init(ppc: PPC) {
|
||||
ppc.c2vi = new C2vi(ppc);
|
||||
|
||||
ppc.cli
|
||||
.command("bed", "command to run when c2vi goes to bed")
|
||||
.action(async () => {
|
||||
await save_habitica_dailies(ppc);
|
||||
await save_habitica_logs(ppc);
|
||||
});
|
||||
|
||||
ppc.cli
|
||||
.command("clearTodos", "command to run when c2vi goes to bed")
|
||||
.alias("clt")
|
||||
.action(async () => {
|
||||
const todos = await ppc.habitica.get_tasks();
|
||||
for (const todo of todos) {
|
||||
await ppc.habitica.delete_task(todo.id);
|
||||
}
|
||||
});
|
||||
|
||||
ppc.cli
|
||||
.command("listTodos", "command to run when c2vi goes to bed")
|
||||
.alias("dut")
|
||||
.action(async () => {
|
||||
const todos = await ppc.habitica.get_tasks();
|
||||
for (const todo of todos) {
|
||||
console.log(todo.text);
|
||||
}
|
||||
});
|
||||
|
||||
ppc.cli
|
||||
.command("buyHealthPotion", "command to run when c2vi goes to bed")
|
||||
.alias("buyh")
|
||||
.action(async () => {
|
||||
await ppc.habitica.api_request("POST", "/user/buy-health-potion");
|
||||
});
|
||||
|
||||
ppc.cli
|
||||
.command("addActionItems", "command to run when c2vi goes to bed")
|
||||
.alias("aal")
|
||||
.action(async () => {
|
||||
await add_action_items(ppc);
|
||||
});
|
||||
|
||||
ppc.cli
|
||||
.command("test", "a command to run some test code")
|
||||
.alias("t")
|
||||
.action(async () => {});
|
||||
|
||||
ppc.cli
|
||||
.command("skip [num]", "command to skip a habitica todo")
|
||||
.alias("sk")
|
||||
.action((num = 1) => {
|
||||
skip_habitica_todo(ppc, parseInt(num));
|
||||
});
|
||||
|
||||
ppc.cli.command("dumpLog", "dump the complete habitica log").action(() => {
|
||||
dump_habitica_logs(ppc);
|
||||
});
|
||||
|
||||
ppc.cli
|
||||
.command("listDailies", "list all dailies")
|
||||
.action(async (folder, options) => {
|
||||
const allDailies = await ppc.c2vi.db.select().from(dailiesTable).all();
|
||||
for (const task of allDailies) {
|
||||
console.log(task.id + ": " + task.text);
|
||||
}
|
||||
});
|
||||
|
||||
ppc.cli
|
||||
.command("printTask <id>", "print a specific todo")
|
||||
.action(async (id) => {
|
||||
const data = await ppc.habitica.api_request("GET", `/tasks/${id}`, {});
|
||||
console.log(data.history);
|
||||
});
|
||||
}
|
||||
|
||||
class C2vi {
|
||||
[key: string]: any;
|
||||
|
||||
constructor(ppc: PPC) {
|
||||
this.ppc = ppc;
|
||||
this.db = drizzle(
|
||||
createClient({
|
||||
url: "file://" + ppc.config.local_storage_path + "/data.db",
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function formatDate(d) {
|
||||
const pad = (n) => n.toString().padStart(2, "0");
|
||||
|
||||
// Custom YYYY-MM-DD format
|
||||
const formatted = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
||||
return formatted;
|
||||
}
|
||||
|
||||
// ============= SCHEMA DEFINITION =============
|
||||
const dailiesTable = sqliteTable("habitica_dailies", {
|
||||
id: text("id").primaryKey(),
|
||||
text: text("text").notNull(),
|
||||
notes: text("notes"),
|
||||
priority: text("priority"), // 0.1, 1, 1.5, 2
|
||||
frequency: text("frequency"), // 'daily', 'weekly', etc.
|
||||
});
|
||||
const habiticaLogTable = sqliteTable("habitica_log", {
|
||||
date: text("date").primaryKey(),
|
||||
data: text("data").notNull(),
|
||||
});
|
||||
|
||||
async function save_habitica_dailies(ppc) {
|
||||
console.log("######### cli bed cmd #########");
|
||||
await ppc.c2vi.db.run(
|
||||
"CREATE TABLE IF NOT EXISTS habitica_dailies (id TEXT PRIMARY KEY, text TEXT NOT NULL, notes TEXT, priority TEXT, frequency TEXT)",
|
||||
);
|
||||
await ppc.c2vi.db.run(
|
||||
"CREATE TABLE IF NOT EXISTS habitica_log (date TEXT PRIMARY KEY, data TEXT NOT NULL)",
|
||||
);
|
||||
|
||||
// ============= DATABASE INITIALIZATION =============
|
||||
if (!ppc.config.habitica.user_id || !ppc.config.habitica.api_token) {
|
||||
console.error(
|
||||
"Error: HABITICA_USER_ID and HABITICA_API_TOKEN env vars required",
|
||||
);
|
||||
console.error(
|
||||
"Get these from Habitica Settings > API and configure them in the ppc.config",
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const dailies = await ppc.habitica.get_tasks("dailys");
|
||||
|
||||
await writeDailiesToDatabase(dailies, ppc);
|
||||
}
|
||||
|
||||
async function dump_habitica_logs(ppc) {
|
||||
const entries = await ppc.c2vi.db.select().from(habiticaLogTable).all();
|
||||
for (const entry of entries) {
|
||||
console.log(entry.date + ": ", JSON.parse(entry.data));
|
||||
}
|
||||
}
|
||||
|
||||
async function skip_habitica_todo(ppc, num) {
|
||||
await ppc.c2vi.db.run(
|
||||
"CREATE TABLE IF NOT EXISTS habitica_dailies (id TEXT PRIMARY KEY, text TEXT NOT NULL, notes TEXT, priority TEXT, frequency TEXT)",
|
||||
);
|
||||
await ppc.c2vi.db.run(
|
||||
"CREATE TABLE IF NOT EXISTS habitica_log (date TEXT PRIMARY KEY, data TEXT NOT NULL)",
|
||||
);
|
||||
|
||||
const todos = await ppc.habitica.get_tasks("todos");
|
||||
|
||||
const date = new Date();
|
||||
const save_for_yesterday = date.getHours() < 12;
|
||||
if (save_for_yesterday) {
|
||||
console.log(
|
||||
"Saving logs for yesterday!!!! because it is " +
|
||||
date.getHours() +
|
||||
"hours of the day",
|
||||
);
|
||||
date.setDate(date.getDate() - 1);
|
||||
}
|
||||
|
||||
const result = await ppc.c2vi.db
|
||||
.select()
|
||||
.from(habiticaLogTable)
|
||||
.where(eq(habiticaLogTable.date, formatDate(date)));
|
||||
|
||||
const data = result[0]
|
||||
? JSON.parse(result[0].data)
|
||||
: {
|
||||
dailies_done: [],
|
||||
dailies_skipped: [],
|
||||
todos_done: [],
|
||||
todos_skipped: [],
|
||||
};
|
||||
|
||||
for (let i = 0; i < num; i++) {
|
||||
const todo = todos[i];
|
||||
if (!todo) continue;
|
||||
await ppc.habitica.delete_task(todo.id);
|
||||
await incrementHabit(ppc);
|
||||
|
||||
data.todos_skipped.push({
|
||||
id: todo.id,
|
||||
text: todo.text,
|
||||
notes: todo.notes || "",
|
||||
checklist: todo.checklist || [],
|
||||
tags: todo.tags || [],
|
||||
});
|
||||
}
|
||||
|
||||
// saving to db
|
||||
await ppc.c2vi.db
|
||||
.insert(habiticaLogTable)
|
||||
.values({ date: formatDate(date), data: JSON.stringify(data) })
|
||||
.onConflictDoUpdate({
|
||||
target: habiticaLogTable.date,
|
||||
set: {
|
||||
data: JSON.stringify(data),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function save_habitica_logs(ppc) {
|
||||
const date = new Date();
|
||||
const save_for_yesterday = date.getHours() < 12;
|
||||
if (save_for_yesterday) {
|
||||
console.log(
|
||||
"Saving logs for yesterday!!!! because it is " +
|
||||
date.getHours() +
|
||||
"hours of the day",
|
||||
);
|
||||
date.setDate(date.getDate() - 1);
|
||||
}
|
||||
|
||||
const result = await ppc.c2vi.db
|
||||
.select()
|
||||
.from(habiticaLogTable)
|
||||
.where(eq(habiticaLogTable.date, formatDate(date)));
|
||||
|
||||
const data = result[0]
|
||||
? JSON.parse(result[0].data)
|
||||
: {
|
||||
dailies_done: [],
|
||||
dailies_skipped: [],
|
||||
todos_done: [],
|
||||
todos_skipped: [],
|
||||
};
|
||||
|
||||
// dailies
|
||||
const dailies = await ppc.habitica.get_tasks("dailys");
|
||||
for (const daily of dailies) {
|
||||
let completed = daily.completed;
|
||||
let isDue = daily.isDue;
|
||||
if (save_for_yesterday) {
|
||||
const yesterday = daily.history.reduce((prev, current) => {
|
||||
return prev.date > current.date ? prev : current;
|
||||
});
|
||||
completed = yesterday.completed;
|
||||
isDue = yesterday.isDue;
|
||||
}
|
||||
if (!isDue) {
|
||||
continue;
|
||||
}
|
||||
if (completed) {
|
||||
data.dailies_done.push(daily.id);
|
||||
console.log("daily-done: " + daily.text);
|
||||
} else {
|
||||
data.dailies_skipped.push(daily.id);
|
||||
console.log("daily-skipped: " + daily.text);
|
||||
}
|
||||
}
|
||||
|
||||
// todos done
|
||||
const todos = await ppc.habitica.get_tasks("completedTodos");
|
||||
for (const todo of todos) {
|
||||
const dateCompleted = new Date(todo.dateCompleted);
|
||||
|
||||
// check if this todo is already saved in yesterday's log entry
|
||||
if (save_for_yesterday) {
|
||||
// get yesterday log entry
|
||||
const result = await ppc.c2vi.db
|
||||
.select()
|
||||
.from(habiticaLogTable)
|
||||
.where(eq(habiticaLogTable.date, formatDate(date)));
|
||||
|
||||
const data = result[0]
|
||||
? JSON.parse(result[0].data)
|
||||
: {
|
||||
dailies_done: [],
|
||||
dailies_skipped: [],
|
||||
todos_done: [],
|
||||
todos_skipped: [],
|
||||
};
|
||||
|
||||
// check if this todo is already saved in yesterday's log entry
|
||||
const todoIndex = data.todos_done.findIndex((t) => t.id === todo.id);
|
||||
if (todoIndex !== -1) {
|
||||
continue; // skipp saving this todo
|
||||
}
|
||||
}
|
||||
|
||||
if (dateCompleted.toDateString() == date.toDateString()) {
|
||||
console.log("todo-done:", todo.text);
|
||||
data.todos_done.push({
|
||||
id: todo.id,
|
||||
text: todo.text,
|
||||
notes: todo.notes || "",
|
||||
checklist: todo.checklist || [],
|
||||
tags: todo.tags || [],
|
||||
});
|
||||
}
|
||||
|
||||
// we save_for_yesterday but the todo was completed today... also save that for this day
|
||||
if (
|
||||
save_for_yesterday &&
|
||||
dateCompleted.toDateString() == new Date().toDateString()
|
||||
) {
|
||||
console.log("todo-done:", todo.text);
|
||||
data.todos_done.push({
|
||||
id: todo.id,
|
||||
text: todo.text,
|
||||
notes: todo.notes || "",
|
||||
checklist: todo.checklist || [],
|
||||
tags: todo.tags || [],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// saving to db
|
||||
await ppc.c2vi.db
|
||||
.insert(habiticaLogTable)
|
||||
.values({ date: formatDate(date), data: JSON.stringify(data) })
|
||||
.onConflictDoUpdate({
|
||||
target: habiticaLogTable.date,
|
||||
set: {
|
||||
data: JSON.stringify(data),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function writeDailiesToDatabase(dailies, ppc) {
|
||||
console.log(`Syncing ${dailies.length} dailies to database...`);
|
||||
|
||||
const records = dailies.map((daily) => ({
|
||||
id: daily.id,
|
||||
text: daily.text,
|
||||
notes: daily.notes || "",
|
||||
priority: daily.priority?.toString() || null,
|
||||
frequency: daily.frequency || "daily",
|
||||
}));
|
||||
|
||||
async function upsertMany(records) {
|
||||
for (const record of records) {
|
||||
await ppc.c2vi.db
|
||||
.insert(dailiesTable)
|
||||
.values(record)
|
||||
.onConflictDoUpdate({
|
||||
target: dailiesTable.id,
|
||||
set: {
|
||||
text: record.text,
|
||||
notes: record.notes,
|
||||
priority: record.priority,
|
||||
frequency: record.frequency,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
await upsertMany(records);
|
||||
}
|
||||
|
||||
async function incrementHabit(ppc) {
|
||||
const habits = await ppc.habitica.get_tasks("habits");
|
||||
let id = "";
|
||||
for (const habit of habits) {
|
||||
if ((habit.text = "skipped a planned task")) {
|
||||
id = habit.id;
|
||||
}
|
||||
}
|
||||
await ppc.habitica.api_request("POST", `tasks/${id}/score/down`);
|
||||
}
|
||||
|
||||
async function add_action_items(ppc: PPC) {
|
||||
let task_ids = [];
|
||||
|
||||
const tmpFile = path.join(os.tmpdir(), `habitica-tasks-${Date.now()}.md`);
|
||||
const initialContent = `
|
||||
gu 10min TIMER
|
||||
uw 15min FROG
|
||||
b coffee/tee/kakau
|
||||
uw FROG
|
||||
b breakfast, brush teeth, lüften
|
||||
uw FROG
|
||||
|
||||
lunch
|
||||
|
||||
uw 15min TIMER of next days FROG
|
||||
fw
|
||||
dt 30min TIMER
|
||||
|
||||
fun 20:00 (smth that can be stopped easily)
|
||||
se 21:40
|
||||
read
|
||||
bed 22:10
|
||||
`;
|
||||
|
||||
fs.writeFileSync(tmpFile, initialContent.trim());
|
||||
|
||||
spawnSync("nvim", [tmpFile], { stdio: "inherit" });
|
||||
|
||||
// read file
|
||||
const listStr = fs.readFileSync(tmpFile, "utf8");
|
||||
|
||||
// delete file
|
||||
fs.unlinkSync(tmpFile);
|
||||
|
||||
// Simple parser: filter out empty lines
|
||||
const tasks = listStr
|
||||
.split("\n")
|
||||
.map((t) => t.trim())
|
||||
.filter((t) => t.length > 0);
|
||||
|
||||
// 5. Add tasks to Habitica
|
||||
for (const todoText of tasks) {
|
||||
const data = await ppc.habitica.api_request(
|
||||
"POST",
|
||||
"tasks/user",
|
||||
{},
|
||||
{ text: todoText, type: "todo" },
|
||||
);
|
||||
task_ids.push(data.id);
|
||||
console.log(`Added to-do: '${todoText}' with id '${data.id}'`);
|
||||
}
|
||||
|
||||
// 6. Move tasks to bottom
|
||||
for (const taskId of task_ids) {
|
||||
await ppc.habitica.api_request("POST", `tasks/${taskId}/move/to/-1`);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user