blun-king-cli 9.1.597 → 9.1.600

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 (106) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +17 -1
  3. package/agent-spine-plugin/CHANGELOG.md +1 -1
  4. package/agent-spine-plugin/docs/host-integration.md +1 -15
  5. package/agent-spine-plugin/docs/preflight-recall.md +1 -1
  6. package/agent-spine-plugin/scripts/check-install.js +1 -6
  7. package/agent-spine-plugin/scripts/hermetic-process.js +8 -0
  8. package/agent-spine-plugin/scripts/release-check.js +2 -3
  9. package/agent-spine-plugin/scripts/run-tests-hermetic.js +8 -11
  10. package/agent-spine-plugin/src/hook.js +40 -40
  11. package/agent-spine-plugin/src/lib/briefing.js +6 -3
  12. package/agent-spine-plugin/src/lib/hook-context.js +63 -64
  13. package/agent-spine-plugin/src/lib/hook-output.js +115 -94
  14. package/agent-spine-plugin/src/lib/hook-timeline.js +20 -11
  15. package/agent-spine-plugin/src/lib/host-instruction-budget.js +8 -14
  16. package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +0 -7
  17. package/agent-spine-plugin/src/lib/pre-answer-timeline-recall.js +104 -0
  18. package/agent-spine-plugin/src/lib/session-timeline-codex.js +0 -4
  19. package/agent-spine-plugin/src/lib/session-timeline-enrollment-source.js +0 -3
  20. package/agent-spine-plugin/src/lib/session-timeline-enrollment-storage.js +0 -4
  21. package/agent-spine-plugin/src/lib/session-timeline-enrollment-transport.js +0 -2
  22. package/agent-spine-plugin/src/lib/session-timeline-enrollment.js +0 -22
  23. package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +0 -4
  24. package/agent-spine-plugin/src/lib/session-timeline-prior.js +42 -50
  25. package/agent-spine-plugin/src/lib/session-timeline-provider.js +0 -3
  26. package/agent-spine-plugin/src/lib/session-timeline-query.js +0 -1
  27. package/agent-spine-plugin/src/lib/session-timeline-sid-acl.js +0 -4
  28. package/agent-spine-plugin/src/lib/session-timeline-source.js +0 -3
  29. package/agent-spine-plugin/src/lib/session-timeline-transport.js +0 -8
  30. package/agent-spine-plugin/src/lib/session-timeline-windows-acl.js +0 -3
  31. package/agent-spine-plugin/src/lib/session-timeline.js +370 -408
  32. package/agent-spine-plugin/src/lib/source-roots.js +26 -16
  33. package/agent-spine-plugin/src/lib/timeline-user-feedback.js +0 -1
  34. package/bin/core-bootstrap.js +18 -10
  35. package/bin/launcher-mode.js +5 -0
  36. package/bin/launcher-runtime.js +27 -0
  37. package/bin/verify-bundled-agent-sources.cjs +28 -2
  38. package/blun.mjs +798 -143
  39. package/bundled-agent-sources.json +192 -155
  40. package/package.json +1 -1
  41. package/standard-skills/translate-native/README.md +1334 -1
  42. package/standard-skills/translate-native/SKILL.md +1 -1
  43. package/standard-skills/translate-native/VERSION +1 -1
  44. package/standard-skills/translate-native/docs/PREMORTEM.md +901 -0
  45. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +208 -41
  46. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1319 -77
  47. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +66 -11
  48. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +19 -1
  49. package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +24 -6
  50. package/standard-skills/translate-native/integrations/commercial_localization_profile.py +23 -0
  51. package/standard-skills/translate-native/integrations/website_localization.py +234 -10
  52. package/standard-skills/translate-native/integrations/website_localization_benchmark.py +39 -3
  53. package/standard-skills/translate-native/integrations/website_localization_cms.py +512 -10
  54. package/standard-skills/translate-native/integrations/website_localization_cms_client.py +116 -0
  55. package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +101 -11
  56. package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +12 -1
  57. package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +186 -24
  58. package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +64 -1
  59. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +528 -5
  60. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth.py +918 -0
  61. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth_runtime.py +609 -0
  62. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_client.py +885 -0
  63. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_http.py +1244 -0
  64. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +220 -0
  65. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_sidecar_adapter.py +331 -0
  66. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_capabilities_http.py +444 -0
  67. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_client.py +673 -0
  68. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch.py +1317 -0
  69. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_client.py +826 -0
  70. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_http.py +1152 -0
  71. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_openapi.py +896 -0
  72. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_runtime.py +621 -0
  73. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_http.py +1180 -0
  74. package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_runtime.py +1479 -0
  75. package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +133 -17
  76. package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +319 -4
  77. package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +72 -2
  78. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +13 -0
  79. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +56 -13
  80. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_openapi.py +335 -0
  81. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +66 -1
  82. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +73 -7
  83. package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +93 -9
  84. package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +221 -11
  85. package/standard-skills/translate-native/integrations/website_localization_health.py +6 -0
  86. package/standard-skills/translate-native/integrations/website_localization_http_provider.py +1 -1
  87. package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +350 -0
  88. package/standard-skills/translate-native/integrations/website_localization_queue.py +126 -56
  89. package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +166 -13
  90. package/standard-skills/translate-native/integrations/website_localization_release.py +423 -17
  91. package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +168 -13
  92. package/standard-skills/translate-native/integrations/website_localization_runner.py +10 -0
  93. package/standard-skills/translate-native/integrations/website_localization_worker.py +213 -9
  94. package/standard-skills/translate-native/provenance.json +2 -2
  95. package/standard-skills/translate-native/references/commercial-localization.md +96 -17
  96. package/standard-skills/translate-native/scripts/blun_language_guard.py +3 -1
  97. package/standard-skills/translate-native/scripts/check_commercial_review.py +69 -9
  98. package/standard-skills/translate-native/scripts/commercial_localization_profile.py +829 -31
  99. package/standard-tools/language-guard/VERSION +1 -1
  100. package/standard-tools/language-guard/blun_language_guard.py +3 -1
  101. package/standard-tools/language-guard/check_commercial_review.py +69 -9
  102. package/standard-tools/language-guard/commercial_localization_profile.py +829 -31
  103. package/standard-tools/language-guard/provenance.json +2 -2
  104. package/standard-tools/manifest.json +1 -1
  105. package/worker-host.mjs +215 -82
  106. package/agent-spine-plugin/scripts/check-install-king.js +0 -37
@@ -4,20 +4,23 @@
4
4
  from __future__ import annotations
5
5
 
6
6
  import hashlib
7
+ import importlib.util
7
8
  import json
8
9
  import re
9
10
  import socket
11
+ import sys
10
12
  import unicodedata
11
13
  import urllib.error
12
14
  import urllib.parse
13
15
  import urllib.request
14
16
  from dataclasses import dataclass
17
+ from pathlib import Path
15
18
  from typing import Any, Callable, Mapping, Protocol
16
19
 
17
20
 
18
21
  REQUEST_SCHEMA = "blun.localization-receipt-verification-http-request.v1"
19
22
  RESPONSE_SCHEMA = "blun.localization-receipt-verification-http-response.v1"
20
- RECEIPT_BINDING_SCHEMA = "blun.localization-quality-receipt-binding.v2"
23
+ RECEIPT_BINDING_SCHEMA = "blun.localization-quality-receipt-binding.v9"
21
24
  MAX_ENDPOINT_LENGTH = 2048
22
25
  MAX_HEADER_VALUE_LENGTH = 4096
23
26
  MAX_TEXT_BYTES = 2_000_000
@@ -28,19 +31,23 @@ HEADER_NAME = re.compile(r"^[!#$%&'*+.^_`|~0-9A-Za-z-]{1,128}$")
28
31
  SHA256 = re.compile(r"^[0-9a-f]{64}$")
29
32
  TOKEN = re.compile(r"^[A-Za-z0-9_.:-]{1,256}$")
30
33
  ERROR_CODE = re.compile(r"^[a-z][a-z0-9_.-]{0,127}$")
31
- COMMERCIAL_REVIEW_SUMMARY_SCHEMA = "translate-native.commercial-review-summary.v1"
34
+ EVIDENCE_REQUEST_ID = re.compile(r"^blun-l10n-evidence-[0-9a-f]{64}$")
35
+ COMMERCIAL_REVIEW_SUMMARY_SCHEMA = "translate-native.commercial-review-summary.v6"
32
36
  COMMERCIAL_DIMENSIONS = (
33
37
  "amount_currency", "discount_basis", "qualifiers", "tax_status",
34
38
  "billing_interval", "commitment", "renewal", "cancellation",
35
39
  "conditions", "offer_assignment",
36
40
  )
37
41
  BINDING_FIELDS = {
38
- "schema", "review_kind", "job_id", "result_sha256", "source_text",
42
+ "schema", "review_kind", "evidence_request_id", "evidence_revision",
43
+ "job_id", "result_sha256", "source_text",
39
44
  "target_text", "source_sha256", "target_sha256", "source_locale",
40
45
  "target_locale", "content_type", "glossary_version", "policy_version",
41
46
  "primary_provider", "review_provider", "software_version",
42
47
  "review_confidence", "quality_profile", "commercial_profile",
43
- "commercial_review",
48
+ "commercial_review", "commercial_review_routing",
49
+ "commercial_review_routing_contract_sha256",
50
+ "commercial_review_resolution_contract_sha256",
44
51
  "human_review_required", "independent_review_required",
45
52
  }
46
53
  RESERVED_HEADERS = {
@@ -51,6 +58,40 @@ RESERVED_HEADERS = {
51
58
  }
52
59
 
53
60
 
61
+ def _commercial_offer_scope(
62
+ value: Any,
63
+ dimensions: list[str],
64
+ offer_count: Any,
65
+ ) -> bool:
66
+ if type(offer_count) is not int or not 0 <= offer_count <= 1000:
67
+ return False
68
+ if not isinstance(value, list) or len(value) > len(COMMERCIAL_DIMENSIONS):
69
+ return False
70
+ previous = -1
71
+ seen: set[str] = set()
72
+ for item in value:
73
+ if (
74
+ not isinstance(item, dict)
75
+ or set(item) != {"dimension", "offer_indexes"}
76
+ or item.get("dimension") not in dimensions
77
+ or item["dimension"] in seen
78
+ or not isinstance(item.get("offer_indexes"), list)
79
+ or not item["offer_indexes"]
80
+ or any(
81
+ type(index) is not int or not 0 <= index < offer_count
82
+ for index in item["offer_indexes"]
83
+ )
84
+ or item["offer_indexes"] != sorted(set(item["offer_indexes"]))
85
+ ):
86
+ return False
87
+ position = COMMERCIAL_DIMENSIONS.index(item["dimension"])
88
+ if position <= previous:
89
+ return False
90
+ previous = position
91
+ seen.add(item["dimension"])
92
+ return True
93
+
94
+
54
95
  class HTTPReceiptVerifierFailed(RuntimeError):
55
96
  """Content-free verifier failure understood by release coordination."""
56
97
 
@@ -66,6 +107,23 @@ class HTTPReceiptVerifierFailed(RuntimeError):
66
107
  self.retryable = retryable
67
108
 
68
109
 
110
+ def _load_module(name: str, path: Path):
111
+ spec = importlib.util.spec_from_file_location(name, path)
112
+ if spec is None or spec.loader is None:
113
+ raise RuntimeError(f"cannot load receipt dependency: {path.name}")
114
+ module = importlib.util.module_from_spec(spec)
115
+ sys.modules[spec.name] = module
116
+ spec.loader.exec_module(module)
117
+ return module
118
+
119
+
120
+ _ROOT = Path(__file__).resolve().parents[1]
121
+ _COMMERCIAL = _load_module(
122
+ "blun_website_localization_receipt_http_commercial",
123
+ _ROOT / "integrations" / "commercial_localization_profile.py",
124
+ )
125
+
126
+
69
127
  @dataclass(frozen=True)
70
128
  class HTTPResult:
71
129
  status: int
@@ -253,6 +311,40 @@ def _provider(value: Any) -> bool:
253
311
  )
254
312
 
255
313
 
314
+ def _quality_profile(
315
+ value: Any,
316
+ *,
317
+ target_locale: Any,
318
+ content_type: Any,
319
+ commercial_profile: Any,
320
+ ) -> bool:
321
+ commercial = commercial_profile is not None
322
+ expected_fields = {"locale", "version", "sha256"}
323
+ if commercial:
324
+ expected_fields.add("commercial")
325
+ if (
326
+ not isinstance(value, dict)
327
+ or set(value) != expected_fields
328
+ or value.get("locale") != target_locale
329
+ or not _token(value.get("version"))
330
+ or not isinstance(value.get("sha256"), str)
331
+ or SHA256.fullmatch(value["sha256"]) is None
332
+ or (content_type == "commercial") != commercial
333
+ ):
334
+ return False
335
+ if not commercial:
336
+ return True
337
+ nested = value.get("commercial")
338
+ return (
339
+ isinstance(nested, dict)
340
+ and set(nested) == {"profile", "version", "sha256"}
341
+ and nested.get("profile") == commercial_profile
342
+ and _token(nested.get("version"))
343
+ and isinstance(nested.get("sha256"), str)
344
+ and SHA256.fullmatch(nested["sha256"]) is not None
345
+ )
346
+
347
+
256
348
  def _binding(value: Any) -> tuple[dict[str, Any], bytes]:
257
349
  if (
258
350
  not isinstance(value, dict)
@@ -267,11 +359,18 @@ def _binding(value: Any) -> tuple[dict[str, Any], bytes]:
267
359
  value, code="binding_invalid", maximum=MAX_REQUEST_BYTES,
268
360
  ))
269
361
  for field in (
270
- "job_id", "source_locale", "target_locale", "content_type",
362
+ "evidence_revision", "job_id", "source_locale", "target_locale", "content_type",
271
363
  "glossary_version", "policy_version", "software_version",
272
364
  ):
273
365
  if not _token(binding[field]):
274
366
  _fail("binding_invalid")
367
+ if (
368
+ not isinstance(binding["evidence_request_id"], str)
369
+ or EVIDENCE_REQUEST_ID.fullmatch(
370
+ binding["evidence_request_id"]
371
+ ) is None
372
+ ):
373
+ _fail("binding_invalid")
275
374
  for field in ("result_sha256", "source_sha256", "target_sha256"):
276
375
  if not isinstance(binding[field], str) or SHA256.fullmatch(binding[field]) is None:
277
376
  _fail("binding_invalid")
@@ -299,16 +398,17 @@ def _binding(value: Any) -> tuple[dict[str, Any], bytes]:
299
398
  confidence = binding["review_confidence"]
300
399
  profile = binding["quality_profile"]
301
400
  commercial_review = binding["commercial_review"]
401
+ commercial_review_routing = binding["commercial_review_routing"]
302
402
  if (
303
403
  not isinstance(confidence, dict)
304
404
  or set(confidence) != {"target_native", "source_fidelity"}
305
405
  or any(result not in {"high", "low"} for result in confidence.values())
306
- or not isinstance(profile, dict)
307
- or set(profile) != {"locale", "version", "sha256"}
308
- or profile["locale"] != binding["target_locale"]
309
- or not _token(profile["version"])
310
- or not isinstance(profile["sha256"], str)
311
- or SHA256.fullmatch(profile["sha256"]) is None
406
+ or not _quality_profile(
407
+ profile,
408
+ target_locale=binding["target_locale"],
409
+ content_type=binding["content_type"],
410
+ commercial_profile=binding["commercial_profile"],
411
+ )
312
412
  or (
313
413
  binding["commercial_profile"] is not None
314
414
  and not _token(binding["commercial_profile"])
@@ -320,10 +420,16 @@ def _binding(value: Any) -> tuple[dict[str, Any], bytes]:
320
420
  not isinstance(commercial_review, dict)
321
421
  or set(commercial_review) != {
322
422
  "schema", "profile", "status",
323
- "review_required_dimensions", "evidence_sha256",
423
+ "review_required_dimensions",
424
+ "offer_count", "review_required_offers",
425
+ "review_evidence_contract_sha256", "evidence_sha256",
324
426
  }
325
427
  or commercial_review["schema"] != COMMERCIAL_REVIEW_SUMMARY_SCHEMA
326
428
  or commercial_review["profile"] != binding["commercial_profile"]
429
+ or commercial_review["review_evidence_contract_sha256"]
430
+ != _COMMERCIAL.public_review_evidence_contract(
431
+ binding["commercial_profile"],
432
+ )["sha256"]
327
433
  or commercial_review["status"] not in {
328
434
  "verified", "review_required",
329
435
  }
@@ -336,9 +442,17 @@ def _binding(value: Any) -> tuple[dict[str, Any], bytes]:
336
442
  ]
337
443
  or len(commercial_review["review_required_dimensions"])
338
444
  != len(set(commercial_review["review_required_dimensions"]))
445
+ or not _commercial_offer_scope(
446
+ commercial_review["review_required_offers"],
447
+ commercial_review["review_required_dimensions"],
448
+ commercial_review["offer_count"],
449
+ )
339
450
  or (
340
451
  commercial_review["status"] == "verified"
341
- and commercial_review["review_required_dimensions"]
452
+ and (
453
+ commercial_review["review_required_dimensions"]
454
+ or commercial_review["review_required_offers"]
455
+ )
342
456
  )
343
457
  or (
344
458
  commercial_review["status"] == "review_required"
@@ -355,6 +469,45 @@ def _binding(value: Any) -> tuple[dict[str, Any], bytes]:
355
469
  or type(binding["independent_review_required"]) is not bool
356
470
  ):
357
471
  _fail("binding_invalid")
472
+ try:
473
+ if (
474
+ commercial_review is not None
475
+ and commercial_review["status"] == "review_required"
476
+ ):
477
+ _COMMERCIAL.validate_review_routing_context(
478
+ commercial_review_routing,
479
+ binding["source_text"],
480
+ binding["target_text"],
481
+ commercial_review,
482
+ binding["commercial_profile"],
483
+ )
484
+ elif commercial_review_routing is not None:
485
+ raise _COMMERCIAL.CommercialReviewBlocked(
486
+ "review.commercial.routing_invalid",
487
+ )
488
+ except _COMMERCIAL.CommercialReviewBlocked:
489
+ _fail("binding_invalid")
490
+ expected_resolution_contract_sha256 = (
491
+ _COMMERCIAL.public_review_resolution_contract(
492
+ binding["commercial_profile"],
493
+ )["sha256"]
494
+ if commercial_review is not None
495
+ and commercial_review["status"] == "review_required"
496
+ else None
497
+ )
498
+ if (
499
+ binding["commercial_review_routing_contract_sha256"]
500
+ != (
501
+ _COMMERCIAL.public_review_routing_contract(
502
+ binding["commercial_profile"]
503
+ )["sha256"]
504
+ if commercial_review is not None
505
+ else None
506
+ )
507
+ or binding["commercial_review_resolution_contract_sha256"]
508
+ != expected_resolution_contract_sha256
509
+ ):
510
+ _fail("binding_invalid")
358
511
  return binding, _canonical_json(
359
512
  binding, code="binding_invalid", maximum=MAX_REQUEST_BYTES,
360
513
  )