@auto-ai/agent 2.1.121 → 2.1.122
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/.env.example +2 -1
- package/dist/404/index.html +1 -1
- package/dist/404.html +1 -1
- package/dist/_next/static/chunks/19aa69c07b3642d5.js +1 -0
- package/dist/_next/static/chunks/24459c7365a2b28b.js +1 -0
- package/dist/_next/static/chunks/{d3e2070a86378cfb.js → 33eeef286c328da0.js} +1 -1
- package/dist/_next/static/chunks/3407244006d6a98a.js +1 -0
- package/dist/_next/static/chunks/566e152e480b267a.js +1 -0
- package/dist/_next/static/chunks/6ad4268160f361a6.js +1 -0
- package/dist/_next/static/chunks/{d9a278a2a26e8ee5.js → 6f9a48a7f83e669a.js} +1 -1
- package/dist/_next/static/chunks/7658b5b9c2865eb1.js +1 -0
- package/dist/_next/static/chunks/7a5fd448b280dd64.js +1 -0
- package/dist/_next/static/chunks/{fa677aa06f1c0539.js → 98f0c5604e839ba2.js} +1 -1
- package/dist/_next/static/chunks/a38eccf0bb5ca1e9.js +1 -0
- package/dist/_next/static/chunks/b29a354245bfc377.css +1 -0
- package/dist/_next/static/chunks/b76778c5811ef7a1.js +1 -0
- package/dist/_next/static/chunks/c2bed9d5fa7be4bd.js +1 -0
- package/dist/_next/static/chunks/c5a4977aae6a008c.js +1 -0
- package/dist/_next/static/chunks/e7bd145455a541af.css +4 -0
- package/dist/_next/static/chunks/f2bb685629307d4d.js +1 -0
- package/dist/_next/static/chunks/f7e71ce1c236f806.js +1 -0
- package/dist/_next/static/chunks/{67acc15b8a448e1a.js → fc4be3bcf72559a0.js} +1 -1
- package/dist/index.html +1 -1
- package/dist/index.txt +16 -16
- package/dist/manage/about/index.html +2 -2
- package/dist/manage/about/index.txt +19 -19
- package/dist/manage/add-account/basic/index.html +2 -2
- package/dist/manage/add-account/basic/index.txt +21 -21
- package/dist/manage/add-account/index.html +2 -2
- package/dist/manage/add-account/index.txt +21 -21
- package/dist/manage/agent-teams/index.html +2 -2
- package/dist/manage/agent-teams/index.txt +21 -21
- package/dist/manage/env/index.html +2 -2
- package/dist/manage/env/index.txt +21 -21
- package/dist/manage/general/index.html +2 -2
- package/dist/manage/general/index.txt +19 -19
- package/dist/manage/index.html +1 -1
- package/dist/manage/index.txt +16 -16
- package/dist/manage/mcp/index.html +2 -2
- package/dist/manage/mcp/index.txt +21 -21
- package/dist/manage/permissions/index.html +2 -2
- package/dist/manage/permissions/index.txt +19 -19
- package/dist/manage/skills/index.html +2 -2
- package/dist/manage/skills/index.txt +21 -21
- package/dist/manage/task/index.html +2 -2
- package/dist/manage/task/index.txt +19 -19
- package/dist/manage/teams/index.html +2 -2
- package/dist/manage/teams/index.txt +19 -19
- package/dist/manage/tools/index.html +2 -2
- package/dist/manage/tools/index.txt +21 -21
- package/dist/ws-test.html +90 -64
- package/mcps-runtime/claude-geelib-channel/.mcp.json +18 -0
- package/mcps-runtime/claude-geelib-channel/server/boot.mjs +32 -0
- package/mcps-runtime/claude-geelib-channel/server/geelib-api.mjs +192 -0
- package/mcps-runtime/claude-geelib-channel/server/geelib-auth.mjs +147 -0
- package/mcps-runtime/claude-geelib-channel/server/geelib-client.mjs +63 -0
- package/mcps-runtime/claude-geelib-channel/server/index.mjs +451 -0
- package/mcps-runtime/claude-geelib-channel/server/poll.mjs +457 -0
- package/mcps-runtime/claude-geelib-channel/server/state.mjs +216 -0
- package/package.json +6 -6
- package/tools-runtime/git-tool/index.cjs +51 -3
- package/tools-runtime/git-tool/src/workspace.ts +101 -4
- package/dist/_next/static/chunks/249606605eed1993.js +0 -1
- package/dist/_next/static/chunks/424d3f3f176d43d7.js +0 -1
- package/dist/_next/static/chunks/4302af16b34bf750.js +0 -1
- package/dist/_next/static/chunks/4a073924e062c459.css +0 -1
- package/dist/_next/static/chunks/6209b42cbfcf288a.js +0 -1
- package/dist/_next/static/chunks/83bf6e4bc0aad48b.css +0 -4
- package/dist/_next/static/chunks/8b34d657c6bbb8df.js +0 -1
- package/dist/_next/static/chunks/904ad158fd721117.js +0 -1
- package/dist/_next/static/chunks/99063f8d79783308.js +0 -1
- package/dist/_next/static/chunks/9cd912a1967f10df.js +0 -1
- package/dist/_next/static/chunks/c52dcbe269bb02d0.js +0 -1
- package/dist/_next/static/chunks/d01957b1055b357a.js +0 -1
- package/dist/_next/static/chunks/dacc94cf10289334.js +0 -1
- package/dist/_next/static/chunks/fff9d250e482f00e.js +0 -1
- package/skills-runtime/geelib/SKILL.md +0 -229
- package/skills-runtime/geelib/geelib-poller-state.json +0 -17
- package/skills-runtime/geelib/geelib.mjs +0 -762
- /package/dist/_next/static/{Uk25KzeENFNl8wcmEtL4K → pVB1xZbEW09ksdJlV12Zn}/_buildManifest.js +0 -0
- /package/dist/_next/static/{Uk25KzeENFNl8wcmEtL4K → pVB1xZbEW09ksdJlV12Zn}/_clientMiddlewareManifest.json +0 -0
- /package/dist/_next/static/{Uk25KzeENFNl8wcmEtL4K → pVB1xZbEW09ksdJlV12Zn}/_ssgManifest.js +0 -0
package/dist/ws-test.html
CHANGED
|
@@ -2901,7 +2901,7 @@
|
|
|
2901
2901
|
</button>
|
|
2902
2902
|
</div>
|
|
2903
2903
|
<p id="mcpItemConfigHint" class="tool-files-sub" style="margin: 0 1rem 0.5rem; line-height: 1.4">
|
|
2904
|
-
标准 mcp.json 单条 server 配置(与 Cursor mcp.json 相同):<code>{ "command": "...", "args": [...], "env": {...} }</code
|
|
2904
|
+
标准 mcp.json 单条 server 配置(与 Cursor mcp.json 相同):<code>{ "command": "...", "args": [...], "env": {...} }</code>。runtime MCP 保存到当前包目录 <code>.mcp.json</code>;remote MCP 保存到 agent <code>.mcp.json</code>。
|
|
2905
2905
|
</p>
|
|
2906
2906
|
<textarea id="mcpItemConfigEditor" class="agent-md-editor" spellcheck="false" placeholder="加载中…"></textarea>
|
|
2907
2907
|
<div class="agent-md-modal-foot">
|
|
@@ -3228,7 +3228,6 @@
|
|
|
3228
3228
|
<div class="schedule-manage-toolbar">
|
|
3229
3229
|
<button type="button" class="btn-system-settings" id="btnScheduleRefresh">刷新</button>
|
|
3230
3230
|
<button type="button" class="btn-system-settings" id="btnScheduleCreateToggle">新建任务</button>
|
|
3231
|
-
<button type="button" class="btn-system-settings" id="btnScheduleGeelibPreset">Geelib 巡检</button>
|
|
3232
3231
|
</div>
|
|
3233
3232
|
<div id="scheduleCreateForm" class="schedule-create-form" hidden>
|
|
3234
3233
|
<div class="schedule-create-row">
|
|
@@ -3403,7 +3402,6 @@
|
|
|
3403
3402
|
const btnScheduleManageModalClose = $('btnScheduleManageModalClose')
|
|
3404
3403
|
const btnScheduleRefresh = $('btnScheduleRefresh')
|
|
3405
3404
|
const btnScheduleCreateToggle = $('btnScheduleCreateToggle')
|
|
3406
|
-
const btnScheduleGeelibPreset = $('btnScheduleGeelibPreset')
|
|
3407
3405
|
const scheduleCreateForm = $('scheduleCreateForm')
|
|
3408
3406
|
const scheduleSessionSelect = $('scheduleSessionSelect')
|
|
3409
3407
|
const schedulePromptInput = $('schedulePromptInput')
|
|
@@ -3964,9 +3962,17 @@
|
|
|
3964
3962
|
}
|
|
3965
3963
|
const SHOW_TEAMMATE_EXIT_LIFECYCLE = true
|
|
3966
3964
|
let renderScheduled = false
|
|
3965
|
+
/** HTTP 历史回放进行中:暂存实时 conversation.delta,避免与回放竞态写乱 transcript 下标 */
|
|
3966
|
+
let sessionReplayInProgress = false
|
|
3967
|
+
const pendingConversationDeltaEnvelopes = []
|
|
3967
3968
|
|
|
3968
3969
|
function sourceAgentPayloadToText(payload) {
|
|
3969
3970
|
if (!payload || typeof payload !== 'object') return ''
|
|
3971
|
+
if (payload.state === 'console') {
|
|
3972
|
+
const consoleLine =
|
|
3973
|
+
typeof payload.message === 'string' ? payload.message.trim() : ''
|
|
3974
|
+
if (consoleLine) return consoleLine
|
|
3975
|
+
}
|
|
3970
3976
|
const t = typeof payload.type === 'string' ? payload.type : 'unknown'
|
|
3971
3977
|
if (t === 'turn.terminal') {
|
|
3972
3978
|
const resultText = typeof payload.resultText === 'string' ? payload.resultText : ''
|
|
@@ -4058,6 +4064,44 @@
|
|
|
4058
4064
|
return buffer
|
|
4059
4065
|
}
|
|
4060
4066
|
|
|
4067
|
+
/**
|
|
4068
|
+
* 业务语义:conversation.delta 的 index 是 transcript 全局下标(续聊时可能远大于当前 buffer 长度)。
|
|
4069
|
+
* 必须把槽位扩到 index 再写入,禁止把 index=206 的消息 push 到 buffer[0]。
|
|
4070
|
+
*/
|
|
4071
|
+
function padRunBufferThroughIndex(runBuffer, index) {
|
|
4072
|
+
while (runBuffer.length <= index) {
|
|
4073
|
+
runBuffer.push(null)
|
|
4074
|
+
}
|
|
4075
|
+
}
|
|
4076
|
+
|
|
4077
|
+
function applyConversationDeltaToRunBuffer(runBuffer, action, index, runMessage) {
|
|
4078
|
+
if (index < 0) return
|
|
4079
|
+
if (action === 'message_removed') {
|
|
4080
|
+
if (index < runBuffer.length) {
|
|
4081
|
+
runBuffer.splice(index, 1)
|
|
4082
|
+
}
|
|
4083
|
+
return
|
|
4084
|
+
}
|
|
4085
|
+
if (action === 'message_added') {
|
|
4086
|
+
if (index <= runBuffer.length) {
|
|
4087
|
+
runBuffer.splice(index, 0, runMessage)
|
|
4088
|
+
} else {
|
|
4089
|
+
padRunBufferThroughIndex(runBuffer, index - 1)
|
|
4090
|
+
runBuffer.push(runMessage)
|
|
4091
|
+
}
|
|
4092
|
+
return
|
|
4093
|
+
}
|
|
4094
|
+
padRunBufferThroughIndex(runBuffer, index)
|
|
4095
|
+
runBuffer[index] = runMessage
|
|
4096
|
+
}
|
|
4097
|
+
|
|
4098
|
+
function flushPendingConversationDeltas() {
|
|
4099
|
+
const pending = pendingConversationDeltaEnvelopes.splice(0)
|
|
4100
|
+
for (let i = 0; i < pending.length; i++) {
|
|
4101
|
+
applyWsEnvelopeV3(pending[i])
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4104
|
+
|
|
4061
4105
|
function isNearBottom(el) {
|
|
4062
4106
|
if (!el) return true
|
|
4063
4107
|
const gap = el.scrollHeight - (el.scrollTop + el.clientHeight)
|
|
@@ -4298,12 +4342,20 @@
|
|
|
4298
4342
|
if (t === 'user') {
|
|
4299
4343
|
const body = extractMessageBody(m)
|
|
4300
4344
|
if (!body.trim()) continue
|
|
4345
|
+
const isToolResult =
|
|
4346
|
+
Array.isArray(m.message && m.message.content) &&
|
|
4347
|
+
m.message.content.some(function (block) {
|
|
4348
|
+
return block && block.type === 'tool_result'
|
|
4349
|
+
})
|
|
4301
4350
|
const div = document.createElement('div')
|
|
4302
4351
|
div.className = 'chat-msg chat-msg-user'
|
|
4303
4352
|
applyScheduledMsgClass(div, isScheduled)
|
|
4304
4353
|
const lab = document.createElement('div')
|
|
4305
4354
|
lab.className = 'chat-msg-label'
|
|
4306
|
-
lab.textContent = formatScheduledLabel(
|
|
4355
|
+
lab.textContent = formatScheduledLabel(
|
|
4356
|
+
(isToolResult ? 'Tool Result' : 'User') + ' · agent=' + messageAgent,
|
|
4357
|
+
isScheduled,
|
|
4358
|
+
)
|
|
4307
4359
|
const bodyEl = document.createElement('div')
|
|
4308
4360
|
bodyEl.className = 'chat-user-body'
|
|
4309
4361
|
setMessageBodyEl(bodyEl, body)
|
|
@@ -4314,12 +4366,20 @@
|
|
|
4314
4366
|
} else if (t === 'assistant') {
|
|
4315
4367
|
const body = extractMessageBody(m)
|
|
4316
4368
|
if (!body.trim()) continue
|
|
4369
|
+
const isToolCall =
|
|
4370
|
+
Array.isArray(m.message && m.message.content) &&
|
|
4371
|
+
m.message.content.some(function (block) {
|
|
4372
|
+
return block && block.type === 'tool_use'
|
|
4373
|
+
})
|
|
4317
4374
|
const div = document.createElement('div')
|
|
4318
4375
|
div.className = 'chat-msg chat-msg-assistant'
|
|
4319
4376
|
applyScheduledMsgClass(div, isScheduled)
|
|
4320
4377
|
const lab = document.createElement('div')
|
|
4321
4378
|
lab.className = 'chat-msg-label'
|
|
4322
|
-
lab.textContent = formatScheduledLabel(
|
|
4379
|
+
lab.textContent = formatScheduledLabel(
|
|
4380
|
+
(isToolCall ? 'Tool Call' : 'Assistant') + ' · agent=' + messageAgent,
|
|
4381
|
+
isScheduled,
|
|
4382
|
+
)
|
|
4323
4383
|
const md = document.createElement('div')
|
|
4324
4384
|
md.className = 'chat-md'
|
|
4325
4385
|
md.innerHTML = renderMd(body)
|
|
@@ -4584,6 +4644,8 @@
|
|
|
4584
4644
|
chatState.streamByRun.clear()
|
|
4585
4645
|
chatState.sourceAgentMessages = []
|
|
4586
4646
|
chatState.seenEventIds.clear()
|
|
4647
|
+
sessionReplayInProgress = false
|
|
4648
|
+
pendingConversationDeltaEnvelopes.length = 0
|
|
4587
4649
|
autoScrollState.mode = 'STICKY_BOTTOM'
|
|
4588
4650
|
if (logEl) logEl.textContent = ''
|
|
4589
4651
|
requestRenderChat()
|
|
@@ -4665,13 +4727,17 @@
|
|
|
4665
4727
|
function applyWsEnvelopeV3(data) {
|
|
4666
4728
|
if (!data || typeof data !== 'object') return false
|
|
4667
4729
|
if (data.protocolVersion !== 3) return false
|
|
4730
|
+
const runId = typeof data.runId === 'string' ? data.runId : 'main'
|
|
4731
|
+
const payload = data.data && typeof data.data === 'object' ? data.data : {}
|
|
4732
|
+
const type = typeof data.type === 'string' ? data.type : 'unknown'
|
|
4733
|
+
if (type === 'conversation.delta' && sessionReplayInProgress) {
|
|
4734
|
+
pendingConversationDeltaEnvelopes.push(data)
|
|
4735
|
+
return true
|
|
4736
|
+
}
|
|
4668
4737
|
if (typeof data.eventId === 'string' && data.eventId) {
|
|
4669
4738
|
if (chatState.seenEventIds.has(data.eventId)) return true
|
|
4670
4739
|
chatState.seenEventIds.add(data.eventId)
|
|
4671
4740
|
}
|
|
4672
|
-
const runId = typeof data.runId === 'string' ? data.runId : 'main'
|
|
4673
|
-
const payload = data.data && typeof data.data === 'object' ? data.data : {}
|
|
4674
|
-
const type = typeof data.type === 'string' ? data.type : 'unknown'
|
|
4675
4741
|
if (type === 'conversation.delta') {
|
|
4676
4742
|
const action = typeof payload.action === 'string' ? payload.action : ''
|
|
4677
4743
|
const index = Number.isInteger(payload.index) ? payload.index : -1
|
|
@@ -4688,32 +4754,7 @@
|
|
|
4688
4754
|
: '',
|
|
4689
4755
|
arrivalSeq: ++chatState.eventClock,
|
|
4690
4756
|
}
|
|
4691
|
-
|
|
4692
|
-
if (index >= 0 && index < runBuffer.length) {
|
|
4693
|
-
runBuffer.splice(index, 1)
|
|
4694
|
-
}
|
|
4695
|
-
} else if (action === 'message_added') {
|
|
4696
|
-
if (index >= 0) {
|
|
4697
|
-
if (index >= runBuffer.length) {
|
|
4698
|
-
runBuffer.push(runMessage)
|
|
4699
|
-
} else {
|
|
4700
|
-
runBuffer.splice(index, 0, runMessage)
|
|
4701
|
-
}
|
|
4702
|
-
}
|
|
4703
|
-
} else if (
|
|
4704
|
-
action === 'message_updated' ||
|
|
4705
|
-
action === 'tool_call' ||
|
|
4706
|
-
action === 'tool_result' ||
|
|
4707
|
-
action === 'message_completed'
|
|
4708
|
-
) {
|
|
4709
|
-
if (index >= 0) {
|
|
4710
|
-
if (index >= runBuffer.length) {
|
|
4711
|
-
runBuffer.push(runMessage)
|
|
4712
|
-
} else {
|
|
4713
|
-
runBuffer[index] = runMessage
|
|
4714
|
-
}
|
|
4715
|
-
}
|
|
4716
|
-
}
|
|
4757
|
+
applyConversationDeltaToRunBuffer(runBuffer, action, index, runMessage)
|
|
4717
4758
|
requestRenderChat()
|
|
4718
4759
|
return true
|
|
4719
4760
|
}
|
|
@@ -5170,6 +5211,8 @@
|
|
|
5170
5211
|
async function loadSessionReplayViaHttp(sessionId) {
|
|
5171
5212
|
const sid = typeof sessionId === 'string' ? sessionId.trim() : ''
|
|
5172
5213
|
if (!sid) return
|
|
5214
|
+
sessionReplayInProgress = true
|
|
5215
|
+
pendingConversationDeltaEnvelopes.length = 0
|
|
5173
5216
|
try {
|
|
5174
5217
|
const r = await fetch(buildSessionReplayUrl(sid))
|
|
5175
5218
|
const data = await r.json()
|
|
@@ -5182,7 +5225,6 @@
|
|
|
5182
5225
|
for (let i = 0; i < envelopes.length; i++) {
|
|
5183
5226
|
applyWsEnvelopeV3(envelopes[i])
|
|
5184
5227
|
}
|
|
5185
|
-
requestRenderChat()
|
|
5186
5228
|
logLine('session-replay-http', {
|
|
5187
5229
|
sessionId: sid,
|
|
5188
5230
|
messageCount: data.messageCount,
|
|
@@ -5191,6 +5233,10 @@
|
|
|
5191
5233
|
} catch (e) {
|
|
5192
5234
|
logLine('session-replay-http', String(e))
|
|
5193
5235
|
setStatus('历史回放失败: ' + e, 'err')
|
|
5236
|
+
} finally {
|
|
5237
|
+
sessionReplayInProgress = false
|
|
5238
|
+
flushPendingConversationDeltas()
|
|
5239
|
+
requestRenderChat()
|
|
5194
5240
|
}
|
|
5195
5241
|
}
|
|
5196
5242
|
|
|
@@ -5262,20 +5308,6 @@
|
|
|
5262
5308
|
}
|
|
5263
5309
|
}
|
|
5264
5310
|
|
|
5265
|
-
/** Geelib 定时巡检快捷模板:/geelib poll,每分钟循环 */
|
|
5266
|
-
function applyGeelibSchedulePreset() {
|
|
5267
|
-
if (scheduleCreateForm) scheduleCreateForm.hidden = false
|
|
5268
|
-
populateScheduleSessionSelect()
|
|
5269
|
-
if (schedulePromptInput) schedulePromptInput.value = '/geelib poll'
|
|
5270
|
-
document.querySelectorAll('input[name="scheduleTriggerMode"]').forEach(function (el) {
|
|
5271
|
-
el.checked = el.value === 'cron'
|
|
5272
|
-
})
|
|
5273
|
-
if (scheduleDelayRow) scheduleDelayRow.hidden = true
|
|
5274
|
-
if (scheduleCronRow) scheduleCronRow.hidden = false
|
|
5275
|
-
if (scheduleCronInput) scheduleCronInput.value = '* * * * *'
|
|
5276
|
-
if (scheduleRecurringInput) scheduleRecurringInput.checked = true
|
|
5277
|
-
}
|
|
5278
|
-
|
|
5279
5311
|
/** 渲染定时任务表格 */
|
|
5280
5312
|
function renderScheduleTaskTable(tasks, timezone) {
|
|
5281
5313
|
if (!scheduleTaskTableBody || !scheduleManageEmpty) return
|
|
@@ -9026,11 +9058,6 @@
|
|
|
9026
9058
|
if (!scheduleCreateForm.hidden) populateScheduleSessionSelect()
|
|
9027
9059
|
})
|
|
9028
9060
|
}
|
|
9029
|
-
if (btnScheduleGeelibPreset) {
|
|
9030
|
-
btnScheduleGeelibPreset.addEventListener('click', function () {
|
|
9031
|
-
applyGeelibSchedulePreset()
|
|
9032
|
-
})
|
|
9033
|
-
}
|
|
9034
9061
|
if (btnScheduleCreateCancel && scheduleCreateForm) {
|
|
9035
9062
|
btnScheduleCreateCancel.addEventListener('click', function () {
|
|
9036
9063
|
scheduleCreateForm.hidden = true
|
|
@@ -9243,16 +9270,15 @@
|
|
|
9243
9270
|
agentEnvSessionTabStrip.setAttribute('aria-label', '环境变量、编辑 agent.md、设置')
|
|
9244
9271
|
agentEnvSessionTabStrip.removeAttribute('hidden')
|
|
9245
9272
|
}
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
|
|
9253
|
-
|
|
9254
|
-
|
|
9255
|
-
}
|
|
9273
|
+
/** 每次打开设置弹窗都拉最新 schema,避免后端新增字段后页面仍用旧缓存。 */
|
|
9274
|
+
void loadProjectEnvDefaults().then(function () {
|
|
9275
|
+
const latestEnvObj =
|
|
9276
|
+
agentConfigState.env && typeof agentConfigState.env === 'object'
|
|
9277
|
+
? agentConfigState.env
|
|
9278
|
+
: {}
|
|
9279
|
+
agentEnvFieldValues = buildAgentEnvFieldValues(latestEnvObj)
|
|
9280
|
+
renderAgentEnvList()
|
|
9281
|
+
})
|
|
9256
9282
|
renderAgentEnvHeaderTabs()
|
|
9257
9283
|
syncAgentEnvTabPanels()
|
|
9258
9284
|
agentEnvModal.classList.add('is-open')
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"geelib": {
|
|
4
|
+
"command": "node",
|
|
5
|
+
"args": [
|
|
6
|
+
"${CLAUDE_PLUGIN_ROOT}/server/boot.mjs"
|
|
7
|
+
],
|
|
8
|
+
"env": {
|
|
9
|
+
"GEELIB_USER": "${GEELIB_USER}",
|
|
10
|
+
"GEELIB_PASSWD": "${GEELIB_PASSWD}",
|
|
11
|
+
"GEELIB_BASE_URL": "${GEELIB_BASE_URL:-https://geelib.qihoo.net}",
|
|
12
|
+
"GEELIB_SUB_ID": "${GEELIB_SUB_ID}",
|
|
13
|
+
"GEELIB_STATE_DIR": "${WS_AGENTS_ROOT}/mcps-runtime/claude-geelib-channel/.state",
|
|
14
|
+
"GEELIB_POLL_INTERVAL_MS": "${GEELIB_POLL_INTERVAL_MS:-60000}"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { mkdirSync, appendFileSync } from 'node:fs'
|
|
2
|
+
import { dirname, join } from 'node:path'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
4
|
+
|
|
5
|
+
const stateDir =
|
|
6
|
+
process.env.GEELIB_STATE_DIR ||
|
|
7
|
+
join(homedir(), '.claude', 'channels', 'geelib')
|
|
8
|
+
const bootLog = join(stateDir, 'boot.log')
|
|
9
|
+
mkdirSync(dirname(bootLog), { recursive: true })
|
|
10
|
+
|
|
11
|
+
function log(line) {
|
|
12
|
+
appendFileSync(bootLog, `${new Date().toISOString()} ${line}\n`, {
|
|
13
|
+
encoding: 'utf8',
|
|
14
|
+
mode: 0o600,
|
|
15
|
+
flag: 'a',
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
log(`[BOOT] geelib-channel boot.mjs start pid=${process.pid}`)
|
|
20
|
+
log(
|
|
21
|
+
`[BOOT] env GEELIB_STATE_DIR=${process.env.GEELIB_STATE_DIR || ''} GEELIB_POLL_INTERVAL_MS=${process.env.GEELIB_POLL_INTERVAL_MS || ''} GEELIB_SUB_ID=${process.env.GEELIB_SUB_ID || ''}`,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
process.on('uncaughtException', err => {
|
|
25
|
+
log(`[BOOT] uncaughtException ${err?.stack || err}`)
|
|
26
|
+
})
|
|
27
|
+
process.on('unhandledRejection', err => {
|
|
28
|
+
log(`[BOOT] unhandledRejection ${err?.stack || err}`)
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
await import('./index.mjs')
|
|
32
|
+
log('[BOOT] imported index.mjs successfully')
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { geelibGet, geelibPost } from './geelib-client.mjs'
|
|
2
|
+
|
|
3
|
+
const PRIORITY_MAP = {
|
|
4
|
+
low: 1,
|
|
5
|
+
medium: 2,
|
|
6
|
+
high: 3,
|
|
7
|
+
urgent: 4,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function cmdGetUserInfo() {
|
|
11
|
+
return geelibGet('/ones/user/userInfo', { need_share: 0 })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function cmdListProjects(query = '') {
|
|
15
|
+
return geelibGet('/projects/subBusMgr/getCanAccessSubList', {
|
|
16
|
+
query,
|
|
17
|
+
simple: 2,
|
|
18
|
+
})
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function cmdGetProjectDetail(subId) {
|
|
22
|
+
return geelibGet('/projects/subBusMgr/getSubDetail', { sub_id: subId })
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function cmdListProjectMembers(subId) {
|
|
26
|
+
return geelibGet('/projects/subBusMgr/getSubUserListSortByInitial', {
|
|
27
|
+
sub_id: subId,
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function cmdListMatterTypes(subId) {
|
|
32
|
+
return geelibGet('/matter/Matter/getMatterType', {
|
|
33
|
+
sub_id: subId,
|
|
34
|
+
page: 0,
|
|
35
|
+
pageSize: 9999,
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function cmdListMatterStatuses(subId, typeId) {
|
|
40
|
+
return geelibGet('/matter/matterType/getMatterTypeStatusList', {
|
|
41
|
+
sub_id: subId,
|
|
42
|
+
type_id: typeId,
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** 从 getMatterList 响应中解析工作项列表(GeeLib 返回 matterList)。 */
|
|
47
|
+
export function extractMatterList(data) {
|
|
48
|
+
if (!data || typeof data !== 'object') {
|
|
49
|
+
return []
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(data.matterList)) {
|
|
52
|
+
return data.matterList
|
|
53
|
+
}
|
|
54
|
+
if (Array.isArray(data.list)) {
|
|
55
|
+
return data.list
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(data.data)) {
|
|
58
|
+
return data.data
|
|
59
|
+
}
|
|
60
|
+
return []
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export async function cmdListMatters(opts) {
|
|
64
|
+
const customContent = {}
|
|
65
|
+
if (opts.statusId !== undefined) {
|
|
66
|
+
customContent.status = [opts.statusId]
|
|
67
|
+
}
|
|
68
|
+
if (opts.assigneeId !== undefined) {
|
|
69
|
+
customContent.executor = [opts.assigneeId]
|
|
70
|
+
}
|
|
71
|
+
const body = {
|
|
72
|
+
sub_id: opts.subId,
|
|
73
|
+
type_id: [opts.typeId],
|
|
74
|
+
page: opts.page ?? 1,
|
|
75
|
+
pageSize: opts.pageSize ?? 20,
|
|
76
|
+
title: opts.keyword ?? '',
|
|
77
|
+
order_by: [],
|
|
78
|
+
customContent,
|
|
79
|
+
is_favor: 0,
|
|
80
|
+
simple: 0,
|
|
81
|
+
from_v3: 1,
|
|
82
|
+
tree: 0,
|
|
83
|
+
need_user_name: 1,
|
|
84
|
+
}
|
|
85
|
+
return geelibPost('/matter/Matter/getMatterList', body)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export async function cmdGetMatter(subId, matterId) {
|
|
89
|
+
return geelibGet('/matter/Matter/getMatterDetail', {
|
|
90
|
+
sub_id: subId,
|
|
91
|
+
id: matterId,
|
|
92
|
+
need_options: 1,
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export async function cmdUpdateMatter(opts) {
|
|
97
|
+
const results = []
|
|
98
|
+
|
|
99
|
+
const hasOtherFields =
|
|
100
|
+
opts.title !== undefined ||
|
|
101
|
+
opts.description !== undefined ||
|
|
102
|
+
opts.assigneeId !== undefined ||
|
|
103
|
+
opts.priority !== undefined ||
|
|
104
|
+
opts.progress !== undefined ||
|
|
105
|
+
opts.sprintId !== undefined
|
|
106
|
+
|
|
107
|
+
if (hasOtherFields) {
|
|
108
|
+
const body = {
|
|
109
|
+
sub_id: opts.subId,
|
|
110
|
+
id: opts.matterId,
|
|
111
|
+
}
|
|
112
|
+
if (opts.title !== undefined) body.title = opts.title
|
|
113
|
+
if (opts.description !== undefined) body.content = opts.description
|
|
114
|
+
if (opts.assigneeId !== undefined) body.executor = opts.assigneeId
|
|
115
|
+
if (opts.priority !== undefined) {
|
|
116
|
+
body.priority = PRIORITY_MAP[opts.priority] ?? opts.priority
|
|
117
|
+
}
|
|
118
|
+
if (opts.progress !== undefined) body.progress = opts.progress
|
|
119
|
+
if (opts.sprintId !== undefined) body.sprint_id = opts.sprintId
|
|
120
|
+
const r = await geelibPost('/matter/Matter/editMatter', body)
|
|
121
|
+
results.push({ fields: 'other', ...r })
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (opts.statusId !== undefined) {
|
|
125
|
+
const statusBody = {
|
|
126
|
+
sub_id: String(opts.subId),
|
|
127
|
+
id: opts.matterId,
|
|
128
|
+
data: { cf_id: '1', cf_value: String(opts.statusId) },
|
|
129
|
+
additional_attribute: [],
|
|
130
|
+
remark: '',
|
|
131
|
+
toUsers: [],
|
|
132
|
+
}
|
|
133
|
+
const sr = await geelibPost('/matter/Matter/editMatter', statusBody)
|
|
134
|
+
|
|
135
|
+
if (sr.errno === 2000) {
|
|
136
|
+
const detail = await geelibGet('/matter/Matter/getMatterDetail', {
|
|
137
|
+
sub_id: opts.subId,
|
|
138
|
+
id: opts.matterId,
|
|
139
|
+
need_options: 1,
|
|
140
|
+
})
|
|
141
|
+
const actualStatus = detail.data?.matter_status
|
|
142
|
+
if (actualStatus !== opts.statusId) {
|
|
143
|
+
const missingFields = (detail.data?.matterCustomAttributes ?? [])
|
|
144
|
+
.filter(a => a.is_required && a.matterCustomAttributeValue === null)
|
|
145
|
+
.map(a => `「${a.cf_name}」(${a.cf_key})`)
|
|
146
|
+
const hint =
|
|
147
|
+
missingFields.length > 0
|
|
148
|
+
? `原因:工作项存在未填的必填字段:${missingFields.join('、')}。请先在 Geelib 网页端补全后重试。`
|
|
149
|
+
: '状态未变更,可能存在未知的状态流转限制。'
|
|
150
|
+
results.push({
|
|
151
|
+
fields: 'status',
|
|
152
|
+
errno: sr.errno,
|
|
153
|
+
errmsg: `API 返回成功但状态实际未变更(当前状态:${detail.data?.status_name ?? actualStatus})。${hint}`,
|
|
154
|
+
})
|
|
155
|
+
} else {
|
|
156
|
+
results.push({
|
|
157
|
+
fields: 'status',
|
|
158
|
+
errno: 2000,
|
|
159
|
+
errmsg: '状态变更成功',
|
|
160
|
+
actual_status: detail.data?.status_name,
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
results.push({ fields: 'status', ...sr })
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (results.length === 0) {
|
|
169
|
+
return { errno: 2000, errmsg: '无需更新(未提供任何修改字段)' }
|
|
170
|
+
}
|
|
171
|
+
if (results.length === 1) {
|
|
172
|
+
return results[0]
|
|
173
|
+
}
|
|
174
|
+
return results
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export async function cmdGetComments(subId, matterId) {
|
|
178
|
+
return geelibGet('/bservice/Comment/getList', {
|
|
179
|
+
sub_id: subId,
|
|
180
|
+
type: 'matter',
|
|
181
|
+
id: matterId,
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export async function cmdAddComment(subId, matterId, content) {
|
|
186
|
+
return geelibPost('/bservice/Comment/add', {
|
|
187
|
+
sub_id: subId,
|
|
188
|
+
type: 'matter',
|
|
189
|
+
id: matterId,
|
|
190
|
+
content,
|
|
191
|
+
})
|
|
192
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/** GeeLib SSO 登录与 Cookie 会话管理 */
|
|
2
|
+
|
|
3
|
+
const SSO_LOGIN_URL = 'https://login.ops.qihoo.net:4436/sec/login'
|
|
4
|
+
const GEELIB_DO_LOGIN_URL = 'https://geelib.qihoo.net/ones/Login/doLogin'
|
|
5
|
+
const GEELIB_VERIFY_URL =
|
|
6
|
+
'https://geelib.qihoo.net/ones/user/userInfo?need_share=0'
|
|
7
|
+
const BOUNDARY = '----WebKitFormBoundaryGeelibCli'
|
|
8
|
+
|
|
9
|
+
let sessionCookie = ''
|
|
10
|
+
|
|
11
|
+
export function getCookie() {
|
|
12
|
+
return sessionCookie
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function buildFormData(fields) {
|
|
16
|
+
let body = ''
|
|
17
|
+
for (const [name, value] of Object.entries(fields)) {
|
|
18
|
+
body += `--${BOUNDARY}\r\n`
|
|
19
|
+
body += `Content-Disposition: form-data; name="${name}"\r\n\r\n`
|
|
20
|
+
body += `${value}\r\n`
|
|
21
|
+
}
|
|
22
|
+
body += `--${BOUNDARY}--\r\n`
|
|
23
|
+
return body
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseCookies(headers) {
|
|
27
|
+
const setCookies = headers.getSetCookie?.() ?? []
|
|
28
|
+
const cookies = {}
|
|
29
|
+
for (const c of setCookies) {
|
|
30
|
+
const [pair] = c.split(';')
|
|
31
|
+
const [name, ...rest] = pair.trim().split('=')
|
|
32
|
+
cookies[name.trim()] = rest.join('=').trim()
|
|
33
|
+
}
|
|
34
|
+
return cookies
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** SSO 换取 sid */
|
|
38
|
+
async function ssoLogin(user, passwd) {
|
|
39
|
+
const body = buildFormData({
|
|
40
|
+
user,
|
|
41
|
+
passwd,
|
|
42
|
+
src: 'qihoo',
|
|
43
|
+
syzm: '',
|
|
44
|
+
ref: 'https://geelib.qihoo.net/geelib/',
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const resp = await fetch(SSO_LOGIN_URL, {
|
|
48
|
+
method: 'POST',
|
|
49
|
+
headers: {
|
|
50
|
+
'Content-Type': `multipart/form-data; boundary=${BOUNDARY}`,
|
|
51
|
+
Accept: 'application/json, text/plain, */*',
|
|
52
|
+
Cookie: 'SSO_PREFERED_DOMAIN=qihoo',
|
|
53
|
+
Referer: 'https://login.ops.qihoo.net:4436/sec/login',
|
|
54
|
+
'User-Agent':
|
|
55
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
56
|
+
},
|
|
57
|
+
body,
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
if (!resp.ok) {
|
|
61
|
+
throw new Error(`SSO login failed: ${resp.status} ${resp.statusText}`)
|
|
62
|
+
}
|
|
63
|
+
const data = await resp.json()
|
|
64
|
+
if (data.status !== 0) {
|
|
65
|
+
throw new Error(`SSO login error: ${JSON.stringify(data)}`)
|
|
66
|
+
}
|
|
67
|
+
return data.sid
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** sid 换 GeeLib Cookie */
|
|
71
|
+
async function doLogin(sid) {
|
|
72
|
+
const resp = await fetch(GEELIB_DO_LOGIN_URL, {
|
|
73
|
+
method: 'POST',
|
|
74
|
+
headers: {
|
|
75
|
+
'Content-Type': 'application/json',
|
|
76
|
+
Accept: 'application/json, text/plain, */*',
|
|
77
|
+
Referer: 'https://geelib.qihoo.net/geelib/',
|
|
78
|
+
Origin: 'https://geelib.qihoo.net',
|
|
79
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
80
|
+
'User-Agent':
|
|
81
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
82
|
+
},
|
|
83
|
+
body: JSON.stringify({ sid, ref: 'https://geelib.qihoo.net/geelib/' }),
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
if (!resp.ok) {
|
|
87
|
+
throw new Error(`doLogin failed: ${resp.status}`)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const cookies = parseCookies(resp.headers)
|
|
91
|
+
const data = await resp.json()
|
|
92
|
+
|
|
93
|
+
if (data.errno !== 2000) {
|
|
94
|
+
throw new Error(`doLogin error: errno=${data.errno} errmsg=${data.errmsg}`)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const cookieStr = Object.entries(cookies)
|
|
98
|
+
.map(([k, v]) => `${k}=${v}`)
|
|
99
|
+
.join('; ')
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
cookieStr,
|
|
103
|
+
userName: data.data?.real_name ?? data.data?.name ?? '',
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function verifyCookie(cookieStr) {
|
|
108
|
+
try {
|
|
109
|
+
const resp = await fetch(GEELIB_VERIFY_URL, {
|
|
110
|
+
headers: {
|
|
111
|
+
Cookie: cookieStr,
|
|
112
|
+
Referer: 'https://geelib.qihoo.net/geelib/',
|
|
113
|
+
'User-Agent':
|
|
114
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
115
|
+
Accept: 'application/json, text/plain, */*',
|
|
116
|
+
'X-Requested-With': 'XMLHttpRequest',
|
|
117
|
+
},
|
|
118
|
+
})
|
|
119
|
+
const data = await resp.json()
|
|
120
|
+
return data.errno === 2000
|
|
121
|
+
} catch {
|
|
122
|
+
return false
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** 使用 GEELIB_USER / GEELIB_PASSWD 登录 */
|
|
127
|
+
export async function login() {
|
|
128
|
+
const user = process.env.GEELIB_USER
|
|
129
|
+
const passwd = process.env.GEELIB_PASSWD
|
|
130
|
+
|
|
131
|
+
if (!user || !passwd) {
|
|
132
|
+
throw new Error('请配置 GEELIB_USER 和 GEELIB_PASSWD 环境变量')
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const sid = await ssoLogin(user, passwd)
|
|
136
|
+
const { cookieStr } = await doLogin(sid)
|
|
137
|
+
sessionCookie = cookieStr
|
|
138
|
+
return cookieStr
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Cookie 失效时自动重新登录 */
|
|
142
|
+
export async function ensureAuth() {
|
|
143
|
+
if (sessionCookie && (await verifyCookie(sessionCookie))) {
|
|
144
|
+
return
|
|
145
|
+
}
|
|
146
|
+
await login()
|
|
147
|
+
}
|