bluelamp 6.4.16 → 6.5.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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * bluelamp-neo i18n — 多言語メッセージ管理
2
+ * bluelamp i18n — 多言語メッセージ管理
3
3
  *
4
4
  * env `MUSUHI_LANGUAGE` で言語を切り替え (default: ja)。 旧 `bluelampportal/mcp/lib/i18n/index.js` を
5
5
  * TypeScript で再実装したもの。挙動は完全互換 (キー欠落時の ja フォールバック / 未知キーは key 文字列を返す / `{var}` テンプレート置換)。
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * bluelamp-neo — barrel exports (auth / utils / i18n).
2
+ * bluelamp — barrel exports (auth / utils / i18n).
3
3
  */
4
4
  export { PortalAuthClient } from './auth/PortalAuthClient.js';
5
5
  export type { AuthResult, AuthSuccess, AuthFailure, AuthenticatedUser, DeviceInfo, } from './auth/PortalAuthClient.js';
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- const{Server:Server}=require("@modelcontextprotocol/sdk/server/index.js"),{StdioServerTransport:StdioServerTransport}=require("@modelcontextprotocol/sdk/server/stdio.js"),{CallToolRequestSchema:CallToolRequestSchema,ListToolsRequestSchema:ListToolsRequestSchema}=require("@modelcontextprotocol/sdk/types.js"),{execSync:execSync}=require("child_process"),fs=require("fs"),os=require("os"),path=require("path");let TokenManager=null;try{({TokenManager:TokenManager}=require("../../auth/TokenManager"))}catch{TokenManager=null}const FALLBACK_TOKEN_PATH=path.join(os.homedir(),".musuhi","portal-token.enc"),TOOLS=[{name:"logout",description:"BlueLamp からログアウトします。ローカルの認証トークン(~/.musuhi/portal-token.enc)を削除するだけで、サーバー側のデータには触れません。別アカウントへ切り替えたいときもこれを使います。実行後に bluelamp1〜300 のいずれかを起動し直すとログイン画面が出るので、新しいアカウントでログインしてください。",inputSchema:{type:"object",properties:{}}},{name:"update_cli",description:"BlueLamp CLI を最新版に更新します(npm install -g bluelamp@latest を実行)。更新後は bluelamp1〜300 を起動し直すと新しい版が使われます。",inputSchema:{type:"object",properties:{}}}];function text(e,t){const n={content:[{type:"text",text:e}]};return t&&(n.isError=!0),n}function tail(e,t){return String(e||"").trim().split("\n").slice(-t).join("\n")}async function handleLogout(){try{let e=!1;return TokenManager&&"function"==typeof TokenManager.deleteToken?e=await TokenManager.deleteToken():fs.existsSync(FALLBACK_TOKEN_PATH)&&(fs.unlinkSync(FALLBACK_TOKEN_PATH),e=!0),text(e?"✅ ログアウトしました(ローカルの認証トークンを削除)。\n次に bluelamp1〜300 のいずれかを起動するとログイン画面が出ます。\n別アカウントに切り替えたい場合は、そのまま新しいメール/パスワードでログインしてください。":"ℹ️ すでにログアウト済みです(認証トークンは見つかりませんでした)。")}catch(e){return text(`Error: ログアウトに失敗しました: ${e&&e.message?e.message:e}`,!0)}}function handleUpdateCli(){try{return text("✅ BlueLamp CLI を更新しました(npm install -g bluelamp@latest)。\n次に bluelamp1〜300 を起動し直すと新しい版が使われます。\n\n"+tail(execSync("npm install -g bluelamp@latest",{encoding:"utf8",stdio:["ignore","pipe","pipe"]}),5))}catch(e){return text("Error: CLI 更新に失敗しました。手動で `npm install -g bluelamp@latest` を実行してください。\n"+tail(e&&(e.stderr||e.message)?e.stderr||e.message:String(e),5),!0)}}async function main(){const e=new Server({name:"bluelamp-account",version:"1.0.0"},{capabilities:{tools:{}}});e.setRequestHandler(ListToolsRequestSchema,async()=>({tools:TOOLS})),e.setRequestHandler(CallToolRequestSchema,async e=>{const t=e.params&&e.params.name;return"logout"===t?handleLogout():"update_cli"===t?handleUpdateCli():text(`Error: unknown tool: ${t}`,!0)});const t=new StdioServerTransport;await e.connect(t),console.error("[bluelamp-account] account-mcp connected (logout / update_cli)")}main().catch(e=>{console.error("[bluelamp-account] startup failed:",e&&e.stack?e.stack:e),process.exit(1)});
2
+ const{Server:Server}=require("@modelcontextprotocol/sdk/server/index.js"),{StdioServerTransport:StdioServerTransport}=require("@modelcontextprotocol/sdk/server/stdio.js"),{CallToolRequestSchema:CallToolRequestSchema,ListToolsRequestSchema:ListToolsRequestSchema}=require("@modelcontextprotocol/sdk/types.js"),{execSync:execSync}=require("child_process"),fs=require("fs"),os=require("os"),path=require("path");let TokenManager=null;try{({TokenManager:TokenManager}=require("../../auth/TokenManager"))}catch{TokenManager=null}const FALLBACK_TOKEN_PATH=path.join(os.homedir(),".musuhi","portal-token.enc");let formatWhoami=null;try{({formatWhoami:formatWhoami}=require("../whoami"))}catch{formatWhoami=null}const TOOLS=[{name:"whoami",description:"今どの BlueLamp アカウント・どのテナントで動いているかを表示します。この端末の全セッション(monster / scheduler / 素の claude を含む)は同じ認証トークンを共有するため、「エージェントが出てこない」「load_knowledge が失敗する」ときは最初にこれで別アカウントになっていないかを確認してください。",inputSchema:{type:"object",properties:{}}},{name:"logout",description:"BlueLamp からログアウトします。ローカルの認証トークン(~/.musuhi/portal-token.enc)を削除するだけで、サーバー側のデータには触れません。別アカウントへ切り替えたいときもこれを使います。実行後に bluelamp1〜300 のいずれかを起動し直すとログイン画面が出るので、新しいアカウントでログインしてください。",inputSchema:{type:"object",properties:{}}},{name:"update_cli",description:"BlueLamp CLI を最新版に更新します(npm install -g bluelamp@latest を実行)。更新後は bluelamp1〜300 を起動し直すと新しい版が使われます。",inputSchema:{type:"object",properties:{}}}];function text(e,t){const n={content:[{type:"text",text:e}]};return t&&(n.isError=!0),n}function tail(e,t){return String(e||"").trim().split("\n").slice(-t).join("\n")}async function handleWhoami(){if("function"!=typeof formatWhoami)return text("Error: whoami は使えません(CLI のビルドが古い可能性)。`npm install -g bluelamp@latest` で更新してください。",!0);try{const e=TokenManager&&"function"==typeof TokenManager.loadToken?await TokenManager.loadToken():null,t=e&&e.token?e.token:null;if(!t)return text(formatWhoami({tokenPresent:!1,validated:null,tokenPath:FALLBACK_TOKEN_PATH}));let n=null;TokenManager&&"function"==typeof TokenManager.validateToken&&(n=await TokenManager.validateToken(t));const a=n&&n.valid&&n.userInfo||{},o=e&&e.userInfo||{};return text(formatWhoami({tokenPresent:!0,validated:!(!n||!n.valid)||null,note:n&&!n.valid?n.error:null,name:a.name||o.name||null,email:a.email||o.email||null,role:a.role||o.role||null,tenantId:a.active_tenant_id||o.active_tenant_id||null,tokenPath:FALLBACK_TOKEN_PATH}))}catch(e){return text(`Error: アカウント情報の取得に失敗しました: ${e&&e.message?e.message:e}`,!0)}}async function handleLogout(){try{let e=!1;return TokenManager&&"function"==typeof TokenManager.deleteToken?e=await TokenManager.deleteToken():fs.existsSync(FALLBACK_TOKEN_PATH)&&(fs.unlinkSync(FALLBACK_TOKEN_PATH),e=!0),text(e?"✅ ログアウトしました(ローカルの認証トークンを削除)。\n次に bluelamp1〜300 のいずれかを起動するとログイン画面が出ます。\n別アカウントに切り替えたい場合は、そのまま新しいメール/パスワードでログインしてください。":"ℹ️ すでにログアウト済みです(認証トークンは見つかりませんでした)。")}catch(e){return text(`Error: ログアウトに失敗しました: ${e&&e.message?e.message:e}`,!0)}}function handleUpdateCli(){try{return text("✅ BlueLamp CLI を更新しました(npm install -g bluelamp@latest)。\n次に bluelamp1〜300 を起動し直すと新しい版が使われます。\n\n"+tail(execSync("npm install -g bluelamp@latest",{encoding:"utf8",stdio:["ignore","pipe","pipe"]}),5))}catch(e){return text("Error: CLI 更新に失敗しました。手動で `npm install -g bluelamp@latest` を実行してください。\n"+tail(e&&(e.stderr||e.message)?e.stderr||e.message:String(e),5),!0)}}async function main(){const e=new Server({name:"bluelamp-account",version:"1.0.0"},{capabilities:{tools:{}}});e.setRequestHandler(ListToolsRequestSchema,async()=>({tools:TOOLS})),e.setRequestHandler(CallToolRequestSchema,async e=>{const t=e.params&&e.params.name;return"whoami"===t?handleWhoami():"logout"===t?handleLogout():"update_cli"===t?handleUpdateCli():text(`Error: unknown tool: ${t}`,!0)});const t=new StdioServerTransport;await e.connect(t),console.error("[bluelamp-account] account-mcp connected (whoami / logout / update_cli)")}main().catch(e=>{console.error("[bluelamp-account] startup failed:",e&&e.stack?e.stack:e),process.exit(1)});
@@ -1 +1 @@
1
- const fetch=(...t)=>import("node-fetch").then(({default:e})=>e(...t)),https=require("https"),fs=require("fs"),path=require("path"),os=require("os"),{logger:logger}=require("../../utils/logger"),{t:t}=require("../../i18n"),PORTAL_URL_ENV=process.env.BLUELAMP_PORTAL_API_BASE_URL||process.env.PORTAL_URL||"",isDevEnvironment=PORTAL_URL_ENV.includes("localhost"),httpsAgent=new https.Agent({rejectUnauthorized:!isDevEnvironment}),PORTAL_URL=PORTAL_URL_ENV||(isDevEnvironment?"http://localhost:8430/api/bluelamp":"https://api.motohi.jp/api/bluelamp"),LOG_DIR=path.join(os.homedir(),".bluelamp-vscode","logs"),LOG_FILE=path.join(LOG_DIR,"mcp.log");function log(t){const e=`[${(new Date).toISOString()}] ${t}\n`;fs.appendFileSync(LOG_FILE,e),logger.debug(t)}let _cliVersion;function getCliVersion(){if(void 0!==_cliVersion)return _cliVersion;let t=__dirname;for(let e=0;e<6;e++){try{const e=require(path.join(t,"package.json"));if(e&&e.version&&e.bin&&Object.keys(e.bin).some(t=>/^[a-z]+\d+$/.test(t)))return _cliVersion=e.version,_cliVersion}catch(t){}const e=path.dirname(t);if(e===t)break;t=e}return _cliVersion=null,_cliVersion}async function getPromptFromPortal(e,o,r="ja"){try{if(log(`[portal-api-client] getPromptFromPortal called with keyword: ${e}, lang: ${r}, token: ${o?"present":"missing"}`),!o)return log("[portal-api-client] No authentication token provided"),{success:!1,error:t("mcp.noAuthToken")};const s=process.env.MUSUHI_TENANT_ID||"",a=encodeURIComponent(e);let n=`${PORTAL_URL}/cli/prompts/knowledge-injection/${a}?lang=${r}`;s&&(n+=`&tenant_id=${encodeURIComponent(s)}`),log(`[portal-api-client] Direct keyword search: ${n}`),log(`[portal-api-client] Token (first 30 chars): ${o.substring(0,30)}...`),log("[portal-api-client] About to call fetch...");const c=await fetch(n,{method:"GET",headers:{"X-CLI-Token":o,...getCliVersion()?{"X-CLI-Version":getCliVersion()}:{},...s?{"X-Tenant-ID":s}:{},"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:n.startsWith("https")?httpsAgent:void 0});if(log("[portal-api-client] Fetch completed"),log(`[portal-api-client] Response status: ${c.status}`),log(`[portal-api-client] Response headers: ${JSON.stringify(Object.fromEntries(c.headers.entries()))}`),!c.ok){log(`[portal-api-client] Portal API error: ${c.status}`);const e=await c.text();log(`[portal-api-client] Error response: ${e}`);let o=t("mcp.portalApiError",{status:c.status});try{const t=JSON.parse(e);t.message&&(o=t.message)}catch(t){}return{success:!1,error:o}}const i=await c.json();if(log("[portal-api-client] Direct keyword search completed successfully"),!i.success)return log("[portal-api-client] API returned success: false"),{success:!1,error:i.message||t("mcp.apiReturnedError")};const l=i.data;if(!l)return log(`[portal-api-client] No prompt found for keyword: ${e}`),{success:!1,error:t("mcp.promptNotFoundForKeyword",{keyword:e})};if(log(`[portal-api-client] Found prompt: ${l.title}`),l.content||l.text)return{success:!0,knowledge:l.content||l.text,title:l.title,tags:l.tags||[]};try{const t=`${PORTAL_URL}/cli/prompts/${l.id}`;log(`[portal-api-client] Fetching prompt details from: ${t}`);const e=await fetch(t,{method:"GET",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:httpsAgent});if(e.ok){const t=await e.json();if(t.success&&t.data?.prompt?.content)return log("[portal-api-client] Successfully fetched prompt content"),{success:!0,knowledge:t.data.prompt.content,title:l.title||l.name,tags:l.tags}}}catch(t){log(`[portal-api-client] Error fetching prompt details: ${t.message}`)}return{success:!0,knowledge:l.description||`# ${l.title}\n\n${t("mcp.knowledgeLoadError",{error:"detail fetch failed"})}`,title:l.title||l.name,tags:l.tags}}catch(e){return log(`[portal-api-client] FATAL ERROR in getPromptFromPortal: ${e.message}`),log(`[portal-api-client] Error stack: ${e.stack}`),logger.error(`Failed to get prompt from Portal: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function getSlotConfig(t,e){try{if(!e)return log("[portal-api-client] getSlotConfig: No token, returning null"),null;const o=process.env.MUSUHI_TENANT_ID||"",r=`${PORTAL_URL}/cli/slot-config/${t}`;log(`[portal-api-client] Fetching slot config: ${r}${o?` (tenant=${o})`:""}`);const s=await fetch(r,{method:"GET",headers:{"X-CLI-Token":e,...getCliVersion()?{"X-CLI-Version":getCliVersion()}:{},...o?{"X-Tenant-ID":o}:{},"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0});if(!s.ok)return log(`[portal-api-client] Slot config API error: ${s.status}, using default`),null;const a=await s.json();return a.success&&a.data?.keyword?(log(`[portal-api-client] Slot ${t}: custom keyword "${a.data.keyword}"`),a.data.keyword):(log(`[portal-api-client] Slot ${t}: no custom config, using default`),null)}catch(t){return log(`[portal-api-client] getSlotConfig error: ${t.message}, using default`),null}}async function reportViolation(e,o,r,s){try{if(log(`[portal-api-client] reportViolation called: severity=${o}`),!r)return{success:!1,error:t("mcp.violationNoToken")};const a=`${PORTAL_URL}/cli/report-violation`,n={reason:e,severity:o};s&&(n.userMessage=s);const c=await fetch(a,{method:"POST",headers:{"X-CLI-Token":r,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:a.startsWith("https")?httpsAgent:void 0,body:JSON.stringify(n)});if(!c.ok){const e=await c.text();return log(`[portal-api-client] reportViolation error: ${c.status} ${e}`),{success:!1,error:t("mcp.violationApiError",{status:c.status})}}const i=await c.json();return log(`[portal-api-client] reportViolation result: action=${i.action}, count=${i.violationCount}`),i}catch(e){return log(`[portal-api-client] reportViolation FATAL: ${e.message}`),{success:!1,error:t("mcp.violationCommunicationError",{error:e.message})}}}async function listAvailableMcps(e={},o,r="ja"){try{if(log(`[portal-api-client] listAvailableMcps called: ${JSON.stringify(e)}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const s=new URLSearchParams;e.category&&s.set("category",e.category),e.search&&s.set("search",e.search),e.limit&&s.set("limit",String(e.limit)),s.set("lang",r);const a=`${PORTAL_URL}/mcp/catalog?${s.toString()}`;log(`[portal-api-client] Fetching MCP catalog: ${a}`);const n=await fetch(a,{method:"GET",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:a.startsWith("https")?httpsAgent:void 0});if(!n.ok){const e=await n.text();log(`[portal-api-client] listAvailableMcps error: ${n.status} ${e}`);let o=t("mcp.listMcpsFailed",{error:`HTTP ${n.status}`});try{const t=JSON.parse(e);t.message&&(o=t.message)}catch(t){}return{success:!1,error:o}}const c=await n.json();return log(`[portal-api-client] listAvailableMcps: ${c.data?.length||0} MCPs found`),{success:!0,data:c.data||[]}}catch(e){return log(`[portal-api-client] listAvailableMcps FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function getMcpInfo(e,o,r="ja"){try{if(log(`[portal-api-client] getMcpInfo called: mcpId=${e}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const s=`${PORTAL_URL}/mcp/${encodeURIComponent(e)}/details?lang=${r}`;log(`[portal-api-client] Fetching MCP info: ${s}`);const a=await fetch(s,{method:"GET",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:s.startsWith("https")?httpsAgent:void 0});if(!a.ok){const e=await a.text();log(`[portal-api-client] getMcpInfo error: ${a.status} ${e}`);let o=t("mcp.getMcpInfoFailed",{error:`HTTP ${a.status}`});try{const t=JSON.parse(e);t.message&&(o=t.message)}catch(t){}return{success:!1,error:o}}const n=await a.json();return log(`[portal-api-client] getMcpInfo: found ${n.data?.name||e}`),{success:!0,data:n.data}}catch(e){return log(`[portal-api-client] getMcpInfo FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function callMcpTool(e,o,r,s){try{if(log(`[portal-api-client] callMcpTool called: mcpId=${e}, tool=${o}`),!s)return{success:!1,error:t("mcp.noAuthToken")};const a=`${PORTAL_URL}/mcp/${encodeURIComponent(e)}/call`,n={tool_name:o,arguments:r};log(`[portal-api-client] Calling MCP tool: ${a}`);const c=await fetch(a,{method:"POST",headers:{"X-CLI-Token":s,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:a.startsWith("https")?httpsAgent:void 0,body:JSON.stringify(n)});if(!c.ok){const e=await c.text();log(`[portal-api-client] callMcpTool error: ${c.status} ${e}`);let o=t("mcp.callToolFailed",{error:`HTTP ${c.status}`});try{const t=JSON.parse(e);t.message&&(o=t.message)}catch(t){}return{success:!1,error:o}}const i=await c.json();return log("[portal-api-client] callMcpTool: success"),{success:!0,data:i.data}}catch(e){return log(`[portal-api-client] callMcpTool FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function scanMcpCode(e,o){try{if(log("[portal-api-client] scanMcpCode called"),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/mcp/scan`,s=await fetch(r,{method:"POST",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0,body:JSON.stringify({code:e})});if(!s.ok){const t=await s.text();return log(`[portal-api-client] scanMcpCode error: ${s.status} ${t}`),{success:!1,error:`HTTP ${s.status}`}}return{success:!0,data:(await s.json()).data}}catch(e){return log(`[portal-api-client] scanMcpCode FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function deployUserMcp(e,o){try{if(log(`[portal-api-client] deployUserMcp called: name=${e.name}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/mcp/deploy`,s=await fetch(r,{method:"POST",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0,body:JSON.stringify(e)});if(!s.ok){const t=await s.text();log(`[portal-api-client] deployUserMcp error: ${s.status} ${t}`);let e=`HTTP ${s.status}`;try{const o=JSON.parse(t);if(o.error&&(e=o.error),o.details)return{success:!1,error:e,details:o.details}}catch(t){}return{success:!1,error:e}}return{success:!0,data:(await s.json()).data}}catch(e){return log(`[portal-api-client] deployUserMcp FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function listUserCreatedMcps(e){try{if(log("[portal-api-client] listUserCreatedMcps called"),!e)return{success:!1,error:t("mcp.noAuthToken")};const o=`${PORTAL_URL}/mcp/user/me/created`,r=await fetch(o,{method:"GET",headers:{"X-CLI-Token":e,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:o.startsWith("https")?httpsAgent:void 0});return r.ok?{success:!0,data:(await r.json()).data}:(await r.text(),log(`[portal-api-client] listUserCreatedMcps error: ${r.status}`),{success:!1,error:`HTTP ${r.status}`})}catch(e){return log(`[portal-api-client] listUserCreatedMcps FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function deleteUserMcp(e,o){try{if(log(`[portal-api-client] deleteUserMcp called: mcpId=${e}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/mcp/${encodeURIComponent(e)}`,s=await fetch(r,{method:"DELETE",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0});if(!s.ok){const t=await s.text();log(`[portal-api-client] deleteUserMcp error: ${s.status}`);let e=`HTTP ${s.status}`;try{const o=JSON.parse(t);o.error&&(e=o.error)}catch(t){}return{success:!1,error:e}}return{success:!0,data:(await s.json()).data}}catch(e){return log(`[portal-api-client] deleteUserMcp FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function listMyPrompts(e){try{if(log("[portal-api-client] listMyPrompts called"),!e)return{success:!1,error:t("mcp.noAuthToken")};const o=`${PORTAL_URL}/cli/my-agents`,r=await fetch(o,{method:"GET",headers:{"X-CLI-Token":e,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:o.startsWith("https")?httpsAgent:void 0});return r.ok?{success:!0,data:(await r.json()).data||[]}:(await r.text(),log(`[portal-api-client] listMyPrompts error: ${r.status}`),{success:!1,error:`HTTP ${r.status}`})}catch(e){return log(`[portal-api-client] listMyPrompts FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function saveMyPrompt(e,o){try{if(log(`[portal-api-client] saveMyPrompt called: title=${e.title}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/cli/my-agents`,s=await fetch(r,{method:"POST",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0,body:JSON.stringify(e)});if(!s.ok){const t=await s.text();log(`[portal-api-client] saveMyPrompt error: ${s.status} ${t}`);let e=`HTTP ${s.status}`;try{const o=JSON.parse(t);o.message&&(e=o.message)}catch(t){}return{success:!1,error:e}}return{success:!0,data:(await s.json()).data}}catch(e){return log(`[portal-api-client] saveMyPrompt FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function deleteMyPrompt(e,o){try{if(log(`[portal-api-client] deleteMyPrompt called: id=${e}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/cli/my-agents/${encodeURIComponent(e)}`,s=await fetch(r,{method:"DELETE",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0});if(!s.ok){const t=await s.text();log(`[portal-api-client] deleteMyPrompt error: ${s.status}`);let e=`HTTP ${s.status}`;try{const o=JSON.parse(t);o.message&&(e=o.message)}catch(t){}return{success:!1,error:e}}return{success:!0,data:(await s.json()).data}}catch(e){return log(`[portal-api-client] deleteMyPrompt FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function downloadMcpPackage(e,o){try{if(log(`[portal-api-client] downloadMcpPackage called: mcpId=${e}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/mcp/${encodeURIComponent(e)}/download`;log(`[portal-api-client] Downloading MCP package: ${r}`);const s=await fetch(r,{method:"GET",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0});if(!s.ok){const t=await s.text();log(`[portal-api-client] downloadMcpPackage error: ${s.status} ${t}`);let e=`Download failed: HTTP ${s.status}`;try{const o=JSON.parse(t);o.message&&(e=o.message)}catch(t){}return{success:!1,error:e}}const a=await s.json();return log(`[portal-api-client] downloadMcpPackage: ${a.data?.files?.length||0} files`),{success:!0,data:a.data}}catch(e){return log(`[portal-api-client] downloadMcpPackage FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function getGatewayConfig(t){try{if(!t)return{success:!1,error:"No token"};const e=`${PORTAL_URL}/mcp/user/me/gateway-config`;log(`[portal-api-client] getGatewayConfig: ${e}`);const o=await fetch(e,{method:"GET",headers:{"X-CLI-Token":t,"Content-Type":"application/json"},agent:e.startsWith("https")?httpsAgent:void 0});if(!o.ok)return{success:!1,error:`HTTP ${o.status}`};const r=await o.json();return log(`[portal-api-client] getGatewayConfig: ${r.data?.services?.length||0} services`),{success:!0,data:r.data}}catch(t){return log(`[portal-api-client] getGatewayConfig error: ${t.message}`),{success:!1,error:t.message}}}async function searchMcpServices(t,e){try{if(!e)return{success:!1,error:"No token"};const o=`${PORTAL_URL}/mcp/search?q=${encodeURIComponent(t)}`;log(`[portal-api-client] searchMcpServices: ${o}`);const r=await fetch(o,{method:"GET",headers:{"X-CLI-Token":e,"Content-Type":"application/json"},agent:o.startsWith("https")?httpsAgent:void 0});return r.ok?{success:!0,data:(await r.json()).data}:{success:!1,error:`HTTP ${r.status}`}}catch(t){return log(`[portal-api-client] searchMcpServices error: ${t.message}`),{success:!1,error:t.message}}}async function installMcpService(t,e,o,r){try{if(!o)return{success:!1,error:"No token"};const s=`${PORTAL_URL}/mcp/user/me/install`,a={mcpId:t,alwaysOn:e??!1};r&&Object.keys(r).length>0&&(a.envOverrides=r);const n=await fetch(s,{method:"POST",headers:{"X-CLI-Token":o,"Content-Type":"application/json"},agent:s.startsWith("https")?httpsAgent:void 0,body:JSON.stringify(a)});return n.ok?{success:!0,data:(await n.json()).data}:{success:!1,error:`HTTP ${n.status}`}}catch(t){return log(`[portal-api-client] installMcpService error: ${t.message}`),{success:!1,error:t.message}}}async function setServiceAlwaysOn(t,e,o){try{if(!o)return{success:!1,error:"No token"};const r=e?"activate":"deactivate",s=`${PORTAL_URL}/mcp/user/me/services/${encodeURIComponent(t)}/${r}`,a=await fetch(s,{method:"POST",headers:{"X-CLI-Token":o,"Content-Type":"application/json"},agent:s.startsWith("https")?httpsAgent:void 0});return a.ok?{success:!0,data:(await a.json()).data}:{success:!1,error:`HTTP ${a.status}`}}catch(t){return log(`[portal-api-client] setServiceAlwaysOn error: ${t.message}`),{success:!1,error:t.message}}}async function uninstallMcpService(t,e){try{if(!e)return{success:!1,error:"No token"};const o=`${PORTAL_URL}/mcp/user/me/services/${encodeURIComponent(t)}`,r=await fetch(o,{method:"DELETE",headers:{"X-CLI-Token":e,"Content-Type":"application/json"},agent:o.startsWith("https")?httpsAgent:void 0});return r.ok?{success:!0,data:(await r.json()).data}:{success:!1,error:`HTTP ${r.status}`}}catch(t){return log(`[portal-api-client] uninstallMcpService error: ${t.message}`),{success:!1,error:t.message}}}async function updateMcpEnv(t,e,o){try{if(!o)return{success:!1,error:"No token"};const r=`${PORTAL_URL}/mcp/user/me/services/${encodeURIComponent(t)}/env`,s=await fetch(r,{method:"PUT",headers:{"X-CLI-Token":o,"Content-Type":"application/json"},agent:r.startsWith("https")?httpsAgent:void 0,body:JSON.stringify({env:e})});return s.ok?{success:!0,data:(await s.json()).data}:{success:!1,error:`HTTP ${s.status}`}}catch(t){return log(`[portal-api-client] updateMcpEnv error: ${t.message}`),{success:!1,error:t.message}}}async function callMcpToolProxy(t,e,o,r){try{if(!r)return{success:!1,error:"No token"};const s=`${PORTAL_URL}/mcp/${encodeURIComponent(t)}/call`,a=await fetch(s,{method:"POST",headers:{"X-CLI-Token":r,"Content-Type":"application/json"},agent:s.startsWith("https")?httpsAgent:void 0,body:JSON.stringify({tool_name:e,arguments:o})});if(!a.ok){const t=await a.text();return{success:!1,error:`HTTP ${a.status}: ${t.slice(0,200)}`}}return await a.json()}catch(t){return log(`[portal-api-client] callMcpToolProxy error: ${t.message}`),{success:!1,error:t.message}}}fs.existsSync(LOG_DIR)||fs.mkdirSync(LOG_DIR,{recursive:!0}),module.exports={getPromptFromPortal:getPromptFromPortal,getSlotConfig:getSlotConfig,reportViolation:reportViolation,listAvailableMcps:listAvailableMcps,getMcpInfo:getMcpInfo,downloadMcpPackage:downloadMcpPackage,callMcpTool:callMcpTool,scanMcpCode:scanMcpCode,deployUserMcp:deployUserMcp,listUserCreatedMcps:listUserCreatedMcps,deleteUserMcp:deleteUserMcp,listMyPrompts:listMyPrompts,saveMyPrompt:saveMyPrompt,deleteMyPrompt:deleteMyPrompt,getGatewayConfig:getGatewayConfig,searchMcpServices:searchMcpServices,installMcpService:installMcpService,setServiceAlwaysOn:setServiceAlwaysOn,uninstallMcpService:uninstallMcpService,updateMcpEnv:updateMcpEnv,callMcpToolProxy:callMcpToolProxy};
1
+ const fetch=(...t)=>import("node-fetch").then(({default:e})=>e(...t)),https=require("https"),fs=require("fs"),path=require("path"),os=require("os"),{logger:logger}=require("../../utils/logger"),{t:t}=require("../../i18n"),PORTAL_URL_ENV=process.env.BLUELAMP_PORTAL_API_BASE_URL||process.env.PORTAL_URL||"",isDevEnvironment=PORTAL_URL_ENV.includes("localhost"),httpsAgent=new https.Agent({rejectUnauthorized:!isDevEnvironment}),PORTAL_URL=PORTAL_URL_ENV||(isDevEnvironment?"http://localhost:8430/api/bluelamp":"https://api.motohi.jp/api/bluelamp"),LOG_DIR=path.join(os.homedir(),".bluelamp-vscode","logs"),LOG_FILE=path.join(LOG_DIR,"mcp.log");function log(t){const e=`[${(new Date).toISOString()}] ${t}\n`;fs.appendFileSync(LOG_FILE,e),logger.debug(t)}let _cliVersion;function getCliVersion(){if(void 0!==_cliVersion)return _cliVersion;let t=__dirname;for(let e=0;e<6;e++){try{const e=require(path.join(t,"package.json"));if(e&&e.version&&e.bin&&Object.keys(e.bin).some(t=>/^[a-z]+\d+$/.test(t)))return _cliVersion=e.version,_cliVersion}catch(t){}const e=path.dirname(t);if(e===t)break;t=e}return _cliVersion=null,_cliVersion}async function getPromptFromPortal(e,o,r="ja"){try{if(log(`[portal-api-client] getPromptFromPortal called with keyword: ${e}, lang: ${r}, token: ${o?"present":"missing"}`),!o)return log("[portal-api-client] No authentication token provided"),{success:!1,error:t("mcp.noAuthToken")};const s=process.env.MUSUHI_TENANT_ID||"",a=encodeURIComponent(e);let n=`${PORTAL_URL}/cli/prompts/knowledge-injection/${a}?lang=${r}`;s&&(n+=`&tenant_id=${encodeURIComponent(s)}`),log(`[portal-api-client] Direct keyword search: ${n}`),log(`[portal-api-client] Token (first 30 chars): ${o.substring(0,30)}...`),log("[portal-api-client] About to call fetch...");const c=await fetch(n,{method:"GET",headers:{"X-CLI-Token":o,...getCliVersion()?{"X-CLI-Version":getCliVersion()}:{},...s?{"X-Tenant-ID":s}:{},"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:n.startsWith("https")?httpsAgent:void 0});if(log("[portal-api-client] Fetch completed"),log(`[portal-api-client] Response status: ${c.status}`),log(`[portal-api-client] Response headers: ${JSON.stringify(Object.fromEntries(c.headers.entries()))}`),!c.ok){log(`[portal-api-client] Portal API error: ${c.status}`);const e=await c.text();log(`[portal-api-client] Error response: ${e}`);let o=t("mcp.portalApiError",{status:c.status}),r=null;try{const t=JSON.parse(e);t.message&&(o=t.message),t.code&&(r=t.code)}catch(t){}return{success:!1,error:o,status:c.status,code:r}}const i=await c.json();if(log("[portal-api-client] Direct keyword search completed successfully"),!i.success)return log("[portal-api-client] API returned success: false"),{success:!1,error:i.message||t("mcp.apiReturnedError")};const l=i.data;if(!l)return log(`[portal-api-client] No prompt found for keyword: ${e}`),{success:!1,error:t("mcp.promptNotFoundForKeyword",{keyword:e})};if(log(`[portal-api-client] Found prompt: ${l.title}`),l.content||l.text)return{success:!0,knowledge:l.content||l.text,title:l.title,tags:l.tags||[]};try{const t=`${PORTAL_URL}/cli/prompts/${l.id}`;log(`[portal-api-client] Fetching prompt details from: ${t}`);const e=await fetch(t,{method:"GET",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:httpsAgent});if(e.ok){const t=await e.json();if(t.success&&t.data?.prompt?.content)return log("[portal-api-client] Successfully fetched prompt content"),{success:!0,knowledge:t.data.prompt.content,title:l.title||l.name,tags:l.tags}}}catch(t){log(`[portal-api-client] Error fetching prompt details: ${t.message}`)}return{success:!0,knowledge:l.description||`# ${l.title}\n\n${t("mcp.knowledgeLoadError",{error:"detail fetch failed"})}`,title:l.title||l.name,tags:l.tags}}catch(e){return log(`[portal-api-client] FATAL ERROR in getPromptFromPortal: ${e.message}`),log(`[portal-api-client] Error stack: ${e.stack}`),logger.error(`Failed to get prompt from Portal: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function getSlotConfig(t,e){try{if(!e)return log("[portal-api-client] getSlotConfig: No token, returning null"),null;const o=process.env.MUSUHI_TENANT_ID||"",r=`${PORTAL_URL}/cli/slot-config/${t}`;log(`[portal-api-client] Fetching slot config: ${r}${o?` (tenant=${o})`:""}`);const s=await fetch(r,{method:"GET",headers:{"X-CLI-Token":e,...getCliVersion()?{"X-CLI-Version":getCliVersion()}:{},...o?{"X-Tenant-ID":o}:{},"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0});if(!s.ok)return log(`[portal-api-client] Slot config API error: ${s.status}, using default`),null;const a=await s.json();return a.success&&a.data?.keyword?(log(`[portal-api-client] Slot ${t}: custom keyword "${a.data.keyword}"`),a.data.keyword):(log(`[portal-api-client] Slot ${t}: no custom config, using default`),null)}catch(t){return log(`[portal-api-client] getSlotConfig error: ${t.message}, using default`),null}}async function reportViolation(e,o,r,s){try{if(log(`[portal-api-client] reportViolation called: severity=${o}`),!r)return{success:!1,error:t("mcp.violationNoToken")};const a=`${PORTAL_URL}/cli/report-violation`,n={reason:e,severity:o};s&&(n.userMessage=s);const c=await fetch(a,{method:"POST",headers:{"X-CLI-Token":r,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:a.startsWith("https")?httpsAgent:void 0,body:JSON.stringify(n)});if(!c.ok){const e=await c.text();return log(`[portal-api-client] reportViolation error: ${c.status} ${e}`),{success:!1,error:t("mcp.violationApiError",{status:c.status})}}const i=await c.json();return log(`[portal-api-client] reportViolation result: action=${i.action}, count=${i.violationCount}`),i}catch(e){return log(`[portal-api-client] reportViolation FATAL: ${e.message}`),{success:!1,error:t("mcp.violationCommunicationError",{error:e.message})}}}async function listAvailableMcps(e={},o,r="ja"){try{if(log(`[portal-api-client] listAvailableMcps called: ${JSON.stringify(e)}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const s=new URLSearchParams;e.category&&s.set("category",e.category),e.search&&s.set("search",e.search),e.limit&&s.set("limit",String(e.limit)),s.set("lang",r);const a=`${PORTAL_URL}/mcp/catalog?${s.toString()}`;log(`[portal-api-client] Fetching MCP catalog: ${a}`);const n=await fetch(a,{method:"GET",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:a.startsWith("https")?httpsAgent:void 0});if(!n.ok){const e=await n.text();log(`[portal-api-client] listAvailableMcps error: ${n.status} ${e}`);let o=t("mcp.listMcpsFailed",{error:`HTTP ${n.status}`});try{const t=JSON.parse(e);t.message&&(o=t.message)}catch(t){}return{success:!1,error:o}}const c=await n.json();return log(`[portal-api-client] listAvailableMcps: ${c.data?.length||0} MCPs found`),{success:!0,data:c.data||[]}}catch(e){return log(`[portal-api-client] listAvailableMcps FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function getMcpInfo(e,o,r="ja"){try{if(log(`[portal-api-client] getMcpInfo called: mcpId=${e}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const s=`${PORTAL_URL}/mcp/${encodeURIComponent(e)}/details?lang=${r}`;log(`[portal-api-client] Fetching MCP info: ${s}`);const a=await fetch(s,{method:"GET",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:s.startsWith("https")?httpsAgent:void 0});if(!a.ok){const e=await a.text();log(`[portal-api-client] getMcpInfo error: ${a.status} ${e}`);let o=t("mcp.getMcpInfoFailed",{error:`HTTP ${a.status}`});try{const t=JSON.parse(e);t.message&&(o=t.message)}catch(t){}return{success:!1,error:o}}const n=await a.json();return log(`[portal-api-client] getMcpInfo: found ${n.data?.name||e}`),{success:!0,data:n.data}}catch(e){return log(`[portal-api-client] getMcpInfo FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function callMcpTool(e,o,r,s){try{if(log(`[portal-api-client] callMcpTool called: mcpId=${e}, tool=${o}`),!s)return{success:!1,error:t("mcp.noAuthToken")};const a=`${PORTAL_URL}/mcp/${encodeURIComponent(e)}/call`,n={tool_name:o,arguments:r};log(`[portal-api-client] Calling MCP tool: ${a}`);const c=await fetch(a,{method:"POST",headers:{"X-CLI-Token":s,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:a.startsWith("https")?httpsAgent:void 0,body:JSON.stringify(n)});if(!c.ok){const e=await c.text();log(`[portal-api-client] callMcpTool error: ${c.status} ${e}`);let o=t("mcp.callToolFailed",{error:`HTTP ${c.status}`});try{const t=JSON.parse(e);t.message&&(o=t.message)}catch(t){}return{success:!1,error:o}}const i=await c.json();return log("[portal-api-client] callMcpTool: success"),{success:!0,data:i.data}}catch(e){return log(`[portal-api-client] callMcpTool FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function scanMcpCode(e,o){try{if(log("[portal-api-client] scanMcpCode called"),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/mcp/scan`,s=await fetch(r,{method:"POST",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0,body:JSON.stringify({code:e})});if(!s.ok){const t=await s.text();return log(`[portal-api-client] scanMcpCode error: ${s.status} ${t}`),{success:!1,error:`HTTP ${s.status}`}}return{success:!0,data:(await s.json()).data}}catch(e){return log(`[portal-api-client] scanMcpCode FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function deployUserMcp(e,o){try{if(log(`[portal-api-client] deployUserMcp called: name=${e.name}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/mcp/deploy`,s=await fetch(r,{method:"POST",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0,body:JSON.stringify(e)});if(!s.ok){const t=await s.text();log(`[portal-api-client] deployUserMcp error: ${s.status} ${t}`);let e=`HTTP ${s.status}`;try{const o=JSON.parse(t);if(o.error&&(e=o.error),o.details)return{success:!1,error:e,details:o.details}}catch(t){}return{success:!1,error:e}}return{success:!0,data:(await s.json()).data}}catch(e){return log(`[portal-api-client] deployUserMcp FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function listUserCreatedMcps(e){try{if(log("[portal-api-client] listUserCreatedMcps called"),!e)return{success:!1,error:t("mcp.noAuthToken")};const o=`${PORTAL_URL}/mcp/user/me/created`,r=await fetch(o,{method:"GET",headers:{"X-CLI-Token":e,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:o.startsWith("https")?httpsAgent:void 0});return r.ok?{success:!0,data:(await r.json()).data}:(await r.text(),log(`[portal-api-client] listUserCreatedMcps error: ${r.status}`),{success:!1,error:`HTTP ${r.status}`})}catch(e){return log(`[portal-api-client] listUserCreatedMcps FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function deleteUserMcp(e,o){try{if(log(`[portal-api-client] deleteUserMcp called: mcpId=${e}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/mcp/${encodeURIComponent(e)}`,s=await fetch(r,{method:"DELETE",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0});if(!s.ok){const t=await s.text();log(`[portal-api-client] deleteUserMcp error: ${s.status}`);let e=`HTTP ${s.status}`;try{const o=JSON.parse(t);o.error&&(e=o.error)}catch(t){}return{success:!1,error:e}}return{success:!0,data:(await s.json()).data}}catch(e){return log(`[portal-api-client] deleteUserMcp FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function listMyPrompts(e){try{if(log("[portal-api-client] listMyPrompts called"),!e)return{success:!1,error:t("mcp.noAuthToken")};const o=`${PORTAL_URL}/cli/my-agents`,r=await fetch(o,{method:"GET",headers:{"X-CLI-Token":e,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:o.startsWith("https")?httpsAgent:void 0});return r.ok?{success:!0,data:(await r.json()).data||[]}:(await r.text(),log(`[portal-api-client] listMyPrompts error: ${r.status}`),{success:!1,error:`HTTP ${r.status}`})}catch(e){return log(`[portal-api-client] listMyPrompts FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function saveMyPrompt(e,o){try{if(log(`[portal-api-client] saveMyPrompt called: title=${e.title}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/cli/my-agents`,s=await fetch(r,{method:"POST",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0,body:JSON.stringify(e)});if(!s.ok){const t=await s.text();log(`[portal-api-client] saveMyPrompt error: ${s.status} ${t}`);let e=`HTTP ${s.status}`;try{const o=JSON.parse(t);o.message&&(e=o.message)}catch(t){}return{success:!1,error:e}}return{success:!0,data:(await s.json()).data}}catch(e){return log(`[portal-api-client] saveMyPrompt FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function deleteMyPrompt(e,o){try{if(log(`[portal-api-client] deleteMyPrompt called: id=${e}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/cli/my-agents/${encodeURIComponent(e)}`,s=await fetch(r,{method:"DELETE",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0});if(!s.ok){const t=await s.text();log(`[portal-api-client] deleteMyPrompt error: ${s.status}`);let e=`HTTP ${s.status}`;try{const o=JSON.parse(t);o.message&&(e=o.message)}catch(t){}return{success:!1,error:e}}return{success:!0,data:(await s.json()).data}}catch(e){return log(`[portal-api-client] deleteMyPrompt FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function downloadMcpPackage(e,o){try{if(log(`[portal-api-client] downloadMcpPackage called: mcpId=${e}`),!o)return{success:!1,error:t("mcp.noAuthToken")};const r=`${PORTAL_URL}/mcp/${encodeURIComponent(e)}/download`;log(`[portal-api-client] Downloading MCP package: ${r}`);const s=await fetch(r,{method:"GET",headers:{"X-CLI-Token":o,"Content-Type":"application/json","User-Agent":"BlueLamp-VSCode-MCP/1.0"},agent:r.startsWith("https")?httpsAgent:void 0});if(!s.ok){const t=await s.text();log(`[portal-api-client] downloadMcpPackage error: ${s.status} ${t}`);let e=`Download failed: HTTP ${s.status}`;try{const o=JSON.parse(t);o.message&&(e=o.message)}catch(t){}return{success:!1,error:e}}const a=await s.json();return log(`[portal-api-client] downloadMcpPackage: ${a.data?.files?.length||0} files`),{success:!0,data:a.data}}catch(e){return log(`[portal-api-client] downloadMcpPackage FATAL: ${e.message}`),{success:!1,error:t("mcp.portalCommunicationError",{error:e.message})}}}async function getGatewayConfig(t){try{if(!t)return{success:!1,error:"No token"};const e=`${PORTAL_URL}/mcp/user/me/gateway-config`;log(`[portal-api-client] getGatewayConfig: ${e}`);const o=await fetch(e,{method:"GET",headers:{"X-CLI-Token":t,"Content-Type":"application/json"},agent:e.startsWith("https")?httpsAgent:void 0});if(!o.ok)return{success:!1,error:`HTTP ${o.status}`};const r=await o.json();return log(`[portal-api-client] getGatewayConfig: ${r.data?.services?.length||0} services`),{success:!0,data:r.data}}catch(t){return log(`[portal-api-client] getGatewayConfig error: ${t.message}`),{success:!1,error:t.message}}}async function searchMcpServices(t,e){try{if(!e)return{success:!1,error:"No token"};const o=`${PORTAL_URL}/mcp/search?q=${encodeURIComponent(t)}`;log(`[portal-api-client] searchMcpServices: ${o}`);const r=await fetch(o,{method:"GET",headers:{"X-CLI-Token":e,"Content-Type":"application/json"},agent:o.startsWith("https")?httpsAgent:void 0});return r.ok?{success:!0,data:(await r.json()).data}:{success:!1,error:`HTTP ${r.status}`}}catch(t){return log(`[portal-api-client] searchMcpServices error: ${t.message}`),{success:!1,error:t.message}}}async function installMcpService(t,e,o,r){try{if(!o)return{success:!1,error:"No token"};const s=`${PORTAL_URL}/mcp/user/me/install`,a={mcpId:t,alwaysOn:e??!1};r&&Object.keys(r).length>0&&(a.envOverrides=r);const n=await fetch(s,{method:"POST",headers:{"X-CLI-Token":o,"Content-Type":"application/json"},agent:s.startsWith("https")?httpsAgent:void 0,body:JSON.stringify(a)});return n.ok?{success:!0,data:(await n.json()).data}:{success:!1,error:`HTTP ${n.status}`}}catch(t){return log(`[portal-api-client] installMcpService error: ${t.message}`),{success:!1,error:t.message}}}async function setServiceAlwaysOn(t,e,o){try{if(!o)return{success:!1,error:"No token"};const r=e?"activate":"deactivate",s=`${PORTAL_URL}/mcp/user/me/services/${encodeURIComponent(t)}/${r}`,a=await fetch(s,{method:"POST",headers:{"X-CLI-Token":o,"Content-Type":"application/json"},agent:s.startsWith("https")?httpsAgent:void 0});return a.ok?{success:!0,data:(await a.json()).data}:{success:!1,error:`HTTP ${a.status}`}}catch(t){return log(`[portal-api-client] setServiceAlwaysOn error: ${t.message}`),{success:!1,error:t.message}}}async function uninstallMcpService(t,e){try{if(!e)return{success:!1,error:"No token"};const o=`${PORTAL_URL}/mcp/user/me/services/${encodeURIComponent(t)}`,r=await fetch(o,{method:"DELETE",headers:{"X-CLI-Token":e,"Content-Type":"application/json"},agent:o.startsWith("https")?httpsAgent:void 0});return r.ok?{success:!0,data:(await r.json()).data}:{success:!1,error:`HTTP ${r.status}`}}catch(t){return log(`[portal-api-client] uninstallMcpService error: ${t.message}`),{success:!1,error:t.message}}}async function updateMcpEnv(t,e,o){try{if(!o)return{success:!1,error:"No token"};const r=`${PORTAL_URL}/mcp/user/me/services/${encodeURIComponent(t)}/env`,s=await fetch(r,{method:"PUT",headers:{"X-CLI-Token":o,"Content-Type":"application/json"},agent:r.startsWith("https")?httpsAgent:void 0,body:JSON.stringify({env:e})});return s.ok?{success:!0,data:(await s.json()).data}:{success:!1,error:`HTTP ${s.status}`}}catch(t){return log(`[portal-api-client] updateMcpEnv error: ${t.message}`),{success:!1,error:t.message}}}async function callMcpToolProxy(t,e,o,r){try{if(!r)return{success:!1,error:"No token"};const s=`${PORTAL_URL}/mcp/${encodeURIComponent(t)}/call`,a=await fetch(s,{method:"POST",headers:{"X-CLI-Token":r,"Content-Type":"application/json"},agent:s.startsWith("https")?httpsAgent:void 0,body:JSON.stringify({tool_name:e,arguments:o})});if(!a.ok){const t=await a.text();return{success:!1,error:`HTTP ${a.status}: ${t.slice(0,200)}`}}return await a.json()}catch(t){return log(`[portal-api-client] callMcpToolProxy error: ${t.message}`),{success:!1,error:t.message}}}fs.existsSync(LOG_DIR)||fs.mkdirSync(LOG_DIR,{recursive:!0}),module.exports={getPromptFromPortal:getPromptFromPortal,getSlotConfig:getSlotConfig,reportViolation:reportViolation,listAvailableMcps:listAvailableMcps,getMcpInfo:getMcpInfo,downloadMcpPackage:downloadMcpPackage,callMcpTool:callMcpTool,scanMcpCode:scanMcpCode,deployUserMcp:deployUserMcp,listUserCreatedMcps:listUserCreatedMcps,deleteUserMcp:deleteUserMcp,listMyPrompts:listMyPrompts,saveMyPrompt:saveMyPrompt,deleteMyPrompt:deleteMyPrompt,getGatewayConfig:getGatewayConfig,searchMcpServices:searchMcpServices,installMcpService:installMcpService,setServiceAlwaysOn:setServiceAlwaysOn,uninstallMcpService:uninstallMcpService,updateMcpEnv:updateMcpEnv,callMcpToolProxy:callMcpToolProxy};
@@ -0,0 +1,77 @@
1
+ /**
2
+ * `~/.mcp.json` の自己修復(P1)。
3
+ *
4
+ * 我々が公開した npm パッケージ `bluelamp` 6.0.2〜6.4.1 の postinstall
5
+ * (`scripts/setup-mcps.js`) が、`~/.mcp.json` に次を書いていた:
6
+ *
7
+ * "bluelamp": { "command": "bluelamp1", "args": [] }
8
+ *
9
+ * `bluelamp1` は MCP サーバーではなく Claude Code 起動ラッパーなので、MCP として
10
+ * 起動されると接続不能になるだけでなく、`npm i -g` 自己更新や
11
+ * `--dangerously-skip-permissions` 付きの入れ子 claude を spawn する経路が開く。
12
+ *
13
+ * 6.4.2 で postinstall は廃止されたが「消す処理」は無かったため、当時インストールした
14
+ * 端末には今も残っている。しかも launcher 経由(`--mcp-config` に正しい定義を渡す)では
15
+ * 同名キーが上書きされて無害化されるため、**素の `claude` を起動した経路だけが壊れる**。
16
+ * 2026-07-30 実測(claude 2.1.220):
17
+ * `--mcp-config` > project scope (`.mcp.json`) > user scope (`~/.claude.json`)
18
+ * SSH ログイン直後の cwd は `$HOME` なので `~/.mcp.json` が project scope として読まれ、
19
+ * user scope の正しい定義を shadow する。これが今日の実害(monster / SSH で詰む)の機構。
20
+ *
21
+ * 🚨 安全要件(主君判断):
22
+ * - 触るのは `mcpServers.bluelamp` の **1 キーだけ**
23
+ * - `command` が我々の writer が書いた形(`bluelamp` + 数字)に一致する場合のみ削除する
24
+ * - 他のキーには一切触らない(同ファイルに残る playwright / password-manager / gmail 等の
25
+ * 古い定義は、他人が手で置いた設定かもしれないので残す)
26
+ * - JSON パースに失敗したファイルは書き戻さない(他人の設定を壊さない)
27
+ */
28
+ /** 自己修復の対象キー(ゲートウェイ 1 本のみ) */
29
+ export declare const GATEWAY_KEY = "bluelamp";
30
+ export interface McpServerEntry {
31
+ command?: unknown;
32
+ [key: string]: unknown;
33
+ }
34
+ export interface McpJsonShape {
35
+ mcpServers?: Record<string, McpServerEntry>;
36
+ [key: string]: unknown;
37
+ }
38
+ export type SelfHealSkipReason = 'not-an-object' | 'no-mcp-servers' | 'no-gateway-entry' | 'command-not-ours';
39
+ export interface SelfHealPlan {
40
+ changed: boolean;
41
+ /** 削除した command 値(ログ表示用) */
42
+ removedCommand?: string;
43
+ /** 書き戻すべき次の姿。changed=false のときは undefined */
44
+ next?: McpJsonShape;
45
+ /** changed=false の理由(診断用) */
46
+ reason?: SelfHealSkipReason;
47
+ }
48
+ /**
49
+ * 削除計画を立てる(純関数)。入力は JSON.parse 済みの値。
50
+ * 他キーの順序・内容はそのまま次の姿に引き継ぐ。
51
+ */
52
+ export declare function planMcpJsonSelfHeal(raw: unknown): SelfHealPlan;
53
+ export interface SelfHealIo {
54
+ exists(filePath: string): boolean;
55
+ read(filePath: string): string;
56
+ write(filePath: string, contents: string): void;
57
+ }
58
+ export type SelfHealOutcome = {
59
+ healed: true;
60
+ removedCommand: string;
61
+ } | {
62
+ healed: false;
63
+ reason: SelfHealSkipReason | 'file-missing' | 'parse-failed' | 'read-failed' | 'write-failed';
64
+ detail?: string;
65
+ };
66
+ /**
67
+ * ファイルに対して自己修復を適用する(薄いシェル)。
68
+ * 例外は投げない — 起動を止めないのが最優先で、失敗は理由付きで返す。
69
+ */
70
+ export declare function healMcpJsonFile(filePath: string, io: SelfHealIo): SelfHealOutcome;
71
+ /** 実機用 IO(呼び出し時に解決する — HOME を差し替えるテストのため事前計算しない) */
72
+ export declare const nodeSelfHealIo: SelfHealIo;
73
+ /** `~/.mcp.json` の絶対パス。呼び出しごとに os.homedir() を解決する */
74
+ export declare function defaultMcpJsonPath(): string;
75
+ /** 実機での自己修復。launcher はこれを起動冒頭で 1 回呼ぶ */
76
+ export declare function healDefaultMcpJson(): SelfHealOutcome;
77
+ //# sourceMappingURL=mcpJsonSelfHeal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpJsonSelfHeal.d.ts","sourceRoot":"","sources":["../../src/lib/mcpJsonSelfHeal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AASH,8BAA8B;AAC9B,eAAO,MAAM,WAAW,aAAa,CAAC;AAEtC,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC5C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,kBAAkB,GAC1B,eAAe,GACf,gBAAgB,GAChB,kBAAkB,GAClB,kBAAkB,CAAC;AAEvB,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,4BAA4B;IAC5B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6CAA6C;IAC7C,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,6BAA6B;IAC7B,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC7B;AAMD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,CAwB9D;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAClC,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACjD;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,kBAAkB,GAAG,cAAc,GAAG,cAAc,GAAG,aAAa,GAAG,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtI;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,GAAG,eAAe,CA+BjF;AAMD,oDAAoD;AACpD,eAAO,MAAM,cAAc,EAAE,UAI5B,CAAC;AAEF,qDAAqD;AACrD,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,wCAAwC;AACxC,wBAAgB,kBAAkB,IAAI,eAAe,CAEpD"}
@@ -0,0 +1 @@
1
+ "use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var a=Object.getOwnPropertyDescriptor(t,n);a&&!("get"in a?!t.__esModule:a.writable||a.configurable)||(a={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,a)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),__importStar=this&&this.__importStar||function(){var e=function(t){return e=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},e(t)};return function(t){if(t&&t.__esModule)return t;var n={};if(null!=t)for(var r=e(t),a=0;a<r.length;a++)"default"!==r[a]&&__createBinding(n,t,r[a]);return __setModuleDefault(n,t),n}}();Object.defineProperty(exports,"__esModule",{value:!0}),exports.nodeSelfHealIo=exports.GATEWAY_KEY=void 0,exports.planMcpJsonSelfHeal=planMcpJsonSelfHeal,exports.healMcpJsonFile=healMcpJsonFile,exports.defaultMcpJsonPath=defaultMcpJsonPath,exports.healDefaultMcpJson=healDefaultMcpJson;const fs=__importStar(require("node:fs")),os=__importStar(require("node:os")),path=__importStar(require("node:path")),OUR_BROKEN_COMMAND=/^bluelamp\d+$/;function isPlainObject(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function planMcpJsonSelfHeal(e){if(!isPlainObject(e))return{changed:!1,reason:"not-an-object"};const t=e.mcpServers;if(!isPlainObject(t))return{changed:!1,reason:"no-mcp-servers"};const n=t[exports.GATEWAY_KEY];if(!isPlainObject(n))return{changed:!1,reason:"no-gateway-entry"};const r=n.command;if("string"!=typeof r||!OUR_BROKEN_COMMAND.test(r))return{changed:!1,reason:"command-not-ours"};const a={};for(const e of Object.keys(t))e!==exports.GATEWAY_KEY&&(a[e]=t[e]);return{changed:!0,removedCommand:r,next:{...e,mcpServers:a}}}function healMcpJsonFile(e,t){if(!t.exists(e))return{healed:!1,reason:"file-missing"};let n,r;try{n=t.read(e)}catch(e){return{healed:!1,reason:"read-failed",detail:messageOf(e)}}try{r=JSON.parse(n)}catch(e){return{healed:!1,reason:"parse-failed",detail:messageOf(e)}}const a=planMcpJsonSelfHeal(r);if(!a.changed||!a.next)return{healed:!1,reason:a.reason??"command-not-ours"};try{t.write(e,`${JSON.stringify(a.next,null,2)}\n`)}catch(e){return{healed:!1,reason:"write-failed",detail:messageOf(e)}}return{healed:!0,removedCommand:a.removedCommand}}function messageOf(e){return e instanceof Error?e.message:String(e)}function defaultMcpJsonPath(){return path.join(os.homedir(),".mcp.json")}function healDefaultMcpJson(){return healMcpJsonFile(defaultMcpJsonPath(),exports.nodeSelfHealIo)}exports.GATEWAY_KEY="bluelamp",exports.nodeSelfHealIo={exists:e=>fs.existsSync(e),read:e=>fs.readFileSync(e,"utf-8"),write:(e,t)=>fs.writeFileSync(e,t,"utf-8")};
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpJsonSelfHeal.js","sourceRoot":"","sources":["../../src/lib/mcpJsonSelfHeal.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8CH,kDAwBC;AAgBD,0CA+BC;AAcD,gDAEC;AAGD,gDAEC;AAxID,4CAA8B;AAC9B,4CAA8B;AAC9B,gDAAkC;AAElC,qDAAqD;AACrD,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAE3C,8BAA8B;AACjB,QAAA,WAAW,GAAG,UAAU,CAAC;AA4BtC,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CAAC,GAAY;IAC9C,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAE5E,MAAM,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC;IAC/B,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAEjF,MAAM,KAAK,GAAG,OAAO,CAAC,mBAAW,CAAC,CAAC;IACnC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAEjF,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;IAC9B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACrE,4DAA4D;QAC5D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC;IACxD,CAAC;IAED,kCAAkC;IAClC,MAAM,WAAW,GAAmC,EAAE,CAAC;IACvD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,IAAI,GAAG,KAAK,mBAAW;YAAE,SAAS;QAClC,WAAW,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAmB,CAAC;IACpD,CAAC;IAED,MAAM,IAAI,GAAiB,EAAE,GAAG,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;IAC/D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC1D,CAAC;AAYD;;;GAGG;AACH,SAAgB,eAAe,CAAC,QAAgB,EAAE,EAAc;IAC9D,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;IAE3E,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;IAC5E,CAAC;IAED,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,uCAAuC;QACvC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;IAC7E,CAAC;IAED,MAAM,IAAI,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAChC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,kBAAkB,EAAE,CAAC;IACtE,CAAC;IAED,IAAI,CAAC;QACH,qDAAqD;QACrD,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAChE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;IAC7E,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,CAAC,cAAwB,EAAE,CAAC;AACzE,CAAC;AAED,SAAS,SAAS,CAAC,KAAc;IAC/B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,oDAAoD;AACvC,QAAA,cAAc,GAAe;IACxC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;IAC7C,IAAI,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC;IACtD,KAAK,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC;CAC7E,CAAC;AAEF,qDAAqD;AACrD,SAAgB,kBAAkB;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AAC9C,CAAC;AAED,wCAAwC;AACxC,SAAgB,kBAAkB;IAChC,OAAO,eAAe,CAAC,kBAAkB,EAAE,EAAE,sBAAc,CAAC,CAAC;AAC/D,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * 本体プロンプト取得失敗時の案内文を組み立てる(P3・純関数)。
3
+ *
4
+ * 従来は失敗理由に関わらず「多くの場合アクティブテナントが未選択です」と決め打ちしていた。
5
+ * 実際の失敗要因は backend で 3 種に分かれており(cliController.getKiPromptByKeyword)、
6
+ * rank 不足(403)を「テナント未選択」と案内すると、エージェントが自信を持って誤原因を
7
+ * 断定し、利用者は無関係な操作(テナント選択のやり直し)を繰り返すことになる。
8
+ * 2026-07-30 の監査でこの誤診断を実害として確認したため、status で出し分ける。
9
+ *
10
+ * backend が返す対応:
11
+ * 403 `Rank not allowed` … rank 不足(allowed_min_rank ゲート)
12
+ * 404 `Prompt not found for keyword` … キーワード未登録 or official の module 非公開
13
+ * 409 `NO_ACTIVE_TENANT` … アクティブテナント未選択(唯一の「テナント未選択」)
14
+ * 401 … CLI トークンが無効(再ログインが必要)
15
+ *
16
+ * 原則: 特定できない失敗は「特定できていない」と言う。推測を案内文に混ぜない(潔癖性)。
17
+ */
18
+ export interface PromptFailureInput {
19
+ /** HTTP status。取得できなかった場合(通信失敗等)は null / undefined */
20
+ status?: number | null;
21
+ /** backend の message(そのまま利用者に見せる一次情報) */
22
+ message?: string | null;
23
+ /** backend の code(例: NO_ACTIVE_TENANT)。status が無くても分岐できる補助情報 */
24
+ code?: string | null;
25
+ }
26
+ /**
27
+ * 案内文を組み立てる。冒頭は必ず backend の生メッセージ(一次情報を隠さない)。
28
+ */
29
+ export declare function buildPromptFailureGuidance(input: PromptFailureInput): string;
30
+ //# sourceMappingURL=promptFailureGuidance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promptFailureGuidance.d.ts","sourceRoot":"","sources":["../../src/lib/promptFailureGuidance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAuCD;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,kBAAkB,GAAG,MAAM,CAW5E"}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.buildPromptFailureGuidance=buildPromptFailureGuidance;const NO_LOAD_KNOWLEDGE="load_knowledge は実行しないでください。";function causeFor(e,n){if("NO_ACTIVE_TENANT"===n)return tenantCause();switch(e){case 401:return"原因: ログイン情報(CLI トークン)が無効です。\n対処: bluelamp-account MCP の logout を実行し、bluelamp1〜300 を起動し直して再ログインするようユーザーへ案内してください。";case 403:return"原因: このアカウントの rank ではこのエージェントを使えません(rank 不足)。\n対処: テナント管理者に、このエージェントの配布(rank 条件の見直し)を依頼するようユーザーへ案内してください。\nテナントを選び直しても解決しません。アカウント切替の心当たりがあるなら bluelamp-account MCP の whoami で今のアカウントを確認してください。";case 404:return"原因: このキーワードのエージェントが見つかりません(未登録、またはテナントの module 設定で非公開)。\n対処: キーワードの綴りを確認し、正しければテナント管理者に配布状況(module の公開設定)を確認するようユーザーへ案内してください。";case 409:return tenantCause();default:return null}}function tenantCause(){return"原因: アクティブテナントが未選択です。\n対処: VSCode の BlueLamp 拡張でテナントを選択してから、BlueLamp を起動し直すようユーザーへ案内してください。"}function buildPromptFailureGuidance(e){const n=e.message&&String(e.message).trim().length>0?String(e.message).trim():"本体プロンプトを取得できませんでした",u=causeFor(e.status,e.code);return`本体プロンプトを読み込めませんでした: ${n}\n${NO_LOAD_KNOWLEDGE}\n${u??"原因はこちらでは特定できていません。上のメッセージをそのままユーザーへ伝え、推測での原因説明はしないでください。"}`}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promptFailureGuidance.js","sourceRoot":"","sources":["../../src/lib/promptFailureGuidance.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;AAmDH,gEAWC;AAnDD,yCAAyC;AACzC,MAAM,iBAAiB,GAAG,6BAA6B,CAAC;AAExD,yDAAyD;AACzD,SAAS,QAAQ,CAAC,MAAiC,EAAE,IAA+B;IAClF,IAAI,IAAI,KAAK,kBAAkB;QAAE,OAAO,WAAW,EAAE,CAAC;IACtD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,GAAG;YACN,OAAO,CACL,8BAA8B;gBAC9B,qFAAqF,CACtF,CAAC;QACJ,KAAK,GAAG;YACN,OAAO,CACL,gDAAgD;gBAChD,8DAA8D;gBAC9D,sFAAsF,CACvF,CAAC;QACJ,KAAK,GAAG;YACN,OAAO,CACL,2DAA2D;gBAC3D,uEAAuE,CACxE,CAAC;QACJ,KAAK,GAAG;YACN,OAAO,WAAW,EAAE,CAAC;QACvB;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,CACL,wBAAwB;QACxB,sEAAsE,CACvE,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,0BAA0B,CAAC,KAAyB;IAClE,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QACtE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE;QAC9B,CAAC,CAAC,oBAAoB,CAAC;IAEzB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,IAAI,GACR,KAAK;QACL,0DAA0D,CAAC;IAE7D,OAAO,uBAAuB,OAAO,KAAK,iBAAiB,KAAK,IAAI,EAAE,CAAC;AACzE,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * 「今どのアカウントで動いているか」の申告文を組み立てる(P4・純関数)。
3
+ *
4
+ * CLI の認証主体は単一グローバルファイル `~/.musuhi/portal-token.enc` であり、
5
+ * セッション / テナント単位の分離が無い。つまり一度アカウントを切り替えると、その端末の
6
+ * 全セッション・全 monster・scheduler が以後そのアカウントになる。
7
+ *
8
+ * ところが launcher (`bluelampN`) はアカウントを起動時に表示する(👤 / 📧 / 🎭)のに、
9
+ * launcher を経由しない経路(monster / scheduler / 素の `claude`)には表示箇所が一つも無い。
10
+ * 2026-07-30 の事故(別アカウントでログインしていたことに気づかず load_knowledge が全滅)は
11
+ * この不可視性そのものだったため、エージェントが自分で確認できる申告手段を用意する。
12
+ */
13
+ export interface WhoamiFacts {
14
+ /** ローカルにトークンが在るか */
15
+ tokenPresent: boolean;
16
+ /**
17
+ * portal が「有効」と明示的に答えたときだけ true。それ以外は null。
18
+ * TokenManager.validateToken は通信失敗も valid:false に潰すため、
19
+ * 「無効」と「繋がらなかった」を我々の側で区別できない。区別できないものを
20
+ * 断定しない(推測を案内文に混ぜない)ため false は作らず、理由は note に載せる。
21
+ */
22
+ validated: true | null;
23
+ /** portal が返した理由 / 通信エラー文(そのまま載せる一次情報) */
24
+ note?: string | null;
25
+ email?: string | null;
26
+ name?: string | null;
27
+ role?: string | null;
28
+ /** アクティブテナント(UUID)。未選択は null */
29
+ tenantId?: string | null;
30
+ /** トークンファイルの場所(利用者に実体を示す) */
31
+ tokenPath?: string | null;
32
+ }
33
+ export declare function formatWhoami(facts: WhoamiFacts): string;
34
+ //# sourceMappingURL=whoami.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/lib/whoami.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,WAAW;IAC1B,oBAAoB;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,SAAS,EAAE,IAAI,GAAG,IAAI,CAAC;IACvB,0CAA0C;IAC1C,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAOD,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAkCvD"}
@@ -0,0 +1 @@
1
+ "use strict";function line(e,l){return null==l||0===String(l).trim().length?null:`${e}: ${String(l).trim()}`}function formatWhoami(e){return e.tokenPresent?[!0===e.validated?"✅ 有効なトークンで認証されています。":"🟡 トークンは保存されていますが、portal で有効と確認できませんでした(無効化された / オフラインのどちらもあり得ます)。以下は保存時の情報です。",...[!0===e.validated?null:line("ℹ️ portal の応答",e.note),line("👤 名前",e.name),line("📧 メール",e.email),line("🎭 role",e.role),e.tenantId?line("🏢 アクティブテナント",e.tenantId):"🏢 アクティブテナント: 未選択(VSCode の BlueLamp 拡張で選択が必要)",line("🗂 トークン",e.tokenPath)].filter(e=>null!==e),"","この端末の全セッション(monster / scheduler / 素の claude を含む)が同じアカウントを共有します。","別アカウントに切り替えるには logout を実行してから bluelamp1〜300 を起動し直してください。"].join("\n"):["🔓 ログインしていません(ローカルに認証トークンがありません)。","bluelamp1〜300 のいずれかを起動するとログイン画面が出ます。",e.tokenPath?`確認した場所: ${e.tokenPath}`:null].filter(e=>null!==e).join("\n")}Object.defineProperty(exports,"__esModule",{value:!0}),exports.formatWhoami=formatWhoami;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/lib/whoami.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;AA4BH,oCAkCC;AAvCD,SAAS,IAAI,CAAC,KAAa,EAAE,KAAc;IACzC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5F,OAAO,GAAG,KAAK,KAAK,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;AAC7C,CAAC;AAED,SAAgB,YAAY,CAAC,KAAkB;IAC7C,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;QACxB,OAAO;YACL,mCAAmC;YACnC,sCAAsC;YACtC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,IAAI;SACtD;aACE,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;aACtC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAED,MAAM,QAAQ,GACZ,KAAK,CAAC,SAAS,KAAK,IAAI;QACtB,CAAC,CAAC,qBAAqB;QACvB,CAAC,CAAC,gFAAgF,CAAC;IAEvF,MAAM,IAAI,GAAG;QACX,KAAK,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,EAAE,KAAK,CAAC,IAAI,CAAC;QACnE,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC;QACzB,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC;QAC3B,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC;QAC3B,KAAK,CAAC,QAAQ;YACZ,CAAC,CAAC,IAAI,CAAC,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC;YACtC,CAAC,CAAC,+CAA+C;QACnD,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,SAAS,CAAC;KACjC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;IAEzC,OAAO;QACL,QAAQ;QACR,GAAG,IAAI;QACP,EAAE;QACF,iEAAiE;QACjE,0DAA0D;KAC3D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1 @@
1
+ "use strict";var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r);var l=Object.getOwnPropertyDescriptor(t,r);l&&!("get"in l?!t.__esModule:l.writable||l.configurable)||(l={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,l)}:function(e,t,r,n){void 0===n&&(n=r),e[n]=t[r]}),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),__importStar=this&&this.__importStar||function(){var e=function(t){return e=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[t.length]=r);return t},e(t)};return function(t){if(t&&t.__esModule)return t;var r={};if(null!=t)for(var n=e(t),l=0;l<n.length;l++)"default"!==n[l]&&__createBinding(r,t,n[l]);return __setModuleDefault(r,t),r}}();Object.defineProperty(exports,"__esModule",{value:!0}),exports.SHELL_PROBE_TIMEOUT_MS=void 0,exports.staticCandidates=staticCandidates,exports.pickPathFromShellOutput=pickPathFromShellOutput,exports.resolveClaudeBinWith=resolveClaudeBinWith,exports.isExecutableFile=isExecutableFile,exports.resolveLoginShell=resolveLoginShell,exports.askLoginShellForClaude=askLoginShellForClaude,exports.resolveClaudeBinDetailed=resolveClaudeBinDetailed;const node_child_process_1=require("node:child_process"),fs=__importStar(require("node:fs")),os=__importStar(require("node:os")),path=__importStar(require("node:path"));function staticCandidates(e){return[path.join(e,".local","bin","claude"),path.join(e,".claude","local","claude"),"/opt/homebrew/bin/claude","/usr/local/bin/claude","/usr/bin/claude"]}function pickPathFromShellOutput(e){const t=e.split("\n").map(e=>e.trim()).filter(e=>e.length>0);for(let e=t.length-1;e>=0;e-=1)if(t[e].startsWith("/"))return t[e];return null}function resolveClaudeBinWith(e){const t=e.env("SCHEDULER_CLAUDE_BIN");if(t&&t.length>0)return{bin:t,source:"env"};const r=e.askLoginShell();if(null!==r&&e.isExecutable(r))return{bin:r,source:"login_shell"};for(const t of staticCandidates(e.home()))if(e.isExecutable(t))return{bin:t,source:"static_candidate"};return{bin:null,error:`claude 実行ファイルを解決できません(${null===r?"ログインシェルからは取得できず":`ログインシェルは ${r} を返したが実行可能ファイルではない`}/静的候補もすべて不在)。SCHEDULER_CLAUDE_BIN に絶対パスを設定すれば確実に解決できます`}}function isExecutableFile(e){try{return!!fs.statSync(e).isFile()&&(fs.accessSync(e,fs.constants.X_OK),!0)}catch{return!1}}function resolveLoginShell(){const e=process.env.SHELL;if(e&&e.length>0)return e;try{const e=os.userInfo().shell;if(e&&e.length>0)return e}catch{}return null}function askLoginShellForClaude(){const e=resolveLoginShell();if(null===e)return null;try{return pickPathFromShellOutput((0,node_child_process_1.execFileSync)(e,["-lic","command -v claude"],{encoding:"utf-8",timeout:exports.SHELL_PROBE_TIMEOUT_MS,stdio:["ignore","pipe","ignore"]}))}catch{return null}}function resolveClaudeBinDetailed(){return resolveClaudeBinWith({env:e=>process.env[e],home:()=>os.homedir(),isExecutable:isExecutableFile,askLoginShell:askLoginShellForClaude})}exports.SHELL_PROBE_TIMEOUT_MS=5e3;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bluelamp",
3
- "version": "6.4.16",
3
+ "version": "6.5.0",
4
4
  "description": "BlueLamp CLI: 旧 bluelampportal/mcp の auth / 200+ bluelamp1-N binary / postinstall scripts を TypeScript 化して monorepo に統合したパッケージ。",
5
5
  "keywords": [
6
6
  "bluelamp",
@@ -31,10 +31,10 @@
31
31
  "url": "https://github.com/yamatovision/mikoto-monorepo/issues"
32
32
  },
33
33
  "scripts": {
34
- "build:tsc": "rm -rf dist && tsc && tsc -p scripts/tsconfig.json",
34
+ "build:tsc": "rm -rf dist && tsc && tsc -p scripts/tsconfig.json && tsc -p tsconfig.claude-bin.json",
35
35
  "build:obfuscate": "node scripts/build-obfuscate.mjs",
36
36
  "build": "pnpm run build:tsc && pnpm run build:obfuscate",
37
- "tsc": "tsc --noEmit && tsc -p scripts/tsconfig.json --noEmit",
37
+ "tsc": "tsc --noEmit && tsc -p scripts/tsconfig.json --noEmit && tsc -p tsconfig.claude-bin.json --noEmit",
38
38
  "generate:bins": "node dist/scripts/generate-commands.js",
39
39
  "test": "node --test --test-force-exit tests/*.test.mjs",
40
40
  "prepublishOnly": "pnpm run build"