From a475c09a1b6100b856ddf44733cc2060e20f9540 Mon Sep 17 00:00:00 2001 From: liuxy0551 Date: Wed, 28 Oct 2026 13:38:15 +0800 Subject: [PATCH 1/3] feat(agents): update sync tooltip and set hourly sync schedule --- app/schedule/syncGitAgents.js | 7 ++-- .../agents/detail/AgentDetailContent.tsx | 4 +-- config/config.default.js | 1 - test/agent-detail-layout.test.js | 14 ++++++++ test/agent-schedule-sync.test.js | 36 +++---------------- 5 files changed, 23 insertions(+), 39 deletions(-) diff --git a/app/schedule/syncGitAgents.js b/app/schedule/syncGitAgents.js index 1527900..2e068d8 100644 --- a/app/schedule/syncGitAgents.js +++ b/app/schedule/syncGitAgents.js @@ -1,12 +1,9 @@ -module.exports = (app) => { - const autoSyncInterval = app.config.agentMarket?.autoSyncInterval; - +module.exports = () => { return { schedule: { - interval: autoSyncInterval || '1h', + cron: '0 0 * * * *', // 每小时整点执行 type: 'worker', // 仅由单个 worker 执行,避免多 worker 并发冲突 immediate: false, // 应用启动后等待到达周期再执行 - disable: !autoSyncInterval || autoSyncInterval === '0', }, // 定时轮询同步所有已配置 GitLab 仓库的 Agent 插件 async task(ctx) { diff --git a/app/web/pages/agents/detail/AgentDetailContent.tsx b/app/web/pages/agents/detail/AgentDetailContent.tsx index ae1d490..1237204 100644 --- a/app/web/pages/agents/detail/AgentDetailContent.tsx +++ b/app/web/pages/agents/detail/AgentDetailContent.tsx @@ -572,7 +572,7 @@ const AgentDetailContent: React.FC = ({ name, history }
最近刷新时间 - + @@ -581,7 +581,7 @@ const AgentDetailContent: React.FC = ({ name, history }
最近同步代码时间 - + diff --git a/config/config.default.js b/config/config.default.js index 7603f89..50aae32 100644 --- a/config/config.default.js +++ b/config/config.default.js @@ -47,7 +47,6 @@ module.exports = (app) => { storageDir: process.env.AGENT_MARKET_STORAGE_DIR || '/data/doraemon/agent-market', gitlabToken: process.env.GITLAB_TOKEN || '', gitlabHostWhitelist: ['gitlab.prod.dtstack.cn'], - autoSyncInterval: process.env.AGENT_MARKET_AUTO_SYNC_INTERVAL || '1h', }; exports.middleware = ['access']; diff --git a/test/agent-detail-layout.test.js b/test/agent-detail-layout.test.js index 4aac951..db8e0d8 100644 --- a/test/agent-detail-layout.test.js +++ b/test/agent-detail-layout.test.js @@ -88,3 +88,17 @@ test('Agent 详情页提供当前原始 ZIP 下载入口(图标与 hover 提 assert.match(style, /\.agent-side-download-btn/); assert.doesNotMatch(component, /agent-archive-download/); }); + +test('Agent 详情页展示刷新和同步代码时间的 hover 提示包含定时间隔', () => { + const { component } = readDetailFiles(); + + assert.match( + component, + /Tooltip title="最近一次向 GitLab 发起检查(确认远端是否有新提交)的时间,定时间隔:1小时"/ + ); + assert.match( + component, + /Tooltip title="最近一次成功拉取新代码变动并完成同步入库的时间,定时间隔:1小时"/ + ); +}); + diff --git a/test/agent-schedule-sync.test.js b/test/agent-schedule-sync.test.js index 530677c..aeab0a5 100644 --- a/test/agent-schedule-sync.test.js +++ b/test/agent-schedule-sync.test.js @@ -3,42 +3,16 @@ const assert = require('node:assert/strict'); const syncScheduleFactory = require('../app/schedule/syncGitAgents'); -test('syncGitAgents 定时任务默认配置 1h 且工作在 worker 模式', () => { - const mockApp = { - config: { - agentMarket: { - autoSyncInterval: '1h', - }, - }, - }; - const scheduleDef = syncScheduleFactory(mockApp); - assert.equal(scheduleDef.schedule.interval, '1h'); +test('syncGitAgents 定时任务配置每小时整点 cron 且工作在 worker 模式', () => { + const scheduleDef = syncScheduleFactory(); + assert.equal(scheduleDef.schedule.cron, '0 0 * * * *'); assert.equal(scheduleDef.schedule.type, 'worker'); - assert.equal(scheduleDef.schedule.disable, false); -}); - -test('syncGitAgents 支持禁用定时任务', () => { - const mockApp = { - config: { - agentMarket: { - autoSyncInterval: '', - }, - }, - }; - const scheduleDef = syncScheduleFactory(mockApp); - assert.equal(scheduleDef.schedule.disable, true); + assert.equal(scheduleDef.schedule.immediate, false); }); test('syncGitAgents 定时任务调用 service.agents.syncAllGitAgents', async () => { let called = false; - const mockApp = { - config: { - agentMarket: { - autoSyncInterval: '5m', - }, - }, - }; - const scheduleDef = syncScheduleFactory(mockApp); + const scheduleDef = syncScheduleFactory(); const mockCtx = { logger: { info() {}, From 0b607727f48574070cd2e32ef23c438aa7d97666 Mon Sep 17 00:00:00 2001 From: liuxy0551 Date: Wed, 28 Oct 2026 15:44:10 +0800 Subject: [PATCH 2/3] fix(skills): prevent updating skill updated_at on zip download --- app/service/skills.js | 12 +++- .../skills/detail/SkillDetailContent.tsx | 6 ++ .../detail/components/SkillInstallPanel.tsx | 7 ++- test/skills-increment-downloads.test.js | 56 +++++++++++++++++++ 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 test/skills-increment-downloads.test.js diff --git a/app/service/skills.js b/app/service/skills.js index a791670..8e1c253 100644 --- a/app/service/skills.js +++ b/app/service/skills.js @@ -221,9 +221,19 @@ class SkillsService extends Service { await SkillsItem.increment('downloads', { by: 1, where: { slug: value, is_delete: 0 }, - // Do not bump updated_at — downloads must not reorder "recent" sort. + // 不触发 updated_at 变更,下载量增加不应影响最近更新时间与排序 silent: true, + attributes: { + updated_at: this.app.Sequelize.col('updated_at'), + }, }); + if (this.skillCache) { + const target = + this.skillCache.bySlug?.[value] || this.skillCache.byInstallKey?.[value]; + if (target) { + target.downloads = (target.downloads || 0) + 1; + } + } } catch (error) { this.ctx.logger.warn( `[skills] increment downloads failed for ${value}: ${error.message}` diff --git a/app/web/pages/skills/detail/SkillDetailContent.tsx b/app/web/pages/skills/detail/SkillDetailContent.tsx index ad78eda..eb74233 100644 --- a/app/web/pages/skills/detail/SkillDetailContent.tsx +++ b/app/web/pages/skills/detail/SkillDetailContent.tsx @@ -129,6 +129,11 @@ const SkillDetailContent: React.FC = ({ } }; + // 点击下载仅递增下载量,不更新最近更新时间 + const handleDownload = () => { + setDetail((prev) => (prev ? { ...prev, downloads: (prev.downloads || 0) + 1 } : prev)); + }; + useEffect(() => { setUiSelectedFilePath(''); setSelectedFilePath(''); @@ -312,6 +317,7 @@ const SkillDetailContent: React.FC = ({ agentTerminalCommand={agentTerminalCommand} manualDownloadUrl={manualDownloadUrl} contributor={detail?.contributor || ''} + onDownload={handleDownload} /> ) : null}
diff --git a/app/web/pages/skills/detail/components/SkillInstallPanel.tsx b/app/web/pages/skills/detail/components/SkillInstallPanel.tsx index 3c39fc6..c30d9be 100644 --- a/app/web/pages/skills/detail/components/SkillInstallPanel.tsx +++ b/app/web/pages/skills/detail/components/SkillInstallPanel.tsx @@ -38,6 +38,7 @@ interface SkillInstallPanelProps { agentTerminalCommand: string; manualDownloadUrl: string; contributor?: string; + onDownload?: () => void; } const renderTerminalCommand = (command: string, copyMessage: string) => ( @@ -77,6 +78,7 @@ export const SkillInstallPanel: React.FC = ({ agentTerminalCommand, manualDownloadUrl, contributor = '', + onDownload, }) => (