--json prints only JSON on stdout (withJsonOutput around every command: logs, tables and prompts to stderr; printJson everywhere; test runs every --json command against the fake stores and parses stdout); prices ppp compares like with like: par = the store's own US-equivalent price (Play convertRegionPrices, Apple equalizations; offline base x fx x (1 + VAT) rounded up) scaled by the PPP price level; defaults only lower, only price levels <= 0.5, World Bank high-income at par, CN at par on Apple and skipped on Play, never above par (--only-decreases, --max-ratio, --min-ratio, --max-level, --include-high-income; --floor / --ceiling kept), top-10 revenue market drops > 20 % warned (sales reports, else a static list), unchanged regions out of the sheet; price changes of existing products only with --allow-price-changes, TTY or not (a terminal yes covered them), then their own question listing each old -> new, held section in dry runs (play products, prices import, play / apple subscriptions); pitfalls 61-63; tests
This commit is contained in:
parent
bab3f63227
commit
357319a775
30 changed files with 865 additions and 209 deletions
20
cli/index.ts
20
cli/index.ts
|
|
@ -4,6 +4,7 @@
|
|||
// `--help` / `-h` anywhere prints the usage of the command (or of a group like `storebound shots`) and exits 0 before
|
||||
// anything loads; an unknown --flag (cli/data/flags.json, tools/gen-flags.ts) exits 2 with the usage, also before.
|
||||
import { parseArgs } from './lib/args';
|
||||
import { withJsonOutput } from './lib/log';
|
||||
import { toolPath } from './lib/tools';
|
||||
import { COMMANDS, PLAIN } from './commands';
|
||||
import FLAGS from './data/flags.json';
|
||||
|
|
@ -81,14 +82,19 @@ async function main(): Promise<void> {
|
|||
const bad = [...new Set(rest.filter(x => /^--[^-]/.test(x)).map(x => x.slice(2).split('=')[0]!).filter(f => !ok.has(f)))];
|
||||
if (bad.length) { console.error(`unknown option${bad.length > 1 ? 's' : ''} for storebound ${key}: ${bad.map(f => '--' + f).join(', ')}\n\n${commandUsage(key)}`); process.exit(2); }
|
||||
}
|
||||
if (PLAIN[key]) return (await PLAIN[key]![0]()).run(parseArgs(rest));
|
||||
// --json: stdout is only the JSON, every log line goes to stderr (lib/log.ts withJsonOutput)
|
||||
|
||||
const json = (f: () => Promise<void>): Promise<void> => (rest.includes('--json') && key !== 'mcp' && key !== 'serve' ? withJsonOutput(f) : f());
|
||||
if (PLAIN[key]) { const plain = PLAIN[key]![0]; return json(async () => (await plain()).run(parseArgs(rest))); }
|
||||
const args = parseArgs(rest);
|
||||
const { loadConfig } = await import('./lib/config');
|
||||
const loaded = await loadConfig(args.get('config'));
|
||||
// one writer per app and store (cli/lib/lock.ts): dry runs and reads take no lock
|
||||
const { acquireLock, lockKeys } = await import('./lib/lock');
|
||||
for (const k of lockKeys(key, args, loaded.config)) acquireLock(loaded.root, k, argv.filter(x => x !== '--force-unlock').join(' '), { force: args.has('force-unlock') });
|
||||
await (await COMMANDS[key]![0]()).run({ loaded, args });
|
||||
await json(async () => {
|
||||
const { loadConfig } = await import('./lib/config');
|
||||
const loaded = await loadConfig(args.get('config'));
|
||||
// one writer per app and store (cli/lib/lock.ts): dry runs and reads take no lock
|
||||
const { acquireLock, lockKeys } = await import('./lib/lock');
|
||||
for (const k of lockKeys(key, args, loaded.config)) acquireLock(loaded.root, k, argv.filter(x => x !== '--force-unlock').join(' '), { force: args.has('force-unlock') });
|
||||
await (await COMMANDS[key]![0]()).run({ loaded, args });
|
||||
});
|
||||
}
|
||||
|
||||
main().catch(e => { console.error(`\nerror: ${(e as Error).message}`); process.exit(1); });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue