@fukuchang/taskchute-cli 0.2.0 → 0.4.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/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  このパッケージの変更履歴。[Keep a Changelog](https://keepachangelog.com/) 準拠。
4
4
 
5
+ ## [0.3.0] - 2026-05-28 — 実績時刻の秒精度サポート
6
+
7
+ ### Added
8
+
9
+ - `taskchute tasks set-actual-times` の `--start` / `--end` が `HH:MM` に加え
10
+ `HH:MM:SS` も受け入れるようになった。秒は任意で、省略時は従来通り 0 として
11
+ 扱う。Web UI でも実績時刻の入力 / 表示が秒精度で行えるようになり、Play ボタン
12
+ を押した時刻も秒単位で `actual_start_time` に記録される。
13
+
14
+ ### Notes
15
+
16
+ - 後方互換あり: 既存の `HH:MM` 入力 / 保存データはそのまま動く。Supabase の
17
+ 時刻カラムは TEXT のためマイグレーション不要
18
+ - `start_task` / `start` 系で記録される `actual_start_time` は今後 `HH:MM:SS`
19
+ 形式で返ることがある (従来は `HH:MM`)。文字列としての扱いは変わらないが、
20
+ 下流ツールが正規表現で `HH:MM` のみを期待していた場合は `HH:MM(:SS)?` に
21
+ ゆるめる必要がある
22
+
5
23
  ## [0.2.0] - 2026-05-28 — Web パリティ完全達成 ✨
6
24
 
7
25
  5 PR (PR1〜5) で MCP/CLI を Web 機能パリティまで拡張し、PR6 で SOLID 観点の
package/dist/index.js CHANGED
@@ -217,14 +217,14 @@ async function deriveKEK(password4, salt, params = DEFAULT_ARGON2ID_PARAMS) {
217
217
  }
218
218
 
219
219
  // ../crypto/src/wrap.ts
220
- async function unwrapMasterKey(wrapped, iv, kek) {
220
+ async function unwrapMasterKey(wrapped, iv, kek, options = {}) {
221
221
  return crypto.subtle.unwrapKey(
222
222
  "raw",
223
223
  wrapped,
224
224
  kek,
225
225
  { name: "AES-GCM", iv },
226
226
  { name: "AES-GCM", length: 256 },
227
- false,
227
+ options.extractable ?? false,
228
228
  ["encrypt", "decrypt"]
229
229
  );
230
230
  }
@@ -510,6 +510,7 @@ async function rowToContext(row, cryptoSession) {
510
510
  id: row.id,
511
511
  name,
512
512
  status: row.status,
513
+ notifyAtScheduledStart: row.notify_at_scheduled_start,
513
514
  createdAt: new Date(row.created_at),
514
515
  updatedAt: new Date(row.updated_at)
515
516
  };
@@ -523,6 +524,9 @@ function nonEncryptedFieldsToRow(input2) {
523
524
  if ("icon" in input2) row.icon = input2.icon ?? null;
524
525
  if ("color" in input2) row.color = input2.color ?? null;
525
526
  if ("status" in input2 && input2.status !== void 0) row.status = input2.status;
527
+ if ("notifyAtScheduledStart" in input2 && input2.notifyAtScheduledStart !== void 0) {
528
+ row.notify_at_scheduled_start = input2.notifyAtScheduledStart;
529
+ }
526
530
  return row;
527
531
  }
528
532
  async function encryptContextFieldsInto(row, entityId, patch, cryptoSession) {
@@ -1612,6 +1616,12 @@ function toTimeString(date) {
1612
1616
  const minutes = String(date.getMinutes()).padStart(2, "0");
1613
1617
  return `${hours}:${minutes}`;
1614
1618
  }
1619
+ function toTimeStringWithSeconds(date) {
1620
+ const hours = String(date.getHours()).padStart(2, "0");
1621
+ const minutes = String(date.getMinutes()).padStart(2, "0");
1622
+ const seconds = String(date.getSeconds()).padStart(2, "0");
1623
+ return `${hours}:${minutes}:${seconds}`;
1624
+ }
1615
1625
 
1616
1626
  // ../domain/src/task-utils.ts
1617
1627
  function sessionDurationSeconds(session) {
@@ -1629,14 +1639,15 @@ function calculateActualSeconds(task, now = /* @__PURE__ */ new Date()) {
1629
1639
  }
1630
1640
 
1631
1641
  // ../domain/src/task-operations.ts
1632
- var TIME_RE = /^([01]\d|2[0-3]):([0-5]\d)$/;
1642
+ var TIME_RE = /^([01]\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?$/;
1633
1643
  function parseTimeOnDate(dateString, timeString) {
1634
1644
  const m = TIME_RE.exec(timeString);
1635
1645
  if (!m || !m[1] || !m[2]) {
1636
1646
  throw new Error(`Invalid time string: ${timeString}`);
1637
1647
  }
1638
1648
  const base = fromDateString(dateString);
1639
- base.setHours(Number(m[1]), Number(m[2]), 0, 0);
1649
+ const seconds = m[3] ? Number(m[3]) : 0;
1650
+ base.setHours(Number(m[1]), Number(m[2]), seconds, 0);
1640
1651
  return base;
1641
1652
  }
1642
1653
  async function startTask(repo, taskId) {
@@ -1649,7 +1660,7 @@ async function startTask(repo, taskId) {
1649
1660
  currentSession: { startedAt: now }
1650
1661
  };
1651
1662
  if (!task.actualStartTime) {
1652
- patch.actualStartTime = toTimeString(now);
1663
+ patch.actualStartTime = toTimeStringWithSeconds(now);
1653
1664
  }
1654
1665
  return repo.update(taskId, patch);
1655
1666
  }
@@ -1736,7 +1747,7 @@ async function interruptTask(repo, params) {
1736
1747
  currentSession: { startedAt: interruptionStartedAt },
1737
1748
  status: "running",
1738
1749
  orderIndex: target.orderIndex + 1,
1739
- actualStartTime: toTimeString(interruptionStartedAt),
1750
+ actualStartTime: toTimeStringWithSeconds(interruptionStartedAt),
1740
1751
  projectId: params.interruption.projectId,
1741
1752
  contextId: params.interruption.contextId,
1742
1753
  tagIds: params.interruption.tagIds ?? []
@@ -1777,7 +1788,7 @@ async function addParallelTask(repo, input2) {
1777
1788
  currentSession: startedAt ? { startedAt } : void 0,
1778
1789
  status: startImmediately ? "running" : "planned",
1779
1790
  orderIndex: maxOrder + 10,
1780
- actualStartTime: startedAt ? toTimeString(startedAt) : void 0,
1791
+ actualStartTime: startedAt ? toTimeStringWithSeconds(startedAt) : void 0,
1781
1792
  projectId: input2.projectId,
1782
1793
  contextId: input2.contextId,
1783
1794
  tagIds: input2.tagIds ?? [],
@@ -2202,6 +2213,14 @@ function pickPropagationTargets(routine, tasks, today) {
2202
2213
  );
2203
2214
  }
2204
2215
 
2216
+ // ../domain/src/context-task-inheritance.ts
2217
+ function applyContextNotificationInheritance(input2, context) {
2218
+ if (context?.notifyAtScheduledStart !== true) return input2;
2219
+ const current = input2.notifyAtScheduledStart;
2220
+ if (current !== void 0) return input2;
2221
+ return { ...input2, notifyAtScheduledStart: true };
2222
+ }
2223
+
2205
2224
  // ../infra-supabase/src/audit-task-repository.ts
2206
2225
  var AuditingTaskRepository = class {
2207
2226
  // `erasableSyntaxOnly` 配下では parameter property が使えないので、明示的に
@@ -2453,12 +2472,16 @@ function contextsArchiveCommand() {
2453
2472
  });
2454
2473
  }
2455
2474
  function contextsCreateCommand() {
2456
- return new Command("create").description("\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u65B0\u898F\u4F5C\u6210\u3059\u308B").argument("<name>", "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u540D").option("--description <text>", "\u8A73\u7D30\u8AAC\u660E").option("--icon <icon>", "\u7D75\u6587\u5B57\u307E\u305F\u306F\u30A2\u30A4\u30B3\u30F3\u540D (\u4F8B: \u{1F3E0})").option("--color <color>", "UI \u8272").action(async (name, opts) => {
2475
+ return new Command("create").description("\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u65B0\u898F\u4F5C\u6210\u3059\u308B").argument("<name>", "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u540D").option("--description <text>", "\u8A73\u7D30\u8AAC\u660E").option("--icon <icon>", "\u7D75\u6587\u5B57\u307E\u305F\u306F\u30A2\u30A4\u30B3\u30F3\u540D (\u4F8B: \u{1F3E0})").option("--color <color>", "UI \u8272").option(
2476
+ "--notify-at-start",
2477
+ "\u3053\u306E\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u4ED8\u3051\u308B\u65B0\u898F/\u66F4\u65B0\u30BF\u30B9\u30AF\u306E\u901A\u77E5\u3092 ON \u306B\u81EA\u52D5\u7D99\u627F\u3059\u308B"
2478
+ ).action(async (name, opts) => {
2457
2479
  const ctx = await createAppContext();
2458
2480
  const input2 = { name, status: "active" };
2459
2481
  if (opts.description !== void 0) input2.description = opts.description;
2460
2482
  if (opts.icon !== void 0) input2.icon = opts.icon;
2461
2483
  if (opts.color !== void 0) input2.color = opts.color;
2484
+ if (opts.notifyAtStart !== void 0) input2.notifyAtScheduledStart = opts.notifyAtStart;
2462
2485
  const context = await ctx.repos.context.create(input2);
2463
2486
  console.log(`\u2713 Created context: ${shortenId(context.id)} ${context.name}`);
2464
2487
  });
@@ -2481,7 +2504,8 @@ function formatContextRow(context) {
2481
2504
  name: context.name,
2482
2505
  status: context.status,
2483
2506
  icon: context.icon ?? "-",
2484
- color: context.color ?? "-"
2507
+ color: context.color ?? "-",
2508
+ notify_at_start: context.notifyAtScheduledStart ? "\u2713" : "-"
2485
2509
  };
2486
2510
  }
2487
2511
 
@@ -2499,7 +2523,10 @@ function contextsListCommand() {
2499
2523
  });
2500
2524
  }
2501
2525
  function contextsUpdateCommand() {
2502
- return new Command("update").description("\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u90E8\u5206\u66F4\u65B0\u3059\u308B").argument("<id-prefix>", "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8 id \u306E\u5148\u982D 4 \u6587\u5B57\u4EE5\u4E0A").option("--name <text>", "\u540D\u524D\u5909\u66F4").option("--description <text>", "\u8A73\u7D30\u8AAC\u660E").option("--clear-description", "\u8A73\u7D30\u8AAC\u660E\u3092\u7A7A\u306B\u3059\u308B").option("--icon <icon>", "\u7D75\u6587\u5B57\u307E\u305F\u306F\u30A2\u30A4\u30B3\u30F3\u540D").option("--clear-icon", "\u30A2\u30A4\u30B3\u30F3\u3092\u5916\u3059").option("--color <color>", "UI \u8272").option("--clear-color", "\u8272\u3092\u5916\u3059").action(async (prefix, opts) => {
2526
+ return new Command("update").description("\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u90E8\u5206\u66F4\u65B0\u3059\u308B").argument("<id-prefix>", "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8 id \u306E\u5148\u982D 4 \u6587\u5B57\u4EE5\u4E0A").option("--name <text>", "\u540D\u524D\u5909\u66F4").option("--description <text>", "\u8A73\u7D30\u8AAC\u660E").option("--clear-description", "\u8A73\u7D30\u8AAC\u660E\u3092\u7A7A\u306B\u3059\u308B").option("--icon <icon>", "\u7D75\u6587\u5B57\u307E\u305F\u306F\u30A2\u30A4\u30B3\u30F3\u540D").option("--clear-icon", "\u30A2\u30A4\u30B3\u30F3\u3092\u5916\u3059").option("--color <color>", "UI \u8272").option("--clear-color", "\u8272\u3092\u5916\u3059").option(
2527
+ "--notify-at-start",
2528
+ "\u3053\u306E\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u3092\u4ED8\u3051\u308B\u65B0\u898F/\u66F4\u65B0\u30BF\u30B9\u30AF\u306E\u901A\u77E5\u3092 ON \u7D99\u627F\u3059\u308B"
2529
+ ).option("--no-notify-at-start", "\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8\u306E\u901A\u77E5\u7D99\u627F\u3092 OFF \u306B\u3059\u308B").action(async (prefix, opts) => {
2503
2530
  const ctx = await createAppContext();
2504
2531
  const all = await ctx.repos.context.findAll();
2505
2532
  const id = resolveResourceIdByPrefix(all, prefix, "context");
@@ -2511,9 +2538,12 @@ function contextsUpdateCommand() {
2511
2538
  else if (opts.icon !== void 0) patch.icon = opts.icon;
2512
2539
  if (opts.clearColor) patch.color = void 0;
2513
2540
  else if (opts.color !== void 0) patch.color = opts.color;
2541
+ if (opts.notifyAtStart !== void 0) {
2542
+ patch.notifyAtScheduledStart = opts.notifyAtStart;
2543
+ }
2514
2544
  if (Object.keys(patch).length === 0) {
2515
2545
  throw new CliError(
2516
- "No field to update. Specify at least one of --name / --description / --icon / --color / --clear-*."
2546
+ "No field to update. Specify at least one of --name / --description / --icon / --color / --notify-at-start / --clear-*."
2517
2547
  );
2518
2548
  }
2519
2549
  const updated = await ctx.repos.context.update(id, patch);
@@ -2944,9 +2974,11 @@ function routinesUpdateCommand() {
2944
2974
  );
2945
2975
  }
2946
2976
  const taskPatch = buildRoutineTaskPatch(updated);
2977
+ const routineContext = updated.contextId ? await ctx.repos.context.findById(updated.contextId) : null;
2978
+ const propagatedPatch = applyContextNotificationInheritance(taskPatch, routineContext);
2947
2979
  await Promise.all(
2948
2980
  targets.map(
2949
- (task) => auditingTask.updateWithCause(task.id, taskPatch, "routine-propagation")
2981
+ (task) => auditingTask.updateWithCause(task.id, propagatedPatch, "routine-propagation")
2950
2982
  )
2951
2983
  );
2952
2984
  propagated = targets.length;
@@ -3053,9 +3085,11 @@ function tasksAddCommand() {
3053
3085
  projectId = resolveResourceIdByPrefix(all, opts.project, "project");
3054
3086
  }
3055
3087
  let contextId;
3088
+ let context = null;
3056
3089
  if (opts.context !== void 0) {
3057
3090
  const all = await ctx.repos.context.findAll();
3058
3091
  contextId = resolveResourceIdByPrefix(all, opts.context, "context");
3092
+ context = all.find((c) => c.id === contextId) ?? null;
3059
3093
  }
3060
3094
  const tagIds = [];
3061
3095
  if (opts.tag !== void 0 && opts.tag.length > 0) {
@@ -3069,7 +3103,7 @@ function tasksAddCommand() {
3069
3103
  }
3070
3104
  const existing = await ctx.repos.task.findByDate(date);
3071
3105
  const orderIndex = computeNextOrderIndex(existing);
3072
- const task = await ctx.repos.task.create({
3106
+ const createInput = {
3073
3107
  date,
3074
3108
  title,
3075
3109
  description: opts.description,
@@ -3083,7 +3117,10 @@ function tasksAddCommand() {
3083
3117
  scheduledStartTime: opts.scheduled,
3084
3118
  notifyAtScheduledStart: opts.notify,
3085
3119
  isBackground: opts.background
3086
- });
3120
+ };
3121
+ const task = await ctx.repos.task.create(
3122
+ applyContextNotificationInheritance(createInput, context)
3123
+ );
3087
3124
  console.log(`\u2713 Created: ${shortenId(task.id)} ${task.title}`);
3088
3125
  });
3089
3126
  }
@@ -3304,19 +3341,19 @@ function tasksReorderCommand() {
3304
3341
  console.log(`\u2195 Reordered: ${shortenId(updated.id)} ${updated.title} (order_index=${updated.orderIndex})`);
3305
3342
  });
3306
3343
  }
3307
- var HHMM4 = /^([01]\d|2[0-3]):[0-5]\d$/;
3344
+ var HHMMSS = /^([01]\d|2[0-3]):[0-5]\d(?::[0-5]\d)?$/;
3308
3345
  function tasksSetActualTimesCommand() {
3309
- return new Command("set-actual-times").description("\u5B9F\u7E3E\u958B\u59CB/\u7D42\u4E86\u6642\u523B\u3092\u76F4\u63A5\u6307\u5B9A\u3059\u308B (Play \u62BC\u3057\u5FD8\u308C\u30EA\u30AB\u30D0\u30EA\u7528)").argument("<id-prefix>", "\u30BF\u30B9\u30AF id \u306E\u5148\u982D 4 \u6587\u5B57\u4EE5\u4E0A").option("-d, --date <date>", "\u5BFE\u8C61\u65E5 (\u30C7\u30D5\u30A9\u30EB\u30C8: \u4ECA\u65E5)").option("--start <HH:MM>", "\u5B9F\u7E3E\u958B\u59CB\u6642\u523B").option("--end <HH:MM>", "\u5B9F\u7E3E\u7D42\u4E86\u6642\u523B").option("--clear-start", "\u958B\u59CB\u6642\u523B\u3092\u30AF\u30EA\u30A2 (end \u3082\u81EA\u52D5\u30AF\u30EA\u30A2)").option("--clear-end", "\u7D42\u4E86\u6642\u523B\u306E\u307F\u30AF\u30EA\u30A2 (status \u306F running \u306B)").option("--reset", "\u5B9F\u7E3E\u3092\u5168\u30AF\u30EA\u30A2 (status \u2192 planned)").action(async (prefix, opts) => {
3346
+ return new Command("set-actual-times").description("\u5B9F\u7E3E\u958B\u59CB/\u7D42\u4E86\u6642\u523B\u3092\u76F4\u63A5\u6307\u5B9A\u3059\u308B (Play \u62BC\u3057\u5FD8\u308C\u30EA\u30AB\u30D0\u30EA\u7528)").argument("<id-prefix>", "\u30BF\u30B9\u30AF id \u306E\u5148\u982D 4 \u6587\u5B57\u4EE5\u4E0A").option("-d, --date <date>", "\u5BFE\u8C61\u65E5 (\u30C7\u30D5\u30A9\u30EB\u30C8: \u4ECA\u65E5)").option("--start <HH:MM[:SS]>", "\u5B9F\u7E3E\u958B\u59CB\u6642\u523B (\u79D2\u306F\u4EFB\u610F)").option("--end <HH:MM[:SS]>", "\u5B9F\u7E3E\u7D42\u4E86\u6642\u523B (\u79D2\u306F\u4EFB\u610F)").option("--clear-start", "\u958B\u59CB\u6642\u523B\u3092\u30AF\u30EA\u30A2 (end \u3082\u81EA\u52D5\u30AF\u30EA\u30A2)").option("--clear-end", "\u7D42\u4E86\u6642\u523B\u306E\u307F\u30AF\u30EA\u30A2 (status \u306F running \u306B)").option("--reset", "\u5B9F\u7E3E\u3092\u5168\u30AF\u30EA\u30A2 (status \u2192 planned)").action(async (prefix, opts) => {
3310
3347
  const ctx = await createAppContext();
3311
3348
  const date = opts.date ?? todayDateString();
3312
3349
  const tasks = await ctx.repos.task.findByDate(date);
3313
3350
  const taskId = resolveTaskIdByPrefix(tasks, prefix);
3314
3351
  const task = tasks.find((t) => t.id === taskId);
3315
- if (opts.start !== void 0 && !HHMM4.test(opts.start)) {
3316
- throw new CliError(`--start must be HH:MM (got "${opts.start}").`);
3352
+ if (opts.start !== void 0 && !HHMMSS.test(opts.start)) {
3353
+ throw new CliError(`--start must be HH:MM or HH:MM:SS (got "${opts.start}").`);
3317
3354
  }
3318
- if (opts.end !== void 0 && !HHMM4.test(opts.end)) {
3319
- throw new CliError(`--end must be HH:MM (got "${opts.end}").`);
3355
+ if (opts.end !== void 0 && !HHMMSS.test(opts.end)) {
3356
+ throw new CliError(`--end must be HH:MM or HH:MM:SS (got "${opts.end}").`);
3320
3357
  }
3321
3358
  let startTime;
3322
3359
  let endTime;
@@ -3430,6 +3467,10 @@ function tasksUpdateCommand() {
3430
3467
  const tasks = await ctx.repos.task.findByDate(date);
3431
3468
  const taskId = resolveTaskIdByPrefix(tasks, prefix);
3432
3469
  const patch = await buildPatch(ctx, opts);
3470
+ if (patch.contextId) {
3471
+ const newContext = await ctx.repos.context.findById(patch.contextId);
3472
+ Object.assign(patch, applyContextNotificationInheritance(patch, newContext));
3473
+ }
3433
3474
  const updated = await ctx.repos.task.update(taskId, patch);
3434
3475
  console.log(`\u270E Updated: ${shortenId(updated.id)} ${updated.title}`);
3435
3476
  });
@@ -3451,15 +3492,15 @@ function timeBlocksArchiveCommand() {
3451
3492
  console.log(`\u{1F4E6} Archived time-block: ${shortenId(archived.id)} ${archived.name}`);
3452
3493
  });
3453
3494
  }
3454
- var HHMM5 = /^([01]\d|2[0-3]):[0-5]\d$/;
3495
+ var HHMM4 = /^([01]\d|2[0-3]):[0-5]\d$/;
3455
3496
  var DATE_RE5 = /^\d{4}-\d{2}-\d{2}$/;
3456
3497
  function timeBlocksCreateCommand() {
3457
3498
  return new Command("create").description("\u30BF\u30A4\u30E0\u30D6\u30ED\u30C3\u30AF\u3092\u65B0\u898F\u4F5C\u6210\u3059\u308B").argument("<name>", "\u30BF\u30A4\u30E0\u30D6\u30ED\u30C3\u30AF\u540D (\u4F8B: morning / work / evening)").requiredOption("--start-time <HH:MM>", "\u958B\u59CB\u6642\u523B").requiredOption("--end-time <HH:MM>", "\u7D42\u4E86\u6642\u523B").requiredOption("--weekdays <csv>", "\u5BFE\u8C61\u66DC\u65E5 (0=\u65E5 \uFF5E 6=\u571F) \u306E\u30AB\u30F3\u30DE\u533A\u5207\u308A (\u4F8B: 1,2,3,4,5)").option("--project <id-prefix>", "\u30C7\u30D5\u30A9\u30EB\u30C8\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8 id (prefix)").option("--context <id-prefix>", "\u30C7\u30D5\u30A9\u30EB\u30C8\u30B3\u30F3\u30C6\u30AD\u30B9\u30C8 id (prefix)").option("--tag <id-prefix>", "\u30C7\u30D5\u30A9\u30EB\u30C8\u30BF\u30B0 id (prefix)\u3002\u8907\u6570\u6307\u5B9A\u53EF", collectTag7, []).option("--color <color>", "UI \u8272").option("--start-date <YYYY-MM-DD>", "\u6709\u52B9\u671F\u9593\u958B\u59CB\u65E5").option("--end-date <YYYY-MM-DD>", "\u6709\u52B9\u671F\u9593\u7D42\u4E86\u65E5").action(async (name, opts) => {
3458
3499
  const ctx = await createAppContext();
3459
- if (!HHMM5.test(opts.startTime)) {
3500
+ if (!HHMM4.test(opts.startTime)) {
3460
3501
  throw new CliError(`--start-time must be HH:MM (got "${opts.startTime}").`);
3461
3502
  }
3462
- if (!HHMM5.test(opts.endTime)) {
3503
+ if (!HHMM4.test(opts.endTime)) {
3463
3504
  throw new CliError(`--end-time must be HH:MM (got "${opts.endTime}").`);
3464
3505
  }
3465
3506
  const weekdays = parseWeekdaysList(opts.weekdays);
@@ -3554,7 +3595,7 @@ function timeBlocksListCommand() {
3554
3595
  console.table(blocks.map(formatTimeBlockRow));
3555
3596
  });
3556
3597
  }
3557
- var HHMM6 = /^([01]\d|2[0-3]):[0-5]\d$/;
3598
+ var HHMM5 = /^([01]\d|2[0-3]):[0-5]\d$/;
3558
3599
  var DATE_RE6 = /^\d{4}-\d{2}-\d{2}$/;
3559
3600
  var TIME_BLOCK_STATUSES = ["active", "archived"];
3560
3601
  function isTimeBlockStatus(value) {
@@ -3565,10 +3606,10 @@ function timeBlocksUpdateCommand() {
3565
3606
  const ctx = await createAppContext();
3566
3607
  const all = await ctx.repos.timeBlock.findAll();
3567
3608
  const id = resolveResourceIdByPrefix(all, prefix, "time-block");
3568
- if (opts.startTime !== void 0 && !HHMM6.test(opts.startTime)) {
3609
+ if (opts.startTime !== void 0 && !HHMM5.test(opts.startTime)) {
3569
3610
  throw new CliError(`--start-time must be HH:MM (got "${opts.startTime}").`);
3570
3611
  }
3571
- if (opts.endTime !== void 0 && !HHMM6.test(opts.endTime)) {
3612
+ if (opts.endTime !== void 0 && !HHMM5.test(opts.endTime)) {
3572
3613
  throw new CliError(`--end-time must be HH:MM (got "${opts.endTime}").`);
3573
3614
  }
3574
3615
  if (opts.startDate !== void 0 && !DATE_RE6.test(opts.startDate)) {
@@ -3683,7 +3724,7 @@ function whoamiCommand() {
3683
3724
 
3684
3725
  // src/index.ts
3685
3726
  var program = new Command();
3686
- program.name("taskchute").description("TaskChute CLI \u2014 CLI/MCP \u304B\u3089 TaskChute \u306B\u30A2\u30AF\u30BB\u30B9\u3059\u308B\u305F\u3081\u306E\u30A8\u30F3\u30C8\u30EA\u30DD\u30A4\u30F3\u30C8").version("0.2.0" );
3727
+ program.name("taskchute").description("TaskChute CLI \u2014 CLI/MCP \u304B\u3089 TaskChute \u306B\u30A2\u30AF\u30BB\u30B9\u3059\u308B\u305F\u3081\u306E\u30A8\u30F3\u30C8\u30EA\u30DD\u30A4\u30F3\u30C8").version("0.4.0" );
3687
3728
  program.addCommand(loginCommand());
3688
3729
  program.addCommand(whoamiCommand());
3689
3730
  program.addCommand(logoutCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fukuchang/taskchute-cli",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "TaskChute CLI — E2EE 暗号化された TaskChute タスクをターミナルから操作するための CLI",
5
5
  "license": "MIT",
6
6
  "author": "fukuchang",
@@ -50,9 +50,9 @@
50
50
  "tsup": "^8.5.1",
51
51
  "tsx": "^4.20.0",
52
52
  "typescript": "~6.0.2",
53
- "@taskchute/crypto": "0.0.0",
54
53
  "@taskchute/domain": "0.0.0",
55
54
  "@taskchute/infra-supabase": "0.0.0",
55
+ "@taskchute/crypto": "0.0.0",
56
56
  "@taskchute/node-shared": "0.0.0"
57
57
  },
58
58
  "scripts": {