@roll-agent/core 0.19.0 → 0.20.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.
Files changed (46) hide show
  1. package/dist/cli/chat/ink/app.d.ts +1 -1
  2. package/dist/cli/chat/ink/app.js +1 -1
  3. package/dist/cli/chat/ink/commands.d.ts +4 -12
  4. package/dist/cli/chat/ink/commands.js +1 -1
  5. package/dist/cli/chat/ink/history-from-messages.js +1 -1
  6. package/dist/cli/chat/ink/history-item.js +1 -1
  7. package/dist/cli/chat/ink/input-history.d.ts +2 -0
  8. package/dist/cli/chat/ink/input-history.js +1 -0
  9. package/dist/cli/chat/ink/line-buffer.d.ts +2 -0
  10. package/dist/cli/chat/ink/line-buffer.js +1 -1
  11. package/dist/cli/chat/ink/live-region.d.ts +2 -0
  12. package/dist/cli/chat/ink/live-region.js +1 -1
  13. package/dist/cli/chat/ink/reasoning-block.d.ts +4 -0
  14. package/dist/cli/chat/ink/reasoning-block.js +1 -0
  15. package/dist/cli/chat/ink/spinner.d.ts +3 -1
  16. package/dist/cli/chat/ink/spinner.js +1 -1
  17. package/dist/cli/chat/ink/state.d.ts +26 -3
  18. package/dist/cli/chat/ink/state.js +1 -1
  19. package/dist/cli/chat/ink/text-prompt.d.ts +3 -1
  20. package/dist/cli/chat/ink/text-prompt.js +1 -1
  21. package/dist/cli/chat/ink/turn-activity.d.ts +19 -0
  22. package/dist/cli/chat/ink/turn-activity.js +1 -0
  23. package/dist/cli/chat/ink/turn-status-line.d.ts +14 -0
  24. package/dist/cli/chat/ink/turn-status-line.js +1 -0
  25. package/dist/cli/chat/ink/use-session.js +1 -1
  26. package/dist/cli/commands/chat.d.ts +28 -0
  27. package/dist/cli/commands/chat.js +1 -1
  28. package/dist/cli/commands/config.js +1 -1
  29. package/dist/cli/utils/chat-renderer.js +1 -1
  30. package/dist/cli/utils/current-cli-shim.d.ts +14 -0
  31. package/dist/cli/utils/current-cli-shim.js +1 -0
  32. package/dist/cli/utils/debug-format.d.ts +4 -0
  33. package/dist/cli/utils/debug-format.js +1 -0
  34. package/dist/config/defaults.d.ts +2 -1
  35. package/dist/config/defaults.js +1 -1
  36. package/dist/config/guidance.d.ts +23 -1
  37. package/dist/config/guidance.js +1 -1
  38. package/dist/config/schema.d.ts +52 -7
  39. package/dist/config/schema.js +1 -1
  40. package/dist/llm/providers.d.ts +6 -4
  41. package/dist/llm/providers.js +1 -1
  42. package/dist/registry/install.js +1 -1
  43. package/dist/skills/invocation.d.ts +27 -0
  44. package/dist/skills/invocation.js +1 -0
  45. package/dist/types/chat.d.ts +3 -0
  46. package/package.json +3 -2
@@ -1 +1 @@
1
- import{existsSync as e,mkdirSync as t,rmSync as s,statSync as r}from"node:fs";import{resolve as a}from"node:path";import{buildNpmRetryPolicy as n,formatPackageManagerError as i,npmInstallNetworkArgs as o,runPackageManagerWithRetry as l}from"../cli/utils/package-manager.js";import{inspectAgentEnvRequirements as g}from"../config/helpers.js";import{discoverAgent as m}from"./discovery.js";import{startAgent as p,stopAgentGracefully as c,waitForAgentReady as u}from"./process-manager.js";import{runAgentSetup as d}from"./runtime-setup.js";import{parsePackageName as f,readInstalledPackageManifest as k,resolveInstalledPackageRoot as y,sanitizeInstallId as h}from"./source.js";import{AgentStore as w}from"./store.js";export const INSTALL_AGENT_STEPS=["resolve","download","discover","setup","register","start"];function v(e){return o({...e.registry?{registry:e.registry}:{},fetchRetries:e.fetchRetries,preferOffline:e.preferOffline})}function S(e){return e.startsWith("git@")||e.startsWith("git+")||e.startsWith("github:")||e.startsWith("gitlab:")||e.startsWith("bitbucket:")||e.endsWith(".git")}function $(t){const s=a(t);return e(s)&&r(s).isDirectory()}function C(e){return e instanceof Error?e.message:String(e)}function A(e){return e.source?.type??"unknown"}function D(e,t,s){return{ok:!1,step:"register",message:`Agent "${e}" 已通过 ${t} 来源注册。为避免覆盖本地/Git Agent,默认不会替换为 npm 安装。请先运行 \`roll agent remove ${e}\`,或确认风险后使用 \`roll agent install ${s} --force\`。`,retryCommand:`roll agent install ${s} --force`}}function j(e,t){return void 0!==e&&"installed-package"!==e.source?.type&&!t}export async function installAgent(r,o){const R=o.report??(()=>{}),B=o.collaborators??{},b=B.runInstall??l,M=B.discover??m,N=B.runSetup??d,T=B.start??p,W=B.waitReady??u,x=B.stopGracefully??c,E=B.resolvePackageRoot??y,L=B.readManifest??k,{packageSpec:G}=r,I=r.autoStart??!0,O=r.replaceExisting??!1;if(S(G))return{ok:!1,step:"resolve",message:`Git URL 请使用 \`roll agent add ${G}\` 注册,不要使用 \`roll agent install\``};if($(G))return{ok:!1,step:"resolve",message:`本地源码目录请使用 \`roll agent add ${G}\` 注册,不要使用 \`roll agent install\``};const P=f(G),_=a(o.agentsConfig.dataDir,"installed",h(P)),q=o.store??new w(o.agentsConfig.dataDir),K=r.expectedSkillName,U=K?q.findByName(K):void 0;if(U&&j(U,O))return D(U.skill.name,A(U),G);const V=e(_);V||t(_,{recursive:!0}),o.installConfig.registry&&R({type:"info",message:`使用 npm registry: ${o.installConfig.registry}(roll.config.yaml install.registry)`}),R({type:"step",step:"download",message:`安装 ${G}...`});const z={command:"npm",args:["install","--prefix",_,G,...v(o.installConfig)]};try{await b(z,{timeout:o.installConfig.networkTimeoutMs},{...n(o.installConfig.fetchRetries),onRetry:({attempt:e,delayMs:t})=>{R({type:"retry",attempt:e,delayMs:t})}})}catch(e){return{ok:!1,step:"download",message:`安装失败: ${i(z,e)}`}}const F=E(_,P);if(!e(F))return{ok:!1,step:"discover",message:`安装完成但未找到包目录: ${F}`};const H=L(F);let J;R({type:"step",step:"discover",message:"解析已安装 Agent 的 SKILL.md..."});try{J=M(F)}catch(e){return{ok:!1,step:"discover",message:C(e)}}const Q={skill:J.skill,transport:J.transport,runtime:J.runtime,installPath:F,registeredAt:(new Date).toISOString(),status:"idle",source:{type:"installed-package",packageName:H?.name??P,packageSpec:G,installDir:_,...H?.version?{installedVersion:H.version}:{}},...J.skillBody.length>0?{skillBody:J.skillBody}:{}},X=q.findByName(J.skill.name);if(X&&j(X,O))return V||s(_,{recursive:!0,force:!0}),D(J.skill.name,A(X),G);"core-managed"===Q.runtime.ownership&&Q.runtime.setup?.playwright&&!r.skipBrowserSetup&&R({type:"info",message:`即将安装浏览器运行时 (${Q.runtime.setup.playwright.browsers.join(", ")}),这可能需要一些时间...`});const Y=await N(Q,{skipBrowserSetup:r.skipBrowserSetup??!1});Y.ok&&!Y.skipped?R({type:"success",message:Y.message}):Y.ok&&R({type:"info",message:Y.message});const Z="core-managed"===X?.runtime.ownership&&"online"===X.status;try{if("installed-package"===X?.source?.type||X&&O){if("installed-package"!==X.source?.type){const e=X.source?.type??"unknown";R({type:"info",message:`Agent "${J.skill.name}" 已通过 ${e} 来源注册,将替换为 npm 安装`})}q.replace(X.skill.name,Q)}else q.add(Q)}catch(e){return{ok:!1,step:"register",message:C(e)}}if(!Y.ok)return Z&&await x(o.agentsConfig.dataDir,Q.skill.name).catch(()=>{}),q.updateStatus(J.skill.name,"error"),{ok:!1,step:"setup",message:Y.message,...Y.retryCommand?{retryCommand:Y.retryCommand}:{}};const ee=g(Q.skill.name,J.skill.env,o.agentsConfig.env),te=ee?.missingRequired??[];let se=!1;const re="core-managed"===Q.runtime.ownership&&I,ae=re&&0===te.length;if(Z&&!ae&&(await x(o.agentsConfig.dataDir,Q.skill.name).catch(()=>{}),q.updateStatus(Q.skill.name,"idle")),re)if(te.length>0)R({type:"warn",message:`Agent "${Q.skill.name}" 缺少必填环境变量(${te.map(e=>e.name).join(", ")}),暂不启动。配置后运行 \`roll agent start ${Q.skill.name}\` 启动`});else{let e=!1;try{Z&&await x(o.agentsConfig.dataDir,Q.skill.name),q.updateStatus(Q.skill.name,"starting"),T(Q,o.agentsConfig.dataDir,o.getStartEnv(Q.skill.name)),e=!0,await W(Q,{startupTimeoutMs:15e3,probeTimeoutMs:2e3}),q.updateStatus(Q.skill.name,"online"),se=!0}catch(t){return e&&await x(o.agentsConfig.dataDir,Q.skill.name).catch(()=>{}),q.updateStatus(Q.skill.name,"error"),{ok:!1,step:"start",message:`Agent "${J.skill.name}" 已安装,但自动启动失败:${C(t)}`}}}return{ok:!0,agent:Q,envReport:ee,started:se}}
1
+ import{randomUUID as e}from"node:crypto";import{existsSync as t,lstatSync as r,mkdirSync as s,readFileSync as n,rmSync as a,statSync as i,writeFileSync as o}from"node:fs";import{basename as l,dirname as c,resolve as m}from"node:path";import{buildNpmRetryPolicy as g,formatPackageManagerError as p,npmInstallNetworkArgs as k,runPackageManagerWithRetry as u}from"../cli/utils/package-manager.js";import{inspectAgentEnvRequirements as f}from"../config/helpers.js";import{discoverAgent as d}from"./discovery.js";import{startAgent as y,stopAgentGracefully as h,waitForAgentReady as w}from"./process-manager.js";import{runAgentSetup as $}from"./runtime-setup.js";import{parsePackageName as v,readInstalledPackageManifest as S,resolveInstalledPackageRoot as D,sanitizeInstallId as A}from"./source.js";import{AgentStore as C}from"./store.js";export const INSTALL_AGENT_STEPS=["resolve","download","discover","setup","register","start"];const P=".install.lock";function T(e){return k({...e.registry?{registry:e.registry}:{},fetchRetries:e.fetchRetries,preferOffline:e.preferOffline})}function j(e){return e.startsWith("git@")||e.startsWith("git+")||e.startsWith("github:")||e.startsWith("gitlab:")||e.startsWith("bitbucket:")||e.endsWith(".git")}function B(e){const r=m(e);return t(r)&&i(r).isDirectory()}function b(e){return e instanceof Error?e.message:String(e)}function E(e,t){return"object"==typeof e&&null!==e&&"code"in e&&e.code===t}function N(e,t){try{e({type:"warn",message:t})}catch{}}function R(e){return m(c(e),`.${l(e)}${P}`)}function I(e,t){o(e,`${JSON.stringify(t)}\n`,{encoding:"utf8",flag:"wx",mode:384})}function O(e){try{const t=JSON.parse(n(e,"utf8"));return"object"==typeof t&&null!==t&&"token"in t&&"string"==typeof t.token?t.token:void 0}catch{return}}function x(e,r){const s=O(e.lockPath);if(void 0!==s)if(s===e.markerToken)try{a(e.lockPath)}catch(t){N(r,`清理安装锁失败: ${e.lockPath}(${b(t)})`)}else N(r,`安装锁已被其他任务替换,未执行清理: ${e.lockPath}`);else t(e.lockPath)&&N(r,`安装锁内容无法验证,未自动删除: ${e.lockPath}`)}function L(t,n){const a=e(),i=R(t),o=c(t);try{s(o,{recursive:!0}),I(i,{token:a,pid:process.pid,startedAt:(new Date).toISOString()})}catch(e){return{ok:!1,failure:{ok:!1,step:"resolve",message:E(e,"EEXIST")?`Agent 安装任务正在使用锁文件: ${i}。请先检查锁文件中的 pid,确认对应安装进程已结束后再手动删除该锁文件并重试;Roll 不会自动抢占疑似 stale lock。`:`无法创建 Agent 安装锁: ${b(e)}`}}}let l;try{l=r(t)}catch(e){if(!E(e,"ENOENT"))return x({installDir:t,lockPath:i,markerToken:a},n),{ok:!1,failure:{ok:!1,step:"resolve",message:`无法检查 Agent 安装目录: ${b(e)}`}}}if(void 0!==l)return l.isSymbolicLink()?(x({installDir:t,lockPath:i,markerToken:a},n),{ok:!1,failure:{ok:!1,step:"resolve",message:`Agent 安装目录不能是符号链接: ${t}`}}):l.isDirectory()?{ok:!0,workspace:{installDir:t,lockPath:i,markerToken:a,createdByInvocation:!1}}:(x({installDir:t,lockPath:i,markerToken:a},n),{ok:!1,failure:{ok:!1,step:"resolve",message:`Agent 安装路径已存在但不是目录: ${t}`}});try{s(t)}catch(e){return x({installDir:t,lockPath:i,markerToken:a},n),{ok:!1,failure:{ok:!1,step:"resolve",message:`无法创建 Agent 安装目录: ${b(e)}`}}}return{ok:!0,workspace:{installDir:t,lockPath:i,markerToken:a,createdByInvocation:!0}}}function M(e,t){if(e.createdByInvocation)if(O(e.lockPath)===e.markerToken)try{a(e.installDir,{recursive:!0,force:!0})}catch(r){N(t,`清理未完成的安装目录失败: ${e.installDir}(${b(r)})`)}else N(t,`安装目录锁不再属于当前任务,未删除目录: ${e.installDir}`)}function W(e){return e.source?.type??"unknown"}function G(e,t,r){return{ok:!1,step:"register",message:`Agent "${e}" 已通过 ${t} 来源注册。为避免覆盖本地/Git Agent,默认不会替换为 npm 安装。请先运行 \`roll agent remove ${e}\`,或确认风险后使用 \`roll agent install ${r} --force\`。`,retryCommand:`roll agent install ${r} --force`}}function J(e,t){return void 0!==e&&"installed-package"!==e.source?.type&&!t}export async function installAgent(e,r){const s=r.report??(()=>{}),n=r.collaborators??{},a=n.runInstall??u,i=n.discover??d,o=n.runSetup??$,l=n.start??y,c=n.waitReady??w,k=n.stopGracefully??h,P=n.resolvePackageRoot??D,E=n.readManifest??S,{packageSpec:N}=e,R=e.autoStart??!0,I=e.replaceExisting??!1;if(j(N))return{ok:!1,step:"resolve",message:`Git URL 请使用 \`roll agent add ${N}\` 注册,不要使用 \`roll agent install\``};if(B(N))return{ok:!1,step:"resolve",message:`本地源码目录请使用 \`roll agent add ${N}\` 注册,不要使用 \`roll agent install\``};const O=v(N),_=m(r.agentsConfig.dataDir,"installed",A(O)),q=r.store??new C(r.agentsConfig.dataDir),K=e.expectedSkillName,U=K?q.findByName(K):void 0;if(U&&J(U,I))return G(U.skill.name,W(U),N);const V=L(_,s);if(!V.ok)return V.failure;const X=V.workspace;try{r.installConfig.registry&&s({type:"info",message:`使用 npm registry: ${r.installConfig.registry}(roll.config.yaml install.registry)`}),s({type:"step",step:"download",message:`安装 ${N}...`});const n={command:"npm",args:["install","--prefix",_,N,...T(r.installConfig)]};try{await a(n,{timeout:r.installConfig.networkTimeoutMs},{...g(r.installConfig.fetchRetries),onRetry:({attempt:e,delayMs:t})=>{s({type:"retry",attempt:e,delayMs:t})}})}catch(e){return M(X,s),{ok:!1,step:"download",message:`安装失败: ${p(n,e)}`}}let m,u,d;try{m=P(_,O)}catch(e){throw M(X,s),e}if(!t(m))return M(X,s),{ok:!1,step:"discover",message:`安装完成但未找到包目录: ${m}`};try{u=E(m)}catch(e){throw M(X,s),e}s({type:"step",step:"discover",message:"解析已安装 Agent 的 SKILL.md..."});try{d=i(m)}catch(e){return M(X,s),{ok:!1,step:"discover",message:b(e)}}const y={skill:d.skill,transport:d.transport,runtime:d.runtime,installPath:m,registeredAt:(new Date).toISOString(),status:"idle",source:{type:"installed-package",packageName:u?.name??O,packageSpec:N,installDir:_,...u?.version?{installedVersion:u.version}:{}},...d.skillBody.length>0?{skillBody:d.skillBody}:{}},h=q.findByName(d.skill.name);if(h&&J(h,I))return M(X,s),G(d.skill.name,W(h),N);let w;"core-managed"===y.runtime.ownership&&y.runtime.setup?.playwright&&!e.skipBrowserSetup&&s({type:"info",message:`即将安装浏览器运行时 (${y.runtime.setup.playwright.browsers.join(", ")}),这可能需要一些时间...`});try{w=await o(y,{skipBrowserSetup:e.skipBrowserSetup??!1})}catch(e){throw M(X,s),e}w.ok&&!w.skipped?s({type:"success",message:w.message}):w.ok&&s({type:"info",message:w.message});const $="core-managed"===h?.runtime.ownership&&"online"===h.status;try{if("installed-package"===h?.source?.type||h&&I){if("installed-package"!==h.source?.type){const e=h.source?.type??"unknown";s({type:"info",message:`Agent "${d.skill.name}" 已通过 ${e} 来源注册,将替换为 npm 安装`})}if(!q.replace(h.skill.name,y))throw new Error(`Agent "${h.skill.name}" 在安装期间已被移除,请重试`)}else q.add(y)}catch(e){return M(X,s),{ok:!1,step:"register",message:b(e)}}if(!w.ok)return $&&await k(r.agentsConfig.dataDir,y.skill.name).catch(()=>{}),q.updateStatus(d.skill.name,"error"),{ok:!1,step:"setup",message:w.message,...w.retryCommand?{retryCommand:w.retryCommand}:{}};const v=f(y.skill.name,d.skill.env,r.agentsConfig.env),S=v?.missingRequired??[];let D=!1;const A="core-managed"===y.runtime.ownership&&R,C=A&&0===S.length;if($&&!C&&(await k(r.agentsConfig.dataDir,y.skill.name).catch(()=>{}),q.updateStatus(y.skill.name,"idle")),A)if(S.length>0)s({type:"warn",message:`Agent "${y.skill.name}" 缺少必填环境变量(${S.map(e=>e.name).join(", ")}),暂不启动。配置后运行 \`roll agent start ${y.skill.name}\` 启动`});else{let e=!1;try{$&&await k(r.agentsConfig.dataDir,y.skill.name),q.updateStatus(y.skill.name,"starting"),l(y,r.agentsConfig.dataDir,r.getStartEnv(y.skill.name)),e=!0,await c(y,{startupTimeoutMs:15e3,probeTimeoutMs:2e3}),q.updateStatus(y.skill.name,"online"),D=!0}catch(t){return e&&await k(r.agentsConfig.dataDir,y.skill.name).catch(()=>{}),q.updateStatus(y.skill.name,"error"),{ok:!1,step:"start",message:`Agent "${d.skill.name}" 已安装,但自动启动失败:${b(t)}`}}}return{ok:!0,agent:y,envReport:v,started:D}}finally{x(X,s)}}
@@ -0,0 +1,27 @@
1
+ export interface SkillInvocationSummary {
2
+ readonly name: string;
3
+ readonly description: string;
4
+ readonly source: string;
5
+ }
6
+ export interface SkillInvocation {
7
+ readonly skills: readonly SkillInvocationSummary[];
8
+ readonly prompt: string;
9
+ }
10
+ export declare const SKILL_INVOCATION_PARSE_KINDS: {
11
+ readonly none: "none";
12
+ readonly valid: "valid";
13
+ readonly unknown: "unknown";
14
+ };
15
+ export type SkillInvocationParseResult = {
16
+ readonly kind: typeof SKILL_INVOCATION_PARSE_KINDS.none;
17
+ } | {
18
+ readonly kind: typeof SKILL_INVOCATION_PARSE_KINDS.valid;
19
+ readonly invocation: SkillInvocation;
20
+ } | {
21
+ readonly kind: typeof SKILL_INVOCATION_PARSE_KINDS.unknown;
22
+ readonly token: string;
23
+ };
24
+ export declare function findSkillBySlashName(token: string, skills: readonly SkillInvocationSummary[]): SkillInvocationSummary | undefined;
25
+ /** Parses one or more known leading /skill tokens without rewriting the user's request. */
26
+ export declare function parseSkillInvocationResult(input: string, skills: readonly SkillInvocationSummary[]): SkillInvocationParseResult;
27
+ export declare function parseSkillInvocation(input: string, skills: readonly SkillInvocationSummary[]): SkillInvocation | undefined;
@@ -0,0 +1 @@
1
+ export const SKILL_INVOCATION_PARSE_KINDS={none:"none",valid:"valid",unknown:"unknown"};export function findSkillBySlashName(n,o){const t=n.toLowerCase();return o.find(n=>`/${n.name}`.toLowerCase()===t)}export function parseSkillInvocationResult(n,o){let t=n.trimStart();const e=[],i=new Set;for(;;){const n=/^(\/\S+)(\s*)/.exec(t);if(!n)break;const a=findSkillBySlashName(n[1]??"",o);if(!a)return{kind:SKILL_INVOCATION_PARSE_KINDS.unknown,token:n[1]??""};const S=a.name.toLowerCase();i.has(S)||(e.push(a),i.add(S)),t=t.slice(n[0].length)}return 0===e.length?{kind:SKILL_INVOCATION_PARSE_KINDS.none}:{kind:SKILL_INVOCATION_PARSE_KINDS.valid,invocation:{skills:e,prompt:t.trim()}}}export function parseSkillInvocation(n,o){const t=parseSkillInvocationResult(n,o);return t.kind===SKILL_INVOCATION_PARSE_KINDS.valid?t.invocation:void 0}
@@ -23,6 +23,9 @@ export interface ChatCompactionSummary {
23
23
  readonly kept: number;
24
24
  readonly truncatedTools?: number;
25
25
  readonly beforeInputTokens?: number;
26
+ readonly checkpointId?: string;
27
+ readonly checkpointGeneration?: number;
28
+ readonly checkpointSummaryStatus?: "valid" | "fallback" | "skipped";
26
29
  }
27
30
  export interface ChatInputRequirement {
28
31
  readonly name: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roll-agent/core",
3
- "version": "0.19.0",
3
+ "version": "0.20.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -68,6 +68,7 @@
68
68
  "@ai-sdk/deepseek": "^3.0.2",
69
69
  "@ai-sdk/openai": "^4.0.4",
70
70
  "@ai-sdk/provider": "^4.0.1",
71
+ "@ai-sdk/xai": "4.0.12",
71
72
  "@clack/prompts": "1.4.0",
72
73
  "@modelcontextprotocol/sdk": "^1.12.0",
73
74
  "ai": "^7.0.9",
@@ -84,7 +85,7 @@
84
85
  "string-width": "8.2.1",
85
86
  "yaml": "^2.7.0",
86
87
  "zod": "^3.25.76",
87
- "@roll-agent/runtime": "0.7.1"
88
+ "@roll-agent/runtime": "0.8.0"
88
89
  },
89
90
  "devDependencies": {
90
91
  "@tailwindcss/vite": "4.3.2",