@mrciphersmith/keryx 0.3.19 → 0.3.20

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 (3) hide show
  1. package/dist/cli.js +73 -17
  2. package/dist/core.js +72 -16
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -9091,8 +9091,24 @@ function lastLineOf(before) {
9091
9091
  `);
9092
9092
  return newline < 0 ? before : before.slice(newline + 1);
9093
9093
  }
9094
+ function isPlainCasedWord(letters) {
9095
+ return /^[a-z]+$/.test(letters) || /^[A-Z]+$/.test(letters) || /^[A-Z][a-z]*$/.test(letters);
9096
+ }
9094
9097
  function isSingleTransitionTag(segment) {
9095
- return /^[A-Za-z]+[0-9]+$/.test(segment) || /^[0-9]+[A-Za-z]+$/.test(segment);
9098
+ const letterThenDigit = /^([A-Za-z]+)([0-9]+)$/.exec(segment);
9099
+ if (letterThenDigit !== null) {
9100
+ const letters = letterThenDigit[1];
9101
+ return letters.length <= TAG_MAX_LETTER_RUN && isPlainCasedWord(letters);
9102
+ }
9103
+ const digitThenLetter = /^([0-9]+)([A-Za-z]+)$/.exec(segment);
9104
+ if (digitThenLetter !== null) {
9105
+ const letters = digitThenLetter[2];
9106
+ return letters.length <= TAG_MAX_LETTER_RUN && isPlainCasedWord(letters);
9107
+ }
9108
+ return false;
9109
+ }
9110
+ function isSlugHexTail(segment) {
9111
+ return SLUG_HEX_TAIL_RE.test(segment);
9096
9112
  }
9097
9113
  function isWordSlug(value) {
9098
9114
  const segments = value.split(/[-_]/);
@@ -9100,15 +9116,25 @@ function isWordSlug(value) {
9100
9116
  return false;
9101
9117
  }
9102
9118
  let words = 0;
9103
- for (const segment of segments) {
9104
- const isAlpha = /^[A-Za-z]+$/.test(segment);
9119
+ for (let i = 0;i < segments.length; i += 1) {
9120
+ const segment = segments[i];
9105
9121
  const isDigits = /^[0-9]+$/.test(segment);
9106
- if (!isAlpha && !isDigits && !isSingleTransitionTag(segment)) {
9107
- return false;
9122
+ if (isDigits) {
9123
+ continue;
9108
9124
  }
9109
- if (isAlpha && segment.length >= 3) {
9110
- words += 1;
9125
+ if (isPlainCasedWord(segment)) {
9126
+ if (segment.length >= 3) {
9127
+ words += 1;
9128
+ }
9129
+ continue;
9130
+ }
9131
+ if (isSingleTransitionTag(segment)) {
9132
+ continue;
9133
+ }
9134
+ if (i === segments.length - 1 && isSlugHexTail(segment)) {
9135
+ continue;
9111
9136
  }
9137
+ return false;
9112
9138
  }
9113
9139
  return words >= 1;
9114
9140
  }
@@ -9252,6 +9278,29 @@ function secretShapedCandidatesIn(text) {
9252
9278
  function looksSecretShapedIn(text) {
9253
9279
  return secretShapedCandidatesIn(text).length > 0;
9254
9280
  }
9281
+ function labelledPieceQualifies(piece) {
9282
+ const base = bareShapeQualifies(piece);
9283
+ if (base.qualifies) {
9284
+ return { entropy: base.entropy };
9285
+ }
9286
+ if (isAllowShapedValue(piece)) {
9287
+ return { entropy: base.entropy };
9288
+ }
9289
+ return null;
9290
+ }
9291
+ function firstQualifyingSlashPiece(head) {
9292
+ let offset = 0;
9293
+ for (const piece of head.split("/")) {
9294
+ if (piece.length > 0) {
9295
+ const found = labelledPieceQualifies(piece);
9296
+ if (found !== null) {
9297
+ return { offset, length: piece.length, entropy: found.entropy };
9298
+ }
9299
+ }
9300
+ offset += piece.length + 1;
9301
+ }
9302
+ return null;
9303
+ }
9255
9304
  function detectEntropy(content) {
9256
9305
  const matches = [];
9257
9306
  const urlSpans = findUrlSpans(content);
@@ -9291,25 +9340,31 @@ function detectEntropy(content) {
9291
9340
  if (matches.some((existing) => start < existing.end && end > existing.start)) {
9292
9341
  continue;
9293
9342
  }
9294
- const head = TOKEN_HEAD.exec(value)?.[0] ?? value;
9295
- const { qualifies, entropy } = bareShapeQualifies(head);
9296
- if (!qualifies) {
9343
+ const before = lastLineOf(content.slice(Math.max(0, start - LABEL_WINDOW), start));
9344
+ if (!ADJACENT_LABEL.test(before)) {
9297
9345
  continue;
9298
9346
  }
9299
- const before = lastLineOf(content.slice(Math.max(0, start - LABEL_WINDOW), start));
9300
- if (!SENSITIVE_LABEL.test(before)) {
9347
+ const head = TOKEN_HEAD.exec(value)?.[0] ?? value;
9348
+ if (head.includes("/")) {
9349
+ const piece = firstQualifyingSlashPiece(head);
9350
+ if (piece === null) {
9351
+ continue;
9352
+ }
9353
+ const pieceStart = start + piece.offset;
9354
+ const pieceEnd = pieceStart + piece.length;
9355
+ matches.push(buildMatch(pieceStart, pieceEnd, content.slice(pieceStart, pieceEnd), piece.entropy));
9301
9356
  continue;
9302
9357
  }
9303
- if (isAllowShapedValue(head) && !ADJACENT_LABEL.test(before)) {
9358
+ const found = labelledPieceQualifies(head);
9359
+ if (found === null) {
9304
9360
  continue;
9305
9361
  }
9306
- matches.push(buildMatch(start, end, value, entropy));
9362
+ matches.push(buildMatch(start, end, value, found.entropy));
9307
9363
  }
9308
9364
  return matches.sort((a, b) => a.start - b.start);
9309
9365
  }
9310
- var SENSITIVE_LABEL_WORDS = "key|secret|token|password|passwd|api|credential|auth|bearer", caseless = (words) => words.replace(/[a-z]/g, (ch) => `[${ch}${ch.toUpperCase()}]`), SENSITIVE_LABEL, ADJACENT_LABEL, LABEL_ASSIGNMENT_RE, TOKEN, TOKEN_HEAD, LABEL_WINDOW = 40, HEX_BLOB, FULL_GIT_SHA_RE, UUID_RE, INTEGRITY_RE, URL_SPAN_RE, URL_TRAILING_PUNCTUATION_RE, URL_COMPONENT_MIN_LENGTH = 20;
9366
+ var SENSITIVE_LABEL_WORDS = "key|secret|token|password|passwd|api|credential|auth|bearer", caseless = (words) => words.replace(/[a-z]/g, (ch) => `[${ch}${ch.toUpperCase()}]`), ADJACENT_LABEL, LABEL_ASSIGNMENT_RE, TOKEN, TOKEN_HEAD, LABEL_WINDOW = 40, HEX_BLOB, FULL_GIT_SHA_RE, UUID_RE, INTEGRITY_RE, TAG_MAX_LETTER_RUN = 8, SLUG_HEX_TAIL_RE, URL_SPAN_RE, URL_TRAILING_PUNCTUATION_RE, URL_COMPONENT_MIN_LENGTH = 20;
9311
9367
  var init_entropy = __esm(() => {
9312
- SENSITIVE_LABEL = new RegExp(`(?:^|[^A-Za-z0-9])(${caseless(SENSITIVE_LABEL_WORDS)})(?:$|[^A-Za-z0-9]|(?=[A-Z]))`);
9313
9368
  ADJACENT_LABEL = new RegExp(`(?:^|[^A-Za-z0-9])(?:${caseless(SENSITIVE_LABEL_WORDS)})[A-Za-z0-9_-]*["']?\\s*[:=]?\\s*["']?$`);
9314
9369
  LABEL_ASSIGNMENT_RE = new RegExp(`(?:^|[^A-Za-z0-9])(?:${SENSITIVE_LABEL_WORDS})[A-Za-z0-9_-]*"?\\s*=\\s*"?([A-Za-z0-9+/_=-]{6,})`, "gi");
9315
9370
  TOKEN = /[A-Za-z0-9+/=_-]{20,}(?:\.[A-Za-z0-9+/=_-]{6,})*/g;
@@ -9318,6 +9373,7 @@ var init_entropy = __esm(() => {
9318
9373
  FULL_GIT_SHA_RE = /^[0-9a-f]{40}$/i;
9319
9374
  UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9320
9375
  INTEGRITY_RE = /^(?:sha256|sha512)-[A-Za-z0-9+/]+=*$/;
9376
+ SLUG_HEX_TAIL_RE = /^[0-9a-f]{10,16}$/i;
9321
9377
  URL_SPAN_RE = /\bhttps?:\/\/[^\s<>"'\\]+/g;
9322
9378
  URL_TRAILING_PUNCTUATION_RE = /[.,;:!?)\]}]$/;
9323
9379
  });
@@ -18037,7 +18093,7 @@ var package_default;
18037
18093
  var init_package = __esm(() => {
18038
18094
  package_default = {
18039
18095
  name: "@mrciphersmith/keryx",
18040
- version: "0.3.19",
18096
+ version: "0.3.20",
18041
18097
  description: "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
18042
18098
  private: false,
18043
18099
  publishConfig: {
package/dist/core.js CHANGED
@@ -4040,8 +4040,24 @@ function lastLineOf(before) {
4040
4040
  `);
4041
4041
  return newline < 0 ? before : before.slice(newline + 1);
4042
4042
  }
4043
+ function isPlainCasedWord(letters) {
4044
+ return /^[a-z]+$/.test(letters) || /^[A-Z]+$/.test(letters) || /^[A-Z][a-z]*$/.test(letters);
4045
+ }
4043
4046
  function isSingleTransitionTag(segment) {
4044
- return /^[A-Za-z]+[0-9]+$/.test(segment) || /^[0-9]+[A-Za-z]+$/.test(segment);
4047
+ const letterThenDigit = /^([A-Za-z]+)([0-9]+)$/.exec(segment);
4048
+ if (letterThenDigit !== null) {
4049
+ const letters = letterThenDigit[1];
4050
+ return letters.length <= TAG_MAX_LETTER_RUN && isPlainCasedWord(letters);
4051
+ }
4052
+ const digitThenLetter = /^([0-9]+)([A-Za-z]+)$/.exec(segment);
4053
+ if (digitThenLetter !== null) {
4054
+ const letters = digitThenLetter[2];
4055
+ return letters.length <= TAG_MAX_LETTER_RUN && isPlainCasedWord(letters);
4056
+ }
4057
+ return false;
4058
+ }
4059
+ function isSlugHexTail(segment) {
4060
+ return SLUG_HEX_TAIL_RE.test(segment);
4045
4061
  }
4046
4062
  function isWordSlug(value) {
4047
4063
  const segments = value.split(/[-_]/);
@@ -4049,15 +4065,25 @@ function isWordSlug(value) {
4049
4065
  return false;
4050
4066
  }
4051
4067
  let words = 0;
4052
- for (const segment of segments) {
4053
- const isAlpha = /^[A-Za-z]+$/.test(segment);
4068
+ for (let i = 0;i < segments.length; i += 1) {
4069
+ const segment = segments[i];
4054
4070
  const isDigits = /^[0-9]+$/.test(segment);
4055
- if (!isAlpha && !isDigits && !isSingleTransitionTag(segment)) {
4056
- return false;
4071
+ if (isDigits) {
4072
+ continue;
4057
4073
  }
4058
- if (isAlpha && segment.length >= 3) {
4059
- words += 1;
4074
+ if (isPlainCasedWord(segment)) {
4075
+ if (segment.length >= 3) {
4076
+ words += 1;
4077
+ }
4078
+ continue;
4079
+ }
4080
+ if (isSingleTransitionTag(segment)) {
4081
+ continue;
4060
4082
  }
4083
+ if (i === segments.length - 1 && isSlugHexTail(segment)) {
4084
+ continue;
4085
+ }
4086
+ return false;
4061
4087
  }
4062
4088
  return words >= 1;
4063
4089
  }
@@ -4201,6 +4227,29 @@ function secretShapedCandidatesIn(text) {
4201
4227
  function looksSecretShapedIn(text) {
4202
4228
  return secretShapedCandidatesIn(text).length > 0;
4203
4229
  }
4230
+ function labelledPieceQualifies(piece) {
4231
+ const base = bareShapeQualifies(piece);
4232
+ if (base.qualifies) {
4233
+ return { entropy: base.entropy };
4234
+ }
4235
+ if (isAllowShapedValue(piece)) {
4236
+ return { entropy: base.entropy };
4237
+ }
4238
+ return null;
4239
+ }
4240
+ function firstQualifyingSlashPiece(head) {
4241
+ let offset = 0;
4242
+ for (const piece of head.split("/")) {
4243
+ if (piece.length > 0) {
4244
+ const found = labelledPieceQualifies(piece);
4245
+ if (found !== null) {
4246
+ return { offset, length: piece.length, entropy: found.entropy };
4247
+ }
4248
+ }
4249
+ offset += piece.length + 1;
4250
+ }
4251
+ return null;
4252
+ }
4204
4253
  function detectEntropy(content) {
4205
4254
  const matches = [];
4206
4255
  const urlSpans = findUrlSpans(content);
@@ -4240,25 +4289,31 @@ function detectEntropy(content) {
4240
4289
  if (matches.some((existing) => start < existing.end && end > existing.start)) {
4241
4290
  continue;
4242
4291
  }
4243
- const head = TOKEN_HEAD.exec(value)?.[0] ?? value;
4244
- const { qualifies, entropy } = bareShapeQualifies(head);
4245
- if (!qualifies) {
4292
+ const before = lastLineOf(content.slice(Math.max(0, start - LABEL_WINDOW), start));
4293
+ if (!ADJACENT_LABEL.test(before)) {
4246
4294
  continue;
4247
4295
  }
4248
- const before = lastLineOf(content.slice(Math.max(0, start - LABEL_WINDOW), start));
4249
- if (!SENSITIVE_LABEL.test(before)) {
4296
+ const head = TOKEN_HEAD.exec(value)?.[0] ?? value;
4297
+ if (head.includes("/")) {
4298
+ const piece = firstQualifyingSlashPiece(head);
4299
+ if (piece === null) {
4300
+ continue;
4301
+ }
4302
+ const pieceStart = start + piece.offset;
4303
+ const pieceEnd = pieceStart + piece.length;
4304
+ matches.push(buildMatch(pieceStart, pieceEnd, content.slice(pieceStart, pieceEnd), piece.entropy));
4250
4305
  continue;
4251
4306
  }
4252
- if (isAllowShapedValue(head) && !ADJACENT_LABEL.test(before)) {
4307
+ const found = labelledPieceQualifies(head);
4308
+ if (found === null) {
4253
4309
  continue;
4254
4310
  }
4255
- matches.push(buildMatch(start, end, value, entropy));
4311
+ matches.push(buildMatch(start, end, value, found.entropy));
4256
4312
  }
4257
4313
  return matches.sort((a, b) => a.start - b.start);
4258
4314
  }
4259
- var SENSITIVE_LABEL_WORDS = "key|secret|token|password|passwd|api|credential|auth|bearer", caseless = (words) => words.replace(/[a-z]/g, (ch) => `[${ch}${ch.toUpperCase()}]`), SENSITIVE_LABEL, ADJACENT_LABEL, LABEL_ASSIGNMENT_RE, TOKEN, TOKEN_HEAD, LABEL_WINDOW = 40, HEX_BLOB, FULL_GIT_SHA_RE, UUID_RE, INTEGRITY_RE, URL_SPAN_RE, URL_TRAILING_PUNCTUATION_RE, URL_COMPONENT_MIN_LENGTH = 20;
4315
+ var SENSITIVE_LABEL_WORDS = "key|secret|token|password|passwd|api|credential|auth|bearer", caseless = (words) => words.replace(/[a-z]/g, (ch) => `[${ch}${ch.toUpperCase()}]`), ADJACENT_LABEL, LABEL_ASSIGNMENT_RE, TOKEN, TOKEN_HEAD, LABEL_WINDOW = 40, HEX_BLOB, FULL_GIT_SHA_RE, UUID_RE, INTEGRITY_RE, TAG_MAX_LETTER_RUN = 8, SLUG_HEX_TAIL_RE, URL_SPAN_RE, URL_TRAILING_PUNCTUATION_RE, URL_COMPONENT_MIN_LENGTH = 20;
4260
4316
  var init_entropy = __esm(() => {
4261
- SENSITIVE_LABEL = new RegExp(`(?:^|[^A-Za-z0-9])(${caseless(SENSITIVE_LABEL_WORDS)})(?:$|[^A-Za-z0-9]|(?=[A-Z]))`);
4262
4317
  ADJACENT_LABEL = new RegExp(`(?:^|[^A-Za-z0-9])(?:${caseless(SENSITIVE_LABEL_WORDS)})[A-Za-z0-9_-]*["']?\\s*[:=]?\\s*["']?$`);
4263
4318
  LABEL_ASSIGNMENT_RE = new RegExp(`(?:^|[^A-Za-z0-9])(?:${SENSITIVE_LABEL_WORDS})[A-Za-z0-9_-]*"?\\s*=\\s*"?([A-Za-z0-9+/_=-]{6,})`, "gi");
4264
4319
  TOKEN = /[A-Za-z0-9+/=_-]{20,}(?:\.[A-Za-z0-9+/=_-]{6,})*/g;
@@ -4267,6 +4322,7 @@ var init_entropy = __esm(() => {
4267
4322
  FULL_GIT_SHA_RE = /^[0-9a-f]{40}$/i;
4268
4323
  UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
4269
4324
  INTEGRITY_RE = /^(?:sha256|sha512)-[A-Za-z0-9+/]+=*$/;
4325
+ SLUG_HEX_TAIL_RE = /^[0-9a-f]{10,16}$/i;
4270
4326
  URL_SPAN_RE = /\bhttps?:\/\/[^\s<>"'\\]+/g;
4271
4327
  URL_TRAILING_PUNCTUATION_RE = /[.,;:!?)\]}]$/;
4272
4328
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrciphersmith/keryx",
3
- "version": "0.3.19",
3
+ "version": "0.3.20",
4
4
  "description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
5
5
  "private": false,
6
6
  "publishConfig": {