@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
@@ -3229,8 +3229,8 @@ var require_utils = __commonJS({
3229
3229
  }
3230
3230
  return ind;
3231
3231
  }
3232
- function removeDotSegments(path10) {
3233
- let input = path10;
3232
+ function removeDotSegments(path11) {
3233
+ let input = path11;
3234
3234
  const output = [];
3235
3235
  let nextSlash = -1;
3236
3236
  let len = 0;
@@ -3482,8 +3482,8 @@ var require_schemes = __commonJS({
3482
3482
  wsComponent.secure = void 0;
3483
3483
  }
3484
3484
  if (wsComponent.resourceName) {
3485
- const [path10, query] = wsComponent.resourceName.split("?");
3486
- wsComponent.path = path10 && path10 !== "/" ? path10 : void 0;
3485
+ const [path11, query] = wsComponent.resourceName.split("?");
3486
+ wsComponent.path = path11 && path11 !== "/" ? path11 : void 0;
3487
3487
  wsComponent.query = query;
3488
3488
  wsComponent.resourceName = void 0;
3489
3489
  }
@@ -6670,7 +6670,7 @@ var require_formats = __commonJS({
6670
6670
  email: /^[a-z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/i
6671
6671
  };
6672
6672
  exports.formatNames = Object.keys(exports.fullFormats);
6673
- function isLeapYear(year) {
6673
+ function isLeapYear2(year) {
6674
6674
  return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0);
6675
6675
  }
6676
6676
  var DATE = /^(\d\d\d\d)-(\d\d)-(\d\d)$/;
@@ -6682,7 +6682,7 @@ var require_formats = __commonJS({
6682
6682
  const year = +matches[1];
6683
6683
  const month = +matches[2];
6684
6684
  const day = +matches[3];
6685
- return month >= 1 && month <= 12 && day >= 1 && day <= (month === 2 && isLeapYear(year) ? 29 : DAYS[month]);
6685
+ return month >= 1 && month <= 12 && day >= 1 && day <= (month === 2 && isLeapYear2(year) ? 29 : DAYS[month]);
6686
6686
  }
6687
6687
  function compareDate(d1, d2) {
6688
6688
  if (!(d1 && d2))
@@ -6902,12 +6902,12 @@ var require_dist = __commonJS({
6902
6902
  throw new Error(`Unknown format "${name}"`);
6903
6903
  return f;
6904
6904
  };
6905
- function addFormats(ajv, list, fs12, exportName) {
6905
+ function addFormats(ajv, list, fs13, exportName) {
6906
6906
  var _a3;
6907
6907
  var _b;
6908
6908
  (_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
6909
6909
  for (const f of list)
6910
- ajv.addFormat(f, fs12[f]);
6910
+ ajv.addFormat(f, fs13[f]);
6911
6911
  }
6912
6912
  module.exports = exports = formatsPlugin;
6913
6913
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -6916,8 +6916,8 @@ var require_dist = __commonJS({
6916
6916
  });
6917
6917
 
6918
6918
  // dist/mcp/server.js
6919
- import fs11 from "fs";
6920
- import path9 from "path";
6919
+ import fs12 from "fs";
6920
+ import path10 from "path";
6921
6921
 
6922
6922
  // node_modules/zod/v4/core/index.js
6923
6923
  var core_exports2 = {};
@@ -7442,10 +7442,10 @@ function mergeDefs(...defs) {
7442
7442
  function cloneDef(schema) {
7443
7443
  return mergeDefs(schema._zod.def);
7444
7444
  }
7445
- function getElementAtPath(obj, path10) {
7446
- if (!path10)
7445
+ function getElementAtPath(obj, path11) {
7446
+ if (!path11)
7447
7447
  return obj;
7448
- return path10.reduce((acc, key) => acc?.[key], obj);
7448
+ return path11.reduce((acc, key) => acc?.[key], obj);
7449
7449
  }
7450
7450
  function promiseAllObject(promisesObj) {
7451
7451
  const keys = Object.keys(promisesObj);
@@ -7854,11 +7854,11 @@ function explicitlyAborted(x, startIndex = 0) {
7854
7854
  }
7855
7855
  return false;
7856
7856
  }
7857
- function prefixIssues(path10, issues) {
7857
+ function prefixIssues(path11, issues) {
7858
7858
  return issues.map((iss) => {
7859
7859
  var _a3;
7860
7860
  (_a3 = iss).path ?? (_a3.path = []);
7861
- iss.path.unshift(path10);
7861
+ iss.path.unshift(path11);
7862
7862
  return iss;
7863
7863
  });
7864
7864
  }
@@ -8005,16 +8005,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
8005
8005
  }
8006
8006
  function formatError(error51, mapper = (issue2) => issue2.message) {
8007
8007
  const fieldErrors = { _errors: [] };
8008
- const processError = (error52, path10 = []) => {
8008
+ const processError = (error52, path11 = []) => {
8009
8009
  for (const issue2 of error52.issues) {
8010
8010
  if (issue2.code === "invalid_union" && issue2.errors.length) {
8011
- issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
8011
+ issue2.errors.map((issues) => processError({ issues }, [...path11, ...issue2.path]));
8012
8012
  } else if (issue2.code === "invalid_key") {
8013
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
8013
+ processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
8014
8014
  } else if (issue2.code === "invalid_element") {
8015
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
8015
+ processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
8016
8016
  } else {
8017
- const fullpath = [...path10, ...issue2.path];
8017
+ const fullpath = [...path11, ...issue2.path];
8018
8018
  if (fullpath.length === 0) {
8019
8019
  fieldErrors._errors.push(mapper(issue2));
8020
8020
  } else {
@@ -8041,17 +8041,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
8041
8041
  }
8042
8042
  function treeifyError(error51, mapper = (issue2) => issue2.message) {
8043
8043
  const result = { errors: [] };
8044
- const processError = (error52, path10 = []) => {
8044
+ const processError = (error52, path11 = []) => {
8045
8045
  var _a3, _b;
8046
8046
  for (const issue2 of error52.issues) {
8047
8047
  if (issue2.code === "invalid_union" && issue2.errors.length) {
8048
- issue2.errors.map((issues) => processError({ issues }, [...path10, ...issue2.path]));
8048
+ issue2.errors.map((issues) => processError({ issues }, [...path11, ...issue2.path]));
8049
8049
  } else if (issue2.code === "invalid_key") {
8050
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
8050
+ processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
8051
8051
  } else if (issue2.code === "invalid_element") {
8052
- processError({ issues: issue2.issues }, [...path10, ...issue2.path]);
8052
+ processError({ issues: issue2.issues }, [...path11, ...issue2.path]);
8053
8053
  } else {
8054
- const fullpath = [...path10, ...issue2.path];
8054
+ const fullpath = [...path11, ...issue2.path];
8055
8055
  if (fullpath.length === 0) {
8056
8056
  result.errors.push(mapper(issue2));
8057
8057
  continue;
@@ -8083,8 +8083,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
8083
8083
  }
8084
8084
  function toDotPath(_path) {
8085
8085
  const segs = [];
8086
- const path10 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
8087
- for (const seg of path10) {
8086
+ const path11 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
8087
+ for (const seg of path11) {
8088
8088
  if (typeof seg === "number")
8089
8089
  segs.push(`[${seg}]`);
8090
8090
  else if (typeof seg === "symbol")
@@ -21082,13 +21082,13 @@ function resolveRef(ref, ctx) {
21082
21082
  if (!ref.startsWith("#")) {
21083
21083
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
21084
21084
  }
21085
- const path10 = ref.slice(1).split("/").filter(Boolean);
21086
- if (path10.length === 0) {
21085
+ const path11 = ref.slice(1).split("/").filter(Boolean);
21086
+ if (path11.length === 0) {
21087
21087
  return ctx.rootSchema;
21088
21088
  }
21089
21089
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
21090
- if (path10[0] === defsKey) {
21091
- const key = path10[1];
21090
+ if (path11[0] === defsKey) {
21091
+ const key = path11[1];
21092
21092
  if (!key || !ctx.defs[key]) {
21093
21093
  throw new Error(`Reference not found: ${ref}`);
21094
21094
  }
@@ -24819,8 +24819,8 @@ var { DatabaseSync } = loadNodeSqlite();
24819
24819
  var BUSY_TIMEOUT_MS = 3e4;
24820
24820
  var MemeshDatabase = class extends DatabaseSync {
24821
24821
  #depth = 0;
24822
- constructor(path10, options = {}) {
24823
- super(path10, options);
24822
+ constructor(path11, options = {}) {
24823
+ super(path11, options);
24824
24824
  this.pragma(`busy_timeout = ${BUSY_TIMEOUT_MS}`);
24825
24825
  }
24826
24826
  pragma(statement) {
@@ -26903,7 +26903,7 @@ function getDatabase() {
26903
26903
  }
26904
26904
 
26905
26905
  // dist/transports/mcp/handlers.js
26906
- import fs10 from "node:fs";
26906
+ import fs11 from "node:fs";
26907
26907
  import { fileURLToPath as fileURLToPath2 } from "node:url";
26908
26908
 
26909
26909
  // dist/core/scoring.js
@@ -27054,13 +27054,98 @@ function deriveNote(raw) {
27054
27054
  var NAMESPACES = ["personal", "team", "global"];
27055
27055
 
27056
27056
  // dist/core/serializer.js
27057
+ var IMPORTABLE_METADATA_KEYS = /* @__PURE__ */ new Set([
27058
+ "title_source",
27059
+ "source_kind",
27060
+ "source",
27061
+ "cluster_key",
27062
+ "dreamed_at",
27063
+ "kind",
27064
+ "project",
27065
+ "previous_namespace",
27066
+ "namespace_moved_at",
27067
+ "split_from",
27068
+ "retired_recall",
27069
+ "priority",
27070
+ "success_criteria",
27071
+ "verification_scenario",
27072
+ "implementation_state",
27073
+ "outcome_state",
27074
+ "accepted_at",
27075
+ "source_ids"
27076
+ ]);
27077
+ var FORGOTTEN_HASH_RE = /^[a-f0-9]{64}$/;
27078
+ var MAX_IMPORTED_FORGOTTEN_HASHES = 1e3;
27079
+ function validateFreshForgottenHashes(value) {
27080
+ if (!Array.isArray(value) || value.length === 0)
27081
+ return null;
27082
+ const deduped = [...new Set(value)];
27083
+ if (!deduped.every((h) => typeof h === "string" && FORGOTTEN_HASH_RE.test(h)))
27084
+ return null;
27085
+ return deduped.length <= MAX_IMPORTED_FORGOTTEN_HASHES ? deduped : null;
27086
+ }
27087
+ function validateFreshSignalScore(value) {
27088
+ return typeof value === "number" && value >= 0 && value <= 1 ? value : null;
27089
+ }
27090
+ var MAX_IMPORTED_REPLACED_HISTORY_ENTRIES = 50;
27091
+ var MAX_IMPORTED_REPLACED_HISTORY_TOTAL_BYTES = 4 * 64 * 1024;
27092
+ var REPLACED_HISTORY_ENTRY_KEYS = /* @__PURE__ */ new Set([
27093
+ "replaced_at",
27094
+ "title",
27095
+ "observations",
27096
+ "tags",
27097
+ "truncated"
27098
+ ]);
27099
+ function isPlainObject3(value) {
27100
+ return typeof value === "object" && value !== null && !Array.isArray(value);
27101
+ }
27102
+ var jsonBytesOf = (v) => Buffer.byteLength(JSON.stringify(v), "utf8");
27103
+ function isValidReplacedHistoryEntry(entry) {
27104
+ if (!isPlainObject3(entry))
27105
+ return false;
27106
+ for (const key of Object.keys(entry)) {
27107
+ if (!REPLACED_HISTORY_ENTRY_KEYS.has(key))
27108
+ return false;
27109
+ }
27110
+ if (typeof entry.replaced_at !== "string" || entry.replaced_at.length > 64)
27111
+ return false;
27112
+ if (!(entry.title === null || typeof entry.title === "string" && entry.title.length <= 500))
27113
+ return false;
27114
+ if (!Array.isArray(entry.observations) || !entry.observations.every((o) => typeof o === "string"))
27115
+ return false;
27116
+ if (!Array.isArray(entry.tags) || !entry.tags.every((t) => typeof t === "string"))
27117
+ return false;
27118
+ if ("truncated" in entry && typeof entry.truncated !== "boolean")
27119
+ return false;
27120
+ return true;
27121
+ }
27122
+ function validateFreshReplacedHistory(value) {
27123
+ if (!Array.isArray(value) || value.length === 0)
27124
+ return null;
27125
+ if (value.length > MAX_IMPORTED_REPLACED_HISTORY_ENTRIES)
27126
+ return null;
27127
+ if (!value.every(isValidReplacedHistoryEntry))
27128
+ return null;
27129
+ return jsonBytesOf(value) <= MAX_IMPORTED_REPLACED_HISTORY_TOTAL_BYTES ? value : null;
27130
+ }
27057
27131
  function buildImportedMetadata(existingMetadata, args) {
27058
- const { guard: _guard, ...bundledSafe } = args.bundled ?? {};
27059
- void _guard;
27132
+ const bundled = args.bundled ?? {};
27133
+ const bundledSafe = {};
27134
+ for (const [key, value] of Object.entries(bundled)) {
27135
+ if (IMPORTABLE_METADATA_KEYS.has(key))
27136
+ bundledSafe[key] = value;
27137
+ }
27138
+ const freshForgottenHashes = args.isNewEntity ? validateFreshForgottenHashes(bundled.forgotten_observation_hashes) : null;
27139
+ const freshPin = args.isNewEntity && bundled.pin === true;
27140
+ const freshSignalScore = args.isNewEntity ? validateFreshSignalScore(bundled.signal_score) : null;
27141
+ const freshReplacedHistory = args.isNewEntity ? validateFreshReplacedHistory(bundled.replaced_history) : null;
27060
27142
  return {
27061
27143
  ...existingMetadata ?? {},
27062
27144
  ...bundledSafe,
27063
- ...Array.isArray(existingMetadata?.forgotten_observation_hashes) ? { forgotten_observation_hashes: existingMetadata.forgotten_observation_hashes } : {},
27145
+ ...freshForgottenHashes ? { forgotten_observation_hashes: freshForgottenHashes } : {},
27146
+ ...freshSignalScore !== null ? { signal_score: freshSignalScore } : {},
27147
+ ...freshPin ? { pin: true } : {},
27148
+ ...freshReplacedHistory ? { replaced_history: freshReplacedHistory } : {},
27064
27149
  trust: "untrusted",
27065
27150
  provenance: {
27066
27151
  ...existingMetadata?.provenance ?? {},
@@ -27130,6 +27215,12 @@ function importMemories(args) {
27130
27215
  if (!MERGE_STRATEGIES.includes(args.merge_strategy)) {
27131
27216
  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.`);
27132
27217
  }
27218
+ if (args.restore_archived !== void 0 && typeof args.restore_archived !== "boolean") {
27219
+ 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.');
27220
+ }
27221
+ if (args.restore_archived === true && args.merge_strategy === "skip") {
27222
+ 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.');
27223
+ }
27133
27224
  if (args.namespace !== void 0 && !NAMESPACES.includes(args.namespace)) {
27134
27225
  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.`);
27135
27226
  }
@@ -27144,6 +27235,7 @@ function importMemories(args) {
27144
27235
  const pendingRelations = [];
27145
27236
  let skipped = 0;
27146
27237
  let appended = 0;
27238
+ let keptArchived = 0;
27147
27239
  const errors = [];
27148
27240
  const skippedRelations = [];
27149
27241
  const setCreatedAt = db2.prepare("UPDATE entities SET created_at = ? WHERE name = ?");
@@ -27164,11 +27256,14 @@ function importMemories(args) {
27164
27256
  bundled: entity.metadata,
27165
27257
  exportedAt: args.data.exported_at,
27166
27258
  importVersion: args.data.version,
27167
- mergeStrategy: args.merge_strategy
27259
+ mergeStrategy: args.merge_strategy,
27260
+ isNewEntity: !existing
27168
27261
  });
27169
27262
  if (existing) {
27170
27263
  if (args.merge_strategy === "skip")
27171
27264
  return { kind: "skipped" };
27265
+ if (existing.archived && args.restore_archived !== true)
27266
+ return { kind: "keptArchived" };
27172
27267
  if (args.merge_strategy === "append") {
27173
27268
  const existingText = new Set(existing.observations);
27174
27269
  const newObservations = (entity.observations ?? []).filter((o) => !existingText.has(o));
@@ -27217,6 +27312,8 @@ function importMemories(args) {
27217
27312
  }).immediate();
27218
27313
  if (outcome.kind === "skipped")
27219
27314
  skipped++;
27315
+ else if (outcome.kind === "keptArchived")
27316
+ keptArchived++;
27220
27317
  else if (outcome.kind === "appended")
27221
27318
  appended++;
27222
27319
  else {
@@ -27240,7 +27337,7 @@ function importMemories(args) {
27240
27337
  errors.push(`${rel.from} -${rel.type}-> ${rel.to}: relation not restored (${err instanceof Error ? err.message : String(err)})`);
27241
27338
  }
27242
27339
  }
27243
- return { imported, overwritten, skipped, appended, errors, skipped_relations: skippedRelations };
27340
+ return { imported, overwritten, skipped, appended, kept_archived: keptArchived, errors, skipped_relations: skippedRelations };
27244
27341
  }
27245
27342
 
27246
27343
  // dist/core/operations.js
@@ -28272,10 +28369,72 @@ function computePatterns(db2, categories) {
28272
28369
  };
28273
28370
  }
28274
28371
 
28275
- // dist/core/repo-state.js
28276
- import { execFileSync as execFileSync2 } from "child_process";
28372
+ // dist/core/config.js
28277
28373
  import fs4 from "fs";
28278
28374
  import path4 from "path";
28375
+ function configDir() {
28376
+ return memeshDir();
28377
+ }
28378
+ function configFilePath() {
28379
+ return path4.join(configDir(), "config.json");
28380
+ }
28381
+ var lastConfigReadWarning = null;
28382
+ function warnUnreadable(p, detail) {
28383
+ const key = `${p}::${detail}`;
28384
+ if (key === lastConfigReadWarning)
28385
+ return;
28386
+ lastConfigReadWarning = key;
28387
+ try {
28388
+ process.stderr.write(`[memesh config] ${p} exists but could not be read as a settings object (${detail}). Existing settings are ignored and will not be overwritten until the file is fixed.
28389
+ `);
28390
+ } catch {
28391
+ }
28392
+ }
28393
+ function readRawConfigResult() {
28394
+ const p = configFilePath();
28395
+ if (!fs4.existsSync(p))
28396
+ return { raw: {}, state: "absent" };
28397
+ try {
28398
+ const parsed = JSON.parse(fs4.readFileSync(p, "utf8"));
28399
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
28400
+ throw new Error("top-level JSON value is not an object");
28401
+ }
28402
+ return { raw: parsed, state: "ok" };
28403
+ } catch (error51) {
28404
+ warnUnreadable(p, error51 instanceof Error ? error51.message : String(error51));
28405
+ return { raw: {}, state: "unreadable" };
28406
+ }
28407
+ }
28408
+ function selectConfig(raw) {
28409
+ const config2 = {};
28410
+ if (typeof raw.autoCapture === "boolean")
28411
+ config2.autoCapture = raw.autoCapture;
28412
+ if (typeof raw.sessionLimit === "number" && Number.isFinite(raw.sessionLimit)) {
28413
+ config2.sessionLimit = raw.sessionLimit;
28414
+ }
28415
+ if (raw.autoUpdate === "off" || raw.autoUpdate === "patch" || raw.autoUpdate === "minor" || raw.autoUpdate === "major") {
28416
+ config2.autoUpdate = raw.autoUpdate;
28417
+ }
28418
+ if (typeof raw.updateCheck === "boolean")
28419
+ config2.updateCheck = raw.updateCheck;
28420
+ if (typeof raw.setupCompleted === "boolean")
28421
+ config2.setupCompleted = raw.setupCompleted;
28422
+ if (raw.briefing !== void 0)
28423
+ config2.briefing = raw.briefing;
28424
+ return config2;
28425
+ }
28426
+ function readConfigResult() {
28427
+ const result = readRawConfigResult();
28428
+ return { config: selectConfig(result.raw), state: result.state };
28429
+ }
28430
+ function readConfig() {
28431
+ return readConfigResult().config;
28432
+ }
28433
+
28434
+ // dist/core/repo-state.js
28435
+ import { execFileSync as execFileSync2 } from "child_process";
28436
+ import fs5 from "fs";
28437
+ import path5 from "path";
28279
28438
  var GIT_TIMEOUT_MS = 5e3;
28280
28439
  function tryGit2(cwd, args) {
28281
28440
  try {
@@ -28290,7 +28449,7 @@ function tryGit2(cwd, args) {
28290
28449
  }
28291
28450
  function declaredVersionOf(repoRoot) {
28292
28451
  try {
28293
- const raw = fs4.readFileSync(path4.join(repoRoot, "package.json"), "utf8");
28452
+ const raw = fs5.readFileSync(path5.join(repoRoot, "package.json"), "utf8");
28294
28453
  const version2 = JSON.parse(raw).version;
28295
28454
  return typeof version2 === "string" && version2.length > 0 ? version2 : null;
28296
28455
  } catch {
@@ -28429,6 +28588,76 @@ function taskStateLines(state, project, now = /* @__PURE__ */ new Date()) {
28429
28588
  }
28430
28589
  return lines;
28431
28590
  }
28591
+ var STALE_TASK_STATE_HOURS = 72;
28592
+ var CLOCK_SKEW_ALLOWANCE_MINUTES = 5;
28593
+ var 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}))$/;
28594
+ function isLeapYear(year) {
28595
+ return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0;
28596
+ }
28597
+ var DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
28598
+ function daysInMonth(year, month) {
28599
+ return month === 2 && isLeapYear(year) ? 29 : DAYS_IN_MONTH[month - 1];
28600
+ }
28601
+ function isRealInstant(groups) {
28602
+ const year = Number(groups.year);
28603
+ const month = Number(groups.month);
28604
+ const day = Number(groups.day);
28605
+ const hour = Number(groups.hour);
28606
+ const minute = Number(groups.minute);
28607
+ const second = groups.second === void 0 ? 0 : Number(groups.second);
28608
+ if (month < 1 || month > 12)
28609
+ return false;
28610
+ if (day < 1 || day > daysInMonth(year, month))
28611
+ return false;
28612
+ if (hour > 23)
28613
+ return false;
28614
+ if (minute > 59)
28615
+ return false;
28616
+ if (second > 59)
28617
+ return false;
28618
+ if (groups.zulu === void 0) {
28619
+ const offHour = Number(groups.offHour);
28620
+ const offMinute = Number(groups.offMinute);
28621
+ if (offHour > 23 || offMinute > 59)
28622
+ return false;
28623
+ if (groups.offSign === "-" && offHour === 0 && offMinute === 0)
28624
+ return false;
28625
+ }
28626
+ return true;
28627
+ }
28628
+ function resolveTaskStateAge(updatedAt, now) {
28629
+ if (!updatedAt)
28630
+ return { known: false };
28631
+ const match = ZONED_INSTANT.exec(updatedAt);
28632
+ if (!match?.groups || !isRealInstant(match.groups))
28633
+ return { known: false };
28634
+ const then = Date.parse(updatedAt);
28635
+ if (Number.isNaN(then))
28636
+ return { known: false };
28637
+ const hours = (now.getTime() - then) / 36e5;
28638
+ if (hours < -(CLOCK_SKEW_ALLOWANCE_MINUTES / 60))
28639
+ return { known: false };
28640
+ return { known: true, hours: Math.max(0, hours) };
28641
+ }
28642
+ function staleTaskStateLine(project, hours) {
28643
+ const days = Math.floor(hours / 24);
28644
+ const age = days >= 1 ? `${days} day${days === 1 ? "" : "s"} ago` : `${Math.floor(hours)} hour${Math.floor(hours) === 1 ? "" : "s"} ago`;
28645
+ 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.`;
28646
+ }
28647
+ function taskStateAgeUnknownLine(project) {
28648
+ 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.`;
28649
+ }
28650
+ function briefingTaskStateLines(state, project, now = /* @__PURE__ */ new Date(), { includeFresh = true } = {}) {
28651
+ if (isEmptyTaskState(state))
28652
+ return [];
28653
+ const age = resolveTaskStateAge(state.updated_at, now);
28654
+ if (!age.known)
28655
+ return [taskStateAgeUnknownLine(project)];
28656
+ if (age.hours > STALE_TASK_STATE_HOURS) {
28657
+ return [staleTaskStateLine(project, age.hours)];
28658
+ }
28659
+ return includeFresh ? taskStateLines(state, project, now) : [];
28660
+ }
28432
28661
 
28433
28662
  // dist/core/task-state-store.js
28434
28663
  function readState(name) {
@@ -28522,7 +28751,7 @@ function unreadInboxLines(count, project, recipient, everSeen) {
28522
28751
  const displayRecipient = JSON.stringify(recipient);
28523
28752
  if (count > 0) {
28524
28753
  const noun = count === 1 ? "message" : "messages";
28525
- 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.`];
28754
+ 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.`];
28526
28755
  }
28527
28756
  if (everSeen === false) {
28528
28757
  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).`];
@@ -28755,6 +28984,9 @@ function assembleTopologyBlock(stateLines, pools, projectName, budget = DEFAULT_
28755
28984
  lines.push(...globalLines);
28756
28985
  return lines;
28757
28986
  }
28987
+ function hasBriefingContent(lines) {
28988
+ return lines.length > 0;
28989
+ }
28758
28990
  function buildReferenceContext(memoryLines) {
28759
28991
  const safeLines = memoryLines.map((line) => String(line ?? "").replace(/[\s\u0085\u001c-\u001e]+/g, " ").trim());
28760
28992
  let longestRun = 0;
@@ -28909,6 +29141,79 @@ function buildBriefingIndex(candidates, projectName, now, options = {}) {
28909
29141
  return { ...closed, shown: rendered.length, more, older, truncated, ids };
28910
29142
  }
28911
29143
 
29144
+ // dist/core/briefing-level.js
29145
+ var BRIEFING_LEVELS = ["minimal", "standard", "full"];
29146
+ var DEFAULT_BRIEFING_LEVEL = "standard";
29147
+ function isBriefingLevel(value) {
29148
+ return typeof value === "string" && BRIEFING_LEVELS.includes(value);
29149
+ }
29150
+ var INVALID_VALUE_SERIALIZED_MAX = 100;
29151
+ var PRE_SLICE_RAW_MAX = 256;
29152
+ function safeRawPreSlice(value, maxUnits) {
29153
+ if (value.length <= maxUnits)
29154
+ return value;
29155
+ let end = maxUnits;
29156
+ const lastKept = value.charCodeAt(end - 1);
29157
+ const nextUnit = value.charCodeAt(end);
29158
+ const lastKeptIsHighSurrogate = lastKept >= 55296 && lastKept <= 56319;
29159
+ const nextUnitIsLowSurrogate = nextUnit >= 56320 && nextUnit <= 57343;
29160
+ if (lastKeptIsHighSurrogate && nextUnitIsLowSurrogate)
29161
+ end -= 1;
29162
+ return value.slice(0, end);
29163
+ }
29164
+ function truncateToSerializedBound(codePoints) {
29165
+ let kept = 0;
29166
+ for (; kept < codePoints.length; kept++) {
29167
+ const candidate = JSON.stringify(`${codePoints.slice(0, kept + 1).join("")}\u2026`);
29168
+ if (candidate.length > INVALID_VALUE_SERIALIZED_MAX)
29169
+ break;
29170
+ }
29171
+ return JSON.stringify(`${codePoints.slice(0, kept).join("")}\u2026`);
29172
+ }
29173
+ function describeInvalidValue(value) {
29174
+ if (typeof value === "string") {
29175
+ if (value.length <= INVALID_VALUE_SERIALIZED_MAX) {
29176
+ const whole = JSON.stringify(value);
29177
+ if (whole.length <= INVALID_VALUE_SERIALIZED_MAX)
29178
+ return whole;
29179
+ return truncateToSerializedBound(Array.from(value));
29180
+ }
29181
+ return truncateToSerializedBound(Array.from(safeRawPreSlice(value, PRE_SLICE_RAW_MAX)));
29182
+ }
29183
+ if (Array.isArray(value))
29184
+ return "[array]";
29185
+ if (value !== null && typeof value === "object")
29186
+ return "[object]";
29187
+ if (typeof value === "bigint")
29188
+ return "[bigint]";
29189
+ if (typeof value === "symbol")
29190
+ return "[symbol]";
29191
+ if (typeof value === "function")
29192
+ return "[function]";
29193
+ return JSON.stringify(value) ?? String(value);
29194
+ }
29195
+ function resolveBriefingLevel(envValue, configValue) {
29196
+ if (envValue !== void 0) {
29197
+ if (isBriefingLevel(envValue))
29198
+ return { level: envValue, invalid: null };
29199
+ return { level: DEFAULT_BRIEFING_LEVEL, invalid: { source: "env", value: describeInvalidValue(envValue) } };
29200
+ }
29201
+ if (configValue !== void 0) {
29202
+ if (isBriefingLevel(configValue))
29203
+ return { level: configValue, invalid: null };
29204
+ return { level: DEFAULT_BRIEFING_LEVEL, invalid: { source: "config", value: describeInvalidValue(configValue) } };
29205
+ }
29206
+ return { level: DEFAULT_BRIEFING_LEVEL, invalid: null };
29207
+ }
29208
+ var POLICIES = {
29209
+ minimal: { global: false, foreign: false, taskState: false, index: false, workPackageNotice: false },
29210
+ standard: { global: false, foreign: false, taskState: true, index: true, workPackageNotice: false },
29211
+ full: { global: true, foreign: true, taskState: true, index: true, workPackageNotice: true }
29212
+ };
29213
+ function briefingLevelPolicy(level) {
29214
+ return POLICIES[level];
29215
+ }
29216
+
28912
29217
  // dist/core/briefing.js
28913
29218
  var PROJECT_LIMIT = 30;
28914
29219
  var RECENT_LIMIT = 5;
@@ -28977,10 +29282,23 @@ function readBriefingIndex(db2, projectName, now = Date.now()) {
28977
29282
  function assembleBriefing(project, recipient) {
28978
29283
  const projectName = project ?? getProjectName();
28979
29284
  const db2 = getDatabase();
29285
+ const resolvedLevel = resolveBriefingLevel(process.env.MEMESH_BRIEFING, readConfig().briefing);
29286
+ if (resolvedLevel.invalid) {
29287
+ const { source, value } = resolvedLevel.invalid;
29288
+ try {
29289
+ process.stderr.write(`[memesh briefing] invalid ${source} briefing level ${value} \u2014 using "${resolvedLevel.level}"
29290
+ `);
29291
+ } catch {
29292
+ }
29293
+ }
29294
+ const level = resolvedLevel.level;
29295
+ const policy = briefingLevelPolicy(level);
28980
29296
  const repoLines = project === void 0 || project === getProjectName() ? repoStateLines(readRepoState()) : [];
28981
29297
  let taskLines;
28982
29298
  try {
28983
- taskLines = taskStateLines(getTaskState(projectName).state, projectName);
29299
+ taskLines = briefingTaskStateLines(getTaskState(projectName).state, projectName, /* @__PURE__ */ new Date(), {
29300
+ includeFresh: policy.taskState
29301
+ });
28984
29302
  } catch (err) {
28985
29303
  if (!(err instanceof TaskStateUnreadableError))
28986
29304
  throw err;
@@ -29001,17 +29319,17 @@ function assembleBriefing(project, recipient) {
29001
29319
  ORDER BY e.id DESC
29002
29320
  LIMIT ?`).all(`project:${projectName}`, TOPOLOGY_CANDIDATE_CAP);
29003
29321
  const projectPool = selectPool(projectRows, PROJECT_LIMIT);
29004
- const globalRows = hasNamespace ? db2.prepare(`SELECT ${CANDIDATE_COLUMNS}
29322
+ const globalRows = policy.global && hasNamespace ? db2.prepare(`SELECT ${CANDIDATE_COLUMNS}
29005
29323
  FROM entities e
29006
29324
  WHERE e.namespace = 'global' AND e.status = 'active'
29007
29325
  ORDER BY e.id DESC
29008
29326
  LIMIT ?`).all(TOPOLOGY_CANDIDATE_CAP) : [];
29009
29327
  const globalPool = selectPool(globalRows, GLOBAL_TOPOLOGY_LIMIT);
29010
- const recentRows = db2.prepare(`SELECT ${CANDIDATE_COLUMNS}
29011
- FROM entities e
29012
- WHERE e.status = 'active'${nonGlobal}
29013
- ORDER BY e.id DESC
29014
- LIMIT ?`).all(TOPOLOGY_CANDIDATE_CAP);
29328
+ const recentRows = policy.foreign ? db2.prepare(`SELECT ${CANDIDATE_COLUMNS}
29329
+ FROM entities e
29330
+ WHERE e.status = 'active'${nonGlobal}
29331
+ ORDER BY e.id DESC
29332
+ LIMIT ?`).all(TOPOLOGY_CANDIDATE_CAP) : [];
29015
29333
  const recentPool = selectPool(recentRows, RECENT_LIMIT);
29016
29334
  const survivorIds = [...new Set([...projectPool, ...globalPool, ...recentPool].map((row) => row.id))];
29017
29335
  const snippets = /* @__PURE__ */ new Map();
@@ -29036,13 +29354,17 @@ function assembleBriefing(project, recipient) {
29036
29354
  ], projectName);
29037
29355
  const withRepo = lines.length > 0 && repoLines.length > 0 ? [...repoLines, "", ...lines] : lines;
29038
29356
  const index = readBriefingIndex(db2, projectName);
29039
- const block = withRepo.length > 0 ? [...withRepo, "", ...index.lines] : index.lines;
29357
+ const indexLines = policy.index ? index.lines : [];
29358
+ const block = withRepo.length > 0 && indexLines.length > 0 ? [...withRepo, "", ...indexLines] : [...withRepo, ...indexLines];
29359
+ const empty = !hasBriefingContent(block);
29040
29360
  return {
29041
29361
  project: projectName,
29042
- text: buildReferenceContext(block),
29362
+ text: empty ? "" : buildReferenceContext(block),
29043
29363
  entityCount: lines.filter((l) => l.startsWith("- [")).length,
29044
29364
  hasTaskState: stateLines.length > 0,
29045
- index
29365
+ index,
29366
+ level,
29367
+ empty
29046
29368
  };
29047
29369
  }
29048
29370
 
@@ -29054,7 +29376,7 @@ import { createHash as createHash9, randomBytes, randomUUID as randomUUID2 } fro
29054
29376
 
29055
29377
  // dist/core/agent-message-storage.js
29056
29378
  import { createHash as createHash8, randomUUID } from "node:crypto";
29057
- import fs5 from "node:fs";
29379
+ import fs6 from "node:fs";
29058
29380
  var TERMINAL_WORKFLOW_STATES = /* @__PURE__ */ new Set(["completed", "cancelled", "rejected"]);
29059
29381
  var AgentMessageStorageError = class extends Error {
29060
29382
  code;
@@ -29686,7 +30008,7 @@ function parseTargetKind(value) {
29686
30008
  }
29687
30009
  function parseJsonObject(json2, label) {
29688
30010
  const parsed = parseJsonObjectOrValue(json2);
29689
- if (!isPlainObject3(parsed))
30011
+ if (!isPlainObject4(parsed))
29690
30012
  throw new AgentMessagingError(`${label} must contain a JSON object.`);
29691
30013
  return parsed;
29692
30014
  }
@@ -29736,7 +30058,7 @@ function assertJsonValue(value, label) {
29736
30058
  value.forEach((entry, index) => assertJsonValue(entry, `${label}[${index}]`));
29737
30059
  return;
29738
30060
  }
29739
- if (isPlainObject3(value)) {
30061
+ if (isPlainObject4(value)) {
29740
30062
  for (const [key, entry] of Object.entries(value)) {
29741
30063
  assertJsonValue(entry, `${label}.${key}`);
29742
30064
  }
@@ -29748,7 +30070,7 @@ function normalizeObject(value) {
29748
30070
  assertJsonValue(value, "object");
29749
30071
  return value;
29750
30072
  }
29751
- function isPlainObject3(value) {
30073
+ function isPlainObject4(value) {
29752
30074
  return typeof value === "object" && value !== null && !Array.isArray(value);
29753
30075
  }
29754
30076
  function requireText(label, value, maxLength) {
@@ -29917,7 +30239,8 @@ var ExportResultSchema = external_exports.object({
29917
30239
  var ImportSchema = external_exports.object({
29918
30240
  data: ExportResultSchema,
29919
30241
  namespace: external_exports.enum(NAMESPACES).optional(),
29920
- merge_strategy: external_exports.enum(["skip", "overwrite", "append"])
30242
+ merge_strategy: external_exports.enum(["skip", "overwrite", "append"]),
30243
+ restore_archived: external_exports.boolean().optional()
29921
30244
  }).strict();
29922
30245
  var LearnSchema = external_exports.object({
29923
30246
  error: external_exports.string().min(1).max(5e3),
@@ -30044,9 +30367,9 @@ var MessageSchema = external_exports.discriminatedUnion("action", [
30044
30367
 
30045
30368
  // dist/core/agent-router.js
30046
30369
  import { randomUUID as randomUUID3 } from "node:crypto";
30047
- import fs6 from "node:fs";
30370
+ import fs7 from "node:fs";
30048
30371
  import net from "node:net";
30049
- import path5 from "node:path";
30372
+ import path6 from "node:path";
30050
30373
  var AGENT_ROUTER_PROTOCOL_VERSION = 2;
30051
30374
  var AGENT_ROUTER_MAX_FRAME_BYTES = 64 * 1024;
30052
30375
  var MAX_LEASE_MS = 5 * 6e4;
@@ -30054,9 +30377,9 @@ var DEFAULT_CLIENT_TIMEOUT_MS = 2e3;
30054
30377
  var MAX_FIELD_LENGTH = 200;
30055
30378
  var MAX_ADAPTER_RECEIPT_BYTES = 16 * 1024;
30056
30379
  function isLegacyAgentRouterVersionMismatchResponse(value) {
30057
- if (!isPlainObject4(value) || value.version !== 1 || value.request_id !== "" || value.ok !== false)
30380
+ if (!isPlainObject5(value) || value.version !== 1 || value.request_id !== "" || value.ok !== false)
30058
30381
  return false;
30059
- if (!isPlainObject4(value.error))
30382
+ if (!isPlainObject5(value.error))
30060
30383
  return false;
30061
30384
  return value.error.code === "unsupported_type" || value.error.code === "unsupported_version";
30062
30385
  }
@@ -30124,7 +30447,7 @@ async function sendAgentRouterRequest(socketPath, request, timeoutMs = DEFAULT_C
30124
30447
  if (isLegacyAgentRouterVersionMismatchResponse(response)) {
30125
30448
  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.");
30126
30449
  }
30127
- const uncorrelatedError = response.request_id === "" && response.ok === false && isPlainObject4(response.error) && typeof response.error.code === "string" && typeof response.error.message === "string";
30450
+ const uncorrelatedError = response.request_id === "" && response.ok === false && isPlainObject5(response.error) && typeof response.error.code === "string" && typeof response.error.message === "string";
30128
30451
  if (response.version !== AGENT_ROUTER_PROTOCOL_VERSION || response.request_id !== request.request_id && !uncorrelatedError) {
30129
30452
  throw new AgentRouterProtocolError("invalid_response", "Router response identity does not match.");
30130
30453
  }
@@ -30143,7 +30466,7 @@ async function sendAgentRouterRequest(socketPath, request, timeoutMs = DEFAULT_C
30143
30466
  });
30144
30467
  }
30145
30468
  function validateRouterSuccessResult(request, value) {
30146
- if (!isPlainObject4(value)) {
30469
+ if (!isPlainObject5(value)) {
30147
30470
  throw new AgentRouterProtocolError("invalid_response", "Router response result must be an object.");
30148
30471
  }
30149
30472
  const requireResultString = (field) => {
@@ -30201,17 +30524,17 @@ function validateRouterSuccessResult(request, value) {
30201
30524
  return value;
30202
30525
  }
30203
30526
  function isSelectionCard(value, project) {
30204
- if (!isPlainObject4(value))
30527
+ if (!isPlainObject5(value))
30205
30528
  return false;
30206
30529
  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;
30207
30530
  }
30208
30531
  function validateSocketPath(socketPath) {
30209
- if (typeof socketPath !== "string" || !path5.isAbsolute(socketPath) || Buffer.byteLength(socketPath) > 103) {
30532
+ if (typeof socketPath !== "string" || !path6.isAbsolute(socketPath) || Buffer.byteLength(socketPath) > 103) {
30210
30533
  throw new AgentRouterProtocolError("invalid_socket_path", "Router socket path must be absolute and at most 103 bytes.");
30211
30534
  }
30212
30535
  return socketPath;
30213
30536
  }
30214
- function isPlainObject4(value) {
30537
+ function isPlainObject5(value) {
30215
30538
  return typeof value === "object" && value !== null && !Array.isArray(value);
30216
30539
  }
30217
30540
 
@@ -30564,14 +30887,14 @@ async function executeAgentMessageAction(db2, rawInput, context, dependencies =
30564
30887
  }
30565
30888
 
30566
30889
  // dist/core/update-entrypoint.js
30567
- import fs9 from "fs";
30568
- import path8 from "path";
30890
+ import fs10 from "fs";
30891
+ import path9 from "path";
30569
30892
  import { spawn } from "child_process";
30570
30893
  import { fileURLToPath } from "url";
30571
30894
 
30572
30895
  // dist/core/version-check.js
30573
- import fs7 from "fs";
30574
- import path6 from "path";
30896
+ import fs8 from "fs";
30897
+ import path7 from "path";
30575
30898
 
30576
30899
  // dist/core/semver.js
30577
30900
  var SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
@@ -30640,7 +30963,7 @@ function getUpdateCheckPath(updateCheckPath, currentVersion) {
30640
30963
  if (process.env.MEMESH_UPDATE_CHECK_PATH)
30641
30964
  return process.env.MEMESH_UPDATE_CHECK_PATH;
30642
30965
  const versionTag = currentVersion && /^[0-9A-Za-z.+-]+$/.test(currentVersion) ? currentVersion : "unknown";
30643
- return path6.join(memeshDir(), `update-check.${versionTag}.json`);
30966
+ return path7.join(memeshDir(), `update-check.${versionTag}.json`);
30644
30967
  }
30645
30968
  function parseIsoDate(value) {
30646
30969
  if (!value)
@@ -30715,9 +31038,9 @@ function parseStoredUpdateCheck(raw) {
30715
31038
  function readStoredUpdateCheck(updateCheckPath, currentVersion) {
30716
31039
  try {
30717
31040
  const targetPath = getUpdateCheckPath(updateCheckPath, currentVersion);
30718
- if (!fs7.existsSync(targetPath))
31041
+ if (!fs8.existsSync(targetPath))
30719
31042
  return null;
30720
- return parseStoredUpdateCheck(JSON.parse(fs7.readFileSync(targetPath, "utf8")));
31043
+ return parseStoredUpdateCheck(JSON.parse(fs8.readFileSync(targetPath, "utf8")));
30721
31044
  } catch {
30722
31045
  return null;
30723
31046
  }
@@ -30730,8 +31053,8 @@ function getLastUpdateCheck(currentVersion, options = {}) {
30730
31053
  }
30731
31054
 
30732
31055
  // dist/core/update-notice.js
30733
- import fs8 from "fs";
30734
- import path7 from "path";
31056
+ import fs9 from "fs";
31057
+ import path8 from "path";
30735
31058
  var UP_TO_DATE_REFRESH_MS = 60 * 60 * 1e3;
30736
31059
  var UPGRADE_AVAILABLE_REFRESH_MS = 12 * 60 * 60 * 1e3;
30737
31060
  var ANSWER_VALID_MS = 24 * 60 * 60 * 1e3;
@@ -30767,16 +31090,16 @@ function parseIso(value) {
30767
31090
  }
30768
31091
  function readJson(file2) {
30769
31092
  try {
30770
- if (!fs8.existsSync(file2))
31093
+ if (!fs9.existsSync(file2))
30771
31094
  return null;
30772
- const parsed = JSON.parse(fs8.readFileSync(file2, "utf8"));
31095
+ const parsed = JSON.parse(fs9.readFileSync(file2, "utf8"));
30773
31096
  return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
30774
31097
  } catch {
30775
31098
  return null;
30776
31099
  }
30777
31100
  }
30778
31101
  function readSnooze(dir) {
30779
- const raw = readJson(path7.join(dir, SNOOZE_FILE));
31102
+ const raw = readJson(path8.join(dir, SNOOZE_FILE));
30780
31103
  if (!raw)
30781
31104
  return null;
30782
31105
  const { target, level, since } = raw;
@@ -30794,7 +31117,7 @@ function snoozeExpiresAt(state) {
30794
31117
  return since + duration3;
30795
31118
  }
30796
31119
  function readJustUpgradedMarker(dir) {
30797
- const raw = readJson(path7.join(dir, JUST_UPGRADED_FILE));
31120
+ const raw = readJson(path8.join(dir, JUST_UPGRADED_FILE));
30798
31121
  if (!raw)
30799
31122
  return null;
30800
31123
  const { from, to, at } = raw;
@@ -30804,21 +31127,21 @@ function readJustUpgradedMarker(dir) {
30804
31127
  }
30805
31128
  function clearJustUpgradedMarker(dir) {
30806
31129
  try {
30807
- fs8.unlinkSync(path7.join(dir, JUST_UPGRADED_FILE));
31130
+ fs9.unlinkSync(path8.join(dir, JUST_UPGRADED_FILE));
30808
31131
  } catch {
30809
31132
  }
30810
31133
  }
30811
31134
  function claimJustUpgradedMarker(dir) {
30812
- const file2 = path7.join(dir, JUST_UPGRADED_FILE);
31135
+ const file2 = path8.join(dir, JUST_UPGRADED_FILE);
30813
31136
  const taken = `${file2}.claimed-${process.pid}-${Math.random().toString(36).slice(2, 8)}`;
30814
31137
  try {
30815
- fs8.renameSync(file2, taken);
31138
+ fs9.renameSync(file2, taken);
30816
31139
  } catch {
30817
31140
  return null;
30818
31141
  }
30819
31142
  const raw = readJson(taken);
30820
31143
  try {
30821
- fs8.unlinkSync(taken);
31144
+ fs9.unlinkSync(taken);
30822
31145
  } catch {
30823
31146
  }
30824
31147
  if (!raw)
@@ -30905,31 +31228,31 @@ function formatUpdateNoticeLine(notice) {
30905
31228
  }
30906
31229
  }
30907
31230
  function recentHookNoticeExists(dir, currentVersion, latestVersion, now = /* @__PURE__ */ new Date()) {
30908
- const claims = path8.join(dir, "update-prompt-claims");
31231
+ const claims = path9.join(dir, "update-prompt-claims");
30909
31232
  let names;
30910
31233
  try {
30911
- names = fs9.readdirSync(claims);
31234
+ names = fs10.readdirSync(claims);
30912
31235
  } catch {
30913
31236
  return false;
30914
31237
  }
30915
31238
  for (const name of names) {
30916
31239
  if (!name.endsWith(".json"))
30917
31240
  continue;
30918
- const file2 = path8.join(claims, name);
31241
+ const file2 = path9.join(claims, name);
30919
31242
  let fd = null;
30920
31243
  try {
30921
- fd = fs9.openSync(file2, "r");
30922
- const stat = fs9.fstatSync(fd);
31244
+ fd = fs10.openSync(file2, "r");
31245
+ const stat = fs10.fstatSync(fd);
30923
31246
  if (now.getTime() - stat.mtimeMs > RECENT_HOOK_NOTICE_MS)
30924
31247
  continue;
30925
- const value = JSON.parse(fs9.readFileSync(fd, "utf8"));
31248
+ const value = JSON.parse(fs10.readFileSync(fd, "utf8"));
30926
31249
  if (value.currentVersion === currentVersion && (latestVersion === null || value.latestVersion === latestVersion))
30927
31250
  return true;
30928
31251
  } catch {
30929
31252
  } finally {
30930
31253
  if (fd !== null)
30931
31254
  try {
30932
- fs9.closeSync(fd);
31255
+ fs10.closeSync(fd);
30933
31256
  } catch {
30934
31257
  }
30935
31258
  }
@@ -30938,7 +31261,7 @@ function recentHookNoticeExists(dir, currentVersion, latestVersion, now = /* @__
30938
31261
  }
30939
31262
  function updateCheckEnabledIn(dir) {
30940
31263
  try {
30941
- const raw = JSON.parse(fs9.readFileSync(path8.join(dir, "config.json"), "utf8"));
31264
+ const raw = JSON.parse(fs10.readFileSync(path9.join(dir, "config.json"), "utf8"));
30942
31265
  return raw.updateCheck !== false;
30943
31266
  } catch {
30944
31267
  return true;
@@ -30946,34 +31269,34 @@ function updateCheckEnabledIn(dir) {
30946
31269
  }
30947
31270
  function cliThrottled(dir, currentVersion, now) {
30948
31271
  const tag = /^[0-9A-Za-z.+-]+$/.test(currentVersion) ? currentVersion : "unknown";
30949
- const marker = path8.join(dir, `last-cli-update-notice.${tag}.lock`);
31272
+ const marker = path9.join(dir, `last-cli-update-notice.${tag}.lock`);
30950
31273
  let fd = null;
30951
31274
  try {
30952
31275
  try {
30953
- fd = fs9.openSync(marker, "r+");
31276
+ fd = fs10.openSync(marker, "r+");
30954
31277
  } catch (err) {
30955
31278
  const code = err.code;
30956
31279
  if (code !== "ENOENT") {
30957
31280
  return true;
30958
31281
  }
30959
- fs9.mkdirSync(dir, { recursive: true, mode: 448 });
31282
+ fs10.mkdirSync(dir, { recursive: true, mode: 448 });
30960
31283
  try {
30961
- fd = fs9.openSync(marker, "wx", 384);
31284
+ fd = fs10.openSync(marker, "wx", 384);
30962
31285
  } catch (raceErr) {
30963
31286
  if (raceErr.code === "EEXIST")
30964
31287
  return true;
30965
31288
  throw raceErr;
30966
31289
  }
30967
- fs9.writeSync(fd, String(now.getTime()));
31290
+ fs10.writeSync(fd, String(now.getTime()));
30968
31291
  return false;
30969
31292
  }
30970
- const stat = fs9.fstatSync(fd);
31293
+ const stat = fs10.fstatSync(fd);
30971
31294
  if (now.getTime() - stat.mtimeMs < CLI_NOTICE_THROTTLE_MS)
30972
31295
  return true;
30973
- fs9.ftruncateSync(fd, 0);
30974
- fs9.writeSync(fd, String(now.getTime()), 0);
31296
+ fs10.ftruncateSync(fd, 0);
31297
+ fs10.writeSync(fd, String(now.getTime()), 0);
30975
31298
  try {
30976
- fs9.fchmodSync(fd, 384);
31299
+ fs10.fchmodSync(fd, 384);
30977
31300
  } catch {
30978
31301
  }
30979
31302
  return false;
@@ -30982,7 +31305,7 @@ function cliThrottled(dir, currentVersion, now) {
30982
31305
  } finally {
30983
31306
  if (fd !== null)
30984
31307
  try {
30985
- fs9.closeSync(fd);
31308
+ fs10.closeSync(fd);
30986
31309
  } catch {
30987
31310
  }
30988
31311
  }
@@ -30990,23 +31313,23 @@ function cliThrottled(dir, currentVersion, now) {
30990
31313
  function spawnCacheRefresh(dir, currentVersion, now) {
30991
31314
  try {
30992
31315
  const cliPath = fileURLToPath(new URL("../transports/cli/cli.js", import.meta.url));
30993
- if (!fs9.existsSync(cliPath))
31316
+ if (!fs10.existsSync(cliPath))
30994
31317
  return false;
30995
31318
  const tag = /^[0-9A-Za-z.+-]+$/.test(currentVersion) ? currentVersion : "unknown";
30996
- const marker = path8.join(dir, `last-fresh-refresh.${tag}.lock`);
31319
+ const marker = path9.join(dir, `last-fresh-refresh.${tag}.lock`);
30997
31320
  try {
30998
- if (now.getTime() - fs9.statSync(marker).mtimeMs < FRESH_CHECK_THROTTLE_MS)
31321
+ if (now.getTime() - fs10.statSync(marker).mtimeMs < FRESH_CHECK_THROTTLE_MS)
30999
31322
  return false;
31000
- fs9.unlinkSync(marker);
31323
+ fs10.unlinkSync(marker);
31001
31324
  } catch {
31002
31325
  }
31003
- fs9.mkdirSync(dir, { recursive: true, mode: 448 });
31326
+ fs10.mkdirSync(dir, { recursive: true, mode: 448 });
31004
31327
  try {
31005
- const fd = fs9.openSync(marker, "wx", 384);
31328
+ const fd = fs10.openSync(marker, "wx", 384);
31006
31329
  try {
31007
- fs9.writeSync(fd, `${process.pid}-${now.getTime()}`);
31330
+ fs10.writeSync(fd, `${process.pid}-${now.getTime()}`);
31008
31331
  } finally {
31009
- fs9.closeSync(fd);
31332
+ fs10.closeSync(fd);
31010
31333
  }
31011
31334
  } catch {
31012
31335
  return false;
@@ -31071,7 +31394,7 @@ function updateNoticeForEntryPoint(input) {
31071
31394
  const dir = input.dir ?? memeshDir();
31072
31395
  const updateCheckEnabled = input.updateCheckEnabled ?? updateCheckEnabledIn(dir);
31073
31396
  const tag = /^[0-9A-Za-z.+-]+$/.test(input.currentVersion) ? input.currentVersion : "unknown";
31074
- const cache = getLastUpdateCheck(input.currentVersion, { now, updateCheckPath: path8.join(dir, `update-check.${tag}.json`) });
31397
+ const cache = getLastUpdateCheck(input.currentVersion, { now, updateCheckPath: path9.join(dir, `update-check.${tag}.json`) });
31075
31398
  if (updateCheckEnabled && shouldRefreshUpdateCache(input.currentVersion, cache, now)) {
31076
31399
  (input.refresh ?? spawnCacheRefresh)(dir, input.currentVersion, now);
31077
31400
  }
@@ -31110,8 +31433,8 @@ function resolveTranscriptWorkspace(project, rootUris) {
31110
31433
  const parsed = new URL(uri);
31111
31434
  if (parsed.protocol !== "file:")
31112
31435
  continue;
31113
- const root = fs10.realpathSync(fileURLToPath2(parsed));
31114
- if (!fs10.statSync(root).isDirectory() || getProjectName(root) !== project)
31436
+ const root = fs11.realpathSync(fileURLToPath2(parsed));
31437
+ if (!fs11.statSync(root).isDirectory() || getProjectName(root) !== project)
31115
31438
  continue;
31116
31439
  matches.add(root);
31117
31440
  } catch {
@@ -31261,7 +31584,7 @@ var TOOL_DEFINITIONS = [
31261
31584
  },
31262
31585
  {
31263
31586
  name: "import",
31264
- description: "Import memories from a JSON export snapshot. Supports skip, append, or overwrite strategies for handling existing entities.",
31587
+ description: "Import memories from a JSON export snapshot. Supports skip, append, or overwrite strategies for handling existing entities. A local memory that was forgotten (archived) stays archived unless restore_archived is true; the result reports how many were left as they were in kept_archived.",
31265
31588
  inputSchema: {
31266
31589
  type: "object",
31267
31590
  properties: {
@@ -31271,6 +31594,10 @@ var TOOL_DEFINITIONS = [
31271
31594
  type: "string",
31272
31595
  enum: ["skip", "overwrite", "append"],
31273
31596
  description: "Required. How to handle an entity that already exists: skip = leave it untouched, append = add these observations to it, overwrite = REPLACE its observations and tags (the old ones are deleted, not archived \u2014 this cannot be undone)"
31597
+ },
31598
+ restore_archived: {
31599
+ type: "boolean",
31600
+ description: "Optional, default false. With append or overwrite, a local entity that is archived (forgotten) is left untouched and counted in kept_archived. Set true to bring it back to active and merge or overwrite it like any other; it requires merge_strategy append or overwrite (an error with skip). Only set it when the user asked for archived memories to return."
31274
31601
  }
31275
31602
  },
31276
31603
  required: ["data", "merge_strategy"],
@@ -31299,7 +31626,7 @@ var TOOL_DEFINITIONS = [
31299
31626
  },
31300
31627
  {
31301
31628
  name: "task_state",
31302
- description: 'Read or update where the work stands on this project: the goal, what is next, what is blocked, what was just finished. Call with no arguments to read it. Injected at the start of the next session, so record ONLY what the user actually stated \u2014 never infer a goal or a next step from files edited or commands run, and leave a field out if it was not said. Pass an empty string to clear a field (e.g. blocked: "" once a blocker is resolved).',
31629
+ description: `Read or update where the work stands on this project: the goal, what is next, what is blocked, what was just finished. Call with no arguments to read it. Included in the next session's briefing at the default level, so record ONLY what the user actually stated \u2014 never infer a goal or a next step from files edited or commands run, and leave a field out if it was not said. Pass an empty string to clear a field (e.g. blocked: "" once a blocker is resolved).`,
31303
31630
  inputSchema: {
31304
31631
  type: "object",
31305
31632
  properties: {
@@ -31317,7 +31644,7 @@ var TOOL_DEFINITIONS = [
31317
31644
  },
31318
31645
  {
31319
31646
  name: "briefing",
31320
- description: "The work topology for a project, assembled and ready to use: where the work was left off (goal / next / blocked / done), decisions and direction, lessons not to repeat, what is known, recent activity, and a capped index of the project\u2019s durable memories (one line each, newest first, with [mem:id] handles; structured counts and token cost in `index`) \u2014 the same block Claude Code receives at session start. Call once at the START of a session to load project context; use recall for specific questions after that. Content is wrapped as untrusted background data.",
31647
+ description: "The work topology for a project, assembled and ready to use: where the work was left off (goal / next / blocked / done), decisions and direction, lessons not to repeat, what is known, recent activity, and a capped index of the project\u2019s durable memories (one line each, newest first, with [mem:id] handles; structured counts and token cost in `index`) \u2014 the same memory block Claude Code receives at session start (at `full`, the SessionStart hook additionally appends a work-package notice; that notice is a host-agent instruction, not memory, and is never part of this tool\u2019s output). How much of this is assembled follows the `briefing` setting (`minimal`, `standard` \u2014 the default, described above \u2014 or `full`, which additionally includes memories from other projects and global memory); at `minimal` it is only this project\u2019s live repository state, decisions, lessons, known facts and recent activity, with no task state and no index, and may be empty. Call once at the START of a session to load project context; use recall for specific questions after that. Content is wrapped as untrusted background data.",
31321
31648
  inputSchema: {
31322
31649
  type: "object",
31323
31650
  properties: {
@@ -31436,8 +31763,8 @@ function fail(message) {
31436
31763
  return { content: [{ type: "text", text: message }], isError: true };
31437
31764
  }
31438
31765
  function formatIssue(issue2) {
31439
- const path10 = issue2.path.join(".");
31440
- return path10 ? `${path10}: ${issue2.message}` : issue2.message;
31766
+ const path11 = issue2.path.join(".");
31767
+ return path11 ? `${path11}: ${issue2.message}` : issue2.message;
31441
31768
  }
31442
31769
  function stripNullProps(value) {
31443
31770
  if (Array.isArray(value))
@@ -31478,7 +31805,7 @@ function normalizeClientHost(name) {
31478
31805
  }
31479
31806
  var packageVersion = (() => {
31480
31807
  try {
31481
- return JSON.parse(fs10.readFileSync(new URL("../../../package.json", import.meta.url), "utf8")).version ?? "0.0.0";
31808
+ return JSON.parse(fs11.readFileSync(new URL("../../../package.json", import.meta.url), "utf8")).version ?? "0.0.0";
31482
31809
  } catch {
31483
31810
  return "0.0.0";
31484
31811
  }
@@ -31655,8 +31982,8 @@ async function handleToolInner(name, args, sourceHost, signal, requestContext =
31655
31982
  }
31656
31983
 
31657
31984
  // dist/mcp/server.js
31658
- var packageJsonPath = path9.resolve(path9.dirname(fileURLToPath3(import.meta.url)), "../../package.json");
31659
- var packageVersion2 = JSON.parse(fs11.readFileSync(packageJsonPath, "utf8")).version ?? "0.0.0";
31985
+ var packageJsonPath = path10.resolve(path10.dirname(fileURLToPath3(import.meta.url)), "../../package.json");
31986
+ var packageVersion2 = JSON.parse(fs12.readFileSync(packageJsonPath, "utf8")).version ?? "0.0.0";
31660
31987
  var server = new Server({ name: "memesh", version: packageVersion2 }, { capabilities: { tools: {} } });
31661
31988
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
31662
31989
  tools: TOOL_DEFINITIONS.map((t) => ({