champollion 0.3.4 → 0.4.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 (132) hide show
  1. package/README.md +41 -26
  2. package/bin/cli.js +53 -5
  3. package/index.js +63 -2
  4. package/lib/api-key.js +17 -4
  5. package/lib/autofix.js +83 -36
  6. package/lib/bridge/method_bridge.py +15 -3
  7. package/lib/cards/reader.js +34 -0
  8. package/lib/cards/remote.js +15 -0
  9. package/lib/cards/search-names.js +178 -0
  10. package/lib/command-help.js +286 -85
  11. package/lib/commands/audit.js +10 -3
  12. package/lib/commands/card.js +583 -226
  13. package/lib/commands/doctor.js +54 -18
  14. package/lib/commands/help.js +37 -32
  15. package/lib/commands/init.js +1689 -87
  16. package/lib/commands/integrity.js +127 -40
  17. package/lib/commands/leaderboard.js +187 -67
  18. package/lib/commands/models.js +9 -2
  19. package/lib/commands/provenance.js +7 -2
  20. package/lib/commands/recommend.js +43 -14
  21. package/lib/commands/register-corpus.js +632 -125
  22. package/lib/commands/seal-corpus.js +1 -1
  23. package/lib/commands/status.js +564 -27
  24. package/lib/commands/submit.js +17 -12
  25. package/lib/commands/sync.js +31 -7
  26. package/lib/commands/tm.js +15 -9
  27. package/lib/commands/verify.js +27 -3
  28. package/lib/commands/wrap.js +63 -5
  29. package/lib/commands/xliff.js +135 -64
  30. package/lib/commercial-eligibility.js +1 -1
  31. package/lib/config.js +196 -14
  32. package/lib/content-estimate.js +96 -0
  33. package/lib/content-refusals.js +270 -0
  34. package/lib/content-review.js +372 -0
  35. package/lib/content-sync.js +1127 -344
  36. package/lib/content.js +94 -7
  37. package/lib/corpus-registration.mjs +194 -35
  38. package/lib/cost-label.js +29 -0
  39. package/lib/cost-report.js +726 -78
  40. package/lib/diff.js +38 -4
  41. package/lib/docusaurus-sync.js +965 -253
  42. package/lib/edit-distance.js +31 -0
  43. package/lib/fallback.js +964 -0
  44. package/lib/file-scope.js +106 -0
  45. package/lib/flatten.js +80 -3
  46. package/lib/flutter-locales.js +124 -0
  47. package/lib/format.js +266 -12
  48. package/lib/hash.js +146 -21
  49. package/lib/icu-structure.js +929 -0
  50. package/lib/integrity.js +223 -75
  51. package/lib/language-pair.js +157 -0
  52. package/lib/lint.js +78 -16
  53. package/lib/local-only-marks.js +106 -0
  54. package/lib/locale-layout.js +1103 -0
  55. package/lib/locale-state.js +571 -0
  56. package/lib/methods/anthropic.js +5 -0
  57. package/lib/methods/apertium.js +6 -3
  58. package/lib/methods/api.js +138 -25
  59. package/lib/methods/base.js +17 -0
  60. package/lib/methods/coaching-data.js +153 -0
  61. package/lib/methods/content-separator.js +43 -0
  62. package/lib/methods/deepl.js +1 -1
  63. package/lib/methods/direct-llm.js +252 -103
  64. package/lib/methods/external.js +146 -63
  65. package/lib/methods/gemini.js +1 -0
  66. package/lib/methods/google-translate.js +1 -0
  67. package/lib/methods/http-utils.js +41 -0
  68. package/lib/methods/libretranslate.js +7 -2
  69. package/lib/methods/llm-coached.js +68 -128
  70. package/lib/methods/llm.js +80 -31
  71. package/lib/methods/local.js +93 -10
  72. package/lib/methods/microsoft-translator.js +1 -2
  73. package/lib/methods/openai.js +4 -2
  74. package/lib/methods/openrouter-client.js +20 -19
  75. package/lib/methods/openrouter-pricing.js +150 -13
  76. package/lib/methods/prompt-methods.js +20 -0
  77. package/lib/methods/provider-pricing.js +42 -1
  78. package/lib/methods/request-capture.js +104 -0
  79. package/lib/methods/tilde.js +1 -1
  80. package/lib/methods/translated.js +1 -2
  81. package/lib/missing-key.js +93 -0
  82. package/lib/models.js +11 -0
  83. package/lib/name-rules.js +32 -0
  84. package/lib/named-keys.js +172 -0
  85. package/lib/no-translate.js +4 -3
  86. package/lib/output.js +160 -19
  87. package/lib/pairs.js +586 -30
  88. package/lib/placeholders.js +394 -0
  89. package/lib/plugins.js +8 -0
  90. package/lib/plural-gap-redo.js +109 -0
  91. package/lib/plurals.js +323 -0
  92. package/lib/po.js +1187 -0
  93. package/lib/public-catalogue.js +74 -0
  94. package/lib/recommend.js +527 -32
  95. package/lib/redo.js +95 -0
  96. package/lib/refusal-category.js +44 -0
  97. package/lib/registers.js +255 -11
  98. package/lib/repair-script.js +20 -13
  99. package/lib/scripts.js +6 -1
  100. package/lib/seal.mjs +4 -3
  101. package/lib/sealed-qualifier.mjs +1 -1
  102. package/lib/segment.js +2 -1
  103. package/lib/seo.js +19 -9
  104. package/lib/serve.js +43 -6
  105. package/lib/shared-output-seed.js +164 -0
  106. package/lib/source-contexts.js +39 -0
  107. package/lib/submit.mjs +57 -5
  108. package/lib/sync.js +2923 -474
  109. package/lib/terminology.js +13 -4
  110. package/lib/tm-evict.js +179 -0
  111. package/lib/tm-seed.js +5 -2
  112. package/lib/tm.js +818 -36
  113. package/lib/translate-pair.js +639 -34
  114. package/lib/translate.js +78 -5
  115. package/lib/types.js +22 -3
  116. package/lib/validate.js +880 -17
  117. package/lib/verify.js +1296 -104
  118. package/lib/watch.js +32 -13
  119. package/lib/xliff.js +44 -3
  120. package/package.json +1 -1
  121. package/shared/CORPORA-CARDS.md +2 -0
  122. package/shared/cards-fallback.json +1 -1
  123. package/shared/curated-orthography-conventions.json +26 -8
  124. package/shared/gettext-plural-forms.json +45 -0
  125. package/shared/method-registry.json +2 -0
  126. package/shared/metric-registry.json +96 -18
  127. package/shared/schemas/champollion-plugin.schema.json +4 -0
  128. package/shared/schemas/corpora-card.schema.json +8 -2
  129. package/shared/schemas/method-index-record.schema.json +67 -0
  130. package/shared/schemas/method-registry.schema.json +4 -0
  131. package/shared/schemas/metric-registry.schema.json +55 -1
  132. package/shared/docent/corpus.json +0 -11739
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The public corpus catalogue, read without a key: the `datasets` table the
3
+ * harness and the leaderboard resolve corpora against (anon SELECT, public
4
+ * segments only — mt-eval-arena/supabase/migrations/016_datasets_rls.sql),
5
+ * through the same read-only REST path the CLI already uses for language
6
+ * cards (lib/cards/remote.js fetchJson, lib/cards/env.js endpoint + key).
7
+ *
8
+ * Used by `network register-corpus` on an npm install, which ships no
9
+ * corpora cards: a private / local-only / sealed registration of a file that
10
+ * is a byte-identical copy of a public benchmark must not be graded
11
+ * "Contamination: NONE" just because the comparison was never made (Round 9,
12
+ * researcher persona).
13
+ *
14
+ * PRIVACY: the file's sha256 never leaves the machine. The catalogue's
15
+ * (id, sha256) pairs are downloaded and compared HERE; only a matching
16
+ * PUBLIC id is then looked up for its name and licence.
17
+ *
18
+ * Fail-soft: offline (CHAMPOLLION_OFFLINE=1), unreachable, or an answer that
19
+ * is not the expected shape → `{ ok: false, why }`, never a guess. The caller
20
+ * then records the comparison as not made.
21
+ */
22
+
23
+ import { fetchJson } from './cards/remote.js';
24
+ import { SUPABASE_URL, OFFLINE } from './cards/env.js';
25
+
26
+ /** PostgREST caps a response at 1000 rows on Supabase. */
27
+ const PAGE = 1000;
28
+ /** A bound on the whole read: a catalogue far larger than this is not this table. */
29
+ const MAX_PAGES = 50;
30
+
31
+ /**
32
+ * Look for public corpora whose built file has one of these sha256s.
33
+ *
34
+ * @param {string[]} sha256s - lower-case hex digests of the local files
35
+ * @param {{ timeoutMs?: number }} [options]
36
+ * @returns {Promise<{ ok: true, compared: number, hits: Map<string, { id: string, name: string, license: string|null }> }
37
+ * | { ok: false, why: string }>}
38
+ * compared: how many public corpora were compared against; hits: sha256 → corpus
39
+ */
40
+ export async function findPublicCorporaBySha(sha256s, { timeoutMs = 8000 } = {}) {
41
+ if (OFFLINE) return { ok: false, why: 'offline (CHAMPOLLION_OFFLINE=1)' };
42
+ const wanted = new Set(sha256s.map(s => String(s).toLowerCase()));
43
+ const found = new Map(); // sha → id
44
+ let compared = 0;
45
+ try {
46
+ for (let page = 0; page < MAX_PAGES; page++) {
47
+ const params = new URLSearchParams({
48
+ select: 'id,sha256', sha256: 'not.is.null', order: 'id.asc', limit: String(PAGE), offset: String(page * PAGE),
49
+ });
50
+ // eslint-disable-next-line no-await-in-loop — pages in order; one at a time is polite to the endpoint
51
+ const rows = await fetchJson(`${SUPABASE_URL}/rest/v1/datasets?${params}`, { timeoutMs, retries: 1 });
52
+ if (!Array.isArray(rows)) return { ok: false, why: 'the public catalogue answered in an unexpected shape' };
53
+ for (const r of rows) {
54
+ if (!r || typeof r.sha256 !== 'string') continue;
55
+ compared++;
56
+ const sha = r.sha256.toLowerCase();
57
+ if (wanted.has(sha) && !found.has(sha)) found.set(sha, String(r.id));
58
+ }
59
+ if (rows.length < PAGE) break;
60
+ }
61
+ const hits = new Map();
62
+ for (const [sha, id] of found) {
63
+ const params = new URLSearchParams({ select: 'id,name,license', id: `eq.${id}`, limit: '1' });
64
+ // eslint-disable-next-line no-await-in-loop — at most one lookup per local file
65
+ const [row] = await fetchJson(`${SUPABASE_URL}/rest/v1/datasets?${params}`, { timeoutMs, retries: 1 });
66
+ hits.set(sha, { id, name: row?.name || id, license: row?.license || null });
67
+ }
68
+ if (compared === 0) return { ok: false, why: 'the public catalogue listed no corpus checksums' };
69
+ return { ok: true, compared, hits };
70
+ } catch (err) {
71
+ const reason = err?.status ? `HTTP ${err.status}` : (err?.name === 'TimeoutError' ? 'no answer in time' : (err?.cause?.code || err?.message || 'unreachable'));
72
+ return { ok: false, why: `the public catalogue could not be read (${reason})` };
73
+ }
74
+ }