@tolkbot/cli 0.4.0 → 0.5.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/dist/index.js +348 -108
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -559,7 +559,7 @@ var require_to_regex_range = __commonJS({
|
|
|
559
559
|
let zipped = zip(start, stop);
|
|
560
560
|
let digits = zipped.length;
|
|
561
561
|
let pattern = "";
|
|
562
|
-
let
|
|
562
|
+
let count2 = 0;
|
|
563
563
|
for (let i = 0; i < digits; i++) {
|
|
564
564
|
let [startDigit, stopDigit] = zipped[i];
|
|
565
565
|
if (startDigit === stopDigit) {
|
|
@@ -567,13 +567,13 @@ var require_to_regex_range = __commonJS({
|
|
|
567
567
|
} else if (startDigit !== "0" || stopDigit !== "9") {
|
|
568
568
|
pattern += toCharacterClass(startDigit, stopDigit, options);
|
|
569
569
|
} else {
|
|
570
|
-
|
|
570
|
+
count2++;
|
|
571
571
|
}
|
|
572
572
|
}
|
|
573
|
-
if (
|
|
573
|
+
if (count2) {
|
|
574
574
|
pattern += options.shorthand === true ? "\\d" : "[0-9]";
|
|
575
575
|
}
|
|
576
|
-
return { pattern, count: [
|
|
576
|
+
return { pattern, count: [count2], digits };
|
|
577
577
|
}
|
|
578
578
|
function splitToPatterns(min, max, tok, options) {
|
|
579
579
|
let ranges = splitToRanges(min, max);
|
|
@@ -2320,13 +2320,13 @@ var require_parse2 = __commonJS({
|
|
|
2320
2320
|
consume(token.value);
|
|
2321
2321
|
};
|
|
2322
2322
|
const negate = () => {
|
|
2323
|
-
let
|
|
2323
|
+
let count2 = 1;
|
|
2324
2324
|
while (peek() === "!" && (peek(2) !== "(" || peek(3) === "?")) {
|
|
2325
2325
|
advance();
|
|
2326
2326
|
state.start++;
|
|
2327
|
-
|
|
2327
|
+
count2++;
|
|
2328
2328
|
}
|
|
2329
|
-
if (
|
|
2329
|
+
if (count2 % 2 === 0) {
|
|
2330
2330
|
return false;
|
|
2331
2331
|
}
|
|
2332
2332
|
state.negated = true;
|
|
@@ -5784,10 +5784,10 @@ var require_out4 = __commonJS({
|
|
|
5784
5784
|
});
|
|
5785
5785
|
|
|
5786
5786
|
// src/main.ts
|
|
5787
|
-
import { Command as
|
|
5787
|
+
import { Command as Command8, CommanderError, Option } from "commander";
|
|
5788
5788
|
|
|
5789
5789
|
// package.json
|
|
5790
|
-
var version = "0.
|
|
5790
|
+
var version = "0.5.0";
|
|
5791
5791
|
|
|
5792
5792
|
// src/commands/auth/index.ts
|
|
5793
5793
|
import { Command } from "commander";
|
|
@@ -8068,14 +8068,14 @@ function codePointLength(str) {
|
|
|
8068
8068
|
const units = str.length;
|
|
8069
8069
|
if (!highSurrogate.test(str))
|
|
8070
8070
|
return units;
|
|
8071
|
-
let
|
|
8071
|
+
let count2 = units;
|
|
8072
8072
|
for (let i = 0; i < units - 1; i++) {
|
|
8073
8073
|
if ((str.charCodeAt(i) & 64512) === 55296 && (str.charCodeAt(i + 1) & 64512) === 56320) {
|
|
8074
|
-
|
|
8074
|
+
count2--;
|
|
8075
8075
|
i++;
|
|
8076
8076
|
}
|
|
8077
8077
|
}
|
|
8078
|
-
return
|
|
8078
|
+
return count2;
|
|
8079
8079
|
}
|
|
8080
8080
|
function getLengthableOrigin(input2) {
|
|
8081
8081
|
if (Array.isArray(input2))
|
|
@@ -12432,8 +12432,8 @@ function az_default() {
|
|
|
12432
12432
|
localeError: error2()
|
|
12433
12433
|
};
|
|
12434
12434
|
}
|
|
12435
|
-
function getBelarusianPlural(
|
|
12436
|
-
const absCount = Math.abs(
|
|
12435
|
+
function getBelarusianPlural(count2, one, few, many) {
|
|
12436
|
+
const absCount = Math.abs(count2);
|
|
12437
12437
|
const lastDigit = absCount % 10;
|
|
12438
12438
|
const lastTwoDigits = absCount % 100;
|
|
12439
12439
|
if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
|
|
@@ -15038,8 +15038,8 @@ function hu_default() {
|
|
|
15038
15038
|
localeError: error23()
|
|
15039
15039
|
};
|
|
15040
15040
|
}
|
|
15041
|
-
function getArmenianPlural(
|
|
15042
|
-
return Math.abs(
|
|
15041
|
+
function getArmenianPlural(count2, one, many) {
|
|
15042
|
+
return Math.abs(count2) === 1 ? one : many;
|
|
15043
15043
|
}
|
|
15044
15044
|
function withDefiniteArticle(word) {
|
|
15045
15045
|
if (!word)
|
|
@@ -17731,8 +17731,8 @@ function ro_default() {
|
|
|
17731
17731
|
localeError: error45()
|
|
17732
17732
|
};
|
|
17733
17733
|
}
|
|
17734
|
-
function getRussianPlural(
|
|
17735
|
-
const absCount = Math.abs(
|
|
17734
|
+
function getRussianPlural(count2, one, few, many) {
|
|
17735
|
+
const absCount = Math.abs(count2);
|
|
17736
17736
|
const lastDigit = absCount % 10;
|
|
17737
17737
|
const lastTwoDigits = absCount % 100;
|
|
17738
17738
|
if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
|
|
@@ -27354,6 +27354,7 @@ var analyticsEventNames = [
|
|
|
27354
27354
|
"glossary_imported",
|
|
27355
27355
|
"translation_job_viewed",
|
|
27356
27356
|
"translation_logs_viewed",
|
|
27357
|
+
"activity_timeline_viewed",
|
|
27357
27358
|
"cli_login_completed",
|
|
27358
27359
|
"cli_command_completed",
|
|
27359
27360
|
"cli_init_completed",
|
|
@@ -28316,6 +28317,16 @@ async function loadPlanContext(cwd) {
|
|
|
28316
28317
|
framework: config3.config.framework
|
|
28317
28318
|
};
|
|
28318
28319
|
}
|
|
28320
|
+
async function readCreditBalance(ctx) {
|
|
28321
|
+
try {
|
|
28322
|
+
const balance = await ctx.client.query(api.usage.getCreditBalance, {
|
|
28323
|
+
organizationId: ctx.project.organizationId
|
|
28324
|
+
});
|
|
28325
|
+
return balance?.total ?? null;
|
|
28326
|
+
} catch {
|
|
28327
|
+
return null;
|
|
28328
|
+
}
|
|
28329
|
+
}
|
|
28319
28330
|
function describePlan(plan) {
|
|
28320
28331
|
const { summary } = plan;
|
|
28321
28332
|
const lines = [
|
|
@@ -28331,9 +28342,9 @@ function describeLeftOut(plan) {
|
|
|
28331
28342
|
const lines = [];
|
|
28332
28343
|
const protectedCount = plan.protectedKeys.length;
|
|
28333
28344
|
if (protectedCount > 0) {
|
|
28334
|
-
const
|
|
28345
|
+
const reasons2 = Object.entries(summary.protected).map(([reason, n]) => `${n} ${reason}`).join(", ");
|
|
28335
28346
|
lines.push(
|
|
28336
|
-
`${protectedCount} changed but kept for a person (${
|
|
28347
|
+
`${protectedCount} changed but kept for a person (${reasons2})`
|
|
28337
28348
|
);
|
|
28338
28349
|
}
|
|
28339
28350
|
if (summary.held > 0)
|
|
@@ -28551,11 +28562,11 @@ function flattenValues(data) {
|
|
|
28551
28562
|
const values = /* @__PURE__ */ new Map();
|
|
28552
28563
|
function walk(obj, prefix) {
|
|
28553
28564
|
for (const [key, value] of Object.entries(obj)) {
|
|
28554
|
-
const
|
|
28565
|
+
const fullKey6 = prefix ? `${prefix}.${key}` : key;
|
|
28555
28566
|
if (typeof value === "string") {
|
|
28556
|
-
values.set(
|
|
28567
|
+
values.set(fullKey6, value);
|
|
28557
28568
|
} else if (typeof value === "object" && value !== null) {
|
|
28558
|
-
walk(value,
|
|
28569
|
+
walk(value, fullKey6);
|
|
28559
28570
|
}
|
|
28560
28571
|
}
|
|
28561
28572
|
}
|
|
@@ -31982,9 +31993,246 @@ learningsCommand.command("remove").description("Permanently remove a learning").
|
|
|
31982
31993
|
await runLearningsRemove(parsed);
|
|
31983
31994
|
});
|
|
31984
31995
|
|
|
31985
|
-
// src/commands/
|
|
31996
|
+
// src/commands/status/index.ts
|
|
31986
31997
|
import { Command as Command5 } from "commander";
|
|
31987
31998
|
import { z as z7 } from "zod/v4";
|
|
31999
|
+
|
|
32000
|
+
// src/commands/status/status.tsx
|
|
32001
|
+
import { Spinner as Spinner13 } from "@inkjs/ui";
|
|
32002
|
+
import { Box as Box16, Text as Text16 } from "ink";
|
|
32003
|
+
|
|
32004
|
+
// src/commands/status/status-core.ts
|
|
32005
|
+
function fullKey4(namespace, key) {
|
|
32006
|
+
return namespace ? `${namespace}.${key}` : key;
|
|
32007
|
+
}
|
|
32008
|
+
function isPersonHold(reason) {
|
|
32009
|
+
return reason === "locked" || reason === "pending-draft";
|
|
32010
|
+
}
|
|
32011
|
+
function count(reasons2) {
|
|
32012
|
+
const byReason = {};
|
|
32013
|
+
for (const reason of reasons2)
|
|
32014
|
+
byReason[reason] = (byReason[reason] ?? 0) + 1;
|
|
32015
|
+
return { total: reasons2.length, byReason };
|
|
32016
|
+
}
|
|
32017
|
+
function openPullRequest(rows, locale) {
|
|
32018
|
+
const row = rows.find(
|
|
32019
|
+
(r) => r.prState === "open" && r.prUrl !== void 0 && sameLocale(r.targetLanguage, locale)
|
|
32020
|
+
);
|
|
32021
|
+
if (!row?.prUrl) return null;
|
|
32022
|
+
return { number: row.prNumber ?? null, url: row.prUrl };
|
|
32023
|
+
}
|
|
32024
|
+
function languageStatus(locale, plan, pullRequests, opts = {}) {
|
|
32025
|
+
const { summary } = plan;
|
|
32026
|
+
const held = [
|
|
32027
|
+
...plan.heldKeys,
|
|
32028
|
+
...plan.protectedKeys.flatMap(
|
|
32029
|
+
({ key, reason }) => isPersonHold(reason) ? [{ key, reason }] : []
|
|
32030
|
+
)
|
|
32031
|
+
];
|
|
32032
|
+
const kept = plan.protectedKeys.flatMap(
|
|
32033
|
+
({ key, reason }) => isPersonHold(reason) ? [] : [{ key, reason }]
|
|
32034
|
+
);
|
|
32035
|
+
const tasks = (reason) => plan.tasks.filter((t) => t.reason === reason).map((t) => fullKey4(t.namespace, t.key));
|
|
32036
|
+
return {
|
|
32037
|
+
locale,
|
|
32038
|
+
expected: summary.totalKeys,
|
|
32039
|
+
upToDate: summary.upToDate,
|
|
32040
|
+
missing: summary.missing,
|
|
32041
|
+
changed: summary.changed,
|
|
32042
|
+
heldByPerson: count(held.map((h) => h.reason)),
|
|
32043
|
+
keptForPerson: count(kept.map((k) => k.reason)),
|
|
32044
|
+
untracked: summary.untracked,
|
|
32045
|
+
pullRequest: openPullRequest(pullRequests, locale),
|
|
32046
|
+
...opts.keys ? {
|
|
32047
|
+
keys: {
|
|
32048
|
+
missing: tasks("missing"),
|
|
32049
|
+
changed: tasks("changed"),
|
|
32050
|
+
heldByPerson: held,
|
|
32051
|
+
keptForPerson: kept,
|
|
32052
|
+
untracked: plan.untrackedKeys.map((k) => k.key)
|
|
32053
|
+
}
|
|
32054
|
+
} : {}
|
|
32055
|
+
};
|
|
32056
|
+
}
|
|
32057
|
+
function needsTranslation(language) {
|
|
32058
|
+
return language.missing > 0 || language.changed > 0;
|
|
32059
|
+
}
|
|
32060
|
+
var REASON_WORDS = {
|
|
32061
|
+
locked: "locked",
|
|
32062
|
+
"pending-draft": "pending draft",
|
|
32063
|
+
manual: "written by a person",
|
|
32064
|
+
"target-edited": "edited since TolkBot wrote it",
|
|
32065
|
+
unknown: "no record of who wrote it"
|
|
32066
|
+
};
|
|
32067
|
+
function reasons(counts) {
|
|
32068
|
+
return Object.entries(counts.byReason).map(
|
|
32069
|
+
([reason, n]) => `${n} ${REASON_WORDS[reason]}`
|
|
32070
|
+
).join(", ");
|
|
32071
|
+
}
|
|
32072
|
+
function describeLanguage(language) {
|
|
32073
|
+
const counts = [
|
|
32074
|
+
`${language.expected} expected`,
|
|
32075
|
+
`${language.upToDate} up to date`,
|
|
32076
|
+
`${language.missing} missing`,
|
|
32077
|
+
`${language.changed} changed since translated`
|
|
32078
|
+
].join(", ");
|
|
32079
|
+
const mark = needsTranslation(language) ? "\u2022" : "\u2713";
|
|
32080
|
+
const lines = [`${mark} ${language.locale}: ${counts}`];
|
|
32081
|
+
if (language.heldByPerson.total > 0) {
|
|
32082
|
+
lines.push(
|
|
32083
|
+
` ${language.heldByPerson.total} held by a person (${reasons(language.heldByPerson)})`
|
|
32084
|
+
);
|
|
32085
|
+
}
|
|
32086
|
+
if (language.keptForPerson.total > 0) {
|
|
32087
|
+
lines.push(
|
|
32088
|
+
` ${language.keptForPerson.total} changed but kept for a person (${reasons(language.keptForPerson)})`
|
|
32089
|
+
);
|
|
32090
|
+
}
|
|
32091
|
+
if (language.untracked > 0) {
|
|
32092
|
+
lines.push(
|
|
32093
|
+
` ${language.untracked} untracked: TolkBot has no record of them`
|
|
32094
|
+
);
|
|
32095
|
+
}
|
|
32096
|
+
if (language.pullRequest) {
|
|
32097
|
+
lines.push(` Pull request: ${language.pullRequest.url}`);
|
|
32098
|
+
}
|
|
32099
|
+
const { keys } = language;
|
|
32100
|
+
if (keys) {
|
|
32101
|
+
const list = (label, names) => {
|
|
32102
|
+
if (names.length === 0) return;
|
|
32103
|
+
lines.push(` ${label}:`);
|
|
32104
|
+
for (const name of names) lines.push(` ${name}`);
|
|
32105
|
+
};
|
|
32106
|
+
list("Missing", keys.missing);
|
|
32107
|
+
list("Changed", keys.changed);
|
|
32108
|
+
list(
|
|
32109
|
+
"Held by a person",
|
|
32110
|
+
keys.heldByPerson.map(
|
|
32111
|
+
(k) => `${k.key} (${REASON_WORDS[k.reason]})`
|
|
32112
|
+
)
|
|
32113
|
+
);
|
|
32114
|
+
list(
|
|
32115
|
+
"Kept for a person",
|
|
32116
|
+
keys.keptForPerson.map(
|
|
32117
|
+
(k) => `${k.key} (${REASON_WORDS[k.reason]})`
|
|
32118
|
+
)
|
|
32119
|
+
);
|
|
32120
|
+
list("Untracked", keys.untracked);
|
|
32121
|
+
}
|
|
32122
|
+
return lines;
|
|
32123
|
+
}
|
|
32124
|
+
|
|
32125
|
+
// src/commands/status/status.tsx
|
|
32126
|
+
import { jsx as jsx16, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
32127
|
+
var OFFLINE_HINT = "Without a login, 'tolkbot validate' checks the files on this machine.";
|
|
32128
|
+
async function runStatus(opts) {
|
|
32129
|
+
let ctx;
|
|
32130
|
+
try {
|
|
32131
|
+
ctx = await loadPlanContext(process.cwd());
|
|
32132
|
+
} catch (error62) {
|
|
32133
|
+
if (error62 instanceof AuthError) {
|
|
32134
|
+
throw new AuthError(
|
|
32135
|
+
error62.baseMessage,
|
|
32136
|
+
[error62.hint, OFFLINE_HINT].filter(Boolean).join(" "),
|
|
32137
|
+
error62.code
|
|
32138
|
+
);
|
|
32139
|
+
}
|
|
32140
|
+
throw error62;
|
|
32141
|
+
}
|
|
32142
|
+
const { project } = ctx;
|
|
32143
|
+
const srcLocale = project.baseLanguage;
|
|
32144
|
+
const locales = project.targetLanguages;
|
|
32145
|
+
const progress = renderTransient(
|
|
32146
|
+
/* @__PURE__ */ jsxs16(Box16, { children: [
|
|
32147
|
+
/* @__PURE__ */ jsx16(Spinner13, {}),
|
|
32148
|
+
/* @__PURE__ */ jsxs16(Text16, { children: [
|
|
32149
|
+
" Reading the status of ",
|
|
32150
|
+
project.name,
|
|
32151
|
+
"\u2026"
|
|
32152
|
+
] })
|
|
32153
|
+
] })
|
|
32154
|
+
);
|
|
32155
|
+
const languages = [];
|
|
32156
|
+
let credits;
|
|
32157
|
+
try {
|
|
32158
|
+
const pullRequests = locales.length === 0 ? [] : await ctx.client.query(api.prJobs.listByProject, {
|
|
32159
|
+
organizationId: project.organizationId,
|
|
32160
|
+
projectId: project._id
|
|
32161
|
+
});
|
|
32162
|
+
for (const locale of locales) {
|
|
32163
|
+
const plan = await planForLocale(ctx, srcLocale, locale);
|
|
32164
|
+
languages.push(
|
|
32165
|
+
languageStatus(locale, plan, pullRequests, {
|
|
32166
|
+
keys: opts.keys
|
|
32167
|
+
})
|
|
32168
|
+
);
|
|
32169
|
+
}
|
|
32170
|
+
credits = await readCreditBalance(ctx);
|
|
32171
|
+
} finally {
|
|
32172
|
+
progress.unmount();
|
|
32173
|
+
}
|
|
32174
|
+
const payload = {
|
|
32175
|
+
project: {
|
|
32176
|
+
name: project.name,
|
|
32177
|
+
slug: project.slug,
|
|
32178
|
+
url: `${env.TOLKBOT_WEB_URL}/projects/${project.slug}`,
|
|
32179
|
+
baseLanguage: srcLocale,
|
|
32180
|
+
pattern: fullPattern(scopeOf(project)),
|
|
32181
|
+
autoCreatePR: project.workflow?.autoCreatePR ?? DEFAULT_BEHAVIORAL_SETTINGS.workflow.autoCreatePR
|
|
32182
|
+
},
|
|
32183
|
+
credits: { balance: credits },
|
|
32184
|
+
languages
|
|
32185
|
+
};
|
|
32186
|
+
const outOfDate = languages.some(needsTranslation);
|
|
32187
|
+
const exitCode = opts.exitCode && outOfDate ? 1 : 0;
|
|
32188
|
+
if (opts.json) {
|
|
32189
|
+
if (exitCode === 0) jsonSuccess(payload);
|
|
32190
|
+
jsonResult(payload, exitCode);
|
|
32191
|
+
return;
|
|
32192
|
+
}
|
|
32193
|
+
const { project: p } = payload;
|
|
32194
|
+
console.log(`${p.name} (${p.slug}) ${p.url}`);
|
|
32195
|
+
console.log(
|
|
32196
|
+
`Base language ${p.baseLanguage}, files ${p.pattern}, auto-create pull requests ${p.autoCreatePR ? "on" : "off"}`
|
|
32197
|
+
);
|
|
32198
|
+
console.log(
|
|
32199
|
+
credits === null ? "Credits left: could not be read" : `Credits left: ${credits}`
|
|
32200
|
+
);
|
|
32201
|
+
console.log("");
|
|
32202
|
+
if (languages.length === 0) {
|
|
32203
|
+
console.log(
|
|
32204
|
+
`No target languages configured. Add them in the project settings at ${p.url}/settings.`
|
|
32205
|
+
);
|
|
32206
|
+
}
|
|
32207
|
+
for (const language of languages) {
|
|
32208
|
+
for (const line of describeLanguage(language)) console.log(line);
|
|
32209
|
+
}
|
|
32210
|
+
if (outOfDate) {
|
|
32211
|
+
console.log(
|
|
32212
|
+
"\nRun 'tolkbot translate --all' to translate what is missing or changed."
|
|
32213
|
+
);
|
|
32214
|
+
}
|
|
32215
|
+
process.exitCode = exitCode;
|
|
32216
|
+
}
|
|
32217
|
+
|
|
32218
|
+
// src/commands/status/index.ts
|
|
32219
|
+
var statusCommand = new Command5("status").description(
|
|
32220
|
+
"Show what each language is missing, what waits for a person, the open pull requests and the credits left"
|
|
32221
|
+
).option("--keys", "List the keys by name under each language").option(
|
|
32222
|
+
"--exit-code",
|
|
32223
|
+
"Exit 1 when any language has missing or changed keys"
|
|
32224
|
+
).option("--json", "Output as JSON (machine-readable)").action(async (opts) => {
|
|
32225
|
+
const schema = z7.object({
|
|
32226
|
+
keys: z7.boolean().optional(),
|
|
32227
|
+
exitCode: z7.boolean().optional(),
|
|
32228
|
+
json: z7.boolean().optional()
|
|
32229
|
+
});
|
|
32230
|
+
await runStatus(validateOrExit(schema, opts));
|
|
32231
|
+
});
|
|
32232
|
+
|
|
32233
|
+
// src/commands/telemetry.ts
|
|
32234
|
+
import { Command as Command6 } from "commander";
|
|
32235
|
+
import { z as z8 } from "zod/v4";
|
|
31988
32236
|
var REASONS = {
|
|
31989
32237
|
env: `disabled by $${TELEMETRY_ENV_VAR}`,
|
|
31990
32238
|
"do-not-track": `disabled by $${DO_NOT_TRACK_ENV_VAR}`,
|
|
@@ -32005,12 +32253,12 @@ async function printStatus(json2) {
|
|
|
32005
32253
|
`Turn it off with \`tolkbot telemetry off\`, $${TELEMETRY_ENV_VAR}=0 or $${DO_NOT_TRACK_ENV_VAR}=1.`
|
|
32006
32254
|
);
|
|
32007
32255
|
}
|
|
32008
|
-
var telemetryCommand = new
|
|
32256
|
+
var telemetryCommand = new Command6("telemetry").description(
|
|
32009
32257
|
"Control anonymous usage reporting"
|
|
32010
32258
|
);
|
|
32011
32259
|
telemetryCommand.command("status", { isDefault: true }).description("Show whether telemetry is on and why").option("--json", "Output as JSON (machine-readable)").action(async (opts) => {
|
|
32012
32260
|
const parsed = validateOrExit(
|
|
32013
|
-
|
|
32261
|
+
z8.object({ json: z8.boolean().optional() }),
|
|
32014
32262
|
opts
|
|
32015
32263
|
);
|
|
32016
32264
|
await printStatus(parsed.json);
|
|
@@ -32027,8 +32275,8 @@ telemetryCommand.command("on").description("Resume reporting usage from this mac
|
|
|
32027
32275
|
});
|
|
32028
32276
|
|
|
32029
32277
|
// src/commands/translate/index.ts
|
|
32030
|
-
import { Command as
|
|
32031
|
-
import { z as
|
|
32278
|
+
import { Command as Command7 } from "commander";
|
|
32279
|
+
import { z as z9 } from "zod/v4";
|
|
32032
32280
|
|
|
32033
32281
|
// src/commands/translate/adopt.tsx
|
|
32034
32282
|
var STAMP_CHUNK2 = 200;
|
|
@@ -32109,8 +32357,8 @@ async function runAdopt(opts) {
|
|
|
32109
32357
|
|
|
32110
32358
|
// src/commands/translate/edit.tsx
|
|
32111
32359
|
import path10 from "path";
|
|
32112
|
-
import { Spinner as
|
|
32113
|
-
import { Box as
|
|
32360
|
+
import { Spinner as Spinner14 } from "@inkjs/ui";
|
|
32361
|
+
import { Box as Box17, render as render16, Text as Text17 } from "ink";
|
|
32114
32362
|
|
|
32115
32363
|
// src/utils/locale-files.ts
|
|
32116
32364
|
import path9 from "path";
|
|
@@ -32148,25 +32396,25 @@ function resolveKeyInFile(key, targetFile, fileCount, namespace) {
|
|
|
32148
32396
|
}
|
|
32149
32397
|
|
|
32150
32398
|
// src/commands/translate/edit.tsx
|
|
32151
|
-
import { jsx as
|
|
32399
|
+
import { jsx as jsx17, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
32152
32400
|
function EditUI({ state }) {
|
|
32153
32401
|
if (state.type === "editing") {
|
|
32154
|
-
return /* @__PURE__ */
|
|
32155
|
-
/* @__PURE__ */
|
|
32156
|
-
/* @__PURE__ */
|
|
32402
|
+
return /* @__PURE__ */ jsxs17(Box17, { children: [
|
|
32403
|
+
/* @__PURE__ */ jsx17(Spinner14, {}),
|
|
32404
|
+
/* @__PURE__ */ jsx17(Text17, { children: " Editing translation\u2026" })
|
|
32157
32405
|
] });
|
|
32158
32406
|
}
|
|
32159
|
-
return /* @__PURE__ */
|
|
32160
|
-
/* @__PURE__ */
|
|
32161
|
-
/* @__PURE__ */
|
|
32162
|
-
/* @__PURE__ */
|
|
32407
|
+
return /* @__PURE__ */ jsxs17(Box17, { flexDirection: "column", children: [
|
|
32408
|
+
/* @__PURE__ */ jsxs17(Box17, { children: [
|
|
32409
|
+
/* @__PURE__ */ jsx17(Text17, { color: "green", children: "\u2713" }),
|
|
32410
|
+
/* @__PURE__ */ jsxs17(Text17, { children: [
|
|
32163
32411
|
" ",
|
|
32164
32412
|
"Updated ",
|
|
32165
|
-
/* @__PURE__ */
|
|
32413
|
+
/* @__PURE__ */ jsx17(Text17, { bold: true, children: state.key })
|
|
32166
32414
|
] })
|
|
32167
32415
|
] }),
|
|
32168
|
-
/* @__PURE__ */
|
|
32169
|
-
/* @__PURE__ */
|
|
32416
|
+
/* @__PURE__ */ jsx17(Box17, { paddingLeft: 2, children: /* @__PURE__ */ jsx17(Text17, { dimColor: true, children: state.value }) }),
|
|
32417
|
+
/* @__PURE__ */ jsx17(Box17, { marginTop: 1, children: /* @__PURE__ */ jsxs17(Text17, { dimColor: true, children: [
|
|
32170
32418
|
"File: ",
|
|
32171
32419
|
state.filePath
|
|
32172
32420
|
] }) })
|
|
@@ -32223,20 +32471,20 @@ async function runEdit(opts) {
|
|
|
32223
32471
|
value: result2.value
|
|
32224
32472
|
});
|
|
32225
32473
|
}
|
|
32226
|
-
const { unmount } = renderTransient(/* @__PURE__ */
|
|
32474
|
+
const { unmount } = renderTransient(/* @__PURE__ */ jsx17(EditUI, { state: { type: "editing" } }));
|
|
32227
32475
|
let result;
|
|
32228
32476
|
try {
|
|
32229
32477
|
result = await performEdit(opts);
|
|
32230
32478
|
} finally {
|
|
32231
32479
|
unmount();
|
|
32232
32480
|
}
|
|
32233
|
-
render16(/* @__PURE__ */
|
|
32481
|
+
render16(/* @__PURE__ */ jsx17(EditUI, { state: { type: "success", ...result } })).unmount();
|
|
32234
32482
|
}
|
|
32235
32483
|
|
|
32236
32484
|
// src/commands/translate/translate.tsx
|
|
32237
|
-
import { Spinner as
|
|
32238
|
-
import { Box as
|
|
32239
|
-
import { jsx as
|
|
32485
|
+
import { Spinner as Spinner15 } from "@inkjs/ui";
|
|
32486
|
+
import { Box as Box18, Text as Text18 } from "ink";
|
|
32487
|
+
import { jsx as jsx18, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
32240
32488
|
function planOutput(plan) {
|
|
32241
32489
|
return {
|
|
32242
32490
|
...plan.summary,
|
|
@@ -32245,7 +32493,7 @@ function planOutput(plan) {
|
|
|
32245
32493
|
untrackedKeys: plan.untrackedKeys.map((k) => k.key)
|
|
32246
32494
|
};
|
|
32247
32495
|
}
|
|
32248
|
-
function
|
|
32496
|
+
function fullKey5(namespace, key) {
|
|
32249
32497
|
return namespace ? `${namespace}.${key}` : key;
|
|
32250
32498
|
}
|
|
32251
32499
|
function characters(text) {
|
|
@@ -32273,21 +32521,11 @@ async function runTranslate(opts) {
|
|
|
32273
32521
|
}
|
|
32274
32522
|
await runLanguages(ctx, srcLocale, dstLocales, opts);
|
|
32275
32523
|
}
|
|
32276
|
-
async function creditBalance(ctx) {
|
|
32277
|
-
try {
|
|
32278
|
-
const balance = await ctx.client.query(api.usage.getCreditBalance, {
|
|
32279
|
-
organizationId: ctx.project.organizationId
|
|
32280
|
-
});
|
|
32281
|
-
return balance?.total ?? null;
|
|
32282
|
-
} catch {
|
|
32283
|
-
return null;
|
|
32284
|
-
}
|
|
32285
|
-
}
|
|
32286
32524
|
var NO_ESTIMATE = "No credit estimate exists for this project yet. Keys and characters are what a run would send.";
|
|
32287
32525
|
async function runDryRun(ctx, srcLocale, dstLocales, opts) {
|
|
32288
32526
|
const languages = [];
|
|
32289
32527
|
const progress = renderTransient(
|
|
32290
|
-
/* @__PURE__ */
|
|
32528
|
+
/* @__PURE__ */ jsx18(Working, { text: `Planning ${dstLocales.join(", ")}\u2026` })
|
|
32291
32529
|
);
|
|
32292
32530
|
try {
|
|
32293
32531
|
for (const dstLocale of dstLocales) {
|
|
@@ -32302,7 +32540,7 @@ async function runDryRun(ctx, srcLocale, dstLocales, opts) {
|
|
|
32302
32540
|
0
|
|
32303
32541
|
),
|
|
32304
32542
|
tasks: plan.tasks.map((task) => ({
|
|
32305
|
-
key:
|
|
32543
|
+
key: fullKey5(task.namespace, task.key),
|
|
32306
32544
|
path: task.path,
|
|
32307
32545
|
reason: task.reason,
|
|
32308
32546
|
...opts.verbose ? { src: task.src } : {}
|
|
@@ -32317,7 +32555,7 @@ async function runDryRun(ctx, srcLocale, dstLocales, opts) {
|
|
|
32317
32555
|
keys: languages.reduce((n, l) => n + l.keys, 0),
|
|
32318
32556
|
characters: languages.reduce((n, l) => n + l.characters, 0)
|
|
32319
32557
|
};
|
|
32320
|
-
const balance = await
|
|
32558
|
+
const balance = await readCreditBalance(ctx);
|
|
32321
32559
|
track("cli_translate_completed", {
|
|
32322
32560
|
mode: "plan",
|
|
32323
32561
|
key_count: total.keys,
|
|
@@ -32365,9 +32603,9 @@ In all: ${total.keys} key(s), ${total.characters} characters.` + (balance === nu
|
|
|
32365
32603
|
console.log("Nothing was started. Run without --dry-run to translate.");
|
|
32366
32604
|
}
|
|
32367
32605
|
function Working({ text }) {
|
|
32368
|
-
return /* @__PURE__ */
|
|
32369
|
-
/* @__PURE__ */
|
|
32370
|
-
/* @__PURE__ */
|
|
32606
|
+
return /* @__PURE__ */ jsxs18(Box18, { children: [
|
|
32607
|
+
/* @__PURE__ */ jsx18(Spinner15, {}),
|
|
32608
|
+
/* @__PURE__ */ jsxs18(Text18, { children: [
|
|
32371
32609
|
" ",
|
|
32372
32610
|
text
|
|
32373
32611
|
] })
|
|
@@ -32420,7 +32658,7 @@ async function runLanguages(ctx, srcLocale, dstLocales, opts) {
|
|
|
32420
32658
|
};
|
|
32421
32659
|
for (const dstLocale of dstLocales) {
|
|
32422
32660
|
const progress = renderTransient(
|
|
32423
|
-
/* @__PURE__ */
|
|
32661
|
+
/* @__PURE__ */ jsx18(Working, { text: `${dstLocale}: planning\u2026` })
|
|
32424
32662
|
);
|
|
32425
32663
|
try {
|
|
32426
32664
|
const { tasks, plan } = await generateTasks(
|
|
@@ -32453,7 +32691,7 @@ async function runLanguages(ctx, srcLocale, dstLocales, opts) {
|
|
|
32453
32691
|
printNotes(json2, leftOut);
|
|
32454
32692
|
continue;
|
|
32455
32693
|
}
|
|
32456
|
-
progress.rerender(/* @__PURE__ */
|
|
32694
|
+
progress.rerender(/* @__PURE__ */ jsx18(Working, { text: progressText(dstLocale, null) }));
|
|
32457
32695
|
let jobId;
|
|
32458
32696
|
try {
|
|
32459
32697
|
jobId = await startTranslationJob({
|
|
@@ -32490,7 +32728,7 @@ async function runLanguages(ctx, srcLocale, dstLocales, opts) {
|
|
|
32490
32728
|
project.organizationId,
|
|
32491
32729
|
jobId,
|
|
32492
32730
|
(latest) => progress.rerender(
|
|
32493
|
-
/* @__PURE__ */
|
|
32731
|
+
/* @__PURE__ */ jsx18(Working, { text: progressText(dstLocale, latest) })
|
|
32494
32732
|
)
|
|
32495
32733
|
);
|
|
32496
32734
|
} catch (error62) {
|
|
@@ -32515,7 +32753,7 @@ async function runLanguages(ctx, srcLocale, dstLocales, opts) {
|
|
|
32515
32753
|
};
|
|
32516
32754
|
if (summary.status !== "cancelled") {
|
|
32517
32755
|
progress.rerender(
|
|
32518
|
-
/* @__PURE__ */
|
|
32756
|
+
/* @__PURE__ */ jsx18(Working, { text: `${dstLocale}: writing the files\u2026` })
|
|
32519
32757
|
);
|
|
32520
32758
|
const applied = await applyJob(ctx, jobId);
|
|
32521
32759
|
finished.written = { files: applied.files, keys: applied.keys };
|
|
@@ -32579,7 +32817,7 @@ function checkTranslateOptions(opts) {
|
|
|
32579
32817
|
|
|
32580
32818
|
// src/commands/translate/index.ts
|
|
32581
32819
|
var RETRANSLATE_UNTRACKED_HELP = "Also retranslate translations TolkBot has no record of (kept by default)";
|
|
32582
|
-
var translateCommand = new
|
|
32820
|
+
var translateCommand = new Command7("translate").description(
|
|
32583
32821
|
"Translate what is missing or changed, and write the results into your locale files"
|
|
32584
32822
|
).option(
|
|
32585
32823
|
"--src <locale>",
|
|
@@ -32595,15 +32833,15 @@ var translateCommand = new Command6("translate").description(
|
|
|
32595
32833
|
"Run 'tolkbot translate --help'. Jobs are under 'tolkbot jobs'."
|
|
32596
32834
|
);
|
|
32597
32835
|
}
|
|
32598
|
-
const schema =
|
|
32599
|
-
src:
|
|
32600
|
-
dst:
|
|
32601
|
-
all:
|
|
32602
|
-
dryRun:
|
|
32603
|
-
wait:
|
|
32604
|
-
retranslateUntracked:
|
|
32605
|
-
verbose:
|
|
32606
|
-
json:
|
|
32836
|
+
const schema = z9.object({
|
|
32837
|
+
src: z9.string().min(1).optional(),
|
|
32838
|
+
dst: z9.string().min(1).optional(),
|
|
32839
|
+
all: z9.boolean().optional(),
|
|
32840
|
+
dryRun: z9.boolean().optional(),
|
|
32841
|
+
wait: z9.boolean(),
|
|
32842
|
+
retranslateUntracked: z9.boolean().optional(),
|
|
32843
|
+
verbose: z9.boolean().optional(),
|
|
32844
|
+
json: z9.boolean().optional()
|
|
32607
32845
|
});
|
|
32608
32846
|
const parsed = validateOrExit(schema, opts);
|
|
32609
32847
|
checkTranslateOptions(parsed);
|
|
@@ -32615,11 +32853,11 @@ translateCommand.command("adopt").description(
|
|
|
32615
32853
|
"--src <locale>",
|
|
32616
32854
|
"Source locale (defaults to the project's base language)"
|
|
32617
32855
|
).option("--dst <locale>", "Destination locale").option("--all", "Every target language").option("--json", "Output as JSON (machine-readable)").action(async (opts) => {
|
|
32618
|
-
const schema =
|
|
32619
|
-
src:
|
|
32620
|
-
dst:
|
|
32621
|
-
all:
|
|
32622
|
-
json:
|
|
32856
|
+
const schema = z9.object({
|
|
32857
|
+
src: z9.string().min(1).optional(),
|
|
32858
|
+
dst: z9.string().min(1).optional(),
|
|
32859
|
+
all: z9.boolean().optional(),
|
|
32860
|
+
json: z9.boolean().optional()
|
|
32623
32861
|
});
|
|
32624
32862
|
const parsed = validateOrExit(schema, opts);
|
|
32625
32863
|
if (parsed.dst && parsed.all) {
|
|
@@ -32628,19 +32866,19 @@ translateCommand.command("adopt").description(
|
|
|
32628
32866
|
await runAdopt(parsed);
|
|
32629
32867
|
});
|
|
32630
32868
|
translateCommand.command("edit").description("Edit a translation value in a locale file").requiredOption("--key <key>", "Translation key (e.g. common.hello)").requiredOption("--locale <locale>", "Target locale (e.g. fr, de)").requiredOption("--value <text>", "New translation value").option("--namespace <ns>", "Namespace to resolve file (if ambiguous)").option("--json", "Output as JSON (machine-readable)").action(async (opts) => {
|
|
32631
|
-
const schema =
|
|
32632
|
-
key:
|
|
32633
|
-
locale:
|
|
32634
|
-
value:
|
|
32635
|
-
namespace:
|
|
32636
|
-
json:
|
|
32869
|
+
const schema = z9.object({
|
|
32870
|
+
key: z9.string().min(1),
|
|
32871
|
+
locale: z9.string().min(1),
|
|
32872
|
+
value: z9.string().min(1),
|
|
32873
|
+
namespace: z9.string().optional(),
|
|
32874
|
+
json: z9.boolean().optional()
|
|
32637
32875
|
});
|
|
32638
32876
|
const parsed = validateOrExit(schema, opts);
|
|
32639
32877
|
await runEdit(parsed);
|
|
32640
32878
|
});
|
|
32641
32879
|
|
|
32642
32880
|
// src/commands/validate.tsx
|
|
32643
|
-
import { Box as
|
|
32881
|
+
import { Box as Box19, render as render17, Text as Text19 } from "ink";
|
|
32644
32882
|
|
|
32645
32883
|
// ../ai/src/validators/placeholders.ts
|
|
32646
32884
|
var IDENTIFIER = /^[A-Za-z0-9_$][A-Za-z0-9_$.[\]-]*$/;
|
|
@@ -33733,7 +33971,7 @@ function finalize2(issues, stats, strict) {
|
|
|
33733
33971
|
}
|
|
33734
33972
|
|
|
33735
33973
|
// src/commands/validate.tsx
|
|
33736
|
-
import { jsx as
|
|
33974
|
+
import { jsx as jsx19, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
33737
33975
|
var LEVEL_COLOR = {
|
|
33738
33976
|
error: "red",
|
|
33739
33977
|
warning: "yellow",
|
|
@@ -33742,12 +33980,12 @@ var LEVEL_COLOR = {
|
|
|
33742
33980
|
var GUTTER = 9;
|
|
33743
33981
|
function IssueLine({ issue: issue2 }) {
|
|
33744
33982
|
const location = [issue2.file, issue2.key].filter(Boolean).join(" \xB7 ");
|
|
33745
|
-
return /* @__PURE__ */
|
|
33746
|
-
/* @__PURE__ */
|
|
33747
|
-
/* @__PURE__ */
|
|
33748
|
-
/* @__PURE__ */
|
|
33983
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
|
|
33984
|
+
/* @__PURE__ */ jsxs19(Box19, { children: [
|
|
33985
|
+
/* @__PURE__ */ jsx19(Box19, { width: GUTTER, flexShrink: 0, children: /* @__PURE__ */ jsx19(Text19, { color: LEVEL_COLOR[issue2.level], children: issue2.level }) }),
|
|
33986
|
+
/* @__PURE__ */ jsx19(Box19, { flexGrow: 1, children: /* @__PURE__ */ jsx19(Text19, { children: issue2.message }) })
|
|
33749
33987
|
] }),
|
|
33750
|
-
/* @__PURE__ */
|
|
33988
|
+
/* @__PURE__ */ jsx19(Box19, { marginLeft: GUTTER, children: /* @__PURE__ */ jsxs19(Text19, { dimColor: true, children: [
|
|
33751
33989
|
issue2.rule,
|
|
33752
33990
|
location ? ` \u2014 ${location}` : ""
|
|
33753
33991
|
] }) })
|
|
@@ -33756,20 +33994,20 @@ function IssueLine({ issue: issue2 }) {
|
|
|
33756
33994
|
function ReportUI({ report }) {
|
|
33757
33995
|
const { counts, stats } = report;
|
|
33758
33996
|
const summary = ["error", "warning", "info"].filter((level) => counts[level] > 0).map((level) => `${counts[level]} ${level}(s)`).join(", ");
|
|
33759
|
-
return /* @__PURE__ */
|
|
33760
|
-
/* @__PURE__ */
|
|
33761
|
-
/* @__PURE__ */
|
|
33762
|
-
/* @__PURE__ */
|
|
33997
|
+
return /* @__PURE__ */ jsxs19(Box19, { flexDirection: "column", children: [
|
|
33998
|
+
/* @__PURE__ */ jsxs19(Box19, { children: [
|
|
33999
|
+
/* @__PURE__ */ jsx19(Text19, { color: report.valid ? "green" : "red", children: report.valid ? "\u2713" : "\u2717" }),
|
|
34000
|
+
/* @__PURE__ */ jsxs19(Text19, { children: [
|
|
33763
34001
|
" Validation ",
|
|
33764
34002
|
report.valid ? "passed" : "failed"
|
|
33765
34003
|
] }),
|
|
33766
|
-
summary ? /* @__PURE__ */
|
|
34004
|
+
summary ? /* @__PURE__ */ jsxs19(Text19, { dimColor: true, children: [
|
|
33767
34005
|
" \u2014 ",
|
|
33768
34006
|
summary
|
|
33769
34007
|
] }) : null
|
|
33770
34008
|
] }),
|
|
33771
|
-
stats.locales.length > 0 && /* @__PURE__ */
|
|
33772
|
-
/* @__PURE__ */
|
|
34009
|
+
stats.locales.length > 0 && /* @__PURE__ */ jsxs19(Box19, { marginTop: 1, flexDirection: "column", children: [
|
|
34010
|
+
/* @__PURE__ */ jsxs19(Text19, { dimColor: true, children: [
|
|
33773
34011
|
stats.filesChecked,
|
|
33774
34012
|
" ",
|
|
33775
34013
|
stats.format,
|
|
@@ -33778,18 +34016,18 @@ function ReportUI({ report }) {
|
|
|
33778
34016
|
stats.totalKeys,
|
|
33779
34017
|
" keys"
|
|
33780
34018
|
] }),
|
|
33781
|
-
/* @__PURE__ */
|
|
34019
|
+
/* @__PURE__ */ jsxs19(Text19, { dimColor: true, children: [
|
|
33782
34020
|
"Locales: ",
|
|
33783
34021
|
stats.locales.join(", "),
|
|
33784
34022
|
stats.baseLocale ? ` (base: ${stats.baseLocale})` : ""
|
|
33785
34023
|
] }),
|
|
33786
|
-
stats.pattern && /* @__PURE__ */
|
|
34024
|
+
stats.pattern && /* @__PURE__ */ jsxs19(Text19, { dimColor: true, children: [
|
|
33787
34025
|
"Pattern: ",
|
|
33788
34026
|
stats.pattern
|
|
33789
34027
|
] })
|
|
33790
34028
|
] }),
|
|
33791
|
-
report.issues.length > 0 && /* @__PURE__ */
|
|
33792
|
-
!report.strict && counts.warning > 0 && report.valid && /* @__PURE__ */
|
|
34029
|
+
report.issues.length > 0 && /* @__PURE__ */ jsx19(Box19, { marginTop: 1, flexDirection: "column", gap: 1, children: report.issues.map((issue2, idx) => /* @__PURE__ */ jsx19(IssueLine, { issue: issue2 }, idx)) }),
|
|
34030
|
+
!report.strict && counts.warning > 0 && report.valid && /* @__PURE__ */ jsx19(Box19, { marginTop: 1, children: /* @__PURE__ */ jsx19(Text19, { dimColor: true, children: "Warnings did not fail this run. Use --strict to treat them as errors." }) })
|
|
33793
34031
|
] });
|
|
33794
34032
|
}
|
|
33795
34033
|
function emit(report, json2) {
|
|
@@ -33809,7 +34047,7 @@ function emit(report, json2) {
|
|
|
33809
34047
|
if (!report.valid) fail(validationFailure(report));
|
|
33810
34048
|
return;
|
|
33811
34049
|
}
|
|
33812
|
-
render17(/* @__PURE__ */
|
|
34050
|
+
render17(/* @__PURE__ */ jsx19(ReportUI, { report })).unmount();
|
|
33813
34051
|
process.exitCode = exitCode;
|
|
33814
34052
|
}
|
|
33815
34053
|
function validationFailure(report) {
|
|
@@ -33868,7 +34106,7 @@ function commandPath(command) {
|
|
|
33868
34106
|
return names.join(" ");
|
|
33869
34107
|
}
|
|
33870
34108
|
function buildProgram() {
|
|
33871
|
-
const program = new
|
|
34109
|
+
const program = new Command8().name("tolkbot").description("Localization workflow for your repo").version(version, "-v, --version", "Output the version number").helpOption("-h, --help", "Show help").helpCommand("help [command]", "Show help for a command").option("--token <token>", TOKEN_HELP).enablePositionalOptions();
|
|
33872
34110
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
33873
34111
|
const { token } = actionCommand.optsWithGlobals();
|
|
33874
34112
|
setTokenOverride(token);
|
|
@@ -33898,6 +34136,7 @@ function buildProgram() {
|
|
|
33898
34136
|
program.addCommand(glossaryCommand);
|
|
33899
34137
|
program.addCommand(jobsCommand);
|
|
33900
34138
|
program.addCommand(learningsCommand);
|
|
34139
|
+
program.addCommand(statusCommand);
|
|
33901
34140
|
program.addCommand(telemetryCommand);
|
|
33902
34141
|
program.addCommand(translateCommand);
|
|
33903
34142
|
program.addHelpText("after", PROGRAM_HELP_FOOTER);
|
|
@@ -33955,6 +34194,7 @@ var PROGRAM_HELP_FOOTER = `
|
|
|
33955
34194
|
Examples:
|
|
33956
34195
|
$ tolkbot auth login
|
|
33957
34196
|
$ tolkbot init
|
|
34197
|
+
$ tolkbot status
|
|
33958
34198
|
$ tolkbot translate --all
|
|
33959
34199
|
$ tolkbot translate --all --dry-run
|
|
33960
34200
|
$ tolkbot jobs list
|
package/package.json
CHANGED