@sonenta/cli 0.4.1 → 0.6.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 +19 -8
- package/dist/index.js +111 -16
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,22 +82,33 @@ summary.
|
|
|
82
82
|
|
|
83
83
|
`agents add` drops a ready-made Claude agent into the project's
|
|
84
84
|
`.claude/agents/` directory — usable interactively in Claude Code or headless in
|
|
85
|
-
CI.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
85
|
+
CI. Both bundled agents are **local-first**: the agent generates the content
|
|
86
|
+
itself and writes it back via CRUD tools (**0 Sonenta AI credits**, drafts to
|
|
87
|
+
review); the server-side AI tools are an explicit, estimated, opt-in fallback.
|
|
88
|
+
|
|
89
|
+
- **`sonenta-a11y`** — accessibility auditor. Drives the Sonenta a11y MCP tools
|
|
90
|
+
(`a11y_report`, `list_a11y_gaps`, `set_a11y_variant`, plus the
|
|
91
|
+
`generate_a11y_variant` / `translate_a11y_variants` fallback) to find WCAG gaps
|
|
92
|
+
— missing aria-labels, images without alt text, hard-to-read copy, missing or
|
|
93
|
+
untranslated a11y variants — and fix them. Also scores plain-language difficulty
|
|
94
|
+
locally (`list_cognitive_candidates` → `set_cognitive_score`, 0 credits) and
|
|
95
|
+
suggests clearer rewrites.
|
|
96
|
+
- **`sonenta-i18n`** — i18n automation. Audits coverage (`coverage_report`,
|
|
97
|
+
`list_missing_keys`), creates missing keys (`create_keys_bulk`), translates the
|
|
98
|
+
untranslated itself honoring the glossary + project context
|
|
99
|
+
(`list_untranslated_keys` → `propose_translations_bulk`), and publishes
|
|
100
|
+
(`publish_cdn`).
|
|
91
101
|
|
|
92
102
|
```bash
|
|
93
103
|
# see what's available (and what's already installed)
|
|
94
104
|
sonenta agents list
|
|
95
105
|
|
|
96
|
-
# install
|
|
106
|
+
# install an agent into .claude/agents/
|
|
97
107
|
sonenta agents add sonenta-a11y
|
|
108
|
+
sonenta agents add sonenta-i18n
|
|
98
109
|
```
|
|
99
110
|
|
|
100
|
-
The
|
|
111
|
+
The agents reach these tools through the
|
|
101
112
|
[`@sonenta/mcp`](https://www.npmjs.com/package/@sonenta/mcp) server, so configure
|
|
102
113
|
that server with an `mcp:*` key first. `--dir <path>` targets another project
|
|
103
114
|
directory; `--force` overwrites an existing definition.
|
package/dist/index.js
CHANGED
|
@@ -42,10 +42,14 @@ or when the developer specifically asks for server-side generation.
|
|
|
42
42
|
(key_uuid, language_code, surface) with a text value. CRUD, **0 AI credits**,
|
|
43
43
|
stored as a draft.
|
|
44
44
|
- \`delete_a11y_variant\` \u2014 clear one variant. CRUD, **0 AI credits**.
|
|
45
|
+
- \`list_cognitive_candidates\` \u2014 text keys eligible for plain-language scoring
|
|
46
|
+
(a type offering plain_language, past a word floor). READ-ONLY.
|
|
47
|
+
- \`set_cognitive_score\` \u2014 record a key's cognitive difficulty score (0-100)
|
|
48
|
+
plus a plain-language suggestion. CRUD, **0 AI credits** (by_bot).
|
|
45
49
|
- \`a11y_estimate\` \u2014 preview the AI-credit cost of the server-side fallback.
|
|
46
|
-
- \`generate_a11y_variant\` / \`translate_a11y_variants\`
|
|
47
|
-
server-side AI
|
|
48
|
-
|
|
50
|
+
- \`generate_a11y_variant\` / \`translate_a11y_variants\` / \`analyze_cognitive\`
|
|
51
|
+
\u2014 **fallback only**: server-side AI that BILLS Sonenta AI credits. Use only
|
|
52
|
+
for very large volumes or on explicit developer request.
|
|
49
53
|
|
|
50
54
|
## The four a11y surfaces (what you write)
|
|
51
55
|
- \`aria_label\` \u2014 a concise accessible NAME for an interactive element (button,
|
|
@@ -63,8 +67,11 @@ assistive tech), not the visible UI string \u2014 keep them concise and meaningf
|
|
|
63
67
|
- \`a11y_variant_absent\` \u2014 a required surface is missing in the source \u2192 compose
|
|
64
68
|
it yourself and \`set_a11y_variant\` (source language).
|
|
65
69
|
- \`alt_missing\` \u2014 an image key has no source alt_text \u2192 write \`alt_text\`.
|
|
66
|
-
- \`reading_level_high\` \u2014
|
|
67
|
-
|
|
70
|
+
- \`reading_level_high\` \u2014 flagged when a key's COGNITIVE SCORE is at/above the
|
|
71
|
+
project threshold. Resolve it locally: judge the difficulty yourself and call
|
|
72
|
+
\`set_cognitive_score(key_uuid, score, suggestion)\` with a plain-language
|
|
73
|
+
rewrite (0 credits, draft). The suggestion is then applied to the
|
|
74
|
+
\`plain_language\` surface (or the base value) on human approval.
|
|
68
75
|
- \`a11y_untranslated\` \u2014 a source a11y variant exists but a locale lacks it \u2192
|
|
69
76
|
TRANSLATE it yourself and \`set_a11y_variant\` for that \`language_code\`.
|
|
70
77
|
|
|
@@ -83,12 +90,20 @@ assistive tech), not the visible UI string \u2014 keep them concise and meaningf
|
|
|
83
90
|
\`a11y_untranslated\`, translate the source variant yourself into the target
|
|
84
91
|
\`language_code\` and \`set_a11y_variant\`. Work through the gap list in
|
|
85
92
|
sensible batches. This spends NO AI credits.
|
|
86
|
-
4. **
|
|
87
|
-
|
|
93
|
+
4. **Score plain-language (local, 0 credits).** Call
|
|
94
|
+
\`list_cognitive_candidates\` (use \`only_unanalyzed=true\` to skip already
|
|
95
|
+
scored keys). For each candidate, JUDGE its cognitive difficulty yourself
|
|
96
|
+
(0-100, higher = harder to read) and write a clearer plain-language rewrite,
|
|
97
|
+
then \`set_cognitive_score(key_uuid, score, suggestion)\`. Keys at/above the
|
|
98
|
+
project threshold then surface as \`reading_level_high\` for a human to
|
|
99
|
+
apply/approve. This spends NO credits \u2014 prefer it over \`analyze_cognitive\`.
|
|
100
|
+
5. **Server fallback (opt-in only).** If the volume is impractical to do locally,
|
|
101
|
+
or the developer explicitly wants Sonenta server-side AI, FIRST call
|
|
88
102
|
\`a11y_estimate\` (report \`credits_required\` vs \`balance\`; stop if not
|
|
89
103
|
\`sufficient\`), confirm, THEN \`generate_a11y_variant\` /
|
|
90
|
-
\`translate_a11y_variants
|
|
91
|
-
|
|
104
|
+
\`translate_a11y_variants\` (or \`analyze_cognitive\` for bulk cognitive
|
|
105
|
+
scoring).
|
|
106
|
+
6. **Report.** Everything you write lands as a **draft** for human review \u2014 never
|
|
92
107
|
present it as final. Summarize what you set (counts by surface / locale), what
|
|
93
108
|
remains, and whether any credits were spent (0 on the local path).
|
|
94
109
|
|
|
@@ -100,20 +115,100 @@ assistive tech), not the visible UI string \u2014 keep them concise and meaningf
|
|
|
100
115
|
local fixes. Only use the credit-billing fallback when explicitly authorized.
|
|
101
116
|
|
|
102
117
|
## Guardrails
|
|
103
|
-
- Default to LOCAL
|
|
104
|
-
\`generate_a11y_variant\` / \`translate_a11y_variants\`
|
|
105
|
-
estimated, opt-in fallback \u2014 never the
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
118
|
+
- Default to LOCAL work + \`set_a11y_variant\` / \`set_cognitive_score\`
|
|
119
|
+
(0 credits). Treat \`generate_a11y_variant\` / \`translate_a11y_variants\` /
|
|
120
|
+
\`analyze_cognitive\` as an explicit, estimated, opt-in fallback \u2014 never the
|
|
121
|
+
silent default.
|
|
122
|
+
- \`set_a11y_variant\` / \`delete_a11y_variant\` / \`set_cognitive_score\` are CRUD
|
|
123
|
+
and never spend AI credits; only \`generate\` / \`translate\` / \`analyze\` do.
|
|
124
|
+
Always estimate before that fallback.
|
|
109
125
|
- You FILL gaps \u2014 never overwrite a human-reviewed variant blindly.
|
|
110
126
|
- Stay within the configured project; confirm it before any bulk operation.
|
|
111
127
|
`;
|
|
128
|
+
var SONENTA_I18N = `---
|
|
129
|
+
name: sonenta-i18n
|
|
130
|
+
description: Internationalization (i18n) automation agent for Sonenta-managed projects. Audits translation coverage, creates missing keys, translates the untranslated content itself (honoring the glossary and project context), and publishes \u2014 driving the Sonenta i18n MCP tools. Local-first (0 AI credits), draft-to-review, usable in Claude Code or headless in CI.
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
You are **sonenta-i18n**, an internationalization specialist for projects managed
|
|
134
|
+
with Sonenta. You run the everyday i18n loop \u2014 assess coverage, fill missing
|
|
135
|
+
keys, translate what is untranslated, and publish \u2014 through the Sonenta MCP
|
|
136
|
+
server's tools.
|
|
137
|
+
|
|
138
|
+
## Cost model \u2014 translate LOCALLY first (default, 0 credits)
|
|
139
|
+
You ARE a capable language model already running in the developer's session
|
|
140
|
+
(Claude Code or CI) on compute they already pay for. So you **translate the
|
|
141
|
+
strings yourself**, honoring the project's glossary and context, and write the
|
|
142
|
+
results with \`propose_translations_bulk\` as **drafts/proposed** \u2014 plain CRUD,
|
|
143
|
+
**zero Sonenta AI credits**. Do NOT reach for server-side on-demand AI
|
|
144
|
+
translation by default; where such a path exists it BILLS Sonenta AI credits and
|
|
145
|
+
is an explicit, estimate-first, opt-in fallback for very large volumes.
|
|
146
|
+
|
|
147
|
+
## Requirements
|
|
148
|
+
- The Sonenta MCP server (\`@sonenta/mcp\`) must be configured with an \`mcp:*\`
|
|
149
|
+
API key. Everything goes through its tools \u2014 never call the HTTP API directly.
|
|
150
|
+
If the tools are missing, tell the user to add the server
|
|
151
|
+
(\`npx -y @sonenta/mcp\`) and set \`SONENTA_API_KEY\`.
|
|
152
|
+
- Tools you drive:
|
|
153
|
+
- **Assess:** \`get_project_info\`, \`coverage_report\`, \`health_report\`,
|
|
154
|
+
\`missing_keys_stats\`, \`list_missing_keys\`.
|
|
155
|
+
- **Fill keys:** \`create_namespace\`, \`create_keys_bulk\`,
|
|
156
|
+
\`update_keys_bulk\`, \`acknowledge_missing_keys\`.
|
|
157
|
+
- **Translate:** \`list_untranslated_keys\`, \`propose_translations_bulk\`
|
|
158
|
+
(your primary write \u2014 CRUD, 0 credits), \`validate_translations\`.
|
|
159
|
+
- **Consistency:** \`glossary_list\`, \`project_context_get\`.
|
|
160
|
+
- **Ship:** \`publish_cdn\`.
|
|
161
|
+
|
|
162
|
+
## Workflow
|
|
163
|
+
1. **Assess.** \`get_project_info\` (source + target languages, namespaces);
|
|
164
|
+
\`coverage_report\` (per-language completeness); \`health_report\`
|
|
165
|
+
(source-string issues); \`missing_keys_stats\` / \`list_missing_keys\`
|
|
166
|
+
(runtime-detected gaps). Summarize where the project stands.
|
|
167
|
+
2. **Fill missing keys.** For runtime-detected missing keys, \`create_keys_bulk\`
|
|
168
|
+
(seed the source value) \u2014 \`create_namespace\` first if a namespace is new \u2014
|
|
169
|
+
then \`acknowledge_missing_keys\` to clear the dashboard.
|
|
170
|
+
3. **Translate the untranslated (default, 0 credits).** For each target
|
|
171
|
+
language, \`list_untranslated_keys\`. BEFORE translating, read
|
|
172
|
+
\`glossary_list\` (respect \`forbidden\` / \`do_not_translate\`, apply
|
|
173
|
+
\`translation\` rules) and \`project_context_get\` (brand voice, domain, tone).
|
|
174
|
+
Translate each value YOURSELF, then write a batch with
|
|
175
|
+
\`propose_translations_bulk\` (status draft/proposed). Work through the
|
|
176
|
+
languages and namespaces in sensible batches.
|
|
177
|
+
4. **Validate (optional).** \`validate_translations\` lints an i18next blob
|
|
178
|
+
server-side; fix anything it flags.
|
|
179
|
+
5. **Publish.** \`publish_cdn\` to release the bundles \u2014 with confirmation in
|
|
180
|
+
interactive mode, only on explicit authorization in CI.
|
|
181
|
+
6. **Report.** Show the coverage delta (before/after), counts of keys created and
|
|
182
|
+
strings translated, what remains, and that translations are drafts to review.
|
|
183
|
+
|
|
184
|
+
## Modes
|
|
185
|
+
- **Interactive (Claude Code):** propose the plan, write the drafts, then confirm
|
|
186
|
+
before publishing.
|
|
187
|
+
- **CI / headless:** run \`coverage_report\` and exit non-zero when completeness
|
|
188
|
+
is below a chosen threshold; optionally auto-write translation drafts; only
|
|
189
|
+
\`publish_cdn\` when the run is explicitly authorized.
|
|
190
|
+
|
|
191
|
+
## Guardrails
|
|
192
|
+
- Translations land as **drafts/proposed** for human review \u2014 never
|
|
193
|
+
auto-approved.
|
|
194
|
+
- Always honor the glossary (\`forbidden\` / \`do_not_translate\`) and the project
|
|
195
|
+
context before translating.
|
|
196
|
+
- Local translation + \`propose_translations_bulk\` is the default and costs 0
|
|
197
|
+
credits; any server-side AI translation is an explicit, estimated, opt-in
|
|
198
|
+
fallback.
|
|
199
|
+
- Never \`publish_cdn\` without confirmation/authorization; stay within the
|
|
200
|
+
configured project.
|
|
201
|
+
`;
|
|
112
202
|
var AGENTS = {
|
|
113
203
|
"sonenta-a11y": {
|
|
114
204
|
name: "sonenta-a11y",
|
|
115
205
|
summary: "Accessibility (a11y) auditor + fixer: scans WCAG gaps and fixes them locally (0-credit set_a11y_variant), with server-side AI generation as an opt-in fallback.",
|
|
116
206
|
content: SONENTA_A11Y
|
|
207
|
+
},
|
|
208
|
+
"sonenta-i18n": {
|
|
209
|
+
name: "sonenta-i18n",
|
|
210
|
+
summary: "i18n automation: audits coverage, creates missing keys, translates the untranslated locally (0-credit propose_translations_bulk), and publishes \u2014 server-side AI translation as an opt-in fallback.",
|
|
211
|
+
content: SONENTA_I18N
|
|
117
212
|
}
|
|
118
213
|
};
|
|
119
214
|
function listAgents() {
|
|
@@ -1122,7 +1217,7 @@ var whoamiCommand = new Command15("whoami").description("Show the configured def
|
|
|
1122
1217
|
|
|
1123
1218
|
// src/index.ts
|
|
1124
1219
|
var program = new Command16();
|
|
1125
|
-
program.name("sonenta").description("CLI for Sonenta translation management.").version("0.
|
|
1220
|
+
program.name("sonenta").description("CLI for Sonenta translation management.").version("0.6.0");
|
|
1126
1221
|
program.addCommand(loginCommand);
|
|
1127
1222
|
program.addCommand(logoutCommand);
|
|
1128
1223
|
program.addCommand(whoamiCommand);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/commands/agents.ts","../src/agents.ts","../src/commands/export.ts","../src/config.ts","../src/credentials.ts","../src/api.ts","../src/i18next_tree.ts","../src/mcp.ts","../src/commands/import.ts","../src/commands/init.ts","../src/commands/keys.ts","../src/commands/login.ts","../src/prompt.ts","../src/commands/logout.ts","../src/commands/missing.ts","../src/commands/projects.ts","../src/commands/pull.ts","../src/locales.ts","../src/commands/push.ts","../src/commands/releases.ts","../src/commands/snapshot.ts","../src/commands/status.ts","../src/commands/whoami.ts"],"sourcesContent":["import { Command } from \"commander\";\n\nimport { agentsCommand } from \"./commands/agents.js\";\nimport { exportCommand } from \"./commands/export.js\";\nimport { importCommand } from \"./commands/import.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { keysCommand } from \"./commands/keys.js\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { logoutCommand } from \"./commands/logout.js\";\nimport { missingCommand } from \"./commands/missing.js\";\nimport { projectsCommand } from \"./commands/projects.js\";\nimport { pullCommand } from \"./commands/pull.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { releasesCommand } from \"./commands/releases.js\";\nimport { snapshotCommand } from \"./commands/snapshot.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { whoamiCommand } from \"./commands/whoami.js\";\n\nconst program = new Command();\nprogram\n .name(\"sonenta\")\n .description(\"CLI for Sonenta translation management.\")\n .version(\"0.4.1\");\n\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(whoamiCommand);\nprogram.addCommand(initCommand);\nprogram.addCommand(projectsCommand);\nprogram.addCommand(keysCommand);\nprogram.addCommand(importCommand);\nprogram.addCommand(pushCommand);\nprogram.addCommand(pullCommand);\nprogram.addCommand(exportCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(releasesCommand);\nprogram.addCommand(snapshotCommand);\nprogram.addCommand(missingCommand);\nprogram.addCommand(agentsCommand);\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n console.error(err instanceof Error ? err.message : err);\n process.exit(1);\n});\n","import { Command } from \"commander\";\n\nimport { AGENTS_DIR, isInstalled, listAgents, writeAgent } from \"../agents.js\";\n\nexport const agentsCommand = new Command(\"agents\")\n .description(\"Install bundled Claude agents (e.g. sonenta-a11y) into .claude/agents/.\")\n .addCommand(\n new Command(\"list\")\n .description(\"List the bundled agents available to install.\")\n .option(\"--dir <path>\", \"Project directory (default: current directory)\")\n .action(async (opts: { dir?: string }) => {\n const baseDir = opts.dir;\n const agents = listAgents();\n console.log(`Available agents (${agents.length}):`);\n for (const a of agents) {\n const installed = await isInstalled(a.name, baseDir);\n const mark = installed ? \"✓ installed\" : \" not installed\";\n console.log(` ${a.name.padEnd(16)} ${mark}`);\n console.log(` ${a.summary}`);\n }\n console.log(`\\nInstall with: sonenta agents add <name>`);\n }),\n )\n .addCommand(\n new Command(\"add\")\n .description(\"Write a bundled agent definition into <dir>/.claude/agents/<name>.md.\")\n .argument(\"<name>\", \"Agent name (e.g. sonenta-a11y)\")\n .option(\"--dir <path>\", \"Project directory (default: current directory)\")\n .option(\"--force\", \"Overwrite an existing agent definition\", false)\n .action(async (name: string, opts: { dir?: string; force: boolean }) => {\n const path = await writeAgent(name, { baseDir: opts.dir, force: opts.force });\n console.log(`Wrote ${path}`);\n console.log(\n `\\nThe ${name} agent drives the Sonenta a11y MCP tools. Make sure the ` +\n `Sonenta MCP server is configured (npx -y @sonenta/mcp) with an ` +\n `mcp:* SONENTA_API_KEY, then use the agent in Claude Code or CI.`,\n );\n console.log(`Agent dir: ${AGENTS_DIR}/`);\n }),\n );\n","import { promises as fs } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\n/**\n * Installable Claude agents shipped with the CLI.\n *\n * `sonenta agents add <name>` writes a bundled agent definition into the\n * project's `.claude/agents/<name>.md` — the directory Claude Code reads\n * project-scoped subagents from. The agents drive the Sonenta a11y MCP tools\n * (from `@sonenta/mcp`) to audit and fix accessibility gaps; they work the same\n * interactively in Claude Code or headless in CI.\n *\n * The registry is intentionally simple (a name -> definition map) so more\n * agents can be added later without touching the command wiring.\n */\n\nexport const AGENTS_DIR = \".claude/agents\";\n\nexport interface AgentDef {\n /** File/agent name (no extension); the file is written as `<name>.md`. */\n name: string;\n /** One-line summary shown by `agents list`. */\n summary: string;\n /** Full agent definition (YAML frontmatter + system prompt). */\n content: string;\n}\n\nconst SONENTA_A11Y = `---\nname: sonenta-a11y\ndescription: Accessibility (a11y) auditor and fixer for Sonenta-managed i18n projects. Scans translation keys for WCAG gaps (missing aria-labels, images without alt text, hard-to-read copy, missing or untranslated a11y variants) and fixes them — generating the a11y text itself and writing it back through the Sonenta MCP tools at zero AI-credit cost. Use interactively in Claude Code or headless in CI.\n---\n\nYou are **sonenta-a11y**, an accessibility specialist for internationalized\nprojects managed with Sonenta. You turn an accessibility audit into concrete,\nreviewable fixes, operating through the Sonenta MCP server's a11y tools.\n\n## Cost model — generate LOCALLY first (this is the default)\nYou ARE a capable language model already running in the developer's session\n(Claude Code or CI), and that compute is already paid for. So **you write the\na11y values yourself, with your own reasoning, and persist them with\n\\`set_a11y_variant\\`** — which is plain CRUD and costs **zero Sonenta AI\ncredits**. Do NOT reach for the server-side AI tools\n(\\`generate_a11y_variant\\` / \\`translate_a11y_variants\\`) by default: those bill\nSonenta AI credits and exist only as an explicit fallback for very large volumes\nor when the developer specifically asks for server-side generation.\n\n## Requirements\n- The Sonenta MCP server (\\`@sonenta/mcp\\`) must be configured with an \\`mcp:*\\`\n API key. Every operation goes through its tools — never call the HTTP API\n directly. If the a11y tools are missing, tell the user to add the server\n (\\`npx -y @sonenta/mcp\\`) and set \\`SONENTA_API_KEY\\`.\n- Tools:\n - \\`a11y_report\\` — full WCAG gap report (rollups + per-item gaps). READ-ONLY.\n - \\`list_a11y_gaps\\` — the actionable gap list, filterable by gap / surface /\n locale. READ-ONLY.\n - \\`set_a11y_variant\\` — **your primary write**: upsert one a11y variant for\n (key_uuid, language_code, surface) with a text value. CRUD, **0 AI credits**,\n stored as a draft.\n - \\`delete_a11y_variant\\` — clear one variant. CRUD, **0 AI credits**.\n - \\`a11y_estimate\\` — preview the AI-credit cost of the server-side fallback.\n - \\`generate_a11y_variant\\` / \\`translate_a11y_variants\\` — **fallback only**:\n server-side AI generation/translation that BILLS Sonenta AI credits. Use\n only for very large volumes or on explicit developer request.\n\n## The four a11y surfaces (what you write)\n- \\`aria_label\\` — a concise accessible NAME for an interactive element (button,\n icon, link). Derive it from the element's visible label and purpose.\n- \\`alt_text\\` — alternative text for an image. Derive it from the key's context /\n description; describe the image's MEANING, not \"image of…\".\n- \\`screen_reader\\` — verbose screen-reader-only text, for when the visible text\n is insufficient out of context.\n- \\`plain_language\\` — a simplified / clear-language (FALC) rewrite of the source.\n\na11y values are SEMANTIC (the accessible name / alt / simplified wording for\nassistive tech), not the visible UI string — keep them concise and meaningful.\n\n## Gap types and how you resolve each (locally, by yourself)\n- \\`a11y_variant_absent\\` — a required surface is missing in the source → compose\n it yourself and \\`set_a11y_variant\\` (source language).\n- \\`alt_missing\\` — an image key has no source alt_text → write \\`alt_text\\`.\n- \\`reading_level_high\\` — source copy is hard to read with no \\`plain_language\\`\n → write a simplified \\`plain_language\\` value.\n- \\`a11y_untranslated\\` — a source a11y variant exists but a locale lacks it →\n TRANSLATE it yourself and \\`set_a11y_variant\\` for that \\`language_code\\`.\n\n## Workflow\n1. **Scan.** Call \\`a11y_report\\` (pass \\`require_surface\\` for the surfaces the\n project needs, typically \\`aria_label\\` and \\`alt_text\\`). Summarize\n \\`total_gaps\\`, \\`by_gap\\`, \\`by_severity\\`, \\`by_surface\\`. Use\n \\`list_a11y_gaps\\` to pull the actionable items — each carries \\`key_uuid\\`,\n \\`key_name\\`, \\`namespace_slug\\`, \\`surface\\`, and \\`locale\\`.\n2. **Triage.** Group by type/severity — warnings first (\\`a11y_untranslated\\`,\n \\`alt_missing\\`), then info (\\`reading_level_high\\`, \\`a11y_variant_absent\\`).\n3. **Generate locally + write (DEFAULT path, 0 credits).** For each gap, compose\n the a11y value YOURSELF — reasoning over the key name, source value, any\n context/description, and the target surface — then persist it with\n \\`set_a11y_variant(key_uuid, language_code, surface, value)\\`. For\n \\`a11y_untranslated\\`, translate the source variant yourself into the target\n \\`language_code\\` and \\`set_a11y_variant\\`. Work through the gap list in\n sensible batches. This spends NO AI credits.\n4. **Server fallback (opt-in only).** If the volume is impractical to do locally,\n or the developer explicitly wants Sonenta server-side generation, FIRST call\n \\`a11y_estimate\\` (report \\`credits_required\\` vs \\`balance\\`; stop if not\n \\`sufficient\\`), confirm, THEN \\`generate_a11y_variant\\` /\n \\`translate_a11y_variants\\`.\n5. **Report.** Everything you write lands as a **draft** for human review — never\n present it as final. Summarize what you set (counts by surface / locale), what\n remains, and whether any credits were spent (0 on the local path).\n\n## Modes\n- **Interactive (Claude Code):** propose the fix plan, then write the local\n fixes; for the credit-billing fallback, show the estimate and confirm first.\n- **CI / headless:** run \\`a11y_report\\` and exit non-zero when \\`total_gaps\\` (or\n a chosen severity) exceeds the project threshold; optionally auto-write the\n local fixes. Only use the credit-billing fallback when explicitly authorized.\n\n## Guardrails\n- Default to LOCAL generation + \\`set_a11y_variant\\` (0 credits). Treat\n \\`generate_a11y_variant\\` / \\`translate_a11y_variants\\` as an explicit,\n estimated, opt-in fallback — never the silent default.\n- \\`set_a11y_variant\\` / \\`delete_a11y_variant\\` are CRUD and never spend AI\n credits; only \\`generate\\` / \\`translate\\` do. Always estimate before that\n fallback.\n- You FILL gaps — never overwrite a human-reviewed variant blindly.\n- Stay within the configured project; confirm it before any bulk operation.\n`;\n\nexport const AGENTS: Record<string, AgentDef> = {\n \"sonenta-a11y\": {\n name: \"sonenta-a11y\",\n summary:\n \"Accessibility (a11y) auditor + fixer: scans WCAG gaps and fixes them locally (0-credit set_a11y_variant), with server-side AI generation as an opt-in fallback.\",\n content: SONENTA_A11Y,\n },\n};\n\nexport function listAgents(): AgentDef[] {\n return Object.values(AGENTS);\n}\n\nexport function getAgent(name: string): AgentDef | undefined {\n return AGENTS[name];\n}\n\n/** Absolute path the agent definition is (or would be) written to. */\nexport function agentInstallPath(name: string, baseDir: string = process.cwd()): string {\n return resolve(baseDir, AGENTS_DIR, `${name}.md`);\n}\n\nexport async function isInstalled(name: string, baseDir: string = process.cwd()): Promise<boolean> {\n try {\n await fs.access(agentInstallPath(name, baseDir));\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Write a bundled agent into `<baseDir>/.claude/agents/<name>.md`.\n * Throws on an unknown agent or when the file exists and `force` is false.\n * Returns the absolute path written.\n */\nexport async function writeAgent(\n name: string,\n opts: { baseDir?: string; force?: boolean } = {},\n): Promise<string> {\n const agent = getAgent(name);\n if (!agent) {\n const known = Object.keys(AGENTS).join(\", \");\n throw new Error(`Unknown agent \"${name}\". Available: ${known}`);\n }\n const baseDir = opts.baseDir ?? process.cwd();\n const path = agentInstallPath(name, baseDir);\n if (!opts.force) {\n try {\n await fs.access(path);\n throw new Error(\n `${path} already exists. Pass --force to overwrite.`,\n );\n } catch (err) {\n // Re-throw the \"already exists\" error; an access() rejection means the\n // file is absent, which is the happy path.\n if (err instanceof Error && err.message.includes(\"already exists\")) throw err;\n }\n }\n await fs.mkdir(resolve(baseDir, AGENTS_DIR), { recursive: true });\n await fs.writeFile(path, agent.content, \"utf8\");\n return path;\n}\n","import { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { Command } from \"commander\";\n\nimport { type ApiContext, resolveContext } from \"../api.js\";\nimport { type FlatMap, sortDeep, unflatten } from \"../i18next_tree.js\";\nimport { getProjectInfo, listKeys } from \"../mcp.js\";\n\n/** language_code -> namespace_slug -> flat map of key -> value. */\ntype Collected = Record<string, Record<string, FlatMap>>;\n\nasync function collect(\n ctx: ApiContext,\n languages: string[],\n namespace?: string,\n): Promise<Collected> {\n const out: Collected = {};\n for (const lang of languages) {\n const items = await listKeys(ctx, { languageCode: lang, namespace });\n for (const it of items) {\n const tr = it.translations?.find((t) => t.language_code === lang);\n if (!tr || tr.value === \"\") continue;\n (out[lang] ??= {})[it.namespace_slug] ??= {};\n out[lang]![it.namespace_slug]![it.key_name] = tr.value;\n }\n }\n return out;\n}\n\nexport const exportCommand = new Command(\"export\")\n .description(\n \"Export Verbumia translations as i18next JSON. Flat dot-notation by \" +\n \"default (--nested for nested trees). Writes <out>/<lang>/<namespace>.json \" +\n \"with --out, otherwise prints { locale: { namespace: tree } } to stdout.\",\n )\n .option(\"--language <code>\", \"Restrict to a single language code\")\n .option(\"--namespace <slug>\", \"Restrict to a single namespace slug\")\n .option(\"--nested\", \"Emit nested JSON instead of flat dot-notation\", false)\n .option(\"--out <dir>\", \"Write files instead of printing to stdout\")\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: {\n language?: string;\n namespace?: string;\n nested: boolean;\n out?: string;\n host?: string;\n }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const languages = opts.language ? [opts.language] : (await getProjectInfo(ctx)).languages;\n const collected = await collect(ctx, languages, opts.namespace);\n const shape = (flat: FlatMap): unknown => (opts.nested ? sortDeep(unflatten(flat)) : sortDeep(flat));\n\n if (opts.out) {\n let files = 0;\n for (const [lang, nss] of Object.entries(collected)) {\n for (const [ns, flat] of Object.entries(nss)) {\n const dir = join(opts.out, lang);\n await fs.mkdir(dir, { recursive: true });\n const p = join(dir, `${ns}.json`);\n await fs.writeFile(p, JSON.stringify(shape(flat), null, 2) + \"\\n\", \"utf8\");\n console.log(` ${p} ${Object.keys(flat).length} keys`);\n files++;\n }\n }\n console.log(`exported ${files} file(s)`);\n return;\n }\n\n const tree: Record<string, Record<string, unknown>> = {};\n for (const [lang, nss] of Object.entries(collected)) {\n tree[lang] = {};\n for (const [ns, flat] of Object.entries(nss)) tree[lang]![ns] = shape(flat);\n }\n process.stdout.write(JSON.stringify(tree, null, 2) + \"\\n\");\n },\n );\n","import { promises as fs } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\n\n/**\n * Project-local config — `sonenta.config.json` at the repo root.\n *\n * Layout (V1, intentionally minimal):\n *\n * {\n * \"host\": \"https://api.sonenta.com\",\n * \"project_uuid\": \"069fc15d-…\",\n * \"version_slug\": \"main\"\n * }\n *\n * `host` may be omitted — commands then fall back to the user-level\n * credentials default. `version_slug` defaults to \"main\" when omitted.\n *\n * Back-compat: the legacy filename `verbumia.config.json` is still READ\n * (with a one-time deprecation warning) when no `sonenta.config.json` is\n * found, so existing projects keep working. New configs are written as\n * `sonenta.config.json`.\n */\n\nexport interface ProjectConfig {\n host?: string;\n project_uuid?: string;\n version_slug?: string;\n}\n\nexport const CONFIG_FILENAME = \"sonenta.config.json\";\nexport const LEGACY_CONFIG_FILENAME = \"verbumia.config.json\";\n\nlet warnedLegacy = false;\n\nexport async function findConfigPath(startDir: string): Promise<string | null> {\n let dir = resolve(startDir);\n // Walk up until we hit a config or the filesystem root. At each level the\n // canonical name wins over the deprecated one.\n while (true) {\n for (const name of [CONFIG_FILENAME, LEGACY_CONFIG_FILENAME]) {\n const candidate = resolve(dir, name);\n try {\n await fs.access(candidate);\n if (name === LEGACY_CONFIG_FILENAME && !warnedLegacy) {\n warnedLegacy = true;\n process.emitWarning(\n `${LEGACY_CONFIG_FILENAME} is deprecated — rename it to ${CONFIG_FILENAME}. ` +\n `The legacy name still works for now.`,\n { type: \"DeprecationWarning\" },\n );\n }\n return candidate;\n } catch {\n // Continue to the next name / parent dir.\n }\n }\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\nexport async function readConfig(startDir: string = process.cwd()): Promise<{\n path: string | null;\n config: ProjectConfig;\n}> {\n const path = await findConfigPath(startDir);\n if (!path) return { path: null, config: {} };\n const raw = await fs.readFile(path, \"utf8\");\n const parsed = JSON.parse(raw) as ProjectConfig;\n return { path, config: parsed };\n}\n\nexport async function writeConfig(\n config: ProjectConfig,\n targetDir: string = process.cwd(),\n): Promise<string> {\n // Always write the canonical filename.\n const path = resolve(targetDir, CONFIG_FILENAME);\n await fs.writeFile(path, JSON.stringify(config, null, 2) + \"\\n\", \"utf8\");\n return path;\n}\n","import { promises as fs } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\n/**\n * Per-user credentials store.\n *\n * Lives at `~/.verbumia/credentials` with file mode 0600. The shape is a\n * keyed map of host → entry, so a single user can have multiple accounts\n * (cloud + self-hosted dev + self-hosted prod) without rewriting the file\n * each time they switch hosts.\n *\n * {\n * \"default\": \"https://api.sonenta.com\",\n * \"hosts\": {\n * \"https://api.sonenta.com\": { \"api_key\": \"vrb_live_…\", \"user_email\": \"...\" },\n * \"https://api.dev.verbumia.ca\":{ \"api_key\": \"vrb_live_…\" }\n * }\n * }\n *\n * The `default` host is what `sonenta` commands target when neither the\n * project's `sonenta.config.json` nor a `--host` flag override it.\n */\n\nexport interface CredentialsEntry {\n api_key: string;\n user_email?: string;\n}\n\nexport interface CredentialsFile {\n default?: string;\n hosts: Record<string, CredentialsEntry>;\n}\n\nexport const credentialsDir = (): string => join(homedir(), \".verbumia\");\nexport const credentialsPath = (): string => join(credentialsDir(), \"credentials\");\n\nconst EMPTY: CredentialsFile = { hosts: {} };\n\nexport async function readCredentials(): Promise<CredentialsFile> {\n try {\n const raw = await fs.readFile(credentialsPath(), \"utf8\");\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\" || !parsed.hosts) {\n return EMPTY;\n }\n return parsed as CredentialsFile;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException)?.code === \"ENOENT\") return { hosts: {} };\n throw err;\n }\n}\n\nexport async function writeCredentials(creds: CredentialsFile): Promise<void> {\n const dir = credentialsDir();\n const path = credentialsPath();\n await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n // Write to a temp file first to keep the original intact if the process\n // crashes mid-write, then rename atomically.\n const tmp = `${path}.tmp`;\n await fs.writeFile(tmp, JSON.stringify(creds, null, 2) + \"\\n\", { mode: 0o600 });\n await fs.rename(tmp, path);\n // chmod again in case the umask widened it on creation\n await fs.chmod(path, 0o600);\n await fs.chmod(dir, 0o700).catch(() => {});\n}\n\nexport async function setHostEntry(\n host: string,\n entry: CredentialsEntry,\n options: { makeDefault?: boolean } = {},\n): Promise<void> {\n const creds = await readCredentials();\n creds.hosts[host] = entry;\n if (options.makeDefault || !creds.default) creds.default = host;\n await writeCredentials(creds);\n}\n\nexport async function removeHost(host: string): Promise<boolean> {\n const creds = await readCredentials();\n if (!(host in creds.hosts)) return false;\n delete creds.hosts[host];\n if (creds.default === host) {\n const remaining = Object.keys(creds.hosts);\n creds.default = remaining[0];\n }\n await writeCredentials(creds);\n return true;\n}\n\nexport function resolveHostEntry(\n creds: CredentialsFile,\n hostOverride?: string,\n): { host: string; entry: CredentialsEntry } | null {\n const host = hostOverride ?? creds.default;\n if (!host) return null;\n const entry = creds.hosts[host];\n if (!entry) return null;\n return { host, entry };\n}\n","import { readConfig } from \"./config.js\";\nimport {\n type CredentialsEntry,\n readCredentials,\n resolveHostEntry,\n} from \"./credentials.js\";\n\n/**\n * Resolved request context for a CLI command:\n * - host: which Verbumia API to talk to\n * - apiKey: the bearer ApiKey token (resolved from credentials)\n * - projectUuid: optional, from project config\n * - versionSlug: defaults to \"main\"\n */\nexport interface ApiContext {\n host: string;\n apiKey: string;\n projectUuid?: string;\n versionSlug: string;\n}\n\nexport interface ResolveOptions {\n hostOverride?: string;\n cwd?: string;\n}\n\nexport async function resolveContext(opts: ResolveOptions = {}): Promise<ApiContext> {\n const { config } = await readConfig(opts.cwd ?? process.cwd());\n const creds = await readCredentials();\n const host = opts.hostOverride ?? config.host ?? creds.default;\n if (!host) {\n throw new Error(\n \"No host configured. Run `sonenta login --host <url>` or add `host` to sonenta.config.json.\",\n );\n }\n\n // Auth resolution order (first wins):\n // 1. SONENTA_TOKEN (or legacy VERBUMIA_TOKEN) env var — highest priority for CI / scripts\n // 2. ~/.verbumia/credentials entry for this host\n // The env-var path lets users run a one-off command in CI without\n // touching the credentials file or typing the token interactively.\n const envToken = process.env.SONENTA_TOKEN ?? process.env.VERBUMIA_TOKEN;\n let apiKey: string | undefined = envToken && envToken.trim() ? envToken.trim() : undefined;\n if (!apiKey) {\n const resolved = resolveHostEntry(creds, host);\n if (!resolved) {\n throw new Error(\n `No credentials for host ${host}. Set SONENTA_TOKEN or run \\`sonenta login --host ${host}\\`.`,\n );\n }\n apiKey = resolved.entry.api_key;\n }\n\n return {\n host,\n apiKey,\n projectUuid: config.project_uuid,\n versionSlug: config.version_slug ?? \"main\",\n };\n}\n\nexport async function apiRequest<T = unknown>(\n ctx: ApiContext,\n path: string,\n init: RequestInit = {},\n): Promise<T> {\n const url = `${ctx.host.replace(/\\/+$/, \"\")}${path}`;\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `ApiKey ${ctx.apiKey}`);\n if (init.body && !headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n const res = await fetch(url, { ...init, headers });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`HTTP ${res.status} ${res.statusText} on ${path}: ${text.slice(0, 300)}`);\n }\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n}\n","/**\n * i18next tree <-> flat-map helpers.\n *\n * Verbumia stores keys as flat dot-notation (`hero.title`). i18next files on\n * disk are commonly nested (`{hero:{title:..}}`). The one-shot import endpoint\n * accepts BOTH, so `import` passes trees through untouched — these helpers are\n * for the OUTPUT side (export/snapshot) where we choose flat or nested.\n */\n\nexport type FlatMap = Record<string, string>;\nexport type Tree = Record<string, unknown>;\n\n/** Expand dot-notation flat keys into a nested tree. */\nexport function unflatten(flat: FlatMap, sep = \".\"): Tree {\n const root: Tree = {};\n for (const [k, v] of Object.entries(flat)) {\n const parts = k.split(sep);\n let node: Tree = root;\n for (let i = 0; i < parts.length - 1; i++) {\n const p = parts[i]!;\n const existing = node[p];\n if (typeof existing !== \"object\" || existing === null) node[p] = {};\n node = node[p] as Tree;\n }\n node[parts[parts.length - 1]!] = v;\n }\n return root;\n}\n\n/** Flatten a nested tree to dot-notation (string leaves only). */\nexport function flatten(tree: Tree, sep = \".\"): FlatMap {\n const out: FlatMap = {};\n const walk = (node: unknown, prefix: string): void => {\n if (!node || typeof node !== \"object\" || Array.isArray(node)) return;\n for (const [k, v] of Object.entries(node as Tree)) {\n const key = prefix ? `${prefix}${sep}${k}` : k;\n if (v && typeof v === \"object\" && !Array.isArray(v)) walk(v, key);\n else if (typeof v === \"string\") out[key] = v;\n }\n };\n walk(tree, \"\");\n return out;\n}\n\n/** Recursively sort object keys for deterministic, diff-friendly output. */\nexport function sortDeep<T>(value: T): T {\n if (Array.isArray(value)) return value.map((v) => sortDeep(v)) as unknown as T;\n if (value && typeof value === \"object\") {\n const src = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const k of Object.keys(src).sort((a, b) => a.localeCompare(b))) out[k] = sortDeep(src[k]);\n return out as T;\n }\n return value;\n}\n","/**\n * MCP-surface client helpers.\n *\n * The whole CLI talks to the metered, key-addressable MCP surface\n * `/v1/mcp/projects/{project_id}/...` (auth = an API key carrying the `mcp:*`\n * scope). That surface addresses keys/namespaces/languages by NAME (no uuids),\n * exposes bulk + one-shot endpoints, and is the contract-blessed automation\n * entrypoint. These helpers wrap the endpoints the commands consume.\n */\n\nimport { type ApiContext, apiRequest } from \"./api.js\";\n\nexport function requireProject(ctx: ApiContext): string {\n if (!ctx.projectUuid) {\n throw new Error(\n \"no project configured — run `sonenta init --project <uuid>` \" +\n \"(or set project_uuid in sonenta.config.json).\",\n );\n }\n return ctx.projectUuid;\n}\n\nfunction projectBase(ctx: ApiContext): string {\n return `/v1/mcp/projects/${requireProject(ctx)}`;\n}\n\n// ---- projects ------------------------------------------------------------\n\nexport interface ProjectSummary {\n uuid: string;\n name?: string;\n slug?: string;\n source_language?: string;\n}\n\nexport async function listProjects(ctx: ApiContext, limit = 200): Promise<ProjectSummary[]> {\n const data = await apiRequest<{ items: ProjectSummary[] }>(\n ctx,\n `/v1/mcp/projects?limit=${limit}`,\n );\n return data.items ?? [];\n}\n\nexport interface ProjectInfo {\n source_language: string;\n languages: string[];\n namespaces: string[];\n}\n\n/** Normalises get_project_info into plain code/slug lists (shape-tolerant). */\nexport async function getProjectInfo(ctx: ApiContext): Promise<ProjectInfo> {\n const d = await apiRequest<Record<string, unknown>>(ctx, projectBase(ctx));\n const src =\n typeof d.source_language === \"string\"\n ? d.source_language\n : (d.source_language as { code?: string })?.code ?? \"\";\n const langs = Array.isArray(d.languages)\n ? (d.languages as unknown[]).map((l) =>\n typeof l === \"string\" ? l : ((l as { code?: string }).code ?? \"\"),\n )\n : [];\n const ns = Array.isArray(d.namespaces)\n ? (d.namespaces as unknown[]).map((n) =>\n typeof n === \"string\" ? n : ((n as { slug?: string }).slug ?? \"\"),\n )\n : [];\n return {\n source_language: src,\n languages: langs.filter(Boolean),\n namespaces: ns.filter(Boolean),\n };\n}\n\n// ---- keys (paginated list) ----------------------------------------------\n\nexport interface KeyTranslation {\n language_code: string;\n value: string;\n status: string;\n}\n\nexport interface KeyItem {\n key_name: string;\n namespace_slug: string;\n source_value: string | null;\n translations?: KeyTranslation[];\n}\n\nexport async function listKeys(\n ctx: ApiContext,\n opts: { languageCode?: string; namespace?: string } = {},\n): Promise<KeyItem[]> {\n const out: KeyItem[] = [];\n let cursor: string | null = null;\n do {\n const params = new URLSearchParams({ limit: \"200\" });\n if (opts.languageCode) params.set(\"language_code\", opts.languageCode);\n if (opts.namespace) params.set(\"namespace\", opts.namespace);\n if (cursor) params.set(\"cursor\", cursor);\n const page = await apiRequest<{ items: KeyItem[]; cursor_next: string | null }>(\n ctx,\n `${projectBase(ctx)}/keys?${params.toString()}`,\n );\n out.push(...(page.items ?? []));\n cursor = page.cursor_next ?? null;\n } while (cursor);\n return out;\n}\n\n// ---- i18next one-shot import --------------------------------------------\n\nexport type I18nextTree = Record<string, unknown>;\n\nexport interface ImportNamespaceUnit {\n namespace: string;\n translations: Record<string, I18nextTree>; // language_code -> i18next tree (nested or flat)\n}\n\nexport interface ImportBody {\n namespaces: ImportNamespaceUnit[];\n version?: string;\n status?: \"draft\" | \"translated\";\n}\n\nexport interface ImportBundleReport {\n project_uuid: string;\n version_slug: string;\n keys_created: number;\n keys_reused: number;\n translations_created: number;\n translations_updated: number;\n translations_unchanged: number;\n plural_keys_marked: number;\n units?: unknown[];\n errors?: { namespace: string; language_code: string; code: string }[];\n glossary_violation_count?: number;\n glossary_violations?: {\n namespace: string;\n language_code: string;\n key: string;\n rule_type: string;\n term: string;\n matched_text?: string;\n message?: string;\n }[];\n}\n\nexport async function importBundle(ctx: ApiContext, body: ImportBody): Promise<ImportBundleReport> {\n return apiRequest<ImportBundleReport>(ctx, `${projectBase(ctx)}/i18next/import`, {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n}\n\n// ---- CDN releases (publish) ---------------------------------------------\n\nexport interface PublishCdnBody {\n language_code?: string;\n namespace?: string;\n version_slug?: string;\n}\n\nexport async function publishCdn(ctx: ApiContext, body: PublishCdnBody): Promise<unknown> {\n return apiRequest(ctx, `${projectBase(ctx)}/cdn/releases`, {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n}\n\n// ---- formatting ----------------------------------------------------------\n\n/** Human-readable lines for an ImportBundleReport (created/updated/unchanged). */\nexport function summariseImport(r: ImportBundleReport): string[] {\n const lines = [\n `keys: ${r.keys_created} created, ${r.keys_reused} reused`,\n `translations: ${r.translations_created} created, ${r.translations_updated} updated, ${r.translations_unchanged} unchanged`,\n ];\n if (r.plural_keys_marked) lines.push(`plural keys: ${r.plural_keys_marked} marked`);\n if (r.errors?.length) {\n lines.push(`errors: ${r.errors.length}`);\n for (const e of r.errors) lines.push(` ! ${e.namespace}/${e.language_code}: ${e.code}`);\n }\n if (r.glossary_violations?.length) {\n lines.push(`glossary: ${r.glossary_violations.length} violation(s)`);\n for (const g of r.glossary_violations) {\n lines.push(` ⚠ ${g.namespace}/${g.language_code} ${g.key}: ${g.rule_type} \"${g.term}\"`);\n }\n }\n return lines;\n}\n","import { promises as fs } from \"node:fs\";\nimport { basename, dirname } from \"node:path\";\n\nimport { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { type I18nextTree, type ImportBody, importBundle, summariseImport } from \"../mcp.js\";\n\n/**\n * Resolve (language, namespace) for a file.\n * - explicit --language / --namespace always win;\n * - otherwise infer from the i18next layout `<lang>/<namespace>.json`\n * (parent dir = language, filename stem = namespace);\n * - a bare `<lang>.json` (no language dir) uses the stem as the language and\n * REQUIRES --namespace.\n */\nexport function resolveLangNs(\n filePath: string,\n optLang?: string,\n optNs?: string,\n): { lang: string; ns: string } {\n const stem = basename(filePath).replace(/\\.json$/i, \"\");\n const parent = basename(dirname(filePath));\n const hasLangDir = parent !== \"\" && parent !== \".\" && parent !== \"locales\";\n const lang = optLang ?? (hasLangDir ? parent : stem);\n const ns = optNs ?? (hasLangDir ? stem : undefined);\n if (!lang) throw new Error(`could not infer a language for ${filePath} — pass --language`);\n if (!ns) {\n throw new Error(\n `could not infer a namespace for ${filePath} — pass --namespace, ` +\n \"or lay files out as <lang>/<namespace>.json\",\n );\n }\n return { lang, ns };\n}\n\nasync function readTree(filePath: string): Promise<I18nextTree> {\n const parsed = JSON.parse(await fs.readFile(filePath, \"utf8\"));\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`${filePath} is not a JSON object`);\n }\n return parsed as I18nextTree;\n}\n\nfunction countLeaves(tree: I18nextTree): number {\n let n = 0;\n for (const v of Object.values(tree)) {\n if (v && typeof v === \"object\" && !Array.isArray(v)) n += countLeaves(v as I18nextTree);\n else n += 1;\n }\n return n;\n}\n\nexport const importCommand = new Command(\"import\")\n .description(\n \"Import i18next JSON file(s) into Verbumia in ONE call — creates missing \" +\n \"keys and upserts translations (idempotent). Accepts nested or flat JSON. \" +\n \"Language/namespace are inferred from the path (<lang>/<namespace>.json) \" +\n \"or forced with --language / --namespace.\",\n )\n .argument(\"<files...>\", \"i18next JSON file(s), e.g. locales/fr/common.json or fr.json\")\n .option(\"--language <code>\", \"Force the language code for every file\")\n .option(\"--namespace <slug>\", \"Force the namespace slug for every file\")\n .option(\"--status <status>\", \"draft | translated (default: translated)\")\n .option(\"--version <slug>\", \"Target version slug (default: production version)\")\n .option(\"--dry-run\", \"Print what would be imported without sending\", false)\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (\n files: string[],\n opts: {\n language?: string;\n namespace?: string;\n status?: string;\n version?: string;\n dryRun: boolean;\n host?: string;\n },\n ) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n\n // namespace -> language_code -> tree\n const byNs = new Map<string, Record<string, I18nextTree>>();\n let totalLeaves = 0;\n for (const f of files) {\n const { lang, ns } = resolveLangNs(f, opts.language, opts.namespace);\n const tree = await readTree(f);\n totalLeaves += countLeaves(tree);\n const langs = byNs.get(ns) ?? {};\n if (langs[lang]) {\n throw new Error(`two input files map to namespace=${ns} language=${lang} — merge them first`);\n }\n langs[lang] = tree;\n byNs.set(ns, langs);\n console.log(` ${f} -> ${ns} / ${lang}`);\n }\n\n const body: ImportBody = {\n namespaces: [...byNs.entries()].map(([namespace, translations]) => ({\n namespace,\n translations,\n })),\n };\n if (opts.status === \"draft\" || opts.status === \"translated\") body.status = opts.status;\n if (opts.version) body.version = opts.version;\n\n if (opts.dryRun) {\n console.log(\n `\\n(dry-run) would import ${totalLeaves} value(s) across ${body.namespaces.length} ` +\n \"namespace(s); nothing sent.\",\n );\n return;\n }\n\n const report = await importBundle(ctx, body);\n console.log(\"\");\n for (const line of summariseImport(report)) console.log(line);\n if (report.errors?.length || report.glossary_violations?.length) process.exitCode = 1;\n },\n );\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nimport { Command } from \"commander\";\n\nimport { CONFIG_FILENAME, writeConfig } from \"../config.js\";\n\nexport const initCommand = new Command(\"init\")\n .description(\"Scaffold a sonenta.config.json in the current directory.\")\n .option(\"--host <url>\", \"API base URL\", \"https://api.sonenta.com\")\n .option(\"--project <uuid>\", \"Project UUID\")\n .option(\"--version <slug>\", \"Version slug (default: main)\", \"main\")\n .option(\"--force\", \"Overwrite an existing sonenta.config.json\", false)\n .action(\n async (opts: { host: string; project?: string; version: string; force: boolean }) => {\n const path = resolve(process.cwd(), CONFIG_FILENAME);\n if (existsSync(path) && !opts.force) {\n console.error(\n `${CONFIG_FILENAME} already exists at ${path}. Pass --force to overwrite.`,\n );\n process.exit(1);\n }\n const written = await writeConfig({\n host: opts.host,\n project_uuid: opts.project,\n version_slug: opts.version,\n });\n console.log(`Wrote ${written}`);\n if (!opts.project) {\n console.log(\n \"Tip: pass --project <uuid> to bind this directory to a specific project \" +\n \"(or edit project_uuid in the file later).\",\n );\n }\n },\n );\n","import { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { listKeys } from \"../mcp.js\";\n\nexport const keysCommand = new Command(\"keys\")\n .description(\"Inspect translation keys for the current project.\")\n .addCommand(\n new Command(\"list\")\n .description(\"List keys for the configured project (addressed by namespace slug + key name).\")\n .option(\"--namespace <slug>\", \"Filter by namespace slug\")\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(async (opts: { namespace?: string; host?: string }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const items = await listKeys(ctx, { namespace: opts.namespace });\n console.log(`total: ${items.length}`);\n for (const k of items) console.log(` ${k.namespace_slug}/${k.key_name}`);\n }),\n );\n","import { Command } from \"commander\";\n\nimport { setHostEntry } from \"../credentials.js\";\nimport { promptLine, promptSecret } from \"../prompt.js\";\n\nconst TOKEN_REGEX = /^vrb_[a-z]+_[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/;\n\nexport const loginCommand = new Command(\"login\")\n .description(\n \"Store an API key for a host. Token resolution order: --token, \" +\n \"SONENTA_TOKEN env, then interactive prompt (TTY only).\",\n )\n .option(\"--host <url>\", \"API base URL\", \"https://api.sonenta.com\")\n .option(\"--token <vrb_live_…>\", \"API key token (prefix.secret form)\")\n .option(\"--email <email>\", \"User email associated with the token (optional)\")\n .option(\"--default\", \"Set this host as the default for future commands\", false)\n .action(async (opts: { host: string; token?: string; email?: string; default?: boolean }) => {\n let host = opts.host;\n if (!host && process.stdin.isTTY) {\n host = (await promptLine(\"Host (default https://api.sonenta.com): \")) || \"https://api.sonenta.com\";\n }\n let token = opts.token ?? (process.env.SONENTA_TOKEN ?? process.env.VERBUMIA_TOKEN) ?? \"\";\n if (!token && process.stdin.isTTY) {\n token = await promptSecret(`API token for ${host}: `);\n }\n if (!token) {\n console.error(\n \"sonenta login: token required. Pass --token, set SONENTA_TOKEN, or run from a TTY for the interactive prompt.\",\n );\n process.exit(1);\n }\n if (!TOKEN_REGEX.test(token)) {\n console.error(\n \"sonenta login: token shape doesn't match `vrb_<env>_<prefix>.<secret>`. \" +\n \"Generate one in the dashboard at Org Settings → API Keys.\",\n );\n process.exit(1);\n }\n await setHostEntry(\n host,\n { api_key: token, user_email: opts.email },\n { makeDefault: opts.default },\n );\n console.log(`Stored credentials for ${host}.`);\n });\n","import { createInterface } from \"node:readline\";\n\n/**\n * Read a line from stdin. Used for interactive prompts when --token / --host\n * aren't passed on the CLI. Returns \"\" if stdin isn't a TTY (so tests + piped\n * usage don't hang waiting for input that will never arrive).\n */\nexport async function promptLine(message: string): Promise<string> {\n if (!process.stdin.isTTY) return \"\";\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n return await new Promise<string>((resolve) => {\n rl.question(message, (answer) => resolve(answer.trim()));\n });\n } finally {\n rl.close();\n }\n}\n\nconst CTRL_C = 0x03;\nconst BACKSPACE = 0x08;\nconst DEL = 0x7f;\nconst CR = 0x0d;\nconst LF = 0x0a;\n\n/**\n * Same as promptLine but masks each echoed character with `*`. If stdin\n * isn't a TTY we return \"\" rather than echoing the secret.\n */\nexport async function promptSecret(message: string): Promise<string> {\n if (!process.stdin.isTTY) return \"\";\n process.stdout.write(message);\n process.stdin.setRawMode(true);\n process.stdin.resume();\n return await new Promise<string>((resolve) => {\n let buffer = \"\";\n const onData = (chunk: Buffer): void => {\n for (const byte of chunk) {\n if (byte === CR || byte === LF) {\n process.stdout.write(\"\\n\");\n process.stdin.removeListener(\"data\", onData);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n resolve(buffer);\n return;\n }\n if (byte === CTRL_C) {\n process.stdout.write(\"\\n\");\n process.stdin.removeListener(\"data\", onData);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n process.exit(130);\n }\n if (byte === BACKSPACE || byte === DEL) {\n if (buffer.length > 0) {\n buffer = buffer.slice(0, -1);\n process.stdout.write(\"\\b \\b\");\n }\n continue;\n }\n buffer += String.fromCharCode(byte);\n process.stdout.write(\"*\");\n }\n };\n process.stdin.on(\"data\", onData);\n });\n}\n","import { Command } from \"commander\";\n\nimport { readCredentials, removeHost } from \"../credentials.js\";\n\nexport const logoutCommand = new Command(\"logout\")\n .description(\"Remove stored credentials for a host (default: the current default host).\")\n .option(\"--host <url>\", \"Host to forget. Omit to forget the current default.\")\n .action(async (opts: { host?: string }) => {\n const creds = await readCredentials();\n const target = opts.host ?? creds.default;\n if (!target) {\n console.log(\"Nothing to forget — no credentials stored.\");\n return;\n }\n const removed = await removeHost(target);\n if (!removed) {\n console.log(`No credentials stored for ${target}.`);\n return;\n }\n console.log(`Forgot credentials for ${target}.`);\n });\n","import { Command } from \"commander\";\n\nimport { apiRequest, resolveContext } from \"../api.js\";\n\ninterface MissingKey {\n uuid: string;\n namespace_slug: string;\n language_code: string;\n key: string;\n source_value: string | null;\n count: number;\n status: string;\n first_seen: string;\n last_seen: string;\n}\n\ninterface MissingKeysPage {\n items: MissingKey[];\n cursor_next: string | null;\n total: number;\n}\n\nexport const missingCommand = new Command(\"missing\")\n .description(\n \"List runtime-detected missing keys for the configured project. Requires \" +\n \"the API key to carry the `mcp:*` scope.\",\n )\n .option(\"--namespace <slug>\", \"Filter by namespace slug\")\n .option(\"--language <code>\", \"Filter by language code\")\n .option(\"--status <state>\", \"Filter by status (open|resolved|...)\")\n .option(\"--limit <n>\", \"Page size (1-200, default 50)\", \"50\")\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: {\n namespace?: string;\n language?: string;\n status?: string;\n limit: string;\n host?: string;\n }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n if (!ctx.projectUuid) {\n console.error(\n \"sonenta missing: no project_uuid configured. Run `sonenta init --project <uuid>`.\",\n );\n process.exit(1);\n }\n const params = new URLSearchParams();\n params.set(\"limit\", opts.limit);\n if (opts.namespace) params.set(\"namespace\", opts.namespace);\n if (opts.language) params.set(\"language_code\", opts.language);\n if (opts.status) params.set(\"status\", opts.status);\n const page = await apiRequest<MissingKeysPage>(\n ctx,\n `/v1/mcp/projects/${ctx.projectUuid}/missing-keys?${params.toString()}`,\n );\n console.log(`total: ${page.total}`);\n for (const m of page.items) {\n const sample = m.source_value ? ` ⟶ \"${m.source_value}\"` : \"\";\n console.log(\n ` ${m.namespace_slug}/${m.key} (${m.language_code}, count=${m.count}, ${m.status})${sample}`,\n );\n }\n if (page.cursor_next) {\n console.log(`(more — re-run with --cursor ${page.cursor_next})`);\n }\n },\n );\n","import { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { listProjects } from \"../mcp.js\";\n\nexport const projectsCommand = new Command(\"projects\")\n .description(\"Inspect Verbumia projects accessible to your API key.\")\n .addCommand(\n new Command(\"list\")\n .description(\"List the projects this API key can reach.\")\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(async (opts: { host?: string }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const items = await listProjects(ctx);\n if (items.length === 0) {\n console.log(\"No projects visible to this key (scoped or revoked?).\");\n return;\n }\n for (const p of items) {\n const slug = p.slug ? ` ${p.slug}` : \"\";\n const src = p.source_language ? ` src=${p.source_language}` : \"\";\n console.log(` ${p.uuid}${slug} ${p.name ?? \"\"}${src}`);\n }\n }),\n );\n","import { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { DEFAULT_LOCALES_DIR, type FlatTranslations, writeLocaleFile } from \"../locales.js\";\nimport { getProjectInfo, listKeys } from \"../mcp.js\";\n\nexport const pullCommand = new Command(\"pull\")\n .description(\n \"Pull translations from Verbumia into locales/<lang>/<namespace>.json \" +\n \"(flat dot-notation). Overwrites local files — pair with `git status`.\",\n )\n .option(\"--language <code>\", \"Restrict to a single language code\")\n .option(\"--namespace <slug>\", \"Restrict to a single namespace slug\")\n .option(\"--dest <dir>\", \"Output directory\", DEFAULT_LOCALES_DIR)\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: { language?: string; namespace?: string; dest: string; host?: string }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n let languages: string[];\n if (opts.language) {\n languages = [opts.language];\n } else {\n languages = (await getProjectInfo(ctx)).languages;\n if (languages.length === 0) {\n console.error(\"sonenta pull: the project reports no languages.\");\n process.exit(1);\n }\n }\n\n let totalKeys = 0;\n let totalFiles = 0;\n for (const lang of languages) {\n const items = await listKeys(ctx, { languageCode: lang, namespace: opts.namespace });\n const byNs = new Map<string, FlatTranslations>();\n for (const it of items) {\n const tr = it.translations?.find((t) => t.language_code === lang);\n if (!tr || tr.value === \"\") continue;\n const map = byNs.get(it.namespace_slug) ?? {};\n map[it.key_name] = tr.value;\n byNs.set(it.namespace_slug, map);\n }\n for (const [ns, map] of byNs) {\n const path = await writeLocaleFile(opts.dest, lang, ns, map);\n totalKeys += Object.keys(map).length;\n totalFiles++;\n console.log(` ${path} ${Object.keys(map).length} keys`);\n }\n }\n console.log(`pulled ${totalKeys} translation(s) across ${totalFiles} file(s)`);\n },\n );\n","import { promises as fs } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\n\n/**\n * On-disk locales layout. V1 is flat: one JSON per (lang, namespace) under\n * the configured locales directory:\n *\n * locales/\n * en/\n * common.json // { \"hello.title\": \"Hello\", ... }\n * errors.json\n * fr/\n * common.json\n *\n * Keys inside each file are flat dot-notation, NOT nested objects. This\n * matches the editor surface 1:1 and keeps push/pull idempotent.\n */\n\nexport const DEFAULT_LOCALES_DIR = \"locales\";\n\nexport type FlatTranslations = Record<string, string>;\n\nexport async function listLocaleFiles(\n rootDir: string,\n): Promise<{ lang: string; namespace: string; path: string }[]> {\n const root = resolve(rootDir);\n let langDirs: string[];\n try {\n langDirs = await fs.readdir(root);\n } catch {\n return [];\n }\n const out: { lang: string; namespace: string; path: string }[] = [];\n for (const lang of langDirs) {\n const langPath = join(root, lang);\n let stat;\n try {\n stat = await fs.stat(langPath);\n } catch {\n continue;\n }\n if (!stat.isDirectory()) continue;\n const files = await fs.readdir(langPath);\n for (const f of files) {\n if (!f.endsWith(\".json\")) continue;\n out.push({ lang, namespace: f.replace(/\\.json$/, \"\"), path: join(langPath, f) });\n }\n }\n return out;\n}\n\nexport async function readLocaleFile(path: string): Promise<FlatTranslations> {\n const raw = await fs.readFile(path, \"utf8\");\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`${path} is not a flat object`);\n }\n const out: FlatTranslations = {};\n for (const [k, v] of Object.entries(parsed)) {\n if (typeof v !== \"string\") {\n throw new Error(`${path}: key \"${k}\" is not a string (V1 flat layout only)`);\n }\n out[k] = v;\n }\n return out;\n}\n\nexport async function writeLocaleFile(\n rootDir: string,\n lang: string,\n namespace: string,\n values: FlatTranslations,\n): Promise<string> {\n const dir = join(rootDir, lang);\n await fs.mkdir(dir, { recursive: true });\n const path = join(dir, `${namespace}.json`);\n // Sort keys for deterministic diffs.\n const sorted = Object.fromEntries(\n Object.entries(values).sort(([a], [b]) => a.localeCompare(b)),\n );\n await fs.writeFile(path, JSON.stringify(sorted, null, 2) + \"\\n\", \"utf8\");\n return path;\n}\n\nexport interface DiffResult {\n added: string[]; // local-only — push will create\n removed: string[]; // remote-only — push leaves alone (V1 doesn't delete)\n changed: { key: string; local: string; remote: string }[];\n unchanged: number;\n}\n\nexport function diffFlat(local: FlatTranslations, remote: FlatTranslations): DiffResult {\n const added: string[] = [];\n const removed: string[] = [];\n const changed: { key: string; local: string; remote: string }[] = [];\n let unchanged = 0;\n\n for (const [k, v] of Object.entries(local)) {\n if (!(k in remote)) {\n added.push(k);\n } else if (remote[k] !== v) {\n changed.push({ key: k, local: v, remote: remote[k]! });\n } else {\n unchanged++;\n }\n }\n for (const k of Object.keys(remote)) {\n if (!(k in local)) removed.push(k);\n }\n return { added, removed, changed, unchanged };\n}\n","import { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { DEFAULT_LOCALES_DIR, listLocaleFiles, readLocaleFile } from \"../locales.js\";\nimport { type ImportBody, importBundle, summariseImport } from \"../mcp.js\";\n\nexport const pushCommand = new Command(\"push\")\n .description(\n \"Push the whole local locales/ tree to Verbumia in ONE import call — \" +\n \"creates missing keys and upserts translations (idempotent). Reads \" +\n \"locales/<lang>/<namespace>.json (flat dot-notation).\",\n )\n .option(\"--language <code>\", \"Restrict to a single language code\")\n .option(\"--namespace <slug>\", \"Restrict to a single namespace slug\")\n .option(\"--src <dir>\", \"Locales directory\", DEFAULT_LOCALES_DIR)\n .option(\"--status <status>\", \"draft | translated (default: translated)\")\n .option(\"--version <slug>\", \"Target version slug (default: production version)\")\n .option(\"--dry-run\", \"Print what would be pushed without sending\", false)\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: {\n language?: string;\n namespace?: string;\n src: string;\n status?: string;\n version?: string;\n dryRun: boolean;\n host?: string;\n }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const files = (await listLocaleFiles(opts.src)).filter((f) => {\n if (opts.language && f.lang !== opts.language) return false;\n if (opts.namespace && f.namespace !== opts.namespace) return false;\n return true;\n });\n if (files.length === 0) {\n console.log(`No locale files found under ${opts.src}/`);\n return;\n }\n\n // namespace -> language_code -> flat map\n const byNs = new Map<string, Record<string, Record<string, string>>>();\n let totalKeys = 0;\n for (const f of files) {\n const flat = await readLocaleFile(f.path);\n totalKeys += Object.keys(flat).length;\n const langs = byNs.get(f.namespace) ?? {};\n langs[f.lang] = flat;\n byNs.set(f.namespace, langs);\n console.log(` ${f.lang}/${f.namespace}.json ${Object.keys(flat).length} keys`);\n }\n\n const body: ImportBody = {\n namespaces: [...byNs.entries()].map(([namespace, translations]) => ({\n namespace,\n translations,\n })),\n };\n if (opts.status === \"draft\" || opts.status === \"translated\") body.status = opts.status;\n if (opts.version) body.version = opts.version;\n\n if (opts.dryRun) {\n console.log(\n `\\n(dry-run) would push ${totalKeys} key(s) across ${body.namespaces.length} ` +\n \"namespace(s); nothing sent.\",\n );\n return;\n }\n\n const report = await importBundle(ctx, body);\n console.log(\"\");\n for (const line of summariseImport(report)) console.log(line);\n if (report.errors?.length || report.glossary_violations?.length) process.exitCode = 1;\n },\n );\n","import { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { type PublishCdnBody, publishCdn } from \"../mcp.js\";\n\nexport const releasesCommand = new Command(\"releases\")\n .description(\"Manage CDN releases for the project.\")\n .addCommand(\n new Command(\"publish\")\n .description(\n \"Trigger a CDN release: build bundles for every (language, namespace) \" +\n \"and push them to the public CDN. Idempotent — unchanged bundles are \" +\n \"reused. Subscribed SDKs receive a live `translations_published` event.\",\n )\n .option(\"--language <code>\", \"Restrict to one language (default: all)\")\n .option(\"--namespace <slug>\", \"Restrict to one namespace (default: all)\")\n .option(\"--version <slug>\", \"Version slug (default: production version)\")\n .option(\"--dry-run\", \"Print the planned release without publishing\", false)\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: {\n language?: string;\n namespace?: string;\n version?: string;\n dryRun: boolean;\n host?: string;\n }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const scope =\n [\n opts.language && `language=${opts.language}`,\n opts.namespace && `namespace=${opts.namespace}`,\n opts.version && `version=${opts.version}`,\n ]\n .filter(Boolean)\n .join(\", \") || \"ALL languages + namespaces\";\n\n if (opts.dryRun) {\n console.log(`(dry-run) would publish a CDN release for ${scope}; nothing sent.`);\n return;\n }\n\n const body: PublishCdnBody = {};\n if (opts.language) body.language_code = opts.language;\n if (opts.namespace) body.namespace = opts.namespace;\n if (opts.version) body.version_slug = opts.version;\n const res = await publishCdn(ctx, body);\n console.log(`published CDN release for ${scope}`);\n console.log(JSON.stringify(res, null, 2));\n },\n ),\n );\n","import { promises as fs } from \"node:fs\";\n\nimport { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { getProjectInfo, requireProject } from \"../mcp.js\";\n\ntype Tree = Record<string, unknown>;\ntype Bundles = Record<string, Record<string, Tree>>;\n\n/** Public CDN bundle URL — the exact path the SDK fetches at runtime. */\nexport function bundleUrl(\n cdnBase: string,\n project: string,\n version: string,\n lang: string,\n ns: string,\n): string {\n return `${cdnBase.replace(/\\/+$/, \"\")}/p/${project}/${version}/latest/${lang}/${ns}.json`;\n}\n\n/**\n * Render the snapshot module. The SDK (#757) reads `initialBundles` as the PURE\n * `Record<locale, Record<namespace, tree>>` map, so provenance lives in a\n * SEPARATE `meta` export — never mixed into `bundles` (otherwise the SDK would\n * treat `version`/`project` as locales).\n */\nexport function renderSnapshot(\n bundles: Bundles,\n meta: { project: string; version: string; cdn: string },\n format: \"ts\" | \"json\",\n): string {\n const json = JSON.stringify(bundles, null, 2);\n if (format === \"json\") return json + \"\\n\";\n return (\n \"// Generated by `sonenta snapshot` — do not edit by hand.\\n\" +\n \"// Build-time fallback for @sonenta/react-i18next:\\n\" +\n '// import { bundles } from \"./<this-file>\";\\n' +\n \"// <VerbumiaProvider initialBundles={bundles} />\\n\" +\n `export const bundles = ${json} as const;\\n\\n` +\n `export const meta = ${JSON.stringify(meta, null, 2)} as const;\\n\\n` +\n \"export default bundles;\\n\"\n );\n}\n\nasync function fetchBundle(url: string): Promise<Tree | null> {\n const res = await fetch(url, { headers: { Accept: \"application/json\" } });\n if (res.status === 404) return null; // bundle not published for this (lang, ns)\n if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${url}`);\n return (await res.json()) as Tree;\n}\n\nexport const snapshotCommand = new Command(\"snapshot\")\n .description(\n \"Generate a build-time translations snapshot for @sonenta/react-i18next \" +\n \"`initialBundles` (offline-first fallback). Fetches the PUBLIC CDN bundles \" +\n \"(exactly what the SDK loads at runtime) and assembles \" +\n \"Record<locale, Record<namespace, tree>>. Emits a .ts module (default) or .json.\",\n )\n .option(\"--language <code>\", \"Restrict to a single language code\")\n .option(\"--namespace <slug>\", \"Restrict to a single namespace slug\")\n .option(\"--version <slug>\", \"Version slug (default: the configured version_slug)\")\n .option(\"--format <fmt>\", \"ts | json (default: ts)\", \"ts\")\n .option(\"--cdn <base>\", \"CDN base URL\", \"https://cdn.sonenta.com\")\n .option(\"--out <file>\", \"Write to a file instead of stdout\")\n .option(\"--host <url>\", \"Override host (used to discover languages/namespaces)\")\n .action(\n async (opts: {\n language?: string;\n namespace?: string;\n version?: string;\n format: string;\n cdn: string;\n out?: string;\n host?: string;\n }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const project = requireProject(ctx);\n const version = opts.version ?? ctx.versionSlug;\n\n // Enumerate (language, namespace). Both pinned => no project-info call.\n let languages: string[];\n let namespaces: string[];\n if (opts.language && opts.namespace) {\n languages = [opts.language];\n namespaces = [opts.namespace];\n } else {\n const info = await getProjectInfo(ctx);\n languages = opts.language ? [opts.language] : info.languages;\n namespaces = opts.namespace ? [opts.namespace] : info.namespaces;\n if (languages.length === 0 || namespaces.length === 0) {\n throw new Error(\n \"could not enumerate languages/namespaces from project-info — \" +\n \"pass --language and --namespace explicitly.\",\n );\n }\n }\n\n const bundles: Bundles = {};\n let fetched = 0;\n let missing = 0;\n for (const lang of languages) {\n for (const ns of namespaces) {\n const tree = await fetchBundle(bundleUrl(opts.cdn, project, version, lang, ns));\n if (!tree) {\n missing++;\n continue;\n }\n (bundles[lang] ??= {})[ns] = tree;\n fetched++;\n }\n }\n\n const output = renderSnapshot(\n bundles,\n { project, version, cdn: opts.cdn.replace(/\\/+$/, \"\") },\n opts.format === \"json\" ? \"json\" : \"ts\",\n );\n\n if (opts.out) {\n await fs.writeFile(opts.out, output, \"utf8\");\n console.log(\n `wrote ${opts.out}: ${fetched} bundle(s)` +\n (missing ? `, ${missing} not published (404)` : \"\"),\n );\n } else {\n process.stdout.write(output);\n if (missing) console.error(`(${missing} bundle(s) not published)`);\n }\n },\n );\n","import { Command } from \"commander\";\n\nimport { type ApiContext, resolveContext } from \"../api.js\";\nimport {\n DEFAULT_LOCALES_DIR,\n diffFlat,\n type FlatTranslations,\n listLocaleFiles,\n readLocaleFile,\n} from \"../locales.js\";\nimport { getProjectInfo, listKeys } from \"../mcp.js\";\n\nexport const statusCommand = new Command(\"status\")\n .description(\"Diff local locales/ against the remote project state.\")\n .option(\"--language <code>\", \"Restrict to one language code\")\n .option(\"--namespace <slug>\", \"Restrict to one namespace slug\")\n .option(\"--src <dir>\", \"Locales directory\", DEFAULT_LOCALES_DIR)\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: { language?: string; namespace?: string; src: string; host?: string }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const knownLangs = new Set((await getProjectInfo(ctx)).languages);\n\n const files = (await listLocaleFiles(opts.src)).filter((f) => {\n if (opts.language && f.lang !== opts.language) return false;\n if (opts.namespace && f.namespace !== opts.namespace) return false;\n return true;\n });\n\n // Fetch remote once per language, grouped by namespace slug.\n const remoteByLang = new Map<string, Map<string, FlatTranslations>>();\n async function remoteFor(ctx2: ApiContext, lang: string): Promise<Map<string, FlatTranslations>> {\n const cached = remoteByLang.get(lang);\n if (cached) return cached;\n const m = new Map<string, FlatTranslations>();\n for (const it of await listKeys(ctx2, { languageCode: lang })) {\n const tr = it.translations?.find((t) => t.language_code === lang);\n if (!tr || tr.value === \"\") continue;\n const map = m.get(it.namespace_slug) ?? {};\n map[it.key_name] = tr.value;\n m.set(it.namespace_slug, map);\n }\n remoteByLang.set(lang, m);\n return m;\n }\n\n let totalAdded = 0;\n let totalRemoved = 0;\n let totalChanged = 0;\n let totalUnchanged = 0;\n\n for (const f of files) {\n if (knownLangs.size > 0 && !knownLangs.has(f.lang)) {\n console.log(`! ${f.lang}/${f.namespace}.json — language not in project, skipped`);\n continue;\n }\n const local = await readLocaleFile(f.path);\n const remote = (await remoteFor(ctx, f.lang)).get(f.namespace) ?? {};\n const d = diffFlat(local, remote);\n totalAdded += d.added.length;\n totalRemoved += d.removed.length;\n totalChanged += d.changed.length;\n totalUnchanged += d.unchanged;\n\n if (d.added.length === 0 && d.removed.length === 0 && d.changed.length === 0) {\n console.log(`= ${f.lang}/${f.namespace}.json (in sync, ${d.unchanged} keys)`);\n continue;\n }\n console.log(\n `~ ${f.lang}/${f.namespace}.json +${d.added.length} -${d.removed.length} ~${d.changed.length}`,\n );\n for (const k of d.added) console.log(` + ${k}`);\n for (const k of d.removed) console.log(` - ${k} (remote-only — push leaves untouched)`);\n for (const c of d.changed) console.log(` ~ ${c.key} \"${c.local}\" <- \"${c.remote}\"`);\n }\n console.log(\n `summary: +${totalAdded} -${totalRemoved} ~${totalChanged} unchanged=${totalUnchanged}`,\n );\n },\n );\n","import { Command } from \"commander\";\n\nimport { readCredentials } from \"../credentials.js\";\n\nexport const whoamiCommand = new Command(\"whoami\")\n .description(\"Show the configured default host + which API key is in use.\")\n .option(\"--host <url>\", \"Inspect a specific host instead of the default\")\n .action(async (opts: { host?: string }) => {\n const creds = await readCredentials();\n if (!creds.default && Object.keys(creds.hosts).length === 0) {\n console.log(\"Not logged in. Run `sonenta login --host <url> --token <…>`.\");\n process.exit(1);\n }\n const target = opts.host ?? creds.default;\n if (!target) {\n console.log(\"No default host set.\");\n process.exit(1);\n }\n const entry = creds.hosts[target];\n if (!entry) {\n console.log(`No credentials stored for ${target}.`);\n process.exit(1);\n }\n const masked = entry.api_key.replace(/\\.[\\s\\S]+$/, \".•••\");\n const envOverride = (process.env.SONENTA_TOKEN ?? process.env.VERBUMIA_TOKEN)?.trim();\n console.log(`host: ${target}${target === creds.default ? \" (default)\" : \"\"}`);\n console.log(`api_key: ${masked}${envOverride ? \" (overridden by SONENTA_TOKEN env)\" : \"\"}`);\n if (entry.user_email) console.log(`email: ${entry.user_email}`);\n const others = Object.keys(creds.hosts).filter((h) => h !== target);\n if (others.length) {\n console.log(`other: ${others.join(\", \")}`);\n }\n });\n"],"mappings":"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","names":["Command","fs","join","Command","fs","resolve","fs","Command","join","fs","fs","dirname","Command","dirname","fs","Command","resolve","Command","Command","resolve","Command","Command","Command","resolve","Command","Command","Command","Command","Command","Command","Command","Command","fs","join","resolve","Command","Command","Command","Command","Command","fs","Command","Command","fs","Command","Command","Command","Command","Command"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/agents.ts","../src/agents.ts","../src/commands/export.ts","../src/config.ts","../src/credentials.ts","../src/api.ts","../src/i18next_tree.ts","../src/mcp.ts","../src/commands/import.ts","../src/commands/init.ts","../src/commands/keys.ts","../src/commands/login.ts","../src/prompt.ts","../src/commands/logout.ts","../src/commands/missing.ts","../src/commands/projects.ts","../src/commands/pull.ts","../src/locales.ts","../src/commands/push.ts","../src/commands/releases.ts","../src/commands/snapshot.ts","../src/commands/status.ts","../src/commands/whoami.ts"],"sourcesContent":["import { Command } from \"commander\";\n\nimport { agentsCommand } from \"./commands/agents.js\";\nimport { exportCommand } from \"./commands/export.js\";\nimport { importCommand } from \"./commands/import.js\";\nimport { initCommand } from \"./commands/init.js\";\nimport { keysCommand } from \"./commands/keys.js\";\nimport { loginCommand } from \"./commands/login.js\";\nimport { logoutCommand } from \"./commands/logout.js\";\nimport { missingCommand } from \"./commands/missing.js\";\nimport { projectsCommand } from \"./commands/projects.js\";\nimport { pullCommand } from \"./commands/pull.js\";\nimport { pushCommand } from \"./commands/push.js\";\nimport { releasesCommand } from \"./commands/releases.js\";\nimport { snapshotCommand } from \"./commands/snapshot.js\";\nimport { statusCommand } from \"./commands/status.js\";\nimport { whoamiCommand } from \"./commands/whoami.js\";\n\nconst program = new Command();\nprogram\n .name(\"sonenta\")\n .description(\"CLI for Sonenta translation management.\")\n .version(\"0.6.0\");\n\nprogram.addCommand(loginCommand);\nprogram.addCommand(logoutCommand);\nprogram.addCommand(whoamiCommand);\nprogram.addCommand(initCommand);\nprogram.addCommand(projectsCommand);\nprogram.addCommand(keysCommand);\nprogram.addCommand(importCommand);\nprogram.addCommand(pushCommand);\nprogram.addCommand(pullCommand);\nprogram.addCommand(exportCommand);\nprogram.addCommand(statusCommand);\nprogram.addCommand(releasesCommand);\nprogram.addCommand(snapshotCommand);\nprogram.addCommand(missingCommand);\nprogram.addCommand(agentsCommand);\n\nprogram.parseAsync(process.argv).catch((err: unknown) => {\n console.error(err instanceof Error ? err.message : err);\n process.exit(1);\n});\n","import { Command } from \"commander\";\n\nimport { AGENTS_DIR, isInstalled, listAgents, writeAgent } from \"../agents.js\";\n\nexport const agentsCommand = new Command(\"agents\")\n .description(\"Install bundled Claude agents (e.g. sonenta-a11y) into .claude/agents/.\")\n .addCommand(\n new Command(\"list\")\n .description(\"List the bundled agents available to install.\")\n .option(\"--dir <path>\", \"Project directory (default: current directory)\")\n .action(async (opts: { dir?: string }) => {\n const baseDir = opts.dir;\n const agents = listAgents();\n console.log(`Available agents (${agents.length}):`);\n for (const a of agents) {\n const installed = await isInstalled(a.name, baseDir);\n const mark = installed ? \"✓ installed\" : \" not installed\";\n console.log(` ${a.name.padEnd(16)} ${mark}`);\n console.log(` ${a.summary}`);\n }\n console.log(`\\nInstall with: sonenta agents add <name>`);\n }),\n )\n .addCommand(\n new Command(\"add\")\n .description(\"Write a bundled agent definition into <dir>/.claude/agents/<name>.md.\")\n .argument(\"<name>\", \"Agent name (e.g. sonenta-a11y)\")\n .option(\"--dir <path>\", \"Project directory (default: current directory)\")\n .option(\"--force\", \"Overwrite an existing agent definition\", false)\n .action(async (name: string, opts: { dir?: string; force: boolean }) => {\n const path = await writeAgent(name, { baseDir: opts.dir, force: opts.force });\n console.log(`Wrote ${path}`);\n console.log(\n `\\nThe ${name} agent drives the Sonenta a11y MCP tools. Make sure the ` +\n `Sonenta MCP server is configured (npx -y @sonenta/mcp) with an ` +\n `mcp:* SONENTA_API_KEY, then use the agent in Claude Code or CI.`,\n );\n console.log(`Agent dir: ${AGENTS_DIR}/`);\n }),\n );\n","import { promises as fs } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\n/**\n * Installable Claude agents shipped with the CLI.\n *\n * `sonenta agents add <name>` writes a bundled agent definition into the\n * project's `.claude/agents/<name>.md` — the directory Claude Code reads\n * project-scoped subagents from. The agents drive the Sonenta a11y MCP tools\n * (from `@sonenta/mcp`) to audit and fix accessibility gaps; they work the same\n * interactively in Claude Code or headless in CI.\n *\n * The registry is intentionally simple (a name -> definition map) so more\n * agents can be added later without touching the command wiring.\n */\n\nexport const AGENTS_DIR = \".claude/agents\";\n\nexport interface AgentDef {\n /** File/agent name (no extension); the file is written as `<name>.md`. */\n name: string;\n /** One-line summary shown by `agents list`. */\n summary: string;\n /** Full agent definition (YAML frontmatter + system prompt). */\n content: string;\n}\n\nconst SONENTA_A11Y = `---\nname: sonenta-a11y\ndescription: Accessibility (a11y) auditor and fixer for Sonenta-managed i18n projects. Scans translation keys for WCAG gaps (missing aria-labels, images without alt text, hard-to-read copy, missing or untranslated a11y variants) and fixes them — generating the a11y text itself and writing it back through the Sonenta MCP tools at zero AI-credit cost. Use interactively in Claude Code or headless in CI.\n---\n\nYou are **sonenta-a11y**, an accessibility specialist for internationalized\nprojects managed with Sonenta. You turn an accessibility audit into concrete,\nreviewable fixes, operating through the Sonenta MCP server's a11y tools.\n\n## Cost model — generate LOCALLY first (this is the default)\nYou ARE a capable language model already running in the developer's session\n(Claude Code or CI), and that compute is already paid for. So **you write the\na11y values yourself, with your own reasoning, and persist them with\n\\`set_a11y_variant\\`** — which is plain CRUD and costs **zero Sonenta AI\ncredits**. Do NOT reach for the server-side AI tools\n(\\`generate_a11y_variant\\` / \\`translate_a11y_variants\\`) by default: those bill\nSonenta AI credits and exist only as an explicit fallback for very large volumes\nor when the developer specifically asks for server-side generation.\n\n## Requirements\n- The Sonenta MCP server (\\`@sonenta/mcp\\`) must be configured with an \\`mcp:*\\`\n API key. Every operation goes through its tools — never call the HTTP API\n directly. If the a11y tools are missing, tell the user to add the server\n (\\`npx -y @sonenta/mcp\\`) and set \\`SONENTA_API_KEY\\`.\n- Tools:\n - \\`a11y_report\\` — full WCAG gap report (rollups + per-item gaps). READ-ONLY.\n - \\`list_a11y_gaps\\` — the actionable gap list, filterable by gap / surface /\n locale. READ-ONLY.\n - \\`set_a11y_variant\\` — **your primary write**: upsert one a11y variant for\n (key_uuid, language_code, surface) with a text value. CRUD, **0 AI credits**,\n stored as a draft.\n - \\`delete_a11y_variant\\` — clear one variant. CRUD, **0 AI credits**.\n - \\`list_cognitive_candidates\\` — text keys eligible for plain-language scoring\n (a type offering plain_language, past a word floor). READ-ONLY.\n - \\`set_cognitive_score\\` — record a key's cognitive difficulty score (0-100)\n plus a plain-language suggestion. CRUD, **0 AI credits** (by_bot).\n - \\`a11y_estimate\\` — preview the AI-credit cost of the server-side fallback.\n - \\`generate_a11y_variant\\` / \\`translate_a11y_variants\\` / \\`analyze_cognitive\\`\n — **fallback only**: server-side AI that BILLS Sonenta AI credits. Use only\n for very large volumes or on explicit developer request.\n\n## The four a11y surfaces (what you write)\n- \\`aria_label\\` — a concise accessible NAME for an interactive element (button,\n icon, link). Derive it from the element's visible label and purpose.\n- \\`alt_text\\` — alternative text for an image. Derive it from the key's context /\n description; describe the image's MEANING, not \"image of…\".\n- \\`screen_reader\\` — verbose screen-reader-only text, for when the visible text\n is insufficient out of context.\n- \\`plain_language\\` — a simplified / clear-language (FALC) rewrite of the source.\n\na11y values are SEMANTIC (the accessible name / alt / simplified wording for\nassistive tech), not the visible UI string — keep them concise and meaningful.\n\n## Gap types and how you resolve each (locally, by yourself)\n- \\`a11y_variant_absent\\` — a required surface is missing in the source → compose\n it yourself and \\`set_a11y_variant\\` (source language).\n- \\`alt_missing\\` — an image key has no source alt_text → write \\`alt_text\\`.\n- \\`reading_level_high\\` — flagged when a key's COGNITIVE SCORE is at/above the\n project threshold. Resolve it locally: judge the difficulty yourself and call\n \\`set_cognitive_score(key_uuid, score, suggestion)\\` with a plain-language\n rewrite (0 credits, draft). The suggestion is then applied to the\n \\`plain_language\\` surface (or the base value) on human approval.\n- \\`a11y_untranslated\\` — a source a11y variant exists but a locale lacks it →\n TRANSLATE it yourself and \\`set_a11y_variant\\` for that \\`language_code\\`.\n\n## Workflow\n1. **Scan.** Call \\`a11y_report\\` (pass \\`require_surface\\` for the surfaces the\n project needs, typically \\`aria_label\\` and \\`alt_text\\`). Summarize\n \\`total_gaps\\`, \\`by_gap\\`, \\`by_severity\\`, \\`by_surface\\`. Use\n \\`list_a11y_gaps\\` to pull the actionable items — each carries \\`key_uuid\\`,\n \\`key_name\\`, \\`namespace_slug\\`, \\`surface\\`, and \\`locale\\`.\n2. **Triage.** Group by type/severity — warnings first (\\`a11y_untranslated\\`,\n \\`alt_missing\\`), then info (\\`reading_level_high\\`, \\`a11y_variant_absent\\`).\n3. **Generate locally + write (DEFAULT path, 0 credits).** For each gap, compose\n the a11y value YOURSELF — reasoning over the key name, source value, any\n context/description, and the target surface — then persist it with\n \\`set_a11y_variant(key_uuid, language_code, surface, value)\\`. For\n \\`a11y_untranslated\\`, translate the source variant yourself into the target\n \\`language_code\\` and \\`set_a11y_variant\\`. Work through the gap list in\n sensible batches. This spends NO AI credits.\n4. **Score plain-language (local, 0 credits).** Call\n \\`list_cognitive_candidates\\` (use \\`only_unanalyzed=true\\` to skip already\n scored keys). For each candidate, JUDGE its cognitive difficulty yourself\n (0-100, higher = harder to read) and write a clearer plain-language rewrite,\n then \\`set_cognitive_score(key_uuid, score, suggestion)\\`. Keys at/above the\n project threshold then surface as \\`reading_level_high\\` for a human to\n apply/approve. This spends NO credits — prefer it over \\`analyze_cognitive\\`.\n5. **Server fallback (opt-in only).** If the volume is impractical to do locally,\n or the developer explicitly wants Sonenta server-side AI, FIRST call\n \\`a11y_estimate\\` (report \\`credits_required\\` vs \\`balance\\`; stop if not\n \\`sufficient\\`), confirm, THEN \\`generate_a11y_variant\\` /\n \\`translate_a11y_variants\\` (or \\`analyze_cognitive\\` for bulk cognitive\n scoring).\n6. **Report.** Everything you write lands as a **draft** for human review — never\n present it as final. Summarize what you set (counts by surface / locale), what\n remains, and whether any credits were spent (0 on the local path).\n\n## Modes\n- **Interactive (Claude Code):** propose the fix plan, then write the local\n fixes; for the credit-billing fallback, show the estimate and confirm first.\n- **CI / headless:** run \\`a11y_report\\` and exit non-zero when \\`total_gaps\\` (or\n a chosen severity) exceeds the project threshold; optionally auto-write the\n local fixes. Only use the credit-billing fallback when explicitly authorized.\n\n## Guardrails\n- Default to LOCAL work + \\`set_a11y_variant\\` / \\`set_cognitive_score\\`\n (0 credits). Treat \\`generate_a11y_variant\\` / \\`translate_a11y_variants\\` /\n \\`analyze_cognitive\\` as an explicit, estimated, opt-in fallback — never the\n silent default.\n- \\`set_a11y_variant\\` / \\`delete_a11y_variant\\` / \\`set_cognitive_score\\` are CRUD\n and never spend AI credits; only \\`generate\\` / \\`translate\\` / \\`analyze\\` do.\n Always estimate before that fallback.\n- You FILL gaps — never overwrite a human-reviewed variant blindly.\n- Stay within the configured project; confirm it before any bulk operation.\n`;\n\nconst SONENTA_I18N = `---\nname: sonenta-i18n\ndescription: Internationalization (i18n) automation agent for Sonenta-managed projects. Audits translation coverage, creates missing keys, translates the untranslated content itself (honoring the glossary and project context), and publishes — driving the Sonenta i18n MCP tools. Local-first (0 AI credits), draft-to-review, usable in Claude Code or headless in CI.\n---\n\nYou are **sonenta-i18n**, an internationalization specialist for projects managed\nwith Sonenta. You run the everyday i18n loop — assess coverage, fill missing\nkeys, translate what is untranslated, and publish — through the Sonenta MCP\nserver's tools.\n\n## Cost model — translate LOCALLY first (default, 0 credits)\nYou ARE a capable language model already running in the developer's session\n(Claude Code or CI) on compute they already pay for. So you **translate the\nstrings yourself**, honoring the project's glossary and context, and write the\nresults with \\`propose_translations_bulk\\` as **drafts/proposed** — plain CRUD,\n**zero Sonenta AI credits**. Do NOT reach for server-side on-demand AI\ntranslation by default; where such a path exists it BILLS Sonenta AI credits and\nis an explicit, estimate-first, opt-in fallback for very large volumes.\n\n## Requirements\n- The Sonenta MCP server (\\`@sonenta/mcp\\`) must be configured with an \\`mcp:*\\`\n API key. Everything goes through its tools — never call the HTTP API directly.\n If the tools are missing, tell the user to add the server\n (\\`npx -y @sonenta/mcp\\`) and set \\`SONENTA_API_KEY\\`.\n- Tools you drive:\n - **Assess:** \\`get_project_info\\`, \\`coverage_report\\`, \\`health_report\\`,\n \\`missing_keys_stats\\`, \\`list_missing_keys\\`.\n - **Fill keys:** \\`create_namespace\\`, \\`create_keys_bulk\\`,\n \\`update_keys_bulk\\`, \\`acknowledge_missing_keys\\`.\n - **Translate:** \\`list_untranslated_keys\\`, \\`propose_translations_bulk\\`\n (your primary write — CRUD, 0 credits), \\`validate_translations\\`.\n - **Consistency:** \\`glossary_list\\`, \\`project_context_get\\`.\n - **Ship:** \\`publish_cdn\\`.\n\n## Workflow\n1. **Assess.** \\`get_project_info\\` (source + target languages, namespaces);\n \\`coverage_report\\` (per-language completeness); \\`health_report\\`\n (source-string issues); \\`missing_keys_stats\\` / \\`list_missing_keys\\`\n (runtime-detected gaps). Summarize where the project stands.\n2. **Fill missing keys.** For runtime-detected missing keys, \\`create_keys_bulk\\`\n (seed the source value) — \\`create_namespace\\` first if a namespace is new —\n then \\`acknowledge_missing_keys\\` to clear the dashboard.\n3. **Translate the untranslated (default, 0 credits).** For each target\n language, \\`list_untranslated_keys\\`. BEFORE translating, read\n \\`glossary_list\\` (respect \\`forbidden\\` / \\`do_not_translate\\`, apply\n \\`translation\\` rules) and \\`project_context_get\\` (brand voice, domain, tone).\n Translate each value YOURSELF, then write a batch with\n \\`propose_translations_bulk\\` (status draft/proposed). Work through the\n languages and namespaces in sensible batches.\n4. **Validate (optional).** \\`validate_translations\\` lints an i18next blob\n server-side; fix anything it flags.\n5. **Publish.** \\`publish_cdn\\` to release the bundles — with confirmation in\n interactive mode, only on explicit authorization in CI.\n6. **Report.** Show the coverage delta (before/after), counts of keys created and\n strings translated, what remains, and that translations are drafts to review.\n\n## Modes\n- **Interactive (Claude Code):** propose the plan, write the drafts, then confirm\n before publishing.\n- **CI / headless:** run \\`coverage_report\\` and exit non-zero when completeness\n is below a chosen threshold; optionally auto-write translation drafts; only\n \\`publish_cdn\\` when the run is explicitly authorized.\n\n## Guardrails\n- Translations land as **drafts/proposed** for human review — never\n auto-approved.\n- Always honor the glossary (\\`forbidden\\` / \\`do_not_translate\\`) and the project\n context before translating.\n- Local translation + \\`propose_translations_bulk\\` is the default and costs 0\n credits; any server-side AI translation is an explicit, estimated, opt-in\n fallback.\n- Never \\`publish_cdn\\` without confirmation/authorization; stay within the\n configured project.\n`;\n\nexport const AGENTS: Record<string, AgentDef> = {\n \"sonenta-a11y\": {\n name: \"sonenta-a11y\",\n summary:\n \"Accessibility (a11y) auditor + fixer: scans WCAG gaps and fixes them locally (0-credit set_a11y_variant), with server-side AI generation as an opt-in fallback.\",\n content: SONENTA_A11Y,\n },\n \"sonenta-i18n\": {\n name: \"sonenta-i18n\",\n summary:\n \"i18n automation: audits coverage, creates missing keys, translates the untranslated locally (0-credit propose_translations_bulk), and publishes — server-side AI translation as an opt-in fallback.\",\n content: SONENTA_I18N,\n },\n};\n\nexport function listAgents(): AgentDef[] {\n return Object.values(AGENTS);\n}\n\nexport function getAgent(name: string): AgentDef | undefined {\n return AGENTS[name];\n}\n\n/** Absolute path the agent definition is (or would be) written to. */\nexport function agentInstallPath(name: string, baseDir: string = process.cwd()): string {\n return resolve(baseDir, AGENTS_DIR, `${name}.md`);\n}\n\nexport async function isInstalled(name: string, baseDir: string = process.cwd()): Promise<boolean> {\n try {\n await fs.access(agentInstallPath(name, baseDir));\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Write a bundled agent into `<baseDir>/.claude/agents/<name>.md`.\n * Throws on an unknown agent or when the file exists and `force` is false.\n * Returns the absolute path written.\n */\nexport async function writeAgent(\n name: string,\n opts: { baseDir?: string; force?: boolean } = {},\n): Promise<string> {\n const agent = getAgent(name);\n if (!agent) {\n const known = Object.keys(AGENTS).join(\", \");\n throw new Error(`Unknown agent \"${name}\". Available: ${known}`);\n }\n const baseDir = opts.baseDir ?? process.cwd();\n const path = agentInstallPath(name, baseDir);\n if (!opts.force) {\n try {\n await fs.access(path);\n throw new Error(\n `${path} already exists. Pass --force to overwrite.`,\n );\n } catch (err) {\n // Re-throw the \"already exists\" error; an access() rejection means the\n // file is absent, which is the happy path.\n if (err instanceof Error && err.message.includes(\"already exists\")) throw err;\n }\n }\n await fs.mkdir(resolve(baseDir, AGENTS_DIR), { recursive: true });\n await fs.writeFile(path, agent.content, \"utf8\");\n return path;\n}\n","import { promises as fs } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { Command } from \"commander\";\n\nimport { type ApiContext, resolveContext } from \"../api.js\";\nimport { type FlatMap, sortDeep, unflatten } from \"../i18next_tree.js\";\nimport { getProjectInfo, listKeys } from \"../mcp.js\";\n\n/** language_code -> namespace_slug -> flat map of key -> value. */\ntype Collected = Record<string, Record<string, FlatMap>>;\n\nasync function collect(\n ctx: ApiContext,\n languages: string[],\n namespace?: string,\n): Promise<Collected> {\n const out: Collected = {};\n for (const lang of languages) {\n const items = await listKeys(ctx, { languageCode: lang, namespace });\n for (const it of items) {\n const tr = it.translations?.find((t) => t.language_code === lang);\n if (!tr || tr.value === \"\") continue;\n (out[lang] ??= {})[it.namespace_slug] ??= {};\n out[lang]![it.namespace_slug]![it.key_name] = tr.value;\n }\n }\n return out;\n}\n\nexport const exportCommand = new Command(\"export\")\n .description(\n \"Export Verbumia translations as i18next JSON. Flat dot-notation by \" +\n \"default (--nested for nested trees). Writes <out>/<lang>/<namespace>.json \" +\n \"with --out, otherwise prints { locale: { namespace: tree } } to stdout.\",\n )\n .option(\"--language <code>\", \"Restrict to a single language code\")\n .option(\"--namespace <slug>\", \"Restrict to a single namespace slug\")\n .option(\"--nested\", \"Emit nested JSON instead of flat dot-notation\", false)\n .option(\"--out <dir>\", \"Write files instead of printing to stdout\")\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: {\n language?: string;\n namespace?: string;\n nested: boolean;\n out?: string;\n host?: string;\n }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const languages = opts.language ? [opts.language] : (await getProjectInfo(ctx)).languages;\n const collected = await collect(ctx, languages, opts.namespace);\n const shape = (flat: FlatMap): unknown => (opts.nested ? sortDeep(unflatten(flat)) : sortDeep(flat));\n\n if (opts.out) {\n let files = 0;\n for (const [lang, nss] of Object.entries(collected)) {\n for (const [ns, flat] of Object.entries(nss)) {\n const dir = join(opts.out, lang);\n await fs.mkdir(dir, { recursive: true });\n const p = join(dir, `${ns}.json`);\n await fs.writeFile(p, JSON.stringify(shape(flat), null, 2) + \"\\n\", \"utf8\");\n console.log(` ${p} ${Object.keys(flat).length} keys`);\n files++;\n }\n }\n console.log(`exported ${files} file(s)`);\n return;\n }\n\n const tree: Record<string, Record<string, unknown>> = {};\n for (const [lang, nss] of Object.entries(collected)) {\n tree[lang] = {};\n for (const [ns, flat] of Object.entries(nss)) tree[lang]![ns] = shape(flat);\n }\n process.stdout.write(JSON.stringify(tree, null, 2) + \"\\n\");\n },\n );\n","import { promises as fs } from \"node:fs\";\nimport { dirname, resolve } from \"node:path\";\n\n/**\n * Project-local config — `sonenta.config.json` at the repo root.\n *\n * Layout (V1, intentionally minimal):\n *\n * {\n * \"host\": \"https://api.sonenta.com\",\n * \"project_uuid\": \"069fc15d-…\",\n * \"version_slug\": \"main\"\n * }\n *\n * `host` may be omitted — commands then fall back to the user-level\n * credentials default. `version_slug` defaults to \"main\" when omitted.\n *\n * Back-compat: the legacy filename `verbumia.config.json` is still READ\n * (with a one-time deprecation warning) when no `sonenta.config.json` is\n * found, so existing projects keep working. New configs are written as\n * `sonenta.config.json`.\n */\n\nexport interface ProjectConfig {\n host?: string;\n project_uuid?: string;\n version_slug?: string;\n}\n\nexport const CONFIG_FILENAME = \"sonenta.config.json\";\nexport const LEGACY_CONFIG_FILENAME = \"verbumia.config.json\";\n\nlet warnedLegacy = false;\n\nexport async function findConfigPath(startDir: string): Promise<string | null> {\n let dir = resolve(startDir);\n // Walk up until we hit a config or the filesystem root. At each level the\n // canonical name wins over the deprecated one.\n while (true) {\n for (const name of [CONFIG_FILENAME, LEGACY_CONFIG_FILENAME]) {\n const candidate = resolve(dir, name);\n try {\n await fs.access(candidate);\n if (name === LEGACY_CONFIG_FILENAME && !warnedLegacy) {\n warnedLegacy = true;\n process.emitWarning(\n `${LEGACY_CONFIG_FILENAME} is deprecated — rename it to ${CONFIG_FILENAME}. ` +\n `The legacy name still works for now.`,\n { type: \"DeprecationWarning\" },\n );\n }\n return candidate;\n } catch {\n // Continue to the next name / parent dir.\n }\n }\n const parent = dirname(dir);\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\nexport async function readConfig(startDir: string = process.cwd()): Promise<{\n path: string | null;\n config: ProjectConfig;\n}> {\n const path = await findConfigPath(startDir);\n if (!path) return { path: null, config: {} };\n const raw = await fs.readFile(path, \"utf8\");\n const parsed = JSON.parse(raw) as ProjectConfig;\n return { path, config: parsed };\n}\n\nexport async function writeConfig(\n config: ProjectConfig,\n targetDir: string = process.cwd(),\n): Promise<string> {\n // Always write the canonical filename.\n const path = resolve(targetDir, CONFIG_FILENAME);\n await fs.writeFile(path, JSON.stringify(config, null, 2) + \"\\n\", \"utf8\");\n return path;\n}\n","import { promises as fs } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\n/**\n * Per-user credentials store.\n *\n * Lives at `~/.verbumia/credentials` with file mode 0600. The shape is a\n * keyed map of host → entry, so a single user can have multiple accounts\n * (cloud + self-hosted dev + self-hosted prod) without rewriting the file\n * each time they switch hosts.\n *\n * {\n * \"default\": \"https://api.sonenta.com\",\n * \"hosts\": {\n * \"https://api.sonenta.com\": { \"api_key\": \"vrb_live_…\", \"user_email\": \"...\" },\n * \"https://api.dev.verbumia.ca\":{ \"api_key\": \"vrb_live_…\" }\n * }\n * }\n *\n * The `default` host is what `sonenta` commands target when neither the\n * project's `sonenta.config.json` nor a `--host` flag override it.\n */\n\nexport interface CredentialsEntry {\n api_key: string;\n user_email?: string;\n}\n\nexport interface CredentialsFile {\n default?: string;\n hosts: Record<string, CredentialsEntry>;\n}\n\nexport const credentialsDir = (): string => join(homedir(), \".verbumia\");\nexport const credentialsPath = (): string => join(credentialsDir(), \"credentials\");\n\nconst EMPTY: CredentialsFile = { hosts: {} };\n\nexport async function readCredentials(): Promise<CredentialsFile> {\n try {\n const raw = await fs.readFile(credentialsPath(), \"utf8\");\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\" || !parsed.hosts) {\n return EMPTY;\n }\n return parsed as CredentialsFile;\n } catch (err: unknown) {\n if ((err as NodeJS.ErrnoException)?.code === \"ENOENT\") return { hosts: {} };\n throw err;\n }\n}\n\nexport async function writeCredentials(creds: CredentialsFile): Promise<void> {\n const dir = credentialsDir();\n const path = credentialsPath();\n await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n // Write to a temp file first to keep the original intact if the process\n // crashes mid-write, then rename atomically.\n const tmp = `${path}.tmp`;\n await fs.writeFile(tmp, JSON.stringify(creds, null, 2) + \"\\n\", { mode: 0o600 });\n await fs.rename(tmp, path);\n // chmod again in case the umask widened it on creation\n await fs.chmod(path, 0o600);\n await fs.chmod(dir, 0o700).catch(() => {});\n}\n\nexport async function setHostEntry(\n host: string,\n entry: CredentialsEntry,\n options: { makeDefault?: boolean } = {},\n): Promise<void> {\n const creds = await readCredentials();\n creds.hosts[host] = entry;\n if (options.makeDefault || !creds.default) creds.default = host;\n await writeCredentials(creds);\n}\n\nexport async function removeHost(host: string): Promise<boolean> {\n const creds = await readCredentials();\n if (!(host in creds.hosts)) return false;\n delete creds.hosts[host];\n if (creds.default === host) {\n const remaining = Object.keys(creds.hosts);\n creds.default = remaining[0];\n }\n await writeCredentials(creds);\n return true;\n}\n\nexport function resolveHostEntry(\n creds: CredentialsFile,\n hostOverride?: string,\n): { host: string; entry: CredentialsEntry } | null {\n const host = hostOverride ?? creds.default;\n if (!host) return null;\n const entry = creds.hosts[host];\n if (!entry) return null;\n return { host, entry };\n}\n","import { readConfig } from \"./config.js\";\nimport {\n type CredentialsEntry,\n readCredentials,\n resolveHostEntry,\n} from \"./credentials.js\";\n\n/**\n * Resolved request context for a CLI command:\n * - host: which Verbumia API to talk to\n * - apiKey: the bearer ApiKey token (resolved from credentials)\n * - projectUuid: optional, from project config\n * - versionSlug: defaults to \"main\"\n */\nexport interface ApiContext {\n host: string;\n apiKey: string;\n projectUuid?: string;\n versionSlug: string;\n}\n\nexport interface ResolveOptions {\n hostOverride?: string;\n cwd?: string;\n}\n\nexport async function resolveContext(opts: ResolveOptions = {}): Promise<ApiContext> {\n const { config } = await readConfig(opts.cwd ?? process.cwd());\n const creds = await readCredentials();\n const host = opts.hostOverride ?? config.host ?? creds.default;\n if (!host) {\n throw new Error(\n \"No host configured. Run `sonenta login --host <url>` or add `host` to sonenta.config.json.\",\n );\n }\n\n // Auth resolution order (first wins):\n // 1. SONENTA_TOKEN (or legacy VERBUMIA_TOKEN) env var — highest priority for CI / scripts\n // 2. ~/.verbumia/credentials entry for this host\n // The env-var path lets users run a one-off command in CI without\n // touching the credentials file or typing the token interactively.\n const envToken = process.env.SONENTA_TOKEN ?? process.env.VERBUMIA_TOKEN;\n let apiKey: string | undefined = envToken && envToken.trim() ? envToken.trim() : undefined;\n if (!apiKey) {\n const resolved = resolveHostEntry(creds, host);\n if (!resolved) {\n throw new Error(\n `No credentials for host ${host}. Set SONENTA_TOKEN or run \\`sonenta login --host ${host}\\`.`,\n );\n }\n apiKey = resolved.entry.api_key;\n }\n\n return {\n host,\n apiKey,\n projectUuid: config.project_uuid,\n versionSlug: config.version_slug ?? \"main\",\n };\n}\n\nexport async function apiRequest<T = unknown>(\n ctx: ApiContext,\n path: string,\n init: RequestInit = {},\n): Promise<T> {\n const url = `${ctx.host.replace(/\\/+$/, \"\")}${path}`;\n const headers = new Headers(init.headers);\n headers.set(\"Authorization\", `ApiKey ${ctx.apiKey}`);\n if (init.body && !headers.has(\"Content-Type\")) {\n headers.set(\"Content-Type\", \"application/json\");\n }\n const res = await fetch(url, { ...init, headers });\n if (!res.ok) {\n const text = await res.text().catch(() => \"\");\n throw new Error(`HTTP ${res.status} ${res.statusText} on ${path}: ${text.slice(0, 300)}`);\n }\n if (res.status === 204) return undefined as T;\n return (await res.json()) as T;\n}\n","/**\n * i18next tree <-> flat-map helpers.\n *\n * Verbumia stores keys as flat dot-notation (`hero.title`). i18next files on\n * disk are commonly nested (`{hero:{title:..}}`). The one-shot import endpoint\n * accepts BOTH, so `import` passes trees through untouched — these helpers are\n * for the OUTPUT side (export/snapshot) where we choose flat or nested.\n */\n\nexport type FlatMap = Record<string, string>;\nexport type Tree = Record<string, unknown>;\n\n/** Expand dot-notation flat keys into a nested tree. */\nexport function unflatten(flat: FlatMap, sep = \".\"): Tree {\n const root: Tree = {};\n for (const [k, v] of Object.entries(flat)) {\n const parts = k.split(sep);\n let node: Tree = root;\n for (let i = 0; i < parts.length - 1; i++) {\n const p = parts[i]!;\n const existing = node[p];\n if (typeof existing !== \"object\" || existing === null) node[p] = {};\n node = node[p] as Tree;\n }\n node[parts[parts.length - 1]!] = v;\n }\n return root;\n}\n\n/** Flatten a nested tree to dot-notation (string leaves only). */\nexport function flatten(tree: Tree, sep = \".\"): FlatMap {\n const out: FlatMap = {};\n const walk = (node: unknown, prefix: string): void => {\n if (!node || typeof node !== \"object\" || Array.isArray(node)) return;\n for (const [k, v] of Object.entries(node as Tree)) {\n const key = prefix ? `${prefix}${sep}${k}` : k;\n if (v && typeof v === \"object\" && !Array.isArray(v)) walk(v, key);\n else if (typeof v === \"string\") out[key] = v;\n }\n };\n walk(tree, \"\");\n return out;\n}\n\n/** Recursively sort object keys for deterministic, diff-friendly output. */\nexport function sortDeep<T>(value: T): T {\n if (Array.isArray(value)) return value.map((v) => sortDeep(v)) as unknown as T;\n if (value && typeof value === \"object\") {\n const src = value as Record<string, unknown>;\n const out: Record<string, unknown> = {};\n for (const k of Object.keys(src).sort((a, b) => a.localeCompare(b))) out[k] = sortDeep(src[k]);\n return out as T;\n }\n return value;\n}\n","/**\n * MCP-surface client helpers.\n *\n * The whole CLI talks to the metered, key-addressable MCP surface\n * `/v1/mcp/projects/{project_id}/...` (auth = an API key carrying the `mcp:*`\n * scope). That surface addresses keys/namespaces/languages by NAME (no uuids),\n * exposes bulk + one-shot endpoints, and is the contract-blessed automation\n * entrypoint. These helpers wrap the endpoints the commands consume.\n */\n\nimport { type ApiContext, apiRequest } from \"./api.js\";\n\nexport function requireProject(ctx: ApiContext): string {\n if (!ctx.projectUuid) {\n throw new Error(\n \"no project configured — run `sonenta init --project <uuid>` \" +\n \"(or set project_uuid in sonenta.config.json).\",\n );\n }\n return ctx.projectUuid;\n}\n\nfunction projectBase(ctx: ApiContext): string {\n return `/v1/mcp/projects/${requireProject(ctx)}`;\n}\n\n// ---- projects ------------------------------------------------------------\n\nexport interface ProjectSummary {\n uuid: string;\n name?: string;\n slug?: string;\n source_language?: string;\n}\n\nexport async function listProjects(ctx: ApiContext, limit = 200): Promise<ProjectSummary[]> {\n const data = await apiRequest<{ items: ProjectSummary[] }>(\n ctx,\n `/v1/mcp/projects?limit=${limit}`,\n );\n return data.items ?? [];\n}\n\nexport interface ProjectInfo {\n source_language: string;\n languages: string[];\n namespaces: string[];\n}\n\n/** Normalises get_project_info into plain code/slug lists (shape-tolerant). */\nexport async function getProjectInfo(ctx: ApiContext): Promise<ProjectInfo> {\n const d = await apiRequest<Record<string, unknown>>(ctx, projectBase(ctx));\n const src =\n typeof d.source_language === \"string\"\n ? d.source_language\n : (d.source_language as { code?: string })?.code ?? \"\";\n const langs = Array.isArray(d.languages)\n ? (d.languages as unknown[]).map((l) =>\n typeof l === \"string\" ? l : ((l as { code?: string }).code ?? \"\"),\n )\n : [];\n const ns = Array.isArray(d.namespaces)\n ? (d.namespaces as unknown[]).map((n) =>\n typeof n === \"string\" ? n : ((n as { slug?: string }).slug ?? \"\"),\n )\n : [];\n return {\n source_language: src,\n languages: langs.filter(Boolean),\n namespaces: ns.filter(Boolean),\n };\n}\n\n// ---- keys (paginated list) ----------------------------------------------\n\nexport interface KeyTranslation {\n language_code: string;\n value: string;\n status: string;\n}\n\nexport interface KeyItem {\n key_name: string;\n namespace_slug: string;\n source_value: string | null;\n translations?: KeyTranslation[];\n}\n\nexport async function listKeys(\n ctx: ApiContext,\n opts: { languageCode?: string; namespace?: string } = {},\n): Promise<KeyItem[]> {\n const out: KeyItem[] = [];\n let cursor: string | null = null;\n do {\n const params = new URLSearchParams({ limit: \"200\" });\n if (opts.languageCode) params.set(\"language_code\", opts.languageCode);\n if (opts.namespace) params.set(\"namespace\", opts.namespace);\n if (cursor) params.set(\"cursor\", cursor);\n const page = await apiRequest<{ items: KeyItem[]; cursor_next: string | null }>(\n ctx,\n `${projectBase(ctx)}/keys?${params.toString()}`,\n );\n out.push(...(page.items ?? []));\n cursor = page.cursor_next ?? null;\n } while (cursor);\n return out;\n}\n\n// ---- i18next one-shot import --------------------------------------------\n\nexport type I18nextTree = Record<string, unknown>;\n\nexport interface ImportNamespaceUnit {\n namespace: string;\n translations: Record<string, I18nextTree>; // language_code -> i18next tree (nested or flat)\n}\n\nexport interface ImportBody {\n namespaces: ImportNamespaceUnit[];\n version?: string;\n status?: \"draft\" | \"translated\";\n}\n\nexport interface ImportBundleReport {\n project_uuid: string;\n version_slug: string;\n keys_created: number;\n keys_reused: number;\n translations_created: number;\n translations_updated: number;\n translations_unchanged: number;\n plural_keys_marked: number;\n units?: unknown[];\n errors?: { namespace: string; language_code: string; code: string }[];\n glossary_violation_count?: number;\n glossary_violations?: {\n namespace: string;\n language_code: string;\n key: string;\n rule_type: string;\n term: string;\n matched_text?: string;\n message?: string;\n }[];\n}\n\nexport async function importBundle(ctx: ApiContext, body: ImportBody): Promise<ImportBundleReport> {\n return apiRequest<ImportBundleReport>(ctx, `${projectBase(ctx)}/i18next/import`, {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n}\n\n// ---- CDN releases (publish) ---------------------------------------------\n\nexport interface PublishCdnBody {\n language_code?: string;\n namespace?: string;\n version_slug?: string;\n}\n\nexport async function publishCdn(ctx: ApiContext, body: PublishCdnBody): Promise<unknown> {\n return apiRequest(ctx, `${projectBase(ctx)}/cdn/releases`, {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n}\n\n// ---- formatting ----------------------------------------------------------\n\n/** Human-readable lines for an ImportBundleReport (created/updated/unchanged). */\nexport function summariseImport(r: ImportBundleReport): string[] {\n const lines = [\n `keys: ${r.keys_created} created, ${r.keys_reused} reused`,\n `translations: ${r.translations_created} created, ${r.translations_updated} updated, ${r.translations_unchanged} unchanged`,\n ];\n if (r.plural_keys_marked) lines.push(`plural keys: ${r.plural_keys_marked} marked`);\n if (r.errors?.length) {\n lines.push(`errors: ${r.errors.length}`);\n for (const e of r.errors) lines.push(` ! ${e.namespace}/${e.language_code}: ${e.code}`);\n }\n if (r.glossary_violations?.length) {\n lines.push(`glossary: ${r.glossary_violations.length} violation(s)`);\n for (const g of r.glossary_violations) {\n lines.push(` ⚠ ${g.namespace}/${g.language_code} ${g.key}: ${g.rule_type} \"${g.term}\"`);\n }\n }\n return lines;\n}\n","import { promises as fs } from \"node:fs\";\nimport { basename, dirname } from \"node:path\";\n\nimport { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { type I18nextTree, type ImportBody, importBundle, summariseImport } from \"../mcp.js\";\n\n/**\n * Resolve (language, namespace) for a file.\n * - explicit --language / --namespace always win;\n * - otherwise infer from the i18next layout `<lang>/<namespace>.json`\n * (parent dir = language, filename stem = namespace);\n * - a bare `<lang>.json` (no language dir) uses the stem as the language and\n * REQUIRES --namespace.\n */\nexport function resolveLangNs(\n filePath: string,\n optLang?: string,\n optNs?: string,\n): { lang: string; ns: string } {\n const stem = basename(filePath).replace(/\\.json$/i, \"\");\n const parent = basename(dirname(filePath));\n const hasLangDir = parent !== \"\" && parent !== \".\" && parent !== \"locales\";\n const lang = optLang ?? (hasLangDir ? parent : stem);\n const ns = optNs ?? (hasLangDir ? stem : undefined);\n if (!lang) throw new Error(`could not infer a language for ${filePath} — pass --language`);\n if (!ns) {\n throw new Error(\n `could not infer a namespace for ${filePath} — pass --namespace, ` +\n \"or lay files out as <lang>/<namespace>.json\",\n );\n }\n return { lang, ns };\n}\n\nasync function readTree(filePath: string): Promise<I18nextTree> {\n const parsed = JSON.parse(await fs.readFile(filePath, \"utf8\"));\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`${filePath} is not a JSON object`);\n }\n return parsed as I18nextTree;\n}\n\nfunction countLeaves(tree: I18nextTree): number {\n let n = 0;\n for (const v of Object.values(tree)) {\n if (v && typeof v === \"object\" && !Array.isArray(v)) n += countLeaves(v as I18nextTree);\n else n += 1;\n }\n return n;\n}\n\nexport const importCommand = new Command(\"import\")\n .description(\n \"Import i18next JSON file(s) into Verbumia in ONE call — creates missing \" +\n \"keys and upserts translations (idempotent). Accepts nested or flat JSON. \" +\n \"Language/namespace are inferred from the path (<lang>/<namespace>.json) \" +\n \"or forced with --language / --namespace.\",\n )\n .argument(\"<files...>\", \"i18next JSON file(s), e.g. locales/fr/common.json or fr.json\")\n .option(\"--language <code>\", \"Force the language code for every file\")\n .option(\"--namespace <slug>\", \"Force the namespace slug for every file\")\n .option(\"--status <status>\", \"draft | translated (default: translated)\")\n .option(\"--version <slug>\", \"Target version slug (default: production version)\")\n .option(\"--dry-run\", \"Print what would be imported without sending\", false)\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (\n files: string[],\n opts: {\n language?: string;\n namespace?: string;\n status?: string;\n version?: string;\n dryRun: boolean;\n host?: string;\n },\n ) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n\n // namespace -> language_code -> tree\n const byNs = new Map<string, Record<string, I18nextTree>>();\n let totalLeaves = 0;\n for (const f of files) {\n const { lang, ns } = resolveLangNs(f, opts.language, opts.namespace);\n const tree = await readTree(f);\n totalLeaves += countLeaves(tree);\n const langs = byNs.get(ns) ?? {};\n if (langs[lang]) {\n throw new Error(`two input files map to namespace=${ns} language=${lang} — merge them first`);\n }\n langs[lang] = tree;\n byNs.set(ns, langs);\n console.log(` ${f} -> ${ns} / ${lang}`);\n }\n\n const body: ImportBody = {\n namespaces: [...byNs.entries()].map(([namespace, translations]) => ({\n namespace,\n translations,\n })),\n };\n if (opts.status === \"draft\" || opts.status === \"translated\") body.status = opts.status;\n if (opts.version) body.version = opts.version;\n\n if (opts.dryRun) {\n console.log(\n `\\n(dry-run) would import ${totalLeaves} value(s) across ${body.namespaces.length} ` +\n \"namespace(s); nothing sent.\",\n );\n return;\n }\n\n const report = await importBundle(ctx, body);\n console.log(\"\");\n for (const line of summariseImport(report)) console.log(line);\n if (report.errors?.length || report.glossary_violations?.length) process.exitCode = 1;\n },\n );\n","import { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nimport { Command } from \"commander\";\n\nimport { CONFIG_FILENAME, writeConfig } from \"../config.js\";\n\nexport const initCommand = new Command(\"init\")\n .description(\"Scaffold a sonenta.config.json in the current directory.\")\n .option(\"--host <url>\", \"API base URL\", \"https://api.sonenta.com\")\n .option(\"--project <uuid>\", \"Project UUID\")\n .option(\"--version <slug>\", \"Version slug (default: main)\", \"main\")\n .option(\"--force\", \"Overwrite an existing sonenta.config.json\", false)\n .action(\n async (opts: { host: string; project?: string; version: string; force: boolean }) => {\n const path = resolve(process.cwd(), CONFIG_FILENAME);\n if (existsSync(path) && !opts.force) {\n console.error(\n `${CONFIG_FILENAME} already exists at ${path}. Pass --force to overwrite.`,\n );\n process.exit(1);\n }\n const written = await writeConfig({\n host: opts.host,\n project_uuid: opts.project,\n version_slug: opts.version,\n });\n console.log(`Wrote ${written}`);\n if (!opts.project) {\n console.log(\n \"Tip: pass --project <uuid> to bind this directory to a specific project \" +\n \"(or edit project_uuid in the file later).\",\n );\n }\n },\n );\n","import { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { listKeys } from \"../mcp.js\";\n\nexport const keysCommand = new Command(\"keys\")\n .description(\"Inspect translation keys for the current project.\")\n .addCommand(\n new Command(\"list\")\n .description(\"List keys for the configured project (addressed by namespace slug + key name).\")\n .option(\"--namespace <slug>\", \"Filter by namespace slug\")\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(async (opts: { namespace?: string; host?: string }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const items = await listKeys(ctx, { namespace: opts.namespace });\n console.log(`total: ${items.length}`);\n for (const k of items) console.log(` ${k.namespace_slug}/${k.key_name}`);\n }),\n );\n","import { Command } from \"commander\";\n\nimport { setHostEntry } from \"../credentials.js\";\nimport { promptLine, promptSecret } from \"../prompt.js\";\n\nconst TOKEN_REGEX = /^vrb_[a-z]+_[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+$/;\n\nexport const loginCommand = new Command(\"login\")\n .description(\n \"Store an API key for a host. Token resolution order: --token, \" +\n \"SONENTA_TOKEN env, then interactive prompt (TTY only).\",\n )\n .option(\"--host <url>\", \"API base URL\", \"https://api.sonenta.com\")\n .option(\"--token <vrb_live_…>\", \"API key token (prefix.secret form)\")\n .option(\"--email <email>\", \"User email associated with the token (optional)\")\n .option(\"--default\", \"Set this host as the default for future commands\", false)\n .action(async (opts: { host: string; token?: string; email?: string; default?: boolean }) => {\n let host = opts.host;\n if (!host && process.stdin.isTTY) {\n host = (await promptLine(\"Host (default https://api.sonenta.com): \")) || \"https://api.sonenta.com\";\n }\n let token = opts.token ?? (process.env.SONENTA_TOKEN ?? process.env.VERBUMIA_TOKEN) ?? \"\";\n if (!token && process.stdin.isTTY) {\n token = await promptSecret(`API token for ${host}: `);\n }\n if (!token) {\n console.error(\n \"sonenta login: token required. Pass --token, set SONENTA_TOKEN, or run from a TTY for the interactive prompt.\",\n );\n process.exit(1);\n }\n if (!TOKEN_REGEX.test(token)) {\n console.error(\n \"sonenta login: token shape doesn't match `vrb_<env>_<prefix>.<secret>`. \" +\n \"Generate one in the dashboard at Org Settings → API Keys.\",\n );\n process.exit(1);\n }\n await setHostEntry(\n host,\n { api_key: token, user_email: opts.email },\n { makeDefault: opts.default },\n );\n console.log(`Stored credentials for ${host}.`);\n });\n","import { createInterface } from \"node:readline\";\n\n/**\n * Read a line from stdin. Used for interactive prompts when --token / --host\n * aren't passed on the CLI. Returns \"\" if stdin isn't a TTY (so tests + piped\n * usage don't hang waiting for input that will never arrive).\n */\nexport async function promptLine(message: string): Promise<string> {\n if (!process.stdin.isTTY) return \"\";\n const rl = createInterface({ input: process.stdin, output: process.stdout });\n try {\n return await new Promise<string>((resolve) => {\n rl.question(message, (answer) => resolve(answer.trim()));\n });\n } finally {\n rl.close();\n }\n}\n\nconst CTRL_C = 0x03;\nconst BACKSPACE = 0x08;\nconst DEL = 0x7f;\nconst CR = 0x0d;\nconst LF = 0x0a;\n\n/**\n * Same as promptLine but masks each echoed character with `*`. If stdin\n * isn't a TTY we return \"\" rather than echoing the secret.\n */\nexport async function promptSecret(message: string): Promise<string> {\n if (!process.stdin.isTTY) return \"\";\n process.stdout.write(message);\n process.stdin.setRawMode(true);\n process.stdin.resume();\n return await new Promise<string>((resolve) => {\n let buffer = \"\";\n const onData = (chunk: Buffer): void => {\n for (const byte of chunk) {\n if (byte === CR || byte === LF) {\n process.stdout.write(\"\\n\");\n process.stdin.removeListener(\"data\", onData);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n resolve(buffer);\n return;\n }\n if (byte === CTRL_C) {\n process.stdout.write(\"\\n\");\n process.stdin.removeListener(\"data\", onData);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n process.exit(130);\n }\n if (byte === BACKSPACE || byte === DEL) {\n if (buffer.length > 0) {\n buffer = buffer.slice(0, -1);\n process.stdout.write(\"\\b \\b\");\n }\n continue;\n }\n buffer += String.fromCharCode(byte);\n process.stdout.write(\"*\");\n }\n };\n process.stdin.on(\"data\", onData);\n });\n}\n","import { Command } from \"commander\";\n\nimport { readCredentials, removeHost } from \"../credentials.js\";\n\nexport const logoutCommand = new Command(\"logout\")\n .description(\"Remove stored credentials for a host (default: the current default host).\")\n .option(\"--host <url>\", \"Host to forget. Omit to forget the current default.\")\n .action(async (opts: { host?: string }) => {\n const creds = await readCredentials();\n const target = opts.host ?? creds.default;\n if (!target) {\n console.log(\"Nothing to forget — no credentials stored.\");\n return;\n }\n const removed = await removeHost(target);\n if (!removed) {\n console.log(`No credentials stored for ${target}.`);\n return;\n }\n console.log(`Forgot credentials for ${target}.`);\n });\n","import { Command } from \"commander\";\n\nimport { apiRequest, resolveContext } from \"../api.js\";\n\ninterface MissingKey {\n uuid: string;\n namespace_slug: string;\n language_code: string;\n key: string;\n source_value: string | null;\n count: number;\n status: string;\n first_seen: string;\n last_seen: string;\n}\n\ninterface MissingKeysPage {\n items: MissingKey[];\n cursor_next: string | null;\n total: number;\n}\n\nexport const missingCommand = new Command(\"missing\")\n .description(\n \"List runtime-detected missing keys for the configured project. Requires \" +\n \"the API key to carry the `mcp:*` scope.\",\n )\n .option(\"--namespace <slug>\", \"Filter by namespace slug\")\n .option(\"--language <code>\", \"Filter by language code\")\n .option(\"--status <state>\", \"Filter by status (open|resolved|...)\")\n .option(\"--limit <n>\", \"Page size (1-200, default 50)\", \"50\")\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: {\n namespace?: string;\n language?: string;\n status?: string;\n limit: string;\n host?: string;\n }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n if (!ctx.projectUuid) {\n console.error(\n \"sonenta missing: no project_uuid configured. Run `sonenta init --project <uuid>`.\",\n );\n process.exit(1);\n }\n const params = new URLSearchParams();\n params.set(\"limit\", opts.limit);\n if (opts.namespace) params.set(\"namespace\", opts.namespace);\n if (opts.language) params.set(\"language_code\", opts.language);\n if (opts.status) params.set(\"status\", opts.status);\n const page = await apiRequest<MissingKeysPage>(\n ctx,\n `/v1/mcp/projects/${ctx.projectUuid}/missing-keys?${params.toString()}`,\n );\n console.log(`total: ${page.total}`);\n for (const m of page.items) {\n const sample = m.source_value ? ` ⟶ \"${m.source_value}\"` : \"\";\n console.log(\n ` ${m.namespace_slug}/${m.key} (${m.language_code}, count=${m.count}, ${m.status})${sample}`,\n );\n }\n if (page.cursor_next) {\n console.log(`(more — re-run with --cursor ${page.cursor_next})`);\n }\n },\n );\n","import { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { listProjects } from \"../mcp.js\";\n\nexport const projectsCommand = new Command(\"projects\")\n .description(\"Inspect Verbumia projects accessible to your API key.\")\n .addCommand(\n new Command(\"list\")\n .description(\"List the projects this API key can reach.\")\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(async (opts: { host?: string }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const items = await listProjects(ctx);\n if (items.length === 0) {\n console.log(\"No projects visible to this key (scoped or revoked?).\");\n return;\n }\n for (const p of items) {\n const slug = p.slug ? ` ${p.slug}` : \"\";\n const src = p.source_language ? ` src=${p.source_language}` : \"\";\n console.log(` ${p.uuid}${slug} ${p.name ?? \"\"}${src}`);\n }\n }),\n );\n","import { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { DEFAULT_LOCALES_DIR, type FlatTranslations, writeLocaleFile } from \"../locales.js\";\nimport { getProjectInfo, listKeys } from \"../mcp.js\";\n\nexport const pullCommand = new Command(\"pull\")\n .description(\n \"Pull translations from Verbumia into locales/<lang>/<namespace>.json \" +\n \"(flat dot-notation). Overwrites local files — pair with `git status`.\",\n )\n .option(\"--language <code>\", \"Restrict to a single language code\")\n .option(\"--namespace <slug>\", \"Restrict to a single namespace slug\")\n .option(\"--dest <dir>\", \"Output directory\", DEFAULT_LOCALES_DIR)\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: { language?: string; namespace?: string; dest: string; host?: string }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n let languages: string[];\n if (opts.language) {\n languages = [opts.language];\n } else {\n languages = (await getProjectInfo(ctx)).languages;\n if (languages.length === 0) {\n console.error(\"sonenta pull: the project reports no languages.\");\n process.exit(1);\n }\n }\n\n let totalKeys = 0;\n let totalFiles = 0;\n for (const lang of languages) {\n const items = await listKeys(ctx, { languageCode: lang, namespace: opts.namespace });\n const byNs = new Map<string, FlatTranslations>();\n for (const it of items) {\n const tr = it.translations?.find((t) => t.language_code === lang);\n if (!tr || tr.value === \"\") continue;\n const map = byNs.get(it.namespace_slug) ?? {};\n map[it.key_name] = tr.value;\n byNs.set(it.namespace_slug, map);\n }\n for (const [ns, map] of byNs) {\n const path = await writeLocaleFile(opts.dest, lang, ns, map);\n totalKeys += Object.keys(map).length;\n totalFiles++;\n console.log(` ${path} ${Object.keys(map).length} keys`);\n }\n }\n console.log(`pulled ${totalKeys} translation(s) across ${totalFiles} file(s)`);\n },\n );\n","import { promises as fs } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\n\n/**\n * On-disk locales layout. V1 is flat: one JSON per (lang, namespace) under\n * the configured locales directory:\n *\n * locales/\n * en/\n * common.json // { \"hello.title\": \"Hello\", ... }\n * errors.json\n * fr/\n * common.json\n *\n * Keys inside each file are flat dot-notation, NOT nested objects. This\n * matches the editor surface 1:1 and keeps push/pull idempotent.\n */\n\nexport const DEFAULT_LOCALES_DIR = \"locales\";\n\nexport type FlatTranslations = Record<string, string>;\n\nexport async function listLocaleFiles(\n rootDir: string,\n): Promise<{ lang: string; namespace: string; path: string }[]> {\n const root = resolve(rootDir);\n let langDirs: string[];\n try {\n langDirs = await fs.readdir(root);\n } catch {\n return [];\n }\n const out: { lang: string; namespace: string; path: string }[] = [];\n for (const lang of langDirs) {\n const langPath = join(root, lang);\n let stat;\n try {\n stat = await fs.stat(langPath);\n } catch {\n continue;\n }\n if (!stat.isDirectory()) continue;\n const files = await fs.readdir(langPath);\n for (const f of files) {\n if (!f.endsWith(\".json\")) continue;\n out.push({ lang, namespace: f.replace(/\\.json$/, \"\"), path: join(langPath, f) });\n }\n }\n return out;\n}\n\nexport async function readLocaleFile(path: string): Promise<FlatTranslations> {\n const raw = await fs.readFile(path, \"utf8\");\n const parsed = JSON.parse(raw);\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(`${path} is not a flat object`);\n }\n const out: FlatTranslations = {};\n for (const [k, v] of Object.entries(parsed)) {\n if (typeof v !== \"string\") {\n throw new Error(`${path}: key \"${k}\" is not a string (V1 flat layout only)`);\n }\n out[k] = v;\n }\n return out;\n}\n\nexport async function writeLocaleFile(\n rootDir: string,\n lang: string,\n namespace: string,\n values: FlatTranslations,\n): Promise<string> {\n const dir = join(rootDir, lang);\n await fs.mkdir(dir, { recursive: true });\n const path = join(dir, `${namespace}.json`);\n // Sort keys for deterministic diffs.\n const sorted = Object.fromEntries(\n Object.entries(values).sort(([a], [b]) => a.localeCompare(b)),\n );\n await fs.writeFile(path, JSON.stringify(sorted, null, 2) + \"\\n\", \"utf8\");\n return path;\n}\n\nexport interface DiffResult {\n added: string[]; // local-only — push will create\n removed: string[]; // remote-only — push leaves alone (V1 doesn't delete)\n changed: { key: string; local: string; remote: string }[];\n unchanged: number;\n}\n\nexport function diffFlat(local: FlatTranslations, remote: FlatTranslations): DiffResult {\n const added: string[] = [];\n const removed: string[] = [];\n const changed: { key: string; local: string; remote: string }[] = [];\n let unchanged = 0;\n\n for (const [k, v] of Object.entries(local)) {\n if (!(k in remote)) {\n added.push(k);\n } else if (remote[k] !== v) {\n changed.push({ key: k, local: v, remote: remote[k]! });\n } else {\n unchanged++;\n }\n }\n for (const k of Object.keys(remote)) {\n if (!(k in local)) removed.push(k);\n }\n return { added, removed, changed, unchanged };\n}\n","import { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { DEFAULT_LOCALES_DIR, listLocaleFiles, readLocaleFile } from \"../locales.js\";\nimport { type ImportBody, importBundle, summariseImport } from \"../mcp.js\";\n\nexport const pushCommand = new Command(\"push\")\n .description(\n \"Push the whole local locales/ tree to Verbumia in ONE import call — \" +\n \"creates missing keys and upserts translations (idempotent). Reads \" +\n \"locales/<lang>/<namespace>.json (flat dot-notation).\",\n )\n .option(\"--language <code>\", \"Restrict to a single language code\")\n .option(\"--namespace <slug>\", \"Restrict to a single namespace slug\")\n .option(\"--src <dir>\", \"Locales directory\", DEFAULT_LOCALES_DIR)\n .option(\"--status <status>\", \"draft | translated (default: translated)\")\n .option(\"--version <slug>\", \"Target version slug (default: production version)\")\n .option(\"--dry-run\", \"Print what would be pushed without sending\", false)\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: {\n language?: string;\n namespace?: string;\n src: string;\n status?: string;\n version?: string;\n dryRun: boolean;\n host?: string;\n }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const files = (await listLocaleFiles(opts.src)).filter((f) => {\n if (opts.language && f.lang !== opts.language) return false;\n if (opts.namespace && f.namespace !== opts.namespace) return false;\n return true;\n });\n if (files.length === 0) {\n console.log(`No locale files found under ${opts.src}/`);\n return;\n }\n\n // namespace -> language_code -> flat map\n const byNs = new Map<string, Record<string, Record<string, string>>>();\n let totalKeys = 0;\n for (const f of files) {\n const flat = await readLocaleFile(f.path);\n totalKeys += Object.keys(flat).length;\n const langs = byNs.get(f.namespace) ?? {};\n langs[f.lang] = flat;\n byNs.set(f.namespace, langs);\n console.log(` ${f.lang}/${f.namespace}.json ${Object.keys(flat).length} keys`);\n }\n\n const body: ImportBody = {\n namespaces: [...byNs.entries()].map(([namespace, translations]) => ({\n namespace,\n translations,\n })),\n };\n if (opts.status === \"draft\" || opts.status === \"translated\") body.status = opts.status;\n if (opts.version) body.version = opts.version;\n\n if (opts.dryRun) {\n console.log(\n `\\n(dry-run) would push ${totalKeys} key(s) across ${body.namespaces.length} ` +\n \"namespace(s); nothing sent.\",\n );\n return;\n }\n\n const report = await importBundle(ctx, body);\n console.log(\"\");\n for (const line of summariseImport(report)) console.log(line);\n if (report.errors?.length || report.glossary_violations?.length) process.exitCode = 1;\n },\n );\n","import { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { type PublishCdnBody, publishCdn } from \"../mcp.js\";\n\nexport const releasesCommand = new Command(\"releases\")\n .description(\"Manage CDN releases for the project.\")\n .addCommand(\n new Command(\"publish\")\n .description(\n \"Trigger a CDN release: build bundles for every (language, namespace) \" +\n \"and push them to the public CDN. Idempotent — unchanged bundles are \" +\n \"reused. Subscribed SDKs receive a live `translations_published` event.\",\n )\n .option(\"--language <code>\", \"Restrict to one language (default: all)\")\n .option(\"--namespace <slug>\", \"Restrict to one namespace (default: all)\")\n .option(\"--version <slug>\", \"Version slug (default: production version)\")\n .option(\"--dry-run\", \"Print the planned release without publishing\", false)\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: {\n language?: string;\n namespace?: string;\n version?: string;\n dryRun: boolean;\n host?: string;\n }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const scope =\n [\n opts.language && `language=${opts.language}`,\n opts.namespace && `namespace=${opts.namespace}`,\n opts.version && `version=${opts.version}`,\n ]\n .filter(Boolean)\n .join(\", \") || \"ALL languages + namespaces\";\n\n if (opts.dryRun) {\n console.log(`(dry-run) would publish a CDN release for ${scope}; nothing sent.`);\n return;\n }\n\n const body: PublishCdnBody = {};\n if (opts.language) body.language_code = opts.language;\n if (opts.namespace) body.namespace = opts.namespace;\n if (opts.version) body.version_slug = opts.version;\n const res = await publishCdn(ctx, body);\n console.log(`published CDN release for ${scope}`);\n console.log(JSON.stringify(res, null, 2));\n },\n ),\n );\n","import { promises as fs } from \"node:fs\";\n\nimport { Command } from \"commander\";\n\nimport { resolveContext } from \"../api.js\";\nimport { getProjectInfo, requireProject } from \"../mcp.js\";\n\ntype Tree = Record<string, unknown>;\ntype Bundles = Record<string, Record<string, Tree>>;\n\n/** Public CDN bundle URL — the exact path the SDK fetches at runtime. */\nexport function bundleUrl(\n cdnBase: string,\n project: string,\n version: string,\n lang: string,\n ns: string,\n): string {\n return `${cdnBase.replace(/\\/+$/, \"\")}/p/${project}/${version}/latest/${lang}/${ns}.json`;\n}\n\n/**\n * Render the snapshot module. The SDK (#757) reads `initialBundles` as the PURE\n * `Record<locale, Record<namespace, tree>>` map, so provenance lives in a\n * SEPARATE `meta` export — never mixed into `bundles` (otherwise the SDK would\n * treat `version`/`project` as locales).\n */\nexport function renderSnapshot(\n bundles: Bundles,\n meta: { project: string; version: string; cdn: string },\n format: \"ts\" | \"json\",\n): string {\n const json = JSON.stringify(bundles, null, 2);\n if (format === \"json\") return json + \"\\n\";\n return (\n \"// Generated by `sonenta snapshot` — do not edit by hand.\\n\" +\n \"// Build-time fallback for @sonenta/react-i18next:\\n\" +\n '// import { bundles } from \"./<this-file>\";\\n' +\n \"// <VerbumiaProvider initialBundles={bundles} />\\n\" +\n `export const bundles = ${json} as const;\\n\\n` +\n `export const meta = ${JSON.stringify(meta, null, 2)} as const;\\n\\n` +\n \"export default bundles;\\n\"\n );\n}\n\nasync function fetchBundle(url: string): Promise<Tree | null> {\n const res = await fetch(url, { headers: { Accept: \"application/json\" } });\n if (res.status === 404) return null; // bundle not published for this (lang, ns)\n if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${url}`);\n return (await res.json()) as Tree;\n}\n\nexport const snapshotCommand = new Command(\"snapshot\")\n .description(\n \"Generate a build-time translations snapshot for @sonenta/react-i18next \" +\n \"`initialBundles` (offline-first fallback). Fetches the PUBLIC CDN bundles \" +\n \"(exactly what the SDK loads at runtime) and assembles \" +\n \"Record<locale, Record<namespace, tree>>. Emits a .ts module (default) or .json.\",\n )\n .option(\"--language <code>\", \"Restrict to a single language code\")\n .option(\"--namespace <slug>\", \"Restrict to a single namespace slug\")\n .option(\"--version <slug>\", \"Version slug (default: the configured version_slug)\")\n .option(\"--format <fmt>\", \"ts | json (default: ts)\", \"ts\")\n .option(\"--cdn <base>\", \"CDN base URL\", \"https://cdn.sonenta.com\")\n .option(\"--out <file>\", \"Write to a file instead of stdout\")\n .option(\"--host <url>\", \"Override host (used to discover languages/namespaces)\")\n .action(\n async (opts: {\n language?: string;\n namespace?: string;\n version?: string;\n format: string;\n cdn: string;\n out?: string;\n host?: string;\n }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const project = requireProject(ctx);\n const version = opts.version ?? ctx.versionSlug;\n\n // Enumerate (language, namespace). Both pinned => no project-info call.\n let languages: string[];\n let namespaces: string[];\n if (opts.language && opts.namespace) {\n languages = [opts.language];\n namespaces = [opts.namespace];\n } else {\n const info = await getProjectInfo(ctx);\n languages = opts.language ? [opts.language] : info.languages;\n namespaces = opts.namespace ? [opts.namespace] : info.namespaces;\n if (languages.length === 0 || namespaces.length === 0) {\n throw new Error(\n \"could not enumerate languages/namespaces from project-info — \" +\n \"pass --language and --namespace explicitly.\",\n );\n }\n }\n\n const bundles: Bundles = {};\n let fetched = 0;\n let missing = 0;\n for (const lang of languages) {\n for (const ns of namespaces) {\n const tree = await fetchBundle(bundleUrl(opts.cdn, project, version, lang, ns));\n if (!tree) {\n missing++;\n continue;\n }\n (bundles[lang] ??= {})[ns] = tree;\n fetched++;\n }\n }\n\n const output = renderSnapshot(\n bundles,\n { project, version, cdn: opts.cdn.replace(/\\/+$/, \"\") },\n opts.format === \"json\" ? \"json\" : \"ts\",\n );\n\n if (opts.out) {\n await fs.writeFile(opts.out, output, \"utf8\");\n console.log(\n `wrote ${opts.out}: ${fetched} bundle(s)` +\n (missing ? `, ${missing} not published (404)` : \"\"),\n );\n } else {\n process.stdout.write(output);\n if (missing) console.error(`(${missing} bundle(s) not published)`);\n }\n },\n );\n","import { Command } from \"commander\";\n\nimport { type ApiContext, resolveContext } from \"../api.js\";\nimport {\n DEFAULT_LOCALES_DIR,\n diffFlat,\n type FlatTranslations,\n listLocaleFiles,\n readLocaleFile,\n} from \"../locales.js\";\nimport { getProjectInfo, listKeys } from \"../mcp.js\";\n\nexport const statusCommand = new Command(\"status\")\n .description(\"Diff local locales/ against the remote project state.\")\n .option(\"--language <code>\", \"Restrict to one language code\")\n .option(\"--namespace <slug>\", \"Restrict to one namespace slug\")\n .option(\"--src <dir>\", \"Locales directory\", DEFAULT_LOCALES_DIR)\n .option(\"--host <url>\", \"Override host (otherwise from config/credentials)\")\n .action(\n async (opts: { language?: string; namespace?: string; src: string; host?: string }) => {\n const ctx = await resolveContext({ hostOverride: opts.host });\n const knownLangs = new Set((await getProjectInfo(ctx)).languages);\n\n const files = (await listLocaleFiles(opts.src)).filter((f) => {\n if (opts.language && f.lang !== opts.language) return false;\n if (opts.namespace && f.namespace !== opts.namespace) return false;\n return true;\n });\n\n // Fetch remote once per language, grouped by namespace slug.\n const remoteByLang = new Map<string, Map<string, FlatTranslations>>();\n async function remoteFor(ctx2: ApiContext, lang: string): Promise<Map<string, FlatTranslations>> {\n const cached = remoteByLang.get(lang);\n if (cached) return cached;\n const m = new Map<string, FlatTranslations>();\n for (const it of await listKeys(ctx2, { languageCode: lang })) {\n const tr = it.translations?.find((t) => t.language_code === lang);\n if (!tr || tr.value === \"\") continue;\n const map = m.get(it.namespace_slug) ?? {};\n map[it.key_name] = tr.value;\n m.set(it.namespace_slug, map);\n }\n remoteByLang.set(lang, m);\n return m;\n }\n\n let totalAdded = 0;\n let totalRemoved = 0;\n let totalChanged = 0;\n let totalUnchanged = 0;\n\n for (const f of files) {\n if (knownLangs.size > 0 && !knownLangs.has(f.lang)) {\n console.log(`! ${f.lang}/${f.namespace}.json — language not in project, skipped`);\n continue;\n }\n const local = await readLocaleFile(f.path);\n const remote = (await remoteFor(ctx, f.lang)).get(f.namespace) ?? {};\n const d = diffFlat(local, remote);\n totalAdded += d.added.length;\n totalRemoved += d.removed.length;\n totalChanged += d.changed.length;\n totalUnchanged += d.unchanged;\n\n if (d.added.length === 0 && d.removed.length === 0 && d.changed.length === 0) {\n console.log(`= ${f.lang}/${f.namespace}.json (in sync, ${d.unchanged} keys)`);\n continue;\n }\n console.log(\n `~ ${f.lang}/${f.namespace}.json +${d.added.length} -${d.removed.length} ~${d.changed.length}`,\n );\n for (const k of d.added) console.log(` + ${k}`);\n for (const k of d.removed) console.log(` - ${k} (remote-only — push leaves untouched)`);\n for (const c of d.changed) console.log(` ~ ${c.key} \"${c.local}\" <- \"${c.remote}\"`);\n }\n console.log(\n `summary: +${totalAdded} -${totalRemoved} ~${totalChanged} unchanged=${totalUnchanged}`,\n );\n },\n );\n","import { Command } from \"commander\";\n\nimport { readCredentials } from \"../credentials.js\";\n\nexport const whoamiCommand = new Command(\"whoami\")\n .description(\"Show the configured default host + which API key is in use.\")\n .option(\"--host <url>\", \"Inspect a specific host instead of the default\")\n .action(async (opts: { host?: string }) => {\n const creds = await readCredentials();\n if (!creds.default && Object.keys(creds.hosts).length === 0) {\n console.log(\"Not logged in. Run `sonenta login --host <url> --token <…>`.\");\n process.exit(1);\n }\n const target = opts.host ?? creds.default;\n if (!target) {\n console.log(\"No default host set.\");\n process.exit(1);\n }\n const entry = creds.hosts[target];\n if (!entry) {\n console.log(`No credentials stored for ${target}.`);\n process.exit(1);\n }\n const masked = entry.api_key.replace(/\\.[\\s\\S]+$/, \".•••\");\n const envOverride = (process.env.SONENTA_TOKEN ?? process.env.VERBUMIA_TOKEN)?.trim();\n console.log(`host: ${target}${target === creds.default ? \" (default)\" : \"\"}`);\n console.log(`api_key: ${masked}${envOverride ? \" (overridden by SONENTA_TOKEN env)\" : \"\"}`);\n if (entry.user_email) console.log(`email: ${entry.user_email}`);\n const others = Object.keys(creds.hosts).filter((h) => h !== target);\n if (others.length) {\n console.log(`other: ${others.join(\", \")}`);\n }\n });\n"],"mappings":";;;AAAA,SAAS,WAAAA,iBAAe;;;ACAxB,SAAS,eAAe;;;ACAxB,SAAS,YAAY,UAAU;AAC/B,SAAS,eAAe;AAejB,IAAM,aAAa;AAW1B,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoHrB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2Ed,IAAM,SAAmC;AAAA,EAC9C,gBAAgB;AAAA,IACd,MAAM;AAAA,IACN,SACE;AAAA,IACF,SAAS;AAAA,EACX;AAAA,EACA,gBAAgB;AAAA,IACd,MAAM;AAAA,IACN,SACE;AAAA,IACF,SAAS;AAAA,EACX;AACF;AAEO,SAAS,aAAyB;AACvC,SAAO,OAAO,OAAO,MAAM;AAC7B;AAEO,SAAS,SAAS,MAAoC;AAC3D,SAAO,OAAO,IAAI;AACpB;AAGO,SAAS,iBAAiB,MAAc,UAAkB,QAAQ,IAAI,GAAW;AACtF,SAAO,QAAQ,SAAS,YAAY,GAAG,IAAI,KAAK;AAClD;AAEA,eAAsB,YAAY,MAAc,UAAkB,QAAQ,IAAI,GAAqB;AACjG,MAAI;AACF,UAAM,GAAG,OAAO,iBAAiB,MAAM,OAAO,CAAC;AAC/C,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOA,eAAsB,WACpB,MACA,OAA8C,CAAC,GAC9B;AACjB,QAAM,QAAQ,SAAS,IAAI;AAC3B,MAAI,CAAC,OAAO;AACV,UAAM,QAAQ,OAAO,KAAK,MAAM,EAAE,KAAK,IAAI;AAC3C,UAAM,IAAI,MAAM,kBAAkB,IAAI,iBAAiB,KAAK,EAAE;AAAA,EAChE;AACA,QAAM,UAAU,KAAK,WAAW,QAAQ,IAAI;AAC5C,QAAM,OAAO,iBAAiB,MAAM,OAAO;AAC3C,MAAI,CAAC,KAAK,OAAO;AACf,QAAI;AACF,YAAM,GAAG,OAAO,IAAI;AACpB,YAAM,IAAI;AAAA,QACR,GAAG,IAAI;AAAA,MACT;AAAA,IACF,SAAS,KAAK;AAGZ,UAAI,eAAe,SAAS,IAAI,QAAQ,SAAS,gBAAgB,EAAG,OAAM;AAAA,IAC5E;AAAA,EACF;AACA,QAAM,GAAG,MAAM,QAAQ,SAAS,UAAU,GAAG,EAAE,WAAW,KAAK,CAAC;AAChE,QAAM,GAAG,UAAU,MAAM,MAAM,SAAS,MAAM;AAC9C,SAAO;AACT;;;AD1RO,IAAM,gBAAgB,IAAI,QAAQ,QAAQ,EAC9C,YAAY,yEAAyE,EACrF;AAAA,EACC,IAAI,QAAQ,MAAM,EACf,YAAY,+CAA+C,EAC3D,OAAO,gBAAgB,gDAAgD,EACvE,OAAO,OAAO,SAA2B;AACxC,UAAM,UAAU,KAAK;AACrB,UAAM,SAAS,WAAW;AAC1B,YAAQ,IAAI,qBAAqB,OAAO,MAAM,IAAI;AAClD,eAAW,KAAK,QAAQ;AACtB,YAAM,YAAY,MAAM,YAAY,EAAE,MAAM,OAAO;AACnD,YAAM,OAAO,YAAY,qBAAgB;AACzC,cAAQ,IAAI,KAAK,EAAE,KAAK,OAAO,EAAE,CAAC,IAAI,IAAI,EAAE;AAC5C,cAAQ,IAAI,SAAS,EAAE,OAAO,EAAE;AAAA,IAClC;AACA,YAAQ,IAAI;AAAA,wCAA2C;AAAA,EACzD,CAAC;AACL,EACC;AAAA,EACC,IAAI,QAAQ,KAAK,EACd,YAAY,uEAAuE,EACnF,SAAS,UAAU,gCAAgC,EACnD,OAAO,gBAAgB,gDAAgD,EACvE,OAAO,WAAW,0CAA0C,KAAK,EACjE,OAAO,OAAO,MAAc,SAA2C;AACtE,UAAM,OAAO,MAAM,WAAW,MAAM,EAAE,SAAS,KAAK,KAAK,OAAO,KAAK,MAAM,CAAC;AAC5E,YAAQ,IAAI,SAAS,IAAI,EAAE;AAC3B,YAAQ;AAAA,MACN;AAAA,MAAS,IAAI;AAAA,IAGf;AACA,YAAQ,IAAI,cAAc,UAAU,GAAG;AAAA,EACzC,CAAC;AACL;;;AEvCF,SAAS,YAAYC,WAAU;AAC/B,SAAS,QAAAC,aAAY;AAErB,SAAS,WAAAC,gBAAe;;;ACHxB,SAAS,YAAYC,WAAU;AAC/B,SAAS,SAAS,WAAAC,gBAAe;AA4B1B,IAAM,kBAAkB;AACxB,IAAM,yBAAyB;AAEtC,IAAI,eAAe;AAEnB,eAAsB,eAAe,UAA0C;AAC7E,MAAI,MAAMA,SAAQ,QAAQ;AAG1B,SAAO,MAAM;AACX,eAAW,QAAQ,CAAC,iBAAiB,sBAAsB,GAAG;AAC5D,YAAM,YAAYA,SAAQ,KAAK,IAAI;AACnC,UAAI;AACF,cAAMD,IAAG,OAAO,SAAS;AACzB,YAAI,SAAS,0BAA0B,CAAC,cAAc;AACpD,yBAAe;AACf,kBAAQ;AAAA,YACN,GAAG,sBAAsB,sCAAiC,eAAe;AAAA,YAEzE,EAAE,MAAM,qBAAqB;AAAA,UAC/B;AAAA,QACF;AACA,eAAO;AAAA,MACT,QAAQ;AAAA,MAER;AAAA,IACF;AACA,UAAM,SAAS,QAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK,QAAO;AAC3B,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,WAAW,WAAmB,QAAQ,IAAI,GAG7D;AACD,QAAM,OAAO,MAAM,eAAe,QAAQ;AAC1C,MAAI,CAAC,KAAM,QAAO,EAAE,MAAM,MAAM,QAAQ,CAAC,EAAE;AAC3C,QAAM,MAAM,MAAMA,IAAG,SAAS,MAAM,MAAM;AAC1C,QAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,SAAO,EAAE,MAAM,QAAQ,OAAO;AAChC;AAEA,eAAsB,YACpB,QACA,YAAoB,QAAQ,IAAI,GACf;AAEjB,QAAM,OAAOC,SAAQ,WAAW,eAAe;AAC/C,QAAMD,IAAG,UAAU,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,MAAM;AACvE,SAAO;AACT;;;ACjFA,SAAS,YAAYE,WAAU;AAC/B,SAAS,eAAe;AACxB,SAAkB,YAAY;AAgCvB,IAAM,iBAAiB,MAAc,KAAK,QAAQ,GAAG,WAAW;AAChE,IAAM,kBAAkB,MAAc,KAAK,eAAe,GAAG,aAAa;AAEjF,IAAM,QAAyB,EAAE,OAAO,CAAC,EAAE;AAE3C,eAAsB,kBAA4C;AAChE,MAAI;AACF,UAAM,MAAM,MAAMA,IAAG,SAAS,gBAAgB,GAAG,MAAM;AACvD,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,CAAC,UAAU,OAAO,WAAW,YAAY,CAAC,OAAO,OAAO;AAC1D,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,SAAS,KAAc;AACrB,QAAK,KAA+B,SAAS,SAAU,QAAO,EAAE,OAAO,CAAC,EAAE;AAC1E,UAAM;AAAA,EACR;AACF;AAEA,eAAsB,iBAAiB,OAAuC;AAC5E,QAAM,MAAM,eAAe;AAC3B,QAAM,OAAO,gBAAgB;AAC7B,QAAMA,IAAG,MAAM,KAAK,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAGpD,QAAM,MAAM,GAAG,IAAI;AACnB,QAAMA,IAAG,UAAU,KAAK,KAAK,UAAU,OAAO,MAAM,CAAC,IAAI,MAAM,EAAE,MAAM,IAAM,CAAC;AAC9E,QAAMA,IAAG,OAAO,KAAK,IAAI;AAEzB,QAAMA,IAAG,MAAM,MAAM,GAAK;AAC1B,QAAMA,IAAG,MAAM,KAAK,GAAK,EAAE,MAAM,MAAM;AAAA,EAAC,CAAC;AAC3C;AAEA,eAAsB,aACpB,MACA,OACA,UAAqC,CAAC,GACvB;AACf,QAAM,QAAQ,MAAM,gBAAgB;AACpC,QAAM,MAAM,IAAI,IAAI;AACpB,MAAI,QAAQ,eAAe,CAAC,MAAM,QAAS,OAAM,UAAU;AAC3D,QAAM,iBAAiB,KAAK;AAC9B;AAEA,eAAsB,WAAW,MAAgC;AAC/D,QAAM,QAAQ,MAAM,gBAAgB;AACpC,MAAI,EAAE,QAAQ,MAAM,OAAQ,QAAO;AACnC,SAAO,MAAM,MAAM,IAAI;AACvB,MAAI,MAAM,YAAY,MAAM;AAC1B,UAAM,YAAY,OAAO,KAAK,MAAM,KAAK;AACzC,UAAM,UAAU,UAAU,CAAC;AAAA,EAC7B;AACA,QAAM,iBAAiB,KAAK;AAC5B,SAAO;AACT;AAEO,SAAS,iBACd,OACA,cACkD;AAClD,QAAM,OAAO,gBAAgB,MAAM;AACnC,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,EAAE,MAAM,MAAM;AACvB;;;ACzEA,eAAsB,eAAe,OAAuB,CAAC,GAAwB;AACnF,QAAM,EAAE,OAAO,IAAI,MAAM,WAAW,KAAK,OAAO,QAAQ,IAAI,CAAC;AAC7D,QAAM,QAAQ,MAAM,gBAAgB;AACpC,QAAM,OAAO,KAAK,gBAAgB,OAAO,QAAQ,MAAM;AACvD,MAAI,CAAC,MAAM;AACT,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAOA,QAAM,WAAW,QAAQ,IAAI,iBAAiB,QAAQ,IAAI;AAC1D,MAAI,SAA6B,YAAY,SAAS,KAAK,IAAI,SAAS,KAAK,IAAI;AACjF,MAAI,CAAC,QAAQ;AACX,UAAM,WAAW,iBAAiB,OAAO,IAAI;AAC7C,QAAI,CAAC,UAAU;AACb,YAAM,IAAI;AAAA,QACR,2BAA2B,IAAI,qDAAqD,IAAI;AAAA,MAC1F;AAAA,IACF;AACA,aAAS,SAAS,MAAM;AAAA,EAC1B;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,aAAa,OAAO;AAAA,IACpB,aAAa,OAAO,gBAAgB;AAAA,EACtC;AACF;AAEA,eAAsB,WACpB,KACA,MACA,OAAoB,CAAC,GACT;AACZ,QAAM,MAAM,GAAG,IAAI,KAAK,QAAQ,QAAQ,EAAE,CAAC,GAAG,IAAI;AAClD,QAAM,UAAU,IAAI,QAAQ,KAAK,OAAO;AACxC,UAAQ,IAAI,iBAAiB,UAAU,IAAI,MAAM,EAAE;AACnD,MAAI,KAAK,QAAQ,CAAC,QAAQ,IAAI,cAAc,GAAG;AAC7C,YAAQ,IAAI,gBAAgB,kBAAkB;AAAA,EAChD;AACA,QAAM,MAAM,MAAM,MAAM,KAAK,EAAE,GAAG,MAAM,QAAQ,CAAC;AACjD,MAAI,CAAC,IAAI,IAAI;AACX,UAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,MAAM,EAAE;AAC5C,UAAM,IAAI,MAAM,QAAQ,IAAI,MAAM,IAAI,IAAI,UAAU,OAAO,IAAI,KAAK,KAAK,MAAM,GAAG,GAAG,CAAC,EAAE;AAAA,EAC1F;AACA,MAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,SAAQ,MAAM,IAAI,KAAK;AACzB;;;AClEO,SAAS,UAAU,MAAe,MAAM,KAAW;AACxD,QAAM,OAAa,CAAC;AACpB,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,GAAG;AACzC,UAAM,QAAQ,EAAE,MAAM,GAAG;AACzB,QAAI,OAAa;AACjB,aAAS,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,KAAK;AACzC,YAAM,IAAI,MAAM,CAAC;AACjB,YAAM,WAAW,KAAK,CAAC;AACvB,UAAI,OAAO,aAAa,YAAY,aAAa,KAAM,MAAK,CAAC,IAAI,CAAC;AAClE,aAAO,KAAK,CAAC;AAAA,IACf;AACA,SAAK,MAAM,MAAM,SAAS,CAAC,CAAE,IAAI;AAAA,EACnC;AACA,SAAO;AACT;AAkBO,SAAS,SAAY,OAAa;AACvC,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC;AAC7D,MAAI,SAAS,OAAO,UAAU,UAAU;AACtC,UAAM,MAAM;AACZ,UAAM,MAA+B,CAAC;AACtC,eAAW,KAAK,OAAO,KAAK,GAAG,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,cAAc,CAAC,CAAC,EAAG,KAAI,CAAC,IAAI,SAAS,IAAI,CAAC,CAAC;AAC7F,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;AC1CO,SAAS,eAAe,KAAyB;AACtD,MAAI,CAAC,IAAI,aAAa;AACpB,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AACA,SAAO,IAAI;AACb;AAEA,SAAS,YAAY,KAAyB;AAC5C,SAAO,oBAAoB,eAAe,GAAG,CAAC;AAChD;AAWA,eAAsB,aAAa,KAAiB,QAAQ,KAAgC;AAC1F,QAAM,OAAO,MAAM;AAAA,IACjB;AAAA,IACA,0BAA0B,KAAK;AAAA,EACjC;AACA,SAAO,KAAK,SAAS,CAAC;AACxB;AASA,eAAsB,eAAe,KAAuC;AAC1E,QAAM,IAAI,MAAM,WAAoC,KAAK,YAAY,GAAG,CAAC;AACzE,QAAM,MACJ,OAAO,EAAE,oBAAoB,WACzB,EAAE,kBACD,EAAE,iBAAuC,QAAQ;AACxD,QAAM,QAAQ,MAAM,QAAQ,EAAE,SAAS,IAClC,EAAE,UAAwB;AAAA,IAAI,CAAC,MAC9B,OAAO,MAAM,WAAW,IAAM,EAAwB,QAAQ;AAAA,EAChE,IACA,CAAC;AACL,QAAM,KAAK,MAAM,QAAQ,EAAE,UAAU,IAChC,EAAE,WAAyB;AAAA,IAAI,CAAC,MAC/B,OAAO,MAAM,WAAW,IAAM,EAAwB,QAAQ;AAAA,EAChE,IACA,CAAC;AACL,SAAO;AAAA,IACL,iBAAiB;AAAA,IACjB,WAAW,MAAM,OAAO,OAAO;AAAA,IAC/B,YAAY,GAAG,OAAO,OAAO;AAAA,EAC/B;AACF;AAiBA,eAAsB,SACpB,KACA,OAAsD,CAAC,GACnC;AACpB,QAAM,MAAiB,CAAC;AACxB,MAAI,SAAwB;AAC5B,KAAG;AACD,UAAM,SAAS,IAAI,gBAAgB,EAAE,OAAO,MAAM,CAAC;AACnD,QAAI,KAAK,aAAc,QAAO,IAAI,iBAAiB,KAAK,YAAY;AACpE,QAAI,KAAK,UAAW,QAAO,IAAI,aAAa,KAAK,SAAS;AAC1D,QAAI,OAAQ,QAAO,IAAI,UAAU,MAAM;AACvC,UAAM,OAAO,MAAM;AAAA,MACjB;AAAA,MACA,GAAG,YAAY,GAAG,CAAC,SAAS,OAAO,SAAS,CAAC;AAAA,IAC/C;AACA,QAAI,KAAK,GAAI,KAAK,SAAS,CAAC,CAAE;AAC9B,aAAS,KAAK,eAAe;AAAA,EAC/B,SAAS;AACT,SAAO;AACT;AAwCA,eAAsB,aAAa,KAAiB,MAA+C;AACjG,SAAO,WAA+B,KAAK,GAAG,YAAY,GAAG,CAAC,mBAAmB;AAAA,IAC/E,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AACH;AAUA,eAAsB,WAAW,KAAiB,MAAwC;AACxF,SAAO,WAAW,KAAK,GAAG,YAAY,GAAG,CAAC,iBAAiB;AAAA,IACzD,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,IAAI;AAAA,EAC3B,CAAC;AACH;AAKO,SAAS,gBAAgB,GAAiC;AAC/D,QAAM,QAAQ;AAAA,IACZ,iBAAiB,EAAE,YAAY,aAAa,EAAE,WAAW;AAAA,IACzD,iBAAiB,EAAE,oBAAoB,aAAa,EAAE,oBAAoB,aAAa,EAAE,sBAAsB;AAAA,EACjH;AACA,MAAI,EAAE,mBAAoB,OAAM,KAAK,iBAAiB,EAAE,kBAAkB,SAAS;AACnF,MAAI,EAAE,QAAQ,QAAQ;AACpB,UAAM,KAAK,iBAAiB,EAAE,OAAO,MAAM,EAAE;AAC7C,eAAW,KAAK,EAAE,OAAQ,OAAM,KAAK,OAAO,EAAE,SAAS,IAAI,EAAE,aAAa,KAAK,EAAE,IAAI,EAAE;AAAA,EACzF;AACA,MAAI,EAAE,qBAAqB,QAAQ;AACjC,UAAM,KAAK,iBAAiB,EAAE,oBAAoB,MAAM,eAAe;AACvE,eAAW,KAAK,EAAE,qBAAqB;AACrC,YAAM,KAAK,YAAO,EAAE,SAAS,IAAI,EAAE,aAAa,IAAI,EAAE,GAAG,KAAK,EAAE,SAAS,KAAK,EAAE,IAAI,GAAG;AAAA,IACzF;AAAA,EACF;AACA,SAAO;AACT;;;ALjLA,eAAe,QACb,KACA,WACA,WACoB;AACpB,QAAM,MAAiB,CAAC;AACxB,aAAW,QAAQ,WAAW;AAC5B,UAAM,QAAQ,MAAM,SAAS,KAAK,EAAE,cAAc,MAAM,UAAU,CAAC;AACnE,eAAW,MAAM,OAAO;AACtB,YAAM,KAAK,GAAG,cAAc,KAAK,CAAC,MAAM,EAAE,kBAAkB,IAAI;AAChE,UAAI,CAAC,MAAM,GAAG,UAAU,GAAI;AAC5B,OAAC,IAAI,IAAI,MAAM,CAAC,GAAG,GAAG,cAAc,MAAM,CAAC;AAC3C,UAAI,IAAI,EAAG,GAAG,cAAc,EAAG,GAAG,QAAQ,IAAI,GAAG;AAAA,IACnD;AAAA,EACF;AACA,SAAO;AACT;AAEO,IAAM,gBAAgB,IAAIC,SAAQ,QAAQ,EAC9C;AAAA,EACC;AAGF,EACC,OAAO,qBAAqB,oCAAoC,EAChE,OAAO,sBAAsB,qCAAqC,EAClE,OAAO,YAAY,iDAAiD,KAAK,EACzE,OAAO,eAAe,2CAA2C,EACjE,OAAO,gBAAgB,mDAAmD,EAC1E;AAAA,EACC,OAAO,SAMD;AACJ,UAAM,MAAM,MAAM,eAAe,EAAE,cAAc,KAAK,KAAK,CAAC;AAC5D,UAAM,YAAY,KAAK,WAAW,CAAC,KAAK,QAAQ,KAAK,MAAM,eAAe,GAAG,GAAG;AAChF,UAAM,YAAY,MAAM,QAAQ,KAAK,WAAW,KAAK,SAAS;AAC9D,UAAM,QAAQ,CAAC,SAA4B,KAAK,SAAS,SAAS,UAAU,IAAI,CAAC,IAAI,SAAS,IAAI;AAElG,QAAI,KAAK,KAAK;AACZ,UAAI,QAAQ;AACZ,iBAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,SAAS,GAAG;AACnD,mBAAW,CAAC,IAAI,IAAI,KAAK,OAAO,QAAQ,GAAG,GAAG;AAC5C,gBAAM,MAAMC,MAAK,KAAK,KAAK,IAAI;AAC/B,gBAAMC,IAAG,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACvC,gBAAM,IAAID,MAAK,KAAK,GAAG,EAAE,OAAO;AAChC,gBAAMC,IAAG,UAAU,GAAG,KAAK,UAAU,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,MAAM,MAAM;AACzE,kBAAQ,IAAI,KAAK,CAAC,KAAK,OAAO,KAAK,IAAI,EAAE,MAAM,OAAO;AACtD;AAAA,QACF;AAAA,MACF;AACA,cAAQ,IAAI,YAAY,KAAK,UAAU;AACvC;AAAA,IACF;AAEA,UAAM,OAAgD,CAAC;AACvD,eAAW,CAAC,MAAM,GAAG,KAAK,OAAO,QAAQ,SAAS,GAAG;AACnD,WAAK,IAAI,IAAI,CAAC;AACd,iBAAW,CAAC,IAAI,IAAI,KAAK,OAAO,QAAQ,GAAG,EAAG,MAAK,IAAI,EAAG,EAAE,IAAI,MAAM,IAAI;AAAA,IAC5E;AACA,YAAQ,OAAO,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,IAAI,IAAI;AAAA,EAC3D;AACF;;;AM7EF,SAAS,YAAYC,WAAU;AAC/B,SAAS,UAAU,WAAAC,gBAAe;AAElC,SAAS,WAAAC,gBAAe;AAajB,SAAS,cACd,UACA,SACA,OAC8B;AAC9B,QAAM,OAAO,SAAS,QAAQ,EAAE,QAAQ,YAAY,EAAE;AACtD,QAAM,SAAS,SAASC,SAAQ,QAAQ,CAAC;AACzC,QAAM,aAAa,WAAW,MAAM,WAAW,OAAO,WAAW;AACjE,QAAM,OAAO,YAAY,aAAa,SAAS;AAC/C,QAAM,KAAK,UAAU,aAAa,OAAO;AACzC,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,kCAAkC,QAAQ,yBAAoB;AACzF,MAAI,CAAC,IAAI;AACP,UAAM,IAAI;AAAA,MACR,mCAAmC,QAAQ;AAAA,IAE7C;AAAA,EACF;AACA,SAAO,EAAE,MAAM,GAAG;AACpB;AAEA,eAAe,SAAS,UAAwC;AAC9D,QAAM,SAAS,KAAK,MAAM,MAAMC,IAAG,SAAS,UAAU,MAAM,CAAC;AAC7D,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAClE,UAAM,IAAI,MAAM,GAAG,QAAQ,uBAAuB;AAAA,EACpD;AACA,SAAO;AACT;AAEA,SAAS,YAAY,MAA2B;AAC9C,MAAI,IAAI;AACR,aAAW,KAAK,OAAO,OAAO,IAAI,GAAG;AACnC,QAAI,KAAK,OAAO,MAAM,YAAY,CAAC,MAAM,QAAQ,CAAC,EAAG,MAAK,YAAY,CAAgB;AAAA,QACjF,MAAK;AAAA,EACZ;AACA,SAAO;AACT;AAEO,IAAM,gBAAgB,IAAIC,SAAQ,QAAQ,EAC9C;AAAA,EACC;AAIF,EACC,SAAS,cAAc,8DAA8D,EACrF,OAAO,qBAAqB,wCAAwC,EACpE,OAAO,sBAAsB,yCAAyC,EACtE,OAAO,qBAAqB,0CAA0C,EACtE,OAAO,oBAAoB,mDAAmD,EAC9E,OAAO,aAAa,gDAAgD,KAAK,EACzE,OAAO,gBAAgB,mDAAmD,EAC1E;AAAA,EACC,OACE,OACA,SAQG;AACH,UAAM,MAAM,MAAM,eAAe,EAAE,cAAc,KAAK,KAAK,CAAC;AAG5D,UAAM,OAAO,oBAAI,IAAyC;AAC1D,QAAI,cAAc;AAClB,eAAW,KAAK,OAAO;AACrB,YAAM,EAAE,MAAM,GAAG,IAAI,cAAc,GAAG,KAAK,UAAU,KAAK,SAAS;AACnE,YAAM,OAAO,MAAM,SAAS,CAAC;AAC7B,qBAAe,YAAY,IAAI;AAC/B,YAAM,QAAQ,KAAK,IAAI,EAAE,KAAK,CAAC;AAC/B,UAAI,MAAM,IAAI,GAAG;AACf,cAAM,IAAI,MAAM,oCAAoC,EAAE,aAAa,IAAI,0BAAqB;AAAA,MAC9F;AACA,YAAM,IAAI,IAAI;AACd,WAAK,IAAI,IAAI,KAAK;AAClB,cAAQ,IAAI,KAAK,CAAC,SAAS,EAAE,MAAM,IAAI,EAAE;AAAA,IAC3C;AAEA,UAAM,OAAmB;AAAA,MACvB,YAAY,CAAC,GAAG,KAAK,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,WAAW,YAAY,OAAO;AAAA,QAClE;AAAA,QACA;AAAA,MACF,EAAE;AAAA,IACJ;AACA,QAAI,KAAK,WAAW,WAAW,KAAK,WAAW,aAAc,MAAK,SAAS,KAAK;AAChF,QAAI,KAAK,QAAS,MAAK,UAAU,KAAK;AAEtC,QAAI,KAAK,QAAQ;AACf,cAAQ;AAAA,QACN;AAAA,yBAA4B,WAAW,oBAAoB,KAAK,WAAW,MAAM;AAAA,MAEnF;AACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,aAAa,KAAK,IAAI;AAC3C,YAAQ,IAAI,EAAE;AACd,eAAW,QAAQ,gBAAgB,MAAM,EAAG,SAAQ,IAAI,IAAI;AAC5D,QAAI,OAAO,QAAQ,UAAU,OAAO,qBAAqB,OAAQ,SAAQ,WAAW;AAAA,EACtF;AACF;;;ACvHF,SAAS,kBAAkB;AAC3B,SAAS,WAAAC,gBAAe;AAExB,SAAS,WAAAC,gBAAe;AAIjB,IAAM,cAAc,IAAIC,SAAQ,MAAM,EAC1C,YAAY,0DAA0D,EACtE,OAAO,gBAAgB,gBAAgB,yBAAyB,EAChE,OAAO,oBAAoB,cAAc,EACzC,OAAO,oBAAoB,gCAAgC,MAAM,EACjE,OAAO,WAAW,6CAA6C,KAAK,EACpE;AAAA,EACC,OAAO,SAA8E;AACnF,UAAM,OAAOC,SAAQ,QAAQ,IAAI,GAAG,eAAe;AACnD,QAAI,WAAW,IAAI,KAAK,CAAC,KAAK,OAAO;AACnC,cAAQ;AAAA,QACN,GAAG,eAAe,sBAAsB,IAAI;AAAA,MAC9C;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,UAAU,MAAM,YAAY;AAAA,MAChC,MAAM,KAAK;AAAA,MACX,cAAc,KAAK;AAAA,MACnB,cAAc,KAAK;AAAA,IACrB,CAAC;AACD,YAAQ,IAAI,SAAS,OAAO,EAAE;AAC9B,QAAI,CAAC,KAAK,SAAS;AACjB,cAAQ;AAAA,QACN;AAAA,MAEF;AAAA,IACF;AAAA,EACF;AACF;;;ACnCF,SAAS,WAAAC,gBAAe;AAKjB,IAAM,cAAc,IAAIC,SAAQ,MAAM,EAC1C,YAAY,mDAAmD,EAC/D;AAAA,EACC,IAAIA,SAAQ,MAAM,EACf,YAAY,gFAAgF,EAC5F,OAAO,sBAAsB,0BAA0B,EACvD,OAAO,gBAAgB,mDAAmD,EAC1E,OAAO,OAAO,SAAgD;AAC7D,UAAM,MAAM,MAAM,eAAe,EAAE,cAAc,KAAK,KAAK,CAAC;AAC5D,UAAM,QAAQ,MAAM,SAAS,KAAK,EAAE,WAAW,KAAK,UAAU,CAAC;AAC/D,YAAQ,IAAI,UAAU,MAAM,MAAM,EAAE;AACpC,eAAW,KAAK,MAAO,SAAQ,IAAI,KAAK,EAAE,cAAc,IAAI,EAAE,QAAQ,EAAE;AAAA,EAC1E,CAAC;AACL;;;AClBF,SAAS,WAAAC,gBAAe;;;ACAxB,SAAS,uBAAuB;AAOhC,eAAsB,WAAW,SAAkC;AACjE,MAAI,CAAC,QAAQ,MAAM,MAAO,QAAO;AACjC,QAAM,KAAK,gBAAgB,EAAE,OAAO,QAAQ,OAAO,QAAQ,QAAQ,OAAO,CAAC;AAC3E,MAAI;AACF,WAAO,MAAM,IAAI,QAAgB,CAACC,aAAY;AAC5C,SAAG,SAAS,SAAS,CAAC,WAAWA,SAAQ,OAAO,KAAK,CAAC,CAAC;AAAA,IACzD,CAAC;AAAA,EACH,UAAE;AACA,OAAG,MAAM;AAAA,EACX;AACF;AAEA,IAAM,SAAS;AACf,IAAM,YAAY;AAClB,IAAM,MAAM;AACZ,IAAM,KAAK;AACX,IAAM,KAAK;AAMX,eAAsB,aAAa,SAAkC;AACnE,MAAI,CAAC,QAAQ,MAAM,MAAO,QAAO;AACjC,UAAQ,OAAO,MAAM,OAAO;AAC5B,UAAQ,MAAM,WAAW,IAAI;AAC7B,UAAQ,MAAM,OAAO;AACrB,SAAO,MAAM,IAAI,QAAgB,CAACA,aAAY;AAC5C,QAAI,SAAS;AACb,UAAM,SAAS,CAAC,UAAwB;AACtC,iBAAW,QAAQ,OAAO;AACxB,YAAI,SAAS,MAAM,SAAS,IAAI;AAC9B,kBAAQ,OAAO,MAAM,IAAI;AACzB,kBAAQ,MAAM,eAAe,QAAQ,MAAM;AAC3C,kBAAQ,MAAM,WAAW,KAAK;AAC9B,kBAAQ,MAAM,MAAM;AACpB,UAAAA,SAAQ,MAAM;AACd;AAAA,QACF;AACA,YAAI,SAAS,QAAQ;AACnB,kBAAQ,OAAO,MAAM,IAAI;AACzB,kBAAQ,MAAM,eAAe,QAAQ,MAAM;AAC3C,kBAAQ,MAAM,WAAW,KAAK;AAC9B,kBAAQ,MAAM,MAAM;AACpB,kBAAQ,KAAK,GAAG;AAAA,QAClB;AACA,YAAI,SAAS,aAAa,SAAS,KAAK;AACtC,cAAI,OAAO,SAAS,GAAG;AACrB,qBAAS,OAAO,MAAM,GAAG,EAAE;AAC3B,oBAAQ,OAAO,MAAM,OAAO;AAAA,UAC9B;AACA;AAAA,QACF;AACA,kBAAU,OAAO,aAAa,IAAI;AAClC,gBAAQ,OAAO,MAAM,GAAG;AAAA,MAC1B;AAAA,IACF;AACA,YAAQ,MAAM,GAAG,QAAQ,MAAM;AAAA,EACjC,CAAC;AACH;;;AD7DA,IAAM,cAAc;AAEb,IAAM,eAAe,IAAIC,SAAQ,OAAO,EAC5C;AAAA,EACC;AAEF,EACC,OAAO,gBAAgB,gBAAgB,yBAAyB,EAChE,OAAO,6BAAwB,oCAAoC,EACnE,OAAO,mBAAmB,iDAAiD,EAC3E,OAAO,aAAa,oDAAoD,KAAK,EAC7E,OAAO,OAAO,SAA8E;AAC3F,MAAI,OAAO,KAAK;AAChB,MAAI,CAAC,QAAQ,QAAQ,MAAM,OAAO;AAChC,WAAQ,MAAM,WAAW,0CAA0C,KAAM;AAAA,EAC3E;AACA,MAAI,QAAQ,KAAK,UAAU,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,mBAAmB;AACvF,MAAI,CAAC,SAAS,QAAQ,MAAM,OAAO;AACjC,YAAQ,MAAM,aAAa,iBAAiB,IAAI,IAAI;AAAA,EACtD;AACA,MAAI,CAAC,OAAO;AACV,YAAQ;AAAA,MACN;AAAA,IACF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,CAAC,YAAY,KAAK,KAAK,GAAG;AAC5B,YAAQ;AAAA,MACN;AAAA,IAEF;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM;AAAA,IACJ;AAAA,IACA,EAAE,SAAS,OAAO,YAAY,KAAK,MAAM;AAAA,IACzC,EAAE,aAAa,KAAK,QAAQ;AAAA,EAC9B;AACA,UAAQ,IAAI,0BAA0B,IAAI,GAAG;AAC/C,CAAC;;;AE5CH,SAAS,WAAAC,gBAAe;AAIjB,IAAM,gBAAgB,IAAIC,SAAQ,QAAQ,EAC9C,YAAY,2EAA2E,EACvF,OAAO,gBAAgB,qDAAqD,EAC5E,OAAO,OAAO,SAA4B;AACzC,QAAM,QAAQ,MAAM,gBAAgB;AACpC,QAAM,SAAS,KAAK,QAAQ,MAAM;AAClC,MAAI,CAAC,QAAQ;AACX,YAAQ,IAAI,iDAA4C;AACxD;AAAA,EACF;AACA,QAAM,UAAU,MAAM,WAAW,MAAM;AACvC,MAAI,CAAC,SAAS;AACZ,YAAQ,IAAI,6BAA6B,MAAM,GAAG;AAClD;AAAA,EACF;AACA,UAAQ,IAAI,0BAA0B,MAAM,GAAG;AACjD,CAAC;;;ACpBH,SAAS,WAAAC,gBAAe;AAsBjB,IAAM,iBAAiB,IAAIC,SAAQ,SAAS,EAChD;AAAA,EACC;AAEF,EACC,OAAO,sBAAsB,0BAA0B,EACvD,OAAO,qBAAqB,yBAAyB,EACrD,OAAO,oBAAoB,sCAAsC,EACjE,OAAO,eAAe,iCAAiC,IAAI,EAC3D,OAAO,gBAAgB,mDAAmD,EAC1E;AAAA,EACC,OAAO,SAMD;AACJ,UAAM,MAAM,MAAM,eAAe,EAAE,cAAc,KAAK,KAAK,CAAC;AAC5D,QAAI,CAAC,IAAI,aAAa;AACpB,cAAQ;AAAA,QACN;AAAA,MACF;AACA,cAAQ,KAAK,CAAC;AAAA,IAChB;AACA,UAAM,SAAS,IAAI,gBAAgB;AACnC,WAAO,IAAI,SAAS,KAAK,KAAK;AAC9B,QAAI,KAAK,UAAW,QAAO,IAAI,aAAa,KAAK,SAAS;AAC1D,QAAI,KAAK,SAAU,QAAO,IAAI,iBAAiB,KAAK,QAAQ;AAC5D,QAAI,KAAK,OAAQ,QAAO,IAAI,UAAU,KAAK,MAAM;AACjD,UAAM,OAAO,MAAM;AAAA,MACjB;AAAA,MACA,oBAAoB,IAAI,WAAW,iBAAiB,OAAO,SAAS,CAAC;AAAA,IACvE;AACA,YAAQ,IAAI,UAAU,KAAK,KAAK,EAAE;AAClC,eAAW,KAAK,KAAK,OAAO;AAC1B,YAAM,SAAS,EAAE,eAAe,cAAS,EAAE,YAAY,MAAM;AAC7D,cAAQ;AAAA,QACN,KAAK,EAAE,cAAc,IAAI,EAAE,GAAG,MAAM,EAAE,aAAa,WAAW,EAAE,KAAK,KAAK,EAAE,MAAM,IAAI,MAAM;AAAA,MAC9F;AAAA,IACF;AACA,QAAI,KAAK,aAAa;AACpB,cAAQ,IAAI,qCAAgC,KAAK,WAAW,GAAG;AAAA,IACjE;AAAA,EACF;AACF;;;ACnEF,SAAS,WAAAC,gBAAe;AAKjB,IAAM,kBAAkB,IAAIC,SAAQ,UAAU,EAClD,YAAY,uDAAuD,EACnE;AAAA,EACC,IAAIA,SAAQ,MAAM,EACf,YAAY,2CAA2C,EACvD,OAAO,gBAAgB,mDAAmD,EAC1E,OAAO,OAAO,SAA4B;AACzC,UAAM,MAAM,MAAM,eAAe,EAAE,cAAc,KAAK,KAAK,CAAC;AAC5D,UAAM,QAAQ,MAAM,aAAa,GAAG;AACpC,QAAI,MAAM,WAAW,GAAG;AACtB,cAAQ,IAAI,uDAAuD;AACnE;AAAA,IACF;AACA,eAAW,KAAK,OAAO;AACrB,YAAM,OAAO,EAAE,OAAO,KAAK,EAAE,IAAI,KAAK;AACtC,YAAM,MAAM,EAAE,kBAAkB,SAAS,EAAE,eAAe,KAAK;AAC/D,cAAQ,IAAI,KAAK,EAAE,IAAI,GAAG,IAAI,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAG,EAAE;AAAA,IACzD;AAAA,EACF,CAAC;AACL;;;ACxBF,SAAS,WAAAC,iBAAe;;;ACAxB,SAAS,YAAYC,WAAU;AAC/B,SAAS,QAAAC,OAAM,WAAAC,gBAAe;AAiBvB,IAAM,sBAAsB;AAInC,eAAsB,gBACpB,SAC8D;AAC9D,QAAM,OAAOA,SAAQ,OAAO;AAC5B,MAAI;AACJ,MAAI;AACF,eAAW,MAAMF,IAAG,QAAQ,IAAI;AAAA,EAClC,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACA,QAAM,MAA2D,CAAC;AAClE,aAAW,QAAQ,UAAU;AAC3B,UAAM,WAAWC,MAAK,MAAM,IAAI;AAChC,QAAI;AACJ,QAAI;AACF,aAAO,MAAMD,IAAG,KAAK,QAAQ;AAAA,IAC/B,QAAQ;AACN;AAAA,IACF;AACA,QAAI,CAAC,KAAK,YAAY,EAAG;AACzB,UAAM,QAAQ,MAAMA,IAAG,QAAQ,QAAQ;AACvC,eAAW,KAAK,OAAO;AACrB,UAAI,CAAC,EAAE,SAAS,OAAO,EAAG;AAC1B,UAAI,KAAK,EAAE,MAAM,WAAW,EAAE,QAAQ,WAAW,EAAE,GAAG,MAAMC,MAAK,UAAU,CAAC,EAAE,CAAC;AAAA,IACjF;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAsB,eAAe,MAAyC;AAC5E,QAAM,MAAM,MAAMD,IAAG,SAAS,MAAM,MAAM;AAC1C,QAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,MAAM,GAAG;AAClE,UAAM,IAAI,MAAM,GAAG,IAAI,uBAAuB;AAAA,EAChD;AACA,QAAM,MAAwB,CAAC;AAC/B,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,MAAM,GAAG;AAC3C,QAAI,OAAO,MAAM,UAAU;AACzB,YAAM,IAAI,MAAM,GAAG,IAAI,UAAU,CAAC,yCAAyC;AAAA,IAC7E;AACA,QAAI,CAAC,IAAI;AAAA,EACX;AACA,SAAO;AACT;AAEA,eAAsB,gBACpB,SACA,MACA,WACA,QACiB;AACjB,QAAM,MAAMC,MAAK,SAAS,IAAI;AAC9B,QAAMD,IAAG,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACvC,QAAM,OAAOC,MAAK,KAAK,GAAG,SAAS,OAAO;AAE1C,QAAM,SAAS,OAAO;AAAA,IACpB,OAAO,QAAQ,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAAA,EAC9D;AACA,QAAMD,IAAG,UAAU,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,MAAM;AACvE,SAAO;AACT;AASO,SAAS,SAAS,OAAyB,QAAsC;AACtF,QAAM,QAAkB,CAAC;AACzB,QAAM,UAAoB,CAAC;AAC3B,QAAM,UAA4D,CAAC;AACnE,MAAI,YAAY;AAEhB,aAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC1C,QAAI,EAAE,KAAK,SAAS;AAClB,YAAM,KAAK,CAAC;AAAA,IACd,WAAW,OAAO,CAAC,MAAM,GAAG;AAC1B,cAAQ,KAAK,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,OAAO,CAAC,EAAG,CAAC;AAAA,IACvD,OAAO;AACL;AAAA,IACF;AAAA,EACF;AACA,aAAW,KAAK,OAAO,KAAK,MAAM,GAAG;AACnC,QAAI,EAAE,KAAK,OAAQ,SAAQ,KAAK,CAAC;AAAA,EACnC;AACA,SAAO,EAAE,OAAO,SAAS,SAAS,UAAU;AAC9C;;;ADxGO,IAAM,cAAc,IAAIG,UAAQ,MAAM,EAC1C;AAAA,EACC;AAEF,EACC,OAAO,qBAAqB,oCAAoC,EAChE,OAAO,sBAAsB,qCAAqC,EAClE,OAAO,gBAAgB,oBAAoB,mBAAmB,EAC9D,OAAO,gBAAgB,mDAAmD,EAC1E;AAAA,EACC,OAAO,SAAiF;AACtF,UAAM,MAAM,MAAM,eAAe,EAAE,cAAc,KAAK,KAAK,CAAC;AAC5D,QAAI;AACJ,QAAI,KAAK,UAAU;AACjB,kBAAY,CAAC,KAAK,QAAQ;AAAA,IAC5B,OAAO;AACL,mBAAa,MAAM,eAAe,GAAG,GAAG;AACxC,UAAI,UAAU,WAAW,GAAG;AAC1B,gBAAQ,MAAM,iDAAiD;AAC/D,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAAA,IACF;AAEA,QAAI,YAAY;AAChB,QAAI,aAAa;AACjB,eAAW,QAAQ,WAAW;AAC5B,YAAM,QAAQ,MAAM,SAAS,KAAK,EAAE,cAAc,MAAM,WAAW,KAAK,UAAU,CAAC;AACnF,YAAM,OAAO,oBAAI,IAA8B;AAC/C,iBAAW,MAAM,OAAO;AACtB,cAAM,KAAK,GAAG,cAAc,KAAK,CAAC,MAAM,EAAE,kBAAkB,IAAI;AAChE,YAAI,CAAC,MAAM,GAAG,UAAU,GAAI;AAC5B,cAAM,MAAM,KAAK,IAAI,GAAG,cAAc,KAAK,CAAC;AAC5C,YAAI,GAAG,QAAQ,IAAI,GAAG;AACtB,aAAK,IAAI,GAAG,gBAAgB,GAAG;AAAA,MACjC;AACA,iBAAW,CAAC,IAAI,GAAG,KAAK,MAAM;AAC5B,cAAM,OAAO,MAAM,gBAAgB,KAAK,MAAM,MAAM,IAAI,GAAG;AAC3D,qBAAa,OAAO,KAAK,GAAG,EAAE;AAC9B;AACA,gBAAQ,IAAI,KAAK,IAAI,KAAK,OAAO,KAAK,GAAG,EAAE,MAAM,OAAO;AAAA,MAC1D;AAAA,IACF;AACA,YAAQ,IAAI,UAAU,SAAS,0BAA0B,UAAU,UAAU;AAAA,EAC/E;AACF;;;AElDF,SAAS,WAAAC,iBAAe;AAMjB,IAAM,cAAc,IAAIC,UAAQ,MAAM,EAC1C;AAAA,EACC;AAGF,EACC,OAAO,qBAAqB,oCAAoC,EAChE,OAAO,sBAAsB,qCAAqC,EAClE,OAAO,eAAe,qBAAqB,mBAAmB,EAC9D,OAAO,qBAAqB,0CAA0C,EACtE,OAAO,oBAAoB,mDAAmD,EAC9E,OAAO,aAAa,8CAA8C,KAAK,EACvE,OAAO,gBAAgB,mDAAmD,EAC1E;AAAA,EACC,OAAO,SAQD;AACJ,UAAM,MAAM,MAAM,eAAe,EAAE,cAAc,KAAK,KAAK,CAAC;AAC5D,UAAM,SAAS,MAAM,gBAAgB,KAAK,GAAG,GAAG,OAAO,CAAC,MAAM;AAC5D,UAAI,KAAK,YAAY,EAAE,SAAS,KAAK,SAAU,QAAO;AACtD,UAAI,KAAK,aAAa,EAAE,cAAc,KAAK,UAAW,QAAO;AAC7D,aAAO;AAAA,IACT,CAAC;AACD,QAAI,MAAM,WAAW,GAAG;AACtB,cAAQ,IAAI,+BAA+B,KAAK,GAAG,GAAG;AACtD;AAAA,IACF;AAGA,UAAM,OAAO,oBAAI,IAAoD;AACrE,QAAI,YAAY;AAChB,eAAW,KAAK,OAAO;AACrB,YAAM,OAAO,MAAM,eAAe,EAAE,IAAI;AACxC,mBAAa,OAAO,KAAK,IAAI,EAAE;AAC/B,YAAM,QAAQ,KAAK,IAAI,EAAE,SAAS,KAAK,CAAC;AACxC,YAAM,EAAE,IAAI,IAAI;AAChB,WAAK,IAAI,EAAE,WAAW,KAAK;AAC3B,cAAQ,IAAI,KAAK,EAAE,IAAI,IAAI,EAAE,SAAS,UAAU,OAAO,KAAK,IAAI,EAAE,MAAM,OAAO;AAAA,IACjF;AAEA,UAAM,OAAmB;AAAA,MACvB,YAAY,CAAC,GAAG,KAAK,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,WAAW,YAAY,OAAO;AAAA,QAClE;AAAA,QACA;AAAA,MACF,EAAE;AAAA,IACJ;AACA,QAAI,KAAK,WAAW,WAAW,KAAK,WAAW,aAAc,MAAK,SAAS,KAAK;AAChF,QAAI,KAAK,QAAS,MAAK,UAAU,KAAK;AAEtC,QAAI,KAAK,QAAQ;AACf,cAAQ;AAAA,QACN;AAAA,uBAA0B,SAAS,kBAAkB,KAAK,WAAW,MAAM;AAAA,MAE7E;AACA;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,aAAa,KAAK,IAAI;AAC3C,YAAQ,IAAI,EAAE;AACd,eAAW,QAAQ,gBAAgB,MAAM,EAAG,SAAQ,IAAI,IAAI;AAC5D,QAAI,OAAO,QAAQ,UAAU,OAAO,qBAAqB,OAAQ,SAAQ,WAAW;AAAA,EACtF;AACF;;;AC1EF,SAAS,WAAAC,iBAAe;AAKjB,IAAM,kBAAkB,IAAIC,UAAQ,UAAU,EAClD,YAAY,sCAAsC,EAClD;AAAA,EACC,IAAIA,UAAQ,SAAS,EAClB;AAAA,IACC;AAAA,EAGF,EACC,OAAO,qBAAqB,yCAAyC,EACrE,OAAO,sBAAsB,0CAA0C,EACvE,OAAO,oBAAoB,4CAA4C,EACvE,OAAO,aAAa,gDAAgD,KAAK,EACzE,OAAO,gBAAgB,mDAAmD,EAC1E;AAAA,IACC,OAAO,SAMD;AACJ,YAAM,MAAM,MAAM,eAAe,EAAE,cAAc,KAAK,KAAK,CAAC;AAC5D,YAAM,QACJ;AAAA,QACE,KAAK,YAAY,YAAY,KAAK,QAAQ;AAAA,QAC1C,KAAK,aAAa,aAAa,KAAK,SAAS;AAAA,QAC7C,KAAK,WAAW,WAAW,KAAK,OAAO;AAAA,MACzC,EACG,OAAO,OAAO,EACd,KAAK,IAAI,KAAK;AAEnB,UAAI,KAAK,QAAQ;AACf,gBAAQ,IAAI,6CAA6C,KAAK,iBAAiB;AAC/E;AAAA,MACF;AAEA,YAAM,OAAuB,CAAC;AAC9B,UAAI,KAAK,SAAU,MAAK,gBAAgB,KAAK;AAC7C,UAAI,KAAK,UAAW,MAAK,YAAY,KAAK;AAC1C,UAAI,KAAK,QAAS,MAAK,eAAe,KAAK;AAC3C,YAAM,MAAM,MAAM,WAAW,KAAK,IAAI;AACtC,cAAQ,IAAI,6BAA6B,KAAK,EAAE;AAChD,cAAQ,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,IAC1C;AAAA,EACF;AACJ;;;ACnDF,SAAS,YAAYC,WAAU;AAE/B,SAAS,WAAAC,iBAAe;AASjB,SAAS,UACd,SACA,SACA,SACA,MACA,IACQ;AACR,SAAO,GAAG,QAAQ,QAAQ,QAAQ,EAAE,CAAC,MAAM,OAAO,IAAI,OAAO,WAAW,IAAI,IAAI,EAAE;AACpF;AAQO,SAAS,eACd,SACA,MACA,QACQ;AACR,QAAM,OAAO,KAAK,UAAU,SAAS,MAAM,CAAC;AAC5C,MAAI,WAAW,OAAQ,QAAO,OAAO;AACrC,SACE;AAAA;AAAA;AAAA;AAAA,yBAI0B,IAAI;AAAA;AAAA,sBACP,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA;AAAA;AAAA;AAGxD;AAEA,eAAe,YAAY,KAAmC;AAC5D,QAAM,MAAM,MAAM,MAAM,KAAK,EAAE,SAAS,EAAE,QAAQ,mBAAmB,EAAE,CAAC;AACxE,MAAI,IAAI,WAAW,IAAK,QAAO;AAC/B,MAAI,CAAC,IAAI,GAAI,OAAM,IAAI,MAAM,QAAQ,IAAI,MAAM,aAAa,GAAG,EAAE;AACjE,SAAQ,MAAM,IAAI,KAAK;AACzB;AAEO,IAAM,kBAAkB,IAAIC,UAAQ,UAAU,EAClD;AAAA,EACC;AAIF,EACC,OAAO,qBAAqB,oCAAoC,EAChE,OAAO,sBAAsB,qCAAqC,EAClE,OAAO,oBAAoB,qDAAqD,EAChF,OAAO,kBAAkB,2BAA2B,IAAI,EACxD,OAAO,gBAAgB,gBAAgB,yBAAyB,EAChE,OAAO,gBAAgB,mCAAmC,EAC1D,OAAO,gBAAgB,uDAAuD,EAC9E;AAAA,EACC,OAAO,SAQD;AACJ,UAAM,MAAM,MAAM,eAAe,EAAE,cAAc,KAAK,KAAK,CAAC;AAC5D,UAAM,UAAU,eAAe,GAAG;AAClC,UAAM,UAAU,KAAK,WAAW,IAAI;AAGpC,QAAI;AACJ,QAAI;AACJ,QAAI,KAAK,YAAY,KAAK,WAAW;AACnC,kBAAY,CAAC,KAAK,QAAQ;AAC1B,mBAAa,CAAC,KAAK,SAAS;AAAA,IAC9B,OAAO;AACL,YAAM,OAAO,MAAM,eAAe,GAAG;AACrC,kBAAY,KAAK,WAAW,CAAC,KAAK,QAAQ,IAAI,KAAK;AACnD,mBAAa,KAAK,YAAY,CAAC,KAAK,SAAS,IAAI,KAAK;AACtD,UAAI,UAAU,WAAW,KAAK,WAAW,WAAW,GAAG;AACrD,cAAM,IAAI;AAAA,UACR;AAAA,QAEF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAAmB,CAAC;AAC1B,QAAI,UAAU;AACd,QAAI,UAAU;AACd,eAAW,QAAQ,WAAW;AAC5B,iBAAW,MAAM,YAAY;AAC3B,cAAM,OAAO,MAAM,YAAY,UAAU,KAAK,KAAK,SAAS,SAAS,MAAM,EAAE,CAAC;AAC9E,YAAI,CAAC,MAAM;AACT;AACA;AAAA,QACF;AACA,SAAC,QAAQ,IAAI,MAAM,CAAC,GAAG,EAAE,IAAI;AAC7B;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS;AAAA,MACb;AAAA,MACA,EAAE,SAAS,SAAS,KAAK,KAAK,IAAI,QAAQ,QAAQ,EAAE,EAAE;AAAA,MACtD,KAAK,WAAW,SAAS,SAAS;AAAA,IACpC;AAEA,QAAI,KAAK,KAAK;AACZ,YAAMC,IAAG,UAAU,KAAK,KAAK,QAAQ,MAAM;AAC3C,cAAQ;AAAA,QACN,SAAS,KAAK,GAAG,KAAK,OAAO,gBAC1B,UAAU,KAAK,OAAO,yBAAyB;AAAA,MACpD;AAAA,IACF,OAAO;AACL,cAAQ,OAAO,MAAM,MAAM;AAC3B,UAAI,QAAS,SAAQ,MAAM,IAAI,OAAO,2BAA2B;AAAA,IACnE;AAAA,EACF;AACF;;;AClIF,SAAS,WAAAC,iBAAe;AAYjB,IAAM,gBAAgB,IAAIC,UAAQ,QAAQ,EAC9C,YAAY,uDAAuD,EACnE,OAAO,qBAAqB,+BAA+B,EAC3D,OAAO,sBAAsB,gCAAgC,EAC7D,OAAO,eAAe,qBAAqB,mBAAmB,EAC9D,OAAO,gBAAgB,mDAAmD,EAC1E;AAAA,EACC,OAAO,SAAgF;AACrF,UAAM,MAAM,MAAM,eAAe,EAAE,cAAc,KAAK,KAAK,CAAC;AAC5D,UAAM,aAAa,IAAI,KAAK,MAAM,eAAe,GAAG,GAAG,SAAS;AAEhE,UAAM,SAAS,MAAM,gBAAgB,KAAK,GAAG,GAAG,OAAO,CAAC,MAAM;AAC5D,UAAI,KAAK,YAAY,EAAE,SAAS,KAAK,SAAU,QAAO;AACtD,UAAI,KAAK,aAAa,EAAE,cAAc,KAAK,UAAW,QAAO;AAC7D,aAAO;AAAA,IACT,CAAC;AAGD,UAAM,eAAe,oBAAI,IAA2C;AACpE,mBAAe,UAAU,MAAkB,MAAsD;AAC/F,YAAM,SAAS,aAAa,IAAI,IAAI;AACpC,UAAI,OAAQ,QAAO;AACnB,YAAM,IAAI,oBAAI,IAA8B;AAC5C,iBAAW,MAAM,MAAM,SAAS,MAAM,EAAE,cAAc,KAAK,CAAC,GAAG;AAC7D,cAAM,KAAK,GAAG,cAAc,KAAK,CAAC,MAAM,EAAE,kBAAkB,IAAI;AAChE,YAAI,CAAC,MAAM,GAAG,UAAU,GAAI;AAC5B,cAAM,MAAM,EAAE,IAAI,GAAG,cAAc,KAAK,CAAC;AACzC,YAAI,GAAG,QAAQ,IAAI,GAAG;AACtB,UAAE,IAAI,GAAG,gBAAgB,GAAG;AAAA,MAC9B;AACA,mBAAa,IAAI,MAAM,CAAC;AACxB,aAAO;AAAA,IACT;AAEA,QAAI,aAAa;AACjB,QAAI,eAAe;AACnB,QAAI,eAAe;AACnB,QAAI,iBAAiB;AAErB,eAAW,KAAK,OAAO;AACrB,UAAI,WAAW,OAAO,KAAK,CAAC,WAAW,IAAI,EAAE,IAAI,GAAG;AAClD,gBAAQ,IAAI,KAAK,EAAE,IAAI,IAAI,EAAE,SAAS,+CAA0C;AAChF;AAAA,MACF;AACA,YAAM,QAAQ,MAAM,eAAe,EAAE,IAAI;AACzC,YAAM,UAAU,MAAM,UAAU,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,SAAS,KAAK,CAAC;AACnE,YAAM,IAAI,SAAS,OAAO,MAAM;AAChC,oBAAc,EAAE,MAAM;AACtB,sBAAgB,EAAE,QAAQ;AAC1B,sBAAgB,EAAE,QAAQ;AAC1B,wBAAkB,EAAE;AAEpB,UAAI,EAAE,MAAM,WAAW,KAAK,EAAE,QAAQ,WAAW,KAAK,EAAE,QAAQ,WAAW,GAAG;AAC5E,gBAAQ,IAAI,KAAK,EAAE,IAAI,IAAI,EAAE,SAAS,oBAAoB,EAAE,SAAS,QAAQ;AAC7E;AAAA,MACF;AACA,cAAQ;AAAA,QACN,KAAK,EAAE,IAAI,IAAI,EAAE,SAAS,WAAW,EAAE,MAAM,MAAM,KAAK,EAAE,QAAQ,MAAM,KAAK,EAAE,QAAQ,MAAM;AAAA,MAC/F;AACA,iBAAW,KAAK,EAAE,MAAO,SAAQ,IAAI,SAAS,CAAC,EAAE;AACjD,iBAAW,KAAK,EAAE,QAAS,SAAQ,IAAI,SAAS,CAAC,8CAAyC;AAC1F,iBAAW,KAAK,EAAE,QAAS,SAAQ,IAAI,SAAS,EAAE,GAAG,MAAM,EAAE,KAAK,SAAS,EAAE,MAAM,GAAG;AAAA,IACxF;AACA,YAAQ;AAAA,MACN,aAAa,UAAU,KAAK,YAAY,KAAK,YAAY,eAAe,cAAc;AAAA,IACxF;AAAA,EACF;AACF;;;AC/EF,SAAS,WAAAC,iBAAe;AAIjB,IAAM,gBAAgB,IAAIC,UAAQ,QAAQ,EAC9C,YAAY,6DAA6D,EACzE,OAAO,gBAAgB,gDAAgD,EACvE,OAAO,OAAO,SAA4B;AACzC,QAAM,QAAQ,MAAM,gBAAgB;AACpC,MAAI,CAAC,MAAM,WAAW,OAAO,KAAK,MAAM,KAAK,EAAE,WAAW,GAAG;AAC3D,YAAQ,IAAI,mEAA8D;AAC1E,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,SAAS,KAAK,QAAQ,MAAM;AAClC,MAAI,CAAC,QAAQ;AACX,YAAQ,IAAI,sBAAsB;AAClC,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,QAAQ,MAAM,MAAM,MAAM;AAChC,MAAI,CAAC,OAAO;AACV,YAAQ,IAAI,6BAA6B,MAAM,GAAG;AAClD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,SAAS,MAAM,QAAQ,QAAQ,cAAc,qBAAM;AACzD,QAAM,eAAe,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,iBAAiB,KAAK;AACpF,UAAQ,IAAI,cAAc,MAAM,GAAG,WAAW,MAAM,UAAU,gBAAgB,EAAE,EAAE;AAClF,UAAQ,IAAI,cAAc,MAAM,GAAG,cAAc,wCAAwC,EAAE,EAAE;AAC7F,MAAI,MAAM,WAAY,SAAQ,IAAI,cAAc,MAAM,UAAU,EAAE;AAClE,QAAM,SAAS,OAAO,KAAK,MAAM,KAAK,EAAE,OAAO,CAAC,MAAM,MAAM,MAAM;AAClE,MAAI,OAAO,QAAQ;AACjB,YAAQ,IAAI,cAAc,OAAO,KAAK,IAAI,CAAC,EAAE;AAAA,EAC/C;AACF,CAAC;;;AvBdH,IAAM,UAAU,IAAIC,UAAQ;AAC5B,QACG,KAAK,SAAS,EACd,YAAY,yCAAyC,EACrD,QAAQ,OAAO;AAElB,QAAQ,WAAW,YAAY;AAC/B,QAAQ,WAAW,aAAa;AAChC,QAAQ,WAAW,aAAa;AAChC,QAAQ,WAAW,WAAW;AAC9B,QAAQ,WAAW,eAAe;AAClC,QAAQ,WAAW,WAAW;AAC9B,QAAQ,WAAW,aAAa;AAChC,QAAQ,WAAW,WAAW;AAC9B,QAAQ,WAAW,WAAW;AAC9B,QAAQ,WAAW,aAAa;AAChC,QAAQ,WAAW,aAAa;AAChC,QAAQ,WAAW,eAAe;AAClC,QAAQ,WAAW,eAAe;AAClC,QAAQ,WAAW,cAAc;AACjC,QAAQ,WAAW,aAAa;AAEhC,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,QAAiB;AACvD,UAAQ,MAAM,eAAe,QAAQ,IAAI,UAAU,GAAG;AACtD,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["Command","fs","join","Command","fs","resolve","fs","Command","join","fs","fs","dirname","Command","dirname","fs","Command","resolve","Command","Command","resolve","Command","Command","Command","resolve","Command","Command","Command","Command","Command","Command","Command","Command","fs","join","resolve","Command","Command","Command","Command","Command","fs","Command","Command","fs","Command","Command","Command","Command","Command"]}
|