aiagentmarket 3.0.9
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 +25 -0
- package/bin/aiagent +387 -0
- package/bin/aiagent-base +387 -0
- package/bin/aiagent1 +387 -0
- package/bin/aiagent10 +387 -0
- package/bin/aiagent100 +387 -0
- package/bin/aiagent11 +387 -0
- package/bin/aiagent12 +387 -0
- package/bin/aiagent13 +387 -0
- package/bin/aiagent14 +387 -0
- package/bin/aiagent15 +387 -0
- package/bin/aiagent16 +387 -0
- package/bin/aiagent17 +387 -0
- package/bin/aiagent18 +387 -0
- package/bin/aiagent19 +387 -0
- package/bin/aiagent2 +387 -0
- package/bin/aiagent20 +387 -0
- package/bin/aiagent21 +387 -0
- package/bin/aiagent22 +387 -0
- package/bin/aiagent23 +387 -0
- package/bin/aiagent24 +387 -0
- package/bin/aiagent25 +387 -0
- package/bin/aiagent26 +387 -0
- package/bin/aiagent27 +387 -0
- package/bin/aiagent28 +387 -0
- package/bin/aiagent29 +387 -0
- package/bin/aiagent3 +387 -0
- package/bin/aiagent30 +387 -0
- package/bin/aiagent31 +387 -0
- package/bin/aiagent32 +387 -0
- package/bin/aiagent33 +387 -0
- package/bin/aiagent34 +387 -0
- package/bin/aiagent35 +387 -0
- package/bin/aiagent36 +387 -0
- package/bin/aiagent37 +387 -0
- package/bin/aiagent38 +387 -0
- package/bin/aiagent39 +387 -0
- package/bin/aiagent4 +387 -0
- package/bin/aiagent40 +387 -0
- package/bin/aiagent41 +387 -0
- package/bin/aiagent42 +387 -0
- package/bin/aiagent43 +387 -0
- package/bin/aiagent44 +387 -0
- package/bin/aiagent45 +387 -0
- package/bin/aiagent46 +387 -0
- package/bin/aiagent47 +387 -0
- package/bin/aiagent48 +387 -0
- package/bin/aiagent49 +387 -0
- package/bin/aiagent5 +387 -0
- package/bin/aiagent50 +387 -0
- package/bin/aiagent51 +387 -0
- package/bin/aiagent52 +387 -0
- package/bin/aiagent53 +387 -0
- package/bin/aiagent54 +387 -0
- package/bin/aiagent55 +387 -0
- package/bin/aiagent56 +387 -0
- package/bin/aiagent57 +387 -0
- package/bin/aiagent58 +387 -0
- package/bin/aiagent59 +387 -0
- package/bin/aiagent6 +387 -0
- package/bin/aiagent60 +387 -0
- package/bin/aiagent61 +387 -0
- package/bin/aiagent62 +387 -0
- package/bin/aiagent63 +387 -0
- package/bin/aiagent64 +387 -0
- package/bin/aiagent65 +387 -0
- package/bin/aiagent66 +387 -0
- package/bin/aiagent67 +387 -0
- package/bin/aiagent68 +387 -0
- package/bin/aiagent69 +387 -0
- package/bin/aiagent7 +387 -0
- package/bin/aiagent70 +387 -0
- package/bin/aiagent71 +387 -0
- package/bin/aiagent72 +387 -0
- package/bin/aiagent73 +387 -0
- package/bin/aiagent74 +387 -0
- package/bin/aiagent75 +387 -0
- package/bin/aiagent76 +387 -0
- package/bin/aiagent77 +387 -0
- package/bin/aiagent78 +387 -0
- package/bin/aiagent79 +387 -0
- package/bin/aiagent8 +387 -0
- package/bin/aiagent80 +387 -0
- package/bin/aiagent81 +387 -0
- package/bin/aiagent82 +387 -0
- package/bin/aiagent83 +387 -0
- package/bin/aiagent84 +387 -0
- package/bin/aiagent85 +387 -0
- package/bin/aiagent86 +387 -0
- package/bin/aiagent87 +387 -0
- package/bin/aiagent88 +387 -0
- package/bin/aiagent89 +387 -0
- package/bin/aiagent9 +387 -0
- package/bin/aiagent90 +387 -0
- package/bin/aiagent91 +387 -0
- package/bin/aiagent92 +387 -0
- package/bin/aiagent93 +387 -0
- package/bin/aiagent94 +387 -0
- package/bin/aiagent95 +387 -0
- package/bin/aiagent96 +387 -0
- package/bin/aiagent97 +387 -0
- package/bin/aiagent98 +387 -0
- package/bin/aiagent99 +387 -0
- package/config/claude-config-template.json +13 -0
- package/lib/mcp-server/dist/InteractiveLogin.js +27 -0
- package/lib/mcp-server/dist/PortalAuthClient.js +1 -0
- package/lib/mcp-server/dist/TokenManager.js +20 -0
- package/lib/mcp-server/dist/bluelamp-system.js +32 -0
- package/lib/mcp-server/dist/crypto-utils.js +27 -0
- package/lib/mcp-server/dist/database-version.js +33 -0
- package/lib/mcp-server/dist/index.js +62 -0
- package/lib/mcp-server/dist/plugins/base-plugin.js +24 -0
- package/lib/mcp-server/dist/plugins/plugin-manager.js +31 -0
- package/lib/mcp-server/dist/plugins/services/leonardo-plugin.js +89 -0
- package/lib/mcp-server/dist/plugins/services/leonardo-prompt-parser.js +36 -0
- package/lib/mcp-server/dist/plugins/services/portal-api-client.js +22 -0
- package/lib/mcp-server/dist/plugins/services/portal-plugin.js +52 -0
- package/lib/mcp-server/dist/secure-mcp-server.js +78 -0
- package/lib/mcp-server/dist/security/ApiKeyManager.js +24 -0
- package/lib/mcp-server/dist/security/InteractiveLogin.js +32 -0
- package/lib/mcp-server/dist/security/PortalAuthClient.js +1 -0
- package/lib/mcp-server/dist/security/SimpleAuthManager.js +1 -0
- package/lib/mcp-server/dist/security/SlotAuthClient.js +9 -0
- package/lib/mcp-server/dist/security/TokenManager.js +25 -0
- package/lib/mcp-server/package.json +22 -0
- package/package.json +147 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import*as fs from"fs"
|
|
2
|
+
import*as path from"path"
|
|
3
|
+
import*as os from"os"
|
|
4
|
+
import*as crypto from"crypto"
|
|
5
|
+
import*as https from"https"
|
|
6
|
+
import*as http from"http"
|
|
7
|
+
import{URL}from"url"
|
|
8
|
+
export class TokenManager{static async saveToken(token,t={}){try{if(!this.validateTokenFormat(token))throw Error("Portal発行のCLI_形式トークンのみサポートされています")
|
|
9
|
+
const e={token:token,savedAt:Date.now(),userInfo:t,version:"3.0",source:"portal"},r=this.encrypt(JSON.stringify(e)),a=path.dirname(this.TOKEN_FILE_PATH)
|
|
10
|
+
return fs.existsSync(a)||fs.mkdirSync(a,{recursive:!0}),fs.writeFileSync(this.TOKEN_FILE_PATH,r),!0}catch(t){return!1}}static async loadToken(){try{if(!fs.existsSync(this.TOKEN_FILE_PATH))return null
|
|
11
|
+
const t=fs.readFileSync(this.TOKEN_FILE_PATH,"utf8"),e=this.decrypt(t),r=JSON.parse(e)
|
|
12
|
+
return r.token&&r.version?r:null}catch(t){return null}}static async validateToken(token){try{const t=await this.makeRequest({method:"POST",url:this.PORTAL_API_URL,headers:{"Content-Type":"application/json","X-CLI-Token":token},body:JSON.stringify({token:token})})
|
|
13
|
+
return t.success&&t.data?{valid:!0,userInfo:{id:t.data.userId,name:t.data.userName,email:t.data.userEmail,role:t.data.userRole}}:{valid:!1,error:t.message}}catch(t){return{valid:!1,error:t.message}}}static async deleteToken(){try{return!fs.existsSync(this.TOKEN_FILE_PATH)||(fs.unlinkSync(this.TOKEN_FILE_PATH),!0)}catch(t){return!1}}static validateTokenFormat(token){return!(!token||"string"!=typeof token||!/^cli_[a-z0-9]{8}_[a-f0-9]{64}$/.test(token)&&(token.startsWith("cli_")||!token.startsWith("CLI_")||!/^CLI_[a-f0-9]{64}$/.test(token)))}static encrypt(t){const e=crypto.scryptSync(this.ENCRYPTION_KEY,"salt",32),r=crypto.randomBytes(16),a=crypto.createCipheriv("aes-256-cbc",e,r)
|
|
14
|
+
let s=a.update(t,"utf8","hex")
|
|
15
|
+
return s+=a.final("hex"),r.toString("hex")+":"+s}static decrypt(t){const e=crypto.scryptSync(this.ENCRYPTION_KEY,"salt",32),r=t.split(":"),a=Buffer.from(r[0],"hex"),s=r[1],o=crypto.createDecipheriv("aes-256-cbc",e,a)
|
|
16
|
+
let n=o.update(s,"hex","utf8")
|
|
17
|
+
return n+=o.final("utf8"),n}static async makeRequest(t){return new Promise((e,r)=>{const a=new URL(t.url),s={hostname:a.hostname,port:a.port||("https:"===a.protocol?443:80),path:a.pathname+a.search,method:t.method||"GET",headers:t.headers||{},timeout:this.REQUEST_TIMEOUT},o=("https:"===a.protocol?https:http).request(s,t=>{let a=""
|
|
18
|
+
t.on("data",t=>{a+=t}),t.on("end",()=>{try{const t=JSON.parse(a)
|
|
19
|
+
e(t)}catch(t){r(Error("Invalid JSON response: "+a))}})})
|
|
20
|
+
o.on("error",t=>{r(t)}),o.on("timeout",()=>{o.destroy(),r(Error("Request timeout"))}),t.body&&o.write(t.body),o.end()})}}TokenManager.TOKEN_FILE_PATH=path.join(os.homedir(),".bluelamp","portal-token.enc"),TokenManager.PORTAL_API_URL="https://bluelamp-portal-235426778039.asia-northeast1.run.app/api/cli/verify",TokenManager.ENCRYPTION_KEY="bluelamp-portal-token-key-2024",TokenManager.REQUEST_TIMEOUT=1e4
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,s,n){void 0===n&&(n=s)
|
|
3
|
+
var r=Object.getOwnPropertyDescriptor(t,s)
|
|
4
|
+
r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[s]}}),Object.defineProperty(e,n,r)}:function(e,t,s,n){void 0===n&&(n=s),e[n]=t[s]}),__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=[]
|
|
5
|
+
for(var s in e)Object.prototype.hasOwnProperty.call(e,s)&&(t[t.length]=s)
|
|
6
|
+
return t},e(t)}
|
|
7
|
+
return function(t){if(t&&t.__esModule)return t
|
|
8
|
+
var s={}
|
|
9
|
+
if(null!=t)for(var n=e(t),r=0;r<n.length;r++)"default"!==n[r]&&__createBinding(s,t,n[r])
|
|
10
|
+
return __setModuleDefault(s,t),s}}()
|
|
11
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.BlueLampProtectionSystem=void 0
|
|
12
|
+
const index_js_1=require("@modelcontextprotocol/sdk/server/index.js"),stdio_js_1=require("@modelcontextprotocol/sdk/server/stdio.js"),types_js_1=require("@modelcontextprotocol/sdk/types.js"),fs=__importStar(require("fs")),path=__importStar(require("path"))
|
|
13
|
+
class BlueLampProtectionSystem{constructor(){this.server=new index_js_1.Server({name:"bluelamp-protection-system",version:"1.0.0"},{capabilities:{tools:{}}}),this.validTokens=new Set,this.accessLogs=[],this.initializeTokens(),this.setupHandlers()}initializeTokens(){const e=process.env.BLUELAMP_TOKEN
|
|
14
|
+
e&&this.validTokens.add(e),this.validTokens.add("test-token-12345"),this.validTokens.add("bluelamp-secure-token-67890")}setupHandlers(){this.server.setRequestHandler(types_js_1.ListToolsRequestSchema,async()=>({tools:[{name:"authenticate_agent",description:"Authenticate access to protected agent",inputSchema:{type:"object",properties:{token:{type:"string",description:"Authentication token"},agentName:{type:"string",description:"Name of the agent to access"}},required:["token","agentName"]}},{name:"get_protected_prompt",description:"Get protected prompt for authenticated agent",inputSchema:{type:"object",properties:{token:{type:"string",description:"Authentication token"},agentName:{type:"string",description:"Name of the agent"},promptId:{type:"string",description:"ID of the prompt to retrieve"}},required:["token","agentName","promptId"]}},{name:"list_protected_agents",description:"List all protected agents available",inputSchema:{type:"object",properties:{token:{type:"string",description:"Authentication token"}},required:["token"]}}]})),this.server.setRequestHandler(types_js_1.CallToolRequestSchema,async e=>{const{name:t,arguments:s}=e.params
|
|
15
|
+
try{switch(t){case"authenticate_agent":return await this.handleAuthenticateAgent(s)
|
|
16
|
+
case"get_protected_prompt":return await this.handleGetProtectedPrompt(s)
|
|
17
|
+
case"list_protected_agents":return await this.handleListProtectedAgents(s)
|
|
18
|
+
default:throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound,"Unknown tool: "+t)}}catch(e){if(e instanceof types_js_1.McpError)throw e
|
|
19
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError,`Tool execution failed: ${t}: ${e}`)}})}validateToken(token){return this.validTokens.has(token)}logAccess(token,e,t){this.accessLogs.push({timestamp:new Date,token:token.substring(0,8)+"...",agentName:e,success:t}),this.accessLogs.length>100&&(this.accessLogs=this.accessLogs.slice(-100))}async handleAuthenticateAgent(e){const{token:token,agentName:t}=e
|
|
20
|
+
return this.validateToken(token)?(this.logAccess(token,t,!0),{content:[{type:"text",text:JSON.stringify({success:!0,message:"Authentication successful for agent: "+t,sessionId:"session_"+Date.now(),expiresAt:new Date(Date.now()+36e5).toISOString()})}]}):(this.logAccess(token,t,!1),{content:[{type:"text",text:JSON.stringify({success:!1,error:"Invalid authentication token",code:"AUTH_FAILED"})}]})}async handleGetProtectedPrompt(e){const{token:token,agentName:t,promptId:s}=e
|
|
21
|
+
if(!this.validateToken(token))return this.logAccess(token,t,!1),{content:[{type:"text",text:JSON.stringify({success:!1,error:"Invalid authentication token",code:"AUTH_FAILED"})}]}
|
|
22
|
+
try{const e=path.join(process.cwd(),"protected-prompts",t),n=path.join(e,s+".md")
|
|
23
|
+
if(!fs.existsSync(n))return{content:[{type:"text",text:JSON.stringify({success:!1,error:`Prompt not found: ${s} for agent: ${t}`,code:"PROMPT_NOT_FOUND"})}]}
|
|
24
|
+
const r=fs.readFileSync(n,"utf-8")
|
|
25
|
+
return this.logAccess(token,t,!0),{content:[{type:"text",text:JSON.stringify({success:!0,agentName:t,promptId:s,content:r,retrievedAt:(new Date).toISOString()})}]}}catch(e){return this.logAccess(token,t,!1),{content:[{type:"text",text:JSON.stringify({success:!1,error:"Failed to retrieve prompt: "+e.message,code:"RETRIEVAL_ERROR"})}]}}}async handleListProtectedAgents(e){const{token:token}=e
|
|
26
|
+
if(!this.validateToken(token))return{content:[{type:"text",text:JSON.stringify({success:!1,error:"Invalid authentication token",code:"AUTH_FAILED"})}]}
|
|
27
|
+
try{const e=path.join(process.cwd(),"protected-prompts")
|
|
28
|
+
if(!fs.existsSync(e))return{content:[{type:"text",text:JSON.stringify({success:!0,agents:[],message:"No protected agents directory found"})}]}
|
|
29
|
+
const t=fs.readdirSync(e,{withFileTypes:!0}).filter(e=>e.isDirectory()).map(t=>{const s=path.join(e,t.name),n=fs.readdirSync(s).filter(e=>e.endsWith(".md")).map(e=>e.replace(".md",""))
|
|
30
|
+
return{name:t.name,promptCount:n.length,prompts:n}})
|
|
31
|
+
return{content:[{type:"text",text:JSON.stringify({success:!0,agents:t,totalAgents:t.length,accessLogs:this.accessLogs.slice(-10)})}]}}catch(e){return{content:[{type:"text",text:JSON.stringify({success:!1,error:"Failed to list agents: "+e.message,code:"LIST_ERROR"})}]}}}async run(){const e=new stdio_js_1.StdioServerTransport
|
|
32
|
+
await this.server.connect(e)}}exports.BlueLampProtectionSystem=BlueLampProtectionSystem,require.main===module&&new BlueLampProtectionSystem
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
var __createBinding=this&&this.__createBinding||(Object.create?function(t,e,r,i){void 0===i&&(i=r)
|
|
3
|
+
var s=Object.getOwnPropertyDescriptor(e,r)
|
|
4
|
+
s&&!("get"in s?!e.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return e[r]}}),Object.defineProperty(t,i,s)}:function(t,e,r,i){void 0===i&&(i=r),t[i]=e[r]}),__setModuleDefault=this&&this.__setModuleDefault||(Object.create?function(t,e){Object.defineProperty(t,"default",{enumerable:!0,value:e})}:function(t,e){t.default=e}),__importStar=this&&this.__importStar||function(){var t=function(e){return t=Object.getOwnPropertyNames||function(t){var e=[]
|
|
5
|
+
for(var r in t)Object.prototype.hasOwnProperty.call(t,r)&&(e[e.length]=r)
|
|
6
|
+
return e},t(e)}
|
|
7
|
+
return function(e){if(e&&e.__esModule)return e
|
|
8
|
+
var r={}
|
|
9
|
+
if(null!=e)for(var i=t(e),s=0;s<i.length;s++)"default"!==i[s]&&__createBinding(r,e,i[s])
|
|
10
|
+
return __setModuleDefault(r,e),r}}()
|
|
11
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.CryptoUtils=void 0
|
|
12
|
+
const crypto=__importStar(require("crypto")),fs=__importStar(require("fs")),path=__importStar(require("path"))
|
|
13
|
+
class CryptoUtils{static deriveKey(t,e){return crypto.pbkdf2Sync(t,e,this.iterations,this.keyLength,"sha256")}static encryptFile(t,e,r){const i=fs.readFileSync(t,"utf-8"),s=crypto.randomBytes(this.saltLength),n=crypto.randomBytes(this.ivLength),c=this.deriveKey(r,s),o=crypto.createCipheriv(this.algorithm,c,n),a=Buffer.concat([o.update(i,"utf8"),o.final()]),l=o.getAuthTag(),p=Buffer.concat([s,n,l,a])
|
|
14
|
+
fs.writeFileSync(e,p)}static decryptFile(t,e){const r=fs.readFileSync(t)
|
|
15
|
+
let i=0
|
|
16
|
+
const s=r.slice(i,i+this.saltLength)
|
|
17
|
+
i+=this.saltLength
|
|
18
|
+
const n=r.slice(i,i+this.ivLength)
|
|
19
|
+
i+=this.ivLength
|
|
20
|
+
const c=r.slice(i,i+this.tagLength)
|
|
21
|
+
i+=this.tagLength
|
|
22
|
+
const o=r.slice(i),a=this.deriveKey(e,s),l=crypto.createDecipheriv(this.algorithm,a,n)
|
|
23
|
+
return l.setAuthTag(c),Buffer.concat([l.update(o),l.final()]).toString("utf-8")}static encryptString(t,e,r){const i=crypto.randomBytes(this.saltLength),s=crypto.randomBytes(this.ivLength),n=this.deriveKey(r,i),c=crypto.createCipheriv(this.algorithm,n,s),o=Buffer.concat([c.update(t,"utf8"),c.final()]),a=c.getAuthTag(),l=Buffer.concat([i,s,a,o])
|
|
24
|
+
fs.writeFileSync(e,l)}static async encryptPerformerDemo(){const t="/Users/tatsuya/Desktop/マルチエージェントウェブ/mcp-sample-server/secure-prompts",e=path.join(t,"performer-protected.enc")
|
|
25
|
+
fs.existsSync(t)||fs.mkdirSync(t,{recursive:!0})
|
|
26
|
+
const r=process.env.BLUELAMP_ENCRYPTION_KEY||"demo-encryption-password-2024"
|
|
27
|
+
try{this.encryptFile("/Users/tatsuya/Desktop/マルチエージェントウェブ/.claude/agents/core/パフォーマー.md",e,r),fs.statSync(e),fs.readFileSync(e).slice(0,100),this.decryptFile(e,r)}catch(t){throw t}}}exports.CryptoUtils=CryptoUtils,CryptoUtils.algorithm="aes-256-gcm",CryptoUtils.saltLength=32,CryptoUtils.tagLength=16,CryptoUtils.ivLength=16,CryptoUtils.iterations=1e5,CryptoUtils.keyLength=32
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict"
|
|
3
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.PromptDatabase=exports.DatabaseMCPServer=void 0
|
|
4
|
+
const index_js_1=require("@modelcontextprotocol/sdk/server/index.js"),stdio_js_1=require("@modelcontextprotocol/sdk/server/stdio.js"),types_js_1=require("@modelcontextprotocol/sdk/types.js")
|
|
5
|
+
function debugLog(e,t){}class PromptDatabase{constructor(){}initializeDatabase(){debugLog("データベーススキーマ初期化",{schema:"\n CREATE TABLE IF NOT EXISTS prompts (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n uri TEXT UNIQUE NOT NULL,\n title TEXT NOT NULL,\n content TEXT NOT NULL,\n category TEXT DEFAULT 'general',\n tags TEXT DEFAULT '',\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\n );\n\n CREATE INDEX IF NOT EXISTS idx_prompts_category ON prompts(category);\n CREATE INDEX IF NOT EXISTS idx_prompts_uri ON prompts(uri);\n CREATE VIRTUAL TABLE IF NOT EXISTS prompts_fts USING fts5(\n title, content, tags, content='prompts', content_rowid='id'\n );\n "})}async searchPrompts(e,t,r=10){debugLog("プロンプト検索",{query:e,category:t,limit:r})
|
|
6
|
+
let s=[{id:1,uri:"prompt://sample/greeting",title:"挨拶プロンプト",content:"こんにちは!私はAIアシスタントです。",category:"general",tags:"挨拶,基本",created_at:(new Date).toISOString(),updated_at:(new Date).toISOString()},{id:2,uri:"prompt://sample/analysis",title:"分析プロンプト",content:"データを詳細に分析し、洞察を提供します。",category:"analysis",tags:"分析,データ",created_at:(new Date).toISOString(),updated_at:(new Date).toISOString()}]
|
|
7
|
+
if(t&&(s=s.filter(e=>e.category===t)),e){const t=e.toLowerCase()
|
|
8
|
+
s=s.filter(e=>e.title.toLowerCase().includes(t)||e.content.toLowerCase().includes(t)||e.tags.toLowerCase().includes(t))}return s.slice(0,r)}async getPromptByUri(e){return debugLog("URI検索",{uri:e}),(await this.searchPrompts()).find(t=>t.uri===e)||null}async addPrompt(e){return debugLog("プロンプト追加",e),{id:Date.now(),uri:e.uri,title:e.title,content:e.content,category:e.category||"general",tags:e.tags||"",created_at:(new Date).toISOString(),updated_at:(new Date).toISOString()}}async getCategories(){return debugLog("カテゴリ一覧取得"),["general","analysis","creative","technical"]}}exports.PromptDatabase=PromptDatabase
|
|
9
|
+
class DatabaseMCPServer{constructor(){this.server=new index_js_1.Server({name:"database-mcp-server",version:"1.0.0"},{capabilities:{resources:{},tools:{}}}),this.database=new PromptDatabase,this.setupHandlers()}setupHandlers(){this.server.setRequestHandler(types_js_1.ListResourcesRequestSchema,async()=>{debugLog("リソース一覧要求")
|
|
10
|
+
try{const e=(await this.database.searchPrompts()).map(e=>({uri:e.uri,name:e.title,description:`${e.category} - ${e.content.substring(0,100)}...`,mimeType:"text/plain"}))
|
|
11
|
+
return debugLog("リソース一覧応答",{count:e.length}),{resources:e}}catch(e){return debugLog("リソース一覧エラー",{error:e.message}),{resources:[]}}}),this.server.setRequestHandler(types_js_1.ReadResourceRequestSchema,async e=>{const{uri:t}=e.params
|
|
12
|
+
debugLog("リソース読み取り要求",{uri:t})
|
|
13
|
+
try{const e=await this.database.getPromptByUri(t)
|
|
14
|
+
if(!e)throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest,"プロンプトが見つかりません: "+t)
|
|
15
|
+
return debugLog("リソース読み取り成功",{uri:t,title:e.title}),{contents:[{uri:e.uri,mimeType:"text/plain",text:e.content}]}}catch(e){if(debugLog("リソース読み取りエラー",{uri:t,error:e.message}),e instanceof types_js_1.McpError)throw e
|
|
16
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError,"リソース読み取りエラー: "+e.message)}}),this.server.setRequestHandler(types_js_1.ListToolsRequestSchema,async()=>(debugLog("ツール一覧要求"),{tools:[{name:"search_prompts",description:"データベースからプロンプトを検索します",inputSchema:{type:"object",properties:{query:{type:"string",description:"検索クエリ(タイトル、内容、タグを対象)"},category:{type:"string",description:"カテゴリでフィルタ"},limit:{type:"number",description:"取得件数の上限",default:10}},required:[]}},{name:"add_prompt",description:"データベースに新しいプロンプトを追加します",inputSchema:{type:"object",properties:{uri:{type:"string",description:"プロンプトのURI"},title:{type:"string",description:"プロンプトのタイトル"},content:{type:"string",description:"プロンプトの内容"},category:{type:"string",description:"カテゴリ",default:"general"},tags:{type:"string",description:"タグ(カンマ区切り)"}},required:["uri","title","content"]}},{name:"get_categories",description:"利用可能なカテゴリ一覧を取得します",inputSchema:{type:"object",properties:{},required:[]}}]})),this.server.setRequestHandler(types_js_1.CallToolRequestSchema,async e=>{const{name:name,arguments:t}=e.params
|
|
17
|
+
debugLog("ツール実行要求: "+name,t)
|
|
18
|
+
try{switch(name){case"search_prompts":return await this.handleSearchPrompts(t||{})
|
|
19
|
+
case"add_prompt":return await this.handleAddPrompt(t)
|
|
20
|
+
case"get_categories":return await this.handleGetCategories()
|
|
21
|
+
default:throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound,"不明なツール: "+name)}}catch(e){if(debugLog("ツール実行エラー",{name:name,error:e.message}),e instanceof types_js_1.McpError)throw e
|
|
22
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError,"ツール実行エラー: "+e.message)}})}async handleSearchPrompts(e){const{query:t,category:r,limit:s=10}=e
|
|
23
|
+
debugLog("プロンプト検索実行",{query:t,category:r,limit:s})
|
|
24
|
+
try{const e=await this.database.searchPrompts(t,r,s),a={type:"text",text:`検索結果: ${e.length}件\n\n`+e.map(e=>`【${e.title}】\nURI: ${e.uri}\nカテゴリ: ${e.category}\n内容: ${e.content.substring(0,100)}...\nタグ: ${e.tags}\n`).join("\n")}
|
|
25
|
+
return debugLog("プロンプト検索完了",{count:e.length}),{content:[a]}}catch(e){throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError,"検索エラー: "+e.message)}}async handleAddPrompt(e){const{uri:t,title:r,content:s,category:a,tags:o}=e
|
|
26
|
+
if(!t||!r||!s)throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams,"uri, title, contentは必須です")
|
|
27
|
+
debugLog("プロンプト追加実行",{uri:t,title:r,category:a})
|
|
28
|
+
try{const e=await this.database.addPrompt({uri:t,title:r,content:s,category:a,tags:o}),n={type:"text",text:`プロンプトを追加しました:\n\n【${e.title}】\nURI: ${e.uri}\nカテゴリ: ${e.category}\nID: ${e.id}\n作成日時: `+e.created_at}
|
|
29
|
+
return debugLog("プロンプト追加完了",{id:e.id,uri:e.uri}),{content:[n]}}catch(e){throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError,"追加エラー: "+e.message)}}async handleGetCategories(){debugLog("カテゴリ一覧取得実行")
|
|
30
|
+
try{const e=await this.database.getCategories(),t={type:"text",text:"利用可能なカテゴリ:\n\n"+e.map(e=>"- "+e).join("\n")}
|
|
31
|
+
return debugLog("カテゴリ一覧取得完了",{count:e.length}),{content:[t]}}catch(e){throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError,"カテゴリ取得エラー: "+e.message)}}async run(){debugLog("データベース版MCPサーバー開始")
|
|
32
|
+
const e=new stdio_js_1.StdioServerTransport
|
|
33
|
+
await this.server.connect(e),debugLog("データベース版MCPサーバー接続完了")}}exports.DatabaseMCPServer=DatabaseMCPServer,require.main===module&&(new DatabaseMCPServer).run().catch(e=>{process.exit(1)})
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict"
|
|
3
|
+
var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,r,n){void 0===n&&(n=r)
|
|
4
|
+
var s=Object.getOwnPropertyDescriptor(t,r)
|
|
5
|
+
s&&!("get"in s?!t.__esModule:s.writable||s.configurable)||(s={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,n,s)}: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=[]
|
|
6
|
+
for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[t.length]=r)
|
|
7
|
+
return t},e(t)}
|
|
8
|
+
return function(t){if(t&&t.__esModule)return t
|
|
9
|
+
var r={}
|
|
10
|
+
if(null!=t)for(var n=e(t),s=0;s<n.length;s++)"default"!==n[s]&&__createBinding(r,t,n[s])
|
|
11
|
+
return __setModuleDefault(r,t),r}}()
|
|
12
|
+
Object.defineProperty(exports,"__esModule",{value:!0})
|
|
13
|
+
const index_js_1=require("@modelcontextprotocol/sdk/server/index.js"),stdio_js_1=require("@modelcontextprotocol/sdk/server/stdio.js"),types_js_1=require("@modelcontextprotocol/sdk/types.js"),plugin_manager_js_1=require("./plugins/plugin-manager.js")
|
|
14
|
+
function debugLog(e,t){}class SampleMCPServer{constructor(){this.server=new index_js_1.Server({name:"bluelamp-mcp-server",version:"1.2.0"},{capabilities:{tools:{},resources:{}}}),this.setupHandlers()}setupHandlers(){this.server.setRequestHandler(types_js_1.ListResourcesRequestSchema,async()=>(debugLog("リソース一覧要求"),{resources:[]})),this.server.setRequestHandler(types_js_1.ReadResourceRequestSchema,async e=>{const{uri:t}=e.params
|
|
15
|
+
throw debugLog("リソース読み取り要求",{uri:t}),new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest,"リソースが見つかりません: "+t)}),this.server.setRequestHandler(types_js_1.ListToolsRequestSchema,async()=>{debugLog("ツール一覧要求")
|
|
16
|
+
const e=[{name:"get_current_time",description:"現在の日時を取得します",inputSchema:{type:"object",properties:{timezone:{type:"string",description:"タイムゾーン (例: Asia/Tokyo)",default:"Asia/Tokyo"}},required:[]}},{name:"calculate",description:"数学的な計算を実行します",inputSchema:{type:"object",properties:{expression:{type:"string",description:"計算式 (例: 2 + 3 * 4)"}},required:["expression"]}},{name:"echo",description:"メッセージをそのまま返します",inputSchema:{type:"object",properties:{message:{type:"string",description:"返すメッセージ"}},required:["message"]}},{name:"inject_knowledge",description:"Portal APIから専門知識を注入します",inputSchema:{type:"object",properties:{keyword:{type:"string",description:"注入する知識のキーワード",enum:["オーケストレーター","要件定義質問テンプレート","要件定義","デザイナー","デザイン設計","UIUX","本番環境準備ガイドテンプレート","データ設計","デプロイ","GitHub","実装計画","プロトタイプ","検証","バックエンド","総合テスト","テスター","フロントエンド","認証追加テンプレート","ブルーランプ","ディレクトリ構造"]},context:{type:"string",description:"追加のコンテキスト情報"},token:{type:"string",description:"Portal APIトークン(省略時は自動取得)",default:"auto"}},required:["keyword"]}}]
|
|
17
|
+
let t=[]
|
|
18
|
+
try{plugin_manager_js_1.pluginManager&&(t=plugin_manager_js_1.pluginManager.getAvailableTools(),debugLog(`プラグインツール取得完了: ${t.length}個`))}catch(e){debugLog("プラグインツール取得エラー",e)}const r=[...e,...t]
|
|
19
|
+
return debugLog(`全ツール数: ${r.length} (基本: ${e.length}, プラグイン: ${t.length})`),{tools:r}}),this.server.setRequestHandler(types_js_1.CallToolRequestSchema,async e=>{const{name:name,arguments:t}=e.params
|
|
20
|
+
debugLog("ツール実行要求: "+name,t)
|
|
21
|
+
try{switch(name){case"get_current_time":return await this.handleGetCurrentTime(t||{})
|
|
22
|
+
case"calculate":return await this.handleCalculate(t||{})
|
|
23
|
+
case"echo":return await this.handleEcho(t||{})
|
|
24
|
+
case"inject_knowledge":return await this.handleInjectKnowledge(t||{})}const e=await this.handlePluginTool(name,t)
|
|
25
|
+
if(e)return e
|
|
26
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.MethodNotFound,"不明なツール: "+name)}catch(e){if(debugLog("ツール実行エラー",{name:name,error:e.message}),e instanceof types_js_1.McpError)throw e
|
|
27
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError,"ツール実行中にエラーが発生しました: "+e.message)}})}async handleGetCurrentTime(e){const{timezone:t="Asia/Tokyo"}=e
|
|
28
|
+
debugLog("現在時刻取得",{timezone:t})
|
|
29
|
+
try{const e=(new Date).toLocaleString("ja-JP",{timeZone:t,year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"}),r={type:"text",text:`現在の日時: ${e} (${t})`}
|
|
30
|
+
return debugLog("現在時刻取得完了",{timeString:e,timezone:t}),{content:[r]}}catch(e){throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError,"時刻取得エラー: "+e.message)}}async handleCalculate(e){const{expression:t}=e
|
|
31
|
+
if(!t)throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams,"計算式が指定されていません")
|
|
32
|
+
debugLog("計算実行",{expression:t})
|
|
33
|
+
try{const e=t.replace(/[^0-9+\-*/().\s]/g,"")
|
|
34
|
+
if(e!==t)throw Error("無効な文字が含まれています")
|
|
35
|
+
const r=Function(`"use strict"; return (${e})`)(),n={type:"text",text:`計算結果: ${t} = ${r}`}
|
|
36
|
+
return debugLog("計算完了",{expression:t,result:r}),{content:[n]}}catch(e){throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams,"計算エラー: "+e.message)}}async handleEcho(e){const{message:t}=e
|
|
37
|
+
if(!t)throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams,"メッセージが指定されていません")
|
|
38
|
+
debugLog("エコー実行",{message:t})
|
|
39
|
+
const r={type:"text",text:"エコー: "+t}
|
|
40
|
+
return debugLog("エコー完了",{message:t}),{content:[r]}}async handleInjectKnowledge(e){const{keyword:keyword,token:token="auto"}=e
|
|
41
|
+
if(!keyword)throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams,"キーワードが指定されていません")
|
|
42
|
+
debugLog("Knowledge Injection実行",{keyword:keyword,token:token}),Date.now()
|
|
43
|
+
try{const{spawn:e}=await Promise.resolve().then(()=>__importStar(require("child_process"))),t="/Users/tatsuya/Desktop/bluelamp-test/knowledge-injection/hooks/inject-encrypted.sh",r={...process.env}
|
|
44
|
+
"auto"!==token&&(r.PORTAL_TOKEN=token),r.KNOWLEDGE_KEYWORD=keyword,debugLog("スクリプト実行開始",{scriptPath:t,keyword:keyword})
|
|
45
|
+
const n=e("bash",[t],{env:r,stdio:["pipe","pipe","pipe"]})
|
|
46
|
+
let s="",o=""
|
|
47
|
+
n.stdout.on("data",e=>{s+=e.toString()}),n.stderr.on("data",e=>{o+=e.toString()})
|
|
48
|
+
const a=await new Promise(e=>{n.on("close",e)})
|
|
49
|
+
if(debugLog("スクリプト実行完了",{exitCode:a,stdout:s.substring(0,200),stderr:o.substring(0,200)}),Date.now(),0===a)return{content:[{type:"text",text:`Knowledge Injection成功: "${keyword}" の知識が注入されました。\n\n実行結果:\n${s}\n\n統計記録: ⚠️ スキップ`}]}
|
|
50
|
+
throw Error(`スクリプト実行失敗 (exit code: ${a})\nstderr: ${o}`)}catch(e){throw debugLog("Knowledge Injectionエラー",{keyword:keyword,error:e.message}),new types_js_1.McpError(types_js_1.ErrorCode.InternalError,"Knowledge Injection実行エラー: "+e.message)}}async handlePluginTool(e,t){try{if(!plugin_manager_js_1.pluginManager)return null
|
|
51
|
+
if(!plugin_manager_js_1.pluginManager.getAvailableTools().find(t=>t.name===e))return null
|
|
52
|
+
debugLog("プラグインツール実行: "+e,t)
|
|
53
|
+
const r={userId:"current_user",service:"leonardo",apiKey:process.env.LEONARDO_API_KEY,settings:{}}
|
|
54
|
+
let n="leonardo"
|
|
55
|
+
e.startsWith("leonardo_")?n="leonardo":e.startsWith("notion_")?n="notion":e.startsWith("slack_")&&(n="slack")
|
|
56
|
+
const s=await plugin_manager_js_1.pluginManager.executePlugin(n,e,t,r)
|
|
57
|
+
if(s.success)return debugLog("プラグインツール実行成功: "+e),{content:s.content,_meta:s.metadata}
|
|
58
|
+
throw debugLog("プラグインツール実行失敗: "+e,s.error),new types_js_1.McpError(types_js_1.ErrorCode.InternalError,"プラグインツール実行エラー: "+s.error)}catch(t){if(debugLog("プラグインツール処理エラー: "+e,t),t instanceof types_js_1.McpError)throw t
|
|
59
|
+
throw new types_js_1.McpError(types_js_1.ErrorCode.InternalError,"プラグイン処理中にエラーが発生しました: "+t.message)}}async run(){debugLog("MCPサーバー開始")
|
|
60
|
+
try{await plugin_manager_js_1.pluginManager.initialize(),debugLog("プラグインマネージャー初期化完了")}catch(e){debugLog("プラグインマネージャー初期化エラー",e)}const e=new stdio_js_1.StdioServerTransport
|
|
61
|
+
await this.server.connect(e),debugLog("MCPサーバー接続完了")}}const server=new SampleMCPServer
|
|
62
|
+
server.run().catch(e=>{process.exit(1)})
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,i,s){void 0===s&&(s=i)
|
|
3
|
+
var n=Object.getOwnPropertyDescriptor(t,i)
|
|
4
|
+
n&&!("get"in n?!t.__esModule:n.writable||n.configurable)||(n={enumerable:!0,get:function(){return t[i]}}),Object.defineProperty(e,s,n)}:function(e,t,i,s){void 0===s&&(s=i),e[s]=t[i]}),__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=[]
|
|
5
|
+
for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[t.length]=i)
|
|
6
|
+
return t},e(t)}
|
|
7
|
+
return function(t){if(t&&t.__esModule)return t
|
|
8
|
+
var i={}
|
|
9
|
+
if(null!=t)for(var s=e(t),n=0;n<s.length;n++)"default"!==s[n]&&__createBinding(i,t,s[n])
|
|
10
|
+
return __setModuleDefault(i,t),i}}()
|
|
11
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.PluginLoader=exports.BasePlugin=void 0
|
|
12
|
+
const zod_1=require("zod")
|
|
13
|
+
class BasePlugin{constructor(){this._initialized=!1,this._credentials=new Map}get isInitialized(){return this._initialized}markInitialized(){this._initialized=!0}validateArgs(e,t){try{return t.parse(e)}catch(e){if(e instanceof zod_1.z.ZodError){const t=e.issues.map(e=>`${e.path.join(".")}: ${e.message}`).join(", ")
|
|
14
|
+
throw Error("引数の検証に失敗しました: "+t)}throw e}}async getCredentials(e){const t=`${e}-${this.manifest.id}`
|
|
15
|
+
if(this._credentials.has(t))return this._credentials.get(t)
|
|
16
|
+
const i=await this.fetchCredentialsFromPortal(e)
|
|
17
|
+
return this._credentials.set(t,i),i}async fetchCredentialsFromPortal(e){const t=process.env[this.manifest.id.toUpperCase()+"_API_KEY"]
|
|
18
|
+
return{userId:e,service:this.manifest.id,apiKey:t,settings:{}}}async recordUsage(e,t,i,s,n){const a={userId:t,pluginId:this.manifest.id,toolName:e,executionTime:s,success:i,timestamp:new Date,metadata:n}
|
|
19
|
+
await this.sendStatsToPortal(a)}async sendStatsToPortal(e){}handleError(e,t){return{success:!1,error:`${t}: ${e?.message||e+""}`,metadata:{errorCode:e?.code||"UNKNOWN_ERROR",pluginId:this.manifest.id,timestamp:(new Date).toISOString()}}}createSuccessResponse(e,t){return{success:!0,content:e,metadata:{pluginId:this.manifest.id,timestamp:(new Date).toISOString(),...t}}}supportsTool(e){return this.manifest.tools.some(t=>t.name===e)}async healthCheck(){try{return this.isInitialized?(await this.performHealthCheck(),{status:"healthy",details:{initialized:!0,toolCount:this.manifest.tools.length,version:this.manifest.version}}):{status:"unhealthy",message:"プラグインが初期化されていません"}}catch(e){return{status:"unhealthy",message:"ヘルスチェックに失敗しました: "+e,details:{error:e+""}}}}async performHealthCheck(){}}exports.BasePlugin=BasePlugin
|
|
20
|
+
class PluginLoader{constructor(){this.loadedPlugins=new Map}static getInstance(){return PluginLoader.instance||(PluginLoader.instance=new PluginLoader),PluginLoader.instance}async loadPlugin(e){try{if(this.loadedPlugins.has(e))return this.loadedPlugins.get(e)
|
|
21
|
+
const t=await Promise.resolve(`./services/${e}-plugin.js`).then(e=>__importStar(require(e))),i=new(t.default||t[Object.keys(t)[0]])
|
|
22
|
+
return await i.initialize(),this.loadedPlugins.set(e,i),i}catch(e){return null}}async unloadPlugin(e){const t=this.loadedPlugins.get(e)
|
|
23
|
+
t&&(await t.shutdown(),this.loadedPlugins.delete(e))}async unloadAllPlugins(){const e=Array.from(this.loadedPlugins.keys()).map(e=>this.unloadPlugin(e))
|
|
24
|
+
await Promise.all(e)}getLoadedPlugins(){return Array.from(this.loadedPlugins.keys())}}exports.PluginLoader=PluginLoader
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.pluginManager=exports.PluginManager=void 0
|
|
3
|
+
const base_plugin_js_1=require("./base-plugin.js")
|
|
4
|
+
class PluginManager{constructor(e={}){this.pluginCache=new Map,this.pluginStats=new Map,this.executionQueue=[],this.isProcessingQueue=!1,this.initialized=!1,this.manifestRegistry=new Map,this.config={maxLoadedPlugins:100,pluginTimeoutMs:3e5,maxConcurrentExecution:50,healthCheckIntervalMs:6e4,portalBaseUrl:process.env.PORTAL_URL||"http://localhost:8080",...e},this.pluginLoader=base_plugin_js_1.PluginLoader.getInstance()}async initialize(){this.initialized||(await this.loadPluginManifests(),this.startHealthCheckTimer(),this.startExecutionQueueProcessor(),this.initialized=!0)}async loadPluginManifests(){try{const e=await this.getBuiltinManifests()
|
|
5
|
+
for(const t of e)this.manifestRegistry.set(t.id,t),this.pluginStats.set(t.id,{pluginId:t.id,loadTime:0,totalExecutions:0,successfulExecutions:0,failedExecutions:0,averageExecutionTime:0,lastExecuted:new Date(0),healthStatus:"healthy"})}catch(e){throw e}}async getBuiltinManifests(){return[{id:"leonardo",name:"Leonardo AI",version:"1.0.0",category:"AI",description:"Leonardo AIによる高品質な画像生成",authType:"api_key",loadPriority:"high",tools:[{name:"leonardo_generate",description:"Leonardo AIで画像を生成します",inputSchema:{type:"object",properties:{prompt:{type:"string",description:"画像生成のプロンプト"},width:{type:"number",description:"画像の幅(512-2048)",default:1024},height:{type:"number",description:"画像の高さ(512-2048)",default:1024},num_images:{type:"number",description:"生成する画像数(1-8)",default:1},modelId:{type:"string",description:"Leonardo AIのモデルID(省略時はデフォルト)"},negativePrompt:{type:"string",description:"ネガティブプロンプト"},photoReal:{type:"boolean",description:"フォトリアル画像の生成",default:!1},alchemy:{type:"boolean",description:"Alchemy v2の使用",default:!0},guidance_scale:{type:"number",description:"ガイダンススケール(1-30)",default:7},outputPath:{type:"string",description:"保存先ディレクトリ(省略時: ./outputs)"}},required:["prompt"]},outputExample:{success:!0,content:[{type:"text",text:"✅ Leonardo AIで1枚の画像を生成しました\\n📁 保存先: ./outputs/leonardo_20250830_001.png"}]}}]}]}async executePlugin(e,t,i,s){return this.manifestRegistry.has(e)?new Promise((n,a)=>{const o={id:this.generateTaskId(),pluginId:e,toolName:t,args:i,userCredentials:s,resolve:n,reject:a,createdAt:new Date}
|
|
6
|
+
this.executionQueue.push(o),this.isProcessingQueue||setImmediate(()=>this.processExecutionQueue())}):{success:!1,error:`プラグイン '${e}' が見つかりません`}}async processExecutionQueue(){if(!this.isProcessingQueue){this.isProcessingQueue=!0
|
|
7
|
+
try{for(;this.executionQueue.length>0;){const e=Math.min(this.config.maxConcurrentExecution,this.executionQueue.length),t=this.executionQueue.splice(0,e).map(e=>this.executeTask(e))
|
|
8
|
+
await Promise.allSettled(t)}}finally{this.isProcessingQueue=!1}}}async executeTask(e){const t=Date.now()
|
|
9
|
+
let i
|
|
10
|
+
try{const s=await this.getOrLoadPlugin(e.pluginId)
|
|
11
|
+
if(!s)throw Error(`プラグイン '${e.pluginId}' の読み込みに失敗しました`)
|
|
12
|
+
i=await s.executeTool(e.toolName,e.args,e.userCredentials),this.recordExecution(e.pluginId,!0,Date.now()-t),e.resolve(i)}catch(s){this.recordExecution(e.pluginId,!1,Date.now()-t),i={success:!1,error:"プラグイン実行エラー: "+s,metadata:{pluginId:e.pluginId,toolName:e.toolName,error:s+""}},e.resolve(i)}}async getOrLoadPlugin(e){const t=this.pluginCache.get(e)
|
|
13
|
+
if(t)return t.lastUsed=new Date,t.usageCount++,t.plugin
|
|
14
|
+
this.pluginCache.size>=this.config.maxLoadedPlugins&&await this.evictLeastUsedPlugin()
|
|
15
|
+
const i=Date.now(),s=await this.pluginLoader.loadPlugin(e)
|
|
16
|
+
if(s){this.pluginCache.set(e,{plugin:s,lastUsed:new Date,usageCount:1})
|
|
17
|
+
const t=this.pluginStats.get(e)
|
|
18
|
+
t&&(t.loadTime=Date.now()-i)}return s}async evictLeastUsedPlugin(){let e=null,t=Date.now()
|
|
19
|
+
for(const[i,s]of this.pluginCache)s.lastUsed.getTime()<t&&(t=s.lastUsed.getTime(),e=i)
|
|
20
|
+
if(e){const t=this.pluginCache.get(e)
|
|
21
|
+
t&&(await t.plugin.shutdown(),this.pluginCache.delete(e))}}recordExecution(e,t,i){const s=this.pluginStats.get(e)
|
|
22
|
+
s&&(s.totalExecutions++,s.lastExecuted=new Date,t?s.successfulExecutions++:s.failedExecutions++,s.averageExecutionTime=(s.averageExecutionTime*(s.totalExecutions-1)+i)/s.totalExecutions)}startHealthCheckTimer(){this.healthCheckTimer=setInterval(async()=>{await this.performHealthChecks()},this.config.healthCheckIntervalMs)}startExecutionQueueProcessor(){setInterval(()=>{this.executionQueue.length>0&&!this.isProcessingQueue&&this.processExecutionQueue()},100)}async performHealthChecks(){const e=[]
|
|
23
|
+
for(const[t,i]of this.pluginCache)e.push(this.checkPluginHealth(t,i.plugin))
|
|
24
|
+
await Promise.allSettled(e)}async checkPluginHealth(e,t){try{const i=await t.healthCheck(),s=this.pluginStats.get(e)
|
|
25
|
+
s&&(s.healthStatus=i.status),i.status}catch(t){const i=this.pluginStats.get(e)
|
|
26
|
+
i&&(i.healthStatus="unhealthy")}}getAvailableTools(){const e=[]
|
|
27
|
+
for(const t of this.manifestRegistry.values())for(const i of t.tools)e.push({name:i.name,description:i.description,inputSchema:i.inputSchema})
|
|
28
|
+
return e}getPluginStats(){return Array.from(this.pluginStats.values())}async shutdown(){this.healthCheckTimer&&clearInterval(this.healthCheckTimer)
|
|
29
|
+
const e=[]
|
|
30
|
+
for(const[t,i]of this.pluginCache)e.push(i.plugin.shutdown())
|
|
31
|
+
await Promise.allSettled(e),this.pluginCache.clear()}generateTaskId(){return`task_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}getPluginManifest(e){return this.manifestRegistry.get(e)}getRegisteredPlugins(){return Array.from(this.manifestRegistry.keys())}}exports.PluginManager=PluginManager,exports.pluginManager=new PluginManager
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,o,a){void 0===a&&(a=o)
|
|
3
|
+
var r=Object.getOwnPropertyDescriptor(t,o)
|
|
4
|
+
r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[o]}}),Object.defineProperty(e,a,r)}:function(e,t,o,a){void 0===a&&(a=o),e[a]=t[o]}),__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=[]
|
|
5
|
+
for(var o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[t.length]=o)
|
|
6
|
+
return t},e(t)}
|
|
7
|
+
return function(t){if(t&&t.__esModule)return t
|
|
8
|
+
var o={}
|
|
9
|
+
if(null!=t)for(var a=e(t),r=0;r<a.length;r++)"default"!==a[r]&&__createBinding(o,t,a[r])
|
|
10
|
+
return __setModuleDefault(o,t),o}}(),__importDefault=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}}
|
|
11
|
+
Object.defineProperty(exports,"__esModule",{value:!0})
|
|
12
|
+
const sdk_1=require("@leonardo-ai/sdk"),zod_1=require("zod"),fs=__importStar(require("fs/promises")),path=__importStar(require("path")),node_fetch_1=__importDefault(require("node-fetch")),sharp_1=__importDefault(require("sharp")),base_plugin_js_1=require("../base-plugin.js"),ApiKeyManager_js_1=require("../../security/ApiKeyManager.js"),leonardo_prompt_parser_js_1=require("./leonardo-prompt-parser.js"),LeonardoAnimateSchema=zod_1.z.object({folderPath:zod_1.z.string().default("./outputs").describe("画像が保存されているフォルダパス"),pattern:zod_1.z.string().default("*.png").describe("対象ファイルのパターン(例: *.png, leonardo_*.png)"),motionStrength:zod_1.z.number().int().min(1).max(10).default(5).describe("動きの強さ(1:穏やか~10:激しい)"),fileLimit:zod_1.z.number().int().min(1).max(10).optional().describe("処理する画像の最大数"),sortBy:zod_1.z.enum(["newest","oldest","name"]).default("newest").describe("ファイルの並び順"),outputPath:zod_1.z.string().default("./outputs/videos").describe("動画の保存先"),isPublic:zod_1.z.boolean().default(!1).describe("生成した動画を公開するか")}),LeonardoGenerateSchema=zod_1.z.object({prompt:zod_1.z.string().min(1,"プロンプトは必須です"),width:zod_1.z.number().int().min(512).max(2048).default(1024),height:zod_1.z.number().int().min(512).max(2048).default(1024),num_images:zod_1.z.number().int().min(1).max(8).default(1),modelId:zod_1.z.string().optional(),negativePrompt:zod_1.z.string().optional(),photoReal:zod_1.z.boolean().default(!1),photoRealVersion:zod_1.z.enum(["v1","v2"]).default("v2"),alchemy:zod_1.z.boolean().default(!0),ultra:zod_1.z.boolean().default(!1).describe("Ultra mode for higher quality (Phoenix only)"),guidance_scale:zod_1.z.number().min(1).max(30).default(7),seed:zod_1.z.number().int().optional(),steps:zod_1.z.number().int().min(30).max(60).default(50),contrast:zod_1.z.number().min(1).max(4.5).default(1),outputPath:zod_1.z.string().default("./outputs"),presetStyle:zod_1.z.enum(["CINEMATIC","DYNAMIC","ENVIRONMENTAL","GENERAL","ILLUSTRATION","PHOTOGRAPHY","RAYTRACED","RENDER_3D","SKETCH_BW","SKETCH_COLOR","VIBRANT"]).optional()})
|
|
13
|
+
class LeonardoPlugin extends base_plugin_js_1.BasePlugin{constructor(){super(...arguments),this.manifest={id:"leonardo",name:"Leonardo AI",version:"1.0.0",category:"AI",description:"Leonardo AIによる高品質な画像生成。PhotoReal、Alchemy v2対応",authType:"api_key",loadPriority:"high",tools:[{name:"leonardo_generate",description:"Leonardo AIで高品質な画像を生成します。プロンプトに基づいて1-8枚の画像を作成し、指定されたフォルダに保存します。",inputSchema:LeonardoGenerateSchema,outputExample:{success:!0,content:[{type:"text",text:"✅ Leonardo AIで2枚の画像を生成しました\\n📁 保存先:\\n- ./outputs/leonardo_20250830_001.png\\n- ./outputs/leonardo_20250830_002.png"}]}},{name:"leonardo_animate",description:"フォルダ内の画像をLeonardo AI Motion 1.0で動画化します。画像をアップロードして動きを追加し、MP4形式で保存します。",inputSchema:LeonardoAnimateSchema,outputExample:{success:!0,content:[{type:"text",text:"🎬 3枚の画像を動画化しました\\n📁 保存先:\\n- ./outputs/videos/motion_20250830_001.mp4\\n- ./outputs/videos/motion_20250830_002.mp4\\n- ./outputs/videos/motion_20250830_003.mp4"}]}}]},this.availableModels=[]}async initialize(){try{this.availableModels=await this.getDefaultModels(),this.markInitialized()}catch(e){throw e}}async shutdown(){this.leonardo=void 0}async executeTool(e,t,o){if(!this.isInitialized)return this.handleError("プラグインが初期化されていません","executeTool")
|
|
14
|
+
switch(e){case"leonardo_generate":return await this.generateImage(t,o)
|
|
15
|
+
case"leonardo_animate":return await this.animateImages(t,o)
|
|
16
|
+
default:return this.handleError("未知のツール: "+e,"executeTool")}}async generateImage(e,t){const o=Date.now()
|
|
17
|
+
try{const a=this.validateArgs(e,LeonardoGenerateSchema),r=leonardo_prompt_parser_js_1.LeonardoPromptParser.parsePrompt(a.prompt),n=this.mergeSettings(r,a)
|
|
18
|
+
if(leonardo_prompt_parser_js_1.LeonardoPromptParser.validateSettings(n).length,await this.initializeLeonardoClient(t),!this.leonardo)return this.handleError("Leonardo AI クライアントの初期化に失敗","generateImage")
|
|
19
|
+
await this.ensureOutputDirectory(n.outputPath||"./outputs")
|
|
20
|
+
const i=await this.requestGeneration(n),s=await this.waitForGeneration(i.generationId)
|
|
21
|
+
if("FAILED"===s.status)return this.handleError("画像生成に失敗しました","generateImage")
|
|
22
|
+
if(!s.images||0===s.images.length)return this.handleError("生成された画像が見つかりません","generateImage")
|
|
23
|
+
const d=await this.downloadAndSaveImages(s.images,n.outputPath||"./outputs"),l=Date.now()-o
|
|
24
|
+
return await this.recordUsage("leonardo_generate",t.userId,!0,l,{imageCount:d.length,prompt:n.cleanPrompt,modelId:n.modelId,parsedFromPrompt:!0}),this.createSuccessResponse([{type:"text",text:`✅ Leonardo AIで${d.length}枚の画像を生成しました\n📝 設定: ${n.modelName||"デフォルト"} / ${n.width}x${n.height}\n📁 保存先:\n${d.map(e=>"- "+e).join("\n")}`}],{generationId:s.id,imageCount:d.length,executionTimeMs:l,savedFiles:d,parsedSettings:{model:n.modelName,size:`${n.width}x${n.height}`,style:n.presetStyle}})}catch(e){const a=Date.now()-o
|
|
25
|
+
return await this.recordUsage("leonardo_generate",t.userId,!1,a,{error:e+""}),this.handleError(e,"generateImage")}}mergeSettings(e,t){return{prompt:e.cleanPrompt||t.prompt,width:t.width||e.width||1024,height:t.height||e.height||1024,num_images:t.num_images||e.num_images||1,modelId:t.modelId||e.modelId,modelName:e.modelName,photoReal:void 0!==t.photoReal?t.photoReal:e.photoReal,photoRealVersion:t.photoRealVersion||e.photoRealVersion||"v2",presetStyle:t.presetStyle||e.presetStyle,alchemy:void 0!==t.alchemy?t.alchemy:void 0===e.alchemy||e.alchemy,guidance_scale:t.guidance_scale||e.guidanceScale||7,steps:t.steps||e.steps||50,contrast:t.contrast||e.contrast||1,negativePrompt:t.negativePrompt,seed:t.seed,outputPath:t.outputPath,originalPrompt:t.prompt,cleanPrompt:e.cleanPrompt}}async initializeLeonardoClient(e){if(this.leonardo)return
|
|
26
|
+
const t=await ApiKeyManager_js_1.ApiKeyManager.getApiKey("leonardo-ai")
|
|
27
|
+
if(!t)throw Error("Leonardo APIキーがPortalに設定されていません。https://bluelamp.vercel.app/settings で設定してください")
|
|
28
|
+
this.leonardo=new sdk_1.Leonardo({bearerAuth:t})}async requestGeneration(e){if(!this.leonardo)throw Error("Leonardo AIクライアントが初期化されていません")
|
|
29
|
+
try{const t={prompt:e.prompt,width:e.width||1024,height:e.height||1024,numImages:e.num_images||1,guidanceScale:e.guidance_scale||7,alchemy:!1!==e.alchemy}
|
|
30
|
+
e.modelId&&(t.modelId=e.modelId),e.negativePrompt&&(t.negativePrompt=e.negativePrompt),e.photoReal&&(t.photoReal=!0,t.photoRealVersion=e.photoRealVersion||"v2"),!0===e.ultra&&(t.ultra=!0,t.alchemy&&delete t.alchemy),e.seed&&(t.seed=e.seed),e.steps&&(t.numInferenceSteps=e.steps),e.presetStyle&&(t.presetStyle=e.presetStyle)
|
|
31
|
+
const o=await this.leonardo.image.createGeneration(t),a=o?.object?.sdGenerationJob?.generationId
|
|
32
|
+
if(!a)throw Error("生成IDが取得できませんでした")
|
|
33
|
+
return{generationId:a}}catch(e){throw Error("Leonardo AI API エラー: "+(e.message||e))}}async waitForGeneration(e){if(!this.leonardo)throw Error("Leonardo AIクライアントが初期化されていません")
|
|
34
|
+
let t=0
|
|
35
|
+
for(;t<30;)try{const o=await this.leonardo.image.getGenerationById(e),a=o?.object?.generationsByPk
|
|
36
|
+
if("COMPLETE"===a?.status)return{id:e,status:"COMPLETE",images:a.generatedImages?.map(e=>({id:e.id||"",url:e.url||"",likelyGuid:e.likelyGuid||""}))}
|
|
37
|
+
if("FAILED"===a?.status)return{id:e,status:"FAILED"}
|
|
38
|
+
await new Promise(e=>setTimeout(e,1e4)),t++}catch(e){if(t++,t>=30)throw Error("生成確認の最大試行回数を超えました: "+e)
|
|
39
|
+
await new Promise(e=>setTimeout(e,5e3))}throw Error("生成がタイムアウトしました。Leonardo AIのサーバーが混雑している可能性があります。")}async downloadAndSaveImages(e,t){const o=[],a=new Date,r=a.toISOString().replace(/[:\-]/g,"").replace("T","_").replace(/\..+/,""),n=`${a.getTime()}_${Math.random().toString(36).substring(2,8)}`
|
|
40
|
+
for(let a=0;a<e.length;a++){const i=e[a]
|
|
41
|
+
try{const e=await(0,node_fetch_1.default)(i.url)
|
|
42
|
+
if(!e.ok)throw Error(`ダウンロード失敗: ${e.status} ${e.statusText}`)
|
|
43
|
+
const s=Buffer.from(await e.arrayBuffer()),d=`leonardo_${r}_${n}_${i.id?i.id.substring(0,8):""}_${(a+1+"").padStart(2,"0")}.png`,l=path.join(t,d)
|
|
44
|
+
await(0,sharp_1.default)(s).png({quality:95,compressionLevel:6}).toFile(l),o.push(l)}catch(e){}}if(0===o.length)throw Error("画像の保存に全て失敗しました")
|
|
45
|
+
return o}async ensureOutputDirectory(e){try{await fs.mkdir(e,{recursive:!0})}catch(t){throw Error(`出力ディレクトリの作成に失敗: ${e} - ${t}`)}}async getDefaultModels(){return[{id:"6bef9f1b-29cb-40c7-b9df-32b51c1f67d3",name:"Leonardo Phoenix",description:"2024年リリースの最新モデル。高いプロンプト忠実度と詳細なテキスト生成が特徴",supportsAlchemy:!0},{id:"aa77f04e-3eec-4034-9c07-d0f619684628",name:"Leonardo Diffusion XL",description:"SDXL基盤の高品質汎用モデル",supportsPhotoReal:!0,supportsAlchemy:!0},{id:"1e60896f-3c26-4296-8ecc-53e2afecc132",name:"Leonardo Kino XL",description:"シネマティック品質の画像生成に特化",supportsPhotoReal:!0,supportsAlchemy:!0},{id:"5c232a9e-9061-4777-980a-ddc8e65647c6",name:"Leonardo Vision XL",description:"フォトリアルな画像生成に最適化",supportsPhotoReal:!0,supportsAlchemy:!0}]}async performHealthCheck(){const e=await ApiKeyManager_js_1.ApiKeyManager.getApiKey("leonardo-ai")
|
|
46
|
+
if(!e)throw Error("Leonardo APIキーがPortalに設定されていません。https://bluelamp.vercel.app/settings で設定してください")
|
|
47
|
+
try{new sdk_1.Leonardo({bearerAuth:e})}catch(e){throw Error("Leonardo AI接続テストに失敗: "+e)}}async animateImages(e,t){const o=Date.now()
|
|
48
|
+
try{const a=this.validateArgs(e,LeonardoAnimateSchema)
|
|
49
|
+
if(await this.initializeLeonardoClient(t),!this.leonardo)return this.handleError("Leonardo AI クライアントの初期化に失敗","animateImages")
|
|
50
|
+
const r=await this.findImageFiles(a.folderPath,a.pattern,a.sortBy,a.fileLimit)
|
|
51
|
+
if(0===r.length)return this.handleError(`${a.folderPath}に対象画像が見つかりません(パターン: ${a.pattern})`,"animateImages")
|
|
52
|
+
await this.ensureOutputDirectory(a.outputPath)
|
|
53
|
+
const n=[],i=[]
|
|
54
|
+
for(let e=0;e<r.length;e++){const t=r[e]
|
|
55
|
+
try{const e=await this.uploadImageToLeonardo(t),o=await this.requestMotionGeneration(e,a.motionStrength,a.isPublic),r=await this.waitForMotionGeneration(o),i=await this.downloadVideo(r,a.outputPath,t)
|
|
56
|
+
n.push(i)}catch(e){const o=`❌ ${path.basename(t)}: ${e}`
|
|
57
|
+
i.push(o)}}const s=Date.now()-o
|
|
58
|
+
return await this.recordUsage("leonardo_animate",t.userId,n.length>0,s,{processedImages:r.length,generatedVideos:n.length,errors:i.length}),0===n.length?this.handleError("すべての動画生成に失敗しました","animateImages"):this.createSuccessResponse([{type:"text",text:`🎬 ${n.length}/${r.length}個の動画を生成しました\n📁 保存先:\n${n.map(e=>"- "+e).join("\n")}${i.length>0?"\n\n⚠️ エラー:\n"+i.join("\n"):""}`}],{processedImages:r.length,generatedVideos:n.length,executionTimeMs:s,savedFiles:n})}catch(e){const a=Date.now()-o
|
|
59
|
+
return await this.recordUsage("leonardo_animate",t.userId,!1,a,{error:e+""}),this.handleError(e,"animateImages")}}async findImageFiles(e,t,o,a){const r=(await Promise.resolve().then(()=>__importStar(require("glob")))).glob,n=path.join(e,t),i=await r(n,{nodir:!0,absolute:!0})
|
|
60
|
+
if(0===i.length)return[]
|
|
61
|
+
const s=await Promise.all(i.map(async e=>({path:e,stat:await fs.stat(e)})))
|
|
62
|
+
return s.sort((e,t)=>{switch(o){case"newest":return t.stat.mtime.getTime()-e.stat.mtime.getTime()
|
|
63
|
+
case"oldest":return e.stat.mtime.getTime()-t.stat.mtime.getTime()
|
|
64
|
+
default:return e.path.localeCompare(t.path)}}),(a?s.slice(0,a):s).map(e=>e.path)}async uploadImageToLeonardo(e){if(!this.leonardo)throw Error("Leonardo AIクライアントが初期化されていません")
|
|
65
|
+
const t=await fs.readFile(e),o=path.basename(e),a=await this.leonardo.image.uploadInitImage({extension:path.extname(o).substring(1)})
|
|
66
|
+
if(!a.object?.uploadInitImage?.url||!a.object?.uploadInitImage?.id)throw Error("アップロードURL取得に失敗しました")
|
|
67
|
+
const{url:r,id:n}=a.object.uploadInitImage,i=await(0,node_fetch_1.default)(r,{method:"PUT",body:t,headers:{"Content-Type":"image/png"}})
|
|
68
|
+
if(!i.ok)throw Error("画像アップロード失敗: "+i.status)
|
|
69
|
+
return n}async requestMotionGeneration(e,t,o){if(!this.leonardo)throw Error("Leonardo AIクライアントが初期化されていません")
|
|
70
|
+
const a=await this.getLeonardoApiKey(),r=await(0,node_fetch_1.default)("https://cloud.leonardo.ai/api/rest/v1/generations-motion-svd",{method:"POST",headers:{Authorization:"Bearer "+a,"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify({imageId:e,motionStrength:t,isInitImage:!0,isPublic:o})})
|
|
71
|
+
if(!r.ok){const e=await r.text()
|
|
72
|
+
throw Error(`Motion生成リクエスト失敗: ${r.status} - ${e}`)}const n=await r.json()
|
|
73
|
+
if(!n.motionSvdGenerationJob?.generationId)throw Error("Motion生成IDが取得できませんでした")
|
|
74
|
+
return n.motionSvdGenerationJob.generationId}async waitForMotionGeneration(e){let t=0
|
|
75
|
+
const o=await this.getLeonardoApiKey()
|
|
76
|
+
for(;t<60;)try{const a=await(0,node_fetch_1.default)("https://cloud.leonardo.ai/api/rest/v1/generations/"+e,{method:"GET",headers:{Authorization:"Bearer "+o,Accept:"application/json"}})
|
|
77
|
+
if(!a.ok)throw Error("生成状況確認失敗: "+a.status)
|
|
78
|
+
const r=(await a.json()).generationsByPk
|
|
79
|
+
if("COMPLETE"===r?.status){const e=r.generatedVideos?.[0]
|
|
80
|
+
if(e?.url)return e.url
|
|
81
|
+
throw Error("動画URLが見つかりません")}if("FAILED"===r?.status)throw Error("動画生成に失敗しました")
|
|
82
|
+
await new Promise(e=>setTimeout(e,1e4)),t++}catch(e){if(t++,t>=60)throw Error("生成確認の最大試行回数を超えました: "+e)
|
|
83
|
+
await new Promise(e=>setTimeout(e,5e3))}throw Error("動画生成がタイムアウトしました")}async getLeonardoApiKey(){if(this.leonardo){const e=this.leonardo.config
|
|
84
|
+
if(e?.bearerAuth)return e.bearerAuth}const e=await ApiKeyManager_js_1.ApiKeyManager.getApiKey("leonardo-ai")
|
|
85
|
+
if(!e)throw Error("Leonardo APIキーがPortalに設定されていません。https://bluelamp.vercel.app/settings で設定してください")
|
|
86
|
+
return e}async downloadVideo(e,t,o){const a=await(0,node_fetch_1.default)(e)
|
|
87
|
+
if(!a.ok)throw Error("動画ダウンロード失敗: "+a.status)
|
|
88
|
+
const r=Buffer.from(await a.arrayBuffer()),n=(new Date).toISOString().replace(/[:\-]/g,"").replace("T","_").replace(/\..+/,""),i=`motion_${path.basename(o,path.extname(o))}_${n}.mp4`,s=path.join(t,i)
|
|
89
|
+
return await fs.writeFile(s,r),s}}exports.default=LeonardoPlugin
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.LeonardoPromptParser=exports.ASPECT_RATIOS=exports.PRESET_STYLES=exports.LEONARDO_MODELS=void 0,exports.LEONARDO_MODELS={phoenix:{id:"6bef9f1b-29cb-40c7-b9df-32b51c1f67d3",name:"Leonardo Phoenix",keywords:["phoenix","フェニックス","最新","latest"],supportsAlchemy:!0,supportsPhotoReal:!1},vision_xl:{id:"5c232a9e-9061-4777-980a-ddc8e65647c6",name:"Leonardo Vision XL",keywords:["vision","ビジョン","フォトリアル","photorealistic","リアル","写真"],supportsAlchemy:!0,supportsPhotoReal:!0},diffusion_xl:{id:"aa77f04e-3eec-4034-9c07-d0f619684628",name:"Leonardo Diffusion XL",keywords:["diffusion","ディフュージョン","汎用","general","バランス"],supportsAlchemy:!0,supportsPhotoReal:!0},kino_xl:{id:"1e60896f-3c26-4296-8ecc-53e2afecc132",name:"Leonardo Kino XL",keywords:["kino","キノ","映画","cinematic","シネマ","movie","film"],supportsAlchemy:!0,supportsPhotoReal:!0,preferredAspectRatio:"21:9"},anime_xl:{id:"e71a1c2f-4f80-4800-934f-2c68979d8cc8",name:"Leonardo Anime XL",keywords:["anime","アニメ","manga","マンガ","漫画","cartoon","illustration"],supportsAlchemy:!0,supportsPhotoReal:!1},lightning_xl:{id:"b24e16ff-06e3-43eb-8aec-8ab3166edcb6",name:"Leonardo Lightning XL",keywords:["lightning","ライトニング","高速","fast","quick","rapid","速い"],supportsAlchemy:!1,supportsPhotoReal:!1}},exports.PRESET_STYLES={cinematic:{value:"CINEMATIC",keywords:["cinematic","シネマティック","映画的","movie","film"],preferredModel:"kino_xl"},dynamic:{value:"DYNAMIC",keywords:["dynamic","ダイナミック","動的","action","motion"],preferredModel:"diffusion_xl"},photography:{value:"PHOTOGRAPHY",keywords:["photography","フォトグラフィー","写真","photo","camera"],preferredModel:"vision_xl"},vibrant:{value:"VIBRANT",keywords:["vibrant","ビブラント","鮮やか","colorful","vivid"]},raytraced:{value:"RAYTRACED",keywords:["raytraced","レイトレース","3D","render","レンダー"]},illustration:{value:"ILLUSTRATION",keywords:["illustration","イラスト","drawing","絵","artwork"]}},exports.ASPECT_RATIOS={"1:1":{keywords:["1:1","正方形","square","スクエア","インスタ","instagram"],width:1024,height:1024},"16:9":{keywords:["16:9","横長","wide","ワイド","youtube","ユーチューブ","HD"],width:1920,height:1080},"9:16":{keywords:["9:16","縦長","portrait","ポートレート","tiktok","ティックトック","stories","ストーリー"],width:1080,height:1920},"4:3":{keywords:["4:3","standard","スタンダード","標準"],width:1024,height:768},"3:4":{keywords:["3:4","縦向き標準"],width:768,height:1024},"2:3":{keywords:["2:3","縦向き","vertical","バーティカル"],width:1024,height:1536},"3:2":{keywords:["3:2","横向き","horizontal","ホリゾンタル"],width:1536,height:1024},"21:9":{keywords:["21:9","ultrawide","ウルトラワイド","cinema","シネマスコープ"],width:2560,height:1080},facebook:{keywords:["facebook","フェイスブック","fb"],width:1200,height:630},twitter:{keywords:["twitter","ツイッター","x"],width:1200,height:675},linkedin:{keywords:["linkedin","リンクトイン"],width:1200,height:627}}
|
|
3
|
+
class LeonardoPromptParser{static parsePrompt(e){const t={cleanPrompt:e},o=this.extractAspectRatio(e)
|
|
4
|
+
o&&(Object.assign(t,o),t.cleanPrompt=o.cleanPrompt||t.cleanPrompt)
|
|
5
|
+
const r=this.extractModel(t.cleanPrompt)
|
|
6
|
+
r&&(Object.assign(t,r),t.cleanPrompt=r.cleanPrompt||t.cleanPrompt)
|
|
7
|
+
const a=this.extractStyle(t.cleanPrompt)
|
|
8
|
+
a&&(Object.assign(t,a),t.cleanPrompt=a.cleanPrompt||t.cleanPrompt)
|
|
9
|
+
const i=this.extractQuality(t.cleanPrompt)
|
|
10
|
+
i&&(Object.assign(t,i),t.cleanPrompt=i.cleanPrompt||t.cleanPrompt)
|
|
11
|
+
const s=this.extractImageCount(t.cleanPrompt)
|
|
12
|
+
s&&(Object.assign(t,s),t.cleanPrompt=s.cleanPrompt||t.cleanPrompt)
|
|
13
|
+
const c=this.extractPhotoReal(t.cleanPrompt)
|
|
14
|
+
return c&&(Object.assign(t,c),t.cleanPrompt=c.cleanPrompt||t.cleanPrompt),t.cleanPrompt=this.cleanupPrompt(t.cleanPrompt),t}static extractAspectRatio(e){let t=e
|
|
15
|
+
const o=e.match(/(\d{3,4})\s*[x×]\s*(\d{3,4})/i)
|
|
16
|
+
if(o){const e=parseInt(o[1]),r=parseInt(o[2])
|
|
17
|
+
return t=t.replace(o[0],"").trim(),{width:e,height:r,cleanPrompt:t}}for(const[o,r]of Object.entries(exports.ASPECT_RATIOS)){const o=r.keywords.join("|"),a=RegExp(`\\b(${o})\\b`,"gi")
|
|
18
|
+
if(e.match(a))return t=t.replace(a,"").trim(),{width:r.width,height:r.height,cleanPrompt:t}}return null}static extractModel(e){let t=e
|
|
19
|
+
for(const[o,r]of Object.entries(exports.LEONARDO_MODELS))for(const keyword of r.keywords){const a=RegExp(/[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]/.test(keyword)?keyword:`\\b${keyword}\\b`,"gi")
|
|
20
|
+
if(e.match(a))return t=t.replace(a,"").trim(),"vision_xl"===o&&e.match(/photoreal|フォトリアル/gi)?{photoReal:!0,photoRealVersion:"v2",modelId:r.id,modelName:r.name,cleanPrompt:t}:{modelId:r.id,modelName:r.name,cleanPrompt:t}}return null}static extractStyle(e){let t=e
|
|
21
|
+
for(const[o,r]of Object.entries(exports.PRESET_STYLES))for(const keyword of r.keywords){const o=RegExp(/[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]/.test(keyword)?keyword:`\\b${keyword}\\b`,"gi")
|
|
22
|
+
if(e.match(o)){t=t.replace(o,"").trim()
|
|
23
|
+
const a={presetStyle:r.value,cleanPrompt:t}
|
|
24
|
+
if("preferredModel"in r&&r.preferredModel&&!e.match(/model|モデル/gi)){const e=exports.LEONARDO_MODELS[r.preferredModel]
|
|
25
|
+
e&&(a.modelId=e.id,a.modelName=e.name)}return a}}return null}static extractQuality(e){let t=e
|
|
26
|
+
const o={}
|
|
27
|
+
return e.match(/高品質|高画質|最高品質|ultra|high quality|best quality/gi)?(o.steps=60,o.guidanceScale=10,o.alchemy=!0,t=t.replace(/高品質|高画質|最高品質|ultra|high quality|best quality/gi,"").trim()):e.match(/中品質|標準|standard|medium quality/gi)?(o.steps=50,o.guidanceScale=7,o.alchemy=!0,t=t.replace(/中品質|標準|standard|medium quality/gi,"").trim()):e.match(/低品質|ドラフト|draft|quick|fast|低画質/gi)&&(o.steps=30,o.guidanceScale=5,o.alchemy=!1,t=t.replace(/低品質|ドラフト|draft|quick|fast|低画質/gi,"").trim()),e.match(/alchemy|アルケミー|魔法/gi)&&(o.alchemy=!0,t=t.replace(/alchemy|アルケミー|魔法/gi,"").trim()),Object.keys(o).length>0?(o.cleanPrompt=t,o):null}static extractImageCount(e){let t=e
|
|
28
|
+
const o=e.match(/(\d+)\s*[枚つ個]/)
|
|
29
|
+
if(o){const e=Math.min(parseInt(o[1]),8)
|
|
30
|
+
return t=t.replace(o[0],"").trim(),{num_images:e,cleanPrompt:t}}const r=e.match(/(\d+)\s*(images?|pictures?|photos?|pieces?)/i)
|
|
31
|
+
if(r){const e=Math.min(parseInt(r[1]),8)
|
|
32
|
+
return t=t.replace(r[0],"").trim(),{num_images:e,cleanPrompt:t}}return null}static extractPhotoReal(e){let t=e
|
|
33
|
+
return e.match(/photoreal|フォトリアル|写真のような|photorealistic/gi)?(t=t.replace(/photoreal|フォトリアル|写真のような|photorealistic/gi,"").trim(),{photoReal:!0,photoRealVersion:"v2",cleanPrompt:t}):null}static cleanupPrompt(e){return e.replace(/\s+/g," ").replace(/^\s*[,、]\s*/g,"").replace(/\s*[,、]\s*$/g,"").replace(/[,、]\s*[,、]/g,",").replace(/で\s*$/g,"").replace(/を\s*$/g,"").trim()}static validateSettings(e){const t=[]
|
|
34
|
+
if(e.photoReal&&e.modelId){const o=Object.values(exports.LEONARDO_MODELS).find(t=>t.id===e.modelId)
|
|
35
|
+
o&&!o.supportsPhotoReal&&t.push(`警告: ${o.name}はPhotoRealをサポートしていません`)}if(e.alchemy&&e.modelId){const o=Object.values(exports.LEONARDO_MODELS).find(t=>t.id===e.modelId)
|
|
36
|
+
o&&!o.supportsAlchemy&&t.push(`警告: ${o.name}はAlchemyをサポートしていません`)}return e.width&&e.width>2048&&t.push("警告: 幅が2048pxを超えています"),e.height&&e.height>2048&&t.push("警告: 高さが2048pxを超えています"),t}}exports.LeonardoPromptParser=LeonardoPromptParser
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
var __importDefault=this&&this.__importDefault||function(t){return t&&t.__esModule?t:{default:t}}
|
|
3
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.portalAPIClient=exports.PortalAPIClient=void 0
|
|
4
|
+
const node_fetch_1=__importDefault(require("node-fetch")),SimpleAuthManager_js_1=require("../../security/SimpleAuthManager.js")
|
|
5
|
+
class PortalAPIClient{constructor(){this.baseURL=process.env.BLUELAMP_PORTAL_API_URL||"http://localhost:8080",this.timeout=3e4,this.retryAttempts=3,this.retryDelay=1e3}async getAuthToken(){try{return await SimpleAuthManager_js_1.SimpleAuthManager.getToken()||null}catch(t){return null}}async makeRequest(t,e={}){const token=await this.getAuthToken()
|
|
6
|
+
if(!token)throw Error("Portal API: 認証トークンが利用できません")
|
|
7
|
+
const a=`${this.baseURL}${t}`,r={method:"GET",headers:{"X-CLI-Token":token,"Content-Type":"application/json","User-Agent":"BlueLamp-MCP-Client/1.0",...e.headers},timeout:this.timeout,...e}
|
|
8
|
+
for(let t=1;t<=this.retryAttempts;t++)try{const t=new AbortController,e=setTimeout(()=>t.abort(),this.timeout),s=await(0,node_fetch_1.default)(a,{...r,signal:t.signal})
|
|
9
|
+
if(clearTimeout(e),!s.ok){if(401===s.status)throw Error("Portal API: 認証失敗 - 無効なトークン")
|
|
10
|
+
if(404===s.status)return null
|
|
11
|
+
throw Error(`Portal API: リクエスト失敗 - ${s.status} ${s.statusText}`)}return await s.json()}catch(e){if(t===this.retryAttempts)throw e
|
|
12
|
+
await new Promise(e=>setTimeout(e,this.retryDelay*t))}return null}async resolveSlot(t){try{const e="/api/slots/resolve/"+t,a=await this.makeRequest(e)
|
|
13
|
+
return a&&a.success?{slotNumber:t,orchestratorEndpoint:a.data.orchestratorEndpoint,configuration:a.data.configuration,status:a.data.status,lastUpdated:a.data.lastUpdated}:null}catch(t){return null}}async getAllSlots(){try{const t="/api/slots/all",e=await this.makeRequest(t)
|
|
14
|
+
return e?.data?.slots||[]}catch(t){return[]}}async getUsageStats(){try{const t="/api/usage/stats",e=await this.makeRequest(t)
|
|
15
|
+
return e?.data||null}catch(t){return null}}async updateUsage(t,e="orchestrator_call"){try{const a="/api/usage/update",r=await this.makeRequest(a,{method:"POST",body:JSON.stringify({slotNumber:t,operation:e,timestamp:(new Date).toISOString()})})
|
|
16
|
+
return r?.success||!1}catch(t){return!1}}async checkFreeUsageAvailable(){try{const t=await this.getUsageStats()
|
|
17
|
+
if(!t)return!1
|
|
18
|
+
const e=t.freeUsageLimit||3
|
|
19
|
+
return(t.totalUsage||0)<e}catch(t){return!1}}async getUserInfo(){try{const t="/api/user/info",e=await this.makeRequest(t)
|
|
20
|
+
return e?.data||null}catch(t){return null}}async getServiceCredentials(t){try{const e="/api/cli/user-credentials/"+t,a=await this.makeRequest(e)
|
|
21
|
+
return a?.success&&a.data?a.data:null}catch(t){return null}}async injectKnowledge(keyword,t){try{const t="/api/cli/prompts/knowledge-injection/"+encodeURIComponent(keyword),e=await this.makeRequest(t,{method:"GET"})
|
|
22
|
+
return e?.success&&e.data?{success:!0,knowledge:e.data.prompt||e.data.content,source:e.data.source||"portal_api"}:{success:!1,error:e?.message||"Knowledge injection failed"}}catch(t){return{success:!1,error:"Knowledge injection error: "+t}}}}exports.PortalAPIClient=PortalAPIClient,exports.portalAPIClient=new PortalAPIClient
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict"
|
|
2
|
+
var __createBinding=this&&this.__createBinding||(Object.create?function(e,t,r,a){void 0===a&&(a=r)
|
|
3
|
+
var n=Object.getOwnPropertyDescriptor(t,r)
|
|
4
|
+
n&&!("get"in n?!t.__esModule:n.writable||n.configurable)||(n={enumerable:!0,get:function(){return t[r]}}),Object.defineProperty(e,a,n)}:function(e,t,r,a){void 0===a&&(a=r),e[a]=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=[]
|
|
5
|
+
for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[t.length]=r)
|
|
6
|
+
return t},e(t)}
|
|
7
|
+
return function(t){if(t&&t.__esModule)return t
|
|
8
|
+
var r={}
|
|
9
|
+
if(null!=t)for(var a=e(t),n=0;n<a.length;n++)"default"!==a[n]&&__createBinding(r,t,a[n])
|
|
10
|
+
return __setModuleDefault(r,t),r}}()
|
|
11
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.DynamicSlotResolver=void 0
|
|
12
|
+
const zod_1=require("zod"),fs=__importStar(require("fs/promises")),path=__importStar(require("path")),os=__importStar(require("os")),base_plugin_js_1=require("../base-plugin.js"),SimpleAuthManager_js_1=require("../../security/SimpleAuthManager.js"),portal_api_client_js_1=require("./portal-api-client.js"),DelegateToAgentSchema=zod_1.z.object({agentName:zod_1.z.string().min(1,"エージェント名は必須です"),token:zod_1.z.string().optional()}),InjectKnowledgeSchema=zod_1.z.object({keyword:zod_1.z.string().min(1,"キーワードは必須です"),context:zod_1.z.string().optional(),level:zod_1.z.string().default("detailed")}),SaveKnowledgeSchema=zod_1.z.object({knowledge:zod_1.z.string().min(1,"知識内容は必須です"),identifier:zod_1.z.string().min(1,"識別子は必須です"),token:zod_1.z.string().min(1,"トークンは必須です")}),ListPromptsSchema=zod_1.z.object({category:zod_1.z.string().optional(),token:zod_1.z.string().min(1,"トークンは必須です")})
|
|
13
|
+
class DynamicSlotResolver{constructor(){this.cacheTimeout=3e5,this.slotCache=new Map,this.agentSlotMapping={orchestrator:1,orchestrator1:1,orchestrator2:2,orchestrator3:3,orchestrator4:4,orchestrator5:5},this.portalClient=portal_api_client_js_1.portalAPIClient}extractSlotNumber(e){if(!e||"string"!=typeof e)throw Error("Invalid agent name provided")
|
|
14
|
+
const t=e.toLowerCase().trim()
|
|
15
|
+
if(this.agentSlotMapping[t])return this.agentSlotMapping[t]
|
|
16
|
+
const r=t.match(/^orchestrator(\d+)?$/)
|
|
17
|
+
if(r)return r[1]?parseInt(r[1],10):1
|
|
18
|
+
const a=e.match(/\d+/)
|
|
19
|
+
return a?parseInt(a[0],10):1}async getSlotConfiguration(e){const t="slot_"+e,r=this.slotCache.get(t)
|
|
20
|
+
if(r&&Date.now()-r.timestamp<this.cacheTimeout)return r.data
|
|
21
|
+
try{const r=await this.portalClient.resolveSlot(e)
|
|
22
|
+
return this.slotCache.set(t,{data:r,timestamp:Date.now()}),r}catch(e){return null}}async resolveOrchestratorConfig(e){try{const t=this.extractSlotNumber(e),r=await this.getSlotConfiguration(t)
|
|
23
|
+
return r?await this.portalClient.checkFreeUsageAvailable()?{success:!0,slotNumber:t,agentName:e,orchestratorEndpoint:r.orchestratorEndpoint,configuration:r.configuration}:{success:!1,error:"Free usage limit exceeded",slotNumber:t,agentName:e,usageExceeded:!0,usageFallback:"Please upgrade to continue using orchestrator features"}:{success:!1,error:`Slot ${t} is not configured in Portal`,slotNumber:t,agentName:e,fallback:this.getFallbackConfig(t)}}catch(t){return{success:!1,error:"Failed to resolve configuration: "+t,agentName:e}}}async delegateToAgent(e){const t=await this.resolveOrchestratorConfig(e)
|
|
24
|
+
if(!t.success)return t
|
|
25
|
+
try{return await this.portalClient.updateUsage(t.slotNumber,"orchestrator_call"),{success:!0,message:"Successfully delegated to "+e,slotNumber:t.slotNumber,orchestratorEndpoint:t.orchestratorEndpoint,configuration:t.configuration}}catch(t){return{success:!1,error:"Delegation failed: "+t,agentName:e}}}getFallbackConfig(e){return{endpoint:"http://localhost:8080/api/orchestrator/fallback",message:`Slot ${e} not configured, using fallback`,features:["basic_responses","error_handling"]}}}exports.DynamicSlotResolver=DynamicSlotResolver
|
|
26
|
+
class PortalPlugin extends base_plugin_js_1.BasePlugin{constructor(){super(...arguments),this.manifest={id:"portal",name:"Portal Integration",version:"1.0.0",category:"Integration",description:"Portal APIとの統合機能を提供(エージェント委譲、知識注入、認証管理)",authType:"token",loadPriority:"high",tools:[{name:"delegate_to_agent",description:"専門エージェントにタスクを委譲します。動的スロット解決により適切なオーケストレーターに接続します。",inputSchema:DelegateToAgentSchema,outputExample:{success:!0,content:[{type:"text",text:"✅ orchestrator2 にタスクを委譲しました\\n🔗 エンドポイント: https://orchestrator-slot2.example.com\\n📊 使用回数を更新しました"}]}},{name:"inject_knowledge",description:"Portal APIから専門知識を注入します。キーワードに基づいて関連する知識ベースからコンテンツを取得します。",inputSchema:InjectKnowledgeSchema,outputExample:{success:!0,content:[{type:"text",text:"🧠 専門知識を注入しました\\n🔍 キーワード: React\\n📚 知識内容: Reactは..."}]}},{name:"save_knowledge",description:"暗号化された知識を保存します。",inputSchema:SaveKnowledgeSchema,outputExample:{success:!0,content:[{type:"text",text:"💾 知識を暗号化して保存しました"}]}},{name:"list_prompts",description:"利用可能な暗号化プロンプトテンプレートを一覧表示します。",inputSchema:ListPromptsSchema,outputExample:{success:!0,content:[{type:"text",text:"📋 利用可能なプロンプト: システムアーキテクト, UI/UXデザイナー, 実装エージェント"}]}}]},this.validTokens=new Set,this.promptCache=new Map,this.cacheTimeout=3e5}async initialize(){try{this.logFilePath=path.join(os.tmpdir(),`portal-debug-${Date.now()}.log`),this.debugLog("Portal Integration Plugin starting - Log file: "+this.logFilePath),this.slotResolver=new DynamicSlotResolver,this.keywordMapping=new Map([["orchestrator","オーケストレーター"],["requirements-engineer","要件定義エンジニア"],["ui-ux-designer","UI/UXデザイナー"],["data-modeling-engineer","データモデリングエンジニア"],["system-architect","システムアーキテクト"],["implementation-consultant","実装コンサルタント"],["environment-setup","環境構築"],["prototype-implementation","プロトタイプ実装"],["implementation-agent","実装エージェント"],["debug-agent","デバッグエージェント"],["deploy-specialist","デプロイスペシャリスト"],["page-creator","ページクリエイター"],["refactoring-engineer","リファクタリングエンジニア"],["ai-friendliness-diagnostic","AI親和性診断"]]),await this.initializeTokens(),this.markInitialized()}catch(e){throw e}}async shutdown(){this.validTokens.clear(),this.promptCache.clear()}async executeTool(e,t,r){if(!this.isInitialized)return this.handleError("プラグインが初期化されていません","executeTool")
|
|
27
|
+
this.debugLog("Tool called: "+e,t)
|
|
28
|
+
try{switch(e){case"delegate_to_agent":return await this.handleDelegateToAgent(t)
|
|
29
|
+
case"inject_knowledge":return await this.handleInjectKnowledge(t)
|
|
30
|
+
case"save_knowledge":return await this.handleSaveKnowledge(t)
|
|
31
|
+
case"list_prompts":return await this.handleListPrompts(t)
|
|
32
|
+
case"get_debug_log_path":return this.handleGetDebugLogPath()
|
|
33
|
+
default:return this.handleError("未知のツール: "+e,"executeTool")}}catch(e){return this.handleError(e,"executeTool")}}async handleDelegateToAgent(e){try{const t=this.validateArgs(e,DelegateToAgentSchema),token=await this.getSystemToken()
|
|
34
|
+
if(!token||!this.validateToken(token))return this.createErrorResponse("システム認証に失敗しました","SYSTEM_AUTH_ERROR")
|
|
35
|
+
this.debugLog("Delegating to agent: "+t.agentName)
|
|
36
|
+
const r=await this.slotResolver.delegateToAgent(t.agentName)
|
|
37
|
+
if(!r.success){this.debugLog(`Delegation failed for ${t.agentName}:`,r)
|
|
38
|
+
const e=r.usageExceeded?"USAGE_EXCEEDED":"SLOT_RESOLUTION_FAILED"
|
|
39
|
+
return this.createErrorResponse(r.error||"エージェント委譲に失敗しました",e,{agentName:t.agentName,slotNumber:r.slotNumber,fallback:r.fallback||r.usageFallback})}return this.createSuccessResponse([{type:"text",text:`✅ ${t.agentName} にタスクを委譲しました\n🔗 エンドポイント: ${r.orchestratorEndpoint}\n📊 スロット番号: ${r.slotNumber}\n⏰ 使用回数を更新しました`}],{agentName:t.agentName,slotNumber:r.slotNumber,orchestratorEndpoint:r.orchestratorEndpoint,success:!0})}catch(e){return this.handleError(e,"handleDelegateToAgent")}}async handleInjectKnowledge(e){try{const t=this.validateArgs(e,InjectKnowledgeSchema),token=await this.getSystemToken()
|
|
40
|
+
if(!token||!this.validateToken(token))return this.createErrorResponse("システム認証に失敗しました","SYSTEM_AUTH_ERROR")
|
|
41
|
+
const r=`${t.keyword}:${t.level}`,a=this.promptCache.get(r)
|
|
42
|
+
let n,o="unknown"
|
|
43
|
+
if(a&&Date.now()-a.timestamp<this.cacheTimeout)n=a.content,o=a.source||"cache",this.debugLog("Using cached knowledge for "+t.keyword)
|
|
44
|
+
else{const e=await portal_api_client_js_1.portalAPIClient.injectKnowledge(t.keyword,t.context)
|
|
45
|
+
if(!e.success)return this.createErrorResponse(e.error||"知識注入に失敗しました","KNOWLEDGE_INJECTION_FAILED")
|
|
46
|
+
n=e.knowledge,o="portal_api",this.promptCache.set(r,{content:n,timestamp:Date.now(),source:o}),this.debugLog("Knowledge injected from Portal API for "+t.keyword)}return this.createSuccessResponse([{type:"text",text:`🧠 専門知識を注入しました\n🔍 キーワード: ${t.keyword}\n📚 ソース: ${o}\n📖 知識内容: ${n||"知識が見つかりませんでした"}`}],{keyword:t.keyword,source:o,knowledgeContent:n,cached:"cache"===o})}catch(e){return this.handleError(e,"handleInjectKnowledge")}}async handleSaveKnowledge(e){try{const t=this.validateArgs(e,SaveKnowledgeSchema)
|
|
47
|
+
return this.validateToken(t.token)?this.createSuccessResponse([{type:"text",text:`💾 知識を暗号化して保存しました\n🔑 識別子: ${t.identifier}\n📝 サイズ: ${t.knowledge.length} 文字`}],{identifier:t.identifier,saved:!0}):this.createErrorResponse("無効な認証トークンです","AUTH_ERROR")}catch(e){return this.handleError(e,"handleSaveKnowledge")}}async handleListPrompts(e){try{const t=this.validateArgs(e,ListPromptsSchema)
|
|
48
|
+
if(!this.validateToken(t.token))return this.createErrorResponse("無効な認証トークンです","AUTH_ERROR")
|
|
49
|
+
const r=Array.from(this.keywordMapping.entries()).map(([e,name])=>({key:e,name:name})),a=r.map(e=>`- ${e.name} (${e.key})`).join("\n")
|
|
50
|
+
return this.createSuccessResponse([{type:"text",text:`📋 利用可能なプロンプトテンプレート:\n${a}\n\n💡 inject_knowledge ツールで任意のキーワードを使用して専門知識を取得できます。`}],{availablePrompts:r,count:r.length})}catch(e){return this.handleError(e,"handleListPrompts")}}handleGetDebugLogPath(){return this.createSuccessResponse([{type:"text",text:JSON.stringify({success:!0,logPath:this.logFilePath,message:"Debug log is being written to: "+this.logFilePath})}],{logPath:this.logFilePath})}async getSystemToken(){try{return await SimpleAuthManager_js_1.SimpleAuthManager.getToken()}catch(e){return this.debugLog("Failed to get system token:",e),null}}validateToken(token){return this.validTokens.has(token)}async initializeTokens(){try{const token=await this.getSystemToken()
|
|
51
|
+
token&&(this.validTokens.add(token),this.debugLog(`System token initialized: ${token.substring(0,30)}...`))}catch(e){this.debugLog("Token initialization failed:",e)}}debugLog(e,t){const r=(new Date).toISOString(),a=t?`[${r}] ${e}\n${JSON.stringify(t,null,2)}\n`:`[${r}] ${e}\n`
|
|
52
|
+
try{fs.appendFile(this.logFilePath,a).catch(()=>{})}catch(e){}}createErrorResponse(e,t,r){return this.createSuccessResponse([{type:"text",text:JSON.stringify({success:!1,error:e,code:t,...r})}],{success:!1,error:e,code:t,...r})}async performHealthCheck(){try{if(!await portal_api_client_js_1.portalAPIClient.getUserInfo())throw Error("Portal API接続テストに失敗しました")}catch(e){throw Error("Portal API接続テストに失敗: "+e)}}}exports.default=PortalPlugin
|