@packmind/cli 0.18.0 → 0.19.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.
Files changed (2) hide show
  1. package/main.cjs +103 -23
  2. package/package.json +1 -1
package/main.cjs CHANGED
@@ -3852,7 +3852,7 @@ var require_package = __commonJS({
3852
3852
  "apps/cli/package.json"(exports2, module2) {
3853
3853
  module2.exports = {
3854
3854
  name: "@packmind/cli",
3855
- version: "0.18.0",
3855
+ version: "0.19.0",
3856
3856
  description: "A command-line interface for Packmind linting and code quality checks",
3857
3857
  private: false,
3858
3858
  bin: {
@@ -11437,6 +11437,70 @@ function normalizeScopeValue(rawValue) {
11437
11437
  return rawValue.replace(/(?:^["'])|(?:["']$)/g, "");
11438
11438
  }
11439
11439
 
11440
+ // apps/cli/src/application/utils/ruleSimilarity.ts
11441
+ var DEFAULT_SIMILARITY_THRESHOLD = 0.5;
11442
+ function matchUpdatedRules(deletedRules, addedRules, threshold = DEFAULT_SIMILARITY_THRESHOLD) {
11443
+ const updates = [];
11444
+ const usedDeleted = /* @__PURE__ */ new Set();
11445
+ const usedAdded = /* @__PURE__ */ new Set();
11446
+ const pairs = [];
11447
+ for (let d = 0; d < deletedRules.length; d++) {
11448
+ for (let a = 0; a < addedRules.length; a++) {
11449
+ const score = combinedSimilarity(deletedRules[d], addedRules[a]);
11450
+ if (score >= threshold) {
11451
+ pairs.push({ deletedIdx: d, addedIdx: a, score });
11452
+ }
11453
+ }
11454
+ }
11455
+ pairs.sort((a, b) => b.score - a.score);
11456
+ for (const pair of pairs) {
11457
+ if (usedDeleted.has(pair.deletedIdx) || usedAdded.has(pair.addedIdx))
11458
+ continue;
11459
+ usedDeleted.add(pair.deletedIdx);
11460
+ usedAdded.add(pair.addedIdx);
11461
+ updates.push({
11462
+ oldValue: deletedRules[pair.deletedIdx],
11463
+ newValue: addedRules[pair.addedIdx]
11464
+ });
11465
+ }
11466
+ const remainingDeleted = deletedRules.filter((_, i) => !usedDeleted.has(i));
11467
+ const remainingAdded = addedRules.filter((_, i) => !usedAdded.has(i));
11468
+ return { updates, remainingDeleted, remainingAdded };
11469
+ }
11470
+ function jaccardSimilarity(a, b) {
11471
+ const setA = new Set(a.toLowerCase().split(/\s+/).filter(Boolean));
11472
+ const setB = new Set(b.toLowerCase().split(/\s+/).filter(Boolean));
11473
+ if (setA.size === 0 && setB.size === 0) return 1;
11474
+ const intersection = new Set([...setA].filter((word) => setB.has(word)));
11475
+ const union = /* @__PURE__ */ new Set([...setA, ...setB]);
11476
+ return intersection.size / union.size;
11477
+ }
11478
+ function combinedSimilarity(a, b) {
11479
+ return Math.max(levenshteinSimilarity(a, b), jaccardSimilarity(a, b));
11480
+ }
11481
+ function levenshteinSimilarity(a, b) {
11482
+ const maxLen = Math.max(a.length, b.length);
11483
+ if (maxLen === 0) return 1;
11484
+ const matrix = [];
11485
+ for (let i = 0; i <= a.length; i++) {
11486
+ matrix[i] = [i];
11487
+ }
11488
+ for (let j = 0; j <= b.length; j++) {
11489
+ matrix[0][j] = j;
11490
+ }
11491
+ for (let i = 1; i <= a.length; i++) {
11492
+ for (let j = 1; j <= b.length; j++) {
11493
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
11494
+ matrix[i][j] = Math.min(
11495
+ matrix[i - 1][j] + 1,
11496
+ matrix[i][j - 1] + 1,
11497
+ matrix[i - 1][j - 1] + cost
11498
+ );
11499
+ }
11500
+ }
11501
+ return 1 - matrix[a.length][b.length] / maxLen;
11502
+ }
11503
+
11440
11504
  // apps/cli/src/application/useCases/diffStrategies/StandardDiffStrategy.ts
11441
11505
  var StandardDiffStrategy = class {
11442
11506
  supports(file) {
@@ -11515,29 +11579,45 @@ var StandardDiffStrategy = class {
11515
11579
  }
11516
11580
  const serverRules = new Set(serverParsed.rules);
11517
11581
  const localRules = new Set(localParsed.rules);
11518
- for (const rule of serverRules) {
11519
- if (!localRules.has(rule)) {
11520
- const ruleId = createRuleId("unresolved");
11521
- diffs.push({
11522
- ...diffBase,
11523
- type: "deleteRule" /* deleteRule */,
11524
- payload: {
11525
- targetId: ruleId,
11526
- item: { id: ruleId, content: rule }
11527
- }
11528
- });
11529
- }
11582
+ const deletedRules = [...serverRules].filter(
11583
+ (rule) => !localRules.has(rule)
11584
+ );
11585
+ const addedRules = [...localRules].filter((rule) => !serverRules.has(rule));
11586
+ const { updates, remainingDeleted, remainingAdded } = matchUpdatedRules(
11587
+ deletedRules,
11588
+ addedRules
11589
+ );
11590
+ for (const update of updates) {
11591
+ const ruleId = createRuleId("unresolved");
11592
+ diffs.push({
11593
+ ...diffBase,
11594
+ type: "updateRule" /* updateRule */,
11595
+ payload: {
11596
+ targetId: ruleId,
11597
+ oldValue: update.oldValue,
11598
+ newValue: update.newValue
11599
+ }
11600
+ });
11530
11601
  }
11531
- for (const rule of localRules) {
11532
- if (!serverRules.has(rule)) {
11533
- diffs.push({
11534
- ...diffBase,
11535
- type: "addRule" /* addRule */,
11536
- payload: {
11537
- item: { content: rule }
11538
- }
11539
- });
11540
- }
11602
+ for (const rule of remainingDeleted) {
11603
+ const ruleId = createRuleId("unresolved");
11604
+ diffs.push({
11605
+ ...diffBase,
11606
+ type: "deleteRule" /* deleteRule */,
11607
+ payload: {
11608
+ targetId: ruleId,
11609
+ item: { id: ruleId, content: rule }
11610
+ }
11611
+ });
11612
+ }
11613
+ for (const rule of remainingAdded) {
11614
+ diffs.push({
11615
+ ...diffBase,
11616
+ type: "addRule" /* addRule */,
11617
+ payload: {
11618
+ item: { content: rule }
11619
+ }
11620
+ });
11541
11621
  }
11542
11622
  return diffs;
11543
11623
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@packmind/cli",
3
- "version": "0.18.0",
3
+ "version": "0.19.0",
4
4
  "description": "A command-line interface for Packmind linting and code quality checks",
5
5
  "private": false,
6
6
  "bin": {