[{"data":1,"prerenderedAt":3183},["ShallowReactive",2],{"post-linear-clipper-extension":3},{"id":4,"title":5,"body":6,"date":3172,"description":3173,"extension":3174,"meta":3175,"navigation":521,"path":3179,"seo":3180,"stem":3181,"__hash__":3182},"blog\u002Fblog\u002Flinear-clipper-extension.md","Linear Clipper 拡張機能を作ってみた",{"type":7,"value":8,"toc":3152},"minimark",[9,13,25,28,46,50,53,383,388,408,411,435,439,442,1279,1282,1313,1317,1320,1929,1932,1961,1965,1968,2312,2315,2336,2340,2343,3128,3131,3139,3142,3145,3148],[10,11,12],"h2",{"id":12},"はじめに",[14,15,16,17,24],"p",{},"タスク管理ツールとして ",[18,19,23],"a",{"href":20,"rel":21},"https:\u002F\u002Flinear.app",[22],"nofollow","Linear"," を使っているのですが、ブラウジング中に見つけた記事やドキュメントをイシューに紐付けたいことがよくあります。毎回 Linear を開いてURLをコピペするのは面倒なので、Chrome 拡張機能を作ってみました。",[10,26,27],{"id":27},"参考リンク",[29,30,31,39],"ul",{},[32,33,34],"li",{},[18,35,38],{"href":36,"rel":37},"https:\u002F\u002Fdeveloper.chrome.com\u002Fdocs\u002Fextensions\u002Freference\u002Fmanifest?hl=ja#register-a-content-script",[22],"マニフェスト ファイル形式 | Manifest | Chrome for Developers",[32,40,41],{},[18,42,45],{"href":43,"rel":44},"https:\u002F\u002Fstudio.apollographql.com\u002Fpublic\u002FLinear-API\u002Fvariant\u002Fcurrent\u002Fschema\u002Freference\u002Fobjects\u002FAttachmentPayload",[22],"Schema | Linear API@current | Studio",[10,47,49],{"id":48},"manifestjson","manifest.json",[14,51,52],{},"Chrome 拡張機能のメタデータと設定を定義する JSON ファイルです。拡張機能のルートディレクトリに必須です。",[54,55,60],"pre",{"className":56,"code":57,"language":58,"meta":59,"style":59},"language-json shiki shiki-themes github-light github-dark","{\n  \"manifest_version\": 3,\n  \"name\": \"Linear Clipper\",\n  \"version\": \"1.0.0\",\n  \"description\": \"現在のページURLをLinearイシューにクリップする\",\n  \"permissions\": [\n    \"storage\",\n    \"activeTab\"\n  ],\n  \"host_permissions\": [\n    \"https:\u002F\u002Fapi.linear.app\u002F*\"\n  ],\n  \"action\": {\n    \"default_popup\": \"popup\u002Fpopup.html\",\n    \"default_icon\": {\n      \"16\": \"icons\u002Ficon16.png\",\n      \"48\": \"icons\u002Ficon48.png\",\n      \"128\": \"icons\u002Ficon128.png\"\n    }\n  },\n  \"options_ui\": {\n    \"page\": \"options\u002Foptions.html\",\n    \"open_in_tab\": true\n  },\n  \"background\": {\n    \"service_worker\": \"scripts\u002Fbackground.js\",\n    \"type\": \"module\"\n  },\n  \"icons\": {\n    \"16\": \"icons\u002Ficon16.png\",\n    \"48\": \"icons\u002Ficon48.png\",\n    \"128\": \"icons\u002Ficon128.png\"\n  }\n}\n","json","",[61,62,63,72,88,102,115,128,137,145,151,157,165,171,176,185,198,206,219,232,243,249,255,263,276,287,292,300,313,324,329,337,349,361,371,377],"code",{"__ignoreMap":59},[64,65,68],"span",{"class":66,"line":67},"line",1,[64,69,71],{"class":70},"sVt8B","{\n",[64,73,75,79,82,85],{"class":66,"line":74},2,[64,76,78],{"class":77},"sj4cs","  \"manifest_version\"",[64,80,81],{"class":70},": ",[64,83,84],{"class":77},"3",[64,86,87],{"class":70},",\n",[64,89,91,94,96,100],{"class":66,"line":90},3,[64,92,93],{"class":77},"  \"name\"",[64,95,81],{"class":70},[64,97,99],{"class":98},"sZZnC","\"Linear Clipper\"",[64,101,87],{"class":70},[64,103,105,108,110,113],{"class":66,"line":104},4,[64,106,107],{"class":77},"  \"version\"",[64,109,81],{"class":70},[64,111,112],{"class":98},"\"1.0.0\"",[64,114,87],{"class":70},[64,116,118,121,123,126],{"class":66,"line":117},5,[64,119,120],{"class":77},"  \"description\"",[64,122,81],{"class":70},[64,124,125],{"class":98},"\"現在のページURLをLinearイシューにクリップする\"",[64,127,87],{"class":70},[64,129,131,134],{"class":66,"line":130},6,[64,132,133],{"class":77},"  \"permissions\"",[64,135,136],{"class":70},": [\n",[64,138,140,143],{"class":66,"line":139},7,[64,141,142],{"class":98},"    \"storage\"",[64,144,87],{"class":70},[64,146,148],{"class":66,"line":147},8,[64,149,150],{"class":98},"    \"activeTab\"\n",[64,152,154],{"class":66,"line":153},9,[64,155,156],{"class":70},"  ],\n",[64,158,160,163],{"class":66,"line":159},10,[64,161,162],{"class":77},"  \"host_permissions\"",[64,164,136],{"class":70},[64,166,168],{"class":66,"line":167},11,[64,169,170],{"class":98},"    \"https:\u002F\u002Fapi.linear.app\u002F*\"\n",[64,172,174],{"class":66,"line":173},12,[64,175,156],{"class":70},[64,177,179,182],{"class":66,"line":178},13,[64,180,181],{"class":77},"  \"action\"",[64,183,184],{"class":70},": {\n",[64,186,188,191,193,196],{"class":66,"line":187},14,[64,189,190],{"class":77},"    \"default_popup\"",[64,192,81],{"class":70},[64,194,195],{"class":98},"\"popup\u002Fpopup.html\"",[64,197,87],{"class":70},[64,199,201,204],{"class":66,"line":200},15,[64,202,203],{"class":77},"    \"default_icon\"",[64,205,184],{"class":70},[64,207,209,212,214,217],{"class":66,"line":208},16,[64,210,211],{"class":77},"      \"16\"",[64,213,81],{"class":70},[64,215,216],{"class":98},"\"icons\u002Ficon16.png\"",[64,218,87],{"class":70},[64,220,222,225,227,230],{"class":66,"line":221},17,[64,223,224],{"class":77},"      \"48\"",[64,226,81],{"class":70},[64,228,229],{"class":98},"\"icons\u002Ficon48.png\"",[64,231,87],{"class":70},[64,233,235,238,240],{"class":66,"line":234},18,[64,236,237],{"class":77},"      \"128\"",[64,239,81],{"class":70},[64,241,242],{"class":98},"\"icons\u002Ficon128.png\"\n",[64,244,246],{"class":66,"line":245},19,[64,247,248],{"class":70},"    }\n",[64,250,252],{"class":66,"line":251},20,[64,253,254],{"class":70},"  },\n",[64,256,258,261],{"class":66,"line":257},21,[64,259,260],{"class":77},"  \"options_ui\"",[64,262,184],{"class":70},[64,264,266,269,271,274],{"class":66,"line":265},22,[64,267,268],{"class":77},"    \"page\"",[64,270,81],{"class":70},[64,272,273],{"class":98},"\"options\u002Foptions.html\"",[64,275,87],{"class":70},[64,277,279,282,284],{"class":66,"line":278},23,[64,280,281],{"class":77},"    \"open_in_tab\"",[64,283,81],{"class":70},[64,285,286],{"class":77},"true\n",[64,288,290],{"class":66,"line":289},24,[64,291,254],{"class":70},[64,293,295,298],{"class":66,"line":294},25,[64,296,297],{"class":77},"  \"background\"",[64,299,184],{"class":70},[64,301,303,306,308,311],{"class":66,"line":302},26,[64,304,305],{"class":77},"    \"service_worker\"",[64,307,81],{"class":70},[64,309,310],{"class":98},"\"scripts\u002Fbackground.js\"",[64,312,87],{"class":70},[64,314,316,319,321],{"class":66,"line":315},27,[64,317,318],{"class":77},"    \"type\"",[64,320,81],{"class":70},[64,322,323],{"class":98},"\"module\"\n",[64,325,327],{"class":66,"line":326},28,[64,328,254],{"class":70},[64,330,332,335],{"class":66,"line":331},29,[64,333,334],{"class":77},"  \"icons\"",[64,336,184],{"class":70},[64,338,340,343,345,347],{"class":66,"line":339},30,[64,341,342],{"class":77},"    \"16\"",[64,344,81],{"class":70},[64,346,216],{"class":98},[64,348,87],{"class":70},[64,350,352,355,357,359],{"class":66,"line":351},31,[64,353,354],{"class":77},"    \"48\"",[64,356,81],{"class":70},[64,358,229],{"class":98},[64,360,87],{"class":70},[64,362,364,367,369],{"class":66,"line":363},32,[64,365,366],{"class":77},"    \"128\"",[64,368,81],{"class":70},[64,370,242],{"class":98},[64,372,374],{"class":66,"line":373},33,[64,375,376],{"class":70},"  }\n",[64,378,380],{"class":66,"line":379},34,[64,381,382],{"class":70},"}\n",[384,385,387],"h3",{"id":386},"permissions-と-host_permissions-の説明","permissions と host_permissions の説明",[29,389,390,396,402],{},[32,391,392,395],{},[61,393,394],{},"\"storage\"",": API キーやチーム ID を拡張機能のストレージに保存するために必要",[32,397,398,401],{},[61,399,400],{},"\"activeTab\"",": 現在のタブの URL とタイトルを取得するために必要",[32,403,404,407],{},[61,405,406],{},"\"host_permissions\": [\"https:\u002F\u002Fapi.linear.app\u002F*\"]",": Linear API への fetch を許可し、CORS 制限を回避する",[384,409,410],{"id":410},"各設定項目",[29,412,413,419,429],{},[32,414,415,418],{},[61,416,417],{},"\"default_popup\"",": 拡張機能のアイコンをクリックしたときに表示されるポップアップの HTML",[32,420,421,424,425,428],{},[61,422,423],{},"\"options_ui\"",": 拡張機能のオプションページ。",[61,426,427],{},"open_in_tab: true"," で新しいタブで開く",[32,430,431,434],{},[61,432,433],{},"\"background\"",": Service Worker として動作するバックグラウンドスクリプト。アイドル時は自動停止する",[10,436,438],{"id":437},"optionsoptionsjs","options\u002Foptions.js",[14,440,441],{},"拡張機能のオプションページです。API キーとチーム ID を設定できるようにします。",[54,443,447],{"className":444,"code":445,"language":446,"meta":59,"style":59},"language-javascript shiki shiki-themes github-light github-dark","async function init() {\n  \u002F\u002F 既存の設定を読み込む\n  const { apiKey, teamId } = await chrome.storage.sync.get(['apiKey', 'teamId']);\n\n  if (apiKey) {\n    apiKeyInput.value = apiKey;\n    await loadTeams(apiKey, teamId);\n  }\n}\n\nasync function loadTeams(apiKey, selectedTeamId = null) {\n  teamSelect.disabled = true;\n  teamSelect.innerHTML = '\u003Coption value=\"\">読み込み中...\u003C\u002Foption>';\n\n  try {\n    \u002F\u002F background.jsにメッセージを送信してチーム一覧を取得\n    const response = await chrome.runtime.sendMessage({\n      action: 'fetchTeams',\n    });\n\n    if (response.error) {\n      throw new Error(response.error);\n    }\n\n    teamSelect.innerHTML = '\u003Coption value=\"\">-- チームを選択 --\u003C\u002Foption>';\n\n    response.teams.forEach((team) => {\n      const option = document.createElement('option');\n      option.value = team.id;\n      option.textContent = team.name;\n      if (team.id === selectedTeamId) {\n        option.selected = true;\n      }\n      teamSelect.appendChild(option);\n    });\n\n    teamSelect.disabled = false;\n  } catch (error) {\n    teamSelect.innerHTML = '\u003Coption value=\"\">エラー: ' + error.message + '\u003C\u002Foption>';\n    showStatus('チームの取得に失敗しました: ' + error.message, 'error');\n  }\n}\n\n\u002F\u002F debounce: 入力のたびにAPIを叩かないよう500ms待機\napiKeyInput.addEventListener('input', () => {\n  clearTimeout(debounceTimer);\n  debounceTimer = setTimeout(async () => {\n    const apiKey = apiKeyInput.value.trim();\n    if (apiKey) {\n      await chrome.storage.sync.set({ apiKey });\n      await loadTeams(apiKey);\n    }\n  }, 500);\n});\n\nsaveBtn.addEventListener('click', async () => {\n  const apiKey = apiKeyInput.value.trim();\n  const teamId = teamSelect.value;\n\n  if (!apiKey) {\n    showStatus('APIキーを入力してください', 'error');\n    return;\n  }\n\n  if (!teamId) {\n    showStatus('チームを選択してください', 'error');\n    return;\n  }\n\n  try {\n    await chrome.storage.sync.set({ apiKey, teamId });\n    showStatus('設定を保存しました', 'success');\n  } catch (error) {\n    showStatus('保存に失敗しました: ' + error.message, 'error');\n  }\n});\n","javascript",[61,448,449,465,471,517,523,531,541,552,556,560,564,592,605,617,621,629,634,655,665,670,674,682,696,700,704,716,720,742,766,776,786,800,811,816,827,832,837,850,862,886,907,912,917,922,928,949,958,980,999,1006,1020,1030,1035,1046,1052,1057,1080,1095,1108,1113,1127,1143,1151,1156,1161,1173,1189,1196,1201,1206,1213,1225,1242,1251,1269,1274],{"__ignoreMap":59},[64,450,451,455,458,462],{"class":66,"line":67},[64,452,454],{"class":453},"szBVR","async",[64,456,457],{"class":453}," function",[64,459,461],{"class":460},"sScJk"," init",[64,463,464],{"class":70},"() {\n",[64,466,467],{"class":66,"line":74},[64,468,470],{"class":469},"sJ8bj","  \u002F\u002F 既存の設定を読み込む\n",[64,472,473,476,479,482,485,488,491,494,497,500,503,506,509,511,514],{"class":66,"line":90},[64,474,475],{"class":453},"  const",[64,477,478],{"class":70}," { ",[64,480,481],{"class":77},"apiKey",[64,483,484],{"class":70},", ",[64,486,487],{"class":77},"teamId",[64,489,490],{"class":70}," } ",[64,492,493],{"class":453},"=",[64,495,496],{"class":453}," await",[64,498,499],{"class":70}," chrome.storage.sync.",[64,501,502],{"class":460},"get",[64,504,505],{"class":70},"([",[64,507,508],{"class":98},"'apiKey'",[64,510,484],{"class":70},[64,512,513],{"class":98},"'teamId'",[64,515,516],{"class":70},"]);\n",[64,518,519],{"class":66,"line":104},[64,520,522],{"emptyLinePlaceholder":521},true,"\n",[64,524,525,528],{"class":66,"line":117},[64,526,527],{"class":453},"  if",[64,529,530],{"class":70}," (apiKey) {\n",[64,532,533,536,538],{"class":66,"line":130},[64,534,535],{"class":70},"    apiKeyInput.value ",[64,537,493],{"class":453},[64,539,540],{"class":70}," apiKey;\n",[64,542,543,546,549],{"class":66,"line":139},[64,544,545],{"class":453},"    await",[64,547,548],{"class":460}," loadTeams",[64,550,551],{"class":70},"(apiKey, teamId);\n",[64,553,554],{"class":66,"line":147},[64,555,376],{"class":70},[64,557,558],{"class":66,"line":153},[64,559,382],{"class":70},[64,561,562],{"class":66,"line":159},[64,563,522],{"emptyLinePlaceholder":521},[64,565,566,568,570,572,575,578,580,583,586,589],{"class":66,"line":167},[64,567,454],{"class":453},[64,569,457],{"class":453},[64,571,548],{"class":460},[64,573,574],{"class":70},"(",[64,576,481],{"class":577},"s4XuR",[64,579,484],{"class":70},[64,581,582],{"class":577},"selectedTeamId",[64,584,585],{"class":453}," =",[64,587,588],{"class":77}," null",[64,590,591],{"class":70},") {\n",[64,593,594,597,599,602],{"class":66,"line":173},[64,595,596],{"class":70},"  teamSelect.disabled ",[64,598,493],{"class":453},[64,600,601],{"class":77}," true",[64,603,604],{"class":70},";\n",[64,606,607,610,612,615],{"class":66,"line":178},[64,608,609],{"class":70},"  teamSelect.innerHTML ",[64,611,493],{"class":453},[64,613,614],{"class":98}," '\u003Coption value=\"\">読み込み中...\u003C\u002Foption>'",[64,616,604],{"class":70},[64,618,619],{"class":66,"line":187},[64,620,522],{"emptyLinePlaceholder":521},[64,622,623,626],{"class":66,"line":200},[64,624,625],{"class":453},"  try",[64,627,628],{"class":70}," {\n",[64,630,631],{"class":66,"line":208},[64,632,633],{"class":469},"    \u002F\u002F background.jsにメッセージを送信してチーム一覧を取得\n",[64,635,636,639,642,644,646,649,652],{"class":66,"line":221},[64,637,638],{"class":453},"    const",[64,640,641],{"class":77}," response",[64,643,585],{"class":453},[64,645,496],{"class":453},[64,647,648],{"class":70}," chrome.runtime.",[64,650,651],{"class":460},"sendMessage",[64,653,654],{"class":70},"({\n",[64,656,657,660,663],{"class":66,"line":234},[64,658,659],{"class":70},"      action: ",[64,661,662],{"class":98},"'fetchTeams'",[64,664,87],{"class":70},[64,666,667],{"class":66,"line":245},[64,668,669],{"class":70},"    });\n",[64,671,672],{"class":66,"line":251},[64,673,522],{"emptyLinePlaceholder":521},[64,675,676,679],{"class":66,"line":257},[64,677,678],{"class":453},"    if",[64,680,681],{"class":70}," (response.error) {\n",[64,683,684,687,690,693],{"class":66,"line":265},[64,685,686],{"class":453},"      throw",[64,688,689],{"class":453}," new",[64,691,692],{"class":460}," Error",[64,694,695],{"class":70},"(response.error);\n",[64,697,698],{"class":66,"line":278},[64,699,248],{"class":70},[64,701,702],{"class":66,"line":289},[64,703,522],{"emptyLinePlaceholder":521},[64,705,706,709,711,714],{"class":66,"line":294},[64,707,708],{"class":70},"    teamSelect.innerHTML ",[64,710,493],{"class":453},[64,712,713],{"class":98}," '\u003Coption value=\"\">-- チームを選択 --\u003C\u002Foption>'",[64,715,604],{"class":70},[64,717,718],{"class":66,"line":302},[64,719,522],{"emptyLinePlaceholder":521},[64,721,722,725,728,731,734,737,740],{"class":66,"line":315},[64,723,724],{"class":70},"    response.teams.",[64,726,727],{"class":460},"forEach",[64,729,730],{"class":70},"((",[64,732,733],{"class":577},"team",[64,735,736],{"class":70},") ",[64,738,739],{"class":453},"=>",[64,741,628],{"class":70},[64,743,744,747,750,752,755,758,760,763],{"class":66,"line":326},[64,745,746],{"class":453},"      const",[64,748,749],{"class":77}," option",[64,751,585],{"class":453},[64,753,754],{"class":70}," document.",[64,756,757],{"class":460},"createElement",[64,759,574],{"class":70},[64,761,762],{"class":98},"'option'",[64,764,765],{"class":70},");\n",[64,767,768,771,773],{"class":66,"line":331},[64,769,770],{"class":70},"      option.value ",[64,772,493],{"class":453},[64,774,775],{"class":70}," team.id;\n",[64,777,778,781,783],{"class":66,"line":339},[64,779,780],{"class":70},"      option.textContent ",[64,782,493],{"class":453},[64,784,785],{"class":70}," team.name;\n",[64,787,788,791,794,797],{"class":66,"line":351},[64,789,790],{"class":453},"      if",[64,792,793],{"class":70}," (team.id ",[64,795,796],{"class":453},"===",[64,798,799],{"class":70}," selectedTeamId) {\n",[64,801,802,805,807,809],{"class":66,"line":363},[64,803,804],{"class":70},"        option.selected ",[64,806,493],{"class":453},[64,808,601],{"class":77},[64,810,604],{"class":70},[64,812,813],{"class":66,"line":373},[64,814,815],{"class":70},"      }\n",[64,817,818,821,824],{"class":66,"line":379},[64,819,820],{"class":70},"      teamSelect.",[64,822,823],{"class":460},"appendChild",[64,825,826],{"class":70},"(option);\n",[64,828,830],{"class":66,"line":829},35,[64,831,669],{"class":70},[64,833,835],{"class":66,"line":834},36,[64,836,522],{"emptyLinePlaceholder":521},[64,838,840,843,845,848],{"class":66,"line":839},37,[64,841,842],{"class":70},"    teamSelect.disabled ",[64,844,493],{"class":453},[64,846,847],{"class":77}," false",[64,849,604],{"class":70},[64,851,853,856,859],{"class":66,"line":852},38,[64,854,855],{"class":70},"  } ",[64,857,858],{"class":453},"catch",[64,860,861],{"class":70}," (error) {\n",[64,863,865,867,869,872,875,878,881,884],{"class":66,"line":864},39,[64,866,708],{"class":70},[64,868,493],{"class":453},[64,870,871],{"class":98}," '\u003Coption value=\"\">エラー: '",[64,873,874],{"class":453}," +",[64,876,877],{"class":70}," error.message ",[64,879,880],{"class":453},"+",[64,882,883],{"class":98}," '\u003C\u002Foption>'",[64,885,604],{"class":70},[64,887,889,892,894,897,899,902,905],{"class":66,"line":888},40,[64,890,891],{"class":460},"    showStatus",[64,893,574],{"class":70},[64,895,896],{"class":98},"'チームの取得に失敗しました: '",[64,898,874],{"class":453},[64,900,901],{"class":70}," error.message, ",[64,903,904],{"class":98},"'error'",[64,906,765],{"class":70},[64,908,910],{"class":66,"line":909},41,[64,911,376],{"class":70},[64,913,915],{"class":66,"line":914},42,[64,916,382],{"class":70},[64,918,920],{"class":66,"line":919},43,[64,921,522],{"emptyLinePlaceholder":521},[64,923,925],{"class":66,"line":924},44,[64,926,927],{"class":469},"\u002F\u002F debounce: 入力のたびにAPIを叩かないよう500ms待機\n",[64,929,931,934,937,939,942,945,947],{"class":66,"line":930},45,[64,932,933],{"class":70},"apiKeyInput.",[64,935,936],{"class":460},"addEventListener",[64,938,574],{"class":70},[64,940,941],{"class":98},"'input'",[64,943,944],{"class":70},", () ",[64,946,739],{"class":453},[64,948,628],{"class":70},[64,950,952,955],{"class":66,"line":951},46,[64,953,954],{"class":460},"  clearTimeout",[64,956,957],{"class":70},"(debounceTimer);\n",[64,959,961,964,966,969,971,973,976,978],{"class":66,"line":960},47,[64,962,963],{"class":70},"  debounceTimer ",[64,965,493],{"class":453},[64,967,968],{"class":460}," setTimeout",[64,970,574],{"class":70},[64,972,454],{"class":453},[64,974,975],{"class":70}," () ",[64,977,739],{"class":453},[64,979,628],{"class":70},[64,981,983,985,988,990,993,996],{"class":66,"line":982},48,[64,984,638],{"class":453},[64,986,987],{"class":77}," apiKey",[64,989,585],{"class":453},[64,991,992],{"class":70}," apiKeyInput.value.",[64,994,995],{"class":460},"trim",[64,997,998],{"class":70},"();\n",[64,1000,1002,1004],{"class":66,"line":1001},49,[64,1003,678],{"class":453},[64,1005,530],{"class":70},[64,1007,1009,1012,1014,1017],{"class":66,"line":1008},50,[64,1010,1011],{"class":453},"      await",[64,1013,499],{"class":70},[64,1015,1016],{"class":460},"set",[64,1018,1019],{"class":70},"({ apiKey });\n",[64,1021,1023,1025,1027],{"class":66,"line":1022},51,[64,1024,1011],{"class":453},[64,1026,548],{"class":460},[64,1028,1029],{"class":70},"(apiKey);\n",[64,1031,1033],{"class":66,"line":1032},52,[64,1034,248],{"class":70},[64,1036,1038,1041,1044],{"class":66,"line":1037},53,[64,1039,1040],{"class":70},"  }, ",[64,1042,1043],{"class":77},"500",[64,1045,765],{"class":70},[64,1047,1049],{"class":66,"line":1048},54,[64,1050,1051],{"class":70},"});\n",[64,1053,1055],{"class":66,"line":1054},55,[64,1056,522],{"emptyLinePlaceholder":521},[64,1058,1060,1063,1065,1067,1070,1072,1074,1076,1078],{"class":66,"line":1059},56,[64,1061,1062],{"class":70},"saveBtn.",[64,1064,936],{"class":460},[64,1066,574],{"class":70},[64,1068,1069],{"class":98},"'click'",[64,1071,484],{"class":70},[64,1073,454],{"class":453},[64,1075,975],{"class":70},[64,1077,739],{"class":453},[64,1079,628],{"class":70},[64,1081,1083,1085,1087,1089,1091,1093],{"class":66,"line":1082},57,[64,1084,475],{"class":453},[64,1086,987],{"class":77},[64,1088,585],{"class":453},[64,1090,992],{"class":70},[64,1092,995],{"class":460},[64,1094,998],{"class":70},[64,1096,1098,1100,1103,1105],{"class":66,"line":1097},58,[64,1099,475],{"class":453},[64,1101,1102],{"class":77}," teamId",[64,1104,585],{"class":453},[64,1106,1107],{"class":70}," teamSelect.value;\n",[64,1109,1111],{"class":66,"line":1110},59,[64,1112,522],{"emptyLinePlaceholder":521},[64,1114,1116,1118,1121,1124],{"class":66,"line":1115},60,[64,1117,527],{"class":453},[64,1119,1120],{"class":70}," (",[64,1122,1123],{"class":453},"!",[64,1125,1126],{"class":70},"apiKey) {\n",[64,1128,1130,1132,1134,1137,1139,1141],{"class":66,"line":1129},61,[64,1131,891],{"class":460},[64,1133,574],{"class":70},[64,1135,1136],{"class":98},"'APIキーを入力してください'",[64,1138,484],{"class":70},[64,1140,904],{"class":98},[64,1142,765],{"class":70},[64,1144,1146,1149],{"class":66,"line":1145},62,[64,1147,1148],{"class":453},"    return",[64,1150,604],{"class":70},[64,1152,1154],{"class":66,"line":1153},63,[64,1155,376],{"class":70},[64,1157,1159],{"class":66,"line":1158},64,[64,1160,522],{"emptyLinePlaceholder":521},[64,1162,1164,1166,1168,1170],{"class":66,"line":1163},65,[64,1165,527],{"class":453},[64,1167,1120],{"class":70},[64,1169,1123],{"class":453},[64,1171,1172],{"class":70},"teamId) {\n",[64,1174,1176,1178,1180,1183,1185,1187],{"class":66,"line":1175},66,[64,1177,891],{"class":460},[64,1179,574],{"class":70},[64,1181,1182],{"class":98},"'チームを選択してください'",[64,1184,484],{"class":70},[64,1186,904],{"class":98},[64,1188,765],{"class":70},[64,1190,1192,1194],{"class":66,"line":1191},67,[64,1193,1148],{"class":453},[64,1195,604],{"class":70},[64,1197,1199],{"class":66,"line":1198},68,[64,1200,376],{"class":70},[64,1202,1204],{"class":66,"line":1203},69,[64,1205,522],{"emptyLinePlaceholder":521},[64,1207,1209,1211],{"class":66,"line":1208},70,[64,1210,625],{"class":453},[64,1212,628],{"class":70},[64,1214,1216,1218,1220,1222],{"class":66,"line":1215},71,[64,1217,545],{"class":453},[64,1219,499],{"class":70},[64,1221,1016],{"class":460},[64,1223,1224],{"class":70},"({ apiKey, teamId });\n",[64,1226,1228,1230,1232,1235,1237,1240],{"class":66,"line":1227},72,[64,1229,891],{"class":460},[64,1231,574],{"class":70},[64,1233,1234],{"class":98},"'設定を保存しました'",[64,1236,484],{"class":70},[64,1238,1239],{"class":98},"'success'",[64,1241,765],{"class":70},[64,1243,1245,1247,1249],{"class":66,"line":1244},73,[64,1246,855],{"class":70},[64,1248,858],{"class":453},[64,1250,861],{"class":70},[64,1252,1254,1256,1258,1261,1263,1265,1267],{"class":66,"line":1253},74,[64,1255,891],{"class":460},[64,1257,574],{"class":70},[64,1259,1260],{"class":98},"'保存に失敗しました: '",[64,1262,874],{"class":453},[64,1264,901],{"class":70},[64,1266,904],{"class":98},[64,1268,765],{"class":70},[64,1270,1272],{"class":66,"line":1271},75,[64,1273,376],{"class":70},[64,1275,1277],{"class":66,"line":1276},76,[64,1278,1051],{"class":70},[384,1280,1281],{"id":1281},"処理の流れ",[1283,1284,1285,1296,1303,1310],"ol",{},[32,1286,1287,1288,1291,1292,1295],{},"ページ読み込み時に ",[61,1289,1290],{},"init"," 関数が呼ばれ、",[61,1293,1294],{},"chrome.storage.sync.get"," で保存されている API キーとチーム ID を取得",[32,1297,1298,1299,1302],{},"background.js に ",[61,1300,1301],{},"{ action: 'fetchTeams' }"," を送信",[32,1304,1305,1306,1309],{},"レスポンスで ",[61,1307,1308],{},"\u003Cselect>"," を構築",[32,1311,1312],{},"保存ボタンがクリックされたときに API キーとチーム ID を保存",[10,1314,1316],{"id":1315},"popuppopupjs","popup\u002Fpopup.js",[14,1318,1319],{},"ツールバーアイコンをクリックしたときに表示されるポップアップのロジックです。",[54,1321,1323],{"className":444,"code":1322,"language":446,"meta":59,"style":59},"\u002F\u002F 5つのView（状態）を切り替える\nfunction showView(view) {\n  [setupView, mainView, successView, loadingView, errorView].forEach((v) => {\n    v.style.display = 'none';\n  });\n  view.style.display = 'flex';\n}\n\nasync function init() {\n  \u002F\u002F 設定が未完了なら setupView を表示\n  const { apiKey, teamId } = await chrome.storage.sync.get(['apiKey', 'teamId']);\n  if (!apiKey || !teamId) {\n    showView(setupView);\n    return;\n  }\n\n  \u002F\u002F 現在のタブ情報を取得（activeTab権限で許可）\n  const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });\n  currentTab = tab;\n\n  titleInput.value = tab.title || '';\n  urlDisplay.textContent = tab.url || '';\n  showView(mainView);\n}\n\n\u002F\u002F 設定画面を開く\nopenOptionsBtn.addEventListener('click', () => {\n  chrome.runtime.openOptionsPage();\n});\n\n\u002F\u002F 「Linearに追加」ボタン\nclipBtn.addEventListener('click', async () => {\n  const title = titleInput.value.trim();\n\n  if (!title) {\n    errorMessage.textContent = 'タイトルを入力してください';\n    showView(errorView);\n    return;\n  }\n\n  showView(loadingView);\n\n  try {\n    const { teamId } = await chrome.storage.sync.get('teamId');\n\n    const response = await chrome.runtime.sendMessage({\n      action: 'createIssue',\n      teamId,\n      title,\n      url: currentTab.url,\n    });\n\n    if (response.error) {\n      throw new Error(response.error);\n    }\n\n    issueLink.textContent = response.issue.identifier;\n    issueLink.href = response.issue.url;\n    showView(successView);\n  } catch (error) {\n    errorMessage.textContent = error.message;\n    showView(errorView);\n  }\n});\n\nretryBtn.addEventListener('click', () => {\n  showView(mainView);\n});\n",[61,1324,1325,1330,1345,1363,1375,1380,1392,1396,1400,1410,1415,1447,1466,1474,1480,1484,1488,1493,1530,1540,1544,1561,1577,1585,1589,1593,1598,1615,1625,1629,1633,1638,1659,1675,1679,1690,1702,1709,1715,1719,1723,1730,1734,1740,1764,1768,1784,1793,1798,1803,1808,1812,1816,1822,1832,1836,1840,1850,1860,1867,1875,1884,1890,1894,1898,1902,1919,1925],{"__ignoreMap":59},[64,1326,1327],{"class":66,"line":67},[64,1328,1329],{"class":469},"\u002F\u002F 5つのView（状態）を切り替える\n",[64,1331,1332,1335,1338,1340,1343],{"class":66,"line":74},[64,1333,1334],{"class":453},"function",[64,1336,1337],{"class":460}," showView",[64,1339,574],{"class":70},[64,1341,1342],{"class":577},"view",[64,1344,591],{"class":70},[64,1346,1347,1350,1352,1354,1357,1359,1361],{"class":66,"line":90},[64,1348,1349],{"class":70},"  [setupView, mainView, successView, loadingView, errorView].",[64,1351,727],{"class":460},[64,1353,730],{"class":70},[64,1355,1356],{"class":577},"v",[64,1358,736],{"class":70},[64,1360,739],{"class":453},[64,1362,628],{"class":70},[64,1364,1365,1368,1370,1373],{"class":66,"line":104},[64,1366,1367],{"class":70},"    v.style.display ",[64,1369,493],{"class":453},[64,1371,1372],{"class":98}," 'none'",[64,1374,604],{"class":70},[64,1376,1377],{"class":66,"line":117},[64,1378,1379],{"class":70},"  });\n",[64,1381,1382,1385,1387,1390],{"class":66,"line":130},[64,1383,1384],{"class":70},"  view.style.display ",[64,1386,493],{"class":453},[64,1388,1389],{"class":98}," 'flex'",[64,1391,604],{"class":70},[64,1393,1394],{"class":66,"line":139},[64,1395,382],{"class":70},[64,1397,1398],{"class":66,"line":147},[64,1399,522],{"emptyLinePlaceholder":521},[64,1401,1402,1404,1406,1408],{"class":66,"line":153},[64,1403,454],{"class":453},[64,1405,457],{"class":453},[64,1407,461],{"class":460},[64,1409,464],{"class":70},[64,1411,1412],{"class":66,"line":159},[64,1413,1414],{"class":469},"  \u002F\u002F 設定が未完了なら setupView を表示\n",[64,1416,1417,1419,1421,1423,1425,1427,1429,1431,1433,1435,1437,1439,1441,1443,1445],{"class":66,"line":167},[64,1418,475],{"class":453},[64,1420,478],{"class":70},[64,1422,481],{"class":77},[64,1424,484],{"class":70},[64,1426,487],{"class":77},[64,1428,490],{"class":70},[64,1430,493],{"class":453},[64,1432,496],{"class":453},[64,1434,499],{"class":70},[64,1436,502],{"class":460},[64,1438,505],{"class":70},[64,1440,508],{"class":98},[64,1442,484],{"class":70},[64,1444,513],{"class":98},[64,1446,516],{"class":70},[64,1448,1449,1451,1453,1455,1458,1461,1464],{"class":66,"line":173},[64,1450,527],{"class":453},[64,1452,1120],{"class":70},[64,1454,1123],{"class":453},[64,1456,1457],{"class":70},"apiKey ",[64,1459,1460],{"class":453},"||",[64,1462,1463],{"class":453}," !",[64,1465,1172],{"class":70},[64,1467,1468,1471],{"class":66,"line":178},[64,1469,1470],{"class":460},"    showView",[64,1472,1473],{"class":70},"(setupView);\n",[64,1475,1476,1478],{"class":66,"line":187},[64,1477,1148],{"class":453},[64,1479,604],{"class":70},[64,1481,1482],{"class":66,"line":200},[64,1483,376],{"class":70},[64,1485,1486],{"class":66,"line":208},[64,1487,522],{"emptyLinePlaceholder":521},[64,1489,1490],{"class":66,"line":221},[64,1491,1492],{"class":469},"  \u002F\u002F 現在のタブ情報を取得（activeTab権限で許可）\n",[64,1494,1495,1497,1500,1503,1506,1508,1510,1513,1516,1519,1522,1525,1527],{"class":66,"line":234},[64,1496,475],{"class":453},[64,1498,1499],{"class":70}," [",[64,1501,1502],{"class":77},"tab",[64,1504,1505],{"class":70},"] ",[64,1507,493],{"class":453},[64,1509,496],{"class":453},[64,1511,1512],{"class":70}," chrome.tabs.",[64,1514,1515],{"class":460},"query",[64,1517,1518],{"class":70},"({ active: ",[64,1520,1521],{"class":77},"true",[64,1523,1524],{"class":70},", currentWindow: ",[64,1526,1521],{"class":77},[64,1528,1529],{"class":70}," });\n",[64,1531,1532,1535,1537],{"class":66,"line":245},[64,1533,1534],{"class":70},"  currentTab ",[64,1536,493],{"class":453},[64,1538,1539],{"class":70}," tab;\n",[64,1541,1542],{"class":66,"line":251},[64,1543,522],{"emptyLinePlaceholder":521},[64,1545,1546,1549,1551,1554,1556,1559],{"class":66,"line":257},[64,1547,1548],{"class":70},"  titleInput.value ",[64,1550,493],{"class":453},[64,1552,1553],{"class":70}," tab.title ",[64,1555,1460],{"class":453},[64,1557,1558],{"class":98}," ''",[64,1560,604],{"class":70},[64,1562,1563,1566,1568,1571,1573,1575],{"class":66,"line":265},[64,1564,1565],{"class":70},"  urlDisplay.textContent ",[64,1567,493],{"class":453},[64,1569,1570],{"class":70}," tab.url ",[64,1572,1460],{"class":453},[64,1574,1558],{"class":98},[64,1576,604],{"class":70},[64,1578,1579,1582],{"class":66,"line":278},[64,1580,1581],{"class":460},"  showView",[64,1583,1584],{"class":70},"(mainView);\n",[64,1586,1587],{"class":66,"line":289},[64,1588,382],{"class":70},[64,1590,1591],{"class":66,"line":294},[64,1592,522],{"emptyLinePlaceholder":521},[64,1594,1595],{"class":66,"line":302},[64,1596,1597],{"class":469},"\u002F\u002F 設定画面を開く\n",[64,1599,1600,1603,1605,1607,1609,1611,1613],{"class":66,"line":315},[64,1601,1602],{"class":70},"openOptionsBtn.",[64,1604,936],{"class":460},[64,1606,574],{"class":70},[64,1608,1069],{"class":98},[64,1610,944],{"class":70},[64,1612,739],{"class":453},[64,1614,628],{"class":70},[64,1616,1617,1620,1623],{"class":66,"line":326},[64,1618,1619],{"class":70},"  chrome.runtime.",[64,1621,1622],{"class":460},"openOptionsPage",[64,1624,998],{"class":70},[64,1626,1627],{"class":66,"line":331},[64,1628,1051],{"class":70},[64,1630,1631],{"class":66,"line":339},[64,1632,522],{"emptyLinePlaceholder":521},[64,1634,1635],{"class":66,"line":351},[64,1636,1637],{"class":469},"\u002F\u002F 「Linearに追加」ボタン\n",[64,1639,1640,1643,1645,1647,1649,1651,1653,1655,1657],{"class":66,"line":363},[64,1641,1642],{"class":70},"clipBtn.",[64,1644,936],{"class":460},[64,1646,574],{"class":70},[64,1648,1069],{"class":98},[64,1650,484],{"class":70},[64,1652,454],{"class":453},[64,1654,975],{"class":70},[64,1656,739],{"class":453},[64,1658,628],{"class":70},[64,1660,1661,1663,1666,1668,1671,1673],{"class":66,"line":373},[64,1662,475],{"class":453},[64,1664,1665],{"class":77}," title",[64,1667,585],{"class":453},[64,1669,1670],{"class":70}," titleInput.value.",[64,1672,995],{"class":460},[64,1674,998],{"class":70},[64,1676,1677],{"class":66,"line":379},[64,1678,522],{"emptyLinePlaceholder":521},[64,1680,1681,1683,1685,1687],{"class":66,"line":829},[64,1682,527],{"class":453},[64,1684,1120],{"class":70},[64,1686,1123],{"class":453},[64,1688,1689],{"class":70},"title) {\n",[64,1691,1692,1695,1697,1700],{"class":66,"line":834},[64,1693,1694],{"class":70},"    errorMessage.textContent ",[64,1696,493],{"class":453},[64,1698,1699],{"class":98}," 'タイトルを入力してください'",[64,1701,604],{"class":70},[64,1703,1704,1706],{"class":66,"line":839},[64,1705,1470],{"class":460},[64,1707,1708],{"class":70},"(errorView);\n",[64,1710,1711,1713],{"class":66,"line":852},[64,1712,1148],{"class":453},[64,1714,604],{"class":70},[64,1716,1717],{"class":66,"line":864},[64,1718,376],{"class":70},[64,1720,1721],{"class":66,"line":888},[64,1722,522],{"emptyLinePlaceholder":521},[64,1724,1725,1727],{"class":66,"line":909},[64,1726,1581],{"class":460},[64,1728,1729],{"class":70},"(loadingView);\n",[64,1731,1732],{"class":66,"line":914},[64,1733,522],{"emptyLinePlaceholder":521},[64,1735,1736,1738],{"class":66,"line":919},[64,1737,625],{"class":453},[64,1739,628],{"class":70},[64,1741,1742,1744,1746,1748,1750,1752,1754,1756,1758,1760,1762],{"class":66,"line":924},[64,1743,638],{"class":453},[64,1745,478],{"class":70},[64,1747,487],{"class":77},[64,1749,490],{"class":70},[64,1751,493],{"class":453},[64,1753,496],{"class":453},[64,1755,499],{"class":70},[64,1757,502],{"class":460},[64,1759,574],{"class":70},[64,1761,513],{"class":98},[64,1763,765],{"class":70},[64,1765,1766],{"class":66,"line":930},[64,1767,522],{"emptyLinePlaceholder":521},[64,1769,1770,1772,1774,1776,1778,1780,1782],{"class":66,"line":951},[64,1771,638],{"class":453},[64,1773,641],{"class":77},[64,1775,585],{"class":453},[64,1777,496],{"class":453},[64,1779,648],{"class":70},[64,1781,651],{"class":460},[64,1783,654],{"class":70},[64,1785,1786,1788,1791],{"class":66,"line":960},[64,1787,659],{"class":70},[64,1789,1790],{"class":98},"'createIssue'",[64,1792,87],{"class":70},[64,1794,1795],{"class":66,"line":982},[64,1796,1797],{"class":70},"      teamId,\n",[64,1799,1800],{"class":66,"line":1001},[64,1801,1802],{"class":70},"      title,\n",[64,1804,1805],{"class":66,"line":1008},[64,1806,1807],{"class":70},"      url: currentTab.url,\n",[64,1809,1810],{"class":66,"line":1022},[64,1811,669],{"class":70},[64,1813,1814],{"class":66,"line":1032},[64,1815,522],{"emptyLinePlaceholder":521},[64,1817,1818,1820],{"class":66,"line":1037},[64,1819,678],{"class":453},[64,1821,681],{"class":70},[64,1823,1824,1826,1828,1830],{"class":66,"line":1048},[64,1825,686],{"class":453},[64,1827,689],{"class":453},[64,1829,692],{"class":460},[64,1831,695],{"class":70},[64,1833,1834],{"class":66,"line":1054},[64,1835,248],{"class":70},[64,1837,1838],{"class":66,"line":1059},[64,1839,522],{"emptyLinePlaceholder":521},[64,1841,1842,1845,1847],{"class":66,"line":1082},[64,1843,1844],{"class":70},"    issueLink.textContent ",[64,1846,493],{"class":453},[64,1848,1849],{"class":70}," response.issue.identifier;\n",[64,1851,1852,1855,1857],{"class":66,"line":1097},[64,1853,1854],{"class":70},"    issueLink.href ",[64,1856,493],{"class":453},[64,1858,1859],{"class":70}," response.issue.url;\n",[64,1861,1862,1864],{"class":66,"line":1110},[64,1863,1470],{"class":460},[64,1865,1866],{"class":70},"(successView);\n",[64,1868,1869,1871,1873],{"class":66,"line":1115},[64,1870,855],{"class":70},[64,1872,858],{"class":453},[64,1874,861],{"class":70},[64,1876,1877,1879,1881],{"class":66,"line":1129},[64,1878,1694],{"class":70},[64,1880,493],{"class":453},[64,1882,1883],{"class":70}," error.message;\n",[64,1885,1886,1888],{"class":66,"line":1145},[64,1887,1470],{"class":460},[64,1889,1708],{"class":70},[64,1891,1892],{"class":66,"line":1153},[64,1893,376],{"class":70},[64,1895,1896],{"class":66,"line":1158},[64,1897,1051],{"class":70},[64,1899,1900],{"class":66,"line":1163},[64,1901,522],{"emptyLinePlaceholder":521},[64,1903,1904,1907,1909,1911,1913,1915,1917],{"class":66,"line":1175},[64,1905,1906],{"class":70},"retryBtn.",[64,1908,936],{"class":460},[64,1910,574],{"class":70},[64,1912,1069],{"class":98},[64,1914,944],{"class":70},[64,1916,739],{"class":453},[64,1918,628],{"class":70},[64,1920,1921,1923],{"class":66,"line":1191},[64,1922,1581],{"class":460},[64,1924,1584],{"class":70},[64,1926,1927],{"class":66,"line":1198},[64,1928,1051],{"class":70},[384,1930,1281],{"id":1931},"処理の流れ-1",[1283,1933,1934,1940,1945,1952,1958],{},[32,1935,1936,1937,1939],{},"ポップアップ表示時に ",[61,1938,1290],{}," が呼ばれる",[32,1941,1942,1944],{},[61,1943,1294],{}," で設定済みか確認",[32,1946,1947,1948,1951],{},"未設定なら setupView、設定済みなら ",[61,1949,1950],{},"chrome.tabs.query"," で現在タブの情報を取得",[32,1953,1954,1955,1302],{},"「Linear に追加」クリックで background.js に ",[61,1956,1957],{},"{ action: 'createIssue' }",[32,1959,1960],{},"結果に応じて successView \u002F errorView を表示",[10,1962,1964],{"id":1963},"scriptsbackgroundjs","scripts\u002Fbackground.js",[14,1966,1967],{},"popup.js や options.js からのメッセージを受け取り、API 通信を実行するメッセージハブです。",[54,1969,1971],{"className":444,"code":1970,"language":446,"meta":59,"style":59},"import { fetchTeams, createIssueWithLink } from '.\u002Flinear-api.js';\n\n\u002F\u002F メッセージを受信するリスナー\nchrome.runtime.onMessage.addListener((request, sender, sendResponse) => {\n  handleMessage(request)\n    .then(sendResponse)\n    .catch((error) => sendResponse({ error: error.message }));\n  return true; \u002F\u002F 非同期でレスポンスを返すために必要\n});\n\nasync function handleMessage(request) {\n  const { apiKey } = await chrome.storage.sync.get('apiKey');\n\n  if (!apiKey) {\n    throw new Error('APIキーが設定されていません。設定画面で設定してください。');\n  }\n\n  switch (request.action) {\n    case 'fetchTeams':\n      return { teams: await fetchTeams(apiKey) };\n\n    case 'createIssue': {\n      const { teamId, title, url } = request;\n      const issue = await createIssueWithLink(apiKey, teamId, title, url);\n      return { issue };\n    }\n\n    default:\n      throw new Error(`Unknown action: ${request.action}`);\n  }\n}\n",[61,1972,1973,1989,1993,1998,2027,2035,2046,2067,2080,2084,2088,2103,2127,2131,2141,2157,2161,2165,2173,2184,2201,2205,2214,2239,2256,2263,2267,2271,2278,2304,2308],{"__ignoreMap":59},[64,1974,1975,1978,1981,1984,1987],{"class":66,"line":67},[64,1976,1977],{"class":453},"import",[64,1979,1980],{"class":70}," { fetchTeams, createIssueWithLink } ",[64,1982,1983],{"class":453},"from",[64,1985,1986],{"class":98}," '.\u002Flinear-api.js'",[64,1988,604],{"class":70},[64,1990,1991],{"class":66,"line":74},[64,1992,522],{"emptyLinePlaceholder":521},[64,1994,1995],{"class":66,"line":90},[64,1996,1997],{"class":469},"\u002F\u002F メッセージを受信するリスナー\n",[64,1999,2000,2003,2006,2008,2011,2013,2016,2018,2021,2023,2025],{"class":66,"line":104},[64,2001,2002],{"class":70},"chrome.runtime.onMessage.",[64,2004,2005],{"class":460},"addListener",[64,2007,730],{"class":70},[64,2009,2010],{"class":577},"request",[64,2012,484],{"class":70},[64,2014,2015],{"class":577},"sender",[64,2017,484],{"class":70},[64,2019,2020],{"class":577},"sendResponse",[64,2022,736],{"class":70},[64,2024,739],{"class":453},[64,2026,628],{"class":70},[64,2028,2029,2032],{"class":66,"line":117},[64,2030,2031],{"class":460},"  handleMessage",[64,2033,2034],{"class":70},"(request)\n",[64,2036,2037,2040,2043],{"class":66,"line":130},[64,2038,2039],{"class":70},"    .",[64,2041,2042],{"class":460},"then",[64,2044,2045],{"class":70},"(sendResponse)\n",[64,2047,2048,2050,2052,2054,2057,2059,2061,2064],{"class":66,"line":139},[64,2049,2039],{"class":70},[64,2051,858],{"class":460},[64,2053,730],{"class":70},[64,2055,2056],{"class":577},"error",[64,2058,736],{"class":70},[64,2060,739],{"class":453},[64,2062,2063],{"class":460}," sendResponse",[64,2065,2066],{"class":70},"({ error: error.message }));\n",[64,2068,2069,2072,2074,2077],{"class":66,"line":147},[64,2070,2071],{"class":453},"  return",[64,2073,601],{"class":77},[64,2075,2076],{"class":70},"; ",[64,2078,2079],{"class":469},"\u002F\u002F 非同期でレスポンスを返すために必要\n",[64,2081,2082],{"class":66,"line":153},[64,2083,1051],{"class":70},[64,2085,2086],{"class":66,"line":159},[64,2087,522],{"emptyLinePlaceholder":521},[64,2089,2090,2092,2094,2097,2099,2101],{"class":66,"line":167},[64,2091,454],{"class":453},[64,2093,457],{"class":453},[64,2095,2096],{"class":460}," handleMessage",[64,2098,574],{"class":70},[64,2100,2010],{"class":577},[64,2102,591],{"class":70},[64,2104,2105,2107,2109,2111,2113,2115,2117,2119,2121,2123,2125],{"class":66,"line":173},[64,2106,475],{"class":453},[64,2108,478],{"class":70},[64,2110,481],{"class":77},[64,2112,490],{"class":70},[64,2114,493],{"class":453},[64,2116,496],{"class":453},[64,2118,499],{"class":70},[64,2120,502],{"class":460},[64,2122,574],{"class":70},[64,2124,508],{"class":98},[64,2126,765],{"class":70},[64,2128,2129],{"class":66,"line":178},[64,2130,522],{"emptyLinePlaceholder":521},[64,2132,2133,2135,2137,2139],{"class":66,"line":187},[64,2134,527],{"class":453},[64,2136,1120],{"class":70},[64,2138,1123],{"class":453},[64,2140,1126],{"class":70},[64,2142,2143,2146,2148,2150,2152,2155],{"class":66,"line":200},[64,2144,2145],{"class":453},"    throw",[64,2147,689],{"class":453},[64,2149,692],{"class":460},[64,2151,574],{"class":70},[64,2153,2154],{"class":98},"'APIキーが設定されていません。設定画面で設定してください。'",[64,2156,765],{"class":70},[64,2158,2159],{"class":66,"line":208},[64,2160,376],{"class":70},[64,2162,2163],{"class":66,"line":221},[64,2164,522],{"emptyLinePlaceholder":521},[64,2166,2167,2170],{"class":66,"line":234},[64,2168,2169],{"class":453},"  switch",[64,2171,2172],{"class":70}," (request.action) {\n",[64,2174,2175,2178,2181],{"class":66,"line":245},[64,2176,2177],{"class":453},"    case",[64,2179,2180],{"class":98}," 'fetchTeams'",[64,2182,2183],{"class":70},":\n",[64,2185,2186,2189,2192,2195,2198],{"class":66,"line":251},[64,2187,2188],{"class":453},"      return",[64,2190,2191],{"class":70}," { teams: ",[64,2193,2194],{"class":453},"await",[64,2196,2197],{"class":460}," fetchTeams",[64,2199,2200],{"class":70},"(apiKey) };\n",[64,2202,2203],{"class":66,"line":257},[64,2204,522],{"emptyLinePlaceholder":521},[64,2206,2207,2209,2212],{"class":66,"line":265},[64,2208,2177],{"class":453},[64,2210,2211],{"class":98}," 'createIssue'",[64,2213,184],{"class":70},[64,2215,2216,2218,2220,2222,2224,2227,2229,2232,2234,2236],{"class":66,"line":278},[64,2217,746],{"class":453},[64,2219,478],{"class":70},[64,2221,487],{"class":77},[64,2223,484],{"class":70},[64,2225,2226],{"class":77},"title",[64,2228,484],{"class":70},[64,2230,2231],{"class":77},"url",[64,2233,490],{"class":70},[64,2235,493],{"class":453},[64,2237,2238],{"class":70}," request;\n",[64,2240,2241,2243,2246,2248,2250,2253],{"class":66,"line":289},[64,2242,746],{"class":453},[64,2244,2245],{"class":77}," issue",[64,2247,585],{"class":453},[64,2249,496],{"class":453},[64,2251,2252],{"class":460}," createIssueWithLink",[64,2254,2255],{"class":70},"(apiKey, teamId, title, url);\n",[64,2257,2258,2260],{"class":66,"line":294},[64,2259,2188],{"class":453},[64,2261,2262],{"class":70}," { issue };\n",[64,2264,2265],{"class":66,"line":302},[64,2266,248],{"class":70},[64,2268,2269],{"class":66,"line":315},[64,2270,522],{"emptyLinePlaceholder":521},[64,2272,2273,2276],{"class":66,"line":326},[64,2274,2275],{"class":453},"    default",[64,2277,2183],{"class":70},[64,2279,2280,2282,2284,2286,2288,2291,2293,2296,2299,2302],{"class":66,"line":331},[64,2281,686],{"class":453},[64,2283,689],{"class":453},[64,2285,692],{"class":460},[64,2287,574],{"class":70},[64,2289,2290],{"class":98},"`Unknown action: ${",[64,2292,2010],{"class":70},[64,2294,2295],{"class":98},".",[64,2297,2298],{"class":70},"action",[64,2300,2301],{"class":98},"}`",[64,2303,765],{"class":70},[64,2305,2306],{"class":66,"line":339},[64,2307,376],{"class":70},[64,2309,2310],{"class":66,"line":351},[64,2311,382],{"class":70},[384,2313,2314],{"id":2314},"重要なポイント",[29,2316,2317,2326,2329],{},[32,2318,2319,2322,2323,2325],{},[61,2320,2321],{},"return true"," が重要。これがないと ",[61,2324,2020],{}," が非同期で呼ばれる前に接続が切れる",[32,2327,2328],{},"API キーは storage から取得（popup\u002Foptions から渡さない設計）",[32,2330,2331,2332,2335],{},"実際の API 通信は ",[61,2333,2334],{},"linear-api.js"," に委譲",[10,2337,2339],{"id":2338},"scriptslinear-apijs","scripts\u002Flinear-api.js",[14,2341,2342],{},"Linear GraphQL API との通信を担当するモジュールです。",[54,2344,2346],{"className":444,"code":2345,"language":446,"meta":59,"style":59},"const LINEAR_API_ENDPOINT = 'https:\u002F\u002Fapi.linear.app\u002Fgraphql';\n\n\u002F\u002F GraphQLリクエストの共通処理\nexport async function linearFetch(apiKey, query, variables = {}) {\n  const response = await fetch(LINEAR_API_ENDPOINT, {\n    method: 'POST',\n    headers: {\n      'Content-Type': 'application\u002Fjson',\n      'Authorization': apiKey,  \u002F\u002F Bearerなしで直接APIキー\n    },\n    body: JSON.stringify({ query, variables }),\n  });\n\n  if (!response.ok) {\n    throw new Error(`HTTP error: ${response.status}`);\n  }\n\n  const result = await response.json();\n\n  if (result.errors) {\n    throw new Error(result.errors[0].message);\n  }\n\n  return result.data;\n}\n\n\u002F\u002F チーム一覧を取得\nexport async function fetchTeams(apiKey) {\n  const query = `\n    query Teams {\n      teams {\n        nodes {\n          id\n          name\n        }\n      }\n    }\n  `;\n\n  const data = await linearFetch(apiKey, query);\n  return data.teams.nodes;\n}\n\n\u002F\u002F イシューを作成\nexport async function createIssue(apiKey, teamId, title) {\n  const mutation = `\n    mutation IssueCreate($title: String!, $teamId: String!) {\n      issueCreate(input: { title: $title, teamId: $teamId }) {\n        success\n        issue {\n          id\n          identifier\n          url\n        }\n      }\n    }\n  `;\n\n  const data = await linearFetch(apiKey, mutation, { title, teamId });\n\n  if (!data.issueCreate.success) {\n    throw new Error('Failed to create issue');\n  }\n\n  return data.issueCreate.issue;\n}\n\n\u002F\u002F イシューにURLを添付\nexport async function addLinkToIssue(apiKey, issueId, url, title) {\n  const mutation = `\n    mutation AttachmentLinkURL($issueId: String!, $url: String!, $title: String) {\n      attachmentLinkURL(issueId: $issueId, url: $url, title: $title) {\n        success\n        attachment {\n          id\n        }\n      }\n    }\n  `;\n\n  const data = await linearFetch(apiKey, mutation, { issueId, url, title });\n\n  if (!data.attachmentLinkURL.success) {\n    throw new Error('Failed to add link to issue');\n  }\n\n  return data.attachmentLinkURL.attachment;\n}\n\n\u002F\u002F イシュー作成 + URL添付をまとめて実行\nexport async function createIssueWithLink(apiKey, teamId, title, url) {\n  const issue = await createIssue(apiKey, teamId, title);\n  await addLinkToIssue(apiKey, issue.id, url, title);\n  return issue;\n}\n",[61,2347,2348,2363,2367,2372,2403,2424,2434,2439,2451,2462,2467,2483,2487,2491,2502,2527,2531,2535,2553,2557,2564,2581,2585,2589,2596,2600,2604,2609,2625,2637,2642,2647,2652,2657,2662,2667,2671,2675,2682,2686,2702,2709,2713,2717,2722,2747,2758,2763,2768,2773,2778,2782,2787,2792,2796,2800,2804,2810,2814,2829,2833,2844,2859,2863,2867,2874,2878,2882,2887,2917,2927,2932,2937,2941,2946,2950,2954,2959,2964,2971,2976,2992,2997,3009,3025,3030,3035,3043,3048,3053,3059,3088,3104,3115,3123],{"__ignoreMap":59},[64,2349,2350,2353,2356,2358,2361],{"class":66,"line":67},[64,2351,2352],{"class":453},"const",[64,2354,2355],{"class":77}," LINEAR_API_ENDPOINT",[64,2357,585],{"class":453},[64,2359,2360],{"class":98}," 'https:\u002F\u002Fapi.linear.app\u002Fgraphql'",[64,2362,604],{"class":70},[64,2364,2365],{"class":66,"line":74},[64,2366,522],{"emptyLinePlaceholder":521},[64,2368,2369],{"class":66,"line":90},[64,2370,2371],{"class":469},"\u002F\u002F GraphQLリクエストの共通処理\n",[64,2373,2374,2377,2380,2382,2385,2387,2389,2391,2393,2395,2398,2400],{"class":66,"line":104},[64,2375,2376],{"class":453},"export",[64,2378,2379],{"class":453}," async",[64,2381,457],{"class":453},[64,2383,2384],{"class":460}," linearFetch",[64,2386,574],{"class":70},[64,2388,481],{"class":577},[64,2390,484],{"class":70},[64,2392,1515],{"class":577},[64,2394,484],{"class":70},[64,2396,2397],{"class":577},"variables",[64,2399,585],{"class":453},[64,2401,2402],{"class":70}," {}) {\n",[64,2404,2405,2407,2409,2411,2413,2416,2418,2421],{"class":66,"line":117},[64,2406,475],{"class":453},[64,2408,641],{"class":77},[64,2410,585],{"class":453},[64,2412,496],{"class":453},[64,2414,2415],{"class":460}," fetch",[64,2417,574],{"class":70},[64,2419,2420],{"class":77},"LINEAR_API_ENDPOINT",[64,2422,2423],{"class":70},", {\n",[64,2425,2426,2429,2432],{"class":66,"line":130},[64,2427,2428],{"class":70},"    method: ",[64,2430,2431],{"class":98},"'POST'",[64,2433,87],{"class":70},[64,2435,2436],{"class":66,"line":139},[64,2437,2438],{"class":70},"    headers: {\n",[64,2440,2441,2444,2446,2449],{"class":66,"line":147},[64,2442,2443],{"class":98},"      'Content-Type'",[64,2445,81],{"class":70},[64,2447,2448],{"class":98},"'application\u002Fjson'",[64,2450,87],{"class":70},[64,2452,2453,2456,2459],{"class":66,"line":153},[64,2454,2455],{"class":98},"      'Authorization'",[64,2457,2458],{"class":70},": apiKey,  ",[64,2460,2461],{"class":469},"\u002F\u002F Bearerなしで直接APIキー\n",[64,2463,2464],{"class":66,"line":159},[64,2465,2466],{"class":70},"    },\n",[64,2468,2469,2472,2475,2477,2480],{"class":66,"line":167},[64,2470,2471],{"class":70},"    body: ",[64,2473,2474],{"class":77},"JSON",[64,2476,2295],{"class":70},[64,2478,2479],{"class":460},"stringify",[64,2481,2482],{"class":70},"({ query, variables }),\n",[64,2484,2485],{"class":66,"line":173},[64,2486,1379],{"class":70},[64,2488,2489],{"class":66,"line":178},[64,2490,522],{"emptyLinePlaceholder":521},[64,2492,2493,2495,2497,2499],{"class":66,"line":187},[64,2494,527],{"class":453},[64,2496,1120],{"class":70},[64,2498,1123],{"class":453},[64,2500,2501],{"class":70},"response.ok) {\n",[64,2503,2504,2506,2508,2510,2512,2515,2518,2520,2523,2525],{"class":66,"line":200},[64,2505,2145],{"class":453},[64,2507,689],{"class":453},[64,2509,692],{"class":460},[64,2511,574],{"class":70},[64,2513,2514],{"class":98},"`HTTP error: ${",[64,2516,2517],{"class":70},"response",[64,2519,2295],{"class":98},[64,2521,2522],{"class":70},"status",[64,2524,2301],{"class":98},[64,2526,765],{"class":70},[64,2528,2529],{"class":66,"line":208},[64,2530,376],{"class":70},[64,2532,2533],{"class":66,"line":221},[64,2534,522],{"emptyLinePlaceholder":521},[64,2536,2537,2539,2542,2544,2546,2549,2551],{"class":66,"line":234},[64,2538,475],{"class":453},[64,2540,2541],{"class":77}," result",[64,2543,585],{"class":453},[64,2545,496],{"class":453},[64,2547,2548],{"class":70}," response.",[64,2550,58],{"class":460},[64,2552,998],{"class":70},[64,2554,2555],{"class":66,"line":245},[64,2556,522],{"emptyLinePlaceholder":521},[64,2558,2559,2561],{"class":66,"line":251},[64,2560,527],{"class":453},[64,2562,2563],{"class":70}," (result.errors) {\n",[64,2565,2566,2568,2570,2572,2575,2578],{"class":66,"line":257},[64,2567,2145],{"class":453},[64,2569,689],{"class":453},[64,2571,692],{"class":460},[64,2573,2574],{"class":70},"(result.errors[",[64,2576,2577],{"class":77},"0",[64,2579,2580],{"class":70},"].message);\n",[64,2582,2583],{"class":66,"line":265},[64,2584,376],{"class":70},[64,2586,2587],{"class":66,"line":278},[64,2588,522],{"emptyLinePlaceholder":521},[64,2590,2591,2593],{"class":66,"line":289},[64,2592,2071],{"class":453},[64,2594,2595],{"class":70}," result.data;\n",[64,2597,2598],{"class":66,"line":294},[64,2599,382],{"class":70},[64,2601,2602],{"class":66,"line":302},[64,2603,522],{"emptyLinePlaceholder":521},[64,2605,2606],{"class":66,"line":315},[64,2607,2608],{"class":469},"\u002F\u002F チーム一覧を取得\n",[64,2610,2611,2613,2615,2617,2619,2621,2623],{"class":66,"line":326},[64,2612,2376],{"class":453},[64,2614,2379],{"class":453},[64,2616,457],{"class":453},[64,2618,2197],{"class":460},[64,2620,574],{"class":70},[64,2622,481],{"class":577},[64,2624,591],{"class":70},[64,2626,2627,2629,2632,2634],{"class":66,"line":331},[64,2628,475],{"class":453},[64,2630,2631],{"class":77}," query",[64,2633,585],{"class":453},[64,2635,2636],{"class":98}," `\n",[64,2638,2639],{"class":66,"line":339},[64,2640,2641],{"class":98},"    query Teams {\n",[64,2643,2644],{"class":66,"line":351},[64,2645,2646],{"class":98},"      teams {\n",[64,2648,2649],{"class":66,"line":363},[64,2650,2651],{"class":98},"        nodes {\n",[64,2653,2654],{"class":66,"line":373},[64,2655,2656],{"class":98},"          id\n",[64,2658,2659],{"class":66,"line":379},[64,2660,2661],{"class":98},"          name\n",[64,2663,2664],{"class":66,"line":829},[64,2665,2666],{"class":98},"        }\n",[64,2668,2669],{"class":66,"line":834},[64,2670,815],{"class":98},[64,2672,2673],{"class":66,"line":839},[64,2674,248],{"class":98},[64,2676,2677,2680],{"class":66,"line":852},[64,2678,2679],{"class":98},"  `",[64,2681,604],{"class":70},[64,2683,2684],{"class":66,"line":864},[64,2685,522],{"emptyLinePlaceholder":521},[64,2687,2688,2690,2693,2695,2697,2699],{"class":66,"line":888},[64,2689,475],{"class":453},[64,2691,2692],{"class":77}," data",[64,2694,585],{"class":453},[64,2696,496],{"class":453},[64,2698,2384],{"class":460},[64,2700,2701],{"class":70},"(apiKey, query);\n",[64,2703,2704,2706],{"class":66,"line":909},[64,2705,2071],{"class":453},[64,2707,2708],{"class":70}," data.teams.nodes;\n",[64,2710,2711],{"class":66,"line":914},[64,2712,382],{"class":70},[64,2714,2715],{"class":66,"line":919},[64,2716,522],{"emptyLinePlaceholder":521},[64,2718,2719],{"class":66,"line":924},[64,2720,2721],{"class":469},"\u002F\u002F イシューを作成\n",[64,2723,2724,2726,2728,2730,2733,2735,2737,2739,2741,2743,2745],{"class":66,"line":930},[64,2725,2376],{"class":453},[64,2727,2379],{"class":453},[64,2729,457],{"class":453},[64,2731,2732],{"class":460}," createIssue",[64,2734,574],{"class":70},[64,2736,481],{"class":577},[64,2738,484],{"class":70},[64,2740,487],{"class":577},[64,2742,484],{"class":70},[64,2744,2226],{"class":577},[64,2746,591],{"class":70},[64,2748,2749,2751,2754,2756],{"class":66,"line":951},[64,2750,475],{"class":453},[64,2752,2753],{"class":77}," mutation",[64,2755,585],{"class":453},[64,2757,2636],{"class":98},[64,2759,2760],{"class":66,"line":960},[64,2761,2762],{"class":98},"    mutation IssueCreate($title: String!, $teamId: String!) {\n",[64,2764,2765],{"class":66,"line":982},[64,2766,2767],{"class":98},"      issueCreate(input: { title: $title, teamId: $teamId }) {\n",[64,2769,2770],{"class":66,"line":1001},[64,2771,2772],{"class":98},"        success\n",[64,2774,2775],{"class":66,"line":1008},[64,2776,2777],{"class":98},"        issue {\n",[64,2779,2780],{"class":66,"line":1022},[64,2781,2656],{"class":98},[64,2783,2784],{"class":66,"line":1032},[64,2785,2786],{"class":98},"          identifier\n",[64,2788,2789],{"class":66,"line":1037},[64,2790,2791],{"class":98},"          url\n",[64,2793,2794],{"class":66,"line":1048},[64,2795,2666],{"class":98},[64,2797,2798],{"class":66,"line":1054},[64,2799,815],{"class":98},[64,2801,2802],{"class":66,"line":1059},[64,2803,248],{"class":98},[64,2805,2806,2808],{"class":66,"line":1082},[64,2807,2679],{"class":98},[64,2809,604],{"class":70},[64,2811,2812],{"class":66,"line":1097},[64,2813,522],{"emptyLinePlaceholder":521},[64,2815,2816,2818,2820,2822,2824,2826],{"class":66,"line":1110},[64,2817,475],{"class":453},[64,2819,2692],{"class":77},[64,2821,585],{"class":453},[64,2823,496],{"class":453},[64,2825,2384],{"class":460},[64,2827,2828],{"class":70},"(apiKey, mutation, { title, teamId });\n",[64,2830,2831],{"class":66,"line":1115},[64,2832,522],{"emptyLinePlaceholder":521},[64,2834,2835,2837,2839,2841],{"class":66,"line":1129},[64,2836,527],{"class":453},[64,2838,1120],{"class":70},[64,2840,1123],{"class":453},[64,2842,2843],{"class":70},"data.issueCreate.success) {\n",[64,2845,2846,2848,2850,2852,2854,2857],{"class":66,"line":1145},[64,2847,2145],{"class":453},[64,2849,689],{"class":453},[64,2851,692],{"class":460},[64,2853,574],{"class":70},[64,2855,2856],{"class":98},"'Failed to create issue'",[64,2858,765],{"class":70},[64,2860,2861],{"class":66,"line":1153},[64,2862,376],{"class":70},[64,2864,2865],{"class":66,"line":1158},[64,2866,522],{"emptyLinePlaceholder":521},[64,2868,2869,2871],{"class":66,"line":1163},[64,2870,2071],{"class":453},[64,2872,2873],{"class":70}," data.issueCreate.issue;\n",[64,2875,2876],{"class":66,"line":1175},[64,2877,382],{"class":70},[64,2879,2880],{"class":66,"line":1191},[64,2881,522],{"emptyLinePlaceholder":521},[64,2883,2884],{"class":66,"line":1198},[64,2885,2886],{"class":469},"\u002F\u002F イシューにURLを添付\n",[64,2888,2889,2891,2893,2895,2898,2900,2902,2904,2907,2909,2911,2913,2915],{"class":66,"line":1203},[64,2890,2376],{"class":453},[64,2892,2379],{"class":453},[64,2894,457],{"class":453},[64,2896,2897],{"class":460}," addLinkToIssue",[64,2899,574],{"class":70},[64,2901,481],{"class":577},[64,2903,484],{"class":70},[64,2905,2906],{"class":577},"issueId",[64,2908,484],{"class":70},[64,2910,2231],{"class":577},[64,2912,484],{"class":70},[64,2914,2226],{"class":577},[64,2916,591],{"class":70},[64,2918,2919,2921,2923,2925],{"class":66,"line":1208},[64,2920,475],{"class":453},[64,2922,2753],{"class":77},[64,2924,585],{"class":453},[64,2926,2636],{"class":98},[64,2928,2929],{"class":66,"line":1215},[64,2930,2931],{"class":98},"    mutation AttachmentLinkURL($issueId: String!, $url: String!, $title: String) {\n",[64,2933,2934],{"class":66,"line":1227},[64,2935,2936],{"class":98},"      attachmentLinkURL(issueId: $issueId, url: $url, title: $title) {\n",[64,2938,2939],{"class":66,"line":1244},[64,2940,2772],{"class":98},[64,2942,2943],{"class":66,"line":1253},[64,2944,2945],{"class":98},"        attachment {\n",[64,2947,2948],{"class":66,"line":1271},[64,2949,2656],{"class":98},[64,2951,2952],{"class":66,"line":1276},[64,2953,2666],{"class":98},[64,2955,2957],{"class":66,"line":2956},77,[64,2958,815],{"class":98},[64,2960,2962],{"class":66,"line":2961},78,[64,2963,248],{"class":98},[64,2965,2967,2969],{"class":66,"line":2966},79,[64,2968,2679],{"class":98},[64,2970,604],{"class":70},[64,2972,2974],{"class":66,"line":2973},80,[64,2975,522],{"emptyLinePlaceholder":521},[64,2977,2979,2981,2983,2985,2987,2989],{"class":66,"line":2978},81,[64,2980,475],{"class":453},[64,2982,2692],{"class":77},[64,2984,585],{"class":453},[64,2986,496],{"class":453},[64,2988,2384],{"class":460},[64,2990,2991],{"class":70},"(apiKey, mutation, { issueId, url, title });\n",[64,2993,2995],{"class":66,"line":2994},82,[64,2996,522],{"emptyLinePlaceholder":521},[64,2998,3000,3002,3004,3006],{"class":66,"line":2999},83,[64,3001,527],{"class":453},[64,3003,1120],{"class":70},[64,3005,1123],{"class":453},[64,3007,3008],{"class":70},"data.attachmentLinkURL.success) {\n",[64,3010,3012,3014,3016,3018,3020,3023],{"class":66,"line":3011},84,[64,3013,2145],{"class":453},[64,3015,689],{"class":453},[64,3017,692],{"class":460},[64,3019,574],{"class":70},[64,3021,3022],{"class":98},"'Failed to add link to issue'",[64,3024,765],{"class":70},[64,3026,3028],{"class":66,"line":3027},85,[64,3029,376],{"class":70},[64,3031,3033],{"class":66,"line":3032},86,[64,3034,522],{"emptyLinePlaceholder":521},[64,3036,3038,3040],{"class":66,"line":3037},87,[64,3039,2071],{"class":453},[64,3041,3042],{"class":70}," data.attachmentLinkURL.attachment;\n",[64,3044,3046],{"class":66,"line":3045},88,[64,3047,382],{"class":70},[64,3049,3051],{"class":66,"line":3050},89,[64,3052,522],{"emptyLinePlaceholder":521},[64,3054,3056],{"class":66,"line":3055},90,[64,3057,3058],{"class":469},"\u002F\u002F イシュー作成 + URL添付をまとめて実行\n",[64,3060,3062,3064,3066,3068,3070,3072,3074,3076,3078,3080,3082,3084,3086],{"class":66,"line":3061},91,[64,3063,2376],{"class":453},[64,3065,2379],{"class":453},[64,3067,457],{"class":453},[64,3069,2252],{"class":460},[64,3071,574],{"class":70},[64,3073,481],{"class":577},[64,3075,484],{"class":70},[64,3077,487],{"class":577},[64,3079,484],{"class":70},[64,3081,2226],{"class":577},[64,3083,484],{"class":70},[64,3085,2231],{"class":577},[64,3087,591],{"class":70},[64,3089,3091,3093,3095,3097,3099,3101],{"class":66,"line":3090},92,[64,3092,475],{"class":453},[64,3094,2245],{"class":77},[64,3096,585],{"class":453},[64,3098,496],{"class":453},[64,3100,2732],{"class":460},[64,3102,3103],{"class":70},"(apiKey, teamId, title);\n",[64,3105,3107,3110,3112],{"class":66,"line":3106},93,[64,3108,3109],{"class":453},"  await",[64,3111,2897],{"class":460},[64,3113,3114],{"class":70},"(apiKey, issue.id, url, title);\n",[64,3116,3118,3120],{"class":66,"line":3117},94,[64,3119,2071],{"class":453},[64,3121,3122],{"class":70}," issue;\n",[64,3124,3126],{"class":66,"line":3125},95,[64,3127,382],{"class":70},[10,3129,3130],{"id":3130},"全体のアーキテクチャ",[54,3132,3137],{"className":3133,"code":3135,"language":3136},[3134],"language-text","popup.js \u002F options.js\n    ↓ chrome.runtime.sendMessage()\nbackground.js (メッセージハブ)\n    ↓ import\nlinear-api.js (API通信)\n    ↓ fetch\nLinear GraphQL API\n","text",[61,3138,3135],{"__ignoreMap":59},[14,3140,3141],{},"この設計により、UI 層（popup\u002Foptions）と API 通信層（linear-api.js）が分離され、保守性が高くなっています。また、background.js がメッセージハブとして機能することで、API キーの管理を一元化できています。",[10,3143,3144],{"id":3144},"まとめ",[14,3146,3147],{},"Chrome 拡張機能 Manifest V3 の基本的な構成と、Linear GraphQL API を使ったイシュー作成の実装を紹介しました。Service Worker ベースの background.js を使ったメッセージパッシングのパターンは、他の API 連携にも応用できるかと思います。",[3149,3150,3151],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":59,"searchDepth":74,"depth":74,"links":3153},[3154,3155,3156,3160,3163,3166,3169,3170,3171],{"id":12,"depth":74,"text":12},{"id":27,"depth":74,"text":27},{"id":48,"depth":74,"text":49,"children":3157},[3158,3159],{"id":386,"depth":90,"text":387},{"id":410,"depth":90,"text":410},{"id":437,"depth":74,"text":438,"children":3161},[3162],{"id":1281,"depth":90,"text":1281},{"id":1315,"depth":74,"text":1316,"children":3164},[3165],{"id":1931,"depth":90,"text":1281},{"id":1963,"depth":74,"text":1964,"children":3167},[3168],{"id":2314,"depth":90,"text":2314},{"id":2338,"depth":74,"text":2339},{"id":3130,"depth":74,"text":3130},{"id":3144,"depth":74,"text":3144},"2026-01-04","現在のページURLをLinearイシューにクリップするChrome拡張機能を作成しました。Manifest V3、GraphQL API、Chrome Storage APIの使い方を解説します。","md",{"tags":3176},[3177,3178,446],"chrome-extension","linear","\u002Fblog\u002Flinear-clipper-extension",{"title":5,"description":3173},"blog\u002Flinear-clipper-extension","i-iwux5J_m84OiPok5BY38rIUoo5INDJ-eHpxa24zFU",1773664053769]