@roll-agent/core 0.18.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. package/THIRD_PARTY_NOTICES.txt +112 -0
  2. package/dist/cli/chat/banner.d.ts +13 -0
  3. package/dist/cli/chat/banner.js +1 -1
  4. package/dist/cli/chat/ink/app.d.ts +4 -1
  5. package/dist/cli/chat/ink/app.js +1 -1
  6. package/dist/cli/chat/ink/banner-view.d.ts +15 -0
  7. package/dist/cli/chat/ink/banner-view.js +1 -0
  8. package/dist/cli/chat/ink/commands.d.ts +4 -12
  9. package/dist/cli/chat/ink/commands.js +1 -1
  10. package/dist/cli/chat/ink/history-from-messages.js +1 -1
  11. package/dist/cli/chat/ink/history-item.js +1 -1
  12. package/dist/cli/chat/ink/input-history.d.ts +2 -0
  13. package/dist/cli/chat/ink/input-history.js +1 -0
  14. package/dist/cli/chat/ink/line-buffer.d.ts +2 -0
  15. package/dist/cli/chat/ink/line-buffer.js +1 -1
  16. package/dist/cli/chat/ink/live-region.d.ts +2 -0
  17. package/dist/cli/chat/ink/live-region.js +1 -1
  18. package/dist/cli/chat/ink/reasoning-block.d.ts +4 -0
  19. package/dist/cli/chat/ink/reasoning-block.js +1 -0
  20. package/dist/cli/chat/ink/run-ink-repl.js +1 -1
  21. package/dist/cli/chat/ink/spinner.d.ts +3 -1
  22. package/dist/cli/chat/ink/spinner.js +1 -1
  23. package/dist/cli/chat/ink/state.d.ts +26 -3
  24. package/dist/cli/chat/ink/state.js +1 -1
  25. package/dist/cli/chat/ink/text-prompt.d.ts +3 -1
  26. package/dist/cli/chat/ink/text-prompt.js +1 -1
  27. package/dist/cli/chat/ink/turn-activity.d.ts +19 -0
  28. package/dist/cli/chat/ink/turn-activity.js +1 -0
  29. package/dist/cli/chat/ink/turn-status-line.d.ts +14 -0
  30. package/dist/cli/chat/ink/turn-status-line.js +1 -0
  31. package/dist/cli/chat/ink/use-session.js +1 -1
  32. package/dist/cli/commands/chat.d.ts +28 -0
  33. package/dist/cli/commands/chat.js +1 -1
  34. package/dist/cli/commands/config-explain.js +1 -1
  35. package/dist/cli/commands/config-setup.js +1 -1
  36. package/dist/cli/commands/config.js +1 -1
  37. package/dist/cli/commands/doctor.js +1 -1
  38. package/dist/cli/commands/ui.d.ts +30 -0
  39. package/dist/cli/commands/ui.js +1 -0
  40. package/dist/cli/index.js +1 -1
  41. package/dist/cli/utils/chat-renderer.js +1 -1
  42. package/dist/cli/utils/current-cli-shim.d.ts +14 -0
  43. package/dist/cli/utils/current-cli-shim.js +1 -0
  44. package/dist/cli/utils/debug-format.d.ts +4 -0
  45. package/dist/cli/utils/debug-format.js +1 -0
  46. package/dist/config/application-service.d.ts +90 -0
  47. package/dist/config/application-service.js +1 -0
  48. package/dist/config/catalog.d.ts +76 -0
  49. package/dist/config/catalog.js +1 -0
  50. package/dist/config/defaults.d.ts +4 -3
  51. package/dist/config/defaults.js +1 -1
  52. package/dist/config/document-store.d.ts +70 -0
  53. package/dist/config/document-store.js +1 -0
  54. package/dist/config/guidance.d.ts +571 -0
  55. package/dist/config/guidance.js +1 -0
  56. package/dist/config/index.d.ts +6 -0
  57. package/dist/config/index.js +1 -1
  58. package/dist/config/key-codec.d.ts +24 -3
  59. package/dist/config/key-codec.js +1 -1
  60. package/dist/config/migration.js +1 -1
  61. package/dist/config/schema.d.ts +52 -7
  62. package/dist/config/schema.js +1 -1
  63. package/dist/config/secret-policy.d.ts +20 -0
  64. package/dist/config/secret-policy.js +1 -0
  65. package/dist/llm/providers.d.ts +8 -4
  66. package/dist/llm/providers.js +1 -1
  67. package/dist/registry/agent-lifecycle.d.ts +97 -0
  68. package/dist/registry/agent-lifecycle.js +1 -0
  69. package/dist/registry/discovery.js +1 -1
  70. package/dist/registry/install.js +1 -1
  71. package/dist/registry/process-identity.d.ts +14 -0
  72. package/dist/registry/process-identity.js +1 -0
  73. package/dist/registry/process-manager.d.ts +28 -7
  74. package/dist/registry/process-manager.js +1 -1
  75. package/dist/registry/store.js +1 -1
  76. package/dist/skills/invocation.d.ts +27 -0
  77. package/dist/skills/invocation.js +1 -0
  78. package/dist/types/agent.d.ts +6 -0
  79. package/dist/types/agent.js +1 -1
  80. package/dist/types/chat.d.ts +3 -0
  81. package/dist/ui/config-controller.d.ts +15 -0
  82. package/dist/ui/config-controller.js +1 -0
  83. package/dist/ui/contracts.d.ts +49 -0
  84. package/dist/ui/contracts.js +1 -0
  85. package/dist/ui/index.d.ts +8 -0
  86. package/dist/ui/index.js +1 -0
  87. package/dist/ui/runtime-controller.d.ts +38 -0
  88. package/dist/ui/runtime-controller.js +1 -0
  89. package/dist/ui/server.d.ts +21 -0
  90. package/dist/ui/server.js +1 -0
  91. package/dist/ui/static-assets.d.ts +2 -0
  92. package/dist/ui/static-assets.js +1 -0
  93. package/dist/ui-assets/assets/app.css +1 -0
  94. package/dist/ui-assets/assets/app.js +53 -0
  95. package/dist/ui-assets/assets/roll-mark-wXIkY5y0.svg +5 -0
  96. package/dist/ui-assets/index.html +17 -0
  97. package/package.json +16 -8
  98. package/dist/cli/commands/config-guidance.d.ts +0 -148
  99. package/dist/cli/commands/config-guidance.js +0 -1
@@ -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,5 +1,5 @@
1
- import type { RollConfig } from "./schema.ts";
2
- export declare const LLM_PROVIDER_OPTIONS: readonly ["anthropic", "openai", "qwen", "deepseek"];
1
+ import { type RollConfig } from "./schema.ts";
2
+ export declare const LLM_PROVIDER_OPTIONS: readonly ["anthropic", "openai", "qwen", "deepseek", "xai"];
3
3
  export type LlmProviderOption = (typeof LLM_PROVIDER_OPTIONS)[number];
4
4
  export declare const DEFAULT_LLM_PROVIDER: LlmProviderOption;
5
5
  export declare const DEFAULT_LLM_MODELS: {
@@ -7,8 +7,9 @@ export declare const DEFAULT_LLM_MODELS: {
7
7
  readonly openai: "gpt-5.5";
8
8
  readonly qwen: "qwen3.6-plus";
9
9
  readonly deepseek: "deepseek-v4-flash";
10
+ readonly xai: "grok-4.5";
10
11
  };
11
- /** 默认配置值 */
12
+ /** 默认配置值;除上述必填 seed 外,全部由 rollConfigSchema 的默认值生成。 */
12
13
  export declare const DEFAULT_CONFIG: RollConfig;
13
14
  /** 配置文件查找顺序 */
14
15
  export declare const CONFIG_FILE_NAMES: readonly ["roll.config.yaml", "roll.config.yml"];
@@ -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:{},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},shell:{enabled:!1,autoApproveSafe:!0,defaultTimeoutMs:1e4,maxTimeoutMs:6e5,maxCaptureBytes:1048576,maxModelOutputChars:16e3,session:{enabled:!1,maxSessions:8,defaultYieldMs:1e4,maxOutputTokens:1e4}}},skills:{dirs:[]},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
+ import{rollConfigSchema as e}from"./schema.js";export const LLM_PROVIDER_OPTIONS=["anthropic","openai","qwen","deepseek","xai"];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",xai:"grok-4.5"};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)}