desktop reads everything by itself: one background read scheduler (4 per store, starts spaced per account, App Store Connect X-Rate-Limit slows it below 20 % and pauses at 100 left, backoff with jitter on 429 / RESOURCE_EXHAUSTED, visible app first, one read per key), per-method TTLs over the saved reads, Settings auto-read (on) and interval (15 min, paused while hidden), Refresh all, a refresh icon and 'read 3 min ago' / 'couldn't refresh' per card, writes invalidate, status line with progress and quota; quota reaches the window through ToolResult.quota (cli/lib/quota.ts); Health top issues open with versions, sample stack (health --issue / --signature, read health_issue), Open in Play Console, Copy for AI and likely-cause hints (cli/lib/crash-hints.ts); tests/scheduler.test.ts, tests/quota-crash-hints.test.ts, boot check auto-read case
This commit is contained in:
parent
89256f1e80
commit
0fb4ce0001
46 changed files with 1531 additions and 141 deletions
|
|
@ -4,6 +4,7 @@
|
|||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { RESULT_MARK } from './log';
|
||||
import { mergeQuota, QUOTA_MARK, type QuotaInfo } from './quota';
|
||||
import { toolPath } from './tools';
|
||||
import * as rt from './rt';
|
||||
|
||||
|
|
@ -29,7 +30,7 @@ export interface RunOptions {
|
|||
}
|
||||
|
||||
/** `err`: the stderr lines only (for the command's own error line). */
|
||||
export interface RunResult { code: number; out: string; err?: string; data?: unknown; cancelled: boolean }
|
||||
export interface RunResult { code: number; out: string; err?: string; data?: unknown; cancelled: boolean; /** Store quota the run saw (cli/lib/quota.ts). */ quota?: QuotaInfo }
|
||||
|
||||
export interface Running { result: Promise<RunResult>; cancel(): void }
|
||||
|
||||
|
|
@ -73,11 +74,16 @@ export function runCommand(argv: string[], o: RunOptions): Running {
|
|||
const lines: string[] = [];
|
||||
const errs: string[] = [];
|
||||
let data: unknown;
|
||||
let quota: QuotaInfo | undefined;
|
||||
const each = (line: string, kind: 'stdout' | 'stderr'): void => {
|
||||
if (kind === 'stdout' && line.startsWith(RESULT_MARK)) {
|
||||
try { data = JSON.parse(line.slice(RESULT_MARK.length)); } catch { lines.push(line); }
|
||||
return;
|
||||
}
|
||||
if (kind === 'stderr' && line.startsWith(QUOTA_MARK)) {
|
||||
try { quota = mergeQuota(quota, JSON.parse(line.slice(QUOTA_MARK.length)) as QuotaInfo); } catch { /* a broken quota line is dropped */ }
|
||||
return;
|
||||
}
|
||||
lines.push(line);
|
||||
if (kind === 'stderr') errs.push(line);
|
||||
o.onLine?.(line, kind);
|
||||
|
|
@ -85,7 +91,7 @@ export function runCommand(argv: string[], o: RunOptions): Running {
|
|||
const result = (async (): Promise<RunResult> => {
|
||||
await Promise.all([pump(p.stdout, 'stdout', each), pump(p.stderr, 'stderr', each)]);
|
||||
const code = await p.exited;
|
||||
return { code, out: lines.join('\n').trim(), err: errs.join('\n').trim(), ...(data === undefined ? {} : { data }), cancelled };
|
||||
return { code, out: lines.join('\n').trim(), err: errs.join('\n').trim(), ...(data === undefined ? {} : { data }), ...(quota ? { quota } : {}), cancelled };
|
||||
})();
|
||||
return { result, cancel: () => { cancelled = true; p.kill(); } };
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue