@fukuchang/taskchute-cli 0.3.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.
Files changed (2) hide show
  1. package/dist/index.js +44 -10
  2. package/package.json +2 -2
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) {
@@ -2209,6 +2213,14 @@ function pickPropagationTargets(routine, tasks, today) {
2209
2213
  );
2210
2214
  }
2211
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
+
2212
2224
  // ../infra-supabase/src/audit-task-repository.ts
2213
2225
  var AuditingTaskRepository = class {
2214
2226
  // `erasableSyntaxOnly` 配下では parameter property が使えないので、明示的に
@@ -2460,12 +2472,16 @@ function contextsArchiveCommand() {
2460
2472
  });
2461
2473
  }
2462
2474
  function contextsCreateCommand() {
2463
- 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) => {
2464
2479
  const ctx = await createAppContext();
2465
2480
  const input2 = { name, status: "active" };
2466
2481
  if (opts.description !== void 0) input2.description = opts.description;
2467
2482
  if (opts.icon !== void 0) input2.icon = opts.icon;
2468
2483
  if (opts.color !== void 0) input2.color = opts.color;
2484
+ if (opts.notifyAtStart !== void 0) input2.notifyAtScheduledStart = opts.notifyAtStart;
2469
2485
  const context = await ctx.repos.context.create(input2);
2470
2486
  console.log(`\u2713 Created context: ${shortenId(context.id)} ${context.name}`);
2471
2487
  });
@@ -2488,7 +2504,8 @@ function formatContextRow(context) {
2488
2504
  name: context.name,
2489
2505
  status: context.status,
2490
2506
  icon: context.icon ?? "-",
2491
- color: context.color ?? "-"
2507
+ color: context.color ?? "-",
2508
+ notify_at_start: context.notifyAtScheduledStart ? "\u2713" : "-"
2492
2509
  };
2493
2510
  }
2494
2511
 
@@ -2506,7 +2523,10 @@ function contextsListCommand() {
2506
2523
  });
2507
2524
  }
2508
2525
  function contextsUpdateCommand() {
2509
- 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) => {
2510
2530
  const ctx = await createAppContext();
2511
2531
  const all = await ctx.repos.context.findAll();
2512
2532
  const id = resolveResourceIdByPrefix(all, prefix, "context");
@@ -2518,9 +2538,12 @@ function contextsUpdateCommand() {
2518
2538
  else if (opts.icon !== void 0) patch.icon = opts.icon;
2519
2539
  if (opts.clearColor) patch.color = void 0;
2520
2540
  else if (opts.color !== void 0) patch.color = opts.color;
2541
+ if (opts.notifyAtStart !== void 0) {
2542
+ patch.notifyAtScheduledStart = opts.notifyAtStart;
2543
+ }
2521
2544
  if (Object.keys(patch).length === 0) {
2522
2545
  throw new CliError(
2523
- "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-*."
2524
2547
  );
2525
2548
  }
2526
2549
  const updated = await ctx.repos.context.update(id, patch);
@@ -2951,9 +2974,11 @@ function routinesUpdateCommand() {
2951
2974
  );
2952
2975
  }
2953
2976
  const taskPatch = buildRoutineTaskPatch(updated);
2977
+ const routineContext = updated.contextId ? await ctx.repos.context.findById(updated.contextId) : null;
2978
+ const propagatedPatch = applyContextNotificationInheritance(taskPatch, routineContext);
2954
2979
  await Promise.all(
2955
2980
  targets.map(
2956
- (task) => auditingTask.updateWithCause(task.id, taskPatch, "routine-propagation")
2981
+ (task) => auditingTask.updateWithCause(task.id, propagatedPatch, "routine-propagation")
2957
2982
  )
2958
2983
  );
2959
2984
  propagated = targets.length;
@@ -3060,9 +3085,11 @@ function tasksAddCommand() {
3060
3085
  projectId = resolveResourceIdByPrefix(all, opts.project, "project");
3061
3086
  }
3062
3087
  let contextId;
3088
+ let context = null;
3063
3089
  if (opts.context !== void 0) {
3064
3090
  const all = await ctx.repos.context.findAll();
3065
3091
  contextId = resolveResourceIdByPrefix(all, opts.context, "context");
3092
+ context = all.find((c) => c.id === contextId) ?? null;
3066
3093
  }
3067
3094
  const tagIds = [];
3068
3095
  if (opts.tag !== void 0 && opts.tag.length > 0) {
@@ -3076,7 +3103,7 @@ function tasksAddCommand() {
3076
3103
  }
3077
3104
  const existing = await ctx.repos.task.findByDate(date);
3078
3105
  const orderIndex = computeNextOrderIndex(existing);
3079
- const task = await ctx.repos.task.create({
3106
+ const createInput = {
3080
3107
  date,
3081
3108
  title,
3082
3109
  description: opts.description,
@@ -3090,7 +3117,10 @@ function tasksAddCommand() {
3090
3117
  scheduledStartTime: opts.scheduled,
3091
3118
  notifyAtScheduledStart: opts.notify,
3092
3119
  isBackground: opts.background
3093
- });
3120
+ };
3121
+ const task = await ctx.repos.task.create(
3122
+ applyContextNotificationInheritance(createInput, context)
3123
+ );
3094
3124
  console.log(`\u2713 Created: ${shortenId(task.id)} ${task.title}`);
3095
3125
  });
3096
3126
  }
@@ -3437,6 +3467,10 @@ function tasksUpdateCommand() {
3437
3467
  const tasks = await ctx.repos.task.findByDate(date);
3438
3468
  const taskId = resolveTaskIdByPrefix(tasks, prefix);
3439
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
+ }
3440
3474
  const updated = await ctx.repos.task.update(taskId, patch);
3441
3475
  console.log(`\u270E Updated: ${shortenId(updated.id)} ${updated.title}`);
3442
3476
  });
@@ -3690,7 +3724,7 @@ function whoamiCommand() {
3690
3724
 
3691
3725
  // src/index.ts
3692
3726
  var program = new Command();
3693
- 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.3.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" );
3694
3728
  program.addCommand(loginCommand());
3695
3729
  program.addCommand(whoamiCommand());
3696
3730
  program.addCommand(logoutCommand());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fukuchang/taskchute-cli",
3
- "version": "0.3.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": {