nlobby-cli 1.4.3 → 1.4.5
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/SKILLS.md +69 -15
- package/dist/index.js +43 -43
- package/package.json +1 -1
package/SKILLS.md
CHANGED
|
@@ -2,23 +2,77 @@
|
|
|
2
2
|
|
|
3
3
|
## CLI Commands
|
|
4
4
|
|
|
5
|
-
| Command | Options / Arguments | Description |
|
|
6
|
-
| ------------------------------ | --------------------------------------------------------------------------------------------------- | ------------------------------------------ |
|
|
7
|
-
| `nlobby login` | | Open browser for interactive login |
|
|
8
|
-
| `nlobby cookies set <cookies>` | | Set cookies manually |
|
|
9
|
-
| `nlobby cookies check` | | Show current authentication status |
|
|
10
|
-
| `nlobby news` | `--limit <n>` `--category <cat>` `--sort newest\|oldest\|title-asc\|title-desc` `--unread` `--json` | List news (default: 10, newest first) |
|
|
11
|
-
| `nlobby news show <id>` | `--json` | Show news article detail |
|
|
12
|
-
| `nlobby news read <id>` | | Mark news article as read |
|
|
13
|
-
| `nlobby schedule [date]` | `--json` | Show schedule (YYYY-MM-DD, default: today) |
|
|
14
|
-
| `nlobby calendar` | `--from <date>` `--to <date>` `--type personal\|school` `--json` | Show calendar events (default: this week) |
|
|
15
|
-
| `nlobby courses` | `--grade <n>` `--semester <n>` `--json` | Show required courses |
|
|
16
|
-
| `nlobby profile` | `--json` | Show user profile / account info |
|
|
17
|
-
| `nlobby health` | `--json` | Check API connectivity and authentication |
|
|
18
|
-
| `nlobby serve` / `nlobby mcp` | | Start MCP server (stdio transport) |
|
|
19
|
-
|
|
20
5
|
> All commands support `--json` to output raw JSON instead of formatted text.
|
|
21
6
|
|
|
7
|
+
### Auth
|
|
8
|
+
|
|
9
|
+
| Command | Options / Arguments | Description |
|
|
10
|
+
| ------------------------------ | ------------------- | ----------------------------------- |
|
|
11
|
+
| `nlobby login` | | Open browser for interactive login |
|
|
12
|
+
| `nlobby login-help` | `--email <email>` | Login help and troubleshooting tips |
|
|
13
|
+
| `nlobby cookies set <cookies>` | | Set cookies manually |
|
|
14
|
+
| `nlobby cookies check` | | Show current authentication status |
|
|
15
|
+
|
|
16
|
+
### News
|
|
17
|
+
|
|
18
|
+
| Command | Options / Arguments | Description |
|
|
19
|
+
| ------------------------- | --------------------------------------------------------------------------------------------------- | --------------------------------- |
|
|
20
|
+
| `nlobby news` | `--limit <n>` `--category <cat>` `--sort newest\|oldest\|title-asc\|title-desc` `--unread` `--json` | List news (default: 10, newest) |
|
|
21
|
+
| `nlobby news show <id>` | `--json` | Show news article detail |
|
|
22
|
+
| `nlobby news read <ids…>` | | Mark one or more articles as read |
|
|
23
|
+
| `nlobby news unread-info` | `--json` | Show unread count and flags |
|
|
24
|
+
|
|
25
|
+
### Schedule & Calendar
|
|
26
|
+
|
|
27
|
+
| Command | Options / Arguments | Description |
|
|
28
|
+
| ------------------------- | ---------------------------------------------------------------- | ------------------------------------------ |
|
|
29
|
+
| `nlobby schedule [date]` | `--json` | Show schedule (YYYY-MM-DD, default: today) |
|
|
30
|
+
| `nlobby calendar` | `--from <date>` `--to <date>` `--type personal\|school` `--json` | Show calendar events (default: this week) |
|
|
31
|
+
| `nlobby calendar test` | `--from <date>` `--to <date>` `--json` | Test both calendar endpoints |
|
|
32
|
+
| `nlobby calendar filters` | `--json` | Show lobby calendar filter list |
|
|
33
|
+
|
|
34
|
+
### Courses & Exam
|
|
35
|
+
|
|
36
|
+
| Command | Options / Arguments | Description |
|
|
37
|
+
| -------------------------- | --------------------------------------- | ------------------------------ |
|
|
38
|
+
| `nlobby courses` | `--grade <n>` `--semester <n>` `--json` | Show required courses |
|
|
39
|
+
| `nlobby exam check [date]` | `--json` | Check if a date is an exam day |
|
|
40
|
+
| `nlobby exam finish` | `--json` | Finish exam day mode |
|
|
41
|
+
| `nlobby exam otp` | `--json` | Get one-time password for exam |
|
|
42
|
+
|
|
43
|
+
### Profile
|
|
44
|
+
|
|
45
|
+
| Command | Options / Arguments | Description |
|
|
46
|
+
| ------------------------------ | ------------------- | ----------------------------------- |
|
|
47
|
+
| `nlobby profile` | `--json` | Show account info from Next.js page |
|
|
48
|
+
| `nlobby profile card` | | Capture student ID card screenshot |
|
|
49
|
+
| `nlobby profile update-access` | `--json` | Update last access timestamp |
|
|
50
|
+
|
|
51
|
+
### Navigation & Interests
|
|
52
|
+
|
|
53
|
+
| Command | Options / Arguments | Description |
|
|
54
|
+
| -------------------------- | ---------------------- | -------------------------------------- |
|
|
55
|
+
| `nlobby nav menus` | `--json` | Show main navigation menu list |
|
|
56
|
+
| `nlobby nav notifications` | `--json` | Show notification messages |
|
|
57
|
+
| `nlobby nav interests` | `--with-icon` `--json` | Show user interest tags |
|
|
58
|
+
| `nlobby nav weights` | `--json` | Show interest weight scale definitions |
|
|
59
|
+
|
|
60
|
+
### Health & Debug
|
|
61
|
+
|
|
62
|
+
| Command | Options / Arguments | Description |
|
|
63
|
+
| ----------------------------- | ---------------------------------- | ----------------------------------------- |
|
|
64
|
+
| `nlobby health` | `--json` | Check API connectivity and authentication |
|
|
65
|
+
| `nlobby health debug` | `--endpoint <path>` | Debug connection with detailed info |
|
|
66
|
+
| `nlobby health page` | `--endpoint <path>` `--length <n>` | Fetch and sample raw page content |
|
|
67
|
+
| `nlobby health trpc <method>` | `--params <json>` `--json` | Test a tRPC endpoint directly |
|
|
68
|
+
| `nlobby health verify` | | Verify cookie sync across all clients |
|
|
69
|
+
|
|
70
|
+
### MCP Server
|
|
71
|
+
|
|
72
|
+
| Command | Description |
|
|
73
|
+
| ----------------------------- | ---------------------------------- |
|
|
74
|
+
| `nlobby serve` / `nlobby mcp` | Start MCP server (stdio transport) |
|
|
75
|
+
|
|
22
76
|
---
|
|
23
77
|
|
|
24
78
|
## MCP Tools
|
package/dist/index.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
`)}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=M.getInstance()});var H,pe=g(()=>{"use strict";S();H=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={}}}});var G,ge=g(()=>{"use strict";T();E();S();G=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()===""){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=>{let t=e instanceof C?e:null;if(i.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 i.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 i.error("[BLOCKED] Access forbidden - insufficient permissions"),new Error("Access forbidden. Check your permissions or re-authenticate.");if(t?.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){throw 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 instanceof C&&(i.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?i.error("[BLOCKED] tRPC 401 Unauthorized - session may be expired or invalid"):r.response?.status===403?i.error("[BLOCKED] tRPC 403 Forbidden - insufficient permissions"):r.response?.status===404?i.error("[BLOCKED] tRPC 404 Not Found - endpoint may not exist"):r.response?.status&&r.response.status>=500&&i.error("[BLOCKED] tRPC Server Error - N Lobby backend issue"),r.code==="ECONNREFUSED"?i.error("[NETWORK] Network Error: Connection refused - N Lobby may be down"):r.code==="ETIMEDOUT"?i.error("[TIMEOUT] Network Error: Request timeout - slow network or server overload"):r.code==="ENOTFOUND"&&i.error("[NETWORK] Network Error: DNS lookup failed - check internet connection")),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 $(o,e){try{i.info("[NETWORK] Fetching HTML using HTTP client (proven method)..."),i.debug(`[URL] URL: ${m.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":m.userAgent},withCredentials:!0});if(i.info(`[SUCCESS] HTTP response: ${t.status} ${t.statusText}`),i.info(`[DATA] Content length: ${typeof t.data=="string"?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){throw i.error("[ERROR] HTTP fetch error:",t instanceof Error?t.message:"Unknown error"),t instanceof C&&i.debug("[DEBUG] HTTP Error Details:",{status:t.response?.status,statusText:t.response?.statusText,url:t.config?.url,hasData:!!t.response?.data}),t}}var V=g(()=>{"use strict";E();S();T()});import*as me from"cheerio";function Gt(o){if(!o)return"";try{return o.replace(/\\u003c/g,"<").replace(/\\u003e/g,">").replace(/\\u0026/g,"&").replace(/\\"/g,'"').replace(/\\\\/g,"\\")}catch{return o}}function he(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=he(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 q(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=`${m.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(([w])=>!["id","title","content","publishedAt","category","priority","url"].includes(w)))}})}function qt(o){try{i.info("[TARGET] Starting Cheerio-based DOM parsing...");let e=me.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="",w="",y=new Date,k=!1,b=!1,p="";if(d.each((f,O)=>{let N=e(O);switch(N.attr("data-field")){case"title":{let R=N.find("a");if(R.length>0){let x=R.attr("href");x&&x.startsWith("/news/")?p=`${m.nlobby.baseUrl}${x}`:p=`${m.nlobby.baseUrl}/news/${u}`;let ue=R.find("span");h=ue.length>0?ue.text().trim():R.text().trim()}else h=N.text().trim(),p=`${m.nlobby.baseUrl}/news/${u}`;break}case"menuName":w=N.text().trim();break;case"isImportant":{k=N.text().trim().length>0||N.find("*").length>0;break}case"isUnread":{let R=N.text().trim();b=R.includes("\u672A\u8AAD")||R.length>0;break}case"publishedAt":{let R=N.text().trim();if(R){let x=new Date(R.replace(/\//g,"-"));isNaN(x.getTime())||(y=x)}break}}}),h){let f=p||`${m.nlobby.baseUrl}/news/${u}`,O={id:u,title:h,content:"",publishedAt:y,category:w||"General",priority:k?"high":"medium",targetAudience:["student"],url:f,menuName:w,isImportant:k,isUnread:b};s.push(O)}}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 Jt(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 w=h[2],y=JSON.parse(w);if(Array.isArray(y))for(let k=0;k<y.length;k++){let b=y[k];if(Array.isArray(b)&&b.length>=4&&b[3]&&typeof b[3]=="object"){let p=b[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 q(p.news)}}}}catch{}else try{let w=JSON.parse(d),y=J(w,`push_call_${s+1}_fallback`);if(y&&y.length>0)return q(y)}catch{}}let u=J(l,`push_call_${s+1}_direct`);if(u&&u.length>0)return q(u)}catch{}}}let n=qt(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 q(l)}catch{}}catch(t){i.error("[ERROR] Error parsing news from HTML:",t)}return e}function Bt(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 y=t[c+1].match(/self\.__next_f\.push\((\[.*?\])\)/);if(y){let k=JSON.parse(y[1]);k.length>=2&&typeof k[1]=="string"&&s.set(h,k[1])}}continue}if(d.length>=2&&typeof d[1]=="string"){let w=d[1].match(/^(\d+):(.*)/);if(w)try{let y=w[2],k=JSON.parse(y),b=he(k);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:Gt(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 i.error("[ERROR] Error parsing news detail from HTML:",t),null}}async function fe(o){i.info("[INFO] Starting getNews with HTTP client..."),i.info("[STATUS] Current authentication status:",o.getCookieStatus());try{let e=await $(o,"/news"),t=Jt(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:
|
|
2
|
+
var jt=Object.defineProperty;var g=(o,e)=>()=>(o&&(e=o(o=0)),e);var j=(o,e)=>{for(var n in e)jt(o,n,{get:e[n],enumerable:!0})};import Mt from"node-fetch";var C,A,T=g(()=>{"use strict";C=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,n)=>{this.responseSuccessInterceptors.push(e),n&&this.responseErrorInterceptors.push(n)}}};constructor(e){this.baseURL=e.baseURL??"",this.defaults={headers:{...e.headers??{}},timeout:e.timeout??3e4,baseURL:this.baseURL}}async get(e,n){return this.request("GET",e,void 0,n)}async post(e,n,t){return this.request("POST",e,n,t)}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 n={};return e.headers.forEach((t,r)=>{n[r]=t}),n}async runErrorInterceptors(e){for(let n of this.responseErrorInterceptors)await n(e)}async request(e,n,t,r){let s=n.startsWith("http")?n:`${this.baseURL}${n}`;if(r?.params&&Object.keys(r.params).length>0){let p={};for(let[$,N]of Object.entries(r.params))N!==void 0&&(p[$]=N);let f=new URLSearchParams(p).toString();s+=(s.includes("?")?"&":"?")+f}let a={...this.defaults.headers,...r?.headers??{}},c={url:s,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};t!==void 0&&(p.body=typeof t=="string"?t:JSON.stringify(t)),h=await Mt(c.url,p),clearTimeout(d)}catch(p){clearTimeout(d);let f=new C(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 C(`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 b={data:w,status:h.status,statusText:h.statusText,headers:y};for(let p of this.responseSuccessInterceptors)b=await p(b);return b}}});import{config as Ht}from"dotenv";function Gt(){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";Ht();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||Gt()}});var pe={};j(pe,{LogLevel:()=>K,Logger:()=>M,logger:()=>i});var K,M,i,S=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||{}),M=class o{static instance;logLevel;constructor(){let e=process.env.NLOBBY_DEBUG==="true"||process.env.DEBUG==="true";this.logLevel=e?0:2}static getInstance(){return o.instance||(o.instance=new o),o.instance}setLogLevel(e){this.logLevel=e}forceProductionMode(){}log(e,n,...t){if(e<this.logLevel)return;let r=new Date().toISOString(),s=K[e],a=t.length>0?`[${r}] [${s}] ${n} ${t.map(c=>typeof c=="object"?JSON.stringify(c):String(c)).join(" ")}`:`[${r}] [${s}] ${n}`;process.stderr.write(a+`
|
|
3
|
+
`)}debug(e,...n){this.log(0,e,...n)}info(e,...n){this.log(1,e,...n)}warn(e,...n){this.log(2,e,...n)}error(e,...n){this.log(3,e,...n)}},i=M.getInstance()});var H,ge=g(()=>{"use strict";S();H=class{cookies={};constructor(){}parseCookies(e){let n={},t=e.split(";");for(let r of t){let[s,a]=r.trim().split("=");s&&a&&(s==="__Secure-next-auth.session-token"?n.sessionToken=decodeURIComponent(a):s==="__Host-next-auth.csrf-token"?n.csrfToken=decodeURIComponent(a):s==="__Secure-next-auth.callback-url"&&(n.callbackUrl=decodeURIComponent(a)))}return n}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={}}}});var G,me=g(()=>{"use strict";T();E();S();G=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()===""){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 n;if(this.allCookies&&this.allCookies.trim()!=="")n=this.allCookies,i.debug("[COOKIE] Using all cookies for tRPC request");else{let s=this.nextAuth.getCookieHeader();s&&s.trim()!==""?(n=s,i.debug("[COOKIE] Using NextAuth cookies for tRPC request")):i.warn("[WARNING] No cookies available for tRPC request")}n&&(e.headers.Cookie=n);let t=this.nextAuth.getSessionToken();t?(e.headers.Authorization=`Bearer ${t}`,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:!!n,hasCSRF:!!r,hasAuth:!!t,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=>{let n=e instanceof C?e:null;if(i.error("[ERROR] tRPC request failed:",{status:n?.response?.status,statusText:n?.response?.statusText,message:e instanceof Error?e.message:"Unknown error",url:n?.config?.url}),n?.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(n?.response?.status===403)throw i.error("[BLOCKED] Access forbidden - insufficient permissions"),new Error("Access forbidden. Check your permissions or re-authenticate.");if(n?.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,n){let t={id:this.getNextRequestId(),method:e,params:n};try{i.info(`[REQUEST] tRPC call: ${e}`,n?`with params: ${JSON.stringify(n)}`:"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,n);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,t,{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){throw 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 instanceof C&&(i.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?i.error("[BLOCKED] tRPC 401 Unauthorized - session may be expired or invalid"):r.response?.status===403?i.error("[BLOCKED] tRPC 403 Forbidden - insufficient permissions"):r.response?.status===404?i.error("[BLOCKED] tRPC 404 Not Found - endpoint may not exist"):r.response?.status&&r.response.status>=500&&i.error("[BLOCKED] tRPC Server Error - N Lobby backend issue"),r.code==="ECONNREFUSED"?i.error("[NETWORK] Network Error: Connection refused - N Lobby may be down"):r.code==="ETIMEDOUT"?i.error("[TIMEOUT] Network Error: Request timeout - slow network or server overload"):r.code==="ENOTFOUND"&&i.error("[NETWORK] Network Error: DNS lookup failed - check internet connection")),r}}buildTRPCUrl(e,n){let t=e,r=JSON.stringify(n||{}),s=new URLSearchParams({input:r}).toString();return`/${t}?${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,n){return this.call("calendar.getLobbyCalendarEvents",{from:e,to:n})}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:n,method:t}of e)try{return i.debug(`Trying tRPC method: ${n}`),await t(),i.info(`[SUCCESS] tRPC health check passed with method: ${n}`),!0}catch(r){i.debug(`[ERROR] tRPC method ${n} failed:`,r instanceof Error?r.message:"Unknown error");continue}return i.error("[ERROR] All tRPC health check methods failed"),!1}}});async function U(o,e){try{i.info("[NETWORK] Fetching HTML using HTTP client (proven method)..."),i.debug(`[URL] URL: ${m.nlobby.baseUrl+e}`),i.info("[COOKIE] Cookies:",o.httpClient.defaults.headers.Cookie?"present":"missing");let n=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":m.userAgent},withCredentials:!0});if(i.info(`[SUCCESS] HTTP response: ${n.status} ${n.statusText}`),i.info(`[DATA] Content length: ${typeof n.data=="string"?n.data.length:"unknown"}`),i.info(`[DATA] Content type: ${n.headers["content-type"]||"unknown"}`),typeof n.data=="string"){let t=n.data,r=t.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: ${t.length} characters`),t}else throw new Error(`Non-string response received: ${typeof n.data}`)}catch(n){throw i.error("[ERROR] HTTP fetch error:",n instanceof Error?n.message:"Unknown error"),n instanceof C&&i.debug("[DEBUG] HTTP Error Details:",{status:n.response?.status,statusText:n.response?.statusText,url:n.config?.url,hasData:!!n.response?.data}),n}}var V=g(()=>{"use strict";E();S();T()});import*as he from"cheerio";function qt(o){if(!o)return"";try{return o.replace(/\\u003c/g,"<").replace(/\\u003e/g,">").replace(/\\u0026/g,"&").replace(/\\"/g,'"').replace(/\\\\/g,"\\")}catch{return o}}function fe(o,e=""){if(!o||typeof o!="object")return null;let n=o;if(n.id&&n.title&&(n.publishedAt||n.description||n.menuName))return i.info(`[INFO] Found news object at path: ${e}`),o;if(n.news&&typeof n.news=="object")return i.info(`[INFO] Found news property at path: ${e}.news`),n.news;for(let[t,r]of Object.entries(n))if(r&&typeof r=="object"){let s=e?`${e}.${t}`:t,a=fe(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 t=o[0];if(t&&typeof t=="object"&&["title","name","content","publishedAt","menuName","createdAt","updatedAt","id"].some(a=>a in t))return i.info(`[INFO] Found potential news array at path: ${e}, length: ${o.length}`),o}return[]}let n=[];for(let[t,r]of Object.entries(o)){let s=["news","announcements","data","items","list","content","notifications","posts","feed","results"],a=e?`${e}.${t}`:t;s.includes(t.toLowerCase())&&i.info(`[INFO] Searching priority key: ${a}`);let c=J(r,a);n.push(...c)}return n}function q(o){return o.map((e,n)=>{let t=e,r=new Date;t.publishedAt?r=new Date(t.publishedAt):t.createdAt?r=new Date(t.createdAt):t.updatedAt?r=new Date(t.updatedAt):t.date&&(r=new Date(t.date));let s=t.title||t.name||t.subject||t.heading||`News Item ${n+1}`,a=t.content||t.description||t.body||t.text||t.summary||"",c=t.category||t.menuName||t.type||t.classification||"General",l="medium";t.isImportant===!0||t.important===!0||t.priority==="high"||t.urgent===!0?l="high":(t.priority==="low"||t.minor===!0)&&(l="low");let u=t.id||n,d=`${m.nlobby.baseUrl}/news/${u}`;return{id:t.id?.toString()||n.toString(),title:s,content:a,publishedAt:r,category:c,priority:l,targetAudience:t.targetAudience||["student"],url:d,menuName:t.menuName,isImportant:!!t.isImportant,isUnread:!!t.isUnread,...Object.fromEntries(Object.entries(t).filter(([w])=>!["id","title","content","publishedAt","category","priority","url"].includes(w)))}})}function Jt(o){try{i.info("[TARGET] Starting Cheerio-based DOM parsing...");let e=he.load(o),n=e('div[role="presentation"]');if(i.info(`[INFO] Found ${n.length} div[role="presentation"] elements`),n.length<2)return i.info('[WARNING] Less than 2 div[role="presentation"] elements found'),[];let t=e(n[1]);i.info('[SUCCESS] Located second div[role="presentation"] element');let r=t.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="",w="",y=new Date,k=!1,b=!1,p="";if(d.each((f,$)=>{let N=e($);switch(N.attr("data-field")){case"title":{let R=N.find("a");if(R.length>0){let x=R.attr("href");x&&x.startsWith("/news/")?p=`${m.nlobby.baseUrl}${x}`:p=`${m.nlobby.baseUrl}/news/${u}`;let de=R.find("span");h=de.length>0?de.text().trim():R.text().trim()}else h=N.text().trim(),p=`${m.nlobby.baseUrl}/news/${u}`;break}case"menuName":w=N.text().trim();break;case"isImportant":{k=N.text().trim().length>0||N.find("*").length>0;break}case"isUnread":{let R=N.text().trim();b=R.includes("\u672A\u8AAD")||R.length>0;break}case"publishedAt":{let R=N.text().trim();if(R){let x=new Date(R.replace(/\//g,"-"));isNaN(x.getTime())||(y=x)}break}}}),h){let f=p||`${m.nlobby.baseUrl}/news/${u}`,$={id:u,title:h,content:"",publishedAt:y,category:w||"General",priority:k?"high":"medium",targetAudience:["student"],url:f,menuName:w,isImportant:k,isUnread:b};s.push($)}}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 Bt(o){let e=[];try{i.info("[INFO] Starting HTML parsing...");let n=o.match(/self\.__next_f\.push\((\[.*?\])\)/g);if(n&&n.length>0){i.info(`[SUCCESS] Found ${n.length} self.__next_f.push() calls`);for(let s=0;s<n.length;s++){let a=n[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 w=h[2],y=JSON.parse(w);if(Array.isArray(y))for(let k=0;k<y.length;k++){let b=y[k];if(Array.isArray(b)&&b.length>=4&&b[3]&&typeof b[3]=="object"){let p=b[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 q(p.news)}}}}catch{}else try{let w=JSON.parse(d),y=J(w,`push_call_${s+1}_fallback`);if(y&&y.length>0)return q(y)}catch{}}let u=J(l,`push_call_${s+1}_direct`);if(u&&u.length>0)return q(u)}catch{}}}let t=Jt(o);if(t&&t.length>0)return t;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 q(l)}catch{}}catch(n){i.error("[ERROR] Error parsing news from HTML:",n)}return e}function zt(o,e){try{let n=o.match(/self\.__next_f\.push\((\[.*?\])\)/g);if(!n||n.length===0)return null;let t=null,r="",s=new Map;for(let c=0;c<n.length;c++){let l=n[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<n.length){let y=n[c+1].match(/self\.__next_f\.push\((\[.*?\])\)/);if(y){let k=JSON.parse(y[1]);k.length>=2&&typeof k[1]=="string"&&s.set(h,k[1])}}continue}if(d.length>=2&&typeof d[1]=="string"){let w=d[1].match(/^(\d+):(.*)/);if(w)try{let y=w[2],k=JSON.parse(y),b=fe(k);b&&(t=b)}catch{}}}catch{}}if(!t)return null;if(t.description){for(let[c,l]of s)if(t.description.includes(c)){r=l;break}}return!r&&s.size>0&&(r=Array.from(s.values())[0]),{id:t.id||e,microCmsId:t.microCmsId,title:t.title||"No Title",content:qt(r)||t.description||"",description:t.description,publishedAt:t.publishedAt?new Date(t.publishedAt):new Date,menuName:t.menuName||[],isImportant:t.isImportant||!1,isByMentor:t.isByMentor||!1,attachments:t.attachments||[],relatedEvents:t.relatedEvents||[],targetUserQueryId:t.targetUserQueryId,url:`${m.nlobby.baseUrl}/news/${e}`}}catch(n){return i.error("[ERROR] Error parsing news detail from HTML:",n),null}}async function ye(o){i.info("[INFO] Starting getNews with HTTP client..."),i.info("[STATUS] Current authentication status:",o.getCookieStatus());try{let e=await U(o,"/news"),n=Bt(e);if(n&&n.length>0)return i.info(`[SUCCESS] Retrieved ${n.length} news items from HTML`),n;{let t=`HTML scraping returned no data. Debug info:
|
|
4
4
|
- Authentication status: ${o.nextAuth.isAuthenticated()?"authenticated":"not authenticated"}
|
|
5
5
|
- HTTP cookies: ${o.httpClient.defaults.headers.Cookie?"present":"missing"}
|
|
6
6
|
- HTML length: ${e.length} characters
|
|
7
7
|
|
|
8
8
|
Troubleshooting steps:
|
|
9
9
|
1. Run 'health_check' to verify connection
|
|
10
|
-
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 ye(o,e){i.info(`[INFO] Fetching news detail for ID: ${e}`);try{let t=`/news/${e}`,n=await $(o,t),r=Bt(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 we(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 be(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 Ce=g(()=>{"use strict";V();E();S()});var z={};j(z,{CalendarType:()=>B});var B,v=g(()=>{"use strict";B=(t=>(t.PERSONAL="personal",t.SCHOOL="school",t))(B||{})});function X(){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 zt(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 U(o,e,t){let{CalendarType:n}=await Promise.resolve().then(()=>(v(),z));try{i.info(`[INFO] Fetching Google Calendar events for ${e}...`);let r=X(),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 instanceof C&&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 Q(o,e,t){try{i.info(`[INFO] Fetching ${e} calendar events...`);let n=await U(o,e,t),r=zt(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 Se(o,e){let{CalendarType:t}=await Promise.resolve().then(()=>(v(),z)),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=X();return Q(o,t.PERSONAL,n)}async function ke(o,e){let{CalendarType:t}=await Promise.resolve().then(()=>(v(),z)),n=e||X(),r={personal:{success:!1,count:0},school:{success:!1,count:0}};try{let s=await U(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 U(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 Ne(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 Re(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 Ee(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 xe(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 Ae(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 Te=g(()=>{"use strict";S();T()});function ve(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=ve(n,r);if(s)return s}return null}function Yt(o){return o.allCount===0?0:Math.round(o.count/o.allCount*100)}function Wt(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 Kt(o){let e=[];for(let t of o.termYears)for(let n of t.courses){let r=Yt(n.report),s=Wt(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 De(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=ve(n);r&&(t=r)}}if(t){let r=Kt(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 Ie(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 Le(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 Oe(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 $e(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 Ue=g(()=>{"use strict";S()});import Pe from"node:fs/promises";import Vt from"node:os";import _e from"node:path";import Fe from"puppeteer";function Xt(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 P(o,e){if(o==null)return null;if(typeof o=="string"){let t=Xt(o);return t?P(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=P(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=P(n,e);if(r)return r}}return null}function Qt(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=P(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=P(a,new WeakSet);if(c)return i.info("[SUCCESS] Found session data in __NEXT_DATA__ payload"),c}catch{}}return null}function Zt(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 en(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 tn(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 nn(){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 Fe.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 Fe.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(`
|
|
10
|
+
2. Ensure you are properly authenticated using 'set_cookies'`;throw new Error(t)}}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 we(o,e){i.info(`[INFO] Fetching news detail for ID: ${e}`);try{let n=`/news/${e}`,t=await U(o,n),r=zt(t,e);if(r)return r;throw new Error(`Failed to parse news detail from HTML for news ID: ${e}`)}catch(n){throw i.error(`[ERROR] getNewsDetail failed for ID ${e}:`,n),n instanceof Error?n:new Error(`Failed to fetch news detail for ID ${e}: ${n instanceof Error?n.message:"Unknown error"}`)}}async function be(o,e){i.info(`[INFO] Marking news article ${e} as read`);try{let n=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`),n.data}catch(n){throw i.error(`[ERROR] Failed to mark news ${e} as read:`,n),n}}async function Ce(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 Se=g(()=>{"use strict";V();E();S()});var z={};j(z,{CalendarType:()=>B});var B,v=g(()=>{"use strict";B=(n=>(n.PERSONAL="personal",n.SCHOOL="school",n))(B||{})});function X(){let o=new Date,e=new Date(o);e.setHours(0,0,0,0);let n=new Date(o);return n.setDate(n.getDate()+7),n.setHours(23,59,59,999),{from:e,to:n}}function Yt(o){return o.map(e=>{let n=e,t,r;n.startDateTime?(t=new Date(n.startDateTime),r=n.endDateTime?new Date(n.endDateTime):new Date(t.getTime()+3600*1e3)):n.start?(n.start.dateTime?t=new Date(n.start.dateTime):n.start.date?t=new Date(n.start.date+"T00:00:00"):t=new Date,n.end&&n.end.dateTime?r=new Date(n.end.dateTime):n.end&&n.end.date?(r=new Date(n.end.date+"T23:59:59"),r.setDate(r.getDate()-1)):r=new Date(t.getTime()+3600*1e3)):(t=new Date,r=new Date(t.getTime()+3600*1e3));let s="event",a=(n.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 n.attendees&&Array.isArray(n.attendees)&&(c=n.attendees.map(u=>u.email).filter(Boolean)),{id:n.id||n.microCmsId||Math.random().toString(),title:n.summary||n.title||"No Title",description:n.description||"",startTime:t,endTime:r,location:n.location||"",type:s,participants:c}})}async function P(o,e,n){let{CalendarType:t}=await Promise.resolve().then(()=>(v(),z));try{i.info(`[INFO] Fetching Google Calendar events for ${e}...`);let r=X(),s=n||r;i.info(`[INFO] Date range: ${s.from.toISOString()} to ${s.to.toISOString()}`);let a=e===t.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 instanceof C&&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 Q(o,e,n){try{i.info(`[INFO] Fetching ${e} calendar events...`);let t=await P(o,e,n),r=Yt(t);return i.info(`[SUCCESS] Retrieved ${r.length} schedule items`),r}catch(t){throw i.error("[ERROR] Error fetching schedule:",t),new Error(`Failed to fetch ${e} calendar: ${t instanceof Error?t.message:"Unknown error"}`)}}async function ke(o,e){let{CalendarType:n}=await Promise.resolve().then(()=>(v(),z)),t;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),t={from:s,to:a}}else t=X();return Q(o,n.PERSONAL,t)}async function Ne(o,e){let{CalendarType:n}=await Promise.resolve().then(()=>(v(),z)),t=e||X(),r={personal:{success:!1,count:0},school:{success:!1,count:0}};try{let s=await P(o,n.PERSONAL,t);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 P(o,n.SCHOOL,t);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 Re(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 Ee(o,e){let n=typeof o=="string"?new Date(o):o,t=typeof e=="string"?new Date(e):e;if(isNaN(n.getTime())||isNaN(t.getTime()))throw new Error("Invalid date format provided");if((t.getTime()-n.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:n,to:t}}function xe(o){let e=typeof o=="string"?new Date(o):o;if(isNaN(e.getTime()))throw new Error("Invalid date format provided");let n=new Date(e);n.setHours(0,0,0,0);let t=new Date(e);return t.setHours(23,59,59,999),{from:n,to:t}}function Ae(o){let e=o?typeof o=="string"?new Date(o):o:new Date;e.setHours(0,0,0,0);let n=new Date(e);return n.setDate(n.getDate()+6),n.setHours(23,59,59,999),{from:e,to:n}}function Te(o,e){let n=new Date,t=o||n.getFullYear(),r=e!==void 0?e:n.getMonth(),s=new Date(t,r,1,0,0,0,0),a=new Date(t,r+1,0,23,59,59,999);return{from:s,to:a}}var ve=g(()=>{"use strict";S();T()});function De(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[n,t]of Object.entries(o))if(t&&typeof t=="object"){let r=e?`${e}.${n}`:n,s=De(t,r);if(s)return s}return null}function Wt(o){return o.allCount===0?0:Math.round(o.count/o.allCount*100)}function Kt(o){let e=o.filter(t=>t.score!==null&&t.progress===100);if(e.length===0)return null;let n=e.reduce((t,r)=>t+(r.score||0),0);return Math.round(n/e.length)}function Vt(o){let e=[];for(let n of o.termYears)for(let t of n.courses){let r=Wt(t.report),s=Kt(t.reportDetails),a=t.acquired.acquisitionStatus===1,c=t.subjectStatus===1||t.subjectStatus===2,l={...t,termYear:n.termYear,grade:n.grade,term:n.term,progressPercentage:r,averageScore:s,isCompleted:a,isInProgress:c};e.push(l)}return e}async function Ie(o){i.info("[INFO] Starting getRequiredCourses...");try{let e=await o.trpcClient.call("requiredCourse.getRequiredCourses"),n=null,t=e;if(t&&t.result&&t.result.data)n=t.result.data;else if(t&&t.data)n=t.data;else if(t&&t.educationProcessName&&t.termYears)n=t;else{if(t&&Array.isArray(t))return t;if(t){let r=De(t);r&&(n=r)}}if(n){let r=Vt(n);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 Le(o,e){try{let n=e?{subject:e}:{},t=await o.httpClient.get("/api/learning-resources",{params:n});if(!t.data.success)throw new Error(t.data.error||"Failed to fetch learning resources");return t.data.data||[]}catch(n){throw i.error("Error fetching learning resources:",n),new Error("Authentication required. Please use the set_cookies tool to provide valid NextAuth.js session cookies from N Lobby.")}}async function Oe(o,e){i.info("[INFO] Checking if date is exam day...");let t=(e||new Date).toISOString();try{let r=await o.trpcClient.call("exam.isExamDay",t);return i.info(`[SUCCESS] isExamDay result: ${r}`),r===!0}catch(r){throw i.error("[ERROR] isExamDay failed:",r),r}}async function $e(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 Ue(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 Pe=g(()=>{"use strict";S()});import _e from"node:fs/promises";import Xt from"node:os";import Fe from"node:path";import je from"puppeteer";function Qt(o){if(typeof o!="string"||o.length===0)return null;let e=o.trim(),n=e.indexOf(":");if(n>0&&n<20){let r=e.slice(0,n);/^[a-z0-9]+$/i.test(r)&&(e=e.slice(n+1))}e=e.trim();let t=e.replace(/"/g,'"').replace(/</g,"<").replace(/>/g,">").replace(/&/g,"&");try{return JSON.parse(t)}catch{return null}}function D(o,e){if(o==null)return null;if(typeof o=="string"){let n=Qt(o);return n?D(n,e):null}if(Array.isArray(o)){let n=o;if(e.has(n))return null;e.add(n);for(let t of o){let r=D(t,e);if(r)return r}return null}if(typeof o=="object"){let n=o;if(e.has(n))return null;if(e.add(n),Object.prototype.hasOwnProperty.call(n,"session")&&n.session&&typeof n.session=="object")return n.session;for(let t of Object.values(n)){let r=D(t,e);if(r)return r}}return null}function Zt(o){let e=/self\.__next_f\.push\((\[[\s\S]*?\])\)/g,n;for(;(n=e.exec(o))!==null;){let r=n[1];if(r)try{let s=JSON.parse(r),a=D(s,new WeakSet);if(a)return i.info("[SUCCESS] Found session data in Next.js flight payload"),a}catch{}}let t=[/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/,/window\.__NEXT_DATA__\s*=\s*({[\s\S]*?})(?:;|\s*<\/script>)/];for(let r of t){let s=o.match(r);if(!(!s||!s[1]))try{let a=JSON.parse(s[1]),c=D(a,new WeakSet);if(c)return i.info("[SUCCESS] Found session data in __NEXT_DATA__ payload"),c}catch{}}return null}function Z(o){let e=o.user??{},n=e.kmsLogin??{},t=n.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 t.userId=="string"?t.userId:void 0,studentNo:typeof t.studentNo=="string"?t.studentNo:void 0,schoolCorporationType:typeof t.schoolCorporationType=="number"?t.schoolCorporationType:void 0,grade:typeof t.grade=="number"?t.grade:void 0,term:typeof t.term=="number"?t.term:void 0,isLobbyAdmin:typeof t.isLobbyAdmin=="boolean"?t.isLobbyAdmin:void 0,firstLoginFlg:typeof t.firstLoginFlg=="number"?t.firstLoginFlg:void 0,kmsLoginSuccess:typeof n.success=="boolean"?n.success:void 0,staffDepartments:Array.isArray(t.staffDepartments)?t.staffDepartments:void 0,studentOrganizations:Array.isArray(t.studentOrganizations)?t.studentOrganizations:void 0,rawSession:o}}function en(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 tn(o,e){let n=[];for(let t of o.split(";")){let r=t.trim();if(!r)continue;let s=r.indexOf("=");if(s<=0)continue;let a=r.slice(0,s),c=r.slice(s+1);n.push({name:a,value:c,domain:e,path:"/",secure:!0,httpOnly:a.startsWith("__Secure-")||a.startsWith("__Host-")||a.toLowerCase().includes("session"),sameSite:"Lax"})}return n}async function nn(){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 je.launch({headless:!0,executablePath:c,args:o})}catch{}let n=[],t=async(c,l)=>{try{return i.info(`[STUDENT_CARD] Trying browser launch via ${l}`),await je.launch(c)}catch(u){return u instanceof Error&&n.push(u),null}},r=await t({headless:!0,args:o},"default Puppeteer bundle");if(r)return r;let s=await t({headless:!0,channel:"chrome",args:o},"system Chrome channel");if(s)return s;let a=n.map(c=>c.message).join(`
|
|
11
11
|
`);throw new Error(`Failed to launch a browser instance for screenshot capture. Please install Chrome via "npx puppeteer browsers install chrome".
|
|
12
|
-
${a}`)}async function rn(o){i.info("[STUDENT_CARD] Launching headless browser for student card capture");let e=await nn();try{let
|
|
13
|
-
`)}async function
|
|
12
|
+
${a}`)}async function rn(o){i.info("[STUDENT_CARD] Launching headless browser for student card capture");let e=await nn();try{let n=await e.newPage();await n.setViewport({width:1280,height:720}),await n.setUserAgent(m.userAgent),o.cookies.length>0&&await n.setCookie(...o.cookies),await n.goto(o.startUrl,{waitUntil:"networkidle2",timeout:6e4}),await n.waitForSelector(o.waitForSelector,{timeout:6e4}),await new Promise(u=>setTimeout(u,1e3));let t=await n.$(o.waitForSelector);if(!t)throw new Error(`Failed to locate element ${o.waitForSelector} for screenshot`);let r=await t.screenshot({type:"png"}),s=Fe.join(Xt.tmpdir(),"nlobby-student-card");await _e.mkdir(s,{recursive:!0});let a=Fe.join(s,o.screenshotName);await _e.writeFile(a,r);let c=await t.boundingBox(),l=c?{width:Math.round(c.width),height:Math.round(c.height)}:void 0;return{base64:r.toString("base64"),path:a,finalUrl:n.url(),elementSize:l}}finally{await e.close()}}async function Me(o){try{let e=await o.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 i.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 on(o){try{i.info("[INFO] Trying /api/auth/session for account info...");let n=(await o.httpClient.get("/api/auth/session")).data;if(!n||typeof n!="object")return null;let t=D(n,new WeakSet);return t?(i.info("[SUCCESS] Got account info from /api/auth/session"),Z(t)):Object.prototype.hasOwnProperty.call(n,"user")&&n.user&&typeof n.user=="object"?(i.info("[SUCCESS] Got account info from /api/auth/session (direct)"),Z(n)):null}catch(e){return i.debug("[DEBUG] /api/auth/session failed:",e instanceof Error?e.message:"Unknown error"),null}}async function ee(o,e="/"){i.info("[INFO] Extracting account information...");let n=await on(o);if(n)return n;i.info(`[INFO] Falling back to Next.js script extraction at ${e}`);try{let t=await U(o,e),r=Zt(t);if(!r)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 s=Z(r);return i.info("[SUCCESS] Account information extracted successfully"),s}catch(t){throw i.error("Error extracting account info from script:",t),new Error(`Failed to extract account information: ${t instanceof Error?t.message:"Unknown error"}`)}}async function He(o){let n=(await ee(o,"/")).studentNo;if(!n||n.length<3)throw new Error("Student number is missing from account information. Ensure you are authenticated and try again.");let t=en(n),r=`https://${t}/mypage/student_card/index`,s=`https://nlobby.nnn.ed.jp/mypage/v1/callback?redirect_uri=${encodeURIComponent(r)}`,a=o.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=tn(a,"nlobby.nnn.ed.jp");if(c.length===0)throw new Error("Failed to parse authentication cookies for browser session.");let l=await rn({startUrl:s,waitForSelector:"#main",screenshotName:`student-card-${Date.now()}.png`,cookies:c});return{base64:l.base64,path:l.path,studentNo:n,secureHost:t,callbackUrl:s,finalUrl:l.finalUrl,elementSize:l.elementSize}}async function Ge(o){i.info("[INFO] Updating last access...");try{return await o.httpClient.post("/api/trpc/user.updateLastAccess","{}",{headers:{"Content-Type":"application/json",Cookie:o.nextAuth.getCookieHeader()}}),i.info("[SUCCESS] updateLastAccess succeeded"),!0}catch(e){throw i.error("[ERROR] updateLastAccess failed:",e),e}}var qe=g(()=>{"use strict";V();E();S()});async function Je(o){i.info("[INFO] Fetching main navigations...");try{let e=await o.trpcClient.call("menu.findMainNavigations",{});return i.info("[SUCCESS] getMainNavigations succeeded"),e&&typeof e=="object"&&"menus"in e?e.menus||[]:Array.isArray(e)?e:[]}catch(e){throw i.error("[ERROR] getMainNavigations failed:",e),e}}async function Be(o){i.info("[INFO] Fetching notification messages...");try{let e=await o.trpcClient.call("notification.getMessages");return i.info("[SUCCESS] getNotificationMessages succeeded"),Array.isArray(e)?e:[]}catch(e){throw i.error("[ERROR] getNotificationMessages failed:",e),e}}async function ze(o,e=!1){let n=e?"interest.readInterestsWithIcon":"interest.readInterests";i.info(`[INFO] Fetching user interests (${n})...`);try{let t=await o.trpcClient.call(n);return i.info("[SUCCESS] getUserInterests succeeded"),t&&typeof t=="object"&&"interests"in t?t.interests||[]:Array.isArray(t)?t:[]}catch(t){throw i.error("[ERROR] getUserInterests failed:",t),t}}async function Ye(o){i.info("[INFO] Fetching interest weights...");try{let e=await o.trpcClient.call("interest.readWeights");return i.info("[SUCCESS] getInterestWeights succeeded"),e&&typeof e=="object"&&"weights"in e?e.weights||[]:Array.isArray(e)?e:[]}catch(e){throw i.error("[ERROR] getInterestWeights failed:",e),e}}var We=g(()=>{"use strict";S()});async function Ke(o){i.info("[INFO] Running N Lobby API health check...");let e=[{name:"tRPC lightweight endpoint",test:async()=>{try{let n=await o.trpcClient.getUnreadNewsCount();return typeof n=="number"&&n>=0}catch{return!1}}},{name:"tRPC batch health check",test:async()=>{try{return await o.trpcClient.healthCheck()}catch{return!1}}},{name:"HTML news page access",test:async()=>{try{let n=await o.httpClient.get("/news",{headers:{Accept:"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"},withCredentials:!0,timeout:8e3});if(n.status===200&&typeof n.data=="string"){let t=n.data.toLowerCase(),r=t.includes("\u30ED\u30B0\u30A4\u30F3")||t.includes("login")||t.includes("sign-in"),s=t.includes("news")||t.includes("\u304A\u77E5\u3089\u305B")||t.includes("nlobby");return!r&&s}return!1}catch{return!1}}},{name:"Basic server connectivity",test:async()=>{try{return(await o.httpClient.get("/",{timeout:5e3,withCredentials:!0})).status===200}catch{return!1}}}];for(let n=0;n<e.length;n++){let t=e[n];i.info(`[STEP${n+1}] Testing ${t.name}...`);try{if(await t.test())return i.info(`[SUCCESS] ${t.name} passed`),n<3?(i.info("[SUCCESS] Health check passed - authentication and connectivity verified"),!0):(i.info("[WARNING] Health check passed with limited functionality"),!0);i.info(`[ERROR] ${t.name} failed`)}catch(r){i.info(`[ERROR] ${t.name} failed with error:`,r instanceof Error?r.message:"Unknown error")}}return i.info("[ERROR] All health check methods failed"),!1}async function Ve(o,e="/news"){let n=[];n.push("[INFO] N Lobby Connection Debug Report"),n.push("=".repeat(50)),n.push(""),n.push("[STATUS] Authentication Status:"),n.push(o.getCookieStatus()),n.push(""),n.push(`[NETWORK] Testing Basic Connectivity to ${e}:`);try{let s=Date.now(),a=await o.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(n.push(`[SUCCESS] Response received (${c-s}ms)`),n.push(`[STATUS] Status: ${a.status} ${a.statusText}`),n.push(`[SIZE] Content Length: ${typeof a.data=="string"?a.data.length:"unknown"}`),typeof a.data=="string"){let l=a.data.toLowerCase();n.push(""),n.push("[INFO] Content Analysis:"),(l.includes("\u30ED\u30B0\u30A4\u30F3")||l.includes("login")||l.includes("sign-in"))&&n.push("[WARNING] Contains login keywords - may need authentication"),(l.includes("unauthorized")||l.includes("access denied"))&&n.push("[BLOCKED] Access denied detected"),(l.includes("news")||l.includes("announcement")||l.includes("\u304A\u77E5\u3089\u305B"))&&n.push("[SUCCESS] Contains news/announcement content")}}catch(s){n.push("[ERROR] Basic connectivity failed"),s instanceof C?n.push(`[STATUS] Error Status: ${s.response?.status||"unknown"}`):n.push(`[DATA] Error: ${s instanceof Error?s.message:"Unknown error"}`)}n.push(""),n.push("[NETWORK] Network Information:"),n.push(`[URL] Base URL: ${o.httpClient.defaults.baseURL??""}`),n.push(`[TIMEOUT] Timeout: ${o.httpClient.defaults.timeout}ms`),n.push(""),n.push("=".repeat(50)),n.push("[TARGET] Recommendations:");let t=!!o.httpClient.defaults.headers.Cookie,r=o.nextAuth.isAuthenticated();return!t&&!r?n.push("1. Run interactive_login to authenticate"):t&&r&&(n.push("1. Authentication looks good - issue may be server-side"),n.push("2. Try different endpoints or wait and retry")),n.join(`
|
|
13
|
+
`)}async function Xe(o,e="/news",n=1e3){try{i.info(`[INFO] Testing page content for ${e}...`);let t=await o.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 t.data=="string"){let r=t.data,s=r.substring(0,n),a=[];a.push(`Status: ${t.status} ${t.statusText}`),a.push(`Content Length: ${r.length} characters`),a.push(`Content Type: ${t.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(`
|
|
14
14
|
`)+`
|
|
15
|
-
`+s;return r.length>
|
|
15
|
+
`+s;return r.length>n?l+`
|
|
16
16
|
|
|
17
|
-
... (${r.length-
|
|
17
|
+
... (${r.length-n} more characters)`:l}else return`Non-string response received: ${typeof t.data}`}catch(t){return i.error(`[ERROR] Failed to test page content for ${e}:`,t),t instanceof C?`Error ${t.response?.status||"unknown"}: ${t.message||"Unknown error"}`:`Error: ${t instanceof Error?t.message:"Unknown error"}`}}async function Qe(o,e,n){try{i.info(`[INFO] Testing tRPC endpoint: ${e}`);let t=await o.trpcClient.call(e,n);return i.info(`[SUCCESS] tRPC endpoint ${e} succeeded`),{success:!0,method:e,params:n,result:t,timestamp:new Date().toISOString()}}catch(t){i.error(`[ERROR] tRPC endpoint ${e} failed:`,t);let r={success:!1,method:e,params:n,error:t instanceof Error?t.message:"Unknown error",timestamp:new Date().toISOString()};return t instanceof C&&(r.status=t.response?.status,r.statusText=t.response?.statusText,r.responseData=t.response?.data),r}}var Ze=g(()=>{"use strict";E();S();T()});import te from"node:fs";import sn from"node:os";import et from"node:path";function an(){try{return te.readFileSync(ne,"utf8")}catch{return null}}function re(o){try{let e=et.dirname(ne);te.mkdirSync(e,{recursive:!0}),te.writeFileSync(ne,o,"utf8")}catch(e){i.warn("[WARNING] Failed to save session to disk:",e)}}var ne,I,Y=g(()=>{"use strict";T();E();S();ge();me();Se();ve();Pe();qe();We();Ze();ne=et.join(sn.homedir(),".nlobby","session");I=class{httpClient;nextAuth;trpcClient;session=null;constructor(){this.nextAuth=new H,this.trpcClient=new G(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=an();e&&(i.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()===""){i.warn("[WARNING] Empty cookies provided to setCookies");return}i.debug("[COOKIE] Setting cookies for all clients..."),this.setCookiesInternal(e),i.info("[SUCCESS] HTTP client cookies set"),i.info("[SUCCESS] NextAuth cookies set"),i.info("[SUCCESS] tRPC client cookies set")}getCookieStatus(){let e=!!this.httpClient.defaults.headers.Cookie,n=this.nextAuth.isAuthenticated(),t=this.nextAuth.getCookies(),r=!!this.trpcClient.allCookies,s=this.httpClient.defaults.headers.Cookie,a=typeof s=="string"?s.length:0,c=this.trpcClient.allCookies?.length||0,l=this.nextAuth.getCookieHeader()?.length||0,u=a===c&&c>0;return`[INFO] Authentication Status:
|
|
18
18
|
[HTTP] HTTP client: ${e?"[SUCCESS] cookies set":"[ERROR] no cookies"} (${a} chars)
|
|
19
19
|
[DEBUG] tRPC client: ${r?"[SUCCESS] cookies set":"[ERROR] no cookies"} (${c} chars)
|
|
20
|
-
[AUTH] NextAuth: ${
|
|
21
|
-
- Session token: ${
|
|
22
|
-
- CSRF token: ${
|
|
23
|
-
- Callback URL: ${
|
|
20
|
+
[AUTH] NextAuth: ${n?"[SUCCESS] authenticated":"[ERROR] not authenticated"} (${l} chars)
|
|
21
|
+
- Session token: ${t.sessionToken?"[SUCCESS] present":"[ERROR] missing"}
|
|
22
|
+
- CSRF token: ${t.csrfToken?"[SUCCESS] present":"[ERROR] missing"}
|
|
23
|
+
- Callback URL: ${t.callbackUrl?"[SUCCESS] present":"[ERROR] missing"}
|
|
24
24
|
|
|
25
25
|
Cookie Synchronization: ${u?"[SUCCESS] synchronized":"[ERROR] not synchronized"}
|
|
26
|
-
${!u&&e?"[WARNING] Cookie length mismatch detected - may cause authentication issues":""}`}async getNews(){return fe(this)}async getNewsDetail(e){return ye(this,e)}async markNewsAsRead(e){return we(this,e)}async getUnreadNewsInfo(){return be(this)}async getSchedule(e,t){return Q(this,e,t)}async getGoogleCalendarEvents(e,t){return U(this,e,t)}async getScheduleByDate(e){return Se(this,e)}async testCalendarEndpoints(e){return ke(this,e)}async getLobbyCalendarFilters(){return Ne(this)}createDateRange(e,t){return Re(e,t)}createSingleDayRange(e){return Ee(e)}createWeekDateRange(e){return xe(e)}createMonthDateRange(e,t){return Ae(e,t)}async getRequiredCourses(){return De(this)}async getLearningResources(e){return Ie(this,e)}async isExamDay(e){return Le(this,e)}async finishExamDayMode(){return Oe(this)}async getExamOneTimePassword(){return $e(this)}async getUserInfo(){return je(this)}async getAccountInfoFromScript(e="/"){return Z(this,e)}async getStudentCardScreenshot(){return Me(this)}async updateLastAccess(){return He(this)}async getMainNavigations(){return qe(this)}async getNotificationMessages(){return Je(this)}async getUserInterests(e=!1){return Be(this,e)}async getInterestWeights(){return ze(this)}async healthCheck(){return We(this)}async debugConnection(e="/news"){return Ke(this,e)}async testPageContent(e="/news",t=1e3){return Ve(this,e,t)}async testTrpcEndpoint(e,t){return Xe(this,e,t)}}});import an from"puppeteer";var I,re=g(()=>{"use strict";E();S();I=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 an.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(m.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(m.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(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),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(m.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 cn}from"crypto";var L,oe=g(()=>{"use strict";S();L=class{credentialStore=new Map;SESSION_TIMEOUT=7200*1e3;hashEmail(e){return cn("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`
|
|
26
|
+
${!u&&e?"[WARNING] Cookie length mismatch detected - may cause authentication issues":""}`}async getNews(){return ye(this)}async getNewsDetail(e){return we(this,e)}async markNewsAsRead(e){return be(this,e)}async getUnreadNewsInfo(){return Ce(this)}async getSchedule(e,n){return Q(this,e,n)}async getGoogleCalendarEvents(e,n){return P(this,e,n)}async getScheduleByDate(e){return ke(this,e)}async testCalendarEndpoints(e){return Ne(this,e)}async getLobbyCalendarFilters(){return Re(this)}createDateRange(e,n){return Ee(e,n)}createSingleDayRange(e){return xe(e)}createWeekDateRange(e){return Ae(e)}createMonthDateRange(e,n){return Te(e,n)}async getRequiredCourses(){return Ie(this)}async getLearningResources(e){return Le(this,e)}async isExamDay(e){return Oe(this,e)}async finishExamDayMode(){return $e(this)}async getExamOneTimePassword(){return Ue(this)}async getUserInfo(){return Me(this)}async getAccountInfoFromScript(e="/"){return ee(this,e)}async getStudentCardScreenshot(){return He(this)}async updateLastAccess(){return Ge(this)}async getMainNavigations(){return Je(this)}async getNotificationMessages(){return Be(this)}async getUserInterests(e=!1){return ze(this,e)}async getInterestWeights(){return Ye(this)}async healthCheck(){return Ke(this)}async debugConnection(e="/news"){return Ve(this,e)}async testPageContent(e="/news",n=1e3){return Xe(this,e,n)}async testTrpcEndpoint(e,n){return Qe(this,e,n)}}});import cn from"puppeteer";var L,oe=g(()=>{"use strict";E();S();L=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 cn.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 n=e.resourceType();["image","media","font","stylesheet"].includes(n)?n==="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(n){i.warn("Error closing browser after initialization failure:",n)}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 n=e.resourceType();["image","media","font","stylesheet"].includes(n)?n==="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(),n,t,r,s=[];for(let c of e){let l=`${c.name}=${c.value}`;s.push(l),c.name==="__Secure-next-auth.session-token"?n=c.value:c.name==="__Host-next-auth.csrf-token"?t=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: ${n?"present":"missing"}`),i.info(`CSRF token: ${t?"present":"missing"}`),{sessionToken:n,csrfToken:t,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 n=`/tmp/${e}`;return await this.page.screenshot({path:n,fullPage:!0}),i.info(`Screenshot saved to ${n}`),n}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,n){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:n/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(m.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(m.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(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),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(m.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(n){if(i.error("Interactive login failed:",n),this.page)try{let t=await this.page.url(),r=await this.page.title();i.error(`Current URL: ${t}`),i.error(`Page title: ${r}`),await this.takeScreenshot("interactive-login-failure-debug.png")}catch(t){i.error("Failed to capture debug information:",t)}throw new Error(`Interactive login failed: ${n instanceof Error?n.message:"Unknown error"}`)}}}});import{createHash as ln}from"crypto";var O,se=g(()=>{"use strict";S();O=class{credentialStore=new Map;SESSION_TIMEOUT=7200*1e3;hashEmail(e){return ln("sha256").update(e).digest("hex")}validateEmail(e){if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e))return{valid:!1,userType:"unknown",message:"Invalid email format"};let t=e.split("@")[1].toLowerCase();return t==="nnn.ed.jp"?{valid:!0,userType:"student"}:t==="nnn.ac.jp"?{valid:!0,userType:"staff"}:t==="gmail.com"||t==="yahoo.com"||t==="outlook.com"||t==="hotmail.com"?{valid:!0,userType:"parent"}:{valid:!0,userType:"parent"}}storeSession(e){let n=this.hashEmail(e),t={emailHash:n,timestamp:Date.now(),sessionValid:!0};this.credentialStore.set(n,t),i.info(`Session stored for user: ${e.split("@")[0]}@***`)}hasValidSession(e){let n=this.hashEmail(e),t=this.credentialStore.get(n);return t?Date.now()-t.timestamp>this.SESSION_TIMEOUT?(this.credentialStore.delete(n),!1):t.sessionValid:!1}invalidateSession(e){let n=this.hashEmail(e);this.credentialStore.delete(n),i.info(`Session invalidated for user: ${e.split("@")[0]}@***`)}getLoginGuidance(e){switch(e){case"student":return`
|
|
27
27
|
[STUDENT] Student Login Guide:
|
|
28
28
|
- Use your @nnn.ed.jp email address
|
|
29
29
|
- Use your N High School password
|
|
@@ -73,19 +73,19 @@ ${!u&&e?"[WARNING] Cookie length mismatch detected - may cause authentication is
|
|
|
73
73
|
[PRO-TIP] Pro Tips:
|
|
74
74
|
- Use 'interactive_login' if automated login fails
|
|
75
75
|
- The browser window will stay open for manual completion
|
|
76
|
-
- 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 ie={};j(ie,{NLobbyMCPServer:()=>se});import{Server as ln}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as un}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as dn,ErrorCode as _,ListResourcesRequestSchema as pn,ListToolsRequestSchema as gn,McpError as F,ReadResourceRequestSchema as mn,ListPromptsRequestSchema as hn,GetPromptRequestSchema as fn}from"@modelcontextprotocol/sdk/types.js";var se,ae=g(()=>{"use strict";Y();E();re();oe();v();S();se=class{server;api;browserAuth;credentialManager;constructor(){this.server=new ln({name:m.mcp.serverName,version:m.mcp.serverVersion},{capabilities:{resources:{},tools:{},prompts:{}}}),this.api=new D,this.browserAuth=new I,this.credentialManager=new L,this.setupHandlers()}setupHandlers(){this.server.setRequestHandler(pn,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(mn,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 F(_.InvalidRequest,`Unknown resource: ${t}`)}}catch(n){throw new F(_.InternalError,`Failed to read resource: ${n instanceof Error?n.message:"Unknown error"}`)}}),this.server.setRequestHandler(gn,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(dn,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"}
|
|
76
|
+
- You can close the browser once login is complete`}cleanupExpiredSessions(){let e=Date.now(),n=0;for(let[t,r]of this.credentialStore.entries())e-r.timestamp>this.SESSION_TIMEOUT&&(this.credentialStore.delete(t),n++);n>0&&i.info(`Cleaned up ${n} expired sessions`)}getSessionStats(){let e=Date.now(),n=0;for(let t of this.credentialStore.values())e-t.timestamp>this.SESSION_TIMEOUT&&n++;return{total:this.credentialStore.size,expired:n}}}});var ae={};j(ae,{NLobbyMCPServer:()=>ie});import{Server as un}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as dn}from"@modelcontextprotocol/sdk/server/stdio.js";import{CallToolRequestSchema as pn,ErrorCode as _,ListResourcesRequestSchema as gn,ListToolsRequestSchema as mn,McpError as F,ReadResourceRequestSchema as hn,ListPromptsRequestSchema as fn,GetPromptRequestSchema as yn}from"@modelcontextprotocol/sdk/types.js";var ie,ce=g(()=>{"use strict";Y();E();oe();se();v();S();ie=class{server;api;browserAuth;credentialManager;constructor(){this.server=new un({name:m.mcp.serverName,version:m.mcp.serverVersion},{capabilities:{resources:{},tools:{},prompts:{}}}),this.api=new I,this.browserAuth=new L,this.credentialManager=new O,this.setupHandlers()}setupHandlers(){this.server.setRequestHandler(gn,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(hn,async e=>{let{uri:n}=e.params;try{switch(n){case"nlobby://news":{let t=await this.api.getNews();return{contents:[{uri:n,mimeType:"application/json",text:JSON.stringify(t,null,2)}]}}case"nlobby://schedule":{let t=await this.api.getSchedule("personal");return{contents:[{uri:n,mimeType:"application/json",text:JSON.stringify(t,null,2)}]}}case"nlobby://user-profile":{let t=await this.api.getUserInfo();return{contents:[{uri:n,mimeType:"application/json",text:JSON.stringify(t,null,2)}]}}case"nlobby://required-courses":{let t=await this.api.getRequiredCourses();return{contents:[{uri:n,mimeType:"application/json",text:JSON.stringify(t,null,2)}]}}default:throw new F(_.InvalidRequest,`Unknown resource: ${n}`)}}catch(t){throw new F(_.InternalError,`Failed to read resource: ${t instanceof Error?t.message:"Unknown error"}`)}}),this.server.setRequestHandler(mn,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(pn,async e=>{let{name:n,arguments:t}=e.params;try{switch(n){case"get_news":try{let{category:r,limit:s=10,sort:a="newest"}=t,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"}
|
|
77
77
|
|
|
78
78
|
To authenticate:
|
|
79
79
|
1. Login to N Lobby in your browser
|
|
80
80
|
2. Open Developer Tools (F12)
|
|
81
81
|
3. Go to Application/Storage tab
|
|
82
82
|
4. Copy cookies and use the set_cookies tool
|
|
83
|
-
5. Use health_check to verify connection`}]}}case"get_news_detail":try{let{newsId:r,markAsRead:s=!1}=
|
|
83
|
+
5. Use health_check to verify connection`}]}}case"get_news_detail":try{let{newsId:r,markAsRead:s=!1}=t,a=await this.api.getNewsDetail(r);if(s)try{await this.api.markNewsAsRead(r)}catch(c){i.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:s,category:a}=t,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)}s&&(l=l.filter(d=>d.termYear&&d.termYear.toString().includes(s))),a&&(l=l.filter(d=>d.curriculumName&&d.curriculumName.toLowerCase().includes(a.toLowerCase())));let u={totalCourses:l.length,filters:{grade:r,semester:s,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}=t,s=await this.api.getScheduleByDate(r);return{content:[{type:"text",text:JSON.stringify(s,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:s,to_date:a,period:c}=t,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 s&&a?u=this.api.createDateRange(s,a):s&&(u=this.api.createSingleDayRange(s));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)"}
|
|
84
84
|
|
|
85
|
-
${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:s}=
|
|
86
|
-
`)}]}}catch(r){return{content:[{type:"text",text:`Error testing calendar endpoints: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"set_cookies":{let{cookies:r}=
|
|
85
|
+
${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:s}=t,a;r&&s?a=this.api.createDateRange(r,s):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(`
|
|
86
|
+
`)}]}}catch(r){return{content:[{type:"text",text:`Error testing calendar endpoints: ${r instanceof Error?r.message:"Unknown error"}`}]}}case"set_cookies":{let{cookies:r}=t;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}=t;return{content:[{type:"text",text:await this.api.debugConnection(r||"/news")}]}}case"test_page_content":{let{endpoint:r,length:s}=t,a=await this.api.testPageContent(r||"/news",s||1e3);return{content:[{type:"text",text:`Sample content from ${r||"/news"}:
|
|
87
87
|
|
|
88
|
-
${a}`}]}}case"test_trpc_endpoint":{let{method:r,params:s}=
|
|
88
|
+
${a}`}]}}case"test_trpc_endpoint":{let{method:r,params:s}=t;try{let a=s?JSON.parse(s):{},c=await this.api.testTrpcEndpoint(r,a);return{content:[{type:"text",text:`Result of ${r} with params ${JSON.stringify(a)}:
|
|
89
89
|
|
|
90
90
|
${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
|
|
91
91
|
|
|
@@ -99,7 +99,7 @@ Extracted cookies:
|
|
|
99
99
|
- CSRF Token: ${r.csrfToken?"present":"missing"}
|
|
100
100
|
- Callback URL: ${r.callbackUrl||"not set"}
|
|
101
101
|
|
|
102
|
-
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}=
|
|
102
|
+
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}=t,s=`[LOGIN] N Lobby Login Help
|
|
103
103
|
|
|
104
104
|
`;if(r){let c=this.credentialManager.validateEmail(r);s+=`[EMAIL] Email: ${r}
|
|
105
105
|
`,s+=`[USER] User Type: ${c.userType}
|
|
@@ -113,31 +113,31 @@ ${this.credentialManager.getTroubleshootingTips()}`;let a=this.credentialManager
|
|
|
113
113
|
|
|
114
114
|
[STATUS] Session Stats:
|
|
115
115
|
- Active sessions: ${a.total-a.expired}
|
|
116
|
-
- Expired sessions: ${a.expired}`,{content:[{type:"text",text:s}]}}case"mark_news_as_read":try{let{ids:r}=
|
|
116
|
+
- Expired sessions: ${a.expired}`,{content:[{type:"text",text:s}]}}case"mark_news_as_read":try{let{ids:r}=t;if(!r||r.length===0)return{content:[{type:"text",text:"Error: No news article IDs provided."}]};let s=[],a=[];for(let l of r)try{await this.api.markNewsAsRead(l),s.push(l)}catch(u){a.push({id:l,error:u instanceof Error?u.message:"Unknown error"})}let c="";return s.length>0&&(c+=`Successfully marked ${s.length} news article(s) as read: ${s.join(", ")}
|
|
117
117
|
`),a.length>0&&(c+=`
|
|
118
118
|
Failed to mark ${a.length} news article(s) as read:
|
|
119
119
|
`,a.forEach(({id:l,error:u})=>{c+=`- ${l}: ${u}
|
|
120
|
-
`})),{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}=
|
|
121
|
-
`)}groupCoursesByGrade(e){let
|
|
122
|
-
`;if(
|
|
123
|
-
Email: ${
|
|
124
|
-
User type: ${s.userType}`,
|
|
125
|
-
Valid: ${s.valid?"Yes":"No"}`,!s.valid&&s.message&&(
|
|
126
|
-
Issue: ${s.message}`),
|
|
127
|
-
`,
|
|
128
|
-
`,
|
|
129
|
-
|
|
130
|
-
[STATUS] Session stats: ${r.total-r.expired} active, ${r.expired} expired`,console.log(
|
|
131
|
-
`).trimEnd()}function
|
|
132
|
-
|
|
133
|
-
`).trim();e.push(
|
|
134
|
-
`)}var
|
|
135
|
-
`).trimEnd()}function
|
|
136
|
-
`).trimEnd()}var
|
|
137
|
-
`).trimEnd()}var
|
|
138
|
-
`)}var
|
|
139
|
-
|
|
140
|
-
${
|
|
141
|
-
|
|
142
|
-
${JSON.stringify(s,null,2)}`)}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}}),e.command("verify").description("Verify authentication status and cookie synchronization across all clients").action(async()=>{try{let
|
|
143
|
-
\u2500\u2500 ${r.categoryName} \u2500\u2500`);for(let{menu:s}of r.items)console.log(` ${s.label}${s.badgeContent?` (${s.badgeContent})`:""}`)}}catch(
|
|
120
|
+
`})),{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}=t,s=r?new Date(r):void 0,a=await this.api.isExamDay(s);return{content:[{type:"text",text:JSON.stringify({date:s?s.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}=t,s=await this.api.getUserInterests(r);return{content:[{type:"text",text:JSON.stringify(s,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 F(_.MethodNotFound,`Unknown tool: ${n}`)}}catch(r){throw new F(_.InternalError,`Tool execution failed: ${r instanceof Error?r.message:"Unknown error"}`)}}),this.server.setRequestHandler(fn,async()=>({prompts:[]})),this.server.setRequestHandler(yn,async e=>{let{name:n}=e.params;throw new F(_.InvalidRequest,`Unknown prompt: ${n}`)})}async start(){try{let e=new dn;await this.server.connect(e),i.info("N Lobby MCP Server started successfully")}catch(e){i.error("Failed to start server:",e),process.exit(1)}}getAuthenticationRecommendations(){let e=this.api.getCookieStatus(),n=[];return e.includes("[ERROR] no cookies")&&e.includes("[ERROR] not authenticated")?(n.push("1. Run interactive_login to authenticate with N Lobby"),n.push("2. Make sure to complete the login process in the browser window"),n.push('3. Wait for the "Login successful" message before proceeding')):e.includes("[ERROR] not synchronized")?(n.push("1. Cookie synchronization issue detected"),n.push("2. Try running interactive_login again to refresh all cookies")):e.includes("[SUCCESS] authenticated")&&e.includes("[SUCCESS] synchronized")?(n.push("1. Authentication appears to be working correctly"),n.push("2. If endpoints are still failing, the issue may be server-side"),n.push("3. Try running health_check to verify connectivity")):(n.push("1. Check the authentication status above for specific issues"),n.push("2. Run health_check to verify overall system health")),n.join(`
|
|
121
|
+
`)}groupCoursesByGrade(e){let n={};for(let t of e){let r=t.grade||"Unknown";n[r]=(n[r]||0)+1}return n}groupCoursesByCurriculum(e){let n={};for(let t of e){let r=t.curriculumName||"Unknown";n[r]=(n[r]||0)+1}return n}}});import{Command as le}from"commander";function tt(o){return new le("login").description("Authenticate with N Lobby via browser").action(async()=>{console.log("Opening browser for N Lobby authentication...");try{let n=new L;await n.initializeBrowser();let t=await n.interactiveLogin();t&&t.allCookies?(o.setCookies(t.allCookies),re(t.allCookies),console.log("[OK] Login successful. Session saved.")):(console.error("[FAIL] Login failed or was cancelled."),process.exit(1))}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}})}function nt(){let o=new O;return new le("login-help").description("Get help and troubleshooting tips for N Lobby login").option("--email <email>","Your email address (for personalized guidance)").action(n=>{let t=`[LOGIN] N Lobby Login Help
|
|
122
|
+
`;if(n.email){let s=o.validateEmail(n.email);t+=`
|
|
123
|
+
Email: ${n.email}`,t+=`
|
|
124
|
+
User type: ${s.userType}`,t+=`
|
|
125
|
+
Valid: ${s.valid?"Yes":"No"}`,!s.valid&&s.message&&(t+=`
|
|
126
|
+
Issue: ${s.message}`),t+=`
|
|
127
|
+
`,t+=o.getLoginGuidance(s.userType)}else t+=o.getLoginGuidance("unknown");t+=`
|
|
128
|
+
`,t+=o.getTroubleshootingTips();let r=o.getSessionStats();t+=`
|
|
129
|
+
|
|
130
|
+
[STATUS] Session stats: ${r.total-r.expired} active, ${r.expired} expired`,console.log(t)})}function rt(o){let e=new le("cookies").description("Manage authentication cookies");return e.command("set <cookies>").description("Set cookies manually").action(n=>{o.setCookies(n),re(n),console.log("[OK] Cookies saved.")}),e.command("check").description("Show current cookie/authentication status").action(()=>{console.log(o.getCookieStatus())}),e}var ot=g(()=>{"use strict";Y();oe();se()});function st(o){if(o.length===0)return"No news found.";let e=[];for(let n of o){let t=new Date(n.publishedAt).toLocaleDateString("ja-JP"),r=n.isUnread?" [UNREAD]":"",s=n.isImportant?" [!]":"";e.push(`[${n.id}] ${t}${s}${r}`),e.push(` ${n.title}`),n.menuName&&e.push(` Category: ${n.menuName}`),e.push("")}return e.join(`
|
|
131
|
+
`).trimEnd()}function it(o){let e=[],n=new Date(o.publishedAt).toLocaleDateString("ja-JP");if(e.push(`Title: ${o.title}`),e.push(`Date: ${n}`),e.push(`Category: ${o.menuName.join(", ")}`),o.isImportant&&e.push("Important: Yes"),e.push(`URL: ${o.url}`),e.push(""),e.push("\u2500".repeat(50)),e.push(""),o.description)e.push(o.description);else{let t=o.content.replace(/<[^>]+>/g,"").replace(/ /g," ").replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/\n{3,}/g,`
|
|
132
|
+
|
|
133
|
+
`).trim();e.push(t)}if(o.attachments&&o.attachments.length>0){e.push(""),e.push("Attachments:");for(let t of o.attachments)e.push(` - ${t.fileName}: ${t.href}`)}return e.join(`
|
|
134
|
+
`)}var at=g(()=>{"use strict"});import{Command as wn}from"commander";function ct(o){let e=new wn("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 n=>{try{let t=await o.getNews();if(n.unread&&(t=t.filter(s=>s.isUnread)),n.category){let s=n.category.toLowerCase();t=t.filter(a=>a.category.toLowerCase().includes(s)||(a.menuName??"").toLowerCase().includes(s))}switch(n.sort){case"oldest":t.sort((s,a)=>new Date(s.publishedAt).getTime()-new Date(a.publishedAt).getTime());break;case"title-asc":t.sort((s,a)=>s.title.localeCompare(a.title));break;case"title-desc":t.sort((s,a)=>a.title.localeCompare(s.title));break;default:t.sort((s,a)=>new Date(a.publishedAt).getTime()-new Date(s.publishedAt).getTime())}let r=parseInt(n.limit,10);t=t.slice(0,r),n.json?console.log(JSON.stringify(t,null,2)):console.log(st(t))}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("show <id>").description("Show news detail").option("--json","Output raw JSON").action(async(n,t)=>{try{let r=await o.getNewsDetail(n);t.json?console.log(JSON.stringify(r,null,2)):console.log(it(r))}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}}),e.command("read <ids...>").description("Mark one or more news articles as read").action(async n=>{let t=[],r=[];for(let s of n)try{await o.markNewsAsRead(s),r.push(s)}catch(a){t.push({id:s,error:a instanceof Error?a.message:String(a)})}if(r.length>0&&console.log(`[OK] Marked as read: ${r.join(", ")}`),t.length>0){for(let s of t)console.error(`[FAIL] ${s.id}: ${s.error}`);process.exit(1)}}),e.command("unread-info").description("Show unread news count and flags").option("--json","Output raw JSON").action(async n=>{try{let t=await o.getUnreadNewsInfo();n.json?console.log(JSON.stringify(t,null,2)):console.log(`Unread: ${t.totalCount} (important: ${t.hasImportantNews}, mentor: ${t.byMentorNewsCount})`)}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e}var lt=g(()=>{"use strict";at()});function W(o){return o.toLocaleTimeString("ja-JP",{hour:"2-digit",minute:"2-digit"})}function ut(o){return o.toLocaleDateString("ja-JP",{year:"numeric",month:"2-digit",day:"2-digit",weekday:"short"})}function dt(o){if(o.length===0)return"No schedule items found.";let e=new Map;for(let t of o){let r=ut(new Date(t.startTime)),s=e.get(r)??[];s.push(t),e.set(r,s)}let n=[];for(let[t,r]of e){n.push(`\u2500\u2500 ${t} \u2500\u2500`);for(let s of r){let a=W(new Date(s.startTime)),c=W(new Date(s.endTime));n.push(` ${a}\u2013${c} ${s.title}`),s.location&&n.push(` Location: ${s.location}`),s.description&&n.push(` ${s.description}`)}n.push("")}return n.join(`
|
|
135
|
+
`).trimEnd()}function pt(o){if(o.length===0)return"No calendar events found.";let e=[];for(let n of o){let t=n.start.dateTime??n.start.date??"",r=n.end.dateTime??n.end.date??"",s=!n.start.dateTime,a;if(s)a=t;else{let c=new Date(t),l=new Date(r);a=`${ut(c)} ${W(c)}\u2013${W(l)}`}if(e.push(`[${n.id}] ${n.summary}`),e.push(` ${a}`),n.location&&e.push(` Location: ${n.location}`),n.description){let c=n.description.replace(/<[^>]+>/g,"").trim();c&&e.push(` ${c}`)}e.push("")}return e.join(`
|
|
136
|
+
`).trimEnd()}var gt=g(()=>{"use strict"});import{Command as mt}from"commander";function ht(o){return new mt("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(n,t)=>{try{let r=await o.getScheduleByDate(n);t.json?console.log(JSON.stringify(r,null,2)):console.log(dt(r))}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}})}function ft(o){let e=new mt("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 n=>{try{let t=n.type==="school"?"school":"personal",r=n.from&&n.to?o.createDateRange(n.from,n.to):o.createWeekDateRange(),s=await o.getGoogleCalendarEvents(t,r);n.json?console.log(JSON.stringify(s,null,2)):console.log(pt(s))}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}});return e.command("test").description("Test both personal and school calendar endpoints").option("--from <date>","Start date (YYYY-MM-DD)").option("--to <date>","End date (YYYY-MM-DD)").option("--json","Output raw JSON").action(async n=>{try{let t=n.from&&n.to?o.createDateRange(n.from,n.to):n.from?o.createSingleDayRange(n.from):void 0,r=await o.testCalendarEndpoints(t);n.json?console.log(JSON.stringify(r,null,2)):(console.log(`Personal: ${r.personal.success?"[OK]":"[FAIL]"} ${r.personal.count} events${r.personal.error?` (${r.personal.error})`:""}`),console.log(`School: ${r.school.success?"[OK]":"[FAIL]"} ${r.school.count} events${r.school.error?` (${r.school.error})`:""}`))}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("filters").description("Show lobby calendar filter list").option("--json","Output raw JSON").action(async n=>{try{let t=await o.getLobbyCalendarFilters();if(n.json)console.log(JSON.stringify(t,null,2));else if(t.length===0)console.log("No calendar filters found.");else for(let r of t)console.log(`[${r.id}] ${r.label} (${r.color})`)}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e}var yt=g(()=>{"use strict";v();gt()});function bn(o){switch(o){case 0:return"Not Started";case 1:return"In Progress";case 2:return"Completed";default:return`Status ${o}`}}function wt(o){if(o.length===0)return"No courses found.";let e=[],n=new Map;for(let t of o){let r=t.grade?`Grade ${t.grade}${t.term!=null?` / Term ${t.term}`:""}`:"Courses",s=n.get(r)??[];s.push(t),n.set(r,s)}for(let[t,r]of n){e.push(`\u2500\u2500 ${t} \u2500\u2500`);for(let s of r){let a=bn(s.subjectStatus),c=s.progressPercentage!=null?` (${s.progressPercentage.toFixed(0)}%)`:"";e.push(` [${s.subjectCode}] ${s.subjectName}`),e.push(` Curriculum: ${s.curriculumName}`),e.push(` Status: ${a}${c}`),e.push(` Reports: ${s.report.count}/${s.report.allCount}`),s.schooling.necessaryCount>0&&e.push(` Attendance: ${s.schooling.attendanceCount}/${s.schooling.necessaryCount}`),s.averageScore!=null&&e.push(` Avg Score: ${s.averageScore.toFixed(1)}`);let l=s.acquired.approvedCredit;l>0&&e.push(` Credits: ${l}`),e.push("")}}return e.join(`
|
|
137
|
+
`).trimEnd()}var bt=g(()=>{"use strict"});import{Command as Cn}from"commander";function Ct(o){return new Cn("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 n=>{try{let t=await o.getRequiredCourses();n.grade&&(t=t.filter(r=>String(r.grade)===n.grade)),n.semester&&(t=t.filter(r=>String(r.term)===n.semester)),n.json?console.log(JSON.stringify(t,null,2)):console.log(wt(t))}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}})}var St=g(()=>{"use strict";bt()});function kt(o){let e=[];return e.push("\u2500\u2500 Account Information \u2500\u2500"),e.push(`Name: ${o.name??"(unknown)"}`),e.push(`Email: ${o.email??"(unknown)"}`),e.push(`Role: ${o.role??"(unknown)"}`),o.studentNo&&e.push(`Student No: ${o.studentNo}`),o.userId&&e.push(`User ID: ${o.userId}`),o.grade!=null&&e.push(`Grade: ${o.grade}`),o.term!=null&&e.push(`Term: ${o.term}`),o.isLobbyAdmin&&e.push("Admin: Yes"),typeof o.kmsLoginSuccess=="boolean"&&e.push(`KMS Login: ${o.kmsLoginSuccess?"OK":"Failed"}`),Array.isArray(o.studentOrganizations)&&o.studentOrganizations.length>0&&e.push(`Organizations: ${o.studentOrganizations.length}`),Array.isArray(o.staffDepartments)&&o.staffDepartments.length>0&&e.push(`Departments: ${o.staffDepartments.length}`),e.join(`
|
|
138
|
+
`)}var Nt=g(()=>{"use strict"});import{Command as Sn}from"commander";function Rt(o){let e=new Sn("profile").description("User profile and account information");return e.command("show",{isDefault:!0}).description("Show user profile (default)").option("--json","Output raw JSON").action(async n=>{try{let t=await o.getAccountInfoFromScript("/");n.json?console.log(JSON.stringify(t,null,2)):console.log(kt(t))}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("card").description("Capture student ID card screenshot").option("--json","Output raw JSON (metadata only, no image)").action(async n=>{try{console.log("Capturing student card screenshot...");let t=await o.getStudentCardScreenshot();n.json?console.log(JSON.stringify({filePath:t.path,studentNo:t.studentNo,secureHost:t.secureHost,callbackUrl:t.callbackUrl,finalUrl:t.finalUrl,elementSize:t.elementSize},null,2)):(console.log(`[OK] Student card saved: ${t.path}`),console.log(` Student No: ${t.studentNo}`),t.elementSize&&console.log(` Size: ${t.elementSize.width}x${t.elementSize.height}`))}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("update-access").description("Update last access timestamp").option("--json","Output raw JSON").action(async n=>{try{let t=await o.updateLastAccess();n.json?console.log(JSON.stringify({success:t},null,2)):console.log(t?"[OK] Last access updated.":"[FAIL] Update failed."),t||process.exit(1)}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e}var Et=g(()=>{"use strict";Nt()});function xt(o){return o?"[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 At=g(()=>{"use strict"});import{Command as kn}from"commander";function Tt(o){let e=new kn("health").description("API connectivity and debugging tools");return e.command("check",{isDefault:!0}).description("Check N Lobby API connectivity and authentication (default)").option("--json","Output raw JSON").action(async n=>{try{let t=await o.healthCheck();n.json?console.log(JSON.stringify({ok:t},null,2)):console.log(xt(t)),t||process.exit(1)}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("debug").description("Debug N Lobby connection with detailed information").option("--endpoint <path>","Endpoint to test","/news").action(async n=>{try{let t=await o.debugConnection(n.endpoint);console.log(t)}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("page").description("Test page content retrieval and show sample content").option("--endpoint <path>","Endpoint to test","/news").option("--length <n>","Number of characters to show","1000").action(async n=>{try{let t=await o.testPageContent(n.endpoint,parseInt(n.length,10));console.log(`Sample content from ${n.endpoint}:
|
|
139
|
+
|
|
140
|
+
${t}`)}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("trpc <method>").description("Test a specific tRPC endpoint (e.g. news.getUnreadNewsCount)").option("--params <json>","JSON string of parameters").option("--json","Output raw JSON result").action(async(n,t)=>{try{let r=t.params?JSON.parse(t.params):{},s=await o.testTrpcEndpoint(n,r);t.json?console.log(JSON.stringify(s,null,2)):console.log(`Result of ${n} with params ${JSON.stringify(r)}:
|
|
141
|
+
|
|
142
|
+
${JSON.stringify(s,null,2)}`)}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}}),e.command("verify").description("Verify authentication status and cookie synchronization across all clients").action(async()=>{try{let n=o.getCookieStatus();console.log(n)}catch(n){console.error("[FAIL]",n instanceof Error?n.message:n),process.exit(1)}}),e}var vt=g(()=>{"use strict";At()});import{Command as Nn}from"commander";function Dt(){return new Nn("serve").alias("mcp").description("Start the MCP server (stdio transport)").action(async()=>{let{logger:e}=await Promise.resolve().then(()=>(S(),pe));e.forceProductionMode();let{NLobbyMCPServer:n}=await Promise.resolve().then(()=>(ce(),ae));await new n().start()})}var It=g(()=>{"use strict"});import{Command as Rn}from"commander";function Lt(o){let e=new Rn("exam").description("Exam day utilities");return e.command("check").description("Check if a date is an exam day (default: today)").argument("[date]","Date in YYYY-MM-DD format").option("--json","Output raw JSON").action(async(n,t)=>{try{let r=n?new Date(n):void 0,s=await o.isExamDay(r),a=(r??new Date).toISOString().split("T")[0];t.json?console.log(JSON.stringify({date:a,isExamDay:s},null,2)):console.log(s?`[EXAM] ${a} is an exam day.`:`[OK] ${a} is not an exam day.`)}catch(r){console.error("[FAIL]",r instanceof Error?r.message:r),process.exit(1)}}),e.command("finish").description("Finish exam day mode").option("--json","Output raw JSON").action(async n=>{try{let t=await o.finishExamDayMode();n.json?console.log(JSON.stringify({success:t},null,2)):console.log(t?"[OK] Exam day mode finished.":"[FAIL] Failed to finish exam day mode."),t||process.exit(1)}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("otp").description("Get one-time password for exam").option("--json","Output raw JSON").action(async n=>{try{let t=await o.getExamOneTimePassword();n.json,console.log(JSON.stringify(t,null,2))}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e}var Ot=g(()=>{"use strict"});import{Command as En}from"commander";function $t(o){let e=new En("nav").description("Navigation, notifications, and user interests");return e.command("menus").description("Show main navigation menu list").option("--json","Output raw JSON").action(async n=>{try{let t=await o.getMainNavigations();if(n.json)console.log(JSON.stringify(t,null,2));else if(t.length===0)console.log("No navigation menus found.");else for(let r of t){r.categoryName&&console.log(`
|
|
143
|
+
\u2500\u2500 ${r.categoryName} \u2500\u2500`);for(let{menu:s}of r.items)console.log(` ${s.label}${s.badgeContent?` (${s.badgeContent})`:""}`)}}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("notifications").description("Show notification messages").option("--json","Output raw JSON").action(async n=>{try{let t=await o.getNotificationMessages();if(n.json)console.log(JSON.stringify(t,null,2));else if(t.length===0)console.log("No notifications.");else for(let r of t)console.log(`[${r.id}] ${r.title??""}`),r.body&&console.log(` ${r.body}`)}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("interests").description("Show user interest tags").option("--with-icon","Include icon information").option("--json","Output raw JSON").action(async n=>{try{let t=await o.getUserInterests(n.withIcon??!1);if(n.json)console.log(JSON.stringify(t,null,2));else if(t.length===0)console.log("No interests found.");else for(let r of t){let s=n.withIcon&&r.iconName?` [${r.iconName}]`:"";console.log(` ${r.name}${s} (weight: ${r.weightId})`)}}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e.command("weights").description("Show interest weight scale definitions").option("--json","Output raw JSON").action(async n=>{try{let t=await o.getInterestWeights();if(n.json)console.log(JSON.stringify(t,null,2));else if(t.length===0)console.log("No weight definitions found.");else for(let r of t)console.log(` [${r.id}] ${r.label} (value: ${r.value})`)}catch(t){console.error("[FAIL]",t instanceof Error?t.message:t),process.exit(1)}}),e}var Ut=g(()=>{"use strict"});var _t={};j(_t,{buildProgram:()=>Pt,runCli:()=>An});import{Command as xn}from"commander";function Pt(){let o=new I,e=new xn().name("nlobby").description("N Lobby CLI \u2014 access N Lobby from the command line").version("1.4.5");return e.addCommand(tt(o)),e.addCommand(rt(o)),e.addCommand(nt()),e.addCommand(ct(o)),e.addCommand(ht(o)),e.addCommand(ft(o)),e.addCommand(Ct(o)),e.addCommand(Rt(o)),e.addCommand(Tt(o)),e.addCommand(Lt(o)),e.addCommand($t(o)),e.addCommand(Dt()),e}async function An(){await Pt().parseAsync(process.argv)}var Ft=g(()=>{"use strict";Y();ot();lt();yt();St();Et();vt();It();Ot();Ut()});var ue=process.argv.slice(2),Tn=ue[0]==="serve"||ue[0]==="mcp",vn=ue.length===0&&!process.stdin.isTTY;async function Dn(){if(Tn||vn){let{NLobbyMCPServer:o}=await Promise.resolve().then(()=>(ce(),ae));await new o().start()}else{let{runCli:o}=await Promise.resolve().then(()=>(Ft(),_t));await o()}}Dn().catch(o=>{console.error("Fatal error:",o instanceof Error?o.message:o),process.exit(1)});
|