@flyle/ai-contact-center-mcp 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -4
- package/main.js +18 -0
- package/manifest.json.br +0 -0
- package/package.json +1 -59
- package/dist/main.js +0 -3800
- package/generated/manifest.json +0 -10673
package/README.md
CHANGED
|
@@ -60,7 +60,3 @@ Claude Code を起動したままログインした場合は、`/mcp` から MCP
|
|
|
60
60
|
- 公開の実行・昇格・取消など、本番の応対に直接影響する操作は提供していません(公開状態の参照はできます)。
|
|
61
61
|
- ツールがダウンロードしたファイル(ナレッジ原本・音声など)は、作業ディレクトリの `.flyle-ai-contact-center-mcp/downloads` に保存されます。
|
|
62
62
|
- アップロードなどで読み込めるのは、作業ディレクトリの中のファイルだけです。
|
|
63
|
-
|
|
64
|
-
## 以前の設定から移行する
|
|
65
|
-
|
|
66
|
-
以前の版で `.mcp.json` の `env` に書いていた API キー・接続先・テナント名などの環境変数は使えなくなりました。`env` を削除し、上の手順でログインしてください。残っていると、MCP サーバーは変数名を示して起動を止めます。
|
package/main.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{homedir as e,hostname as t,userInfo as n}from"node:os";import{serveStdio as r}from"@modelcontextprotocol/server/stdio";import{createHash as i,randomBytes as a,timingSafeEqual as o}from"node:crypto";import{chmod as s,link as c,mkdir as l,open as u,readFile as d,realpath as f,rename as p,rm as m,unlink as h,writeFile as ee}from"node:fs/promises";import*as g from"node:path";import{spawn as te}from"node:child_process";import{createServer as ne}from"node:http";import{parseArgs as re}from"node:util";import{constants as ie,readFileSync as ae}from"node:fs";import{brotliDecompressSync as oe}from"node:zlib";import{McpServer as se,fromJsonSchema as ce}from"@modelcontextprotocol/server";function _(e,t){return Object.hasOwn(e,t)}const le=(e,t)=>_(e,t),ue=e=>{let t=[];for(let n in e)le(e,n)&&t.push(n);return t},de=e=>{let t=[];for(let n in e)if(le(e,n)){let r=Reflect.get(e,n);t.push([n,r])}return t},fe=e=>{let t={};for(let[n,r]of e)Object.defineProperty(t,n,{configurable:!0,enumerable:!0,value:r,writable:!0});return t},v=e=>typeof e==`object`&&!!e&&!Array.isArray(e);function pe(e){return{lang:e?.lang??void 0,message:e?.message,abortEarly:e?.abortEarly??void 0,abortPipeEarly:e?.abortPipeEarly??void 0}}function me(e){let t=typeof e;return t===`string`?`"${e}"`:t===`number`||t===`bigint`||t===`boolean`?`${e}`:t===`object`||t===`function`?(e&&Object.getPrototypeOf(e)?.constructor?.name)??`null`:t}function y(e,t,n,r,i){let a=i&&`input`in i?i.input:n.value,o=i?.expected??e.expects??null,s=i?.received??me(a),c={kind:e.kind,type:e.type,input:a,expected:o,received:s,message:`Invalid ${t}: ${o?`Expected ${o} but r`:`R`}eceived ${s}`,requirement:e.requirement,path:i?.path,issues:i?.issues,lang:r.lang,abortEarly:r.abortEarly,abortPipeEarly:r.abortPipeEarly},l=e.kind===`schema`,u=i?.message??e.message??(e.reference,c.lang,void 0)??(l?(c.lang,void 0):null)??r.message??(c.lang,void 0);u!==void 0&&(c.message=typeof u==`function`?u(c):u),l&&(n.typed=!1),n.issues?n.issues.push(c):n.issues=[c]}function b(e){return{version:1,vendor:`valibot`,validate(t){return e[`~run`]({value:t},pe())}}}function he(e,t){let n=[...new Set(e)];return n.length>1?`(${n.join(` ${t} `)})`:n[0]??`never`}const ge=/^\d{4}-(?:0[1-9]|1[0-2])-(?:[12]\d|0[1-9]|3[01])[T ](?:0\d|1\d|2[0-3])(?::[0-5]\d){2}(?:\.\d{1,9})?(?:Z| ?[+-](?:0\d|1\d|2[0-3])(?::?[0-5]\d)?)$/u;function _e(e,t){return{kind:`validation`,type:`check`,reference:_e,async:!1,expects:null,requirement:e,message:t,"~run"(e,t){return e.typed&&!this.requirement(e.value)&&y(this,`input`,e,t),e}}}function ve(e,t){let n=me(e);return{kind:`validation`,type:`includes`,reference:ve,async:!1,expects:n,requirement:e,message:t,"~run"(e,t){return e.typed&&!e.value.includes(this.requirement)&&y(this,`content`,e,t,{received:`!${n}`}),e}}}function x(e){return{kind:`validation`,type:`iso_timestamp`,reference:x,async:!1,expects:null,requirement:ge,message:e,"~run"(e,t){return e.typed&&!this.requirement.test(e.value)&&y(this,`timestamp`,e,t),e}}}function S(e,t){return{kind:`validation`,type:`regex`,reference:S,async:!1,expects:`${e}`,requirement:e,message:t,"~run"(e,t){return e.typed&&!this.requirement.test(e.value)&&y(this,`format`,e,t),e}}}function ye(e){return{kind:`validation`,type:`url`,reference:ye,async:!1,expects:null,requirement(e){try{return new URL(e),!0}catch{return!1}},message:e,"~run"(e,t){return e.typed&&!this.requirement(e.value)&&y(this,`URL`,e,t),e}}}function be(e,t,n){return typeof e.fallback==`function`?e.fallback(t,n):e.fallback}function xe(e,t,n){return typeof e.default==`function`?e.default(t,n):e.default}function Se(e,t){return{kind:`schema`,type:`array`,reference:Se,expects:`Array`,async:!1,item:e,message:t,get"~standard"(){return b(this)},"~run"(e,t){let n=e.value;if(Array.isArray(n)){e.typed=!0,e.value=[];for(let r=0;r<n.length;r++){let i=n[r],a=this.item[`~run`]({value:i},t);if(a.issues){let o={type:`array`,origin:`value`,input:n,key:r,value:i};for(let t of a.issues)t.path?t.path.unshift(o):t.path=[o],e.issues?.push(t);if(e.issues||=a.issues,t.abortEarly){e.typed=!1;break}}a.typed||(e.typed=!1),e.value.push(a.value)}}else y(this,`type`,e,t);return e}}}function Ce(e,t){return{kind:`schema`,type:`literal`,reference:Ce,expects:me(e),async:!1,literal:e,message:t,get"~standard"(){return b(this)},"~run"(e,t){return e.value===this.literal?e.typed=!0:y(this,`type`,e,t),e}}}function we(e,t){return{kind:`schema`,type:`nullable`,reference:we,expects:`(${e.expects} | null)`,async:!1,wrapped:e,default:t,get"~standard"(){return b(this)},"~run"(e,t){return e.value===null&&(this.default!==void 0&&(e.value=xe(this,e,t)),e.value===null)?(e.typed=!0,e):this.wrapped[`~run`](e,t)}}}function C(e,t){return{kind:`schema`,type:`object`,reference:C,expects:`Object`,async:!1,entries:e,message:t,get"~standard"(){return b(this)},"~run"(e,t){let n=e.value;if(n&&typeof n==`object`){e.typed=!0,e.value={};for(let r in this.entries){let i=this.entries[r];if(r in n||(i.type===`exact_optional`||i.type===`optional`||i.type===`nullish`)&&i.default!==void 0){let a=r in n?n[r]:xe(i),o=i[`~run`]({value:a},t);if(o.issues){let i={type:`object`,origin:`value`,input:n,key:r,value:a};for(let t of o.issues)t.path?t.path.unshift(i):t.path=[i],e.issues?.push(t);if(e.issues||=o.issues,t.abortEarly){e.typed=!1;break}}o.typed||(e.typed=!1),e.value[r]=o.value}else if(i.fallback!==void 0)e.value[r]=be(i);else if(i.type!==`exact_optional`&&i.type!==`optional`&&i.type!==`nullish`&&(y(this,`key`,e,t,{input:void 0,expected:`"${r}"`,path:[{type:`object`,origin:`key`,input:n,key:r,value:n[r]}]}),t.abortEarly))break}}else y(this,`type`,e,t);return e}}}function Te(e,t){return{kind:`schema`,type:`optional`,reference:Te,expects:`(${e.expects} | undefined)`,async:!1,wrapped:e,default:t,get"~standard"(){return b(this)},"~run"(e,t){return e.value===void 0&&(this.default!==void 0&&(e.value=xe(this,e,t)),e.value===void 0)?(e.typed=!0,e):this.wrapped[`~run`](e,t)}}}function Ee(e,t){return{kind:`schema`,type:`strict_object`,reference:Ee,expects:`Object`,async:!1,entries:e,message:t,get"~standard"(){return b(this)},"~run"(e,t){let n=e.value;if(n&&typeof n==`object`){e.typed=!0,e.value={};for(let r in this.entries){let i=this.entries[r];if(r in n||(i.type===`exact_optional`||i.type===`optional`||i.type===`nullish`)&&i.default!==void 0){let a=r in n?n[r]:xe(i),o=i[`~run`]({value:a},t);if(o.issues){let i={type:`object`,origin:`value`,input:n,key:r,value:a};for(let t of o.issues)t.path?t.path.unshift(i):t.path=[i],e.issues?.push(t);if(e.issues||=o.issues,t.abortEarly){e.typed=!1;break}}o.typed||(e.typed=!1),e.value[r]=o.value}else if(i.fallback!==void 0)e.value[r]=be(i);else if(i.type!==`exact_optional`&&i.type!==`optional`&&i.type!==`nullish`&&(y(this,`key`,e,t,{input:void 0,expected:`"${r}"`,path:[{type:`object`,origin:`key`,input:n,key:r,value:n[r]}]}),t.abortEarly))break}if(!e.issues||!t.abortEarly){for(let r in n)if(!(r in this.entries)){y(this,`key`,e,t,{input:r,expected:`never`,path:[{type:`object`,origin:`key`,input:n,key:r,value:n[r]}]});break}}}else y(this,`type`,e,t);return e}}}function w(e){return{kind:`schema`,type:`string`,reference:w,expects:`string`,async:!1,message:e,get"~standard"(){return b(this)},"~run"(e,t){return typeof e.value==`string`?e.typed=!0:y(this,`type`,e,t),e}}}function De(e){let t;if(e)for(let n of e)t?t.push(...n.issues):t=n.issues;return t}function Oe(e,t){return{kind:`schema`,type:`union`,reference:Oe,expects:he(e.map(e=>e.expects),`|`),async:!1,options:e,message:t,get"~standard"(){return b(this)},"~run"(e,t){let n,r,i;for(let a of this.options){let o=a[`~run`]({value:e.value},t);if(o.typed){if(o.issues)r?r.push(o):r=[o];else{n=o;break}}else i?i.push(o):i=[o]}if(n)return n;if(r){if(r.length===1)return r[0];y(this,`type`,e,t,{issues:De(r)}),e.typed=!0}else if(i?.length===1)return i[0];else y(this,`type`,e,t,{issues:De(i)});return e}}}function T(...e){return{...e[0],pipe:e,get"~standard"(){return b(this)},"~run"(t,n){for(let r of e)if(r.kind!==`metadata`){if(t.issues&&(r.kind===`schema`||r.kind===`transformation`)){t.typed=!1;break}(!t.issues||!n.abortEarly&&!n.abortPipeEarly)&&(t=r[`~run`](t,n))}return t}}}function E(e,t,n){let r=e[`~run`]({value:t},pe(n));return{typed:r.typed,success:!r.issues,output:r.value,issues:r.issues}}const ke=`0.2.0`,Ae=/^flyle_ai_contact_center_ac_[0-9A-Za-z]{43}$/,je=/^flyle_ai_contact_center_ut_[0-9A-Za-z]{43}$/,Me=/^flyle_ai_contact_center_rt_[0-9A-Za-z]{43}$/,Ne=/^[0-7][0-9A-HJKMNP-TV-Z]{25}$/,Pe=/^[a-z0-9](-?[a-z0-9])*$/,Fe=6e5,Ie=536870912;var Le=class extends Error{name=`ManifestLoadError`},D=class extends Error{name=`ConfigError`},O=class extends Error{name=`ApiError`;info;constructor(e){super(`${e.status} ${e.code??`http_error`}: ${e.message}`),this.info=e}},k=class extends Error{name=`TransportError`;kind;status;constructor(e,t,n=null){super(t),this.kind=e,this.status=n}},A=class extends Error{name=`TransferError`;kind;status;constructor(e,t,n=null){super(t),this.kind=e,this.status=n}},j=class extends Error{name=`LocalFileError`;kind;constructor(e,t){super(t),this.kind=e}},M=class extends Error{name=`InlineFileError`;kind;constructor(e,t){super(t),this.kind=e}},N=class extends Error{name=`InvalidArgumentsError`},Re=class extends Error{name=`OperationFailedError`;payload;constructor(e,t){super(e),this.payload=t}},P=class extends Error{name=`WorkspaceBindingError`;kind;constructor(e,t){super(t),this.kind=e}};const ze="ログインが必要です。作業ディレクトリで `npx @flyle/ai-contact-center-mcp login` を実行してください";var F=class extends Error{name=`AuthError`;kind;constructor(e,t=ze){super(t),this.kind=e}},Be=class extends Error{name=`InvalidGrantError`},I=class extends Error{name=`CliError`};const Ve={allowInsecureHttp:`FLYLE_AI_CONTACT_CENTER_MCP_ALLOW_INSECURE_HTTP`},He=[`FLYLE_AI_CONTACT_CENTER_API_BASE_URL`,`FLYLE_AI_CONTACT_CENTER_TENANT_NAME`,`FLYLE_AI_CONTACT_CENTER_MCP_OUTPUT_DIR`,`FLYLE_AI_CONTACT_CENTER_MCP_FILE_ROOTS`,`FLYLE_AI_CONTACT_CENTER_MCP_STORAGE_HOSTS`],Ue=[`.amazonaws.com`],We=new Set([`localhost`,`127.0.0.1`,`[::1]`]),Ge=e=>{let t=e.length;for(;t>0&&e[t-1]===`/`;)--t;return e.slice(0,t)},Ke=e=>We.has(e),L=(e,t,n)=>{let r;try{r=new URL(e)}catch{throw new D(`${n} is not a valid URL`)}if(r.search!==``||r.hash!==``||r.username!==``||r.password!==``)throw new D(`${n} must not contain query, hash, or credentials`);let i=r.protocol===`http:`&&t&&Ke(r.hostname);if(r.protocol!==`https:`&&!i)throw new D(`${n} must use https (http is allowed only for localhost with ${Ve.allowInsecureHttp}=1)`);let a=Ge(r.pathname);return new URL(`${r.origin}${a}`)},qe=e=>e===`1`||e===`true`,Je=e=>e.length>=2&&e.length<=32&&Pe.test(e),Ye=(e,t)=>{if(!Je(e))throw new D(`${t} is not a valid tenant name`);return e},Xe=e=>{if(e.FLYLE_AI_CONTACT_CENTER_API_KEY!=null)throw new D("API キー方式は廃止されました。`npx @flyle/ai-contact-center-mcp login` でログインしてください");let t=He.filter(t=>e[t]!=null);if(t.length!==0)throw new D(`${t.join(`, `)} は廃止しました。MCP の設定から削除してください。接続先(環境とテナント)は作業ディレクトリで \`npx @flyle/ai-contact-center-mcp login --tenant <テナント名>\` を実行すると決まり、保存先と読込元は作業ディレクトリです。`)},Ze=e=>qe(e[Ve.allowInsecureHttp]),R=e=>e.host,Qe=(e,t,n)=>{let r=Ze(e);return{baseUrl:L(n.apiBaseUrl,r,`作業ディレクトリの接続先`),tenantName:Ye(n.tenantName,`作業ディレクトリのテナント`),outputDir:g.resolve(t,`.flyle-ai-contact-center-mcp/downloads`),fileRoots:[t],storageHostSuffixes:Ue,allowInsecureHttp:r}},z=()=>{},$e=`flyle-ai-contact-center-mcp`,et=`credentials`,B=()=>a(8).toString(`hex`),tt=Ee({version:Ce(1),apiBaseUrl:T(w(),ye()),tenantName:T(w(),_e(Je)),loginConnectionId:T(w(),S(Ne)),accessToken:T(w(),S(je)),accessTokenExpiresAt:T(w(),x()),refreshToken:T(w(),S(Me)),refreshTokenExpiresAt:T(w(),x())}),nt=({platform:e,env:t,homeDir:n})=>{let r=t.XDG_CONFIG_HOME;if(r!=null&&g.isAbsolute(r))return g.join(r,$e,et);let i=t.APPDATA;return e===`win32`&&i!=null&&g.isAbsolute(i)?g.join(i,$e,et):g.join(n,`.config`,$e,et)},rt=(e,t)=>g.join(e,`${t}.json`),V=e=>e instanceof Error&&_(e,`code`)?e.code:null,it=async e=>{let t;try{t=await d(e,`utf8`)}catch(e){if(V(e)===`ENOENT`)return null;throw e}let n;try{n=JSON.parse(t)}catch{n=null}let r=E(tt,n);if(!r.success)throw new F(`login_required`,`保存されたログイン情報(${e})を読めません。作業ディレクトリで \`npx @flyle/ai-contact-center-mcp login\` を実行し直してください`);return r.output},at=async e=>{await l(e,{recursive:!0,mode:448}),await s(e,448)},ot=async(e,t)=>{await at(g.dirname(e));let n={version:1,...t},r=`${e}.${B()}.tmp`;try{let t=await u(r,`wx`,384);try{await t.writeFile(`${JSON.stringify(n,null,2)}\n`)}finally{await t.close()}await p(r,e)}catch(e){throw await m(r,{force:!0}).catch(z),e}},st=async e=>{await m(e,{force:!0})},ct=(e,t)=>({staleMs:6e4,acquireTimeoutMs:9e4,retryIntervalMs:100,now:e,sleep:t}),lt=async e=>{let t;try{t=await u(e,`r`)}catch(e){if(V(e)===`ENOENT`)return null;throw e}try{let[e,n]=await Promise.all([t.readFile(`utf8`),t.stat()]);return{owner:e,mtimeMs:n.mtimeMs}}finally{await t.close()}},ut=async(e,t)=>{let n=`${e}.${B()}.aside`;try{await p(e,n)}catch(e){if(V(e)===`ENOENT`)return!1;throw e}return await d(n,`utf8`)===t?(await m(n,{force:!0}),!0):(await c(n,e).catch(e=>{if(V(e)!==`EEXIST`)throw e}),await m(n,{force:!0}),!1)},dt=async(e,t)=>{let n=await lt(e);return n==null?!0:t.now()-n.mtimeMs<t.staleMs?!1:ut(e,n.owner)},ft=async(e,t)=>{let n=`${e}.${B()}.tmp`,r=await u(n,`wx`,384);try{await r.writeFile(t)}finally{await r.close()}try{return await c(n,e),!0}catch(e){if(V(e)===`EEXIST`)return!1;throw e}finally{await m(n,{force:!0})}},pt=async(e,t,n)=>{await at(g.dirname(e));let r=`${e}.lock`,i=B(),a=t.now()+t.acquireTimeoutMs;for(;!await ft(r,i);)if(!await dt(r,t)){if(t.now()>=a)throw Error(`ログイン情報のロック(${r})を取得できませんでした。別の MCP プロセスが更新中です。しばらくしてから再実行してください`);await t.sleep(t.retryIntervalMs)}try{return await n()}finally{await ut(r,i)}},mt=/\r\n|\n|\r/,ht=()=>{let e=``,t=!1,n=``,r=[],i=null,a=()=>{if(r.length===0)return n=``,null;let e={event:n===``?`message`:n,data:r.join(`
|
|
3
|
+
`),id:i};return n=``,r=[],e},o=e=>{if(e===``)return a();if(e.startsWith(`:`))return null;let t=e.indexOf(`:`),o=t===-1?e:e.slice(0,t),s=t===-1?``:e.slice(t+1);return s.startsWith(` `)&&(s=s.slice(1)),o===`event`?n=s:o===`data`?r.push(s):o===`id`&&!s.includes(`\0`)&&(i=s),null};return{push:n=>{e+=n,t&&(t=!1,e.startsWith(`
|
|
4
|
+
`)&&(e=e.slice(1)));let r=[],i=e.search(mt);for(;i!==-1;){let n=e.slice(0,i);e[i]===`\r`&&i===e.length-1&&(t=!0);let a=e.startsWith(`\r
|
|
5
|
+
`,i)?2:1;e=e.slice(i+a);let s=o(n);s!=null&&r.push(s),i=e.search(mt)}return r},hasPendingIncomplete:()=>e!==``||r.length>0,flush:()=>(e=``,t=!1,n=``,r=[],[])}},gt=async(e,t)=>{if(t<=0)return`deadline`;let n=null,r=new Promise(e=>{n=setTimeout(()=>e(`deadline`),t)});try{return await Promise.race([e.read(),r])}finally{n!=null&&clearTimeout(n)}},_t=async(e,t)=>{let n=e.getReader(),r=new TextDecoder(`utf-8`),i=ht(),a=[],o=0,s=async e=>(await n.cancel().catch(z),{events:a,truncated:!0,reason:e,discardedIncomplete:!1});for(;;){let e=await gt(n,t.deadlineAt-t.now());if(e===`deadline`)return await s(`deadline`);if(e.done){a.push(...i.push(r.decode()));let e=i.hasPendingIncomplete();return i.flush(),{events:a,truncated:!1,reason:`end`,discardedIncomplete:e}}if(o+=e.value.byteLength,o>t.maxBytes)return await s(`max_bytes`);if(a.push(...i.push(r.decode(e.value,{stream:!0}))),a.length>t.maxEvents)return a.length=t.maxEvents,await s(`max_events`)}},H=`application/json`,vt=`text/event-stream`,yt=`x-request-id`,bt={headersTimeoutMs:6e4,maxJsonBytes:16777216,sseTotalMs:9e5,sseMaxEvents:1e4,sseMaxBytes:33554432,maxRetryAfterSeconds:30},xt=(e,t)=>{if(e.origin!==t.origin)throw new k(`network`,`refusing to send credentials outside the configured API origin`)},St=(e,t)=>{let n=Ge(e.pathname),r=new URL(`${n}${t.path}`,e);for(let[e,n]of t.query)r.searchParams.append(e,n);return xt(r,e),r},Ct=e=>{switch(e){case`json`:case`empty`:return H;case`sse`:return vt;case`binary`:return`*/*`;default:throw Error(`unknown response kind ${String(e)}`)}},wt=async(e,t)=>{let n=Number(e.headers.get(`content-length`));if(Number.isFinite(n)&&n>t)throw await e.body?.cancel().catch(z),new k(`response_too_large`,`response exceeds ${t} bytes`,e.status);if(e.body==null)return new Uint8Array;let r=e.body.getReader(),i=[],a=0;for(;;){let{done:n,value:o}=await r.read();if(n)break;if(a+=o.byteLength,a>t)throw await r.cancel().catch(z),new k(`response_too_large`,`response exceeds ${t} bytes`,e.status);i.push(o)}let o=new Uint8Array(a),s=0;for(let e of i)o.set(e,s),s+=e.byteLength;return o},Tt=e=>new TextDecoder(`utf-8`).decode(e),Et=(e,t)=>(e.headers.get(`content-type`)??``).toLowerCase().startsWith(t),Dt=e=>{if(e==null)return null;let t=Number(e);return Number.isInteger(t)&&t>=0?t:null},Ot=(e,t)=>{let n=e[t];return typeof n==`string`?n:null},kt=e=>typeof e==`object`&&!!e&&!Array.isArray(e),At=async(e,t)=>{let n=e.headers.get(yt),r=Dt(e.headers.get(`retry-after`)),i;try{i=Tt(await wt(e,t))}catch{i=``}if(Et(e,H))try{let t=JSON.parse(i),a=kt(t)&&kt(t.error)?t.error:null;if(a!=null)return new O({status:e.status,code:Ot(a,`code`),message:Ot(a,`message`)??e.statusText,detail:Ot(a,`detail`),requestId:Ot(a,`requestId`)??n,retryAfterSeconds:r})}catch{}return new O({status:e.status,code:null,message:i.slice(0,500)||e.statusText||`HTTP error`,detail:null,requestId:n,retryAfterSeconds:r})},jt=e=>{if(e==null)return null;let t=/filename\*=UTF-8''([^;]+)/i.exec(e);if(t?.[1]!=null)try{return decodeURIComponent(t[1].trim())}catch{return null}return/filename="?([^";]+)"?/i.exec(e)?.[1]?.trim()??null},Mt=e=>e instanceof k?e:e instanceof Error&&e.name===`AbortError`?new k(`timeout`,`the API did not respond in time`):new k(`network`,e instanceof Error?e.message:`network failure`),U=(e,t=bt)=>{let{config:n,auth:r,workspaceId:i,fetch:a,now:o,sleep:s,logger:c}=e,l=async(e,r)=>{let s=St(n.baseUrl,e),c=new Headers({accept:Ct(e.responseKind),"user-agent":`flyle-ai-contact-center-mcp/${ke}`,"x-flyle-client-workspace":i});r!=null&&c.set(`authorization`,`Bearer ${r}`);let l;e.hasBody&&(l=JSON.stringify(e.body??{}),c.set(`content-type`,H));let u=new AbortController,d=setTimeout(()=>u.abort(),t.headersTimeoutMs),f;try{f=await a(s,{method:e.method,headers:c,...l==null?{}:{body:l},redirect:`manual`,signal:u.signal})}catch(e){throw clearTimeout(d),Mt(e)}if(f.status>=300&&f.status<400)throw clearTimeout(d),await f.body?.cancel().catch(z),new k(`redirect_not_followed`,`redirect responses are not followed`,f.status);if(!f.ok)try{throw await At(f,t.maxJsonBytes)}finally{clearTimeout(d)}let p=f.headers.get(yt);switch(e.responseKind){case`json`:try{if(!Et(f,H))throw await f.body?.cancel().catch(z),new k(`unexpected_content_type`,`expected an application/json response`,f.status);let e=Tt(await wt(f,t.maxJsonBytes)),n;try{n=JSON.parse(e)}catch{throw new k(`invalid_json`,`the response body is not valid JSON`,f.status)}return{kind:`json`,status:f.status,requestId:p,body:n}}catch(e){throw Mt(e)}finally{clearTimeout(d)}case`empty`:return clearTimeout(d),await f.body?.cancel().catch(z),{kind:`empty`,status:f.status,requestId:p};case`sse`:{if(clearTimeout(d),!Et(f,vt))throw await f.body?.cancel().catch(z),new k(`unexpected_content_type`,`expected a text/event-stream response`,f.status);if(f.body==null)throw new k(`empty_body`,`the stream has no body`,f.status);let e=await _t(f.body,{deadlineAt:o()+t.sseTotalMs,maxEvents:t.sseMaxEvents,maxBytes:t.sseMaxBytes,now:o});return{kind:`sse`,status:f.status,requestId:p,...e}}case`binary`:if(clearTimeout(d),f.body==null)throw new k(`empty_body`,`the download has no body`,f.status);return{kind:`binary`,status:f.status,requestId:p,contentType:f.headers.get(`content-type`),fileName:jt(f.headers.get(`content-disposition`)),body:f.body};default:throw e.responseKind,Error(`unknown response kind ${String(e.responseKind)}`)}},u=async(e,n)=>{let r=e.method===`GET`&&(e.responseKind===`json`||e.responseKind===`empty`);try{return await l(e,n)}catch(i){if(!r)throw i;if(i instanceof O&&i.info.status===429&&i.info.retryAfterSeconds!=null&&i.info.retryAfterSeconds<=t.maxRetryAfterSeconds)return c.warn(`rate limited; retrying once`,{path:e.path,retryAfterSeconds:i.info.retryAfterSeconds}),await s(i.info.retryAfterSeconds*1e3),await l(e,n);if(i instanceof k&&i.kind===`network`)return c.warn(`network failure; retrying once`,{path:e.path}),await l(e,n);throw i}};return{request:async e=>{if(r==null)return u(e,null);let t=await r.getAccessToken();try{return await u(e,t)}catch(n){if(!(n instanceof O)||n.info.status!==401)throw n;let i=await r.refreshAfterRejection(t);if(i===t)throw n;return c.warn(`access token rejected; retrying once with a refreshed token`,{path:e.path}),await u(e,i)}}}},Nt=`{tenantName}`,Pt={...bt,headersTimeoutMs:2e4},Ft=C({authorizationUrlTemplate:T(w(),ve(Nt))}),It=C({accessToken:T(w(),S(je)),accessTokenExpiresAt:T(w(),x()),refreshToken:T(w(),S(Me)),refreshTokenExpiresAt:T(w(),x()),tenantName:T(w(),_e(Je)),loginConnectionId:T(w(),S(Ne))}),Lt=(e,t,n)=>{let r=E(e,t);if(!r.success)throw new k(`invalid_json`,`the login connection response does not match the contract`,n);return r.output},Rt=async e=>{let t=await e.request({method:`GET`,path:`/v0/login-connections/metadata`,query:[],hasBody:!1,body:null,responseKind:`json`});if(t.kind!==`json`)throw new k(`unexpected_content_type`,`not JSON`);return Lt(Ft,t.body,t.status).authorizationUrlTemplate},zt=async(e,t)=>{let n;try{n=await e.request({method:`POST`,path:`/v0/login-connections/token`,query:[],hasBody:!0,body:t,responseKind:`json`})}catch(e){throw e instanceof O&&e.info.code===`invalid_grant`?new Be(`the authorization code or refresh token is no longer valid`):e}if(n.kind!==`json`)throw new k(`unexpected_content_type`,`not JSON`);return Lt(It,n.body,n.status)},Bt=(e,t,n)=>{if(e.apiBaseUrl!==t.href||e.tenantName!==n)throw new F(`credentials_mismatch`,`保存されたログイン(環境 ${R(new URL(e.apiBaseUrl))} / テナント ${e.tenantName})が、この作業ディレクトリの接続先(環境 ${R(t)} / テナント ${n})と一致しません。この作業ディレクトリで \`npx @flyle/ai-contact-center-mcp login\` を実行し直してください`)},Vt=(e,t)=>({apiBaseUrl:t.href,tenantName:e.tenantName,loginConnectionId:e.loginConnectionId,accessToken:e.accessToken,accessTokenExpiresAt:e.accessTokenExpiresAt,refreshToken:e.refreshToken,refreshTokenExpiresAt:e.refreshTokenExpiresAt}),Ht=e=>{let{credentialsFile:t,baseUrl:n,tenantName:r,tokenClient:i,now:a}=e,o=null,s=null,c=[],l=(...e)=>{c.push(...e),c.splice(0,Math.max(0,c.length-8))},u=async()=>{let e=await it(t);if(e==null||Date.parse(e.refreshTokenExpiresAt)<=a())throw new F(`login_required`);return Bt(e,n,r),e},d=e=>e-a()>6e4,f=a=>pt(t,e.lock,async()=>{let e=await u();l(e.accessToken,e.refreshToken);let s=Date.parse(e.accessTokenExpiresAt);if(e.accessToken!==a&&d(s))return o={token:e.accessToken,expiresAt:s},e.accessToken;let c;try{c=await zt(i,{grant_type:`refresh_token`,refresh_token:e.refreshToken})}catch(e){throw e instanceof Be?(await st(t),new F(`login_required`)):e}if(l(c.accessToken,c.refreshToken),c.tenantName!==r)throw await st(t),new F(`login_required`,`ログインの更新で、設定と違うテナント(${c.tenantName})の応答を受け取ったため、保存したログイン情報を破棄しました。${ze}`);return await ot(t,Vt(c,n)),o={token:c.accessToken,expiresAt:Date.parse(c.accessTokenExpiresAt)},c.accessToken}),p=e=>(s??=f(e).finally(()=>{s=null}),s);return{getAccessToken:()=>o!=null&&d(o.expiresAt)?Promise.resolve(o.token):p(o?.token??null),refreshAfterRejection:e=>o!=null&&o.token!==e?Promise.resolve(o.token):(o=null,p(e)),assertLoggedIn:async()=>{o??await u()},secrets:()=>c,whenIdle:async()=>{await Promise.allSettled(s==null?[]:[s])}}},Ut=(e,t)=>e===`darwin`?[`open`,[t]]:e===`win32`?[`rundll32`,[`url.dll,FileProtocolHandler`,t]]:[`xdg-open`,[t]],Wt=(e,t=process.platform)=>{let[n,r]=Ut(t,e),i=te(n,r,{stdio:`ignore`,detached:!0,shell:!1});i.on(`error`,z),i.unref()},Gt=`.flyle-ai-contact-center-mcp`,Kt=C({tenantName:w(),apiBaseUrl:Te(we(w()),null)}),qt=e=>g.join(e,Gt,`workspace.json`),Jt=e=>e instanceof Error&&_(e,`code`)&&e.code===`ENOENT`,Yt=e=>e instanceof Error&&_(e,`code`)&&e.code===`EEXIST`,Xt=async e=>{let t;try{t=await d(qt(e),`utf8`)}catch(e){if(Jt(e))return null;throw e}let n;try{n=JSON.parse(t)}catch{n=null}let r=E(Kt,n);if(!r.success)throw new P(`corrupted`,`${qt(e)} is not a valid workspace binding. Inspect it manually; the MCP server never overwrites it.`);return r.output},Zt=async e=>(await Xt(e))?.tenantName??null,Qt=(e,t,n)=>new P(`tenant_mismatch`,`${e} is dedicated to tenant "${t}", not "${n}". Use a separate directory (and a separate Claude Code session) for each tenant.`),$t=(e,t,n)=>new P(`environment_mismatch`,`${e} is dedicated to the API ${new URL(t).host}, not ${new URL(n).host}. Use a separate directory for each environment.`),en=e=>{let t=[],n=g.dirname(e);for(;n!==g.dirname(n);)t.push(n),n=g.dirname(n);return t.push(n),t},tn=async(e,t)=>{let n=await Promise.all(en(e).map(async e=>({dir:e,tenant:await Zt(e)})));for(let{dir:e,tenant:r}of n)if(r!=null&&r!==t)throw Qt(e,r,t)},nn=(e,t)=>i(`sha256`).update(`${e.hostname}\0${e.username}\0${t}`).digest(`base64url`).slice(0,32),rn=(e,t)=>{let n={version:2,tenantName:e.tenantName,apiBaseUrl:e.apiBaseUrl,boundAt:t.toISOString()};return`${JSON.stringify(n,null,2)}\n`},an=async(e,t,n)=>{let r=qt(e),i=`${r}.${a(8).toString(`hex`)}.tmp`;try{await ee(i,rn(t,n),{flag:`wx`}),await p(i,r)}finally{await m(i,{force:!0})}},on=async(e,t,n,r)=>{await l(g.join(e,Gt),{recursive:!0});try{await ee(qt(e),rn(t,n),{flag:`wx`});return}catch(e){if(!Yt(e))throw e}let i=await Xt(e);if(i?.tenantName!==t.tenantName)throw Qt(e,i?.tenantName??`(unknown)`,t.tenantName);if(i.apiBaseUrl!==t.apiBaseUrl){if(i.apiBaseUrl==null&&r){await an(e,t,n);return}throw $t(e,i.apiBaseUrl??`(unknown)`,t.apiBaseUrl)}},sn=async e=>{let t=await f(e.cwd);if(t===await f(e.homeDir).catch(()=>e.homeDir)||t===g.parse(t).root)throw new P(`shared_directory`,`${t} is shared by everything you do and cannot be dedicated to one tenant. Create a directory for this tenant (e.g. ~/flyle-cs/<tenant>) and start the session there.`);return t},cn=async(e,t)=>{let n=await sn(e);return await tn(n,t.tenantName),await on(n,t,e.now(),!0),{...t,root:n,workspaceId:nn(e,n)}},ln=async e=>{let t=await sn(e),n=await Xt(t);return n?.apiBaseUrl==null?null:(await tn(t,n.tenantName),{tenantName:n.tenantName,apiBaseUrl:n.apiBaseUrl,root:t,workspaceId:nn(e,t)})},un=async(e,t)=>{await on(e.root,e,t,!1)},dn=(e,t,n)=>new P(`outside_workspace`,`${n} (${t}) must be inside the tenant workspace ${e}; a shared location could mix files between tenants.`),fn=async(e,t)=>{if(!t.startsWith(`${e.root}${g.sep}`))throw dn(e.root,t,`the file`);let n=[];for(let r=g.dirname(t);r!==e.root;r=g.dirname(r))n.push(r);let r=await Promise.all(n.map(async e=>({dir:e,tenant:await Zt(e)})));for(let{dir:t,tenant:n}of r)if(n!=null&&n!==e.tenantName)throw Qt(t,n,e.tenantName)},pn=(e,t,n)=>U({config:{baseUrl:t},auth:null,workspaceId:n,fetch:e.fetch,now:e.now,sleep:e.sleep,logger:e.logger},Pt),mn=async e=>{let t=await ln(e.workspaceEnv);if(t==null)return null;let n=rt(e.credentialsDir,t.workspaceId),r=await it(n);return r==null?null:{workspace:t,file:n,stored:r,baseUrl:L(r.apiBaseUrl,Ze(e.env),`${n} の apiBaseUrl`)}},hn=(e,t)=>{let n=Ht({credentialsFile:t.file,baseUrl:t.baseUrl,tenantName:t.stored.tenantName,tokenClient:pn(e,t.baseUrl,t.workspace.workspaceId),now:e.now,lock:e.lock});return{auth:n,client:U({config:{baseUrl:t.baseUrl},auth:n,workspaceId:t.workspace.workspaceId,fetch:e.fetch,now:e.now,sleep:e.sleep,logger:e.logger})}},gn=(e,t)=>`/v0/tenants/${encodeURIComponent(e)}${t}`,W=e=>e instanceof I||e instanceof F||e instanceof D||e instanceof P?e.message:e instanceof O?`公開 API がエラーを返しました(${String(e.info.status)} ${e.info.code??`http_error`}): ${e.info.message}`:e instanceof k?`公開 API と通信できませんでした(${e.kind}): ${e.message}`:e instanceof Error?e.message:String(e),G=(e,t)=>{let n=e;for(let e of t)e.length!==0&&(n=n.split(e).join(`[redacted]`));return n},_n=(e,t,n,r)=>{let i={level:e,message:t,...n,time:new Date().toISOString()};return G(JSON.stringify(i),r)},vn=(e,t=e=>console.error(e))=>({info:(n,r)=>t(_n(`info`,n,r,e())),warn:(n,r)=>t(_n(`warn`,n,r,e())),error:(n,r)=>t(_n(`error`,n,r,e()))}),yn=async(e,t)=>{let{client:n}=hn(e,t);try{await n.request({method:`DELETE`,path:gn(t.stored.tenantName,`/current-login-connection`),query:[],hasBody:!1,body:null,responseKind:`empty`})}catch(e){if(!(e instanceof F&&e.kind===`login_required`||e instanceof O&&e.info.status===401))throw e}},bn=async e=>{let t=await mn(e);if(t==null){e.out(`この作業ディレクトリにはログイン情報がありません。`);return}await yn(e,t),await pt(t.file,e.lock,()=>st(t.file)),e.out(`ログアウトしました(環境 ${R(t.baseUrl)} / テナント ${t.stored.tenantName})。`)},xn=`127.0.0.1`,Sn=`/callback`,Cn=e=>{try{let{values:t}=re({args:[...e],options:{tenant:{type:`string`},"api-base-url":{type:`string`}},strict:!0,allowPositionals:!1});return{tenant:t.tenant??null,apiBaseUrl:t[`api-base-url`]??null}}catch(e){throw new I(`${e instanceof Error?e.message:String(e)}\n使い方: login [--tenant <テナント名>] [--api-base-url <URL>]`)}},wn=(e,t,n)=>e==null?t?.apiBaseUrl==null?L(`https://api.flygate.flyle.io`,n,`既定の接続先`):L(t.apiBaseUrl,n,`作業ディレクトリの接続先`):L(e,n,`--api-base-url`),Tn=(e,t)=>{if(e!=null)return Ye(e,`--tenant`);if(t!=null)return t.tenantName;throw new I("テナントを決められません。`login --tenant <テナント名>` で指定してください(作業ディレクトリをそのテナント専用にします)。")},En=()=>a(32).toString(`base64url`),Dn=e=>i(`sha256`).update(e).digest(`base64url`),On=(e,t)=>{let n=Buffer.from(e),r=Buffer.from(t);return n.length===r.length&&o(n,r)},kn=(e,t,n)=>{let r;try{r=new URL(e.replaceAll(Nt,t))}catch{throw new I(`公開 API が返した同意画面の URL が不正です。`)}let i=r.protocol===`http:`&&n&&(Ke(r.hostname)||r.hostname.endsWith(`.localhost`));if(r.protocol!==`https:`&&!i)throw new I(`公開 API が返した同意画面の URL が https ではありません。`);return r},An=/[\p{Cc}\p{Cf}]/gu,jn=(e,t)=>{let n=``;for(let r of e){if(n.length+r.length>t)break;n+=r}return n},Mn=(e,t)=>{let n=e=>e.replaceAll(An,``);return jn(`${n(e)} / ${n(g.basename(t))}`,255)},Nn=Oe([C({error:T(w(),S(/^[a-z_]{1,64}$/)),state:w()}),C({code:T(w(),S(Ae)),state:w()})]),Pn={success:`ログインが完了しました。このタブは閉じてかまいません。`,denied:`ログインを中止しました。このタブは閉じてかまいません。`,failure:`ログインを完了できませんでした。このタブを閉じて、ターミナルの表示を確認してください。`,handled:`このログインは処理済みです。このタブは閉じてかまいません。`,unknown:`実行中のログインの応答として確認できませんでした。ログインを続ける場合は、ターミナルに表示された URL から同意画面を開き直してください。`,rejected:`この宛先への要求は受け付けていません。`},K=(e,t,n)=>{e.writeHead(t,{"content-type":`text/html; charset=utf-8`,"cache-control":`no-store`,"content-security-policy":`default-src 'none'`,"referrer-policy":`no-referrer`}),e.end(`<!doctype html><html lang="ja"><meta charset="utf-8"><title>Flyle AIコンタクトセンター</title><p>${Pn[n]}</p></html>`)},Fn=e=>new Promise((t,n)=>{e.once(`error`,n),e.listen(0,xn,()=>{let r=e.address();if(r==null||typeof r==`string`){n(new I(`ログイン用の待受ポートを開けませんでした。`));return}t(r.port)})}),In=async(e,t,n)=>{let r=!1,i=0,a=null,o=Promise.withResolvers(),s=e=>{r=!0,o.reject(new I(e))},c=(e,t,r)=>{i+=1,K(e,400,t),n(r)},l=ne((t,n)=>{if(a==null||t.headers.host!==a){c(n,`rejected`,`ログイン用の待受に、想定外の宛先(Host ヘッダ)の要求が届いたため拒否しました。ログインは待ち続けています。`);return}let i=new URL(t.url??`/`,`http://${a}`);if(t.method!==`GET`||i.pathname!==Sn){n.writeHead(404).end();return}if(r){K(n,410,`handled`);return}let l=i.searchParams.get(`state`);if(l==null||!On(l,e)){c(n,`unknown`,`このログインのものではない応答(state が一致しない、または無い)を受け取ったため無視しました。ブラウザで同意を続けてください。`);return}let u=E(Nn,fe(i.searchParams));if(!u.success){K(n,400,`failure`),s(`同意画面からの応答の形式が正しくありません(認可コードがない、または形式が違います)。もう一度 login を実行してください。`);return}let d=u.output;if(_(d,`error`)){let e=d.error===`access_denied`;K(n,200,e?`denied`:`failure`),s(e?`ブラウザでログインが拒否されました。`:`同意画面がエラーを返しました(${d.error})。`);return}r=!0;let f=!1;o.resolve({code:d.code,finish:e=>{f||(f=!0,K(n,e===`success`?200:400,e))}})}),u=await Fn(l);a=`${xn}:${String(u)}`;let d=setTimeout(()=>{if(r)return;let e=i===0?``:`(このログインのものではない要求を ${String(i)} 件受け取り、無視しました)`;s(`${String(Math.round(t/1e3/60))} 分以内にブラウザでの同意が完了しませんでした${e}。もう一度 login を実行してください。`)},t);return{port:u,received:o.promise,close:()=>new Promise(e=>{clearTimeout(d),l.closeAllConnections(),l.close(()=>e())})}},Ln=`その接続は最長 30 日間有効なまま残る可能性があります。管理画面の「設定 → 外部ツール接続」から切断してください。`,Rn=async(e,t)=>{if(t!=null)try{await yn(e,t)}catch(n){e.err(`以前のログイン(接続 ID ${t.stored.loginConnectionId})をサーバーで切断できませんでした(${W(n)})。${Ln}`)}},zn=async e=>{try{return await mn(e)}catch(t){if(!(t instanceof F&&t.kind===`login_required`)&&!(t instanceof D))throw t;return e.err(`以前のログイン情報を読めなかったため、新しいログインで上書きします(${W(t)})。以前の接続はサーバーで切断できていません。${Ln}`),null}},Bn=async(e,t,n,r)=>{let i=rt(e.credentialsDir,t.workspaceId);await pt(i,e.lock,()=>ot(i,Vt(r,n)))},Vn=e=>({getAccessToken:()=>Promise.resolve(e),refreshAfterRejection:()=>Promise.resolve(e),assertLoggedIn:()=>Promise.resolve(),secrets:()=>[e]}),Hn=async(e,t,n,r)=>{let i=U({config:{baseUrl:t},auth:Vn(r.accessToken),workspaceId:n.workspaceId,fetch:e.fetch,now:e.now,sleep:e.sleep,logger:e.logger});try{return await i.request({method:`DELETE`,path:gn(r.tenantName,`/current-login-connection`),query:[],hasBody:!1,body:null,responseKind:`empty`}),!0}catch{return!1}},Un=async e=>{let t=Cn(e.argv),n=Ze(e.env),r=await Xt(e.workspaceEnv.cwd),i=wn(t.apiBaseUrl,r,n),a=Tn(t.tenant,r),o=await cn(e.workspaceEnv,{tenantName:a,apiBaseUrl:i.href}),s=await zn(e),c=pn(e,i,o.workspaceId),l=kn(await Rt(c),a,n),u=En(),d=En(),f=[u,d],p=await In(d,e.callbackTimeoutMs,e.err),m=null;try{let t=`http://${xn}:${String(p.port)}${Sn}`;l.searchParams.set(`tenant_name`,a),l.searchParams.set(`code_challenge`,Dn(u)),l.searchParams.set(`code_challenge_method`,`S256`),l.searchParams.set(`redirect_uri`,t),l.searchParams.set(`state`,d),l.searchParams.set(`connection_name`,Mn(e.workspaceEnv.hostname,o.root)),l.searchParams.set(`api_origin`,i.origin),e.err(`環境 ${R(i)} のテナント「${a}」にログインします。ブラウザで同意画面を開きます。\n開かない場合は、次の URL をブラウザで開いてください:\n${l.href}`),e.openBrowser(l.href),m=await p.received,f.push(m.code);let n;try{n=await zt(c,{grant_type:`authorization_code`,code:m.code,code_verifier:u,redirect_uri:t})}catch(e){throw e instanceof Be?new I(`認可コードを交換できませんでした。もう一度 login を実行してください。`):e}if(f.push(n.accessToken,n.refreshToken),n.tenantName!==a){let t=await Hn(e,i,o,n);throw new I(`ブラウザで同意したテナント(${n.tenantName})が、ログインしようとしたテナント(${a})と違います。ログイン情報は保存していません。`+(t?`そのテナントに作られた接続は切断しました。`:`テナント ${n.tenantName} の管理画面の「設定 → 外部ツール接続」から、作られた接続を切断してください。`))}await un(o,new Date(e.now())),await Rn(e,s),await Bn(e,o,i,n),m.finish(`success`),e.out(`ログインしました(環境 ${R(i)} / テナント ${a} / 作業ディレクトリ ${o.root})。`)}catch(e){throw m?.finish(`failure`),new I(G(W(e),f))}finally{await p.close()}},Wn=C({currentUser:C({name:we(w()),email:we(w()),roles:Se(C({roleName:w()})),currentLoginConnection:C({name:w(),expiresAt:T(w(),x())})})}),Gn="ログインしていません。作業ディレクトリで `npx @flyle/ai-contact-center-mcp login` を実行してください",Kn=async e=>{let t=await mn(e);if(t==null)throw new I(Gn);e.out(`環境: ${R(t.baseUrl)}`),e.out(`テナント: ${t.stored.tenantName}`);let{client:n}=hn(e,t),r;try{r=await n.request({method:`GET`,path:gn(t.stored.tenantName,`/current-user`),query:[],hasBody:!1,body:null,responseKind:`json`})}catch(e){throw e instanceof F&&e.kind===`login_required`?new I(`ログインの有効期限が切れています。${Gn}`):e}let i=E(Wn,r.kind===`json`?r.body:null);if(!i.success)throw new k(`invalid_json`,`the current user response does not match the contract`);let a=i.output.currentUser,o=a.email==null?``:` <${a.email}>`;e.out(`ユーザー: ${a.name??`(名前未設定)`}${o}`),e.out(`ロール: ${a.roles.map(e=>e.roleName).join(`, `)||`(なし)`}`),e.out(`接続名: ${a.currentLoginConnection.name}`),e.out(`ログインの有効期限: ${a.currentLoginConnection.expiresAt}(使うたびに延長。ログインから最長 90 日)`)},qn=async e=>{let t=await u(e,ie.O_RDONLY|ie.O_NONBLOCK|ie.O_NOFOLLOW);try{let e=await t.stat();if(!e.isFile())throw new j(`not_a_file`,`only regular files can be read`);return{handle:t,size:e.size}}catch(e){throw await t.close(),e}},Jn=async(e,t)=>{let{handle:n,size:r}=await qn(e);try{if(r>t)throw new j(`too_large`,`the file exceeds ${String(t)} bytes`);let e=[],i=0;for(;;){let r=Buffer.allocUnsafe(Math.min(1048576,t-i+1)),{bytesRead:a}=await n.read(r,0,r.length,null);if(a===0)break;if(i+=a,i>t)throw new j(`too_large`,`the file exceeds ${String(t)} bytes`);e.push(r.subarray(0,a))}return Buffer.concat(e,i)}finally{await n.close()}},Yn=(e,t)=>e===t||e.startsWith(`${t}${g.sep}`),Xn=async(e,t,n,r)=>{let i=g.resolve(n,e),a;try{a=await f(i)}catch{throw new j(`not_found`,`file not found: ${e}`)}if(!(await Promise.all(t.map(e=>f(e).catch(()=>e)))).some(e=>Yn(a,e)))throw new j(`outside_roots`,`the path is outside the configured file roots`);return await fn(r,a),a},Zn=new Map([[`.md`,`text/markdown`],[`.markdown`,`text/markdown`],[`.txt`,`text/plain`],[`.csv`,`text/csv`],[`.json`,`application/json`],[`.html`,`text/html`],[`.htm`,`text/html`],[`.pdf`,`application/pdf`],[`.docx`,`application/vnd.openxmlformats-officedocument.wordprocessingml.document`],[`.xlsx`,`application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`],[`.pptx`,`application/vnd.openxmlformats-officedocument.presentationml.presentation`],[`.png`,`image/png`],[`.jpg`,`image/jpeg`],[`.jpeg`,`image/jpeg`],[`.zip`,`application/zip`]]),Qn=e=>Zn.get(g.extname(e).toLowerCase())??`application/octet-stream`,$n=e=>new Promise((t,n)=>{let r=i(`sha256`);e.on(`data`,e=>r.update(e)).on(`error`,n).on(`end`,()=>t(r.digest()))}),er=async(e,t,n,r)=>{let i=await Xn(e,t,n,r),{handle:a,size:o}=await qn(i),s;try{s=await $n(a.createReadStream())}finally{await a.close()}let c=g.basename(i);return{path:i,fileName:c,sizeBytes:o,sha256Hex:s.toString(`hex`),sha256Base64:s.toString(`base64`),mimeType:Qn(c)}},tr=(e,t=9e5,n=1e3)=>{let r=new Map,i=()=>{let t=e();for(let[e,n]of r)n.expiresAt<=t&&r.delete(e)};return{get size(){return r.size},register:(a,o,s)=>{for(i();r.size>=n;){let e=r.keys().next();if(e.done)break;r.delete(e.value)}r.delete(a),r.set(a,{kind:o,headers:s,expiresAt:e()+t})},take:(t,n)=>{let i=r.get(t);if(i?.kind!==n)throw new A(`unknown_url`,`the URL was not returned by a recent API call for this kind of transfer`);if(r.delete(t),i.expiresAt<=e())throw new A(`expired_url`,`the signed URL has expired; call the API again to get a new one`);return i}}},nr=(e,t)=>{let n;try{n=new URL(e)}catch{throw new A(`not_allowed_host`,`the transfer URL is not a valid URL`)}let r=t.allowInsecureHttp&&Ke(n.hostname);if(n.protocol!==`https:`&&!(n.protocol===`http:`&&r))throw new A(`insecure_url`,`transfer URLs must use https`);if(n.username!==``||n.password!==``)throw new A(`not_allowed_host`,`transfer URLs must not contain credentials`);let i=n.hostname.toLowerCase();if(!(r||t.storageHostSuffixes.some(e=>e.startsWith(`.`)?i.endsWith(e):i===e)))throw new A(`not_allowed_host`,`the host ${i} is not an allowed storage host`);return n},rr=e=>e.replaceAll(`~1`,`/`).replaceAll(`~0`,`~`),ir=e=>Array.isArray(e),q=(e,t)=>{if(t===``)return[e];let n=t.split(`/`).slice(1).map(e=>rr(e)),r=[e];for(let e of n){let t=[];for(let n of r)if(e===`*`)ir(n)&&t.push(...n);else if(ir(n)){let r=Number(e);Number.isInteger(r)&&r>=0&&r<n.length&&t.push(n[r])}else v(n)&&_(n,e)&&t.push(n[e]);r=t}return r},ar=e=>{if(!v(e))return{};let t={};for(let[n,r]of de(e))typeof r==`string`&&(t[n]=r);return t},or=(e,t)=>{if(t==null)return[];let n=q(e,t.urlPointer).filter(e=>typeof e==`string`),r=t.headersPointer==null?[]:q(e,t.headersPointer).map(e=>ar(e));return n.map((e,n)=>({url:e,kind:t.kind,headers:r.length===1?r[0]??{}:r[n]??{}}))},sr=4096,cr=async e=>{if(e.body==null)return``;let t=e.body.getReader(),n=[],r=0;try{for(;r<sr;){let{done:e,value:i}=await t.read();if(e)break;n.push(i),r+=i.byteLength}}catch{}finally{await t.cancel().catch(z)}return new TextDecoder(`utf-8`).decode(Buffer.concat(n)).slice(0,sr)},lr=e=>e instanceof A?e:e instanceof Error&&(e.name===`AbortError`||e.name===`TimeoutError`)?new A(`timeout`,`the storage did not respond in time`):new A(`network`,e instanceof Error?e.message:`network failure`),ur=async e=>{if(ue(e.headers).some(e=>e.toLowerCase()===`authorization`))throw new A(`invalid_headers`,`transfer headers must not include authorization`);let t;try{t=await Jn(e.filePath,e.maxBytes)}catch(e){throw e instanceof j&&(e.kind===`not_a_file`||e.kind===`too_large`)?new A(e.kind,e.kind===`not_a_file`?`only regular files can be uploaded`:e.message):e}let n;try{n=await e.fetch(e.url,{method:`PUT`,headers:e.headers,body:t,redirect:`manual`,signal:AbortSignal.timeout(e.timeoutMs)})}catch(e){throw lr(e)}if(n.status>=300&&n.status<400)throw await n.body?.cancel().catch(z),new A(`redirect_not_followed`,`redirect responses are not followed`,n.status);if(!n.ok)throw new A(`http_error`,`upload failed: ${(await cr(n)).slice(0,300)}`,n.status);return await n.body?.cancel().catch(z),{status:n.status,etag:n.headers.get(`etag`),bytes:t.byteLength}},dr=/[^A-Za-z0-9._-]/g,fr=(e,t)=>{let n=g.basename(e??``).replace(dr,`_`).replace(/^_+/,``).slice(0,120);return n===``||/^\.+$/.test(n)?t:n},pr=e=>`${new Date().toISOString().replaceAll(/[:.]/g,`-`)}-${a(3).toString(`hex`)}-${e}`,mr=async(e,t)=>{if(t<=0)return`timeout`;let n=null,r=new Promise(e=>{n=setTimeout(()=>e(`timeout`),t)});try{return await Promise.race([e.read(),r])}finally{n!=null&&clearTimeout(n)}},hr=async(e,t)=>{await l(t.outputDir,{recursive:!0});let n=g.join(t.outputDir,pr(t.fileName)),r=await u(n,`wx`),a=i(`sha256`),o=e.getReader(),s=Date.now()+t.timeoutMs,c=0;try{for(;;){let e=await mr(o,s-Date.now());if(e===`timeout`)throw await o.cancel().catch(z),new A(`timeout`,`the download did not finish within ${t.timeoutMs} ms`);let{done:n,value:i}=e;if(n)break;if(c+=i.byteLength,c>t.maxBytes)throw await o.cancel().catch(z),new A(`too_large`,`the download exceeds ${t.maxBytes} bytes`);a.update(i),await r.write(i)}}catch(e){throw await r.close(),await h(n).catch(z),lr(e)}return await r.close(),{path:n,bytes:c,sha256Hex:a.digest(`hex`)}},gr=async e=>{let t;try{t=await e.fetch(e.url,{method:`GET`,redirect:`manual`,signal:AbortSignal.timeout(e.timeoutMs)})}catch(e){throw lr(e)}if(t.status>=300&&t.status<400)throw await t.body?.cancel().catch(z),new A(`redirect_not_followed`,`redirect responses are not followed`,t.status);if(!t.ok)throw new A(`http_error`,`download failed: ${(await cr(t)).slice(0,300)}`,t.status);if(t.body==null)throw new A(`network`,`the download has no body`,t.status);return{...await hr(t.body,{outputDir:e.outputDir,fileName:e.fileName,maxBytes:e.maxBytes,timeoutMs:e.timeoutMs}),status:t.status,contentType:t.headers.get(`content-type`)}},_r=new URL(`./manifest.json.br`,import.meta.url),vr=[`GET`,`POST`,`PUT`,`PATCH`,`DELETE`],yr=[`json`,`empty`,`sse`,`binary`],br=[`upload`,`download`],xr=[`read`,`draft`],Sr=[`wav-pcm16`,`base64`],Cr=[`pcm16le`,`base64`],J=e=>{throw new Le(e)},Y=e=>e===null,X=e=>Array.isArray(e)&&e.every(e=>typeof e==`string`),wr=e=>{if(!Array.isArray(e)||e.length===0)return!1;let t=0;for(let n of e){if(typeof n!=`number`||!Number.isInteger(n)||n<200||n>=300||n<=t)return!1;t=n}return!0},Tr=e=>typeof e==`string`&&vr.some(t=>t===e),Er=e=>typeof e==`string`&&yr.some(t=>t===e),Dr=e=>typeof e==`string`&&br.some(t=>t===e),Or=e=>typeof e==`string`&&xr.some(t=>t===e),kr=(e,t)=>{if(Y(e))return null;if(!v(e))return J(`${t}.transfer must be an object or null`);let{kind:n,urlPointer:r,headersPointer:i}=e;return Dr(n)?typeof r==`string`?!Y(i)&&typeof i!=`string`?J(`${t}.transfer.headersPointer is invalid`):{kind:n,urlPointer:r,headersPointer:i}:J(`${t}.transfer.urlPointer is invalid`):J(`${t}.transfer.kind is invalid`)},Ar=e=>typeof e==`string`&&Sr.some(t=>t===e),jr=e=>typeof e==`string`&&Cr.some(t=>t===e),Mr=e=>typeof e==`number`&&Number.isInteger(e)&&e>0,Nr=(e,t)=>{if(Y(e))return null;if(!v(e))return J(`${t} must be an object or null`);let{sampleRateHz:n,channels:r}=e;return Mr(n)?Mr(r)?{sampleRateHz:n,channels:r}:J(`${t}.channels is invalid`):J(`${t}.sampleRateHz is invalid`)},Pr=(e,t)=>{if(!v(e))return J(`${t} must be an object`);let{pointer:n,format:r,maxBytes:i,pcm:a}=e;if(typeof n!=`string`||!n.startsWith(`/`))return J(`${t}.pointer is invalid`);if(!Ar(r))return J(`${t}.format is invalid`);if(!Mr(i))return J(`${t}.maxBytes is invalid`);let o=Nr(a,`${t}.pcm`);return r===`wav-pcm16`==(o!=null)?{pointer:n,format:r,maxBytes:i,pcm:o}:J(`${t}.pcm does not match the format`)},Fr=(e,t)=>{if(!v(e))return J(`${t} must be an object`);let{event:n,pointer:r,format:i,pcm:a,mediaType:o}=e;if(!Y(n)&&typeof n!=`string`)return J(`${t}.event is invalid`);if(typeof r!=`string`||!r.startsWith(`/`))return J(`${t}.pointer is invalid`);if(!jr(i))return J(`${t}.format is invalid`);if(!Y(o)&&typeof o!=`string`)return J(`${t}.mediaType is invalid`);let s=Nr(a,`${t}.pcm`);return i===`pcm16le`==(s!=null)?i===`base64`==(o!=null)?{event:n,pointer:r,format:i,pcm:s,mediaType:o}:J(`${t}.mediaType does not match the format`):J(`${t}.pcm does not match the format`)},Ir=(e,t)=>{if(Y(e))return null;if(!v(e))return J(`${t}.inlineFiles must be an object or null`);let{input:n,output:r}=e;return!Array.isArray(n)||!Array.isArray(r)?J(`${t}.inlineFiles is invalid`):n.length===0&&r.length===0?J(`${t}.inlineFiles must declare input or output`):{input:n.map((e,n)=>Pr(e,`${t}.inlineFiles.input[${String(n)}]`)),output:r.map((e,n)=>Fr(e,`${t}.inlineFiles.output[${String(n)}]`))}},Lr=(e,t)=>{if(Y(e))return null;if(!v(e))return J(`${t}.sseOutcome must be an object or null`);let{requiredEvents:n,terminalEvent:r,successPointer:i,successValue:a,failureEvents:o}=e;return X(n)?typeof r==`string`?Y(i)&&Y(a)?X(o)?{requiredEvents:n,terminalEvent:r,successPointer:i,successValue:a,failureEvents:o}:J(`${t}.sseOutcome.failureEvents is invalid`):typeof i!=`string`||!i.startsWith(`/`)?J(`${t}.sseOutcome.successPointer is invalid`):typeof a!=`string`&&typeof a!=`number`&&typeof a!=`boolean`?J(`${t}.sseOutcome.successValue is invalid`):X(o)?{requiredEvents:n,terminalEvent:r,successPointer:i,successValue:a,failureEvents:o}:J(`${t}.sseOutcome.failureEvents is invalid`):J(`${t}.sseOutcome.terminalEvent is invalid`):J(`${t}.sseOutcome.requiredEvents is invalid`)},Rr=(e,t)=>{let n=`operations[${t}]`;if(!v(e))return J(`${n} must be an object`);let{operationId:r,method:i,pathTemplate:a,summary:o,description:s,permission:c,effect:l,responseKind:u,successStatuses:d,pathParams:f,queryParams:p,bodyFields:m,wholeBodyField:h,inputSchema:ee,transfer:g,inlineFiles:te,sseOutcome:ne}=e;return typeof r!=`string`||r===``?J(`${n}.operationId is invalid`):Tr(i)?typeof a!=`string`||!a.startsWith(`/`)?J(`${n}.pathTemplate is invalid`):typeof o==`string`?!Y(s)&&typeof s!=`string`?J(`${n}.description is invalid`):!Y(l)&&!Or(l)?J(`${n}.effect is invalid`):Er(u)?wr(d)?X(f)?X(p)?!Y(m)&&!X(m)?J(`${n}.bodyFields is invalid`):!Y(h)&&typeof h!=`string`?J(`${n}.wholeBodyField is invalid`):m!=null&&h!=null?J(`${n} declares both bodyFields and wholeBodyField`):v(ee)?{operationId:r,method:i,pathTemplate:a,summary:o,description:s,permission:c??null,effect:l,responseKind:u,successStatuses:d,pathParams:f,queryParams:p,bodyFields:m,wholeBodyField:h,inputSchema:ee,transfer:kr(g,n),inlineFiles:Ir(te,n),sseOutcome:Lr(ne,n)}:J(`${n}.inputSchema is invalid`):J(`${n}.queryParams is invalid`):J(`${n}.pathParams is invalid`):J(`${n}.successStatuses is invalid`):J(`${n}.responseKind is invalid`):J(`${n}.summary is invalid`):J(`${n}.method is invalid`)},zr=e=>{if(!v(e))return J(`manifest must be an object`);let t=e.source;if(!v(t)||typeof t.title!=`string`||typeof t.version!=`string`)return J(`manifest.source is invalid`);let n=e.operations;if(!Array.isArray(n))return J(`manifest.operations must be an array`);let r=n.map((e,t)=>Rr(e,t));return new Set(r.map(e=>e.operationId)).size===r.length?{source:{title:t.title,version:t.version},operations:r}:J(`manifest.operations has duplicate operationId`)},Br=(e=_r)=>{let t=ae(e),n;try{n=JSON.parse((e.pathname.endsWith(`.br`)?oe(t):t).toString(`utf8`))}catch{return J(`manifest at ${e.pathname} is not valid JSON or brotli`)}return zr(n)},Vr=/^[A-Za-z0-9+/]*={0,2}$/,Hr=(e,t)=>t+8>e.length?null:{id:e.toString(`latin1`,t,t+4),size:e.readUInt32LE(t+4)},Ur=e=>{if(e.length<12||e.toString(`latin1`,0,4)!==`RIFF`||e.toString(`latin1`,8,12)!==`WAVE`)throw new M(`not_wav`,`the file is not a RIFF/WAVE file`);let t=null,n=null,r=12;for(;;){let i=Hr(e,r);if(i==null)break;let a=r+8,o=a+i.size;if(o>e.length)throw new M(`not_wav`,`the "${i.id}" chunk claims more bytes than the file holds`);if(i.id===`fmt `){if(o-a<16)throw new M(`not_wav`,`the fmt chunk is truncated`);let n=e.readUInt16LE(a);if((n===65534&&o-a>=26?e.readUInt16LE(a+24):n)!==1)throw new M(`unsupported_format`,`unsupported WAV format code ${String(n)} (only PCM is accepted)`);t={channels:e.readUInt16LE(a+2),sampleRateHz:e.readUInt32LE(a+4),bitsPerSample:e.readUInt16LE(a+14)}}else i.id===`data`&&(n=e.subarray(a,o));r=a+i.size+i.size%2}if(t==null||n==null)throw new M(`not_wav`,`the WAV file lacks a fmt or data chunk`);if(t.bitsPerSample!==16)throw new M(`unsupported_format`,`unsupported bit depth ${String(t.bitsPerSample)} (only 16-bit PCM is accepted)`);if(n.length===0)throw new M(`empty`,`the WAV file has no audio samples`);if(n.length%(2*t.channels)!=0)throw new M(`not_wav`,`the data chunk is not aligned to whole samples`);return{sampleRateHz:t.sampleRateHz,channels:t.channels,pcm:n}},Wr=(e,t)=>{let n=Buffer.alloc(44),r=2*t.channels;return n.write(`RIFF`,0,`latin1`),n.writeUInt32LE(36+e.length,4),n.write(`WAVE`,8,`latin1`),n.write(`fmt `,12,`latin1`),n.writeUInt32LE(16,16),n.writeUInt16LE(1,20),n.writeUInt16LE(t.channels,22),n.writeUInt32LE(t.sampleRateHz,24),n.writeUInt32LE(t.sampleRateHz*r,28),n.writeUInt16LE(r,32),n.writeUInt16LE(16,34),n.write(`data`,36,`latin1`),n.writeUInt32LE(e.length,40),Buffer.concat([n,e])},Gr=(e,t)=>Math.round(e/(2*t.channels*t.sampleRateHz)*1e3),Kr=async(e,t,n,r)=>{let i=await Xn(e,r.fileRoots,r.cwd,r.workspace);try{return await Jn(i,t)}catch(e){throw e instanceof j&&e.kind===`too_large`?new M(`too_large`,`"${n}" exceeds ${String(t)} bytes`):e}},qr=async(e,t,n,r)=>{if(typeof t!=`string`||t===``)throw new M(`not_a_path`,`"${n}" must be a local file path`);let i=await Kr(t,e.format===`wav-pcm16`?e.maxBytes+44:e.maxBytes,n,r);if(e.format===`base64`){if(i.length===0)throw new M(`empty`,`"${n}" points at an empty file`);return i.toString(`base64`)}let a=Ur(i),o=e.pcm;if(o!=null&&(a.sampleRateHz!==o.sampleRateHz||a.channels!==o.channels))throw new M(`unsupported_format`,`"${n}" must be ${String(o.sampleRateHz)} Hz / ${String(o.channels)} channel PCM 16-bit WAV (got ${String(a.sampleRateHz)} Hz / ${String(a.channels)} channel)`);if(a.pcm.length>e.maxBytes)throw new M(`too_large`,`"${n}" holds ${String(a.pcm.length)} bytes of audio; at most ${String(e.maxBytes)} are accepted`);return{encoding:`pcm16le`,sampleRateHz:a.sampleRateHz,channels:a.channels,data:a.pcm.toString(`base64`)}},Jr=e=>e.replaceAll(`~1`,`/`).replaceAll(`~0`,`~`),Yr=async(e,t,n)=>{let r=async(e,t,i)=>{let[a,...o]=t;if(a==null)return n(e,i);if(a===`*`){if(!Array.isArray(e))return e;let t=[];for(let[n,a]of e.entries())t.push(await r(a,o,`${i}/${String(n)}`));return t}if(Array.isArray(e)){let t=Number(a);if(!Number.isInteger(t)||t<0||t>=e.length)return e;let n=[...e];return n[t]=await r(e[t],o,`${i}/${a}`),n}return v(e)&&_(e,a)?{...e,[a]:await r(e[a],o,`${i}/${a}`)}:e};return r(e,t.split(`/`).slice(1).map(e=>Jr(e)),``)},Xr=async(e,t,n)=>{let r=t;for(let t of e.input)r=await Yr(r,t.pointer,(e,r)=>qr(t,e,r,n));return v(r)?r:t},Zr=(e,t)=>{if(typeof e!=`string`||e.length%4!=0||!Vr.test(e))throw new M(`invalid_base64`,`"${t}" is not valid base64`);return Buffer.from(e,`base64`)},Qr=new Map([[`audio/mpeg`,`.mp3`],[`audio/mp4`,`.m4a`],[`audio/ogg`,`.ogg`],[`audio/wav`,`.wav`],[`audio/webm`,`.webm`],[`image/png`,`.png`],[`image/jpeg`,`.jpg`],[`image/webp`,`.webp`],[`application/pdf`,`.pdf`]]),$r=async(e,t,n)=>{let r=[],i=0;for(let[a,o]of t.entries()){let t=Zr(o,`${e.event??`body`}${e.pointer}[${String(a)}]`);if(e.format===`pcm16le`&&t.length%2!=0)throw new M(`unsupported_format`,`${e.event??`body`}${e.pointer} chunk ${String(a)} is not whole PCM 16-bit samples`);if(i+=t.length,i>n.maxBytes)throw new M(`too_large`,`inline output exceeds ${String(n.maxBytes)} bytes`);r.push(t)}let a=Buffer.concat(r),o=e.pcm,s=e.format===`pcm16le`&&o!=null,c=s?Wr(a,o):a,l=s?`audio/wav`:e.mediaType??`application/octet-stream`,u=s?`.wav`:Qr.get(l)??`.bin`;return{...await hr(new Blob([new Uint8Array(c)]).stream(),{outputDir:n.outputDir,fileName:fr(`${n.fileName}${u}`,`inline${u}`),maxBytes:n.maxBytes+44,timeoutMs:n.timeoutMs}),event:e.event,pointer:e.pointer,mediaType:l,chunks:t.length,durationMs:s?Gr(a.length,o):null}},ei=e=>{try{return JSON.parse(e)}catch{return e}},ti=async(e,t,n)=>{let r=new Set,i=[];for(let a of e.output){if(a.event==null)continue;r.add(a.event);let e=t.filter(e=>e.event===a.event).flatMap(e=>q(ei(e.data),a.pointer));e.length!==0&&i.push(await $r(a,e,n))}return{events:t.filter(e=>e.event==null||!r.has(e.event)),files:i}},ni=async(e,t,n)=>{let r=t,i=[];for(let t of e.output){if(t.event!=null)continue;let e=q(r,t.pointer);if(e.length===0)continue;let a=await $r(t,e,n);i.push(a),r=await Yr(r,t.pointer,()=>Promise.resolve(`[saved to ${a.path}]`))}return{body:r,files:i}},ri=(e,t,n)=>{let r=t.findIndex(t=>t.event===e.terminalEvent),i=r===-1?null:t[r],a=r===-1?t:t.slice(0,r),o=i==null?null:ei(i.data),s=new Set(a.map(e=>e.event)),c=e.failureEvents.find(e=>s.has(e));if(c!=null)return{outcome:`failed`,reason:`received failure event "${c}"`,terminal:o};if(i==null)return n.truncated?{outcome:`unknown`,reason:`the stream was cut off by the client limit (${n.reason??`unknown`})`,terminal:o}:{outcome:`unknown`,reason:`the stream ended without the terminal event "${e.terminalEvent}"`,terminal:o};let l=e.successPointer==null?null:q(o,e.successPointer)[0];if(e.successPointer!=null&&l!==e.successValue)return{outcome:`failed`,reason:`"${e.terminalEvent}" ended with ${e.successPointer}=${JSON.stringify(l)} (expected ${JSON.stringify(e.successValue)})`,terminal:o};let u=e.requiredEvents.filter(e=>!s.has(e));return u.length>0?{outcome:`failed`,reason:`required event(s) missing before "${e.terminalEvent}": ${u.join(`, `)}`,terminal:o}:{outcome:`success`,reason:null,terminal:o}},ii={transferTimeoutMs:Fe,maxDownloadBytes:Ie,maxAutoDownloadsPerCall:20,maxInlineOutputBytes:33554432},ai=(e,t)=>{let n=``,r=0,i=e.indexOf(`{`);for(;i!==-1;){let a=e.indexOf(`}`,i+1);if(a===-1)break;n+=a===i+1?e.slice(r,a+1):e.slice(r,i)+t(e.slice(i+1,a)),r=a+1,i=e.indexOf(`{`,r)}return n+e.slice(r)},oi=(e,t)=>{if(typeof t==`string`)return t;if(typeof t==`number`||typeof t==`boolean`)return String(t);throw new N(`argument "${e}" must be a string, number, or boolean`)},si=(e,t,n)=>{if(_(n,`tenantName`))throw new N(`"tenantName" is fixed by the server configuration`);let r=ai(t.pathTemplate,t=>{if(t===`tenantName`)return encodeURIComponent(e.tenantName);let r=n[t];if(r==null)throw new N(`path parameter "${t}" is required`);return encodeURIComponent(oi(t,r))}),i=[];for(let e of t.queryParams){let t=n[e];if(t!=null){if(Array.isArray(t))for(let n of t)i.push([e,oi(e,n)]);else i.push([e,oi(e,t)])}}let a=null,o=!1;if(t.wholeBodyField!=null){if(!_(n,t.wholeBodyField))throw new N(`argument "${t.wholeBodyField}" is required`);a=n[t.wholeBodyField],o=!0}else if(t.bodyFields!=null){let e={};for(let r of t.bodyFields)_(n,r)&&(e[r]=n[r]);a=e,o=!0}return{method:t.method,path:r,query:i,hasBody:o,body:a,responseKind:t.responseKind}},ci=e=>{try{return JSON.parse(e)}catch{return e}},li=e=>({event:e.event,data:ci(e.data),...e.id==null?{}:{id:e.id}}),ui=(e,t)=>{if(e instanceof O)return{isError:!0,payload:{error:{kind:`api`,...e.info}}};if(e instanceof k)return{isError:!0,payload:{error:{kind:`transport`,failure:e.kind,status:e.status,message:e.message}}};if(e instanceof A)return{isError:!0,payload:{error:{kind:`transfer`,failure:e.kind,status:e.status,message:e.message}}};if(e instanceof N)return{isError:!0,payload:{error:{kind:`invalid_arguments`,message:e.message}}};if(e instanceof j)return{isError:!0,payload:{error:{kind:`local_file`,failure:e.kind,message:e.message}}};if(e instanceof M)return{isError:!0,payload:{error:{kind:`inline_file`,failure:e.kind,message:e.message}}};if(e instanceof P)return{isError:!0,payload:{error:{kind:`workspace`,failure:e.kind,message:e.message}}};if(e instanceof F)return{isError:!0,payload:{error:{kind:`auth`,failure:e.kind,message:e.message}}};if(e instanceof Re)return{isError:!0,payload:e.payload};if(e instanceof Error)return{isError:!0,payload:{error:{kind:`unexpected`,message:G(e.message,t)}}};throw e},Z=async(e,t,n)=>{try{return await un(e.workspace,new Date(e.now())),await e.auth.assertLoggedIn(),{isError:!1,payload:await n()}}catch(n){let r=e.auth.secrets(),i=ui(n,r),a=JSON.parse(G(JSON.stringify(i.payload),r));return e.logger.warn(`tool call failed`,{operationId:t,payload:a}),{isError:!0,payload:a}}},di=async(e,t,n,r)=>{let i=or(n,t.transfer);if(i.length===0)return{};let a=[],o=[],s=[],c=[];for(let n of i){let i;try{i=nr(n.url,e.config)}catch(e){c.push({url:n.url,reason:e instanceof Error?e.message:`rejected`});continue}if(n.kind===`upload`){e.registry.register(n.url,`upload`,n.headers),a.push(n.url);continue}if(o.length>=r.maxAutoDownloadsPerCall){e.registry.register(n.url,`download`,{});continue}let l=fr(i.pathname.split(`/`).at(-1)??null,`${t.operationId}.bin`),u;try{u=await gr({url:i,outputDir:e.config.outputDir,fileName:l,fetch:e.fetch,maxBytes:r.maxDownloadBytes,timeoutMs:r.transferTimeoutMs})}catch(r){if(!(r instanceof A))throw r;e.logger.warn(`automatic download failed`,{operationId:t.operationId,host:i.hostname,failure:r.kind}),e.registry.register(n.url,`download`,{}),s.push({url:n.url,failure:r.kind});continue}o.push({url:n.url,path:u.path,bytes:u.bytes,sha256Hex:u.sha256Hex,contentType:u.contentType})}return{...a.length===0?{}:{uploadUrls:a,uploadHint:`Call upload_file with one of these URLs and a local file path.`},...o.length===0?{}:{downloads:o},...s.length===0?{}:{failedDownloads:s,downloadHint:`The API response above is complete; only the automatic download failed. Retry it with download_file and the same URL.`},...c.length===0?{}:{rejectedTransferUrls:c}}},fi=(e,t,n)=>({outputDir:e.config.outputDir,fileName:t.operationId,maxBytes:n.maxInlineOutputBytes,timeoutMs:n.transferTimeoutMs}),pi=e=>e.length===0?{}:{files:e},mi=async(e,t,n,r=ii)=>Z(e,t.operationId,async()=>{let i=t.inlineFiles,a=i==null?n:await Xr(i,n,{fileRoots:e.config.fileRoots,cwd:e.cwd,workspace:e.workspace}),o=si(e.config,t,a),s=await e.client.request(o);switch(s.kind){case`json`:{let n=await di(e,t,s.body,r),a=i==null?{body:s.body,files:[]}:await ni(i,s.body,fi(e,t,r));return{status:s.status,requestId:s.requestId,body:a.body,...n,...pi(a.files)}}case`empty`:return{status:s.status,requestId:s.requestId};case`sse`:{let n=i==null?{events:s.events,files:[]}:await ti(i,s.events,fi(e,t,r)),a={status:s.status,requestId:s.requestId,events:n.events.map(e=>li(e)),truncated:s.truncated,stopReason:s.reason,discardedIncomplete:s.discardedIncomplete,...pi(n.files)};if(t.sseOutcome==null)return a;let o=ri(t.sseOutcome,s.events,{truncated:s.truncated,reason:s.reason}),c={...a,outcome:o.outcome,outcomeReason:o.reason,terminal:o.terminal};if(o.outcome!==`success`)throw new Re(o.reason??`operation failed`,{...c,retryHint:`Not retried automatically. Check the affected resource or execution history before running this operation again.`});return c}case`binary`:{let n=await hr(s.body,{outputDir:e.config.outputDir,fileName:fr(s.fileName,`${t.operationId}.bin`),maxBytes:r.maxDownloadBytes,timeoutMs:r.transferTimeoutMs});return{status:s.status,requestId:s.requestId,file:{...n,contentType:s.contentType,fileName:s.fileName}}}default:throw Error(`unknown response kind`)}}),hi=(e,t)=>`Flyle AIコンタクトセンターの公開 API を呼ぶツール群です。
|
|
6
|
+
- 接続先テナントは「${e}」、環境(公開 API のホスト)は「${t}」です。テナント・環境・ログインはサーバー起動時に固定されており、ツール引数でテナントを指定することはできません。
|
|
7
|
+
- この作業ディレクトリは「${e}」専用です。別の顧客(テナント)の情報・ファイル・記憶をこのテナントへの書き込みに使わないでください。別テナントの作業は別ディレクトリの別セッションで行います。
|
|
8
|
+
- 各ツール結果の先頭の environment と tenantName は、その操作を実行した環境とテナントです。
|
|
9
|
+
- 顧客の環境を利用者の合意なしに変えないでください。まず読み取り系ツール(readOnlyHint)で調べ、どの設定・データをどう変えるか(対象、変更前 → 変更後、影響)と理由を示して、利用者の明示的な合意を得てから書き込み系ツールを呼びます。合意した範囲を超える変更が必要になったら、その都度改めて合意を得てください。プレビューでの対話・検証の実行・改善分析など、設定やデータを変えない確認は合意なしで進めて構いません。利用者が合意を省いてよいと明示した場合は、その範囲に限って確認を省けます。
|
|
10
|
+
- ツールが「ログインが必要です」と返したら、利用者に作業ディレクトリで \`npx @flyle/ai-contact-center-mcp login\` を実行してもらってください。
|
|
11
|
+
- 書き込み系ツールは自動再送しません。タイムアウトや transport エラーの後は、対象を再取得して状態を確認してください。
|
|
12
|
+
- 一覧は各ツールの入力スキーマと応答に従って取得してください。cursor / limit+offset / ページングなしの全件取得があります。
|
|
13
|
+
- 大きな JSON 結果は出力ディレクトリに全文を保存し、保存先と先頭部分を返します。全文は保存ファイルを参照してください。
|
|
14
|
+
- 改善要望は、現在の設定・既存ケースの取得 → 追加するケースと修正案を示して合意を得る → create_eval_case / import_eval_cases でケースを保存 → 変更前の検証 → 合意した修正 → プレビュー作成完了の確認 → 全ケースの再検証の順に進めます。エージェントの設定(ID 情報・ノード・ルーティング・フォームなど)の変更は、プレビューと検証に直ちに反映されます。プレビュービルドはナレッジベースの検索用インデックスだけを作るため、設定だけを変えても previewRevisionSerial は変わりません。再ビルドが必要なのは、参照するナレッジベースや文書を変えたときです。create_improvement_analysis は分析結果を返すだけで、検証ケースや設定を保存しません。
|
|
15
|
+
- 改善提案は内容と get_improvement_proposal_plan を確認し、根拠のある actionIndexes だけを resolve_improvement_proposal で適用してください。検証の受付だけで合格と判断せず、get_eval_run と list_eval_run_case_results で完了・ケース別結果を確認してください。
|
|
16
|
+
- ファイル取込は inspect_local_file → create_knowledge_upload_urls → upload_file → create_knowledge_import の順に進め、取込と文書の処理完了を確認します。API の byteSize には sizeBytes、checksumSha256 には sha256Hex を渡します(sha256Base64 ではありません)。URL の発行と upload_file は同じ MCP 接続で行ってください。ダウンロード系はファイルパスを返します。`,gi=e=>v(e)&&e.type===`object`&&v(e.properties),_i=(e,t)=>{if(!gi(e))throw Error(`${t}: input schema must be an object schema`);return e},vi=e=>typeof e==`string`?e:Array.isArray(e)&&e.every(e=>typeof e==`string`)?e.join(`, `):null,yi=e=>{if(!v(e))return null;let t=e.gate;if(t===`none`)return`認証のみ(ロール不要)`;let n=vi(e.action??e.actions);return n==null||typeof t!=`string`?null:t===`any-resource`?`必要な権限: ${n}(いずれかのエージェントで保持)`:t===`per-resource`?`必要な権限: ${n}(対象エージェントに対して)`:t===`per-resource-all`?`必要な権限: ${n} のすべて(対象エージェントに対して)`:t===`per-resource-any`?`必要な権限: ${n} のいずれか(対象エージェントに対して)`:`必要な権限: ${n}(${t})`},bi={read:null,draft:`下書きへの変更です。公開版(利用者への配信)には publish まで反映されません。`},xi=e=>e.effect==null?null:bi[e.effect],Si=e=>{let t=[e.summary];e.description!=null&&t.push(``,e.description),t.push(``,`HTTP: ${e.method} ${e.pathTemplate}`);let n=yi(e.permission);n!=null&&t.push(n);let r=xi(e);r!=null&&t.push(``,r),e.responseKind===`sse`&&t.push(``,`ストリーミング応答を終端まで収集してから返します(数分かかることがあります)。`),e.responseKind===`binary`&&t.push(``,`ファイルを出力ディレクトリに保存し、パスと sha256 を返します。`),e.transfer?.kind===`download`&&t.push(``,`応答に含まれる署名付き URL からその場でダウンロードし、ファイルパスを返します。`),e.transfer?.kind===`upload`&&t.push(``,`応答のアップロード URL は upload_file ツールで使えます(15 分・1 回限り)。`),e.wholeBodyField!=null&&t.push(``,`リクエストボディは "${e.wholeBodyField}" 引数にそのまま渡します(判別共用体)。`);for(let n of e.inlineFiles?.input??[])t.push(``,n.format===`wav-pcm16`&&n.pcm!=null?`"${n.pointer}" にはローカル WAV ファイルのパス(PCM 16bit / ${String(n.pcm.sampleRateHz)} Hz / ${String(n.pcm.channels)}ch、音声 ${String(n.maxBytes)} バイト以内)を渡します。base64 化はこのサーバーが行います。`:`"${n.pointer}" にはローカルファイルのパス(${String(n.maxBytes)} バイト以内)を渡します。base64 化はこのサーバーが行います。`);if((e.inlineFiles?.output.length??0)>0&&t.push(``,`応答に埋め込まれた音声 / ファイルは出力ディレクトリに保存し、パスだけを返します(base64 は結果に含めません)。`),e.sseOutcome!=null){let n=[...e.sseOutcome.requiredEvents,e.sseOutcome.successPointer==null?e.sseOutcome.terminalEvent:`${e.sseOutcome.terminalEvent}{${e.sseOutcome.successPointer}=${JSON.stringify(e.sseOutcome.successValue)}}`];t.push(``,`成功判定: ${n.join(` と `)} が揃ったときだけ outcome=success。欠落・異常終了・打ち切りは isError で返し、自動再送しません。`)}return e.method!==`GET`&&t.push(``,`この操作は自動再送しません。タイムアウト時は状態を再取得して確認してください。`),t.join(`
|
|
17
|
+
`)},Ci=e=>({readOnlyHint:e.method===`GET`,destructiveHint:e.method!==`GET`,idempotentHint:e.method===`GET`||e.method===`PUT`||e.method===`DELETE`,openWorldHint:!1}),wi=e=>{let t=e.slice(0,4096),n=t.codePointAt(t.length-1)??0;return n>=55296&&n<=56319?t.slice(0,-1):t},Ti=e=>new ReadableStream({start(t){t.enqueue(e),t.close()}}),Ei=(e,t,n)=>({content:[{type:`text`,text:JSON.stringify({environment:e.environment,tenantName:e.tenantName})},{type:`text`,text:t}],isError:n}),Di=async(e,t)=>{let{secrets:n}=t,r=G(JSON.stringify(e.payload,null,2)??`null`,n);if(r.length<=1048576)return Ei(t,r,e.isError);let i=Buffer.from(G(JSON.stringify(e.payload)??`null`,n),`utf8`),a={totalChars:r.length,preview:wi(r)};try{let n=await hr(Ti(i),{outputDir:t.outputDir,fileName:t.fileName,maxBytes:t.maxFileBytes,timeoutMs:Fe});return Ei(t,JSON.stringify({file:{...n,format:`json`},...a},null,2),e.isError)}catch(e){let n=e instanceof A?e.kind:`unexpected`;return t.logger.warn(`tool result could not be saved`,{fileName:t.fileName,failure:n,bytes:i.byteLength}),Ei(t,JSON.stringify({error:{kind:`result_not_saved`,failure:n,message:`The full result was not saved; only the preview below is available. The operation may have completed; check its state before retrying.`},...a},null,2),!0)}},Oi=(e,t)=>({environment:R(e.config.baseUrl),tenantName:e.config.tenantName,outputDir:e.config.outputDir,fileName:`${t}.result.json`,logger:e.logger,secrets:e.auth.secrets(),maxFileBytes:67108864}),ki=e=>v(e)?e:{},Ai=(e,t)=>{let n=e[t];if(typeof n!=`string`||n===``)throw new N(`argument "${t}" is required`);return n},ji={inspectLocalFile:{type:`object`,properties:{path:{type:`string`,description:`ローカルファイルのパス(相対パスは作業ディレクトリ基準)。`}},required:[`path`],additionalProperties:!1},uploadFile:{type:`object`,properties:{url:{type:`string`,description:`直前の API 応答で返されたアップロード URL。`},path:{type:`string`,description:`アップロードするローカルファイルのパス。`}},required:[`url`,`path`],additionalProperties:!1},downloadFile:{type:`object`,properties:{url:{type:`string`,description:`直前の API 応答で返されたダウンロード URL。`},fileName:{type:`string`,description:`保存名(省略時は URL の末尾から決める)。`}},required:[`url`],additionalProperties:!1}},Mi=(e,t)=>{e.registerTool(`inspect_local_file`,{title:`ローカルファイルの検査`,description:`アップロード前にローカルファイルの名前・サイズ・sha256(hex / base64)・MIME を返します。API の byteSize には sizeBytes、checksumSha256 には sha256Hex を渡してください。読めるのは起動設定の根ディレクトリ配下だけです。`,inputSchema:ce(_i(ji.inspectLocalFile,`inspect_local_file`)),annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1}},async e=>{let n=ki(e);return Di(await Z(t,`inspect_local_file`,()=>er(Ai(n,`path`),t.config.fileRoots,t.cwd,t.workspace)),Oi(t,`inspect_local_file`))}),e.registerTool(`upload_file`,{title:`署名付き URL へアップロード`,description:`直前の API 応答で返されたアップロード URL へローカルファイルを PUT します。URL は応答由来のものだけを 15 分・1 回限りで受け付け、認証ヘッダは付けません。`,inputSchema:ce(_i(ji.uploadFile,`upload_file`)),annotations:{readOnlyHint:!1,destructiveHint:!1,idempotentHint:!1,openWorldHint:!1}},async e=>{let n=ki(e);return Di(await Z(t,`upload_file`,async()=>{let e=Ai(n,`url`),r=await Xn(Ai(n,`path`),t.config.fileRoots,t.cwd,t.workspace),i=t.registry.take(e,`upload`);return await ur({url:new URL(e),headers:i.headers,filePath:r,fetch:t.fetch,maxBytes:536870912,timeoutMs:Fe})}),Oi(t,`upload_file`))}),e.registerTool(`download_file`,{title:`署名付き URL からダウンロード`,description:`直前の API 応答で返されたダウンロード URL からファイルを取得し、出力ディレクトリに保存してパスを返します。URL は応答由来のものだけを受け付けます。`,inputSchema:ce(_i(ji.downloadFile,`download_file`)),annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0,openWorldHint:!1}},async e=>{let n=ki(e);return Di(await Z(t,`download_file`,async()=>{let e=Ai(n,`url`);t.registry.take(e,`download`);let r=new URL(e),i=typeof n.fileName==`string`?n.fileName:null;return await gr({url:r,outputDir:t.config.outputDir,fileName:fr(i??r.pathname.split(`/`).at(-1)??null,`download.bin`),fetch:t.fetch,maxBytes:Ie,timeoutMs:Fe})}),Oi(t,`download_file`))})},Ni=(e,t)=>{let n=new se({name:`flyle-ai-contact-center`,version:ke},{capabilities:{tools:{}},instructions:hi(e.config.tenantName,R(e.config.baseUrl))});for(let r of t.operations)n.registerTool(r.operationId,{title:r.summary,description:Si(r),inputSchema:ce(_i(r.inputSchema,r.operationId)),annotations:Ci(r)},async t=>Di(await mi(e,r,ki(t)),Oi(e,r.operationId)));return Mi(n,e),n},Q=e=>new Promise(t=>setTimeout(t,e)),$=()=>Date.now(),Pi=()=>({cwd:process.cwd(),homeDir:e(),hostname:t(),username:n().username,now:()=>new Date}),Fi=()=>nt({platform:process.platform,env:process.env,homeDir:e()}),Ii=(e,t)=>{console.error(e),process.exit(t)},Li=async e=>{try{return await it(e)}catch(e){if(e instanceof F&&e.kind===`login_required`)return null;throw e}},Ri=async e=>{let{cwd:t}=e;Xe(process.env);let n=await ln(e);if(n==null)throw new I("この作業ディレクトリはまだログインしていません。このディレクトリで `npx @flyle/ai-contact-center-mcp login --tenant <テナント名>` を実行してから、MCP サーバーを起動し直してください。");let r=Qe(process.env,t,n),i=rt(Fi(),n.workspaceId),a=await Li(i);return a!=null&&Bt(a,r.baseUrl,r.tenantName),{config:r,workspace:n,credentialsFile:i,loggedIn:a!=null}},zi=async()=>{let e=Pi(),{cwd:t}=e,n=await Ri(e).catch(e=>Ii(W(e),1)),{config:i,workspace:a,credentialsFile:o}=n,s=()=>[],c=vn(()=>s()),l=Ht({credentialsFile:o,baseUrl:i.baseUrl,tenantName:i.tenantName,tokenClient:U({config:i,auth:null,workspaceId:a.workspaceId,fetch:globalThis.fetch,now:$,sleep:Q,logger:c},Pt),now:$,lock:ct($,Q)});s=l.secrets;let u=Br(),d={config:i,auth:l,client:U({config:i,auth:l,workspaceId:a.workspaceId,fetch:globalThis.fetch,now:$,sleep:Q,logger:c}),registry:tr($),fetch:globalThis.fetch,logger:c,now:$,cwd:t,workspace:a},f=r(()=>Ni(d,u));c.info(`flygate mcp server started`,{environment:R(i.baseUrl),tenantName:i.tenantName,workspace:a.root,loggedIn:n.loggedIn,operations:u.operations.length});let p=!1,m=()=>{p||(p=!0,Promise.race([l.whenIdle(),Q(25e3)]).then(()=>f.close()).catch(z).finally(()=>process.exit(0)))};process.on(`SIGINT`,m),process.on(`SIGTERM`,m),process.stdin.once(`end`,m)},Bi=()=>({env:process.env,workspaceEnv:Pi(),credentialsDir:Fi(),fetch:globalThis.fetch,now:$,sleep:Q,lock:ct($,Q),logger:vn(()=>[]),out:e=>console.log(e),err:e=>console.error(e)}),Vi=async e=>{try{await e()}catch(e){Ii(W(e),1)}};await(async()=>{let[e,...t]=process.argv.slice(2);if(e==null){await zi();return}let n={login:()=>Un({...Bi(),argv:t,openBrowser:e=>Wt(e),callbackTimeoutMs:6e5}),logout:()=>bn(Bi()),status:()=>Kn(Bi())},r=_(n,e)?n[e]:null;if(r==null)return Ii(`使い方: flyle-ai-contact-center-mcp [login [--tenant <テナント名>] [--api-base-url <URL>] | logout | status]
|
|
18
|
+
引数なしで起動すると MCP サーバー(stdio)として動きます。`,2);await Vi(async()=>{Xe(process.env),await r()})})();export{};
|
package/manifest.json.br
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,59 +1 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@flyle/ai-contact-center-mcp",
|
|
3
|
-
"version": "0.1.1",
|
|
4
|
-
"description": "MCP server for the Flyle AI Contact Center public API",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"flyle",
|
|
7
|
-
"mcp",
|
|
8
|
-
"modelcontextprotocol"
|
|
9
|
-
],
|
|
10
|
-
"license": "SEE LICENSE IN LICENSE",
|
|
11
|
-
"author": "Flyle.inc",
|
|
12
|
-
"repository": {
|
|
13
|
-
"type": "git",
|
|
14
|
-
"url": "git+https://github.com/flyle-io/flyle-nexus.git",
|
|
15
|
-
"directory": "apps/flygate/mcp"
|
|
16
|
-
},
|
|
17
|
-
"bin": {
|
|
18
|
-
"flyle-ai-contact-center-mcp": "./dist/main.js"
|
|
19
|
-
},
|
|
20
|
-
"files": [
|
|
21
|
-
"dist",
|
|
22
|
-
"generated"
|
|
23
|
-
],
|
|
24
|
-
"type": "module",
|
|
25
|
-
"sideEffects": false,
|
|
26
|
-
"publishConfig": {
|
|
27
|
-
"access": "public",
|
|
28
|
-
"registry": "https://registry.npmjs.org/"
|
|
29
|
-
},
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"@modelcontextprotocol/server": "2.0.0"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"rolldown": "1.2.4",
|
|
35
|
-
"valibot": "1.3.1",
|
|
36
|
-
"@flyle-lib/utils": "0.0.0"
|
|
37
|
-
},
|
|
38
|
-
"engines": {
|
|
39
|
-
"node": ">=22.0.0"
|
|
40
|
-
},
|
|
41
|
-
"scripts": {
|
|
42
|
-
"start": "node src/main.ts",
|
|
43
|
-
"build": "rolldown -c",
|
|
44
|
-
"format:check": "rsvelte-fmt --check .",
|
|
45
|
-
"format:verify:oxfmt": "oxfmt --write . && oxfmt --check .",
|
|
46
|
-
"format:fix": "rsvelte-fmt .",
|
|
47
|
-
"type:check": "tsc --noEmit",
|
|
48
|
-
"type:check:tsgo": "tsgo --noEmit",
|
|
49
|
-
"lint:check": "oxlint -c=../../../.oxlintrc.jsonc && eslint --cache --cache-strategy content --concurrency auto --max-warnings 0 .",
|
|
50
|
-
"lint:fix": "oxlint --fix -c=../../../.oxlintrc.jsonc && eslint --cache --cache-strategy content --concurrency auto --fix .",
|
|
51
|
-
"test": "vitest run --silent=false --coverage",
|
|
52
|
-
"test:watch": "vitest --silent=false",
|
|
53
|
-
"manifest:generate": "node ./scripts/generate-manifest.ts --write",
|
|
54
|
-
"manifest:check": "node ./scripts/generate-manifest.ts --check",
|
|
55
|
-
"publint": "pnpm build && publint",
|
|
56
|
-
"knip": "knip",
|
|
57
|
-
"test:all": "pnpm format:check && pnpm type:check && pnpm lint:check && pnpm test && pnpm publint && pnpm knip"
|
|
58
|
-
}
|
|
59
|
-
}
|
|
1
|
+
{"name":"@flyle/ai-contact-center-mcp","version":"0.2.0","description":"MCP server for the Flyle AI Contact Center public API","keywords":["flyle","mcp","modelcontextprotocol"],"license":"SEE LICENSE IN LICENSE","author":"Flyle.inc","repository":{"type":"git","url":"git+https://github.com/flyle-io/flyle-nexus.git","directory":"apps/flygate/mcp"},"type":"module","engines":{"node":">=22.0.0"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"bin":{"flyle-ai-contact-center-mcp":"./main.js"},"dependencies":{"@modelcontextprotocol/server":"2.0.0"}}
|