@wirecat/cli-memo 0.131.68 → 0.131.70

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 (72) hide show
  1. package/dist/bin/memo.js +2 -2
  2. package/dist/bundle/{app-server-PGZD3JUW.js → app-server-UP3AL2XQ.js} +10 -10
  3. package/dist/bundle/{auto-OVLXIZRU.js → auto-CVILDIC6.js} +17 -17
  4. package/dist/bundle/{chunk-JQREFZWM.js → chunk-2NFI7SDW.js} +5 -0
  5. package/dist/bundle/{chunk-EEBQN7TK.js → chunk-3OEV7GNU.js} +4 -4
  6. package/dist/bundle/{chunk-V6QYWGO4.js → chunk-3TFK7RBA.js} +3 -3
  7. package/dist/bundle/{chunk-5JPVRS7W.js → chunk-52F4LHCH.js} +3 -3
  8. package/dist/bundle/{chunk-KX7CVSAY.js → chunk-57SQU2YO.js} +4 -4
  9. package/dist/bundle/{chunk-FOF7KGG3.js → chunk-5EHUHZU5.js} +5 -5
  10. package/dist/bundle/{chunk-YVVRV3PQ.js → chunk-7OXLZZ27.js} +31 -1
  11. package/dist/bundle/{chunk-FSDAEZFS.js → chunk-EQKS6M52.js} +3 -3
  12. package/dist/bundle/{chunk-5EB34LNI.js → chunk-FQ54GW57.js} +8 -8
  13. package/dist/bundle/{chunk-FYWGFRR2.js → chunk-GGFL64HF.js} +1 -1
  14. package/dist/bundle/{chunk-5RYMHX2O.js → chunk-GVEY6743.js} +2 -2
  15. package/dist/bundle/{chunk-6A6HR2CS.js → chunk-GVP6CAPH.js} +3 -3
  16. package/dist/bundle/{chunk-4AH6FONF.js → chunk-IJAILIZR.js} +4 -4
  17. package/dist/bundle/{chunk-PUACXS7G.js → chunk-JMGQATR6.js} +1 -1
  18. package/dist/bundle/{chunk-BQYAMBKB.js → chunk-LYAJUZM4.js} +6 -6
  19. package/dist/bundle/{chunk-37H7TTWN.js → chunk-MYLNRBDF.js} +2 -2
  20. package/dist/bundle/{chunk-A3WUEOEV.js → chunk-OAO5UCPJ.js} +1 -1
  21. package/dist/bundle/{chunk-EOJPZ3LX.js → chunk-OHA7HDPX.js} +15 -15
  22. package/dist/bundle/{chunk-RG4GW7EY.js → chunk-QAXIZHK7.js} +9 -9
  23. package/dist/bundle/{chunk-WLD5XU3T.js → chunk-UEMI6FXR.js} +2 -2
  24. package/dist/bundle/{chunk-QHUPSOQT.js → chunk-XTEJXJJ3.js} +3 -3
  25. package/dist/bundle/{chunk-5EZOMIPL.js → chunk-YBTUFOQG.js} +4 -4
  26. package/dist/bundle/{chunk-AJMAR5DC.js → chunk-YXXAPVAZ.js} +4 -4
  27. package/dist/bundle/{command-contract-RX6RWHCT.js → command-contract-OGW2DX4C.js} +3 -3
  28. package/dist/bundle/{entry-XHWG43NW.js → entry-7S2ONYSF.js} +1 -1
  29. package/dist/bundle/{failure-Z7WOYPMA.js → failure-HM55W3NH.js} +15 -15
  30. package/dist/bundle/{first-run-FQ2BAEYK.js → first-run-MLIFZSVH.js} +1 -1
  31. package/dist/bundle/{first-screen-GP2QGKUA.js → first-screen-DGTTK6VK.js} +4 -4
  32. package/dist/bundle/{mcp-USR3ZFQU.js → mcp-CFIL7WZU.js} +7 -7
  33. package/dist/bundle/memo.js +6 -6
  34. package/dist/bundle/{program-FVSSLRBJ.js → program-RSUVU6HA.js} +250 -114
  35. package/dist/bundle/{server-YRZDZ2PZ.js → server-AASCSGCI.js} +10 -10
  36. package/dist/bundle/{server-3FW2MQRQ.js → server-BVRPQPGY.js} +20 -20
  37. package/dist/bundle/{server-SWSWXNDP.js → server-YQLPZK4Z.js} +7 -7
  38. package/dist/bundle/{store-PIQ4TF4O.js → store-VQQVUA4W.js} +2 -2
  39. package/dist/bundle/{store-maintenance-command-EWEXJ253.js → store-maintenance-command-GCBABKEZ.js} +6 -6
  40. package/dist/bundle/{update-6QYRXRVJ.js → update-ZE53ASCW.js} +16 -16
  41. package/dist/contract-overrides/skill.d.ts.map +1 -1
  42. package/dist/contract-overrides/skill.js +5 -10
  43. package/dist/contract-overrides/skill.js.map +1 -1
  44. package/dist/digest/backfill.d.ts.map +1 -1
  45. package/dist/digest/backfill.js +4 -2
  46. package/dist/digest/backfill.js.map +1 -1
  47. package/dist/digest/brief.d.ts +14 -0
  48. package/dist/digest/brief.d.ts.map +1 -0
  49. package/dist/digest/brief.js +143 -0
  50. package/dist/digest/brief.js.map +1 -0
  51. package/dist/examples.d.ts.map +1 -1
  52. package/dist/examples.js +10 -1
  53. package/dist/examples.js.map +1 -1
  54. package/dist/knowledge/command.d.ts.map +1 -1
  55. package/dist/knowledge/command.js +17 -6
  56. package/dist/knowledge/command.js.map +1 -1
  57. package/dist/knowledge/project-context.d.ts.map +1 -1
  58. package/dist/knowledge/project-context.js +3 -2
  59. package/dist/knowledge/project-context.js.map +1 -1
  60. package/dist/knowledge/relationships.d.ts.map +1 -1
  61. package/dist/knowledge/relationships.js +11 -2
  62. package/dist/knowledge/relationships.js.map +1 -1
  63. package/dist/program.d.ts.map +1 -1
  64. package/dist/program.js +16 -8
  65. package/dist/program.js.map +1 -1
  66. package/dist/reasons.d.ts.map +1 -1
  67. package/dist/reasons.js +30 -0
  68. package/dist/reasons.js.map +1 -1
  69. package/dist/version.d.ts +1 -1
  70. package/dist/version.js +1 -1
  71. package/package.json +2 -2
  72. package/skills/cli-memo/topics/projects.md +7 -0
@@ -6,17 +6,17 @@ import {
6
6
  autoState,
7
7
  lastAutoRun,
8
8
  recordAutoRun
9
- } from "./chunk-EEBQN7TK.js";
9
+ } from "./chunk-3OEV7GNU.js";
10
10
  import {
11
11
  installer,
12
12
  latest,
13
13
  upgradeCommand
14
- } from "./chunk-5EZOMIPL.js";
14
+ } from "./chunk-YBTUFOQG.js";
15
15
  import {
16
16
  mcpOwnerAllowed,
17
17
  readOnlyAvailability,
18
18
  refuseWritesUnderLock
19
- } from "./chunk-FSDAEZFS.js";
19
+ } from "./chunk-EQKS6M52.js";
20
20
  import {
21
21
  answers,
22
22
  atDetail,
@@ -27,7 +27,7 @@ import {
27
27
  trackAnswers,
28
28
  wholeList,
29
29
  withStore
30
- } from "./chunk-KX7CVSAY.js";
30
+ } from "./chunk-57SQU2YO.js";
31
31
  import {
32
32
  ATTACHMENT_CHARS,
33
33
  DIALECTS,
@@ -59,7 +59,7 @@ import {
59
59
  showMail,
60
60
  unsetConfigKey,
61
61
  updateConfig
62
- } from "./chunk-5EB34LNI.js";
62
+ } from "./chunk-FQ54GW57.js";
63
63
  import "./chunk-QP3KNC5D.js";
64
64
  import "./chunk-TXOXPQN2.js";
65
65
  import "./chunk-EO4JMJFZ.js";
@@ -67,7 +67,7 @@ import "./chunk-MWQI6FSU.js";
67
67
  import {
68
68
  errorObject,
69
69
  recognisable
70
- } from "./chunk-5JPVRS7W.js";
70
+ } from "./chunk-52F4LHCH.js";
71
71
  import {
72
72
  AGENT_INPUT_MAX_CHARS,
73
73
  DISCOVERY_DESCRIPTIONS,
@@ -112,7 +112,7 @@ import {
112
112
  tasksStatsCommand,
113
113
  templatesCommand,
114
114
  withSqliteSidecars
115
- } from "./chunk-EOJPZ3LX.js";
115
+ } from "./chunk-OHA7HDPX.js";
116
116
  import "./chunk-7JFLHRQL.js";
117
117
  import "./chunk-RHW3DDWI.js";
118
118
  import {
@@ -121,7 +121,7 @@ import {
121
121
  messageHitItem,
122
122
  noteHitItem,
123
123
  shownOf
124
- } from "./chunk-BQYAMBKB.js";
124
+ } from "./chunk-LYAJUZM4.js";
125
125
  import "./chunk-OBQ7TSUB.js";
126
126
  import {
127
127
  REASONS as REASONS2,
@@ -129,15 +129,15 @@ import {
129
129
  skillCommand,
130
130
  skillPath,
131
131
  skillVersion
132
- } from "./chunk-37H7TTWN.js";
132
+ } from "./chunk-MYLNRBDF.js";
133
133
  import {
134
134
  recoveryNotes,
135
135
  storeInfo,
136
136
  storeRecoveryCheck,
137
137
  storeRecoveryRun,
138
138
  storeSummary
139
- } from "./chunk-FOF7KGG3.js";
140
- import "./chunk-6A6HR2CS.js";
139
+ } from "./chunk-5EHUHZU5.js";
140
+ import "./chunk-GVP6CAPH.js";
141
141
  import {
142
142
  LIST_QUERY_GUIDE,
143
143
  STATUS_SIGNALS,
@@ -197,7 +197,7 @@ import {
197
197
  timeLimit,
198
198
  typedQuery,
199
199
  withQuery
200
- } from "./chunk-V6QYWGO4.js";
200
+ } from "./chunk-3TFK7RBA.js";
201
201
  import {
202
202
  readBoundedUtf8File,
203
203
  writeFileAtomic
@@ -206,9 +206,9 @@ import {
206
206
  commandsText,
207
207
  inSection,
208
208
  installHelp
209
- } from "./chunk-WLD5XU3T.js";
209
+ } from "./chunk-UEMI6FXR.js";
210
210
  import "./chunk-HTQTIKWP.js";
211
- import "./chunk-PUACXS7G.js";
211
+ import "./chunk-JMGQATR6.js";
212
212
  import {
213
213
  Command,
214
214
  DEFAULT_TEXT_MODEL,
@@ -245,15 +245,15 @@ import {
245
245
  snakeKeys,
246
246
  textModels,
247
247
  textModelsFile
248
- } from "./chunk-A3WUEOEV.js";
248
+ } from "./chunk-OAO5UCPJ.js";
249
249
  import "./chunk-N73YBQ42.js";
250
- import "./chunk-QHUPSOQT.js";
250
+ import "./chunk-XTEJXJJ3.js";
251
251
  import {
252
252
  isNewer
253
253
  } from "./chunk-LJCT7YG6.js";
254
254
  import "./chunk-L62FWN3Y.js";
255
255
  import "./chunk-EDPA54WQ.js";
256
- import "./chunk-5RYMHX2O.js";
256
+ import "./chunk-GVEY6743.js";
257
257
  import "./chunk-2DQYP2K3.js";
258
258
  import "./chunk-22CDLXSR.js";
259
259
  import {
@@ -303,7 +303,7 @@ import {
303
303
  plainQuery,
304
304
  providerNamed,
305
305
  refLabel
306
- } from "./chunk-FYWGFRR2.js";
306
+ } from "./chunk-GGFL64HF.js";
307
307
  import {
308
308
  CATALOG_KINDS,
309
309
  CONTRACT_KINDS,
@@ -311,6 +311,7 @@ import {
311
311
  DEAL_KINDS,
312
312
  DEAL_ROLES,
313
313
  DEAL_STATUSES,
314
+ ENGAGEMENT_LEVELS,
314
315
  FACT_STATUSES,
315
316
  FACT_TYPES,
316
317
  FINANCE_REVIEWS,
@@ -331,6 +332,7 @@ import {
331
332
  TRANSACTION_STATUSES,
332
333
  WALLET_KINDS,
333
334
  WORK_TASK_TYPES,
335
+ byEngagement,
334
336
  createUpcomingMeetingReader,
335
337
  dateRange,
336
338
  dayBoundary,
@@ -352,7 +354,7 @@ import {
352
354
  timezoneOf,
353
355
  validateQuery,
354
356
  walkQuery
355
- } from "./chunk-JQREFZWM.js";
357
+ } from "./chunk-2NFI7SDW.js";
356
358
  import "./chunk-3LGLKLBA.js";
357
359
  import "./chunk-TV75OHKJ.js";
358
360
  import "./chunk-BGWPKEKK.js";
@@ -376,7 +378,7 @@ import {
376
378
  REASONS,
377
379
  STORE_CLIENT,
378
380
  VERSION
379
- } from "./chunk-YVVRV3PQ.js";
381
+ } from "./chunk-7OXLZZ27.js";
380
382
  import "./chunk-DSU6UR2X.js";
381
383
  import "./chunk-SYWHHQMC.js";
382
384
  import "./chunk-D72URWJE.js";
@@ -4346,7 +4348,8 @@ var search = [
4346
4348
  ];
4347
4349
 
4348
4350
  // dist/contract-overrides/skill.js
4349
- var REASON2 = "Memo installs its own stored-data instructions through its environment, prints the packaged primary skill without filesystem effects, and takes --json on each skill command because it has no global one.";
4351
+ var REASON2 = "Memo installs its own stored-data instructions through its environment, prints the packaged skills (morning-digest with the owner's brief from the store after it), and takes --json on each skill command because it has no global one.";
4352
+ var SHOW_DESCRIPTION = "print SKILL.md \u2014 `memo skill install` puts it where Claude Code, Codex, Gemini CLI and OpenClaw look for it, and where Hermes does on request; --for prints the copy already there";
4350
4353
  var JSON_OPTION2 = { flags: "--json", description: "print JSON", takes_value: false, mandatory: false };
4351
4354
  var SHOW_FOR = {
4352
4355
  flags: "--for <agents>",
@@ -4366,15 +4369,9 @@ var INSTALL_FOR = {
4366
4369
  var skill = [
4367
4370
  {
4368
4371
  command: ["skill", "show"],
4369
- field: "effects",
4370
- before: {
4371
- remote: "none",
4372
- local: "read"
4373
- },
4374
- after: {
4375
- remote: "none",
4376
- local: "none"
4377
- },
4372
+ field: "description",
4373
+ before: SHOW_DESCRIPTION,
4374
+ after: `${SHOW_DESCRIPTION}; morning-digest ends with your brief from \`memo digest brief\` when you wrote one`,
4378
4375
  reason: REASON2
4379
4376
  },
4380
4377
  {
@@ -4432,12 +4429,122 @@ var skill = [
4432
4429
  var SHELL_OVERRIDES = { search, doctor, skill, mcp, commands, notes, meetings };
4433
4430
 
4434
4431
  // dist/digest/backfill.js
4435
- import { existsSync as existsSync6, readdirSync as readdirSync4 } from "node:fs";
4436
- import { join as join6 } from "node:path";
4432
+ import { existsSync as existsSync7, readdirSync as readdirSync4 } from "node:fs";
4433
+ import { join as join7 } from "node:path";
4434
+
4435
+ // dist/digest/brief.js
4436
+ import { spawnSync } from "node:child_process";
4437
+ import { existsSync as existsSync3, mkdtempSync, readFileSync as readFileSync4, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
4438
+ import { tmpdir } from "node:os";
4439
+ import { join as join3 } from "node:path";
4440
+ var BRIEF = { key: "digest/brief", channel: "text", language: "any" };
4441
+ var BRIEF_LIMIT = 4e3;
4442
+ var readBrief = /* @__PURE__ */ __name(async (env) => {
4443
+ if (!existsSync3(storePath(env)))
4444
+ return void 0;
4445
+ return withStore(env, async (store) => store.templates.get(BRIEF)?.body);
4446
+ }, "readBrief");
4447
+ var withBrief = /* @__PURE__ */ __name((skill2, brief) => brief === void 0 ? skill2 : `${skill2}
4448
+
4449
+ ## The owner's brief
4450
+
4451
+ The owner wrote this himself: it adds to everything above, and where it contradicts a rule of this skill, the brief wins.
4452
+
4453
+ ${brief.trim()}`, "withBrief");
4454
+ var systemEditor = /* @__PURE__ */ __name((path, env) => {
4455
+ const editor = env.VISUAL?.trim() || env.EDITOR?.trim();
4456
+ if (!editor)
4457
+ throw new CliError("validation_error", "set VISUAL or EDITOR, or pass the brief with --file", {
4458
+ reason: "brief.no-editor"
4459
+ });
4460
+ const [program = editor, ...args] = editor.split(/\s+/);
4461
+ const ran = spawnSync(program, [...args, path], { stdio: "inherit", env });
4462
+ if (ran.status !== 0)
4463
+ throw new CliError("validation_error", `the editor exited with ${ran.status ?? ran.signal}; nothing was saved`);
4464
+ }, "systemEditor");
4465
+ var refuseAgent = /* @__PURE__ */ __name((env) => {
4466
+ if (authorOf(env) !== "owner")
4467
+ throw new CliError("permission_error", "only the owner changes the digest brief, not an agent", {
4468
+ reason: "brief.owner-only"
4469
+ });
4470
+ }, "refuseAgent");
4471
+ var historyOf = /* @__PURE__ */ __name((store) => store.templates.history(BRIEF).map((entry) => ({
4472
+ saved_at: new Date(entry.savedAt).toISOString(),
4473
+ saved_by: entry.savedBy,
4474
+ replaced_at: new Date(entry.replacedAt).toISOString(),
4475
+ chars: entry.body.length
4476
+ })), "historyOf");
4477
+ var briefCommand = /* @__PURE__ */ __name((digest, print, env, editor = systemEditor) => {
4478
+ const brief = annotate(new Command("brief"), { effects: LOCAL_READ }).summary("your own instructions on what the morning digest collects").description(`your own instructions on what the morning digest collects: projects, people, topics, what to skip, how many items. The morning-digest skill ends with them, and where they contradict its rules they win; the run stays read only, with memo as its only tool and the schedule's cost cap. At most ${BRIEF_LIMIT} characters`);
4479
+ digest.addCommand(brief);
4480
+ annotate(brief.command("show"), { effects: LOCAL_READ }).summary("the brief the morning digest follows, and the bodies your changes replaced").option("--json", "print JSON").action(async (given2) => {
4481
+ const item = existsSync3(storePath(env)) ? await withStore(env, async (store) => {
4482
+ const row = store.templates.get(BRIEF);
4483
+ return {
4484
+ body: row?.body ?? null,
4485
+ chars: row?.body.length ?? 0,
4486
+ limit: BRIEF_LIMIT,
4487
+ updated_at: row ? new Date(row.updatedAt).toISOString() : null,
4488
+ updated_by: row?.updatedBy ?? null,
4489
+ history: historyOf(store)
4490
+ };
4491
+ }) : { body: null, chars: 0, limit: BRIEF_LIMIT, updated_at: null, updated_by: null, history: [] };
4492
+ print(given2.json, itemAnswer(item), item.body ?? "No brief: the morning digest follows its skill alone. `memo digest brief edit` writes one.");
4493
+ });
4494
+ grantsAuthority(annotate(brief.command("edit"), { effects: LOCAL_WRITE })).summary("write the brief in $EDITOR or from --file; only you, never an agent").description(`write the brief in $EDITOR, or from --file; at most ${BRIEF_LIMIT} characters. The body it replaces is kept, and --undo puts it back. Only you change it, never an agent or a read-only run`).option("--file <file>", "take the brief from this file instead of opening an editor; - reads stdin").addOption(new Option("--undo", "put back the body your last change replaced").conflicts("file")).option("--json", "print JSON").action(async (given2) => {
4495
+ refuseAgent(env);
4496
+ const { current, previous } = await withStore(env, async (store) => ({
4497
+ current: store.templates.get(BRIEF)?.body,
4498
+ previous: store.templates.history(BRIEF, 1)[0]?.body
4499
+ }));
4500
+ let draft;
4501
+ let body;
4502
+ if (given2.undo) {
4503
+ if (previous === void 0)
4504
+ throw new CliError("validation_error", "the brief has no earlier body to put back", {
4505
+ reason: "brief.no-history"
4506
+ });
4507
+ body = previous;
4508
+ } else if (given2.file !== void 0) {
4509
+ body = readFileSync4(given2.file === "-" ? 0 : given2.file, "utf8");
4510
+ } else {
4511
+ draft = join3(mkdtempSync(join3(tmpdir(), "memo-brief-")), "brief.md");
4512
+ writeFileSync3(draft, current ?? "", { mode: 384 });
4513
+ editor(draft, env);
4514
+ body = readFileSync4(draft, "utf8");
4515
+ }
4516
+ const kept = draft ? `. Your text is in ${draft}; fix it and run again with --file ${draft}` : "";
4517
+ body = body.trim();
4518
+ if (!body)
4519
+ throw new CliError("validation_error", `the brief is empty; memo digest brief reset removes it${kept}`, {
4520
+ reason: "brief.empty"
4521
+ });
4522
+ if (body.length > BRIEF_LIMIT)
4523
+ throw new CliError("validation_error", `the brief is ${body.length} characters; the limit is ${BRIEF_LIMIT}, because every morning run reads it and pays for it. Nothing was saved${kept}`, { reason: "brief.too-long", chars: body.length, limit: BRIEF_LIMIT });
4524
+ if (draft)
4525
+ rmSync2(join3(draft, ".."), { recursive: true, force: true });
4526
+ if (body === current) {
4527
+ print(given2.json, itemAnswer({ changed: false, chars: body.length }), "The brief is unchanged; nothing saved.");
4528
+ return;
4529
+ }
4530
+ const saved = await withStore(env, async (store) => store.templates.save(BRIEF, body, "memo"));
4531
+ print(given2.json, itemAnswer({
4532
+ changed: true,
4533
+ chars: body.length,
4534
+ limit: BRIEF_LIMIT,
4535
+ updated_at: new Date(saved.updatedAt).toISOString()
4536
+ }), `Saved the brief (${body.length} of ${BRIEF_LIMIT} characters); the next morning digest follows it.`);
4537
+ });
4538
+ grantsAuthority(annotate(brief.command("reset"), { effects: LOCAL_WRITE })).summary("remove the brief; edit --undo brings it back").description("remove the brief, so the morning digest follows its skill alone; edit --undo brings it back").option("--json", "print JSON").action(async (given2) => {
4539
+ refuseAgent(env);
4540
+ const changed = await withStore(env, async (store) => store.templates.reset(BRIEF));
4541
+ print(given2.json, itemAnswer({ changed }), changed ? "Removed the brief; memo digest brief edit --undo brings it back." : "There was no brief.");
4542
+ });
4543
+ }, "briefCommand");
4437
4544
 
4438
4545
  // dist/digest/tasks.js
4439
- import { existsSync as existsSync5, readdirSync as readdirSync3 } from "node:fs";
4440
- import { join as join5 } from "node:path";
4546
+ import { existsSync as existsSync6, readdirSync as readdirSync3 } from "node:fs";
4547
+ import { join as join6 } from "node:path";
4441
4548
 
4442
4549
  // dist/tasks/list.js
4443
4550
  import { createHash as createHash2 } from "node:crypto";
@@ -4607,13 +4714,13 @@ var countTasks = /* @__PURE__ */ __name(async (store, words) => {
4607
4714
  }, "countTasks");
4608
4715
 
4609
4716
  // dist/digest/sync-health.js
4610
- import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "node:fs";
4611
- import { join as join4 } from "node:path";
4717
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync6 } from "node:fs";
4718
+ import { join as join5 } from "node:path";
4612
4719
 
4613
4720
  // dist/knowledge/messenger-sync.js
4614
4721
  import { spawn } from "node:child_process";
4615
- import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync4, realpathSync, statSync as statSync2 } from "node:fs";
4616
- import { delimiter, join as join3 } from "node:path";
4722
+ import { existsSync as existsSync4, readdirSync, readFileSync as readFileSync5, realpathSync, statSync as statSync2 } from "node:fs";
4723
+ import { delimiter, join as join4 } from "node:path";
4617
4724
  var STATE = {
4618
4725
  tg: { appName: "tg-cli", envPrefix: "TG" },
4619
4726
  max: { appName: "max-cli", envPrefix: "MAX" },
@@ -4633,10 +4740,10 @@ var syncProfileOf = /* @__PURE__ */ __name((value, previous = {}) => {
4633
4740
  throw new InvalidArgumentError(`one profile per tool; ${tool} is already ${previous[tool]}`);
4634
4741
  return { ...previous, [tool]: profile };
4635
4742
  }, "syncProfileOf");
4636
- var accountsDir = /* @__PURE__ */ __name((tool, env) => join3(resolvePaths({ appName: tool.appName, prefix: tool.envPrefix, env }).state, "accounts"), "accountsDir");
4743
+ var accountsDir = /* @__PURE__ */ __name((tool, env) => join4(resolvePaths({ appName: tool.appName, prefix: tool.envPrefix, env }).state, "accounts"), "accountsDir");
4637
4744
  var signedInAccount = /* @__PURE__ */ __name((tool, profile, env) => {
4638
4745
  try {
4639
- return JSON.parse(readFileSync4(join3(accountsDir(tool, env), `${profile}.json`), "utf8"))?.account;
4746
+ return JSON.parse(readFileSync5(join4(accountsDir(tool, env), `${profile}.json`), "utf8"))?.account;
4640
4747
  } catch {
4641
4748
  return void 0;
4642
4749
  }
@@ -4646,7 +4753,7 @@ var profileFor = /* @__PURE__ */ __name((provider, account2, env, chosen = {}) =
4646
4753
  if (!tool)
4647
4754
  return void 0;
4648
4755
  const dir = accountsDir(tool, env);
4649
- const profiles = existsSync3(dir) ? readdirSync(dir).filter((name2) => name2.endsWith(".json")).map((name2) => name2.slice(0, -".json".length)).sort() : [];
4756
+ const profiles = existsSync4(dir) ? readdirSync(dir).filter((name2) => name2.endsWith(".json")).map((name2) => name2.slice(0, -".json".length)).sort() : [];
4650
4757
  const accountOf = /* @__PURE__ */ __name((profile) => signedInAccount(tool, profile, env), "accountOf");
4651
4758
  const all = profiles.join(", ") || "none";
4652
4759
  const pick = chosen[tool.tool];
@@ -4666,7 +4773,7 @@ var profileFor = /* @__PURE__ */ __name((provider, account2, env, chosen = {}) =
4666
4773
  };
4667
4774
  return { why: `no ${tool.tool} profile here is signed in to account ${account2}; profiles: ${all}`, profiles: [] };
4668
4775
  }, "profileFor");
4669
- var onPath = /* @__PURE__ */ __name((name2, env) => (env.PATH ?? "").split(delimiter).filter(Boolean).map((dir) => join3(dir, name2)).find((path) => {
4776
+ var onPath = /* @__PURE__ */ __name((name2, env) => (env.PATH ?? "").split(delimiter).filter(Boolean).map((dir) => join4(dir, name2)).find((path) => {
4670
4777
  try {
4671
4778
  return statSync2(path).isFile();
4672
4779
  } catch {
@@ -4722,7 +4829,7 @@ var binaryOf = /* @__PURE__ */ __name(async (provider, env, run) => {
4722
4829
  const real = realpathSync(short);
4723
4830
  if (real.includes(`/${mark}/`))
4724
4831
  return short;
4725
- return statSync2(real).size < 65536 && readFileSync4(real, "utf8").includes(mark) ? short : void 0;
4832
+ return statSync2(real).size < 65536 && readFileSync5(real, "utf8").includes(mark) ? short : void 0;
4726
4833
  }, "binaryOf");
4727
4834
  var answerOf = /* @__PURE__ */ __name((stdout) => {
4728
4835
  try {
@@ -4830,13 +4937,13 @@ var SOURCE_WORDS = {
4830
4937
  var toolOf = /* @__PURE__ */ __name((provider) => provider === "email" ? MAIL2 : messengerToolOf(provider), "toolOf");
4831
4938
  var stateDirs = /* @__PURE__ */ __name((tool, env) => resolvePaths({ appName: tool.appName, prefix: tool.envPrefix, env }), "stateDirs");
4832
4939
  var schedulesOf = /* @__PURE__ */ __name((state) => {
4833
- const dir = join4(state, "schedules");
4834
- if (!existsSync4(dir))
4940
+ const dir = join5(state, "schedules");
4941
+ if (!existsSync5(dir))
4835
4942
  return [];
4836
4943
  const last = new Map(scheduledRuns(state).map((one2) => [one2.job, one2.last]));
4837
4944
  return readdirSync2(dir).flatMap((name2) => {
4838
4945
  try {
4839
- const schedule = JSON.parse(readFileSync5(join4(dir, name2, "schedule.json"), "utf8"));
4946
+ const schedule = JSON.parse(readFileSync6(join5(dir, name2, "schedule.json"), "utf8"));
4840
4947
  return [
4841
4948
  {
4842
4949
  name: String(schedule.name),
@@ -4851,15 +4958,15 @@ var schedulesOf = /* @__PURE__ */ __name((state) => {
4851
4958
  }
4852
4959
  });
4853
4960
  }, "schedulesOf");
4854
- var signedIn = /* @__PURE__ */ __name((dir) => existsSync4(dir) ? readdirSync2(dir).filter((name2) => name2.endsWith(".json")).map((name2) => name2.slice(0, -".json".length)) : [], "signedIn");
4961
+ var signedIn = /* @__PURE__ */ __name((dir) => existsSync5(dir) ? readdirSync2(dir).filter((name2) => name2.endsWith(".json")).map((name2) => name2.slice(0, -".json".length)) : [], "signedIn");
4855
4962
  var profilesOf = /* @__PURE__ */ __name((provider, tool, env) => {
4856
4963
  if (provider !== "email")
4857
- return new Map(signedIn(join4(stateDirs(tool, env).state, "accounts")).map((profile) => [
4964
+ return new Map(signedIn(join5(stateDirs(tool, env).state, "accounts")).map((profile) => [
4858
4965
  profile,
4859
4966
  signedInAccount(tool, profile, env)
4860
4967
  ]));
4861
4968
  try {
4862
- const config = JSON.parse(readFileSync5(configFilePath(stateDirs(MAIL2, env).config), "utf8"));
4969
+ const config = JSON.parse(readFileSync6(configFilePath(stateDirs(MAIL2, env).config), "utf8"));
4863
4970
  return new Map(Object.entries(config?.profiles ?? {}).map(([profile, one2]) => [
4864
4971
  profile,
4865
4972
  one2?.address
@@ -4949,8 +5056,8 @@ var runTime = /* @__PURE__ */ __name((file) => {
4949
5056
  }, "runTime");
4950
5057
  var digestReportTimes = /* @__PURE__ */ __name((env) => {
4951
5058
  const { state, schedule } = digestSchedule(env);
4952
- const runs = schedule ? join5(state, "schedules", schedule.name, "runs") : void 0;
4953
- if (!runs || !existsSync5(runs))
5059
+ const runs = schedule ? join6(state, "schedules", schedule.name, "runs") : void 0;
5060
+ if (!runs || !existsSync6(runs))
4954
5061
  return [];
4955
5062
  return readdirSync3(runs).filter((file) => file.endsWith(".report.json")).map(runTime).filter((at) => !Number.isNaN(at)).sort((a, b) => a - b);
4956
5063
  }, "digestReportTimes");
@@ -5079,7 +5186,8 @@ var usd = /* @__PURE__ */ __name((value) => `$${value.toFixed(2)}`, "usd");
5079
5186
  var cents = /* @__PURE__ */ __name((value) => Math.round(value * 100) / 100, "cents");
5080
5187
  var digestCommand = /* @__PURE__ */ __name((program, streams, env) => {
5081
5188
  const { print } = answers(program, streams, env);
5082
- const digest = program.command("digest").description("the morning digest's history: build the digests of past days").summary("the morning digest's history");
5189
+ const digest = program.command("digest").description("the morning digest: your brief on what it collects, and the digests of past days").summary("the morning digest: your brief, past days");
5190
+ briefCommand(digest, print, env);
5083
5191
  fromAppOption(annotate(digest.command("backfill"), { effects: LOCAL_WRITE })).summary("build the morning digests of past days, without sending them").description("build the morning digest each past day would have had: the morning-digest schedule's agent runs as its timer does (the same skill, flags and cost caps), reading the agenda as of that day's run time, and the result is kept as that day's run, marked backfill, for WireCat Desktop's digests screen. It is never sent to Telegram or mail. A day that already has a digest is skipped. Without --yes it only prints what it would build and the estimate: the days times the last digest run's cost. Each day is a paid model call: it stops once today's runs cost the schedule's daily cap or a day fails, and only you run it, never an agent. The store keeps what holds now, so a chat answered since reads as answered").requiredOption("--from <date>", "the first day, YYYY-MM-DD").requiredOption("--to <date>", "the last day, YYYY-MM-DD; not a day whose run time is still ahead").option("--yes", "build them; without it, only the estimate is printed").option("--json", "print JSON").action(async (given2, command) => {
5084
5192
  const from = dateOf(given2.from, "--from");
5085
5193
  const to = dateOf(given2.to, "--to");
@@ -5100,8 +5208,8 @@ var digestCommand = /* @__PURE__ */ __name((program, streams, env) => {
5100
5208
  throw new CliError("validation_error", `the ${given2.to} digest's time has not come yet; --to an earlier day`, {
5101
5209
  param: "--to"
5102
5210
  });
5103
- const runs = join6(file, "..", "runs");
5104
- const done = new Set((existsSync6(runs) ? readdirSync4(runs) : []).filter((name2) => name2.endsWith(".report.json")).map((name2) => localDate(runTime(name2))));
5211
+ const runs = join7(file, "..", "runs");
5212
+ const done = new Set((existsSync7(runs) ? readdirSync4(runs) : []).filter((name2) => name2.endsWith(".report.json")).map((name2) => localDate(runTime(name2))));
5105
5213
  const days2 = all.filter((day2) => !done.has(day2.date));
5106
5214
  const skipped = all.filter((day2) => done.has(day2.date)).map((day2) => day2.date);
5107
5215
  const lastCost = schedule.last?.costUsd;
@@ -5246,9 +5354,9 @@ var commandsCommand = /* @__PURE__ */ __name((program, streams) => {
5246
5354
  }, "commandsCommand");
5247
5355
 
5248
5356
  // dist/doctor/command.js
5249
- import { existsSync as existsSync7, readdirSync as readdirSync5, readFileSync as readFileSync6 } from "node:fs";
5357
+ import { existsSync as existsSync8, readdirSync as readdirSync5, readFileSync as readFileSync7 } from "node:fs";
5250
5358
  import { homedir } from "node:os";
5251
- import { dirname, join as join7 } from "node:path";
5359
+ import { dirname, join as join8 } from "node:path";
5252
5360
  var retiredMailAddresses = /* @__PURE__ */ __name((mail) => {
5253
5361
  const accounts = mail?.accounts;
5254
5362
  if (!Array.isArray(accounts))
@@ -5274,7 +5382,7 @@ var diagnose = /* @__PURE__ */ __name(async (env, program, { deep = false } = {}
5274
5382
  problems.push({ what: "the store is from a newer version than this memo", fix: "memo upgrade" });
5275
5383
  const folders = noteFolders(config.notes).map(({ path, id }) => ({
5276
5384
  path,
5277
- exists: existsSync7(path),
5385
+ exists: existsSync8(path),
5278
5386
  bound: id !== null
5279
5387
  }));
5280
5388
  for (const folder of folders) {
@@ -5305,13 +5413,13 @@ var diagnose = /* @__PURE__ */ __name(async (env, program, { deep = false } = {}
5305
5413
  fix: `fix text_models in ${textModelsFile(env)}, or remove it to go back to ${DEFAULT_TEXT_MODEL}`
5306
5414
  });
5307
5415
  }
5308
- const modelDir = join7(sharedModelsDirectory("text", env), textModel);
5309
- const model = existsSync7(modelDir) && readdirSync5(modelDir).length > 0;
5416
+ const modelDir = join8(sharedModelsDirectory("text", env), textModel);
5417
+ const model = existsSync8(modelDir) && readdirSync5(modelDir).length > 0;
5310
5418
  const state = autoState(config);
5311
- const unitFile = join7(env.XDG_CONFIG_HOME ?? join7(env.HOME ?? homedir(), ".config"), "systemd", "user", "memo-import.service");
5312
- const unit = existsSync7(unitFile) ? readFileSync6(unitFile, "utf8") : void 0;
5419
+ const unitFile = join8(env.XDG_CONFIG_HOME ?? join8(env.HOME ?? homedir(), ".config"), "systemd", "user", "memo-import.service");
5420
+ const unit = existsSync8(unitFile) ? readFileSync7(unitFile, "utf8") : void 0;
5313
5421
  const runs = unit ? unitPaths(unit) : [];
5314
- const missing = runs.filter((path) => !existsSync7(path));
5422
+ const missing = runs.filter((path) => !existsSync8(path));
5315
5423
  const last = lastAutoRun(env);
5316
5424
  const failing = last && last.exitCode !== 0 ? { since: last.failingSince ?? last.at, runs: last.failures ?? 1, reason: last.reason ?? null } : null;
5317
5425
  if (state.enabled && !unit)
@@ -5322,7 +5430,7 @@ var diagnose = /* @__PURE__ */ __name(async (env, program, { deep = false } = {}
5322
5430
  problems.push({ what: `the timer has failed ${failing.runs} runs since ${failing.since}`, fix: "memo jobs status" });
5323
5431
  const skills = SKILL_TARGETS.map((target) => {
5324
5432
  const path = skillPath(target, APP.appName, env);
5325
- const version = existsSync7(path) ? skillVersion(readFileSync6(path, "utf8")) ?? "unknown" : null;
5433
+ const version = existsSync8(path) ? skillVersion(readFileSync7(path, "utf8")) ?? "unknown" : null;
5326
5434
  return { target, path, version };
5327
5435
  });
5328
5436
  if (skills.some(({ version }) => version !== null && version !== VERSION))
@@ -5951,10 +6059,12 @@ var EXAMPLES = {
5951
6059
  "projects key-documents list": ["memo projects key-documents list HRB"],
5952
6060
  "relationships update": [
5953
6061
  "memo relationships update 12 --purpose sales",
5954
- "memo relationships update 12 --role contractor --reason 'builds the site'"
6062
+ "memo relationships update 12 --engagement low",
6063
+ "memo relationships update 12 --role approver --role-note 'signs the acts'"
5955
6064
  ],
5956
6065
  "relationships add": [
5957
6066
  "memo relationships add person:3 organization:1 --role employee",
6067
+ "memo relationships add person:3 project:1 --role client-contact --engagement low",
5958
6068
  "memo relationships add project:2 organization:1 --kind related-to --reason 'same client'"
5959
6069
  ],
5960
6070
  "relationships list": ['memo relationships list about:"person:3"', "memo relationships list confirmed:false"],
@@ -6190,6 +6300,13 @@ var EXAMPLES = {
6190
6300
  "memo digest backfill --from 2026-11-01 --to 2026-11-07",
6191
6301
  "memo digest backfill --from 2026-11-01 --to 2026-11-07 --yes --json"
6192
6302
  ],
6303
+ "digest brief show": ["memo digest brief show", "memo digest brief show --json"],
6304
+ "digest brief edit": [
6305
+ "memo digest brief edit",
6306
+ "memo digest brief edit --file brief.md",
6307
+ "memo digest brief edit --undo"
6308
+ ],
6309
+ "digest brief reset": ["memo digest brief reset"],
6193
6310
  "schedule remove": ["memo schedule remove digest"],
6194
6311
  "schedule exec": ["memo schedule exec ~/.local/state/cli-memo/schedules/digest/schedule.json"],
6195
6312
  "templates list": ["memo templates list", "memo templates list channel:telegram source:stored --json"],
@@ -8441,7 +8558,7 @@ var projectFindings = /* @__PURE__ */ __name(async (store, project, links) => {
8441
8558
  // dist/knowledge/project-context.js
8442
8559
  var projectContext = /* @__PURE__ */ __name(async (store, env, reference2) => {
8443
8560
  const project = await projectOf(store, reference2);
8444
- const relationships = (await store.notes.links({ to: project.ref })).concat(await store.notes.links({ from: project.ref })).filter((link2) => link2.kind !== "about" && link2.kind !== "links-to" && link2.role !== "key");
8561
+ const relationships = byEngagement((await store.notes.links({ to: project.ref })).concat(await store.notes.links({ from: project.ref })).filter((link2) => link2.kind !== "about" && link2.kind !== "links-to" && link2.role !== "key"));
8445
8562
  const documents = await keyDocuments(store, project);
8446
8563
  const pending2 = /* @__PURE__ */ __name((kind) => proposalRegistry(store).list({ project: project.ref, kinds: [kind], status: "proposed", limit: 50, offset: 0 }), "pending");
8447
8564
  const [facts, tasks, findings, keys, links, waiting2] = await Promise.all([
@@ -8898,7 +9015,7 @@ var listRelationships = /* @__PURE__ */ __name(async (store, words) => {
8898
9015
  const confirmed = terms2.get("confirmed");
8899
9016
  const found = confirmed === "false" ? await pending(store, about) : {
8900
9017
  hasMore: false,
8901
- items: (await store.knowledge.relations(null, about)).filter((one2) => confirmed === void 0 || one2.confirmed).map((one2) => ({ ...one2, status: one2.confirmed ? "confirmed" : "proposed" }))
9018
+ items: byEngagement(await store.knowledge.relations(null, about)).filter((one2) => confirmed === void 0 || one2.confirmed).map((one2) => ({ ...one2, status: one2.confirmed ? "confirmed" : "proposed" }))
8902
9019
  };
8903
9020
  const label = await labelsFor(store, found.items.flatMap((one2) => [one2.from, one2.to]));
8904
9021
  return {
@@ -8910,7 +9027,13 @@ var listRelationships = /* @__PURE__ */ __name(async (store, words) => {
8910
9027
  var relationshipsText = /* @__PURE__ */ __name((items) => items.length ? items.map((one2) => [
8911
9028
  one2.id,
8912
9029
  `${one2.fromTitle} \u2192 ${one2.toTitle}`,
8913
- [one2.kind, one2.role && `as ${one2.role}`, one2.purpose && `for ${one2.purpose}`].filter(Boolean).join(" "),
9030
+ [
9031
+ one2.kind,
9032
+ one2.role && `as ${one2.role}`,
9033
+ "roleNote" in one2 && one2.roleNote && `(${one2.roleNote})`,
9034
+ one2.purpose && `for ${one2.purpose}`,
9035
+ "engagement" in one2 && one2.engagement && `engagement ${one2.engagement}`
9036
+ ].filter(Boolean).join(" "),
8914
9037
  "proposer" in one2 ? `proposed by ${one2.proposer}` : one2.confirmed ? "" : "suggested"
8915
9038
  ].filter(Boolean).join(" ")).join("\n") : "no relationships", "relationshipsText");
8916
9039
 
@@ -8924,6 +9047,7 @@ var pendingLink = /* @__PURE__ */ __name(async (store, id) => {
8924
9047
  throw error;
8925
9048
  }
8926
9049
  }, "pendingLink");
9050
+ var ENGAGEMENT_HELP = "a person on a project: how much you deal with them yourself, not how active they are: none, low, medium or high";
8927
9051
  var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
8928
9052
  const { run, print } = answers(program, streams, env);
8929
9053
  const warn = /* @__PURE__ */ __name((text3) => streams.diagnostic(text3), "warn");
@@ -9001,7 +9125,7 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9001
9125
  return ownedList("projects key-documents list", options, async (store) => keyDocuments(store, await projectOf(store, project), id === void 0 ? {} : { id }));
9002
9126
  });
9003
9127
  const relations = program.command("relationships").description("relations between people, organizations and projects; never between identities");
9004
- byOption(annotate(relations.command("add"), { effects: LOCAL_WRITE }).description("state that a person, organization or project belongs to or relates to another, or that a chat is a project's (member-of only); an agent's waits for you to confirm it").summary("state that a person, organization, project or chat belongs or relates to another")).argument("<from>", "the person:, organization: or project: that belongs or relates, or chat:<provider>/<account>/<chat> of a project").argument("<to>", "the person:, organization: or project: it belongs or relates to").option("--json", "print JSON; --json=id,title keeps only those fields").option("--kind <kind>", "member-of or related-to", "member-of").option("--role <role>", "the role it has there; a person's role in an organization or a project is one from its list, such as employee or contributor").option("--reason <text>", "why you think so, in a sentence").action(async (from, to, options, command) => {
9128
+ byOption(annotate(relations.command("add"), { effects: LOCAL_WRITE }).description("state that a person, organization or project belongs to or relates to another, or that a chat is a project's (member-of only); an agent's waits for you to confirm it").summary("state that a person, organization, project or chat belongs or relates to another")).argument("<from>", "the person:, organization: or project: that belongs or relates, or chat:<provider>/<account>/<chat> of a project").argument("<to>", "the person:, organization: or project: it belongs or relates to").option("--json", "print JSON; --json=id,title keeps only those fields").option("--kind <kind>", "member-of or related-to", "member-of").option("--role <role>", "the role it has there; a person's role in an organization or a project is one from its list, such as employee or contributor").option("--role-note <text>", "what the role means here, in your words, beside a role from its list").option("--engagement <level>", ENGAGEMENT_HELP, oneOf(ENGAGEMENT_LEVELS)).option("--reason <text>", "why you think so, in a sentence").action(async (from, to, options, command) => {
9005
9129
  const by = await whoRuns(command, env, { asOwner: options.asOwner, question: "state it as yours?" });
9006
9130
  return owned(options, async (store) => {
9007
9131
  const input = {
@@ -9009,6 +9133,8 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9009
9133
  to: await withOwner(store, to),
9010
9134
  kind: options.kind,
9011
9135
  ...options.role === void 0 ? {} : { role: options.role },
9136
+ ...options.roleNote === void 0 ? {} : { roleNote: options.roleNote },
9137
+ ...options.engagement === void 0 ? {} : { engagement: options.engagement },
9012
9138
  ...options.reason === void 0 ? {} : { evidence: options.reason }
9013
9139
  };
9014
9140
  return by === "owner" ? store.knowledge.relate(null, { ...input, by }) : store.knowledge.relate(null, { ...input, by });
@@ -9018,15 +9144,18 @@ var knowledgeCommands = /* @__PURE__ */ __name((program, streams, env) => {
9018
9144
  const found = await withStore(env, (store) => listRelationships(store, words));
9019
9145
  print(options.json, listAnswer("relationships list", { items: found.items, limit: found.limit, has_more: found.hasMore }), relationshipsText(found.items));
9020
9146
  });
9021
- byOption(annotate(relations.command("update"), { effects: LOCAL_WRITE }).description("set what a relationship is: its role, or what a chat is for in a project (work, sales, support, other); an agent's change waits for you in memo review").summary("set a relationship's role or a chat's purpose in a project").argument("<id>", "the relationship's id, as relationships list gives it").option("--role <role>", "the role it has there, from the same list as relationships add; an empty value clears it").option("--purpose <purpose>", "what the chat is for in the project: work, sales, support or other").option("--reason <text>", "why, in a sentence").option("--json", "print JSON; --json=id,title keeps only those fields")).action(async (id, options, command) => {
9147
+ byOption(annotate(relations.command("update"), { effects: LOCAL_WRITE }).description("set what a relationship is: its role and a note beside it, how much you deal with a person on a project, or what a chat is for in a project (work, sales, support, other); an agent's change waits for you in memo review").summary("set a relationship's role, engagement or a chat's purpose in a project").argument("<id>", "the relationship's id, as relationships list gives it").option("--role <role>", "the role it has there, from the same list as relationships add; an empty value clears it").option("--role-note <text>", "what the role means here, in your words; an empty value clears it").option("--engagement <level>", `${ENGAGEMENT_HELP}; an empty value clears it`, (value) => value === "" ? "" : oneOf(ENGAGEMENT_LEVELS)(value)).option("--purpose <purpose>", "what the chat is for in the project: work, sales, support or other").option("--reason <text>", "why, in a sentence").option("--json", "print JSON; --json=id,title keeps only those fields")).action(async (id, options, command) => {
9148
+ const cleared = /* @__PURE__ */ __name((value) => value === "" ? null : value, "cleared");
9022
9149
  const change = {
9023
- ...options.role === void 0 ? {} : { role: options.role === "" ? null : options.role },
9150
+ ...options.role === void 0 ? {} : { role: cleared(options.role) },
9151
+ ...options.roleNote === void 0 ? {} : { roleNote: cleared(options.roleNote) },
9152
+ ...options.engagement === void 0 ? {} : { engagement: cleared(options.engagement) },
9024
9153
  ...options.purpose === void 0 ? {} : { purpose: options.purpose }
9025
9154
  };
9026
9155
  const by = await whoRuns(command, env, { asOwner: options.asOwner, question: `change relationship ${id}?` });
9027
9156
  return owned(options, (store) => {
9028
- if (options.role === void 0 && options.purpose === void 0)
9029
- throw new CliError("validation_error", "say what to change: --role, --purpose or both", {
9157
+ if (!Object.keys(change).length)
9158
+ throw new CliError("validation_error", "say what to change: --role, --role-note, --engagement or --purpose", {
9030
9159
  reason: "input.invalid",
9031
9160
  param: "--purpose"
9032
9161
  });
@@ -9490,9 +9619,9 @@ var messagesCommand = /* @__PURE__ */ __name((program, streams, env) => {
9490
9619
  }, "messagesCommand");
9491
9620
 
9492
9621
  // dist/mcp/command.js
9493
- import { join as join8 } from "node:path";
9622
+ import { join as join9 } from "node:path";
9494
9623
  var DEFAULT_PORT = 8767;
9495
- var httpTokenFile = /* @__PURE__ */ __name((env) => join8(resolvePaths({ appName: APP.appName, prefix: APP.envPrefix, env }).state, "mcp-http", "memo.json"), "httpTokenFile");
9624
+ var httpTokenFile = /* @__PURE__ */ __name((env) => join9(resolvePaths({ appName: APP.appName, prefix: APP.envPrefix, env }).state, "mcp-http", "memo.json"), "httpTokenFile");
9496
9625
  var mcpCommandDefinition = /* @__PURE__ */ __name((program, streams, env, createProgram2) => {
9497
9626
  const out = answers(program, streams, env);
9498
9627
  const mcp2 = annotate(program.command("mcp"), { effects: LOCAL_READ, mcp: false }).summary("serve this profile's commands to an AI agent, and set that up").description("serve memo commands over MCP on stdio or authenticated HTTP, limited by saved permissions \u2014 `claude mcp add memo -- memo mcp serve`");
@@ -9504,10 +9633,10 @@ var mcpCommandDefinition = /* @__PURE__ */ __name((program, streams, env, create
9504
9633
  }).summary("serve this profile's commands to an AI agent").description("serve memo commands over MCP on stdio or authenticated HTTP, limited by saved permissions").option("--permission <key=level>", "tighten one saved permission for this server; repeat for more keys", (value, previous = []) => [...previous, value]).option("--http", "serve on 127.0.0.1 behind an HTTPS tunnel with an owner access-code login").option("--port <port>", `local HTTP port (default ${DEFAULT_PORT}); requires --http`).option("--public-url <url>", "tunnel's HTTPS address without /mcp, or a path of it such as https://<name>.ts.net/memo; requires --http").action(async (options) => {
9505
9634
  if (!options.http && (options.port !== void 0 || options.publicUrl !== void 0))
9506
9635
  throw new CliError("validation_error", "--port and --public-url require --http");
9507
- const { createMemoServer } = await import("./server-3FW2MQRQ.js");
9636
+ const { createMemoServer } = await import("./server-BVRPQPGY.js");
9508
9637
  const build = /* @__PURE__ */ __name(() => createMemoServer(env, createProgram2, options.permission), "build");
9509
9638
  if (options.http) {
9510
- const { httpLockFile, mcpUrlOf, portOf, publicUrlOf, serveOverHttp } = await import("./mcp-USR3ZFQU.js");
9639
+ const { httpLockFile, mcpUrlOf, portOf, publicUrlOf, serveOverHttp } = await import("./mcp-CFIL7WZU.js");
9511
9640
  const publicUrl = publicUrlOf(options.publicUrl, {
9512
9641
  missing: "--http",
9513
9642
  reaches: "the browser apps reach memo",
@@ -9559,7 +9688,7 @@ var mcpCommandDefinition = /* @__PURE__ */ __name((program, streams, env, create
9559
9688
  });
9560
9689
  });
9561
9690
  annotate(mcp2.command("revoke"), { effects: LOCAL_WRITE, mcp: false, examples: ["memo mcp revoke --json"] }).summary("forget every login given to a browser app").description("forget every login `memo mcp serve --http` gave a browser app; each app must log in again").option("--json", "print JSON").action(async function() {
9562
- const { revokeAll } = await import("./mcp-USR3ZFQU.js");
9691
+ const { revokeAll } = await import("./mcp-CFIL7WZU.js");
9563
9692
  revokeAll(httpTokenFile(env));
9564
9693
  out.print(this.opts().json, itemAnswer({ revoked: true }));
9565
9694
  });
@@ -9850,7 +9979,7 @@ var modelsCommand = /* @__PURE__ */ __name((program, streams, env, keyring) => {
9850
9979
  }, "modelsCommand");
9851
9980
 
9852
9981
  // dist/notes/command.js
9853
- import { readFileSync as readFileSync8 } from "node:fs";
9982
+ import { readFileSync as readFileSync9 } from "node:fs";
9854
9983
 
9855
9984
  // dist/people/identity.js
9856
9985
  var identityOf = /* @__PURE__ */ __name(async (store, reference2) => {
@@ -9888,8 +10017,8 @@ import { resolve as resolve3 } from "node:path";
9888
10017
 
9889
10018
  // dist/notes/export.js
9890
10019
  import { createHash as createHash3 } from "node:crypto";
9891
- import { existsSync as existsSync8, mkdirSync as mkdirSync3, readdirSync as readdirSync6, readFileSync as readFileSync7, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "node:fs";
9892
- import { join as join9 } from "node:path";
10020
+ import { existsSync as existsSync9, mkdirSync as mkdirSync3, readdirSync as readdirSync6, readFileSync as readFileSync8, renameSync as renameSync2, writeFileSync as writeFileSync4 } from "node:fs";
10021
+ import { join as join10 } from "node:path";
9893
10022
  var HASH_LINE = /^memo-hash: .*\r?\n/m;
9894
10023
  var PLACEHOLDER = "f".repeat(64);
9895
10024
  var UNSAFE = /[\\/:*?"<>|#^[\]\p{Cc}]/gu;
@@ -9913,7 +10042,7 @@ var exportedIn = /* @__PURE__ */ __name((dir) => {
9913
10042
  for (const entry of readdirSync6(dir, { withFileTypes: true })) {
9914
10043
  if (!entry.isFile() || !/\.(md|markdown)$/i.test(entry.name))
9915
10044
  continue;
9916
- const id = readMemoId(join9(dir, entry.name));
10045
+ const id = readMemoId(join10(dir, entry.name));
9917
10046
  if (id !== null)
9918
10047
  found.set(id, entry.name);
9919
10048
  }
@@ -9930,11 +10059,11 @@ var exportNotes = /* @__PURE__ */ __name(({ dir, dialect, notes: notes2 }) => {
9930
10059
  frontMatter["memo-hash"] = PLACEHOLDER;
9931
10060
  const content = withHash(dialect.render({ ...note, frontMatter }));
9932
10061
  const known2 = existing.get(id);
9933
- const name2 = known2 ?? fileName(note.title, id, (candidate) => claimed.has(candidate) || existsSync8(join9(dir, candidate)));
10062
+ const name2 = known2 ?? fileName(note.title, id, (candidate) => claimed.has(candidate) || existsSync9(join10(dir, candidate)));
9934
10063
  claimed.add(name2);
9935
- const path = join9(dir, name2);
10064
+ const path = join10(dir, name2);
9936
10065
  if (known2 !== void 0) {
9937
- const current = readFileSync7(path, "utf8");
10066
+ const current = readFileSync8(path, "utf8");
9938
10067
  if (editedSinceExport(current)) {
9939
10068
  result.edited.push({ path, id });
9940
10069
  continue;
@@ -9944,8 +10073,8 @@ var exportNotes = /* @__PURE__ */ __name(({ dir, dialect, notes: notes2 }) => {
9944
10073
  continue;
9945
10074
  }
9946
10075
  }
9947
- const partial = join9(dir, `.${name2}.memo-tmp`);
9948
- writeFileSync3(partial, content);
10076
+ const partial = join10(dir, `.${name2}.memo-tmp`);
10077
+ writeFileSync4(partial, content);
9949
10078
  renameSync2(partial, path);
9950
10079
  result.written.push(path);
9951
10080
  }
@@ -10045,7 +10174,7 @@ var textOf = /* @__PURE__ */ __name((options, given2) => {
10045
10174
  if (sources.length !== 1)
10046
10175
  throw new CliError("validation_error", "give the text once: as an argument, --text or --text-file");
10047
10176
  if (options.textFile !== void 0)
10048
- return readFileSync8(options.textFile === "-" ? 0 : options.textFile, "utf8");
10177
+ return readFileSync9(options.textFile === "-" ? 0 : options.textFile, "utf8");
10049
10178
  return sources[0];
10050
10179
  }, "textOf");
10051
10180
  var noteOf = /* @__PURE__ */ __name(async (store, env, reference2) => {
@@ -10201,9 +10330,9 @@ import { statSync as statSync4 } from "node:fs";
10201
10330
  import { basename as basename2, resolve as resolve4 } from "node:path";
10202
10331
 
10203
10332
  // dist/run/lock.js
10204
- import { join as join10 } from "node:path";
10333
+ import { join as join11 } from "node:path";
10205
10334
  var withImportLock = /* @__PURE__ */ __name(async (env, work) => {
10206
- const lock = join10(resolvePaths({ appName: "cli-memo", prefix: "MEMO", env }).state, "import.lock");
10335
+ const lock = join11(resolvePaths({ appName: "cli-memo", prefix: "MEMO", env }).state, "import.lock");
10207
10336
  const holder = takeLock(lock, { pid: process.pid, startedAt: (/* @__PURE__ */ new Date()).toISOString() });
10208
10337
  if (holder !== void 0)
10209
10338
  throw new CliError("rate_limited", `another memo sync is running (process ${holder.pid}); try again when it ends`, {
@@ -10334,7 +10463,7 @@ var foldersCommand = /* @__PURE__ */ __name((program, streams, env) => {
10334
10463
  }, "foldersCommand");
10335
10464
 
10336
10465
  // dist/people/command.js
10337
- import { join as join11 } from "node:path";
10466
+ import { join as join12 } from "node:path";
10338
10467
  var noteCommand = /* @__PURE__ */ __name((program, streams, env) => {
10339
10468
  const notes2 = program.commands.find((command) => command.name() === "notes") ?? program.command("notes");
10340
10469
  const links = notes2.command("links").description("imported note files linked to the person behind an identity");
@@ -10387,7 +10516,7 @@ var noteCommand = /* @__PURE__ */ __name((program, streams, env) => {
10387
10516
  }
10388
10517
  const paths = (await files()).map(({ note }) => {
10389
10518
  const folder = folders.find((candidate) => candidate.id === note.folderId);
10390
- return folder ? join11(folder.path, note.path) : note.ref;
10519
+ return folder ? join12(folder.path, note.path) : note.ref;
10391
10520
  });
10392
10521
  return { person: to, name: person.name ?? person.uid, files: paths };
10393
10522
  });
@@ -10830,8 +10959,8 @@ ${SOURCE_REVIEW_HELP}`);
10830
10959
  }, "reviewCommand");
10831
10960
 
10832
10961
  // dist/notes/embed.js
10833
- import { existsSync as existsSync9, readdirSync as readdirSync7 } from "node:fs";
10834
- import { join as join12 } from "node:path";
10962
+ import { existsSync as existsSync10, readdirSync as readdirSync7 } from "node:fs";
10963
+ import { join as join13 } from "node:path";
10835
10964
  var EMBED_PER_RUN = 600;
10836
10965
  var SLOWEST_KNOWN = 2;
10837
10966
  var embedPerRun = /* @__PURE__ */ __name((env = process.env) => {
@@ -10848,8 +10977,8 @@ var missingModel = /* @__PURE__ */ __name((error, env) => {
10848
10977
  }, "missingModel");
10849
10978
  var searchModelPresent = /* @__PURE__ */ __name((env) => {
10850
10979
  try {
10851
- const path = join12(sharedModelsDirectory("text", env), chosenTextModel(env).id);
10852
- return existsSync9(path) && readdirSync7(path).length > 0;
10980
+ const path = join13(sharedModelsDirectory("text", env), chosenTextModel(env).id);
10981
+ return existsSync10(path) && readdirSync7(path).length > 0;
10853
10982
  } catch {
10854
10983
  return false;
10855
10984
  }
@@ -11330,8 +11459,8 @@ var searchText = /* @__PURE__ */ __name((result, offset = 0) => [
11330
11459
  ].join("\n"), "searchText");
11331
11460
 
11332
11461
  // dist/search/hits.js
11333
- var BRIEF = ["ref", "chat_title", "timestamp", "sender_name", "excerpt", "score"];
11334
- var briefHit = /* @__PURE__ */ __name((hit) => Object.fromEntries(BRIEF.flatMap((key) => hit[key] === void 0 || hit[key] === null ? [] : [[key, hit[key]]])), "briefHit");
11462
+ var BRIEF2 = ["ref", "chat_title", "timestamp", "sender_name", "excerpt", "score"];
11463
+ var briefHit = /* @__PURE__ */ __name((hit) => Object.fromEntries(BRIEF2.flatMap((key) => hit[key] === void 0 || hit[key] === null ? [] : [[key, hit[key]]])), "briefHit");
11335
11464
 
11336
11465
  // dist/search/answers.js
11337
11466
  var named4 = /* @__PURE__ */ __name((accounts) => [
@@ -11752,29 +11881,29 @@ var showCommand = /* @__PURE__ */ __name((program, streams, env) => {
11752
11881
  }, "showCommand");
11753
11882
 
11754
11883
  // dist/sources/command.js
11755
- import { existsSync as existsSync11 } from "node:fs";
11884
+ import { existsSync as existsSync12 } from "node:fs";
11756
11885
 
11757
11886
  // dist/sources/copy.js
11758
11887
  import { randomUUID } from "node:crypto";
11759
- import { existsSync as existsSync10, mkdirSync as mkdirSync4, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync4 } from "node:fs";
11760
- import { isAbsolute, join as join13, relative as relative2, resolve as resolve5, sep as sep2 } from "node:path";
11761
- var copiesDir = /* @__PURE__ */ __name((env) => join13(resolvePaths({ appName: APP.appName, prefix: APP.envPrefix, env }).state, "sources"), "copiesDir");
11762
- var copyPath = /* @__PURE__ */ __name((env, hash) => join13(copiesDir(env), hash), "copyPath");
11888
+ import { existsSync as existsSync11, mkdirSync as mkdirSync4, renameSync as renameSync3, rmSync as rmSync3, writeFileSync as writeFileSync5 } from "node:fs";
11889
+ import { isAbsolute, join as join14, relative as relative2, resolve as resolve5, sep as sep2 } from "node:path";
11890
+ var copiesDir = /* @__PURE__ */ __name((env) => join14(resolvePaths({ appName: APP.appName, prefix: APP.envPrefix, env }).state, "sources"), "copiesDir");
11891
+ var copyPath = /* @__PURE__ */ __name((env, hash) => join14(copiesDir(env), hash), "copyPath");
11763
11892
  var keepCopy = /* @__PURE__ */ __name((env, hash, bytes) => {
11764
11893
  const path = copyPath(env, hash);
11765
- if (existsSync10(path))
11894
+ if (existsSync11(path))
11766
11895
  return { path, wrote: false };
11767
11896
  mkdirSync4(copiesDir(env), { recursive: true, mode: 448 });
11768
11897
  const partial = `${path}.${randomUUID()}.part`;
11769
- writeFileSync4(partial, bytes, { mode: 384 });
11898
+ writeFileSync5(partial, bytes, { mode: 384 });
11770
11899
  renameSync3(partial, path);
11771
11900
  return { path, wrote: true };
11772
11901
  }, "keepCopy");
11773
11902
  var dropCopy = /* @__PURE__ */ __name((env, path) => {
11774
11903
  const inside2 = relative2(resolve5(copiesDir(env)), resolve5(path));
11775
- if (!inside2 || isAbsolute(inside2) || inside2.startsWith("..") || inside2.includes(sep2) || !existsSync10(path))
11904
+ if (!inside2 || isAbsolute(inside2) || inside2.startsWith("..") || inside2.includes(sep2) || !existsSync11(path))
11776
11905
  return false;
11777
- rmSync2(path);
11906
+ rmSync3(path);
11778
11907
  return true;
11779
11908
  }, "dropCopy");
11780
11909
 
@@ -11848,7 +11977,7 @@ ${note.text}`);
11848
11977
  }, "namedIn");
11849
11978
 
11850
11979
  // dist/sources/read.js
11851
- import { readFileSync as readFileSync9, statSync as statSync5 } from "node:fs";
11980
+ import { readFileSync as readFileSync10, statSync as statSync5 } from "node:fs";
11852
11981
  import { basename as basename3, extname as extname2 } from "node:path";
11853
11982
  var SOURCE_TEXT_CHARS = 2e5;
11854
11983
  var URL_LIKE = /^[a-z][a-z0-9+.-]*:\/\//i;
@@ -11966,7 +12095,7 @@ var readFile = /* @__PURE__ */ __name(async (path, { maxChars, load = importEngi
11966
12095
  throw new CliError("validation_error", `${path} is not a file`, { path });
11967
12096
  if (stat.size > MAX_FILE_BYTES)
11968
12097
  throw tooLarge2(name2);
11969
- const bytes = new Uint8Array(readFileSync9(path));
12098
+ const bytes = new Uint8Array(readFileSync10(path));
11970
12099
  const extension = extname2(name2).toLowerCase();
11971
12100
  const mime = MIMES[extension] ?? null;
11972
12101
  const found = await extractText(bytes, { kind: "file", name: name2, mime, path }, load);
@@ -12168,7 +12297,7 @@ var sourcesCommand = /* @__PURE__ */ __name((program, streams, env, { fetch: fet
12168
12297
  mime: source?.mime ?? null,
12169
12298
  bytes: source?.size ?? null,
12170
12299
  // The row says a copy was kept; only the file itself says it still is.
12171
- kept: source === void 0 ? null : source.copy !== null && existsSync11(source.copy) ? "copy" : "text",
12300
+ kept: source === void 0 ? null : source.copy !== null && existsSync12(source.copy) ? "copy" : "text",
12172
12301
  chars: note.text.length,
12173
12302
  text: text3,
12174
12303
  textTruncated: truncated,
@@ -13294,14 +13423,19 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13294
13423
  program.addCommand(scheduleCommand(env));
13295
13424
  digestCommand(program, streams, env);
13296
13425
  commandsCommand(program, streams);
13297
- const skill2 = customizeSharedCommand(skillCommand2(APP, new URL("../skills/cli-memo/SKILL.md", new URL("../program.js", import.meta.url).href)), "Memo installs its own stored-data instructions through its environment, prints the packaged primary skill without filesystem effects, and takes --json on each skill command because it has no global one.", () => {
13426
+ const skill2 = customizeSharedCommand(skillCommand2(APP, new URL("../skills/cli-memo/SKILL.md", new URL("../program.js", import.meta.url).href)), "Memo installs its own stored-data instructions through its environment, prints the packaged skills (morning-digest with the owner's brief from the store after it), and takes --json on each skill command because it has no global one.", () => {
13298
13427
  const out = answers(program, streams, env);
13428
+ let brief;
13299
13429
  const skill3 = skillCommand(APP, new URL("../skills/cli-memo/SKILL.md", new URL("../program.js", import.meta.url).href), (command) => {
13300
13430
  const json5 = command.opts().json === true;
13301
13431
  const renderer = createRenderer({ format: json5 ? "json" : "pretty", color: false, streams });
13432
+ const result = /* @__PURE__ */ __name((value) => {
13433
+ const shown3 = value;
13434
+ out.print(true, itemAnswer(shown3.content === void 0 ? value : { ...shown3, content: withBrief(shown3.content, brief) }));
13435
+ }, "result");
13302
13436
  return {
13303
- renderer: json5 ? { ...renderer, result: /* @__PURE__ */ __name((value) => out.print(true, itemAnswer(value)), "result") } : renderer,
13304
- streams,
13437
+ renderer: json5 ? { ...renderer, result } : renderer,
13438
+ streams: { ...streams, data: /* @__PURE__ */ __name((text3) => streams.data(withBrief(text3, brief)), "data") },
13305
13439
  env
13306
13440
  };
13307
13441
  }, {
@@ -13312,8 +13446,10 @@ var createProgram = /* @__PURE__ */ __name(({ streams: raw = processStreams, env
13312
13446
  for (const command of skill3.commands)
13313
13447
  command.option("--json", "print JSON");
13314
13448
  const show = skill3.commands.find((command) => command.name() === "show");
13315
- if (show)
13316
- annotate(show, { effects: NO_EFFECTS });
13449
+ show?.description(`${show.description()}; morning-digest ends with your brief from \`memo digest brief\` when you wrote one`);
13450
+ show?.hook("preAction", async (command) => {
13451
+ brief = command.args[0] === "morning-digest" ? await readBrief(env) : void 0;
13452
+ });
13317
13453
  return skill3;
13318
13454
  }, SHELL_OVERRIDES.skill);
13319
13455
  program.addCommand(skill2);