@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
@@ -0,0 +1,82 @@
1
+ // ============================================================================
2
+ // AUTO-GENERATED from src/core/briefing-level.ts — DO NOT EDIT BY HAND.
3
+ // Regenerate with: npm run build (scripts/generate-hook-core.mjs)
4
+ //
5
+ // Claude Code hooks import this committed copy instead of dist/, so the
6
+ // always-on capture path survives a missing or stale dist/ while staying
7
+ // byte-locked to core — eliminating the hand-mirror drift behind the P0 FTS bug.
8
+ // ============================================================================
9
+ export const BRIEFING_LEVELS = ['minimal', 'standard', 'full'];
10
+ export const DEFAULT_BRIEFING_LEVEL = 'standard';
11
+ export function isBriefingLevel(value) {
12
+ return typeof value === 'string' && BRIEFING_LEVELS.includes(value);
13
+ }
14
+ const INVALID_VALUE_SERIALIZED_MAX = 100;
15
+ const PRE_SLICE_RAW_MAX = 256;
16
+ function safeRawPreSlice(value, maxUnits) {
17
+ if (value.length <= maxUnits)
18
+ return value;
19
+ let end = maxUnits;
20
+ const lastKept = value.charCodeAt(end - 1);
21
+ const nextUnit = value.charCodeAt(end);
22
+ const lastKeptIsHighSurrogate = lastKept >= 0xd800 && lastKept <= 0xdbff;
23
+ const nextUnitIsLowSurrogate = nextUnit >= 0xdc00 && nextUnit <= 0xdfff;
24
+ if (lastKeptIsHighSurrogate && nextUnitIsLowSurrogate)
25
+ end -= 1;
26
+ return value.slice(0, end);
27
+ }
28
+ function truncateToSerializedBound(codePoints) {
29
+ let kept = 0;
30
+ for (; kept < codePoints.length; kept++) {
31
+ const candidate = JSON.stringify(`${codePoints.slice(0, kept + 1).join('')}…`);
32
+ if (candidate.length > INVALID_VALUE_SERIALIZED_MAX)
33
+ break;
34
+ }
35
+ return JSON.stringify(`${codePoints.slice(0, kept).join('')}…`);
36
+ }
37
+ function describeInvalidValue(value) {
38
+ if (typeof value === 'string') {
39
+ if (value.length <= INVALID_VALUE_SERIALIZED_MAX) {
40
+ const whole = JSON.stringify(value);
41
+ if (whole.length <= INVALID_VALUE_SERIALIZED_MAX)
42
+ return whole;
43
+ return truncateToSerializedBound(Array.from(value));
44
+ }
45
+ return truncateToSerializedBound(Array.from(safeRawPreSlice(value, PRE_SLICE_RAW_MAX)));
46
+ }
47
+ if (Array.isArray(value))
48
+ return '[array]';
49
+ if (value !== null && typeof value === 'object')
50
+ return '[object]';
51
+ if (typeof value === 'bigint')
52
+ return '[bigint]';
53
+ if (typeof value === 'symbol')
54
+ return '[symbol]';
55
+ if (typeof value === 'function')
56
+ return '[function]';
57
+ return JSON.stringify(value) ?? String(value);
58
+ }
59
+ export function resolveBriefingLevel(envValue, configValue) {
60
+ if (envValue !== undefined) {
61
+ if (isBriefingLevel(envValue))
62
+ return { level: envValue, invalid: null };
63
+ return { level: DEFAULT_BRIEFING_LEVEL, invalid: { source: 'env', value: describeInvalidValue(envValue) } };
64
+ }
65
+ if (configValue !== undefined) {
66
+ if (isBriefingLevel(configValue))
67
+ return { level: configValue, invalid: null };
68
+ return { level: DEFAULT_BRIEFING_LEVEL, invalid: { source: 'config', value: describeInvalidValue(configValue) } };
69
+ }
70
+ return { level: DEFAULT_BRIEFING_LEVEL, invalid: null };
71
+ }
72
+ const POLICIES = {
73
+ minimal: { global: false, foreign: false, taskState: false, index: false, workPackageNotice: false },
74
+ standard: { global: false, foreign: false, taskState: true, index: true, workPackageNotice: false },
75
+ full: { global: true, foreign: true, taskState: true, index: true, workPackageNotice: true },
76
+ };
77
+ export function briefingLevelPolicy(level) {
78
+ return POLICIES[level];
79
+ }
80
+ export function sessionStartAppendsWorkPackageNotice(level) {
81
+ return briefingLevelPolicy(level).workPackageNotice;
82
+ }
@@ -130,6 +130,7 @@ export const SKIP_REASONS = {
130
130
  noFilePath: 'no file_path in the tool input',
131
131
  noDatabaseForRecall: 'no database yet — nothing to recall',
132
132
  nothingToRecall: 'no guard matched and nothing to recall for this file',
133
+ candidateWindowTruncated: 'more candidates may exist than the search window examined',
133
134
  noPromptIntent: 'the prompt carried no remember intent and no update decision',
134
135
  noMemoryDir: 'no Claude Code memory directory for this project',
135
136
  noNoteChanged: 'no note file changed since the last ingestion',
@@ -100,6 +100,10 @@ function tryGit(cwd, args) {
100
100
  return null;
101
101
  }
102
102
  }
103
+ export function gitRepoRoot(cwdInput) {
104
+ const cwd = cwdInput && cwdInput.length > 0 ? cwdInput : process.cwd();
105
+ return tryGit(cwd, ['rev-parse', '--show-toplevel']);
106
+ }
103
107
  export function canonicalRemoteLocator(remote) {
104
108
  const value = remote.trim();
105
109
  if (!value)
@@ -62,6 +62,11 @@ const LONE_UNSPACED_CHAR = new RegExp(`[${UNSPACED_SCRIPT_CLASS}]`, 'u');
62
62
  export function isLoneUnspacedChar(term) {
63
63
  return [...term].length === 1 && LONE_UNSPACED_CHAR.test(term);
64
64
  }
65
+ export function renderPhraseExpression(terms) {
66
+ if (terms.length === 0)
67
+ return null;
68
+ return `"${terms.map((term) => term.replace(/"/g, '""')).join(' ')}"`;
69
+ }
65
70
  function foldTitleIntoObservations(title, observationsText) {
66
71
  return title ? `${title} ${observationsText}` : observationsText;
67
72
  }
@@ -96,3 +96,73 @@ export function taskStateLines(state, project, now = new Date()) {
96
96
  }
97
97
  return lines;
98
98
  }
99
+ export const STALE_TASK_STATE_HOURS = 72;
100
+ export const CLOCK_SKEW_ALLOWANCE_MINUTES = 5;
101
+ const 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}))$/;
102
+ function isLeapYear(year) {
103
+ return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
104
+ }
105
+ const DAYS_IN_MONTH = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
106
+ function daysInMonth(year, month) {
107
+ return month === 2 && isLeapYear(year) ? 29 : DAYS_IN_MONTH[month - 1];
108
+ }
109
+ function isRealInstant(groups) {
110
+ const year = Number(groups.year);
111
+ const month = Number(groups.month);
112
+ const day = Number(groups.day);
113
+ const hour = Number(groups.hour);
114
+ const minute = Number(groups.minute);
115
+ const second = groups.second === undefined ? 0 : Number(groups.second);
116
+ if (month < 1 || month > 12)
117
+ return false;
118
+ if (day < 1 || day > daysInMonth(year, month))
119
+ return false;
120
+ if (hour > 23)
121
+ return false;
122
+ if (minute > 59)
123
+ return false;
124
+ if (second > 59)
125
+ return false;
126
+ if (groups.zulu === undefined) {
127
+ const offHour = Number(groups.offHour);
128
+ const offMinute = Number(groups.offMinute);
129
+ if (offHour > 23 || offMinute > 59)
130
+ return false;
131
+ if (groups.offSign === '-' && offHour === 0 && offMinute === 0)
132
+ return false;
133
+ }
134
+ return true;
135
+ }
136
+ function resolveTaskStateAge(updatedAt, now) {
137
+ if (!updatedAt)
138
+ return { known: false };
139
+ const match = ZONED_INSTANT.exec(updatedAt);
140
+ if (!match?.groups || !isRealInstant(match.groups))
141
+ return { known: false };
142
+ const then = Date.parse(updatedAt);
143
+ if (Number.isNaN(then))
144
+ return { known: false };
145
+ const hours = (now.getTime() - then) / 3_600_000;
146
+ if (hours < -(CLOCK_SKEW_ALLOWANCE_MINUTES / 60))
147
+ return { known: false };
148
+ return { known: true, hours: Math.max(0, hours) };
149
+ }
150
+ function staleTaskStateLine(project, hours) {
151
+ const days = Math.floor(hours / 24);
152
+ const age = days >= 1 ? `${days} day${days === 1 ? '' : 's'} ago` : `${Math.floor(hours)} hour${Math.floor(hours) === 1 ? '' : 's'} ago`;
153
+ return `Task state for "${project}" was last stated ${age} — older than ${STALE_TASK_STATE_HOURS}h, so it is not shown as current. Run \`memesh task\` to see or update it.`;
154
+ }
155
+ function taskStateAgeUnknownLine(project) {
156
+ return `Task state for "${project}" has a missing, unreadable, or future-dated timestamp, so its age could not be established — not shown as current. Run \`memesh task\` to see or update it.`;
157
+ }
158
+ export function briefingTaskStateLines(state, project, now = new Date(), { includeFresh = true } = {}) {
159
+ if (isEmptyTaskState(state))
160
+ return [];
161
+ const age = resolveTaskStateAge(state.updated_at, now);
162
+ if (!age.known)
163
+ return [taskStateAgeUnknownLine(project)];
164
+ if (age.hours > STALE_TASK_STATE_HOURS) {
165
+ return [staleTaskStateLine(project, age.hours)];
166
+ }
167
+ return includeFresh ? taskStateLines(state, project, now) : [];
168
+ }
@@ -200,6 +200,9 @@ export function assembleTopologyBlock(stateLines, pools, projectName, budget = D
200
200
  lines.push(...globalLines);
201
201
  return lines;
202
202
  }
203
+ export function hasBriefingContent(lines) {
204
+ return lines.length > 0;
205
+ }
203
206
  export function buildReferenceContext(memoryLines) {
204
207
  const safeLines = memoryLines.map((line) => String(line ?? '')
205
208
  .replace(/[\s\u0085\u001c-\u001e]+/g, ' ')