@pcircle/memesh 4.10.1 → 4.10.2

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 (86) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/AGENTS.md +44 -13
  5. package/README.de.md +3 -3
  6. package/README.md +3 -3
  7. package/README.zh-TW.md +3 -3
  8. package/dashboard/dist/index.html +1 -1
  9. package/dist/core/agent-message-inbox.d.ts +6 -0
  10. package/dist/core/agent-message-inbox.d.ts.map +1 -1
  11. package/dist/core/agent-message-inbox.js +28 -1
  12. package/dist/core/agent-message-inbox.js.map +1 -1
  13. package/dist/core/briefing-level.d.ts +22 -0
  14. package/dist/core/briefing-level.d.ts.map +1 -0
  15. package/dist/core/briefing-level.js +75 -0
  16. package/dist/core/briefing-level.js.map +1 -0
  17. package/dist/core/briefing.d.ts +3 -0
  18. package/dist/core/briefing.d.ts.map +1 -1
  19. package/dist/core/briefing.js +33 -11
  20. package/dist/core/briefing.js.map +1 -1
  21. package/dist/core/capture-liveness.d.ts +1 -0
  22. package/dist/core/capture-liveness.d.ts.map +1 -1
  23. package/dist/core/capture-liveness.js +1 -0
  24. package/dist/core/capture-liveness.js.map +1 -1
  25. package/dist/core/config.d.ts +1 -0
  26. package/dist/core/config.d.ts.map +1 -1
  27. package/dist/core/config.js +3 -1
  28. package/dist/core/config.js.map +1 -1
  29. package/dist/core/paths.d.ts +1 -0
  30. package/dist/core/paths.d.ts.map +1 -1
  31. package/dist/core/paths.js +4 -0
  32. package/dist/core/paths.js.map +1 -1
  33. package/dist/core/schema-export.d.ts.map +1 -1
  34. package/dist/core/schema-export.js +5 -1
  35. package/dist/core/schema-export.js.map +1 -1
  36. package/dist/core/serializer.d.ts +2 -0
  37. package/dist/core/serializer.d.ts.map +1 -1
  38. package/dist/core/serializer.js +119 -6
  39. package/dist/core/serializer.js.map +1 -1
  40. package/dist/core/task-state.d.ts +5 -0
  41. package/dist/core/task-state.d.ts.map +1 -1
  42. package/dist/core/task-state.js +70 -0
  43. package/dist/core/task-state.js.map +1 -1
  44. package/dist/core/types.d.ts +2 -0
  45. package/dist/core/types.d.ts.map +1 -1
  46. package/dist/core/work-topology.d.ts +1 -0
  47. package/dist/core/work-topology.d.ts.map +1 -1
  48. package/dist/core/work-topology.js +3 -0
  49. package/dist/core/work-topology.js.map +1 -1
  50. package/dist/mcp/THIRD_PARTY_NOTICES.txt +2 -2
  51. package/dist/mcp/server.js +448 -121
  52. package/dist/mcp/server.js.map +3 -3
  53. package/dist/skills-manifest.json +29 -24
  54. package/dist/storage/fts-index.d.ts +1 -0
  55. package/dist/storage/fts-index.d.ts.map +1 -1
  56. package/dist/storage/fts-index.js +5 -0
  57. package/dist/storage/fts-index.js.map +1 -1
  58. package/dist/transports/cli/cli.d.ts.map +1 -1
  59. package/dist/transports/cli/cli.js +348 -53
  60. package/dist/transports/cli/cli.js.map +3 -3
  61. package/dist/transports/http/server.d.ts.map +1 -1
  62. package/dist/transports/http/server.js +10 -1
  63. package/dist/transports/http/server.js.map +1 -1
  64. package/dist/transports/mcp/handlers.d.ts +7 -3
  65. package/dist/transports/mcp/handlers.d.ts.map +1 -1
  66. package/dist/transports/mcp/handlers.js +7 -3
  67. package/dist/transports/mcp/handlers.js.map +1 -1
  68. package/dist/transports/schemas.d.ts +1 -0
  69. package/dist/transports/schemas.d.ts.map +1 -1
  70. package/dist/transports/schemas.js +1 -0
  71. package/dist/transports/schemas.js.map +1 -1
  72. package/docs/platforms/agent-messaging.md +17 -3
  73. package/package.json +4 -9
  74. package/scripts/hooks/_generated/agent-message-inbox.js +28 -1
  75. package/scripts/hooks/_generated/briefing-level.js +82 -0
  76. package/scripts/hooks/_generated/capture-liveness.js +1 -0
  77. package/scripts/hooks/_generated/core-paths.js +4 -0
  78. package/scripts/hooks/_generated/fts-index.js +5 -0
  79. package/scripts/hooks/_generated/task-state.js +70 -0
  80. package/scripts/hooks/_generated/work-topology.js +3 -0
  81. package/scripts/hooks/_shared.js +623 -15
  82. package/scripts/hooks/pre-edit-recall.js +386 -65
  83. package/scripts/hooks/session-start.js +261 -77
  84. package/scripts/hooks/user-prompt-intent.js +38 -6
  85. package/scripts/upgrade-plugin.sh +3 -4
  86. package/skills/memesh/SKILL.md +26 -16
@@ -5890,13 +5890,66 @@ var init_types = __esm({
5890
5890
  });
5891
5891
 
5892
5892
  // dist/core/serializer.js
5893
+ function validateFreshForgottenHashes(value) {
5894
+ if (!Array.isArray(value) || value.length === 0)
5895
+ return null;
5896
+ const deduped = [...new Set(value)];
5897
+ if (!deduped.every((h) => typeof h === "string" && FORGOTTEN_HASH_RE.test(h)))
5898
+ return null;
5899
+ return deduped.length <= MAX_IMPORTED_FORGOTTEN_HASHES ? deduped : null;
5900
+ }
5901
+ function validateFreshSignalScore(value) {
5902
+ return typeof value === "number" && value >= 0 && value <= 1 ? value : null;
5903
+ }
5904
+ function isPlainObject(value) {
5905
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5906
+ }
5907
+ function isValidReplacedHistoryEntry(entry) {
5908
+ if (!isPlainObject(entry))
5909
+ return false;
5910
+ for (const key of Object.keys(entry)) {
5911
+ if (!REPLACED_HISTORY_ENTRY_KEYS.has(key))
5912
+ return false;
5913
+ }
5914
+ if (typeof entry.replaced_at !== "string" || entry.replaced_at.length > 64)
5915
+ return false;
5916
+ if (!(entry.title === null || typeof entry.title === "string" && entry.title.length <= 500))
5917
+ return false;
5918
+ if (!Array.isArray(entry.observations) || !entry.observations.every((o) => typeof o === "string"))
5919
+ return false;
5920
+ if (!Array.isArray(entry.tags) || !entry.tags.every((t) => typeof t === "string"))
5921
+ return false;
5922
+ if ("truncated" in entry && typeof entry.truncated !== "boolean")
5923
+ return false;
5924
+ return true;
5925
+ }
5926
+ function validateFreshReplacedHistory(value) {
5927
+ if (!Array.isArray(value) || value.length === 0)
5928
+ return null;
5929
+ if (value.length > MAX_IMPORTED_REPLACED_HISTORY_ENTRIES)
5930
+ return null;
5931
+ if (!value.every(isValidReplacedHistoryEntry))
5932
+ return null;
5933
+ return jsonBytesOf(value) <= MAX_IMPORTED_REPLACED_HISTORY_TOTAL_BYTES ? value : null;
5934
+ }
5893
5935
  function buildImportedMetadata(existingMetadata, args) {
5894
- const { guard: _guard, ...bundledSafe } = args.bundled ?? {};
5895
- void _guard;
5936
+ const bundled = args.bundled ?? {};
5937
+ const bundledSafe = {};
5938
+ for (const [key, value] of Object.entries(bundled)) {
5939
+ if (IMPORTABLE_METADATA_KEYS.has(key))
5940
+ bundledSafe[key] = value;
5941
+ }
5942
+ const freshForgottenHashes = args.isNewEntity ? validateFreshForgottenHashes(bundled.forgotten_observation_hashes) : null;
5943
+ const freshPin = args.isNewEntity && bundled.pin === true;
5944
+ const freshSignalScore = args.isNewEntity ? validateFreshSignalScore(bundled.signal_score) : null;
5945
+ const freshReplacedHistory = args.isNewEntity ? validateFreshReplacedHistory(bundled.replaced_history) : null;
5896
5946
  return {
5897
5947
  ...existingMetadata ?? {},
5898
5948
  ...bundledSafe,
5899
- ...Array.isArray(existingMetadata?.forgotten_observation_hashes) ? { forgotten_observation_hashes: existingMetadata.forgotten_observation_hashes } : {},
5949
+ ...freshForgottenHashes ? { forgotten_observation_hashes: freshForgottenHashes } : {},
5950
+ ...freshSignalScore !== null ? { signal_score: freshSignalScore } : {},
5951
+ ...freshPin ? { pin: true } : {},
5952
+ ...freshReplacedHistory ? { replaced_history: freshReplacedHistory } : {},
5900
5953
  trust: "untrusted",
5901
5954
  provenance: {
5902
5955
  ...existingMetadata?.provenance ?? {},
@@ -5965,6 +6018,12 @@ function importMemories(args) {
5965
6018
  if (!MERGE_STRATEGIES.includes(args.merge_strategy)) {
5966
6019
  throw new Error(`Unknown merge strategy "${args.merge_strategy}". Use one of: ${MERGE_STRATEGIES.join(", ")}. Nothing was imported \u2014 refusing rather than guessing, because the wrong guess overwrites existing memories.`);
5967
6020
  }
6021
+ if (args.restore_archived !== void 0 && typeof args.restore_archived !== "boolean") {
6022
+ throw new Error('restore_archived must be the boolean true or false. Nothing was imported \u2014 refusing rather than guessing, because "yes" brings back memories the user forgot.');
6023
+ }
6024
+ if (args.restore_archived === true && args.merge_strategy === "skip") {
6025
+ throw new Error('restore_archived (--restore-archived) only applies with merge strategy "append" or "overwrite"; "skip" leaves every existing entity untouched, so there is nothing to restore. Nothing was imported.');
6026
+ }
5968
6027
  if (args.namespace !== void 0 && !NAMESPACES.includes(args.namespace)) {
5969
6028
  throw new Error(`Unknown namespace "${args.namespace}". Use one of: ${NAMESPACES.join(", ")}. Nothing was imported \u2014 an unrecognised namespace would move existing memories somewhere nothing queries.`);
5970
6029
  }
@@ -5979,6 +6038,7 @@ function importMemories(args) {
5979
6038
  const pendingRelations = [];
5980
6039
  let skipped = 0;
5981
6040
  let appended = 0;
6041
+ let keptArchived = 0;
5982
6042
  const errors = [];
5983
6043
  const skippedRelations = [];
5984
6044
  const setCreatedAt = db2.prepare("UPDATE entities SET created_at = ? WHERE name = ?");
@@ -5999,11 +6059,14 @@ function importMemories(args) {
5999
6059
  bundled: entity.metadata,
6000
6060
  exportedAt: args.data.exported_at,
6001
6061
  importVersion: args.data.version,
6002
- mergeStrategy: args.merge_strategy
6062
+ mergeStrategy: args.merge_strategy,
6063
+ isNewEntity: !existing
6003
6064
  });
6004
6065
  if (existing) {
6005
6066
  if (args.merge_strategy === "skip")
6006
6067
  return { kind: "skipped" };
6068
+ if (existing.archived && args.restore_archived !== true)
6069
+ return { kind: "keptArchived" };
6007
6070
  if (args.merge_strategy === "append") {
6008
6071
  const existingText = new Set(existing.observations);
6009
6072
  const newObservations = (entity.observations ?? []).filter((o) => !existingText.has(o));
@@ -6052,6 +6115,8 @@ function importMemories(args) {
6052
6115
  }).immediate();
6053
6116
  if (outcome.kind === "skipped")
6054
6117
  skipped++;
6118
+ else if (outcome.kind === "keptArchived")
6119
+ keptArchived++;
6055
6120
  else if (outcome.kind === "appended")
6056
6121
  appended++;
6057
6122
  else {
@@ -6075,9 +6140,9 @@ function importMemories(args) {
6075
6140
  errors.push(`${rel.from} -${rel.type}-> ${rel.to}: relation not restored (${err instanceof Error ? err.message : String(err)})`);
6076
6141
  }
6077
6142
  }
6078
- return { imported, overwritten, skipped, appended, errors, skipped_relations: skippedRelations };
6143
+ return { imported, overwritten, skipped, appended, kept_archived: keptArchived, errors, skipped_relations: skippedRelations };
6079
6144
  }
6080
- var MERGE_STRATEGIES;
6145
+ var IMPORTABLE_METADATA_KEYS, FORGOTTEN_HASH_RE, MAX_IMPORTED_FORGOTTEN_HASHES, MAX_IMPORTED_REPLACED_HISTORY_ENTRIES, MAX_IMPORTED_REPLACED_HISTORY_TOTAL_BYTES, REPLACED_HISTORY_ENTRY_KEYS, jsonBytesOf, MERGE_STRATEGIES;
6081
6146
  var init_serializer = __esm({
6082
6147
  "dist/core/serializer.js"() {
6083
6148
  "use strict";
@@ -6086,6 +6151,38 @@ var init_serializer = __esm({
6086
6151
  init_title();
6087
6152
  init_time_utils();
6088
6153
  init_types();
6154
+ IMPORTABLE_METADATA_KEYS = /* @__PURE__ */ new Set([
6155
+ "title_source",
6156
+ "source_kind",
6157
+ "source",
6158
+ "cluster_key",
6159
+ "dreamed_at",
6160
+ "kind",
6161
+ "project",
6162
+ "previous_namespace",
6163
+ "namespace_moved_at",
6164
+ "split_from",
6165
+ "retired_recall",
6166
+ "priority",
6167
+ "success_criteria",
6168
+ "verification_scenario",
6169
+ "implementation_state",
6170
+ "outcome_state",
6171
+ "accepted_at",
6172
+ "source_ids"
6173
+ ]);
6174
+ FORGOTTEN_HASH_RE = /^[a-f0-9]{64}$/;
6175
+ MAX_IMPORTED_FORGOTTEN_HASHES = 1e3;
6176
+ MAX_IMPORTED_REPLACED_HISTORY_ENTRIES = 50;
6177
+ MAX_IMPORTED_REPLACED_HISTORY_TOTAL_BYTES = 4 * 64 * 1024;
6178
+ REPLACED_HISTORY_ENTRY_KEYS = /* @__PURE__ */ new Set([
6179
+ "replaced_at",
6180
+ "title",
6181
+ "observations",
6182
+ "tags",
6183
+ "truncated"
6184
+ ]);
6185
+ jsonBytesOf = (v) => Buffer.byteLength(JSON.stringify(v), "utf8");
6089
6186
  MERGE_STRATEGIES = ["skip", "overwrite", "append"];
6090
6187
  }
6091
6188
  });
@@ -6417,6 +6514,8 @@ function selectConfig(raw) {
6417
6514
  config2.updateCheck = raw.updateCheck;
6418
6515
  if (typeof raw.setupCompleted === "boolean")
6419
6516
  config2.setupCompleted = raw.setupCompleted;
6517
+ if (raw.briefing !== void 0)
6518
+ config2.briefing = raw.briefing;
6420
6519
  return config2;
6421
6520
  }
6422
6521
  function findRetiredConfigKeys(raw) {
@@ -6469,7 +6568,7 @@ var init_config = __esm({
6469
6568
  "dist/core/config.js"() {
6470
6569
  "use strict";
6471
6570
  init_paths();
6472
- CONFIG_KEYS = ["autoCapture", "sessionLimit", "autoUpdate", "updateCheck", "setupCompleted"];
6571
+ CONFIG_KEYS = ["autoCapture", "sessionLimit", "autoUpdate", "updateCheck", "setupCompleted", "briefing"];
6473
6572
  RETIRED_CONFIG_KEYS = [
6474
6573
  "llm",
6475
6574
  "llmFallbacks",
@@ -7365,7 +7464,7 @@ __export(util_exports, {
7365
7464
  getSizableOrigin: () => getSizableOrigin,
7366
7465
  hexToUint8Array: () => hexToUint8Array,
7367
7466
  isObject: () => isObject,
7368
- isPlainObject: () => isPlainObject,
7467
+ isPlainObject: () => isPlainObject2,
7369
7468
  issue: () => issue,
7370
7469
  joinValues: () => joinValues,
7371
7470
  jsonStringifyReplacer: () => jsonStringifyReplacer,
@@ -7527,7 +7626,7 @@ function slugify2(input) {
7527
7626
  function isObject(data) {
7528
7627
  return typeof data === "object" && data !== null && !Array.isArray(data);
7529
7628
  }
7530
- function isPlainObject(o) {
7629
+ function isPlainObject2(o) {
7531
7630
  if (isObject(o) === false)
7532
7631
  return false;
7533
7632
  const ctor = o.constructor;
@@ -7544,7 +7643,7 @@ function isPlainObject(o) {
7544
7643
  return true;
7545
7644
  }
7546
7645
  function shallowClone(o) {
7547
- if (isPlainObject(o))
7646
+ if (isPlainObject2(o))
7548
7647
  return { ...o };
7549
7648
  if (Array.isArray(o))
7550
7649
  return [...o];
@@ -7684,7 +7783,7 @@ function omit(schema, mask) {
7684
7783
  return clone(schema, def);
7685
7784
  }
7686
7785
  function extend(schema, shape) {
7687
- if (!isPlainObject(shape)) {
7786
+ if (!isPlainObject2(shape)) {
7688
7787
  throw new Error("Invalid input to extend: expected a plain object");
7689
7788
  }
7690
7789
  const checks = schema._zod.def.checks;
@@ -7707,7 +7806,7 @@ function extend(schema, shape) {
7707
7806
  return clone(schema, def);
7708
7807
  }
7709
7808
  function safeExtend(schema, shape) {
7710
- if (!isPlainObject(shape)) {
7809
+ if (!isPlainObject2(shape)) {
7711
7810
  throw new Error("Invalid input to safeExtend: expected a plain object");
7712
7811
  }
7713
7812
  const def = mergeDefs(schema._zod.def, {
@@ -9225,7 +9324,7 @@ function mergeValues(a, b) {
9225
9324
  if (a instanceof Date && b instanceof Date && +a === +b) {
9226
9325
  return { valid: true, data: a };
9227
9326
  }
9228
- if (isPlainObject(a) && isPlainObject(b)) {
9327
+ if (isPlainObject2(a) && isPlainObject2(b)) {
9229
9328
  const bKeys = Object.keys(b);
9230
9329
  const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
9231
9330
  const newObj = { ...a, ...b };
@@ -10492,7 +10591,7 @@ var init_schemas = __esm({
10492
10591
  $ZodType.init(inst, def);
10493
10592
  inst._zod.parse = (payload, ctx) => {
10494
10593
  const input = payload.value;
10495
- if (!isPlainObject(input)) {
10594
+ if (!isPlainObject2(input)) {
10496
10595
  payload.issues.push({
10497
10596
  expected: "record",
10498
10597
  code: "invalid_type",
@@ -23254,7 +23353,7 @@ function parseTargetKind(value) {
23254
23353
  }
23255
23354
  function parseJsonObject(json2, label) {
23256
23355
  const parsed = parseJsonObjectOrValue(json2);
23257
- if (!isPlainObject2(parsed))
23356
+ if (!isPlainObject3(parsed))
23258
23357
  throw new AgentMessagingError(`${label} must contain a JSON object.`);
23259
23358
  return parsed;
23260
23359
  }
@@ -23304,7 +23403,7 @@ function assertJsonValue(value, label) {
23304
23403
  value.forEach((entry, index) => assertJsonValue(entry, `${label}[${index}]`));
23305
23404
  return;
23306
23405
  }
23307
- if (isPlainObject2(value)) {
23406
+ if (isPlainObject3(value)) {
23308
23407
  for (const [key, entry] of Object.entries(value)) {
23309
23408
  assertJsonValue(entry, `${label}.${key}`);
23310
23409
  }
@@ -23316,7 +23415,7 @@ function normalizeObject(value) {
23316
23415
  assertJsonValue(value, "object");
23317
23416
  return value;
23318
23417
  }
23319
- function isPlainObject2(value) {
23418
+ function isPlainObject3(value) {
23320
23419
  return typeof value === "object" && value !== null && !Array.isArray(value);
23321
23420
  }
23322
23421
  function requireText(label, value, maxLength) {
@@ -23527,7 +23626,8 @@ var init_schemas3 = __esm({
23527
23626
  ImportSchema = external_exports.object({
23528
23627
  data: ExportResultSchema,
23529
23628
  namespace: external_exports.enum(NAMESPACES).optional(),
23530
- merge_strategy: external_exports.enum(["skip", "overwrite", "append"])
23629
+ merge_strategy: external_exports.enum(["skip", "overwrite", "append"]),
23630
+ restore_archived: external_exports.boolean().optional()
23531
23631
  }).strict();
23532
23632
  LearnSchema = external_exports.object({
23533
23633
  error: external_exports.string().min(1).max(5e3),
@@ -23808,7 +23908,73 @@ function taskStateLines(state, project, now = /* @__PURE__ */ new Date()) {
23808
23908
  }
23809
23909
  return lines;
23810
23910
  }
23811
- var TASK_STATE_TYPE, TASK_STATE_FIELDS, MAX_FIELD_CHARS, FIELD_LABELS;
23911
+ function isLeapYear(year) {
23912
+ return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
23913
+ }
23914
+ function daysInMonth(year, month) {
23915
+ return month === 2 && isLeapYear(year) ? 29 : DAYS_IN_MONTH[month - 1];
23916
+ }
23917
+ function isRealInstant(groups) {
23918
+ const year = Number(groups.year);
23919
+ const month = Number(groups.month);
23920
+ const day = Number(groups.day);
23921
+ const hour = Number(groups.hour);
23922
+ const minute = Number(groups.minute);
23923
+ const second = groups.second === void 0 ? 0 : Number(groups.second);
23924
+ if (month < 1 || month > 12)
23925
+ return false;
23926
+ if (day < 1 || day > daysInMonth(year, month))
23927
+ return false;
23928
+ if (hour > 23)
23929
+ return false;
23930
+ if (minute > 59)
23931
+ return false;
23932
+ if (second > 59)
23933
+ return false;
23934
+ if (groups.zulu === void 0) {
23935
+ const offHour = Number(groups.offHour);
23936
+ const offMinute = Number(groups.offMinute);
23937
+ if (offHour > 23 || offMinute > 59)
23938
+ return false;
23939
+ if (groups.offSign === "-" && offHour === 0 && offMinute === 0)
23940
+ return false;
23941
+ }
23942
+ return true;
23943
+ }
23944
+ function resolveTaskStateAge(updatedAt, now) {
23945
+ if (!updatedAt)
23946
+ return { known: false };
23947
+ const match = ZONED_INSTANT.exec(updatedAt);
23948
+ if (!match?.groups || !isRealInstant(match.groups))
23949
+ return { known: false };
23950
+ const then = Date.parse(updatedAt);
23951
+ if (Number.isNaN(then))
23952
+ return { known: false };
23953
+ const hours = (now.getTime() - then) / 36e5;
23954
+ if (hours < -(CLOCK_SKEW_ALLOWANCE_MINUTES / 60))
23955
+ return { known: false };
23956
+ return { known: true, hours: Math.max(0, hours) };
23957
+ }
23958
+ function staleTaskStateLine(project, hours) {
23959
+ const days = Math.floor(hours / 24);
23960
+ const age = days >= 1 ? `${days} day${days === 1 ? "" : "s"} ago` : `${Math.floor(hours)} hour${Math.floor(hours) === 1 ? "" : "s"} ago`;
23961
+ return `Task state for "${project}" was last stated ${age} \u2014 older than ${STALE_TASK_STATE_HOURS}h, so it is not shown as current. Run \`memesh task\` to see or update it.`;
23962
+ }
23963
+ function taskStateAgeUnknownLine(project) {
23964
+ return `Task state for "${project}" has a missing, unreadable, or future-dated timestamp, so its age could not be established \u2014 not shown as current. Run \`memesh task\` to see or update it.`;
23965
+ }
23966
+ function briefingTaskStateLines(state, project, now = /* @__PURE__ */ new Date(), { includeFresh = true } = {}) {
23967
+ if (isEmptyTaskState(state))
23968
+ return [];
23969
+ const age = resolveTaskStateAge(state.updated_at, now);
23970
+ if (!age.known)
23971
+ return [taskStateAgeUnknownLine(project)];
23972
+ if (age.hours > STALE_TASK_STATE_HOURS) {
23973
+ return [staleTaskStateLine(project, age.hours)];
23974
+ }
23975
+ return includeFresh ? taskStateLines(state, project, now) : [];
23976
+ }
23977
+ var TASK_STATE_TYPE, TASK_STATE_FIELDS, MAX_FIELD_CHARS, FIELD_LABELS, STALE_TASK_STATE_HOURS, CLOCK_SKEW_ALLOWANCE_MINUTES, ZONED_INSTANT, DAYS_IN_MONTH;
23812
23978
  var init_task_state = __esm({
23813
23979
  "dist/core/task-state.js"() {
23814
23980
  "use strict";
@@ -23821,6 +23987,10 @@ var init_task_state = __esm({
23821
23987
  blocked: "Blocked",
23822
23988
  done: "Had just finished"
23823
23989
  };
23990
+ STALE_TASK_STATE_HOURS = 72;
23991
+ CLOCK_SKEW_ALLOWANCE_MINUTES = 5;
23992
+ ZONED_INSTANT = /^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})[Tt](?<hour>\d{2}):(?<minute>\d{2})(?::(?<second>\d{2})(?:\.\d+)?)?(?:(?<zulu>[Zz])|(?<offSign>[+-])(?<offHour>\d{2}):?(?<offMinute>\d{2}))$/;
23993
+ DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
23824
23994
  }
23825
23995
  });
23826
23996
 
@@ -23927,7 +24097,7 @@ function unreadInboxLines(count, project, recipient, everSeen) {
23927
24097
  const displayRecipient = JSON.stringify(recipient);
23928
24098
  if (count > 0) {
23929
24099
  const noun = count === 1 ? "message" : "messages";
23930
- return [`${count} ${noun} waiting for ${displayRecipient} in project ${displayProject} \u2014 poll the message tool with project ${displayProject} and recipient ${displayRecipient}, then fetch each message_id; fetching does not acknowledge.`];
24100
+ return [`${count} ${noun} waiting for ${displayRecipient} in project ${displayProject} \u2014 poll the message tool with project ${displayProject} and recipient ${displayRecipient}, then fetch each message_id and record the intake action for it: fetching alone does not acknowledge, and only intake ends this line.`];
23931
24101
  }
23932
24102
  if (everSeen === false) {
23933
24103
  return [`No messages waiting for ${displayRecipient} in project ${displayProject} \u2014 and this recipient id has never been seen in this project (check for a typo).`];
@@ -24090,6 +24260,9 @@ function assembleTopologyBlock(stateLines, pools, projectName, budget = DEFAULT_
24090
24260
  lines.push(...globalLines);
24091
24261
  return lines;
24092
24262
  }
24263
+ function hasBriefingContent(lines) {
24264
+ return lines.length > 0;
24265
+ }
24093
24266
  function buildReferenceContext(memoryLines) {
24094
24267
  const safeLines = memoryLines.map((line) => String(line ?? "").replace(/[\s\u0085\u001c-\u001e]+/g, " ").trim());
24095
24268
  let longestRun = 0;
@@ -24293,6 +24466,85 @@ var init_briefing_index = __esm({
24293
24466
  }
24294
24467
  });
24295
24468
 
24469
+ // dist/core/briefing-level.js
24470
+ function isBriefingLevel(value) {
24471
+ return typeof value === "string" && BRIEFING_LEVELS.includes(value);
24472
+ }
24473
+ function safeRawPreSlice(value, maxUnits) {
24474
+ if (value.length <= maxUnits)
24475
+ return value;
24476
+ let end = maxUnits;
24477
+ const lastKept = value.charCodeAt(end - 1);
24478
+ const nextUnit = value.charCodeAt(end);
24479
+ const lastKeptIsHighSurrogate = lastKept >= 55296 && lastKept <= 56319;
24480
+ const nextUnitIsLowSurrogate = nextUnit >= 56320 && nextUnit <= 57343;
24481
+ if (lastKeptIsHighSurrogate && nextUnitIsLowSurrogate)
24482
+ end -= 1;
24483
+ return value.slice(0, end);
24484
+ }
24485
+ function truncateToSerializedBound(codePoints) {
24486
+ let kept = 0;
24487
+ for (; kept < codePoints.length; kept++) {
24488
+ const candidate = JSON.stringify(`${codePoints.slice(0, kept + 1).join("")}\u2026`);
24489
+ if (candidate.length > INVALID_VALUE_SERIALIZED_MAX)
24490
+ break;
24491
+ }
24492
+ return JSON.stringify(`${codePoints.slice(0, kept).join("")}\u2026`);
24493
+ }
24494
+ function describeInvalidValue(value) {
24495
+ if (typeof value === "string") {
24496
+ if (value.length <= INVALID_VALUE_SERIALIZED_MAX) {
24497
+ const whole = JSON.stringify(value);
24498
+ if (whole.length <= INVALID_VALUE_SERIALIZED_MAX)
24499
+ return whole;
24500
+ return truncateToSerializedBound(Array.from(value));
24501
+ }
24502
+ return truncateToSerializedBound(Array.from(safeRawPreSlice(value, PRE_SLICE_RAW_MAX)));
24503
+ }
24504
+ if (Array.isArray(value))
24505
+ return "[array]";
24506
+ if (value !== null && typeof value === "object")
24507
+ return "[object]";
24508
+ if (typeof value === "bigint")
24509
+ return "[bigint]";
24510
+ if (typeof value === "symbol")
24511
+ return "[symbol]";
24512
+ if (typeof value === "function")
24513
+ return "[function]";
24514
+ return JSON.stringify(value) ?? String(value);
24515
+ }
24516
+ function resolveBriefingLevel(envValue, configValue) {
24517
+ if (envValue !== void 0) {
24518
+ if (isBriefingLevel(envValue))
24519
+ return { level: envValue, invalid: null };
24520
+ return { level: DEFAULT_BRIEFING_LEVEL, invalid: { source: "env", value: describeInvalidValue(envValue) } };
24521
+ }
24522
+ if (configValue !== void 0) {
24523
+ if (isBriefingLevel(configValue))
24524
+ return { level: configValue, invalid: null };
24525
+ return { level: DEFAULT_BRIEFING_LEVEL, invalid: { source: "config", value: describeInvalidValue(configValue) } };
24526
+ }
24527
+ return { level: DEFAULT_BRIEFING_LEVEL, invalid: null };
24528
+ }
24529
+ function briefingLevelPolicy(level) {
24530
+ return POLICIES[level];
24531
+ }
24532
+ var BRIEFING_LEVELS, DEFAULT_BRIEFING_LEVEL, INVALID_VALUE_SERIALIZED_MAX, PRE_SLICE_RAW_MAX, POLICIES;
24533
+ var init_briefing_level = __esm({
24534
+ "dist/core/briefing-level.js"() {
24535
+ "use strict";
24536
+ BRIEFING_LEVELS = ["minimal", "standard", "full"];
24537
+ DEFAULT_BRIEFING_LEVEL = "standard";
24538
+ INVALID_VALUE_SERIALIZED_MAX = 100;
24539
+ PRE_SLICE_RAW_MAX = 256;
24540
+ POLICIES = {
24541
+ minimal: { global: false, foreign: false, taskState: false, index: false, workPackageNotice: false },
24542
+ standard: { global: false, foreign: false, taskState: true, index: true, workPackageNotice: false },
24543
+ full: { global: true, foreign: true, taskState: true, index: true, workPackageNotice: true }
24544
+ };
24545
+ }
24546
+ });
24547
+
24296
24548
  // dist/core/briefing.js
24297
24549
  function parseMetadata(raw) {
24298
24550
  if (!raw)
@@ -24358,10 +24610,23 @@ function readBriefingIndex(db2, projectName, now = Date.now()) {
24358
24610
  function assembleBriefing(project, recipient) {
24359
24611
  const projectName = project ?? getProjectName();
24360
24612
  const db2 = getDatabase();
24613
+ const resolvedLevel = resolveBriefingLevel(process.env.MEMESH_BRIEFING, readConfig().briefing);
24614
+ if (resolvedLevel.invalid) {
24615
+ const { source, value } = resolvedLevel.invalid;
24616
+ try {
24617
+ process.stderr.write(`[memesh briefing] invalid ${source} briefing level ${value} \u2014 using "${resolvedLevel.level}"
24618
+ `);
24619
+ } catch {
24620
+ }
24621
+ }
24622
+ const level = resolvedLevel.level;
24623
+ const policy = briefingLevelPolicy(level);
24361
24624
  const repoLines = project === void 0 || project === getProjectName() ? repoStateLines(readRepoState()) : [];
24362
24625
  let taskLines;
24363
24626
  try {
24364
- taskLines = taskStateLines(getTaskState(projectName).state, projectName);
24627
+ taskLines = briefingTaskStateLines(getTaskState(projectName).state, projectName, /* @__PURE__ */ new Date(), {
24628
+ includeFresh: policy.taskState
24629
+ });
24365
24630
  } catch (err) {
24366
24631
  if (!(err instanceof TaskStateUnreadableError))
24367
24632
  throw err;
@@ -24382,17 +24647,17 @@ function assembleBriefing(project, recipient) {
24382
24647
  ORDER BY e.id DESC
24383
24648
  LIMIT ?`).all(`project:${projectName}`, TOPOLOGY_CANDIDATE_CAP);
24384
24649
  const projectPool = selectPool(projectRows, PROJECT_LIMIT);
24385
- const globalRows = hasNamespace ? db2.prepare(`SELECT ${CANDIDATE_COLUMNS}
24650
+ const globalRows = policy.global && hasNamespace ? db2.prepare(`SELECT ${CANDIDATE_COLUMNS}
24386
24651
  FROM entities e
24387
24652
  WHERE e.namespace = 'global' AND e.status = 'active'
24388
24653
  ORDER BY e.id DESC
24389
24654
  LIMIT ?`).all(TOPOLOGY_CANDIDATE_CAP) : [];
24390
24655
  const globalPool = selectPool(globalRows, GLOBAL_TOPOLOGY_LIMIT);
24391
- const recentRows = db2.prepare(`SELECT ${CANDIDATE_COLUMNS}
24392
- FROM entities e
24393
- WHERE e.status = 'active'${nonGlobal}
24394
- ORDER BY e.id DESC
24395
- LIMIT ?`).all(TOPOLOGY_CANDIDATE_CAP);
24656
+ const recentRows = policy.foreign ? db2.prepare(`SELECT ${CANDIDATE_COLUMNS}
24657
+ FROM entities e
24658
+ WHERE e.status = 'active'${nonGlobal}
24659
+ ORDER BY e.id DESC
24660
+ LIMIT ?`).all(TOPOLOGY_CANDIDATE_CAP) : [];
24396
24661
  const recentPool = selectPool(recentRows, RECENT_LIMIT);
24397
24662
  const survivorIds = [...new Set([...projectPool, ...globalPool, ...recentPool].map((row) => row.id))];
24398
24663
  const snippets = /* @__PURE__ */ new Map();
@@ -24417,13 +24682,17 @@ function assembleBriefing(project, recipient) {
24417
24682
  ], projectName);
24418
24683
  const withRepo = lines.length > 0 && repoLines.length > 0 ? [...repoLines, "", ...lines] : lines;
24419
24684
  const index = readBriefingIndex(db2, projectName);
24420
- const block = withRepo.length > 0 ? [...withRepo, "", ...index.lines] : index.lines;
24685
+ const indexLines = policy.index ? index.lines : [];
24686
+ const block = withRepo.length > 0 && indexLines.length > 0 ? [...withRepo, "", ...indexLines] : [...withRepo, ...indexLines];
24687
+ const empty = !hasBriefingContent(block);
24421
24688
  return {
24422
24689
  project: projectName,
24423
- text: buildReferenceContext(block),
24690
+ text: empty ? "" : buildReferenceContext(block),
24424
24691
  entityCount: lines.filter((l) => l.startsWith("- [")).length,
24425
24692
  hasTaskState: stateLines.length > 0,
24426
- index
24693
+ index,
24694
+ level,
24695
+ empty
24427
24696
  };
24428
24697
  }
24429
24698
  var PROJECT_LIMIT, RECENT_LIMIT, CANDIDATE_COLUMNS;
@@ -24432,6 +24701,7 @@ var init_briefing = __esm({
24432
24701
  "use strict";
24433
24702
  init_db();
24434
24703
  init_paths();
24704
+ init_config();
24435
24705
  init_repo_state();
24436
24706
  init_scoring();
24437
24707
  init_task_state_store();
@@ -24440,6 +24710,7 @@ var init_briefing = __esm({
24440
24710
  init_task_state();
24441
24711
  init_briefing_index();
24442
24712
  init_work_topology();
24713
+ init_briefing_level();
24443
24714
  PROJECT_LIMIT = 30;
24444
24715
  RECENT_LIMIT = 5;
24445
24716
  CANDIDATE_COLUMNS = "e.id, e.name, e.type, e.title, e.metadata, e.access_count, e.last_accessed_at, e.confidence, e.recall_hits, e.recall_misses";
@@ -24791,9 +25062,9 @@ import fs15 from "node:fs";
24791
25062
  import net from "node:net";
24792
25063
  import path14 from "node:path";
24793
25064
  function isLegacyAgentRouterVersionMismatchResponse(value) {
24794
- if (!isPlainObject3(value) || value.version !== 1 || value.request_id !== "" || value.ok !== false)
25065
+ if (!isPlainObject4(value) || value.version !== 1 || value.request_id !== "" || value.ok !== false)
24795
25066
  return false;
24796
- if (!isPlainObject3(value.error))
25067
+ if (!isPlainObject4(value.error))
24797
25068
  return false;
24798
25069
  return value.error.code === "unsupported_type" || value.error.code === "unsupported_version";
24799
25070
  }
@@ -24852,7 +25123,7 @@ async function sendAgentRouterRequest(socketPath, request, timeoutMs = DEFAULT_C
24852
25123
  if (isLegacyAgentRouterVersionMismatchResponse(response)) {
24853
25124
  throw new AgentRouterProtocolError("router_version_mismatch", "router_version_mismatch: the configured router endpoint uses a stale protocol; restart that router with the current MeMesh version.");
24854
25125
  }
24855
- const uncorrelatedError = response.request_id === "" && response.ok === false && isPlainObject3(response.error) && typeof response.error.code === "string" && typeof response.error.message === "string";
25126
+ const uncorrelatedError = response.request_id === "" && response.ok === false && isPlainObject4(response.error) && typeof response.error.code === "string" && typeof response.error.message === "string";
24856
25127
  if (response.version !== AGENT_ROUTER_PROTOCOL_VERSION || response.request_id !== request.request_id && !uncorrelatedError) {
24857
25128
  throw new AgentRouterProtocolError("invalid_response", "Router response identity does not match.");
24858
25129
  }
@@ -24871,7 +25142,7 @@ async function sendAgentRouterRequest(socketPath, request, timeoutMs = DEFAULT_C
24871
25142
  });
24872
25143
  }
24873
25144
  function validateRouterSuccessResult(request, value) {
24874
- if (!isPlainObject3(value)) {
25145
+ if (!isPlainObject4(value)) {
24875
25146
  throw new AgentRouterProtocolError("invalid_response", "Router response result must be an object.");
24876
25147
  }
24877
25148
  const requireResultString = (field) => {
@@ -24929,7 +25200,7 @@ function validateRouterSuccessResult(request, value) {
24929
25200
  return value;
24930
25201
  }
24931
25202
  function isSelectionCard(value, project) {
24932
- if (!isPlainObject3(value))
25203
+ if (!isPlainObject4(value))
24933
25204
  return false;
24934
25205
  return typeof value.session_id === "string" && typeof value.principal_id === "string" && ["codex", "claude", "gemini", "other"].includes(String(value.host_kind)) && value.project === project && (value.model === null || typeof value.model === "string") && (value.work_summary === null || typeof value.work_summary === "string") && value.active === true && Number.isSafeInteger(value.generation) && value.generation >= 1 && Number.isSafeInteger(value.lease_expires_at_ms) && value.lease_expires_at_ms >= 0;
24935
25206
  }
@@ -24939,7 +25210,7 @@ function validateSocketPath(socketPath) {
24939
25210
  }
24940
25211
  return socketPath;
24941
25212
  }
24942
- function isPlainObject3(value) {
25213
+ function isPlainObject4(value) {
24943
25214
  return typeof value === "object" && value !== null && !Array.isArray(value);
24944
25215
  }
24945
25216
  var AGENT_ROUTER_PROTOCOL_VERSION, AGENT_ROUTER_MAX_FRAME_BYTES, MAX_LEASE_MS, DEFAULT_CLIENT_TIMEOUT_MS, MAX_FIELD_LENGTH, MAX_ADAPTER_RECEIPT_BYTES, AgentRouterError, AgentRouterProtocolError;
@@ -25710,6 +25981,10 @@ function exportOpenAITools() {
25710
25981
  type: "string",
25711
25982
  enum: ["skip", "overwrite", "append"],
25712
25983
  description: "Required. How to handle existing entities: skip, overwrite (replace), or append (merge observations)."
25984
+ },
25985
+ restore_archived: {
25986
+ type: "boolean",
25987
+ description: "Optional, default false. With append or overwrite, an archived (forgotten) local entity is left untouched and counted in kept_archived; true brings it back to active and merges or overwrites it, and requires append or overwrite (an error with skip)."
25713
25988
  }
25714
25989
  },
25715
25990
  required: ["data", "merge_strategy"]
@@ -25755,7 +26030,7 @@ function exportOpenAITools() {
25755
26030
  type: "function",
25756
26031
  function: {
25757
26032
  name: "memesh_briefing",
25758
- description: "The assembled work topology for a project: where the work was left off, decisions, lessons, knowledge, recent activity. Call once at the start of a session to load project context.",
26033
+ description: "The assembled work topology for a project: where the work was left off (by default), decisions, lessons, knowledge, recent activity. Call once at the start of a session to load project context.",
25759
26034
  parameters: {
25760
26035
  type: "object",
25761
26036
  properties: {
@@ -42232,10 +42507,10 @@ var require_object_inspect = __commonJS({
42232
42507
  }
42233
42508
  if (!isDate(obj) && !isRegExp(obj)) {
42234
42509
  var ys = arrObjKeys(obj, inspect);
42235
- var isPlainObject4 = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object;
42510
+ var isPlainObject5 = gPO ? gPO(obj) === Object.prototype : obj instanceof Object || obj.constructor === Object;
42236
42511
  var protoTag = obj instanceof Object ? "" : "null prototype";
42237
- var stringTag = !isPlainObject4 && toStringTag && Object(obj) === obj && toStringTag in obj ? $slice.call(toStr(obj), 8, -1) : protoTag ? "Object" : "";
42238
- var constructorTag = isPlainObject4 || typeof obj.constructor !== "function" ? "" : obj.constructor.name ? obj.constructor.name + " " : "";
42512
+ var stringTag = !isPlainObject5 && toStringTag && Object(obj) === obj && toStringTag in obj ? $slice.call(toStr(obj), 8, -1) : protoTag ? "Object" : "";
42513
+ var constructorTag = isPlainObject5 || typeof obj.constructor !== "function" ? "" : obj.constructor.name ? obj.constructor.name + " " : "";
42239
42514
  var tag = constructorTag + (stringTag || protoTag ? "[" + $join.call($concat.call([], stringTag || [], protoTag || []), ": ") + "] " : "");
42240
42515
  if (ys.length === 0) {
42241
42516
  return tag + "{}";
@@ -55352,6 +55627,7 @@ var init_capture_liveness = __esm({
55352
55627
  noFilePath: "no file_path in the tool input",
55353
55628
  noDatabaseForRecall: "no database yet \u2014 nothing to recall",
55354
55629
  nothingToRecall: "no guard matched and nothing to recall for this file",
55630
+ candidateWindowTruncated: "more candidates may exist than the search window examined",
55355
55631
  noPromptIntent: "the prompt carried no remember intent and no update decision",
55356
55632
  noMemoryDir: "no Claude Code memory directory for this project",
55357
55633
  noNoteChanged: "no note file changed since the last ingestion",
@@ -58343,7 +58619,7 @@ MeMesh HTTP: bearer token generated for remote access.
58343
58619
  function __setRemoteTokenForTest(value) {
58344
58620
  remoteToken = value;
58345
58621
  }
58346
- var import_express, packageJsonPath, packageRoot, packageVersion, app, apiLimiter, remoteToken, serverAuthRequired, CROSS_SITE_REFUSAL, DoctorFixBody, HttpError, ConfigBody, TaskStateQuerySchema, DreamProposalsQuerySchema, RejectBodySchema, EntitiesQuerySchema, HOST, PORT, ALLOW_REMOTE_BY_ENV, isMain, shutdown;
58622
+ var import_express, packageJsonPath, packageRoot, packageVersion, app, apiLimiter, remoteToken, serverAuthRequired, CROSS_SITE_REFUSAL, DoctorFixBody, HttpError, ConfigReadBody, ConfigBody, TaskStateQuerySchema, DreamProposalsQuerySchema, RejectBodySchema, EntitiesQuerySchema, HOST, PORT, ALLOW_REMOTE_BY_ENV, isMain, shutdown;
58347
58623
  var init_server = __esm({
58348
58624
  "dist/transports/http/server.js"() {
58349
58625
  "use strict";
@@ -58354,6 +58630,7 @@ var init_server = __esm({
58354
58630
  init_operations();
58355
58631
  init_knowledge_graph();
58356
58632
  init_config();
58633
+ init_briefing_level();
58357
58634
  init_doctor_fixes();
58358
58635
  init_patterns();
58359
58636
  init_analytics();
@@ -58553,14 +58830,22 @@ var init_server = __esm({
58553
58830
  limit: data.limit
58554
58831
  });
58555
58832
  }));
58833
+ ConfigReadBody = external_exports.object({
58834
+ autoCapture: external_exports.boolean().optional(),
58835
+ sessionLimit: external_exports.number().int().min(1).max(100).optional(),
58836
+ autoUpdate: external_exports.enum(["off", "patch", "minor", "major"]).optional(),
58837
+ setupCompleted: external_exports.boolean().optional(),
58838
+ briefing: external_exports.unknown().optional()
58839
+ }).strip();
58556
58840
  app.get("/v1/config", (_req, res) => handleGet(res, () => ({
58557
- config: ConfigBody.strip().parse(readConfig())
58841
+ config: ConfigReadBody.parse(readConfig())
58558
58842
  })));
58559
58843
  ConfigBody = external_exports.object({
58560
58844
  autoCapture: external_exports.boolean().optional(),
58561
58845
  sessionLimit: external_exports.number().int().min(1).max(100).optional(),
58562
58846
  autoUpdate: external_exports.enum(["off", "patch", "minor", "major"]).optional(),
58563
- setupCompleted: external_exports.boolean().optional()
58847
+ setupCompleted: external_exports.boolean().optional(),
58848
+ briefing: external_exports.enum(BRIEFING_LEVELS).optional()
58564
58849
  }).strict();
58565
58850
  app.post("/v1/config", (req, res) => handlePost(ConfigBody, req, res, (data) => ConfigBody.strip().parse(updateConfig(data))));
58566
58851
  app.get("/v1/update-status", (req, res) => handleGet(res, async () => {
@@ -60344,6 +60629,7 @@ function summarizeNoteIngest(r) {
60344
60629
 
60345
60630
  // dist/transports/cli/cli.js
60346
60631
  init_briefing();
60632
+ init_briefing_level();
60347
60633
  init_work_topology();
60348
60634
 
60349
60635
  // dist/core/session-insight.js
@@ -61290,15 +61576,15 @@ program2.command("export").description("Export memories as JSON. Defaults to std
61290
61576
  }
61291
61577
  });
61292
61578
  });
61293
- program2.command("import").description("Import memories from a JSON export file, or a directory of note files (--notes)").argument("[file]", "Path to JSON export file").option("--namespace <ns>", "Override namespace for all imported entities").option("--merge <strategy>", "Merge strategy: skip | overwrite | append", "skip").option("--notes <dir>", "Ingest every frontmatter note file (*.md with name/description/metadata.type) under <dir>: one memory per file, tagged source:note-file; a changed file replaces its memory, a vanished one is tagged source:note-file:missing. Read-only on the directory.").option("--project <name>", "With --notes: the project tag for ingested memories (default: the current directory's project)").option("--json", "With --notes: output the ingestion result as JSON").action(async (file2, opts, cmd) => {
61579
+ program2.command("import").description("Import memories from a JSON export file, or a directory of note files (--notes)").argument("[file]", "Path to JSON export file").option("--namespace <ns>", "Override namespace for all imported entities").option("--merge <strategy>", "Merge strategy: skip | overwrite | append", "skip").option("--restore-archived", "Requires --merge append or overwrite (an error with skip, the default): bring back a local memory you archived (forgot) when the file names it. Without this it stays archived and untouched.").option("--notes <dir>", "Ingest every frontmatter note file (*.md with name/description/metadata.type) under <dir>: one memory per file, tagged source:note-file; a changed file replaces its memory, a vanished one is tagged source:note-file:missing. Read-only on the directory.").option("--project <name>", "With --notes: the project tag for ingested memories (default: the current directory's project)").option("--json", "With --notes: output the ingestion result as JSON").action(async (file2, opts, cmd) => {
61294
61580
  if (opts.notes !== void 0) {
61295
61581
  if (file2) {
61296
61582
  console.error("Error: pass either a JSON export file or --notes <dir>, not both.");
61297
61583
  process.exit(1);
61298
61584
  }
61299
- const ignored = ["namespace", "merge"].filter((k) => cmd.getOptionValueSource(k) === "cli");
61585
+ const ignored = ["namespace", "merge", "restoreArchived"].filter((k) => cmd.getOptionValueSource(k) === "cli");
61300
61586
  if (ignored.length > 0) {
61301
- console.error(`Error: --notes does not take ${ignored.map((k) => `--${k}`).join(" or ")}. Note files always go to the personal namespace and a changed file replaces its memory.`);
61587
+ console.error(`Error: --notes does not take ${ignored.map((k) => `--${k.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)}`).join(" or ")}. Note files always go to the personal namespace and a changed file replaces its memory.`);
61302
61588
  process.exit(1);
61303
61589
  }
61304
61590
  await withDatabase(() => {
@@ -61330,7 +61616,7 @@ program2.command("import").description("Import memories from a JSON export file,
61330
61616
  }
61331
61617
  const notesOnly = ["project", "json"].filter((k) => cmd.getOptionValueSource(k) === "cli");
61332
61618
  if (notesOnly.length > 0) {
61333
- console.error(`Error: ${notesOnly.map((k) => `--${k}`).join(" and ")} only appl${notesOnly.length > 1 ? "y" : "ies"} to --notes. A JSON export file is imported with --namespace and --merge.`);
61619
+ console.error(`Error: ${notesOnly.map((k) => `--${k}`).join(" and ")} only appl${notesOnly.length > 1 ? "y" : "ies"} to --notes. A JSON export file is imported with --namespace, --merge and --restore-archived.`);
61334
61620
  process.exit(1);
61335
61621
  }
61336
61622
  requireOneOf(opts.merge, ["skip", "overwrite", "append"], "--merge");
@@ -61369,7 +61655,8 @@ program2.command("import").description("Import memories from a JSON export file,
61369
61655
  result = importMemories({
61370
61656
  data,
61371
61657
  namespace: opts.namespace,
61372
- merge_strategy: opts.merge
61658
+ merge_strategy: opts.merge,
61659
+ restore_archived: opts.restoreArchived === true
61373
61660
  });
61374
61661
  } catch (err) {
61375
61662
  console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
@@ -61377,6 +61664,9 @@ program2.command("import").description("Import memories from a JSON export file,
61377
61664
  }
61378
61665
  const overwriteNote = result.overwritten > 0 ? ` (${result.overwritten} overwritten)` : "";
61379
61666
  console.log(`Imported: ${result.imported}${overwriteNote}, Skipped: ${result.skipped}, Appended: ${result.appended}`);
61667
+ if (result.kept_archived > 0) {
61668
+ console.log(`Kept archived: ${result.kept_archived} (you archived these; the file names them, so they were left untouched). Add --restore-archived to bring them back.`);
61669
+ }
61380
61670
  if (result.skipped_relations.length > 0) {
61381
61671
  console.error(`Note: ${result.skipped_relations.length} relation(s) not restored \u2014 the target is not in this bundle:
61382
61672
  ${result.skipped_relations.join("\n ")}`);
@@ -61663,7 +61953,7 @@ agentCmd.command("setup").argument("<host>", "codex-session | codex | claude | g
61663
61953
  ]
61664
61954
  ].join("\n"));
61665
61955
  });
61666
- program2.command("briefing").description("The assembled work topology for a project \u2014 task state, decisions, lessons, knowledge, recent activity").option("--project <name>", "Project name (default: the current directory\u2019s project)").option("--recipient <id>", "Exact recipient; enables recipient-scoped unread message guidance").option("--index", "Only the index of durable memories (decisions, lessons, patterns, references), newest first").option("--json", "Output as JSON").action(async (opts) => {
61956
+ program2.command("briefing").description("The assembled work topology for a project \u2014 decisions, lessons, knowledge and recent activity; task state and the durable-memory index are included at standard/full (the `briefing` setting)").option("--project <name>", "Project name (default: the current directory\u2019s project)").option("--recipient <id>", "Exact recipient; enables recipient-scoped unread message guidance").option("--index", "Only the index of durable memories (decisions, lessons, patterns, references), newest first").option("--json", "Output as JSON").action(async (opts) => {
61667
61957
  await withDatabase(() => {
61668
61958
  if (opts.index) {
61669
61959
  const project = opts.project ?? getProjectName();
@@ -61680,6 +61970,10 @@ program2.command("briefing").description("The assembled work topology for a proj
61680
61970
  console.log(JSON.stringify(result));
61681
61971
  return;
61682
61972
  }
61973
+ if (result.empty) {
61974
+ console.log(`Nothing to brief at level ${result.level} \u2014 no project memories yet.`);
61975
+ return;
61976
+ }
61683
61977
  console.log(result.text);
61684
61978
  if (result.entityCount === 0 && !result.hasTaskState && result.index.shown === 0 && result.index.older === 0) {
61685
61979
  console.log(`
@@ -61905,23 +62199,24 @@ configCmd.command("list").description("Show current configuration").action(() =>
61905
62199
  console.log(` ${key}: ${value}`);
61906
62200
  }
61907
62201
  });
61908
- var ALLOWED_KEYS = /* @__PURE__ */ new Set(["autoUpdate", "sessionLimit", "autoCapture", "updateCheck"]);
62202
+ var ALLOWED_KEYS = /* @__PURE__ */ new Set(["autoUpdate", "sessionLimit", "autoCapture", "updateCheck", "briefing"]);
61909
62203
  var KEY_VALIDATORS = {
61910
62204
  autoUpdate: (v) => ["off", "patch", "minor", "major"].includes(v) ? null : "must be one of: off, patch, minor, major",
61911
62205
  autoCapture: (v) => ["true", "false", "1", "0"].includes(v) ? null : "must be one of: true, false, 1, 0",
61912
- updateCheck: (v) => ["true", "false", "1", "0"].includes(v) ? null : "must be one of: true, false, 1, 0"
62206
+ updateCheck: (v) => ["true", "false", "1", "0"].includes(v) ? null : "must be one of: true, false, 1, 0",
62207
+ briefing: (v) => BRIEFING_LEVELS.includes(v) ? null : `must be one of: ${BRIEFING_LEVELS.join(", ")}`
61913
62208
  };
61914
62209
  function buildConfigListing(config2) {
61915
62210
  const rows = [];
61916
62211
  for (const key of Array.from(ALLOWED_KEYS).sort()) {
61917
62212
  const raw = config2[key];
61918
- if (raw === void 0 || raw === null)
62213
+ if (raw === void 0)
61919
62214
  continue;
61920
62215
  rows.push({ key, value: String(raw) });
61921
62216
  }
61922
62217
  return rows;
61923
62218
  }
61924
- configCmd.command("set").description("Set an ordinary config value (autoCapture, sessionLimit, autoUpdate, updateCheck)").argument("<key>", "Config key \u2014 see `memesh config list` for valid keys").argument("<value>", "Config value").action((key, value) => {
62219
+ configCmd.command("set").description("Set an ordinary config value (autoCapture, sessionLimit, autoUpdate, updateCheck, briefing)").argument("<key>", "Config key \u2014 see `memesh config list` for valid keys").argument("<value>", "Config value").action((key, value) => {
61925
62220
  const canonical = key;
61926
62221
  if (!ALLOWED_KEYS.has(canonical)) {
61927
62222
  console.error(`Unknown key: ${key}`);