@mnemonik/shared 7.72.0 → 7.72.6

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.
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ export { AST_LANGUAGE_IDS, QUERY_CHAIN, VENDORED_ARTIFACT_DIR, astArtifactReport
11
11
  export { MAX_AST_PARSE_BYTES, chunkWithAst, type AstChunk, type AstChunkResult, } from './ast/astChunker.js';
12
12
  export { SECRET_PATTERNS, SECRET_REDACTION_PLACEHOLDER, scrubSecrets, redactHighEntropyTokens, } from './secretPatterns.js';
13
13
  export { FETCH_TIMEOUT_MS, TELEMETRY_TIMEOUT_MS, POST_TOOL_TIMEOUT_MS, MCP_PRECHECK_TIMEOUT_MS, withHookTimeout, } from './hookTimeouts.js';
14
- export { persistJitDeliveryRef, readPendingJitDeliveryRefs, acknowledgeJitDeliveryRefs, } from './jitDeliveryAck.js';
14
+ export { persistJitDeliveryRef, readPendingJitDeliveryRefs, reportJitDeliveryRefsAttached, acknowledgeJitDeliveryRefs, pruneExpiredJitDeliveryRefs, applyJitDeliveryReceiptResponse, normalizeJitHookVersion, type JitReceiptClientEvent, type JitReceiptClientEventName, type JitReceiptEventContext, } from './jitDeliveryAck.js';
15
15
  export * from './settingsIo.js';
16
16
  export * from './claudeProxySettings.js';
17
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,SAAS,EACd,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,wBAAwB,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,KAAK,QAAQ,EACb,KAAK,cAAc,GACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,eAAe,EACf,4BAA4B,EAC5B,YAAY,EACZ,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,SAAS,EACd,KAAK,WAAW,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,wBAAwB,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,KAAK,QAAQ,EACb,KAAK,cAAc,GACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,eAAe,EACf,4BAA4B,EAC5B,YAAY,EACZ,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,+BAA+B,EAC/B,uBAAuB,EACvB,KAAK,qBAAqB,EAC1B,KAAK,yBAAyB,EAC9B,KAAK,sBAAsB,GAC5B,MAAM,qBAAqB,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC"}
package/dist/index.js CHANGED
@@ -11,7 +11,7 @@ export { AST_LANGUAGE_IDS, QUERY_CHAIN, VENDORED_ARTIFACT_DIR, astArtifactReport
11
11
  export { MAX_AST_PARSE_BYTES, chunkWithAst, } from './ast/astChunker.js';
12
12
  export { SECRET_PATTERNS, SECRET_REDACTION_PLACEHOLDER, scrubSecrets, redactHighEntropyTokens, } from './secretPatterns.js';
13
13
  export { FETCH_TIMEOUT_MS, TELEMETRY_TIMEOUT_MS, POST_TOOL_TIMEOUT_MS, MCP_PRECHECK_TIMEOUT_MS, withHookTimeout, } from './hookTimeouts.js';
14
- export { persistJitDeliveryRef, readPendingJitDeliveryRefs, acknowledgeJitDeliveryRefs, } from './jitDeliveryAck.js';
14
+ export { persistJitDeliveryRef, readPendingJitDeliveryRefs, reportJitDeliveryRefsAttached, acknowledgeJitDeliveryRefs, pruneExpiredJitDeliveryRefs, applyJitDeliveryReceiptResponse, normalizeJitHookVersion, } from './jitDeliveryAck.js';
15
15
  export * from './settingsIo.js';
16
16
  export * from './claudeProxySettings.js';
17
17
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,GAGrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GAKnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,mBAAmB,EACnB,YAAY,GAGb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,eAAe,EACf,4BAA4B,EAC5B,YAAY,EACZ,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC/F,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,sBAAsB,EACtB,uBAAuB,EACvB,oBAAoB,EACpB,0BAA0B,EAC1B,oBAAoB,EACpB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,GAGrB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,gBAAgB,EAChB,WAAW,EACX,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EACvB,WAAW,EACX,gBAAgB,EAChB,kBAAkB,GAKnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,mBAAmB,EACnB,YAAY,GAGb,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,eAAe,EACf,4BAA4B,EAC5B,YAAY,EACZ,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,uBAAuB,EACvB,eAAe,GAChB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,qBAAqB,EACrB,0BAA0B,EAC1B,6BAA6B,EAC7B,0BAA0B,EAC1B,2BAA2B,EAC3B,+BAA+B,EAC/B,uBAAuB,GAIxB,MAAM,qBAAqB,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC"}
@@ -1,6 +1,30 @@
1
+ export declare function normalizeJitHookVersion(hookVersion: unknown): string;
2
+ export type JitReceiptClientEventName = 'marker_persisted' | 'marker_read' | 'attached_to_request' | 'marker_confirmed' | 'pruned_expired';
3
+ export interface JitReceiptClientEvent {
4
+ mnemonik_marker: 'jit_receipt_client';
5
+ event: JitReceiptClientEventName;
6
+ deliveryRefHash: string;
7
+ sessionFingerprint: string;
8
+ hookVersion: string;
9
+ reason?: 'client_retention' | 'server_unknown_or_expired';
10
+ }
11
+ export interface JitReceiptEventContext {
12
+ sessionId: string;
13
+ hookVersion: string;
14
+ /** Test seam; production writes one JSON event per line to hook stderr. */
15
+ emit?: (event: JitReceiptClientEvent) => void;
16
+ }
1
17
  /** Persist only after the final host-visible payload contains this JIT result. */
2
- export declare function persistJitDeliveryRef(directory: string, deliveryRef: string): boolean;
3
- export declare function readPendingJitDeliveryRefs(directory: string): string[];
18
+ export declare function persistJitDeliveryRef(directory: string, deliveryRef: string, context?: JitReceiptEventContext): boolean;
19
+ export declare function readPendingJitDeliveryRefs(directory: string, context?: JitReceiptEventContext): string[];
20
+ export declare function reportJitDeliveryRefsAttached(deliveryRefs: string[], context?: JitReceiptEventContext): void;
4
21
  /** Remove only references the server says were valid or safe duplicates. */
5
- export declare function acknowledgeJitDeliveryRefs(directory: string, deliveryRefs: string[]): void;
22
+ export declare function acknowledgeJitDeliveryRefs(directory: string, deliveryRefs: string[], context?: JitReceiptEventContext): void;
23
+ /** Remove references the server can no longer accept instead of retrying forever. */
24
+ export declare function pruneExpiredJitDeliveryRefs(directory: string, deliveryRefs: string[], context?: JitReceiptEventContext): void;
25
+ /** Apply only receipt outcomes correlated to the exact refs on this request. */
26
+ export declare function applyJitDeliveryReceiptResponse(directory: string, attachedDeliveryRefs: string[], response: {
27
+ confirmedDeliveryRefs?: string[];
28
+ discardedDeliveryRefs?: string[];
29
+ }, context?: JitReceiptEventContext): void;
6
30
  //# sourceMappingURL=jitDeliveryAck.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jitDeliveryAck.d.ts","sourceRoot":"","sources":["../src/jitDeliveryAck.ts"],"names":[],"mappings":"AA6BA,kFAAkF;AAClF,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CA2BrF;AAED,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAuCtE;AAED,4EAA4E;AAC5E,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,IAAI,CAS1F"}
1
+ {"version":3,"file":"jitDeliveryAck.d.ts","sourceRoot":"","sources":["../src/jitDeliveryAck.ts"],"names":[],"mappings":"AAoBA,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,CAOpE;AAED,MAAM,MAAM,yBAAyB,GACjC,kBAAkB,GAClB,aAAa,GACb,qBAAqB,GACrB,kBAAkB,GAClB,gBAAgB,CAAC;AAErB,MAAM,WAAW,qBAAqB;IACpC,eAAe,EAAE,oBAAoB,CAAC;IACtC,KAAK,EAAE,yBAAyB,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,kBAAkB,GAAG,2BAA2B,CAAC;CAC3D;AAED,MAAM,WAAW,sBAAsB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;CAC/C;AAyCD,kFAAkF;AAClF,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CA8BT;AAED,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,MAAM,EAAE,CAyCV;AAED,wBAAgB,6BAA6B,CAC3C,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,IAAI,CAMN;AAED,4EAA4E;AAC5E,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,IAAI,CAUN;AAED,qFAAqF;AACrF,wBAAgB,2BAA2B,CACzC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,IAAI,CAUN;AAED,gFAAgF;AAChF,wBAAgB,+BAA+B,CAC7C,SAAS,EAAE,MAAM,EACjB,oBAAoB,EAAE,MAAM,EAAE,EAC9B,QAAQ,EAAE;IAAE,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,EAChF,OAAO,CAAC,EAAE,sBAAsB,GAC/B,IAAI,CAYN"}
@@ -1,8 +1,44 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import { chmodSync, closeSync, constants, existsSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync, } from 'node:fs';
2
3
  import { join } from 'node:path';
4
+ import { stderr } from 'node:process';
3
5
  const DELIVERY_REF_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
6
+ const HOOK_VERSION_RE = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
4
7
  const MAX_PENDING_REFS = 8;
5
8
  const DELIVERY_REF_RETENTION_MS = 240_000;
9
+ export function normalizeJitHookVersion(hookVersion) {
10
+ if (hookVersion === undefined || hookVersion === null)
11
+ return 'unknown';
12
+ return typeof hookVersion === 'string' &&
13
+ hookVersion.length <= 64 &&
14
+ HOOK_VERSION_RE.test(hookVersion)
15
+ ? hookVersion
16
+ : 'unrecognized';
17
+ }
18
+ function hash(value) {
19
+ return createHash('sha256').update(value).digest('hex');
20
+ }
21
+ function emitReceiptEvent(context, event, deliveryRef, reason) {
22
+ if (!context)
23
+ return;
24
+ const record = {
25
+ mnemonik_marker: 'jit_receipt_client',
26
+ event,
27
+ deliveryRefHash: hash(deliveryRef),
28
+ sessionFingerprint: hash(context.sessionId).slice(0, 16),
29
+ hookVersion: normalizeJitHookVersion(context.hookVersion),
30
+ ...(reason ? { reason } : {}),
31
+ };
32
+ try {
33
+ if (context.emit)
34
+ context.emit(record);
35
+ else
36
+ stderr.write(`${JSON.stringify(record)}\n`);
37
+ }
38
+ catch {
39
+ // Receipt instrumentation must never interfere with the host turn.
40
+ }
41
+ }
6
42
  function ensurePrivateDirectory(path) {
7
43
  if (!path)
8
44
  return false;
@@ -18,19 +54,23 @@ function ensurePrivateDirectory(path) {
18
54
  }
19
55
  }
20
56
  /** Persist only after the final host-visible payload contains this JIT result. */
21
- export function persistJitDeliveryRef(directory, deliveryRef) {
57
+ export function persistJitDeliveryRef(directory, deliveryRef, context) {
22
58
  if (!DELIVERY_REF_RE.test(deliveryRef) || !ensurePrivateDirectory(directory))
23
59
  return false;
24
60
  let fd = null;
25
61
  try {
26
62
  fd = openSync(join(directory, deliveryRef), constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | (constants.O_NOFOLLOW ?? 0), 0o600);
63
+ emitReceiptEvent(context, 'marker_persisted', deliveryRef);
27
64
  return true;
28
65
  }
29
66
  catch {
30
67
  // An existing marker is already the desired idempotent state.
31
68
  try {
32
69
  const stat = lstatSync(join(directory, deliveryRef));
33
- return stat.isFile() && !stat.isSymbolicLink() && (stat.mode & 0o077) === 0;
70
+ const persisted = stat.isFile() && !stat.isSymbolicLink() && (stat.mode & 0o077) === 0;
71
+ if (persisted)
72
+ emitReceiptEvent(context, 'marker_persisted', deliveryRef);
73
+ return persisted;
34
74
  }
35
75
  catch {
36
76
  return false;
@@ -47,7 +87,7 @@ export function persistJitDeliveryRef(directory, deliveryRef) {
47
87
  }
48
88
  }
49
89
  }
50
- export function readPendingJitDeliveryRefs(directory) {
90
+ export function readPendingJitDeliveryRefs(directory, context) {
51
91
  if (!directory)
52
92
  return [];
53
93
  try {
@@ -73,8 +113,10 @@ export function readPendingJitDeliveryRefs(directory) {
73
113
  catch {
74
114
  // Keep expired markers out of the send window even if cleanup races or fails.
75
115
  }
116
+ emitReceiptEvent(context, 'pruned_expired', deliveryRef, 'client_retention');
76
117
  continue;
77
118
  }
119
+ emitReceiptEvent(context, 'marker_read', deliveryRef);
78
120
  live.push({ deliveryRef, modifiedAt: marker.mtimeMs });
79
121
  }
80
122
  catch {
@@ -90,11 +132,19 @@ export function readPendingJitDeliveryRefs(directory) {
90
132
  return [];
91
133
  }
92
134
  }
135
+ export function reportJitDeliveryRefsAttached(deliveryRefs, context) {
136
+ for (const deliveryRef of new Set(deliveryRefs)) {
137
+ if (DELIVERY_REF_RE.test(deliveryRef)) {
138
+ emitReceiptEvent(context, 'attached_to_request', deliveryRef);
139
+ }
140
+ }
141
+ }
93
142
  /** Remove only references the server says were valid or safe duplicates. */
94
- export function acknowledgeJitDeliveryRefs(directory, deliveryRefs) {
143
+ export function acknowledgeJitDeliveryRefs(directory, deliveryRefs, context) {
95
144
  for (const deliveryRef of new Set(deliveryRefs)) {
96
145
  if (!DELIVERY_REF_RE.test(deliveryRef))
97
146
  continue;
147
+ emitReceiptEvent(context, 'marker_confirmed', deliveryRef);
98
148
  try {
99
149
  unlinkSync(join(directory, deliveryRef));
100
150
  }
@@ -103,4 +153,24 @@ export function acknowledgeJitDeliveryRefs(directory, deliveryRefs) {
103
153
  }
104
154
  }
105
155
  }
156
+ /** Remove references the server can no longer accept instead of retrying forever. */
157
+ export function pruneExpiredJitDeliveryRefs(directory, deliveryRefs, context) {
158
+ for (const deliveryRef of new Set(deliveryRefs)) {
159
+ if (!DELIVERY_REF_RE.test(deliveryRef))
160
+ continue;
161
+ try {
162
+ unlinkSync(join(directory, deliveryRef));
163
+ }
164
+ catch {
165
+ // Missing/locked marker: the ordinary client-retention sweep remains a backstop.
166
+ }
167
+ emitReceiptEvent(context, 'pruned_expired', deliveryRef, 'server_unknown_or_expired');
168
+ }
169
+ }
170
+ /** Apply only receipt outcomes correlated to the exact refs on this request. */
171
+ export function applyJitDeliveryReceiptResponse(directory, attachedDeliveryRefs, response, context) {
172
+ const attached = new Set(attachedDeliveryRefs);
173
+ acknowledgeJitDeliveryRefs(directory, (response.confirmedDeliveryRefs ?? []).filter((deliveryRef) => attached.has(deliveryRef)), context);
174
+ pruneExpiredJitDeliveryRefs(directory, (response.discardedDeliveryRefs ?? []).filter((deliveryRef) => attached.has(deliveryRef)), context);
175
+ }
106
176
  //# sourceMappingURL=jitDeliveryAck.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jitDeliveryAck.js","sourceRoot":"","sources":["../src/jitDeliveryAck.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jitDeliveryAck.js","sourceRoot":"","sources":["../src/jitDeliveryAck.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mnemonik/shared",
3
- "version": "7.72.0",
3
+ "version": "7.72.6",
4
4
  "description": "Shared constants and utilities for Mnemonik packages",
5
5
  "repository": {
6
6
  "type": "git",
package/src/index.ts CHANGED
@@ -61,7 +61,14 @@ export {
61
61
  export {
62
62
  persistJitDeliveryRef,
63
63
  readPendingJitDeliveryRefs,
64
+ reportJitDeliveryRefsAttached,
64
65
  acknowledgeJitDeliveryRefs,
66
+ pruneExpiredJitDeliveryRefs,
67
+ applyJitDeliveryReceiptResponse,
68
+ normalizeJitHookVersion,
69
+ type JitReceiptClientEvent,
70
+ type JitReceiptClientEventName,
71
+ type JitReceiptEventContext,
65
72
  } from './jitDeliveryAck.js';
66
73
  export * from './settingsIo.js';
67
74
  export * from './claudeProxySettings.js';
@@ -1,3 +1,4 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import {
2
3
  chmodSync,
3
4
  closeSync,
@@ -10,11 +11,72 @@ import {
10
11
  unlinkSync,
11
12
  } from 'node:fs';
12
13
  import { join } from 'node:path';
14
+ import { stderr } from 'node:process';
13
15
 
14
16
  const DELIVERY_REF_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
17
+ const HOOK_VERSION_RE = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$/;
15
18
  const MAX_PENDING_REFS = 8;
16
19
  const DELIVERY_REF_RETENTION_MS = 240_000;
17
20
 
21
+ export function normalizeJitHookVersion(hookVersion: unknown): string {
22
+ if (hookVersion === undefined || hookVersion === null) return 'unknown';
23
+ return typeof hookVersion === 'string' &&
24
+ hookVersion.length <= 64 &&
25
+ HOOK_VERSION_RE.test(hookVersion)
26
+ ? hookVersion
27
+ : 'unrecognized';
28
+ }
29
+
30
+ export type JitReceiptClientEventName =
31
+ | 'marker_persisted'
32
+ | 'marker_read'
33
+ | 'attached_to_request'
34
+ | 'marker_confirmed'
35
+ | 'pruned_expired';
36
+
37
+ export interface JitReceiptClientEvent {
38
+ mnemonik_marker: 'jit_receipt_client';
39
+ event: JitReceiptClientEventName;
40
+ deliveryRefHash: string;
41
+ sessionFingerprint: string;
42
+ hookVersion: string;
43
+ reason?: 'client_retention' | 'server_unknown_or_expired';
44
+ }
45
+
46
+ export interface JitReceiptEventContext {
47
+ sessionId: string;
48
+ hookVersion: string;
49
+ /** Test seam; production writes one JSON event per line to hook stderr. */
50
+ emit?: (event: JitReceiptClientEvent) => void;
51
+ }
52
+
53
+ function hash(value: string): string {
54
+ return createHash('sha256').update(value).digest('hex');
55
+ }
56
+
57
+ function emitReceiptEvent(
58
+ context: JitReceiptEventContext | undefined,
59
+ event: JitReceiptClientEventName,
60
+ deliveryRef: string,
61
+ reason?: JitReceiptClientEvent['reason']
62
+ ): void {
63
+ if (!context) return;
64
+ const record: JitReceiptClientEvent = {
65
+ mnemonik_marker: 'jit_receipt_client',
66
+ event,
67
+ deliveryRefHash: hash(deliveryRef),
68
+ sessionFingerprint: hash(context.sessionId).slice(0, 16),
69
+ hookVersion: normalizeJitHookVersion(context.hookVersion),
70
+ ...(reason ? { reason } : {}),
71
+ };
72
+ try {
73
+ if (context.emit) context.emit(record);
74
+ else stderr.write(`${JSON.stringify(record)}\n`);
75
+ } catch {
76
+ // Receipt instrumentation must never interfere with the host turn.
77
+ }
78
+ }
79
+
18
80
  function ensurePrivateDirectory(path: string): boolean {
19
81
  if (!path) return false;
20
82
  try {
@@ -28,7 +90,11 @@ function ensurePrivateDirectory(path: string): boolean {
28
90
  }
29
91
 
30
92
  /** Persist only after the final host-visible payload contains this JIT result. */
31
- export function persistJitDeliveryRef(directory: string, deliveryRef: string): boolean {
93
+ export function persistJitDeliveryRef(
94
+ directory: string,
95
+ deliveryRef: string,
96
+ context?: JitReceiptEventContext
97
+ ): boolean {
32
98
  if (!DELIVERY_REF_RE.test(deliveryRef) || !ensurePrivateDirectory(directory)) return false;
33
99
  let fd: number | null = null;
34
100
  try {
@@ -37,12 +103,15 @@ export function persistJitDeliveryRef(directory: string, deliveryRef: string): b
37
103
  constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | (constants.O_NOFOLLOW ?? 0),
38
104
  0o600
39
105
  );
106
+ emitReceiptEvent(context, 'marker_persisted', deliveryRef);
40
107
  return true;
41
108
  } catch {
42
109
  // An existing marker is already the desired idempotent state.
43
110
  try {
44
111
  const stat = lstatSync(join(directory, deliveryRef));
45
- return stat.isFile() && !stat.isSymbolicLink() && (stat.mode & 0o077) === 0;
112
+ const persisted = stat.isFile() && !stat.isSymbolicLink() && (stat.mode & 0o077) === 0;
113
+ if (persisted) emitReceiptEvent(context, 'marker_persisted', deliveryRef);
114
+ return persisted;
46
115
  } catch {
47
116
  return false;
48
117
  }
@@ -57,7 +126,10 @@ export function persistJitDeliveryRef(directory: string, deliveryRef: string): b
57
126
  }
58
127
  }
59
128
 
60
- export function readPendingJitDeliveryRefs(directory: string): string[] {
129
+ export function readPendingJitDeliveryRefs(
130
+ directory: string,
131
+ context?: JitReceiptEventContext
132
+ ): string[] {
61
133
  if (!directory) return [];
62
134
  try {
63
135
  if (!existsSync(directory)) return [];
@@ -78,8 +150,10 @@ export function readPendingJitDeliveryRefs(directory: string): string[] {
78
150
  } catch {
79
151
  // Keep expired markers out of the send window even if cleanup races or fails.
80
152
  }
153
+ emitReceiptEvent(context, 'pruned_expired', deliveryRef, 'client_retention');
81
154
  continue;
82
155
  }
156
+ emitReceiptEvent(context, 'marker_read', deliveryRef);
83
157
  live.push({ deliveryRef, modifiedAt: marker.mtimeMs });
84
158
  } catch {
85
159
  // A marker removed concurrently is already in the desired state.
@@ -98,10 +172,26 @@ export function readPendingJitDeliveryRefs(directory: string): string[] {
98
172
  }
99
173
  }
100
174
 
175
+ export function reportJitDeliveryRefsAttached(
176
+ deliveryRefs: string[],
177
+ context?: JitReceiptEventContext
178
+ ): void {
179
+ for (const deliveryRef of new Set(deliveryRefs)) {
180
+ if (DELIVERY_REF_RE.test(deliveryRef)) {
181
+ emitReceiptEvent(context, 'attached_to_request', deliveryRef);
182
+ }
183
+ }
184
+ }
185
+
101
186
  /** Remove only references the server says were valid or safe duplicates. */
102
- export function acknowledgeJitDeliveryRefs(directory: string, deliveryRefs: string[]): void {
187
+ export function acknowledgeJitDeliveryRefs(
188
+ directory: string,
189
+ deliveryRefs: string[],
190
+ context?: JitReceiptEventContext
191
+ ): void {
103
192
  for (const deliveryRef of new Set(deliveryRefs)) {
104
193
  if (!DELIVERY_REF_RE.test(deliveryRef)) continue;
194
+ emitReceiptEvent(context, 'marker_confirmed', deliveryRef);
105
195
  try {
106
196
  unlinkSync(join(directory, deliveryRef));
107
197
  } catch {
@@ -109,3 +199,40 @@ export function acknowledgeJitDeliveryRefs(directory: string, deliveryRefs: stri
109
199
  }
110
200
  }
111
201
  }
202
+
203
+ /** Remove references the server can no longer accept instead of retrying forever. */
204
+ export function pruneExpiredJitDeliveryRefs(
205
+ directory: string,
206
+ deliveryRefs: string[],
207
+ context?: JitReceiptEventContext
208
+ ): void {
209
+ for (const deliveryRef of new Set(deliveryRefs)) {
210
+ if (!DELIVERY_REF_RE.test(deliveryRef)) continue;
211
+ try {
212
+ unlinkSync(join(directory, deliveryRef));
213
+ } catch {
214
+ // Missing/locked marker: the ordinary client-retention sweep remains a backstop.
215
+ }
216
+ emitReceiptEvent(context, 'pruned_expired', deliveryRef, 'server_unknown_or_expired');
217
+ }
218
+ }
219
+
220
+ /** Apply only receipt outcomes correlated to the exact refs on this request. */
221
+ export function applyJitDeliveryReceiptResponse(
222
+ directory: string,
223
+ attachedDeliveryRefs: string[],
224
+ response: { confirmedDeliveryRefs?: string[]; discardedDeliveryRefs?: string[] },
225
+ context?: JitReceiptEventContext
226
+ ): void {
227
+ const attached = new Set(attachedDeliveryRefs);
228
+ acknowledgeJitDeliveryRefs(
229
+ directory,
230
+ (response.confirmedDeliveryRefs ?? []).filter((deliveryRef) => attached.has(deliveryRef)),
231
+ context
232
+ );
233
+ pruneExpiredJitDeliveryRefs(
234
+ directory,
235
+ (response.discardedDeliveryRefs ?? []).filter((deliveryRef) => attached.has(deliveryRef)),
236
+ context
237
+ );
238
+ }