floq 0.0.1

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.
Files changed (59) hide show
  1. package/README.ja.md +133 -0
  2. package/README.md +133 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.js +124 -0
  5. package/dist/commands/add.d.ts +6 -0
  6. package/dist/commands/add.js +36 -0
  7. package/dist/commands/config.d.ts +6 -0
  8. package/dist/commands/config.js +73 -0
  9. package/dist/commands/done.d.ts +1 -0
  10. package/dist/commands/done.js +37 -0
  11. package/dist/commands/list.d.ts +2 -0
  12. package/dist/commands/list.js +96 -0
  13. package/dist/commands/move.d.ts +1 -0
  14. package/dist/commands/move.js +50 -0
  15. package/dist/commands/project.d.ts +8 -0
  16. package/dist/commands/project.js +160 -0
  17. package/dist/config.d.ts +14 -0
  18. package/dist/config.js +64 -0
  19. package/dist/db/index.d.ts +6 -0
  20. package/dist/db/index.js +72 -0
  21. package/dist/db/schema.d.ts +192 -0
  22. package/dist/db/schema.js +13 -0
  23. package/dist/i18n/en.d.ts +160 -0
  24. package/dist/i18n/en.js +108 -0
  25. package/dist/i18n/index.d.ts +7 -0
  26. package/dist/i18n/index.js +15 -0
  27. package/dist/i18n/ja.d.ts +2 -0
  28. package/dist/i18n/ja.js +108 -0
  29. package/dist/index.d.ts +2 -0
  30. package/dist/index.js +3 -0
  31. package/dist/paths.d.ts +6 -0
  32. package/dist/paths.js +22 -0
  33. package/dist/ui/App.d.ts +2 -0
  34. package/dist/ui/App.js +472 -0
  35. package/dist/ui/SplashScreen.d.ts +7 -0
  36. package/dist/ui/SplashScreen.js +61 -0
  37. package/dist/ui/TaskList.d.ts +10 -0
  38. package/dist/ui/TaskList.js +9 -0
  39. package/dist/ui/ThemeSelector.d.ts +7 -0
  40. package/dist/ui/ThemeSelector.js +17 -0
  41. package/dist/ui/components/FullScreenBox.d.ts +8 -0
  42. package/dist/ui/components/FullScreenBox.js +10 -0
  43. package/dist/ui/components/FunctionKeyBar.d.ts +10 -0
  44. package/dist/ui/components/FunctionKeyBar.js +19 -0
  45. package/dist/ui/components/HelpModal.d.ts +6 -0
  46. package/dist/ui/components/HelpModal.js +11 -0
  47. package/dist/ui/components/StatusBadge.d.ts +7 -0
  48. package/dist/ui/components/StatusBadge.js +16 -0
  49. package/dist/ui/components/TaskItem.d.ts +9 -0
  50. package/dist/ui/components/TaskItem.js +10 -0
  51. package/dist/ui/theme/index.d.ts +10 -0
  52. package/dist/ui/theme/index.js +11 -0
  53. package/dist/ui/theme/themes.d.ts +9 -0
  54. package/dist/ui/theme/themes.js +163 -0
  55. package/dist/ui/theme/types.d.ts +43 -0
  56. package/dist/ui/theme/types.js +1 -0
  57. package/dist/version.d.ts +1 -0
  58. package/dist/version.js +7 -0
  59. package/package.json +57 -0
@@ -0,0 +1,50 @@
1
+ import { eq, like } from 'drizzle-orm';
2
+ import { getDb, schema } from '../db/index.js';
3
+ import { t, fmt } from '../i18n/index.js';
4
+ export async function moveTask(taskId, targetStatus, waitingFor) {
5
+ const db = getDb();
6
+ const i18n = t();
7
+ const validStatuses = ['inbox', 'next', 'waiting', 'someday'];
8
+ if (!validStatuses.includes(targetStatus)) {
9
+ console.error(fmt(i18n.commands.move.invalidStatus, { status: targetStatus }));
10
+ console.error(fmt(i18n.commands.move.validStatuses, { statuses: validStatuses.join(', ') }));
11
+ process.exit(1);
12
+ }
13
+ if (targetStatus === 'waiting' && !waitingFor) {
14
+ console.error(i18n.commands.move.specifyWaiting);
15
+ process.exit(1);
16
+ }
17
+ // Find task by ID prefix
18
+ const tasks = db
19
+ .select()
20
+ .from(schema.tasks)
21
+ .where(like(schema.tasks.id, `${taskId}%`))
22
+ .all();
23
+ if (tasks.length === 0) {
24
+ console.error(fmt(i18n.commands.move.notFound, { id: taskId }));
25
+ process.exit(1);
26
+ }
27
+ if (tasks.length > 1) {
28
+ console.error(fmt(i18n.commands.move.multipleMatch, { id: taskId }));
29
+ for (const task of tasks) {
30
+ console.error(` [${task.id.slice(0, 8)}] ${task.title}`);
31
+ }
32
+ process.exit(1);
33
+ }
34
+ const task = tasks[0];
35
+ db.update(schema.tasks)
36
+ .set({
37
+ status: targetStatus,
38
+ waitingFor: targetStatus === 'waiting' ? waitingFor : null,
39
+ updatedAt: new Date(),
40
+ })
41
+ .where(eq(schema.tasks.id, task.id))
42
+ .run();
43
+ console.log(fmt(i18n.commands.move.success, {
44
+ title: task.title,
45
+ status: i18n.status[targetStatus]
46
+ }));
47
+ if (waitingFor) {
48
+ console.log(fmt(i18n.commands.move.waitingFor, { person: waitingFor }));
49
+ }
50
+ }
@@ -0,0 +1,8 @@
1
+ interface AddProjectOptions {
2
+ description?: string;
3
+ }
4
+ export declare function addProject(name: string, options: AddProjectOptions): Promise<void>;
5
+ export declare function listProjectsCommand(): Promise<void>;
6
+ export declare function showProject(projectId: string): Promise<void>;
7
+ export declare function completeProject(projectId: string): Promise<void>;
8
+ export {};
@@ -0,0 +1,160 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import { eq, like, and } from 'drizzle-orm';
3
+ import { getDb, schema } from '../db/index.js';
4
+ import { t, fmt } from '../i18n/index.js';
5
+ export async function addProject(name, options) {
6
+ const db = getDb();
7
+ const now = new Date();
8
+ const i18n = t();
9
+ // Check if project already exists
10
+ const existing = db
11
+ .select()
12
+ .from(schema.tasks)
13
+ .where(and(eq(schema.tasks.title, name), eq(schema.tasks.isProject, true)))
14
+ .get();
15
+ if (existing) {
16
+ console.error(fmt(i18n.commands.project.alreadyExists, { name }));
17
+ process.exit(1);
18
+ }
19
+ const project = {
20
+ id: uuidv4(),
21
+ title: name,
22
+ description: options.description,
23
+ status: 'next',
24
+ isProject: true,
25
+ createdAt: now,
26
+ updatedAt: now,
27
+ };
28
+ db.insert(schema.tasks).values(project).run();
29
+ console.log(fmt(i18n.commands.project.created, { name }));
30
+ }
31
+ export async function listProjectsCommand() {
32
+ const db = getDb();
33
+ const i18n = t();
34
+ const statuses = ['next', 'someday', 'done'];
35
+ const statusLabels = {
36
+ next: i18n.projectStatus.active,
37
+ someday: i18n.projectStatus.someday,
38
+ done: i18n.projectStatus.completed,
39
+ };
40
+ for (const status of statuses) {
41
+ const projects = db
42
+ .select()
43
+ .from(schema.tasks)
44
+ .where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.status, status)))
45
+ .all();
46
+ if (projects.length === 0 && status !== 'next')
47
+ continue;
48
+ console.log(`\n${statusLabels[status]} (${projects.length})`);
49
+ console.log('─'.repeat(40));
50
+ if (projects.length === 0) {
51
+ console.log(` ${i18n.commands.project.noProjects}`);
52
+ }
53
+ else {
54
+ for (const project of projects) {
55
+ const childTasks = db
56
+ .select()
57
+ .from(schema.tasks)
58
+ .where(eq(schema.tasks.parentId, project.id))
59
+ .all();
60
+ const activeTasks = childTasks.filter(t => t.status !== 'done').length;
61
+ const doneTasks = childTasks.filter(t => t.status === 'done').length;
62
+ const shortId = project.id.slice(0, 8);
63
+ console.log(` [${shortId}] ${project.title} (${fmt(i18n.commands.list.activeDone, { active: activeTasks, done: doneTasks })})`);
64
+ if (project.description) {
65
+ console.log(` ${project.description}`);
66
+ }
67
+ }
68
+ }
69
+ }
70
+ console.log();
71
+ }
72
+ export async function showProject(projectId) {
73
+ const db = getDb();
74
+ const i18n = t();
75
+ // Find project by ID prefix or name
76
+ let projects = db
77
+ .select()
78
+ .from(schema.tasks)
79
+ .where(and(eq(schema.tasks.isProject, true), like(schema.tasks.id, `${projectId}%`)))
80
+ .all();
81
+ if (projects.length === 0) {
82
+ projects = db
83
+ .select()
84
+ .from(schema.tasks)
85
+ .where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.title, projectId)))
86
+ .all();
87
+ }
88
+ if (projects.length === 0) {
89
+ console.error(fmt(i18n.commands.project.notFound, { id: projectId }));
90
+ process.exit(1);
91
+ }
92
+ if (projects.length > 1) {
93
+ console.error(fmt(i18n.commands.project.multipleMatch, { id: projectId }));
94
+ for (const project of projects) {
95
+ console.error(` [${project.id.slice(0, 8)}] ${project.title}`);
96
+ }
97
+ process.exit(1);
98
+ }
99
+ const project = projects[0];
100
+ const childTasks = db
101
+ .select()
102
+ .from(schema.tasks)
103
+ .where(eq(schema.tasks.parentId, project.id))
104
+ .all();
105
+ console.log(`\nProject: ${project.title}`);
106
+ console.log('─'.repeat(40));
107
+ if (project.description) {
108
+ console.log(fmt(i18n.commands.project.description, { description: project.description }));
109
+ }
110
+ console.log(fmt(i18n.commands.project.statusLabel, { status: project.status }));
111
+ console.log(fmt(i18n.commands.project.tasksCount, { count: childTasks.length }));
112
+ console.log();
113
+ const groupedTasks = {
114
+ inbox: childTasks.filter(t => t.status === 'inbox'),
115
+ next: childTasks.filter(t => t.status === 'next'),
116
+ waiting: childTasks.filter(t => t.status === 'waiting'),
117
+ someday: childTasks.filter(t => t.status === 'someday'),
118
+ done: childTasks.filter(t => t.status === 'done'),
119
+ };
120
+ for (const [status, statusTasks] of Object.entries(groupedTasks)) {
121
+ if (statusTasks.length === 0)
122
+ continue;
123
+ console.log(` ${i18n.status[status]}:`);
124
+ for (const task of statusTasks) {
125
+ const shortId = task.id.slice(0, 8);
126
+ let line = ` [${shortId}] ${task.title}`;
127
+ if (task.waitingFor) {
128
+ line += ` (${i18n.status.waiting.toLowerCase()}: ${task.waitingFor})`;
129
+ }
130
+ console.log(line);
131
+ }
132
+ }
133
+ console.log();
134
+ }
135
+ export async function completeProject(projectId) {
136
+ const db = getDb();
137
+ const i18n = t();
138
+ const projects = db
139
+ .select()
140
+ .from(schema.tasks)
141
+ .where(and(eq(schema.tasks.isProject, true), like(schema.tasks.id, `${projectId}%`)))
142
+ .all();
143
+ if (projects.length === 0) {
144
+ console.error(fmt(i18n.commands.project.notFound, { id: projectId }));
145
+ process.exit(1);
146
+ }
147
+ if (projects.length > 1) {
148
+ console.error(fmt(i18n.commands.project.multipleMatch, { id: projectId }));
149
+ process.exit(1);
150
+ }
151
+ const project = projects[0];
152
+ db.update(schema.tasks)
153
+ .set({
154
+ status: 'done',
155
+ updatedAt: new Date(),
156
+ })
157
+ .where(eq(schema.tasks.id, project.id))
158
+ .run();
159
+ console.log(fmt(i18n.commands.project.completed, { name: project.title }));
160
+ }
@@ -0,0 +1,14 @@
1
+ export type Locale = 'en' | 'ja';
2
+ export type ThemeName = 'modern' | 'norton-commander' | 'dos-prompt' | 'turbo-pascal';
3
+ export interface Config {
4
+ locale: Locale;
5
+ db_path?: string;
6
+ theme: ThemeName;
7
+ }
8
+ export declare function loadConfig(): Config;
9
+ export declare function saveConfig(updates: Partial<Config>): void;
10
+ export declare function getDbPath(): string;
11
+ export declare function getLocale(): Locale;
12
+ export declare function setLocale(locale: Locale): void;
13
+ export declare function getThemeName(): ThemeName;
14
+ export declare function setThemeName(theme: ThemeName): void;
package/dist/config.js ADDED
@@ -0,0 +1,64 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
2
+ import { dirname, join, isAbsolute } from 'path';
3
+ import { CONFIG_FILE, DATA_DIR } from './paths.js';
4
+ const DEFAULT_CONFIG = {
5
+ locale: 'en',
6
+ theme: 'modern',
7
+ };
8
+ let configCache = null;
9
+ export function loadConfig() {
10
+ if (configCache) {
11
+ return configCache;
12
+ }
13
+ try {
14
+ if (existsSync(CONFIG_FILE)) {
15
+ const content = readFileSync(CONFIG_FILE, 'utf-8');
16
+ const parsed = JSON.parse(content);
17
+ configCache = { ...DEFAULT_CONFIG, ...parsed };
18
+ return configCache;
19
+ }
20
+ }
21
+ catch {
22
+ // Ignore errors
23
+ }
24
+ configCache = DEFAULT_CONFIG;
25
+ return configCache;
26
+ }
27
+ export function saveConfig(updates) {
28
+ const current = loadConfig();
29
+ const newConfig = { ...current, ...updates };
30
+ try {
31
+ const configDir = dirname(CONFIG_FILE);
32
+ if (!existsSync(configDir)) {
33
+ mkdirSync(configDir, { recursive: true });
34
+ }
35
+ writeFileSync(CONFIG_FILE, JSON.stringify(newConfig, null, 2));
36
+ configCache = newConfig;
37
+ }
38
+ catch {
39
+ // Ignore errors
40
+ }
41
+ }
42
+ export function getDbPath() {
43
+ const config = loadConfig();
44
+ if (config.db_path) {
45
+ // 絶対パスならそのまま、相対パスならDATA_DIRからの相対
46
+ if (isAbsolute(config.db_path)) {
47
+ return config.db_path;
48
+ }
49
+ return join(DATA_DIR, config.db_path);
50
+ }
51
+ return join(DATA_DIR, 'gtd.db');
52
+ }
53
+ export function getLocale() {
54
+ return loadConfig().locale;
55
+ }
56
+ export function setLocale(locale) {
57
+ saveConfig({ locale });
58
+ }
59
+ export function getThemeName() {
60
+ return loadConfig().theme || 'modern';
61
+ }
62
+ export function setThemeName(theme) {
63
+ saveConfig({ theme });
64
+ }
@@ -0,0 +1,6 @@
1
+ import Database from 'better-sqlite3';
2
+ import * as schema from './schema.js';
3
+ export declare function getDb(): import("drizzle-orm/better-sqlite3").BetterSQLite3Database<typeof schema> & {
4
+ $client: Database.Database;
5
+ };
6
+ export { schema };
@@ -0,0 +1,72 @@
1
+ import Database from 'better-sqlite3';
2
+ import { drizzle } from 'drizzle-orm/better-sqlite3';
3
+ import { mkdirSync, existsSync } from 'fs';
4
+ import { dirname } from 'path';
5
+ import * as schema from './schema.js';
6
+ import { getDbPath } from '../config.js';
7
+ function ensureDbDir(dbPath) {
8
+ const dbDir = dirname(dbPath);
9
+ if (!existsSync(dbDir)) {
10
+ mkdirSync(dbDir, { recursive: true });
11
+ }
12
+ }
13
+ function initializeSchema(sqlite) {
14
+ // Check if we need to migrate from old schema
15
+ const tableInfo = sqlite.prepare("PRAGMA table_info(tasks)").all();
16
+ const hasProjectId = tableInfo.some(col => col.name === 'project_id');
17
+ const hasIsProject = tableInfo.some(col => col.name === 'is_project');
18
+ const tableExists = tableInfo.length > 0;
19
+ if (tableExists && hasProjectId && !hasIsProject) {
20
+ // Migration: old schema -> new schema
21
+ // Add new columns
22
+ sqlite.prepare("ALTER TABLE tasks ADD COLUMN is_project INTEGER NOT NULL DEFAULT 0").run();
23
+ sqlite.prepare("ALTER TABLE tasks ADD COLUMN parent_id TEXT").run();
24
+ // Migrate: convert projects to tasks with is_project=1
25
+ const projects = sqlite.prepare("SELECT * FROM projects").all();
26
+ const insertStmt = sqlite.prepare(`
27
+ INSERT INTO tasks (id, title, description, status, is_project, parent_id, waiting_for, due_date, created_at, updated_at)
28
+ VALUES (?, ?, ?, ?, 1, NULL, NULL, NULL, ?, ?)
29
+ `);
30
+ for (const p of projects) {
31
+ const newStatus = p.status === 'active' ? 'next' : (p.status === 'completed' ? 'done' : p.status);
32
+ insertStmt.run(p.id, p.name, p.description, newStatus, p.created_at, p.updated_at);
33
+ }
34
+ // Update parent_id from old project_id
35
+ sqlite.prepare("UPDATE tasks SET parent_id = project_id WHERE project_id IS NOT NULL").run();
36
+ // Create new indexes
37
+ sqlite.prepare("CREATE INDEX IF NOT EXISTS idx_tasks_parent_id ON tasks(parent_id)").run();
38
+ sqlite.prepare("CREATE INDEX IF NOT EXISTS idx_tasks_is_project ON tasks(is_project)").run();
39
+ }
40
+ else if (!tableExists) {
41
+ // Fresh install: create new schema
42
+ sqlite.prepare(`
43
+ CREATE TABLE IF NOT EXISTS tasks (
44
+ id TEXT PRIMARY KEY,
45
+ title TEXT NOT NULL,
46
+ description TEXT,
47
+ status TEXT NOT NULL DEFAULT 'inbox' CHECK(status IN ('inbox', 'next', 'waiting', 'someday', 'done')),
48
+ is_project INTEGER NOT NULL DEFAULT 0,
49
+ parent_id TEXT,
50
+ waiting_for TEXT,
51
+ due_date INTEGER,
52
+ created_at INTEGER NOT NULL,
53
+ updated_at INTEGER NOT NULL
54
+ )
55
+ `).run();
56
+ sqlite.prepare("CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)").run();
57
+ sqlite.prepare("CREATE INDEX IF NOT EXISTS idx_tasks_parent_id ON tasks(parent_id)").run();
58
+ sqlite.prepare("CREATE INDEX IF NOT EXISTS idx_tasks_is_project ON tasks(is_project)").run();
59
+ }
60
+ }
61
+ let dbInstance = null;
62
+ export function getDb() {
63
+ if (!dbInstance) {
64
+ const dbPath = getDbPath();
65
+ ensureDbDir(dbPath);
66
+ const sqlite = new Database(dbPath);
67
+ initializeSchema(sqlite);
68
+ dbInstance = drizzle(sqlite, { schema });
69
+ }
70
+ return dbInstance;
71
+ }
72
+ export { schema };
@@ -0,0 +1,192 @@
1
+ export declare const tasks: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
2
+ name: "tasks";
3
+ schema: undefined;
4
+ columns: {
5
+ id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
6
+ name: "id";
7
+ tableName: "tasks";
8
+ dataType: "string";
9
+ columnType: "SQLiteText";
10
+ data: string;
11
+ driverParam: string;
12
+ notNull: true;
13
+ hasDefault: false;
14
+ isPrimaryKey: true;
15
+ isAutoincrement: false;
16
+ hasRuntimeDefault: false;
17
+ enumValues: [string, ...string[]];
18
+ baseColumn: never;
19
+ identity: undefined;
20
+ generated: undefined;
21
+ }, {}, {
22
+ length: number | undefined;
23
+ }>;
24
+ title: import("drizzle-orm/sqlite-core").SQLiteColumn<{
25
+ name: "title";
26
+ tableName: "tasks";
27
+ dataType: "string";
28
+ columnType: "SQLiteText";
29
+ data: string;
30
+ driverParam: string;
31
+ notNull: true;
32
+ hasDefault: false;
33
+ isPrimaryKey: false;
34
+ isAutoincrement: false;
35
+ hasRuntimeDefault: false;
36
+ enumValues: [string, ...string[]];
37
+ baseColumn: never;
38
+ identity: undefined;
39
+ generated: undefined;
40
+ }, {}, {
41
+ length: number | undefined;
42
+ }>;
43
+ description: import("drizzle-orm/sqlite-core").SQLiteColumn<{
44
+ name: "description";
45
+ tableName: "tasks";
46
+ dataType: "string";
47
+ columnType: "SQLiteText";
48
+ data: string;
49
+ driverParam: string;
50
+ notNull: false;
51
+ hasDefault: false;
52
+ isPrimaryKey: false;
53
+ isAutoincrement: false;
54
+ hasRuntimeDefault: false;
55
+ enumValues: [string, ...string[]];
56
+ baseColumn: never;
57
+ identity: undefined;
58
+ generated: undefined;
59
+ }, {}, {
60
+ length: number | undefined;
61
+ }>;
62
+ status: import("drizzle-orm/sqlite-core").SQLiteColumn<{
63
+ name: "status";
64
+ tableName: "tasks";
65
+ dataType: "string";
66
+ columnType: "SQLiteText";
67
+ data: "inbox" | "next" | "waiting" | "someday" | "done";
68
+ driverParam: string;
69
+ notNull: true;
70
+ hasDefault: true;
71
+ isPrimaryKey: false;
72
+ isAutoincrement: false;
73
+ hasRuntimeDefault: false;
74
+ enumValues: ["inbox", "next", "waiting", "someday", "done"];
75
+ baseColumn: never;
76
+ identity: undefined;
77
+ generated: undefined;
78
+ }, {}, {
79
+ length: number | undefined;
80
+ }>;
81
+ isProject: import("drizzle-orm/sqlite-core").SQLiteColumn<{
82
+ name: "is_project";
83
+ tableName: "tasks";
84
+ dataType: "boolean";
85
+ columnType: "SQLiteBoolean";
86
+ data: boolean;
87
+ driverParam: number;
88
+ notNull: true;
89
+ hasDefault: true;
90
+ isPrimaryKey: false;
91
+ isAutoincrement: false;
92
+ hasRuntimeDefault: false;
93
+ enumValues: undefined;
94
+ baseColumn: never;
95
+ identity: undefined;
96
+ generated: undefined;
97
+ }, {}, {}>;
98
+ parentId: import("drizzle-orm/sqlite-core").SQLiteColumn<{
99
+ name: "parent_id";
100
+ tableName: "tasks";
101
+ dataType: "string";
102
+ columnType: "SQLiteText";
103
+ data: string;
104
+ driverParam: string;
105
+ notNull: false;
106
+ hasDefault: false;
107
+ isPrimaryKey: false;
108
+ isAutoincrement: false;
109
+ hasRuntimeDefault: false;
110
+ enumValues: [string, ...string[]];
111
+ baseColumn: never;
112
+ identity: undefined;
113
+ generated: undefined;
114
+ }, {}, {
115
+ length: number | undefined;
116
+ }>;
117
+ waitingFor: import("drizzle-orm/sqlite-core").SQLiteColumn<{
118
+ name: "waiting_for";
119
+ tableName: "tasks";
120
+ dataType: "string";
121
+ columnType: "SQLiteText";
122
+ data: string;
123
+ driverParam: string;
124
+ notNull: false;
125
+ hasDefault: false;
126
+ isPrimaryKey: false;
127
+ isAutoincrement: false;
128
+ hasRuntimeDefault: false;
129
+ enumValues: [string, ...string[]];
130
+ baseColumn: never;
131
+ identity: undefined;
132
+ generated: undefined;
133
+ }, {}, {
134
+ length: number | undefined;
135
+ }>;
136
+ dueDate: import("drizzle-orm/sqlite-core").SQLiteColumn<{
137
+ name: "due_date";
138
+ tableName: "tasks";
139
+ dataType: "date";
140
+ columnType: "SQLiteTimestamp";
141
+ data: Date;
142
+ driverParam: number;
143
+ notNull: false;
144
+ hasDefault: false;
145
+ isPrimaryKey: false;
146
+ isAutoincrement: false;
147
+ hasRuntimeDefault: false;
148
+ enumValues: undefined;
149
+ baseColumn: never;
150
+ identity: undefined;
151
+ generated: undefined;
152
+ }, {}, {}>;
153
+ createdAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
154
+ name: "created_at";
155
+ tableName: "tasks";
156
+ dataType: "date";
157
+ columnType: "SQLiteTimestamp";
158
+ data: Date;
159
+ driverParam: number;
160
+ notNull: true;
161
+ hasDefault: false;
162
+ isPrimaryKey: false;
163
+ isAutoincrement: false;
164
+ hasRuntimeDefault: false;
165
+ enumValues: undefined;
166
+ baseColumn: never;
167
+ identity: undefined;
168
+ generated: undefined;
169
+ }, {}, {}>;
170
+ updatedAt: import("drizzle-orm/sqlite-core").SQLiteColumn<{
171
+ name: "updated_at";
172
+ tableName: "tasks";
173
+ dataType: "date";
174
+ columnType: "SQLiteTimestamp";
175
+ data: Date;
176
+ driverParam: number;
177
+ notNull: true;
178
+ hasDefault: false;
179
+ isPrimaryKey: false;
180
+ isAutoincrement: false;
181
+ hasRuntimeDefault: false;
182
+ enumValues: undefined;
183
+ baseColumn: never;
184
+ identity: undefined;
185
+ generated: undefined;
186
+ }, {}, {}>;
187
+ };
188
+ dialect: "sqlite";
189
+ }>;
190
+ export type Task = typeof tasks.$inferSelect;
191
+ export type NewTask = typeof tasks.$inferInsert;
192
+ export type TaskStatus = 'inbox' | 'next' | 'waiting' | 'someday' | 'done';
@@ -0,0 +1,13 @@
1
+ import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
2
+ export const tasks = sqliteTable('tasks', {
3
+ id: text('id').primaryKey(),
4
+ title: text('title').notNull(),
5
+ description: text('description'),
6
+ status: text('status', { enum: ['inbox', 'next', 'waiting', 'someday', 'done'] }).notNull().default('inbox'),
7
+ isProject: integer('is_project', { mode: 'boolean' }).notNull().default(false),
8
+ parentId: text('parent_id'),
9
+ waitingFor: text('waiting_for'),
10
+ dueDate: integer('due_date', { mode: 'timestamp' }),
11
+ createdAt: integer('created_at', { mode: 'timestamp' }).notNull(),
12
+ updatedAt: integer('updated_at', { mode: 'timestamp' }).notNull(),
13
+ });