engineering-memory 1.11.0 → 1.11.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "engineering-memory",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "Installs the Engineering Memory skill and its local MCP bridge. Sign in after installing; your organization and project are resolved from your account.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -1019,16 +1019,26 @@ export class BridgeService {
1019
1019
  if (!run || typeof run.id !== 'string')
1020
1020
  throw refuse('The inspection response has no run identity.', 'memory.sync_status');
1021
1021
  if (run.state === 'inventory' || run.state === 'planning') {
1022
- for (let offset = 0; offset < snapshot.files.length; offset += 1000) {
1023
- const page = cleanJson({
1022
+ for (let offset = 0; offset < snapshot.files.length;) {
1023
+ const page = {
1024
1024
  projectId: input.projectId,
1025
1025
  runId: run.id,
1026
- files: snapshot.files.slice(offset, offset + 1000),
1027
- });
1028
- assertSafeToPersist(page);
1026
+ files: [],
1027
+ };
1028
+ let bytes = Buffer.byteLength(JSON.stringify(page));
1029
+ while (offset < snapshot.files.length && page.files.length < 1000) {
1030
+ const file = snapshot.files[offset];
1031
+ const addedBytes = Buffer.byteLength(JSON.stringify(file)) + (page.files.length ? 1 : 0);
1032
+ if (page.files.length && bytes + addedBytes > 64 * 1024)
1033
+ break;
1034
+ page.files.push(file);
1035
+ bytes += addedBytes;
1036
+ offset += 1;
1037
+ }
1038
+ assertSafeToPersist(cleanJson(page));
1029
1039
  await this.dependencies.client.request('/memory/sync/inventory', {
1030
1040
  method: 'POST',
1031
- body: page,
1041
+ body: cleanJson(page),
1032
1042
  });
1033
1043
  }
1034
1044
  await this.dependencies.client.request('/memory/sync/inventory', {
@@ -6,6 +6,22 @@ import { sha256, stableStringify } from '../utilities/hash.js';
6
6
  const sensitiveKeyPattern = /(authorization|password|passcode|secret|token|cookie|email|phone|mobile|customer|account|user.?id|user.?name)/i;
7
7
  const emailPattern = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i;
8
8
  const phonePattern = /\+\d[\d ()-]{7,}\d/;
9
+ const repositoryPathFields = new Set([
10
+ 'path',
11
+ 'paths',
12
+ 'originalPath',
13
+ 'changedPaths',
14
+ 'pathPatterns',
15
+ 'evidencePaths',
16
+ ]);
17
+ const iosAssetScalePathPattern = /^(?:[\p{L}\p{N}_. -]+\/)*[\p{L}\p{N}_. -]+\.xcassets\/[\p{L}\p{N}_. -]+\.(?:appiconset|imageset)\/[\p{L}\p{N}_. -]+@[123]x\.(?:png|jpe?g)$/iu;
18
+ function emailScanValue(value, key) {
19
+ if (!repositoryPathFields.has(key) ||
20
+ !iosAssetScalePathPattern.test(value) ||
21
+ value.split('/').some((part) => part === '.' || part === '..'))
22
+ return value;
23
+ return value.replace(/@[123]x(?=\.(?:png|jpe?g)$)/i, '');
24
+ }
9
25
  const bearerPattern = /\bbearer\s+[a-z0-9._~-]+/i;
10
26
  const jwtPattern = /\beyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\b/;
11
27
  const privateKeyPattern = /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/;
@@ -155,7 +171,7 @@ export function assertSafeToPersist(value, key = '') {
155
171
  throw new Error(`Sensitive field cannot be persisted: ${key}`);
156
172
  }
157
173
  if (typeof value === 'string') {
158
- if (emailPattern.test(value) ||
174
+ if (emailPattern.test(emailScanValue(value, key)) ||
159
175
  phonePattern.test(value) ||
160
176
  bearerPattern.test(value) ||
161
177
  jwtPattern.test(value) ||
@@ -199,13 +215,13 @@ export function redactForCache(value) {
199
215
  return null;
200
216
  }
201
217
  }
202
- function redactValue(value) {
218
+ function redactValue(value, key = '') {
203
219
  if (typeof value === 'string') {
204
- assertSafeToPersist(value);
220
+ assertSafeToPersist(value, key);
205
221
  return value;
206
222
  }
207
223
  if (Array.isArray(value)) {
208
- return value.map((entry) => redactValue(entry));
224
+ return value.map((entry) => redactValue(entry, key));
209
225
  }
210
226
  if (value !== null && typeof value === 'object') {
211
227
  const result = {};
@@ -213,7 +229,7 @@ function redactValue(value) {
213
229
  if (sensitiveKeyPattern.test(key)) {
214
230
  continue;
215
231
  }
216
- result[key] = redactValue(entry);
232
+ result[key] = redactValue(entry, key);
217
233
  }
218
234
  return result;
219
235
  }