@mnemonik/shared 7.68.0 → 7.72.0

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,6 +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
15
  export * from './settingsIo.js';
15
16
  export * from './claudeProxySettings.js';
16
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,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,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC"}
package/dist/index.js CHANGED
@@ -11,6 +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
15
  export * from './settingsIo.js';
15
16
  export * from './claudeProxySettings.js';
16
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,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,0BAA0B,GAC3B,MAAM,qBAAqB,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC"}
@@ -0,0 +1,6 @@
1
+ /** 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[];
4
+ /** Remove only references the server says were valid or safe duplicates. */
5
+ export declare function acknowledgeJitDeliveryRefs(directory: string, deliveryRefs: string[]): void;
6
+ //# sourceMappingURL=jitDeliveryAck.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,106 @@
1
+ import { chmodSync, closeSync, constants, existsSync, lstatSync, mkdirSync, openSync, readdirSync, unlinkSync, } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ 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;
4
+ const MAX_PENDING_REFS = 8;
5
+ const DELIVERY_REF_RETENTION_MS = 240_000;
6
+ function ensurePrivateDirectory(path) {
7
+ if (!path)
8
+ return false;
9
+ try {
10
+ if (existsSync(path) && lstatSync(path).isSymbolicLink())
11
+ return false;
12
+ mkdirSync(path, { recursive: true, mode: 0o700 });
13
+ chmodSync(path, 0o700);
14
+ return lstatSync(path).isDirectory() && !lstatSync(path).isSymbolicLink();
15
+ }
16
+ catch {
17
+ return false;
18
+ }
19
+ }
20
+ /** Persist only after the final host-visible payload contains this JIT result. */
21
+ export function persistJitDeliveryRef(directory, deliveryRef) {
22
+ if (!DELIVERY_REF_RE.test(deliveryRef) || !ensurePrivateDirectory(directory))
23
+ return false;
24
+ let fd = null;
25
+ try {
26
+ fd = openSync(join(directory, deliveryRef), constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | (constants.O_NOFOLLOW ?? 0), 0o600);
27
+ return true;
28
+ }
29
+ catch {
30
+ // An existing marker is already the desired idempotent state.
31
+ try {
32
+ const stat = lstatSync(join(directory, deliveryRef));
33
+ return stat.isFile() && !stat.isSymbolicLink() && (stat.mode & 0o077) === 0;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ }
39
+ finally {
40
+ if (fd !== null) {
41
+ try {
42
+ closeSync(fd);
43
+ }
44
+ catch {
45
+ // Receipt persistence is fail-open for the host turn.
46
+ }
47
+ }
48
+ }
49
+ }
50
+ export function readPendingJitDeliveryRefs(directory) {
51
+ if (!directory)
52
+ return [];
53
+ try {
54
+ if (!existsSync(directory))
55
+ return [];
56
+ const stat = lstatSync(directory);
57
+ if (!stat.isDirectory() || stat.isSymbolicLink())
58
+ return [];
59
+ const now = Date.now();
60
+ const live = [];
61
+ for (const deliveryRef of readdirSync(directory)) {
62
+ if (!DELIVERY_REF_RE.test(deliveryRef))
63
+ continue;
64
+ const markerPath = join(directory, deliveryRef);
65
+ try {
66
+ const marker = lstatSync(markerPath);
67
+ if (!marker.isFile() || marker.isSymbolicLink())
68
+ continue;
69
+ if (now - marker.mtimeMs >= DELIVERY_REF_RETENTION_MS) {
70
+ try {
71
+ unlinkSync(markerPath);
72
+ }
73
+ catch {
74
+ // Keep expired markers out of the send window even if cleanup races or fails.
75
+ }
76
+ continue;
77
+ }
78
+ live.push({ deliveryRef, modifiedAt: marker.mtimeMs });
79
+ }
80
+ catch {
81
+ // A marker removed concurrently is already in the desired state.
82
+ }
83
+ }
84
+ return live
85
+ .sort((left, right) => right.modifiedAt - left.modifiedAt || right.deliveryRef.localeCompare(left.deliveryRef))
86
+ .slice(0, MAX_PENDING_REFS)
87
+ .map(({ deliveryRef }) => deliveryRef);
88
+ }
89
+ catch {
90
+ return [];
91
+ }
92
+ }
93
+ /** Remove only references the server says were valid or safe duplicates. */
94
+ export function acknowledgeJitDeliveryRefs(directory, deliveryRefs) {
95
+ for (const deliveryRef of new Set(deliveryRefs)) {
96
+ if (!DELIVERY_REF_RE.test(deliveryRef))
97
+ continue;
98
+ try {
99
+ unlinkSync(join(directory, deliveryRef));
100
+ }
101
+ catch {
102
+ // Missing/locked marker: retrying is harmless and bounded by server TTL.
103
+ }
104
+ }
105
+ }
106
+ //# sourceMappingURL=jitDeliveryAck.js.map
@@ -0,0 +1 @@
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.68.0",
3
+ "version": "7.72.0",
4
4
  "description": "Shared constants and utilities for Mnemonik packages",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,6 +34,10 @@
34
34
  "./git-edit-detector": {
35
35
  "import": "./dist/gitEditDetector.js",
36
36
  "types": "./dist/gitEditDetector.d.ts"
37
+ },
38
+ "./jit-delivery-ack": {
39
+ "import": "./dist/jitDeliveryAck.js",
40
+ "types": "./dist/jitDeliveryAck.d.ts"
37
41
  }
38
42
  },
39
43
  "scripts": {
package/src/index.ts CHANGED
@@ -58,5 +58,10 @@ export {
58
58
  MCP_PRECHECK_TIMEOUT_MS,
59
59
  withHookTimeout,
60
60
  } from './hookTimeouts.js';
61
+ export {
62
+ persistJitDeliveryRef,
63
+ readPendingJitDeliveryRefs,
64
+ acknowledgeJitDeliveryRefs,
65
+ } from './jitDeliveryAck.js';
61
66
  export * from './settingsIo.js';
62
67
  export * from './claudeProxySettings.js';
@@ -0,0 +1,111 @@
1
+ import {
2
+ chmodSync,
3
+ closeSync,
4
+ constants,
5
+ existsSync,
6
+ lstatSync,
7
+ mkdirSync,
8
+ openSync,
9
+ readdirSync,
10
+ unlinkSync,
11
+ } from 'node:fs';
12
+ import { join } from 'node:path';
13
+
14
+ 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;
15
+ const MAX_PENDING_REFS = 8;
16
+ const DELIVERY_REF_RETENTION_MS = 240_000;
17
+
18
+ function ensurePrivateDirectory(path: string): boolean {
19
+ if (!path) return false;
20
+ try {
21
+ if (existsSync(path) && lstatSync(path).isSymbolicLink()) return false;
22
+ mkdirSync(path, { recursive: true, mode: 0o700 });
23
+ chmodSync(path, 0o700);
24
+ return lstatSync(path).isDirectory() && !lstatSync(path).isSymbolicLink();
25
+ } catch {
26
+ return false;
27
+ }
28
+ }
29
+
30
+ /** Persist only after the final host-visible payload contains this JIT result. */
31
+ export function persistJitDeliveryRef(directory: string, deliveryRef: string): boolean {
32
+ if (!DELIVERY_REF_RE.test(deliveryRef) || !ensurePrivateDirectory(directory)) return false;
33
+ let fd: number | null = null;
34
+ try {
35
+ fd = openSync(
36
+ join(directory, deliveryRef),
37
+ constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | (constants.O_NOFOLLOW ?? 0),
38
+ 0o600
39
+ );
40
+ return true;
41
+ } catch {
42
+ // An existing marker is already the desired idempotent state.
43
+ try {
44
+ const stat = lstatSync(join(directory, deliveryRef));
45
+ return stat.isFile() && !stat.isSymbolicLink() && (stat.mode & 0o077) === 0;
46
+ } catch {
47
+ return false;
48
+ }
49
+ } finally {
50
+ if (fd !== null) {
51
+ try {
52
+ closeSync(fd);
53
+ } catch {
54
+ // Receipt persistence is fail-open for the host turn.
55
+ }
56
+ }
57
+ }
58
+ }
59
+
60
+ export function readPendingJitDeliveryRefs(directory: string): string[] {
61
+ if (!directory) return [];
62
+ try {
63
+ if (!existsSync(directory)) return [];
64
+ const stat = lstatSync(directory);
65
+ if (!stat.isDirectory() || stat.isSymbolicLink()) return [];
66
+ const now = Date.now();
67
+ const live: Array<{ deliveryRef: string; modifiedAt: number }> = [];
68
+
69
+ for (const deliveryRef of readdirSync(directory)) {
70
+ if (!DELIVERY_REF_RE.test(deliveryRef)) continue;
71
+ const markerPath = join(directory, deliveryRef);
72
+ try {
73
+ const marker = lstatSync(markerPath);
74
+ if (!marker.isFile() || marker.isSymbolicLink()) continue;
75
+ if (now - marker.mtimeMs >= DELIVERY_REF_RETENTION_MS) {
76
+ try {
77
+ unlinkSync(markerPath);
78
+ } catch {
79
+ // Keep expired markers out of the send window even if cleanup races or fails.
80
+ }
81
+ continue;
82
+ }
83
+ live.push({ deliveryRef, modifiedAt: marker.mtimeMs });
84
+ } catch {
85
+ // A marker removed concurrently is already in the desired state.
86
+ }
87
+ }
88
+
89
+ return live
90
+ .sort(
91
+ (left, right) =>
92
+ right.modifiedAt - left.modifiedAt || right.deliveryRef.localeCompare(left.deliveryRef)
93
+ )
94
+ .slice(0, MAX_PENDING_REFS)
95
+ .map(({ deliveryRef }) => deliveryRef);
96
+ } catch {
97
+ return [];
98
+ }
99
+ }
100
+
101
+ /** Remove only references the server says were valid or safe duplicates. */
102
+ export function acknowledgeJitDeliveryRefs(directory: string, deliveryRefs: string[]): void {
103
+ for (const deliveryRef of new Set(deliveryRefs)) {
104
+ if (!DELIVERY_REF_RE.test(deliveryRef)) continue;
105
+ try {
106
+ unlinkSync(join(directory, deliveryRef));
107
+ } catch {
108
+ // Missing/locked marker: retrying is harmless and bounded by server TTL.
109
+ }
110
+ }
111
+ }