From 576b11106f2ab2810ecc99035ef69fce7c0538b0 Mon Sep 17 00:00:00 2001 From: William Valentin Date: Fri, 27 Feb 2026 13:30:08 -0800 Subject: [PATCH] fix(audit): expand home paths across phase0 CLI scripts Apply HOME-based ~ expansion to summarize/drift/prune audit scripts for input/output path flags to match capture behavior and avoid literal ~/ path bugs. Architecture/protocol diagrams reviewed; no updates needed for this path-resolution change. --- docs/plans/state.json | 13 +++++++++++++ .../check-phase0-baseline-backend-drift.ts | 19 +++++++++++++++---- scripts/prune-phase0-baseline-artifacts.ts | 17 ++++++++++++++--- scripts/summarize-phase0-baseline.ts | 17 +++++++++++++++-- 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/docs/plans/state.json b/docs/plans/state.json index 6157d09..cfc067d 100644 --- a/docs/plans/state.json +++ b/docs/plans/state.json @@ -604,6 +604,19 @@ ], "test_status": "pnpm typecheck + node --import tsx/esm scripts/prune-phase0-baseline-artifacts.ts --artifacts-dir --format json passing" }, + "phase0-live-baseline-home-path-expansion-consistency": { + "status": "completed", + "date": "2026-02-27", + "updated": "2026-02-27", + "summary": "Added `~` home-path expansion consistency across phase-0 summarize/drift/prune CLIs for audit/artefact path flags (`--audit`, `--artifacts-dir`, `--summary-*-out`, `--out`) to match capture script behavior.", + "files_modified": [ + "scripts/summarize-phase0-baseline.ts", + "scripts/check-phase0-baseline-backend-drift.ts", + "scripts/prune-phase0-baseline-artifacts.ts", + "docs/plans/state.json" + ], + "test_status": "pnpm typecheck + HOME=/tmp path-expansion smoke checks passing" + }, "phase0-instrumentation-ticket-checklist": { "status": "completed", "date": "2026-02-25", diff --git a/scripts/check-phase0-baseline-backend-drift.ts b/scripts/check-phase0-baseline-backend-drift.ts index 6204cda..75ea545 100644 --- a/scripts/check-phase0-baseline-backend-drift.ts +++ b/scripts/check-phase0-baseline-backend-drift.ts @@ -176,6 +176,17 @@ function formatFreshnessHours(value: number | null): string { return `${Math.round(value * 100) / 100}`; } +function expandHomePath(pathValue: string): string { + if (!pathValue.startsWith('~')) { + return pathValue; + } + const home = process.env.HOME; + if (!home) { + return pathValue; + } + return resolve(home, pathValue.slice(1)); +} + async function writeOutput(pathValue: string, output: string): Promise { await mkdir(dirname(pathValue), { recursive: true }); await writeFile(pathValue, `${output}\n`, 'utf8'); @@ -370,7 +381,7 @@ async function main(): Promise { return; } - const artifactsDir = resolve(values['artifacts-dir'] ?? 'docs/plans/artifacts'); + const artifactsDir = resolve(expandHomePath(values['artifacts-dir'] ?? 'docs/plans/artifacts')); const backends = parseBackends(values.backend); const candidateTag = values.tag ? normalizeArtifactTag(values.tag, '--tag') @@ -388,12 +399,12 @@ async function main(): Promise { const defaultBaseName = resolve(artifactsDir, `phase0_baseline_live_backend_drift_${reportTag}`); const summaryJsonOut = values['summary-json-out'] - ? resolve(values['summary-json-out']) + ? resolve(expandHomePath(values['summary-json-out'])) : writeDefaultArtifacts ? `${defaultBaseName}.json` : undefined; const summaryMdOut = values['summary-md-out'] - ? resolve(values['summary-md-out']) + ? resolve(expandHomePath(values['summary-md-out'])) : writeDefaultArtifacts ? `${defaultBaseName}.md` : undefined; @@ -497,7 +508,7 @@ async function main(): Promise { } if (values.out) { - await writeOutput(resolve(values.out), output); + await writeOutput(resolve(expandHomePath(values.out)), output); } else { process.stdout.write(`${output}\n`); } diff --git a/scripts/prune-phase0-baseline-artifacts.ts b/scripts/prune-phase0-baseline-artifacts.ts index ac77f9c..0fc6c5d 100644 --- a/scripts/prune-phase0-baseline-artifacts.ts +++ b/scripts/prune-phase0-baseline-artifacts.ts @@ -30,6 +30,17 @@ function isoDateTagNow(): string { return new Date().toISOString().slice(0, 10); } +function expandHomePath(pathValue: string): string { + if (!pathValue.startsWith('~')) { + return pathValue; + } + const home = process.env.HOME; + if (!home) { + return pathValue; + } + return resolve(home, pathValue.slice(1)); +} + function parseOptionalInteger(raw: string | undefined, flag: string): number | undefined { if (!raw) { return undefined; @@ -111,7 +122,7 @@ async function main(): Promise { return; } - const artifactsDir = resolve(values['artifacts-dir'] ?? 'docs/plans/artifacts'); + const artifactsDir = resolve(expandHomePath(values['artifacts-dir'] ?? 'docs/plans/artifacts')); const keepPerFamily = parseOptionalInteger(values['keep-per-family'], '--keep-per-family') ?? 8; const apply = Boolean(values.apply); const format = values.format ?? 'text'; @@ -124,12 +135,12 @@ async function main(): Promise { const defaultBaseName = resolve(artifactsDir, `phase0_baseline_live_prune_${reportTag}`); const summaryJsonOut = values['summary-json-out'] - ? resolve(values['summary-json-out']) + ? resolve(expandHomePath(values['summary-json-out'])) : writeDefaultArtifacts ? `${defaultBaseName}.json` : undefined; const summaryMdOut = values['summary-md-out'] - ? resolve(values['summary-md-out']) + ? resolve(expandHomePath(values['summary-md-out'])) : writeDefaultArtifacts ? `${defaultBaseName}.md` : undefined; diff --git a/scripts/summarize-phase0-baseline.ts b/scripts/summarize-phase0-baseline.ts index ae8f602..1efb902 100644 --- a/scripts/summarize-phase0-baseline.ts +++ b/scripts/summarize-phase0-baseline.ts @@ -1,6 +1,7 @@ #!/usr/bin/env node import { writeFile } from 'node:fs/promises'; +import { resolve } from 'node:path'; import { parseArgs } from 'node:util'; import { queryAuditLogs } from '../src/audit/export.js'; import { @@ -59,6 +60,17 @@ function parseCsv(value: string | undefined): string[] | undefined { return values.length > 0 ? values : undefined; } +function expandHomePath(pathValue: string): string { + if (!pathValue.startsWith('~')) { + return pathValue; + } + const home = process.env.HOME; + if (!home) { + return pathValue; + } + return resolve(home, pathValue.slice(1)); +} + function parseOptionalNumber(raw: string | undefined, flag: string): number | undefined { if (!raw) { return undefined; @@ -148,7 +160,8 @@ async function main(): Promise { const startTime = parseTime(values.since, '--since'); const endTime = parseTime(values.until, '--until'); - const events = await queryAuditLogs(values.audit, { + const auditPath = expandHomePath(values.audit); + const events = await queryAuditLogs(auditPath, { start_time: startTime, end_time: endTime, event_types: [...DEFAULT_EVENT_TYPES], @@ -170,7 +183,7 @@ async function main(): Promise { : renderPhase0BaselineMarkdown(summary, summaryOptions); if (values.out) { - await writeFile(values.out, `${output}\n`, 'utf-8'); + await writeFile(expandHomePath(values.out), `${output}\n`, 'utf-8'); } else { process.stdout.write(`${output}\n`); }