@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 +18 -0
- package/dist/index.js +68 -27
- package/package.json +2 -2
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
|
-
|
|
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 =
|
|
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:
|
|
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 ?
|
|
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").
|
|
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").
|
|
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,
|
|
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
|
|
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
|
|
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 && !
|
|
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 && !
|
|
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
|
|
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 (!
|
|
3500
|
+
if (!HHMM4.test(opts.startTime)) {
|
|
3460
3501
|
throw new CliError(`--start-time must be HH:MM (got "${opts.startTime}").`);
|
|
3461
3502
|
}
|
|
3462
|
-
if (!
|
|
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
|
|
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 && !
|
|
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 && !
|
|
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.
|
|
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.
|
|
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": {
|