floq 0.0.1 → 0.1.0

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/README.ja.md CHANGED
@@ -9,6 +9,7 @@ MS-DOSスタイルのテーマを備えたターミナルベースのGTD(Getti
9
9
  - **TUIインターフェース**: Ink(CLI用React)で構築されたインタラクティブなターミナルUI
10
10
  - **GTDワークフロー**: Inbox、Next Actions、Waiting For、Someday/Maybe
11
11
  - **プロジェクト**: タスクをプロジェクトに整理
12
+ - **クラウド同期**: [Turso](https://turso.tech/)のembedded replicasによるオプションの同期機能
12
13
  - **テーマ**: MS-DOSノスタルジックスタイルを含む複数テーマ
13
14
  - **多言語対応**: 英語・日本語サポート
14
15
  - **Vimスタイルナビゲーション**: hjklまたは矢印キーで操作
@@ -16,6 +17,14 @@ MS-DOSスタイルのテーマを備えたターミナルベースのGTD(Getti
16
17
  ## インストール
17
18
 
18
19
  ```bash
20
+ npm install -g floq
21
+ ```
22
+
23
+ ### ソースからインストール
24
+
25
+ ```bash
26
+ git clone https://github.com/polidog/gtd-cli.git
27
+ cd gtd-cli
19
28
  npm install
20
29
  npm run build
21
30
  npm link
@@ -89,39 +98,78 @@ floq config show
89
98
  floq config lang en # 英語
90
99
  floq config lang ja # 日本語
91
100
 
92
- # テーマ設定
101
+ # テーマ設定(j/kで選択するインタラクティブセレクター)
102
+ floq config theme
103
+
104
+ # または直接指定
93
105
  floq config theme modern # デフォルト
94
- floq config theme norton-commander # MS-DOSスタイル
95
- floq config theme dos-prompt # 緑テキスト
96
- floq config theme turbo-pascal # IDEスタイル
106
+ floq config theme synthwave # ネオン80sスタイル
97
107
 
98
108
  # データベースパス設定
99
109
  floq config db /path/to/custom.db
100
110
  floq config db # デフォルトに戻す
101
111
  ```
102
112
 
103
- ## テーマ
113
+ ## クラウド同期(Turso)
114
+
115
+ Floqは[Turso](https://turso.tech/)を使用したクラウド同期をサポートしています。Embedded replicasにより、データはクラウドに同期されつつ、オフラインでも利用可能です。
116
+
117
+ ### セットアップ
118
+
119
+ 1. [turso.tech](https://turso.tech/)でデータベースを作成
120
+ 2. データベースURLと認証トークンを取得
121
+ 3. Floqを設定:
104
122
 
105
- ### modern(デフォルト)
106
- シンプルでクリーンなスタイル。シングルボーダー。
123
+ ```bash
124
+ # Turso同期を有効化
125
+ floq config turso --url libsql://your-db.turso.io --token your-auth-token
126
+
127
+ # 設定確認
128
+ floq config show
107
129
 
108
- ### norton-commander
109
- - ダブルラインボーダー(╔═╗║╚═╝)
110
- - 大文字ヘッダー
111
- - 画面下部にファンクションキーバー
112
- - シアン/黄色のカラースキーム
130
+ # 手動同期
131
+ floq sync
132
+
133
+ # Turso同期を無効化
134
+ floq config turso --disable
135
+ ```
113
136
 
114
- ### dos-prompt
115
- - シングルラインボーダー
116
- - 緑テキスト(CRTモニター風)
117
- - シンプルな `>` 選択インジケータ
137
+ ### 仕組み
118
138
 
119
- ### turbo-pascal
120
- - ダブルラインボーダー
121
- - 黄色のアクセント
122
- - IDE風の外観
139
+ - **Embedded Replicas**: ローカルSQLiteデータベースがTursoクラウドと同期
140
+ - **オフラインサポート**: オフラインでも動作し、接続時に同期
141
+ - **自動同期**: オンライン時は60秒ごとにバックグラウンド同期
142
+ - **データベース分離**: Tursoモードは`gtd-turso.db`を使用し、ローカルDBと競合しない
143
+
144
+ ### ステータス表示
145
+
146
+ - TUIヘッダーに接続状態を表示(Tursoはクラウドアイコン、ローカルはローカルアイコン)
147
+ - CLIコマンド実行時、Turso有効時は`🔄 Turso sync: hostname`を表示
148
+
149
+ ## テーマ
123
150
 
124
- > **注意**: 背景色はターミナルの設定に依存します。完全なDOS体験のためには、ターミナルの背景色を青(#0000AA)に設定してください。
151
+ 16種類のテーマが利用可能。`floq config theme` でインタラクティブに選択(j/kで移動)。
152
+
153
+ | テーマ | 説明 |
154
+ |--------|------|
155
+ | `modern` | シンプルでクリーン(デフォルト) |
156
+ | `norton-commander` | MS-DOSファイルマネージャー風 |
157
+ | `dos-prompt` | 緑のCRTモニター |
158
+ | `turbo-pascal` | Borland IDE風 |
159
+ | `classic-mac` | Macintosh System 7モノクロ |
160
+ | `apple-ii` | Apple ][ グリーンモニター |
161
+ | `commodore-64` | C64の青紫カラー |
162
+ | `amiga-workbench` | Amigaのオレンジ&ブルー |
163
+ | `matrix` | デジタルレイン風グリーン |
164
+ | `amber-crt` | 琥珀色モニター |
165
+ | `phosphor` | CRT残光エフェクト |
166
+ | `solarized-dark` | Solarizedダーク |
167
+ | `solarized-light` | Solarizedライト |
168
+ | `synthwave` | ネオン80sスタイル |
169
+ | `paper` | 紙とインク風ライト |
170
+ | `coffee` | 暖かみのある茶系 |
171
+
172
+ > **注意**: 背景色はターミナルの設定に依存します。
125
173
 
126
174
  ## データ保存場所
127
175
 
package/README.md CHANGED
@@ -9,6 +9,7 @@ A terminal-based GTD (Getting Things Done) task manager with MS-DOS style themes
9
9
  - **TUI Interface**: Interactive terminal UI built with Ink (React for CLI)
10
10
  - **GTD Workflow**: Inbox, Next Actions, Waiting For, Someday/Maybe
11
11
  - **Projects**: Organize tasks into projects
12
+ - **Cloud Sync**: Optional sync with [Turso](https://turso.tech/) using embedded replicas
12
13
  - **Themes**: Multiple themes including MS-DOS nostalgic styles
13
14
  - **i18n**: English and Japanese support
14
15
  - **Vim-style Navigation**: Use hjkl or arrow keys
@@ -16,6 +17,14 @@ A terminal-based GTD (Getting Things Done) task manager with MS-DOS style themes
16
17
  ## Installation
17
18
 
18
19
  ```bash
20
+ npm install -g floq
21
+ ```
22
+
23
+ ### From Source
24
+
25
+ ```bash
26
+ git clone https://github.com/polidog/gtd-cli.git
27
+ cd gtd-cli
19
28
  npm install
20
29
  npm run build
21
30
  npm link
@@ -89,39 +98,78 @@ floq config show
89
98
  floq config lang en # English
90
99
  floq config lang ja # Japanese
91
100
 
92
- # Set theme
101
+ # Set theme (interactive selector with j/k navigation)
102
+ floq config theme
103
+
104
+ # Or specify directly
93
105
  floq config theme modern # Default
94
- floq config theme norton-commander # MS-DOS style
95
- floq config theme dos-prompt # Green on black
96
- floq config theme turbo-pascal # IDE style
106
+ floq config theme synthwave # Neon 80s aesthetic
97
107
 
98
108
  # Set database path
99
109
  floq config db /path/to/custom.db
100
110
  floq config db # Reset to default
101
111
  ```
102
112
 
103
- ## Themes
113
+ ## Cloud Sync (Turso)
114
+
115
+ Floq supports cloud synchronization using [Turso](https://turso.tech/), a SQLite-compatible database service. With embedded replicas, your data syncs to the cloud while remaining available offline.
116
+
117
+ ### Setup
118
+
119
+ 1. Create a Turso database at [turso.tech](https://turso.tech/)
120
+ 2. Get your database URL and auth token
121
+ 3. Configure Floq:
104
122
 
105
- ### modern (default)
106
- Clean, minimal style with single borders.
123
+ ```bash
124
+ # Enable Turso sync
125
+ floq config turso --url libsql://your-db.turso.io --token your-auth-token
126
+
127
+ # Check configuration
128
+ floq config show
107
129
 
108
- ### norton-commander
109
- - Double-line borders (╔═╗║╚═╝)
110
- - Uppercase headers
111
- - Function key bar at bottom
112
- - Cyan/yellow color scheme
130
+ # Manual sync
131
+ floq sync
132
+
133
+ # Disable Turso sync
134
+ floq config turso --disable
135
+ ```
113
136
 
114
- ### dos-prompt
115
- - Single-line borders
116
- - Green text (CRT monitor style)
117
- - Simple `>` selection indicator
137
+ ### How It Works
118
138
 
119
- ### turbo-pascal
120
- - Double-line borders
121
- - Yellow accents
122
- - IDE-style appearance
139
+ - **Embedded Replicas**: Local SQLite database syncs with Turso cloud
140
+ - **Offline Support**: Works offline, syncs when connected
141
+ - **Auto Sync**: Background sync every 60 seconds when online
142
+ - **Separate Database**: Turso mode uses `gtd-turso.db` to avoid conflicts
143
+
144
+ ### Status Indicator
145
+
146
+ - TUI header shows connection status (cloud icon for Turso, local icon for local mode)
147
+ - CLI commands display `🔄 Turso sync: hostname` when Turso is enabled
148
+
149
+ ## Themes
123
150
 
124
- > **Note**: Background colors depend on your terminal settings. For the full DOS experience, configure your terminal's background color to blue (#0000AA).
151
+ 16 themes available. Use `floq config theme` for interactive selection (j/k to navigate).
152
+
153
+ | Theme | Description |
154
+ |-------|-------------|
155
+ | `modern` | Clean, minimal style (default) |
156
+ | `norton-commander` | MS-DOS file manager style |
157
+ | `dos-prompt` | Green CRT monitor |
158
+ | `turbo-pascal` | Borland IDE style |
159
+ | `classic-mac` | Macintosh System 7 monochrome |
160
+ | `apple-ii` | Apple ][ green phosphor |
161
+ | `commodore-64` | C64 blue/purple palette |
162
+ | `amiga-workbench` | Amiga orange & blue |
163
+ | `matrix` | Digital rain green |
164
+ | `amber-crt` | Amber monitor |
165
+ | `phosphor` | CRT phosphor glow |
166
+ | `solarized-dark` | Solarized dark palette |
167
+ | `solarized-light` | Solarized light palette |
168
+ | `synthwave` | Neon 80s aesthetic |
169
+ | `paper` | Light minimal theme |
170
+ | `coffee` | Warm brown tones |
171
+
172
+ > **Note**: Background colors depend on your terminal settings.
125
173
 
126
174
  ## Data Storage
127
175
 
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import { listTasks, listProjects } from './commands/list.js';
7
7
  import { moveTask } from './commands/move.js';
8
8
  import { markDone } from './commands/done.js';
9
9
  import { addProject, listProjectsCommand, showProject, completeProject, } from './commands/project.js';
10
- import { showConfig, setLanguage, setDbPath, resetDbPath, setTheme, selectTheme } from './commands/config.js';
10
+ import { showConfig, setLanguage, setDbPath, resetDbPath, setTheme, selectTheme, setTurso, disableTurso, syncCommand } from './commands/config.js';
11
11
  import { VERSION } from './version.js';
12
12
  const program = new Command();
13
13
  program
@@ -121,4 +121,30 @@ configCmd
121
121
  await selectTheme();
122
122
  }
123
123
  });
124
+ configCmd
125
+ .command('turso')
126
+ .description('Configure Turso cloud sync')
127
+ .option('--url <url>', 'Turso database URL (libsql://xxx.turso.io)')
128
+ .option('--token <token>', 'Turso auth token')
129
+ .option('--disable', 'Disable Turso sync')
130
+ .action(async (options) => {
131
+ if (options.disable) {
132
+ await disableTurso();
133
+ }
134
+ else if (options.url && options.token) {
135
+ await setTurso(options.url, options.token);
136
+ }
137
+ else {
138
+ console.error('Usage: floq config turso --url <url> --token <token>');
139
+ console.error(' floq config turso --disable');
140
+ process.exit(1);
141
+ }
142
+ });
143
+ // Sync command
144
+ program
145
+ .command('sync')
146
+ .description('Sync with Turso cloud')
147
+ .action(async () => {
148
+ await syncCommand();
149
+ });
124
150
  export { program };
@@ -8,16 +8,15 @@ export async function addTask(title, options) {
8
8
  const i18n = t();
9
9
  let parentId;
10
10
  if (options.project) {
11
- const project = db
11
+ const projects = await db
12
12
  .select()
13
13
  .from(schema.tasks)
14
- .where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.title, options.project)))
15
- .get();
16
- if (!project) {
14
+ .where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.title, options.project)));
15
+ if (projects.length === 0) {
17
16
  console.error(fmt(i18n.commands.add.projectNotFound, { project: options.project }));
18
17
  process.exit(1);
19
18
  }
20
- parentId = project.id;
19
+ parentId = projects[0].id;
21
20
  }
22
21
  const task = {
23
22
  id: uuidv4(),
@@ -28,7 +27,7 @@ export async function addTask(title, options) {
28
27
  createdAt: now,
29
28
  updatedAt: now,
30
29
  };
31
- db.insert(schema.tasks).values(task).run();
30
+ await db.insert(schema.tasks).values(task);
32
31
  console.log(fmt(i18n.commands.add.success, { title }));
33
32
  if (parentId) {
34
33
  console.log(fmt(i18n.commands.add.withProject, { project: options.project }));
@@ -4,3 +4,6 @@ export declare function setDbPath(dbPath: string): Promise<void>;
4
4
  export declare function resetDbPath(): Promise<void>;
5
5
  export declare function setTheme(theme: string): Promise<void>;
6
6
  export declare function selectTheme(): Promise<void>;
7
+ export declare function setTurso(url: string, token: string): Promise<void>;
8
+ export declare function disableTurso(): Promise<void>;
9
+ export declare function syncCommand(): Promise<void>;
@@ -1,10 +1,11 @@
1
1
  import { render } from 'ink';
2
2
  import React from 'react';
3
- import { loadConfig, saveConfig, getDbPath } from '../config.js';
3
+ import { loadConfig, saveConfig, getDbPath, isTursoEnabled, setTursoConfig } from '../config.js';
4
4
  import { CONFIG_FILE } from '../paths.js';
5
5
  import { ThemeSelector } from '../ui/ThemeSelector.js';
6
+ import { syncDb } from '../db/index.js';
7
+ import { VALID_THEMES, themes } from '../ui/theme/themes.js';
6
8
  const VALID_LOCALES = ['en', 'ja'];
7
- const VALID_THEMES = ['modern', 'norton-commander', 'dos-prompt', 'turbo-pascal'];
8
9
  export async function showConfig() {
9
10
  const config = loadConfig();
10
11
  console.log('GTD CLI Configuration');
@@ -13,9 +14,13 @@ export async function showConfig() {
13
14
  console.log(`Language: ${config.locale}`);
14
15
  console.log(`Database: ${getDbPath()}`);
15
16
  console.log(`Theme: ${config.theme || 'modern'}`);
17
+ console.log(`Turso: ${isTursoEnabled() ? 'enabled' : 'disabled'}`);
16
18
  if (config.db_path) {
17
19
  console.log(` (custom: ${config.db_path})`);
18
20
  }
21
+ if (config.turso) {
22
+ console.log(` URL: ${config.turso.url}`);
23
+ }
19
24
  }
20
25
  export async function setLanguage(locale) {
21
26
  if (!VALID_LOCALES.includes(locale)) {
@@ -45,13 +50,8 @@ export async function setTheme(theme) {
45
50
  process.exit(1);
46
51
  }
47
52
  saveConfig({ theme: theme });
48
- const messages = {
49
- 'modern': 'Theme set to Modern',
50
- 'norton-commander': 'Theme set to Norton Commander (MS-DOS style)',
51
- 'dos-prompt': 'Theme set to DOS Prompt (green on black)',
52
- 'turbo-pascal': 'Theme set to Turbo Pascal IDE',
53
- };
54
- console.log(messages[theme]);
53
+ const themeData = themes[theme];
54
+ console.log(`Theme set to ${themeData.displayName}`);
55
55
  }
56
56
  export async function selectTheme() {
57
57
  return new Promise((resolve) => {
@@ -59,15 +59,42 @@ export async function selectTheme() {
59
59
  onSelect: (theme) => {
60
60
  unmount();
61
61
  saveConfig({ theme });
62
- const messages = {
63
- 'modern': 'Theme set to Modern',
64
- 'norton-commander': 'Theme set to Norton Commander (MS-DOS style)',
65
- 'dos-prompt': 'Theme set to DOS Prompt (green on black)',
66
- 'turbo-pascal': 'Theme set to Turbo Pascal IDE',
67
- };
68
- console.log(messages[theme]);
62
+ const themeData = themes[theme];
63
+ console.log(`Theme set to ${themeData.displayName}`);
69
64
  resolve();
70
65
  },
71
66
  }));
72
67
  });
73
68
  }
69
+ export async function setTurso(url, token) {
70
+ setTursoConfig({ url, authToken: token });
71
+ console.log('Turso sync enabled');
72
+ console.log(` URL: ${url}`);
73
+ console.log('Run "floq sync" to sync with Turso cloud');
74
+ }
75
+ export async function disableTurso() {
76
+ setTursoConfig(undefined);
77
+ console.log('Turso sync disabled');
78
+ }
79
+ export async function syncCommand() {
80
+ if (!isTursoEnabled()) {
81
+ console.error('Turso sync is not enabled.');
82
+ console.error('Use "floq config turso --url <url> --token <token>" to enable.');
83
+ process.exit(1);
84
+ }
85
+ console.log('Syncing with Turso cloud...');
86
+ try {
87
+ await syncDb();
88
+ console.log('Sync complete');
89
+ }
90
+ catch (error) {
91
+ const message = error instanceof Error ? error.message : String(error);
92
+ console.error(`Sync failed: ${message}`);
93
+ console.error('');
94
+ console.error('Possible solutions:');
95
+ console.error(' 1. Check your Turso URL and auth token');
96
+ console.error(' 2. Verify network connectivity');
97
+ console.error(' 3. Try again later');
98
+ process.exit(1);
99
+ }
100
+ }
@@ -5,11 +5,10 @@ export async function markDone(taskId) {
5
5
  const db = getDb();
6
6
  const i18n = t();
7
7
  // Find task by ID prefix
8
- const tasks = db
8
+ const tasks = await db
9
9
  .select()
10
10
  .from(schema.tasks)
11
- .where(like(schema.tasks.id, `${taskId}%`))
12
- .all();
11
+ .where(like(schema.tasks.id, `${taskId}%`));
13
12
  if (tasks.length === 0) {
14
13
  console.error(fmt(i18n.commands.done.notFound, { id: taskId }));
15
14
  process.exit(1);
@@ -26,12 +25,11 @@ export async function markDone(taskId) {
26
25
  console.log(fmt(i18n.commands.done.alreadyDone, { title: task.title }));
27
26
  return;
28
27
  }
29
- db.update(schema.tasks)
28
+ await db.update(schema.tasks)
30
29
  .set({
31
30
  status: 'done',
32
31
  updatedAt: new Date(),
33
32
  })
34
- .where(eq(schema.tasks.id, task.id))
35
- .run();
33
+ .where(eq(schema.tasks.id, task.id));
36
34
  console.log(fmt(i18n.commands.done.success, { title: task.title }));
37
35
  }
@@ -11,11 +11,10 @@ export async function listTasks(status) {
11
11
  console.error(fmt(i18n.commands.list.validStatuses, { statuses: validStatuses.join(', ') }));
12
12
  process.exit(1);
13
13
  }
14
- const tasks = db
14
+ const tasks = await db
15
15
  .select()
16
16
  .from(schema.tasks)
17
- .where(eq(schema.tasks.status, status))
18
- .all();
17
+ .where(eq(schema.tasks.status, status));
19
18
  console.log(`\n${i18n.status[status]} (${tasks.length})`);
20
19
  console.log('─'.repeat(40));
21
20
  if (tasks.length === 0) {
@@ -40,11 +39,10 @@ export async function listTasks(status) {
40
39
  // Show all lists
41
40
  const statuses = ['inbox', 'next', 'waiting', 'someday'];
42
41
  for (const s of statuses) {
43
- const tasks = db
42
+ const tasks = await db
44
43
  .select()
45
44
  .from(schema.tasks)
46
- .where(eq(schema.tasks.status, s))
47
- .all();
45
+ .where(eq(schema.tasks.status, s));
48
46
  console.log(`\n${i18n.status[s]} (${tasks.length})`);
49
47
  console.log('─'.repeat(40));
50
48
  if (tasks.length === 0) {
@@ -66,12 +64,11 @@ export async function listTasks(status) {
66
64
  export async function listProjects() {
67
65
  const db = getDb();
68
66
  const i18n = t();
69
- const projects = db
67
+ const allProjects = await db
70
68
  .select()
71
69
  .from(schema.tasks)
72
- .where(eq(schema.tasks.isProject, true))
73
- .all()
74
- .filter(p => p.status !== 'done');
70
+ .where(eq(schema.tasks.isProject, true));
71
+ const projects = allProjects.filter(p => p.status !== 'done');
75
72
  console.log(`\n${i18n.projectStatus.active} (${projects.length})`);
76
73
  console.log('─'.repeat(40));
77
74
  if (projects.length === 0) {
@@ -79,11 +76,10 @@ export async function listProjects() {
79
76
  }
80
77
  else {
81
78
  for (const project of projects) {
82
- const childTasks = db
79
+ const childTasks = await db
83
80
  .select()
84
81
  .from(schema.tasks)
85
- .where(eq(schema.tasks.parentId, project.id))
86
- .all();
82
+ .where(eq(schema.tasks.parentId, project.id));
87
83
  const activeTasks = childTasks.filter(t => t.status !== 'done').length;
88
84
  const shortId = project.id.slice(0, 8);
89
85
  console.log(` [${shortId}] ${project.title} (${fmt(i18n.commands.list.tasks, { count: activeTasks })})`);
@@ -15,11 +15,10 @@ export async function moveTask(taskId, targetStatus, waitingFor) {
15
15
  process.exit(1);
16
16
  }
17
17
  // Find task by ID prefix
18
- const tasks = db
18
+ const tasks = await db
19
19
  .select()
20
20
  .from(schema.tasks)
21
- .where(like(schema.tasks.id, `${taskId}%`))
22
- .all();
21
+ .where(like(schema.tasks.id, `${taskId}%`));
23
22
  if (tasks.length === 0) {
24
23
  console.error(fmt(i18n.commands.move.notFound, { id: taskId }));
25
24
  process.exit(1);
@@ -32,14 +31,13 @@ export async function moveTask(taskId, targetStatus, waitingFor) {
32
31
  process.exit(1);
33
32
  }
34
33
  const task = tasks[0];
35
- db.update(schema.tasks)
34
+ await db.update(schema.tasks)
36
35
  .set({
37
36
  status: targetStatus,
38
37
  waitingFor: targetStatus === 'waiting' ? waitingFor : null,
39
38
  updatedAt: new Date(),
40
39
  })
41
- .where(eq(schema.tasks.id, task.id))
42
- .run();
40
+ .where(eq(schema.tasks.id, task.id));
43
41
  console.log(fmt(i18n.commands.move.success, {
44
42
  title: task.title,
45
43
  status: i18n.status[targetStatus]
@@ -7,12 +7,11 @@ export async function addProject(name, options) {
7
7
  const now = new Date();
8
8
  const i18n = t();
9
9
  // Check if project already exists
10
- const existing = db
10
+ const existingProjects = await db
11
11
  .select()
12
12
  .from(schema.tasks)
13
- .where(and(eq(schema.tasks.title, name), eq(schema.tasks.isProject, true)))
14
- .get();
15
- if (existing) {
13
+ .where(and(eq(schema.tasks.title, name), eq(schema.tasks.isProject, true)));
14
+ if (existingProjects.length > 0) {
16
15
  console.error(fmt(i18n.commands.project.alreadyExists, { name }));
17
16
  process.exit(1);
18
17
  }
@@ -25,7 +24,7 @@ export async function addProject(name, options) {
25
24
  createdAt: now,
26
25
  updatedAt: now,
27
26
  };
28
- db.insert(schema.tasks).values(project).run();
27
+ await db.insert(schema.tasks).values(project);
29
28
  console.log(fmt(i18n.commands.project.created, { name }));
30
29
  }
31
30
  export async function listProjectsCommand() {
@@ -38,11 +37,10 @@ export async function listProjectsCommand() {
38
37
  done: i18n.projectStatus.completed,
39
38
  };
40
39
  for (const status of statuses) {
41
- const projects = db
40
+ const projects = await db
42
41
  .select()
43
42
  .from(schema.tasks)
44
- .where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.status, status)))
45
- .all();
43
+ .where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.status, status)));
46
44
  if (projects.length === 0 && status !== 'next')
47
45
  continue;
48
46
  console.log(`\n${statusLabels[status]} (${projects.length})`);
@@ -52,11 +50,10 @@ export async function listProjectsCommand() {
52
50
  }
53
51
  else {
54
52
  for (const project of projects) {
55
- const childTasks = db
53
+ const childTasks = await db
56
54
  .select()
57
55
  .from(schema.tasks)
58
- .where(eq(schema.tasks.parentId, project.id))
59
- .all();
56
+ .where(eq(schema.tasks.parentId, project.id));
60
57
  const activeTasks = childTasks.filter(t => t.status !== 'done').length;
61
58
  const doneTasks = childTasks.filter(t => t.status === 'done').length;
62
59
  const shortId = project.id.slice(0, 8);
@@ -73,17 +70,15 @@ export async function showProject(projectId) {
73
70
  const db = getDb();
74
71
  const i18n = t();
75
72
  // Find project by ID prefix or name
76
- let projects = db
73
+ let projects = await db
77
74
  .select()
78
75
  .from(schema.tasks)
79
- .where(and(eq(schema.tasks.isProject, true), like(schema.tasks.id, `${projectId}%`)))
80
- .all();
76
+ .where(and(eq(schema.tasks.isProject, true), like(schema.tasks.id, `${projectId}%`)));
81
77
  if (projects.length === 0) {
82
- projects = db
78
+ projects = await db
83
79
  .select()
84
80
  .from(schema.tasks)
85
- .where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.title, projectId)))
86
- .all();
81
+ .where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.title, projectId)));
87
82
  }
88
83
  if (projects.length === 0) {
89
84
  console.error(fmt(i18n.commands.project.notFound, { id: projectId }));
@@ -97,11 +92,10 @@ export async function showProject(projectId) {
97
92
  process.exit(1);
98
93
  }
99
94
  const project = projects[0];
100
- const childTasks = db
95
+ const childTasks = await db
101
96
  .select()
102
97
  .from(schema.tasks)
103
- .where(eq(schema.tasks.parentId, project.id))
104
- .all();
98
+ .where(eq(schema.tasks.parentId, project.id));
105
99
  console.log(`\nProject: ${project.title}`);
106
100
  console.log('─'.repeat(40));
107
101
  if (project.description) {
@@ -135,11 +129,10 @@ export async function showProject(projectId) {
135
129
  export async function completeProject(projectId) {
136
130
  const db = getDb();
137
131
  const i18n = t();
138
- const projects = db
132
+ const projects = await db
139
133
  .select()
140
134
  .from(schema.tasks)
141
- .where(and(eq(schema.tasks.isProject, true), like(schema.tasks.id, `${projectId}%`)))
142
- .all();
135
+ .where(and(eq(schema.tasks.isProject, true), like(schema.tasks.id, `${projectId}%`)));
143
136
  if (projects.length === 0) {
144
137
  console.error(fmt(i18n.commands.project.notFound, { id: projectId }));
145
138
  process.exit(1);
@@ -149,12 +142,11 @@ export async function completeProject(projectId) {
149
142
  process.exit(1);
150
143
  }
151
144
  const project = projects[0];
152
- db.update(schema.tasks)
145
+ await db.update(schema.tasks)
153
146
  .set({
154
147
  status: 'done',
155
148
  updatedAt: new Date(),
156
149
  })
157
- .where(eq(schema.tasks.id, project.id))
158
- .run();
150
+ .where(eq(schema.tasks.id, project.id));
159
151
  console.log(fmt(i18n.commands.project.completed, { name: project.title }));
160
152
  }
package/dist/config.d.ts CHANGED
@@ -1,12 +1,21 @@
1
+ import type { ThemeName } from './ui/theme/types.js';
1
2
  export type Locale = 'en' | 'ja';
2
- export type ThemeName = 'modern' | 'norton-commander' | 'dos-prompt' | 'turbo-pascal';
3
+ export type { ThemeName };
4
+ export interface TursoConfig {
5
+ url: string;
6
+ authToken: string;
7
+ }
3
8
  export interface Config {
4
9
  locale: Locale;
5
10
  db_path?: string;
6
11
  theme: ThemeName;
12
+ turso?: TursoConfig;
7
13
  }
8
14
  export declare function loadConfig(): Config;
9
15
  export declare function saveConfig(updates: Partial<Config>): void;
16
+ export declare function getTursoConfig(): TursoConfig | undefined;
17
+ export declare function setTursoConfig(config: TursoConfig | undefined): void;
18
+ export declare function isTursoEnabled(): boolean;
10
19
  export declare function getDbPath(): string;
11
20
  export declare function getLocale(): Locale;
12
21
  export declare function setLocale(locale: Locale): void;