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
package/README.ja.md ADDED
@@ -0,0 +1,133 @@
1
+ # Floq
2
+
3
+ [English](./README.md)
4
+
5
+ MS-DOSスタイルのテーマを備えたターミナルベースのGTD(Getting Things Done)タスクマネージャー。
6
+
7
+ ## 特徴
8
+
9
+ - **TUIインターフェース**: Ink(CLI用React)で構築されたインタラクティブなターミナルUI
10
+ - **GTDワークフロー**: Inbox、Next Actions、Waiting For、Someday/Maybe
11
+ - **プロジェクト**: タスクをプロジェクトに整理
12
+ - **テーマ**: MS-DOSノスタルジックスタイルを含む複数テーマ
13
+ - **多言語対応**: 英語・日本語サポート
14
+ - **Vimスタイルナビゲーション**: hjklまたは矢印キーで操作
15
+
16
+ ## インストール
17
+
18
+ ```bash
19
+ npm install
20
+ npm run build
21
+ npm link
22
+ ```
23
+
24
+ ## 使い方
25
+
26
+ ### TUIモード
27
+
28
+ ```bash
29
+ floq
30
+ ```
31
+
32
+ ### キーボードショートカット
33
+
34
+ | キー | アクション |
35
+ |------|-----------|
36
+ | `1-5` | タブ切り替え |
37
+ | `h/l` または `←/→` | 前/次のタブ |
38
+ | `j/k` または `↑/↓` | タスク選択 |
39
+ | `a` | タスク追加 |
40
+ | `d` | 完了にする |
41
+ | `n` | Next Actionsに移動 |
42
+ | `s` | Someday/Maybeに移動 |
43
+ | `i` | Inboxに移動 |
44
+ | `p` | プロジェクトに変換 |
45
+ | `P` | プロジェクトに紐付け |
46
+ | `Enter` | プロジェクトを開く(Projectsタブ) |
47
+ | `Esc/b` | プロジェクトから戻る |
48
+ | `r` | 更新 |
49
+ | `?` | ヘルプ |
50
+ | `q` | 終了 |
51
+
52
+ ### CLIコマンド
53
+
54
+ ```bash
55
+ # タスク追加
56
+ floq add "タスクのタイトル"
57
+ floq add "タスクのタイトル" -p "プロジェクト名"
58
+
59
+ # タスク一覧
60
+ floq list # 未完了タスク全て
61
+ floq list inbox # Inboxのみ
62
+ floq list next # Next actions
63
+ floq list waiting # Waiting for
64
+ floq list someday # Someday/maybe
65
+ floq list projects # プロジェクト
66
+
67
+ # タスク移動
68
+ floq move <id> next
69
+ floq move <id> waiting "担当者名"
70
+ floq move <id> someday
71
+
72
+ # タスク完了
73
+ floq done <id>
74
+
75
+ # プロジェクト
76
+ floq project add "プロジェクト名"
77
+ floq project list
78
+ floq project show <id>
79
+ floq project complete <id>
80
+ ```
81
+
82
+ ## 設定
83
+
84
+ ```bash
85
+ # 設定表示
86
+ floq config show
87
+
88
+ # 言語設定
89
+ floq config lang en # 英語
90
+ floq config lang ja # 日本語
91
+
92
+ # テーマ設定
93
+ 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スタイル
97
+
98
+ # データベースパス設定
99
+ floq config db /path/to/custom.db
100
+ floq config db # デフォルトに戻す
101
+ ```
102
+
103
+ ## テーマ
104
+
105
+ ### modern(デフォルト)
106
+ シンプルでクリーンなスタイル。シングルボーダー。
107
+
108
+ ### norton-commander
109
+ - ダブルラインボーダー(╔═╗║╚═╝)
110
+ - 大文字ヘッダー
111
+ - 画面下部にファンクションキーバー
112
+ - シアン/黄色のカラースキーム
113
+
114
+ ### dos-prompt
115
+ - シングルラインボーダー
116
+ - 緑テキスト(CRTモニター風)
117
+ - シンプルな `>` 選択インジケータ
118
+
119
+ ### turbo-pascal
120
+ - ダブルラインボーダー
121
+ - 黄色のアクセント
122
+ - IDE風の外観
123
+
124
+ > **注意**: 背景色はターミナルの設定に依存します。完全なDOS体験のためには、ターミナルの背景色を青(#0000AA)に設定してください。
125
+
126
+ ## データ保存場所
127
+
128
+ - 設定: `~/.config/gtd-cli/config.json`
129
+ - データベース: `~/.local/share/gtd-cli/gtd.db`
130
+
131
+ ## ライセンス
132
+
133
+ MIT
package/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # Floq
2
+
3
+ [日本語](./README.ja.md)
4
+
5
+ A terminal-based GTD (Getting Things Done) task manager with MS-DOS style themes.
6
+
7
+ ## Features
8
+
9
+ - **TUI Interface**: Interactive terminal UI built with Ink (React for CLI)
10
+ - **GTD Workflow**: Inbox, Next Actions, Waiting For, Someday/Maybe
11
+ - **Projects**: Organize tasks into projects
12
+ - **Themes**: Multiple themes including MS-DOS nostalgic styles
13
+ - **i18n**: English and Japanese support
14
+ - **Vim-style Navigation**: Use hjkl or arrow keys
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install
20
+ npm run build
21
+ npm link
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### TUI Mode
27
+
28
+ ```bash
29
+ floq
30
+ ```
31
+
32
+ ### Keyboard Shortcuts
33
+
34
+ | Key | Action |
35
+ |-----|--------|
36
+ | `1-5` | Switch tabs |
37
+ | `h/l` or `←/→` | Previous/Next tab |
38
+ | `j/k` or `↑/↓` | Navigate tasks |
39
+ | `a` | Add task |
40
+ | `d` | Mark as done |
41
+ | `n` | Move to Next Actions |
42
+ | `s` | Move to Someday/Maybe |
43
+ | `i` | Move to Inbox |
44
+ | `p` | Convert to project |
45
+ | `P` | Link to project |
46
+ | `Enter` | Open project (on Projects tab) |
47
+ | `Esc/b` | Back from project |
48
+ | `r` | Refresh |
49
+ | `?` | Help |
50
+ | `q` | Quit |
51
+
52
+ ### CLI Commands
53
+
54
+ ```bash
55
+ # Add task
56
+ floq add "Task title"
57
+ floq add "Task title" -p "Project name"
58
+
59
+ # List tasks
60
+ floq list # All non-done tasks
61
+ floq list inbox # Inbox only
62
+ floq list next # Next actions
63
+ floq list waiting # Waiting for
64
+ floq list someday # Someday/maybe
65
+ floq list projects # Projects
66
+
67
+ # Move task
68
+ floq move <id> next
69
+ floq move <id> waiting "Person name"
70
+ floq move <id> someday
71
+
72
+ # Complete task
73
+ floq done <id>
74
+
75
+ # Projects
76
+ floq project add "Project name"
77
+ floq project list
78
+ floq project show <id>
79
+ floq project complete <id>
80
+ ```
81
+
82
+ ## Configuration
83
+
84
+ ```bash
85
+ # Show configuration
86
+ floq config show
87
+
88
+ # Set language
89
+ floq config lang en # English
90
+ floq config lang ja # Japanese
91
+
92
+ # Set theme
93
+ 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
97
+
98
+ # Set database path
99
+ floq config db /path/to/custom.db
100
+ floq config db # Reset to default
101
+ ```
102
+
103
+ ## Themes
104
+
105
+ ### modern (default)
106
+ Clean, minimal style with single borders.
107
+
108
+ ### norton-commander
109
+ - Double-line borders (╔═╗║╚═╝)
110
+ - Uppercase headers
111
+ - Function key bar at bottom
112
+ - Cyan/yellow color scheme
113
+
114
+ ### dos-prompt
115
+ - Single-line borders
116
+ - Green text (CRT monitor style)
117
+ - Simple `>` selection indicator
118
+
119
+ ### turbo-pascal
120
+ - Double-line borders
121
+ - Yellow accents
122
+ - IDE-style appearance
123
+
124
+ > **Note**: Background colors depend on your terminal settings. For the full DOS experience, configure your terminal's background color to blue (#0000AA).
125
+
126
+ ## Data Storage
127
+
128
+ - Config: `~/.config/gtd-cli/config.json`
129
+ - Database: `~/.local/share/gtd-cli/gtd.db`
130
+
131
+ ## License
132
+
133
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ declare const program: Command;
3
+ export { program };
package/dist/cli.js ADDED
@@ -0,0 +1,124 @@
1
+ import { Command } from 'commander';
2
+ import { render } from 'ink';
3
+ import React from 'react';
4
+ import { App } from './ui/App.js';
5
+ import { addTask } from './commands/add.js';
6
+ import { listTasks, listProjects } from './commands/list.js';
7
+ import { moveTask } from './commands/move.js';
8
+ import { markDone } from './commands/done.js';
9
+ import { addProject, listProjectsCommand, showProject, completeProject, } from './commands/project.js';
10
+ import { showConfig, setLanguage, setDbPath, resetDbPath, setTheme, selectTheme } from './commands/config.js';
11
+ import { VERSION } from './version.js';
12
+ const program = new Command();
13
+ program
14
+ .name('floq')
15
+ .description('Floq - Flow your tasks, clear your mind')
16
+ .version(VERSION);
17
+ // Default command - launch TUI
18
+ program
19
+ .action(() => {
20
+ render(React.createElement(App));
21
+ });
22
+ // Add task
23
+ program
24
+ .command('add <title>')
25
+ .description('Add a new task to Inbox')
26
+ .option('-p, --project <name>', 'Add to a specific project')
27
+ .option('-d, --description <text>', 'Add a description')
28
+ .action(async (title, options) => {
29
+ await addTask(title, options);
30
+ });
31
+ // List tasks
32
+ program
33
+ .command('list [status]')
34
+ .description('List tasks (inbox, next, waiting, someday, done, projects, all)')
35
+ .action(async (status) => {
36
+ if (status === 'projects') {
37
+ await listProjects();
38
+ }
39
+ else {
40
+ await listTasks(status);
41
+ }
42
+ });
43
+ // Move task
44
+ program
45
+ .command('move <id> <status> [waitingFor]')
46
+ .description('Move a task to another list (inbox, next, waiting, someday)')
47
+ .action(async (id, status, waitingFor) => {
48
+ await moveTask(id, status, waitingFor);
49
+ });
50
+ // Mark task as done
51
+ program
52
+ .command('done <id>')
53
+ .description('Mark a task as done')
54
+ .action(async (id) => {
55
+ await markDone(id);
56
+ });
57
+ // Project commands
58
+ const projectCmd = program
59
+ .command('project')
60
+ .description('Project management commands');
61
+ projectCmd
62
+ .command('add <name>')
63
+ .description('Create a new project')
64
+ .option('-d, --description <text>', 'Add a description')
65
+ .action(async (name, options) => {
66
+ await addProject(name, options);
67
+ });
68
+ projectCmd
69
+ .command('list')
70
+ .description('List all projects')
71
+ .action(async () => {
72
+ await listProjectsCommand();
73
+ });
74
+ projectCmd
75
+ .command('show <id>')
76
+ .description('Show project details and tasks')
77
+ .action(async (id) => {
78
+ await showProject(id);
79
+ });
80
+ projectCmd
81
+ .command('complete <id>')
82
+ .description('Mark a project as completed')
83
+ .action(async (id) => {
84
+ await completeProject(id);
85
+ });
86
+ // Config commands
87
+ const configCmd = program
88
+ .command('config')
89
+ .description('Configuration commands');
90
+ configCmd
91
+ .command('show')
92
+ .description('Show current configuration')
93
+ .action(async () => {
94
+ await showConfig();
95
+ });
96
+ configCmd
97
+ .command('lang <locale>')
98
+ .description('Set language (en, ja)')
99
+ .action(async (locale) => {
100
+ await setLanguage(locale);
101
+ });
102
+ configCmd
103
+ .command('db [path]')
104
+ .description('Set database path (omit path to reset to default)')
105
+ .action(async (path) => {
106
+ if (path) {
107
+ await setDbPath(path);
108
+ }
109
+ else {
110
+ await resetDbPath();
111
+ }
112
+ });
113
+ configCmd
114
+ .command('theme [name]')
115
+ .description('Set UI theme (interactive if no name provided)')
116
+ .action(async (name) => {
117
+ if (name) {
118
+ await setTheme(name);
119
+ }
120
+ else {
121
+ await selectTheme();
122
+ }
123
+ });
124
+ export { program };
@@ -0,0 +1,6 @@
1
+ interface AddOptions {
2
+ project?: string;
3
+ description?: string;
4
+ }
5
+ export declare function addTask(title: string, options: AddOptions): Promise<void>;
6
+ export {};
@@ -0,0 +1,36 @@
1
+ import { v4 as uuidv4 } from 'uuid';
2
+ import { eq, and } from 'drizzle-orm';
3
+ import { getDb, schema } from '../db/index.js';
4
+ import { t, fmt } from '../i18n/index.js';
5
+ export async function addTask(title, options) {
6
+ const db = getDb();
7
+ const now = new Date();
8
+ const i18n = t();
9
+ let parentId;
10
+ if (options.project) {
11
+ const project = db
12
+ .select()
13
+ .from(schema.tasks)
14
+ .where(and(eq(schema.tasks.isProject, true), eq(schema.tasks.title, options.project)))
15
+ .get();
16
+ if (!project) {
17
+ console.error(fmt(i18n.commands.add.projectNotFound, { project: options.project }));
18
+ process.exit(1);
19
+ }
20
+ parentId = project.id;
21
+ }
22
+ const task = {
23
+ id: uuidv4(),
24
+ title,
25
+ description: options.description,
26
+ status: 'inbox',
27
+ parentId,
28
+ createdAt: now,
29
+ updatedAt: now,
30
+ };
31
+ db.insert(schema.tasks).values(task).run();
32
+ console.log(fmt(i18n.commands.add.success, { title }));
33
+ if (parentId) {
34
+ console.log(fmt(i18n.commands.add.withProject, { project: options.project }));
35
+ }
36
+ }
@@ -0,0 +1,6 @@
1
+ export declare function showConfig(): Promise<void>;
2
+ export declare function setLanguage(locale: string): Promise<void>;
3
+ export declare function setDbPath(dbPath: string): Promise<void>;
4
+ export declare function resetDbPath(): Promise<void>;
5
+ export declare function setTheme(theme: string): Promise<void>;
6
+ export declare function selectTheme(): Promise<void>;
@@ -0,0 +1,73 @@
1
+ import { render } from 'ink';
2
+ import React from 'react';
3
+ import { loadConfig, saveConfig, getDbPath } from '../config.js';
4
+ import { CONFIG_FILE } from '../paths.js';
5
+ import { ThemeSelector } from '../ui/ThemeSelector.js';
6
+ const VALID_LOCALES = ['en', 'ja'];
7
+ const VALID_THEMES = ['modern', 'norton-commander', 'dos-prompt', 'turbo-pascal'];
8
+ export async function showConfig() {
9
+ const config = loadConfig();
10
+ console.log('GTD CLI Configuration');
11
+ console.log('─'.repeat(40));
12
+ console.log(`Config file: ${CONFIG_FILE}`);
13
+ console.log(`Language: ${config.locale}`);
14
+ console.log(`Database: ${getDbPath()}`);
15
+ console.log(`Theme: ${config.theme || 'modern'}`);
16
+ if (config.db_path) {
17
+ console.log(` (custom: ${config.db_path})`);
18
+ }
19
+ }
20
+ export async function setLanguage(locale) {
21
+ if (!VALID_LOCALES.includes(locale)) {
22
+ console.error(`Invalid locale: ${locale}`);
23
+ console.error(`Valid locales: ${VALID_LOCALES.join(', ')}`);
24
+ process.exit(1);
25
+ }
26
+ saveConfig({ locale: locale });
27
+ const messages = {
28
+ en: 'Language set to English',
29
+ ja: '言語を日本語に設定しました',
30
+ };
31
+ console.log(messages[locale]);
32
+ }
33
+ export async function setDbPath(dbPath) {
34
+ saveConfig({ db_path: dbPath });
35
+ console.log(`Database path set to: ${getDbPath()}`);
36
+ }
37
+ export async function resetDbPath() {
38
+ saveConfig({ db_path: undefined });
39
+ console.log(`Database path reset to default: ${getDbPath()}`);
40
+ }
41
+ export async function setTheme(theme) {
42
+ if (!VALID_THEMES.includes(theme)) {
43
+ console.error(`Invalid theme: ${theme}`);
44
+ console.error(`Valid themes: ${VALID_THEMES.join(', ')}`);
45
+ process.exit(1);
46
+ }
47
+ 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]);
55
+ }
56
+ export async function selectTheme() {
57
+ return new Promise((resolve) => {
58
+ const { unmount } = render(React.createElement(ThemeSelector, {
59
+ onSelect: (theme) => {
60
+ unmount();
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]);
69
+ resolve();
70
+ },
71
+ }));
72
+ });
73
+ }
@@ -0,0 +1 @@
1
+ export declare function markDone(taskId: string): Promise<void>;
@@ -0,0 +1,37 @@
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 markDone(taskId) {
5
+ const db = getDb();
6
+ const i18n = t();
7
+ // Find task by ID prefix
8
+ const tasks = db
9
+ .select()
10
+ .from(schema.tasks)
11
+ .where(like(schema.tasks.id, `${taskId}%`))
12
+ .all();
13
+ if (tasks.length === 0) {
14
+ console.error(fmt(i18n.commands.done.notFound, { id: taskId }));
15
+ process.exit(1);
16
+ }
17
+ if (tasks.length > 1) {
18
+ console.error(fmt(i18n.commands.done.multipleMatch, { id: taskId }));
19
+ for (const task of tasks) {
20
+ console.error(` [${task.id.slice(0, 8)}] ${task.title}`);
21
+ }
22
+ process.exit(1);
23
+ }
24
+ const task = tasks[0];
25
+ if (task.status === 'done') {
26
+ console.log(fmt(i18n.commands.done.alreadyDone, { title: task.title }));
27
+ return;
28
+ }
29
+ db.update(schema.tasks)
30
+ .set({
31
+ status: 'done',
32
+ updatedAt: new Date(),
33
+ })
34
+ .where(eq(schema.tasks.id, task.id))
35
+ .run();
36
+ console.log(fmt(i18n.commands.done.success, { title: task.title }));
37
+ }
@@ -0,0 +1,2 @@
1
+ export declare function listTasks(status?: string): Promise<void>;
2
+ export declare function listProjects(): Promise<void>;
@@ -0,0 +1,96 @@
1
+ import { eq } from 'drizzle-orm';
2
+ import { getDb, schema } from '../db/index.js';
3
+ import { t, fmt } from '../i18n/index.js';
4
+ export async function listTasks(status) {
5
+ const db = getDb();
6
+ const i18n = t();
7
+ if (status && status !== 'all') {
8
+ const validStatuses = ['inbox', 'next', 'waiting', 'someday', 'done'];
9
+ if (!validStatuses.includes(status)) {
10
+ console.error(fmt(i18n.commands.list.invalidStatus, { status }));
11
+ console.error(fmt(i18n.commands.list.validStatuses, { statuses: validStatuses.join(', ') }));
12
+ process.exit(1);
13
+ }
14
+ const tasks = db
15
+ .select()
16
+ .from(schema.tasks)
17
+ .where(eq(schema.tasks.status, status))
18
+ .all();
19
+ console.log(`\n${i18n.status[status]} (${tasks.length})`);
20
+ console.log('─'.repeat(40));
21
+ if (tasks.length === 0) {
22
+ console.log(` ${i18n.commands.list.noTasks}`);
23
+ }
24
+ else {
25
+ for (const task of tasks) {
26
+ const shortId = task.id.slice(0, 8);
27
+ let line = ` [${shortId}] ${task.title}`;
28
+ if (task.waitingFor) {
29
+ line += ` (${i18n.status.waiting.toLowerCase()}: ${task.waitingFor})`;
30
+ }
31
+ if (task.dueDate) {
32
+ line += ` (due: ${task.dueDate.toLocaleDateString()})`;
33
+ }
34
+ console.log(line);
35
+ }
36
+ }
37
+ console.log();
38
+ return;
39
+ }
40
+ // Show all lists
41
+ const statuses = ['inbox', 'next', 'waiting', 'someday'];
42
+ for (const s of statuses) {
43
+ const tasks = db
44
+ .select()
45
+ .from(schema.tasks)
46
+ .where(eq(schema.tasks.status, s))
47
+ .all();
48
+ console.log(`\n${i18n.status[s]} (${tasks.length})`);
49
+ console.log('─'.repeat(40));
50
+ if (tasks.length === 0) {
51
+ console.log(` ${i18n.commands.list.noTasks}`);
52
+ }
53
+ else {
54
+ for (const task of tasks) {
55
+ const shortId = task.id.slice(0, 8);
56
+ let line = ` [${shortId}] ${task.title}`;
57
+ if (task.waitingFor) {
58
+ line += ` (${i18n.status.waiting.toLowerCase()}: ${task.waitingFor})`;
59
+ }
60
+ console.log(line);
61
+ }
62
+ }
63
+ }
64
+ console.log();
65
+ }
66
+ export async function listProjects() {
67
+ const db = getDb();
68
+ const i18n = t();
69
+ const projects = db
70
+ .select()
71
+ .from(schema.tasks)
72
+ .where(eq(schema.tasks.isProject, true))
73
+ .all()
74
+ .filter(p => p.status !== 'done');
75
+ console.log(`\n${i18n.projectStatus.active} (${projects.length})`);
76
+ console.log('─'.repeat(40));
77
+ if (projects.length === 0) {
78
+ console.log(` ${i18n.commands.list.noProjects}`);
79
+ }
80
+ else {
81
+ for (const project of projects) {
82
+ const childTasks = db
83
+ .select()
84
+ .from(schema.tasks)
85
+ .where(eq(schema.tasks.parentId, project.id))
86
+ .all();
87
+ const activeTasks = childTasks.filter(t => t.status !== 'done').length;
88
+ const shortId = project.id.slice(0, 8);
89
+ console.log(` [${shortId}] ${project.title} (${fmt(i18n.commands.list.tasks, { count: activeTasks })})`);
90
+ if (project.description) {
91
+ console.log(` ${project.description}`);
92
+ }
93
+ }
94
+ }
95
+ console.log();
96
+ }
@@ -0,0 +1 @@
1
+ export declare function moveTask(taskId: string, targetStatus: string, waitingFor?: string): Promise<void>;