floq 0.1.0 → 0.2.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 (42) hide show
  1. package/README.ja.md +89 -9
  2. package/README.md +89 -9
  3. package/dist/changelog.d.ts +13 -0
  4. package/dist/changelog.js +95 -0
  5. package/dist/cli.js +44 -1
  6. package/dist/commands/comment.d.ts +2 -0
  7. package/dist/commands/comment.js +67 -0
  8. package/dist/commands/config.d.ts +4 -0
  9. package/dist/commands/config.js +123 -1
  10. package/dist/commands/setup.d.ts +1 -0
  11. package/dist/commands/setup.js +13 -0
  12. package/dist/config.d.ts +5 -0
  13. package/dist/config.js +40 -3
  14. package/dist/db/index.js +20 -0
  15. package/dist/db/schema.d.ts +83 -0
  16. package/dist/db/schema.js +6 -0
  17. package/dist/i18n/en.d.ts +278 -0
  18. package/dist/i18n/en.js +148 -3
  19. package/dist/i18n/ja.js +148 -3
  20. package/dist/index.js +14 -4
  21. package/dist/paths.d.ts +4 -0
  22. package/dist/paths.js +63 -5
  23. package/dist/ui/App.js +320 -37
  24. package/dist/ui/ModeSelector.d.ts +7 -0
  25. package/dist/ui/ModeSelector.js +37 -0
  26. package/dist/ui/SetupWizard.d.ts +6 -0
  27. package/dist/ui/SetupWizard.js +321 -0
  28. package/dist/ui/components/HelpModal.d.ts +2 -1
  29. package/dist/ui/components/HelpModal.js +155 -4
  30. package/dist/ui/components/KanbanBoard.d.ts +6 -0
  31. package/dist/ui/components/KanbanBoard.js +498 -0
  32. package/dist/ui/components/KanbanColumn.d.ts +12 -0
  33. package/dist/ui/components/KanbanColumn.js +11 -0
  34. package/dist/ui/components/ProgressBar.d.ts +7 -0
  35. package/dist/ui/components/ProgressBar.js +13 -0
  36. package/dist/ui/components/SearchBar.d.ts +8 -0
  37. package/dist/ui/components/SearchBar.js +11 -0
  38. package/dist/ui/components/SearchResults.d.ts +9 -0
  39. package/dist/ui/components/SearchResults.js +18 -0
  40. package/dist/ui/components/TaskItem.d.ts +6 -1
  41. package/dist/ui/components/TaskItem.js +3 -2
  42. 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=完了 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,24 @@ 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
+ infoTab: '情報',
120
+ tabHint: 'Tab: 表示切替',
97
121
  navigation: 'ナビゲーション',
98
- tabSwitch: 'タブ切替 (5=プロジェクト)',
122
+ tabSwitch: 'タブ切替 (5=プロジェクト, 6=完了)',
99
123
  prevNextTab: '前後のタブ',
100
124
  taskSelect: 'タスク選択',
101
125
  actions: 'アクション',
@@ -103,6 +127,7 @@ export const ja = {
103
127
  completeTask: '選択タスクを完了',
104
128
  moveToNext: '次のアクションへ移動',
105
129
  moveToSomeday: 'いつかやるへ移動',
130
+ moveToWaiting: '連絡待ちへ移動',
106
131
  moveToInbox: 'Inboxへ移動',
107
132
  refresh: 'リスト更新',
108
133
  projects: 'プロジェクト',
@@ -110,10 +135,130 @@ export const ja = {
110
135
  linkToProject: 'タスクをプロジェクトに紐づけ',
111
136
  openProject: 'プロジェクトを開く (Projectsタブ)',
112
137
  backFromProject: 'プロジェクト詳細から戻る',
138
+ taskDetail: 'タスク詳細を表示',
139
+ addComment: 'コメント追加',
140
+ searchTasks: 'タスク検索',
113
141
  other: 'その他',
114
142
  showHelp: 'このヘルプを表示',
115
143
  quit: '終了',
116
- closeHint: '任意のキーで閉じる',
144
+ closeHint: 'Esc/q: 閉じる',
145
+ },
146
+ // What's New / Changelog
147
+ whatsNew: {
148
+ title: '更新履歴',
149
+ noChanges: '更新履歴はありません',
150
+ added: '追加',
151
+ changed: '変更',
152
+ deprecated: '非推奨',
153
+ removed: '削除',
154
+ fixed: '修正',
155
+ security: 'セキュリティ',
156
+ },
157
+ // Kanban mode help
158
+ kanbanHelp: {
159
+ title: 'Kanbanショートカット',
160
+ navigation: 'ナビゲーション',
161
+ columnSwitch: 'カラム切替',
162
+ columnDirect: 'カラムに直接ジャンプ',
163
+ taskSelect: 'タスク選択',
164
+ actions: 'アクション',
165
+ addTask: '新規タスク追加 (TODOへ)',
166
+ completeTask: '完了へ移動',
167
+ moveRight: '次のカラムへ移動',
168
+ moveLeft: '前のカラムへ戻す',
169
+ searchTasks: 'タスク検索',
170
+ other: 'その他',
171
+ showHelp: 'このヘルプを表示',
172
+ quit: '終了',
173
+ closeHint: 'Esc/q: 閉じる',
174
+ },
175
+ addComment: '新規コメント: ',
176
+ noComments: 'コメントはまだありません',
177
+ commentHint: 'i: コメント追加',
178
+ linkHint: 'P: プロジェクト紐づけ',
179
+ commentAdded: 'コメントを追加しました',
180
+ commentDeleted: 'コメントを削除しました',
181
+ taskDetailTitle: 'タスク詳細',
182
+ taskDetailFooter: 'j/k=選択 i=コメント d=削除 P=紐づけ b/Esc=戻る',
183
+ taskDetailStatus: 'ステータス',
184
+ deleteConfirm: '「{title}」を削除しますか? (y/n)',
185
+ deleted: '削除しました: 「{title}」',
186
+ deleteCancelled: '削除をキャンセルしました',
187
+ comments: 'コメント',
188
+ projectTasks: 'タスク一覧',
189
+ // Search
190
+ search: {
191
+ prefix: '/',
192
+ placeholder: 'タスクを検索...',
193
+ help: '(Enterで選択, Ctrl+j/kで移動, Escでキャンセル)',
194
+ noResults: '該当するタスクがありません',
195
+ resultsTitle: '検索結果',
196
+ searchTasks: 'タスク検索',
197
+ },
198
+ // Info tab
199
+ info: {
200
+ settings: '設定',
201
+ database: 'データベース',
202
+ paths: 'パス',
203
+ theme: 'テーマ',
204
+ language: '言語',
205
+ viewMode: '表示モード',
206
+ dbType: '種類',
207
+ dbPath: 'パス',
208
+ tursoUrl: 'Turso URL',
209
+ configFile: '設定ファイル',
210
+ dataDir: 'データディレクトリ',
211
+ local: 'ローカル',
212
+ turso: 'turso',
213
+ },
214
+ },
215
+ // Setup wizard
216
+ setup: {
217
+ welcome: {
218
+ title: 'Floqへようこそ!',
219
+ subtitle: 'タスクマネージャーを設定しましょう',
220
+ instruction: '任意のキーを押して設定を開始...',
221
+ },
222
+ language: {
223
+ title: '言語を選択',
224
+ hint: 'j/k: 選択, Enter: 確定, Esc: 戻る',
225
+ },
226
+ theme: {
227
+ title: 'テーマを選択',
228
+ hint: 'j/k: 選択, Enter: 確定, Esc: 戻る',
229
+ },
230
+ viewMode: {
231
+ title: '表示モードを選択',
232
+ hint: 'j/k: 選択, Enter: 確定, Esc: 戻る',
233
+ gtd: 'GTD (Getting Things Done)',
234
+ gtdDesc: 'Inbox、次のアクション、連絡待ち、いつかやるリストによるクラシックGTDワークフロー',
235
+ kanban: 'Kanbanボード',
236
+ kanbanDesc: '3カラムのKanbanボード表示',
237
+ },
238
+ database: {
239
+ title: 'データベースモードを選択',
240
+ local: 'ローカル',
241
+ localDesc: 'このデバイスにデータをローカル保存',
242
+ turso: 'Turso Cloud',
243
+ tursoDesc: 'Turso経由でデバイス間でデータを同期',
244
+ hint: 'j/k: 選択, Enter: 確定, Esc: 戻る',
245
+ },
246
+ turso: {
247
+ urlPrompt: 'TursoデータベースURL',
248
+ urlPlaceholder: 'libsql://your-db.turso.io',
249
+ urlError: 'URLはlibsql://で始まる必要があります',
250
+ tokenPrompt: 'Turso認証トークン',
251
+ tokenError: 'トークンは空にできません',
252
+ inputHint: 'Enter: 確定, Esc: 戻る',
253
+ },
254
+ complete: {
255
+ title: '設定完了!',
256
+ summary: '設定内容:',
257
+ language: '言語',
258
+ theme: 'テーマ',
259
+ viewMode: '表示モード',
260
+ database: 'データベース',
261
+ confirm: 'Enterを押してFloqを開始...',
117
262
  },
118
263
  },
119
264
  };
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, 'gtd-cli');
25
+ return join(xdgConfigHome, APP_NAME);
9
26
  }
10
- return join(homedir(), '.config', 'gtd-cli');
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, 'gtd-cli');
32
+ return join(xdgDataHome, APP_NAME);
16
33
  }
17
- return join(homedir(), '.local', 'share', 'gtd-cli');
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, 'gtd.db');
80
+ export const DB_PATH = join(DATA_DIR, 'floq.db');