@tasksai/install 0.1.31 → 0.1.33

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": "@tasksai/install",
3
- "version": "0.1.31",
3
+ "version": "0.1.33",
4
4
  "description": "Shared TasksAI MCP installer CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -58,13 +58,20 @@ DEFAULT_THRESHOLDS = {"high": 90, "medium": 45}
58
58
  DEFAULT_RESULT_COUNT = 3
59
59
  MAXIMUM_RESULT_COUNT = 10
60
60
  DEFAULT_RESULT_COUNTS = {"realtor": 5}
61
+ MINIMUM_RESULT_COUNTS = {"realtor": 3}
61
62
  REALTOR_ACTION_WORDS = {
62
63
  "assemble", "build", "create", "develop", "document", "draft",
63
64
  "generate", "make", "prepare", "produce", "write", "writing",
64
65
  }
66
+ REALTOR_DISCOVERY_WORDS = {
67
+ "browse", "display", "find", "get", "give", "look", "pull",
68
+ "search", "searching", "see", "show", "up", "view",
69
+ }
65
70
  DEFAULT_TOKEN_ALIASES = {
66
71
  "realtor": {
67
72
  "assemble": "create",
73
+ "bill": "commission",
74
+ "billing": "commission",
68
75
  "build": "create",
69
76
  "develop": "create",
70
77
  "draft": "create",
@@ -72,6 +79,8 @@ DEFAULT_TOKEN_ALIASES = {
72
79
  "generate": "create",
73
80
  "home": "property",
74
81
  "house": "property",
82
+ "invoice": "commission",
83
+ "invoicing": "commission",
75
84
  "listed": "listing",
76
85
  "listings": "listing",
77
86
  "list": "listing",
@@ -343,6 +352,7 @@ def _resolve_config(product_id: str, config: Mapping[str, object] | None) -> tup
343
352
  }
344
353
  if _canonical_product_id(product_id) == "realtor":
345
354
  stop_words.difference_update(REALTOR_ACTION_WORDS)
355
+ stop_words.update(REALTOR_DISCOVERY_WORDS)
346
356
  context_default = DEFAULT_CONTEXT_WORDS.get(_canonical_product_id(product_id), set())
347
357
  supplied_context_words = source.get("context_words", context_default)
348
358
  if not isinstance(supplied_context_words, Sequence) or isinstance(supplied_context_words, (str, bytes)):
@@ -366,13 +376,20 @@ def _resolve_config(product_id: str, config: Mapping[str, object] | None) -> tup
366
376
  product_default_count = DEFAULT_RESULT_COUNTS.get(
367
377
  _canonical_product_id(product_id), DEFAULT_RESULT_COUNT
368
378
  )
379
+ product_minimum_count = MINIMUM_RESULT_COUNTS.get(
380
+ _canonical_product_id(product_id), 0
381
+ )
382
+ minimum_count = source.get("minimum_result_count", product_minimum_count)
369
383
  default_count = source.get("default_result_count", product_default_count)
370
384
  maximum_count = source.get("maximum_result_count", MAXIMUM_RESULT_COUNT)
371
385
  if not isinstance(default_count, int) or isinstance(default_count, bool) or default_count < 1:
372
386
  default_count = product_default_count
387
+ if not isinstance(minimum_count, int) or isinstance(minimum_count, bool) or minimum_count < 0:
388
+ minimum_count = product_minimum_count
373
389
  if not isinstance(maximum_count, int) or isinstance(maximum_count, bool) or maximum_count < 1:
374
390
  maximum_count = MAXIMUM_RESULT_COUNT
375
391
  maximum_count = min(maximum_count, MAXIMUM_RESULT_COUNT)
392
+ minimum_count = min(minimum_count, maximum_count)
376
393
  default_count = min(default_count, maximum_count)
377
394
 
378
395
  configured_abbreviations = source.get("abbreviations", {})
@@ -383,6 +400,7 @@ def _resolve_config(product_id: str, config: Mapping[str, object] | None) -> tup
383
400
  "stop_words": stop_words,
384
401
  "context_words": context_words,
385
402
  "thresholds": thresholds,
403
+ "minimum_result_count": minimum_count,
386
404
  "default_result_count": default_count,
387
405
  "maximum_result_count": maximum_count,
388
406
  "abbreviations": configured_abbreviations,
@@ -629,7 +647,11 @@ def match_skills(
629
647
  requested_count = policy["default_result_count"] if result_count is None else result_count
630
648
  if not isinstance(requested_count, int) or isinstance(requested_count, bool):
631
649
  requested_count = policy["default_result_count"]
632
- requested_count = max(1, min(requested_count, policy["maximum_result_count"]))
650
+ requested_count = max(
651
+ 1,
652
+ policy["minimum_result_count"],
653
+ min(requested_count, policy["maximum_result_count"]),
654
+ )
633
655
 
634
656
  if len(scoped_skills) != len(skills):
635
657
  diagnostics.append("product_mismatches_filtered")
@@ -640,12 +662,24 @@ def match_skills(
640
662
  if skill.get("id")
641
663
  ]
642
664
  ranked.sort(key=_sort_key)
665
+ diversified = _diversify(ranked)
643
666
  qualified = [
644
667
  result
645
- for result in _diversify(ranked)
668
+ for result in diversified
646
669
  if result["confidence"] in {"high", "medium"}
647
670
  ]
648
671
  selected = qualified[:requested_count]
672
+ minimum_count = min(policy["minimum_result_count"], requested_count)
673
+ if len(selected) < minimum_count:
674
+ selected_ids = {result["skill_id"] for result in selected}
675
+ for result in diversified:
676
+ if result["skill_id"] in selected_ids:
677
+ continue
678
+ selected.append(result)
679
+ selected_ids.add(result["skill_id"])
680
+ if len(selected) >= minimum_count:
681
+ break
682
+ diagnostics.append("minimum_results_filled")
649
683
 
650
684
  public_results = []
651
685
  for result in selected: