@lansenger/openclaw-channel-lansenger 0.0.1 → 0.0.2

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.
@@ -14,20 +14,7 @@ export interface BotAgentBinding {
14
14
  */
15
15
  export declare class BindingManager {
16
16
  private bindings;
17
- private storagePath;
18
17
  constructor();
19
- /**
20
- * Get storage file path
21
- */
22
- private getStorageFilePath;
23
- /**
24
- * Load bindings from storage
25
- */
26
- private loadBindings;
27
- /**
28
- * Save bindings to storage
29
- */
30
- private saveBindings;
31
18
  /**
32
19
  * Bind a bot to an agent
33
20
  */
@@ -1 +1 @@
1
- import n from"fs";import i from"path";import{logger as t}from"../index.js";import{tryGetLansengerRuntime as e}from"../../openclaw-adapter/runtime-store.js";export class BindingManager{bindings=[];storagePath;constructor(){this.storagePath=this.getStorageFilePath(),this.loadBindings()}getStorageFilePath(){const s=e();let g;if(s&&s.state){const n=s.state.resolveStateDir();g=i.join(n,"extensions","openclaw-channel-lansenger"),t.info("Using runtime state directory for binding storage:",{stateDir:n})}else g=i.join("extensions","openclaw-channel-lansenger"),t.info("Using relative path for binding storage (runtime not available)");return n.existsSync(g)||n.mkdirSync(g,{recursive:!0}),i.join(g,"agent-bindings.json")}loadBindings(){try{if(n.existsSync(this.storagePath)){const i=n.readFileSync(this.storagePath,"utf8");this.bindings=JSON.parse(i),t.info(`Loaded ${this.bindings.length} bot-agent bindings`)}else t.info("No binding storage file found, initializing empty bindings"),this.bindings=[]}catch(n){t.error("Error loading bindings:",n),this.bindings=[]}}saveBindings(){try{n.writeFileSync(this.storagePath,JSON.stringify(this.bindings,null,2)),t.info(`Saved ${this.bindings.length} bot-agent bindings`)}catch(n){t.error("Error saving bindings:",n)}}bindBotToAgent(n,i){const e=this.bindings.findIndex(i=>i.botId===n);e>=0?(this.bindings[e]={botId:n,agentId:i,lastUpdated:(new Date).toISOString()},t.info(`Updated binding: ${n} -> ${i}`)):(this.bindings.push({botId:n,agentId:i,lastUpdated:(new Date).toISOString()}),t.info(`Added binding: ${n} -> ${i}`)),this.saveBindings()}getBotAgent(n){const i=this.bindings.find(i=>i.botId===n);return i?i.agentId:"default"}getAllBindings(){return[...this.bindings]}removeBinding(n){const i=this.bindings.length;this.bindings=this.bindings.filter(i=>i.botId!==n),this.bindings.length<i&&(t.info(`Removed binding for bot: ${n}`),this.saveBindings())}hasBinding(n){return this.bindings.some(i=>i.botId===n)}}let s=null;export function createBindingManager(){return s||(s=new BindingManager),s}export function getBindingManager(){return s||(s=new BindingManager),s}
1
+ import{logger as n}from"../index.js";export class BindingManager{bindings=[];constructor(){n.info("Initialized binding manager with in-memory storage")}bindBotToAgent(i,t){const d=this.bindings.findIndex(n=>n.botId===i);d>=0?(this.bindings[d]={botId:i,agentId:t,lastUpdated:(new Date).toISOString()},n.info(`Updated binding: ${i} -> ${t}`)):(this.bindings.push({botId:i,agentId:t,lastUpdated:(new Date).toISOString()}),n.info(`Added binding: ${i} -> ${t}`))}getBotAgent(n){const i=this.bindings.find(i=>i.botId===n);return i?i.agentId:"default"}getAllBindings(){return[...this.bindings]}removeBinding(i){const t=this.bindings.length;this.bindings=this.bindings.filter(n=>n.botId!==i),this.bindings.length<t&&n.info(`Removed binding for bot: ${i}`)}hasBinding(n){return this.bindings.some(i=>i.botId===n)}}let i=null;export function createBindingManager(){return i||(i=new BindingManager),i}export function getBindingManager(){return i||(i=new BindingManager),i}
@@ -5,6 +5,7 @@ interface PairingRequest {
5
5
  createdAt: string;
6
6
  }
7
7
  export declare class PairingManager {
8
+ private pairingData;
8
9
  constructor();
9
10
  generatePairingCode(): string;
10
11
  getExistingPairingCode(identifier: string): string | null;
@@ -1 +1 @@
1
- import{logger as e}from"../utils/error-handling.js";import{loadPairingData as r,savePairingData as i}from"./storage.js";export class PairingManager{constructor(){e.debug("Initialized PairingManager")}generatePairingCode(){const r="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";let i="";for(let e=0;e<8;e++)i+=r.charAt(Math.floor(36*Math.random()));return e.debug("Generated new pairing code",{code:i}),i}getExistingPairingCode(s){e.debug("Checking for existing pairing code",{identifier:s});const{pairingRequests:t,approvedUsers:d}=r();for(const r in t){const n=t[r];if(n.staffId===s||n.userId===s){const o=new Date(n.createdAt),a=((new Date).getTime()-o.getTime())/36e5;if(a<=1)return e.debug("Found existing valid pairing code",{identifier:s,code:r,diffInHours:a}),r;e.debug("Found existing but expired pairing code",{identifier:s,code:r,diffInHours:a}),delete t[r],i(t,d)}}return e.debug("No existing valid pairing code found",{identifier:s}),null}storePairingRequest(s,t,d){e.info("Storing pairing request",{code:s,userId:t,staffId:d});const{pairingRequests:n,approvedUsers:o}=r();e.info("Current pairingRequests before storing:",Object.keys(n)),n[s]={code:s,userId:t,staffId:d,createdAt:(new Date).toISOString()},e.info("Pairing request stored in memory:",n[s]),i(n,o),e.info("Pairing request stored successfully",{code:s,userId:t,staffId:d})}getPairingRequest(s){e.debug("Getting pairing request",{code:s});const{pairingRequests:t,approvedUsers:d}=r(),n=t[s];if(!n)return e.debug("No pairing request found",{code:s}),null;const o=new Date(n.createdAt),a=((new Date).getTime()-o.getTime())/36e5;return a>1?(e.debug("Pairing request expired",{code:s,diffInHours:a}),delete t[s],i(t,d),null):(e.debug("Found valid pairing request",{code:s,staffId:n.staffId}),n)}approveUser(s){e.debug("Approving user",{staffId:s});const{pairingRequests:t,approvedUsers:d}=r();d.includes(s)?e.debug("User already in approved list",{staffId:s}):(e.debug("Adding user to approved list",{staffId:s}),d.push(s),i(t,d),e.debug("User added to approved list successfully",{staffId:s,approvedUsers:d}))}isUserApproved(i){try{e.debug("Checking if user is approved",{staffId:i});const{approvedUsers:s}=r(),t=s.includes(i);return e.debug("User approval status",{staffId:i,isApproved:t,approvedUsers:s}),t}catch(r){return e.error("Error checking if user is approved",{error:r,staffId:i}),!1}}removePairingRequest(e){const{pairingRequests:s,approvedUsers:t}=r();delete s[e],i(s,t)}approvePairingRequest(r){e.debug("Approving pairing request",{code:r});const i=this.getPairingRequest(r);return i?(e.debug("Pairing request found, approving user",{code:r,staffId:i.staffId}),this.approveUser(i.staffId),this.removePairingRequest(r),e.debug("Pairing request approved successfully",{code:r,staffId:i.staffId}),!0):(e.debug("Pairing request not found or expired",{code:r}),!1)}getSessionByCode(r){e.debug("Getting session by code",{code:r});const i=this.getPairingRequest(r);return i?(e.debug("Found session for code",{code:r,staffId:i.staffId}),{staffId:i.staffId}):(e.debug("No session found for code",{code:r}),null)}}export function createPairingManager(e){return new PairingManager}
1
+ import{logger as e}from"../utils/error-handling.js";export class PairingManager{pairingData;constructor(){this.pairingData={pairingRequests:{},approvedUsers:[],lastUpdated:(new Date).toISOString()},e.debug("Initialized PairingManager with in-memory storage")}generatePairingCode(){const i="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";let t="";for(let e=0;e<8;e++)t+=i.charAt(Math.floor(36*Math.random()));return e.debug("Generated new pairing code",{code:t}),t}getExistingPairingCode(i){e.debug("Checking for existing pairing code",{identifier:i});for(const t in this.pairingData.pairingRequests){const r=this.pairingData.pairingRequests[t];if(r.staffId===i||r.userId===i){const a=new Date(r.createdAt),s=((new Date).getTime()-a.getTime())/36e5;if(s<=1)return e.debug("Found existing valid pairing code",{identifier:i,code:t,diffInHours:s}),t;e.debug("Found existing but expired pairing code",{identifier:i,code:t,diffInHours:s}),delete this.pairingData.pairingRequests[t],this.pairingData.lastUpdated=(new Date).toISOString()}}return e.debug("No existing valid pairing code found",{identifier:i}),null}storePairingRequest(i,t,r){e.info("Storing pairing request",{code:i,userId:t,staffId:r}),e.info("Current pairingRequests before storing:",Object.keys(this.pairingData.pairingRequests)),this.pairingData.pairingRequests[i]={code:i,userId:t,staffId:r,createdAt:(new Date).toISOString()},this.pairingData.lastUpdated=(new Date).toISOString(),e.info("Pairing request stored in memory:",this.pairingData.pairingRequests[i]),e.info("Pairing request stored successfully",{code:i,userId:t,staffId:r})}getPairingRequest(i){e.debug("Getting pairing request",{code:i});const t=this.pairingData.pairingRequests[i];if(!t)return e.debug("No pairing request found",{code:i}),null;const r=new Date(t.createdAt),a=((new Date).getTime()-r.getTime())/36e5;return a>1?(e.debug("Pairing request expired",{code:i,diffInHours:a}),delete this.pairingData.pairingRequests[i],this.pairingData.lastUpdated=(new Date).toISOString(),null):(e.debug("Found valid pairing request",{code:i,staffId:t.staffId}),t)}approveUser(i){e.debug("Approving user",{staffId:i}),this.pairingData.approvedUsers.includes(i)?e.debug("User already in approved list",{staffId:i}):(e.debug("Adding user to approved list",{staffId:i}),this.pairingData.approvedUsers.push(i),this.pairingData.lastUpdated=(new Date).toISOString(),e.debug("User added to approved list successfully",{staffId:i,approvedUsers:this.pairingData.approvedUsers}))}isUserApproved(i){try{e.debug("Checking if user is approved",{staffId:i});const t=this.pairingData.approvedUsers.includes(i);return e.debug("User approval status",{staffId:i,isApproved:t,approvedUsers:this.pairingData.approvedUsers}),t}catch(t){return e.error("Error checking if user is approved",{error:t,staffId:i}),!1}}removePairingRequest(e){delete this.pairingData.pairingRequests[e],this.pairingData.lastUpdated=(new Date).toISOString()}approvePairingRequest(i){e.debug("Approving pairing request",{code:i});const t=this.getPairingRequest(i);return t?(e.debug("Pairing request found, approving user",{code:i,staffId:t.staffId}),this.approveUser(t.staffId),this.removePairingRequest(i),e.debug("Pairing request approved successfully",{code:i,staffId:t.staffId}),!0):(e.debug("Pairing request not found or expired",{code:i}),!1)}getSessionByCode(i){e.debug("Getting session by code",{code:i});const t=this.getPairingRequest(i);return t?(e.debug("Found session for code",{code:i,staffId:t.staffId}),{staffId:t.staffId}):(e.debug("No session found for code",{code:i}),null)}}export function createPairingManager(e){return new PairingManager}
@@ -1 +1 @@
1
- import*as e from"fs";import*as t from"path";import{logger as r}from"./error-handling.js";import{tryGetLansengerRuntime as n}from"../../openclaw-adapter/runtime-store.js";export function getStorageFilePath(){let i;const o=n();if(o&&o.state){const e=o.state.resolveStateDir();i=t.join(e,"extensions/openclaw-channel-lansenger/data"),r.info("Using runtime state directory for storage:",{stateDir:e})}else i=t.join("~/.openclaw/extensions/openclaw-channel-lansenger/data"),r.info("Using relative path for storage (runtime not available)");return e.existsSync(i)||e.mkdirSync(i,{recursive:!0}),t.join(i,"pairing-data.json")}export function readFile(t){return e.readFileSync(t,"utf8")}export function writeFile(t,r){e.writeFileSync(t,r)}export function fileExists(t){return e.existsSync(t)}export function createDirectory(t){e.existsSync(t)||e.mkdirSync(t,{recursive:!0})}
1
+ import*as r from"fs";import*as e from"path";import{logger as t}from"./error-handling.js";import{tryGetLansengerRuntime as i}from"../../openclaw-adapter/runtime-store.js";export function getStorageFilePath(){let o;const a=i();if(a&&a.state){const r=a.state.resolveStateDir();o=e.join(r,"extensions/openclaw-channel-lansenger/data"),t.info("Using runtime state directory for storage:",{stateDir:r})}else o=e.join("data"),t.info("Using relative data directory for storage");try{r.existsSync(o)||(r.mkdirSync(o,{recursive:!0}),t.info("Created storage directory:",{storageDir:o}))}catch(r){return t.error("Failed to create storage directory:",{error:r,storageDir:o}),"pairing-data.json"}return e.join(o,"pairing-data.json")}export function readFile(e){try{return r.readFileSync(e,"utf8")}catch(r){return t.error("Failed to read file:",{error:r,filePath:e}),"{}"}}export function writeFile(e,i){try{r.writeFileSync(e,i)}catch(r){t.error("Failed to write file:",{error:r,filePath:e})}}export function fileExists(e){try{return r.existsSync(e)}catch(r){return t.error("Failed to check if file exists:",{error:r,filePath:e}),!1}}export function createDirectory(e){try{r.existsSync(e)||r.mkdirSync(e,{recursive:!0})}catch(r){t.error("Failed to create directory:",{error:r,dirPath:e})}}
@@ -1 +1 @@
1
- import t from"node:fs";import e from"node:path";import n from"node:https";import o from"node:http";import{fileURLToPath as i}from"node:url";const r=i(import.meta.url),a=e.dirname(r);export function getMediaType(t,e){const n=t.toLowerCase();if(/\.(jpg|jpeg|png|gif|webp|bmp)(\?|$)/i.test(n))return"image";if(/\.(mp4|mov|avi|mkv|webm)(\?|$)/i.test(n))return"video";if(/\.(mp3|wav|ogg|m4a|aac)(\?|$)/i.test(n))return"audio";if(e){if(e.startsWith("image/"))return"image";if(e.startsWith("video/"))return"video";if(e.startsWith("audio/"))return"audio"}return"file"}export function getFileExtension(t){const e=t.match(/\.([a-zA-Z0-9]+)(\?|$)/);return e?e[1].toLowerCase():"bin"}export async function downloadToTempFile(i,r="unknown"){if(i.startsWith("/")||i.startsWith("file://")){return{path:i.replace("file://",""),isTemp:!1}}getFileExtension(i);const s=Date.now(),c=e.join(a,"../../../../workspace"),m=e.join(c,"media","inbound",r);t.existsSync(m)||t.mkdirSync(m,{recursive:!0});const p=new URL(i);let u=e.basename(p.pathname);e.extname(u)||(u+="."+getFileExtension(i));const d=`${s}_${u}`,l=e.join(m,d);return new Promise((e,a)=>{const s=i.startsWith("https")?n:o,c=t.createWriteStream(l);s.get(i,n=>{if(301===n.statusCode||302===n.statusCode){c.close();try{t.unlinkSync(l)}catch{}const o=n.headers.location;return o?void downloadToTempFile(o,r).then(e).catch(a):void a(new Error("Redirect without location header"))}if(200===n.statusCode)n.pipe(c),c.on("finish",()=>{c.close(),e({path:l,isTemp:!1})}),c.on("error",e=>{try{t.unlinkSync(l)}catch{}a(e)});else{c.close();try{t.unlinkSync(l)}catch{}a(new Error(`Failed to download: HTTP ${n.statusCode}`))}}).on("error",e=>{c.close();try{t.unlinkSync(l)}catch{}a(e)})})}export async function uploadImage(t,e){throw new Error("Lanxin image upload not implemented yet")}export async function uploadFile(t,e,n,o="stream"){throw new Error("Lanxin file upload not implemented yet")}export function cleanupTemp(e,n){if(n)try{t.unlinkSync(e)}catch{}}
1
+ import t from"node:fs";import e from"node:os";import n from"node:path";import o from"node:https";import i from"node:http";import{fileURLToPath as r}from"node:url";const a=r(import.meta.url);n.dirname(a);export function getMediaType(t,e){const n=t.toLowerCase();if(/\.(jpg|jpeg|png|gif|webp|bmp)(\?|$)/i.test(n))return"image";if(/\.(mp4|mov|avi|mkv|webm)(\?|$)/i.test(n))return"video";if(/\.(mp3|wav|ogg|m4a|aac)(\?|$)/i.test(n))return"audio";if(e){if(e.startsWith("image/"))return"image";if(e.startsWith("video/"))return"video";if(e.startsWith("audio/"))return"audio"}return"file"}export function getFileExtension(t){const e=t.match(/\.([a-zA-Z0-9]+)(\?|$)/);return e?e[1].toLowerCase():"bin"}export async function downloadToTempFile(r,a="unknown"){if(r.startsWith("/")||r.startsWith("file://")){return{path:r.replace("file://",""),isTemp:!1}}getFileExtension(r);const s=Date.now(),c=e.tmpdir(),m=n.join(c,"openclaw-lansenger","media","inbound",a);t.existsSync(m)||t.mkdirSync(m,{recursive:!0});const p=new URL(r);let d=n.basename(p.pathname);n.extname(d)||(d+="."+getFileExtension(r));const u=`${s}_${d}`,l=n.join(m,u);return new Promise((e,n)=>{const s=r.startsWith("https")?o:i,c=t.createWriteStream(l);s.get(r,o=>{if(301===o.statusCode||302===o.statusCode){c.close();try{t.unlinkSync(l)}catch{}const i=o.headers.location;return i?void downloadToTempFile(i,a).then(e).catch(n):void n(new Error("Redirect without location header"))}if(200===o.statusCode)o.pipe(c),c.on("finish",()=>{c.close(),e({path:l,isTemp:!1})}),c.on("error",e=>{try{t.unlinkSync(l)}catch{}n(e)});else{c.close();try{t.unlinkSync(l)}catch{}n(new Error(`Failed to download: HTTP ${o.statusCode}`))}}).on("error",e=>{c.close();try{t.unlinkSync(l)}catch{}n(e)})})}export async function uploadImage(t,e){throw new Error("Lanxin image upload not implemented yet")}export async function uploadFile(t,e,n,o="stream"){throw new Error("Lanxin file upload not implemented yet")}export function cleanupTemp(e,n){if(n)try{t.unlinkSync(e)}catch{}}
@@ -1 +1 @@
1
- import*as s from"fs";import*as e from"path";export const pairingSessionManager=new class{sessions=new Map;staffIdToCode=new Map;storagePath;constructor(){this.storagePath=e.join(process.cwd(),"extensions","openclaw-channel-lansenger","storage"),s.existsSync(this.storagePath)||s.mkdirSync(this.storagePath,{recursive:!0}),this.loadSessions()}loadSessions(){try{const t=e.join(this.storagePath,"pairing-sessions.json");if(s.existsSync(t)){const e=s.readFileSync(t,"utf8");JSON.parse(e).forEach(s=>{this.sessions.set(s.code,s),this.staffIdToCode.set(`${s.accountId}:${s.staffId}`,s.code)})}}catch(s){}}saveSessions(){try{const t=e.join(this.storagePath,"pairing-sessions.json"),o=Array.from(this.sessions.values());s.writeFileSync(t,JSON.stringify(o,null,2))}catch(s){}}generateCode(){const s="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";let e="";for(let t=0;t<6;t++)e+=s.charAt(Math.floor(36*Math.random()));return e}createSession(s,e){const t=this.generateCode(),o={code:t,staffId:e,createdAt:Date.now(),accountId:s};return this.sessions.set(t,o),this.staffIdToCode.set(`${s}:${e}`,t),this.saveSessions(),o}getSessionByCode(s){return this.sessions.get(s)}getSessionByStaffId(s,e){const t=this.staffIdToCode.get(`${s}:${e}`);if(t)return this.sessions.get(t)}deleteSession(s){const e=this.sessions.get(s);e&&(this.staffIdToCode.delete(`${e.accountId}:${e.staffId}`),this.sessions.delete(s),this.saveSessions())}clearSessions(s){for(const[e,t]of this.sessions.entries())t.accountId===s&&(this.staffIdToCode.delete(`${s}:${t.staffId}`),this.sessions.delete(e));this.saveSessions()}clearAllSessions(){this.sessions.clear(),this.staffIdToCode.clear(),this.saveSessions()}};
1
+ export const pairingSessionManager=new class{sessions=new Map;staffIdToCode=new Map;constructor(){}generateCode(){const s="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";let e="";for(let t=0;t<6;t++)e+=s.charAt(Math.floor(36*Math.random()));return e}createSession(s,e){const t=this.generateCode(),o={code:t,staffId:e,createdAt:Date.now(),accountId:s};return this.sessions.set(t,o),this.staffIdToCode.set(`${s}:${e}`,t),o}getSessionByCode(s){return this.sessions.get(s)}getSessionByStaffId(s,e){const t=this.staffIdToCode.get(`${s}:${e}`);if(t)return this.sessions.get(t)}deleteSession(s){const e=this.sessions.get(s);e&&(this.staffIdToCode.delete(`${e.accountId}:${e.staffId}`),this.sessions.delete(s))}clearSessions(s){for(const[e,t]of this.sessions.entries())t.accountId===s&&(this.staffIdToCode.delete(`${s}:${t.staffId}`),this.sessions.delete(e))}clearAllSessions(){this.sessions.clear(),this.staffIdToCode.clear()}};
@@ -2,7 +2,7 @@
2
2
  "id": "openclaw-channel-lansenger",
3
3
  "name": "Lansenger",
4
4
  "description": "Lansenger (蓝信) channel plugin — WebSocket long-connection bot",
5
- "version": "0.0.1",
5
+ "version": "0.0.2",
6
6
  "main": "dist/index.js",
7
7
  "kind": "channel",
8
8
  "channels": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lansenger/openclaw-channel-lansenger",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "type": "module",
5
5
  "description": "蓝信机器人插件 - 让 AI 助手接入蓝信,无需服务器 | Lanxin/Lark channel plugin for OpenClaw",
6
6
  "author": "lxfe",