@pify/usage 0.12.0 → 0.12.1

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 CHANGED
@@ -44,7 +44,7 @@ By project (all time)
44
44
  D--project-shop-api $6.60 · 3.6M tok
45
45
  ```
46
46
 
47
- `/usage export` writes the history out — `by-model.csv`, `by-day.csv`, `by-project.csv` and `totals.json`, full precision — into a timestamped folder under the OS temp directory (or `PIFY_USAGE_EXPORT_DIR`), never into the repository or your home, and prints the path.
47
+ `/usage export` writes the history out — `by-model.csv`, `by-day.csv`, `by-project.csv` and `totals.json`, full precision — into a timestamped folder under the OS temp directory (or `PIFY_USAGE_EXPORT_DIR`), never into the repository or your home, readable by you only, and prints the path.
48
48
 
49
49
  The per-file scan cache is also kept on disk (`usage-scan-cache.json` next to pi's other state, keyed by size and mtime, versioned), so a fresh `pi` no longer pays the whole cold scan on its first `/usage`: it is read once before the first scan and rewritten after each completed one; a corrupt or older file is ignored and rebuilt, and only files the latest scan saw are kept.
50
50
 
@@ -332,12 +332,16 @@ export default function usage(pi: ExtensionAPI) {
332
332
  const now = Date.now();
333
333
  const stamp = new Date(now).toISOString().replace(/[:.]/g, "-");
334
334
  const dir = join(process.env.PIFY_USAGE_EXPORT_DIR?.trim() || join(tmpdir(), "pify-usage"), stamp);
335
+ // Spend and project names are the user's business: the folder and
336
+ // files are readable by the user only, and `wx` never follows a link
337
+ // someone else placed at the path (pi 1.0.3's own output-file rule).
338
+ const fileOptions = { mode: 0o600, flag: "wx" } as const;
335
339
  try {
336
- mkdirSync(dir, { recursive: true });
337
- writeFileSync(join(dir, "by-model.csv"), buildByModelCsv(history.byModel));
338
- writeFileSync(join(dir, "by-day.csv"), buildByDayCsv(history.byDay));
339
- writeFileSync(join(dir, "by-project.csv"), buildByProjectCsv(history.byProject));
340
- writeFileSync(join(dir, "totals.json"), buildTotalsJson(history.total, history.files, now));
340
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
341
+ writeFileSync(join(dir, "by-model.csv"), buildByModelCsv(history.byModel), fileOptions);
342
+ writeFileSync(join(dir, "by-day.csv"), buildByDayCsv(history.byDay), fileOptions);
343
+ writeFileSync(join(dir, "by-project.csv"), buildByProjectCsv(history.byProject), fileOptions);
344
+ writeFileSync(join(dir, "totals.json"), buildTotalsJson(history.total, history.files, now), fileOptions);
341
345
  } catch (err) {
342
346
  ctx.ui.notify(`Export failed: ${err instanceof Error ? err.message : String(err)}`, "error");
343
347
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pify/usage",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "Token and cost reporting for pi sessions: live footer, local-history dashboard with per-project costs, opt-in provider quota",
5
5
  "keywords": [
6
6
  "pi-package",
package/src/sessions.ts CHANGED
@@ -65,7 +65,7 @@ export function persistScanCache(file: string): number {
65
65
  try {
66
66
  mkdirSync(dirname(file), { recursive: true });
67
67
  const tmp = `${file}.${process.pid}.tmp`;
68
- writeFileSync(tmp, JSON.stringify({ version: SCAN_CACHE_VERSION, entries }));
68
+ writeFileSync(tmp, JSON.stringify({ version: SCAN_CACHE_VERSION, entries }), { mode: 0o600 });
69
69
  renameSync(tmp, file);
70
70
  } catch {
71
71
  // An unwritable cache costs the next process one cold scan, nothing else.