diff --git a/index.html b/index.html
index 3acc068..a64ed12 100644
--- a/index.html
+++ b/index.html
@@ -180,7 +180,23 @@
-
外観
+
GitHub 連携
+
+
Personal Access Token
+
+ github.com → Settings → Developer settings
+ → Fine-grained tokens → Generate new token
+ Permissions: Contents: Read-only
+
+
+
+
+
+
+
+
+
外観
テーマ
@@ -487,47 +503,85 @@ document.getElementById('copyBtn').addEventListener('click', async () => {
}
});
+// ── GitHub PAT 設定 ───────────────────
+const GH_PAT_KEY = 'posimai-chronicle-gh-pat';
+function getGhPat() { return localStorage.getItem(GH_PAT_KEY) || ''; }
+
+(function initGhPatUI() {
+ const input = document.getElementById('ghPatInput');
+ const status = document.getElementById('ghPatStatus');
+ const pat = getGhPat();
+ if (pat) {
+ input.value = pat;
+ status.textContent = '設定済み';
+ status.style.color = 'var(--accent)';
+ }
+ document.getElementById('ghPatSaveBtn').addEventListener('click', () => {
+ const val = input.value.trim();
+ if (!val) {
+ localStorage.removeItem(GH_PAT_KEY);
+ status.textContent = '削除しました';
+ status.style.color = 'var(--text3)';
+ return;
+ }
+ localStorage.setItem(GH_PAT_KEY, val);
+ status.textContent = '保存しました';
+ status.style.color = 'var(--accent)';
+ });
+})();
+
// ── コミット読み込み ──────────────────
document.getElementById('loadCommitsBtn').addEventListener('click', async () => {
- const token = getToken();
- if (!token) { showToast('ログインが必要です'); return; }
+ const ghPat = getGhPat();
+ if (!ghPat) {
+ showToast('設定パネルで GitHub PAT を設定してください');
+ document.getElementById('settingsBtn').click();
+ return;
+ }
const btn = document.getElementById('loadCommitsBtn');
btn.disabled = true;
btn.innerHTML = ' 読み込み中';
+ const since = new Date(Date.now() - activeDays * 86400000).toISOString();
+
try {
- const resp = await fetch(`${API}/chronicle/activity?days=${activeDays}`, {
- headers: { 'Authorization': `Bearer ${token}` }
- });
+ const resp = await fetch(
+ 'https://api.github.com/orgs/posimai/events?per_page=100',
+ { headers: { 'Authorization': `Bearer ${ghPat}`, 'Accept': 'application/vnd.github+json' } }
+ );
+ if (resp.status === 401) throw new Error('PAT が無効です。設定を確認してください');
+ if (!resp.ok) throw new Error(`GitHub API ${resp.status}`);
- if (resp.status === 503) {
- showToast('VPS に CHRONICLE_GITHUB_TOKEN が未設定です');
- return;
+ const events = await resp.json();
+ const commits = [];
+ const byRepo = {};
+
+ for (const ev of events) {
+ if (ev.type !== 'PushEvent') continue;
+ if (ev.created_at < since) continue;
+ const repo = ev.repo.name.replace('posimai/', '');
+ if (!byRepo[repo]) byRepo[repo] = [];
+ for (const c of ev.payload?.commits || []) {
+ const msg = c.message.split('\n')[0];
+ if (/^Merge\b/i.test(msg)) continue;
+ byRepo[repo].push(msg);
+ commits.push(msg);
+ }
}
- if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
- const data = await resp.json();
- if (!data.commits?.length) {
+ if (!commits.length) {
showToast('この期間にコミットが見つかりませんでした');
return;
}
- const byRepo = {};
- for (const c of data.commits) {
- if (!byRepo[c.repo]) byRepo[c.repo] = [];
- byRepo[c.repo].push(c.message);
- }
-
const lines = [];
for (const [repo, messages] of Object.entries(byRepo)) {
lines.push(`【${repo}】`);
for (const m of messages) lines.push(`- ${m}`);
}
-
- const area = document.getElementById('activities');
- area.value = lines.join('\n');
- showToast(`${data.commits.length} 件のコミットを読み込みました`);
+ document.getElementById('activities').value = lines.join('\n');
+ showToast(`${commits.length} 件のコミットを読み込みました`);
} catch (e) {
showToast(`読み込み失敗: ${e.message}`);
} finally {