nlobby-cli 1.3.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/index.js +32 -32
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# N Lobby CLI
|
|
1
|
+
# N Lobby CLI
|
|
2
2
|
|
|
3
3
|
> **Note:** The developer assumes no responsibility for any damages that may occur from using this tool. This software was developed for educational purposes and its operation is not guaranteed.
|
|
4
4
|
|
|
@@ -28,8 +28,8 @@ npm install -g nlobby-cli
|
|
|
28
28
|
1. Clone the repository:
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
|
-
git clone https://github.com/minagishl/nlobby-
|
|
32
|
-
cd nlobby-
|
|
31
|
+
git clone https://github.com/minagishl/nlobby-cli.git
|
|
32
|
+
cd nlobby-cli
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
2. Install dependencies:
|
|
@@ -50,7 +50,7 @@ Create a `.env` file if you need to override defaults (optional):
|
|
|
50
50
|
|
|
51
51
|
```env
|
|
52
52
|
NLOBBY_BASE_URL=https://nlobby.nnn.ed.jp
|
|
53
|
-
MCP_SERVER_NAME=nlobby-
|
|
53
|
+
MCP_SERVER_NAME=nlobby-cli
|
|
54
54
|
MCP_SERVER_VERSION=1.0.0
|
|
55
55
|
```
|
|
56
56
|
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var Dt=Object.defineProperty;var p=(o,e)=>()=>(o&&(e=o(o=0)),e);var P=(o,e)=>{for(var t in e)Dt(o,t,{get:e[t],enumerable:!0})};var J={};P(J,{LogLevel:()=>z,Logger:()=>$,logger:()=>i});var z,$,i,m=p(()=>{"use strict";z=(r=>(r[r.DEBUG=0]="DEBUG",r[r.INFO=1]="INFO",r[r.WARN=2]="WARN",r[r.ERROR=3]="ERROR",r))(z||{}),$=class o{static instance;logLevel=1;isProduction=!1;constructor(){this.isProduction=process.env.NODE_ENV==="production"||process.env.MCP_PRODUCTION==="true"||!process.stdout.isTTY}static getInstance(){return o.instance||(o.instance=new o),o.instance}setLogLevel(e){this.logLevel=e}forceProductionMode(){this.isProduction=!0}log(e,t,...n){if(e<this.logLevel||this.isProduction&&e<2)return;let r=new Date().toISOString(),s=z[e],a=`[${r}] [${s}]`;switch(e){case 0:console.debug(a,t,...n);break;case 1:console.info(a,t,...n);break;case 2:console.warn(a,t,...n);break;case 3:console.error(a,t,...n);break}}debug(e,...t){this.log(0,e,...t)}info(e,...t){this.log(1,e,...t)}warn(e,...t){this.log(2,e,...t)}error(e,...t){this.log(3,e,...t)}},i=$.getInstance()});import{config as It}from"dotenv";function Lt(){switch(process.platform){case"darwin":return"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";case"win32":return"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";case"linux":default:return"Mozilla/5.0 (X11; CrOS x86_64 10066.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"}}var g,S=p(()=>{"use strict";It();g={nlobby:{baseUrl:process.env.NLOBBY_BASE_URL||"https://nlobby.nnn.ed.jp"},mcp:{serverName:process.env.MCP_SERVER_NAME||"nlobby-mcp",serverVersion:process.env.MCP_SERVER_VERSION||"1.3.0"},userAgent:process.env.USER_AGENT||Lt()}});var O,ae=p(()=>{"use strict";m();O=class{cookies={};constructor(){}parseCookies(e){let t={},n=e.split(";");for(let r of n){let[s,a]=r.trim().split("=");s&&a&&(s==="__Secure-next-auth.session-token"?t.sessionToken=decodeURIComponent(a):s==="__Host-next-auth.csrf-token"?t.csrfToken=decodeURIComponent(a):s==="__Secure-next-auth.callback-url"&&(t.callbackUrl=decodeURIComponent(a)))}return t}setCookies(e){this.cookies=this.parseCookies(e),i.debug("NextAuth cookies parsed:",{hasSessionToken:!!this.cookies.sessionToken,hasCsrfToken:!!this.cookies.csrfToken,hasCallbackUrl:!!this.cookies.callbackUrl})}getCookies(){return this.cookies}getCookieHeader(){let e=[];return this.cookies.sessionToken&&e.push(`__Secure-next-auth.session-token=${encodeURIComponent(this.cookies.sessionToken)}`),this.cookies.csrfToken&&e.push(`__Host-next-auth.csrf-token=${encodeURIComponent(this.cookies.csrfToken)}`),this.cookies.callbackUrl&&e.push(`__Secure-next-auth.callback-url=${encodeURIComponent(this.cookies.callbackUrl)}`),e.join("; ")}isAuthenticated(){return!!this.cookies.sessionToken}getSessionToken(){return this.cookies.sessionToken||null}async decodeSessionToken(){if(!this.cookies.sessionToken)return null;try{return{token:this.cookies.sessionToken}}catch(e){return i.error("Error decoding session token:",e),null}}clear(){this.cookies={}}}});import Ut from"axios";var _,ce=p(()=>{"use strict";S();m();_=class{httpClient;nextAuth;requestId=1;allCookies="";constructor(e){this.nextAuth=e,this.httpClient=Ut.create({baseURL:`${g.nlobby.baseUrl}/api/trpc`,timeout:15e3,headers:{"Content-Type":"application/json","User-Agent":g.userAgent,Accept:"application/json","Accept-Language":"ja,en-US;q=0.7,en;q=0.3","Accept-Encoding":"gzip, deflate, br",Connection:"keep-alive","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"same-origin"},withCredentials:!0}),this.setupInterceptors()}setAllCookies(e){if(!e||e.trim()===""){i.warn("[WARNING] Empty cookies provided to tRPC client"),this.allCookies="";return}this.allCookies=e,i.info("[SUCCESS] tRPC client cookies updated"),i.info(`[SIZE] tRPC cookie string length: ${e.length}`),this.allCookies===e?i.info("[SUCCESS] tRPC cookie verification successful"):i.error("[ERROR] tRPC cookie verification failed")}setupInterceptors(){this.httpClient.interceptors.request.use(e=>{let t;if(this.allCookies&&this.allCookies.trim()!=="")t=this.allCookies,i.debug("[COOKIE] Using all cookies for tRPC request");else{let s=this.nextAuth.getCookieHeader();s&&s.trim()!==""?(t=s,i.debug("[COOKIE] Using NextAuth cookies for tRPC request")):i.warn("[WARNING] No cookies available for tRPC request")}t&&(e.headers.Cookie=t);let n=this.nextAuth.getSessionToken();n?(e.headers.Authorization=`Bearer ${n}`,i.debug("Added Authorization header with session token")):i.warn("[WARNING] No session token available for Authorization header");let r=this.nextAuth.getCookies().csrfToken;return r&&(e.headers["X-CSRF-Token"]=r,i.debug("Added CSRF token to tRPC request")),i.debug("[REQUEST] tRPC request details:",{url:e.url,method:e.method?.toUpperCase(),hasCookies:!!t,hasCSRF:!!r,hasAuth:!!n,cookieSource:this.allCookies?"allCookies":"nextAuth"}),e}),this.httpClient.interceptors.response.use(e=>(i.debug("[SUCCESS] tRPC response received:",{status:e.status,statusText:e.statusText,hasData:!!e.data}),e),async e=>{if(i.error("[ERROR] tRPC request failed:",{status:e.response?.status,statusText:e.response?.statusText,message:e.message,url:e.config?.url}),e.response?.status===401)throw i.error("[BLOCKED] Authentication failed - NextAuth session may be expired"),new Error("Authentication expired. Please re-authenticate with NextAuth cookies.");if(e.response?.status===403)throw i.error("[BLOCKED] Access forbidden - insufficient permissions"),new Error("Access forbidden. Check your permissions or re-authenticate.");if(e.response?.status===404)throw i.error("[BLOCKED] tRPC endpoint not found"),new Error("tRPC endpoint not found. The API may have changed.");return Promise.reject(e)})}getNextRequestId(){return this.requestId++}async call(e,t){let n={id:this.getNextRequestId(),method:e,params:t};try{i.info(`[REQUEST] tRPC call: ${e}`,t?`with params: ${JSON.stringify(t)}`:"without params");let r=this.allCookies||this.nextAuth.getCookieHeader();i.debug(`[COOKIE] Request cookies: ${r?"present":"missing"}`),i.debug("Trying GET approach...");try{let s=this.buildTRPCUrl(e,t);i.debug(`[URL] tRPC GET URL: ${s}`);let a=await this.httpClient.get(s);if(i.debug(`[SUCCESS] tRPC ${e} GET response status: ${a.status}`),a.data.error)throw i.error(`[ERROR] tRPC ${e} GET returned error:`,a.data.error),new Error(`tRPC Error [${a.data.error.code}]: ${a.data.error.message}`);return i.debug(`[SUCCESS] tRPC ${e} GET succeeded`),a.data.result}catch(s){i.debug("[WARNING] GET approach failed, trying POST approach..."),i.debug("[DEBUG] GET error details:",s instanceof Error?s.message:"Unknown error");let a=e;i.debug(`[URL] tRPC POST URL: ${a}`);let c=await this.httpClient.post(a,n,{headers:{"Content-Type":"application/json"}});if(i.debug(`[SUCCESS] tRPC ${e} POST response status: ${c.status}`),c.data.error)throw i.error(`[ERROR] tRPC ${e} POST returned error:`,c.data.error),new Error(`tRPC Error [${c.data.error.code}]: ${c.data.error.message}`);return i.debug(`[SUCCESS] tRPC ${e} POST succeeded`),c.data.result}}catch(r){if(i.error(`[ERROR] tRPC call failed for ${e}:`,{message:r instanceof Error?r.message:"Unknown error",stack:r instanceof Error?r.stack:void 0}),r&&typeof r=="object"&&"response"in r){let s=r;i.error(`[DEBUG] tRPC ${e} Axios error details:`,{status:s.response?.status,statusText:s.response?.statusText,headers:s.response?.headers,data:s.response?.data,url:s.config?.url,method:s.config?.method,timeout:s.config?.timeout,cookies:s.config?.headers?.Cookie?"present":"missing"}),s.response?.status===401?i.error("[BLOCKED] tRPC 401 Unauthorized - session may be expired or invalid"):s.response?.status===403?i.error("[BLOCKED] tRPC 403 Forbidden - insufficient permissions"):s.response?.status===404?i.error("[BLOCKED] tRPC 404 Not Found - endpoint may not exist"):s.response?.status&&s.response.status>=500&&i.error("[BLOCKED] tRPC Server Error - N Lobby backend issue")}else if(r&&typeof r=="object"&&"code"in r){let s=r;s.code==="ECONNREFUSED"?i.error("[NETWORK] Network Error: Connection refused - N Lobby may be down"):s.code==="ETIMEDOUT"?i.error("[TIMEOUT] Network Error: Request timeout - slow network or server overload"):s.code==="ENOTFOUND"&&i.error("[NETWORK] Network Error: DNS lookup failed - check internet connection")}throw r}}buildTRPCUrl(e,t){let n=e,r=JSON.stringify(t||{}),s=new URLSearchParams({input:r}).toString();return`${n}?${s}`}async getUnreadNewsCount(){return this.call("news.getUnreadNewsCount")}async getNotificationMessages(){return this.call("notification.getMessages")}async updateLastAccess(){return this.call("user.updateLastAccess")}async findMainNavigations(){return this.call("menu.findMainNavigations",{})}async readInterestsWithIcon(){return this.call("interest.readInterestsWithIcon")}async readInterests(){return this.call("interest.readInterests")}async readWeights(){return this.call("interest.readWeights")}async getLobbyCalendarEvents(e,t){return this.call("calendar.getLobbyCalendarEvents",{from:e,to:t})}async healthCheck(){i.info("Running tRPC health check...");let e=[{name:"updateLastAccess",method:()=>this.updateLastAccess()},{name:"getUnreadNewsCount",method:()=>this.getUnreadNewsCount()},{name:"findMainNavigations",method:()=>this.findMainNavigations()}];for(let{name:t,method:n}of e)try{return i.debug(`Trying tRPC method: ${t}`),await n(),i.info(`[SUCCESS] tRPC health check passed with method: ${t}`),!0}catch(r){i.debug(`[ERROR] tRPC method ${t} failed:`,r instanceof Error?r.message:"Unknown error");continue}return i.error("[ERROR] All tRPC health check methods failed"),!1}}});async function v(o,e){try{i.info("[NETWORK] Fetching HTML using HTTP client (proven method)..."),i.debug(`[URL] URL: ${g.nlobby.baseUrl+e}`),i.info("[COOKIE] Cookies:",o.httpClient.defaults.headers.Cookie?"present":"missing");let t=await o.httpClient.get(e,{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","Accept-Language":"ja,en-US;q=0.7,en;q=0.3","Accept-Encoding":"gzip, deflate, br",Connection:"keep-alive","Upgrade-Insecure-Requests":"1","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"none","Cache-Control":"max-age=0","User-Agent":g.userAgent},withCredentials:!0});if(i.info(`[SUCCESS] HTTP response: ${t.status} ${t.statusText}`),i.info(`[DATA] Content length: ${t.data?.length||"unknown"}`),i.info(`[DATA] Content type: ${t.headers["content-type"]||"unknown"}`),typeof t.data=="string"){let n=t.data,r=n.toLowerCase();if(r.includes("\u30ED\u30B0\u30A4\u30F3")||r.includes("login")?i.warn("[WARNING] WARNING: Page contains login keywords - authentication may have failed"):(r.includes("news")||r.includes("\u304A\u77E5\u3089\u305B"))&&i.info("[SUCCESS] Page appears to contain news content"),r.includes("unauthorized")||r.includes("access denied"))throw new Error("Access denied - authentication failed");return i.info(`[TARGET] HTML retrieved successfully: ${n.length} characters`),n}else throw new Error(`Non-string response received: ${typeof t.data}`)}catch(t){if(i.error("[ERROR] HTTP fetch error:",t instanceof Error?t.message:"Unknown error"),t&&typeof t=="object"&&"response"in t){let n=t;i.debug("[DEBUG] HTTP Error Details:",{status:n.response?.status,statusText:n.response?.statusText,url:n.config?.url,hasData:!!n.response?.data})}throw t}}var Y=p(()=>{"use strict";S();m()});import*as le from"cheerio";function Pt(o){if(!o)return"";try{return o.replace(/\\u003c/g,"<").replace(/\\u003e/g,">").replace(/\\u0026/g,"&").replace(/\\"/g,'"').replace(/\\\\/g,"\\")}catch{return o}}function ue(o,e=""){if(!o||typeof o!="object")return null;let t=o;if(t.id&&t.title&&(t.publishedAt||t.description||t.menuName))return i.info(`[INFO] Found news object at path: ${e}`),o;if(t.news&&typeof t.news=="object")return i.info(`[INFO] Found news property at path: ${e}.news`),t.news;for(let[n,r]of Object.entries(t))if(r&&typeof r=="object"){let s=e?`${e}.${n}`:n,a=ue(r,s);if(a)return a}return null}function j(o,e=""){if(!o||typeof o!="object")return[];if(Array.isArray(o)){if(o.length>0){let n=o[0];if(n&&typeof n=="object"&&["title","name","content","publishedAt","menuName","createdAt","updatedAt","id"].some(a=>a in n))return i.info(`[INFO] Found potential news array at path: ${e}, length: ${o.length}`),o}return[]}let t=[];for(let[n,r]of Object.entries(o)){let s=["news","announcements","data","items","list","content","notifications","posts","feed","results"],a=e?`${e}.${n}`:n;s.includes(n.toLowerCase())&&i.info(`[INFO] Searching priority key: ${a}`);let c=j(r,a);t.push(...c)}return t}function F(o){return o.map((e,t)=>{let n=e,r=new Date;n.publishedAt?r=new Date(n.publishedAt):n.createdAt?r=new Date(n.createdAt):n.updatedAt?r=new Date(n.updatedAt):n.date&&(r=new Date(n.date));let s=n.title||n.name||n.subject||n.heading||`News Item ${t+1}`,a=n.content||n.description||n.body||n.text||n.summary||"",c=n.category||n.menuName||n.type||n.classification||"General",l="medium";n.isImportant===!0||n.important===!0||n.priority==="high"||n.urgent===!0?l="high":(n.priority==="low"||n.minor===!0)&&(l="low");let u=n.id||t,d=`${g.nlobby.baseUrl}/news/${u}`;return{id:n.id?.toString()||t.toString(),title:s,content:a,publishedAt:r,category:c,priority:l,targetAudience:n.targetAudience||["student"],url:d,menuName:n.menuName,isImportant:!!n.isImportant,isUnread:!!n.isUnread,...Object.fromEntries(Object.entries(n).filter(([y])=>!["id","title","content","publishedAt","category","priority","url"].includes(y)))}})}function $t(o){try{i.info("[TARGET] Starting Cheerio-based DOM parsing...");let e=le.load(o),t=e('div[role="presentation"]');if(i.info(`[INFO] Found ${t.length} div[role="presentation"] elements`),t.length<2)return i.info('[WARNING] Less than 2 div[role="presentation"] elements found'),[];let n=e(t[1]);i.info('[SUCCESS] Located second div[role="presentation"] element');let r=n.find('div[role="row"]');i.info(`[INFO] Found ${r.length} DataGrid rows`);let s=[];return r.each((a,c)=>{try{let l=e(c),u=l.attr("data-id");if(!u)return;let d=l.find('div[role="gridcell"]'),h="",y="",f=new Date,w=!1,b=!1,C="";if(d.each((x,W)=>{let N=e(W);switch(N.attr("data-field")){case"title":{let k=N.find("a");if(k.length>0){let E=k.attr("href");E&&E.startsWith("/news/")?C=`${g.nlobby.baseUrl}${E}`:C=`${g.nlobby.baseUrl}/news/${u}`;let ie=k.find("span");h=ie.length>0?ie.text().trim():k.text().trim()}else h=N.text().trim(),C=`${g.nlobby.baseUrl}/news/${u}`;break}case"menuName":y=N.text().trim();break;case"isImportant":{w=N.text().trim().length>0||N.find("*").length>0;break}case"isUnread":{let k=N.text().trim();b=k.includes("\u672A\u8AAD")||k.length>0;break}case"publishedAt":{let k=N.text().trim();if(k){let E=new Date(k.replace(/\//g,"-"));isNaN(E.getTime())||(f=E)}break}}}),h){let x=C||`${g.nlobby.baseUrl}/news/${u}`,W={id:u,title:h,content:"",publishedAt:f,category:y||"General",priority:w?"high":"medium",targetAudience:["student"],url:x,menuName:y,isImportant:w,isUnread:b};s.push(W)}}catch(l){i.error(`[ERROR] Error parsing row ${a}:`,l instanceof Error?l.message:"Unknown error")}}),i.info(`[TARGET] Cheerio parsing completed: ${s.length} news items extracted`),s}catch(e){return i.error("[ERROR] Cheerio parsing failed:",e instanceof Error?e.message:"Unknown error"),[]}}function Ot(o){let e=[];try{i.info("[INFO] Starting HTML parsing...");let t=o.match(/self\.__next_f\.push\((\[.*?\])\)/g);if(t&&t.length>0){i.info(`[SUCCESS] Found ${t.length} self.__next_f.push() calls`);for(let s=0;s<t.length;s++){let a=t[s];try{let c=a.match(/self\.__next_f\.push\((\[.*?\])\)/);if(!c)continue;let l=JSON.parse(c[1]);if(l.length>=2&&typeof l[1]=="string"){let d=l[1],h=d.match(/^(\d+):(.*)/);if(h)try{let y=h[2],f=JSON.parse(y);if(Array.isArray(f))for(let w=0;w<f.length;w++){let b=f[w];if(Array.isArray(b)&&b.length>=4&&b[3]&&typeof b[3]=="object"){let C=b[3];if(C.news&&Array.isArray(C.news)&&C.news.length>0){let x=C.news[0];if(x&&typeof x=="object"&&(x.id||x.title||x.microCmsId))return F(C.news)}}}}catch{}else try{let y=JSON.parse(d),f=j(y,`push_call_${s+1}_fallback`);if(f&&f.length>0)return F(f)}catch{}}let u=j(l,`push_call_${s+1}_direct`);if(u&&u.length>0)return F(u)}catch{}}}let n=$t(o);if(n&&n.length>0)return n;let r=[o.match(/window\.__NEXT_DATA__\s*=\s*({.*?})\s*(?:;|<\/script>)/s),o.match(/<script id="__NEXT_DATA__"[^>]*>([^<]*)<\/script>/s)];for(let s of r)if(s)try{let a=s[1]||s[0],c=JSON.parse(a),l=j(c,"__NEXT_DATA__");if(l&&l.length>0)return F(l)}catch{}}catch(t){i.error("[ERROR] Error parsing news from HTML:",t)}return e}function _t(o,e){try{let t=o.match(/self\.__next_f\.push\((\[.*?\])\)/g);if(!t||t.length===0)return null;let n=null,r="",s=new Map;for(let c=0;c<t.length;c++){let l=t[c];try{let u=l.match(/self\.__next_f\.push\((\[.*?\])\)/);if(!u)continue;let d=JSON.parse(u[1]);if(d.length>=2&&typeof d[1]=="string"&&d[1].match(/^\d+:T\d+,?$/)){let h=d[1].replace(/,$/,"");if(c+1<t.length){let f=t[c+1].match(/self\.__next_f\.push\((\[.*?\])\)/);if(f){let w=JSON.parse(f[1]);w.length>=2&&typeof w[1]=="string"&&s.set(h,w[1])}}continue}if(d.length>=2&&typeof d[1]=="string"){let y=d[1].match(/^(\d+):(.*)/);if(y)try{let f=y[2],w=JSON.parse(f),b=ue(w);b&&(n=b)}catch{}}}catch{}}if(!n)return null;if(n.description){for(let[c,l]of s)if(n.description.includes(c)){r=l;break}}return!r&&s.size>0&&(r=Array.from(s.values())[0]),{id:n.id||e,microCmsId:n.microCmsId,title:n.title||"No Title",content:Pt(r)||n.description||"",description:n.description,publishedAt:n.publishedAt?new Date(n.publishedAt):new Date,menuName:n.menuName||[],isImportant:n.isImportant||!1,isByMentor:n.isByMentor||!1,attachments:n.attachments||[],relatedEvents:n.relatedEvents||[],targetUserQueryId:n.targetUserQueryId,url:`${g.nlobby.baseUrl}/news/${e}`}}catch(t){return i.error("[ERROR] Error parsing news detail from HTML:",t),null}}async function de(o){i.info("[INFO] Starting getNews with HTTP client..."),i.info("[STATUS] Current authentication status:",o.getCookieStatus());try{let e=await v(o,"/news"),t=Ot(e);if(t&&t.length>0)return i.info(`[SUCCESS] Retrieved ${t.length} news items from HTML`),t;{let n=`HTML scraping returned no data. Debug info:
|
|
3
|
-
- Authentication status: ${
|
|
4
|
-
- HTTP cookies: ${
|
|
2
|
+
var Ut=Object.defineProperty;var g=(s,e)=>()=>(s&&(e=s(s=0)),e);var F=(s,e)=>{for(var t in e)Ut(s,t,{get:e[t],enumerable:!0})};var V={};F(V,{LogLevel:()=>K,Logger:()=>j,logger:()=>o});var K,j,o,b=g(()=>{"use strict";K=(r=>(r[r.DEBUG=0]="DEBUG",r[r.INFO=1]="INFO",r[r.WARN=2]="WARN",r[r.ERROR=3]="ERROR",r))(K||{}),j=class s{static instance;logLevel=1;isProduction=!1;constructor(){this.isProduction=process.env.NODE_ENV==="production"||process.env.MCP_PRODUCTION==="true"||!process.stdout.isTTY}static getInstance(){return s.instance||(s.instance=new s),s.instance}setLogLevel(e){this.logLevel=e}forceProductionMode(){this.isProduction=!0}log(e,t,...n){if(e<this.logLevel||this.isProduction&&e<2)return;let r=new Date().toISOString(),i=K[e],a=`[${r}] [${i}]`;switch(e){case 0:console.debug(a,t,...n);break;case 1:console.info(a,t,...n);break;case 2:console.warn(a,t,...n);break;case 3:console.error(a,t,...n);break}}debug(e,...t){this.log(0,e,...t)}info(e,...t){this.log(1,e,...t)}warn(e,...t){this.log(2,e,...t)}error(e,...t){this.log(3,e,...t)}},o=j.getInstance()});import Pt from"node-fetch";var k,A,T=g(()=>{"use strict";k=class extends Error{response;config;code;constructor(e){super(e),this.name="HttpClientError"}},A=class{defaults;baseURL;requestInterceptors=[];responseSuccessInterceptors=[];responseErrorInterceptors=[];interceptors={request:{use:e=>{this.requestInterceptors.push(e)}},response:{use:(e,t)=>{this.responseSuccessInterceptors.push(e),t&&this.responseErrorInterceptors.push(t)}}};constructor(e){this.baseURL=e.baseURL??"",this.defaults={headers:{...e.headers??{}},timeout:e.timeout??3e4,baseURL:this.baseURL}}async get(e,t){return this.request("GET",e,void 0,t)}async post(e,t,n){return this.request("POST",e,t,n)}async parseBody(e){if((e.headers.get("content-type")??"").includes("application/json"))try{return await e.json()}catch{return await e.text()}return await e.text()}extractHeaders(e){let t={};return e.headers.forEach((n,r)=>{t[r]=n}),t}async runErrorInterceptors(e){for(let t of this.responseErrorInterceptors)await t(e)}async request(e,t,n,r){let i=t.startsWith("http")?t:`${this.baseURL}${t}`;if(r?.params&&Object.keys(r.params).length>0){let p={};for(let[L,R]of Object.entries(r.params))R!==void 0&&(p[L]=R);let f=new URLSearchParams(p).toString();i+=(i.includes("?")?"&":"?")+f}let a={...this.defaults.headers,...r?.headers??{}},c={url:i,method:e,headers:a,timeout:r?.timeout??this.defaults.timeout};for(let p of this.requestInterceptors)c=await p(c);let l={};for(let[p,f]of Object.entries(c.headers))f!==void 0&&(l[p]=f);let u=new AbortController,d=setTimeout(()=>u.abort(),c.timeout),h;try{let p={method:c.method,headers:l,signal:u.signal};n!==void 0&&(p.body=typeof n=="string"?n:JSON.stringify(n)),h=await Pt(c.url,p),clearTimeout(d)}catch(p){clearTimeout(d);let f=new k(p instanceof Error?p.message:"Network error");throw f.config={url:c.url,method:c.method,headers:c.headers,timeout:c.timeout},p instanceof Error&&(p.name==="AbortError"?(f.code="ETIMEDOUT",f.message=`timeout of ${c.timeout}ms exceeded`):p.message.includes("ECONNREFUSED")?f.code="ECONNREFUSED":p.message.includes("ENOTFOUND")&&(f.code="ENOTFOUND")),await this.runErrorInterceptors(f),f}let w=await this.parseBody(h),y=this.extractHeaders(h);if(!h.ok){let p=new k(`Request failed with status code ${h.status}`);throw p.response={status:h.status,statusText:h.statusText,data:w,headers:y},p.config={url:c.url,method:c.method,headers:c.headers,timeout:c.timeout},await this.runErrorInterceptors(p),p}let C={data:w,status:h.status,statusText:h.statusText,headers:y};for(let p of this.responseSuccessInterceptors)C=await p(C);return C}}});import{config as Ot}from"dotenv";function $t(){switch(process.platform){case"darwin":return"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";case"win32":return"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36";case"linux":default:return"Mozilla/5.0 (X11; CrOS x86_64 10066.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"}}var m,E=g(()=>{"use strict";Ot();m={nlobby:{baseUrl:process.env.NLOBBY_BASE_URL||"https://nlobby.nnn.ed.jp"},mcp:{serverName:process.env.MCP_SERVER_NAME||"nlobby-cli",serverVersion:process.env.MCP_SERVER_VERSION||"1.3.0"},userAgent:process.env.USER_AGENT||$t()}});var M,ue=g(()=>{"use strict";b();M=class{cookies={};constructor(){}parseCookies(e){let t={},n=e.split(";");for(let r of n){let[i,a]=r.trim().split("=");i&&a&&(i==="__Secure-next-auth.session-token"?t.sessionToken=decodeURIComponent(a):i==="__Host-next-auth.csrf-token"?t.csrfToken=decodeURIComponent(a):i==="__Secure-next-auth.callback-url"&&(t.callbackUrl=decodeURIComponent(a)))}return t}setCookies(e){this.cookies=this.parseCookies(e),o.debug("NextAuth cookies parsed:",{hasSessionToken:!!this.cookies.sessionToken,hasCsrfToken:!!this.cookies.csrfToken,hasCallbackUrl:!!this.cookies.callbackUrl})}getCookies(){return this.cookies}getCookieHeader(){let e=[];return this.cookies.sessionToken&&e.push(`__Secure-next-auth.session-token=${encodeURIComponent(this.cookies.sessionToken)}`),this.cookies.csrfToken&&e.push(`__Host-next-auth.csrf-token=${encodeURIComponent(this.cookies.csrfToken)}`),this.cookies.callbackUrl&&e.push(`__Secure-next-auth.callback-url=${encodeURIComponent(this.cookies.callbackUrl)}`),e.join("; ")}isAuthenticated(){return!!this.cookies.sessionToken}getSessionToken(){return this.cookies.sessionToken||null}async decodeSessionToken(){if(!this.cookies.sessionToken)return null;try{return{token:this.cookies.sessionToken}}catch(e){return o.error("Error decoding session token:",e),null}}clear(){this.cookies={}}}});var H,de=g(()=>{"use strict";T();E();b();H=class{httpClient;nextAuth;requestId=1;allCookies="";constructor(e){this.nextAuth=e,this.httpClient=new A({baseURL:`${m.nlobby.baseUrl}/api/trpc`,timeout:15e3,headers:{"Content-Type":"application/json","User-Agent":m.userAgent,Accept:"application/json","Accept-Language":"ja,en-US;q=0.7,en;q=0.3","Accept-Encoding":"gzip, deflate, br",Connection:"keep-alive","Sec-Fetch-Dest":"empty","Sec-Fetch-Mode":"cors","Sec-Fetch-Site":"same-origin"},withCredentials:!0}),this.setupInterceptors()}setAllCookies(e){if(!e||e.trim()===""){o.warn("[WARNING] Empty cookies provided to tRPC client"),this.allCookies="";return}this.allCookies=e,o.info("[SUCCESS] tRPC client cookies updated"),o.info(`[SIZE] tRPC cookie string length: ${e.length}`),this.allCookies===e?o.info("[SUCCESS] tRPC cookie verification successful"):o.error("[ERROR] tRPC cookie verification failed")}setupInterceptors(){this.httpClient.interceptors.request.use(e=>{let t;if(this.allCookies&&this.allCookies.trim()!=="")t=this.allCookies,o.debug("[COOKIE] Using all cookies for tRPC request");else{let i=this.nextAuth.getCookieHeader();i&&i.trim()!==""?(t=i,o.debug("[COOKIE] Using NextAuth cookies for tRPC request")):o.warn("[WARNING] No cookies available for tRPC request")}t&&(e.headers.Cookie=t);let n=this.nextAuth.getSessionToken();n?(e.headers.Authorization=`Bearer ${n}`,o.debug("Added Authorization header with session token")):o.warn("[WARNING] No session token available for Authorization header");let r=this.nextAuth.getCookies().csrfToken;return r&&(e.headers["X-CSRF-Token"]=r,o.debug("Added CSRF token to tRPC request")),o.debug("[REQUEST] tRPC request details:",{url:e.url,method:e.method?.toUpperCase(),hasCookies:!!t,hasCSRF:!!r,hasAuth:!!n,cookieSource:this.allCookies?"allCookies":"nextAuth"}),e}),this.httpClient.interceptors.response.use(e=>(o.debug("[SUCCESS] tRPC response received:",{status:e.status,statusText:e.statusText,hasData:!!e.data}),e),async e=>{let t=e instanceof k?e:null;if(o.error("[ERROR] tRPC request failed:",{status:t?.response?.status,statusText:t?.response?.statusText,message:e instanceof Error?e.message:"Unknown error",url:t?.config?.url}),t?.response?.status===401)throw o.error("[BLOCKED] Authentication failed - NextAuth session may be expired"),new Error("Authentication expired. Please re-authenticate with NextAuth cookies.");if(t?.response?.status===403)throw o.error("[BLOCKED] Access forbidden - insufficient permissions"),new Error("Access forbidden. Check your permissions or re-authenticate.");if(t?.response?.status===404)throw o.error("[BLOCKED] tRPC endpoint not found"),new Error("tRPC endpoint not found. The API may have changed.");return Promise.reject(e)})}getNextRequestId(){return this.requestId++}async call(e,t){let n={id:this.getNextRequestId(),method:e,params:t};try{o.info(`[REQUEST] tRPC call: ${e}`,t?`with params: ${JSON.stringify(t)}`:"without params");let r=this.allCookies||this.nextAuth.getCookieHeader();o.debug(`[COOKIE] Request cookies: ${r?"present":"missing"}`),o.debug("Trying GET approach...");try{let i=this.buildTRPCUrl(e,t);o.debug(`[URL] tRPC GET URL: ${i}`);let a=await this.httpClient.get(i);if(o.debug(`[SUCCESS] tRPC ${e} GET response status: ${a.status}`),a.data.error)throw o.error(`[ERROR] tRPC ${e} GET returned error:`,a.data.error),new Error(`tRPC Error [${a.data.error.code}]: ${a.data.error.message}`);return o.debug(`[SUCCESS] tRPC ${e} GET succeeded`),a.data.result}catch(i){o.debug("[WARNING] GET approach failed, trying POST approach..."),o.debug("[DEBUG] GET error details:",i instanceof Error?i.message:"Unknown error");let a=e;o.debug(`[URL] tRPC POST URL: ${a}`);let c=await this.httpClient.post(a,n,{headers:{"Content-Type":"application/json"}});if(o.debug(`[SUCCESS] tRPC ${e} POST response status: ${c.status}`),c.data.error)throw o.error(`[ERROR] tRPC ${e} POST returned error:`,c.data.error),new Error(`tRPC Error [${c.data.error.code}]: ${c.data.error.message}`);return o.debug(`[SUCCESS] tRPC ${e} POST succeeded`),c.data.result}}catch(r){throw o.error(`[ERROR] tRPC call failed for ${e}:`,{message:r instanceof Error?r.message:"Unknown error",stack:r instanceof Error?r.stack:void 0}),r instanceof k&&(o.error(`[DEBUG] tRPC ${e} fetch error details:`,{status:r.response?.status,statusText:r.response?.statusText,headers:r.response?.headers,data:r.response?.data,url:r.config?.url,method:r.config?.method,timeout:r.config?.timeout,cookies:r.config?.headers?.Cookie?"present":"missing"}),r.response?.status===401?o.error("[BLOCKED] tRPC 401 Unauthorized - session may be expired or invalid"):r.response?.status===403?o.error("[BLOCKED] tRPC 403 Forbidden - insufficient permissions"):r.response?.status===404?o.error("[BLOCKED] tRPC 404 Not Found - endpoint may not exist"):r.response?.status&&r.response.status>=500&&o.error("[BLOCKED] tRPC Server Error - N Lobby backend issue"),r.code==="ECONNREFUSED"?o.error("[NETWORK] Network Error: Connection refused - N Lobby may be down"):r.code==="ETIMEDOUT"?o.error("[TIMEOUT] Network Error: Request timeout - slow network or server overload"):r.code==="ENOTFOUND"&&o.error("[NETWORK] Network Error: DNS lookup failed - check internet connection")),r}}buildTRPCUrl(e,t){let n=e,r=JSON.stringify(t||{}),i=new URLSearchParams({input:r}).toString();return`${n}?${i}`}async getUnreadNewsCount(){return this.call("news.getUnreadNewsCount")}async getNotificationMessages(){return this.call("notification.getMessages")}async updateLastAccess(){return this.call("user.updateLastAccess")}async findMainNavigations(){return this.call("menu.findMainNavigations",{})}async readInterestsWithIcon(){return this.call("interest.readInterestsWithIcon")}async readInterests(){return this.call("interest.readInterests")}async readWeights(){return this.call("interest.readWeights")}async getLobbyCalendarEvents(e,t){return this.call("calendar.getLobbyCalendarEvents",{from:e,to:t})}async healthCheck(){o.info("Running tRPC health check...");let e=[{name:"updateLastAccess",method:()=>this.updateLastAccess()},{name:"getUnreadNewsCount",method:()=>this.getUnreadNewsCount()},{name:"findMainNavigations",method:()=>this.findMainNavigations()}];for(let{name:t,method:n}of e)try{return o.debug(`Trying tRPC method: ${t}`),await n(),o.info(`[SUCCESS] tRPC health check passed with method: ${t}`),!0}catch(r){o.debug(`[ERROR] tRPC method ${t} failed:`,r instanceof Error?r.message:"Unknown error");continue}return o.error("[ERROR] All tRPC health check methods failed"),!1}}});async function U(s,e){try{o.info("[NETWORK] Fetching HTML using HTTP client (proven method)..."),o.debug(`[URL] URL: ${m.nlobby.baseUrl+e}`),o.info("[COOKIE] Cookies:",s.httpClient.defaults.headers.Cookie?"present":"missing");let t=await s.httpClient.get(e,{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8","Accept-Language":"ja,en-US;q=0.7,en;q=0.3","Accept-Encoding":"gzip, deflate, br",Connection:"keep-alive","Upgrade-Insecure-Requests":"1","Sec-Fetch-Dest":"document","Sec-Fetch-Mode":"navigate","Sec-Fetch-Site":"none","Cache-Control":"max-age=0","User-Agent":m.userAgent},withCredentials:!0});if(o.info(`[SUCCESS] HTTP response: ${t.status} ${t.statusText}`),o.info(`[DATA] Content length: ${typeof t.data=="string"?t.data.length:"unknown"}`),o.info(`[DATA] Content type: ${t.headers["content-type"]||"unknown"}`),typeof t.data=="string"){let n=t.data,r=n.toLowerCase();if(r.includes("\u30ED\u30B0\u30A4\u30F3")||r.includes("login")?o.warn("[WARNING] WARNING: Page contains login keywords - authentication may have failed"):(r.includes("news")||r.includes("\u304A\u77E5\u3089\u305B"))&&o.info("[SUCCESS] Page appears to contain news content"),r.includes("unauthorized")||r.includes("access denied"))throw new Error("Access denied - authentication failed");return o.info(`[TARGET] HTML retrieved successfully: ${n.length} characters`),n}else throw new Error(`Non-string response received: ${typeof t.data}`)}catch(t){throw o.error("[ERROR] HTTP fetch error:",t instanceof Error?t.message:"Unknown error"),t instanceof k&&o.debug("[DEBUG] HTTP Error Details:",{status:t.response?.status,statusText:t.response?.statusText,url:t.config?.url,hasData:!!t.response?.data}),t}}var X=g(()=>{"use strict";E();b();T()});import*as pe from"cheerio";function _t(s){if(!s)return"";try{return s.replace(/\\u003c/g,"<").replace(/\\u003e/g,">").replace(/\\u0026/g,"&").replace(/\\"/g,'"').replace(/\\\\/g,"\\")}catch{return s}}function ge(s,e=""){if(!s||typeof s!="object")return null;let t=s;if(t.id&&t.title&&(t.publishedAt||t.description||t.menuName))return o.info(`[INFO] Found news object at path: ${e}`),s;if(t.news&&typeof t.news=="object")return o.info(`[INFO] Found news property at path: ${e}.news`),t.news;for(let[n,r]of Object.entries(t))if(r&&typeof r=="object"){let i=e?`${e}.${n}`:n,a=ge(r,i);if(a)return a}return null}function q(s,e=""){if(!s||typeof s!="object")return[];if(Array.isArray(s)){if(s.length>0){let n=s[0];if(n&&typeof n=="object"&&["title","name","content","publishedAt","menuName","createdAt","updatedAt","id"].some(a=>a in n))return o.info(`[INFO] Found potential news array at path: ${e}, length: ${s.length}`),s}return[]}let t=[];for(let[n,r]of Object.entries(s)){let i=["news","announcements","data","items","list","content","notifications","posts","feed","results"],a=e?`${e}.${n}`:n;i.includes(n.toLowerCase())&&o.info(`[INFO] Searching priority key: ${a}`);let c=q(r,a);t.push(...c)}return t}function G(s){return s.map((e,t)=>{let n=e,r=new Date;n.publishedAt?r=new Date(n.publishedAt):n.createdAt?r=new Date(n.createdAt):n.updatedAt?r=new Date(n.updatedAt):n.date&&(r=new Date(n.date));let i=n.title||n.name||n.subject||n.heading||`News Item ${t+1}`,a=n.content||n.description||n.body||n.text||n.summary||"",c=n.category||n.menuName||n.type||n.classification||"General",l="medium";n.isImportant===!0||n.important===!0||n.priority==="high"||n.urgent===!0?l="high":(n.priority==="low"||n.minor===!0)&&(l="low");let u=n.id||t,d=`${m.nlobby.baseUrl}/news/${u}`;return{id:n.id?.toString()||t.toString(),title:i,content:a,publishedAt:r,category:c,priority:l,targetAudience:n.targetAudience||["student"],url:d,menuName:n.menuName,isImportant:!!n.isImportant,isUnread:!!n.isUnread,...Object.fromEntries(Object.entries(n).filter(([w])=>!["id","title","content","publishedAt","category","priority","url"].includes(w)))}})}function Ft(s){try{o.info("[TARGET] Starting Cheerio-based DOM parsing...");let e=pe.load(s),t=e('div[role="presentation"]');if(o.info(`[INFO] Found ${t.length} div[role="presentation"] elements`),t.length<2)return o.info('[WARNING] Less than 2 div[role="presentation"] elements found'),[];let n=e(t[1]);o.info('[SUCCESS] Located second div[role="presentation"] element');let r=n.find('div[role="row"]');o.info(`[INFO] Found ${r.length} DataGrid rows`);let i=[];return r.each((a,c)=>{try{let l=e(c),u=l.attr("data-id");if(!u)return;let d=l.find('div[role="gridcell"]'),h="",w="",y=new Date,S=!1,C=!1,p="";if(d.each((f,L)=>{let R=e(L);switch(R.attr("data-field")){case"title":{let N=R.find("a");if(N.length>0){let x=N.attr("href");x&&x.startsWith("/news/")?p=`${m.nlobby.baseUrl}${x}`:p=`${m.nlobby.baseUrl}/news/${u}`;let le=N.find("span");h=le.length>0?le.text().trim():N.text().trim()}else h=R.text().trim(),p=`${m.nlobby.baseUrl}/news/${u}`;break}case"menuName":w=R.text().trim();break;case"isImportant":{S=R.text().trim().length>0||R.find("*").length>0;break}case"isUnread":{let N=R.text().trim();C=N.includes("\u672A\u8AAD")||N.length>0;break}case"publishedAt":{let N=R.text().trim();if(N){let x=new Date(N.replace(/\//g,"-"));isNaN(x.getTime())||(y=x)}break}}}),h){let f=p||`${m.nlobby.baseUrl}/news/${u}`,L={id:u,title:h,content:"",publishedAt:y,category:w||"General",priority:S?"high":"medium",targetAudience:["student"],url:f,menuName:w,isImportant:S,isUnread:C};i.push(L)}}catch(l){o.error(`[ERROR] Error parsing row ${a}:`,l instanceof Error?l.message:"Unknown error")}}),o.info(`[TARGET] Cheerio parsing completed: ${i.length} news items extracted`),i}catch(e){return o.error("[ERROR] Cheerio parsing failed:",e instanceof Error?e.message:"Unknown error"),[]}}function jt(s){let e=[];try{o.info("[INFO] Starting HTML parsing...");let t=s.match(/self\.__next_f\.push\((\[.*?\])\)/g);if(t&&t.length>0){o.info(`[SUCCESS] Found ${t.length} self.__next_f.push() calls`);for(let i=0;i<t.length;i++){let a=t[i];try{let c=a.match(/self\.__next_f\.push\((\[.*?\])\)/);if(!c)continue;let l=JSON.parse(c[1]);if(l.length>=2&&typeof l[1]=="string"){let d=l[1],h=d.match(/^(\d+):(.*)/);if(h)try{let w=h[2],y=JSON.parse(w);if(Array.isArray(y))for(let S=0;S<y.length;S++){let C=y[S];if(Array.isArray(C)&&C.length>=4&&C[3]&&typeof C[3]=="object"){let p=C[3];if(p.news&&Array.isArray(p.news)&&p.news.length>0){let f=p.news[0];if(f&&typeof f=="object"&&(f.id||f.title||f.microCmsId))return G(p.news)}}}}catch{}else try{let w=JSON.parse(d),y=q(w,`push_call_${i+1}_fallback`);if(y&&y.length>0)return G(y)}catch{}}let u=q(l,`push_call_${i+1}_direct`);if(u&&u.length>0)return G(u)}catch{}}}let n=Ft(s);if(n&&n.length>0)return n;let r=[s.match(/window\.__NEXT_DATA__\s*=\s*({.*?})\s*(?:;|<\/script>)/s),s.match(/<script id="__NEXT_DATA__"[^>]*>([^<]*)<\/script>/s)];for(let i of r)if(i)try{let a=i[1]||i[0],c=JSON.parse(a),l=q(c,"__NEXT_DATA__");if(l&&l.length>0)return G(l)}catch{}}catch(t){o.error("[ERROR] Error parsing news from HTML:",t)}return e}function Mt(s,e){try{let t=s.match(/self\.__next_f\.push\((\[.*?\])\)/g);if(!t||t.length===0)return null;let n=null,r="",i=new Map;for(let c=0;c<t.length;c++){let l=t[c];try{let u=l.match(/self\.__next_f\.push\((\[.*?\])\)/);if(!u)continue;let d=JSON.parse(u[1]);if(d.length>=2&&typeof d[1]=="string"&&d[1].match(/^\d+:T\d+,?$/)){let h=d[1].replace(/,$/,"");if(c+1<t.length){let y=t[c+1].match(/self\.__next_f\.push\((\[.*?\])\)/);if(y){let S=JSON.parse(y[1]);S.length>=2&&typeof S[1]=="string"&&i.set(h,S[1])}}continue}if(d.length>=2&&typeof d[1]=="string"){let w=d[1].match(/^(\d+):(.*)/);if(w)try{let y=w[2],S=JSON.parse(y),C=ge(S);C&&(n=C)}catch{}}}catch{}}if(!n)return null;if(n.description){for(let[c,l]of i)if(n.description.includes(c)){r=l;break}}return!r&&i.size>0&&(r=Array.from(i.values())[0]),{id:n.id||e,microCmsId:n.microCmsId,title:n.title||"No Title",content:_t(r)||n.description||"",description:n.description,publishedAt:n.publishedAt?new Date(n.publishedAt):new Date,menuName:n.menuName||[],isImportant:n.isImportant||!1,isByMentor:n.isByMentor||!1,attachments:n.attachments||[],relatedEvents:n.relatedEvents||[],targetUserQueryId:n.targetUserQueryId,url:`${m.nlobby.baseUrl}/news/${e}`}}catch(t){return o.error("[ERROR] Error parsing news detail from HTML:",t),null}}async function me(s){o.info("[INFO] Starting getNews with HTTP client..."),o.info("[STATUS] Current authentication status:",s.getCookieStatus());try{let e=await U(s,"/news"),t=jt(e);if(t&&t.length>0)return o.info(`[SUCCESS] Retrieved ${t.length} news items from HTML`),t;{let n=`HTML scraping returned no data. Debug info:
|
|
3
|
+
- Authentication status: ${s.nextAuth.isAuthenticated()?"authenticated":"not authenticated"}
|
|
4
|
+
- HTTP cookies: ${s.httpClient.defaults.headers.Cookie?"present":"missing"}
|
|
5
5
|
- HTML length: ${e.length} characters
|
|
6
6
|
|
|
7
7
|
Troubleshooting steps:
|
|
8
8
|
1. Run 'health_check' to verify connection
|
|
9
|
-
2. Ensure you are properly authenticated using 'set_cookies'`;throw new Error(n)}}catch(e){throw i.error("[ERROR] getNews failed:",e),e instanceof Error?e:new Error(`Failed to fetch news: ${e instanceof Error?e.message:"Unknown error"}`)}}async function pe(o,e){i.info(`[INFO] Fetching news detail for ID: ${e}`);try{let t=`/news/${e}`,n=await v(o,t),r=_t(n,e);if(r)return r;throw new Error(`Failed to parse news detail from HTML for news ID: ${e}`)}catch(t){throw i.error(`[ERROR] getNewsDetail failed for ID ${e}:`,t),t instanceof Error?t:new Error(`Failed to fetch news detail for ID ${e}: ${t instanceof Error?t.message:"Unknown error"}`)}}async function ge(o,e){i.info(`[INFO] Marking news article ${e} as read`);try{let t=await o.httpClient.post("/api/trpc/news.upsertBrowsingHistory",`"${e}"`,{headers:{"Content-Type":"application/json",Authorization:o.nextAuth.getCookieHeader(),Referer:`https://nlobby.nnn.ed.jp/news/${e}`}});return i.info(`[SUCCESS] News article ${e} marked as read`),t.data}catch(t){throw i.error(`[ERROR] Failed to mark news ${e} as read:`,t),t}}async function me(o){i.info("[INFO] Fetching unread news info...");try{let e=await o.trpcClient.call("news.getUnreadNewsInfo");return i.info("[SUCCESS] getUnreadNewsInfo succeeded"),e}catch(e){throw i.error("[ERROR] getUnreadNewsInfo failed:",e),e}}var he=p(()=>{"use strict";Y();S();m()});var G={};P(G,{CalendarType:()=>M});var M,R=p(()=>{"use strict";M=(t=>(t.PERSONAL="personal",t.SCHOOL="school",t))(M||{})});function K(){let o=new Date,e=new Date(o);e.setHours(0,0,0,0);let t=new Date(o);return t.setDate(t.getDate()+7),t.setHours(23,59,59,999),{from:e,to:t}}function Ft(o){return o.map(e=>{let t=e,n,r;t.startDateTime?(n=new Date(t.startDateTime),r=t.endDateTime?new Date(t.endDateTime):new Date(n.getTime()+3600*1e3)):t.start?(t.start.dateTime?n=new Date(t.start.dateTime):t.start.date?n=new Date(t.start.date+"T00:00:00"):n=new Date,t.end&&t.end.dateTime?r=new Date(t.end.dateTime):t.end&&t.end.date?(r=new Date(t.end.date+"T23:59:59"),r.setDate(r.getDate()-1)):r=new Date(n.getTime()+3600*1e3)):(n=new Date,r=new Date(n.getTime()+3600*1e3));let s="event",a=(t.summary||"").toLowerCase();a.includes("\u6388\u696D")||a.includes("class")?s="class":a.includes("mtg")||a.includes("\u30DF\u30FC\u30C6\u30A3\u30F3\u30B0")||a.includes("meeting")||a.includes("\u9762\u8AC7")?s="meeting":(a.includes("\u8A66\u9A13")||a.includes("exam")||a.includes("\u30C6\u30B9\u30C8"))&&(s="exam");let c=[];return t.attendees&&Array.isArray(t.attendees)&&(c=t.attendees.map(u=>u.email).filter(Boolean)),{id:t.id||t.microCmsId||Math.random().toString(),title:t.summary||t.title||"No Title",description:t.description||"",startTime:n,endTime:r,location:t.location||"",type:s,participants:c}})}async function D(o,e,t){let{CalendarType:n}=await Promise.resolve().then(()=>(R(),G));try{i.info(`[INFO] Fetching Google Calendar events for ${e}...`);let r=K(),s=t||r;i.info(`[INFO] Date range: ${s.from.toISOString()} to ${s.to.toISOString()}`);let a=e===n.PERSONAL?"/api/trpc/calendar.getGoogleCalendarEvents":"/api/trpc/calendar.getLobbyCalendarEvents",c={from:s.from.toISOString(),to:s.to.toISOString()},l=await o.httpClient.get(a,{params:{input:JSON.stringify(c)},headers:{Accept:"application/json","Content-Type":"application/json"},withCredentials:!0}),u=[],d=l.data;if(d?.result?.data?.gcal)u=d.result.data.gcal;else if(d?.result?.data?.lcal)u=d.result.data.lcal;else if(d?.result?.data&&Array.isArray(d.result.data))u=d.result.data;else if(d?.data?.gcal)u=d.data.gcal;else if(d?.data&&Array.isArray(d.data))u=d.data;else if(d?.gcal)u=d.gcal;else if(Array.isArray(d))u=d;else throw new Error(`Invalid calendar response format for ${e} calendar.`);if(!Array.isArray(u))throw new Error(`Calendar events is not an array: ${typeof u}`);return u}catch(r){throw i.error("[ERROR] Error fetching Google Calendar events:",r),r&&typeof r=="object"&&"response"in r&&r.response?.status===401?new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby."):r}}async function V(o,e,t){try{i.info(`[INFO] Fetching ${e} calendar events...`);let n=await D(o,e,t),r=Ft(n);return i.info(`[SUCCESS] Retrieved ${r.length} schedule items`),r}catch(n){throw i.error("[ERROR] Error fetching schedule:",n),new Error(`Failed to fetch ${e} calendar: ${n instanceof Error?n.message:"Unknown error"}`)}}async function fe(o,e){let{CalendarType:t}=await Promise.resolve().then(()=>(R(),G)),n;if(e){let r=new Date(e);if(isNaN(r.getTime()))throw new Error(`Invalid date format: ${e}`);let s=new Date(r);s.setHours(0,0,0,0);let a=new Date(r);a.setHours(23,59,59,999),n={from:s,to:a}}else n=K();return V(o,t.PERSONAL,n)}async function ye(o,e){let{CalendarType:t}=await Promise.resolve().then(()=>(R(),G)),n=e||K(),r={personal:{success:!1,count:0},school:{success:!1,count:0}};try{let s=await D(o,t.PERSONAL,n);r.personal.success=!0,r.personal.count=s.length}catch(s){r.personal.error=s instanceof Error?s.message:"Unknown error"}try{let s=await D(o,t.SCHOOL,n);r.school.success=!0,r.school.count=s.length}catch(s){r.school.error=s instanceof Error?s.message:"Unknown error"}return r}async function we(o){i.info("[INFO] Fetching lobby calendar filters...");try{let e=await o.trpcClient.call("calendar.getLobbyCalendarFilters",{});return i.info("[SUCCESS] getLobbyCalendarFilters succeeded"),e&&typeof e=="object"&&"result"in e?e.result?.filter||[]:Array.isArray(e)?e:[]}catch(e){throw i.error("[ERROR] getLobbyCalendarFilters failed:",e),e}}function be(o,e){let t=typeof o=="string"?new Date(o):o,n=typeof e=="string"?new Date(e):e;if(isNaN(t.getTime())||isNaN(n.getTime()))throw new Error("Invalid date format provided");if((n.getTime()-t.getTime())/(1e3*60*60*24)<1)throw new Error('To date must be at least 1 day after from date. For single day queries, use period="today" or single from_date parameter.');return{from:t,to:n}}function Ce(o){let e=typeof o=="string"?new Date(o):o;if(isNaN(e.getTime()))throw new Error("Invalid date format provided");let t=new Date(e);t.setHours(0,0,0,0);let n=new Date(e);return n.setHours(23,59,59,999),{from:t,to:n}}function ke(o){let e=o?typeof o=="string"?new Date(o):o:new Date;e.setHours(0,0,0,0);let t=new Date(e);return t.setDate(t.getDate()+6),t.setHours(23,59,59,999),{from:e,to:t}}function Se(o,e){let t=new Date,n=o||t.getFullYear(),r=e!==void 0?e:t.getMonth(),s=new Date(n,r,1,0,0,0,0),a=new Date(n,r+1,0,23,59,59,999);return{from:s,to:a}}var xe=p(()=>{"use strict";m()});function Ne(o,e=""){if(!o||typeof o!="object")return null;if(o.educationProcessName&&o.termYears&&Array.isArray(o.termYears))return i.info(`[INFO] Found education data at path: ${e}`),o;for(let[t,n]of Object.entries(o))if(n&&typeof n=="object"){let r=e?`${e}.${t}`:t,s=Ne(n,r);if(s)return s}return null}function jt(o){return o.allCount===0?0:Math.round(o.count/o.allCount*100)}function Mt(o){let e=o.filter(n=>n.score!==null&&n.progress===100);if(e.length===0)return null;let t=e.reduce((n,r)=>n+(r.score||0),0);return Math.round(t/e.length)}function Gt(o){let e=[];for(let t of o.termYears)for(let n of t.courses){let r=jt(n.report),s=Mt(n.reportDetails),a=n.acquired.acquisitionStatus===1,c=n.subjectStatus===1||n.subjectStatus===2,l={...n,termYear:t.termYear,grade:t.grade,term:t.term,progressPercentage:r,averageScore:s,isCompleted:a,isInProgress:c};e.push(l)}return e}async function Ee(o){i.info("[INFO] Starting getRequiredCourses...");try{let e=await o.trpcClient.call("requiredCourse.getRequiredCourses"),t=null,n=e;if(n&&n.result&&n.result.data)t=n.result.data;else if(n&&n.data)t=n.data;else if(n&&n.educationProcessName&&n.termYears)t=n;else{if(n&&Array.isArray(n))return n;if(n){let r=Ne(n);r&&(t=r)}}if(t){let r=Gt(t);return i.info(`[SUCCESS] Total courses extracted: ${r.length}`),r}else throw new Error("Unexpected response format from required courses endpoint.")}catch(e){throw i.error("[ERROR] getRequiredCourses failed:",e),e instanceof Error?e:new Error(`Failed to fetch required courses: ${e instanceof Error?e.message:"Unknown error"}`)}}async function Re(o,e){try{let t=e?{subject:e}:{},n=await o.httpClient.get("/api/learning-resources",{params:t});if(!n.data.success)throw new Error(n.data.error||"Failed to fetch learning resources");return n.data.data||[]}catch(t){throw i.error("Error fetching learning resources:",t),new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby.")}}async function Ae(o,e){i.info("[INFO] Checking if date is exam day...");let n=(e||new Date).toISOString();try{let r=await o.trpcClient.call("exam.isExamDay",n);return i.info(`[SUCCESS] isExamDay result: ${r}`),r===!0}catch(r){throw i.error("[ERROR] isExamDay failed:",r),r}}async function Te(o){i.info("[INFO] Finishing exam day mode...");try{let e=await o.httpClient.post("/api/trpc/exam.finishExamDayMode","{}",{headers:{"Content-Type":"application/json",Cookie:o.nextAuth.getCookieHeader()}});return i.info("[SUCCESS] finishExamDayMode succeeded"),e.data?.result?.data===!0}catch(e){throw i.error("[ERROR] finishExamDayMode failed:",e),e}}async function ve(o){i.info("[INFO] Fetching exam one-time password...");try{let e=await o.trpcClient.call("auth.student.examOneTimePasswordDisplay");return i.info("[SUCCESS] getExamOneTimePassword succeeded"),e}catch(e){throw i.error("[ERROR] getExamOneTimePassword failed:",e),e}}var De=p(()=>{"use strict";m()});import Ie from"node:fs/promises";import Ht from"node:os";import Le from"node:path";import Ue from"puppeteer";function qt(o){if(typeof o!="string"||o.length===0)return null;let e=o.trim(),t=e.indexOf(":");if(t>0&&t<20){let r=e.slice(0,t);/^[a-z0-9]+$/i.test(r)&&(e=e.slice(t+1))}e=e.trim();let n=e.replace(/"/g,'"').replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&");try{return JSON.parse(n)}catch{return null}}function I(o,e){if(o==null)return null;if(typeof o=="string"){let t=qt(o);return t?I(t,e):null}if(Array.isArray(o)){let t=o;if(e.has(t))return null;e.add(t);for(let n of o){let r=I(n,e);if(r)return r}return null}if(typeof o=="object"){let t=o;if(e.has(t))return null;if(e.add(t),Object.prototype.hasOwnProperty.call(t,"session")&&t.session&&typeof t.session=="object")return t.session;for(let n of Object.values(t)){let r=I(n,e);if(r)return r}}return null}function Bt(o){let e=/self\.__next_f\.push\((\[[\s\S]*?\])\)/g,t;for(;(t=e.exec(o))!==null;){let r=t[1];if(r)try{let s=JSON.parse(r),a=I(s,new WeakSet);if(a)return i.info("[SUCCESS] Found session data in Next.js flight payload"),a}catch{}}let n=[/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/,/window\.__NEXT_DATA__\s*=\s*({[\s\S]*?})(?:;|\s*<\/script>)/];for(let r of n){let s=o.match(r);if(!(!s||!s[1]))try{let a=JSON.parse(s[1]),c=I(a,new WeakSet);if(c)return i.info("[SUCCESS] Found session data in __NEXT_DATA__ payload"),c}catch{}}return null}function Wt(o){let e=o.user??{},t=e.kmsLogin??{},n=t.content??{},r;return typeof e.image=="string"?r=e.image!=="$undefined"?e.image:null:e.image===null&&(r=null),{name:typeof e.name=="string"?e.name:null,email:typeof e.email=="string"?e.email:null,role:typeof e.role=="string"?e.role:null,image:r,userId:typeof n.userId=="string"?n.userId:void 0,studentNo:typeof n.studentNo=="string"?n.studentNo:void 0,schoolCorporationType:typeof n.schoolCorporationType=="number"?n.schoolCorporationType:void 0,grade:typeof n.grade=="number"?n.grade:void 0,term:typeof n.term=="number"?n.term:void 0,isLobbyAdmin:typeof n.isLobbyAdmin=="boolean"?n.isLobbyAdmin:void 0,firstLoginFlg:typeof n.firstLoginFlg=="number"?n.firstLoginFlg:void 0,kmsLoginSuccess:typeof t.success=="boolean"?t.success:void 0,staffDepartments:Array.isArray(n.staffDepartments)?n.staffDepartments:void 0,studentOrganizations:Array.isArray(n.studentOrganizations)?n.studentOrganizations:void 0,rawSession:o}}function zt(o){let e=o.charAt(2)?.toUpperCase();return!e||e==="N"||!/[A-Z]/.test(e)?"secure.nnn.ed.jp":`${e.toLowerCase()}-secure.nnn.ed.jp`}function Jt(o,e){let t=[];for(let n of o.split(";")){let r=n.trim();if(!r)continue;let s=r.indexOf("=");if(s<=0)continue;let a=r.slice(0,s),c=r.slice(s+1);t.push({name:a,value:c,domain:e,path:"/",secure:!0,httpOnly:a.startsWith("__Secure-")||a.startsWith("__Host-")||a.toLowerCase().includes("session"),sameSite:"Lax"})}return t}async function Yt(){let o=["--no-sandbox","--disable-setuid-sandbox"],e=[process.env.PUPPETEER_EXECUTABLE_PATH,process.env.CHROME_PATH].filter(c=>!!c&&c.trim().length>0);for(let c of e)try{return await Ue.launch({headless:!0,executablePath:c,args:o})}catch{}let t=[],n=async(c,l)=>{try{return i.info(`[STUDENT_CARD] Trying browser launch via ${l}`),await Ue.launch(c)}catch(u){return u instanceof Error&&t.push(u),null}},r=await n({headless:!0,args:o},"default Puppeteer bundle");if(r)return r;let s=await n({headless:!0,channel:"chrome",args:o},"system Chrome channel");if(s)return s;let a=t.map(c=>c.message).join(`
|
|
9
|
+
2. Ensure you are properly authenticated using 'set_cookies'`;throw new Error(n)}}catch(e){throw o.error("[ERROR] getNews failed:",e),e instanceof Error?e:new Error(`Failed to fetch news: ${e instanceof Error?e.message:"Unknown error"}`)}}async function he(s,e){o.info(`[INFO] Fetching news detail for ID: ${e}`);try{let t=`/news/${e}`,n=await U(s,t),r=Mt(n,e);if(r)return r;throw new Error(`Failed to parse news detail from HTML for news ID: ${e}`)}catch(t){throw o.error(`[ERROR] getNewsDetail failed for ID ${e}:`,t),t instanceof Error?t:new Error(`Failed to fetch news detail for ID ${e}: ${t instanceof Error?t.message:"Unknown error"}`)}}async function fe(s,e){o.info(`[INFO] Marking news article ${e} as read`);try{let t=await s.httpClient.post("/api/trpc/news.upsertBrowsingHistory",`"${e}"`,{headers:{"Content-Type":"application/json",Authorization:s.nextAuth.getCookieHeader(),Referer:`https://nlobby.nnn.ed.jp/news/${e}`}});return o.info(`[SUCCESS] News article ${e} marked as read`),t.data}catch(t){throw o.error(`[ERROR] Failed to mark news ${e} as read:`,t),t}}async function ye(s){o.info("[INFO] Fetching unread news info...");try{let e=await s.trpcClient.call("news.getUnreadNewsInfo");return o.info("[SUCCESS] getUnreadNewsInfo succeeded"),e}catch(e){throw o.error("[ERROR] getUnreadNewsInfo failed:",e),e}}var we=g(()=>{"use strict";X();E();b()});var W={};F(W,{CalendarType:()=>B});var B,v=g(()=>{"use strict";B=(t=>(t.PERSONAL="personal",t.SCHOOL="school",t))(B||{})});function Q(){let s=new Date,e=new Date(s);e.setHours(0,0,0,0);let t=new Date(s);return t.setDate(t.getDate()+7),t.setHours(23,59,59,999),{from:e,to:t}}function Ht(s){return s.map(e=>{let t=e,n,r;t.startDateTime?(n=new Date(t.startDateTime),r=t.endDateTime?new Date(t.endDateTime):new Date(n.getTime()+3600*1e3)):t.start?(t.start.dateTime?n=new Date(t.start.dateTime):t.start.date?n=new Date(t.start.date+"T00:00:00"):n=new Date,t.end&&t.end.dateTime?r=new Date(t.end.dateTime):t.end&&t.end.date?(r=new Date(t.end.date+"T23:59:59"),r.setDate(r.getDate()-1)):r=new Date(n.getTime()+3600*1e3)):(n=new Date,r=new Date(n.getTime()+3600*1e3));let i="event",a=(t.summary||"").toLowerCase();a.includes("\u6388\u696D")||a.includes("class")?i="class":a.includes("mtg")||a.includes("\u30DF\u30FC\u30C6\u30A3\u30F3\u30B0")||a.includes("meeting")||a.includes("\u9762\u8AC7")?i="meeting":(a.includes("\u8A66\u9A13")||a.includes("exam")||a.includes("\u30C6\u30B9\u30C8"))&&(i="exam");let c=[];return t.attendees&&Array.isArray(t.attendees)&&(c=t.attendees.map(u=>u.email).filter(Boolean)),{id:t.id||t.microCmsId||Math.random().toString(),title:t.summary||t.title||"No Title",description:t.description||"",startTime:n,endTime:r,location:t.location||"",type:i,participants:c}})}async function P(s,e,t){let{CalendarType:n}=await Promise.resolve().then(()=>(v(),W));try{o.info(`[INFO] Fetching Google Calendar events for ${e}...`);let r=Q(),i=t||r;o.info(`[INFO] Date range: ${i.from.toISOString()} to ${i.to.toISOString()}`);let a=e===n.PERSONAL?"/api/trpc/calendar.getGoogleCalendarEvents":"/api/trpc/calendar.getLobbyCalendarEvents",c={from:i.from.toISOString(),to:i.to.toISOString()},l=await s.httpClient.get(a,{params:{input:JSON.stringify(c)},headers:{Accept:"application/json","Content-Type":"application/json"},withCredentials:!0}),u=[],d=l.data;if(d?.result?.data?.gcal)u=d.result.data.gcal;else if(d?.result?.data?.lcal)u=d.result.data.lcal;else if(d?.result?.data&&Array.isArray(d.result.data))u=d.result.data;else if(d?.data?.gcal)u=d.data.gcal;else if(d?.data&&Array.isArray(d.data))u=d.data;else if(d?.gcal)u=d.gcal;else if(Array.isArray(d))u=d;else throw new Error(`Invalid calendar response format for ${e} calendar.`);if(!Array.isArray(u))throw new Error(`Calendar events is not an array: ${typeof u}`);return u}catch(r){throw o.error("[ERROR] Error fetching Google Calendar events:",r),r instanceof k&&r.response?.status===401?new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby."):r}}async function Z(s,e,t){try{o.info(`[INFO] Fetching ${e} calendar events...`);let n=await P(s,e,t),r=Ht(n);return o.info(`[SUCCESS] Retrieved ${r.length} schedule items`),r}catch(n){throw o.error("[ERROR] Error fetching schedule:",n),new Error(`Failed to fetch ${e} calendar: ${n instanceof Error?n.message:"Unknown error"}`)}}async function be(s,e){let{CalendarType:t}=await Promise.resolve().then(()=>(v(),W)),n;if(e){let r=new Date(e);if(isNaN(r.getTime()))throw new Error(`Invalid date format: ${e}`);let i=new Date(r);i.setHours(0,0,0,0);let a=new Date(r);a.setHours(23,59,59,999),n={from:i,to:a}}else n=Q();return Z(s,t.PERSONAL,n)}async function Ce(s,e){let{CalendarType:t}=await Promise.resolve().then(()=>(v(),W)),n=e||Q(),r={personal:{success:!1,count:0},school:{success:!1,count:0}};try{let i=await P(s,t.PERSONAL,n);r.personal.success=!0,r.personal.count=i.length}catch(i){r.personal.error=i instanceof Error?i.message:"Unknown error"}try{let i=await P(s,t.SCHOOL,n);r.school.success=!0,r.school.count=i.length}catch(i){r.school.error=i instanceof Error?i.message:"Unknown error"}return r}async function ke(s){o.info("[INFO] Fetching lobby calendar filters...");try{let e=await s.trpcClient.call("calendar.getLobbyCalendarFilters",{});return o.info("[SUCCESS] getLobbyCalendarFilters succeeded"),e&&typeof e=="object"&&"result"in e?e.result?.filter||[]:Array.isArray(e)?e:[]}catch(e){throw o.error("[ERROR] getLobbyCalendarFilters failed:",e),e}}function Se(s,e){let t=typeof s=="string"?new Date(s):s,n=typeof e=="string"?new Date(e):e;if(isNaN(t.getTime())||isNaN(n.getTime()))throw new Error("Invalid date format provided");if((n.getTime()-t.getTime())/(1e3*60*60*24)<1)throw new Error('To date must be at least 1 day after from date. For single day queries, use period="today" or single from_date parameter.');return{from:t,to:n}}function Re(s){let e=typeof s=="string"?new Date(s):s;if(isNaN(e.getTime()))throw new Error("Invalid date format provided");let t=new Date(e);t.setHours(0,0,0,0);let n=new Date(e);return n.setHours(23,59,59,999),{from:t,to:n}}function Ne(s){let e=s?typeof s=="string"?new Date(s):s:new Date;e.setHours(0,0,0,0);let t=new Date(e);return t.setDate(t.getDate()+6),t.setHours(23,59,59,999),{from:e,to:t}}function Ee(s,e){let t=new Date,n=s||t.getFullYear(),r=e!==void 0?e:t.getMonth(),i=new Date(n,r,1,0,0,0,0),a=new Date(n,r+1,0,23,59,59,999);return{from:i,to:a}}var xe=g(()=>{"use strict";b();T()});function Ae(s,e=""){if(!s||typeof s!="object")return null;if(s.educationProcessName&&s.termYears&&Array.isArray(s.termYears))return o.info(`[INFO] Found education data at path: ${e}`),s;for(let[t,n]of Object.entries(s))if(n&&typeof n=="object"){let r=e?`${e}.${t}`:t,i=Ae(n,r);if(i)return i}return null}function Gt(s){return s.allCount===0?0:Math.round(s.count/s.allCount*100)}function qt(s){let e=s.filter(n=>n.score!==null&&n.progress===100);if(e.length===0)return null;let t=e.reduce((n,r)=>n+(r.score||0),0);return Math.round(t/e.length)}function Bt(s){let e=[];for(let t of s.termYears)for(let n of t.courses){let r=Gt(n.report),i=qt(n.reportDetails),a=n.acquired.acquisitionStatus===1,c=n.subjectStatus===1||n.subjectStatus===2,l={...n,termYear:t.termYear,grade:t.grade,term:t.term,progressPercentage:r,averageScore:i,isCompleted:a,isInProgress:c};e.push(l)}return e}async function Te(s){o.info("[INFO] Starting getRequiredCourses...");try{let e=await s.trpcClient.call("requiredCourse.getRequiredCourses"),t=null,n=e;if(n&&n.result&&n.result.data)t=n.result.data;else if(n&&n.data)t=n.data;else if(n&&n.educationProcessName&&n.termYears)t=n;else{if(n&&Array.isArray(n))return n;if(n){let r=Ae(n);r&&(t=r)}}if(t){let r=Bt(t);return o.info(`[SUCCESS] Total courses extracted: ${r.length}`),r}else throw new Error("Unexpected response format from required courses endpoint.")}catch(e){throw o.error("[ERROR] getRequiredCourses failed:",e),e instanceof Error?e:new Error(`Failed to fetch required courses: ${e instanceof Error?e.message:"Unknown error"}`)}}async function ve(s,e){try{let t=e?{subject:e}:{},n=await s.httpClient.get("/api/learning-resources",{params:t});if(!n.data.success)throw new Error(n.data.error||"Failed to fetch learning resources");return n.data.data||[]}catch(t){throw o.error("Error fetching learning resources:",t),new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby.")}}async function De(s,e){o.info("[INFO] Checking if date is exam day...");let n=(e||new Date).toISOString();try{let r=await s.trpcClient.call("exam.isExamDay",n);return o.info(`[SUCCESS] isExamDay result: ${r}`),r===!0}catch(r){throw o.error("[ERROR] isExamDay failed:",r),r}}async function Ie(s){o.info("[INFO] Finishing exam day mode...");try{let e=await s.httpClient.post("/api/trpc/exam.finishExamDayMode","{}",{headers:{"Content-Type":"application/json",Cookie:s.nextAuth.getCookieHeader()}});return o.info("[SUCCESS] finishExamDayMode succeeded"),e.data?.result?.data===!0}catch(e){throw o.error("[ERROR] finishExamDayMode failed:",e),e}}async function Le(s){o.info("[INFO] Fetching exam one-time password...");try{let e=await s.trpcClient.call("auth.student.examOneTimePasswordDisplay");return o.info("[SUCCESS] getExamOneTimePassword succeeded"),e}catch(e){throw o.error("[ERROR] getExamOneTimePassword failed:",e),e}}var Ue=g(()=>{"use strict";b()});import Pe from"node:fs/promises";import Wt from"node:os";import Oe from"node:path";import $e from"puppeteer";function zt(s){if(typeof s!="string"||s.length===0)return null;let e=s.trim(),t=e.indexOf(":");if(t>0&&t<20){let r=e.slice(0,t);/^[a-z0-9]+$/i.test(r)&&(e=e.slice(t+1))}e=e.trim();let n=e.replace(/"/g,'"').replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&");try{return JSON.parse(n)}catch{return null}}function O(s,e){if(s==null)return null;if(typeof s=="string"){let t=zt(s);return t?O(t,e):null}if(Array.isArray(s)){let t=s;if(e.has(t))return null;e.add(t);for(let n of s){let r=O(n,e);if(r)return r}return null}if(typeof s=="object"){let t=s;if(e.has(t))return null;if(e.add(t),Object.prototype.hasOwnProperty.call(t,"session")&&t.session&&typeof t.session=="object")return t.session;for(let n of Object.values(t)){let r=O(n,e);if(r)return r}}return null}function Jt(s){let e=/self\.__next_f\.push\((\[[\s\S]*?\])\)/g,t;for(;(t=e.exec(s))!==null;){let r=t[1];if(r)try{let i=JSON.parse(r),a=O(i,new WeakSet);if(a)return o.info("[SUCCESS] Found session data in Next.js flight payload"),a}catch{}}let n=[/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/,/window\.__NEXT_DATA__\s*=\s*({[\s\S]*?})(?:;|\s*<\/script>)/];for(let r of n){let i=s.match(r);if(!(!i||!i[1]))try{let a=JSON.parse(i[1]),c=O(a,new WeakSet);if(c)return o.info("[SUCCESS] Found session data in __NEXT_DATA__ payload"),c}catch{}}return null}function Yt(s){let e=s.user??{},t=e.kmsLogin??{},n=t.content??{},r;return typeof e.image=="string"?r=e.image!=="$undefined"?e.image:null:e.image===null&&(r=null),{name:typeof e.name=="string"?e.name:null,email:typeof e.email=="string"?e.email:null,role:typeof e.role=="string"?e.role:null,image:r,userId:typeof n.userId=="string"?n.userId:void 0,studentNo:typeof n.studentNo=="string"?n.studentNo:void 0,schoolCorporationType:typeof n.schoolCorporationType=="number"?n.schoolCorporationType:void 0,grade:typeof n.grade=="number"?n.grade:void 0,term:typeof n.term=="number"?n.term:void 0,isLobbyAdmin:typeof n.isLobbyAdmin=="boolean"?n.isLobbyAdmin:void 0,firstLoginFlg:typeof n.firstLoginFlg=="number"?n.firstLoginFlg:void 0,kmsLoginSuccess:typeof t.success=="boolean"?t.success:void 0,staffDepartments:Array.isArray(n.staffDepartments)?n.staffDepartments:void 0,studentOrganizations:Array.isArray(n.studentOrganizations)?n.studentOrganizations:void 0,rawSession:s}}function Kt(s){let e=s.charAt(2)?.toUpperCase();return!e||e==="N"||!/[A-Z]/.test(e)?"secure.nnn.ed.jp":`${e.toLowerCase()}-secure.nnn.ed.jp`}function Vt(s,e){let t=[];for(let n of s.split(";")){let r=n.trim();if(!r)continue;let i=r.indexOf("=");if(i<=0)continue;let a=r.slice(0,i),c=r.slice(i+1);t.push({name:a,value:c,domain:e,path:"/",secure:!0,httpOnly:a.startsWith("__Secure-")||a.startsWith("__Host-")||a.toLowerCase().includes("session"),sameSite:"Lax"})}return t}async function Xt(){let s=["--no-sandbox","--disable-setuid-sandbox"],e=[process.env.PUPPETEER_EXECUTABLE_PATH,process.env.CHROME_PATH].filter(c=>!!c&&c.trim().length>0);for(let c of e)try{return await $e.launch({headless:!0,executablePath:c,args:s})}catch{}let t=[],n=async(c,l)=>{try{return o.info(`[STUDENT_CARD] Trying browser launch via ${l}`),await $e.launch(c)}catch(u){return u instanceof Error&&t.push(u),null}},r=await n({headless:!0,args:s},"default Puppeteer bundle");if(r)return r;let i=await n({headless:!0,channel:"chrome",args:s},"system Chrome channel");if(i)return i;let a=t.map(c=>c.message).join(`
|
|
10
10
|
`);throw new Error(`Failed to launch a browser instance for screenshot capture. Please install Chrome via "npx puppeteer browsers install chrome".
|
|
11
|
-
${a}`)}async function
|
|
12
|
-
`)}async function
|
|
11
|
+
${a}`)}async function Qt(s){o.info("[STUDENT_CARD] Launching headless browser for student card capture");let e=await Xt();try{let t=await e.newPage();await t.setViewport({width:1280,height:720}),await t.setUserAgent(m.userAgent),s.cookies.length>0&&await t.setCookie(...s.cookies),await t.goto(s.startUrl,{waitUntil:"networkidle2",timeout:6e4}),await t.waitForSelector(s.waitForSelector,{timeout:6e4}),await new Promise(u=>setTimeout(u,1e3));let n=await t.$(s.waitForSelector);if(!n)throw new Error(`Failed to locate element ${s.waitForSelector} for screenshot`);let r=await n.screenshot({type:"png"}),i=Oe.join(Wt.tmpdir(),"nlobby-student-card");await Pe.mkdir(i,{recursive:!0});let a=Oe.join(i,s.screenshotName);await Pe.writeFile(a,r);let c=await n.boundingBox(),l=c?{width:Math.round(c.width),height:Math.round(c.height)}:void 0;return{base64:r.toString("base64"),path:a,finalUrl:t.url(),elementSize:l}}finally{await e.close()}}async function _e(s){try{let e=await s.httpClient.get("/api/user");if(!e.data.success)throw new Error(e.data.error||"Failed to fetch user info");return e.data.data}catch(e){throw o.error("Error fetching user info:",e),new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby.")}}async function ee(s,e="/"){o.info(`[INFO] Extracting account information from Next.js script at ${e}`);try{let t=await U(s,e),n=Jt(t);if(!n)throw new Error("Could not locate session data in Next.js flight scripts. Authentication might be required or the page structure may have changed.");let r=Yt(n);return o.info("[SUCCESS] Account information extracted successfully"),r}catch(t){throw o.error("Error extracting account info from script:",t),new Error(`Failed to extract account information: ${t instanceof Error?t.message:"Unknown error"}`)}}async function Fe(s){let t=(await ee(s,"/")).studentNo;if(!t||t.length<3)throw new Error("Student number is missing from account information. Ensure you are authenticated and try again.");let n=Kt(t),r=`https://${n}/mypage/student_card/index`,i=`https://nlobby.nnn.ed.jp/mypage/v1/callback?redirect_uri=${encodeURIComponent(r)}`,a=s.httpClient.defaults.headers.Cookie;if(!a)throw new Error("Authentication cookies are not set. Use the set_cookies tool or interactive_login first.");let c=Vt(a,"nlobby.nnn.ed.jp");if(c.length===0)throw new Error("Failed to parse authentication cookies for browser session.");let l=await Qt({startUrl:i,waitForSelector:"#main",screenshotName:`student-card-${Date.now()}.png`,cookies:c});return{base64:l.base64,path:l.path,studentNo:t,secureHost:n,callbackUrl:i,finalUrl:l.finalUrl,elementSize:l.elementSize}}async function je(s){o.info("[INFO] Updating last access...");try{return await s.httpClient.post("/api/trpc/user.updateLastAccess","{}",{headers:{"Content-Type":"application/json",Cookie:s.nextAuth.getCookieHeader()}}),o.info("[SUCCESS] updateLastAccess succeeded"),!0}catch(e){throw o.error("[ERROR] updateLastAccess failed:",e),e}}var Me=g(()=>{"use strict";X();E();b()});async function He(s){o.info("[INFO] Fetching main navigations...");try{let e=await s.trpcClient.call("menu.findMainNavigations",{});return o.info("[SUCCESS] getMainNavigations succeeded"),e&&typeof e=="object"&&"menus"in e?e.menus||[]:Array.isArray(e)?e:[]}catch(e){throw o.error("[ERROR] getMainNavigations failed:",e),e}}async function Ge(s){o.info("[INFO] Fetching notification messages...");try{let e=await s.trpcClient.call("notification.getMessages");return o.info("[SUCCESS] getNotificationMessages succeeded"),Array.isArray(e)?e:[]}catch(e){throw o.error("[ERROR] getNotificationMessages failed:",e),e}}async function qe(s,e=!1){let t=e?"interest.readInterestsWithIcon":"interest.readInterests";o.info(`[INFO] Fetching user interests (${t})...`);try{let n=await s.trpcClient.call(t);return o.info("[SUCCESS] getUserInterests succeeded"),n&&typeof n=="object"&&"interests"in n?n.interests||[]:Array.isArray(n)?n:[]}catch(n){throw o.error("[ERROR] getUserInterests failed:",n),n}}async function Be(s){o.info("[INFO] Fetching interest weights...");try{let e=await s.trpcClient.call("interest.readWeights");return o.info("[SUCCESS] getInterestWeights succeeded"),e&&typeof e=="object"&&"weights"in e?e.weights||[]:Array.isArray(e)?e:[]}catch(e){throw o.error("[ERROR] getInterestWeights failed:",e),e}}var We=g(()=>{"use strict";b()});async function ze(s){o.info("[INFO] Running N Lobby API health check...");let e=[{name:"tRPC lightweight endpoint",test:async()=>{try{let t=await s.trpcClient.getUnreadNewsCount();return typeof t=="number"&&t>=0}catch{return!1}}},{name:"tRPC batch health check",test:async()=>{try{return await s.trpcClient.healthCheck()}catch{return!1}}},{name:"HTML news page access",test:async()=>{try{let t=await s.httpClient.get("/news",{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"},withCredentials:!0,timeout:8e3});if(t.status===200&&typeof t.data=="string"){let n=t.data.toLowerCase(),r=n.includes("\u30ED\u30B0\u30A4\u30F3")||n.includes("login")||n.includes("sign-in"),i=n.includes("news")||n.includes("\u304A\u77E5\u3089\u305B")||n.includes("nlobby");return!r&&i}return!1}catch{return!1}}},{name:"Basic server connectivity",test:async()=>{try{return(await s.httpClient.get("/",{timeout:5e3,withCredentials:!0})).status===200}catch{return!1}}}];for(let t=0;t<e.length;t++){let n=e[t];o.info(`[STEP${t+1}] Testing ${n.name}...`);try{if(await n.test())return o.info(`[SUCCESS] ${n.name} passed`),t<3?(o.info("[SUCCESS] Health check passed - authentication and connectivity verified"),!0):(o.info("[WARNING] Health check passed with limited functionality"),!0);o.info(`[ERROR] ${n.name} failed`)}catch(r){o.info(`[ERROR] ${n.name} failed with error:`,r instanceof Error?r.message:"Unknown error")}}return o.info("[ERROR] All health check methods failed"),!1}async function Je(s,e="/news"){let t=[];t.push("[INFO] N Lobby Connection Debug Report"),t.push("=".repeat(50)),t.push(""),t.push("[STATUS] Authentication Status:"),t.push(s.getCookieStatus()),t.push(""),t.push(`[NETWORK] Testing Basic Connectivity to ${e}:`);try{let i=Date.now(),a=await s.httpClient.get(e,{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","User-Agent":m.userAgent},withCredentials:!0,timeout:1e4}),c=Date.now();if(t.push(`[SUCCESS] Response received (${c-i}ms)`),t.push(`[STATUS] Status: ${a.status} ${a.statusText}`),t.push(`[SIZE] Content Length: ${typeof a.data=="string"?a.data.length:"unknown"}`),typeof a.data=="string"){let l=a.data.toLowerCase();t.push(""),t.push("[INFO] Content Analysis:"),(l.includes("\u30ED\u30B0\u30A4\u30F3")||l.includes("login")||l.includes("sign-in"))&&t.push("[WARNING] Contains login keywords - may need authentication"),(l.includes("unauthorized")||l.includes("access denied"))&&t.push("[BLOCKED] Access denied detected"),(l.includes("news")||l.includes("announcement")||l.includes("\u304A\u77E5\u3089\u305B"))&&t.push("[SUCCESS] Contains news/announcement content")}}catch(i){t.push("[ERROR] Basic connectivity failed"),i instanceof k?t.push(`[STATUS] Error Status: ${i.response?.status||"unknown"}`):t.push(`[DATA] Error: ${i instanceof Error?i.message:"Unknown error"}`)}t.push(""),t.push("[NETWORK] Network Information:"),t.push(`[URL] Base URL: ${s.httpClient.defaults.baseURL??""}`),t.push(`[TIMEOUT] Timeout: ${s.httpClient.defaults.timeout}ms`),t.push(""),t.push("=".repeat(50)),t.push("[TARGET] Recommendations:");let n=!!s.httpClient.defaults.headers.Cookie,r=s.nextAuth.isAuthenticated();return!n&&!r?t.push("1. Run interactive_login to authenticate"):n&&r&&(t.push("1. Authentication looks good - issue may be server-side"),t.push("2. Try different endpoints or wait and retry")),t.join(`
|
|
12
|
+
`)}async function Ye(s,e="/news",t=1e3){try{o.info(`[INFO] Testing page content for ${e}...`);let n=await s.httpClient.get(e,{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8","Accept-Language":"ja,en-US;q=0.7,en;q=0.3","User-Agent":m.userAgent},withCredentials:!0,timeout:1e4});if(typeof n.data=="string"){let r=n.data,i=r.substring(0,t),a=[];a.push(`Status: ${n.status} ${n.statusText}`),a.push(`Content Length: ${r.length} characters`),a.push(`Content Type: ${n.headers["content-type"]||"unknown"}`),a.push("");let c=r.toLowerCase();c.includes("\u30ED\u30B0\u30A4\u30F3")||c.includes("login")?a.push("[WARNING] Page contains login keywords - may not be authenticated"):(c.includes("news")||c.includes("\u304A\u77E5\u3089\u305B"))&&a.push("[SUCCESS] Page appears to contain news content"),a.push(""),a.push("[DATA] Content Sample:"),a.push("-".repeat(50));let l=a.join(`
|
|
13
13
|
`)+`
|
|
14
|
-
`+
|
|
14
|
+
`+i;return r.length>t?l+`
|
|
15
15
|
|
|
16
|
-
... (${r.length-t} more characters)`:l}else return`Non-string response received: ${typeof n.data}`}catch(n){
|
|
16
|
+
... (${r.length-t} more characters)`:l}else return`Non-string response received: ${typeof n.data}`}catch(n){return o.error(`[ERROR] Failed to test page content for ${e}:`,n),n instanceof k?`Error ${n.response?.status||"unknown"}: ${n.message||"Unknown error"}`:`Error: ${n instanceof Error?n.message:"Unknown error"}`}}async function Ke(s,e,t){try{o.info(`[INFO] Testing tRPC endpoint: ${e}`);let n=await s.trpcClient.call(e,t);return o.info(`[SUCCESS] tRPC endpoint ${e} succeeded`),{success:!0,method:e,params:t,result:n,timestamp:new Date().toISOString()}}catch(n){o.error(`[ERROR] tRPC endpoint ${e} failed:`,n);let r={success:!1,method:e,params:t,error:n instanceof Error?n.message:"Unknown error",timestamp:new Date().toISOString()};return n instanceof k&&(r.status=n.response?.status,r.statusText=n.response?.statusText,r.responseData=n.response?.data),r}}var Ve=g(()=>{"use strict";E();b();T()});import te from"node:fs";import Zt from"node:os";import Xe from"node:path";function en(){try{return te.readFileSync(ne,"utf8")}catch{return null}}function re(s){try{let e=Xe.dirname(ne);te.mkdirSync(e,{recursive:!0}),te.writeFileSync(ne,s,"utf8")}catch(e){o.warn("[WARNING] Failed to save session to disk:",e)}}var ne,D,z=g(()=>{"use strict";T();E();b();ue();de();we();xe();Ue();Me();We();Ve();ne=Xe.join(Zt.homedir(),".nlobby","session");D=class{httpClient;nextAuth;trpcClient;session=null;constructor(){this.nextAuth=new M,this.trpcClient=new H(this.nextAuth),this.httpClient=new A({baseURL:m.nlobby.baseUrl,timeout:1e4,headers:{"Content-Type":"application/json","User-Agent":m.userAgent}}),this.setupInterceptors();let e=en();e&&(o.info("[INFO] Loaded session from disk"),this.setCookiesInternal(e))}setupInterceptors(){this.httpClient.interceptors.request.use(e=>(this.session&&(e.headers.Authorization=`Bearer ${this.session.accessToken}`),e)),this.httpClient.interceptors.response.use(e=>e,async e=>{if(e instanceof Error&&"response"in e&&e.response?.status===401&&this.session)throw new Error("Authentication expired. Please re-authenticate.");return Promise.reject(e)})}setCookiesInternal(e){!e||e.trim()===""||(this.httpClient.defaults.headers.Cookie=e,this.nextAuth.setCookies(e),this.trpcClient.setAllCookies(e))}setSession(e){this.session=e}setCookies(e){if(!e||e.trim()===""){o.warn("[WARNING] Empty cookies provided to setCookies");return}o.debug("[COOKIE] Setting cookies for all clients..."),this.setCookiesInternal(e),o.info("[SUCCESS] HTTP client cookies set"),o.info("[SUCCESS] NextAuth cookies set"),o.info("[SUCCESS] tRPC client cookies set")}getCookieStatus(){let e=!!this.httpClient.defaults.headers.Cookie,t=this.nextAuth.isAuthenticated(),n=this.nextAuth.getCookies(),r=!!this.trpcClient.allCookies,i=this.httpClient.defaults.headers.Cookie,a=typeof i=="string"?i.length:0,c=this.trpcClient.allCookies?.length||0,l=this.nextAuth.getCookieHeader()?.length||0,u=a===c&&c>0;return`[INFO] Authentication Status:
|
|
17
17
|
[HTTP] HTTP client: ${e?"[SUCCESS] cookies set":"[ERROR] no cookies"} (${a} chars)
|
|
18
18
|
[DEBUG] tRPC client: ${r?"[SUCCESS] cookies set":"[ERROR] no cookies"} (${c} chars)
|
|
19
19
|
[AUTH] NextAuth: ${t?"[SUCCESS] authenticated":"[ERROR] not authenticated"} (${l} chars)
|
|
@@ -22,7 +22,7 @@ ${a}`)}async function Kt(o){i.info("[STUDENT_CARD] Launching headless browser fo
|
|
|
22
22
|
- Callback URL: ${n.callbackUrl?"[SUCCESS] present":"[ERROR] missing"}
|
|
23
23
|
|
|
24
24
|
Cookie Synchronization: ${u?"[SUCCESS] synchronized":"[ERROR] not synchronized"}
|
|
25
|
-
${!u&&e?"[WARNING] Cookie length mismatch detected - may cause authentication issues":""}`}async getNews(){return de(this)}async getNewsDetail(e){return pe(this,e)}async markNewsAsRead(e){return ge(this,e)}async getUnreadNewsInfo(){return me(this)}async getSchedule(e,t){return V(this,e,t)}async getGoogleCalendarEvents(e,t){return D(this,e,t)}async getScheduleByDate(e){return fe(this,e)}async testCalendarEndpoints(e){return ye(this,e)}async getLobbyCalendarFilters(){return we(this)}createDateRange(e,t){return be(e,t)}createSingleDayRange(e){return Ce(e)}createWeekDateRange(e){return ke(e)}createMonthDateRange(e,t){return Se(e,t)}async getRequiredCourses(){return Ee(this)}async getLearningResources(e){return Re(this,e)}async isExamDay(e){return Ae(this,e)}async finishExamDayMode(){return Te(this)}async getExamOneTimePassword(){return ve(this)}async getUserInfo(){return Pe(this)}async getAccountInfoFromScript(e="/"){return X(this,e)}async getStudentCardScreenshot(){return $e(this)}async updateLastAccess(){return Oe(this)}async getMainNavigations(){return Fe(this)}async getNotificationMessages(){return je(this)}async getUserInterests(e=!1){return Me(this,e)}async getInterestWeights(){return Ge(this)}async healthCheck(){return qe(this)}async debugConnection(e="/news"){return Be(this,e)}async testPageContent(e="/news",t=1e3){return We(this,e,t)}async testTrpcEndpoint(e,t){return ze(this,e,t)}}});import Zt from"puppeteer";var T,te=p(()=>{"use strict";S();m();T=class{browser=null;page=null;async initializeBrowser(){try{if(i.info("Initializing browser for authentication..."),this.browser){try{await this.browser.close()}catch(e){i.warn("Error closing existing browser:",e)}this.browser=null,this.page=null}this.browser=await Zt.launch({headless:!1,defaultViewport:{width:1280,height:800},ignoreDefaultArgs:["--disable-extensions","--disable-default-apps"],args:["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage","--disable-gpu","--no-first-run","--no-default-browser-check","--no-pings","--password-store=basic","--use-mock-keychain","--memory-pressure-off","--max_old_space_size=4096",'--js-flags="--max-old-space-size=4096"',"--disable-background-timer-throttling","--disable-renderer-backgrounding","--disable-backgrounding-occluded-windows","--disable-background-mode","--disable-default-apps","--disable-sync","--disable-translate","--disable-infobars","--disable-notifications","--disable-popup-blocking","--enable-async-dns","--enable-simple-cache-backend","--enable-tcp-fast-open","--prerender-from-omnibox=disabled","--disable-features=VizDisplayCompositor,TranslateUI","--disable-search-engine-choice-screen","--disable-component-update","--allow-running-insecure-content","--disable-hang-monitor","--disable-prompt-on-repost","--disable-client-side-phishing-detection","--disable-domain-reliability","--disable-logging","--disable-login-animations","--disable-modal-animations","--disable-motion-blur","--disable-smooth-scrolling","--disable-threaded-animation","--disable-threaded-scrolling","--disable-checker-imaging","--disable-new-profile-management","--disable-new-avatar-menu","--disable-new-bookmark-apps"],timeout:6e4,protocolTimeout:6e4,slowMo:250}),this.page=await this.browser.newPage(),await this.page.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"),await this.page.setDefaultNavigationTimeout(6e4),await this.page.setDefaultTimeout(3e4),this.page.on("error",e=>{i.error("Page error:",e)}),this.page.on("pageerror",e=>{i.error("Page JavaScript error:",e)}),this.page.on("console",e=>{e.type()==="error"&&i.error("Browser console error:",e.text())}),this.page.on("framedetached",e=>{i.warn("Frame detached:",e.url())}),this.browser.on("disconnected",()=>{i.error("Browser disconnected unexpectedly"),this.browser=null,this.page=null}),this.browser.on("targetcreated",e=>{i.info("New browser target created:",e.url())}),this.browser.on("targetdestroyed",e=>{i.info("Browser target destroyed:",e.url())}),await this.page.setJavaScriptEnabled(!0),await this.page.setCacheEnabled(!1),await this.page.setRequestInterception(!0),this.page.on("request",e=>{let t=e.resourceType();["image","media","font","stylesheet"].includes(t)?t==="image"&&(e.url().includes("accounts.google.com")||e.url().includes("gstatic.com")||e.url().includes("googleapis.com"))?e.continue():e.abort():e.continue()}),i.info("Browser initialized successfully")}catch(e){if(i.error("Failed to initialize browser:",e),this.browser){try{await this.browser.close()}catch(t){i.warn("Error closing browser after initialization failure:",t)}this.browser=null,this.page=null}throw new Error("Failed to initialize browser for authentication")}}async setupPageConfiguration(){if(!this.page)throw new Error("Page not initialized");await this.page.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"),await this.page.setDefaultNavigationTimeout(6e4),await this.page.setDefaultTimeout(3e4),this.page.on("error",e=>{i.error("Page error:",e)}),this.page.on("pageerror",e=>{i.error("Page JavaScript error:",e)}),this.page.on("console",e=>{e.type()==="error"&&i.error("Browser console error:",e.text())}),await this.page.setJavaScriptEnabled(!0),await this.page.setCacheEnabled(!1),await this.page.setRequestInterception(!0),this.page.on("request",e=>{let t=e.resourceType();["image","media","font","stylesheet"].includes(t)?t==="image"&&(e.url().includes("accounts.google.com")||e.url().includes("gstatic.com")||e.url().includes("googleapis.com"))?e.continue():e.abort():e.continue()})}async checkBrowserHealth(){try{return!this.browser||!this.browser.isConnected()?(i.warn("Browser is not connected"),!1):!this.page||this.page.isClosed()?(i.warn("Page is closed"),!1):(await this.page.evaluate(()=>document.readyState),!0)}catch(e){return i.warn("Browser health check failed:",e),!1}}async extractCookies(){if(!this.page)throw new Error("Page not initialized");try{i.info("Extracting cookies from N Lobby session...");let e=await this.page.cookies(),t,n,r,s=[];for(let c of e){let l=`${c.name}=${c.value}`;s.push(l),c.name==="__Secure-next-auth.session-token"?t=c.value:c.name==="__Host-next-auth.csrf-token"?n=c.value:c.name==="__Secure-next-auth.callback-url"&&(r=decodeURIComponent(c.value))}let a=s.join("; ");return i.info(`Extracted ${e.length} cookies from N Lobby session`),i.info(`Session token: ${t?"present":"missing"}`),i.info(`CSRF token: ${n?"present":"missing"}`),{sessionToken:t,csrfToken:n,callbackUrl:r,allCookies:a}}catch(e){throw i.error("Failed to extract cookies:",e),new Error("Failed to extract authentication cookies")}}async takeScreenshot(e="nlobby-auth-screenshot.png"){if(!this.page)throw new Error("Page not initialized");let t=`/tmp/${e}`;return await this.page.screenshot({path:t,fullPage:!0}),i.info(`Screenshot saved to ${t}`),t}async getCurrentUrl(){if(!this.page)throw new Error("Page not initialized");return this.page.url()}async getPageTitle(){if(!this.page)throw new Error("Page not initialized");return this.page.title()}async waitForRedirectWithRetry(e,t){let s=e.replace("https://","").replace("http://","");for(let a=1;a<=3;a++)try{(!this.browser||!this.browser.isConnected())&&(i.error("Browser crashed or disconnected, reinitializing..."),await this.initializeBrowser()),i.info(`Waiting for redirect back to N Lobby (attempt ${a}/3)...`),await this.page.waitForFunction(c=>window.location.href.includes(c),{timeout:t/3},s),i.info("Successfully redirected back to N Lobby");return}catch(c){if(a===3)throw i.error("All redirect attempts failed:",c),new Error(`Failed to detect redirect after 3 attempts: ${c instanceof Error?c.message:"Unknown error"}`);i.warn(`Redirect attempt ${a} failed, retrying in 2000ms...`),await new Promise(l=>setTimeout(l,2e3));try{!this.browser||!this.browser.isConnected()?(i.error("Browser crashed, reinitializing..."),await this.initializeBrowser(),await this.page.goto(e,{waitUntil:"networkidle2",timeout:3e4})):await this.page.evaluate(()=>document.readyState)}catch{i.warn("Page became inaccessible, creating new page..."),this.browser&&this.browser.isConnected()&&(this.page=await this.browser.newPage(),await this.setupPageConfiguration())}}}async waitForLoginCompletionWithRetry(e){for(let r=1;r<=3;r++)try{(!this.browser||!this.browser.isConnected())&&(i.error("Browser crashed during login detection, reinitializing..."),await this.initializeBrowser(),await this.page.goto(g.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4})),i.info(`Waiting for login completion (attempt ${r}/3)...`),await this.page.waitForFunction(()=>document.querySelector('[data-testid="user-menu"], .user-profile, .logout-btn')!==null||document.cookie.includes("next-auth.session-token")||window.location.pathname.includes("/home")||window.location.pathname.includes("/dashboard"),{timeout:e/3}),i.info("Login completion detected");return}catch(s){if(r===3)throw i.error("All login detection attempts failed:",s),new Error(`Failed to detect login completion after 3 attempts: ${s instanceof Error?s.message:"Unknown error"}`);i.warn(`Login detection attempt ${r} failed, retrying in 2000ms...`),await new Promise(a=>setTimeout(a,2e3));try{!this.browser||!this.browser.isConnected()?(i.error("Browser crashed during login detection, reinitializing..."),await this.initializeBrowser(),await this.page.goto(g.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4})):await this.page.evaluate(()=>document.readyState)}catch{i.warn("Page became inaccessible during login detection, creating new page..."),this.browser&&this.browser.isConnected()&&(this.page=await this.browser.newPage(),await this.setupPageConfiguration(),await this.page.goto(g.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4}))}}}async close(){try{this.page&&(await this.page.close(),this.page=null),this.browser&&(await this.browser.close(),this.browser=null),i.info("Browser closed successfully")}catch(e){i.error("Error closing browser:",e)}}async interactiveLogin(){if(await this.checkBrowserHealth()||(i.warn("Browser unhealthy, reinitializing..."),await this.initializeBrowser()),!this.browser||!this.page)throw new Error("Browser not initialized. Call initializeBrowser() first.");try{return i.info("Starting interactive login process..."),await this.page.goto(g.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4}),i.info("N Lobby page loaded. Please complete the login process in the browser window."),i.info("The browser will remain open for you to login manually."),await this.waitForLoginCompletionWithRetry(3e5),i.info("Login detected! Extracting cookies..."),await this.extractCookies()}catch(t){if(i.error("Interactive login failed:",t),this.page)try{let n=await this.page.url(),r=await this.page.title();i.error(`Current URL: ${n}`),i.error(`Page title: ${r}`),await this.takeScreenshot("interactive-login-failure-debug.png")}catch(n){i.error("Failed to capture debug information:",n)}throw new Error(`Interactive login failed: ${t instanceof Error?t.message:"Unknown error"}`)}}}});import{createHash as en}from"crypto";var q,Ke=p(()=>{"use strict";m();q=class{credentialStore=new Map;SESSION_TIMEOUT=7200*1e3;hashEmail(e){return en("sha256").update(e).digest("hex")}validateEmail(e){if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e))return{valid:!1,userType:"unknown",message:"Invalid email format"};let n=e.split("@")[1].toLowerCase();return n==="nnn.ed.jp"?{valid:!0,userType:"student"}:n==="nnn.ac.jp"?{valid:!0,userType:"staff"}:n==="gmail.com"||n==="yahoo.com"||n==="outlook.com"||n==="hotmail.com"?{valid:!0,userType:"parent"}:{valid:!0,userType:"parent"}}storeSession(e){let t=this.hashEmail(e),n={emailHash:t,timestamp:Date.now(),sessionValid:!0};this.credentialStore.set(t,n),i.info(`Session stored for user: ${e.split("@")[0]}@***`)}hasValidSession(e){let t=this.hashEmail(e),n=this.credentialStore.get(t);return n?Date.now()-n.timestamp>this.SESSION_TIMEOUT?(this.credentialStore.delete(t),!1):n.sessionValid:!1}invalidateSession(e){let t=this.hashEmail(e);this.credentialStore.delete(t),i.info(`Session invalidated for user: ${e.split("@")[0]}@***`)}getLoginGuidance(e){switch(e){case"student":return`
|
|
25
|
+
${!u&&e?"[WARNING] Cookie length mismatch detected - may cause authentication issues":""}`}async getNews(){return me(this)}async getNewsDetail(e){return he(this,e)}async markNewsAsRead(e){return fe(this,e)}async getUnreadNewsInfo(){return ye(this)}async getSchedule(e,t){return Z(this,e,t)}async getGoogleCalendarEvents(e,t){return P(this,e,t)}async getScheduleByDate(e){return be(this,e)}async testCalendarEndpoints(e){return Ce(this,e)}async getLobbyCalendarFilters(){return ke(this)}createDateRange(e,t){return Se(e,t)}createSingleDayRange(e){return Re(e)}createWeekDateRange(e){return Ne(e)}createMonthDateRange(e,t){return Ee(e,t)}async getRequiredCourses(){return Te(this)}async getLearningResources(e){return ve(this,e)}async isExamDay(e){return De(this,e)}async finishExamDayMode(){return Ie(this)}async getExamOneTimePassword(){return Le(this)}async getUserInfo(){return _e(this)}async getAccountInfoFromScript(e="/"){return ee(this,e)}async getStudentCardScreenshot(){return Fe(this)}async updateLastAccess(){return je(this)}async getMainNavigations(){return He(this)}async getNotificationMessages(){return Ge(this)}async getUserInterests(e=!1){return qe(this,e)}async getInterestWeights(){return Be(this)}async healthCheck(){return ze(this)}async debugConnection(e="/news"){return Je(this,e)}async testPageContent(e="/news",t=1e3){return Ye(this,e,t)}async testTrpcEndpoint(e,t){return Ke(this,e,t)}}});import tn from"puppeteer";var I,se=g(()=>{"use strict";E();b();I=class{browser=null;page=null;async initializeBrowser(){try{if(o.info("Initializing browser for authentication..."),this.browser){try{await this.browser.close()}catch(e){o.warn("Error closing existing browser:",e)}this.browser=null,this.page=null}this.browser=await tn.launch({headless:!1,defaultViewport:{width:1280,height:800},ignoreDefaultArgs:["--disable-extensions","--disable-default-apps"],args:["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage","--disable-gpu","--no-first-run","--no-default-browser-check","--no-pings","--password-store=basic","--use-mock-keychain","--memory-pressure-off","--max_old_space_size=4096",'--js-flags="--max-old-space-size=4096"',"--disable-background-timer-throttling","--disable-renderer-backgrounding","--disable-backgrounding-occluded-windows","--disable-background-mode","--disable-default-apps","--disable-sync","--disable-translate","--disable-infobars","--disable-notifications","--disable-popup-blocking","--enable-async-dns","--enable-simple-cache-backend","--enable-tcp-fast-open","--prerender-from-omnibox=disabled","--disable-features=VizDisplayCompositor,TranslateUI","--disable-search-engine-choice-screen","--disable-component-update","--allow-running-insecure-content","--disable-hang-monitor","--disable-prompt-on-repost","--disable-client-side-phishing-detection","--disable-domain-reliability","--disable-logging","--disable-login-animations","--disable-modal-animations","--disable-motion-blur","--disable-smooth-scrolling","--disable-threaded-animation","--disable-threaded-scrolling","--disable-checker-imaging","--disable-new-profile-management","--disable-new-avatar-menu","--disable-new-bookmark-apps"],timeout:6e4,protocolTimeout:6e4,slowMo:250}),this.page=await this.browser.newPage(),await this.page.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"),await this.page.setDefaultNavigationTimeout(6e4),await this.page.setDefaultTimeout(3e4),this.page.on("error",e=>{o.error("Page error:",e)}),this.page.on("pageerror",e=>{o.error("Page JavaScript error:",e)}),this.page.on("console",e=>{e.type()==="error"&&o.error("Browser console error:",e.text())}),this.page.on("framedetached",e=>{o.warn("Frame detached:",e.url())}),this.browser.on("disconnected",()=>{o.error("Browser disconnected unexpectedly"),this.browser=null,this.page=null}),this.browser.on("targetcreated",e=>{o.info("New browser target created:",e.url())}),this.browser.on("targetdestroyed",e=>{o.info("Browser target destroyed:",e.url())}),await this.page.setJavaScriptEnabled(!0),await this.page.setCacheEnabled(!1),await this.page.setRequestInterception(!0),this.page.on("request",e=>{let t=e.resourceType();["image","media","font","stylesheet"].includes(t)?t==="image"&&(e.url().includes("accounts.google.com")||e.url().includes("gstatic.com")||e.url().includes("googleapis.com"))?e.continue():e.abort():e.continue()}),o.info("Browser initialized successfully")}catch(e){if(o.error("Failed to initialize browser:",e),this.browser){try{await this.browser.close()}catch(t){o.warn("Error closing browser after initialization failure:",t)}this.browser=null,this.page=null}throw new Error("Failed to initialize browser for authentication")}}async setupPageConfiguration(){if(!this.page)throw new Error("Page not initialized");await this.page.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"),await this.page.setDefaultNavigationTimeout(6e4),await this.page.setDefaultTimeout(3e4),this.page.on("error",e=>{o.error("Page error:",e)}),this.page.on("pageerror",e=>{o.error("Page JavaScript error:",e)}),this.page.on("console",e=>{e.type()==="error"&&o.error("Browser console error:",e.text())}),await this.page.setJavaScriptEnabled(!0),await this.page.setCacheEnabled(!1),await this.page.setRequestInterception(!0),this.page.on("request",e=>{let t=e.resourceType();["image","media","font","stylesheet"].includes(t)?t==="image"&&(e.url().includes("accounts.google.com")||e.url().includes("gstatic.com")||e.url().includes("googleapis.com"))?e.continue():e.abort():e.continue()})}async checkBrowserHealth(){try{return!this.browser||!this.browser.isConnected()?(o.warn("Browser is not connected"),!1):!this.page||this.page.isClosed()?(o.warn("Page is closed"),!1):(await this.page.evaluate(()=>document.readyState),!0)}catch(e){return o.warn("Browser health check failed:",e),!1}}async extractCookies(){if(!this.page)throw new Error("Page not initialized");try{o.info("Extracting cookies from N Lobby session...");let e=await this.page.cookies(),t,n,r,i=[];for(let c of e){let l=`${c.name}=${c.value}`;i.push(l),c.name==="__Secure-next-auth.session-token"?t=c.value:c.name==="__Host-next-auth.csrf-token"?n=c.value:c.name==="__Secure-next-auth.callback-url"&&(r=decodeURIComponent(c.value))}let a=i.join("; ");return o.info(`Extracted ${e.length} cookies from N Lobby session`),o.info(`Session token: ${t?"present":"missing"}`),o.info(`CSRF token: ${n?"present":"missing"}`),{sessionToken:t,csrfToken:n,callbackUrl:r,allCookies:a}}catch(e){throw o.error("Failed to extract cookies:",e),new Error("Failed to extract authentication cookies")}}async takeScreenshot(e="nlobby-auth-screenshot.png"){if(!this.page)throw new Error("Page not initialized");let t=`/tmp/${e}`;return await this.page.screenshot({path:t,fullPage:!0}),o.info(`Screenshot saved to ${t}`),t}async getCurrentUrl(){if(!this.page)throw new Error("Page not initialized");return this.page.url()}async getPageTitle(){if(!this.page)throw new Error("Page not initialized");return this.page.title()}async waitForRedirectWithRetry(e,t){let i=e.replace("https://","").replace("http://","");for(let a=1;a<=3;a++)try{(!this.browser||!this.browser.isConnected())&&(o.error("Browser crashed or disconnected, reinitializing..."),await this.initializeBrowser()),o.info(`Waiting for redirect back to N Lobby (attempt ${a}/3)...`),await this.page.waitForFunction(c=>window.location.href.includes(c),{timeout:t/3},i),o.info("Successfully redirected back to N Lobby");return}catch(c){if(a===3)throw o.error("All redirect attempts failed:",c),new Error(`Failed to detect redirect after 3 attempts: ${c instanceof Error?c.message:"Unknown error"}`);o.warn(`Redirect attempt ${a} failed, retrying in 2000ms...`),await new Promise(l=>setTimeout(l,2e3));try{!this.browser||!this.browser.isConnected()?(o.error("Browser crashed, reinitializing..."),await this.initializeBrowser(),await this.page.goto(e,{waitUntil:"networkidle2",timeout:3e4})):await this.page.evaluate(()=>document.readyState)}catch{o.warn("Page became inaccessible, creating new page..."),this.browser&&this.browser.isConnected()&&(this.page=await this.browser.newPage(),await this.setupPageConfiguration())}}}async waitForLoginCompletionWithRetry(e){for(let r=1;r<=3;r++)try{(!this.browser||!this.browser.isConnected())&&(o.error("Browser crashed during login detection, reinitializing..."),await this.initializeBrowser(),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4})),o.info(`Waiting for login completion (attempt ${r}/3)...`),await this.page.waitForFunction(()=>document.querySelector('[data-testid="user-menu"], .user-profile, .logout-btn')!==null||document.cookie.includes("next-auth.session-token")||window.location.pathname.includes("/home")||window.location.pathname.includes("/dashboard"),{timeout:e/3}),o.info("Login completion detected");return}catch(i){if(r===3)throw o.error("All login detection attempts failed:",i),new Error(`Failed to detect login completion after 3 attempts: ${i instanceof Error?i.message:"Unknown error"}`);o.warn(`Login detection attempt ${r} failed, retrying in 2000ms...`),await new Promise(a=>setTimeout(a,2e3));try{!this.browser||!this.browser.isConnected()?(o.error("Browser crashed during login detection, reinitializing..."),await this.initializeBrowser(),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4})):await this.page.evaluate(()=>document.readyState)}catch{o.warn("Page became inaccessible during login detection, creating new page..."),this.browser&&this.browser.isConnected()&&(this.page=await this.browser.newPage(),await this.setupPageConfiguration(),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4}))}}}async close(){try{this.page&&(await this.page.close(),this.page=null),this.browser&&(await this.browser.close(),this.browser=null),o.info("Browser closed successfully")}catch(e){o.error("Error closing browser:",e)}}async interactiveLogin(){if(await this.checkBrowserHealth()||(o.warn("Browser unhealthy, reinitializing..."),await this.initializeBrowser()),!this.browser||!this.page)throw new Error("Browser not initialized. Call initializeBrowser() first.");try{return o.info("Starting interactive login process..."),await this.page.goto(m.nlobby.baseUrl,{waitUntil:"networkidle2",timeout:3e4}),o.info("N Lobby page loaded. Please complete the login process in the browser window."),o.info("The browser will remain open for you to login manually."),await this.waitForLoginCompletionWithRetry(3e5),o.info("Login detected! Extracting cookies..."),await this.extractCookies()}catch(t){if(o.error("Interactive login failed:",t),this.page)try{let n=await this.page.url(),r=await this.page.title();o.error(`Current URL: ${n}`),o.error(`Page title: ${r}`),await this.takeScreenshot("interactive-login-failure-debug.png")}catch(n){o.error("Failed to capture debug information:",n)}throw new Error(`Interactive login failed: ${t instanceof Error?t.message:"Unknown error"}`)}}}});import{createHash as nn}from"crypto";var J,Qe=g(()=>{"use strict";b();J=class{credentialStore=new Map;SESSION_TIMEOUT=7200*1e3;hashEmail(e){return nn("sha256").update(e).digest("hex")}validateEmail(e){if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e))return{valid:!1,userType:"unknown",message:"Invalid email format"};let n=e.split("@")[1].toLowerCase();return n==="nnn.ed.jp"?{valid:!0,userType:"student"}:n==="nnn.ac.jp"?{valid:!0,userType:"staff"}:n==="gmail.com"||n==="yahoo.com"||n==="outlook.com"||n==="hotmail.com"?{valid:!0,userType:"parent"}:{valid:!0,userType:"parent"}}storeSession(e){let t=this.hashEmail(e),n={emailHash:t,timestamp:Date.now(),sessionValid:!0};this.credentialStore.set(t,n),o.info(`Session stored for user: ${e.split("@")[0]}@***`)}hasValidSession(e){let t=this.hashEmail(e),n=this.credentialStore.get(t);return n?Date.now()-n.timestamp>this.SESSION_TIMEOUT?(this.credentialStore.delete(t),!1):n.sessionValid:!1}invalidateSession(e){let t=this.hashEmail(e);this.credentialStore.delete(t),o.info(`Session invalidated for user: ${e.split("@")[0]}@***`)}getLoginGuidance(e){switch(e){case"student":return`
|
|
26
26
|
[STUDENT] Student Login Guide:
|
|
27
27
|
- Use your @nnn.ed.jp email address
|
|
28
28
|
- Use your N High School password
|
|
@@ -72,19 +72,19 @@ ${!u&&e?"[WARNING] Cookie length mismatch detected - may cause authentication is
|
|
|
72
72
|
[PRO-TIP] Pro Tips:
|
|
73
73
|
- Use 'interactive_login' if automated login fails
|
|
74
74
|
- The browser window will stay open for manual completion
|
|
75
|
-
- You can close the browser once login is complete`}cleanupExpiredSessions(){let e=Date.now(),t=0;for(let[n,r]of this.credentialStore.entries())e-r.timestamp>this.SESSION_TIMEOUT&&(this.credentialStore.delete(n),t++);t>0&&i.info(`Cleaned up ${t} expired sessions`)}getSessionStats(){let e=Date.now(),t=0;for(let n of this.credentialStore.values())e-n.timestamp>this.SESSION_TIMEOUT&&t++;return{total:this.credentialStore.size,expired:t}}}});var re={};P(re,{NLobbyMCPServer:()=>ne});import{Server as tn}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as nn}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as rn,ErrorCode as L,ListResourcesRequestSchema as on,ListToolsRequestSchema as sn,McpError as U,ReadResourceRequestSchema as an,ListPromptsRequestSchema as cn,GetPromptRequestSchema as ln}from"@modelcontextprotocol/sdk/types.js";var ne,oe=p(()=>{"use strict";H();S();te();Ke();R();m();ne=class{server;api;browserAuth;credentialManager;constructor(){this.server=new tn({name:g.mcp.serverName,version:g.mcp.serverVersion},{capabilities:{resources:{},tools:{},prompts:{}}}),this.api=new A,this.browserAuth=new T,this.credentialManager=new q,this.setupHandlers()}setupHandlers(){this.server.setRequestHandler(on,async()=>({resources:[{uri:"nlobby://news",name:"School News",description:"Latest school news and notices",mimeType:"application/json"},{uri:"nlobby://schedule",name:"School Schedule",description:"Daily class schedule and events",mimeType:"application/json"},{uri:"nlobby://user-profile",name:"User Profile",description:"Current user information and preferences",mimeType:"application/json"},{uri:"nlobby://required-courses",name:"Required Courses",description:"Required courses and academic information",mimeType:"application/json"}]})),this.server.setRequestHandler(an,async e=>{let{uri:t}=e.params;try{switch(t){case"nlobby://news":{let n=await this.api.getNews();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://schedule":{let n=await this.api.getSchedule("personal");return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://user-profile":{let n=await this.api.getUserInfo();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://required-courses":{let n=await this.api.getRequiredCourses();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}default:throw new U(L.InvalidRequest,`Unknown resource: ${t}`)}}catch(n){throw new U(L.InternalError,`Failed to read resource: ${n instanceof Error?n.message:"Unknown error"}`)}}),this.server.setRequestHandler(sn,async()=>({tools:[{name:"get_news",description:"Retrieve school news",inputSchema:{type:"object",properties:{category:{type:"string",description:"Filter by category (optional)"},limit:{type:"number",description:"Maximum number of news items to retrieve (optional, default: 10)",minimum:1,default:10},sort:{type:"string",description:"Sort order: 'newest' (default), 'oldest', 'title-asc', 'title-desc'",enum:["newest","oldest","title-asc","title-desc"]}}}},{name:"get_news_detail",description:"Retrieve detailed information for a specific news article",inputSchema:{type:"object",properties:{newsId:{type:"string",description:"The ID of the news article to retrieve"},markAsRead:{type:"boolean",description:"Mark the news article as read (optional, default: false)",default:!1}},required:["newsId"]}},{name:"get_account_info",description:"Extract account information by parsing Next.js flight data from a rendered page",inputSchema:{type:"object",properties:{}}},{name:"get_student_card_screenshot",description:"Capture a screenshot of the student ID card by following the secure portal redirect flow",inputSchema:{type:"object",properties:{}}},{name:"get_required_courses",description:"Retrieve required courses information with detailed progress tracking",inputSchema:{type:"object",properties:{grade:{type:"number",description:"Filter by grade level (1, 2, or 3) (optional)"},semester:{type:"string",description:'Filter by term year (e.g., "2024", "2025") (optional)'},category:{type:"string",description:'Filter by curriculum category (e.g., "\u56FD\u8A9E", "\u6570\u5B66", "\u82F1\u8A9E") (optional)'}}}},{name:"get_schedule",description:"Get school schedule for a specific date (backward compatibility)",inputSchema:{type:"object",properties:{date:{type:"string",description:"Date in YYYY-MM-DD format (optional, defaults to today)"}}}},{name:"get_calendar_events",description:"Get calendar events with advanced options",inputSchema:{type:"object",properties:{calendar_type:{type:"string",enum:["personal","school"],description:"Type of calendar to retrieve (personal or school)",default:"personal"},from_date:{type:"string",description:"Start date in YYYY-MM-DD format (optional). If only from_date is provided, it will be treated as a single day."},to_date:{type:"string",description:"End date in YYYY-MM-DD format (optional). Must be at least 1 day after from_date when both are provided."},period:{type:"string",enum:["today","week","month"],description:'Predefined period (optional, overrides from/to dates). Use "today" for single day queries.'}}}},{name:"test_calendar_endpoints",description:"Test both personal and school calendar endpoints",inputSchema:{type:"object",properties:{from_date:{type:"string",description:"Start date in YYYY-MM-DD format (optional). If only from_date is provided, it will be treated as a single day."},to_date:{type:"string",description:"End date in YYYY-MM-DD format (optional). Must be at least 1 day after from_date when both are provided."}}}},{name:"set_cookies",description:"Set authentication cookies for N Lobby access",inputSchema:{type:"object",properties:{cookies:{type:"string",description:"Cookie string from authenticated N Lobby session"}},required:["cookies"]}},{name:"check_cookies",description:"Check if authentication cookies are set",inputSchema:{type:"object",properties:{}}},{name:"health_check",description:"Check if N Lobby API connection is working",inputSchema:{type:"object",properties:{}}},{name:"debug_connection",description:"Debug N Lobby connection with detailed information",inputSchema:{type:"object",properties:{endpoint:{type:"string",description:"Endpoint to test (default: /news)",default:"/news"}}}},{name:"test_page_content",description:"Test page content retrieval and show sample content",inputSchema:{type:"object",properties:{endpoint:{type:"string",description:"Endpoint to test (default: /news)",default:"/news"},length:{type:"number",description:"Number of characters to show (default: 1000)",default:1e3}}}},{name:"test_trpc_endpoint",description:"Test specific tRPC endpoint with detailed response",inputSchema:{type:"object",properties:{method:{type:"string",description:"tRPC method to test (e.g., news.getUnreadNewsCount, user.updateLastAccess)",default:"user.updateLastAccess"},params:{type:"string",description:"JSON string of parameters (optional)"}}}},{name:"verify_authentication",description:"Verify authentication status and cookie synchronization across all clients",inputSchema:{type:"object",properties:{}}},{name:"interactive_login",description:"Open browser for manual login to N Lobby (no credentials required)",inputSchema:{type:"object",properties:{}}},{name:"login_help",description:"Get help and troubleshooting tips for N Lobby login",inputSchema:{type:"object",properties:{email:{type:"string",description:"Your email address (optional, for personalized help)"}}}},{name:"mark_news_as_read",description:"Mark news articles as read",inputSchema:{type:"object",properties:{ids:{type:"array",items:{type:"string"},description:"Array of news article IDs to mark as read"}},required:["ids"]}},{name:"check_exam_day",description:"Check if the specified date (or today if omitted) is an exam day",inputSchema:{type:"object",properties:{date:{type:"string",description:"Date in YYYY-MM-DD format (optional, defaults to today)"}}}},{name:"finish_exam_day_mode",description:"Finish exam day mode",inputSchema:{type:"object",properties:{}}},{name:"get_exam_otp",description:"Get one-time password for exam",inputSchema:{type:"object",properties:{}}},{name:"update_last_access",description:"Update the last access timestamp for the current user",inputSchema:{type:"object",properties:{}}},{name:"get_navigation_menus",description:"Get main navigation menu list",inputSchema:{type:"object",properties:{}}},{name:"get_unread_news_info",description:"Get unread news information including count and important news flags",inputSchema:{type:"object",properties:{}}},{name:"get_notifications",description:"Get notification messages",inputSchema:{type:"object",properties:{}}},{name:"get_user_interests",description:"Get user interest tags (optionally with icon information)",inputSchema:{type:"object",properties:{with_icon:{type:"boolean",description:"Whether to include icon information (optional, default: false)",default:!1}}}},{name:"get_interest_weights",description:"Get interest weight scale definitions",inputSchema:{type:"object",properties:{}}},{name:"get_calendar_filters",description:"Get lobby calendar filter list",inputSchema:{type:"object",properties:{}}}]})),this.server.setRequestHandler(rn,async e=>{let{name:t,arguments:n}=e.params;try{switch(t){case"get_news":try{let{category:r,limit:s=10,sort:a="newest"}=n,c=await this.api.getNews(),l=r?c.filter(u=>u.category===r):c;switch(a){case"oldest":l.sort((u,d)=>new Date(u.publishedAt||0).getTime()-new Date(d.publishedAt||0).getTime());break;case"title-asc":l.sort((u,d)=>(u.title||"").localeCompare(d.title||""));break;case"title-desc":l.sort((u,d)=>(d.title||"").localeCompare(u.title||""));break;case"newest":default:l.sort((u,d)=>new Date(d.publishedAt||0).getTime()-new Date(u.publishedAt||0).getTime());break}return s>0&&(l=l.slice(0,s)),{content:[{type:"text",text:JSON.stringify(l,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}
|
|
75
|
+
- You can close the browser once login is complete`}cleanupExpiredSessions(){let e=Date.now(),t=0;for(let[n,r]of this.credentialStore.entries())e-r.timestamp>this.SESSION_TIMEOUT&&(this.credentialStore.delete(n),t++);t>0&&o.info(`Cleaned up ${t} expired sessions`)}getSessionStats(){let e=Date.now(),t=0;for(let n of this.credentialStore.values())e-n.timestamp>this.SESSION_TIMEOUT&&t++;return{total:this.credentialStore.size,expired:t}}}});var ie={};F(ie,{NLobbyMCPServer:()=>oe});import{Server as rn}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as sn}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as on,ErrorCode as $,ListResourcesRequestSchema as an,ListToolsRequestSchema as cn,McpError as _,ReadResourceRequestSchema as ln,ListPromptsRequestSchema as un,GetPromptRequestSchema as dn}from"@modelcontextprotocol/sdk/types.js";var oe,ae=g(()=>{"use strict";z();E();se();Qe();v();b();oe=class{server;api;browserAuth;credentialManager;constructor(){this.server=new rn({name:m.mcp.serverName,version:m.mcp.serverVersion},{capabilities:{resources:{},tools:{},prompts:{}}}),this.api=new D,this.browserAuth=new I,this.credentialManager=new J,this.setupHandlers()}setupHandlers(){this.server.setRequestHandler(an,async()=>({resources:[{uri:"nlobby://news",name:"School News",description:"Latest school news and notices",mimeType:"application/json"},{uri:"nlobby://schedule",name:"School Schedule",description:"Daily class schedule and events",mimeType:"application/json"},{uri:"nlobby://user-profile",name:"User Profile",description:"Current user information and preferences",mimeType:"application/json"},{uri:"nlobby://required-courses",name:"Required Courses",description:"Required courses and academic information",mimeType:"application/json"}]})),this.server.setRequestHandler(ln,async e=>{let{uri:t}=e.params;try{switch(t){case"nlobby://news":{let n=await this.api.getNews();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://schedule":{let n=await this.api.getSchedule("personal");return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://user-profile":{let n=await this.api.getUserInfo();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}case"nlobby://required-courses":{let n=await this.api.getRequiredCourses();return{contents:[{uri:t,mimeType:"application/json",text:JSON.stringify(n,null,2)}]}}default:throw new _($.InvalidRequest,`Unknown resource: ${t}`)}}catch(n){throw new _($.InternalError,`Failed to read resource: ${n instanceof Error?n.message:"Unknown error"}`)}}),this.server.setRequestHandler(cn,async()=>({tools:[{name:"get_news",description:"Retrieve school news",inputSchema:{type:"object",properties:{category:{type:"string",description:"Filter by category (optional)"},limit:{type:"number",description:"Maximum number of news items to retrieve (optional, default: 10)",minimum:1,default:10},sort:{type:"string",description:"Sort order: 'newest' (default), 'oldest', 'title-asc', 'title-desc'",enum:["newest","oldest","title-asc","title-desc"]}}}},{name:"get_news_detail",description:"Retrieve detailed information for a specific news article",inputSchema:{type:"object",properties:{newsId:{type:"string",description:"The ID of the news article to retrieve"},markAsRead:{type:"boolean",description:"Mark the news article as read (optional, default: false)",default:!1}},required:["newsId"]}},{name:"get_account_info",description:"Extract account information by parsing Next.js flight data from a rendered page",inputSchema:{type:"object",properties:{}}},{name:"get_student_card_screenshot",description:"Capture a screenshot of the student ID card by following the secure portal redirect flow",inputSchema:{type:"object",properties:{}}},{name:"get_required_courses",description:"Retrieve required courses information with detailed progress tracking",inputSchema:{type:"object",properties:{grade:{type:"number",description:"Filter by grade level (1, 2, or 3) (optional)"},semester:{type:"string",description:'Filter by term year (e.g., "2024", "2025") (optional)'},category:{type:"string",description:'Filter by curriculum category (e.g., "\u56FD\u8A9E", "\u6570\u5B66", "\u82F1\u8A9E") (optional)'}}}},{name:"get_schedule",description:"Get school schedule for a specific date (backward compatibility)",inputSchema:{type:"object",properties:{date:{type:"string",description:"Date in YYYY-MM-DD format (optional, defaults to today)"}}}},{name:"get_calendar_events",description:"Get calendar events with advanced options",inputSchema:{type:"object",properties:{calendar_type:{type:"string",enum:["personal","school"],description:"Type of calendar to retrieve (personal or school)",default:"personal"},from_date:{type:"string",description:"Start date in YYYY-MM-DD format (optional). If only from_date is provided, it will be treated as a single day."},to_date:{type:"string",description:"End date in YYYY-MM-DD format (optional). Must be at least 1 day after from_date when both are provided."},period:{type:"string",enum:["today","week","month"],description:'Predefined period (optional, overrides from/to dates). Use "today" for single day queries.'}}}},{name:"test_calendar_endpoints",description:"Test both personal and school calendar endpoints",inputSchema:{type:"object",properties:{from_date:{type:"string",description:"Start date in YYYY-MM-DD format (optional). If only from_date is provided, it will be treated as a single day."},to_date:{type:"string",description:"End date in YYYY-MM-DD format (optional). Must be at least 1 day after from_date when both are provided."}}}},{name:"set_cookies",description:"Set authentication cookies for N Lobby access",inputSchema:{type:"object",properties:{cookies:{type:"string",description:"Cookie string from authenticated N Lobby session"}},required:["cookies"]}},{name:"check_cookies",description:"Check if authentication cookies are set",inputSchema:{type:"object",properties:{}}},{name:"health_check",description:"Check if N Lobby API connection is working",inputSchema:{type:"object",properties:{}}},{name:"debug_connection",description:"Debug N Lobby connection with detailed information",inputSchema:{type:"object",properties:{endpoint:{type:"string",description:"Endpoint to test (default: /news)",default:"/news"}}}},{name:"test_page_content",description:"Test page content retrieval and show sample content",inputSchema:{type:"object",properties:{endpoint:{type:"string",description:"Endpoint to test (default: /news)",default:"/news"},length:{type:"number",description:"Number of characters to show (default: 1000)",default:1e3}}}},{name:"test_trpc_endpoint",description:"Test specific tRPC endpoint with detailed response",inputSchema:{type:"object",properties:{method:{type:"string",description:"tRPC method to test (e.g., news.getUnreadNewsCount, user.updateLastAccess)",default:"user.updateLastAccess"},params:{type:"string",description:"JSON string of parameters (optional)"}}}},{name:"verify_authentication",description:"Verify authentication status and cookie synchronization across all clients",inputSchema:{type:"object",properties:{}}},{name:"interactive_login",description:"Open browser for manual login to N Lobby (no credentials required)",inputSchema:{type:"object",properties:{}}},{name:"login_help",description:"Get help and troubleshooting tips for N Lobby login",inputSchema:{type:"object",properties:{email:{type:"string",description:"Your email address (optional, for personalized help)"}}}},{name:"mark_news_as_read",description:"Mark news articles as read",inputSchema:{type:"object",properties:{ids:{type:"array",items:{type:"string"},description:"Array of news article IDs to mark as read"}},required:["ids"]}},{name:"check_exam_day",description:"Check if the specified date (or today if omitted) is an exam day",inputSchema:{type:"object",properties:{date:{type:"string",description:"Date in YYYY-MM-DD format (optional, defaults to today)"}}}},{name:"finish_exam_day_mode",description:"Finish exam day mode",inputSchema:{type:"object",properties:{}}},{name:"get_exam_otp",description:"Get one-time password for exam",inputSchema:{type:"object",properties:{}}},{name:"update_last_access",description:"Update the last access timestamp for the current user",inputSchema:{type:"object",properties:{}}},{name:"get_navigation_menus",description:"Get main navigation menu list",inputSchema:{type:"object",properties:{}}},{name:"get_unread_news_info",description:"Get unread news information including count and important news flags",inputSchema:{type:"object",properties:{}}},{name:"get_notifications",description:"Get notification messages",inputSchema:{type:"object",properties:{}}},{name:"get_user_interests",description:"Get user interest tags (optionally with icon information)",inputSchema:{type:"object",properties:{with_icon:{type:"boolean",description:"Whether to include icon information (optional, default: false)",default:!1}}}},{name:"get_interest_weights",description:"Get interest weight scale definitions",inputSchema:{type:"object",properties:{}}},{name:"get_calendar_filters",description:"Get lobby calendar filter list",inputSchema:{type:"object",properties:{}}}]})),this.server.setRequestHandler(on,async e=>{let{name:t,arguments:n}=e.params;try{switch(t){case"get_news":try{let{category:r,limit:i=10,sort:a="newest"}=n,c=await this.api.getNews(),l=r?c.filter(u=>u.category===r):c;switch(a){case"oldest":l.sort((u,d)=>new Date(u.publishedAt||0).getTime()-new Date(d.publishedAt||0).getTime());break;case"title-asc":l.sort((u,d)=>(u.title||"").localeCompare(d.title||""));break;case"title-desc":l.sort((u,d)=>(d.title||"").localeCompare(u.title||""));break;case"newest":default:l.sort((u,d)=>new Date(d.publishedAt||0).getTime()-new Date(u.publishedAt||0).getTime());break}return i>0&&(l=l.slice(0,i)),{content:[{type:"text",text:JSON.stringify(l,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}
|
|
76
76
|
|
|
77
77
|
To authenticate:
|
|
78
78
|
1. Login to N Lobby in your browser
|
|
79
79
|
2. Open Developer Tools (F12)
|
|
80
80
|
3. Go to Application/Storage tab
|
|
81
81
|
4. Copy cookies and use the set_cookies tool
|
|
82
|
-
5. Use health_check to verify connection`}]}}case"get_news_detail":try{let{newsId:r,markAsRead:
|
|
82
|
+
5. Use health_check to verify connection`}]}}case"get_news_detail":try{let{newsId:r,markAsRead:i=!1}=n,a=await this.api.getNewsDetail(r);if(i)try{await this.api.markNewsAsRead(r)}catch(c){o.error(`Failed to mark news ${r} as read:`,c)}return{content:[{type:"text",text:JSON.stringify(a,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_account_info":try{let r=await this.api.getAccountInfoFromScript();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_student_card_screenshot":try{let r=await this.api.getStudentCardScreenshot();return{content:[{type:"text",text:JSON.stringify({message:"Student card screenshot captured successfully. Image data attached as base64.",filePath:r.path,studentNo:r.studentNo,secureHost:r.secureHost,callbackUrl:r.callbackUrl,finalUrl:r.finalUrl,elementSize:r.elementSize},null,2)},{type:"image",mimeType:"image/png",data:r.base64}]}}catch(r){return{content:[{type:"text",text:`Error capturing student card screenshot: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_required_courses":try{let{grade:r,semester:i,category:a}=n,l=await this.api.getRequiredCourses();if(r!==void 0){let d=r===1?"1\u5E74\u6B21":r===2?"2\u5E74\u6B21":r===3?"3\u5E74\u6B21":`${r}\u5E74\u6B21`;l=l.filter(h=>h.grade===d)}i&&(l=l.filter(d=>d.termYear&&d.termYear.toString().includes(i))),a&&(l=l.filter(d=>d.curriculumName&&d.curriculumName.toLowerCase().includes(a.toLowerCase())));let u={totalCourses:l.length,filters:{grade:r,semester:i,category:a},coursesByGrade:this.groupCoursesByGrade(l),coursesByCurriculum:this.groupCoursesByCurriculum(l),completedCourses:l.filter(d=>d.isCompleted).length,inProgressCourses:l.filter(d=>d.isInProgress).length,courses:l};return{content:[{type:"text",text:JSON.stringify(u,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_schedule":try{let{date:r}=n,i=await this.api.getScheduleByDate(r);return{content:[{type:"text",text:JSON.stringify(i,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_calendar_events":try{let{calendar_type:r,from_date:i,to_date:a,period:c}=n,l=r==="school"?"school":"personal",u;if(c)switch(c){case"today":{let h=new Date;u=this.api.createSingleDayRange(h);break}case"week":u=this.api.createWeekDateRange();break;case"month":u=this.api.createMonthDateRange();break;default:throw new Error(`Invalid period: ${c}`)}else i&&a?u=this.api.createDateRange(i,a):i&&(u=this.api.createSingleDayRange(i));let d=await this.api.getSchedule(l,u);return{content:[{type:"text",text:`[DATE] Calendar Events (${r||"personal"})${u?` from ${u.from.toDateString()} to ${u.to.toDateString()}`:" (current week)"}
|
|
83
83
|
|
|
84
|
-
${JSON.stringify(d,null,2)}`}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"test_calendar_endpoints":try{let{from_date:r,to_date:
|
|
85
|
-
`)}]}}catch(r){return{content:[{type:"text",text:`Error testing calendar endpoints: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"set_cookies":{let{cookies:r}=n;return this.api.setCookies(r),{content:[{type:"text",text:"Authentication cookies have been set. You can now access real N Lobby data."}]}}case"check_cookies":return{content:[{type:"text",text:`Cookie status: ${this.api.getCookieStatus()}`}]};case"health_check":return{content:[{type:"text",text:`N Lobby API connection: ${await this.api.healthCheck()?"healthy":"failed"}`}]};case"debug_connection":{let{endpoint:r}=n;return{content:[{type:"text",text:await this.api.debugConnection(r||"/news")}]}}case"test_page_content":{let{endpoint:r,length:
|
|
84
|
+
${JSON.stringify(d,null,2)}`}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"test_calendar_endpoints":try{let{from_date:r,to_date:i}=n,a;r&&i?a=this.api.createDateRange(r,i):r&&(a=this.api.createSingleDayRange(r));let c=await this.api.testCalendarEndpoints(a);return{content:[{type:"text",text:["[TEST] Calendar Endpoints Test Results","=".repeat(40),"",`[DATE] Test Period: ${a?`${a.from.toDateString()} to ${a.to.toDateString()}`:"Current week (default)"}`,"","[PERSONAL] Personal Calendar:",` Status: ${c.personal.success?"[SUCCESS] Success":"[ERROR] Failed"}`,` Events: ${c.personal.count}`,c.personal.error?` Error: ${c.personal.error}`:"","","[SCHOOL] School Calendar:",` Status: ${c.school.success?"[SUCCESS] Success":"[ERROR] Failed"}`,` Events: ${c.school.count}`,c.school.error?` Error: ${c.school.error}`:"","","[STATUS] Summary:"," Total Endpoints: 2",` Successful: ${(c.personal.success?1:0)+(c.school.success?1:0)}`,` Failed: ${(c.personal.success?0:1)+(c.school.success?0:1)}`,` Total Events: ${c.personal.count+c.school.count}`].filter(Boolean).join(`
|
|
85
|
+
`)}]}}catch(r){return{content:[{type:"text",text:`Error testing calendar endpoints: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"set_cookies":{let{cookies:r}=n;return this.api.setCookies(r),{content:[{type:"text",text:"Authentication cookies have been set. You can now access real N Lobby data."}]}}case"check_cookies":return{content:[{type:"text",text:`Cookie status: ${this.api.getCookieStatus()}`}]};case"health_check":return{content:[{type:"text",text:`N Lobby API connection: ${await this.api.healthCheck()?"healthy":"failed"}`}]};case"debug_connection":{let{endpoint:r}=n;return{content:[{type:"text",text:await this.api.debugConnection(r||"/news")}]}}case"test_page_content":{let{endpoint:r,length:i}=n,a=await this.api.testPageContent(r||"/news",i||1e3);return{content:[{type:"text",text:`Sample content from ${r||"/news"}:
|
|
86
86
|
|
|
87
|
-
${a}`}]}}case"test_trpc_endpoint":{let{method:r,params:
|
|
87
|
+
${a}`}]}}case"test_trpc_endpoint":{let{method:r,params:i}=n;try{let a=i?JSON.parse(i):{},c=await this.api.testTrpcEndpoint(r,a);return{content:[{type:"text",text:`Result of ${r} with params ${JSON.stringify(a)}:
|
|
88
88
|
|
|
89
89
|
${JSON.stringify(c,null,2)}`}]}}catch(a){return{content:[{type:"text",text:`Error testing tRPC endpoint ${r}: ${a instanceof Error?a.message:"Unknown error"}`}]}}}case"verify_authentication":return{content:[{type:"text",text:`[INFO] Authentication Verification Report
|
|
90
90
|
|
|
@@ -98,31 +98,31 @@ Extracted cookies:
|
|
|
98
98
|
- CSRF Token: ${r.csrfToken?"present":"missing"}
|
|
99
99
|
- Callback URL: ${r.callbackUrl||"not set"}
|
|
100
100
|
|
|
101
|
-
You can now access real N Lobby data using other tools.`}]}}catch(r){return await this.browserAuth.close(),{content:[{type:"text",text:`[ERROR] Interactive login failed: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"login_help":{let{email:r}=n,
|
|
101
|
+
You can now access real N Lobby data using other tools.`}]}}catch(r){return await this.browserAuth.close(),{content:[{type:"text",text:`[ERROR] Interactive login failed: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"login_help":{let{email:r}=n,i=`[LOGIN] N Lobby Login Help
|
|
102
102
|
|
|
103
|
-
`;if(r){let c=this.credentialManager.validateEmail(r);
|
|
104
|
-
`,
|
|
105
|
-
`,
|
|
103
|
+
`;if(r){let c=this.credentialManager.validateEmail(r);i+=`[EMAIL] Email: ${r}
|
|
104
|
+
`,i+=`[USER] User Type: ${c.userType}
|
|
105
|
+
`,i+=`[SUCCESS] Valid: ${c.valid?"Yes":"No"}
|
|
106
106
|
|
|
107
|
-
`,c.valid||(
|
|
107
|
+
`,c.valid||(i+=`[ERROR] Issue: ${c.message}
|
|
108
108
|
|
|
109
|
-
`),
|
|
109
|
+
`),i+=this.credentialManager.getLoginGuidance(c.userType)}else i+=this.credentialManager.getLoginGuidance("unknown");i+=`
|
|
110
110
|
|
|
111
|
-
${this.credentialManager.getTroubleshootingTips()}`;let a=this.credentialManager.getSessionStats();return
|
|
111
|
+
${this.credentialManager.getTroubleshootingTips()}`;let a=this.credentialManager.getSessionStats();return i+=`
|
|
112
112
|
|
|
113
113
|
[STATUS] Session Stats:
|
|
114
114
|
- Active sessions: ${a.total-a.expired}
|
|
115
|
-
- Expired sessions: ${a.expired}`,{content:[{type:"text",text:
|
|
115
|
+
- Expired sessions: ${a.expired}`,{content:[{type:"text",text:i}]}}case"mark_news_as_read":try{let{ids:r}=n;if(!r||r.length===0)return{content:[{type:"text",text:"Error: No news article IDs provided."}]};let i=[],a=[];for(let l of r)try{await this.api.markNewsAsRead(l),i.push(l)}catch(u){a.push({id:l,error:u instanceof Error?u.message:"Unknown error"})}let c="";return i.length>0&&(c+=`Successfully marked ${i.length} news article(s) as read: ${i.join(", ")}
|
|
116
116
|
`),a.length>0&&(c+=`
|
|
117
117
|
Failed to mark ${a.length} news article(s) as read:
|
|
118
118
|
`,a.forEach(({id:l,error:u})=>{c+=`- ${l}: ${u}
|
|
119
|
-
`})),{content:[{type:"text",text:c.trim()}]}}catch(r){return{content:[{type:"text",text:`Error marking news as read: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"check_exam_day":try{let{date:r}=n,
|
|
120
|
-
`)}groupCoursesByGrade(e){let t={};for(let n of e){let r=n.grade||"Unknown";t[r]=(t[r]||0)+1}return t}groupCoursesByCurriculum(e){let t={};for(let n of e){let r=n.curriculumName||"Unknown";t[r]=(t[r]||0)+1}return t}}});import{Command as
|
|
121
|
-
`).trimEnd()}function
|
|
122
|
-
|
|
123
|
-
`).trim();e.push(n)}if(
|
|
124
|
-
`)}var
|
|
125
|
-
`).trimEnd()}function
|
|
126
|
-
`).trimEnd()}var
|
|
127
|
-
`).trimEnd()}var
|
|
128
|
-
`)}var
|
|
119
|
+
`})),{content:[{type:"text",text:c.trim()}]}}catch(r){return{content:[{type:"text",text:`Error marking news as read: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"check_exam_day":try{let{date:r}=n,i=r?new Date(r):void 0,a=await this.api.isExamDay(i);return{content:[{type:"text",text:JSON.stringify({date:i?i.toISOString().split("T")[0]:new Date().toISOString().split("T")[0],isExamDay:a},null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"finish_exam_day_mode":try{let r=await this.api.finishExamDayMode();return{content:[{type:"text",text:JSON.stringify({success:r},null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_exam_otp":try{let r=await this.api.getExamOneTimePassword();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"update_last_access":try{let r=await this.api.updateLastAccess();return{content:[{type:"text",text:JSON.stringify({success:r},null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_navigation_menus":try{let r=await this.api.getMainNavigations();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_unread_news_info":try{let r=await this.api.getUnreadNewsInfo();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_notifications":try{let r=await this.api.getNotificationMessages();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_user_interests":try{let{with_icon:r=!1}=n,i=await this.api.getUserInterests(r);return{content:[{type:"text",text:JSON.stringify(i,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_interest_weights":try{let r=await this.api.getInterestWeights();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"get_calendar_filters":try{let r=await this.api.getLobbyCalendarFilters();return{content:[{type:"text",text:JSON.stringify(r,null,2)}]}}catch(r){return{content:[{type:"text",text:`Error: ${r instanceof Error?r.message:"Unknown error"}`}]}}default:throw new _($.MethodNotFound,`Unknown tool: ${t}`)}}catch(r){throw new _($.InternalError,`Tool execution failed: ${r instanceof Error?r.message:"Unknown error"}`)}}),this.server.setRequestHandler(un,async()=>({prompts:[]})),this.server.setRequestHandler(dn,async e=>{let{name:t}=e.params;throw new _($.InvalidRequest,`Unknown prompt: ${t}`)})}async start(){try{let e=new sn;await this.server.connect(e),o.info("N Lobby MCP Server started successfully")}catch(e){o.error("Failed to start server:",e),process.exit(1)}}getAuthenticationRecommendations(){let e=this.api.getCookieStatus(),t=[];return e.includes("[ERROR] no cookies")&&e.includes("[ERROR] not authenticated")?(t.push("1. Run interactive_login to authenticate with N Lobby"),t.push("2. Make sure to complete the login process in the browser window"),t.push('3. Wait for the "Login successful" message before proceeding')):e.includes("[ERROR] not synchronized")?(t.push("1. Cookie synchronization issue detected"),t.push("2. Try running interactive_login again to refresh all cookies")):e.includes("[SUCCESS] authenticated")&&e.includes("[SUCCESS] synchronized")?(t.push("1. Authentication appears to be working correctly"),t.push("2. If endpoints are still failing, the issue may be server-side"),t.push("3. Try running health_check to verify connectivity")):(t.push("1. Check the authentication status above for specific issues"),t.push("2. Run health_check to verify overall system health")),t.join(`
|
|
120
|
+
`)}groupCoursesByGrade(e){let t={};for(let n of e){let r=n.grade||"Unknown";t[r]=(t[r]||0)+1}return t}groupCoursesByCurriculum(e){let t={};for(let n of e){let r=n.curriculumName||"Unknown";t[r]=(t[r]||0)+1}return t}}});import{Command as Ze}from"commander";function et(s){return new Ze("login").description("Authenticate with N Lobby via browser").action(async()=>{console.log("Opening browser for N Lobby authentication...");try{let t=new I;await t.initializeBrowser();let n=await t.interactiveLogin();n&&n.allCookies?(s.setCookies(n.allCookies),re(n.allCookies),console.log("[OK] Login successful. Session saved.")):(console.error("[FAIL] Login failed or was cancelled."),process.exit(1))}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}})}function tt(s){let e=new Ze("cookies").description("Manage authentication cookies");return e.command("set <cookies>").description("Set cookies manually").action(t=>{s.setCookies(t),re(t),console.log("[OK] Cookies saved.")}),e.command("check").description("Show current cookie/authentication status").action(()=>{console.log(s.getCookieStatus())}),e}var nt=g(()=>{"use strict";z();se()});function rt(s){if(s.length===0)return"No news found.";let e=[];for(let t of s){let n=new Date(t.publishedAt).toLocaleDateString("ja-JP"),r=t.isUnread?" [UNREAD]":"",i=t.isImportant?" [!]":"";e.push(`[${t.id}] ${n}${i}${r}`),e.push(` ${t.title}`),t.menuName&&e.push(` Category: ${t.menuName}`),e.push("")}return e.join(`
|
|
121
|
+
`).trimEnd()}function st(s){let e=[],t=new Date(s.publishedAt).toLocaleDateString("ja-JP");if(e.push(`Title: ${s.title}`),e.push(`Date: ${t}`),e.push(`Category: ${s.menuName.join(", ")}`),s.isImportant&&e.push("Important: Yes"),e.push(`URL: ${s.url}`),e.push(""),e.push("\u2500".repeat(50)),e.push(""),s.description)e.push(s.description);else{let n=s.content.replace(/<[^>]+>/g,"").replace(/ /g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/\n{3,}/g,`
|
|
122
|
+
|
|
123
|
+
`).trim();e.push(n)}if(s.attachments&&s.attachments.length>0){e.push(""),e.push("Attachments:");for(let n of s.attachments)e.push(` - ${n.fileName}: ${n.href}`)}return e.join(`
|
|
124
|
+
`)}var ot=g(()=>{"use strict"});import{Command as pn}from"commander";function it(s){let e=new pn("news").description("N Lobby news");return e.command("list",{isDefault:!0}).description("List news").option("--limit <n>","Number of items to show","10").option("--category <cat>","Filter by category").option("--sort <order>","Sort order: newest|oldest|title-asc|title-desc","newest").option("--unread","Show only unread items").option("--json","Output raw JSON").action(async t=>{try{let n=await s.getNews();if(t.unread&&(n=n.filter(i=>i.isUnread)),t.category){let i=t.category.toLowerCase();n=n.filter(a=>a.category.toLowerCase().includes(i)||(a.menuName??"").toLowerCase().includes(i))}switch(t.sort){case"oldest":n.sort((i,a)=>new Date(i.publishedAt).getTime()-new Date(a.publishedAt).getTime());break;case"title-asc":n.sort((i,a)=>i.title.localeCompare(a.title));break;case"title-desc":n.sort((i,a)=>a.title.localeCompare(i.title));break;default:n.sort((i,a)=>new Date(a.publishedAt).getTime()-new Date(i.publishedAt).getTime())}let r=parseInt(t.limit,10);n=n.slice(0,r),t.json?console.log(JSON.stringify(n,null,2)):console.log(rt(n))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e.command("show <id>").description("Show news detail").option("--json","Output raw JSON").action(async(t,n)=>{try{let r=await s.getNewsDetail(t);n.json?console.log(JSON.stringify(r,null,2)):console.log(st(r))}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}}),e.command("read <id>").description("Mark news as read").action(async t=>{try{await s.markNewsAsRead(t),console.log(`[OK] Marked ${t} as read.`)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e}var at=g(()=>{"use strict";ot()});function Y(s){return s.toLocaleTimeString("ja-JP",{hour:"2-digit",minute:"2-digit"})}function ct(s){return s.toLocaleDateString("ja-JP",{year:"numeric",month:"2-digit",day:"2-digit",weekday:"short"})}function lt(s){if(s.length===0)return"No schedule items found.";let e=new Map;for(let n of s){let r=ct(new Date(n.startTime)),i=e.get(r)??[];i.push(n),e.set(r,i)}let t=[];for(let[n,r]of e){t.push(`\u2500\u2500 ${n} \u2500\u2500`);for(let i of r){let a=Y(new Date(i.startTime)),c=Y(new Date(i.endTime));t.push(` ${a}\u2013${c} ${i.title}`),i.location&&t.push(` Location: ${i.location}`),i.description&&t.push(` ${i.description}`)}t.push("")}return t.join(`
|
|
125
|
+
`).trimEnd()}function ut(s){if(s.length===0)return"No calendar events found.";let e=[];for(let t of s){let n=t.start.dateTime??t.start.date??"",r=t.end.dateTime??t.end.date??"",i=!t.start.dateTime,a;if(i)a=n;else{let c=new Date(n),l=new Date(r);a=`${ct(c)} ${Y(c)}\u2013${Y(l)}`}if(e.push(`[${t.id}] ${t.summary}`),e.push(` ${a}`),t.location&&e.push(` Location: ${t.location}`),t.description){let c=t.description.replace(/<[^>]+>/g,"").trim();c&&e.push(` ${c}`)}e.push("")}return e.join(`
|
|
126
|
+
`).trimEnd()}var dt=g(()=>{"use strict"});import{Command as pt}from"commander";function gt(s){return new pt("schedule").description("Show schedule for a date (default: today)").argument("[date]","Date in YYYY-MM-DD format (default: today)").option("--json","Output raw JSON").action(async(t,n)=>{try{let r=await s.getScheduleByDate(t);n.json?console.log(JSON.stringify(r,null,2)):console.log(lt(r))}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}})}function mt(s){return new pt("calendar").description("Show calendar events").option("--from <date>","Start date (YYYY-MM-DD)").option("--to <date>","End date (YYYY-MM-DD)").option("--type <type>","Calendar type: personal|school (default: personal)","personal").option("--json","Output raw JSON").action(async t=>{try{let n=t.type==="school"?"school":"personal",r=t.from&&t.to?s.createDateRange(t.from,t.to):s.createWeekDateRange(),i=await s.getGoogleCalendarEvents(n,r);t.json?console.log(JSON.stringify(i,null,2)):console.log(ut(i))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}})}var ht=g(()=>{"use strict";v();dt()});function gn(s){switch(s){case 0:return"Not Started";case 1:return"In Progress";case 2:return"Completed";default:return`Status ${s}`}}function ft(s){if(s.length===0)return"No courses found.";let e=[],t=new Map;for(let n of s){let r=n.grade?`Grade ${n.grade}${n.term!=null?` / Term ${n.term}`:""}`:"Courses",i=t.get(r)??[];i.push(n),t.set(r,i)}for(let[n,r]of t){e.push(`\u2500\u2500 ${n} \u2500\u2500`);for(let i of r){let a=gn(i.subjectStatus),c=i.progressPercentage!=null?` (${i.progressPercentage.toFixed(0)}%)`:"";e.push(` [${i.subjectCode}] ${i.subjectName}`),e.push(` Curriculum: ${i.curriculumName}`),e.push(` Status: ${a}${c}`),e.push(` Reports: ${i.report.count}/${i.report.allCount}`),i.schooling.necessaryCount>0&&e.push(` Attendance: ${i.schooling.attendanceCount}/${i.schooling.necessaryCount}`),i.averageScore!=null&&e.push(` Avg Score: ${i.averageScore.toFixed(1)}`);let l=i.acquired.approvedCredit;l>0&&e.push(` Credits: ${l}`),e.push("")}}return e.join(`
|
|
127
|
+
`).trimEnd()}var yt=g(()=>{"use strict"});import{Command as mn}from"commander";function wt(s){return new mn("courses").description("Show required courses").option("--grade <n>","Filter by grade").option("--semester <n>","Filter by semester/term").option("--json","Output raw JSON").action(async t=>{try{let n=await s.getRequiredCourses();t.grade&&(n=n.filter(r=>String(r.grade)===t.grade)),t.semester&&(n=n.filter(r=>String(r.term)===t.semester)),t.json?console.log(JSON.stringify(n,null,2)):console.log(ft(n))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}})}var bt=g(()=>{"use strict";yt()});function Ct(s){let e=[];return e.push("\u2500\u2500 Account Information \u2500\u2500"),e.push(`Name: ${s.name??"(unknown)"}`),e.push(`Email: ${s.email??"(unknown)"}`),e.push(`Role: ${s.role??"(unknown)"}`),s.studentNo&&e.push(`Student No: ${s.studentNo}`),s.userId&&e.push(`User ID: ${s.userId}`),s.grade!=null&&e.push(`Grade: ${s.grade}`),s.term!=null&&e.push(`Term: ${s.term}`),s.isLobbyAdmin&&e.push("Admin: Yes"),typeof s.kmsLoginSuccess=="boolean"&&e.push(`KMS Login: ${s.kmsLoginSuccess?"OK":"Failed"}`),Array.isArray(s.studentOrganizations)&&s.studentOrganizations.length>0&&e.push(`Organizations: ${s.studentOrganizations.length}`),Array.isArray(s.staffDepartments)&&s.staffDepartments.length>0&&e.push(`Departments: ${s.staffDepartments.length}`),e.join(`
|
|
128
|
+
`)}var kt=g(()=>{"use strict"});import{Command as hn}from"commander";function St(s){return new hn("profile").description("Show user profile and account information").option("--json","Output raw JSON").action(async t=>{try{let n=await s.getAccountInfoFromScript("/");t.json?console.log(JSON.stringify(n,null,2)):console.log(Ct(n))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}})}var Rt=g(()=>{"use strict";kt()});function Nt(s){return s?"[OK] N Lobby API is reachable and authenticated.":"[FAIL] N Lobby API health check failed. Run `nlobby login` or `nlobby cookies set <cookies>` to authenticate."}var Et=g(()=>{"use strict"});import{Command as fn}from"commander";function xt(s){return new fn("health").description("Check N Lobby API connectivity and authentication").option("--json","Output raw JSON").action(async t=>{try{let n=await s.healthCheck();t.json?console.log(JSON.stringify({ok:n},null,2)):console.log(Nt(n)),n||process.exit(1)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}})}var At=g(()=>{"use strict";Et()});import{Command as yn}from"commander";function Tt(){return new yn("serve").alias("mcp").description("Start the MCP server (stdio transport)").action(async()=>{let{logger:e}=await Promise.resolve().then(()=>(b(),V));e.forceProductionMode();let{NLobbyMCPServer:t}=await Promise.resolve().then(()=>(ae(),ie));await new t().start()})}var vt=g(()=>{"use strict"});var It={};F(It,{buildProgram:()=>Dt,runCli:()=>bn});import{Command as wn}from"commander";function Dt(){let s=new D,e=new wn().name("nlobby").description("N Lobby CLI \u2014 access N Lobby from the command line").version("1.4.0");return e.addCommand(et(s)),e.addCommand(tt(s)),e.addCommand(it(s)),e.addCommand(gt(s)),e.addCommand(mt(s)),e.addCommand(wt(s)),e.addCommand(St(s)),e.addCommand(xt(s)),e.addCommand(Tt()),e}async function bn(){await Dt().parseAsync(process.argv)}var Lt=g(()=>{"use strict";z();nt();at();ht();bt();Rt();At();vt()});var ce=process.argv.slice(2),Cn=ce[0]==="serve"||ce[0]==="mcp",kn=ce.length===0&&!process.stdin.isTTY;async function Sn(){if(Cn||kn){let{logger:s}=await Promise.resolve().then(()=>(b(),V));s.forceProductionMode();let{NLobbyMCPServer:e}=await Promise.resolve().then(()=>(ae(),ie));await new e().start()}else{let{runCli:s}=await Promise.resolve().then(()=>(Lt(),It));await s()}}Sn().catch(s=>{console.error("Fatal error:",s instanceof Error?s.message:s),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nlobby-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.1",
|
|
4
4
|
"description": "CLI and MCP server for N Lobby school portal",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -16,15 +16,15 @@
|
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "https://github.com/minagishl/nlobby-
|
|
19
|
+
"url": "https://github.com/minagishl/nlobby-cli.git"
|
|
20
20
|
},
|
|
21
|
-
"homepage": "https://github.com/minagishl/nlobby-
|
|
21
|
+
"homepage": "https://github.com/minagishl/nlobby-cli#readme",
|
|
22
22
|
"bugs": {
|
|
23
|
-
"url": "https://github.com/minagishl/nlobby-
|
|
23
|
+
"url": "https://github.com/minagishl/nlobby-cli/issues"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"@modelcontextprotocol/sdk": "^0.6.0",
|
|
27
|
-
"
|
|
27
|
+
"node-fetch": "^3.3.2",
|
|
28
28
|
"cheerio": "^1.0.0",
|
|
29
29
|
"commander": "^12.1.0",
|
|
30
30
|
"dotenv": "^16.3.1",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"dev": "tsc --watch",
|
|
63
63
|
"start": "node dist/index.js",
|
|
64
64
|
"test": "jest",
|
|
65
|
-
"lint": "eslint src
|
|
65
|
+
"lint": "eslint src",
|
|
66
66
|
"format": "prettier --write ."
|
|
67
67
|
}
|
|
68
68
|
}
|