From 04483c8744f16fd143f1ca7ec06cce630850bf1f Mon Sep 17 00:00:00 2001 From: posimai Date: Tue, 21 Apr 2026 15:59:07 +0900 Subject: [PATCH] =?UTF-8?q?feat(pc-audit):=20=E3=83=93=E3=83=A5=E3=83=BC?= =?UTF-8?q?=E3=83=9D=E3=83=BC=E3=83=88=E3=83=95=E3=82=A3=E3=83=83=E3=83=88?= =?UTF-8?q?=E3=83=BB=E5=85=A8BAT=E8=87=AA=E5=8B=95=E8=AA=AD=E3=81=BF?= =?UTF-8?q?=E8=BE=BC=E3=81=BF=E5=AF=BE=E5=BF=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - report-viewer: html/body overflow:hidden で 100vh 固定、3カラムがビューポートを埋める - col 1(概要)・col 2(チェック)・col 3(ポート)が独立してスクロール - 生データ・免責は col 1 のスクロール枠内に移動(グリッド外に出ない) - ファイル読込後は upload-wrap を非表示にして「別ファイルを読む」に切替 - run-audit.bat / run-audit-share.bat も JSON インジェクション方式に統一 Co-Authored-By: Claude Sonnet 4.6 --- tools/pc-audit/Invoke-PcAudit.ps1 | 2 +- tools/pc-audit/README-PORTABLE.md | 33 +++ tools/pc-audit/report-viewer.html | 457 ++++++++++++++++------------- tools/pc-audit/run-audit-share.bat | 10 +- tools/pc-audit/run-audit.bat | 10 +- 5 files changed, 309 insertions(+), 203 deletions(-) create mode 100644 tools/pc-audit/README-PORTABLE.md diff --git a/tools/pc-audit/Invoke-PcAudit.ps1 b/tools/pc-audit/Invoke-PcAudit.ps1 index 97e139a7..175595dd 100644 --- a/tools/pc-audit/Invoke-PcAudit.ps1 +++ b/tools/pc-audit/Invoke-PcAudit.ps1 @@ -1,4 +1,4 @@ -#Requires -Version 5.1 +#Requires -Version 5.1 <# .SYNOPSIS Read-only local PC audit (developer / AI-tooling focused). No writes except report output. diff --git a/tools/pc-audit/README-PORTABLE.md b/tools/pc-audit/README-PORTABLE.md new file mode 100644 index 00000000..fd46a6d8 --- /dev/null +++ b/tools/pc-audit/README-PORTABLE.md @@ -0,0 +1,33 @@ +# Posimai PC Audit(ポータブル) + +Windows PC 向けの読み取り専用監査ツールです。Node.js やリポジトリのクローンは不要です(PowerShell 5.1 が標準搭載の環境を想定)。 + +## 含まれるファイル + +| ファイル | 説明 | +|----------|------| +| `Invoke-PcAudit.ps1` | 監査本体 | +| `report-viewer.html` | 生成 JSON をブラウザで確認するビューア | +| `Run-Portable.bat` | 通常モードで実行し、終了後にビューアを開く | +| `Run-Portable-Share.bat` | 共有向け(機微を抑えた)レポートで同様に実行 | + +## 手順 + +1. ZIP を任意のフォルダに展開する(例: `C:\Tools\PosimaiPcAudit`)。 +2. `Run-Portable.bat` または `Run-Portable-Share.bat` をダブルクリックする。 +3. 同じフォルダに `out` が作成され、`latest.json` などが出力される。 +4. 開いた `report-viewer.html` で `out\latest.json` を選択する。 + +## スキャン対象について + +ポータブル配置時は、プロジェクト用のファイル走査の既定ルートが **ユーザープロファイル**(`%USERPROFILE%`)になります。リポジトリ直下を走査したい場合は、PowerShell から次のように指定できます。 + +```powershell +cd C:\展開先 +powershell -NoProfile -ExecutionPolicy Bypass -File .\Invoke-PcAudit.ps1 -ProjectRoot "D:\your\repo\root" +``` + +## 注意 + +- 管理者権限なしでも多くの情報は取得できますが、一部項目は権限により空になることがあります。 +- 本 ZIP は PWA ではなく、ローカルで動かすオフライン寄りのツールです。 diff --git a/tools/pc-audit/report-viewer.html b/tools/pc-audit/report-viewer.html index ea81081e..1e4c6772 100644 --- a/tools/pc-audit/report-viewer.html +++ b/tools/pc-audit/report-viewer.html @@ -26,43 +26,79 @@ --info-border: rgba(96,165,250,0.2); --radius: 12px; --radius-sm: 8px; + --header-h: 44px; } * { box-sizing: border-box; margin: 0; padding: 0; } - body { + + html, body { + height: 100%; + overflow: hidden; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: var(--bg); color: var(--text); line-height: 1.6; - min-height: 100vh; } - .page { padding: 2rem 1.5rem 4rem; } + /* ── Page shell ── */ + .page { + height: 100vh; + display: flex; + flex-direction: column; + padding: 0.9rem 1.5rem 0.75rem; + gap: 0.75rem; + } - .header { margin-bottom: 1.5rem; display: flex; align-items: baseline; gap: 1.5rem; flex-wrap: wrap; } - .header h1 { font-size: 1.1rem; font-weight: 600; letter-spacing: 0.05em; color: var(--text2); } - .header h1 span { color: var(--accent); } - .privacy-note { - font-size: 0.75rem; - color: var(--text3); + /* ── Header bar ── */ + .header { + flex-shrink: 0; display: flex; align-items: center; - gap: 0.4rem; + gap: 1rem; + flex-wrap: wrap; + min-height: var(--header-h); } - .privacy-dot { display: inline-block; width: 5px; height: 5px; border-radius: 50%; background: var(--accent); flex-shrink: 0; } + .header h1 { + font-size: 1rem; font-weight: 600; letter-spacing: 0.05em; color: var(--text2); + } + .header h1 span { color: var(--accent); } + .header-meta { + display: flex; align-items: center; gap: 0.75rem; flex: 1; flex-wrap: wrap; + } + .privacy-note { + font-size: 0.72rem; color: var(--text3); + display: flex; align-items: center; gap: 0.35rem; + } + .privacy-dot { + display: inline-block; width: 5px; height: 5px; + border-radius: 50%; background: var(--accent); flex-shrink: 0; + } + .alt-file-btn { + background: none; border: none; padding: 0; margin-left: auto; + font-size: 0.72rem; color: var(--text3); cursor: pointer; + text-decoration: underline; text-underline-offset: 2px; + } + .alt-file-btn:hover { color: var(--accent); } - /* Upload — shown when no auto-load, or via "別ファイル" link */ - .upload-area { - background: var(--surface); - border: 1px dashed var(--border); - border-radius: var(--radius); - padding: 1.1rem 1.25rem; - margin-bottom: 1.25rem; + /* ── Upload state (no data) ── */ + .upload-wrap { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + } + .upload-area { + background: var(--surface); border: 1px dashed var(--border); + border-radius: var(--radius); padding: 2rem 2.5rem; + width: 100%; max-width: 440px; + } + .upload-label { + font-size: 0.85rem; font-weight: 600; color: var(--text2); + margin-bottom: 0.5rem; display: block; } - .upload-label { font-size: 0.82rem; font-weight: 600; color: var(--text2); margin-bottom: 0.4rem; display: block; } .upload-path { font-size: 0.73rem; color: var(--text3); background: var(--surface2); - padding: 0.2rem 0.5rem; border-radius: var(--radius-sm); font-family: monospace; - display: inline-block; margin-bottom: 0.6rem; + padding: 0.2rem 0.5rem; border-radius: var(--radius-sm); + font-family: monospace; display: inline-block; margin-bottom: 0.75rem; } input[type="file"] { font-size: 0.82rem; color: var(--text2); cursor: pointer; max-width: 100%; } input[type="file"]::file-selector-button { @@ -71,40 +107,53 @@ cursor: pointer; margin-right: 0.5rem; } - /* "別ファイルを読む" secondary link (shown after auto-load) */ - .alt-file-link { + /* ── 3-column grid (data state) ── */ + #output { + flex: 1; + min-height: 0; display: none; - margin-bottom: 1rem; - font-size: 0.75rem; - color: var(--text3); + flex-direction: column; } - .alt-file-link button { - background: none; border: none; padding: 0; - font-size: 0.75rem; color: var(--accent); - cursor: pointer; text-decoration: underline; text-underline-offset: 2px; - } - - /* 3-column grid */ .grid3 { + flex: 1; + min-height: 0; display: grid; - grid-template-columns: 272px 1fr 1fr; - gap: 1.25rem; - align-items: start; + grid-template-columns: 264px 1fr 1fr; + gap: 1rem; } @media (max-width: 900px) { + html, body { overflow: auto; height: auto; } + .page { height: auto; overflow: visible; padding: 1rem; } + #output { display: flex !important; flex-direction: column; } .grid3 { grid-template-columns: 1fr; } - .page { padding: 1rem 1rem 3rem; } + .grid-col { max-height: 70vh; } + } + + /* ── Grid column (flex column, child scroll-pane fills it) ── */ + .grid-col { + min-height: 0; + display: flex; + flex-direction: column; + overflow: hidden; } .col-label { - font-size: 0.65rem; font-weight: 700; letter-spacing: 0.1em; + flex-shrink: 0; + font-size: 0.63rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text3); - margin-bottom: 0.75rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--border); + margin-bottom: 0.6rem; padding-bottom: 0.45rem; + border-bottom: 1px solid var(--border); } - /* Scroll panes for col 2 and col 3 */ + .filter-row { + flex-shrink: 0; + display: flex; gap: 0.4rem; margin-bottom: 0.6rem; flex-wrap: wrap; + } + + /* ── Scrollable area inside each column ── */ .scroll-pane { - max-height: calc(100vh - 190px); + flex: 1; + min-height: 0; overflow-y: auto; padding-right: 3px; scrollbar-width: thin; @@ -114,8 +163,7 @@ .scroll-pane::-webkit-scrollbar-track { background: transparent; } .scroll-pane::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; } - /* Filter chips */ - .filter-row { display: flex; gap: 0.4rem; margin-bottom: 0.7rem; flex-wrap: wrap; } + /* ── Filter chips ── */ .chip { font-size: 0.68rem; font-weight: 600; padding: 0.18rem 0.55rem; border-radius: 99px; border: 1px solid var(--border); @@ -125,144 +173,173 @@ } .chip:hover { border-color: var(--text2); color: var(--text2); } .chip.active { background: var(--surface2); color: var(--text); border-color: var(--accent); } - .chip.warn-chip.active { border-color: var(--warn-color); color: var(--warn-color); } - .chip.info-chip.active { border-color: var(--info-color); color: var(--info-color); } - .chip.scope-all-chip.active { border-color: var(--warn-color); color: var(--warn-color); } - .chip.scope-local-chip.active { border-color: var(--ok-color); color: var(--ok-color); } + .chip.warn-chip.active { border-color: var(--warn-color); color: var(--warn-color); } + .chip.info-chip.active { border-color: var(--info-color); color: var(--info-color); } + .chip.scope-all-chip.active { border-color: var(--warn-color); color: var(--warn-color); } + .chip.scope-local-chip.active { border-color: var(--ok-color); color: var(--ok-color); } - /* Summary metrics */ - .summary-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; margin-bottom: 0.75rem; } + /* ── Summary metrics ── */ + .summary-grid { + display: grid; grid-template-columns: 1fr 1fr; + gap: 0.45rem; margin-bottom: 0.65rem; + } .metric { background: var(--surface); border: 1px solid var(--border); - border-radius: var(--radius-sm); padding: 0.65rem 0.85rem; + border-radius: var(--radius-sm); padding: 0.6rem 0.8rem; } .metric.full { grid-column: 1 / -1; } - .metric-label { font-size: 0.68rem; color: var(--text3); margin-bottom: 0.12rem; } - .metric-value { font-size: 0.9rem; font-weight: 600; color: var(--text); word-break: break-all; } + .metric-label { font-size: 0.67rem; color: var(--text3); margin-bottom: 0.1rem; } + .metric-value { font-size: 0.88rem; font-weight: 600; color: var(--text); word-break: break-all; } - /* Diff card */ + /* ── Diff card ── */ .diff-card { background: var(--surface); border: 1px solid var(--border); - border-radius: var(--radius); padding: 0.9rem 1rem; margin-top: 0.75rem; + border-radius: var(--radius); padding: 0.8rem 0.9rem; margin-bottom: 0.65rem; } - .diff-card-title { font-size: 0.78rem; font-weight: 600; color: var(--text2); margin-bottom: 0.6rem; } - .diff-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; } - .diff-alert { margin-top: 0.5rem; font-size: 0.78rem; color: var(--warn-color); } + .diff-card-title { font-size: 0.77rem; font-weight: 600; color: var(--text2); margin-bottom: 0.55rem; } + .diff-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.45rem; } + .diff-alert { margin-top: 0.45rem; font-size: 0.77rem; color: var(--warn-color); } - /* Guidance cards */ + /* ── Raw data (lives in col 1 scroll pane) ── */ + .raw-details { + background: var(--surface); border: 1px solid var(--border); + border-radius: var(--radius); padding: 0.8rem 1rem; + margin-bottom: 0.65rem; + } + .raw-details summary { + cursor: pointer; font-size: 0.75rem; font-weight: 600; + color: var(--text3); user-select: none; + } + .raw-details pre { + margin-top: 0.5rem; font-size: 0.68rem; color: var(--text3); + overflow: auto; max-height: 14rem; line-height: 1.5; + } + .disclaimer { + font-size: 0.7rem; color: var(--text3); + border-top: 1px solid var(--border); padding-top: 0.75rem; margin-bottom: 0.5rem; + } + + /* ── Guidance cards ── */ .card { background: var(--surface); border: 1px solid var(--border); - border-radius: var(--radius); padding: 0.9rem 1rem; margin-bottom: 0.5rem; + border-radius: var(--radius); padding: 0.85rem 0.95rem; margin-bottom: 0.45rem; } .card.warn { background: var(--warn-dim); border-color: var(--warn-border); } .card.ok { background: var(--ok-dim); border-color: var(--ok-border); } .card.info { background: var(--info-dim); border-color: var(--info-border); } - .card-header { display: flex; align-items: flex-start; gap: 0.45rem; margin-bottom: 0.45rem; } + .card-header { display: flex; align-items: flex-start; gap: 0.4rem; margin-bottom: 0.4rem; } .badge { - font-size: 0.62rem; font-weight: 700; letter-spacing: 0.06em; - padding: 0.15rem 0.45rem; border-radius: 99px; white-space: nowrap; - flex-shrink: 0; margin-top: 0.2rem; + font-size: 0.61rem; font-weight: 700; letter-spacing: 0.06em; + padding: 0.14rem 0.42rem; border-radius: 99px; white-space: nowrap; + flex-shrink: 0; margin-top: 0.22rem; } .badge-warn { background: rgba(245,158,11,0.15); color: var(--warn-color); } .badge-ok { background: rgba(110,231,183,0.15); color: var(--ok-color); } .badge-info { background: rgba(96,165,250,0.15); color: var(--info-color); } - .card-title { font-size: 0.86rem; font-weight: 600; color: var(--text); line-height: 1.4; } - .card-body { font-size: 0.8rem; color: var(--text2); line-height: 1.65; } + .card-title { font-size: 0.85rem; font-weight: 600; color: var(--text); line-height: 1.4; } + .card-body { font-size: 0.79rem; color: var(--text2); line-height: 1.65; } .action-box { - margin-top: 0.65rem; background: var(--surface2); - border-radius: var(--radius-sm); padding: 0.6rem 0.8rem; - font-size: 0.78rem; color: var(--text2); + margin-top: 0.6rem; background: var(--surface2); + border-radius: var(--radius-sm); padding: 0.55rem 0.75rem; + font-size: 0.77rem; color: var(--text2); } .action-label { - font-size: 0.62rem; font-weight: 700; letter-spacing: 0.1em; - color: var(--accent); text-transform: uppercase; display: block; margin-bottom: 0.2rem; + font-size: 0.61rem; font-weight: 700; letter-spacing: 0.1em; + color: var(--accent); text-transform: uppercase; display: block; margin-bottom: 0.18rem; } - /* Port table */ + /* ── Port list ── */ + .port-legend { + flex-shrink: 0; + font-size: 0.72rem; color: var(--text2); + margin-bottom: 0.55rem; line-height: 1.7; + } + .port-summary-row { + display: flex; gap: 0.9rem; flex-wrap: wrap; margin-bottom: 0.55rem; + } + .port-summary-item { font-size: 0.72rem; color: var(--text3); } + .port-summary-item strong { color: var(--text); } .table-wrap { overflow-x: auto; } - table { width: 100%; border-collapse: collapse; font-size: 0.8rem; } + table { width: 100%; border-collapse: collapse; font-size: 0.78rem; } thead th { - position: sticky; top: 0; background: var(--bg); - text-align: left; padding: 0.45rem 0.6rem; - font-size: 0.63rem; font-weight: 700; letter-spacing: 0.08em; - text-transform: uppercase; color: var(--text3); border-bottom: 1px solid var(--border); - z-index: 1; + position: sticky; top: 0; z-index: 1; + background: var(--bg); + text-align: left; padding: 0.42rem 0.55rem; + font-size: 0.62rem; font-weight: 700; letter-spacing: 0.08em; + text-transform: uppercase; color: var(--text3); + border-bottom: 1px solid var(--border); } tbody tr { border-bottom: 1px solid var(--border); } tbody tr:last-child { border-bottom: none; } - tbody td { padding: 0.38rem 0.6rem; color: var(--text2); vertical-align: top; } - .addr-cell { font-family: monospace; font-size: 0.73rem; color: var(--text3); } + tbody td { padding: 0.36rem 0.55rem; color: var(--text2); vertical-align: top; } + .addr-cell { font-family: monospace; font-size: 0.71rem; color: var(--text3); } .port-cell { font-family: monospace; font-weight: 600; color: var(--text); } - .scope-all { color: var(--warn-color); font-size: 0.75rem; } - .scope-localhost { color: var(--ok-color); font-size: 0.75rem; } - .scope-specific { color: var(--info-color); font-size: 0.75rem; } - .hint-line { font-size: 0.68rem; color: var(--text3); margin-top: 0.1rem; } - .port-empty { font-size: 0.8rem; color: var(--text3); padding: 0.75rem 0; } - - /* Port legend */ - .port-legend { - font-size: 0.75rem; color: var(--text2); margin-bottom: 0.8rem; line-height: 1.7; - } - .port-summary-row { - display: flex; gap: 1rem; flex-wrap: wrap; margin-bottom: 0.8rem; - } - .port-summary-item { font-size: 0.75rem; color: var(--text3); } - .port-summary-item strong { color: var(--text); } - - /* Raw JSON */ - details { - background: var(--surface); border: 1px solid var(--border); - border-radius: var(--radius); padding: 0.9rem 1.1rem; margin-top: 1.5rem; - } - summary { cursor: pointer; font-size: 0.78rem; font-weight: 600; color: var(--text3); user-select: none; } - pre { margin-top: 0.6rem; font-size: 0.7rem; color: var(--text3); overflow: auto; max-height: 18rem; line-height: 1.5; } - .disclaimer { font-size: 0.73rem; color: var(--text3); border-top: 1px solid var(--border); padding-top: 0.9rem; margin-top: 1.5rem; } + .scope-all { color: var(--warn-color); font-size: 0.73rem; } + .scope-localhost { color: var(--ok-color); font-size: 0.73rem; } + .scope-specific { color: var(--info-color); font-size: 0.73rem; } + .hint-line { font-size: 0.66rem; color: var(--text3); margin-top: 0.08rem; } + .port-empty { font-size: 0.78rem; color: var(--text3); padding: 0.6rem 0; }
+ +

PC Audit / Posimai

-

ブラウザ内のみで動作。データは外部に送信されません。

+
+

ブラウザ内のみで動作。データは外部に送信されません。

+ +
-
- -
tools\pc-audit\out\latest.json

- + +
+
+ +
tools\pc-audit\out\latest.json

+ +
- - -