@roll-agent/core 0.5.1 → 0.6.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.
- package/dist/cli/commands/agent-info.js +1 -1
- package/dist/cli/commands/agent-tools.d.ts +13 -0
- package/dist/cli/commands/agent-tools.js +1 -0
- package/dist/cli/commands/agent.js +1 -1
- package/dist/cli/commands/ask.js +1 -1
- package/dist/cli/commands/config.js +1 -1
- package/dist/cli/commands/doctor.js +1 -1
- package/dist/cli/commands/run.js +1 -1
- package/dist/cli/utils/agent-tools.d.ts +7 -0
- package/dist/cli/utils/agent-tools.js +1 -0
- package/dist/cli/utils/tool-results.d.ts +5 -0
- package/dist/cli/utils/tool-results.js +1 -0
- package/dist/config/helpers.d.ts +3 -0
- package/dist/config/helpers.js +1 -1
- package/dist/config/key-codec.d.ts +15 -0
- package/dist/config/key-codec.js +1 -0
- package/dist/config/loader.js +1 -1
- package/dist/config/migration.d.ts +6 -1
- package/dist/config/migration.js +1 -1
- package/dist/config/runtime-env.d.ts +79 -0
- package/dist/config/runtime-env.js +1 -0
- package/dist/mcp/agent-diagnostics.d.ts +7 -0
- package/dist/mcp/agent-diagnostics.js +1 -0
- package/dist/tool-runtime/messages.d.ts +2 -2
- package/dist/tool-runtime/messages.js +1 -1
- package/dist/tool-runtime/preflight.d.ts +6 -2
- package/dist/tool-runtime/preflight.js +1 -1
- package/dist/types/ask.d.ts +13 -0
- package/dist/types/ask.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineCommand as o}from"citty";import{
|
|
1
|
+
import{defineCommand as o}from"citty";import{getAgentEnvFromAgentsConfig as e,inspectAgentEnvRequirements as s}from"../../config/helpers.js";import{formatAgentEnvDeclarationSource as n,formatAgentEnvRuntimeStatus as t,formatAgentRuntimeVerification as l,inspectAgentRuntimeEnvRequirements as r}from"../../config/runtime-env.js";import{loadAgentsConfig as i}from"../../config/loader.js";import{inspectAgentRuntimeEnv as c}from"../../mcp/agent-diagnostics.js";import{formatAgentSourceType as a,getAgentLocation as g,inferAgentSourceType as m}from"../../registry/source.js";import{AgentStore as p}from"../../registry/store.js";export default o({meta:{description:"查看 Agent 详情"},args:{name:{type:"positional",description:"Agent 名称",required:!0}},async run({args:o}){const{agentsConfig:f}=i(),$=new p(f.dataDir).findByName(o.name);if(!$)return console.error(`✗ Agent "${o.name}" 未找到`),void(process.exitCode=1);if(console.log(`名称: ${$.skill.name}`),console.log(`描述: ${$.skill.description}`),console.log(`状态: ${$.status}`),console.log(`来源: ${a(m($))}`),console.log(`传输: ${$.transport.type}`),console.log(`位置: ${g($)}`),console.log(`注册时间: ${$.registeredAt}`),"installed-package"===$.source?.type&&(console.log(`安装包: ${$.source.packageSpec}`),console.log(`安装目录: ${$.source.installDir}`)),Object.keys($.skill.metadata).length>0){console.log("元数据:");for(const[o,e]of Object.entries($.skill.metadata))console.log(` ${o}: ${e}`)}const d=s($.skill.name,$.skill.env,f.env);if(d){const o=await c($,{agentsConfig:f}),s=r(d,e(f,$.skill.name),o);console.log("环境变量:"),console.log(` 运行态校验: ${l(s)}`);for(const o of s.items){const e=n(o),s=o.required?"必填":"可选",l=t(o);console.log(` ${o.name}: [${s}] ${e}${l?`;运行态: ${l}`:""}`),o.purpose&&console.log(` 用途: ${o.purpose}`)}}}});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{defineCommand as o}from"citty";import t from"cli-table3";import{getAgentEnvFromAgentsConfig as e}from"../../config/helpers.js";import{loadAgentsConfig as n}from"../../config/loader.js";import{McpClientManager as i}from"../../mcp/client-manager.js";import{resolveTransportWithDevSpawnSpec as r}from"../../registry/dev-spawn.js";import{AgentStore as s}from"../../registry/store.js";import{normalizeListedTools as l}from"../utils/agent-tools.js";import{log as a}from"../utils/output.js";export default o({meta:{description:"查看 Agent 暴露的 MCP tools 与 inputSchema"},args:{name:{type:"positional",description:"Agent 名称",required:!0},json:{type:"boolean",description:"JSON 格式输出",default:!1}},async run({args:o}){const{agentsConfig:m}=n(),c=new s(m.dataDir).findByName(o.name);if(!c)return a.error(`Agent "${o.name}" 未找到。使用 \`roll agent list\` 查看已注册 Agent。`),void(process.exitCode=1);const p=new i;try{a.info(`连接 Agent "${c.skill.name}" 并获取 MCP tools/list...`);const n=r(c),i=e(m,c.skill.name),s=await p.connect(c.skill.name,n,c.installPath,{...i?{env:i}:{}}),{tools:g}=await s.listTools(),f=l(g);if(o.json)return void console.log(JSON.stringify(f,null,2));if(0===f.length)return void console.log(`Agent "${c.skill.name}" 暂未暴露任何 tool。`);const d=new t({head:["Name","Description","Input Schema"],style:{head:["cyan"]}});for(const o of f)d.push([o.name,o.description??"",JSON.stringify(o.inputSchema,null,2)]);console.log(d.toString())}catch(o){a.error(o instanceof Error?o.message:String(o)),process.exitCode=1}finally{await p.disconnectAll()}}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var t=this&&this.__rewriteRelativeImportExtension||function(t,e){return"string"==typeof t&&/^\.\.?\//.test(t)?t.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i,function(t,n,s,
|
|
1
|
+
var t=this&&this.__rewriteRelativeImportExtension||function(t,e){return"string"==typeof t&&/^\.\.?\//.test(t)?t.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i,function(t,n,s,o,a){return n?e?".jsx":".js":!s||o&&a?s+o+"."+a.toLowerCase()+"js":t}):t};import{defineCommand as e}from"citty";const n=import.meta.url.endsWith(".ts")?"ts":"js";function s(e){const s=new URL(`./${e}.${n}`,import.meta.url).href;return import(t(s)).then(t=>t.default)}export default e({meta:{description:"管理 Agent(支持本地目录、已安装产物、远程服务)"},subCommands:{add:()=>s("agent-add"),install:()=>s("agent-install"),remove:()=>s("agent-remove"),list:()=>s("agent-list"),tools:()=>s("agent-tools"),start:()=>s("agent-start"),stop:()=>s("agent-stop"),info:()=>s("agent-info"),health:()=>s("agent-health")}});
|
package/dist/cli/commands/ask.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineCommand as e}from"citty";import{loadConfig as
|
|
1
|
+
import{defineCommand as e}from"citty";import{loadConfig as s}from"../../config/loader.js";import{getAgentEnv as t,getMissingAgentEnvRuntimeIssues as o,inspectAgentEnvRequirements as r}from"../../config/helpers.js";import{shouldSkipRuntimeReadinessForTool as n}from"../../config/runtime-env.js";import{createProviderModel as i,resolveLLMCall as a}from"../../llm/providers.js";import{McpClientManager as l}from"../../mcp/client-manager.js";import{AgentStore as m}from"../../registry/store.js";import{resolveTransportWithDevSpawnSpec as c}from"../../registry/dev-spawn.js";import{routeWithLLM as u}from"../../router/llm-router.js";import{extractToolInput as d}from"../../tool-runtime/argument-extractor.js";import{formatValidationIssuesMessage as g}from"../../tool-runtime/messages.js";import{preflightToolCall as f}from"../../tool-runtime/preflight.js";import{formatMissingToolMessage as p,normalizeListedTools as v}from"../utils/agent-tools.js";import{log as j}from"../utils/output.js";import{extractTextContent as y,isToolErrorResult as $}from"../utils/tool-results.js";const N=.5;function k(e){console.log(JSON.stringify(e,null,2))}function x(e){const s=y("object"==typeof e.result&&null!==e.result&&"content"in e.result?e.result.content:void 0);for(const e of s)console.log(e)}export default e({meta:{description:"LLM 智能路由,自动选择 Agent 和 tool"},args:{message:{type:"positional",description:"自然语言消息",required:!0},json:{type:"boolean",description:"JSON 格式输出",default:!1}},async run({args:e}){const{config:w}=s(),h=new m(w.agents.dataDir).list();if(0===h.length)return j.error("暂无已注册的 Agent。可使用 `roll agent add <path>`、`roll agent install <package>` 或 `roll agent add --remote <endpoint>`。"),void(process.exitCode=1);const C=s=>{if(e.json)k(s);else if("success"===s.status)x(s)},L=w.llm.defaultProvider,M=w.ask.llmModel??w.llm.defaultModel,S=w.llm.providers[L];if(!S)return j.error(`LLM provider "${L}" 未配置。请检查 roll.config.yaml`),void(process.exitCode=1);const{model:A,providerOptions:I}=a(L,M,S.apiKey,"structured-output",S.baseUrl);let b;j.info(`分析意图: "${e.message}"`);try{b=await u(e.message,h,A,I)}catch(e){const s={status:"failed",stage:"route",message:`LLM 路由失败: ${e instanceof Error?e.message:String(e)}`};return j.error(s.message),C(s),void(process.exitCode=1)}j.info(`路由决策: ${b.agentName}.${b.toolName} (置信度: ${String(b.confidence)})`);const O=w.ask.confirmThreshold??N;if(b.confidence<O){const e={status:"needs_confirmation",decision:b,message:`置信度 ${String(b.confidence)} 低于阈值 ${String(O)},跳过执行。 可使用 \`roll run ${b.agentName} ${b.toolName}\` 手动调用。`};return j.warn(e.message),C(e),void(process.exitCode=1)}const T=h.find(e=>e.skill.name===b.agentName);if(!T){const e={status:"failed",stage:"route",decision:b,message:`Agent "${b.agentName}" 未找到(LLM 返回了无效的 Agent 名称)`};return j.error(e.message),C(e),void(process.exitCode=1)}const J=i(L,w.llm.defaultModel,S.apiKey,S.baseUrl),E=new l;let K="connect";try{j.info(`连接 Agent "${T.skill.name}"...`);const s=t(w,T.skill.name),i=c(T),a=await E.connect(T.skill.name,i,T.installPath,{samplingModel:J,...s?{env:s}:{}}),l=v((await a.listTools()).tools),m=l.find(e=>e.name===b.toolName);if(!m){const e={status:"failed",stage:"route",decision:b,message:p(T.skill.name,b.toolName,l)};return j.error(e.message),C(e),void(process.exitCode=1)}K="execute";const u=await d(e.message,m,A,I),N={...b,input:u},k=r(T.skill.name,T.skill.env,w.agents.env),x=n(m.name)?[]:o(k),h=f(m,N.input,{runtimeIssues:x});if(!h.ok){const e={status:"needs_input",decision:N,validationIssues:h.issues,runtimeIssues:h.runtimeIssues,message:g(T.skill.name,b.toolName,h.issues,h.runtimeIssues)};return j.warn(e.message),C(e),void(process.exitCode=1)}j.info(`调用 ${T.skill.name}.${b.toolName}(${JSON.stringify(N.input)})`);const L=await a.callTool({name:b.toolName,arguments:N.input});if($(L)){const e={status:"failed",stage:"execute",decision:N,message:y(L.content).join("\n")||"Tool 调用失败"};return j.error(e.message),C(e),void(process.exitCode=1)}C({status:"success",decision:N,result:L}),j.success("调用完成")}catch(e){const s={status:"failed",stage:K,decision:b,message:e instanceof Error?e.message:String(e)};j.error(s.message),C(s),process.exitCode=1}finally{await E.disconnectAll()}}});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineCommand as o}from"citty";import{readFileSync as t,writeFileSync as
|
|
1
|
+
import{defineCommand as o}from"citty";import{readFileSync as t,writeFileSync as r,existsSync as e}from"node:fs";import{resolve as n}from"node:path";import{createInterface as i}from"node:readline/promises";import{stringify as s}from"yaml";import{inspectConfigFile as c,loadConfig as a,parseConfigDocument as l,validateConfigText as d}from"../../config/loader.js";import{encodePathToYaml as f,normalizeUserPath as u}from"../../config/key-codec.js";import{applyKnownConfigMigrations as g}from"../../config/migration.js";export default o({meta:{description:"管理全局配置"},args:{action:{type:"positional",description:"操作(init/get/set/migrate)",required:!0},key:{type:"positional",description:"配置键(get/set 时使用,点号分隔)",required:!1},value:{type:"positional",description:"配置值(set 时使用)",required:!1}},async run({args:o}){try{if("init"===o.action)return void await v();if("get"===o.action)return void w(o.key);if("set"===o.action)return void S(o.key,o.value);if("migrate"===o.action)return void $();console.error(`✗ 未知操作: ${o.action}。可用: init, get, set, migrate`),process.exitCode=1}catch(o){const t=o instanceof Error?o.message:String(o);console.error(`✗ ${t}`),process.exitCode=1}}});function p(o,t){const r=o?.trim();return r||t}function m({provider:o,model:t,apiKeyEnv:r}){return`llm:\n default-provider: ${o}\n default-model: ${t}\n providers:\n ${o}:\n api-key: \${${r}}\n\nask:\n confirm-threshold: 0.5\n\nagents:\n data-dir: ~/.roll-agent/agents\n`}async function h(){if(!process.stdin.isTTY){const[o,r,e]=t(0,"utf-8").split(/\r?\n/u);return{provider:p(o,"anthropic"),model:p(r,"claude-sonnet-4-20250514"),apiKeyEnv:p(e,"ANTHROPIC_API_KEY")}}const o=i({input:process.stdin,output:process.stderr}),r=p(await o.question("默认 LLM provider (anthropic/openai/qwen) [anthropic]: "),"anthropic"),e=p(await o.question("默认 model [claude-sonnet-4-20250514]: "),"claude-sonnet-4-20250514"),n=p(await o.question("API Key 环境变量名 [ANTHROPIC_API_KEY]: "),"ANTHROPIC_API_KEY");return o.close(),{provider:r,model:e,apiKeyEnv:n}}async function v(){const o=n(process.cwd(),"roll.config.yaml");if(e(o)){const t=c({configPath:o});switch(t.status){case"needs-migration":console.error(`⚠ 现有配置文件需要迁移: ${o}`),console.error(" 建议先运行 `roll config migrate`,再决定是否重新初始化。");break;case"invalid":console.error(`⚠ 现有配置文件存在问题:\n${t.error.message}`)}if(console.error(`⚠ 配置文件已存在: ${o}`),!process.stdin.isTTY)throw new Error("非交互模式下不会覆盖现有配置文件,请手动删除后重试。");const r=i({input:process.stdin,output:process.stderr}),e=await r.question("是否覆盖?(y/N) ");if(r.close(),"y"!==e.toLowerCase())return void console.error("已取消。")}const t=m(await h());d(t,o),r(o,t,"utf-8"),console.log(`✓ 配置文件已创建: ${o}`)}function y(o){const t=new Date;return`${o}.bak.${[t.getFullYear().toString().padStart(4,"0"),(t.getMonth()+1).toString().padStart(2,"0"),t.getDate().toString().padStart(2,"0"),"-",t.getHours().toString().padStart(2,"0"),t.getMinutes().toString().padStart(2,"0"),t.getSeconds().toString().padStart(2,"0")].join("")}`}function $(){const o=c();if("not-found"===o.status)throw new Error("未找到配置文件。请先运行 roll config init");if("valid"===o.status)return void console.log(`✓ 配置文件已是最新格式,无需迁移: ${o.configPath}`);if("invalid"===o.status)throw o.error;const t=l(o.raw,o.configPath),e=g(t);if(!e.ok){const o=e.issues.map(o=>` - ${o.message}`).join("\n");throw new Error(`配置无法自动迁移:\n${o}`)}if(!e.changed)return void console.log(`✓ 配置文件已是最新格式,无需迁移: ${o.configPath}`);const n=y(o.configPath);r(n,o.raw,"utf-8");const i=s(e.document,{lineWidth:0});d(i,o.configPath),r(o.configPath,i,"utf-8"),console.log(`✓ 配置文件已迁移: ${o.configPath}`),console.log(`✓ 已备份原文件: ${n}`);for(const o of e.summary)console.log(` - ${o}`)}function w(o){const{config:t,configPath:r}=a();if(!o)return console.log(JSON.stringify(t,null,2)),void(r&&console.error(`(来源: ${r})`));const e=u(o.split("."));let n=t;for(const t of e){if("object"!=typeof n||null===n)return console.error(`✗ 配置键 "${o}" 不存在`),void(process.exitCode=1);n=n[t]}if(void 0===n)return console.error(`✗ 配置键 "${o}" 不存在`),void(process.exitCode=1);console.log("object"==typeof n?JSON.stringify(n,null,2):String(n))}function S(o,e){if(!o||void 0===e)return console.error("✗ 用法: roll config set <key> <value>"),console.error(" 示例: roll config set ask.confirmThreshold 0.5"),void(process.exitCode=1);const{configPath:n}=a();if(!n)return console.error("✗ 未找到配置文件。请先运行 roll config init"),void(process.exitCode=1);const i=t(n,"utf-8"),c=l(i,n),u=f(o.split(".")),g=u[u.length-1];if(void 0===g)return console.error("✗ 配置键不能为空"),void(process.exitCode=1);let p=c;for(let o=0;o<u.length-1;o++){const t=u[o],r=p[t];("object"!=typeof r||null===r||Array.isArray(r))&&(p[t]={}),p=p[t]}let m=e;"true"===e?m=!0:"false"===e?m=!1:/^\d+(\.\d+)?$/.test(e)&&(m=Number(e)),p[g]=m;const h=s(c,{lineWidth:0});d(h,n),r(n,h,"utf-8"),console.log(`✓ ${o} = ${String(m)}`),console.error(` (已写入: ${n})`)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{defineCommand as s}from"citty";import{existsSync as e}from"node:fs";import{inspectAgentEnvRequirements as n}from"../../config/helpers.js";import{inspectConfigFile as
|
|
1
|
+
import{defineCommand as s}from"citty";import{existsSync as e}from"node:fs";import{getAgentEnvFromAgentsConfig as t,inspectAgentEnvRequirements as n}from"../../config/helpers.js";import{inspectConfigFile as o,loadAgentsConfig as a,loadConfig as r}from"../../config/loader.js";import{inspectAgentRuntimeEnvRequirements as i,summarizeAgentRuntimeEnvReport as m}from"../../config/runtime-env.js";import{inspectAgentRuntimeEnv as g}from"../../mcp/agent-diagnostics.js";import{AgentStore as c}from"../../registry/store.js";const l={ok:"✓",warn:"⚠",fail:"✗"},u={major:22,minor:6,patch:0};export function isNodeVersionSupported(s){const e=/^(\d+)\.(\d+)\.(\d+)/.exec(s);if(!e)return!1;const t=Number(e[1]),n=Number(e[2]),o=Number(e[3]);return t>u.major||!(t<u.major)&&(n>u.minor||!(n<u.minor)&&o>=u.patch)}export default s({meta:{description:"诊断系统状态"},args:{json:{type:"boolean",description:"JSON 格式输出",default:!1}},async run({args:s}){const u=[];let p;const f=process.versions.node;u.push(isNodeVersionSupported(f)?{name:"Node.js 版本",status:"ok",message:`v${f}`}:{name:"Node.js 版本",status:"fail",message:`v${f} (需要 ≥22.6.0)`});const d=o();let h;switch(d.status){case"not-found":u.push({name:"配置文件",status:"warn",message:"未找到,使用默认配置"}),p=r().config;break;case"valid":u.push({name:"配置文件",status:"ok",message:d.configPath}),p=d.config;break;case"needs-migration":u.push({name:"配置文件",status:"warn",message:`${d.configPath} (需要迁移,运行 roll config migrate)`});break;case"invalid":u.push({name:"配置文件",status:"fail",message:d.error.message})}try{h=a().agentsConfig}catch(s){u.push({name:"Agent 配置",status:"fail",message:s instanceof Error?s.message:String(s)})}if(p){const s=Object.keys(p.llm.providers);if(s.length>0){const e=s.filter(s=>{const e=p.llm.providers[s]?.apiKey??"";return e.startsWith("${")||0===e.length});e.length>0?u.push({name:"LLM Providers",status:"warn",message:`${s.join(", ")} (${e.join(", ")} API key 未设置)`}):u.push({name:"LLM Providers",status:"ok",message:s.join(", ")})}else u.push({name:"LLM Providers",status:"warn",message:"未配置任何 provider"})}else"needs-migration"===d.status&&u.push({name:"LLM Providers",status:"warn",message:"配置需要迁移,跳过完整 LLM 配置校验"});if(h){const s=h.dataDir;u.push(e(s)?{name:"Agent 数据目录",status:"ok",message:s}:{name:"Agent 数据目录",status:"warn",message:`${s} (不存在,首次 add 时创建)`});const o=new c(h.dataDir).list();u.push({name:"已注册 Agent",status:o.length>0?"ok":"warn",message:o.length>0?`${String(o.length)} 个 (${o.map(s=>s.skill.name).join(", ")})`:"无"});for(const s of o){const e=n(s.skill.name,s.skill.env,h.env);if(!e)continue;const o=await g(s,{agentsConfig:h}),a=i(e,t(h,s.skill.name),o),r=m(a);u.push({name:`Agent 环境变量 (${s.skill.name})`,status:r.status,message:r.message})}}const j=u.some(s=>"fail"===s.status);if(s.json)return console.log(JSON.stringify(u,null,2)),void(j&&(process.exitCode=1));console.log("Roll Agent 系统诊断\n");for(const s of u){const e=l[s.status];console.log(` ${e} ${s.name}: ${s.message}`)}console.log(j?"\n存在问题,请修复后重试。":"\n系统状态正常。"),j&&(process.exitCode=1)}});
|
package/dist/cli/commands/run.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFileSync as
|
|
1
|
+
import{readFileSync as o}from"node:fs";import{defineCommand as t}from"citty";import{loadConfig as r}from"../../config/loader.js";import{getAgentEnv as e,getMissingAgentEnvRuntimeIssues as n,inspectAgentEnvRequirements as s}from"../../config/helpers.js";import{AgentStore as i}from"../../registry/store.js";import{McpClientManager as l}from"../../mcp/client-manager.js";import{resolveTransportWithDevSpawnSpec as a}from"../../registry/dev-spawn.js";import{createProviderModel as c}from"../../llm/providers.js";import{formatValidationIssuesMessage as f}from"../../tool-runtime/messages.js";import{preflightToolCall as p}from"../../tool-runtime/preflight.js";import{formatMissingToolMessage as u,normalizeListedTools as m}from"../utils/agent-tools.js";import{extractTextContent as g,isToolErrorResult as d}from"../utils/tool-results.js";import{log as h}from"../utils/output.js";import{shouldSkipRuntimeReadinessForTool as j}from"../../config/runtime-env.js";export default t({meta:{description:"声明式调用 Agent 的指定 tool"},args:{agent:{type:"positional",description:"Agent 名称",required:!0},tool:{type:"positional",description:"Tool 名称",required:!0},json:{type:"boolean",description:"JSON 格式输出",default:!1},"input-json":{type:"string",description:"以 JSON 字符串提供完整 tool 输入对象"},"input-file":{type:"string",description:"从 JSON 文件读取完整 tool 输入对象"}},async run({args:o,rawArgs:t}){const{config:y}=r(),v=new i(y.agents.dataDir).findByName(o.agent);if(!v)return h.error(`Agent "${o.agent}" 未注册。使用 \`roll agent list\` 查看已注册 Agent。`),void(process.exitCode=1);let w;try{w=resolveToolArgs(t)}catch(o){return h.error(o instanceof Error?o.message:String(o)),void(process.exitCode=1)}const S=new l;try{const t=y.llm.defaultProvider,r=y.llm.providers[t],i=r?c(t,y.llm.defaultModel,r.apiKey,r.baseUrl):void 0;h.info(`连接 Agent "${v.skill.name}"...`);const l=e(y,v.skill.name),$=a(v),A=await S.connect(v.skill.name,$,v.installPath,{...i?{samplingModel:i}:{},...l?{env:l}:{}}),N=m((await A.listTools()).tools),x=N.find(t=>t.name===o.tool);if(!x)return h.error(u(v.skill.name,o.tool,N)),void(process.exitCode=1);const E=s(v.skill.name,v.skill.env,y.agents.env),k=j(x.name)?[]:n(E),T=p(x,w,{runtimeIssues:k});if(!T.ok)return h.error(f(v.skill.name,o.tool,T.issues,T.runtimeIssues)),void(process.exitCode=1);h.info(`调用 ${v.skill.name}.${o.tool}(${JSON.stringify(w)})`);const J=await A.callTool({name:o.tool,arguments:w});if(o.json)console.log(JSON.stringify(J,null,2));else for(const o of g(J.content))console.log(o);if(d(J))return h.error("tool 返回 isError=true"),void(process.exitCode=1);h.success("调用完成")}catch(o){const t=o instanceof Error?o.message:String(o),r=o instanceof Error&&o.cause?`\n cause: ${String(o.cause)}`:"";h.error(`${t}${r}`),process.exitCode=1}finally{await S.disconnectAll()}}});const y=new Set(["json","verbose","v","help","h","version"]),v=new Set(["config","input-json","input-file"]);function w(o){return"object"==typeof o&&null!==o&&!Array.isArray(o)}function S(o,t){let r;try{r=JSON.parse(o)}catch(o){throw new Error(`${t} 不是合法 JSON: ${o instanceof Error?o.message:String(o)}`)}if(!w(r))throw new Error(`${t} 必须是 JSON object`);return r}function $(o,t){let r=0;for(;r<o.length&&!o[r]?.startsWith("--");)r++;for(;r<o.length;){if(o[r]!==`--${t}`){r++;continue}const e=o[r+1];if(!e||e.startsWith("--"))throw new Error(`选项 --${t} 需要提供值`);return e}}export function parseExplicitToolInput(t){const r=$(t,"input-json"),e=$(t,"input-file");if(r&&e)throw new Error("不能同时使用 --input-json 和 --input-file");if(r)return S(r,"--input-json");if(e){return S(o(e,"utf-8"),`输入文件 ${e}`)}}export function resolveToolArgs(o){return{...parseExplicitToolInput(o)??{},...parseToolArgs(o)}}export function parseToolArgs(o){const t={};let r=0;for(;r<o.length&&!o[r]?.startsWith("--");)r++;for(;r<o.length;){const e=o[r];if(!e?.startsWith("--")){r++;continue}const n=e.slice(2),s=o[r+1];if(y.has(n))r++;else if(v.has(n))r+=s&&!s.startsWith("--")?2:1;else if(!s||s.startsWith("--"))t[n]=!0,r++;else{const o=Number(s);t[n]=Number.isNaN(o)?s:o,r+=2}}return t}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import type { AgentTool } from "../../types/agent.ts";
|
|
3
|
+
type ListedTool = Awaited<ReturnType<Client["listTools"]>>["tools"][number];
|
|
4
|
+
export declare function normalizeListedTools(tools: readonly ListedTool[]): AgentTool[];
|
|
5
|
+
export declare function getToolNameSuggestions(requestedToolName: string, tools: ReadonlyArray<Pick<AgentTool, "name">>, maxSuggestions?: number): string[];
|
|
6
|
+
export declare function formatMissingToolMessage(agentName: string, requestedToolName: string, tools: ReadonlyArray<Pick<AgentTool, "name">>): string;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isJsonSchemaObject as e,isPlainObject as t}from"../../tool-runtime/schema.js";const n=/[-_\s]+/,o=/[^a-z0-9]+/g;function r(e){return e.toLowerCase().replace(o,"")}function i(e){return e.toLowerCase().split(n).map(e=>e.trim()).filter(e=>e.length>0)}function s(e,t){if(e===t)return 0;if(0===e.length)return t.length;if(0===t.length)return e.length;const n=Array.from({length:t.length+1},(e,t)=>t),o=new Array(t.length+1).fill(0);for(let r=0;r<e.length;r+=1){o[0]=r+1;for(let i=0;i<t.length;i+=1){const s=e[r]===t[i]?0:1,a=(n[i+1]??Number.POSITIVE_INFINITY)+1,l=(o[i]??Number.POSITIVE_INFINITY)+1,c=(n[i]??Number.POSITIVE_INFINITY)+s;o[i+1]=Math.min(a,l,c)}n.splice(0,n.length,...o)}return n[t.length]??Math.max(e.length,t.length)}function a(e,t){const n=[...t];let o=0;for(const t of e){const e=n.indexOf(t);-1!==e&&(o+=1,n.splice(e,1))}return o}function l(e,t){const n=r(e),o=r(t),l=i(e),c=i(t),u=s(n,o),m=a(l,c);return{name:t,distance:u,tokenOverlap:m,score:u-3*m-(o.startsWith(n)||n.startsWith(o)?2:0)-(o.includes(n)||n.includes(o)?1:0)}}function c(e,t){const n=r(t),o=Math.max(2,Math.floor(.45*n.length));return e.tokenOverlap>0||e.distance<=o}function u(e,t){return e.score!==t.score?e.score-t.score:e.distance!==t.distance?e.distance-t.distance:e.tokenOverlap!==t.tokenOverlap?t.tokenOverlap-e.tokenOverlap:e.name.localeCompare(t.name)}function m(n){return t(n)&&e(n)?n:{type:"object"}}export function normalizeListedTools(e){return e.map(e=>({name:e.name,..."string"==typeof e.description?{description:e.description}:{},inputSchema:m(e.inputSchema)}))}export function getToolNameSuggestions(e,t,n=3){return t.map(t=>l(e,t.name)).filter(t=>c(t,e)).sort(u).slice(0,n).map(e=>e.name)}export function formatMissingToolMessage(e,t,n){const o=getToolNameSuggestions(t,n),r=n.map(e=>`\`${e.name}\``),i=[`Tool "${t}" 不存在于 Agent "${e}" 中。`];if(1===o.length){const[e]=o;void 0!==e&&i.push(`Did you mean: \`${e}\`?`)}else o.length>1&&i.push(`Did you mean one of: ${o.map(e=>`\`${e}\``).join(", ")}?`);return r.length>0&&i.push(`可用 tools: ${r.join(", ")}`),i.push(`使用 \`roll agent tools ${e}\` 查看完整 tool 列表与 inputSchema。`),i.join("\n")}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function extractTextContent(t){if(!Array.isArray(t))return[];const r=[];for(const e of t)"object"==typeof e&&null!==e&&"type"in e&&"text"===e.type&&"text"in e&&"string"==typeof e.text&&r.push(e.text);return r}export function isToolErrorResult(t){return"object"==typeof t&&null!==t&&"isError"in t&&!0===t.isError}
|
package/dist/config/helpers.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentSkillEnvDeclarations } from "../types/agent.ts";
|
|
2
|
+
import type { AskRuntimeIssue } from "../types/ask.ts";
|
|
2
3
|
import type { RollConfig } from "./schema.ts";
|
|
3
4
|
type AgentEnvMap = RollConfig["agents"]["env"];
|
|
4
5
|
export interface AgentEnvCheckItem {
|
|
@@ -14,7 +15,9 @@ export interface AgentEnvCheckReport {
|
|
|
14
15
|
readonly missingRequired: readonly AgentEnvCheckItem[];
|
|
15
16
|
readonly processEnvOnlyRequired: readonly AgentEnvCheckItem[];
|
|
16
17
|
}
|
|
18
|
+
export declare function getAgentEnvFromAgentsConfig(agentsConfig: RollConfig["agents"], agentName: string): Readonly<Record<string, string>> | undefined;
|
|
17
19
|
/** 获取指定 Agent 的环境变量配置,没有则返回 undefined */
|
|
18
20
|
export declare function getAgentEnv(config: RollConfig, agentName: string): Readonly<Record<string, string>> | undefined;
|
|
19
21
|
export declare function inspectAgentEnvRequirements(agentName: string, declarations: AgentSkillEnvDeclarations | undefined, envMap: AgentEnvMap, inheritedEnv?: NodeJS.ProcessEnv): AgentEnvCheckReport | undefined;
|
|
22
|
+
export declare function getMissingAgentEnvRuntimeIssues(report: AgentEnvCheckReport | undefined): ReadonlyArray<AskRuntimeIssue>;
|
|
20
23
|
export {};
|
package/dist/config/helpers.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=/\$\{[^}]+\}/;function
|
|
1
|
+
const e=/\$\{[^}]+\}/;function n(e,n){return e?.[n]}export function getAgentEnvFromAgentsConfig(e,r){return t(n(e.env,r))}export function getAgentEnv(e,n){return getAgentEnvFromAgentsConfig(e.agents,n)}export function inspectAgentEnvRequirements(e,i,s,u=process.env){if(!i)return;const o=t(n(s,e)),g=[...r(i.required,!0,o,u),...r(i.optional,!1,o,u)];return 0!==g.length?{items:g,missingRequired:g.filter(e=>e.required&&"missing"===e.source),processEnvOnlyRequired:g.filter(e=>e.required&&"process.env"===e.source)}:void 0}export function getMissingAgentEnvRuntimeIssues(e){return e?e.missingRequired.map(e=>({category:"env",code:"missing_required_env",name:e.name,message:`必填环境变量 ${e.name} 未配置`,...e.purpose?{purpose:e.purpose}:{},...e.example?{example:e.example}:{}})):[]}function r(e,n,r,t){return e?e.map(e=>{const i=r?.[e.name];if(void 0!==i&&i.length>0)return{...e,required:n,source:"agents.env"};const s=t[e.name];return"string"==typeof s&&s.length>0?{...e,required:n,source:"process.env"}:e.default?{...e,required:n,source:"default"}:{...e,required:n,source:"missing"}}):[]}function t(e){if(!e)return;const n=Object.entries(e).filter(([,e])=>i(e));return 0!==n.length?Object.fromEntries(n):void 0}function i(n){return"string"==typeof n&&n.length>0&&!e.test(n)}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type KeyCodecNode = {
|
|
2
|
+
readonly kind: "object";
|
|
3
|
+
readonly fields: Readonly<Record<string, KeyCodecNode>>;
|
|
4
|
+
} | {
|
|
5
|
+
readonly kind: "record";
|
|
6
|
+
readonly value: KeyCodecNode;
|
|
7
|
+
} | {
|
|
8
|
+
readonly kind: "leaf";
|
|
9
|
+
};
|
|
10
|
+
export declare const CONFIG_KEY_CODEC: KeyCodecNode;
|
|
11
|
+
export declare function kebabToCamel(key: string): string;
|
|
12
|
+
export declare function camelToKebab(key: string): string;
|
|
13
|
+
export declare function decodeFromYaml(value: unknown, node?: KeyCodecNode): unknown;
|
|
14
|
+
export declare function encodePathToYaml(parts: readonly string[]): string[];
|
|
15
|
+
export declare function normalizeUserPath(parts: readonly string[]): string[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e={kind:"leaf"},r={kind:"object",fields:{apiKey:e,baseUrl:e}};export const CONFIG_KEY_CODEC={kind:"object",fields:{llm:{kind:"object",fields:{defaultProvider:e,defaultModel:e,providers:{kind:"record",value:r}}},ask:{kind:"object",fields:{llmModel:e,confirmThreshold:e}},agents:{kind:"object",fields:{dataDir:e,env:{kind:"record",value:{kind:"record",value:e}}}}}};export function kebabToCamel(e){return e.replace(/-([a-z])/g,(e,r)=>r.toUpperCase())}export function camelToKebab(e){return e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}function o(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}export function decodeFromYaml(r,n=CONFIG_KEY_CODEC){if(Array.isArray(r))return r.map(e=>decodeFromYaml(e,n));if(!o(r))return r;if("object"===n.kind){const o={};for(const[t,a]of Object.entries(r)){const r=kebabToCamel(t),c=n.fields[r]??e;o[r]=decodeFromYaml(a,c)}return o}if("record"===n.kind){const e={};for(const[o,t]of Object.entries(r))e[o]=decodeFromYaml(t,n.value);return e}return r}function n(r,o){const n=[];let t=CONFIG_KEY_CODEC;for(const a of r)if("object"===t.kind){const r=kebabToCamel(a),c=t.fields[r];c?(n.push("camel"===o?r:camelToKebab(r)),t=c):(n.push(a),t=e)}else"record"===t.kind?(n.push(a),t=t.value):n.push(a);return n}export function encodePathToYaml(e){return n(e,"kebab")}export function normalizeUserPath(e){return n(e,"camel")}
|
package/dist/config/loader.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFileSync as n,existsSync as r}from"node:fs";import{resolve as t}from"node:path";import{parse as o}from"yaml";import{agentsConfigSchema as e,rollConfigSchema as i}from"./schema.js";import{DEFAULT_CONFIG as a,CONFIG_FILE_NAMES as s}from"./defaults.js";import{
|
|
1
|
+
import{readFileSync as n,existsSync as r}from"node:fs";import{resolve as t}from"node:path";import{parse as o}from"yaml";import{agentsConfigSchema as e,rollConfigSchema as i}from"./schema.js";import{DEFAULT_CONFIG as a,CONFIG_FILE_NAMES as s}from"./defaults.js";import{decodeFromYaml as f}from"./key-codec.js";import{detectKnownConfigMigrations as c,formatConfigMigrationError as u}from"./migration.js";function g(n){if("string"==typeof n)return n.replace(/\$\{([^}]+)\}/g,(n,r)=>process.env[r]??n);if(Array.isArray(n))return n.map(g);if(l(n)){const r={};for(const[t,o]of Object.entries(n))r[t]=g(o);return r}return n}function l(n){return"object"==typeof n&&null!==n&&!Array.isArray(n)}function d(n){return l(n)&&"number"==typeof n.line&&"number"==typeof n.col}function p(n){return n instanceof Error&&"linePos"in n&&Array.isArray(n.linePos)&&n.linePos.length>0&&n.linePos.every(d)}function h(n,r){const t=`Invalid YAML syntax in config file: ${n}`;if(!(r instanceof Error))return`${t}\n${String(r)}`;if(p(r)){const[n]=r.linePos;if(n)return`${t} at line ${n.line}, column ${n.col}\n${r.message}`}return`${t}\n${r.message}`}function m(n){let o=t(n);const e=t("/");for(;o!==e;){for(const n of s){const e=t(o,n);if(r(e))return e}const n=t(o,"..");if(n===o)break;o=n}}function v(n){if(n.startsWith("~/")){const r=process.env.HOME??process.env.USERPROFILE??"";return t(r,n.slice(2))}return n}function w(n){return{...n,agents:{...n.agents,dataDir:v(n.agents.dataDir)}}}const $={notFound:"not-found",valid:"valid",needsMigration:"needs-migration",invalid:"invalid"};export function parseConfigDocument(n,r){let t;try{t=o(n)}catch(n){throw new Error(h(r,n),{cause:n instanceof Error?n:void 0})}if(!l(t))throw new Error(`Invalid config file: ${r} (expected YAML object)`);return t}function y(n,r,t={}){const o=parseConfigDocument(n,r),e=c(o,t);if(e.needsMigration)throw new Error(u(r,e));return o}export function validateConfigText(n,r){const t=y(n,r),o=g(f(t));if(!l(o))throw new Error(`Invalid config file: ${r} (expected YAML object)`);const e=C(a,o),s=i.safeParse(e);if(!s.success){const n=s.error.issues.map(n=>` - ${n.path.join(".")}: ${n.message}`).join("\n");throw new Error(`Config validation failed (${r}):\n${n}`)}return w(s.data)}function P(n,r){const t=y(n,r,{scope:"agents"}),o=g(f(t));if(!l(o))throw new Error(`Invalid config file: ${r} (expected YAML object)`);const i=l(o.agents)?o.agents:{},s=C(a.agents,i),c=e.safeParse(s);if(!c.success){const n=c.error.issues.map(n=>` - agents.${n.path.join(".")}: ${n.message}`).join("\n");throw new Error(`Config validation failed (${r}):\n${n}`)}return{...c.data,dataDir:v(c.data.dataDir)}}export function loadConfig(t={}){const o=resolveConfigPath(t);if(!o)return{config:w(a),configPath:void 0};if(!r(o))throw new Error(`Config file not found: ${o}`);return{config:validateConfigText(n(o,"utf-8"),o),configPath:o}}export function loadAgentsConfig(t={}){const o=resolveConfigPath(t);if(!o)return{agentsConfig:{...a.agents,dataDir:v(a.agents.dataDir)},configPath:void 0};if(!r(o))throw new Error(`Config file not found: ${o}`);return{agentsConfig:P(n(o,"utf-8"),o),configPath:o}}export function resolveConfigPath(n={}){const{configPath:r,cwd:t=process.cwd()}=n;return r??m(t)}export function inspectConfigFile(t={}){const o=resolveConfigPath(t);if(!o)return{status:$.notFound,configPath:void 0};if(!r(o))return{status:$.invalid,configPath:o,raw:"",error:new Error(`Config file not found: ${o}`)};const e=n(o,"utf-8");let i;try{i=parseConfigDocument(e,o)}catch(n){return{status:$.invalid,configPath:o,raw:e,error:n instanceof Error?n:new Error(String(n))}}const a=c(i);if(a.needsMigration)return{status:$.needsMigration,configPath:o,raw:e,report:a};try{return{status:$.valid,configPath:o,config:validateConfigText(e,o)}}catch(n){return{status:$.invalid,configPath:o,raw:e,error:n instanceof Error?n:new Error(String(n))}}}function C(n,r){const t={...n};for(const[o,e]of Object.entries(r)){const r=n[o];"object"!=typeof e||null===e||Array.isArray(e)||"object"!=typeof r||null===r||Array.isArray(r)?t[o]=e:t[o]=C(r,e)}return t}
|
|
@@ -5,6 +5,8 @@ declare const CONFIG_MIGRATION_ISSUE_CODES: {
|
|
|
5
5
|
readonly routerAskConflict: "router-ask-conflict";
|
|
6
6
|
readonly duplicateEquivalentKeys: "duplicate-equivalent-keys";
|
|
7
7
|
readonly unknownRouterKeys: "unknown-router-keys";
|
|
8
|
+
readonly legacyCamelCaseAgentEnvKey: "legacy-camelcase-agent-env-key";
|
|
9
|
+
readonly legacyAgentEnvKeyConflict: "legacy-agent-env-key-conflict";
|
|
8
10
|
};
|
|
9
11
|
type ConfigMigrationIssueCode = (typeof CONFIG_MIGRATION_ISSUE_CODES)[keyof typeof CONFIG_MIGRATION_ISSUE_CODES];
|
|
10
12
|
export interface ConfigMigrationIssue {
|
|
@@ -27,7 +29,10 @@ export type ApplyKnownConfigMigrationsResult = {
|
|
|
27
29
|
readonly changed: false;
|
|
28
30
|
readonly issues: readonly ConfigMigrationIssue[];
|
|
29
31
|
};
|
|
30
|
-
export
|
|
32
|
+
export type ConfigMigrationScope = "llm" | "ask" | "agents";
|
|
33
|
+
export declare function detectKnownConfigMigrations(document: Record<string, unknown>, options?: {
|
|
34
|
+
readonly scope?: ConfigMigrationScope;
|
|
35
|
+
}): ConfigMigrationReport;
|
|
31
36
|
export declare function applyKnownConfigMigrations(document: Record<string, unknown>): ApplyKnownConfigMigrationsResult;
|
|
32
37
|
export declare function formatConfigMigrationError(configPath: string, report: ConfigMigrationReport): string;
|
|
33
38
|
export {};
|
package/dist/config/migration.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const
|
|
1
|
+
import{camelToKebab as e}from"./key-codec.js";const t={deprecatedRouterSection:"deprecated-router-section",invalidAskSection:"invalid-ask-section",invalidRouterSection:"invalid-router-section",routerAskConflict:"router-ask-conflict",duplicateEquivalentKeys:"duplicate-equivalent-keys",unknownRouterKeys:"unknown-router-keys",legacyCamelCaseAgentEnvKey:"legacy-camelcase-agent-env-key",legacyAgentEnvKeyConflict:"legacy-agent-env-key-conflict"},s={llmModel:{routerKeys:["llm-model","llmModel"],askKeys:["llm-model","llmModel"],targetAskKey:"llm-model"},confirmThreshold:{routerKeys:["confirm-threshold","confirmThreshold"],askKeys:["confirm-threshold","confirmThreshold"],targetAskKey:"confirm-threshold"}},n=[...s.llmModel.routerKeys,...s.confirmThreshold.routerKeys,"mode"],o=new Set([t.invalidAskSection,t.invalidRouterSection,t.routerAskConflict,t.unknownRouterKeys,t.legacyAgentEnvKeyConflict]);function r(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function u(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function i(e,t){return{code:e,message:t}}function c(e,t){return t.filter(t=>u(e,t))}function a(e,s,n){const o=c(s,n);if(0===o.length)return{ok:!0,key:void 0,value:void 0};const[r]=o,u=r?s[r]:void 0;return o.some(e=>s[e]!==u)?{ok:!1,issue:i(t.duplicateEquivalentKeys,`\`${e}\` 同时包含等价键 ${o.join(", ")} 且值不一致,请手动处理。`)}:{ok:!0,key:r,value:u}}function l(e){if(!u(e,"router"))return{matches:!1,canAutoMigrate:!1,issues:[]};const c=[i(t.deprecatedRouterSection,"`router` 配置段已废弃,请改用 `ask`。"),i(t.deprecatedRouterSection,"将 `router.llm-model` 迁移为 `ask.llm-model`。"),i(t.deprecatedRouterSection,"将 `router.confirm-threshold` 迁移为 `ask.confirm-threshold`。"),i(t.deprecatedRouterSection,"删除 `router.mode`;命令本身已决定策略(`run` / `ask` / `chat`)。")],l=e.router;if(!r(l))return c.push(i(t.invalidRouterSection,"`router` 配置段不是对象,无法自动迁移,请手动修复。")),{matches:!0,canAutoMigrate:!1,issues:c};const d=Object.keys(l).filter(e=>!n.includes(e));d.length>0&&c.push(i(t.unknownRouterKeys,`\`router\` 包含无法自动迁移的未知键:${d.join(", ")}。`));const g=e.ask;if(void 0===g||r(g)||c.push(i(t.invalidAskSection,"`ask` 配置段不是对象,无法自动迁移,请手动修复。")),r(g))for(const e of Object.keys(s)){const n=s[e],o=a("router",l,n.routerKeys),r=a("ask",g,n.askKeys);o.ok?r.ok?o.key&&r.key&&r.value!==o.value&&c.push(i(t.routerAskConflict,`\`router.${n.targetAskKey}\` 与 \`ask.${n.targetAskKey}\` 同时存在且值冲突,请手动处理。`)):c.push(r.issue):c.push(o.issue)}return{matches:!0,canAutoMigrate:!c.some(e=>o.has(e.code)),issues:c}}function d(e){const t=l(e);if(!t.matches)return{ok:!0,changed:!1,document:structuredClone(e),issues:[],summary:[]};if(!t.canAutoMigrate)return{ok:!1,changed:!1,issues:t.issues};const n=structuredClone(e),o=n.router;if(!r(o))return{ok:!1,changed:!1,issues:t.issues};const i=n.ask,c=r(i)?i:{};let d=!1;const g=[];for(const e of Object.keys(s)){const t=s[e],n=a("router",o,t.routerKeys);if(!n.ok)return{ok:!1,changed:!1,issues:[n.issue]};if(!n.key)continue;const r=a("ask",c,t.askKeys);if(!r.ok)return{ok:!1,changed:!1,issues:[r.issue]};r.key?g.push(`移除已废弃的 \`router.${t.targetAskKey}\``):(c[t.targetAskKey]=n.value,d=!0,g.push(`将 \`router.${t.targetAskKey}\` 迁移到 \`ask.${t.targetAskKey}\``));for(const e of t.routerKeys)u(o,e)&&delete o[e]}return u(o,"mode")&&(delete o.mode,g.push("删除已废弃的 `router.mode`")),d&&(n.ask=c),0===Object.keys(o).length&&(delete n.router,g.push("删除空的 `router` 配置段")),{ok:!0,changed:g.length>0,document:n,issues:t.issues,summary:g}}const g=/^[a-z0-9]+(-[a-z0-9]+)*$/;function f(e){return!g.test(e)}function k(t){const s=e(t).toLowerCase();return g.test(s)?s:void 0}function y(e){const s=e.agents;if(!r(s))return{matches:!1,canAutoMigrate:!1,issues:[]};const n=s.env;if(!r(n))return{matches:!1,canAutoMigrate:!1,issues:[]};const o=Object.keys(n).filter(f);if(0===o.length)return{matches:!1,canAutoMigrate:!1,issues:[]};const c=[];let a=!1;for(const e of o){const s=k(e);void 0!==s?u(n,s)?(a=!0,c.push(i(t.legacyAgentEnvKeyConflict,`\`agents.env\` 下同时存在 \`${e}\` 与 \`${s}\`,无法自动合并,请手动处理。`))):c.push(i(t.legacyCamelCaseAgentEnvKey,`\`agents.env.${e}\` 应使用 kebab-case(\`${s}\`)。`)):(a=!0,c.push(i(t.legacyAgentEnvKeyConflict,`\`agents.env.${e}\` 命名不符合 kebab-case 规范,无法自动迁移,请手动重命名。`)))}return{matches:!0,canAutoMigrate:!a,issues:c}}function h(e){const t=y(e);if(!t.matches)return{ok:!0,changed:!1,document:structuredClone(e),issues:[],summary:[]};if(!t.canAutoMigrate)return{ok:!1,changed:!1,issues:t.issues};const s=structuredClone(e),n=s.agents;if(!r(n))return{ok:!1,changed:!1,issues:t.issues};const o=n.env;if(!r(o))return{ok:!1,changed:!1,issues:t.issues};const u=[];for(const e of Object.keys(o).filter(f)){const t=k(e);void 0!==t&&(o[t]=o[e],delete o[e],u.push(`将 \`agents.env.${e}\` 重命名为 \`agents.env.${t}\``))}return{ok:!0,changed:u.length>0,document:s,issues:t.issues,summary:u}}const m=[{id:"router-to-ask",scopes:new Set(["ask"]),inspect:l,apply:d},{id:"legacy-agent-env-keys",scopes:new Set(["agents"]),inspect:y,apply:h}];export function detectKnownConfigMigrations(e,t={}){const{scope:s}=t,n=(void 0!==s?m.filter(e=>e.scopes.has(s)):m).map(t=>t.inspect(e)).filter(e=>e.matches);return 0===n.length?{needsMigration:!1,canAutoMigrate:!1,issues:[]}:{needsMigration:!0,canAutoMigrate:n.every(e=>e.canAutoMigrate),issues:n.flatMap(e=>e.issues)}}export function applyKnownConfigMigrations(e){let t=structuredClone(e);const s=[],n=[];let o=!1;for(const e of m){const r=e.apply(t);if(!r.ok)return{ok:!1,changed:!1,issues:r.issues};t=r.document,r.changed&&(o=!0,s.push(...r.summary)),n.push(...r.issues)}return{ok:!0,changed:o,document:t,summary:s,issues:n}}export function formatConfigMigrationError(e,t){const s=[`Config validation failed (${e}):`];for(const e of t.issues)s.push(` - ${e.message}`);return t.canAutoMigrate?s.push(" - 可运行 `roll config migrate` 自动迁移当前配置。"):t.needsMigration&&s.push(" - 检测到配置迁移冲突,请手动处理后再重试。"),s.join("\n")}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { AgentEnvCheckItem, AgentEnvCheckReport } from "./helpers.ts";
|
|
3
|
+
export declare const DIAGNOSTIC_TOOL_CANDIDATES: readonly ["diagnostic_status", "browser_status"];
|
|
4
|
+
export type DiagnosticToolName = (typeof DIAGNOSTIC_TOOL_CANDIDATES)[number];
|
|
5
|
+
export declare const EffectiveEnvSourceSchema: z.ZodObject<{
|
|
6
|
+
present: z.ZodBoolean;
|
|
7
|
+
fingerprint: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, "strip", z.ZodTypeAny, {
|
|
9
|
+
present: boolean;
|
|
10
|
+
fingerprint?: string | undefined;
|
|
11
|
+
}, {
|
|
12
|
+
present: boolean;
|
|
13
|
+
fingerprint?: string | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
export declare const AgentRuntimeEnvDiagnosticPayloadSchema: z.ZodObject<{
|
|
16
|
+
effectiveEnvSources: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
17
|
+
present: z.ZodBoolean;
|
|
18
|
+
fingerprint: z.ZodOptional<z.ZodString>;
|
|
19
|
+
}, "strip", z.ZodTypeAny, {
|
|
20
|
+
present: boolean;
|
|
21
|
+
fingerprint?: string | undefined;
|
|
22
|
+
}, {
|
|
23
|
+
present: boolean;
|
|
24
|
+
fingerprint?: string | undefined;
|
|
25
|
+
}>>;
|
|
26
|
+
}, "strip", z.ZodTypeAny, {
|
|
27
|
+
effectiveEnvSources: Record<string, {
|
|
28
|
+
present: boolean;
|
|
29
|
+
fingerprint?: string | undefined;
|
|
30
|
+
}>;
|
|
31
|
+
}, {
|
|
32
|
+
effectiveEnvSources: Record<string, {
|
|
33
|
+
present: boolean;
|
|
34
|
+
fingerprint?: string | undefined;
|
|
35
|
+
}>;
|
|
36
|
+
}>;
|
|
37
|
+
export type AgentRuntimeEnvDiagnosticPayload = z.infer<typeof AgentRuntimeEnvDiagnosticPayloadSchema>;
|
|
38
|
+
export type AgentRuntimeEnvInspection = {
|
|
39
|
+
readonly status: "verified";
|
|
40
|
+
readonly toolName: DiagnosticToolName;
|
|
41
|
+
readonly payload: AgentRuntimeEnvDiagnosticPayload;
|
|
42
|
+
} | {
|
|
43
|
+
readonly status: "unverified";
|
|
44
|
+
readonly reason: "agent-not-running" | "connection-failed" | "diagnostic-tool-unavailable";
|
|
45
|
+
readonly message: string;
|
|
46
|
+
};
|
|
47
|
+
export type AgentRuntimeEnvVerification = {
|
|
48
|
+
readonly verified: false;
|
|
49
|
+
readonly reason: "agent-not-running" | "connection-failed" | "diagnostic-tool-unavailable";
|
|
50
|
+
readonly message: string;
|
|
51
|
+
} | {
|
|
52
|
+
readonly verified: true;
|
|
53
|
+
readonly present: false;
|
|
54
|
+
} | {
|
|
55
|
+
readonly verified: true;
|
|
56
|
+
readonly present: true;
|
|
57
|
+
readonly fingerprint?: string;
|
|
58
|
+
readonly matchesAgentsEnv: boolean;
|
|
59
|
+
};
|
|
60
|
+
export interface AgentRuntimeEnvCheckItem extends AgentEnvCheckItem {
|
|
61
|
+
readonly configuredInAgentsEnv: boolean;
|
|
62
|
+
readonly runtime: AgentRuntimeEnvVerification;
|
|
63
|
+
}
|
|
64
|
+
export interface AgentRuntimeEnvCheckReport {
|
|
65
|
+
readonly items: readonly AgentRuntimeEnvCheckItem[];
|
|
66
|
+
readonly inspection: AgentRuntimeEnvInspection;
|
|
67
|
+
readonly missingRequired: readonly AgentRuntimeEnvCheckItem[];
|
|
68
|
+
readonly ephemeralItems: readonly AgentRuntimeEnvCheckItem[];
|
|
69
|
+
}
|
|
70
|
+
export interface AgentRuntimeEnvSummary {
|
|
71
|
+
readonly status: "ok" | "warn" | "fail";
|
|
72
|
+
readonly message: string;
|
|
73
|
+
}
|
|
74
|
+
export declare function shouldSkipRuntimeReadinessForTool(toolName: string): boolean;
|
|
75
|
+
export declare function inspectAgentRuntimeEnvRequirements(report: AgentEnvCheckReport, configuredEnv: Readonly<Record<string, string>> | undefined, inspection: AgentRuntimeEnvInspection): AgentRuntimeEnvCheckReport;
|
|
76
|
+
export declare function summarizeAgentRuntimeEnvReport(report: AgentRuntimeEnvCheckReport): AgentRuntimeEnvSummary;
|
|
77
|
+
export declare function formatAgentEnvDeclarationSource(item: AgentEnvCheckItem): string;
|
|
78
|
+
export declare function formatAgentRuntimeVerification(report: AgentRuntimeEnvCheckReport): string;
|
|
79
|
+
export declare function formatAgentEnvRuntimeStatus(item: AgentRuntimeEnvCheckItem): string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash as e}from"node:crypto";import{z as n}from"zod";export const DIAGNOSTIC_TOOL_CANDIDATES=["diagnostic_status","browser_status"];const t=new Set(DIAGNOSTIC_TOOL_CANDIDATES),s=/^[0-9a-f]{8}$/;export const EffectiveEnvSourceSchema=n.object({present:n.boolean(),fingerprint:n.string().regex(s).optional()});export const AgentRuntimeEnvDiagnosticPayloadSchema=n.object({effectiveEnvSources:n.record(EffectiveEnvSourceSchema)});export function shouldSkipRuntimeReadinessForTool(e){return t.has(e)}export function inspectAgentRuntimeEnvRequirements(e,n,t){const s=e.items.map(e=>{const s=n?.[e.name],r=void 0!==s;if("unverified"===t.status)return{...e,configuredInAgentsEnv:r,runtime:{verified:!1,reason:t.reason,message:t.message}};const o=t.payload.effectiveEnvSources[e.name];return o?.present?{...e,configuredInAgentsEnv:r,runtime:{verified:!0,present:!0,...void 0!==o.fingerprint?{fingerprint:o.fingerprint}:{},matchesAgentsEnv:void 0!==s&&void 0!==o.fingerprint&&i(s)===o.fingerprint}}:{...e,configuredInAgentsEnv:r,runtime:{verified:!0,present:!1}}});return{items:s,inspection:t,missingRequired:s.filter(e=>e.required&&r(e)),ephemeralItems:s.filter(o)}}export function summarizeAgentRuntimeEnvReport(e){if(e.missingRequired.length>0){const n=u(e.missingRequired);return"verified"===e.inspection.status?{status:"fail",message:`运行态缺失: ${n}`}:{status:"fail",message:`${a(e)};${e.inspection.message}`}}if(e.ephemeralItems.length>0)return{status:"warn",message:`运行态漂移: ${u(e.ephemeralItems)}`};if("verified"===e.inspection.status)return{status:"ok",message:`声明的必填项已在运行态生效(${e.inspection.toolName})`};const n=e.items.filter(e=>e.required&&"process.env"===e.source);return n.length>0?{status:"warn",message:`依赖当前 shell 环境: ${u(n)};${e.inspection.message}`}:"diagnostic-tool-unavailable"===e.inspection.reason?{status:"ok",message:`声明的必填项已满足(${e.inspection.message})`}:{status:"warn",message:`声明的必填项已满足;${e.inspection.message}`}}export function formatAgentEnvDeclarationSource(e){switch(e.source){case"agents.env":return"已配置于 agents.env";case"process.env":return"仅当前 shell 环境";case"default":return`默认值 (${e.default})`;case"missing":return"缺失"}}export function formatAgentRuntimeVerification(e){return"verified"===e.inspection.status?`已验证(${e.inspection.toolName})`:`未校验(${e.inspection.message})`}export function formatAgentEnvRuntimeStatus(e){if(e.runtime.verified)return e.runtime.present?e.runtime.matchesAgentsEnv?"✓ from yaml (stable)":e.configuredInAgentsEnv?"⚠ differs from yaml (ephemeral)":"⚠ from shell (ephemeral)":"default"===e.source?"未设置(使用默认值)":"process.env"===e.source?"✗ 当前运行 agent 未看到该变量":"✗ missing"}function i(n){return e("sha256").update(n).digest("hex").slice(0,8)}function r(e){return e.runtime.verified?!e.runtime.present&&"default"!==e.source:"missing"===e.source}function o(e){return e.runtime.verified&&e.runtime.present&&!e.runtime.matchesAgentsEnv}function a(e){return`缺少必填项: ${u(e.missingRequired)}`}function u(e){return e.map(e=>e.name).join(", ")}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type AgentRuntimeEnvInspection } from "../config/runtime-env.ts";
|
|
2
|
+
import type { RegisteredAgent } from "../types/agent.ts";
|
|
3
|
+
import type { RollConfig } from "../config/schema.ts";
|
|
4
|
+
export declare function inspectAgentRuntimeEnv(agent: RegisteredAgent, options: {
|
|
5
|
+
readonly agentsConfig: RollConfig["agents"];
|
|
6
|
+
readonly timeoutMs?: number;
|
|
7
|
+
}): Promise<AgentRuntimeEnvInspection>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{getAgentEnvFromAgentsConfig as t}from"../config/helpers.js";import{AgentRuntimeEnvDiagnosticPayloadSchema as n,DIAGNOSTIC_TOOL_CANDIDATES as e}from"../config/runtime-env.js";import{resolveTransportWithDevSpawnSpec as o}from"../registry/dev-spawn.js";import{getAgentPid as r}from"../registry/process-manager.js";import{McpClientManager as i}from"./client-manager.js";export async function inspectAgentRuntimeEnv(a,c){if("core-managed"===a.runtime.ownership){if(void 0===r(c.agentsConfig.dataDir,a.skill.name))return{status:"unverified",reason:"agent-not-running",message:"agent 未运行(缺少活动 PID)"}}const f=new i;try{const r=o(a),i=t(c.agentsConfig,a.skill.name),l=await f.connect(a.skill.name,r,a.installPath,{...void 0!==c.timeoutMs?{timeoutMs:c.timeoutMs}:{},...i?{env:i}:{}}),{tools:m}=await l.listTools(),u=e.find(t=>m.some(n=>n.name===t));if(!u)return{status:"unverified",reason:"diagnostic-tool-unavailable",message:"agent 未暴露 diagnostic_status / browser_status.effectiveEnvSources"};const g=await l.callTool({name:u,arguments:{}});return{status:"verified",toolName:u,payload:n.parse(s(g))}}catch(t){return{status:"unverified",reason:"connection-failed",message:`无法校验运行态: ${t instanceof Error?t.message:String(t)}`}}finally{await f.disconnectAll()}}function s(t){const n=a(t,"诊断 tool 未返回 text content");try{return JSON.parse(n)}catch(t){throw new Error(`诊断 tool 返回了不可解析的 JSON: ${t instanceof Error?t.message:String(t)}`)}}function a(t,n){const e=c(t);for(const t of e)if("object"==typeof t&&null!==t&&"type"in t&&"text"===t.type&&"text"in t&&"string"==typeof t.text)return t.text;throw new Error(n)}function c(t){if("object"!=typeof t||null===t||!("content"in t))throw new Error("诊断 tool 未返回 MCP content 数组");const n=t.content;if(!Array.isArray(n))throw new Error("诊断 tool 返回的 content 不是数组");return n}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { AskValidationIssue } from "../types/ask.ts";
|
|
2
|
-
export declare function formatValidationIssuesMessage(agentName: string, toolName: string, validationIssues: ReadonlyArray<AskValidationIssue>): string;
|
|
1
|
+
import type { AskRuntimeIssue, AskValidationIssue } from "../types/ask.ts";
|
|
2
|
+
export declare function formatValidationIssuesMessage(agentName: string, toolName: string, validationIssues: ReadonlyArray<AskValidationIssue>, runtimeIssues?: ReadonlyArray<AskRuntimeIssue>): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function n(n,e){return e?`${n}(${e})`:n}export function formatValidationIssuesMessage(e,s,o,t=[]){const i=[`已路由到 ${e}.${s}`];if(o.length>0){const t=o.map(o=>"requires_explicit_input"===o.code?"- "+n(`${o.message};请使用 \`roll run ${e} ${s} --input-json\` 或上游编排器显式提供`,o.description):`- ${n(o.message,o.description)}`);i.push(["A. 输入缺失 / 参数校验",...t].join("\n"))}if(t.length>0){const s=t.map(s=>{const o=`请在 \`roll.config.yaml\` 的 \`agents.env.${e}\` 中配置,或在当前 shell 环境导出后重试`;return`- ${n(`${s.message};${o}`,s.purpose)}`});i.push(["B. 运行条件缺失",...s].join("\n"))}return i.join("\n")}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import type { AgentTool } from "../types/agent.ts";
|
|
2
|
-
import type { AskValidationIssue } from "../types/ask.ts";
|
|
2
|
+
import type { AskRuntimeIssue, AskValidationIssue } from "../types/ask.ts";
|
|
3
3
|
export interface ToolCallPreflightSuccess {
|
|
4
4
|
readonly ok: true;
|
|
5
5
|
}
|
|
6
6
|
export interface ToolCallPreflightFailure {
|
|
7
7
|
readonly ok: false;
|
|
8
8
|
readonly issues: ReadonlyArray<AskValidationIssue>;
|
|
9
|
+
readonly runtimeIssues: ReadonlyArray<AskRuntimeIssue>;
|
|
9
10
|
}
|
|
10
11
|
export type ToolCallPreflightResult = ToolCallPreflightSuccess | ToolCallPreflightFailure;
|
|
12
|
+
export interface ToolCallPreflightOptions {
|
|
13
|
+
readonly runtimeIssues?: ReadonlyArray<AskRuntimeIssue>;
|
|
14
|
+
}
|
|
11
15
|
export declare function getInputValidationIssues(tool: Pick<AgentTool, "inputSchema">, input: Readonly<Record<string, unknown>>): ReadonlyArray<AskValidationIssue>;
|
|
12
|
-
export declare function preflightToolCall(tool: Pick<AgentTool, "inputSchema">, input: Readonly<Record<string, unknown
|
|
16
|
+
export declare function preflightToolCall(tool: Pick<AgentTool, "inputSchema">, input: Readonly<Record<string, unknown>>, options?: ToolCallPreflightOptions): ToolCallPreflightResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{describeValueType as e,getAdditionalPropertiesSetting as t,getSchemaDescription as n,getSchemaEnum as r,getSchemaItems as s,getSchemaProperties as i,getSchemaRequired as
|
|
1
|
+
import{describeValueType as e,getAdditionalPropertiesSetting as t,getSchemaDescription as n,getSchemaEnum as r,getSchemaItems as s,getSchemaProperties as i,getSchemaRequired as u,getSchemaType as o,isNaturallyExtractableSchema as c,isJsonSchemaObject as a,isPlainObject as p}from"./schema.js";function f(e,t){const r=n(t),s=t&&!c(t);return{path:e,code:s?"requires_explicit_input":"missing_required",message:s?`${e} 无法从自然语言可靠提取,需要显式提供`:`${e} 为必填字段`,...r?{description:r}:{}}}function l(e,t){if(t&&a(t)){const n=g({inputSchema:t},{},e);if(n.length>0)return n}return[f(e,t)]}function m(t,i,u){const c=[],f=n(t),l=r(t),h=o(t);if(l&&!l.some(e=>Object.is(e,i)))return c.push({path:u,code:"invalid_enum",message:`${u} 必须是以下值之一:${l.map(e=>JSON.stringify(e)).join("、")}`,...f?{description:f}:{},expected:l.map(e=>JSON.stringify(e)).join(" | "),actual:JSON.stringify(i)}),c;if(!h)return c;const d=e(i),$=()=>{c.push({path:u,code:"invalid_type",message:`${u} 应为 ${h},当前是 ${d}`,...f?{description:f}:{},expected:h,actual:d})};switch(h){case"string":return"string"!=typeof i&&$(),c;case"number":return("number"!=typeof i||Number.isNaN(i))&&$(),c;case"integer":return"number"==typeof i&&Number.isInteger(i)||$(),c;case"boolean":return"boolean"!=typeof i&&$(),c;case"null":return null!==i&&$(),c;case"array":if(!Array.isArray(i))return $(),c;{const e=s(t);return e?i.flatMap((t,n)=>m(e,t,`${u}[${String(n)}]`)):c}case"object":return p(i)?a(t)?g({inputSchema:t},i,u):c:($(),c);default:return c}}function g(e,n,r=""){const s=u(e),o=i(e.inputSchema),c=[];for(const e of s){const t=n[e];if(null!=t)continue;const s=o[e],i=r?`${r}.${e}`:e;c.push(...l(i,s))}for(const[s,i]of Object.entries(n)){const n=r?`${r}.${s}`:s,u=o[s];u?c.push(...m(u,i,n)):!1===t(e.inputSchema)&&c.push({path:n,code:"unexpected_property",message:`${n} 不是允许的参数`})}return c}export function getInputValidationIssues(e,t){return g(e,t)}export function preflightToolCall(e,t,n={}){const r=getInputValidationIssues(e,t),s=n.runtimeIssues??[];return 0===r.length&&0===s.length?{ok:!0}:{ok:!1,issues:r,runtimeIssues:s}}
|
package/dist/types/ask.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ export declare const ASK_FAILURE_STAGES: readonly ["route", "connect", "execute"
|
|
|
5
5
|
export type AskFailureStage = (typeof ASK_FAILURE_STAGES)[number];
|
|
6
6
|
export declare const ASK_VALIDATION_ISSUE_CODES: readonly ["missing_required", "requires_explicit_input", "invalid_type", "invalid_enum", "unexpected_property"];
|
|
7
7
|
export type AskValidationIssueCode = (typeof ASK_VALIDATION_ISSUE_CODES)[number];
|
|
8
|
+
export declare const ASK_RUNTIME_ISSUE_CATEGORIES: readonly ["env"];
|
|
9
|
+
export type AskRuntimeIssueCategory = (typeof ASK_RUNTIME_ISSUE_CATEGORIES)[number];
|
|
10
|
+
export declare const ASK_RUNTIME_ISSUE_CODES: readonly ["missing_required_env"];
|
|
11
|
+
export type AskRuntimeIssueCode = (typeof ASK_RUNTIME_ISSUE_CODES)[number];
|
|
8
12
|
export interface AskValidationIssue {
|
|
9
13
|
readonly path: string;
|
|
10
14
|
readonly code: AskValidationIssueCode;
|
|
@@ -13,10 +17,19 @@ export interface AskValidationIssue {
|
|
|
13
17
|
readonly expected?: string;
|
|
14
18
|
readonly actual?: string;
|
|
15
19
|
}
|
|
20
|
+
export interface AskRuntimeIssue {
|
|
21
|
+
readonly category: AskRuntimeIssueCategory;
|
|
22
|
+
readonly code: AskRuntimeIssueCode;
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly message: string;
|
|
25
|
+
readonly purpose?: string;
|
|
26
|
+
readonly example?: string;
|
|
27
|
+
}
|
|
16
28
|
export interface AskNeedsInputResult {
|
|
17
29
|
readonly status: "needs_input";
|
|
18
30
|
readonly decision: RouteDecision;
|
|
19
31
|
readonly validationIssues: ReadonlyArray<AskValidationIssue>;
|
|
32
|
+
readonly runtimeIssues: ReadonlyArray<AskRuntimeIssue>;
|
|
20
33
|
readonly message: string;
|
|
21
34
|
}
|
|
22
35
|
export interface AskNeedsConfirmationResult {
|
package/dist/types/ask.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const ASK_RESULT_STATUSES=["success","needs_input","needs_confirmation","failed"];export const ASK_FAILURE_STAGES=["route","connect","execute"];export const ASK_VALIDATION_ISSUE_CODES=["missing_required","requires_explicit_input","invalid_type","invalid_enum","unexpected_property"];
|
|
1
|
+
export const ASK_RESULT_STATUSES=["success","needs_input","needs_confirmation","failed"];export const ASK_FAILURE_STAGES=["route","connect","execute"];export const ASK_VALIDATION_ISSUE_CODES=["missing_required","requires_explicit_input","invalid_type","invalid_enum","unexpected_property"];export const ASK_RUNTIME_ISSUE_CATEGORIES=["env"];export const ASK_RUNTIME_ISSUE_CODES=["missing_required_env"];
|