teamcopilot 0.1.1 → 0.1.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.
@@ -1,7 +1,5 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.maskValue = maskValue;
4
- exports.isLikelySensitiveKey = isLikelySensitiveKey;
5
3
  exports.sanitizeStringContent = sanitizeStringContent;
6
4
  exports.sanitizeForClient = sanitizeForClient;
7
5
  const SENSITIVE_KEY_PATTERN = /(token|secret|password|passwd|api[_-]?key|auth|credential)/i;
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createResourceFileManager = createResourceFileManager;
7
7
  const crypto_1 = __importDefault(require("crypto"));
8
+ const diff_1 = require("diff");
8
9
  const fs_1 = __importDefault(require("fs"));
9
10
  const path_1 = __importDefault(require("path"));
10
11
  const redact_1 = require("./redact");
@@ -137,19 +138,6 @@ function createResourceFileManager(options) {
137
138
  };
138
139
  }
139
140
  }
140
- function findClosingQuoteIndex(input, quote) {
141
- for (let i = 1; i < input.length; i += 1) {
142
- const ch = input[i];
143
- if (ch === "\\") {
144
- i += 1;
145
- continue;
146
- }
147
- if (ch === quote) {
148
- return i;
149
- }
150
- }
151
- return -1;
152
- }
153
141
  function toFileNode(parentRelativePath, name, absolutePath) {
154
142
  const lstat = fs_1.default.lstatSync(absolutePath);
155
143
  const isDir = lstat.isDirectory();
@@ -199,131 +187,52 @@ function createResourceFileManager(options) {
199
187
  }
200
188
  return false;
201
189
  }
202
- function parseEnvAssignmentLine(line) {
203
- const match = line.match(/^(\s*(?:export\s+)?)([A-Za-z_][A-Za-z0-9_-]*)(\s*=\s*)(.*)$/);
204
- if (!match) {
205
- return { kind: "other" };
206
- }
207
- const [, prefix, key, separator, remainder] = match;
208
- if (remainder.startsWith('"')) {
209
- const closeIdx = findClosingQuoteIndex(remainder, '"');
210
- if (closeIdx === -1) {
211
- return { kind: "other" };
212
- }
213
- return {
214
- kind: "assignment",
215
- prefix,
216
- key,
217
- separator,
218
- quote: '"',
219
- value: remainder.slice(1, closeIdx),
220
- suffix: remainder.slice(closeIdx + 1),
221
- };
222
- }
223
- if (remainder.startsWith("'")) {
224
- const closeIdx = findClosingQuoteIndex(remainder, "'");
225
- if (closeIdx === -1) {
226
- return { kind: "other" };
190
+ function buildSanitizedBoundaryMap(raw, sanitized) {
191
+ const boundaries = Array(sanitized.length + 1).fill(raw.length);
192
+ let rawIndex = 0;
193
+ let sanitizedIndex = 0;
194
+ boundaries[0] = 0;
195
+ for (const change of (0, diff_1.diffChars)(raw, sanitized)) {
196
+ const segmentLength = change.value.length;
197
+ if (change.added) {
198
+ for (let offset = 0; offset < segmentLength; offset += 1) {
199
+ sanitizedIndex += 1;
200
+ boundaries[sanitizedIndex] = rawIndex;
201
+ }
202
+ continue;
227
203
  }
228
- return {
229
- kind: "assignment",
230
- prefix,
231
- key,
232
- separator,
233
- quote: "'",
234
- value: remainder.slice(1, closeIdx),
235
- suffix: remainder.slice(closeIdx + 1),
236
- };
237
- }
238
- const commentStart = remainder.search(/\s#/);
239
- if (commentStart === -1) {
240
- return {
241
- kind: "assignment",
242
- prefix,
243
- key,
244
- separator,
245
- quote: null,
246
- value: remainder.trim(),
247
- suffix: "",
248
- };
249
- }
250
- const valuePart = remainder.slice(0, commentStart).trim();
251
- const suffix = remainder.slice(commentStart);
252
- return {
253
- kind: "assignment",
254
- prefix,
255
- key,
256
- separator,
257
- quote: null,
258
- value: valuePart,
259
- suffix,
260
- };
261
- }
262
- function serializeEnvAssignment(parsed) {
263
- if (parsed.quote === '"') {
264
- return `${parsed.prefix}${parsed.key}${parsed.separator}"${parsed.value}"${parsed.suffix}`;
265
- }
266
- if (parsed.quote === "'") {
267
- return `${parsed.prefix}${parsed.key}${parsed.separator}'${parsed.value}'${parsed.suffix}`;
268
- }
269
- return `${parsed.prefix}${parsed.key}${parsed.separator}${parsed.value}${parsed.suffix}`;
270
- }
271
- function splitLinesPreserveNewline(input) {
272
- const parts = [];
273
- const regex = /([^\r\n]*)(\r\n|\n|\r|$)/g;
274
- let match;
275
- while ((match = regex.exec(input)) !== null) {
276
- const line = match[1];
277
- const newline = match[2];
278
- if (line === "" && newline === "" && match.index === input.length) {
279
- break;
204
+ if (change.removed) {
205
+ rawIndex += segmentLength;
206
+ continue;
280
207
  }
281
- parts.push({ line, newline });
282
- if (newline === "") {
283
- break;
208
+ for (let offset = 0; offset < segmentLength; offset += 1) {
209
+ rawIndex += 1;
210
+ sanitizedIndex += 1;
211
+ boundaries[sanitizedIndex] = rawIndex;
284
212
  }
285
213
  }
286
- return parts;
214
+ return boundaries;
287
215
  }
288
- function mergeDotenvMaskedValues(currentRaw, editedContent) {
289
- const currentLines = splitLinesPreserveNewline(currentRaw);
290
- const editedLines = splitLinesPreserveNewline(editedContent);
291
- const currentQueuesByKey = new Map();
292
- for (const item of currentLines) {
293
- const parsed = parseEnvAssignmentLine(item.line);
294
- if (parsed.kind !== "assignment")
295
- continue;
296
- const arr = currentQueuesByKey.get(parsed.key) ?? [];
297
- arr.push(parsed);
298
- currentQueuesByKey.set(parsed.key, arr);
216
+ function mergeRedactedEditorContent(currentRaw, editedContent) {
217
+ const sanitizedCurrent = (0, redact_1.sanitizeStringContent)(currentRaw);
218
+ if (editedContent === sanitizedCurrent) {
219
+ return currentRaw;
299
220
  }
221
+ const boundaries = buildSanitizedBoundaryMap(currentRaw, sanitizedCurrent);
300
222
  const output = [];
301
- for (const item of editedLines) {
302
- const parsedEdited = parseEnvAssignmentLine(item.line);
303
- if (parsedEdited.kind !== "assignment" || !(0, redact_1.isLikelySensitiveKey)(parsedEdited.key)) {
304
- output.push(item.line + item.newline);
305
- continue;
306
- }
307
- const queue = currentQueuesByKey.get(parsedEdited.key);
308
- const currentParsed = queue?.shift();
309
- if (!currentParsed) {
310
- output.push(item.line + item.newline);
223
+ let sanitizedIndex = 0;
224
+ for (const change of (0, diff_1.diffChars)(sanitizedCurrent, editedContent)) {
225
+ if (change.added) {
226
+ output.push(change.value);
311
227
  continue;
312
228
  }
313
- if (parsedEdited.quote !== currentParsed.quote) {
314
- output.push(item.line + item.newline);
315
- continue;
229
+ const nextSanitizedIndex = sanitizedIndex + change.value.length;
230
+ const rawStart = boundaries[sanitizedIndex] ?? currentRaw.length;
231
+ const rawEnd = boundaries[nextSanitizedIndex] ?? currentRaw.length;
232
+ if (!change.removed) {
233
+ output.push(currentRaw.slice(rawStart, rawEnd));
316
234
  }
317
- const maskedCurrent = (0, redact_1.maskValue)(currentParsed.value);
318
- if (parsedEdited.value !== maskedCurrent) {
319
- output.push(item.line + item.newline);
320
- continue;
321
- }
322
- const mergedLine = serializeEnvAssignment({
323
- ...parsedEdited,
324
- value: currentParsed.value,
325
- });
326
- output.push(mergedLine + item.newline);
235
+ sanitizedIndex = nextSanitizedIndex;
327
236
  }
328
237
  return output.join("");
329
238
  }
@@ -435,9 +344,10 @@ function createResourceFileManager(options) {
435
344
  };
436
345
  }
437
346
  const name = path_1.default.basename(relativePath);
438
- const isDotenv = name === ".env";
439
- const nextContent = isDotenv
440
- ? mergeDotenvMaskedValues(currentBytes.toString("utf-8"), request.content)
347
+ const currentRawContent = currentBytes.toString("utf-8");
348
+ const wasServedRedacted = name === ".env" || resourceLabel === "skill";
349
+ const nextContent = wasServedRedacted
350
+ ? mergeRedactedEditorContent(currentRawContent, request.content)
441
351
  : request.content;
442
352
  fs_1.default.writeFileSync(absolutePath, nextContent, "utf-8");
443
353
  const nextBytes = fs_1.default.readFileSync(absolutePath);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teamcopilot",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "A shared AI Agent for Teams",
5
5
  "homepage": "https://teamcopilot.ai",
6
6
  "repository": {
@@ -65,6 +65,7 @@
65
65
  "cookie-parser": "^1.4.7",
66
66
  "cors": "^2.8.5",
67
67
  "cron": "^4.4.0",
68
+ "diff": "^8.0.4",
68
69
  "dotenv": "^16.4.7",
69
70
  "express": "^4.21.2",
70
71
  "ignore": "^7.0.5",