altalandi 0.6.1 → 0.6.3
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 +35 -12
- package/altalandi.mjs +32 -0
- package/auth.mjs +2 -4
- package/batch.mjs +257 -46
- package/client.d.ts +200 -122
- package/client.mjs +260 -219
- package/package.json +1 -1
- package/report.mjs +75 -13
- package/skill/SKILL.md +35 -19
- package/update.mjs +3 -0
package/README.md
CHANGED
|
@@ -99,6 +99,8 @@ altalandi --fast "..." # skip the meaning + nativeness gates
|
|
|
99
99
|
altalandi --diff --file draft.txt # show before, after and every change with its reason
|
|
100
100
|
altalandi --review --file in.txt --out out.txt # for agents: one block to show as it is
|
|
101
101
|
altalandi --report --file draft.txt # also write a Markdown report to ./altalandi-reports/
|
|
102
|
+
altalandi --review --job j_20261013a1b2c3 --job-title "Handbók" --part "Hluti 1 af 3" --file part1.txt
|
|
103
|
+
# one part of a longer text: same --job on every part
|
|
102
104
|
```
|
|
103
105
|
|
|
104
106
|
| flag | default | meaning |
|
|
@@ -107,11 +109,14 @@ altalandi --report --file draft.txt # also write a Markdown report to ./altal
|
|
|
107
109
|
| `--register` | `neutral` | `formal` \| `neutral` \| `warm` |
|
|
108
110
|
| `--json` | off | print the full API response |
|
|
109
111
|
| `--diff` | off | print the text before and after, then each change with its reason, on `stderr` (coloured in a terminal; `NO_COLOR` turns colour off) |
|
|
110
|
-
| `--review` | off | print one Markdown block on `stdout`, made to be shown as it is: the verdict, the text before and after, each change with its reason, what the call cost and the balance and free
|
|
111
|
-
| `--no-store` | off | send `contribute: false`: this text is never kept. Without it, free use (calls covered by the free daily
|
|
112
|
+
| `--review` | off | print one Markdown block on `stdout`, made to be shown as it is: the verdict, the text before and after, each change with its reason, what the call cost and the balance and free characters left. Exits on the outcome: `0` rewritten and verified or no change needed, `3` refused or unverified, `4` out of credit |
|
|
113
|
+
| `--no-store` | off | send `contribute: false`: this text is never kept. Without it, free use (calls covered by the free daily characters) is kept with personal data scrubbed, to improve the service; paid use is kept only with consent ([privacy](https://altalandi.is/personuvernd#textabanki)) |
|
|
112
114
|
| `--out <file>` | | write the refined text to `<file>` (UTF-8); with `--review` the block names it when the text is shortened |
|
|
113
115
|
| `--report` | off | also write `./altalandi-reports/altalandi-<time>-<id>.md`: input, output, a table of every change (before, after, reason, layer), warnings and the verdict |
|
|
114
116
|
| `--report-dir <dir>` | | write the report to `<dir>` instead (implies `--report`) |
|
|
117
|
+
| `--job <id>` | | make this call a part of a job (verk): every call with the same id is one job on the site, one page for the whole text. The id is yours to choose: `j_` and 8–64 of `A-Z a-z 0-9 _ -`, e.g. `j_` + the date + a few random characters. With `--review`, the block links the job (`Verkið`) and this part (`Hlutinn`) |
|
|
118
|
+
| `--job-title <text>` | | the job's name (up to 120 characters); the first call that sends one names it |
|
|
119
|
+
| `--part <text>` | | this call's part, e.g. `Hluti 2 af 5` (up to 300 characters); needs `--job` |
|
|
115
120
|
| `--fast` | off | `preserveMeaning:false`, `scoreNativeness:false`, `onlyImprove:false`, `polishPass:false`, `scoring:"none"` — normally one model call (structured input can still add a structure-preserving retry) |
|
|
116
121
|
|
|
117
122
|
## Folders, i18n catalogs and websites
|
|
@@ -127,8 +132,11 @@ altalandi https://example.com/pricing --out pricing-is.md # one page → Markd
|
|
|
127
132
|
altalandi https://example.com/docs/ --site --max-pages 50 # a site → ./example.com-is/
|
|
128
133
|
```
|
|
129
134
|
|
|
130
|
-
Each passage (a paragraph, list item, table cell, heading or string) is
|
|
131
|
-
|
|
135
|
+
Each passage (a paragraph, list item, table cell, heading or string) is refined
|
|
136
|
+
and checked on its own. Short passages (up to 1,500 characters) are sent
|
|
137
|
+
together through `/v1/refine/batch`, up to 40 a request and 6,000 characters;
|
|
138
|
+
longer ones go one call each to `/v1/refine`. Everything outside the passages is
|
|
139
|
+
written back byte for byte:
|
|
132
140
|
|
|
133
141
|
| format | refined | never touched |
|
|
134
142
|
|--------|---------|---------------|
|
|
@@ -154,13 +162,19 @@ the same origin and under the URL's folder.
|
|
|
154
162
|
from the public tariff:
|
|
155
163
|
|
|
156
164
|
```text
|
|
157
|
-
5 files, 24 passages, about 851 characters (23
|
|
165
|
+
5 files, 24 passages, about 851 characters (23 to send: repeated passages are sent once).
|
|
166
|
+
1 request: 23 short passages together in 1 batch.
|
|
158
167
|
1 more file has nothing to refine and is copied unchanged.
|
|
159
|
-
|
|
168
|
+
Kostnaður: um 3.016 stafir (um 1 A4-síða), um 30 kr. ef greitt er af inneign.
|
|
169
|
+
Hvert kall telst minnst 250 stafir; margir stuttir textar í einu kalli minnst 130 stafir hver. Hver aðgangur fær ókeypis dagskammt af stöfum (`GET /v1/pricing`).
|
|
160
170
|
```
|
|
161
171
|
|
|
162
|
-
|
|
163
|
-
|
|
172
|
+
Billing is by character (stafir): every character sent, spaces and punctuation
|
|
173
|
+
included. In a batch each string is billed at least 130 characters, and the
|
|
174
|
+
250-character per-call minimum is paid once per request, not once per string:
|
|
175
|
+
short strings cost about half what one call each would. The summary and the
|
|
176
|
+
report show the characters actually billed. An older self-hosted engine without the batch endpoint gets one
|
|
177
|
+
call per passage (the run says so once). In a terminal it asks before sending; without one (CI,
|
|
164
178
|
agents) it sends nothing unless you pass `--yes`.
|
|
165
179
|
|
|
166
180
|
| flag | default | meaning |
|
|
@@ -169,15 +183,24 @@ agents) it sends nothing unless you pass `--yes`.
|
|
|
169
183
|
| `--dry-run` | off | list every passage and the estimate; send nothing, write nothing |
|
|
170
184
|
| `--yes`, `-y` | off | send without asking |
|
|
171
185
|
| `--max-chars <n>` | | files are sent in order until the next would go over n characters; the rest are neither sent nor written |
|
|
172
|
-
| `--concurrency <n>` | `2` |
|
|
186
|
+
| `--concurrency <n>` | `2` | requests at once, 1–4 |
|
|
173
187
|
| `--site` / `--max-pages <n>` | off / `20` | read a site from the URL, up to n pages |
|
|
174
188
|
| `--no-store` | off | keep none of the passages (free use is otherwise kept, scrubbed of personal data) |
|
|
175
189
|
| `--json` | off | a machine-readable summary of every file and passage on stdout |
|
|
190
|
+
| `--job <id>` / `--job-title <text>` | a new job | add the run to an existing job, or name it |
|
|
176
191
|
|
|
177
192
|
A `429` waits as long as `Retry-After` asks (up to 5 minutes) and retries. A
|
|
178
193
|
`402` stops the run cleanly: finished files are written, the rest are listed and
|
|
179
194
|
not written; run the same command again after topping up.
|
|
180
195
|
|
|
196
|
+
**One job.** A run is one job (verk) on your account: every request sends the
|
|
197
|
+
same `job` id (`j_` + the date + 10 random characters, made per run), titled by
|
|
198
|
+
the folder's name or the site's host, and each file (its relative path) or page
|
|
199
|
+
(its URL) is a part. A batch that holds several small files is named by its
|
|
200
|
+
first file; a file that fits in one batch is not split across two. The summary
|
|
201
|
+
and the report show one `Verkið: <link>` to the job's page, not one link per
|
|
202
|
+
call. An engine that does not know jobs simply leaves the line out.
|
|
203
|
+
|
|
181
204
|
**Results.** Only verified changes are written. A passage keeps its original
|
|
182
205
|
text when its meaning check did not pass (`meaningCheck` other than `passed`, or
|
|
183
206
|
`meaningPreserved` not `true`), or when the refined text lost or changed code, a
|
|
@@ -255,6 +278,6 @@ the explicit verification opt-out and exits 0 after a successful API response.
|
|
|
255
278
|
|
|
256
279
|
MIT licensed. Calls are paid from the account's prepaid credit (a 500 kr trial,
|
|
257
280
|
then credit bought in the portal); a call the credit cannot cover exits with the
|
|
258
|
-
server's `402 insufficient_balance` message. The request's text and glossary fields are charged
|
|
259
|
-
|
|
260
|
-
|
|
281
|
+
server's `402 insufficient_balance` message. The request's text and glossary fields are charged by the character
|
|
282
|
+
(every Unicode character, spaces, punctuation and line breaks included) at the
|
|
283
|
+
effective billing-tier weight, with a minimum per call.
|
package/altalandi.mjs
CHANGED
|
@@ -108,6 +108,9 @@ for (let i = 0; i < args.length; i++) {
|
|
|
108
108
|
else if (a === "--yes" || a === "-y") opts.yes = true;
|
|
109
109
|
else if (a === "--max-chars") opts.maxChars = Number(args[++i]);
|
|
110
110
|
else if (a === "--concurrency") opts.concurrency = Number(args[++i]);
|
|
111
|
+
else if (a === "--job") opts.job = args[++i] ?? "";
|
|
112
|
+
else if (a === "--job-title") opts.jobTitle = args[++i] ?? "";
|
|
113
|
+
else if (a === "--part") opts.part = args[++i] ?? "";
|
|
111
114
|
else positional.push(a);
|
|
112
115
|
}
|
|
113
116
|
|
|
@@ -122,6 +125,9 @@ Usage:
|
|
|
122
125
|
for agents: one block to show as it is
|
|
123
126
|
echo "text" | altalandi
|
|
124
127
|
altalandi --domain marketing --register warm "text"
|
|
128
|
+
altalandi --review --job j_20261013a1b2c3 --job-title "Handbók" --part "Hluti 1 af 3" --file part1.txt
|
|
129
|
+
one part of a longer text: every part with the same
|
|
130
|
+
--job is one verk (job) on the site
|
|
125
131
|
|
|
126
132
|
Folders and websites:
|
|
127
133
|
altalandi ./docs every .md .txt .html .json under ./docs → ./docs-is
|
|
@@ -154,6 +160,10 @@ Options:
|
|
|
154
160
|
--report also write a Markdown report (input, output, changes, reasons, verdict)
|
|
155
161
|
to ./altalandi-reports/ (or --report-dir <dir>; ALTALANDI_REPORT=1 turns it on)
|
|
156
162
|
--file read the text from a UTF-8 file instead of an argument
|
|
163
|
+
--job a job id (j_ and 8-64 of A-Z a-z 0-9 _ -) you choose: calls with the same id
|
|
164
|
+
are the parts of one verk; --review then links the job and this part
|
|
165
|
+
--job-title the job's name, kept from the first call that sends one (up to 120 characters)
|
|
166
|
+
--part this call's part, e.g. "Hluti 2 af 5" (up to 300 characters; needs --job)
|
|
157
167
|
--base-url API base (default $ALTALANDI_BASE_URL or https://altalandi.is/api)
|
|
158
168
|
|
|
159
169
|
stdout = refined text; stderr = nativeness / meaning / warnings / diff.
|
|
@@ -169,6 +179,9 @@ Folder and website options:
|
|
|
169
179
|
--site with a URL: its pages on the same site, under the URL's folder
|
|
170
180
|
--max-pages pages to read with --site (default 20)
|
|
171
181
|
--json print a machine-readable summary at the end
|
|
182
|
+
--job add the run to this job; --job-title names it (default: a new
|
|
183
|
+
job per run, named by the folder or the site's host; each file
|
|
184
|
+
or page is a part)
|
|
172
185
|
Code, URLs, link targets, placeholders ({name}, %s, ICU), HTML tags and JSON keys
|
|
173
186
|
stay byte for byte. Only changes whose meaning check passed are written; other
|
|
174
187
|
passages keep the original text and are listed in the report
|
|
@@ -186,6 +199,13 @@ function readStdin() {
|
|
|
186
199
|
});
|
|
187
200
|
}
|
|
188
201
|
|
|
202
|
+
// --job / --job-title / --part: checked here so a bad id never reaches the API.
|
|
203
|
+
const JOB_ID = /^j_[A-Za-z0-9_-]{8,64}$/;
|
|
204
|
+
if (opts.job !== undefined && !JOB_ID.test(opts.job)) {
|
|
205
|
+
console.error(`--job must be j_ followed by 8 to 64 letters, digits, _ or - (for example j_20261013a1b2c3); got "${opts.job}".`);
|
|
206
|
+
process.exit(2);
|
|
207
|
+
}
|
|
208
|
+
|
|
189
209
|
const stored = readCredentials();
|
|
190
210
|
const baseUrl = (opts.baseUrl || process.env.ALTALANDI_BASE_URL || stored?.baseUrl || "https://altalandi.is/api").replace(/\/$/, "");
|
|
191
211
|
const { key } = resolveKey({ flag: opts.key });
|
|
@@ -206,6 +226,10 @@ if (opts.site || opts.dryRun || opts.maxChars !== undefined || opts.maxPages !==
|
|
|
206
226
|
console.error("--site, --dry-run, --max-chars, --max-pages and --concurrency need a folder or a URL: altalandi ./docs --dry-run");
|
|
207
227
|
process.exit(2);
|
|
208
228
|
}
|
|
229
|
+
if (opts.job === undefined && (opts.jobTitle !== undefined || opts.part !== undefined)) {
|
|
230
|
+
console.error("--job-title and --part need --job <id>: the same id on every part of the text.");
|
|
231
|
+
process.exit(2);
|
|
232
|
+
}
|
|
209
233
|
|
|
210
234
|
let text = positional.join(" ").trim();
|
|
211
235
|
if (opts.file) {
|
|
@@ -224,6 +248,14 @@ const requestOptions = {
|
|
|
224
248
|
register: opts.register,
|
|
225
249
|
...(opts.noStore ? { contribute: false } : {}),
|
|
226
250
|
};
|
|
251
|
+
if (opts.job) {
|
|
252
|
+
const cap = (s, n) => [...String(s)].slice(0, n).join("");
|
|
253
|
+
requestOptions.job = {
|
|
254
|
+
id: opts.job,
|
|
255
|
+
...(opts.jobTitle ? { title: cap(opts.jobTitle, 120) } : {}),
|
|
256
|
+
...(opts.part ? { part: cap(opts.part, 300) } : {}),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
227
259
|
// --fast disables every optional quality/verification pass. The writer can
|
|
228
260
|
// still retry once when it drops document structure, as documented in --help.
|
|
229
261
|
// Name every switch explicitly so a future server-default change cannot make
|
package/auth.mjs
CHANGED
|
@@ -211,10 +211,8 @@ export async function runWhoami(flags = {}, io = {}) {
|
|
|
211
211
|
const me = await res.json();
|
|
212
212
|
if (flags.json) out(JSON.stringify({ ...me, keySource: source }, null, 2));
|
|
213
213
|
else {
|
|
214
|
-
const {
|
|
215
|
-
const free =
|
|
216
|
-
? `ókeypis eftir í dag ${formatInt(me.freeUnitsLeftToday)} af ${formatInt(me.freeDailyUnits)} einingum`
|
|
217
|
-
: me.freeDailyUnits ? `ókeypis ${formatInt(me.freeDailyUnits)} einingar á dag` : "";
|
|
214
|
+
const { formatIsk, freeCharsText } = await import("./report.mjs");
|
|
215
|
+
const free = freeCharsText(null, me);
|
|
218
216
|
out([me.username ?? "(lykill án aðgangs)",
|
|
219
217
|
`inneign ${me.balanceIsk != null ? formatIsk(me.balanceIsk) : "—"}`,
|
|
220
218
|
free, `lykill ${me.keyId} (${source})`].filter(Boolean).join(" · "));
|