@opentiny/next-sdk 0.2.9 → 0.3.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -146,30 +146,33 @@ class FloatingBlock {
146
146
 
147
147
  /**
148
148
  * 合并菜单项配置。
149
- * - sessionId:使用默认菜单 + 用户配置(可定制每一项的 show/text/icon 等)
150
- * - sessionId:不渲染任何下拉菜单,仅保留点击浮标打开对话框的能力
149
+ * - 用户明确传入 menuItems:直接使用用户配置,不受 sessionId 限制;未传 icon 时自动补充默认图标
150
+ * - sessionId 且未传 menuItems:使用默认菜单
151
+ * - 无 sessionId 且未传 menuItems:不渲染任何下拉菜单,仅保留点击浮标打开对话框的能力
151
152
  */
152
153
  private mergeMenuItems(userMenuItems?: MenuItemConfig[]): MenuItemConfig[] {
153
- // sessionId:完全关闭下拉菜单(包括 ai-chat 项),只保留点击浮标触发 onShowAIChat
154
- if (!this.options.sessionId) {
155
- return []
154
+ // action 对应的默认图标映射
155
+ const defaultIcons: Partial<Record<ActionType, string>> = {
156
+ 'qr-code': qrCode,
157
+ 'ai-chat': chat,
158
+ 'remote-url': link,
159
+ 'remote-control': scan
156
160
  }
157
161
 
158
- if (!userMenuItems) {
159
- return getDefaultMenuItems(this.options)
162
+ // 用户明确传入了 menuItems,直接使用,并补充缺失的图标
163
+ if (userMenuItems) {
164
+ return userMenuItems.map((item) => ({
165
+ ...item,
166
+ icon: item.icon ?? defaultIcons[item.action]
167
+ }))
160
168
  }
161
169
 
162
- return getDefaultMenuItems(this.options).map((defaultItem) => {
163
- const userItem = userMenuItems.find((item) => item.action === defaultItem.action)
164
- if (userItem) {
165
- return {
166
- ...defaultItem,
167
- ...userItem,
168
- show: userItem.show !== undefined ? userItem.show : defaultItem.show
169
- }
170
- }
171
- return defaultItem
172
- })
170
+ // sessionId 且无用户菜单:完全关闭下拉菜单,只保留点击浮标触发 onShowAIChat
171
+ if (!this.options.sessionId) {
172
+ return []
173
+ }
174
+
175
+ return getDefaultMenuItems(this.options)
173
176
  }
174
177
 
175
178
  private init(): void {
@@ -220,7 +223,7 @@ class FloatingBlock {
220
223
  <div class="tiny-remoter-dropdown-item__content">
221
224
  <div title="${item.tip}">${item.text}</div>
222
225
  <div class="tiny-remoter-dropdown-item__desc-wrapper">
223
- <div class="tiny-remoter-dropdown-item__desc ${item.active ? 'tiny-remoter-dropdown-item__desc--active' : ''} ${item.know ? 'tiny-remoter-dropdown-item__desc--know' : ''}">${item.desc}</div>
226
+ <div class="tiny-remoter-dropdown-item__desc ${item.active ? 'tiny-remoter-dropdown-item__desc--active' : ''} ${item.know ? 'tiny-remoter-dropdown-item__desc--know' : ''}">${item.desc ?? ''}</div>
224
227
  <div>
225
228
  ${
226
229
  item.showCopyIcon
@@ -357,13 +360,31 @@ class FloatingBlock {
357
360
  }
358
361
 
359
362
  private copyRemoteControl(): void {
360
- if (!this.options.sessionId) return
361
- this.copyToClipboard(this.options.sessionId.slice(-6))
363
+ // 优先使用用户菜单项中的 desc/text(支持自定义识别码),回退到 sessionId 末 6 位
364
+ const menuItem = this.menuItems.find((item) => item.action === 'remote-control')
365
+ const codeToCopy =
366
+ menuItem?.desc || menuItem?.text || (this.options.sessionId ? this.options.sessionId.slice(-6) : '')
367
+ if (codeToCopy) {
368
+ this.copyToClipboard(codeToCopy)
369
+ }
362
370
  }
363
371
 
364
372
  private copyRemoteURL(): void {
365
- if (!this.options.sessionId) return
366
- this.copyToClipboard(this.options.remoteUrl + this.sessionPrefix + this.options.sessionId)
373
+ const menuItem = this.menuItems.find((item) => item.action === 'remote-url')
374
+
375
+ // 构造带 sessionId 的完整遥控链接(默认行为)
376
+ const sessionUrl = this.options.sessionId
377
+ ? this.options.remoteUrl + this.sessionPrefix + this.options.sessionId
378
+ : ''
379
+
380
+ // 仅当 desc 是用户真正自定义的值(不同于裸 remoteUrl)时才优先使用,
381
+ // 否则回退到带 sessionId 的完整链接,避免默认菜单场景复制裸域名
382
+ const customDesc = menuItem?.desc && menuItem.desc !== this.options.remoteUrl ? menuItem.desc : undefined
383
+ const urlToCopy = customDesc || sessionUrl || menuItem?.text || ''
384
+
385
+ if (urlToCopy) {
386
+ this.copyToClipboard(urlToCopy)
387
+ }
367
388
  }
368
389
 
369
390
  // 实现复制到剪贴板功能
@@ -47,7 +47,7 @@ export class ExtensionClientTransport implements Transport {
47
47
  console.log('【Client Transport】处理server消息错误:', error)
48
48
  }
49
49
  },
50
- 'content->side'
50
+ 'content->bg'
51
51
  )
52
52
  }
53
53
 
@@ -63,14 +63,24 @@ export class ExtensionClientTransport implements Transport {
63
63
  this._throwError(() => this._isClosed, '【Client Transport】 已关闭,无法发送消息')
64
64
 
65
65
  // 查询 当前sessionId的最后一个tabid
66
- const sessionInfo = chrome.sessionRegistry.get(this.targetSessionId)
67
- this._throwError(() => !sessionInfo, `【Client Transport】sessionRegistry中未找到${this.targetSessionId}`)
66
+ let tabId: number | undefined
67
+ if (chrome.sessionRegistry) {
68
+ const sessionInfo = chrome.sessionRegistry.get(this.targetSessionId)
69
+ if (sessionInfo && sessionInfo.tabIds.length > 0) {
70
+ tabId = sessionInfo.tabIds[sessionInfo.tabIds.length - 1]
71
+ }
72
+ }
73
+
74
+ if (tabId == null) {
75
+ tabId = await chrome.runtime.sendMessage({ type: 'get-session-tab-id', sessionId: this.targetSessionId })
76
+ }
77
+
78
+ this._throwError(() => tabId == null, `【Client Transport】后台未找到活动的tabId用于${this.targetSessionId}`)
68
79
 
69
- const tabId = sessionInfo.tabIds[sessionInfo.tabIds.length - 1]
70
80
  sendRuntimeMessage(
71
81
  'mcp-client-to-server',
72
82
  { sessionId: this.targetSessionId, tabId, mcpMessage: message },
73
- 'side->content'
83
+ 'bg->content'
74
84
  )
75
85
  }
76
86
 
@@ -54,18 +54,7 @@ export class ContentScriptServerTransport implements Transport {
54
54
  this.sessionId = sessionId || randomUUID()
55
55
  this.tabId = tabId
56
56
 
57
- onRuntimeMessage(
58
- 'sidepanel-ready',
59
- () => {
60
- if (this._lastRegistration && this._isStarted) {
61
- this.notifyRegistration(this._lastRegistration).catch((error) => {
62
- console.log('【Content Svr Transport】 notifyRegistration 失败', error)
63
- })
64
- }
65
- },
66
- 'side->content',
67
- this.tabId
68
- )
57
+ // 移除对 sidepanel-ready 的监听,因为现在的注册信息将直接发送给长期驻留的 background,不丢失状态
69
58
  }
70
59
 
71
60
  /** 启动 transport,开始监听MCP client 消息 */
@@ -99,7 +88,7 @@ export class ContentScriptServerTransport implements Transport {
99
88
  console.log('【Content Svr Transport】 处理消息时发生错误:', error)
100
89
  }
101
90
  },
102
- 'side->content',
91
+ 'bg->content',
103
92
  this.tabId
104
93
  )
105
94
 
@@ -120,7 +109,7 @@ export class ContentScriptServerTransport implements Transport {
120
109
  sessionId: this.sessionId,
121
110
  mcpMessage: message
122
111
  },
123
- 'content->side'
112
+ 'content->bg'
124
113
  )
125
114
 
126
115
  // 判断是否为工具调用成功了!
@@ -153,7 +142,7 @@ export class ContentScriptServerTransport implements Transport {
153
142
  title: document.title
154
143
  }
155
144
  },
156
- 'content->side'
145
+ 'content->bg'
157
146
  )
158
147
  }
159
148
 
@@ -30,7 +30,7 @@ export class ExtensionPageServerTransport implements Transport {
30
30
  readonly sessionId: string
31
31
 
32
32
  // 内部状态
33
- private _messageListener1: () => void
33
+
34
34
  private _messageListener2: () => void
35
35
  private _isStarted: boolean = false
36
36
  private _isClosed: boolean = false
@@ -50,17 +50,7 @@ export class ExtensionPageServerTransport implements Transport {
50
50
  // 如果提供了 sessionId,使用提供的;否则随机生成
51
51
  this.sessionId = sessionId || randomUUID()
52
52
 
53
- this._messageListener1 = onWindowMessage(
54
- 'sidepanel-ready-to-page',
55
- () => {
56
- if (this._lastRegistration && this._isStarted) {
57
- this.notifyRegistration(this._lastRegistration).catch((error) => {
58
- console.error('【Page Svr Transport】 notifyRegistration失败:', error)
59
- })
60
- }
61
- },
62
- 'content->page'
63
- )
53
+ // 移除了对 sidepanel-ready-to-page 的监听,因为信息直接发往常驻的 background
64
54
 
65
55
  this._messageListener2 = onWindowMessage(
66
56
  'mcp-client-to-server-to-page',
@@ -146,7 +136,7 @@ export class ExtensionPageServerTransport implements Transport {
146
136
  if (this._isClosed) return
147
137
 
148
138
  try {
149
- this._messageListener1 && this._messageListener1()
139
+
150
140
  this._messageListener2 && this._messageListener2()
151
141
 
152
142
  this._isClosed = true
package/vite-build-tsc.ts CHANGED
@@ -35,10 +35,13 @@ export default defineConfig(() => {
35
35
  build: {
36
36
  emptyOutDir: false,
37
37
  lib: {
38
- entry: 'index.ts',
38
+ entry: {
39
+ index: 'index.ts',
40
+ core: 'core.ts'
41
+ },
39
42
  name: 'NEXT-SDK',
40
43
  formats: ['es'],
41
- fileName: () => 'index.js'
44
+ fileName: (format, entryName) => `${entryName}.js`
42
45
  },
43
46
  rollupOptions: {
44
47
  // 排除第三方依赖,保留本地文件