agent-remnote 0.0.2 → 0.1.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/main.js +582 -530
  2. package/package.json +1 -1
package/dist/main.js CHANGED
@@ -75248,6 +75248,257 @@ function sanitizeRemnoteWritePayload(value8) {
75248
75248
  return out;
75249
75249
  }
75250
75250
 
75251
+ // src/kernel/op-catalog/catalog.ts
75252
+ var OP_CATALOG = {
75253
+ create_rem: {
75254
+ op_type: "create_rem",
75255
+ aliases: ["rem.create"],
75256
+ payload: {
75257
+ required: ["parent_id"],
75258
+ optional: ["text", "tags", "is_document", "position", "client_temp_id"]
75259
+ },
75260
+ description: "Create a Rem (parent required).",
75261
+ id_fields: ["parent_id", "tags[]"]
75262
+ },
75263
+ create_portal: {
75264
+ op_type: "create_portal",
75265
+ aliases: ["portal.create", "rem.createPortal"],
75266
+ payload: {
75267
+ required: ["parent_id", "target_rem_id"],
75268
+ optional: ["position", "client_temp_id"]
75269
+ },
75270
+ description: "Create a portal under parent that directly includes target_rem_id.",
75271
+ id_fields: ["parent_id", "target_rem_id"]
75272
+ },
75273
+ create_link_rem: {
75274
+ op_type: "create_link_rem",
75275
+ aliases: ["rem.createLink"],
75276
+ payload: {
75277
+ required: ["url", "parent_id"],
75278
+ optional: ["add_title", "client_temp_id"]
75279
+ },
75280
+ description: "Create a link Rem (parent required).",
75281
+ id_fields: ["parent_id"]
75282
+ },
75283
+ update_text: {
75284
+ op_type: "update_text",
75285
+ aliases: ["rem.updateText"],
75286
+ payload: { required: ["rem_id", "text"], optional: [] },
75287
+ description: "Update Rem text.",
75288
+ id_fields: ["rem_id"]
75289
+ },
75290
+ move_rem: {
75291
+ op_type: "move_rem",
75292
+ aliases: ["rem.move"],
75293
+ payload: { required: ["rem_id", "new_parent_id"], optional: ["position"] },
75294
+ description: "Move a Rem to a new parent.",
75295
+ id_fields: ["rem_id", "new_parent_id"]
75296
+ },
75297
+ delete_rem: {
75298
+ op_type: "delete_rem",
75299
+ aliases: ["rem.delete"],
75300
+ payload: { required: ["rem_id"], optional: [] },
75301
+ description: "Delete a Rem.",
75302
+ id_fields: ["rem_id"]
75303
+ },
75304
+ create_single_rem_with_markdown: {
75305
+ op_type: "create_single_rem_with_markdown",
75306
+ aliases: ["rem.createSingleWithMarkdown"],
75307
+ payload: { required: ["parent_id", "markdown"], optional: ["client_temp_id"] },
75308
+ description: "Create a single Rem from Markdown (parent required).",
75309
+ id_fields: ["parent_id"]
75310
+ },
75311
+ create_tree_with_markdown: {
75312
+ op_type: "create_tree_with_markdown",
75313
+ aliases: ["rem.createTreeWithMarkdown"],
75314
+ payload: {
75315
+ required: ["parent_id", "markdown"],
75316
+ optional: [
75317
+ "position",
75318
+ "indent_mode",
75319
+ "indent_size",
75320
+ "parse_mode",
75321
+ "prepared",
75322
+ "client_temp_ids",
75323
+ "bundle"
75324
+ ]
75325
+ },
75326
+ description: "Create a tree from Markdown (parent required).",
75327
+ id_fields: ["parent_id"]
75328
+ },
75329
+ replace_selection_with_markdown: {
75330
+ op_type: "replace_selection_with_markdown",
75331
+ payload: {
75332
+ required: ["markdown"],
75333
+ optional: ["target", "require_same_parent", "require_contiguous", "portal_id"]
75334
+ },
75335
+ description: "Replace a selection of Rems with Markdown.",
75336
+ id_fields: ["target.rem_ids[]", "portal_id"]
75337
+ },
75338
+ daily_note_write: {
75339
+ op_type: "daily_note_write",
75340
+ payload: {
75341
+ required: [],
75342
+ optional: ["text", "markdown", "date", "offset_days", "prepend", "position", "bundle"]
75343
+ },
75344
+ description: "Write to Daily Note.",
75345
+ id_fields: []
75346
+ },
75347
+ add_tag: {
75348
+ op_type: "add_tag",
75349
+ aliases: ["tag.add"],
75350
+ payload: { required: ["rem_id", "tag_id"], optional: [] },
75351
+ description: "Add a tag to a Rem.",
75352
+ id_fields: ["rem_id", "tag_id"]
75353
+ },
75354
+ remove_tag: {
75355
+ op_type: "remove_tag",
75356
+ aliases: ["tag.remove"],
75357
+ payload: { required: ["rem_id", "tag_id"], optional: ["remove_properties"] },
75358
+ description: "Remove a tag from a Rem.",
75359
+ id_fields: ["rem_id", "tag_id"]
75360
+ },
75361
+ set_attribute: {
75362
+ op_type: "set_attribute",
75363
+ aliases: ["attribute.set"],
75364
+ payload: { required: ["rem_id", "property_id"], optional: ["value"] },
75365
+ description: "Set an attribute value (RichText).",
75366
+ id_fields: ["rem_id", "property_id"]
75367
+ },
75368
+ table_cell_write: {
75369
+ op_type: "table_cell_write",
75370
+ aliases: ["table.cellWrite"],
75371
+ payload: { required: ["rem_id", "property_id"], optional: ["value"] },
75372
+ description: "Write text/RichText into a table cell (alias of set_attribute).",
75373
+ id_fields: ["rem_id", "property_id"]
75374
+ },
75375
+ create_table: {
75376
+ op_type: "create_table",
75377
+ aliases: ["table.create"],
75378
+ payload: { required: ["parent_id"], optional: ["tag_id", "position", "client_temp_id"] },
75379
+ description: "Create a table (parent required; optional header Tag).",
75380
+ id_fields: ["parent_id", "tag_id"]
75381
+ },
75382
+ add_property: {
75383
+ op_type: "add_property",
75384
+ aliases: ["property.add"],
75385
+ payload: { required: ["tag_id"], optional: ["name", "property_id", "type", "options"] },
75386
+ description: "Add a property under a table header Tag.",
75387
+ id_fields: ["tag_id"]
75388
+ },
75389
+ set_property_type: {
75390
+ op_type: "set_property_type",
75391
+ aliases: ["property.setType"],
75392
+ payload: { required: ["property_id", "type"], optional: [] },
75393
+ description: "Set property type.",
75394
+ id_fields: ["property_id"]
75395
+ },
75396
+ set_table_filter: {
75397
+ op_type: "set_table_filter",
75398
+ aliases: ["table.setFilter"],
75399
+ payload: { required: ["table_id"], optional: ["column_id", "contains_text", "expr"] },
75400
+ description: "Set a table filter (Query expression).",
75401
+ id_fields: ["table_id", "column_id"]
75402
+ },
75403
+ add_option: {
75404
+ op_type: "add_option",
75405
+ aliases: ["option.add"],
75406
+ payload: { required: ["property_id", "text"], optional: ["option_id"] },
75407
+ description: "Add an option under a property.",
75408
+ id_fields: ["property_id"]
75409
+ },
75410
+ remove_option: {
75411
+ op_type: "remove_option",
75412
+ aliases: ["option.remove"],
75413
+ payload: { required: ["option_id"], optional: [] },
75414
+ description: "Remove an option.",
75415
+ id_fields: ["option_id"]
75416
+ },
75417
+ table_add_row: {
75418
+ op_type: "table_add_row",
75419
+ aliases: ["table.addRow"],
75420
+ payload: {
75421
+ required: ["table_tag_id"],
75422
+ optional: ["parent_id", "rem_id", "text", "client_temp_id", "values", "extra_tags"]
75423
+ },
75424
+ description: "Add a row to a table (tag a Rem, optionally creating a new one).",
75425
+ id_fields: ["table_tag_id", "parent_id", "rem_id", "extra_tags[]", "values[].property_id"]
75426
+ },
75427
+ table_remove_row: {
75428
+ op_type: "table_remove_row",
75429
+ aliases: ["table.removeRow"],
75430
+ payload: { required: ["table_tag_id", "rem_id"], optional: ["remove_properties"] },
75431
+ description: "Remove a row tag from a table.",
75432
+ id_fields: ["table_tag_id", "rem_id"]
75433
+ },
75434
+ set_cell_select: {
75435
+ op_type: "set_cell_select",
75436
+ aliases: ["cell.setSelect"],
75437
+ payload: { required: ["rem_id", "property_id", "option_ids"], optional: [] },
75438
+ description: "Set a select/multi-select cell value.",
75439
+ id_fields: ["rem_id", "property_id", "option_ids", "option_ids[]"]
75440
+ },
75441
+ set_cell_checkbox: {
75442
+ op_type: "set_cell_checkbox",
75443
+ aliases: ["cell.setCheckbox"],
75444
+ payload: { required: ["rem_id", "property_id", "value"], optional: [] },
75445
+ description: "Set a checkbox cell value.",
75446
+ id_fields: ["rem_id", "property_id"]
75447
+ },
75448
+ set_cell_number: {
75449
+ op_type: "set_cell_number",
75450
+ aliases: ["cell.setNumber"],
75451
+ payload: { required: ["rem_id", "property_id", "value"], optional: [] },
75452
+ description: "Set a number cell value.",
75453
+ id_fields: ["rem_id", "property_id"]
75454
+ },
75455
+ set_cell_date: {
75456
+ op_type: "set_cell_date",
75457
+ aliases: ["cell.setDate"],
75458
+ payload: { required: ["rem_id", "property_id", "value"], optional: [] },
75459
+ description: "Set a date cell value (requires the Daily doc to exist).",
75460
+ id_fields: ["rem_id", "property_id"]
75461
+ },
75462
+ add_source: {
75463
+ op_type: "add_source",
75464
+ aliases: ["source.add"],
75465
+ payload: { required: ["rem_id", "source_id"], optional: [] },
75466
+ description: "Add a source link to a Rem.",
75467
+ id_fields: ["rem_id", "source_id"]
75468
+ },
75469
+ remove_source: {
75470
+ op_type: "remove_source",
75471
+ aliases: ["source.remove"],
75472
+ payload: { required: ["rem_id", "source_id"], optional: [] },
75473
+ description: "Remove a source link from a Rem.",
75474
+ id_fields: ["rem_id", "source_id"]
75475
+ },
75476
+ set_todo_status: {
75477
+ op_type: "set_todo_status",
75478
+ aliases: ["todo.setStatus"],
75479
+ payload: { required: ["rem_id", "status"], optional: [] },
75480
+ description: "Set todo completion status.",
75481
+ id_fields: ["rem_id"]
75482
+ }
75483
+ };
75484
+
75485
+ // src/kernel/op-catalog/normalize.ts
75486
+ function normalizeOpTypeInput(opTypeRaw) {
75487
+ return typeof opTypeRaw === "string" ? opTypeRaw.trim() : "";
75488
+ }
75489
+ var OP_ALIAS_TO_TYPE = Object.freeze(Object.fromEntries(Object.entries(OP_CATALOG).flatMap(([type2, entry]) => {
75490
+ const aliases = Array.isArray(entry.aliases) ? entry.aliases : [];
75491
+ return aliases.map((alias) => [alias, type2]);
75492
+ })));
75493
+ function canonicalizeOpType(opTypeRaw) {
75494
+ const opType = normalizeOpTypeInput(opTypeRaw);
75495
+ if (!opType)
75496
+ return "";
75497
+ if (OP_CATALOG[opType])
75498
+ return opType;
75499
+ return OP_ALIAS_TO_TYPE[opType] ?? opType;
75500
+ }
75501
+
75251
75502
  // src/kernel/conflicts/deriveConflictKeys.ts
75252
75503
  function asNonEmptyString(value8) {
75253
75504
  if (typeof value8 !== "string")
@@ -75310,7 +75561,7 @@ function isStructureOp(opType) {
75310
75561
  return opType === "move_rem" || opType === "delete_rem" || opType === "replace_selection_with_markdown";
75311
75562
  }
75312
75563
  function deriveConflictKeys(opTypeRaw, payload) {
75313
- const opType = typeof opTypeRaw === "string" ? opTypeRaw.trim() : "";
75564
+ const opType = canonicalizeOpType(opTypeRaw);
75314
75565
  const p3 = payload && typeof payload === "object" ? payload : null;
75315
75566
  const keys8 = [];
75316
75567
  if (opType === "daily_note_write") {
@@ -75319,6 +75570,7 @@ function deriveConflictKeys(opTypeRaw, payload) {
75319
75570
  }
75320
75571
  const remId = getFirstString(p3, ["rem_id", "remId"]);
75321
75572
  const parentId = getFirstString(p3, ["parent_id", "parentId"]);
75573
+ const newParentId = getFirstString(p3, ["new_parent_id", "newParentId"]);
75322
75574
  const toParentId = getFirstString(p3, ["to_parent_id", "toParentId", "target_parent_id", "targetParentId"]);
75323
75575
  const fromParentId = getFirstString(p3, ["from_parent_id", "fromParentId"]);
75324
75576
  if (opType === "create_portal") {
@@ -75347,7 +75599,7 @@ function deriveConflictKeys(opTypeRaw, payload) {
75347
75599
  if (isStructureOp(opType)) {
75348
75600
  if (remId)
75349
75601
  keys8.push(`rem:${remId}`);
75350
- const parents = [parentId, toParentId, fromParentId].filter((x) => typeof x === "string" && x.length > 0);
75602
+ const parents = [parentId, newParentId, toParentId, fromParentId].filter((x) => typeof x === "string" && x.length > 0);
75351
75603
  for (const pid of parents)
75352
75604
  keys8.push(`children:${pid}`);
75353
75605
  if (!remId && parents.length === 0) {
@@ -75595,7 +75847,7 @@ function ackSuccess(db, params3) {
75595
75847
  return { ok: false, op_id: params3.opId, attempt_id: params3.attemptId, reason: "invalid_attempt", current: cur };
75596
75848
  }
75597
75849
  const res = db.prepare(`UPDATE queue_ops
75598
- SET status='succeeded', updated_at=@t
75850
+ SET status='succeeded', locked_at=NULL, lease_expires_at=NULL, updated_at=@t
75599
75851
  WHERE op_id=@op_id AND status='in_flight' AND locked_by=@locked_by AND attempt_id=@attempt_id`).run({ t, op_id: params3.opId, locked_by: params3.lockedBy, attempt_id: params3.attemptId });
75600
75852
  if (res.changes === 0) {
75601
75853
  return { ok: false, op_id: params3.opId, attempt_id: params3.attemptId, reason: "stale_ack", current: cur };
@@ -75627,7 +75879,7 @@ function ackSuccess(db, params3) {
75627
75879
  function ackRetry(db, params3) {
75628
75880
  const t = nowMs();
75629
75881
  const trx = db.transaction(() => {
75630
- const current2 = db.prepare(`SELECT status, attempt_id, locked_by, attempt_count, max_attempts FROM queue_ops WHERE op_id=?`).get(params3.opId);
75882
+ const current2 = db.prepare(`SELECT txn_id, status, attempt_id, locked_by, attempt_count, max_attempts FROM queue_ops WHERE op_id=?`).get(params3.opId);
75631
75883
  if (!current2) {
75632
75884
  return { ok: false, op_id: params3.opId, attempt_id: params3.attemptId, reason: "not_found" };
75633
75885
  }
@@ -75636,13 +75888,54 @@ function ackRetry(db, params3) {
75636
75888
  attempt_id: current2.attempt_id ?? null,
75637
75889
  locked_by: current2.locked_by ?? null
75638
75890
  };
75639
- if (cur.attempt_id === params3.attemptId && cur.locked_by === params3.lockedBy && cur.status === "pending") {
75891
+ if (cur.attempt_id === params3.attemptId && cur.locked_by === params3.lockedBy && (cur.status === "pending" || cur.status === "dead")) {
75640
75892
  return { ok: true, op_id: params3.opId, attempt_id: params3.attemptId, duplicate: true };
75641
75893
  }
75642
75894
  if (cur.attempt_id !== params3.attemptId) {
75643
75895
  return { ok: false, op_id: params3.opId, attempt_id: params3.attemptId, reason: "invalid_attempt", current: cur };
75644
75896
  }
75645
75897
  const attempt2 = Number(current2.attempt_count ?? 0) + 1;
75898
+ const maxAttemptsRaw = Number(current2.max_attempts ?? 10);
75899
+ const maxAttempts = Number.isFinite(maxAttemptsRaw) && maxAttemptsRaw > 0 ? Math.floor(maxAttemptsRaw) : 10;
75900
+ if (attempt2 >= maxAttempts) {
75901
+ const reason = params3.error.message ?? params3.error.code ?? "max attempts exceeded";
75902
+ const res2 = db.prepare(`UPDATE queue_ops
75903
+ SET status='dead',
75904
+ attempt_count=@attempt,
75905
+ dead_reason=@reason,
75906
+ locked_at=NULL,
75907
+ lease_expires_at=NULL,
75908
+ updated_at=@t
75909
+ WHERE op_id=@op_id AND status='in_flight' AND locked_by=@locked_by AND attempt_id=@attempt_id`).run({
75910
+ attempt: attempt2,
75911
+ reason,
75912
+ t,
75913
+ op_id: params3.opId,
75914
+ locked_by: params3.lockedBy,
75915
+ attempt_id: params3.attemptId
75916
+ });
75917
+ if (res2.changes === 0) {
75918
+ return { ok: false, op_id: params3.opId, attempt_id: params3.attemptId, reason: "stale_ack", current: cur };
75919
+ }
75920
+ db.prepare(`INSERT OR REPLACE INTO queue_op_results(op_id, error_code, error_message, finished_at) VALUES(@op_id, @code, @message, @t)`).run({ op_id: params3.opId, code: params3.error.code ?? null, message: params3.error.message ?? null, t });
75921
+ upsertOpAttempt(db, {
75922
+ opId: params3.opId,
75923
+ attemptId: params3.attemptId,
75924
+ connId: params3.lockedBy,
75925
+ status: "dead",
75926
+ detail: {
75927
+ acked_at: t,
75928
+ retry_after_ms: null,
75929
+ max_attempts: maxAttempts,
75930
+ exhausted_at_attempt: attempt2
75931
+ }
75932
+ });
75933
+ db.prepare(`UPDATE queue_txns SET status='failed', finished_at=@t, updated_at=@t WHERE txn_id=@txn_id`).run({
75934
+ t,
75935
+ txn_id: String(current2.txn_id)
75936
+ });
75937
+ return { ok: true, op_id: params3.opId, attempt_id: params3.attemptId, duplicate: false };
75938
+ }
75646
75939
  const base = Math.min(60000, Math.pow(2, attempt2) * 1000);
75647
75940
  const jitter = Math.round(base * (0.1 + Math.random() * 0.2));
75648
75941
  const delay3 = params3.error.retryAfterMs ?? base + jitter;
@@ -75651,6 +75944,7 @@ function ackRetry(db, params3) {
75651
75944
  SET status='pending',
75652
75945
  attempt_count=@attempt,
75653
75946
  next_attempt_at=@next,
75947
+ locked_at=NULL,
75654
75948
  lease_expires_at=NULL,
75655
75949
  updated_at=@t
75656
75950
  WHERE op_id=@op_id AND status='in_flight' AND locked_by=@locked_by AND attempt_id=@attempt_id`).run({ attempt: attempt2, next: next4, t, op_id: params3.opId, locked_by: params3.lockedBy, attempt_id: params3.attemptId });
@@ -75689,7 +75983,7 @@ function ackDead(db, params3) {
75689
75983
  }
75690
75984
  const reason = params3.error.message ?? params3.error.code ?? "dead";
75691
75985
  const res = db.prepare(`UPDATE queue_ops
75692
- SET status='dead', dead_reason=@reason, lease_expires_at=NULL, updated_at=@t
75986
+ SET status='dead', dead_reason=@reason, locked_at=NULL, lease_expires_at=NULL, updated_at=@t
75693
75987
  WHERE op_id=@op_id AND status='in_flight' AND locked_by=@locked_by AND attempt_id=@attempt_id`).run({ reason, t, op_id: params3.opId, locked_by: params3.lockedBy, attempt_id: params3.attemptId });
75694
75988
  if (res.changes === 0) {
75695
75989
  return { ok: false, op_id: params3.opId, attempt_id: params3.attemptId, reason: "stale_ack", current: cur };
@@ -75787,8 +76081,12 @@ function getRemoteIdsByClientTempIds(db, clientTempIds) {
75787
76081
  return out;
75788
76082
  }
75789
76083
  function queueStats(db) {
76084
+ const now2 = nowMs();
75790
76085
  const q = (sql) => db.prepare(sql).get();
75791
- const pending2 = q(`SELECT COUNT(1) as c FROM queue_ops WHERE status='pending' AND next_attempt_at<=${nowMs()}`)?.c ?? 0;
76086
+ const pending2 = q(`SELECT COUNT(1) as c
76087
+ FROM queue_ops o
76088
+ JOIN queue_txns x ON x.txn_id = o.txn_id
76089
+ WHERE o.status='pending' AND o.next_attempt_at<=${now2} AND x.status IN ('ready','in_progress')`)?.c ?? 0;
75792
76090
  const in_flight = q(`SELECT COUNT(1) as c FROM queue_ops WHERE status='in_flight'`)?.c ?? 0;
75793
76091
  const dead = q(`SELECT COUNT(1) as c FROM queue_ops WHERE status='dead'`)?.c ?? 0;
75794
76092
  const ready_txns = q(`SELECT COUNT(1) as c FROM queue_txns WHERE status IN ('ready','in_progress')`)?.c ?? 0;
@@ -76269,278 +76567,71 @@ function handleOpAckMessage(params3) {
76269
76567
  actions.push({ _tag: "SendJson", connId: params3.connId, msg: { type: "AckOk", ok: true, op_id: opId, attempt_id: attemptId } });
76270
76568
  return { actions, touchAckTimestamp: true, invalidateStatusLineReason: "op_acked" };
76271
76569
  }
76272
-
76273
- // src/kernel/op-catalog/catalog.ts
76274
- var OP_CATALOG = {
76275
- create_rem: {
76276
- op_type: "create_rem",
76277
- aliases: ["rem.create"],
76278
- payload: {
76279
- required: ["parent_id"],
76280
- optional: ["text", "tags", "is_document", "position", "client_temp_id"]
76281
- },
76282
- description: "Create a Rem (parent required).",
76283
- id_fields: ["parent_id", "tags[]"]
76284
- },
76285
- create_portal: {
76286
- op_type: "create_portal",
76287
- aliases: ["portal.create", "rem.createPortal"],
76288
- payload: {
76289
- required: ["parent_id", "target_rem_id"],
76290
- optional: ["position", "client_temp_id"]
76291
- },
76292
- description: "Create a portal under parent that directly includes target_rem_id.",
76293
- id_fields: ["parent_id", "target_rem_id"]
76294
- },
76295
- create_link_rem: {
76296
- op_type: "create_link_rem",
76297
- aliases: ["rem.createLink"],
76298
- payload: {
76299
- required: ["url", "parent_id"],
76300
- optional: ["add_title", "client_temp_id"]
76301
- },
76302
- description: "Create a link Rem (parent required).",
76303
- id_fields: ["parent_id"]
76304
- },
76305
- update_text: {
76306
- op_type: "update_text",
76307
- aliases: ["rem.updateText"],
76308
- payload: { required: ["rem_id", "text"], optional: [] },
76309
- description: "Update Rem text.",
76310
- id_fields: ["rem_id"]
76311
- },
76312
- move_rem: {
76313
- op_type: "move_rem",
76314
- aliases: ["rem.move"],
76315
- payload: { required: ["rem_id", "new_parent_id"], optional: ["position"] },
76316
- description: "Move a Rem to a new parent.",
76317
- id_fields: ["rem_id", "new_parent_id"]
76318
- },
76319
- delete_rem: {
76320
- op_type: "delete_rem",
76321
- aliases: ["rem.delete"],
76322
- payload: { required: ["rem_id"], optional: [] },
76323
- description: "Delete a Rem.",
76324
- id_fields: ["rem_id"]
76325
- },
76326
- create_single_rem_with_markdown: {
76327
- op_type: "create_single_rem_with_markdown",
76328
- aliases: ["rem.createSingleWithMarkdown"],
76329
- payload: { required: ["parent_id", "markdown"], optional: ["client_temp_id"] },
76330
- description: "Create a single Rem from Markdown (parent required).",
76331
- id_fields: ["parent_id"]
76332
- },
76333
- create_tree_with_markdown: {
76334
- op_type: "create_tree_with_markdown",
76335
- aliases: ["rem.createTreeWithMarkdown"],
76336
- payload: {
76337
- required: ["parent_id", "markdown"],
76338
- optional: [
76339
- "position",
76340
- "indent_mode",
76341
- "indent_size",
76342
- "parse_mode",
76343
- "prepared",
76344
- "client_temp_ids",
76345
- "bundle"
76346
- ]
76347
- },
76348
- description: "Create a tree from Markdown (parent required).",
76349
- id_fields: ["parent_id"]
76350
- },
76351
- replace_selection_with_markdown: {
76352
- op_type: "replace_selection_with_markdown",
76353
- payload: {
76354
- required: ["markdown"],
76355
- optional: ["target", "require_same_parent", "require_contiguous", "portal_id"]
76356
- },
76357
- description: "Replace a selection of Rems with Markdown.",
76358
- id_fields: ["target.rem_ids[]", "portal_id"]
76359
- },
76360
- daily_note_write: {
76361
- op_type: "daily_note_write",
76362
- payload: {
76363
- required: [],
76364
- optional: ["text", "markdown", "date", "offset_days", "prepend", "position", "bundle"]
76365
- },
76366
- description: "Write to Daily Note.",
76367
- id_fields: []
76368
- },
76369
- add_tag: {
76370
- op_type: "add_tag",
76371
- aliases: ["tag.add"],
76372
- payload: { required: ["rem_id", "tag_id"], optional: [] },
76373
- description: "Add a tag to a Rem.",
76374
- id_fields: ["rem_id", "tag_id"]
76375
- },
76376
- remove_tag: {
76377
- op_type: "remove_tag",
76378
- aliases: ["tag.remove"],
76379
- payload: { required: ["rem_id", "tag_id"], optional: ["remove_properties"] },
76380
- description: "Remove a tag from a Rem.",
76381
- id_fields: ["rem_id", "tag_id"]
76382
- },
76383
- set_attribute: {
76384
- op_type: "set_attribute",
76385
- aliases: ["attribute.set"],
76386
- payload: { required: ["rem_id", "property_id"], optional: ["value"] },
76387
- description: "Set an attribute value (RichText).",
76388
- id_fields: ["rem_id", "property_id"]
76389
- },
76390
- table_cell_write: {
76391
- op_type: "table_cell_write",
76392
- aliases: ["table.cellWrite"],
76393
- payload: { required: ["rem_id", "property_id"], optional: ["value"] },
76394
- description: "Write text/RichText into a table cell (alias of set_attribute).",
76395
- id_fields: ["rem_id", "property_id"]
76396
- },
76397
- create_table: {
76398
- op_type: "create_table",
76399
- aliases: ["table.create"],
76400
- payload: { required: ["parent_id"], optional: ["tag_id", "position", "client_temp_id"] },
76401
- description: "Create a table (parent required; optional header Tag).",
76402
- id_fields: ["parent_id", "tag_id"]
76403
- },
76404
- add_property: {
76405
- op_type: "add_property",
76406
- aliases: ["property.add"],
76407
- payload: { required: ["tag_id"], optional: ["name", "property_id", "type", "options"] },
76408
- description: "Add a property under a table header Tag.",
76409
- id_fields: ["tag_id"]
76410
- },
76411
- set_property_type: {
76412
- op_type: "set_property_type",
76413
- aliases: ["property.setType"],
76414
- payload: { required: ["property_id", "type"], optional: [] },
76415
- description: "Set property type.",
76416
- id_fields: ["property_id"]
76417
- },
76418
- set_table_filter: {
76419
- op_type: "set_table_filter",
76420
- aliases: ["table.setFilter"],
76421
- payload: { required: ["table_id"], optional: ["column_id", "contains_text", "expr"] },
76422
- description: "Set a table filter (Query expression).",
76423
- id_fields: ["table_id", "column_id"]
76424
- },
76425
- add_option: {
76426
- op_type: "add_option",
76427
- aliases: ["option.add"],
76428
- payload: { required: ["property_id", "text"], optional: ["option_id"] },
76429
- description: "Add an option under a property.",
76430
- id_fields: ["property_id"]
76431
- },
76432
- remove_option: {
76433
- op_type: "remove_option",
76434
- aliases: ["option.remove"],
76435
- payload: { required: ["option_id"], optional: [] },
76436
- description: "Remove an option.",
76437
- id_fields: ["option_id"]
76438
- },
76439
- table_add_row: {
76440
- op_type: "table_add_row",
76441
- aliases: ["table.addRow"],
76442
- payload: {
76443
- required: ["table_tag_id"],
76444
- optional: ["parent_id", "rem_id", "text", "client_temp_id", "values", "extra_tags"]
76445
- },
76446
- description: "Add a row to a table (tag a Rem, optionally creating a new one).",
76447
- id_fields: ["table_tag_id", "parent_id", "rem_id", "extra_tags[]"]
76448
- },
76449
- table_remove_row: {
76450
- op_type: "table_remove_row",
76451
- aliases: ["table.removeRow"],
76452
- payload: { required: ["table_tag_id", "rem_id"], optional: ["remove_properties"] },
76453
- description: "Remove a row tag from a table.",
76454
- id_fields: ["table_tag_id", "rem_id"]
76455
- },
76456
- set_cell_select: {
76457
- op_type: "set_cell_select",
76458
- aliases: ["cell.setSelect"],
76459
- payload: { required: ["rem_id", "property_id", "option_ids"], optional: [] },
76460
- description: "Set a select/multi-select cell value.",
76461
- id_fields: ["rem_id", "property_id", "option_ids", "option_ids[]"]
76462
- },
76463
- set_cell_checkbox: {
76464
- op_type: "set_cell_checkbox",
76465
- aliases: ["cell.setCheckbox"],
76466
- payload: { required: ["rem_id", "property_id", "value"], optional: [] },
76467
- description: "Set a checkbox cell value.",
76468
- id_fields: ["rem_id", "property_id"]
76469
- },
76470
- set_cell_number: {
76471
- op_type: "set_cell_number",
76472
- aliases: ["cell.setNumber"],
76473
- payload: { required: ["rem_id", "property_id", "value"], optional: [] },
76474
- description: "Set a number cell value.",
76475
- id_fields: ["rem_id", "property_id"]
76476
- },
76477
- set_cell_date: {
76478
- op_type: "set_cell_date",
76479
- aliases: ["cell.setDate"],
76480
- payload: { required: ["rem_id", "property_id", "value"], optional: [] },
76481
- description: "Set a date cell value (requires the Daily doc to exist).",
76482
- id_fields: ["rem_id", "property_id"]
76483
- },
76484
- add_source: {
76485
- op_type: "add_source",
76486
- aliases: ["source.add"],
76487
- payload: { required: ["rem_id", "source_id"], optional: [] },
76488
- description: "Add a source link to a Rem.",
76489
- id_fields: ["rem_id", "source_id"]
76490
- },
76491
- remove_source: {
76492
- op_type: "remove_source",
76493
- aliases: ["source.remove"],
76494
- payload: { required: ["rem_id", "source_id"], optional: [] },
76495
- description: "Remove a source link from a Rem.",
76496
- id_fields: ["rem_id", "source_id"]
76497
- },
76498
- set_todo_status: {
76499
- op_type: "set_todo_status",
76500
- aliases: ["todo.setStatus"],
76501
- payload: { required: ["rem_id", "status"], optional: [] },
76502
- description: "Set todo completion status.",
76503
- id_fields: ["rem_id"]
76570
+ // src/kernel/op-catalog/idFields.ts
76571
+ function idFieldPathsForOpType(opTypeRaw) {
76572
+ const opType = canonicalizeOpType(opTypeRaw);
76573
+ const entry = OP_CATALOG[opType];
76574
+ if (!entry)
76575
+ return [];
76576
+ return Array.isArray(entry.id_fields) ? entry.id_fields : [];
76577
+ }
76578
+ // src/kernel/op-catalog/pathWalk.ts
76579
+ function parsePathTokens(path11) {
76580
+ return path11.split(".").map((part) => part.trim()).filter(Boolean).map((part) => {
76581
+ const isArray2 = part.endsWith("[]");
76582
+ const key = isArray2 ? part.slice(0, -2).trim() : part;
76583
+ return { key, isArray: isArray2 };
76584
+ }).filter((token) => token.key.length > 0);
76585
+ }
76586
+ function collectLeafValues(value8, path11, idx = 0) {
76587
+ if (idx >= path11.length)
76588
+ return [value8];
76589
+ if (!value8 || typeof value8 !== "object")
76590
+ return [];
76591
+ const token = path11[idx];
76592
+ const next4 = value8[token.key];
76593
+ if (token.isArray) {
76594
+ if (!Array.isArray(next4))
76595
+ return [];
76596
+ const out = [];
76597
+ for (const item of next4) {
76598
+ out.push(...collectLeafValues(item, path11, idx + 1));
76599
+ }
76600
+ return out;
76601
+ }
76602
+ return collectLeafValues(next4, path11, idx + 1);
76603
+ }
76604
+ function mapLeafValuesInPlace(value8, path11, mapFn, idx = 0) {
76605
+ if (idx >= path11.length)
76606
+ return;
76607
+ if (!value8 || typeof value8 !== "object")
76608
+ return;
76609
+ const token = path11[idx];
76610
+ const isLeaf = idx === path11.length - 1;
76611
+ if (token.isArray) {
76612
+ const next4 = value8[token.key];
76613
+ if (!Array.isArray(next4))
76614
+ return;
76615
+ if (isLeaf) {
76616
+ value8[token.key] = next4.map((item) => mapFn(item));
76617
+ return;
76618
+ }
76619
+ for (const item of next4) {
76620
+ mapLeafValuesInPlace(item, path11, mapFn, idx + 1);
76621
+ }
76622
+ return;
76504
76623
  }
76505
- };
76506
- // src/kernel/op-catalog/idFields.ts
76507
- function idFieldPathsForOpType(opTypeRaw) {
76508
- const opType = typeof opTypeRaw === "string" ? opTypeRaw.trim() : "";
76509
- const entry = OP_CATALOG[opType];
76510
- if (!entry)
76511
- return [];
76512
- return Array.isArray(entry.id_fields) ? entry.id_fields : [];
76624
+ if (isLeaf) {
76625
+ value8[token.key] = mapFn(value8[token.key]);
76626
+ return;
76627
+ }
76628
+ mapLeafValuesInPlace(value8[token.key], path11, mapFn, idx + 1);
76513
76629
  }
76630
+
76514
76631
  // src/kernel/op-catalog/substituteIds.ts
76515
76632
  function isTempId(value8) {
76516
76633
  return typeof value8 === "string" && value8.trim().startsWith("tmp:");
76517
76634
  }
76518
- function parsePath(path11) {
76519
- const array10 = path11.endsWith("[]");
76520
- const raw4 = array10 ? path11.slice(0, -2) : path11;
76521
- const segments = raw4.split(".").filter(Boolean);
76522
- return { segments, array: array10 };
76523
- }
76524
- function getAt2(root, segments) {
76525
- let cur = root;
76526
- for (const k of segments) {
76527
- if (!cur || typeof cur !== "object")
76528
- return;
76529
- cur = cur[k];
76530
- }
76531
- return cur;
76532
- }
76533
- function setAt(root, segments, value8) {
76534
- let cur = root;
76535
- for (let i = 0;i < segments.length - 1; i += 1) {
76536
- const k = segments[i];
76537
- const next4 = cur[k];
76538
- if (!next4 || typeof next4 !== "object")
76539
- cur[k] = {};
76540
- cur = cur[k];
76541
- }
76542
- cur[segments[segments.length - 1]] = value8;
76543
- }
76544
76635
  function cloneJson(value8) {
76545
76636
  if (value8 == null || typeof value8 !== "object")
76546
76637
  return value8;
@@ -76556,19 +76647,14 @@ function collectTempIdsFromPayload(opTypeRaw, payload) {
76556
76647
  if (!payload || typeof payload !== "object")
76557
76648
  return [];
76558
76649
  const out = [];
76559
- for (const p3 of idFieldPathsForOpType(opTypeRaw)) {
76560
- const parsed = parsePath(p3);
76561
- const current2 = getAt2(payload, parsed.segments);
76562
- if (parsed.array) {
76563
- if (!Array.isArray(current2))
76564
- continue;
76565
- for (const v of current2) {
76566
- if (isTempId(v) && !out.includes(v.trim()))
76567
- out.push(v.trim());
76568
- }
76569
- } else {
76570
- if (isTempId(current2) && !out.includes(current2.trim()))
76571
- out.push(current2.trim());
76650
+ for (const path11 of idFieldPathsForOpType(opTypeRaw)) {
76651
+ const tokens = parsePathTokens(path11);
76652
+ if (tokens.length === 0)
76653
+ continue;
76654
+ const values5 = collectLeafValues(payload, tokens);
76655
+ for (const value8 of values5) {
76656
+ if (isTempId(value8) && !out.includes(value8.trim()))
76657
+ out.push(value8.trim());
76572
76658
  }
76573
76659
  }
76574
76660
  return out;
@@ -76577,26 +76663,16 @@ function substituteTempIdsInPayload(opTypeRaw, payload, idMap) {
76577
76663
  if (!payload || typeof payload !== "object")
76578
76664
  return payload;
76579
76665
  const out = cloneJson(payload);
76580
- for (const p3 of idFieldPathsForOpType(opTypeRaw)) {
76581
- const parsed = parsePath(p3);
76582
- const current2 = getAt2(out, parsed.segments);
76583
- if (parsed.array) {
76584
- if (!Array.isArray(current2))
76585
- continue;
76586
- const next4 = current2.map((v) => {
76587
- if (!isTempId(v))
76588
- return v;
76589
- const mapped = idMap[v.trim()];
76590
- return mapped ? mapped : v;
76591
- });
76592
- setAt(out, parsed.segments, next4);
76593
- } else {
76594
- if (!isTempId(current2))
76595
- continue;
76596
- const mapped = idMap[current2.trim()];
76597
- if (mapped)
76598
- setAt(out, parsed.segments, mapped);
76599
- }
76666
+ for (const path11 of idFieldPathsForOpType(opTypeRaw)) {
76667
+ const tokens = parsePathTokens(path11);
76668
+ if (tokens.length === 0)
76669
+ continue;
76670
+ mapLeafValuesInPlace(out, tokens, (value8) => {
76671
+ if (!isTempId(value8))
76672
+ return value8;
76673
+ const mapped = idMap[value8.trim()];
76674
+ return mapped ? mapped : value8;
76675
+ });
76600
76676
  }
76601
76677
  return out;
76602
76678
  }
@@ -77899,8 +77975,8 @@ function getTimezoneOffsetInMilliseconds(date6) {
77899
77975
 
77900
77976
  // ../../node_modules/date-fns/_lib/normalizeDates.js
77901
77977
  function normalizeDates(context8, ...dates) {
77902
- const normalize2 = constructFrom.bind(null, context8 || dates.find((date6) => typeof date6 === "object"));
77903
- return dates.map(normalize2);
77978
+ const normalize3 = constructFrom.bind(null, context8 || dates.find((date6) => typeof date6 === "object"));
77979
+ return dates.map(normalize3);
77904
77980
  }
77905
77981
 
77906
77982
  // ../../node_modules/date-fns/startOfDay.js
@@ -91715,12 +91791,16 @@ function normalizeOp(raw4, normalizer) {
91715
91791
  if (!type2) {
91716
91792
  throw new CliError({ code: "INVALID_PAYLOAD", message: "op.type is required and must be a string", exitCode: 2 });
91717
91793
  }
91794
+ const canonicalType = canonicalizeOpType(type2);
91795
+ if (!canonicalType) {
91796
+ throw new CliError({ code: "INVALID_PAYLOAD", message: "op.type is required and must be a string", exitCode: 2 });
91797
+ }
91718
91798
  const payload = normalizer(raw4.payload ?? {});
91719
91799
  const idempotencyKey = typeof raw4.idempotencyKey === "string" ? raw4.idempotencyKey : typeof raw4.idempotency_key === "string" ? raw4.idempotency_key : undefined;
91720
91800
  const maxAttempts = typeof raw4.maxAttempts === "number" ? raw4.maxAttempts : typeof raw4.max_attempts === "number" ? raw4.max_attempts : undefined;
91721
91801
  const deliverAfterMs = typeof raw4.deliverAfterMs === "number" ? raw4.deliverAfterMs : typeof raw4.deliver_after_ms === "number" ? raw4.deliver_after_ms : undefined;
91722
91802
  return {
91723
- type: type2,
91803
+ type: canonicalType,
91724
91804
  payload,
91725
91805
  idempotencyKey,
91726
91806
  maxAttempts,
@@ -93541,23 +93621,7 @@ function compileWritePlanV1(plan, params3) {
93541
93621
  }
93542
93622
  return { alias_map: aliasMap, ops };
93543
93623
  }
93544
- // src/commands/plan/apply.ts
93545
- function optionToUndefined16(opt) {
93546
- return isSome2(opt) ? opt.value : undefined;
93547
- }
93548
- function readOptionalText4(name) {
93549
- return text9(name).pipe(optional5, map34(optionToUndefined16));
93550
- }
93551
- var payload = text9("payload");
93552
- var clientId5 = readOptionalText4("client-id");
93553
- var idempotencyKey5 = readOptionalText4("idempotency-key");
93554
- var metaSpec5 = readOptionalText4("meta");
93555
- var priority5 = integer7("priority").pipe(optional5, map34(optionToUndefined16));
93556
- var notify5 = boolean8("no-notify").pipe(map34((v) => !v));
93557
- var ensureDaemon6 = boolean8("no-ensure-daemon").pipe(map34((v) => !v));
93558
- var wait3 = boolean8("wait");
93559
- var timeoutMs3 = integer7("timeout-ms").pipe(optional5, map34(optionToUndefined16));
93560
- var pollMs3 = integer7("poll-ms").pipe(optional5, map34(optionToUndefined16));
93624
+ // src/commands/_resolveRefsInPayload.ts
93561
93625
  function shouldResolveRef(value8) {
93562
93626
  const s = value8.trim();
93563
93627
  if (!s)
@@ -93572,184 +93636,202 @@ function shouldResolveRef(value8) {
93572
93636
  const prefix2 = s.slice(0, idx).trim().toLowerCase();
93573
93637
  return prefix2 === "id" || prefix2 === "page" || prefix2 === "title" || prefix2 === "daily";
93574
93638
  }
93575
- function parsePath2(path22) {
93576
- const array10 = path22.endsWith("[]");
93577
- const raw4 = array10 ? path22.slice(0, -2) : path22;
93578
- const segments = raw4.split(".").filter(Boolean);
93579
- return { segments, array: array10 };
93639
+ function resolveRefsInPayload(params3) {
93640
+ return gen2(function* () {
93641
+ const refs = yield* RefResolver;
93642
+ const out = structuredClone(params3.payload);
93643
+ const resolvedRefCache = new Map;
93644
+ const idPaths = idFieldPathsForOpType(params3.opType);
93645
+ for (const path22 of idPaths) {
93646
+ const tokens = parsePathTokens(path22);
93647
+ if (tokens.length === 0)
93648
+ continue;
93649
+ const leaves = collectLeafValues(out, tokens);
93650
+ if (leaves.length === 0)
93651
+ continue;
93652
+ const mapped = yield* forEach9(leaves, (leaf) => gen2(function* () {
93653
+ if (typeof leaf !== "string")
93654
+ return leaf;
93655
+ const refValue = leaf.trim();
93656
+ if (!shouldResolveRef(refValue))
93657
+ return leaf;
93658
+ const cached4 = resolvedRefCache.get(refValue);
93659
+ if (cached4)
93660
+ return cached4;
93661
+ const resolved = yield* refs.resolve(refValue);
93662
+ resolvedRefCache.set(refValue, resolved);
93663
+ return resolved;
93664
+ }), { concurrency: 1 });
93665
+ let idx = 0;
93666
+ mapLeafValuesInPlace(out, tokens, () => mapped[idx++]);
93667
+ }
93668
+ return out;
93669
+ });
93580
93670
  }
93671
+
93672
+ // src/commands/_tempId.ts
93581
93673
  function makeUuidLike() {
93582
93674
  const g = globalThis;
93583
93675
  if (g.crypto && typeof g.crypto.randomUUID === "function")
93584
93676
  return String(g.crypto.randomUUID());
93585
93677
  return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;
93586
93678
  }
93587
- function getAt3(root, segments) {
93588
- let cur = root;
93589
- for (const k of segments) {
93590
- if (!cur || typeof cur !== "object")
93591
- return;
93592
- cur = cur[k];
93593
- }
93594
- return cur;
93679
+ function makeTempId() {
93680
+ return `tmp:${makeUuidLike()}`;
93595
93681
  }
93596
- function setAt2(root, segments, value8) {
93597
- let cur = root;
93598
- for (let i = 0;i < segments.length - 1; i += 1) {
93599
- const k = segments[i];
93600
- const next4 = cur[k];
93601
- if (!next4 || typeof next4 !== "object") {
93602
- cur[k] = {};
93603
- }
93604
- cur = cur[k];
93605
- }
93606
- cur[segments[segments.length - 1]] = value8;
93682
+
93683
+ // src/commands/_writePlanCommand.ts
93684
+ function optionToUndefined16(opt) {
93685
+ return isSome2(opt) ? opt.value : undefined;
93607
93686
  }
93608
- function resolveRefsInPayload(params3) {
93609
- return gen2(function* () {
93610
- const refs = yield* RefResolver;
93611
- const out = structuredClone(params3.payload);
93612
- const idPaths = idFieldPathsForOpType(params3.opType);
93613
- for (const p3 of idPaths) {
93614
- const parsed = parsePath2(p3);
93615
- const current2 = getAt3(out, parsed.segments);
93616
- if (parsed.array) {
93617
- if (!Array.isArray(current2))
93618
- continue;
93619
- const next4 = [];
93620
- for (const v of current2) {
93621
- if (typeof v === "string" && shouldResolveRef(v)) {
93622
- next4.push(yield* refs.resolve(v));
93623
- } else {
93624
- next4.push(v);
93625
- }
93626
- }
93627
- setAt2(out, parsed.segments, next4);
93628
- } else {
93629
- if (typeof current2 === "string" && shouldResolveRef(current2)) {
93630
- setAt2(out, parsed.segments, yield* refs.resolve(current2));
93631
- }
93632
- }
93633
- }
93634
- return out;
93635
- });
93687
+ function readOptionalText4(name) {
93688
+ return text9(name).pipe(optional5, map34(optionToUndefined16));
93636
93689
  }
93637
- var planApplyCommand = exports_Command.make("apply", {
93638
- payload,
93639
- dryRun: boolean8("dry-run"),
93640
- notify: notify5,
93641
- ensureDaemon: ensureDaemon6,
93642
- wait: wait3,
93643
- timeoutMs: timeoutMs3,
93644
- pollMs: pollMs3,
93645
- priority: priority5,
93646
- clientId: clientId5,
93647
- idempotencyKey: idempotencyKey5,
93648
- meta: metaSpec5
93649
- }, ({ payload: payload2, dryRun, notify: notify6, ensureDaemon: ensureDaemon7, wait: wait4, timeoutMs: timeoutMs4, pollMs: pollMs4, priority: priority6, clientId: clientId6, idempotencyKey: idempotencyKey6, meta }) => gen2(function* () {
93650
- if (!wait4 && (timeoutMs4 !== undefined || pollMs4 !== undefined)) {
93651
- return yield* fail8(new CliError({
93652
- code: "INVALID_ARGS",
93653
- message: "Use --wait to enable --timeout-ms/--poll-ms",
93654
- exitCode: 2
93655
- }));
93656
- }
93657
- if (dryRun && wait4) {
93658
- return yield* fail8(new CliError({
93659
- code: "INVALID_ARGS",
93660
- message: "--wait is not compatible with --dry-run",
93661
- exitCode: 2
93662
- }));
93663
- }
93664
- const payloadSvc = yield* Payload;
93665
- const raw4 = yield* payloadSvc.readJson(payload2);
93666
- const normalized = payloadSvc.normalizeKeys(raw4);
93667
- const plan = yield* try_3({
93668
- try: () => parseWritePlanV1(normalized),
93669
- catch: (e) => isCliError(e) ? e : new CliError({
93670
- code: "INVALID_PAYLOAD",
93671
- message: String(e?.message || "Invalid write plan payload"),
93672
- exitCode: 2
93673
- })
93674
- });
93675
- const compiled = yield* try_3({
93676
- try: () => compileWritePlanV1(plan, {
93677
- makeTempId: () => `tmp:${makeUuidLike()}`
93678
- }),
93679
- catch: (e) => isCliError(e) ? e : new CliError({
93680
- code: "INVALID_PAYLOAD",
93681
- message: String(e?.message || "Failed to compile write plan"),
93682
- exitCode: 2
93683
- })
93684
- });
93685
- const resolvedOps = yield* forEach9(compiled.ops, (op) => resolveRefsInPayload({ opType: op.type, payload: op.payload }).pipe(map17((payload3) => ({ ...op, payload: payload3 }))), { concurrency: 1 });
93686
- const normalizedOps = yield* try_3({
93687
- try: () => resolvedOps.map((o) => normalizeOp(o, payloadSvc.normalizeKeys)),
93688
- catch: (e) => isCliError(e) ? e : new CliError({
93689
- code: "INVALID_PAYLOAD",
93690
- message: "Failed to generate ops",
93691
- exitCode: 2,
93692
- details: { error: String(e?.message || e) }
93693
- })
93694
- });
93695
- const metaValue = meta ? yield* payloadSvc.readJson(meta) : undefined;
93696
- const metaForTxn = metaValue && typeof metaValue === "object" ? { ...metaValue, write_plan: { version: 1, alias_map: compiled.alias_map } } : { write_plan: { version: 1, alias_map: compiled.alias_map } };
93697
- if (dryRun) {
93698
- yield* writeSuccess({
93699
- data: {
93700
- dry_run: true,
93701
- op_count: normalizedOps.length,
93702
- alias_map: compiled.alias_map,
93703
- ops: resolvedOps,
93704
- meta: payloadSvc.normalizeKeys(metaForTxn)
93705
- },
93706
- md: [`- dry_run: true`, `- ops: ${normalizedOps.length}`, `- aliases: ${Object.keys(compiled.alias_map).length}`].join(`
93707
- `)
93690
+ var payload = text9("payload");
93691
+ var clientId5 = readOptionalText4("client-id");
93692
+ var idempotencyKey5 = readOptionalText4("idempotency-key");
93693
+ var metaSpec5 = readOptionalText4("meta");
93694
+ var priority5 = integer7("priority").pipe(optional5, map34(optionToUndefined16));
93695
+ var notify5 = boolean8("no-notify").pipe(map34((v) => !v));
93696
+ var ensureDaemon6 = boolean8("no-ensure-daemon").pipe(map34((v) => !v));
93697
+ var wait3 = boolean8("wait");
93698
+ var timeoutMs3 = integer7("timeout-ms").pipe(optional5, map34(optionToUndefined16));
93699
+ var pollMs3 = integer7("poll-ms").pipe(optional5, map34(optionToUndefined16));
93700
+ function makeWritePlanCommand(config3) {
93701
+ return exports_Command.make(config3.commandName, {
93702
+ payload,
93703
+ dryRun: boolean8("dry-run"),
93704
+ notify: notify5,
93705
+ ensureDaemon: ensureDaemon6,
93706
+ wait: wait3,
93707
+ timeoutMs: timeoutMs3,
93708
+ pollMs: pollMs3,
93709
+ priority: priority5,
93710
+ clientId: clientId5,
93711
+ idempotencyKey: idempotencyKey5,
93712
+ meta: metaSpec5
93713
+ }, ({ payload: payload2, dryRun, notify: notify6, ensureDaemon: ensureDaemon7, wait: wait4, timeoutMs: timeoutMs4, pollMs: pollMs4, priority: priority6, clientId: clientId6, idempotencyKey: idempotencyKey6, meta }) => gen2(function* () {
93714
+ if (!wait4 && (timeoutMs4 !== undefined || pollMs4 !== undefined)) {
93715
+ return yield* fail8(new CliError({
93716
+ code: "INVALID_ARGS",
93717
+ message: "Use --wait to enable --timeout-ms/--poll-ms",
93718
+ exitCode: 2
93719
+ }));
93720
+ }
93721
+ if (dryRun && wait4) {
93722
+ return yield* fail8(new CliError({
93723
+ code: "INVALID_ARGS",
93724
+ message: "--wait is not compatible with --dry-run",
93725
+ exitCode: 2
93726
+ }));
93727
+ }
93728
+ const payloadSvc = yield* Payload;
93729
+ const raw4 = yield* payloadSvc.readJson(payload2);
93730
+ const normalized = payloadSvc.normalizeKeys(raw4);
93731
+ const plan = yield* try_3({
93732
+ try: () => parseWritePlanV1(normalized),
93733
+ catch: (e) => isCliError(e) ? e : new CliError({
93734
+ code: "INVALID_PAYLOAD",
93735
+ message: String(e?.message || "Invalid write plan payload"),
93736
+ exitCode: 2
93737
+ })
93708
93738
  });
93709
- return;
93710
- }
93711
- const data = yield* enqueueOps({
93712
- ops: normalizedOps,
93713
- priority: priority6,
93714
- clientId: clientId6,
93715
- idempotencyKey: idempotencyKey6,
93716
- meta: metaForTxn,
93717
- notify: notify6,
93718
- ensureDaemon: ensureDaemon7
93719
- });
93720
- const waited = wait4 ? yield* waitForTxn({ txnId: data.txn_id, timeoutMs: timeoutMs4, pollMs: pollMs4 }) : null;
93721
- const out = waited ? { ...data, ...waited } : data;
93722
- const aliasMapForOutput = data.deduped === true ? yield* gen2(function* () {
93723
- const cfg = yield* AppConfig;
93724
- const queue = yield* Queue;
93725
- const inspected = yield* queue.inspect({ dbPath: cfg.storeDb, txnId: data.txn_id });
93726
- const metaJson = inspected?.txn?.meta_json;
93727
- let stored = undefined;
93728
- if (typeof metaJson === "string" && metaJson.trim()) {
93729
- try {
93730
- const parsedMeta = payloadSvc.normalizeKeys(JSON.parse(metaJson));
93731
- stored = parsedMeta?.write_plan?.alias_map;
93732
- } catch {}
93739
+ const compiled = yield* try_3({
93740
+ try: () => compileWritePlanV1(plan, {
93741
+ makeTempId
93742
+ }),
93743
+ catch: (e) => isCliError(e) ? e : new CliError({
93744
+ code: "INVALID_PAYLOAD",
93745
+ message: String(e?.message || "Failed to compile write plan"),
93746
+ exitCode: 2
93747
+ })
93748
+ });
93749
+ const resolvedOps = yield* forEach9(compiled.ops, (op) => resolveRefsInPayload({ opType: op.type, payload: op.payload }).pipe(map17((payload3) => ({ ...op, payload: payload3 }))), { concurrency: 1 });
93750
+ const normalizedOps = yield* try_3({
93751
+ try: () => resolvedOps.map((o) => normalizeOp(o, payloadSvc.normalizeKeys)),
93752
+ catch: (e) => isCliError(e) ? e : new CliError({
93753
+ code: "INVALID_PAYLOAD",
93754
+ message: "Failed to generate ops",
93755
+ exitCode: 2,
93756
+ details: { error: String(e?.message || e) }
93757
+ })
93758
+ });
93759
+ const metaValue = meta ? yield* payloadSvc.readJson(meta) : undefined;
93760
+ const metaForTxn = metaValue && typeof metaValue === "object" ? { ...metaValue, write_plan: { version: 1, alias_map: compiled.alias_map } } : { write_plan: { version: 1, alias_map: compiled.alias_map } };
93761
+ if (dryRun) {
93762
+ yield* writeSuccess({
93763
+ data: {
93764
+ dry_run: true,
93765
+ op_count: normalizedOps.length,
93766
+ alias_map: compiled.alias_map,
93767
+ ops: resolvedOps,
93768
+ meta: payloadSvc.normalizeKeys(metaForTxn)
93769
+ },
93770
+ md: [`- dry_run: true`, `- ops: ${normalizedOps.length}`, `- aliases: ${Object.keys(compiled.alias_map).length}`].join(`
93771
+ `)
93772
+ });
93773
+ return;
93733
93774
  }
93734
- return stored && typeof stored === "object" ? stored : compiled.alias_map;
93735
- }).pipe(catchAll2(() => succeed8(compiled.alias_map))) : compiled.alias_map;
93736
- yield* writeSuccess({
93737
- data: {
93775
+ const data = yield* enqueueOps({
93776
+ ops: normalizedOps,
93777
+ priority: priority6,
93778
+ clientId: clientId6,
93779
+ idempotencyKey: idempotencyKey6,
93780
+ meta: metaForTxn,
93781
+ notify: notify6,
93782
+ ensureDaemon: ensureDaemon7
93783
+ });
93784
+ const waited = wait4 ? yield* waitForTxn({ txnId: data.txn_id, timeoutMs: timeoutMs4, pollMs: pollMs4 }) : null;
93785
+ const out = waited ? { ...data, ...waited } : data;
93786
+ const aliasMapForOutput = data.deduped === true ? yield* gen2(function* () {
93787
+ const cfg = yield* AppConfig;
93788
+ const queue = yield* Queue;
93789
+ const inspected = yield* queue.inspect({ dbPath: cfg.storeDb, txnId: data.txn_id });
93790
+ const metaJson = inspected?.txn?.meta_json;
93791
+ let stored = undefined;
93792
+ if (typeof metaJson === "string" && metaJson.trim()) {
93793
+ try {
93794
+ const parsedMeta = payloadSvc.normalizeKeys(JSON.parse(metaJson));
93795
+ stored = parsedMeta?.write_plan?.alias_map;
93796
+ } catch {}
93797
+ }
93798
+ return stored && typeof stored === "object" ? stored : compiled.alias_map;
93799
+ }).pipe(catchAll2(() => succeed8(compiled.alias_map))) : compiled.alias_map;
93800
+ const successData = {
93738
93801
  ...out,
93739
93802
  alias_map: aliasMapForOutput
93740
- },
93741
- ids: [data.txn_id, ...data.op_ids],
93742
- md: [
93743
- `- txn_id: ${data.txn_id}`,
93744
- `- op_ids: ${data.op_ids.length}`,
93745
- `- notified: ${data.notified}`,
93746
- `- sent: ${data.sent ?? ""}`,
93747
- `- aliases: ${Object.keys(aliasMapForOutput).length}`,
93748
- ...waited ? [`- status: ${waited.status}`, `- elapsed_ms: ${waited.elapsed_ms}`] : []
93749
- ].join(`
93803
+ };
93804
+ if (config3.includeOpCountInSuccessData) {
93805
+ successData.op_count = normalizedOps.length;
93806
+ }
93807
+ const mdLines = [`- txn_id: ${data.txn_id}`, `- op_ids: ${data.op_ids.length}`];
93808
+ if (config3.aliasesBeforeNotifyInMd) {
93809
+ mdLines.push(`- aliases: ${Object.keys(aliasMapForOutput).length}`);
93810
+ }
93811
+ mdLines.push(`- notified: ${data.notified}`);
93812
+ mdLines.push(`- sent: ${data.sent ?? ""}`);
93813
+ if (!config3.aliasesBeforeNotifyInMd) {
93814
+ mdLines.push(`- aliases: ${Object.keys(aliasMapForOutput).length}`);
93815
+ }
93816
+ if (waited) {
93817
+ mdLines.push(`- status: ${waited.status}`);
93818
+ mdLines.push(`- elapsed_ms: ${waited.elapsed_ms}`);
93819
+ }
93820
+ yield* writeSuccess({
93821
+ data: successData,
93822
+ ids: [data.txn_id, ...data.op_ids],
93823
+ md: mdLines.join(`
93750
93824
  `)
93751
- });
93752
- }).pipe(catchAll2(writeFailure)));
93825
+ });
93826
+ }).pipe(catchAll2(writeFailure)));
93827
+ }
93828
+
93829
+ // src/commands/plan/apply.ts
93830
+ var planApplyCommand = makeWritePlanCommand({
93831
+ commandName: "apply",
93832
+ includeOpCountInSuccessData: false,
93833
+ aliasesBeforeNotifyInMd: false
93834
+ });
93753
93835
 
93754
93836
  // src/commands/plan/index.ts
93755
93837
  var planCommand = exports_Command.make("plan", {}).pipe(exports_Command.withSubcommands([planApplyCommand]));
@@ -95753,12 +95835,6 @@ var writePowerupPropertyCommand = exports_Command.make("property", {}).pipe(expo
95753
95835
 
95754
95836
  // src/commands/write/powerup/record/add.ts
95755
95837
  var dispatchMode2 = choice5("dispatch-mode", ["serial", "conflict_parallel"]).pipe(optional5, map34(optionToUndefined27));
95756
- function makeUuidLike2() {
95757
- const g = globalThis;
95758
- if (g.crypto && typeof g.crypto.randomUUID === "function")
95759
- return String(g.crypto.randomUUID());
95760
- return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;
95761
- }
95762
95838
  var writePowerupRecordAddCommand = exports_Command.make("add", {
95763
95839
  tagId: text9("tag-id").pipe(optional5, map34(optionToUndefined27)),
95764
95840
  powerup: text9("powerup").pipe(optional5, map34(optionToUndefined27)),
@@ -95840,7 +95916,7 @@ var writePowerupRecordAddCommand = exports_Command.make("add", {
95840
95916
  const tableTagId = resolved ? resolved.id : normalizeRemIdInput(tagId);
95841
95917
  const resolvedRef = ref3 ?? "daily:today";
95842
95918
  const parentId = typeof parent3 === "string" ? parent3 : dryRun ? resolvedRef : yield* refs.resolve(resolvedRef);
95843
- const rowClientTempId = `tmp:${makeUuidLike2()}`;
95919
+ const rowClientTempId = makeTempId();
95844
95920
  const rawValues = values5 ? yield* payloadSvc.readJson(values5) : undefined;
95845
95921
  const parsedValues = rawValues !== undefined ? yield* try_3({
95846
95922
  try: () => parseValuesArrayOnly(payloadSvc.normalizeKeys(rawValues)),
@@ -97012,12 +97088,6 @@ var readResolveRefCommand = exports_Command.make("resolve-ref", {
97012
97088
  }).pipe(catchAll2(writeFailure)));
97013
97089
 
97014
97090
  // src/commands/write/rem/create.ts
97015
- function makeUuidLike3() {
97016
- const g = globalThis;
97017
- if (g.crypto && typeof g.crypto.randomUUID === "function")
97018
- return String(g.crypto.randomUUID());
97019
- return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;
97020
- }
97021
97091
  function normalizeRemIdInput2(raw4) {
97022
97092
  const trimmed2 = raw4.trim();
97023
97093
  const link3 = tryParseRemnoteLink(trimmed2);
@@ -97105,7 +97175,7 @@ var writeRemCreateCommand = exports_Command.make("create", {
97105
97175
  const resolvedRef = ref5 ?? "";
97106
97176
  const parentId = typeof parent3 === "string" ? normalizeRemIdInput2(parent3) : dryRun ? normalizeRemIdInput2(resolvedRef) : yield* refs.resolve(resolvedRef);
97107
97177
  const tags2 = Array.isArray(tag9) ? tag9.map(normalizeRemIdInput2).filter(Boolean) : [];
97108
- const remClientTempId = clientTempId ? String(clientTempId).trim() : `tmp:${makeUuidLike3()}`;
97178
+ const remClientTempId = clientTempId ? String(clientTempId).trim() : makeTempId();
97109
97179
  const textValue = text16 !== undefined ? trimBoundaryBlankLines(text16) : undefined;
97110
97180
  const payload3 = {
97111
97181
  parentId,
@@ -97541,7 +97611,7 @@ function normalizeRemIdInput5(raw4) {
97541
97611
  return link3.remId;
97542
97612
  return trimmed2;
97543
97613
  }
97544
- var writeRemTextCommand = exports_Command.make("text", {
97614
+ var writeRemSetTextCommand = exports_Command.make("set-text", {
97545
97615
  rem: text9("rem"),
97546
97616
  text: text9("text"),
97547
97617
  notify: writeCommonOptions.notify,
@@ -97621,7 +97691,7 @@ var writeRemTextCommand = exports_Command.make("text", {
97621
97691
  var remCommand = exports_Command.make("rem", {}).pipe(exports_Command.withSubcommands([
97622
97692
  writeRemCreateCommand,
97623
97693
  writeRemMoveCommand,
97624
- writeRemTextCommand,
97694
+ writeRemSetTextCommand,
97625
97695
  writeRemTagCommand,
97626
97696
  writeRemDeleteCommand,
97627
97697
  readInspectCommand,
@@ -97772,7 +97842,7 @@ var ensureDaemon8 = boolean8("no-ensure-daemon").pipe(map34((v) => !v));
97772
97842
  var wait4 = boolean8("wait");
97773
97843
  var timeoutMs5 = integer7("timeout-ms").pipe(optional5, map34(optionToUndefined37));
97774
97844
  var pollMs4 = integer7("poll-ms").pipe(optional5, map34(optionToUndefined37));
97775
- var replaceBlockCommand = exports_Command.make("block", {
97845
+ var replaceMarkdownCommand = exports_Command.make("markdown", {
97776
97846
  selection,
97777
97847
  stateFile: stateFile10,
97778
97848
  staleMs: staleMs9,
@@ -97856,7 +97926,7 @@ var replaceBlockCommand = exports_Command.make("block", {
97856
97926
  if (scopeValue !== "roots") {
97857
97927
  return yield* fail8(new CliError({
97858
97928
  code: "INVALID_ARGS",
97859
- message: "replace block does not support --scope subtree (block-level replace deletes roots and recursively deletes their subtrees)",
97929
+ message: "replace markdown does not support --scope subtree (block-level replace deletes roots and recursively deletes their subtrees)",
97860
97930
  exitCode: 2
97861
97931
  }));
97862
97932
  }
@@ -98013,7 +98083,7 @@ function replaceRichText(value8, replacer) {
98013
98083
  }
98014
98084
  return { value: value8, changed: false };
98015
98085
  }
98016
- var replaceTextCommand = exports_Command.make("text", {
98086
+ var replaceLiteralCommand = exports_Command.make("literal", {
98017
98087
  selection: selection2,
98018
98088
  stateFile: stateFile11,
98019
98089
  staleMs: staleMs10,
@@ -98211,7 +98281,7 @@ var replaceTextCommand = exports_Command.make("text", {
98211
98281
  }).pipe(catchAll2(writeFailure)));
98212
98282
 
98213
98283
  // src/commands/write/replace/index.ts
98214
- var writeReplaceCommand = exports_Command.make("replace", {}).pipe(exports_Command.withSubcommands([replaceBlockCommand, replaceTextCommand]));
98284
+ var writeReplaceCommand = exports_Command.make("replace", {}).pipe(exports_Command.withSubcommands([replaceMarkdownCommand, replaceLiteralCommand]));
98215
98285
 
98216
98286
  // src/commands/replace/index.ts
98217
98287
  var replaceCommand = writeReplaceCommand;
@@ -98278,12 +98348,6 @@ var readSearchCommand = exports_Command.make("search", {
98278
98348
  var searchCommand = readSearchCommand;
98279
98349
 
98280
98350
  // src/commands/write/table/create.ts
98281
- function makeUuidLike4() {
98282
- const g = globalThis;
98283
- if (g.crypto && typeof g.crypto.randomUUID === "function")
98284
- return String(g.crypto.randomUUID());
98285
- return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;
98286
- }
98287
98351
  function normalizeRemIdInput6(raw4) {
98288
98352
  const trimmed2 = raw4.trim();
98289
98353
  const link3 = tryParseRemnoteLink(trimmed2);
@@ -98373,7 +98437,7 @@ var writeTableCreateCommand = exports_Command.make("create", {
98373
98437
  }
98374
98438
  const resolvedRef = ref7 ?? "";
98375
98439
  const parentId2 = typeof parent3 === "string" ? normalizeRemIdInput6(parent3) : dryRun ? resolvedRef : yield* refs.resolve(resolvedRef);
98376
- const tableClientTempId = clientTempId ? String(clientTempId).trim() : `tmp:${makeUuidLike4()}`;
98440
+ const tableClientTempId = clientTempId ? String(clientTempId).trim() : makeTempId();
98377
98441
  const op2 = yield* try_3({
98378
98442
  try: () => normalizeOp({
98379
98443
  type: "create_table",
@@ -98768,12 +98832,6 @@ var writeTablePropertySetTypeCommand = exports_Command.make("set-type", {
98768
98832
  var writeTablePropertyCommand = exports_Command.make("property", {}).pipe(exports_Command.withSubcommands([writeTablePropertyAddCommand, writeTablePropertySetTypeCommand]));
98769
98833
 
98770
98834
  // src/commands/write/table/record/add.ts
98771
- function makeUuidLike5() {
98772
- const g = globalThis;
98773
- if (g.crypto && typeof g.crypto.randomUUID === "function")
98774
- return String(g.crypto.randomUUID());
98775
- return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;
98776
- }
98777
98835
  var writeTableRecordAddCommand = exports_Command.make("add", {
98778
98836
  tableTag: text9("table-tag"),
98779
98837
  parent: text9("parent").pipe(optional5, map34(optionToUndefined27)),
@@ -98839,7 +98897,7 @@ var writeTableRecordAddCommand = exports_Command.make("add", {
98839
98897
  details: e.details,
98840
98898
  hint: e.hint
98841
98899
  }))));
98842
- const rowClientTempId = `tmp:${makeUuidLike5()}`;
98900
+ const rowClientTempId = makeTempId();
98843
98901
  const rawValues = values5 ? yield* payloadSvc.readJson(values5) : undefined;
98844
98902
  const parsedValues = rawValues !== undefined ? yield* try_3({
98845
98903
  try: () => parseValuesArrayOnly(payloadSvc.normalizeKeys(rawValues)),
@@ -99904,12 +99962,6 @@ var readTopicCommand = exports_Command.make("topic", {}).pipe(exports_Command.wi
99904
99962
  var topicCommand = readTopicCommand;
99905
99963
 
99906
99964
  // src/commands/write/portal/create.ts
99907
- function makeUuidLike6() {
99908
- const g = globalThis;
99909
- if (g.crypto && typeof g.crypto.randomUUID === "function")
99910
- return String(g.crypto.randomUUID());
99911
- return `${Date.now().toString(16)}-${Math.random().toString(16).slice(2)}-${Math.random().toString(16).slice(2)}`;
99912
- }
99913
99965
  function normalizeRemIdInput7(raw4) {
99914
99966
  const trimmed2 = raw4.trim();
99915
99967
  const link3 = tryParseRemnoteLink(trimmed2);
@@ -100003,7 +100055,7 @@ var writePortalCreateCommand = exports_Command.make("create", {
100003
100055
  exitCode: 2
100004
100056
  }));
100005
100057
  }
100006
- const portalClientTempId = clientTempId ? String(clientTempId).trim() : `tmp:${makeUuidLike6()}`;
100058
+ const portalClientTempId = clientTempId ? String(clientTempId).trim() : makeTempId();
100007
100059
  const op2 = yield* try_3({
100008
100060
  try: () => normalizeOp({
100009
100061
  type: "create_portal",