/** * apply-remark-fix-496626.js * ------------------------------------------------------------ * SiteId 496626 の一覧画面スクリプト(Id:4 new03_一覧画面自動処理)を、 * 備考の3文字省略+独自ポップアップ表示に対応した修正版へ差し替える。 * * 対象は desired_config.json(build-desired-config.js が * configs/site-496626_新・着工要因(東京)v2/ 配下から再構成したもの)の * SiteSettings.Scripts/Styles/ServerScripts/Processes をそのまま送信する。 * 事前に確認した通り、実際に内容が変わるのは Scripts の Id:4 のみ * (他はキー順序が変わるだけでBodyは現状と完全一致)。 * * ユーザーがその場で「直接適用してよい」と明示的に許可した場合に限り実行する * 一回限りの専用スクリプト(.claude/skills/pleasanter-site-spec/SKILL.md * 「クロスサイト構造変更」節の運用に準拠)。 * * 使い方: * node apply-remark-fix-496626.js … 差分表示のみ(送信なし) * node apply-remark-fix-496626.js --execute … 上記に加えて実際に送信する * ------------------------------------------------------------ */ const fs = require("fs"); const path = require("path"); const { latestJsonPath, newModifyDir, latestModifyDir, findSiteDir } = require("./site-paths"); const SITE_ID = 496626; const baseDir = path.join(__dirname, "..", ".."); const configsDir = path.join(baseDir, "configs"); const execute = process.argv.includes("--execute"); function loadJson(p, required = true) { if (!fs.existsSync(p)) { if (required) { console.error(`[エラー] ファイルが見つかりません: ${p}`); process.exit(1); } return null; } return JSON.parse(fs.readFileSync(p, "utf-8")); } function maskApiKey(key) { if (!key) return key; return key.length > 8 ? key.slice(0, 4) + "****" + key.slice(-4) : "****"; } function timestamp() { return new Date().toISOString().replace(/[:.]/g, "-"); } const config = loadJson(path.join(baseDir, "config.json")); const desired = loadJson(path.join(baseDir, "desired_config.json")); if (desired.SiteId !== SITE_ID) { console.error(`[エラー] desired_config.json の SiteId (${desired.SiteId}) が ${SITE_ID} ではありません。`); console.error(`先に node build-desired-config.js site-${SITE_ID}_新・着工要因(東京)v2 を実行してください。`); process.exit(1); } const currentPath = latestJsonPath(configsDir, SITE_ID); const current = loadJson(currentPath, false); const currentScripts = current?.Response?.Data?.SiteSettings?.Scripts || []; const desiredScripts = desired.SiteSettings.Scripts || []; const curScript4 = currentScripts.find((s) => s.Id === 4); const newScript4 = desiredScripts.find((s) => s.Id === 4); console.log("========================================"); console.log(` 一覧画面スクリプト(Id:4)の差し替え${execute ? "(実行)" : "(プレビューのみ)"}`); console.log("========================================"); console.log(`対象: SiteId ${SITE_ID}("${current?.Response?.Data?.Title || ""}")`); console.log(""); console.log(`Script Id:4 現状の文字数: ${curScript4 ? curScript4.Body.length : "(取得できず)"}`); console.log(`Script Id:4 変更後の文字数: ${newScript4 ? newScript4.Body.length : "(取得できず)"}`); console.log(`Script Id:4 以外のScripts/Styles/ServerScripts/Processesは内容変更なし(キー順序のみ変わる場合あり)`); const siteDir = findSiteDir(configsDir, SITE_ID); const modifyDir = latestModifyDir(siteDir) || newModifyDir(siteDir, "remark-truncate-fix"); const ts = timestamp(); const diffOutPath = path.join(modifyDir, `site-${SITE_ID}_remark_fix_diff_${ts}.txt`); fs.writeFileSync( diffOutPath, [ `SiteId ${SITE_ID} 一覧画面スクリプト(Id:4)差し替えプレビュー (${ts})`, "", "--- 現状のBody ---", curScript4 ? curScript4.Body : "(取得できず)", "", "--- 変更後のBody ---", newScript4 ? newScript4.Body : "(取得できず)", ].join("\n"), "utf-8" ); console.log(`\n[OK] 差分プレビューを保存しました: ${diffOutPath}`); const url = `${config.BaseUrl.replace(/\/+$/, "")}/api/items/${SITE_ID}/updatesitesettings`; const body = { ApiVersion: config.ApiVersion || "1.1", ApiKey: config.ApiKey, SiteId: SITE_ID, SiteSettings: desired.SiteSettings, }; const maskedBody = { ...body, ApiKey: maskApiKey(body.ApiKey) }; console.log("\n--- 送信されるBody(APIキーはマスク表示) ---"); console.log( JSON.stringify( { ...maskedBody, SiteSettings: { Scripts: `${desired.SiteSettings.Scripts.length}件(Id:4のみ内容変更)`, Styles: `${desired.SiteSettings.Styles.length}件(変更なし)`, ServerScripts: `${desired.SiteSettings.ServerScripts.length}件(変更なし)`, Processes: `${desired.SiteSettings.Processes.length}件(変更なし)`, }, }, null, 2 ) ); if (!execute) { console.log("\n[注意] --execute が指定されていないため、送信は行っていません。"); console.log("内容を確認の上、問題なければ次を実行してください: node apply-remark-fix-496626.js --execute"); process.exit(0); } (async () => { console.log("\n実際に送信します..."); const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body), }); const text = await res.text(); const resultOutPath = path.join(modifyDir, `site-${SITE_ID}_remark_fix_result_${ts}.json`); fs.writeFileSync(resultOutPath, text, "utf-8"); console.log(`HTTP ${res.status} ${res.statusText}`); console.log(`[OK] 応答を保存しました: ${resultOutPath}`); try { const json = JSON.parse(text); if (json.StatusCode === 200) { console.log("[OK] 適用に成功しました。管理画面・一覧画面で表示を確認してください。"); } else { console.error("[エラー] 適用に失敗した可能性があります。応答内容を確認してください。"); } } catch { console.log(text); } })();