@roll-agent/core 0.17.0 → 0.19.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/THIRD_PARTY_NOTICES.txt +112 -0
- package/dist/cli/chat/banner.d.ts +13 -0
- package/dist/cli/chat/banner.js +1 -1
- package/dist/cli/chat/ink/app.d.ts +3 -0
- package/dist/cli/chat/ink/app.js +1 -1
- package/dist/cli/chat/ink/banner-view.d.ts +15 -0
- package/dist/cli/chat/ink/banner-view.js +1 -0
- package/dist/cli/chat/ink/history-item.js +1 -1
- package/dist/cli/chat/ink/run-ink-repl.js +1 -1
- package/dist/cli/commands/chat.js +1 -1
- package/dist/cli/commands/config-explain.js +1 -1
- package/dist/cli/commands/config-setup.js +1 -1
- package/dist/cli/commands/config.js +1 -1
- package/dist/cli/commands/doctor.js +1 -1
- package/dist/cli/commands/ui.d.ts +30 -0
- package/dist/cli/commands/ui.js +1 -0
- package/dist/cli/index.js +1 -1
- package/dist/config/application-service.d.ts +90 -0
- package/dist/config/application-service.js +1 -0
- package/dist/config/catalog.d.ts +76 -0
- package/dist/config/catalog.js +1 -0
- package/dist/config/defaults.d.ts +2 -2
- package/dist/config/defaults.js +1 -1
- package/dist/config/document-store.d.ts +70 -0
- package/dist/config/document-store.js +1 -0
- package/dist/config/guidance.d.ts +549 -0
- package/dist/config/guidance.js +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.js +1 -1
- package/dist/config/key-codec.d.ts +24 -3
- package/dist/config/key-codec.js +1 -1
- package/dist/config/migration.js +1 -1
- package/dist/config/secret-policy.d.ts +20 -0
- package/dist/config/secret-policy.js +1 -0
- package/dist/llm/providers.d.ts +2 -0
- package/dist/llm/providers.js +1 -1
- package/dist/registry/agent-lifecycle.d.ts +97 -0
- package/dist/registry/agent-lifecycle.js +1 -0
- package/dist/registry/discovery.js +1 -1
- package/dist/registry/process-identity.d.ts +14 -0
- package/dist/registry/process-identity.js +1 -0
- package/dist/registry/process-manager.d.ts +28 -7
- package/dist/registry/process-manager.js +1 -1
- package/dist/registry/store.js +1 -1
- package/dist/types/agent.d.ts +6 -0
- package/dist/types/agent.js +1 -1
- package/dist/ui/config-controller.d.ts +15 -0
- package/dist/ui/config-controller.js +1 -0
- package/dist/ui/contracts.d.ts +49 -0
- package/dist/ui/contracts.js +1 -0
- package/dist/ui/index.d.ts +8 -0
- package/dist/ui/index.js +1 -0
- package/dist/ui/runtime-controller.d.ts +38 -0
- package/dist/ui/runtime-controller.js +1 -0
- package/dist/ui/server.d.ts +21 -0
- package/dist/ui/server.js +1 -0
- package/dist/ui/static-assets.d.ts +2 -0
- package/dist/ui/static-assets.js +1 -0
- package/dist/ui-assets/assets/app.css +1 -0
- package/dist/ui-assets/assets/app.js +53 -0
- package/dist/ui-assets/assets/roll-mark-wXIkY5y0.svg +5 -0
- package/dist/ui-assets/index.html +17 -0
- package/package.json +15 -8
- package/dist/cli/commands/config-guidance.d.ts +0 -148
- package/dist/cli/commands/config-guidance.js +0 -1
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { YamlConfigDocumentStore, type ConfigPatch, type ConfigPath, type ConfigRevision } from "./document-store.ts";
|
|
2
|
+
import { type LoadConfigOptions } from "./loader.ts";
|
|
3
|
+
export declare const CONFIG_UI_SECRET_SENTINEL: "__ROLL_UI_KEEP_EXISTING_SECRET__";
|
|
4
|
+
export declare const CONFIG_ACTIVATION_KINDS: readonly ["next-command", "next-chat", "restart-agent", "manual"];
|
|
5
|
+
export type ConfigActivationKind = (typeof CONFIG_ACTIVATION_KINDS)[number];
|
|
6
|
+
export interface ConfigActivationEffect {
|
|
7
|
+
readonly kind: ConfigActivationKind;
|
|
8
|
+
readonly paths: readonly ConfigPath[];
|
|
9
|
+
readonly title: string;
|
|
10
|
+
readonly description: string;
|
|
11
|
+
readonly agentName?: string;
|
|
12
|
+
readonly requiresConfirmation: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface ConfigValidationIssue {
|
|
15
|
+
readonly path: string;
|
|
16
|
+
readonly message: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ConfigDiffLine {
|
|
19
|
+
readonly kind: "context" | "add" | "remove";
|
|
20
|
+
readonly text: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ConfigApplicationSnapshot {
|
|
23
|
+
readonly configPath: string;
|
|
24
|
+
readonly existed: boolean;
|
|
25
|
+
readonly revision: ConfigRevision;
|
|
26
|
+
readonly persisted: Readonly<Record<string, unknown>>;
|
|
27
|
+
readonly yaml: string;
|
|
28
|
+
readonly configuredSecretPaths: readonly ConfigPath[];
|
|
29
|
+
}
|
|
30
|
+
export interface ConfigApplicationPreview {
|
|
31
|
+
readonly snapshot: ConfigApplicationSnapshot;
|
|
32
|
+
readonly changed: boolean;
|
|
33
|
+
readonly changedPaths: readonly ConfigPath[];
|
|
34
|
+
readonly effects: readonly ConfigActivationEffect[];
|
|
35
|
+
readonly diff: readonly ConfigDiffLine[];
|
|
36
|
+
}
|
|
37
|
+
export interface ConfigApplicationSaveResult extends ConfigApplicationPreview {
|
|
38
|
+
readonly backupPath?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface ConfigApplicationRecoverySaveResult {
|
|
41
|
+
readonly snapshot: ConfigApplicationSnapshot;
|
|
42
|
+
readonly changed: boolean;
|
|
43
|
+
readonly backupPath?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ConfigApplicationServiceOptions extends LoadConfigOptions {
|
|
46
|
+
/** Extra Agent env names declared as secret in their env.yaml contract. */
|
|
47
|
+
readonly secretEnvNames?: readonly string[];
|
|
48
|
+
/** Exact Agent env visibility derived from registered env.yaml declarations. */
|
|
49
|
+
readonly agentEnvFields?: readonly ConfigAgentEnvFieldPolicy[];
|
|
50
|
+
/** Fail closed for undeclared Agent env fields, including newly added candidate values. */
|
|
51
|
+
readonly redactUnknownAgentEnv?: boolean;
|
|
52
|
+
}
|
|
53
|
+
export interface ConfigAgentEnvFieldPolicy {
|
|
54
|
+
readonly agentName: string;
|
|
55
|
+
readonly name: string;
|
|
56
|
+
readonly secret: boolean;
|
|
57
|
+
}
|
|
58
|
+
export declare class ConfigApplicationValidationError extends Error {
|
|
59
|
+
readonly code: "config_validation_failed";
|
|
60
|
+
readonly issues: readonly ConfigValidationIssue[];
|
|
61
|
+
constructor(error: unknown);
|
|
62
|
+
}
|
|
63
|
+
export declare class ConfigApplicationService {
|
|
64
|
+
readonly configPath: string;
|
|
65
|
+
readonly store: YamlConfigDocumentStore;
|
|
66
|
+
private readonly isSecretPath;
|
|
67
|
+
constructor(options?: ConfigApplicationServiceOptions);
|
|
68
|
+
read(): ConfigApplicationSnapshot;
|
|
69
|
+
/** Load syntactically valid persisted data so a focused CLI setup can repair schema errors. */
|
|
70
|
+
readForRepair(): ConfigApplicationSnapshot;
|
|
71
|
+
previewPatches(patches: readonly ConfigPatch[], expectedRevision?: ConfigRevision): ConfigApplicationPreview;
|
|
72
|
+
savePatches(patches: readonly ConfigPatch[], expectedRevision?: ConfigRevision): ConfigApplicationSaveResult;
|
|
73
|
+
previewStructured(persisted: unknown, expectedRevision?: ConfigRevision): ConfigApplicationPreview;
|
|
74
|
+
saveStructured(persisted: unknown, expectedRevision?: ConfigRevision): ConfigApplicationSaveResult;
|
|
75
|
+
previewYaml(yaml: string, expectedRevision?: ConfigRevision): ConfigApplicationPreview;
|
|
76
|
+
saveYaml(yaml: string, expectedRevision?: ConfigRevision): ConfigApplicationSaveResult;
|
|
77
|
+
/**
|
|
78
|
+
* Recover an invalid existing file during an explicitly confirmed `roll config init` overwrite.
|
|
79
|
+
* The generated candidate is fully validated, but the old document is never parsed or returned
|
|
80
|
+
* to a browser. UI and ordinary CLI edits must continue to use preview/save methods above.
|
|
81
|
+
*/
|
|
82
|
+
replaceYamlForInit(yaml: string, expectedRevision: ConfigRevision): ConfigApplicationRecoverySaveResult;
|
|
83
|
+
private preparePatches;
|
|
84
|
+
private prepareStructured;
|
|
85
|
+
private prepareYaml;
|
|
86
|
+
private prepareDocumentPreview;
|
|
87
|
+
private commitPrepared;
|
|
88
|
+
}
|
|
89
|
+
export declare function planConfigActivation(changedPaths: readonly ConfigPath[]): readonly ConfigActivationEffect[];
|
|
90
|
+
export declare function createConfigPatches(before: unknown, after: unknown, path?: ConfigPath): readonly ConfigPatch[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{homedir as t}from"node:os";import{resolve as e}from"node:path";import{stringify as r}from"yaml";import{DEFAULT_CONFIG as n}from"./defaults.js";import{ConfigRevisionConflictError as i,YamlConfigDocumentStore as o,applyPatchesToYamlText as s}from"./document-store.js";import{CONFIG_KEY_CODEC as a,decodeFromYaml as c,encodePathToYaml as p,encodeToYaml as h,kebabToCamel as u}from"./key-codec.js";import{parseConfigDocument as f,resolveConfigPath as l,validateConfigText as d}from"./loader.js";import{detectKnownConfigMigrations as g,formatConfigMigrationError as m}from"./migration.js";import{isRollConfigSecretPath as w,isSecretConfigValue as v}from"./secret-policy.js";export const CONFIG_UI_SECRET_SENTINEL="__ROLL_UI_KEEP_EXISTING_SECRET__";export const CONFIG_ACTIVATION_KINDS=["next-command","next-chat","restart-agent","manual"];export class ConfigApplicationValidationError extends Error{code="config_validation_failed";issues;constructor(t){const e=t instanceof Error?t:new Error(String(t));super(e.message,{cause:e}),this.name="ConfigApplicationValidationError",this.issues=D(e.message)}}export class ConfigApplicationService{configPath;store;isSecretPath;constructor(r={}){this.configPath=l(r)??e(t(),"roll.config.yaml"),this.store=new o(this.configPath,Y());const n=new Set(r.secretEnvNames??[]),i=new Map((r.agentEnvFields??[]).map(t=>[F(t.agentName,t.name),t.secret]));this.isSecretPath=t=>V(t,n,i,r.redactUnknownAgentEnv??!1)}read(){const t=this.store.read();return y(t.raw,t.configPath),P(t,this.isSecretPath)}readForRepair(){const t=this.store.read(),e=f(t.raw,t.configPath),r=g(e);if(r.needsMigration)throw new ConfigApplicationValidationError(new Error(m(t.configPath,r)));return P(t,this.isSecretPath)}previewPatches(t,e){return this.preparePatches(t,e).publicPreview}savePatches(t,e){return this.commitPrepared(this.preparePatches(t,e))}previewStructured(t,e){return this.prepareStructured(t,e).publicPreview}saveStructured(t,e){return this.commitPrepared(this.prepareStructured(t,e))}previewYaml(t,e){return this.prepareYaml(t,e).publicPreview}saveYaml(t,e){return this.commitPrepared(this.prepareYaml(t,e))}replaceYamlForInit(t,e){y(t,this.configPath);const r=this.store.replaceRawForRecovery(t,e);return{snapshot:P(r,this.isSecretPath),changed:r.changed,...void 0!==r.backupPath?{backupPath:r.backupPath}:{}}}preparePatches(t,e){const r=t.map(S),n=this.store.previewPatches(r,e);return this.prepareDocumentPreview(n)}prepareStructured(t,e){if(!M(t))throw new ConfigApplicationValidationError(new Error("配置内容必须是一个 JSON/YAML object。"));const r=this.store.read();if(void 0!==e&&e!==r.revision)throw new i(e,r.revision);const n=O(t,A(r.persisted),[],this.isSecretPath),o=h(n);if(!M(o))throw new ConfigApplicationValidationError(new Error("编码后的配置必须是 object。"));const s=this.store.previewObject(o,r.revision);return this.prepareDocumentPreview(s)}prepareYaml(t,e){const r=this.store.read();if(void 0!==e&&e!==r.revision)throw new i(e,r.revision);let n,o=t;try{n=f(o,this.configPath)}catch(t){throw new ConfigApplicationValidationError(t)}const c=[];let p;j(n,A(r.persisted),[],[],c,this.isSecretPath,a),c.length>0&&(o=s(o,this.configPath,c));try{p=this.store.previewRaw(o,r.revision)}catch(t){throw new ConfigApplicationValidationError(t)}return this.prepareDocumentPreview(p)}prepareDocumentPreview(t){y(t.raw,this.configPath);const e=_(A(f(t.previousRaw,this.configPath)),A(t.persisted)),r=P(t,this.isSecretPath),n=f(t.previousRaw,this.configPath),i=P({configPath:t.configPath,existed:t.existed,raw:t.previousRaw,revision:t.previousRevision,persisted:n},this.isSecretPath);return{documentPreview:t,publicPreview:{snapshot:r,changed:t.changed,changedPaths:e,effects:planConfigActivation(e),diff:U(i.yaml,r.yaml)}}}commitPrepared(t){const e=this.store.commit(t.documentPreview,{backup:!0}),r=P(e,this.isSecretPath);return{...t.publicPreview,snapshot:r,...void 0!==e.backupPath?{backupPath:e.backupPath}:{}}}}export function planConfigActivation(t){const e=new Map;for(const r of t){const t=E(r),n=`${t.kind}:${t.agentName??""}:${t.title}`,i=e.get(n);void 0!==i?i.paths.push(r):e.set(n,{...t,paths:[r]})}return[...e.values()].map(t=>({...t,paths:t.paths}))}export function createConfigPatches(t,e,r=[]){if(M(t)&&M(e)){const n=[],i=new Set([...Object.keys(t),...Object.keys(e)]);for(const o of i)o in e?o in t?n.push(...createConfigPatches(t[o],e[o],[...r,o])):n.push({op:"set",path:[...r,o],value:e[o]}):n.push({op:"delete",path:[...r,o]});return n}if(q(t,e))return[];if(0===r.length)throw new ConfigApplicationValidationError(new Error("配置根节点必须保持为 object。"));return[{op:"set",path:r,value:e}]}function E(t){const[e,r,n]=t;return"agents"===e&&"dataDir"===r?{kind:"manual",title:"Agent 数据目录需要人工迁移",description:"保存不会搬迁旧 PID、日志或注册数据;请先停止 Agent,再人工迁移目录。",requiresConfirmation:!0}:"agents"===e&&"env"===r&&"string"==typeof n?{kind:"restart-agent",title:`重启 ${n}`,description:"运行中的 core-managed Agent 需要重启;已停止的 Agent 保持停止。",agentName:n,requiresConfirmation:!0}:"browser"===e?{kind:"restart-agent",title:"重启 browser-use-agent",description:"浏览器实例声明在 Agent 启动时注入;重启 Agent 后 Chrome 仍会在首次工具调用时懒启动。",agentName:"browser-use-agent",requiresConfirmation:!0}:"runtime"===e||"skills"===e?{kind:"next-chat",title:"新会话生效",description:"当前 roll chat 会话保持原配置,新会话会重新加载。",requiresConfirmation:!1}:{kind:"next-command",title:"后续命令生效",description:"后续 Roll 命令会重新加载该配置。",requiresConfirmation:!1}}function P(t,e){const r=A(t.persisted),n=N(t.persisted,[],[],e,a),i=n.map(t=>t.path),o=new Set(i.map(L)),c=I(r,[],o);if(!M(c))throw new ConfigApplicationValidationError(new Error("脱敏后的配置必须是 object。"));const p=n.filter(t=>{const e=G(r,t.path);return!("string"==typeof e&&$(e))}).map(t=>({op:"set",path:t.persistedPath,value:CONFIG_UI_SECRET_SENTINEL})),h=0===p.length?t.raw:s(t.raw,t.configPath,p);return{configPath:t.configPath,existed:t.existed,revision:t.revision,persisted:c,yaml:h,configuredSecretPaths:i}}function y(t,e){try{d(t,e)}catch(t){throw new ConfigApplicationValidationError(t)}}function A(t){const e=c(t);if(!M(e))throw new ConfigApplicationValidationError(new Error("持久化配置必须是 object。"));return e}function S(t){const e=C(t.path);return"set"===t.op?{op:"set",path:e,value:k(t.value,t.path)}:{op:"delete",path:e}}function C(t){return p(t.map(String)).map((e,r)=>"number"==typeof t[r]?t[r]:e)}function k(t,e){if(!M(t)&&!Array.isArray(t))return t;const r=b({},e,t),n=h(r);return M(n)?G(n,C(e)):t}function b(t,e,r){let n=t;for(const[t,i]of e.entries()){const o=String(i);if(t===e.length-1){n[o]=r;break}const s={};n[o]=s,n=s}return t}function _(t,e,r=[]){const n=[],i=new Set([...Object.keys(t),...Object.keys(e)]);for(const o of i){const i=t[o],s=e[o],a=[...r,o];M(i)||M(s)?n.push(..._(M(i)?i:{},M(s)?s:{},a)):q(i,s)||n.push(a)}return n}function N(t,e,r,n,i){const o=[];if(Array.isArray(t)){const s="array"===i?.kind?i.item:i;return t.forEach((t,i)=>{const a=[...e,i],c=[...r,i],p=R(t,s);v(a,p,n)?o.push({path:a,persistedPath:c}):(Array.isArray(t)||M(t))&&o.push(...N(t,a,c,n,s))}),o}if(!M(t))return o;for(const[s,a]of Object.entries(t)){const t=x(s,a,i),c=[...e,t.key],p=[...r,s];v(c,t.value,n)?o.push({path:c,persistedPath:p}):(Array.isArray(a)||M(a))&&o.push(...N(a,c,p,n,t.node))}return o}function I(t,e,r){return r.has(L(e))?"string"==typeof t&&$(t)?t:CONFIG_UI_SECRET_SENTINEL:"string"==typeof t?t:Array.isArray(t)?t.map((t,n)=>I(t,[...e,n],r)):M(t)?Object.fromEntries(Object.entries(t).map(([t,n])=>[t,I(n,[...e,t],r)])):t}function O(t,e,r,n){if(t===CONFIG_UI_SECRET_SENTINEL)return T(e,r,n),e;if(Array.isArray(t)){const i=Array.isArray(e)?e:[];return t.map((t,e)=>O(t,i[e],[...r,e],n))}if(!M(t))return t;const i=M(e)?e:{};return Object.fromEntries(Object.entries(t).map(([t,e])=>[t,O(e,i[t],[...r,t],n)]))}function j(t,e,r,n,i,o,s){if(Array.isArray(t)){const a="array"===s?.kind?s.item:s;return void t.forEach((t,s)=>{const c=[...r,s],p=[...n,s],h=G(e,c);if(t===CONFIG_UI_SECRET_SENTINEL)return T(h,c,o),void i.push({op:"set",path:p,value:h});j(t,e,c,p,i,o,a)})}if(M(t))for(const[a,c]of Object.entries(t)){const t=x(a,c,s),p=[...r,t.key],h=[...n,a],u=G(e,p);c!==CONFIG_UI_SECRET_SENTINEL?j(c,e,p,h,i,o,t.node):(T(u,p,o),i.push({op:"set",path:h,value:u}))}}function x(t,e,r){if("object"===r?.kind){const n=u(t),i=r.fields[n];return{key:n,value:R(e,i),node:i}}return"record"===r?.kind?{key:t,value:R(e,r.value),node:r.value}:{key:t,value:e,node:void 0}}function R(t,e){return void 0===e||"leaf"===e.kind?t:c(t,e)}function T(t,e,r){if(void 0===t||t===CONFIG_UI_SECRET_SENTINEL||!v(e,t,r))throw new ConfigApplicationValidationError(new Error(`无法在原路径恢复敏感配置: ${K(e)}`))}function V(t,e=new Set,r=new Map,n=!1){if(w(t))return!0;if(4===t.length&&"agents"===t[0]&&"env"===t[1]){const i=t[2],o=t[3];if("string"!=typeof i||"string"!=typeof o)return!1;const s=F(i,o);return r.has(s)?!0===r.get(s):!(!e.has(o)&&!n)||(/(?:^|_)(?:TOKEN|API_KEY|SECRET|PASSWORD|PRIVATE_KEY)(?:_|$)/u.test(o)||o.endsWith("_WEBHOOK"))}return!1}function F(t,e){return`${t}\0${e}`}function $(t){return/^\$\{[^{}]+\}$/u.test(t)}function L(t){return JSON.stringify(t)}function G(t,e){let r=t;for(const t of e)if(Array.isArray(r)&&"number"==typeof t)r=r[t];else{if(!M(r))return;r=r[String(t)]}return r}function U(t,e){if(t===e)return t.split("\n").map(t=>({kind:"context",text:t}));const r=t.split("\n"),n=e.split("\n");let i=0;for(;i<r.length&&i<n.length&&r[i]===n[i];)i+=1;let o=0;for(;o<r.length-i&&o<n.length-i&&r[r.length-o-1]===n[n.length-o-1];)o+=1;return[...r.slice(0,i).map(t=>({kind:"context",text:t})),...r.slice(i,r.length-o).map(t=>({kind:"remove",text:t})),...n.slice(i,n.length-o).map(t=>({kind:"add",text:t})),...r.slice(r.length-o).map(t=>({kind:"context",text:t}))]}function Y(){const t={llm:n.llm,ask:n.ask,agents:n.agents};return r(h(t),{lineWidth:0})}function D(t){const e=t.split("\n").map(t=>t.match(/^\s*-\s+([^:]+):\s*(.+)$/u)).filter(t=>null!==t).map(e=>({path:e[1]??"",message:e[2]??t}));return e.length>0?e:[{path:"",message:t}]}function K(t){return t.map(String).join(" / ")}function q(t,e){if(Object.is(t,e))return!0;if(Array.isArray(t)&&Array.isArray(e))return t.length===e.length&&t.every((t,r)=>q(t,e[r]));if(!M(t)||!M(e))return!1;const r=Object.keys(t),n=Object.keys(e);return r.length===n.length&&r.every(r=>r in e&&q(t[r],e[r]))}function M(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { RegisteredAgent } from "../types/agent.ts";
|
|
2
|
+
export declare const CONFIG_CATALOG_NODE_KINDS: readonly ["object", "record", "array", "string", "number", "boolean", "enum", "unknown"];
|
|
3
|
+
export type ConfigCatalogNodeKind = (typeof CONFIG_CATALOG_NODE_KINDS)[number];
|
|
4
|
+
export declare const CONFIG_FIELD_WIDGETS: readonly ["text", "password", "url", "path", "textarea", "number", "duration", "switch", "select", "string-list", "record", "object"];
|
|
5
|
+
export type ConfigFieldWidget = (typeof CONFIG_FIELD_WIDGETS)[number];
|
|
6
|
+
interface ConfigCatalogNodeBase {
|
|
7
|
+
readonly kind: ConfigCatalogNodeKind;
|
|
8
|
+
readonly path: readonly string[];
|
|
9
|
+
readonly title: string;
|
|
10
|
+
readonly description?: string;
|
|
11
|
+
readonly defaultBehavior?: string;
|
|
12
|
+
readonly example?: string;
|
|
13
|
+
readonly setupCommand?: string;
|
|
14
|
+
readonly effectiveRequired: boolean;
|
|
15
|
+
readonly persistedRequired: boolean;
|
|
16
|
+
readonly defaultValue?: unknown;
|
|
17
|
+
readonly widget: ConfigFieldWidget;
|
|
18
|
+
readonly secret: boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface ConfigNumberConstraints {
|
|
21
|
+
readonly minimum?: number;
|
|
22
|
+
readonly maximum?: number;
|
|
23
|
+
readonly exclusiveMinimum: boolean;
|
|
24
|
+
readonly exclusiveMaximum: boolean;
|
|
25
|
+
readonly integer: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface ConfigObjectCatalogNode extends ConfigCatalogNodeBase {
|
|
28
|
+
readonly kind: "object";
|
|
29
|
+
readonly fields: Readonly<Record<string, ConfigCatalogNode>>;
|
|
30
|
+
}
|
|
31
|
+
export interface ConfigRecordCatalogNode extends ConfigCatalogNodeBase {
|
|
32
|
+
readonly kind: "record";
|
|
33
|
+
readonly value: ConfigCatalogNode;
|
|
34
|
+
}
|
|
35
|
+
export interface ConfigArrayCatalogNode extends ConfigCatalogNodeBase {
|
|
36
|
+
readonly kind: "array";
|
|
37
|
+
readonly item: ConfigCatalogNode;
|
|
38
|
+
}
|
|
39
|
+
export interface ConfigEnumCatalogNode extends ConfigCatalogNodeBase {
|
|
40
|
+
readonly kind: "enum";
|
|
41
|
+
readonly options: readonly string[];
|
|
42
|
+
}
|
|
43
|
+
export interface ConfigLeafCatalogNode extends ConfigCatalogNodeBase {
|
|
44
|
+
readonly kind: "string" | "boolean" | "unknown";
|
|
45
|
+
}
|
|
46
|
+
export interface ConfigNumberCatalogNode extends ConfigCatalogNodeBase {
|
|
47
|
+
readonly kind: "number";
|
|
48
|
+
readonly constraints: ConfigNumberConstraints;
|
|
49
|
+
}
|
|
50
|
+
export type ConfigCatalogNode = ConfigObjectCatalogNode | ConfigRecordCatalogNode | ConfigArrayCatalogNode | ConfigEnumCatalogNode | ConfigNumberCatalogNode | ConfigLeafCatalogNode;
|
|
51
|
+
export interface AgentEnvCatalogField {
|
|
52
|
+
readonly name: string;
|
|
53
|
+
readonly title: string;
|
|
54
|
+
readonly description?: string;
|
|
55
|
+
readonly example?: string;
|
|
56
|
+
readonly defaultValue?: string;
|
|
57
|
+
readonly required: boolean;
|
|
58
|
+
readonly type: "string" | "boolean" | "number" | "json" | "url";
|
|
59
|
+
readonly widget: "text" | "password" | "url" | "number" | "switch" | "textarea";
|
|
60
|
+
readonly secret: boolean;
|
|
61
|
+
readonly configurable: boolean;
|
|
62
|
+
readonly sourcePath?: readonly string[];
|
|
63
|
+
}
|
|
64
|
+
export interface AgentConfigCatalog {
|
|
65
|
+
readonly name: string;
|
|
66
|
+
readonly description: string;
|
|
67
|
+
readonly ownership: RegisteredAgent["runtime"]["ownership"];
|
|
68
|
+
readonly fields: readonly AgentEnvCatalogField[];
|
|
69
|
+
}
|
|
70
|
+
export interface RollConfigCatalog {
|
|
71
|
+
readonly schemaVersion: 1;
|
|
72
|
+
readonly root: ConfigObjectCatalogNode;
|
|
73
|
+
readonly agents: readonly AgentConfigCatalog[];
|
|
74
|
+
}
|
|
75
|
+
export declare function buildRollConfigCatalog(agents?: readonly RegisteredAgent[]): RollConfigCatalog;
|
|
76
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{z as e}from"zod";import{listConfigGuidanceEntries as t}from"./guidance.js";import{DEFAULT_CONFIG as n}from"./defaults.js";import{normalizeUserPath as i}from"./key-codec.js";import{rollConfigSchema as o}from"./schema.js";import{isRollConfigSecretPath as r}from"./secret-policy.js";export const CONFIG_CATALOG_NODE_KINDS=["object","record","array","string","number","boolean","enum","unknown"];export const CONFIG_FIELD_WIDGETS=["text","password","url","path","textarea","number","duration","switch","select","string-list","record","object"];export function buildRollConfigCatalog(e=[]){const t=a(o,[],n);if("object"!==t.kind)throw new Error("rollConfigSchema root must be an object");return{schemaVersion:1,root:t,agents:e.map(l)}}function a(t,n,i){const o=!t.safeParse(void 0).success,r=d(t),c=v(n),l=u(t,n,i,o,c);if(r instanceof e.ZodObject){const t=b(i)?i:{},o=Object.fromEntries(Object.entries(r.shape).map(([i,o])=>{if(!(o instanceof e.ZodType))throw new Error(`Unsupported Zod object field at ${[...n,i].join(".")}`);return[i,a(o,[...n,i],t[i])]}));return{...l,kind:"object",widget:"object",fields:o}}return r instanceof e.ZodRecord?{...l,kind:"record",widget:"record",value:a(r.valueSchema,[...n,"*"],void 0)}:r instanceof e.ZodArray?{...l,kind:"array",widget:r.element instanceof e.ZodString?"string-list":"object",item:a(r.element,[...n,"*"],void 0)}:r instanceof e.ZodEnum?{...l,kind:"enum",widget:"select",options:r.options}:r instanceof e.ZodString?{...l,kind:"string",widget:p(n)}:r instanceof e.ZodNumber?{...l,kind:"number",widget:!0===n.at(-1)?.endsWith("Ms")?"duration":"number",constraints:s(r)}:r instanceof e.ZodBoolean?{...l,kind:"boolean",widget:"switch"}:{...l,kind:"unknown",widget:"textarea"}}function s(e){let t,n;for(const i of e._def.checks)"min"!==i.kind?"max"===i.kind&&(void 0===n||i.value<n.value||i.value===n.value&&!i.inclusive)&&(n={value:i.value,exclusive:!i.inclusive}):(void 0===t||i.value>t.value||i.value===t.value&&!i.inclusive)&&(t={value:i.value,exclusive:!i.inclusive});return{...void 0!==t?{minimum:t.value}:{},...void 0!==n?{maximum:n.value}:{},exclusiveMinimum:t?.exclusive??!1,exclusiveMaximum:n?.exclusive??!1,integer:e.isInt}}function u(e,t,n,i,o){const a=void 0!==n?{defaultValue:n}:c(e);return{kind:"unknown",path:t,title:o?.title??g(t.at(-1)??"Roll configuration"),...void 0!==o?.purpose?{description:o.purpose}:{},...void 0!==o?.defaultBehavior?{defaultBehavior:o.defaultBehavior}:{},...void 0!==o?.example?{example:o.example}:{},...void 0!==o?.setupCommand?{setupCommand:o.setupCommand}:{},effectiveRequired:i,persistedRequired:i&&!("defaultValue"in a),...a,widget:"text",secret:r(t)}}function c(e){const t=e.safeParse(void 0);return t.success&&void 0!==t.data?{defaultValue:t.data}:{}}function d(t){return t instanceof e.ZodOptional||t instanceof e.ZodNullable?d(t.unwrap()):t instanceof e.ZodDefault?d(t.removeDefault()):t instanceof e.ZodEffects?d(t.innerType()):t instanceof e.ZodCatch?d(t.removeCatch()):t instanceof e.ZodBranded?d(t.unwrap()):t}function l(e){const t=new Set((e.skill.env?.required??[]).map(e=>e.name)),n=[...e.skill.env?.required??[],...e.skill.env?.optional??[]];return{name:e.skill.name,description:e.skill.description,ownership:e.runtime.ownership,fields:n.map(e=>{const n=e.type??m(e.name),i=e.secret??!0,o=e.configurable??"BROWSER_INSTANCES_JSON"!==e.name,r=e.sourcePath??("BROWSER_INSTANCES_JSON"===e.name?["browser","instances"]:void 0);return{name:e.name,title:w(e.name),...void 0!==e.purpose?{description:e.purpose}:{},...void 0!==e.example?{example:e.example}:{},...void 0!==e.default?{defaultValue:e.default}:{},required:t.has(e.name),type:n,widget:f(n,i),secret:i,configurable:o,...void 0!==r?{sourcePath:r}:{}}})}}function m(e){return e.endsWith("_JSON")?"json":e.endsWith("_ENABLED")||e.startsWith("ENABLE_")?"boolean":e.endsWith("_MS")||e.endsWith("_TIMEOUT")?"number":e.endsWith("_URL")||e.endsWith("_URI")?"url":"string"}function f(e,t){if(t)return"password";switch(e){case"boolean":return"switch";case"number":return"number";case"json":return"textarea";case"url":return"url";case"string":return"text"}}function p(e){if(r(e))return"password";const t=e.at(-1)??"";return/(?:Url|Uri)$/u.test(t)?"url":/(?:Dir|Path)$/u.test(t)?"path":"text"}function v(e){return t().find(t=>{const n=h(t.path);return n.length===e.length&&n.every((t,n)=>"*"===t||t===e[n])})}function h(e){const t=e.split(".");return i(t).map(e=>e.startsWith("<")&&e.endsWith(">")?"*":e)}function g(e){return e.replace(/([a-z0-9])([A-Z])/gu,"$1 $2").replace(/[-_]/gu," ").replace(/^./u,e=>e.toUpperCase())}function w(e){return e.toLowerCase().split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function b(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type RollConfig } from "./schema.ts";
|
|
2
2
|
export declare const LLM_PROVIDER_OPTIONS: readonly ["anthropic", "openai", "qwen", "deepseek"];
|
|
3
3
|
export type LlmProviderOption = (typeof LLM_PROVIDER_OPTIONS)[number];
|
|
4
4
|
export declare const DEFAULT_LLM_PROVIDER: LlmProviderOption;
|
|
@@ -8,7 +8,7 @@ export declare const DEFAULT_LLM_MODELS: {
|
|
|
8
8
|
readonly qwen: "qwen3.6-plus";
|
|
9
9
|
readonly deepseek: "deepseek-v4-flash";
|
|
10
10
|
};
|
|
11
|
-
/**
|
|
11
|
+
/** 默认配置值;除上述必填 seed 外,全部由 rollConfigSchema 的默认值生成。 */
|
|
12
12
|
export declare const DEFAULT_CONFIG: RollConfig;
|
|
13
13
|
/** 配置文件查找顺序 */
|
|
14
14
|
export declare const CONFIG_FILE_NAMES: readonly ["roll.config.yaml", "roll.config.yml"];
|
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"};
|
|
1
|
+
import{rollConfigSchema as e}from"./schema.js";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"};const o={llm:{defaultProvider:"anthropic",defaultModel:DEFAULT_LLM_MODELS.anthropic,providers:{}},ask:{},agents:{dataDir:"~/.roll-agent/agents"}};export const DEFAULT_CONFIG=e.parse(o);export const CONFIG_FILE_NAMES=["roll.config.yaml","roll.config.yml"];
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
declare const CONFIG_REVISION_BRAND: unique symbol;
|
|
2
|
+
export type ConfigRevision = string & {
|
|
3
|
+
readonly [CONFIG_REVISION_BRAND]: true;
|
|
4
|
+
};
|
|
5
|
+
export type ConfigPath = readonly (string | number)[];
|
|
6
|
+
export type ConfigPatch = {
|
|
7
|
+
readonly op: "set";
|
|
8
|
+
readonly path: ConfigPath;
|
|
9
|
+
readonly value: unknown;
|
|
10
|
+
} | {
|
|
11
|
+
readonly op: "delete";
|
|
12
|
+
readonly path: ConfigPath;
|
|
13
|
+
};
|
|
14
|
+
export interface ConfigDocumentSnapshot {
|
|
15
|
+
readonly configPath: string;
|
|
16
|
+
readonly existed: boolean;
|
|
17
|
+
readonly raw: string;
|
|
18
|
+
readonly revision: ConfigRevision;
|
|
19
|
+
readonly persisted: Readonly<Record<string, unknown>>;
|
|
20
|
+
}
|
|
21
|
+
export interface ConfigDocumentPreview extends ConfigDocumentSnapshot {
|
|
22
|
+
readonly previousRaw: string;
|
|
23
|
+
readonly previousRevision: ConfigRevision;
|
|
24
|
+
readonly changed: boolean;
|
|
25
|
+
}
|
|
26
|
+
export interface ConfigDocumentWriteResult extends ConfigDocumentPreview {
|
|
27
|
+
readonly backupPath?: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ConfigDocumentRecoveryWriteResult extends ConfigDocumentSnapshot {
|
|
30
|
+
readonly previousRaw: string;
|
|
31
|
+
readonly previousRevision: ConfigRevision;
|
|
32
|
+
readonly changed: boolean;
|
|
33
|
+
readonly backupPath?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare class ConfigRevisionConflictError extends Error {
|
|
36
|
+
readonly code: "config_revision_conflict";
|
|
37
|
+
readonly expectedRevision: ConfigRevision;
|
|
38
|
+
readonly actualRevision: ConfigRevision;
|
|
39
|
+
constructor(expectedRevision: ConfigRevision, actualRevision: ConfigRevision);
|
|
40
|
+
}
|
|
41
|
+
export declare class ConfigWriteLockError extends Error {
|
|
42
|
+
readonly code: "config_write_locked";
|
|
43
|
+
constructor();
|
|
44
|
+
}
|
|
45
|
+
export declare class ConfigDocumentParseError extends Error {
|
|
46
|
+
readonly code: "config_document_parse_error";
|
|
47
|
+
constructor(configPath: string, message: string, cause?: Error);
|
|
48
|
+
}
|
|
49
|
+
export declare function createConfigRevision(raw: string): ConfigRevision;
|
|
50
|
+
export declare class YamlConfigDocumentStore {
|
|
51
|
+
readonly configPath: string;
|
|
52
|
+
readonly fallbackRaw: string;
|
|
53
|
+
constructor(configPath: string, fallbackRaw: string);
|
|
54
|
+
read(): ConfigDocumentSnapshot;
|
|
55
|
+
previewPatches(patches: readonly ConfigPatch[], expectedRevision?: ConfigRevision): ConfigDocumentPreview;
|
|
56
|
+
previewObject(persisted: Readonly<Record<string, unknown>>, expectedRevision?: ConfigRevision): ConfigDocumentPreview;
|
|
57
|
+
previewRaw(raw: string, expectedRevision?: ConfigRevision): ConfigDocumentPreview;
|
|
58
|
+
commit(preview: ConfigDocumentPreview, options?: {
|
|
59
|
+
readonly backup?: boolean;
|
|
60
|
+
}): ConfigDocumentWriteResult;
|
|
61
|
+
/**
|
|
62
|
+
* Replace an existing, potentially unparseable document after an upper layer has validated the
|
|
63
|
+
* candidate. This intentionally bypasses read()/preview so `roll config init` can recover a
|
|
64
|
+
* malformed file after explicit confirmation; ordinary CLI/UI writes must keep using commit().
|
|
65
|
+
*/
|
|
66
|
+
replaceRawForRecovery(raw: string, expectedRevision: ConfigRevision): ConfigDocumentRecoveryWriteResult;
|
|
67
|
+
private readRawSnapshot;
|
|
68
|
+
}
|
|
69
|
+
export declare function applyPatchesToYamlText(raw: string, configPath: string, patches: readonly ConfigPatch[]): string;
|
|
70
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createHash as e,randomUUID as t}from"node:crypto";import{closeSync as r,existsSync as i,fsyncSync as o,lstatSync as n,mkdirSync as s,openSync as c,readFileSync as a,realpathSync as f,renameSync as u,statSync as h,unlinkSync as d,writeFileSync as p}from"node:fs";import{basename as l,dirname as g,resolve as v}from"node:path";import{parseDocument as w}from"yaml";import{isProcessStartToken as m,readProcessStartToken as y}from"../registry/process-identity.js";const R=Symbol("ConfigRevision"),P=3e5;export class ConfigRevisionConflictError extends Error{code="config_revision_conflict";expectedRevision;actualRevision;constructor(e,t){super("配置文件已被其他进程修改,请刷新后重试。"),this.name="ConfigRevisionConflictError",this.expectedRevision=e,this.actualRevision=t}}export class ConfigWriteLockError extends Error{code="config_write_locked";constructor(){super("配置正在由另一个 Roll 进程写入,请稍后刷新并重试。"),this.name="ConfigWriteLockError"}}export class ConfigDocumentParseError extends Error{code="config_document_parse_error";constructor(e,t,r){super(`Invalid YAML syntax in config file: ${e}\n${t}`,{...void 0!==r?{cause:r}:{}}),this.name="ConfigDocumentParseError"}}export function createConfigRevision(t){return e("sha256").update(t).digest("hex")}export class YamlConfigDocumentStore{configPath;fallbackRaw;constructor(e,t){this.configPath=v(e),this.fallbackRaw=t}read(){const e=i(this.configPath),t=e?a(this.configPath,"utf-8"):this.fallbackRaw,r=b(t,this.configPath);return{configPath:this.configPath,existed:e,raw:t,revision:createConfigRevision(t),persisted:r}}previewPatches(e,t){const r=this.read();return x(r.revision,t),k(r,applyPatchesToYamlText(r.raw,this.configPath,e))}previewObject(e,t){const r=this.read();x(r.revision,t);const i=C(r.raw,this.configPath);return E(i,r.persisted,e,[]),k(r,i.toString({lineWidth:0}))}previewRaw(e,t){const r=this.read();return x(r.revision,t),b(e,this.configPath),k(r,A(e))}commit(e,t={}){if(!e.changed){return x(this.read().revision,e.previousRevision),{...e}}const r=$(this.configPath),i=M(r);try{const i=this.read();x(i.revision,e.previousRevision),N(this.configPath,r,e.previousRevision);const o=!1!==t.backup&&i.existed?T(r,i.raw):void 0;return j(r,e.raw,i.existed,()=>{J(this.configPath,this.fallbackRaw,r,i.existed,i.revision)}),{...e,existed:!0,...void 0!==o?{backupPath:o}:{}}}finally{i.release()}}replaceRawForRecovery(e,t){const r=A(e),i=b(r,this.configPath),o=$(this.configPath),n=M(o);try{const e=this.readRawSnapshot();x(e.revision,t),N(this.configPath,o,t);if(!(!e.existed||r!==e.raw))return{...e,persisted:i,previousRaw:e.raw,previousRevision:e.revision,changed:!1};const n=e.existed?T(o,e.raw):void 0;return j(o,r,e.existed,()=>{J(this.configPath,this.fallbackRaw,o,e.existed,e.revision)}),{configPath:this.configPath,existed:!0,raw:r,revision:createConfigRevision(r),persisted:i,previousRaw:e.raw,previousRevision:e.revision,changed:!0,...void 0!==n?{backupPath:n}:{}}}finally{n.release()}}readRawSnapshot(){const e=i(this.configPath),t=e?a(this.configPath,"utf-8"):this.fallbackRaw;return{configPath:this.configPath,existed:e,raw:t,revision:createConfigRevision(t)}}}export function applyPatchesToYamlText(e,t,r){const i=C(e,t);for(const e of r){if(0===e.path.length)throw new Error("配置 patch 路径不能为空");switch(e.op){case"set":i.setIn([...e.path],e.value);break;case"delete":i.deleteIn([...e.path])}}return i.toString({lineWidth:0})}function k(e,t){const r=A(t);return{configPath:e.configPath,existed:e.existed,raw:r,revision:createConfigRevision(r),persisted:b(r,e.configPath),previousRaw:e.raw,previousRevision:e.revision,changed:r!==e.raw}}function x(e,t){if(void 0!==t&&t!==e)throw new ConfigRevisionConflictError(t,e)}function C(e,t){const r=w(e,{keepSourceTokens:!0,prettyErrors:!0});if(r.errors.length>0){const[e]=r.errors,i=r.errors.map(e=>e.message).join("\n");throw new ConfigDocumentParseError(t,i,e)}return r}function b(e,t){const r=C(e,t).toJS();if(!X(r))throw new ConfigDocumentParseError(t,"expected YAML object");return r}function E(e,t,r,i){for(const o of Object.keys(t))o in r||e.deleteIn([...i,o]);for(const[o,n]of Object.entries(r)){const r=t[o],s=[...i,o];X(r)&&X(n)?E(e,r,n,s):S(r,n)||e.setIn(s,n)}}function S(e,t){if(Object.is(e,t))return!0;if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,r)=>S(e,t[r]));if(!X(e)||!X(t))return!1;const r=Object.keys(e),i=Object.keys(t);return r.length===i.length&&r.every(r=>r in t&&S(e[r],t[r]))}function A(e){return e.endsWith("\n")?e:`${e}\n`}function $(e){return i(e)&&n(e).isSymbolicLink()?f(e):e}function T(e,r){const o=`${e}.bak.${(new Date).toISOString().replace(/[-:]/gu,"").replace("T","-").replace("Z","").replace(".","-")}`,n=i(o)?`${o}.${t().slice(0,8)}`:o;return p(n,r,{encoding:"utf-8",flag:"wx",mode:384}),n}function j(e,n,a,f){const w=g(e);s(w,{recursive:!0});const m=a?511&h(e).mode:384,y=v(w,`.${l(e)}.${String(process.pid)}.${t()}.tmp`);let R;try{R=c(y,"wx",m),p(R,n,"utf-8"),o(R),r(R),R=void 0,f?.(),u(y,e),F(w)}catch(e){throw void 0!==R&&r(R),i(y)&&d(y),e}}function M(e){s(g(e),{recursive:!0});const r=`${e}.roll-write.lock`,i=y(process.pid);if(void 0===i)throw new Error(`无法验证当前 Roll 进程 (PID: ${String(process.pid)}) 的 OS 启动身份,拒绝获取配置写锁。`);const o={pid:process.pid,processStartToken:i,token:t(),createdAtMs:Date.now()},n=`${JSON.stringify(o)}\n`;for(let e=0;e<2;e+=1)try{p(r,n,{encoding:"utf-8",flag:"wx",mode:384});let e=!1;return{release:()=>{e||(e=!0,O(r,o.token))}}}catch(t){if(!Y(t,"EEXIST"))throw t;if(0===e&&D(r))continue;throw new ConfigWriteLockError}throw new ConfigWriteLockError}function O(e,t){try{const r=I(e);r?.token===t&&d(e)}catch{}}function D(e){let t,r;try{t=a(e,"utf-8"),r=h(e).mtimeMs}catch{return!1}const i=L(t),o=Date.now()-(i?.createdAtMs??r);if(!(void 0===i?o>P:W(i)))return!1;try{return a(e,"utf-8")===t&&(d(e),!0)}catch{return!1}}function I(e){if(i(e))return L(a(e,"utf-8"))}function L(e){let t;try{t=JSON.parse(e)}catch{return}if(X(t)&&"number"==typeof t.pid&&Number.isInteger(t.pid)&&!(t.pid<=0)&&m(t.processStartToken)&&"string"==typeof t.token&&"number"==typeof t.createdAtMs&&Number.isFinite(t.createdAtMs))return{pid:t.pid,processStartToken:t.processStartToken,token:t.token,createdAtMs:t.createdAtMs}}function W(e){if(!_(e.pid))return!0;const t=y(e.pid);return void 0!==t&&t!==e.processStartToken}function _(e){try{return process.kill(e,0),!0}catch(e){return Y(e,"EPERM")}}function Y(e,t){return e instanceof Error&&"code"in e&&e.code===t}function N(e,t,r){if($(e)!==t)throw new ConfigRevisionConflictError(r,r)}function J(e,t,r,o,n){const s=i(e),c=createConfigRevision(s?a(e,"utf-8"):t);if(s!==o||c!==n||$(e)!==r)throw new ConfigRevisionConflictError(n,c)}function F(e){if("win32"===process.platform)return;let t;try{t=c(e,"r"),o(t)}finally{void 0!==t&&r(t)}}function X(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}
|