champollion 0.3.3 → 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.
- package/README.md +52 -37
- package/bin/cli.js +53 -5
- package/index.js +63 -2
- package/lib/api-key.js +17 -4
- package/lib/autofix.js +83 -36
- package/lib/bridge/method_bridge.py +15 -3
- package/lib/cards/reader.js +51 -3
- package/lib/cards/remote.js +15 -0
- package/lib/cards/search-names.js +178 -0
- package/lib/command-help.js +289 -88
- package/lib/commands/audit.js +10 -3
- package/lib/commands/card.js +583 -226
- package/lib/commands/doctor.js +54 -18
- package/lib/commands/help.js +37 -32
- package/lib/commands/init.js +1689 -87
- package/lib/commands/integrity.js +127 -40
- package/lib/commands/leaderboard.js +187 -67
- package/lib/commands/models.js +9 -2
- package/lib/commands/provenance.js +7 -2
- package/lib/commands/recommend.js +43 -14
- package/lib/commands/register-corpus.js +649 -130
- package/lib/commands/seal-corpus.js +1 -1
- package/lib/commands/status.js +564 -27
- package/lib/commands/submit.js +17 -12
- package/lib/commands/sync.js +31 -7
- package/lib/commands/tm.js +16 -10
- package/lib/commands/verify.js +27 -3
- package/lib/commands/wrap.js +63 -5
- package/lib/commands/xliff.js +135 -64
- package/lib/commercial-eligibility.js +1 -1
- package/lib/config.js +196 -14
- package/lib/content-estimate.js +96 -0
- package/lib/content-refusals.js +270 -0
- package/lib/content-review.js +372 -0
- package/lib/content-sync.js +1127 -344
- package/lib/content.js +94 -7
- package/lib/corpus-registration.mjs +197 -38
- package/lib/cost-label.js +29 -0
- package/lib/cost-report.js +726 -78
- package/lib/diff.js +38 -4
- package/lib/docusaurus-sync.js +965 -253
- package/lib/edit-distance.js +31 -0
- package/lib/fallback.js +964 -0
- package/lib/file-scope.js +106 -0
- package/lib/flatten.js +80 -3
- package/lib/flutter-locales.js +124 -0
- package/lib/format.js +266 -12
- package/lib/hash.js +146 -21
- package/lib/icu-structure.js +929 -0
- package/lib/integrity.js +223 -75
- package/lib/language-pair.js +157 -0
- package/lib/lint.js +78 -16
- package/lib/local-only-marks.js +106 -0
- package/lib/locale-layout.js +1103 -0
- package/lib/locale-state.js +571 -0
- package/lib/methods/anthropic.js +5 -0
- package/lib/methods/apertium.js +6 -3
- package/lib/methods/api.js +138 -25
- package/lib/methods/base.js +17 -0
- package/lib/methods/coaching-data.js +153 -0
- package/lib/methods/content-separator.js +43 -0
- package/lib/methods/deepl.js +1 -1
- package/lib/methods/direct-llm.js +252 -103
- package/lib/methods/external.js +146 -63
- package/lib/methods/gemini.js +1 -0
- package/lib/methods/google-translate.js +1 -0
- package/lib/methods/http-utils.js +41 -0
- package/lib/methods/libretranslate.js +7 -2
- package/lib/methods/llm-coached.js +68 -128
- package/lib/methods/llm.js +80 -31
- package/lib/methods/local.js +93 -10
- package/lib/methods/microsoft-translator.js +1 -2
- package/lib/methods/openai.js +4 -2
- package/lib/methods/openrouter-client.js +20 -19
- package/lib/methods/openrouter-pricing.js +150 -13
- package/lib/methods/prompt-methods.js +20 -0
- package/lib/methods/provider-pricing.js +42 -1
- package/lib/methods/request-capture.js +104 -0
- package/lib/methods/tilde.js +1 -1
- package/lib/methods/translated.js +1 -2
- package/lib/missing-key.js +93 -0
- package/lib/models.js +11 -0
- package/lib/name-rules.js +32 -0
- package/lib/named-keys.js +172 -0
- package/lib/no-translate.js +4 -3
- package/lib/output.js +160 -19
- package/lib/pairs.js +586 -30
- package/lib/placeholders.js +394 -0
- package/lib/plugins.js +8 -0
- package/lib/plural-gap-redo.js +109 -0
- package/lib/plurals.js +323 -0
- package/lib/po.js +1187 -0
- package/lib/public-catalogue.js +74 -0
- package/lib/recommend.js +527 -32
- package/lib/redo.js +95 -0
- package/lib/refusal-category.js +44 -0
- package/lib/registers.js +255 -11
- package/lib/repair-script.js +20 -13
- package/lib/scripts.js +193 -106
- package/lib/seal.mjs +6 -5
- package/lib/sealed-qualifier.mjs +2 -2
- package/lib/segment.js +2 -1
- package/lib/seo.js +19 -9
- package/lib/serve.js +43 -6
- package/lib/shared-output-seed.js +164 -0
- package/lib/source-contexts.js +39 -0
- package/lib/submit.mjs +57 -5
- package/lib/sync.js +2923 -474
- package/lib/terminology.js +13 -4
- package/lib/tm-evict.js +179 -0
- package/lib/tm-seed.js +5 -2
- package/lib/tm.js +818 -36
- package/lib/translate-pair.js +639 -34
- package/lib/translate.js +78 -5
- package/lib/types.js +22 -3
- package/lib/validate.js +880 -17
- package/lib/verify.js +1296 -104
- package/lib/watch.js +32 -13
- package/lib/xliff.js +44 -3
- package/package.json +3 -2
- package/shared/CORPORA-CARDS.md +2 -0
- package/shared/DATA-SOVEREIGNTY.md +19 -20
- package/shared/LANGUAGE-CARD-FIELDS.md +1 -1
- package/shared/cards-fallback.json +1 -1
- package/shared/catalogue/card-config.json +1 -1
- package/shared/curated-orthography-conventions.json +26 -8
- package/shared/docent/faq.en.json +14 -16
- package/shared/docent/system-prompt.md +17 -19
- package/shared/explainers/tc-features.json +15 -15
- package/shared/gettext-plural-forms.json +45 -0
- package/shared/human-services.json +1 -1
- package/shared/method-registry.json +2 -0
- package/shared/metric-registry.json +96 -18
- package/shared/schemas/champollion-plugin.schema.json +4 -0
- package/shared/schemas/corpora-card.schema.json +20 -10
- package/shared/schemas/human-services.schema.json +2 -2
- package/shared/schemas/language-card.schema.json +1 -1
- package/shared/schemas/method-card.schema.json +1 -1
- package/shared/schemas/method-index-record.schema.json +67 -0
- package/shared/schemas/method-registry.schema.json +4 -0
- package/shared/schemas/metric-registry.schema.json +55 -1
- package/shared/docent/corpus.json +0 -11333
package/lib/command-help.js
CHANGED
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { DEFAULT_OPENROUTER_MODEL, DEFAULT_TEMPERATURE, DEFAULT_BATCH_SIZE } from './config.js';
|
|
14
|
+
import { LOCALE_FILE_FORMATS } from './format.js';
|
|
15
|
+
|
|
16
|
+
// The --format values a config accepts — the reader's own list, so the help
|
|
17
|
+
// can never fall behind a format the CLI learns (lib/format.js).
|
|
18
|
+
const FORMAT_CHOICES = ['auto', ...LOCALE_FILE_FORMATS].join(', ');
|
|
14
19
|
|
|
15
20
|
const COMMAND_HELP = {
|
|
16
21
|
init: {
|
|
@@ -22,24 +27,40 @@ const COMMAND_HELP = {
|
|
|
22
27
|
'In non-interactive environments (CI/piped stdin), or with --yes,',
|
|
23
28
|
'generates a default config without prompting. In interactive mode',
|
|
24
29
|
'the same flags prefill the wizard, so each step is Enter to accept.',
|
|
30
|
+
'Finds your locale files first: Flutter lib/l10n/app_<lang>.arb (or',
|
|
31
|
+
'the arb-dir/template-arb-file in l10n.yaml), gettext catalogs',
|
|
32
|
+
'(Django locale/<lang>/LC_MESSAGES/<domain>.po, Babel translations/,',
|
|
33
|
+
'GNU po/), next-intl messages/, i18next public/locales/<lang>/ (one',
|
|
34
|
+
'folder per language), vue-i18n src/locales/, Hugo i18n/, then common',
|
|
35
|
+
'folders. --langs also creates the empty target files in that layout.',
|
|
25
36
|
],
|
|
26
37
|
options: [
|
|
27
38
|
['--yes', 'Skip wizard, use defaults'],
|
|
28
|
-
['--force', '
|
|
39
|
+
['--force', 'Re-run over an existing config: rewrites only what the flags name (and re-detects the locale layout when the config no longer finds the source files); every other setting is kept. Prints what changed, and backs the file up first (champollion.config.json.bak; an older backup is never overwritten — .bak.2, .bak.3 …). To change one setting, edit it in the file instead'],
|
|
29
40
|
['--langs <codes>', 'Target languages, comma-separated (e.g., fr,de,ja); presets: european, asian, global, nordic'],
|
|
41
|
+
['--script <choice>', 'Writing system for a language with more than one real orthography (Plains Cree: Latn = SRO, Cans = Syllabics; Serbian: Latn, Cyrl): crk=Cans, or several as crk=Cans,sr=Latn. Without it init says which languages need a choice'],
|
|
42
|
+
['--name <code=name>', 'Display name for a language with no card — a private-use code (qaa–qtz) for a variety not yet confirmed: qaa="Ayta (variety not yet confirmed)"; several separated by ";". Written as "languages": { "qaa": { "name": … } }; it is what the model is told'],
|
|
30
43
|
['--source <code>', 'Source locale (default: en)'],
|
|
31
|
-
['--dir <path>', 'Locales directory (default: ./locales)'],
|
|
32
|
-
['--
|
|
44
|
+
['--dir <path>', 'Locales directory (default: detected from your project, else ./locales)'],
|
|
45
|
+
['--content-dir <dir>', 'A folder of Markdown/MDX files to translate too (writes "contentDir"; the folder must exist)'],
|
|
46
|
+
['--method <name>', 'Translation method: llm, openai, anthropic, gemini, local (your own model: Ollama/vLLM/LM Studio/nmt-forge), deepl, microsoft-translator, libretranslate, google-translate, api (a champollion API endpoint — needs --endpoint) (default: llm = OpenRouter; local when a file in the project is marked local-only — a <file>.champollion.json sidecar with "transmission": "local-only")'],
|
|
47
|
+
['--endpoint <url>', 'With --method api: the endpoint URL (e.g. http://127.0.0.1:8378/translate from `nmt-forge serve`). Writes one "pairs" entry per target, as the model\'s DEPLOY.md shows'],
|
|
48
|
+
['--accepts-instructions <true|false>', 'With --method api: whether the endpoint follows per-key instructions (a model trained with nmt-forge does not: false). Default: what an installed plugin manifest for that endpoint says, else not stated'],
|
|
33
49
|
['--model <model>', `Translation model (default: ${DEFAULT_OPENROUTER_MODEL})`],
|
|
34
50
|
['--temperature <n>', `Sampling temperature, 0.0-1.0 (default: ${DEFAULT_TEMPERATURE})`],
|
|
35
|
-
['--format <fmt>',
|
|
51
|
+
['--format <fmt>', `File format: ${FORMAT_CHOICES} (default: auto — detected from the file extension)`],
|
|
36
52
|
],
|
|
37
53
|
examples: [
|
|
38
54
|
'champollion init # Interactive wizard',
|
|
39
55
|
'champollion init --langs fr,de,ja # Wizard with prefilled targets',
|
|
40
56
|
'champollion init --yes --langs fr,de,ja # Non-interactive, quick setup',
|
|
41
57
|
'champollion init --yes --langs fr,de --method deepl --temperature 0.2',
|
|
58
|
+
'champollion init --yes --langs fr,de --method local --model llama3.1 # a model on this machine (Ollama, LM Studio…), no key',
|
|
59
|
+
'champollion init --yes --langs abc --method api --endpoint http://127.0.0.1:8378/translate --accepts-instructions false # nmt-forge serve',
|
|
60
|
+
'champollion init --yes --langs crk --script crk=Latn # Plains Cree in SRO (Cans = Syllabics)',
|
|
61
|
+
'champollion init --yes --langs qaa --name qaa="Ayta (variety not yet confirmed)" # a variety with no confirmed code',
|
|
42
62
|
'champollion init --yes # Minimal config, auto-detect',
|
|
63
|
+
'champollion init --force --langs fr,de,es # Over an existing config: the target list changes, every other setting stays',
|
|
43
64
|
],
|
|
44
65
|
},
|
|
45
66
|
|
|
@@ -55,21 +76,28 @@ const COMMAND_HELP = {
|
|
|
55
76
|
['--dry', 'Preview changes without writing files'],
|
|
56
77
|
['--list-keys', 'With --dry: name every queued key, grouped by reason (missing / fallback / unstamped echo / changed / forced)'],
|
|
57
78
|
['--pair <src:tgt>', 'Only sync the named pair(s), comma-separated (e.g. en:fr). Unknown pairs fail loud'],
|
|
58
|
-
['--
|
|
59
|
-
['--
|
|
60
|
-
['--force
|
|
61
|
-
['--
|
|
79
|
+
['--redo <scope>', 'Translate again: all | keys:<k1,k2> | content | files:<glob> | gaps (repeatable). Anything the cache already holds is served free (and gate-checked), so a redo is cheap. all and content keep text a person edited (and say how much); keys:<k> and files:<glob> replace it — the key/file was named. gaps: every plural message on disk without a form its language uses for ordinary counts (the "other" form standing in, marked "# champollion:" in a catalog) — asked from the model, not the cache. A gettext context key can be typed as ctx\\x04msgid (or ctx␄msgid, as reports print it)'],
|
|
80
|
+
['--fresh', 'Do not use the cache for what is queued — it is paid for again. With --redo files:<glob>, the files are re-translated from scratch (lock, keep-hand-translated rule and cache all bypassed)'],
|
|
81
|
+
['--force', 'Same as --redo all: re-queue EVERY source key — whole-locale rebuild; values a person edited are kept (sync names them). Scope with --pair; add --fresh (or --no-tm) to also bypass the cache'],
|
|
82
|
+
['--force-keys <keys>', 'Same as --redo keys:<keys>: comma-separated keys to translate again — replaced even when a person edited them (the edited wording is printed and kept in .champollion-replaced-edits.jsonl). `\\,` = a comma inside a key; a gettext context key: ctx\\x04msgid'],
|
|
83
|
+
['--force-content', 'Same as --redo content: ignore the content lock and re-process every champollion-managed content file (hand-translated files are still preserved). Cached content is served free; text the TM has never seen is billed'],
|
|
84
|
+
['--files <glob>', 'Only these content files this run (repeatable; paths as sync prints them, e.g. "docs/intro.md", "posts/**")'],
|
|
85
|
+
['--retranslate <glob>', 'Same as --redo files:<glob> --fresh. Translate these content files fresh — bypasses the lock and the cache, so it is billed, and replaces paragraphs a person edited in them (said first; like --redo files:<glob>, a named file is replaced — every other redo keeps edits) (repeatable)'],
|
|
86
|
+
['--model <model>', 'Translation model for this run only — champollion.config.json is not changed, and a plain sync uses its "model" again. To switch for good, edit "model" there'],
|
|
62
87
|
['--config <path>', 'Path to config file'],
|
|
63
88
|
['--dir <path>', 'Override locales directory'],
|
|
64
|
-
['--content-dir <p>', 'Hugo content
|
|
89
|
+
['--content-dir <p>', 'Folder of Markdown/MDX to translate (Hugo content/ or any folder)'],
|
|
65
90
|
['--source <code>', 'Override source locale (default: en)'],
|
|
66
|
-
['--format <fmt>',
|
|
67
|
-
['--method <method>', 'Translation method: llm, llm-coached, google-translate,
|
|
91
|
+
['--format <fmt>', `Locale file format: ${FORMAT_CHOICES} (po = gettext, arb = Flutter)`],
|
|
92
|
+
['--method <method>', 'Translation method: llm, llm-coached, local (your own model: Ollama/vLLM/LM Studio/forge), openai, anthropic, gemini, google-translate, deepl, microsoft-translator, libretranslate, api. Overrides the config for this run only — including a pair\'s own method (sync names the pairs); scope with --pair. To switch for good, edit "defaultMethod" (or the pair\'s "method") in champollion.config.json'],
|
|
68
93
|
['--temperature <n>', `Sampling temperature for LLM methods (default: ${DEFAULT_TEMPERATURE})`],
|
|
69
94
|
['--batch-size <n>', `Keys per translation API call (positive integer, default: ${DEFAULT_BATCH_SIZE})`],
|
|
70
|
-
['--max-cost <usd>', 'Abort before any API call if the pre-run cost estimate exceeds this USD cap (exit 2; unknown estimates abort too — unknown is not free)'],
|
|
95
|
+
['--max-cost <usd>', 'Abort before any API call if the pre-run cost estimate exceeds this USD cap (exit 2; unknown estimates abort too — unknown is not free). With --dry: says whether the real run would stop there'],
|
|
96
|
+
['--show-prompt [key]', 'With --dry: print the exact request the method would be sent (system/user messages or request body, keys redacted) — for one key, or the first batch each file would send. Shows whether a gettext msgctxt or #. comment reaches the model'],
|
|
71
97
|
['--no-verify', 'Skip post-sync verification pass'],
|
|
72
|
-
['--no-tm', '
|
|
98
|
+
['--no-tm', 'Same as --fresh: skip the Translation Memory cache (fresh API calls for everything queued)'],
|
|
99
|
+
['--fresh-on-model-change', 'Don\'t reuse the previous model\'s cached translations for what this run translates (default: reuse them, at no cost). On its own it affects only new or changed keys; to have the new model translate what an earlier model wrote: --redo all --fresh-on-model-change'],
|
|
100
|
+
['--prune plural-extras', 'Remove i18next plural keys for a form the language does not have (Spanish count_two from a source with count_one/count_other) — CLDR says which. Lists each key it removes and touches nothing else; never without this flag. With --dry: says what it would remove'],
|
|
73
101
|
['--json', 'Machine-readable NDJSON output (one JSON object per line)'],
|
|
74
102
|
['--quiet, -q', 'Suppress informational messages; show only warnings and errors'],
|
|
75
103
|
],
|
|
@@ -80,12 +108,16 @@ const COMMAND_HELP = {
|
|
|
80
108
|
'champollion sync --force-keys hero.title # Re-translate specific keys',
|
|
81
109
|
'champollion sync --pair "en:tlh" --force # Rebuild one whole locale',
|
|
82
110
|
'champollion sync --pair "en:tlh" --force --no-tm # …bypassing a suspect cache',
|
|
83
|
-
'champollion sync --content-dir ./
|
|
111
|
+
'champollion sync --content-dir ./newsletters # Include a folder of Markdown',
|
|
84
112
|
'champollion sync --max-cost 0.50 # Refuse to spend more than $0.50',
|
|
113
|
+
'champollion sync --redo gaps # Ask again for plural forms a model left out',
|
|
114
|
+
'champollion sync --prune plural-extras # Remove plural keys for forms a language does not have',
|
|
115
|
+
'champollion sync --dry --show-prompt \'verb␄Open\' # The request for one gettext entry (context included), not sent',
|
|
85
116
|
],
|
|
86
117
|
},
|
|
87
118
|
|
|
88
119
|
serve: {
|
|
120
|
+
summary: "Serves this project's own translation stack over HTTP, for another project's `api` method.",
|
|
89
121
|
usage: 'champollion serve [options]',
|
|
90
122
|
description: [
|
|
91
123
|
'Serves this project\'s OWN configured translation stack (method,',
|
|
@@ -143,18 +175,22 @@ const COMMAND_HELP = {
|
|
|
143
175
|
},
|
|
144
176
|
|
|
145
177
|
audit: {
|
|
178
|
+
summary: 'Lists what is not translated, or out of date, across locale files — with the command that fixes it.',
|
|
146
179
|
usage: 'champollion audit [options]',
|
|
147
180
|
description: [
|
|
148
|
-
'Lists
|
|
149
|
-
'
|
|
150
|
-
'
|
|
181
|
+
'Lists what is not translated across locale files — keys missing,',
|
|
182
|
+
'empty, or still an [EN] fallback — and translations that are OUT OF',
|
|
183
|
+
'DATE: made from an older source text than the current one (the record',
|
|
184
|
+
'in .champollion.lock), with the command that re-translates them.',
|
|
185
|
+
'Returns exit code 1 if any exist — usable as a CI gate to block',
|
|
186
|
+
'deploys with missing or stale translations.',
|
|
151
187
|
],
|
|
152
188
|
options: [
|
|
153
189
|
['--config <path>', 'Path to config file'],
|
|
154
190
|
['--dir <path>', 'Override locales directory'],
|
|
155
191
|
['--source <code>', 'Override source locale'],
|
|
156
192
|
['--format <fmt>', 'Locale file format: json, toml, yaml, auto'],
|
|
157
|
-
['--json', 'Machine-readable NDJSON output (one JSON object per line; summary carries the untranslated key
|
|
193
|
+
['--json', 'Machine-readable NDJSON output (one JSON object per line; summary carries the untranslated and out-of-date key lists)'],
|
|
158
194
|
],
|
|
159
195
|
examples: [
|
|
160
196
|
'champollion audit # List untranslated keys',
|
|
@@ -163,13 +199,46 @@ const COMMAND_HELP = {
|
|
|
163
199
|
],
|
|
164
200
|
},
|
|
165
201
|
|
|
202
|
+
network: {
|
|
203
|
+
usage: 'champollion network <command> [options]',
|
|
204
|
+
description: [
|
|
205
|
+
'Commands for the shared index and leaderboard, not your project.',
|
|
206
|
+
'Each also works without the "network" prefix.',
|
|
207
|
+
'',
|
|
208
|
+
' card <code> What the index knows about a language, every value cited',
|
|
209
|
+
' recommend <s> <t> Methods you can run for a pair, and the evidence for each',
|
|
210
|
+
' leaderboard Published results (--pair, --sort, --json)',
|
|
211
|
+
' register-corpus Register a test set without handing it over',
|
|
212
|
+
' seal-corpus Sealed-tier crypto: keygen / seal / open',
|
|
213
|
+
' submit Propose an index entry (review-gated)',
|
|
214
|
+
'',
|
|
215
|
+
'A language pair is written source>target: "eng>crk" (quote it — an unquoted >',
|
|
216
|
+
'sends the output to a file). The commands that take a pair also read eng-crk',
|
|
217
|
+
'and eng:crk; a code with its own hyphen (pt-BR) needs >: "eng>pt-BR".',
|
|
218
|
+
],
|
|
219
|
+
options: [],
|
|
220
|
+
examples: [
|
|
221
|
+
'champollion network card crk',
|
|
222
|
+
'champollion network recommend eng crk',
|
|
223
|
+
'champollion network recommend eng-crk # the same pair, as one value',
|
|
224
|
+
'champollion network leaderboard --pair "eng>crk"',
|
|
225
|
+
'champollion network register-corpus --data data/test.tsv --name "Ward phrases" --pair "eng>xyz" --license proprietary --tier local-only --domain medical',
|
|
226
|
+
],
|
|
227
|
+
},
|
|
228
|
+
|
|
166
229
|
card: {
|
|
167
|
-
usage: 'champollion card <code> [options]',
|
|
230
|
+
usage: 'champollion network card <code> [options]',
|
|
168
231
|
description: [
|
|
169
232
|
'Pretty-prints a language card from the shared language-cards directory.',
|
|
170
|
-
'Shows identification, classification, speaker estimates,
|
|
171
|
-
'corpus availability,
|
|
172
|
-
'and data sources in a
|
|
233
|
+
'Shows identification, classification, speaker estimates, endangerment,',
|
|
234
|
+
'typology, corpus availability, language resources, eval datasets,',
|
|
235
|
+
'pipeline readiness, method support, and data sources in a',
|
|
236
|
+
'color-formatted terminal layout.',
|
|
237
|
+
'',
|
|
238
|
+
'Where sources disagree (names, families, speaker counts, endangerment, …)',
|
|
239
|
+
'every value is printed with its source and none is elected. A section',
|
|
240
|
+
'the card has nothing for says "not recorded on this card": absence is',
|
|
241
|
+
'unknown, not "none".',
|
|
173
242
|
'',
|
|
174
243
|
'Resolves aliases automatically (e.g., "fr" → "fra", "es" → "spa").',
|
|
175
244
|
],
|
|
@@ -177,41 +246,59 @@ const COMMAND_HELP = {
|
|
|
177
246
|
['--json', 'Output the raw card JSON instead of the formatted display'],
|
|
178
247
|
],
|
|
179
248
|
examples: [
|
|
180
|
-
'champollion card crk # Plains Cree',
|
|
181
|
-
'champollion card spa # Spanish',
|
|
182
|
-
'champollion card cmn --json # Raw JSON for Mandarin',
|
|
183
|
-
'champollion card fr # French (resolves alias)',
|
|
249
|
+
'champollion network card crk # Plains Cree',
|
|
250
|
+
'champollion network card spa # Spanish',
|
|
251
|
+
'champollion network card cmn --json # Raw JSON for Mandarin',
|
|
252
|
+
'champollion network card fr # French (resolves alias)',
|
|
184
253
|
],
|
|
185
254
|
},
|
|
186
255
|
|
|
187
256
|
'register-corpus': {
|
|
188
|
-
usage: 'champollion register-corpus [options]',
|
|
257
|
+
usage: 'champollion network register-corpus [options]',
|
|
189
258
|
description: [
|
|
190
259
|
'Register a new evaluation corpus, choosing its license and exposure tier.',
|
|
191
|
-
'You control the license and how far the corpus travels —
|
|
260
|
+
'You control the license and how far the corpus travels — four exposure',
|
|
192
261
|
'tiers, defaulting to the most private:',
|
|
193
262
|
' local-only — never registered or uploaded; card + text stay on your machine.',
|
|
194
263
|
' private — register METADATA ONLY (WMT-style sovereign held-out set);',
|
|
195
264
|
' your text is never uploaded or hosted; you keep custody.',
|
|
196
265
|
' public — publish a metadata card + fetch-from-source pointer; text never',
|
|
197
266
|
' hosted by us, and gated to redistribution-cleared licenses.',
|
|
198
|
-
' sealed — encrypt the corpus ON YOUR DEVICE
|
|
199
|
-
'
|
|
200
|
-
'
|
|
267
|
+
' sealed — encrypt the corpus ON YOUR DEVICE to the custodian group’s',
|
|
268
|
+
' key; the ciphertext stays with you and we receive only a',
|
|
269
|
+
' content-free card. Paired with a public qualifier a method',
|
|
201
270
|
' must clear before any sealed run can be proposed.',
|
|
202
271
|
'',
|
|
203
|
-
'Champollion never
|
|
272
|
+
'Champollion never uploads or hosts your corpus text, in any tier. A file you',
|
|
273
|
+
'name is read on this machine only: --data to count its entries and checksum',
|
|
274
|
+
'it, --seal-input to encrypt it. None of it is sent anywhere.',
|
|
204
275
|
'Interactive in a terminal; fully scriptable with flags (or --yes).',
|
|
276
|
+
'',
|
|
277
|
+
'A test set a model may be trained against (--role test, or a local-only or',
|
|
278
|
+
'private set with no role stated): the command prints the nmt-forge steps —',
|
|
279
|
+
'register it, screen the training corpus, write down predictions — that must',
|
|
280
|
+
'come before its first score, then the baseline run.',
|
|
281
|
+
'',
|
|
282
|
+
'Card id: eval-<src>-<tgt>-<name>[-<role>]-v1, e.g. --name "Ward phrases"',
|
|
283
|
+
'--pair "eng>xyz" --role test → eval-eng-xyz-ward-phrases-test-v1.',
|
|
284
|
+
'The name part comes from --name (from --publisher only when the name has no',
|
|
285
|
+
'a-z/0-9 letters). The role part appears only when you pass --role; no role is',
|
|
286
|
+
'ever guessed. A file registered with --data keeps the id it was registered',
|
|
287
|
+
'under: re-running asks you to pass it with --id.',
|
|
205
288
|
],
|
|
206
289
|
options: [
|
|
207
290
|
['--tier <tier>', 'local-only | private | public | sealed (default: local-only). Alias: --exposure'],
|
|
208
291
|
['--license <id>', 'License key / SPDX id / list number (see --list)'],
|
|
209
|
-
['--name <text>', 'Corpus name (required)'],
|
|
210
|
-
['--
|
|
211
|
-
|
|
292
|
+
['--name <text>', 'Corpus name (required; also names the card id)'],
|
|
293
|
+
['--role <role>', 'What the set is for: test | dev | train. Goes into the id; left out, the id names no role'],
|
|
294
|
+
// The pair text is lib/language-pair.js's PAIR_NOTATION_HELP (a test holds them equal).
|
|
295
|
+
['--pair <pair>', 'Language pair, source>target, e.g. "eng>crk" (quote it: an unquoted > sends the output to a file). eng-crk, eng:crk and "eng crk" are read the same way; a code with its own hyphen (pt-BR) needs >, e.g. "eng>pt-BR". Or --source-lang/--target-lang'],
|
|
296
|
+
['--data <file>', 'The local test-set file (TSV/JSONL/JSON): read on this machine only to count and checksum it, never uploaded; writes <file>.champollion.json so mt-eval run applies the licence (local-only: remote models refused)'],
|
|
297
|
+
['--size <n>', 'Number of sentence pairs (required unless --data)'],
|
|
212
298
|
['--domain <text>', 'Domain: news, conversational, educational, … (required)'],
|
|
213
|
-
['--contamination <l>', 'NONE | LOW | MEDIUM | HIGH
|
|
299
|
+
['--contamination <l>', 'NONE | LOW | MEDIUM | HIGH. Default: LOW for public, NONE otherwise — UNCHECKED when a --data or --seal-input file could not be compared with the public corpora (a copy of a public corpus is never graded NONE)'],
|
|
214
300
|
['--publisher <text>', 'Publisher / your name or org'],
|
|
301
|
+
['--description <text>', 'One-line description'],
|
|
215
302
|
['--repo-url <url>', 'Public tier: fetch-from-source archive/repo URL'],
|
|
216
303
|
['--source-url <url>', 'Public tier: canonical project/dataset URL'],
|
|
217
304
|
['--builder <id>', 'Public tier: builder adapter id (rebuilds from source)'],
|
|
@@ -221,28 +308,33 @@ const COMMAND_HELP = {
|
|
|
221
308
|
['--seal-out <path>', 'Sealed tier: where to write the ciphertext artifact'],
|
|
222
309
|
['--qualifier-id <id>', 'Sealed tier: paired public qualifier card id (vYYYY)'],
|
|
223
310
|
['--qualifier-threshold <n>', 'Sealed tier: score a method must clear on the qualifier'],
|
|
224
|
-
['--
|
|
225
|
-
['--
|
|
311
|
+
['--key-scheme <s>', 'Sealed tier: custody scheme label (default: TSS-3-of-5)'],
|
|
312
|
+
['--id <id>', 'Set the card id yourself (eval-…/ref-…, used as given; other text replaces the name part)'],
|
|
313
|
+
['--out <dir>', 'Where to write the card (default: next to --data, else cwd)'],
|
|
226
314
|
['--list', 'Print the license + tier catalog (add --json for JSON)'],
|
|
227
315
|
['--json', 'Machine-readable output (for agents)'],
|
|
228
316
|
['--yes', 'Non-interactive; take values from flags'],
|
|
229
317
|
],
|
|
230
318
|
examples: [
|
|
231
|
-
'champollion register-corpus # interactive wizard',
|
|
232
|
-
'champollion register-corpus --list # see licenses + tiers',
|
|
233
|
-
'champollion register-corpus --yes --name "My set" --pair "eng>crk" \\',
|
|
319
|
+
'champollion network register-corpus # interactive wizard',
|
|
320
|
+
'champollion network register-corpus --list # see licenses + tiers',
|
|
321
|
+
'champollion network register-corpus --yes --name "My set" --pair "eng>crk" \\',
|
|
234
322
|
' --license cc-by-4.0 --tier local-only --size 200 --domain news',
|
|
235
|
-
'champollion register-corpus --yes --name "Holdout" --pair "eng>crk" \\',
|
|
236
|
-
' --license cc-by-nc-4.0 --tier private --size 500 --domain educational',
|
|
237
|
-
'champollion register-corpus --yes --name "
|
|
323
|
+
'champollion network register-corpus --yes --name "Holdout" --pair "eng>crk" \\',
|
|
324
|
+
' --license cc-by-nc-4.0 --tier private --role test --size 500 --domain educational',
|
|
325
|
+
'champollion network register-corpus --yes --name "Tatoeba eng-crk" --pair eng-crk \\',
|
|
326
|
+
' --license cc-by-4.0 --tier public --size 1000 --domain conversational \\',
|
|
327
|
+
' --repo-url https://example.org/data.tar --builder tatoeba-challenge',
|
|
328
|
+
'champollion network register-corpus --yes --name "Sealed" --pair "eng>crk" \\',
|
|
238
329
|
' --license proprietary --tier sealed --size 500 --domain educational \\',
|
|
239
330
|
' --seal-input ./secret.json --threshold-pubkey ./group.pub \\',
|
|
240
|
-
' --custodian-group
|
|
331
|
+
' --custodian-group example-community-trust --qualifier-id eval-eng-crk-…-qualifier-v2026',
|
|
241
332
|
],
|
|
242
333
|
},
|
|
243
334
|
|
|
244
335
|
'seal-corpus': {
|
|
245
|
-
|
|
336
|
+
summary: 'Encrypts, decrypts and signs corpora for the sealed exposure tier (keygen, seal, open, sign, verify).',
|
|
337
|
+
usage: 'champollion network seal-corpus <keygen|seal|open|sign-keygen|sign|verify> [options]',
|
|
246
338
|
description: [
|
|
247
339
|
'The crypto verbs around the sealed exposure tier (lib/seal.mjs is the one',
|
|
248
340
|
'cipher implementation: X25519-ECDH → HKDF-SHA256 → AES-256-GCM). Used by',
|
|
@@ -279,21 +371,21 @@ const COMMAND_HELP = {
|
|
|
279
371
|
['--pubkey <k>', 'verify: Ed25519 public key (file / b64 / PEM)'],
|
|
280
372
|
],
|
|
281
373
|
examples: [
|
|
282
|
-
'champollion seal-corpus keygen --out ~/.contest-keys',
|
|
283
|
-
'champollion seal-corpus seal --seal-input ./refs.json --id eval-eng-xxx-blindtest-v1 \\',
|
|
374
|
+
'champollion network seal-corpus keygen --out ~/.contest-keys',
|
|
375
|
+
'champollion network seal-corpus seal --seal-input ./refs.json --id eval-eng-xxx-blindtest-v1 \\',
|
|
284
376
|
' --custodian-group org-a1b2 --threshold-pubkey ~/.contest-keys/threshold-….pub.json \\',
|
|
285
377
|
' --seal-out ~/contest/refs.sealed.json --card-block-out ~/contest/sealed-block.json',
|
|
286
|
-
'champollion seal-corpus open --artifact ~/contest/refs.sealed.json \\',
|
|
378
|
+
'champollion network seal-corpus open --artifact ~/contest/refs.sealed.json \\',
|
|
287
379
|
' --privkey ~/.contest-keys/threshold-….key.json --out /tmp/scratch/refs.json',
|
|
288
|
-
'champollion seal-corpus sign-keygen --out ~/.contest-keys',
|
|
289
|
-
'champollion seal-corpus sign --payload score-bundle.json --privkey ~/.contest-keys/score-sign-….key.json',
|
|
290
|
-
'champollion seal-corpus verify --payload score-bundle.json --sig score-bundle.json.sig.json \\',
|
|
380
|
+
'champollion network seal-corpus sign-keygen --out ~/.contest-keys',
|
|
381
|
+
'champollion network seal-corpus sign --payload score-bundle.json --privkey ~/.contest-keys/score-sign-….key.json',
|
|
382
|
+
'champollion network seal-corpus verify --payload score-bundle.json --sig score-bundle.json.sig.json \\',
|
|
291
383
|
' --pubkey ~/.contest-keys/score-sign-….pub.json',
|
|
292
384
|
],
|
|
293
385
|
},
|
|
294
386
|
|
|
295
387
|
submit: {
|
|
296
|
-
usage: 'champollion submit [options]',
|
|
388
|
+
usage: 'champollion network submit [options]',
|
|
297
389
|
description: [
|
|
298
390
|
'Propose an entry for the Champollion index along a REVIEW-GATED path.',
|
|
299
391
|
'Gathers the fields for a chosen submission type and prints a PRE-FILLED',
|
|
@@ -310,10 +402,13 @@ const COMMAND_HELP = {
|
|
|
310
402
|
' external-result — a published result from another system/paper (cited, never re-hosted).',
|
|
311
403
|
' card-correction — a fix to a language card (cited; applied at the data source).',
|
|
312
404
|
'',
|
|
405
|
+
'A "pairs" field takes one language pair per line, source>target ("eng>crk";',
|
|
406
|
+
'eng-crk and eng:crk work too). The issue carries each one as eng>crk.',
|
|
407
|
+
'',
|
|
313
408
|
'Interactive in a terminal; fully scriptable with flags (or --yes).',
|
|
314
409
|
],
|
|
315
410
|
options: [
|
|
316
|
-
['--type <key>', 'dataset | resource | method | human-service | external-result'],
|
|
411
|
+
['--type <key>', 'dataset | resource | method | human-service | external-result | card-correction'],
|
|
317
412
|
['--values <json>', 'JSON object of field id -> value'],
|
|
318
413
|
['--field <id=val>', 'Set one field (repeatable): --field source-url=https://…'],
|
|
319
414
|
['--attest', 'Confirm the required compliance attestation (and consent)'],
|
|
@@ -325,12 +420,12 @@ const COMMAND_HELP = {
|
|
|
325
420
|
['--yes', 'Non-interactive; take values from flags'],
|
|
326
421
|
],
|
|
327
422
|
examples: [
|
|
328
|
-
'champollion submit # interactive wizard',
|
|
329
|
-
'champollion submit --list # see the submission types',
|
|
330
|
-
'champollion submit --yes --type dataset --attest \\',
|
|
423
|
+
'champollion network submit # interactive wizard',
|
|
424
|
+
'champollion network submit --list # see the submission types',
|
|
425
|
+
'champollion network submit --yes --type dataset --attest \\',
|
|
331
426
|
' --field dataset-name="GlobalVoices eng-amh" --field pairs=eng-amh \\',
|
|
332
427
|
' --field license=CC-BY-4.0 --field source-url=https://globalvoices.org',
|
|
333
|
-
'champollion submit --yes --type external-result --attest --out ./submission.json \\',
|
|
428
|
+
'champollion network submit --yes --type external-result --attest --out ./submission.json \\',
|
|
334
429
|
' --values \'{"system-name":"NLLB-200","pairs":"eng-crk","dataset":"FLORES-200","metric":"chrF++","score":"28.4","citation":"https://arxiv.org/abs/2207.04672"}\'',
|
|
335
430
|
],
|
|
336
431
|
},
|
|
@@ -345,6 +440,7 @@ const COMMAND_HELP = {
|
|
|
345
440
|
options: [
|
|
346
441
|
['--src <path>', 'Source directory to scan (auto-detected by default)'],
|
|
347
442
|
['--min-length <n>','Minimum string length to flag (default: 2)'],
|
|
443
|
+
['--ignore <names>', 'Comma-separated directory/file names to skip (adds to config lint.ignore)'],
|
|
348
444
|
['--warn-only', 'Exit 0 even if issues found'],
|
|
349
445
|
['--json', 'Machine-readable JSON output (single document with findings)'],
|
|
350
446
|
['--config <path>', 'Path to config file'],
|
|
@@ -402,6 +498,7 @@ const COMMAND_HELP = {
|
|
|
402
498
|
},
|
|
403
499
|
|
|
404
500
|
integrity: {
|
|
501
|
+
summary: 'Audits locale files for structural issues.',
|
|
405
502
|
usage: 'champollion integrity [options]',
|
|
406
503
|
description: [
|
|
407
504
|
'Audits locale files for structural issues:',
|
|
@@ -410,6 +507,12 @@ const COMMAND_HELP = {
|
|
|
410
507
|
' - Encoding problems (mojibake, BOM issues)',
|
|
411
508
|
' - Key structure drift between locales',
|
|
412
509
|
' - ICU MessageFormat plural category completeness',
|
|
510
|
+
' - ICU MessageFormat structure damage (translated keywords, variables,',
|
|
511
|
+
' selectors; lost # or printf placeholders)',
|
|
512
|
+
' - Flutter .arb file damage (@@locale, placeholder metadata)',
|
|
513
|
+
'',
|
|
514
|
+
'A damaged value the Translation Memory produced is removed from the',
|
|
515
|
+
'cache, so `sync --force-keys <key>` translates it again.',
|
|
413
516
|
'',
|
|
414
517
|
'Returns exit code 1 if issues found (unless --warn-only).',
|
|
415
518
|
],
|
|
@@ -465,6 +568,7 @@ const COMMAND_HELP = {
|
|
|
465
568
|
},
|
|
466
569
|
|
|
467
570
|
status: {
|
|
571
|
+
summary: 'Shows the project configuration summary.',
|
|
468
572
|
usage: 'champollion status [options]',
|
|
469
573
|
description: [
|
|
470
574
|
'Shows the project configuration summary:',
|
|
@@ -628,59 +732,119 @@ const COMMAND_HELP = {
|
|
|
628
732
|
verify: {
|
|
629
733
|
usage: 'champollion verify [options]',
|
|
630
734
|
description: [
|
|
631
|
-
'
|
|
632
|
-
'
|
|
633
|
-
'
|
|
735
|
+
'Checks the locale files on disk: complete, and structurally intact.',
|
|
736
|
+
'',
|
|
737
|
+
'Re-reads the files (not what sync remembers) and compares each locale',
|
|
738
|
+
'with the source — the gap between sync reporting success and keys being',
|
|
739
|
+
'wrong in fact. Structure only: the meaning is not checked.',
|
|
634
740
|
'',
|
|
635
|
-
'
|
|
636
|
-
'
|
|
741
|
+
'Errors (exit 1):',
|
|
742
|
+
' - a key missing — i18next plural keys included: the locale needs',
|
|
743
|
+
' a key for each of its CLDR plural forms (French count_one,',
|
|
744
|
+
' count_many, count_other; English needs count_one, count_other)',
|
|
745
|
+
' - an empty value, or a fallback marker ("[EN] " — fallbackPrefix)',
|
|
746
|
+
' - wrong script: Latin-only text in a non-Latin locale, or fullwidth',
|
|
747
|
+
' Latin letters',
|
|
748
|
+
' - a placeholder lost, renamed or added, named by its syntax:',
|
|
749
|
+
' ICU MessageFormat structure (a translated variable name,',
|
|
750
|
+
' plural/select keyword or selector, a lost #), printf/python-format',
|
|
751
|
+
' (%s, %d, %(name)s), i18next {{name}}, single-brace {name}',
|
|
752
|
+
' - markup: a tag opened, closed or nested differently',
|
|
753
|
+
' - a hollowed value (the source with its letters deleted), or a',
|
|
754
|
+
' no-translate key that differs from the source',
|
|
755
|
+
' - one text written for several different source strings',
|
|
756
|
+
' - Flutter .arb: a wrong @@locale or changed placeholder metadata',
|
|
757
|
+
' - a configured locale with no file, or nothing found to check',
|
|
637
758
|
'',
|
|
638
|
-
'
|
|
639
|
-
'
|
|
759
|
+
'Warnings (exit 0 unless --strict):',
|
|
760
|
+
' - plurals: an i18next key for a form the locale does not have',
|
|
761
|
+
' (Spanish count_two — `sync --prune plural-extras` removes those',
|
|
762
|
+
' keys and nothing else); an ICU plural message without a form the',
|
|
763
|
+
' language uses for ordinary counts (Russian few, many); gettext',
|
|
764
|
+
' msgstr[] forms repeating "other" (marked # champollion:), or more',
|
|
765
|
+
' of them than the catalog\'s nplurals',
|
|
766
|
+
' - source echoes, encoding issues (invisible characters, U+FFFD),',
|
|
767
|
+
' a lost closing ? or !',
|
|
768
|
+
' - two locales with identical text',
|
|
769
|
+
' - translations made from an older source text (out of date —',
|
|
770
|
+
' `audit` fails on those)',
|
|
771
|
+
' - Markdown blocks or front-matter fields the quality gate refuses',
|
|
772
|
+
'Said, never counted: an i18next plural form holding the text of the',
|
|
773
|
+
'form it was translated from, with no record of the model writing it.',
|
|
774
|
+
'',
|
|
775
|
+
'Each locale also gets a line per kind of plural it carries — the',
|
|
776
|
+
'forms its CLDR rules (or its gettext Plural-Forms) expect, and how',
|
|
777
|
+
'many plurals have all of them: "Plural forms (CLDR fr): one, many,',
|
|
778
|
+
'other ✓". --json writes one {"level":"event","event":"verify",…}',
|
|
779
|
+
'record per locale (findings, placeholders by syntax, plural coverage)',
|
|
780
|
+
'before the closing line, which carries the error and warning counts.',
|
|
781
|
+
'',
|
|
782
|
+
'A plain sync keeps a value already on disk, damaged or not: each',
|
|
783
|
+
'damage finding (placeholders, ICU structure, hollowed text) names the',
|
|
784
|
+
'command that repairs it — `champollion sync --pair en:fr --redo',
|
|
785
|
+
'keys:<key>` (`<ns>::<key>` when a locale spans several files, `\\,` for',
|
|
786
|
+
'a comma inside a key). No --fresh is needed: a damaged value the',
|
|
787
|
+
'Translation Memory produced is removed from the cache here, so the redo',
|
|
788
|
+
'translates it again instead of serving the same text for free.',
|
|
789
|
+
'Hand-written values and the files themselves are not touched.',
|
|
790
|
+
'',
|
|
791
|
+
'This is the same verification that runs automatically after sync',
|
|
792
|
+
'(where `sync --pair` verifies only the pairs that ran).',
|
|
640
793
|
],
|
|
641
794
|
options: [
|
|
642
|
-
['--
|
|
643
|
-
['--
|
|
644
|
-
['--
|
|
645
|
-
['--
|
|
795
|
+
['--pair <src:tgt>', 'Only verify the named pair(s), comma-separated (e.g. en:fr). Unknown pairs fail loud'],
|
|
796
|
+
['--strict', 'Exit 1 on warnings too (CI that must not pass a plural gap or an out-of-date value)'],
|
|
797
|
+
['--warn-only', 'Exit 0 even if errors found'],
|
|
798
|
+
['--json', 'NDJSON: one "verify" event per locale on stdout, errors and warnings on stderr, then the closing line with the counts'],
|
|
799
|
+
['--config <path>', 'Path to config file'],
|
|
800
|
+
['--dir <path>', 'Override locales directory'],
|
|
801
|
+
['--source <code>', 'Override source locale'],
|
|
646
802
|
],
|
|
647
803
|
examples: [
|
|
648
804
|
'champollion verify # Verify all locale files',
|
|
805
|
+
'champollion verify --pair en:fr # Only French',
|
|
649
806
|
'champollion verify --warn-only # Non-blocking verification',
|
|
807
|
+
'champollion verify --strict # Warnings fail too (CI)',
|
|
650
808
|
'champollion verify && echo "All good" # CI gate',
|
|
809
|
+
'champollion verify --json 2>/dev/null | jq -c \'select(.event == "verify") | {locale, plurals}\'',
|
|
651
810
|
],
|
|
652
811
|
},
|
|
653
812
|
|
|
654
813
|
leaderboard: {
|
|
655
|
-
usage: 'champollion leaderboard [options]',
|
|
814
|
+
usage: 'champollion network leaderboard [options]',
|
|
656
815
|
description: [
|
|
657
816
|
'Fetches and displays MT evaluation leaderboard data from Supabase.',
|
|
658
|
-
'
|
|
817
|
+
'Ranks by chrF++ with its 95% confidence interval (scoring standard/1,',
|
|
818
|
+
'as in WMT and FLORES-200), shows BLEU, TER and COMET beside it, and',
|
|
819
|
+
'diagnostics (exact match, FST acceptance) apart. No quality labels.',
|
|
659
820
|
'Supports filtering by language pair, sorting by any metric, and',
|
|
660
821
|
'NDJSON output for CI/CD integration.',
|
|
661
822
|
],
|
|
662
823
|
options: [
|
|
663
|
-
['--pair <pair>', 'Filter by language pair (
|
|
664
|
-
['--sort <key>', 'Sort by
|
|
824
|
+
['--pair <pair>', 'Filter by language pair, as the board writes it: "eng>crk" (ISO 639-3; quote the >). eng-crk and eng:crk work too, and a 2-letter code is resolved (en → eng)'],
|
|
825
|
+
['--sort <key>', 'Sort by: chrf (default), bleu, ter, comet; diagnostics exact, fst, equivalent, semantic; cost, date; composite (the retired legacy composite, old cards only)'],
|
|
665
826
|
['--top <n>', 'Show only the top N results'],
|
|
666
827
|
['--json', 'Machine-readable NDJSON output (one JSON object per line)'],
|
|
667
828
|
],
|
|
668
829
|
examples: [
|
|
669
|
-
'champollion leaderboard
|
|
670
|
-
'champollion leaderboard --pair "
|
|
671
|
-
'champollion leaderboard --sort chrf --top 10 # Top 10 by chrF++',
|
|
672
|
-
'champollion leaderboard --json | jq .
|
|
830
|
+
'champollion network leaderboard # All results, ranked by chrF++',
|
|
831
|
+
'champollion network leaderboard --pair "eng>crk" # Filter to English→Cree (quote the >)',
|
|
832
|
+
'champollion network leaderboard --sort chrf --top 10 # Top 10 by chrF++',
|
|
833
|
+
'champollion network leaderboard --json | jq .chrF # Pipe to jq for processing',
|
|
673
834
|
],
|
|
674
835
|
},
|
|
675
836
|
|
|
676
837
|
recommend: {
|
|
677
|
-
|
|
838
|
+
summary: 'Method guidance for one source→target pair: the engines and open models that can translate it, and the published evidence.',
|
|
839
|
+
usage: 'champollion network recommend <src> <tgt> [options] (or one pair: eng-crk, "eng>crk", --pair)',
|
|
678
840
|
description: [
|
|
679
841
|
'Method guidance for one source→target pair (ISO 639-3 codes): every',
|
|
680
842
|
'dispatchable engine with its live availability (API key present?',
|
|
681
|
-
'license lane?), the
|
|
682
|
-
'
|
|
683
|
-
'
|
|
843
|
+
'license lane?), the open models whose own model card declares the',
|
|
844
|
+
'target and that local-model can load (runnable, no published evidence —',
|
|
845
|
+
'a claim to benchmark, not a measurement), the published evidence indexed',
|
|
846
|
+
'for the pair (cited, never reproduced by us; relative-comparison-only),',
|
|
847
|
+
'and which evidenced models are actually runnable here.',
|
|
684
848
|
'',
|
|
685
849
|
'Honest by construction: no evidence means it says so and points at',
|
|
686
850
|
'runnable corpora instead of guessing. The commercial lane is STRICT —',
|
|
@@ -688,13 +852,15 @@ const COMMAND_HELP = {
|
|
|
688
852
|
'excluded with reasons, never silently dropped.',
|
|
689
853
|
],
|
|
690
854
|
options: [
|
|
855
|
+
['--pair <pair>', 'The pair as one value instead of two codes: "eng>yor" (quote the >), eng-yor or eng:yor'],
|
|
691
856
|
['--use <lane>', 'License lane: non-commercial (default) or commercial (STRICT)'],
|
|
692
|
-
['--json', 'Machine-readable payload (
|
|
857
|
+
['--json', 'Machine-readable payload (the `mt-eval recommend --json` shape, plus declared_models)'],
|
|
693
858
|
],
|
|
694
859
|
examples: [
|
|
695
|
-
'champollion recommend eng yor # Guidance for English→Yoruba',
|
|
696
|
-
'champollion recommend eng
|
|
697
|
-
'champollion recommend eng
|
|
860
|
+
'champollion network recommend eng yor # Guidance for English→Yoruba',
|
|
861
|
+
'champollion network recommend eng-yor # The same pair, as one value',
|
|
862
|
+
'champollion network recommend eng yor --use commercial # Commercial lane (AGPL excluded)',
|
|
863
|
+
'champollion network recommend eng quy --json | jq .notes # Honest no-evidence state',
|
|
698
864
|
],
|
|
699
865
|
},
|
|
700
866
|
|
|
@@ -711,7 +877,7 @@ const COMMAND_HELP = {
|
|
|
711
877
|
['cards', 'Verify language cards load correctly, report coverage stats'],
|
|
712
878
|
['config', 'Validate project config file and language code resolution'],
|
|
713
879
|
['fst [code]', 'Check FST installation (all or specific language)'],
|
|
714
|
-
['methods', 'Check API keys, server reachability, Python packages'],
|
|
880
|
+
['methods', 'Check API keys (that each is set; an OpenRouter key is also sent to OpenRouter\'s free key endpoint, which rejects a bad one), server reachability, Python packages'],
|
|
715
881
|
],
|
|
716
882
|
options: [
|
|
717
883
|
['--json', 'Machine-readable JSON output (single document with all check results)'],
|
|
@@ -733,12 +899,47 @@ const COMMAND_HELP = {
|
|
|
733
899
|
* @param {string} commandName - The command to show help for
|
|
734
900
|
* @returns {boolean} true if help was displayed, false if command not found
|
|
735
901
|
*/
|
|
902
|
+
/** Abbreviations whose period does not end a sentence ("e.g. AGPL"). */
|
|
903
|
+
const NOT_A_SENTENCE_END = /\b(?:e\.g|i\.e|etc|vs|cf)$/i;
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* The one-line heading of a command's help: its `summary`, else the first
|
|
907
|
+
* sentence of its description — never the first LINE, which cut nine
|
|
908
|
+
* headings off mid-sentence ("Serves this project's OWN configured
|
|
909
|
+
* translation stack (method," — Round 12). A sentence ends at . ! or ?
|
|
910
|
+
* followed by a space or the end, outside parentheses, and not after an
|
|
911
|
+
* abbreviation; the description's first paragraph is read as one text.
|
|
912
|
+
*
|
|
913
|
+
* @param {{ summary?: string, description: string[] }} help
|
|
914
|
+
* @returns {string}
|
|
915
|
+
*/
|
|
916
|
+
function helpHeading(help) {
|
|
917
|
+
if (typeof help.summary === 'string' && help.summary.trim()) return help.summary.trim();
|
|
918
|
+
const para = [];
|
|
919
|
+
for (const line of help.description || []) {
|
|
920
|
+
if (!line.trim()) break;
|
|
921
|
+
para.push(line.trim());
|
|
922
|
+
}
|
|
923
|
+
const text = para.join(' ');
|
|
924
|
+
let depth = 0;
|
|
925
|
+
for (let i = 0; i < text.length; i++) {
|
|
926
|
+
const ch = text[i];
|
|
927
|
+
if (ch === '(') depth++;
|
|
928
|
+
else if (ch === ')') depth = Math.max(0, depth - 1);
|
|
929
|
+
else if (depth === 0 && '.!?'.includes(ch) && (i === text.length - 1 || /\s/.test(text[i + 1]))
|
|
930
|
+
&& !NOT_A_SENTENCE_END.test(text.slice(0, i))) {
|
|
931
|
+
return text.slice(0, i + 1);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return text;
|
|
935
|
+
}
|
|
936
|
+
|
|
736
937
|
function showCommandHelp(commandName) {
|
|
737
938
|
const help = COMMAND_HELP[commandName];
|
|
738
939
|
if (!help) return false;
|
|
739
940
|
|
|
740
941
|
console.log('');
|
|
741
|
-
console.log(` champollion ${commandName} — ${help
|
|
942
|
+
console.log(` champollion ${commandName} — ${helpHeading(help)}`);
|
|
742
943
|
console.log('');
|
|
743
944
|
|
|
744
945
|
// Usage
|
|
@@ -787,4 +988,4 @@ function showCommandHelp(commandName) {
|
|
|
787
988
|
return true;
|
|
788
989
|
}
|
|
789
990
|
|
|
790
|
-
export { COMMAND_HELP, showCommandHelp };
|
|
991
|
+
export { COMMAND_HELP, showCommandHelp, helpHeading };
|