@roll-agent/core 0.10.0 → 0.10.1
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineCommand as e}from"citty";import{resolve as t}from"node:path";import{existsSync as r}from"node:fs";import{execFile as a}from"node:child_process";import{promisify as s}from"node:util";import{inspectConfigFile as n,loadAgentsConfig as i,loadConfig as o,loadInstallConfig as l}from"../../config/loader.js";import{DEFAULT_CONFIG as c}from"../../config/defaults.js";import{getAgentEnv as u}from"../../config/helpers.js";import{getAgentPid as m,startAgent as p,stopAgentGracefully as f,waitForAgentReady as g}from"../../registry/process-manager.js";import{resolveTransportWithDevSpawnSpec as k}from"../../registry/dev-spawn.js";import{runAgentSetup as d}from"../../registry/runtime-setup.js";import{AgentStore as y}from"../../registry/store.js";import{discoverAgent as h}from"../../registry/discovery.js";import{inferAgentSourceType as $,readInstalledPackageManifest as w,resolveInstalledPackageRoot as v}from"../../registry/source.js";import{McpClientManager as S}from"../../mcp/client-manager.js";import{log as b,createSpinner as V}from"../utils/output.js";import{checkForUpdate as j,checkPublishedPackageUpdate as P,getCurrentVersion as A}from"../utils/update-checker.js";import{buildNpmRetryPolicy as M,detectInstallCommand as B,formatPackageManagerError as T,npmInstallNetworkArgs as D,runPackageManager as R,runPackageManagerWithRetry as E}from"../utils/package-manager.js";function N(e){return D({...e.registry?{registry:e.registry}:{},fetchRetries:e.fetchRetries,preferOffline:e.preferOffline})}function x(e){return{forceRefresh:!0,fetchRetries:e.fetchRetries,...e.registry?{registry:e.registry}:{}}}function C(e){return"invalid"===e.status&&(e.error.message.startsWith("Invalid YAML syntax")||e.error.message.includes("(expected YAML object)"))}const I=s(a);export{inferAgentSourceType as inferSourceType}from"../../registry/source.js";export{detectInstallCommand}from"../utils/package-manager.js";function L(e,t){switch(e.status){case"needs-migration":{const r="post-update"===t?"升级后需要迁移本地配置":"检测到本地配置需要迁移";b.warn(`${r}: ${e.configPath}`);for(const t of e.report.issues)b.warn(` - ${t.message}`);e.report.canAutoMigrate&&b.info("建议命令: roll config migrate");break}case"invalid":b.warn(`本地配置存在问题: ${e.configPath??"(unknown path)"}`),b.warn(` - ${e.error.message}`),"post-update"===t&&b.info("请修复配置文件后再继续使用相关命令。")}}function O(e){switch(e){case"up-to-date":return"✅";case"update-available":return"⬆";case"pinned-behind":return"📌";case"unsupported-spec":case"unknown":return"?"}}function U(e,t){switch(e.status){case"up-to-date":return e.currentVersion?`已是最新版本 (v${e.currentVersion})`:"已是最新版本";case"update-available":return e.currentVersion&&e.latestVersion?`可更新 v${e.currentVersion} → v${e.latestVersion}`:"检测到可用更新";case"pinned-behind":return e.currentVersion&&e.latestVersion?`固定版本 v${e.currentVersion};latest=v${e.latestVersion}`:"固定版本,需手动调整 package spec";case"unsupported-spec":return`不支持检查此 package spec: ${t}`;case"unknown":return e.currentVersion?`无法检查最新版本 (current=v${e.currentVersion})`:"无法检查最新版本"}}function Y(e,t){if("installed-package"!==e.source?.type)return e;const r=v(e.source.installDir,e.source.packageName),a=w(r);if(!a)return e;const s={...e.source,...a.name?{packageName:a.name}:{},...a.version?{installedVersion:a.version}:{}},n=s.packageName!==e.source.packageName||s.installedVersion!==e.source.installedVersion,i=r!==e.installPath;if(!n&&!i)return e;const o={...e,installPath:r,source:s};return t&&t.replace(e.skill.name,o),o}async function K(e,t,r){const a=A();if(a===e)return b.info(`roll 已是最新版本 (v${a})`),!1;if(b.info(`roll v${a} → v${e}`),t)return b.info("[dry-run] 跳过实际更新"),!0;const s=V("正在更新 @roll-agent/core...").start(),n={command:"npm",args:["install","-g",`@roll-agent/core@${e}`,...N(r)]};try{return await E(n,{timeout:r.networkTimeoutMs},{...M(r.fetchRetries),onRetry:({attempt:e,delayMs:t})=>{s.text=`roll 更新遇到网络问题,${Math.round(t/1e3)}s 后重试(第 ${e+1} 次)...`}}),s.succeed(`roll 已更新到 v${e}`),!0}catch(e){return s.fail("更新失败"),b.error(T(n,e)),!1}}async function W(e){const a=V(`更新 ${e.skill.name} (git pull)...`).start();try{await I("git",["pull"],{cwd:e.installPath,timeout:3e4}),a.succeed(`${e.skill.name} 代码已更新`);const s=t(e.installPath,"package.json");if(r(s)){const t=B(e.installPath);if(t){const r=V(`安装 ${e.skill.name} 依赖...`).start();try{await R(t,{cwd:e.installPath,timeout:6e4}),r.succeed(`${e.skill.name} 依赖已更新 (${t.command} ${t.args.join(" ")})`)}catch(a){return r.fail(`${e.skill.name} 依赖安装失败`),b.error(T(t,a)),!1}}else b.warn(`${e.skill.name} 未检测到 packageManager 或 lockfile,跳过依赖安装。`)}return!0}catch(t){return a.fail(`${e.skill.name} 更新失败`),b.error(t instanceof Error?t.message:String(t)),!1}}async function _(e,t){if("installed-package"!==e.source?.type)return;const a=V(`更新 ${e.skill.name} (npm install)...`).start(),s={command:"npm",args:["install","--prefix",e.source.installDir,e.source.packageSpec,...N(t)]};try{await E(s,{timeout:t.networkTimeoutMs},{...M(t.fetchRetries),onRetry:({attempt:t,delayMs:r})=>{a.text=`更新 ${e.skill.name} 遇到网络问题,${Math.round(r/1e3)}s 后重试(第 ${t+1} 次)...`}});const n=v(e.source.installDir,e.source.packageName);if(!r(n))throw new Error(`Installed package root not found: ${n}`);const i=w(n);return a.succeed(`${e.skill.name} 已重新安装`),{packageRoot:n,packageName:i?.name??e.source.packageName,...i?.version?{installedVersion:i.version}:{}}}catch(t){return a.fail(`${e.skill.name} 更新失败`),void b.error(T(s,t))}}async function q(e){const t=V(`刷新 ${e.skill.name} (MCP tools/list)...`).start(),r=new S;try{const a=k(e),s=await r.connect(e.skill.name,a,e.installPath),{tools:n}=await s.listTools();return t.succeed(`${e.skill.name} 元数据已刷新(${n.length} 个 tool)`),!0}catch(r){return t.fail(`${e.skill.name} 刷新失败`),b.error(r instanceof Error?r.message:String(r)),!1}finally{await r.disconnectAll()}}export default e({meta:{description:"检查并更新 roll 及已注册 Agent"},args:{check:{type:"boolean",description:"仅检查 roll/Agent 可用更新,不执行安装或刷新",default:!1},"skip-browser-setup":{type:"boolean",description:"跳过 Playwright 浏览器运行时安装/校验",default:!1}},async run({args:e}){const t=e.check,r=n();let a;try{a=l().installConfig}catch(e){if(!C(r))return b.error(`install 配置无效,已停止更新:${e instanceof Error?e.message:String(e)}`),void(process.exitCode=1);a=c.install,b.warn(`无法读取 install 配置,使用默认值:${e instanceof Error?e.message:String(e)}`)}a.registry&&b.info(`使用 npm registry: ${a.registry}(roll.config.yaml install.registry)`);const s=x(a);b.info("检查 roll 更新...");const o=await j(s);let u,p;o.hasUpdate?b.success(`roll 有新版本: v${o.current} → v${o.latest}`):b.info(`roll 已是最新版本 (v${o.current})`);let g=[];try{u=i().agentsConfig,p=new y(u.dataDir),g=p.list()}catch(e){b.warn(`无法读取 Agent 配置,跳过已注册 Agent 检查:${e instanceof Error?e.message:String(e)}`)}const k=[];for(const e of g){let t=e;"installed-package"===$(t)&&(t=Y(t,p));const r=$(t);switch(r){case"git":k.push({name:t.skill.name,sourceType:r,icon:"~",action:"可执行 git pull + 重新安装依赖"});break;case"installed-package":{if("installed-package"!==t.source?.type){k.push({name:t.skill.name,sourceType:r,icon:"?",action:"无法检查已安装包版本"});break}const e=await P({packageName:t.source.packageName,packageSpec:t.source.packageSpec,...t.source.installedVersion?{currentVersion:t.source.installedVersion}:{}},s);k.push({name:t.skill.name,sourceType:r,icon:O(e.status),action:U(e,t.source.packageSpec)});break}case"remote-manifest":k.push({name:t.skill.name,sourceType:r,icon:"~",action:"可刷新本地 manifest + MCP 元数据"});break;case"local-path":k.push({name:t.skill.name,sourceType:r,icon:"⏭",action:"刷新本地 SKILL/manifest"})}}if(g.length>0){b.info(`\n已注册 Agent (${g.length}):`);for(const e of k)b.info(` ${e.icon} ${e.name} [${e.sourceType}] — ${e.action}`)}else u&&b.info("无已注册 Agent");if("needs-migration"!==r.status&&"invalid"!==r.status||(b.info(""),L(r,t?"check":"pre-update")),t)return;b.info("");let w=!1,v=!1;o.hasUpdate&&(w=await K(o.latest,!1,a),w||(v=!0)),!w||"needs-migration"!==r.status&&"invalid"!==r.status||(b.info(""),L(r,"post-update"));let S=0,V=0;for(const t of g){if(!p||!u)break;switch($(t)){case"git":{const e="core-managed"===t.runtime.ownership&&void 0!==m(u.dataDir,t.skill.name);if(await W(t))try{const r=h(t.installPath),a={...t,skill:r.skill,transport:r.transport,runtime:r.runtime,...r.skillBody.length>0?{skillBody:r.skillBody}:{}};p.replace(t.skill.name,a)?(await z(a,e,u.dataDir),S++):(b.warn(`${t.skill.name} 已从注册表中移除,跳过元数据刷新`),V++)}catch(e){p.updateStatus(t.skill.name,"error"),b.warn(`${t.skill.name} metadata 刷新或重启失败: ${e instanceof Error?e.message:String(e)}`),V++}else V++;break}case"installed-package":{const r="core-managed"===t.runtime.ownership&&void 0!==m(u.dataDir,t.skill.name);if(r)try{await f(u.dataDir,t.skill.name)}catch(e){p.updateStatus(t.skill.name,"error"),b.warn(`${t.skill.name} 停止失败,无法继续升级: ${e instanceof Error?e.message:String(e)}`),V++;break}const s=await _(t,a);if(s)try{const a=h(s.packageRoot),n="installed-package"===t.source?.type?{...t.source,packageName:s.packageName,...s.installedVersion?{installedVersion:s.installedVersion}:{}}:void 0,i={...t,skill:a.skill,transport:a.transport,runtime:a.runtime,installPath:s.packageRoot,...n?{source:n}:{},...a.skillBody.length>0?{skillBody:a.skillBody}:{}},o=await d(i,{skipBrowserSetup:e["skip-browser-setup"]});o.ok||(b.warn(`${i.skill.name} setup 失败:${o.message}`),o.retryCommand&&b.info(`重试命令: ${o.retryCommand}`));p.replace(t.skill.name,i)?o.ok?(r&&await F(i,u.dataDir),S++):(p.updateStatus(i.skill.name,"error"),V++):(b.warn(`${t.skill.name} 已从注册表中移除,跳过元数据刷新`),V++)}catch(e){p.updateStatus(t.skill.name,"error"),b.warn(`${t.skill.name} metadata 刷新、setup 或重启失败: ${e instanceof Error?e.message:String(e)}`),V++}else{if(r)try{await F(t,u.dataDir)}catch{p.updateStatus(t.skill.name,"error")}V++}break}case"remote-manifest":try{const e=h(t.installPath),r={...t,skill:e.skill,transport:e.transport,runtime:e.runtime,...e.skillBody.length>0?{skillBody:e.skillBody}:{}};if(!p.replace(t.skill.name,r)){b.warn(`${t.skill.name} 已从注册表中移除,跳过元数据刷新`),V++;break}await q(r)?S++:V++}catch(e){b.warn(`${t.skill.name} manifest 刷新失败: ${e instanceof Error?e.message:String(e)}`),V++}break;case"local-path":{const e="core-managed"===t.runtime.ownership&&void 0!==m(u.dataDir,t.skill.name);try{const r=h(t.installPath),a={...t,skill:r.skill,transport:r.transport,runtime:r.runtime,...r.skillBody.length>0?{skillBody:r.skillBody}:{}};p.replace(t.skill.name,a)?(await z(a,e,u.dataDir),S++):(b.warn(`${t.skill.name} 已从注册表中移除,跳过元数据刷新`),V++)}catch(e){p.updateStatus(t.skill.name,"error"),b.warn(`${t.skill.name} 本地 metadata 刷新或重启失败: ${e instanceof Error?e.message:String(e)}`),V++}break}}}b.info("");if(V+(v?1:0)>0){process.exitCode=1;const e=v?"roll 更新失败":w?"roll ✓":"roll 无更新";return void b.warn(`更新完成但有失败:${e}${V>0?`,${V} 个 Agent 更新失败`:""}${S>0?`,${S} 个 Agent 已更新`:""}`)}w||S>0?b.success(`更新完成:${w?"roll ✓":"roll 无更新"}${S>0?`,${S} 个 Agent 已更新`:""}`):b.success("一切都已是最新版本")}});async function z(e,t,r){t&&"core-managed"===e.runtime.ownership&&(await f(r,e.skill.name),await F(e,r))}async function F(e,t){let r=!1;try{p(e,t,u(o().config,e.skill.name)),r=!0,await g(e,{startupTimeoutMs:15e3,probeTimeoutMs:2e3})}catch(a){throw r&&await f(t,e.skill.name).catch(()=>{}),a}}
|
|
1
|
+
import{defineCommand as e}from"citty";import{resolve as t}from"node:path";import{existsSync as r}from"node:fs";import{execFile as a}from"node:child_process";import{promisify as s}from"node:util";import{inspectConfigFile as n,loadAgentsConfig as i,loadConfig as o,loadInstallConfig as l}from"../../config/loader.js";import{DEFAULT_CONFIG as c}from"../../config/defaults.js";import{getAgentEnv as u}from"../../config/helpers.js";import{getAgentPid as m,startAgent as p,stopAgentGracefully as f,waitForAgentReady as g}from"../../registry/process-manager.js";import{resolveTransportWithDevSpawnSpec as k}from"../../registry/dev-spawn.js";import{runAgentSetup as d}from"../../registry/runtime-setup.js";import{AgentStore as $}from"../../registry/store.js";import{discoverAgent as y}from"../../registry/discovery.js";import{inferAgentSourceType as h,readInstalledPackageManifest as w,resolveInstalledPackageRoot as v}from"../../registry/source.js";import{McpClientManager as S}from"../../mcp/client-manager.js";import{log as b,createSpinner as V}from"../utils/output.js";import{checkForUpdate as j,checkPublishedPackageUpdate as P,getCurrentVersion as A,isPinnedPublishedPackageSpec as M}from"../utils/update-checker.js";import{buildNpmRetryPolicy as B,detectInstallCommand as T,formatPackageManagerError as D,npmInstallNetworkArgs as N,runPackageManager as R,runPackageManagerWithRetry as E}from"../utils/package-manager.js";function x(e){return N({...e.registry?{registry:e.registry}:{},fetchRetries:e.fetchRetries,preferOffline:e.preferOffline})}function C(e){return{forceRefresh:!0,fetchRetries:e.fetchRetries,...e.registry?{registry:e.registry}:{}}}function I(e){return"invalid"===e.status&&(e.error.message.startsWith("Invalid YAML syntax")||e.error.message.includes("(expected YAML object)"))}const L=s(a);export{inferAgentSourceType as inferSourceType}from"../../registry/source.js";export{detectInstallCommand}from"../utils/package-manager.js";function O(e,t){switch(e.status){case"needs-migration":{const r="post-update"===t?"升级后需要迁移本地配置":"检测到本地配置需要迁移";b.warn(`${r}: ${e.configPath}`);for(const t of e.report.issues)b.warn(` - ${t.message}`);e.report.canAutoMigrate&&b.info("建议命令: roll config migrate");break}case"invalid":b.warn(`本地配置存在问题: ${e.configPath??"(unknown path)"}`),b.warn(` - ${e.error.message}`),"post-update"===t&&b.info("请修复配置文件后再继续使用相关命令。")}}function U(e){switch(e){case"up-to-date":return"✅";case"update-available":return"⬆";case"pinned-behind":return"📌";case"unsupported-spec":case"unknown":return"?"}}function W(e,t){switch(e.status){case"up-to-date":return e.currentVersion?`已是最新版本 (v${e.currentVersion})`:"已是最新版本";case"update-available":return e.currentVersion&&e.latestVersion?`可更新 v${e.currentVersion} → v${e.latestVersion}`:"检测到可用更新";case"pinned-behind":return e.currentVersion&&e.latestVersion?`固定版本 v${e.currentVersion};latest=v${e.latestVersion}`:"固定版本,需手动调整 package spec";case"unsupported-spec":return`不支持检查此 package spec: ${t}`;case"unknown":return e.currentVersion?`无法检查最新版本 (current=v${e.currentVersion})`:"无法检查最新版本"}}function Y(e,t){if("installed-package"!==e.source?.type)return e;const r=v(e.source.installDir,e.source.packageName),a=w(r);if(!a)return e;const s={...e.source,...a.name?{packageName:a.name}:{},...a.version?{installedVersion:a.version}:{}},n=s.packageName!==e.source.packageName||s.installedVersion!==e.source.installedVersion,i=r!==e.installPath;if(!n&&!i)return e;const o={...e,installPath:r,source:s};return t&&t.replace(e.skill.name,o),o}function K(e){if("installed-package"!==e.source?.type)return;const{packageName:t,packageSpec:r}=e.source;return r===t||r.startsWith(`${t}@`)&&!M(t,r)?`${t}@latest`:r}async function _(e,t,r){const a=A();if(a===e)return b.info(`roll 已是最新版本 (v${a})`),!1;if(b.info(`roll v${a} → v${e}`),t)return b.info("[dry-run] 跳过实际更新"),!0;const s=V("正在更新 @roll-agent/core...").start(),n={command:"npm",args:["install","-g",`@roll-agent/core@${e}`,...x(r)]};try{return await E(n,{timeout:r.networkTimeoutMs},{...B(r.fetchRetries),onRetry:({attempt:e,delayMs:t})=>{s.text=`roll 更新遇到网络问题,${Math.round(t/1e3)}s 后重试(第 ${e+1} 次)...`}}),s.succeed(`roll 已更新到 v${e}`),!0}catch(e){return s.fail("更新失败"),b.error(D(n,e)),!1}}async function q(e){const a=V(`更新 ${e.skill.name} (git pull)...`).start();try{await L("git",["pull"],{cwd:e.installPath,timeout:3e4}),a.succeed(`${e.skill.name} 代码已更新`);const s=t(e.installPath,"package.json");if(r(s)){const t=T(e.installPath);if(t){const r=V(`安装 ${e.skill.name} 依赖...`).start();try{await R(t,{cwd:e.installPath,timeout:6e4}),r.succeed(`${e.skill.name} 依赖已更新 (${t.command} ${t.args.join(" ")})`)}catch(a){return r.fail(`${e.skill.name} 依赖安装失败`),b.error(D(t,a)),!1}}else b.warn(`${e.skill.name} 未检测到 packageManager 或 lockfile,跳过依赖安装。`)}return!0}catch(t){return a.fail(`${e.skill.name} 更新失败`),b.error(t instanceof Error?t.message:String(t)),!1}}async function z(e,t){if("installed-package"!==e.source?.type)return;const a=V(`更新 ${e.skill.name} (npm install)...`).start(),s=K(e);if(!s)return void a.fail(`${e.skill.name} 更新失败`);const n={command:"npm",args:["install","--prefix",e.source.installDir,s,...x(t)]};try{await E(n,{timeout:t.networkTimeoutMs},{...B(t.fetchRetries),onRetry:({attempt:t,delayMs:r})=>{a.text=`更新 ${e.skill.name} 遇到网络问题,${Math.round(r/1e3)}s 后重试(第 ${t+1} 次)...`}});const s=v(e.source.installDir,e.source.packageName);if(!r(s))throw new Error(`Installed package root not found: ${s}`);const i=w(s);return a.succeed(`${e.skill.name} 已重新安装`),{packageRoot:s,packageName:i?.name??e.source.packageName,...i?.version?{installedVersion:i.version}:{}}}catch(t){return a.fail(`${e.skill.name} 更新失败`),void b.error(D(n,t))}}async function F(e){const t=V(`刷新 ${e.skill.name} (MCP tools/list)...`).start(),r=new S;try{const a=k(e),s=await r.connect(e.skill.name,a,e.installPath),{tools:n}=await s.listTools();return t.succeed(`${e.skill.name} 元数据已刷新(${n.length} 个 tool)`),!0}catch(r){return t.fail(`${e.skill.name} 刷新失败`),b.error(r instanceof Error?r.message:String(r)),!1}finally{await r.disconnectAll()}}export default e({meta:{description:"检查并更新 roll 及已注册 Agent"},args:{check:{type:"boolean",description:"仅检查 roll/Agent 可用更新,不执行安装或刷新",default:!1},"skip-browser-setup":{type:"boolean",description:"跳过 Playwright 浏览器运行时安装/校验",default:!1}},async run({args:e}){const t=e.check,r=n();let a;try{a=l().installConfig}catch(e){if(!I(r))return b.error(`install 配置无效,已停止更新:${e instanceof Error?e.message:String(e)}`),void(process.exitCode=1);a=c.install,b.warn(`无法读取 install 配置,使用默认值:${e instanceof Error?e.message:String(e)}`)}a.registry&&b.info(`使用 npm registry: ${a.registry}(roll.config.yaml install.registry)`);const s=C(a);b.info("检查 roll 更新...");const o=await j(s);let u,p;o.hasUpdate?b.success(`roll 有新版本: v${o.current} → v${o.latest}`):b.info(`roll 已是最新版本 (v${o.current})`);let g=[];try{u=i().agentsConfig,p=new $(u.dataDir),g=p.list()}catch(e){b.warn(`无法读取 Agent 配置,跳过已注册 Agent 检查:${e instanceof Error?e.message:String(e)}`)}const k=[];for(const e of g){let t=e;"installed-package"===h(t)&&(t=Y(t,p));const r=h(t);switch(r){case"git":k.push({name:t.skill.name,sourceType:r,icon:"~",action:"可执行 git pull + 重新安装依赖"});break;case"installed-package":{if("installed-package"!==t.source?.type){k.push({name:t.skill.name,sourceType:r,icon:"?",action:"无法检查已安装包版本"});break}const e=await P({packageName:t.source.packageName,packageSpec:t.source.packageSpec,...t.source.installedVersion?{currentVersion:t.source.installedVersion}:{}},s);k.push({name:t.skill.name,sourceType:r,icon:U(e.status),action:W(e,t.source.packageSpec)});break}case"remote-manifest":k.push({name:t.skill.name,sourceType:r,icon:"~",action:"可刷新本地 manifest + MCP 元数据"});break;case"local-path":k.push({name:t.skill.name,sourceType:r,icon:"⏭",action:"刷新本地 SKILL/manifest"})}}if(g.length>0){b.info(`\n已注册 Agent (${g.length}):`);for(const e of k)b.info(` ${e.icon} ${e.name} [${e.sourceType}] — ${e.action}`)}else u&&b.info("无已注册 Agent");if("needs-migration"!==r.status&&"invalid"!==r.status||(b.info(""),O(r,t?"check":"pre-update")),t)return;b.info("");let w=!1,v=!1;o.hasUpdate&&(w=await _(o.latest,!1,a),w||(v=!0)),!w||"needs-migration"!==r.status&&"invalid"!==r.status||(b.info(""),O(r,"post-update"));let S=0,V=0;for(const t of g){if(!p||!u)break;switch(h(t)){case"git":{const e="core-managed"===t.runtime.ownership&&void 0!==m(u.dataDir,t.skill.name);if(await q(t))try{const r=y(t.installPath),a={...t,skill:r.skill,transport:r.transport,runtime:r.runtime,...r.skillBody.length>0?{skillBody:r.skillBody}:{}};p.replace(t.skill.name,a)?(await G(a,e,u.dataDir),S++):(b.warn(`${t.skill.name} 已从注册表中移除,跳过元数据刷新`),V++)}catch(e){p.updateStatus(t.skill.name,"error"),b.warn(`${t.skill.name} metadata 刷新或重启失败: ${e instanceof Error?e.message:String(e)}`),V++}else V++;break}case"installed-package":{const r="core-managed"===t.runtime.ownership&&void 0!==m(u.dataDir,t.skill.name);if(r)try{await f(u.dataDir,t.skill.name)}catch(e){p.updateStatus(t.skill.name,"error"),b.warn(`${t.skill.name} 停止失败,无法继续升级: ${e instanceof Error?e.message:String(e)}`),V++;break}const s=await z(t,a);if(s)try{const a=y(s.packageRoot),n="installed-package"===t.source?.type?{...t.source,packageName:s.packageName,...s.installedVersion?{installedVersion:s.installedVersion}:{}}:void 0,i={...t,skill:a.skill,transport:a.transport,runtime:a.runtime,installPath:s.packageRoot,...n?{source:n}:{},...a.skillBody.length>0?{skillBody:a.skillBody}:{}},o=await d(i,{skipBrowserSetup:e["skip-browser-setup"]});o.ok||(b.warn(`${i.skill.name} setup 失败:${o.message}`),o.retryCommand&&b.info(`重试命令: ${o.retryCommand}`));p.replace(t.skill.name,i)?o.ok?(r&&await H(i,u.dataDir),S++):(p.updateStatus(i.skill.name,"error"),V++):(b.warn(`${t.skill.name} 已从注册表中移除,跳过元数据刷新`),V++)}catch(e){p.updateStatus(t.skill.name,"error"),b.warn(`${t.skill.name} metadata 刷新、setup 或重启失败: ${e instanceof Error?e.message:String(e)}`),V++}else{if(r)try{await H(t,u.dataDir)}catch{p.updateStatus(t.skill.name,"error")}V++}break}case"remote-manifest":try{const e=y(t.installPath),r={...t,skill:e.skill,transport:e.transport,runtime:e.runtime,...e.skillBody.length>0?{skillBody:e.skillBody}:{}};if(!p.replace(t.skill.name,r)){b.warn(`${t.skill.name} 已从注册表中移除,跳过元数据刷新`),V++;break}await F(r)?S++:V++}catch(e){b.warn(`${t.skill.name} manifest 刷新失败: ${e instanceof Error?e.message:String(e)}`),V++}break;case"local-path":{const e="core-managed"===t.runtime.ownership&&void 0!==m(u.dataDir,t.skill.name);try{const r=y(t.installPath),a={...t,skill:r.skill,transport:r.transport,runtime:r.runtime,...r.skillBody.length>0?{skillBody:r.skillBody}:{}};p.replace(t.skill.name,a)?(await G(a,e,u.dataDir),S++):(b.warn(`${t.skill.name} 已从注册表中移除,跳过元数据刷新`),V++)}catch(e){p.updateStatus(t.skill.name,"error"),b.warn(`${t.skill.name} 本地 metadata 刷新或重启失败: ${e instanceof Error?e.message:String(e)}`),V++}break}}}b.info("");if(V+(v?1:0)>0){process.exitCode=1;const e=v?"roll 更新失败":w?"roll ✓":"roll 无更新";return void b.warn(`更新完成但有失败:${e}${V>0?`,${V} 个 Agent 更新失败`:""}${S>0?`,${S} 个 Agent 已更新`:""}`)}w||S>0?b.success(`更新完成:${w?"roll ✓":"roll 无更新"}${S>0?`,${S} 个 Agent 已更新`:""}`):b.success("一切都已是最新版本")}});async function G(e,t,r){t&&"core-managed"===e.runtime.ownership&&(await f(r,e.skill.name),await H(e,r))}async function H(e,t){let r=!1;try{p(e,t,u(o().config,e.skill.name)),r=!0,await g(e,{startupTimeoutMs:15e3,probeTimeoutMs:2e3})}catch(a){throw r&&await f(t,e.skill.name).catch(()=>{}),a}}
|
|
@@ -24,6 +24,7 @@ export interface UpdateInfo {
|
|
|
24
24
|
export declare function fetchLatestPublishedVersion(packageName: string, options?: PackageVersionQueryOptions): Promise<string | undefined>;
|
|
25
25
|
export declare function getCurrentVersion(): string;
|
|
26
26
|
export declare function isNewerVersion(latest: string, current: string): boolean;
|
|
27
|
+
export declare function isPinnedPublishedPackageSpec(packageName: string, packageSpec: string): boolean;
|
|
27
28
|
export declare function checkPublishedPackageUpdate(input: {
|
|
28
29
|
packageName: string;
|
|
29
30
|
packageSpec: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{readFileSync as e,writeFileSync as t,mkdirSync as n,existsSync as r}from"node:fs";import{resolve as s,dirname as a}from"node:path";import{homedir as o}from"node:os";import{npmViewNetworkArgs as i,runPackageManager as c}from"./package-manager.js";const u=864e5,p="@roll-agent/core",f=1e4;export const PUBLISHED_PACKAGE_UPDATE_STATUSES=["up-to-date","update-available","pinned-behind","unsupported-spec","unknown"];function l(){return s(o(),".roll-agent","update-check.json")}function h(e){return"object"==typeof e&&null!==e&&("latestVersion"in e&&"checkedAt"in e&&("string"==typeof e.latestVersion&&e.latestVersion.length>0&&"number"==typeof e.checkedAt))}function d(e){return"object"==typeof e&&null!==e&&"packages"in e&&("object"==typeof e.packages&&null!==e.packages&&Object.values(e.packages).every(e=>h(e)))}function g(e){return h(e)}function k(){const t=l();if(r(t))try{const n=e(t,"utf-8"),r=JSON.parse(n);if(d(r))return r;if(g(r))return{packages:{[p]:{latestVersion:r.latestVersion,checkedAt:r.checkedAt}}}}catch{}}function m(e){try{const s=l(),o=a(s);r(o)||n(o,{recursive:!0}),t(s,JSON.stringify(e),"utf-8")}catch{}}function V(e,t){const n=k();m({packages:{...n?.packages??{},[e]:{latestVersion:t,checkedAt:Date.now()}}})}function y(e){return k()?.packages[e]}async function b(e,t={}){try{const n=i({...t.registry?{registry:t.registry}:{},...void 0!==t.fetchRetries?{fetchRetries:t.fetchRetries}:{}}),{stdout:r}=await c({command:"npm",args:["view",e,"version","--json",...n]},{timeout:t.timeoutMs??f}),s=r.trim();if(0===s.length)return;const a=JSON.parse(s);return"string"==typeof a&&a.length>0?a:void 0}catch{return}}export async function fetchLatestPublishedVersion(e,t={}){const n=t.forceRefresh??!1,r=t.allowNetwork??!0,s=y(e);if(!n&&s&&Date.now()-s.checkedAt<u)return s.latestVersion;if(!r)return s?.latestVersion;const a=await b(e,t);return a?(V(e,a),a):s?.latestVersion}export function getCurrentVersion(){try{const t=s(import.meta.dirname,"../../../package.json"),n=e(t,"utf-8"),r=JSON.parse(n);if("object"==typeof r&&null!==r&&"version"in r){const e=r.version;if("string"==typeof e)return e}}catch{}return"0.0.0"}export function isNewerVersion(e,t){const n=e=>e.replace(/^v/,"").split(".").map(Number),r=n(e),s=n(t);for(let e=0;e<3;e+=1){const t=r[e]??0,n=s[e]??0;if(t>n)return!0;if(t<n)return!1}return!1}function w(e,t){return!["file:","git+","http://","https://","link:","workspace:","npm:"].some(e=>t.startsWith(e))&&(!(t.startsWith(".")||t.startsWith("/")||t.startsWith("~")||t.endsWith(".tgz")||t.endsWith(".tar.gz"))&&(t===e||t.startsWith(`${e}@`)))}function N(e,t){if(t.startsWith(`${e}@`))return t.slice(e.length+1)}export function isPinnedPublishedPackageSpec(e,t){const n=N(e,t);if(!n)return!1;const r=n.replace(/^v/,"");return/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(r)}export async function checkPublishedPackageUpdate(e,t={}){const{packageName:n,packageSpec:r,currentVersion:s}=e;if(!w(n,r))return{packageName:n,...s?{currentVersion:s}:{},status:"unsupported-spec"};if(!s)return{packageName:n,status:"unknown"};const a=await fetchLatestPublishedVersion(n,t);return a?isNewerVersion(a,s)?isPinnedPublishedPackageSpec(n,r)?{packageName:n,currentVersion:s,latestVersion:a,status:"pinned-behind"}:{packageName:n,currentVersion:s,latestVersion:a,status:"update-available"}:{packageName:n,currentVersion:s,latestVersion:a,status:"up-to-date"}:{packageName:n,currentVersion:s,status:"unknown"}}export async function checkForUpdate(e={}){const t=getCurrentVersion(),n=await fetchLatestPublishedVersion(p,e)??t;return{current:t,latest:n,hasUpdate:isNewerVersion(n,t)}}
|