@roll-agent/core 0.10.1 → 0.12.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/bin/roll.js +56 -1
- package/dist/cli/chat/ink/app.d.ts +15 -0
- package/dist/cli/chat/ink/app.js +1 -0
- package/dist/cli/chat/ink/commands.d.ts +6 -0
- package/dist/cli/chat/ink/commands.js +1 -0
- package/dist/cli/chat/ink/confirm-select.d.ts +6 -0
- package/dist/cli/chat/ink/confirm-select.js +1 -0
- package/dist/cli/chat/ink/history-from-messages.d.ts +3 -0
- package/dist/cli/chat/ink/history-from-messages.js +1 -0
- package/dist/cli/chat/ink/history-item.d.ts +5 -0
- package/dist/cli/chat/ink/history-item.js +1 -0
- package/dist/cli/chat/ink/live-region.d.ts +5 -0
- package/dist/cli/chat/ink/live-region.js +1 -0
- package/dist/cli/chat/ink/markdown.d.ts +4 -0
- package/dist/cli/chat/ink/markdown.js +1 -0
- package/dist/cli/chat/ink/run-ink-repl.d.ts +13 -0
- package/dist/cli/chat/ink/run-ink-repl.js +1 -0
- package/dist/cli/chat/ink/slash-popup.d.ts +7 -0
- package/dist/cli/chat/ink/slash-popup.js +1 -0
- package/dist/cli/chat/ink/spinner.d.ts +2 -0
- package/dist/cli/chat/ink/spinner.js +1 -0
- package/dist/cli/chat/ink/state.d.ts +95 -0
- package/dist/cli/chat/ink/state.js +1 -0
- package/dist/cli/chat/ink/status-line.d.ts +5 -0
- package/dist/cli/chat/ink/status-line.js +1 -0
- package/dist/cli/chat/ink/text-prompt.d.ts +12 -0
- package/dist/cli/chat/ink/text-prompt.js +1 -0
- package/dist/cli/chat/ink/thinking-text.d.ts +9 -0
- package/dist/cli/chat/ink/thinking-text.js +1 -0
- package/dist/cli/chat/ink/thinking.d.ts +3 -0
- package/dist/cli/chat/ink/thinking.js +1 -0
- package/dist/cli/chat/ink/tool-label.d.ts +4 -0
- package/dist/cli/chat/ink/tool-label.js +1 -0
- package/dist/cli/chat/ink/use-session.d.ts +20 -0
- package/dist/cli/chat/ink/use-session.js +1 -0
- package/dist/cli/chat/title.d.ts +1 -0
- package/dist/cli/chat/title.js +1 -0
- package/dist/cli/commands/browser-stop.d.ts +4 -4
- package/dist/cli/commands/chat.d.ts +27 -0
- package/dist/cli/commands/chat.js +1 -1
- package/dist/cli/commands/config-guidance.d.ts +12 -0
- package/dist/cli/commands/config-guidance.js +1 -1
- package/dist/cli/utils/chat-renderer.d.ts +21 -0
- package/dist/cli/utils/chat-renderer.js +1 -0
- package/dist/cli/utils/output.d.ts +1 -0
- package/dist/cli/utils/output.js +1 -1
- package/dist/cli/utils/package-manager.d.ts +5 -0
- package/dist/cli/utils/package-manager.js +1 -1
- package/dist/cli/utils/token-format.d.ts +18 -0
- package/dist/cli/utils/token-format.js +1 -0
- package/dist/cli/utils/tool-format.d.ts +1 -0
- package/dist/cli/utils/tool-format.js +1 -0
- package/dist/config/defaults.js +1 -1
- package/dist/config/key-codec.js +1 -1
- package/dist/config/loader.js +1 -1
- package/dist/config/runtime-env.d.ts +16 -16
- package/dist/config/schema.d.ts +246 -22
- package/dist/config/schema.js +1 -1
- package/dist/llm/providers.d.ts +5 -2
- package/dist/llm/providers.js +1 -1
- package/dist/mcp/client-manager.d.ts +2 -0
- package/dist/mcp/client-manager.js +1 -1
- package/dist/types/chat.d.ts +23 -0
- package/package.json +40 -6
|
@@ -76,4 +76,9 @@ export declare function formatPackageManagerCommand(spec: PackageManagerRunSpec)
|
|
|
76
76
|
export declare function isLikelyNetworkError(error: unknown): boolean;
|
|
77
77
|
/** 网络/超时类错误才值得对整条命令重试。 */
|
|
78
78
|
export declare function isRetryablePackageManagerError(error: unknown): boolean;
|
|
79
|
+
/**
|
|
80
|
+
* npm 新 package / 新 scoped package 发布后,registry edge 有时会短暂返回 package
|
|
81
|
+
* metadata 404。只对 @roll-agent scope 放行重试,避免把普通包名写错也当成网络问题。
|
|
82
|
+
*/
|
|
83
|
+
export declare function isLikelyRollAgentRegistryPropagationError(error: unknown): boolean;
|
|
79
84
|
export declare function formatPackageManagerError(spec: PackageManagerRunSpec, error: unknown, platform?: NodeJS.Platform): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execFile as
|
|
1
|
+
import{execFile as r}from"node:child_process";import{existsSync as e,readFileSync as n}from"node:fs";import{resolve as t}from"node:path";import{promisify as o}from"node:util";const i=o(r),a=67108864;export const PACKAGE_MANAGER_COMMANDS=["bun","npm","pnpm","yarn"];export function detectInstallCommand(r){const n=t(r,"package.json");if(e(n)){const r=m(n);if(r)return{command:r,args:["install"]}}const o=[["pnpm-lock.yaml","pnpm"],["package-lock.json","npm"],["npm-shrinkwrap.json","npm"],["yarn.lock","yarn"],["bun.lock","bun"],["bun.lockb","bun"]];for(const[n,i]of o)if(e(t(r,n)))return{command:i,args:["install"]}}export function createInstallCommand(r="pnpm"){return{command:r,args:["install"]}}export async function runPackageManager(r,e={}){const{platform:n,...t}=e,o=createPackageManagerExecInvocation(r,n??process.platform),s=await i(o.file,[...o.args],{maxBuffer:a,...t,encoding:"utf-8",...o.shell?{shell:o.shell}:{}});return{stdout:s.stdout,stderr:s.stderr}}function s(r){return new Promise(e=>setTimeout(e,r))}export async function runPackageManagerWithRetry(r,e={},n){const t=Math.max(1,n.attempts),o=n.isRetryable??isRetryablePackageManagerError;let i;for(let a=1;a<=t;a+=1)try{return await runPackageManager(r,e)}catch(r){i=r;if(!(a<t)||!o(r))throw r;const e=n.backoffMs??[],c=e[a-1]??e[e.length-1]??2e3;n.onRetry?.({attempt:a,error:r,delayMs:c}),await s(c)}throw i}export function buildNpmRetryPolicy(r){const e=Math.min(Math.max(r,0)+1,3);return{attempts:e,backoffMs:[2e3,5e3].slice(0,Math.max(e-1,0)),isRetryable:isRetryablePackageManagerError}}export function createPackageManagerExecInvocation(r,e=process.platform){return shouldRunPackageManagerViaShell(e)?{file:c(),args:["/d","/s","/c",E(r)],shell:!1}:{file:r.command,args:r.args,shell:!1}}export function shouldRunPackageManagerViaShell(r){return"win32"===r}function c(){const r=process.env.ComSpec??process.env.COMSPEC;return r&&r.trim().length>0?r:"cmd.exe"}export function npmInstallNetworkArgs(r={}){const e=["--no-audit","--no-fund"];return r.registry&&e.push(`--registry=${r.registry}`),void 0!==r.fetchRetries&&e.push(`--fetch-retries=${String(r.fetchRetries)}`),r.preferOffline&&e.push("--prefer-offline"),e}export function npmViewNetworkArgs(r={}){const e=[];return r.registry&&e.push(`--registry=${r.registry}`),void 0!==r.fetchRetries&&e.push(`--fetch-retries=${String(r.fetchRetries)}`),e}export function formatPackageManagerCommand(r){return[r.command,...r.args].map(d).join(" ")}const u="疑似网络或 npm 源不稳定。可在 roll.config.yaml 配置 `install.registry` 指向可用镜像(如 https://registry.npmmirror.com),或检查 VPN / 代理后重试。",l=new Set(["ETIMEDOUT","ECONNRESET","ECONNREFUSED","ENOTFOUND","EAI_AGAIN","ENETUNREACH","EHOSTUNREACH","EPIPE","ERR_SOCKET_TIMEOUT","UND_ERR_CONNECT_TIMEOUT","UND_ERR_HEADERS_TIMEOUT"]),f=[/\bnetwork\b/i,/ETIMEDOUT/i,/ECONNRESET/i,/ECONNREFUSED/i,/ENOTFOUND/i,/EAI_AGAIN/i,/socket hang up/i,/fetch failed/i,/getaddrinfo/i,/tunneling socket could not be established/i,/request to .+ failed/i,/npm\s+(?:error|ERR!)\s+code\s+E429/i,/\bregistry\b.*\b(timeout|timed out|unreachable)\b/i,/\bproxy\b/i];function g(r){if("object"!=typeof r||null===r)return!1;const e="killed"in r&&!0===r.killed,n="signal"in r&&"SIGTERM"===r.signal,t=!("code"in r)||null===r.code||void 0===r.code;return e&&n&&t}export function isLikelyNetworkError(r){const e=R(r);if(e&&l.has(e))return!0;const n=N(r);return f.some(r=>r.test(n))}export function isRetryablePackageManagerError(r){return g(r)||isLikelyNetworkError(r)||isLikelyRollAgentRegistryPropagationError(r)}export function isLikelyRollAgentRegistryPropagationError(r){const e=N(r);return/\bnpm\s+(?:error|ERR!)\s+code\s+E404\b/i.test(e)&&/(?:@roll-agent%2f|@roll-agent\/)[a-z0-9._-]+/i.test(e)&&/(?:Not Found - GET|is not in this registry)/i.test(e)}export function formatPackageManagerError(r,e,n=process.platform){const t=formatPackageManagerCommand(r);if(k(r.command,e,n))return[`未找到 ${r.command},无法执行 \`${t}\`。`,"win32"===n?`请确认 ${r.command}.cmd 位于 PATH 中;npm 全局目录通常是 C:\\Users\\<you>\\AppData\\Roaming\\npm。`:`请确认已安装 ${r.command},并且当前 shell 的 PATH 可以访问它。`].join("");if(g(e))return`\`${t}\` 执行超时被终止。${u}`;if(isLikelyNetworkError(e)){return`\`${t}\` 执行失败:${e instanceof Error?e.message:String(e)}\n${u}`}return e instanceof Error?e.message:String(e)}function m(r){try{const e=JSON.parse(n(r,"utf-8"));if("string"!=typeof e.packageManager||0===e.packageManager.length)return;const[t]=e.packageManager.split("@",1);if(!t)return;return p(t)?t:void 0}catch{return}}function p(r){return PACKAGE_MANAGER_COMMANDS.some(e=>e===r)}function d(r){return/\s/.test(r)?JSON.stringify(r):r}function E(r){return[r.command,...r.args].map(h).join(" ")}function h(r){if(0===r.length)return'""';if(/["\r\n]/.test(r))throw new Error(`Unsupported Windows shell argument: ${r}`);return/[\s"&|<>^()%!]/.test(r)?`"${y(r)}"`:r}function y(r){return r.replace(/[\^&|<>%!]/g,r=>`^${r}`)}function k(r,e,n){if("ENOENT"===R(e))return!0;if("win32"!==n)return!1;const t=N(e).toLowerCase();return t.includes(`'${r}' is not recognized`)||t.includes(`"${r}" is not recognized`)||t.includes(`${r} is not recognized`)||t.includes(`'${r}' 不是内部或外部命令`)||t.includes(`"${r}" 不是内部或外部命令`)||t.includes(`${r} 不是内部或外部命令`)}function R(r){if("object"==typeof r&&null!==r&&"code"in r)return"string"==typeof r.code?r.code:void 0}function N(r){return r instanceof Error?r.message:String(r)}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { SessionTokenUsage } from "@roll-agent/runtime";
|
|
2
|
+
export interface UsageLineParts {
|
|
3
|
+
readonly inputTokens?: number;
|
|
4
|
+
readonly outputTokens?: number;
|
|
5
|
+
readonly sessionTokens?: number;
|
|
6
|
+
readonly cachedInputTokens?: number;
|
|
7
|
+
readonly reasoningTokens?: number;
|
|
8
|
+
readonly percentLeft?: number;
|
|
9
|
+
readonly usedTokens?: number;
|
|
10
|
+
readonly contextWindow?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface UsagePartsOptions {
|
|
13
|
+
readonly baselineHeadroom?: number;
|
|
14
|
+
}
|
|
15
|
+
export declare function formatTokens(value: number): string;
|
|
16
|
+
export declare function sessionTotal(usage: SessionTokenUsage): number;
|
|
17
|
+
export declare function computeUsageParts(turn: SessionTokenUsage | undefined, session: SessionTokenUsage | undefined, contextWindow: number | undefined, contextInputTokens: number | undefined, options?: UsagePartsOptions): UsageLineParts;
|
|
18
|
+
export declare function formatUsageLine(parts: UsageLineParts): string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const o=12e3,n=.2;export function formatTokens(o){return o>=1e3?`${(o/1e3).toFixed(1)}k`:String(o)}export function sessionTotal(o){return void 0!==o.totalTokens&&o.totalTokens>0?o.totalTokens:(o.inputTokens??0)+(o.outputTokens??0)}function e(o,e,t){const s=Math.min(t,Math.floor(e*n)),i=Math.max(e-s,1),u=Math.max(o-s,0),a=Math.max(i-u,0);return Math.min(Math.max(Math.round(a/i*100),0),100)}export function computeUsageParts(n,t,s,i,u){const a=i??n?.inputTokens,T=u?.baselineHeadroom??o,k=n?.cachedInputTokens,r=n?.reasoningTokens;return{...void 0!==n?.inputTokens?{inputTokens:n.inputTokens}:{},...void 0!==n?.outputTokens?{outputTokens:n.outputTokens}:{},...t?{sessionTokens:sessionTotal(t)}:{},...void 0!==k&&k>0?{cachedInputTokens:k}:{},...void 0!==r&&r>0?{reasoningTokens:r}:{},...void 0!==s&&void 0!==a?{percentLeft:e(a,s,T),usedTokens:a,contextWindow:s}:{}}}export function formatUsageLine(o){const n=[];if(void 0!==o.inputTokens){const e=void 0!==o.cachedInputTokens?` (+${formatTokens(o.cachedInputTokens)} cached)`:"";n.push(`in ${formatTokens(o.inputTokens)}${e}`)}if(void 0!==o.outputTokens){const e=void 0!==o.reasoningTokens?` (+${formatTokens(o.reasoningTokens)} reasoning)`:"";n.push(`out ${formatTokens(o.outputTokens)}${e}`)}return void 0!==o.sessionTokens&&n.push(`session ${formatTokens(o.sessionTokens)}`),void 0!==o.percentLeft&&void 0!==o.usedTokens&&void 0!==o.contextWindow&&n.push(`${String(o.percentLeft)}% left (${formatTokens(o.usedTokens)}/${formatTokens(o.contextWindow)})`),n.length>0?`↳ ${n.join(" · ")}`:void 0}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function formatToolInput(input: unknown): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{redactToolArgsForLog as t}from"./output.js";export function formatToolInput(o){const n=JSON.stringify(t(o))??"";return n.length>80?`${n.slice(0,79)}…`:n}
|
package/dist/config/defaults.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const LLM_PROVIDER_OPTIONS=["anthropic","openai","qwen","deepseek"];export const DEFAULT_LLM_PROVIDER="anthropic";export const DEFAULT_LLM_MODELS={anthropic:"claude-sonnet-4-6",openai:"gpt-5.5",qwen:"qwen3.6-plus",deepseek:"deepseek-v4-flash"};export const DEFAULT_CONFIG={llm:{defaultProvider:"anthropic",defaultModel:DEFAULT_LLM_MODELS.anthropic,providers:{}},ask:{},agents:{dataDir:"~/.roll-agent/agents"},install:{fetchRetries:3,preferOffline:!1,networkTimeoutMs:12e4},browser:{instances:{}}};export const CONFIG_FILE_NAMES=["roll.config.yaml","roll.config.yml"];
|
|
1
|
+
export const LLM_PROVIDER_OPTIONS=["anthropic","openai","qwen","deepseek"];export const DEFAULT_LLM_PROVIDER="anthropic";export const DEFAULT_LLM_MODELS={anthropic:"claude-sonnet-4-6",openai:"gpt-5.5",qwen:"qwen3.6-plus",deepseek:"deepseek-v4-flash"};export const DEFAULT_CONFIG={llm:{defaultProvider:"anthropic",defaultModel:DEFAULT_LLM_MODELS.anthropic,providers:{}},ask:{},runtime:{maxSteps:80,turnTimeoutMs:3e5,threadsDir:"~/.roll-agent/threads",thinkingLevel:"medium",approval:{default:"guarded",overrides:{}},compaction:{enabled:!0,strategy:"summarize",threshold:.75,keepRecentTurns:4,keepRecentTokens:32e3}},agents:{dataDir:"~/.roll-agent/agents"},install:{fetchRetries:3,preferOffline:!1,networkTimeoutMs:12e4},browser:{instances:{}}};export const CONFIG_FILE_NAMES=["roll.config.yaml","roll.config.yml"];
|
package/dist/config/key-codec.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const e={kind:"leaf"},r={kind:"object",fields:{apiKey:e,baseUrl:e}},o={kind:"object",fields:{platform:e,mode:e,headless:e,cdpUrl:e,cdpHost:e,cdpPort:e,channel:e,executablePath:e,userDataDir:e,sessionsDir:e,args:e,profileName:e,profileColor:e,windowBounds:{kind:"object",fields:{x:e,y:e,width:e,height:e}},trackingAgentId: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}}}},install:{kind:"object",fields:{registry:e,fetchRetries:e,preferOffline:e,networkTimeoutMs:e}},browser:{kind:"object",fields:{defaultInstance:e,instances:{kind:"record",value:o}}}}};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 t(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}export function decodeFromYaml(r,o=CONFIG_KEY_CODEC){if(Array.isArray(r))return r.map(e=>decodeFromYaml(e,o));if(!t(r))return r;if("object"===o.kind){const t={};for(const[n,i]of Object.entries(r)){const r=kebabToCamel(n),d=o.fields[r]??e;t[r]=decodeFromYaml(i,d)}return t}if("record"===o.kind){const e={};for(const[t,n]of Object.entries(r))e[t]=decodeFromYaml(n,o.value);return e}return r}function n(r,o){const t=[];let n=CONFIG_KEY_CODEC;for(const i of r)if("object"===n.kind){const r=kebabToCamel(i),d=n.fields[r];d?(t.push("camel"===o?r:camelToKebab(r)),n=d):(t.push(i),n=e)}else"record"===n.kind?(t.push(i),n=n.value):t.push(i);return t}export function encodePathToYaml(e){return n(e,"kebab")}export function normalizeUserPath(e){return n(e,"camel")}
|
|
1
|
+
const e={kind:"leaf"},r={kind:"object",fields:{apiKey:e,baseUrl:e}},o={kind:"object",fields:{platform:e,mode:e,headless:e,cdpUrl:e,cdpHost:e,cdpPort:e,channel:e,executablePath:e,userDataDir:e,sessionsDir:e,args:e,profileName:e,profileColor:e,windowBounds:{kind:"object",fields:{x:e,y:e,width:e,height:e}},trackingAgentId: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}},runtime:{kind:"object",fields:{provider:e,model:e,maxSteps:e,turnTimeoutMs:e,threadsDir:e,contextWindow:e,thinkingLevel:e,approval:{kind:"object",fields:{default:e,overrides:{kind:"record",value:e}}},compaction:{kind:"object",fields:{enabled:e,strategy:e,threshold:e,keepRecentTurns:e,keepRecentTokens:e}}}},agents:{kind:"object",fields:{dataDir:e,env:{kind:"record",value:{kind:"record",value:e}}}},install:{kind:"object",fields:{registry:e,fetchRetries:e,preferOffline:e,networkTimeoutMs:e}},browser:{kind:"object",fields:{defaultInstance:e,instances:{kind:"record",value:o}}}}};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 t(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}export function decodeFromYaml(r,o=CONFIG_KEY_CODEC){if(Array.isArray(r))return r.map(e=>decodeFromYaml(e,o));if(!t(r))return r;if("object"===o.kind){const t={};for(const[n,i]of Object.entries(r)){const r=kebabToCamel(n),d=o.fields[r]??e;t[r]=decodeFromYaml(i,d)}return t}if("record"===o.kind){const e={};for(const[t,n]of Object.entries(r))e[t]=decodeFromYaml(n,o.value);return e}return r}function n(r,o){const t=[];let n=CONFIG_KEY_CODEC;for(const i of r)if("object"===n.kind){const r=kebabToCamel(i),d=n.fields[r];d?(t.push("camel"===o?r:camelToKebab(r)),n=d):(t.push(i),n=e)}else"record"===n.kind?(t.push(i),n=n.value):t.push(i);return t}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,installConfigSchema as i,rollConfigSchema as s}from"./schema.js";import{DEFAULT_CONFIG as a,CONFIG_FILE_NAMES as f}from"./defaults.js";import{decodeFromYaml as c}from"./key-codec.js";import{detectKnownConfigMigrations as u,formatConfigMigrationError as l}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(d(n)){const r={};for(const[t,o]of Object.entries(n))r[t]=g(o);return r}return n}function d(n){return"object"==typeof n&&null!==n&&!Array.isArray(n)}function p(n){return d(n)&&"number"==typeof n.line&&"number"==typeof n.col}function h(n){return n instanceof Error&&"linePos"in n&&Array.isArray(n.linePos)&&n.linePos.length>0&&n.linePos.every(p)}function m(n,r){const t=`Invalid YAML syntax in config file: ${n}`;if(!(r instanceof Error))return`${t}\n${String(r)}`;if(h(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 w(n){let o=t(n);const e=t("/");for(;o!==e;){for(const n of f){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 $(n){return{...n,agents:{...n.agents,dataDir:v(n.agents.dataDir)},browser:{...n.browser,instances:Object.fromEntries(Object.entries(n.browser.instances).map(([n,r])=>[n,{...r,userDataDir:v(r.userDataDir),...void 0!==r.sessionsDir?{sessionsDir:v(r.sessionsDir)}:{}}]))}}}const C={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(m(r,n),{cause:n instanceof Error?n:void 0})}if(!d(t))throw new Error(`Invalid config file: ${r} (expected YAML object)`);return t}function P(n,r,t={}){const o=parseConfigDocument(n,r),e=u(o,t);if(e.needsMigration)throw new Error(l(r,e));return o}export function validateConfigText(n,r){const t=P(n,r),o=g(c(t));if(!d(o))throw new Error(`Invalid config file: ${r} (expected YAML object)`);const e=j(a,o),i=s.safeParse(e);if(!i.success){const n=i.error.issues.map(n=>` - ${n.path.join(".")}: ${n.message}`).join("\n");throw new Error(`Config validation failed (${r}):\n${n}`)}return $(i.data)}function E(n,r){const t=P(n,r,{scope:"agents"}),o=g(c(t));if(!d(o))throw new Error(`Invalid config file: ${r} (expected YAML object)`);const i=d(o.agents)?o.agents:{},s=j(a.agents,i),f=e.safeParse(s);if(!f.success){const n=f.error.issues.map(n=>` - agents.${n.path.join(".")}: ${n.message}`).join("\n");throw new Error(`Config validation failed (${r}):\n${n}`)}return{...f.data,dataDir:v(f.data.dataDir)}}function y(n,r){const t=parseConfigDocument(n,r),o=g(c(t));if(!d(o))throw new Error(`Invalid config file: ${r} (expected YAML object)`);const e=d(o.install)?o.install:{},s=j(a.install,e),f=i.safeParse(s);if(!f.success){const n=f.error.issues.map(n=>` - install.${n.path.join(".")}: ${n.message}`).join("\n");throw new Error(`Config validation failed (${r}):\n${n}`)}return f.data}export function loadInstallConfig(t={}){const o=resolveConfigPath(t);if(!o)return{installConfig:a.install,configPath:void 0};if(!r(o))throw new Error(`Config file not found: ${o}`);return{installConfig:y(n(o,"utf-8"),o),configPath:o}}export function loadConfig(t={}){const o=resolveConfigPath(t);if(!o)return{config:$(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:E(n(o,"utf-8"),o),configPath:o}}export function resolveConfigPath(n={}){const{configPath:r,cwd:t=process.cwd()}=n;return r??w(t)}export function inspectConfigFile(t={}){const o=resolveConfigPath(t);if(!o)return{status:C.notFound,configPath:void 0};if(!r(o))return{status:C.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:C.invalid,configPath:o,raw:e,error:n instanceof Error?n:new Error(String(n))}}const s=u(i);if(s.needsMigration)return{status:C.needsMigration,configPath:o,raw:e,report:s};try{return{status:C.valid,configPath:o,config:validateConfigText(e,o)}}catch(n){return{status:C.invalid,configPath:o,raw:e,error:n instanceof Error?n:new Error(String(n))}}}function j(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]=j(r,e)}return t}
|
|
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,installConfigSchema as i,rollConfigSchema as s}from"./schema.js";import{DEFAULT_CONFIG as a,CONFIG_FILE_NAMES as f}from"./defaults.js";import{decodeFromYaml as c}from"./key-codec.js";import{detectKnownConfigMigrations as u,formatConfigMigrationError as l}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(d(n)){const r={};for(const[t,o]of Object.entries(n))r[t]=g(o);return r}return n}function d(n){return"object"==typeof n&&null!==n&&!Array.isArray(n)}function p(n){return d(n)&&"number"==typeof n.line&&"number"==typeof n.col}function h(n){return n instanceof Error&&"linePos"in n&&Array.isArray(n.linePos)&&n.linePos.length>0&&n.linePos.every(p)}function m(n,r){const t=`Invalid YAML syntax in config file: ${n}`;if(!(r instanceof Error))return`${t}\n${String(r)}`;if(h(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 w(n){let o=t(n);const e=t("/");for(;o!==e;){for(const n of f){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 $(n){return{...n,agents:{...n.agents,dataDir:v(n.agents.dataDir)},runtime:{...n.runtime,threadsDir:v(n.runtime.threadsDir)},browser:{...n.browser,instances:Object.fromEntries(Object.entries(n.browser.instances).map(([n,r])=>[n,{...r,userDataDir:v(r.userDataDir),...void 0!==r.sessionsDir?{sessionsDir:v(r.sessionsDir)}:{}}]))}}}const C={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(m(r,n),{cause:n instanceof Error?n:void 0})}if(!d(t))throw new Error(`Invalid config file: ${r} (expected YAML object)`);return t}function P(n,r,t={}){const o=parseConfigDocument(n,r),e=u(o,t);if(e.needsMigration)throw new Error(l(r,e));return o}export function validateConfigText(n,r){const t=P(n,r),o=g(c(t));if(!d(o))throw new Error(`Invalid config file: ${r} (expected YAML object)`);const e=j(a,o),i=s.safeParse(e);if(!i.success){const n=i.error.issues.map(n=>` - ${n.path.join(".")}: ${n.message}`).join("\n");throw new Error(`Config validation failed (${r}):\n${n}`)}return $(i.data)}function E(n,r){const t=P(n,r,{scope:"agents"}),o=g(c(t));if(!d(o))throw new Error(`Invalid config file: ${r} (expected YAML object)`);const i=d(o.agents)?o.agents:{},s=j(a.agents,i),f=e.safeParse(s);if(!f.success){const n=f.error.issues.map(n=>` - agents.${n.path.join(".")}: ${n.message}`).join("\n");throw new Error(`Config validation failed (${r}):\n${n}`)}return{...f.data,dataDir:v(f.data.dataDir)}}function y(n,r){const t=parseConfigDocument(n,r),o=g(c(t));if(!d(o))throw new Error(`Invalid config file: ${r} (expected YAML object)`);const e=d(o.install)?o.install:{},s=j(a.install,e),f=i.safeParse(s);if(!f.success){const n=f.error.issues.map(n=>` - install.${n.path.join(".")}: ${n.message}`).join("\n");throw new Error(`Config validation failed (${r}):\n${n}`)}return f.data}export function loadInstallConfig(t={}){const o=resolveConfigPath(t);if(!o)return{installConfig:a.install,configPath:void 0};if(!r(o))throw new Error(`Config file not found: ${o}`);return{installConfig:y(n(o,"utf-8"),o),configPath:o}}export function loadConfig(t={}){const o=resolveConfigPath(t);if(!o)return{config:$(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:E(n(o,"utf-8"),o),configPath:o}}export function resolveConfigPath(n={}){const{configPath:r,cwd:t=process.cwd()}=n;return r??w(t)}export function inspectConfigFile(t={}){const o=resolveConfigPath(t);if(!o)return{status:C.notFound,configPath:void 0};if(!r(o))return{status:C.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:C.invalid,configPath:o,raw:e,error:n instanceof Error?n:new Error(String(n))}}const s=u(i);if(s.needsMigration)return{status:C.needsMigration,configPath:o,raw:e,report:s};try{return{status:C.valid,configPath:o,config:validateConfigText(e,o)}}catch(n){return{status:C.invalid,configPath:o,raw:e,error:n instanceof Error?n:new Error(String(n))}}}function j(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]=j(r,e)}return t}
|
|
@@ -22,13 +22,13 @@ export declare const BrowserSecurityDiagnosticSchema: z.ZodObject<{
|
|
|
22
22
|
domainAllowlist: string[];
|
|
23
23
|
maxPageContentBytes: number;
|
|
24
24
|
maxSnapshotNodes: number;
|
|
25
|
-
actionPolicy: "
|
|
25
|
+
actionPolicy: "deny" | "confirm" | "log";
|
|
26
26
|
foregroundPolicy: "never" | "when-minimized" | "always";
|
|
27
27
|
}, {
|
|
28
28
|
domainAllowlist: string[];
|
|
29
29
|
maxPageContentBytes: number;
|
|
30
30
|
maxSnapshotNodes: number;
|
|
31
|
-
actionPolicy: "
|
|
31
|
+
actionPolicy: "deny" | "confirm" | "log";
|
|
32
32
|
foregroundPolicy?: "never" | "when-minimized" | "always" | undefined;
|
|
33
33
|
}>;
|
|
34
34
|
export declare const BrowserUseToolPolicyDiagnosticSchema: z.ZodObject<{
|
|
@@ -36,18 +36,18 @@ export declare const BrowserUseToolPolicyDiagnosticSchema: z.ZodObject<{
|
|
|
36
36
|
tools: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
37
37
|
policy: z.ZodEnum<["log", "deny", "confirm"]>;
|
|
38
38
|
}, "strip", z.ZodTypeAny, {
|
|
39
|
-
policy: "
|
|
39
|
+
policy: "deny" | "confirm" | "log";
|
|
40
40
|
}, {
|
|
41
|
-
policy: "
|
|
41
|
+
policy: "deny" | "confirm" | "log";
|
|
42
42
|
}>>;
|
|
43
43
|
}, "strip", z.ZodTypeAny, {
|
|
44
44
|
tools: Record<string, {
|
|
45
|
-
policy: "
|
|
45
|
+
policy: "deny" | "confirm" | "log";
|
|
46
46
|
}>;
|
|
47
47
|
approvalTtlMs: number;
|
|
48
48
|
}, {
|
|
49
49
|
tools: Record<string, {
|
|
50
|
-
policy: "
|
|
50
|
+
policy: "deny" | "confirm" | "log";
|
|
51
51
|
}>;
|
|
52
52
|
approvalTtlMs: number;
|
|
53
53
|
}>;
|
|
@@ -164,13 +164,13 @@ export declare const AgentRuntimeEnvDiagnosticPayloadSchema: z.ZodObject<{
|
|
|
164
164
|
domainAllowlist: string[];
|
|
165
165
|
maxPageContentBytes: number;
|
|
166
166
|
maxSnapshotNodes: number;
|
|
167
|
-
actionPolicy: "
|
|
167
|
+
actionPolicy: "deny" | "confirm" | "log";
|
|
168
168
|
foregroundPolicy: "never" | "when-minimized" | "always";
|
|
169
169
|
}, {
|
|
170
170
|
domainAllowlist: string[];
|
|
171
171
|
maxPageContentBytes: number;
|
|
172
172
|
maxSnapshotNodes: number;
|
|
173
|
-
actionPolicy: "
|
|
173
|
+
actionPolicy: "deny" | "confirm" | "log";
|
|
174
174
|
foregroundPolicy?: "never" | "when-minimized" | "always" | undefined;
|
|
175
175
|
}>>;
|
|
176
176
|
toolPolicy: z.ZodOptional<z.ZodObject<{
|
|
@@ -178,18 +178,18 @@ export declare const AgentRuntimeEnvDiagnosticPayloadSchema: z.ZodObject<{
|
|
|
178
178
|
tools: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
179
179
|
policy: z.ZodEnum<["log", "deny", "confirm"]>;
|
|
180
180
|
}, "strip", z.ZodTypeAny, {
|
|
181
|
-
policy: "
|
|
181
|
+
policy: "deny" | "confirm" | "log";
|
|
182
182
|
}, {
|
|
183
|
-
policy: "
|
|
183
|
+
policy: "deny" | "confirm" | "log";
|
|
184
184
|
}>>;
|
|
185
185
|
}, "strip", z.ZodTypeAny, {
|
|
186
186
|
tools: Record<string, {
|
|
187
|
-
policy: "
|
|
187
|
+
policy: "deny" | "confirm" | "log";
|
|
188
188
|
}>;
|
|
189
189
|
approvalTtlMs: number;
|
|
190
190
|
}, {
|
|
191
191
|
tools: Record<string, {
|
|
192
|
-
policy: "
|
|
192
|
+
policy: "deny" | "confirm" | "log";
|
|
193
193
|
}>;
|
|
194
194
|
approvalTtlMs: number;
|
|
195
195
|
}>>;
|
|
@@ -316,12 +316,12 @@ export declare const AgentRuntimeEnvDiagnosticPayloadSchema: z.ZodObject<{
|
|
|
316
316
|
domainAllowlist: string[];
|
|
317
317
|
maxPageContentBytes: number;
|
|
318
318
|
maxSnapshotNodes: number;
|
|
319
|
-
actionPolicy: "
|
|
319
|
+
actionPolicy: "deny" | "confirm" | "log";
|
|
320
320
|
foregroundPolicy: "never" | "when-minimized" | "always";
|
|
321
321
|
} | undefined;
|
|
322
322
|
toolPolicy?: {
|
|
323
323
|
tools: Record<string, {
|
|
324
|
-
policy: "
|
|
324
|
+
policy: "deny" | "confirm" | "log";
|
|
325
325
|
}>;
|
|
326
326
|
approvalTtlMs: number;
|
|
327
327
|
} | undefined;
|
|
@@ -360,12 +360,12 @@ export declare const AgentRuntimeEnvDiagnosticPayloadSchema: z.ZodObject<{
|
|
|
360
360
|
domainAllowlist: string[];
|
|
361
361
|
maxPageContentBytes: number;
|
|
362
362
|
maxSnapshotNodes: number;
|
|
363
|
-
actionPolicy: "
|
|
363
|
+
actionPolicy: "deny" | "confirm" | "log";
|
|
364
364
|
foregroundPolicy?: "never" | "when-minimized" | "always" | undefined;
|
|
365
365
|
} | undefined;
|
|
366
366
|
toolPolicy?: {
|
|
367
367
|
tools: Record<string, {
|
|
368
|
-
policy: "
|
|
368
|
+
policy: "deny" | "confirm" | "log";
|
|
369
369
|
}>;
|
|
370
370
|
approvalTtlMs: number;
|
|
371
371
|
} | undefined;
|