floq 0.1.0 → 0.2.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 +89 -9
- package/README.md +89 -9
- package/dist/changelog.d.ts +13 -0
- package/dist/changelog.js +95 -0
- package/dist/cli.js +44 -1
- package/dist/commands/comment.d.ts +2 -0
- package/dist/commands/comment.js +67 -0
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.js +123 -1
- package/dist/commands/setup.d.ts +1 -0
- package/dist/commands/setup.js +13 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.js +40 -3
- package/dist/db/index.js +20 -0
- package/dist/db/schema.d.ts +83 -0
- package/dist/db/schema.js +6 -0
- package/dist/i18n/en.d.ts +237 -0
- package/dist/i18n/en.js +127 -3
- package/dist/i18n/ja.js +127 -3
- package/dist/index.js +14 -4
- package/dist/paths.d.ts +4 -0
- package/dist/paths.js +63 -5
- package/dist/ui/App.js +280 -25
- package/dist/ui/ModeSelector.d.ts +7 -0
- package/dist/ui/ModeSelector.js +37 -0
- package/dist/ui/SetupWizard.d.ts +6 -0
- package/dist/ui/SetupWizard.js +321 -0
- package/dist/ui/components/HelpModal.d.ts +2 -1
- package/dist/ui/components/HelpModal.js +118 -4
- package/dist/ui/components/KanbanBoard.d.ts +6 -0
- package/dist/ui/components/KanbanBoard.js +508 -0
- package/dist/ui/components/KanbanColumn.d.ts +12 -0
- package/dist/ui/components/KanbanColumn.js +11 -0
- package/dist/ui/components/ProgressBar.d.ts +7 -0
- package/dist/ui/components/ProgressBar.js +13 -0
- package/dist/ui/components/SearchBar.d.ts +8 -0
- package/dist/ui/components/SearchBar.js +11 -0
- package/dist/ui/components/SearchResults.d.ts +9 -0
- package/dist/ui/components/SearchResults.js +18 -0
- package/dist/ui/components/TaskItem.d.ts +6 -1
- package/dist/ui/components/TaskItem.js +3 -2
- package/package.json +1 -1
package/dist/i18n/ja.js
CHANGED
|
@@ -7,6 +7,12 @@ export const ja = {
|
|
|
7
7
|
someday: 'いつかやる',
|
|
8
8
|
done: '完了',
|
|
9
9
|
},
|
|
10
|
+
// Kanban mode labels
|
|
11
|
+
kanban: {
|
|
12
|
+
todo: 'TODO',
|
|
13
|
+
doing: '作業中',
|
|
14
|
+
done: '完了',
|
|
15
|
+
},
|
|
10
16
|
// Project status
|
|
11
17
|
projectStatus: {
|
|
12
18
|
active: 'アクティブなプロジェクト',
|
|
@@ -54,6 +60,13 @@ export const ja = {
|
|
|
54
60
|
statusLabel: 'ステータス: {status}',
|
|
55
61
|
tasksCount: 'タスク: {count}件',
|
|
56
62
|
},
|
|
63
|
+
comment: {
|
|
64
|
+
added: '「{title}」にコメントを追加しました',
|
|
65
|
+
notFound: 'タスクが見つかりません: {id}',
|
|
66
|
+
multipleMatch: '「{id}」に一致するタスクが複数あります。より具体的に指定してください:',
|
|
67
|
+
noComments: 'コメントはありません',
|
|
68
|
+
listHeader: '「{title}」のコメント:',
|
|
69
|
+
},
|
|
57
70
|
},
|
|
58
71
|
// TUI
|
|
59
72
|
tui: {
|
|
@@ -65,8 +78,10 @@ export const ja = {
|
|
|
65
78
|
added: '追加しました: 「{title}」',
|
|
66
79
|
completed: '完了しました: 「{title}」',
|
|
67
80
|
movedTo: '「{title}」を{status}に移動しました',
|
|
81
|
+
movedToWaiting: '「{title}」を連絡待ち({person})に移動しました',
|
|
82
|
+
waitingFor: '待機相手: ',
|
|
68
83
|
refreshed: '更新しました',
|
|
69
|
-
footer: 'a=追加 d=完了 n=次 s=いつか i=Inbox p=プロジェクト化 P=紐づけ',
|
|
84
|
+
footer: 'a=追加 d=完了 n=次 s=いつか w=待ち i=Inbox p=プロジェクト化 P=紐づけ',
|
|
70
85
|
noTasks: 'タスクなし',
|
|
71
86
|
// Tab labels
|
|
72
87
|
tabInbox: 'Inbox',
|
|
@@ -74,6 +89,7 @@ export const ja = {
|
|
|
74
89
|
tabWaiting: '待ち',
|
|
75
90
|
tabSomeday: 'いつか',
|
|
76
91
|
tabProjects: 'プロジェクト',
|
|
92
|
+
tabDone: '完了',
|
|
77
93
|
// Project actions
|
|
78
94
|
madeProject: 'プロジェクト化しました: 「{title}」',
|
|
79
95
|
linkedToProject: '「{title}」を{project}に紐づけました',
|
|
@@ -86,16 +102,23 @@ export const ja = {
|
|
|
86
102
|
done: '完了',
|
|
87
103
|
next: '次へ',
|
|
88
104
|
someday: 'いつか',
|
|
105
|
+
waiting: '待ち',
|
|
89
106
|
inbox: 'Inbox',
|
|
90
107
|
project: 'プロジェクト',
|
|
91
108
|
help: 'ヘルプ',
|
|
92
109
|
quit: '終了',
|
|
110
|
+
comment: 'コメント',
|
|
111
|
+
back: '戻る',
|
|
112
|
+
delete: '削除',
|
|
93
113
|
},
|
|
94
114
|
// Help modal
|
|
95
115
|
help: {
|
|
96
116
|
title: 'キーボードショートカット',
|
|
117
|
+
whatsNewTab: '更新履歴',
|
|
118
|
+
keybindingsTab: 'キー操作',
|
|
119
|
+
tabHint: 'Tab: 表示切替',
|
|
97
120
|
navigation: 'ナビゲーション',
|
|
98
|
-
tabSwitch: 'タブ切替 (5
|
|
121
|
+
tabSwitch: 'タブ切替 (5=プロジェクト, 6=完了)',
|
|
99
122
|
prevNextTab: '前後のタブ',
|
|
100
123
|
taskSelect: 'タスク選択',
|
|
101
124
|
actions: 'アクション',
|
|
@@ -103,6 +126,7 @@ export const ja = {
|
|
|
103
126
|
completeTask: '選択タスクを完了',
|
|
104
127
|
moveToNext: '次のアクションへ移動',
|
|
105
128
|
moveToSomeday: 'いつかやるへ移動',
|
|
129
|
+
moveToWaiting: '連絡待ちへ移動',
|
|
106
130
|
moveToInbox: 'Inboxへ移動',
|
|
107
131
|
refresh: 'リスト更新',
|
|
108
132
|
projects: 'プロジェクト',
|
|
@@ -110,10 +134,110 @@ export const ja = {
|
|
|
110
134
|
linkToProject: 'タスクをプロジェクトに紐づけ',
|
|
111
135
|
openProject: 'プロジェクトを開く (Projectsタブ)',
|
|
112
136
|
backFromProject: 'プロジェクト詳細から戻る',
|
|
137
|
+
taskDetail: 'タスク詳細を表示',
|
|
138
|
+
addComment: 'コメント追加',
|
|
139
|
+
searchTasks: 'タスク検索',
|
|
140
|
+
other: 'その他',
|
|
141
|
+
showHelp: 'このヘルプを表示',
|
|
142
|
+
quit: '終了',
|
|
143
|
+
closeHint: 'Esc/q: 閉じる',
|
|
144
|
+
},
|
|
145
|
+
// What's New / Changelog
|
|
146
|
+
whatsNew: {
|
|
147
|
+
title: '更新履歴',
|
|
148
|
+
noChanges: '更新履歴はありません',
|
|
149
|
+
added: '追加',
|
|
150
|
+
changed: '変更',
|
|
151
|
+
deprecated: '非推奨',
|
|
152
|
+
removed: '削除',
|
|
153
|
+
fixed: '修正',
|
|
154
|
+
security: 'セキュリティ',
|
|
155
|
+
},
|
|
156
|
+
// Kanban mode help
|
|
157
|
+
kanbanHelp: {
|
|
158
|
+
title: 'Kanbanショートカット',
|
|
159
|
+
navigation: 'ナビゲーション',
|
|
160
|
+
columnSwitch: 'カラム切替',
|
|
161
|
+
columnDirect: 'カラムに直接ジャンプ',
|
|
162
|
+
taskSelect: 'タスク選択',
|
|
163
|
+
actions: 'アクション',
|
|
164
|
+
addTask: '新規タスク追加 (TODOへ)',
|
|
165
|
+
completeTask: '完了へ移動',
|
|
166
|
+
moveRight: '次のカラムへ移動',
|
|
167
|
+
moveLeft: '前のカラムへ戻す',
|
|
168
|
+
searchTasks: 'タスク検索',
|
|
113
169
|
other: 'その他',
|
|
114
170
|
showHelp: 'このヘルプを表示',
|
|
115
171
|
quit: '終了',
|
|
116
|
-
closeHint: '
|
|
172
|
+
closeHint: 'Esc/q: 閉じる',
|
|
173
|
+
},
|
|
174
|
+
addComment: '新規コメント: ',
|
|
175
|
+
noComments: 'コメントはまだありません',
|
|
176
|
+
commentHint: 'i: コメント追加',
|
|
177
|
+
linkHint: 'P: プロジェクト紐づけ',
|
|
178
|
+
commentAdded: 'コメントを追加しました',
|
|
179
|
+
commentDeleted: 'コメントを削除しました',
|
|
180
|
+
taskDetailTitle: 'タスク詳細',
|
|
181
|
+
taskDetailFooter: 'j/k=選択 i=コメント d=削除 P=紐づけ b/Esc=戻る',
|
|
182
|
+
comments: 'コメント',
|
|
183
|
+
projectTasks: 'タスク一覧',
|
|
184
|
+
// Search
|
|
185
|
+
search: {
|
|
186
|
+
prefix: '/',
|
|
187
|
+
placeholder: 'タスクを検索...',
|
|
188
|
+
help: '(Enterで選択, Ctrl+j/kで移動, Escでキャンセル)',
|
|
189
|
+
noResults: '該当するタスクがありません',
|
|
190
|
+
resultsTitle: '検索結果',
|
|
191
|
+
searchTasks: 'タスク検索',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
// Setup wizard
|
|
195
|
+
setup: {
|
|
196
|
+
welcome: {
|
|
197
|
+
title: 'Floqへようこそ!',
|
|
198
|
+
subtitle: 'タスクマネージャーを設定しましょう',
|
|
199
|
+
instruction: '任意のキーを押して設定を開始...',
|
|
200
|
+
},
|
|
201
|
+
language: {
|
|
202
|
+
title: '言語を選択',
|
|
203
|
+
hint: 'j/k: 選択, Enter: 確定, Esc: 戻る',
|
|
204
|
+
},
|
|
205
|
+
theme: {
|
|
206
|
+
title: 'テーマを選択',
|
|
207
|
+
hint: 'j/k: 選択, Enter: 確定, Esc: 戻る',
|
|
208
|
+
},
|
|
209
|
+
viewMode: {
|
|
210
|
+
title: '表示モードを選択',
|
|
211
|
+
hint: 'j/k: 選択, Enter: 確定, Esc: 戻る',
|
|
212
|
+
gtd: 'GTD (Getting Things Done)',
|
|
213
|
+
gtdDesc: 'Inbox、次のアクション、連絡待ち、いつかやるリストによるクラシックGTDワークフロー',
|
|
214
|
+
kanban: 'Kanbanボード',
|
|
215
|
+
kanbanDesc: '3カラムのKanbanボード表示',
|
|
216
|
+
},
|
|
217
|
+
database: {
|
|
218
|
+
title: 'データベースモードを選択',
|
|
219
|
+
local: 'ローカル',
|
|
220
|
+
localDesc: 'このデバイスにデータをローカル保存',
|
|
221
|
+
turso: 'Turso Cloud',
|
|
222
|
+
tursoDesc: 'Turso経由でデバイス間でデータを同期',
|
|
223
|
+
hint: 'j/k: 選択, Enter: 確定, Esc: 戻る',
|
|
224
|
+
},
|
|
225
|
+
turso: {
|
|
226
|
+
urlPrompt: 'TursoデータベースURL',
|
|
227
|
+
urlPlaceholder: 'libsql://your-db.turso.io',
|
|
228
|
+
urlError: 'URLはlibsql://で始まる必要があります',
|
|
229
|
+
tokenPrompt: 'Turso認証トークン',
|
|
230
|
+
tokenError: 'トークンは空にできません',
|
|
231
|
+
inputHint: 'Enter: 確定, Esc: 戻る',
|
|
232
|
+
},
|
|
233
|
+
complete: {
|
|
234
|
+
title: '設定完了!',
|
|
235
|
+
summary: '設定内容:',
|
|
236
|
+
language: '言語',
|
|
237
|
+
theme: 'テーマ',
|
|
238
|
+
viewMode: '表示モード',
|
|
239
|
+
database: 'データベース',
|
|
240
|
+
confirm: 'Enterを押してFloqを開始...',
|
|
117
241
|
},
|
|
118
242
|
},
|
|
119
243
|
};
|
package/dist/index.js
CHANGED
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { program } from './cli.js';
|
|
3
3
|
import { initDb } from './db/index.js';
|
|
4
|
-
import { isTursoEnabled, getTursoConfig } from './config.js';
|
|
4
|
+
import { isTursoEnabled, getTursoConfig, isFirstRun } from './config.js';
|
|
5
|
+
import { runSetupWizard } from './commands/setup.js';
|
|
5
6
|
async function main() {
|
|
6
7
|
// 起動時にモードを表示(TUI以外のコマンド時)
|
|
7
8
|
const args = process.argv.slice(2);
|
|
8
9
|
const isTuiMode = args.length === 0;
|
|
9
10
|
const isConfigCommand = args[0] === 'config';
|
|
10
11
|
const isSyncCommand = args[0] === 'sync';
|
|
12
|
+
const isSetupCommand = args[0] === 'setup';
|
|
13
|
+
// 初回起動時(引数なし + config未作成)はウィザードを起動
|
|
14
|
+
if (isTuiMode && isFirstRun()) {
|
|
15
|
+
await runSetupWizard();
|
|
16
|
+
// ウィザード完了後、DBを初期化してTUIを起動
|
|
17
|
+
await initDb();
|
|
18
|
+
program.parse();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
11
21
|
// config/syncコマンド以外でTursoモードの場合は接続先を表示
|
|
12
|
-
if (!isTuiMode && !isConfigCommand && !isSyncCommand && isTursoEnabled()) {
|
|
22
|
+
if (!isTuiMode && !isConfigCommand && !isSyncCommand && !isSetupCommand && isTursoEnabled()) {
|
|
13
23
|
const turso = getTursoConfig();
|
|
14
24
|
if (turso) {
|
|
15
25
|
const host = new URL(turso.url).host;
|
|
16
26
|
console.log(`🔄 Turso sync: ${host}`);
|
|
17
27
|
}
|
|
18
28
|
}
|
|
19
|
-
// configコマンドはDB不要なのでスキップ
|
|
20
|
-
if (!isConfigCommand) {
|
|
29
|
+
// config/setupコマンドはDB不要なのでスキップ
|
|
30
|
+
if (!isConfigCommand && !isSetupCommand) {
|
|
21
31
|
await initDb();
|
|
22
32
|
}
|
|
23
33
|
program.parse();
|
package/dist/paths.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export declare function getConfigDir(): string;
|
|
2
2
|
export declare function getDataDir(): string;
|
|
3
|
+
/**
|
|
4
|
+
* Run migration from legacy paths if needed
|
|
5
|
+
*/
|
|
6
|
+
export declare function runMigration(): void;
|
|
3
7
|
export declare const CONFIG_DIR: string;
|
|
4
8
|
export declare const DATA_DIR: string;
|
|
5
9
|
export declare const CONFIG_FILE: string;
|
package/dist/paths.js
CHANGED
|
@@ -1,22 +1,80 @@
|
|
|
1
1
|
import { homedir } from 'os';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
+
import { existsSync, renameSync, mkdirSync, readdirSync } from 'fs';
|
|
3
4
|
// XDG Base Directory Specification
|
|
4
5
|
// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html
|
|
6
|
+
const APP_NAME = 'floq';
|
|
7
|
+
const LEGACY_APP_NAME = 'gtd-cli';
|
|
8
|
+
function getLegacyConfigDir() {
|
|
9
|
+
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
10
|
+
if (xdgConfigHome) {
|
|
11
|
+
return join(xdgConfigHome, LEGACY_APP_NAME);
|
|
12
|
+
}
|
|
13
|
+
return join(homedir(), '.config', LEGACY_APP_NAME);
|
|
14
|
+
}
|
|
15
|
+
function getLegacyDataDir() {
|
|
16
|
+
const xdgDataHome = process.env.XDG_DATA_HOME;
|
|
17
|
+
if (xdgDataHome) {
|
|
18
|
+
return join(xdgDataHome, LEGACY_APP_NAME);
|
|
19
|
+
}
|
|
20
|
+
return join(homedir(), '.local', 'share', LEGACY_APP_NAME);
|
|
21
|
+
}
|
|
5
22
|
export function getConfigDir() {
|
|
6
23
|
const xdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
7
24
|
if (xdgConfigHome) {
|
|
8
|
-
return join(xdgConfigHome,
|
|
25
|
+
return join(xdgConfigHome, APP_NAME);
|
|
9
26
|
}
|
|
10
|
-
return join(homedir(), '.config',
|
|
27
|
+
return join(homedir(), '.config', APP_NAME);
|
|
11
28
|
}
|
|
12
29
|
export function getDataDir() {
|
|
13
30
|
const xdgDataHome = process.env.XDG_DATA_HOME;
|
|
14
31
|
if (xdgDataHome) {
|
|
15
|
-
return join(xdgDataHome,
|
|
32
|
+
return join(xdgDataHome, APP_NAME);
|
|
16
33
|
}
|
|
17
|
-
return join(homedir(), '.local', 'share',
|
|
34
|
+
return join(homedir(), '.local', 'share', APP_NAME);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Migrate from legacy gtd-cli directories to floq directories
|
|
38
|
+
*/
|
|
39
|
+
function migrateDirectory(legacyDir, newDir) {
|
|
40
|
+
// Only migrate if legacy exists and new doesn't
|
|
41
|
+
if (existsSync(legacyDir) && !existsSync(newDir)) {
|
|
42
|
+
try {
|
|
43
|
+
// Create parent directory if needed
|
|
44
|
+
const parentDir = join(newDir, '..');
|
|
45
|
+
if (!existsSync(parentDir)) {
|
|
46
|
+
mkdirSync(parentDir, { recursive: true });
|
|
47
|
+
}
|
|
48
|
+
// Rename (move) the directory
|
|
49
|
+
renameSync(legacyDir, newDir);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// If rename fails (cross-device), copy files manually
|
|
53
|
+
try {
|
|
54
|
+
mkdirSync(newDir, { recursive: true });
|
|
55
|
+
const files = readdirSync(legacyDir);
|
|
56
|
+
for (const file of files) {
|
|
57
|
+
const legacyPath = join(legacyDir, file);
|
|
58
|
+
const newPath = join(newDir, file);
|
|
59
|
+
renameSync(legacyPath, newPath);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Ignore migration errors, user can migrate manually
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Run migration from legacy paths if needed
|
|
70
|
+
*/
|
|
71
|
+
export function runMigration() {
|
|
72
|
+
migrateDirectory(getLegacyConfigDir(), getConfigDir());
|
|
73
|
+
migrateDirectory(getLegacyDataDir(), getDataDir());
|
|
18
74
|
}
|
|
75
|
+
// Run migration on module load
|
|
76
|
+
runMigration();
|
|
19
77
|
export const CONFIG_DIR = getConfigDir();
|
|
20
78
|
export const DATA_DIR = getDataDir();
|
|
21
79
|
export const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
|
|
22
|
-
export const DB_PATH = join(DATA_DIR, '
|
|
80
|
+
export const DB_PATH = join(DATA_DIR, 'floq.db');
|