taskin 0.1.0-beta.0 → 0.1.0-beta.2

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 (110) hide show
  1. package/README.md +91 -12
  2. package/dist/index.d.ts +380 -5
  3. package/dist/index.js +1372 -25
  4. package/package.json +15 -11
  5. package/dist/commands/commands.types.d.ts +0 -13
  6. package/dist/commands/commands.types.js +0 -6
  7. package/dist/commands/commands.types.js.map +0 -1
  8. package/dist/commands/define-command/define-command.d.ts +0 -6
  9. package/dist/commands/define-command/define-command.js +0 -27
  10. package/dist/commands/define-command/define-command.js.map +0 -1
  11. package/dist/commands/define-command/define-command.test.d.ts +0 -4
  12. package/dist/commands/define-command/define-command.test.js +0 -125
  13. package/dist/commands/define-command/define-command.test.js.map +0 -1
  14. package/dist/commands/define-command/define-command.types.d.ts +0 -49
  15. package/dist/commands/define-command/define-command.types.js +0 -5
  16. package/dist/commands/define-command/define-command.types.js.map +0 -1
  17. package/dist/commands/define-command/index.d.ts +0 -5
  18. package/dist/commands/define-command/index.js +0 -6
  19. package/dist/commands/define-command/index.js.map +0 -1
  20. package/dist/commands/finish.d.ts +0 -4
  21. package/dist/commands/finish.js +0 -69
  22. package/dist/commands/finish.js.map +0 -1
  23. package/dist/commands/index.d.ts +0 -9
  24. package/dist/commands/index.js +0 -10
  25. package/dist/commands/index.js.map +0 -1
  26. package/dist/commands/init.d.ts +0 -4
  27. package/dist/commands/init.js +0 -192
  28. package/dist/commands/init.js.map +0 -1
  29. package/dist/commands/lint.d.ts +0 -4
  30. package/dist/commands/lint.js +0 -31
  31. package/dist/commands/lint.js.map +0 -1
  32. package/dist/commands/list.d.ts +0 -4
  33. package/dist/commands/list.js +0 -132
  34. package/dist/commands/list.js.map +0 -1
  35. package/dist/commands/pause.d.ts +0 -4
  36. package/dist/commands/pause.js +0 -69
  37. package/dist/commands/pause.js.map +0 -1
  38. package/dist/commands/start.d.ts +0 -4
  39. package/dist/commands/start.js +0 -70
  40. package/dist/commands/start.js.map +0 -1
  41. package/dist/index.js.map +0 -1
  42. package/dist/lib/colors.d.ts +0 -26
  43. package/dist/lib/colors.js +0 -42
  44. package/dist/lib/colors.js.map +0 -1
  45. package/dist/lib/file-system-task-linter/file-system-task-linter.d.ts +0 -36
  46. package/dist/lib/file-system-task-linter/file-system-task-linter.js +0 -219
  47. package/dist/lib/file-system-task-linter/file-system-task-linter.js.map +0 -1
  48. package/dist/lib/file-system-task-linter/file-system-task-linter.mock.d.ts +0 -81
  49. package/dist/lib/file-system-task-linter/file-system-task-linter.mock.js +0 -152
  50. package/dist/lib/file-system-task-linter/file-system-task-linter.mock.js.map +0 -1
  51. package/dist/lib/file-system-task-linter/file-system-task-linter.test.d.ts +0 -4
  52. package/dist/lib/file-system-task-linter/file-system-task-linter.test.js +0 -146
  53. package/dist/lib/file-system-task-linter/file-system-task-linter.test.js.map +0 -1
  54. package/dist/lib/file-system-task-linter/file-system-task-linter.types.d.ts +0 -52
  55. package/dist/lib/file-system-task-linter/file-system-task-linter.types.js +0 -6
  56. package/dist/lib/file-system-task-linter/file-system-task-linter.types.js.map +0 -1
  57. package/dist/lib/file-system-task-linter/index.d.ts +0 -6
  58. package/dist/lib/file-system-task-linter/index.js +0 -7
  59. package/dist/lib/file-system-task-linter/index.js.map +0 -1
  60. package/dist/lib/help.d.ts +0 -4
  61. package/dist/lib/help.js +0 -104
  62. package/dist/lib/help.js.map +0 -1
  63. package/dist/lib/index.d.ts +0 -6
  64. package/dist/lib/index.js +0 -7
  65. package/dist/lib/index.js.map +0 -1
  66. package/dist/lib/provider-installer/index.d.ts +0 -5
  67. package/dist/lib/provider-installer/index.js +0 -6
  68. package/dist/lib/provider-installer/index.js.map +0 -1
  69. package/dist/lib/provider-installer/provider-installer.d.ts +0 -28
  70. package/dist/lib/provider-installer/provider-installer.js +0 -86
  71. package/dist/lib/provider-installer/provider-installer.js.map +0 -1
  72. package/dist/lib/provider-installer/provider-installer.types.d.ts +0 -4
  73. package/dist/lib/provider-installer/provider-installer.types.js +0 -5
  74. package/dist/lib/provider-installer/provider-installer.types.js.map +0 -1
  75. package/dist/lib/provider-installer.d.ts +0 -27
  76. package/dist/lib/provider-installer.js +0 -86
  77. package/dist/lib/provider-installer.js.map +0 -1
  78. package/dist/lib/provider-registry/index.d.ts +0 -5
  79. package/dist/lib/provider-registry/index.js +0 -6
  80. package/dist/lib/provider-registry/index.js.map +0 -1
  81. package/dist/lib/provider-registry/provider-registry.d.ts +0 -9
  82. package/dist/lib/provider-registry/provider-registry.js +0 -111
  83. package/dist/lib/provider-registry/provider-registry.js.map +0 -1
  84. package/dist/lib/provider-registry/provider-registry.types.d.ts +0 -5
  85. package/dist/lib/provider-registry/provider-registry.types.js +0 -6
  86. package/dist/lib/provider-registry/provider-registry.types.js.map +0 -1
  87. package/dist/lib/provider-registry.d.ts +0 -26
  88. package/dist/lib/provider-registry.js +0 -111
  89. package/dist/lib/provider-registry.js.map +0 -1
  90. package/dist/lib/task-linter/index.d.ts +0 -5
  91. package/dist/lib/task-linter/index.js +0 -6
  92. package/dist/lib/task-linter/index.js.map +0 -1
  93. package/dist/lib/task-linter/task-linter.d.ts +0 -36
  94. package/dist/lib/task-linter/task-linter.js +0 -219
  95. package/dist/lib/task-linter/task-linter.js.map +0 -1
  96. package/dist/lib/task-linter/task-linter.types.d.ts +0 -52
  97. package/dist/lib/task-linter/task-linter.types.js +0 -6
  98. package/dist/lib/task-linter/task-linter.types.js.map +0 -1
  99. package/dist/lib/task-linter.d.ts +0 -29
  100. package/dist/lib/task-linter.js +0 -215
  101. package/dist/lib/task-linter.js.map +0 -1
  102. package/dist/lib/task-linter.types.d.ts +0 -38
  103. package/dist/lib/task-linter.types.js +0 -5
  104. package/dist/lib/task-linter.types.js.map +0 -1
  105. package/dist/main.d.ts +0 -14
  106. package/dist/main.js +0 -29
  107. package/dist/main.js.map +0 -1
  108. package/dist/taskin.d.ts +0 -33
  109. package/dist/taskin.js +0 -101
  110. package/dist/taskin.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,38 +1,1385 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Taskin CLI - Main entry point
4
- * Command-line interface for managing tasks
5
- */
6
- import { Command } from 'commander';
7
- import { finishCommand } from './commands/finish.js';
8
- import { initCommand } from './commands/init.js';
9
- import { lintCommand } from './commands/lint.js';
10
- import { listCommand } from './commands/list.js';
11
- import { pauseCommand } from './commands/pause.js';
12
- import { startCommand } from './commands/start.js';
13
- import { showCustomHelp } from './lib/help.js';
14
- const program = new Command();
15
- program
16
- .name('taskin')
17
- .description('🚀 Task Management System')
18
- .version('0.1.0')
19
- .configureHelp({
20
- formatHelp: () => showCustomHelp(),
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
4
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
5
+ }) : x)(function(x) {
6
+ if (typeof require !== "undefined") return require.apply(this, arguments);
7
+ throw Error('Dynamic require of "' + x + '" is not supported');
8
+ });
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+
13
+ // ../../node_modules/.pnpm/tsup@8.5.0_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
14
+ import path from "path";
15
+ import { fileURLToPath } from "url";
16
+ var init_esm_shims = __esm({
17
+ "../../node_modules/.pnpm/tsup@8.5.0_postcss@8.5.6_tsx@4.20.6_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js"() {
18
+ "use strict";
19
+ }
20
+ });
21
+
22
+ // src/index.ts
23
+ init_esm_shims();
24
+ import { Command } from "commander";
25
+
26
+ // src/commands/finish.ts
27
+ init_esm_shims();
28
+
29
+ // ../fs-task-provider/src/index.ts
30
+ init_esm_shims();
31
+
32
+ // ../fs-task-provider/src/fs-task-provider.ts
33
+ init_esm_shims();
34
+ import { promises as fs } from "fs";
35
+ import path2 from "path";
36
+ var FileSystemTaskProvider = class {
37
+ constructor(tasksDirectory) {
38
+ this.tasksDirectory = tasksDirectory;
39
+ }
40
+ async findTask(taskId) {
41
+ const files = await fs.readdir(this.tasksDirectory);
42
+ const taskFile = files.find(
43
+ (file) => file.startsWith(`task-${taskId}-`) && file.endsWith(".md")
44
+ );
45
+ if (!taskFile) {
46
+ return void 0;
47
+ }
48
+ const filePath = path2.join(this.tasksDirectory, taskFile);
49
+ const content = await fs.readFile(filePath, "utf-8");
50
+ const titleMatch = content.match(/^# Task \d+ - (.+)$/m);
51
+ const title = titleMatch ? titleMatch[1] : "Untitled";
52
+ const task = {
53
+ id: taskId,
54
+ title,
55
+ content,
56
+ filePath,
57
+ userId: "unknown",
58
+ status: "pending",
59
+ type: "feat",
60
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
61
+ };
62
+ return task;
63
+ }
64
+ async updateTask(task) {
65
+ await fs.writeFile(task.filePath, task.content);
66
+ }
67
+ async getAllTasks() {
68
+ const files = await fs.readdir(this.tasksDirectory);
69
+ const taskFiles = files.filter(
70
+ (file) => file.startsWith("task-") && file.endsWith(".md")
71
+ );
72
+ const tasks = [];
73
+ for (const file of taskFiles) {
74
+ const filePath = path2.join(this.tasksDirectory, file);
75
+ const content = await fs.readFile(filePath, "utf-8");
76
+ const idMatch = file.match(/^task-(\d+)-/);
77
+ const taskId = idMatch ? idMatch[1] : "unknown";
78
+ const titleMatch = content.match(/^# .*Task.*?[—-]\s*(.+)$/im);
79
+ const title = titleMatch ? titleMatch[1].trim() : "Untitled";
80
+ const headerSection = content.split(/^##/m)[0];
81
+ const statusMatch = headerSection.match(/^Status:\s*(.+)$/im);
82
+ const typeMatch = headerSection.match(/^Type:\s*(.+)$/im);
83
+ const userMatch = headerSection.match(/^Assignee:\s*(.+)$/im);
84
+ const task = {
85
+ id: taskId,
86
+ title,
87
+ content,
88
+ filePath,
89
+ userId: userMatch ? userMatch[1].trim() : void 0,
90
+ status: statusMatch ? statusMatch[1].trim().toLowerCase() : "pending",
91
+ type: typeMatch ? typeMatch[1].trim().toLowerCase() : "feat",
92
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
93
+ };
94
+ tasks.push(task);
95
+ }
96
+ return tasks;
97
+ }
98
+ };
99
+
100
+ // ../task-manager/src/index.ts
101
+ init_esm_shims();
102
+
103
+ // ../task-manager/src/task-manager.ts
104
+ init_esm_shims();
105
+ var TaskManager = class {
106
+ constructor(taskProvider) {
107
+ this.taskProvider = taskProvider;
108
+ }
109
+ async startTask(taskId) {
110
+ const task = await this.taskProvider.findTask(taskId);
111
+ if (!task) {
112
+ throw new Error(`Task with ID '${taskId}' not found.`);
113
+ }
114
+ if (task.status === "in-progress") {
115
+ throw new Error(`Task '${taskId}' is already in progress.`);
116
+ }
117
+ if (task.status === "done") {
118
+ throw new Error(`Task '${taskId}' is already done.`);
119
+ }
120
+ const updatedTask = { ...task, status: "in-progress" };
121
+ await this.taskProvider.updateTask(updatedTask);
122
+ return updatedTask;
123
+ }
124
+ async finishTask(taskId) {
125
+ const task = await this.taskProvider.findTask(taskId);
126
+ if (!task) {
127
+ throw new Error(`Task with ID '${taskId}' not found.`);
128
+ }
129
+ const updatedTask = { ...task, status: "done" };
130
+ await this.taskProvider.updateTask(updatedTask);
131
+ return updatedTask;
132
+ }
133
+ };
134
+
135
+ // ../task-manager/src/task-manager.mock.ts
136
+ init_esm_shims();
137
+
138
+ // ../task-manager/src/task-manager.types.ts
139
+ init_esm_shims();
140
+
141
+ // src/commands/finish.ts
142
+ import path3 from "path";
143
+
144
+ // src/lib/colors.ts
145
+ init_esm_shims();
146
+ import chalk from "chalk";
147
+ var colors = {
148
+ info: chalk.cyan,
149
+ success: chalk.green,
150
+ warning: chalk.yellow,
151
+ error: chalk.red,
152
+ highlight: chalk.bold.white,
153
+ secondary: chalk.gray,
154
+ normal: chalk.white
155
+ };
156
+ var icons = {
157
+ rocket: "\u{1F680}",
158
+ list: "\u{1F4CA}",
159
+ check: "\u2705",
160
+ pause: "\u23F8\uFE0F",
161
+ info: "\u{1F4A1}",
162
+ task: "\u{1F4CB}",
163
+ gear: "\u2699\uFE0F"
164
+ };
165
+ function printHeader(title, icon) {
166
+ console.log();
167
+ console.log(colors.highlight("\u2550".repeat(60)));
168
+ console.log(colors.highlight(`${icon} ${title}`));
169
+ console.log(colors.highlight("\u2550".repeat(60)));
170
+ console.log();
171
+ }
172
+ function success(message) {
173
+ console.log(colors.success(`\u2713 ${message}`));
174
+ }
175
+ function error(message) {
176
+ console.error(colors.error(`\u2717 ${message}`));
177
+ }
178
+ function info(message) {
179
+ console.log(colors.info(`\u2139 ${message}`));
180
+ }
181
+
182
+ // src/commands/define-command/index.ts
183
+ init_esm_shims();
184
+
185
+ // src/commands/define-command/define-command.ts
186
+ init_esm_shims();
187
+ var defineCommand = (config) => {
188
+ return (program2) => {
189
+ const cmd = program2.command(config.name).description(config.description);
190
+ if (config.alias) {
191
+ cmd.alias(config.alias);
192
+ }
193
+ config.options?.forEach((opt) => {
194
+ cmd.option(opt.flags, opt.description, opt.defaultValue);
195
+ });
196
+ cmd.action(async (...args) => {
197
+ try {
198
+ await config.handler(...args);
199
+ } catch (err) {
200
+ error(
201
+ `Failed to execute command: ${err instanceof Error ? err.message : String(err)}`
202
+ );
203
+ process.exit(1);
204
+ }
205
+ });
206
+ };
207
+ };
208
+
209
+ // src/commands/define-command/define-command.types.ts
210
+ init_esm_shims();
211
+
212
+ // src/commands/finish.ts
213
+ var finishCommand = defineCommand({
214
+ name: "finish <task-id>",
215
+ description: "\u2705 Complete a task",
216
+ alias: "done",
217
+ options: [
218
+ {
219
+ flags: "-s, --skip-update",
220
+ description: "Skip updating task status"
221
+ }
222
+ ],
223
+ handler: async (taskId, options) => {
224
+ await finishTask(taskId, options);
225
+ }
226
+ });
227
+ async function finishTask(taskId, options) {
228
+ printHeader(`Finishing Task ${taskId}`, "\u2705");
229
+ const normalizedId = taskId.replace(/^task-/, "").padStart(3, "0");
230
+ const tasksDir = path3.join(process.cwd(), "TASKS");
231
+ const taskProvider = new FileSystemTaskProvider(tasksDir);
232
+ const taskManager = new TaskManager(taskProvider);
233
+ const task = await taskProvider.findTask(normalizedId);
234
+ if (!task) {
235
+ error(`Task ${normalizedId} not found in TASKS/ directory`);
236
+ process.exit(1);
237
+ }
238
+ info(`Found task: ${task.title}`);
239
+ info(`Current status: ${task.status}`);
240
+ if (task.status === "done") {
241
+ error("Task is already done");
242
+ process.exit(1);
243
+ }
244
+ if (!options.skipUpdate) {
245
+ info("Marking task as done...");
246
+ const updatedTask = await taskManager.finishTask(task.id);
247
+ success(`Task ${updatedTask.id} completed successfully! \u{1F389}`);
248
+ success(`Status changed to: ${updatedTask.status}`);
249
+ } else {
250
+ info("Skipping status update (--skip-update flag)");
251
+ }
252
+ console.log();
253
+ info("Suggested commit message:");
254
+ const commitType = task.type || "feat";
255
+ console.log(
256
+ colors.highlight(` ${commitType}(task-${normalizedId}): ${task.title}`)
257
+ );
258
+ console.log();
259
+ info("Next steps:");
260
+ console.log(colors.secondary(" 1. Review your changes"));
261
+ console.log(colors.secondary(" 2. Commit: git add . && git commit"));
262
+ console.log(colors.secondary(" 3. Push: git push"));
263
+ console.log(colors.secondary(" 4. Create a Pull Request"));
264
+ console.log();
265
+ success("Great work! \u{1F680}");
266
+ console.log();
267
+ }
268
+
269
+ // src/commands/init.ts
270
+ init_esm_shims();
271
+ import { existsSync as existsSync2, mkdirSync, writeFileSync } from "fs";
272
+ import inquirer from "inquirer";
273
+ import { join } from "path";
274
+
275
+ // src/lib/provider-installer/index.ts
276
+ init_esm_shims();
277
+
278
+ // src/lib/provider-installer/provider-installer.ts
279
+ init_esm_shims();
280
+ import { execSync } from "child_process";
281
+ import { existsSync } from "fs";
282
+ function detectPackageManager() {
283
+ if (existsSync("pnpm-lock.yaml")) {
284
+ return "pnpm";
285
+ }
286
+ if (existsSync("yarn.lock")) {
287
+ return "yarn";
288
+ }
289
+ return "npm";
290
+ }
291
+ function isProviderInstalled(packageName) {
292
+ try {
293
+ __require.resolve(packageName);
294
+ return true;
295
+ } catch {
296
+ return false;
297
+ }
298
+ }
299
+ function installProvider(provider) {
300
+ const packageManager = detectPackageManager();
301
+ const { packageName } = provider;
302
+ console.log(`
303
+ \u{1F4E6} Installing ${packageName}...`);
304
+ try {
305
+ let command;
306
+ switch (packageManager) {
307
+ case "pnpm":
308
+ command = `pnpm add ${packageName}`;
309
+ break;
310
+ case "yarn":
311
+ command = `yarn add ${packageName}`;
312
+ break;
313
+ default:
314
+ command = `npm install ${packageName}`;
315
+ }
316
+ execSync(command, { stdio: "inherit" });
317
+ console.log(`\u2705 ${packageName} installed successfully!
318
+ `);
319
+ } catch (error2) {
320
+ console.error(`
321
+ \u274C Failed to install ${packageName}`);
322
+ throw error2;
323
+ }
324
+ }
325
+ async function loadProvider(packageName) {
326
+ try {
327
+ const module = await import(packageName);
328
+ return module.default || module;
329
+ } catch (error2) {
330
+ console.error(`Failed to load provider: ${packageName}`);
331
+ throw error2;
332
+ }
333
+ }
334
+ async function ensureProviderInstalled(provider) {
335
+ const { packageName } = provider;
336
+ if (!isProviderInstalled(packageName)) {
337
+ console.log(`
338
+ \u26A0\uFE0F Provider ${packageName} is not installed.`);
339
+ installProvider(provider);
340
+ }
341
+ return loadProvider(packageName);
342
+ }
343
+
344
+ // src/lib/provider-installer/provider-installer.types.ts
345
+ init_esm_shims();
346
+
347
+ // src/lib/provider-registry/index.ts
348
+ init_esm_shims();
349
+
350
+ // src/lib/provider-registry/provider-registry.ts
351
+ init_esm_shims();
352
+ var AVAILABLE_PROVIDERS = [
353
+ {
354
+ id: "fs",
355
+ name: "\u{1F4C1} File System",
356
+ description: "Store tasks as Markdown files in a local TASKS/ directory",
357
+ packageName: "@opentask/taskin-fs-provider",
358
+ configSchema: {
359
+ required: ["tasksDir"],
360
+ properties: {
361
+ tasksDir: {
362
+ type: "string",
363
+ description: "Directory to store task files"
364
+ }
365
+ }
366
+ },
367
+ status: "stable"
368
+ },
369
+ {
370
+ id: "redmine",
371
+ name: "\u{1F534} Redmine",
372
+ description: "Sync tasks with Redmine issues via REST API",
373
+ packageName: "@opentask/taskin-redmine-provider",
374
+ configSchema: {
375
+ required: ["apiUrl", "apiKey", "projectId"],
376
+ properties: {
377
+ apiUrl: {
378
+ type: "string",
379
+ description: "Redmine server URL (e.g., https://redmine.example.com)"
380
+ },
381
+ apiKey: {
382
+ type: "string",
383
+ description: "Your Redmine API key",
384
+ secret: true
385
+ },
386
+ projectId: {
387
+ type: "string",
388
+ description: "Project identifier or ID"
389
+ }
390
+ }
391
+ },
392
+ status: "coming-soon"
393
+ },
394
+ {
395
+ id: "jira",
396
+ name: "\u{1F535} Jira",
397
+ description: "Sync tasks with Jira issues via REST API",
398
+ packageName: "@opentask/taskin-jira-provider",
399
+ configSchema: {
400
+ required: ["apiUrl", "email", "apiToken", "projectKey"],
401
+ properties: {
402
+ apiUrl: {
403
+ type: "string",
404
+ description: "Jira server URL (e.g., https://company.atlassian.net)"
405
+ },
406
+ email: {
407
+ type: "string",
408
+ description: "Your Atlassian account email"
409
+ },
410
+ apiToken: {
411
+ type: "string",
412
+ description: "Your Jira API token",
413
+ secret: true
414
+ },
415
+ projectKey: {
416
+ type: "string",
417
+ description: "Project key (e.g., PROJ)"
418
+ }
419
+ }
420
+ },
421
+ status: "coming-soon"
422
+ },
423
+ {
424
+ id: "github",
425
+ name: "\u{1F419} GitHub Issues",
426
+ description: "Sync tasks with GitHub Issues",
427
+ packageName: "@opentask/taskin-github-provider",
428
+ configSchema: {
429
+ required: ["owner", "repo", "token"],
430
+ properties: {
431
+ owner: {
432
+ type: "string",
433
+ description: "Repository owner (username or organization)"
434
+ },
435
+ repo: {
436
+ type: "string",
437
+ description: "Repository name"
438
+ },
439
+ token: {
440
+ type: "string",
441
+ description: "GitHub Personal Access Token",
442
+ secret: true
443
+ }
444
+ }
445
+ },
446
+ status: "coming-soon"
447
+ }
448
+ ];
449
+ function getProviderById(id) {
450
+ return AVAILABLE_PROVIDERS.find((p) => p.id === id);
451
+ }
452
+ function getAllProviders() {
453
+ return AVAILABLE_PROVIDERS;
454
+ }
455
+
456
+ // src/lib/provider-registry/provider-registry.types.ts
457
+ init_esm_shims();
458
+
459
+ // src/commands/init.ts
460
+ var initCommand = defineCommand({
461
+ name: "init",
462
+ alias: "setup",
463
+ description: "\u{1F3AF} Initialize Taskin in your project",
464
+ options: [
465
+ {
466
+ flags: "-f, --force",
467
+ description: "Force initialization (overwrite existing configuration)"
468
+ }
469
+ ],
470
+ handler: async (options) => {
471
+ await initializeTaskin(options);
472
+ }
473
+ });
474
+ async function initializeTaskin(options) {
475
+ printHeader("Initializing Taskin", "\u{1F3AF}");
476
+ const cwd = process.cwd();
477
+ const configFile = join(cwd, ".taskin.json");
478
+ if (existsSync2(configFile) && !options.force) {
479
+ error("Taskin is already initialized in this project");
480
+ info("Use --force to reinitialize");
481
+ process.exit(1);
482
+ }
483
+ const allProviders = getAllProviders();
484
+ const choices = allProviders.map((p) => {
485
+ const installed = isProviderInstalled(p.packageName);
486
+ const status = p.status === "coming-soon" ? " (coming soon)" : "";
487
+ const installedMark = installed ? " \u2713" : "";
488
+ return {
489
+ name: `${p.name}${installedMark}${status} - ${p.description}`,
490
+ value: p.id,
491
+ disabled: p.status === "coming-soon" ? "Not yet implemented" : false
492
+ };
21
493
  });
22
- // Register commands
494
+ const { providerId } = await inquirer.prompt([
495
+ {
496
+ type: "list",
497
+ name: "providerId",
498
+ message: "Select a task provider:",
499
+ choices,
500
+ default: "fs"
501
+ }
502
+ ]);
503
+ const selectedProvider = getProviderById(providerId);
504
+ if (!selectedProvider) {
505
+ error(`Provider "${providerId}" not found`);
506
+ process.exit(1);
507
+ }
508
+ console.log();
509
+ info(`Setting up task provider: ${colors.highlight(selectedProvider.name)}`);
510
+ console.log();
511
+ await ensureProviderInstalled(selectedProvider);
512
+ const providerConfig = await setupProviderConfig(selectedProvider, cwd);
513
+ const config = {
514
+ version: "0.1.0",
515
+ provider: {
516
+ type: selectedProvider.id,
517
+ config: providerConfig
518
+ }
519
+ };
520
+ info("Creating configuration file...");
521
+ writeFileSync(configFile, JSON.stringify(config, null, 2), "utf-8");
522
+ success(`\u2713 Created ${colors.highlight(".taskin.json")}`);
523
+ const gitignorePath = join(cwd, ".gitignore");
524
+ if (existsSync2(gitignorePath)) {
525
+ const gitignoreContent = __require("fs").readFileSync(gitignorePath, "utf-8");
526
+ if (!gitignoreContent.includes(".taskin.json")) {
527
+ info("Adding .taskin.json to .gitignore...");
528
+ writeFileSync(
529
+ gitignorePath,
530
+ `${gitignoreContent}
531
+ # Taskin configuration
532
+ .taskin.json
533
+ `,
534
+ "utf-8"
535
+ );
536
+ success("\u2713 Updated .gitignore");
537
+ }
538
+ }
539
+ console.log();
540
+ success("\u{1F389} Taskin initialized successfully!");
541
+ console.log();
542
+ info("Next steps:");
543
+ console.log(colors.secondary(" 1. Run: taskin list"));
544
+ console.log(
545
+ colors.secondary(
546
+ selectedProvider.id === "fs" ? " 2. Edit or create tasks in TASKS/" : ` 2. Tasks will be synced with ${selectedProvider.name}`
547
+ )
548
+ );
549
+ console.log(colors.secondary(" 3. Start working: taskin start <task-id>"));
550
+ console.log();
551
+ info("For more information, run: taskin --help");
552
+ console.log();
553
+ }
554
+ async function setupProviderConfig(provider, cwd) {
555
+ if (provider.id === "fs") {
556
+ return setupFileSystemProvider(cwd);
557
+ }
558
+ info(`Configuring ${provider.name}...`);
559
+ console.log();
560
+ const questions = Object.entries(provider.configSchema.properties).map(
561
+ ([key, schema]) => ({
562
+ type: schema.secret ? "password" : "input",
563
+ name: key,
564
+ message: `${schema.description}:`,
565
+ validate: (input) => {
566
+ if (provider.configSchema.required.includes(key) && input.length === 0) {
567
+ return `${schema.description} is required`;
568
+ }
569
+ return true;
570
+ }
571
+ })
572
+ );
573
+ const answers = await inquirer.prompt(questions);
574
+ console.log();
575
+ success(`\u2713 ${provider.name} configuration saved`);
576
+ return answers;
577
+ }
578
+ async function setupFileSystemProvider(cwd) {
579
+ const tasksDir = join(cwd, "TASKS");
580
+ if (!existsSync2(tasksDir)) {
581
+ info(`Creating TASKS directory...`);
582
+ mkdirSync(tasksDir, { recursive: true });
583
+ success(`\u2713 Created ${colors.highlight("TASKS/")} directory`);
584
+ } else {
585
+ info(`${colors.highlight("TASKS/")} directory already exists`);
586
+ }
587
+ const sampleTaskFile = join(tasksDir, "task-001-setup-project.md");
588
+ if (!existsSync2(sampleTaskFile)) {
589
+ info("Creating sample task...");
590
+ const sampleTask = `# Task 001 \u2014 Setup Project
591
+
592
+ Status: pending
593
+ Type: chore
594
+ Assignee: developer
595
+
596
+ ## Description
597
+
598
+ This is a sample task created during Taskin initialization.
599
+
600
+ ## Tasks
601
+
602
+ - [ ] Review Taskin documentation
603
+ - [ ] Create your first task
604
+ - [ ] Start working on a task
605
+
606
+ ## Notes
607
+
608
+ You can edit or delete this file. Use \`taskin list\` to see all tasks.
609
+ `;
610
+ writeFileSync(sampleTaskFile, sampleTask, "utf-8");
611
+ success(
612
+ `\u2713 Created sample task ${colors.highlight("task-001-setup-project.md")}`
613
+ );
614
+ }
615
+ return {
616
+ tasksDir: "TASKS"
617
+ };
618
+ }
619
+
620
+ // src/commands/lint.ts
621
+ init_esm_shims();
622
+ import { join as join3 } from "path";
623
+
624
+ // src/lib/file-system-task-linter/index.ts
625
+ init_esm_shims();
626
+
627
+ // src/lib/file-system-task-linter/file-system-task-linter.ts
628
+ init_esm_shims();
629
+ import chalk2 from "chalk";
630
+ import { readdir, readFile } from "fs/promises";
631
+ import { join as join2 } from "path";
632
+ var VALID_STATUSES = ["pending", "in-progress", "done", "blocked"];
633
+ var VALID_TYPES = ["feat", "fix", "chore", "docs", "refactor", "test"];
634
+ var FileSystemTaskLinter = class {
635
+ errors = [];
636
+ addError(file, message, severity = "error", line) {
637
+ this.errors.push({ file, message, severity, line });
638
+ }
639
+ /**
640
+ * Validate task file name format (FileSystem-specific)
641
+ */
642
+ validateFileName(fileName) {
643
+ const pattern = /^task-\d{2,3}-[a-z0-9-]+\.md$/;
644
+ if (!pattern.test(fileName)) {
645
+ return {
646
+ file: fileName,
647
+ message: "Invalid filename. Expected: task-NNN-kebab-case-title.md",
648
+ severity: "error"
649
+ };
650
+ }
651
+ return null;
652
+ }
653
+ extractMetadata(content) {
654
+ const headerSection = content.split(/^##/m)[0];
655
+ const statusMatch = headerSection.match(/^Status:\s*(.+)$/im);
656
+ const typeMatch = headerSection.match(/^Type:\s*(.+)$/im);
657
+ const assigneeMatch = headerSection.match(/^Assignee:\s*(.+)$/im);
658
+ return {
659
+ status: statusMatch?.[1]?.trim().toLowerCase(),
660
+ type: typeMatch?.[1]?.trim().toLowerCase(),
661
+ assignee: assigneeMatch?.[1]?.trim()
662
+ };
663
+ }
664
+ /**
665
+ * Validate task metadata (FileSystem-specific)
666
+ */
667
+ validateMetadata(metadata, filePath) {
668
+ const errors = [];
669
+ if (!metadata.status) {
670
+ errors.push({
671
+ file: filePath,
672
+ message: "Missing required metadata: Status",
673
+ severity: "error"
674
+ });
675
+ } else if (!VALID_STATUSES.includes(metadata.status)) {
676
+ errors.push({
677
+ file: filePath,
678
+ message: `Invalid status "${metadata.status}". Valid: ${VALID_STATUSES.join(", ")}`,
679
+ severity: "error"
680
+ });
681
+ }
682
+ if (!metadata.type) {
683
+ errors.push({
684
+ file: filePath,
685
+ message: "Missing required metadata: Type",
686
+ severity: "error"
687
+ });
688
+ } else if (!VALID_TYPES.includes(metadata.type)) {
689
+ errors.push({
690
+ file: filePath,
691
+ message: `Invalid type "${metadata.type}". Valid: ${VALID_TYPES.join(", ")}`,
692
+ severity: "error"
693
+ });
694
+ }
695
+ if (!metadata.assignee) {
696
+ errors.push({
697
+ file: filePath,
698
+ message: "Missing recommended metadata: Assignee",
699
+ severity: "warning"
700
+ });
701
+ }
702
+ return errors;
703
+ }
704
+ validateContent(filename, content) {
705
+ const lines = content.split("\n");
706
+ if (!lines[0]?.trim().startsWith("# ")) {
707
+ this.addError(
708
+ filename,
709
+ "Task file must start with a level 1 heading (# Task NNN \u2014 Title)",
710
+ "error",
711
+ 1
712
+ );
713
+ }
714
+ const h1Pattern = /^#\s+(?:🧩\s+)?Task\s+\d{2,3}\s+[—-]\s+.+$/i;
715
+ if (lines[0] && !h1Pattern.test(lines[0])) {
716
+ this.addError(
717
+ filename,
718
+ 'H1 heading must follow format: "# Task NNN \u2014 Title"',
719
+ "error",
720
+ 1
721
+ );
722
+ }
723
+ const metadata = this.extractMetadata(content);
724
+ const metadataErrors = this.validateMetadata(metadata, filename);
725
+ metadataErrors.forEach((error2) => {
726
+ this.addError(error2.file, error2.message, error2.severity, error2.line);
727
+ });
728
+ const h2Sections = content.match(/^##\s+.+$/gm);
729
+ if (!h2Sections || h2Sections.length === 0) {
730
+ this.addError(
731
+ filename,
732
+ "Task should have at least one section (## heading)",
733
+ "warning"
734
+ );
735
+ }
736
+ const firstH2Index = content.indexOf("\n##");
737
+ if (firstH2Index > -1) {
738
+ const afterH2 = content.substring(firstH2Index);
739
+ if (afterH2.match(/^Status:/im) || afterH2.match(/^Type:/im) || afterH2.match(/^Assignee:/im)) {
740
+ this.addError(
741
+ filename,
742
+ "Metadata must be placed BEFORE the first ## section",
743
+ "error"
744
+ );
745
+ }
746
+ }
747
+ }
748
+ /**
749
+ * Lint a single task file (FileSystem-specific)
750
+ */
751
+ async lintFile(filePath) {
752
+ const errors = [];
753
+ const fileName = filePath.split("/").pop() || filePath;
754
+ const fileNameError = this.validateFileName(fileName);
755
+ if (fileNameError) {
756
+ errors.push(fileNameError);
757
+ }
758
+ try {
759
+ const content = await readFile(filePath, "utf-8");
760
+ this.errors = [];
761
+ this.validateContent(fileName, content);
762
+ errors.push(...this.errors);
763
+ } catch (error2) {
764
+ errors.push({
765
+ file: fileName,
766
+ message: `Failed to read file: ${error2}`,
767
+ severity: "error"
768
+ });
769
+ }
770
+ return errors;
771
+ }
772
+ /**
773
+ * Lint all task files in the specified directory (FileSystem-specific)
774
+ */
775
+ async lintDirectory(tasksDir) {
776
+ this.errors = [];
777
+ try {
778
+ const files = await readdir(tasksDir);
779
+ const taskFiles = files.filter((f) => f.endsWith(".md"));
780
+ for (const file of taskFiles) {
781
+ const fileNameError = this.validateFileName(file);
782
+ if (fileNameError) {
783
+ this.addError(file, fileNameError.message, fileNameError.severity);
784
+ }
785
+ const content = await readFile(join2(tasksDir, file), "utf-8");
786
+ this.validateContent(file, content);
787
+ }
788
+ const errors = this.errors.filter((e) => e.severity === "error");
789
+ const warnings = this.errors.filter((e) => e.severity === "warning");
790
+ return {
791
+ errors,
792
+ warnings,
793
+ filesChecked: taskFiles.length,
794
+ valid: errors.length === 0
795
+ };
796
+ } catch (error2) {
797
+ throw new Error(`Failed to lint tasks: ${error2}`);
798
+ }
799
+ }
800
+ static printResults(result) {
801
+ if (result.errors.length === 0 && result.warnings.length === 0) {
802
+ console.log(
803
+ chalk2.green(`\u2705 All ${result.filesChecked} task files are valid!
804
+ `)
805
+ );
806
+ return;
807
+ }
808
+ console.log(
809
+ chalk2.bold(
810
+ `
811
+ \u{1F4CA} Validation Results (${result.filesChecked} files checked):
812
+ `
813
+ )
814
+ );
815
+ const errorsByFile = /* @__PURE__ */ new Map();
816
+ [...result.errors, ...result.warnings].forEach((error2) => {
817
+ if (!errorsByFile.has(error2.file)) {
818
+ errorsByFile.set(error2.file, []);
819
+ }
820
+ errorsByFile.get(error2.file).push(error2);
821
+ });
822
+ for (const [file, fileErrors] of errorsByFile) {
823
+ console.log(chalk2.cyan(`
824
+ \u{1F4C4} ${file}`));
825
+ for (const error2 of fileErrors) {
826
+ const icon = error2.severity === "error" ? chalk2.red("\u274C") : chalk2.yellow("\u26A0\uFE0F");
827
+ const location = error2.line ? `:${error2.line}` : "";
828
+ console.log(` ${icon} ${error2.message}${location}`);
829
+ }
830
+ }
831
+ console.log("\n" + "\u2500".repeat(60));
832
+ console.log(
833
+ chalk2.bold(
834
+ `
835
+ \u{1F4CA} Summary: ${chalk2.red(result.errors.length + " error(s)")}, ${chalk2.yellow(result.warnings.length + " warning(s)")}
836
+ `
837
+ )
838
+ );
839
+ }
840
+ };
841
+
842
+ // src/lib/file-system-task-linter/file-system-task-linter.mock.ts
843
+ init_esm_shims();
844
+ function createMockFileValidationError(overrides) {
845
+ return {
846
+ file: "task-001.md",
847
+ message: "Mock validation error",
848
+ severity: "error",
849
+ ...overrides
850
+ };
851
+ }
852
+ var MOCK_INVALID_LINT_RESULT = {
853
+ errors: [
854
+ createMockFileValidationError({
855
+ file: "task-001.md",
856
+ message: 'Invalid status: "invalid"'
857
+ }),
858
+ createMockFileValidationError({
859
+ file: "task-002.md",
860
+ message: 'Invalid type: "unknown"'
861
+ })
862
+ ],
863
+ filesChecked: 2,
864
+ valid: false,
865
+ warnings: []
866
+ };
867
+ var MOCK_WARNINGS_LINT_RESULT = {
868
+ errors: [],
869
+ filesChecked: 3,
870
+ valid: true,
871
+ warnings: [
872
+ createMockFileValidationError({
873
+ file: "task-003.md",
874
+ message: "Consider adding assignee",
875
+ severity: "warning"
876
+ })
877
+ ]
878
+ };
879
+ var MOCK_VALIDATION_ERRORS = [
880
+ createMockFileValidationError({
881
+ file: "task-001.md",
882
+ message: "Invalid status: must be one of [pending, in-progress, done, blocked]",
883
+ line: 5
884
+ }),
885
+ createMockFileValidationError({
886
+ file: "task-001.md",
887
+ message: "Invalid type: must be one of [feat, fix, chore, docs, refactor, test]",
888
+ line: 6
889
+ })
890
+ ];
891
+
892
+ // src/lib/file-system-task-linter/file-system-task-linter.types.ts
893
+ init_esm_shims();
894
+
895
+ // src/commands/lint.ts
896
+ var lintCommand = defineCommand({
897
+ name: "lint",
898
+ description: "\u{1F50D} Validate task markdown files",
899
+ options: [
900
+ {
901
+ flags: "-p, --path <directory>",
902
+ description: "Path to TASKS directory",
903
+ defaultValue: "TASKS"
904
+ }
905
+ ],
906
+ handler: async (options) => {
907
+ await executeLint(options);
908
+ }
909
+ });
910
+ async function executeLint(options) {
911
+ const tasksDir = options.path || join3(process.cwd(), "TASKS");
912
+ console.log(`\u{1F4CB} Linting task files in: ${tasksDir}
913
+ `);
914
+ const linter = new FileSystemTaskLinter();
915
+ const result = await linter.lintDirectory(tasksDir);
916
+ FileSystemTaskLinter.printResults(result);
917
+ if (!result.valid) {
918
+ process.exit(1);
919
+ }
920
+ }
921
+
922
+ // src/commands/list.ts
923
+ init_esm_shims();
924
+ import path4 from "path";
925
+ var listCommand = defineCommand({
926
+ name: "list [filter]",
927
+ description: "\u{1F4CA} List all tasks in the project",
928
+ alias: "ls",
929
+ options: [
930
+ {
931
+ flags: "-s, --status <status>",
932
+ description: "Filter by status (pending, in-progress, done, blocked)"
933
+ },
934
+ {
935
+ flags: "-t, --type <type>",
936
+ description: "Filter by type (feat, fix, refactor, docs, test, chore)"
937
+ },
938
+ {
939
+ flags: "-u, --user <user>",
940
+ description: "Filter by user"
941
+ }
942
+ ],
943
+ handler: async (filter, options) => {
944
+ await listTasks(filter, options);
945
+ }
946
+ });
947
+ async function listTasks(filter, options) {
948
+ printHeader("Task List", "\u{1F4CA}");
949
+ const tasksDir = path4.join(process.cwd(), "TASKS");
950
+ const taskProvider = new FileSystemTaskProvider(tasksDir);
951
+ const tasks = await taskProvider.getAllTasks();
952
+ if (tasks.length === 0) {
953
+ console.log(colors.warning("No tasks found in TASKS/ directory"));
954
+ return;
955
+ }
956
+ let filteredTasks = tasks;
957
+ if (options.status) {
958
+ filteredTasks = filteredTasks.filter((t) => t.status === options.status);
959
+ }
960
+ if (options.type) {
961
+ filteredTasks = filteredTasks.filter((t) => t.type === options.type);
962
+ }
963
+ if (options.assignee) {
964
+ filteredTasks = filteredTasks.filter(
965
+ (t) => t.userId?.toLowerCase().includes(options.assignee.toLowerCase())
966
+ );
967
+ }
968
+ if (filter) {
969
+ const lowerFilter = filter.toLowerCase();
970
+ filteredTasks = filteredTasks.filter(
971
+ (t) => t.id.includes(lowerFilter) || t.title.toLowerCase().includes(lowerFilter) || t.status.toLowerCase().includes(lowerFilter) || t.userId?.toLowerCase().includes(lowerFilter)
972
+ );
973
+ }
974
+ if (filteredTasks.length === 0) {
975
+ console.log(colors.warning("No tasks match the filters"));
976
+ return;
977
+ }
978
+ console.log(
979
+ colors.highlight(
980
+ `${"ID".padEnd(15)} ${"Status".padEnd(15)} ${"Type".padEnd(12)} ${"User".padEnd(15)} ${"Title"}`
981
+ )
982
+ );
983
+ console.log(colors.secondary("\u2500".repeat(100)));
984
+ filteredTasks.forEach((task) => {
985
+ const statusColor = getStatusColor(task.status);
986
+ const typeColor = getTypeColor(task.type);
987
+ console.log(
988
+ `${colors.info(task.id.padEnd(15))} ${statusColor(task.status.padEnd(15))} ${typeColor(task.type.padEnd(12))} ${colors.secondary((task.userId || "unknown").padEnd(15))} ${colors.normal(task.title)}`
989
+ );
990
+ });
991
+ console.log();
992
+ console.log(colors.secondary("\u2500".repeat(100)));
993
+ const statusCounts = {
994
+ pending: filteredTasks.filter((t) => t.status === "pending").length,
995
+ "in-progress": filteredTasks.filter((t) => t.status === "in-progress").length,
996
+ done: filteredTasks.filter((t) => t.status === "done").length,
997
+ blocked: filteredTasks.filter((t) => t.status === "blocked").length
998
+ };
999
+ console.log(
1000
+ colors.info(
1001
+ `\u{1F4CA} Total: ${filteredTasks.length} tasks | \u23F3 Pending: ${statusCounts.pending} | \u{1F680} In Progress: ${statusCounts["in-progress"]} | \u2705 Done: ${statusCounts.done} | \u{1F6AB} Blocked: ${statusCounts.blocked}`
1002
+ )
1003
+ );
1004
+ console.log();
1005
+ }
1006
+ function getStatusColor(status) {
1007
+ switch (status) {
1008
+ case "pending":
1009
+ return colors.secondary;
1010
+ case "in-progress":
1011
+ return colors.info;
1012
+ case "done":
1013
+ return colors.success;
1014
+ case "blocked":
1015
+ return colors.error;
1016
+ default:
1017
+ return colors.normal;
1018
+ }
1019
+ }
1020
+ function getTypeColor(type) {
1021
+ switch (type) {
1022
+ case "feat":
1023
+ return colors.success;
1024
+ case "fix":
1025
+ return colors.error;
1026
+ case "refactor":
1027
+ return colors.warning;
1028
+ case "docs":
1029
+ return colors.info;
1030
+ case "test":
1031
+ return colors.secondary;
1032
+ case "chore":
1033
+ return colors.normal;
1034
+ default:
1035
+ return colors.normal;
1036
+ }
1037
+ }
1038
+
1039
+ // src/commands/pause.ts
1040
+ init_esm_shims();
1041
+ import path5 from "path";
1042
+ var pauseCommand = defineCommand({
1043
+ name: "pause <task-id>",
1044
+ description: "\u23F8\uFE0F Pause work on a task",
1045
+ alias: "stop",
1046
+ options: [
1047
+ {
1048
+ flags: "-m, --message <message>",
1049
+ description: "Custom commit message"
1050
+ },
1051
+ {
1052
+ flags: "-s, --skip-commit",
1053
+ description: "Skip commit (just show what would be done)"
1054
+ }
1055
+ ],
1056
+ handler: async (taskId, options) => {
1057
+ await pauseTask(taskId, options);
1058
+ }
1059
+ });
1060
+ async function pauseTask(taskId, options) {
1061
+ printHeader(`Pausing Task ${taskId}`, "\u23F8\uFE0F");
1062
+ const normalizedId = taskId.replace(/^task-/, "").padStart(3, "0");
1063
+ const tasksDir = path5.join(process.cwd(), "TASKS");
1064
+ const taskProvider = new FileSystemTaskProvider(tasksDir);
1065
+ const task = await taskProvider.findTask(normalizedId);
1066
+ if (!task) {
1067
+ error(`Task ${normalizedId} not found in TASKS/ directory`);
1068
+ process.exit(1);
1069
+ }
1070
+ info(`Found task: ${task.title}`);
1071
+ info(`Current status: ${task.status}`);
1072
+ if (task.status !== "in-progress") {
1073
+ error('Task is not in progress. Use "taskin start" first.');
1074
+ process.exit(1);
1075
+ }
1076
+ const commitMessage = options.message || `WIP: task-${normalizedId} - ${task.title}`;
1077
+ if (options.skipCommit) {
1078
+ info("Would create commit with message:");
1079
+ console.log(colors.highlight(` "${commitMessage}"`));
1080
+ console.log();
1081
+ info("Use without --skip-commit to actually commit");
1082
+ } else {
1083
+ info("Creating commit...");
1084
+ console.log(colors.secondary(` Message: "${commitMessage}"`));
1085
+ console.log();
1086
+ success("Task paused successfully!");
1087
+ info("Commit created (not pushed)");
1088
+ console.log();
1089
+ info("Next steps:");
1090
+ console.log(colors.secondary(" 1. Switch to another task"));
1091
+ console.log(
1092
+ colors.secondary(" 2. Or continue later with the same branch")
1093
+ );
1094
+ }
1095
+ console.log();
1096
+ }
1097
+
1098
+ // src/commands/start.ts
1099
+ init_esm_shims();
1100
+ import path6 from "path";
1101
+ var startCommand = defineCommand({
1102
+ name: "start <task-id>",
1103
+ description: "\u{1F680} Start working on a task",
1104
+ alias: "begin",
1105
+ options: [
1106
+ {
1107
+ flags: "-f, --force",
1108
+ description: "Force start even with uncommitted changes"
1109
+ },
1110
+ {
1111
+ flags: "-b, --base <branch>",
1112
+ description: "Base branch to create from (default: current)"
1113
+ }
1114
+ ],
1115
+ handler: async (taskId, options) => {
1116
+ await startTask(taskId, options);
1117
+ }
1118
+ });
1119
+ async function startTask(taskId, _options) {
1120
+ printHeader(`Starting Task ${taskId}`, "\u{1F680}");
1121
+ const normalizedId = taskId.replace(/^task-/, "").padStart(3, "0");
1122
+ const tasksDir = path6.join(process.cwd(), "TASKS");
1123
+ const taskProvider = new FileSystemTaskProvider(tasksDir);
1124
+ const taskManager = new TaskManager(taskProvider);
1125
+ const task = await taskProvider.findTask(normalizedId);
1126
+ if (!task) {
1127
+ error(`Task ${normalizedId} not found in TASKS/ directory`);
1128
+ process.exit(1);
1129
+ }
1130
+ info(`Found task: ${task.title}`);
1131
+ info(`Current status: ${task.status}`);
1132
+ if (task.status === "in-progress") {
1133
+ error("Task is already in progress");
1134
+ process.exit(1);
1135
+ }
1136
+ if (task.status === "done") {
1137
+ error("Task is already done");
1138
+ process.exit(1);
1139
+ }
1140
+ info("Starting task...");
1141
+ const updatedTask = await taskManager.startTask(task.id);
1142
+ success(`Task ${updatedTask.id} started successfully!`);
1143
+ success(`Status changed to: ${updatedTask.status}`);
1144
+ console.log();
1145
+ info("Next steps:");
1146
+ console.log(
1147
+ colors.secondary(
1148
+ " 1. Create a branch: git checkout -b feat/task-" + normalizedId
1149
+ )
1150
+ );
1151
+ console.log(colors.secondary(" 2. Start coding! \u{1F4BB}"));
1152
+ console.log(colors.secondary(' 3. Use "taskin pause" to save progress'));
1153
+ console.log();
1154
+ }
1155
+
1156
+ // src/lib/help.ts
1157
+ init_esm_shims();
1158
+ function showCustomHelp() {
1159
+ printHeader("Taskin - Task Management System", icons.rocket);
1160
+ console.log(colors.info("\u{1F4CB} AVAILABLE COMMANDS"));
1161
+ console.log(colors.highlight("\u2550".repeat(60)));
1162
+ console.log();
1163
+ const commands = [
1164
+ {
1165
+ name: colors.highlight("taskin init"),
1166
+ alias: colors.secondary("Alias: setup"),
1167
+ description: "Initialize Taskin in your project",
1168
+ examples: ["taskin init", "taskin setup"],
1169
+ icon: "\u{1F3AF}"
1170
+ },
1171
+ {
1172
+ name: colors.highlight("taskin list") + colors.normal(" [filter]"),
1173
+ alias: colors.secondary("Alias: ls"),
1174
+ description: "List all tasks in the project",
1175
+ examples: [
1176
+ "taskin list",
1177
+ "taskin list pending",
1178
+ "taskin list --status in-progress",
1179
+ "taskin list --type feat"
1180
+ ],
1181
+ icon: "\u{1F4CA}"
1182
+ },
1183
+ {
1184
+ name: colors.highlight("taskin start") + colors.normal(" <task-id>"),
1185
+ alias: colors.secondary("Alias: begin"),
1186
+ description: "Start working on a task",
1187
+ examples: [
1188
+ "taskin start 001",
1189
+ "taskin start task-001",
1190
+ "taskin start 001 --force"
1191
+ ],
1192
+ icon: "\u{1F680}"
1193
+ },
1194
+ {
1195
+ name: colors.highlight("taskin pause") + colors.normal(" <task-id>"),
1196
+ alias: colors.secondary("Alias: stop"),
1197
+ description: "Pause a task (commit without push)",
1198
+ examples: ["taskin pause 001", 'taskin pause 001 -m "saving progress"'],
1199
+ icon: "\u23F8\uFE0F"
1200
+ },
1201
+ {
1202
+ name: colors.highlight("taskin finish") + colors.normal(" <task-id>"),
1203
+ alias: colors.secondary("Alias: done"),
1204
+ description: "Finish a task",
1205
+ examples: ["taskin finish 001", "taskin done task-001"],
1206
+ icon: "\u2705"
1207
+ },
1208
+ {
1209
+ name: colors.highlight("taskin lint") + colors.normal(" [options]"),
1210
+ alias: colors.secondary("Options: -p, --path <directory>"),
1211
+ description: "Validate task markdown files",
1212
+ examples: [
1213
+ "taskin lint",
1214
+ "taskin lint --path ./TASKS",
1215
+ "taskin lint -p /path/to/tasks"
1216
+ ],
1217
+ icon: "\u{1F50D}"
1218
+ }
1219
+ ];
1220
+ commands.forEach((cmd, index) => {
1221
+ console.log(colors.warning(`${cmd.icon} ${cmd.name}`));
1222
+ console.log(colors.normal(` ${cmd.alias}`));
1223
+ console.log(colors.info(` ${cmd.description}`));
1224
+ console.log();
1225
+ console.log(colors.normal(` ${colors.info("\u{1F4DD} Examples:")}`));
1226
+ cmd.examples.forEach((example) => {
1227
+ console.log(colors.secondary(` ${example}`));
1228
+ });
1229
+ if (index < commands.length - 1) {
1230
+ console.log();
1231
+ console.log(colors.normal(" " + colors.secondary("\u2500".repeat(50))));
1232
+ console.log();
1233
+ }
1234
+ });
1235
+ console.log();
1236
+ console.log(colors.highlight("\u2550".repeat(60)));
1237
+ console.log();
1238
+ console.log(colors.info("\u{1F4A1} QUICK TIPS"));
1239
+ console.log(
1240
+ colors.normal(
1241
+ `${colors.warning("\u2022")} Use short IDs: ${colors.highlight("001")}, ${colors.highlight("task-001")}`
1242
+ )
1243
+ );
1244
+ console.log(
1245
+ colors.normal(
1246
+ `${colors.warning("\u2022")} All commands support ${colors.highlight("--help")} for more options`
1247
+ )
1248
+ );
1249
+ console.log(
1250
+ colors.normal(
1251
+ `${colors.warning("\u2022")} Use aliases for faster commands: ${colors.highlight("ls")}, ${colors.highlight("begin")}, ${colors.highlight("stop")}, ${colors.highlight("done")}`
1252
+ )
1253
+ );
1254
+ console.log();
1255
+ console.log(colors.info("\u{1F527} FOR MORE HELP"));
1256
+ console.log(
1257
+ colors.secondary("taskin ") + colors.highlight("<command>") + colors.secondary(" --help")
1258
+ );
1259
+ console.log();
1260
+ return "";
1261
+ }
1262
+
1263
+ // src/main.ts
1264
+ init_esm_shims();
1265
+ import { join as join4 } from "path";
1266
+
1267
+ // src/taskin.ts
1268
+ init_esm_shims();
1269
+ var Taskin = class {
1270
+ constructor(taskProvider, taskManager, linter) {
1271
+ this.taskProvider = taskProvider;
1272
+ this.taskManager = taskManager;
1273
+ this.linter = linter;
1274
+ }
1275
+ async list(options) {
1276
+ const tasks = await this.taskProvider.getAllTasks();
1277
+ return tasks.map((taskFile) => {
1278
+ const task = {
1279
+ createdAt: taskFile.createdAt,
1280
+ id: taskFile.id,
1281
+ status: taskFile.status,
1282
+ title: taskFile.title,
1283
+ type: taskFile.type,
1284
+ assignee: taskFile.userId
1285
+ // Map userId to assignee
1286
+ };
1287
+ return task;
1288
+ }).filter((task) => {
1289
+ if (options?.status && task.status !== options.status) {
1290
+ return false;
1291
+ }
1292
+ if (options?.type && task.type !== options.type) {
1293
+ return false;
1294
+ }
1295
+ if (options?.assignee && task.assignee !== options.assignee) {
1296
+ return false;
1297
+ }
1298
+ return true;
1299
+ });
1300
+ }
1301
+ async start(taskId, options) {
1302
+ const task = await this.taskProvider.findTask(taskId);
1303
+ if (!task) {
1304
+ throw new Error(`Task not found: ${taskId}`);
1305
+ }
1306
+ await this.taskManager.startTask(taskId);
1307
+ if (options?.force) {
1308
+ }
1309
+ if (options?.base) {
1310
+ }
1311
+ }
1312
+ async pause(taskId, options) {
1313
+ const task = await this.taskProvider.findTask(taskId);
1314
+ if (!task) {
1315
+ throw new Error(`Task not found: ${taskId}`);
1316
+ }
1317
+ if (!options?.skipCommit) {
1318
+ task.status = "pending";
1319
+ await this.taskProvider.updateTask(task);
1320
+ }
1321
+ if (options?.message) {
1322
+ }
1323
+ }
1324
+ async finish(taskId, _options) {
1325
+ const task = await this.taskProvider.findTask(taskId);
1326
+ if (!task) {
1327
+ throw new Error(`Task not found: ${taskId}`);
1328
+ }
1329
+ await this.taskManager.finishTask(taskId);
1330
+ }
1331
+ async lint(options) {
1332
+ const lintPath = options?.path || "TASKS";
1333
+ const fileResult = await this.linter.lintDirectory(lintPath);
1334
+ return {
1335
+ errors: fileResult.errors.map((e) => ({
1336
+ taskId: e.file,
1337
+ message: e.message,
1338
+ severity: e.severity,
1339
+ line: e.line
1340
+ })),
1341
+ warnings: fileResult.warnings.map((e) => ({
1342
+ taskId: e.file,
1343
+ message: e.message,
1344
+ severity: e.severity,
1345
+ line: e.line
1346
+ })),
1347
+ tasksChecked: fileResult.filesChecked,
1348
+ valid: fileResult.valid
1349
+ };
1350
+ }
1351
+ };
1352
+
1353
+ // src/main.ts
1354
+ function createTaskin(tasksDir) {
1355
+ const resolvedTasksDir = tasksDir || join4(process.cwd(), "TASKS");
1356
+ const taskProvider = new FileSystemTaskProvider(resolvedTasksDir);
1357
+ const taskManager = new TaskManager(taskProvider);
1358
+ const linter = new FileSystemTaskLinter();
1359
+ return new Taskin(taskProvider, taskManager, linter);
1360
+ }
1361
+ function getTaskin() {
1362
+ return createTaskin();
1363
+ }
1364
+
1365
+ // src/index.ts
1366
+ var program = new Command();
1367
+ program.name("taskin").description("\u{1F680} Task Management System").version("0.1.0").configureHelp({
1368
+ formatHelp: () => showCustomHelp()
1369
+ });
23
1370
  initCommand(program);
24
1371
  listCommand(program);
25
1372
  startCommand(program);
26
1373
  pauseCommand(program);
27
1374
  finishCommand(program);
28
1375
  lintCommand(program);
29
- // Show custom help if no command provided
30
1376
  if (process.argv.length <= 2) {
31
1377
  showCustomHelp();
32
1378
  process.exit(0);
33
1379
  }
34
- // Parse arguments
35
1380
  program.parse();
36
- export { createTaskin, getTaskin } from './main.js';
37
- export { Taskin } from './taskin.js';
38
- //# sourceMappingURL=index.js.map
1381
+ export {
1382
+ Taskin,
1383
+ createTaskin,
1384
+ getTaskin
1385
+ };