@wspc/cli 0.1.4 → 0.1.5

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/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { Command as Command73 } from "commander";
4
+ import { Command as Command74 } from "commander";
5
5
  import { realpathSync } from "fs";
6
6
  import { fileURLToPath } from "url";
7
7
 
@@ -1178,6 +1178,11 @@ var todoCommentUpdate = (options) => (options.client ?? client).patch({
1178
1178
  ...options.headers
1179
1179
  }
1180
1180
  });
1181
+ var projectDelete = (options) => (options.client ?? client).delete({
1182
+ security: [{ scheme: "bearer", type: "http" }],
1183
+ url: "/todo/projects/{id}",
1184
+ ...options
1185
+ });
1181
1186
  var recurrenceRuleDelete = (options) => (options.client ?? client).delete({
1182
1187
  security: [{ scheme: "bearer", type: "http" }],
1183
1188
  url: "/todo/recurrence-rules/{id}",
@@ -1464,9 +1469,9 @@ function createConsistencyFetch(opts) {
1464
1469
  }
1465
1470
 
1466
1471
  // src/version.ts
1467
- var VERSION = "0.1.4";
1468
- var SPEC_SHA = "e0bbc1e3";
1469
- var SPEC_FETCHED_AT = "2026-06-22T06:55:37.490Z";
1472
+ var VERSION = "0.1.5";
1473
+ var SPEC_SHA = "706a2577";
1474
+ var SPEC_FETCHED_AT = "2026-06-22T07:51:02.058Z";
1470
1475
  var API_BASE = "https://api.wspc.ai";
1471
1476
 
1472
1477
  // src/index.ts
@@ -3586,9 +3591,30 @@ var todoCommentUpdateCommand = new Command56("edit").description("Edit a comment
3586
3591
  render({ kind: "todo_comment_update", display: { "shape": "object", "format": { "id": "id-short", "todo_id": "id-short", "user_id": "id-short", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
3587
3592
  });
3588
3593
 
3589
- // src/generated/cli/todo/rule/rm.ts
3594
+ // src/generated/cli/todo/project/rm.ts
3590
3595
  import { Command as Command57 } from "commander";
3591
- var recurrenceRuleDeleteCommand = new Command57("rm").description("Delete a recurring todo rule").argument("<id>", "id").option("--expected-version <value>", "expected_version").action(async (id, opts) => {
3596
+ var projectDeleteCommand = new Command57("rm").description("Soft-delete a project").argument("<id>", "id").action(async (id, opts) => {
3597
+ const client2 = await loadSdkClient();
3598
+ const result = await projectDelete({
3599
+ client: client2._rawClient,
3600
+ path: {
3601
+ id
3602
+ }
3603
+ });
3604
+ if (result.error || !result.response?.ok) {
3605
+ process.stderr.write(
3606
+ `HTTP ${result.response?.status ?? "?"}: ${JSON.stringify(result.error ?? "unknown error", null, 2)}
3607
+ `
3608
+ );
3609
+ process.exitCode = 1;
3610
+ return;
3611
+ }
3612
+ render({ kind: "project_delete", display: { "shape": "object", "format": { "id": "id-short", "org_id": "id-short", "creator_user_id": "id-short", "default_todo_type_id": "id-short", "name": "truncate", "created_at": "relative-time", "updated_at": "relative-time", "deleted_at": "relative-time" } } }, result.data);
3613
+ });
3614
+
3615
+ // src/generated/cli/todo/rule/rm.ts
3616
+ import { Command as Command58 } from "commander";
3617
+ var recurrenceRuleDeleteCommand = new Command58("rm").description("Delete a recurring todo rule").argument("<id>", "id").option("--expected-version <value>", "expected_version").action(async (id, opts) => {
3592
3618
  const client2 = await loadSdkClient();
3593
3619
  const result = await recurrenceRuleDelete({
3594
3620
  client: client2._rawClient,
@@ -3611,8 +3637,8 @@ var recurrenceRuleDeleteCommand = new Command57("rm").description("Delete a recu
3611
3637
  });
3612
3638
 
3613
3639
  // src/generated/cli/todo/rule/show.ts
3614
- import { Command as Command58 } from "commander";
3615
- var recurrenceRuleGetCommand = new Command58("show").description("Get a recurring todo rule").argument("<id>", "id").action(async (id, opts) => {
3640
+ import { Command as Command59 } from "commander";
3641
+ var recurrenceRuleGetCommand = new Command59("show").description("Get a recurring todo rule").argument("<id>", "id").action(async (id, opts) => {
3616
3642
  const client2 = await loadSdkClient();
3617
3643
  const result = await recurrenceRuleGet({
3618
3644
  client: client2._rawClient,
@@ -3632,8 +3658,8 @@ var recurrenceRuleGetCommand = new Command58("show").description("Get a recurrin
3632
3658
  });
3633
3659
 
3634
3660
  // src/generated/cli/todo/rm.ts
3635
- import { Command as Command59 } from "commander";
3636
- var todoDeleteCommand = new Command59("rm").description("Soft-delete a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--cascade <value>", "cascade").action(async (id, opts) => {
3661
+ import { Command as Command60 } from "commander";
3662
+ var todoDeleteCommand = new Command60("rm").description("Soft-delete a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--cascade <value>", "cascade").action(async (id, opts) => {
3637
3663
  const client2 = await loadSdkClient();
3638
3664
  const result = await todoDelete({
3639
3665
  client: client2._rawClient,
@@ -3657,8 +3683,8 @@ var todoDeleteCommand = new Command59("rm").description("Soft-delete a todo").ar
3657
3683
  });
3658
3684
 
3659
3685
  // src/generated/cli/todo/show.ts
3660
- import { Command as Command60 } from "commander";
3661
- var todoGetCommand = new Command60("show").description("Get a todo by id").argument("<id>", "id").option("--include-deleted <value>", "include_deleted").option("--include-orphan-fields <value>", "include_orphan_fields").action(async (id, opts) => {
3686
+ import { Command as Command61 } from "commander";
3687
+ var todoGetCommand = new Command61("show").description("Get a todo by id").argument("<id>", "id").option("--include-deleted <value>", "include_deleted").option("--include-orphan-fields <value>", "include_orphan_fields").action(async (id, opts) => {
3662
3688
  const client2 = await loadSdkClient();
3663
3689
  const result = await todoGet({
3664
3690
  client: client2._rawClient,
@@ -3683,8 +3709,8 @@ var todoGetCommand = new Command60("show").description("Get a todo by id").argum
3683
3709
  });
3684
3710
 
3685
3711
  // src/generated/cli/todo/update.ts
3686
- import { Command as Command61 } from "commander";
3687
- var todoUpdateCommand = new Command61("update").description("Update a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--title <value>", "New title. Omit to leave the existing title unchanged. Must be non-empty when supplied.").option("--description <value>", 'New description. Markdown formatted (CommonMark + GFM tables, strikethrough, task lists). Pass empty string `""` explicitly to clear an existing description, or omit to leave unchanged. Passing `null` is strictly rejected.').option("--parent-id <value>", "Re-parent the todo. Pass a valid parent ID to attach under another todo, pass `null` to move it back to the root level, or omit to leave unchanged. Nesting is limited to one level; attempting to set a child todo as a parent will trigger `PARENT_IS_CHILD`.").option("--status <value>", "New status of the todo. Allowed transitions: `open` \u2794 `in_progress` \u2794 `done`. `cancelled` represents a terminal state. Transitioning to `done` automatically emits a `captureTodoCompleted` analytics event. Omit to leave the existing status unchanged.").option("--due-at <value>", 'Update calendar due date in ISO date-only format (`YYYY-MM-DD`). Pass `""` explicitly to clear an existing due date, or omit to leave it unchanged. Passing `null` is strictly rejected.').option("--type-id <value>", "Re-assign this todo to a different active type. The new type must belong to the todo's same project; otherwise the request fails with TYPE_PROJECT_MISMATCH. New server-generated type ids use typ_<ULID>; legacy ids remain accepted.").option("--custom-fields <value>", "PATCH semantics: only the keys present in this map change. Pass `null` for a key (e.g. `custom_fields: { priority: null }`) to explicitly delete that custom field value. Array values are replaced wholesale with no element-level diff. Providing a key that is not declared on the effective todo type is rejected with `UNDECLARED_FIELD`.").option("--user-id <value>", "Reassign the owner (assignee) user ID of this todo. Target user must belong to the same organization.").action(async (id, opts) => {
3712
+ import { Command as Command62 } from "commander";
3713
+ var todoUpdateCommand = new Command62("update").description("Update a todo").argument("<id>", "id").option("--expected-version <value>", "expected_version").option("--title <value>", "New title. Omit to leave the existing title unchanged. Must be non-empty when supplied.").option("--description <value>", 'New description. Markdown formatted (CommonMark + GFM tables, strikethrough, task lists). Pass empty string `""` explicitly to clear an existing description, or omit to leave unchanged. Passing `null` is strictly rejected.').option("--parent-id <value>", "Re-parent the todo. Pass a valid parent ID to attach under another todo, pass `null` to move it back to the root level, or omit to leave unchanged. Nesting is limited to one level; attempting to set a child todo as a parent will trigger `PARENT_IS_CHILD`.").option("--status <value>", "New status of the todo. Allowed transitions: `open` \u2794 `in_progress` \u2794 `done`. `cancelled` represents a terminal state. Transitioning to `done` automatically emits a `captureTodoCompleted` analytics event. Omit to leave the existing status unchanged.").option("--due-at <value>", 'Update calendar due date in ISO date-only format (`YYYY-MM-DD`). Pass `""` explicitly to clear an existing due date, or omit to leave it unchanged. Passing `null` is strictly rejected.').option("--type-id <value>", "Re-assign this todo to a different active type. The new type must belong to the todo's same project; otherwise the request fails with TYPE_PROJECT_MISMATCH. New server-generated type ids use typ_<ULID>; legacy ids remain accepted.").option("--custom-fields <value>", "PATCH semantics: only the keys present in this map change. Pass `null` for a key (e.g. `custom_fields: { priority: null }`) to explicitly delete that custom field value. Array values are replaced wholesale with no element-level diff. Providing a key that is not declared on the effective todo type is rejected with `UNDECLARED_FIELD`.").option("--user-id <value>", "Reassign the owner (assignee) user ID of this todo. Target user must belong to the same organization.").action(async (id, opts) => {
3688
3714
  const client2 = await loadSdkClient();
3689
3715
  const result = await todoUpdate({
3690
3716
  client: client2._rawClient,
@@ -3785,6 +3811,7 @@ function registerGeneratedCommands(root) {
3785
3811
  const root_todo_project = root_todo.command("project").description("project commands");
3786
3812
  root_todo_project.addCommand(projectCreateCommand);
3787
3813
  root_todo_project.addCommand(projectListCommand);
3814
+ root_todo_project.addCommand(projectDeleteCommand);
3788
3815
  const root_todo_rule = root_todo.command("rule").description("rule commands");
3789
3816
  root_todo_rule.addCommand(recurrenceRuleCreateCommand);
3790
3817
  root_todo_rule.addCommand(recurrenceRuleListCommand);
@@ -3800,7 +3827,7 @@ function registerGeneratedCommands(root) {
3800
3827
  }
3801
3828
 
3802
3829
  // src/handwritten/commands/login.ts
3803
- import { Command as Command62 } from "commander";
3830
+ import { Command as Command63 } from "commander";
3804
3831
 
3805
3832
  // src/handwritten/auth/device-flow.ts
3806
3833
  var DEFAULT_SLEEP = (ms) => new Promise((r) => setTimeout(r, ms));
@@ -4042,7 +4069,7 @@ function resolveLoginTarget(opts, env) {
4042
4069
  function wantsJson(opts, env) {
4043
4070
  return opts.json === true || env.WSPC_OUTPUT === "json";
4044
4071
  }
4045
- var loginCommand = new Command62("login").description("Log in via OAuth device flow (default) or API key").option("--api-key <key>", "Log in with a wspc API key (escape hatch)").option("--api-base <url>", "Target API base URL (default: production)").option("--env <name>", "Config env name to store credentials under").option("--json", "Emit machine-readable events to stdout").action(async (opts) => {
4072
+ var loginCommand = new Command63("login").description("Log in via OAuth device flow (default) or API key").option("--api-key <key>", "Log in with a wspc API key (escape hatch)").option("--api-base <url>", "Target API base URL (default: production)").option("--env <name>", "Config env name to store credentials under").option("--json", "Emit machine-readable events to stdout").action(async (opts) => {
4046
4073
  const store = new ConfigStore();
4047
4074
  const { baseUrl, envName } = resolveLoginTarget(opts, process.env);
4048
4075
  const output = wantsJson(opts, process.env) ? { write: () => {
@@ -4061,7 +4088,7 @@ var loginCommand = new Command62("login").description("Log in via OAuth device f
4061
4088
  });
4062
4089
 
4063
4090
  // src/handwritten/commands/logout.ts
4064
- import { Command as Command63 } from "commander";
4091
+ import { Command as Command64 } from "commander";
4065
4092
 
4066
4093
  // src/handwritten/auth/logout.ts
4067
4094
  async function runLogout(opts) {
@@ -4094,7 +4121,7 @@ async function runLogout(opts) {
4094
4121
  }
4095
4122
 
4096
4123
  // src/handwritten/commands/logout.ts
4097
- var logoutCommand = new Command63("logout").description("Log out an account (default: the active account in the current env)").argument("[email]", "Email of the account to log out").option("--all", "Log out every account in the current env").action(async (email, opts) => {
4124
+ var logoutCommand = new Command64("logout").description("Log out an account (default: the active account in the current env)").argument("[email]", "Email of the account to log out").option("--all", "Log out every account in the current env").action(async (email, opts) => {
4098
4125
  const res = await runLogout({ store: new ConfigStore(), email, all: opts.all });
4099
4126
  if (res.removed.length === 0) {
4100
4127
  process.stdout.write("nothing to log out\n");
@@ -4107,7 +4134,7 @@ var logoutCommand = new Command63("logout").description("Log out an account (def
4107
4134
  });
4108
4135
 
4109
4136
  // src/handwritten/commands/whoami.ts
4110
- import { Command as Command64 } from "commander";
4137
+ import { Command as Command65 } from "commander";
4111
4138
  var ENV_DISPLAY = {
4112
4139
  shape: "object",
4113
4140
  fields: ["name", "api_base", "account", "actor", "agent_label"]
@@ -4138,7 +4165,7 @@ async function backfillActiveEmail(store, envName, email, userId) {
4138
4165
  rekeyLegacyAccount(cfg, envName, email, userId);
4139
4166
  });
4140
4167
  }
4141
- var whoamiCommand = new Command64("whoami").description("Show the active env, signed-in account, and organization").action(async () => {
4168
+ var whoamiCommand = new Command65("whoami").description("Show the active env, signed-in account, and organization").action(async () => {
4142
4169
  const store = new ConfigStore();
4143
4170
  const config = await store.read();
4144
4171
  let resolved;
@@ -4191,8 +4218,8 @@ function printLoggedOut() {
4191
4218
  }
4192
4219
 
4193
4220
  // src/handwritten/commands/config.ts
4194
- import { Command as Command65 } from "commander";
4195
- var configCommand = new Command65("config").description("Manage wspc local config");
4221
+ import { Command as Command66 } from "commander";
4222
+ var configCommand = new Command66("config").description("Manage wspc local config");
4196
4223
  registerRenderer("config_show", (data) => {
4197
4224
  const d = data;
4198
4225
  if (d.envs.length === 0) {
@@ -4263,7 +4290,7 @@ configCommand.command("use <env>").description("Switch current_env").action(asyn
4263
4290
  });
4264
4291
 
4265
4292
  // src/handwritten/commands/account.ts
4266
- import { Command as Command66 } from "commander";
4293
+ import { Command as Command67 } from "commander";
4267
4294
  async function listAccounts(store) {
4268
4295
  const c = await store.read();
4269
4296
  const envName = c.current_env;
@@ -4304,7 +4331,7 @@ registerRenderer("account_ls", (data) => {
4304
4331
  ]);
4305
4332
  process.stdout.write(table(headers, body));
4306
4333
  });
4307
- var accountCommand = new Command66("account").description("Manage logged-in accounts");
4334
+ var accountCommand = new Command67("account").description("Manage logged-in accounts");
4308
4335
  accountCommand.command("ls").description("List accounts in the current env (active marked with \u2713)").action(async () => {
4309
4336
  const accounts = await listAccounts(new ConfigStore());
4310
4337
  render({ kind: "account_ls" }, { accounts });
@@ -4316,7 +4343,7 @@ accountCommand.command("switch <email>").description("Set the active account for
4316
4343
  });
4317
4344
 
4318
4345
  // src/handwritten/commands/todo-done.ts
4319
- import { Command as Command67 } from "commander";
4346
+ import { Command as Command68 } from "commander";
4320
4347
  var TODO_UPDATE_DISPLAY = {
4321
4348
  shape: "object",
4322
4349
  format: {
@@ -4334,7 +4361,7 @@ var TODO_UPDATE_DISPLAY = {
4334
4361
  deleted_at: "relative-time"
4335
4362
  }
4336
4363
  };
4337
- var todoDoneCommand = new Command67("done").description("Mark a todo done (sugar for `update <id> --status done`)").argument("<id>", "Todo id").action(async (id) => {
4364
+ var todoDoneCommand = new Command68("done").description("Mark a todo done (sugar for `update <id> --status done`)").argument("<id>", "Todo id").action(async (id) => {
4338
4365
  const client2 = await loadSdkClient();
4339
4366
  const result = await todoUpdate({
4340
4367
  client: client2._rawClient,
@@ -4353,7 +4380,8 @@ var todoDoneCommand = new Command67("done").description("Mark a todo done (sugar
4353
4380
  });
4354
4381
 
4355
4382
  // src/handwritten/commands/email/send.ts
4356
- import { Command as Command68 } from "commander";
4383
+ import { Command as Command69 } from "commander";
4384
+ import { randomUUID } from "crypto";
4357
4385
  import { readFile, stat } from "fs/promises";
4358
4386
  import { basename } from "path";
4359
4387
 
@@ -4411,7 +4439,7 @@ async function resolveAttachment(input) {
4411
4439
  `--attach ${input}: neither a readable file nor a valid <prefix>_<ulid>:<idx> reference.`
4412
4440
  );
4413
4441
  }
4414
- var sendCommand = new Command68("send").description("Send an outbound email").requiredOption("--from <alias-email>", "alias email to send from").option("--to <addr...>", "recipient address (repeatable)", []).option("--subject <text>", "subject").option("--text <body>", "plain-text body").option("--text-file <path>", "read text body from file").option("--reply <id>", "inbound email id to reply to").option("--attach <path-or-ref...>", "attachment (file path or eml_xxx:idx)", []).requiredOption("--idempotency-key <key>", "idempotency key").action(async (opts) => {
4442
+ var sendCommand = new Command69("send").description("Send an outbound email").requiredOption("--from <alias-email>", "alias email to send from").option("--to <addr...>", "recipient address (repeatable)", []).option("--subject <text>", "subject").option("--text <body>", "plain-text body").option("--text-file <path>", "read text body from file").option("--reply <id>", "inbound email id to reply to").option("--attach <path-or-ref...>", "attachment (file path or eml_xxx:idx)", []).option("--idempotency-key <key>", "idempotency key (auto-generated if omitted)").action(async (opts) => {
4415
4443
  const isReply = Boolean(opts.reply);
4416
4444
  const to = opts.to;
4417
4445
  const attachInputs = opts.attach;
@@ -4469,7 +4497,9 @@ var sendCommand = new Command68("send").description("Send an outbound email").re
4469
4497
  const body = {
4470
4498
  from_alias_email: opts.from,
4471
4499
  text,
4472
- idempotency_key: opts.idempotencyKey
4500
+ // Server requires an idempotency_key; a fresh random one makes each send a
4501
+ // distinct request, which is the right default for one-shot CLI sends.
4502
+ idempotency_key: opts.idempotencyKey ?? randomUUID()
4473
4503
  };
4474
4504
  if (isReply) {
4475
4505
  body.in_reply_to_email_id = opts.reply;
@@ -4498,7 +4528,7 @@ var sendCommand = new Command68("send").description("Send an outbound email").re
4498
4528
  });
4499
4529
 
4500
4530
  // src/handwritten/commands/email/attachment.ts
4501
- import { Command as Command69 } from "commander";
4531
+ import { Command as Command70 } from "commander";
4502
4532
  import { createWriteStream } from "fs";
4503
4533
  import { Readable } from "stream";
4504
4534
  import { pipeline } from "stream/promises";
@@ -4516,7 +4546,7 @@ function parseContentDispositionFilename(header) {
4516
4546
  }
4517
4547
 
4518
4548
  // src/handwritten/commands/email/attachment.ts
4519
- var attachmentCommand = new Command69("attachment").description("Download an inbound email attachment by index").argument("<email-id>").argument("<idx>").option("--output <path>", "output file path").option("--include-deleted", "allow downloads from soft-deleted parent emails").action(async (emailId, idxArg, opts) => {
4549
+ var attachmentCommand = new Command70("attachment").description("Download an inbound email attachment by index").argument("<email-id>").argument("<idx>").option("--output <path>", "output file path").option("--include-deleted", "allow downloads from soft-deleted parent emails").action(async (emailId, idxArg, opts) => {
4520
4550
  const idx = Number(idxArg);
4521
4551
  if (!Number.isInteger(idx) || idx < 0) {
4522
4552
  process.stderr.write(`<idx> must be a non-negative integer (got "${idxArg}")
@@ -4548,7 +4578,7 @@ var attachmentCommand = new Command69("attachment").description("Download an inb
4548
4578
  });
4549
4579
 
4550
4580
  // src/handwritten/commands/drive/bind.ts
4551
- import { Command as Command70 } from "commander";
4581
+ import { Command as Command71 } from "commander";
4552
4582
  import { stat as stat2 } from "fs/promises";
4553
4583
  import { resolve } from "path";
4554
4584
 
@@ -4638,7 +4668,7 @@ async function createDriveApi(opts = {}) {
4638
4668
 
4639
4669
  // src/handwritten/commands/drive/state.ts
4640
4670
  import { mkdir, open, readFile as readFile2, rename, rm, writeFile } from "fs/promises";
4641
- import { randomUUID } from "crypto";
4671
+ import { randomUUID as randomUUID2 } from "crypto";
4642
4672
  import { join as join2 } from "path";
4643
4673
  import { DateTime as DateTime4 } from "luxon";
4644
4674
 
@@ -4678,7 +4708,7 @@ async function readDriveState(root) {
4678
4708
  }
4679
4709
  async function writeDriveState(root, state, clock) {
4680
4710
  await mkdir(join2(root, DRIVE_DIR), { recursive: true });
4681
- const tmp = join2(root, DRIVE_DIR, `state.json.tmp-${process.pid}-${randomUUID()}`);
4711
+ const tmp = join2(root, DRIVE_DIR, `state.json.tmp-${process.pid}-${randomUUID2()}`);
4682
4712
  const snapshot = JSON.stringify(
4683
4713
  {
4684
4714
  ...state,
@@ -4734,7 +4764,7 @@ async function ensureDriveRealtimeState(root) {
4734
4764
  ...state,
4735
4765
  realtime: {
4736
4766
  ...state.realtime,
4737
- client_id: `drvcli_${randomUUID().replace(/-/g, "")}`
4767
+ client_id: `drvcli_${randomUUID2().replace(/-/g, "")}`
4738
4768
  }
4739
4769
  };
4740
4770
  await writeDriveState(root, next);
@@ -4811,7 +4841,7 @@ async function assertExistingDirectory(path) {
4811
4841
  }
4812
4842
  }
4813
4843
  function driveBindCommand() {
4814
- return new Command70("bind").description("Bind a local folder to an existing Drive library").requiredOption("--library <id>", "existing Drive library id").argument("[path]", "local folder path", ".").action(async (path, opts) => {
4844
+ return new Command71("bind").description("Bind a local folder to an existing Drive library").requiredOption("--library <id>", "existing Drive library id").argument("[path]", "local folder path", ".").action(async (path, opts) => {
4815
4845
  const root = resolve(path);
4816
4846
  await assertExistingDirectory(root);
4817
4847
  const api = await createDriveApi();
@@ -4829,10 +4859,10 @@ function driveBindCommand() {
4829
4859
  }
4830
4860
 
4831
4861
  // src/handwritten/commands/drive/sync.ts
4832
- import { Command as Command71 } from "commander";
4862
+ import { Command as Command72 } from "commander";
4833
4863
  import { mkdir as mkdir3, readFile as readFile4, rm as rm3, writeFile as writeFile3 } from "fs/promises";
4834
4864
  import { basename as basename3, dirname as dirname2, join as join5, posix as pathPosix2, resolve as resolve3 } from "path";
4835
- import { createHash as createHash3, randomUUID as randomUUID3 } from "crypto";
4865
+ import { createHash as createHash3, randomUUID as randomUUID4 } from "crypto";
4836
4866
 
4837
4867
  // src/handwritten/commands/drive/decision.ts
4838
4868
  function decideDriveAction(entry, local, remote) {
@@ -5213,7 +5243,7 @@ async function hashDriveFile(path) {
5213
5243
  import { createWriteStream as createWriteStream2 } from "fs";
5214
5244
  import { link, mkdir as mkdir2, readFile as readFile3, rename as rename2, rm as rm2, unlink, writeFile as writeFile2 } from "fs/promises";
5215
5245
  import { basename as basename2, dirname, join as join4 } from "path";
5216
- import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
5246
+ import { createHash as createHash2, randomUUID as randomUUID3 } from "crypto";
5217
5247
  import { Readable as Readable2, Transform } from "stream";
5218
5248
  import { pipeline as pipeline2 } from "stream/promises";
5219
5249
  async function assertLocalStillScanned(localPath, scanned) {
@@ -5228,7 +5258,7 @@ async function assertLocalStillScanned(localPath, scanned) {
5228
5258
  async function writeMergedLocalFile(root, path, bytes, digest, scanned, onLocalMutation) {
5229
5259
  const target = resolveInsideRoot(root, path);
5230
5260
  await mkdir2(dirname(target), { recursive: true });
5231
- const tmp = join4(dirname(target), `.${basename2(target)}.wspc-merge-${randomUUID2()}.tmp`);
5261
+ const tmp = join4(dirname(target), `.${basename2(target)}.wspc-merge-${randomUUID3()}.tmp`);
5232
5262
  try {
5233
5263
  await writeFile2(tmp, bytes, { flag: "wx" });
5234
5264
  return await installMergedLocalFile(root, path, tmp, scanned, digest, bytes.byteLength, onLocalMutation);
@@ -5280,7 +5310,7 @@ async function installMergedLocalFile(root, path, tmp, scanned, mergedSha256, me
5280
5310
  }
5281
5311
  }
5282
5312
  async function restoreMergedLocalFile(target, backup, backupSha256, backupSizeBytes, mergedSha256, mergedSizeBytes) {
5283
- const quarantine = join4(dirname(target), `.${basename2(target)}.wspc-merge-restore-${randomUUID2()}.tmp`);
5313
+ const quarantine = join4(dirname(target), `.${basename2(target)}.wspc-merge-restore-${randomUUID3()}.tmp`);
5284
5314
  try {
5285
5315
  await rename2(target, quarantine);
5286
5316
  } catch (error) {
@@ -5310,7 +5340,7 @@ async function restoreMergedLocalFile(target, backup, backupSha256, backupSizeBy
5310
5340
  async function downloadRemote(root, libraryId, path, api, expectedSha256, entry, onLocalMutation) {
5311
5341
  const target = resolveInsideRoot(root, path);
5312
5342
  await mkdir2(dirname(target), { recursive: true });
5313
- const tmp = join4(dirname(target), `.${basename2(target)}.wspc-download-${randomUUID2()}.tmp`);
5343
+ const tmp = join4(dirname(target), `.${basename2(target)}.wspc-download-${randomUUID3()}.tmp`);
5314
5344
  try {
5315
5345
  const response = await api.downloadFile(libraryId, path);
5316
5346
  if (!response.body) {
@@ -5444,7 +5474,7 @@ async function localFileExists(path) {
5444
5474
  return digest !== void 0;
5445
5475
  }
5446
5476
  function localMutationBackupPath(target) {
5447
- return join4(dirname(target), `.${basename2(target)}.wspc-backup-${randomUUID2()}.tmp`);
5477
+ return join4(dirname(target), `.${basename2(target)}.wspc-backup-${randomUUID3()}.tmp`);
5448
5478
  }
5449
5479
  function expectedLocalBaseSha256(entry) {
5450
5480
  return entry?.last_local_sha256 ?? entry?.content_sha256;
@@ -5546,7 +5576,7 @@ async function runDriveSyncOnce(root, api, clock = systemDriveClock) {
5546
5576
  });
5547
5577
  }
5548
5578
  function driveSyncCommand(api) {
5549
- const sync = new Command71("sync").description("Drive sync commands");
5579
+ const sync = new Command72("sync").description("Drive sync commands");
5550
5580
  sync.command("once").description("Run one Drive sync pass").argument("[path]", "local folder path", ".").action(async (path) => {
5551
5581
  const summary = await runDriveSyncOnce(resolve3(path), api);
5552
5582
  render({ kind: "drive_sync_once", display: { shape: "object" } }, summary);
@@ -5858,7 +5888,7 @@ async function writeConflictCopy(root, path, side, versionId, bytes, clock) {
5858
5888
  const target = resolveInsideRoot(root, candidate);
5859
5889
  await mkdir3(dirname2(target), { recursive: true });
5860
5890
  for (; ; ) {
5861
- const tmp = join5(dirname2(target), `.${basename3(target)}.wspc-conflict-${randomUUID3()}.tmp`);
5891
+ const tmp = join5(dirname2(target), `.${basename3(target)}.wspc-conflict-${randomUUID4()}.tmp`);
5862
5892
  let tmpWritten = false;
5863
5893
  try {
5864
5894
  await writeFile3(tmp, bytes, { flag: "wx" });
@@ -5999,7 +6029,7 @@ function containsVersionConflict(value) {
5999
6029
  }
6000
6030
 
6001
6031
  // src/handwritten/commands/drive/watch.ts
6002
- import { Command as Command72 } from "commander";
6032
+ import { Command as Command73 } from "commander";
6003
6033
  import chokidar from "chokidar";
6004
6034
  import { relative as relative2, resolve as resolve4 } from "path";
6005
6035
 
@@ -6438,7 +6468,7 @@ async function runDriveWatch(root, options = {}) {
6438
6468
  }
6439
6469
  }
6440
6470
  function driveWatchCommand(options = {}) {
6441
- return new Command72("watch").description("Watch a bound Drive folder and sync local changes").argument("[path]", "local folder path", ".").action(async (path) => {
6471
+ return new Command73("watch").description("Watch a bound Drive folder and sync local changes").argument("[path]", "local folder path", ".").action(async (path) => {
6442
6472
  await runDriveWatch(resolve4(path), options);
6443
6473
  });
6444
6474
  }
@@ -6502,7 +6532,7 @@ function waitForStopSignal(onRegistered) {
6502
6532
  function mountDriveCommands(program) {
6503
6533
  let drive = program.commands.find((c) => c.name() === "drive");
6504
6534
  if (!drive) {
6505
- drive = new Command73("drive").description("Drive commands");
6535
+ drive = new Command74("drive").description("Drive commands");
6506
6536
  program.addCommand(drive);
6507
6537
  }
6508
6538
  if (!drive.commands.some((c) => c.name() === "bind")) {
@@ -6528,7 +6558,7 @@ function isCliEntrypoint(argv = process.argv, metaUrl = import.meta.url) {
6528
6558
  }
6529
6559
  }
6530
6560
  function buildProgram() {
6531
- const program = new Command73().name("wspc").description("Official CLI for wspc.ai").version(`wspc ${VERSION} (spec ${SPEC_SHA}, fetched ${SPEC_FETCHED_AT})`).option("--json", "Output raw JSON (machine-readable)").option("--account <email>", "Run as a specific account (overrides the active account)").hook("preAction", (_thisCommand, actionCommand) => {
6561
+ const program = new Command74().name("wspc").description("Official CLI for wspc.ai").version(`wspc ${VERSION} (spec ${SPEC_SHA}, fetched ${SPEC_FETCHED_AT})`).option("--json", "Output raw JSON (machine-readable)").option("--account <email>", "Run as a specific account (overrides the active account)").hook("preAction", (_thisCommand, actionCommand) => {
6532
6562
  const globals = actionCommand.optsWithGlobals();
6533
6563
  if (globals.json) process.env.WSPC_OUTPUT = "json";
6534
6564
  if (globals.account) process.env.WSPC_ACCOUNT = String(globals.account);