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 +69 -21
- package/README.md +69 -21
- package/dist/cli.js +27 -1
- package/dist/commands/add.js +5 -6
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.js +43 -16
- package/dist/commands/done.js +4 -6
- package/dist/commands/list.js +9 -13
- package/dist/commands/move.js +4 -6
- package/dist/commands/project.js +18 -26
- package/dist/config.d.ts +10 -1
- package/dist/config.js +14 -0
- package/dist/db/index.d.ts +5 -4
- package/dist/db/index.js +107 -32
- package/dist/i18n/en.d.ts +21 -0
- package/dist/i18n/en.js +11 -0
- package/dist/i18n/ja.js +11 -0
- package/dist/index.js +23 -1
- package/dist/ui/App.js +106 -113
- package/dist/ui/ThemeSelector.d.ts +1 -1
- package/dist/ui/ThemeSelector.js +23 -10
- package/dist/ui/components/FunctionKeyBar.d.ts +5 -4
- package/dist/ui/components/FunctionKeyBar.js +19 -15
- package/dist/ui/theme/themes.d.ts +12 -0
- package/dist/ui/theme/themes.js +495 -3
- package/dist/ui/theme/types.d.ts +1 -1
- package/package.json +2 -1
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
|
|
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
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
130
|
+
# 手動同期
|
|
131
|
+
floq sync
|
|
132
|
+
|
|
133
|
+
# Turso同期を無効化
|
|
134
|
+
floq config turso --disable
|
|
135
|
+
```
|
|
113
136
|
|
|
114
|
-
###
|
|
115
|
-
- シングルラインボーダー
|
|
116
|
-
- 緑テキスト(CRTモニター風)
|
|
117
|
-
- シンプルな `>` 選択インジケータ
|
|
137
|
+
### 仕組み
|
|
118
138
|
|
|
119
|
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
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
|
-
|
|
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
|
|
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
|
-
##
|
|
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
|
-
|
|
106
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
130
|
+
# Manual sync
|
|
131
|
+
floq sync
|
|
132
|
+
|
|
133
|
+
# Disable Turso sync
|
|
134
|
+
floq config turso --disable
|
|
135
|
+
```
|
|
113
136
|
|
|
114
|
-
###
|
|
115
|
-
- Single-line borders
|
|
116
|
-
- Green text (CRT monitor style)
|
|
117
|
-
- Simple `>` selection indicator
|
|
137
|
+
### How It Works
|
|
118
138
|
|
|
119
|
-
|
|
120
|
-
-
|
|
121
|
-
-
|
|
122
|
-
-
|
|
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
|
-
|
|
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 };
|
package/dist/commands/add.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 =
|
|
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)
|
|
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>;
|
package/dist/commands/config.js
CHANGED
|
@@ -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
|
|
49
|
-
|
|
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
|
|
63
|
-
|
|
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
|
+
}
|
package/dist/commands/done.js
CHANGED
|
@@ -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
|
}
|
package/dist/commands/list.js
CHANGED
|
@@ -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
|
|
67
|
+
const allProjects = await db
|
|
70
68
|
.select()
|
|
71
69
|
.from(schema.tasks)
|
|
72
|
-
.where(eq(schema.tasks.isProject, true))
|
|
73
|
-
|
|
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 })})`);
|
package/dist/commands/move.js
CHANGED
|
@@ -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]
|
package/dist/commands/project.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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)
|
|
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
|
|
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;
|